Symmetric Key, Hazmat and Python

Symmetric key methods provide the core foundation of privacy in cybersecurity. With this Bob and Alice have the same encryption key, and…

Photo by Jason D on Unsplash

Symmetric Key, Hazmat and Python

Symmetric key methods provide the core foundation of privacy in cybersecurity. With this Bob and Alice have the same encryption key, and this key is used to encrypt and also to decrypt. We normally also add a salt value — known as an IV (Initialization Vector). In this case, we will use the Hazmat primitives in the cryptography library.

For most of the encryption modes we can use the following function:

def go_encrypt(msg,method,mode):
cipher = Cipher(method, mode)
encryptor = cipher.encryptor()
ct = encryptor.update(msg) + encryptor.finalize()
return (ct)


def go_decrypt(ct,method,mode):
cipher = Cipher(method, mode)
decryptor = cipher.decryptor()
return (decryptor.update(ct) + decryptor.finalize())

We can then pass the algorithm with the key, and the mode. In this case, we use the CBC mode with the IV:

cipher=go_encrypt(padded_data,algorithms.AES(key), modes.CBC(iv))

plain=go_decrypt(cipher,algorithms.AES(key), modes.CBC(iv))

Overall we must pad our input data with:

def pad(data,size=128):
padder = padding.PKCS7(size).padder()
padded_data = padder.update(data)
padded_data += padder.finalize()
return(padded_data)

and unpad after decryption with:

def unpad(data,size=128):
padder = padding.PKCS7(size).unpadder()
unpadded_data = padder.update(data)
unpadded_data += padder.finalize()
return(unpadded_data)

In both cases, the block size is 128 bits in size. There are some ciphers, such as ChaCha20 and AES GCM, where we do not need to pad and unpad, as they are stream ciphers. With GCM we add an authentication tag:

def go_encrypt_with_auth(msg,method,mode,add):
cipher = Cipher(method, mode)
encryptor = cipher.encryptor()
encryptor.authenticate_additional_data(add)
ct = encryptor.update(msg) + encryptor.finalize()
return (ct,encryptor.tag)


def go_decrypt_with_auth(ct,method,mode,add):
cipher = Cipher(method, mode)
decryptor = cipher.decryptor()
decryptor.authenticate_additional_data(add)
pl=decryptor.update(ct) + decryptor.finalize()
return (pl)

The full code is [here]:

import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding

import binascii

def go_encrypt(msg,method,mode):
cipher = Cipher(method, mode)
encryptor = cipher.encryptor()
ct = encryptor.update(msg) + encryptor.finalize()
return (ct)


def go_decrypt(ct,method,mode):
cipher = Cipher(method, mode)
decryptor = cipher.decryptor()
return (decryptor.update(ct) + decryptor.finalize())

def go_encrypt_with_auth(msg,method,mode,add):
cipher = Cipher(method, mode)
encryptor = cipher.encryptor()
encryptor.authenticate_additional_data(add)
ct = encryptor.update(msg) + encryptor.finalize()
return (ct,encryptor.tag)


def go_decrypt_with_auth(ct,method,mode,add):
cipher = Cipher(method, mode)
decryptor = cipher.decryptor()
decryptor.authenticate_additional_data(add)
pl=decryptor.update(ct) + decryptor.finalize()
return (pl)

def pad(data,size=128):
padder = padding.PKCS7(size).padder()
padded_data = padder.update(data)
padded_data += padder.finalize()
return(padded_data)

def unpad(data,size=128):
padder = padding.PKCS7(size).unpadder()
unpadded_data = padder.update(data)
unpadded_data += padder.finalize()
return(unpadded_data)


key = os.urandom(32)
iv = os.urandom(16)
msg=b"Hello"
print ("Message:\t",msg.decode())
print ("Key:\t",binascii.b2a_hex(key))
print ("IV:\t",binascii.b2a_hex(iv))

padded_data=pad(msg)


print ("\n\n=== AES ECB === ")
cipher=go_encrypt(padded_data,algorithms.AES(key), modes.ECB())

plain=go_decrypt(cipher,algorithms.AES(key), modes.ECB())
data=unpad(plain)

print ("Cipher: ",binascii.b2a_hex(cipher))
print (f"Decrypted: {data.decode()}")

