实现 BCSdfApiService 中 sm4 加解密接口
This commit is contained in:
@@ -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密钥对并输出
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user