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 |