zoukankan      html  css  js  c++  java
  • BouncyCastle的SM实践

    BouncyCastle的SM实践

    一、按照pdf配置环境

    配置好后代码大致结构如图所示:

    SM2

    二、SM2

    按照PDF实践即可,效果如上图所示

    需要小改以下demo文件

    package BC;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import java.security.*;
    import java.security.spec.ECGenParameterSpec;
    public class sm2_demo {
        private static String test="lzc_SM2_demo";
        public static void main(String[] args) throws NoSuchAlgorithmException,
                InvalidAlgorithmParameterException {
            SM2Util sm2 = new SM2Util();
            final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
    // 获取一个椭圆曲线类型的密钥对生成器
            final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", new
                    BouncyCastleProvider());
    // 使用SM2参数初始化生成器
            kpg.initialize(sm2Spec);
    // 获取密钥对
            KeyPair keyPair = kpg.generateKeyPair();
            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();
            String data = sm2.encrypt(publicKey,test);
            System.out.println("明文:"+test);
            System.out.println("密文:"+data);
            String text=sm2.decrypt(privateKey,data);
            System.out.println("解密结果:"+text);
        }
    }
    

    三、SM3

    参考博客Java国密相关算法(bouncycastle) - alsodzy - 博客园 (cnblogs.com)

    SM3代码如下:

    package GM_test;
    
    
    import org.bouncycastle.crypto.digests.SM3Digest;
    import org.bouncycastle.crypto.macs.HMac;
    import org.bouncycastle.crypto.params.KeyParameter;
    import org.bouncycastle.util.encoders.Hex;
    
    import java.nio.charset.StandardCharsets;
    import java.security.MessageDigest;
    
    /**
     * @Author: dzy
     * @Date: 2018/10/19 16:36
     * @Describe: SM3工具类(杂凑算法-hash算法)
     */
    
    public class SM3Util {
    
        /**
         * 16进制字符串SM3生成HASH签名值算法
         * @param hexString     16进制字符串
         * @return
         */
        public static String hexEncrypt(String hexString) {
            byte[] srcData = Hex.decode(hexString);
            byte[] encrypt = encrypt(srcData);
            String cipherStr  = Hex.toHexString(encrypt);
            return cipherStr;
        }
    
        /**
         * 16进制字符串SM3生成HASH签名值算法
         * @param hexKey        16进制密钥
         * @param hexString     16进制字符串
         * @return
         */
        public static String hexEncrypt(String hexKey, String hexString) {
            byte[] key = Hex.decode(hexKey);
            byte[] srcData = Hex.decode(hexString);
            byte[] encrypt = encrypt(key, srcData);
            String cipherStr  = Hex.toHexString(encrypt);
            return cipherStr;
        }
    
        /**
         * 普通文本SM3生成HASH签名算法
         * @param plain     待签名数据
         * @return
         */
        public static String plainEncrypt(String plain) {
            // 将返回的hash值转换成16进制字符串
            String cipherStr = null;
            try {
                //将字符串转换成byte数组
                byte[] srcData = plain.getBytes(StandardCharsets.UTF_8);
                //调用encrypt计算hash
                byte[] encrypt = encrypt(srcData);
                //将返回的hash值转换成16进制字符串
                cipherStr = Hex.toHexString(encrypt);
            } catch (Exception e) {
                //log.error("将字符串转换为字节时出现异常:", e);
            }
            return cipherStr;
        }
    
        /**
         * 普通文本SM3生成HASH签名算法
         * @param hexKey        密钥
         * @param plain         待签名数据
         * @return
         */
        public static String plainEncrypt(String hexKey, String plain) {
            // 将返回的hash值转换成16进制字符串
            String cipherStr = null;
            try {
                //将字符串转换成byte数组
                byte[] srcData = plain.getBytes(StandardCharsets.UTF_8);
                //密钥
                byte[] key = Hex.decode(hexKey);
                //调用encrypt计算hash
                byte[] encrypt = encrypt(key, srcData);
                //将返回的hash值转换成16进制字符串
                cipherStr = Hex.toHexString(encrypt);
            } catch (Exception e) {
                //log.error("将字符串转换为字节时出现异常:", e);
            }
            return cipherStr;
        }
    
        /**
         * SM3计算hashCode
         * @param srcData   待计算数据
         * @return
         */
        public static byte[] encrypt(byte[] srcData) {
            SM3Digest sm3Digest = new SM3Digest();
            sm3Digest.update(srcData, 0, srcData.length);
            byte[] encrypt = new byte[sm3Digest.getDigestSize()];
            sm3Digest.doFinal(encrypt, 0);
            return encrypt;
        }
    
        /**
         * 通过密钥进行加密
         * @param key       密钥byte数组
         * @param srcData   被加密的byte数组
         * @return
         */
        public static byte[] encrypt(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;
        }
    
        /**
         * SM3计算hashCode
         * @param srcData   待计算数据
         * @return
         * @throws Exception
         */
        public static byte[] encrypt_0(byte[] srcData) throws Exception {
            MessageDigest messageDigest = MessageDigest.getInstance("SM3", "BC");
            byte[] digest = messageDigest.digest(srcData);
            return digest;
        }
    
    }
    

    SM3测试代码:

    package GM_test;
    
    
    import GM_test.SM3Util;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import java.security.*;
    import java.security.spec.ECGenParameterSpec;
    public class sm3_demo {
        private static String test="lzc_SM3_demo";
        public static void main(String[] args) throws NoSuchAlgorithmException,
                InvalidAlgorithmParameterException {
            SM3Util sm3 = new SM3Util();
            String data = sm3.plainEncrypt(test);
            System.out.println("明文:"+test);
            System.out.println("哈希值:"+data);
        }
    }
    

    测试结果:

    SM3

    四、SM4

    参考博客Java国密相关算法(bouncycastle) - alsodzy - 博客园 (cnblogs.com)

    SM4代码如下:

    package GM_test;
    
    import org.bouncycastle.crypto.engines.SM4Engine;
    import org.bouncycastle.crypto.params.KeyParameter;
    import org.bouncycastle.util.encoders.Hex;
    
    /**
     * @Author: dzy
     * @Date: 2018/10/9 16:41
     * @Describe: SM4算法
     */
    public class SM4Util {
    
        //加解密的字节快大小
        public static final int BLOCK_SIZE = 16;
    
        /**
         * SM4ECB加密算法
         * @param in            待加密内容
         * @param keyBytes      密钥
         * @return
         */
        public static byte[] encryptByEcb0(byte[] in, byte[] keyBytes) {
            SM4Engine sm4Engine = new SM4Engine();
            sm4Engine.init(true, new KeyParameter(keyBytes));
            int inLen = in.length;
            byte[] out = new byte[inLen];
    
            int times = inLen / BLOCK_SIZE;
    
            for (int i = 0; i < times; i++) {
                sm4Engine.processBlock(in, i * BLOCK_SIZE, out, i * BLOCK_SIZE);
            }
    
            return out;
        }
    
        /**
         * SM4ECB加密算法
         * @param in            待加密内容
         * @param keyBytes      密钥
         * @return
         */
        public static String encryptByEcb(byte[] in, byte[] keyBytes) {
            byte[] out = encryptByEcb0(in, keyBytes);
            String cipher = Hex.toHexString(out);
            return cipher;
        }
    
        /**
         * SM4的ECB加密算法
         * @param content   待加密内容
         * @param key       密钥
         * @return
         */
        public static String encryptByEcb(String content, String key) {
            byte[] in = Hex.decode(content);
            byte[] keyBytes = Hex.decode(key);
    
            String cipher = encryptByEcb(in, keyBytes);
            return cipher;
        }
    
        /**
         * SM4的ECB解密算法
         * @param in        密文内容
         * @param keyBytes  密钥
         * @return
         */
        public static byte[] decryptByEcb0(byte[] in, byte[] keyBytes) {
            SM4Engine sm4Engine = new SM4Engine();
            sm4Engine.init(false, new KeyParameter(keyBytes));
            int inLen = in.length;
            byte[] out = new byte[inLen];
    
            int times = inLen / BLOCK_SIZE;
    
            for (int i = 0; i < times; i++) {
                sm4Engine.processBlock(in, i * BLOCK_SIZE, out, i * BLOCK_SIZE);
            }
    
            return out;
        }
    
        /**
         * SM4的ECB解密算法
         * @param in        密文内容
         * @param keyBytes  密钥
         * @return
         */
        public static String decryptByEcb(byte[] in, byte[] keyBytes) {
            byte[] out = decryptByEcb0(in, keyBytes);
            String plain = Hex.toHexString(out);
            return plain;
        }
    
        /**
         * SM4的ECB解密算法
         * @param cipher    密文内容
         * @param key       密钥
         * @return
         */
        public static String decryptByEcb(String cipher, String key) {
            byte[] in = Hex.decode(cipher);
            byte[] keyBytes = Hex.decode(key);
    
            String plain = decryptByEcb(in, keyBytes);
            return plain;
        }
    
        public static String strToHexadecimal(String str) {
            char[] chars = "0123456789ABCDEF".toCharArray();
            StringBuilder sb = new StringBuilder("");
            byte[] bs = str.getBytes();
            int bit;
            for (int i = 0; i < bs.length; i++) {
                bit = (bs[i] & 0x0f0) >> 4;
                sb.append(chars[bit]);
                bit = bs[i] & 0x0f;
                sb.append(chars[bit]);
            }
            return sb.toString().trim();
        }
    
        public static String hexadecimalToStr(String hexStr) {
            String str = "0123456789ABCDEF";
            char[] hexs = hexStr.toCharArray();
            byte[] bytes = new byte[hexStr.length() / 2];
            int n;
            for (int i = 0; i < bytes.length; i++) {
                n = str.indexOf(hexs[2 * i]) * 16;
                n += str.indexOf(hexs[2 * i + 1]);
                bytes[i] = (byte) (n & 0xff);
            }
            return new String(bytes);
        }
    }
    
    

    SM4测试代码:

    package GM_test;
    
    
    import GM_test.SM4Util;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.bouncycastle.util.encoders.Hex;
    
    import java.security.*;
    import java.security.spec.ECGenParameterSpec;
    public class sm4_demo {
        private static String test= "lzc_SM4_demonmsl";
        private static String mykey= "6cef39eb85614df44f6b0f6bbbdd89b6";
        public static void main(String[] args) throws NoSuchAlgorithmException,
                InvalidAlgorithmParameterException {
            SM4Util sm4 = new SM4Util();
            //SM3Util sm3 = new SM3Util();
            //String data_in = sm3.plainEncrypt(test);
            //String data = sm4.encryptByEcb(data_in,mykey);
            String x16 = sm4.strToHexadecimal(test);
            //System.out.println(x16);
            String data = sm4.encryptByEcb(x16,mykey);
            System.out.println("明文:"+test);
            //System.out.println("摘   要:"+data_in);
            System.out.println("密文:"+data);
            String text_16 = sm4.decryptByEcb(data,mykey);
            //System.out.println(text_16);
            //System.out.println(x16.equals(text_16.toUpperCase()));
            String text = sm4.hexadecimalToStr(text_16.toUpperCase());
            System.out.println("解密结果:"+text);
        }
    }
    

    测试结果:

    SM4

    五、小缺陷

    SM4有一个小问题:字符串的长度需要满足是16的倍数(>=1),应该是分组的问题,需要增加两个模块,一个用于补全输入使其满足16的倍数,另一个负责将输出的结果删除填充的内容,恢复真正的明文,这个功能的实现并不难,相信聪明的你已经想到了解决的办法,快去动手实践吧。

    源代码链接 提取码:NMSL

  • 相关阅读:
    MongoDB-JAVA-Driver 3.2版本常用代码全整理(4)
    MongoDB-JAVA-Driver 3.2版本常用代码全整理(3)
    MongoDB-JAVA-Driver 3.2版本常用代码全整理(2)
    MongoDB-JAVA-Driver 3.2版本常用代码全整理(1)
    c++清除输入缓冲区之 sync() vs ignore()
    typedef 类型重命名 和 #define 宏定义(1)
    从gcc的__attribute__((packed))聊到结构体大小的问题
    对于volatile的理解
    把一个string串的所有小写字母转成大写字母的例子来看看看全局函数的使用
    string与char* 互相转换以及周边问题
  • 原文地址:https://www.cnblogs.com/wqnmlkb/p/14826688.html
Copyright © 2011-2022 走看看