172 lines
5.5 KiB
Java
172 lines
5.5 KiB
Java
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 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 javax.crypto.BadPaddingException;
|
|
import javax.crypto.Cipher;
|
|
import javax.crypto.IllegalBlockSizeException;
|
|
import javax.crypto.NoSuchPaddingException;
|
|
import java.security.*;
|
|
|
|
|
|
/**
|
|
* 基于 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 extends AbstractSdfApiService {
|
|
|
|
public BCSdfApiService() {
|
|
super();
|
|
}
|
|
|
|
@Override
|
|
public byte[] generateRandom(int len) {
|
|
byte[] res = new byte[len];
|
|
new SecureRandom().nextBytes(res);
|
|
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() {
|
|
// 生成密钥对
|
|
KeyPair keyPair = BCSM2Utils.generateKeyPair();
|
|
BCECPublicKey pubKey = (BCECPublicKey) keyPair.getPublic();
|
|
BCECPrivateKey priKey = (BCECPrivateKey) keyPair.getPrivate();
|
|
byte[] x = pubKey.getQ().getXCoord().getEncoded();
|
|
byte[] y = pubKey.getQ().getYCoord().getEncoded();
|
|
byte[] d = BigIntegers.asUnsignedByteArray(32, priKey.getD());
|
|
return new EccKey(LangUtils.merge(x, y), d);
|
|
}
|
|
|
|
|
|
@Override
|
|
public byte[] calculateMAC(byte[] symKey, byte[] pucIv, byte[] pucData) {
|
|
return new byte[0];
|
|
}
|
|
|
|
@Override
|
|
public byte[] hmac(byte[] key, byte[] srcData) {
|
|
return BCSM3Utils.hmac(key, srcData);
|
|
}
|
|
|
|
@Override
|
|
public byte[] hash(byte[] pucData) {
|
|
return BCSM3Utils.hash(pucData);
|
|
}
|
|
|
|
@Override
|
|
public byte[] encryptByTMK(byte[] data) {
|
|
return data;
|
|
}
|
|
|
|
@Override
|
|
public byte[] decryptByTMK(byte[] data) {
|
|
return data;
|
|
}
|
|
|
|
}
|