JSSE Java Secure Socket Extension
JGSS Java Generic Security Services - kerberos
SASL Simple Authentication and Security Layer
JCE 使用和 JCA 一样的架构,JCE 应该被看做是 JCA 的一部分.
JDK 中的 JCA 包含两个组件:
- 定义密码服务以及提供支持的框架
- 实际提供实现的 provider, 如 Sun, SunRsaSign, SunJCE
JCA 设计原则
- 实现独立性与互操作性
- 算法独立性与可扩展
使用密码服务,例如数字签名,消息摘要等,并不需要担心实现的细节,甚至是组成这些基础概念的的算法。完全的算法独立性是做不到的,这里的意思就是不可能完全抽象出一个接口,屏蔽使用的细节,做到算法的独立性。JCA 提供了标准化的,特定类型相关算法的 API. 并且当有多个实现时,允许开发者指定特定的实现。
算法的独立性
通过密码引擎(cryptographic engines), 以及提供这些密码引擎功能的定义类实现独立性。这些类被称为 引擎类,如 MessageDigest
, Signature
, KeyFactory
, KeyPairGenerator
, Cipher
等类
实现的独立性
使用基于 procider 的架构实现的, provider(Cryptograpic Service Provider)在这里指的是实现一个或多个密码服务(如数字签名算法,消息摘要算法等)的包或一组包。应用程序可能只是简单的从安装的众多 provider 中请求实现了某个特定服务的特定类型对象,如实现了 DSA 签名算法的 Signature
对象,当然也可以自己指定从哪个特定的 provider 中获取。provider 对应用程序的使用是透明的。
可互操作性
的事项也可以正常工作,一个 provider 提供的某个服务实现产生的密钥,可以用于另一个 provider 相同服务提供的实现。再比如证书以及证书的验证等。其实就是算法都是相同的,JCA 对输入,输出进行了标准化,所以不同的 provider 实现都要遵循相同的标准,又是实现相同的算法,当然可以互相操作了。
算法的可扩展性
只要是现有引擎类支持,该引擎类类的新算法可以很容易的被添加。比如,现在有一种新的消息摘要算法,实现之后就可以提供 provider ,应用中使用相同的引擎类 MessageDigest
类获取该新算法的实例,就可以使用了。
Cryptographic Service Providers
java.security.Provider
类是所有 provider 的基类,每一个 CSP 包含了这个类的一个实例,其中包含了 provider 的名称以及所有它实现的安全服务/算法的列表。 当需要某个特定算法的实例时,JCA 框架会查询所有的 provider,如果有匹配,就会创建它的实例。
providers 的包提供了一些广为人知的密码算法的具体实现。每一个 JDK 都默认安装并配置了一个或多个 provider。额外的 provider 可以被静态或动态的安装。客户端可以配置它们的运行时环境来指定 provider 的优先级顺序。就是 provider 被搜索的顺序。
使用 JCA,可以直接请求某个特定类型的对象和特定的算法,如 MessageDigest
, 使用 SHA-256
摘要算法,这会从安装的 provider 中获得一个该算法的实现:
1 | md = MessageDigest.getInstance("SHA-256"); |
如果需要,当然也可以指定某个具体的 provider
1 | md = MessageDigest.getInstance("SHA-256","providerName"); |
JDK 中的密码服务实现分布在几个不同的 provider 中(Sun, SunJSSE, SunJCE, SunRsaSing), 其它 Java 运行时环境可能不包含这些 provider ,所以只有在确定某个 provider 安装的情况下,才可以指定使用哪个 provider 的实现。JCA 提供了 API 可以用户查询安装的 provider 以及它们提供的安全服务/算法。JCA 使得第三方的 provider 的添加也是很容易的, 如 BouncyCastle。
Provider 具体是怎么实现的
有如下的代码,目的是获取一个 AES 密码算法的实例:
1 | Cipher c = Cipher.getInstance("AES"); |
具体的流程大概如下:
1 | 调用引擎类 Cipher 的静态工厂方法 getInstance |
当调用 init
方法时,Cipher 实例会将请求委托给 AESCiphrt对象对应的 engineInit
方法
KeyStore
keystore 是一种用来管理密钥和证书的数据库。应用在需要数据认证,加密以及签名时,就可以使用 keystore,在程序中,可以通过 KeyStore
类(位于 java.security 包下)。
keystore 类型/格式
- pkcs12 - 基于 RSA PKCS12 (Personal Information Exchange Syntax Standard)标准, JDK9 默认以及推荐的格式
- jks - 私有格式
- jceks - 私有格式
- pkcs11 - 基于 RSA PKCS11 标准,支持对密码令牌的访问,如硬件安全模块和智能卡
应用可以从不同的 provider 中选择不同类型的 keystore 实现。 KeyStore 类提供了接口来访问和修改一个 keystore 中的信息。这个类代表了一个内存中密钥和证书的集合,主要用来管理两种类型的条目:
密钥 - Key
密钥类型的条目保存了非常敏感的密钥信息,必须进行保护以避免未经授权的访问。通常,是一个私密的密钥 (secret key) 或者是一个私钥(private key)以及对其公钥进行认证的证书链。私钥以及证书链被一个指定的实体使用数字签名来进行自认证。例如:软件供应商对 JAR 文件进行数字签名,作为软件发布的一部分
受信任的证书 - Trusted Certificate Entry
这种类型的条目仅包含了一个个公钥证书(从属于其它实体), 被称为受信任的证书,因为 keystore 的拥有者新人证书中的公钥确实是属于证书
subject(owner)
所标识的实体
keystore 中的每一个条目都通过一个别名 (alias) 字符串表示. 对于私钥及其关联的证书链,这些字符串区分实体进行身份验证的不同方式。
示例
1 | /** |
Engine Classes and Algorithoms
引擎类提供了到某一个具体类型的安全服务的接口, 与 provider 及算法是独立的,提供了以下功能:
密码服务操作(加密解密、数字签名,消息摘要等)
密码材料(cryotographic material)的生成或转换(密钥和算法初始化参数)
封装密码数据的对象(keystore 或证书),可以在抽象层的上层使用
可用的引擎类:
- SecureRandom 用来生成随机数或伪随机数
- MessageDigest 用来计算数据的消息摘要(hash, 单向散列函数)
- Signature 通过密钥进行初始化,用来对数据进行签名以及验证数字签名
- Cipher 通过密钥初始化,用来对数据进行加密,解密,有不同类型的密码算法:对称、非对称、PBE 等
- Mac Message Authentication Codes 同样也是用来生成 hash 值的,但是要用到密钥,用来保护数据的完整性
- KeyFactory 用来将非透明
Key
类型的密钥转换为特定密钥标准形式,反之亦然 - SecretKeyFactory 用来将非透明
SecretKey
类型的密钥转换为特定密钥标准形式,SecretKeyFactory 是 KeyFactory 的特殊形式,专门用来生成秘密的堆成密码的密钥 - KeyPairGenerator 用来生成一个新的公钥,私钥对,适用于特定的算法
- KeyGeneraor 用来生成特定算法的密钥
- KeyAgreement 使用在通信的两端,用来协商创建一个特定的密钥,使用在特定的密码操作中
- AlgorithmParameters 用来存储的特定算法的参数,包含参数编码和解码
- AlgorithmParameterGeneraor 用来生成适用于特定算法的一组 AlgorithmParameters
- KeyStore 用来创建以及管理一个 keystore. 一个 keystore 是一个存储密钥的数据库,keystore 中的私钥还关联了一个与其相关的证书链,用来认证对应的公钥。keystore 可能包含来自信任实体的证书
- CertificateFactory 用来创建公钥证书和 CRLs (Certificate Revtocation Lists) 证书撤回列表
- CertPathBuilder 用来创建一个证书链(也称之为证书路径)
- CertPathVlidator 用来对证书链进行验证
- CertStore 用来从一个 repository 中检索证书和 CRLs