Keytool 简述

About keytool

Java Keytool 是一个可以生成公私钥对并将其存储到 [Java KeyStore](./About KeyStore.md) 的命令行工具. 是随 JDK (或者 JRE) 发布的.

λ keytool
密钥和证书管理工具

命令:

 -certreq            生成证书请求
 -changealias        更改条目的别名
 -delete             删除条目
 -exportcert         导出证书
 -genkeypair         生成密钥对
 -genseckey          生成密钥
 -gencert            根据证书请求生成证书
 -importcert         导入证书或证书链
 -importpass         导入口令
 -importkeystore     从其他密钥库导入一个或所有条目
 -keypasswd          更改条目的密钥口令
 -list               列出密钥库中的条目
 -printcert          打印证书内容
 -printcertreq       打印证书请求的内容
 -printcrl           打印 CRL 文件的内容
 -storepasswd        更改密钥库的存储口令

本文会介绍这些命令的通常用法.

生成密钥对

使用 Java Keytool 最常见的场景大概就是生成公私钥对了, 生成的自签名密钥对被放到 Java KeyStore 文件中. 以下是一些用于生成密钥对的常用的参数:

λ keytool -genkeypair -help
keytool -genkeypair [OPTION]...

生成密钥对

选项:

 -alias <alias>                  生成的密钥被标识唯一的 Java KeyStore 的名称.
 -keyalg <keyalg>                密钥算法名称
 -keysize <keysize>              密钥位大小
 -sigalg <sigalg>                签名算法名称
 -destalias <destalias>          目标别名
 -dname <dname>                  唯一判别名, X.500 标准中的专有名词. 在 KeyStore 中, 这个名称与当前密钥对的别名关联. 在自签名的证书中, 这个名称同样也作为 issuer 和 subject
 -startdate <startdate>          证书有效期开始日期/时间
 -ext <value>                    X.509 扩展
 -validity <valDays>             有效天数
 -keypass <arg>                  密钥口令
 -keystore <keystore>            密钥库名称
 -storepass <arg>                密钥库口令
 -storetype <storetype>          密钥库类型
 -providername <providername>    提供方名称
 -providerclass <providerclass>  提供方类名
 -providerarg <arg>              提供方参数
 -providerpath <pathlist>        提供方类路径
 -v                              详细输出
 -protected                      通过受保护的机制的口令

例子:

keytool -genkeypair -alias my-very-first-key -keyalg RSA -keysize 2048 -dname "CN=caplike, OU=personal, O=caplike, L=Chengdu, ST=Unknown, C=CN" -keypass my-very-first-key-password -validity 100 -storetype JKS -keystore my-very-first-keystore.jks -storepass my-key-store-password

这样, 在当前目录下会生成一个名为 my-very-first-keystore.jks 的文件.

证书相关操作

导出证书

Java KeyTool 也能导出保存在 KeyStore 中的证书, 以下是导出证书的命令说明:

λ  keytool -exportcert -help
keytool -exportcert [OPTION]...

导出证书

选项:

 -rfc                            以 RFC 样式输出
 -alias <alias>                  要处理的条目的别名
 -file <filename>                输出文件名
 -keystore <keystore>            密钥库名称
 -storepass <arg>                密钥库口令
 -storetype <storetype>          密钥库类型
 -providername <providername>    提供方名称
 -providerclass <providerclass>  提供方类名
 -providerarg <arg>              提供方参数
 -providerpath <pathlist>        提供方类路径
 -v                              详细输出
 -protected                      通过受保护的机制的口令

例子:

keytool -exportcert -alias my-very-first-key -keypass my-very-first-key-password -storetype JKS -keystore my-very-first-keystore.jks -file my-very-first-cert.cert -storepass my-key-store-password
存储在文件 <my-very-first-cert.cert> 中的证书

当前目录下会生成一个名为 my-very-first-cert.cert 的文件.

导入证书

Java Keytool 也能将证书导入 KeyStore.

λ  keytool -importcert -help
keytool -importcert [OPTION]...

导入证书或证书链

