一、    基础
        BouncyCastle,是一个用于Java平台的轻量级开源密码包。目前除了支持Java外,也支持C#。授权遵循MIT协议。
        BouncyCastle几乎完成了当前主流的所有加解密算法、证书生成签发等内容。作为JCE(Java Cryptography Extension)的提供者(Provider),BouncyCastle对如消息摘要处理、非对称加密密钥对生成、证书签名处理等都提供了良好的支持。
二、    关键词
        ECDSA,椭圆曲线数字签名算法(ECDSA)是使用椭圆曲线密码(ECC)对数字签名算法(DSA)的模拟。具体算法不在此描述。
        secp256r1,可以简单理解为一种ECC,或者就简单理解为一种曲线。
        非对称加密算法,可以理解为通信的双方,各自有一套密钥对。即公钥和私钥。私钥自己保存,公钥可公开。在双方通信时,一方先使用对方的公钥对数据加密,另一方在收到数据后,用自己的私钥解密数据。
        数字证书,包含公钥、主体信息、扩展部分等诸多内容,最后使用签名算法,用私钥对这些信息进行签名。在双方通信过程中,通过数字证书的传递,可以理解为识别对方主体信息、并交换了公钥,及对其中的签名进行认证(判断可信度)。
CA,即电子商务认证中心,可以理解为一个权威的第三方机构。假设一种情景,如果两人交互,在彼此不认识的情况下,又无法识别对方的证件真伪时,一般是很难互相取得信任的。但是,如果存在双方都信任的第三个人(中间人),这个事情就好办多了。CA就类似于这个中间人。CA会对双方的证书进行签名,这样在一方与另一方通信时,只要携带被共同信任的CA签名过的证书,就可以认为这方可以信任。
        CSR,即证书签名请求,包含自身的公钥、主体信息及与公钥对应的私钥自签名。一方可向CA机构提出证书签名请求,从而获取经CA签名过的数字证书。
三、    自签名步骤
        一个自签名的步骤可按照如下顺序进行:
(1)    生成自签名根CA证书(含证书及私钥)
(2)    生成待签名主体的密钥对(含公钥及私钥)
(3)    生成待签名主体的证书签名请求(CSR)
(4)    解析CSR,并根据自签名根CA证书和其对应的私钥,对待签名主体进行签名
四、    生成自签名根CA证书
        这个步骤可以使用openssl进行,如在安装有openssl的电脑上,用命令行工具执行以下脚本:

openssl ecparam -genkey -name secp256r1 | openssl ec -out privateKeys\oemRootCA.key -aes128 -passout file:passphrase.txt
openssl req -new -x509 -days 36500 -sha256 -key privateKeys\oemRootCA.key -set_serial 05 -passin file:passphrase.txt -config configs\oemRootCACert.cnf -extensions ext -out certs\oemRootCA.pem

第一句使用ecparam,设置ec(用椭圆曲线算法生成密钥)时使用的曲线为secp256r1,接下来,使用ec命令,生成私钥。并使用128位AES对这个私钥的内容加密。
        第二句提出证书签名请求,并使用SHA256算法进行签名,生成证书为X.509格式的。
经过这命令后,可生成根CA证书及私钥文件。

五、    生成待签名主体的密钥对
        有了根CA证书(虽然是自签名的,但也没关系),我们就可以在Java中使用BouncyCastle库,生成密钥对了。
        在使用BouncyCastle前,首先需要将BouncyCastle加入到Security的提供者中:

Security.addProvider(new BouncyCastleProvider());

这样,以后在使用BouncyCastle时,提供者就可以使用名称“BC”获取。比如:

provider = Security.getProvider("BC");

默认情况下,虚拟机会使用Java自带的默认提供者进行签名等相关操作,但是自带的提供者库是不支持很多新的算法和曲线的。
        之后,可如下生成密钥对:

// 获取椭圆曲线签名算法ECDSA生成器
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECDSA", provider);
// 设置椭圆曲线参数
ECGenParameterSpec ecSpec = new ECGenParameterSpec(ecName);
// 生成密钥对
KeyPair pair = keyGen.initialize(ecSpec);

六、    生成证书签名请求
        在生成证书签名请求之前,还需要准备几个内容:主体信息、扩展信息等。
(1)    主体信息
        主体信息(Subject),一般包含了ASN1定义的一些内容,如:CN,commonName代表公用名;O,organization代表组织;OU,organizationUnit代表组织单位,等等。
        在Java中,我们使用X500Name构建这个信息:

