Bouncy Castle(轻量级密码术包)是一种用于 Java 平台的开放源码的轻量级密码术包,它支持大量的密码术算法,并提供 JCE 1.2.1 的实现。最近项目上正好用到了Bouncy Castle,用于生成数字签名、数字信封,去网上找了很久,都没有找到合适的案例,而Bouncy Castle本身的文档也不多,最有用的就是官网上的Java Doc文档,因为这个问题也困扰了我好几天,最后还是通过阅读Java Doc文档找到了合适的类和方法,果然阅读Doc文档还是很有必要的啊。好了,话不多说,把我写的方法列出来,以防忘记,并给有同样需求的同学提供一些参考,其中有些代码也是参考了网上的写法,最有用的还是Doc文档里提供的一些示例写法,基本的需求已经能够满足了。

要使用Bouncy Castle,就需要引入相应的jar包,在官网就可以根据自己的需要进行下载,然后就可以使用了。

  1. import java.io.FileInputStream;
  2. import java.io.InputStream;
  3. import java.security.KeyStore;
  4. import java.security.PrivateKey;
  5. import java.security.Provider;
  6. import java.security.Security;
  7. import java.security.cert.Certificate;
  8. import java.security.cert.CertificateFactory;
  9. import java.security.cert.X509Certificate;
  10. import java.util.ArrayList;
  11. import java.util.Collection;
  12. import java.util.Iterator;
  13. import java.util.List;
  14.  
  15. import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
  16. import org.bouncycastle.cert.X509CertificateHolder;
  17. import org.bouncycastle.cert.jcajce.JcaCertStore;
  18. import org.bouncycastle.cms.CMSEnvelopedData;
  19. import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
  20. import org.bouncycastle.cms.CMSProcessableByteArray;
  21. import org.bouncycastle.cms.CMSSignedData;
  22. import org.bouncycastle.cms.CMSSignedDataGenerator;
  23. import org.bouncycastle.cms.CMSTypedData;
  24. import org.bouncycastle.cms.RecipientInformation;
  25. import org.bouncycastle.cms.RecipientInformationStore;
  26. import org.bouncycastle.cms.SignerInformation;
  27. import org.bouncycastle.cms.SignerInformationStore;
  28. import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
  29. import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
  30. import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
  31. import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
  32. import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
  33. import org.bouncycastle.jce.provider.BouncyCastleProvider;
  34. import org.bouncycastle.operator.ContentSigner;
  35. import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
  36. import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
  37. import org.bouncycastle.util.Store;
  38. import org.bouncycastle.util.encoders.Base64;
  39.  
  40. public class MessageUtil {
  41. private String ksType = "PKCS12";
  42.  
  43. /**
  44. * 生成数字签名
  45. * @param srcMsg 源信息
  46. * @param charSet 字符编码
  47. * @param certPath 证书路径
  48. * @param certPwd 证书密码
  49. * @return
  50. */
  51. public byte[] signMessage(String srcMsg, String charSet, String certPath, String certPwd) {
  52. String priKeyName = null;
  53. char passphrase[] = certPwd.toCharArray();
  54.  
  55. try {
  56. Provider provider = new BouncyCastleProvider();
  57. // 添加BouncyCastle作为安全提供
  58. Security.addProvider(provider);
  59.  
  60. // 加载证书
  61. KeyStore ks = KeyStore.getInstance(ksType);
  62. ks.load(new FileInputStream(certPath), passphrase);
  63.  
  64. if (ks.aliases().hasMoreElements()) {
  65. priKeyName = ks.aliases().nextElement();
  66. }
  67.  
  68. Certificate cert = (Certificate) ks.getCertificate(priKeyName);
  69.  
  70. // 获取私钥
  71. PrivateKey prikey = (PrivateKey) ks.getKey(priKeyName, passphrase);
  72.  
  73. X509Certificate cerx509 = (X509Certificate) cert;
  74.  
  75. List<Certificate> certList = new ArrayList<Certificate>();
  76. certList.add(cerx509);
  77.  
  78. CMSTypedData msg = (CMSTypedData) new CMSProcessableByteArray(
  79. srcMsg.getBytes(charSet));
  80.  
  81. Store certs = new JcaCertStore(certList);
  82.  
  83. CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
  84. ContentSigner sha1Signer = new JcaContentSignerBuilder(
  85. "SHA1withRSA").setProvider("BC").build(prikey);
  86.  
  87. gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
  88. new JcaDigestCalculatorProviderBuilder().setProvider("BC")
  89. .build()).build(sha1Signer, cerx509));
  90.  
  91. gen.addCertificates(certs);
  92.  
  93. CMSSignedData sigData = gen.generate(msg, true);
  94.  
  95. return Base64.encode(sigData.getEncoded());
  96.  
  97. } catch (Exception e) {
  98. e.printStackTrace();
  99. return null;
  100. }
  101. }
  102.  
  103. /**
  104. * 验证数字签名
  105. * @param signedData
  106. * @return
  107. */
  108. public boolean signedDataVerify(byte[] signedData) {
  109. boolean verifyRet = true;
  110. try {
  111. // 新建PKCS#7签名数据处理对象
  112. CMSSignedData sign = new CMSSignedData(signedData);
  113.  
  114. // 添加BouncyCastle作为安全提供
  115. Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
  116.  
  117. // 获得证书信息
  118. Store certs = sign.getCertificates();
  119.  
  120. // 获得签名者信息
  121. SignerInformationStore signers = sign.getSignerInfos();
  122. Collection c = signers.getSigners();
  123. Iterator it = c.iterator();
  124.  
  125. // 当有多个签名者信息时需要全部验证
  126. while (it.hasNext()) {
  127. SignerInformation signer = (SignerInformation) it.next();
  128.  
  129. // 证书链
  130. Collection certCollection = certs.getMatches(signer.getSID());
  131. Iterator certIt = certCollection.iterator();
  132. X509CertificateHolder cert = (X509CertificateHolder) certIt
  133. .next();
  134.  
  135. // 验证数字签名
  136. if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder()
  137. .setProvider("BC").build(cert))) {
  138. verifyRet = true;
  139. } else {
  140. verifyRet = false;
  141. }
  142. }
  143.  
  144. } catch (Exception e) {
  145. verifyRet = false;
  146. e.printStackTrace();
  147. System.out.println("验证数字签名失败");
  148. }
  149. return verifyRet;
  150. }
  151.  
  152. /**
  153. * 加密数据
  154. * @param srcMsg 源信息
  155. * @param certPath 证书路径
  156. * @param charSet 字符编码
  157. * @return
  158. * @throws Exception
  159. */
  160. public String envelopeMessage(String srcMsg, String certPath, String charSet) throws Exception {
  161. CertificateFactory certificatefactory;
  162. X509Certificate cert;
  163. // 使用公钥对对称密钥进行加密 //若此处不加参数 "BC" 会报异常:CertificateException -
  164. certificatefactory = CertificateFactory.getInstance("X.509", "BC");
  165. // 读取.crt文件;你可以读取绝对路径文件下的crt,返回一个InputStream(或其子类)即可。
  166. InputStream bais = new FileInputStream(certPath);
  167.  
  168. cert = (X509Certificate) certificatefactory.generateCertificate(bais);
  169.  
  170. //添加数字信封
  171. CMSTypedData msg = new CMSProcessableByteArray(srcMsg.getBytes(charSet));
  172.  
  173. CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
  174.  
  175. edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(
  176. cert).setProvider("BC"));
  177.  
  178. CMSEnvelopedData ed = edGen.generate(msg,
  179. new JceCMSContentEncryptorBuilder(PKCSObjectIdentifiers.rc4)
  180. .setProvider("BC").build());
  181.  
  182. String rslt = new String(Base64.encode(ed.getEncoded()));
  183.  
  184. System.out.println(rslt);
  185. return rslt;
  186. }
  187.  
  188. /**
  189. * 解密数据
  190. * @param encode 加密后的密文
  191. * @param certPath 证书路径
  192. * @param certPwd 证书密码
  193. * @param charSet 字符编码
  194. * @return
  195. * @throws Exception
  196. */
  197. public String openEnvelope(String encode, String certPath, String certPwd, String charSet) throws Exception {
  198. //获取密文
  199. CMSEnvelopedData ed = new CMSEnvelopedData(Base64.decode(encode.getBytes()));
  200.  
  201. RecipientInformationStore recipients = ed.getRecipientInfos();
  202.  
  203. Collection c = recipients.getRecipients();
  204. Iterator it = c.iterator();
  205.  
  206. // 加载证书
  207. KeyStore ks = KeyStore.getInstance(ksType);
  208. ks.load(new FileInputStream(certPath), certPwd.toCharArray());
  209.  
  210. String priKeyName = null;
  211. if (ks.aliases().hasMoreElements()) {
  212. priKeyName = ks.aliases().nextElement();
  213. }
  214.  
  215. // 获取私钥
  216. PrivateKey prikey = (PrivateKey) ks.getKey(priKeyName, certPwd.toCharArray());
  217.  
  218. byte[] recData = null;
  219. //解密
  220. if (it.hasNext()) {
  221. RecipientInformation recipient = (RecipientInformation) it.next();
  222.  
  223. recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(
  224. prikey).setProvider("BC"));
  225. }
  226.  
  227. return new String(recData, charSet);
  228. }
  229.  
  230. public MessageUtil() {
  231. Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
  232. }
  233.  
  234. }

