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_CMAC
18
19 #include <stdlib.h>
20 #include "bsl_sal.h"
21 #include "crypt_errno.h"
22 #include "crypt_utils.h"
23 #include "bsl_err_internal.h"
24 #include "cipher_mac_common.h"
25 #include "crypt_cmac.h"
26 #include "eal_mac_local.h"
27
CRYPT_CMAC_NewCtx(CRYPT_MAC_AlgId id)28 CRYPT_CMAC_Ctx *CRYPT_CMAC_NewCtx(CRYPT_MAC_AlgId id)
29 {
30 int32_t ret;
31 EAL_MacMethLookup method = {0};
32 ret = EAL_MacFindMethod(id, &method);
33 if (ret != CRYPT_SUCCESS) {
34 return NULL;
35 }
36 CRYPT_CMAC_Ctx *ctx = BSL_SAL_Calloc(1, sizeof(CRYPT_CMAC_Ctx));
37 if (ctx == NULL) {
38 BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
39 return NULL;
40 }
41 ret = CipherMacInitCtx(ctx, method.ciph);
42 if (ret != CRYPT_SUCCESS) {
43 BSL_SAL_Free(ctx);
44 return NULL;
45 }
46 return ctx;
47 }
48
CRYPT_CMAC_Init(CRYPT_CMAC_Ctx * ctx,const uint8_t * key,uint32_t len,void * param)49 int32_t CRYPT_CMAC_Init(CRYPT_CMAC_Ctx *ctx, const uint8_t *key, uint32_t len, void *param)
50 {
51 (void)param;
52 return CipherMacInit((Cipher_MAC_Common_Ctx *)ctx, key, len);
53 }
54
CRYPT_CMAC_Update(CRYPT_CMAC_Ctx * ctx,const uint8_t * in,uint32_t len)55 int32_t CRYPT_CMAC_Update(CRYPT_CMAC_Ctx *ctx, const uint8_t *in, uint32_t len)
56 {
57 return CipherMacUpdate((Cipher_MAC_Common_Ctx *)ctx, in, len);
58 }
59
LeftShiftOneBit(const uint8_t * in,uint32_t len,uint8_t * out)60 static inline void LeftShiftOneBit(const uint8_t *in, uint32_t len, uint8_t *out)
61 {
62 uint32_t i = len - 1;
63
64 out[i] = (in[i] << 1) | 0;
65 do {
66 i--;
67 out[i] = (in[i] << 1) | (in[i + 1] >> 7); // 7 is used to obtain the most significant bit of the 8-bit data.
68 } while (i != 0);
69 }
70
CMAC_Final(CRYPT_CMAC_Ctx * ctx)71 static void CMAC_Final(CRYPT_CMAC_Ctx *ctx)
72 {
73 const uint8_t z[CIPHER_MAC_MAXBLOCKSIZE] = {0};
74 uint8_t rb;
75 uint8_t l[CIPHER_MAC_MAXBLOCKSIZE];
76 uint8_t k1[CIPHER_MAC_MAXBLOCKSIZE];
77 const EAL_SymMethod *method = ctx->method;
78 uint32_t blockSize = method->blockSize;
79 int32_t ret;
80
81 ret = method->encryptBlock(ctx->key, z, l, blockSize);
82 if (ret != CRYPT_SUCCESS) {
83 BSL_ERR_PUSH_ERROR(ret);
84 return;
85 }
86 LeftShiftOneBit(l, blockSize, k1);
87
88 if (blockSize == CIPHER_MAC_MAXBLOCKSIZE) {
89 rb = 0x87; /* When the AES algorithm is used and the blocksize is 128 bits, rb uses 0x87. */
90 } else {
91 rb = 0x1B; /* When the DES and TDES algorithms are used and blocksize is 64 bits, rb uses 0x1B. */
92 }
93 if ((l[0] & 0x80) != 0) {
94 k1[blockSize - 1] ^= rb;
95 }
96 uint32_t length = ctx->len;
97 if (length == blockSize) { // When the message length is an integer multiple of blockSize, use K1
98 DATA_XOR(ctx->left, k1, ctx->left, blockSize);
99 } else { // The message length is not an integer multiple of blockSize. Use K2 after padding.
100 /* padding */
101 ctx->left[length++] = 0x80; // 0x80 indicates that the first bit of the data is added with 1.
102 while (length < blockSize) {
103 ctx->left[length++] = 0;
104 }
105
106 uint8_t k2[CIPHER_MAC_MAXBLOCKSIZE];
107 LeftShiftOneBit(k1, blockSize, k2);
108 if ((k1[0] & 0x80) != 0) {
109 k2[blockSize - 1] ^= rb;
110 }
111 DATA_XOR(ctx->left, k2, ctx->left, blockSize);
112 ctx->len = blockSize;
113 }
114 }
115
CRYPT_CMAC_Final(CRYPT_CMAC_Ctx * ctx,uint8_t * out,uint32_t * len)116 int32_t CRYPT_CMAC_Final(CRYPT_CMAC_Ctx *ctx, uint8_t *out, uint32_t *len)
117 {
118 if (ctx == NULL || ctx->method == NULL || len == NULL || out == NULL) {
119 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
120 return CRYPT_NULL_INPUT;
121 }
122 const EAL_SymMethod *method = ctx->method;
123 uint32_t blockSize = method->blockSize;
124 if (*len < blockSize) {
125 BSL_ERR_PUSH_ERROR(CRYPT_CMAC_OUT_BUFF_LEN_NOT_ENOUGH);
126 return CRYPT_CMAC_OUT_BUFF_LEN_NOT_ENOUGH;
127 }
128
129 CMAC_Final(ctx);
130 DATA_XOR(ctx->left, ctx->data, ctx->left, blockSize);
131 int32_t ret = method->encryptBlock(ctx->key, ctx->left, out, blockSize);
132 if (ret != CRYPT_SUCCESS) {
133 BSL_ERR_PUSH_ERROR(ret);
134 return ret;
135 }
136 *len = blockSize;
137 return CRYPT_SUCCESS;
138 }
139
CRYPT_CMAC_Reinit(CRYPT_CMAC_Ctx * ctx)140 void CRYPT_CMAC_Reinit(CRYPT_CMAC_Ctx *ctx)
141 {
142 CipherMacReinit((Cipher_MAC_Common_Ctx *)ctx);
143 }
144
CRYPT_CMAC_Deinit(CRYPT_CMAC_Ctx * ctx)145 void CRYPT_CMAC_Deinit(CRYPT_CMAC_Ctx *ctx)
146 {
147 CipherMacDeinit((Cipher_MAC_Common_Ctx *)ctx);
148 }
149
CRYPT_CMAC_Ctrl(CRYPT_CMAC_Ctx * ctx,uint32_t opt,void * val,uint32_t len)150 int32_t CRYPT_CMAC_Ctrl(CRYPT_CMAC_Ctx *ctx, uint32_t opt, void *val, uint32_t len)
151 {
152 if (ctx == NULL) {
153 BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
154 return CRYPT_NULL_INPUT;
155 }
156 switch (opt) {
157 case CRYPT_CTRL_GET_MACLEN:
158 return CipherMacGetMacLen(ctx, val, len);
159 default:
160 break;
161 }
162 BSL_ERR_PUSH_ERROR(CRYPT_CMAC_ERR_UNSUPPORTED_CTRL_OPTION);
163 return CRYPT_CMAC_ERR_UNSUPPORTED_CTRL_OPTION;
164 }
165
CRYPT_CMAC_FreeCtx(CRYPT_CMAC_Ctx * ctx)166 void CRYPT_CMAC_FreeCtx(CRYPT_CMAC_Ctx *ctx)
167 {
168 CipherMacDeinitCtx(ctx);
169 BSL_SAL_Free(ctx);
170 }
171
172 #endif /* HITLS_CRYPTO_CMAC */
173