Java中如何从私钥获取公钥

21

我记得很久以前用OpenSSL做过这件事,但我想知道是否可能以及如何在Java中使用密码学。


请参考以下回答,基于此问题的答案:https://dev59.com/o2gu5IYBdhLWcg3wZmW8 - Eli Rosencruft
3个回答

42
假设我们正在讨论RSA私钥和公钥。如果您使用PEM格式文件,则需要首先从文件中读取私钥并将其存储到一个PrivateKey对象中:
    public PrivateKey readPemRsaPrivateKey(String pemFilename) throws
            java.io.IOException,
            java.security.NoSuchAlgorithmException,
            java.security.spec.InvalidKeySpecException
    {
            String pemString = File2String(pemFilename);

            pemString = pemString.replace("-----BEGIN RSA PRIVATE KEY-----\n", "");
            pemString = pemString.replace("-----END RSA PRIVATE KEY-----", "");

            byte[] decoded = Base64.decodeBase64(pemString);

            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decoded);
            KeyFactory kf = KeyFactory.getInstance("RSA");

            return kf.generatePrivate(keySpec);
    }

其中File2String类似于:

    private static String File2String(String fileName) throws
            java.io.FileNotFoundException, java.io.IOException
    {
            File file = new File(fileName);

            char[] buffer = null;

            BufferedReader bufferedReader = new BufferedReader(new FileReader(file));

            buffer = new char[(int)file.length()];

            int i = 0;
            int c = bufferedReader.read();

            while (c != -1) {
                    buffer[i++] = (char)c;
                    c = bufferedReader.read();
            }
            return new String(buffer);
    }

现在,您可以使用以下代码生成相应的公钥:
    import java.security.interfaces.RSAPrivateCrtKey;
    import java.security.spec.RSAPublicKeySpec;

...

    PrivateKey myPrivateKey = readPemRsaPrivateKey(myPrivateKeyPemFileName);
    RSAPrivateCrtKey privk = (RSAPrivateCrtKey)myPrivateKey;

    RSAPublicKeySpec publicKeySpec = new java.security.spec.RSAPublicKeySpec(privk.getModulus(), privk.getPublicExponent());

    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PublicKey myPublicKey = keyFactory.generatePublic(publicKeySpec);

致谢:如何通过私钥获取RSA公钥?


公钥规范的参数顺序是否正确? 应该先是模数吧? - Archimedes Trajano

7
请确保Eli Rosencruft的回答基本正确,但是模数和公共指数的顺序是错误的!这是正确的声明:
RSAPublicKeySpec publicKeySpec = new java.security.spec.RSAPublicKeySpec(privk.getModulus(), privk.getPublicExponent());

-9

您无法直接从另一个密钥生成任何一种密钥,这在数学上是不可能的。如果您有一个包含公钥和私钥的密钥 blob,您可以相对容易地提取其中的任何一个。

编辑,2017年: 经过多年的发展和更好的加密理解,现在我明白这个答案并不完全正确。

引用维基百科的话:

公钥由模数n和公共(或加密)指数e组成。私钥由模数n和私有(或解密)指数d组成,必须保密。p、q和λ(n)也必须保密,因为它们可用于计算d。

公共模数n可以计算为p×q。原始私钥唯一缺少的是e值,但此值通常选择为65537,如果没有,您仍然可以从d和λ(n)计算出e。

但是,许多私钥存储格式实际上将公共模数n与其他组件一起包含在内,因此您可以直接提取这些值。

编辑,2018年:我仍然因为这个回答而受到负评,这是正确的!我保留这个回答,让人们看到我最初的错误,并提醒自己将来不要再犯错。


6
假设这个密钥是一个RSA密钥,并且以标准方式存储,那么由库(openssl)指代的“私钥”包含了公钥。这不是关于“生成”,而更多地是关于“提取”或“访问”。 - Romain
1
@Romain - 这就是我在我的回答中所说的 :) - Polynomial
2
确实如此。不过在这种情况下,你并没有回答问题——OP问的是“如何”以“相对容易”的方式提取其中一个 :) - Romain
2
这个答案是错误的。可以从私钥生成RSA公钥。 - tObi
2
确实。看来六年前我对RSA的理解相当有误。我已经编辑过了,包括了正确的答案。 - Polynomial
显示剩余5条评论

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