| OLD | NEW |
| (Empty) |
| 1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
| 2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 4 | |
| 5 #ifdef FREEBL_NO_DEPEND | |
| 6 #include "stubs.h" | |
| 7 #endif | |
| 8 | |
| 9 #include <string.h> | |
| 10 #include <stdio.h> | |
| 11 | |
| 12 #include "seccomon.h" | |
| 13 #include "secerr.h" | |
| 14 #include "blapit.h" | |
| 15 | |
| 16 #ifndef NSS_DISABLE_CHACHAPOLY | |
| 17 #include "poly1305.h" | |
| 18 #include "chacha20.h" | |
| 19 #include "chacha20poly1305.h" | |
| 20 #endif | |
| 21 | |
| 22 /* Poly1305Do writes the Poly1305 authenticator of the given additional data | |
| 23 * and ciphertext to |out|. */ | |
| 24 #ifndef NSS_DISABLE_CHACHAPOLY | |
| 25 static void | |
| 26 Poly1305Do(unsigned char *out, const unsigned char *ad, unsigned int adLen, | |
| 27 const unsigned char *ciphertext, unsigned int ciphertextLen, | |
| 28 const unsigned char key[32]) | |
| 29 { | |
| 30 poly1305_state state; | |
| 31 unsigned int j; | |
| 32 unsigned char lengthBytes[8]; | |
| 33 static const unsigned char zeros[15]; | |
| 34 unsigned int i; | |
| 35 | |
| 36 Poly1305Init(&state, key); | |
| 37 Poly1305Update(&state, ad, adLen); | |
| 38 if (adLen % 16 > 0) { | |
| 39 Poly1305Update(&state, zeros, 16 - adLen % 16); | |
| 40 } | |
| 41 Poly1305Update(&state, ciphertext, ciphertextLen); | |
| 42 if (ciphertextLen % 16 > 0) { | |
| 43 Poly1305Update(&state, zeros, 16 - ciphertextLen % 16); | |
| 44 } | |
| 45 j = adLen; | |
| 46 for (i = 0; i < sizeof(lengthBytes); i++) { | |
| 47 lengthBytes[i] = j; | |
| 48 j >>= 8; | |
| 49 } | |
| 50 Poly1305Update(&state, lengthBytes, sizeof(lengthBytes)); | |
| 51 j = ciphertextLen; | |
| 52 for (i = 0; i < sizeof(lengthBytes); i++) { | |
| 53 lengthBytes[i] = j; | |
| 54 j >>= 8; | |
| 55 } | |
| 56 Poly1305Update(&state, lengthBytes, sizeof(lengthBytes)); | |
| 57 Poly1305Finish(&state, out); | |
| 58 } | |
| 59 #endif | |
| 60 | |
| 61 SECStatus | |
| 62 ChaCha20Poly1305_InitContext(ChaCha20Poly1305Context *ctx, | |
| 63 const unsigned char *key, unsigned int keyLen, | |
| 64 unsigned int tagLen) | |
| 65 { | |
| 66 #ifdef NSS_DISABLE_CHACHAPOLY | |
| 67 return SECFailure; | |
| 68 #else | |
| 69 if (keyLen != 32) { | |
| 70 PORT_SetError(SEC_ERROR_BAD_KEY); | |
| 71 return SECFailure; | |
| 72 } | |
| 73 if (tagLen == 0 || tagLen > 16) { | |
| 74 PORT_SetError(SEC_ERROR_INPUT_LEN); | |
| 75 return SECFailure; | |
| 76 } | |
| 77 | |
| 78 PORT_Memcpy(ctx->key, key, sizeof(ctx->key)); | |
| 79 ctx->tagLen = tagLen; | |
| 80 | |
| 81 return SECSuccess; | |
| 82 #endif | |
| 83 } | |
| 84 | |
| 85 ChaCha20Poly1305Context * | |
| 86 ChaCha20Poly1305_CreateContext(const unsigned char *key, unsigned int keyLen, | |
| 87 unsigned int tagLen) | |
| 88 { | |
| 89 #ifdef NSS_DISABLE_CHACHAPOLY | |
| 90 return NULL; | |
| 91 #else | |
| 92 ChaCha20Poly1305Context *ctx; | |
| 93 | |
| 94 ctx = PORT_New(ChaCha20Poly1305Context); | |
| 95 if (ctx == NULL) { | |
| 96 return NULL; | |
| 97 } | |
| 98 | |
| 99 if (ChaCha20Poly1305_InitContext(ctx, key, keyLen, tagLen) != SECSuccess) { | |
| 100 PORT_Free(ctx); | |
| 101 ctx = NULL; | |
| 102 } | |
| 103 | |
| 104 return ctx; | |
| 105 #endif | |
| 106 } | |
| 107 | |
| 108 void | |
| 109 ChaCha20Poly1305_DestroyContext(ChaCha20Poly1305Context *ctx, PRBool freeit) | |
| 110 { | |
| 111 #ifndef NSS_DISABLE_CHACHAPOLY | |
| 112 PORT_Memset(ctx, 0, sizeof(*ctx)); | |
| 113 if (freeit) { | |
| 114 PORT_Free(ctx); | |
| 115 } | |
| 116 #endif | |
| 117 } | |
| 118 | |
| 119 SECStatus | |
| 120 ChaCha20Poly1305_Seal(const ChaCha20Poly1305Context *ctx, unsigned char *output, | |
| 121 unsigned int *outputLen, unsigned int maxOutputLen, | |
| 122 const unsigned char *input, unsigned int inputLen, | |
| 123 const unsigned char *nonce, unsigned int nonceLen, | |
| 124 const unsigned char *ad, unsigned int adLen) | |
| 125 { | |
| 126 #ifdef NSS_DISABLE_CHACHAPOLY | |
| 127 return SECFailure; | |
| 128 #else | |
| 129 unsigned char block[64]; | |
| 130 unsigned char tag[16]; | |
| 131 | |
| 132 if (nonceLen != 12) { | |
| 133 PORT_SetError(SEC_ERROR_INPUT_LEN); | |
| 134 return SECFailure; | |
| 135 } | |
| 136 *outputLen = inputLen + ctx->tagLen; | |
| 137 if (maxOutputLen < *outputLen) { | |
| 138 PORT_SetError(SEC_ERROR_OUTPUT_LEN); | |
| 139 return SECFailure; | |
| 140 } | |
| 141 | |
| 142 PORT_Memset(block, 0, sizeof(block)); | |
| 143 // Generate a block of keystream. The first 32 bytes will be the poly1305 | |
| 144 // key. The remainder of the block is discarded. | |
| 145 ChaCha20XOR(block, block, sizeof(block), ctx->key, nonce, 0); | |
| 146 ChaCha20XOR(output, input, inputLen, ctx->key, nonce, 1); | |
| 147 | |
| 148 Poly1305Do(tag, ad, adLen, output, inputLen, block); | |
| 149 PORT_Memcpy(output + inputLen, tag, ctx->tagLen); | |
| 150 | |
| 151 return SECSuccess; | |
| 152 #endif | |
| 153 } | |
| 154 | |
| 155 SECStatus | |
| 156 ChaCha20Poly1305_Open(const ChaCha20Poly1305Context *ctx, unsigned char *output, | |
| 157 unsigned int *outputLen, unsigned int maxOutputLen, | |
| 158 const unsigned char *input, unsigned int inputLen, | |
| 159 const unsigned char *nonce, unsigned int nonceLen, | |
| 160 const unsigned char *ad, unsigned int adLen) | |
| 161 { | |
| 162 #ifdef NSS_DISABLE_CHACHAPOLY | |
| 163 return SECFailure; | |
| 164 #else | |
| 165 unsigned char block[64]; | |
| 166 unsigned char tag[16]; | |
| 167 unsigned int ciphertextLen; | |
| 168 | |
| 169 if (nonceLen != 12) { | |
| 170 PORT_SetError(SEC_ERROR_INPUT_LEN); | |
| 171 return SECFailure; | |
| 172 } | |
| 173 if (inputLen < ctx->tagLen) { | |
| 174 PORT_SetError(SEC_ERROR_INPUT_LEN); | |
| 175 return SECFailure; | |
| 176 } | |
| 177 ciphertextLen = inputLen - ctx->tagLen; | |
| 178 *outputLen = ciphertextLen; | |
| 179 if (maxOutputLen < *outputLen) { | |
| 180 PORT_SetError(SEC_ERROR_OUTPUT_LEN); | |
| 181 return SECFailure; | |
| 182 } | |
| 183 | |
| 184 PORT_Memset(block, 0, sizeof(block)); | |
| 185 // Generate a block of keystream. The first 32 bytes will be the poly1305 | |
| 186 // key. The remainder of the block is discarded. | |
| 187 ChaCha20XOR(block, block, sizeof(block), ctx->key, nonce, 0); | |
| 188 Poly1305Do(tag, ad, adLen, input, ciphertextLen, block); | |
| 189 if (NSS_SecureMemcmp(tag, &input[ciphertextLen], ctx->tagLen) != 0) { | |
| 190 PORT_SetError(SEC_ERROR_BAD_DATA); | |
| 191 return SECFailure; | |
| 192 } | |
| 193 | |
| 194 ChaCha20XOR(output, input, ciphertextLen, ctx->key, nonce, 1); | |
| 195 | |
| 196 return SECSuccess; | |
| 197 #endif | |
| 198 } | |
| OLD | NEW |