1. 程式人生 > >SM2的非對稱加解密java工具類

SM2的非對稱加解密java工具類

由於工作原因需要對原有加密方式RSA已不適用,要支援國密SM2

maven依賴

<dependency>
    <groupId>org.bouncycastle</groupId>
	<artifactId>bcprov-jdk15on</artifactId>
	<version>1.54</version>
</dependency>

java實現如下

import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Arrays;

import org.bouncycastle.crypto.DerivationFunction;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.ShortenedDigest;
import org.bouncycastle.crypto.generators.KDF1BytesGenerator;
import org.bouncycastle.crypto.params.ISO18033KDFParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;

/**
 * 	 <B>說	明<B/>:SM2的非對稱加解密工具類,橢圓曲線方程為:y^2=x^3+ax+b 使用Fp-256
 * 
 * @author 作者名:馮龍淼
 * 		   E-mail:
[email protected]
* * @version 版 本 號:1.0.<br/> * 建立時間:2018年3月6日 上午9:40:53 */ public class SM2Util { /** 素數p */ private static final BigInteger p = new BigInteger("FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "00000000" + "FFFFFFFF" + "FFFFFFFF", 16); /** 係數a */ private static final BigInteger a = new BigInteger("FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "00000000" + "FFFFFFFF" + "FFFFFFFC", 16); /** 係數b */ private static final BigInteger b = new BigInteger("28E9FA9E" + "9D9F5E34" + "4D5A9E4B" + "CF6509A7" + "F39789F5" + "15AB8F92" + "DDBCBD41" + "4D940E93", 16); /** 座標x */ private static final BigInteger xg = new BigInteger("32C4AE2C" + "1F198119" + "5F990446" + "6A39C994" + "8FE30BBF" + "F2660BE1" + "715A4589" + "334C74C7", 16); /** 座標y */ private static final BigInteger yg = new BigInteger("BC3736A2" + "F4F6779C" + "59BDCEE3" + "6B692153" + "D0A9877C" + "C62A4740" + "02DF32E5" + "2139F0A0", 16); /** 基點G, G=(xg,yg),其介記為n */ private static final BigInteger n = new BigInteger("FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "7203DF6B" + "21C6052B" + "53BBF409" + "39D54123", 16); private static SecureRandom random = new SecureRandom(); private ECCurve.Fp curve; private ECPoint G; public static String printHexString(byte[] b) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < b.length; i++) { String hex = Integer.toHexString(b[i] & 0xFF); if (hex.length() == 1) { builder.append('0'+hex); hex = '0' + hex; } // System.out.print(hex.toUpperCase()); System.out.print(hex.toUpperCase()); builder.append(hex); } System.out.println(); return builder.toString(); } public BigInteger random(BigInteger max) { BigInteger r = new BigInteger(256, random); // int count = 1; while (r.compareTo(max) >= 0) { r = new BigInteger(128, random); // count++; } // System.out.println("count: " + count); return r; } private boolean allZero(byte[] buffer) { for (int i = 0; i < buffer.length; i++) { if (buffer[i] != 0) return false; } return true; } /** * 加密 * @param input 待加密訊息M * @param publicKey 公鑰 * @return byte[] 加密後的位元組陣列 */ public byte[] encrypt(String input, ECPoint publicKey) { System.out.println("publicKey is: "+publicKey); byte[] inputBuffer = input.getBytes(); printHexString(inputBuffer); /* 1 產生隨機數k,k屬於[1, n-1] */ BigInteger k = random(n); System.out.print("k: "); printHexString(k.toByteArray()); /* 2 計算橢圓曲線點C1 = [k]G = (x1, y1) */ ECPoint C1 = G.multiply(k); byte[] C1Buffer = C1.getEncoded(false); System.out.print("C1: "); printHexString(C1Buffer); // 3 計算橢圓曲線點 S = [h]Pb * curve沒有指定餘因子,h為空 // BigInteger h = curve.getCofactor(); System.out.print("h: "); // printHexString(h.toByteArray()); if (publicKey != null) { ECPoint // result = publicKey.multiply(h); if (!result.isInfinity()) { // System.out.println("pass"); } else { // System.err.println("計算橢圓曲線點 S = [h]Pb失敗"); return null; } } /* 4 計算 [k]PB = (x2, y2) */ ECPoint kpb = publicKey.multiply(k).normalize(); /* 5 計算 t = KDF(x2||y2, klen) */ byte[] kpbBytes = kpb.getEncoded(false); DerivationFunction kdf = new KDF1BytesGenerator(new ShortenedDigest( new SHA256Digest(), 20)); byte[] t = new byte[inputBuffer.length]; kdf.init(new ISO18033KDFParameters(kpbBytes)); kdf.generateBytes(t, 0, t.length); if (allZero(t)) { System.err.println("all zero"); } /* 6 計算C2=M^t */ byte[] C2 = new byte[inputBuffer.length]; for (int i = 0; i < inputBuffer.length; i++) { C2[i] = (byte) (inputBuffer[i] ^ t[i]); } /* 7 計算C3 = Hash(x2 || M || y2) */ byte[] C3 = calculateHash(kpb.getXCoord().toBigInteger(), inputBuffer, kpb.getYCoord().toBigInteger()); /* 8 輸出密文 C=C1 || C2 || C3 */ byte[] encryptResult = new byte[C1Buffer.length + C2.length + C3.length]; System.arraycopy(C1Buffer, 0, encryptResult, 0, C1Buffer.length); System.arraycopy(C2, 0, encryptResult, C1Buffer.length, C2.length); System.arraycopy(C3, 0, encryptResult, C1Buffer.length + C2.length, C3.length); System.out.print("密文: "); printHexString(encryptResult); return encryptResult; } public void decrypt(byte[] encryptData, BigInteger privateKey) { System.out.println("privateKey is: "+privateKey); System.out.println("encryptData length: " + encryptData.length); byte[] C1Byte = new byte[65]; System.arraycopy(encryptData, 0, C1Byte, 0, C1Byte.length); ECPoint C1 = curve.decodePoint(C1Byte).normalize(); /* 計算[dB]C1 = (x2, y2) */ ECPoint dBC1 = C1.multiply(privateKey).normalize(); /* 計算t = KDF(x2 || y2, klen) */ byte[] dBC1Bytes = dBC1.getEncoded(false); DerivationFunction kdf = new KDF1BytesGenerator(new ShortenedDigest( new SHA256Digest(), 20)); int klen = encryptData.length - 65 - 20; System.out.println("klen = " + klen); byte[] t = new byte[klen]; kdf.init(new ISO18033KDFParameters(dBC1Bytes)); kdf.generateBytes(t, 0, t.length); if (allZero(t)) { System.err.println("all zero"); } /* 5 計算M'=C2^t */ byte[] M = new byte[klen]; for (int i = 0; i < M.length; i++) { M[i] = (byte) (encryptData[C1Byte.length + i] ^ t[i]); } /* 6 計算 u = Hash(x2 || M' || y2) 判斷 u == C3是否成立 */ byte[] C3 = new byte[20]; System.arraycopy(encryptData, encryptData.length - 20, C3, 0, 20); byte[] u = calculateHash(dBC1.getXCoord().toBigInteger(), M, dBC1 .getYCoord().toBigInteger()); if (Arrays.equals(u, C3)) { System.out.println("解密成功"); System.out.println("M' = " + new String(M)); } else { System.out.print("u = "); printHexString(u); System.out.print("C3 = "); printHexString(C3); System.err.println("解密驗證失敗"); } } private byte[] calculateHash(BigInteger x2, byte[] M, BigInteger y2) { ShortenedDigest digest = new ShortenedDigest(new SHA256Digest(), 20); byte[] buf = x2.toByteArray(); digest.update(buf, 0, buf.length); digest.update(M, 0, M.length); buf = y2.toByteArray(); digest.update(buf, 0, buf.length); buf = new byte[20]; digest.doFinal(buf, 0); return buf; } private boolean between(BigInteger param, BigInteger min, BigInteger max) { if (param.compareTo(min) >= 0 && param.compareTo(max) < 0) { return true; } else { return false; } } /** * 公鑰校驗 * @param publicKey 公鑰 * @return boolean true或false */ private boolean checkPublicKey(ECPoint publicKey) { if (!publicKey.isInfinity()) { BigInteger x = publicKey.getXCoord().toBigInteger(); BigInteger y = publicKey.getYCoord().toBigInteger(); if (between(x, new BigInteger("0"), p) && between(y, new BigInteger("0"), p)) { BigInteger xResult = x.pow(3).add(a.multiply(x)).add(b).mod(p); System.out.println("xResult: " + xResult.toString()); BigInteger yResult = y.pow(2).mod(p); System.out.println("yResult: " + yResult.toString()); if (yResult.equals(xResult) && publicKey.multiply(n).isInfinity()) { return true; } } return false; } else { return false; } } /** * 獲得公私鑰對 * @return */ public SM2KeyPair generateKeyPair() { BigInteger d = random(n.subtract(new BigInteger("1"))); SM2KeyPair keyPair = new SM2KeyPair(G.multiply(d).normalize(), d); if (checkPublicKey(keyPair.getPublicKey())) { System.out.println("generate key successfully"); return keyPair; } else { System.err.println("generate key failed"); return null; } } public SM2Util() { curve = new ECCurve.Fp(p, // q a, // a b); // b G = curve.createPoint(xg, yg); } }

import java.math.BigInteger;

import org.bouncycastle.math.ec.ECPoint;

/**
 * 	 <B>說	明<B/>:SM2公私鑰實體類
 * 
 * @author 作者名:馮龍淼
 * 		   E-mail:[email protected]
 * 
 * @version 版   本  號:1.0.<br/>
 *          建立時間:2018年3月6日 上午9:43:56
 */
public class SM2KeyPair {
	
	/** 公鑰 */
	private  ECPoint publicKey;
	
	/** 私鑰 */
	private BigInteger privateKey;

	SM2KeyPair(ECPoint publicKey, BigInteger privateKey) {
		this.publicKey = publicKey;
		this.privateKey = privateKey;
	}

	public ECPoint getPublicKey() {
		return publicKey;
	}

	public BigInteger getPrivateKey() {
		return privateKey;
	}
	
}

import java.util.Arrays;

/**
 * 	 <B>說	明<B/>:SM2非對稱加解密工具類測試
 * @author 作者名:馮龍淼
 * 		   E-mail:[email protected]
 * 
 * @version 版   本  號:1.0.<br/>
 *          建立時間:2018年3月6日 下午5:20:56
 */
public class SM2UtilTest {

	/** 元訊息串 */
	private static String M = "哈哈哈,&*&…………&、、//\\[email protected]#$%^&*()物品[email protected]#$%^&*())))))ooooooooppppppppppppppppppplllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkffffffffffffffffffffffffffffffffffffff";
	
	public static void main(String[] args) {
		SM2Util sm2 = new SM2Util();
		SM2KeyPair keyPair = sm2.generateKeyPair();
		byte[] data = sm2.encrypt(M,keyPair.getPublicKey());
		System.out.println("data is:"+Arrays.toString(data));
		sm2.decrypt(data, keyPair.getPrivateKey());//71017045908707391874054405929626258767106914144911649587813342322113806533034
	}
	
}

相關推薦

SM2對稱解密java工具

由於工作原因需要對原有加密方式RSA已不適用,要支援國密SM2 maven依賴 <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov

對稱對稱解密

32位 tro 進行 ont 什麽 金融 被鎖 方式 str 對稱 DES: DES算法 再大多運用在 如信用卡持卡人的PIN的加密傳輸,IC卡與POS間的雙向認證、金融交易數據包的MAC校驗等領域 DES算法的入口參數有三

iOS-RSA對稱解密

實驗目標 程式語言不限 至少實現RSA生成公私鑰,並儲存為金鑰檔案,最好是ECC演算法 明文“學號+姓名+專業+學院” 使用其中一種金鑰加密,輸出密文 解密密文,輸出明文 調研PKI公鑰體系,在報告中說明,如何用公私鑰實現PKI體系 簡述E

軟實現對稱解密,公鑰證書與公鑰值區別,包含提取公約值程式碼

目前有部分未採購簽名驗籤伺服器的企業,採用軟實現做非對稱、對稱加解密,本文簡略說明一下工作過程中遇到的問題。 本交易涉及傳送方,接收方 問題背景: 對方即接收方採用的是軟實現,並且只提供了公鑰值(未經CA簽發) 我方即傳送方,採用的是硬體簽名驗籤服務。伺服器中存有我方的私鑰,

對稱解密——RSA加密、解密以及數字簽名

對稱與非對稱加解密,最主要區別在於:對稱加密,加解密的金鑰是一致的;非對稱加密,加解密的金鑰是不一致的; 對稱加密的例子如另一篇文章中的DES加解密、3DES加解密。 這裡要介紹的是非對稱加解密中,應用最廣泛的一種:RSA。 RSA簡介 RSA的由來,你可以簡單的百度到,它

RSA對稱解密演算法的使用

加密金鑰和解密金鑰相同時則稱為對稱加密。由於加密金鑰和解密金鑰相同,它們也被稱為Shared Key。如AES等。 加密金鑰(公鑰)和解密金鑰(私鑰)不相同時則稱為非對稱加密,別稱公鑰密碼。如RSA等。 非對稱加密例子: 假設張三擁有的公鑰Pu和私鑰Pr,其公鑰是公開的,誰

C#建立數字證書並匯出為pfx,並使用pfx進行對稱解密

我的專案當中,考慮到安全性,需要為每個客戶端分發一個數字證書,同時使用數字證書中的公私鑰來進行資料的加解密。為了完成這個安全模組,特寫了如下一個DEMO程式,該DEMO程式包含的功能有: 1:呼叫.NET2.0的MAKECERT建立含有私鑰的數字證書,並存儲到個人證書區;

RSA對稱解密

RSA加密演算法的數字證書操作 最早以前的加密演算法是對稱加密 (1)甲方選擇某一種加密規則,對資訊進行加密; (2)乙方使用同一種規則,對資訊進行解密。 最大弱點:甲方必須把加密規則告訴乙方,否則

對稱解密,私鑰和公鑰到底是誰來加密,誰來解密

第一種用法:公鑰加密,私鑰解密。---用於加解密 第二種用法:私鑰簽名,公鑰驗籤。---用於簽名 有點混亂,不要去硬記,總結一下: 你只要想: 既然是加密,那肯定是不希望別人知道我的訊息,所以只有我才能

SM2對稱演算法解密

在前面文章我們已經可以製作SM2證書了,主要應用了SM2簽名驗證演算法和SM3摘要演算法,在本文中主要介紹SM2公鑰加密演算法。這裡我們使用SM2數字證書來做SM2非對稱加密,然後使用硬體加密裝置做解密,比如加密檔案只能由指定的智慧密碼鑰匙UKey才能解開。 SM2加

Java工具——DES加密和解密工具 II

import java.security.Key; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import

Java對稱對稱加密解密,AES與RSA

加密技術可以分為對稱與非對稱兩種. 對稱加密,解密,即加密與解密用的是同一把祕鑰,常用的對稱加密技術有DES,AES等 而非對稱技術,加密與解密用的是不同的祕鑰,常用的非對稱加密技術有RSA等 為什麼要有非對稱加密,解密技術呢 假設這樣一種場景A要傳送一段訊息給B,但是又

Java 常用工具(16) : BigDecimal減乘除工具

import java.math.BigDecimal; public class BigDecimalUtil { /** * 由於Java的簡單型別不能夠精確的對浮點數進行運算,這個工具類提供精 確的浮點數運算,包括加減乘除和四捨五入。 */ priva

java工具,在Windows,Linux系統獲取電腦的MAC地址、本地IP、電腦名

copy iter 去掉m [] equals linu stat cli catch package com.cloudssaas.util; import java.io.BufferedReader; import java.io.IOException;

Escape解密Java

java[java] view plain copy /** * 中文加密 * Created by geo on 2017/7/4. */ public class EscapeUtils { /** * Escape編碼 * @p

自定義的jdbc連接工具JDBCUtils【java 工具

tco 成功 val update red source dex imp 添加 JDBCUtils 類:   1. 創建私有的屬性*(連接數據庫必要的四個變量):dreiver url user password   2. 將構造函數私有化   3.將註冊驅動寫入靜態代碼塊

java工具

new style strings 數組 toarray div ngs tro ron 1.list轉化為數組 ArrayList<String> list=new ArrayList<String>(); String[] strings = n

排名前 16 的 Java 工具

md5 normal 註釋 github上 數組 使用 讀取 lena dma 在Java中,工具類定義了一組公共方法,這篇文章將介紹Java中使用最頻繁及最通用的Java工具類。以下工具類、方法按使用流行度排名,參考數據來源於Github上隨機選取的5萬個開源項目源碼。

Json序列化java工具

java對象 writev ctype imp date eval 取消 cti empty json序列化通用工具類(java)>為了支持此工具類的正常使用,先導入以下jar包 1.lombok包是一個簡化java冗余代碼的jar包,實際開發中很方便在maven的p

排名前16的Java工具

-s lang 分隔符 獲得 輸出流 capital 分隔 部分 檢測字符串 原文:https://www.jianshu.com/p/9e937d178203 在Java中,工具類定義了一組公共方法,這篇文章將介紹Java中使用最頻繁及最通用的Java工具類。以下