java操作x509数字证书_x509cert jar包-程序员宅基地

技术标签: java  数字证书  加密  

openssl 自建ca,颁发客户端证书
前一篇介绍了非对称加密,数字证书,ca等概念之后,剩下的就是一些实战了

java操作x509数字证书

一般我们自建了ca系统之后,就要颁发给客户端使用,当然证书用途很多了,例如,加密解密,签名验签等这些最原理性的使用,应用场景就比较多了,例如电子签章,数据指纹,生物识别,电商,支付安全等等都使用到了数字证书,例如有些政府部门做的内部身份认证系统,与设备,生物识别等都用到了数字证书。
本人是做java开发的,所以就从java的角度来具体操作下吧
本篇由于篇幅限制,所以不涉及加密,解密,签名验签等操作,只从代码的角度具体操作x509证书


x509证书简介

所有的X.509证书包含以下数据:
1、X.509版本号:指出该证书使用了哪种版本的X.509标准,版本号会影响证书中的一些特定信息。目前的版本是3。
2、证书持有人的公钥:包括证书持有人的公钥、算法(指明密钥属于哪种密码系统)的标识符和其他相关的密钥参数。
3、证书的序列号:由CA给予每一个证书分配的唯一的数字型编号,当证书被取消时,实际上是将此证书序列号放入由CA签发的CRL(Certificate Revocation List证书作废表,或证书黑名单表)中。这也是序列号唯一的原因。
4、主题信息:证书持有人唯一的标识符(或称DN-distinguished name)这个名字在 Internet上应该是唯一的。DN由许多部分组成,看起来象这样:
CN=Bob Allen, OU=Total Network Security Division
O=Network Associates, Inc.
C=US
这些信息指出该科目的通用名、组织单位、组织和国家或者证书持有人的姓名、服务处所等信息。
5、证书的有效期:证书起始日期和时间以及终止日期和时间;指明证书在这两个时间内有效。
6、认证机构:证书发布者,是签发该证书的实体唯一的CA的X.509名字。使用该证书意味着信任签发证书的实体。(注意:在某些情况下,比如根或顶级CA证书,发布者自己签发证书)
7、发布者的数字签名:这是使用发布者私钥生成的签名,以确保这个证书在发放之后没有被撰改过。
8、签名算法标识符:用来指定CA签署证书时所使用的签名算法。算法标识符用来指定CA签发证书时所使用的公开密钥算法和HASH算法。

证书主题属性

属性类型名称 含义 简写
Common Name 通用名称 CN
Organizational Unit name 机构单元名称 OU
Organization name 机构名 O
Locality 地理位置 L
State or province name 州/省名 S
Country 国名 C

此外还有一些有效期,颁发者,证书颁发对象,用途等
http://www.cnblogs.com/jiu0821/p/4598352.html

java操作代码实践

java对x509有自己的一套实现可以选择sun公司自己的实现类,但是有些复杂的操作sun自带的做不了,所以我们一般使用bouncycastle这个java开源加密包下载地址http://www.bouncycastle.org/latest_releases.html
虽然这里不介绍对称加密,但还是另提一句,jdk自带的aes加密只支持到128位,更高的256位的加密,需要到oracle官网下载jce包,替换java自带的加密包。一般对称和非对称加密都是混合使用的,这也是为了在安全性和效率上取得平衡,这也是业内目前普遍采用的方法。

具体代码

代码用到的jar包
这里写图片描述

x509接口


import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Date;

public interface X509Dao {
    

    /**
     * @param issuer 发布者  C=CN,ST=BJ,L=BJ,O=组织,OU=单位,CN=CCERT
     * @param notBefore 使用日期
     * @param notAfter 到期
     * @param certDestPath 生成证书地址
     * @param serial 证书序列号
     * @param alias 证书别名
     * @throws Exception
     */
    void createCert(String issuer, Date notBefore, Date notAfter, String certDestPath, BigInteger serial,
            String keyPassword, String alias) throws Exception;

    /** 输出证书信息
     * @param certPath 证书地址
     * @param keyPassword 证书密码
     */
    void printCert(String certPath, String keyPassword) throws Exception;

    /** 返回公钥
     * @param certPath 证书路径
     * @param keyPassword 证书密码
     * @return
     * @throws Exception
     */
    PublicKey getPublicKey(String certPath, String keyPassword) throws Exception;

    /** 返回私钥
     * @param certPath
     * @param keyPassword
     * @return
     * @throws Exception
     */
    PrivateKey getPrivateKey(String certPath, String keyPassword) throws Exception;

