def pubkey_from_tpm2b_public(public: bytes) -> pubkey_type: (public, rest) = _extract_tpm2b(public) if len(rest) != 0: raise ValueError("More in tpm2b_public than tpmt_public") # Extract type, [nameAlg], and [objectAttributes] (we don't care about the # latter two) (alg_type, _, _) = struct.unpack(">HHI", public[0:8]) # Ignore the authPolicy (_, sym_parms) = _extract_tpm2b(public[8:]) # Ignore the non-asym-alg parameters (sym_mode, ) = struct.unpack(">H", sym_parms[0:2]) # Ignore the sym_mode and keybits (4 bytes), possibly symmetric (2) and sign # scheme (2) to_skip = 4 + 2 # sym_mode, keybits and sign scheme if sym_mode != TPM2_ALG_NULL: to_skip = to_skip + 2 asym_parms = sym_parms[to_skip:] # Handle fields if alg_type == TPM_ALG_RSA: (keybits, exponent) = struct.unpack(">HI", asym_parms[0:6]) if exponent == 0: exponent = 65537 (modulus, _) = _extract_tpm2b(asym_parms[6:]) if (len(modulus) * 8) != keybits: raise ValueError( f"Misparsed either modulus or keybits: {len(modulus)}*8 != {keybits}" ) bmodulus = int.from_bytes(modulus, byteorder="big") numbers = RSAPublicNumbers(exponent, bmodulus) return numbers.public_key(backend=default_backend()) if alg_type == TPM_ALG_ECC: (curve, _) = struct.unpack(">HH", asym_parms[0:4]) asym_x = asym_parms[4:] curve = _curve_from_curve_id(curve) (x, asym_y) = _extract_tpm2b(asym_x) (y, rest) = _extract_tpm2b(asym_y) if len(rest) != 0: raise ValueError("Misparsed: more contents after X and Y") if (len(x) * 8) != curve.key_size: raise ValueError( f"Misparsed either X or curve: {len(x)}*8 != {curve.key_size}") if (len(y) * 8) != curve.key_size: raise ValueError( f"Misparsed either Y or curve curve: {len(y)}*8 != {curve.key_size}" ) bx = int.from_bytes(x, byteorder="big") by = int.from_bytes(y, byteorder="big") numbers = EllipticCurvePublicNumbers(bx, by, curve) return numbers.public_key(backend=default_backend()) raise ValueError(f"Invalid tpm2b_public type: {alg_type}")
def verify(self): """ Verify the SSHCSR object in situ """ public_key = RSAPublicNumbers(self.public_key.e, self.public_key.n) try: public_key.public_key(default_backend()).verify( base64.b64decode(self.signature), self.json(False), padding.PKCS1v15(), hashes.SHA256()) return True except InvalidSignature: return False
def validate(self, message): """Verify the signature of self RSA fulfillment. The signature of self RSA fulfillment is verified against the provided message and the condition's public modulus. Args: message (bytes): Message to verify. Returns: bool: Whether self fulfillment is valid. """ if not isinstance(message, bytes): raise Exception('Message must be provided as bytes, was: ' + message) public_numbers = RSAPublicNumbers( PUBLIC_EXPONENT, int.from_bytes(self.modulus, byteorder='big'), ) public_key = public_numbers.public_key(default_backend()) try: public_key.verify( self.signature, message, padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=SALT_LENGTH, ), hashes.SHA256()) except InvalidSignature as exc: raise ValidationError('Invalid RSA signature') from exc return True
def test_response_values(app, client): """ Do some more thorough checking on the response obtained from the JWKS endpoint. Because fence only uses the RSA algorithm for signing and validating JWTs, the ``alg``, ``kty``, ``use``, and ``key_ops`` fields are hard-coded for this. Furthermore, every JWK in the response should have values for the RSA public modulus ``n`` and exponent ``e`` which may be used to reconstruct the public key. """ keys = client.get('/.well-known/jwks').json['keys'] app_kids = [keypair.kid for keypair in app.keypairs] app_public_keys = [keypair.public_key for keypair in app.keypairs] for key in keys: assert key['alg'] == 'RS256' assert key['kty'] == 'RSA' assert key['use'] == 'sig' assert key['key_ops'] == 'verify' assert key['kid'] in app_kids # Attempt to reproduce the public key from the values for the public # modulus and exponent provided in the response, using cryptography # primitives. n = int(base64.b64decode(key['n'])) e = int(base64.b64decode(key['e'])) numbers = RSAPublicNumbers(e, n) key = numbers.public_key(default_backend()) key_pem = key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) assert key_pem in app_public_keys
def _convert(exponent: int, modulus: int) -> bytearray: components = RSAPublicNumbers(exponent, modulus) pub = components.public_key(backend=default_backend()) key_bytes = pub.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo, ) return cast(bytearray, key_bytes)
def rsa_pem_from_jwk(jwk): public_num = RSAPublicNumbers(n=decode_value(jwk['n']), e=decode_value(jwk['e'])) public_key = public_num.public_key(default_backend()) pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) return pem
def get_PEM_from_RSA(self, modulus, exponent): exponent_long = self.base64_to_long(exponent) modulus_long = self.base64_to_long(modulus) numbers = RSAPublicNumbers(exponent_long, modulus_long) public_key = numbers.public_key(backend=default_backend()) pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) return pem
def jwk_to_pem(jwk): exponent = base64_to_long(jwk['e']) modulus = base64_to_long(jwk['n']) numbers = RSAPublicNumbers(exponent, modulus) public_key = numbers.public_key(backend=default_backend()) pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) return pem
def pemFromModExp(modulus, exponent): exponentlong = base64_to_long(exponent) moduluslong = base64_to_long(modulus) numbers = RSAPublicNumbers(exponentlong, moduluslong) public_key = numbers.public_key(backend=default_backend()) pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) return pem
def from_jwk(obj): if obj.get('kty') != 'RSA': raise InvalidKeyError('Not an RSA key') # Public key numbers = RSAPublicNumbers(from_base64url_uint(obj['e']), from_base64url_uint(obj['n'])) return numbers.public_key(default_backend())
def rsa_pem_from_jwk(jsonKeyResult): print(jsonKeyResult['keys'][0]['n']) exponent = base64_to_long(jsonKeyResult['keys'][0]['e']) modulus = base64_to_long(jsonKeyResult['keys'][0]['n']) numbers = RSAPublicNumbers(exponent, modulus) public_key = numbers.public_key(backend=default_backend()) pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) return pem
def jwk_to_pem(jwk_): # source: https://github.com/jpf/okta-jwks-to-pem/blob/master/jwks_to_pem.py exponent = base64_to_long(jwk_['e']) modulus = base64_to_long(jwk_['n']) numbers = RSAPublicNumbers(exponent, modulus) public_key = numbers.public_key(backend=default_backend()) pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo ) return pem
def from_jwk(jwk): if not isinstance(jwk, JsonWebKey): raise TypeError('The specified jwk must be a JsonWebKey') if jwk.kty != 'RSA' and jwk.kty != 'RSA-HSM': raise ValueError( 'The specified jwk must have a key type of "RSA" or "RSA-HSM"') if not jwk.n or not jwk.e: raise ValueError( 'Invalid RSA jwk, both n and e must be have values') rsa_key = _RsaKey() rsa_key.kid = jwk.kid rsa_key.kty = jwk.kty rsa_key.key_ops = jwk.key_ops pub = RSAPublicNumbers(n=_bytes_to_int(jwk.n), e=_bytes_to_int(jwk.e)) # if the private key values are specified construct a private key # only the secret primes and private exponent are needed as other fields can be calculated if jwk.p and jwk.q and jwk.d: # convert the values of p, q, and d from bytes to int p = _bytes_to_int(jwk.p) q = _bytes_to_int(jwk.q) d = _bytes_to_int(jwk.d) # convert or compute the remaining private key numbers dmp1 = _bytes_to_int(jwk.dp) if jwk.dp else rsa_crt_dmp1( private_exponent=d, p=p) dmq1 = _bytes_to_int(jwk.dq) if jwk.dq else rsa_crt_dmq1( private_exponent=d, q=q) iqmp = _bytes_to_int(jwk.qi) if jwk.qi else rsa_crt_iqmp(p=p, q=q) # create the private key from the jwk key values priv = RSAPrivateNumbers(p=p, q=q, d=d, dmp1=dmp1, dmq1=dmq1, iqmp=iqmp, public_numbers=pub) key_impl = priv.private_key( cryptography.hazmat.backends.default_backend()) # if the necessary private key values are not specified create the public key else: key_impl = pub.public_key( cryptography.hazmat.backends.default_backend()) rsa_key._rsa_impl = key_impl return rsa_key
def jwks_to_pem_keys(json_web_keys): pem_keys = [] for jwk in json_web_keys['keys']: exponent = base64_to_long(jwk['e']) modulus = base64_to_long(jwk['n']) numbers = RSAPublicNumbers(exponent, modulus) public_key = numbers.public_key(backend=default_backend()) pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) pem_keys.append(pem) return pem_keys
def _load_public_key(self, e, n): def to_int(x): bs = base64.urlsafe_b64decode(x + "==") return int.from_bytes(bs, byteorder="big") ei = to_int(e) ni = to_int(n) numbers = RSAPublicNumbers(ei, ni) public_key = numbers.public_key(backend=default_backend()) pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) return pem
def get_pem_public_key_from_modulus_exponent(n, e): def _b64decode(data): # padding to have multiple of 4 characters if len(data) % 4: data = data + '=' * (len(data) % 4) data = data.encode('ascii') data = bytes(data) return long(base64.urlsafe_b64decode(data).encode('hex'), 16) modulus = _b64decode(n) exponent = _b64decode(e) numbers = RSAPublicNumbers(exponent, modulus) public_key = numbers.public_key(backend=default_backend()) return public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo)
def from_jwk(cls, jwk): if jwk.kty != "RSA" and jwk.kty != "RSA-HSM": raise ValueError( 'The specified jwk must have a key type of "RSA" or "RSA-HSM"') if not jwk.n or not jwk.e: raise ValueError( "Invalid RSA jwk, both n and e must be have values") rsa_key = cls(kid=jwk.kid) rsa_key.kty = jwk.kty rsa_key.key_ops = jwk.key_ops pub = RSAPublicNumbers(n=_bytes_to_int(jwk.n), e=_bytes_to_int(jwk.e)) # if the private key values are specified construct a private key # only the secret primes and private exponent are needed as other fields can be calculated if jwk.p and jwk.q and jwk.d: # convert the values of p, q, and d from bytes to int p = _bytes_to_int(jwk.p) q = _bytes_to_int(jwk.q) d = _bytes_to_int(jwk.d) # convert or compute the remaining private key numbers dmp1 = _bytes_to_int(jwk.dp) if jwk.dp else rsa_crt_dmp1( private_exponent=d, p=p) dmq1 = _bytes_to_int(jwk.dq) if jwk.dq else rsa_crt_dmq1( private_exponent=d, q=q) iqmp = _bytes_to_int(jwk.qi) if jwk.qi else rsa_crt_iqmp(p=p, q=q) # create the private key from the jwk key values priv = RSAPrivateNumbers(p=p, q=q, d=d, dmp1=dmp1, dmq1=dmq1, iqmp=iqmp, public_numbers=pub) key_impl = priv.private_key(default_backend()) # if the necessary private key values are not specified create the public key else: key_impl = pub.public_key(default_backend()) rsa_key._rsa_impl = key_impl # pylint:disable=protected-access return rsa_key
def from_dict(cls, dct): if 'oth' in dct: raise UnsupportedKeyTypeError( 'RSA keys with multiples primes are not supported') try: e = uint_b64decode(dct['e']) n = uint_b64decode(dct['n']) except KeyError as why: raise MalformedJWKError('e and n are required') from why pub_numbers = RSAPublicNumbers(e, n) if 'd' not in dct: return cls( pub_numbers.public_key(backend=default_backend()), **dct) d = uint_b64decode(dct['d']) privparams = {'p', 'q', 'dp', 'dq', 'qi'} product = set(dct.keys()) & privparams if len(product) == 0: p, q = rsa_recover_prime_factors(n, e, d) priv_numbers = RSAPrivateNumbers( d=d, p=p, q=q, dmp1=rsa_crt_dmp1(d, p), dmq1=rsa_crt_dmq1(d, q), iqmp=rsa_crt_iqmp(p, q), public_numbers=pub_numbers) elif product == privparams: priv_numbers = RSAPrivateNumbers( d=d, p=uint_b64decode(dct['p']), q=uint_b64decode(dct['q']), dmp1=uint_b64decode(dct['dp']), dmq1=uint_b64decode(dct['dq']), iqmp=uint_b64decode(dct['qi']), public_numbers=pub_numbers) else: # If the producer includes any of the other private key parameters, # then all of the others MUST be present, with the exception of # "oth", which MUST only be present when more than two prime # factors were used. raise MalformedJWKError( 'p, q, dp, dq, qi MUST be present or' 'all of them MUST be absent') return cls(priv_numbers.private_key(backend=default_backend()), **dct)
def from_dict(cls, dct): if 'oth' in dct: raise UnsupportedKeyTypeError( 'RSA keys with multiples primes are not supported') try: e = uint_b64decode(dct['e']) n = uint_b64decode(dct['n']) except KeyError as why: raise MalformedJWKError('e and n are required') pub_numbers = RSAPublicNumbers(e, n) if 'd' not in dct: return cls( pub_numbers.public_key(backend=default_backend()), **dct) d = uint_b64decode(dct['d']) privparams = {'p', 'q', 'dp', 'dq', 'qi'} product = set(dct.keys()) & privparams if len(product) == 0: p, q = rsa_recover_prime_factors(n, e, d) priv_numbers = RSAPrivateNumbers( d=d, p=p, q=q, dmp1=rsa_crt_dmp1(d, p), dmq1=rsa_crt_dmq1(d, q), iqmp=rsa_crt_iqmp(p, q), public_numbers=pub_numbers) elif product == privparams: priv_numbers = RSAPrivateNumbers( d=d, p=uint_b64decode(dct['p']), q=uint_b64decode(dct['q']), dmp1=uint_b64decode(dct['dp']), dmq1=uint_b64decode(dct['dq']), iqmp=uint_b64decode(dct['qi']), public_numbers=pub_numbers) else: # If the producer includes any of the other private key parameters, # then all of the others MUST be present, with the exception of # "oth", which MUST only be present when more than two prime # factors were used. raise MalformedJWKError( 'p, q, dp, dq, qi MUST be present or' 'all of them MUST be absent') return cls(priv_numbers.private_key(backend=default_backend()), **dct)
def from_jwk(jwk): if not isinstance(jwk, JsonWebKey): raise TypeError('The specified jwk must be a JsonWebKey') if jwk.kty != 'RSA' and jwk.kty != 'RSA-HSM': raise ValueError('The specified jwk must have a key type of "RSA" or "RSA-HSM"') if not jwk.n or not jwk.e: raise ValueError('Invalid RSA jwk, both n and e must be have values') rsa_key = _RsaKey() rsa_key.kid = jwk.kid rsa_key.kty = jwk.kty rsa_key.key_ops = jwk.key_ops pub = RSAPublicNumbers(n=_bytes_to_int(jwk.n), e=_bytes_to_int(jwk.e)) # if the private key values are specified construct a private key # only the secret primes and private exponent are needed as other fields can be calculated if jwk.p and jwk.q and jwk.d: # convert the values of p, q, and d from bytes to int p = _bytes_to_int(jwk.p) q = _bytes_to_int(jwk.q) d = _bytes_to_int(jwk.d) # convert or compute the remaining private key numbers dmp1 = _bytes_to_int(jwk.dp) if jwk.dp else rsa_crt_dmp1(private_exponent=d, p=p) dmq1 = _bytes_to_int(jwk.dq) if jwk.dq else rsa_crt_dmq1(private_exponent=d, q=q) iqmp = _bytes_to_int(jwk.qi) if jwk.qi else rsa_crt_iqmp(p=p, q=q) # create the private key from the jwk key values priv = RSAPrivateNumbers(p=p, q=q, d=d, dmp1=dmp1, dmq1=dmq1, iqmp=iqmp, public_numbers=pub) key_impl = priv.private_key(cryptography.hazmat.backends.default_backend()) # if the necessary private key values are not specified create the public key else: key_impl = pub.public_key(cryptography.hazmat.backends.default_backend()) rsa_key._rsa_impl = key_impl return rsa_key
def wrap_aes_key_local(self, aes_key, public_key): """ Wraps AES key locally. Uses RSA-OAEP algorithm to wrap provided key. :param str aes_key: unencrypted AES key. :param str public_key: public part of RSA key. :return: String with encrypted AES key. """ int_n = self._bytes_to_int(public_key.n) int_e = self._bytes_to_int(public_key.e) public_numbers = RSAPublicNumbers(int_e, int_n) public_key = public_numbers.public_key(default_backend()) wrapped_key = public_key.encrypt( aes_key, padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), label=None)) return wrapped_key
def calculate_cost(self): """Calculate the cost of fulfilling self condition. The cost of the RSA condition is the size of the modulus squared, divided By 64. Returns: int: Expected maximum cost to fulfill self condition. """ if self.modulus is None: raise MissingDataError('Requires a public modulus') public_numbers = RSAPublicNumbers( PUBLIC_EXPONENT, int.from_bytes(self.modulus, byteorder='big'), ) public_key = public_numbers.public_key(default_backend()) modulus_bit_length = public_key.key_size # TODO watch out >> in Python is not the sane as JS >>>, may need to be # corrected. For instance see: # http://grokbase.com/t/python/python-list/0454t3tgaw/zero-fill-shift return int(math.pow(modulus_bit_length, 2)) >> RsaSha256.COST_RIGHT_SHIFT
def validate(self, message): """Verify the signature of self RSA fulfillment. The signature of self RSA fulfillment is verified against the provided message and the condition's public modulus. Args: message (bytes): Message to verify. Returns: bool: Whether self fulfillment is valid. """ if not isinstance(message, bytes): raise Exception( 'Message must be provided as bytes, was: ' + message) public_numbers = RSAPublicNumbers( PUBLIC_EXPONENT, int.from_bytes(self.modulus, byteorder='big'), ) public_key = public_numbers.public_key(default_backend()) verifier = public_key.verifier( self.signature, padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=SALT_LENGTH, ), hashes.SHA256() ) verifier.update(message) try: verifier.verify() except InvalidSignature as exc: raise ValidationError('Invalid RSA signature') from exc return True
def get_public_key(self, token, jwks_uri): headers = jwt.get_unverified_header(token) if headers is None or 'kid' not in headers: raise jwt.exceptions.InvalidTokenError( 'cannot extract kid from headers') kid = headers['kid'] jwks_content = self.get_http_content(jwks_uri) jwks = json.loads(jwks_content) jwk = None for j in jwks.get('keys', []): if j.get('kid') == kid: jwk = j if jwk is None: raise jwt.exceptions.InvalidTokenError( 'JWK not found for kid={0}'.format(kid, str(jwks))) public_num = RSAPublicNumbers(n=decode_value(jwk['n']), e=decode_value(jwk['e'])) public_key = public_num.public_key(default_backend()) pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) return pem
def calculate_cost(self): """Calculate the cost of fulfilling self condition. The cost of the RSA condition is the size of the modulus squared, divided By 64. Returns: int: Expected maximum cost to fulfill self condition. """ if self.modulus is None: raise MissingDataError('Requires a public modulus') public_numbers = RSAPublicNumbers( PUBLIC_EXPONENT, int.from_bytes(self.modulus, byteorder='big'), ) public_key = public_numbers.public_key(default_backend()) modulus_bit_length = public_key.key_size # TODO watch out >> in Python is not the sane as JS >>>, may need to be # corrected. For instance see: # http://grokbase.com/t/python/python-list/0454t3tgaw/zero-fill-shift return int(math.pow(modulus_bit_length, 2)) >> RsaSha256.COST_RIGHT_SHIFT
def validateToken(token, jwks_url): k_stackTrace = {} try: #k_stackTrace['message'] = "validateToken Start-->>" kid = get_KID(token) #k_stackTrace['kid'] = str(kid) alg = get_ALG(token) #k_stackTrace['alg'] = str(alg) k_stackTrace['jwks_url'] = jwks_url jwk_sets = get_jwks_json(token, jwks_url) jwk = get_matching_jwks(jwk_sets, kid, alg) #k_stackTrace['jwks_url'] = str(jwks_url) #k_stackTrace['jwk'] = str(jwk) exponent = base64_to_long(jwk['e']) #k_stackTrace['exponent'] = str(exponent) modulus = base64_to_long(jwk['n']) #k_stackTrace['modulus'] = str(modulus) numbers = RSAPublicNumbers(exponent, modulus) public_key = numbers.public_key(backend=default_backend()) #k_stackTrace['public_key'] = str(public_key) pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) secret = pem #k_stackTrace['secret/pem'] = str(secret) payload_decoded_and_verified = jwt.decode(token, secret, algorithms=[alg], verify=True) k_stackTrace[ 'payload_decoded_and_verified'] = payload_decoded_and_verified return k_stackTrace except Exception, e: k_stackTrace['exception'] = str(e) return k_stackTrace
def load_public_key(self): numbers = RSAPublicNumbers(base64_to_int(self._dict_data['e']), base64_to_int(self._dict_data['n'])) return numbers.public_key(default_backend())
def convert(exponent, modulus): components = RSAPublicNumbers(exponent, modulus) pub = components.public_key(backend=default_backend()) return pub.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo)
def __init__(self, password, modulus, exponent): self._password = password.encode('utf-8') modulus = int(modulus, 16) exponent = int(exponent, 16) public_numbers = RSAPublicNumbers(exponent, modulus) self.public_key = public_numbers.public_key(default_backend())
def intarr2long(arr): return int(''.join(["%02x" % byte for byte in arr]), 16) def base64_to_long(data): if isinstance(data, six.text_type): data = data.encode("ascii") # urlsafe_b64decode will happily convert b64encoded data _d = base64.urlsafe_b64decode(bytes(data) + b'==') return intarr2long(struct.unpack('%sB' % len(_d), _d)) print("Fetching JWKS from {}".format(args.org)) r = requests.get("https://{}/oauth2/v1/keys".format(args.org)) jwks = r.json() for jwk in jwks['keys']: exponent = base64_to_long(jwk['e']) modulus = base64_to_long(jwk['n']) numbers = RSAPublicNumbers(exponent, modulus) public_key = numbers.public_key(backend=default_backend()) pem = public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) print "PEM for KID '{}'".format(jwk['kid']) print pem
def __init__(self, params: Dict[int, Any]): super().__init__(params) self._key: Any = None self._hash: Any = None self._padding: Any = None salt_len: Any = padding.PSS.MAX_LENGTH # Validate kty. if params[1] != 3: raise ValueError("kty(1) should be RSA(3).") # Validate alg. if 3 not in params: raise ValueError("alg(3) not found.") if params[3] not in COSE_ALGORITHMS_RSA.values(): raise ValueError( f"Unsupported or unknown alg(3) for RSA: {params[3]}.") if params[3] == -259 or params[3] == -39: self._hash = hashes.SHA512 salt_len = 64 elif params[3] == -258 or params[3] == -38: self._hash = hashes.SHA384 salt_len = 48 elif params[3] == -257 or params[3] == -37: self._hash = hashes.SHA256 salt_len = 32 else: raise ValueError( f"Unsupported or unknown alg(3) for RSA: {params[3]}.") if params[3] in [-37, -38, -39]: self._padding = padding.PSS(mgf=padding.MGF1(self._hash()), salt_length=salt_len) else: self._padding = padding.PKCS1v15() # Validate key_ops. if -3 not in params: # the RSA private exponent d. if not self._key_ops: self._key_ops = RSAKey._ACCEPTABLE_PUBLIC_KEY_OPS else: prohibited = [ ops for ops in self._key_ops if ops not in RSAKey._ACCEPTABLE_PUBLIC_KEY_OPS ] if prohibited: raise ValueError( f"Unknown or not permissible key_ops(4) for RSAKey: {prohibited[0]}." ) else: if not self._key_ops: self._key_ops = RSAKey._ACCEPTABLE_PRIVATE_KEY_OPS else: prohibited = [ ops for ops in self._key_ops if ops not in RSAKey._ACCEPTABLE_PRIVATE_KEY_OPS ] if prohibited: raise ValueError( f"Unknown or not permissible key_ops(4) for RSAKey: {prohibited[0]}." ) # Validate RSA specific parameters. if -1 not in params or not isinstance(params[-1], bytes): raise ValueError("n(-1) should be set as bytes.") if -2 not in params or not isinstance(params[-2], bytes): raise ValueError("e(-2) should be set as bytes.") public_numbers = RSAPublicNumbers( n=int.from_bytes(params[-1], "big"), e=int.from_bytes(params[-2], "big"), ) self._dict = params if -3 not in params: # the RSA private exponent d. private_props = [ p for p in params.keys() if p in [-4, -5, -6, -7, -8] ] if private_props: raise ValueError( f"RSA public key should not have private parameter: {private_props[0]}." ) self._key = public_numbers.public_key() return if -3 not in params or not isinstance(params[-3], bytes): raise ValueError("d(-3) should be set as bytes.") if -4 not in params or not isinstance(params[-4], bytes): raise ValueError("p(-4) should be set as bytes.") if -5 not in params or not isinstance(params[-5], bytes): raise ValueError("q(-5) should be set as bytes.") if -6 not in params or not isinstance(params[-6], bytes): raise ValueError("dP(-6) should be set as bytes.") if -7 not in params or not isinstance(params[-7], bytes): raise ValueError("dQ(-7) should be set as bytes.") if -8 not in params or not isinstance(params[-8], bytes): raise ValueError("qInv(-8) should be set as bytes.") private_numbers = RSAPrivateNumbers( d=int.from_bytes(params[-3], "big"), p=int.from_bytes(params[-4], "big"), q=int.from_bytes(params[-5], "big"), dmp1=int.from_bytes(params[-6], "big"), dmq1=int.from_bytes(params[-7], "big"), iqmp=int.from_bytes(params[-8], "big"), public_numbers=public_numbers, ) self._key = private_numbers.private_key() return
def loads_public_key(self, obj): numbers = RSAPublicNumbers(base64_to_int(obj['e']), base64_to_int(obj['n'])) return numbers.public_key(default_backend())