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