java - d * e mod phi == 1 对于 RSA key 对并不总是正确

标签 java cryptography rsa bouncycastle

当使用 BouncycaSTLe 使用以下程序生成 RSA key 时(见下文),原因是

d * e mod phi == 1 其中 phi := (p - 1) * (q - 1)

在大多数情况下为真(check1的值)?

import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class TestRsaKey1 {

    private static Provider BC_PROVIDER;

    static {
        BC_PROVIDER = new BouncyCastleProvider();
        Security.insertProviderAt(BC_PROVIDER, 1);
    } // static

    public static void main(String[] args) throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(512);
        for (int i = 0; i < 10; i++) {
            boolean check0, check1;
            KeyPair keyPair = keyPairGenerator.genKeyPair();
            BCRSAPrivateCrtKey kPriv = (BCRSAPrivateCrtKey)keyPair.getPrivate();
            BigInteger n, e, d, p, q;
            n = kPriv.getModulus();
            e = kPriv.getPublicExponent();
            d = kPriv.getPrivateExponent();
            p = kPriv.getPrimeP();
            q = kPriv.getPrimeQ();
            
            // phi := (p - 1) * (q - 1)
            BigInteger phi = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE)); // phi := (p - 1) * (q - 1)
            
            // following check p * q == n ?  is true in 100% of cases
            check0 = n.equals(p.multiply(q));   

            // following check d * e mod phi == 1 ?  is true only in ca. 30% of cases
            check1 = BigInteger.ONE.equals(d.multiply(e).mod(phi));

            System.out.println(check0 + " " + check1);
        }
    } // main

} // class

最佳答案

key 导出的实现(就像几乎所有现代实现一样)使用 Carmichael totient 函数lambda(n) = lcm(p-1, q-1),而不是 Euler totient 函数phi(n) = (p-1)*(q-1)

如果使用 Carmichael totient 函数执行测试,则所有测试都满足条件d*e = 1 (mod lambda(n)): p>

BigInteger lambda = lcm(p.subtract(BigInteger.ONE), q.subtract(BigInteger.ONE));
boolean check2 = BigInteger.ONE.equals(d.multiply(e).mod(lambda)); // d * e mod lambda == 1 ?  <-- true for ALL cases
System.out.println(check0 + " " + check2);

与 ( here )

private static BigInteger lcm(BigInteger a, BigInteger b) {
    BigInteger mul = a.multiply(b);
    BigInteger gcd = a.gcd(b);
    BigInteger lcm = mul.divide(gcd);
    return lcm;
}

Euler 与 Carmichael totient 函数的引用,例如:
RSA (cryptosystem) - Key generation
Do Carmichael's and Euler's totient functions in RSA generate the same keys?
Main purpose for Carmichael's Function in RSA
Why do we need Euler's totient function φ(N) in RSA?
lcm versus phi in RSA

关于java - d * e mod phi == 1 对于 RSA key 对并不总是正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67123346/

相关文章:

java.util.Random NextDouble() 偏向于更高的均匀数

java - EntityManager 使用 id 以外的特定列合并

java - 为什么创建从Internet下载gradle.zip的Gradle项目?

java - 在服务器端解密加密消息

openssl - RSA-OAEP 和 RSAES-OAEP 之间有什么区别?

iphone - RSA 加密库或类

java - 在不安装 Eclipse 的情况下运行 RCP 应用程序

encryption - RSA 私钥的哪些部分是保密的?

python - 如何在 Python2 中使用 "cryptography"库从证书打印公钥?

go - 如何在 Go 中使用 RSA key 加密和解密纯文本?