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 #ifdef HITLS_CRYPTO_SM2_CRYPT
18 #include <limits.h>
19 #include "securec.h"
20 #include "crypt_errno.h"
21 #include "crypt_types.h"
22 #include "crypt_utils.h"
23 #include "bsl_sal.h"
24 #include "bsl_err_internal.h"
25 #include "crypt_bn.h"
26 #include "crypt_ecc.h"
27 #include "crypt_ecc_pkey.h"
28 #include "crypt_local_types.h"
29 #include "sm2_local.h"
30 #include "crypt_sm2.h"
31 #include "crypt_encode_internal.h"
32
33 #define SM2_POINT_SINGLE_COORDINATE_LEN 32
34 #define SM2_POINT_COORDINATE_LEN 65
35
EncryptMemFree(ECC_Point * c1,ECC_Point * tmp,BN_BigNum * k,BN_BigNum * order,uint8_t * c2)36 static void EncryptMemFree(ECC_Point *c1, ECC_Point *tmp, BN_BigNum *k,
37 BN_BigNum *order, uint8_t *c2)
38 {
39 ECC_FreePoint(c1);
40 ECC_FreePoint(tmp);
41 BN_Destroy(k);
42 BN_Destroy(order);
43 BSL_SAL_FREE(c2);
44 }
45
ParaCheckAndCalculate(CRYPT_SM2_Ctx * ctx,ECC_Point * tmp,BN_BigNum * k)46 static int32_t ParaCheckAndCalculate(CRYPT_SM2_Ctx *ctx, ECC_Point *tmp, BN_BigNum *k)
47 {
48 int32_t ret;
49 // Check whether [h]PB is equal to infinity point.
50 GOTO_ERR_IF(ECC_PointCheck(ctx->pkey->pubkey), ret);
51 // Calculate [k] * PB
52 GOTO_ERR_IF(ECC_PointMul(ctx->pkey->para, tmp, k, ctx->pkey->pubkey), ret);
53 ERR:
54 return ret;
55 }
56
Sm3Hash(const EAL_MdMethod * hashMethod,const uint8_t * pbBuf,const uint8_t * data,uint32_t datalen,uint8_t * c3Buf,uint32_t * c3BufLen)57 static int32_t Sm3Hash(const EAL_MdMethod *hashMethod, const uint8_t *pbBuf, const uint8_t *data, uint32_t datalen,
58 uint8_t *c3Buf, uint32_t *c3BufLen)
59 {
60 int32_t ret;
61 void *mdCtx = hashMethod->newCtx();
62 if (mdCtx == NULL) {
63 ret = CRYPT_MEM_ALLOC_FAIL;
64 BSL_ERR_PUSH_ERROR(ret);
65 return ret;
66 }
67 GOTO_ERR_IF(hashMethod->init(mdCtx, NULL), ret);
68 GOTO_ERR_IF(hashMethod->update(mdCtx, pbBuf + 1,
69 SM2_POINT_SINGLE_COORDINATE_LEN), ret); // Horizontal coordinate x2 of PB
70 GOTO_ERR_IF(hashMethod->update(mdCtx, data, datalen), ret); // M
71 GOTO_ERR_IF(hashMethod->update(mdCtx, pbBuf + SM2_POINT_SINGLE_COORDINATE_LEN + 1,
72 SM2_POINT_SINGLE_COORDINATE_LEN), ret); // Vertical coordinate y2 of PB
73 // Calculated c3, in c3Buf
74 GOTO_ERR_IF(hashMethod->final(mdCtx, c3Buf, c3BufLen), ret);
75 ERR:
76 hashMethod->freeCtx(mdCtx);
77 return ret;
78 }
79
IsDataZero(const uint8_t * data,uint32_t datalen)80 static int32_t IsDataZero(const uint8_t *data, uint32_t datalen)
81 {
82 uint8_t check = 0;
83 for (uint32_t i = 0; i < datalen; i++) {
84 check |= data[i];
85 }
86 if (check == 0) {
87 BSL_ERR_PUSH_ERROR(CRYPT_SM2_DECRYPT_FAIL);
88 return CRYPT_SM2_DECRYPT_FAIL;
89 }
90 return CRYPT_SUCCESS;
91 }
92
MemAllocCheck(const BN_BigNum * k,const BN_BigNum * order,const ECC_Point * c1,const ECC_Point * tmp,const uint8_t * c2)93 static int32_t MemAllocCheck(const BN_BigNum *k, const BN_BigNum *order,
94 const ECC_Point *c1, const ECC_Point *tmp, const uint8_t *c2)
95 {
96 if (k == NULL || order == NULL || c1 == NULL || tmp == NULL || c2 == NULL) {
97 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
98 return CRYPT_MEM_ALLOC_FAIL;
99 }
100 return CRYPT_SUCCESS;
101 }
102
XorCalculate(uint8_t * c2,const uint8_t * data,uint32_t datalen)103 static void XorCalculate(uint8_t *c2, const uint8_t *data, uint32_t datalen)
104 {
105 uint32_t i;
106 for (i = 0; i < datalen; ++i) {
107 c2[i] ^= data[i];
108 }
109 return;
110 }
111
EncryptInputCheck(const CRYPT_SM2_Ctx * ctx,const uint8_t * data,uint32_t datalen,const uint8_t * out,const uint32_t * outlen)112 static int32_t EncryptInputCheck(const CRYPT_SM2_Ctx *ctx, const uint8_t *data, uint32_t datalen,
113 const uint8_t *out, const uint32_t *outlen)
114 {
115 // 0-length plaintext encryption is not supported.
116 if (ctx == NULL || data == NULL || datalen == 0 || out == NULL || outlen == NULL || *outlen == 0) {
117 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
118 return CRYPT_NULL_INPUT;
119 }
120 uint32_t encodeLen = 0;
121 int32_t ret = CRYPT_EAL_GetSm2EncryptDataEncodeLen(SM2_POINT_SINGLE_COORDINATE_LEN, SM2_POINT_SINGLE_COORDINATE_LEN,
122 SM3_MD_SIZE, datalen, &encodeLen);
123 if (ret != CRYPT_SUCCESS) {
124 BSL_ERR_PUSH_ERROR(ret);
125 return ret;
126 }
127 if (*outlen < encodeLen) {
128 BSL_ERR_PUSH_ERROR(CRYPT_SM2_BUFF_LEN_NOT_ENOUGH);
129 return CRYPT_SM2_BUFF_LEN_NOT_ENOUGH;
130 }
131 if (ctx->pkey == NULL) {
132 BSL_ERR_PUSH_ERROR(CRYPT_SM2_ERR_EMPTY_KEY);
133 return CRYPT_SM2_ERR_EMPTY_KEY;
134 }
135 if (ctx->pkey->pubkey == NULL) {
136 BSL_ERR_PUSH_ERROR(CRYPT_SM2_NO_PUBKEY);
137 return CRYPT_SM2_NO_PUBKEY;
138 }
139 return CRYPT_SUCCESS;
140 }
141
CRYPT_SM2_Encrypt(CRYPT_SM2_Ctx * ctx,const uint8_t * data,uint32_t datalen,uint8_t * out,uint32_t * outlen)142 int32_t CRYPT_SM2_Encrypt(CRYPT_SM2_Ctx *ctx, const uint8_t *data, uint32_t datalen, uint8_t *out, uint32_t *outlen)
143 {
144 int32_t ret = EncryptInputCheck(ctx, data, datalen, out, outlen);
145 if (ret != CRYPT_SUCCESS) {
146 return ret;
147 }
148 uint32_t i;
149 BN_BigNum *k = BN_Create(CRYPT_SM2_GetBits(ctx));
150 BN_BigNum *order = ECC_GetParaN(ctx->pkey->para);
151 ECC_Point *c1 = ECC_NewPoint(ctx->pkey->para);
152 ECC_Point *tmp = ECC_NewPoint(ctx->pkey->para);
153 uint32_t buflen = SM2_POINT_COORDINATE_LEN;
154 uint8_t c1Buf[SM2_POINT_COORDINATE_LEN];
155 uint8_t tmpBuf[SM2_POINT_COORDINATE_LEN];
156 uint8_t *c2 = BSL_SAL_Malloc(datalen);
157 uint8_t c3Buf[SM3_MD_SIZE];
158 uint32_t c3BufLen = SM3_MD_SIZE;
159 CRYPT_SM2_EncryptData encData = {
160 // +1: Skip one byte for '04'
161 .x = c1Buf + 1, .xLen = SM2_POINT_SINGLE_COORDINATE_LEN,
162 .y = c1Buf + SM2_POINT_SINGLE_COORDINATE_LEN + 1, .yLen = SM2_POINT_SINGLE_COORDINATE_LEN,
163 .hash = c3Buf, .hashLen = c3BufLen,
164 .cipher = c2, .cipherLen = datalen,
165 };
166 GOTO_ERR_IF(MemAllocCheck(k, order, c1, tmp, c2), ret);
167 for (i = 0; i < CRYPT_ECC_TRY_MAX_CNT; i++) {
168 GOTO_ERR_IF(BN_RandRangeEx(ctx->pkey->libCtx, k, order), ret);
169 if (BN_IsZero(k)) {
170 continue;
171 }
172 // c1 = k * G
173 GOTO_ERR_IF(ECC_PointMul(ctx->pkey->para, c1, k, NULL), ret);
174 // Convert the point format into binary data stream and save the data stream in tmpbuf.
175 GOTO_ERR_IF(ECC_EncodePoint(ctx->pkey->para, c1, c1Buf, &buflen, CRYPT_POINT_UNCOMPRESSED), ret);
176 GOTO_ERR_IF(ParaCheckAndCalculate(ctx, tmp, k), ret);
177 GOTO_ERR_IF(ECC_EncodePoint(ctx->pkey->para, tmp, tmpBuf, &buflen, CRYPT_POINT_UNCOMPRESSED), ret);
178 // Calculate the kdf.
179 GOTO_ERR_IF(KdfGmt0032012(c2, &datalen, tmpBuf + 1, buflen - 1, ctx->hashMethod), ret);
180 if (IsDataZero(c2, datalen) == CRYPT_SUCCESS) {
181 break;
182 }
183 }
184 if (i == CRYPT_ECC_TRY_MAX_CNT) {
185 BSL_ERR_PUSH_ERROR(CRYPT_SM2_ERR_TRY_CNT);
186 ret = CRYPT_SM2_ERR_TRY_CNT;
187 goto ERR;
188 }
189 // Bitwise XOR
190 XorCalculate(c2, data, datalen);
191 // x2 || M || y2, calculate the hash value
192 GOTO_ERR_IF(Sm3Hash(ctx->hashMethod, tmpBuf, data, datalen, c3Buf, &c3BufLen), ret);
193
194 GOTO_ERR_IF(CRYPT_EAL_EncodeSm2EncryptData(&encData, out, outlen), ret);
195 ERR:
196 EncryptMemFree(c1, tmp, k, order, c2);
197 return ret;
198 }
199
IsUEqualToC3(const uint8_t * data,const uint8_t * sm3Buf,uint32_t sm3BufLen)200 static int32_t IsUEqualToC3(const uint8_t *data, const uint8_t *sm3Buf, uint32_t sm3BufLen)
201 {
202 uint8_t check = 0;
203 for (uint32_t i = 0; i < sm3BufLen; i++) {
204 check |= sm3Buf[i] ^ data[i + SM2_POINT_COORDINATE_LEN];
205 }
206 if (check != 0) {
207 BSL_ERR_PUSH_ERROR(CRYPT_SM2_DECRYPT_FAIL);
208 return CRYPT_SM2_DECRYPT_FAIL;
209 }
210 return CRYPT_SUCCESS;
211 }
212
DecryptInputCheck(const CRYPT_SM2_Ctx * ctx,const uint8_t * data,uint32_t datalen,const uint8_t * out,const uint32_t * outlen)213 static int32_t DecryptInputCheck(const CRYPT_SM2_Ctx *ctx, const uint8_t *data, uint32_t datalen,
214 const uint8_t *out, const uint32_t *outlen)
215 {
216 // 0-length plaintext decryption is not supported.
217 if (ctx == NULL || data == NULL || datalen == 0 || out == NULL || outlen == NULL || *outlen == 0) {
218 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
219 return CRYPT_NULL_INPUT;
220 }
221 if (ctx->pkey == NULL) {
222 BSL_ERR_PUSH_ERROR(CRYPT_SM2_ERR_EMPTY_KEY);
223 return CRYPT_SM2_ERR_EMPTY_KEY;
224 }
225 if (ctx->pkey->prvkey == NULL) {
226 BSL_ERR_PUSH_ERROR(CRYPT_SM2_NO_PRVKEY);
227 return CRYPT_SM2_NO_PRVKEY;
228 }
229 return CRYPT_SUCCESS;
230 }
231
DecodeEncryptData(const uint8_t * data,uint32_t datalen,uint8_t ** decode,const uint8_t ** cipher,uint32_t * cipherLen)232 static int32_t DecodeEncryptData(const uint8_t *data, uint32_t datalen, uint8_t **decode,
233 const uint8_t **cipher, uint32_t *cipherLen)
234 {
235 *decode = BSL_SAL_Calloc(1u, datalen);
236 if (*decode == NULL) {
237 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
238 return CRYPT_MEM_ALLOC_FAIL;
239 }
240 // Add uncompressed point identifier
241 (*decode)[0] = 0x04;
242 CRYPT_SM2_EncryptData encData = {
243 .x = *decode + 1, // Reserve one byte for '04'
244 .xLen = SM2_POINT_SINGLE_COORDINATE_LEN,
245 .y = *decode + SM2_POINT_SINGLE_COORDINATE_LEN + 1,
246 .yLen = SM2_POINT_SINGLE_COORDINATE_LEN,
247 .hash = *decode + SM2_POINT_COORDINATE_LEN,
248 .hashLen = SM3_MD_SIZE,
249 .cipher = *decode + SM2_POINT_COORDINATE_LEN + SM3_MD_SIZE,
250 .cipherLen = datalen - SM2_POINT_COORDINATE_LEN - SM3_MD_SIZE
251 };
252
253 int32_t ret = CRYPT_EAL_DecodeSm2EncryptData(data, datalen, &encData);
254 if (ret != CRYPT_SUCCESS) {
255 BSL_SAL_Free(*decode);
256 *decode = NULL;
257 BSL_ERR_PUSH_ERROR(ret);
258 return ret;
259 }
260
261 // Return cipher related information
262 *cipher = encData.cipher;
263 *cipherLen = encData.cipherLen;
264
265 return CRYPT_SUCCESS;
266 }
267
CRYPT_SM2_Decrypt(CRYPT_SM2_Ctx * ctx,const uint8_t * data,uint32_t datalen,uint8_t * out,uint32_t * outlen)268 int32_t CRYPT_SM2_Decrypt(CRYPT_SM2_Ctx *ctx, const uint8_t *data, uint32_t datalen, uint8_t *out, uint32_t *outlen)
269 {
270 // take out the c1
271 int32_t ret = DecryptInputCheck(ctx, data, datalen, out, outlen);
272 if (ret != CRYPT_SUCCESS) {
273 BSL_ERR_PUSH_ERROR(ret);
274 return ret;
275 }
276
277 uint8_t *decode = NULL;
278 const uint8_t *cipher = NULL;
279 uint32_t cipherLen = 0;
280 ret = DecodeEncryptData(data, datalen, &decode, &cipher, &cipherLen);
281 if (ret != CRYPT_SUCCESS) {
282 return ret;
283 }
284 if (*outlen < cipherLen) {
285 BSL_SAL_Free(decode);
286 BSL_ERR_PUSH_ERROR(CRYPT_SM2_BUFF_LEN_NOT_ENOUGH);
287 return CRYPT_SM2_BUFF_LEN_NOT_ENOUGH;
288 }
289
290 uint8_t sm3Buf[SM3_MD_SIZE];
291 uint32_t sm3BufLen = SM3_MD_SIZE;
292 uint32_t tmplen = SM2_POINT_COORDINATE_LEN;
293 uint8_t tmpBuf[SM2_POINT_COORDINATE_LEN];
294 ECC_Point *c1 = ECC_NewPoint(ctx->pkey->para);
295 ECC_Point *tmp = ECC_NewPoint(ctx->pkey->para);
296 uint8_t *t = BSL_SAL_Malloc(cipherLen);
297 if (c1 == NULL || tmp == NULL || t == NULL) {
298 ret = CRYPT_MEM_ALLOC_FAIL;
299 BSL_ERR_PUSH_ERROR(ret);
300 goto ERR;
301 }
302
303 GOTO_ERR_IF(ECC_DecodePoint(ctx->pkey->para, c1, decode, SM2_POINT_COORDINATE_LEN), ret);
304 // Calculate [dB]C1 = (x2, y2) and save it to the point tmp.
305 GOTO_ERR_IF(ECC_PointMul(ctx->pkey->para, tmp, ctx->pkey->prvkey, c1), ret);
306 // Extract x and y of the point tmp and save them to tmpbuf.
307 GOTO_ERR_IF(ECC_EncodePoint(ctx->pkey->para, tmp, tmpBuf, &tmplen, CRYPT_POINT_UNCOMPRESSED), ret);
308 // Calculate the kdf(x2 || y2, cipherLen).
309 GOTO_ERR_IF(KdfGmt0032012(t, &cipherLen, tmpBuf + 1, tmplen - 1, ctx->hashMethod), ret);
310 // Check whether t is all 0s. If yes, report an error and exit.
311 GOTO_ERR_IF(IsDataZero(t, cipherLen), ret);
312
313 // Calculate M' = C2 ^ t
314 // Bitwise XOR, and the result is still stored in t.
315 for (uint32_t i = 0; i < cipherLen; ++i) {
316 t[i] ^= cipher[i];
317 }
318 // Calculate hash(x2 || t || y2)
319 GOTO_ERR_IF(Sm3Hash(ctx->hashMethod, tmpBuf, t, cipherLen, sm3Buf, &sm3BufLen), ret);
320 // Check whether u is equal to c3.
321 GOTO_ERR_IF(IsUEqualToC3(decode, sm3Buf, sm3BufLen), ret);
322 // The verification is successful. M' is the last plaintext.
323 (void)memcpy_s(out, *outlen, t, cipherLen);
324 *outlen = cipherLen;
325
326 ERR:
327 BSL_SAL_FREE(decode);
328 ECC_FreePoint(c1);
329 ECC_FreePoint(tmp);
330 BSL_SAL_CleanseData((void*)t, cipherLen);
331 BSL_SAL_FREE(t);
332 return ret;
333 }
334 #endif // HITLS_CRYPTO_SM2_CRYPT
335