def __init__(self, filename, masterkey, aessiv=False): if aessiv: self.decrypt_block = self.decrypt_siv_block self.key = HKDF(masterkey, salt=b"", key_len=64, hashmod=SHA256, context=b"AES-SIV file content encryption") else: self.decrypt_block = self.decrypt_gcm_block self.key = HKDF(masterkey, salt=b"", key_len=32, hashmod=SHA256, context=b"AES-GCM file content encryption") self.fp = open(filename, "rb") header = self.fp.read(18) if len(header) == 0: # An empty file is valid. It means that the plaintext file # was empty. self.fileid = None else: assert len(header) == 18 assert header[0:2] == b"\x00\x02" self.fileid = header[2:] self.blockno = 0 self.remaining = io.BytesIO()
def compute_2skd(sk, password, email, p2salt, iterations, algorithm): p_debug("** Computing 2SKD\n") version = sk[0:2] account_id = sk[3:9] secret = re.sub('-', '', sk[10:]) email = email.lower() # simple hack...not doing "proper" normalizaiton... email = str.encode(str(email)) version = str.encode(str(version)) secret = str.encode(str(secret)) account_id = str.encode(str(account_id)) algorithm = str.encode(str(algorithm)) p_str('Password', password) p_str('Email', email) p_str('Secret Key', sk) p_str(' Version', version) p_str(' AcctID', account_id) p_str(' Secret', secret) p_str('Algorithm', algorithm) p_str('Iterations (p2c)', iterations) p_str('Salt (p2s)', opb64e(p2salt)) p_data('Salt (decoded)', p2salt, dump=False) hkdf_pass_salt = HKDF(p2salt, 32, email, SHA256, 1, algorithm) p_debug('\nHKDF(ikm=p2s, len=32, salt=email, hash=SHA256, count=1, info=algorithm)') p_data('HKDF out: pass salt', hkdf_pass_salt, dump=False) password = str.encode(str(password)) password_key = hashlib.pbkdf2_hmac('sha256', password, hkdf_pass_salt, iterations, dklen=32) p_debug('\nPBKDF2(sha256, password, salt=HKDF_salt, iterations=p2c, 32 bytes)') p_data('Derived password key', password_key, dump=False) p_debug('\nHKDF(ikm=secret, len=32, salt=AcctID, hash=SHA256, count=1, info=version)') hkdf_key = HKDF(secret, 32, account_id, SHA256, 1, 'A3') p_data('HKDF out: secret key', hkdf_key, dump=False) final_key = '' for x in range(0,32): a = ord(password_key[x]) b = ord(hkdf_key[x]) c = a^b final_key = final_key + chr(c) p_debug('\nXOR PBKDF2 output and SecretKey HKDF output') p_data('Final 2SKD out', final_key, dump=False) return final_key
def test2(self): ref = HKDF(b("XXXXXX"), 12, b("YYYY"), SHA1) # Same output, but this time split over 2 keys key1, key2 = HKDF(b("XXXXXX"), 6, b("YYYY"), SHA1, 2) self.assertEqual((ref[:6], ref[6:]), (key1, key2)) # Same output, but this time split over 3 keys key1, key2, key3 = HKDF(b("XXXXXX"), 4, b("YYYY"), SHA1, 3) self.assertEqual((ref[:4], ref[4:8], ref[8:]), (key1, key2, key3))
def test1(self): for tv in self._test_vector: secret, salt, info, exp = [ t2b(tv[x]) for x in (1,2,3,5) ] key_len, hashmod = [ tv[x] for x in (4,0) ] output = HKDF(secret, key_len, salt, hashmod, 1, info) self.assertEqual(output, exp)
def get_masterkey(self, password): scrypt = self.config['ScryptObject'] block = base64.b64decode(self.config['EncryptedKey']) scryptkey = hashlib.scrypt(password.encode('utf-8'), salt=base64.b64decode(scrypt['Salt']), n=scrypt['N'], r=scrypt['R'], p=scrypt['P'], maxmem=0x7fffffff, dklen=scrypt['KeyLen']) key = HKDF(scryptkey, salt=b"", key_len=32, hashmod=SHA256, context=b"AES-GCM file content encryption") assert len(block) > 32 assert block != CIPHERTEXT_ZERO # Layout: [ NONCE | CIPHERTEXT (...) | TAG ] nonce, tag, ciphertext = block[:16], block[-16:], block[16:-16] aes = AES.new(key, AES.MODE_GCM, nonce=nonce) aes.update(struct.pack(">Q", 0)) return aes.decrypt_and_verify(ciphertext, tag)
def encrypt(k, pt, ad): kd_out = HKDF(k, salt = (b'\0' * 32), key_len = 80, hashmod = SHA256.new(), context = b'kdf_encrypt_info') enc_key = SA.keygen('shared', key_mat = kd_out[:32]) auth_key = SA.keygen('mac', key_mat = kd_out[32:64]) kd_iv = kd_out[64:] ct = SA.encrypt(pt, key = enc_key, iv = kd_iv) data, mac = SA.sign(ad + ct, key = auth_key) return ct + mac
def test_verify(self, tv): self._id = "Wycheproof HKDF Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) try: key = HKDF(tv.ikm, tv.size, tv.salt, tv.hash_module, 1, tv.info) except ValueError: assert not tv.valid else: if key != tv.okm: assert not tv.valid else: assert tv.valid self.warn(tv)
def decrypt(k, ct, ad): kd_out = HKDF(k, salt = (b'\0' * 32), key_len = 80, hashmod = SHA256.new(), context = b'kdf_encrypt_info') enc_key = SA.keygen('shared', key_mat = kd_out[:32]) auth_key = SA.keygen('mac', key_mat = kd_out[32:64]) kd_iv = kd_out[64:] ct_iv = ct[:16] ct_mac = ct[-32:] ct_ct = ct[:-32] assert kd_iv == ct_iv verdict = SA.verify((b'\0' + ad + ct_ct, ct_mac), key = auth_key) if verdict != None: return SA.decrypt(ct_ct, key = enc_key) else: raise Exception
def test_hdkf(self): derived = HKDF(b'secret', 32, b'', SHA256).hex() self.assertEqual( derived, "2f34e5ff91ec85d53ca9b543683174d0cf550b60d5f52b24c97b386cfcf6cbbf") k1 = PrivateKey(secret=bytes([2])) self.assertEqual(k1.to_int(), 2) k2 = PrivateKey(secret=bytes([3])) self.assertEqual(k2.to_int(), 3) self.assertEqual(encapsulate(k1, k2.public_key), decapsulate(k1.public_key, k2)) self.assertEqual( encapsulate(k1, k2.public_key).hex(), "6f982d63e8590c9d9b5b4c1959ff80315d772edd8f60287c9361d548d5200f82")
def derive_key(key_material, salt, info): """ Derive a fixed-size (64-byte) key for use in cryptographic operations. The key is derived using HKDF with the SHA-512 hash function. See https://tools.ietf.org/html/rfc5869. :type key_material: str or bytes :type salt: bytes :type info: bytes """ if not isinstance(key_material, bytes): key_material = key_material.encode() return HKDF( master=key_material, key_len=64, salt=salt, hashmod=SHA512, num_keys=1, context=info, )
def kdf(secret, key_len): from Cryptodome.Protocol.KDF import HKDF from Cryptodome.Hash import SHA512 return HKDF(as_bytes(secret), key_len, None, SHA512)
def decapsulate(public_key: PublicKey, peer_private_key: PrivateKey) -> bytes: shared_point = public_key.multiply(peer_private_key.secret) master = public_key.format(compressed=False) + shared_point.format( compressed=False) derived = HKDF(master, AES_KEY_BYTES_LEN, b'', SHA256) return derived
def kdf(KM): F = b'\xff' * 32 s = b'\0' * 32 info = b'x3dh info' return HKDF(KM, salt = s, key_len = 32, hashmod = SHA256.new(), context = info)