def new_server_session(keys, pin): """Create SRP server session.""" context = SRPContext( "Pair-Setup", str(pin), prime=constants.PRIME_3072, generator=constants.PRIME_3072_GEN, hash_func=hashlib.sha512, bits_salt=128, bits_random=512, ) username, verifier, salt = context.get_user_data_triplet() context_server = SRPContext( username, prime=constants.PRIME_3072, generator=constants.PRIME_3072_GEN, hash_func=hashlib.sha512, bits_salt=128, bits_random=512, ) session = SRPServerSession( context_server, verifier, binascii.hexlify(keys.auth).decode() ) return session, salt
def get_user_data_triplet(username, password): """Print out user data triplet: username, password verifier, salt.""" context = SRPContext(username, password) username, password_verifier, salt = context.get_user_data_triplet( base64=True) click.secho('Username: %s' % username) click.secho('Password verifier: %s' % password_verifier) click.secho('Salt: %s' % salt)
def step1(self, pin): """First pairing step.""" context = SRPContext( 'Pair-Setup', str(pin), prime=constants.PRIME_3072, generator=constants.PRIME_3072_GEN, hash_func=hashlib.sha512) self._session = SRPClientSession( context, binascii.hexlify(self._auth_private).decode())
def __init__(self, loop, credentials, atv_device_id): """Initialize a new instance of ProxyMrpAppleTV.""" self.loop = loop self.credentials = credentials self.atv_device_id = atv_device_id self.server = None self.buffer = b'' self.has_paired = False self.transport = None self.chacha = None self.connection = None self.input_key = None self.output_key = None self.mapping = { protobuf.DEVICE_INFO_MESSAGE: self.handle_device_info, protobuf.CRYPTO_PAIRING_MESSAGE: self.handle_crypto_pairing, } self._shared = None self._session_key = None self._signing_key = SigningKey(32 * b'\x01') self._auth_private = self._signing_key.to_seed() self._auth_public = self._signing_key.get_verifying_key().to_bytes() self._verify_private = curve25519.Private(secret=32 * b'\x01') self._verify_public = self._verify_private.get_public() self.context = SRPContext('Pair-Setup', str(1111), prime=constants.PRIME_3072, generator=constants.PRIME_3072_GEN, hash_func=hashlib.sha512, bits_salt=128) self.username, self.verifier, self.salt = \ self.context.get_user_data_triplet() context_server = SRPContext('Pair-Setup', prime=constants.PRIME_3072, generator=constants.PRIME_3072_GEN, hash_func=hashlib.sha512, bits_salt=128) self._session = SRPServerSession( context_server, self.verifier, binascii.hexlify(self._auth_private).decode())
def get_private_and_public(username, password_verifier, private, preset): """Print out server public and private.""" session = SRPServerSession(SRPContext(username, prime=preset[0], generator=preset[1]), hex_from_b64(password_verifier), private=private) click.secho('Server private: %s' % session.private_b64) click.secho('Server public: %s' % session.public_b64)
def get_private_and_public(ctx, username, password, private, preset): """Print out server public and private.""" session = SRPClientSession(SRPContext(username, password, prime=preset[0], generator=preset[1]), private=private) click.secho('Client private: %s' % session.private_b64) click.secho('Client public: %s' % session.public_b64)
def get_session_data(username, password_verifier, salt, client_public, private, preset): """Print out server session data.""" session = SRPServerSession(SRPContext(username, prime=preset[0], generator=preset[1]), hex_from_b64(password_verifier), private=private) session.process(client_public, salt, base64=True) click.secho('Server session key: %s' % session.key_b64) click.secho('Server session key proof: %s' % session.key_proof_b64) click.secho('Server session key hash: %s' % session.key_proof_hash_b64)
def get_session_data(ctx, username, password, salt, server_public, private, preset): """Print out client session data.""" session = SRPClientSession(SRPContext(username, password, prime=preset[0], generator=preset[1]), private=private) session.process(server_public, salt, base64=True) click.secho('Client session key: %s' % session.key_b64) click.secho('Client session key proof: %s' % session.key_proof_b64) click.secho('Client session key hash: %s' % session.key_proof_hash_b64)
def test_context_raises(): context = SRPContext('alice') with pytest.raises(SRPException): context.get_common_password_hash(123)
s.bind((HOST, PORT)) except socket.error as msg: print('Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]) sys.exit() print('Socket bind complete') s.listen(10) print('Socket now listening') #wait to accept a connection - blocking call while 1: conn, addr = s.accept() print('A new padding test requested by ' + addr[0] + ':' + str(addr[1])) #this should be done offline, only once, the server should store somewhere these data context = SRPContext(USERNAME, PASSWORD) username, password_verifier, server_salt = context.get_user_data_triplet() print(username) print(password_verifier) print(server_salt) prime = context.prime gen = context.generator print(prime) print(gen) # generate user-based server parameters server_session = SRPServerSession( SRPContext(username, prime=prime, generator=gen), password_verifier) server_public_B = server_session.public print(server_public_B)
if __name__ == '__main__': server = remote(HOST, PORT) # domain parameters received_data = server.recv(DATA_SIZE).decode() server_data = json.loads(received_data) print(server_data['prime']) # prime print(server_data['generator']) # generator print(server_data['B']) # server public key B print(server_data['server_salt']) # salt # receive server verifier and salt and all the public parameters client_session = SRPClientSession( SRPContext(USERNAME, PASSWORD, prime=server_data['prime'], generator=server_data['generator'])) client_session.process(server_data['B'], server_data['server_salt']) client_public_A = client_session.public print(client_public_A) # client public key A client_session_key_proof = client_session.key_proof.hex() print(client_session_key_proof) client_parameters = json.dumps({ 'A': client_public_A, 'client_session_key_proof': client_session_key_proof }) print(client_parameters)
class ProxyMrpAppleTV(asyncio.Protocol): # pylint: disable=too-many-instance-attributes # noqa """Implementation of a fake MRP Apple TV.""" def __init__(self, loop, credentials, atv_device_id): """Initialize a new instance of ProxyMrpAppleTV.""" self.loop = loop self.credentials = credentials self.atv_device_id = atv_device_id self.server = None self.buffer = b'' self.has_paired = False self.transport = None self.chacha = None self.connection = None self.input_key = None self.output_key = None self.mapping = { protobuf.DEVICE_INFO_MESSAGE: self.handle_device_info, protobuf.CRYPTO_PAIRING_MESSAGE: self.handle_crypto_pairing, } self._shared = None self._session_key = None self._signing_key = SigningKey(32 * b'\x01') self._auth_private = self._signing_key.to_seed() self._auth_public = self._signing_key.get_verifying_key().to_bytes() self._verify_private = curve25519.Private(secret=32 * b'\x01') self._verify_public = self._verify_private.get_public() self.context = SRPContext('Pair-Setup', str(1111), prime=constants.PRIME_3072, generator=constants.PRIME_3072_GEN, hash_func=hashlib.sha512, bits_salt=128) self.username, self.verifier, self.salt = \ self.context.get_user_data_triplet() context_server = SRPContext('Pair-Setup', prime=constants.PRIME_3072, generator=constants.PRIME_3072_GEN, hash_func=hashlib.sha512, bits_salt=128) self._session = SRPServerSession( context_server, self.verifier, binascii.hexlify(self._auth_private).decode()) def start(self, address, port): """Start the proxy instance.""" # Establish connection to ATV self.connection = MrpConnection(address, port, self.loop) protocol = MrpProtocol( self.loop, self.connection, SRPAuthHandler(), MrpService(None, port, credentials=self.credentials)) self.loop.run_until_complete( protocol.start(skip_initial_messages=True)) self.connection.listener = self # Setup server used to publish a fake MRP server coro = self.loop.create_server(lambda: self, '0.0.0.0') self.server = self.loop.run_until_complete(coro) _LOGGER.info('Started MRP server at port %d', self.port) @property def port(self): """Port used by MRP proxy server.""" return self.server.sockets[0].getsockname()[1] def connection_made(self, transport): """Client did connect to proxy.""" self.transport = transport def _send(self, message): data = message.SerializeToString() _LOGGER.info('<<(DECRYPTED): %s', message) if self.chacha: data = self.chacha.encrypt(data) log_binary(_LOGGER, '<<(ENCRYPTED)', Message=message) length = variant.write_variant(len(data)) self.transport.write(length + data) def _send_raw(self, raw): parsed = protobuf.ProtocolMessage() parsed.ParseFromString(raw) log_binary(_LOGGER, 'ATV->APP', Raw=raw) _LOGGER.info('ATV->APP Parsed: %s', parsed) if self.chacha: raw = self.chacha.encrypt(raw) log_binary(_LOGGER, 'ATV->APP', Encrypted=raw) length = variant.write_variant(len(raw)) try: self.transport.write(length + raw) except Exception: # pylint: disable=broad-except _LOGGER.exception('Failed to send to app') def message_received(self, _, raw): """Message received from ATV.""" self._send_raw(raw) def data_received(self, data): """Message received from iOS app/client.""" self.buffer += data while self.buffer: length, raw = variant.read_variant(self.buffer) if len(raw) < length: break data = raw[:length] self.buffer = raw[length:] if self.chacha: log_binary(_LOGGER, 'ENC Phone->ATV', Encrypted=data) data = self.chacha.decrypt(data) parsed = protobuf.ProtocolMessage() parsed.ParseFromString(data) _LOGGER.info('(DEC Phone->ATV): %s', parsed) try: def unhandled_message(_, raw): self.connection.send_raw(raw) self.mapping.get(parsed.type, unhandled_message)(parsed, data) except Exception: # pylint: disable=broad-except _LOGGER.exception('Error while dispatching message') def handle_device_info(self, message, _): """Handle received device information message.""" _LOGGER.debug('Received device info message') # TODO: Consolidate this better with message.device_information(...) resp = messages.create(protobuf.DEVICE_INFO_MESSAGE) resp.identifier = message.identifier resp.inner().uniqueIdentifier = self.atv_device_id.decode() resp.inner().name = 'ATVProxy' resp.inner().systemBuildVersion = '15K600' resp.inner().applicationBundleIdentifier = 'com.apple.mediaremoted' resp.inner().protocolVersion = 1 resp.inner().lastSupportedMessageType = 58 resp.inner().supportsSystemPairing = True resp.inner().allowsPairing = True resp.inner().systemMediaApplication = "com.apple.TVMusic" resp.inner().supportsACL = True resp.inner().supportsSharedQueue = True resp.inner().supportsExtendedMotion = True resp.inner().sharedQueueVersion = 2 self._send(resp) def handle_crypto_pairing(self, message, _): """Handle incoming crypto pairing message.""" _LOGGER.debug('Received crypto pairing message') pairing_data = tlv8.read_tlv(message.inner().pairingData) seqno = pairing_data[tlv8.TLV_SEQ_NO][0] getattr(self, "_seqno_" + str(seqno))(pairing_data) def _seqno_1(self, pairing_data): if self.has_paired: server_pub_key = self._verify_public.serialize() client_pub_key = pairing_data[tlv8.TLV_PUBLIC_KEY] self._shared = self._verify_private.get_shared_key( curve25519.Public(client_pub_key), hashfunc=lambda x: x) session_key = hkdf_expand('Pair-Verify-Encrypt-Salt', 'Pair-Verify-Encrypt-Info', self._shared) info = server_pub_key + self.atv_device_id + client_pub_key signature = SigningKey(self._signing_key.to_seed()).sign(info) tlv = tlv8.write_tlv({ tlv8.TLV_IDENTIFIER: self.atv_device_id, tlv8.TLV_SIGNATURE: signature }) chacha = chacha20.Chacha20Cipher(session_key, session_key) encrypted = chacha.encrypt(tlv, nounce='PV-Msg02'.encode()) msg = messages.crypto_pairing({ tlv8.TLV_SEQ_NO: b'\x02', tlv8.TLV_PUBLIC_KEY: server_pub_key, tlv8.TLV_ENCRYPTED_DATA: encrypted }) self.output_key = hkdf_expand('MediaRemote-Salt', 'MediaRemote-Write-Encryption-Key', self._shared) self.input_key = hkdf_expand('MediaRemote-Salt', 'MediaRemote-Read-Encryption-Key', self._shared) log_binary(_LOGGER, 'Keys', Output=self.output_key, Input=self.input_key) else: msg = messages.crypto_pairing({ tlv8.TLV_SALT: binascii.unhexlify(self.salt), tlv8.TLV_PUBLIC_KEY: binascii.unhexlify(self._session.public), tlv8.TLV_SEQ_NO: b'\x02' }) self._send(msg) def _seqno_3(self, pairing_data): if self.has_paired: self._send(messages.crypto_pairing({tlv8.TLV_SEQ_NO: b'\x04'})) self.chacha = chacha20.Chacha20Cipher(self.input_key, self.output_key) else: pubkey = binascii.hexlify( pairing_data[tlv8.TLV_PUBLIC_KEY]).decode() self._session.process(pubkey, self.salt) proof = binascii.unhexlify(self._session.key_proof_hash) assert self._session.verify_proof( binascii.hexlify(pairing_data[tlv8.TLV_PROOF])) msg = messages.crypto_pairing({ tlv8.TLV_PROOF: proof, tlv8.TLV_SEQ_NO: b'\x04' }) self._send(msg) def _seqno_5(self, _): self._session_key = hkdf_expand('Pair-Setup-Encrypt-Salt', 'Pair-Setup-Encrypt-Info', binascii.unhexlify(self._session.key)) acc_device_x = hkdf_expand('Pair-Setup-Accessory-Sign-Salt', 'Pair-Setup-Accessory-Sign-Info', binascii.unhexlify(self._session.key)) device_info = acc_device_x + self.atv_device_id + self._auth_public signature = self._signing_key.sign(device_info) tlv = tlv8.write_tlv({ tlv8.TLV_IDENTIFIER: self.atv_device_id, tlv8.TLV_PUBLIC_KEY: self._auth_public, tlv8.TLV_SIGNATURE: signature }) chacha = chacha20.Chacha20Cipher(self._session_key, self._session_key) encrypted = chacha.encrypt(tlv, nounce='PS-Msg06'.encode()) msg = messages.crypto_pairing({ tlv8.TLV_SEQ_NO: b'\x06', tlv8.TLV_ENCRYPTED_DATA: encrypted, }) self.has_paired = True self._send(msg)
def get_context(prime=None, generator=None, hash_func=None): return SRPContext(username, password, prime=prime, generator=generator, hash_func=hash_func)
def test_byte_hashes(): static_salt = int_from_hex('99e50c9ad1bd2856') static_client_private = int_from_hex('2b557313c052bb0e24a3c7462e8f436769a54e8d325da794004cefab83ac8b71') static_server_private = int_from_hex( '57e997761d2aeb4c8dbfed9fde120c0ec730af1237e296f58649a6b3193ff21b36f5cfaed3049ee0051e5378f666f13d' '0c7c91040940a77a3ff1a461666c41e9aca3bd4747d74036e34941578553eb56d369638f796707425d0294809e81363f' 'ac90af29c7fde1ae142f8c280e3c2e17f9c4d68f644de5406aac7d378b812a34') context = SRPContext('bouke', 'test') password_hash = context.get_common_password_hash(static_salt) password_verifier = context.get_common_password_verifier(password_hash) assert hex_from(password_verifier) == ( '52e3ee0cde007d2e7cee87acca1c041999b528e56dec925112d30a63d8e814231c2cd3bac9ae40220c44d63029912f1f' '7dda878e938ab5bfe7b87b854bb8385020d765054d07424eb5749fcd90344dbc0372432f6db25ae12cca4584ea72270c' 'a61d831540b10919a31fde1b7b9e1cc7110429d8bbde1a6fe005896697b91436') client_public = context.get_client_public(static_client_private) assert hex_from(client_public) == ( 'e18b11cddbfa709020fa2c67344a20e6704dba3e5ca6c4ca864b94ff5442965c80dfa751a9404feb2234fcd02d7f179d' 'ca4e308d76af173ec4eacc13a8daf0237bf19d4ac0ae9a4db885fdb46d5107caea8f71a8db39eda96d594e216c632a0d' '9720d84e8abb82b3dfa67fad099e1c67b13081bb564b2369c6db5f10358680b2') server_public = context.get_server_public(password_verifier, static_server_private) assert hex_from(server_public) == ( '0b3cc73f40a5fbdee992995dc26bfc43558803689798731fd303cdf18fdecbb5544f5caf960910f1b9449c772032be38' '2b22d8763104781793553977bfdbd7cd3b05af0bf00deee22d76b477275e3294713711e3fe97f34724f9580bf2c055e7' '8ae138664dfecaa2fe353768e30c3cc395541a929dc2af6a66e118ca937cffe8') common_secret = context.get_common_secret(server_public, client_public) assert hex_from(common_secret) == 'cb709a3c8a6767fda651ad6543436e4da2c85268' expected_premaster_secret = ( '8c0ade0a5cc22507230bf092348a518fe9c29f1cbeb7a1a089ac070da5f5f7d540377fa30703164823017f421cc71237' '2cc2093228fc6b05a4c77f05216c7c911fbdc2ed63f48a1ecec9da8a1edda3c810c724d8c45f83acd48a6c05f33d36b4' '0ebca6db6f34a3f8e69289f7e49ef3492265d18488d447fb232b56306cb39a3a') server_premaster_secret = context.get_server_premaster_secret( password_verifier, static_server_private, client_public, common_secret) assert hex_from(server_premaster_secret) == expected_premaster_secret client_premaster_secret = context.get_client_premaster_secret( password_hash, server_public, static_client_private, common_secret) assert hex_from(client_premaster_secret) == expected_premaster_secret expected_session_key = b'86a5aff58ae7eca772b05bbb629f5b1c51677b14' server_session_key = context.get_common_session_key(server_premaster_secret) assert hex_from(server_session_key) == expected_session_key client_session_key = context.get_common_session_key(client_premaster_secret) assert hex_from(client_session_key) == expected_session_key client_session_key_prove = context.get_common_session_key_proof( client_session_key, static_salt, server_public, client_public) assert hex_from(client_session_key_prove) == b'001961fb3aa5c24c437df55a18a41cabce3d57b4' server_session_key_prove = context.get_common_session_key_proof_hash( server_session_key, client_session_key_prove, client_public) assert hex_from(server_session_key_prove) == b'f0a6d49e5037f34b770a8e2de9ec5e3c0880953b'
from mysecrets import HOST,PORT, cbc_oracle_iv as iv from mysecrets import cbc_oracle_ciphertext as ciphertext DATA_SIZE = 65535 USERNAME = '******' PASSWORD = '******' if __name__ == '__main__': # the user should receive the salt from the server, before generating the context context = SRPContext(USERNAME, PASSWORD) username, password_verifier, client_salt = context.get_user_data_triplet() print(username) print(password_verifier) print(client_salt) prime = context.prime gen = context.generator print(prime) print(gen) server = remote(HOST, PORT) auth_data = json.dumps({'username': username, 'prime': prime, 'generator': gen, 'password_verifier': password_verifier, 'salt': client_salt}) print(auth_data)
def pairing(socket, config): msg = ProtocolMessage_pb2.ProtocolMessage() msg.type = ProtocolMessage_pb2.ProtocolMessage.CRYPTO_PAIRING_MESSAGE msg.Extensions[CryptoPairingMessage_pb2.cryptoPairingMessage].status = 0 msg.Extensions[ CryptoPairingMessage_pb2.cryptoPairingMessage].pairingData = tlv_build( { kTLVType_Method: b'\x00', kTLVType_State: b'\x01' }) msg.Extensions[CryptoPairingMessage_pb2.cryptoPairingMessage].state = 2 send(msg, socket) msg = receive(socket) parsed = tlv_parse(msg.Extensions[ CryptoPairingMessage_pb2.cryptoPairingMessage].pairingData) appletv_public = parsed[kTLVType_PublicKey] salt = parsed[kTLVType_Salt] code = input("Enter code displayed by Apple TV: ") session = SRPClientSession( SRPContext("Pair-Setup", code, PRIME_3072, PRIME_3072_GEN, hashlib.sha512, bits_random=256, bits_salt=128)) session.process(binascii.hexlify(appletv_public), binascii.hexlify(salt)) our_public = binascii.unhexlify(session.public) key_proof = binascii.unhexlify(session.key_proof) msg = ProtocolMessage_pb2.ProtocolMessage() msg.type = ProtocolMessage_pb2.ProtocolMessage.CRYPTO_PAIRING_MESSAGE msg.Extensions[CryptoPairingMessage_pb2.cryptoPairingMessage].status = 0 tlv = tlv_build({ kTLVType_State: b'\x03', kTLVType_PublicKey: our_public, kTLVType_Proof: key_proof }) msg.Extensions[ CryptoPairingMessage_pb2.cryptoPairingMessage].pairingData = tlv send(msg, socket) msg = receive(socket) parsed = tlv_parse(msg.Extensions[ CryptoPairingMessage_pb2.cryptoPairingMessage].pairingData) proof = parsed[kTLVType_Proof] if not session.verify_proof(binascii.hexlify(proof)): print("proof does not match!") exit(1) ltsk, ltpk = ed25519.create_keypair() hkdf = HKDF(hashes.SHA512(), 32, b"Pair-Setup-Controller-Sign-Salt", b"Pair-Setup-Controller-Sign-Info", default_backend()) x = hkdf.derive(binascii.unhexlify(session.key)) device_id = bytes(config['device_id'], 'utf-8') info = x + device_id + ltpk.to_bytes() subtlv = tlv_build({ kTLVType_Identifier: device_id, kTLVType_PublicKey: ltpk.to_bytes(), kTLVType_Signature: ltsk.sign(info) }) hkdf = HKDF(hashes.SHA512(), 32, b"Pair-Setup-Encrypt-Salt", b"Pair-Setup-Encrypt-Info", default_backend()) x = hkdf.derive(binascii.unhexlify(session.key)) cha_cha_poly = ChaCha20Poly1305(x) encrypted = cha_cha_poly.encrypt(b"\0\0\0\0PS-Msg05", subtlv, None) msg = ProtocolMessage_pb2.ProtocolMessage() msg.type = ProtocolMessage_pb2.ProtocolMessage.CRYPTO_PAIRING_MESSAGE msg.Extensions[CryptoPairingMessage_pb2.cryptoPairingMessage].status = 0 msg.Extensions[ CryptoPairingMessage_pb2.cryptoPairingMessage].pairingData = tlv_build( { kTLVType_State: b'\x05', kTLVType_EncryptedData: encrypted }) send(msg, socket) msg = receive(socket) parsed = tlv_parse(msg.Extensions[ CryptoPairingMessage_pb2.cryptoPairingMessage].pairingData) encrypted = parsed[kTLVType_EncryptedData] subtlv = tlv_parse( cha_cha_poly.decrypt(b"\0\0\0\0PS-Msg06", encrypted, None)) hkdf = HKDF(hashes.SHA512(), 32, b"Pair-Setup-Accessory-Sign-Salt", b"Pair-Setup-Accessory-Sign-Info", default_backend()) x = hkdf.derive(binascii.unhexlify(session.key)) info = x + subtlv[kTLVType_Identifier] + subtlv[kTLVType_PublicKey] ed25519.VerifyingKey(subtlv[kTLVType_PublicKey]).verify( subtlv[kTLVType_Signature], info) pickle.dump( { "seed": ltsk.to_seed(), "peer_id": subtlv[kTLVType_Identifier], "peer_public_key": subtlv[kTLVType_PublicKey] }, open("data/pairing.state", "wb"))
# print(prime) # print(gen) # receive user data user_data = conn.recv(DATA_SIZE).decode() auth_data = json.loads(user_data) # print(auth_data) print("username = "******"prime = " + str(auth_data['prime'])) print("generator= " + str(auth_data['generator'])) print("verifier = " + str(auth_data['password_verifier'])) # generate user-based server parameters server_session = SRPServerSession( SRPContext(auth_data['username'], prime=auth_data['prime'], generator=auth_data['generator']), auth_data['password_verifier']) server_public = server_session.public print("server public= " + str(server_public)) server_data = json.dumps({'server_verifier': server_public}) # 'server_salt' : server_salt}) # print(server_data) conn.send(server_data.encode()) # receive client parameters user_data = conn.recv(DATA_SIZE).decode() client_parameters = json.loads(user_data) # print(client_parameters)
subparsers.is_required = True subparsers.add_parser("server") subparsers.add_parser("client") parser.add_argument("username", type=hex_encoded_utf8) parser.add_argument("password", type=hex_encoded_utf8) args = parser.parse_args() prime = groups[args.group][0] generator = groups[args.group][1] hash_func = algorithms[args.algorithm] ensure_hash_size = ensure_hash_sizes[args.algorithm] context = SRPContext(args.username, args.password, prime=prime, generator=generator, hash_func=hash_func) if args.command == "server": if args.salt: salt = args.salt password_verifier = value_encode( context.get_common_password_verifier( context.get_common_password_hash(unhexlify(salt)))) else: _, password_verifier, salt = context.get_user_data_triplet() print("v:", password_verifier) # Client => Server: username, A
PASSWORD = '******' if __name__ == '__main__': server = remote(HOST, PORT) received_data = server.recv(DATA_SIZE).decode() server_data = json.loads(received_data) print(server_data['prime']) print(server_data['generator']) print(server_data['B']) print(server_data['server_salt']) #receive server verifier and salt, and all the public parameters client_session = SRPClientSession( SRPContext(USERNAME, PASSWORD, prime=server_data['prime'], generator = server_data['generator'] ) ) client_session.process(server_data['B'], server_data['server_salt']) client_public_A = client_session.public print(client_public_A) client_session_key_proof = client_session.key_proof.hex() print(client_session_key_proof) client_parameters = json.dumps({'A':client_public_A,'client_session_key_proof':client_session_key_proof}) print(client_parameters) server.send(client_parameters.encode()) print("KEY = " + str(client_session.key)) # receive the server key proof
from srptools import SRPContext, SRPServerSession, SRPClientSession username = '******' password = '******' ### at the client, where the password is known srp_context = SRPContext(username, password) # gen, prime user, password_verifier, salt = srp_context.get_user_data_triplet() gen = srp_context.generator prime = srp_context.prime ##### # HERE WE ARE IN THE SERVER # client send the server user, password_verifier, salt, gen, prime server_context = SRPContext(username, prime=prime, generator=gen) ########### # authentication starts here server_session = SRPServerSession(server_context, password_verifier) server_public_B = server_session.public # to be sent to the client ##### # HERE WE ARE IN THE CLIENT client_session = SRPClientSession(srp_context) client_public_A = client_session.public # the client has received B # the server has received A
def test_context(): def to_hex_u(val): return hex_from(val).upper() static_salt = int_from_hex('BEB25379D1A8581EB5A727673A2441EE') static_client_private = int_from_hex('60975527035CF2AD1989806F0407210BC81EDC04E2762A56AFD529DDDA2D4393') static_server_private = int_from_hex('E487CB59D31AC550471E81F00F6928E01DDA08E974A004F49E61F5D105284D20') context = SRPContext( 'alice', 'password123', multiplier='7556AA045AEF2CDD07ABAF0F665C3E818913186F', ) assert context.prime_b64 assert context.generator_b64 password_hash = context.get_common_password_hash(static_salt) assert to_hex_u(password_hash) == '94B7555AABE9127CC58CCF4993DB6CF84D16C124' password_verifier = context.get_common_password_verifier(password_hash) assert to_hex_u(password_verifier) == ( '7E273DE8696FFC4F4E337D05B4B375BEB0DDE1569E8FA00A9886D8129BADA1F1822223CA1A605B530E379BA4729FDC59' 'F105B4787E5186F5C671085A1447B52A48CF1970B4FB6F8400BBF4CEBFBB168152E08AB5EA53D15C1AFF87B2B9DA6E04' 'E058AD51CC72BFC9033B564E26480D78E955A5E29E7AB245DB2BE315E2099AFB') client_public = context.get_client_public(static_client_private) assert to_hex_u(client_public) == ( '61D5E490F6F1B79547B0704C436F523DD0E560F0C64115BB72557EC44352E8903211C04692272D8B2D1A5358A2CF1B6E' '0BFCF99F921530EC8E39356179EAE45E42BA92AEACED825171E1E8B9AF6D9C03E1327F44BE087EF06530E69F66615261' 'EEF54073CA11CF5858F0EDFDFE15EFEAB349EF5D76988A3672FAC47B0769447B') server_public = context.get_server_public(password_verifier, static_server_private) assert to_hex_u(server_public) == ( 'BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011BAF38964DC46A0670DD125B95A981652236F99D9' 'B681CBF87837EC996C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA37089E6F9C6059F388838E7A' '00030B331EB76840910440B1B27AAEAEEB4012B7D7665238A8E3FB004B117B58') common_secret = context.get_common_secret(server_public, client_public) assert to_hex_u(common_secret) == 'CE38B9593487DA98554ED47D70A7AE5F462EF019' expected_premaster_secret = ( 'B0DC82BABCF30674AE450C0287745E7990A3381F63B387AAF271A10D233861E359B48220F7C4693C9AE12B0A6F67809F' '0876E2D013800D6C41BB59B6D5979B5C00A172B4A2A5903A0BDCAF8A709585EB2AFAFA8F3499B200210DCC1F10EB3394' '3CD67FC88A2F39A4BE5BEC4EC0A3212DC346D7E474B29EDE8A469FFECA686E5A') expected_session_key = b'017EEFA1CEFC5C2E626E21598987F31E0F1B11BB' server_premaster_secret = context.get_server_premaster_secret( password_verifier, static_server_private, client_public, common_secret) assert to_hex_u(server_premaster_secret) == expected_premaster_secret client_premaster_secret = context.get_client_premaster_secret( password_hash, server_public, static_client_private, common_secret) assert to_hex_u(client_premaster_secret) == expected_premaster_secret server_session_key = context.get_common_session_key(server_premaster_secret) assert to_hex_u(server_session_key) == expected_session_key client_session_key = context.get_common_session_key(client_premaster_secret) assert to_hex_u(client_session_key) == expected_session_key client_session_key_prove = context.get_common_session_key_proof( client_session_key, static_salt, server_public, client_public) assert to_hex_u(client_session_key_prove) == b'3F3BC67169EA71302599CF1B0F5D408B7B65D347' server_session_key_prove = context.get_common_session_key_proof_hash( server_session_key, client_session_key_prove, client_public) assert to_hex_u(server_session_key_prove) == b'9CAB3C575A11DE37D3AC1421A9F009236A48EB55'