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. 【转】Pro Android学习笔记(十):了解Intent(上)

    目录(?)[-] Intent基本含义 系统的Intent Android引入了Intent的概念来唤起components,component包括:1.Activity(UI元件) 2.Servic ...

  2. VisualGDB系列1:VisualGDB总体概述

    根据VisualGDB官网(https://visualgdb.com)的帮助文档大致翻译而成.主要是作为个人学习记录.有错误的地方,Robin欢迎大家指正. 本文总体介绍VisualGDB能给你带来 ...

  3. springMVC绑定json参数之二(2.1.1)

    二.springmvc 接收不同格式的json字符串 1.首先扫盲几个知识点: 例子如下: 前台传递json对象(这里uu[0]的名字uu要和Test对象中的属性List<User>名称对 ...

  4. shell入门-awk-2

    awk的条件操作符 ///显示第一段有root的行 [root@wangshaojun ~]# awk -F ':' '$1=="root"' 1.txtroot:x:0:0:ro ...

  5. centos 7之文件共享

    一,安装过程 1.在VirtualBox的软件菜单里面选择 “设备”--“存储”,添加VBoxGuestAdditions.iso(在VirtualBox目录下).      2.在桌面上出现一个光驱 ...

  6. 【总结整理】http-https

    上面这种加密消息的方式就是对称加密,你知道如何加密,也知道如何解码.然后李雷跟韩梅梅用的字母表偏移的加密方法叫 Caesar cipher, 凯撒加密.现实世界中用的加密算法会更复杂,但是基本原理相同 ...

  7. Shrio00 Shiro角色授权、Shiro权限授权、开启Shiro缓存

    1 需求01 用户进行过认证登录后,某些接口是有权限限制的:如何实现只有相应权限的用户才可以调用相应接口 2 修改shiro配置类  ShiroConfiguration package cn.xia ...

  8. std::min error C2059: 语法错误:“::” 的解决方法

    std::min error C2059: 语法错误:"::" 的解决方法 下面这段代码: size_t n = std::min(count_, num_elements); 编 ...

  9. 20169219 linux内核原理与分析第二周作业

    "linux内核分析"的第一讲主要讲了计算机的体系结构,和各寄存器之间对数据的处理过程. 通用寄存器 AX:累加器 BX:基地址寄存器 CX:计数寄存器 DX:数据寄存器 BP:堆 ...

  10. 消息队列--RabbitMQ(一)

    1.消息队列概述 可以理解为保存消息的一个媒介/或者是个容器,与之相关有两个概念(即生产者(Publish)与消费者(Consumer)).所谓生产者,就是生产创造消息的一方,那么,消费者便是从队列中 ...