10. Updating the threat model

November 20, 2017 ยท View on GitHub

By now our bank has mitigated the original threat model to a degree where the threat has shifted from the transaction log itself, and unto the key-pair. This means that we have centralised security onto something that is easier to reason about and has a much smaller attack surface, albeit being even more sensitive to the operation of our bank. However, this problem is now more a question of operations and policy than cryptography.

This also means that our priorities shift as we now have other threats that pose higher risk. In this age of data leaks, we want to make sure that if an adversary, eg. a three letter gov't agency, breaks into our bank server at night and steals the transaction log, they stand to learn very little about the banks business.

To achieve this, we need to introduce a new cryptographic primitive, symmetric encryption.

Symmetric crypto dates all the way back to at least Julius Caesar, who used it to communicate securely with his generals. Much has happened since then, but the basic idea is the same, you have a key that is used for both the encrypt and decrypt operations. In modern schemes you often also need a nonce which is often a random piece of data, that is not required to be secret, but protects against a several classes of attacks.

Using sodium-native this functionality is exposed through the crypto_secretbox APIs:

  • sodium.crypto_secretbox_easy(cipher, message, nonce, secretKey) Encrypt message Buffer into cipher Buffer with nonce and secretKey. The secret key must be sodium.crypto_secretbox_KEYBYTES and is best generated using the sodium.randombytes_buf API. This key must be persisted somehow. nonce should be another random buffer of size sodium.crypto_secretbox_NONCEBYTES. The cipher Buffer should be message.length + sodium.crypto_secretbox_MACBYTES long. It is important that you never re-use a nonce to encrypt more than a single message.
  • var bool = sodium.crypto_secretbox_open_easy(message, cipher, nonce, secretKey) Decrypt cipher Buffer into message Buffer using nonce and secretKey. Will return a boolean depending on whether the cipher text could be decrypted.

Problem

Use the APIs described above to make three new programs, secret-key.js encrypt.js and decrypt.js.

  • secret-key.js should generate a secret key using the randombytes_buf api of the correct length
  • encrypt.js should accept a secret key and a message and print out the encrypted message and the random nonce used to encrypt it.
  • decrypt.js should accept the encrypted message, secret key and nonce and print out the plaintext message if valid.

Testing

Try running a couple of test messages like Hello, World through your encrypter and try decrypting them to see that it works. Then try tampering with some of the encrypted messages to see that decryption fails.

Continue to problem 11