InvalidKeyException:无效的密钥格式 java

Roh*_*ohi 13 java digital-signature public-key-encryption public-key

我正在尝试从 Vault 检索公钥。它被秘密存储。

我正在尝试将检索到的字符串转换为公钥以验证签名。

示例公钥字符串如下所示

-----开始公钥----- MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQBWeqVZ8Ub/o4VQ8nnm888B /Ydqv2IN5bObxupZ7njMKuT/WPgwlK8+Wc0Xjhy82E51XW6E4/0um8sIQ1cxvoSO QsrfkRagD+ O9OrjQbb2TqrilDDhFx9EGjXuZpR3brDUufCG6SkypqiKSaMuoVoax c82TZ1uAIp5OSroWt1IdUkvam24X/7zDIf1l8XWCmbfCDrBb73hBYA4MgTjsSckC 5nz+GLcWTfz0wze4lwHCi1KYFv+1+WcYHWPLbqL tc8nzVqkuP5Ne/9HAFkaEAIw5 fKLccksaT/TLyIcrALcfuABlgX1yeBulVcbTAp+WiYRvo9+FKK23pbwkh+uy0tq1 AgMBAAE= -----结束公钥-----

我在我的秘密值中添加了相同的内容,并且没有格式。

但是,使用下面的代码,我在行中遇到错误 InvalidKeyException: INVALID KEY FORMAT

 PublicKey publicKey = fact.generatePublic(pubKeySpec);
Run Code Online (Sandbox Code Playgroud)

这是代码:

            String publicKeyAsString = secretClient.getSecret("key-name").getValue();
    
            byte[] keyContentAsBytes = publicKeyAsString.getBytes();
    
            KeyFactory fact = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(keyContentAsBytes);
            PublicKey publicKey = fact.generatePublic(pubKeySpec);
Run Code Online (Sandbox Code Playgroud)

用堆栈跟踪编辑:

Caused by: java.security.InvalidKeyException: invalid key format
    at sun.security.x509.X509Key.decode(X509Key.java:386) ~[?:?]
    at sun.security.x509.X509Key.decode(X509Key.java:401) ~[?:?]
    at sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:122) ~[?:?]
    at sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:330) ~[?:?]
    at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:235) ~[?:?]
Run Code Online (Sandbox Code Playgroud)

编辑:用于测试的公钥:

-----开始公钥----- MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQBWeqVZ8Ub/o4VQ8nnm888B /Ydqv2IN5bObxupZ7njMKuT/WPgwlK8+Wc0Xjhy82E51XW6E4/0um8sIQ1cxvoSO QsrfkRagD+ O9OrjQbb2TqrilDDhFx9EGjXuZpR3brDUufCG6SkypqiKSaMuoVoax c82TZ1uAIp5OSroWt1IdUkvam24X/7zDIf1l8XWCmbfCDrBb73hBYA4MgTjsSckC 5nz+GLcWTfz0wze4lwHCi1KYFv+1+WcYHWPLbqL tc8nzVqkuP5Ne/9HAFkaEAIw5 fKLccksaT/TLyIcrALcfuABlgX1yeBulVcbTAp+WiYRvo9+FKK23pbwkh+uy0tq1 AgMBAAE= -----结束公钥-----

PublicKeyAsString的值如下所示:

-----开始公钥----- MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQBWeqVZ8Ub/o4VQ8nnm888B /Ydqv2IN5bObxupZ7njMKuT/WPgwlK8+Wc0Xjhy82E51XW6E4/0um8sIQ1cxvoSO QsrfkRagD+ O9OrjQbb2TqrilDDhFx9EGjXuZpR3brDUufCG6SkypqiKSaMuoVoax c82TZ1uAIp5OSroWt1IdUkvam24X/7zDIf1l8XWCmbfCDrBb73hBYA4MgTjsSckC 5nz+GLcWTfz0wze4lwHCi1KYFv+1+WcYHWPLbqL tc8nzVqkuP5Ne/9HAFkaEAIw5 fKLccksaT/TLyIcrALcfuABlgX1yeBulVcbTAp+WiYRvo9+FKK23pbwkh+uy0tq1 AgMBAAE= -----结束公钥-----