选项:

 -noprompt                       不提示
 -trustcacerts                   信任来自 cacerts 的证书
 -protected                      通过受保护的机制的口令
 -alias <alias>                  要处理的条目的别名
 -file <filename>                输入文件名
 -keypass <arg>                  密钥口令
 -keystore <keystore>            密钥库名称
 -storepass <arg>                密钥库口令
 -storetype <storetype>          密钥库类型
 -providername <providername>    提供方名称
 -providerclass <providerclass>  提供方类名
 -providerarg <arg>              提供方参数
 -providerpath <pathlist>        提供方类路径
 -v                              详细输出

例子:

keytool -importcert -alias my-very-first-key -keypass my-very-first-key-password -storetype JKS -keystore my-second-keystore.jks -file another-cert.cert -rfc -storepass my-key-store-password

查看证书

λ keytool -printcert -help
keytool -printcert [OPTION]...

打印证书内容

选项:

 -rfc                        以 RFC 样式输出
 -file <filename>            输入文件名
 -sslserver <server[:port]>  SSL 服务器主机和端口
 -jarfile <filename>         已签名的 jar 文件
 -v                          详细输出

例子:

λ keytool -printcert -file my-very-first-cert.cert -v

控制台输出:

所有者: CN=caplike, OU=personal, O=caplike, L=Chengdu, ST=Unknown, C=CN
发布者: CN=caplike, OU=personal, O=caplike, L=Chengdu, ST=Unknown, C=CN
序列号: 309c2dc8
有效期为 Tue Jul 14 14:50:00 CST 2020 至 Thu Oct 22 14:50:00 CST 2020
证书指纹:
         MD5:  58:2D:17:7A:E6:57:06:F0:32:6A:5E:45:9B:9D:57:49
         SHA1: A3:41:6E:54:13:4A:80:83:BE:48:F2:B8:C0:A7:83:24:89:B4:65:F2
         SHA256: F2:42:37:FC:8E:AF:B2:12:B4:FC:9C:CB:8C:1E:4F:FC:B0:F5:DB:1D:F6:05:CC:1F:08:DC:EE:8E:B3:08:17:13
签名算法名称: SHA256withRSA
主体公共密钥算法: 2048 位 RSA 密钥
版本: 3

扩展:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 84 A0 3B 38 46 80 A3 D6   2E 78 06 16 29 36 48 F5  ..;8F....x..)6H.
0010: EB A9 85 EF                                        ....
]
]

或者直接查看证书详细信息:

λ keytool -list -rfc -keystore authorization-server.jks
输入密钥库口令:
密钥库类型: PKCS12
密钥库提供方: SUN

您的密钥库包含 1 个条目

别名: authorization-server-jwt-keypair
创建日期: 2020-7-17
条目类型: PrivateKeyEntry
证书链长度: 1
证书[1]:
-----BEGIN CERTIFICATE-----
MIIDbzCCAlegAwIBAgIEAfMOsjANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJD
TjEQMA4GA1UECBMHU2ljaHVhbjEQMA4GA1UEBxMHQ2hlbmdkdTEQMA4GA1UEChMH
Y2FwbGlrZTERMA8GA1UECxMIcGVyc29uYWwxEDAOBgNVBAMTB2NhcGxpa2UwHhcN
MjAwNzE3MDc0MzU0WhcNMzAwNzE1MDc0MzU0WjBoMQswCQYDVQQGEwJDTjEQMA4G
A1UECBMHU2ljaHVhbjEQMA4GA1UEBxMHQ2hlbmdkdTEQMA4GA1UEChMHY2FwbGlr
ZTERMA8GA1UECxMIcGVyc29uYWwxEDAOBgNVBAMTB2NhcGxpa2UwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCUvHlvPfO7+m1mlW68IFBnh0x4OGZkmbLG
JrsD3vToHmj+KksVxmeM60pVBxlNrxQ6eJMMnjoOYzIrZDmhbx3bhykx09LDE0xT
/t06/jQMWegVQUhZRH/58BlVMJ8lvukGnNamYua86EtXytI4pslMh5FRaCwVmwIk
lqohrf/qTuahNXgNRFSCHUAGYzJdR3f/N5KR08le71AJ3EXKBI9Umzh3kGqv3uZE
4h232qaeBqnUtyHZ6XCvNa5DHreYbGgr6XERAHp+108u+kQAG4IGzuE7XwIGPl6L
0b5+hoV7/vua40IgsC29zxSIPo9Ft/l7VhcSnQgdmKy46F52OoEVAgMBAAGjITAf
MB0GA1UdDgQWBBRqowFVjNkW77ZciS10KyMWs/3n2jANBgkqhkiG9w0BAQsFAAOC
AQEAJ+d+/0ss/Hl8IhPuIbH5Hh3MMxK8f02/QBPyJ5+ZJgt9k1BZc6/eMYbWd41z
05gb2m2arXfAS2HEdsY1pCfcssb85cVYUwMoDfK7pLRX34V0uhdUm0wqTBumIs2i
CCLCz7Eci4XpAv+RWHVKXbg+pP7GrKBh0iNYTuV+pDr+D7K6rZwGjYsGAqqpc1Lj
NNaN68pHhTnwXu4igM/gLsNRmR+2zXyJ1FZegnk0fsFWojOqHwCZxYli9245N4Hg
ePIVTvFTu+QzdLzFUcsGqhrynHfwQOvTyPMpaowpOsguNSzTdmRRK3QdtKHglE10
us40NUJZQgavCigGcVwAv/jCdA==
-----END CERTIFICATE-----


