JAVA加密体系结构


JavaTM 加密体系结构

API 规范和参考

 

上次修改时间: 1998 年 10 月 30 日


简介
设计原理
体系结构
概念

 

核心类和接口
Provider 类
如何请求和提供提供者的实现
安装提供者
Sercuity 类
MessageDigest 类
Signature 类
算法参数类
算法参数规范接口和类
AlgorithmParameterSpec 接口
DSAParameterSpec 类
AlgorithmParameters 类
AlgorithmParameterGenerator 类
密钥接口
密钥规范接口和类
KeySpec 接口
DSAPrivateKeySpec 类
DSAPublicKeySpec 类
RSAPrivateKeySpec 类
RSAPrivateCrtKeySpec 类
RSAPublicKeySpec 类
EncodedKeySpec 类
PKCS8EncodedKeySpec 类
X509EncodedKeySpec 类
KeyFactory 类
CertificateFactory 类
KeyPair 类
KeyPairGenerator 类
密钥管理
Keystore 位置
Keystore 实现
KeyStore 类
SecureRandom 类

 

代码示例
计算 MessageDigest 对象
生成密钥对
用生成的密钥来生成和校验签名
用密钥规范和 KeyFactory 来生成和校验签名
读取用 Base64 编码的证书
解析证书答复

 

附录 A:标准名称
附录 B:算法

简介

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 对象的 initSigninitVerify 方法使用的格式提供 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 加密体系结构中提供的核心类和接口:

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

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 类中的 addProviderinsertProviderAt 方法。这种类型的注册并不是持久的,且只能由“可信任”的程序来进行。参见安全

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 缓冲区中,起点是 offsetlenbuf 中分配给该摘要的字节数。该方法返回实际存储在 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 类定义了两个初始化方法:initSigninitVerify 方法,它们将分别把状态改为 SIGNVERIFY

创建 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 缓冲区中,起点是 offsetlenoutbuf 中分派给签名的字节数。该方法返回实际存储的字节数。

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

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

也可以指定另一个私钥重新调用 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)

其中的参数必须是字节数组,该数组包含被编码为两个整数 rs 的标准 ANSI .1 序列的签名。这是一种常用的标准编码。它与由 sign 方法产生的一样。

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

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

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

算法参数类

算法参数规范接口和类

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

一组参数的透明表示意思是可以通过相应规范类中定义的某个“get"(获取)方法来分别访问组中的每个参数值(例如,DSAParameterSpec 定义了 getPgetQgetG 方法,分别用于访问 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”接口中定义的三种方法(见下面)来访问:getAlgorithmgetFormatgetEncoded。 这与透明表示形成对照。在透明表示中,用户可以通过相应规范类中定义的某个“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 定义了 getXgetPgetQgetG 方法,用以访问私钥 x 和计算密钥时所用的 DSA 算法参数:质数 p、亚质数 q 和基数 g

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

