0

There are various other posts which talk about grabbing a key from ram such as

My question is a bit different. Assume that we have the key and for a brief window we'll use it to initialize a cipher (in this case ChaCha20) and then wipe the key from memory (using best practices, memset_s etc.)[*edit2]

Once the cipher is initialized, is that equivalent to having the key in memory?

Specifically, looking at the ChaCha20 reference code: https://cr.yp.to/streamciphers/timings/estreambench/submissions/salsa20/chacha8/ref/chacha.c

void ECRYPT_keysetup(ECRYPT_ctx *x,const u8 *k,u32 kbits,u32 ivbits)
{
  const char *constants;

  x->input[4] = U8TO32_LITTLE(k + 0);
  x->input[5] = U8TO32_LITTLE(k + 4);
  x->input[6] = U8TO32_LITTLE(k + 8);
  x->input[7] = U8TO32_LITTLE(k + 12);
  if (kbits == 256) { /* recommended */
    k += 16;
    constants = sigma;
  } else { /* kbits == 128 */
    constants = tau;
  }
  x->input[8] = U8TO32_LITTLE(k + 0);
  x->input[9] = U8TO32_LITTLE(k + 4);
  x->input[10] = U8TO32_LITTLE(k + 8);
  x->input[11] = U8TO32_LITTLE(k + 12);
  x->input[0] = U8TO32_LITTLE(constants + 0);
  x->input[1] = U8TO32_LITTLE(constants + 4);
  x->input[2] = U8TO32_LITTLE(constants + 8);
  x->input[3] = U8TO32_LITTLE(constants + 12);
}

It seems that one simply needs to get the memory location pointed at by x->input, read in like 48 bytes of data from that point, and you've got it.

  1. Is this correct?
  2. How can this be prevented in software? (best practices)

EDIT: I see that at least input[12] and input[13] are adjusted as bytes are crunched... and that the cipher can be "seeked" by adjusting input[8] and input[9] (or at least in salsa20, I guess chacha20 is similar)... so therefore it would probably be enough to simply seek to a random "location", and encrypt some random filler bytes, upon initialization

  1. Is this correct, would it improve defense against grabbing the key (or initialization state)?

EDIT 2:

I believe the key can be wiped from memory once the cipher is initialized since the reference implementation does not use it for decryption... or am I missing something?

Example:

ECRYPT_init();
ECRYPT_keysetup(&ctx, MyKey, ECRYPT_MAXKEYSIZE, ECRYPT_MAXIVSIZE);
ECRYPT_ivsetup(&ctx, MyIv);

//notice neither MyKey nor MyIv are used here:
ECRYPT_decrypt_bytes(&ctx, ciphertext, plaintext, ciphertext_len);
1

The ChaCha20 algorithm is simple enough that if you're curious about how it works you could just write your own implementation (but don't use it in production!). RFC 7539 is a simple reference that also comes with examples so you can easily check for correctness as you go along. But the way it works is that you XOR the message with a keystream that is generated as a set of 64-byte blocks, where each block is "named" by three arguments:

  1. The key (secret);
  2. The nonce (not secret);
  3. The block counter (not secret).

The block is initialized with these values and some constants in the way that your code snippet shows. Then the block is scrambled with the doubleround operation ten times (ten double rounds = twenty rounds, that's why there's a "20" in the name). And now, critically, the initial state of the block is added into the result of that, and this step requires the key again—so if you erased it you wouldn't be able to carry out this final step.

After that final addition the key should not be easily recoverable from the resulting block (or otherwise the cipher is completely broken!). But nevertheless the block's content is a sensitive secret, because an attacker who sees it can decrypt the corresponding ciphertext block.

All you've got at this point, however, is one 64-byte block, which is good only for encrypting or decrypting one 64-byte block of the message. Unless 64 bytes is the largest message length you'll ever encrypt, you're going to need the key again and again to generate additional blocks. So you can only erase the key and blocks after you've encrypted or decrypted the whole message.

Since both the key and the keystream blocks are secret data, you'd want to use your operating system's facilities to prevent that memory from being swapped out to disk. And you'll want to safely zero out that memory after you're done with it.

Similar considerations apply to other ciphers, but the details are different. For example, many ciphers (but not ChaCha20) have a key schedule, i.e. a sequence of "subkeys" that are derived from the secret key. Often it is the case that after you've generated the key schedule you don't need the key any more, so you could zero out the key at that point, but the subkeys need to be protected, and you need to hang on to them because you reuse them for each block that you process.

  • thanks, I really appreciate the detailed answer and breaking it down into simple terms! However I'm a bit confused about not needing the key anymore... I edited the question to address that (see EDIT 2). Am I mistaken? – davidkomer Jun 17 '16 at 8:36
  • @davidkomer: That code is written to a common interface from the eSTREAM competition, to facilitate testing of contestants, which IMHO obscures the details of ChaCha20 a tiny bit. But looking at it, notice that the ECRYPT_keysetup function copies the key into its ECRYPT_ctx argument, which then needs to be reused for each block generated by the salsa20_wordtobyte function. So while you may safely zero out the *k argument to ECRYPT_keysetup, keep in mind another copy of it lives on! – Luis Casillas Jun 17 '16 at 18:22
  • thanks, and for the explanation :) Quick followup - for " you'd want to use your operating system's facilities to prevent that memory from being swapped out to disk." is there a standard library in C which will handle this for me in a cross-platform way? – davidkomer Jun 19 '16 at 8:18
  • You're going to need to check your OS documentation to confirm this. In Linux it's the mlock() system call. – Luis Casillas Jun 20 '16 at 3:48
  • Cool.. I've looked into this and it seems libgcrypt handles all the different unixes in secmem.c :) However, on windows, it's a different story. I've posted a new question here if you're interested: security.stackexchange.com/questions/127514/… – davidkomer Jun 20 '16 at 4:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.