1/* 2 * Copyright (c) 2022-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 "scrypt.h" 17#include <openssl/ossl_typ.h> 18#include <openssl/kdf.h> 19#include "securec.h" 20#include <unordered_map> 21#include "iam_logger.h" 22 23#define LOG_TAG "PIN_AUTH_SDK" 24 25namespace OHOS { 26namespace UserIam { 27namespace PinAuth { 28namespace { 29constexpr uint32_t OUT_LENGTH = 64; 30constexpr uint32_t SCRYPT_N_V0 = 32768; 31constexpr uint32_t SCRYPT_N_V1 = 2048; 32constexpr uint32_t SCRYPT_R = 8; 33constexpr uint32_t SCRYPT_P = 1; 34constexpr uint32_t SCRYPT_P_V3 = 2; 35 36struct ScryptParameters { 37 int32_t scryptN; 38 int32_t scryptR; 39 int32_t scryptP; 40}; 41 42std::unordered_map<uint32_t, ScryptParameters> g_version2Param_ = { 43 { PIN_ALGO_VERSION_V0, { SCRYPT_N_V0, SCRYPT_R, SCRYPT_P } }, 44 { PIN_ALGO_VERSION_V1, { SCRYPT_N_V1, SCRYPT_R, SCRYPT_P } }, 45 { PIN_ALGO_VERSION_V2, { SCRYPT_N_V1, SCRYPT_R, SCRYPT_P } }, 46 { PIN_ALGO_VERSION_V3, { SCRYPT_N_V1, SCRYPT_R, SCRYPT_P_V3 } } 47}; 48} 49 50bool Scrypt::DoScrypt(const std::vector<uint8_t> &data, uint32_t algoVersion, EVP_PKEY_CTX *pctx) 51{ 52 auto index = g_version2Param_.find(algoVersion); 53 if (index == g_version2Param_.end()) { 54 IAM_LOGE("version is not in g_version2Param_"); 55 return false; 56 } 57 ScryptParameters scryptParameters = index->second; 58 if (EVP_PKEY_CTX_set1_pbe_pass(pctx, reinterpret_cast<const char *>(data.data()), data.size()) <= 0) { 59 IAM_LOGE("EVP_PKEY_CTX_set1_pbe_pass fail"); 60 return false; 61 } 62 if (EVP_PKEY_CTX_set1_scrypt_salt(pctx, algoParameter_.data(), algoParameter_.size()) <= 0) { 63 IAM_LOGE("EVP_PKEY_CTX_set1_scrypt_salt fail"); 64 return false; 65 } 66 if (EVP_PKEY_CTX_set_scrypt_N(pctx, scryptParameters.scryptN) <= 0) { 67 IAM_LOGE("EVP_PKEY_CTX_set_scrypt_N fail"); 68 return false; 69 } 70 if (EVP_PKEY_CTX_set_scrypt_r(pctx, scryptParameters.scryptR) <= 0) { 71 IAM_LOGE("EVP_PKEY_CTX_set_scrypt_r fail"); 72 return false; 73 } 74 if (EVP_PKEY_CTX_set_scrypt_p(pctx, scryptParameters.scryptP) <= 0) { 75 IAM_LOGE("EVP_PKEY_CTX_set_scrypt_p fail"); 76 return false; 77 } 78 79 return true; 80} 81 82std::vector<uint8_t> Scrypt::GetScrypt(const std::vector<uint8_t> &data, uint32_t algoVersion) 83{ 84 IAM_LOGI("start"); 85 std::vector<uint8_t> out; 86 EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_SCRYPT, NULL); 87 if (EVP_PKEY_derive_init(pctx) <= 0) { 88 IAM_LOGE("EVP_PKEY_derive_init fail"); 89 return out; 90 } 91 92 if (!DoScrypt(data, algoVersion, pctx)) { 93 IAM_LOGE("DoScrypt fail"); 94 EVP_PKEY_CTX_free(pctx); 95 return out; 96 } 97 out.resize(OUT_LENGTH); 98 size_t outlen = out.size(); 99 if (EVP_PKEY_derive(pctx, out.data(), &outlen) <= 0) { 100 IAM_LOGE("EVP_PKEY_derive fail"); 101 EVP_PKEY_CTX_free(pctx); 102 (void)memset_s(out.data(), out.size(), 0, out.size()); 103 out.clear(); 104 return out; 105 } 106 107 EVP_PKEY_CTX_free(pctx); 108 return out; 109} 110} // namespace PinAuth 111} // namespace UserIam 112} // namespace OHOS