2
$\begingroup$

I'm implementing a cryptographic primitive and I have a question about the memory model. The function (simplified) looks something like this:

void encrypt(unsigned char *out,
             const unsigned char *in,
             const unsigned char *pub_key)
{
  unsigned char buf[OUTPUT_SIZE];
  size_t i, j;

  memcpy(out, in, OUTPUT_SIZE);
  for (i = OUTPUT_SIZE; i < INPUT_SIZE; i += OUTPUT_SIZE) {
     compute(buf, in[i], pub_key);
     for (j = 0; j < OUTPUT_SIZE; ++j) {
        out[j] ^= buf[j];
     }
  }
}

To summarize: the input (plaintext) is chopped in blocks of size OUTPUT_SIZE and a computation is done on each block (except the first). Each iteration, the result of a computation on the input block and the public key gets stored in the buffer. The output (ciphertext) is the result of the binary sum (xor) of all processed blocks. The caller of the function has to provide an allocated memory block for the output. This memory may reside on the stack or the heap.

My question is: is this construction secure? I am afraid that because the memory is provided by the caller, there are scenario's in which an adversary can inspect intermediate values of this memory through sidechannels and learn about the secret plaintext. On the other hand I'm thinking: if the attacker has access to the out buffer, then why not also to the in buffer?

$\endgroup$
  • 1
    $\begingroup$ You should implement the OS "unpaged" apis to make sure that the memory location will not be placed in the pagefile for any reason (VirtualLock in windows) until you are done with that memory location $\endgroup$ – Richie Frame Aug 9 '16 at 0:26
6
$\begingroup$

If the computation is performed via an ordinary function call, then the caller and the callee live in the same address space. In this case, there is no concern about secrecy: the callee is not protected from the caller in any way. A malicious caller has access to the same memory as the callee and so they can access the key, they can inspect and modify the execution of the function, etc.

You should worry about accidental leaks, due to a buggy caller. It is standard good practice to wipe all memory that has been used for cryptographic computations after use. This way, even if the program later leaks memory, that's one secret that won't leak. For example, in this case, you should wipe the temporary variable on the stack. The basic idea is to call memset(buf, 0, sizeof(buf)) at the end of encrypt, but this actually doesn't work in practice, because the compiler is likely to optimize it away (what sense is there to write to an object that goes out of scope immediately afterwards?). CERT recommendation MSC06-C discusses this problem and some solutions (use memset_s if you have it, but it was only standardized in C11).

If the call is a cross-context call of some kind, for example a system call from a user program to a cryptographic service running in a more privileged CPU mode, or a call to a different process using shared memory, then the situation is different. In such cases, you need to be careful inside the cryptographic service to use the service's own memory for all key material and intermediate results that the client must not be able to access. Furthermore, in the service, you need to be careful when reading data in memory that is shared with the client, because the client might change the content of that memory: never read the same memory twice, or read back what you wrote. And you need to be careful when writing data to memory that is shared with the client, as the timing of these writes might convey information. The general rule for a data processing service running in a different context but communicating via shared memory (e.g. an operating system kernel) is: first copy the input parameters; then process the data in the service's memory; then copy the final output into shared memory. It sometimes makes sense to do this in several stages, but keep the data flow in mind and be aware of what the client might observe and perturb.

$\endgroup$

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.