实现 BCSdfApiService 中 sm4 加解密接口

This commit is contained in:
Cheney
2024-11-14 15:31:11 +08:00
parent b500a4e9cc
commit a98659f3a9
10 changed files with 482 additions and 17 deletions
@@ -0,0 +1,61 @@
package com.sunyard.chsm.sdf;
import com.sunyard.chsm.enums.AlgMode;
import com.sunyard.chsm.enums.KeyAlg;
import com.sunyard.chsm.enums.Padding;
import java.util.HashMap;
import java.util.Map;
import static com.sunyard.chsm.utils.gm.BCSM4Utils.DEFAULT_KEY_SIZE;
/**
* 实现 SdfApiService 接口中的通用逻辑
* 处理参数缺失时的默认参数,确保下层入参没有 null
* @author Cheney
*/
public abstract class AbstractSdfApiService implements SdfApiService {
private static final Map<KeyAlg, Integer> algKeyLen = new HashMap<>();
static {
algKeyLen.put( KeyAlg.SM4, DEFAULT_KEY_SIZE );
}
/**
* 处理算法的默认密钥长度
* @param alg 算法,只支持对称算法
* 密钥长度根据 alg 指定的算法自动选择。
* @return 密钥
*/
@Override
public byte[] genSymKey(KeyAlg alg) {
return genSymKey( alg, algKeyLen.get( alg ) );
}
/**
* 对称加密
* 内部实现和解密共用逻辑
* @param alg 算法,只支持对称算法
* @param key 密钥值,明文
* @param data 原始数据
*/
@Override
public byte[] symEncrypt(KeyAlg alg, byte[] key, byte[] data){
return symEncrypt( alg, AlgMode.ECB, Padding.PCKS5Padding, key, data );
}
/**
* 对称解密
* 内部实现和加密共用逻辑
* @param alg 算法,只支持对称算法
* @param key 密钥值,明文
* @param data 密文数据
*/
@Override
public byte[] symDecrypt(KeyAlg alg, byte[] key, byte[] data) {
return symDecrypt( alg, AlgMode.ECB, Padding.PCKS5Padding, key, data );
}
}
@@ -1,29 +1,50 @@
package com.sunyard.chsm.sdf;
import com.sunyard.chsm.enums.AlgMode;
import com.sunyard.chsm.enums.KeyAlg;
import com.sunyard.chsm.enums.KeyCategory;
import com.sunyard.chsm.enums.Padding;
import com.sunyard.chsm.sdf.model.EccKey;
import com.sunyard.chsm.sdf.util.LangUtils;
import com.sunyard.chsm.utils.gm.BCSM2Utils;
import com.sunyard.chsm.utils.gm.BCSM3Utils;
import com.sunyard.chsm.utils.gm.BCSM4Utils;
import lombok.SneakyThrows;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.util.BigIntegers;
import org.springframework.stereotype.Service;
import java.security.KeyPair;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
/**
* @author liulu
* 基于 BC 库的国密软算法实现
* 当前实现类的接口返回的对称密钥和私钥认为是明文,在上层 Service 进行使用和存储时的加密和解密运算。
* <p>
* 主密钥:
* - 生成。 软随机数。项目启动时不存在则自动生成。
* - 存储。 存储在 SC_PARAM_CONF 表, KEY 为 mk 的字段,值为固定的 48 字节,以 HEX 格式 96 字节存储。
* 前 16 字节为主密钥值,后 32 字节为主密钥值使用 SM3 计算的校验值。
* - 同步。基于数据库进行导入、导出、和备份、恢复。多台应用服务器连接同一个数据库,无需同步。
* - 使用。顶层密钥,用于保护其他存于数据的密钥。
*
* @author liulu 、Cheney
* @since 2024/10/23
*/
@Slf4j
@Service
public class BCSdfApiService implements SdfApiService {
public class BCSdfApiService extends AbstractSdfApiService {
public BCSdfApiService() {
super();
}
@Override
public byte[] generateRandom(int len) {
@@ -32,6 +53,82 @@ public class BCSdfApiService implements SdfApiService {
return res;
}
/**
* 生成对称算法密钥
*
* @param alg 算法,只支持对称算法
* @param keyLen 密钥长度(bit),只针对密钥长度可变的算法。
* 禁止传 null
* @return
*/
@Override
public byte[] genSymKey(KeyAlg alg, Integer keyLen) {
switch (alg) {
case SM4: {
if (null == keyLen || keyLen != BCSM4Utils.DEFAULT_KEY_SIZE) {
throw new IllegalArgumentException("Invalid key length: " + keyLen);
}
try {
return BCSM4Utils.generateKey();
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
throw new RuntimeException("算法实现错误", e);
}
}
default: {
throw new IllegalArgumentException("Unsupported algorithm: " + alg);
}
}
}
@Override
public byte[] symEncrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) {
return symCalc(Cipher.ENCRYPT_MODE, alg, mode, padding, key, data);
}
@Override
public byte[] symDecrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) {
return symCalc(Cipher.DECRYPT_MODE, alg, mode, padding, key, data);
}
/**
* 对称加解密的统一实现
*
* @param alg 算法,只支持对称算法
* @param key 密钥值,明文
* @param data 加密时明文数据,解密时为密文数据
*/
private byte[] symCalc(int cipherMode, KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data) {
if (alg.getCategory() != KeyCategory.SYM_KEY) {
throw new IllegalArgumentException("Must SYM_KEY, unsupported algorithm: " + alg);
}
// 算法
String algName = null;
if (alg == KeyAlg.SM4) {
algName = "SM4/";
} else {
throw new IllegalArgumentException("Unsupported algorithm: " + alg);
}
// 算法轮模式
algName += mode.getCode() + "/";
// 填充模式
algName += padding.getCode();
Cipher cipher = null;
try {
cipher = BCSM4Utils.generateECBCipher(algName, cipherMode, key);
return cipher.doFinal(data);
} catch (IllegalBlockSizeException | BadPaddingException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidKeyException e) {
throw new RuntimeException("算法执行错误", e);
}
}
@SneakyThrows
@Override
public EccKey genKeyPairEcc() {
@@ -53,14 +150,7 @@ public class BCSdfApiService implements SdfApiService {
@Override
public byte[] hmac(byte[] key, byte[] srcData) {
KeyParameter keyParameter = new KeyParameter(key);
SM3Digest digest = new SM3Digest();
HMac mac = new HMac(digest);
mac.init(keyParameter);
mac.update(srcData, 0, srcData.length);
byte[] result = new byte[mac.getMacSize()];
mac.doFinal(result, 0);
return result;
return BCSM3Utils.hmac(key, srcData);
}
@Override
@@ -1,8 +1,12 @@
package com.sunyard.chsm.sdf;
import com.sunyard.chsm.enums.AlgMode;
import com.sunyard.chsm.enums.KeyAlg;
import com.sunyard.chsm.enums.Padding;
import com.sunyard.chsm.sdf.model.EccKey;
/**
* @author liulu
* @since 2024/10/23
@@ -18,6 +22,44 @@ public interface SdfApiService {
*/
byte[] generateRandom(int len);
/**
* 生成对称密钥
* @param alg 算法,只支持对称算法
* @param keyLen 密钥长度(bit),只针对密钥长度可变的算法。
* 禁止传 null
* @return 对称密钥
*/
byte[] genSymKey(KeyAlg alg, Integer keyLen);
byte[] genSymKey(KeyAlg alg);
/**
* 对称加密
* @param alg 算法,只支持对称算法
* @param mode 轮模式
* @param padding 填充模式
* @param key 密钥值,明文
* @param data 原始数据
*/
byte[] symEncrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data);
byte[] symEncrypt(KeyAlg alg, byte[] key, byte[] data);
/**
* 对称解密
* @param alg 算法,只支持对称算法
* @param key 密钥值,明文
* @param mode 轮模式
* @param padding 填充模式
* @param data 密文数据
*/
byte[] symDecrypt(KeyAlg alg, AlgMode mode, Padding padding, byte[] key, byte[] data);
byte[] symDecrypt(KeyAlg alg, byte[] key, byte[] data);
/**
* 产生ECC密钥对并输出
*