X500NameBuilder builder = new X500NameBuilder(X500Name.getDefaultStyle());
builder.addRDN(BCStyle.C, country);
builder.addRDN(BCStyle.O, organization);
builder.addRDN(BCStyle.OU, organizationalUnit);
builder.addRDN(BCStyle.CN, commonName);
builder.addRDN(BCStyle.DC, domainComponent);
builder.build();

(2)    扩展信息
        扩展信息(Extensions),一般包含了ASN1定义的一些证书次要内容,如:basicConstraints、keyUsage等。
        这里,我们使用一个列表,构建Extension的集合:

List<Extension> extensions = new ArrayList<Extension>();
BasicConstraints basicConstraints = new BasicConstraints(isCA);
Extension extension = new Extension(Extension.basicConstraints, true, new DEROctetString(basicConstraints));
extensions.add(extension);
KeyUsage keys = new KeyUsage(keyUsage);
extension = new Extension(Extension.keyUsage, keyUsageCritical, new DEROctetString(keys));
extensions.add(extension);

(3)    构建证书签名请求
        证书签名请求实际上是使用待签名主体的私钥,对其主体信息及公钥信息进行自签名的过程:

PKCS10CertificationRequestBuilder builder = new PKCS10CertificationRequestBuilder(subject, publicKeyInfo);
if (extensions != null && extensions.size() > 0)
{for (Extension extension : extensions) {if (extension == null) {continue;}builder.addAttribute(extension.getExtnId(), extension.getParsedValue());}
}
ContentSigner signer = null;
PKCS10CertificationRequest csr = null;
try {//获取签名信息signer = getContentSigner(privateKey, signatureAlgorithm);//构建证书签名请求csr = builder.build(signer);
}catch(IOException|OperatorCreationException e)
{//获取签名信息失败e.printStackTrace();
}

在签名前,我们需要准备好主体信息,及公钥信息。并采用指定的签名算法,对内容进行签名。签名后得到的就是证书签名请求文件了。
        证书签名请求文件,包含了待签名主体的信息、待签名主体的公钥及用与公钥对应的私钥进行的签名。
七、    签发证书
        这一步,我们使用先前生成的根CA证书及其对应私钥,对证书请求文件进行签名。
        首先,我们需要通过CA证书,得到CA的主体信息,这个信息以后会关联到最后签发后的证书中的父级主题中。

X500Principal principal = certIssuer.getSubjectX500Principal();
X500Name parentSubjectDn = X500Name.getInstance(principal.getEncoded());

这里的certIssuer就是X509格式证书,即X509Certificate。
        接下来,我们就可以签发证书了:

//初始化证书的序列号
BigInteger serial = BigInteger.probablePrime(32, new Random());
//日期转化
Date notBeforeDate = Date.from(notBefore.atZone(ZoneId.systemDefault()).toInstant());
Date notAfterDate = Date.from(notAfter.atZone(ZoneId.systemDefault()).toInstant());
//证书签名构建器
X509v3CertificateBuilder builder = new X509v3CertificateBuilder(issuerDn, serial, notBeforeDate, notAfterDate, csr.getSubject(), csr.getSubjectPublicKeyInfo());
if (extensions != null && extensions.size() > 0)
{for (Extension extension : extensions) {if (extension == null) {continue;}builder.addExtension(extension.getExtnId(), extension.isCritical(), extension.getParsedValue());}JcaX509ExtensionUtils sdf = new JcaX509ExtensionUtils();SubjectKeyIdentifier subjectKeyIdentifier =  sdf.createSubjectKeyIdentifier(csr.getSubjectPublicKeyInfo());builder.addExtension(Extension.subjectKeyIdentifier, false, subjectKeyIdentifier);
}
//获取签名(签发证书时,使用CA的私钥来签名)
ContentSigner signer = getContentSigner(issuerPrivateKey, signatureAlgorithm);
X509CertificateHolder holder = builder.build(signer);
// BC加密算法
X509Certificate cert = new JcaX509CertificateConverter().setProvider(provider).getCertificate(holder);
//验证用于签名证书的私钥是否与传入的公钥是一对
cert.verify(issuerPublicKey);

这个步骤,我们构建了证书的序列号、证书的有效期(notBefore及notAfter)。并根据证书签名请求文件,构建了X509证书构建器。
        和先前一样,我们提供了待签名的主体信息。
        以上这些作为待签名的内容,最后使用CA根证书的私钥及指定的签名算法SHA256,生成签名后的证书。这个证书就是颁发给待签名主体的证书了。
八、    工具包
        最后的最后,为了方便使用,我编写了BouncyCastleUtility工具包,封装了此过程中的零碎操作。有需要的小伙伴可以前往下载。地址Java平台BouncyCastleUtility工具包-Java文档类资源-CSDN下载

