def decode(buffer: bytes, **kwargs) -> object: """ Decodes a JWK JSON string into an RSA object. Parameters: buffer (bytes/str): JWK JSON string. Returns: RSA: RSA object. """ from samson.public_key.rsa import RSA if issubclass(type(buffer), (bytes, bytearray)): buffer = buffer.decode() jwk = json.loads(buffer) n = Bytes(url_b64_decode(jwk['n'].encode('utf-8'))).int() e = Bytes(url_b64_decode(jwk['e'].encode('utf-8'))).int() if 'p' in jwk: p = Bytes(url_b64_decode(jwk['p'].encode('utf-8'))).int() q = Bytes(url_b64_decode(jwk['q'].encode('utf-8'))).int() else: p = 2 q = 3 rsa = RSA(8, p=p, q=q, e=e) rsa.n = n rsa.bits = rsa.n.bit_length() return rsa
def decrypt(self, kek: bytes, encrypted_key: bytes, header: dict) -> Bytes: rij = Rijndael(kek) gcm = GCM(rij) return gcm.decrypt( url_b64_decode(header['iv'].encode('utf-8')), encrypted_key + url_b64_decode(header['tag'].encode('utf-8')), b'')
def decode(buffer: bytes, **kwargs) -> object: """ Decodes a JWK JSON string into an ECDSA object. Parameters: buffer (bytes/str): JWK JSON string. Returns: ECDSA: ECDSA object. """ from samson.public_key.ecdsa import ECDSA if issubclass(type(buffer), (bytes, bytearray)): buffer = buffer.decode() jwk = json.loads(buffer) curve = JWK_INVERSE_CURVE_LOOKUP[jwk['crv']] x = Bytes(url_b64_decode(jwk['x'].encode('utf-8'))).int() y = Bytes(url_b64_decode(jwk['y'].encode('utf-8'))).int() if 'd' in jwk: d = Bytes(url_b64_decode(jwk['d'].encode('utf-8'))).int() else: d = 0 ecdsa = ECDSA(G=curve.G, hash_obj=None, d=d) ecdsa.Q = curve(x, y) return ecdsa
def decode(buffer: bytes, **kwargs) -> object: """ Decodes a JWK JSON string into EdDSA parameters. Parameters: buffer (bytes/str): JWK JSON string. Returns: EdDSA: EdDSA object. """ from samson.public_key.eddsa import EdDSA from samson.protocols.dh25519 import DH25519 if issubclass(type(buffer), (bytes, bytearray)): buffer = buffer.decode() jwk = json.loads(buffer) curve = JWK_INVERSE_CURVE_LOOKUP[jwk['crv']] x = Bytes(url_b64_decode(jwk['x'].encode('utf-8')), 'little') if 'd' in jwk: d = Bytes(url_b64_decode(jwk['d'].encode('utf-8'))).int() else: d = 0 if jwk['crv'] in ['Ed25519', 'Ed448']: eddsa = EdDSA(curve=curve, d=d) eddsa.A = eddsa.decode_point(x) else: eddsa = DH25519(curve=curve, d=d, pub=x.int()) return eddsa
def process_signature(jws_dict: dict, payload: bytes) -> (JWS, dict): """ Internal method to decode signatures. """ jws = JWS(url_b64_decode(jws_dict['protected'].encode('utf-8')), payload, url_b64_decode(jws_dict['signature'].encode('utf-8'))) unprotected_header = jws_dict['header'] if 'header' in jws_dict else {} return (jws, unprotected_header)
def derive(self, kek: tuple, derived_length: int, header: dict) -> Bytes: from samson.encoding.general import PKIAutoParser # Support input formats # 1) (priv, pub): Allows user to specify their own private key. if type(kek) is tuple: priv_key, peer_pub = kek # 2) priv: Pull 'epk from header. Used in decryption. elif 'epk' in header: priv_key = kek peer_pub = PKIAutoParser.import_key( json.dumps(header['epk']).encode('utf-8')) # 3) pub: Ephemeral private key. else: priv_key = ECDHE(G=kek.curve.G) peer_pub = kek # Need to clean up priv and pub keys if type(priv_key) is ECDSA: priv_key = ECDHE(d=priv_key.d, G=priv_key.G) if hasattr(peer_pub, 'Q'): peer_pub = peer_pub.Q elif hasattr(peer_pub, 'pub'): peer_pub = peer_pub.pub # Add 'epk' header if not present if not 'epk' in header: if type(priv_key) in [ECDSA, ECDHE]: encoded_key = ECDSA( G=priv_key.G, d=priv_key.d).export_public_key(encoding=PKIEncoding.JWK) else: encoded_key = JWKEdDSAPublicKey.encode(priv_key) header['epk'] = json.loads(encoded_key.decode()) # Actual key derivation process agreement_key = priv_key.derive_key(peer_pub) apu = url_b64_decode( header['apu'].encode('utf-8')) if 'apu' in header else b'' apv = url_b64_decode( header['apv'].encode('utf-8')) if 'apv' in header else b'' alg_id = header[self.key_alg].encode('utf-8') other_info = b''.join([ Bytes(len(item)).zfill(4) + Bytes.wrap(item) for item in [alg_id, apu, apv] ]) + Bytes(derived_length * 8).zfill(4) kdf = ConcatKDF(SHA256(), derived_length) return kdf.derive(agreement_key, other_info)
def encrypt(self, kek: bytes, cek: bytes, header: dict) -> Bytes: rij = Rijndael(kek) gcm = GCM(rij) ct_and_tag = gcm.encrypt(url_b64_decode(header['iv'].encode('utf-8')), cek, b'') header['tag'] = url_b64_encode(ct_and_tag[-16:]).decode() return ct_and_tag[:-16]
def derive_key(self, kek: bytes, header: dict) -> Bytes: derived_salt = header['alg'].encode() + b'\x00' + url_b64_decode( header['p2s'].encode('utf-8')) # kdf = PBKDF2(self.hash_fn, self.hash_obj.digest_size // 2, header['p2c']) # derived_key = kdf.derive(kek, derived_salt) derived_key = hashlib.pbkdf2_hmac(self.hash_obj().name, kek, derived_salt, header['p2c'], self.hash_obj().digest_size // 2) return derived_key
def parse(token: bytes) -> object: """ Parses a compact bytestring `token` into a JWS object. Parameters: token (bytes): The JWS token to parse. Returns: JWS: JWS representation. """ header, body, signature = [ url_b64_decode(part) for part in token.split(b'.') ] return JWS(header, body, Bytes.wrap(signature))
def test(self): known_jwk = '{"kty": "oct", "k": "QqzzWH1tYqQO48IDvW7VH7gvJz89Ita7G6APhV-uLMo"}' correct_decoding = url_b64_decode( b'QqzzWH1tYqQO48IDvW7VH7gvJz89Ita7G6APhV-uLMo') # Decode as string decoded = JWKOctKey.decode(known_jwk) self.assertEqual(decoded, correct_decoding) # Decode as bytes decoded = JWKOctKey.decode(known_jwk.encode('utf-8')) self.assertEqual(decoded, correct_decoding) # Encode encoded = JWKOctKey.encode(decoded) self.assertEqual(encoded, known_jwk.encode('utf-8')) # Check function self.assertTrue(JWKOctKey.check(known_jwk)) self.assertTrue(JWKOctKey.check(known_jwk.encode('utf-8'))) self.assertFalse(JWKOctKey.check(b''))
def parse(token: bytes) -> object: """ Parses a JSON bytestring `token` into a JWSSet object. Parameters: token (bytes): The JWSSet token to parse. Returns: JWSSet: JWSSet representation. """ token_dict = json.loads(token.decode()) payload = url_b64_decode(token_dict['payload'].encode('utf-8')) # Is this a flattened token? if 'signature' in token_dict: jwsset = JWSSet(payload, [JWSSet.process_signature(token_dict, payload)]) else: jwsset = JWSSet(payload) for jws_dict in token_dict['signatures']: jwsset.signatures.append( JWSSet.process_signature(jws_dict, payload)) return jwsset