前言
项目里需要用到sm4加密,在这里记录一下(springboot)。
依赖
bouncycastle
<!-- 一个开源的加解密算法包 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcmail-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<!-- 实用工具相关,这里主要用了里面的hexUtil,也可以自己封装 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.1</version>
</dependency>
代码
直接贴代码,可以根据自己的需要封装相对应的代码逻辑。
//需要注意的是,使用KeyGenerator生成密钥种子的时候,windows和linux上会产生不一致。
//例如:
KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, PROVIDER_NAME);
SecureRandom random = new SecureRandom();
if(null != seed && !"".equals(seed)){
random.setSeed(seed.getBytes());
}
kg.init(keySize, random);
//解决办法
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
import cn.hutool.core.util.HexUtil;
import com.spinfo.common.constants.UserConstants;
import com.spinfo.controller.UserController;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.DigestUtils;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.util.Arrays;
public class SM4Util {
private static Logger logger = LoggerFactory.getLogger(SM4Util.class);
private static final String PROVIDER_NAME = "BC";
public static final String ALGORITHM_NAME = "SM4";
public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding";
public static final String ALGORITHM_NAME_CBC_PADDING = "SM4/CBC/PKCS5Padding";
public static final String DEFAULT_KEY = "random_seed";
public static final int DEFAULT_KEY_SIZE = 128;
private static final int ENCRYPT_MODE = 1;
private static final int DECRYPT_MODE = 2;
static {
Security.addProvider(new BouncyCastleProvider());
}
public static byte[] generateKey() throws NoSuchAlgorithmException, NoSuchProviderException {
return generateKey(DEFAULT_KEY, DEFAULT_KEY_SIZE);
}
public static byte[] generateKey(String seed) throws NoSuchAlgorithmException, NoSuchProviderException {
return generateKey(seed, DEFAULT_KEY_SIZE);
}
public static byte[] generateKey(String seed, int keySize) throws NoSuchAlgorithmException, NoSuchProviderException {
KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, PROVIDER_NAME);
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
if(null != seed && !"".equals(seed)){
random.setSeed(seed.getBytes());
}
kg.init(keySize, random);
return kg.generateKey().getEncoded();
}
/**
* ecb 加密
* @param key
* @param data
*/
public static byte[] encryptEcbPadding(byte[] key, byte[] data) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = generateEcbCipher(ENCRYPT_MODE, key);
return cipher.doFinal(data);
}
/**
* ecb 解密
* @param key
* @param cipherText
*/
public static byte[] decryptEcbPadding(byte[] key, byte[] cipherText) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException {
Cipher cipher = generateEcbCipher(DECRYPT_MODE, key);
return cipher.doFinal(cipherText);
}
/**
* cbc 加密
* @param key
* @param data
*/
public static byte[] encryptCbcPadding(byte[] key, byte[] iv, byte[] data) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
Cipher cipher = generateCbcCipher(ENCRYPT_MODE, key, iv);
return cipher.doFinal(data);
}
public static String encryptCbcPaddingString(byte[] key, byte[] iv, byte[] data) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
Cipher cipher = generateCbcCipher(ENCRYPT_MODE, key, iv);
byte[] result = cipher.doFinal(data);
return Base64.toBase64String(result);
}
/**
* cbc 解密
* @param key
* @param iv
* @param cipherText
*/
public static byte[] decryptCbcPadding(byte[] key, byte[] iv, String cipherText) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidAlgorithmParameterException {
byte[] cipherBytes = Base64.decode(cipherText);
Cipher cipher = generateCbcCipher(DECRYPT_MODE, key, iv);
return cipher.doFinal(cipherBytes);
}
public static byte[] decryptCbcPadding(byte[] key, byte[] iv, byte[] cipherText) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidAlgorithmParameterException {
Cipher cipher = generateCbcCipher(DECRYPT_MODE, key, iv);
return cipher.doFinal(cipherText);
}
/**
* ecb cipher
* @param mode
* @param key
* @return
*/
private static Cipher generateEcbCipher(int mode, byte[] key) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException {
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME_ECB_PADDING, PROVIDER_NAME);
Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
cipher.init(mode, sm4Key);
return cipher;
}
/**
* cbc cipher
* @param mode
* @param key
* @return
*/
private static Cipher generateCbcCipher(int mode, byte[] key, byte[] iv) throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException {
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME_CBC_PADDING, PROVIDER_NAME);
Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
cipher.init(mode, sm4Key, ivParameterSpec);
return cipher;
}
/**
* ecb 加密 times 次
* @param data
* @param salt
* @param times
* @return=
*/
public static String encryptEcbDataTimes(String data, String salt, int times) throws GeneralSecurityException {
try {
byte[] key = HexUtil.decodeHex(salt);
byte[] bytes = data.getBytes();
for(int i = 0; i < times; ++i) {
bytes = encryptEcbPadding(key, bytes);
}
data = Base64.toBase64String(bytes);
return data;
} catch (BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException | NoSuchProviderException | NoSuchAlgorithmException | InvalidKeyException var5) {
throw new GeneralSecurityException("SM4加密失败");
}
}
/**
* ecb 解密 times 次
* @param data
* @param salt
* @param times
* @return
* @throws GeneralSecurityException
*/
public static String decryptEcbDataTimes(String data, String salt, int times) throws GeneralSecurityException {
try {
byte[] bytes = Base64.decode(data);
byte[] key = HexUtil.decodeHex(salt);
for(int i = 0; i < times; ++i) {
bytes = decryptEcbPadding(key, bytes);
}
data = new String(bytes);
return data;
} catch (BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException | NoSuchProviderException | NoSuchAlgorithmException | InvalidKeyException var5) {
throw new GeneralSecurityException("SM4解密失败");
}
}
/**
* cbc 加密 times 次
* @param data
* @param salt
* @param times
* @return=
*/
public static String encryptCbcDataTimes(String data, String salt, int times) {
try {
byte[] iv = generateKey();
byte[] key = generateKey(salt);
byte[] bytes = data.getBytes();
Cipher cipher = generateCbcCipher(ENCRYPT_MODE, key, iv);
for(int i = 0; i < times; ++i) {
bytes = cipher.doFinal(bytes);
}
data = Base64.toBase64String(bytes);
return data;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* cbc 解密 times 次
* @param data
* @param salt
* @param times
* @return
* @throws GeneralSecurityException
*/
public static String decryptCbcDataTimes(String data, String salt, int times) throws GeneralSecurityException {
try {
byte[] iv = generateKey();
byte[] bytes = Base64.decode(data);
byte[] key = generateKey(salt);
Cipher cipher = generateCbcCipher(ENCRYPT_MODE, key, iv);
for(int i = 0; i < times; ++i) {
bytes = cipher.doFinal(bytes);
}
data = new String(bytes);
return data;
} catch (BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException | NoSuchProviderException | NoSuchAlgorithmException | InvalidKeyException var5) {
throw new GeneralSecurityException("SM4解密失败");
}
}
}