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