【Java密码学】使用Bouncy Castle生成数字签名、数字信封的更多相关文章

  1. JAVA 解密pkcs7(smime.p7m)加密内容 ,公钥:.crt 私钥:.pem 使用Bouncy Castle生成数字签名、数字信封

    第三方使用公钥.crt加密后返回的内容,需要使用私钥解密.pem 返回内容格式如下 MIME-Version: 1.0 Content-Disposition: attachment; filenam ...

  2. 在C#中保存Bouncy Castle生成的密钥对

    在用Bouncy Castle的C#版API产生公钥和私钥 中产生了一对密钥对,可以用bouncy caslte提供的API进行保存 公钥方面的3个类,具体代码根据命名空间自行查看其源代码: Org. ...

  3. Java 密码学算法

    Java 密码学算法 候捷老师在< 深入浅出MFC 2e(电子版)>中引用林语堂先生的一句话: 只用一样东西,不明白它的道理,实在不高明 只知道How,不知道Why,出了一点小问题时就无能 ...

  4. 用Bouncy Castle的C#版API产生公钥和私钥

    开源API链接地址:The Legion of the Bouncy Castle Bouncy Castle,简称为BC,原本是java的一个开源JCE提供者,后来也提供了C#版本的API,我下载其 ...

  5. 加密 bouncy castle

    1.去官方站点下载Bouncy Castle的JCE Provider包 bcprov-ext-jdk15-145.jar 2.把jar文件复制到 $JAVA_HOME$\jre\lib\ext 目录 ...

  6. Java Security:公钥私钥、数字签名、消息摘要是什么

    1. 鲍勃有两把钥匙,一把是公钥,另一把是私钥. 2. 鲍勃把公钥送给他的朋友们----帕蒂.道格.苏珊----每人一把. 3. 苏珊要给鲍勃写一封保密的信.她写完后用鲍勃的公钥加密,就可以达到保密的 ...

  7. bouncy castle的配置

    Bouncy Castle 是一种用于 Java 平台的开放源码的轻量级密码术包.它支持大量的密码术算法,并提供 JCE 1.2.1 的实现.因为 Bouncy Castle 被设计成轻量级的,所以从 ...

  8. java工具类(三)之生成若干位随机数

    java 生成若干位随机数的问题 在一次编程的过程中偶然碰到一个小问题,就是需要生成一个4位数的随机数,如果是一个不到4位大的数字,前面可以加0来显示.因为要求最后是一个4位的整数,不带小数点.当时就 ...

  9. Bouncy Castle Crypto API c# port

    Bouncy Castle 是一种用于 Java 平台的开放源码的轻量级密码术包.它支持大量的密码术算法,并提供 JCE 1.2.1 的实现.现在有了C#的版本.下面是网站上的介绍 This port ...

