【发布时间】:2021-09-02 09:10:54
【问题描述】:
我目前正在尝试读取包含私钥的 pem 文件。密钥是由另一个使用 Python 的系统生成的,我收到一个 pem 文件,我需要从中读取私钥。 pem 文件的内容如下所示:
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,F58A9640CD4A47DF1C8FB281C7B36D69
jLMaq0JWEV/rJnM0Pxho7jyY/c5I7lZ8mCawGINPDz7Zpdv6MEsc8rFjVZHur4+1
I3AxD8NDNkhNVofGpSlAnciOVeILwsScgJSfxHA14s+SCqOX3q4zEB+jJDDfJGn3
w+7I9X0qB4MYSWLwT8r3GUAETigeJZ7m7cSlcO9cSMg=
-----END EC PRIVATE KEY-----
在另一个系统中,我的一位同事正在使用 Python 生成和读取 pem 文件。他是这样读钥匙的:
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec
def read(path):
with open(path, "rb") as f:
data = f.read()
return data
# Load a PEM-encoded, encrypted private key
def load(path, passphrase):
return serialization.load_pem_private_key(read(path), passphrase)
现在,我必须用 Java 阅读这个生成的 pem 文件。到目前为止,我尝试通过 FileInputStream 读取文件的内容,并尝试使用 EncodedKeySpec 类生成私钥:
FileInputStream is = new FileInputStream(file);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(is.readAllBytes());
KeyFactory factory = KeyFactory.getInstance("EC");
PrivateKey key = factory.generatePrivate(spec);
这种方式虽然我总是收到有关的异常
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : Short read of DER length
at jdk.crypto.ec/sun.security.ec.ECKeyFactory.engineGeneratePrivate(ECKeyFactory.java:169)
at java.base/java.security.KeyFactory.generatePrivate(KeyFactory.java:390)
at my.package.name.here.MyInputReader.loadKey(MyInputReader.java:107)
at my.package.name.here.MyInputReader.createDLCBinary(MyInputReader.java:47)
at my.package.name.here.MyInputReaderTest.test(MyInputReaderTest.java:11)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.security.InvalidKeyException: IOException : Short read of DER length
at java.base/sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:350)
at java.base/sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:355)
at jdk.crypto.ec/sun.security.ec.ECPrivateKeyImpl.<init>(ECPrivateKeyImpl.java:74)
at jdk.crypto.ec/sun.security.ec.ECKeyFactory.implGeneratePrivate(ECKeyFactory.java:237)
at jdk.crypto.ec/sun.security.ec.ECKeyFactory.engineGeneratePrivate(ECKeyFactory.java:165)
... 69 more
我注意到我的同事在从 pem 文件中读取密钥时使用了密码,我也可以访问此密码。虽然我没有找到任何功能来实际使用文件内容上的密码。我可能在这里遗漏了一些重要的东西,我希望你能帮我解决这个问题。
更新: 这个问题也在这个线程中讨论,并有一些可能的解决方案:How to read a password encrypted key with java?
【问题讨论】:
-
您的 EC 私钥采用“传统”OpenSSL 编码(“SEC1”)并使用 AES-256-CBC 加密。要在 Java 中读取这种键,您需要像 BouncyCastle 这样的外部库。或者...您使用 ASN1 阅读器从头开始编写代码。
-
(@MichaelFehr) ... 或使用命令行
openssl pkey(或openssl pkcs8 -topk8 -nocrypt)将其转换为未加密的 PKCS8,也可选择转换为 DER,如果您可以接受这样的未加密密钥环境。 PKCS8 未加密的 DER 可以直接在 KeyFactory 的 PKCS8EncodedKeySpec 中使用,PKCS8 未加密的 PEM 只需删除 BEGIN/END 行和换行符,其余部分进行 base64 解码即可转换为 DER。 -
嗯,我明白了。感谢您的意见,我会尽快尝试。
标签: java bouncycastle private-key pem