国密SM2/SM3算法
國密算法
國密算法
分類
1、SM1是一種分組加密算法
對稱加密算法中的分組加密算法,其分組長度、秘鑰長度都是128bit,算法安全保密強度跟 AES 相當,但是算法不公開,僅以IP核的形式存在于芯片中,需要通過加密芯片的接口進行調用。
采用該算法已經研制了系列芯片、智能IC卡、智能密碼鑰匙、加密卡、加密機等安全產品,廣泛應用于電子政務、電子商務及國民經濟的各個應用領域(包括國家政務通、警務通等重要領域)。
2、SM2是非對稱加密算法
它是基于橢圓曲線密碼的公鑰密碼算法標準,其秘鑰長度256bit,包含數字簽名、密鑰交換和公鑰加密,用于替換RSA/DH/ECDSA/ECDH等國際算法??梢詽M足電子認證服務系統等應用需求,由國家密碼管理局于2010年12月17號發布。
SM2采用的是ECC 256位的一種,其安全強度比RSA 2048位高,且運算速度快于RSA。
3、SM3是一種密碼雜湊算法
用于替代MD5/SHA-1/SHA-2等國際算法,適用于數字簽名和驗證、消息認證碼的生成與驗證以及隨機數的生成,可以滿足電子認證服務系統等應用需求,于2010年12月17日發布。
它是在SHA-256基礎上改進實現的一種算法,采用Merkle-Damgard結構,消息分組長度為512bit,輸出的摘要值長度為256bit。
4、SM4是分組加密算法
跟SM1類似,是我國自主設計的分組對稱密碼算法,用于替代DES/AES等國際算法。SM4算法與AES算法具有相同的密鑰長度、分組長度,都是128bit。于2012年3月21日發布,適用于密碼應用中使用分組密碼的需求。
5、SM7是一種分組加密算法
該算法沒有公開。SM7適用于非接IC卡應用包括身份識別類應用(門禁卡、工作證、參賽證),票務類應用(大型賽事門票、展會門票),支付與通卡類應用(積分消費卡、校園一卡通、企業一卡通、公交一卡通)。
6、SM9是基于標識的非對稱密碼算法
用橢圓曲線對實現的基于標識的數字簽名算法、密鑰交換協議、密鑰封裝機制和公鑰加密與解密算法,包括數字簽名生成算法和驗證算法,并給出了數字簽名與驗證算法及其相應的流程。并提供了相應的流程??梢蕴娲跀底肿C書的PKI/CA體系。
SM9主要用于用戶的身份認證。據新華網公開報道,SM9的加密強度等同于3072位密鑰的RSA加密算法,于2016年3月28日發布。
算法下載地址:http://www.scctc.org.cn/templates/Download/index.aspx?nodeid=71
規范
國標文檔中定義國密算法使用256位橢圓曲線;
原文摘抄:
SM2密文由C1、C2、C3三部分構成,如何對SM2密文進行編碼在已經公布的兩個標準中有所不同,在早期公布的《SM2橢圓曲線公鑰密碼算法 第4部分:公鑰加密算法》中,SM2密文中的三部分依次輸出,沒有采用如Tag-Length-Value形式的編碼,我們稱其為Plain編碼。在之后公布的GM/T國標中,SM2密文采用ASN.1/DER方式編碼。
SM3是國密密碼雜湊算法標準,由國家密碼管理局于2010年12月公布。SM3的輸出雜湊值長度為256比特(32字節),與國際標準SHA-256等長。SM3設計安全性為128比特,安全性與256比特橢圓曲線/SM2、SM4/SMS4、AES-128等同。
工具包BouncyCastle
Java標準庫提供了一系列常用的哈希算法。但如果我們要用的某種算法,Java標準庫沒有提供怎么辦,BouncyCastle就是一個提供了很多哈希算法和加密算法的第三方庫。它提供了Java標準庫沒有的一些算法。
安裝
方式一
動態安裝
引入包,
最新的包及jdk支持 可以戳 這里
使用時需要通過Security.addProvider(new BouncyCastleProvider())動態加載到jvm
方式二
靜態安裝
(1)去BouncyCastle官網下載provider的包,然后放入$JAVA_HOME\jre\lib\ext目錄下;
(2)修改配置文件
java8: %java_home%\jre\lib\security\java.security
java9+: %JAVA_HOME%\conf\security.
加入一行配置:
security.provider.按順序填數字=org.bouncycastle.jce.provider.BouncyCastleProvider
java代碼實現
SM2工具類
SM2KeyInfo.java
package com.tom.crypto;/*** @ClassName SM2KeyInfo* @Description 生成密鑰info* @Author tom*/ public class SM2KeyInfo {/**** BC庫使用的公鑰=64個字節+1個字節(04標志位),BC庫使用的私鑰=32個字節* SM2秘鑰的組成部分有 私鑰D 、公鑰X 、 公鑰Y , 他們都可以用長度為64的16進制的HEX串表示,* SM2公鑰并不是直接由X+Y表示 , 而是額外添加了一個頭,當啟用壓縮時:公鑰=有頭+公鑰X ,即省略了公鑰Y的部分*/private String publicKeyHex;private String privateKeyHex;private String pubX;private String pubY;public SM2KeyInfo() {}public String getPublicKeyHex() {return publicKeyHex;}public void setPublicKeyHex(String publicKeyHex) {this.publicKeyHex = publicKeyHex;}public String getPrivateKeyHex() {return privateKeyHex;}public void setPrivateKeyHex(String privateKeyHex) {this.privateKeyHex = privateKeyHex;}public String getPubX() {return pubX;}public void setPubX(String pubX) {this.pubX = pubX;}public String getPubY() {return pubY;}public void setPubY(String pubY) {this.pubY = pubY;}@Overridepublic String toString() {final StringBuffer sb = new StringBuffer("SM2KeyInfo{");sb.append("publicKeyHex='").append(publicKeyHex).append('\'');sb.append(", privateKeyHex='").append(privateKeyHex).append('\'');sb.append(", pubX='").append(pubX).append('\'');sb.append(", pubY='").append(pubY).append('\'');sb.append('}');return sb.toString();} }SM2Util.java
package com.tom.crypto;import org.bouncycastle.asn1.gm.GMNamedCurves; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.engines.SM2Engine; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; import org.bouncycastle.jcajce.spec.SM2ParameterSpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.ECParameterSpec; import org.bouncycastle.jce.spec.ECPrivateKeySpec; import org.bouncycastle.jce.spec.ECPublicKeySpec; import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex;import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.*; import java.security.spec.ECGenParameterSpec;/*** Sm2算法工具類* 支持公鑰加密、私鑰解密 ,私鑰加簽 公鑰解簽* 收集網上資料整理:* 參考bouncycastle demo*/ public class SM2Utils {//橢圓曲線ECParameters ASN.1 結構,sm2P256V1代表國密SM2推薦參數定義的橢圓曲線private static X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");//橢圓曲線公鑰或私鑰的基本域參數。private static ECParameterSpec ecDomainParameters = new ECParameterSpec(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());//構造domain參數private static ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());/*** 生成密鑰對** @return*/public static KeyPair generateECKeyPair() {//使用標準名稱創建EC參數生成的參數規范final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");// 獲取一個橢圓曲線類型的密鑰對生成器final KeyPairGenerator kpg;try {kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());// 使用SM2算法域參數集初始化密鑰生成器(默認使用以最高優先級安裝的提供者的 SecureRandom 的實現作為隨機源)// 使用SM2的算法域參數集和指定的隨機源初始化密鑰生成器kpg.initialize(sm2Spec, new SecureRandom());// 通過密鑰生成器生成密鑰對KeyPair keyPair = kpg.generateKeyPair();return keyPair;} catch (Exception e) {e.printStackTrace();return null;}}/*** 生成密鑰相關信息** @return*/public static SM2KeyInfo generateSM2Key() {SM2KeyInfo sm2KeyInfo = new SM2KeyInfo();KeyPair keyPair = generateECKeyPair();PublicKey publicKey = keyPair.getPublic();if (publicKey instanceof BCECPublicKey) {//獲取65字節非壓縮縮的十六進制公鑰串(0x04)BCECPublicKey bcecPublicKey = (BCECPublicKey) publicKey;ECPoint ecPoint = bcecPublicKey.getQ();String publicKeyHex = Hex.toHexString(ecPoint.getEncoded(false));String pubX = ecPoint.getXCoord().toBigInteger().toString(16);String pubY = ecPoint.getYCoord().toBigInteger().toString(16);sm2KeyInfo.setPubX(pubX);sm2KeyInfo.setPubY(pubY);sm2KeyInfo.setPublicKeyHex(publicKeyHex);}PrivateKey privateKey = keyPair.getPrivate();if (privateKey instanceof BCECPrivateKey) {//獲取32字節十六進制私鑰串String privateKeyHex = ((BCECPrivateKey) privateKey).getD().toString(16);sm2KeyInfo.setPrivateKeyHex(privateKeyHex);}return sm2KeyInfo;}/*** @param publicKeyHex SM2十六進制公鑰* @param data 明文數據* @return* @Description 公鑰加密*/public static String encrypt(String publicKeyHex, String data) throws UnsupportedEncodingException, InvalidCipherTextException {//提取公鑰點ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(publicKeyHex));// 公鑰前面的02或者03表示是壓縮公鑰,04表示未壓縮公鑰, 04的時候,可以去掉前面的04ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);// 設置sm2為加密模式sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));byte[] in = data.getBytes("utf-8");byte[] arrayOfBytes = sm2Engine.processBlock(in, 0, in.length);return Hex.toHexString(arrayOfBytes);}/*** 加密 返回16進制字符串** @param pubX* @param pubY* @param data 明文* @return*/public static String encrypt(String pubX, String pubY, String data) throws UnsupportedEncodingException, InvalidCipherTextException {BigInteger x = new BigInteger(pubX, 16);BigInteger y = new BigInteger(pubY, 16);//提取公鑰點ECPoint pukPoint = sm2ECParameters.getCurve().createPoint(x, y);// 公鑰前面的02或者03表示是壓縮公鑰,04表示未壓縮公鑰, 04的時候,可以去掉前面的04ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);// 設置sm2為加密模式sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));byte[] in = data.getBytes("utf-8");byte[] arrayOfBytes = sm2Engine.processBlock(in, 0, in.length);return Hex.toHexString(arrayOfBytes);}/*** 公鑰加密 加密模式是SM2Engine.Mode.C1C3C2** @param publicKey SM2公鑰* @param data 明文數據* @return String* @Description 公鑰加密* @Author msx*/public static String encrypt(BCECPublicKey publicKey, String data) throws UnsupportedEncodingException, InvalidCipherTextException {//通過公鑰對象獲取公鑰的基本域參數。ECParameterSpec ecParameterSpec = publicKey.getParameters();// 構造ECC算法參數,曲線方程、橢圓曲線G點、大整數NECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),ecParameterSpec.getG(), ecParameterSpec.getN());//通過公鑰值和公鑰基本參數創建公鑰參數對象ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(publicKey.getQ(), ecDomainParameters);//根據加密模式實例化SM2公鑰加密引擎SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);//初始化加密引擎sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));//將明文字符串轉換為指定編碼的字節串byte[] in = data.getBytes("utf-8");//通過加密引擎對字節數串行加密byte[] arrayOfBytes = sm2Engine.processBlock(in, 0, in.length);//將加密后的字節串轉換為十六進制字符串return Hex.toHexString(arrayOfBytes);}/*** @param privateKey SM私鑰* @param cipherData 密文數據* @return* @Description 私鑰解密* @Author msx*/public static String decrypt(BCECPrivateKey privateKey, String cipherData) throws UnsupportedEncodingException, InvalidCipherTextException {// 使用BC庫加解密時密文以04開頭,傳入的密文前面沒有04則補上if (!cipherData.startsWith("04")) {cipherData = "04" + cipherData;}//將十六進制字符串密文轉換為字節數組(需要與加密一致,加密是:加密后的字節數組轉換為了十六進制字符串)byte[] cipherDataByte = Hex.decode(cipherData);//通過私鑰對象獲取私鑰的基本域參數。ECParameterSpec ecParameterSpec = privateKey.getParameters();ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),ecParameterSpec.getG(), ecParameterSpec.getN());//通過私鑰值和私鑰鑰基本參數創建私鑰參數對象ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(privateKey.getD(),ecDomainParameters);//通過解密模式創建解密引擎并初始化SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);sm2Engine.init(false, ecPrivateKeyParameters);//通過解密引擎對密文字節串進行解密byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);//將解密后的字節串轉換為utf8字符編碼的字符串(需要與明文加密時字符串轉換成字節串所指定的字符編碼保持一致)return new String(arrayOfBytes, "utf-8");}/*** @param privateKeyHex SM2十六進制私鑰* @param cipherData 密文數據* @return String* @Description 私鑰解密* @Author msx*/public static String decrypt(String privateKeyHex, String cipherData) throws UnsupportedEncodingException, InvalidCipherTextException {// 使用BC庫加解密時密文以04開頭,傳入的密文前面沒有04則補上if (!cipherData.startsWith("04")) {cipherData = "04" + cipherData;}//將十六進制字符串密文轉換為字節數組(需要與加密一致,加密是:加密后的字節數組轉換為了十六進制字符串)byte[] cipherDataByte = Hex.decode(cipherData);BigInteger privateKeyD = new BigInteger(privateKeyHex, 16);ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);// 設置sm2為解密模式sm2Engine.init(false, privateKeyParameters);byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);return new String(arrayOfBytes);}/*** @param pubKeyHex 64字節十六進制公鑰字符串(如果公鑰字符串為65字節首個字節為0x04:表示該公鑰為非壓縮格式,操作時需要刪除)* @return BCECPublicKey SM2公鑰對象* @Description 公鑰字符串轉換為 BCECPublicKey 公鑰對象* @Author msx*/public static BCECPublicKey getECPublicKeyByPublicKeyHex(String pubKeyHex) {//截取64字節有效的SM2公鑰(如果公鑰首個字節為0x04)if (pubKeyHex.length() > 128) {pubKeyHex = pubKeyHex.substring(pubKeyHex.length() - 128);}//將公鑰拆分為x,y分量(各32字節)String pubX = pubKeyHex.substring(0, 64);String pubY = pubKeyHex.substring(pubX.length());//將公鑰x、y分量轉換為BigInteger類型BigInteger x = new BigInteger(pubX, 16);BigInteger y = new BigInteger(pubY, 16);//通過公鑰x、y分量創建橢圓曲線公鑰規范ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(sm2ECParameters.getCurve().createPoint(x, y), ecDomainParameters);//通過橢圓曲線公鑰規范,創建出橢圓曲線公鑰對象(可用于SM2加密及驗簽)return new BCECPublicKey("EC", ecPublicKeySpec, BouncyCastleProvider.CONFIGURATION);}/*** @param privateKeyHex 32字節十六進制私鑰字符串* @return BCECPrivateKey SM2私鑰對象* @Description 私鑰字符串轉換為 BCECPrivateKey 私鑰對象* @Author msx*/public static BCECPrivateKey getBCECPrivateKeyByPrivateKeyHex(String privateKeyHex) {//將十六進制私鑰字符串轉換為BigInteger對象BigInteger d = new BigInteger(privateKeyHex, 16);//通過私鑰和私鑰域參數集創建橢圓曲線私鑰規范ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(d, ecDomainParameters);//通過橢圓曲線私鑰規范,創建出橢圓曲線私鑰對象(可用于SM2解密和簽名)return new BCECPrivateKey("EC", ecPrivateKeySpec, BouncyCastleProvider.CONFIGURATION);}/*** Generate an encoded SM2 signature based on the SM3 digest using the* passed in EC private key and input data.** @param ecPrivate the private key for generating the signature with.* @param input the input to be signed.* @return the encoded signature.*/public static byte[] generateSM2Signature(PrivateKey ecPrivate, byte[] input)throws GeneralSecurityException {Signature signature = Signature.getInstance("SM3withSM2", "BC");signature.initSign(ecPrivate);signature.update(input);return signature.sign();}/*** Return true if the passed in SM3withSM2 signature verifies against* the passed in EC public key and input.** @param ecPublic the public key of the signature creator.* @param input the input that was supposed to have been signed.* @param encSignature the encoded signature.* @return true if the signature verifies, false otherwise.*/public static boolean verifySM2Signature(PublicKey ecPublic, byte[] input, byte[] encSignature)throws GeneralSecurityException {Signature signature = Signature.getInstance("SM3withSM2", "BC");signature.initVerify(ecPublic);signature.update(input);return signature.verify(encSignature);}/*** Generate an encoded SM2 signature based on the SM3 digest using the* passed in EC private key and input data.** @param ecPrivate the private key for generating the signature with.* @param sm2Spec the SM2 specification carrying the ID of the signer.* @param input the input to be signed.* @return the encoded signature.*/public static byte[] generateSM2Signature(PrivateKey ecPrivate, SM2ParameterSpec sm2Spec, byte[] input)throws GeneralSecurityException {Signature signature = Signature.getInstance("SM3withSM2", "BC");signature.setParameter(sm2Spec);signature.initSign(ecPrivate);signature.update(input);return signature.sign();}/*** Return true if the passed in SM3withSM2 signature verifies against* the passed in EC public key and input.** @param ecPublic the public key of the signature creator.* @param sm2Spec the SM2 specification carrying the expected ID of the signer.* @param input the input that was supposed to have been signed.* @param encSignature the encoded signature.* @return true if the signature verifies, false otherwise.*/public static boolean verifySM2Signature(PublicKey ecPublic, SM2ParameterSpec sm2Spec,byte[] input, byte[] encSignature)throws GeneralSecurityException {Signature signature = Signature.getInstance("SM3withSM2", "BC");signature.setParameter(sm2Spec);signature.initVerify(ecPublic);signature.update(input);return signature.verify(encSignature);}}SM2UtilTest.java
package com.tom.crypto;import org.bouncycastle.jcajce.spec.SM2ParameterSpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; import org.junit.Assert; import org.junit.Test;import java.security.Security;/*** @ClassName TestSM2* @Description* @Author tom*/ public class SM2UtilTest {static {Security.addProvider(new BouncyCastleProvider());}@Testpublic void testSm2() throws Exception {SM2KeyInfo sm2KeyInfo = SM2Util.generateSM2Key();System.out.println(sm2KeyInfo);String publicKeyHex = sm2KeyInfo.getPublicKeyHex();String privateKeyHex = sm2KeyInfo.getPrivateKeyHex();String pubX = sm2KeyInfo.getPubX();String pubY = sm2KeyInfo.getPubY();/*** 公鑰加密*/String plainText = "=========原文數據====zw!!!=====";String encryptData = SM2Util.encrypt(publicKeyHex, plainText);System.out.println("---->encrypt加密結果:" + encryptData);String encryptData2 = SM2Util.encrypt(pubX, pubY, plainText);System.out.println("---->encrypt加密結果:" + encryptData2);/*** 私鑰解密*/String decryptData = SM2Util.decrypt(privateKeyHex, encryptData);Assert.assertEquals(plainText,decryptData);System.out.println("---->decrypt解密結果:" + decryptData);String decryptData2 = SM2Util.decrypt(privateKeyHex, encryptData2);System.out.println("---->decrypt2解密結果:" + plainText);Assert.assertEquals(plainText,decryptData2);byte[] signResult = SM2Util.generateSM2Signature(SM2Util.getBCECPrivateKeyByPrivateKeyHex(privateKeyHex), plainText.getBytes());String signResultHex = Hex.toHexString(signResult);System.out.println("---->簽名結果:" + signResultHex);boolean verifyResult = SM2Util.verifySM2Signature(SM2Util.getECPublicKeyByPublicKeyHex(publicKeyHex), plainText.getBytes(), Hex.decode(signResultHex));System.out.println("---->驗簽結果:" + verifyResult);Assert.assertTrue(verifyResult);SM2ParameterSpec sm2Spec = new SM2ParameterSpec(Strings.toByteArray("zwtom@baidu.com"));byte[] sm2Signature = SM2Util.generateSM2Signature(SM2Util.getBCECPrivateKeyByPrivateKeyHex(privateKeyHex), sm2Spec,Strings.toByteArray(plainText));String sm2SignatureHex = Hex.toHexString(sm2Signature);System.out.println("---->簽名結果2:" + sm2SignatureHex);boolean verifyReuslt2 = SM2Util.verifySM2Signature(SM2Util.getECPublicKeyByPublicKeyHex(publicKeyHex), sm2Spec,Strings.toByteArray(plainText), Hex.decode(sm2SignatureHex));System.out.println("---->驗簽結果:" + verifyReuslt2);Assert.assertTrue(verifyReuslt2);} }運算結果:
SM2KeyInfo{publicKeyHex='04ae5070d54d6603482d0f5abb888e39f58503f4ac6bf48ce8bcf64ba10f348af801ca7b0c439cf57d884f1a77ff8350006ee5eae5deac2e186ddeb873e4b0d427', privateKeyHex='5648e255a8460aa34663ebc0fb01069a844142fdda8cb663cefe56a2e0a8af00', pubX='ae5070d54d6603482d0f5abb888e39f58503f4ac6bf48ce8bcf64ba10f348af8', pubY='1ca7b0c439cf57d884f1a77ff8350006ee5eae5deac2e186ddeb873e4b0d427'} ---->encrypt加密結果:04ecadd6f10fdf720c9c86354a9cd5e1cc6b776d42b3c158275f0685baa033c2aab125de6889027093cb6f151bdd1f2fa174f6780a17d3190c8093ad0c13a93bc3debe26fb9f45e7ecd6c207b9a918ab321a1b1939881539dd8782166aa16350671055d3ef5cad464662f0b1545adeea2f3c778b01fd0c81ad3bf7827876154d368c3fbd ---->encrypt加密結果:04ea902db9a38d92ae21064a56b990ebafc95a9374a7bacbd1e61f5c845532a5c116c30f82198164283b1e6fdaa939e1da7fc334825faeebc3b75c2c0e211fbf56e0cfd57464fc8753ae5c4992459dafe8b9a8395c3e7a4ead0ad8fa5f7fe4609a3b0db09eb4a812424d74d715ed1a5e761710533a280f3baedd5ba1d55e258a63c18c02 ---->decrypt解密結果:=========原文數據====zw!!!===== ---->decrypt2解密結果:=========原文數據====zw!!!===== ---->簽名結果:3045022100dcbc6cdde483ba71f04f56e15409a9d7555bfeb52fefbf4d096bfdf0fc97fda602206a2d14db705fe7c1890dcd5bd7fd3748b5f86f0c9b97037feb65202ab5abda5b ---->驗簽結果:true ---->簽名結果2:3045022100e791b7df8ee931cc7df4f86df3d9f6a8b08d85824e32657d5f254040c65789ae022024b679695961352435d9975fc7b277f25e220dbaba4a00c8bc83514f2c149d5f ---->驗簽結果:trueSM3工具類
SM3Util.java
package com.tom.crypto;import org.bouncycastle.crypto.digests.SM3Digest; import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.params.KeyParameter;import java.util.Arrays;/*** SM3算法工具類*/ public class SM3Util {/*** 計算SM3摘要值** @param srcData 原文* @return 摘要值,對于SM3算法來說是32字節*/public static byte[] hash(byte[] srcData) {SM3Digest digest = new SM3Digest();digest.update(srcData, 0, srcData.length);byte[] hash = new byte[digest.getDigestSize()];digest.doFinal(hash, 0);return hash;}/*** 驗證摘要** @param srcData 原文* @param sm3Hash 摘要值* @return 返回true標識驗證成功,false標識驗證失敗*/public static boolean verify(byte[] srcData, byte[] sm3Hash) {byte[] newHash = hash(srcData);if (Arrays.equals(newHash, sm3Hash)) {return true;} else {return false;}}/*** 計算SM3 Mac值** @param key key值,可以是任意長度的字節數組* @param srcData 原文* @return Mac值,對于HMac-SM3來說是32字節*/public static byte[] hmac(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;} }SM3UtilTest 工具類
package com.tom.crypto;import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; import org.bouncycastle.util.encoders.Hex; import org.junit.Assert; import org.junit.Test;import java.security.Security; import java.util.Arrays;public class SM3UtilTest {static String plainText = "=========原文數據====zw!!!=====";static {Security.addProvider(new BouncyCastleProvider());}@Testpublic void testHashAndVerify() {try {byte[] hash = SM3Util.hash(plainText.getBytes("utf-8"));System.out.println("SM3 hash result:\n" + Hex.toHexString(hash));boolean flag = SM3Util.verify(plainText.getBytes("utf-8"), hash);Assert.assertTrue(flag);} catch (Exception ex) {ex.printStackTrace();Assert.fail();}}@Testpublic void testHmacSM3() {try {byte[] hmacKey = new byte[]{1, 2, 3, 4, 5, 6, 7, 8};byte[] hmac = SM3Util.hmac(hmacKey, plainText.getBytes("utf-8"));System.out.println("SM3 hash result:\n" + Arrays.toString(hmac));} catch (Exception ex) {ex.printStackTrace();Assert.fail();}} }參考網站
BouncyCastle介紹:
https://www.liaoxuefeng.com/wiki/1252599548343744/1305362418368545
BouncyCastle wiki :
https://github.com/bcgit/bc-java/wiki
BouncyCastle 官網
https://www.bouncycastle.org/latest_releases.html
國密局標準:
https://openstd.samr.gov.cn/bzgk/gb/std_list?p.p1=0&p.p90=circulation_date&p.p91=desc&p.p2=32918
草案:
https://datatracker.ietf.org/doc/html/draft-shen-sm2-ecdsa-02
開源密碼箱工具
http://gmssl.org/docs/quickstart.html
總結
以上是生活随笔為你收集整理的国密SM2/SM3算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言题目练习100例——题目+题目分析
- 下一篇: 最新版WinRAR 6.0 永久去除广告