cipher=go_encrypt(padded_data,algorithms.AES(key), modes.CBC(iv))

print ("=== AES CBC === ")
cipher=go_encrypt(padded_data,algorithms.AES(key), modes.CBC(iv))

plain=go_decrypt(cipher,algorithms.AES(key), modes.CBC(iv))
data=unpad(plain)

print ("Cipher: ",binascii.b2a_hex(cipher))
print (f"Decrypted: {data.decode()}")

cipher=go_encrypt(padded_data,algorithms.AES(key), modes.CBC(iv))

print ("=== AES OFB === ")
cipher=go_encrypt(padded_data,algorithms.AES(key), modes.OFB(iv))

plain=go_decrypt(cipher,algorithms.AES(key), modes.OFB(iv))
data=unpad(plain)

print ("Cipher: ",binascii.b2a_hex(cipher))
print (f"Decrypted: {data.decode()}")

print ("=== AES CTR === ")
cipher=go_encrypt(padded_data,algorithms.AES(key), modes.CTR(iv))

plain=go_decrypt(cipher,algorithms.AES(key), modes.CTR(iv))
data=unpad(plain)

print ("Cipher: ",binascii.b2a_hex(cipher))
print (f"Decrypted: {data.decode()}")

print ("=== AES GCM === ")
tag= b"authenticated but not encrypted payload"
cipher,auth_tag=go_encrypt_with_auth(msg,algorithms.AES(key), modes.GCM(iv),tag)

plain=go_decrypt_with_auth(cipher,algorithms.AES(key), modes.GCM(iv,auth_tag),tag)

print ("Cipher: ",binascii.b2a_hex(cipher))
print (f"Decrypted: {plain.decode()}")





print ("\n=== Blowfish ECB === ")

cipher=go_encrypt(padded_data,algorithms.Blowfish(key), modes.ECB())

plain=go_decrypt(cipher,algorithms.Blowfish(key), modes.ECB())

data=unpad(plain)

print ("Cipher: ",binascii.b2a_hex(cipher))
print (f"Decrypted: {data.decode()}")

print ("=== Blowfish CBC === ")

cipher=go_encrypt(padded_data,algorithms.Blowfish(key), modes.CBC(iv[:8]))

plain=go_decrypt(cipher,algorithms.Blowfish(key), modes.CBC(iv[:8]))

data=unpad(plain)

print ("Cipher: ",binascii.b2a_hex(cipher))
print (f"Decrypted: {data.decode()}")

print ("\n=== ChaCha20 === ")

cipher=go_encrypt(msg,algorithms.ChaCha20(key,iv), None)

plain=go_decrypt(cipher,algorithms.ChaCha20(key,iv), None)

print ("Cipher: ",binascii.b2a_hex(cipher))
print (f"Decrypted: {data.decode()}")

print ("\n=== 3DES ECB === ")
cipher=go_encrypt(padded_data,algorithms.TripleDES(key[:16]), modes.ECB())

plain=go_decrypt(cipher,algorithms.TripleDES(key[:16]), modes.ECB())

print ("Cipher: ",binascii.b2a_hex(cipher))
print (f"Decrypted: {data.decode()}")

print ("=== 3DES CBC === ")
cipher=go_encrypt(padded_data,algorithms.TripleDES(key[:16]), modes.CBC(iv[:8]))

plain=go_decrypt(cipher,algorithms.TripleDES(key[:16]), modes.CBC(iv[:8]))

print ("Cipher: ",binascii.b2a_hex(cipher))
print (f"Decrypted: {data.decode()}")


print ("\n=== Camellia ECB === ")
cipher=go_encrypt(padded_data,algorithms.Camellia(key), modes.ECB())

plain=go_decrypt(cipher,algorithms.Camellia(key), modes.ECB())

print ("Cipher: ",binascii.b2a_hex(cipher))
print (f"Decrypted: {data.decode()}")


print ("=== Camellia CBC === ")
cipher=go_encrypt(padded_data,algorithms.Camellia(key), modes.CBC(iv))

plain=go_decrypt(cipher,algorithms.Camellia(key), modes.CBC(iv))

print ("Cipher: ",binascii.b2a_hex(cipher))
print (f"Decrypted: {data.decode()}")

