Chromium Code Reviews| Index: nss/lib/freebl/chacha20poly1305.c |
| =================================================================== |
| --- nss/lib/freebl/chacha20poly1305.c (revision 0) |
| +++ nss/lib/freebl/chacha20poly1305.c (revision 0) |
| @@ -0,0 +1,197 @@ |
| +/* This Source Code Form is subject to the terms of the Mozilla Public |
| + * License, v. 2.0. If a copy of the MPL was not distributed with this |
| + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| + |
| +#ifdef FREEBL_NO_DEPEND |
| +#include "stubs.h" |
| +#endif |
| + |
| +#include <string.h> |
| +#include <stdio.h> |
| + |
| +#include "seccomon.h" |
| +#include "secerr.h" |
| +#include "blapit.h" |
| +#include "poly1305/poly1305.h" |
| +#include "chacha20/chacha20.h" |
| + |
| +/* ChaCha20Poly1305ContextStr saves the key and additional data for a |
| + * ChaCha20+Poly1305 AEAD operation. */ |
| +struct ChaCha20Poly1305ContextStr { |
| + unsigned char key[32]; |
| + unsigned char nonce[8]; |
| + unsigned char ad[16]; |
| + unsigned char *adOverflow; |
| + unsigned int adLen; |
| + unsigned char tagLen; |
| +}; |
| + |
| +/* Poly1305Do writes the Poly1305 authenticator of the given additional data |
| + * and ciphertext to |out|. */ |
| +static void |
| +Poly1305Do(unsigned char *out, |
| + const unsigned char *ad, unsigned int adLen, |
| + const unsigned char *ciphertext, unsigned int ciphertextLen, |
| + const unsigned char key[32]) |
| +{ |
| + poly1305_state state; |
| + unsigned int j; |
| + unsigned char lengthBytes[8]; |
| + unsigned int i; |
| + |
| + Poly1305Init(&state, key); |
| + j = adLen; |
| + for (i = 0; i < sizeof(lengthBytes); i++) { |
| + lengthBytes[i] = j; |
| + j >>= 8; |
| + } |
| + Poly1305Update(&state, ad, adLen); |
| + Poly1305Update(&state, lengthBytes, sizeof(lengthBytes)); |
| + j = ciphertextLen; |
| + for (i = 0; i < sizeof(lengthBytes); i++) { |
| + lengthBytes[i] = j; |
| + j >>= 8; |
| + } |
| + Poly1305Update(&state, ciphertext, ciphertextLen); |
| + Poly1305Update(&state, lengthBytes, sizeof(lengthBytes)); |
| + Poly1305Finish(&state, out); |
| +} |
| + |
| +ChaCha20Poly1305Context * |
| +ChaCha20Poly1305_CreateContext(const unsigned char *key, unsigned int keyLen, |
| + const unsigned char *nonce, unsigned int nonceLen, |
| + const unsigned char *ad, unsigned int adLen, |
| + unsigned int tagBits) |
| +{ |
| + ChaCha20Poly1305Context *ctx; |
| + |
| + if (keyLen != 32) { |
| + PORT_SetError(SEC_ERROR_BAD_KEY); |
| + return NULL; |
| + } |
| + if (nonceLen != sizeof(ctx->nonce)) { |
| + PORT_SetError(SEC_ERROR_INPUT_LEN); |
| + return NULL; |
| + } |
| + if (tagBits == 0 || tagBits > 128 || (tagBits & 7) != 0) { |
| + PORT_SetError(SEC_ERROR_INPUT_LEN); |
| + return NULL; |
| + } |
| + |
| + ctx = PORT_New(ChaCha20Poly1305Context); |
| + if (ctx == NULL) { |
| + return NULL; |
| + } |
| + |
| + memcpy(ctx->key, key, sizeof(ctx->key)); |
| + memcpy(ctx->nonce, nonce, sizeof(ctx->nonce)); |
| + ctx->tagLen = tagBits >> 3; |
| + |
| + if (adLen > sizeof(ctx->ad)) { |
| + /* Need to allocate an overflow buffer for the additional data. */ |
| + ctx->adOverflow = (unsigned char *)PORT_Alloc(adLen); |
| + if (!ctx->adOverflow) { |
| + PORT_Free(ctx); |
| + return NULL; |
| + } |
| + memcpy(ctx->adOverflow, ad, adLen); |
| + } else { |
| + ctx->adOverflow = NULL; |
| + memcpy(ctx->ad, ad, adLen); |
| + } |
| + ctx->adLen = adLen; |
| + |
| + return ctx; |
| +} |
| + |
| +void |
| +ChaCha20Poly1305_DestroyContext(ChaCha20Poly1305Context *ctx, PRBool freeit) |
| +{ |
| + if (ctx->adOverflow != NULL) { |
| + PORT_Free(ctx->adOverflow); |
| + ctx->adOverflow = NULL; |
| + } |
| + if (freeit) { |
| + PORT_Free(ctx); |
| + } |
| +} |
| + |
| +SECStatus |
| +ChaCha20Poly1305_Seal(const ChaCha20Poly1305Context *ctx, |
| + unsigned char *output, unsigned int *outputLen, |
| + unsigned int maxOutputLen, |
| + const unsigned char *input, unsigned int inputLen) |
| +{ |
| + const unsigned char *ad = ctx->adOverflow; |
| + unsigned char block[64]; |
| + unsigned char tag[16]; |
| + |
| + if (ctx->tagLen == 0 || ctx->tagLen > sizeof(tag)) { |
|
agl
2013/10/21 21:53:39
This test shouldn't be needed now?
wtc
2013/10/22 22:36:42
Done.
|
| + PORT_SetError(SEC_ERROR_INPUT_LEN); |
| + return SECFailure; |
| + } |
| + *outputLen = inputLen + ctx->tagLen; |
| + if (maxOutputLen < *outputLen) { |
| + PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
| + return SECFailure; |
| + } |
| + |
| + if (ad == NULL) { |
| + ad = ctx->ad; |
| + } |
| + |
| + memset(block, 0, sizeof(block)); |
| + // Generate a block of keystream. The first 32 bytes will be the poly1305 |
| + // key. The remainder of the block is discarded. |
| + ChaCha20XOR(block, block, sizeof(block), ctx->key, ctx->nonce, 0); |
| + ChaCha20XOR(output, input, inputLen, ctx->key, ctx->nonce, 1); |
| + |
| + Poly1305Do(tag, ad, ctx->adLen, output, inputLen, block); |
| + memcpy(output + inputLen, tag, ctx->tagLen); |
| + |
| + return SECSuccess; |
| +} |
| + |
| +SECStatus |
| +ChaCha20Poly1305_Open(const ChaCha20Poly1305Context *ctx, |
| + unsigned char *output, unsigned int *outputLen, |
| + unsigned int maxOutputLen, |
| + const unsigned char *input, unsigned int inputLen) |
| +{ |
| + const unsigned char *ad = ctx->adOverflow; |
| + unsigned char block[64]; |
| + unsigned int i; |
| + unsigned char tag[16]; |
| + |
| + if (ctx->tagLen == 0 || ctx->tagLen > sizeof(tag)) { |
|
agl
2013/10/21 21:53:39
This test shouldn't be needed now?
wtc
2013/10/22 22:36:42
Done.
|
| + PORT_SetError(SEC_ERROR_INPUT_LEN); |
| + return SECFailure; |
| + } |
| + if (inputLen < ctx->tagLen) { |
| + PORT_SetError(SEC_ERROR_INPUT_LEN); |
| + return SECFailure; |
| + } |
| + *outputLen = inputLen - ctx->tagLen; |
| + if (maxOutputLen < *outputLen) { |
| + PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
| + return SECFailure; |
| + } |
| + |
| + if (ad == NULL) { |
| + ad = ctx->ad; |
| + } |
| + |
| + memset(block, 0, sizeof(block)); |
| + // Generate a block of keystream. The first 32 bytes will be the poly1305 |
| + // key. The remainder of the block is discarded. |
| + ChaCha20XOR(block, block, sizeof(block), ctx->key, ctx->nonce, 0); |
| + Poly1305Do(tag, ad, ctx->adLen, input, inputLen - ctx->tagLen, block); |
| + if (NSS_SecureMemcmp(tag, &input[inputLen - ctx->tagLen], ctx->tagLen) != 0) { |
| + PORT_SetError(SEC_ERROR_BAD_DATA); |
| + return SECFailure; |
| + } |
| + |
| + ChaCha20XOR(output, input, inputLen - ctx->tagLen, ctx->key, ctx->nonce, 1); |
| + |
| + return SECSuccess; |
| +} |
| Property changes on: nss/lib/freebl/chacha20poly1305.c |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |