IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> X.509证书与java -> 正文阅读

[网络协议]X.509证书与java

作者:template-box

1. X.509证书简介

X.509是密码学里公钥证书的格式标准。X.509证书己应用在包括TLS/SSL(WWW万维网安全浏览的基石)在内的众多Internet协议里。同时它也用在很多非在线应用场景里,比如电子签名服务。X.509证书里含有公钥、身份信息(比如网络主机名,组织的名称或个体名称等)和签名信息(可以是证书签发机构CA的签名,也可以是自签名)。对于一份经由可信的证书签发机构签名或者可以通过其它方式验证的证书,证书的拥有者就可以用证书及相应的私钥来创建安全的通信,对文档进行数字签名。-百度百科

所有的X.509证书包含以下数据:

①X.509版本号:指出该证书使用了哪种版本的X.509标准,版本号会影响证书中的一些特定信息。目前的版本是3。

②证书持有人的公钥:包括证书持有人的公钥、算法(指明密钥属于哪种密码系统)的标识符和其他相关的密钥参数。

③证书的序列号:由CA给予每一个证书分配的唯一的数字型编号,当证书被取消时,实际上是将此证书序列号放入由CA签发的CRL(Certificate Revocation List证书作废表,或证书黑名单表)中。这也是序列号唯一的原因。

④主题信息:证书持有人唯一的标识符(或称DN-distinguished name)这个名字在 Internet上应该是唯一的。DN由许多部分组成,看起来象这样:

CN=Bob Allen

OU=Total Network Security Division

O=Network Associates, Inc.

C=US

这些信息指出该科目的通用名、组织单位、组织和国家或者证书持有人的姓名、服务处所等信息。

⑤证书的有效期:证书起始日期和时间以及终止日期和时间;指明证书在这两个时间内有效。

⑥认证机构:证书发布者,是签发该证书的实体唯一的CA的X.509名字。使用该证书意味着信任签发证书的实体。(注意:在某些情况下,比如根或顶级CA证书,发布者自己签发证书)

⑦发布者的数字签名:这是使用发布者私钥生成的签名,以确保这个证书在发放之后没有被撰改过。

⑧签名算法标识符:用来指定CA签署证书时所使用的签名算法。算法标识符用来指定CA签发证书时所使用的公开密钥算法和HASH算法。

证书主题属性

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

此外还有一些有效期,颁发者,证书颁发对象,用途等。详情参考

2.java操作X.509证书

java对x509有自己的一套实现可以选择sun公司自己的实现类,但是有些复杂的操作sun自带的做不了,所以我们一般使用bouncycastle这个java开源加密包。

需要注意的是:jdk自带的aes加密只支持到128位,更高的256位的加密,需要到oracle官网下载jce包,替换java自带的加密包。一般对称和非对称加密都是混合使用的,这也是为了在安全性和效率上取得平衡,这也是业内目前普遍采用的方法。

需要引入的包:

    <dependencies>
        <!--bouncycastle加密包-->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpkix-jdk15on</artifactId>
            <version>1.64</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.64</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcmail-jdk15</artifactId>
            <version>1.46</version>
        </dependency>
        <!--StringUtils等都在这个包下-->
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
    </dependencies>

X509接口

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

public interface X509Dao {
    /**
     * 制作证书
     * @param issuer 发布者
     * @param notBefore 使用日期
     * @param notAfter 到期
     * @param certDestPath 生成证书地址
     * @param serial 证书序列号
     * @param keyPassword 证书密码
     * @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 证书密码
     * @throws Exception
     */
    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 keyPassword
     * @throws Exception
     */
    void certDelayTo(Date endTime, String certPath, String keyPassword) throws Exception;

    /**
     * 修改密码
     * @param certPath
     * @param oldPwd
     * @param newPwd
     * @throws Exception
     */
    void changePassword(String certPath, String oldPwd, String newPwd) throws Exception;

    /**
     * 删除证书
     * @param certPath
     * @param keyPassword
     * @param alias
     * @param entry
     * @throws Exception
     */
    void deleteAlias(String certPath, String keyPassword, String alias, String entry) throws Exception;

}

X509实现类

package testx509;

import org.apache.commons.lang.time.DateUtils;
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;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;


