zoukankan      html  css  js  c++  java
  • 区块链中的密码学之非对称密码ELGamal算法(十一)

    1. 前言

    ELGamal密码是除了RSA之外最有代表性的公开密钥密码之一,它的安全性建立在离散对数问题的困难性之上,是一种公认安全的公钥密码。

    我们再来回顾下离散对数问题:

    设p为素数,若存在一个正整数α,使得α、α2、...、αp-1关于模p互不同余,则称α为模p的一个原根。于是有如下运算:α的幂乘运算:y=αx(mod p),1≤x≤p-1,α的对数运算:x=logαy,1≤y≤p-1

    只要p足够大,求解离散对数问题时相当复杂的。离散对数问题具有较好的单向性。

    2. 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=y^k(mod p)、C1=α^k(mod p)、C2=UM(mod p)。

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

    解密

      1.计算V=C1^d(mod p)。

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

    正确性证明

    image-20190329184230678

    3. ELGamal算法细节

    实现ELGamal算法,需要实现以下几个部分:

      1.对大数的素数判定;(RSA算法学习过)

      2.判断原根;

      3.模指运算;(RSA算法学习过)

      4.模逆运算。(RSA算法学习过)

    判断原根

    已知a和m互素,如果d是满足a^d=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),使得a^d=1(mod m),则a不是模m的原根。所以判断a是否为模m的原根,最快的方法就是判断φ(m)的每一个因子d是否使得a^d=1(mod m)。如果满足ad=1(mod m)的d=φ(m),则a是模m的原根。

    eg:判断2是不是模11的原根,φ(11)=10。10的因子有1、2、5、10,所以:

    2(mod 11)=2

    2^2(mod 11)=4

    2^5(mod 11)=10

    2^10(mod 11)=1

    因此,2是模11的原根。

    4. ELGamal密码的安全性

    由于ELGamal密码的安全性建立在GF(p)上离散对数的困难性之上,而目前尚无求解GF(p)上离散对数的有效算法,所以在p足够大时ELGamal密码是安全的。理想情况下p为强素数,p-1=2q,q为大素数。

      为了安全加密所使用的k必须是一次性的。如果长期使用同一个k加密的话,就可能被攻击者获取,从而根据V=U=y^k(mod p),M=C2V^-1(mod p)而得到明文。另外,使用同一个k加密不同的明文M和M',则由于

    image-20190329185123824

    如果攻击者知道M,则很容易求出M'。此外,k选取时还要保证U=y^k(mod p)≠1。

    5. 基于ELGamal的java源码的实现

    ELGamal源码:

    import java.math.BigInteger;
    import java.util.Random;
    
    public class ELGamal {
      public BigInteger p, alpha, y;
      private BigInteger d;
    
      public ELGamal() {
        do {
          //1. 随机地选择一个大素数p,且要求p-1有大素数因子,将p公开。
          p = BigInteger.probablePrime(100, new Random());
        } while (p.subtract(BigInteger.ONE).divide(new BigInteger("2")).isProbablePrime(100));
        do {
          //2.选择一个模p的原根α,并将α公开。
          alpha = new BigInteger(100, new Random());
        } while (! isOrigin(alpha, p));
        do {
          //3.随机地选择一个整数d(1<d<p-1)作为私钥,并对d保密。
          d = new BigInteger(100, new Random());
        } while (d.compareTo(BigInteger.ONE) != 1 || d.compareTo(p.subtract(BigInteger.ONE)) != -1);
        //4.计算公钥y=α^d(mod p),并将y公开。
        y = alpha.modPow(d, p);
      }
    
      public ELGamal(BigInteger p, BigInteger alpha, BigInteger d) {
        this.p = p;
        this.alpha = alpha;
        this.d = d;
        y = alpha.modPow(d, p);
      }
    
      /**
       * 加密
       * 随机地选取一个整数k(1<k<p-1)
       * 计算U=yk(mod p)、C1=αk(mod p)、C2=UM(mod p)
       * 取(C1,C2)作为密文
       * @param M
       * @return
       */
      BigInteger[] encrypt(BigInteger M) {
        BigInteger[] C = new BigInteger[2];
        BigInteger k, U;
        do {
          do {
            k = new BigInteger(100, new Random());
          } while (k.compareTo(BigInteger.ONE) != 1 || k.compareTo(p.subtract(BigInteger.ONE)) != -1);
          U = y.modPow(k, p);
        } while (U.intValue() != 1);
        C[0] = alpha.modPow(k, p);
        C[1] = U.multiply(M).mod(p);
        return C;
      }
    
      /**
       * 加密
       * @param M
       * @param k
       * @return
       */
      BigInteger[] encrypt(BigInteger M, BigInteger k) {
        BigInteger[] C = new BigInteger[2];
        BigInteger U = y.modPow(k, p);
        C[0] = alpha.modPow(k, p);
        C[1] = U.multiply(M).mod(p);
        return C;
      }
    
      /**
       * 解密
       * 计算V=C1^d(mod p);
       * 计算M=C2V^-1(mod p)
       * @param C
       * @return
       */
      BigInteger decrypt(BigInteger[] C) {
        BigInteger V = C[0].modPow(d, p);
        BigInteger M = C[1].multiply(V.modPow(new BigInteger("-1"), p)).mod(p);
        return M;
      }
    
      /**
       * 判断a是否为模m的原根,其中m为素数
       * @param a
       * @param m
       * @return
       */
      static boolean isOrigin(BigInteger a, BigInteger m) {
        if (a.gcd(m).intValue() != 1) return false;
        BigInteger i = new BigInteger("2");
        while (i.compareTo(m.subtract(BigInteger.ONE)) == -1) {
          if (m.mod(i).intValue() == 0) {
            if (a.modPow(i, m).intValue() == 1)
              return false;
            while (m.mod(i).intValue() == 0)
              m = m.divide(i);
          }
          i = i.add(BigInteger.ONE);
        }
        return true;
      }
      public BigInteger getD() {
        return d;
      }
    }
    

    测试代码:

    import java.math.BigInteger;
    
    public class TestELGamal {
    	public static void main(String[] args) {
    		BigInteger p = new BigInteger("2579");
    		BigInteger alpha = new BigInteger("2");
    		BigInteger d = new BigInteger("765");
    		ELGamal elgamal = new ELGamal(p, alpha, d);
    		System.out.println("p=" + elgamal.p);
    		System.out.println("α=" + elgamal.alpha);
    		System.out.println("d=" + elgamal.getD());
    		System.out.println("y=" + elgamal.y);
    		BigInteger M = new BigInteger("1299");
    		BigInteger k = new BigInteger("853");
    		BigInteger[] C = elgamal.encrypt(M, k);
    		System.out.println("明文:M=" + M);
    		System.out.println("k=" + k);
    		System.out.println("密文:(C1, C2)=(" + C[0] + ", " + C[1] + ")");
    		BigInteger decryptM=elgamal.decrypt(C);
    		System.out.println("解密:decryptM=" + decryptM);
    	}
    }
    

    测试结果:

    image-20190329185942702

    更多代码请参考:https://github.com/Anapodoton/Encryption/tree/master/ELGamal

  • 相关阅读:
    unity assert server 与 cache server
    Excel文件读写
    String与StringBuilder之间区别(转)
    c# 文件遍历
    C#整数三种强制类型转换int、Convert.ToInt32()、int.Parse()的区别
    2014年读过的书总结
    求职在年末
    被辞退于年末
    Unity Svn(转)
    公司的人员流动
  • 原文地址:https://www.cnblogs.com/hjs-junyu/p/10623296.html
Copyright © 2011-2022 走看看