【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 ...
随机推荐
- 3 K8s安裝ELK+filebeat
1 Filebeat: apiVersion: v1 kind: Service metadata: name: XX spec: ports: - name: http port: targetPo ...
- bootstrap插件使用
首先,针对导航栏(单页面导航插件(缓慢跳转)) 引入插件:jquery.singlePageNav.min.js 下载链接:http://pan.baidu.com/s/1jHBaQxg 密码: ...
- ABP源码学习目录
ABP源码理解笔记 之前看过abp源码,但是时间久了很多也不记得了,所以近期打算重新看一遍,顺便做下笔记. 目录如下: Abp 框架启动流程分析 模块系统 依赖注入 模块配置 系统设置 工作单元的实现 ...
- 异常:Project configuration is not up-to-date with pom.xml解决方案
转自:https://www.cnblogs.com/zhujiabin/p/6343423.html 1. Description Resource Path Location ...
- java不定参数列表---乔老师没讲,但是传智有讲
**public static void sum(int i,int...srgs){** package com.xml; public class dremo1 { public static v ...
- mount/umount文件挂载
用法: mount [-lhV] mount -a [选项] mount [选项] [--source] <源> | [--target] <目录> mount [选项] &l ...
- 高级查询子条件查询filter
Filter Context 在查询过程中,只判断该文档是否满足条件,只有Yes或者No { "query":{ "bool":{ //布尔关键词 " ...
- Shrio00 Shiro角色授权、Shiro权限授权、开启Shiro缓存
1 需求01 用户进行过认证登录后,某些接口是有权限限制的:如何实现只有相应权限的用户才可以调用相应接口 2 修改shiro配置类 ShiroConfiguration package cn.xia ...
- 【机器学习】关联规则分析(一):Apriori
一.Apriori原理 Apriori是关联分析中较早的一种方法,主要用来挖掘那些频繁项集合,其思想是: 1.如果一个项目集合不是频繁集合,那么任何包含它的项目(超集)也一定不是频繁集. 2.如果一个 ...
- TCP三次握手四次挥手原理
转自http://www.cnblogs.com/liuxiaoming/archive/2013/04/27/3047803.html TCP协议三次握手原理: 首先,给张图片,建立TCP三次握手的 ...