def test_compact_rsa(self): jwe = JWE(algorithms=JWE_ALGORITHMS) s = jwe.serialize_compact({ 'alg': 'RSA-OAEP', 'enc': 'A256GCM' }, 'hello', read_file_path('rsa_public.pem')) data = jwe.deserialize_compact(s, read_file_path('rsa_private.pem')) header, payload = data['header'], data['payload'] self.assertEqual(payload, b'hello') self.assertEqual(header['alg'], 'RSA-OAEP')
def __init__(self, algorithms=None, private_headers=None): if algorithms is None: self._jws = JWS(JWS_ALGORITHMS, private_headers) self._jwe = JWE(JWE_ALGORITHMS, private_headers) else: self._jws = JWS(None, private_headers) self._jwe = JWE(None, private_headers) if isinstance(algorithms, (tuple, list)): for algorithm in algorithms: self.register_algorithm(algorithm) elif isinstance(algorithms, text_types): self.register_algorithm(algorithms)
def test_aes_jwe(self): jwe = JWE(algorithms=JWE_ALGORITHMS) sizes = [128, 192, 256] _enc_choices = [ 'A128CBC-HS256', 'A192CBC-HS384', 'A256CBC-HS512', 'A128GCM', 'A192GCM', 'A256GCM' ] for s in sizes: alg = 'A{}KW'.format(s) key = os.urandom(s // 8) for enc in _enc_choices: protected = {'alg': alg, 'enc': enc} data = jwe.serialize_compact(protected, b'hello', key) rv = jwe.deserialize_compact(data, key) self.assertEqual(rv['payload'], b'hello')
def deserialize_and_decrypt(self, auth_code): return str( JWE(JWE_ALGORITHMS).deserialize_compact( auth_code, self.privkey_data)['payload'], 'utf-8')
def encrypt_and_serialize(self, id_token): eprot = {'alg': 'RSA-OAEP', 'enc': 'A256GCM'} return JWE(JWE_ALGORITHMS).serialize_compact(eprot, id_token.encode('utf-8'), self.pubkey_data)
def test_register_invalid_algorithms(self): jwe = JWE(algorithms=[]) self.assertRaises(ValueError, jwe.register_algorithm, JWS_ALGORITHMS[0])
def test_ase_jwe_invalid_key(self): jwe = JWE(algorithms=JWE_ALGORITHMS) protected = {'alg': 'A128KW', 'enc': 'A128GCM'} self.assertRaises(ValueError, jwe.serialize_compact, protected, b'hello', b'invalid-key')
def test_not_enough_segments(self): s = 'a.b.c' jwe = JWE(algorithms=JWE_ALGORITHMS) self.assertRaises(errors.DecodeError, jwe.deserialize_compact, s, None)
class JWT(object): SENSITIVE_NAMES = ('password', 'token', 'secret', 'secret_key') # Thanks to sentry SensitiveDataFilter SENSITIVE_VALUES = re.compile(r'|'.join([ # http://www.richardsramblings.com/regex/credit-card-numbers/ r'\b(?:3[47]\d|(?:4\d|5[1-5]|65)\d{2}|6011)\d{12}\b', # various private keys r'-----BEGIN[A-Z ]+PRIVATE KEY-----.+-----END[A-Z ]+PRIVATE KEY-----', # social security numbers (US) r'^\b(?!(000|666|9))\d{3}-(?!00)\d{2}-(?!0000)\d{4}\b', ]), re.DOTALL) def __init__(self, algorithms=None, private_headers=None): if algorithms is None: self._jws = JWS(JWS_ALGORITHMS, private_headers) self._jwe = JWE(JWE_ALGORITHMS, private_headers) else: self._jws = JWS(None, private_headers) self._jwe = JWE(None, private_headers) if isinstance(algorithms, (tuple, list)): for algorithm in algorithms: self.register_algorithm(algorithm) elif isinstance(algorithms, text_types): self.register_algorithm(algorithms) def register_algorithm(self, algorithm): if isinstance(algorithm, text_types): algorithm = _AVAILABLE_ALGORITHMS.get(algorithm) if algorithm.TYPE == 'JWS': self._jws.register_algorithm(algorithm) elif algorithm.TYPE == 'JWE': self._jwe.register_algorithm(algorithm) def check_sensitive_data(self, payload): """Check if payload contains sensitive information.""" for k in payload: # check claims key name if k in self.SENSITIVE_NAMES: raise InsecureClaimError(k) # check claims values v = payload[k] if isinstance(v, text_types) and self.SENSITIVE_VALUES.search(v): raise InsecureClaimError(k) def encode(self, header, payload, key, check=True): """Encode a JWT with the given header, payload and key. :param header: A dict of JWS header :param payload: A dict to be encoded :param key: key used to sign the signature :param check: check if sensitive data in payload :return: JWT """ header['typ'] = 'JWT' for k in ['exp', 'iat', 'nbf']: # convert datetime into timestamp claim = payload.get(k) if isinstance(claim, datetime.datetime): payload[k] = calendar.timegm(claim.utctimetuple()) if check: self.check_sensitive_data(payload) key = load_key(key, header, payload) text = to_bytes(json.dumps(payload, separators=(',', ':'))) if 'enc' in header: return self._jwe.serialize_compact(header, text, key) else: return self._jws.serialize_compact(header, text, key) def decode(self, s, key, claims_cls=None, claims_options=None, claims_params=None): """Decode the JWS with the given key. This is similar with :meth:`verify`, except that it will raise BadSignatureError when signature doesn't match. :param s: text of JWT :param key: key used to verify the signature :param claims_cls: class to be used for JWT claims :param claims_options: `options` parameters for claims_cls :param claims_params: `params` parameters for claims_cls :return: claims_cls instance :raise: BadSignatureError """ if claims_cls is None: claims_cls = JWTClaims key_func = create_key_func(key) s = to_bytes(s) dot_count = s.count(b'.') if dot_count == 2: data = self._jws.deserialize_compact(s, key_func, decode_payload) elif dot_count == 4: data = self._jwe.deserialize_compact(s, key_func, decode_payload) else: raise DecodeError('Invalid input segments length') return claims_cls( data['payload'], data['header'], options=claims_options, params=claims_params, )