eclipse實(shí)現(xiàn)Schnorr數(shù)字簽名
Schnorr數(shù)字簽名,供大家參考,具體內(nèi)容如下
一、實(shí)驗(yàn)?zāi)康?/strong>
學(xué)習(xí)Schnorr算法在數(shù)字簽名方面的使用,掌握公鑰簽名中最基礎(chǔ)的簽名算法-Schnorr數(shù)字簽名算法的編寫。
二、實(shí)驗(yàn)要求
1. 熟悉Schnorr算法的描述,已經(jīng)其使用場(chǎng)景。
2. 熟悉Schnorr數(shù)字簽名算法。
3. 掌握如何使用java語言,實(shí)現(xiàn)Schnorr簽名算法。
三、開發(fā)環(huán)境
JDK1.8,eclipse。
四、實(shí)驗(yàn)原理
數(shù)字簽名是指消息發(fā)送方利用特定參數(shù)產(chǎn)生的一段消息碼,該消息碼可以用來標(biāo)識(shí)消息發(fā)送者真實(shí)身份,同時(shí)可以標(biāo)識(shí)發(fā)送的數(shù)據(jù)的完整性,所以在一定程度防止了發(fā)送的數(shù)據(jù)在發(fā)送過程中被攻擊者篡改的行為。簡(jiǎn)而言之,數(shù)字簽名就是由消息發(fā)送者利用身份信息與消息相結(jié)合產(chǎn)生的一個(gè)消息摘要。
在數(shù)字簽名過程中核心的兩個(gè)步驟就是產(chǎn)生簽名信息和對(duì)簽名信息的驗(yàn)證,產(chǎn)生簽名就是消息發(fā)送方使用特定的簽名算法將數(shù)據(jù)產(chǎn)生成消息摘要,同時(shí)使用私鑰對(duì)其摘要進(jìn)行加密,最后將加密后的密文和原始的數(shù)據(jù)一起發(fā)送。消息接收方收到信息后,首先用發(fā)送者的公鑰來算數(shù)據(jù)的摘要,然后把此結(jié)果與收到的摘要對(duì)比,如果一致,則驗(yàn)證通過,認(rèn)為該消息是真實(shí)有效的。反之無效,丟棄該消息。過程如下圖1所示。

a) 數(shù)字簽名加密過程
b) 數(shù)字簽名解密驗(yàn)證過程

圖1 數(shù)字簽名過程
Schnorr簽名算法是由德國數(shù)學(xué)家、密碼學(xué)家Claus Schnorr提出,是Elgamal簽名方案的變種。
具體步驟如下:
首先是生成公鑰/私鑰對(duì),過程如下:
a. 選擇素?cái)?shù) 和 ,其中 是 的素因子;
b. 選擇一個(gè)整數(shù) ,使得 ; 、 和 構(gòu)成全局公鑰參數(shù),在用戶組內(nèi)的每個(gè)用戶都可以使用;
c. 選擇隨機(jī)整數(shù) 作為用戶的私鑰,其中 ;
d. 計(jì)算公鑰 ;
對(duì)于密鑰對(duì)為 的用戶,通過以下過程產(chǎn)生簽名:
a. 選擇隨機(jī)整數(shù),計(jì)算 ;
b. 將 附在消息后面,一起計(jì)算Hash值 :
c. 計(jì)算。
簽名對(duì)為 ,其他用戶通過以為過程來驗(yàn)證簽名:
a. 計(jì)算;
b. 驗(yàn)證等式 是否成立。