A sample run is [here]:

Message:  The quick brown fox jumps over the lazy dog
Key: b'7611452ae24ce51d6a4a088a08162056c36cd2398ecf3d1fe1294c86c7187d55'
IV: b'7ace9bcf10bcefded0a77e20689903d3'
=== AES ECB === 
Cipher: b'b29966b72d9e58b9cc9304fb0aa671c0fcd2b894be42ab15b42ed2ac4fee1a2654c4edd4b411c20799236c028e21892b'
Decrypted: The quick brown fox jumps over the lazy dog
=== AES CBC ===
Cipher: b'20c3650a6f5c57a163ed8523bf07b8cb47ecda0749cbe1ebf0c2c96a93c1eec1ed8889506dd3be8872873cfda69a4061'
Decrypted: The quick brown fox jumps over the lazy dog
=== AES OFB ===
Cipher: b'5e22dd9e427ce19f1ffaea21ae6bfdb0d2a8da0cdbf33e2bff10f6eb9afa1aae85cb79fdc28b3271e8e0965be9b862e5'
Decrypted: The quick brown fox jumps over the lazy dog
=== AES CTR ===
Cipher: b'5e22dd9e427ce19f1ffaea21ae6bfdb029c39c9abe27d984a0f323059ad5dc0acc964870e38472d2147846f9925d8f40'
Decrypted: The quick brown fox jumps over the lazy dog
=== AES GCM ===
Cipher: b'586b9717e58ce3e365b07ac174c98a6200d58fd7ae1bb46705170692c3432db2bd2dc95cf08456e0c15da1'
Decrypted: The quick brown fox jumps over the lazy dog
=== Blowfish ECB === 
Cipher: b'598bf4dad14eca2bc6d2dc0e9dbfd82431585ea01968dfc81da50788d97f0a4b27a2cdd28ddfd452363a12dea8540cf7'
Decrypted: The quick brown fox jumps over the lazy dog
=== Blowfish CBC ===
Cipher: b'589074e3bd1656edd9aad1ab9a459a7c726a3c5e8e9e16fd37c33d66e2d19fd81eccdf0a00f1374ff9fbb178eca53290'
Decrypted: The quick brown fox jumps over the lazy dog
=== ChaCha20 === 
Cipher: b'f2abe4462c4a7af77143eade7357aedffb718fefe9ac12db7dec3c4ab8547bbd586b1cba1ee5493e374ee3'
Decrypted: The quick brown fox jumps over the lazy dog
=== 3DES ECB === 
Cipher: b'0d2905adae378a973238c33883307b176a725ca1d0216a7fa4ab608c7ce9562ff09051e827796131a74c188f5a7f68b5'
Decrypted: The quick brown fox jumps over the lazy dog
=== 3DES CBC ===
Cipher: b'46fec683592d327665728c02bf35c1ed955a633c4923119e0ea2cb2eb1b49f4f8ff395628577b7303f473109f22f8809'
Decrypted: The quick brown fox jumps over the lazy dog
=== Camellia ECB === 
Cipher: b'9ddd4eac391d6de02dc4790d2cb752295c42fd8680761fa1a26fa2686679a68d399ef529f55c1261c0e188b0145c8140'
Decrypted: The quick brown fox jumps over the lazy dog
=== Camellia CBC ===
Cipher: b'8fbd26332a3ef9272ea15f011168abadabb820929e1276d06ad6f0cee8834522048a92ba9f71018f7d62477d95721591'
Decrypted: The quick brown fox jumps over the lazy dog
=== IDEA ECB ===
Cipher: b'397e0c98b353ac87c3bfaa793a8412e179a63f85d10fe817dd46754a6e00b53662c468481b45214b7e6dc7e2384983ce'
Decrypted: The quick brown fox jumps over the lazy dog
=== IDEA CBC ===
Cipher: b'aa9398a5be08ca00ef725747ac8286d1a618f8968c0250d508b6c808c135c869ec5301055d99e82df79bff6a5f11f920'
Decrypted: The quick brown fox jumps over the lazy dog

The running code is:

Conclusions

You can’t look much past AES for symmetric key, and AES GCM is the fastest mode and where you can also add authentication data. ChaCha20 is another fast cipher, as it is a stream cipher.