密钥可用针对算法的方式或用与算法无关的编码格式(例如 ASN.1)来指定。例如,DSA 私钥可用它的组件 xp, qg (参见 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 的质数因子 pq、指数 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 公钥可用它的组件 ypqg(参见 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”提供者将使用一批预先计算好的值来作为 pqg 参数的值。 如果模数大小不是上述列出的值,则“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:keytooljarsigner 及一个名为 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 重新设置随机数种子。所提供的随机数种子将用来补充现有的随机数种子而不是将其换掉。这样就可以保证重复调用不会降低随机性。

使用 SecureRandom 对象

要获取随机字节,调用程序只需传送一个任意长度的数组,该数组随即被填上了随机字节:

    synchronized public void nextBytes(byte[] bytes)

生成种子字节

需要的话,可以调用 generateSeed 方法来产生给定数目的随机数种子字节(例如,可用它来为其它的随机数发生器设置随机数种子):

    public byte[] generateSeed(int numBytes)

代码示例

计算 MessageDigest 对象

首先,按下例所述创建 message digest(报文摘要)对象:

    MessageDigest sha = MessageDigest.getInstance("SHA");

该调用语句将把已适当初始化后的 message digest 对象赋给 sha 变量。该实现方法实现了安全散列算法 (SHA),其定义在美国国家标准技术局 (NIST) 的 FIPS 180-1 文档中给出。有关对标准名称和算法的完整讨论,参见附录 A

下一步,假设有三个字节数组 i1i2i3 组成整个输入。我们要计算它们的报文摘要。该摘要(或“散列”) 可通过以下的调用来计算:

    sha.update(i1);
    sha.update(i2);
    sha.update(i3);
    byte[] hash = sha.digest();

另一组等效的调用是:

    sha.update(i1);
    sha.update(i2);
    byte[] hash = sha.digest(i3);

计算出报文摘要后,message digest 对象即自动重置并准备就绪,可接受新数据及计算新数据的摘要。所有先前的状态(即原来提供给 update 调用的数据)都不再存在。

有些散列实现方法也可通过复制支持中间散列。 假设我们要分别计算以下各组合的散列:

  • i1
  • i1 和 i2
  • i1、i2 和 i3

一种方法是:

    /* compute the hash for i1 */
    sha.update(i1);
    byte[] i1Hash = sha.clone().digest();

    /* compute the hash for i1 and i2 */
    sha.update(i2);
    byte[] i12Hash = sha.clone().digest();

    /* compute the hash for i1, i2 and i3 */
    sha.update(i3);
    byte[] i123hash = sha.digest();

这只有在 SHA 实现方法可复制时可行。message digest 的某些实现是可复制的,而另一些却无法复制。要确定是否能复制,可以试着复制 MessageDigest 对象并捕获可能的异常:

try {
   // try and clone it
    /* compute the hash for i1 */
    sha.update(i1);
    byte[] i1Hash = sha.clone().digest();
    . . .
    byte[] i123hash = sha.digest();
} catch (CloneNotSupportedException cnse) {
  // do something else, such as the code shown below
}

如果报文摘要是不可复制的,则另一种较为复杂的计算中间摘要的方法就是创建几个 摘要。这种情况下,必须事先知道要计算的中间摘要个数:

    MessageDigest i1 = MessageDigest.getMessageDigest("SHA");
    MessageDigest i12 = MessageDigest.getMessageDigest("SHA");
    MessageDigest i123 = MessageDigest.getMessageDigest("SHA");

    byte[] i1Hash = i1.digest(i1);

    i12.update(i1);
    byte[] i12Hash = i12.digest(i2);

    i123.update(i1);
    i123.update(i2);
    byte[] i123Hash = i123.digest(i3);

生成密钥对

本例中,我们将为名为“DSA”(数字签名算法)的算法生成一个公钥-私钥对。我们将使用一个名为 userSeed 的用户提供的随机数种子来产生具有 1024-位模数的密钥。我们并不关心算法的实现由哪个提供者提供。

生成密钥对生成器

为 DSA 算法生成密钥的第一步是取得一个密钥对生成器对象:

    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
初始化密钥对生成器

第二步是初始化密钥对生成器。大多数情况下,用与算法无关的初始化方法就足够了,但某些时候,要用针对算法的初始化方法。

与算法无关的初始化方法

所有的密钥对生成器都共用两个概念:密钥大小和随机源。 KeyPairGenerator 类的 initialize(初始化)方法带有这两类变量。因此,要生成密钥大小为 1024 的密钥和由 userSeed 值来提供随机数种子的新 SecureRandom 对象,可用以下代码:

    SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
    random.setSeed(userSeed);
    keyGen.initialize(1024, random);

由于调用上述与算法无关的 initialize 方法时不指定其它参数,因此,对于与每个密钥相关联的针对算法的参数(如果有)的处理就是提供者的事了。提供者也许会使用一些预先计算好的值,也许会提供新的值。

针对算法的初始化方法

对于已有一批算法相关参数的情况(如 DSA 中所谓的“通用参数”),有两个 initialize 方法是带 AlgorithmParameterSpec 变量的。假设密钥对生成器是用于“DSA”算法的,且您有一组针对 DSA 的参数(pqg),现在要用这些参数来产生密钥对。您可以执行以下代码来初始化密钥对生成器(注意,DSAParameterSpec 是一个 AlgorithmParameterSpec):

    DSAParameterSpec dsaSpec = new DSAParameterSpec(p, q, g);
    SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
    random.setSeed(userSeed);
    keyGen.initialize(dsaSpec, random);

(注意:名为 p 的参数是个质数,它的长度就是模数的长度 - “大小”。因此,无需再调用任何别的方法来指定模数的长度)。

生成密钥对

最后一步是生成密钥对。不管是用哪类初始化方法(与算法无关的或是针对算法的),都用相同的代码来产生密钥对

    KeyPair pair = keyGen.generateKeyPair();

用生成的密钥来生成和校验签名

以下是生成和校验签名的示例,它们都要用到上述密钥对示例中生成的密钥对。

生成签名

首先创建 signature 对象:

    Signature dsa = Signature.getInstance("SHA1withDSA");

第二步,利用在密钥对示例中所生成的密钥对,用私钥对该对象进行初始化,然后对名为 data(数据)的字节数组签名。

    /* Initializing the object with a private key */
    PrivateKey priv = pair.getPrivate();
    dsa.initSign(priv);

    /* Update and sign the data */
    dsa.update(data);
    byte[] sig = dsa.sign();
校验签名

校验签名非常简单(注意:此处我们仍然用在密钥对示例中生成的密钥对)。

    /* Initializing the object with the public key */
    PublicKey pub = pair.getPublic();
    dsa.initVerify(pub);

    /* Update and verify the data */
    dsa.update(data);
    boolean verifies = dsa.verify(sig);
    System.out.println("signature verifies: " + verifies);

用密钥规范和 KeyFactory 生成和校验签名

假设您没有公钥/私钥对(上述密钥对示例中所生成的密钥对),而只有 DSA 私钥组件:x(私钥)、p(质数)、q(亚质数)和 g(基数)。

进一步假设您要用私钥对存放在名为 someData 字节数组中的某些数据进行数字签名。您将执行以下步骤来达到这一目的。这些步骤也阐述了如何创建密钥规范和如何使用密钥工厂来从密钥规范获取 PrivateKey(initSign 方法要用 PrivateKey):

    DSAPrivateKeySpec dsaPrivKeySpec =
        new DSAPrivateKeySpec(x, p, q, g);

    KeyFactory keyFactory = KeyFactory.getInstance("DSA");
    PrivateKey privKey = keyFactory.generatePrivate(dsaPrivKeySpec);

    Signature sig = Signature.getInstance("SHA1withDSA");
    sig.initSign(privKey);
    sig.update(someData);
    byte[] signature = sig.sign();

假设 Alice 要用您已签名的数据。要使她能使用您已签名的数据以及校验您的签名,则必须给她送去以下三件东西:

  • 数据
  • 签名
  • 与用来对数据进行签名的私钥相对应的公钥

您可以将 someData 字节存在一个文件中,将 signature 字节存在另一个文件中,然后将这些发送给 Alice。

对于公钥,如在签名示例中那样,假设您有用来签写数据用的 DSA 私钥所对应的公钥组件。于是,您可以用这些组件来创建 DSAPublicKeySpec:

        DSAPublicKeySpec dsaPubKeySpec =
                new DSAPublicKeySpec(y, p, q, g);

您仍需要提取密钥字节,以便将它们放在文件中。为此,可以先调用上例所创建 DSA 密钥工厂中的 generatePublic 方法 :

        PublicKey pubKey = keyFactory.generatePublic(dsaPubKeySpec);

之后,您就可以用以下方法来提取(已编码的)密钥字节:

        byte[] encKey = pubKey.getEncoded();

现在,您就可以将这些字节存在某个文件中,并将它和含有数据及签名的那些文件一起发送给 Alice。

现在,假设 Alice 已经接收到这些文件,并将数据文件中的数据字节复制到名为 data 的字节数组中,同时将签名文件中的签名字节复制到名为 signature 的字节数组中,而将公钥文件中的已编码公钥字节复制到名为 encodedPubKey 的字节数组中。

现在,Alice 即可执行下述代码来校验签名。这一代码也阐述了如何使用密钥工厂利用编码来实例化 DSA 公钥(initVerify 要用到 PublicKey)。

    X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encodedPubKey);

    KeyFactory keyFactory = KeyFactory.getInstance("DSA");
    PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);

    Signature sig = Signature.getInstance("SHA1withDSA");
    sig.initVerify(pubKey);
    sig.update(data);
    sig.verify(signature);

