`

JavaTM 加密体系结构

    博客分类:
  • pki
阅读更多

简介
JDK 安全 API 是 Java 编程语言的核心 API,位于 java.security 包(及其子包)中。该 API 设计用于帮助开发人员在程序中同时使用低级和高级安全功能。

JDK 1.1 中第一次发布的 JDK 安全中引入了“Java 加密体系结构”(JCA),指的是用于访问和开发 Java 平台密码功能的构架。在 JDK 1.1 中,JCA 包括用于数字签名和报文摘要的 API。

正如本文档所述,JDK 1.2 大大扩展了 Java 加密体系结构。它还对证书管理基础结构进行了升级以支持 X.509 v3 证书,并为划分细致、可配置性强、功能灵活、可扩展的访问控制引入了新的 Java 安全体系结构。

Java 加密体系结构包含 JDK 1.2 安全 API 中与密码有关的部分,以及本文档中提供的一组约定和规范。为实现多重、可互操作的密码,它还提供了“提供者”体系结构。

Java 密码扩展 (JCE) 扩展了 JCA API,包括用于加密、密钥交换和信息认证码(MAC)的 API。JCE 和 JDK 密码共同提供了一个与平台无关的完整密码 API。JCE 作为 JDK 的扩展将独立发布,以符合美国的出口控制约束。

本文档是对 Java 开发工具包 (JDK) 1.2 版中发布的 Java 加密体系结构 API 及其缺省提供者的描述和说明。描述 JCE API 的文档将在 JCE 版本中提供。有关 JDK 安全 API 中 Java 安全体系结构方面的信息,参见“Java 安全体系结构规范”。

注:该 JCA 规范的最新版本可在公共网站 http://java.sun.com/products/jdk/1.2/docs/guide/security/CryptoSpec.html 上找到。

设计原理
Java 加密体系结构 (JCA) 是根据以下原理设计的:

实现的独立性和互操作性
算法的独立性和可扩展性
实现的独立性和算法独立性是互补的:其目的是让 API 用户能用密码学的概念(如数字签名和报文摘要),但又不必关心这些概念的实现甚至实现这些概念所用算法的实现。当不可能完全实现算法独立性时,JCA 将为开发人员提供标准的特定算法 API。当实现方法的独立性不可能实现时,JCA 将让开发人员指明所要求的特定实现方法。

算法独立性是通过定义密码“引擎”(服务)的类型以及定义提供这些密码引擎功能的类来实现的。这些类称为 engine(引擎)类,例如 MessageDigest 类、 Signature 类和 KeyFactory 类。

实现的独立性是通过使用基于“提供者”的体系结构而实现的。密码服务提供者(简称“提供者”)指的是用于实现一种或多种密码服务的一个包或一组包,如数字签名算法、报文摘要算法及密钥交换服务。程序可以只是简单地请求某类对象(如签名对象)实现某种服务(如 DSA 数字签名算法),并从任一安装好的提供者上获取实现方法。反之,必要时程序可从某个特定的提供者那请求实现方法。当有更快或更安全的版本可用时,提供者的升级对应用程序来说是透明的。

实现的互操作性指的是各种实现方法可在一起工作,使用彼此的密钥或校验彼此的签名。这意味着对于相同的算法,由一个提供者生成的密钥可被另一个提供者使用,而一个提供者生成的签名也可由另一个提供者来校验。

算法的可扩展性指的是可以很容易地添加那些能适应所支持的 engine 类的新算法。

体系结构
密码服务提供者
Java 加密体系结构引入了密码服务提供者 (简称为“提供者”)的概念。它是指一个(或一组)包,用于提供 JDK 安全 API 的密码子集的具体实现。

例如,在 JDK 1.1 中,提供者可包含一个或多个数字签名算法、报文摘要算法及密钥生成算法的实现。JDK 1.2 增加了五类附加服务:密钥工厂、密钥仓库的创建与管理;算法参数管理;算法参数的生成和证书工厂。它还允许提供者提供随机数生成 (RNG) 算法。在以前的版本中,RNG 不是由提供者提供的,而是某一特定的算法嵌入在 JDK 中的。

如前所述,程序可以只是简单地请求某类对象(如 Signature 对象)提供某种服务(如 DSA 签名算法),并从某一安装好的提供者上获取该对象的实现方法。程序也可请求某一特定的提供者(每个提供者都有自己的名称,供引用时使用)。

Sun 版本的 Java 运行时环境都带有一个名为“SUN”的缺省标准提供者。其它的 Java 运行时环境可能不一定提供“SUN”提供者。“SUN”提供者包包括:

一个数字签名算法 (DSA) 的实现,在 NIST FIPS 186 中描述。
一个 MD5 (RFC 1321) 和 SHA-1 (NIST FIPS 180-1) 报文摘要算法的实现。
一个 DSA 密钥对的生成器,用于生成与该 DSA 算法相匹配的公钥和私钥对。
一个 DSA 算法参数生成器。
一个 DSA 算法参数管理器。
一个 DSA “密钥工厂”,用于提供(不透明)的 DSA 私钥对象和公钥对象及其所含的密钥信息之间的双向转换。
一个符合 IEEE P1363 标准(见附录 G.7)的专用“SHA1PRNG”伪随机数生成算法的实现。
一个为 X.509 证书和证书撤消清单 (CRL) 服务的“证书工厂”。
一个用于名为“JKS”的专用密钥仓库类型的密钥仓库实现。
每个 JDK 安装都将安装一个或多个提供者包。新的提供者可以以动态或静态方式添加进来(参见 Provider 和 Security 类)。Java 加密体系结构提供了一组可供用户查询安装有哪些提供者及这些提供者支持哪些服务的 API。

客户可用不同的提供者配置他们的运行环境,并为每个提供者指定一个优先顺序。优先顺序是在未请求某一指定提供者时根据所请求的服务对提供者进行搜索的顺序。

密钥管理
可使用一个叫做“密钥仓库”的数据库来管理密钥和证书。

应用程序可使用密钥仓库来完成认证或签名。

应用程序可通过实现 java.security 包中的 KeyStore 类来访问密钥仓库。Sun Microsystems 提供了一个缺省 KeyStore 实现方法。它利用一个名为“JKS”的专用密钥仓库类型(格式),将密钥仓库实现为一个文件。

通过使用 KeyStore 类中提供的“getInstance”方法,应用程序可从不同的提供者中选择不同类型的密钥仓库实现方法。

有关详细信息,参见密钥管理一节。

概念
本节介绍 API 中引入的一些主要概念。

引擎类和算法
一个“引擎类”以一种抽象方式(无具体的实现方法)定义一种密码服务。

密码服务总是与某个特定的算法或类型相关联,它或者提供密码运算(如数字签名或报文摘要中的运算),生成或提供密码运算所需要的密码信息(密钥或参数),或者生成安全封装的密钥(这些密钥可用于密码运算中)的数据对象。例如,Signature 和 KeyFactory 类就是两个引擎类。Signature 类提供对数字签名算法功能的访问。DSA KeyFactory 以一种可供 DSA Signature 对象的 initSign 或 initVerify 方法使用的格式提供 DSA 私钥或公钥(从其编码或透明规范中)。

Java 加密体系结构包含了 JDK 1.2 安全包中与密码有关的类,包括引擎类。API 用户可通过请求和利用引擎类的实例来执行相应的运算。JDK 1.2 中定义了以下引擎类:

MessageDigest — 用于计算数据的报文摘要(散列)。
Signature — 用于对数据进行签名和校验数字签名。
KeyPairGenerator — 用于生成与指定算法相匹配的公钥和私钥对。
KeyFactory — 用于将类型为 Key(密钥)的不透明密钥转换为密钥规范(密钥信息的透明表示),反之亦然。
CertificateFactory 用于创建公钥证书和证书撤消清单(CRL)。
KeyStore — 用于创建和管理密钥仓库。密钥仓库是密钥的数据库。密钥仓库中的私钥有一个与之关联的证书链,用于认证对应的公钥。密钥仓库还含有来自可信实体的证书。
AlgorithmParameters — 用于管理某一特定算法的参数,包括编码和解码参数。
AlgorithmParameterGenerator — 用于生成一组与指定算法相匹配的参数。
SecureRandom — 用于生成随机数或伪随机数。
注意:“生成器”将创建新对象,而“工厂”将从现有信息(如某个编码方法)中创建对象。?

一个引擎类提供某类密码服务功能的接口(与特定的密码算法无关)。它定义“应用程序接口” (API) 方法,以使应用程序能够访问所提供的某类密码服务。实际的实现方法(由一个或多个提供者提供)即是那些指定算法的实现。例如,Signature 引擎类将提供对数字签名算法功能的访问。SignatureSpi 子类中(参见下一段落)所提供的实际实现方法将是某个指定签名算法(如带有 DSA 的 SHA1、 带有 RSA 的 SHA1 或带有 RSA 的 MD5)的实现。

引擎类所提供的 API 是用“服务提供者接口” (SPI) 来实现的。也就是说,对每一个引擎类,都有一个对应的抽象 SPI 类,它定义了密码服务提供者必须实现的服务提供者接口方法。

作为引擎类的实例,“API 对象”封装(作为 private 域)了对应的 SPI 类的实例,即“SPI 对象”。API 对象的所有 API 方法都被声明为“final”,且其实现方法调用了所封装的 SPI 对象的相应 SPI 方法。调用某个引擎类的 getInstance factory 方法将创建该引擎类(及其对应的 SPI 类)的实例。

SPI 类的名称与对应的引擎类名称相同,后跟“Spi”。例如,与 Signature 引擎类相对应的 SPI 类是 SignatureSpi 类。

每个 SPI 类都是抽象的。要实现某一指定算法的某一特定类型的服务,提供者必须对相应的 SPI 类进行子类化并提供所有抽象方法的实现。

另一个引擎类的例子是 MessageDigest 类,它提供对报文摘要算法的访问。它在 MessageDigestSpi 子类中的实现可以是诸如 SHA-1、MD5 或 MD2 各种报文摘要算法的实现。

最后一个例子:KeyFactory 引擎类支持将不透明密钥转换为透明密钥的规范,反之亦然(参见密钥规范接口和类一节)。KeyFactorySpi 子类中提供的实际实现将是指定类型的密钥(如 DSA 公钥和私钥)的实现。

实现和提供者
各种密码服务的实现由 JCA 密码服务提供者提供。提供者实际上是那些可提供一个或多个密码服务实现的包。例如,Java 开发工具包 (JDK) 的缺省提供者名为“SUN”,它可提供下述算法的实现:DSA 签名算法、MD5 和 SHA-1 报文摘要算法、DSA 密钥对生成算法和 SHA1PRNG 伪随机数生成算法。它还为 DSA 私钥和公钥提供密钥工厂,为 X.509 证书和 CRL 提供证书工厂,并提供 DSA 参数(包括其生成)的实现,同时也可为名为“JKS”的专用密钥仓库类型提供密钥仓库的实现。

其它提供者也可能已为这些服务或其它服务(如某个基于 RSA 的签名算法或 MD2 报文摘要算法)定义了自己的实现。

获得实现实例的 factory(工厂)方法
对于 API 中的每个引擎类,调用该引擎类中的 factory 方法就对某个特定的实现方法提出了请求并将之实例化。factory 方法是一种静态方法,它返回类的实例。

获取正确 Signature(签名)对象的基本机制如下所示:用户通过指定签名算法名(如“带 DSA 的 SHA1”),或再加上提供所需实现的提供者名称,然后调用 Signature 类中的 getInstance 方法,即可请求获得该对象。getInstance 方法将找到一种满足给定算法和提供者参数的实现方法。如果不指定提供者,getInstance 将按优先顺序搜索已注册的提供者,最后确定带指定算法的实现的提供者。有关注册提供者的详细信息,参见 Provider 类 。

核心类和接口
本节将讨论 Java 加密体系结构中提供的核心类和接口:

Provider 和 Security 类
MessageDigest、Signature、KeyPairGenerator、 KeyFactory、AlgorithmParameters、AlgorithmParameterGenerator、CertificateFactory、 KeyStore 和 SecureRandom 引擎类
密钥接口和类
算法参数规范接口和类及密钥规范接口和类
本节将演示每个类和接口中 main 方法的功能。相应的示例部分给出了这些类(MessageDigest、Signature、KeyPairGenerator、SecureRandom、KeyFactory 以及密钥规范类)的用法示例。有关 Security API 包的完整参考文档,可在以下网址中找到:

java.security 包概览
java.security.spec 包概览
java.security.interfaces 包概览
Provider 类
“密码服务提供者”(简称“提供者”)是指一个或一组包,该包可提供 JDK 安全 API 密码功能子集的具体实现。Provider 类是这个(或这组)包的接口。它含有访问提供者名称、版本号和其它信息的方法。

要实际提供密码服务的实现,某一实体(如某个开发小组)就必须编写实现代码和创建 Provider 类的子类。该子类的构造函数将对 JDK 安全 API 查询由提供者所实现的服务所需各种属性的值进行设置。也就是说,它指定了实现各种服务的类的名称。

提供者包可实现多种类型的服务 — 参见引擎类和算法。

不同的实现可能有不同的功能。有些可能是基于软件的,而另一些可能是基于硬件的。有些可能与平台无关,而另一些可能是针对指定平台的。有些提供者提供源代码以供复查和评估用,而另一些却不提供。

Java 加密体系结构 (JCA) 可让最终用户和开发人员都能决定各自所需。本节中,我们将说明最终用户如何安装满足自身需求的密码实现,同时也介绍开发人员如何请求满足自身需求的实现。

(注意: 有关实现Provider的信息,参见如何为 Java 加密体系结构实现Provider。)

如何请求和提供Provider的实现
对 API 中的每个引擎类,任一特定的实现都是通过下列方法来进行请求和实例化的:首先指定所要的算法名称,有时再加上指定所需实现所属的提供者名称,然后调用该引擎类中的 getInstance 方法。

如果不指定提供者,getInstance 将搜索已注册的提供者,确定与指定算法相关联的所需密码服务的实现。在每个给定的 Java 虚拟机 (JVM) 中,将按某一给定的优先顺序来安装提供者。该顺序是在请求中未指定提供者时搜索提供者所用的顺序。例如,假设 JVM 中安装有两个提供者,一个名为“PROVIDER_1”,另一个名为“PROVIDER_2”。 进一步假设:

PROVIDER_1 实现 SHA1withDSA、SHA、MD5、DES 和 DES3
PROVIDER_2 实现 SHA1withDSA、MD5withRSA、MD2withRSA、MD2、MD5、RC4、RC5、DES 和 RSA
如果 PROVIDER_1 的优先顺序是 1 (最高优先顺序),而 PROVIDER_2 的优先顺序是 2,则将导致以下行为:

假设正在查询 MD5 的实现。尽管这两个提供者都提供上述实现,但返回的是 PROVIDER_1 上的实现,这是因为 PROVIDER_1 具有最高优先权,因而将最先被搜索到。
如果是在查询 MD5withRSA 签名算法,就会首先搜索 PROVIDER_1 以查询该方法。由于在 PROVIDER_1 上找不到该实现,因此接着对 PROVIDER_2 进行搜索。找到该实现后即将将其返回。
假设是在查询 SHA1withRSA 签名算法。由于所安装的提供者都不提供该实现,因此抛出 NoSuchAlgorithmException 。
带提供者变量的 getInstance 方法是为那些需要指定一个算法应由哪个提供者来提供的开发人员而准备的。例如,联邦代理机构要用已被联邦认证的提供者的实现。不妨假设由 PROVIDER_1 提供的的 SHA1withDSA 实现还没有接受这样的证书,而由 PROVIDER_2 提供的 DSA 实现已接受该证书。

于是,Federal 程序将指定 PROVIDER_2 来进行下列调用,因为它含有已获证书的实现:

        Signature dsa = Signature.getInstance("SHA1withDSA", "PROVIDER_2");这种情况下,如果没有安装“PROVIDER_2”,则将抛出 NoSuchProviderException,即使有另一个已安装了的提供者可实现所请求的算法。

程序也可选择获取一个包括所有安装了的提供者的清单(使用 Security 类中的getProviders 方法)并从该清单中选取某个提供者)。

安装提供者
安装提供者包括两部分:安装提供者包中的类及对提供者进行配置。?

安装 Provider 类
有几个方法可用于安装 provider 类:

将包含这些类的 zip 或 JAR 文件放在 CLASSPATH 中的任何位置
将提供者的 JAR 文件作为“已安装”或 “已捆绑的”扩展来提供。有关如何部署某个扩展的详细信息,参见如何发布扩展?。
配置提供者
下一步是将提供者添加到认可的提供者的清单中。这是通过编辑 JKD lib/security 目录中的 java.security 文件来静态完成的。因此,如果 JDK 安装在 jdk1.2 目录中,则该文件将是 jdk1.2/lib/security/java.security。可在java.security 中进行设置的一类属性具有以下形式:

    security.provider。n=masterClassName该语句声明了一个提供者,并指定其优先顺序 n。优先顺序是在没有指定提供者时查询所请求的算法时搜索各提供者所用的顺序。顺序以 1 为基础,即 1 是最高的优先级,紧接着是 2 等等。

masterClassName 必须指定提供者的“main”类。提供者的文档将指定其主类。这个主类永远是 Provider 类的一个子类。子类的构造函数设置了 JDK 密码 API 查询提供者所实现的算法或其它功能所需的各种属性的值。

假设该主类是 COM.acme.provider.Acme,而且您想将 Acme 配置为具有第三优先级的提供者。为此,请将下列行添加到 java.security 文件中:

    security.provider.3=COM.acme.provider.Acme用户也可动态地注册提供者。要动态地注册提供者,请调用 Security 类中的 addProvider 或 insertProviderAt 方法。这种类型的注册并不是持久的,且只能由“可信任”的程序来进行。参见安全。

Provider 类的方法
每个 Provider 类的实例都有一个名称(目前区分大小写)、版本号和该提供者及其服务的描述字符串。通过调用下述方法查询 Provider 实例,即可获得这些信息:

    public String getName()
    public double getVersion()
    public String getInfo()Security 类
Security 类管理所安装的提供者和系统安全范围内的属性。它只含静态方法,并且无法实例化。

注意:用于添加或去除提供者及用于设置 Security 属性的方法只能由可信任的程序来执行。 目前,“可信任的程序”是指

没在安全管理器下运行的本地应用程序,或者
拥有执行指定方法权限的 applet 或应用程序(如下所示)。
为使代码可信任并可执行某项动作(如添加提供者),需要授予该 applet 对该特定动作的权限。

例如,在缺省 Policy(策略)实现中,JDK 安装的策略配置文件指定了给定代码源中代码的权限(即可访问哪些类型的系统资源)。 (有关详细信息,参见后面的内容和 “缺省 Policy 实现和策略文件语法” 及 “Java 安全体系结构规范” 文件)。

正在执行的代码总是来自某个特定的“代码源”。代码源不仅包括 applet 的源位置(URL),而且包括与签写代码的私钥相对应的公钥的引用。代码源中的公钥由用户密钥仓库中的(符号)别名引用。

在策略配置文件中,代码源可表示为两个组件: 一个是代码源 (URL),另一个是别名(前面由“signedBy”引导)。其中,别名用于标识含有校验代码签名所用公钥的 keystore 入口。

上述文件中的每个“grant”语句将一组权限授予指定的代码源,指明哪些动作是允许使用的。

以下所示的是一个样本策略配置文件。

  grant signedBy "sysadmin", codeBase "file:/home/sysadmin/" {
    permission java.security.SecurityPermission "Security.insertProvider.*";
    permission java.security.SecurityPermission "Security.removeProvider.*";
    permission java.security.SecurityPermission "Security.setProperty.*";
  };该样本文件指定:只有从本地文件系统上“/home/sysadmin/”目录(及其以下目录)下某个已签名 JAR 文件(其签名可用用户密钥仓库中的“sysadmin”别名所引用的公钥来校验)加载来的代码,才能调用 Security 类中的方法以添加或去除提供者或设置 Security 属性。

代码源的任一组件(或两个组件)都可以没有。下面就是一个没有 codeBase 组件的示例:

  grant signedBy "sysadmin" {
    permission java.security.SecurityPermission "Security.insertProvider.*";
    permission java.security.SecurityPermission "Security.removeProvider.*";
};如果上述策略生效,则来自“sysadmin”签名 JAR 文件中的代码就可以添加/删除提供者 — 不管这个 JAR 文件来源于何处。

以下是一个没有签名人的示例:

  grant codeBase "file:/home/sysadmin/" {
    permission java.security.SecurityPermission "Security.insertProvider.*";
    permission java.security.SecurityPermission "Security.removeProvider.*";
};该例中,本地文件系统上“/home/sysadmin/”目录(及其以下目录)下的代码都可以添加/删除提供者。代码无需签名。

以下是一个既无 codeBase 又无 signedBy 的示例:

  grant {
    permission java.security.SecurityPermission "Security.insertProvider.*";
    permission java.security.SecurityPermission "Security.removeProvider.*";
};此处,由于代码源的两个组件都没有,因此任何代码(无论它来自何处或是否已签名,也不管是谁签名)都可以添加/删除提供者。

管理 Provider
Security 类可用于查询所安装的提供者,也可用于运行时安装新提供者。

查询 Provider
        public Provider[] getProviders()该方法将返回一个数组,其中包含了所有已安装的提供者(从技术上来说,是每个包提供者的 Prodiver 子类)。数组中各 Provider 的顺序就是它们的优先顺序。

        public Provider getProvider(String providerName)此方法将返回名为 providerName 的 Provider。 如果找不到该 Provider,它将返回 null。

添加 Provider
    public static int addProvider(Provider provider) {此方法将向已安装的提供者清单中添加提供者。它将返回该提供者所添加处的优先位置;如果由于已安装该提供者的缘故而没有添加该提供者,则返回 -1。

        public int insertProviderAt(Provider provider, int position)此方法将在某个指定位置添加新提供者。该位置就是在未指定要用哪个提供者的情况下,查询所请求的算法时搜索各提供者所用的优先顺序。位置以 1 为基础, 1 的优先级最高,接着是 2 等等。如果已将给定的提供者安装在所要求的位置上,则原先位于该位置的提供者及所有位置大于该位置的提供者都要上移一个位置(向已安装的提供者的清单末端方向移动)。

注意,我们不能担保一定能将该提供者添加到所要求的位置上。例如,有时添加提供者是合法的,但只能加到最后的位置。这种情况下 position(位置)参数将被忽略。同样,如果该提供者已被安装,也就无法再添加它了。

该方法将返回该提供者所添加处的实际优先位置;如果由于已安装该提供者的缘故而没有添加该提供者,则返回 -1。

注意:如果要改变某个提供者的优先级位置,必须先将它删除,然后再将它插入新的优先级位置。

删除提供者
        public void removeProvider(String name)此方法将删除指定名称的提供者。如果该提供者并未安装,它将无声返回。当指定的提供者被删除后,位置大于被删除的提供者所在位置的所有提供者都要下移一个位置(向已安装的提供者清单起始方向移动)。

Security 属性
Security 类含有一系列全系统安全属性。可信任的程序可通过以下方法来访问这些属性并可对其进行设置。

        public static String getProperty(String key)
        public static void setProperty(String key, String datum)MessageDigest 类
MessageDigest 类是一个引擎类,它是为了提供诸如 SHA1 或 MD5 等密码上安全的报文摘要功能而设计的。密码上安全的报文摘要可接受任意大小的输入(一个字节数组),并产生固定大小的输出,该输出称为一个摘要或散列。摘要具有以下属性:

无法通过计算找到两个散列成相同值的报文。
摘要不反映任何与输入有关的内容。
使用报文摘要可以生成数据唯一且可靠的标识符。有时它们被称为数据的“数字指纹”。

创建 MessageDigest 对象
计算摘要的第一步是创建报文摘要实例。象所有的引擎类一样,获取某类报文摘要算法的 MessageDigest 对象的途径是调用 MessageDigest 类中的 getInstance 静态 factory 方法:

    public static MessageDigest getInstance(String algorithm)注意:算法名不区分大小写。例如,以下所有调用都是相等的:

    MessageDigest.getInstance("SHA")
    MessageDigest.getInstance("sha")
    MessageDigest.getInstance("sHa")调用程序可选择指定提供者名称,以保证所要求的算法是由已命名提供者实现的:

    public static MessageDigest getInstance(String algorithm, String provider)调用 getInstance 将返回已初始化过的报文摘要对象。因此,它不需要进一步的初始化。

更新报文摘要对象
计算数据的摘要的第二步是向已初始化的报文摘要对象提供数据。这将通过一次或多次调用以下某个 update(更新)方法来完成:

    public void update(byte input)
    public void update(byte[] input)
    public void update(byte[] input, int offset, int len)计算摘要
通过调用 update 方法提供数据后,程序就调用以下某个 digest(摘要)方法来计算摘要:

    public byte[] digest()
    public byte[] digest(byte[] input)
    public int digest(byte[] buf, int offset, int len)前两个方法返回计算出的摘要。后一个方法把计算出的摘要储存在所提供的 buf 缓冲区中,起点是 offset。len 是 buf 中分配给该摘要的字节数。该方法返回实际存储在 buf 中的字节数。

对接受输入字节数组变量的 digest 方法的调用等价于用指定的输入调用:

    public void update(byte[] input),接着调用不带参数的 digest 方法。

有关详细信息,参见示例部分。

Signature 类
Signature 类是个引擎类 ,它是为了提供诸如 DSA 或 RSA with MD5 这样的数字签名算法功能而设计的。密码学上安全的签名算法可接受任意大小的输入和一个私钥,并产生一个比较短(常常是固定大小的)的名为 signature 的字节串,它具有以下属性:

给定与签名的私钥相对应的公钥,就应能校验输入的真实性和完整性。
签名和公钥不反映有关私钥的任何内容。
Signature 对象可用于数据签名。它还可用于校验某个签名是否为与之关联的数据的真实签名。 有关对数据签名和校验的样例,参见示例部分。

Signature 对象状态
Signature 对象是个模型对象。这意味着 Signature 对象总是处在某个给定的状态(在这种状态下,它只能进行一类操作)下。状态以各自的类(如 Signature)中定义的 final 整数常数来表示。

Signature 对象可能有三种状态:

UNINITIALIZED
SIGN
VERIFY
Signature 对象首次生成时将处于 UNINITIALIZED(未初始化)态。Signature 类定义了两个初始化方法:initSign 和 initVerify 方法,它们将分别把状态改为 SIGN 和 VERIFY。

创建 Signature 对象
签名或校验签名的第一步是创建 Signature 实例。正如所有的引擎类一样,为特定类型的签名算法获取 Signature 对象的途径是调用 Signature 类中的 getInstance 静态 factory 方法:

    public static Signature getInstance(String algorithm)注意:算法名称不区分大小写。

调用程序可选择指定提供者名称,以保证所要求的算法是由已命名提供者实现的:?

    public static Signature getInstance(String algorithm,
                                        String provider)初始化 Signature 对象
使用 Signature 对象前必须先将它初始化。所用的初始化方法取决于该对象是先用于签名还是先用于校验。

如果是用于签名,必须用签名的拥有者实体的私钥来初始化该对象。这种初始化是通过调用以下方法来完成的:

    public final void initSign(PrivateKey privateKey)该方法将 Signature 对象置于 SIGN(签名)状态。

反之,如果 Signature 对象是用于校验,则必须先用签名的拥有者实体的公钥来初始化该对象。这种初始化是通过调用以下方法来完成的:

    public final void initVerify(PublicKey publicKey)该方法将 Signature 对象置于 VERIFY(校验)状态。

签名
如果 Signature 对象已初始化为用于签名(即如果它处于 SIGN 状态),则可将待签数据提供给该对象。这可通过一次或多次调用以下某个 update 方法来完成:

    public final void update(byte b)
    public final void update(byte[] data)
    public final void update(byte[] data, int off, int len)应该不断地调用 update 方法直到将所有待签的数据都提供给该 Signature 对象。

要产生签名,只需调用以下某个 sign(签名)方法:

    public final byte[] sign()
    public final int sign(byte[] outbuf, int offset, int len)第一个方法返回一个字节数组,内放签名结果。第二个方法将签名结果储存在所提供的 outbuf 缓冲区中,起点是 offset。len 是 outbuf 中分派给签名的字节数。该方法返回实际存储的字节数。

签名被编码为两个整数 r 和 s 的标准 ASN.1 序列。有关如何在 Java 加密体系结构中使用 ASN.1 编码的详细信息,参见附录 B 。

调用 sign 方法将把该 signature 对象重置为当初通过调用 initSign 方法对其进行初始化以用于签名时所处的状态。也就是说,该对象将被重置并可通过重新调用 update 和 sign(使用同一私钥)来产生另一个签名。

也可以指定另一个私钥重新调用 initSign 或调用 initVerify (将该 Signature 对象初始化为用于校验的对象)

校验
如果 Signature 对象被初始化为校验用(即如果它是处于 VERIFY 状态),则它可校验某个签名是否为与之关联的数据的真实签名。要开始该过程,请将待校验的数据(与签名相对)提供给该对象。这可通过一次或多次调用以下某个 update 方法来完成:

    public final void update(byte b)
    public final void update(byte[] data)
    public final void update(byte[] data, int off, int len)应该不断调用 update 方法,直到将所有数据都提供给该 Signature 对象为止。

之后,可通过调用下面的 verify(校验)方法来校验签名:

    public final boolean verify(byte[] encodedSignature)其中的参数必须是字节数组,该数组包含被编码为两个整数 r 和 s 的标准 ANSI .1 序列的签名。这是一种常用的标准编码。它与由 sign 方法产生的一样。

verify 方法返回一个布尔量,指明被编码的签名是否为提供给 update 方法的数据的真实签名。

调用 verify 方法将把该 signature 对象重置为当初通过调用 initVerify 方法对其进行初始化以用来校验时所处的状态 也就是说,该对象将被重置并可通过调用initVerify 时其公钥被指定的身份来校验另一个签名。

也可以重新调用 initVerify(将该 Signature 对象初始化为检验不同实体的签名)以指定不同的公钥,或者调用 initSign (将该 Signature 对象初始化为用于生成签名)。

算法参数类
算法参数规范接口和类
算法参数规范是对算法中所用参数组的“透明”表示。

一组参数的透明表示意思是可以通过相应规范类中定义的某个“get"(获取)方法来分别访问组中的每个参数值(例如,DSAParameterSpec 定义了 getP、getQ 和 getG 方法,分别用于访问 p、q 和 g)。

这与不透明表示形成对照;正如 AlgorithmParameters 类给出的那样,用户将无法直接访问各参数域,而只能得到与该参数集相关联的算法名(通过 getAlgorithm 方法)和该参数集的某类编码(通过 getEncoded 方法)。

在 java.security.spec 包中出现的算法参数规范接口和类将在下面进行说明。

AlgorithmParameterSpec 接口
AlgorithmParameterSpec 是密码参数透明规范的一个接口。

该接口不含任何方法或常数。它的唯一用途在于对所有的参数规范进行分组(以及为它们提供类型安全性)。所有的参数规范都必须执行这一接口。

DSAParameterSpec 类
该类(它实现 AlgorithmParameterSpec 接口)指定 DSA 算法中使用的参数组。它含有以下方法:

    public BigInteger getP()

    public BigInteger getQ()

    public BigInteger getG()这些方法将返回以下的 DSA 算法参数:质数 p、亚质数 q 和基数 g。

AlgorithmParameters 类
AlgorithmParameters 类是个引擎类,它提供密码参数的不透明表示。

不透明表示的意思是:在这种表示中,不可以直接访问各参数域,只能得到与参数集相关联的算法名及该参数集的某类编码。这与参数的透明表示形成对照,在透明表示中,用户可以通过相应规范类中定义的某个“get”方法来分别访问每个值。注意:用户可以通过调用 AlgorithmParameters 的 getParameterSpec 方法,将 AlgorithmParameters 对象转换成透明规范(参见下面的内容)。

创建 AlgorithmParameters 对象
正如所有的引擎类一样,为某一类型的算法获取 AlgorithmParameters 对象的途径是调用 AlgorithmParameters 类中的 getInstance 静态 factory 方法:

    public static AlgorithmParameters getInstance(String algorithm)注意:算法名称不区分大小写。

调用程序可选择指定提供者名称,以保证所要求的算法参数是由已命名提供者实现的:

    public static AlgorithmParameters getInstance(String algorithm, String provider)初始化 AlgorithmParameters 对象
对某个 AlgorithmParameters 对象进行实例化后,必须用适当的参数规范或参数编码来调用 init,以便对该对象进行初始化:

    public void init(AlgorithmParameterSpec paramSpec)

    public void init(byte[] params)

    public void init(byte[] params, String format)上面这些语句中,params(参数)是个数组,它包含了被编码的参数,format(格式)是编码格式名。在上述带 params 变量但不带 format 变量的 init 方法中,将使用参数的主要解码格式。如果有参数的 ASN.1 规范,主要解码格式就是 ASN.1。

注意:AlgorithmParameters 对象只能被初始化一次。也就是说,它们无法重用。

获取被编码的参数
AlgorithmParameters 对象中出现的参数的某个字节编码可通过调用 getEncoded 来获得:

    public byte[] getEncoded()该调用将以主要编码格式返回这些参数。如果存在这类参数的 ANS.1 规范,则主要编码格式就是 ASN.1。

如果需要以指定的编码格式来返回这些参数,请使用

    public byte[] getEncoded(String format)如果 format 是空的,则使用参数的主要编码格式,就象其它的 getEncoded 方法中那样。

请注意:在 AlgorithmParameters 的缺省实现(由“SUN”提供者提供)中,目前将忽略 format 变量。

将 AlgorithmParameters 对象转换为透明规范
算法参数的透明参数规范可以通过调用 getParameterSpec 从 AlgorithmParameters 对象中得到:

    public AlgorithmParameterSpec getParameterSpec(Class paramSpec)paramSpec

指示这些参数将在哪个规范类中返回。例如,它可以是 DSAParameterSpec.class,表明这些参数应该是从 DSAParameterSpec 类(该类在 java.security.spec 包中)的某个实例中返回的。
AlgorithmParameterGenerator 类
AlgorithmParameterGenerator 类是个引擎类,它用于产生一组与给定算法(当创建某个 AlgorithmParameterGenerator 实例时,也就指定了算法)相匹配的参数。

创建 AlgorithmParameterGenerator 对象
正如所有的引擎类一样,为某一类型的算法获取 AlgorithmParameterGenerator 对象的途径是调用 AlgorithmParameterGenerator 类中的 getInstance 静态 factory 方法:

    public static AlgorithmParameterGenerator getInstance(
                        String algorithm)注意:算法名称不区分大小写。

调用程序可选择指定提供者的名称,以保证该算法的参数生成器是由已命名提供者实现的:

    public static AlgorithmParameterGenerator getInstance(
                       String algorithm,
                       String provider)初始化 AlgorithmParameterGenerator 对象
可用两种不同的方式来初始化 AlgorithmParameterGenerator 对象:与算法无关的方式及针对某个算法的方式。

与算法无关的方式利用这样一个事实:所有的参数生成器均共用“大小”这个概念和随机源。大小量度是由所有的算法参数普遍共用的,虽然不同的算法对它的解释并不一样。例如,在 DSA 算法参数中,“大小”对应于质数模数的大小,单位是比特(有关特定算法的大小的信息,参见附录 B:算法)。使用这种方法时,针对算法的参数的产生值(如果有)将缺省为一些标准值。init 方法接受这两类普遍共用的变量:

    public void init(int size, SecureRandom random);还有一个方法只接受 size(大小)变量;它使用由系统提供的随机源:

    public void init(int size)另一个处理方式是使用针对算法的语句来初始化参数生成器,这些语句表示为一组由 AlgorithmParameterSpec 对象给出的针对算法的参数生成值:

    public void init(AlgorithmParameterSpec genParamSpec,
                           SecureRandom random)

    public void init(AlgorithmParameterSpec genParamSpec)例如,要生成 Diffie-Hellman 系统参数,参数生成值通常由质数模数的大小和随机指数的大小组成,两者都以比特数给出。Diffie-Hellman 算法将作为 JCE 1.2 的组件发布。

生成算法参数
一旦创建并初始化某个 AlgorithmParameterGenerator 对象后,就可以用 generateParameters 方法来生成算法参数:

    public AlgorithmParameters generateParameters()密钥接口
密钥接口是所有不透明密钥的最高级接口。它定义了所有不透明密钥对象所共享的功能。

不透明密钥表示的意思是:在这种表示中,用户无法直接访问组成密钥的密钥信息。另言之: “不透明”限制了对密钥的访问 — 只能用“Key”接口中定义的三种方法(见下面)来访问:getAlgorithm、getFormat 和 getEncoded。 这与透明表示形成对照。在透明表示中,用户可以通过相应规范类中定义的某个“get”方法来分别访问每个密钥资料值。

所有不透明密钥都有三个属性:

算法
这是该密钥的密钥算法。该密钥算法通常是一种加密算法或不对称加密算法(例如 DSA 或 RSA),它将与上述算法及有关的算法(如 MD5 with RSA、SHA1 with RSA 等)协同工作。密钥算法的名称可由下面方法来获得:

    public String getAlgorithm()编码方式
这是需要在 Java 虚拟机外提供密钥的标准表示时,所使用的一种密钥外部编码方式。它按某种标准格式(如 X.509 或 PKCS#8)对密钥进行编码,并用以下方法返回:

    public byte[] getEncoded()格式
这是经过编码处理后的密钥的格式名。它由以下方法返回:

    public String getFormat()密钥一般通过密钥生成器、证书和密钥规范(用 KeyFactory 方法)获得,或通过 KeyStore 的实现访问管理密钥的“密钥仓库”数据库来获得。

可以用与算法有关的方式,用 KeyFactory 解析经过编码处理的密钥。

也可以用 CertificateFactory 来解析证书。

PublicKey 和 PrivateKey 接口
PublicKey 和 PrivateKey 接口(两者都是对 Key 接口的扩展)都是不含方法的接口,用在类型安全和类型识别中。

密钥规范接口和类
密钥规范是组成密钥的密钥信息的透明表示。如果密钥存储在某个硬件设备上,它的规范中就可能含有可帮助识别该设备上的密钥的信息。

密钥的透明表示意味着可以通过相应规范类中定义的某个“get”方法来分别访问每个密钥信息的值。例如, DSAPrivateKeySpec 定义了 getX、 getP、getQ 和 getG 方法,用以访问私钥 x 和计算密钥时所用的 DSA 算法参数:质数 p、亚质数 q 和基数 g。

这与由 Key 接口定义的不透明表示形成对照。在不透明表示中,用户无法直接访问各个密钥资料域。换言之,“不透明”表示限制了对密钥的访问 — 只能用 Key 接口中定义的下列三种方法来访问密钥:getAlgorithm、getFormat、和 getEncoded。

密钥可用针对算法的方式或用与算法无关的编码格式(例如 ASN.1)来指定。例如,DSA 私钥可用它的组件 x、 p, q 和 g (参见 DSAPrivateKeySpec)来指定,也可用它的 DER 编码(参见 PKCS8EncodedKeySpec)来指定。

密钥规范接口和类位于 java.security.spec 包中。下面是对它们的描述。

KeySpec 接口
这一接口不含任何方法和常数。它的唯一用途就是对所有的密钥规范进行分组(并为它们提供类型安全性)。所有密钥规范都必须实现这一接口。

DSAPrivateKeySpec 类
该类(它实现 KeySpec 接口) 用其相关的参数来指定 DSA 私钥。它含有以下方法:

    public BigInteger getX()

    public BigInteger getP()

    public BigInteger getQ()

    public BigInteger getG()这些方法将返回私钥 x 和用于计算密钥的 DSA 算法参数:质数 p、亚质数 q 和基数 g。

DSAPublicKeySpec 类
该类(它实现 KeySpec 接口) 用其相关的参数来指定 DSA 公钥。它含有以下方法:

    public BigInteger getY()

    public BigInteger getP()

    public BigInteger getQ()

    public BigInteger getG()这些方法将返回公钥 y 和用于计算密钥的 DSA 算法参数:质数 p、亚质数 q 和基数 g。

RSAPrivateKeySpec 类
该类(它实现 KeySpec 接口)指定 RSA 私钥。它含有以下方法:

    public BigInteger getModulus()

    public BigInteger getPrivateExponent()这些方法将返回 RSA 模数 n 和组成 RSA 私钥的秘密指数 d 的值。

RSAPrivateCrtKeySpec 类
该类(它扩展了 RSAPrivateKeySpec 类)利用中国余数定理 (CRT) 信息值来指定 PKCS#1 中定义的 RSA 私钥。它含有以下方法(加上从它的父类 RSAPrivateKeySpec 继承来的方法):

    public BigInteger getPublicExponent()

    public BigInteger getPrimeP()

    public BigInteger getPrimeQ()

    public BigInteger getPrimeExponentP()

    public BigInteger getPrimeExponentQ()

    public BigInteger getCrtCoefficient()这些方法将返回公有指数 e 和 CRT 信息整数即:模数 n 的质数因子 p 和 q、指数 d 模 (p-1) 的值、指数 d 模 (q-1) 的值以及“中国余数定理”系数 q 的倒数模 p 的值。

RSA 私钥逻辑上只由模数和秘密指数组成。CRT 值的存在只是为了提高运算效率。

RSAPublicKeySpec 类
该类(它实现 KeySpec 接口)指定 RSA 公钥。它含有以下方法:

    public BigInteger getModulus()

    public BigInteger getPublicExponent()这些方法将返回 RSA 模数 n 和组成 RSA 公钥的公有指数 e 的值。

EncodedKeySpec 类
这是个抽象类(它实现 KeySpec 接口),以编码格式来表示公钥或私钥。它的 getEncoded 方法返回编码后的密钥:

    public abstract byte[] getEncoded();而它的 getFormat 方法返回编码格式的名称:

    public abstract String getFormat();有关 PKCS8EncodedKeySpec 和 X509EncodedKeySpec 的具体实现,参见下面的内容。

PKCS8EncodedKeySpec 类
该类是 EncodedKeySpec 的子类,它以 PKCS #8 标准中指定的格式表示私钥的 DER 编码。

它的 getEncoded 方法返回按 PKCS #8 标准编码后的密钥字节。它的 getFormat 方法返回字符串“PKCS#8"。

X509EncodedKeySpec 类
该类是 EncodedKeySpec 的子类,它以 X.509 标准中指定的格式表示公钥或私钥的 DER 编码。

它的 getEncoded 方法返回按 X.509 标准编码后的密钥字节。它的 getFormat 方法返回字符串“ X.509"。

KeyFactory 类
KeyFactory 类是个引擎类,它可用于提供不透明(Key 类型)密钥和密钥规范(其所含的密钥信息的透明表示)之间的转换。

密钥工厂是双向的,即它们允许从给定的密钥规范(密钥信息)来建立不透明的密钥对象,或以适当的格式取出密钥对象所含的密钥信息。

对同一密钥可存在多个互相兼容的密钥规范。例如, DSA 公钥可用它的组件 y、p、q 和 g(参见 DSAPublicKeySpec)来指定,也可根据 X.509 标准(参见 X509EncodedKeySpec)用 DER 编码来指定。

密钥工厂可用于相互兼容的密钥规范之间的转换。密钥的解析可通过相互兼容的密钥规范之间的转换而得到。例如,当从 X509EncodedKeySpec 转换为 DSAPublicKeySpec 时,基本上就将经过编码处理的密钥解析为它的组件。有关示例,参见使用密钥规范和 KeyFactory 生成和校验签名一节。

创建 KeyFactory 对象
正如所有的引擎类一样,为特定类型的密钥算法获取 KeyFactory 对象的途径是调用 KeyFactory 类中的 getInstance 静态 factory 方法:

    public static KeyFactory getInstance(String algorithm)注意:算法名称不区分大小写。

调用程序可选择指定提供者名称,以保证所要求的密钥工厂是由已命名提供者实现的:

    public static KeyFactory getInstance(String algorithm, String provider)密钥说明和密钥对象之间的转换
如果有公钥的密钥规范,即可从密钥规范用 generatePublic 方法中得到不透明的 PublicKey 对象:

    public PublicKey generatePublic(KeySpec keySpec)同样,如果有私钥的密钥规范,即可从密钥规范用 generatePrivate 方法得到不透明的 PrivateKey 对象:

    public PrivateKey generatePrivate(KeySpec keySpec)Key 对象和密钥规范之间的转换
如果有 Key 对象,即可通过调用 getKeySpec 方法得到相应的密钥规范对象:

    public KeySpec getKeySpec(Key key, Class keySpec)keySpec

有关详细信息,参见示例部分。

指定这些参数将在哪个规范类中返回。例如,它可以是 DSAPublicKeySpec.class,指示这些参数应该是在 DSAPublicKeySpec 类的某个实例中返回。
CertificateFactory 类
CertificateFactory 类是个引擎类,它定义了证书工厂的功能,后者用于从编码产生证书对象和证书撤消清单 (CRL) 对象。

X.509 证书工厂必须返回属于 java.security.cert.X509Certificate 的实例的证书,以及返回属于 java.security.cert.X509CRL 实例的 CRL。

创建 CertificateFactory 对象
正如所有的引擎类一样,为特定类型的证书或 CRL 类型获取 CertificateFactory 对象的途径是调用 CertificateFactory 类中的 getInstance 静态 factory 方法:

    public static CertificateFactory getInstance(String type)注意:类型名称不区分大小写。

调用程序可选择指定提供者名称,以保证所要求的证书工厂是由已命名的提供者实现的:

    public static CertificateFactory getInstance(String type, String provider)生成 Certificate 对象
要产生证书对象并用从输入流读入的数据来对其进行初始化,可用下面的 generateCertificate 方法:

    public final Certificate generateCertificate(InputStream inStream)要返回从给定输入流中读入的所有证书的集合(可能为空),可用下面的 generateCertificates 方法:

    public final Collection generateCertificates(InputStream inStream)生成 CRL 对象
要产生证书撤消清单对象 (CRL) 并用从输入流读入的数据来对其进行初始化,可用generateCRL 方法:

    public final CRL generateCRL(InputStream inStream)要返回从给定输入流读入的所有 CRL 的集合(可能为空),可用下面的 generateCRLs 方法:

    public final Collection generateCRLs(InputStream inStream)KeyPair 类
KeyPair 类是密钥对(公钥和私钥)的简单容器。它含有两个公用方法:一个用来返回公钥,另一个用来返回私钥:

    public PrivateKey getPrivate()
    public PublicKey getPublic()KeyPairGenerator 类
KeyPairGenerator 类是个引擎类,用于产生公钥和私钥对。

有两种产生密钥对的方法:与算法无关的方法和针对算法的方法。两者之间的唯一差别只是对象的初始化方式。有关调用以下方法的示例,参见示例部分。

创建 KeyPairGenerator
所有密钥对的生成都从 KeyPairGenerator 开始。这是用 KeyPairGenerator 的某个 factory 方法来完成的。

    public static KeyPairGenerator getInstance(String algorithm)
    public static KeyPairGenerator getInstance(String algorithm,
        String provider)注意: 算法名称不区分大小写。

初始化 KeyPairGenerator
一个特定算法的密钥对生成器创建一个将与该算法一起使用的公钥/私钥对。它还将算法的参数与每个生成的密钥关联起来。

必须先对密钥对生成器进行初始化才能产生密钥对。大多数情况下,用与算法无关的初始化方法就足够了。但在某些情况下,还要用针对算法的初始化方法。

与算法无关的初始化方法
所有的生成器都共用两个概念:密钥大小和随机源。不同算法中对密钥大小的解释是不同的。例如,在 DSA 算法中,密钥大小对应于模数的长度(有关特定算法的密钥大小的信息,参见附录 B:算法)。

initialize 方法可接受这两类被普遍共用的变量:

    public void initialize(int keysize, SecureRandom random)还有一个方法只接受 keysize 变量;它使用由系统提供的随机源:

    public void initialize(int keysize)由于调用上述与算法无关的 initialize 方法时不指定其它的参数,因此对于与每个密钥相关联的算法参数(如有的话)的处理就是提供者的事了。

如果算法是个“DSA”算法且模数的大小 (keysize) 是 512、768 或 1024,那么“SUN”提供者将使用一批预先计算好的值来作为 p、q 和 g 参数的值。 如果模数大小不是上述列出的值,则“SUN”提供者将创建一批新的参数。有的提供者除对上述所提的三个模数之外,还可能为其它情况也准备了预先计算好的值。不过,有的也许根本就不提供预先计算好的参数,而是总要创建新的参数集。

针对算法的初始化方法
对于已有一批特定算法的参数的情况(如 DSA 中所谓的“通用参数”),有两个initialize 方法是带 AlgorithmParameterSpec 变量的。其中一个还带 SecureRandom 变量,而另一个的随机源由系统提供。

    public void initialize(AlgorithmParameterSpec params,
                   SecureRandom random)

    public void initialize(AlgorithmParameterSpec params)有关详细信息,参见示例部分。

生成密钥对
不管使用的是哪种初始化方法(也就是算法),密钥对的生成方法总是一样,即总是通过调用 KeyPairGenerator 的以下方法:

    public KeyPair generateKeyPair()对 generateKeyPair 进行多次调用将得到不同的密钥对。

密钥管理
可使用名为“密钥仓库”的数据库来管理密钥和证书库 (证书是来自一个实体的数字签名的声明,即声明另一实体的公钥确实是某一特定值)。

Keystore(密钥仓库)实现
KeyStore

目前有两类命令行工具使用 KeyStore:keytool、jarsigner 及一个名为 policytool 的图形用户界面工具。它还被缺省 Policy 实现用于处理策略文件。策略文件用于指定授予来自不同源的代码的(访问系统资源)的权限。由于 KeyStore 是公开的,因此 JDK 用户可利用它来编写其它安全应用程序。

Sun Microsystems 公司提供了一个内嵌的缺省实现。它利用一个名为“JKS” 的专用密钥仓库类型(格式),将密钥仓库实现为一个文件。它用不同的口令来保护每个私钥,也用(可能)不同的口令来保护整个密钥仓库的完整性。

Keystore 的实现是基于提供者的。具体地说,由 KeyStore 所给的 API 是借助于“服务提供者接口”(SPI) 来实现的。也就是说,有一个对应的抽象 KeystoreSpi 类(也在 java.security 包中),它定义了“提供者”必须实现的服务提供者接口方法 (“提供者”指的是一个或一组包,它们提供了一批可由 JDK 安全 API 访问的那些服务的具体实现)。 因此,要提供某个密钥仓库实现方法,客户必须实现一个“提供者”,然后象如何为 Java 加密体系结构实现提供者中所述的那样给出 KeystoreSpi 子类的实现。

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

缺省的密钥仓库类型是“jks”(这是由“SUN”提供者提供的密钥仓库实现方法的专用类型)。在安全属性文件中它由下面一行进行指定。

    keystore.type=jks要让工具及其它应用程序使用缺省类型以外的密钥仓库实现方法,可更改这一行,指定一个不同的密钥仓库类型。另一种解决办法是让工具及其它应用程序的用户指定密钥仓库类型,然后将指定值传给 KeyStore 的 getInstance 方法。

下面是前面一种处理方法的示例:如果有这样一个提供者包,它给出名为“pkcs12”的密钥仓库类型的密钥仓库实现,则应将前面提到的那行改为:

    keystore.type=pkcs12注意:密钥仓库类型的名称中大小写无关紧要。例如,“JKS”被认为与“jks”相同。

类提供一些相当完善的接口来访问和修改密钥仓库中的信息。可以有多个不同的具体实现,其中每个实现都是对某个特定类型密钥仓库的具体实现。
KeyStore 类
KeyStore 类是个引擎类,它提供一些相当完善的接口来访问和修改密钥仓库中的信息。

该类代表内存中密钥和证书的一个集合。它管理两类入口:

Key 入口
这类密钥仓库入口用来放极为敏感的密钥信息(这种信息以一种受保护的格式储存以防止未经认可的访问)。

通常,储存在这类入口中的密钥是秘密密钥,或是带有用于认证相应公钥的证书链的私钥。

私钥和证书链将用于某个实体用数字签名进行自我认证。例如,软件分销机构可以对 JAR 文件进行数字签名,然后作为发行软件和/或软件签发许可证的一部分。

可信证书入口
这类入口含有属于另一方的单一公钥证书。它之所以叫可信证书,是因为密钥仓库的拥有者相信证书中的公钥确实属于证书主体(拥有者)所标识的身份。

该入口可用于认证其他方。

密钥仓库中的每个入口都用一个“别名”字符串来标识。对于私钥及其相关的证书链,这些字符串可以区分实体进行自我认证时的不同方法。例如,实体可向不同的认证机构认证自己或用不同的公钥算法来进行自我认证。

这并未指定密钥仓库是否持久以及密钥仓库使用的机制是否持久,因此就需要使用各种技术来保护敏感的密钥(如私钥或秘密密钥)。用户可以选择智能卡或其它集成密码引擎 (SafeKeyper),也可采用(各种格式的)文件之类的更简单机制。

下面说明主要的 KeyStore 方法。

创建 KeyStore 对象
正如所有的引擎类一样,获取 KeyStore 对象的途径是调用 KeyStore 类中的 getInstance 静态 factory 方法:

    public static KeyStore getInstance(String type)调用程序可选择指定提供者名称,以保证所要求的类型是由已命名提供者实现的:

    public static KeyStore getInstance(String type, String provider)将某个 Keystore 加载到内存中
在使用某个 KeyStore 对象前,必须先用 load(加载)方法将实际的密钥仓库数据载入内存:

    public final void load(InputStream stream, String password)口令是可选项,用来检查密钥仓库数据的完整性。如果不给口令,则不进行完整性的检查。

要创建空密钥仓库,请将 null 作为 InputStream 变量传给 load 方法。

获取密钥仓库别名清单
所有密钥仓库入口都是通过唯一的 aliases(别名)访问的。

aliases 方法返回密钥仓库中所有别名的清单:

    public final Enumeration aliases()确定 Keystore 入口类型
正如 KeyStore 类中所述,密钥仓库中有两种不同类型的入口。

以下方法分别用于确定由某个给定别名指定的入口是密钥入口/证书或可信证书入口。

    public final boolean isKeyEntry(String alias)

    public final boolean isCertificateEntry(String alias)添加/设置/删除 Keystore 入口
setCertificateEntry

    public final void setCertificateEntry(String alias, Certificate cert)如果别名不存在,则创建具有该别名的可信证书入口。如果别名存在并识别出了某个可信证书入口,则用 cert 替换与之关联的证书。

setKeyEntry 方法用于添加(如果别名尚不存在)或设置密钥入口:

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

    public final void setKeyEntry(String alias, byte[] key,
                                  Certificate[] chain)在 key 是字节数组的方法中,密钥的字节是被保护的格式。例如,在“SUN”提供者给出的密钥仓库实现中, key 字节数组应是含有被保护私钥的数组,它被编码为 PKCS#8 标准中定义的EncryptedPrivateKeyInfo。在其它方法中,password(口令)是用于保护密钥的口令。

deleteEntry 方法用于删除入口:

    public final void deleteEntry(String alias)方法可为某一别名指定证书:
从密钥仓库中获取信息
getKey

    public final Key getKey(String alias, String password)以下方法分别用于返回与给定别名相关联的证书或证书链:

    public final Certificate getCertificate(String alias)

    public final Certificate[] getCertificateChain(String alias)可用以下方法确定第一个与所给证书相匹配的入口名(别名):

    public final String getCertificateAlias(Certificate cert)方法返回与所给别名相关联的密钥。密钥由所给的口令来还原:
保存密钥仓库
内存中的密钥仓库可用 store(保存)方法来保存:

    public final void store(OutputStream stream, String password)口令用于计算密钥仓库中数据的完整性校验和,该完整性校验和将附加在密钥仓库数据上。

SecureRandom 类
SecureRandom 类是个引擎类,它提供随机数发生器功能。

创建 SecureRandom 对象
正如所有的引擎类一样,获取 SecureRandom 对象的途径是调用 SecureRandom 类中的 getInstance 静态 factory 方法:

    public static SecureRandom getInstance(String algorithm)调用程序可选择指定提供者名称,以保证所要求的随机数发生器 (RNG) 算法是由已命名的提供者实现的:

    public static final SecureRandom getInstance(String algorithm,
                                                 String provider)设置或重置 SecureRandom 对象的随机数种子
除非调用程序在调用 getInstance 方法后接着调用 setSeed 方法,否则 SecureRandom 实现方法将会完全使发生器的内部状态随机化:

    synchronized public void setSeed(byte[] seed)
    public void setSeed(long seed)一旦对 SecureRandom 对象设置了随机数种子,它就会象原始种子那样随机地产生比特。

任何时候都可用 setSeed 方法对 SecureRandom 重新设置随机数

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics