【问题标题】:How to fix "invalid key format" while read public or private key from file?从文件中读取公钥或私钥时如何修复“无效的密钥格式”?
【发布时间】:2019-12-10 08:39:49
【问题描述】:

我已经创建了公钥和私钥。 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 编码”公钥?因为没有像 PKCS#8 编码的公钥这样的; PKCS#8 仅用于私钥/密钥(实际上,the standard 的标题是“私钥信息语法规范版本 1.2”)。所以这是另一个 PHP 决定“做点什么”而不是简单地失败的例子,因为代码是不正确的
  • @Maarten-reinstateMonica - 在这种情况下,PKCS#8 指的是使用以下 ASN.1 格式的密钥:pastebin.com/4Gy0p9Qw 当然,PKCS#8 可能不是最好的描述,但不知道会是什么。这些键以-----BEGIN PUBLIC KEY----- 开头。这与 Xihar 的库所指的 PKCS#1 密钥形成对比,后者以 -----BEGIN RSA PUBLIC KEY----------BEGIN EC PUBLIC KEY----- 或其他开头。我明白了 - PKCS#1 只谈论 RSA 而不是 EC 公钥,但你还要怎么称呼它?
  • @Maarten-reinstateMonica - none-the-less, pastebin.com/c03kGJjh 是 OP (Xihar) 正在谈论的格式中的一个关键。
  • @neubert 最后一个是称为SubjectPublicKeyInfo 的结构,它是X.509 证书格式的一部分(因此在Java 中为X509EncodedKeySpec)。
  • @Maarten-reinstateMonica - 最佳名称的构成有点主观。对于私钥,PKCS#8 最终是一种包装格式,其中包含算法特定信息作为需要单独解码的八位字节字符串。从精神上讲,这与 Java 的 X509EncodedKeySpec 相同,在某些方面我觉得它可能是一个更好的名字,因为 X509EncodedKeySpec 可能会在不应该的时候让人联想到整个 X.509 规范的图像。

标签: java php cryptography rsa phpseclib


【解决方案1】:

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

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

所以你要做的就是卸下盔甲。您最好使用 PEM 阅读器,例如 Bouncy Castle 提供的阅读器。

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

对于怀疑论者 - hi neubert ;) - 这是来自 X.509 specification 的 SubjectPublicKeyInfo 的定义:

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

subjectPublicKey 包含 PKCS#1 格式的编码公钥 - 当然是 RSA 公钥。

here 是 neubert 密钥的解码版本,因此您可以进行比较。 Java中解析出来的key是同一个key。

【讨论】:

  • 非常感谢您的详细解决方案。它工作正常。
猜你喜欢
  • 2019-03-09
  • 2017-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-26
  • 2022-01-15
  • 2018-06-07
  • 2015-05-23
相关资源
最近更新 更多