def load_keys(): try: tmp_keys = json.load(open(key_path)) fix_key_perms() except: keys['my_key'] = curve25519.Private() save_keys() return for key in tmp_keys: if key == 'my_key': keys[key] = curve25519.Private(b64decode(tmp_keys[key])) else: keys[key] = curve25519.Public(b64decode(tmp_keys[key]))
def decrypt_message(self, ct, decryptor): decryptor = self.derive_keys(decryptor) pt = self.decrypt(ct, decryptor['message_key'], decryptor['message_counter']) if not pt: return None bob_ephemeral, msg = pt[:32], pt[32:] self.receive = decryptor # it's encrypted with the same key it advertised.. shouldn't happen. if bob_ephemeral == self.receive['bob'].serialize(): raise # it's advertising the receive_pending key, we need to respond again because # they may not have gotten it. elif self.receive_pending \ and bob_ephemeral == self.receive_pending['bob'].serialize(): pass # yay a new key! we need to respond. elif not self.receive_pending \ or bob_ephemeral != self.receive_pending['bob'].serialize(): self.receive_pending = { 'alice': curve25519.Private(), 'bob': curve25519.Public(bob_ephemeral), 'receiver': True, 'acked': False } # uncharted territory... else: raise return msg
def recover_seed(key='', modulus=None, pos=1): # recreate the master private key from the passphrase master = curve25519.Private(secret=sha256(key).digest()) # extract the ephemeral public key from modulus ephem_pub = curve25519.Public(modulus[pos:pos + 32]) # compute seed with master private and ephemeral public return (master.get_shared_key(ephem_pub), ephem_pub)
def login(self): self._expected_message_tags = ['s1', 's2', 's3', 's4'] self._clientId = str(b64encode(os.urandom(16)), 'utf8') self._whatsappweb_version = get_whatsappweb_version() connection_query_name = 'connection_query' self._expected_message_tags.append(connection_query_name) connection_query_json = ['admin', 'init', self._whatsappweb_version, self._browser_desc, self._clientId, True] self.ws_send(connection_query_name, connection_query_json) connection_result = self.wait_query_pop_json(connection_query_name) if connection_result['status'] != 200: raise ConnectionRefusedError('Websocket connection refused') self._qrcode = { 'must_scan': False, 'id': 0, 'ref': connection_result['ref'], 'ttl' : connection_result['ttl'] / 1000 - 1, 'time' : connection_result['time']} self._qrcode['timeout'] = time.time() + self._qrcode['ttl'] if self._session_path and os.path.exists(self._session_path): self.restore_session() self.post_login() else: self._qrcode['must_scan'] = True self._privateKey = curve25519.Private() self._publicKey = self._privateKey.get_public() bin_qrcode = gen_qrcode(self._qrcode['ref'], self._publicKey, self._clientId) self._qrcode['qrcode'] = render_qrcode(bin_qrcode)
def verify1(self): """ First device verification step. """ self._verify_private = curve25519.Private(secret=self.seed) self._verify_public = self._verify_private.get_public() verify_public = self._verify_public.serialize() return b'\x01\x00\x00\x00' + verify_public + self._auth_public
def initialize(self): """Initialize operation by generating new keys.""" self._signing_key = SigningKey(os.urandom(32)) 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=os.urandom(32)) self._verify_public = self._verify_private.get_public() return self._auth_public, self._verify_public.serialize()
def test_curve25519(r): sec1 = bytes(bytearray(r.randbytes(32))) sec2 = bytes(bytearray(r.randbytes(32))) pub1 = curve25519.Private(sec1).get_public() pub2 = curve25519.Private(sec2).get_public() session1 = r.randbytes(32) lib.curve25519_scalarmult(session1, sec2, pub1.public) session2 = r.randbytes(32) lib.curve25519_scalarmult(session2, sec1, pub2.public) assert bytearray(session1) == bytearray(session2) shared1 = curve25519.Private(sec2).get_shared_key(pub1, hashfunc=lambda x: x) shared2 = curve25519.Private(sec1).get_shared_key(pub2, hashfunc=lambda x: x) assert shared1 == shared2 assert bytearray(session1) == shared1 assert bytearray(session2) == shared2
def _generate_keys(self, mkey): """ start to generate authentication keys, and allowing to set the mac_key value in case exists """ self.private = curve25519.Private() self.public = self.private.get_public() self.mac_key = mkey
def generate_keys(seed): """Generate server encryption keys from seed.""" signing_key = SigningKey(seed) verify_private = curve25519.Private(secret=seed) return ServerKeys(sign=signing_key, auth=signing_key.to_bytes(), auth_pub=signing_key.get_verifying_key().to_bytes(), verify=verify_private, verify_pub=verify_private.get_public())
def __init__(self, node): # 5.1.4. The "ntor" handshake # This handshake uses a set of DH handshakes to compute a set of # shared keys which the client knows are shared only with a particular # server, and the server knows are shared with whomever sent the # original handshake (or with nobody at all). Here we use the # "curve25519" group and representation as specified in "Curve25519: # new Diffie-Hellman speed records" by D. J. Bernstein. # [The ntor handshake was added in Tor 0.2.4.8-alpha.] self.node = node # In this section, define: # H(x,t) as HMAC_SHA256 with message x and key t. # H_LENGTH = 32. # ID_LENGTH = 20. # G_LENGTH = 32 # PROTOID = "ntor-curve25519-sha256-1" # t_mac = PROTOID | ":mac" # t_key = PROTOID | ":key_extract" # t_verify = PROTOID | ":verify" # MULT(a,b) = the multiplication of the curve25519 point 'a' by the # scalar 'b'. # G = The preferred base point for curve25519 ([9]) # KEYGEN() = The curve25519 key generation algorithm, returning # a private/public keypair. # m_expand = PROTOID | ":key_expand" # H is defined as hmac() # MULT is included in the curve25519 library as get_shared_key() # KEYGEN() is curve25519.Private() self.protoid = 'ntor-curve25519-sha256-1' self.t_mac = self.protoid + ':mac' self.t_key = self.protoid + ':key_extract' self.t_verify = self.protoid + ':verify' self.m_expand = self.protoid + ':key_expand' # To perform the handshake, the client needs to know an identity key # digest for the server, and an ntor onion key (a curve25519 public # key) for that server. Call the ntor onion key "B". The client # generates a temporary keypair: # x,X = KEYGEN() self.x = curve25519.Private() self.X = self.x.get_public() self.B = curve25519.Public(b64decode(self.node['ntor-onion-key'])) # and generates a client-side handshake with contents: # NODEID Server identity digest [ID_LENGTH bytes] # KEYID KEYID(B) [H_LENGTH bytes] # CLIENT_PK X [G_LENGTH bytes] self.handshake = b64decode(self.node['identity']) self.handshake += self.B.serialize() self.handshake += self.X.serialize()
def verify1(self): """First device verification step.""" self._check_initialized() self._verify_private = curve25519.Private(secret=self.seed) self._verify_public = self._verify_private.get_public() _log_debug('Verification keys', Private=self._verify_private.serialize(), Public=self._verify_public.serialize()) verify_public = self._verify_public.serialize() return b'\x01\x00\x00\x00' + verify_public + self._auth_public
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 _pair_verify_one(self, tlv_objects): """Generate new session key pair and send a proof to the client. @param tlv_objects: The TLV data received from the client. @type tlv_object: dict """ logger.debug("Pair verify [1/2].") client_public = tlv_objects[HAP_TLV_TAGS.PUBLIC_KEY] private_key = curve25519.Private() public_key = private_key.get_public() shared_key = private_key.get_shared_key( curve25519.Public(client_public), # Key is hashed before being returned, we don't want it; This fixes that. lambda x: x, ) mac = self.state.mac.encode() material = public_key.serialize() + mac + client_public server_proof = self.state.private_key.sign(material) output_key = hap_hkdf(shared_key, self.PVERIFY_1_SALT, self.PVERIFY_1_INFO) self._set_encryption_ctx(client_public, private_key, public_key, shared_key, output_key) message = tlv.encode(HAP_TLV_TAGS.USERNAME, mac, HAP_TLV_TAGS.PROOF, server_proof) cipher = ChaCha20Poly1305(output_key) aead_message = bytes( cipher.encrypt(self.PVERIFY_1_NONCE, bytes(message), b"")) data = tlv.encode( HAP_TLV_TAGS.SEQUENCE_NUM, b"\x02", HAP_TLV_TAGS.ENCRYPTED_DATA, aead_message, HAP_TLV_TAGS.PUBLIC_KEY, public_key.serialize(), ) self.send_response(200) self.send_header("Content-Type", self.PAIRING_RESPONSE_TYPE) self.end_response(data)
def __init__(self, ref_dict, priv_key_list, pub_key_list): self.conn_data = { "private_key": None, "public_key": None, "secret": None, "shared_secret": None, "shared_secret_ex": None, "aes_key": None, "mac_key": None } self.conn_data["private_key"] = curve25519.Private("".join( [chr(x) for x in priv_key_list])) self.conn_data["public_key"] = self.conn_data[ "private_key"].get_public() assert (self.conn_data["public_key"].serialize() == "".join( [chr(x) for x in pub_key_list])) self.conn_data["secret"] = base64.b64decode(ref_dict["secret"]) self.conn_data["shared_secret"] = self.conn_data[ "private_key"].get_shared_key( curve25519.Public(self.conn_data["secret"][:32]), lambda key: key) shared_expended = self.conn_data["shared_secret_ex"] = HKDF( self.conn_data["shared_secret"], 80) check_hmac = hmac_sha256( shared_expended[32:64], self.conn_data["secret"][:32] + self.conn_data["secret"][64:]) if check_hmac != self.conn_data["secret"][32:64]: raise ValueError("Error hmac mismatch") keysDecrypted = AESDecrypt( shared_expended[:32], shared_expended[64:] + self.conn_data["secret"][64:]) self.conn_data["aes_key"] = keysDecrypted[:32] self.conn_data["mac_key"] = keysDecrypted[32:64]
def _pair_verify_one(self, tlv_objects): """Generate new session key pair and send a proof to the client. @param tlv_objects: The TLV data received from the client. @type tlv_object: dict """ logging.debug("Pair verify [1/2].") client_public = tlv_objects[HAP_TLV_TAGS.PUBLIC_KEY] private_key = curve25519.Private() public_key = private_key.get_public() shared_key = private_key.get_shared_key( curve25519.Public(client_public), # Key is hashed before being returned, we don't want it; This fixes that. lambda x: x) mac = self._state.mac.encode() material = public_key.serialize() + mac + client_public server_proof = self._state.private_key.sign(material) output_key = hap_hkdf(shared_key, PVERIFY_1_SALT, PVERIFY_1_INFO) enc_context = { "client_public": client_public, "private_key": private_key, "public_key": public_key, "shared_key": shared_key, "pre_session_key": output_key } message = tlv.encode(HAP_TLV_TAGS.USERNAME, mac, HAP_TLV_TAGS.PROOF, server_proof) cipher = CHACHA20_POLY1305(output_key, "python") aead_message = bytes( cipher.seal(PVERIFY_1_NONCE, bytearray(message), b"")) data = tlv.encode(HAP_TLV_TAGS.SEQUENCE_NUM, b'\x02', HAP_TLV_TAGS.ENCRYPTED_DATA, aead_message, HAP_TLV_TAGS.PUBLIC_KEY, public_key.serialize()) return data, enc_context
def _pair_verify_one(self, tlv_objects): """Generate new session key pair and send a proof to the client. @param tlv_objects: The TLV data received from the client. @type tlv_object: dict """ logger.debug("Pair verify [1/2].") client_public = tlv_objects[HAP_TLV_TAGS.PUBLIC_KEY] private_key = curve25519.Private() public_key = private_key.get_public() shared_key = private_key.get_shared_key( curve25519.Public(client_public), # Why not randomly hash the key before returning it # so that it is incompatible with another # implementation and force clients to use hacks? lambda x: x) mac = self.accessory.mac.encode() material = public_key.serialize() + mac + client_public server_proof = self.accessory.private_key.sign(material) output_key = hap_hkdf(shared_key, self.PVERIFY_1_SALT, self.PVERIFY_1_INFO) self._set_encryption_ctx(client_public, private_key, public_key, shared_key, output_key) message = tlv.encode(HAP_TLV_TAGS.USERNAME, mac, HAP_TLV_TAGS.PROOF, server_proof) cipher = CHACHA20_POLY1305(output_key, "python") aead_message = bytes( cipher.seal(self.PVERIFY_1_NONCE, bytearray(message), b"")) data = tlv.encode(HAP_TLV_TAGS.SEQUENCE_NUM, b'\x02', HAP_TLV_TAGS.ENCRYPTED_DATA, aead_message, HAP_TLV_TAGS.PUBLIC_KEY, public_key.serialize()) self.send_response(200) self.send_header("Content-Type", self.PAIRING_RESPONSE_TYPE) self.end_response(data)
def initLocalParams(self): logging.info('Entering Initlocalparms') self.data = self.restoreSession() keySecret = None if self.data is None: self.mydata['clientId'] = base64.b64encode(os.urandom(16)) keySecret = os.urandom(32) self.mydata["keySecret"] = base64.b64encode(keySecret) else: self.sessionExists = True self.mydata = self.data['myData'] keySecret = base64.b64decode(self.mydata["keySecret"]) self.clientId = self.mydata['clientId'] self.privateKey = curve25519.Private(secret=keySecret) self.publicKey = self.privateKey.get_public() logging.info('ClientId %s' % self.clientId) logging.info('Exiting Initlocalparms') if self.sessionExists: self.setConnInfoParams(base64.b64decode(self.data["secret"]))
def derive_keys(self, key=None): # initial key exchanges. if not key or 'bob' not in key: master = self.long_term.get_shared_key(self.bob_long_term, self.derive_key) key = key or {} # we're sending elif 'receiver' not in key: master = self.long_term.get_shared_key(key['bob'], self.derive_key) master += key['alice'].get_shared_key(self.bob_long_term, self.derive_key) master += key['alice'].get_shared_key(key['bob'], self.derive_key) # we are receiving else: if 'alice' not in key: key['alice'] = curve25519.Private() master = key['alice'].get_shared_key(self.bob_long_term, self.derive_key) master += self.long_term.get_shared_key(key['bob'], self.derive_key) master += key['alice'].get_shared_key(key['bob'], self.derive_key) # derive keys # increment counter if 'counter' in key: key['counter'] += 1 else: key['counter'] = 0 mac_key = self.proto_id + '::poly1305' master = poly1305(master + str(key['counter']), mac_key) master = self.derive_key(master, 176) keys = list(struct.unpack('>32s32s32s32s24s24s', master)) key['exchange_counter'] = keys.pop() key['message_counter'] = keys.pop() key['exchange_chaff_key'] = keys.pop() key['chaff_key'] = keys.pop() key['exchange_key'] = keys.pop() key['message_key'] = keys.pop() return key
def encrypt_msg(self, msg): self.send = self.derive_keys(self.send) self.print_key('Encrypting message.', self.send) if not self.send_pending: self.send_pending = { 'alice': curve25519.Private() } pt = self.get_public(self.send_pending['alice']) pt += msg # message buffering if 'msgs' not in self.send_pending: self.send_pending['msgs'] = [] self.send_pending['msgs'].append(msg) if not self.established(): return ct = self.encrypt(pt, self.send['message_key'], self.send['message_counter']) blocks = self.mac_blocks(ct, self.send['chaff_key']) return self.chaff(blocks)
def __init__(self, ref_dict, priv_key_list, pub_key_list): self.decrypted_serialized_content = None self.message_tag = None self.decrypted_content = None self.original_content = None self.private_key = None self.public_key = None self.secret = None self.shared_secret = None self.aes_key = None self.mac_key = None self.private_key = curve25519.Private("".join( [chr(x) for x in priv_key_list])) self.public_key = self.private_key.get_public() assert (self.public_key.serialize() == "".join( [chr(x) for x in pub_key_list])) self.secret = base64.b64decode(ref_dict["secret"]) self.shared_secret = self.private_key.get_shared_key( curve25519.Public(self.secret[:32]), lambda key: key) shared_expended = HKDF(self.shared_secret, 80) check_hmac = hmac_sha256(shared_expended[32:64], self.secret[:32] + self.secret[64:]) if check_hmac != self.secret[32:64]: raise ValueError("Error hmac mismatch") keys_decrypted = aes_decrypt(shared_expended[:32], shared_expended[64:] + self.secret[64:]) self.aes_key = keys_decrypted[:32] self.mac_key = keys_decrypted[32:64]
def initLocalParams(self): logging.info('Entering Initlocalparms') logging.info('Local storage is: {}'.format(self.isLocalStorage)) self.data = self.restoreSession() keySecret = None if self.data is None: self.mydata['clientId'] = base64.b64encode(os.urandom(16)) keySecret = os.urandom(32) self.mydata["keySecret"] = base64.b64encode(keySecret) else: self.sessionExists = True if not self.isLocalStorage: self.mydata = self.data['myData'] keySecret = base64.b64decode(self.mydata["keySecret"]) else: self.mydata = self.data self.data["clientToken"] = json.loads(self.data["WAToken1"]) self.data["serverToken"] = json.loads(self.data["WAToken2"]) self.data["clientId"] = json.loads(self.data["WABrowserId"]) self.mydata = self.data self.clientId = self.mydata['clientId'] self.privateKey = curve25519.Private(secret=keySecret) self.publicKey = self.privateKey.get_public() logging.info('ClientId %s' % self.clientId) logging.info('Exiting Initlocalparms') if self.sessionExists: if not self.isLocalStorage: self.setConnInfoParams(base64.b64decode(self.data["secret"])) else: secretBundle = json.loads(self.data['WASecretBundle']) self.encKey = base64.b64decode(secretBundle['encKey']) self.macKey = base64.b64decode(secretBundle['macKey']) self.subscribeStarted = False
def test_curve25519_pubkey(r): sec = bytes(bytearray(r.randbytes(32))) pub = curve25519.Private(sec).get_public() res = r.randbytes(32) lib.curve25519_scalarmult_basepoint(res, sec) assert bytearray(res) == pub.public
if __name__ == "__main__": # passphrase and filename as arguments if len(sys.argv) == 3: # Load an x.509 certificate from a file x509 = X509.load_cert(sys.argv[2]) # Pull the modulus out of the certificate orig_modulus = unhexlify(x509.get_pubkey().get_modulus()) (seed, ephem_pub) = recover_seed(key=sys.argv[1], modulus=orig_modulus, pos=80) # no arguments, just generate a private key else: # deserialize master ECDH public key embedded in program master_pub = curve25519.Public(unhexlify(MASTER_PUB_HEX)) # generate a random (yes, actually random) ECDH private key ephem = curve25519.Private() # derive the corresponding public key for later embedding ephem_pub = ephem.get_public() # combine the ECDH keys to generate the seed seed = ephem.get_shared_key(master_pub) prng = AESPRNG(seed) ephem_pub = ephem_pub.serialize() # deterministic key generation from seed rsa = build_key(embed=ephem_pub, pos=80, randfunc=prng.randbytes) if 'orig_modulus' in locals(): if long(hexlify(orig_modulus), 16) != long(rsa.n): raise Exception("key recovery failed")
def __init__(self, secret=None): self._private = curve25519.Private(secret)
def init_keys(self): self.initialized = False self.initial_key = { 'initial_key': True } self.send = { 'alice': curve25519.Private() } self.receive = { 'alice': curve25519.Private(), 'receiver': True }
def pairVerifyStep1(self, tlvData): publicKey = tlvData['public_key']['data'] accessoryLTSK = ed25519.SigningKey(self.longTermKey, encoding='hex') # accessoryLTPK = accessoryLTSK.get_verifying_key() accessoryPairingID = HapHandler.getId() iosDevicePublicKey = curve25519.Public(''.join( [chr(x) for x in publicKey])) # Step 1 private = curve25519.Private() public = private.get_public() publicSerialized = public.serialize() # Step 2 shared = private.get_shared_key(iosDevicePublicKey, hashfunc=lambda x: x) # Step 3 accessoryPairingInfo = publicSerialized + accessoryPairingID + iosDevicePublicKey.serialize( ) # Step 4 accessorySignature = accessoryLTSK.sign(accessoryPairingInfo) # Step 5 response = [] response.append({ 'type': 'identifier', 'length': len(accessoryPairingID), 'data': accessoryPairingID }) response.append({ 'type': 'signature', 'length': len(accessorySignature), 'data': accessorySignature }) subTLV = pack(response) # tlv # Step 6 inputKey = shared salt = 'Pair-Verify-Encrypt-Salt' info = 'Pair-Verify-Encrypt-Info' key = Hkdf(salt, inputKey, hash=hashlib.sha512) sessionKey = key.expand(info, length=32) key = Hkdf('Control-Salt', shared, hash=hashlib.sha512) writeKey = key.expand('Control-Write-Encryption-Key', length=32) key = Hkdf('Control-Salt', shared, hash=hashlib.sha512) readKey = key.expand('Control-Read-Encryption-Key', length=32) self.sessionStorage = { 'clientPublicKey': iosDevicePublicKey.serialize(), 'secretKey': private.serialize(), 'publicKey': publicSerialized, 'sharedSec': shared, 'hkdfPairEncKey': sessionKey, 'writeKey': writeKey, 'readKey': readKey } # Step 7 ciphertext, mac = HapHandler.encryptAndSeal(sessionKey, 'PV-Msg02', [ord(x) for x in subTLV]) self.sendTLVResponse([ { 'type': 'state', 'length': 1, 'data': 2 }, { 'type': 'public_key', 'length': len(publicSerialized), 'data': publicSerialized }, { 'type': 'encrypted_data', 'length': len(ciphertext + mac), 'data': ciphertext + mac }, ])
print 'Bob ephemeral public: ' + key['bob'].serialize().encode('hex') if 'message_key' in key: print 'Shared key: ' + key['message_key'].encode('hex') if 'chaff_key' in key: print 'Chaff key: ' + key['chaff_key'].encode('hex') if 'exchange_key' in key: print 'Exchange shared key: ' + key['exchange_key'].encode('hex') if 'exchange_chaff_key' in key: print 'Exchange chaff key: ' + key['exchange_chaff_key'].encode('hex') if 'counter' in key: print 'Counter: %d' % key['counter'] print '' if __name__ == "__main__": alice_key = curve25519.Private() bob_key = curve25519.Private() alice = Chats(alice_key, bob_key.get_public(), 400, 8, debug=False) bob = Chats(bob_key, alice_key.get_public(), 400, 8, debug=False) ct = alice.encrypt_initial_keyx() msg = bob.decrypt_msg(ct) alice.decrypt_msg(msg['keyx']) print '\nAlice -> Bob initial: ' ct = alice.encrypt_msg('ayy lmaoayy lmao') msg = bob.decrypt_msg(ct) if msg['keyx']: alice.decrypt_msg(msg['keyx']) print 'Plaintext: %s' % msg['msg']