def _encrypt_via_chacha20_poly1305(plaintext: bytes, key: bytes, aad: bytes = b"header") -> dict: """Encrypt a bytestring with the stream cipher ChaCha20. Additional cleartext data can be provided so that the generated mac tag also verifies its integrity. :param plaintext: the bytes to cipher :param key: 32 bytes long cryptographic key :param aad: optional "additional authenticated data" :return: dict with fields "ciphertext", "tag", "nonce" and "header" as bytestrings""" _check_symmetric_key_length_bytes(len(key)) cipher = ChaCha20_Poly1305.new(key=key) cipher.update(aad) ciphertext, tag = cipher.encrypt_and_digest(plaintext) nonce = cipher.nonce encryption = { "ciphertext": ciphertext, "tag": tag, "nonce": nonce, "aad": aad } return encryption
def _decrypt_via_aes_eax(cipherdict: dict, key: bytes) -> bytes: """Decrypt a bytestring using AES (EAX mode). :param cipherdict: dict with fields "ciphertext", "tag" and "nonce" as bytestrings :param key: the cryptographic key used to decipher :return: the decrypted bytestring""" _check_symmetric_key_length_bytes(len(key)) decipher = AES.new(key, AES.MODE_EAX, nonce=cipherdict["nonce"]) plaintext = decipher.decrypt(cipherdict["ciphertext"]) decipher.verify(cipherdict["tag"]) return plaintext
def _decrypt_via_aes_cbc(cipherdict: dict, key: bytes) -> bytes: """Decrypt a bytestring using AES (CBC mode). :param cipherdict: dict with fields "iv" and "ciphertext" as bytestrings :param key: the cryptographic key used to decipher :return: the decrypted bytestring""" _check_symmetric_key_length_bytes(len(key)) iv = cipherdict["iv"] ciphertext = cipherdict["ciphertext"] decipher = AES.new(key, AES.MODE_CBC, iv) plaintext = unpad(decipher.decrypt(ciphertext), block_size=AES.block_size) return plaintext
def _encrypt_via_aes_eax(plaintext: bytes, key: bytes) -> dict: """Encrypt a bytestring using AES (EAX mode). :param plaintext: the bytes to cipher :param key: AES cryptographic key. It must be 16, 24 or 32 bytes long (respectively for *AES-128*, *AES-192* or *AES-256*). :return: dict with fields "ciphertext", "tag" and "nonce" as bytestrings""" _check_symmetric_key_length_bytes(len(key)) cipher = AES.new(key, AES.MODE_EAX) nonce = cipher.nonce ciphertext, tag = cipher.encrypt_and_digest(plaintext) cipherdict = {"ciphertext": ciphertext, "tag": tag, "nonce": nonce} return cipherdict
def _encrypt_via_aes_cbc(plaintext: bytes, key: bytes) -> dict: """Encrypt a bytestring using AES (CBC mode). :param plaintext: the bytes to cipher :param key: AES cryptographic key. It must be 16, 24 or 32 bytes long (respectively for *AES-128*, *AES-192* or *AES-256*). :return: dict with fields "iv" and "ciphertext" as bytestrings""" _check_symmetric_key_length_bytes(len(key)) iv = get_random_bytes(AES.block_size) cipher = AES.new(key, AES.MODE_CBC, iv) ciphertext = cipher.encrypt(pad(plaintext, block_size=AES.block_size)) cipherdict = {"iv": iv, "ciphertext": ciphertext} return cipherdict
def _decrypt_via_chacha20_poly1305(cipherdict: dict, key: bytes) -> bytes: """Decrypt a bytestring with the stream cipher ChaCha20. :param cipherdict: dict with fields "ciphertext", "tag", "nonce" and "header" as bytestrings :param key: the cryptographic key used to decipher :return: the decrypted bytestring""" _check_symmetric_key_length_bytes(len(key)) decipher = ChaCha20_Poly1305.new(key=key, nonce=cipherdict["nonce"]) decipher.update(cipherdict["aad"]) plaintext = decipher.decrypt_and_verify( ciphertext=cipherdict["ciphertext"], received_mac_tag=cipherdict["tag"]) return plaintext