native.py 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import hashlib
  2. import hmac
  3. import os
  4. from jose.backends.base import Key
  5. from jose.constants import ALGORITHMS
  6. from jose.exceptions import JWKError
  7. from jose.utils import base64url_decode, base64url_encode
  8. def get_random_bytes(num_bytes):
  9. return bytes(os.urandom(num_bytes))
  10. class HMACKey(Key):
  11. """
  12. Performs signing and verification operations using HMAC
  13. and the specified hash function.
  14. """
  15. HASHES = {ALGORITHMS.HS256: hashlib.sha256, ALGORITHMS.HS384: hashlib.sha384, ALGORITHMS.HS512: hashlib.sha512}
  16. def __init__(self, key, algorithm):
  17. if algorithm not in ALGORITHMS.HMAC:
  18. raise JWKError("hash_alg: %s is not a valid hash algorithm" % algorithm)
  19. self._algorithm = algorithm
  20. self._hash_alg = self.HASHES.get(algorithm)
  21. if isinstance(key, dict):
  22. self.prepared_key = self._process_jwk(key)
  23. return
  24. if not isinstance(key, str) and not isinstance(key, bytes):
  25. raise JWKError("Expecting a string- or bytes-formatted key.")
  26. if isinstance(key, str):
  27. key = key.encode("utf-8")
  28. invalid_strings = [
  29. b"-----BEGIN PUBLIC KEY-----",
  30. b"-----BEGIN RSA PUBLIC KEY-----",
  31. b"-----BEGIN CERTIFICATE-----",
  32. b"ssh-rsa",
  33. ]
  34. if any(string_value in key for string_value in invalid_strings):
  35. raise JWKError(
  36. "The specified key is an asymmetric key or x509 certificate and"
  37. " should not be used as an HMAC secret."
  38. )
  39. self.prepared_key = key
  40. def _process_jwk(self, jwk_dict):
  41. if not jwk_dict.get("kty") == "oct":
  42. raise JWKError("Incorrect key type. Expected: 'oct', Received: %s" % jwk_dict.get("kty"))
  43. k = jwk_dict.get("k")
  44. k = k.encode("utf-8")
  45. k = bytes(k)
  46. k = base64url_decode(k)
  47. return k
  48. def sign(self, msg):
  49. return hmac.new(self.prepared_key, msg, self._hash_alg).digest()
  50. def verify(self, msg, sig):
  51. return hmac.compare_digest(sig, self.sign(msg))
  52. def to_dict(self):
  53. return {
  54. "alg": self._algorithm,
  55. "kty": "oct",
  56. "k": base64url_encode(self.prepared_key).decode("ASCII"),
  57. }