在Java的知识体系中,Java平台安全是很重要的一部分。作为Android开发者,其实这部分知识对我们来说既陌生又熟悉。说熟悉,Android中Apk打包离不开的jks签名文件,Android 6.0提供的指纹识别接口的调用(Demo), 都是建立在Android平台安全的体系上。而Android平台安全又是建立在Java平台安全的这个坚实的基础上。说陌生,对于Java密码学架构(Java Cryptography Architecture 简称JCA)的还挺陌生,该系列文章分为上下两部分,这一篇主要聊聊JCA的基础知识,可能有些枯燥,在下篇,我会结合具体代码,完成一次简单的字符串缓存加密和解密。
JCA的基本介绍
先看来自《Java Cryptography Architecture
(JCA) Reference Guide》的一段背景介绍:
Java平台重视安全性,包括语言安全性,密码学,公钥基础设施,身份验证,安全通行和访问控制。
JCA是JDk平台上非常重要的部分,通过包含一个 “provider”架构,设计了一套API为包括 数字签名、消息摘要、证书和证书验证、加密(对称和非对称,分组和流式密码)、秘钥生成和管理、安全随机码生成等功能服务。
可以看出,JCA是Java平台安全的基础,其它相关的还有Java密码学拓展(Java Cryptography Extension 简称JCE)、Java Secure Socket Extension (JSSE) 、Java Generic Security Services (JGSS)。
JCA的设计原则
JCA在设计之初就遵循一些基本原则,也就是
- 实现的独立性和互操作性
- 算法的独立性和可扩展性
应用无需实现具体的安全算法,或者说应用请求来自Java平台的安全服务。这些安全服务在“providers”(下面会介绍)中实现,这些providers可以互相协作,与应用之间没有必然的绑定限制。Java平台提供了现成的实现算法的providers,应用也可以通过自定义providers来实现特殊的算法。
JCA的架构
Cryptographic Service Providers CSP 密码服务提供者
刚才在设计原则那部分,反复提到了“providers”,那providers到底是个什么东西呢? JCA文档是这么介绍的:
a package or set of packages that supply a concrete implementation of a subset of the JDK Security API cryptography features
一个包或包结合,提供JDK安全API密码特性的具体实现
这么看还是很抽象,首先要了解java.security.Provider,这个抽象类是所有安全提供者的基础类。每一个CSP,也就是我们的密码服务提供者,都包含java.security.Provider类的一个实例,这个实例包含了“providers”的名称和所有实现的安全服务/算法的列表,当我们需要某种算法时,JCA框架就会去查询这个“providers”数据库,找到匹配的实例并创建它。
1 | public abstract class Provider extends Properties { |
引用下JCA文档中的这张图:
配合这张图就很清晰了,我们开发者处于应用层,JCA框架层对应用层只提供接口,具体的实现逻辑被封装起来。
1 | //我们仅需通过具体的Engine class并提供需要的算法名称“MD5”,我们就可以获得一个provider实现的消息摘要实例 |
Key Management 秘钥的管理
KeyStore是一个数据库,它可以被用于管理秘钥和证书的仓库。秘钥可用于应用的的数据验证,加密或签名。Sun Microsystems提供了默认的KeyStore实现。它将秘钥实现为一个文件,使用专有的秘钥类型(格式)叫“jks”.其他的秘钥格式如”jceks”(一种比jks加密强度更大的秘钥库格式)、”pkcs12”等。Android开发者应该很熟悉jks,打包生成apk的时候,我们就会用到jkd格式的秘钥。
例如,Android系统提供了默认的KeyStore,可以通过名称“AndroidKeyStore”来获取
1 |
|
Engine Classes and Algorithms 引擎类和算法
例如上文MessageDigest就是一类引擎类,1.4会介绍一些常用的引擎类,这里就不多做介绍了。
JCA的核心类和接口
看到这,想必大家对Providers,KeyStore,引擎类, 算法这些概念有了一些基础的认知。先放松一下,看一下gakki的笑容,放松一下。
骚年,我们继续。从API这个角度入手,了解一下JCA框架有哪些基础的类。了解之后,才方便我们后面的实战部分。
JCA的类大致可以分为以下几种:
- Provider and Security 类
- 各种Engine类,如SecureRandom, MessageDigest, Signature, Cipher, Mac, KeyFactory, SecretKeyFactory, KeyPairGenerator, KeyGenerator, KeyAgreement, AlgorithmParameters, AlgorithmParameterGenerator , KeyStore, and CertificateFactory
- Key 接口和类
- 算法参数规格接口和类(the Algorithm Parameter Specification Interfaces and Classes)
秘钥规格接口和类(the Key Specification Interfaces and Classes) - 多种支持和便利接口和类
Key
首先了解一下秘钥,对应的定义是java.security.Key,是所有opaque keys的顶层接口,所谓opaque keys,也就是无法直接访问到构成key的材料,也就是说opaque keys给予了访问限制。只能通过getAlgorithm()、getFormat()、getEncoded()这些方法来获取到秘钥指定的信息。
1 | public interface Key extends java.io.Serializable { |
KeyStore
用于创建和管理秘钥库, KeyStore是秘钥的数据库。秘钥库中的私有秘钥有与之相关的证书链,用于验证相关联的公有密钥。秘钥库也包含来自受信任实体的证书。上文有介绍,这里就不多说了。
KeyGenerator
通过使用特殊算法来生成秘钥,如果希望生成非对称秘钥,请使用KeyPairGenerator
初始化:有两种初始化方式:
- 算法无关
1 | public void init(SecureRandom random); |
- 算法相关
1 | public void init(AlgorithmParameterSpec params); |
生成秘钥
1 | public SecretKey generateKey(); |
AlgorithmParameterSpec
算法参数,看源码可知只是个接口,具体的实现如KeyGenParameterSpec
1 | package java.security.spec; |
KeyGenParameterSpec
参数很多,显然也是通过构建者模式进行的初始化,构建者AlgorithmParameterSpec.Builder,重要的参数有
秘钥别名,秘钥目的,block modes、EncryptionPadding等
PurposeEnum
秘钥目的:加密、解密、签名、验证
1 | public PurposeEnum {} |
下面介绍几个Engine class
Cipher
用于数据的加密和解密,通过秘钥初始化。有几种不同的算法:如 对称加密协议 symmetric bulk encryption(AES, DES, DESede, Blowfish, IDEA),流式加密 stream encryption(RC4等), 非对称加密 asymmetric encryption(RSA等), 密码基础的加密 password-based encryption(PBE)
signature
提供用于密码数字签名算法(如DSA或RSAwithMD5)的功能
MessageDigest
提供密码信息摘要(如SHA-1或MD5)的功能,接受任意直接长度的输入(byte[]格式),生成
固定长度的输出(称为digest或hash)
Mac
Message Authentication Code的缩写,与MessageDigest类似, 用于检测信息的完整性以及在不可靠媒介上存储(包含一个secret key,持有正确key的人能够验证已接收的信息)
** 参考资料 **