# laoqianjunzi-crypto `laoqianjunzi-crypto` 是一个面向 `uni-app x` 的多端加密工具插件,统一封装了文本编解码、摘要、HMAC、AES、DES、3DES、RC4、RSA 等常见能力。 插件当前覆盖以下平台: - `App-Android` - `App-iOS` - `App-Harmony` - `Web` - `微信小程序` 适合以下场景: - 业务请求签名、摘要校验、口令派生前的基础处理 - 本地敏感文本或字节数据加解密 - 公私钥生成、RSA 短文本加解密 - 需要在多端复用同一套加密接口的 `uni-app x` 项目 ## 功能概览 - 支持 `utf8`、`hex`、`base64`、`base64url`、`latin1`、`utf16` 编解码 - 支持 `md5`、`sha1`、`sha256`、`sha512` 摘要 - 支持 `HMAC-SHA1`、`HMAC-SHA256`、`HMAC-SHA512` - 支持 AES 文本加解密与 AES 字节数组加解密 - 支持 DES、3DES、RC4 文本加解密 - 支持 RSA 密钥对生成与短文本加解密 - 支持读取当前运行时的底层引擎信息 - 所有计算均在本地执行,不包含网络上传逻辑 ## 版本要求 根据插件当前 `package.json` 配置,建议使用以下环境: - `HBuilderX` `5.07` 或更高版本 - `uni-app x` `4.75` 或更高版本 ## 平台支持矩阵 | 平台 | 加密能力 | RSA | 运行时引擎 | | --- | --- | --- | --- | | App-Android | 支持 | 支持 | `JCA` 原生桥接 | | App-iOS | 支持 | 支持 | `CommonCrypto` 原生桥接 | | App-Harmony | 支持 | 支持 | `@ohos/crypto-js` + 原生 RSA | | Web | 支持 | 支持 | `crypto-es` + `jsencrypt` | | 微信小程序 | 支持 | 支持 | `crypto-es` + `jsencrypt` | 说明: - `describeCryptoRuntime()` 可返回当前平台名、底层引擎名、是否支持高级分组模式、是否经过原生桥接 - Web 与微信小程序端的实现基于纯脚本运行时,App 端优先走原生桥接 - 文本加密、文本解密、摘要、签名、RSA 等接口均采用统一函数签名,便于业务跨端复用 ## 安装与导入 将插件放入项目 `uni_modules` 目录后,直接从插件根目录导入: ```uts import { aesDecryptBytes, aesDecryptText, aesEncryptBytes, aesEncryptText, createRsaPair, decodeText, defaultByteCipherOptions, defaultTextCipherOptions, describeCryptoRuntime, digestText, encodeText, rsaDecryptText, rsaEncryptText, signText } from "@/uni_modules/laoqianjunzi-crypto" import type { CryptoByteCipherOptions, CryptoRsaPair, CryptoRuntimeSnapshot, CryptoTextCipherOptions } from "@/uni_modules/laoqianjunzi-crypto" ``` 请注意: - 只从插件根目录导入,不要直接导入插件内部 `utssdk` 文件 - 业务代码建议统一使用插件根导出,便于后续维护和跨端类型识别 ## 快速开始 下面示例演示最常用的四类能力:运行时信息、文本编解码、摘要/HMAC、AES 文本加解密、RSA 密钥对与短文本加解密。 ```uts import { aesDecryptText, aesEncryptText, createRsaPair, decodeText, defaultTextCipherOptions, describeCryptoRuntime, digestText, encodeText, rsaDecryptText, rsaEncryptText, signText } from "@/uni_modules/laoqianjunzi-crypto" import type { CryptoRsaPair, CryptoRuntimeSnapshot, CryptoTextCipherOptions } from "@/uni_modules/laoqianjunzi-crypto" function runCryptoDemo(): void { const runtime: CryptoRuntimeSnapshot = describeCryptoRuntime() console.log("runtime", runtime.platformName, runtime.engineName) const plainText = "Hello uni-app x" const secretText = "1234567890abcdef" const ivText = "fedcba0987654321" const base64Text = encodeText("base64", plainText) const restoreText = decodeText("base64", base64Text) console.log("base64", base64Text) console.log("restore", restoreText) const sha256Text = digestText("sha256", plainText) const hmacText = signText("sha256", "sign-key", plainText) console.log("sha256", sha256Text) console.log("hmac", hmacText) const aesOptions: CryptoTextCipherOptions = defaultTextCipherOptions() aesOptions.mode = "CBC" aesOptions.padding = "PKCS7" aesOptions.ivText = ivText aesOptions.keyLength = 16 const aesCipherText = aesEncryptText(secretText, plainText, aesOptions) const aesPlainText = aesDecryptText(secretText, aesCipherText, aesOptions) console.log("aes cipher", aesCipherText) console.log("aes plain", aesPlainText) const rsaPair: CryptoRsaPair = createRsaPair(2048) const rsaCipherText = rsaEncryptText(rsaPair.publicKey, plainText, "base64") const rsaPlainText = rsaDecryptText(rsaPair.privateKey, rsaCipherText, "base64") console.log("rsa plain", rsaPlainText) } ``` ## AES 字节数组示例 如果你的业务处理的是二进制数据,而不是普通字符串,建议使用字节接口: ```uts import { aesDecryptBytes, aesEncryptBytes, defaultByteCipherOptions } from "@/uni_modules/laoqianjunzi-crypto" import type { CryptoByteCipherOptions } from "@/uni_modules/laoqianjunzi-crypto" function textToBytes(input: string): Uint8Array { const output = new Uint8Array(input.length) let index = 0 while (index < input.length) { const code = input.charCodeAt(index) output[index] = code == null ? 0 : code & 0xff index += 1 } return output } function bytesToText(input: Uint8Array): string { let output = "" let index = 0 while (index < input.length) { output += String.fromCharCode(input[index]) index += 1 } return output } function runByteCipherDemo(): void { const options: CryptoByteCipherOptions = defaultByteCipherOptions() options.mode = "CTR" options.padding = "PKCS7" options.keyLength = 16 const secretBytes = textToBytes("1234567890abcdef") const plainBytes = textToBytes("hello-bytes") const cipherBytes = aesEncryptBytes(secretBytes, plainBytes, options) const restoreBytes = aesDecryptBytes(secretBytes, cipherBytes, options) console.log("byte plain", bytesToText(restoreBytes)) console.log("cipher length", cipherBytes.length) } ``` ## 对外类型 ### CryptoDigestKind 摘要算法枚举: - `md5` - `sha1` - `sha256` - `sha512` ### CryptoMacKind HMAC 算法枚举: - `sha1` - `sha256` - `sha512` ### CryptoCodecKind 文本编解码枚举: - `utf8` - `hex` - `base64` - `base64url` - `latin1` - `utf16` ### CryptoBlockMode 分组模式枚举: - `ECB` - `CBC` - `CFB` - `CTR` - `CTRGladman` - `OFB` ### CryptoPaddingKind 填充模式枚举: - `PKCS7` - `ANSI_X923` - `ISO_10126` - `ISO_97971` - `NONE` - `ZERO` ### RsaOutputKind RSA 密文输出格式: - `base64` - `hex` ### CryptoTextCipherOptions AES 文本加解密参数: | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `mode` | `CryptoBlockMode` | 是 | 分组模式 | | `padding` | `CryptoPaddingKind` | 是 | 填充模式 | | `ivText` | `string \\| null` | 是 | 初始向量文本,`ECB` 模式可传 `null` | | `keyLength` | `number \\| null` | 是 | AES 密钥长度,建议传 `16`、`24`、`32` | ### CryptoByteCipherOptions AES 字节加解密参数: | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `mode` | `CryptoBlockMode` | 是 | 分组模式 | | `padding` | `CryptoPaddingKind` | 是 | 填充模式 | | `ivBytes` | `Uint8Array \\| null` | 是 | 初始向量字节数组,`ECB` 模式可传 `null` | | `keyLength` | `number \\| null` | 是 | AES 密钥长度,建议传 `16`、`24`、`32` | ### CryptoTripleDesOptions 3DES 参数: | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `mode` | `"ECB" \\| "CBC"` | 是 | 3DES 当前支持的分组模式 | | `ivText` | `string \\| null` | 是 | 初始向量文本,`ECB` 模式可传 `null` | ### CryptoDesOptions DES 参数: | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `mode` | `CryptoBlockMode` | 是 | 分组模式 | | `padding` | `CryptoPaddingKind` | 是 | 填充模式 | | `ivText` | `string \\| null` | 是 | 初始向量文本,`ECB` 模式可传 `null` | ### CryptoRsaPair RSA 密钥对对象: | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `publicKey` | `string` | 是 | 公钥 PEM 文本 | | `privateKey` | `string` | 是 | 私钥 PEM 文本 | ### CryptoRuntimeSnapshot 运行时描述对象: | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `platformName` | `string` | 是 | 平台名称 | | `engineName` | `string` | 是 | 当前底层实现名称 | | `supportsAdvancedModes` | `boolean` | 是 | 是否支持高级分组模式 | | `usesNativeBridge` | `boolean` | 是 | 是否经过原生桥接 | ## 默认参数函数 ### defaultTextCipherOptions() 返回 AES 文本加解密默认参数: | 字段 | 默认值 | | --- | --- | | `mode` | `CBC` | | `padding` | `PKCS7` | | `ivText` | `0123456789abcdef` | | `keyLength` | `16` | ### defaultByteCipherOptions() 返回 AES 字节加解密默认参数: | 字段 | 默认值 | | --- | --- | | `mode` | `CBC` | | `padding` | `PKCS7` | | `ivBytes` | `0123456789abcdef` 的 ASCII 字节 | | `keyLength` | `16` | ### defaultTripleDesOptions() 返回 3DES 默认参数: | 字段 | 默认值 | | --- | --- | | `mode` | `CBC` | | `ivText` | `12345678` | ### defaultDesOptions() 返回 DES 默认参数: | 字段 | 默认值 | | --- | --- | | `mode` | `CBC` | | `padding` | `PKCS7` | | `ivText` | `12345678` | ## 运行时信息函数 ### describeCryptoRuntime() 返回当前平台的运行时信息: ```uts const runtime = describeCryptoRuntime() console.log(runtime.platformName) console.log(runtime.engineName) console.log(runtime.supportsAdvancedModes) console.log(runtime.usesNativeBridge) ``` ## API 清单 ### 编解码 | 函数 | 说明 | 返回值 | | --- | --- | --- | | `encodeText(codec, plainText)` | 将普通文本编码为指定格式文本 | `string` | | `decodeText(codec, encodedText)` | 将指定格式文本还原为普通文本 | `string` | ### 摘要与签名 | 函数 | 说明 | 返回值 | | --- | --- | --- | | `digestText(kind, plainText)` | 计算摘要,结果为十六进制字符串 | `string` | | `signText(kind, secretText, plainText)` | 计算 HMAC,结果为十六进制字符串 | `string` | ### AES 文本加解密 | 函数 | 说明 | 返回值 | | --- | --- | --- | | `aesEncryptText(secretText, plainText, options)` | 使用文本密钥加密文本 | `string` | | `aesDecryptText(secretText, cipherText, options)` | 使用文本密钥解密文本 | `string` | ### AES 字节加解密 | 函数 | 说明 | 返回值 | | --- | --- | --- | | `aesEncryptBytes(secretBytes, plainBytes, options)` | 使用字节密钥加密字节数组 | `Uint8Array` | | `aesDecryptBytes(secretBytes, cipherBytes, options)` | 使用字节密钥解密字节数组 | `Uint8Array` | ### 3DES | 函数 | 说明 | 返回值 | | --- | --- | --- | | `tripleDesEncryptText(secretText, plainText, options)` | 3DES 文本加密 | `string` | | `tripleDesDecryptText(secretText, cipherText, options)` | 3DES 文本解密 | `string` | ### DES | 函数 | 说明 | 返回值 | | --- | --- | --- | | `desEncryptText(secretText, plainText, options)` | DES 文本加密 | `string` | | `desDecryptText(secretText, cipherText, options)` | DES 文本解密 | `string` | ### RC4 | 函数 | 说明 | 返回值 | | --- | --- | --- | | `rc4EncryptText(secretText, plainText)` | RC4 加密,返回十六进制密文 | `string` | | `rc4DecryptText(secretText, cipherHexText)` | RC4 解密十六进制密文 | `string` | ### RSA | 函数 | 说明 | 返回值 | | --- | --- | --- | | `createRsaPair(keySize)` | 生成 RSA 密钥对 | `CryptoRsaPair` | | `rsaEncryptText(publicKey, plainText, outputKind)` | 使用公钥加密短文本 | `string` | | `rsaDecryptText(privateKey, cipherText, outputKind)` | 使用私钥解密短文本 | `string` | 建议: - `keySize` 推荐使用 `1024`、`2048`、`3072`、`4096` - 一般业务默认建议使用 `2048` ## 使用建议 - 编解码、摘要、HMAC 建议直接使用字符串接口,返回值稳定、便于日志记录和接口传输 - 处理图片片段、协议报文、蓝牙包、文件块等二进制内容时,优先使用 `aesEncryptBytes` 与 `aesDecryptBytes` - AES 跨端调用时,`keyLength` 建议固定传 `16`、`24`、`32` 之一,避免不同运行时对推断长度的理解差异 - 使用 `CBC`、`CFB`、`CTR`、`OFB` 等模式时,建议显式传入业务自定义 `ivText` 或 `ivBytes` - `RSA` 更适合短文本、密钥交换或签名相关前置处理,不适合大体积正文直接加解密 - `RC4`、`DES`、`3DES` 更适用于兼容特定协议场景,新业务优先建议选择 `AES` 或 `RSA` ## 异常处理建议 参数不合法、密文格式不正确、密钥与向量不匹配时,接口可能抛出错误。业务代码建议统一使用 `try/catch` 包裹: ```uts import { aesEncryptText, defaultTextCipherOptions } from "@/uni_modules/laoqianjunzi-crypto" try { const options = defaultTextCipherOptions() const cipherText = aesEncryptText("1234567890abcdef", "hello", options) console.log(cipherText) } catch (error) { console.error("crypto error", error) } ``` ## 注意事项 - 本插件面向 `uni-app x`,不面向传统 `uni-app` 页面运行时 - 文本接口默认适合 UTF-8 文本场景;如果你的原始数据本身不是普通文本,请优先使用字节接口 - `ECB` 模式不依赖 IV,其余分组模式建议始终显式设置 IV - RSA 密文输出格式由 `outputKind` 控制,发送方与接收方应保持一致 - 通过 `default*Options()` 获取参数对象后,可按当前业务需求覆盖默认值 ## 示例页面 插件内已提供示例页面,可用于快速验证能力是否正常: - `uni_modules/laoqianjunzi-crypto/pages/index` 如果项目已在 `pages.json` 中注册该页面,可直接运行到对应页面进行体验。