Java “如何修复”;无效的密钥格式";从文件中读取公钥或私钥时?

Java “如何修复”;无效的密钥格式";从文件中读取公钥或私钥时?,java,php,cryptography,rsa,phpseclib,Java,Php,Cryptography,Rsa,Phpseclib,我已经创建了公钥和私钥。php代码生成的公钥和私钥: <?php require __DIR__ . '/vendor/autoload.php'; use phpseclib\Crypt\RSA; $rsa = new RSA(); extract($rsa->createKey()); $rsa->setPrivateKeyFormat(RSA::PRIVATE_FORMAT_PKCS8); $rsa->setPubl

我已经创建了公钥和私钥。php代码生成的公钥和私钥:

<?php
    require __DIR__ . '/vendor/autoload.php';
    use phpseclib\Crypt\RSA;
    $rsa = new RSA();
    extract($rsa->createKey()); 
    $rsa->setPrivateKeyFormat(RSA::PRIVATE_FORMAT_PKCS8);
    $rsa->setPublicKeyFormat(RSA::PUBLIC_FORMAT_PKCS8);

    file_put_contents("privateKey.pem",$privatekey);
    file_put_contents("publicKey.pem", $publickey);
它生成
java.security.InvalidKeyException:无效密钥格式。


我需要帮助。提前感谢。

首先,如评论中所述,没有PKCS#8公钥。这意味着PHP库不知道它在说什么。相反,如果neubert是正确的,您似乎得到的是一个为X.509证书定义的结构,名为
X509EncodedKeySpec
。在Java代码中,您确实试图使用它来读取公钥

但是,您忘记的是
X509EncodedKeySpec
是ASN.1 DER中指定的二进制格式。您收到的是一个使用ASCII保护的PEM编码密钥。换句话说,二进制文件已编码为base64,并添加了页眉和页脚行。这样做是为了使其与文本接口(如邮件(隐私增强邮件或PEM))兼容

所以你要做的就是移除盔甲。最好使用Bouncy Castle提供的PEM阅读器来实现这一点

PemReader=newpemreader(newfilereader(“spki.pem”);
PemObject readPemObject=reader.readPemObject();
字符串类型=readPemObject.getType();
字节[]subjectPublicKey=readPemObject.getContent();
系统输出打印项次(类型);
X509EncodedKeySpec=新X509EncodedKeySpec(主题公钥);
KeyFactory kf=KeyFactory.getInstance(“RSA”);
RSAPublicKey publikey=(RSAPublicKey)kf.generatePublic(spec);
System.out.println(pubKey);
哪张照片

公钥

Sun RSA公钥,1024位
参数:null
模数:11944573232327954598056145200053932732877863846799652384989588303752732874397055988321114648728631716814244695550890293603512470937221178664495142802998472668683753168203283261713419770651542536651368444940702230798655555555555555717164202446955555555555590239046794919
公众指数:65537

对于怀疑论者——以下是主题PublicKeyInfo的定义:

SubjectPublicKeyInfo::=序列{
算法识别器,
subjectPublicKey位字符串}
其中
subjectPublicKey
包含PKCS#1格式的编码公钥-当然是RSA公钥


是纽伯特钥匙的解码版本,你可以比较一下。Java中解析的密钥是同一个密钥。

能否包含“PKCS#8编码”公钥?因为没有PKCS#8编码的公钥;PKCS#8仅用于私钥/密钥(实际上,其标题是“私钥信息语法规范1.2版”)。因此,这是另一个PHP决定“有所作为”而不是因为代码不正确而失败的例子。@Maarten-Monica-在本例中,PKCS#8所指的是使用以下ASN.1格式的密钥:当然,PKCS#8可能不是最好的描述,但idk应该是什么。此类密钥以
----开始公钥------
开始。这与Xihar的库所称的PKCS#1密钥形成了对比,PKCS#1密钥以
---BEGIN RSA公钥------
---BEGIN EC公钥------
或其他任何形式开始。我明白了-PKCS#1只讨论RSA而不是EC公钥,但你还打算称它为什么?@Maarten-Monica-尽管如此,我还是希望它是OP(Xihar)所讨论的格式的密钥。@neubert最后一个是名为
SubjectPublicKeyInfo
的结构,它是X.509证书格式的一部分(因此,
X509EncodedKeySpec
在Java中)@Maarten-Monica-最佳名称的构成有点主观。对于私钥PKCS#8最终是一种包装格式,包含特定于算法的信息,作为需要单独解码的八位字节字符串。从精神上讲,这与Java的
X509EncodedKeySpec
是一样的,在某些方面我觉得它是y是一个更好的名字,因为
X509EncodedKeySpec
可能会在不应该出现的时候出现整个X.509规范的图像。非常感谢您提供的详细解决方案。它工作正常。
    import java.io.*;
    import java.security.*;
    import java.security.spec.*;

    public class PublicKeyReader {

    public static PublicKey get(String filename)
        throws Exception {

        File f = new File(filename);
        FileInputStream fis = new FileInputStream(f);
        DataInputStream dis = new DataInputStream(fis);
        byte[] keyBytes = new byte[(int)f.length()];
        dis.readFully(keyBytes);
        dis.close();

        X509EncodedKeySpec spec =
          new X509EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePublic(spec);
      }

   public static void main (String [] args) throws Exception {
    PublicKeyReader publicKeyReader = new PublicKeyReader();
    PublicKey publicKey = publicKeyReader.get("key/testPub.pem");
    System.out.println(publicKey);
   }
   }