def test_already_finalized(self, backend): ckdf = ConcatKDFHash(hashes.SHA256(), 16, None, backend) ckdf.derive(b"\x01" * 16) with pytest.raises(AlreadyFinalized): ckdf.derive(b"\x02" * 16)
def _derive(self, privkey, pubkey, alg, keydatalen, headers): # OtherInfo is defined in NIST SP 56A 5.8.1.2.1 # AlgorithmID otherinfo = struct.pack('>I', len(alg)) otherinfo += bytes(alg.encode('utf8')) # PartyUInfo apu = base64url_decode(headers['apu']) if 'apu' in headers else b'' otherinfo += struct.pack('>I', len(apu)) otherinfo += apu # PartyVInfo apv = base64url_decode(headers['apv']) if 'apv' in headers else b'' otherinfo += struct.pack('>I', len(apv)) otherinfo += apv # SuppPubInfo otherinfo += struct.pack('>I', keydatalen) # no SuppPrivInfo shared_key = privkey.exchange(ec.ECDH(), pubkey) ckdf = ConcatKDFHash(algorithm=hashes.SHA256(), length=keydatalen // 8, otherinfo=otherinfo, backend=self.backend) return ckdf.derive(shared_key)
def kdfe(hashAlg, z, use, partyuinfo, partyvinfo, bits): halg = _get_digest(hashAlg) if halg is None: raise ValueError(f"unsupported digest algorithm: {hashAlg}") if bits % 8: raise ValueError(f"bad key length {bits}, not a multiple of 8") klen = int(bits / 8) otherinfo = use + partyuinfo + partyvinfo kdf = ConcatKDFHash(algorithm=halg(), length=klen, otherinfo=otherinfo, backend=default_backend()) return kdf.derive(z)
def test_invalid_verify(self, backend): prk = binascii.unhexlify( b"52169af5c485dcc2321eb8d26d5efa21fb9b93c98e38412ee2484cf14f0d0d23" ) oinfo = binascii.unhexlify( b"a1b2c3d4e53728157e634612c12d6d5223e204aeea4341565369647bd184bcd2" b"46f72971f292badaa2fe4124612cba") ckdf = ConcatKDFHash(hashes.SHA256(), 16, oinfo, backend) with pytest.raises(InvalidKey): ckdf.verify(prk, b"wrong key")
def test_invalid_verify(self, backend): prk = binascii.unhexlify( b"52169af5c485dcc2321eb8d26d5efa21fb9b93c98e38412ee2484cf14f0d0d23" ) oinfo = binascii.unhexlify( b"a1b2c3d4e53728157e634612c12d6d5223e204aeea4341565369647bd184bcd2" b"46f72971f292badaa2fe4124612cba" ) ckdf = ConcatKDFHash(hashes.SHA256(), 16, oinfo, backend) with pytest.raises(InvalidKey): ckdf.verify(prk, b"wrong key")
def test_verify(self, backend): prk = binascii.unhexlify( b"52169af5c485dcc2321eb8d26d5efa21fb9b93c98e38412ee2484cf14f0d0d23" ) okm = binascii.unhexlify(b"1c3bc9e7c4547c5191c0d478cccaed55") oinfo = binascii.unhexlify( b"a1b2c3d4e53728157e634612c12d6d5223e204aeea4341565369647bd184bcd2" b"46f72971f292badaa2fe4124612cba") ckdf = ConcatKDFHash(hashes.SHA256(), 16, oinfo, backend) ckdf.verify(prk, okm)
def derive_key(self, s, curve, pkalg, fingerprint): # wrapper around the Concatenation KDF method provided by cryptography # assemble the additional data as defined in RFC 6637: # Param = curve_OID_len || curve_OID || public_key_alg_ID || 03 || 01 || KDF_hash_ID || KEK_alg_ID for AESKeyWrap || "Anonymous data = bytearray() data += encoder.encode(curve.value)[1:] data.append(pkalg) data += b'\x03\x01' data.append(self.halg) data.append(self.encalg) data += b'Anonymous Sender ' data += binascii.unhexlify(fingerprint.replace(' ', '')) ckdf = ConcatKDFHash(algorithm=getattr(hashes, self.halg.name)(), length=self.encalg.key_size // 8, otherinfo=bytes(data), backend=default_backend()) return ckdf.derive(s)
def test_verify(self, backend): prk = binascii.unhexlify( b"52169af5c485dcc2321eb8d26d5efa21fb9b93c98e38412ee2484cf14f0d0d23" ) okm = binascii.unhexlify(b"1c3bc9e7c4547c5191c0d478cccaed55") oinfo = binascii.unhexlify( b"a1b2c3d4e53728157e634612c12d6d5223e204aeea4341565369647bd184bcd2" b"46f72971f292badaa2fe4124612cba" ) ckdf = ConcatKDFHash(hashes.SHA256(), 16, oinfo, backend) assert ckdf.verify(prk, okm) is None
def test_invalid_backend(): pretend_backend = object() with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): ConcatKDFHash(hashes.SHA256(), 16, None, pretend_backend) with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): ConcatKDFHMAC(hashes.SHA256(), 16, None, None, pretend_backend)
def __init__(self, credential_id, app_id): if not hasattr(serialization.Encoding, "X962"): raise unittest.SkipTest("Requires Cryptography >= 2.5") assert isinstance(credential_id, six.binary_type) assert isinstance(app_id, six.binary_type) # Note: do not use in production, no garantees is provided this is # cryptographically safe to use. priv_key_params = ConcatKDFHash( algorithm=hashes.SHA256(), length=32, otherinfo=credential_id + app_id, backend=default_backend(), ).derive(self._priv_key_bytes) self.app_id = app_id self.priv_key = ec.derive_private_key(bytes2int(priv_key_params), ec.SECP256R1(), default_backend()) self.pub_key = self.priv_key.public_key() self.public_key_bytes = self.pub_key.public_bytes( serialization.Encoding.X962, serialization.PublicFormat.UncompressedPoint) self.credential_id = self.key_handle = credential_id
def ecdh_get_shared_secret(self, private_key, partner_public_key): shared_key = private_key.exchange(ec.ECDH(), partner_public_key) shared_key = ConcatKDFHash( algorithm=hashes.SHA256(), length=32, otherinfo=None, backend=default_backend()).derive(shared_key) return base64.urlsafe_b64encode(shared_key)
def _derive(self, privkey, pubkey, alg, bitsize, headers): # OtherInfo is defined in NIST SP 56A 5.8.1.2.1 # AlgorithmID otherinfo = struct.pack('>I', len(alg)) otherinfo += bytes(alg.encode('utf8')) # PartyUInfo apu = base64url_decode(headers['apu']) if 'apu' in headers else b'' otherinfo += struct.pack('>I', len(apu)) otherinfo += apu # PartyVInfo apv = base64url_decode(headers['apv']) if 'apv' in headers else b'' otherinfo += struct.pack('>I', len(apv)) otherinfo += apv # SuppPubInfo otherinfo += struct.pack('>I', bitsize) # no SuppPrivInfo # Shared Key generation if isinstance(privkey, ec.EllipticCurvePrivateKey): if isinstance(pubkey, ec.EllipticCurvePublicKey): aff_nums = pubkey.public_numbers() x, y = aff_nums.x, aff_nums.y else: x, y = pubkey P = vulnecc.AffinePoint(vulnecc.curveP256_vuln, x, y) s = privkey.private_numbers().private_value shared = s * P shared_key = int.to_bytes(shared.x, 32, "big") else: # X25519/X448 shared_key = privkey.exchange(pubkey) ckdf = ConcatKDFHash(algorithm=hashes.SHA256(), length=_inbytes(bitsize), otherinfo=otherinfo, backend=self.backend) return ckdf.derive(shared_key)
def decrypt_ecdh(ec_key, pub_pem, payload, other_info): """ Decrypt a payload using ECDH shared secret to derive AES256-GCM key Args: My private key Peer's public key Payload to decrypt Application specific context information Return: Decrypted payload """ peer_public_key = serialization.load_pem_public_key( pub_pem, backend=default_backend()) secret = compute_ecdh_secret(ec_key, peer_public_key) ckdf = ConcatKDFHash(algorithm=hashes.SHA256(), length=32, otherinfo=other_info, backend=default_backend()) key = ckdf.derive(secret) plaintext = decrypt_aes_gcm(key, payload[:12], payload[12:]) return plaintext
def encrypt_ecdh(ec_key, pub_pem, payload, other_info): """ Encrypt a payload using ECDH shared secret to derive AES256-GCM key Args: My private key Peer's public key Payload to encrypt Application specific context information Return: Encrypted payload """ peer_public_key = serialization.load_pem_public_key( pub_pem, backend=default_backend()) secret = compute_ecdh_secret(ec_key, peer_public_key) ckdf = ConcatKDFHash(algorithm=hashes.SHA256(), length=32, otherinfo=other_info, backend=default_backend()) key = ckdf.derive(secret) nonce = os.urandom(12) ciphertext = nonce + encrypt_aes_gcm(key, nonce, payload, other_info) return ciphertext
def deliver(self, key, pubkey, headers, bit_size): # AlgorithmID if self.key_size is None: alg_id = _u32be_len_input(headers['enc']) else: alg_id = _u32be_len_input(headers['alg']) # PartyUInfo apu_info = _u32be_len_input(headers.get('apu'), True) # PartyVInfo apv_info = _u32be_len_input(headers.get('apv'), True) # SuppPubInfo pub_info = struct.pack('>I', bit_size) other_info = alg_id + apu_info + apv_info + pub_info shared_key = key.exchange_shared_key(pubkey) ckdf = ConcatKDFHash(algorithm=hashes.SHA256(), length=bit_size // 8, otherinfo=other_info, backend=default_backend()) return ckdf.derive(shared_key)
def test_unicode_typeerror(self, backend): with pytest.raises(TypeError): ConcatKDFHash( hashes.SHA256(), 16, otherinfo=u"foo", backend=backend ) with pytest.raises(TypeError): ckdf = ConcatKDFHash( hashes.SHA256(), 16, otherinfo=None, backend=backend ) ckdf.derive(u"foo") with pytest.raises(TypeError): ckdf = ConcatKDFHash( hashes.SHA256(), 16, otherinfo=None, backend=backend ) ckdf.verify(u"foo", b"bar") with pytest.raises(TypeError): ckdf = ConcatKDFHash( hashes.SHA256(), 16, otherinfo=None, backend=backend ) ckdf.verify(b"foo", u"bar")
def test_unicode_typeerror(self, backend): with pytest.raises(TypeError): ConcatKDFHash( hashes.SHA256(), 16, otherinfo="foo", # type: ignore[arg-type] backend=backend, ) with pytest.raises(TypeError): ckdf = ConcatKDFHash(hashes.SHA256(), 16, otherinfo=None, backend=backend) ckdf.derive("foo") # type: ignore[arg-type] with pytest.raises(TypeError): ckdf = ConcatKDFHash(hashes.SHA256(), 16, otherinfo=None, backend=backend) ckdf.verify("foo", b"bar") # type: ignore[arg-type] with pytest.raises(TypeError): ckdf = ConcatKDFHash(hashes.SHA256(), 16, otherinfo=None, backend=backend) ckdf.verify(b"foo", "bar") # type: ignore[arg-type]
def test_length_limit(self, backend): big_length = hashes.SHA256().digest_size * (2**32 - 1) + 1 with pytest.raises(ValueError): ConcatKDFHash(hashes.SHA256(), big_length, None, backend)
import base64 import os from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.concatkdf import ConcatKDFHash from cryptography.hazmat.backends import default_backend # The sample code is extracted from the book Python Cryptography # The book can be downloaded from https://leanpub.com/cryptop # Online Crypto Playgroud https://8gwifi.org # Author Anish Nath backend = default_backend() otherinfo = b"concatkdf-example" ckdf = ConcatKDFHash(algorithm=hashes.SHA256(), length=32, otherinfo=otherinfo, backend=backend) # CKDF Derive key key = ckdf.derive(b"input key") base64.b64encode(key) # CKDF Verify Key ckdf = ConcatKDFHash(algorithm=hashes.SHA256(), length=32, otherinfo=otherinfo, backend=backend) ckdf.verify(b"input key", key)
def compute_derived_key(self, shared_key, fixed_info, bit_size): ckdf = ConcatKDFHash(algorithm=hashes.SHA256(), length=bit_size // 8, otherinfo=fixed_info, backend=default_backend()) return ckdf.derive(shared_key)