数字证书
我们在前面看到了一些计算机密码学的一些算法
1. 摘要算法确保数据没有被篡改
2. 非对称加密就是对数据进行加解密
3. 数据签名可以确保数据完整性和抗否认性
而数字证书就是集合了多种密码学算法,用于实现数据加解密,身份认证,签名等多种功能的一种网络安全标准
我们看数字证书:
1. 首先实现了非对称加密算法,可以对数据进行加解密
2. 然后他有签名算法,能够确保数据完整性和抗否认性
3. 最后通过摘要算法,确保证书本身没有被篡改
package com.learn.securl;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.X509Certificate;
import java.util.Base64;
import javax.crypto.Cipher;
public class X509 {
/**
* 在这个类中我们定义一个privateKey
* privateKey代表的是私钥
*/
private final PrivateKey privateKey;
/**
* 和一个X509Certificate的一个变量
* X509Certificate表示的是证书,公钥,以及摘要的
*/
private final X509Certificate certificate;
/**
* 我们需要传入keyStore和证书的名称和password
* 我们通过KeyStore的getKey方法传入名称和password
* 就可以得到一个privateKey
* 我们通过KeyStore的getCertificate方法传入证书的名称
* 就可以得到一个X509Certificate的一个对象
* @param ks
* @param certName
* @param password
* @throws GeneralSecurityException
*/
public X509(KeyStore ks, String certName, String password) throws GeneralSecurityException{
/**
* 注意密码用于获得私钥
*/
this.privateKey = (PrivateKey) ks.getKey(certName, password.toCharArray());
/**
* 获得证书是不需要口令的
*/
this.certificate = (X509Certificate) ks.getCertificate(certName);
}
/**
* 然后我们定义一个encrypt仿方法进行加密
* @param message
* @return
* @throws GeneralSecurityException
*/
public byte[] encrypt(byte[] message) throws GeneralSecurityException{
/**
* 在加密的时候我们首先通过Cipher.getInstance
* 然后我们通过privateKey.getAlgorithm获得加密算法
*/
Cipher cipher = Cipher.getInstance(this.privateKey.getAlgorithm());
/**
* 然后我们设置ENCRYPT_MODE并且传入privateKey
*/
cipher.init(Cipher.ENCRYPT_MODE, this.privateKey);
/**
* 然后获取密文
*/
return cipher.doFinal(message);
}
/**
* 然后我们定义一个decrypt
* @param data
* @return
* @throws GeneralSecurityException
*/
public byte[] decrypt(byte[] data) throws GeneralSecurityException{
/**
* 在解密的时候通过certificate对象getPublicKey就可以获得公钥publicKey
*/
PublicKey publicKey = this.certificate.getPublicKey();
/**
* 然后我们还是通过Cipher.getInstance获得一个Cipher对象
*/
Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
/**
* 设置为解密模式
*/
cipher.init(Cipher.DECRYPT_MODE, publicKey);
/**
* 然后传入publicKey
* 就可以正常的解密
*/
return cipher.doFinal(data);
}
/**
* 我们再定义一个sign方法用于签名
* 传入原始的Message
* @param message
* @return
* @throws GeneralSecurityException
*/
public byte[] sign(byte[] message) throws GeneralSecurityException{
/**
* 然后通过Signature.getInstance
* 通过certificate对象getSigAlgName获得签名算法
*/
Signature signature = Signature.getInstance(this.certificate.getSigAlgName());
/**
* 我们用privateKey进行签名
*/
signature.initSign(this.privateKey);
signature.update(message);
/**
* 获得签名以后的数据
*/
return signature.sign();
}
/**
* 我们再定义一个verify方法验证签名
* 需要传入原始信息和签名信息
* 验证签名的时候需要使用公钥
* 同时获得的还有签名的算法
* @param message
* @param sign
* @return
* @throws GeneralSecurityException
*/
public boolean verify(byte[] message, byte[] sign) throws GeneralSecurityException{
Signature signature = Signature.getInstance(this.certificate.getSigAlgName());
signature.initVerify(this.certificate);
signature.update(message);
return signature.verify(sign);
}
/**
* 我们定义一个新的方法loadKeyStore
* 用于加载一个KeyStore文件
* 因为JAVA的数字证书是存储在KeyStore里面的
* 我们需要指定一个KeyStore的文件
* 打开KeyStore用到的密码
* @param keyStoreFile
* @param password
* @return
* @throws GeneralSecurityException
* @throws IOException
*/
static KeyStore loadKeyStore(String keyStoreFile, String password) throws GeneralSecurityException, IOException{
try(InputStream input = new BufferedInputStream(new FileInputStream(keyStoreFile))){
/**
* 我们通过KeyStore.getInstance得到一个KeyStore对象
*/
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
/**
* 通过KeyStore的load方法
* 传入一个inputStream就可以得到KeyStore对象
*/
ks.load(input, password.toCharArray());
return ks;
}
}
/**
* 最后我们使用main方法使用数字证书以及加密和签名,
* 在执行这个程序之前,
* 首先我们要创建我们的数字证书
* keytool -genkeypair -keyalg RSA -keysize 1024
* -sigalg SHA1withRSA -validity 36500 -alias mycert
* -keystore my.keystore -dname “CN=test07, OU=sample,
* O=sample, L=BJ, ST=BJ, C=CN” -keypass 123456
* -storepass 456789
* genkeypair表示我们要生成一个数字证书
* -keyalg RSA他的算法是RSA
* -keysize 1024他的密钥长度是1024
* -sigalg SHA1withRSA我们指定的算法长度是SHA1withRSA
* -validity 36500我们指定数字证书的有效期是36500
* -alias mycert我们给这个证书写一个名字叫做mycert
* -keystore my.keystore同时我们指定了一个keystore的文件叫做my.keystore
* “CN=test07, OU=sample, O=sample, L=BJ, ST=BJ, C=CN”
* -keypass 123456然后我们用keypass指定证书的密码123456
* -storepass 456789我们用storepass指定store的密码是456789
* 紧接着我们要给证书指定CN OU这些属性
* 如果这个证书将来要用于网站
* CN的属性必须和网站的域名完全一致
* keytool -list -keystore my.keystore -storepass 456789
* 我们还可以通过keytool的命令查询证书
* 我们输入命令然后回车
* 我们就可以看到包含了一个证书mycert
* 我们就可以看到在项目的根目录中生成一个my.cert的一个文件
*
* 我们在执行的时候可以看到
* 我们在执行证书得到加密以后的密文
* 解密以后得到原始的明文
* 我们对数字证书对原始的消息进行签名
* 得到Base64表示的签名
* 最后我们用证书得到这个签名结果为true
* @param args
* @throws GeneralSecurityException
* @throws IOException
*/
public static void main(String[] args) throws GeneralSecurityException, IOException {
byte[] message = "Hello, 使用X.509证书进行加密和签名!".getBytes();
// 读取KeyStore:
/**
* 首先我们需要读取一个KeyStore
* 然后传入KeyStore的密码
*
* 注意到我们用loadKeyStore的时候传入了keyStore文件的密码
*/
KeyStore ks = loadKeyStore("my.keystore", "456789");
// 读取证书:
/**
* 紧接着我们需要读取一个X509证书
* 并且传入证书的密码
* 并且获取他的私钥
*
* 我们在读取证书的时候传入的是证书的密码
*/
X509 x509 = new X509(ks, "mycert", "123456");
// 加密:
/**
* 然后我们进行加密
*/
byte[] encrypted = x509.encrypt(message);
System.out.println("encrypted: " + Base64.getEncoder().encodeToString(encrypted));
// 解密:
byte[] decrypted = x509.decrypt(encrypted);
System.out.println("decrypted: " + new String(decrypted, "UTF-8"));
// 签名:
byte[] sign = x509.sign(message);
System.out.println("sign: " + Base64.getEncoder().encodeToString(sign));
// 验证签名:
boolean verified = x509.verify(message, sign);
System.out.println("verify: " + verified);
}
}
数字证书采用链式签名认证,他的底层证书是Geo Trust 证书,然后由他签发的GeoTrust SSL CA - G3证书,最后由mail.qq.com
我们最后来看一下数字证书的应用:
1.我们在上网的时候用到的https,这个协议实际上是http over ssl
2. 在使用https的时候,服务器会发送证书给客户端,这个证书包括公钥,签名,和CA证书
3. 客户端可以验证服务器端的证书是否有效,来确认服务器的身份
4. 然后客户端使用证书加密一个随机口令,发送给服务器端,采用的是公钥加密
5. 而服务器端解密获得一个随机口令,采用的是私钥解密
6. 双方随后就可以使用AES加密进行通信,这个时候使用的是对称加密
服务器发送的数字证书实际上是publicKey,就是公钥,以及public的信息,比如摘要签名等,服务器的私钥永远
保存在服务器端,不能泄露,所以数字证书实际上包含的是公钥
最后我们总结一下:
1. 数字证书实际上就是集合了多种密码学算法,用于实现数据加解密,身份认证,签名等多种功能的一种网络安全标准
2. 数字认证采用的是一种链式签名的管理,顶级的CA证书已经内置在操作系统中
3. 常用的算法有MD5,SHA1,SHA256,RSA,DSA