注意:上述代码中,Alice 必须从已编码的密钥比特生成一个 PublicKey,这是因为 initVerify 要用到 PublicKey。 有了 PublicKey 对象后,她就可以用 KeyFactory 的 getKeySpec 方法将之转换为 DSAPublicKeySpec 对象,以便在必要时可以访问各组件,如下所示:

    DSAPublicKeySpec dsaPubKeySpec =
        (DSAPublicKeySpec)keyFactory.getKeySpec(pubKey,
            DSAPublicKeySpec.class)

现在,她就可以通过 DSAPublicKeySpec 类中相应的“get”方法(getYgetPgetQgetG)来访问 DSA 公钥的组件 ypqg

读取用 Base64 编码的证书

下例将是读取含有用 Base64 编码的证书,这种证书的起始行是:

-----BEGIN CERTIFICATE-----

结束行是:

-----END CERTIFICATE-----

我们将 FileInputStream(它不支持 markreset 方法)转换为 ByteArrayInputStream(它支持这些方法),以便使每次对 generateCertificate 的调用都只用一个证书,且输入流的读取位置定位在文件的下一个证书上:

FileInputStream fis = new FileInputStream(filename);
DataInputStream dis = new DataInputStream(fis);

CertificateFactory cf = CertificateFactory.getInstance("X.509");

byte[] bytes = new byte[dis.available()];
dis.readFully(bytes);
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);

while (bais.available() > 0) {
   Certificate cert = cf.generateCertificate(bais);
   System.out.println(cert.toString());
}

解析证书答复

下例将解析保存在文件中的 PKCS#7 格式的证书答复并从文件中提取全部证书:

FileInputStream fis = new FileInputStream(filename);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Collection c = cf.generateCertificates(fis);
Iterator i = c.iterator();
while (i.hasNext()) {
   Certificate cert = (Certificate)i.next();
   System.out.println(cert);
}

附录 A:标准名称

JDK 安全 API 需要并使用了一套算法、证书和密钥仓库类型的标准名称。本规范确立以下名称为标准名称。

注意:密码和密钥协议算法标准名称的对应清单在 Java 密码扩展 (JCE 1.2) 的“API 规范和参考”指南的附录 A 中。有关本版本的详细信息可在 http://java.sun.com/products/jdk/1.2/jce/index.html 中找到。

有关算法规范的信息,参见附录 B。

报文摘要算法

这一节中的算法名称可在生成 MessageDigest 的实例时指定。

SHA: 安全散列算法,在安全散列标准 NIST FIPS 180-1 中定义。

MD2: RFC 1319 中定义的 MD2 报文摘要算法。

MD5: RFC 1321 中定义的 MD5 报文摘要算法。

密钥和密钥参数算法

这一节中的算法名称可在生成 KeyPairGeneratorKeyFactoryAlgorithmParameterGeneratorAlgorithmParameters 的实例时指定。

RSA: PKCS#1 中定义的 RSA 加密算法。

DSA: FIPS PUB 186 中定义的数字签名算法。

数字签名算法

这一节中的算法名称可在生成 MessageDigest 的实例时指定。

SHA1withDSA: 带 SHA-1 的 DSA 签名算法,它使用 SHA-1 digest 算法和 DSA 来创建和校验 FIPS PUB 186 中定义的 DSA 数字签名。

MD2withRSA: 带 RSA 的 MD2 加密签名算法,它使用 MD2 digest 算法和 RSA 来创建和校验 PKCS#1 中定义的 RSA 数字签名。

MD5withRSA: 带 RSA 的 MD5 加密签名算法,它使用 MD5 digest 算法和 RSA 来创建和校验 PKCS#1 中定义的 RSA 数字签名。

SHA1withRSA: 带 SHA-1 的签名算法和在“OSI 的互操作性研讨会”上定义的签名算法,它使用 PKCS #1 中说明的填充约定。

