• 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_AES) && defined(HITLS_CRYPTO_GCM)
18 
19 #include "crypt_aes.h"
20 #include "asm_aes_gcm.h"
21 #include "modes_local.h"
22 #include "crypt_utils.h"
23 #include "crypt_errno.h"
24 #include "crypt_modes_gcm.h"
25 
AES_GCM_EncryptBlock(MODES_CipherGCMCtx * ctx,const uint8_t * in,uint8_t * out,uint32_t len)26 int32_t AES_GCM_EncryptBlock(MODES_CipherGCMCtx *ctx, const uint8_t *in, uint8_t *out, uint32_t len)
27 {
28     if (ctx->ciphCtx == NULL) {
29         return CRYPT_NULL_INPUT;
30     }
31     int32_t ret = CryptLenCheckAndRefresh(ctx, len);
32     if (ret != CRYPT_SUCCESS) {
33         return ret;
34     }
35     uint32_t lastLen = MODES_GCM_LastHandle(ctx, in, out, len, true);
36     // Data processing is complete. Exit.
37     if (lastLen == len) {
38         return CRYPT_SUCCESS;
39     }
40     uint32_t clen = len - lastLen;
41     if (clen >= 64) { // If the value is greater than 64, the logic for processing large blocks is used.
42         // invoke the assembly API
43         uint32_t finishedLen = AES_GCM_EncryptBlockAsm(ctx, in + lastLen, out + lastLen, clen, ctx->ciphCtx);
44         lastLen += finishedLen; // add the processed length
45         clen -= finishedLen; // subtract the processed length
46     }
47     if (clen >= 16) { // Remaining 16, use small block processing logic
48         AES_GCM_Encrypt16BlockAsm(ctx, in + lastLen, out + lastLen, clen, ctx->ciphCtx); // call the assembly API
49         lastLen += clen & 0xfffffff0;
50         clen = clen & 0x0f; // take the remainder of 16
51     }
52     AES_GCM_ClearAsm(); // clear the Neon register
53     if (clen > 0) { // tail processing
54         uint32_t ctr = GET_UINT32_BE(ctx->iv, 12);
55         ret = ctx->ciphMeth->encryptBlock(ctx->ciphCtx, ctx->iv, ctx->last, GCM_BLOCKSIZE);
56         if (ret != CRYPT_SUCCESS) {
57             return ret;
58         }
59         uint32_t i;
60         // encryption
61         const uint8_t *cin = (const uint8_t *)(in + lastLen);
62         uint8_t *cout = out + lastLen;
63         for (i = 0; i < clen; i++) {
64             cout[i] = cin[i] ^ ctx->last[i];
65             ctx->remCt[i] = cout[i];
66         }
67 
68         ctr++;
69         PUT_UINT32_BE(ctr, ctx->iv, 12); // offset of 12 bytes, the last four bytes are used
70         ctx->lastLen = GCM_BLOCKSIZE - clen;
71     }
72     return CRYPT_SUCCESS;
73 }
74 
AES_GCM_DecryptBlock(MODES_CipherGCMCtx * ctx,const uint8_t * in,uint8_t * out,uint32_t len)75 int32_t AES_GCM_DecryptBlock(MODES_CipherGCMCtx *ctx, const uint8_t *in, uint8_t *out, uint32_t len)
76 {
77     if (ctx->ciphCtx == NULL) {
78         return CRYPT_NULL_INPUT;
79     }
80     int32_t ret = CryptLenCheckAndRefresh(ctx, len);
81     if (ret != CRYPT_SUCCESS) {
82         return ret;
83     }
84     uint32_t lastLen = MODES_GCM_LastHandle(ctx, in, out, len, false);
85     // Data processing is complete. Exit.
86     if (lastLen == len) {
87         return CRYPT_SUCCESS;
88     }
89     uint32_t clen = len - lastLen;
90     if (clen >= 64) { // If the value is greater than 64, the logic for processing large blocks is used.
91         // invoke the assembly API
92         uint32_t finishedLen = AES_GCM_DecryptBlockAsm(ctx, in + lastLen, out + lastLen, clen, ctx->ciphCtx);
93         lastLen += finishedLen; // add the processed length
94         clen -= finishedLen; // subtract the processed length
95     }
96     if (clen >= 16) { // Remaining 16, use small block processing logic
97         AES_GCM_Decrypt16BlockAsm(ctx, in + lastLen, out + lastLen, clen, ctx->ciphCtx); // call the assembly API
98         lastLen += clen & 0xfffffff0;
99         clen = clen & 0x0f; // take the remainder of 16
100     }
101     AES_GCM_ClearAsm(); // clear the Neon register
102     if (clen > 0) { // tail processing
103         uint32_t ctr = GET_UINT32_BE(ctx->iv, 12);
104         ret = ctx->ciphMeth->encryptBlock(ctx->ciphCtx, ctx->iv, ctx->last, GCM_BLOCKSIZE);
105         if (ret != CRYPT_SUCCESS) {
106             return ret;
107         }
108         uint32_t i;
109         // encryption
110         const uint8_t *cin = (const uint8_t *)(in + lastLen);
111         uint8_t *cout = out + lastLen;
112         for (i = 0; i < clen; i++) {
113             ctx->remCt[i] = cin[i];
114             cout[i] = cin[i] ^ ctx->last[i];
115         }
116         ctr++;
117         PUT_UINT32_BE(ctr, ctx->iv, 12); // offset of 12 bytes, the last four bytes are used
118         ctx->lastLen = GCM_BLOCKSIZE - clen;
119     }
120     return CRYPT_SUCCESS;
121 }
122 
AES_GCM_Update(MODES_GCM_Ctx * modeCtx,const uint8_t * in,uint32_t inLen,uint8_t * out,uint32_t * outLen)123 int32_t AES_GCM_Update(MODES_GCM_Ctx *modeCtx, const uint8_t *in, uint32_t inLen, uint8_t *out, uint32_t *outLen)
124 {
125     return MODES_CipherStreamProcess(modeCtx->enc ? AES_GCM_EncryptBlock : AES_GCM_DecryptBlock, &modeCtx->gcmCtx,
126         in, inLen, out, outLen);
127 }
128 
129 #endif