使用 Bouncy Castle 在 Java 中复制“openssl smime”?
Posted
技术标签:
【中文标题】使用 Bouncy Castle 在 Java 中复制“openssl smime”?【英文标题】:Replicating 'openssl smime' in Java with Bouncy Castle? 【发布时间】:2012-10-04 17:10:01 【问题描述】:我手头有问题。不懂 Java 的同事正在使用 OpenSSL 命令对文件进行签名,如下所示:
openssl smime -binary -sign -certfile WWDR.pem -signer passcertificate.pem \
-inkey passkey.pem -in manifest.json -out signature -outform DER \
-passin pass:12345
如您所见,这里有三个文件被提供给 openssl 命令以生成签名。
现在我们想要使用 Java 复制相同的功能,因为我们假设要签名的内容将是动态的,并且本质上是服务器端的。我读到 BouncyCastle 是要走的路。但我不确定如何使用该库。我对密码学技术也不是很熟悉。我无法理解如何使用上述所有三个文件对manifest.json
中的内容进行签名。
如果有人可以指导我找到正确的代码或给我一个开始,我将非常感谢你的努力。
【问题讨论】:
这个问题有点过于宽泛了。如果您在互联网上找不到它,那么任何人都不太可能提供完整的示例。 【参考方案1】:我还必须在 java 中复制该 openssl 命令,这就是我完成它的方法。无需使用运行时。
public byte[] signMobileConfig(byte[] mobileconfig)
throws CertificateEncodingException, PEMException, FileNotFoundException, IOException, CertificateException, OperatorCreationException, CMSException
Security.addProvider(new BouncyCastleProvider());
X509CertificateHolder caCertificate = loadCertfile();
JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter();
X509Certificate serverCertificate = certificateConverter.getCertificate(loadSigner());
PrivateKeyInfo privateKeyInfo = loadInKey();
PrivateKey inKey = new JcaPEMKeyConverter().getPrivateKey(privateKeyInfo);
ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(inKey);
CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
JcaDigestCalculatorProviderBuilder digestProviderBuilder = new JcaDigestCalculatorProviderBuilder().setProvider("BC");
JcaSignerInfoGeneratorBuilder generatotBuilder = new JcaSignerInfoGeneratorBuilder(digestProviderBuilder.build());
generator.addSignerInfoGenerator(generatotBuilder.build(sha1Signer, serverCertificate));
generator.addCertificate(new X509CertificateHolder(serverCertificate.getEncoded()));
generator.addCertificate(new X509CertificateHolder(caCertificate.getEncoded()));
CMSProcessableByteArray bytes = new CMSProcessableByteArray(mobileconfig);
CMSSignedData signedData = generator.generate(bytes, true);
return signedData.getEncoded();
这是我加载文件的方式:
public X509CertificateHolder loadSigner() throws FileNotFoundException, IOException
InputStream inputStream = externalResourcesFacade.getResourceAsStream("path/to/.crt");
PEMParser parser = new PEMParser(new InputStreamReader(inputStream));
return (X509CertificateHolder) parser.readObject();
public PrivateKeyInfo loadInKey() throws FileNotFoundException, IOException
InputStream inputStream = externalResourcesFacade.getResourceAsStream("path/to/.key");
PEMParser parser = new PEMParser(new InputStreamReader(inputStream));
return (PrivateKeyInfo) parser.readObject();
public X509CertificateHolder loadCertfile() throws FileNotFoundException, IOException
InputStream inputStream = externalResourcesFacade.getResourceAsStream("path/to/.crt");
PEMParser parser = new PEMParser(new InputStreamReader(inputStream));
return (X509CertificateHolder) parser.readObject();
这是我的文件映射:
myCrtFile.crt -> signerCertHolder
myKeyFile.key -> privateKeyInfo
bundleCertificate.crt -> certificateHolder
【讨论】:
将此标记为答案。【参考方案2】:首先,不要因为难以理解 BouncyCastle 而感到难过。这是一个非常有用的 API,但它的文档记录很差。最好的办法是四处搜索可以教您如何使用 API 的示例。
由于我之前没有将 BouncyCastle 用于 SMIME(我主要将其用于 PGP 和/或 JCE),因此对“bouncycastle smime example
”的简短搜索让我找到了this page,特别是this example。
希望这是一个好的开始,进一步的谷歌搜索将有助于了解正在使用的 API 类。我怀疑仅凭这个示例就可以完成 80% 的任务。
如果您对输入文件的用途有任何混淆:
-certfile WWDR.pem
- 这是要在消息中指定的附加证书。签名消息的接收者在验证签名时会考虑此证书。
-signer passcertificate.pem
- 这是与您的签名密钥直接对应的证书。
-inkey passkey.pem
- 这是你的签名密钥
【讨论】:
【参考方案3】:因此,如果有人想知道我是如何解决上述问题的,我就是这样做的:
我使用了 Java 的 Runtime 对象!
String openSSLCommand = openssl smime -binary
-sign -certfile WWDR.pem -signer passcertificate.pem
-inkey passkey.pem -in manifest.json -out signature -outform DER
-passin pass:12345
Process process = Runtime.getRuntime().exec(openSSLCommand);
谢谢大家
【讨论】:
以上是关于使用 Bouncy Castle 在 Java 中复制“openssl smime”?的主要内容,如果未能解决你的问题,请参考以下文章
在没有 Bouncy Castle 的情况下,如何在 java 中从私有(ecdsa)生成公钥?
Java Bouncy Castle 生成的 ES256 密钥不适用于 JWT.io
使用 RSA Bouncy Castle 加密/解密无法正常工作