This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from cryptography.hazmat.primitives import hashes, hmac | |
from cryptography.hazmat.primitives.kdf.hkdf import HKDF | |
from cryptography.hazmat.primitives.asymmetric import x25519 | |
from cryptography.hazmat.primitives.serialization import ( | |
load_pem_public_key, | |
load_pem_private_key | |
) | |
def main(): | |
sk_path = ... | |
pk_path = ... | |
source_sk = load_pem_private_key(sk_path.read_bytes(), password=None) | |
target_pk = load_pem_public_key(pk_path.read_bytes()) | |
# Generate 256-bit ECDHE keys, encoded with x509 SubjectPublicKeyInfo | |
ecdhe_sk = x25519.X25519PrivateKey.generate() | |
ecdhe_pk = ecdhe_sk.public_key() | |
# Send ECDHE public key and recieve peer public key to derive shared secret | |
send(ecdhe_pk) | |
peer_pk = recv() | |
# X25519 key exchange | |
shared_key = ecdhe_sk.exchange(peer_pk) | |
# Generate handshake secret material | |
def make_key(info, length): | |
salt = ... # current message context for caller protocol state | |
return HKDF(hashes.SHA256(), length, salt, info).derive(shared_key) | |
source_mac_key = make_key(b"initiator mac key", 32) | |
target_mac_key = make_key(b"responder mac key", 32) | |
# Provide proof of posession using the secret material | |
mac = hmac.HMAC(source_mac_key, hashes.SHA256()).update(source_pk).finalize() | |
signature = source_pk.sign(..., ecdhe_pk + peer_pk + mac) | |
send(source_pk + signature) | |
proof = recv() | |
# Ensure identity matches our target (assume target_pk != source_pk) | |
assert proof.identity == target_pk | |
mac = hmac.HMAC(target_mac_key, hashes.SHA256()).update(target_pk).finalize() | |
assert target_pk.verify(proof.signature, peer_pk + ecdhe_pk + mac) | |
# Generate a consistent key or have independent keys | |
source_session_key = make_key(b"initiator session key", 32) | |
target_session_key = make_key(b"responder session key", 32) | |
# Encrypt all further communication with ChaCha20-Poly1305 or other suitable cipher | |
pass |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment