El Gamal数字签名结构莫名其妙地失败了

时间:2017-10-30 22:17:44

标签: java cryptography digital-signature biginteger elgamal

我正在尝试实施El Gamal数字签名方案,使用BigInteger类生成大质数。 Samantha生成公钥,私钥,选择消息,签名,然后Victor验证签名。

问题:输出始终表示签名尚未经过验证,即验证算法在每次执行时都返回false,这会再次使数字随机化。但是,当使用小的常数进行测试时,我得到了正确的结果。

问题:我在哪里做错了什么?我似乎无法得出结论。

到目前为止我的代码:

ElGamal_test - 用于预计算步骤和测试的方法

public static void ElGamal_test(){

    // Samantha picks q, a 1024 bit prime and computes p = 2q + 1
    Random rng = new SecureRandom();
    BigInteger q = BigInteger.probablePrime(1024, rng);
    BigInteger p = q.multiply(BigInteger.valueOf(2)).add(BigInteger.ONE);
    //  BigInteger p = BigInteger.valueOf(467);

    // Samantha computes g, a primitive root modulo p
    BigInteger g;

    while(true){
        g = new BigInteger(1024, rng);
        if(g.compareTo(BigInteger.ONE) > 0 &&
           g.compareTo(p) < 0 &&
           !(g.multiply(g).mod(p).equals(BigInteger.ONE)) &&
           !(g.modPow(q, p).equals(BigInteger.ONE)))
            break;
    }
    //  g = BigInteger.valueOf(2);

    // Samantha computes her private key
    BigInteger s;

    while(true){
        s = new BigInteger(1024, rng);
        if(s.compareTo(BigInteger.ONE) > 0 &&
           s.compareTo(p.subtract(BigInteger.ONE)) < 0)
            break;
    }
    //  s = BigInteger.valueOf(127);

    // Samantha computes her public key
    BigInteger v = g.modPow(s, p);

    // Samantha chooses her message, m
    BigInteger m = new BigInteger("100");

    // Samantha signs her message
    BigInteger[] key = Cryptography.ElGamalSignature(p, g, s, m);

    // Victor verifies the signature
    boolean result = Cryptography.ElGamalVerification(p, g, v, m, key);

    String str = (result == true) ? "The signature has been verified" : "The signature has not been verified";
    System.out.println(str);
}

ElGamalSignature - 用于签名算法的方法

public static BigInteger[] ElGamalSignature(BigInteger prime, BigInteger generator, BigInteger privExp, BigInteger doc){

    BigInteger[] signature = new BigInteger[2];
    Random rng = new SecureRandom();

    // Samantha picks the ephemeral key
    BigInteger e;
    while(true){
        e = new BigInteger(1024, rng);
        if(e.compareTo(BigInteger.ONE) > 0 &&
           e.compareTo(prime.subtract(BigInteger.ONE)) < 0 &&
           e.gcd(prime.subtract(BigInteger.ONE)).equals(BigInteger.ONE))
            break;
    }
    //  e = BigInteger.valueOf(213);

    // Samantha computes the signature
    signature[0] = generator.modPow(e, prime);
    signature[1] = (doc.subtract(privExp.multiply(signature[0])))
                 .multiply(e.modInverse(prime.subtract(BigInteger.ONE)))
                 .mod(prime.subtract(BigInteger.ONE));
    return signature;
}

ElGamalVerification - 用于验证算法的方法

public static boolean ElGamalVerification(BigInteger prime, BigInteger generator, BigInteger publicExp, BigInteger doc, BigInteger[] key){

    BigInteger part1 = (publicExp.modPow(key[0], prime).multiply(key[0].modPow(key[1], prime))).mod(prime);
    BigInteger part2 = generator.modPow(doc, prime);

    if(part1.equals(part2))
        return true;
    else
        return false;
}

1 个答案:

答案 0 :(得分:2)

评论扩大; TLDR你的p不是素数。

你引用https://crypto.stackexchange.com/questions/820/how-does-one-calculate-a-primitive-root-for-diffie-hellman来计算DH的生成器g而不是p和q。

Thomas Pornin答案的第4段考虑了一个DH组,其中p = 2q + 1,q也是素数。对于DH,在这种情况下,如果生成器具有订单q 2q就足够了,但它必须具有非常小的顺序(2或1)。正如他所说,只有1有1阶,只有p-1有2阶,所以任何其他的group元素都可以用作生成器,通常2是为了方便。

OTOH Jus12的答案解决了(错误地)陈述的问题,即当p = 2k + 1时使用k prime(使用k而不是q代表索菲 - 日耳曼素数)找到原语根。原始意味着它有2k的顺序。要做到这一点,需要测试2..p-1中的候选项(您编码为&gt; 1和&lt; p)以找到其顺序为 2或k(您的q)的候选项,这是你的代码做了什么。与DH不同,ElGamal 需要原始根,因此这是找到g 给定有效p和q的正确方法。

这两个答案都假设你已经拥有 p = 2q + 1,q p prime。他们找不到p和q。你的算法首先找到q prime(概率上但足够好),然后只是计算 p = 2q + 1。但是你不能验证p = 2q + 1是否为素数 - 而且通常不是。即使这个数学符号中的p表示素数,Java也不会自动生成名为p prime的变量。并且当p不是素数时,ElGamal不起作用。

你需要生成q素数并验证p = 2q + 1也是素数,或者生成p素数并验证q =(p-1)/ 2也是素数。