Hazmat with ChaCha/Poly1305 with Key DerivationChacha20 is a stream cipher which uses a 256-bit key and a 96-bit nonce. Currently AES has a virtual monopoly on secret key encryption. There would be major problems, though, if this was cracked. Along with this AES has been shown to be weak around cache-collision attacks. Google thus propose ChaCha20 as an alternative, and actively use it within TLS connections. Currently it is three times faster than software-enabled AES, and is not sensitive to timing attacks. It operates by creating a key stream which is then X-ORed with the plaintext. It has been standardised with RFC 7539. In this case we will use AEAD and where we can add an additional data element to the cipher, in order to authenticate the cipher. This data might relate to the network port number we are sending, or to the sequence number of an encrypted data packet. Poly1305 is a message authentication code for data integrity and message authenticity of a message. It is standardized in RFC 8439. In this case, we will use a HKDF (HMAC Key Derivation Function) to generate the encryption key from a password. We will not use any salt for this, but in practice we would generate a random salt value. |
Code
Hazmat supports core cryptographical primitives for HOTP:
import os from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 import sys import binascii from cryptography.hazmat.primitives.kdf.hkdf import HKDF from cryptography.hazmat.primitives import hashes msg = "a message" add = "additional data" password="qwerty" length=32 # 256 bits if (len(sys.argv)>1): password=str(sys.argv[1]) if (len(sys.argv)>2): msg=str(sys.argv[2]) if (len(sys.argv)>3): add=str(sys.argv[3]) hkdf = HKDF(algorithm=hashes.SHA256(), length=length,salt=b"", info=b"") mykey=hkdf.derive(password.encode()) print ("Password: ",password) print ("Data:\t",msg) print ("Additional data:\t",add) # key = ChaCha20Poly1305.generate_key() chacha = ChaCha20Poly1305(mykey) nonce = os.urandom(12) cipher = chacha.encrypt(nonce, msg.encode(), add.encode()) rtn=chacha.decrypt(nonce, cipher, add.encode()) print ("\nKey:\t",binascii.b2a_hex(mykey).decode()) print ("Nonce:\t",binascii.b2a_hex(nonce).decode()) print ("\nCipher:\t",binascii.b2a_hex(cipher).decode()) print ("Decrypted:\t",rtn.decode())
A sample run is:
Password: qwerty Data: a message Additional data: additional data Key: 697b0111081294978a075c6cae24729665be7f5a646007ac90aadc3954a484f8 Nonce: f291fbdd3ceb3a437184f595 Cipher: c5a28909e1ad86545728d6715f987f94187c80b8f233bdf78d Decrypted: a message