BouncyCastle的SM实践#

一、按照pdf配置环境#

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

image.png

二、SM2#

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

需要小改以下demo文件

Copypackage 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代码如下:#

Copypackage 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测试代码:#

Copypackage 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);
    }
}

测试结果:#

image.png

四、SM4#

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

SM4代码如下:#

Copypackage 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测试代码:#

Copypackage 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);
    }
}

测试结果:#

image.png

五、小缺陷#

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

转自:https://www.cnblogs.com/wqnmlkb/p/14826688.html#sm4%E4%BB%A3%E7%A0%81%E5%A6%82%E4%B8%8B