Java密码学

来源:互联网 发布:诺亚幻想 知乎 编辑:程序博客网 时间:2024/06/05 05:52

不知道数字信封的具体原理, 可以点击传送门

信息发送者首先利用随机产生的【对称密码】加密信息(因为非对称加密技术的速度比较慢),再利用接收方的【公钥】加密对称密码,被公钥加密后的对称密钥被称之为数字信封。在传递信息时,信息接收方要解密信息时,必须先用自己的私钥解密数字信封,得到对称密码,才能利用对称密码解密所得到的信息。

这里, 我们要的参数有以下

  1. 对称密钥或者对称密钥的生成算法
  2. 对方的公钥 (证书里含有)
  3. 正文(内容)

getCertificateChain这方式就是获取证书的array


证书的获取, 之前的文章里有提及, 使用pem格式也好, 使用keystore提取也好, 都可以.

CMSTypedData msg = new CMSProcessableByteArray(需要签名的内容);CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(cert)//证书(含公钥)        .setProvider("BC"));        CMSEnvelopedData ed = edGen.generate(                msg,                new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC)//对称加密的算法                        .setProvider("BC").build());

首先, 这段代码在BC的document或者源码都可以看到

org.bouncycastle.cms (Bouncy Castle Library 1.57 API Specification)

A package for processing RFC 3852 Cryptographic Message Syntax (CMS) objects - also referred to as PKCS#7 (formerly RFC 2630, 3369).

CMS是消息加密语法

1.数据处理

CMSTypedData msg = new CMSProcessableByteArray(content);

2.信封生成 (卧槽, 名字怎么这么长…)

CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(cert).setProvider("BC"));edGen.generate(                msg,                new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC)                        .setProvider("BC").build());

拆开来看

edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(cert).setProvider("BC"));

是将证书里的内容提取出来, 再进行内容的转换成BC的结构 (原来是java.security的内容).

这里的信息有

  1. 公钥 (进行加密)
  2. Issuer 发行者 SerialNumber 发行者序列 (识别)
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();CMSEnvelopedData ed = edGen.generate(数据,生成随机密钥);

3.返回CMSEnvelopedData信封加密数据


获取数字信封内容的代码

public byte[] openEnvelope(PrivateKey prikey) throws Exception {    Security.addProvider(new BouncyCastleProvider());    PEMParser pr = new PEMParser(new FileReader(envfile));    ContentInfo o = (ContentInfo) pr.readObject();//读取PEM格式的数字信封    //获取密文    CMSEnvelopedData ed = new CMSEnvelopedData(o.getEncoded());    RecipientInformationStore recipients = ed.getRecipientInfos();    //解密    ArrayList list = (ArrayList) recipients.getRecipients();    RecipientInformation recipient = (RecipientInformation) list.get(0);    return recipient.getContent(new JceKeyTransEnvelopedRecipient(            prikey).setProvider("BC"));}

步骤

1.封装原始数据 (接收人信息+内容) ,并给了个引用接收人信息对象

CMSEnvelopedData ed = new CMSEnvelopedData(数字信封);

获得接收人信息, 并读取对应接收人等信息 (这里 ,我们可以知道, 接收人可以不止一个人, 只有对应的密钥才能解开)
我们就一个接收人, 所以读取第一个即可

RecipientInformationStore recipients = ed.getRecipientInfos();ArrayList list = (ArrayList) recipients.getRecipients();RecipientInformation recipient = (RecipientInformation) list.get(0);

算法等的准备完成后 ,接收私钥并完成解密

byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(私钥 ).setProvider("BC"));

PS: 这里有个坑, 就是代码需要设置BC作为提供者, 缺少是运行不了

Security.addProvider(new BouncyCastleProvider());
原创粉丝点击