From 704e9650f97ca6491f5bcbec9ae3abffaeab206c Mon Sep 17 00:00:00 2001
From: xiaozhi <1822691309@qq.com>
Date: Sun, 7 Jun 2026 10:59:23 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AF=BC=E5=85=A5=E5=8A=A0?=
=?UTF-8?q?=E5=AF=86=E6=8F=92=E4=BB=B6"laoqianjunzi-crypto"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
uni_modules/laoqianjunzi-crypto/changelog.md | 2 +
uni_modules/laoqianjunzi-crypto/package.json | 104 ++
.../laoqianjunzi-crypto/pages/index.uvue | 518 ++++++++
uni_modules/laoqianjunzi-crypto/readme.md | 483 +++++++
.../utssdk/app-android/NativeCipherCore.kt | 744 +++++++++++
.../utssdk/app-android/config.json | 3 +
.../utssdk/app-android/index.uts | 241 ++++
.../utssdk/app-harmony/config.json | 5 +
.../utssdk/app-harmony/index.uts | 428 +++++++
.../utssdk/app-harmony/native_rsa.ets | 176 +++
.../utssdk/app-ios/NativeCipherCore.swift | 1130 +++++++++++++++++
.../utssdk/app-ios/index.uts | 251 ++++
.../utssdk/deps/package-lock.json | 28 +
.../utssdk/deps/package.json | 9 +
.../laoqianjunzi-crypto/utssdk/index.uts | 22 +
.../laoqianjunzi-crypto/utssdk/interface.uts | 58 +
.../utssdk/mp-weixin/index.uts | 209 +++
.../utssdk/shared/compat.uts | 771 +++++++++++
.../utssdk/shared/options.uts | 106 ++
.../utssdk/shared/portable_crypto.ts | 425 +++++++
.../laoqianjunzi-crypto/utssdk/unierror.uts | 27 +
.../laoqianjunzi-crypto/utssdk/web/index.uts | 209 +++
22 files changed, 5949 insertions(+)
create mode 100644 uni_modules/laoqianjunzi-crypto/changelog.md
create mode 100644 uni_modules/laoqianjunzi-crypto/package.json
create mode 100644 uni_modules/laoqianjunzi-crypto/pages/index.uvue
create mode 100644 uni_modules/laoqianjunzi-crypto/readme.md
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/app-android/NativeCipherCore.kt
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/app-android/config.json
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/app-android/index.uts
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/app-harmony/config.json
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/app-harmony/index.uts
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/app-harmony/native_rsa.ets
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/app-ios/NativeCipherCore.swift
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/app-ios/index.uts
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/deps/package-lock.json
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/deps/package.json
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/index.uts
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/interface.uts
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/mp-weixin/index.uts
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/shared/compat.uts
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/shared/options.uts
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/shared/portable_crypto.ts
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/unierror.uts
create mode 100644 uni_modules/laoqianjunzi-crypto/utssdk/web/index.uts
diff --git a/uni_modules/laoqianjunzi-crypto/changelog.md b/uni_modules/laoqianjunzi-crypto/changelog.md
new file mode 100644
index 0000000..23e8ff9
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/changelog.md
@@ -0,0 +1,2 @@
+## 1.0.0(2026-05-30)
+初次提交
diff --git a/uni_modules/laoqianjunzi-crypto/package.json b/uni_modules/laoqianjunzi-crypto/package.json
new file mode 100644
index 0000000..db510b7
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/package.json
@@ -0,0 +1,104 @@
+{
+ "id": "laoqianjunzi-crypto",
+ "displayName": "多端加密工具箱",
+ "version": "1.0.0",
+ "description": "为 uni-app x 提供 Android、iOS、Harmony、Web、微信小程序统一加密能力,覆盖摘要、编码、HMAC、AES、DES、RC4 与 RSA。",
+ "keywords": [
+ "crypto",
+ "hash",
+ "aes",
+ "rsa",
+ "uts"
+],
+ "repository": "",
+ "engines": {
+ "HBuilderX": "^5.07",
+ "uni-app": "",
+ "uni-app-x": "^4.75"
+ },
+ "dcloudext": {
+ "type": "uts",
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ },
+ "contact": {
+ "qq": ""
+ },
+ "declaration": {
+ "ads": "无",
+ "data": "所有加解密与编码运算均在本地执行,不内置远程上传逻辑",
+ "permissions": "无"
+ },
+ "darkmode": "√",
+ "i18n": "√",
+ "widescreen": "√",
+ "npmurl": "https://gitee.com/laoqianjunzi/laoqianjunzi-crypto"
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": [],
+ "platforms": {
+ "client": {
+ "uni-app": {
+ "vue": {
+ "vue2": "-",
+ "vue3": "-"
+ },
+ "web": {
+ "safari": "-",
+ "chrome": "-"
+ },
+ "app": {
+ "vue": "-",
+ "nvue": "-",
+ "android": "-",
+ "ios": "-",
+ "harmony": "-"
+ },
+ "mp": {
+ "weixin": "-",
+ "alipay": "-",
+ "toutiao": "-",
+ "baidu": "-",
+ "kuaishou": "-",
+ "jd": "-",
+ "harmony": "-",
+ "qq": "-",
+ "lark": "-"
+ },
+ "quickapp": {
+ "huawei": "-",
+ "union": "-"
+ }
+ },
+ "uni-app-x": {
+ "web": {
+ "safari": "√",
+ "chrome": "√"
+ },
+ "app": {
+ "android": {
+ "extVersion": "",
+ "minVersion": "21"
+ },
+ "ios": "√",
+ "harmony": "√"
+ },
+ "mp": {
+ "weixin": "√"
+ }
+ }
+ },
+ "cloud": {
+ "tcb": "√",
+ "aliyun": "√",
+ "alipay": "√"
+ }
+ }
+ }
+}
diff --git a/uni_modules/laoqianjunzi-crypto/pages/index.uvue b/uni_modules/laoqianjunzi-crypto/pages/index.uvue
new file mode 100644
index 0000000..39934b3
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/pages/index.uvue
@@ -0,0 +1,518 @@
+
+
+
+
+
+
+ LAOQIANJUNZI-CRYPTO
+ 统一加密能力演示
+ 这一页直接调用插件导出的新接口,集中演示编码、摘要、HMAC、AES、3DES、RC4、RSA 与字节数组加解密。
+
+
+
+ 运行时概览
+
+ 平台
+ {{ runtimeInfo.platformName }}
+
+
+ 引擎
+ {{ runtimeInfo.engineName }}
+
+
+ 高级模式
+ {{ runtimeInfo.supportsAdvancedModes ? '已启用' : '受限' }}
+
+
+ 原生桥接
+ {{ runtimeInfo.usesNativeBridge ? '是' : '否' }}
+
+
+
+
+ 输入参数
+
+ 明文
+
+
+
+ 主密钥
+
+
+
+ 向量
+
+
+
+ HMAC 密钥
+
+
+
+ 3DES 密钥
+
+
+
+ RSA 位数
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 编码
+ Base64: {{ codecBase64 }}
+ Hex: {{ codecHex }}
+ Base64url: {{ codecBase64url }}
+ 反解: {{ codecBackText }}
+
+
+
+ 摘要与签名
+ MD5: {{ md5Text }}
+ SHA256: {{ sha256Text }}
+ SHA512: {{ sha512Text }}
+ HMAC-SHA256: {{ hmacText }}
+
+
+
+ AES 文本
+ 密文: {{ aesCipherText }}
+ 解密: {{ aesPlainText }}
+
+
+
+ AES 字节
+ 字节密文: {{ aesByteCipherHex }}
+ 字节解密: {{ aesBytePlainText }}
+
+
+
+ 3DES 与 RC4
+ 3DES 密文: {{ tripleCipherText }}
+ 3DES 解密: {{ triplePlainText }}
+ RC4 密文: {{ rc4CipherHex }}
+ RC4 解密: {{ rc4PlainText }}
+
+
+
+ RSA
+ 公钥长度: {{ rsaPublicBrief }}
+ 私钥长度: {{ rsaPrivateBrief }}
+ RSA 密文: {{ rsaCipherText }}
+ RSA 解密: {{ rsaPlainText }}
+
+
+
+
+ 执行日志
+
+ {{ item }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uni_modules/laoqianjunzi-crypto/readme.md b/uni_modules/laoqianjunzi-crypto/readme.md
new file mode 100644
index 0000000..9df9147
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/readme.md
@@ -0,0 +1,483 @@
+# 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` 中注册该页面,可直接运行到对应页面进行体验。
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/app-android/NativeCipherCore.kt b/uni_modules/laoqianjunzi-crypto/utssdk/app-android/NativeCipherCore.kt
new file mode 100644
index 0000000..f751f82
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/app-android/NativeCipherCore.kt
@@ -0,0 +1,744 @@
+package uts.sdk.modules.laoqianjunziCrypto
+
+import android.util.Base64
+import java.io.ByteArrayOutputStream
+import java.nio.charset.StandardCharsets
+import java.security.GeneralSecurityException
+import java.security.KeyFactory
+import java.security.KeyPairGenerator
+import java.security.MessageDigest
+import java.security.SecureRandom
+import java.security.interfaces.RSAPrivateKey
+import java.security.interfaces.RSAPublicKey
+import java.security.spec.PKCS8EncodedKeySpec
+import java.security.spec.X509EncodedKeySpec
+import javax.crypto.Cipher
+import javax.crypto.Mac
+import javax.crypto.spec.IvParameterSpec
+import javax.crypto.spec.SecretKeySpec
+
+data class NativeRsaBundle(val publicKey: String, val privateKey: String)
+
+object NativeCipherCore {
+ private const val AES_BLOCK_SIZE = 16
+ private const val DES_BLOCK_SIZE = 8
+ private val secureRandom = SecureRandom()
+
+ fun digestHex(kind: String, plainText: String): String {
+ return try {
+ val digest = MessageDigest.getInstance(resolveDigestAlgorithm(kind))
+ toHex(digest.digest(plainText.toByteArray(StandardCharsets.UTF_8)))
+ } catch (e: IllegalArgumentException) {
+ throw e
+ } catch (e: Exception) {
+ throw IllegalStateException("摘要失败")
+ }
+ }
+
+ fun hmacHex(kind: String, secretText: String, plainText: String): String {
+ return try {
+ val mac = Mac.getInstance(resolveHmacAlgorithm(kind))
+ mac.init(SecretKeySpec(secretText.toByteArray(StandardCharsets.UTF_8), mac.algorithm))
+ toHex(mac.doFinal(plainText.toByteArray(StandardCharsets.UTF_8)))
+ } catch (e: IllegalArgumentException) {
+ throw e
+ } catch (e: Exception) {
+ throw IllegalStateException("HMAC失败")
+ }
+ }
+
+ fun encodeBase64(plainText: String): String {
+ return Base64.encodeToString(plainText.toByteArray(StandardCharsets.UTF_8), Base64.NO_WRAP)
+ }
+
+ fun decodeBase64(encodedText: String): String {
+ return try {
+ String(Base64.decode(encodedText, Base64.DEFAULT), StandardCharsets.UTF_8)
+ } catch (e: Exception) {
+ throw IllegalArgumentException("Base64无效")
+ }
+ }
+
+ fun encodeCodec(codec: String, plainText: String): String {
+ val bytes = plainText.toByteArray(StandardCharsets.UTF_8)
+ return when (codec.lowercase()) {
+ "utf8" -> plainText
+ "hex" -> toHex(bytes)
+ "base64" -> Base64.encodeToString(bytes, Base64.NO_WRAP)
+ "base64url" -> Base64.encodeToString(bytes, Base64.NO_WRAP)
+ .replace('+', '-')
+ .replace('/', '_')
+ .trimEnd('=')
+ "latin1" -> latin1FromBytes(bytes)
+ "utf16" -> utf16CodecFromBytes(bytes)
+ else -> throw IllegalArgumentException("不支持的编码类型")
+ }
+ }
+
+ fun decodeCodec(codec: String, encodedText: String): String {
+ return when (codec.lowercase()) {
+ "utf8" -> encodedText
+ "hex" -> String(fromHex(encodedText), StandardCharsets.UTF_8)
+ "base64" -> decodeBase64(encodedText)
+ "base64url" -> {
+ var normalized = encodedText.replace('-', '+').replace('_', '/')
+ while (normalized.length % 4 != 0) {
+ normalized += '='
+ }
+ decodeBase64(normalized)
+ }
+ "latin1" -> String(bytesFromLatin1(encodedText), StandardCharsets.UTF_8)
+ "utf16" -> String(bytesFromUtf16Codec(encodedText), StandardCharsets.UTF_8)
+ else -> throw IllegalArgumentException("不支持的编码类型")
+ }
+ }
+
+ fun aesEncryptText(
+ secretText: String,
+ plainText: String,
+ mode: String,
+ padding: String,
+ ivText: String?,
+ keyLength: Int?
+ ): String {
+ val cipherBytes = aesEncryptBytes(
+ secretText.toByteArray(StandardCharsets.UTF_8),
+ plainText.toByteArray(StandardCharsets.UTF_8),
+ mode,
+ padding,
+ ivText?.toByteArray(StandardCharsets.UTF_8),
+ keyLength
+ )
+ return Base64.encodeToString(cipherBytes, Base64.NO_WRAP)
+ }
+
+ fun aesDecryptText(
+ secretText: String,
+ cipherText: String,
+ mode: String,
+ padding: String,
+ ivText: String?,
+ keyLength: Int?
+ ): String {
+ val cipherBytes = try {
+ Base64.decode(cipherText, Base64.DEFAULT)
+ } catch (e: Exception) {
+ throw IllegalArgumentException("密文Base64无效")
+ }
+ val plainBytes = aesDecryptBytes(
+ secretText.toByteArray(StandardCharsets.UTF_8),
+ cipherBytes,
+ mode,
+ padding,
+ ivText?.toByteArray(StandardCharsets.UTF_8),
+ keyLength
+ )
+ return String(plainBytes, StandardCharsets.UTF_8)
+ }
+
+ fun aesEncryptBytes(
+ secretBytes: ByteArray,
+ plainBytes: ByteArray,
+ mode: String,
+ padding: String,
+ ivBytes: ByteArray?,
+ keyLength: Int?
+ ): ByteArray {
+ return cryptAes(true, secretBytes, plainBytes, mode, padding, ivBytes, keyLength)
+ }
+
+ fun aesDecryptBytes(
+ secretBytes: ByteArray,
+ cipherBytes: ByteArray,
+ mode: String,
+ padding: String,
+ ivBytes: ByteArray?,
+ keyLength: Int?
+ ): ByteArray {
+ return cryptAes(false, secretBytes, cipherBytes, mode, padding, ivBytes, keyLength)
+ }
+
+ fun tripleDesEncryptText(secretText: String, plainText: String, mode: String, ivText: String?): String {
+ val encrypted = cryptTripleDes(
+ true,
+ secretText.toByteArray(StandardCharsets.UTF_8),
+ plainText.toByteArray(StandardCharsets.UTF_8),
+ mode,
+ ivText?.toByteArray(StandardCharsets.UTF_8)
+ )
+ return Base64.encodeToString(encrypted, Base64.NO_WRAP)
+ }
+
+ fun tripleDesDecryptText(secretText: String, cipherText: String, mode: String, ivText: String?): String {
+ val cipherBytes = try {
+ Base64.decode(cipherText, Base64.DEFAULT)
+ } catch (e: Exception) {
+ throw IllegalArgumentException("密文Base64无效")
+ }
+ val decrypted = cryptTripleDes(
+ false,
+ secretText.toByteArray(StandardCharsets.UTF_8),
+ cipherBytes,
+ mode,
+ ivText?.toByteArray(StandardCharsets.UTF_8)
+ )
+ return String(decrypted, StandardCharsets.UTF_8)
+ }
+
+ fun desEncryptText(secretText: String, plainText: String, mode: String, padding: String, ivText: String?): String {
+ val encrypted = cryptDes(
+ true,
+ secretText.toByteArray(StandardCharsets.UTF_8),
+ plainText.toByteArray(StandardCharsets.UTF_8),
+ mode,
+ padding,
+ ivText?.toByteArray(StandardCharsets.UTF_8)
+ )
+ return Base64.encodeToString(encrypted, Base64.NO_WRAP)
+ }
+
+ fun desDecryptText(secretText: String, cipherText: String, mode: String, padding: String, ivText: String?): String {
+ val cipherBytes = try {
+ Base64.decode(cipherText, Base64.DEFAULT)
+ } catch (e: Exception) {
+ throw IllegalArgumentException("密文Base64无效")
+ }
+ val decrypted = cryptDes(
+ false,
+ secretText.toByteArray(StandardCharsets.UTF_8),
+ cipherBytes,
+ mode,
+ padding,
+ ivText?.toByteArray(StandardCharsets.UTF_8)
+ )
+ return String(decrypted, StandardCharsets.UTF_8)
+ }
+
+ fun rc4EncryptToHex(secretText: String, plainText: String): String {
+ return toHex(rc4(secretText.toByteArray(StandardCharsets.UTF_8), plainText.toByteArray(StandardCharsets.UTF_8)))
+ }
+
+ fun rc4DecryptFromHex(secretText: String, cipherHexText: String): String {
+ val plainBytes = rc4(secretText.toByteArray(StandardCharsets.UTF_8), fromHex(cipherHexText))
+ return String(plainBytes, StandardCharsets.UTF_8)
+ }
+
+ fun createRsaBundle(keySize: Int): NativeRsaBundle {
+ return try {
+ val generator = KeyPairGenerator.getInstance("RSA")
+ generator.initialize(keySize)
+ val pair = generator.generateKeyPair()
+ val publicPem = toPem("PUBLIC KEY", pair.public.encoded)
+ val privatePem = toPem("PRIVATE KEY", pair.private.encoded)
+ NativeRsaBundle(publicPem, privatePem)
+ } catch (e: IllegalArgumentException) {
+ throw e
+ } catch (e: Exception) {
+ throw IllegalStateException("RSA生成失败")
+ }
+ }
+
+ fun rsaEncrypt(publicKey: String, plainText: String, outputKind: String?): String {
+ return try {
+ val rsaKey = parsePublicKey(publicKey)
+ val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
+ cipher.init(Cipher.ENCRYPT_MODE, rsaKey)
+ val encrypted = rsaProcess(cipher, plainText.toByteArray(StandardCharsets.UTF_8), rsaEncryptChunkSize(rsaKey), "RSA加密失败")
+ if (isHexOutput(outputKind)) toHex(encrypted) else Base64.encodeToString(encrypted, Base64.NO_WRAP)
+ } catch (e: IllegalArgumentException) {
+ throw e
+ } catch (e: Exception) {
+ throw IllegalStateException("RSA加密失败")
+ }
+ }
+
+ fun rsaDecrypt(privateKey: String, cipherText: String, outputKind: String?): String {
+ return try {
+ val rsaKey = parsePrivateKey(privateKey)
+ val cipherBytes = if (isHexOutput(outputKind)) {
+ fromHex(cipherText)
+ } else {
+ try {
+ Base64.decode(cipherText, Base64.DEFAULT)
+ } catch (e: Exception) {
+ throw IllegalArgumentException("RSA密文无效")
+ }
+ }
+ val cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding")
+ cipher.init(Cipher.DECRYPT_MODE, rsaKey)
+ val decrypted = rsaProcess(cipher, cipherBytes, rsaDecryptChunkSize(rsaKey), "RSA解密失败")
+ String(decrypted, StandardCharsets.UTF_8)
+ } catch (e: IllegalArgumentException) {
+ throw e
+ } catch (e: Exception) {
+ throw IllegalStateException("RSA解密失败")
+ }
+ }
+
+ private fun cryptAes(
+ encrypt: Boolean,
+ secretBytes: ByteArray,
+ inputBytes: ByteArray,
+ mode: String,
+ padding: String,
+ ivBytes: ByteArray?,
+ keyLength: Int?
+ ): ByteArray {
+ try {
+ val normalizedMode = resolveAesMode(mode)
+ val normalizedPadding = resolvePadding(padding)
+ val key = SecretKeySpec(normalizeAesKey(secretBytes, keyLength), "AES")
+ val data = if (encrypt) padBytes(inputBytes, AES_BLOCK_SIZE, normalizedPadding) else inputBytes
+ if (!encrypt && data.isEmpty()) {
+ return ByteArray(0)
+ }
+ val cipher = Cipher.getInstance("AES/$normalizedMode/NoPadding")
+ initCipher(cipher, encrypt, key, normalizedMode, normalizeIv(ivBytes, AES_BLOCK_SIZE, normalizedMode))
+ val output = cipher.doFinal(data)
+ return if (encrypt) output else unpadBytes(output, AES_BLOCK_SIZE, normalizedPadding)
+ } catch (e: IllegalArgumentException) {
+ throw e
+ } catch (e: GeneralSecurityException) {
+ throw IllegalStateException(if (encrypt) "AES加密失败" else "AES解密失败")
+ }
+ }
+
+ private fun cryptTripleDes(
+ encrypt: Boolean,
+ secretBytes: ByteArray,
+ inputBytes: ByteArray,
+ mode: String,
+ ivBytes: ByteArray?
+ ): ByteArray {
+ try {
+ val normalizedMode = resolveTripleDesMode(mode)
+ val key = SecretKeySpec(normalizeTripleDesKey(secretBytes), "DESede")
+ val data = if (encrypt) padBytes(inputBytes, DES_BLOCK_SIZE, "PKCS7") else inputBytes
+ val cipher = Cipher.getInstance("DESede/$normalizedMode/NoPadding")
+ initCipher(cipher, encrypt, key, normalizedMode, normalizeIv(ivBytes, DES_BLOCK_SIZE, normalizedMode))
+ val output = cipher.doFinal(data)
+ return if (encrypt) output else unpadBytes(output, DES_BLOCK_SIZE, "PKCS7")
+ } catch (e: IllegalArgumentException) {
+ throw e
+ } catch (e: GeneralSecurityException) {
+ throw IllegalStateException(if (encrypt) "3DES加密失败" else "3DES解密失败")
+ }
+ }
+
+ private fun cryptDes(
+ encrypt: Boolean,
+ secretBytes: ByteArray,
+ inputBytes: ByteArray,
+ mode: String,
+ padding: String,
+ ivBytes: ByteArray?
+ ): ByteArray {
+ try {
+ val normalizedMode = resolveDesMode(mode)
+ val normalizedPadding = resolvePadding(padding)
+ val key = SecretKeySpec(normalizeDesKey(secretBytes), "DES")
+ val data = if (encrypt) padBytes(inputBytes, DES_BLOCK_SIZE, normalizedPadding) else inputBytes
+ if (!encrypt && data.isEmpty()) {
+ return ByteArray(0)
+ }
+ val cipher = Cipher.getInstance("DES/$normalizedMode/NoPadding")
+ initCipher(cipher, encrypt, key, normalizedMode, normalizeIv(ivBytes, DES_BLOCK_SIZE, normalizedMode))
+ val output = cipher.doFinal(data)
+ return if (encrypt) output else unpadBytes(output, DES_BLOCK_SIZE, normalizedPadding)
+ } catch (e: IllegalArgumentException) {
+ throw e
+ } catch (e: GeneralSecurityException) {
+ throw IllegalStateException(if (encrypt) "DES加密失败" else "DES解密失败")
+ }
+ }
+
+ private fun initCipher(cipher: Cipher, encrypt: Boolean, key: SecretKeySpec, mode: String, ivBytes: ByteArray?) {
+ if (mode == "ECB") {
+ cipher.init(if (encrypt) Cipher.ENCRYPT_MODE else Cipher.DECRYPT_MODE, key)
+ } else {
+ val actualIv = ivBytes ?: throw IllegalArgumentException("IV不能为空")
+ cipher.init(if (encrypt) Cipher.ENCRYPT_MODE else Cipher.DECRYPT_MODE, key, IvParameterSpec(actualIv))
+ }
+ }
+
+ private fun resolveDigestAlgorithm(kind: String): String {
+ return when (kind.lowercase()) {
+ "md5" -> "MD5"
+ "sha1" -> "SHA-1"
+ "sha256" -> "SHA-256"
+ "sha512" -> "SHA-512"
+ else -> throw IllegalArgumentException("不支持的摘要算法")
+ }
+ }
+
+ private fun resolveHmacAlgorithm(kind: String): String {
+ return when (kind.lowercase()) {
+ "sha1" -> "HmacSHA1"
+ "sha256" -> "HmacSHA256"
+ "sha512" -> "HmacSHA512"
+ else -> throw IllegalArgumentException("不支持的HMAC算法")
+ }
+ }
+
+ private fun resolveAesMode(mode: String): String {
+ return when (mode.uppercase()) {
+ "ECB", "CBC", "CFB", "CTR", "OFB" -> mode.uppercase()
+ // CTRGladman 在 Android 端按标准 CTR 变换兼容映射处理。
+ "CTRGLADMAN" -> "CTR"
+ else -> throw IllegalArgumentException("不支持的AES模式")
+ }
+ }
+
+ private fun resolveTripleDesMode(mode: String): String {
+ return when (mode.uppercase()) {
+ "ECB", "CBC" -> mode.uppercase()
+ else -> throw IllegalArgumentException("不支持的3DES模式")
+ }
+ }
+
+ private fun resolveDesMode(mode: String): String {
+ return when (mode.uppercase()) {
+ "ECB", "CBC", "CFB", "CTR", "OFB" -> mode.uppercase()
+ "CTRGLADMAN" -> "CTR"
+ else -> throw IllegalArgumentException("不支持的DES模式")
+ }
+ }
+
+ private fun resolvePadding(padding: String): String {
+ return when (padding.uppercase()) {
+ "PKCS7", "ANSI_X923", "ISO_10126", "ISO_97971", "NONE", "ZERO" -> padding.uppercase()
+ else -> throw IllegalArgumentException("不支持的填充")
+ }
+ }
+
+ private fun normalizeAesKey(secretBytes: ByteArray, keyLength: Int?): ByteArray {
+ val keySize = when (keyLength) {
+ null -> inferAesKeySize(secretBytes.size)
+ 128, 192, 256 -> keyLength / 8
+ else -> throw IllegalArgumentException("AES密钥长度无效")
+ }
+ return fitBytes(secretBytes, keySize)
+ }
+
+ private fun inferAesKeySize(size: Int): Int {
+ return when {
+ size <= 16 -> 16
+ size <= 24 -> 24
+ size <= 32 -> 32
+ else -> throw IllegalArgumentException("AES密钥长度无效")
+ }
+ }
+
+ private fun normalizeTripleDesKey(secretBytes: ByteArray): ByteArray {
+ val source = fitBytes(secretBytes, 24)
+ if (secretBytes.size <= 16) {
+ System.arraycopy(source, 0, source, 16, 8)
+ }
+ return source
+ }
+
+ private fun normalizeDesKey(secretBytes: ByteArray): ByteArray {
+ if (secretBytes.isEmpty()) {
+ throw IllegalArgumentException("密钥不能为空")
+ }
+ return fitBytes(secretBytes, 8)
+ }
+
+ private fun normalizeIv(ivBytes: ByteArray?, expectedSize: Int, mode: String): ByteArray? {
+ if (mode == "ECB") return null
+ val bytes = ivBytes ?: return null
+ return fitBytes(bytes, expectedSize)
+ }
+
+ private fun fitBytes(source: ByteArray, targetSize: Int): ByteArray {
+ val output = ByteArray(targetSize)
+ val copySize = minOf(source.size, targetSize)
+ System.arraycopy(source, 0, output, 0, copySize)
+ return output
+ }
+
+ private fun padBytes(input: ByteArray, blockSize: Int, padding: String): ByteArray {
+ if (padding == "NONE") {
+ if (input.size % blockSize != 0) {
+ throw IllegalArgumentException("数据长度不是块大小整数倍")
+ }
+ return input
+ }
+ val padSize = blockSize - (input.size % blockSize).let { if (it == 0) blockSize else it }
+ val actualPadSize = if (padSize == 0) blockSize else padSize
+ val output = ByteArray(input.size + actualPadSize)
+ System.arraycopy(input, 0, output, 0, input.size)
+ when (padding) {
+ "PKCS7" -> fillPad(output, input.size, actualPadSize, actualPadSize.toByte())
+ "ANSI_X923" -> output[output.lastIndex] = actualPadSize.toByte()
+ "ISO_10126" -> {
+ val randomBytes = ByteArray(actualPadSize - 1)
+ if (randomBytes.isNotEmpty()) {
+ secureRandom.nextBytes(randomBytes)
+ System.arraycopy(randomBytes, 0, output, input.size, randomBytes.size)
+ }
+ output[output.lastIndex] = actualPadSize.toByte()
+ }
+ "ISO_97971" -> {
+ output[input.size] = 0x80.toByte()
+ }
+ "ZERO" -> {
+ }
+ else -> throw IllegalArgumentException("不支持的填充")
+ }
+ return output
+ }
+
+ private fun fillPad(output: ByteArray, start: Int, count: Int, value: Byte) {
+ for (i in start until start + count) {
+ output[i] = value
+ }
+ }
+
+ private fun unpadBytes(input: ByteArray, blockSize: Int, padding: String): ByteArray {
+ if (padding == "NONE") {
+ return input
+ }
+ if (input.isEmpty() || input.size % blockSize != 0) {
+ throw IllegalArgumentException("密文长度无效")
+ }
+ val dataLength = when (padding) {
+ "PKCS7" -> {
+ val padSize = input.last().toInt() and 0xFF
+ validatePadSize(padSize, blockSize)
+ for (i in input.size - padSize until input.size) {
+ if ((input[i].toInt() and 0xFF) != padSize) {
+ throw IllegalArgumentException("填充无效")
+ }
+ }
+ input.size - padSize
+ }
+ "ANSI_X923" -> {
+ val padSize = input.last().toInt() and 0xFF
+ validatePadSize(padSize, blockSize)
+ for (i in input.size - padSize until input.lastIndex) {
+ if (input[i].toInt() != 0) {
+ throw IllegalArgumentException("填充无效")
+ }
+ }
+ input.size - padSize
+ }
+ "ISO_10126" -> {
+ val padSize = input.last().toInt() and 0xFF
+ validatePadSize(padSize, blockSize)
+ input.size - padSize
+ }
+ "ISO_97971" -> {
+ var index = input.lastIndex
+ while (index >= 0 && input[index].toInt() == 0) {
+ index -= 1
+ }
+ if (index < 0 || input[index] != 0x80.toByte()) {
+ throw IllegalArgumentException("填充无效")
+ }
+ index
+ }
+ "ZERO" -> {
+ var index = input.size
+ while (index > 0 && input[index - 1].toInt() == 0) {
+ index -= 1
+ }
+ index
+ }
+ else -> throw IllegalArgumentException("不支持的填充")
+ }
+ return input.copyOf(dataLength)
+ }
+
+ private fun validatePadSize(padSize: Int, blockSize: Int) {
+ if (padSize <= 0 || padSize > blockSize) {
+ throw IllegalArgumentException("填充无效")
+ }
+ }
+
+ private fun rc4(secretBytes: ByteArray, inputBytes: ByteArray): ByteArray {
+ if (secretBytes.isEmpty()) {
+ throw IllegalArgumentException("RC4密钥不能为空")
+ }
+ val s = IntArray(256) { it }
+ var j = 0
+ for (i in 0 until 256) {
+ j = (j + s[i] + (secretBytes[i % secretBytes.size].toInt() and 0xFF)) and 0xFF
+ val tmp = s[i]
+ s[i] = s[j]
+ s[j] = tmp
+ }
+ val output = ByteArray(inputBytes.size)
+ var i = 0
+ j = 0
+ for (index in inputBytes.indices) {
+ i = (i + 1) and 0xFF
+ j = (j + s[i]) and 0xFF
+ val tmp = s[i]
+ s[i] = s[j]
+ s[j] = tmp
+ val keyByte = s[(s[i] + s[j]) and 0xFF]
+ output[index] = (inputBytes[index].toInt() xor keyByte).toByte()
+ }
+ return output
+ }
+
+ private fun parsePublicKey(publicKey: String): RSAPublicKey {
+ try {
+ val keyBytes = decodePem(publicKey, "PUBLIC KEY")
+ val keySpec = X509EncodedKeySpec(keyBytes)
+ return KeyFactory.getInstance("RSA").generatePublic(keySpec) as RSAPublicKey
+ } catch (e: IllegalArgumentException) {
+ throw e
+ } catch (e: Exception) {
+ throw IllegalArgumentException("公钥无效")
+ }
+ }
+
+ private fun parsePrivateKey(privateKey: String): RSAPrivateKey {
+ try {
+ val keyBytes = decodePem(privateKey, "PRIVATE KEY")
+ val keySpec = PKCS8EncodedKeySpec(keyBytes)
+ return KeyFactory.getInstance("RSA").generatePrivate(keySpec) as RSAPrivateKey
+ } catch (e: IllegalArgumentException) {
+ throw e
+ } catch (e: Exception) {
+ throw IllegalArgumentException("私钥无效")
+ }
+ }
+
+ private fun decodePem(pemText: String, label: String): ByteArray {
+ val header = "-----BEGIN $label-----"
+ val footer = "-----END $label-----"
+ val trimmed = pemText.trim()
+ if (!trimmed.startsWith(header) || !trimmed.endsWith(footer)) {
+ throw IllegalArgumentException("PEM格式无效")
+ }
+ val content = trimmed
+ .removePrefix(header)
+ .removeSuffix(footer)
+ .replace("\\s".toRegex(), "")
+ return try {
+ Base64.decode(content, Base64.DEFAULT)
+ } catch (e: Exception) {
+ throw IllegalArgumentException("PEM内容无效")
+ }
+ }
+
+ private fun toPem(label: String, keyBytes: ByteArray): String {
+ val base64 = Base64.encodeToString(keyBytes, Base64.NO_WRAP)
+ val builder = StringBuilder()
+ builder.append("-----BEGIN ").append(label).append("-----\n")
+ var index = 0
+ while (index < base64.length) {
+ val end = minOf(index + 64, base64.length)
+ builder.append(base64, index, end).append('\n')
+ index = end
+ }
+ builder.append("-----END ").append(label).append("-----")
+ return builder.toString()
+ }
+
+ private fun rsaEncryptChunkSize(key: RSAPublicKey): Int {
+ return (key.modulus.bitLength() + 7) / 8 - 11
+ }
+
+ private fun rsaDecryptChunkSize(key: RSAPrivateKey): Int {
+ return (key.modulus.bitLength() + 7) / 8
+ }
+
+ private fun rsaProcess(cipher: Cipher, input: ByteArray, chunkSize: Int, failureMessage: String): ByteArray {
+ if (chunkSize <= 0) {
+ throw IllegalArgumentException("RSA密钥无效")
+ }
+ val output = ByteArrayOutputStream()
+ var offset = 0
+ try {
+ while (offset < input.size) {
+ val size = minOf(chunkSize, input.size - offset)
+ output.write(cipher.doFinal(input, offset, size))
+ offset += size
+ }
+ return output.toByteArray()
+ } catch (e: Exception) {
+ throw IllegalStateException(failureMessage)
+ } finally {
+ output.close()
+ }
+ }
+
+ private fun isHexOutput(outputKind: String?): Boolean {
+ return outputKind?.lowercase() == "hex"
+ }
+
+ private fun latin1FromBytes(bytes: ByteArray): String {
+ val chars = CharArray(bytes.size)
+ for (i in bytes.indices) {
+ chars[i] = (bytes[i].toInt() and 0xFF).toChar()
+ }
+ return String(chars)
+ }
+
+ private fun bytesFromLatin1(text: String): ByteArray {
+ val output = ByteArray(text.length)
+ for (i in text.indices) {
+ output[i] = (text[i].code and 0xFF).toByte()
+ }
+ return output
+ }
+
+ private fun utf16CodecFromBytes(bytes: ByteArray): String {
+ if (bytes.isEmpty()) {
+ return ""
+ }
+ val chars = CharArray((bytes.size + 1) / 2)
+ var byteIndex = 0
+ var charIndex = 0
+ while (byteIndex < bytes.size) {
+ val high = bytes[byteIndex].toInt() and 0xFF
+ val low = if (byteIndex + 1 < bytes.size) bytes[byteIndex + 1].toInt() and 0xFF else 0
+ chars[charIndex] = ((high shl 8) or low).toChar()
+ byteIndex += 2
+ charIndex += 1
+ }
+ return String(chars)
+ }
+
+ private fun bytesFromUtf16Codec(text: String): ByteArray {
+ val output = ByteArray(text.length * 2)
+ var index = 0
+ for (charValue in text) {
+ val code = charValue.code
+ output[index] = ((code ushr 8) and 0xFF).toByte()
+ output[index + 1] = (code and 0xFF).toByte()
+ index += 2
+ }
+ return output
+ }
+
+ private fun toHex(bytes: ByteArray): String {
+ val chars = CharArray(bytes.size * 2)
+ val digits = "0123456789abcdef"
+ for (i in bytes.indices) {
+ val value = bytes[i].toInt() and 0xFF
+ chars[i * 2] = digits[value ushr 4]
+ chars[i * 2 + 1] = digits[value and 0x0F]
+ }
+ return String(chars)
+ }
+
+ private fun fromHex(hexText: String): ByteArray {
+ val normalized = hexText.trim()
+ if (normalized.length % 2 != 0) {
+ throw IllegalArgumentException("Hex无效")
+ }
+ val output = ByteArray(normalized.length / 2)
+ for (i in output.indices) {
+ val start = i * 2
+ val value = normalized.substring(start, start + 2).toIntOrNull(16)
+ ?: throw IllegalArgumentException("Hex无效")
+ output[i] = value.toByte()
+ }
+ return output
+ }
+}
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/app-android/config.json b/uni_modules/laoqianjunzi-crypto/utssdk/app-android/config.json
new file mode 100644
index 0000000..5defc8f
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/app-android/config.json
@@ -0,0 +1,3 @@
+{
+ "minSdkVersion": "21"
+}
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/app-android/index.uts b/uni_modules/laoqianjunzi-crypto/utssdk/app-android/index.uts
new file mode 100644
index 0000000..9000246
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/app-android/index.uts
@@ -0,0 +1,241 @@
+import NativeCipherCore from 'uts.sdk.modules.laoqianjunziCrypto.NativeCipherCore'
+import type { CryptoByteCipherOptions, CryptoCodecKind, CryptoDesOptions, CryptoDigestKind, CryptoMacKind, CryptoRsaPair, CryptoRuntimeSnapshot, CryptoTextCipherOptions, CryptoTripleDesOptions, RsaOutputKind } from '../interface.uts'
+import { buildRuntimeSnapshot, createDefaultByteCipherOptions, createDefaultDesOptions, createDefaultTextCipherOptions, createDefaultTripleDesOptions, normalizeByteCipherOptions, normalizeDesOptions, normalizeTextCipherOptions, normalizeTripleDesOptions, resolveHexOutput } from '../shared/options.uts'
+import type { CompatBridge, CompatCrypto } from '../shared/compat.uts'
+import { aesDecryptBytesCompat, aesDecryptCompat, aesEncryptBytesCompat, aesEncryptCompat, base64DecodeCompat, base64EncodeCompat, createCompatBridge, createCompatCrypto, desDecryptCompat, desEncryptCompat, generateRsaKeyPairCompat, hmacSha1Compat, hmacSha256Compat, hmacSha512Compat, md5Compat, rc4DecryptCompat, rc4EncryptCompat, rsaDecryptCompat, rsaEncryptCompat, sha1Compat, sha256Compat, sha512Compat } from '../shared/compat.uts'
+
+function toNativeBytes(source : Uint8Array) : ByteArray {
+ const output = new ByteArray(source.length.toInt())
+ let index = 0
+ while (index < source.length) {
+ output[index.toInt()] = source[index.toInt()].toByte()
+ index += 1
+ }
+ return output
+}
+
+function fromNativeBytes(source : ByteArray) : Uint8Array {
+ const output = new Uint8Array(source.size)
+ let index = 0
+ while (index < source.size) {
+ output[index.toInt()] = source[index.toInt()] & 0xff
+ index += 1
+ }
+ return output
+}
+
+function byteToHex(value : number) : string {
+ let part = value.toString(16)
+ if (part.length < 2) {
+ part = '0' + part
+ }
+ return part
+}
+
+export function defaultTextCipherOptions() : CryptoTextCipherOptions {
+ return createDefaultTextCipherOptions()
+}
+
+export function defaultByteCipherOptions() : CryptoByteCipherOptions {
+ return createDefaultByteCipherOptions()
+}
+
+export function defaultTripleDesOptions() : CryptoTripleDesOptions {
+ return createDefaultTripleDesOptions()
+}
+
+export function defaultDesOptions() : CryptoDesOptions {
+ return createDefaultDesOptions()
+}
+
+export function describeCryptoRuntime() : CryptoRuntimeSnapshot {
+ return buildRuntimeSnapshot('Android', 'JCA', true, true)
+}
+
+export function encodeText(codec : CryptoCodecKind, plainText : string) : string {
+ return NativeCipherCore.encodeCodec(codec, plainText)
+}
+
+export function decodeText(codec : CryptoCodecKind, encodedText : string) : string {
+ return NativeCipherCore.decodeCodec(codec, encodedText)
+}
+
+export function digestText(kind : CryptoDigestKind, plainText : string) : string {
+ return NativeCipherCore.digestHex(kind, plainText)
+}
+
+export function signText(kind : CryptoMacKind, secretText : string, plainText : string) : string {
+ return NativeCipherCore.hmacHex(kind, secretText, plainText)
+}
+
+export function aesEncryptText(secretText : string, plainText : string, options : CryptoTextCipherOptions | null) : string {
+ const actual = normalizeTextCipherOptions(options)
+ const actualKeyLength = actual.keyLength == null ? null : actual.keyLength.toInt()
+ return NativeCipherCore.aesEncryptText(secretText, plainText, actual.mode, actual.padding, actual.ivText, actualKeyLength)
+}
+
+export function aesDecryptText(secretText : string, cipherText : string, options : CryptoTextCipherOptions | null) : string {
+ const actual = normalizeTextCipherOptions(options)
+ const actualKeyLength = actual.keyLength == null ? null : actual.keyLength.toInt()
+ return NativeCipherCore.aesDecryptText(secretText, cipherText, actual.mode, actual.padding, actual.ivText, actualKeyLength)
+}
+
+export function aesEncryptBytes(secretBytes : Uint8Array, plainBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array {
+ const actual = normalizeByteCipherOptions(options)
+ const actualKeyLength = actual.keyLength == null ? null : actual.keyLength.toInt()
+ return fromNativeBytes(NativeCipherCore.aesEncryptBytes(toNativeBytes(secretBytes), toNativeBytes(plainBytes), actual.mode, actual.padding, actual.ivBytes == null ? null : toNativeBytes(actual.ivBytes), actualKeyLength))
+}
+
+export function aesDecryptBytes(secretBytes : Uint8Array, cipherBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array {
+ const actual = normalizeByteCipherOptions(options)
+ const actualKeyLength = actual.keyLength == null ? null : actual.keyLength.toInt()
+ return fromNativeBytes(NativeCipherCore.aesDecryptBytes(toNativeBytes(secretBytes), toNativeBytes(cipherBytes), actual.mode, actual.padding, actual.ivBytes == null ? null : toNativeBytes(actual.ivBytes), actualKeyLength))
+}
+
+export function tripleDesEncryptText(secretText : string, plainText : string, options : CryptoTripleDesOptions | null) : string {
+ const actual = normalizeTripleDesOptions(options)
+ return NativeCipherCore.tripleDesEncryptText(secretText, plainText, actual.mode, actual.ivText)
+}
+
+export function tripleDesDecryptText(secretText : string, cipherText : string, options : CryptoTripleDesOptions | null) : string {
+ const actual = normalizeTripleDesOptions(options)
+ return NativeCipherCore.tripleDesDecryptText(secretText, cipherText, actual.mode, actual.ivText)
+}
+
+export function desEncryptText(secretText : string, plainText : string, options : CryptoDesOptions | null) : string {
+ const actual = normalizeDesOptions(options)
+ return NativeCipherCore.desEncryptText(secretText, plainText, actual.mode, actual.padding, actual.ivText)
+}
+
+export function desDecryptText(secretText : string, cipherText : string, options : CryptoDesOptions | null) : string {
+ const actual = normalizeDesOptions(options)
+ return NativeCipherCore.desDecryptText(secretText, cipherText, actual.mode, actual.padding, actual.ivText)
+}
+
+export function rc4EncryptText(secretText : string, plainText : string) : string {
+ return NativeCipherCore.rc4EncryptToHex(secretText, plainText)
+}
+
+export function rc4DecryptText(secretText : string, cipherHexText : string) : string {
+ return NativeCipherCore.rc4DecryptFromHex(secretText, cipherHexText)
+}
+
+export function createRsaPair(keySize : number) : CryptoRsaPair {
+ const bundle = NativeCipherCore.createRsaBundle(keySize.toInt())
+ return {
+ publicKey: bundle.publicKey,
+ privateKey: bundle.privateKey
+ } as CryptoRsaPair
+}
+
+export function rsaEncryptText(publicKey : string, plainText : string, outputKind : RsaOutputKind | null) : string {
+ return NativeCipherCore.rsaEncrypt(publicKey, plainText, resolveHexOutput(outputKind) ? 'hex' : 'base64')
+}
+
+export function rsaDecryptText(privateKey : string, cipherText : string, outputKind : RsaOutputKind | null) : string {
+ return NativeCipherCore.rsaDecrypt(privateKey, cipherText, resolveHexOutput(outputKind) ? 'hex' : 'base64')
+}
+
+function compatBridge() : CompatBridge {
+ return createCompatBridge(
+ (codec : CryptoCodecKind, plainText : string) : string => encodeText(codec, plainText),
+ (codec : CryptoCodecKind, encodedText : string) : string => decodeText(codec, encodedText),
+ (kind : CryptoDigestKind, plainText : string) : string => digestText(kind, plainText),
+ (kind : CryptoMacKind, secretText : string, plainText : string) : string => signText(kind, secretText, plainText),
+ (secretText : string, plainText : string, options : CryptoTextCipherOptions | null) : string => aesEncryptText(secretText, plainText, options),
+ (secretText : string, cipherText : string, options : CryptoTextCipherOptions | null) : string => aesDecryptText(secretText, cipherText, options),
+ (secretBytes : Uint8Array, plainBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array => aesEncryptBytes(secretBytes, plainBytes, options),
+ (secretBytes : Uint8Array, cipherBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array => aesDecryptBytes(secretBytes, cipherBytes, options),
+ (secretText : string, plainText : string, options : CryptoDesOptions | null) : string => desEncryptText(secretText, plainText, options),
+ (secretText : string, cipherText : string, options : CryptoDesOptions | null) : string => desDecryptText(secretText, cipherText, options),
+ (keySize : number) : CryptoRsaPair => createRsaPair(keySize),
+ (publicKey : string, plainText : string, outputKind : RsaOutputKind | null) : string => rsaEncryptText(publicKey, plainText, outputKind),
+ (privateKey : string, cipherText : string, outputKind : RsaOutputKind | null) : string => rsaDecryptText(privateKey, cipherText, outputKind),
+ (secretText : string, plainText : string) : string => rc4EncryptText(secretText, plainText),
+ (secretText : string, cipherHexText : string) : string => rc4DecryptText(secretText, cipherHexText)
+ )
+}
+
+export function base64Encode(input : string) : string {
+ return base64EncodeCompat(compatBridge(), input)
+}
+
+export function base64Decode(input : string) : string {
+ return base64DecodeCompat(compatBridge(), input)
+}
+
+export function md5(input : string) : string {
+ return md5Compat(compatBridge(), input)
+}
+
+export function sha1(input : string) : string {
+ return sha1Compat(compatBridge(), input)
+}
+
+export function sha256(input : string) : string {
+ return sha256Compat(compatBridge(), input)
+}
+
+export function sha512(input : string) : string {
+ return sha512Compat(compatBridge(), input)
+}
+
+export function hmacSha1(key : string, data : string) : string {
+ return hmacSha1Compat(compatBridge(), key, data)
+}
+
+export function hmacSha256(key : string, data : string) : string {
+ return hmacSha256Compat(compatBridge(), key, data)
+}
+
+export function hmacSha512(key : string, data : string) : string {
+ return hmacSha512Compat(compatBridge(), key, data)
+}
+
+export function aesEncrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null, keySize : number | null = 16) : string {
+ return aesEncryptCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function aesDecrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null, keySize : number | null = 16) : string {
+ return aesDecryptCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function aesEncrypt2(key : Uint8Array, data : Uint8Array, mode : string = 'ECB', iv : Uint8Array | null = null, keySize : number | null = 16) : Uint8Array {
+ return aesEncryptBytesCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function aesDecrypt2(key : Uint8Array, data : Uint8Array, mode : string = 'ECB', iv : Uint8Array | null = null, keySize : number | null = 16) : Uint8Array {
+ return aesDecryptBytesCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function desEncrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null) : string {
+ return desEncryptCompat(compatBridge(), key, data, mode, iv)
+}
+
+export function desDecrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null) : string {
+ return desDecryptCompat(compatBridge(), key, data, mode, iv)
+}
+
+export function generateRSAKeyPair(keySize : number = 2048) : CryptoRsaPair {
+ return generateRsaKeyPairCompat(compatBridge(), keySize)
+}
+
+export function rsaEncrypt(publicKey : string, data : string) : string {
+ return rsaEncryptCompat(compatBridge(), publicKey, data)
+}
+
+export function rsaDecrypt(privateKey : string, data : string) : string {
+ return rsaDecryptCompat(compatBridge(), privateKey, data)
+}
+
+export function rc4Encrypt(key : string, data : string) : string {
+ return rc4EncryptCompat(compatBridge(), key, data)
+}
+
+export function rc4Decrypt(key : string, data : string) : string {
+ return rc4DecryptCompat(compatBridge(), key, data)
+}
+
+export function useCrypto() : CompatCrypto {
+ return createCompatCrypto(compatBridge())
+}
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/app-harmony/config.json b/uni_modules/laoqianjunzi-crypto/utssdk/app-harmony/config.json
new file mode 100644
index 0000000..ea289a4
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/app-harmony/config.json
@@ -0,0 +1,5 @@
+{
+ "dependencies": {
+ "@ohos/crypto-js": "2.0.4"
+ }
+}
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/app-harmony/index.uts b/uni_modules/laoqianjunzi-crypto/utssdk/app-harmony/index.uts
new file mode 100644
index 0000000..2d8d623
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/app-harmony/index.uts
@@ -0,0 +1,428 @@
+import type { CryptoByteCipherOptions, CryptoCodecKind, CryptoDesOptions, CryptoDigestKind, CryptoMacKind, CryptoRsaPair, CryptoRuntimeSnapshot, CryptoTextCipherOptions, CryptoTripleDesOptions, RsaOutputKind } from '../interface.uts'
+import { buildRuntimeSnapshot, createDefaultByteCipherOptions, createDefaultDesOptions, createDefaultTextCipherOptions, createDefaultTripleDesOptions, normalizeByteCipherOptions, normalizeDesOptions, normalizeTextCipherOptions, normalizeTripleDesOptions, resolveHexOutput } from '../shared/options.uts'
+import { NativeHarmonyRsaCore } from './native_rsa.ets'
+import { CryptoJS } from '@ohos/crypto-js'
+import type { CompatBridge, CompatCrypto } from '../shared/compat.uts'
+import { aesDecryptBytesCompat, aesDecryptCompat, aesEncryptBytesCompat, aesEncryptCompat, base64DecodeCompat, base64EncodeCompat, createCompatBridge, createCompatCrypto, desDecryptCompat, desEncryptCompat, generateRsaKeyPairCompat, hmacSha1Compat, hmacSha256Compat, hmacSha512Compat, md5Compat, rc4DecryptCompat, rc4EncryptCompat, rsaDecryptCompat, rsaEncryptCompat, sha1Compat, sha256Compat, sha512Compat } from '../shared/compat.uts'
+
+type WordValue = CryptoJS.lib.WordArray
+
+function bytesToWordArray(input : Uint8Array) : WordValue {
+ const words = [] as number[]
+ let index = 0
+ while (index < input.length) {
+ let word = 0
+ let offset = 0
+ while (offset < 4 && index + offset < input.length) {
+ word |= input[index + offset] << (24 - offset * 8)
+ offset += 1
+ }
+ words.push(word)
+ index += 4
+ }
+ return CryptoJS.lib.WordArray.create(words, input.length)
+}
+
+function wordArrayToBytes(input : WordValue) : Uint8Array {
+ const output = new Uint8Array(input.sigBytes)
+ let index = 0
+ while (index < input.sigBytes) {
+ const wordIndex = Math.floor(index / 4)
+ const offset = index % 4
+ output[index] = (input.words[wordIndex] >>> (24 - offset * 8)) & 0xff
+ index += 1
+ }
+ return output
+}
+
+function resolveAesMode(mode : string) : CryptoJS.BlockCipherMode {
+ if (mode == 'CBC') {
+ return CryptoJS.mode.CBC
+ }
+ if (mode == 'CFB') {
+ return CryptoJS.mode.CFB
+ }
+ if (mode == 'CTR') {
+ return CryptoJS.mode.CTR
+ }
+ if (mode == 'CTRGladman') {
+ return CryptoJS.mode.CTRGladman
+ }
+ if (mode == 'ECB') {
+ return CryptoJS.mode.ECB
+ }
+ return CryptoJS.mode.OFB
+}
+
+function resolvePadding(padding : string) : CryptoJS.Padding {
+ if (padding == 'PKCS7') {
+ return CryptoJS.pad.Pkcs7
+ }
+ if (padding == 'ANSI_X923') {
+ return CryptoJS.pad.AnsiX923
+ }
+ if (padding == 'ISO_10126') {
+ return CryptoJS.pad.Iso10126
+ }
+ if (padding == 'ISO_97971') {
+ return CryptoJS.pad.Iso97971
+ }
+ if (padding == 'NONE') {
+ return CryptoJS.pad.NoPadding
+ }
+ return CryptoJS.pad.ZeroPadding
+}
+
+function fitIvText(ivText : string | null, size : number) : WordValue {
+ const bytes = new Uint8Array(size)
+ if (ivText != null) {
+ const parsed : WordValue = CryptoJS.enc.Utf8.parse(ivText)
+ const source = wordArrayToBytes(parsed)
+ let index = 0
+ while (index < size && index < source.length) {
+ bytes[index] = source[index]
+ index += 1
+ }
+ }
+ return bytesToWordArray(bytes)
+}
+
+function fitIvBytes(ivBytes : Uint8Array | null, size : number) : WordValue {
+ const bytes = new Uint8Array(size)
+ if (ivBytes != null) {
+ let index = 0
+ while (index < size && index < ivBytes.length) {
+ bytes[index] = ivBytes[index]
+ index += 1
+ }
+ }
+ return bytesToWordArray(bytes)
+}
+
+function fitKeyWordFromText(secretText : string, keyLength : number | null) : WordValue {
+ let target = 16
+ if (keyLength == 24 || keyLength == 32) {
+ target = keyLength
+ }
+ const sourceWord : WordValue = CryptoJS.enc.Utf8.parse(secretText)
+ const source = wordArrayToBytes(sourceWord)
+ const output = new Uint8Array(target)
+ let index = 0
+ while (index < target && index < source.length) {
+ output[index] = source[index]
+ index += 1
+ }
+ return bytesToWordArray(output)
+}
+
+function fitKeyWordFromBytes(secretBytes : Uint8Array, keyLength : number | null) : WordValue {
+ let target = 16
+ if (keyLength == 24 || keyLength == 32) {
+ target = keyLength
+ }
+ const output = new Uint8Array(target)
+ let index = 0
+ while (index < target && index < secretBytes.length) {
+ output[index] = secretBytes[index]
+ index += 1
+ }
+ return bytesToWordArray(output)
+}
+
+export function defaultTextCipherOptions() : CryptoTextCipherOptions {
+ return createDefaultTextCipherOptions()
+}
+
+export function defaultByteCipherOptions() : CryptoByteCipherOptions {
+ return createDefaultByteCipherOptions()
+}
+
+export function defaultTripleDesOptions() : CryptoTripleDesOptions {
+ return createDefaultTripleDesOptions()
+}
+
+export function defaultDesOptions() : CryptoDesOptions {
+ return createDefaultDesOptions()
+}
+
+export function describeCryptoRuntime() : CryptoRuntimeSnapshot {
+ return buildRuntimeSnapshot('Harmony', '@ohos/crypto-js', true, true)
+}
+
+export function encodeText(codec : CryptoCodecKind, plainText : string) : string {
+ if (codec == 'utf8') {
+ return plainText
+ }
+ const word : WordValue = CryptoJS.enc.Utf8.parse(plainText)
+ if (codec == 'hex') {
+ return CryptoJS.enc.Hex.stringify(word)
+ }
+ if (codec == 'base64') {
+ return CryptoJS.enc.Base64.stringify(word)
+ }
+ if (codec == 'base64url') {
+ return CryptoJS.enc.Base64url.stringify(word)
+ }
+ if (codec == 'latin1') {
+ return CryptoJS.enc.Latin1.stringify(word)
+ }
+ return CryptoJS.enc.Utf16.stringify(word)
+}
+
+export function decodeText(codec : CryptoCodecKind, encodedText : string) : string {
+ if (codec == 'utf8') {
+ return encodedText
+ }
+ if (codec == 'hex') {
+ return CryptoJS.enc.Hex.parse(encodedText).toString(CryptoJS.enc.Utf8)
+ }
+ if (codec == 'base64') {
+ return CryptoJS.enc.Base64.parse(encodedText).toString(CryptoJS.enc.Utf8)
+ }
+ if (codec == 'base64url') {
+ return CryptoJS.enc.Base64url.parse(encodedText).toString(CryptoJS.enc.Utf8)
+ }
+ if (codec == 'latin1') {
+ return CryptoJS.enc.Latin1.parse(encodedText).toString(CryptoJS.enc.Utf8)
+ }
+ return CryptoJS.enc.Utf16.parse(encodedText).toString(CryptoJS.enc.Utf8)
+}
+
+export function digestText(kind : CryptoDigestKind, plainText : string) : string {
+ if (kind == 'md5') {
+ return CryptoJS.MD5(plainText).toString()
+ }
+ if (kind == 'sha1') {
+ return CryptoJS.SHA1(plainText).toString()
+ }
+ if (kind == 'sha256') {
+ return CryptoJS.SHA256(plainText).toString()
+ }
+ return CryptoJS.SHA512(plainText).toString()
+}
+
+export function signText(kind : CryptoMacKind, secretText : string, plainText : string) : string {
+ if (kind == 'sha1') {
+ return CryptoJS.HmacSHA1(plainText, secretText).toString()
+ }
+ if (kind == 'sha256') {
+ return CryptoJS.HmacSHA256(plainText, secretText).toString()
+ }
+ return CryptoJS.HmacSHA512(plainText, secretText).toString()
+}
+
+export function aesEncryptText(secretText : string, plainText : string, options : CryptoTextCipherOptions | null) : string {
+ const actual = normalizeTextCipherOptions(options)
+ const encrypted : CryptoJS.lib.CipherParams = CryptoJS.AES.encrypt(plainText, fitKeyWordFromText(secretText, actual.keyLength), {
+ iv: fitIvText(actual.ivText, 16),
+ mode: resolveAesMode(actual.mode),
+ padding: resolvePadding(actual.padding)
+ })
+ return encrypted.toString()
+}
+
+export function aesDecryptText(secretText : string, cipherText : string, options : CryptoTextCipherOptions | null) : string {
+ const actual = normalizeTextCipherOptions(options)
+ const decrypted : WordValue = CryptoJS.AES.decrypt(cipherText, fitKeyWordFromText(secretText, actual.keyLength), {
+ iv: fitIvText(actual.ivText, 16),
+ mode: resolveAesMode(actual.mode),
+ padding: resolvePadding(actual.padding)
+ })
+ return decrypted.toString(CryptoJS.enc.Utf8)
+}
+
+export function aesEncryptBytes(secretBytes : Uint8Array, plainBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array {
+ const actual = normalizeByteCipherOptions(options)
+ const encrypted : CryptoJS.lib.CipherParams = CryptoJS.AES.encrypt(bytesToWordArray(plainBytes), fitKeyWordFromBytes(secretBytes, actual.keyLength), {
+ iv: fitIvBytes(actual.ivBytes, 16),
+ mode: resolveAesMode(actual.mode),
+ padding: resolvePadding(actual.padding)
+ })
+ return wordArrayToBytes(encrypted.ciphertext)
+}
+
+export function aesDecryptBytes(secretBytes : Uint8Array, cipherBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array {
+ const actual = normalizeByteCipherOptions(options)
+ const payload : UTSJSONObject = {
+ ciphertext: bytesToWordArray(cipherBytes)
+ }
+ const decrypted : WordValue = CryptoJS.AES.decrypt(CryptoJS.lib.CipherParams.create(payload), fitKeyWordFromBytes(secretBytes, actual.keyLength), {
+ iv: fitIvBytes(actual.ivBytes, 16),
+ mode: resolveAesMode(actual.mode),
+ padding: resolvePadding(actual.padding)
+ })
+ return wordArrayToBytes(decrypted)
+}
+
+export function tripleDesEncryptText(secretText : string, plainText : string, options : CryptoTripleDesOptions | null) : string {
+ const actual = normalizeTripleDesOptions(options)
+ const encrypted : CryptoJS.lib.CipherParams = CryptoJS.TripleDES.encrypt(plainText, fitKeyWordFromText(secretText, 24), {
+ iv: fitIvText(actual.ivText, 8),
+ mode: actual.mode == 'ECB' ? CryptoJS.mode.ECB : CryptoJS.mode.CBC,
+ padding: CryptoJS.pad.Pkcs7
+ })
+ return encrypted.toString()
+}
+
+export function tripleDesDecryptText(secretText : string, cipherText : string, options : CryptoTripleDesOptions | null) : string {
+ const actual = normalizeTripleDesOptions(options)
+ const decrypted : WordValue = CryptoJS.TripleDES.decrypt(cipherText, fitKeyWordFromText(secretText, 24), {
+ iv: fitIvText(actual.ivText, 8),
+ mode: actual.mode == 'ECB' ? CryptoJS.mode.ECB : CryptoJS.mode.CBC,
+ padding: CryptoJS.pad.Pkcs7
+ })
+ return decrypted.toString(CryptoJS.enc.Utf8)
+}
+
+export function desEncryptText(secretText : string, plainText : string, options : CryptoDesOptions | null) : string {
+ const actual = normalizeDesOptions(options)
+ const encrypted : CryptoJS.lib.CipherParams = CryptoJS.DES.encrypt(plainText, fitKeyWordFromText(secretText, 8), {
+ iv: fitIvText(actual.ivText, 8),
+ mode: resolveAesMode(actual.mode),
+ padding: resolvePadding(actual.padding)
+ })
+ return encrypted.toString()
+}
+
+export function desDecryptText(secretText : string, cipherText : string, options : CryptoDesOptions | null) : string {
+ const actual = normalizeDesOptions(options)
+ const decrypted : WordValue = CryptoJS.DES.decrypt(cipherText, fitKeyWordFromText(secretText, 8), {
+ iv: fitIvText(actual.ivText, 8),
+ mode: resolveAesMode(actual.mode),
+ padding: resolvePadding(actual.padding)
+ })
+ return decrypted.toString(CryptoJS.enc.Utf8)
+}
+
+export function rc4EncryptText(secretText : string, plainText : string) : string {
+ const encrypted : CryptoJS.lib.CipherParams = CryptoJS.RC4.encrypt(plainText, CryptoJS.enc.Utf8.parse(secretText))
+ return encrypted.ciphertext.toString(CryptoJS.enc.Hex)
+}
+
+export function rc4DecryptText(secretText : string, cipherHexText : string) : string {
+ const payload : UTSJSONObject = {
+ ciphertext: CryptoJS.enc.Hex.parse(cipherHexText)
+ }
+ const decrypted : WordValue = CryptoJS.RC4.decrypt(CryptoJS.lib.CipherParams.create(payload), CryptoJS.enc.Utf8.parse(secretText))
+ return decrypted.toString(CryptoJS.enc.Utf8)
+}
+
+export function createRsaPair(keySize : number) : CryptoRsaPair {
+ const bundle = NativeHarmonyRsaCore.createRsaBundle(keySize)
+ return {
+ publicKey: bundle.publicKey,
+ privateKey: bundle.privateKey
+ } as CryptoRsaPair
+}
+
+export function rsaEncryptText(publicKey : string, plainText : string, outputKind : RsaOutputKind | null) : string {
+ return NativeHarmonyRsaCore.rsaEncrypt(publicKey, plainText, resolveHexOutput(outputKind) ? 'hex' : 'base64')
+}
+
+export function rsaDecryptText(privateKey : string, cipherText : string, outputKind : RsaOutputKind | null) : string {
+ return NativeHarmonyRsaCore.rsaDecrypt(privateKey, cipherText, resolveHexOutput(outputKind) ? 'hex' : 'base64')
+}
+
+function compatBridge() : CompatBridge {
+ return createCompatBridge(
+ (codec : CryptoCodecKind, plainText : string) : string => encodeText(codec, plainText),
+ (codec : CryptoCodecKind, encodedText : string) : string => decodeText(codec, encodedText),
+ (kind : CryptoDigestKind, plainText : string) : string => digestText(kind, plainText),
+ (kind : CryptoMacKind, secretText : string, plainText : string) : string => signText(kind, secretText, plainText),
+ (secretText : string, plainText : string, options : CryptoTextCipherOptions | null) : string => aesEncryptText(secretText, plainText, options),
+ (secretText : string, cipherText : string, options : CryptoTextCipherOptions | null) : string => aesDecryptText(secretText, cipherText, options),
+ (secretBytes : Uint8Array, plainBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array => aesEncryptBytes(secretBytes, plainBytes, options),
+ (secretBytes : Uint8Array, cipherBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array => aesDecryptBytes(secretBytes, cipherBytes, options),
+ (secretText : string, plainText : string, options : CryptoDesOptions | null) : string => desEncryptText(secretText, plainText, options),
+ (secretText : string, cipherText : string, options : CryptoDesOptions | null) : string => desDecryptText(secretText, cipherText, options),
+ (keySize : number) : CryptoRsaPair => createRsaPair(keySize),
+ (publicKey : string, plainText : string, outputKind : RsaOutputKind | null) : string => rsaEncryptText(publicKey, plainText, outputKind),
+ (privateKey : string, cipherText : string, outputKind : RsaOutputKind | null) : string => rsaDecryptText(privateKey, cipherText, outputKind),
+ (secretText : string, plainText : string) : string => rc4EncryptText(secretText, plainText),
+ (secretText : string, cipherHexText : string) : string => rc4DecryptText(secretText, cipherHexText)
+ )
+}
+
+export function base64Encode(input : string) : string {
+ return base64EncodeCompat(compatBridge(), input)
+}
+
+export function base64Decode(input : string) : string {
+ return base64DecodeCompat(compatBridge(), input)
+}
+
+export function md5(input : string) : string {
+ return md5Compat(compatBridge(), input)
+}
+
+export function sha1(input : string) : string {
+ return sha1Compat(compatBridge(), input)
+}
+
+export function sha256(input : string) : string {
+ return sha256Compat(compatBridge(), input)
+}
+
+export function sha512(input : string) : string {
+ return sha512Compat(compatBridge(), input)
+}
+
+export function hmacSha1(key : string, data : string) : string {
+ return hmacSha1Compat(compatBridge(), key, data)
+}
+
+export function hmacSha256(key : string, data : string) : string {
+ return hmacSha256Compat(compatBridge(), key, data)
+}
+
+export function hmacSha512(key : string, data : string) : string {
+ return hmacSha512Compat(compatBridge(), key, data)
+}
+
+export function aesEncrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null, keySize : number | null = 16) : string {
+ return aesEncryptCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function aesDecrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null, keySize : number | null = 16) : string {
+ return aesDecryptCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function aesEncrypt2(key : Uint8Array, data : Uint8Array, mode : string = 'ECB', iv : Uint8Array | null = null, keySize : number | null = 16) : Uint8Array {
+ return aesEncryptBytesCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function aesDecrypt2(key : Uint8Array, data : Uint8Array, mode : string = 'ECB', iv : Uint8Array | null = null, keySize : number | null = 16) : Uint8Array {
+ return aesDecryptBytesCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function desEncrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null) : string {
+ return desEncryptCompat(compatBridge(), key, data, mode, iv)
+}
+
+export function desDecrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null) : string {
+ return desDecryptCompat(compatBridge(), key, data, mode, iv)
+}
+
+export function generateRSAKeyPair(keySize : number = 2048) : CryptoRsaPair {
+ return generateRsaKeyPairCompat(compatBridge(), keySize)
+}
+
+export function rsaEncrypt(publicKey : string, data : string) : string {
+ return rsaEncryptCompat(compatBridge(), publicKey, data)
+}
+
+export function rsaDecrypt(privateKey : string, data : string) : string {
+ return rsaDecryptCompat(compatBridge(), privateKey, data)
+}
+
+export function rc4Encrypt(key : string, data : string) : string {
+ return rc4EncryptCompat(compatBridge(), key, data)
+}
+
+export function rc4Decrypt(key : string, data : string) : string {
+ return rc4DecryptCompat(compatBridge(), key, data)
+}
+
+export function useCrypto() : CompatCrypto {
+ return createCompatCrypto(compatBridge())
+}
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/app-harmony/native_rsa.ets b/uni_modules/laoqianjunzi-crypto/utssdk/app-harmony/native_rsa.ets
new file mode 100644
index 0000000..03d7765
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/app-harmony/native_rsa.ets
@@ -0,0 +1,176 @@
+import cryptoFramework from '@ohos.security.cryptoFramework'
+import util from '@ohos.util'
+
+const UTF8_ENCODER = new util.TextEncoder('utf-8')
+const UTF8_DECODER = util.TextDecoder.create('utf-8')
+const BASE64_HELPER = new util.Base64Helper()
+
+const PUBLIC_PEM_FORMATS: string[] = ['X509', 'x509', 'SPKI', 'spki', 'PKCS1', 'pkcs1']
+const PRIVATE_PEM_FORMATS: string[] = ['PKCS8', 'pkcs8', 'PKCS1', 'pkcs1']
+const RSA_GENERATOR_ALGS: string[] = ['RSA']
+const RSA_CIPHER_ALGS: string[] = [
+ 'RSA/ECB/PKCS1Padding',
+ 'RSA/None/PKCS1Padding',
+ 'RSA/None/OAEPWithSHA256AndMGF1Padding',
+ 'RSA'
+]
+
+export class NativeRsaBundle {
+ public publicKey: string
+ public privateKey: string
+
+ constructor(publicKey: string = '', privateKey: string = '') {
+ this.publicKey = publicKey
+ this.privateKey = privateKey
+ }
+}
+
+export class NativeHarmonyRsaCore {
+ static createRsaBundle(keySize: number): NativeRsaBundle {
+ const generator = NativeHarmonyRsaCore.createKeyGenerator(keySize)
+ const keyPair = generator.generateKeyPairSync()
+ const publicKey = NativeHarmonyRsaCore.exportPublicPem(keyPair.pubKey)
+ const privateKey = NativeHarmonyRsaCore.exportPrivatePem(keyPair.priKey)
+ return new NativeRsaBundle(publicKey, privateKey)
+ }
+
+ static rsaEncrypt(publicKey: string, plainText: string, outputKind: string | null): string {
+ const keyPair = NativeHarmonyRsaCore.importPemKeyPair(publicKey, null)
+ const cipher = NativeHarmonyRsaCore.createCipher()
+ cipher.initSync(cryptoFramework.CryptoMode.ENCRYPT_MODE, keyPair.pubKey, null)
+ const output = cipher.doFinalSync({ data: NativeHarmonyRsaCore.encodeUtf8(plainText) })
+ return NativeHarmonyRsaCore.encodeCipherOutput(output.data, outputKind)
+ }
+
+ static rsaDecrypt(privateKey: string, cipherText: string, outputKind: string | null): string {
+ const keyPair = NativeHarmonyRsaCore.importPemKeyPair(null, privateKey)
+ const cipher = NativeHarmonyRsaCore.createCipher()
+ cipher.initSync(cryptoFramework.CryptoMode.DECRYPT_MODE, keyPair.priKey, null)
+ const sourceBytes = NativeHarmonyRsaCore.decodeCipherInput(cipherText)
+ const output = cipher.doFinalSync({ data: sourceBytes })
+ return NativeHarmonyRsaCore.decodePlainOutput(output.data, outputKind)
+ }
+
+ private static createKeyGenerator(keySize: number): cryptoFramework.AsyKeyGenerator {
+ const candidates: string[] = [
+ 'RSA' + keySize.toString(),
+ 'RSA|' + keySize.toString(),
+ 'RSA/' + keySize.toString(),
+ 'RSA'
+ ]
+ let lastError: Error | null = null
+ for (const algName of candidates) {
+ try {
+ return cryptoFramework.createAsyKeyGenerator(algName)
+ } catch (error) {
+ lastError = error as Error
+ }
+ }
+ throw lastError ?? new Error('create RSA key generator failed')
+ }
+
+ private static importPemKeyPair(publicKey: string | null, privateKey: string | null): cryptoFramework.KeyPair {
+ let lastError: Error | null = null
+ for (const algName of RSA_GENERATOR_ALGS) {
+ try {
+ const generator = cryptoFramework.createAsyKeyGenerator(algName)
+ return generator.convertPemKeySync(publicKey, privateKey)
+ } catch (error) {
+ lastError = error as Error
+ }
+ }
+ throw lastError ?? new Error('import RSA PEM failed')
+ }
+
+ private static createCipher(): cryptoFramework.Cipher {
+ let lastError: Error | null = null
+ for (const algName of RSA_CIPHER_ALGS) {
+ try {
+ return cryptoFramework.createCipher(algName)
+ } catch (error) {
+ lastError = error as Error
+ }
+ }
+ throw lastError ?? new Error('create RSA cipher failed')
+ }
+
+ private static exportPublicPem(publicKey: cryptoFramework.PubKey): string {
+ let lastError: Error | null = null
+ for (const formatName of PUBLIC_PEM_FORMATS) {
+ try {
+ return publicKey.getEncodedPem(formatName)
+ } catch (error) {
+ lastError = error as Error
+ }
+ }
+ throw lastError ?? new Error('export public PEM failed')
+ }
+
+ private static exportPrivatePem(privateKey: cryptoFramework.PriKey): string {
+ let lastError: Error | null = null
+ for (const formatName of PRIVATE_PEM_FORMATS) {
+ try {
+ return privateKey.getEncodedPem(formatName)
+ } catch (error) {
+ lastError = error as Error
+ }
+ }
+ throw lastError ?? new Error('export private PEM failed')
+ }
+
+ private static encodeUtf8(input: string): Uint8Array {
+ return UTF8_ENCODER.encodeInto(input)
+ }
+
+ private static decodeUtf8(input: Uint8Array): string {
+ return UTF8_DECODER.decode(input)
+ }
+
+ private static encodeCipherOutput(input: Uint8Array, outputKind: string | null): string {
+ if (outputKind === 'hex') {
+ return NativeHarmonyRsaCore.bytesToHex(input)
+ }
+ return BASE64_HELPER.encodeToStringSync(input)
+ }
+
+ private static decodePlainOutput(input: Uint8Array, outputKind: string | null): string {
+ if (outputKind === 'hex') {
+ return NativeHarmonyRsaCore.bytesToHex(input)
+ }
+ return NativeHarmonyRsaCore.decodeUtf8(input)
+ }
+
+ private static decodeCipherInput(cipherText: string): Uint8Array {
+ const normalized = cipherText.trim()
+ if (NativeHarmonyRsaCore.looksLikeHex(normalized)) {
+ return NativeHarmonyRsaCore.hexToBytes(normalized)
+ }
+ return BASE64_HELPER.decodeSync(normalized)
+ }
+
+ private static looksLikeHex(input: string): boolean {
+ return input.length > 0 && input.length % 2 == 0 && /^[0-9a-fA-F]+$/.test(input)
+ }
+
+ private static bytesToHex(input: Uint8Array): string {
+ let output = ''
+ for (let i = 0; i < input.length; i++) {
+ const item = input[i]
+ if (item < 16) {
+ output += '0'
+ }
+ output += item.toString(16)
+ }
+ return output
+ }
+
+ private static hexToBytes(input: string): Uint8Array {
+ const length = input.length / 2
+ const output = new Uint8Array(length)
+ for (let i = 0; i < length; i++) {
+ const offset = i * 2
+ output[i] = Number.parseInt(input.substring(offset, offset + 2), 16)
+ }
+ return output
+ }
+}
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/app-ios/NativeCipherCore.swift b/uni_modules/laoqianjunzi-crypto/utssdk/app-ios/NativeCipherCore.swift
new file mode 100644
index 0000000..5448d97
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/app-ios/NativeCipherCore.swift
@@ -0,0 +1,1130 @@
+import Foundation
+import CommonCrypto
+import Security
+
+public struct NativeRsaBundle {
+ public let publicKey: String
+ public let privateKey: String
+
+ public init(publicKey: String, privateKey: String) {
+ self.publicKey = publicKey
+ self.privateKey = privateKey
+ }
+}
+
+public enum NativeCipherCore {
+ public static func digestHex(kind: String, plainText: String) throws -> String {
+ let input = Data(plainText.utf8)
+ let digest: Data
+ switch normalize(kind) {
+ case "MD5":
+ digest = hashData(input, length: Int(CC_MD5_DIGEST_LENGTH)) { buffer, bytes, count in
+ _ = CC_MD5(bytes, CC_LONG(count), buffer.bindMemory(to: UInt8.self).baseAddress)
+ }
+ case "SHA1":
+ digest = hashData(input, length: Int(CC_SHA1_DIGEST_LENGTH)) { buffer, bytes, count in
+ _ = CC_SHA1(bytes, CC_LONG(count), buffer.bindMemory(to: UInt8.self).baseAddress)
+ }
+ case "SHA256":
+ digest = hashData(input, length: Int(CC_SHA256_DIGEST_LENGTH)) { buffer, bytes, count in
+ _ = CC_SHA256(bytes, CC_LONG(count), buffer.bindMemory(to: UInt8.self).baseAddress)
+ }
+ case "SHA512":
+ digest = hashData(input, length: Int(CC_SHA512_DIGEST_LENGTH)) { buffer, bytes, count in
+ _ = CC_SHA512(bytes, CC_LONG(count), buffer.bindMemory(to: UInt8.self).baseAddress)
+ }
+ default:
+ throw cipherError("不支持的摘要算法")
+ }
+ return digest.hexString()
+ }
+
+ public static func hmacHex(kind: String, secretText: String, plainText: String) throws -> String {
+ let algorithm: CCHmacAlgorithm
+ let digestLength: Int
+ switch normalize(kind) {
+ case "SHA1":
+ algorithm = CCHmacAlgorithm(kCCHmacAlgSHA1)
+ digestLength = Int(CC_SHA1_DIGEST_LENGTH)
+ case "SHA256":
+ algorithm = CCHmacAlgorithm(kCCHmacAlgSHA256)
+ digestLength = Int(CC_SHA256_DIGEST_LENGTH)
+ case "SHA512":
+ algorithm = CCHmacAlgorithm(kCCHmacAlgSHA512)
+ digestLength = Int(CC_SHA512_DIGEST_LENGTH)
+ default:
+ throw cipherError("不支持的HMAC算法")
+ }
+
+ let keyData = Data(secretText.utf8)
+ let inputData = Data(plainText.utf8)
+ var output = Data(count: digestLength)
+ output.withUnsafeMutableBytes { outputBuffer in
+ keyData.withUnsafeBytes { keyBuffer in
+ inputData.withUnsafeBytes { inputBuffer in
+ CCHmac(
+ algorithm,
+ keyBuffer.baseAddress,
+ keyData.count,
+ inputBuffer.baseAddress,
+ inputData.count,
+ outputBuffer.baseAddress
+ )
+ }
+ }
+ }
+ return output.hexString()
+ }
+
+ public static func encodeBase64(plainText: String) -> String {
+ Data(plainText.utf8).base64EncodedString()
+ }
+
+ public static func decodeBase64(encodedText: String) throws -> String {
+ guard let data = Data(base64Encoded: encodedText) else {
+ throw cipherError("Base64无效")
+ }
+ guard let text = String(data: data, encoding: .utf8) else {
+ throw cipherError("文本解码失败")
+ }
+ return text
+ }
+
+ public static func encodeCodec(codec: String, plainText: String) throws -> String {
+ let input = Data(plainText.utf8)
+ switch normalize(codec) {
+ case "UTF8":
+ return plainText
+ case "HEX":
+ return input.hexString()
+ case "BASE64":
+ return input.base64EncodedString()
+ case "BASE64URL":
+ return input.base64EncodedString()
+ .replacingOccurrences(of: "+", with: "-")
+ .replacingOccurrences(of: "/", with: "_")
+ .replacingOccurrences(of: "=+$", with: "", options: .regularExpression)
+ case "LATIN1":
+ return latin1String(from: input)
+ case "UTF16":
+ return utf16CodecString(from: input)
+ default:
+ throw cipherError("不支持的编码类型")
+ }
+ }
+
+ public static func decodeCodec(codec: String, encodedText: String) throws -> String {
+ switch normalize(codec) {
+ case "UTF8":
+ return encodedText
+ case "HEX":
+ return try utf8String(from: Data(hexString: encodedText))
+ case "BASE64":
+ return try decodeBase64(encodedText: encodedText)
+ case "BASE64URL":
+ var normalized = encodedText.replacingOccurrences(of: "-", with: "+")
+ .replacingOccurrences(of: "_", with: "/")
+ while normalized.count % 4 != 0 {
+ normalized.append("=")
+ }
+ return try decodeBase64(encodedText: normalized)
+ case "LATIN1":
+ return try utf8String(from: dataFromLatin1String(encodedText))
+ case "UTF16":
+ return try utf8String(from: dataFromUtf16CodecString(encodedText))
+ default:
+ throw cipherError("不支持的编码类型")
+ }
+ }
+
+ public static func aesEncryptText(secretText: String, plainText: String, mode: String, padding: String, ivText: String?, keyLength: Int?) throws -> String {
+ let cipherBytes = try aesEncryptBytes(
+ secretBytes: Array(Data(secretText.utf8)),
+ plainBytes: Array(Data(plainText.utf8)),
+ mode: mode,
+ padding: padding,
+ ivBytes: ivText.map { Array(Data($0.utf8)) },
+ keyLength: keyLength
+ )
+ return Data(cipherBytes).base64EncodedString()
+ }
+
+ public static func aesDecryptText(secretText: String, cipherText: String, mode: String, padding: String, ivText: String?, keyLength: Int?) throws -> String {
+ guard let cipherData = Data(base64Encoded: cipherText) else {
+ throw cipherError("Base64无效")
+ }
+ let plainBytes = try aesDecryptBytes(
+ secretBytes: Array(Data(secretText.utf8)),
+ cipherBytes: Array(cipherData),
+ mode: mode,
+ padding: padding,
+ ivBytes: ivText.map { Array(Data($0.utf8)) },
+ keyLength: keyLength
+ )
+ guard let text = String(data: Data(plainBytes), encoding: .utf8) else {
+ throw cipherError("文本解码失败")
+ }
+ return text
+ }
+
+ public static func aesEncryptBytes(secretBytes: [UInt8], plainBytes: [UInt8], mode: String, padding: String, ivBytes: [UInt8]?, keyLength: Int?) throws -> [UInt8] {
+ let config = try makeAesConfig(mode: mode, padding: padding, keyLength: keyLength)
+ let key = try normalizeKey(secretBytes, to: config.keyLength)
+ let iv = try normalizeIV(ivBytes, blockSize: kCCBlockSizeAES128, mode: config.mode)
+ let plainData = Data(plainBytes)
+ let padded = try applyPaddingIfNeeded(plainData, blockSize: kCCBlockSizeAES128, padding: config.padding, mode: config.mode)
+ let encrypted = try cryptWithMode(
+ operation: CCOperation(kCCEncrypt),
+ algorithm: CCAlgorithm(kCCAlgorithmAES),
+ mode: config.mode.ccMode,
+ options: config.mode.ccOptions,
+ key: key,
+ iv: iv,
+ input: padded
+ )
+ return Array(encrypted)
+ }
+
+ public static func aesDecryptBytes(secretBytes: [UInt8], cipherBytes: [UInt8], mode: String, padding: String, ivBytes: [UInt8]?, keyLength: Int?) throws -> [UInt8] {
+ let config = try makeAesConfig(mode: mode, padding: padding, keyLength: keyLength)
+ let key = try normalizeKey(secretBytes, to: config.keyLength)
+ let iv = try normalizeIV(ivBytes, blockSize: kCCBlockSizeAES128, mode: config.mode)
+ let decrypted = try cryptWithMode(
+ operation: CCOperation(kCCDecrypt),
+ algorithm: CCAlgorithm(kCCAlgorithmAES),
+ mode: config.mode.ccMode,
+ options: config.mode.ccOptions,
+ key: key,
+ iv: iv,
+ input: Data(cipherBytes)
+ )
+ let plainData = try removePaddingIfNeeded(decrypted, blockSize: kCCBlockSizeAES128, padding: config.padding, mode: config.mode)
+ return Array(plainData)
+ }
+
+ public static func tripleDesEncryptText(secretText: String, plainText: String, mode: String, ivText: String?) throws -> String {
+ let cipherData = try tripleDesTransform(
+ operation: CCOperation(kCCEncrypt),
+ secretBytes: Array(Data(secretText.utf8)),
+ input: try applyPadding(Data(plainText.utf8), blockSize: kCCBlockSize3DES, padding: .pkcs7),
+ modeName: mode,
+ ivBytes: ivText.map { Array(Data($0.utf8)) }
+ )
+ return cipherData.base64EncodedString()
+ }
+
+ public static func tripleDesDecryptText(secretText: String, cipherText: String, mode: String, ivText: String?) throws -> String {
+ guard let cipherData = Data(base64Encoded: cipherText) else {
+ throw cipherError("Base64无效")
+ }
+ let plainData = try tripleDesTransform(
+ operation: CCOperation(kCCDecrypt),
+ secretBytes: Array(Data(secretText.utf8)),
+ input: cipherData,
+ modeName: mode,
+ ivBytes: ivText.map { Array(Data($0.utf8)) }
+ )
+ let unpadded = try removePadding(plainData, blockSize: kCCBlockSize3DES, padding: .pkcs7)
+ guard let text = String(data: unpadded, encoding: .utf8) else {
+ throw cipherError("文本解码失败")
+ }
+ return text
+ }
+
+ public static func desEncryptText(secretText: String, plainText: String, mode: String, padding: String, ivText: String?) throws -> String {
+ let config = try makeDesConfig(mode: mode, padding: padding)
+ let key = try normalizeKey(Array(Data(secretText.utf8)), to: kCCKeySizeDES)
+ let iv = try normalizeIV(ivText.map { Array(Data($0.utf8)) }, blockSize: kCCBlockSizeDES, mode: config.mode)
+ let padded = try applyPaddingIfNeeded(Data(plainText.utf8), blockSize: kCCBlockSizeDES, padding: config.padding, mode: config.mode)
+ let encrypted = try cryptWithMode(
+ operation: CCOperation(kCCEncrypt),
+ algorithm: CCAlgorithm(kCCAlgorithmDES),
+ mode: config.mode.ccMode,
+ options: config.mode.ccOptions,
+ key: key,
+ iv: iv,
+ input: padded
+ )
+ return encrypted.base64EncodedString()
+ }
+
+ public static func desDecryptText(secretText: String, cipherText: String, mode: String, padding: String, ivText: String?) throws -> String {
+ guard let cipherData = Data(base64Encoded: cipherText) else {
+ throw cipherError("Base64无效")
+ }
+ let config = try makeDesConfig(mode: mode, padding: padding)
+ let key = try normalizeKey(Array(Data(secretText.utf8)), to: kCCKeySizeDES)
+ let iv = try normalizeIV(ivText.map { Array(Data($0.utf8)) }, blockSize: kCCBlockSizeDES, mode: config.mode)
+ let decrypted = try cryptWithMode(
+ operation: CCOperation(kCCDecrypt),
+ algorithm: CCAlgorithm(kCCAlgorithmDES),
+ mode: config.mode.ccMode,
+ options: config.mode.ccOptions,
+ key: key,
+ iv: iv,
+ input: cipherData
+ )
+ let plainData = try removePaddingIfNeeded(decrypted, blockSize: kCCBlockSizeDES, padding: config.padding, mode: config.mode)
+ return try utf8String(from: plainData)
+ }
+
+ public static func rc4EncryptToHex(secretText: String, plainText: String) throws -> String {
+ let cipher = try rc4Transform(secret: Data(secretText.utf8), input: Data(plainText.utf8))
+ return cipher.hexString()
+ }
+
+ public static func rc4DecryptFromHex(secretText: String, cipherHexText: String) throws -> String {
+ let cipher = try Data(hexString: cipherHexText)
+ let plain = try rc4Transform(secret: Data(secretText.utf8), input: cipher)
+ guard let text = String(data: plain, encoding: .utf8) else {
+ throw cipherError("文本解码失败")
+ }
+ return text
+ }
+
+ public static func createRsaBundle(keySize: Int) throws -> NativeRsaBundle {
+ let normalizedKeySize = try normalizeRsaKeySize(keySize)
+ let attributes: [String: Any] = [
+ kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
+ kSecAttrKeySizeInBits as String: normalizedKeySize,
+ kSecPrivateKeyAttrs as String: [
+ kSecAttrIsPermanent as String: false
+ ],
+ kSecPublicKeyAttrs as String: [
+ kSecAttrIsPermanent as String: false
+ ]
+ ]
+
+ var error: Unmanaged?
+ guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
+ throw securityError(error, fallback: "RSA生成失败")
+ }
+ guard let publicKey = SecKeyCopyPublicKey(privateKey) else {
+ throw cipherError("RSA公钥生成失败")
+ }
+
+ guard let privateData = SecKeyCopyExternalRepresentation(privateKey, &error) as Data? else {
+ throw securityError(error, fallback: "导出私钥失败")
+ }
+ guard let publicPkcs1 = SecKeyCopyExternalRepresentation(publicKey, &error) as Data? else {
+ throw securityError(error, fallback: "导出公钥失败")
+ }
+
+ let publicPem = pemString(header: "PUBLIC KEY", body: wrapRsaPublicKeyToSpki(publicPkcs1))
+ let privatePem = pemString(header: "RSA PRIVATE KEY", body: privateData)
+ return NativeRsaBundle(publicKey: publicPem, privateKey: privatePem)
+ }
+
+ public static func rsaEncrypt(publicKey: String, plainText: String, outputKind: String?) throws -> String {
+ let key = try makeRsaPublicKey(from: publicKey)
+ let plainData = Data(plainText.utf8)
+ let encrypted = try rsaChunkedTransform(key: key, data: plainData, encrypting: true)
+ return try encodeCipherOutput(encrypted, kind: outputKind)
+ }
+
+ public static func rsaDecrypt(privateKey: String, cipherText: String, outputKind: String?) throws -> String {
+ let key = try makeRsaPrivateKey(from: privateKey)
+ let cipherData = try decodeCipherInput(cipherText, kind: outputKind)
+ let decrypted = try rsaChunkedTransform(key: key, data: cipherData, encrypting: false)
+ guard let text = String(data: decrypted, encoding: .utf8) else {
+ throw cipherError("文本解码失败")
+ }
+ return text
+ }
+}
+
+private enum NativeAesMode {
+ case ecb
+ case cbc
+ case cfb
+ case ctr
+ case ctrGladman
+ case ofb
+
+ var ccMode: CCMode {
+ switch self {
+ case .ecb:
+ return CCMode(kCCModeECB)
+ case .cbc:
+ return CCMode(kCCModeCBC)
+ case .cfb:
+ return CCMode(kCCModeCFB)
+ case .ctr, .ctrGladman:
+ return CCMode(kCCModeCTR)
+ case .ofb:
+ return CCMode(kCCModeOFB)
+ }
+ }
+
+ var ccOptions: CCModeOptions {
+ switch self {
+ case .ctr:
+ return CCModeOptions(kCCModeOptionCTR_BE)
+ case .ctrGladman:
+ // CommonCrypto 未单独提供 Gladman 计数器模式,这里映射为标准 CTR 兼容实现。
+ return CCModeOptions(kCCModeOptionCTR_BE)
+ default:
+ return CCModeOptions(0)
+ }
+ }
+
+ var needsBlockAlignmentWithoutPadding: Bool {
+ switch self {
+ case .ecb, .cbc:
+ return true
+ default:
+ return false
+ }
+ }
+
+ var usesIV: Bool {
+ switch self {
+ case .ecb:
+ return false
+ default:
+ return true
+ }
+ }
+}
+
+private enum NativePadding {
+ case pkcs7
+ case ansiX923
+ case iso10126
+ case iso97971
+ case none
+ case zero
+}
+
+private struct AesConfig {
+ let mode: NativeAesMode
+ let padding: NativePadding
+ let keyLength: Int
+}
+
+private struct DesConfig {
+ let mode: NativeAesMode
+ let padding: NativePadding
+}
+
+private func makeAesConfig(mode: String, padding: String, keyLength: Int?) throws -> AesConfig {
+ let aesMode: NativeAesMode
+ switch normalize(mode) {
+ case "ECB":
+ aesMode = .ecb
+ case "CBC":
+ aesMode = .cbc
+ case "CFB":
+ aesMode = .cfb
+ case "CTR":
+ aesMode = .ctr
+ case "CTRGLADMAN":
+ aesMode = .ctrGladman
+ case "OFB":
+ aesMode = .ofb
+ default:
+ throw cipherError("不支持的AES模式")
+ }
+
+ let aesPadding: NativePadding
+ switch normalize(padding) {
+ case "PKCS7":
+ aesPadding = .pkcs7
+ case "ANSI_X923":
+ aesPadding = .ansiX923
+ case "ISO_10126":
+ aesPadding = .iso10126
+ case "ISO_97971":
+ aesPadding = .iso97971
+ case "NONE":
+ aesPadding = .none
+ case "ZERO":
+ aesPadding = .zero
+ default:
+ throw cipherError("不支持的AES填充")
+ }
+
+ return AesConfig(mode: aesMode, padding: aesPadding, keyLength: try normalizeAesKeyLength(keyLength))
+}
+
+private func makeDesConfig(mode: String, padding: String) throws -> DesConfig {
+ let desMode: NativeAesMode
+ switch normalize(mode) {
+ case "ECB":
+ desMode = .ecb
+ case "CBC":
+ desMode = .cbc
+ case "CFB":
+ desMode = .cfb
+ case "CTR", "CTRGLADMAN":
+ desMode = .ctr
+ case "OFB":
+ desMode = .ofb
+ default:
+ throw cipherError("不支持的DES模式")
+ }
+
+ let desPadding: NativePadding
+ switch normalize(padding) {
+ case "PKCS7":
+ desPadding = .pkcs7
+ case "ANSI_X923":
+ desPadding = .ansiX923
+ case "ISO_10126":
+ desPadding = .iso10126
+ case "ISO_97971":
+ desPadding = .iso97971
+ case "NONE":
+ desPadding = .none
+ case "ZERO":
+ desPadding = .zero
+ default:
+ throw cipherError("不支持的DES填充")
+ }
+
+ return DesConfig(mode: desMode, padding: desPadding)
+}
+
+private func normalize(_ value: String) -> String {
+ value.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
+}
+
+private func normalizeAesKeyLength(_ keyLength: Int?) throws -> Int {
+ guard let keyLength else {
+ return kCCKeySizeAES256
+ }
+ switch keyLength {
+ case 16, 24, 32:
+ return keyLength
+ case 128, 192, 256:
+ return keyLength / 8
+ default:
+ throw cipherError("AES密钥长度无效")
+ }
+}
+
+private func normalizeRsaKeySize(_ keySize: Int) throws -> Int {
+ if keySize == 1024 || keySize == 2048 || keySize == 3072 || keySize == 4096 {
+ return keySize
+ }
+ throw cipherError("RSA密钥长度无效")
+}
+
+private func normalizeKey(_ secretBytes: [UInt8], to length: Int) throws -> Data {
+ if secretBytes.isEmpty {
+ throw cipherError("密钥不能为空")
+ }
+ var key = Data(secretBytes)
+ if key.count > length {
+ key = key.prefix(length)
+ } else if key.count < length {
+ key.append(Data(repeating: 0, count: length - key.count))
+ }
+ return key
+}
+
+private func normalizeIV(_ ivBytes: [UInt8]?, blockSize: Int, mode: NativeAesMode) throws -> Data? {
+ guard mode.usesIV else {
+ return nil
+ }
+ var iv = Data(ivBytes ?? [])
+ if iv.count > blockSize {
+ iv = iv.prefix(blockSize)
+ } else if iv.count < blockSize {
+ iv.append(Data(repeating: 0, count: blockSize - iv.count))
+ }
+ return iv
+}
+
+private func applyPaddingIfNeeded(_ data: Data, blockSize: Int, padding: NativePadding, mode: NativeAesMode) throws -> Data {
+ if padding == .none && !mode.needsBlockAlignmentWithoutPadding {
+ return data
+ }
+ return try applyPadding(data, blockSize: blockSize, padding: padding)
+}
+
+private func removePaddingIfNeeded(_ data: Data, blockSize: Int, padding: NativePadding, mode: NativeAesMode) throws -> Data {
+ if padding == .none && !mode.needsBlockAlignmentWithoutPadding {
+ return data
+ }
+ return try removePadding(data, blockSize: blockSize, padding: padding)
+}
+
+private func applyPadding(_ data: Data, blockSize: Int, padding: NativePadding) throws -> Data {
+ switch padding {
+ case .none:
+ if data.count % blockSize != 0 {
+ throw cipherError("数据长度无效")
+ }
+ return data
+ case .pkcs7:
+ let remain = data.count % blockSize
+ let actualPad = remain == 0 ? blockSize : blockSize - remain
+ return data + Data(repeating: UInt8(actualPad), count: actualPad)
+ case .ansiX923:
+ let padCount = blockSize - (data.count % blockSize)
+ let actualPad = padCount == 0 ? blockSize : padCount
+ var result = data
+ if actualPad > 1 {
+ result.append(Data(repeating: 0, count: actualPad - 1))
+ }
+ result.append(UInt8(actualPad))
+ return result
+ case .iso10126:
+ let padCount = blockSize - (data.count % blockSize)
+ let actualPad = padCount == 0 ? blockSize : padCount
+ var result = data
+ if actualPad > 1 {
+ var random = Data(count: actualPad - 1)
+ let status = random.withUnsafeMutableBytes { SecRandomCopyBytes(kSecRandomDefault, actualPad - 1, $0.baseAddress!) }
+ if status != errSecSuccess {
+ throw cipherError("随机填充失败")
+ }
+ result.append(random)
+ }
+ result.append(UInt8(actualPad))
+ return result
+ case .iso97971:
+ var result = data
+ result.append(0x80)
+ let remain = result.count % blockSize
+ if remain != 0 {
+ result.append(Data(repeating: 0, count: blockSize - remain))
+ }
+ return result
+ case .zero:
+ let remain = data.count % blockSize
+ if remain == 0 {
+ return data
+ }
+ return data + Data(repeating: 0, count: blockSize - remain)
+ }
+}
+
+private func removePadding(_ data: Data, blockSize: Int, padding: NativePadding) throws -> Data {
+ switch padding {
+ case .none:
+ if data.count % blockSize != 0 {
+ throw cipherError("数据长度无效")
+ }
+ return data
+ case .pkcs7:
+ guard let last = data.last else { return data }
+ let pad = Int(last)
+ guard pad > 0, pad <= blockSize, pad <= data.count else {
+ throw cipherError("填充无效")
+ }
+ let tail = data.suffix(pad)
+ if tail.allSatisfy({ $0 == last }) {
+ return Data(data.dropLast(pad))
+ }
+ throw cipherError("填充无效")
+ case .ansiX923:
+ guard let last = data.last else { return data }
+ let pad = Int(last)
+ guard pad > 0, pad <= blockSize, pad <= data.count else {
+ throw cipherError("填充无效")
+ }
+ if pad > 1 && !data.dropLast().suffix(pad - 1).allSatisfy({ $0 == 0 }) {
+ throw cipherError("填充无效")
+ }
+ return Data(data.dropLast(pad))
+ case .iso10126:
+ guard let last = data.last else { return data }
+ let pad = Int(last)
+ guard pad > 0, pad <= blockSize, pad <= data.count else {
+ throw cipherError("填充无效")
+ }
+ return Data(data.dropLast(pad))
+ case .iso97971:
+ var index = data.endIndex
+ while index > data.startIndex {
+ index = data.index(before: index)
+ let value = data[index]
+ if value == 0x80 {
+ return Data(data[.. Data {
+ var cryptor: CCCryptorRef?
+ let status = key.withUnsafeBytes { keyBuffer in
+ ivDataPointer(iv) { ivPointer in
+ CCCryptorCreateWithMode(
+ operation,
+ mode,
+ algorithm,
+ CCPadding(ccNoPadding),
+ ivPointer,
+ keyBuffer.baseAddress,
+ key.count,
+ nil,
+ 0,
+ 0,
+ options,
+ &cryptor
+ )
+ }
+ }
+
+ guard status == kCCSuccess, let cryptor else {
+ throw cipherError("加解密初始化失败")
+ }
+ defer { CCCryptorRelease(cryptor) }
+
+ var output = Data(count: input.count + kCCBlockSizeAES128)
+ var moved = 0
+ var finalMoved = 0
+ let updateStatus = output.withUnsafeMutableBytes { outputBuffer in
+ input.withUnsafeBytes { inputBuffer in
+ CCCryptorUpdate(
+ cryptor,
+ inputBuffer.baseAddress,
+ input.count,
+ outputBuffer.baseAddress,
+ output.count,
+ &moved
+ )
+ }
+ }
+ guard updateStatus == kCCSuccess else {
+ throw cipherError("加解密失败")
+ }
+
+ let finalStatus = output.withUnsafeMutableBytes { outputBuffer in
+ CCCryptorFinal(
+ cryptor,
+ outputBuffer.baseAddress?.advanced(by: moved),
+ output.count - moved,
+ &finalMoved
+ )
+ }
+ guard finalStatus == kCCSuccess else {
+ throw cipherError("加解密失败")
+ }
+ output.removeSubrange((moved + finalMoved)..(_ iv: Data?, _ body: (UnsafeRawPointer?) -> T) -> T {
+ guard let iv else {
+ return body(nil)
+ }
+ return iv.withUnsafeBytes { body($0.baseAddress) }
+}
+
+private func tripleDesTransform(operation: CCOperation, secretBytes: [UInt8], input: Data, modeName: String, ivBytes: [UInt8]?) throws -> Data {
+ let mode: NativeAesMode
+ switch normalize(modeName) {
+ case "ECB":
+ mode = .ecb
+ case "CBC":
+ mode = .cbc
+ default:
+ throw cipherError("不支持的3DES模式")
+ }
+ let key = try normalizeKey(secretBytes, to: kCCKeySize3DES)
+ let iv = try normalizeIV(ivBytes, blockSize: kCCBlockSize3DES, mode: mode)
+ return try cryptWithMode(
+ operation: operation,
+ algorithm: CCAlgorithm(kCCAlgorithm3DES),
+ mode: mode.ccMode,
+ options: CCModeOptions(0),
+ key: key,
+ iv: iv,
+ input: input
+ )
+}
+
+private func rc4Transform(secret: Data, input: Data) throws -> Data {
+ if secret.isEmpty {
+ throw cipherError("密钥不能为空")
+ }
+ var output = Data(count: input.count + kCCBlockSizeRC2)
+ var moved = 0
+ let status = output.withUnsafeMutableBytes { outputBuffer in
+ secret.withUnsafeBytes { keyBuffer in
+ input.withUnsafeBytes { inputBuffer in
+ CCCrypt(
+ CCOperation(kCCEncrypt),
+ CCAlgorithm(kCCAlgorithmRC4),
+ CCOptions(0),
+ keyBuffer.baseAddress,
+ secret.count,
+ nil,
+ inputBuffer.baseAddress,
+ input.count,
+ outputBuffer.baseAddress,
+ output.count,
+ &moved
+ )
+ }
+ }
+ }
+ guard status == kCCSuccess else {
+ throw cipherError("RC4处理失败")
+ }
+ output.removeSubrange(moved.. Void) -> Data {
+ var output = Data(count: length)
+ output.withUnsafeMutableBytes { outputBuffer in
+ input.withUnsafeBytes { inputBuffer in
+ body(outputBuffer, inputBuffer.baseAddress, input.count)
+ }
+ }
+ return output
+}
+
+private func utf8String(from data: Data) throws -> String {
+ guard let text = String(data: data, encoding: .utf8) else {
+ throw cipherError("文本解码失败")
+ }
+ return text
+}
+
+private func latin1String(from data: Data) -> String {
+ var output = ""
+ output.reserveCapacity(data.count)
+ for byte in data {
+ if let scalar = UnicodeScalar(Int(byte)) {
+ output.append(Character(scalar))
+ }
+ }
+ return output
+}
+
+private func dataFromLatin1String(_ text: String) -> Data {
+ var bytes = [UInt8]()
+ bytes.reserveCapacity(text.count)
+ for value in text.unicodeScalars {
+ bytes.append(UInt8(value.value & 0xFF))
+ }
+ return Data(bytes)
+}
+
+private func utf16CodecString(from data: Data) -> String {
+ if data.isEmpty {
+ return ""
+ }
+ var units = [UInt16]()
+ units.reserveCapacity((data.count + 1) / 2)
+ var index = data.startIndex
+ while index < data.endIndex {
+ let high = UInt16(data[index]) << 8
+ let nextIndex = data.index(after: index)
+ let low: UInt16 = nextIndex < data.endIndex ? UInt16(data[nextIndex]) : 0
+ units.append(high | low)
+ index = data.index(index, offsetBy: 2, limitedBy: data.endIndex) ?? data.endIndex
+ }
+ return String(utf16CodeUnits: units, count: units.count)
+}
+
+private func dataFromUtf16CodecString(_ text: String) -> Data {
+ let units = Array(text.utf16)
+ var bytes = [UInt8]()
+ bytes.reserveCapacity(units.count * 2)
+ for unit in units {
+ bytes.append(UInt8((unit >> 8) & 0xFF))
+ bytes.append(UInt8(unit & 0xFF))
+ }
+ return Data(bytes)
+}
+
+private func makeRsaPublicKey(from pem: String) throws -> SecKey {
+ let body = try decodePemBody(from: pem)
+ let raw = pem.contains("BEGIN PUBLIC KEY") ? try unwrapSubjectPublicKeyInfo(body) : body
+ let attributes: [String: Any] = [
+ kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
+ kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
+ kSecAttrKeySizeInBits as String: rsaBitLength(fromPkcs1: raw)
+ ]
+ var error: Unmanaged?
+ guard let key = SecKeyCreateWithData(raw as CFData, attributes as CFDictionary, &error) else {
+ throw securityError(error, fallback: "公钥无效")
+ }
+ return key
+}
+
+private func makeRsaPrivateKey(from pem: String) throws -> SecKey {
+ let body = try decodePemBody(from: pem)
+ let raw = pem.contains("BEGIN PRIVATE KEY") && !pem.contains("BEGIN RSA PRIVATE KEY") ? try unwrapPkcs8PrivateKey(body) : body
+ let attributes: [String: Any] = [
+ kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
+ kSecAttrKeyClass as String: kSecAttrKeyClassPrivate,
+ kSecAttrKeySizeInBits as String: rsaBitLength(fromPrivateKey: raw)
+ ]
+ var error: Unmanaged?
+ guard let key = SecKeyCreateWithData(raw as CFData, attributes as CFDictionary, &error) else {
+ throw securityError(error, fallback: "私钥无效")
+ }
+ return key
+}
+
+private func rsaChunkedTransform(key: SecKey, data: Data, encrypting: Bool) throws -> Data {
+ let algorithm: SecKeyAlgorithm = .rsaEncryptionPKCS1
+ guard SecKeyIsAlgorithmSupported(key, encrypting ? .encrypt : .decrypt, algorithm) else {
+ throw cipherError(encrypting ? "RSA加密不可用" : "RSA解密不可用")
+ }
+
+ let blockSize = SecKeyGetBlockSize(key)
+ let chunkSize = encrypting ? blockSize - 11 : blockSize
+ if chunkSize <= 0 {
+ throw cipherError("RSA块大小无效")
+ }
+
+ var result = Data()
+ var offset = 0
+ while offset < data.count {
+ let next = min(offset + chunkSize, data.count)
+ let chunk = data.subdata(in: offset..?
+ let transformed: Data?
+ if encrypting {
+ transformed = SecKeyCreateEncryptedData(key, algorithm, chunk as CFData, &error) as Data?
+ } else {
+ transformed = SecKeyCreateDecryptedData(key, algorithm, chunk as CFData, &error) as Data?
+ }
+ guard let transformed else {
+ throw securityError(error, fallback: encrypting ? "RSA加密失败" : "RSA解密失败")
+ }
+ result.append(transformed)
+ offset = next
+ }
+ return result
+}
+
+private func encodeCipherOutput(_ data: Data, kind: String?) throws -> String {
+ switch normalize(kind ?? "base64") {
+ case "BASE64":
+ return data.base64EncodedString()
+ case "HEX":
+ return data.hexString()
+ default:
+ throw cipherError("RSA输出格式无效")
+ }
+}
+
+private func decodeCipherInput(_ text: String, kind: String?) throws -> Data {
+ switch normalize(kind ?? "base64") {
+ case "BASE64":
+ guard let data = Data(base64Encoded: text) else {
+ throw cipherError("Base64无效")
+ }
+ return data
+ case "HEX":
+ return try Data(hexString: text)
+ default:
+ throw cipherError("RSA输入格式无效")
+ }
+}
+
+private func decodePemBody(from pem: String) throws -> Data {
+ let lines = pem
+ .components(separatedBy: .newlines)
+ .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
+ .filter { !$0.isEmpty && !$0.hasPrefix("-----BEGIN") && !$0.hasPrefix("-----END") }
+ let joined = lines.joined()
+ guard let data = Data(base64Encoded: joined) else {
+ throw cipherError("PEM无效")
+ }
+ return data
+}
+
+private func pemString(header: String, body: Data) -> String {
+ let content = body.base64EncodedString()
+ let lines = stride(from: 0, to: content.count, by: 64).map { start -> String in
+ let startIndex = content.index(content.startIndex, offsetBy: start)
+ let endIndex = content.index(startIndex, offsetBy: min(64, content.count - start))
+ return String(content[startIndex.. Data {
+ let algorithmIdentifier = Data([0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00])
+ let bitString = asn1Wrap(tag: 0x03, content: Data([0x00]) + pkcs1)
+ return asn1Wrap(tag: 0x30, content: algorithmIdentifier + bitString)
+}
+
+private func unwrapSubjectPublicKeyInfo(_ der: Data) throws -> Data {
+ let sequence = try readAsn1Element(from: der, at: 0, expectedTag: 0x30)
+ var cursor = sequence.contentStartIndex
+ let algorithm = try readAsn1Element(from: der, at: cursor, expectedTag: 0x30)
+ cursor = algorithm.endIndex
+ let bitString = try readAsn1Element(from: der, at: cursor, expectedTag: 0x03)
+ let bitStringData = der.subdata(in: bitString.contentStartIndex.. Data {
+ let sequence = try readAsn1Element(from: der, at: 0, expectedTag: 0x30)
+ var cursor = sequence.contentStartIndex
+ let version = try readAsn1Element(from: der, at: cursor, expectedTag: 0x02)
+ cursor = version.endIndex
+ let algorithm = try readAsn1Element(from: der, at: cursor, expectedTag: 0x30)
+ cursor = algorithm.endIndex
+ let octetString = try readAsn1Element(from: der, at: cursor, expectedTag: 0x04)
+ return der.subdata(in: octetString.contentStartIndex.. Asn1Element {
+ guard index < data.count, data[index] == expectedTag else {
+ throw cipherError("PEM无效")
+ }
+ let lengthInfo = try readAsn1Length(from: data, at: index + 1)
+ let contentStart = lengthInfo.nextIndex
+ let end = contentStart + lengthInfo.length
+ guard end <= data.count else {
+ throw cipherError("PEM无效")
+ }
+ return Asn1Element(contentStartIndex: contentStart, endIndex: end)
+}
+
+private func readAsn1Length(from data: Data, at index: Int) throws -> (length: Int, nextIndex: Int) {
+ guard index < data.count else {
+ throw cipherError("PEM无效")
+ }
+ let first = data[index]
+ if first & 0x80 == 0 {
+ return (Int(first), index + 1)
+ }
+ let byteCount = Int(first & 0x7F)
+ guard byteCount > 0, index + byteCount < data.count else {
+ throw cipherError("PEM无效")
+ }
+ var length = 0
+ for offset in 0.. Data {
+ var output = Data([tag])
+ output.append(asn1LengthBytes(content.count))
+ output.append(content)
+ return output
+}
+
+private func asn1LengthBytes(_ length: Int) -> Data {
+ if length < 0x80 {
+ return Data([UInt8(length)])
+ }
+ var value = length
+ var bytes: [UInt8] = []
+ while value > 0 {
+ bytes.insert(UInt8(value & 0xFF), at: 0)
+ value >>= 8
+ }
+ return Data([0x80 | UInt8(bytes.count)] + bytes)
+}
+
+private func rsaBitLength(fromPkcs1 data: Data) -> Int {
+ if let modulus = try? extractRsaModulus(fromPublicPkcs1: data) {
+ return modulusBitLength(modulus)
+ }
+ return max(1024, data.count * 8)
+}
+
+private func rsaBitLength(fromPrivateKey data: Data) -> Int {
+ if let modulus = try? extractRsaModulus(fromPrivatePkcs1: data) {
+ return modulusBitLength(modulus)
+ }
+ return max(1024, data.count * 8)
+}
+
+private func extractRsaModulus(fromPublicPkcs1 data: Data) throws -> Data {
+ let sequence = try readAsn1Element(from: data, at: 0, expectedTag: 0x30)
+ let integer = try readAsn1Element(from: data, at: sequence.contentStartIndex, expectedTag: 0x02)
+ return trimmedInteger(data.subdata(in: integer.contentStartIndex.. Data {
+ let sequence = try readAsn1Element(from: data, at: 0, expectedTag: 0x30)
+ var cursor = sequence.contentStartIndex
+ let version = try readAsn1Element(from: data, at: cursor, expectedTag: 0x02)
+ cursor = version.endIndex
+ let modulus = try readAsn1Element(from: data, at: cursor, expectedTag: 0x02)
+ return trimmedInteger(data.subdata(in: modulus.contentStartIndex.. Data {
+ var result = data
+ while result.count > 1 && result.first == 0x00 {
+ result.removeFirst()
+ }
+ return result
+}
+
+private func modulusBitLength(_ modulus: Data) -> Int {
+ guard let first = modulus.first else {
+ return 0
+ }
+ var bits = modulus.count * 8
+ var mask: UInt8 = 0x80
+ while mask > 0, first & mask == 0 {
+ bits -= 1
+ mask >>= 1
+ }
+ return bits
+}
+
+private func cipherError(_ message: String) -> NSError {
+ NSError(domain: "NativeCipherCore", code: -1, userInfo: [NSLocalizedDescriptionKey: message])
+}
+
+private func securityError(_ error: Unmanaged?, fallback: String) -> NSError {
+ if let error {
+ let message = CFErrorCopyDescription(error.takeRetainedValue()) as String
+ return cipherError(message.isEmpty ? fallback : message)
+ }
+ return cipherError(fallback)
+}
+
+private extension Data {
+ init(hexString: String) throws {
+ let cleaned = hexString.trimmingCharacters(in: .whitespacesAndNewlines)
+ guard cleaned.count % 2 == 0 else {
+ throw cipherError("Hex无效")
+ }
+ var output = Data(capacity: cleaned.count / 2)
+ var index = cleaned.startIndex
+ while index < cleaned.endIndex {
+ let next = cleaned.index(index, offsetBy: 2)
+ let pair = cleaned[index.. String {
+ map { String(format: "%02x", $0) }.joined()
+ }
+}
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/app-ios/index.uts b/uni_modules/laoqianjunzi-crypto/utssdk/app-ios/index.uts
new file mode 100644
index 0000000..8cb339d
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/app-ios/index.uts
@@ -0,0 +1,251 @@
+import type { CryptoByteCipherOptions, CryptoCodecKind, CryptoDesOptions, CryptoDigestKind, CryptoMacKind, CryptoRsaPair, CryptoRuntimeSnapshot, CryptoTextCipherOptions, CryptoTripleDesOptions, RsaOutputKind } from '../interface.uts'
+import { buildRuntimeSnapshot, createDefaultByteCipherOptions, createDefaultDesOptions, createDefaultTextCipherOptions, createDefaultTripleDesOptions, normalizeByteCipherOptions, normalizeDesOptions, normalizeTextCipherOptions, normalizeTripleDesOptions, resolveHexOutput } from '../shared/options.uts'
+import type { CompatBridge, CompatCrypto } from '../shared/compat.uts'
+import { aesDecryptBytesCompat, aesDecryptCompat, aesEncryptBytesCompat, aesEncryptCompat, base64DecodeCompat, base64EncodeCompat, createCompatBridge, createCompatCrypto, desDecryptCompat, desEncryptCompat, generateRsaKeyPairCompat, hmacSha1Compat, hmacSha256Compat, hmacSha512Compat, md5Compat, rc4DecryptCompat, rc4EncryptCompat, rsaDecryptCompat, rsaEncryptCompat, sha1Compat, sha256Compat, sha512Compat } from '../shared/compat.uts'
+
+function toNumberArray(source : Uint8Array) : number[] {
+ const output = [] as number[]
+ let index = 0
+ while (index < source.length) {
+ output.push(source[index])
+ index += 1
+ }
+ return output
+}
+
+function fromNumberArray(source : number[]) : Uint8Array {
+ const output = new Uint8Array(source.length)
+ let index = 0
+ while (index < source.length) {
+ output[index] = source[index] & 0xff
+ index += 1
+ }
+ return output
+}
+
+function unwrapString(value : string | null, message : string) : string {
+ if (value == null) {
+ throw new Error(message)
+ }
+ return value
+}
+
+function unwrapNumberArray(value : number[] | null, message : string) : number[] {
+ if (value == null) {
+ throw new Error(message)
+ }
+ return value
+}
+
+function unwrapBundle(value : NativeRsaBundle | null, message : string) : NativeRsaBundle {
+ if (value == null) {
+ throw new Error(message)
+ }
+ return value
+}
+
+export function defaultTextCipherOptions() : CryptoTextCipherOptions {
+ return createDefaultTextCipherOptions()
+}
+
+export function defaultByteCipherOptions() : CryptoByteCipherOptions {
+ return createDefaultByteCipherOptions()
+}
+
+export function defaultTripleDesOptions() : CryptoTripleDesOptions {
+ return createDefaultTripleDesOptions()
+}
+
+export function defaultDesOptions() : CryptoDesOptions {
+ return createDefaultDesOptions()
+}
+
+export function describeCryptoRuntime() : CryptoRuntimeSnapshot {
+ return buildRuntimeSnapshot('iOS', 'CommonCrypto', true, true)
+}
+
+export function encodeText(codec : CryptoCodecKind, plainText : string) : string {
+ return unwrapString(UTSiOS.try(NativeCipherCore.encodeCodec(codec, plainText), '?'), '编码失败')
+}
+
+export function decodeText(codec : CryptoCodecKind, encodedText : string) : string {
+ return unwrapString(UTSiOS.try(NativeCipherCore.decodeCodec(codec, encodedText), '?'), '解码失败')
+}
+
+export function digestText(kind : CryptoDigestKind, plainText : string) : string {
+ return unwrapString(UTSiOS.try(NativeCipherCore.digestHex(kind, plainText), '?'), '摘要失败')
+}
+
+export function signText(kind : CryptoMacKind, secretText : string, plainText : string) : string {
+ return unwrapString(UTSiOS.try(NativeCipherCore.hmacHex(kind, secretText, plainText), '?'), 'HMAC失败')
+}
+
+export function aesEncryptText(secretText : string, plainText : string, options : CryptoTextCipherOptions | null) : string {
+ const actual = normalizeTextCipherOptions(options)
+ return unwrapString(UTSiOS.try(NativeCipherCore.aesEncryptText(secretText, plainText, actual.mode, actual.padding, actual.ivText, actual.keyLength), '?'), 'AES加密失败')
+}
+
+export function aesDecryptText(secretText : string, cipherText : string, options : CryptoTextCipherOptions | null) : string {
+ const actual = normalizeTextCipherOptions(options)
+ return unwrapString(UTSiOS.try(NativeCipherCore.aesDecryptText(secretText, cipherText, actual.mode, actual.padding, actual.ivText, actual.keyLength), '?'), 'AES解密失败')
+}
+
+export function aesEncryptBytes(secretBytes : Uint8Array, plainBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array {
+ const actual = normalizeByteCipherOptions(options)
+ const response = unwrapNumberArray(UTSiOS.try(NativeCipherCore.aesEncryptBytes(toNumberArray(secretBytes), toNumberArray(plainBytes), actual.mode, actual.padding, actual.ivBytes == null ? null : toNumberArray(actual.ivBytes), actual.keyLength), '?'), 'AES字节加密失败')
+ return fromNumberArray(response)
+}
+
+export function aesDecryptBytes(secretBytes : Uint8Array, cipherBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array {
+ const actual = normalizeByteCipherOptions(options)
+ const response = unwrapNumberArray(UTSiOS.try(NativeCipherCore.aesDecryptBytes(toNumberArray(secretBytes), toNumberArray(cipherBytes), actual.mode, actual.padding, actual.ivBytes == null ? null : toNumberArray(actual.ivBytes), actual.keyLength), '?'), 'AES字节解密失败')
+ return fromNumberArray(response)
+}
+
+export function tripleDesEncryptText(secretText : string, plainText : string, options : CryptoTripleDesOptions | null) : string {
+ const actual = normalizeTripleDesOptions(options)
+ return unwrapString(UTSiOS.try(NativeCipherCore.tripleDesEncryptText(secretText, plainText, actual.mode, actual.ivText), '?'), '3DES加密失败')
+}
+
+export function tripleDesDecryptText(secretText : string, cipherText : string, options : CryptoTripleDesOptions | null) : string {
+ const actual = normalizeTripleDesOptions(options)
+ return unwrapString(UTSiOS.try(NativeCipherCore.tripleDesDecryptText(secretText, cipherText, actual.mode, actual.ivText), '?'), '3DES解密失败')
+}
+
+export function desEncryptText(secretText : string, plainText : string, options : CryptoDesOptions | null) : string {
+ const actual = normalizeDesOptions(options)
+ return unwrapString(UTSiOS.try(NativeCipherCore.desEncryptText(secretText, plainText, actual.mode, actual.padding, actual.ivText), '?'), 'DES加密失败')
+}
+
+export function desDecryptText(secretText : string, cipherText : string, options : CryptoDesOptions | null) : string {
+ const actual = normalizeDesOptions(options)
+ return unwrapString(UTSiOS.try(NativeCipherCore.desDecryptText(secretText, cipherText, actual.mode, actual.padding, actual.ivText), '?'), 'DES解密失败')
+}
+
+export function rc4EncryptText(secretText : string, plainText : string) : string {
+ return unwrapString(UTSiOS.try(NativeCipherCore.rc4EncryptToHex(secretText, plainText), '?'), 'RC4加密失败')
+}
+
+export function rc4DecryptText(secretText : string, cipherHexText : string) : string {
+ return unwrapString(UTSiOS.try(NativeCipherCore.rc4DecryptFromHex(secretText, cipherHexText), '?'), 'RC4解密失败')
+}
+
+export function createRsaPair(keySize : number) : CryptoRsaPair {
+ const bundle = unwrapBundle(UTSiOS.try(NativeCipherCore.createRsaBundle(keySize), '?'), 'RSA密钥生成失败')
+ return {
+ publicKey: bundle.publicKey,
+ privateKey: bundle.privateKey
+ } as CryptoRsaPair
+}
+
+export function rsaEncryptText(publicKey : string, plainText : string, outputKind : RsaOutputKind | null) : string {
+ return unwrapString(UTSiOS.try(NativeCipherCore.rsaEncrypt(publicKey, plainText, resolveHexOutput(outputKind) ? 'hex' : 'base64'), '?'), 'RSA加密失败')
+}
+
+export function rsaDecryptText(privateKey : string, cipherText : string, outputKind : RsaOutputKind | null) : string {
+ return unwrapString(UTSiOS.try(NativeCipherCore.rsaDecrypt(privateKey, cipherText, resolveHexOutput(outputKind) ? 'hex' : 'base64'), '?'), 'RSA解密失败')
+}
+
+function compatBridge() : CompatBridge {
+ return createCompatBridge(
+ (codec : CryptoCodecKind, plainText : string) : string => encodeText(codec, plainText),
+ (codec : CryptoCodecKind, encodedText : string) : string => decodeText(codec, encodedText),
+ (kind : CryptoDigestKind, plainText : string) : string => digestText(kind, plainText),
+ (kind : CryptoMacKind, secretText : string, plainText : string) : string => signText(kind, secretText, plainText),
+ (secretText : string, plainText : string, options : CryptoTextCipherOptions | null) : string => aesEncryptText(secretText, plainText, options),
+ (secretText : string, cipherText : string, options : CryptoTextCipherOptions | null) : string => aesDecryptText(secretText, cipherText, options),
+ (secretBytes : Uint8Array, plainBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array => aesEncryptBytes(secretBytes, plainBytes, options),
+ (secretBytes : Uint8Array, cipherBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array => aesDecryptBytes(secretBytes, cipherBytes, options),
+ (secretText : string, plainText : string, options : CryptoDesOptions | null) : string => desEncryptText(secretText, plainText, options),
+ (secretText : string, cipherText : string, options : CryptoDesOptions | null) : string => desDecryptText(secretText, cipherText, options),
+ (keySize : number) : CryptoRsaPair => createRsaPair(keySize),
+ (publicKey : string, plainText : string, outputKind : RsaOutputKind | null) : string => rsaEncryptText(publicKey, plainText, outputKind),
+ (privateKey : string, cipherText : string, outputKind : RsaOutputKind | null) : string => rsaDecryptText(privateKey, cipherText, outputKind),
+ (secretText : string, plainText : string) : string => rc4EncryptText(secretText, plainText),
+ (secretText : string, cipherHexText : string) : string => rc4DecryptText(secretText, cipherHexText)
+ )
+}
+
+export function base64Encode(input : string) : string {
+ return base64EncodeCompat(compatBridge(), input)
+}
+
+export function base64Decode(input : string) : string {
+ return base64DecodeCompat(compatBridge(), input)
+}
+
+export function md5(input : string) : string {
+ return md5Compat(compatBridge(), input)
+}
+
+export function sha1(input : string) : string {
+ return sha1Compat(compatBridge(), input)
+}
+
+export function sha256(input : string) : string {
+ return sha256Compat(compatBridge(), input)
+}
+
+export function sha512(input : string) : string {
+ return sha512Compat(compatBridge(), input)
+}
+
+export function hmacSha1(key : string, data : string) : string {
+ return hmacSha1Compat(compatBridge(), key, data)
+}
+
+export function hmacSha256(key : string, data : string) : string {
+ return hmacSha256Compat(compatBridge(), key, data)
+}
+
+export function hmacSha512(key : string, data : string) : string {
+ return hmacSha512Compat(compatBridge(), key, data)
+}
+
+export function aesEncrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null, keySize : number | null = 16) : string {
+ return aesEncryptCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function aesDecrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null, keySize : number | null = 16) : string {
+ return aesDecryptCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function aesEncrypt2(key : Uint8Array, data : Uint8Array, mode : string = 'ECB', iv : Uint8Array | null = null, keySize : number | null = 16) : Uint8Array {
+ return aesEncryptBytesCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function aesDecrypt2(key : Uint8Array, data : Uint8Array, mode : string = 'ECB', iv : Uint8Array | null = null, keySize : number | null = 16) : Uint8Array {
+ return aesDecryptBytesCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function desEncrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null) : string {
+ return desEncryptCompat(compatBridge(), key, data, mode, iv)
+}
+
+export function desDecrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null) : string {
+ return desDecryptCompat(compatBridge(), key, data, mode, iv)
+}
+
+export function generateRSAKeyPair(keySize : number = 2048) : CryptoRsaPair {
+ return generateRsaKeyPairCompat(compatBridge(), keySize)
+}
+
+export function rsaEncrypt(publicKey : string, data : string) : string {
+ return rsaEncryptCompat(compatBridge(), publicKey, data)
+}
+
+export function rsaDecrypt(privateKey : string, data : string) : string {
+ return rsaDecryptCompat(compatBridge(), privateKey, data)
+}
+
+export function rc4Encrypt(key : string, data : string) : string {
+ return rc4EncryptCompat(compatBridge(), key, data)
+}
+
+export function rc4Decrypt(key : string, data : string) : string {
+ return rc4DecryptCompat(compatBridge(), key, data)
+}
+
+export function useCrypto() : CompatCrypto {
+ return createCompatCrypto(compatBridge())
+}
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/deps/package-lock.json b/uni_modules/laoqianjunzi-crypto/utssdk/deps/package-lock.json
new file mode 100644
index 0000000..cc788f8
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/deps/package-lock.json
@@ -0,0 +1,28 @@
+{
+ "name": "laoqianjunzi-crypto-runtime-deps",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "laoqianjunzi-crypto-runtime-deps",
+ "version": "1.0.0",
+ "dependencies": {
+ "crypto-es": "^2.1.0",
+ "jsencrypt": "^3.5.4"
+ }
+ },
+ "node_modules/crypto-es": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmmirror.com/crypto-es/-/crypto-es-2.1.0.tgz",
+ "integrity": "sha512-C5Dbuv4QTPGuloy5c5Vv/FZHtmK+lobLAypFfuRaBbwCsk3qbCWWESCH3MUcBsrgXloRNMrzwUAiPg4U6+IaKA==",
+ "license": "MIT"
+ },
+ "node_modules/jsencrypt": {
+ "version": "3.5.4",
+ "resolved": "https://registry.npmmirror.com/jsencrypt/-/jsencrypt-3.5.4.tgz",
+ "integrity": "sha512-kNjfYEMNASxrDGsmcSQh/rUTmcoRfSUkxnAz+MMywM8jtGu+fFEZ3nJjHM58zscVnwR0fYmG9sGkTDjqUdpiwA==",
+ "license": "MIT"
+ }
+ }
+}
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/deps/package.json b/uni_modules/laoqianjunzi-crypto/utssdk/deps/package.json
new file mode 100644
index 0000000..44e63ee
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/deps/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "laoqianjunzi-crypto-runtime-deps",
+ "private": true,
+ "version": "1.0.0",
+ "dependencies": {
+ "crypto-es": "^2.1.0",
+ "jsencrypt": "^3.5.4"
+ }
+}
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/index.uts b/uni_modules/laoqianjunzi-crypto/utssdk/index.uts
new file mode 100644
index 0000000..96b9734
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/index.uts
@@ -0,0 +1,22 @@
+export * from './interface.uts'
+export * from './unierror.uts'
+
+// #ifdef APP-ANDROID
+export * from './app-android/index.uts'
+// #endif
+
+// #ifdef APP-IOS
+export * from './app-ios/index.uts'
+// #endif
+
+// #ifdef APP-HARMONY
+export * from './app-harmony/index.uts'
+// #endif
+
+// #ifdef WEB
+export * from './web/index.uts'
+// #endif
+
+// #ifdef MP-WEIXIN
+export * from './mp-weixin/index.uts'
+// #endif
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/interface.uts b/uni_modules/laoqianjunzi-crypto/utssdk/interface.uts
new file mode 100644
index 0000000..b802f32
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/interface.uts
@@ -0,0 +1,58 @@
+export type CryptoDigestKind = "md5" | "sha1" | "sha256" | "sha512"
+
+export type CryptoMacKind = "sha1" | "sha256" | "sha512"
+
+export type CryptoCodecKind = "utf8" | "hex" | "base64" | "base64url" | "latin1" | "utf16"
+
+export type CryptoBlockMode = "ECB" | "CBC" | "CFB" | "CTR" | "CTRGladman" | "OFB"
+
+export type CryptoPaddingKind = "PKCS7" | "ANSI_X923" | "ISO_10126" | "ISO_97971" | "NONE" | "ZERO"
+
+export type RsaOutputKind = "base64" | "hex"
+
+export type CryptoTextCipherOptions = {
+ mode : CryptoBlockMode,
+ padding : CryptoPaddingKind,
+ ivText : string | null,
+ keyLength : number | null
+}
+
+export type CryptoByteCipherOptions = {
+ mode : CryptoBlockMode,
+ padding : CryptoPaddingKind,
+ ivBytes : Uint8Array | null,
+ keyLength : number | null
+}
+
+export type CryptoTripleDesOptions = {
+ mode : "ECB" | "CBC",
+ ivText : string | null
+}
+
+export type CryptoDesOptions = {
+ mode : CryptoBlockMode,
+ padding : CryptoPaddingKind,
+ ivText : string | null
+}
+
+export type CryptoRsaPair = {
+ publicKey : string,
+ privateKey : string
+}
+
+export type RSARANDOMKEY = CryptoRsaPair
+
+export type RSAKeyPair = CryptoRsaPair
+
+export type CryptoRuntimeSnapshot = {
+ platformName : string,
+ engineName : string,
+ supportsAdvancedModes : boolean,
+ usesNativeBridge : boolean
+}
+
+export type CryptoBridgeErrorCode = 7401 | 7402 | 7403 | 7404 | 7405 | 7406 | 7407 | 7408 | 7409 | 7410
+
+export interface CryptoBridgeFailure extends IUniError {
+ errCode : CryptoBridgeErrorCode
+}
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/mp-weixin/index.uts b/uni_modules/laoqianjunzi-crypto/utssdk/mp-weixin/index.uts
new file mode 100644
index 0000000..08abc37
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/mp-weixin/index.uts
@@ -0,0 +1,209 @@
+import type { CryptoByteCipherOptions, CryptoCodecKind, CryptoDesOptions, CryptoDigestKind, CryptoMacKind, CryptoRsaPair, CryptoRuntimeSnapshot, CryptoTextCipherOptions, CryptoTripleDesOptions, RsaOutputKind } from '../interface.uts'
+import { buildRuntimeSnapshot, createDefaultByteCipherOptions, createDefaultDesOptions, createDefaultTextCipherOptions, createDefaultTripleDesOptions, normalizeByteCipherOptions, normalizeDesOptions, normalizeTextCipherOptions, normalizeTripleDesOptions, resolveHexOutput } from '../shared/options.uts'
+import { aesDecryptBytesPortable, aesDecryptTextPortable, aesEncryptBytesPortable, aesEncryptTextPortable, createRsaPairPortable, decodeTextPortable, desDecryptTextPortable, desEncryptTextPortable, digestTextPortable, encodeTextPortable, rc4DecryptTextPortable, rc4EncryptTextPortable, rsaDecryptTextPortable, rsaEncryptTextPortable, signTextPortable, tripleDesDecryptTextPortable, tripleDesEncryptTextPortable } from '../shared/portable_crypto'
+import type { CompatBridge, CompatCrypto } from '../shared/compat.uts'
+import { aesDecryptBytesCompat, aesDecryptCompat, aesEncryptBytesCompat, aesEncryptCompat, base64DecodeCompat, base64EncodeCompat, createCompatBridge, createCompatCrypto, desDecryptCompat, desEncryptCompat, generateRsaKeyPairCompat, hmacSha1Compat, hmacSha256Compat, hmacSha512Compat, md5Compat, rc4DecryptCompat, rc4EncryptCompat, rsaDecryptCompat, rsaEncryptCompat, sha1Compat, sha256Compat, sha512Compat } from '../shared/compat.uts'
+
+export function defaultTextCipherOptions() : CryptoTextCipherOptions {
+ return createDefaultTextCipherOptions()
+}
+
+export function defaultByteCipherOptions() : CryptoByteCipherOptions {
+ return createDefaultByteCipherOptions()
+}
+
+export function defaultTripleDesOptions() : CryptoTripleDesOptions {
+ return createDefaultTripleDesOptions()
+}
+
+export function defaultDesOptions() : CryptoDesOptions {
+ return createDefaultDesOptions()
+}
+
+export function describeCryptoRuntime() : CryptoRuntimeSnapshot {
+ return buildRuntimeSnapshot('mp-weixin', 'crypto-es', true, false)
+}
+
+export function encodeText(codec : CryptoCodecKind, plainText : string) : string {
+ return encodeTextPortable(codec, plainText)
+}
+
+export function decodeText(codec : CryptoCodecKind, encodedText : string) : string {
+ return decodeTextPortable(codec, encodedText)
+}
+
+export function digestText(kind : CryptoDigestKind, plainText : string) : string {
+ return digestTextPortable(kind, plainText)
+}
+
+export function signText(kind : CryptoMacKind, secretText : string, plainText : string) : string {
+ return signTextPortable(kind, secretText, plainText)
+}
+
+export function aesEncryptText(secretText : string, plainText : string, options : CryptoTextCipherOptions | null) : string {
+ const actual = normalizeTextCipherOptions(options)
+ return aesEncryptTextPortable(secretText, plainText, actual.mode, actual.padding, actual.ivText, actual.keyLength)
+}
+
+export function aesDecryptText(secretText : string, cipherText : string, options : CryptoTextCipherOptions | null) : string {
+ const actual = normalizeTextCipherOptions(options)
+ return aesDecryptTextPortable(secretText, cipherText, actual.mode, actual.padding, actual.ivText, actual.keyLength)
+}
+
+export function aesEncryptBytes(secretBytes : Uint8Array, plainBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array {
+ const actual = normalizeByteCipherOptions(options)
+ return aesEncryptBytesPortable(secretBytes, plainBytes, actual.mode, actual.padding, actual.ivBytes, actual.keyLength)
+}
+
+export function aesDecryptBytes(secretBytes : Uint8Array, cipherBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array {
+ const actual = normalizeByteCipherOptions(options)
+ return aesDecryptBytesPortable(secretBytes, cipherBytes, actual.mode, actual.padding, actual.ivBytes, actual.keyLength)
+}
+
+export function tripleDesEncryptText(secretText : string, plainText : string, options : CryptoTripleDesOptions | null) : string {
+ const actual = normalizeTripleDesOptions(options)
+ return tripleDesEncryptTextPortable(secretText, plainText, actual.mode, actual.ivText)
+}
+
+export function tripleDesDecryptText(secretText : string, cipherText : string, options : CryptoTripleDesOptions | null) : string {
+ const actual = normalizeTripleDesOptions(options)
+ return tripleDesDecryptTextPortable(secretText, cipherText, actual.mode, actual.ivText)
+}
+
+export function desEncryptText(secretText : string, plainText : string, options : CryptoDesOptions | null) : string {
+ const actual = normalizeDesOptions(options)
+ return desEncryptTextPortable(secretText, plainText, actual.mode, actual.padding, actual.ivText)
+}
+
+export function desDecryptText(secretText : string, cipherText : string, options : CryptoDesOptions | null) : string {
+ const actual = normalizeDesOptions(options)
+ return desDecryptTextPortable(secretText, cipherText, actual.mode, actual.padding, actual.ivText)
+}
+
+export function rc4EncryptText(secretText : string, plainText : string) : string {
+ return rc4EncryptTextPortable(secretText, plainText)
+}
+
+export function rc4DecryptText(secretText : string, cipherHexText : string) : string {
+ return rc4DecryptTextPortable(secretText, cipherHexText)
+}
+
+export function createRsaPair(keySize : number) : CryptoRsaPair {
+ const bundle = createRsaPairPortable(keySize)
+ return {
+ publicKey: bundle.publicKey,
+ privateKey: bundle.privateKey
+ } as CryptoRsaPair
+}
+
+export function rsaEncryptText(publicKey : string, plainText : string, outputKind : RsaOutputKind | null) : string {
+ return rsaEncryptTextPortable(publicKey, plainText, resolveHexOutput(outputKind) ? 'hex' : 'base64')
+}
+
+export function rsaDecryptText(privateKey : string, cipherText : string, outputKind : RsaOutputKind | null) : string {
+ return rsaDecryptTextPortable(privateKey, cipherText, resolveHexOutput(outputKind) ? 'hex' : 'base64')
+}
+
+function compatBridge() : CompatBridge {
+ return createCompatBridge(
+ (codec : CryptoCodecKind, plainText : string) : string => encodeText(codec, plainText),
+ (codec : CryptoCodecKind, encodedText : string) : string => decodeText(codec, encodedText),
+ (kind : CryptoDigestKind, plainText : string) : string => digestText(kind, plainText),
+ (kind : CryptoMacKind, secretText : string, plainText : string) : string => signText(kind, secretText, plainText),
+ (secretText : string, plainText : string, options : CryptoTextCipherOptions | null) : string => aesEncryptText(secretText, plainText, options),
+ (secretText : string, cipherText : string, options : CryptoTextCipherOptions | null) : string => aesDecryptText(secretText, cipherText, options),
+ (secretBytes : Uint8Array, plainBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array => aesEncryptBytes(secretBytes, plainBytes, options),
+ (secretBytes : Uint8Array, cipherBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array => aesDecryptBytes(secretBytes, cipherBytes, options),
+ (secretText : string, plainText : string, options : CryptoDesOptions | null) : string => desEncryptText(secretText, plainText, options),
+ (secretText : string, cipherText : string, options : CryptoDesOptions | null) : string => desDecryptText(secretText, cipherText, options),
+ (keySize : number) : CryptoRsaPair => createRsaPair(keySize),
+ (publicKey : string, plainText : string, outputKind : RsaOutputKind | null) : string => rsaEncryptText(publicKey, plainText, outputKind),
+ (privateKey : string, cipherText : string, outputKind : RsaOutputKind | null) : string => rsaDecryptText(privateKey, cipherText, outputKind),
+ (secretText : string, plainText : string) : string => rc4EncryptText(secretText, plainText),
+ (secretText : string, cipherHexText : string) : string => rc4DecryptText(secretText, cipherHexText)
+ )
+}
+
+export function base64Encode(input : string) : string {
+ return base64EncodeCompat(compatBridge(), input)
+}
+
+export function base64Decode(input : string) : string {
+ return base64DecodeCompat(compatBridge(), input)
+}
+
+export function md5(input : string) : string {
+ return md5Compat(compatBridge(), input)
+}
+
+export function sha1(input : string) : string {
+ return sha1Compat(compatBridge(), input)
+}
+
+export function sha256(input : string) : string {
+ return sha256Compat(compatBridge(), input)
+}
+
+export function sha512(input : string) : string {
+ return sha512Compat(compatBridge(), input)
+}
+
+export function hmacSha1(key : string, data : string) : string {
+ return hmacSha1Compat(compatBridge(), key, data)
+}
+
+export function hmacSha256(key : string, data : string) : string {
+ return hmacSha256Compat(compatBridge(), key, data)
+}
+
+export function hmacSha512(key : string, data : string) : string {
+ return hmacSha512Compat(compatBridge(), key, data)
+}
+
+export function aesEncrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null, keySize : number | null = 16) : string {
+ return aesEncryptCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function aesDecrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null, keySize : number | null = 16) : string {
+ return aesDecryptCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function aesEncrypt2(key : Uint8Array, data : Uint8Array, mode : string = 'ECB', iv : Uint8Array | null = null, keySize : number | null = 16) : Uint8Array {
+ return aesEncryptBytesCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function aesDecrypt2(key : Uint8Array, data : Uint8Array, mode : string = 'ECB', iv : Uint8Array | null = null, keySize : number | null = 16) : Uint8Array {
+ return aesDecryptBytesCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function desEncrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null) : string {
+ return desEncryptCompat(compatBridge(), key, data, mode, iv)
+}
+
+export function desDecrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null) : string {
+ return desDecryptCompat(compatBridge(), key, data, mode, iv)
+}
+
+export function generateRSAKeyPair(keySize : number = 2048) : CryptoRsaPair {
+ return generateRsaKeyPairCompat(compatBridge(), keySize)
+}
+
+export function rsaEncrypt(publicKey : string, data : string) : string {
+ return rsaEncryptCompat(compatBridge(), publicKey, data)
+}
+
+export function rsaDecrypt(privateKey : string, data : string) : string {
+ return rsaDecryptCompat(compatBridge(), privateKey, data)
+}
+
+export function rc4Encrypt(key : string, data : string) : string {
+ return rc4EncryptCompat(compatBridge(), key, data)
+}
+
+export function rc4Decrypt(key : string, data : string) : string {
+ return rc4DecryptCompat(compatBridge(), key, data)
+}
+
+export function useCrypto() : CompatCrypto {
+ return createCompatCrypto(compatBridge())
+}
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/shared/compat.uts b/uni_modules/laoqianjunzi-crypto/utssdk/shared/compat.uts
new file mode 100644
index 0000000..fdb4068
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/shared/compat.uts
@@ -0,0 +1,771 @@
+import type { CryptoBlockMode, CryptoByteCipherOptions, CryptoCodecKind, CryptoDesOptions, CryptoDigestKind, CryptoMacKind, CryptoPaddingKind, CryptoRsaPair, CryptoTextCipherOptions, RsaOutputKind } from '../interface.uts'
+
+const LIME_MODE_CBC = 1
+const LIME_MODE_CFB = 2
+const LIME_MODE_CTR = 3
+const LIME_MODE_CTR_GLADMAN = 4
+const LIME_MODE_ECB = 5
+const LIME_MODE_OFB = 6
+
+const LIME_PAD_PKCS7 = 1
+const LIME_PAD_ANSI_X923 = 2
+const LIME_PAD_ISO_10126 = 3
+const LIME_PAD_ISO_97971 = 4
+const LIME_PAD_NONE = 5
+const LIME_PAD_ZERO = 6
+
+const BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+
+export type CompatBridge = {
+ encodeText : (codec : CryptoCodecKind, plainText : string) => string,
+ decodeText : (codec : CryptoCodecKind, encodedText : string) => string,
+ digestText : (kind : CryptoDigestKind, plainText : string) => string,
+ signText : (kind : CryptoMacKind, secretText : string, plainText : string) => string,
+ aesEncryptText : (secretText : string, plainText : string, options : CryptoTextCipherOptions | null) => string,
+ aesDecryptText : (secretText : string, cipherText : string, options : CryptoTextCipherOptions | null) => string,
+ aesEncryptBytes : (secretBytes : Uint8Array, plainBytes : Uint8Array, options : CryptoByteCipherOptions | null) => Uint8Array,
+ aesDecryptBytes : (secretBytes : Uint8Array, cipherBytes : Uint8Array, options : CryptoByteCipherOptions | null) => Uint8Array,
+ desEncryptText : (secretText : string, plainText : string, options : CryptoDesOptions | null) => string,
+ desDecryptText : (secretText : string, cipherText : string, options : CryptoDesOptions | null) => string,
+ createRsaPair : (keySize : number) => CryptoRsaPair,
+ rsaEncryptText : (publicKey : string, plainText : string, outputKind : RsaOutputKind | null) => string,
+ rsaDecryptText : (privateKey : string, cipherText : string, outputKind : RsaOutputKind | null) => string,
+ rc4EncryptText : (secretText : string, plainText : string) => string,
+ rc4DecryptText : (secretText : string, cipherHexText : string) => string
+}
+
+export type CompatEncSet = {
+ Utf8 : CompatEncoder,
+ Hex : CompatEncoder,
+ Base64 : CompatEncoder,
+ Latin1 : CompatEncoder,
+ Utf16 : CompatEncoder,
+ Base64url : CompatEncoder
+}
+
+export type CompatModeSet = {
+ CBC : number,
+ CFB : number,
+ CTR : number,
+ CTRGladman : number,
+ ECB : number,
+ OFB : number
+}
+
+export type CompatPadSet = {
+ Pkcs7 : number,
+ AnsiX923 : number,
+ Iso10126 : number,
+ Iso97971 : number,
+ NoPadding : number,
+ ZeroPadding : number
+}
+
+export function createCompatBridge(
+ encodeText : (codec : CryptoCodecKind, plainText : string) => string,
+ decodeText : (codec : CryptoCodecKind, encodedText : string) => string,
+ digestText : (kind : CryptoDigestKind, plainText : string) => string,
+ signText : (kind : CryptoMacKind, secretText : string, plainText : string) => string,
+ aesEncryptText : (secretText : string, plainText : string, options : CryptoTextCipherOptions | null) => string,
+ aesDecryptText : (secretText : string, cipherText : string, options : CryptoTextCipherOptions | null) => string,
+ aesEncryptBytes : (secretBytes : Uint8Array, plainBytes : Uint8Array, options : CryptoByteCipherOptions | null) => Uint8Array,
+ aesDecryptBytes : (secretBytes : Uint8Array, cipherBytes : Uint8Array, options : CryptoByteCipherOptions | null) => Uint8Array,
+ desEncryptText : (secretText : string, plainText : string, options : CryptoDesOptions | null) => string,
+ desDecryptText : (secretText : string, cipherText : string, options : CryptoDesOptions | null) => string,
+ createRsaPair : (keySize : number) => CryptoRsaPair,
+ rsaEncryptText : (publicKey : string, plainText : string, outputKind : RsaOutputKind | null) => string,
+ rsaDecryptText : (privateKey : string, cipherText : string, outputKind : RsaOutputKind | null) => string,
+ rc4EncryptText : (secretText : string, plainText : string) => string,
+ rc4DecryptText : (secretText : string, cipherHexText : string) => string
+) : CompatBridge {
+ return {
+ encodeText,
+ decodeText,
+ digestText,
+ signText,
+ aesEncryptText,
+ aesDecryptText,
+ aesEncryptBytes,
+ aesDecryptBytes,
+ desEncryptText,
+ desDecryptText,
+ createRsaPair,
+ rsaEncryptText,
+ rsaDecryptText,
+ rc4EncryptText,
+ rc4DecryptText
+ } as CompatBridge
+}
+
+function cloneBytes(input : Uint8Array) : Uint8Array {
+ const output = new Uint8Array(input.length)
+ let index = 0
+ while (index < input.length) {
+ output[index] = input[index]
+ index += 1
+ }
+ return output
+}
+
+function bytesToWords(input : Uint8Array) : number[] {
+ const output = [] as number[]
+ let index = 0
+ while (index < input.length) {
+ let word = 0
+ let offset = 0
+ while (offset < 4 && index + offset < input.length) {
+ word |= input[index + offset] << (24 - offset * 8)
+ offset += 1
+ }
+ output.push(word)
+ index += 4
+ }
+ return output
+}
+
+function byteToHex(value : number) : string {
+ let part = value.toString(16)
+ if (part.length < 2) {
+ part = '0' + part
+ }
+ return part
+}
+
+function bytesToHex(input : Uint8Array) : string {
+ let output = ''
+ let index = 0
+ while (index < input.length) {
+ output += byteToHex(input[index] & 0xff)
+ index += 1
+ }
+ return output
+}
+
+function hexValueOfChar(ch : string) : number {
+ const lower = ch.toLowerCase()
+ const code = lower.charCodeAt(0)
+ const actualCode = code == null ? 0 : code
+ if (lower >= '0' && lower <= '9') {
+ return actualCode - 48
+ }
+ return actualCode - 87
+}
+
+function hexToBytes(hexText : string) : Uint8Array {
+ const actualLength = hexText.length % 2 == 0 ? hexText.length : hexText.length - 1
+ const output = new Uint8Array(actualLength / 2)
+ let index = 0
+ while (index < actualLength) {
+ const high = hexValueOfChar(hexText.substring(index, index + 1))
+ const low = hexValueOfChar(hexText.substring(index + 1, index + 2))
+ const targetIndex = index / 2
+ output[targetIndex] = ((high << 4) | low) & 0xff
+ index += 2
+ }
+ return output
+}
+
+function base64IndexOf(ch : string) : number {
+ return BASE64_ALPHABET.indexOf(ch)
+}
+
+function toBase64UrlText(input : string) : string {
+ let output = ''
+ let index = 0
+ while (index < input.length) {
+ const ch = input.substring(index, index + 1)
+ if (ch == '+') {
+ output += '-'
+ } else if (ch == '/') {
+ output += '_'
+ } else if (ch != '=') {
+ output += ch
+ }
+ index += 1
+ }
+ return output
+}
+
+function fromBase64UrlText(input : string) : string {
+ let output = ''
+ let index = 0
+ while (index < input.length) {
+ const ch = input.substring(index, index + 1)
+ if (ch == '-') {
+ output += '+'
+ } else if (ch == '_') {
+ output += '/'
+ } else {
+ output += ch
+ }
+ index += 1
+ }
+ while (output.length % 4 != 0) {
+ output += '='
+ }
+ return output
+}
+
+function bytesToBase64(input : Uint8Array, urlSafe : boolean) : string {
+ let output = ''
+ let index = 0
+ while (index < input.length) {
+ const first = input[index] & 0xff
+ const hasSecond = index + 1 < input.length
+ const hasThird = index + 2 < input.length
+ const second = hasSecond ? input[index + 1] & 0xff : 0
+ const third = hasThird ? input[index + 2] & 0xff : 0
+ const block = (first << 16) | (second << 8) | third
+ output += BASE64_ALPHABET.substring((block >>> 18) & 0x3f, ((block >>> 18) & 0x3f) + 1)
+ output += BASE64_ALPHABET.substring((block >>> 12) & 0x3f, ((block >>> 12) & 0x3f) + 1)
+ if (hasSecond) {
+ output += BASE64_ALPHABET.substring((block >>> 6) & 0x3f, ((block >>> 6) & 0x3f) + 1)
+ } else {
+ output += '='
+ }
+ if (hasThird) {
+ output += BASE64_ALPHABET.substring(block & 0x3f, (block & 0x3f) + 1)
+ } else {
+ output += '='
+ }
+ index += 3
+ }
+ if (urlSafe) {
+ return toBase64UrlText(output)
+ }
+ return output
+}
+
+function normalizeBase64Text(input : string) : string {
+ return fromBase64UrlText(input)
+}
+
+function base64ToBytes(input : string, urlSafe : boolean) : Uint8Array {
+ const source = urlSafe ? normalizeBase64Text(input) : input
+ const output = [] as number[]
+ let index = 0
+ while (index < source.length) {
+ const char1 = source.substring(index, index + 1)
+ const char2 = source.substring(index + 1, index + 2)
+ const char3 = source.substring(index + 2, index + 3)
+ const char4 = source.substring(index + 3, index + 4)
+ const value1 = base64IndexOf(char1)
+ const value2 = base64IndexOf(char2)
+ const value3 = char3 == '=' ? -1 : base64IndexOf(char3)
+ const value4 = char4 == '=' ? -1 : base64IndexOf(char4)
+ const block = (value1 << 18) | (value2 << 12) | ((value3 < 0 ? 0 : value3) << 6) | (value4 < 0 ? 0 : value4)
+ output.push((block >>> 16) & 0xff)
+ if (value3 >= 0) {
+ output.push((block >>> 8) & 0xff)
+ }
+ if (value4 >= 0) {
+ output.push(block & 0xff)
+ }
+ index += 4
+ }
+ return new Uint8Array(output)
+}
+
+function latin1ToBytes(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 bytesToLatin1(input : Uint8Array) : string {
+ let output = ''
+ let index = 0
+ while (index < input.length) {
+ output += String.fromCharCode(input[index] & 0xff)
+ index += 1
+ }
+ return output
+}
+
+function utf16ToBytes(input : string) : Uint8Array {
+ const output = new Uint8Array(input.length * 2)
+ let index = 0
+ while (index < input.length) {
+ const code = input.charCodeAt(index)
+ const actualCode = code == null ? 0 : code
+ output[index * 2] = (actualCode >>> 8) & 0xff
+ output[index * 2 + 1] = actualCode & 0xff
+ index += 1
+ }
+ return output
+}
+
+function bytesToUtf16(input : Uint8Array) : string {
+ let output = ''
+ let index = 0
+ while (index + 1 < input.length) {
+ const code = ((input[index] & 0xff) << 8) | (input[index + 1] & 0xff)
+ output += String.fromCharCode(code)
+ index += 2
+ }
+ return output
+}
+
+function textToUtf8Bytes(input : string, bridge : CompatBridge) : Uint8Array {
+ return hexToBytes(bridge.encodeText('hex', input))
+}
+
+function utf8BytesToText(input : Uint8Array, bridge : CompatBridge) : string {
+ return bridge.decodeText('hex', bytesToHex(input))
+}
+
+function parseCodecBytes(kind : CryptoCodecKind, input : string, bridge : CompatBridge) : Uint8Array {
+ if (kind == 'utf8') {
+ return textToUtf8Bytes(input, bridge)
+ }
+ if (kind == 'hex') {
+ return hexToBytes(input)
+ }
+ if (kind == 'base64') {
+ return base64ToBytes(input, false)
+ }
+ if (kind == 'base64url') {
+ return base64ToBytes(input, true)
+ }
+ if (kind == 'latin1') {
+ return latin1ToBytes(input)
+ }
+ return utf16ToBytes(input)
+}
+
+function stringifyCodecBytes(kind : CryptoCodecKind, input : Uint8Array, bridge : CompatBridge) : string {
+ if (kind == 'utf8') {
+ return utf8BytesToText(input, bridge)
+ }
+ if (kind == 'hex') {
+ return bytesToHex(input)
+ }
+ if (kind == 'base64') {
+ return bytesToBase64(input, false)
+ }
+ if (kind == 'base64url') {
+ return bytesToBase64(input, true)
+ }
+ if (kind == 'latin1') {
+ return bytesToLatin1(input)
+ }
+ return bytesToUtf16(input)
+}
+
+function normalizeKeyLength(keySize : number | null) : number | null {
+ if (keySize == null) {
+ return null
+ }
+ if (keySize == 128) {
+ return 16
+ }
+ if (keySize == 192) {
+ return 24
+ }
+ if (keySize == 256) {
+ return 32
+ }
+ if (keySize == 16 || keySize == 24 || keySize == 32) {
+ return keySize
+ }
+ return 16
+}
+
+function toLimeMode(mode : number | null) : CryptoBlockMode {
+ if (mode == LIME_MODE_CFB) {
+ return 'CFB'
+ }
+ if (mode == LIME_MODE_CTR) {
+ return 'CTR'
+ }
+ if (mode == LIME_MODE_CTR_GLADMAN) {
+ return 'CTRGladman'
+ }
+ if (mode == LIME_MODE_ECB) {
+ return 'ECB'
+ }
+ if (mode == LIME_MODE_OFB) {
+ return 'OFB'
+ }
+ return 'CBC'
+}
+
+function toLimePadding(padding : number | null) : CryptoPaddingKind {
+ if (padding == LIME_PAD_ANSI_X923) {
+ return 'ANSI_X923'
+ }
+ if (padding == LIME_PAD_ISO_10126) {
+ return 'ISO_10126'
+ }
+ if (padding == LIME_PAD_ISO_97971) {
+ return 'ISO_97971'
+ }
+ if (padding == LIME_PAD_NONE) {
+ return 'NONE'
+ }
+ if (padding == LIME_PAD_ZERO) {
+ return 'ZERO'
+ }
+ return 'PKCS7'
+}
+
+function readConfigNumber(cfg : UTSJSONObject | null, key : string) : number | null {
+ if (cfg == null) {
+ return null
+ }
+ return cfg.getNumber(key)
+}
+
+function readConfigWordArray(cfg : UTSJSONObject | null, key : string) : CompatWordArray | null {
+ if (cfg == null) {
+ return null
+ }
+ const raw = cfg.get(key) as object | null
+ if (raw != null && raw instanceof CompatWordArray) {
+ return raw as CompatWordArray
+ }
+ return null
+}
+
+function buildLimeTextOptions(cfg : UTSJSONObject | null, bridge : CompatBridge) : CryptoTextCipherOptions {
+ const iv = readConfigWordArray(cfg, 'iv')
+ return {
+ mode: toLimeMode(readConfigNumber(cfg, 'mode')),
+ padding: toLimePadding(readConfigNumber(cfg, 'padding')),
+ ivText: iv == null ? null : utf8BytesToText(iv.toUint8Array(), bridge),
+ keyLength: null
+ } as CryptoTextCipherOptions
+}
+
+function buildLimeDesOptions(cfg : UTSJSONObject | null, bridge : CompatBridge) : CryptoDesOptions {
+ const iv = readConfigWordArray(cfg, 'iv')
+ return {
+ mode: toLimeMode(readConfigNumber(cfg, 'mode')),
+ padding: toLimePadding(readConfigNumber(cfg, 'padding')),
+ ivText: iv == null ? null : utf8BytesToText(iv.toUint8Array(), bridge)
+ } as CryptoDesOptions
+}
+
+function buildXTextOptions(mode : string, iv : string | null, keySize : number | null) : CryptoTextCipherOptions {
+ return {
+ mode: mode == 'CBC' ? 'CBC' : 'ECB',
+ padding: 'PKCS7',
+ ivText: iv,
+ keyLength: normalizeKeyLength(keySize)
+ } as CryptoTextCipherOptions
+}
+
+function buildXByteOptions(mode : string, iv : Uint8Array | null, keySize : number | null) : CryptoByteCipherOptions {
+ return {
+ mode: mode == 'CBC' ? 'CBC' : 'ECB',
+ padding: 'PKCS7',
+ ivBytes: iv,
+ keyLength: normalizeKeyLength(keySize)
+ } as CryptoByteCipherOptions
+}
+
+function buildXDesOptions(mode : string, iv : string | null) : CryptoDesOptions {
+ return {
+ mode: mode == 'CBC' ? 'CBC' : 'ECB',
+ padding: 'PKCS7',
+ ivText: iv
+ } as CryptoDesOptions
+}
+
+function keyToText(key : string | CompatWordArray, bridge : CompatBridge) : string {
+ if (typeof key == 'string') {
+ return key
+ }
+ if (key instanceof CompatWordArray) {
+ return utf8BytesToText(key.toUint8Array(), bridge)
+ }
+ return ''
+}
+
+export class CompatWordArray {
+ words : number[]
+ sigBytes : number
+ private rawBytes : Uint8Array
+
+ constructor(rawBytes : Uint8Array) {
+ this.rawBytes = cloneBytes(rawBytes)
+ this.words = bytesToWords(this.rawBytes)
+ this.sigBytes = this.rawBytes.length
+ }
+
+ toString(encoder : CompatEncoder | null = null) : string {
+ if (encoder == null) {
+ return bytesToHex(this.rawBytes)
+ }
+ return encoder.stringify(this)
+ }
+
+ toUint8Array() : Uint8Array {
+ return cloneBytes(this.rawBytes)
+ }
+}
+
+export class CompatCipherResult {
+ ciphertext : CompatWordArray
+ private serialized : string
+
+ constructor(serialized : string, cipherBytes : Uint8Array) {
+ this.serialized = serialized
+ this.ciphertext = new CompatWordArray(cipherBytes)
+ }
+
+ toString(encoder : CompatEncoder | null = null) : string {
+ if (encoder == null) {
+ return this.serialized
+ }
+ return this.ciphertext.toString(encoder)
+ }
+}
+
+export class CompatEncoder {
+ private kind : CryptoCodecKind
+ private bridge : CompatBridge
+
+ constructor(kind : CryptoCodecKind, bridge : CompatBridge) {
+ this.kind = kind
+ this.bridge = bridge
+ }
+
+ parse(input : string) : CompatWordArray {
+ return new CompatWordArray(parseCodecBytes(this.kind, input, this.bridge))
+ }
+
+ stringify(wordArray : CompatWordArray) : string {
+ return stringifyCodecBytes(this.kind, wordArray.toUint8Array(), this.bridge)
+ }
+}
+
+export class CompatRsaAdapter {
+ private bridge : CompatBridge
+ private publicKey : string = ''
+ private privateKey : string = ''
+
+ constructor(bridge : CompatBridge) {
+ this.bridge = bridge
+ }
+
+ generateKeyPair() : CryptoRsaPair {
+ const pair = this.bridge.createRsaPair(2048)
+ this.publicKey = pair.publicKey
+ this.privateKey = pair.privateKey
+ return pair
+ }
+
+ setPublicKey(publicKey : string) : void {
+ this.publicKey = publicKey
+ }
+
+ setPrivateKey(privateKey : string) : void {
+ this.privateKey = privateKey
+ }
+
+ encrypt(data : string) : string {
+ return this.bridge.rsaEncryptText(this.publicKey, data, 'base64')
+ }
+
+ decrypt(encryptedData : string) : string {
+ return this.bridge.rsaDecryptText(this.privateKey, encryptedData, 'base64')
+ }
+
+ getPublicKey() : string {
+ return this.publicKey
+ }
+
+ getPrivateKey() : string {
+ return this.privateKey
+ }
+}
+
+export class CompatSymmetricAdapter {
+ private bridge : CompatBridge
+ private algorithm : string
+
+ constructor(bridge : CompatBridge, algorithm : string) {
+ this.bridge = bridge
+ this.algorithm = algorithm
+ }
+
+ encrypt(message : string, key : string | CompatWordArray, cfg : UTSJSONObject | null = null) : CompatCipherResult {
+ const keyText = keyToText(key, this.bridge)
+ if (this.algorithm == 'DES') {
+ const cipherText = this.bridge.desEncryptText(keyText, message, buildLimeDesOptions(cfg, this.bridge))
+ return new CompatCipherResult(cipherText, parseCodecBytes('base64', cipherText, this.bridge))
+ }
+ const cipherText = this.bridge.aesEncryptText(keyText, message, buildLimeTextOptions(cfg, this.bridge))
+ return new CompatCipherResult(cipherText, parseCodecBytes('base64', cipherText, this.bridge))
+ }
+
+ decrypt(ciphertext : string, password : string | CompatWordArray, cfg : UTSJSONObject | null = null) : CompatWordArray {
+ const keyText = keyToText(password, this.bridge)
+ if (this.algorithm == 'DES') {
+ return new CompatWordArray(textToUtf8Bytes(this.bridge.desDecryptText(keyText, ciphertext, buildLimeDesOptions(cfg, this.bridge)), this.bridge))
+ }
+ return new CompatWordArray(textToUtf8Bytes(this.bridge.aesDecryptText(keyText, ciphertext, buildLimeTextOptions(cfg, this.bridge)), this.bridge))
+ }
+}
+
+export class CompatCrypto {
+ enc : CompatEncSet
+ mode : CompatModeSet
+ pad : CompatPadSet
+ AES : CompatSymmetricAdapter
+ DES : CompatSymmetricAdapter
+ RSA : CompatRsaAdapter
+ private bridge : CompatBridge
+
+ constructor(bridge : CompatBridge) {
+ this.bridge = bridge
+ this.enc = {
+ Utf8: new CompatEncoder('utf8', bridge),
+ Hex: new CompatEncoder('hex', bridge),
+ Base64: new CompatEncoder('base64', bridge),
+ Latin1: new CompatEncoder('latin1', bridge),
+ Utf16: new CompatEncoder('utf16', bridge),
+ Base64url: new CompatEncoder('base64url', bridge)
+ } as CompatEncSet
+ this.mode = {
+ CBC: LIME_MODE_CBC,
+ CFB: LIME_MODE_CFB,
+ CTR: LIME_MODE_CTR,
+ CTRGladman: LIME_MODE_CTR_GLADMAN,
+ ECB: LIME_MODE_ECB,
+ OFB: LIME_MODE_OFB
+ } as CompatModeSet
+ this.pad = {
+ Pkcs7: LIME_PAD_PKCS7,
+ AnsiX923: LIME_PAD_ANSI_X923,
+ Iso10126: LIME_PAD_ISO_10126,
+ Iso97971: LIME_PAD_ISO_97971,
+ NoPadding: LIME_PAD_NONE,
+ ZeroPadding: LIME_PAD_ZERO
+ } as CompatPadSet
+ this.AES = new CompatSymmetricAdapter(bridge, 'AES')
+ this.DES = new CompatSymmetricAdapter(bridge, 'DES')
+ this.RSA = new CompatRsaAdapter(bridge)
+ }
+
+ MD5(message : string) : CompatWordArray {
+ return new CompatWordArray(hexToBytes(this.bridge.digestText('md5', message)))
+ }
+
+ SHA1(message : string) : CompatWordArray {
+ return new CompatWordArray(hexToBytes(this.bridge.digestText('sha1', message)))
+ }
+
+ SHA256(message : string) : CompatWordArray {
+ return new CompatWordArray(hexToBytes(this.bridge.digestText('sha256', message)))
+ }
+
+ SHA512(message : string) : CompatWordArray {
+ return new CompatWordArray(hexToBytes(this.bridge.digestText('sha512', message)))
+ }
+
+ HmacSHA256(message : string, secretKey : string | CompatWordArray) : CompatWordArray {
+ return new CompatWordArray(hexToBytes(this.bridge.signText('sha256', typeof secretKey == 'string' ? secretKey : keyToText(secretKey, this.bridge), message)))
+ }
+
+ HmacSHA1(message : string, secretKey : string | CompatWordArray) : CompatWordArray {
+ return new CompatWordArray(hexToBytes(this.bridge.signText('sha1', typeof secretKey == 'string' ? secretKey : keyToText(secretKey, this.bridge), message)))
+ }
+
+ HmacSHA512(message : string, secretKey : string | CompatWordArray) : CompatWordArray {
+ return new CompatWordArray(hexToBytes(this.bridge.signText('sha512', typeof secretKey == 'string' ? secretKey : keyToText(secretKey, this.bridge), message)))
+ }
+
+ onError(_callback : (err : IUniError) => void) : void {
+ }
+}
+
+export function createCompatCrypto(bridge : CompatBridge) : CompatCrypto {
+ return new CompatCrypto(bridge)
+}
+
+export function base64EncodeCompat(bridge : CompatBridge, input : string) : string {
+ return bridge.encodeText('base64', input)
+}
+
+export function base64DecodeCompat(bridge : CompatBridge, input : string) : string {
+ return bridge.decodeText('base64', input)
+}
+
+export function md5Compat(bridge : CompatBridge, input : string) : string {
+ return bridge.digestText('md5', input)
+}
+
+export function sha1Compat(bridge : CompatBridge, input : string) : string {
+ return bridge.digestText('sha1', input)
+}
+
+export function sha256Compat(bridge : CompatBridge, input : string) : string {
+ return bridge.digestText('sha256', input)
+}
+
+export function sha512Compat(bridge : CompatBridge, input : string) : string {
+ return bridge.digestText('sha512', input)
+}
+
+export function hmacSha1Compat(bridge : CompatBridge, key : string, data : string) : string {
+ return bridge.signText('sha1', key, data)
+}
+
+export function hmacSha256Compat(bridge : CompatBridge, key : string, data : string) : string {
+ return bridge.signText('sha256', key, data)
+}
+
+export function hmacSha512Compat(bridge : CompatBridge, key : string, data : string) : string {
+ return bridge.signText('sha512', key, data)
+}
+
+export function aesEncryptCompat(bridge : CompatBridge, key : string, data : string, mode : string = 'ECB', iv : string | null = null, keySize : number | null = 16) : string {
+ return bridge.aesEncryptText(key, data, buildXTextOptions(mode, iv, keySize))
+}
+
+export function aesDecryptCompat(bridge : CompatBridge, key : string, data : string, mode : string = 'ECB', iv : string | null = null, keySize : number | null = 16) : string {
+ return bridge.aesDecryptText(key, data, buildXTextOptions(mode, iv, keySize))
+}
+
+export function aesEncryptBytesCompat(bridge : CompatBridge, key : Uint8Array, data : Uint8Array, mode : string = 'ECB', iv : Uint8Array | null = null, keySize : number | null = 16) : Uint8Array {
+ return bridge.aesEncryptBytes(key, data, buildXByteOptions(mode, iv, keySize))
+}
+
+export function aesDecryptBytesCompat(bridge : CompatBridge, key : Uint8Array, data : Uint8Array, mode : string = 'ECB', iv : Uint8Array | null = null, keySize : number | null = 16) : Uint8Array {
+ return bridge.aesDecryptBytes(key, data, buildXByteOptions(mode, iv, keySize))
+}
+
+export function desEncryptCompat(bridge : CompatBridge, key : string, data : string, mode : string = 'ECB', iv : string | null = null) : string {
+ return bridge.desEncryptText(key, data, buildXDesOptions(mode, iv))
+}
+
+export function desDecryptCompat(bridge : CompatBridge, key : string, data : string, mode : string = 'ECB', iv : string | null = null) : string {
+ return bridge.desDecryptText(key, data, buildXDesOptions(mode, iv))
+}
+
+export function generateRsaKeyPairCompat(bridge : CompatBridge, keySize : number = 2048) : CryptoRsaPair {
+ return bridge.createRsaPair(keySize)
+}
+
+export function rsaEncryptCompat(bridge : CompatBridge, publicKey : string, data : string) : string {
+ return bridge.rsaEncryptText(publicKey, data, 'base64')
+}
+
+export function rsaDecryptCompat(bridge : CompatBridge, privateKey : string, data : string) : string {
+ return bridge.rsaDecryptText(privateKey, data, 'base64')
+}
+
+export function rc4EncryptCompat(bridge : CompatBridge, key : string, data : string) : string {
+ return bridge.rc4EncryptText(key, data)
+}
+
+export function rc4DecryptCompat(bridge : CompatBridge, key : string, data : string) : string {
+ return bridge.rc4DecryptText(key, data)
+}
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/shared/options.uts b/uni_modules/laoqianjunzi-crypto/utssdk/shared/options.uts
new file mode 100644
index 0000000..380143e
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/shared/options.uts
@@ -0,0 +1,106 @@
+import type { CryptoBlockMode, CryptoByteCipherOptions, CryptoDesOptions, CryptoPaddingKind, CryptoRuntimeSnapshot, CryptoTextCipherOptions, CryptoTripleDesOptions, RsaOutputKind } from "../interface.uts"
+
+export function createDefaultTextCipherOptions() : CryptoTextCipherOptions {
+ return {
+ mode: "CBC",
+ padding: "PKCS7",
+ ivText: "0123456789abcdef",
+ keyLength: 16
+ } as CryptoTextCipherOptions
+}
+
+export function createDefaultByteCipherOptions() : CryptoByteCipherOptions {
+ return {
+ mode: "CBC",
+ padding: "PKCS7",
+ ivBytes: new Uint8Array([48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102]),
+ keyLength: 16
+ } as CryptoByteCipherOptions
+}
+
+export function createDefaultTripleDesOptions() : CryptoTripleDesOptions {
+ return {
+ mode: "CBC",
+ ivText: "12345678"
+ } as CryptoTripleDesOptions
+}
+
+export function createDefaultDesOptions() : CryptoDesOptions {
+ return {
+ mode: "CBC",
+ padding: "PKCS7",
+ ivText: "12345678"
+ } as CryptoDesOptions
+}
+
+export function normalizeTextCipherOptions(options : CryptoTextCipherOptions | null) : CryptoTextCipherOptions {
+ if (options == null) {
+ return createDefaultTextCipherOptions()
+ }
+ return {
+ mode: options.mode,
+ padding: options.padding,
+ ivText: options.ivText,
+ keyLength: options.keyLength
+ } as CryptoTextCipherOptions
+}
+
+export function normalizeByteCipherOptions(options : CryptoByteCipherOptions | null) : CryptoByteCipherOptions {
+ if (options == null) {
+ return createDefaultByteCipherOptions()
+ }
+ return {
+ mode: options.mode,
+ padding: options.padding,
+ ivBytes: options.ivBytes,
+ keyLength: options.keyLength
+ } as CryptoByteCipherOptions
+}
+
+export function normalizeTripleDesOptions(options : CryptoTripleDesOptions | null) : CryptoTripleDesOptions {
+ if (options == null) {
+ return createDefaultTripleDesOptions()
+ }
+ return {
+ mode: options.mode,
+ ivText: options.ivText
+ } as CryptoTripleDesOptions
+}
+
+export function normalizeDesOptions(options : CryptoDesOptions | null) : CryptoDesOptions {
+ if (options == null) {
+ return createDefaultDesOptions()
+ }
+ return {
+ mode: options.mode,
+ padding: options.padding,
+ ivText: options.ivText
+ } as CryptoDesOptions
+}
+
+export function buildRuntimeSnapshot(platformName : string, engineName : string, supportsAdvancedModes : boolean, usesNativeBridge : boolean) : CryptoRuntimeSnapshot {
+ return {
+ platformName: platformName,
+ engineName: engineName,
+ supportsAdvancedModes: supportsAdvancedModes,
+ usesNativeBridge: usesNativeBridge
+ } as CryptoRuntimeSnapshot
+}
+
+export function resolveHexOutput(outputKind : RsaOutputKind | null) : boolean {
+ return outputKind == "hex"
+}
+
+export function createAsciiBlock(text : string, size : number) : Uint8Array {
+ const output = new Uint8Array(size)
+ let index = 0
+ while (index < size) {
+ if (index < text.length) {
+ output[index] = text.charCodeAt(index) & 0xff
+ } else {
+ output[index] = 0
+ }
+ index += 1
+ }
+ return output
+}
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/shared/portable_crypto.ts b/uni_modules/laoqianjunzi-crypto/utssdk/shared/portable_crypto.ts
new file mode 100644
index 0000000..3515bbe
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/shared/portable_crypto.ts
@@ -0,0 +1,425 @@
+// @ts-nocheck
+import CryptoES from '../deps/node_modules/crypto-es/lib/index.js'
+import JSEncrypt from '../deps/node_modules/jsencrypt/lib/index.js'
+
+function ensureSupportedCodec(codec: string): void {
+ const value = codec.toLowerCase()
+ if (value == 'utf8' || value == 'hex' || value == 'base64' || value == 'base64url' || value == 'latin1' || value == 'utf16') {
+ return
+ }
+ throw new Error('不支持的编码类型')
+}
+
+function ensureDigestKind(kind: string): string {
+ const value = kind.toLowerCase()
+ if (value == 'md5' || value == 'sha1' || value == 'sha256' || value == 'sha512') {
+ return value
+ }
+ throw new Error('不支持的摘要算法')
+}
+
+function ensureMacKind(kind: string): string {
+ const value = kind.toLowerCase()
+ if (value == 'sha1' || value == 'sha256' || value == 'sha512') {
+ return value
+ }
+ throw new Error('不支持的HMAC算法')
+}
+
+function ensureAesMode(mode: string): any {
+ const value = mode.toUpperCase()
+ if (value == 'CBC') {
+ return CryptoES.mode.CBC
+ }
+ if (value == 'CFB') {
+ return CryptoES.mode.CFB
+ }
+ if (value == 'CTR') {
+ return CryptoES.mode.CTR
+ }
+ if (value == 'CTRGLADMAN') {
+ return CryptoES.mode.CTRGladman
+ }
+ if (value == 'ECB') {
+ return CryptoES.mode.ECB
+ }
+ if (value == 'OFB') {
+ return CryptoES.mode.OFB
+ }
+ throw new Error('不支持的AES模式')
+}
+
+function ensureAesPadding(padding: string): any {
+ const value = padding.toUpperCase()
+ if (value == 'PKCS7') {
+ return CryptoES.pad.Pkcs7
+ }
+ if (value == 'ANSI_X923') {
+ return CryptoES.pad.AnsiX923
+ }
+ if (value == 'ISO_10126') {
+ return CryptoES.pad.Iso10126
+ }
+ if (value == 'ISO_97971') {
+ return CryptoES.pad.Iso97971
+ }
+ if (value == 'NONE') {
+ return CryptoES.pad.NoPadding
+ }
+ if (value == 'ZERO') {
+ return CryptoES.pad.ZeroPadding
+ }
+ throw new Error('不支持的AES填充')
+}
+
+function ensureTripleDesMode(mode: string): any {
+ const value = mode.toUpperCase()
+ if (value == 'CBC') {
+ return CryptoES.mode.CBC
+ }
+ if (value == 'ECB') {
+ return CryptoES.mode.ECB
+ }
+ throw new Error('不支持的3DES模式')
+}
+
+function ensureDesMode(mode: string): any {
+ const value = mode.toUpperCase()
+ if (value == 'CBC') {
+ return CryptoES.mode.CBC
+ }
+ if (value == 'CFB') {
+ return CryptoES.mode.CFB
+ }
+ if (value == 'CTR') {
+ return CryptoES.mode.CTR
+ }
+ if (value == 'CTRGLADMAN') {
+ return CryptoES.mode.CTRGladman
+ }
+ if (value == 'ECB') {
+ return CryptoES.mode.ECB
+ }
+ if (value == 'OFB') {
+ return CryptoES.mode.OFB
+ }
+ throw new Error('不支持的DES模式')
+}
+
+function inferKeyLength(sourceLength: number, hint: number | null): number {
+ if (hint != null) {
+ if (hint == 16 || hint == 24 || hint == 32) {
+ return hint
+ }
+ if (hint == 128) {
+ return 16
+ }
+ if (hint == 192) {
+ return 24
+ }
+ if (hint == 256) {
+ return 32
+ }
+ throw new Error('AES密钥长度无效')
+ }
+ if (sourceLength <= 16) {
+ return 16
+ }
+ if (sourceLength <= 24) {
+ return 24
+ }
+ return 32
+}
+
+function clampBytes(source: Uint8Array, targetLength: number): Uint8Array {
+ const output = new Uint8Array(targetLength)
+ const actualLength = source.length < targetLength ? source.length : targetLength
+ let index = 0
+ while (index < actualLength) {
+ output[index] = source[index]
+ index += 1
+ }
+ return output
+}
+
+function textToUtf8Bytes(input: string): Uint8Array {
+ const wordArray = CryptoES.enc.Utf8.parse(input)
+ return wordArrayToBytes(wordArray)
+}
+
+function utf8BytesToText(input: Uint8Array): string {
+ return bytesToWordArray(input).toString(CryptoES.enc.Utf8)
+}
+
+function bytesToWordArray(input: Uint8Array): any {
+ const words: number[] = []
+ let index = 0
+ while (index < input.length) {
+ let word = 0
+ let offset = 0
+ while (offset < 4 && index + offset < input.length) {
+ word |= input[index + offset] << (24 - offset * 8)
+ offset += 1
+ }
+ words.push(word)
+ index += 4
+ }
+ return CryptoES.lib.WordArray.create(words, input.length)
+}
+
+function wordArrayToBytes(wordArray: any): Uint8Array {
+ const sigBytes = wordArray.sigBytes
+ const output = new Uint8Array(sigBytes)
+ const words = wordArray.words
+ let index = 0
+ while (index < sigBytes) {
+ const wordIndex = Math.floor(index / 4)
+ const byteOffset = index % 4
+ output[index] = (words[wordIndex] >>> (24 - byteOffset * 8)) & 0xff
+ index += 1
+ }
+ return output
+}
+
+function fitKeyText(secretText: string, keyLength: number | null): any {
+ const rawBytes = textToUtf8Bytes(secretText)
+ const actualLength = inferKeyLength(rawBytes.length, keyLength)
+ return bytesToWordArray(clampBytes(rawBytes, actualLength))
+}
+
+function fitFixedTextKey(secretText: string, targetLength: number): any {
+ return bytesToWordArray(clampBytes(textToUtf8Bytes(secretText), targetLength))
+}
+
+function fitKeyBytes(secretBytes: Uint8Array, keyLength: number | null): any {
+ const actualLength = inferKeyLength(secretBytes.length, keyLength)
+ return bytesToWordArray(clampBytes(secretBytes, actualLength))
+}
+
+function fitIvText(ivText: string | null, size: number): any {
+ const source = ivText == null ? new Uint8Array(size) : clampBytes(textToUtf8Bytes(ivText), size)
+ return bytesToWordArray(source)
+}
+
+function fitIvBytes(ivBytes: Uint8Array | null, size: number): any {
+ const source = ivBytes == null ? new Uint8Array(size) : clampBytes(ivBytes, size)
+ return bytesToWordArray(source)
+}
+
+function wrapCipherBytes(cipherBytes: Uint8Array): any {
+ return CryptoES.lib.CipherParams.create({
+ ciphertext: bytesToWordArray(cipherBytes)
+ })
+}
+
+function toBase64Url(base64Text: string): string {
+ return base64Text.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '')
+}
+
+function fromBase64Url(base64UrlText: string): string {
+ let output = base64UrlText.replace(/-/g, '+').replace(/_/g, '/')
+ while (output.length % 4 != 0) {
+ output += '='
+ }
+ return output
+}
+
+function base64ToHex(base64Text: string): string {
+ return CryptoES.enc.Base64.parse(base64Text).toString(CryptoES.enc.Hex)
+}
+
+function hexToBase64(hexText: string): string {
+ return CryptoES.enc.Hex.parse(hexText).toString(CryptoES.enc.Base64)
+}
+
+export function encodeTextPortable(codec: string, plainText: string): string {
+ ensureSupportedCodec(codec)
+ const value = codec.toLowerCase()
+ if (value == 'utf8') {
+ return plainText
+ }
+ const word = CryptoES.enc.Utf8.parse(plainText)
+ if (value == 'hex') {
+ return CryptoES.enc.Hex.stringify(word)
+ }
+ if (value == 'base64') {
+ return CryptoES.enc.Base64.stringify(word)
+ }
+ if (value == 'base64url') {
+ return toBase64Url(CryptoES.enc.Base64.stringify(word))
+ }
+ if (value == 'latin1') {
+ return CryptoES.enc.Latin1.stringify(word)
+ }
+ return CryptoES.enc.Utf16.stringify(word)
+}
+
+export function decodeTextPortable(codec: string, encodedText: string): string {
+ ensureSupportedCodec(codec)
+ const value = codec.toLowerCase()
+ if (value == 'utf8') {
+ return encodedText
+ }
+ if (value == 'hex') {
+ return CryptoES.enc.Hex.parse(encodedText).toString(CryptoES.enc.Utf8)
+ }
+ if (value == 'base64') {
+ return CryptoES.enc.Base64.parse(encodedText).toString(CryptoES.enc.Utf8)
+ }
+ if (value == 'base64url') {
+ return CryptoES.enc.Base64.parse(fromBase64Url(encodedText)).toString(CryptoES.enc.Utf8)
+ }
+ if (value == 'latin1') {
+ return CryptoES.enc.Latin1.parse(encodedText).toString(CryptoES.enc.Utf8)
+ }
+ return CryptoES.enc.Utf16.parse(encodedText).toString(CryptoES.enc.Utf8)
+}
+
+export function digestTextPortable(kind: string, plainText: string): string {
+ const value = ensureDigestKind(kind)
+ if (value == 'md5') {
+ return CryptoES.MD5(plainText).toString()
+ }
+ if (value == 'sha1') {
+ return CryptoES.SHA1(plainText).toString()
+ }
+ if (value == 'sha256') {
+ return CryptoES.SHA256(plainText).toString()
+ }
+ return CryptoES.SHA512(plainText).toString()
+}
+
+export function signTextPortable(kind: string, secretText: string, plainText: string): string {
+ const value = ensureMacKind(kind)
+ if (value == 'sha1') {
+ return CryptoES.HmacSHA1(plainText, secretText).toString()
+ }
+ if (value == 'sha256') {
+ return CryptoES.HmacSHA256(plainText, secretText).toString()
+ }
+ return CryptoES.HmacSHA512(plainText, secretText).toString()
+}
+
+export function aesEncryptTextPortable(secretText: string, plainText: string, mode: string, padding: string, ivText: string | null, keyLength: number | null): string {
+ const encrypted = CryptoES.AES.encrypt(plainText, fitKeyText(secretText, keyLength), {
+ iv: fitIvText(ivText, 16),
+ mode: ensureAesMode(mode),
+ padding: ensureAesPadding(padding)
+ })
+ return encrypted.toString()
+}
+
+export function aesDecryptTextPortable(secretText: string, cipherText: string, mode: string, padding: string, ivText: string | null, keyLength: number | null): string {
+ const decrypted = CryptoES.AES.decrypt(cipherText, fitKeyText(secretText, keyLength), {
+ iv: fitIvText(ivText, 16),
+ mode: ensureAesMode(mode),
+ padding: ensureAesPadding(padding)
+ })
+ return decrypted.toString(CryptoES.enc.Utf8)
+}
+
+export function aesEncryptBytesPortable(secretBytes: Uint8Array, plainBytes: Uint8Array, mode: string, padding: string, ivBytes: Uint8Array | null, keyLength: number | null): Uint8Array {
+ const encrypted = CryptoES.AES.encrypt(bytesToWordArray(plainBytes), fitKeyBytes(secretBytes, keyLength), {
+ iv: fitIvBytes(ivBytes, 16),
+ mode: ensureAesMode(mode),
+ padding: ensureAesPadding(padding)
+ })
+ return wordArrayToBytes(encrypted.ciphertext)
+}
+
+export function aesDecryptBytesPortable(secretBytes: Uint8Array, cipherBytes: Uint8Array, mode: string, padding: string, ivBytes: Uint8Array | null, keyLength: number | null): Uint8Array {
+ const decrypted = CryptoES.AES.decrypt(wrapCipherBytes(cipherBytes), fitKeyBytes(secretBytes, keyLength), {
+ iv: fitIvBytes(ivBytes, 16),
+ mode: ensureAesMode(mode),
+ padding: ensureAesPadding(padding)
+ })
+ return wordArrayToBytes(decrypted)
+}
+
+export function tripleDesEncryptTextPortable(secretText: string, plainText: string, mode: string, ivText: string | null): string {
+ const encrypted = CryptoES.TripleDES.encrypt(plainText, fitKeyText(secretText, 24), {
+ iv: fitIvText(ivText, 8),
+ mode: ensureTripleDesMode(mode),
+ padding: CryptoES.pad.Pkcs7
+ })
+ return encrypted.toString()
+}
+
+export function tripleDesDecryptTextPortable(secretText: string, cipherText: string, mode: string, ivText: string | null): string {
+ const decrypted = CryptoES.TripleDES.decrypt(cipherText, fitKeyText(secretText, 24), {
+ iv: fitIvText(ivText, 8),
+ mode: ensureTripleDesMode(mode),
+ padding: CryptoES.pad.Pkcs7
+ })
+ return decrypted.toString(CryptoES.enc.Utf8)
+}
+
+export function desEncryptTextPortable(secretText: string, plainText: string, mode: string, padding: string, ivText: string | null): string {
+ const encrypted = CryptoES.DES.encrypt(plainText, fitFixedTextKey(secretText, 8), {
+ iv: fitIvText(ivText, 8),
+ mode: ensureDesMode(mode),
+ padding: ensureAesPadding(padding)
+ })
+ return encrypted.toString()
+}
+
+export function desDecryptTextPortable(secretText: string, cipherText: string, mode: string, padding: string, ivText: string | null): string {
+ const decrypted = CryptoES.DES.decrypt(cipherText, fitFixedTextKey(secretText, 8), {
+ iv: fitIvText(ivText, 8),
+ mode: ensureDesMode(mode),
+ padding: ensureAesPadding(padding)
+ })
+ return decrypted.toString(CryptoES.enc.Utf8)
+}
+
+export function rc4EncryptTextPortable(secretText: string, plainText: string): string {
+ const encrypted = CryptoES.RC4.encrypt(plainText, CryptoES.enc.Utf8.parse(secretText))
+ return encrypted.ciphertext.toString(CryptoES.enc.Hex)
+}
+
+export function rc4DecryptTextPortable(secretText: string, cipherHexText: string): string {
+ const decrypted = CryptoES.RC4.decrypt(wrapCipherBytes(wordArrayToBytes(CryptoES.enc.Hex.parse(cipherHexText))), CryptoES.enc.Utf8.parse(secretText))
+ return decrypted.toString(CryptoES.enc.Utf8)
+}
+
+export function createRsaPairPortable(keySize: number): { publicKey: string, privateKey: string } {
+ const engine = new JSEncrypt({ default_key_size: keySize.toString() })
+ engine.getKey()
+ return {
+ publicKey: engine.getPublicKey(),
+ privateKey: engine.getPrivateKey()
+ }
+}
+
+export function rsaEncryptTextPortable(publicKey: string, plainText: string, outputKind: string | null): string {
+ const engine = new JSEncrypt()
+ engine.setPublicKey(publicKey)
+ const encrypted = engine.encrypt(plainText)
+ if (encrypted == null || encrypted == false) {
+ throw new Error('RSA加密失败')
+ }
+ return outputKind == 'hex' ? base64ToHex(encrypted as string) : encrypted as string
+}
+
+export function rsaDecryptTextPortable(privateKey: string, cipherText: string, outputKind: string | null): string {
+ const engine = new JSEncrypt()
+ engine.setPrivateKey(privateKey)
+ const source = outputKind == 'hex' ? hexToBase64(cipherText) : cipherText
+ const decrypted = engine.decrypt(source)
+ if (decrypted == null || decrypted == false) {
+ throw new Error('RSA解密失败')
+ }
+ return decrypted as string
+}
+
+export function bytesToHexPortable(input: Uint8Array): string {
+ return bytesToWordArray(input).toString(CryptoES.enc.Hex)
+}
+
+export function utf8ToBytesPortable(input: string): Uint8Array {
+ return textToUtf8Bytes(input)
+}
+
+export function bytesToUtf8Portable(input: Uint8Array): string {
+ return utf8BytesToText(input)
+}
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/unierror.uts b/uni_modules/laoqianjunzi-crypto/utssdk/unierror.uts
new file mode 100644
index 0000000..a59d331
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/unierror.uts
@@ -0,0 +1,27 @@
+import { CryptoBridgeErrorCode, CryptoBridgeFailure } from "./interface.uts"
+
+export const CryptoErrorSubject = "laoqianjunzi-crypto"
+
+export const CryptoErrorMessages : Map = new Map([
+ [7401, "crypto bridge: text input is empty"],
+ [7402, "crypto bridge: unsupported codec kind"],
+ [7403, "crypto bridge: unsupported digest kind"],
+ [7404, "crypto bridge: unsupported hmac kind"],
+ [7405, "crypto bridge: unsupported block mode"],
+ [7406, "crypto bridge: unsupported padding kind"],
+ [7407, "crypto bridge: invalid cipher payload"],
+ [7408, "crypto bridge: invalid key or iv"],
+ [7409, "crypto bridge: rsa operation failed"],
+ [7410, "crypto bridge: current platform is missing required capability"]
+])
+
+export class CryptoBridgeFailureImpl extends UniError implements CryptoBridgeFailure {
+ override errCode : CryptoBridgeErrorCode
+
+ constructor(errCode : CryptoBridgeErrorCode) {
+ super()
+ this.errSubject = CryptoErrorSubject
+ this.errCode = errCode
+ this.errMsg = CryptoErrorMessages[errCode] ?? ""
+ }
+}
diff --git a/uni_modules/laoqianjunzi-crypto/utssdk/web/index.uts b/uni_modules/laoqianjunzi-crypto/utssdk/web/index.uts
new file mode 100644
index 0000000..3ac065e
--- /dev/null
+++ b/uni_modules/laoqianjunzi-crypto/utssdk/web/index.uts
@@ -0,0 +1,209 @@
+import type { CryptoByteCipherOptions, CryptoCodecKind, CryptoDesOptions, CryptoDigestKind, CryptoMacKind, CryptoRsaPair, CryptoRuntimeSnapshot, CryptoTextCipherOptions, CryptoTripleDesOptions, RsaOutputKind } from '../interface.uts'
+import { buildRuntimeSnapshot, createDefaultByteCipherOptions, createDefaultDesOptions, createDefaultTextCipherOptions, createDefaultTripleDesOptions, normalizeByteCipherOptions, normalizeDesOptions, normalizeTextCipherOptions, normalizeTripleDesOptions, resolveHexOutput } from '../shared/options.uts'
+import { aesDecryptBytesPortable, aesDecryptTextPortable, aesEncryptBytesPortable, aesEncryptTextPortable, createRsaPairPortable, decodeTextPortable, desDecryptTextPortable, desEncryptTextPortable, digestTextPortable, encodeTextPortable, rc4DecryptTextPortable, rc4EncryptTextPortable, rsaDecryptTextPortable, rsaEncryptTextPortable, signTextPortable, tripleDesDecryptTextPortable, tripleDesEncryptTextPortable } from '../shared/portable_crypto'
+import type { CompatBridge, CompatCrypto } from '../shared/compat.uts'
+import { aesDecryptBytesCompat, aesDecryptCompat, aesEncryptBytesCompat, aesEncryptCompat, base64DecodeCompat, base64EncodeCompat, createCompatBridge, createCompatCrypto, desDecryptCompat, desEncryptCompat, generateRsaKeyPairCompat, hmacSha1Compat, hmacSha256Compat, hmacSha512Compat, md5Compat, rc4DecryptCompat, rc4EncryptCompat, rsaDecryptCompat, rsaEncryptCompat, sha1Compat, sha256Compat, sha512Compat } from '../shared/compat.uts'
+
+export function defaultTextCipherOptions() : CryptoTextCipherOptions {
+ return createDefaultTextCipherOptions()
+}
+
+export function defaultByteCipherOptions() : CryptoByteCipherOptions {
+ return createDefaultByteCipherOptions()
+}
+
+export function defaultTripleDesOptions() : CryptoTripleDesOptions {
+ return createDefaultTripleDesOptions()
+}
+
+export function defaultDesOptions() : CryptoDesOptions {
+ return createDefaultDesOptions()
+}
+
+export function describeCryptoRuntime() : CryptoRuntimeSnapshot {
+ return buildRuntimeSnapshot('Web', 'crypto-es', true, false)
+}
+
+export function encodeText(codec : CryptoCodecKind, plainText : string) : string {
+ return encodeTextPortable(codec, plainText)
+}
+
+export function decodeText(codec : CryptoCodecKind, encodedText : string) : string {
+ return decodeTextPortable(codec, encodedText)
+}
+
+export function digestText(kind : CryptoDigestKind, plainText : string) : string {
+ return digestTextPortable(kind, plainText)
+}
+
+export function signText(kind : CryptoMacKind, secretText : string, plainText : string) : string {
+ return signTextPortable(kind, secretText, plainText)
+}
+
+export function aesEncryptText(secretText : string, plainText : string, options : CryptoTextCipherOptions | null) : string {
+ const actual = normalizeTextCipherOptions(options)
+ return aesEncryptTextPortable(secretText, plainText, actual.mode, actual.padding, actual.ivText, actual.keyLength)
+}
+
+export function aesDecryptText(secretText : string, cipherText : string, options : CryptoTextCipherOptions | null) : string {
+ const actual = normalizeTextCipherOptions(options)
+ return aesDecryptTextPortable(secretText, cipherText, actual.mode, actual.padding, actual.ivText, actual.keyLength)
+}
+
+export function aesEncryptBytes(secretBytes : Uint8Array, plainBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array {
+ const actual = normalizeByteCipherOptions(options)
+ return aesEncryptBytesPortable(secretBytes, plainBytes, actual.mode, actual.padding, actual.ivBytes, actual.keyLength)
+}
+
+export function aesDecryptBytes(secretBytes : Uint8Array, cipherBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array {
+ const actual = normalizeByteCipherOptions(options)
+ return aesDecryptBytesPortable(secretBytes, cipherBytes, actual.mode, actual.padding, actual.ivBytes, actual.keyLength)
+}
+
+export function tripleDesEncryptText(secretText : string, plainText : string, options : CryptoTripleDesOptions | null) : string {
+ const actual = normalizeTripleDesOptions(options)
+ return tripleDesEncryptTextPortable(secretText, plainText, actual.mode, actual.ivText)
+}
+
+export function tripleDesDecryptText(secretText : string, cipherText : string, options : CryptoTripleDesOptions | null) : string {
+ const actual = normalizeTripleDesOptions(options)
+ return tripleDesDecryptTextPortable(secretText, cipherText, actual.mode, actual.ivText)
+}
+
+export function desEncryptText(secretText : string, plainText : string, options : CryptoDesOptions | null) : string {
+ const actual = normalizeDesOptions(options)
+ return desEncryptTextPortable(secretText, plainText, actual.mode, actual.padding, actual.ivText)
+}
+
+export function desDecryptText(secretText : string, cipherText : string, options : CryptoDesOptions | null) : string {
+ const actual = normalizeDesOptions(options)
+ return desDecryptTextPortable(secretText, cipherText, actual.mode, actual.padding, actual.ivText)
+}
+
+export function rc4EncryptText(secretText : string, plainText : string) : string {
+ return rc4EncryptTextPortable(secretText, plainText)
+}
+
+export function rc4DecryptText(secretText : string, cipherHexText : string) : string {
+ return rc4DecryptTextPortable(secretText, cipherHexText)
+}
+
+export function createRsaPair(keySize : number) : CryptoRsaPair {
+ const bundle = createRsaPairPortable(keySize)
+ return {
+ publicKey: bundle.publicKey,
+ privateKey: bundle.privateKey
+ } as CryptoRsaPair
+}
+
+export function rsaEncryptText(publicKey : string, plainText : string, outputKind : RsaOutputKind | null) : string {
+ return rsaEncryptTextPortable(publicKey, plainText, resolveHexOutput(outputKind) ? 'hex' : 'base64')
+}
+
+export function rsaDecryptText(privateKey : string, cipherText : string, outputKind : RsaOutputKind | null) : string {
+ return rsaDecryptTextPortable(privateKey, cipherText, resolveHexOutput(outputKind) ? 'hex' : 'base64')
+}
+
+function compatBridge() : CompatBridge {
+ return createCompatBridge(
+ (codec : CryptoCodecKind, plainText : string) : string => encodeText(codec, plainText),
+ (codec : CryptoCodecKind, encodedText : string) : string => decodeText(codec, encodedText),
+ (kind : CryptoDigestKind, plainText : string) : string => digestText(kind, plainText),
+ (kind : CryptoMacKind, secretText : string, plainText : string) : string => signText(kind, secretText, plainText),
+ (secretText : string, plainText : string, options : CryptoTextCipherOptions | null) : string => aesEncryptText(secretText, plainText, options),
+ (secretText : string, cipherText : string, options : CryptoTextCipherOptions | null) : string => aesDecryptText(secretText, cipherText, options),
+ (secretBytes : Uint8Array, plainBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array => aesEncryptBytes(secretBytes, plainBytes, options),
+ (secretBytes : Uint8Array, cipherBytes : Uint8Array, options : CryptoByteCipherOptions | null) : Uint8Array => aesDecryptBytes(secretBytes, cipherBytes, options),
+ (secretText : string, plainText : string, options : CryptoDesOptions | null) : string => desEncryptText(secretText, plainText, options),
+ (secretText : string, cipherText : string, options : CryptoDesOptions | null) : string => desDecryptText(secretText, cipherText, options),
+ (keySize : number) : CryptoRsaPair => createRsaPair(keySize),
+ (publicKey : string, plainText : string, outputKind : RsaOutputKind | null) : string => rsaEncryptText(publicKey, plainText, outputKind),
+ (privateKey : string, cipherText : string, outputKind : RsaOutputKind | null) : string => rsaDecryptText(privateKey, cipherText, outputKind),
+ (secretText : string, plainText : string) : string => rc4EncryptText(secretText, plainText),
+ (secretText : string, cipherHexText : string) : string => rc4DecryptText(secretText, cipherHexText)
+ )
+}
+
+export function base64Encode(input : string) : string {
+ return base64EncodeCompat(compatBridge(), input)
+}
+
+export function base64Decode(input : string) : string {
+ return base64DecodeCompat(compatBridge(), input)
+}
+
+export function md5(input : string) : string {
+ return md5Compat(compatBridge(), input)
+}
+
+export function sha1(input : string) : string {
+ return sha1Compat(compatBridge(), input)
+}
+
+export function sha256(input : string) : string {
+ return sha256Compat(compatBridge(), input)
+}
+
+export function sha512(input : string) : string {
+ return sha512Compat(compatBridge(), input)
+}
+
+export function hmacSha1(key : string, data : string) : string {
+ return hmacSha1Compat(compatBridge(), key, data)
+}
+
+export function hmacSha256(key : string, data : string) : string {
+ return hmacSha256Compat(compatBridge(), key, data)
+}
+
+export function hmacSha512(key : string, data : string) : string {
+ return hmacSha512Compat(compatBridge(), key, data)
+}
+
+export function aesEncrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null, keySize : number | null = 16) : string {
+ return aesEncryptCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function aesDecrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null, keySize : number | null = 16) : string {
+ return aesDecryptCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function aesEncrypt2(key : Uint8Array, data : Uint8Array, mode : string = 'ECB', iv : Uint8Array | null = null, keySize : number | null = 16) : Uint8Array {
+ return aesEncryptBytesCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function aesDecrypt2(key : Uint8Array, data : Uint8Array, mode : string = 'ECB', iv : Uint8Array | null = null, keySize : number | null = 16) : Uint8Array {
+ return aesDecryptBytesCompat(compatBridge(), key, data, mode, iv, keySize)
+}
+
+export function desEncrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null) : string {
+ return desEncryptCompat(compatBridge(), key, data, mode, iv)
+}
+
+export function desDecrypt(key : string, data : string, mode : string = 'ECB', iv : string | null = null) : string {
+ return desDecryptCompat(compatBridge(), key, data, mode, iv)
+}
+
+export function generateRSAKeyPair(keySize : number = 2048) : CryptoRsaPair {
+ return generateRsaKeyPairCompat(compatBridge(), keySize)
+}
+
+export function rsaEncrypt(publicKey : string, data : string) : string {
+ return rsaEncryptCompat(compatBridge(), publicKey, data)
+}
+
+export function rsaDecrypt(privateKey : string, data : string) : string {
+ return rsaDecryptCompat(compatBridge(), privateKey, data)
+}
+
+export function rc4Encrypt(key : string, data : string) : string {
+ return rc4EncryptCompat(compatBridge(), key, data)
+}
+
+export function rc4Decrypt(key : string, data : string) : string {
+ return rc4DecryptCompat(compatBridge(), key, data)
+}
+
+export function useCrypto() : CompatCrypto {
+ return createCompatCrypto(compatBridge())
+}