*******************************************
*******************************************

罗列 KeyStore 的条目

可以用 -list 命令罗列 Java KeyStore 中的条目.

λ keytool -list -help
keytool -list [OPTION]...

列出密钥库中的条目

选项:

 -rfc                            以 RFC 样式输出
 -alias <alias>                  要处理的条目的别名
 -keystore <keystore>            密钥库名称
 -storepass <arg>                密钥库口令
 -storetype <storetype>          密钥库类型
 -providername <providername>    提供方名称
 -providerclass <providerclass>  提供方类名
 -providerarg <arg>              提供方参数
 -providerpath <pathlist>        提供方类路径
 -v                              详细输出
 -protected                      通过受保护的机制的口令

例子:

keytool -list -storetype JKS -keystore my-very-first-keystore.jks -storepass my-key-store-password

控制台输出:

λ keytool -list -storetype JKS -keystore my-very-first-keystore.jks -storepass my-key-store-password
密钥库类型: JKS
密钥库提供方: SUN

您的密钥库包含 1 个条目

my-very-first-key, 2020-7-14, PrivateKeyEntry,
证书指纹 (SHA1): A3:41:6E:54:13:4A:80:83:BE:48:F2:B8:C0:A7:83:24:89:B4:65:F2

也可以通过指定别名的方式显示列举某一条记录.

删除 KeyStore 条目

The Keytool has a command that can delete a key entry in a Java KeyStore. The Keytool command for deleting keys is -delete. Here is the format of the Keytool -delete command:

λ keytool -delete -help
keytool -delete [OPTION]...

删除条目

选项:

 -alias <alias>                  要处理的条目的别名
 -keystore <keystore>            密钥库名称
 -storepass <arg>                密钥库口令
 -storetype <storetype>          密钥库类型
 -providername <providername>    提供方名称
 -providerclass <providerclass>  提供方类名
 -providerarg <arg>              提供方参数
 -providerpath <pathlist>        提供方类路径
 -v                              详细输出
 -protected                      通过受保护的机制的口令

该命令会删除 JKS 文件中与当前别名匹配的条目.

keytool -delete -alias <alias> -storetype JKS -keystore <keystore> -storepass <keystore-pass>

证书请求

生成证书请求

-certreq 命令用于生成 “证书请求”. 证书请求是请求发证机构 (CA) 为你的组织创建公共证书的请求. 一旦创建, 证书请求应当被发送到你想创建证书的颁发机构去.

Before you can generate a certificate request for a private key, public key pair, you must have generated that private key, public key pair into the Keystore (or imported it). See elsewhere in this Java Keytool tutorial to see how to do that.

Here is the command format for generating a certificate request. Remember to remove all line breaks when trying out this command:

