* Copyright (c) 2026 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.
*/
#include "crypto_wrapper.h"
#include <cstring>
#include <openssl/rand.h>
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/crypto.h>
#include "saf_log.h"
#include "saf_result_code.h"
const int32_t MAX_INPUT_SIZE = 1024 * 1024;
int32_t GenerateRandomBytes(Uint8Buff *buf)
{
if (buf == nullptr || buf->buf == nullptr || buf->size == 0) {
LOGE("[FATAL]GenerateRandomBytes invalid params.");
return SAF_ERR_NULL_PTR;
}
int ret = RAND_bytes(buf->buf, buf->size);
if (ret != 1) {
LOGE("[FATAL]RAND_bytes failed, ret: %{public}d.", ret);
return SAF_ERR_CRYPTO_OPERATION;
}
return SAF_SUCCESS;
}
int32_t ComputeHmacSha256(const Uint8Buff *key, const Uint8Buff *data, Uint8Buff *hmac)
{
if (key == nullptr || key->buf == nullptr || data == nullptr || data->buf == nullptr ||
hmac == nullptr || hmac->buf == nullptr) {
LOGE("[FATAL]ComputeHmacSha256 invalid params.");
return SAF_ERR_NULL_PTR;
}
if (hmac->size < HMAC_SHA256_SIZE) {
LOGE("[FATAL]ComputeHmacSha256 hmac buffer too small.");
return SAF_ERR_INVALID_HMAC_SIZE;
}
unsigned int len = HMAC_SHA256_SIZE;
uint8_t *result =
HMAC(EVP_sha256(), key->buf, key->size, data->buf, static_cast<size_t>(data->size), hmac->buf, &len);
if (result == nullptr) {
LOGE("[FATAL]HMAC computation failed.");
return SAF_ERR_CRYPTO_OPERATION;
}
return SAF_SUCCESS;
}
int32_t VerifyHmacSha256(const Uint8Buff *key, const Uint8Buff *data, const Uint8Buff *expectedHmac)
{
if (expectedHmac == nullptr || expectedHmac->buf == nullptr ||
expectedHmac->size != HMAC_SHA256_SIZE) {
LOGE("[FATAL]VerifyHmacSha256 invalid params.");
return SAF_ERR_NULL_PTR;
}
uint8_t computedHmac[HMAC_SHA256_SIZE];
Uint8Buff computedBuf = { computedHmac, HMAC_SHA256_SIZE };
int32_t ret = ComputeHmacSha256(key, data, &computedBuf);
if (ret != SAF_SUCCESS) {
return ret;
}
if (CRYPTO_memcmp(computedHmac, expectedHmac->buf, HMAC_SHA256_SIZE) != 0) {
LOGE("[FATAL]VerifyHmacSha256 hmac mismatch.");
return SAF_EVALUATE_DENY;
}
return SAF_SUCCESS;
}
int32_t Base64Encode(const Uint8Buff *input, Uint8Buff *output)
{
if (input == nullptr || input->buf == nullptr || output == nullptr || output->buf == nullptr) {
LOGE("[FATAL]Base64Encode invalid params.");
return SAF_ERR_NULL_PTR;
}
if (input->size > MAX_INPUT_SIZE) {
LOGE("[FATAL]Base64Encode input size too large.");
return SAF_ERR_BASE64_INVALID_LEN;
}
size_t expectedLen = 4 * ((input->size + 2) / 3) + 1;
if (output->size < expectedLen) {
LOGE("[FATAL]Base64Encode output buffer too small.");
return SAF_ERR_BASE64_INVALID_LEN;
}
int len = EVP_EncodeBlock(output->buf, input->buf, input->size);
if (len < 0) {
LOGE("[FATAL]EVP_EncodeBlock failed.");
return SAF_ERR_CRYPTO_OPERATION;
}
output->size = static_cast<uint32_t>(len);
return SAF_SUCCESS;
}
int32_t Base64Decode(const Uint8Buff *input, Uint8Buff *output)
{
if (input == nullptr || input->buf == nullptr || output == nullptr || output->buf == nullptr) {
LOGE("[FATAL]Base64Decode invalid params.");
return SAF_ERR_NULL_PTR;
}
if (input->size == 0) {
LOGE("[FATAL]Base64Decode invalid input size.");
return SAF_ERR_BASE64_INVALID_LEN;
}
size_t expectedLen = 3 * input->size / 4;
if (output->size < expectedLen) {
LOGE("[FATAL]Base64Decode output buffer too small.");
return SAF_ERR_BASE64_INVALID_LEN;
}
int len = EVP_DecodeBlock(output->buf, input->buf, input->size);
if (len < 0) {
LOGE("[FATAL]EVP_DecodeBlock failed, len = %{public}d.", len);
return SAF_ERR_CRYPTO_OPERATION;
}
size_t padding = 0;
for (int32_t i = input->size - 1; i >= 0 && input->buf[i] == '='; --i) {
padding++;
}
if (padding > static_cast<size_t>(len)) {
LOGE("[FATAL]padding is greater than len, len = %{public}d.", len);
return SAF_ERR_CRYPTO_OPERATION;
}
len -= padding;
output->size = static_cast<uint32_t>(len);
return SAF_SUCCESS;
}