Close

The crypto method

A project log for Orthrus

SD card secure RAID USB storage

nick-sayerNick Sayer 03/30/2017 at 06:020 Comments

I've been pondering the exact crypto methodology this evening. I think what I've settled on is AES-128 counter mode.

In counter mode, each block of plaintext is XORed with the output of a single block of ECB encryption done with the key over a block of data built from a nonce (more later) and a counter that starts with 0 and counts upwards. The nonce is the equivalent of an OFB or CBC initialization vector. The whole scheme effectively turns ECB mode into a sort of pseudo one-time pad that generates data you XOR either with the plaintext for encryption or the ciphertext for decryption.

Normal disk blocks are 512 bytes long. The AES block size is 128 bits or 16 bytes, so a disk block is 32 AES blocks long. Therefore a single byte counter is plenty for the job. However, we also want to perturb the crypto on a per-block basis so that if you write the same data to two different blocks on the disk you get different ciphertext. The easy way to achieve that is to combine the single byte counter with a 4 byte block number (32 bits of block number for 512 byte sectors means a potential addressing range of 2 petabytes). That still leaves 11 bytes left for some other nonce value that can perhaps perturb different sections of the disk differently, or could just act as more key bits for the whole-disk encryption.

When writing a sector, you take the nonce and the initial block counter value of 0 and run those through AES with the disk's key. You then XOR the first 16 blocks of the sector data with the AES output. You then increment the counter value, encrypt the nonce/counter block and XOR the next 16 bits with that data. When reading a sector from the disk, you do the exact same thing to recover the plaintext from the on-disk ciphertext.

Whatever constant values of the nonce (not counting the sector number and the intra-sector block counter) need to be preserved as part of the key material of the disk. I am inclined to simply use separate nonces for the two cards and store them on the opposite card from the data they're for. The only other metadata we need to store on the card is half of the key and a RAID position indicator so we can tell if two matched cards are inserted in the "wrong" slots (such a configuration should be allowed to work normally). We probably also want to have a chunk of random data that's shared between the two cards. We'd do this to detect mismatches to prevent accidental corruption. If the volume ID data doesn't match, an LED could be made to turn red (the LED would be out if fewer than two cards are inserted, and green if two matching cards are in place). A small recessed button could be used to initialize new cards, which would simply create new key data and write the key blocks on each card.

EDIT:

In thinking more about this, I think it's going to be quite important to have a random 8 or 9 byte (or so) nonce for each card stored on the other card. The reason for this is if we were to store half the key on each card and if that were the only protection we had, then there would only be 64 bits of missing key data, which starts to be low enough an amount to contemplate brute-forcing.

Perhaps better would be to derive the primary key by performing a key derivation (like a Diffie-Hellman) with two chunks of random data stored on each card. That way none of the bits of the key are present until both cards are inserted. At that point, the primary key can be reconstituted and both of the nonces fetched and then all of the data on the cards should be available.

Discussions