SM2/SM3 TypeScript implementation based on Bouncy Castle Java
一比一复刻 Bouncy Castle Java 的 SM2、SM3 和 SM4 算法的 TypeScript 实现。
-
🔐 SM2 - 椭圆曲线公钥密码算法(数字签名、公钥加密、密钥交换��
-
🔒 SM3 - 密码杂凑算法(256位消息摘要)
-
🔑 SM4 - 分组密码算法(128位对称加密)
-
🎯 零运行时依赖 - 纯 TypeScript 实现
-
🔒 完全兼容 - 与 Bouncy Castle Java 完全互操作
-
📦 多格式输出 - 支持 CommonJS、ESM 和 IIFE
-
🧪 双重验证 - 自闭环测试 + GraalVM 跨语言测试
-
📚 完整文档 - 详细的 API 文档和使用指南
-
✅ 高质量 - >90% 测试覆盖率
-
🌐 浏览器支持 - 可在浏览器和 Node.js 中使用
npm install sm-js-bc💡 提示: 以下是基础用法示例。想要完整的可运行代码?直接跳转到 📚 完整示例 章��,所有示例都可以直接运行!
以下代码片段展示了各算法的基本用法:
import { SM3Digest } from 'sm-js-bc';
const digest = new SM3Digest();
const data = new TextEncoder().encode('Hello, SM3!');
digest.update(data, 0, data.length);
const hash = new Uint8Array(digest.getDigestSize());
digest.doFinal(hash, 0);
console.log('SM3 Hash:', Buffer.from(hash).toString('hex'));📖 完整示例: example/sm3-hash.mjs
import { SM2 } from 'sm-js-bc';
const keyPair = SM2.generateKeyPair();
console.log('Private key:', keyPair.privateKey.toString(16));
console.log('Public key X:', keyPair.publicKey.x.toString(16));
console.log('Public key Y:', keyPair.publicKey.y.toString(16));📖 完整示例: example/sm2-keypair.mjs
import { SM2 } from 'sm-js-bc';
const keyPair = SM2.generateKeyPair();
// 签名
const message = 'Hello, SM2!';
const signature = SM2.sign(message, keyPair.privateKey);
// 验签
const isValid = SM2.verify(message, signature, keyPair.publicKey);
console.log('Signature valid:', isValid);📖 完整示例: example/sm2-sign.mjs
import { SM2 } from 'sm-js-bc';
const keyPair = SM2.generateKeyPair();
// 加密
const plaintext = new TextEncoder().encode('Secret message');
const ciphertext = SM2.encrypt(plaintext, keyPair.publicKey);
// 解密
const decrypted = SM2.decrypt(ciphertext, keyPair.privateKey);
console.log('Decrypted:', new TextDecoder().decode(decrypted));📖 完整示例: example/sm2-encrypt.mjs
import { SM4 } from 'sm-js-bc';
// 生成密钥并加密
const key = SM4.generateKey();
const plaintext = new TextEncoder().encode('Hello, SM4!');
const ciphertext = SM4.encrypt(plaintext, key);
// 解密
const decrypted = SM4.decrypt(ciphertext, key);
console.log('Decrypted:', new TextDecoder().decode(decrypted));
⚠️ 安全提示: 上述示例使用 ECB 模式,仅用于演示。生产环境请使用 CBC、CTR 或 GCM 模式。
📖 完整示例:
- example/sm4-ecb-simple.mjs - 基础加密示例
- example/sm4-modes.mjs - 多种工作模式(ECB/CBC/CTR/GCM)
import {
SM2,
SM2KeyExchange,
SM2KeyExchangePrivateParameters,
SM2KeyExchangePublicParameters,
ECPrivateKeyParameters,
ECPublicKeyParameters
} from 'sm-js-bc';
// 获取SM2域参数
const domainParams = SM2.getParameters();
const curve = domainParams.getCurve();
// Alice 生成密钥对(静态 + 临时)
const aliceStatic = SM2.generateKeyPair();
const aliceEphemeral = SM2.generateKeyPair();
const aliceStaticPriv = new ECPrivateKeyParameters(aliceStatic.privateKey, domainParams);
const aliceStaticPub = new ECPublicKeyParameters(
curve.createPoint(aliceStatic.publicKey.x, aliceStatic.publicKey.y),
domainParams
);
const aliceEphemeralPriv = new ECPrivateKeyParameters(aliceEphemeral.privateKey, domainParams);
const aliceEphemeralPub = new ECPublicKeyParameters(
curve.createPoint(aliceEphemeral.publicKey.x, aliceEphemeral.publicKey.y),
domainParams
);
// Bob 生成密钥对(静态 + 临时)
const bobStatic = SM2.generateKeyPair();
const bobEphemeral = SM2.generateKeyPair();
const bobStaticPriv = new ECPrivateKeyParameters(bobStatic.privateKey, domainParams);
const bobStaticPub = new ECPublicKeyParameters(
curve.createPoint(bobStatic.publicKey.x, bobStatic.publicKey.y),
domainParams
);
const bobEphemeralPriv = new ECPrivateKeyParameters(bobEphemeral.privateKey, domainParams);
const bobEphemeralPub = new ECPublicKeyParameters(
curve.createPoint(bobEphemeral.publicKey.x, bobEphemeral.publicKey.y),
domainParams
);
// Alice 初始化密钥交换(发起方)
const aliceExchange = new SM2KeyExchange();
const alicePrivParams = new SM2KeyExchangePrivateParameters(
true, // initiator
aliceStaticPriv,
aliceEphemeralPriv
);
aliceExchange.init(alicePrivParams);
// Alice 计算共享密钥
const bobPubParams = new SM2KeyExchangePublicParameters(bobStaticPub, bobEphemeralPub);
const aliceSharedKey = aliceExchange.calculateKey(128, bobPubParams);
// Bob 初始化密钥交换(响应方)
const bobExchange = new SM2KeyExchange();
const bobPrivParams = new SM2KeyExchangePrivateParameters(
false, // responder
bobStaticPriv,
bobEphemeralPriv
);
bobExchange.init(bobPrivParams);
// Bob 计算共享密钥
const alicePubParams = new SM2KeyExchangePublicParameters(aliceStaticPub, aliceEphemeralPub);
const bobSharedKey = bobExchange.calculateKey(128, alicePubParams);
// 验证双方密钥一致
console.log('Keys match:',
Buffer.from(aliceSharedKey).equals(Buffer.from(bobSharedKey))
);💡 提示: SM2 密钥交换涉及多个参数类和步骤,建议查看完整示例了解详细用法。
📖 完整示例: example/sm2-keyexchange.mjs
所有算法都提供了完整的可运行示例,位于 example 目录:
| 示例文件 | 说明 | 演示内容 |
|---|---|---|
| sm3-hash.mjs | SM3 哈希计算 | 基本哈希、分段更新、空数据处理 |
| sm2-keypair.mjs | SM2 密钥对生成 | 生成密钥对、查看公私钥 |
| sm2-sign.mjs | SM2 数字签名 | 签名、验签、错误验证 |
| sm2-encrypt.mjs | SM2 公钥加密 | 加密、解密、不同长度消息 |
| sm2-keyexchange.mjs | SM2 密钥交换 | ECDH 协议、密钥协商 |
| sm4-ecb-simple.mjs | SM4 基础加密 | ECB 模式、PKCS7 填充 |
| sm4-modes.mjs | SM4 多种模式 | ECB/CBC/CTR/GCM 对比 |
# 进入示例目录
cd example
# 安装依赖
npm install
# 运行单个示例
npm run sm3-hash # SM3 哈希
npm run sm2-keypair # SM2 密钥对生成
npm run sm2-sign # SM2 数字签名
npm run sm2-encrypt # SM2 公钥加密
npm run sm2-keyexchange # SM2 密钥交换
npm run sm4-ecb-simple # SM4 基础加密
npm run sm4-modes # SM4 多种模式
# 运行所有示例
npm run all详细说明请查看 example/README.md。
详细文档请查看 docs 目录:
本项目采用双重验证策略,包含 TypeScript 单元测试和 Java GraalVM 跨语言互操作测试,总计 1077+ 个测试用例,确保代码质���和跨语言兼容性。
完整的跨语言互操作测试套件:
| 算法 | 测试类别 | 测试数量 | 说明 |
|---|---|---|---|
| SM3 | 参数化测试 | 77 | 不同长度、字符集、标准向量 |
| 属性测试 | 720 | 72个属性 × 10次迭代 | |
| 互操作测试 | 5 | Java ↔ JavaScript 一致性 | |
| 小计 | 802 | ||
| SM2 签名 | 参数化测试 | 25 | 不同消息、密钥对、错误处理 |
| 属性测试 | 100 | 10个属性 × 10次迭代 | |
| 互操作测试 | 4 | Java签名 ↔ JS验证 | |
| 小计 | 125 | ||
| SM2 加密 | 参数化测试 | 39 | 多种大小、跨语言、边界情况 |
| 属性测试 | 100 | 10个属性 × 10次迭代 | |
| 互操作测试 | 4 | Java加密 ↔ JS解密 | |
| 小计 | 139 | ||
| 跨语言测试 | 简化测试 | 3 | SM3 基础互操作 |
| 总计 | 1077 | 全部通过 ✅ |
- 参数化测试 - 使用 JUnit 5
@ParameterizedTest,覆盖各种输入场景 - 属性测试 - 使用
@RepeatedTest,验证数学和安全属性 - 互操作测试 - 通过 GraalVM Polyglot API 确保 Java ↔ JavaScript 完全兼容
# 运行所有测试(JavaScript + Java)
node test-all.mjs
# 详细输出模式
node test-all.mjs --verbose
# 仅运行 JavaScript 测试
node test-all.mjs --skip-java
# 仅运行 Java 测试
node test-all.mjs --skip-js
# 查看帮助
node test-all.mjs --help# 运行所有单元测试
npm test
# 监听模式
npm run test:watch
# 测试覆盖率
npm run test:coverage
# 测试 UI
npm run test:ui# 前置条件:安装 Maven 和 GraalVM (推荐 21+)
# 运行所有 Java 测试
cd test/graalvm-integration/java
mvn test
# 运行特定测试类
mvn test -Dtest=SM3ParameterizedTest
mvn test -Dtest=SM2SignaturePropertyTest
mvn test -Dtest=SM2EncryptionParameterizedTest
# 编译并运行
mvn clean test- JavaScript 测试: Node.js >= 20.0.0
- Java 测试:
- JDK >= 17 (推荐 GraalVM 21+)
- Maven >= 3.8.0
- Bouncy Castle >= 1.70
test/
├── unit/ # TypeScript 单元测试
│ ├── crypto/ # 密码学算法测试
│ ├── math/ # 数学库测试
│ └── util/ # 工具类测试
│
└── graalvm-integration/ # 跨语言互操作测试
├── java/ # Java 测试项目
│ ├── src/test/java/
│ │ ├── base/ # 测试基类
│ │ ├── interop/ # 互操作测试
│ │ ├── parameterized/ # 参数化测试
│ │ └── property/ # 属性测试
│ └── pom.xml # Maven 配置
│
└── BUG_FIX_SUMMARY.md # 已知问题和修复
sm-js-bc/
├── src/ # 源代码
│ ├── crypto/ # 密码学算法
│ │ ├── digests/ # 摘要算法(SM3)
│ │ ├── engines/ # 加密引擎(SM2)
│ │ ├── signers/ # 签名算法(SM2)
│ │ ├── agreement/ # 密钥交换
│ │ └── params/ # 参数类
│ ├── math/ # 数学运算
│ │ ├── ec/ # 椭圆曲线
│ │ └── field/ # 有限域
│ ├── util/ # 工具类
│ └── exceptions/ # 异常类
├── test/ # 测试
│ ├── unit/ # 单元测试
│ └── graalvm-integration/ # 互操作测试
├── docs/ # 文档
└── dist/ # 编译输出
- Node.js >= 20.0.0
- TypeScript >= 5.3.0
- Java >= 17(仅互操作测试需要,推荐 GraalVM 21+)
# 克隆项目
git clone <repository-url>
cd sm-js-bc
# 安装依赖
npm install
# 开发模式(监听文件变化)
npm run dev
# 运行测试
npm run test:watch
# 构建
npm run buildfeat: 新功能
fix: 修复 bug
docs: 文档更新
test: 测试相关
refactor: 重构
perf: 性能优化
chore: 构建/工具相关
欢迎贡献!请遵循以下步骤:
- Fork 本项目
- 创建特性分支 (
git checkout -b feature/AmazingFeature) - 提交更改 (
git commit -m 'feat: Add some AmazingFeature') - 推送到分支 (
git push origin feature/AmazingFeature) - 开启 Pull Request
请确保:
- ✅ 所有测试通过
- ✅ 代码覆盖率 >90%
- ✅ 遵循代码规范
- ✅ 更新相关文档
- Bouncy Castle Java - 参考实现
- GM/T 0003-2012 - SM2 标准
- GM/T 0004-2012 - SM3 标准
- GraalVM - 跨语言互操作平台
- Bouncy Castle 项目提供了优秀的参考实现
- 所有为国密算法标准化做出贡献的专家学者
为了在 JavaScript/TypeScript 生态中提供一个与 Bouncy Castle Java 完全兼容的 SM2/SM3 实现,确保跨语言互操作性。
- ✅ 基于 Bouncy Castle Java 一比一复刻,保证兼容性
- ✅ 通过 GraalVM 跨语言测试验证互操作性
- ✅ 零运行时依赖,纯 TypeScript 实现
- ✅ 完整的类型定义和文档
JavaScript 引擎(V8/Node.js)的性能已经非常接近 JVM。对于加密算法这类计算密集型任务,性能差异在可接受范围内,通常在同一数量级。
项目目前处于开发阶段。建议等到 v1.0.0 正式版发布并经过充分测试后再用于生产环境。
如有问题或建议,欢迎提出 Issue 或 Pull Request!