Java使用BouncyCastle进行基于ECDSA算法的椭圆曲线secp256r1证书自签名相关推荐

  1. 基于mbedTLS算法库实现国密SM2签名和验签算法

    网上有大量的基于OpenSSL实现的国密算法库,比如著名的GmSSL,可以直接拿来用.我自己常用的是mbedTLS的算法库,比较小巧简单,在mbedTLS的大数算法的基础上实现了国密SM2的签名和验签 ...

  2. java 签名 ecdsa_Java数字签名——ECDSA算法

    ECDSA 例如微软产品的序列号的验证算法. Elliptic Curve Digital Signature Algorithm,椭圆曲线数字签名算法. 速度快,强度高,签名短 ---------- ...

  3. 一种基于DFA算法的敏感词检测JAVA程序片段

    本文章提供一种基于DFA算法的敏感词检测JAVA程序片段,如下: 1.构造多叉树数据结构 import org.jetbrains.annotations.NotNull;/*** 多叉树* @aut ...

  4. 基于Rete算法的JAVA规则引擎

    作者:张渊 夏清国( 西北工业大学计算机学院, 西安710072) 出自:<科学技术与工程> 第 6 卷第 11 期 2006 年 6 月 摘要 在软件应用中若能抽取出规则, 可以使软件实 ...

  5. JAVA套料程序_Nest4J是一款基于Java作为开发语言的Nest算法包

    Nest4J Nest4J是一款基于Java作为开发语言的Nest算法包.可以看做一款能在服务端进行运行计算的Nest算法库. 基于SVGNest进行了Java化的改造. 同样这也作为了我本科的毕业设 ...

  6. 2023最新SSM计算机毕业设计选题大全(附源码+LW)之java基于推荐算法的餐厅点餐系统7czh9

    现在毕设刚开始.时间还有很多,可以从头开始学也可以.毕设其实不难,难的是我们懒散到这种时候再去静下心学.能自己独立完成尽量自己独立完成.相信你看过很多上面回答的,都不建议去某宝.毕竟这一行参差不齐哈. ...

  7. Jcseg是基于mmseg算法的一个轻量级Java中文分词器

    Jcseg是基于mmseg算法的一个轻量级中文分词器,同时集成了关键字提取,关键短语提取,关键句子提取和文章自动摘要等功能,并且提供了一个基于Jetty的web服务器,方便各大语言直接http调用,同 ...

  8. 一个基于RSA算法的Java数字签名例子

    ====================================================== 注:本文源代码点此下载 ================================= ...

  9. 基于Apriori算法的网上图书销售ssm java毕业设计

    基于Apriori算法的网络书城,首先系统的主要研究是算法方面,通过算法,进行书籍的关联计算,并且进行图书的精准销售,营销,为客户推荐一些兴趣书籍,扩大用户的选择范围,提高网站的营销量.本系统开发平台 ...

最新文章

  1. python3.7和3.8的区别-Python2.7和3.7区别
  2. 前端代码标准最佳实践:javascript篇
  3. 《深入理解Java函数式编程》系列文章
  4. Java生鲜电商平台-缓存架构实战
  5. TensorFlow 常见API
  6. [5] ADB 与应用交互
  7. java写入excel文件poi
  8. 六面美团后,我有一个重要的发现...
  9. Linux/Ubuntu下解压命令
  10. 基于情感词典的网络文本情感倾向分类模型
  11. 关于LNK2005的错误
  12. 【Python通过分贝监测Windows系统是否有声音播放】
  13. unix下的softlink和hardlink
  14. Linux中断(interrupt)子系统之三:中断流控处理层(转)
  15. AI 作画《NBA球星动漫头像》| 用stable diffusion生成
  16. Photoshop——更改图片比例
  17. 视频融合技术平台解决方案
  18. 开发框架——横版格斗——动作游戏教程
  19. 【json】慕课网json学习
  20. 工业智能网关BL110应用之64:如何实现智能楼宇控制BACnet 接入金鸽MQTT云平台

热门文章

  1. Spark开发——Spark简介及入门
  2. rb格式转换器有哪些
  3. 惠普HP LaserJet Pro M329dw 打印机驱动
  4. 了解ACL及其配置方法
  5. 创建型设计模式——建造者模式
  6. 镍氢电池升压IC,0.7V极低输入,10uA功耗
  7. 网络测试期末复习大纲
  8. Java动态代理的实现原理
  9. [iOS UI进阶 - 0] Quiartz2D
  10. RSA基本原理及常见攻击方法