数字证书

一.数字证书概念

1. 数字证书集合了多种密码学的算法:
  • 自身带有公钥信息,可以完成相应的加密和解密操作;
  • 同时还带有数字签名,可以鉴别消息的来源;
  • 并且自身带有消息摘要信息,可以验证证书的完整新;
  • 由于证书本身还有用户身份信息,因而具有认证性

  数字证书中常用的非对称加密算法是RSA算法,签名算法是SHA1withRSA算法,消息摘要算法是SHA算法。

  数字证书类似生活中的身份证,只是数字证书是签发给网络用户(计算机)的身份凭证。并且这些身份凭证需要有认证机构(Certificate Authority)CA签发,并且只有经过CA签发的证书在网络中才具有可认证性。

2. 数字证书格式标准:

  数字证书有多重文件编码格式,主要包含CER,DER编码等。
  所有证书符合公钥基础设置指定的国际标准,目前有三个版本如下:
在这里插入图片描述
以上标准用于证书的申请和更新等操作;如PKCS#10文件用来证书的签发申请,PKCS#12文件可以用作Java中的密匙库和信任库直接使用。通常用Base64编码作为数字证书文件的存储格式。

3.模型分析
证书签发

办法流程如下所示:
在这里插入图片描述

说明:
1)由数字证书需求方产生自己的密匙对
2)由数字证书需求方将算法、公钥和证书申请者身份信息传送认证机构
3)由认证机构核实用户身份,执行相应的步骤,确保请求确实是用户发送而来
4)由认证机构将数字证书颁发给用户

二、证书管理

  要获得数字证书,我们需要使用数字证书管理工具(KeyTool或者OpenSSL)构建CSR(certificate signing request,数字证书申请),交由CA机构签发,形成最终的设资证书。

1.KeyTool证书管理

  keyTool是Java中数字证书管理的工具, 用于数字证书的申请、导入、导出和撤销等操作。KeyTool和本地密匙库相关联,将私钥存于密匙库,公钥则以数字证书输出。这个工具位于%JDK_HOME%/bin目录中。需要通过控制台命令行操作。

1.1 构建自签名证书
1.1.1 第一步生成数字证书

在%JDK_HOME%/bin>中执行如下命令,生成本地数字证书:

 keytool -genkeypair -keyalg RSA -keysize 2048 -sigalg SHA1withRSA -validity 36000 -alias www.vison.org -keystore vison.keystore

说明:
-genkeypair : 表示生成密匙
-keyalg: 指定密匙算法,这里指定为RSA算法
-keysize:指定密匙长度,默认是1024,这里指定为2048
-sigalg:指定数字签名算法,这里指定为SHA1withRSA算法
-validity:指定证书有效期,这里指定为36000天
-alias:指定别名,这里是www.vison.org
-keystore:指定密匙库存储位置,这里是vison.keystore
然后需要输入相关的用户信息,如下:
在这里插入图片描述

1.1.2 第二步 导出数字证书

在%JDK_HOME%/bin>中执行如下命令,导出数字证书:

   keytool -exportcert -alias www.vison.org -keystore vison.keystore -file vison.cer -rfc

说明:
-exportcert :表示证书导出操作
-alias :指定导出别名,这里是www.vison.org -keystore :指定密匙库文件,这里是vison.keystore -file :指定导出文件路径,这类是vison.cer -rfc:指定以Base64编码格式输出

1.1.3 第三步 打印数字证书信息

在%JDK_HOME%/bin>中执行如下命令,打印数字证书:

keytool -printcert -file vison.cer

总结:上面就生成了一个自签名的X.509第三版类型的根证书,并且用Base64编码保存,自签名证书虽然可以使用,但是未经CA认证是没有任何的法律效力的。

1.2 构建CA签发证书

如果需要获取CA认证机构认证的数字证书,需要将数字证书签发申请(CAR)导出,然后由CA机构认证颁发,并且将认证后的证书导入本地密匙库和信任库。

1.2.1 第一步 导出数字证书签发申请

执行如下命令,会生成一个vison.csr文件:

keytool -certreq -alias www.vison.org -keystore vison.keystore -file vison.csr -v

这里需要指定密匙库口令和密匙口令。

说明:
-certreq :表示数字证书的申请操作
-alias:指定别名,这里是指www.vison.org
-keystore:指定密匙库,这里是vison.keystore
-file:指定到导出文件地址,这里是vison.csr
-v:详细信息
目前由VeriSign、GeoTrust和Thawte国际权威数字证书颁发认证机构“三巨头”认证数字证书价格不菲,当然我们使用使用免费的CAcert签发证书。当你获取了证书后,然后就可以通过如下方式导入证书了。

1.2.2 第二步 导入数字证书

执行如下命令:

keytool -importcert -trustcacerts -alias www.vison.org -file vison.cer -keystore vison.keystore

说明
-importcert:表示导入数字证书
-trustcacerts:表示将数字证书导入信任库
-alias:指定导别名,这里为www.vison.org
-file:指定导入数字证书文件路径,这里是vison.cer
-keystore:指定密匙库文件,这里是vison.keystore
这里需要指定密匙库

1.2.3 第三步 查看导入数字证书
keytool -list -alias www.vison.org -keystore vison.keystore

说明:
-list:表示导入数字证书
-alias:指定别名,这里是www.vison.org
-keystore:指定密匙库文件,这里是vison.keystore

2.OpenSSL证书管理

OpenSSL是一个开放源代码的软件包,这个是实现了SSL及相关加密技术,也是常用的证书管理工具,OpenSSL功能远胜于KeyTool,可用于根证书,服务器证书和客户证书的管理,相关的操作可以参考官方文档。

三、证书使用

  Java提供完善的数字证书管理实现,通过操作密匙库和数字证书就可以完成加密、解密和签名验证操作,密匙库管理私钥,数字证书管理公钥,私钥和密钥分属消息传递两方,进行加密消息传递,这里的keystore和证书都是用之前用keytool生成的证书来测试。
  我们可以简单的将密匙库当做私钥的相关操作的入口,数字证书则是公钥相关操作的入口。

package keytools;

import org.apache.commons.codec.binary.Hex;

import javax.crypto.Cipher;
import java.io.FileInputStream;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

public class CertificateCodeTest {
    //证书类型
    private static final String CERT_TYPE ="X.509";
    //测试
    public static void main(String[] args) throws Exception {

        String keyStorePath ="C:\\Program Files\\Java\\jdk1.8.0_144\\bin\\vison.keystore";
        String alias ="www.vison.org";
        String password ="123456";
        String certificatePath="C:\\Program Files\\Java\\jdk1.8.0_144\\bin\\vison.cer";

        String str ="签名 vison";
        byte[] sign = sign(str.getBytes(), keyStorePath, alias, password);
        System.out.println("sign: " + Hex.encodeHex(sign) );

        //验证
        boolean verify = verify(str.getBytes(), sign, certificatePath);
        System.out.println("verify: " +verify);

    }

    /**
     * 验证签名
     * @param data
     * @param sign
     * @param certificatePath
     * @return
     * @throws Exception
     */
    public static boolean verify (byte[] data,byte[] sign,String certificatePath) throws Exception{
        X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);
        Signature signature = Signature.getInstance(x509Certificate.getSigAlgName());
        signature.initVerify(x509Certificate);
        signature.update(data);
        return signature.verify(sign);
    }
    /**
     * 签名
     * @param data
     * @param keyStorePath
     * @param alias
     * @param password
     * @return
     * @throws Exception
     */
    public static byte[] sign(byte[] data,String keyStorePath,String alias, String password)throws Exception{
        X509Certificate x509Certificate = (X509Certificate) getCertificate(keyStorePath, alias, password);
        Signature signature = Signature.getInstance(x509Certificate.getSigAlgName());
        PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);
        signature.initSign(privateKey);
        signature.update(data);
        return  signature.sign();
    }
    /**
     * 公钥解密
     * @param data
     * @param certificatePath
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] data,String certificatePath)throws Exception{
        PublicKey publicKey = getPublicKeyByCertificate(certificatePath);
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE,publicKey);
        return cipher.doFinal(data);
    }

    /**
     * 公钥加密
     * @param data
     * @param certificatePath
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data,String certificatePath)throws Exception{
        PublicKey publicKey = getPublicKeyByCertificate(certificatePath);
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE,publicKey);
        return cipher.doFinal(data);
    }

    /**
     * 私钥解密
     * @param data
     * @param keyStorePath
     * @param alias
     * @param password
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] data,String keyStorePath,String alias,String password)throws Exception{
        PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE,privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 私钥加密
     * @param data
     * @param keyStorePath
     * @param alias
     * @param password
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data,String keyStorePath,String alias,String password)throws Exception{
        PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE,privateKey);
        return cipher.doFinal(data);
    }
    /**
     * 获取私钥
     * @param keyStorePath 密匙库路径
     * @param alias 别名
     * @param password 密码
     * @return PrivateKey
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String keyStorePath,String alias,String password) throws Exception{
        KeyStore keyStore = getKeyStore(keyStorePath, password);
        return (PrivateKey)keyStore.getKey(alias,password.toCharArray());
    }

    /**
     * 获取公钥
     * @param certificatePath 证书路径
     * @return PublicKey
     * @throws Exception
     */
    private static PublicKey getPublicKeyByCertificate(String certificatePath) throws Exception{
        Certificate certificate = getCertificate(certificatePath);
        return certificate.getPublicKey();
    }

    /**
     * 获取Certificate
     * @param certificatePath 证书路径
     * @return Certificate 证书
     * @throws Exception
     */
    public static Certificate getCertificate(String certificatePath) throws Exception{
        CertificateFactory certificateFactory = CertificateFactory.getInstance(CERT_TYPE);
        FileInputStream is = new FileInputStream(certificatePath);
        Certificate certificate = certificateFactory.generateCertificate(is);
        is.close();
        return certificate;
    }

    /**
     * 获取Certificate
     * @param keyStorePath 密匙库路径
     * @param alias 别名
     * @param password 密码
     * @return Certificate 证书
     * @throws Exception
     */
    public static Certificate getCertificate(String keyStorePath,String alias,String password) throws Exception{
        KeyStore keyStore = getKeyStore(keyStorePath, password);
        return keyStore.getCertificate(alias);
    }


    /**
     * 获取keySotre
     * @param keyStorePath 密匙库的路径
     * @param password  密匙库的密码
     * @return KeyStore
     * @throws Exception
     */
    public static KeyStore getKeyStore(String keyStorePath,String password) throws Exception {
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        FileInputStream is = new FileInputStream(keyStorePath);
        keyStore.load(is,password.toCharArray());
        is.close();
        return keyStore;
    }
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值