    /**
     * @param endTime 延期时间
     * @param certPath 证书地址
     * @param password 密码
     * @throws Exception 目前未实现,
     */
    void certDelayTo(Date endTime, String certPath, String password) throws Exception;

    /**修改密码
     * @param certPath 证书地址 密码
     * @param oldPwd 原始密码
     * @param newPwd 新密码
     * @throws Exception
     */
    void changePassword(String certPath, String oldPwd, String newPwd) throws Exception;

    /** 删除证书
     * @param certPath 证书地址
     * @param password 密码
     * @param alias 别名
     * @param entry 条目
     * @throws Exception
     */
    void deleteAlias(String certPath, String password, String alias, String entry) throws Exception;

}

x509 实现类



import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Enumeration;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;


public class X509CertDaoImpl implements   X509Dao {
     

    public static final String Default_keyType="PKCS12";
    public static final String Default_KeyPairGenerator="RSA";
    public static final String Default_Signature="SHA1withRSA";
    public static final String cert_type="X509";
    public static final Integer Default_KeySize=2048;

    static {
        // 系统添加BC加密算法 以后系统中调用的算法都是BC的算法
        Security.addProvider(new BouncyCastleProvider());
    }

    @Override
    public void createCert(String issuer,Date notBefore,Date notAfter,String certDestPath,
            BigInteger serial,String keyPassword,String alias) throws Exception{
        //产生公私钥对
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(Default_KeyPairGenerator);
        kpg.initialize(Default_KeySize);
        KeyPair keyPair = kpg.generateKeyPair();
        PublicKey publicKey = keyPair.getPublic();  
        PrivateKey privateKey = keyPair.getPrivate();  
        // 组装证书
        X500Name issueDn = new X500Name(issuer);  
        X500Name subjectDn = new X500Name(issuer);  
        //组装公钥信息  
        SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo  
                 .getInstance(new ASN1InputStream(publicKey.getEncoded())  
                         .readObject());

        X509v3CertificateBuilder builder = new X509v3CertificateBuilder(  
                issueDn, serial, notBefore, notAfter, subjectDn,  
                subjectPublicKeyInfo); 
         //证书的签名数据  
        ContentSigner sigGen = new JcaContentSignerBuilder(Default_Signature).build(privateKey);  
        X509CertificateHolder holder = builder.build(sigGen); 
        byte[] certBuf = holder.getEncoded();  
        X509Certificate certificate = (X509Certificate) CertificateFactory.getInstance(cert_type).generateCertificate(new ByteArrayInputStream(certBuf));  
        // 创建KeyStore,存储证书
        KeyStore store = KeyStore.getInstance(Default_keyType);
        store.load(null, null);
        store.setKeyEntry(alias, keyPair.getPrivate(),   
                 keyPassword.toCharArray(), new Certificate[] { certificate });
        FileOutputStream fout =new FileOutputStream(certDestPath);
        store.store(fout, keyPassword.toCharArray());       
        fout.close(); 
    }



    @Override
    public    void printCert(String certPath, String keyPassword) throws Exception{
                char[] charArray = keyPassword.toCharArray();
                KeyStore ks = KeyStore.getInstance(Default_keyType);
                FileInputStream fis = new FileInputStream(certPath);
                ks.load(fis, charArray);
                fis.close();
                System.out.println("keystore type=" + ks.getType());
                Enumeration enumas = ks.aliases();
                String keyAlias = null;
                if (enumas.hasMoreElements())
                {
                    keyAlias = (String)enumas.nextElement(); 
                    System.out.println("alias=[" + keyAlias + "]");
                }
                System.out.println("is key entry=" + ks.isKeyEntry(keyAlias));
                PrivateKey prikey = (PrivateKey) ks.getKey(keyAlias,charArray );
                Certificate cert = ks.getCertificate(keyAlias);
                PublicKey pubkey = cert.getPublicKey();
                System.out.println("cert class = " + cert.getClass().getName());
                System.out.println("cert = " + cert);
                System.out.println("public key = " + pubkey);
                System.out.println("private key = " + prikey);
    }


