import binascii
from Crypto.Cipher import AES
from Crypto.Util import Counter
from Crypto import Random
# AES supports multiple key sizes: 16 (AES128), 24 (AES192), or 32 (AES256).
key_bytes = 32
# Takes as input a 32-byte key and an arbitrary-length plaintext and returns a pair (iv, ciphertext). "iv" stands for initialization vector.
def encrypt(key, plaintext):
assert len(key) == key_bytes
# Choose a random, 16-byte IV.
iv = Random.new().read(AES.block_size)
# Convert the IV to a Python integer.
iv_int = int(binascii.hexlify(iv), 16)
# Create a new Counter object with IV = iv_int.
ctr = Counter.new(AES.block_size * 8, initial_value=iv_int)
# Create AES-CTR cipher.
aes = AES.new(key, AES.MODE_CTR, counter=ctr)
# Encrypt and return IV and ciphertext.
ciphertext = aes.encrypt(plaintext.encode('utf-8'))
return (iv, ciphertext)
# Takes as input a 32-byte key, a 16-byte IV, and a ciphertext, and outputs the corresponding plaintext.
def decrypt(key, iv, ciphertext):
assert len(key) == key_bytes
# Initialize counter for decryption. iv should be the same as the output of encrypt().
iv_int = int(binascii.hexlify(iv), 16)
ctr = Counter.new(AES.block_size * 8, initial_value=iv_int)
# Create AES-CTR cipher.
aes = AES.new(key, AES.MODE_CTR, counter=ctr)
# Decrypt and return the plaintext.
plaintext = aes.decrypt(ciphertext)
return plaintext.decode('utf-8')
# Example usage
key = '01234567890123456789012345678901'.encode('utf-8')
(iv, ciphertext) = encrypt(key, 'Coronavirus')
plaintext = decrypt(key, iv, ciphertext)
print("Ciphertext: {}".format(binascii.hexlify(ciphertext).decode('utf-8')))
print("Decrypted plaintext: {}".format(plaintext))
aW1wb3J0IGJpbmFzY2lpCmZyb20gQ3J5cHRvLkNpcGhlciBpbXBvcnQgQUVTCmZyb20gQ3J5cHRvLlV0aWwgaW1wb3J0IENvdW50ZXIKZnJvbSBDcnlwdG8gaW1wb3J0IFJhbmRvbQoKIyBBRVMgc3VwcG9ydHMgbXVsdGlwbGUga2V5IHNpemVzOiAxNiAoQUVTMTI4KSwgMjQgKEFFUzE5MiksIG9yIDMyIChBRVMyNTYpLgprZXlfYnl0ZXMgPSAzMgoKIyBUYWtlcyBhcyBpbnB1dCBhIDMyLWJ5dGUga2V5IGFuZCBhbiBhcmJpdHJhcnktbGVuZ3RoIHBsYWludGV4dCBhbmQgcmV0dXJucyBhIHBhaXIgKGl2LCBjaXBoZXJ0ZXh0KS4gIml2IiBzdGFuZHMgZm9yIGluaXRpYWxpemF0aW9uIHZlY3Rvci4KZGVmIGVuY3J5cHQoa2V5LCBwbGFpbnRleHQpOgogICAgYXNzZXJ0IGxlbihrZXkpID09IGtleV9ieXRlcwoKICAgICMgQ2hvb3NlIGEgcmFuZG9tLCAxNi1ieXRlIElWLgogICAgaXYgPSBSYW5kb20ubmV3KCkucmVhZChBRVMuYmxvY2tfc2l6ZSkKCiAgICAjIENvbnZlcnQgdGhlIElWIHRvIGEgUHl0aG9uIGludGVnZXIuCiAgICBpdl9pbnQgPSBpbnQoYmluYXNjaWkuaGV4bGlmeShpdiksIDE2KSAKCiAgICAjIENyZWF0ZSBhIG5ldyBDb3VudGVyIG9iamVjdCB3aXRoIElWID0gaXZfaW50LgogICAgY3RyID0gQ291bnRlci5uZXcoQUVTLmJsb2NrX3NpemUgKiA4LCBpbml0aWFsX3ZhbHVlPWl2X2ludCkKCiAgICAjIENyZWF0ZSBBRVMtQ1RSIGNpcGhlci4KICAgIGFlcyA9IEFFUy5uZXcoa2V5LCBBRVMuTU9ERV9DVFIsIGNvdW50ZXI9Y3RyKQoKICAgICMgRW5jcnlwdCBhbmQgcmV0dXJuIElWIGFuZCBjaXBoZXJ0ZXh0LgogICAgY2lwaGVydGV4dCA9IGFlcy5lbmNyeXB0KHBsYWludGV4dC5lbmNvZGUoJ3V0Zi04JykpCiAgICByZXR1cm4gKGl2LCBjaXBoZXJ0ZXh0KQoKIyBUYWtlcyBhcyBpbnB1dCBhIDMyLWJ5dGUga2V5LCBhIDE2LWJ5dGUgSVYsIGFuZCBhIGNpcGhlcnRleHQsIGFuZCBvdXRwdXRzIHRoZSBjb3JyZXNwb25kaW5nIHBsYWludGV4dC4KZGVmIGRlY3J5cHQoa2V5LCBpdiwgY2lwaGVydGV4dCk6CiAgICBhc3NlcnQgbGVuKGtleSkgPT0ga2V5X2J5dGVzCgogICAgIyBJbml0aWFsaXplIGNvdW50ZXIgZm9yIGRlY3J5cHRpb24uIGl2IHNob3VsZCBiZSB0aGUgc2FtZSBhcyB0aGUgb3V0cHV0IG9mIGVuY3J5cHQoKS4KICAgIGl2X2ludCA9IGludChiaW5hc2NpaS5oZXhsaWZ5KGl2KSwgMTYpCiAgICBjdHIgPSBDb3VudGVyLm5ldyhBRVMuYmxvY2tfc2l6ZSAqIDgsIGluaXRpYWxfdmFsdWU9aXZfaW50KQoKICAgICMgQ3JlYXRlIEFFUy1DVFIgY2lwaGVyLgogICAgYWVzID0gQUVTLm5ldyhrZXksIEFFUy5NT0RFX0NUUiwgY291bnRlcj1jdHIpCgogICAgIyBEZWNyeXB0IGFuZCByZXR1cm4gdGhlIHBsYWludGV4dC4KICAgIHBsYWludGV4dCA9IGFlcy5kZWNyeXB0KGNpcGhlcnRleHQpCiAgICByZXR1cm4gcGxhaW50ZXh0LmRlY29kZSgndXRmLTgnKQoKIyBFeGFtcGxlIHVzYWdlCmtleSA9ICcwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMScuZW5jb2RlKCd1dGYtOCcpCihpdiwgY2lwaGVydGV4dCkgPSBlbmNyeXB0KGtleSwgJ0Nvcm9uYXZpcnVzJykKcGxhaW50ZXh0ID0gZGVjcnlwdChrZXksIGl2LCBjaXBoZXJ0ZXh0KQoKcHJpbnQoIkNpcGhlcnRleHQ6IHt9Ii5mb3JtYXQoYmluYXNjaWkuaGV4bGlmeShjaXBoZXJ0ZXh0KS5kZWNvZGUoJ3V0Zi04JykpKQpwcmludCgiRGVjcnlwdGVkIHBsYWludGV4dDoge30iLmZvcm1hdChwbGFpbnRleHQpKQ==