使用PEM编码的加密私钥本地签名消息

我正在尝试使用PEM(X.509)证书(存储在磁盘上的privateKey.pem文件中)来签署通过Java中的套接字发送的消息,但是在找到一个接近的示例时遇到了很多麻烦。 我通常是一个C ++人,他只是踩着这个项目来帮忙,所以我把它们放在代码中有点困难,因为我不熟悉API。

不幸的是,我只限于Java(1.6.0 Update 16)标准的方法,所以虽然我发现了一个使用BouncyCastle的PEMReader的类似例子,但它对这个特定的项目没有多大帮助。

我的privateKey.pem密钥是passphrase protected,格式为:

-----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----- 

它们的密钥是使用OpenSSL生成的:

 openssl.exe genrsa -out private_key.pem 4096 

我无法在运行之前将此密钥转换为DER或其他格式,所需的任何转换都需要在代码内部完成,因为密钥需要易于更换且格式仍为PEM。

我听过各种各样的事情,我并不完全确定,并且希望这里的集体思想可以帮助把各个部分拉到一起。

我听说它说PEM证书需要Base64解码才能将其转换为可以使用的DER证书。 我有一个名为MiGBase64的Base64解码工具,但我不完全确定如何/何时需要解码。

我已经迷失在Java API文档中,试图追踪存在的15种不同类型的Keys,KeyStores,KeyGenerators,Certificates等,但我对它们中的任何一种都不熟悉,无法正确识别我需要的使用,以及如何一起使用它们。

基本算法看起来很简单,这就是为什么我无法编写同样简单的实现特别令人沮丧的原因:

1)从文件中读取privateKey.pem
2)使用密码短语将私钥加载到XXX类中以解密密钥
3)使用带有Signature类的密钥对象对消息进行签名

非常感谢帮助,特别是示例代码。 我一直在努力寻找这个问题的有用示例,因为大多数“关闭”示例都是使用BouncyCastle生成新密钥,或者只是使用不适用于此处的不同forms的密钥/类。

这似乎是一个非常简单的问题,但它让我发疯,任何非常简单的答案?

如果您使用的是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); } } } 

OpenSSL命令生成密钥对并以PKCS#1格式对其进行编码。 如果您不使用加密(没有为命令提供密码),则PEM只是用于PKCS#1 RSAPrivateKey的Base64编码的DER。

不幸的是,Sun的JCE没有提供公共接口来读取这种格式的密钥。 你有2个选择,

  1. 将密钥导入密钥库,您可以从那里读取密钥。 Keytool不允许导入私钥。 您可以找到其他工具来执行此操作。

  2. OAuth库具有处理此function的function。 看看这里的代码,

http://oauth.googlecode.com/svn/code/java/core/commons/src/main/java/net/oauth/signature/pem/PKCS1EncodedKeySpec.java