-certreq
    -alias alias
    -sigalg sigalg
    -file certreq_file
    -keypass keypass
    -storetype storetype
    -keystore keystore
    -storepass storepass
    -providerName provider_name
    -providerClass provider_class_name
      -providerArg provider_arg
    -v
    -protected
    -Jjavaoption

The arguments are explained in the Keytool Arguments section. Not all of these arguments are needed. Many are optional. The Keytool will tell you if you are missing a required argument.

Here is a Java Keytool -certreq command example:

"C:\\Program Files\Java\jdk1.8.0_111\bin\keytool"
    -certreq
    -alias testkey
    -keypass 123456
    -storetype JKS
    -keystore keystore.jks
    -storepass abcdef
    -file certreq.certreq

This command will generate a certificate request for the key stored with alias testkey in the keystore file keystore.jks, and write the certificate request into the file named certreq.certreq .

附录

keytool 参数列表

参数描述
-aliaskey 的别名, 标识一条 key 记录.
-keyalgThe name of the algorithm used to generate the key. A common value is RSA meaning the RSA algorithm should be used to generate the key pair.
-keysize8 which aligns with a number of bytes. Additionally, different algorithms may only support certain preset key sizes. You will need to check what the key size should be for the key you want to generate.
-sigalg密钥对的签名算法.
-dname标识名 (X.500 标准), 会与这个密钥对关联, 如果是自签名证书, dname 也会作为 “issuer” 和 “subject” 字段的值. 由证书拥有者名称 (CN), 组织单位 (OU), 组织 (O), 州 (ST), 城市 (L), 国家/地区 © 组成.
-keypass访问当前密钥对的密码.
-validity关联这个密钥对的证书的有效期 (天).
-storetypeKeyStore 的类型. 默认是 JKS. 也可以是其他类型例如 PKCS11.
-keystoreKeyStore 文件名.
-fileThe name of the file to read from or write to (certificate or certificate request).
-storepassThe password for the whole KeyStore. Anyone who wants to open this KeyStore later will need this password. The storepass is not the same as the keypass. The keypass password only counts for a single key. You will need both the KeyStore password and the key password to access any given key stored in a KeyStore.
-rfcIf this flag is included (it has no value following it) then Keytool will use a textual format rather than binary format e.g. for export or import of certificates. 指定以Base64编码格式输出, 通常不设置
-providerNameThe name of the cryptographic API provider you want to use (if any) when generating the key pair. The provider name must be listed in the Java security property files for this to work.
-providerClassThe name of the root class of the cryptographic API provider you want to use. Use this when the provider name is not listed in the Java security property files.
-providerArg初始化的时候可以传递给 Provider 的参数 (如果需要).
-vverbose 以可读的方式打印额外信息.
-protectedSpecifies whether or not the KeyStore password should be provided by some external mechanism like a pin reader. Valid values are true and false.
-Jjavaoption可用与传递给 JVM 的可选字符串参数.

