在JAVA安全体系中,密钥很重要,通过密钥,可以执行从数字签名到加密数据流的大量加密操作。在这些安全的操作中,必须为许多算法提供密钥或证书,有时需要私钥,有时需要密钥,有时需要证书中包含的公钥。密钥管理系统的目的是存储这些密钥,并允许以命令和编程方式(或通过某些工具)检索它们。在Java平台中, 密钥库是通过管理工具(keytool)创建和操作的,并且有一个Java API允许以编程方式使用密钥库。在本章中,将通过查看keytool工具,使我们熟悉密钥库所体现的概念,然后将看到如何以编程方式使用密钥库。

Keystore位置

用户密钥库默认存储在用户主目录中名为.keystore的文件中,由“user.home”系统属性确定。 密钥库文件可以根据需要进行定位。 在某些环境中,可能存在多个密钥库。 例如,在JSSE(SSL / TLS)中,一个密钥库可能包含用户的私钥,而另一个可能包含用于建立信任关系的证书。
除了用户的密钥库以外,JDK还维护一个系统范围的密钥仓库,用于存储来自各种证书颁发机构(CA)的可信证书。 这些CA证书可以用来帮助做出信任与否的决定。 例如,在SSL / TLS中,当SunJSSE提供者被呈现来自远程的证书时,将检查信任证书库:

Solaris, Linux, or Mac OS X: /lib/ext/cacerts
Windows: \lib\ext\cacerts
来确定连接是否被信任。 应用程序可以设置和使用自己的密钥库,甚至可以使用上述的用户密钥库,而不是使用系统范围的cacerts密钥库。

Keystore实现

KeyStore类提供了定义良好的接口来访问和修改密钥库中的信息。 有可能存在多个不同的具体实现,其中每个实现都是针对特定类型的密钥库的实现。

应用程序可以使用KeyStore类中的getInstance方法,不同的提供者选择不同类型的密钥库实现。 密钥库类型定义密钥库信息的存储和数据格式,以及用于保护密钥库中的私钥和密钥库本身的完整性的算法。 不同类型的密钥库实现不兼容。

推荐的keystore实现是“pkcs12”。 这是基于RSA PKCS12个人信息交换语法标准的跨平台密钥库。 此标准主要用于存储或传输用户的私钥,证书和其他秘密。 任意属性可以与PKCS12密钥库中的单个条目相关联。

默认的keystore实现类型是“jks”,它在java.security文件中的以下行中指定:

keystore.type=jks

要使工具和其他应用程序使用不同的默认密钥库实现,可以更改该行以指定另一个默认类型。 例如,要使用“pkcs12”作为默认密钥库实现,将该行更改为:

keystore.type=pkcs12

某些应用程序(如keytool)也可以覆盖默认的密钥库类型(通过-storetype命令行参数)。

注意:密钥库类型标识不区分大小写。 例如,“jks”将被视为与“JKS”相同。

另“jceks”是替代的专有密钥库格式,用于使用基于密码的三重DES进行加密的“jks”。
Sun的“jceks”实现可以解析并将“jks”密钥库文件转换为“jceks”格式。 可以通过更改密钥库中私钥条目的密码并指定-storetype jceks作为密钥库类型,将类型“jks”的密钥库升级到类型为“jceks”的密钥库。 要在默认密钥库中应用提供给名为“signkey”的私钥的加密强密钥保护,请使用以下命令,该命令将提示您输入旧密钥和新密钥密码:
keytool -keypasswd -alias signkey -storetype jceks

KeyStore类

KeyStore类是一个引擎类,提供良好定义的接口来访问和修改密钥库中的信息。

这个类表示内存中的密钥和证书集合。 KeyStore管理三种类型的条目:

每种类型的条目都实现了KeyStore.Entry接口。提供了三个基本的KeyStore.Entry实现:

KeyStore.PrivateKeyEntry
此类条目包含加密PrivateKey,可选择以受保护的格式存储,以防止未经授权的访问。它还附带相应公钥的证书链。

私钥和证书链由给定实体用于自我认证。此身份验证的应用程序包括软件分发组织,它们将JAR文件作为发布和/或许可软件的一部分进行签名。

KeyStore.SecretKeyEntry
此类条目包含加密SecretKey,可选择以受保护的格式存储,以防止未经授权的访问。

KeyStore.TrustedCertificateEntry
此类条目包含属于另一方的单个公钥证书。它被称为可信证书,因为密钥库所有者信任证书中的公钥确实属于证书的主体(所有者)所标识的身份。

