【Java密码学】使用Bouncy Castle生成数字签名、数字信封
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生成数字签名、数字信封的更多相关文章
- JAVA 解密pkcs7(smime.p7m)加密内容 ,公钥:.crt 私钥:.pem 使用Bouncy Castle生成数字签名、数字信封
第三方使用公钥.crt加密后返回的内容,需要使用私钥解密.pem 返回内容格式如下 MIME-Version: 1.0 Content-Disposition: attachment; filenam ...
- 在C#中保存Bouncy Castle生成的密钥对
在用Bouncy Castle的C#版API产生公钥和私钥 中产生了一对密钥对,可以用bouncy caslte提供的API进行保存 公钥方面的3个类,具体代码根据命名空间自行查看其源代码: Org. ...
- Java 密码学算法
Java 密码学算法 候捷老师在< 深入浅出MFC 2e(电子版)>中引用林语堂先生的一句话: 只用一样东西,不明白它的道理,实在不高明 只知道How,不知道Why,出了一点小问题时就无能 ...
- 用Bouncy Castle的C#版API产生公钥和私钥
开源API链接地址:The Legion of the Bouncy Castle Bouncy Castle,简称为BC,原本是java的一个开源JCE提供者,后来也提供了C#版本的API,我下载其 ...
- 加密 bouncy castle
1.去官方站点下载Bouncy Castle的JCE Provider包 bcprov-ext-jdk15-145.jar 2.把jar文件复制到 $JAVA_HOME$\jre\lib\ext 目录 ...
- Java Security:公钥私钥、数字签名、消息摘要是什么
1. 鲍勃有两把钥匙,一把是公钥,另一把是私钥. 2. 鲍勃把公钥送给他的朋友们----帕蒂.道格.苏珊----每人一把. 3. 苏珊要给鲍勃写一封保密的信.她写完后用鲍勃的公钥加密,就可以达到保密的 ...
- bouncy castle的配置
Bouncy Castle 是一种用于 Java 平台的开放源码的轻量级密码术包.它支持大量的密码术算法,并提供 JCE 1.2.1 的实现.因为 Bouncy Castle 被设计成轻量级的,所以从 ...
- java工具类(三)之生成若干位随机数
java 生成若干位随机数的问题 在一次编程的过程中偶然碰到一个小问题,就是需要生成一个4位数的随机数,如果是一个不到4位大的数字,前面可以加0来显示.因为要求最后是一个4位的整数,不带小数点.当时就 ...
- Bouncy Castle Crypto API c# port
Bouncy Castle 是一种用于 Java 平台的开放源码的轻量级密码术包.它支持大量的密码术算法,并提供 JCE 1.2.1 的实现.现在有了C#的版本.下面是网站上的介绍 This port ...
随机推荐
- mybatis 学习三 mapper xml 配置信息
mapper xml 映射文件 1,select 标签 简单是用就这样,其中resultType 代表从这条语句中返回的期望类型的类的完全限定名或别名.也可以使用resultMap对应的id ...
- java验证,”支持6-20个字母、数字、下划线或减号,以字母开头“这个的正则表达式怎么写?
转自:https://yq.aliyun.com/wenzhang/show_96854 问题描述 java验证,”支持6-20个字母.数字.下划线或减号,以字母开头“这个的正则表达式怎么写? 验证” ...
- linux命令-rpm查询包
安装了哪些rpm包呢 [root@wangshaojun Packages]# rpm -qa /////查看全部安装的包 [root@wangshaojun Packages]# rpm -qa l ...
- 0008_Python变量
1.变量名:数字,字母,下划线组成,不能以数字开头,不能是Python内部关键字. 2.变量类型:数字,字符串,布尔值(首字母大写) 3.内存与变量: 4. = 赋值 == 比较 is == ...
- Java探索之旅(11)——抽象类与接口
1.Java数据类型 ❶不可变类,是指当创建了这个类的实例后,就不允许修改它的属性值. 它包括: Primitive变量:boolean,byte, char, doubl ...
- 线程中event.wait() event_obj.set() 的使用
#!/usr/bin/env python import threading # event.wait()##阻断线程向下执行 event_obj.set()#释放进程向下执行 def do(even ...
- Ubuntu W: GPG 错误:下列签名无效: BADSIG 84DBCE2DCEC45805 Launchpad PPA fo
Ubuntu12.04 安装R语言的时候出现的报错. 研究了两个晚上,解决办法如下,跟参考贴有点出入: ############################################### ...
- python实现DNA序列字符串转换,互补链,反向链,反向互补链
在生物信息学分析中,经常对DNA序列进行一系列操作,包括子序列截取,互补序列获取,反向序列获取,反向互补序列获取.在python语言中,可编写如下函数完成这些简单功能. 子序列截取 python中对序 ...
- CodeForces 279B Books (滑动窗口)
题意:给定n本书的阅读时间,然后你从第 i 本开始阅读,问你最多能看多少本书在给定时间内. 析:就是一个滑动窗口的水题. 代码如下: #pragma comment(linker, "/ST ...
- node安装和配置
windows 环境 安装node node下载地址 下载后点击安装,默认下一步即可(安装路径可更改为d:盘) 检测PATH环境变量是否配置了Node.js 点击开始=>运行=>输入&qu ...