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