|
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 #include "poly1305/poly1305.h" | |
16 #include "chacha20/chacha20.h" | |
17 | |
18 /* ChaCha20Poly1305ContextStr saves the key and additional data for a | |
19 * ChaCha20+Poly1305 AEAD operation. */ | |
20 struct ChaCha20Poly1305ContextStr { | |
21 unsigned char key[32]; | |
22 unsigned char nonce[8]; | |
23 unsigned char ad[16]; | |
24 unsigned char *adOverflow; | |
25 unsigned int adLen; | |
26 unsigned char tagLen; | |
27 }; | |
28 | |
29 /* Poly1305Do writes the Poly1305 authenticator of the given additional data | |
30 * and ciphertext to |out|. */ | |
31 static void | |
32 Poly1305Do(unsigned char *out, | |
33 const unsigned char *ad, unsigned int adLen, | |
34 const unsigned char *ciphertext, unsigned int ciphertextLen, | |
35 const unsigned char key[32]) | |
36 { | |
37 poly1305_state state; | |
38 unsigned int j; | |
39 unsigned char lengthBytes[8]; | |
40 unsigned int i; | |
41 | |
42 Poly1305Init(&state, key); | |
43 j = adLen; | |
44 for (i = 0; i < sizeof(lengthBytes); i++) { | |
45 lengthBytes[i] = j; | |
46 j >>= 8; | |
47 } | |
48 Poly1305Update(&state, ad, adLen); | |
49 Poly1305Update(&state, lengthBytes, sizeof(lengthBytes)); | |
50 j = ciphertextLen; | |
51 for (i = 0; i < sizeof(lengthBytes); i++) { | |
52 lengthBytes[i] = j; | |
53 j >>= 8; | |
54 } | |
55 Poly1305Update(&state, ciphertext, ciphertextLen); | |
56 Poly1305Update(&state, lengthBytes, sizeof(lengthBytes)); | |
57 Poly1305Finish(&state, out); | |
58 } | |
59 | |
60 ChaCha20Poly1305Context * | |
61 ChaCha20Poly1305_CreateContext(const unsigned char *key, unsigned int keyLen, | |
62 const unsigned char *nonce, unsigned int nonceLen , | |
63 const unsigned char *ad, unsigned int adLen, | |
64 unsigned int tagBits) | |
65 { | |
66 ChaCha20Poly1305Context *ctx; | |
67 | |
68 if (keyLen != 32) { | |
69 PORT_SetError(SEC_ERROR_BAD_KEY); | |
70 return NULL; | |
71 } | |
72 if (nonceLen != sizeof(ctx->nonce)) { | |
73 PORT_SetError(SEC_ERROR_INPUT_LEN); | |
74 return NULL; | |
75 } | |
76 if (tagBits == 0 || tagBits > 128 || (tagBits & 7) != 0) { | |
77 PORT_SetError(SEC_ERROR_INPUT_LEN); | |
78 return NULL; | |
79 } | |
80 | |
81 ctx = PORT_New(ChaCha20Poly1305Context); | |
82 if (ctx == NULL) { | |
83 return NULL; | |
84 } | |
85 | |
86 memcpy(ctx->key, key, sizeof(ctx->key)); | |
87 memcpy(ctx->nonce, nonce, sizeof(ctx->nonce)); | |
88 ctx->tagLen = tagBits >> 3; | |
89 | |
90 if (adLen > sizeof(ctx->ad)) { | |
91 /* Need to allocate an overflow buffer for the additional data. */ | |
92 ctx->adOverflow = (unsigned char *)PORT_Alloc(adLen); | |
93 if (!ctx->adOverflow) { | |
94 PORT_Free(ctx); | |
95 return NULL; | |
96 } | |
97 memcpy(ctx->adOverflow, ad, adLen); | |
98 } else { | |
99 ctx->adOverflow = NULL; | |
100 memcpy(ctx->ad, ad, adLen); | |
101 } | |
102 ctx->adLen = adLen; | |
103 | |
104 return ctx; | |
105 } | |
106 | |
107 void | |
108 ChaCha20Poly1305_DestroyContext(ChaCha20Poly1305Context *ctx, PRBool freeit) | |
109 { | |
110 if (ctx->adOverflow != NULL) { | |
111 PORT_Free(ctx->adOverflow); | |
112 ctx->adOverflow = NULL; | |
113 } | |
114 if (freeit) { | |
115 PORT_Free(ctx); | |
116 } | |
117 } | |
118 | |
119 SECStatus | |
120 ChaCha20Poly1305_Seal(const ChaCha20Poly1305Context *ctx, | |
121 unsigned char *output, unsigned int *outputLen, | |
122 unsigned int maxOutputLen, | |
123 const unsigned char *input, unsigned int inputLen) | |
124 { | |
125 const unsigned char *ad = ctx->adOverflow; | |
126 unsigned char block[64]; | |
127 unsigned char tag[16]; | |
128 | |
129 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.
| |
130 PORT_SetError(SEC_ERROR_INPUT_LEN); | |
131 return SECFailure; | |
132 } | |
133 *outputLen = inputLen + ctx->tagLen; | |
134 if (maxOutputLen < *outputLen) { | |
135 PORT_SetError(SEC_ERROR_OUTPUT_LEN); | |
136 return SECFailure; | |
137 } | |
138 | |
139 if (ad == NULL) { | |
140 ad = ctx->ad; | |
141 } | |
142 | |
143 memset(block, 0, sizeof(block)); | |
144 // Generate a block of keystream. The first 32 bytes will be the poly1305 | |
145 // key. The remainder of the block is discarded. | |
146 ChaCha20XOR(block, block, sizeof(block), ctx->key, ctx->nonce, 0); | |
147 ChaCha20XOR(output, input, inputLen, ctx->key, ctx->nonce, 1); | |
148 | |
149 Poly1305Do(tag, ad, ctx->adLen, output, inputLen, block); | |
150 memcpy(output + inputLen, tag, ctx->tagLen); | |
151 | |
152 return SECSuccess; | |
153 } | |
154 | |
155 SECStatus | |
156 ChaCha20Poly1305_Open(const ChaCha20Poly1305Context *ctx, | |
157 unsigned char *output, unsigned int *outputLen, | |
158 unsigned int maxOutputLen, | |
159 const unsigned char *input, unsigned int inputLen) | |
160 { | |
161 const unsigned char *ad = ctx->adOverflow; | |
162 unsigned char block[64]; | |
163 unsigned int i; | |
164 unsigned char tag[16]; | |
165 | |
166 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.
| |
167 PORT_SetError(SEC_ERROR_INPUT_LEN); | |
168 return SECFailure; | |
169 } | |
170 if (inputLen < ctx->tagLen) { | |
171 PORT_SetError(SEC_ERROR_INPUT_LEN); | |
172 return SECFailure; | |
173 } | |
174 *outputLen = inputLen - ctx->tagLen; | |
175 if (maxOutputLen < *outputLen) { | |
176 PORT_SetError(SEC_ERROR_OUTPUT_LEN); | |
177 return SECFailure; | |
178 } | |
179 | |
180 if (ad == NULL) { | |
181 ad = ctx->ad; | |
182 } | |
183 | |
184 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, ctx->nonce, 0); | |
188 Poly1305Do(tag, ad, ctx->adLen, input, inputLen - ctx->tagLen, block); | |
189 if (NSS_SecureMemcmp(tag, &input[inputLen - ctx->tagLen], ctx->tagLen) != 0) { | |
190 PORT_SetError(SEC_ERROR_BAD_DATA); | |
191 return SECFailure; | |
192 } | |
193 | |
194 ChaCha20XOR(output, input, inputLen - ctx->tagLen, ctx->key, ctx->nonce, 1); | |
195 | |
196 return SECSuccess; | |
197 } | |
OLD | NEW |