• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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