用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);
谢谢大家