In symmetric key, we generate a secret key. This key is typically a random value or generated from a password and a salt value. If we use a password, we typically use a KDF (Key Derivation Function), and which uses a password and a salt value, in order to create a key of a given size. In this case we will use Argon2i, and which is memory resilent. Argon2 was designed Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich is a key derivation function (KDF), where were we can create hashed values of passwords, or create encryption keys based on a password. It was a winner of the Password Hashing Competition in July 2015, and is robust against GPU and side channel attacks [paper].
Sodium: NaCl - Encrypting with a Password |
Outline
In symmetric key, we generate a secret key. This key is typically a random value or generated from a password and a salt value. If we use a password, we typically use a KDF (Key Derivation Function), and which uses a password and a salt value, in order to create a key of a given size. In this case we will use Argon2i, and which is memory resilent.
Argon2 is a hashing method which has a cost in memory, and for CPU processing. We also want to create a method which makes it difficult to apply parallel threads (and thus run it on GPUs). It was designed Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich as a key derivation function. It was a winner of the Password Hashing Competition in July 2015, and is robust against GPU attacks. It is resistant to GPU attacks, and also has a memory cost. The costs include: execution time (CPU cost); memory required (memory cost); and degree of parallelism. The parameters include:
- Password (P): Defines the password bytes to be hashed
- Salt (S): Defines the bytes to be used for salting.
- Parallelism (p): Defines the number of thread that are required for the parallelism.
- TagLength (T): Define the number of bytes to return for the hash.
- MemorySizeKB (m): Amount of memory (in KB) to use.
Coding
The code is:
import nacl.secret import nacl.utils import nacl.pwhash import binascii import sys mess='hello' password="test" if (len(sys.argv)>1): mess=str(sys.argv[1]) if (len(sys.argv)>2): password=str(sys.argv[2]) salt=nacl.utils.random(16) print("Message: ",mess) print(f"Password: {password} Salt: {binascii.b2a_hex(salt)}") message=mess.encode() password=password.encode() mlevel=nacl.pwhash.MEMLIMIT_INTERACTIVE kdf = nacl.pwhash.argon2i.kdf key = kdf(nacl.secret.SecretBox.KEY_SIZE, password, salt,opslimit=3,memlimit=mlevel) nonce=nacl.utils.random(nacl.secret.SecretBox.NONCE_SIZE) box=nacl.secret.SecretBox(key) encrypted= box.encrypt(message,nonce) plain = box.decrypt(encrypted) print ("\nKey (32 byte): ",binascii.b2a_hex(key)) print ("Nonce (24 byte): ",binascii.b2a_hex(nonce)) print ("\nEncrypted: ",binascii.b2a_hex(encrypted.ciphertext)) print (f"Length of cipher: {len(encrypted.ciphertext)} = Cipher message: {len(message)} + MAC bytes: {box.MACBYTES}") print ("\nDecrypted: ",plain.decode())
A sample run is:
Message: Hello123 Password: mypass Salt: b'fd3d25ea44ce2d45f7563f1ca2c90002' Key (32 byte): b'dce0c1365379d0bada268b6a2efd3f3887fa945bdbe9a2e16e47ace0fa618966' Nonce (24 byte): b'f42828a9a2f229a45221b139cd504b2112f497d13b398642' Encrypted: b'70107d3c88552e0310379792357524267a342d666958c8d9' Length of cipher: 24 = Cipher message: 8 + MAC bytes: 16 Decrypted: Hello123