BouncyCastle的SM实践#
一、按照pdf配置环境#
配置好后代码大致结构如图所示:
二、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); } }
测试结果:#
四、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); } }
测试结果:#
五、小缺陷#
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