java网络学习之 jca体系概述(12)
java安全体系包括以下:JCA、JCE、JSSE、JAAS、JGSS、SASL
jca 概述
JCA主要包含了多个服务分别用于数字签名,消息摘要(哈希),证书和证书验证,加密(对称/非对称块/流密码),**生成 管理和安全随机数生成等等。jca服务的使用是基于jca 的多个引擎类,这些引擎类实现了对应的服务接口,引擎类好似一个路由,它内部会去遍历providers,查找对应的算法并返回。java 提供了一个Provider 接口, 所有人都可以自定义provider 实现,然后注册到java.security 中就可以了。
在jca 体系中 客户端直接使用的是服务,而服务的实现可以基于多个逻辑实现(算法),并且服务可以由多家供应商提供,所以获取一个服务其实 需要两个参数 算法和供应商,如果不指定供应商,则按顺序找到第一个就返回了。
JCA框架定义了服务接口和provider接口,JCE包里包含了很多供应商如Sun,SunRsaSign,SunJCE等。
java 内置的供应商实现由于美国出口限制,所以算法实现没有那么精密,只给出了比较简单的算法实现。如果要使用比较精密的算法实现,可以添加其他供应商。例如 bouncy castle和apache common codec,它们提供了额外的算法以及在JDK基础上提高了易用性
术语
- JCE(Java Cryptography Extension),在早期JDK版本中,由于受美国的密码出口条例约束,Java中涉及加解密功能的API被限制出口,所以Java中安全组件被分成了两部分: 不含加密功能的JCA(Java Cryptography Architecture )和含加密功能的JCE(Java Cryptography Extension)。现在JCE已经捆绑在JDK中,所以,这里JCE是JCA的一部分。
设计原则
- 实现独立性和互操作性
- 算法独立性和可扩展性
JCA提供标准化的、算法特定的API来实现上面两个原则。
- 通过各种引擎类来实现不同的功能,实现算法独立性(例如MessageDigest,Signature,KeyFactory,KeyPairGenerator和Cipher类)
- 使用Provider(提供者)的体系结构来达到“实现独立性”,程序可以指定使用特定服务提供者的算法实现。
- 实现互操作性意味着各种实现可以相互协作,使用彼此的**,或者验证彼此的签名。 这就意味着,对于相同的算法,由一个提供者生成的**可以被另一个提供者使用,并且由一个提供者生成的签名可以被另一个提供者验证。
核心包
JCA相关安全API软件包:
- java.security
- javax.crypto
- java.security.cert
- java.security.spec
- javax.crypto.spec
- java.security.interfaces
- javax.crypto.interfaces
provider 提供者
provider提供者,这里的全称是 Cryptographic Service Provider (CSP),是指实现一个或多个密码服务(如数字签名算法,消息摘要算法和**转换服务)的包或一组包。 每个JDK安装都默认安装并配置了一个或多个provider包。用户可以静态或动态添加其他provider。
JDK中的加密库出于历史原因,由几个不同的提供者实现:
- Sun
- SunJSSE
- SunJCE
- SunRsaSign
java.security.Provider是所有安全提供程序的基类。
如何自己定provider?
为了提供密码服务的实现,一个实体(例如开发组)编写实现代码并创建Provider类的子类。 Provider子类的构造函数设置各种属性的值; JDK安全API使用这些值来查找提供者实现的服务。 换句话说,子类指定实现服务的类的名称。
JCA实现原理(引擎类路由和provider 架构)
JCA使用引擎类作为路由,来实现java开发者和底层Provider实现的关联,实现实现独立性。
- 引擎类:每个引擎类,都有一个对应的抽象SPI类,它定义了每个加密服务提供者算法必须实现的方法。
- SPI(服务提供者接口):每个SPI类的名称与相应的引擎类相同,接着是Spi。 例如,Signature引擎类提供对数字签名算法的功能的访问。 实际的提供者实现是在SignatureSpi的子类中提供的。 应用程序调用引擎类的API方法,在实际的实现中又调用SPI方法。
下面的案例,展示了引擎类的使用,获取Provider对象实例的过程:
例如
import javax.crypto.*;
Cipher c = Cipher.getInstance("AES");
c.init(ENCRYPT_MODE, key);
- 这里的应用程序需要一个“AES”算法的javax.crypto.Cipher实例,并不关心使用哪个提供者。
- 应用程序调用Cipher引擎类的getInstance()工厂方法,然后请求JCA框架查找支持“AES”的第一个提供程序实例。
- 该框架会咨询每个已安装的提供者,并获取提供者类的提供者实例。框架搜索每个提供者,最终在CSP3中找到合适的条目。
- 这个数据库入口指向扩展CipherSpi的实现类com.foo.AESCipher,因此适用于Cipher引擎类。创建一个com.foo.AESCipher的实例,并将其封装在一个新创建的javax.crypto.Cipher实例中,该实例返回给应用程序。
- 当应用程序现在对Cipher实例执行init()操作时,Cipher引擎类将请求路由到com.foo.AESCipher类中相应的engineInit()支持方法中。
引擎类
引擎类为特定类型的密码服务提供接口,而不依赖于特定的密码算法或提供者。 引擎需要提供:
- 密码操作(加密,数字签名,消息摘要等)(下文红色部分)
- 发生器或密码材料的转换器(**和算法参数) (下文绿色部分)
- 对象(**库或证书)封装了密码数据,可以在更高的抽象层使用。(下文蓝色部分)
以下引擎类是可用的:
- SecureRandom:用于生成随机或伪随机数字。
- MessageDigest:用于计算指定数据的消息摘要(散列)。
- Signature:使用**初始化,这些签名用于签署数据并验证数字签
- Cipher:用**初始化,用于加密/解密数据。存在各种类型的算法:对称批量加密(例如AES),非对称加密(例如RSA)和基于密码的加密(例如PBE)。
-
Message Authentication Codes(MAC):与MessageDigests一样,它们也会生成散列值,但是首先使用**初始化以保护消息的完整性。
KeyFactory:用于将Key类型的现有不透明**转换为**规范(底层**材料的透明表示),反之亦然。
SecretKeyFactory:用于将SecretKey类型的现有不透明加***转换为**规范(底层**材料的透明表示),反之亦然。
KeyPairGenerator:用于生成一对适用于指定算法的公钥和私钥。
KeyGenerator:用于生成与指定算法一起使用的新**。
KeyAgreement:由两方或多方使用,商定和建立一个特定的**,用于特定的密码操作。
AlgorithmParameters:用于存储特定算法的参数,包括参数编码和解码。
AlgorithmParameterGenerator:用于生成适合于指定算法的一组AlgorithmParameters。
KeyStore:用于创建和管理**库。**库是**的数据库。**库中的私钥具有与其关联的证书链,用于验证相应的公钥。**库还包含来自可信实体的证书。
CertificateFactory:用于创建公钥证书和证书吊销列表(CRL)。
CertPathBuilder:用于构建证书链(也称为证书路径)。
CertPathValidator:用于验证证书链。
CertStore:用于从存储库中检索证书和CRL。
注意:生成器可以创建具有全新内容的对象,而工厂只能从现有材料(例如编码)中创建对象。
JCA 常用类简单介绍
1. Provider类
- 指定Provider类
在调用引擎类的getInstance方法来请求和实例化实现实例时,指定想要实现的所需算法的名称以及可选的Provider(或提供者类)的名称。 - 安装Providers
有两种方式安装Provider:1 在classpath的任何位置放置一个包含Provider类的zip或JAR文件;2将程序置于标准扩展目录中,则该提供程序将被视为已安装的扩展程序 - 注册Provider
静态注册:在配置文件JAVA_HOME\lib\security\java.security中注册security.provider.n=masterClassName
动态注册:调用Security类中的addProvider或insertProviderAt方法。 - Provider类方法
public String getName()
public double getVersion()
public String getInfo()
2. Security类
Security类管理已安装的提供程序和安全性属性。 它只包含静态方法,永远不会实例化。
提供了一系列API查询Provider、增加Provider、删除Provider
Provider[] arr = Security.getProviders();
3. SecureRandom随机生成器类
SecureRandom类是提供随机数生成器(RNG)功能的引擎类。 它不同于java.lang.Random类,因为它产生密码强的随机数。 如果生成器中的随机性不足,则会使保护机制变得更加容易。 在密码学中使用随机数字,例如生成加***,算法参数等等。
4. MessageDigest摘要类
MessageDigest类是一个引擎类,用于提供密码安全的消息摘要(如SHA-256或SHA-512)的功能。 加密安全的消息摘要采用任意大小的输入(一个字节数组),并生成一个固定大小的输出,称为摘要或散列。
5. Signature 签名类
Signature类是一个引擎类,旨在提供加密数字签名算法(如DSA或RSAwithMD5)的功能。 密码安全签名算法采用任意大小的输入和私钥,并生成一个相对较短(通常是固定大小)的字节串,称为签名,具有以下属性:
- 只有私钥/公钥对的所有者才能创建签名。 任何拥有公钥的人都可以在计算上不可能恢复私钥
- 鉴于与用于生成签名的私钥相对应的公钥,应该有可能验证输入的真实性和完整性。
-
签名和公钥没有透露有关私钥的任何信息。
6. Cipher 加密解密类
Cipher类提供用于加密和解密的加密密码的功能。 加密是取数据(称为明文)和**的过程,并且产生对不知道**的第三方毫无意义的数据(密文)。 解密是相反的过程:取密文和**并产生明文。
7. SealedObject 密封对象类
这个类使程序员能够用密码算法创建对象并保护其机密性。
给定任何实现了java.io.Serializable接口的对象,可以使用密码算法创建一个封装原始对象的SealedObject,以序列化格式(即“深层复制”)封装原始对象,并封装(加密)其序列化内容 如AES,以保护其机密性。 加密的内容稍后可以被解密(使用正确的解***的相应算法)并且解序列化,产生原始对象。
8. Mac 消息认证码类
HMAC是基于密码散列函数实现的MAC,是MAC的一种。 HMAC使用密码散列函数(例如SHA-256)算法 ,然后结合共享**使用。
9. Key **接口
秘钥有两种表示形式:key(不透明)和keyspecs(透明)。
- 不透明的**接口无法直接访问**材料字段,只有定义的三种方法:getAlgorithm,getFormat和getEncoded。
- 透明的**,可以以通过相应规范类中定义的某个get方法单独访问每个关键字值。 例如,DSAPrivateKeySpec定义了getX,getP,getQ和getG方法来访问私钥x以及用于计算**的DSA算法参数:素数p,次数q和基数g。 如果**存储在硬件设备上,其规格可能包含有助于识别设备**的信息。
9.1 Key 不透明秘钥接口
秘钥可以通过以下方式获得:
- KeyGenerator (生成对称秘钥)
- KeyPairGenerator(生成非对称秘钥)
- Certificate证书
- KeyStore密码库
- 转换KeySpecs(使用KeyFactory)
java.security.Key接口是所有不透明**的顶层接口。
以下是在java.security.interfaces和javax.crypto.interfaces包中扩展Key接口的接口列表:
SecretKey用于对称秘钥
PublicKey和PrivateKey接口分别用于非对称秘钥的公钥和私钥。
KeyPair类是**对(公钥和私钥)的简单持有者。
9.2 KeySpecs 透明秘钥接口
也叫**规范(**材料)接口
java.security.spec包中的**规范接口和类。
DESKeySpec是一种DES**规范。
X509EncodedKeySpec是一种公钥编码规范,它表示公钥的DER编码,根据X.509标准中规定的格式。
PKCS8EncodedKeySpec是一种私钥编码规范,以PKCS8标准中指定的格式对私钥进行DER编码。
KeySpecs实现的子类如下:
10 生成器和工厂类的区别:
10.1 生成器 **Generator
生成器用于生成一个全新的对象(秘钥)。比如KeyGenerator生成SecretKey,KeyPairGenerator生成KeyPair。
生成器一般有两种方法来生成**对
- 以独立于算法的方式
void initialize(int keysize, SecureRandom random)
void initialize(int keysize)
- 以特定于算法的方式
void initialize(AlgorithmParameterSpec params, SecureRandom random)
void initialize(AlgorithmParameterSpec params)
KeyPairGenerator类,用于生成公钥和私钥对的引擎类。
KeyGenerator类, 用于为对称算法生成**。
10.2 工厂类 **Factory
工厂类用于将数据从一个现有的对象类型转换为另一个。一个**工厂可以用来在兼容的**规范之间进行转换。
比如SecretKeyFactory和KeyFactory,可以转换keySpecs为key。比如CertificateFactory,从字节输入流(FileInputStream)转换成证书(Certificate)对象。
秘钥工厂是双向的,**工厂用于将**(java.security.Key类型的不透明**)转换为**规范(以合适的格式对基础**材料进行透明表示),反之亦然。
比如KeyFactory类和SecretKeyFactory类:
11 KeyAgreement 秘钥协商类
Diffie-Hellman算法是一种**协议,是两方或多方可以建立相同密码**而不必交换任何秘密信息的协议。
生成共享**有如下几步:
- 创建KeyAgreement对象
KeyAgreement.getInstance()
- 初始化KeyAgreement
public void init(Key key);
public void init(Key key, SecureRandom random);
public void init(Key key, AlgorithmParameterSpec params);
public void init(Key key, AlgorithmParameterSpec params, SecureRandom random);
- 执行**协商阶段
public Key doPhase(Key key, boolean lastPhase);
- 生成共享**
public byte[] generateSecret();
public int generateSecret(byte[] sharedSecret, int offset);
public SecretKey generateSecret(String algorithm);
12. 密码库KeyStore
“**库”是一种可用于管理**和证书的存储库,一个密码库包含多个私钥和证书。
- KeyStore文件:用户**库默认存储在用户主目录中名为.keystore的文件中。
- 密码库工具:keytool和jarsigner的命令行工具,以及一个名为policytool的基于GUI的工具。
- **库实现类型:
默认的keystore实现类型是“jks”,
推荐的keystore实现是“pkcs12”,
可以在java.security文件中的修改默认实现类型:
keystore.type=jks
KeyStore类
**库中有两种不同类型的条目:Key Entry(**条目)和Trusted Certificate Entry(可信任的证书条目)
KeyStore对象可以从文件中load()或store()到文件。并提供了一系列方法来操作key条目和Certificate条目。
KeyStore 一个安全的,用于存储密码和可信证书的仓库。
CertStore 用于存储不相关的,不受信的证书。同样它可以存储CRLs。
13. AlgorithmParameters和AlgorithmParameterSpecs
AlgorithmParameters:不透明的加密参数接口
AlgorithmParameterSpecs:透明的加密参数接口
AlgorithmParameters或AlgorithmParameterSpecs用于配置算法的初始化参数
AlgorithmParameterGenerator生成器,是一个引擎类,用于生成一组适用于特定算法的全新参数,提供了生成AlgorithmParameters和AlgorithmParameterSpecs的方法。
14. CertificateFactory类
CertificateFactory类是定义证书工厂功能的引擎类,用于从其编码(文件流)生成证书和证书吊销列表(CRL)对象。
15. JCA如何在SSL / TLS实现中使用
- 使用KeyManager(**库)和TrustManagerSSLContext(信任度)初始化SSLContext
- 使用上下文SSLContext,创建实际实现SSL / TLS协议的对象(SSLSocket和SSLEngine)。
- SSLSocket和SSLEngine将直接在通信对象中使用。
KeyManager和TrustManager作用:
- JSSE KeyManager负责向对等端显示使用的凭证(使用的密码标准、加密算法、证书、公钥、签名等)
- JSSE TrustManager负责验证从对等端收到的凭证,验证凭证有多种方式:其中之一是创建CertPath对象,并让JDK的内置公钥基础结构(PKI)框架处理验证。 在内部,CertPath实现可能会创建一个Signature对象,并使用它来验证证书链中的每个签名。