本文主要介绍keytool自签名SSL证书(免费)以及私钥签名、公钥验签流程,点击查看keytool CA签名SSL证书(收费)
最近给银行做一个系统,虽说是给行内使用的,但是系统要同时支持内外网方式登录,采用https(http+ssl)传输协议,经过SSL加密信息,防止用户信息被截获。
因此花了一段时间研究这方面的知识,主要从JDK自带keytool入手,研究如何通过keytool最终得到自签名SSL证书。
百度百科【CA】
证书颁发机构(CA, Certificate Authority)即颁发数字证书的机构。是负责发放和管理数字证书的权威机构,并作为电子商务交易中受信任的第三方,承担公钥体系中公钥的合法性检验的责任。科
百度百科【SSL】
Secure Sockets Layer 安全套接层及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。
对于JDK自带的keytool指令,不论Windows还是Linux,该指令文件存放在JAVA_HOME/bin目录下,使用的前提是系统已搭建好JDK环境且配置JAVA环境变量。
正文以Windows操作为例,D:/keys/是我个人证书文件存放路径,实际请自行替换相关路径。
目录
一、生成密钥库
二、证书库导出公钥证书
三、私钥签名、公钥验签
一、生成密钥库
keytool -genkeypair -alias mykeystore -keyalg RSA -keysize 2048 -keypass mypassword -sigalg SHA256withRSA -dname "cn=www.justinqin.com,ou=justinqin,o=qjg,l=Shenzhen,st=Guangdong,c=CN" -validity 1095 -keystore D:/keys/mykeystore.keystore -storetype JKS -storepass mypassword
==================参数含义=======================
-genkeypair
非对称密钥(密钥对,私钥签名、公钥验签),对称密钥为-gendeskey(单个密钥)
-alias mykeystore
证书库别名为mykeystore
-keyalg RSA
加密算法为RSA,加密算法可以分为对称加密、不对称加密和不可逆加密算法
对称加密算法:加解密都用的同一把密钥,如DES、AES
不对称加密算法:使用密钥对即公钥、私钥进行加解密,如RSA SHS
不可逆加密算法:加密过程中不需要密钥,明文加密成密文后不可逆,如MD5
MD5、SHS的加密都是用了哈希加密算法
-keysize 2048
密钥长度,位数越大越安全,但同时加解密时间成正比增长
-keypass mypassword
私钥密码为mypassword
-sigalg SHA256withRSA
签名算法为SHA256withRSA
keyalg=RSA时,sigalg可选MD5withRSA、SHA1withRSA、SHA256withRSA、SHA384withRSA、SHA512withRSA
keyalg=DSA时,sigalg可选SHA1withDSA、SHA256withDSA
-dname "cn=www.justinqin.com,ou=justinqin,o=qjg,l=Shenzhen,st=Guangdong,c=CN"
证书相关信息
CN=名字与姓氏/域名
OU=组织单位名称
O=组织名称
L=城市或区域名称
ST=州或省份名称
C=单位的两字母国家代码
-keystore D:/keys/mykeystore.keystore
生成的证书库文件为mykeystore.keystore,存储位置D:/keys/
-validity 1095
证书有效天数为3年=1095
-storetype JKS
证书库类型为JKS,JDK1.9以前默认JKS,JDK1.9及以后默认PKCS12
-storepass mypassword
证书库密码为mypassword
keytool -export -alias mykeystore -keystore D:/keys/mykeystore.keystore -storepass mypassword -file D:/keys/publickey.cer
=========================证书查看相关指令==============
证书库查看
keytool -list -v -keystore D:/keys/mykeystore.keystore -storepass mypassword
公钥证书查看
keytool -printcert -file D:/keys/publickey.cer
package com.justin.key;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.Enumeration;
import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Encoder;
/**
* 从证书库获取公私钥、公钥证书获取公钥、私钥签名、公钥验签
* @author justinqin
*
*/
public class GenKeyStoreTest {
public static String KEYSTORD_FILE = "D:\\keys\\mykeystore.keystore";//证书库文件
public static String PUB_CER_FILE = "D:\\keys\\publickey.cer";//公钥证书
public static String KEYSTORD_PASSWORD = "mypassword";//证书库密码
public static String PRIKEY_PASSWORD = "mypassword";//私钥密码
public static String KEYSTORD_ALIAS = "mykeystore";//证书库别名:有多个别名时,引用参数指定具体别名
public static String CONTENT = "内容content";
public static String SIGALG_MD5WITHRSA ="MD5withRSA"; //sigalg(签名算法):MD5withRSA
public static String SIGALG_SHA1WITHRSA ="SHA1withRSA"; //sigalg(签名算法):SHA1withRSA
public static String SIGALG_SHA256WITHRSA ="SHA256withRSA"; //sigalg(签名算法):SHA256withRSA
public static String SIGALG_SHA384WITHRSA ="SHA384withRSA"; //sigalg(签名算法):SHA384withRSA
public static String SIGALG_SHA512WITHRSA ="SHA512withRSA"; //sigalg(签名算法):SHA256withRSA
public static String STORE_TYPE_JKS ="JKS";
public static void main(String[] args) throws Exception {
//====================证书库中获取私钥、公钥,公钥证书中获取公钥========================
KeyStore keyStore = getKeyStore(KEYSTORD_FILE);
Certificate certificate = keyStore.getCertificate(KEYSTORD_ALIAS);
//私钥
PrivateKey privateKey = (PrivateKey) keyStore.getKey(KEYSTORD_ALIAS, PRIKEY_PASSWORD.toCharArray());
//公钥(从证书库文件中)
PublicKey publicKey = certificate.getPublicKey();
//公钥(从公钥证书中获取)
PublicKey cerPublicKey = getPublicKeyFromPubCerFile(PUB_CER_FILE);
//====================base64位输出公私钥========================
base64PrintKey(privateKey.getEncoded(),"证书库","私钥");
String base64KeystorePubKey = base64PrintKey(publicKey.getEncoded(),"证书库","公钥");
String base64CerPubKey = base64PrintKey(cerPublicKey.getEncoded(),"公钥证书","公钥");
System.out.println("证书库中的公钥和公钥证书中的公钥是否相同:" + base64KeystorePubKey.equals(base64CerPubKey));
//====================用私钥对明文进行签名========================
String md5Sign = sign(CONTENT.getBytes(),privateKey,SIGALG_MD5WITHRSA,null);
String sha1Sign = sign(CONTENT.getBytes(),privateKey,SIGALG_SHA1WITHRSA,null);
String sha256Sign = sign(CONTENT.getBytes(),privateKey,SIGALG_SHA256WITHRSA,null);
String sha384Sign = sign(CONTENT.getBytes(),privateKey,SIGALG_SHA384WITHRSA,null);
String sha512Sign = sign(CONTENT.getBytes(),privateKey,SIGALG_SHA512WITHRSA,null);
//====================公钥验签========================
verify(CONTENT.getBytes(),Base64.decodeBase64(md5Sign), publicKey,SIGALG_MD5WITHRSA,null);
verify(CONTENT.getBytes(),Base64.decodeBase64(sha1Sign), publicKey,SIGALG_SHA1WITHRSA,null);
verify(CONTENT.getBytes(),Base64.decodeBase64(sha256Sign), publicKey,SIGALG_SHA256WITHRSA,null);
verify(CONTENT.getBytes(),Base64.decodeBase64(sha384Sign), publicKey,SIGALG_SHA384WITHRSA,null);
verify(CONTENT.getBytes(),Base64.decodeBase64(sha512Sign), publicKey,SIGALG_SHA512WITHRSA,null);
}
/**
* base64输出公私钥
* @param keyEncoded
* @param keyFile
* @param keyType
* @return
*/
private static String base64PrintKey(byte[] keyEncoded,String keyFile,String keyType) {
String base64Key = new BASE64Encoder().encode(keyEncoded);
System.out.println("base64输出" + keyFile + "中的"+ keyType + ":");
System.out.println(base64Key);
return base64Key;
}
/**
* 获取证书库对象
* @param keystoreFile
* @return
* @throws Exception
*/
private static KeyStore getKeyStore(String keystoreFile) throws Exception {
FileInputStream keystoreIs = new FileInputStream(new File(KEYSTORD_FILE));
KeyStore keyStore = KeyStore.getInstance(STORE_TYPE_JKS);
keyStore.load(keystoreIs, KEYSTORD_PASSWORD.toCharArray());
keystoreIs.close();
return keyStore;
}
/**
* 签名:使用私钥进行签名
* @param message
* @param privateKey
* @param algorithm
* @param provider
* @return
* @throws Exception
*/
public static String sign(byte[] message, PrivateKey privateKey, String algorithm, String provider) throws Exception {
Signature signature;
if (null == provider || provider.length() == 0) {
signature = Signature.getInstance(algorithm);
} else {
signature = Signature.getInstance(algorithm, provider);
}
signature.initSign(privateKey);
signature.update(message);
byte[] sign = signature.sign();
return Base64.encodeBase64String(sign);
}
/**
* 验签:使用公钥进行验签
* @param message
* @param signMessage
* @param publicKey
* @param algorithm
* @param provider
* @return
* @throws Exception
*/
public static boolean verify(byte[] message, byte[] signMessage, PublicKey publicKey, String algorithm,
String provider) throws Exception {
Signature signature;
boolean verifyResult;
if (null == provider || provider.length() == 0) {
signature = Signature.getInstance(algorithm);
} else {
signature = Signature.getInstance(algorithm, provider);
}
signature.initVerify(publicKey);
signature.update(message);
verifyResult = signature.verify(signMessage);
System.out.println(algorithm+ "验签结果:" + verifyResult);
return verifyResult;
}
/**
* 从公钥证书中获取公钥
* @param pubCerFile
* @return
* @throws Exception
*/
public static PublicKey getPublicKeyFromPubCerFile(String pubCerFile) throws Exception{
FileInputStream cerIs = new FileInputStream(new File(pubCerFile));
CertificateFactory cer = CertificateFactory.getInstance("X.509");
Certificate cerCertificate = cer.generateCertificate(cerIs);
cerIs.close();
PublicKey cerPublicKey = cerCertificate.getPublicKey();
return cerPublicKey;
}
/**
* 证书库获取别名:证书库只有一个别名时,该方法能取到默认别名,有多个别名时,会被覆盖,需引用参数指定具体别名
*
* @param pubCerFile
* @return
* @throws Exception
*/
public static String getAliasByKeystore(KeyStore keyStore) throws Exception{
Enumeration aliasEnum = keyStore.aliases();
String keystoreAlias=null;
while (aliasEnum.hasMoreElements()) keystoreAlias = (String) aliasEnum.nextElement();
return keystoreAlias;
}
}
========================测试结果====================
base64输出证书库中的私钥:
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCA1U01yh9UIb2JYFgBvJO6My2n
UKVOz5Squ25T9Hw6nJVemZrwmRIRm1lYEE0Zp92uxelQZfMerERoRFEZwdh8TwLnxBfyR9YRC99F
DsRty2m2Dkwvkr3EI70ruHANsaFmS3ReSw4O6ZgpvAiboC87o49AQe3rv+ICHIbbjHUZy/bIYML2
24AbjOrOajqC3fEl7ZwHn94lEAf2EXOFU5B/qfk13YqdZcb46txwbtVWdHIT0PzU2+e1qZU655ZR
jO4kVLyPKURfelyTemTmezI5o3RBiKU3psLsMnC69DzA6F66+FAYt5IiX7EWvfXe0Oj6AU2LKVnT
V+3g9ZBNvsG/AgMBAAECggEAV0QkkJLgtbRFFpDUDBkYV7/i5LqTvtaM9TkQen3YyDrYUsPpV5/X
xWVdF3GzR/WVC5WzfGoSTGyTyay84p2TbmB2r1b8gXh3YASSr8xY8aYfbNoycOcM85bhxIOiIyR3
Fzt1D4n3c9J2544epovScqtPlU8TQeUvyg5Yqs5xY473CuRezAGz6OGBJ/PT4JlwDsOf5vOx2U5F
8+4fbkvACz14uM49vSmFeoz2VA3W8/+WrJFIJc+x7qIJFecfRxE4i+1f94OSLFn0fYciPV07jZt4
bZMLc2iAIJaCUDbJUTDCBH4J0wk4qmjJhrR/3M+3VLKPLRhpW3ezHcyB46OfwQKBgQC10WcQ1INW
hf4+UlT2u97LqeyKUI9sdFa0GmCWxEfHNxiycvqbevqon63rxEcTD2GS2aqzHGSLnp/WcawKt2Xr
GEwf/jvtVypVPcQVrkRIoFw1aynbazVy11oYACAUheqenCtS8NFpCVSBEMqA4c//GaRZInvYga9z
zq7sbEYKvQKBgQC1Zbl3io8nuVOQVZQFJbnlFF1wIy6/855APQLS5udxIFpC5VrYjhm44B7+aii1
21uz7dfsrDIFabv21vq+ITssxNw1MmCS9ihwwUbZmNK0BTFAK1RywHiU6GEeVLoVFbPe6Ghs7vOc
RksPo8nOTAjHV6fmnd+GGDbyujUcYhAEKwKBgB1FfDlabValtdvkt2cNsf3J+pn+BEkqpbbTNE+x
g/jPpvs7xZr4fphdNMvrSqIH7OaOgovZe1p7DDKjFFaZViA2RjM0ZAN+8ALPMd1ns/iZUJ8NBK0d
ono9r3SDuKZ1NOOaMuNkf+JQLTmmMWP0dt8UCsCK67NclZmoYcMQX2plAoGBAKOtcUezR+8BI6zF
+3UVkIJq+NDZfjKH4VB3fNfOsCF8ntVj3LAwsHcIDA9mvOszTrCxOTd+PPhzar6VRtVOaPXBgC2k
Ek4pPV5Yl9R6OA1l7gXH00Bj+anrcM6MhwfFeHL3ZFp+1mQ5bTtkgBDcvMMajg7ifzGhIdutN4Uv
2uHXAoGAa3wj3zviGCaDh2CRsOgs62fR+nu0ck+OvqMDUoQN4qKitoaqpixgLPz99byFPbD65Z80
t61mG1k0rp5OXVSr7QnZmtQ+rh763i7gg6AEYNDnPH116ozY+Klf2Rl9CIs0G8/UHTGO1/Q5ZqD7
0xtrMMwe2Qw6fgsH4kTP6iwIml0=
base64输出证书库中的公钥:
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgNVNNcofVCG9iWBYAbyTujMtp1ClTs+U
qrtuU/R8OpyVXpma8JkSEZtZWBBNGafdrsXpUGXzHqxEaERRGcHYfE8C58QX8kfWEQvfRQ7Ebctp
tg5ML5K9xCO9K7hwDbGhZkt0XksODumYKbwIm6AvO6OPQEHt67/iAhyG24x1Gcv2yGDC9tuAG4zq
zmo6gt3xJe2cB5/eJRAH9hFzhVOQf6n5Nd2KnWXG+OrccG7VVnRyE9D81NvntamVOueWUYzuJFS8
jylEX3pck3pk5nsyOaN0QYilN6bC7DJwuvQ8wOheuvhQGLeSIl+xFr313tDo+gFNiylZ01ft4PWQ
Tb7BvwIDAQAB
base64输出公钥证书中的公钥:
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgNVNNcofVCG9iWBYAbyTujMtp1ClTs+U
qrtuU/R8OpyVXpma8JkSEZtZWBBNGafdrsXpUGXzHqxEaERRGcHYfE8C58QX8kfWEQvfRQ7Ebctp
tg5ML5K9xCO9K7hwDbGhZkt0XksODumYKbwIm6AvO6OPQEHt67/iAhyG24x1Gcv2yGDC9tuAG4zq
zmo6gt3xJe2cB5/eJRAH9hFzhVOQf6n5Nd2KnWXG+OrccG7VVnRyE9D81NvntamVOueWUYzuJFS8
jylEX3pck3pk5nsyOaN0QYilN6bC7DJwuvQ8wOheuvhQGLeSIl+xFr313tDo+gFNiylZ01ft4PWQ
Tb7BvwIDAQAB
证书库中的公钥和公钥证书中的公钥是否相同:true
MD5withRSA验签结果:true
SHA1withRSA验签结果:true
SHA256withRSA验签结果:true
SHA384withRSA验签结果:true
SHA512withRSA验签结果:true
==========拷贝得到的公私钥字符串,首尾格式化
公钥首尾:
-----BEGIN PUBLIC KEY-----
公钥字符串
-----END PUBLIC KEY-----
私钥首尾:
-----BEGIN RSA PRIVATE KEY-----
私钥字符串
-----END RSA PRIVATE KEY-----
==========在线RSA公私密钥校验、RSA公私密钥检查 http://tool.chacuo.net/cryptrsakeyvalid