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 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 generate( public_key, encryption_alg="AES-PMAC-SIV", digest_alg=hashes.SHA256(), salt=None, csrng=os.urandom, ): """ Generate an XSTREAM encryptor object with a random ephemeral key :param public_key: 32-byte X25519 public key (i.e. compressed Montgomery-u coordinate) :param encryption_alg: symmetric encryption algorithm to use with STREAM (default "AES-PMAC-SIV") :param digest_alg: digest algorithm to use with HKDF (default "SHA256") :param salt: (optional) salt value to pass to HKDF (default None) :param csrng: (optional) secure random number generator used to generate ephemeral key (default os.urandom) :return: STREAM encryptor and ephemeral public key """ ephemeral_scalar = X25519PrivateKey._from_private_bytes( csrng(X25519_KEY_SIZE)) symmetric_key = kdf( private_key=ephemeral_scalar, public_key=X25519PublicKey.from_public_bytes(public_key), digest_alg=digest_alg, length=SYMMETRIC_KEY_SIZE, salt=salt) enc = Encryptor(encryption_alg, symmetric_key, NONCE) return enc, ephemeral_scalar.public_key().public_bytes()
def modify(packet): pkt = dpkt.ip6.IP6(packet.get_payload()) if is_icmp_neighbour_message(pkt): packet.accept() return global client_id aes_key_text = pkt.data[:256] aes_key_text = asymmetrickeys.decrypt(aes_key_text) nonce = struct.unpack(">I", pkt.data[256:260])[0] public_ecdhe_key = pkt.data[260:292] ci = struct.unpack(">I", pkt.data[292:296])[0] aes_key = AESGCM(aes_key_text) decrypted_block = bytes( aes_key.decrypt(bytes(nonce), pkt.data[296:-288], '')) ip_b = decrypted_block[:16] # --- Header 2 header_2 = pkt.data[-288:] ecdhe = X25519PrivateKey.generate() shared_key = ecdhe.exchange( X25519PublicKey.from_public_bytes(public_ecdhe_key)) derived_key = HKDF(algorithm=hashes.SHA512(), length=32, info=None, salt=None, backend=default_backend()).derive(shared_key) key = AESGCM(derived_key) nonce = random.randint(0, 4294967295) encrypted_header = key.encrypt(bytes(nonce), header_2, '') signature = sign(ecdhe.public_key().public_bytes(), asymmetrickeys) header_2 = ecdhe.public_key().public_bytes() + signature + struct.pack( ">I", nonce) + encrypted_header + struct.pack(">I", client_id) client_id = client_id + 1 # Finalize packet pkt.data = decrypted_block[16:] + header_2 pkt.plen = len(pkt.data) pkt.dst = ip_b sockfd.sendto(bytes(pkt), (socket.inet_ntop(socket.AF_INET6, ip_b), 0)) packet.drop()
def verify_start(config: Config, context: dict, ios_device_public_key: bytes) -> List[dict]: """pair_verify M1 and M2""" curve25519 = X25519PrivateKey.generate() accessory_curve25519_public_key: bytes = curve25519.public_key().public_bytes() shared_secret: bytes = curve25519.exchange(X25519PublicKey.from_public_bytes(ios_device_public_key)) accessory_info: bytes = accessory_curve25519_public_key + config.device_id.encode() + ios_device_public_key signing_key = ed25519.SigningKey(config.accessory_ltsk) accessory_signature = signing_key.sign(accessory_info) sub_tlv = tlv_parser.encode([{ TlvCode.identifier: config.device_id, TlvCode.signature: accessory_signature, }]) hkdf = HKDF(algorithm=SHA512(), length=32, salt=SALT_VERIFY, info=INFO_VERIFY, backend=default_backend()) session_key = hkdf.derive(shared_secret) chacha = ChaCha20Poly1305(session_key) encrypted_data = chacha.encrypt(NONCE_VERIFY_M2, sub_tlv, None) context['session_key'] = session_key context['shared_secret'] = shared_secret context['accessory_curve25519_public_key'] = accessory_curve25519_public_key context['ios_device_curve25519_public_key'] = ios_device_public_key return [{ TlvCode.state: TlvState.m2, TlvCode.public_key: accessory_curve25519_public_key, TlvCode.encrypted_data: encrypted_data, }]
def __init__(self, private_key, ephemeral_public, encryption_alg="AES-PMAC-SIV", digest_alg=hashes.SHA256(), salt=None): """ Create an XSTREAM decryptor object using our private key and an ephemeral public key :param private_key: 32-byte X25519 private key (i.e. private scalar) :param ephemeral_public: 32-byte X25519 ephemeral public key from XSTREAM encryption :param encryption_alg: symmetric encryption algorithm to use with STREAM (default "AES-PMAC-SIV") :param digest_alg: digest algorithm to use with HKDF (default "SHA256") :param salt: (optional) salt value to pass to HKDF (default None) """ # Perform an X25519 elliptic curve Diffie-Hellman operation and use # the resulting shared secret to derive a symmetric key (using HKDF) symmetric_key = kdf( private_key=X25519PrivateKey._from_private_bytes(private_key), public_key=X25519PublicKey.from_public_bytes(ephemeral_public), digest_alg=digest_alg, length=SYMMETRIC_KEY_SIZE, salt=salt) super(Decryptor, self).__init__(encryption_alg, symmetric_key, NONCE)
def accept(self): """Accept an incoming connection & initialize the encryption layer for that client Returns ------- returns (socket, addr) of the client """ clt, addr = super().accept() # Generate a private key server_key = X25519PrivateKey.generate() pubkey = server_key.public_key().public_bytes(encoding=Encoding.Raw, format=PublicFormat.Raw) data = clt.recv(32) # Receive client public Key clt.sendall(pubkey) # send public key to client public_key = X25519PublicKey.from_public_bytes(data) # get Shared key shared_key = server_key.exchange(public_key) shared_key = HKDF(algorithm=hashes.SHA256(), length=48, salt=None, info=b'handshake data', backend=default_backend()).derive(shared_key) encrypted_socket = wrap_socket(clt, False, handshaked=True) encrypted_socket.cipher = Cipher(algorithms.AES(shared_key[0:32]), modes.CBC(shared_key[32:]), backend=default_backend()) return encrypted_socket, addr
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 setup0_response(self, response_data): # Interpret SessionResp0 response packet setup_resp = proto.session_pb2.SessionData() setup_resp.ParseFromString(tobytes(response_data)) self._print_verbose("Security version:\t" + str(setup_resp.sec_ver)) if setup_resp.sec_ver != session_pb2.SecScheme1: print("Incorrect sec scheme") exit(1) self.device_public_key = setup_resp.sec1.sr0.device_pubkey # Device random is the initialization vector device_random = setup_resp.sec1.sr0.device_random self._print_verbose("Device Public Key:\t" + utils.str_to_hexstr(self.device_public_key.decode('latin-1'))) self._print_verbose("Device Random:\t" + utils.str_to_hexstr(device_random.decode('latin-1'))) # Calculate Curve25519 shared key using Client private key and Device public key sharedK = self.client_private_key.exchange(X25519PublicKey.from_public_bytes(self.device_public_key)) self._print_verbose("Shared Key:\t" + utils.str_to_hexstr(sharedK.decode('latin-1'))) # If PoP is provided, XOR SHA256 of PoP with the previously # calculated Shared Key to form the actual Shared Key if len(self.pop) > 0: # Calculate SHA256 of PoP h = hashes.Hash(hashes.SHA256(), backend=default_backend()) h.update(self.pop) digest = h.finalize() # XOR with and update Shared Key sharedK = xor(sharedK, digest) self._print_verbose("New Shared Key XORed with PoP:\t" + utils.str_to_hexstr(sharedK.decode('latin-1'))) # Initialize the encryption engine with Shared Key and initialization vector cipher = Cipher(algorithms.AES(sharedK), modes.CTR(device_random), backend=default_backend()) self.cipher = cipher.encryptor()
def _handshake(self): """Open a socket to address, port and initialize the encryption layer by exchanging a key using X25519. The key is used as an AES key throughout the communication. Returns ------- return itself """ private_key = X25519PrivateKey.generate() pubkey = private_key.public_key().public_bytes(encoding=Encoding.Raw, format=PublicFormat.Raw) # send client public key super().send(pubkey) # receive server public Key data = super().recv(32) # from public key get shared_key server_key = X25519PublicKey.from_public_bytes(data) shared_key = private_key.exchange(server_key) key = HKDF(algorithm=hashes.SHA256(), length=48, salt=None, info=b'handshake data', backend=default_backend()).derive(shared_key) self.cipher = Cipher(algorithms.AES(key[0:32]), modes.CBC(key[32:]), backend=default_backend()) return self
def setup0_response(self, response_data): setup_resp = proto.session_pb2.SessionData() setup_resp.ParseFromString(utils.bytearr_to_bytes(response_data)) self._print_verbose("Security version:\t" + str(setup_resp.sec_ver)) if setup_resp.sec_ver != session_pb2.SecScheme1: print("Incorrect sec scheme") exit(1) self._print_verbose( "Device Public Key:\t" + utils.bytes_to_hexstr(setup_resp.sec1.sr0.device_pubkey)) self._print_verbose( "Device Random:\t" + utils.bytes_to_hexstr(setup_resp.sec1.sr0.device_random)) sharedK = self.client_private_key.exchange( X25519PublicKey.from_public_bytes( setup_resp.sec1.sr0.device_pubkey)) self._print_verbose("Shared Key:\t" + utils.bytes_to_hexstr(sharedK)) if len(self.pop) > 0: h = hashes.Hash(hashes.SHA256(), backend=default_backend()) h.update(self.pop) digest = h.finalize() sharedK = utils.xor(sharedK, digest) self._print_verbose("New Shared Key XORed with PoP:\t" + utils.bytes_to_hexstr(sharedK)) self._print_verbose("IV " + hex( int(utils.bytes_to_hexstr(setup_resp.sec1.sr0.device_random), 16))) cipher = Cipher(algorithms.AES(sharedK), modes.CTR(setup_resp.sec1.sr0.device_random), backend=default_backend()) self.cipher = cipher.encryptor() self.client_verify = self.cipher.update( setup_resp.sec1.sr0.device_pubkey) self._print_verbose("Client Verify:\t" + utils.bytes_to_hexstr(self.client_verify))
def __init__(self): self.s = socket.socket() host = socket.gethostname() port = 12345 self.s.connect((host, port)) self.messages = [] private_key_bob = X25519PrivateKey.generate() public_key_bob = private_key_bob.public_key() peer_public_alice_raw = (self.s.recv(2048)) #print(peer_public_alice_raw) self.s.send(public_key_bob.public_bytes(Encoding.Raw, PublicFormat.Raw)) peer_public_alice = X25519PublicKey.from_public_bytes( peer_public_alice_raw) shared_key = private_key_bob.exchange(peer_public_alice) derived_key = HKDF(algorithm=hashes.SHA256(), length=32, salt=None, info=b'handshake data', backend=default_backend()).derive(shared_key) self.f = Fernet(base64.urlsafe_b64encode(derived_key)) t = threading.Thread(target=self.recvMessages, args=(self.s, )) t.start()
def _parse_kexecdh_init(self, m): peer_key_bytes = m.get_string() peer_key = X25519PublicKey.from_public_bytes(peer_key_bytes) K = self._perform_exchange(peer_key) K = long(binascii.hexlify(K), 16) # compute exchange hash hm = Message() hm.add( self.transport.remote_version, self.transport.local_version, self.transport.remote_kex_init, self.transport.local_kex_init, ) server_key_bytes = self.transport.get_server_key().asbytes() exchange_key_bytes = self.key.public_key().public_bytes( serialization.Encoding.Raw, serialization.PublicFormat.Raw) hm.add_string(server_key_bytes) hm.add_string(peer_key_bytes) hm.add_string(exchange_key_bytes) hm.add_mpint(K) H = self.hash_algo(hm.asbytes()).digest() self.transport._set_K_H(K, H) sig = self.transport.get_server_key().sign_ssh_data(H) # construct reply m = Message() m.add_byte(c_MSG_KEXECDH_REPLY) m.add_string(server_key_bytes) m.add_string(exchange_key_bytes) m.add_string(sig) self.transport._send_message(m) self.transport._activate_outbound()
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 _parse_kexecdh_reply(self, m): peer_host_key_bytes = m.get_string() peer_key_bytes = m.get_string() sig = m.get_binary() peer_key = X25519PublicKey.from_public_bytes(peer_key_bytes) K = self._perform_exchange(peer_key) K = long(binascii.hexlify(K), 16) # compute exchange hash and verify signature hm = Message() hm.add( self.transport.local_version, self.transport.remote_version, self.transport.local_kex_init, self.transport.remote_kex_init, ) hm.add_string(peer_host_key_bytes) hm.add_string(self.key.public_key().public_bytes( serialization.Encoding.Raw, serialization.PublicFormat.Raw)) hm.add_string(peer_key_bytes) hm.add_mpint(K) self.transport._set_K_H(K, self.hash_algo(hm.asbytes()).digest()) self.transport._verify_key(peer_host_key_bytes, sig) self.transport._activate_outbound()
def test_round_trip_client_auth_text_keys(): client = pssst.PSSSTClient(k1_pub, k2_priv) server = pssst.PSSSTServer(k1_priv) client_public_key = X25519PublicKey.from_public_bytes( bytes.fromhex(k2_pub)) test_message = b"This is a test message" request_packet, client_reply_handler = client.pack_request(test_message) received_message, received_client_public_key, server_reply_handler = server.unpack_request( request_packet) assert received_message == test_message, "Message didn't arrive intact" source_client_key_bytes = client_public_key.public_bytes( encoding=Encoding.Raw, format=PublicFormat.Raw) received_client_key_bytes = received_client_public_key.public_bytes( encoding=Encoding.Raw, format=PublicFormat.Raw) assert received_client_key_bytes == source_client_key_bytes, "Bad client auth" reply_packet = server_reply_handler(received_message) round_trip_message = client_reply_handler(reply_packet) assert round_trip_message == test_message, "Round trip failed"
def setup0_response(self, response_data): # Interpret SessionResp0 response packet setup_resp = proto.session_pb2.SessionData() setup_resp.ParseFromString(tobytes(response_data)) self._print_verbose('Security version:\t' + str(setup_resp.sec_ver)) if setup_resp.sec_ver != session_pb2.SecScheme1: print('Incorrect sec scheme') exit(1) self.device_public_key = setup_resp.sec1.sr0.device_pubkey # Device random is the initialization vector device_random = setup_resp.sec1.sr0.device_random self._print_verbose('Device Public Key:\t' + utils.str_to_hexstr(self.device_public_key.decode('latin-1'))) self._print_verbose('Device Random:\t' + utils.str_to_hexstr(device_random.decode('latin-1'))) # Calculate Curve25519 shared key using Client private key and Device public key sharedK = self.client_private_key.exchange(X25519PublicKey.from_public_bytes(self.device_public_key)) self._print_verbose('Shared Key:\t' + utils.str_to_hexstr(sharedK.decode('latin-1'))) # If PoP is provided, XOR SHA256 of PoP with the previously # calculated Shared Key to form the actual Shared Key if len(self.pop) > 0: # Calculate SHA256 of PoP h = hashes.Hash(hashes.SHA256(), backend=default_backend()) h.update(self.pop) digest = h.finalize() # XOR with and update Shared Key sharedK = xor(sharedK, digest) self._print_verbose('New Shared Key XORed with PoP:\t' + utils.str_to_hexstr(sharedK.decode('latin-1'))) # Initialize the encryption engine with Shared Key and initialization vector cipher = Cipher(algorithms.AES(sharedK), modes.CTR(device_random), backend=default_backend()) self.cipher = cipher.encryptor()
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 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_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_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 __init__(self, public_key: Union[str, X25519PublicKey]): if isinstance(public_key, X25519PublicKey): self.__public_key = public_key elif isinstance(public_key, str): self.__public_key = X25519PublicKey.from_public_bytes( base64.b64decode(public_key)) else: raise TypeError( "public_key must be a string or X25519PublicKey object")
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 key_exchange(): key_pair = X25519PrivateKey.generate() public_key = key_pair.public_key() peer_public_key = X25519PublicKey.from_public_bytes(base64.b64decode(request.get_json().get('data').encode('utf-8'))) secret = key_pair.exchange(peer_public_key) id = base64.b64encode(urandom(16)).decode('utf-8') users[id] = secret return jsonify({'id': id, 'public_key': base64.b64encode( public_key.public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw)).decode('utf-8')})
def _on_dhkey(self, peer_id, dh_key): """Used only on session establishment. Subsequently it's sent via EncryptedMessage. """ self.logger.debug(f"peer dhkey: {dh_key}") dh_public_key = X25519PublicKey.from_public_bytes( base64.b64decode(dh_key)) self.sessions[peer_id].dh_public_key = dh_public_key self.dh_ratchet(peer_id, dh_public_key) self.sessions[peer_id].state = RatchetState.SENDING
def load_peer(self, peer_pub_bytes, peer_sig_pub_bytes): self.peer_pub_bytes = peer_pub_bytes self.peer_pub = X25519PublicKey.from_public_bytes(self.peer_pub_bytes) self.peer_sig_pub_bytes = peer_sig_pub_bytes self.peer_sig_pub = Ed25519PublicKey.from_public_bytes( self.peer_sig_pub_bytes) if not hasattr(self.peer_pub, "curve"): self.peer_pub.curve = Link.CURVE
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 check_ecdh(card, key_num=2): myPublicKey, myPrivateKey = ecdsa_keys.generate_key_eddsa_ecdh() myPublicKeyTLV = ecdh_public_key_encode(ecdsa_keys.ecc_to_string(myPublicKey)) pk = card.cmd_get_public_key(key_num) pk_info = get_pk_info(pk) sharedSecret = card.cmd_pso(0x80, 0x86, myPublicKeyTLV) peer_pk = X25519PublicKey.from_public_bytes(pk_info[0]) mySharedSecret = myPrivateKey.exchange(peer_pk) return sharedSecret == mySharedSecret
def x25519_key_derive(private, peer): peer_public = X25519PublicKey.from_public_bytes( bytes.fromhex(peer.strip())) shared = private.exchange(peer_public) derived_key = HKDF( algorithm=hashes.SHA256(), length=32, salt=b'', info=b'exchange', backend=default_backend() ).derive(shared) return derived_key.hex().strip()
def _on_new_session(self, n, peer_id, rest): self.peer_keys[peer_id]["EK"] = X25519PublicKey.from_public_bytes( base64.b64decode(rest)) if peer_id in self.sessions: return self.x3dh_receiver(self.peer_keys[peer_id]) self.init_ratchets(peer_id, sender=False) self.sessions[ peer_id].dh_ratchet = dh_ratchet = X25519PrivateKey.generate() dh_key = b64k(dh_ratchet.public_key()) message = " ".join(["/dhkey", dh_key]) n.whisper(peer_id, message.encode("utf-8"))
def test_fake_client_auth(): server_private_key, server_public_key = generate_key_pair( cipher_suite=pssst.CipherSuite.X25519_AESGCM128) client_private_key, client_public_key = generate_key_pair( cipher_suite=pssst.CipherSuite.X25519_AESGCM128) server = PSSSTServer(server_private_key) test_message = b"This is a test message" # Build a fake client-auth packet header = Header(cipher_suite=CipherSuite.X25519_AESGCM128, reply=False, client_auth=True) partial_key_bytes = client_private_key.exchange(server_public_key) client_server_pub = X25519PublicKey.from_public_bytes(partial_key_bytes) temp_priv_key = X25519PrivateKey.generate() exchange_dh = temp_priv_key.exchange(client_public_key) shared_secret = temp_priv_key.exchange(client_server_pub) client_pub_bytes = client_public_key.public_bytes(encoding=Encoding.Raw, format=PublicFormat.Raw) temp_private_bytes = temp_priv_key.private_bytes( encoding=Encoding.Raw, format=PrivateFormat.Raw, encryption_algorithm=NoEncryption()) data = client_pub_bytes + temp_private_bytes + test_message key, nonce_client, nonce_server = pssst.pssst._DKF_SHA256( exchange_dh, shared_secret) # Test 1: make sure that our dummy code works packet = header.packet_bytes + exchange_dh cipher = AESGCM(key) data = client_pub_bytes + temp_private_bytes + test_message packet += cipher.encrypt(nonce_client, data, packet[:4]) server.unpack_request(packet) # Test 2: make sure it fails when we pass the wrong public key packet = header.packet_bytes + exchange_dh cipher = AESGCM(key) bad_key = b'\xaa' * 32 data = bad_key + temp_private_bytes + test_message packet += cipher.encrypt(nonce_client, data, packet[:4]) with pytest.raises(pssst.PSSSTClientAuthFailed): server.unpack_request(packet)
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 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 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_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_invalid_length_from_public_bytes(self, backend): with pytest.raises(ValueError): X25519PublicKey.from_public_bytes(b"a" * 31) with pytest.raises(ValueError): X25519PublicKey.from_public_bytes(b"a" * 33)
def test_public_bytes(self, private_bytes, public_bytes, backend): private_key = X25519PrivateKey._from_private_bytes(private_bytes) assert private_key.public_key().public_bytes() == public_bytes public_key = X25519PublicKey.from_public_bytes(public_bytes) assert public_key.public_bytes() == public_bytes