• 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_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