Last active
November 7, 2022 02:46
-
-
Save SafeEval/e4ae7ffe8ca7137d69bf7124cea91017 to your computer and use it in GitHub Desktop.
Example of PyCA's high level AESGCM interface.
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
#!/usr/bin/env python3 | |
""" | |
pyca-aesgcm-example.py | |
Author: Jack Sullivan | |
Example of using PyCA cryptography's high level AESGCM interface | |
to encrypt and decrypt data. Also demonstrates how modifying ciphertext | |
data or the auth tag (MAC) invalidates decryption. | |
The high level AESGCM interface doesn't seem to separate out the ciphertext | |
data from the auth tag, or bundle it with the IV. | |
https://cryptography.io/en/latest/hazmat/primitives/aead/#cryptography.hazmat.primitives.ciphers.aead.AESGCM | |
""" | |
import binascii | |
import os | |
from cryptography.exceptions import InvalidTag | |
from cryptography.hazmat.primitives.ciphers.aead import AESGCM | |
TRIGGER_INVALID_TAG = False | |
def main(): | |
# Show the plaintext. | |
plaintext_string = "a" | |
plaintext = plaintext_string.encode() | |
print("\nPlain: ", plaintext) | |
display_data("Plain", plaintext) | |
# Existing static key. | |
static_key_string = "d1884987a6d4dd93da9c5e24f8cccb5935a65f8e4f078cf02df9cbc4d628369e" | |
static_key = hex_string_to_bytes(static_key_string) | |
display_data("S Key", static_key) | |
# Generate key at runtime. | |
keylen = 256 | |
generated_key = AESGCM.generate_key(bit_length=keylen) | |
display_data("G Key", generated_key) | |
# High level AES GCM instance. | |
aesgcm = AESGCM(static_key) | |
# Additional data to authenticate. Can be None if none was passed during encryption. | |
# associated_data = b"authenticated but unencrypted data" | |
associated_data = None | |
# Generate IV. Never reuse an IV for multiple messages. | |
iv_nonce = os.urandom(12) | |
display_data("IV", iv_nonce) | |
# Encrypt the plaintext. | |
# 1 byte PT --> 29 byte CT = 12byte IV + 16byte data + 1byte tag | |
ciphertext = aesgcm.encrypt(iv_nonce, plaintext, associated_data) | |
display_data("Cipher", ciphertext) | |
# Decompose ciphertext. | |
ct_data = [x for x in ciphertext[0:16]] | |
ct_tag = ciphertext[16:] | |
display_data("CT data", bytes(ct_data)) | |
display_data("CT tag", bytes(ct_tag)) | |
# Decrypt the ciphertext. | |
plaintext = aesgcm.decrypt(iv_nonce, ciphertext, associated_data) | |
display_data("Plain", plaintext) | |
print("Plain: ", plaintext) | |
# Fail at decrypting data with modified auth tag. | |
if TRIGGER_INVALID_TAG: | |
print("\n") | |
bad_ct_tag = [x+1 for x in ct_tag] | |
display_data("Bad tag", bytes(bad_ct_tag)) | |
bad_ciphertext = bytes(ct_data + bad_ct_tag) | |
try: | |
plaintext = aesgcm.decrypt(iv_nonce, bad_ciphertext, associated_data) | |
except InvalidTag as e: | |
print("Error: Invalid AES-GCM auth tag") | |
def bytes_to_hex_string(bytes, spaced=True): | |
"""Get a pretty string of hex bytes, separated by spaces.""" | |
sep = " " if spaced else None | |
pretty_hex_string = binascii.hexlify(bytes, sep=sep) | |
return pretty_hex_string.decode("utf-8") | |
def hex_string_to_bytes(hex_string): | |
"""Get bytes from a hex string.""" | |
bytes = binascii.unhexlify(hex_string.replace(' ', '')) | |
return bytes | |
def display_data(name, data): | |
"""Display data value and size is standard format""" | |
bytelen = len(data) | |
bitlen = bytelen * 8 | |
hex_string = bytes_to_hex_string(data) | |
print(f"HEX for {name}\t({bytelen} bytes, {bitlen} bits):\t{hex_string}") | |
if __name__ == "__main__": | |
main() |
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
Plain: b'a' | |
HEX for Plain (1 bytes, 8 bits): 61 | |
HEX for S Key (32 bytes, 256 bits): d1 88 49 87 a6 d4 dd 93 da 9c 5e 24 f8 cc cb 59 35 a6 5f 8e 4f 07 8c f0 2d f9 cb c4 d6 28 36 9e | |
HEX for G Key (32 bytes, 256 bits): 97 74 eb 46 67 20 b3 9c 4d b9 63 fc f8 92 96 d0 bd fc 3b c0 ff a5 c5 5c 57 bd 62 2f a7 a0 8b c5 | |
HEX for IV (12 bytes, 96 bits): e6 f5 d3 46 88 55 c9 56 b0 ee 43 33 | |
HEX for Cipher (17 bytes, 136 bits): ce d5 aa 0e 7a f6 3f 32 7c 41 36 c6 f1 e0 0d 8c b9 | |
HEX for CT data (16 bytes, 128 bits): ce d5 aa 0e 7a f6 3f 32 7c 41 36 c6 f1 e0 0d 8c | |
HEX for CT tag (1 bytes, 8 bits): b9 | |
HEX for Plain (1 bytes, 8 bits): 61 | |
Plain: b'a' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment