1/*
2 * Copyright (c) 2023 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#include "dm_crypto.h"
16#include "dm_log.h"
17#if !(defined(__LITEOS_M__) || defined(LITE_DEVICE))
18#include "datetime_ex.h"
19#include "kv_adapter_manager.h"
20#endif
21#include <iostream>
22#include <sstream>
23
24#include <openssl/rand.h>
25#include "openssl/sha.h"
26
27namespace OHOS {
28namespace DistributedHardware {
29
30constexpr int32_t HEX_TO_UINT8 = 2;
31constexpr int WIDTH = 4;
32constexpr unsigned char MASK = 0x0F;
33constexpr int DEC_MAX_NUM = 10;
34constexpr int HEX_MAX_BIT_NUM = 4;
35constexpr uint32_t ERR_DM_FAILED = 96929744;
36constexpr int32_t DM_OK = 0;
37constexpr int32_t DM_ERR = -1;
38constexpr int32_t ERR_DM_INPUT_PARA_INVALID = 96929749;
39constexpr int HEX_DIGIT_MAX_NUM = 16;
40constexpr int SHORT_DEVICE_ID_HASH_LENGTH = 16;
41constexpr int32_t SALT_LENGTH = 8;
42const std::string SALT_DEFAULT = "salt_defsalt_def";
43constexpr int SHORT_ACCOUNTID_ID_HASH_LENGTH = 6;
44#if !(defined(__LITEOS_M__) || defined(LITE_DEVICE))
45#define DM_MAX_DEVICE_ID_LEN (97)
46#endif
47
48uint32_t HexifyLen(uint32_t len)
49{
50    return len * HEX_TO_UINT8 + 1;
51}
52
53void DmGenerateStrHash(const void *data, size_t dataSize, unsigned char *outBuf, uint32_t outBufLen,
54    uint32_t startIndex)
55{
56    if (data == nullptr || outBuf == nullptr || startIndex > outBufLen) {
57        LOGE("Invalied param.");
58        return;
59    }
60    SHA256_CTX ctx;
61    SHA256_Init(&ctx);
62    SHA256_Update(&ctx, data, dataSize);
63    SHA256_Final(&outBuf[startIndex], &ctx);
64}
65
66int32_t ConvertBytesToHexString(char *outBuf, uint32_t outBufLen, const unsigned char *inBuf,
67    uint32_t inLen)
68{
69    if ((outBuf == nullptr) || (inBuf == nullptr) || (outBufLen < HexifyLen(inLen))) {
70        return ERR_DM_INPUT_PARA_INVALID;
71    }
72    while (inLen > 0) {
73        unsigned char h = *inBuf / HEX_DIGIT_MAX_NUM;
74        unsigned char l = *inBuf % HEX_DIGIT_MAX_NUM;
75        if (h < DEC_MAX_NUM) {
76            *outBuf++ = '0' + h;
77        } else {
78            *outBuf++ = 'a' + h - DEC_MAX_NUM;
79        }
80        if (l < DEC_MAX_NUM) {
81            *outBuf++ = '0' + l;
82        } else {
83            *outBuf++ = 'a' + l - DEC_MAX_NUM;
84        }
85        ++inBuf;
86        inLen--;
87    }
88    return DM_OK;
89}
90
91std::string Crypto::Sha256(const std::string &text, bool isUpper)
92{
93    return Sha256(text.data(), text.size(), isUpper);
94}
95
96std::string Crypto::Sha256(const void *data, size_t size, bool isUpper)
97{
98    unsigned char hash[SHA256_DIGEST_LENGTH * HEX_TO_UINT8 + 1] = "";
99    DmGenerateStrHash(data, size, hash, HexifyLen(SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH);
100    // here we translate sha256 hash to hexadecimal. each 8-bit char will be presented by two characters([0-9a-f])
101    const char* hexCode = isUpper ? "0123456789ABCDEF" : "0123456789abcdef";
102    for (int32_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
103        unsigned char value = hash[SHA256_DIGEST_LENGTH + i];
104        // uint8_t is 2 digits in hexadecimal.
105        hash[i * HEX_TO_UINT8] = hexCode[(value >> WIDTH) & MASK];
106        hash[i * HEX_TO_UINT8 + 1] = hexCode[value & MASK];
107    }
108    hash[SHA256_DIGEST_LENGTH * HEX_TO_UINT8] = 0;
109    std::stringstream ss;
110    ss << hash;
111    return ss.str();
112}
113
114int32_t Crypto::GetUdidHash(const std::string &udid, unsigned char *udidHash)
115{
116    unsigned char hash[SHA256_DIGEST_LENGTH] = "";
117    DmGenerateStrHash(udid.data(), udid.size(), hash, SHA256_DIGEST_LENGTH, 0);
118    if (ConvertBytesToHexString(reinterpret_cast<char *>(udidHash), SHORT_DEVICE_ID_HASH_LENGTH + 1,
119        reinterpret_cast<const uint8_t *>(hash), SHORT_DEVICE_ID_HASH_LENGTH / HEX_TO_UINT8) != DM_OK) {
120        LOGE("ConvertBytesToHexString failed.");
121        return ERR_DM_FAILED;
122    }
123    return DM_OK;
124}
125
126int32_t Crypto::ConvertHexStringToBytes(unsigned char *outBuf, uint32_t outBufLen, const char *inBuf,
127    uint32_t inLen)
128{
129    (void)outBufLen;
130    if ((outBuf == NULL) || (inBuf == NULL) || (inLen % HEX_TO_UINT8 != 0)) {
131        LOGE("invalid param");
132        return ERR_DM_FAILED;
133    }
134
135    uint32_t outLen = inLen / HEX_TO_UINT8;
136    uint32_t i = 0;
137    while (i < outLen) {
138        unsigned char c = *inBuf++;
139        if ((c >= '0') && (c <= '9')) {
140            c -= '0';
141        } else if ((c >= 'a') && (c <= 'f')) {
142            c -= 'a' - DEC_MAX_NUM;
143        } else if ((c >= 'A') && (c <= 'F')) {
144            c -= 'A' - DEC_MAX_NUM;
145        } else {
146            LOGE("HexToString Error! %{public}c", c);
147            return ERR_DM_FAILED;
148        }
149        unsigned char c2 = *inBuf++;
150        if ((c2 >= '0') && (c2 <= '9')) {
151            c2 -= '0';
152        } else if ((c2 >= 'a') && (c2 <= 'f')) {
153            c2 -= 'a' - DEC_MAX_NUM;
154        } else if ((c2 >= 'A') && (c2 <= 'F')) {
155            c2 -= 'A' - DEC_MAX_NUM;
156        } else {
157            LOGE("HexToString Error! %{public}c", c2);
158            return ERR_DM_FAILED;
159        }
160        *outBuf++ = (c << HEX_MAX_BIT_NUM) | c2;
161        i++;
162    }
163    return DM_OK;
164}
165
166std::string Crypto::GetGroupIdHash(const std::string &groupId)
167{
168    unsigned char hash[SHA256_DIGEST_LENGTH] = "";
169    DmGenerateStrHash(groupId.data(), groupId.size(), hash, SHA256_DIGEST_LENGTH, 0);
170    std::stringstream ss;
171    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
172        ss << std::hex << (int)hash[i];
173    }
174    return ss.str().substr(0, SHORT_DEVICE_ID_HASH_LENGTH);
175}
176
177int32_t Crypto::GetSecRandom(uint8_t *out, size_t outLen)
178{
179    if (out == NULL) {
180        return DM_ERR;
181    }
182
183    if (outLen == 0) {
184        return DM_ERR;
185    }
186
187    RAND_poll();
188    RAND_bytes(out, outLen);
189    return DM_OK;
190}
191
192std::string Crypto::GetSecSalt()
193{
194    uint8_t out[SALT_LENGTH] = {0};
195    if (Crypto::GetSecRandom(out, SALT_LENGTH) != DM_OK) {
196        return SALT_DEFAULT;
197    }
198
199    char outHex[SALT_LENGTH * HEX_TO_UINT8 + 1] = {0};
200    if (ConvertBytesToHexString(outHex, SALT_LENGTH * HEX_TO_UINT8 + 1, out, SALT_LENGTH) != DM_OK) {
201        return SALT_DEFAULT;
202    }
203
204    return std::string(outHex);
205}
206
207std::string Crypto::GetHashWithSalt(const std::string &text, const std::string &salt)
208{
209    std::string rawText = text + salt;
210    return Crypto::Sha256(rawText);
211}
212
213int32_t Crypto::GetAccountIdHash(const std::string &accountId, unsigned char *accountIdHash)
214{
215    unsigned char hash[SHA256_DIGEST_LENGTH] = "";
216    DmGenerateStrHash(accountId.data(), accountId.size(), hash, SHA256_DIGEST_LENGTH, 0);
217    if (ConvertBytesToHexString(reinterpret_cast<char *>(accountIdHash), SHORT_ACCOUNTID_ID_HASH_LENGTH + 1,
218        reinterpret_cast<const uint8_t *>(hash), SHORT_ACCOUNTID_ID_HASH_LENGTH / HEX_TO_UINT8) != DM_OK) {
219        LOGE("ConvertBytesToHexString failed.");
220        return ERR_DM_FAILED;
221    }
222    return DM_OK;
223}
224
225#if !(defined(__LITEOS_M__) || defined(LITE_DEVICE))
226int32_t Crypto::ConvertUdidHashToAnoyAndSave(const std::string &appId, const std::string &udidHash,
227    DmKVValue &kvValue)
228{
229    if (GetAnoyDeviceInfo(appId, udidHash, kvValue) == DM_OK) {
230        kvValue.lastModifyTime = GetSecondsSince1970ToNow();
231        KVAdapterManager::GetInstance().PutByAnoyDeviceId(kvValue.anoyDeviceId, kvValue);
232        return DM_OK;
233    }
234    int32_t ret = ConvertUdidHashToAnoyGenerate(appId, udidHash, kvValue);
235    if (ret != DM_OK) {
236        LOGE("failed");
237        return ERR_DM_FAILED;
238    }
239    KVAdapterManager::GetInstance().PutByAnoyDeviceId(kvValue.anoyDeviceId, kvValue);
240    return DM_OK;
241}
242
243int32_t Crypto::ConvertUdidHashToAnoyDeviceId(const std::string &appId, const std::string &udidHash,
244    DmKVValue &kvValue)
245{
246    LOGI("start.");
247    if (GetAnoyDeviceInfo(appId, udidHash, kvValue) == DM_OK) {
248        return DM_OK;
249    }
250    return ConvertUdidHashToAnoyGenerate(appId, udidHash, kvValue);
251}
252
253int32_t Crypto::GetAnoyDeviceInfo(const std::string &appId, const std::string &udidHash, DmKVValue &kvValue)
254{
255    LOGI("start");
256    std::string udidPrefix = appId + DB_KEY_DELIMITER + udidHash;
257    if (KVAdapterManager::GetInstance().Get(udidPrefix, kvValue) != DM_OK) {
258        LOGI("Get kv value from DB failed");
259        return ERR_DM_FAILED;
260    }
261    return DM_OK;
262}
263
264int32_t Crypto::ConvertUdidHashToAnoyGenerate(const std::string &appId, const std::string &udidHash,
265    DmKVValue &kvValue)
266{
267    LOGI("start.");
268    std::string salt = GetSecSalt();
269    std::string udidTemp = appId + DB_KEY_DELIMITER + udidHash + DB_KEY_DELIMITER + salt;
270    char anoyDeviceId[DM_MAX_DEVICE_ID_LEN] = {0};
271    if (GetUdidHash(udidTemp, reinterpret_cast<uint8_t *>(anoyDeviceId)) != DM_OK) {
272        LOGE("get anoyDeviceId by udidTemp failed.");
273        return ERR_DM_FAILED;
274    }
275    kvValue.udidHash = udidHash;
276    kvValue.anoyDeviceId = std::string(anoyDeviceId);
277    kvValue.appID = appId;
278    kvValue.salt = salt;
279    kvValue.lastModifyTime = GetSecondsSince1970ToNow();
280    return DM_OK;
281}
282#endif
283} // namespace DistributedHardware
284} // namespace OHOS
285