1

I use AES to creature HMAC signatures for API calls and while I understand what nonces are and why they're important, I'm a little confused on where exactly they're meant to be implemented.

I had the idea of using the nonce to alter a client's secret key to generate a new single-use key to sign calls that could otherwise be easily exploited with replay attacks.

The basic premise is the User, who gets a secret key when they log in, calls a setup API procedure which creates and returns a transactionID and a new nonce. The user then combines their own secret key and the nonce to sign the TransactionID and a few other things. The server then tries to match this signature using the currently active nonce for that user.

The server automatically clears old nonces and overwrites them when new setup calls are made so the user must always follow this paired sequence (you can't just reuse the second call, since the old nonce will have been deleted and the server will no longer accept this signature).

If this is the valid way to use nonces, how do I combine them with the client's keys to get a valid Secret key?

I generate AES providers this way:

 private static AesCryptoServiceProvider GetProvider(byte[] key, byte[] IV)
    {
        AesCryptoServiceProvider result = new AesCryptoServiceProvider();
        result.BlockSize = 128;
        result.KeySize = 256;
        result.Mode = CipherMode.CBC;
        result.Padding = PaddingMode.PKCS7;

        result.IV = IV;
        result.Key = key;

        return result;
    }

I use AES-256 so my keys are always 32 Bytes long. But if I want to create a new key using a nonce, I can't simply concatenate them since the resulting string would no longer be 32 bytes.

Should I concatenate and then use a fixed-length hash function to get the result back into a 32-byte length? Or is there an AESCryptoServiceProvider constructor/method that automatically handles nonces I'm missing? Or am I just supposed to append nonces in plaintext into the signature and let the server read them separately and check them directly?

ConnorU
  • 1,379
  • 2
  • 15
  • 27

1 Answers1

1

There are many ways to solve this. The easiest would be to use hashing. You can use HMAC or even HKDF.

SessionKey = HMAC_SHA256(SecretKey, Nonce)

Be sure to use the user's SecretKey only for deriving other keys. If you want to use this derivation for different things, then you need to bind the uses into the key:

SessionKey = HMAC_SHA256(SecretKey, "Encryption".Concat(Nonce))
SessionToken = HMAC_SHA256(SecretKey, "Token".Concat(Nonce))

This is just pseudo-code. Here are some examples of actual HMAC in C#.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222