jcc*_*ero 12

最初我认为您的问题与 Azure KeyVault Secret API 返回的信息类型有关,通常编码为 base 64。

在这种情况下,您需要在尝试执行实际的密钥材料处理之前执行正确的 Base 64 解码:

String publicKeyAsString = secretClient.getSecret("key-name").getValue();
    
byte[] keyContentAsBytes = Base64.getDecoder().decode(publicKeyAsString);
Run Code Online (Sandbox Code Playgroud)

但 Azure 客户端似乎以纯文本形式向您提供信息。

在本例中,秘密是 pem 编码的公钥。

该标准KeyFactory不允许您开箱即用地处理返回的信息,但可以稍加修改。例如,尝试以下操作:

// Actually
// String publicKeyAsString = secretClient.getSecret("key-name").getValue();

String publicKeyAsString =
    "-----BEGIN PUBLIC KEY-----\n" +
    "MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQBWeqVZ8Ub/o4VQ8nnm888B\n" +
    "/Ydqv2IN5bObxupZ7njMKuT/WPgwlK8+Wc0Xjhy82E51XW6E4/0um8sIQ1cxvoSO\n" +
    "QsrfkRagD+O9OrjQbb2TqrilDDhFx9EGjXuZpR3brDUufCG6SkypqiKSaMuoVoax\n" +
    "c82TZ1uAIp5OSroWt1IdUkvam24X/7zDIf1l8XWCmbfCDrBb73hBYA4MgTjsSckC\n" +
    "5nz+GLcWTfz0wze4lwHCi1KYFv+1+WcYHWPLbqLtc8nzVqkuP5Ne/9HAFkaEAIw5\n" +
    "fKLccksaT/TLyIcrALcfuABlgX1yeBulVcbTAp+WiYRvo9+FKK23pbwkh+uy0tq1\n" +
    "AgMBAAE=\n" +
    "-----END PUBLIC KEY-----";

String publicKeyPem = publicKeyAsString
    .replace("-----BEGIN PUBLIC KEY-----", "")
    .replaceAll("\\n", "")
    .replace("-----END PUBLIC KEY-----", "");

byte[] keyContentAsBytes =  Base64.getDecoder().decode(publicKeyPem);

try {
  KeyFactory fact = KeyFactory.getInstance("RSA");
  X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(keyContentAsBytes);
  PublicKey publicKey = fact.generatePublic(pubKeySpec);
  System.out.println(publicKey);
}catch (Throwable t) {
  t.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)

或者更好的是,使用 BouncyCastlePemReader来完成此任务:

try (
    Reader reader = new StringReader(publicKeyAsString);
    PemReader pemReader = new PemReader(reader)
) {
  KeyFactory fact = KeyFactory.getInstance("RSA");
  PemObject pemObject = pemReader.readPemObject();
  byte[] keyContentAsBytesFromBC = pemObject.getContent();
  X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(keyContentAsBytesFromBC);
  PublicKey publicKey = fact.generatePublic(pubKeySpec);
  System.out.println(publicKey);
} catch (Throwable t) {
  t.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)

请注意,我在变量的定义中包含了几个回车符publicKeyAsString,它们是程序处理信息所必需的。

请验证 Azure 是否以类似的方式返回 pem 编码密钥:如果不是这种情况,则很可能是问题的原因。

另外,请注意 Azure KeyVault 在您上传密钥时会返回该密钥:也许问题就在那里。请尝试以下操作:

PublicKey publicKey = ...
StringWriter writer = new StringWriter();
PemWriter pemWriter = new PemWriter(writer);
pemWriter.writeObject(
  new PemObject("PUBLIC KEY", publicKey.getEncoded())
);
pemWriter.flush();
pemWriter.close();
String publicKeyAsString = writer.toString();
// Upload to Azure KeyVault
Run Code Online (Sandbox Code Playgroud)