• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "crypto_mgr.h"
17 
18 #include <atomic>
19 #include <cstdlib>
20 
21 #include "mbedtls/base64.h"
22 #include "mbedtls/cipher.h"
23 #include "mbedtls/ctr_drbg.h"
24 #include "mbedtls/entropy.h"
25 #include "mbedtls/gcm.h"
26 #include "mbedtls/md.h"
27 #include "mbedtls/platform.h"
28 
29 #include "securec.h"
30 
31 #include "dm_error_type.h"
32 #include "dm_crypto.h"
33 #include "dm_log.h"
34 
35 namespace OHOS {
36 namespace DistributedHardware {
37 constexpr uint32_t MAX_SESSION_KEY_LENGTH = 512;
38 constexpr uint32_t TAG_LEN = 16;
39 constexpr uint32_t OVERHEAD_LEN = GCM_IV_LEN + TAG_LEN;
40 constexpr uint32_t MAX_ENCRY_MSG_LEN = 10 * 1024 * 1024; // 10MB
41 constexpr uint32_t KEY_BITS_UNIT = 8;
42 constexpr uint32_t HEX_TO_UINT8 = 2;
CryptoMgr()43 CryptoMgr::CryptoMgr()
44 {
45     LOGI("CryptoMgr ctor");
46 }
47 
~CryptoMgr()48 CryptoMgr::~CryptoMgr()
49 {
50     LOGI("CryptoMgr dtor");
51     ClearSessionKey();
52 }
53 
EncryptMessage(const std::string & inputMsg,std::string & outputMsg)54 int32_t CryptoMgr::EncryptMessage(const std::string &inputMsg, std::string &outputMsg)
55 {
56     if (inputMsg.length() > MAX_ENCRY_MSG_LEN) {
57         LOGE("Encrypt msg too long, size: %{public}zu", inputMsg.size());
58         return ERR_DM_CRYPTO_PARA_INVALID;
59     }
60 
61     std::lock_guard<std::mutex> lock(sessionKeyMtx_);
62     AesGcmCipherKey cipherKey = {.keyLen = sessionKey_.keyLen};
63     if (memcpy_s(cipherKey.key, SESSION_KEY_LENGTH, sessionKey_.key, sessionKey_.keyLen) != EOK) {
64         LOGE("set key fail");
65         return ERR_DM_CRYPTO_OPT_FAILED;
66     }
67 
68     uint32_t encDataLen = inputMsg.length() + OVERHEAD_LEN;
69     unsigned char *encData = (unsigned char *)calloc(encDataLen, sizeof(unsigned char));
70     if (encData == nullptr) {
71         LOGE("calloc fail");
72         return ERR_DM_CRYPTO_OPT_FAILED;
73     }
74     int32_t ret = DoEncryptData(&cipherKey, reinterpret_cast<const unsigned char*>(inputMsg.c_str()),
75         static_cast<uint32_t>(inputMsg.length()), encData, &encDataLen);
76     if (ret != DM_OK) {
77         LOGE("EncryptData fail=%{public}d", ret);
78         free(encData);
79         encData = nullptr;
80         return ERR_DM_CRYPTO_OPT_FAILED;
81     }
82     if (memset_s(&cipherKey, sizeof(AesGcmCipherKey), 0, sizeof(AesGcmCipherKey)) != DM_OK) {
83         LOGE("memset_s failed.");
84         free(encData);
85         encData = nullptr;
86         return ERR_DM_SECURITY_FUNC_FAILED;
87     }
88     const uint32_t hexStrLen = encDataLen * HEX_TO_UINT8 + 1;
89     char hexStrTemp[hexStrLen];
90     if (memset_s(hexStrTemp, hexStrLen, 0, hexStrLen) != DM_OK) {
91         LOGE("memset_s failed.");
92         free(encData);
93         encData = nullptr;
94         return ERR_DM_SECURITY_FUNC_FAILED;
95     }
96     Crypto::ConvertBytesToHexString(hexStrTemp, hexStrLen, encData, encDataLen);
97     outputMsg.clear();
98     outputMsg.assign(hexStrTemp, encDataLen * HEX_TO_UINT8);
99     free(encData);
100     encData = nullptr;
101     return DM_OK;
102 }
103 
DoEncryptData(AesGcmCipherKey * cipherKey,const unsigned char * input,uint32_t inLen,unsigned char * encryptData,uint32_t * encryptLen)104 int32_t CryptoMgr::DoEncryptData(AesGcmCipherKey *cipherKey, const unsigned char *input, uint32_t inLen,
105     unsigned char *encryptData, uint32_t *encryptLen)
106 {
107     if (cipherKey == nullptr || input == nullptr || inLen == 0 || encryptData == nullptr || encryptLen == nullptr) {
108         return ERR_DM_CRYPTO_PARA_INVALID;
109     }
110 
111     if (GenerateRandomArray(cipherKey->iv, sizeof(cipherKey->iv)) != DM_OK) {
112         LOGE("generate random iv error.");
113         return ERR_DM_CRYPTO_OPT_FAILED;
114     }
115     uint32_t outLen = inLen + OVERHEAD_LEN;
116     int32_t result = MbedAesGcmEncrypt(cipherKey, input, inLen, encryptData, outLen);
117     if (result <= 0) {
118         return ERR_DM_CRYPTO_OPT_FAILED;
119     }
120     *encryptLen = result;
121     return DM_OK;
122 }
123 
MbedAesGcmEncrypt(const AesGcmCipherKey * cipherKey,const unsigned char * plainText,uint32_t plainTextSize,unsigned char * cipherText,uint32_t cipherTextLen)124 int32_t CryptoMgr::MbedAesGcmEncrypt(const AesGcmCipherKey *cipherKey, const unsigned char *plainText,
125     uint32_t plainTextSize, unsigned char *cipherText, uint32_t cipherTextLen)
126 {
127     if ((cipherKey == nullptr) || (plainText == nullptr) || (plainTextSize == 0) || cipherText == nullptr ||
128         (cipherTextLen < plainTextSize + OVERHEAD_LEN)) {
129         LOGE("Encrypt invalid para");
130         return ERR_DM_CRYPTO_PARA_INVALID;
131     }
132 
133     int32_t ret = -1;
134     unsigned char tagBuf[TAG_LEN] = { 0 };
135     mbedtls_gcm_context aesContext;
136     mbedtls_gcm_init(&aesContext);
137 
138     ret = mbedtls_gcm_setkey(&aesContext, MBEDTLS_CIPHER_ID_AES, cipherKey->key, cipherKey->keyLen * KEY_BITS_UNIT);
139     if (ret != 0) {
140         mbedtls_gcm_free(&aesContext);
141         return ERR_DM_CRYPTO_OPT_FAILED;
142     }
143 
144     ret = mbedtls_gcm_crypt_and_tag(&aesContext, MBEDTLS_GCM_ENCRYPT, plainTextSize, cipherKey->iv, GCM_IV_LEN, NULL, 0,
145         plainText, cipherText + GCM_IV_LEN, TAG_LEN, tagBuf);
146     if (ret != 0) {
147         mbedtls_gcm_free(&aesContext);
148         return ERR_DM_CRYPTO_OPT_FAILED;
149     }
150 
151     if (memcpy_s(cipherText, cipherTextLen, cipherKey->iv, GCM_IV_LEN) != EOK) {
152         mbedtls_gcm_free(&aesContext);
153         return ERR_DM_CRYPTO_OPT_FAILED;
154     }
155 
156     if (memcpy_s(cipherText + GCM_IV_LEN + plainTextSize, cipherTextLen - GCM_IV_LEN - plainTextSize, tagBuf,
157                  TAG_LEN) != 0) {
158         mbedtls_gcm_free(&aesContext);
159         return ERR_DM_CRYPTO_OPT_FAILED;
160     }
161 
162     mbedtls_gcm_free(&aesContext);
163     return (plainTextSize + OVERHEAD_LEN);
164 }
165 
GenerateRandomArray(unsigned char * randStr,uint32_t len)166 int32_t CryptoMgr::GenerateRandomArray(unsigned char *randStr, uint32_t len)
167 {
168     if (randStr == NULL || len == 0) {
169         return ERR_DM_CRYPTO_PARA_INVALID;
170     }
171 
172     static mbedtls_entropy_context entropy;
173     static mbedtls_ctr_drbg_context ctrDrbg;
174     static std::atomic<bool> initFlag = false;
175     int32_t ret;
176 
177     if (!initFlag) {
178         std::lock_guard<std::mutex> lock(randomLock_);
179         mbedtls_ctr_drbg_init(&ctrDrbg);
180         mbedtls_entropy_init(&entropy);
181         ret = mbedtls_ctr_drbg_seed(&ctrDrbg, mbedtls_entropy_func, &entropy, NULL, 0);
182         if (ret != 0) {
183             LOGE("gen random seed error, ret=%{public}d", ret);
184             return ERR_DM_CRYPTO_OPT_FAILED;
185         }
186         initFlag = true;
187     }
188 
189     std::lock_guard<std::mutex> lock(randomLock_);
190     ret = mbedtls_ctr_drbg_random(&ctrDrbg, randStr, len);
191     if (ret != 0) {
192         LOGE("gen random error, ret=%{public}d", ret);
193         return ERR_DM_CRYPTO_OPT_FAILED;
194     }
195     return DM_OK;
196 }
197 
DecryptMessage(const std::string & inputMsg,std::string & outputMsg)198 int32_t CryptoMgr::DecryptMessage(const std::string &inputMsg, std::string &outputMsg)
199 {
200     const uint32_t inputMsgBytesLen = inputMsg.length() / HEX_TO_UINT8;
201     unsigned char inputMsgBytsTemp[inputMsgBytesLen];
202     if (memset_s(inputMsgBytsTemp, inputMsgBytesLen, 0, inputMsgBytesLen) != DM_OK) {
203         LOGE("memset_s failed.");
204         return ERR_DM_CRYPTO_OPT_FAILED;
205     }
206     Crypto::ConvertHexStringToBytes(inputMsgBytsTemp, inputMsgBytesLen,
207         reinterpret_cast<const char*>(inputMsg.c_str()), inputMsg.length());
208     std::lock_guard<std::mutex> lock(sessionKeyMtx_);
209     AesGcmCipherKey cipherKey = {.keyLen = sessionKey_.keyLen};
210     if (memcpy_s(cipherKey.key, SESSION_KEY_LENGTH, sessionKey_.key, sessionKey_.keyLen) != EOK) {
211         LOGE("set key fail");
212         return ERR_DM_CRYPTO_OPT_FAILED;
213     }
214 
215     uint32_t outLen = inputMsgBytesLen - OVERHEAD_LEN + 1; /* for '\0' */
216     unsigned char *outData = (unsigned char *)calloc(outLen, sizeof(unsigned char));
217     if (outData == nullptr) {
218         LOGE("calloc fail");
219         return ERR_DM_CRYPTO_OPT_FAILED;
220     }
221 
222     int32_t ret = DoDecryptData(&cipherKey, inputMsgBytsTemp,
223         static_cast<uint32_t>(inputMsg.length() / HEX_TO_UINT8), outData, &outLen);
224     if (ret != DM_OK) {
225         LOGE("SoftBusDecryptDataWithSeq fail=%{public}d", ret);
226         free(outData);
227         outData = nullptr;
228         return ERR_DM_CRYPTO_OPT_FAILED;
229     }
230     if (memset_s(&cipherKey, sizeof(AesGcmCipherKey), 0, sizeof(AesGcmCipherKey)) != DM_OK) {
231         LOGE("memset_s failed.");
232         free(outData);
233         outData = nullptr;
234         return ERR_DM_SECURITY_FUNC_FAILED;
235     }
236     outputMsg.clear();
237     outputMsg.assign(reinterpret_cast<const char*>(outData), outLen);
238     free(outData);
239     outData = nullptr;
240     return DM_OK;
241 }
242 
MbedAesGcmDecrypt(const AesGcmCipherKey * cipherKey,const unsigned char * cipherText,uint32_t cipherTextSize,unsigned char * plain,uint32_t plainLen)243 int32_t CryptoMgr::MbedAesGcmDecrypt(const AesGcmCipherKey *cipherKey, const unsigned char *cipherText,
244     uint32_t cipherTextSize, unsigned char *plain, uint32_t plainLen)
245 {
246     if ((cipherKey == NULL) || (cipherText == NULL) || (cipherTextSize <= OVERHEAD_LEN) || plain == NULL ||
247         (plainLen < cipherTextSize - OVERHEAD_LEN)) {
248         LOGE("Decrypt invalid para");
249         return ERR_DM_CRYPTO_PARA_INVALID;
250     }
251 
252     mbedtls_gcm_context aesContext;
253     mbedtls_gcm_init(&aesContext);
254     int32_t ret =
255         mbedtls_gcm_setkey(&aesContext, MBEDTLS_CIPHER_ID_AES, cipherKey->key, cipherKey->keyLen * KEY_BITS_UNIT);
256     if (ret != 0) {
257         LOGE("Decrypt mbedtls_gcm_setkey fail.");
258         mbedtls_gcm_free(&aesContext);
259         return ERR_DM_CRYPTO_OPT_FAILED;
260     }
261 
262     int32_t actualPlainLen = (int32_t)(cipherTextSize - OVERHEAD_LEN);
263     ret = mbedtls_gcm_auth_decrypt(&aesContext, cipherTextSize - OVERHEAD_LEN, cipherKey->iv, GCM_IV_LEN, NULL, 0,
264         cipherText + actualPlainLen + GCM_IV_LEN, TAG_LEN, cipherText + GCM_IV_LEN, plain);
265     if (ret != 0) {
266         LOGE("[TRANS] Decrypt mbedtls_gcm_auth_decrypt fail. ret=%{public}d", ret);
267         mbedtls_gcm_free(&aesContext);
268         return ERR_DM_CRYPTO_OPT_FAILED;
269     }
270 
271     mbedtls_gcm_free(&aesContext);
272     return actualPlainLen;
273 }
274 
DoDecryptData(AesGcmCipherKey * cipherKey,const unsigned char * input,uint32_t inLen,unsigned char * decryptData,uint32_t * decryptLen)275 int32_t CryptoMgr::DoDecryptData(AesGcmCipherKey *cipherKey, const unsigned char *input, uint32_t inLen,
276     unsigned char *decryptData, uint32_t *decryptLen)
277 {
278     if (cipherKey == NULL || input == NULL || inLen < GCM_IV_LEN || decryptData == NULL || decryptLen == NULL) {
279         return ERR_DM_CRYPTO_PARA_INVALID;
280     }
281 
282     if (memcpy_s(cipherKey->iv, sizeof(cipherKey->iv), input, GCM_IV_LEN) != EOK) {
283         LOGE("copy iv failed.");
284         return ERR_DM_CRYPTO_OPT_FAILED;
285     }
286     uint32_t outLen = inLen - OVERHEAD_LEN;
287     int32_t result = MbedAesGcmDecrypt(cipherKey, input, inLen, decryptData, outLen);
288     if (result <= 0) {
289         return ERR_DM_CRYPTO_OPT_FAILED;
290     }
291     *decryptLen = (uint32_t)result;
292     return DM_OK;
293 }
294 
SaveSessionKey(const uint8_t * sessionKey,const uint32_t keyLen)295 int32_t CryptoMgr::SaveSessionKey(const uint8_t *sessionKey, const uint32_t keyLen)
296 {
297     if (keyLen > MAX_SESSION_KEY_LENGTH) {
298         LOGE("SessionKey too long, len: %{public}d", keyLen);
299         return ERR_DM_SAVE_SESSION_KEY_FAILED;
300     }
301 
302     ClearSessionKey();
303     {
304         std::lock_guard<std::mutex> lock(sessionKeyMtx_);
305         sessionKey_.key = (uint8_t*)calloc(keyLen, sizeof(uint8_t));
306         sessionKey_.keyLen = keyLen;
307     }
308     return DM_OK;
309 }
310 
ClearSessionKey()311 void CryptoMgr::ClearSessionKey()
312 {
313     std::lock_guard<std::mutex> lock(sessionKeyMtx_);
314     if (sessionKey_.key != nullptr) {
315         (void)memset_s(sessionKey_.key, sessionKey_.keyLen, 0, sessionKey_.keyLen);
316         free(sessionKey_.key);
317         sessionKey_.key = nullptr;
318         sessionKey_.keyLen = 0;
319     }
320 }
321 
ProcessSessionKey(const uint8_t * sessionKey,const uint32_t keyLen)322 int32_t CryptoMgr::ProcessSessionKey(const uint8_t *sessionKey, const uint32_t keyLen)
323 {
324     if (sessionKey == nullptr || keyLen > MAX_SESSION_KEY_LENGTH) {
325         LOGE("Invalid param, SessionKey len: %{public}d", keyLen);
326         return ERR_DM_PROCESS_SESSION_KEY_FAILED;
327     }
328     ClearSessionKey();
329     {
330         std::lock_guard<std::mutex> lock(sessionKeyMtx_);
331         sessionKey_.key = (uint8_t*)calloc(keyLen, sizeof(uint8_t));
332         if (memcpy_s(sessionKey_.key, keyLen, sessionKey, keyLen) != DM_OK) {
333             LOGE("memcpy_s failed.");
334             return ERR_DM_PROCESS_SESSION_KEY_FAILED;
335         }
336         sessionKey_.keyLen = keyLen;
337     }
338     return DM_OK;
339 }
340 } // namespace DistributedHardware
341 } // namespace OHOS