JCA简介
Java平台强调安全性,包括语言安全性、密码学、公钥基础设施、身份验证、安全通信和访问控制。
JCA是java平台的重要部分,它包含了“provider”架构和一系列数字签名、消息摘要、证书和证书认证、加密(对称/非对称 流式/分组 加密),秘钥生成和管理、安全随机数生成API。这些API是的开发者可以十分简单的把安全集成到应用代码中。JCA架构设计上遵循如下准则:
- 实现独立: 应用程序不必自己实现安全算法,但是它们可以从java平台获取安全服务。安全服务是在providers (参考Cryptographic Service Providers)中以可插拔的方式实现的。应用程序可能依赖多个独立的providers 来实现安全功能。
- 实现互操作性: provider是跨应用程序互操作的。具体来说,应用程序不绑定到特定的provider,provider也不绑定到特定的应用程序。
- 算法可扩展性 Java平台包括许多内置的providers,它们实现了一组基本的安全服务,这些服务在今天被广泛使用。然而,有些应用程序可能依赖于尚未实现的新标准或专有服务。java平台支持安装定制的provider来扩展内置的providers。
JCA设计原则
JCA是围绕以下原则设计的
- 实现独立性和互操作性
- 算法独立性和可扩展性
实现独立性和算法独立性是互补的;您可以使用加密服务,比如数字签名和消息摘要,而不用担心实现细节,甚至不用担心构成这些概念基础的算法。虽然不可能完全独立于算法,但是JCA提供了标准化的、特定于算法的api。当不需要实现独立性时,JCA允许开发人员指定特定的实现。
算法独立性是通过定义加密“引擎”(服务)类型和定义提供这些加密引擎功能的类来实现的。这些类称为引擎类,比如MessageDigest, Signature, KeyFactory, KeyPairGenerator, and Cipher
实现独立性是通过使用基于“provider”的体系结构来实现的。实现独立性是通过使用基于“提供者”的体系结构来实现的。加密服务提供者(CSP)与“provider”是两个等价的术语,(请参阅加Cryptographic Service Providers
)指实现一个或多个加密服务的包或一系列包,如数字签名算法、消息摘要算法和密钥转换服务。程序可以简单地请求实现特定服务(如DSA签名算法)的特定类型的对象(如签名对象),并从安装的providers实现中选择一个。
实现互操作性意味着各种实现可以相互协作、使用彼此的密钥或验证彼此的签名。例如,对于相同的算法,一个provider生成的密钥可以被另一个provider使用,一个provider生成的签名可以被另一个provider验证。
算法的可扩展性意味着可以很容易地添加适合支持引擎类的新算法。
Provider架构
Providers包含一个包(或一组包),它为公开的加密算法提供具体的实现。
CSP
java.security.Provider
是所有Provider的基类。每个CSP都包含该类的一个实例,该实例包含provider的名称,并列出它实现的所有安全服务/算法。当需要特定算法的实例时,JCA框架会查询provider的数据库,如果找到了合适的匹配,就会创建实例。
Provider包含一个包(或一组包),它为公开的加密算法提供具体的实现。JDK在安装时会自带一个或多个provider,可以静态或动态添加其他provider。客户机可以配置其运行时环境来指定provider优先序,当没有指定特定的provider时, provider按照优先序返回第一个搜索到的provider。
要使用JCA,应用程序只需请求特定类型的对象(如MessageDigest)和特定的算法或服务(如“SHA-256”算法),并从安装的provider之一获得实现。例如,以下语句从已安装的provider请求SHA-256消息摘要:
md = MessageDigest.getInstance("SHA-256");
或者,程序可以指定provider。每个provider都有一个用于引用它的名称。例如,以下语句从名为ProviderC的provider请求SHA-256消息摘要:
md = MessageDigest.getInstance("SHA-256", "ProviderC");
下面的图说明了请求SHA-256消息摘要实现。它们显示了三个不同的provider,它们实现了各种消息摘要算法(SHA-256、SHA-384和SHA-512)。provider优先序从左到右递减。在图2-1中,应用程序不指定provider名称请求SHA-256算法实现,按照优先顺序搜索provider会返回ProviderB。在图2-2中,应用程序从特定的提供者ProviderC请求SHA-256算法实现。这一次会返回ProviderC的实例,即使具有更高优先级顺序的提供者ProviderB也提供MD5实现。
图2-1没有指定提供程序的请求SHA-256消息摘要实现
图2-2使用ProviderC请求SHA-256消息摘要
JDK中的加密实现是通过几个不同的provider(Sun、SunJSSE、SunJCE、SunRsaSign)分发的,这主要是由于历史原因,但在较小程度上是由于它们提供的功能类型和算法。其他Java运行时环境可能不一定包含这些provider,因此应用程序不应该请求特定于provider的实现,除非知道某个特定provider是可用的。
JCA提供了一组api,允许用户查询安装了哪些provider以及它们支持哪些服务。
这种体系结构还使最终用户可以很容易地添加其他provider。许多第三方provider实现已经可用。有关provider如何编写、安装和注册的详细信息,请参阅Provider 类
provider是如何实现的
算法独立性是通过定义一个通用的高级应用程序编程接口(API)来实现的,所有应用程序都使用这个API来访问服务类型。实现独立性是通过让所有的provider实现遵守定义好的接口。比如引擎类,应用程序调用通过engine类路由并传递到底层的支持实现。实现处理请求并返回正确的结果。
每个引擎类中的应用程序API方法通过实现相应服务provider接口(SPI)的类路由到provider的实现。也就是说,对于每个引擎类,都有一个相应的抽象SPI类,它定义了每个加密服务provider的算法必须实现的方法。每个SPI类的名称与相应引擎类的名称相同,后面跟着SPI。比如, Signature
签名引擎提供了数字签名的功能, 实际provider 需要实现的SPI为SignatureSpi
,应用程序调用engine类的API方法,后者在实际实现中调用SPI方法。
每个SPI类都是抽象的。要为特定算法提供特定类型服务的实现,Provider必须子类化相应的SPI类,并为所有抽象方法提供实现。
对于API中的每个引擎类,通过调用引擎类中的getInstance()
工厂方法来请求和实例化实现实例。引擎类使用上面描述的框架provider选择机制来获得实际的支持实现(SPI),然后创建实际的引擎对象。engine类的每个实例都封装了相应SPI类的实例(作为私有字段),即SPI对象。API对象的所有API方法都声明为final,它们的实现调用封装的SPI对象的相应SPI方法。
为了更清楚地说明这一点,请看示例2-1和图2-3:
示例2-1 获取Engine类实例的示例代码
import javax.crypto.*;
Cipher c = Cipher.getInstance("AES");
c.init(ENCRYPT_MODE, key);
图2-3 应用程序检索“AES”密码实例
如图所示应用需要一个javax.crypto.Cipher.AES
的实例而不关心使用哪一个provider。应用程序调用Cipher
engine类的getInstance()
工厂方法,该方法要求JCA框架找到第一个支持AES
的provider实例。框架咨询每个已安装的provider,并获得provider类的provider实例。(回想一下,Provider类是可用算法的数据库。)框架搜索每个provider,最后在CSP3中找到合适的条目。这个数据库入口指向扩展了CipherSpi的com.foo.AESCipher实现类,因此适用于Cipher engine。com.foo.AESCipher
实例创建并封装在新创建的javax.crypto.Cipher
实例中.当应用程序现在对Cipher
实例执行init()
操作时,Cipher engine
类将请求路由到com.foo.AESCipher
中的相应engineInit()
方法。
Java Security Standard Algorithm Names列出为Java安全环境定义的标准名称。其他第三方provider可能会定义自己的这些服务的实现,甚至是附加服务。
Keystores(密钥存储库)
所谓keystore
是一个可以用来管理密钥和证书的数据库。对于需要数据进行身份验证、加密或签名的应用程序,可以使用密钥存储库
应用程序可以使用java.security
包中的 KeyStore
的实现类来访问一个秘钥存储库。在JDK 9中,默认和推荐的密钥存储类型(格式)是“pkcs12”,它基于RSA pkcs12个人信息交换语法标准。在此之前,默认的密钥存储类型是“jks”,这是一种专有格式。还可以使用其他密钥存储格式,例如“jceks”(另一种专用密钥存储格式)和“pkcs11”(基于RSA pkcs11标准),支持访问加密令牌,如硬件安全模块和智能卡。
应用程序可以从不同的提供者中选择不同的密钥存储实现。
引擎类和算法
engine类为特定类型的加密服务提供接口,独立于特定的加密算法或provider
引擎提供以下之一:
- 加密操作(加密、数字签名、消息摘要等)
- 密码材料的生成器或转换器(密钥和算法参数)
- 封装加密数据并可用于更高抽象层的对象(密钥存储或证书)
引擎类:
- SecureRandom:用于生成随机数或伪随机数。
- MessageDigest:用于计算指定数据的消息摘要(散列)。
- Signature: 使用密钥初始化, 用于数据签名和验证数字签名
- Cipher: 使用密钥初始化,用于加解密数据。有各种类型的算法: 对称加密 (e.g. AES), 非对称加密(e.g. RSA), 和基于密码的加密(e.g. PBE).
- Message Authentication Codes (MAC): 与MessageDigests一样,它们也生成哈希值,但首先使用密钥进行初始化,以保护消息的完整性。
- KeyFactory: 用于将现有的不透明类型密钥转换为密钥规范(底层密钥材料的透明表示),反之亦然
- SecretKeyFactory:用于将现有的、不透明的、类型为SecretKey的加密密钥转换为密钥规范(底层密钥材料的透明表示),反之亦然。
- Secretkeyfactory是专门的keyfactory,仅创建私钥(对称)。
- KeyPairGenerator: 用于生成适合与指定算法一起使用的公钥和私钥对。
- KeyGenerator: 用于生成用于指定算法的私钥。
- KeyAgreement: 由两个或多个方共同商定并建立一个特定的密钥以用于特定的加密操作
- AlgorithmParameters: 用于存储特定算法的参数,包括参数编码和解码。
- AlgorithmParameterGenerator :用于生成一组适合于指定算法的算法参数。
- KeyStore: 用于创建和管理密钥存储库。密钥存储库是密钥的数据库。密钥存储库中的私钥具有与它们相关联的证书链,从而对相应的公钥进行身份验证。密钥存储库还包含来自受信任实体的证书。
CertificateFactory: 用于创建公钥证书和证书撤销列表(crls)
CertPathBuilder:用于构建证书链(也称为证书路径)。
CertPathValidator: 用于验证证书链。
CertStore:用于从存储库中检索证书和crl
核心类和接口
以下是JCA中提供的核心类和接口。
-
Provider
和Security
-
SecureRandom
,MessageDigest
,Signature
,Cipher
,Mac
,KeyFactory
,SecretKeyFactory
,KeyPairGenerator
,KeyGenerator
,KeyAgreement
,AlgorithmParameter
,AlgorithmParameterGenerator
,KeyStore
,CertificateFactory
, 和引擎 -
Key
接口,KeyPair
-
AlgorithmParameterSpec
接口,AlgorithmParameters
, -
AlgorithmParameterGenerator
, 和在java.security.spec
与javax.crypto.spec
包中的算法参数和特定接口类 -
KeySpec
接口,EncodedKeySpec
,PKCS8EncodedKeySpec
, 和X509EncodedKeySpec
. -
SecretKeyFactory
,KeyFactory
,KeyPairGenerator
,KeyGenerator
,KeyAgreement
, 和KeyStore
.
本指南将首先介绍最有用的高级类(Provider, Security, SecureRandom, MessageDigest, Signature, Cipher, and Mac),然后深入研究各种支持类。现在,只需简单地说键(public, private, and secret)是由各种JCA类生成和表示的,高级类将其用作操作的一部分就足够了。
本节展示了每个类和接口中的主要方法,这些类(MessageDigest, Signature, KeyPairGenerator, SecureRandom, KeyFactory, 和key specification classes) 中的一些示例在相应的代码示例部分中提供
有关安全API包的完整参考文档可以在包摘要中找到:
java.security
javax.crypto
java.security.cert
java.security.spec
javax.crypto.spec
java.security.interfaces
javax.crypto.interfaces