def __init__(self, key=None): if key is None: super().__init__() elif isinstance(key, PrivateKey): super().__init__(key) elif isinstance(key, X25519PrivateKey): super().__init__(key.private_bytes( encoding=serialization.Encoding.Raw, format=serialization.PrivateFormat.Raw, encryption_algorithm=serialization.NoEncryption(), )) elif isinstance(key, (bytes, bytearray)): super().__init__(X25519PrivateKey.from_private_bytes(key).private_bytes( encoding=serialization.Encoding.Raw, format=serialization.PrivateFormat.Raw, encryption_algorithm=serialization.NoEncryption(), )) elif isinstance(key, str): super().__init__(X25519PrivateKey.from_private_bytes(b64decode(key)).private_bytes( encoding=serialization.Encoding.Raw, format=serialization.PrivateFormat.Raw, encryption_algorithm=serialization.NoEncryption(), )) else: raise TypeError("key must be PrivateKey, bytes, bytearray, or str")
def test_x25519_unsupported(backend): with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM): X25519PublicKey.from_public_bytes(b"0" * 32) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM): X25519PrivateKey.from_private_bytes(b"0" * 32) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM): X25519PrivateKey.generate()
def x25519_key_derivation( self, public_key: 'OKP', context: CoseKDFContext = b'', alg: Optional[CoseAlgorithms] = None, curve: Optional[CoseEllipticCurves] = None) -> Tuple[bytes, bytes]: self._check_key_conf(alg, KeyOps.DERIVE_KEY, public_key, curve) try: alg_cfg = config(CoseAlgorithms(self.alg)) except KeyError as err: raise CoseIllegalAlgorithm(err) p = X25519PublicKey.from_public_bytes(public_key.x) d = X25519PrivateKey.from_private_bytes(self.d) shared_secret = d.exchange(p) derived_key = alg_cfg.kdf( algorithm=alg_cfg.hash(), length=int(context.supp_pub_info.key_data_length / 8), salt=None, info=context.encode(), backend=default_backend()).derive(shared_secret) return shared_secret, derived_key
def shared_secret(private_key: 'CK', public_key: 'CK') -> bytes: """ Compute the shared secret. """ if public_key.crv == X25519: d = X25519PrivateKey.from_private_bytes(private_key.d) x = X25519PublicKey.from_public_bytes(public_key.x) secret = d.exchange(x) elif public_key.crv == X448: d = X448PrivateKey.from_private_bytes(private_key.d) x = X448PublicKey.from_public_bytes(public_key.x) secret = d.exchange(x) elif public_key.crv == P256: d = ec.derive_private_key(int(hexlify(private_key.d), 16), SECP256R1(), default_backend()) x = ec.EllipticCurvePublicNumbers(int(hexlify(public_key.x), 16), int(hexlify(public_key.y), 16), SECP256R1()) x = x.public_key() secret = d.exchange(ec.ECDH(), x) else: raise CoseIllegalCurve(f"{public_key.crv} is unsupported") return secret
def get_shared_secret(client_private_key, server_public_key, cryptographic_group): # x25519 (x00 x1d) if cryptographic_group == b"\x00\x1d": private_key = X25519PrivateKey.from_private_bytes( client_private_key) public_key = X25519PublicKey.from_public_bytes(server_public_key) return private_key.exchange(public_key) # x448 (x00 x1e) elif cryptographic_group == b"\x00\x1e": private_key = X448PrivateKey.from_private_bytes(client_private_key) public_key = X448PublicKey.from_public_bytes(server_public_key) return private_key.exchange(public_key) # secp256r1 (x00 x17) elif cryptographic_group == b"\x00\x17": return Crypto_Helper.get_shared_secret_secpr1( client_private_key, server_public_key, SECP256R1) # secp384r1 (x00 x18) elif cryptographic_group == b"\x00\x18": return Crypto_Helper.get_shared_secret_secpr1( client_private_key, server_public_key, SECP384R1) # secp521r1 (x00 x19) elif cryptographic_group == b"\x00\x19": return Crypto_Helper.get_shared_secret_secpr1( client_private_key, server_public_key, SECP521R1)
def test_profileA(self): hn_privkey = unhexlify( 'c53c22208b61860b06c62e5406a7b330c2b577aa5558981510d128247d38bd1d') hn_pubkey = unhexlify( '5a8d38864820197c3394b92613b20b91633cbd897119273bf8e4a6f4eec0a650') eph_privkey = unhexlify( 'c80949f13ebe61af4ebdbd293ea4f942696b9e815d7e8f0096bbf6ed7de62256') eph_pubkey = unhexlify( 'b2e92f836055a255837debf850b528997ce0201cb82adfe4be1f587d07d8457d') shared_key = unhexlify( '028ddf890ec83cdf163947ce45f6ec1a0e3070ea5fe57e2b1f05139f3e82422a') # plaintext = bytes.fromhex('00012080f6') ciphertext = unhexlify('cb02352410') mactag = unhexlify('cddd9e730ef3fa87') x1 = X25519(eph_privkey) x2 = X25519(hn_privkey) ue = ECIES_UE(profile='A') ue.EC.priv_key = X25519PrivateKey.from_private_bytes(eph_privkey) hn = ECIES_HN(profile='A', hn_priv_key=hn_privkey) ue.generate_sharedkey(hn_pubkey, fresh=False) ue_pk, ue_ct, ue_mac = ue.protect(plaintext) hn_ct = hn.unprotect(ue_pk, ue_ct, ue_mac) self.assertEqual(x1.get_pubkey(), eph_pubkey) self.assertEqual(x1.generate_sharedkey(hn_pubkey), shared_key) self.assertEqual(x2.get_pubkey(), hn_pubkey) self.assertEqual(x2.generate_sharedkey(eph_pubkey), shared_key) self.assertEqual(ue_ct, ciphertext) self.assertEqual(ue_mac, mactag) self.assertEqual(hn_ct, plaintext)
def wg_derive_pubkey(privkey): privkey_data = base64.b64decode(privkey.encode("ascii")) x = X25519PrivateKey.from_private_bytes(privkey_data) p = x.public_key() pubkey_data = p.public_bytes(Encoding.Raw, PublicFormat.Raw) pubkey = base64.b64encode(pubkey_data) return pubkey.decode("ascii")
def main(key_file, port): if key_file: private_key_text = open(key_file).readline().strip() private_key = X25519PrivateKey.from_private_bytes( bytes.fromhex(private_key_text)) else: private_key = X25519PrivateKey.generate() print( "Server public key: ", private_key.public_key().public_bytes(encoding=Encoding.Raw, format=PublicFormat.Raw).hex()) server_handler = pssst.PSSSTServer(private_key) with closing(socket.socket(socket.AF_INET, socket.SOCK_DGRAM)) as server_socket: server_socket.bind(('127.0.0.1', port)) while True: packet, client_addr = server_socket.recvfrom(2048) try: data, client_key, reply_handler = server_handler.unpack_request( packet) reply_packet = reply_handler(data) server_socket.sendto(reply_packet, client_addr) except pssst.PSSSTException as e: print("Server Exception: {}".format(e))
def load_private_key(self, prv_bytes): """ Load a private key into the instance. :param prv_bytes: The private key as *bytes*. :returns: True if the key was loaded, otherwise False. """ try: self.prv_bytes = prv_bytes[:Identity.KEYSIZE // 8 // 2] self.prv = X25519PrivateKey.from_private_bytes(self.prv_bytes) self.sig_prv_bytes = prv_bytes[Identity.KEYSIZE // 8 // 2:] self.sig_prv = Ed25519PrivateKey.from_private_bytes( self.sig_prv_bytes) self.pub = self.prv.public_key() self.pub_bytes = self.pub.public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) self.sig_pub = self.sig_prv.public_key() self.sig_pub_bytes = self.sig_pub.public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) self.update_hashes() return True except Exception as e: raise e RNS.log("Failed to load identity key", RNS.LOG_ERROR) RNS.log("The contained exception was: " + str(e), RNS.LOG_ERROR) return False
def test_buffer_protocol(self, backend): private_bytes = bytearray(os.urandom(32)) key = X25519PrivateKey.from_private_bytes(private_bytes) assert (key.private_bytes( serialization.Encoding.Raw, serialization.PrivateFormat.Raw, serialization.NoEncryption(), ) == private_bytes)
def test_rfc7748(self, vector, backend): private = binascii.unhexlify(vector["input_scalar"]) public = binascii.unhexlify(vector["input_u"]) shared_key = binascii.unhexlify(vector["output_u"]) private_key = X25519PrivateKey.from_private_bytes(private) public_key = X25519PublicKey.from_public_bytes(public) computed_shared_key = private_key.exchange(public_key) assert computed_shared_key == shared_key
def test_buffer_protocol(self, backend): private_bytes = bytearray(os.urandom(32)) key = X25519PrivateKey.from_private_bytes(private_bytes) assert key.private_bytes( serialization.Encoding.Raw, serialization.PrivateFormat.Raw, serialization.NoEncryption() ) == private_bytes
def test_rfc7748_1000_iteration(self, backend): old_private = private = public = binascii.unhexlify( b"090000000000000000000000000000000000000000000000000000000000" b"0000") shared_key = binascii.unhexlify( b"684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d9953" b"2c51") private_key = X25519PrivateKey.from_private_bytes(private) public_key = X25519PublicKey.from_public_bytes(public) for _ in range(1000): computed_shared_key = private_key.exchange(public_key) private_key = X25519PrivateKey.from_private_bytes( computed_shared_key) public_key = X25519PublicKey.from_public_bytes(old_private) old_private = computed_shared_key assert computed_shared_key == shared_key
def diffie_hellman(priv_bytes: bytes, pub_bytes: bytes) -> bytes: """ Performs a Diffie-Hellman operation on the two keys :param priv_bytes: bytes of the first key :param pub_bytes: bytes of the second key :return: exchange of the two keys """ return X25519PrivateKey.from_private_bytes(priv_bytes).exchange( X25519PublicKey.from_public_bytes(pub_bytes))
def __init__(self, private_key: Union[str, X25519PrivateKey]): if isinstance(private_key, X25519PrivateKey): self.__private_key = private_key elif isinstance(private_key, str): self.__private_key = X25519PrivateKey.from_private_bytes( base64.b64decode(private_key)) else: raise TypeError( "private_key must be a string or X25519PrivateKey object")
def public_key(self): return PublicKey(X25519PrivateKey.from_private_bytes(bytes(self)).public_key().public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw, )) if isinstance(other, Key) and not isinstance(other, PrivateKey): return NotImplemented return super().__eq__(other)
def to_age_private_key(self) -> AgePrivateKey: # use pynacl for this conversion ed25519_pk = self._key.public_key().public_bytes( Encoding.Raw, PublicFormat.Raw) ed25519_sk = self._key.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption()) curve25519_sk = crypto_sign_ed25519_sk_to_curve25519(ed25519_sk + ed25519_pk) private_key = X25519PrivateKey.from_private_bytes(curve25519_sk) return AgePrivateKey(private_key)
def _key_check(key_value, public): if key_value is None: return None if isinstance(key_value, str): key_value = bytes.fromhex(key_value) if isinstance(key_value, bytes): if public: key_value = X25519PublicKey.from_public_bytes(key_value) else: key_value = X25519PrivateKey.from_private_bytes(key_value) return key_value
def test_rfc7748_1000_iteration(self, backend): old_private = private = public = binascii.unhexlify( b"090000000000000000000000000000000000000000000000000000000000" b"0000" ) shared_key = binascii.unhexlify( b"684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d9953" b"2c51" ) private_key = X25519PrivateKey.from_private_bytes(private) public_key = X25519PublicKey.from_public_bytes(public) for _ in range(1000): computed_shared_key = private_key.exchange(public_key) private_key = X25519PrivateKey.from_private_bytes( computed_shared_key ) public_key = X25519PublicKey.from_public_bytes(old_private) old_private = computed_shared_key assert computed_shared_key == shared_key
def test_generate(capsys): gen_func = "cryptography.hazmat.primitives.asymmetric.x25519.X25519PrivateKey.generate" with mock.patch(gen_func) as mock_generate, mock.patch("age.cli.datetime") as mock_datetime: mock_datetime.now.return_value = datetime.datetime(2019, 11, 10, 10, 00, 00) mock_datetime.side_effect = lambda *args, **kw: datetime.datetime(*args, **kw) mock_generate.return_value = X25519PrivateKey.from_private_bytes(TEST_KEY_RAW) generate() captured = capsys.readouterr() assert captured.out == TEST_KEY
def test_null_shared_key_raises_error(self, backend): """ The vector used here is taken from wycheproof's x25519 test vectors """ public = binascii.unhexlify( "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157") private = binascii.unhexlify( "78f1e8edf14481b389448dac8f59c70b038e7cf92ef2c7eff57a72466e115296") private_key = X25519PrivateKey.from_private_bytes(private) public_key = X25519PublicKey.from_public_bytes(public) with pytest.raises(ValueError): private_key.exchange(public_key)
def test_pub_priv_bytes_raw(self, private_bytes, public_bytes, backend): private_key = X25519PrivateKey.from_private_bytes(private_bytes) assert private_key.private_bytes( serialization.Encoding.Raw, serialization.PrivateFormat.Raw, serialization.NoEncryption()) == private_bytes assert private_key.public_key().public_bytes( serialization.Encoding.Raw, serialization.PublicFormat.Raw) == public_bytes public_key = X25519PublicKey.from_public_bytes(public_bytes) assert public_key.public_bytes( serialization.Encoding.Raw, serialization.PublicFormat.Raw) == public_bytes
def __init__(self, loc_privkey=None): """ Create the class object Args: loc_privkey: loc_privkey Returns: None """ if not loc_privkey: self.generate_keypair() else: self.priv_key = X25519PrivateKey.from_private_bytes(loc_privkey)
def test_pub_priv_bytes_raw(self, private_bytes, public_bytes, backend): private_key = X25519PrivateKey.from_private_bytes(private_bytes) assert private_key.private_bytes( serialization.Encoding.Raw, serialization.PrivateFormat.Raw, serialization.NoEncryption() ) == private_bytes assert private_key.public_key().public_bytes( serialization.Encoding.Raw, serialization.PublicFormat.Raw ) == public_bytes public_key = X25519PublicKey.from_public_bytes(public_bytes) assert public_key.public_bytes( serialization.Encoding.Raw, serialization.PublicFormat.Raw ) == public_bytes
def unpack_request(self, packet): # pylint: disable=too-many-locals """Unpack an incoming request :param packet: Incoming packet to unpack :type packet: bytes :raises PSSSTUnsupportedCipher: cipher suite indicated in packet is not supported. :raises PSSSTNotRequest: packet is not a request packet. :raises PSSSTDecryptFailed: payload did not decrypt to valid and authentic data :raises PSSSTClientAuthFailed: client auth was present but did not match request :returns: tuple of unpacked data, authenticated client public key and reply handler """ hdr = Header.from_packet(packet[:4]) if hdr.reply: raise PSSSTNotRequest() if hdr.cipher_suite != self._suite: raise PSSSTUnsupportedCipher() dh_bytes = packet[4:36] exchange_dh = X25519PublicKey.from_public_bytes(dh_bytes) shared_secret = self._server_private.exchange(exchange_dh) key, nonce_client, nonce_server = _DKF_SHA256(dh_bytes, shared_secret) cipher = AESGCM(key) try: plaintext = cipher.decrypt(nonce_client, packet[36:], packet[:4]) except InvalidTag as err: raise PSSSTDecryptFailed() from err if hdr.client_auth: client_public_key = X25519PublicKey.from_public_bytes( plaintext[:32]) temp_privte_key = X25519PrivateKey.from_private_bytes( plaintext[32:64]) auth_dh = temp_privte_key.exchange(client_public_key) if auth_dh != exchange_dh.public_bytes(encoding=Encoding.Raw, format=PublicFormat.Raw): raise PSSSTClientAuthFailed() plaintext = plaintext[64:] else: client_public_key = None reply_handler = _ServerReplyHandler(packet[4:36], hdr.client_auth, hdr.cipher_suite, cipher, nonce_server) return (plaintext, client_public_key, reply_handler)
def test_null_shared_key_raises_error(self, backend): """ The vector used here is taken from wycheproof's x25519 test vectors """ public = binascii.unhexlify( "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157" ) private = binascii.unhexlify( "78f1e8edf14481b389448dac8f59c70b038e7cf92ef2c7eff57a72466e115296" ) private_key = X25519PrivateKey.from_private_bytes( private ) public_key = X25519PublicKey.from_public_bytes(public) with pytest.raises(ValueError): private_key.exchange(public_key)
def main(public_key, client_key_file, port, iterations, payload, threads): if client_key_file: private_key_text = open(client_key_file).readline().strip() private_key = X25519PrivateKey.from_private_bytes( bytes.fromhex(private_key_text)) else: private_key = None client = pssst.PSSSTClient(public_key, private_key) payload = payload.encode("UTF8") result_list = [] tests = [client.pack_request(payload) for _ in range(iterations)] def send_tests(test_subset): replies = 0 start_time = time.time() with closing(socket.socket(socket.AF_INET, socket.SOCK_DGRAM)) as client_socket: client_socket.settimeout(0.25) for packet, reply_handler in test_subset: client_socket.sendto(packet, ('127.0.0.1', port)) try: client_socket.recvfrom(2048) replies += 1 except socket.timeout: pass end_time = time.time() result_list.append((len(test_subset), replies, end_time - start_time)) chops = [(iterations * i) // threads for i in range(threads + 1)] thread_list = [ Thread(target=send_tests, args=(tests[chops[i]:chops[i + 1]], )) for i in range(threads) ] for t in thread_list: t.start() for t in thread_list: t.join() total_sent = sum(row[0] for row in result_list) total_received = sum(row[1] for row in result_list) duration = max(row[2] for row in result_list) print("Sent: {}, received: {}, total time: {:.2f}".format( total_sent, total_received, duration))
def generate_keys(seed): """Generate server encryption keys from seed.""" signing_key = Ed25519PrivateKey.from_private_bytes(seed) verify_private = X25519PrivateKey.from_private_bytes(seed) return ServerKeys( sign=signing_key, auth=signing_key.private_bytes( encoding=serialization.Encoding.Raw, format=serialization.PrivateFormat.Raw, encryption_algorithm=serialization.NoEncryption(), ), auth_pub=signing_key.public_key().public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw), verify=verify_private, verify_pub=verify_private.public_key(), )
def initialize(self): """Initialize operation by generating new keys.""" self._signing_key = Ed25519PrivateKey.from_private_bytes(os.urandom(32)) self._auth_private = self._signing_key.private_bytes( encoding=serialization.Encoding.Raw, format=serialization.PrivateFormat.Raw, encryption_algorithm=serialization.NoEncryption(), ) self._auth_public = self._signing_key.public_key().public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw ) self._verify_private = X25519PrivateKey.from_private_bytes(os.urandom(32)) self._verify_public = self._verify_private.public_key() self._public_bytes = self._verify_public.public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw ) return self._auth_public, self._public_bytes
def pubkey(privkey: str) -> str: """convert WireGuard private key into public key Args: privkey (str): WireGuard X25519 private key encoded in base64 format Returns: str: corresponding public key of the provided private key encoded as a base64 string """ return base64.b64encode( X25519PrivateKey.from_private_bytes( base64.b64decode(privkey.encode())).public_key().public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw, )).decode()
def test_x25519(backend, wycheproof): assert list(wycheproof.testgroup.items()) == [("curve", "curve25519")] private_key = X25519PrivateKey.from_private_bytes( binascii.unhexlify(wycheproof.testcase["private"])) public_key = X25519PublicKey.from_public_bytes( binascii.unhexlify(wycheproof.testcase["public"])) assert wycheproof.valid or wycheproof.acceptable expected = binascii.unhexlify(wycheproof.testcase["shared"]) if expected == b"\x00" * 32: assert wycheproof.acceptable # OpenSSL returns an error on all zeros shared key with pytest.raises(ValueError): private_key.exchange(public_key) else: assert private_key.exchange(public_key) == expected
def test_x25519(backend, wycheproof): assert list(wycheproof.testgroup.items()) == [("curve", "curve25519")] private_key = X25519PrivateKey.from_private_bytes( binascii.unhexlify(wycheproof.testcase["private"]) ) public_key = X25519PublicKey.from_public_bytes( binascii.unhexlify(wycheproof.testcase["public"]) ) assert wycheproof.valid or wycheproof.acceptable expected = binascii.unhexlify(wycheproof.testcase["shared"]) if expected == b"\x00" * 32: assert wycheproof.acceptable # OpenSSL returns an error on all zeros shared key with pytest.raises(ValueError): private_key.exchange(public_key) else: assert private_key.exchange(public_key) == expected
def verify1(self): """First device verification step.""" self._check_initialized() self._verify_private = X25519PrivateKey.from_private_bytes(self.seed) self._verify_public = self._verify_private.public_key() verify_private_bytes = self._verify_private.private_bytes( encoding=serialization.Encoding.Raw, format=serialization.PrivateFormat.Raw, encryption_algorithm=serialization.NoEncryption(), ) self._public_bytes = self._verify_public.public_bytes( encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) log_binary( _LOGGER, "Verification keys", Private=verify_private_bytes, Public=self._public_bytes, ) return b"\x01\x00\x00\x00" + self._public_bytes + self._auth_public
def shared_secret(private_key: Key, public_key: Key) -> bytes: """ Compute the shared secret. """ if public_key.crv == CoseEllipticCurves.X25519: d = X25519PrivateKey.from_private_bytes(private_key.d) x = X25519PublicKey.from_public_bytes(public_key.x) elif public_key.crv == CoseEllipticCurves.X448: d = X448PrivateKey.from_private_bytes(private_key.d) x = X448PublicKey.from_public_bytes(public_key.x) elif public_key.crv == CoseEllipticCurves.P_256: d = ec.derive_private_key(int(hexlify(private_key.d), 16), config_cose(public_key.crv).curve[1](), default_backend()) x = ec.EllipticCurvePublicNumbers( int(hexlify(public_key.x), 16), int(hexlify(public_key.y), 16), config_cose(public_key.crv).curve[1]()) else: raise CoseIllegalCurve(f"{public_key.crv} is unsupported") secret = d.exchange(x) return secret
def authenticate(self, password: bytes): """ Decrypt the secret keys and test if it is identical to identity. :param password The password used to encrypt the keys. :return A tuple containing an X25519PrivateKey and an Ed25519PrivateKey, or None if the results does not match. """ # Attempt to decrypt signature key session = _gen_login_key(password, self.identity) context = Cipher(algorithms.ChaCha20(session, self.sign_iv), None, default_backend()).decryptor() sign = context.update(self.sign_priv) + context.finalize() # Verification identity = blake2b(sign).digest() if identity != self.identity: return None # Decrypt the encryption key context = Cipher(algorithms.ChaCha20(session, self.xchg_iv), None, default_backend()).decryptor() xchg = context.update(self.xchg_priv) + context.finalize() return (Ed25519PrivateKey.from_private_bytes(sign), X25519PrivateKey.from_private_bytes(xchg))
def test_invalid_length_from_private_bytes(self, backend): with pytest.raises(ValueError): X25519PrivateKey.from_private_bytes(b"a" * 31) with pytest.raises(ValueError): X25519PrivateKey.from_private_bytes(b"a" * 33)