Bouncy Castle(輕量級密碼術包)是一種用於 Java 平臺的開放源碼的輕量級密碼術包,它支持大量的密碼術算法,並提供 JCE 1.2.1 的實現。最近項目上正好用到了Bouncy Castle,用於生成數字簽名、數字信封,去網上找了好久,都沒有找到合適的案例,而Bouncy Castle自己的文檔也很少,最有用的就是官網上的Java Doc文檔,由於這個問題也困擾了我好幾天,最後仍是經過閱讀Java Doc文檔找到了合適的類和方法,果真閱讀Doc文檔仍是頗有必要的啊。好了,話很少說,把我寫的方法列出來,以防忘記,並給有一樣需求的同窗提供一些參考,其中有些代碼也是參考了網上的寫法,最有用的仍是Doc文檔裏提供的一些示例寫法,基本的需求已經可以知足了。java
要使用Bouncy Castle,就須要引入相應的jar包,在官網就能夠根據本身的須要進行下載,而後就可使用了。算法
import java.io.FileInputStream; import java.io.InputStream; import java.security.KeyStore; import java.security.PrivateKey; import java.security.Provider; import java.security.Security; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaCertStore; import org.bouncycastle.cms.CMSEnvelopedData; import org.bouncycastle.cms.CMSEnvelopedDataGenerator; import org.bouncycastle.cms.CMSProcessableByteArray; import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.CMSSignedDataGenerator; import org.bouncycastle.cms.CMSTypedData; import org.bouncycastle.cms.RecipientInformation; import org.bouncycastle.cms.RecipientInformationStore; import org.bouncycastle.cms.SignerInformation; import org.bouncycastle.cms.SignerInformationStore; import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder; import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder; import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient; import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; import org.bouncycastle.util.Store; import org.bouncycastle.util.encoders.Base64; public class MessageUtil { private String ksType = "PKCS12"; /** * 生成數字簽名 * @param srcMsg 源信息 * @param charSet 字符編碼 * @param certPath 證書路徑 * @param certPwd 證書密碼 * @return */ public byte[] signMessage(String srcMsg, String charSet, String certPath, String certPwd) { String priKeyName = null; char passphrase[] = certPwd.toCharArray(); try { Provider provider = new BouncyCastleProvider(); // 添加BouncyCastle做爲安全提供 Security.addProvider(provider); // 加載證書 KeyStore ks = KeyStore.getInstance(ksType); ks.load(new FileInputStream(certPath), passphrase); if (ks.aliases().hasMoreElements()) { priKeyName = ks.aliases().nextElement(); } Certificate cert = (Certificate) ks.getCertificate(priKeyName); // 獲取私鑰 PrivateKey prikey = (PrivateKey) ks.getKey(priKeyName, passphrase); X509Certificate cerx509 = (X509Certificate) cert; List<Certificate> certList = new ArrayList<Certificate>(); certList.add(cerx509); CMSTypedData msg = (CMSTypedData) new CMSProcessableByteArray( srcMsg.getBytes(charSet)); Store certs = new JcaCertStore(certList); CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); ContentSigner sha1Signer = new JcaContentSignerBuilder( "SHA1withRSA").setProvider("BC").build(prikey); gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder( new JcaDigestCalculatorProviderBuilder().setProvider("BC") .build()).build(sha1Signer, cerx509)); gen.addCertificates(certs); CMSSignedData sigData = gen.generate(msg, true); return Base64.encode(sigData.getEncoded()); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 驗證數字簽名 * @param signedData * @return */ public boolean signedDataVerify(byte[] signedData) { boolean verifyRet = true; try { // 新建PKCS#7簽名數據處理對象 CMSSignedData sign = new CMSSignedData(signedData); // 添加BouncyCastle做爲安全提供 Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); // 得到證書信息 Store certs = sign.getCertificates(); // 得到簽名者信息 SignerInformationStore signers = sign.getSignerInfos(); Collection c = signers.getSigners(); Iterator it = c.iterator(); // 當有多個簽名者信息時須要所有驗證 while (it.hasNext()) { SignerInformation signer = (SignerInformation) it.next(); // 證書鏈 Collection certCollection = certs.getMatches(signer.getSID()); Iterator certIt = certCollection.iterator(); X509CertificateHolder cert = (X509CertificateHolder) certIt .next(); // 驗證數字簽名 if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder() .setProvider("BC").build(cert))) { verifyRet = true; } else { verifyRet = false; } } } catch (Exception e) { verifyRet = false; e.printStackTrace(); System.out.println("驗證數字簽名失敗"); } return verifyRet; } /** * 加密數據 * @param srcMsg 源信息 * @param certPath 證書路徑 * @param charSet 字符編碼 * @return * @throws Exception */ public String envelopeMessage(String srcMsg, String certPath, String charSet) throws Exception { CertificateFactory certificatefactory; X509Certificate cert; // 使用公鑰對對稱密鑰進行加密 //若此處不加參數 "BC" 會報異常:CertificateException - certificatefactory = CertificateFactory.getInstance("X.509", "BC"); // 讀取.crt文件;你能夠讀取絕對路徑文件下的crt,返回一個InputStream(或其子類)便可。 InputStream bais = new FileInputStream(certPath); cert = (X509Certificate) certificatefactory.generateCertificate(bais); //添加數字信封 CMSTypedData msg = new CMSProcessableByteArray(srcMsg.getBytes(charSet)); CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator(); edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator( cert).setProvider("BC")); CMSEnvelopedData ed = edGen.generate(msg, new JceCMSContentEncryptorBuilder(PKCSObjectIdentifiers.rc4) .setProvider("BC").build()); String rslt = new String(Base64.encode(ed.getEncoded())); System.out.println(rslt); return rslt; } /** * 解密數據 * @param encode 加密後的密文 * @param certPath 證書路徑 * @param certPwd 證書密碼 * @param charSet 字符編碼 * @return * @throws Exception */ public String openEnvelope(String encode, String certPath, String certPwd, String charSet) throws Exception { //獲取密文 CMSEnvelopedData ed = new CMSEnvelopedData(Base64.decode(encode.getBytes())); RecipientInformationStore recipients = ed.getRecipientInfos(); Collection c = recipients.getRecipients(); Iterator it = c.iterator(); // 加載證書 KeyStore ks = KeyStore.getInstance(ksType); ks.load(new FileInputStream(certPath), certPwd.toCharArray()); String priKeyName = null; if (ks.aliases().hasMoreElements()) { priKeyName = ks.aliases().nextElement(); } // 獲取私鑰 PrivateKey prikey = (PrivateKey) ks.getKey(priKeyName, certPwd.toCharArray()); byte[] recData = null; //解密 if (it.hasNext()) { RecipientInformation recipient = (RecipientInformation) it.next(); recData = recipient.getContent(new JceKeyTransEnvelopedRecipient( prikey).setProvider("BC")); } return new String(recData, charSet); } public MessageUtil() { Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); } }