代碼段:
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長(zhǎng)度
* @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ā)的證書,如果你強(qiáng)制要重新產(chǎn)生參數(shù),請(qǐng)備份所有文件到其他路徑下,并重新生產(chǎn)密鑰對(duì)并重新簽名");
}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長(zhǎng)度的q, q是p-1的素因子
//生成BigInteger偽隨機(jī)數(shù),它可能是(概率不小于1 - 1/2certainty)一個(gè)具有指定 bitLength 的素?cái)?shù)
q = new BigInteger(blq, certainty, sr);
qp = BigInteger.ONE;
do { // 選擇一個(gè)素?cái)?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: 為用戶生成公私鑰對(duì)
* @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ā)了密鑰,請(qǐng)備份所有文件到其他路徑下,并重新簽名");
}else {
System.out.println("密鑰頒發(fā)中,請(qǐng)稍后");
System.out.println("... ...");
BigInteger sk,pk;// 私鑰和公鑰
int blq = Integer.parseInt(KeyPairOperate.getDataFromFile(PARAM_PATH, "blq"));
SecureRandom sr = new SecureRandom();
// 隨機(jī)數(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 -- 注意這兒是正,所以下面驗(yàn)證的時(shí)候是用的負(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")); // 素?cái)?shù) q
BigInteger p = new BigInteger(KeyPairOperate.getDataFromFile(PARAM_PATH, "p")); // 素?cái)?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); // 隨機(jī)數(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的符號(hào)大小表示法轉(zhuǎn)換成一個(gè)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: 驗(yàn)證簽名
* @param sourcePath : 原文件路徑
* @param user:傳入用戶的身份
* @Return:void
* @Date:上午11:07:04
*/
public static void checkSign(String sourcefilePath, String user) {
System.out.println("驗(yàn)證簽名");
BigInteger p = new BigInteger(KeyPairOperate.getDataFromFile(PARAM_PATH, "p")); // 素?cái)?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: 加密后的消息
// 計(jì)算的 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) + "驗(yàn)證通過 !");
else
System.out.println(user+ "的文件" + KeyPairOperate.getFileName(sourcefilePath) + "驗(yàn)證失敗 !");
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
GetProjectPath:
import java.io.File;
/**
* @ClassName: GetProjectPath
* @date: 2020年6月16日 下午10:58:53
* @Description: 獲取項(xiàng)目絕對(duì)路徑
*/
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: 密鑰對(duì)的管理與存儲(chǔ)
*/
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 : 存儲(chǔ)的路徑
* @param param : 參數(shù)
* @param flag : 是否是追加存儲(chǔ),公共參數(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");
}
}
以上代碼均來自https://blog.csdn.net/qq_27731689/article/details/106828368 作者:黎明小書生
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- eclipse實(shí)現(xiàn)ElGamal數(shù)字簽名
- Java PDF 添加數(shù)字簽名的實(shí)現(xiàn)方法
- Java實(shí)現(xiàn)的數(shù)字簽名算法RSA完整示例
- 詳解Java數(shù)字簽名提供XML安全
- 淺析java消息摘要與數(shù)字簽名
- Java數(shù)字簽名算法DSA實(shí)例詳解
- Java加密解密和數(shù)字簽名完整代碼示例
- 使用數(shù)字簽名實(shí)現(xiàn)數(shù)據(jù)庫記錄防篡改(Java實(shí)現(xiàn))
- 常用數(shù)字簽名算法RSA與DSA的Java程序內(nèi)實(shí)現(xiàn)示例
- eclipse實(shí)現(xiàn)DSA數(shù)字簽名
相關(guān)文章
SpringBoot使用MyBatis時(shí)的幾種傳參規(guī)范示例
使用Mybatis作為持久層框架時(shí),對(duì)于數(shù)據(jù)庫的增刪改查等操作都需要參數(shù)的傳遞,本文就詳細(xì)的介紹了一下SpringBoot使用MyBatis時(shí)的幾種傳參規(guī)范示例,感興趣的可以了解一下2022-02-02
springboot實(shí)現(xiàn)rabbitmq消息確認(rèn)的示例代碼
RabbitMQ的消息確認(rèn)有兩種, 一種是消息發(fā)送確認(rèn),第二種是消費(fèi)接收確認(rèn),本文主要介紹了springboot實(shí)現(xiàn)rabbitmq消息確認(rèn)的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09
解決springboot接入springfox-swagger2遇到的一些問題
這篇文章主要介紹了解決springboot接入springfox-swagger2遇到的一些問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
Java實(shí)現(xiàn)AOP面向切面編程的實(shí)例教程
這篇文章主要介紹了Java實(shí)現(xiàn)AOP面向切面編程的實(shí)例教程,通常Java中的AOP都是利用Spring框架中造好的輪子來開發(fā),而本文則關(guān)注于Java本身AOP的設(shè)計(jì)模式實(shí)現(xiàn),需要的朋友可以參考下2016-04-04
Springmvc工程跳轉(zhuǎn)controller無效的解決
這篇文章主要介紹了Springmvc工程跳轉(zhuǎn)controller無效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
MybatisPlus?QueryWrapper常用方法實(shí)例
MyBatis-Plus(opens new window)是一個(gè)MyBatis(opens new window)的增強(qiáng)工具,在 MyBatis的基礎(chǔ)上只做增強(qiáng)不做改變,為簡(jiǎn)化開發(fā)、提高效率而生,下面這篇文章主要給大家介紹了關(guān)于MybatisPlus?QueryWrapper常用方法的相關(guān)資料,需要的朋友可以參考下2022-04-04
idea創(chuàng)建SpringBoot項(xiàng)目及注解配置相關(guān)應(yīng)用小結(jié)
Spring Boot是Spring社區(qū)發(fā)布的一個(gè)開源項(xiàng)目,旨在幫助開發(fā)者快速并且更簡(jiǎn)單的構(gòu)建項(xiàng)目,Spring Boot框架,其功能非常簡(jiǎn)單,便是幫助我們實(shí)現(xiàn)自動(dòng)配置,本文給大家介紹idea創(chuàng)建SpringBoot項(xiàng)目及注解配置相關(guān)應(yīng)用,感興趣的朋友跟隨小編一起看看吧2023-11-11