随机数生成 (RNG) 算法

本节中的算法名称可在生成 SecureRandom 的实例时指定。

SHA1PRNG: 由 SUN 提供者所提供的伪随机数生成 (PRNG) 算法名。该实现符合 IEEE P1363 标准(附录 G.7:源位的扩展),并用 SHA1 作为 PRNG 的基础。它计算一个真随机种子值上的 SHA1 散列,该真随机种子值与一个 64 位的计数器串接在一起,每运算一次值就增加 1。从 160 位的 SHA1 输出中,只用 64 位。

证书类型

本节中的类型可在生成 CertificateFactory 的实例时指定。

X.509: X.509 中定义的证书类型。

密钥仓库类型

本节中的类型可在生成 KeyStore 的实例时指定。

JKS: 由 SUN 提供者提供的密钥仓库实现方法。

PKCS12: PKCS#12 中定义的个人身份信息传送语法。


附录 B:算法

本附录将对附录 A 中定义的某些算法的具体细节加以说明。任何提供者要提供所列算法的实现时都应符合本附录中的说明。注意:本文档的最新版本可在公共网站 http://java.sun.com/products/jdk/1.2/docs/guide/security/index.html 上得到。

要添加某个未在此处指定的新算法,应首先调查一下提供提供者包的个人或公司是否已将该算法添加进去。如果已经添加进去,请用他们公布的定义(如果已经公布)。否则,就应创建一个模板并使之可供他人使用(就象本附录 B 中所建的那些),从而对所提供的算法提供规范。

说明模板

后面将要谈到的算法规范包含以下这几个域:

名称

算法的名称。这是请求该算法时传给 getInstance 方法的名称,它可由 getAlgorithm 方法返回,用以确定现有算法对象的名称。这些算法包含在相关的引擎类中:SignatureMessageDigestKeyPairGeneratorAlgorithmParameterGenerator

类型

算法类型:Signature、MessageDigest、KeyPairGenerator 或 ParameterGenerator。

描述

有关算法的一般性解释,包括由算法实现的标准、适用的专利等。

KeyPair 算法(可选项)

该算法的密钥对算法。

Keysize(可选项)

用于加密算法或密钥生成算法:合法的密钥大小。

Size(可选项)

用于算法参数生成算法:算法参数生成的合法“大小”。

参数缺省值(可选项)

用于密钥生成算法:缺省的参数值。

签名格式(可选项)

用于签名算法,指签名的格式。也就是说,校验和签名方法的输入和输出的签名格式。

算法规范

SHA-1 报文摘要算法

名称: SHA

类型: MessageDigest

描述: NIST's FIPS 180-1 中定义的报文摘要,该算法的输出为 160 位的摘要。

MD2 报文摘要算法

名称: MD2

类型: MessageDigest

描述: RFC 1319 中定义的报文摘要算法,该算法的输出为 128 位(16 字节)的摘要。

MD5 报文摘要算法

名称: MD5

类型: MessageDigest

描述: RFC 1321 中定义的报文摘要算法,该算法的输出为 128 位(16 字节)的摘要。

数字签名算法

名称: SHA1withDSA

类型: Signature

描述: 该算法是 NIST FIPS 186 中描述的签名算法,它使用带 SHA1 的 DSA 报文摘要算法。

KeyPair 算法: DSA

签名格式:两个整数值:rs 的 ANSI.1 序列,顺序为:SEQUENCE ::= { r INTEGER, s INTEGER }

带 MD2、MD5 或 SHA1 的基于 RSA 的签名算法

名称: MD2withRSA、MD5withRSA 和 SHA1withRSA

类型: Signature

描述: 这些分别是使用带 RSA 加密的 MD2、MD5、和 SHA1 报文摘要算法。

KeyPair 算法: RSA

签名格式: RSA Laboratory's Public Key Cryptography Standards Note #1 中定义的 DER 编码 的 PKCS#1 块。加密数据就是被签名数据的摘要。

DSA KeyPair 生成算法

名称: DSA

类型: KeyPairGenerator

