【问题标题】:How to extract the public key algorithm from a String public key?如何从字符串公钥中提取公钥算法?
【发布时间】:2021-12-23 05:56:11
【问题描述】:

我有一个字符串公钥,我正在尝试使用下面的代码将其转换为 Java PublicKey 对象,但是我不知道用于生成此公钥的算法。无论如何从字符串公钥中提取算法名称?

 String stringPubKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmRk7MSZQCX2u4UIQgVzma1JEo3yASVafls/5nw/V9T6e5EbsK64MM0KhsPH9aK/aElRt1+Rxtd1AsHVvsQJjKw==";
 byte[] publicBytes = Base64.getDecoder().decode(stringPubKey);
 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes);
 KeyFactory keyFactory = KeyFactory.getInstance(algorithmName);
 PublicKey publicKey = keyFactory.generatePublic(keySpec);

【问题讨论】:

    标签: java public-key


    【解决方案1】:

    我不确定,但我认为您提供的密钥规范具有算法。在此处查看 getAlgorithm() 方法:https://docs.oracle.com/javase/8/docs/api/index.html?java/security/KeyFactory.html

    也在这里 (https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#KeyFactoryEx) 我看到了这个:

    Algorithm Parameters Classes 与 Keys 和 Keyspecs 类似,算法的初始化参数由以下任一表示 算法参数或算法参数规范。根据用途 在这种情况下,算法可以直接使用参数,或者 参数可能需要转换为更便携的格式 传输或存储。

    一组参数的透明表示(通过 AlgorithmParameterSpec) 表示您可以访问每个参数值 在单独的集合中。您可以通过以下方式之一访问这些值 相应规范类中定义的 get 方法 (例如,DSAParameterSpec 定义了 getP、getQ 和 getG 方法,以 分别访问 p、q 和 g)。

    相比之下,AlgorithmParameters 类提供了一个不透明的 表示,您无法直接访问参数 字段。您只能获取与 参数集(通过 getAlgorithm)和某种编码 参数集(通过 getEncoded)。

    【讨论】:

      【解决方案2】:

      顺便说一句:您拥有的是 one 公钥的“字符串”(文本)表示,特别是 X.509 和 PKIX 中定义的 ASN.1 结构 SubjectPublicKeyInfo 的 base64 编码,以及默认情况下在 Java 加密中使用,如 X509EncodedKeySpec 的文档中所述,但在 Key 中进行了更全面的解释。公钥的许多其他“字符串”表示形式完全不同,并且在 Java 中不那么容易使用。

      Java 实际上有用于此结构和相关结构的类——并在处理 包含 SPKI 的 X.509 证书时使用它们——但它们是内部的且未记录,虽然在过去几年中可以只调用内部类,但 Java (Oracle) 现在正努力逐步使这变得更加困难或不可能,所以我不推荐它。

      如果您可以专门使用第三方代码BouncyCastle,这很容易。与您要求的最接近的方法是解析 SPKI 并从中获取算法“名称”——但这是 ASN.1 对象标识符(又名 OID)的形式,而不是 Java 通常使用的名称。 如果您使用 BouncyCastle provider (bcprov*.jar) 进行 KeyFactory 调用,则它具有将此 OID 的别名映射到正常名称:

          String stringPubKey = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmRk7MSZQCX2u4UIQgVzma1JEo3yASVafls/5nw/V9T6e5EbsK64MM0KhsPH9aK/aElRt1+Rxtd1AsHVvsQJjKw==";
          byte[] publicBytes = Base64.getDecoder().decode(stringPubKey);
          
          String oid = org.bouncycastle.asn1.x509.SubjectPublicKeyInfo.getInstance(publicBytes)
                  .getAlgorithm().getAlgorithm().toString(); /* yes, two different .getAlgorithm() ! */
          PublicKey pk = KeyFactory.getInstance(oid, new org.bouncycastle.jce.provider.BouncyCastleProvider())
                  .generatePublic(new X509EncodedKeySpec(publicBytes));
          System.out.println(oid + " -> " + pk.getAlgorithm());
      

      但是,如果您使用 bcpkix*.jar 库(这取决于 bcprov 是否可用但不一定已注册),它会处理与 any 提供程序的 OID 名称映射(如普通 SunEC)并管理一站式为您提供 KeyFactory:

          // setup as above
          /*PublicKey*/ pk = new org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter().getPublicKey(
                  org.bouncycastle.asn1.x509.SubjectPublicKeyInfo.getInstance(publicBytes));
          System.out.println(pk.getAlgorithm());
      

      【讨论】: