You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

77 lines
2.2 KiB

import hashlib
import hmac
import os
from jose.backends.base import Key
from jose.constants import ALGORITHMS
from jose.exceptions import JWKError
from jose.utils import base64url_decode, base64url_encode
def get_random_bytes(num_bytes):
return bytes(os.urandom(num_bytes))
class HMACKey(Key):
"""
Performs signing and verification operations using HMAC
and the specified hash function.
"""
HASHES = {ALGORITHMS.HS256: hashlib.sha256, ALGORITHMS.HS384: hashlib.sha384, ALGORITHMS.HS512: hashlib.sha512}
def __init__(self, key, algorithm):
if algorithm not in ALGORITHMS.HMAC:
raise JWKError("hash_alg: %s is not a valid hash algorithm" % algorithm)
self._algorithm = algorithm
self._hash_alg = self.HASHES.get(algorithm)
if isinstance(key, dict):
self.prepared_key = self._process_jwk(key)
return
if not isinstance(key, str) and not isinstance(key, bytes):
raise JWKError("Expecting a string- or bytes-formatted key.")
if isinstance(key, str):
key = key.encode("utf-8")
invalid_strings = [
b"-----BEGIN PUBLIC KEY-----",
b"-----BEGIN RSA PUBLIC KEY-----",
b"-----BEGIN CERTIFICATE-----",
b"ssh-rsa",
]
if any(string_value in key for string_value in invalid_strings):
raise JWKError(
"The specified key is an asymmetric key or x509 certificate and"
" should not be used as an HMAC secret."
)
self.prepared_key = key
def _process_jwk(self, jwk_dict):
if not jwk_dict.get("kty") == "oct":
raise JWKError("Incorrect key type. Expected: 'oct', Received: %s" % jwk_dict.get("kty"))
k = jwk_dict.get("k")
k = k.encode("utf-8")
k = bytes(k)
k = base64url_decode(k)
return k
def sign(self, msg):
return hmac.new(self.prepared_key, msg, self._hash_alg).digest()
def verify(self, msg, sig):
return hmac.compare_digest(sig, self.sign(msg))
def to_dict(self):
return {
"alg": self._algorithm,
"kty": "oct",
"k": base64url_encode(self.prepared_key).decode("ASCII"),
}