Skip to content

Instantly share code, notes, and snippets.

@tarcieri
Last active March 18, 2019 10:51
Show Gist options
  • Save tarcieri/5351974 to your computer and use it in GitHub Desktop.
Save tarcieri/5351974 to your computer and use it in GitHub Desktop.
Authenticated Encryption for Dummies

It might seem like a silly exercise, but I was looking at the "NIST approved" algorithms in NaCl (i.e. AES, HMAC) and wondering if I could build an authenticated encryption system with them. djb lists AES-GCM as a "todo" secretbox primitive so unfortunately NaCl does not presently expose any AES-based authenticated encryption, only aes128ctr.

This is what I came up with using the algorithms available in NaCl:

Diagram

A quick rundown:

Encrypt-then-MAC with AES-CTR (128-bit for now, 256-bit later!) encryption and HMAC SHA-512256 (i.e. SHA-512, truncated to 256-bits by NaCl via crypto_auth_hmacsha512256) authentication. MAC comparisons are performed using a NaCl supplied verifier function which is (hopefully!) constant time.

Separate keys are used for AES and HMAC, derived by combining an initial 256-bit key and a nonce with HKDF and expanding the result into unique keys for AES and HMAC. Because a unique key is used for each AES encryption, the AES counter can always start at 0.

While a cryptographic layman should probably not be designing an authenticated encryption mode, it seems like these particular primitives are relatively free of rough edges, particularly when I am using the implementations available in NaCl

Cool story, should I run off and implement this?

No, you want Crypto::SecretBox

@tarcieri
Copy link
Author

@namelessjon I think MACing the nonce just removes more margin-of-error. I should probably enquire with Matt Green what the exact rationale is though. Or you can! ;)

RE: Arbitrary length nonces, I'd probably set a cap. Marsh Ray suggested MACing nonce length || nonce || ciphertext. If I used a byte to represent the nonce length, it'd set the maximum size of the nonce at an (unrealistically large) 256 bytes.

@namelessjon
Copy link

Conversations on Twitter while you sleep are fun to wake up to, but hard to contribute to ;)

I guess I buy his "why the hell not?" argument, but I'm also glad I didn't miss a more fundamental one.

Re: nonce length, I would specify one as part of the scheme, e.g. 24 bytes or 32 bytes. Long enough to safely pick at random, short enough it's not wasting effort (or random bytes).

@tarcieri
Copy link
Author

@namelessjon I think originally he didn't see I had changed the scheme to have the nonce be HKDF input, which accomplishes the same thing.

A fixed length nonce is probably fine. 24-bytes seems reasonable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment