如何在从文件读取 public 或私钥时修复 "invalid key format"?

How to fix "invalid key format" while read public or private key from file?

我已经创建了 public 和私钥。 public 和从 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源代码:

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

它产生java.security.InvalidKeyException: invalid key format.

需要这方面的帮助。提前致谢。

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

然而,您忘记的是 X509EncodedKeySpec 是一种二进制格式,在 ASN.1 DER 中指定。您收到的是使用 ASCII 装甲的 PEM 编码密钥。换句话说,二进制文件已被编码为 base64,并添加了页眉和页脚行。这样做是为了使其与邮件(隐私增强邮件或 PEM)等文本界面兼容。

所以你要做的就是卸下盔甲。您最好使用 PEM reader(例如 Bouncy Castle 提供的 PEM)来完成此操作。

PemReader reader = new PemReader(new FileReader("spki.pem"));
PemObject readPemObject = reader.readPemObject();
String type = readPemObject.getType();
byte[] subjectPublicKey = readPemObject.getContent();

System.out.println(type);

X509EncodedKeySpec spec = new X509EncodedKeySpec(subjectPublicKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(spec);
System.out.println(pubKey);

打印

PUBLIC KEY

接着是

Sun RSA public key, 1024 bits
  params: null
  modulus: 119445732379544598056145200053932732877863846799652384989588303737527328743970559883211146487286317168142202446955508902936035124709397221178664495721428029984726868375359168203283442617134197706515425366188396513684446494070223079865755643116690165578452542158755074958452695530623055205290232290667934914919
  public exponent: 65537

对于怀疑论者 - - here is the definition of SubjectPublicKeyInfo from the X.509 specification:

SubjectPublicKeyInfo  ::=  SEQUENCE  {
     algorithm            AlgorithmIdentifier,
     subjectPublicKey     BIT STRING  }

其中 subjectPublicKey 包含 PKCS#1 格式的编码 public 密钥 - 当然,在 RSA public 密钥的情况下。

here是neubert密钥的解码版本,大家可以对比一下。 Java 中解析的键是同一个键。