从私钥模数和私钥指数中获取 RSA public 密钥

Get RSA public key from private key modulus and private exponent

我一直在阅读一些 RSA 文献和堆栈溢出问题,但我没有得到明确的答案。

仅给出 RSA 私钥模数和私钥指数,这是我所有的(并且对于所有加密相关操作也足够),我能否获得相关的 public 密钥模数和 public指数?

另外,我可以只用这两个参数得到私钥的编码形式吗?我在 java 中尝试了以下操作(java 不是实际要求),但是支持它的 OpenSSL 引擎失败并显示 error:04000090:RSA routines:OPENSSL_internal:VALUE_MISSING

@NonNull
public static byte[] getEncodedRsaPrivateKey(@NonNull BigInteger nModulus, @NonNull BigInteger nPrivateExponent) throws NoSuchAlgorithmException, InvalidKeySpecException {
    RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(nModulus, nPrivateExponent);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
    return privateKey.getEncoded();
}

我想这两个问题的答案都是否定的,但我不确定。

一般RSA私钥包含以下数据:

  • n - 半素数模数

  • d - 私有指数

  • p & q - n

    的质因数
  • e - public 指数

至少 ,私钥必须包含:

  • nd.

所以回答你的问题:

can I get the associated public key modulus?

是的,你已经拥有了。与私钥使用的n相同。

can I get the public exponent?

不知道 pq 就不容易了,虽然你可以猜到它,但它几乎总是一个小素数,最常见的是 365537.

两者都试一下,检查密文是否有效。

按照@Woodstock 的指示,我搜索了 public 指数并成功:

int nPublicExponent;
boolean bFound = false;
for (nPublicExponent = 3; nPublicExponent <= 65537; nPublicExponent++) {
    publicKeySpec = new RSAPublicKeySpec(privateKey.getModulus(), new BigInteger(String.valueOf(nPublicExponent)));
    publicKey = rsaKeyFactory.generatePublic(publicKeySpec);
    if (publicKey == null) {
        continue;
    }
    byte[] encryptMessage = testEncrypt("hello", publicKey);
    if (encryptMessage == null) {
        continue;
    }
    String sMessage = testDecrypt(encryptMessage, privateKey);
    if (TextUtils.isEmpty(sMessage)) {
        continue;
    }
    if (TextUtils.equals(sMessage, "hello")) {
        bFound = true;
        break;
    }
}
if (!bFound) {
    Utils.DebugLog("Public exponent not found");
} else {
    Utils.DebugLog("Public exponent found: " + nPublicExponent);
}

@Nullable
public static byte[] testEncrypt(String sMessage, PublicKey publicKey) {
    try {
        Cipher encrypt =  Cipher.getInstance("RSA/ECB/PKCS1Padding");
        encrypt.init(Cipher.ENCRYPT_MODE, publicKey);
        return encrypt.doFinal(sMessage.getBytes());
    } catch (Exception ex) {
        return null;
    }
}

@Nullable
public static String testDecrypt(byte[] encryptedMessage, Key privateKey) {
    try {
        Cipher decrypt = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        decrypt.init(Cipher.DECRYPT_MODE, privateKey);
        return new String(decrypt.doFinal(encryptedMessage));
    } catch (Exception ex) {
        return null;
    }
}