1 /*
2 * This file is part of the openHiTLS project.
3 *
4 * openHiTLS is licensed under the Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 *
8 * http://license.coscl.org.cn/MulanPSL2
9 *
10 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13 * See the Mulan PSL v2 for more details.
14 */
15
16 #include "hitls_build.h"
17 #if defined(HITLS_CRYPTO_CHACHA20) && defined(HITLS_CRYPTO_CHACHA20POLY1305)
18
19 #include <stdint.h>
20 #include "securec.h"
21 #include "bsl_sal.h"
22 #include "bsl_err_internal.h"
23 #include "crypt_utils.h"
24 #include "crypt_errno.h"
25 #include "modes_local.h"
26 #include "poly1305_core.h"
27 #include "crypt_modes.h"
28
Poly1305SetKey(Poly1305Ctx * ctx,const uint8_t key[POLY1305_KEYSIZE])29 void Poly1305SetKey(Poly1305Ctx *ctx, const uint8_t key[POLY1305_KEYSIZE])
30 {
31 // RFC_7539-2.5
32 ctx->r[0] = GET_UINT32_LE(key, 0);
33 ctx->r[1] = GET_UINT32_LE(key, 4);
34 ctx->r[2] = GET_UINT32_LE(key, 8);
35 ctx->r[3] = GET_UINT32_LE(key, 12);
36 ctx->s[0] = GET_UINT32_LE(key, 16);
37 ctx->s[1] = GET_UINT32_LE(key, 20);
38 ctx->s[2] = GET_UINT32_LE(key, 24);
39 ctx->s[3] = GET_UINT32_LE(key, 28);
40
41 /**
42 * r[3], r[7], r[11], and r[15] are required to have their top four
43 * bits clear (be smaller than 16)
44 * r[4], r[8], and r[12] are required to have their bottom two bits
45 * clear (be divisible by 4)
46 */
47 ctx->r[0] &= 0x0FFFFFFF;
48 ctx->r[1] &= 0x0FFFFFFC;
49 ctx->r[2] &= 0x0FFFFFFC;
50 ctx->r[3] &= 0x0FFFFFFC;
51
52 ctx->acc[0] = 0;
53 ctx->acc[1] = 0;
54 ctx->acc[2] = 0;
55 ctx->acc[3] = 0;
56 ctx->acc[4] = 0;
57 ctx->acc[5] = 0;
58
59 (void)memset_s(ctx->last, sizeof(ctx->last), 0, sizeof(ctx->last));
60 ctx->lastLen = 0;
61 Poly1305InitForAsm(ctx); // Information such as tables required for initializing the assembly
62 }
63
Poly1305Update(Poly1305Ctx * ctx,const uint8_t * data,uint32_t dataLen)64 void Poly1305Update(Poly1305Ctx *ctx, const uint8_t *data, uint32_t dataLen)
65 {
66 uint32_t i;
67 uint32_t len = dataLen;
68 const uint8_t *off = data;
69 if (ctx->lastLen != 0) {
70 uint64_t end = (uint64_t)len + ctx->lastLen;
71 if (end > POLY1305_BLOCKSIZE) {
72 end = POLY1305_BLOCKSIZE;
73 }
74 for (i = ctx->lastLen; i < end; i++) {
75 ctx->last[i] = *off;
76 off++;
77 }
78 len -= (uint32_t)(end - ctx->lastLen);
79 if (end == POLY1305_BLOCKSIZE) {
80 (void)Poly1305Block(ctx, ctx->last, POLY1305_BLOCKSIZE, 1);
81 } else {
82 ctx->lastLen = (uint32_t)end;
83 return;
84 }
85 }
86 /**
87 * Add one bit beyond the number of octets. For a 16-byte block,
88 * this is equivalent to adding 2^128 to the number.
89 */
90 if (len >= POLY1305_BLOCKSIZE) {
91 (void)Poly1305Block(ctx, off, len & 0xfffffff0, 1);
92 }
93 ctx->lastLen = len & 0x0f; // mod 16;
94 off += len - ctx->lastLen;
95 for (i = 0; i < ctx->lastLen; i++) {
96 ctx->last[i] = off[i];
97 }
98 return;
99 }
100
Poly1305Final(Poly1305Ctx * ctx,uint8_t mac[POLY1305_TAGSIZE])101 void Poly1305Final(Poly1305Ctx *ctx, uint8_t mac[POLY1305_TAGSIZE])
102 {
103 uint32_t len = ctx->lastLen;
104 if (len > 0) {
105 /**
106 * For the shorter block, it can be 2^120, 2^112, or any power of two that is
107 * evenly divisible by 8, all the way down to 2^8
108 */
109 ctx->last[len++] = 1;
110 /**
111 * If the block is not 17 bytes long (the last block), pad it with
112 * zeros. This is meaningless if you are treating the blocks as
113 * numbers.
114 */
115 while (len < POLY1305_BLOCKSIZE) {
116 ctx->last[len++] = 0;
117 }
118 Poly1305Block(ctx, ctx->last, POLY1305_BLOCKSIZE, 0);
119 ctx->lastLen = 0;
120 }
121 Poly1305Last(ctx, mac);
122 }
123
124
MODES_CHACHA20POLY1305_Encrypt(MODES_CipherChaChaPolyCtx * ctx,const uint8_t * in,uint8_t * out,uint32_t len)125 int32_t MODES_CHACHA20POLY1305_Encrypt(MODES_CipherChaChaPolyCtx *ctx, const uint8_t *in, uint8_t *out, uint32_t len)
126 {
127 if (ctx == NULL || in == NULL || out == NULL || len == 0) {
128 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
129 return CRYPT_NULL_INPUT;
130 }
131 int32_t ret = ctx->method->encryptBlock(ctx->key, in, out, len);
132 if (ret != CRYPT_SUCCESS) {
133 BSL_ERR_PUSH_ERROR(ret);
134 return ret;
135 }
136 Poly1305Update(&(ctx->polyCtx), out, len);
137 ctx->cipherTextLen += (uint64_t)len;
138 return CRYPT_SUCCESS;
139 }
140
MODES_CHACHA20POLY1305_Decrypt(MODES_CipherChaChaPolyCtx * ctx,const uint8_t * in,uint8_t * out,uint32_t len)141 int32_t MODES_CHACHA20POLY1305_Decrypt(MODES_CipherChaChaPolyCtx *ctx, const uint8_t *in, uint8_t *out, uint32_t len)
142 {
143 if (ctx == NULL || in == NULL || out == NULL || len == 0) {
144 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
145 return CRYPT_NULL_INPUT;
146 }
147 Poly1305Update(&(ctx->polyCtx), in, len);
148 ctx->cipherTextLen += (uint64_t)len;
149 int32_t ret = ctx->method->decryptBlock(ctx->key, in, out, len);
150 if (ret != CRYPT_SUCCESS) {
151 BSL_ERR_PUSH_ERROR(ret);
152 }
153 return ret;
154 }
155
CipherTextPad(MODES_CipherChaChaPolyCtx * ctx)156 static void CipherTextPad(MODES_CipherChaChaPolyCtx *ctx)
157 {
158 /**
159 * The ciphertext
160 * padding2 -- the padding is up to 15 zero bytes, and it brings
161 * the total length so far to an integral multiple of 16. If the
162 * length of the ciphertext was already an integral multiple of 16
163 * bytes, this field is zero-length.
164 */
165 Poly1305Ctx *polyCtx = &(ctx->polyCtx);
166 uint32_t len = polyCtx->lastLen;
167 if (len != 0) {
168 const uint8_t pad2[POLY1305_BLOCKSIZE] = {0};
169 Poly1305Update(polyCtx, pad2, POLY1305_BLOCKSIZE - len);
170 }
171
172 uint8_t pad[POLY1305_BLOCKSIZE];
173 /**
174 * The length of the additional data in octets (as a 64-bit
175 * little-endian integer).
176 */
177 PUT_UINT64_LE(ctx->aadLen, pad, 0); // The first eight bytes are padded with the length of the AAD.
178 /**
179 * The length of the ciphertext in octets (as a 64-bit littleendian
180 * integer).
181 */
182 PUT_UINT64_LE(ctx->cipherTextLen, pad, 8); // The last 8 bytes are padded the length of the ciphertext.
183 Poly1305Update(polyCtx, pad, POLY1305_BLOCKSIZE);
184 }
185
GetTag(MODES_CipherChaChaPolyCtx * ctx,uint8_t * val,uint32_t len)186 static int32_t GetTag(MODES_CipherChaChaPolyCtx *ctx, uint8_t *val, uint32_t len)
187 {
188 if (val == NULL) {
189 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
190 return CRYPT_NULL_INPUT;
191 }
192 if (len != POLY1305_TAGSIZE) {
193 BSL_ERR_PUSH_ERROR(CRYPT_MODES_TAGLEN_ERROR);
194 return CRYPT_MODES_TAGLEN_ERROR;
195 }
196 CipherTextPad(ctx);
197 Poly1305Final(&(ctx->polyCtx), val);
198 return CRYPT_SUCCESS;
199 }
200
SetIv(MODES_CipherChaChaPolyCtx * ctx,const uint8_t * iv,uint32_t ivLen)201 static int32_t SetIv(MODES_CipherChaChaPolyCtx *ctx, const uint8_t *iv, uint32_t ivLen)
202 {
203 /**
204 * RFC_7539-2.6
205 * ChaCha20 as specified here requires a 96-bit nonce.
206 * So if the provided nonce is only 64-bit, then the first 32
207 * bits of the nonce will be set to a constant number. This will
208 * usually be zero, but for protocols with multiple senders it may be
209 * different for each sender, but should be the same for all
210 * invocations of the function with the same key by a particular
211 * sender.
212 */
213 if (iv == NULL) {
214 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
215 return CRYPT_NULL_INPUT;
216 }
217 // 96 bits or 64 bits, that is, 12 bytes or 8 bytes.
218 if (ivLen != 12 && ivLen != 8) {
219 BSL_ERR_PUSH_ERROR(CRYPT_MODES_IVLEN_ERROR);
220 return CRYPT_MODES_IVLEN_ERROR;
221 }
222 int32_t ret;
223 uint8_t block[POLY1305_KEYSIZE] = { 0 };
224 if (ivLen == 8) { // If the length of the IV is 8, 0 data must be padded before.
225 uint8_t tmpBuff[12] = { 0 };
226 (void)memcpy_s(tmpBuff + 4, sizeof(tmpBuff) - 4, iv, ivLen); // // 4 bytes 0 data must be padded before.
227 ret = ctx->method->cipherCtrl(ctx->key, CRYPT_CTRL_SET_IV, tmpBuff, sizeof(tmpBuff));
228 // Clear sensitive data.
229 (void)BSL_SAL_CleanseData(tmpBuff, sizeof(tmpBuff));
230 } else {
231 ret = ctx->method->cipherCtrl(ctx->key, CRYPT_CTRL_SET_IV, (void *)(uintptr_t)iv, ivLen);
232 }
233 if (ret != CRYPT_SUCCESS) {
234 BSL_ERR_PUSH_ERROR(ret);
235 return ret;
236 }
237 /**
238 * RFC_7539-2.6
239 * The block counter is set to zero
240 */
241 uint8_t initCount[4] = { 0 };
242 ret = ctx->method->cipherCtrl(ctx->key, CRYPT_CTRL_SET_COUNT, initCount, sizeof(initCount));
243 if (ret != CRYPT_SUCCESS) {
244 BSL_ERR_PUSH_ERROR(ret);
245 return ret;
246 }
247 ret = ctx->method->encryptBlock(ctx->key, block, block, POLY1305_KEYSIZE);
248 if (ret != CRYPT_SUCCESS) {
249 BSL_ERR_PUSH_ERROR(ret);
250 return ret;
251 }
252 Poly1305SetKey(&(ctx->polyCtx), block);
253 /**
254 * RFC_7539-2.8
255 * the ChaCha20 encryption function is called to encrypt the
256 * plaintext, using the same key and nonce, and with the initial
257 * counter set to 1
258 */
259 initCount[0] = 0x01;
260 ret = ctx->method->cipherCtrl(ctx->key, CRYPT_CTRL_SET_COUNT, initCount, sizeof(initCount)); // 4bytes count
261 if (ret != CRYPT_SUCCESS) {
262 BSL_ERR_PUSH_ERROR(ret);
263 }
264 // Information that needs to be reset.
265 ctx->aadLen = 0;
266 ctx->cipherTextLen = 0;
267 return ret;
268 }
269
270 // Set the AAD information. The AAD information can be set only once.
SetAad(MODES_CipherChaChaPolyCtx * ctx,const uint8_t * aad,uint32_t aadLen)271 static int32_t SetAad(MODES_CipherChaChaPolyCtx *ctx, const uint8_t *aad, uint32_t aadLen)
272 {
273 /**
274 * RFC_7539-2.8
275 * The AAD
276 * padding1 -- the padding is up to 15 zero bytes, and it brings
277 * the total length so far to an integral multiple of 16. If the
278 * length of the AAD was already an integral multiple of 16 bytes,
279 * this field is zero-length.
280 */
281 if (ctx->aadLen != 0 || ctx->cipherTextLen != 0) { // aad is set
282 BSL_ERR_PUSH_ERROR(CRYPT_MODES_AAD_REPEAT_SET_ERROR);
283 return CRYPT_MODES_AAD_REPEAT_SET_ERROR;
284 }
285 if (aadLen == 0) {
286 return CRYPT_SUCCESS;
287 }
288 if (aad == NULL) {
289 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
290 return CRYPT_NULL_INPUT;
291 }
292 const uint8_t pad[16] = { 0 };
293 ctx->aadLen = aadLen;
294 Poly1305Update(&(ctx->polyCtx), aad, aadLen);
295 uint32_t padLen = (16 - aadLen % 16) % 16;
296 Poly1305Update(&(ctx->polyCtx), pad, padLen);
297 return CRYPT_SUCCESS;
298 }
299
MODES_CHACHA20POLY1305_SetEncryptKey(MODES_CipherChaChaPolyCtx * ctx,const uint8_t * key,uint32_t len)300 int32_t MODES_CHACHA20POLY1305_SetEncryptKey(MODES_CipherChaChaPolyCtx *ctx, const uint8_t *key, uint32_t len)
301 {
302 if (ctx == NULL) {
303 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
304 return CRYPT_NULL_INPUT;
305 }
306 return ctx->method->setEncryptKey(ctx->key, key, len);
307 }
MODES_CHACHA20POLY1305_SetDecryptKey(MODES_CipherChaChaPolyCtx * ctx,const uint8_t * key,uint32_t len)308 int32_t MODES_CHACHA20POLY1305_SetDecryptKey(MODES_CipherChaChaPolyCtx *ctx, const uint8_t *key, uint32_t len)
309 {
310 if (ctx == NULL) {
311 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
312 return CRYPT_NULL_INPUT;
313 }
314 return ctx->method->setDecryptKey(ctx->key, key, len);
315 }
MODES_CHACHA20POLY1305_Ctrl(MODES_CHACHAPOLY_Ctx * modeCtx,int32_t opt,void * val,uint32_t len)316 int32_t MODES_CHACHA20POLY1305_Ctrl(MODES_CHACHAPOLY_Ctx *modeCtx, int32_t opt, void *val, uint32_t len)
317 {
318 if (modeCtx == NULL) {
319 BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);
320 return CRYPT_INVALID_ARG;
321 }
322
323 switch (opt) {
324 case CRYPT_CTRL_REINIT_STATUS:
325 return SetIv(&modeCtx->chachaCtx, val, len);
326 case CRYPT_CTRL_GET_TAG:
327 return GetTag(&modeCtx->chachaCtx, val, len);
328 case CRYPT_CTRL_SET_AAD:
329 return SetAad(&modeCtx->chachaCtx, val, len);
330 case CRYPT_CTRL_GET_BLOCKSIZE:
331 if (val == NULL || len != sizeof(uint32_t)) {
332 return CRYPT_INVALID_ARG;
333 }
334 *(int32_t *)val = 1;
335 return CRYPT_SUCCESS;
336 default:
337 if (modeCtx->chachaCtx.method == NULL ||
338 modeCtx->chachaCtx.method->cipherCtrl == NULL) {
339 BSL_ERR_PUSH_ERROR(CRYPT_MODES_CTRL_TYPE_ERROR);
340 return CRYPT_MODES_CTRL_TYPE_ERROR;
341 }
342 return modeCtx->chachaCtx.method->cipherCtrl(modeCtx->chachaCtx.key, opt, val, len);
343 }
344 }
345
MODES_CHACHA20POLY1305_NewCtx(int32_t algId)346 MODES_CHACHAPOLY_Ctx *MODES_CHACHA20POLY1305_NewCtx(int32_t algId)
347 {
348 const EAL_SymMethod *method = EAL_GetSymMethod(algId);
349 if (method == NULL) {
350 BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);
351 return NULL;
352 }
353 MODES_CHACHAPOLY_Ctx *ctx = BSL_SAL_Calloc(1, sizeof(MODES_CHACHAPOLY_Ctx));
354 if (ctx == NULL) {
355 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
356 return ctx;
357 }
358 ctx->algId = algId;
359
360 ctx->chachaCtx.key = BSL_SAL_Calloc(1, method->ctxSize);
361 if (ctx->chachaCtx.key == NULL) {
362 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
363 BSL_SAL_Free(ctx);
364 return NULL;
365 }
366
367 ctx->chachaCtx.method = method;
368 return ctx;
369 }
370
MODES_CHACHA20POLY1305_InitCtx(MODES_CHACHAPOLY_Ctx * modeCtx,const uint8_t * key,uint32_t keyLen,const uint8_t * iv,uint32_t ivLen,void * param,bool enc)371 int32_t MODES_CHACHA20POLY1305_InitCtx(MODES_CHACHAPOLY_Ctx *modeCtx, const uint8_t *key, uint32_t keyLen,
372 const uint8_t *iv, uint32_t ivLen, void *param, bool enc)
373 {
374 (void)param;
375 if (modeCtx == NULL) {
376 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
377 return CRYPT_NULL_INPUT;
378 }
379 int32_t ret = enc ? modeCtx->chachaCtx.method->setEncryptKey(modeCtx->chachaCtx.key, key, keyLen) :
380 modeCtx->chachaCtx.method->setDecryptKey(modeCtx->chachaCtx.key, key, keyLen);
381 if (ret != CRYPT_SUCCESS) {
382 BSL_ERR_PUSH_ERROR(ret);
383 return ret;
384 }
385 ret = SetIv(&modeCtx->chachaCtx, iv, ivLen);
386 if (ret != CRYPT_SUCCESS) {
387 modeCtx->chachaCtx.method->cipherDeInitCtx(modeCtx->chachaCtx.key);
388 BSL_ERR_PUSH_ERROR(ret);
389 return ret;
390 }
391 modeCtx->enc = enc;
392 return ret;
393 }
394
MODES_CHACHA20POLY1305_Update(MODES_CHACHAPOLY_Ctx * modeCtx,const uint8_t * in,uint32_t inLen,uint8_t * out,uint32_t * outLen)395 int32_t MODES_CHACHA20POLY1305_Update(MODES_CHACHAPOLY_Ctx *modeCtx, const uint8_t *in, uint32_t inLen,
396 uint8_t *out, uint32_t *outLen)
397 {
398 if (modeCtx == NULL) {
399 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
400 return CRYPT_NULL_INPUT;
401 }
402 return MODES_CipherStreamProcess(modeCtx->enc ? MODES_CHACHA20POLY1305_Encrypt : MODES_CHACHA20POLY1305_Decrypt,
403 &modeCtx->chachaCtx, in, inLen, out, outLen);
404 }
405
MODES_CHACHA20POLY1305_Final(MODES_CHACHAPOLY_Ctx * modeCtx,uint8_t * out,uint32_t * outLen)406 int32_t MODES_CHACHA20POLY1305_Final(MODES_CHACHAPOLY_Ctx *modeCtx, uint8_t *out, uint32_t *outLen)
407 {
408 (void) modeCtx;
409 (void) out;
410 (void) outLen;
411 return CRYPT_EAL_CIPHER_FINAL_WITH_AEAD_ERROR;
412 }
413
MODES_CHACHA20POLY1305_DeInitCtx(MODES_CHACHAPOLY_Ctx * modeCtx)414 int32_t MODES_CHACHA20POLY1305_DeInitCtx(MODES_CHACHAPOLY_Ctx *modeCtx)
415 {
416 if (modeCtx == NULL) {
417 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
418 return CRYPT_NULL_INPUT;
419 }
420
421 modeCtx->chachaCtx.method->cipherDeInitCtx(modeCtx->chachaCtx.key);
422 BSL_SAL_CleanseData((void *)(&(modeCtx->chachaCtx.polyCtx)), sizeof(Poly1305Ctx));
423 modeCtx->chachaCtx.aadLen = 0;
424 modeCtx->chachaCtx.cipherTextLen = 0;
425 Poly1305CleanRegister();
426 return CRYPT_SUCCESS;
427 }
428
MODES_CHACHA20POLY1305_FreeCtx(MODES_CHACHAPOLY_Ctx * modeCtx)429 void MODES_CHACHA20POLY1305_FreeCtx(MODES_CHACHAPOLY_Ctx *modeCtx)
430 {
431 if (modeCtx == NULL) {
432 return;
433 }
434
435 modeCtx->chachaCtx.method->cipherDeInitCtx(modeCtx->chachaCtx.key);
436 BSL_SAL_FREE(modeCtx->chachaCtx.key);
437 BSL_SAL_ClearFree(modeCtx, sizeof(MODES_CHACHAPOLY_Ctx));
438 }
439
440 #endif