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

要使用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());
} }

【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. binlog之二:怎么样安全删除mysql下的binlog日志

    删除binlog方法 第一种方法: mysql> show binary logs; 查看mysql bin-log日志,除了这个以外的,其它都可以使用删除.mysql> purge bi ...

  2. Spring整合JUnit4测试时,使用注解引入多个配置文件

    转自:https://blog.csdn.net/pwh309315228/article/details/62226372 一般情况下: @ContextConfiguration(Location ...

  3. Servlet编程实例 续1

    -----------------siwuxie095                                 在 LoginServlet 中,右键->Open Type Hierar ...

  4. Pig Latin JOIN (inner) 与JOIN (outer)的区别

    1.内连接(自然连接): 只有两个表相匹配的行才能在结果集中出现 2.外连接: 包括 (1)左外连接(左边的表不加限制) (2)右外连接(右边的表不加限制) (3)全外连接(左右两表都不加限制) 3. ...

  5. 使用python ftplib包递归下载文件夹及文件

    #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2018-06-11 09:35:49 # @Author : Yaheng Wang ...

  6. 【机器学习】关联规则分析(一):Apriori

    一.Apriori原理 Apriori是关联分析中较早的一种方法,主要用来挖掘那些频繁项集合,其思想是: 1.如果一个项目集合不是频繁集合,那么任何包含它的项目(超集)也一定不是频繁集. 2.如果一个 ...

  7. redis系列:通过队列案例学习list命令

    前言 这一篇文章将讲述Redis中的list类型命令,同样也是通过demo来讲述,其他部分这里就不在赘述了. 项目Github地址:https://github.com/rainbowda/learn ...

  8. JetBrains Rider 自定义项目编译路径

    在项目开发过程中有时可能想要自定义 Rider 的编译输出路径,它的具体设置方式如下: 1.选择需要更改配置的项目,右键选择 Properties 菜单.   2.在 Configurations 菜 ...

  9. SpringBoot第六篇:整合通用Mapper

    作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/10876339.html 版权声明:本文为博主原创文章,转载请附上博文链接! 引言   在以往的项 ...

  10. linux下编译Boost库

    下载源码 boost_1_66_0.tar.gz 生成编译工具 # tar axf boost_1_66_0.tar.gz # cd boost_1_66_0 # yum install gcc gc ...