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 "tel_aes_crypto_util.h"
17 
18 #include <algorithm>
19 
20 #include "securec.h"
21 #include "tel_profile_util.h"
22 #include "telephony_log_wrapper.h"
23 
24 namespace OHOS {
25 namespace Telephony {
26 constexpr uint32_t MAX_UPDATE_SIZE = 1024;
27 constexpr uint32_t AAD_SIZE = 16;
28 constexpr uint32_t NONCE_SIZE = 12;
29 constexpr uint32_t AEAD_SIZE = 16;
30 constexpr uint8_t AAD[AAD_SIZE] = {0};
31 constexpr uint8_t NONCE[NONCE_SIZE] = {0};
32 constexpr uint8_t AEAD[AEAD_SIZE] = {0};
33 constexpr const char TEL_AES_KEY_ALIAS[] = "TelAesKeyAlias";
34 
35 constexpr size_t HEX_UNIT_LEN = 2;
36 constexpr int32_t ENCODE_UNIT_LEN = 3;
37 constexpr int32_t HEX_OFFSET = 16;
38 constexpr int32_t DEC_OFFSET = 10;
39 
40 #define AES_ALGORITHM_PARAM                     \
41     {                                           \
42         .tag = HKS_TAG_ALGORITHM,               \
43         .uint32Param = HKS_ALG_AES              \
44     }, {                                        \
45         .tag = HKS_TAG_KEY_SIZE,                \
46         .uint32Param = HKS_AES_KEY_SIZE_128     \
47     }, {                                        \
48         .tag = HKS_TAG_PADDING,                 \
49         .uint32Param = HKS_PADDING_NONE         \
50     }, {                                        \
51         .tag = HKS_TAG_BLOCK_MODE,              \
52         .uint32Param = HKS_MODE_GCM             \
53     }, {                                        \
54         .tag = HKS_TAG_AUTH_STORAGE_LEVEL,              \
55         .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE             \
56     }
57 
58 #define GCM_MODE_PARAM                          \
59     {                                           \
60         .tag = HKS_TAG_DIGEST,                  \
61         .uint32Param = HKS_DIGEST_NONE          \
62     }, {                                        \
63         .tag = HKS_TAG_ASSOCIATED_DATA,         \
64         .blob = {                               \
65             .size = AAD_SIZE,                   \
66             .data = (uint8_t *)AAD              \
67         }                                       \
68     }, {                                        \
69         .tag = HKS_TAG_NONCE,                   \
70         .blob = {                               \
71             .size = NONCE_SIZE,                 \
72             .data = (uint8_t *)NONCE            \
73         }                                       \
74     }
75 
SaveEncryptString(const std::string & key,int32_t id,const std::string & rawData)76 int TelAesCryptoUtils::SaveEncryptString(const std::string &key, int32_t id, const std::string &rawData)
77 {
78     auto telProfileUtil = DelayedSingleton<TelProfileUtil>::GetInstance();
79     std::string encryptValue = AesCryptoEncrypt(rawData);
80     return telProfileUtil->SaveString(key + std::to_string(id), encryptValue);
81 }
82 
ObtainDecryptString(const std::string & key,int32_t id,const std::string & defValue)83 std::string TelAesCryptoUtils::ObtainDecryptString(const std::string &key, int32_t id, const std::string &defValue)
84 {
85     auto telProfileUtil = DelayedSingleton<TelProfileUtil>::GetInstance();
86     std::string encryptValue = telProfileUtil->ObtainString(key + std::to_string(id), defValue);
87     std::string str = AesCryptoDecrypt(encryptValue);
88     return str;
89 }
90 
AesCryptoEncrypt(const std::string & srcData)91 std::string TelAesCryptoUtils::AesCryptoEncrypt(const std::string &srcData)
92 {
93     if (srcData.empty()) {
94         return "";
95     }
96     struct HksBlob keyAlias = { strlen(TEL_AES_KEY_ALIAS), (uint8_t *)TEL_AES_KEY_ALIAS };
97 
98     struct HksParamSet *genParamSet = nullptr;
99     struct HksParam genParams[] = {
100         {
101             .tag = HKS_TAG_PURPOSE,
102             .uint32Param = HKS_KEY_PURPOSE_ENCRYPT | HKS_KEY_PURPOSE_DECRYPT
103         },
104         AES_ALGORITHM_PARAM
105     };
106     int32_t ret = InitParamSet(&genParamSet, genParams, sizeof(genParams) / sizeof(HksParam));
107     if (ret != 0) {
108         HksFreeParamSet(&genParamSet);
109         TELEPHONY_LOGE("InitParamSet genParamSet failed");
110         return "";
111     }
112 
113     struct HksParamSet *encryptParamSet = nullptr;
114     static struct HksParam encryptParams[] = {
115         {
116             .tag = HKS_TAG_PURPOSE,
117             .uint32Param = HKS_KEY_PURPOSE_ENCRYPT
118         }, {
119             .tag = HKS_TAG_AE_TAG,
120             .blob = {
121                 .size = AEAD_SIZE,
122                 .data = (uint8_t *)AEAD
123             }
124         },
125         AES_ALGORITHM_PARAM,
126         GCM_MODE_PARAM
127     };
128     ret = InitParamSet(&encryptParamSet, encryptParams, sizeof(encryptParams) / sizeof(HksParam));
129     if (ret != 0) {
130         TELEPHONY_LOGE("InitParamSet encryptParamSet failed");
131         HksFreeParamSet(&genParamSet);
132         HksFreeParamSet(&encryptParamSet);
133         return "";
134     }
135 
136     std::string encryptData = AesCryptoEncryptInner(&keyAlias, genParamSet, encryptParamSet, srcData);
137     HksFreeParamSet(&genParamSet);
138     HksFreeParamSet(&encryptParamSet);
139     return encryptData;
140 }
141 
AesCryptoDecrypt(std::string & srcData)142 std::string TelAesCryptoUtils::AesCryptoDecrypt(std::string &srcData)
143 {
144     if (srcData.empty()) {
145         return "";
146     }
147     struct HksBlob keyAlias = { strlen(TEL_AES_KEY_ALIAS), (uint8_t *)TEL_AES_KEY_ALIAS };
148 
149     struct HksParamSet *decryptGcmParamSet = nullptr;
150     static struct HksParam decryptGcmParams[] = {
151         {
152             .tag = HKS_TAG_PURPOSE,
153             .uint32Param = HKS_KEY_PURPOSE_DECRYPT
154         },
155         AES_ALGORITHM_PARAM,
156         GCM_MODE_PARAM,
157         {
158             .tag = HKS_TAG_AE_TAG,
159             .blob = {
160                 .size = AEAD_SIZE,
161                 .data = (uint8_t *)AEAD
162             }
163         }
164     };
165     int32_t ret = InitParamSet(&decryptGcmParamSet, decryptGcmParams, sizeof(decryptGcmParams) / sizeof(HksParam));
166     if (ret != 0) {
167         TELEPHONY_LOGE("InitParamSet decryptGcmParamSet failed");
168         HksFreeParamSet(&decryptGcmParamSet);
169         return "";
170     }
171     std::string decryptData = AesCryptoDecryptInner(&keyAlias, decryptGcmParamSet, srcData);
172     HksFreeParamSet(&decryptGcmParamSet);
173     return decryptData;
174 }
175 
InitParamSet(struct HksParamSet ** paramSet,const struct HksParam * params,uint32_t paramCount)176 int32_t TelAesCryptoUtils::InitParamSet(struct HksParamSet **paramSet, const struct HksParam *params,
177     uint32_t paramCount)
178 {
179     int32_t ret = HksInitParamSet(paramSet);
180     if (ret != 0) {
181         TELEPHONY_LOGE("HksInitParamSet failed");
182         return ret;
183     }
184 
185     ret = HksAddParams(*paramSet, params, paramCount);
186     if (ret != 0) {
187         TELEPHONY_LOGE("HksAddParams failed");
188         return ret;
189     }
190 
191     ret = HksBuildParamSet(paramSet);
192     if (ret != 0) {
193         TELEPHONY_LOGE("HksBuildParamSet failed");
194         return ret;
195     }
196     return ret;
197 }
198 
AesCryptoEncryptInner(const struct HksBlob * keyAlias,struct HksParamSet * genParamSet,struct HksParamSet * encryptParamSet,const std::string & srcData)199 std::string TelAesCryptoUtils::AesCryptoEncryptInner(const struct HksBlob *keyAlias,
200     struct HksParamSet *genParamSet, struct HksParamSet *encryptParamSet, const std::string &srcData)
201 {
202     struct HksBlob inData = {
203         srcData.length(),
204         const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(srcData.c_str()))
205     };
206 
207     // 1. Generate Key
208     int32_t ret;
209     if (HksKeyExist(keyAlias, genParamSet) != 0) {
210         ret = HksGenerateKey(keyAlias, genParamSet, nullptr);
211         if (ret != 0) {
212             TELEPHONY_LOGE("HksGenerateKey failed");
213             return "";
214         }
215     }
216 
217     // 2. Encrypt
218     uint8_t handleData[sizeof(uint64_t)] = {0};
219     struct HksBlob handle = { sizeof(uint64_t), handleData };
220     ret = HksInit(keyAlias, encryptParamSet, &handle, nullptr);
221     if (ret != 0) {
222         TELEPHONY_LOGE("HksInit failed");
223         return "";
224     }
225 
226     uint8_t *cipher = (uint8_t *)calloc(srcData.length() + AEAD_SIZE, sizeof(uint8_t));
227     if (cipher == nullptr) {
228         return "";
229     }
230     struct HksBlob cipherText = { srcData.length() + AEAD_SIZE, cipher };
231     ret = AesCryptoLoopUpdate(&handle, encryptParamSet, &inData, &cipherText);
232     if (ret != 0) {
233         TELEPHONY_LOGE("AesCryptoLoopUpdate failed");
234         free(cipher);
235         return "";
236     }
237     std::string encryptStr = DecToHexString(cipherText.data, cipherText.size);
238     free(cipher);
239     return encryptStr;
240 }
241 
AesCryptoDecryptInner(const struct HksBlob * keyAlias,struct HksParamSet * decryptGcmParamSet,std::string & srcData)242 std::string TelAesCryptoUtils::AesCryptoDecryptInner(const struct HksBlob *keyAlias,
243     struct HksParamSet *decryptGcmParamSet, std::string &srcData)
244 {
245     std::pair<uint8_t *, size_t> decryptDataPair = HexToDecString(srcData);
246     if (decryptDataPair.first == nullptr || decryptDataPair.second <= 0) {
247         TELEPHONY_LOGE("decryptDataPair is invalid");
248         if (decryptDataPair.first != nullptr) {
249             free(decryptDataPair.first);
250         }
251         return "";
252     }
253     struct HksBlob inData = { decryptDataPair.second, decryptDataPair.first };
254 
255     inData.size -= AEAD_SIZE;
256     for (uint32_t i = 0; i < decryptGcmParamSet->paramsCnt; i++) {
257         if (decryptGcmParamSet->params[i].tag == HKS_TAG_AE_TAG) {
258             if (memcpy_s(decryptGcmParamSet->params[i].blob.data, AEAD_SIZE,
259                 inData.data + inData.size, AEAD_SIZE) != 0) {
260                 TELEPHONY_LOGE("AesCryptoDecryptInner memcpy_s failed");
261                 free(inData.data);
262                 return "";
263             }
264             break;
265         }
266     }
267 
268     uint8_t handleData[sizeof(uint64_t)] = {0};
269     struct HksBlob handle = { sizeof(uint64_t), handleData };
270     int32_t ret = HksInit(keyAlias, decryptGcmParamSet, &handle, nullptr);
271     if (ret != 0) {
272         TELEPHONY_LOGE("AesCryptoDecryptInner HksInit failed");
273         free(inData.data);
274         return "";
275     }
276 
277     // Update & Finish
278     uint8_t *plain = (uint8_t *)calloc(decryptDataPair.second, sizeof(uint8_t));
279     if (plain == nullptr) {
280         TELEPHONY_LOGE("AesCryptoDecryptInner calloc failed");
281         free(inData.data);
282         return "";
283     }
284     struct HksBlob plainText = { decryptDataPair.second, plain };
285     ret = AesCryptoLoopUpdate(&handle, decryptGcmParamSet, &inData, &plainText);
286     free(inData.data);
287     if (ret != 0) {
288         TELEPHONY_LOGE("AesCryptoLoopUpdate failed");
289         free(plain);
290         return "";
291     }
292 
293     std::string decryptStr((char *)plainText.data);
294     free(plain);
295     return decryptStr;
296 }
297 
AesCryptoLoopUpdate(const struct HksBlob * handle,const struct HksParamSet * paramSet,const struct HksBlob * inData,struct HksBlob * outData)298 int32_t TelAesCryptoUtils::AesCryptoLoopUpdate(const struct HksBlob *handle, const struct HksParamSet *paramSet,
299     const struct HksBlob *inData, struct HksBlob *outData)
300 {
301     uint32_t inDataSize = inData->size;
302     uint32_t handledInDataSize = 0;
303     struct HksBlob inDataSeg = *inData;
304     struct HksBlob outDataSeg = { MAX_UPDATE_SIZE, NULL };
305     uint8_t *cur = outData->data;
306     outData->size = 0;
307 
308     while (handledInDataSize < inDataSize) {
309         uint32_t aesDataLen = std::min(MAX_UPDATE_SIZE, (inDataSize - handledInDataSize));
310         inDataSeg.size = aesDataLen;
311         outDataSeg.size = aesDataLen + AEAD_SIZE;
312         outDataSeg.data = (uint8_t *)malloc(outDataSeg.size);
313         if (outDataSeg.data == nullptr) {
314             return HKS_FAILURE;
315         }
316         int32_t hksResult = 0;
317         if (handledInDataSize + aesDataLen < inDataSize) {
318             hksResult = HksUpdate(handle, paramSet, &inDataSeg, &outDataSeg);
319         } else {
320             hksResult = HksFinish(handle, paramSet, &inDataSeg, &outDataSeg);
321         }
322 
323         if (hksResult != 0) {
324             TELEPHONY_LOGE("AesCryptoDecryptInner HksUpdate failed");
325             free(outDataSeg.data);
326             return HKS_FAILURE;
327         }
328         if (memcpy_s(cur, outDataSeg.size, outDataSeg.data, outDataSeg.size) != EOK) {
329             free(outDataSeg.data);
330             return HKS_FAILURE;
331         }
332         cur += outDataSeg.size;
333         outData->size += outDataSeg.size;
334         free(outDataSeg.data);
335         inDataSeg.data += aesDataLen;
336         handledInDataSize += aesDataLen;
337     }
338     return 0;
339 }
340 
HexToDec(char hex,uint8_t & decodeValue)341 bool TelAesCryptoUtils::HexToDec(char hex, uint8_t &decodeValue)
342 {
343     if (hex >= '0' && hex <= '9') {
344         decodeValue = static_cast<uint8_t>(hex - '0');
345         return true;
346     }
347     if (hex >= 'a' && hex <= 'f') {
348         decodeValue = static_cast<uint8_t>(hex - 'a' + DEC_OFFSET);
349         return true;
350     }
351     return false;
352 }
353 
DecToHexString(const uint8_t * data,size_t len)354 std::string TelAesCryptoUtils::DecToHexString(const uint8_t *data, size_t len)
355 {
356     if (data == nullptr || len == 0) {
357         return "";
358     }
359 
360     std::string hexString;
361     char encodeUnit[ENCODE_UNIT_LEN] = {0};
362     for (size_t i = 0; i < len; i++) {
363         if (sprintf_s(encodeUnit, ENCODE_UNIT_LEN, "%02x", data[i]) <= 0) {
364             TELEPHONY_LOGE("DecToHexString failed");
365             return "";
366         }
367         hexString.push_back(encodeUnit[0]);
368         hexString.push_back(encodeUnit[1]);
369     }
370 
371     return hexString;
372 }
373 
HexToDecString(const std::string & hexString)374 std::pair<uint8_t *, size_t> TelAesCryptoUtils::HexToDecString(const std::string &hexString)
375 {
376     if (hexString.empty() || hexString.length() % HEX_UNIT_LEN != 0) {
377         TELEPHONY_LOGE("HexToDecString failed");
378         return std::make_pair(nullptr, 0);
379     }
380 
381     size_t pos = 0;
382     size_t len = hexString.length() / HEX_UNIT_LEN;
383     uint8_t *data = reinterpret_cast<uint8_t *>(calloc(len + 1, sizeof(uint8_t)));
384     if (data == nullptr) {
385         TELEPHONY_LOGE("HexToDecString failed");
386         return std::make_pair(nullptr, 0);
387     }
388     uint8_t decodeUnitFirst;
389     uint8_t decodeUnitSecond;
390     for (size_t i = 0; i < len; i++) {
391         if (!HexToDec(hexString.at(pos), decodeUnitFirst) || !HexToDec(hexString.at(pos + 1), decodeUnitSecond)) {
392             free(data);
393             TELEPHONY_LOGE("HexToDecString failed");
394             return std::make_pair(nullptr, 0);
395         }
396         data[i] = static_cast<uint8_t>(decodeUnitFirst * HEX_OFFSET + decodeUnitSecond);
397         pos += HEX_UNIT_LEN;
398     }
399     return std::make_pair(data, len);
400 }
401 } // namespace UpdateEngine
402 } // namespace OHOS