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_MD5
18
19 #include "securec.h"
20 #include "bsl_err_internal.h"
21 #include "crypt_errno.h"
22 #include "crypt_utils.h"
23 #include "md5_core.h"
24 #include "crypt_md5.h"
25 #include "bsl_sal.h"
26 #include "crypt_types.h"
27
28 #ifdef __cplusplus
29 extern "C" {
30 #endif /* __cpluscplus */
31
32 #define CRYPT_MD5_DIGESTSIZE 16
33 #define CRYPT_MD5_BLOCKSIZE 64
34
35 /* md5 ctx */
36 struct CryptMdCtx {
37 uint32_t h[CRYPT_MD5_DIGESTSIZE / sizeof(uint32_t)]; /* store the intermediate data of the hash value */
38 uint8_t block[CRYPT_MD5_BLOCKSIZE]; /* store the remaining data of less than one block */
39 uint32_t hNum, lNum; /* input data counter, maximum value 2 ^ 64 bits */
40 /* Number of remaining bytes in 'block' arrary that are stored less than one block */
41 uint32_t num;
42 };
43
CRYPT_MD5_NewCtx(void)44 CRYPT_MD5_Ctx *CRYPT_MD5_NewCtx(void)
45 {
46 return BSL_SAL_Calloc(1, sizeof(CRYPT_MD5_Ctx));
47 }
48
CRYPT_MD5_FreeCtx(CRYPT_MD5_Ctx * ctx)49 void CRYPT_MD5_FreeCtx(CRYPT_MD5_Ctx *ctx)
50 {
51 CRYPT_MD5_Ctx *mdCtx = ctx;
52 if (mdCtx == NULL) {
53 return;
54 }
55 BSL_SAL_ClearFree(ctx, sizeof(CRYPT_MD5_Ctx));
56 }
57
CRYPT_MD5_Init(CRYPT_MD5_Ctx * ctx,BSL_Param * param)58 int32_t CRYPT_MD5_Init(CRYPT_MD5_Ctx *ctx, BSL_Param *param)
59 {
60 if (ctx == NULL) {
61 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
62 return CRYPT_NULL_INPUT;
63 }
64 (void) param;
65 (void)memset_s(ctx, sizeof(CRYPT_MD5_Ctx), 0, sizeof(CRYPT_MD5_Ctx));
66 /* Set the initial values of A, B, C, and D according to step 3 in section 3.3 of RFC1321. */
67 ctx->h[0] = 0x67452301;
68 ctx->h[1] = 0xefcdab89;
69 ctx->h[2] = 0x98badcfe;
70 ctx->h[3] = 0x10325476;
71 return CRYPT_SUCCESS;
72 }
73
CRYPT_MD5_Deinit(CRYPT_MD5_Ctx * ctx)74 void CRYPT_MD5_Deinit(CRYPT_MD5_Ctx *ctx)
75 {
76 if (ctx == NULL) {
77 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
78 return;
79 }
80 (void)memset_s(ctx, sizeof(CRYPT_MD5_Ctx), 0, sizeof(CRYPT_MD5_Ctx));
81 }
82
IsInputOverflow(CRYPT_MD5_Ctx * ctx,uint32_t nbytes)83 static uint32_t IsInputOverflow(CRYPT_MD5_Ctx *ctx, uint32_t nbytes)
84 {
85 uint32_t cnt0 = ctx->lNum + (nbytes << SHIFTS_PER_BYTE);
86 if (cnt0 < ctx->lNum) {
87 if (++ctx->hNum == 0) {
88 BSL_ERR_PUSH_ERROR(CRYPT_MD5_INPUT_OVERFLOW);
89 return CRYPT_MD5_INPUT_OVERFLOW;
90 }
91 }
92 uint32_t cnt1 = ctx->hNum + (uint32_t)(nbytes >> (BITSIZE(uint32_t) - SHIFTS_PER_BYTE));
93 if (cnt1 < ctx->hNum) {
94 BSL_ERR_PUSH_ERROR(CRYPT_MD5_INPUT_OVERFLOW);
95 return CRYPT_MD5_INPUT_OVERFLOW;
96 }
97 ctx->hNum = cnt1;
98 ctx->lNum = cnt0;
99 return CRYPT_SUCCESS;
100 }
101
IsUpdateParamValid(CRYPT_MD5_Ctx * ctx,const uint8_t * in,uint32_t len)102 static int32_t IsUpdateParamValid(CRYPT_MD5_Ctx *ctx, const uint8_t *in, uint32_t len)
103 {
104 if ((ctx == NULL) || (in == NULL && len != 0)) {
105 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
106 return CRYPT_NULL_INPUT;
107 }
108
109 if (IsInputOverflow(ctx, len) != CRYPT_SUCCESS) {
110 BSL_ERR_PUSH_ERROR(CRYPT_MD5_INPUT_OVERFLOW);
111 return CRYPT_MD5_INPUT_OVERFLOW;
112 }
113
114 return CRYPT_SUCCESS;
115 }
116
CRYPT_MD5_Update(CRYPT_MD5_Ctx * ctx,const uint8_t * in,uint32_t len)117 int32_t CRYPT_MD5_Update(CRYPT_MD5_Ctx *ctx, const uint8_t *in, uint32_t len)
118 {
119 int32_t ret = IsUpdateParamValid(ctx, in, len);
120 if (ret != CRYPT_SUCCESS) {
121 BSL_ERR_PUSH_ERROR(ret);
122 return ret;
123 }
124
125 if (len == 0) {
126 return CRYPT_SUCCESS;
127 }
128
129 const uint8_t *data = in;
130 uint32_t dataLen = len;
131 uint32_t left = CRYPT_MD5_BLOCKSIZE - ctx->num;
132
133 if (ctx->num != 0) {
134 if (dataLen < left) {
135 (void)memcpy_s(ctx->block + ctx->num, left, data, dataLen);
136 ctx->num += dataLen;
137 return CRYPT_SUCCESS;
138 }
139 // When the external input data is greater than the remaining space of the block,
140 // copy the data which is the same length as the remaining space.
141 (void)memcpy_s(ctx->block + ctx->num, left, data, left);
142 MD5_Compress(ctx->h, ctx->block, 1);
143 dataLen -= left;
144 data += left;
145 ctx->num = 0;
146 }
147
148 uint32_t blockCnt = dataLen / CRYPT_MD5_BLOCKSIZE;
149 if (blockCnt > 0) {
150 MD5_Compress(ctx->h, data, blockCnt);
151 blockCnt *= CRYPT_MD5_BLOCKSIZE;
152 data += blockCnt;
153 dataLen -= blockCnt;
154 }
155
156 if (dataLen != 0) {
157 // Copy the remaining data to the cache array.
158 (void)memcpy_s(ctx->block, CRYPT_MD5_BLOCKSIZE, data, dataLen);
159 ctx->num = dataLen;
160 }
161
162 return CRYPT_SUCCESS;
163 }
164
IsFinalParamValid(const CRYPT_MD5_Ctx * ctx,const uint8_t * out,const uint32_t * outLen)165 static int32_t IsFinalParamValid(const CRYPT_MD5_Ctx *ctx, const uint8_t *out, const uint32_t *outLen)
166 {
167 if ((ctx == NULL) || (out == NULL) || (outLen == NULL)) {
168 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
169 return CRYPT_NULL_INPUT;
170 }
171
172 if (*outLen < CRYPT_MD5_DIGESTSIZE) {
173 BSL_ERR_PUSH_ERROR(CRYPT_MD5_OUT_BUFF_LEN_NOT_ENOUGH);
174 return CRYPT_MD5_OUT_BUFF_LEN_NOT_ENOUGH;
175 }
176
177 return CRYPT_SUCCESS;
178 }
179
180
CRYPT_MD5_Final(CRYPT_MD5_Ctx * ctx,uint8_t * out,uint32_t * outLen)181 int32_t CRYPT_MD5_Final(CRYPT_MD5_Ctx *ctx, uint8_t *out, uint32_t *outLen)
182 {
183 int32_t ret = IsFinalParamValid(ctx, out, outLen);
184 if (ret != CRYPT_SUCCESS) {
185 BSL_ERR_PUSH_ERROR(ret);
186 return ret;
187 }
188
189 ctx->block[ctx->num++] = 0x80; /* 0x80 indicates that '1' is appended to the end of a message. */
190 uint8_t *block = ctx->block;
191 uint32_t num = ctx->num;
192 uint32_t left = CRYPT_MD5_BLOCKSIZE - num;
193 if (left < 8) { /* Less than 8 bytes, insufficient for storing data of the accumulated data length(lNum&hNum). */
194 (void)memset_s(block + num, left, 0, left);
195 MD5_Compress(ctx->h, ctx->block, 1);
196 num = 0;
197 left = CRYPT_MD5_BLOCKSIZE;
198 }
199 (void)memset_s(block + num, left - 8, 0, left - 8); /* 8 byte is used to store data of accumulated data length. */
200 block += CRYPT_MD5_BLOCKSIZE - 8; /* 8 byte is used to store data of the accumulated data length(lNum&hNum). */
201 PUT_UINT32_LE(ctx->lNum, block, 0);
202 block += sizeof(uint32_t);
203 PUT_UINT32_LE(ctx->hNum, block, 0);
204 MD5_Compress(ctx->h, ctx->block, 1);
205 ctx->num = 0;
206
207 PUT_UINT32_LE(ctx->h[0], out, 0);
208 PUT_UINT32_LE(ctx->h[1], out, 4);
209 PUT_UINT32_LE(ctx->h[2], out, 8);
210 PUT_UINT32_LE(ctx->h[3], out, 12);
211 *outLen = CRYPT_MD5_DIGESTSIZE;
212
213 return CRYPT_SUCCESS;
214 }
215
CRYPT_MD5_CopyCtx(CRYPT_MD5_Ctx * dst,const CRYPT_MD5_Ctx * src)216 int32_t CRYPT_MD5_CopyCtx(CRYPT_MD5_Ctx *dst, const CRYPT_MD5_Ctx *src)
217 {
218 if (dst == NULL || src == NULL) {
219 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
220 return CRYPT_NULL_INPUT;
221 }
222
223 (void)memcpy_s(dst, sizeof(CRYPT_MD5_Ctx), src, sizeof(CRYPT_MD5_Ctx));
224 return CRYPT_SUCCESS;
225 }
226
CRYPT_MD5_DupCtx(const CRYPT_MD5_Ctx * src)227 CRYPT_MD5_Ctx *CRYPT_MD5_DupCtx(const CRYPT_MD5_Ctx *src)
228 {
229 if (src == NULL) {
230 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
231 return NULL;
232 }
233 CRYPT_MD5_Ctx *newCtx = CRYPT_MD5_NewCtx();
234 if (newCtx == NULL) {
235 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
236 return NULL;
237 }
238 (void)memcpy_s(newCtx, sizeof(CRYPT_MD5_Ctx), src, sizeof(CRYPT_MD5_Ctx));
239 return newCtx;
240 }
241
242 #ifdef __cplusplus
243 }
244 #endif /* __cpluscplus */
245
246 #endif // HITLS_CRYPTO_MD5
247