鸿蒙Des 加密解密 C++版本
写文档的时候,现在的 API 主流版本可能还是 API15 及以上,des 加密算法是在 API20 的时候才加入的。但是 API20 预计升级也是在 2025.10 月以后了。当前用到了 DES 加密解密,因此还是需要想办法实现一下的。
而且当前需要的是一个把 so 库的版本,需要把 Des 加密算法使用 c++实现,并且打包到 so 库中。
本文主要介绍一下,如何实现 Des 加密解密的 c++ 版本。
cryptopp 库
当然肯定不是自己实现一套加解密算法,现在是用的 cryptoPP 库,cryptoPP 库是一个开源的加解密库,支持多种加解密算法,包括 DES、AES、RSA 等。
cryptopp 项目地址:gitcode.com/openharmony...
下载项目代码
base
git clone https://gitcode.com/openharmony-sig/tpc_c_cplusplus.git
配置编译环境
下载 command line tools
developer.huawei.com/consumer/cn...
导出 OHOS_SDK 环境变量
base
export OHOS_SDK=~/command-line-tools/sdk/default/openharmony
拷贝必要鸿蒙平台的 cmake
这个地方可能要根据自己的本地的 cmake 地址来修改路径
base
cp command-line-tools/sdk/default/openharmony/native/build-tools/cmake/share/cmake-3.28/Modules/Platform/OHOS.cmake /opt/homebrew/Cellar/cmake/4.0.2/share/cmake/Modules/Platform/
进入到相应的编译工具文件夹
base
cd tpc_c_cplusplus/lycium/Buildtools
解压工具链
base
tar -zxvf toolchain.tar.gz
拷贝必要的编译工具
base
cp toolchain/\* command-line-tools/sdk/default/openharmony/native/llvm/bin/
进入到
tpc_c_cplusplus/lycium
开始编译
./build cryptopp
之后产物就在 lycium/usr 目录下 cd tpc_c_cplusplus/lycium/usr
在之后就可以根据文档来引入相关的库来编译 cryptopp
接入到项目中
如果是新项目,可以选择模版的时候创建 c++模版,这次主要说一下如何在已有项目中接入 c++库;
创建相应的目录
在 src/main 的目录下创建 cpp 文件夹。
cpp 文件夹下包含以下文件/文件夹:
bash
├── CMakeLists.txt // c++ cmake 编译文件
├── include // 头文件目录
├── napi_init.cpp // 同arkts交互的接口文件,一般逻辑都在这个地方
├── thirdparty // 第三方目录文件,刚才编译完的crypto的文件直接拷贝到这个地方
├── cryptopp
├── arm64-v8a
├── armeabi-v7a
├── types
├── libentry
├── Index.d.ts // 导出的so接口
├── oh-package.json5 // so的配置文件
CMakeLists.txt
bash
# the minimum version of CMake.
cmake_minimum_required(VERSION 3.5.0)
project(Encrypt) // 可以改一个名字,不过影响不大
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
if(DEFINED PACKAGE_FIND_FILE)
include(${PACKAGE_FIND_FILE})
endif()
include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include)
add_library(entry SHARED napi_init.cpp)
target_link_libraries(entry PUBLIC libace_napi.z.so)
target_link_libraries(entry PUBLIC libohcrypto.so)
target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so)
# 这个地方是 cryptopp 库的引入文件方式
#将三方库加入工程中
target_link_libraries(entry PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/cryptopp/${OHOS_ARCH}/lib/libcryptopp.a)
#将三方库的头文件加入工程中
target_include_directories(entry PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/cryptopp/${OHOS_ARCH}/include)
napi_init.cpp
实现了一个解密算法,加密算法稍微改改参数就可以了。
c
#include "napi/native_api.h"
#include <iostream>
#include <random>
#include <ctime>
#include <string.h>
#include <cstring>
#include "hilog/log.h"
#include "cryptopp/des.h"
#include "cryptopp/rsa.h"
#include "cryptopp/cryptlib.h"
#include "cryptopp/base64.h"
#include "cryptopp/filters.h"
#include "cryptopp/modes.h"
#include "cryptopp/hex.h"
#include "cryptopp/osrng.h"
#include "cryptopp/config_int.h"
std::string hexDecode(const std::string& hexStr) {
std::string decoded;
CryptoPP::StringSource ss(
hexStr, true,
new CryptoPP::HexDecoder(new CryptoPP::StringSink(decoded))
);
return decoded;
}
std::string generate_random_alphanumeric_string() {
const std::string charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const int length = 8; // 固定生成8位字符串
std::string result;
// 使用随机设备作为种子(更安全)[2,5](@ref)
std::random_device rd;
std::mt19937 generator(rd());
std::uniform_int_distribution<size_t> distribution(0, charset.size() - 1);
// 预分配空间以提高性能[5](@ref)
result.reserve(length);
for (int i = 0; i < length; ++i) {
result += charset[distribution(generator)];
}
return result;
}
static napi_value doDesDecrypt(napi_env env, napi_callback_info info)
{
size_t argc = 2;
napi_value args[2] = {nullptr};
napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
// 获取加密字符串
size_t encrypted_length = 0;
napi_status status = napi_get_value_string_utf8(env, args[0], nullptr, 0, &encrypted_length);
if (status != napi_ok) {
return nullptr;
}
char* encryptedStr = new char[encrypted_length + 1];
std::memset(encryptedStr, 0, encrypted_length + 1);
status = napi_get_value_string_utf8(env, args[0], encryptedStr, encrypted_length + 1, &encrypted_length);
if (status != napi_ok) {
if (encryptedStr) {
delete[] encryptedStr;
}
return nullptr;
}
napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
size_t key_length = 0;
napi_status status = napi_get_value_string_utf8(env, args[1], nullptr, 0, &key_length);
if (status != napi_ok) {
OH_LOG_ERROR(LOG_APP, "xxx get key failed");
return nullptr;
}
char* keyStr = new char[key_length + 1];
std::memset(keyStr, 0, key_length + 1);
status = napi_get_value_string_utf8(env, args[1], keyStr, key_length + 1, &key_length);
if (status != napi_ok) {
if (keyStr) {
delete[] keyStr;
}
OH_LOG_ERROR(LOG_APP, "xxx copy key failed");
return nullptr;
}
CryptoPP::ECB_Mode<CryptoPP::DES>::Decryption decryptor;
decryptor.SetKey(reinterpret_cast<const CryptoPP::byte*>(keyStr), key_length);
std::string decrypted;
CryptoPP::StringSource ss(
hexDecode(encryptedStr), true,
new CryptoPP::StreamTransformationFilter(
decryptor,
new CryptoPP::StringSink(decrypted)
)
);
napi_value result = nullptr;
status = napi_create_string_utf8(env, decrypted.data(), decrypted.size(), &result);
if (status != napi_ok) {
napi_throw_error(env, nullptr, "Failed to create UTF-8 string");
return nullptr;
}
return result;
}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
napi_property_descriptor desc[] = {
{ "decrypt", nullptr, doDesDecrypt, nullptr, nullptr, nullptr, napi_default, nullptr},
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}
EXTERN_C_END
static napi_module demoModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "entry",
.nm_priv = ((void*)0),
.reserved = { 0 },
};
extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
napi_module_register(&demoModule);
}
Index.d.ts
导出相应的函数,如果在 napi_init.cpp 中保存一个全局变量,那么在导出的函数中也能够使用。
javacript
export const decrypt: (encrypted: string, key: string) => string;
oh-package.json5
json
{
"name": "libentry.so",
"types": "./Index.d.ts",
"version": "1.0.0",
"description": "Please describe the basic information."
}
build-profile.json
然后需要在模块的编译配置中增加如下配置:
json
"buildOption": {
"externalNativeOptions": {
"path": "./src/main/cpp/CMakeLists.txt",
"arguments": "",
"cppFlags": "",
}
},
模块 package 依赖中增加 c++模块依赖
json
"dependencies": {
"libentry.so": "file:./src/main/cpp/types/libentry"
}
结束
这样基本上就完成了 c++模块的加密解密功能的实现,在 ts 中调用也比较方便。
javascript
import libEntry from 'libentry.so' // libEntry 是随便起了个名字
let res = libEntry.decrypt('des加密串', 'des密钥')