随机推荐

  1. mybatis 学习三 mapper xml 配置信息

    mapper xml 映射文件 1,select 标签      简单是用就这样,其中resultType 代表从这条语句中返回的期望类型的类的完全限定名或别名.也可以使用resultMap对应的id ...

  2. java验证,”支持6-20个字母、数字、下划线或减号,以字母开头“这个的正则表达式怎么写?

    转自:https://yq.aliyun.com/wenzhang/show_96854 问题描述 java验证,”支持6-20个字母.数字.下划线或减号,以字母开头“这个的正则表达式怎么写? 验证” ...

  3. linux命令-rpm查询包

    安装了哪些rpm包呢 [root@wangshaojun Packages]# rpm -qa /////查看全部安装的包 [root@wangshaojun Packages]# rpm -qa l ...

  4. 0008_Python变量

    1.变量名:数字,字母,下划线组成,不能以数字开头,不能是Python内部关键字. 2.变量类型:数字,字符串,布尔值(首字母大写) 3.内存与变量: 4. =    赋值 ==   比较 is == ...

  5. Java探索之旅(11)——抽象类与接口

    1.Java数据类型       ❶不可变类,是指当创建了这个类的实例后,就不允许修改它的属性值. 它包括:         Primitive变量:boolean,byte, char, doubl ...

  6. 线程中event.wait() event_obj.set() 的使用

    #!/usr/bin/env python import threading # event.wait()##阻断线程向下执行 event_obj.set()#释放进程向下执行 def do(even ...

  7. Ubuntu W: GPG 错误:下列签名无效: BADSIG 84DBCE2DCEC45805 Launchpad PPA fo

    Ubuntu12.04  安装R语言的时候出现的报错. 研究了两个晚上,解决办法如下,跟参考贴有点出入: ############################################### ...

  8. python实现DNA序列字符串转换,互补链,反向链,反向互补链

    在生物信息学分析中,经常对DNA序列进行一系列操作,包括子序列截取,互补序列获取,反向序列获取,反向互补序列获取.在python语言中,可编写如下函数完成这些简单功能. 子序列截取 python中对序 ...

  9. CodeForces 279B Books (滑动窗口)

    题意:给定n本书的阅读时间,然后你从第 i 本开始阅读,问你最多能看多少本书在给定时间内. 析:就是一个滑动窗口的水题. 代码如下: #pragma comment(linker, "/ST ...

  10. node安装和配置

    windows 环境 安装node node下载地址 下载后点击安装,默认下一步即可(安装路径可更改为d:盘) 检测PATH环境变量是否配置了Node.js 点击开始=>运行=>输入&qu ...