Appearance
SPI SM Crypto Extension 说明文档
功能概述
spi-sm-crypto-extension 是一个 Keycloak 扩展,实现了 Keycloak 的加密 SPI,集成了中国国家标准密码算法(国密算法),包括 SM2(椭圆曲线公钥密码算法)、SM3(密码杂凑算法)和 SM4(分组密码算法)。
该扩展为 Keycloak 提供了符合中国密码标准的加密能力,使 Keycloak 能够在需要使用国密算法的场景中正常工作,如政府、金融等对密码算法有特殊要求的领域。
界面预览


技术支持
- 技术支持: 北京必码科技工作室
- 官方文档: https://bima.cc
- 官方店铺: https://bima.taobao.com
- 联系邮箱: bima.cc@qq.com
- 联系微信: e18929958
核心组件
1. 国密算法工具类
SM2Util
功能:提供 SM2 椭圆曲线密码算法的实现,用于数字签名和密钥交换。
主要方法:
generateKeyPair():生成 SM2 密钥对sign(byte[] privateKey, byte[] data):使用 SM2 私钥对数据进行签名verify(byte[] publicKey, byte[] data, byte[] signature):使用 SM2 公钥验证签名encrypt(byte[] publicKey, byte[] data):使用 SM2 公钥加密数据decrypt(byte[] privateKey, byte[] encryptedData):使用 SM2 私钥解密数据
SM3Util
功能:提供 SM3 密码杂凑算法的实现,用于数据完整性校验和消息认证。
主要方法:
digest(byte[] data):对数据进行 SM3 哈希计算- 参数:
data- 要哈希的数据字节数组 - 返回值:SM3 哈希值字节数组(32字节)
- 功能:使用 SM3 算法对输入数据进行哈希计算
- 参数:
SM4Util
功能:提供 SM4 分组密码算法的实现,用于数据加密和解密。
主要方法:
encrypt(byte[] key, byte[] data):使用 SM4 密钥加密数据decrypt(byte[] key, byte[] encryptedData):使用 SM4 密钥解密数据generateKey():生成 SM4 密钥
2. 加密提供者实现
SMContentEncryptionProvider
功能:实现了 Keycloak 的 ContentEncryptionProvider 接口,用于内容加密,支持 JWE(JSON Web Encryption)。
主要方法:
jweEncryptionProvider():返回 JWE 加密提供者- 返回值:
JWEEncryptionProvider实例,当前返回 null,需要实现完整的 SM4 JWE 加密提供者
- 返回值:
SMContentEncryptionProviderFactory
功能:实现了 Keycloak 的 ContentEncryptionProviderFactory 接口,负责创建 SMContentEncryptionProvider 实例。
主要方法:
getId():返回提供者工厂的ID- 返回值:字符串,固定为 "bima-sm-content-encryption"
create(KeycloakSession session):创建内容加密提供者实例- 参数:
session- Keycloak 会话对象 - 返回值:
SMContentEncryptionProvider实例
- 参数:
SMHashProvider
功能:实现了 Keycloak 的 HashProvider 接口,用于哈希计算,使用 SM3 算法。
主要方法:
hash(byte[] data):对数据进行哈希计算,使用 SM3 算法- 参数:
data- 要哈希的数据字节数组 - 返回值:SM3 哈希值字节数组
- 参数:
SMHashProviderFactory
功能:实现了 Keycloak 的 HashProviderFactory 接口,负责创建 SMHashProvider 实例。
主要方法:
getId():返回提供者工厂的ID- 返回值:字符串,固定为 "bima-sm-hash"
create(KeycloakSession session):创建哈希提供者实例- 参数:
session- Keycloak 会话对象 - 返回值:
SMHashProvider实例
- 参数:
SMKeyProvider
功能:实现了 Keycloak 的 KeyProvider 接口,用于 SM 密钥管理。
主要方法:
getKey(String kid):根据密钥ID获取密钥getKeys():获取所有密钥createKey(RealmModel realm, Map<String, String> config):创建新密钥
SMKeyProviderFactory
功能:实现了 Keycloak 的 KeyProviderFactory 接口,负责创建 SMKeyProvider 实例。
主要方法:
getId():返回提供者工厂的ID- 返回值:字符串,固定为 "bima-sm-key"
create(KeycloakSession session, ComponentModel model):创建密钥提供者实例- 参数:
session- Keycloak 会话对象model- 组件模型对象
- 返回值:
SMKeyProvider实例
- 参数:
SMSignatureProvider
功能:实现了 Keycloak 的 SignatureProvider 接口,用于 SM2 数字签名。
主要方法:
signer(String algorithm, Key key):获取签名器上下文verifier(String algorithm, Key key):获取验证器上下文
SMSignatureProviderFactory
功能:实现了 Keycloak 的 SignatureProviderFactory 接口,负责创建 SMSignatureProvider 实例。
主要方法:
getId():返回提供者工厂的ID- 返回值:字符串,固定为 "bima-sm-signature"
create(KeycloakSession session):创建签名提供者实例- 参数:
session- Keycloak 会话对象 - 返回值:
SMSignatureProvider实例
- 参数:
SMSignatureSignerContext
功能:实现了 Keycloak 的 SignatureSignerContext 接口,用于 SM2 签名上下文。
主要方法:
sign(byte[] data):对数据进行签名sign(InputStream data):对输入流数据进行签名
SMSignatureVerifierContext
功能:实现了 Keycloak 的 SignatureVerifierContext 接口,用于 SM2 签名验证上下文。
主要方法:
verify(byte[] data, byte[] signature):验证签名verify(InputStream data, byte[] signature):验证输入流数据的签名
配置与使用
1. 开发环境搭建
前提条件
- JDK 11 或更高版本
- Maven 3.6 或更高版本
- Keycloak 17.0.0 或更高版本
- Bouncy Castle 库 1.68 或更高版本
编译构建
bash
cd spi-sm-crypto-extension
mvn clean package编译完成后,在 target 目录下会生成 spi-sm-crypto-extension-1.0.0.jar 文件。
2. 部署
将编译好的 JAR 文件放入 Keycloak 的 standalone/deployments 目录。
3. 依赖配置
该扩展依赖于 Bouncy Castle 库来实现国密算法,因此需要确保 Keycloak 环境中包含 Bouncy Castle 依赖。
方法一:将 Bouncy Castle JAR 文件放入 Keycloak 的 standalone/lib 目录
- 下载 Bouncy Castle 库(bcprov-jdk15on-1.68.jar 和 bcpkix-jdk15on-1.68.jar)
- 将这两个 JAR 文件放入 Keycloak 的
standalone/lib目录 - 重启 Keycloak 服务器
方法二:在 Maven 依赖中添加 Bouncy Castle
在 pom.xml 文件中添加 Bouncy Castle 依赖:
xml
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.68</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.68</version>
</dependency>4. 使用
Keycloak 会自动检测并加载该扩展,之后可以在 Keycloak 的配置中使用国密算法。
4.1 使用 SM3 哈希算法
在 Keycloak 中,可以通过以下方式使用 SM3 哈希算法:
- 登录 Keycloak 管理控制台
- 进入 Realm 设置 → 认证 → 密码策略
- 在哈希算法中选择 "bima-sm-hash"
- 保存配置
4.2 使用 SM2 数字签名
在 Keycloak 中,可以通过以下方式使用 SM2 数字签名:
- 登录 Keycloak 管理控制台
- 进入 Realm 设置 → 密钥
- 添加新的密钥,选择 "bima-sm-key" 类型
- 配置密钥参数并保存
- 在需要使用签名的地方选择该密钥
4.3 使用 SM4 加密
当前实现中,SM4 加密功能尚未完全实现,需要完成 SMContentEncryptionProvider.jweEncryptionProvider() 方法的实现。
扩展与定制
完善 SM4 加密实现
当前 SMContentEncryptionProvider.jweEncryptionProvider() 方法返回 null,需要实现完整的 SM4 JWE 加密提供者。
实现示例:
java
@Override
public JWEEncryptionProvider jweEncryptionProvider() {
return new JWEEncryptionProvider() {
@Override
public String getAlgorithm() {
return "A256GCM"; // 暂时使用 A256GCM,后续可实现 SM4 特定算法
}
@Override
public byte[] encrypt(byte[] data, byte[] key, byte[] iv, byte[] aad) throws Exception {
// 使用 SM4 算法加密数据
return SM4Util.encrypt(key, data);
}
@Override
public byte[] decrypt(byte[] encryptedData, byte[] key, byte[] iv, byte[] aad) throws Exception {
// 使用 SM4 算法解密数据
return SM4Util.decrypt(key, encryptedData);
}
@Override
public int getKeyLength() {
return 16; // SM4 密钥长度为 16 字节
}
@Override
public int getIVLength() {
return 16; // SM4 IV 长度为 16 字节
}
};
}扩展其他国密算法
可以根据需要扩展其他国密算法,如 SM9(标识密码算法)等。
实现示例:
- 创建 SM9 工具类
java
public class SM9Util {
// SM9 算法实现
public static byte[] sign(byte[] privateKey, byte[] data) {
// 实现 SM9 签名
return new byte[0];
}
public static boolean verify(byte[] publicKey, byte[] data, byte[] signature) {
// 实现 SM9 签名验证
return false;
}
}- 创建 SM9 签名提供者
java
public class SM9SignatureProvider implements SignatureProvider {
@Override
public SignatureSignerContext signer(String algorithm, Key key) {
// 实现 SM9 签名器
return null;
}
@Override
public SignatureVerifierContext verifier(String algorithm, Key key) {
// 实现 SM9 验证器
return null;
}
@Override
public void close() {
// 清理资源
}
}- 创建 SM9 签名提供者工厂
java
public class SM9SignatureProviderFactory implements SignatureProviderFactory {
public static final String ID = "bima-sm9-signature";
@Override
public String getId() {
return ID;
}
@Override
public SignatureProvider create(KeycloakSession session) {
return new SM9SignatureProvider();
}
@Override
public void init(Config.Scope config) {
// 初始化配置
}
@Override
public void postInit(KeycloakSessionFactory factory) {
// 后初始化
}
@Override
public void close() {
// 清理资源
}
}- 注册服务
在 META-INF/services/org.keycloak.crypto.SignatureProviderFactory 文件中添加:
cc.bima.keycloak.extension.sm.SM9SignatureProviderFactory优化现有实现
1. 性能优化
SM3Util 优化示例:
java
public class SM3Util {
static {
// 注册 Bouncy Castle 提供者
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
// 线程本地变量,避免重复创建 SM3Digest 对象
private static final ThreadLocal<SM3Digest> digestThreadLocal = ThreadLocal.withInitial(SM3Digest::new);
public static byte[] digest(byte[] data) {
try {
SM3Digest digest = digestThreadLocal.get();
digest.reset(); // 重置摘要对象
digest.update(data, 0, data.length);
byte[] result = new byte[digest.getDigestSize()];
digest.doFinal(result, 0);
return result;
} catch (Exception e) {
throw new RuntimeException("SM3 digest failed", e);
}
}
}2. 安全性增强
SM4Util 安全性增强示例:
java
public class SM4Util {
// 使用安全的随机数生成器
private static final SecureRandom secureRandom = new SecureRandom();
public static byte[] generateKey() {
byte[] key = new byte[16];
secureRandom.nextBytes(key);
return key;
}
public static byte[] encrypt(byte[] key, byte[] data) {
try {
// 使用 CCM 模式增强安全性
SM4Engine engine = new SM4Engine();
CCMParameters params = new CCMParameters(new KeyParameter(key), 128);
engine.init(true, params);
byte[] encrypted = new byte[engine.getOutputSize(data.length)];
int len = engine.processBytes(data, 0, data.length, encrypted, 0);
engine.doFinal(encrypted, len);
return encrypted;
} catch (Exception e) {
throw new RuntimeException("SM4 encryption failed", e);
}
}
public static byte[] decrypt(byte[] key, byte[] encryptedData) {
try {
SM4Engine engine = new SM4Engine();
CCMParameters params = new CCMParameters(new KeyParameter(key), 128);
engine.init(false, params);
byte[] decrypted = new byte[engine.getOutputSize(encryptedData.length)];
int len = engine.processBytes(encryptedData, 0, encryptedData.length, decrypted, 0);
engine.doFinal(decrypted, len);
return decrypted;
} catch (Exception e) {
throw new RuntimeException("SM4 decryption failed", e);
}
}
}代码结构
spi-sm-crypto-extension/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── cc/bima/keycloak/extension/sm/
│ │ │ ├── SM2Util.java # SM2 算法工具类
│ │ │ ├── SM3Util.java # SM3 算法工具类
│ │ │ ├── SM4Util.java # SM4 算法工具类
│ │ │ ├── SMContentEncryptionProvider.java # 内容加密提供者
│ │ │ ├── SMContentEncryptionProviderFactory.java # 内容加密提供者工厂
│ │ │ ├── SMHashProvider.java # 哈希提供者
│ │ │ ├── SMHashProviderFactory.java # 哈希提供者工厂
│ │ │ ├── SMKeyProvider.java # 密钥提供者
│ │ │ ├── SMKeyProviderFactory.java # 密钥提供者工厂
│ │ │ ├── SMSignatureProvider.java # 签名提供者
│ │ │ ├── SMSignatureProviderFactory.java # 签名提供者工厂
│ │ │ ├── SMSignatureSignerContext.java # 签名上下文
│ │ │ └── SMSignatureVerifierContext.java # 签名验证上下文
│ │ └── resources/
│ │ └── META-INF/
│ │ └── services/
│ │ ├── org.keycloak.crypto.ContentEncryptionProviderFactory # 内容加密提供者服务配置
│ │ ├── org.keycloak.crypto.HashProviderFactory # 哈希提供者服务配置
│ │ ├── org.keycloak.crypto.SignatureProviderFactory # 签名提供者服务配置
│ │ └── org.keycloak.keys.KeyProviderFactory # 密钥提供者服务配置
│ └── test/
│ └── java/
│ └── cc/bima/keycloak/extension/sm/ # 测试代码
└── pom.xml # Maven 配置文件部署与维护
1. 部署方式
1.1 标准部署
将编译好的 JAR 文件放入 Keycloak 的 standalone/deployments 目录,Keycloak 会自动部署该扩展。
1.2 Docker 部署
如果使用 Docker 运行 Keycloak,可以将扩展 JAR 文件和 Bouncy Castle JAR 文件复制到容器中。
Dockerfile 示例:
dockerfile
FROM quay.io/keycloak/keycloak:17.0.0
# 复制 Bouncy Castle JAR 文件
COPY bcprov-jdk15on-1.68.jar /opt/keycloak/standalone/lib/
COPY bcpkix-jdk15on-1.68.jar /opt/keycloak/standalone/lib/
# 复制国密算法扩展 JAR 文件
COPY spi-sm-crypto-extension-1.0.0.jar /opt/keycloak/standalone/deployments/
ENV KEYCLOAK_ADMIN=admin
ENV KEYCLOAK_ADMIN_PASSWORD=admin
ENTRYPOINT ["/opt/keycloak/bin/kc.sh", "start-dev"]2. 监控与日志
2.1 日志配置
在 Keycloak 的 standalone/configuration/standalone.xml 文件中,可以配置日志级别:
xml
<logger category="cc.bima.keycloak.extension.sm" level="info"/>2.2 监控指标
可以通过 Keycloak 的管理 API 或 JMX 监控扩展的运行状态。
3. 故障排除
3.1 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 扩展未加载 | Bouncy Castle 库未正确部署 | 确保 Bouncy Castle JAR 文件已放入 Keycloak 的 standalone/lib 目录 |
| SM3 哈希算法未生效 | 未在 Keycloak 管理控制台中配置 | 登录管理控制台,在密码策略中选择 "bima-sm-hash" |
| SM2 签名失败 | 密钥配置错误 | 检查密钥配置是否正确,确保使用的是 SM2 密钥 |
| SM4 加密未生效 | 未实现完整的 JWE 加密提供者 | 实现 SMContentEncryptionProvider.jweEncryptionProvider() 方法 |
性能优化
- 缓存机制:对常用的加密对象(如 SM3Digest)使用线程本地变量或对象池,避免重复创建
- 批处理:对批量数据进行处理时,使用单次哈希计算而非多次调用
- 并行处理:对大量数据的加密或哈希计算,考虑使用并行处理
- 密钥管理:使用密钥缓存,避免频繁加载密钥
- 算法优化:根据具体使用场景选择合适的加密模式和参数
注意事项
- Bouncy Castle 库版本:确保使用与国密算法实现兼容的 Bouncy Castle 版本,建议使用 1.68 或更高版本
- 密钥长度和加密模式:生产环境中应根据安全要求配置适当的密钥长度和加密模式
- 性能测试:建议对国密算法的使用进行性能测试,确保满足业务需求
- 合规性:遵循国家密码管理相关规定,确保算法使用符合要求
- 安全性:定期更新密钥,使用安全的随机数生成器,避免密钥泄露
- 兼容性:注意 Keycloak 版本与扩展版本的兼容性,避免因版本不匹配导致的问题
- 备份:定期备份密钥材料,防止密钥丢失
- 审计:对加密操作进行审计,记录关键的加密/解密操作
- 测试:在生产环境部署前,进行充分的测试,确保国密算法的正确实现
- 文档:维护详细的文档,记录密钥管理流程和算法使用情况
免责声明
本项目基于 GitHub 开源软件进行定制化开发,旨在为企业和开发者提供更便捷的项目基座解决方案。使用本项目时,请务必了解以下免责声明:
- 开源基础:本项目基于 GitHub 开源软件构建,遵循原开源协议的相关规定。
- 定制开发:我们对原开源软件进行了定制和扩展,以提供更优质的开发体验和功能支持。
- 责任限制:对于使用本项目可能产生的任何直接或间接的经济损失、数据丢失或其他问题,北京必码科技工作室不承担任何责任。
- 使用建议:在生产环境中使用本项目前,请进行充分的测试和验证,确保其符合您的业务需求和安全要求。
- 技术支持:我们提供技术支持服务,但不保证解决所有可能出现的问题。
- 合规使用:用户应确保在使用本项目时遵守相关法律法规和行业规范,不得用于任何违法或违规用途。