eclipse實現ElGamal數字簽名

ElGamal數字簽名

一、實驗目的

學習ElGamal算法在數字簽名方面的使用,掌握教科書版本的ElGamal數字簽名算法的編寫,掌握ElGamal加密算法和ElGamal數字簽名算法的異同。

二、實驗要求

1. 熟悉ElGamal數字簽名算法。
2. 掌握如何使用Java BigInteger類,簡單實現教科書式的ElGamal公私鑰簽名算法。
3. 瞭解ElGamal加密算法和ElGamal數字簽名算法的異同。

三、開發環境

JDK 1.7,Java開發環境(本實驗採用Windows+eclipse作爲實驗環境),要求參與實驗的同學按照對稱加密提供的方法,提前安裝好JDK。

四、實驗內容

【1-1】ElGamal簽名算法的實現
1.實現公私鑰生成算法:根據教材,ElGamal公私鑰生成算法首選需要選取一個大素數 ,然後選取 作爲其生成元。接着隨機選取私鑰 ,計算 作爲其公鑰。因此,可寫代碼如下:

public void initKeys() {
	System.out.println("choose a prime p with securitylevel " 
		+ securitylevel + " , please wait ...");
	p = new BigInteger(securitylevel, 100, new Random());
	System.out.println("p : " + p);
	g = __randomInZp();
	System.out.println("g : " + g);
	x = __randomInZp();
	System.out.println("x : " + x);
	y = g.modPow(x, p);
	System.out.println("y : " + y);
	
}

其中,__randomInZp定義如下函數,實現從 中隨機選取一個大整數:

public BigInteger __randomInZp() {
	BigInteger r = null;
	do {
		System.out.print(".");
		r = new BigInteger(securitylevel, new SecureRandom());
	}while(r.compareTo(p) >= 0);
	System.out.println(".");
	return r;
}

2.實現簽名算法
ElGamal簽名算法需要隨機選取 ,同時計算
此時, 即爲簽名。因此,可根據公式,寫代碼如下:

public BigInteger[] signature(byte m[]) {
	BigInteger sig[] = new BigInteger[2];
	BigInteger k = __randomPrimeInZp();
	sig[0] = g.modPow(k, p);
	sig[1] = __hashInZp(m).subtract(x.multiply(sig[0]))
		.mod(p.subtract(BigInteger.ONE))
		.multiply(k.modInverse(p.subtract(BigInteger.ONE)))
		.mod(p.subtract(BigInteger.ONE));
	System.out.println("[r,s] = [" + sig[0] + ", " + sig[1] + "]");
	return sig;
}

此處的__randomPrimeInZp意爲從 中隨機選取一個大素數,實現如下:

public BigInteger __randomPrimeInZp() {
	BigInteger r = null;
	do {
		System.out.print(".");
		r = new BigInteger(securitylevel, 100, new SecureRandom());
	}while(r.compareTo(p) >= 0);
	System.out.println(".");
	return r;
}

另有一哈希函數,實現如下:

public BigInteger __hashInZp(byte m[]) {
	MessageDigest md;
	try {
		md = MessageDigest.getInstance("SHA-256");
		md.update(m);
	    byte b[] = new byte[33];
	    System.arraycopy(md.digest(), 0, b, 1, 32);
	    return new BigInteger(b);
	} catch (NoSuchAlgorithmException e) {
		System.out.println("this cannot happen.");
	}
    return null;
}

3.實現驗證算法:ElGamal簽名驗證算法即判定公式 是否成立。因此,可考慮寫代碼如下:

public boolean verify(byte m[], BigInteger sig[]) {
	BigInteger l = y.modPow(sig[0], p)
		.multiply(sig[0].modPow(sig[1], p)).mod(p);
	BigInteger r = g.modPow(__hashInZp(m), p);
	return l.compareTo(r) == 0;
}

4.實現main方法,在main方法中調用算法進行測試:

