/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "SECURITYMANAGER" #include "security_manager.h" #include #include #include #include #include "file_ex.h" #include "hks_api.h" #include "hks_param.h" #include "log_print.h" #include "securec.h" #include "store_types.h" #include "store_util.h" #include "task_executor.h" namespace OHOS::DistributedKv { SecurityManager::SecurityManager() { vecRootKeyAlias_ = std::vector(ROOT_KEY_ALIAS, ROOT_KEY_ALIAS + strlen(ROOT_KEY_ALIAS)); vecNonce_ = std::vector(HKS_BLOB_TYPE_NONCE, HKS_BLOB_TYPE_NONCE + strlen(HKS_BLOB_TYPE_NONCE)); vecAad_ = std::vector(HKS_BLOB_TYPE_AAD, HKS_BLOB_TYPE_AAD + strlen(HKS_BLOB_TYPE_AAD)); } SecurityManager::~SecurityManager() {} SecurityManager &SecurityManager::GetInstance() { static SecurityManager instance; return instance; } bool SecurityManager::Retry() { auto status = CheckRootKey(); if (status == HKS_SUCCESS) { hasRootKey_ = true; ZLOGE("root key already exist."); return true; } if (status == HKS_ERROR_NOT_EXIST && GenerateRootKey() == HKS_SUCCESS) { hasRootKey_ = true; ZLOGE("GenerateRootKey success."); return true; } constexpr int32_t interval = 100; TaskExecutor::GetInstance().Schedule(std::chrono::milliseconds(interval), [this] { Retry(); }); return false; } SecurityManager::DBPassword SecurityManager::GetDBPassword(const std::string &name, const std::string &path, bool needCreate) { DBPassword dbPassword; auto secKey = LoadKeyFromFile(name, path, dbPassword.isKeyOutdated); std::vector key{}; if (secKey.empty() && needCreate) { key = Random(KEY_SIZE); if (!SaveKeyToFile(name, path, key)) { secKey.assign(secKey.size(), 0); key.assign(key.size(), 0); return dbPassword; } } if ((!secKey.empty() && Decrypt(secKey, key)) || !key.empty()) { dbPassword.SetValue(key.data(), key.size()); } secKey.assign(secKey.size(), 0); key.assign(key.size(), 0); return dbPassword; } bool SecurityManager::SaveDBPassword(const std::string &name, const std::string &path, const DistributedDB::CipherPassword &key) { std::vector pwd(key.GetData(), key.GetData() + key.GetSize()); auto result = SaveKeyToFile(name, path, pwd); pwd.assign(pwd.size(), 0); return result; } void SecurityManager::DelDBPassword(const std::string &name, const std::string &path) { auto keyPath = path + "/key/" + name + ".key"; StoreUtil::Remove(keyPath); } std::vector SecurityManager::Random(int32_t len) { std::random_device randomDevice; std::uniform_int_distribution distribution(0, std::numeric_limits::max()); std::vector key(len); for (int32_t i = 0; i < len; i++) { key[i] = static_cast(distribution(randomDevice)); } return key; } std::vector SecurityManager::LoadKeyFromFile(const std::string &name, const std::string &path, bool &isOutdated) { auto keyPath = path + "/key/" + name + ".key"; if (!FileExists(keyPath)) { return {}; } StoreUtil::RemoveRWXForOthers(path + "/key"); std::vector content; auto loaded = LoadBufferFromFile(keyPath, content); if (!loaded) { return {}; } if (content.size() < (sizeof(time_t) / sizeof(uint8_t)) + KEY_SIZE + 1) { return {}; } size_t offset = 0; if (content[offset] != char((sizeof(time_t) / sizeof(uint8_t)) + KEY_SIZE)) { return {}; } offset++; std::vector date; date.assign(content.begin() + offset, content.begin() + (sizeof(time_t) / sizeof(uint8_t)) + offset); isOutdated = IsKeyOutdated(date); offset += (sizeof(time_t) / sizeof(uint8_t)); std::vector key{ content.begin() + offset, content.end() }; content.assign(content.size(), 0); return key; } bool SecurityManager::SaveKeyToFile(const std::string &name, const std::string &path, std::vector &key) { if (!hasRootKey_ && !Retry()) { ZLOGE("failed! no root key and generation failed"); return false; } auto secretKey = Encrypt(key); auto keyPath = path + "/key"; StoreUtil::InitPath(keyPath); std::vector content; auto time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::system_clock::now()); std::vector date(reinterpret_cast(&time), reinterpret_cast(&time) + sizeof(time)); content.push_back(char((sizeof(time_t) / sizeof(uint8_t)) + KEY_SIZE)); content.insert(content.end(), date.begin(), date.end()); content.insert(content.end(), secretKey.begin(), secretKey.end()); auto keyFullPath = keyPath + "/" + name + ".key"; auto ret = SaveBufferToFile(keyFullPath, content); if (access(keyFullPath.c_str(), F_OK) == 0) { StoreUtil::RemoveRWXForOthers(keyFullPath); } content.assign(content.size(), 0); if (!ret) { ZLOGE("client SaveSecretKey failed!"); return false; } return ret; } std::vector SecurityManager::Encrypt(const std::vector &key) { struct HksBlob blobAad = { uint32_t(vecAad_.size()), vecAad_.data() }; struct HksBlob blobNonce = { uint32_t(vecNonce_.size()), vecNonce_.data() }; struct HksBlob rootKeyName = { uint32_t(vecRootKeyAlias_.size()), vecRootKeyAlias_.data() }; struct HksBlob plainKey = { uint32_t(key.size()), const_cast(key.data()) }; struct HksParamSet *params = nullptr; int32_t ret = HksInitParamSet(¶ms); if (ret != HKS_SUCCESS) { ZLOGE("HksInitParamSet failed, status: %{public}d", ret); return {}; } struct HksParam hksParam[] = { { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT }, { .tag = HKS_TAG_DIGEST, .uint32Param = 0 }, { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, { .tag = HKS_TAG_NONCE, .blob = blobNonce }, { .tag = HKS_TAG_ASSOCIATED_DATA, .blob = blobAad }, { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE }, }; ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); if (ret != HKS_SUCCESS) { ZLOGE("HksAddParams failed, status: %{public}d", ret); HksFreeParamSet(¶ms); return {}; } ret = HksBuildParamSet(¶ms); if (ret != HKS_SUCCESS) { ZLOGE("HksBuildParamSet failed, status: %{public}d", ret); HksFreeParamSet(¶ms); return {}; } uint8_t cipherBuf[256] = { 0 }; struct HksBlob cipherText = { sizeof(cipherBuf), cipherBuf }; ret = HksEncrypt(&rootKeyName, params, &plainKey, &cipherText); (void)HksFreeParamSet(¶ms); if (ret != HKS_SUCCESS) { ZLOGE("HksEncrypt failed, status: %{public}d", ret); return {}; } std::vector encryptedKey(cipherText.data, cipherText.data + cipherText.size); (void)memset_s(cipherBuf, sizeof(cipherBuf), 0, sizeof(cipherBuf)); return encryptedKey; } bool SecurityManager::Decrypt(std::vector &source, std::vector &key) { struct HksBlob blobAad = { uint32_t(vecAad_.size()), &(vecAad_[0]) }; struct HksBlob blobNonce = { uint32_t(vecNonce_.size()), &(vecNonce_[0]) }; struct HksBlob rootKeyName = { uint32_t(vecRootKeyAlias_.size()), &(vecRootKeyAlias_[0]) }; struct HksBlob encryptedKeyBlob = { uint32_t(source.size()), source.data() }; struct HksParamSet *params = nullptr; int32_t ret = HksInitParamSet(¶ms); if (ret != HKS_SUCCESS) { ZLOGE("HksInitParamSet failed, status: %{public}d", ret); return false; } struct HksParam hksParam[] = { { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_DECRYPT }, { .tag = HKS_TAG_DIGEST, .uint32Param = 0 }, { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, { .tag = HKS_TAG_NONCE, .blob = blobNonce }, { .tag = HKS_TAG_ASSOCIATED_DATA, .blob = blobAad }, { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE }, }; ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); if (ret != HKS_SUCCESS) { ZLOGE("HksAddParams failed, status: %{public}d", ret); HksFreeParamSet(¶ms); return false; } ret = HksBuildParamSet(¶ms); if (ret != HKS_SUCCESS) { ZLOGE("HksBuildParamSet failed, status: %{public}d", ret); HksFreeParamSet(¶ms); return false; } uint8_t plainBuf[256] = { 0 }; struct HksBlob plainKeyBlob = { sizeof(plainBuf), plainBuf }; ret = HksDecrypt(&rootKeyName, params, &encryptedKeyBlob, &plainKeyBlob); (void)HksFreeParamSet(¶ms); if (ret != HKS_SUCCESS) { ZLOGE("HksDecrypt, status: %{public}d", ret); return false; } key.assign(plainKeyBlob.data, plainKeyBlob.data + plainKeyBlob.size); (void)memset_s(plainBuf, sizeof(plainBuf), 0, sizeof(plainBuf)); return true; } int32_t SecurityManager::GenerateRootKey() { struct HksBlob rootKeyName = { uint32_t(vecRootKeyAlias_.size()), vecRootKeyAlias_.data() }; struct HksParamSet *params = nullptr; int32_t ret = HksInitParamSet(¶ms); if (ret != HKS_SUCCESS) { ZLOGE("HksInitParamSet failed, status: %{public}d", ret); return ret; } struct HksParam hksParam[] = { { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, { .tag = HKS_TAG_KEY_SIZE, .uint32Param = HKS_AES_KEY_SIZE_256 }, { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT | HKS_KEY_PURPOSE_DECRYPT }, { .tag = HKS_TAG_DIGEST, .uint32Param = 0 }, { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE }, }; ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); if (ret != HKS_SUCCESS) { ZLOGE("HksAddParams failed, status: %{public}d", ret); HksFreeParamSet(¶ms); return ret; } ret = HksBuildParamSet(¶ms); if (ret != HKS_SUCCESS) { ZLOGE("HksBuildParamSet failed, status: %{public}d", ret); HksFreeParamSet(¶ms); return ret; } ret = HksGenerateKey(&rootKeyName, params, nullptr); HksFreeParamSet(¶ms); ZLOGI("HksGenerateKey status: %{public}d", ret); return ret; } int32_t SecurityManager::CheckRootKey() { struct HksBlob rootKeyName = { uint32_t(vecRootKeyAlias_.size()), vecRootKeyAlias_.data() }; struct HksParamSet *params = nullptr; int32_t ret = HksInitParamSet(¶ms); if (ret != HKS_SUCCESS) { ZLOGE("HksInitParamSet failed, status: %{public}d", ret); return ret; } struct HksParam hksParam[] = { { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, { .tag = HKS_TAG_KEY_SIZE, .uint32Param = HKS_AES_KEY_SIZE_256 }, { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT | HKS_KEY_PURPOSE_DECRYPT }, { .tag = HKS_TAG_DIGEST, .uint32Param = 0 }, { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE }, }; ret = HksAddParams(params, hksParam, sizeof(hksParam) / sizeof(hksParam[0])); if (ret != HKS_SUCCESS) { ZLOGE("HksAddParams failed, status: %{public}d", ret); HksFreeParamSet(¶ms); return ret; } ret = HksBuildParamSet(¶ms); if (ret != HKS_SUCCESS) { ZLOGE("HksBuildParamSet failed, status: %{public}d", ret); HksFreeParamSet(¶ms); return ret; } ret = HksKeyExist(&rootKeyName, params); HksFreeParamSet(¶ms); ZLOGI("HksKeyExist status: %{public}d", ret); return ret; } bool SecurityManager::IsKeyOutdated(const std::vector &date) { time_t time = *reinterpret_cast(const_cast(&date[0])); auto createTime = std::chrono::system_clock::from_time_t(time); return ((createTime + std::chrono::hours(HOURS_PER_YEAR)) < std::chrono::system_clock::now()); } } // namespace OHOS::DistributedKv