前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SM4加密解密

SM4加密解密

原创
作者头像
bug专8
修改2021-02-04 10:00:24
3.3K2
修改2021-02-04 10:00:24
举报

1、SM4简介

https://baike.baidu.com/item/SM4.0/3901780

2、引入SM4的依赖包

pom.xml中增加SM4的依赖包。

代码语言:html
复制
<dependency>
   <groupId>org.bouncycastle</groupId>
   <artifactId>bcprov-jdk15on</artifactId>
   <version>1.59</version>
</dependency>

3、项目中使用

封装好SM4工具类,调用的代码很简单。

代码语言:java
复制
//身份证、手机号SM4加密存储
sysBfinfo.setLeaderIdcard(SM4Util.encryptEcb(SM4Util.hexKey,sysBfinfo.getLeaderIdcard()));
sysBfinfo.setPhone(SM4Util.encryptEcb(SM4Util.hexKey,sysBfinfo.getPhone()));
代码语言:java
复制
//身份证、手机号SM4解密
String leaderIdcard = SM4Util.decryptEcb(SM4Util.hexKey,sftSysBfinfoBo.getLeaderIdcard());
String phone = SM4Util.decryptEcb(SM4Util.hexKey,sftSysBfinfoBo.getPhone());

4、SM4Util工具类

代码语言:java
复制
import cn.hutool.core.util.HexUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.bouncycastle.util.encoders.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
/**
 * @author jiangdongping
 * @version v1.0
 * @ClassName: SM4Util
 * @date 2021/1/29  15:48
 */
public class SM4Util {

    private static Logger logger = LoggerFactory.getLogger(SM4Util.class);

    private static final String ENCODING = "UTF-8";
    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";
    // 128-32位16进制;256-64位16进制
    public static final int DEFAULT_KEY_SIZE = 128;
    private static final int ENCRYPT_MODE = 1;
    private static final int DECRYPT_MODE = 2;

    //固定的16进制密钥
    public static final String hexKey = "f2326ad437059c6a2283d5e94176dde8";

    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解密失败");
        }
    }

    /**
     * sm4加密
     * @explain 加密模式:ECB 密文长度不固定,会随着被加密字符串长度的变化而变化
     * @param hexKey 16进制密钥(忽略大小写)
     * @param paramStr 待加密字符串
     * @return 返回16进制的加密字符串
     */

    public static String encryptEcb(String hexKey, String paramStr) {
        try{
            byte[] keyData = ByteUtils.fromHexString(hexKey);
            byte[] srcData = paramStr.getBytes(ENCODING);
            //加密
            byte[] cipherArray = encryptEcbPadding(keyData, srcData);
            String cipherText = ByteUtils.toHexString(cipherArray);
            return cipherText;
        }catch (Exception e){
            logger.error(e.getMessage());
        }
        return paramStr;
    }

    /**
     * sm4解密
     * @explain 解密模式:采用ECB
     * @param hexKey 16进制密钥
     * @param cipherText 16进制的加密字符串(忽略大小写)
     * @return 解密后的字符串
     */
    public static String decryptEcb(String hexKey, String cipherText) {
        try{
            byte[] keyData = ByteUtils.fromHexString(hexKey);
            byte[] cipherData = ByteUtils.fromHexString(cipherText);
            //解密
            byte[] srcData = decryptEcbPadding(keyData, cipherData);
            String decryptStr = new String(srcData, ENCODING);
            return decryptStr;
        }catch (Exception e){
            logger.error(e.getMessage());
        }
        return cipherText;
    }

    /**
     * byte数组转换成16进制字符串
     * @param src
     * @return
     */
    public static String bytesToHexString(byte[] src){
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    public static void main(String[] args) {
        try{
            //随机的密钥
            String key = ByteUtils.toHexString(generateKey());
            System.out.println(key);
            String phone = "15680234351";
            //加密
            String encPhone = encryptEcb(key,phone);
            System.out.println(encPhone);
            //解密
            String decPhone = encryptEcb(key,phone);
            System.out.println(decryptEcb(key,decPhone));
        }catch (Exception e){
           logger.error(e.getMessage());
        }
    }
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、SM4简介
  • 2、引入SM4的依赖包
  • 3、项目中使用
  • 4、SM4Util工具类
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档