ELGamal詳解(Java實現)


GitHub


ELGamal密碼

  ELGamal密碼是除了RSA之外最有代表性的公開密鑰密碼之一,它的安全性建立在離散對數問題的困難性之上,是一種公認安全的公鑰密碼。

離散對數問題

  設p為素數,若存在一個正整數α,使得α、α2、...、αp-1關於模p互不同余,則稱α為模p的一個原根。於是有如下運算:

  α的冪乘運算:

y=αx(mod p),1≤x≤p-1

  α的對數運算:

x=logαy,1≤y≤p-1

  只要p足夠大,求解離散對數問題時相當復雜的。離散對數問題具有較好的單向性。


ELGamal加解密算法

  1.隨機地選擇一個大素數p,且要求p-1有大素數因子,將p公開。

  2.選擇一個模p的原根α,並將α公開。

  3.隨機地選擇一個整數d(1<d<p-1)作為私鑰,並對d保密。

  4.計算公鑰y=αd(mod p),並將y公開。

加密

  1.隨機地選取一個整數k(1<k<p-1)。

  2.計算U=yk(mod p)、C1k(mod p)、C2=UM(mod p)。

  3.取(C1,C2)作為密文。

解密

  1.計算V=C1d(mod p)。

  2.計算M=C2V-1(mod p)。


ELGamal算法細節

  實現ELGamal算法,需要實現以下幾個部分:

  1.對大數的素數判定;

  2.判斷原根;

  3.模指運算;

  4.模逆運算。

判斷原根

  已知a和m互素,如果d是滿足ad=1(mod m)的最小正整數,則稱d為a模m的階,記為d=σm(a)。由於a和m互素,根據歐拉定理可知aφ(m)=1(mod m),由此可以得到σm(a) | φ(m)。

  若a是m的原根,則σm(a)=φ(m)。

  根據上述兩點,推出逆否命題:如果∃d | φ(m)且d≠φ(m),使得ad=1(mod m),則a不是模m的原根。所以判斷a是否為模m的原根,最快的方法就是判斷φ(m)的每一個因子d是否使得ad=1(mod m)。如果滿足ad=1(mod m)的d=φ(m),則a是模m的原根。

  e.m.判斷2是不是模11的原根

φ(11)=10

         10的因子有1、2、5、10,所以:

2(mod 11)=2

22(mod 11)=4

25(mod 11)=10

210(mod 11)=1

         因此,2是模11的原根。


ELGamal密碼的安全性

  由於ELGamal密碼的安全性建立在GF(p)上離散對數的困難性之上,而目前尚無求解GF(p)上離散對數的有效算法,所以在p足夠大時ELGamal密碼是安全的。理想情況下p為強素數,p-1=2q,q為大素數。

  為了安全加密所使用的k必須是一次性的。如果長期使用同一個k加密的話,就可能被攻擊者獲取,從而根據V=U=yk(mod p),M=C2V-1(mod p)而得到明文。另外,使用同一個k加密不同的明文M和M',則由於

如果攻擊者知道M,則很容易求出M'此外,k選取時還要保證U=yk(mod p)≠1。


Java實現

ELGamal

 1 do {
 2     p = BigInteger.probablePrime(100, new Random());
 3 } while (p.subtract(BigInteger.ONE).divide(new BigInteger("2")).isProbablePrime(100));
 4 do {
 5     alpha = new BigInteger(100, new Random());
 6 } while (! isOrigin(alpha, p));
 7 do {
 8     d = new BigInteger(100, new Random());
 9 } while (d.compareTo(BigInteger.ONE) != 1 || d.compareTo(p.subtract(BigInteger.ONE)) != -1);
10 y = alpha.modPow(d, p);
 1 /**
 2  * 加密
 3  * @param M
 4  * @return
 5  */
 6 BigInteger[] encrypt(BigInteger M) {
 7     BigInteger[] C = new BigInteger[2];
 8     BigInteger k, U;
 9     do {
10         do {
11             k = new BigInteger(100, new Random());
12         } while (k.compareTo(BigInteger.ONE) != 1 || k.compareTo(p.subtract(BigInteger.ONE)) != -1);
13         U = y.modPow(k, p);
14     } while (U.intValue() != 1);
15     C[0] = alpha.modPow(k, p);
16     C[1] = U.multiply(M).mod(p);
17     return C;
18 }
 1 /**
 2  * 解密
 3  * @param C
 4  * @return
 5  */
 6 BigInteger decrypt(BigInteger[] C) {
 7     BigInteger V = C[0].modPow(d, p);
 8     BigInteger M = C[1].multiply(V.modPow(new BigInteger("-1"), p)).mod(p);
 9     return M;
10 }

判斷原根

 1 /**
 2  * 判斷a是否為模m的原根,其中m為素數
 3  * @param a
 4  * @param m
 5  * @return
 6  */
 7 static boolean isOrigin(BigInteger a, BigInteger m) {
 8     if (a.gcd(m).intValue() != 1) return false;
 9     BigInteger i = new BigInteger("2");
10     while (i.compareTo(m.subtract(BigInteger.ONE)) == -1) {
11         if (m.mod(i).intValue() == 0) {
12             if (a.modPow(i, m).intValue() == 1)
13                 return false;
14             while (m.mod(i).intValue() == 0)
15                 m = m.divide(i);
16         }
17         i = i.add(BigInteger.ONE);
18     }
19     return true;
20 }

測試

測試數據

  p=2579

  α=2

  d=765

  M=1299

  k=853

測試結果


參考文獻

  張煥國,唐明.密碼學引論(第三版).武漢大學出版社,2015年


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM