sm4加密

前言

项目里需要用到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解密失败");
      }
   }
}
原文地址:https://www.cnblogs.com/wmg92/p/13667567.html