Java 是否可以从PEM文件中读取私钥,而无需遍历所有可能的算法或编写ASN.1解析器?

Java 是否可以从PEM文件中读取私钥,而无需遍历所有可能的算法或编写ASN.1解析器?,java,private-key,pki,Java,Private Key,Pki,我正在研究从PEM编码的DER文件中读取一个或多个私钥,我想知道这是否可以在不尝试所有可能的算法(这是丑陋和粗暴的)或编写ASN.1解析器的情况下可靠地完成 除了标准Java库之外,我试图在没有任何依赖项的情况下完成这项工作。我相信BouncyCastle可以做到这一点,但我对开箱即用Java的可能性感兴趣 PEM编码的DER文件是一种比较常见的文件,其外观如下: -----BEGIN EC PRIVATE KEY----- [base64-encoded DER data] -----END

我正在研究从PEM编码的DER文件中读取一个或多个私钥,我想知道这是否可以在不尝试所有可能的算法(这是丑陋和粗暴的)或编写ASN.1解析器的情况下可靠地完成

除了标准Java库之外,我试图在没有任何依赖项的情况下完成这项工作。我相信BouncyCastle可以做到这一点,但我对开箱即用Java的可能性感兴趣

PEM编码的DER文件是一种比较常见的文件,其外观如下:

-----BEGIN EC PRIVATE KEY-----
[base64-encoded DER data]
-----END EC PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
[base64 encoded DER data]
-----END PRIVATE KEY-----
在上面的示例中,文本表示密钥的类型:它是椭圆曲线密钥,因此我们可以向Java请求EC密钥工厂:

byte[] keyBytes = // get DER bytes
KeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("EC");
PrivateKey key = kf.generateKey(spec);
但也有可能该文件不公布其内容,如下所示:

-----BEGIN EC PRIVATE KEY-----
[base64-encoded DER data]
-----END EC PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
[base64 encoded DER data]
-----END PRIVATE KEY-----
在这种情况下,我只看到两种明显的可能性:

  • 遍历所有支持的算法,尝试所有算法并忽略某些错误

  • 实现一个ASN.1解析器来确定密钥的实际类型,然后使用右边的
    KeyFactory

  • 循环似乎很简单,但我不喜欢:

    byte[] keyBytes = // get DER bytes
    KeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
    PrivateKey key = null;
    for(String algorithm : new String[] { "EC", "RSA", "DSA" }) {
      try {
        KeyFactory kf = KeyFactory.getInstance(algorithm);
        key = kf.generatePrivateKey(keyBytes);
      } catch (....) {
        // Ignore "wrong algorithm" exceptions
      }
    }
    // "key" is either null (couldn't read/interpret) or non-null and OK
    
    这也可能会耗费大量时间,尽管通常密钥设置是一个“罕见”的操作,因此性能并不十分重要

    我唯一能想到的另一个选择是检查数据,以准确了解数据表示的内容,然后使用正确的类型:

    byte[] keyBytes = // get DER bytes
    KeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
    ASN1Parser a1p = new ASN1Parser();
    String algorithm  = a1p.parse(keyBytes).getAlgorithm();
    KeyFactory kf = KeyFactory.getInstance(algorithm);
    PrivateKey key = fk.generatePrivateKey(spec);
    
    与阅读X.509证书相比,您不必了解加载证书的算法:

    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    cf.generateCertificate(new ByteArrayInputStream(certBytes));
    
    我是否在API中遗漏了允许这种“只为我做”机制的内容,或者在加载关键材料之前必须知道算法


    编写ASN.1解析器并不简单,尽管它们存在于第三方库中,但我希望尽可能地限制依赖关系。

    您的第一个示例
    BEGIN/END EC私钥
    不是PKCS8密钥,任何JCA
    KeyFactory
    都无法读取。对于PKCS8 clear格式的
    开始/结束私钥
    您的ASN1Parser方法几乎是可行的;您需要
    .getAlgorithmIdentifier().getAlgorithm[AsString]()
    CertificateFactory
    (或者更确切地说是它背后的“引擎”)实际上为X.509 SPKI而不是PKCS8做了等效的工作。请记住,PKCS8和“传统”私钥PEM文件都可以使用非常不同的方法进行加密,这增加了复杂性。@dave_thompson_085我不想通过引入私钥加密使问题更加复杂。我没有意识到“BEGIN EC私钥”不是PKCS8,而是一个单独的标准(RFC5915)。