def newServerKeys(path, keyid): skey = JWK(generate='RSA', use='sig', kid=keyid) ekey = JWK(generate='RSA', use='enc', kid=keyid) with open(path, 'w') as f: os.fchmod(f.fileno(), 0o600) os.fchown(f.fileno(), 0, 0) f.write('[%s,%s]' % (skey.export(), ekey.export())) return [skey.get_op_key('verify'), ekey.get_op_key('encrypt')]
def server_keys(self): if self._server_keys is None: with open(self.config['server_keys']) as f: jsonkeys = f.read() dictkeys = json_decode(jsonkeys) self._server_keys = (JWK(**dictkeys[KEY_USAGE_SIG]), JWK(**dictkeys[KEY_USAGE_ENC])) return self._server_keys
def test_4_KEMClient_SET(self): server_keys = [JWK(**test_keys[kem.KEY_USAGE_SIG]), None] client_keys = [JWK(**self.client_keys[kem.KEY_USAGE_SIG]), JWK(**self.client_keys[kem.KEY_USAGE_ENC])] cli = kem.KEMClient(server_keys, client_keys) kh = kem.KEMHandler({'KEMKeysStore': self.kk}) req = cli.make_request("key name", "key value") kh.parse(req, "key name") self.assertEqual(kh.payload, "key value")
def server_keys(self): if self._server_keys is None: if 'server_keys' not in self.config: raise UnknownPublicKey("Server Keys not defined") skey = self.find_key(self.config['server_keys'], KEY_USAGE_SIG) ekey = self.find_key(self.config['server_keys'], KEY_USAGE_ENC) self._server_keys = [JWK(**(json_decode(skey))), JWK(**(json_decode(ekey)))] return self._server_keys
def parse(self, msg, name): """Parses the message. We check that the message is properly formatted. :param msg: a json-encoded value containing a JWS or JWE+JWS token :raises InvalidMessage: if the message cannot be parsed or validated :returns: A verified payload """ try: jtok = JWT(jwt=msg) except Exception as e: raise InvalidMessage('Failed to parse message: %s' % str(e)) try: token = jtok.token if isinstance(token, JWE): token.decrypt(self.kkstore.server_keys[KEY_USAGE_ENC]) # If an encrypted payload is received then there must be # a nested signed payload to verify the provenance. payload = token.payload.decode('utf-8') token = JWS() token.deserialize(payload) elif isinstance(token, JWS): pass else: raise TypeError("Invalid Token type: %s" % type(jtok)) # Retrieve client keys for later use self.client_keys = [ JWK(**self._get_key(token.jose_header, KEY_USAGE_SIG)), JWK(**self._get_key(token.jose_header, KEY_USAGE_ENC)) ] # verify token and get payload token.verify(self.client_keys[KEY_USAGE_SIG]) claims = json_decode(token.payload) except Exception as e: logger.debug('Failed to validate message', exc_info=True) raise InvalidMessage('Failed to validate message: %s' % str(e)) check_kem_claims(claims, name) self.name = name self.payload = claims.get('value') self.msg_type = 'kem' return { 'type': self.msg_type, 'value': { 'kid': self.client_keys[KEY_USAGE_ENC].key_id, 'claims': claims } }
def _decode_key(self, key): if key is None: return None elif isinstance(key, JWK): return key elif isinstance(key, dict): return JWK(**key) elif isinstance(key, str): return JWK(**(json_decode(key))) else: raise TypeError("Invalid key type")
def test_2_KEMClient(self): server_keys = [JWK(**test_keys[KEY_USAGE_SIG]), None] client_keys = [JWK(**self.client_keys[KEY_USAGE_SIG]), JWK(**self.client_keys[KEY_USAGE_ENC])] cli = KEMClient(server_keys, client_keys) kem = KEMHandler({'KEMKeysStore': self.kk}) req = cli.make_request("key name") kem.parse(req, "key name") msg = json_decode(kem.reply('key value')) rep = cli.parse_reply("key name", msg['value']) self.assertEqual(rep, 'key value')
def newJwk(**key_args): """Create a new JWK obkject with a 'kid' attribute that contains the key's thumbprint. """ from .keystore import keystore if not key_args: jwk = JWK(generate="EC", size=256) else: jwk = JWK(**key_args) jwk._params["kid"] = thumbprint(jwk) keystore().add(jwk) return jwk
def test_1_Parse_GET(self): cli_skey = JWK(**self.client_keys[0]) jtok = make_sig_kem("mykey", None, cli_skey, "RS256") kem = KEMHandler({'KEMKeysStore': self.kk}) kem.parse(jtok, "mykey") out = kem.reply('output') jtok = JWT(jwt=json_decode(out)['value']) cli_ekey = JWK(**self.client_keys[1]) jtok.token.decrypt(cli_ekey) nested = jtok.token.payload jtok = JWT(jwt=nested.decode('utf-8')) jtok.token.verify(JWK(**test_keys[0])) payload = json_decode(jtok.token.payload)['value'] self.assertEqual(payload, 'output')
def test_3_KEMClient(self): server_keys = [JWK(**test_keys[kem.KEY_USAGE_SIG]), JWK(**test_keys[kem.KEY_USAGE_ENC])] client_keys = [JWK(**self.client_keys[kem.KEY_USAGE_SIG]), JWK(**self.client_keys[kem.KEY_USAGE_ENC])] cli = kem.KEMClient(server_keys, client_keys) kh = kem.KEMHandler({'KEMKeysStore': self.kk}) req = cli.make_request("key name", encalg=('RSA-OAEP', 'A256CBC-HS512')) kh.parse(req, "key name") msg = kh.reply('key value') self.assertEqual(msg, json_decode(json_encode(msg))) rep = cli.parse_reply("key name", msg['value']) self.assertEqual(rep, 'key value')
def _verify(self, prop: str, key: JWK, alg: Optional[AlgorithmName], header: JsonObject, signer: Optional[JsonObject], patch_header: _PatchHeader) -> None: a = self._get_alg(alg, signer or header, InvalidJWSSignature) # Prepare payload for verification algorithm payload = copy(self._payload) h = copy(header) s = copy(signer) signature = base64url_decode((s or h).pop(_VALUE)) exclude = h.pop(_EXCLUDES, []) for x in exclude: payload.pop(x, None) h.update(patch_header(s)) payload[prop] = h canonical = _dumpb(payload) # Verify signature if key is None: key = JWK(**((s or h).get(_PUBLICKEY, None))) c = JWSCore(a, key, header=None, payload='', algs=self._allowed_algs) c.engine.verify(key, canonical, signature)
def _get_key(self, alg, key, p2s, p2c): if isinstance(key, bytes): plain = key else: plain = key.encode('utf8') salt = bytes(self.name.encode('utf8')) + b'\x00' + p2s if self.hashsize == 256: hashalg = hashes.SHA256() elif self.hashsize == 384: hashalg = hashes.SHA384() elif self.hashsize == 512: hashalg = hashes.SHA512() else: raise ValueError('Unknown Hash Size') kdf = PBKDF2HMAC(algorithm=hashalg, length=_inbytes(self.keysize), salt=salt, iterations=p2c, backend=self.backend) rk = kdf.derive(plain) if _bitsize(rk) != self.keysize: raise InvalidJWEKeyLength(self.keysize, len(rk)) return JWK(kty="oct", use="enc", k=base64url_encode(rk))
def dump_pem_to_jwks(in_private): try: from jwcrypto.jwk import JWK, JWKSet except ImportError as e: msg = "You have to install jwcrypto to use this function" print(msg) raise ImportError(msg) from e with open(in_private, "rb") as privfile: data = privfile.read() jwk = JWK() jwk.import_from_pem(data) jwks = JWKSet() jwks.add(jwk) raw = jwks.export(private_keys=True) formatted = json.dumps(json.loads(raw), indent=2) with open("private.json", "w") as priv_jwks_file: priv_jwks_file.write(formatted) raw = jwks.export(private_keys=False) formatted = json.dumps(json.loads(raw), indent=2) with open("public.json", "w") as public_jwks_file: public_jwks_file.write(formatted)
def wrap_fake(self, key, bitsize, cek, headers, point_x, point_y, aes_key): self._check_key(key) dk_size = self.keysize if self.keysize is None: if cek is not None: raise InvalidJWEOperation('ECDH-ES cannot use an existing CEK') alg = headers['enc'] dk_size = bitsize else: alg = headers['alg'] epk = JWK.generate(kty=key.key_type, crv=key.key_curve) dk = self._derive(epk.get_op_key('unwrapKey'), key.get_op_key('wrapKey'), alg, dk_size, headers) if self.keysize is None: ret = {'cek': aes_key} else: aeskw = self.aeskwmap[self.keysize]() kek = JWK(kty="oct", use="enc", k=base64url_encode(dk)) ret = aeskw.wrap(kek, bitsize, cek, headers) ret['header'] = { 'epk': { "crv": "P-256", "kty": "EC", "x": base64url_encode(int.to_bytes(point_x, 32, "big")), "y": base64url_encode(int.to_bytes(point_y, 32, "big")) } } return ret
def wrap(self, key, bitsize, cek, headers): self._check_key(key) dk_size = self.keysize if self.keysize is None: if cek is not None: raise InvalidJWEOperation('ECDH-ES cannot use an existing CEK') alg = headers['enc'] dk_size = bitsize else: alg = headers['alg'] epk = JWK.generate(kty=key.key_type, crv=key.key_curve) dk = self._derive(epk.get_op_key('unwrapKey'), key.get_op_key('wrapKey'), alg, dk_size, headers) if self.keysize is None: ret = {'cek': dk} else: aeskw = self.aeskwmap[self.keysize]() kek = JWK(kty="oct", use="enc", k=base64url_encode(dk)) ret = aeskw.wrap(kek, bitsize, cek, headers) ret['header'] = {'epk': json_decode(epk.export_public())} return ret
def make_tok(self, key, alg, name): pri_key = JWK(**key) protected = {"typ": "JOSE+JSON", "kid": key['kid'], "alg": alg} plaintext = {"sub": name, "exp": int(time.time()) + (5 * 60)} jws = JWS(payload=json_encode(plaintext)) jws.add_signature(pri_key, None, json_encode(protected)) return jws.serialize()
def gen_keys(key_size): try: from jwcrypto.jwk import JWK, JWKSet except ImportError as e: msg = "You have to install jwcrypto to use this function" print(msg) raise ImportError(msg) from e jwk = JWK() jwk.generate_key(generate="RSA", size=key_size) contents = jwk.export_to_pem(private_key=True, password=None) with open("private.pem", "w") as priv_pem_file: priv_pem_file.write(contents.decode("utf8")) contents = jwk.export_to_pem(private_key=False, password=None) with open("public.pem", "w") as priv_pem_file: priv_pem_file.write(contents.decode("utf8")) jwks = JWKSet() jwks.add(jwk) raw = jwks.export(private_keys=True) formatted = json.dumps(json.loads(raw), indent=2) with open("private.json", "w") as priv_jwks_file: priv_jwks_file.write(formatted) raw = jwks.export(private_keys=False) formatted = json.dumps(json.loads(raw), indent=2) with open("public.json", "w") as public_jwks_file: public_jwks_file.write(formatted)
def create_JWK(): """Create a private key and return it formatted as JWK """ # Generate the private key using Ethereum methods acc = Account.create( extra_entropy= "Alastria is the first Public-Permissioned Blockchain Network") # Get the public key publicKey = PublicKey.from_private(acc._key_obj) # The public key is 64 bytes composed of the x and y curve coordinates # x and y are each 32 bytes long # We convert x and y to hex, so the dictionary can be converted to JSON x = publicKey[:32] y = publicKey[32:] # Create the Json Web Key (JWK) representation, as specified by W3C DID Document format key_JWK = JWK(kty="EC", crv="secp256k1", d=base64url_encode(acc.privateKey), x=base64url_encode(x), y=base64url_encode(y)) return key_JWK
def setUp(self): k = Identity.generateKey() k.export = MagicMock(return_value=k.export()) k.export_public = MagicMock(return_value=k.export_public()) self.mocked_exports = k self.key = Identity.generateKey() self.public_key = JWK(**json.loads(self.key.export_public()))
def __init__(self, config, section): super(EncryptedOverlay, self).__init__(config, section) self.store_name = self.backing_store self.store = None if (not os.path.isfile(self.master_key) and self.autogen_master_key): # XXX https://github.com/latchset/jwcrypto/issues/50 size = self.key_sizes.get(self.master_enctype, 512) key = JWK(generate='oct', size=size) with open(self.master_key, 'w') as f: os.fchmod(f.fileno(), 0o600) f.write(key.export()) with open(self.master_key) as f: data = f.read() key = json_decode(data) self.mkey = JWK(**key)
def load_account(path): if not os.path.isfile(path): # 文件不存在 jwk = JWK.generate(kty='EC', crv='P-384') return {'jwk': jwk, 'uri': None} else: with open(path) as account_file: account = json_decode(account_file.read()) return {'jwk': JWK(**account['jwk']), 'uri': account['uri']}
def expiration_datetime_from_jwt_token(jwt_token: str, jwt_secret: str) -> datetime: key = JWK(kty='oct', k=jwt_secret) jwt = JWT(jwt=jwt_token, key=key) jwt_claims_json = jwt.claims claims = json.loads(jwt_claims_json) expiration_datetime = datetime.datetime.fromtimestamp(claims['exp']) return expiration_datetime
def generate(header, payload, priv_pem): priv_pem = json_decode(priv_pem.replace('\n', '\\n')) if priv_pem.startswith("-----BEGIN"): priv_key = JWK.from_pem(to_bytes_2and3(priv_pem)) else: priv_key = JWK(kty='oct', k=base64url_encode(priv_pem)) sig = JWS(payload) sig.add_signature(priv_key, protected=header) sys.stdout.write(sig.serialize(compact=True))
def _load_public(self, data): try: self._public = serialization.load_pem_public_key( b64decode(data), backend=self._backend) self._public_jwk = JWK() self._public_jwk.import_from_pyca(self._public) except Exception: # pragma: no cover LOGGER.error('Failed to parse public key starting with: %s', data[:26])
def _load_private(self, data): try: self._private = serialization.load_pem_private_key( b64decode(data), password=None, backend=self._backend) self._private_jwk = JWK() self._private_jwk.import_from_pyca(self._private) except Exception: # pragma: no cover LOGGER.error('Failed to parse private key starting with: %s', data[:28])
def verify(sjws, pub_pem): sjws = json_decode(sjws) pub_pem = json_decode(pub_pem.replace('\n', '\\n')) if pub_pem.startswith("-----BEGIN"): pub_key = JWK.from_pem(to_bytes_2and3(pub_pem)) else: pub_key = JWK(kty='oct', k=base64url_encode(pub_pem)) sig = JWS() sig.deserialize(sjws, pub_key) sys.stdout.write(base64url_decode(json_decode(sig.serialize())['payload']))
def jwkset(self): from authentic2.crypto import base64url_encode if self.idtoken_algo == self.ALGO_RSA: if self.jwkset_json: return JWKSet.from_json(json.dumps(self.jwkset_json)) if self.idtoken_algo == self.ALGO_HMAC: return JWK(kty='oct', k=base64url_encode(self.client_secret.encode('utf-8'))) return None
def unwrap(self, key, bitsize, ek, headers): if 'epk' not in headers: raise ValueError('Invalid Header, missing "epk" parameter') self._check_key(key) if self.keysize is None: alg = headers['enc'] else: bitsize = self.keysize alg = headers['alg'] epk = JWK(**headers['epk']) dk = self._derive(key.get_op_key('unwrapKey'), epk.get_op_key('wrapKey'), alg, bitsize, headers) if self.keysize is None: return dk else: aeskw = self.aeskwmap[bitsize]() kek = JWK(kty="oct", use="enc", k=base64url_encode(dk)) cek = aeskw.unwrap(kek, bitsize, ek, headers) return cek
def init_idp(self): self.keyset = JWKSet() with open(self.idp_key_file, 'r') as keyfile: loaded_keys = json.loads(keyfile.read()) for key in loaded_keys['keys']: self.keyset.add(JWK(**key)) static_store = OpenIDCStaticStore( self.get_config_value('static database url')) self.datastore = OpenIDCStore(self.get_config_value('database url'), static_store)
def __init__(self, config): super(EncryptedStore, self).__init__(config) if 'master_key' not in config: raise ValueError('Missing "master_key" for Encrypted Store') with open(config['master_key']) as f: data = f.read() key = json_decode(data) self.mkey = JWK(**key) if 'master_enctype' in config: self.enc = config['master_enctype'] else: self.enc = 'A256CBC_HS512'