Warning: JKS 密钥库使用专用格式 (JKS 转 PKCS#12)

如果生成密钥对或是读取公钥是看到如下提示:

Warning:

JKS 密钥库使用专用格式。建议使用 “keytool -importkeystore -srckeystore authorization-server.jks -destkeystore authorization-server.jks -deststoretype pkcs12” 迁移到行业标准格式 PKCS12。

说明我们需要把 KeyStore 的类格式换成 PKCS12, 执行如下命令即可:

λ keytool -importkeystore -srckeystore authorization-server.jks -destkeystore authorization-server.jks -deststoretype pkcs12 -destkeypass ********
输入源密钥库口令:
警告: PKCS12 密钥库不支持其他存储和密钥口令。正在忽略用户指定的-destkeypass值。
输入 <authorization-server-jwt-keypair> 的密钥口令
已成功导入别名 authorization-server-jwt-keypair 的条目。
已完成导入命令: 1 个条目成功导入, 0 个条目失败或取消

Warning:
已将 "authorization-server.jks" 迁移到 Non JKS/JCEKS。将 JKS 密钥库作为 "authorization-server.jks.old" 进行了备份。

具体原因: JKS 全称 Java Key Store, 是 JAVA 密钥库的专属格式, 一般用于 Tomcat 服务器. PKCS#12 全称 Personal Information Exchange Syntax Standard, 描述了将用户公钥, 私钥, 证书和其他相关信息打包的语法. 和 JKS 一样都是二进制格式, 同时包含证书和私钥.


需要注意的是 PKCS#12 类型的密钥库不支持单独为 PrivateKey 指定密钥, 所以 -keypass 会被忽略. 密钥库的密钥就是 KeyPair 的密钥, 所以如果创建 PKCS#12 类型的密钥库, 命令应该形如:

keytool -genkeypair -alias authorization-server-jwt-keypair -keyalg RSA -keysize 2048 -dname "CN=caplike, OU=personal, O=caplike, L=Chengdu, ST=Sichuan, C=CN" -vali dity 3650 -storetype PKCS12 -keystore authorization-server.jks -storepass *******

FormatNameDescription
PKCS #7Cryptographic Message Syntax StandardA PKCS #7 file can be used to store certificates,
which is a SignedData structure without data (just the certificates). The file name extension is usually .p7b, .p7c
PKCS #8Private-Key Information Syntax Standard.Used to carry private certificate keypairs (encrypted or unencrypted).
PKCS #12Personal Information Exchange Syntax Standard.Defines a file format commonly used to store private keys with accompanying public key certificates,
protected with a password-based symmetric key. It is the successor to PFX from Microsoft.
DERDistinguished Encoding RulesA binary format for keys or certificates. It is a message transfer syntax specified by the ITU in X.690.
PEMPrivacy Enhanced Mail一般是文本格式,
Base64 encoded DER certificates or keys, with additional header and footer lines.
The PEM private key format uses the header and footer lines:
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
The PEM public key format uses the header and footer lines:
-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----
The PEM certificate uses the header and footer lines:
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----

Reference

OpenSSL 从 KeyStore 中读取公钥和证书

我们还可以通过如下命令以命令行的形式直接从 KeyStore 中以 X.509 格式标准, 采用 PEM 的格式读取公钥和证书内容:

λ keytool -list -rfc --keystore authorization-server.jks | openssl x509 -inform pem -pubkey
输入密钥库口令:  ********
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0KwrwapB4g+jtX9UevtB
H/G9MAJLT+aJ+7D8WsKO4EEEVTnnS3PpO8TGQ5oYdWfHMQpJ3NhdNrMLz+6jX2on
zyRYvjBjCezIM3Ug3vXxm7JryDSvQZSyqcbXfAjrYQKaZOb2Ikgb6o3wvryJxE90
CIE1GtMcE6PKydg4tcKCR9ZYb5cw9Oehk7UI5GK8L17rF71YIWU0DQXAeHVhsSa7
/MNclfgAb5fJftwCzWOkP7dCfxuDfAWvKyko6BRnGVKReU5dXLbAU5PSqFcnaW1S
VqeHLSct1eKUoeDN7iUjuVim2UxFb2ZlIMIVBqle5WqZwFIVql0hOjzN2lC77X1P
/QIDAQAB
-----END PUBLIC KEY-----
-----BEGIN CERTIFICATE-----
MIIDbzCCAlegAwIBAgIEfy56hzANBgkqhkiG9w0BAQsFADBoMQswCQYDVQQGEwJD
TjEQMA4GA1UECBMHU2ljaHVhbjEQMA4GA1UEBxMHQ2hlbmdkdTEQMA4GA1UEChMH
Y2FwbGlrZTERMA8GA1UECxMIcGVyc29uYWwxEDAOBgNVBAMTB2NhcGxpa2UwHhcN
MjAwNzE3MDUyMjM3WhcNMzAwNzE1MDUyMjM3WjBoMQswCQYDVQQGEwJDTjEQMA4G
A1UECBMHU2ljaHVhbjEQMA4GA1UEBxMHQ2hlbmdkdTEQMA4GA1UEChMHY2FwbGlr
ZTERMA8GA1UECxMIcGVyc29uYWwxEDAOBgNVBAMTB2NhcGxpa2UwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQrCvBqkHiD6O1f1R6+0Ef8b0wAktP5on7
sPxawo7gQQRVOedLc+k7xMZDmhh1Z8cxCknc2F02swvP7qNfaifPJFi+MGMJ7Mgz
dSDe9fGbsmvINK9BlLKpxtd8COthAppk5vYiSBvqjfC+vInET3QIgTUa0xwTo8rJ
2Di1woJH1lhvlzD056GTtQjkYrwvXusXvVghZTQNBcB4dWGxJrv8w1yV+ABvl8l+
3ALNY6Q/t0J/G4N8Ba8rKSjoFGcZUpF5Tl1ctsBTk9KoVydpbVJWp4ctJy3V4pSh
4M3uJSO5WKbZTEVvZmUgwhUGqV7lapnAUhWqXSE6PM3aULvtfU/9AgMBAAGjITAf
MB0GA1UdDgQWBBSrIIuwp9u3nwm9PFP6wbabSWUsvTANBgkqhkiG9w0BAQsFAAOC
AQEAh+J/ghJbGDFaSUcbj0AyvMSMD2NjlpLrRNsneccztA6vuLdHVM8Ow5JIBdaN
55mS0eZwS9hwHiiJlkE43znh1PESZtltZN/bGtCtI/0DOQHEyamzXrSjigRX7W0Y
+71CwQbONcPVFXAAklxq1Pf51fQKs82GrR2TY97EWBofwqIzaAT6a7l+Bkqasr1A
6Q9aWbDC/QJhzWtEGMAYysuquEOBcfcfyBfm7y/FMqPoKCOI391KDERB7DC9+1l3
y0qEtVBR6Hp/w3iEABrPsBvoWMtqJUQtfQzmmYYTeupPnsiQC9hH1+4PxUbKiMl3
KKhFVqDr3Zt+8tZy8GUK05UGBw==
-----END CERTIFICATE-----

Reference

JAVA 从 KeyStore 中读取公私钥

/**
 * Description: 从证书中读取公钥和私钥
 *
 * @return void
 * @author LiKe
 * @date 2020-07-14 15:49:15
 */
public static void read() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException {
    final KeyStore keyStore = KeyStore.getInstance("JKS");
    keyStore.load(new FileInputStream("D:\\caplike\\coding\\temp\\my-very-first-keystore.jks"), "my-key-store-password".toCharArray());
    
    final PublicKey publicKey = keyStore.getCertificate("my-very-first-key").getPublicKey();
    System.out.println("PublicKey: ");
    System.out.println(Base64.getEncoder().encodeToString(publicKey.getEncoded()));

    final Key key = keyStore.getKey("my-very-first-key", "my-very-first-key-password".toCharArray());
    System.out.println("PrivateKey: ");
    System.out.println(Base64.getEncoder().encodeToString(key.getEncoded()));
}

控制台输出:

PublicKey: 
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnXr2y4WHXd7zQYHLY8AaV1DeDJ+NDNJrRy++gGtXtgPqV81bDa/9VAap0fM3fmgVPzVBmG5ke/lKCAEGyvoOAD/eVADGi6yuyjcruFEjKOVk8ZVqA/1GNzuGzYzzQcSQ3Nd4BQape/qUfurnmVHEHPzG60vR1vinKm+llgUCf7GmSOiCjHq5FPCC5LrRJvmFE1UpSiuWbFIN+7Vb03PAgC70HWLk0eaY3hKD8T7DKYAWZmTBN4zZy9VbTFFigUcHb7OJ0vLaBaLOWqScYRyENE55xfGaZJd4CWyjr2e2GPCl8bab65R6XpovKhh4kDTbFpUABiGDMYo0jwCpDEQuOwIDAQAB
PrivateKey: 
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCdevbLhYdd3vNBgctjwBpXUN4Mn40M0mtHL76Aa1e2A+pXzVsNr/1UBqnR8zd+aBU/NUGYbmR7+UoIAQbK+g4AP95UAMaLrK7KNyu4USMo5WTxlWoD/UY3O4bNjPNBxJDc13gFBql7+pR+6ueZUcQc/MbrS9HW+Kcqb6WWBQJ/saZI6IKMerkU8ILkutEm+YUTVSlKK5ZsUg37tVvTc8CALvQdYuTR5pjeEoPxPsMpgBZmZME3jNnL1VtMUWKBRwdvs4nS8toFos5apJxhHIQ0TnnF8Zpkl3gJbKOvZ7YY8KXxtpvrlHpemi8qGHiQNNsWlQAGIYMxijSPAKkMRC47AgMBAAECggEAZ/tOQ7oKVLAmvKVAL8AjZG4QABPFpaa2kQ10YwT9qEBTluAQdCw1QCsaLHfEt6FwDglTI5wYm0dSW5CZ9KJBZmbFnX/ZmVZPH1RoeM6SQameCmoW00WD/GpAqy6bXFy3LirTo7XvaN5e+KKQg8rajC1YBvtMNf5/GmUX18O9D6SqMcLfICqbEOjUfRT26gDRQGjZw2qgrzspY/qThNA9Qf/9Bbro4JHzjQJfX59VGeMVk/v5RsOWFGxFBE0zni7po6ODTVlCZT6T1RBS7Smw6y3mmfJ4mafFIciS0RI0ey0E3GLe1MpR0BLIkMz+d7/hPJbxIXLluljQ/s/sEQ7+QQKBgQDbP7LYpJIF8VtajO41M+TupKvdb8SSr3bGzicpzE+8VpjqcwSSiofrek3aFZzMpzA5v+uvfOflPEtLouY33ZlCgXjDYAN9a84qvpXqrMPUvWujx+Hm19pzLGLeFRrkNkiGYxX+HlC6CUjwwc7oEoYLw3TKWKklRhbTP/RuALHqoQKBgQC34K9j+TVwl/Sb1xVtqdrJmQlYp1PvZMf2+xS4gCWDN6ofSLJlHkFQ2l2EW11/4Ce+RYZ8K4bqR1zm/IS0wx/uFBo7ZVfBduo7VmoGOnf99SyrAhh3LUzmzSNNLiCPPXyoofrhYCT6nt9bvbK/gBy728hgpgunm2qzDSaWOj9nWwKBgQDDf+sz7psenXa+KYiG/D0Y5tExZOY9fiRFZbHaPYqj//veoqzjFo/YU3h0DG2Ct1nzRMUd+By3daoWSa1LB1gPy28pl8XE4oo15ze6yE7etgDzS9qNgtARfvSx3tPZxuWon1YPAG0vVfQqakba/Rl2B9VuUNySlgroV9DW/dunwQKBgQCLwgcNIZlwns6YtH3hADz/BYaJD4VIa31hR62UHjJk7aYsaQDOwpQ6c/6oXxlN3H3YrNdvAVZmMx91oXDsQ3K9biISCxEMRun5d9DWMxKIwBTXVZxq2M+ejUTLoMe2l7FsKtGZA46XvrFd9W0rCKDOWFqQuyQYnJQYy2IMxPD0CQKBgE8J/D5j7UDz4Hk675n3IUluEJEdBoopMqDj/avJU6bov9ZqdSlo2xqb6WluYO3mWofwpGGIzNnLwHSWVLTcoby0DMyI7Ze7EGyzjcWkKZyGFheWxWkcageXOgCV8P7iDIPm6EE1DS9IR9S5mkpaE+Jw+F4OT9v5OJlBYCmxquxH

JAVA 从证书中读取公钥

public void extractPublicKeyFromCertificateFile() {
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");

    //生成一个证书对象并使用从输入流 inStream 中读取的数据对它进行初始化。
    Certificate certificate = certificateFactory.generateCertificate(KeyStoreTools.class.getClassLoader().getResourceAsStream("public.cert"));
    PublicKey publicKey = certificate.getPublicKey();

    System.out.println("PublicKey: ");
    System.out.println(Base64.getEncoder().encodeToString(publicKey.getEncoded()));
}

Reference

修订日志

  • 2020-7-14 17:14:58
    • The Very First Version.
  • 2020-7-17 14:04:59
    • 新增 “附录” 章节.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值