目錄
BouncyCastle的SM實踐
一、按照pdf配置環境
配置好后代碼大致結構如圖所示:
二、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);
}
}
測試結果:
四、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有一個小問題:字符串的長度需要滿足是16的倍數(>=1),應該是分組的問題,需要增加兩個模塊,一個用於補全輸入使其滿足16的倍數,另一個負責將輸出的結果刪除填充的內容,恢復真正的明文,這個功能的實現並不難,相信聰明的你已經想到了解決的辦法,快去動手實踐吧。
源代碼鏈接 提取碼:NMSL