一、概述
- SM1-無具體實現
SM1作為一種對稱加密算法,由于其算法細節并未公開,且主要在中國國內使用,因此在國際通用的加密庫(如Bouncy Castle)中并不直接支持SM1算法。
SM1算法的具體實現涉及國家密碼管理局的規范,通常需要使用國家指定的安全模塊(如SSF33、SC1/SC2卡)或通過國家認證的加密硬件/軟件產品來實現。
不過,如果你有合法授權并且在合規的環境下需要使用SM1算法,可能需要依賴特定的國產加密庫或SDK,比如某些商用的密碼機提供的SDK,這些SDK會封裝好SM1的加解密接口供開發者調用。
但具體的實現代碼和工具類因為涉及知識產權和國家安全規定,無法在這里直接提供。
- SM2
非對稱加密、簽名算法
加密 解密 加簽 驗簽可替換
RSA
- SM3
簽名算法 雜湊算法
加簽 驗簽可替換
MD5
等Hash算法
- SM4
對稱加解密密算法
加密 解密可替換
DES
- SM9-無具體實現
目前,標準的Java庫如Bouncy Castle并不直接支持SM9算法;
因此可能需要使用特定的國密算法支持庫或遵循國家密碼管理局推薦的實現;
準備-添加依賴
<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.64</version>
</dependency>
二、國密詳解
2.1 SM2實現
import org.bouncycastle.jce.provider.BouncyCastleProvider;import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.util.Base64;/*** SM2實現工具類*/
public class SM2Util {/** 這行代碼是在Java中用于向安全系統添加Bouncy Castle安全提供器的。* Bouncy Castle是一個流行的開源加密庫,它提供了許多密碼學算法和安全協議的實現。* 通過調用Security.addProvider并傳入BouncyCastleProvider對象,你可以注冊Bouncy Castle提供的安全服務和算法到Java的安全框架中。* 這樣一來,你就可以在你的應用程序中使用Bouncy Castle所提供的加密算法、密鑰生成和管理等功能。*/static {Security.addProvider(new BouncyCastleProvider());}public static KeyPair generateKeyPair() throws Exception {KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");keyPairGenerator.initialize(new ECGenParameterSpec("sm2p256v1"));return keyPairGenerator.generateKeyPair();}public static byte[] encrypt(PublicKey publicKey, byte[] data) throws Exception {Cipher cipher = Cipher.getInstance("SM2", "BC");cipher.init(Cipher.ENCRYPT_MODE, publicKey);return cipher.doFinal(data);}public static byte[] decrypt(PrivateKey privateKey, byte[] encryptedData) throws Exception {Cipher cipher = Cipher.getInstance("SM2", "BC");cipher.init(Cipher.DECRYPT_MODE, privateKey);return cipher.doFinal(encryptedData);}public static byte[] sign(PrivateKey privateKey, byte[] data) throws Exception {Signature signature = Signature.getInstance("SM3withSM2", "BC");signature.initSign(privateKey);signature.update(data);return signature.sign();}public static boolean verifySignature(PublicKey publicKey, byte[] data, byte[] signature) throws Exception {Signature sig = Signature.getInstance("SM3withSM2", "BC");sig.initVerify(publicKey);sig.update(data);return sig.verify(signature);}public static void main(String[] args) throws Exception {// 將公鑰私鑰字符串轉換為PublicKey和PrivateKey對象KeyPair keyPair = generateKeyPair();PublicKey publicKey = keyPair.getPublic();System.out.println("Public Key: " + Base64.getEncoder().encodeToString(publicKey.getEncoded()));PrivateKey privateKey = keyPair.getPrivate();System.out.printf("Private Key: " + Base64.getEncoder().encodeToString(privateKey.getEncoded()));// 待加密數據byte[] dataToEncrypt = "Hello, SM2!".getBytes();// 加密byte[] encryptedData = encrypt(publicKey, dataToEncrypt);System.out.println("Encrypted: " + Base64.getEncoder().encodeToString(encryptedData));// 解密byte[] decryptedData = decrypt(privateKey, encryptedData);System.out.println("Decrypted: " + new String(decryptedData));// 加簽byte[] signature = sign(privateKey, dataToEncrypt);System.out.println("Signature: " + Base64.getEncoder().encodeToString(signature));// 驗簽boolean isVerified = verifySignature(publicKey, dataToEncrypt, signature);System.out.println("Signature verified: " + isVerified);}}
2.2 SM3實現
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.util.encoders.Hex;/*** sm3工具類* 2024/6/25 16:29*/
public class SM3Util {/*** sm3簽名* @param signString 待簽名信息* @return 簽名*/public static String sign(String signString) {byte[] bytes = signString.getBytes();byte[] result = new byte[32];SM3Digest sm3 = new SM3Digest();sm3.update(bytes, 0, bytes.length);sm3.doFinal(result, 0);return Hex.toHexString(result);}
}
2.3 SM4實現
import org.bouncycastle.jce.provider.BouncyCastleProvider;import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Base64;public class SM4Util {/*** 加密算法*/public static final String ALGORITHM = "SM4";/*** 加密工作模式:GCM* 數據填充模式:PKCS5Padding*/public static final String ALGORITHM_MODEL_GCM_PADDING = "SM4/GCM/NoPadding";/*** 隨機數的長度*/public static final int NONCE_LENGTH = 128;static {// 添加Bouncy Castle providerSecurity.addProvider(new BouncyCastleProvider());}/*** 使用SM4-GCM模式加密** @param plainText 需要加密的內容* @param keyBytes 密鑰字節數組* @param ivBytes 初始化向量字節數組* @return 加密之后的內容* @throws Exception 加密過程中可能發生的異常*/public static String encryptWithGCM(String plainText, byte[] keyBytes, byte[] ivBytes) throws Exception {SecretKeySpec sm4Key = new SecretKeySpec(keyBytes, ALGORITHM);GCMParameterSpec ivSpec = new GCMParameterSpec(NONCE_LENGTH, ivBytes);Cipher cipher = Cipher.getInstance(ALGORITHM_MODEL_GCM_PADDING, "BC");cipher.init(Cipher.ENCRYPT_MODE, sm4Key, ivSpec);byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));return Base64.getEncoder().encodeToString(encryptedBytes);}/*** 使用SM4-GCM模式解密** @param cipherText 需要解密的內容* @param keyBytes 密鑰字節數組* @param ivBytes 初始化向量字節數據* @return 解密之后內容* @throws Exception 解密過程中可能發生的異常*/public static String decryptWithGCM(String cipherText, byte[] keyBytes, byte[] ivBytes) throws Exception {SecretKeySpec sm4Key = new SecretKeySpec(keyBytes, ALGORITHM);GCMParameterSpec ivSpec = new GCMParameterSpec(NONCE_LENGTH, ivBytes);Cipher cipher = Cipher.getInstance(ALGORITHM_MODEL_GCM_PADDING, "BC");cipher.init(Cipher.DECRYPT_MODE, sm4Key, ivSpec);byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(cipherText));return new String(decryptedBytes, StandardCharsets.UTF_8);}/*** 使用SecureRandom生成指定長度的密鑰或IV** @param length 密鑰或IV的長度(字節數)* @return 生成的隨機字節數組*/public static byte[] generateKey(int length) {SecureRandom secureRandom = new SecureRandom();byte[] bytes = new byte[length];secureRandom.nextBytes(bytes);return bytes;}/*** 生成指定長度的初始化向量(IV)** @param length IV的長度(字節數)* @return 生成的隨機字節數組*/public static byte[] generateIV(int length) {// IV的生成方式與密鑰相同,使用SecureRandomreturn generateKey(length);}public static void main(String[] args) throws Exception {String plainText = "1234測試567";// 使用隨機的byte[] key = generateKey(16);byte[] iv = generateIV(16);String cipherText1 = encryptWithGCM(plainText, key, iv);System.out.println("加密后:" + cipherText1);String decryptedText1 = decryptWithGCM(cipherText1, key, iv);System.out.println("解密后:" + decryptedText1);}
}
三、聚合工具類SMUtil
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;public abstract class SMUtil {/*** SM1作為一種對稱加密算法,由于其算法細節并未公開,且主要在中國國內使用,因此在國際通用的加密庫(如Bouncy Castle)中并不直接支持SM1算法。* SM1算法的具體實現涉及國家密碼管理局的規范,通常需要使用國家指定的安全模塊(如SSF33、SC1/SC2卡)或通過國家認證的加密硬件/軟件產品來實現。* 不過,如果你有合法授權并且在合規的環境下需要使用SM1算法,可能需要依賴特定的國產加密庫或SDK,比如某些商用的密碼機提供的SDK,這些SDK會封裝好SM1的加解密接口供開發者調用。* 但具體的實現代碼和工具類因為涉及知識產權和國家安全規定,無法在這里直接提供。**/abstract void sm1();/*** SM2生成 私鑰和公鑰* @return 私鑰和公鑰*/public static KeyPair sm2GenerateKeyPair() {try {return SM2Util.generateKeyPair();} catch (Exception e) {throw new RuntimeException(e);}}/*** sm2簽名* @param privateKey 私鑰* @param data 待簽名內容* @return 簽名*/public static String sm2Sign(PrivateKey privateKey, String data) {try {byte[] sign = SM2Util.sign(privateKey, data.getBytes(StandardCharsets.UTF_8));return Base64.getEncoder().encodeToString(sign);} catch (Exception e) {throw new RuntimeException(e);}}/*** sm2驗簽* @param publicKey 公鑰* @param data 待驗簽內容* @param sign 簽名* @return 是否驗簽通過*/public static boolean sm2VerifySign(PublicKey publicKey, String data, String sign) {try {return SM2Util.verifySignature(publicKey, data.getBytes(StandardCharsets.UTF_8), Base64.getDecoder().decode(sign));} catch (Exception e) {throw new RuntimeException(e);}}/*** sm2加密* @param publicKey 公鑰* @param data 待加密內容* @return 加密之后的內容*/public static String sm2Encrypt(PublicKey publicKey, String data) {try {byte[] encrypt = SM2Util.encrypt(publicKey, data.getBytes(StandardCharsets.UTF_8));return Base64.getEncoder().encodeToString(encrypt);} catch (Exception e) {throw new RuntimeException(e);}}/*** sm2解密* @param privateKey 私鑰* @param data 待解密內容* @return 解密之后的內容*/public static String sm2Decrypt(PrivateKey privateKey, String data) {try {byte[] decrypt = SM2Util.decrypt(privateKey, Base64.getDecoder().decode(data));return new String(decrypt, StandardCharsets.UTF_8);} catch (Exception e) {throw new RuntimeException(e);}}/*** sm3簽名* @param signString 待簽名信息* @return 簽名*/public static String sm3Sign(String signString) {return SM3Util.sign(signString);}/*** sm4加密* 使用傳輸的密鑰和初始化向量進行加密* @param plainText 需要加密的內容* @param key 密鑰 長度必須為16* @param iv 初始化向量 長度必須為16* @return 加密之后的內容* @throws Exception 加密過程中可能發生的異常*/public static String sm4Encrypt(String plainText, String key, String iv) throws Exception {return SM4Util.encryptWithGCM(plainText, key.getBytes(StandardCharsets.UTF_8), iv.getBytes(StandardCharsets.UTF_8));}/**** sm4解密* 使用傳輸的密鑰和初始化向量進行加密* @param plainText 需要加密的內容* @param key 密鑰 長度必須為16* @param iv 初始化向量 長度必須為16* @return 加密之后的內容* @throws Exception 加密過程中可能發生的異常*/public static String sm4Decrypt(String plainText, String key, String iv) throws Exception {return SM4Util.decryptWithGCM(plainText, key.getBytes(StandardCharsets.UTF_8), iv.getBytes(StandardCharsets.UTF_8));}/*** 目前,標準的Java庫如Bouncy Castle并不直接支持SM9算法;* 因此可能需要使用特定的國密算法支持庫或遵循國家密碼管理局推薦的實現;*/abstract void sm9();public static void main(String[] args) throws Exception {// sm2 演示// 生成密鑰對KeyPair keyPair = sm2GenerateKeyPair();System.out.println(keyPair.getPrivate());System.out.println(keyPair.getPublic());String x = sm2Sign(keyPair.getPrivate(), "12謝謝哈哈");System.out.println(sm2VerifySign(keyPair.getPublic(), "12謝謝哈哈", x));String y = sm2Encrypt(keyPair.getPublic(), "12謝謝哈哈");System.out.println(sm2Decrypt(keyPair.getPrivate(), y));// sm3 演示String s = sm3Sign("12謝謝哈哈");System.out.println(s);// sm4String key = "jsikjrblkwqb79ik";String iv = "1224567890998880";String sm4Encrypt = sm4Encrypt("123測試!@456",key, iv);System.out.println(sm4Encrypt);String sm4Decrypt = sm4Decrypt(sm4Encrypt, key, iv);System.out.println(sm4Decrypt);}
}