用Bouncy Castle复制Java中的’openssl smime’?

我手头有问题。 我的不了解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复制相同的function,因为我们假设要签名的内容将是动态的,并且本质上是服务器端的。 我读到BouncyCastle是要走的路。 但我不知道如何使用该库。 我对密码技术也不是很熟悉。 我无法理解如何使用上面的所有三个文件来对manifest.json的内容进行签名。

如果有人可以指导我找到正确的代码或给我一个开始,我将非常感谢你的努力。

我还必须在java中复制那个openssl命令,这就是我完成它的方法。 无需使用Runtime。

 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 

首先,对于努力理解BouncyCastle并不感到难过。 这是一个非常有用的API,但它的文档记录很差。 最好的办法是搜索可以教您如何使用API​​的示例。

由于我之前没有使用BouncyCastle for SMIME(我主要用于PGP和/或JCE),对“ bouncycastle smime example ”的简短搜索已经把我带到了这个页面 ,特别是这个例子 。

希望这是一个良好的开端,进一步的谷歌搜索将有助于理解正在使用的API类。 我怀疑只有这样的例子会让你获得80%的胜利。


如果您对输入文件的目的有任何疑惑:

-certfile WWDR.pem这是要在消息中指定的附加证书。 签名消息的收件人将在validation签名时考虑此证书。

-signer passcertificate.pem这是与您的签名密钥直接对应的证书。

-inkey passkey.pem这是你的签名密钥

所以,如果有人想知道我是如何解决上面的问题,那么我所做的就是:

我用过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); 

谢谢大家