    @Override
    public  PublicKey getPublicKey(String certPath, String keyPassword) throws Exception{
            char[] charArray = keyPassword.toCharArray();
            KeyStore ks = KeyStore.getInstance(Default_keyType);
            FileInputStream fis = new FileInputStream(certPath);
            ks.load(fis, charArray);
            fis.close();
            Enumeration enumas = ks.aliases();
            String keyAlias = null;
            if (enumas.hasMoreElements())
            {
                keyAlias = (String)enumas.nextElement();
                Certificate certificate = ks.getCertificate(keyAlias);

                return ks.getCertificate(keyAlias).getPublicKey();
            }
            return null;
}
    @Override
    public  PrivateKey getPrivateKey(String certPath, String keyPassword) throws Exception{
        char[] charArray = keyPassword.toCharArray();
        KeyStore ks = KeyStore.getInstance(Default_keyType);
        FileInputStream fis = new FileInputStream(certPath);
        ks.load(fis, charArray);
        fis.close();
        Enumeration enumas = ks.aliases();
        String keyAlias = null;
        if (enumas.hasMoreElements())
        {
            keyAlias = (String)enumas.nextElement();
            Certificate certificate = ks.getCertificate(keyAlias);

            return (PrivateKey) ks.getKey(keyAlias, charArray);
        }
        return null;
}


    @Override
    public void certDelayTo(Date endTime,String certPath,String password) throws Exception{

    }

    @Override
    public void changePassword(String certPath,String oldPwd,String newPwd) throws Exception{
        KeyStore ks = KeyStore.getInstance(Default_keyType);
        FileInputStream fis = new FileInputStream(certPath);
        ks.load(fis, oldPwd.toCharArray());
        fis.close();
        FileOutputStream output = new  FileOutputStream(certPath);
        ks.store(output,newPwd.toCharArray());
        output.close();
    }

    @Override
    public void deleteAlias(String certPath,String password,String alias,String entry) throws Exception{
        char[] charArray = password.toCharArray();
        KeyStore ks = KeyStore.getInstance(Default_keyType);
        FileInputStream fis = new FileInputStream(certPath);
        ks.load(fis, charArray);
        fis.close();
      if(ks.containsAlias(alias)){
            ks.deleteEntry(entry);
            FileOutputStream output = new  FileOutputStream(certPath );
            ks.store(output,password.toCharArray());
            output.close();
      }else{
          throw new Exception("该证书未包含别名--->"+alias);
      }
    }
    public static void main(String[] args) throws Exception {
        X509Dao impl=new X509CertDaoImpl();
        String issuer="C=CN,ST=BJ,L=BJ,O=testserver,OU=testserver,CN=testserver";
        String certDestPath="e://test.p12";
        BigInteger serial=BigInteger.valueOf(System.currentTimeMillis());
        String keyPassword="123";
        String alias="test";
        //impl.createCert(issuer, new Date(), new Date("2017/09/27"), certDestPath, serial, keyPassword, alias);
        //impl.changePassword(certDestPath, "123", "123");
        //impl.createCert(issuer, new Date(), new Date("2017/09/27"), certDestPath, serial, keyPassword, alias);
        //未实现
        impl.certDelayTo(new Date("2017/09/28"), certDestPath, keyPassword);
        //impl.printCert(certDestPath, keyPassword);
    }

}

目前证书延期这块,没有做到,p12 证书延期可以通过openssl 做,但是具体怎么做,我也没搞懂,以后有时间的话,具体看下openssl的文档,在公布给大家

这是java相关的证书操作,后续会介绍,java如何使用x509实现加密解密,签名验签等操作,以及这些技术的使用场景简介

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/do_bset_yourself/article/details/78159697

智能推荐

攻防世界_难度8_happy_puzzle_攻防世界困难模式攻略图文-程序员宅基地

文章浏览阅读645次。这个肯定是末尾的IDAT了,因为IDAT必须要满了才会开始一下个IDAT,这个明显就是末尾的IDAT了。,对应下面的create_head()代码。,对应下面的create_tail()代码。不要考虑爆破,我已经试了一下,太多情况了。题目来源:UNCTF。_攻防世界困难模式攻略图文

达梦数据库的导出(备份)、导入_达梦数据库导入导出-程序员宅基地

文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作  导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释:   cwy_init/init_123..._达梦数据库导入导出

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

随便推点

Thinkpad X250 secure boot failed 启动失败问题解决_安装完系统提示secureboot failure-程序员宅基地

文章浏览阅读304次。Thinkpad X250笔记本电脑,装的是FreeBSD,进入BIOS修改虚拟化配置(其后可能是误设置了安全开机),保存退出后系统无法启动,显示:secure boot failed ,把自己惊出一身冷汗,因为这台笔记本刚好还没开始做备份.....根据错误提示,到bios里面去找相关配置,在Security里面找到了Secure Boot选项,发现果然被设置为Enabled,将其修改为Disabled ,再开机,终于正常启动了。_安装完系统提示secureboot failure

C++如何做字符串分割(5种方法)_c++ 字符串分割-程序员宅基地

文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf

推荐文章

热门文章

相关标签