import os __all__ = [ "AES_BLOCK_BYTES", "aes_cbc_encrypt", "aes_cbc_decrypt", "aes_cfb8_encrypt", "aes_cfb8_decrypt", "dh_modp1024_exchange", "hkdf_sha256_derive", "pkcs7_pad", "pkcs7_unpad", ] # Second Oakley group (RFC 2409), to be used as "dh-ietf1024" in the 'Secret # Service' API. Don't look at me. I didn't write the spec. MODP1024_PRIME = int("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" "FFFFFFFFFFFFFFFF", 16) MODP1024_GENERATOR = 2 backend = os.environ.get("CRYPTO_BACKEND", "cryptography") if backend == "cryptodome": from Crypto.Cipher import AES from Crypto.Hash import SHA256 from Crypto.Protocol.KDF import HKDF from Crypto.Random.random import randint from Crypto.Util import Padding AES_BLOCK_BYTES = AES.block_size def aes_cbc_encrypt(data, key, iv): return AES.new(key, AES.MODE_CBC, iv).encrypt(data) def aes_cbc_decrypt(data, key, iv): return AES.new(key, AES.MODE_CBC, iv).decrypt(data) def aes_cfb8_encrypt(data, key, iv): return AES.new(key, AES.MODE_CFB, iv, segment_size=8).encrypt(data) def aes_cfb8_decrypt(data, key, iv): return AES.new(key, AES.MODE_CFB, iv, segment_size=8).decrypt(data) def aes_cfb128_encrypt(data, key, iv): return AES.new(key, AES.MODE_CFB, iv, segment_size=128).encrypt(data) def aes_cfb128_decrypt(data, key, iv): return AES.new(key, AES.MODE_CFB, iv, segment_size=128).decrypt(data) def dh_modp1024_exchange(peer_pubkey): prime = MODP1024_PRIME generator = MODP1024_GENERATOR our_privkey = randint(1, prime-1) our_pubkey = pow(generator, our_privkey, prime) shared_key = pow(peer_pubkey, our_privkey, prime) shared_key = shared_key.to_bytes(1024 // 8, "big") return our_pubkey, shared_key def hkdf_sha256_derive(input, nbytes): return HKDF(input, nbytes, b"", hashmod=SHA256) def pkcs7_pad(data, size): return Padding.pad(data, size, style="pkcs7") def pkcs7_unpad(data, size): return Padding.unpad(data, size, style="pkcs7") print("using 'PyCryptodome' as crypto backend") elif backend == "cryptography": from cryptography.hazmat.primitives.asymmetric import dh from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import CBC, CFB, CFB8 from cryptography.hazmat.primitives.hashes import SHA256 from cryptography.hazmat.primitives.kdf.hkdf import HKDF from cryptography.hazmat.primitives.padding import PKCS7 AES_BLOCK_BYTES = AES.block_size // 8 def aes_cbc_encrypt(data, key, iv): c = Cipher(AES(key), CBC(iv)).encryptor() return c.update(data) + c.finalize() def aes_cbc_decrypt(data, key, iv): c = Cipher(AES(key), CBC(iv)).decryptor() return c.update(data) + c.finalize() def aes_cfb8_encrypt(data, key, iv): c = Cipher(AES(key), CFB8(iv)).encryptor() return c.update(data) + c.finalize() def aes_cfb8_decrypt(data, key, iv): c = Cipher(AES(key), CFB8(iv)).decryptor() return c.update(data) + c.finalize() def aes_cfb128_encrypt(data, key, iv): c = Cipher(AES(key), CFB(iv)).encryptor() return c.update(data) + c.finalize() def aes_cfb128_decrypt(data, key, iv): c = Cipher(AES(key), CFB(iv)).decryptor() return c.update(data) + c.finalize() def dh_modp1024_exchange(peer_pubkey): group = dh.DHParameterNumbers(p=MODP1024_PRIME, g=MODP1024_GENERATOR) peer_pubkey = dh.DHPublicNumbers(peer_pubkey, group).public_key() our_privkey = group.parameters().generate_private_key() shared_key = our_privkey.exchange(peer_pubkey) our_pubkey = our_privkey.public_key().public_numbers().y return our_pubkey, shared_key def hkdf_sha256_derive(input, nbytes): k = HKDF(algorithm=SHA256(), length=nbytes, salt=b"", info=b"") return k.derive(input) def pkcs7_pad(data, size): p = PKCS7(size * 8).padder() return p.update(data) + p.finalize() def pkcs7_unpad(data, size): p = PKCS7(size * 8).unpadder() return p.update(data) + p.finalize() print("using 'python-cryptography' as crypto backend") else: raise RuntimeError("unsupported crypto backend %r" % backend)