Java 使用 PEM 编码的加密私钥对消息进行本地签名
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1580012/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using a PEM encoded, encrypted private key to sign a message natively
提问by KevenK
I'm trying to use a PEM(X.509) certificate (stored in a privateKey.pem file on disk) to sign messages sent via sockets in Java, but am having a lot of trouble finding an example that's close. I'm normally a C++ guy who's just stepping in to help on this project, so it's been a little difficult for me to put it all together into code that works when I'm unfamiliar with the APIs.
我正在尝试使用 PEM(X.509) 证书(存储在磁盘上的 privateKey.pem 文件中)对通过 Java 中的套接字发送的消息进行签名,但是我很难找到一个接近的示例。我通常是一个 C++ 人,他只是介入帮助这个项目,所以当我不熟悉 API 时,将它们全部整合到代码中对我来说有点困难。
Unfortunately, I'm limited to methods that come standard with Java (1.6.0 Update 16), so although I found a similar example using BouncyCastle's PEMReader, it hasn't helped much on this particular project.
不幸的是,我仅限于 Java(1.6.0 更新 16)的标准方法,所以虽然我发现了一个使用BouncyCastle的PEMReader的类似示例,但它对这个特定项目并没有太大帮助。
My privateKey.pem key is passphrase protected, in the form of:
我的 privateKey.pem 密钥受密码保护,形式如下:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED DEK-Info:
DES-EDE3-CBC,63A862F284B1280B
[...]
tsjQI4H8lhOBuk+NelHu7h2+uqbBQzwkPoA8IqbPXUz+B/MAGhoTGl4AKPjfm9gu
OqEorRU2vGiSaUPgDaRhdPKK0stxMxbByUi8xQ2156d/Ipk2IPLSEZDXONrB/4O5
[...]
-----END RSA PRIVATE KEY-----
They key was generated using OpenSSL:
他们的密钥是使用 OpenSSL 生成的:
openssl.exe genrsa -out private_key.pem 4096
I am unable to convert this key to a DER or other format prior to runtime, any conversions necessary will need to be done internally in code, as the key needs to be easily replaceable and the format will remain PEM.
我无法在运行之前将此密钥转换为 DER 或其他格式,任何必要的转换都需要在代码内部完成,因为密钥需要易于替换并且格式将保持 PEM。
I've heard a mix of things which I'm not entirely sure about, and was hoping the collective minds here at SO could help pull the pieces together.
我听到了一些我不太确定的事情,希望 SO 的集体思想可以帮助将这些碎片整合在一起。
I've heard it said that the PEM certificate needs Base64 Decoded to convert it into a DER certificate that can be used. I have a Base64 Decoding tool called MiGBase64but am not entirely sure how/when this decoding needs done.
我听说 PEM 证书需要 Base64 Decoded 才能将其转换为可以使用的 DER 证书。我有一个名为MiGBase64的 Base64 解码工具,但我不完全确定如何/何时完成此解码。
I've gotten lost in the Java API docs trying to track down the 15 different types of Keys, KeyStores, KeyGenerators, Certificates, etc that exist, but I'm not familiar enough with any of them to properly identify which I need to be using, and how to use them together.
我在 Java API 文档中迷失了方向,试图追踪存在的 15 种不同类型的密钥、密钥库、密钥生成器、证书等,但我对它们中的任何一个都不够熟悉,无法正确识别我需要的是哪一个使用,以及如何一起使用它们。
The basic algorithm seems pretty simple, which is why it has been particularly frustrating that I haven't been able to write an equally simple implementation:
基本算法看起来非常简单,这就是为什么我无法编写同样简单的实现特别令人沮丧的原因:
1) Read the privateKey.pem from file
2) Load the private Key into XXX class, using the Passphrase to decrypt the key
3) Use the key object with the Signature class to sign the message
1) 从文件中读取 privateKey.pem
2) 将私钥加载到 XXX 类中,使用 Passphrase 解密密钥
3) 使用带有 Signature 类的密钥对象对消息进行签名
Help with this, especially example code, is greatly appreciated. I've been struggling to find useful examples for this problem, as most 'close' examples are generating new keys, using BouncyCastle, or just otherwise using different forms of keys/classes not applicable here.
非常感谢对此的帮助,尤其是示例代码。我一直在努力寻找解决这个问题的有用示例,因为大多数“关闭”示例正在生成新密钥、使用 BouncyCastle,或者只是使用此处不适用的不同形式的密钥/类。
This seems like a really simple problem but it's driving me crazy, any really simple answers?
这似乎是一个非常简单的问题,但它让我发疯了,有什么非常简单的答案吗?
采纳答案by Kevin
If you're using BouncyCastle, try the following:
如果您使用的是 BouncyCastle,请尝试以下操作:
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.security.KeyPair;
import java.security.Security;
import java.security.Signature;
import java.util.Arrays;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMReader;
import org.bouncycastle.openssl.PasswordFinder;
import org.bouncycastle.util.encoders.Hex;
public class SignatureExample {
public static void main(String [] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
String message = "hello world";
File privateKey = new File("private.pem");
KeyPair keyPair = readKeyPair(privateKey, "password".toCharArray());
Signature signature = Signature.getInstance("SHA256WithRSAEncryption");
signature.initSign(keyPair.getPrivate());
signature.update(message.getBytes());
byte [] signatureBytes = signature.sign();
System.out.println(new String(Hex.encode(signatureBytes)));
Signature verifier = Signature.getInstance("SHA256WithRSAEncryption");
verifier.initVerify(keyPair.getPublic());
verifier.update(message.getBytes());
if (verifier.verify(signatureBytes)) {
System.out.println("Signature is valid");
} else {
System.out.println("Signature is invalid");
}
}
private static KeyPair readKeyPair(File privateKey, char [] keyPassword) throws IOException {
FileReader fileReader = new FileReader(privateKey);
PEMReader r = new PEMReader(fileReader, new DefaultPasswordFinder(keyPassword));
try {
return (KeyPair) r.readObject();
} catch (IOException ex) {
throw new IOException("The private key could not be decrypted", ex);
} finally {
r.close();
fileReader.close();
}
}
private static class DefaultPasswordFinder implements PasswordFinder {
private final char [] password;
private DefaultPasswordFinder(char [] password) {
this.password = password;
}
@Override
public char[] getPassword() {
return Arrays.copyOf(password, password.length);
}
}
}
回答by ZZ Coder
The OpenSSL command generate key-pair and encodes it in PKCS#1 format. If you don't use the encryption (didn't provide password for the command), the PEM is simply Base64-encoded DER for the PKCS#1 RSAPrivateKey.
OpenSSL 命令生成密钥对并将其编码为 PKCS#1 格式。如果您不使用加密(没有为命令提供密码),则 PEM 只是 PKCS#1 RSAPrivateKey 的 Base64 编码 DER。
Unfortunately, Sun's JCE doesn't provide a public interface to read the key in this format. You have 2 options,
不幸的是,Sun 的 JCE 没有提供公共接口来读取这种格式的密钥。你有2个选择,
Import the key into keystore and you can read it from there. Keytool doesn't allow for importing of private keys. You can find other tools to do this.
OAuth library has a function to handle this. Look at code here,
将密钥导入密钥库,您可以从那里读取它。Keytool 不允许导入私钥。您可以找到其他工具来执行此操作。
OAuth 库有一个函数来处理这个。看这里的代码,