Keytool简介

Keytool是一个Java密钥及数据证书的管理工具,这个工具一般在 JDK\jre\bin\security\目录下 。所有的数字证书是以一条一条(采用别名区别)的形式存入证书库的中,证书库中的每个证书包含该条证书的私钥,公钥和对应的数字证书的信息。

证书库中的一条证书可以导出数字证书文件,数字证书文件只包括主体信息和对应的公钥
Keytool将密钥(key)和证书(certificates)存在一个称为keystore的文件中
在keystore里,包含两种数据:

密钥实体(Key entity)— 密钥(secret key)又或者是私钥和配对公钥(采用非对称加密)
可信任的证书实体(trusted certificate entries)— 只包含公钥

keytool命令以及常见的option

Keytool 常见命令示例

创建公私钥对

keytool -genkeypair -alias “tomcat” -keyalg “RSA” -keystore “mykeystore.keystore” -dname “CN=localhost, OU=localhost, O=localhost, L=BJ, S=BJ, C=CN” -keypass “123456” -storepass -validity 180

参数说明:

-genkeypair 表示要创建一个新的密钥

-dname  表示密钥的Distinguished Names, 表明了密钥的发行者身份

  CN=commonName 注:生成证书时,CN要和服务器的域名相同,如果在本地测试,则使用localhost

  OU=organizationUnit

  O=organizationName

  L=localityName

  S=stateName

  C=country

-keyalg    使用加密的算法,这里是RSA

-alias     和keystore关联的别名,这个alias通常不区分大小写

-keypass   私有密钥的密码,这里设置为 123456

-keystore    密钥保存在D:盘目录下的mykeystore文件中

-storepass   存取密码,这里设置为changeit,这个密码提供系统从mykeystore文件中将信息取出

-validity    该密钥的有效期为 180天 (默认为90天)

下面是各选项的缺省值。

-alias “mykey”
-keyalg “DSA”
-keysize 1024
-validity 90
-keystore 用户宿主目录中名为 .keystore 的文件
-file 读时为标准输入,写时为标准输出

cacerts证书文件(The cacerts Certificates File)

该证书文件存在于java.home\jre\lib\security目录下,是Java系统的CA证书仓库

导出证书,由客户端安装

keytool -export -alias tomcat -keystore mykeystore -file d:\mycerts.cer -storepass 123456

导入证书到客户端的信任证书库中


keytool -import -trustcacerts -alias tomcat -keystore “%JAVA_HOME%/jre/lib/security/cacerts ” -file d:\mycerts.cer -storepass 123456

生成的证书可以交付客户端用户使用,用以进行SSL通讯,或者伴随电子签名的jar包进行发布者的身份认证。

常出现的异常:“未找到可信任的证书”–主要原因为在客户端未将服务器下发的证书导入到JVM中,可以用

keytool -list -alias tomcat -keystore “$JAVA_HOME/jre/lib/security/cacerts” -storepass 123456

来查看证书是否真的导入到JVM中。

其他的一些Keytool 命令示例如下所示:

要删除证书库里面的某个证书,可以使用如下命令:
keytool -delete -alias tomcat -keystore cacerts -storepass 666666

要导出证书库里面的某个证书,可以使用如下命令:
keytool -export -keystore cacerts -storepass 666666 -alias tomcat -file F:\server.cer
keytool -export -alias tomcat -keystore e:/server.jks -file e:/server.crt -rfc -storepass 123456

注意:keystore.jks 也可以为 .keystore格式 ; server.crt也可以为 .cer格式
“-rfc” 表示以base64输出文件,否则以二进制输出。

keytool -keypasswd -alias tomcat -keystore cacerts
这个不是交互式的,输入命令后直接更改
Keytool -keypasswd -alias tomcat -keypass 888888 -new 123456 -storepass 666666 -keystore cacerts

修改别名如下:
keytool -changealias -keystore mykeystore.keystore -alias 当前别名 -destalias 新别名

下面简单介绍Keystore类的主要方法,通过JAVA API 可以对Keystore 进行常见的操作。

KeyStore创建

KeyStore对象是通过使用KeyStore getInstance()静态工厂方法之一获得的。

将特定的密钥库加载到内存中

在可以使用KeyStore对象之前,必须通过load方法将实际的密钥库数据加载到内存中:

final void load(InputStream stream, char[] password)

可选的password参数用于检查密钥库数据的完整性。 如果没有提供密码,则不执行完整性检查。

