diff options
Diffstat (limited to 'docs/hazmat')
-rw-r--r-- | docs/hazmat/primitives/symmetric-encryption.rst | 86 |
1 files changed, 73 insertions, 13 deletions
diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index a1a3ec0d..a683bb98 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -356,20 +356,80 @@ Modes :param bytes tag: The tag bytes to verify during decryption. When encrypting this must be None. - .. doctest:: + .. testcode:: - >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes - >>> from cryptography.hazmat.backends import default_backend - >>> cipher = Cipher(algorithms.AES(key), modes.GCM(iv), backend=default_backend()) - >>> encryptor = cipher.encryptor() - >>> encryptor.authenticate_additional_data(b"authenticated but not encrypted payload") - >>> ct = encryptor.update(b"a secret message") + encryptor.finalize() - >>> tag = encryptor.tag - >>> cipher = Cipher(algorithms.AES(key), modes.GCM(iv, tag), backend) - >>> decryptor = cipher.decryptor() - >>> decryptor.authenticate_additional_data(b"authenticated but not encrypted payload") - >>> decryptor.update(ct) + decryptor.finalize() - 'a secret message' + import os + + from cryptography.hazmat.primitives.ciphers import ( + Cipher, algorithms, modes + ) + + from cryptography.hazmat.primitives.padding import PKCS7 + + def encrypt(key, plaintext, associated_data): + # Generate a random 96-bit IV. + iv = os.urandom(12) + + # Construct a AES-GCM Cipher object with the given and our randomly + # generated IV. + encryptor = Cipher( + algorithms.AES(key), + modes.GCM(iv), + backend=default_backend() + ).encryptor() + + # We have to pad our plaintext because it may not be a + # multiple of the block size. + padder = PKCS7(algorithms.AES.block_size).padder() + padded_plaintext = padder.update(plaintext) + padder.finalize() + + # associated_data will be authenticated but not encrypted, + # it must also be passed in on decryption. + encryptor.authenticate_additional_data(associated_data) + + # Encrypt the plaintext and get the associated ciphertext. + ciphertext = encryptor.update(padded_plaintext) + encryptor.finalize() + + return (iv, ciphertext, encryptor.tag) + + def decrypt(key, associated_data, iv, ciphertext, tag): + # Construct a Cipher object, with the key, iv, and additionally the + # GCM tag used for authenticating the message. + decryptor = Cipher( + algorithms.AES(key), + modes.GCM(iv, tag), + backend=default_backend() + ).decryptor() + + # We will need to unpad the plaintext. + unpadder = PKCS7(algorithms.AES.block_size).unpadder() + + # We put associated_data back in or the tag will fail to verify + # when we finalize the decryptor. + decryptor.authenticate_additional_data(associated_data) + + # Decryption gets us the authenticated padded plaintext. + padded_plaintext = decryptor.update(ciphertext) + decryptor.finalize() + + return unpadder.update(padded_plaintext) + unpadder.finalize() + + iv, ciphertext, tag = encrypt( + key, + b"a secret message!", + b"authenticated but not encrypted payload" + ) + + print(decrypt( + key, + b"authenticated but not encrypted payload", + iv, + ciphertext, + tag + )) + + .. testoutput:: + + a secret message! Insecure Modes |