def test_valid_ecdsa512(self): key = self.sk512 header = {'alg': 'ES512'} sinput, sig = jws.sign(header, self.payload, key) self.assertTrue(len(sig) > 0) self.assertTrue( jws.verify(header, self.payload, sig, key.get_verifying_key()))
def to_jwt(claim, algo, key): header = {'typ': 'JWT', 'alg': algo} return '.'.join([ jws.utils.encode(header), jws.utils.encode(claim), jws.sign(header, claim, key) ])
def test_custom_algorithm(self): class F7U12(jws.algos.AlgorithmBase): def __init__(self): pass def sign(self, msg, key): return 'u mad?' + key def verify(self, msg, sig, key): import sys if sys.version < '3': if sig == 'u mad?' + key: return '<trollface>' else: if sig == b'u mad?' + bytes(key, 'UTF-8'): return '<trollface>' raise jws.SignatureError('Y U NO GIVE GOOD SIGNATURE') jws.algos.CUSTOM = [('F7U12', F7U12)] header = {'alg': 'F7U12'} payload = {'some': 'claim'} sig = jws.sign(header, payload, 'wutlol') self.assertEqual(jws.verify(header, payload, sig, 'wutlol'), '<trollface>') self.assertRaises(jws.SignatureError, jws.verify, header, payload, sig, 'raaaaage')
def test_valid_rsa512(self): header = {'alg': 'RS512'} sinput,sig = jws.sign(header, self.payload, self.private) public = self.private.publickey() self.assertTrue(len(sig) > 0) self.assertTrue(jws.verify(header, self.payload, sig, public)) self.assertTrue(jws.verify(header, None, sig, public, signing_input=sinput))
def _sign(self, pdata, sks, dump_json_data): if not isinstance(sks, list): sks = [sks] jheader = '{"alg": "ES256"}' jheader_b64 = base64url_encode(jheader) jpayload = json.dumps(pdata) if dump_json_data else pdata jpayload_b64 = base64url_encode(jpayload) pdata_sig = {'payload': jpayload_b64, 'signatures': []} for sk in sks: sig_string_b64 = jws.sign(jheader, jpayload, sk, is_json=True) order = sk.curve.order sig_string = base64url_decode(sig_string_b64) r, s = sigdecode_string(sig_string, order) sig_der = sigencode_der(r, s, order) sig_der_b64 = base64url_encode(sig_der) pdata_sig['signatures'].append({'protected': jheader_b64, 'signature': sig_der_b64}) return pdata_sig
def sign_dict(data, key): data['_salt'] = ''.join( random.choice(string.ascii_lowercase + string.ascii_uppercase + string.digits) for _ in range(10)) data['_time'] = int(time.time()) data = OrderedDict(sorted(data.items())) data['_token'] = jws.sign({'alg': 'HS384'}, data, key).decode('utf-8') return data
def generate_jwt(claims, priv_key=None, algorithm='PS512', lifetime=None, expires=None, not_before=None, jti_size=16): """ Generate a JSON Web Token. :param claims: The claims you want included in the signature. :type claims: dict :param priv_key: The private key to be used to sign the token. Note: if you pass ``None`` then the token will be returned with an empty cryptographic signature and :obj:`algorithm` will be forced to the value ``none``. :type priv_key: `_RSAobj <https://www.dlitz.net/software/pycrypto/api/current/Crypto.PublicKey.RSA._RSAobj-class.html>`_ (for ``RSA*`` or ``PS*``), `SigningKey <https://github.com/warner/python-ecdsa>`_ (for ``ES*``) or str (for ``HS*``) :param algorithm: The algorithm to use for generating the signature. ``RS256``, ``RS384``, ``RS512``, ``PS256``, ``PS384``, ``PS512``, ``ES256``, ``ES384``, ``ES512``, ``HS256``, ``HS384``, ``HS512`` and ``none`` are supported. :type algorithm: str :param lifetime: How long the token is valid for. :type lifetime: datetime.timedelta :param expires: When the token expires (if :obj:`lifetime` isn't specified) :type expires: datetime.datetime :param not_before: When the token is valid from. Defaults to current time (if ``None`` is passed). :type not_before: datetime.datetime :param jti_size: Size in bytes of the unique token ID to put into the token (can be used to detect replay attacks). Defaults to 16 (128 bits). Specify 0 or ``None`` to omit the JTI from the token. :type jti_size: int :rtype: unicode :returns: The JSON Web Token. Note this includes a header, the claims and a cryptographic signature. The following extra claims are added, per the `JWT spec <http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html>`_: - **exp** (*IntDate*) -- The UTC expiry date and time of the token, in number of seconds from 1970-01-01T0:0:0Z UTC. - **iat** (*IntDate*) -- The UTC date and time at which the token was generated. - **nbf** (*IntDate*) -- The UTC valid-from date and time of the token. - **jti** (*str*) -- A unique identifier for the token. """ header = {'typ': 'JWT', 'alg': algorithm if priv_key else 'none'} claims = dict(claims) now = datetime.utcnow() if jti_size: claims['jti'] = urlsafe_b64encode(urandom(jti_size)).decode('utf-8') claims['nbf'] = timegm((not_before or now).utctimetuple()) claims['iat'] = timegm(now.utctimetuple()) if lifetime: claims['exp'] = timegm((now + lifetime).utctimetuple()) elif expires: claims['exp'] = timegm(expires.utctimetuple()) return u'%s.%s.%s' % (jws.utils.encode(header).decode('utf-8'), jws.utils.encode(claims).decode('utf-8'), '' if header['alg'] == 'none' else jws.sign( header, claims, priv_key).decode('utf-8'))
def test_valid_rsa512(self): header = {'alg': 'RS512'} sinput, sig = jws.sign(header, self.payload, self.private) public = self.private.publickey() self.assertTrue(len(sig) > 0) self.assertTrue(jws.verify(header, self.payload, sig, public)) self.assertTrue( jws.verify(header, None, sig, public, signing_input=sinput))
def test_invalid_ecdsa_decode(self): header = {"alg": "ES256"} sig = jws.sign(header, self.payload, self.sk256) vk = self.sk256.get_verifying_key() badkey = self.sk384.get_verifying_key() self.assertRaises(jws.SignatureError, jws.verify, header, self.payload, "not a good sig", vk) self.assertRaises(jws.SignatureError, jws.verify, header, {"bad": 1}, sig, vk) self.assertRaises(jws.SignatureError, jws.verify, header, {"bad": 1}, sig, badkey)
def test_invalid_ecdsa_decode(self): header = {'alg': 'ES256'} sig = jws.sign(header, self.payload, self.sk256) vk = self.sk256.get_verifying_key() badkey = self.sk384.get_verifying_key() self.assertRaises(jws.SignatureError, jws.verify, header, self.payload, 'not a good sig', vk) self.assertRaises(jws.SignatureError, jws.verify, header, {'bad':1}, sig, vk) self.assertRaises(jws.SignatureError, jws.verify, header, {'bad':1}, sig, badkey)
def generate_jwt(claims, priv_key=None, algorithm='PS512', lifetime=None, expires=None, not_before=None): """ Generate a JSON Web Token. :param claims: The claims you want included in the signature. :type claims: dict :param priv_key: The private key to be used to sign the token. Note: if you pass ``None`` then the token will be returned with an empty cryptographic signature and :obj:`algorithm` will be forced to the value ``none``. :type priv_key: `_RSAobj <https://www.dlitz.net/software/pycrypto/api/current/Crypto.PublicKey.RSA._RSAobj-class.html>`_, `SigningKey <https://github.com/warner/python-ecdsa>`_ or str :param algorithm: The algorithm to use for generating the signature. ``RS256``, ``RS384``, ``RS512``, ``PS256``, ``PS384``, ``PS512``, ``ES256``, ``ES384``, ``ES512``, ``HS256``, ``HS384``, ``HS512`` and ``none`` are supported. :type algorithm: str :param lifetime: How long the token is valid for. :type lifetime: datetime.timedelta :param expires: When the token expires (if :obj:`lifetime` isn't specified) :type expires: datetime.datetime :param not_before: When the token is valid from. Defaults to current time (if ``None`` is passed). :type not_before: datetime.datetime :rtype: str :returns: The JSON Web Token. Note this includes a header, the claims and a cryptographic signature. The following extra claims are added, per the `JWT spec <http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html>`_: - **exp** (*IntDate*) -- The UTC expiry date and time of the token, in number of seconds from 1970-01-01T0:0:0Z UTC. - **iat** (*IntDate*) -- The UTC date and time at which the token was generated. - **nbf** (*IntDate*) -- The UTC valid-from date and time of the token. - **jti** (*str*) -- A unique identifier for the token. """ header = { 'typ': 'JWT', 'alg': algorithm if priv_key else 'none' } claims = dict(claims) now = datetime.utcnow() claims['jti'] = urlsafe_b64encode(urandom(128)) claims['nbf'] = timegm((not_before or now).utctimetuple()) claims['iat'] = timegm(now.utctimetuple()) if lifetime: claims['exp'] = timegm((now + lifetime).utctimetuple()) elif expires: claims['exp'] = timegm(expires.utctimetuple()) return "%s.%s.%s" % ( jws.utils.encode(header), jws.utils.encode(claims), '' if header['alg'] == 'none' else jws.sign(header, claims, priv_key) )
def generate(header, payload, priv_pem): priv_pem = json.loads(priv_pem.replace('\n', '\\n')) if priv_pem.startswith("-----BEGIN"): priv_key = RSA.importKey(priv_pem) else: priv_key = priv_pem sys.stdout.write("%s.%s.%s" % ( jws.utils.to_base64(header), jws.utils.to_base64(payload), jws.sign(header, payload, priv_key, True) ))
def test_can_full_verify_with_revocation_check(self): input_assertion = json.loads(test_components['2_0_basic_assertion']) input_assertion['verification'] = {'type': 'signed', 'creator': 'http://example.org/key1'} set_up_image_mock(u'https://example.org/beths-robot-badge.png') input_badgeclass = json.loads(test_components['2_0_basic_badgeclass']) set_up_image_mock(input_badgeclass['image']) revocation_list = { '@context': OPENBADGES_CONTEXT_V2_URI, 'id': 'http://example.org/revocationList', 'type': 'RevocationList', 'revokedAssertions': []} input_issuer = json.loads(test_components['2_0_basic_issuer']) input_issuer['revocationList'] = revocation_list['id'] input_issuer['publicKey'] = input_assertion['verification']['creator'] private_key = RSA.generate(2048) print("PKEY") print(private_key.publickey().exportKey('PEM').decode()) cryptographic_key_doc = { '@context': OPENBADGES_CONTEXT_V2_URI, 'id': input_assertion['verification']['creator'], 'type': 'CryptographicKey', 'owner': input_issuer['id'], 'publicKeyPem': private_key.publickey().exportKey('PEM').decode() } set_up_context_mock() for doc in [input_assertion, input_badgeclass, input_issuer, cryptographic_key_doc, revocation_list]: responses.add(responses.GET, doc['id'], json=doc, status=200) header = json.dumps({'alg': 'RS256'}) payload = json.dumps(input_assertion) encoded_separator = '.' if not sys.version[:3] < '3': encoded_separator = '.'.encode() encoded_header = b64encode(header.encode()) encoded_payload = b64encode(payload.encode()) else: encoded_header = b64encode(header) encoded_payload = b64encode(payload) signature = encoded_separator.join([ encoded_header, encoded_payload, jws.sign(header, payload, private_key, is_json=True) ]) response = verify(signature, use_cache=False) self.assertTrue(response['report']['valid'])
def return_signed_data(data): try: key = get_key() header = {'alg': 'RS256'} sig = jws.sign(header, data, key) except MintUserException: raise # re-raise key exception, don't log again. except Exception as err: signing_failed = '. Signing failed. Check logs. ' raise MintUserException(signing_failed) else: return str(sig)
def test_custom_algorithm(self): class F7U12(jws.algos.AlgorithmBase): def __init__(self): pass def sign(self, msg, key): return 'u mad?' + key def verify(self, msg, sig, key): if sig == 'u mad?' + key: return '<trollface>' raise jws.SignatureError('Y U NO GIVE GOOD SIGNATURE') jws.algos.CUSTOM = [ ('F7U12', F7U12) ] header = {'alg': 'F7U12'} payload = {'some': 'claim'} sig = jws.sign(header, payload, 'wutlol') self.assertEqual(jws.verify(header,payload,sig, 'wutlol'), '<trollface>') self.assertRaises(jws.SignatureError, jws.verify, header, payload, sig, 'raaaaage')
def setUp(self): self.private_key = RSA.generate(2048) self.signing_key_doc = { 'id': 'http://example.org/key1', 'type': 'CryptographicKey', 'owner': 'http://example.org/issuer', 'publicKeyPem': self.private_key.publickey().exportKey('PEM') } self.issuer_data = { 'id': 'http://example.org/issuer', 'publicKey': 'http://example.org/key1' } self.badgeclass = {'id': '_:b1', 'issuer': 'http://example.org/issuer'} self.verification_object = { 'id': '_:b0', 'type': 'SignedBadge', 'creator': 'http://example.org/key1' } self.assertion_data = { 'id': 'urn:uuid:bf8d3c3d-fe60-487c-87a3-06440d0d0163', 'verification': '_:b0', 'badge': '_:b1' } header = {'alg': 'RS256'} payload = self.assertion_data signature = jws.sign(header, payload, self.private_key) encoded_separator = '.' if sys.version[:3] < '3': encoded_header = b64encode(json.dumps(header)) encoded_payload = b64encode(json.dumps(payload)) else: encoded_separator = '.'.encode() encoded_header = b64encode(json.dumps(header).encode()) encoded_payload = b64encode(json.dumps(payload).encode()) self.signed_assertion = encoded_separator.join( (encoded_header, encoded_payload, signature)) self.state = { 'graph': [ self.signing_key_doc, self.issuer_data, self.badgeclass, self.verification_object, self.assertion_data ] }
def _create_auth_token(self, sk, profile): jheader = '{"alg": "ES256"}' jheader_b64 = base64url_encode(jheader) body = {'id': profile.profile_id, 'timestamp': int(time.time())} jbody = json.dumps(body) jbody_b64 = base64url_encode(jbody) sig_string_b64 = jws.sign(jheader, jbody, sk, is_json=True) order = sk.curve.order sig_string = base64url_decode(sig_string_b64) r, s = sigdecode_string(sig_string, order) sig_der = sigencode_der(r, s, order) sig_der_b64 = base64url_encode(sig_der) return '{0}.{1}.{2}'.format(jheader_b64, jbody_b64, sig_der_b64)
def prepare(self, signer): """Timestamp and sign a notif in preparation for sending, updating, etc. Argument: signer -- Signer object specifying the private key and selector to use """ currtime = datetime.utcnow() self.expiration = datetime.isoformat(currtime + self.lifetime)+"Z" self.origtime = datetime.isoformat(currtime) + "Z" self.payload = json.dumps({"origtime": self.origtime, "priority": self.priority, "expires": self.expiration, "subject": self.subject, "body": self.body}) self.protected = json.dumps({ 'alg':'RS256', 'kid':signer.selector }) self.signature = jws.sign(self.protected, self.payload, signer.pk, True) return 0
def test_custom_algorithm(self): class F7U12(jws.algos.AlgorithmBase): def __init__(self): pass def sign(self, msg, key): return "u mad?" + key def verify(self, msg, sig, key): if sig == "u mad?" + key: return "<trollface>" raise jws.SignatureError("Y U NO GIVE GOOD SIGNATURE") jws.algos.CUSTOM = [("F7U12", F7U12)] header = {"alg": "F7U12"} payload = {"some": "claim"} sig = jws.sign(header, payload, "wutlol") self.assertEqual(jws.verify(header, payload, sig, "wutlol"), "<trollface>") self.assertRaises(jws.SignatureError, jws.verify, header, payload, sig, "raaaaage")
def signJsonArray(self, postArr, nonce = None): """ Signs the given array of post data with this key. It additionally can add some nonce to the jwsHeader, if nonce parameter is different from None. The returned value is a urlsafe base64 encoded string, containing the JWK header, the content and the JWS. @param postArr: The post array to be signed. @param nonce: An additional nonce to be added to the JWS header. @return: Base64 enconded JSON including JWS. """ jwsHeader = { 'typ' : 'JWT', 'alg': 'RS256', 'jwk' : self.getJwk() } if nonce is not None: jwsHeader['nonce'] = nonce postList = [jws.utils.encode(jwsHeader), jws.utils.encode(postArr), jws.sign(jwsHeader, postArr, self.__key)] postData = "%s.%s.%s" % tuple(postList) return postData
def prepare(self, signer): """Timestamp and sign a notif in preparation for sending, updating, etc. Argument: signer -- Signer object specifying the private key and selector to use """ currtime = datetime.utcnow() self.expiration = datetime.isoformat(currtime + self.lifetime) + "Z" self.origtime = datetime.isoformat(currtime) + "Z" self.payload = json.dumps({ "origtime": self.origtime, "priority": self.priority, "expires": self.expiration, "subject": self.subject, "body": self.body }) self.protected = json.dumps({'alg': 'RS256', 'kid': signer.selector}) self.signature = jws.sign(self.protected, self.payload, signer.pk, True) return 0
def signJsonArray(self, postArr, nonce=None): """ Signs the given array of post data with this key. It additionally can add some nonce to the jwsHeader, if nonce parameter is different from None. The returned value is a urlsafe base64 encoded string, containing the JWK header, the content and the JWS. @param postArr: The post array to be signed. @param nonce: An additional nonce to be added to the JWS header. @return: Base64 enconded JSON including JWS. """ jwsHeader = {'typ': 'JWT', 'alg': 'RS256', 'jwk': self.getJwk()} if nonce is not None: jwsHeader['nonce'] = nonce postList = [ jws.utils.encode(jwsHeader), jws.utils.encode(postArr), jws.sign(jwsHeader, postArr, self.__key) ] postData = "%s.%s.%s" % tuple(postList) return postData
def test_can_verify_jws(self): task_meta = add_task(VERIFY_JWS, data=self.signed_assertion, node_id=self.assertion_data['id']) success, message, actions = verify_jws_signature(self.state, task_meta) print("TEST CAN VERIFY JWS : success:") print(success) print("TEST CAN VERIFY JWS : message:") print(message) print("TEST CAN VERIFY JWS : actions:") print(actions) self.assertTrue(success) self.assertEqual(len(actions), 2) # Construct an invalid signature by adding to payload after signing, one theoretical attack. header = {'alg': 'RS256'} signature = jws.sign(header, self.assertion_data, self.private_key) self.assertion_data['evidence'] = 'http://hahafakeinserteddata.com' encoded_separator = '.' if sys.version[:3] < '3': encoded_header = b64encode(json.dumps(header)) encoded_payload = b64encode(json.dumps(self.assertion_data)) else: encoded_separator = '.'.encode() encoded_header = b64encode(json.dumps(header).encode()) encoded_payload = b64encode(json.dumps(self.assertion_data).encode()) self.signed_assertion = encoded_separator.join((encoded_header, encoded_payload, signature)) task_meta = add_task(VERIFY_JWS, data=self.signed_assertion, node_id=self.assertion_data['id']) success, message, actions = verify_jws_signature(self.state, task_meta) self.assertFalse(success) self.assertEqual(len(actions), 2)
def _login(self): def to_base64(s): return base64.urlsafe_b64encode(s).replace('=', '') header = {'alg': 'HS512'} body = { 'username': self.username, 'entity': self.entity, 'datetime': datetime.utcnow().isoformat('T') } signature = jws.sign(header, body, self.shared_secret) encoded_header = to_base64(json.dumps(header)) encoded_body = to_base64(json.dumps(body)) # signature is already encoded r = requests.get(self.api_url.format('/v1/cc/token'), params={ 'jws': '%s.%s.%s' % (encoded_header, encoded_body, signature), }) if r.status_code == 200: return r.content
def test_valid_ecdsa256(self): key = self.sk256 header = {"alg": "ES256"} sig = jws.sign(header, self.payload, key) self.assertTrue(len(sig) > 0) self.assertTrue(jws.verify(header, self.payload, sig, key.get_verifying_key()))
def test_valid_rsa384(self): header = {'alg': 'RS384'} sinput, sig = jws.sign(header, self.payload, self.private) public = self.private.publickey() self.assertTrue(len(sig) > 0) self.assertTrue(jws.verify(header, self.payload, sig, public))
def test_invalid_hmac(self): header = {'alg': 'HS512'} sinput, sig = jws.sign(header, self.payload, 'secret') self.assertRaises( jws.SignatureError(header, self.payload, sig, 'failwhale'))
def test_valid_hmac512(self): header = {'alg': 'HS512'} sinput, sig = jws.sign(header, self.payload, 'secret') self.assertTrue(len(sig) > 0) self.assertTrue(jws.verify(header, self.payload, sig, 'secret'))
def test_can_full_verify_jws_signed_assertion(self): """ I can input a JWS string I can extract the Assertion from the input signature string and store it as the canonical version of the Assertion. I can discover and retrieve key information from the Assertion. I can Access the signing key I can verify the key is associated with the listed issuer Profile I can verify the JWS signature has been created by a key trusted to correspond to the issuer Profile Next: I can verify an assertion with an ephemeral embedded badgeclass as well """ input_assertion = json.loads(test_components['2_0_basic_assertion']) input_assertion['verification'] = {'type': 'signed', 'creator': 'http://example.org/key1'} set_up_image_mock(u'https://example.org/beths-robot-badge.png') input_badgeclass = json.loads(test_components['2_0_basic_badgeclass']) set_up_image_mock(input_badgeclass['image']) input_issuer = json.loads(test_components['2_0_basic_issuer']) input_issuer['publicKey'] = input_assertion['verification']['creator'] private_key = RSA.generate(2048) cryptographic_key_doc = { '@context': OPENBADGES_CONTEXT_V2_URI, 'id': input_assertion['verification']['creator'], 'type': 'CryptographicKey', 'owner': input_issuer['id'], 'publicKeyPem': private_key.publickey().exportKey('PEM').decode() } set_up_context_mock() for doc in [input_assertion, input_badgeclass, input_issuer, cryptographic_key_doc]: responses.add(responses.GET, doc['id'], json=doc, status=200) header = json.dumps({'alg': 'RS256'}) payload = json.dumps(input_assertion) encoded_separator = '.' if not sys.version[:3] < '3': encoded_separator = '.'.encode() encoded_header = b64encode(header.encode()) encoded_payload = b64encode(payload.encode()) else: encoded_header = b64encode(header) encoded_payload = b64encode(payload) signature = encoded_separator.join([ encoded_header, encoded_payload, jws.sign(header,payload,private_key, is_json=True) ]) response = verify(signature, use_cache=False) print("TEST CAN FULLY VERIFY JWS SIGNED ASSERTION : response:") print(response['report']) self.assertTrue(response['report']['valid'])
def test_valid_rsa384_pkcs1_5(self): header = {'alg': 'RS384'} sig = jws.sign(header, self.payload, self.private) public = self.private.publickey() self.assertTrue(len(sig) > 0) self.assertTrue(jws.verify(header, self.payload, sig, public))
# otherwise raise a SignatureError def verify(self, msg, sig, key): if sig != self.sign(msg, key): raise SignatureError('nope') return True # algos.CUSTOM is a list that holds custom algorithms. # the format is [(routing_regex, algorithm_class)...] # # values from the 'alg' key in headers are run through each algorithm # routing_regex, stopping on the first one that matches. algos in the CUSTOM # list take precedence over the defaults -- note that this means you can add # override any default algorithms by defining a custom algorithm with a # routing_regex that matches one of the defaults. jws.algos.CUSTOM = [ # a regular expression with two named matching groups. # named groups will be sent to the class constructor (r'^(?P<fval>f+)(?P<uval>u+)$', FXUY), ] ## now this will be the algorithm discovered for any of the following headers: # will sign with FXUY(fval=3, uval=3).sign jws.sign({'alg': 'fffuuu'}, {'claim': 'rad'}, 'key') # will sign with FXUY(fval=1, uval=8).sign jws.sign({'alg': 'fuuuuuuuu'}, {'claim': 'rad'}, 'key') # will sign with FXUY(fval=7, uval=12).sign jws.sign({'alg': 'fffffffuuuuuuuuuuu'}, {'claim': 'rad'}, 'key')
def test_valid_ecdsa512(self): key = self.sk512 header = {'alg': 'ES512'} sig = jws.sign(header, self.payload, key) self.assertTrue(len(sig) > 0) self.assertTrue(jws.verify(header, self.payload, sig, key.get_verifying_key()))
def test_valid_hmac512(self): header = {'alg': 'HS512'} sig = jws.sign(header, self.payload, 'secret') self.assertTrue(len(sig) > 0) self.assertTrue(jws.verify(header, self.payload, sig, 'secret'))
def test_valid_rsa256(self): header = {"alg": "RS256"} sig = jws.sign(header, self.payload, self.private) public = self.private.publickey() self.assertTrue(len(sig) > 0) self.assertTrue(jws.verify(header, self.payload, sig, public))
def test_invalid_hmac(self): header = {"alg": "HS512"} sig = jws.sign(header, self.payload, "secret") self.assertRaises(jws.SignatureError(header, self.payload, sig, "failwhale"))
def test_valid_hmac512(self): header = {"alg": "HS512"} sig = jws.sign(header, self.payload, "secret") self.assertTrue(len(sig) > 0) self.assertTrue(jws.verify(header, self.payload, sig, "secret"))
def test_invalid_hmac(self): header = {'alg': 'HS512'} sig = jws.sign(header, self.payload, 'secret') self.assertRaises(jws.SignatureError(header, self.payload, sig, 'failwhale'))
import jws header = {'alg': 'HS256'} payload = {'name': 'Kuntal Samanta', 'age': '25'} # Creating signature signature = jws.sign(header, payload, 'key') # Validating signature res = jws.verify(header, payload, signature, 'key') print(res)
def test_valid_rsa512_pss(self): header = {'alg': 'PS512'} sig = jws.sign(header, self.payload, self.private) public = self.private.publickey() self.assertTrue(len(sig) > 0) self.assertTrue(jws.verify(header, self.payload, sig, public))
# verify should only return if the signature is valid. # otherwise raise a SignatureError def verify(self, msg, sig, key): if sig != self.sign(msg, key): raise SignatureError('nope') return True # algos.CUSTOM is a list that holds custom algorithms. # the format is [(routing_regex, algorithm_class)...] # # values from the 'alg' key in headers are run through each algorithm # routing_regex, stopping on the first one that matches. algos in the CUSTOM # list take precedence over the defaults -- note that this means you can add # override any default algorithms by defining a custom algorithm with a # routing_regex that matches one of the defaults. jws.algos.CUSTOM = [ # a regular expression with two named matching groups. # named groups will be sent to the class constructor (r'^(?P<fval>f+)(?P<uval>u+)$', FXUY), ] ## now this will be the algorithm discovered for any of the following headers: # will sign with FXUY(fval=3, uval=3).sign jws.sign({'alg': 'fffuuu'}, {'claim':'rad'}, 'key') # will sign with FXUY(fval=1, uval=8).sign jws.sign({'alg': 'fuuuuuuuu'}, {'claim':'rad'}, 'key') # will sign with FXUY(fval=7, uval=12).sign jws.sign({'alg': 'fffffffuuuuuuuuuuu'}, {'claim':'rad'}, 'key')
def test_revoked_badge_marked_invalid(self): input_assertion = json.loads(test_components['2_0_basic_assertion']) input_assertion['verification'] = {'type': 'signed', 'creator': 'http://example.org/key1'} input_badgeclass = json.loads(test_components['2_0_basic_badgeclass']) revocation_list = { '@context': OPENBADGES_CONTEXT_V2_URI, 'id': 'http://example.org/revocationList', 'type': 'RevocationList', 'revokedAssertions': [ {'id': input_assertion['id'], 'revocationReason': 'A good reason, for sure'}, {'id': 'urn:uuid:52e4c6b3-8c13-4fa8-8482-a5cf34ef37a9'}, 'urn:uuid:6deb4a00-ebce-4b28-8cc2-afa705ef7be4' ] } input_issuer = json.loads(test_components['2_0_basic_issuer']) input_issuer['revocationList'] = revocation_list['id'] input_issuer['publicKey'] = input_assertion['verification']['creator'] private_key = RSA.generate(2048) cryptographic_key_doc = { '@context': OPENBADGES_CONTEXT_V2_URI, 'id': input_assertion['verification']['creator'], 'type': 'CryptographicKey', 'owner': input_issuer['id'], 'publicKeyPem': make_string_from_bytes(private_key.publickey().exportKey('PEM')) } set_up_context_mock() for doc in [input_assertion, input_badgeclass, input_issuer, cryptographic_key_doc, revocation_list]: responses.add(responses.GET, doc['id'], json=doc, status=200) header = json.dumps({'alg': 'RS256'}) payload = json.dumps(input_assertion) encoded_separator = '.' if not sys.version[:3] < '3': encoded_separator = '.'.encode() encoded_header = b64encode(header.encode()) encoded_payload = b64encode(payload.encode()) else: encoded_header = b64encode(header) encoded_payload = b64encode(payload) signature = encoded_separator.join([ encoded_header, encoded_payload, jws.sign(header, payload, private_key, is_json=True) ]) response = verify(signature, use_cache=False) self.assertFalse(response['report']['valid']) msg = [a for a in response['report']['messages'] if a.get('name') == VERIFY_SIGNED_ASSERTION_NOT_REVOKED][0] self.assertIn('A good reason', msg['result']) # Assert pruning went well to eliminate revocationlist revokedAssertions except for the revoked one rev_list = [n for n in response['graph'] if n.get('id') == revocation_list['id']][0] self.assertEqual(len(rev_list['revokedAssertions']), 1) self.assertEqual(rev_list['revokedAssertions'], [revocation_list['revokedAssertions'][0]])
def sign_data(payload, priv_key = sk256): header = { 'alg': 'ES256' } sig = jws.sign(header, payload, priv_key) return payload, sig, vk