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_SM4) && defined(HITLS_CRYPTO_GCM)
18
19 #include "bsl_sal.h"
20 #include "bsl_err_internal.h"
21 #include "crypt_sm4.h"
22 #include "crypt_utils.h"
23 #include "crypt_errno.h"
24 #include "modes_local.h"
25 #include "crypt_modes_gcm.h"
26
MODES_SM4_GCM_SetKey(MODES_CipherGCMCtx * ctx,const uint8_t * key,uint32_t len)27 int32_t MODES_SM4_GCM_SetKey(MODES_CipherGCMCtx *ctx, const uint8_t *key, uint32_t len)
28 {
29 if (ctx == NULL) {
30 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
31 return CRYPT_NULL_INPUT;
32 }
33 uint8_t gcmKey[GCM_BLOCKSIZE] = { 0 };
34 int32_t ret = CRYPT_SM4_SetEncryptKey(ctx->ciphCtx, key, len);
35 if (ret != CRYPT_SUCCESS) {
36 BSL_ERR_PUSH_ERROR(ret);
37 return ret;
38 }
39 ret = ctx->ciphMeth->encryptBlock(ctx->ciphCtx, gcmKey, gcmKey, GCM_BLOCKSIZE);
40 if (ret != CRYPT_SUCCESS) {
41 BSL_ERR_PUSH_ERROR(ret);
42 return ret;
43 }
44 GcmTableGen4bit(gcmKey, ctx->hTable);
45 ctx->tagLen = 16; // The default tag length is 128 bits, that is, 16 bytes.
46 BSL_SAL_CleanseData(gcmKey, sizeof(gcmKey));
47 return CRYPT_SUCCESS;
48 }
49
GcmRemHandle(MODES_CipherGCMCtx * ctx,const uint8_t * in,uint8_t * out,uint32_t len,bool enc)50 static void GcmRemHandle(MODES_CipherGCMCtx *ctx, const uint8_t *in, uint8_t *out, uint32_t len, bool enc)
51 {
52 (void)ctx->ciphMeth->encryptBlock(ctx->ciphCtx, ctx->iv, ctx->last, GCM_BLOCKSIZE);
53 uint32_t i;
54 if (enc) {
55 for (i = 0; i < len; i++) {
56 out[i] = in[i] ^ ctx->last[i];
57 ctx->remCt[i] = out[i];
58 }
59 } else {
60 for (i = 0; i < len; i++) {
61 ctx->remCt[i] = in[i];
62 out[i] = in[i] ^ ctx->last[i];
63 }
64 }
65
66 uint32_t ctr = GET_UINT32_BE(ctx->iv, 12); // offset 12 bytes and obtain the last four bytes
67 ctr++;
68 PUT_UINT32_BE(ctr, ctx->iv, 12); // offset 12 bytes and obtain the last four bytes
69 ctx->lastLen = GCM_BLOCKSIZE - len;
70 }
71
MODES_SM4_GCM_EncryptBlock(MODES_CipherGCMCtx * ctx,const uint8_t * in,uint8_t * out,uint32_t len)72 int32_t MODES_SM4_GCM_EncryptBlock(MODES_CipherGCMCtx *ctx, const uint8_t *in, uint8_t *out, uint32_t len)
73 {
74 ctx->plaintextLen += len;
75 uint32_t lastLen = MODES_GCM_LastHandle(ctx, in, out, len, true);
76 // Data processing is complete. Exit.
77 if (lastLen == len) {
78 return CRYPT_SUCCESS;
79 }
80 const uint8_t *tmpIn = in + lastLen;
81 uint8_t *tmpOut = out + lastLen;
82 uint32_t clen = len - lastLen;
83 if (clen >= GCM_BLOCKSIZE) {
84 uint32_t calLen = clen & 0xfffffff0;
85 (void)CRYPT_SM4_CTR_Encrypt(ctx->ciphCtx, tmpIn, tmpOut, calLen / GCM_BLOCKSIZE, ctx->iv);
86 GcmHashMultiBlock(ctx->ghash, ctx->hTable, tmpOut, calLen);
87 clen -= calLen;
88 tmpIn += calLen;
89 tmpOut += calLen;
90 }
91 if (clen > 0) { // tail processing
92 GcmRemHandle(ctx, tmpIn, tmpOut, clen, true);
93 }
94 return CRYPT_SUCCESS;
95 }
96
MODES_SM4_GCM_DecryptBlock(MODES_CipherGCMCtx * ctx,const uint8_t * in,uint8_t * out,uint32_t len)97 int32_t MODES_SM4_GCM_DecryptBlock(MODES_CipherGCMCtx *ctx, const uint8_t *in, uint8_t *out, uint32_t len)
98 {
99 ctx->plaintextLen += len;
100 uint32_t lastLen = MODES_GCM_LastHandle(ctx, in, out, len, false);
101 // Data processing is complete. Exit.
102 if (lastLen == len) {
103 return CRYPT_SUCCESS;
104 }
105 const uint8_t *tmpIn = in + lastLen;
106 uint8_t *tmpOut = out + lastLen;
107 uint32_t clen = len - lastLen;
108 if (clen >= GCM_BLOCKSIZE) {
109 uint32_t calLen = clen & 0xfffffff0; // Obtains the length that is an integer multiple of 16 bytes.
110 GcmHashMultiBlock(ctx->ghash, ctx->hTable, tmpIn, calLen);
111 (void)CRYPT_SM4_CTR_Encrypt(ctx->ciphCtx, tmpIn, tmpOut, calLen / GCM_BLOCKSIZE, ctx->iv);
112 tmpIn += calLen;
113 tmpOut += calLen;
114 clen -= calLen;
115 }
116 if (clen > 0) { // tail processing
117 GcmRemHandle(ctx, tmpIn, tmpOut, clen, false);
118 }
119 return CRYPT_SUCCESS;
120 }
121
SM4_GCM_InitCtx(MODES_GCM_Ctx * modeCtx,const uint8_t * key,uint32_t keyLen,const uint8_t * iv,uint32_t ivLen,bool enc)122 int32_t SM4_GCM_InitCtx(MODES_GCM_Ctx *modeCtx, const uint8_t *key, uint32_t keyLen, const uint8_t *iv,
123 uint32_t ivLen, bool enc)
124 {
125 int32_t ret = MODES_SM4_GCM_SetKey(&modeCtx->gcmCtx, key, keyLen);
126 if (ret != CRYPT_SUCCESS) {
127 BSL_ERR_PUSH_ERROR(ret);
128 return ret;
129 }
130
131 ret = MODES_GCM_SetIv(&modeCtx->gcmCtx, iv, ivLen);
132 if (ret != CRYPT_SUCCESS) {
133 BSL_ERR_PUSH_ERROR(ret);
134 (void)MODES_GCM_DeInitCtx(modeCtx);
135 return ret;
136 }
137 modeCtx->enc = enc;
138 return ret;
139 }
140
SM4_GCM_Update(MODES_GCM_Ctx * modeCtx,const uint8_t * in,uint32_t inLen,uint8_t * out,uint32_t * outLen)141 int32_t SM4_GCM_Update(MODES_GCM_Ctx *modeCtx, const uint8_t *in, uint32_t inLen, uint8_t *out, uint32_t *outLen)
142 {
143 return MODES_CipherStreamProcess(modeCtx->enc ? MODES_SM4_GCM_EncryptBlock : MODES_SM4_GCM_DecryptBlock,
144 &modeCtx->gcmCtx, in, inLen, out, outLen);
145 }
146 #endif
147