描述: 该算法是 NIST FIPS 186 for DSA 中定义的密钥对生成算法。

密钥大小: 模数 p 的长度,单位是比特。其范围必须在 512 到 1024 之间,且必须为 64 的倍数。缺省的密钥大小是 1024。

参数缺省值: 密钥大小为 512、768 和 1024 比特时使用下列各缺省参数值。

512 位密钥参数
SEED = b869c82b 35d70e1b 1ff91b28 e37a62ec dc34409b

counter = 123

p = fca682ce 8e12caba 26efccf7 110e526d b078b05e decbcd1e b4a208f3
    ae1617ae 01f35b91 a47e6df6 3413c5e1 2ed0899b cd132acd 50d99151
    bdc43ee7 37592e17

q = 962eddcc 369cba8e bb260ee6 b6a126d9 346e38c5

g = 678471b2 7a9cf44e e91a49c5 147db1a9 aaf244f0 5a434d64 86931d2d
    14271b9e 35030b71 fd73da17 9069b32e 2935630e 1c206235 4d0da20a
    6c416e50 be794ca4
768 位密钥参数
SEED = 77d0f8c4 dad15eb8 c4f2f8d6 726cefd9 6d5bb399

counter = 263

p = e9e64259 9d355f37 c97ffd35 67120b8e 25c9cd43 e927b3a9 670fbec5
    d8901419 22d2c3b3 ad248009 3799869d 1e846aab 49fab0ad 26d2ce6a
    22219d47 0bce7d77 7d4a21fb e9c270b5 7f607002 f3cef839 3694cf45
    ee3688c1 1a8c56ab 127a3daf

q = 9cdbd84c 9f1ac2f3 8d0f80f4 2ab952e7 338bf511

g = 30470ad5 a005fb14 ce2d9dcd 87e38bc7 d1b1c5fa cbaecbe9 5f190aa7
    a31d23c4 dbbcbe06 17454440 1a5b2c02 0965d8c2 bd2171d3 66844577
    1f74ba08 4d2029d8 3c1c1585 47f3a9f1 a2715be2 3d51ae4d 3e5a1f6a
    7064f316 933a346d 3f529252
1024 位密钥参数
SEED = 8d515589 4229d5e6 89ee01e6 018a237e 2cae64cd

counter = 92

p = fd7f5381 1d751229 52df4a9c 2eece4e7 f611b752 3cef4400 c31e3f80
    b6512669 455d4022 51fb593d 8d58fabf c5f5ba30 f6cb9b55 6cd7813b
    801d346f f26660b7 6b9950a5 a49f9fe8 047b1022 c24fbba9 d7feb7c6
    1bf83b57 e7c6a8a6 150f04fb 83f6d3c5 1ec30235 54135a16 9132f675
    f3ae2b61 d72aeff2 2203199d d14801c7

q = 9760508f 15230bcc b292b982 a2eb840b f0581cf5

g = f7e1a085 d69b3dde cbbcab5c 36b857b9 7994afbb fa3aea82 f9574c0b
    3d078267 5159578e bad4594f e6710710 8180b449 167123e8 4c281613
    b7cf0932 8cc8a6e1 3c167a8b 547c8d28 e0a3ae1e 2bb3a675 916ea37f
    0bfa2135 62f1fb62 7a01243b cca4f1be a8519089 a883dfe1 5ae59f06
    928b665e 807b5525 64014c3b fecf492a
RSA KeyPair 生成算法

名称: RSA

类型: KeyPairGenerator

描述: 该算法是 PKCS#1 中定义的密钥对生成算法。

大小: 任何一个等于或大于 512 同时也是 8 的倍数的整数。

DSA 参数生成算法

名称: DSA

类型: ParameterGenerator

描述: 该算法是 NIST FIPS 186 for DSA 中定义的参数生成算法。

大小: 模数 p 的长度,单位是比特。其范围必须在 512 到 1024 之间,且必须为 64 的倍数。缺省的大小是 1024。



版权所有 (C) 1996-98 Sun Microsystems, Inc。 保留所有权利。

如有意见,请发送到: java-security@java.sun.com。这不是订单。 

Sun 
Java Software 

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值