要创建一个空的密钥库,可以将null作为InputStream参数传递给load方法。

通过将DomainLoadStoreParameter传递给备用加载方法来加载DKS密钥库:

final void load(KeyStore.LoadStoreParameter param)

获取密钥库别名列表

所有密钥库条目都通过唯一的别名来访问。 别名方法返回密钥库中别名的枚举:

final Enumeration aliases()

添加/设置/删除密钥库条目

setCertificateEntry方法将一个证书分配给指定的别名:

final void setCertificateEntry(String alias, Certificate cert)

如果别名不存在,则创建具有该别名的可信证书条目。 如果存在别名并标识可信证书条目,则与其关联的证书将由cert替换。

setKeyEntry方法添加(如果别名尚不存在)或设置键值条目:

final void setKeyEntry(String alias,
Key key,
char[] password,
Certificate[] chain)

final void setKeyEntry(String alias,
byte[] key,
Certificate[] chain)

在key作为字节数组的方法中,它是受保护格式的密钥的字节。 例如,在SUN提供程序提供的密钥库实现中,密钥字节数组需要包含一个受保护的私钥,该私钥被编码为PKCS8标准中定义的EncryptedPrivateKeyInfo。 在另一种方法中,密码是用于保护密钥的密码。

deleteEntry方法删除一个条目:

final void deleteEntry(String alias)

PKCS#12密钥库支持包含任意属性的条目。 使用java.security.PKCS12Attribute类来创建属性。 在创建新的密钥库条目时,使用接受属性的构造函数方法。 最后,使用以下方法将条目添加到密钥库:

final void setEntry(String alias, Entry entry,
ProtectionParameter protParam)

从密钥库获取信息

getKey方法返回与给定别名关联的密钥。 密钥使用给定的密码恢复:

final Key getKey(String alias, char[] password)

以下方法分别返回与给定别名关联的证书或证书链:

final Certificate getCertificate(String alias)
final Certificate[] getCertificateChain(String alias)

可以通过以下方式确定证书与给定证书匹配的第一个条目的名称(别名):

final String getCertificateAlias(Certificate cert)

PKCS#12密钥库支持包含任意属性的条目。 使用以下方法检索可能包含属性的条目:

final Entry getEntry(String alias, ProtectionParameter protParam)

然后使用KeyStore.Entry.getAttributes方法来提取这些属性,并使用KeyStore.Entry.Attribute接口的方法来检查它们。

保存KeyStore

内存中的密钥库可以通过存储方法保存:

final void store(OutputStream stream, char[] password)

CertificateFactory类

CertificateFactory类是定义证书工厂功能的引擎类,用于从其编码生成证书和证书吊销列表(CRL)对象。

X.509的证书工厂必须返回作为java.security.cert.X509Certificate实例的证书和作为java.security.cert.X509CRL实例的CRL。

创建CertificateFactory对象

CertificateFactory对象是通过使用getInstance()静态工厂方法之一获得的。

生成Certificate

要生成证书对象并使用从输入流读取的数据进行初始化,请使用generateCertificate方法:

final Certificate generateCertificate(InputStream inStream)

要返回从给定输入流中读取的证书(可能为空)的集合视图,请使用generateCertificates方法:

final Collection generateCertificates(InputStream inStream)

生成CRL

要生成证书吊销列表(CRL)对象并使用从输入流中读取的数据进行初始化,请使用generateCRL方法:

final CRL generateCRL(InputStream inStream)

要返回从给定输入流读取的CRL的(可能是空的)集合视图,请使用generateCRLs方法:

final Collection generateCRLs(InputStream inStream)

生成CertPath

PKIX的证书路径生成器和验证器由Internet X.509公钥基础结构证书和CRL配置文件RFC 3280定义。

用于从Collection和LDAP目录中检索证书和CRL的证书存储实现(使用PKIX LDAP V2架构)也可以从IETF以RFC 2587形式获得。

要生成CertPath对象并使用从输入流中读取的数据对其进行初始化,请使用以下一种generateCertPath方法(带或不带指定要用于数据的编码):

final CertPath generateCertPath(InputStream inStream)

final CertPath generateCertPath(InputStream inStream,
String encoding)

要生成CertPath对象并使用证书列表对其进行初始化,请使用以下方法:

final CertPath generateCertPath(List certificates)

要检索此证书工厂支持的CertPath编码列表,可以调用getCertPathEncodings方法:

final Iterator getCertPathEncodings()

默认编码将首先列出。



关注微信服务号,手机看文章
关注微信服务号,手机看文章