public class X509CertDaoImpl implements X509Dao{
    public static final String Default_keyType = "PKCS12";//存储证书keyStore类型
    public static final String Default_KeyPairGenerator = "RSA";//非对称加密算法
    public static final String Default_Signature = "SHA1withRSA";//签名算法:RSA签名,用MD5哈希算法摘要
    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 signGen = new JcaContentSignerBuilder(Default_Signature).build(privateKey);
        X509CertificateHolder holder = builder.build(signGen);
        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);

        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;
        while (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();
            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();
            return  (PrivateKey) ks.getKey(keyAlias, charArray);
        }
        return null;
    }

    @Override
    public void certDelayTo(Date endTime, String certPath, String keyPassword) 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 fout = new FileOutputStream(certPath);
        ks.store(fout,newPwd.toCharArray());
        fout.close();
    }

    @Override
    public void deleteAlias(String certPath, String keyPassword, String alias, String entry) throws Exception {
        char[] charArray = keyPassword.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 fout = new FileOutputStream(certPath);
            ks.store(fout,keyPassword.toCharArray());
            fout.close();
        }else {
            throw new Exception("该证书未包含别名------->"+alias);
        }
    }

    public static void main(String[] args) throws Exception {
        //1.创建证书
        //X509CertDaoImpl impl = new X509CertDaoImpl();
        //String issuer="C=CN,ST=BJ,L=Beijing,O=testserver,OU=testserver,CN=testserver";
        //String certDestPath="E:\\iotest\\test2.p12";
        //BigInteger serial=BigInteger.valueOf(System.currentTimeMillis());
        //String keyPassword="123456";
        //String alias="test2";
        //
        //Calendar calendar = Calendar.getInstance();
        //calendar.add(Calendar.YEAR,5);
        //
        //impl.createCert(issuer,new Date(),calendar.getTime(),certDestPath,serial,keyPassword,alias);
        //System.out.println("创建证书成功");

        //2.遍历打印证书信息
        X509CertDaoImpl impl = new X509CertDaoImpl();
        impl.printCert("E:\\iotest\\cert\\test.p12","123456");

        //3.DateUtils的使用
        //Date date = DateUtils.parseDate("2021-11-12 09:50:00", new String[]{"yyyy-MM-dd HH:mm:ss"});
        //System.out.println(date.toLocaleString());

        //4.枚举的遍历问题
        //char[] charArray = "123456".toCharArray();
        //KeyStore ks = KeyStore.getInstance(Default_keyType);
        //FileInputStream fis = new FileInputStream("E:\\iotest\\cert\\test.p12");
        //ks.load(fis, charArray);
        //fis.close();
        //System.out.println("keystore type=" + ks.getType());
        //Enumeration enumas = ks.aliases();
        //ArrayList<String> aliasList = new ArrayList<>();
        //String [] keyAlias = null;
        //while (enumas.hasMoreElements()) {
        //    String alias = (String) enumas.nextElement();
        //    aliasList.add(alias);
        //}
        //System.out.println(aliasList);
    }
}

这是java相关的证书操作(证书延期没有做),关于java如何使用x509实现加密解密,签名验签等操作,可以阅读这篇文章

3.证书文件扩展名

X.509有多种常用的扩展名。不过其中的一些还用于其它用途,就是说具有这个扩展名的文件可能并不是证书,比如说可能只是保存了私钥。

.pem:(隐私增强型电子邮件)DER编码的证书再进行Base64编码的数据存放在"-----BEGIN CERTIFICATE-----"和"-----END CERTIFICATE-----"之中。

.cer、.crt、.der:用于存放证书,通常是二进制格式,但Base64编码后也很常见,不含私钥。

.p7b、.p7c:PKCS#7SignedData structure without data, just certificate(s) orCRL(s)

.p12:PKCS#12格式,包含证书的同时可能还有带密码保护的私钥。

.pfx:PFX,PKCS#12之前的格式(通常用PKCS#12格式,比如那些由IIS产生的PFX文件)。

PKCS#7是签名或加密数据的格式标准,官方称之为容器。由于证书是可验真的签名数据,所以可以用SignedData结构表述。.P7C文件是退化的SignedData结构,没有包括签名的数据。

PKCS#12由PFX进化而来的用于交换公共的和私有的对象的标准格式,可以包含公钥证书及其私钥,也可包含整个证书链。

4.证书管理工具keytool

Java自带的keytool工具是个密钥和证书管理工具。它使用户能够管理自己的公钥/私钥对及相关证书,用于(通过数字签名)自我认证(用户向别的用户/服务认证自己)或数据完整性以及认证服务。它还允许用户储存他们的通信对等者的公钥(以证书形式)。

keytool将密钥和证书储存在一个所谓的密钥仓库(keystore)中。缺省的密钥仓库实现将密钥仓库实现为一个文件。它用口令来保护私钥。

Java KeyStore的类型

JKS和JCEKS是Java密钥库(KeyStore)的两种比较常见类型(还有JKS、JCEKS、PKCS12、BKS、UBER)。

JKS的Provider是SUN,在每个版本的JDK中都有,JCEKS的Provider是SUNJCE,1.4后我们都能够直接使用它。

JCEKS在安全级别上要比JKS强,使用的Provider是JCEKS(推荐),尤其在保护KeyStore中的私钥上(使用TripleDes)。

PKCS#12是公钥加密标准,它规定了可包含所有私钥、公钥和证书。其以二进制格式存储,也称为PFX文件,在windows中可以直接导入到密钥区,注意,PKCS#12的密钥库保护密码同时也用于保护Key。

BKS来自BouncyCastle Provider,它使用的也是TripleDES来保护密钥库中的Key,它能够防止证书库被不小心修改(Keystore的keyentry改掉1个bit都会产生错误),BKS能够跟JKS互操作。

UBER比较特别,当密码是通过命令行提供的时候,它只能跟keytool交互。整个keystore是通过PBE/SHA1/Twofish加密,因此keystore能够防止被误改、察看以及校验。以前,Sun JDK(提供者为SUN)允许你在不提供密码的情况下直接加载一个Keystore,类似cacerts,UBER不允许这种情况。

从.p12中提出为.cer证书

使用上述的java代码,生成了test2.p12,alias为test2。使用keytool操作命令如下:

keytool -export -alias test2 -keystore test2.p12 -storetype PKCS12 -rfc -file test2.cer

将.cer证书放入.p12中

使用上述的java代码,生成了test.p12,alias为test。将上面的test2.cer放入到test.p12中:

keytool -import -alias test2 -trustcacerts -file test2.cer -keystore test.p12

这样在test.p12中就存在了两个别名的证书test和test2。

?参考文献:

原文链接:https://blog.csdn.net/do_bset_yourself/article/details/78159697

https://www.cnblogs.com/testlife007/p/6888191.html

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-11-15 16:11:28  更:2021-11-15 16:11:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年7日历 -2024/7/3 21:30:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码