public static void main(String args[]) {
	ElGamalSignatureInstance instance = new ElGamalSignatureInstance();
	instance.initKeys();
	byte m[] = "my name is ElGamal, my student number is 201300012345.".getBytes();
	BigInteger sig[] = instance.signature(m);
	System.out.println("Real  signature verify result : " + instance.verify(m, sig));
	sig[0] = sig[0].add(BigInteger.ONE);
	System.out.println("Faked signature verify result : " + instance.verify(m, sig));
}

【1-2】完整參考代碼

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;


public class ElGamalSignatureInstance {
	int securitylevel = 1024;
	BigInteger p, g, x, y;
	
	public BigInteger __randomInZp() {
		BigInteger r = null;
		do {
			System.out.print(".");
			r = new BigInteger(securitylevel, new SecureRandom());
		}while(r.compareTo(p) >= 0);
		System.out.println(".");
		return r;
	}
	
	public BigInteger __randomPrimeInZp() {
		BigInteger r = null;
		do {
			System.out.print(".");
			r = new BigInteger(securitylevel, 100, new SecureRandom());
		}while(r.compareTo(p) >= 0);
		System.out.println(".");
		return r;
	}
	
	public BigInteger __hashInZp(byte m[]) {
		MessageDigest md;
		try {
			md = MessageDigest.getInstance("SHA-256");
			md.update(m);
		    byte b[] = new byte[33];
		    System.arraycopy(md.digest(), 0, b, 1, 32);
		    return new BigInteger(b);
		} catch (NoSuchAlgorithmException e) {
			System.out.println("this cannot happen.");
		}
	    return null;
	}
	
	public void initKeys() {
		System.out.println("choose a prime p with securitylevel " + securitylevel + " , please wait ...");
		p = new BigInteger(securitylevel, 100, new Random());
		System.out.println("p : " + p);
		g = __randomInZp();
		System.out.println("g : " + g);
		x = __randomInZp();
		System.out.println("x : " + x);
		y = g.modPow(x, p);
		System.out.println("y : " + y);
		
	}
	
	public BigInteger[] signature(byte m[]) {
		BigInteger sig[] = new BigInteger[2];
		BigInteger k = __randomPrimeInZp();
		sig[0] = g.modPow(k, p);
		sig[1] = __hashInZp(m).subtract(x.multiply(sig[0])).mod(p.subtract(BigInteger.ONE))
			.multiply(k.modInverse(p.subtract(BigInteger.ONE))).mod(p.subtract(BigInteger.ONE));
		System.out.println("[r,s] = [" + sig[0] + ", " + sig[1] + "]");
		return sig;
	}
	
	public boolean verify(byte m[], BigInteger sig[]) {
 		BigInteger l = y.modPow(sig[0], p).multiply(sig[0].modPow(sig[1], p)).mod(p);
		BigInteger r = g.modPow(__hashInZp(m), p);
		return l.compareTo(r) == 0;
	}
	
	public static void main(String args[]) {
		ElGamalSignatureInstance instance = new ElGamalSignatureInstance();
		instance.initKeys();
		byte m[] = "my name is ElGamal, my student number is 201300012345.".getBytes();
		BigInteger sig[] = instance.signature(m);
		System.out.println("Real  signature verify result : " + instance.verify(m, sig));
		sig[0] = sig[0].add(BigInteger.ONE);
		System.out.println("Faked signature verify result : " + instance.verify(m, sig));
	}
}


由於產生隨機大素數的方法(即__randomPrimeInZp)的運行速度受到 值和電腦CPU速度的影響,在某些同學的電腦上可能出現選取參數緩慢的問題。此時可將securitylevel的值調低(缺省1024,可調低到512),即可提高速度。但注意調低securitylevel將會導致安全強度下降。
【1-5】擴展內容:ElGamal加密算法和ElGamal簽名算法有何異同?
答:
(1)在產生公私鑰方面,二者幾乎完全一致。
(2)加密/簽名步驟,都需要先選取一個隨機數 並計算 作爲其密文的第一分量(這也是ElGamal的概率輸出的原因所在)。不同點在於,加密算法後續採用 的方式產生密文第二分量,而簽名算法採用了 作爲其第二分量。
(3)解密/驗證方面,解密算法採用 恢復明文,而簽名驗證算法採用公式 來驗證簽名是否吻合。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章