您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)eclipse實現(xiàn)Schnorr數(shù)字簽名的方法,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
一、實驗?zāi)康?/strong>
學(xué)習(xí)Schnorr算法在數(shù)字簽名方面的使用,掌握公鑰簽名中最基礎(chǔ)的簽名算法-Schnorr數(shù)字簽名算法的編寫。
二、實驗要求
1. 熟悉Schnorr算法的描述,已經(jīng)其使用場景。
2. 熟悉Schnorr數(shù)字簽名算法。
3. 掌握如何使用java語言,實現(xiàn)Schnorr簽名算法。
三、開發(fā)環(huán)境/p>
JDK1.8,eclipse。
四、實驗原理
數(shù)字簽名是指消息發(fā)送方利用特定參數(shù)產(chǎn)生的一段消息碼,該消息碼可以用來標(biāo)識消息發(fā)送者真實身份,同時可以標(biāo)識發(fā)送的數(shù)據(jù)的完整性,所以在一定程度防止了發(fā)送的數(shù)據(jù)在發(fā)送過程中被攻擊者篡改的行為。簡而言之,數(shù)字簽名就是由消息發(fā)送者利用身份信息與消息相結(jié)合產(chǎn)生的一個消息摘要。
在數(shù)字簽名過程中核心的兩個步驟就是產(chǎn)生簽名信息和對簽名信息的驗證,產(chǎn)生簽名就是消息發(fā)送方使用特定的簽名算法將數(shù)據(jù)產(chǎn)生成消息摘要,同時使用私鑰對其摘要進行加密,最后將加密后的密文和原始的數(shù)據(jù)一起發(fā)送。消息接收方收到信息后,首先用發(fā)送者的公鑰來算數(shù)據(jù)的摘要,然后把此結(jié)果與收到的摘要對比,如果一致,則驗證通過,認(rèn)為該消息是真實有效的。反之無效,丟棄該消息。過程如下圖1所示。
a) 數(shù)字簽名加密過程
b) 數(shù)字簽名解密驗證過程
圖1 數(shù)字簽名過程
Schnorr簽名算法是由德國數(shù)學(xué)家、密碼學(xué)家Claus Schnorr提出,是Elgamal簽名方案的變種。
具體步驟如下:
首先是生成公鑰/私鑰對,過程如下:
a. 選擇素數(shù) 和 ,其中 是 的素因子;
b. 選擇一個整數(shù) ,使得 ; 、 和 構(gòu)成全局公鑰參數(shù),在用戶組內(nèi)的每個用戶都可以使用;
c. 選擇隨機整數(shù) 作為用戶的私鑰,其中 ;
d. 計算公鑰 ;
對于密鑰對為 的用戶,通過以下過程產(chǎn)生簽名:
a. 選擇隨機整數(shù),計算 ;
b. 將 附在消息后面,一起計算Hash值 :
c. 計算。
簽名對為 ,其他用戶通過以為過程來驗證簽名:
a. 計算;
b. 驗證等式 是否成立。
代碼段:
SchnorrSignature
import java.io.File; import java.math.BigInteger; import java.nio.file.Files; import java.nio.file.Paths; import java.security.MessageDigest; import java.security.SecureRandom; import java.util.List; /** * @ClassName: SchnorrSignature * @date: 2020年6月16日 下午9:25:09 * @Description:schnorr簽名 */ public class SchnorrSignature { // 路徑前綴 private static final String PERFIX_PATH = GetProjectPath.getPath() + "/ra/"; // 存放公共參數(shù) private static final String PARAM_PATH = PERFIX_PATH + "initParams.properties"; // 存放公鑰的路徑 private static final String PUBLIC_KEY_PATH = PERFIX_PATH + "publicKey.properties"; /** * @Description: 系統(tǒng)初始化階段,把初始化的密碼公共參數(shù)存放到文件中去 * @param blq:選擇的q的bit長度 * @Date:下午9:28:20 */ public static void initPara(int blq) { File file = new File(PARAM_PATH); if(file.exists()) { System.out.println("已經(jīng)存在初始化參數(shù),為不影響已經(jīng)頒發(fā)的證書,如果你強制要重新產(chǎn)生參數(shù),請備份所有文件到其他路徑下,并重新生產(chǎn)密鑰對并重新簽名"); }else { System.out.println("系統(tǒng)初始化中,生產(chǎn)公共參數(shù)... ..."); BigInteger one = new BigInteger("1"); BigInteger two = new BigInteger("2"); BigInteger q, qp, p, a, g; int certainty = 100; SecureRandom sr = new SecureRandom(); // blq長度的q, q是p-1的素因子 //生成BigInteger偽隨機數(shù),它可能是(概率不小于1 - 1/2certainty)一個具有指定 bitLength 的素數(shù) q = new BigInteger(blq, certainty, sr); qp = BigInteger.ONE; do { // 選擇一個素數(shù) p p = q.multiply(qp).multiply(two).add(one); if(p.isProbablePrime(certainty)) break; qp = qp.add(BigInteger.ONE); } while(true); while(true) { a = (two.add(new BigInteger(blq, 100, sr))).mod(p);// (2+x) mod p BigInteger ga = (p.subtract(BigInteger.ONE)).divide(q);// (p-1)/q g = a.modPow(ga, p); // a^ga mod p = 1 if(g.compareTo(BigInteger.ONE) != 0) // g!=1 break; } // 存放公共參數(shù) List<String> transArryToLi = KeyPairOperate.transArryToLi(new String[] {"blq=" + blq,"q=" + q, "p=" + p, "g=" + g}); KeyPairOperate.writePublicKeyToFile(PARAM_PATH, transArryToLi, false); System.out.println("..."); System.out.println("初始化完成!"); } } /** * @Description: 為用戶生成公私鑰對 * @param user:傳入用戶的身份 * @Return:void * @Date:上午9:32:18 */ public static void generateKeyForUser(String user) { File file = new File(PERFIX_PATH + user + ".properties"); if(file.exists()) { System.out.println(user + "已經(jīng)頒發(fā)了密鑰,請備份所有文件到其他路徑下,并重新簽名"); }else { System.out.println("密鑰頒發(fā)中,請稍后"); System.out.println("... ..."); BigInteger sk,pk;// 私鑰和公鑰 int blq = Integer.parseInt(KeyPairOperate.getDataFromFile(PARAM_PATH, "blq")); SecureRandom sr = new SecureRandom(); // 隨機數(shù)作為私鑰 sk = new BigInteger(blq, sr); // 私鑰的話名字命名 List<String> toLiSK = KeyPairOperate.transArryToLi(new String[] {"sk=" + sk}); KeyPairOperate.writePublicKeyToFile(PERFIX_PATH + user + ".properties", toLiSK, false); BigInteger g = new BigInteger(KeyPairOperate.getDataFromFile(PARAM_PATH, "g")); BigInteger p = new BigInteger(KeyPairOperate.getDataFromFile(PARAM_PATH, "p")); // 公鑰 pk = g.modPow(sk, p);// g^w mod p -- 注意這兒是正,所以下面驗證的時候是用的負(fù) List<String> toLiPK = KeyPairOperate.transArryToLi(new String[] {user + "=" + pk}); KeyPairOperate.writePublicKeyToFile(PUBLIC_KEY_PATH, toLiPK, true); System.out.println(user + " 密鑰頒發(fā)完成"); } } /** * @Description: 產(chǎn)生簽名 * @param sourcefilePath : 待簽名文件路徑 * @param user:傳入用戶的身份 * @Date:下午10:41:37 */ public static void makeSign(String sourcefilePath, String user) { System.out.println(user+ "的文件" + KeyPairOperate.getFileName(sourcefilePath) + " 簽名開始"); System.out.println("... ..."); BigInteger q = new BigInteger(KeyPairOperate.getDataFromFile(PARAM_PATH, "q")); // 素數(shù) q BigInteger p = new BigInteger(KeyPairOperate.getDataFromFile(PARAM_PATH, "p")); // 素數(shù) p BigInteger g = new BigInteger(KeyPairOperate.getDataFromFile(PARAM_PATH, "g")); // q的原根 a // 私鑰 BigInteger sk = new BigInteger(KeyPairOperate.getDataFromFile(PERFIX_PATH + user + ".properties", "sk")); // 私鑰 SecureRandom sr = new SecureRandom(); BigInteger r, x, e, y; r = new BigInteger(q.bitLength(), sr); // 隨機數(shù) x = g.modPow(r, p); // g^r mod p // e=H(M||x) try { MessageDigest md5 = MessageDigest.getInstance("MD5"); md5.update(Files.readAllBytes(Paths.get(sourcefilePath))); md5.update(x.toString().getBytes()); byte[] digest = md5.digest(); // e 將BigInteger的符號大小表示法轉(zhuǎn)換成一個BigInteger值 e = new BigInteger(1, digest); // y s2 = r y = (r.subtract(sk.multiply(e))).mod(q); List<String> transArryToLi = KeyPairOperate.transArryToLi(new String[] {"e="+e,"y="+y}); String fileName =PERFIX_PATH + user + "_sign_" + KeyPairOperate.getFileName(sourcefilePath) + ".properties"; KeyPairOperate.writePublicKeyToFile(fileName, transArryToLi, false); System.out.println(user+ "的文件" + KeyPairOperate.getFileName(sourcefilePath) + "簽名成功 !"); } catch (Exception e1) { e1.printStackTrace(); } } /** * @Description: 驗證簽名 * @param sourcePath : 原文件路徑 * @param user:傳入用戶的身份 * @Return:void * @Date:上午11:07:04 */ public static void checkSign(String sourcefilePath, String user) { System.out.println("驗證簽名"); BigInteger p = new BigInteger(KeyPairOperate.getDataFromFile(PARAM_PATH, "p")); // 素數(shù) p BigInteger g = new BigInteger(KeyPairOperate.getDataFromFile(PARAM_PATH, "g")); // q的原根 a BigInteger pk = new BigInteger(KeyPairOperate.getDataFromFile(PUBLIC_KEY_PATH, user));// 公鑰 String fileName =PERFIX_PATH + user + "_sign_" + KeyPairOperate.getFileName(sourcefilePath) + ".properties"; BigInteger e = new BigInteger(KeyPairOperate.getDataFromFile(fileName, "e")); // e 簽名信息1: 產(chǎn)生的簽名信息 BigInteger y = new BigInteger(KeyPairOperate.getDataFromFile(fileName, "y"));; // y 簽名信息2: 加密后的消息 // 計算的 x' BigInteger x1 = g.modPow(y, p); // g^y mod p -- y BigInteger x2 = (pk.modPow(e, p)).mod(p); // pk^e mod p BigInteger x = x1.multiply(x2).mod(p); // x1*x2 mod p = (g^y)*(pk^e)mod p try { MessageDigest md5 = MessageDigest.getInstance("MD5"); md5.update(Files.readAllBytes(Paths.get(sourcefilePath))); md5.update(x.toString().getBytes()); byte[] digest = md5.digest(); BigInteger h = new BigInteger(1, digest); System.out.println("... ..."); if(e.equals(h)) System.out.println(user+ "的文件" + KeyPairOperate.getFileName(sourcefilePath) + "驗證通過 !"); else System.out.println(user+ "的文件" + KeyPairOperate.getFileName(sourcefilePath) + "驗證失敗 !"); } catch (Exception e1) { e1.printStackTrace(); } } }
GetProjectPath:
import java.io.File; /** * @ClassName: GetProjectPath * @date: 2020年6月16日 下午10:58:53 * @Description: 獲取項目絕對路徑 */ public class GetProjectPath { public static String getPath() { File directory = new File(""); String courseFile = null; try { courseFile = directory.getCanonicalPath().replace("\\", "/"); }catch (Exception e) { e.printStackTrace(); } return courseFile; } }
KeyPairOperate
import java.io.FileInputStream; import java.io.FileWriter; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.Properties; /** * @ClassName: KeyPairOperate * @date: 2020年6月16日 下午9:53:11 * @Description: 密鑰對的管理與存儲 */ public class KeyPairOperate { public static String getFileName(String path) { int indexOf = path.lastIndexOf("\\")+1; int last = path.lastIndexOf("."); return path.substring(indexOf, last); } /** * @Description: 工具類,數(shù)組轉(zhuǎn)集合 * @param para * @return * @Return:List<String> * @Date:上午10:24:33 */ public static List<String> transArryToLi(String[] para){ List<String> li = new ArrayList<String>(); for(int i=0; i<para.length; i++) { li.add(para[i]); } return li; } /** * @Description: 獲取配置文件參數(shù) * @param path : 文件路徑 * @param para : 獲取參數(shù)的key * @Date:上午9:46:26 */ public static String getDataFromFile(String path, String key) { String para = null; try { Properties pro = new Properties(); pro.load(new FileInputStream(path)); para = (String) pro.get(key); } catch (Exception e) { e.printStackTrace(); } return para; } /** * @Description:寫公共密鑰到文件 -- 公鑰證書列表 * @param path : 存儲的路徑 * @param param : 參數(shù) * @param flag : 是否是追加存儲,公共參數(shù)不是追加,公鑰是追加; 追加: true, 覆蓋: flase * @Return:void * @Date:上午10:20:25 */ public static void writePublicKeyToFile(String path, List<String> param, Boolean flag) { try { PrintWriter printWriter = new PrintWriter(new FileWriter(path,flag)); for(String element : param) { printWriter.println(element); } printWriter.close(); } catch (Exception e) { e.printStackTrace(); } } }
Shtest
import org.junit.Test; public class Shtest { String pathFile ="C:\\Users\\89763\\Desktop\\www.rtf"; @Test public void initPara() { SchnorrSignature.initPara(12); } @Test public void generateKeyForUser() { SchnorrSignature.generateKeyForUser("xiaoming"); SchnorrSignature.generateKeyForUser("xiaowang"); } @Test public void makeSign() { SchnorrSignature.makeSign(pathFile,"xiaoming"); SchnorrSignature.makeSign(pathFile,"xiaowang"); } @Test public void checkSign() { SchnorrSignature.checkSign( pathFile ,"xiaoming"); SchnorrSignature.checkSign( pathFile ,"xiaowang"); } }
關(guān)于eclipse實現(xiàn)Schnorr數(shù)字簽名的方法就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。