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