从私钥模数和私钥指数获取RSA公钥

3

我已经阅读了一些RSA文献和Stack Overflow的问题,但是我没有得到明确的答案。

只有给定RSA私钥模数和私钥指数,这就是我拥有的所有内容(也足以进行所有与加密相关操作),我能否获取关联的公钥模数和公钥指数?

此外,我只有这两个参数,是否可以获取私钥的编码形式? 我在Java中尝试了以下内容(Java不是实际要求),但是支持它的OpenSSL引擎失败并出现错误:04000090:RSA程序: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();
}

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

2个回答

2
通常,RSA私钥包含以下数据:
  • n - 半素数模数
  • d - 私有指数
  • pq - n的质数因子
  • e - 公共指数
最少,私钥必须包含:nd所以回答你的问题:

我能获取关联的公共密钥模数吗?

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

我能获取公共指数吗?

没有易于获取的方法,除非您知道pq,但您可以猜测它,它几乎总是一个小质数,最常见的是365537 尝试两个并检查密文是否有效。

1
想不到,一个糟糕的for循环寻找指数竟然奏效了。谢谢! - user1831114

1

按照 @Woodstock 的指示,我搜索了公共指数并成功找到:

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;
    }
}

1
它是65537。在Android手机上运行不到一分钟。我记得在SSL证书上到处都能看到这个数字,所以我猜它很常见。这个数字可以任意高,对吗?这会让这个过程稍微困难一些吗?但由于它已经需要私钥,所以从安全角度来看,这没有意义。 - user1831114

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接