RSA 密钥生成的 BigInteger 实现

BigInteger implementation of RSA's key generation

我在使模数的大小始终为 128 字节大时遇到了一些麻烦。有时模数的字节数组大小为129甚至130。我在网上搜索了实现,我的实现非常接近link:http://introcs.cs.princeton.edu/java/78crypto/RSA.java.html

这是我的实现:

public static void genKey() throws NoSuchAlgorithmException, NoSuchProviderException {
    int bitLength = 512;
    SecureRandom srand = new SecureRandom();
    BigInteger one  = new BigInteger("1");
    BigInteger p = BigInteger.probablePrime(bitLength, srand);
    BigInteger q = BigInteger.probablePrime(bitLength, srand);
    BigInteger phi = (p.subtract(one)).multiply(q.subtract(one));

    BigInteger modulus    = p.multiply(q); //Varies here                                  
    BigInteger publicKey  = new BigInteger("65537");     
    BigInteger privateKey = publicKey.modInverse(phi);

    byte[] modulusArray = modulus.toByteArray();
    byte[] publicKeyArray = publicKey.toByteArray();
    byte[] privateKeyArray = privateKey.toByteArray();
    byte[] tmpArray = new byte[128];
    for (int i = 0; i < publicKeyArray.length; i++) {
        tmpArray[i] = publicKeyArray[i];
    }
    publicKeyArray = tmpArray;
    byte[] publicKeyAndModulus = concat(modulusArray, publicKeyArray);
    byte[] privateKeyAndModulus = concat(modulusArray, privateKeyArray);
}

此外,privateKey 的长度也会有所不同。我可以使用 java.Security 库使大小更加一致吗?或者这是不可能实现的?

我建议你使用BouncyCastle and create an AsymmetricCipherKeyPair; here is an example I adapted from RSA using BouncyCastle

public static AsymmetricCipherKeyPair generateKeys(int keySizeInBits) {
    RSAKeyPairGenerator kpg = new RSAKeyPairGenerator();
    kpg.init(new KeyGenerationParameters(new SecureRandom(), keySizeInBits));
    return kpg.generateKeyPair();
}

BigInteger#bitLength()函数有必要的文档:

Returns the number of bits in the minimal two's-complement representation of this BigInteger, excluding a sign bit.

当您使用 bitLength 512 生成一个 BigInteger 时,最高有效位将是 0 ~50% 的时间,在这种情况下,符号位将取代它的位置并且它将适合 64 个字节,但是在其他情况下,最高有效位将为 1,这意味着符号位将被放入一个新字节中。

这意味着使用 511 作为 bitLength 总是会产生 64 字节的 BigIntegers 和 128 字节的模数。

您不应该真正自己生成 pq、模数和所有其他值。最好使用现有的 API,例如 Java 的 Cipher class,它还提供适当的填充以与 OAEP 等 RSA 一起使用(PKCS#1 v1.5 不再适用): "RSA/ECB/OAEPWithSHA-256AndMGF1Padding".