java jce-Cipher(加密、解密)
在开发时,总要涉及到数据的加密与解密,之前一直有些糊涂,最近看了 jce.jar的源码,来整理记录一下
1、概念
JCA(Java Cryptography Architecture)
: Java密码体系结构
JCE(Java Cryptography Extension)
:它是一组包,提供用于加密、密钥生成和协商以及 Message Authentication Code(MAC)算法的框架和实现。它提供了对称、不对称、块和流密码的加密支持,并且还支持安全流和密封的对象,不对外出口,开发完成封装后将无法调用。
在早期JDK版本中,由于受美国的密码出口条例约束,Java中涉及加解密功能的API被限制出口,所以Java中安全组件被分成了两部分: 不含加密功能的JCA(Java Cryptography Architecture )和含加密功能的JCE(Java Cryptography Extension)。
在JDK1.1-1.3版本期间,JCE属于扩展包,仅供美国和加拿大的用户下载,JDK1.4+版本后,JCE已经捆绑在JDK中,即jdk中的 jce.jar 包
1.1 加密算法
数据加密的基本过程就是对原来为明文的
文件 或 数据
按某种
算法
进行处理,使其成为不可读的一段代码为“密文”,使其只能在输入相应的 密钥 之后才能显示出原容,通过这样的途径来达到保护数据不被非法人窃取、阅读的目的,常见的加密算法,分为对称加密与非对称加密
1.1.1 对称式加密技术
加密和解密使用
同一个密钥
,通常称之为“Session Key ” ,如美国政府所采用的
DES
加密标准就是一种典型的
对称式加密法
,它的Session Key长度为56bits
1.1.2 非对称式加密技术
加密和解密所使用的
不是同一个密钥
,通常有两个密钥,称为**“公钥”
和
“私钥”
,它们两个必需
配对使用**,否则
不能打开加密文件
“公钥”是指可以对外公布的,“私钥”则不能
,只能由持有人一个人知道。它的优越性就在这里,因为对称式的加密方法如果是在网络上传输加密文件就很难不把密钥告诉对方,不管用什么方法都有可能被别人窃听到。而非对称式的加密方法有两个密钥,且其中的“公钥”是可以公开的,也就不怕别人知道,收件人解密时只要用自己的私钥即可以,这样就很好地
避免了密钥的传输安全性问题
1.1.3 常用的加密算法
算法名称 | 密钥长 | 块长 | 速度 | 说明 | 类型 |
---|---|---|---|---|---|
DES | 56 | 64 | 较快 | 适用于加密大量数据,不太安全 | 对称加密 |
3DES | 112/168 | 64 | 较慢 | 中等安全, 适合加密较小的数据 | 对称加密 |
AES | 128, 192, 256 | 128 | 快 | 安全 | 对称加密 |
Blowfish | (4至56)*8 | 64 | 快 | 应该安全, 在安全界尚未被充分分析、论证 | 对称加密 |
RC4 | 40-1024 | 64 | 很快 | 安全性不明确,变长密钥对大量数据进行加密 | 对称加密 |
RSA | 500-1024 | 很慢 | 512位被视为不安全的;768位不用担心受到危害;1024位几乎是安全的,用于少量数据加密 | 飞对称加密 | |
MD5 | 128 | 32 | 快 | 普遍、稳定广泛应用于普通数据,不可逆 | 散列算法 |
SHA1 | 160 | 快 | 安全散列算法,但安全性如今被密码学家严重质疑 | 散列算法 |
总结:
- 非对称加密普遍会比对称加密慢,取决于密码长度(长度长计算复杂度大)
- 非对称加密普遍使用RSA,对称加密普遍使用AES
- 对称加密的密钥管理较为重要,需要保证传输的安全性
- 散列算法的安全性不高,有被破解的可能
2、核心类与核心方法
以jdk 1.8 为例进行下面的说明
jce.jar 包的核心API都在
javax.crypto
包下,主要包括:加解密、密钥生成(对称)、MAC生成、密钥协商等核心功能
核心的一些类/接口如下:
- Cipher
- KeyGenerator
- SecretKeyFactory
这篇主要介绍Cipher,其他的会单独写一些博客来记录一下
Cipher
加解密功能在该类实现,是JCE中最核心的类
-
加密:是获取数据(称为
明文
)和
密钥
,并生成对不知道密钥的第三方无意义的数据(
密文)的过程
- 解密:加密逆过程,获取密文和密钥并生成明文
主要由以下方法:
- getInstance:创建一个Cipher对象
- init:Cipher对象初始化
- update:执行加密或解密数据(多步骤)如果事先不知道数据的长度,或者数据太长,无法一次存储在内存中,则使用该操作
- doFinal:执行加密或解密数据(单步骤)
下面详细说明:
1 getInstance:创建一个Cipher对象
根据以下三种重载方法获取到一个Cipher对象
// var0 是 transformation
public static final Cipher getInstance(String var0) throws NoSuchAlgorithmException, NoSuchPaddingException {
}
// var1 是具体的 provider name java.security.Security根据name获取Prvider
public static final Cipher getInstance(String var0, String var1) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException {
}
// var1 是具体的provider
public static final Cipher getInstance(String var0, Provider var1) throws NoSuchAlgorithmException, NoSuchPaddingException {
}
说明:
1)transformatior有以下两种形式: 具体细节与详情可查看
Java密体系结构标准算法文档
,算法 algorithm必填,缺省的mode为
ECB
,缺省的padding为
PKCS5Padding
-
“
algorithm/mode/padding
” example:“AES/CBC/PKCS5Padding” -
“
algorithm
” example:“AES”
algorithm取值:
- AES / AESWrap
- ARCFOUR
- Blowfish
- RC2 / RC4 / RC5
- RSA
- DES / DESede / DESedeWrap / ECIES
mode取值:具体可查看
加密模式介绍(ECB、CBC、PCBC、CFB、OFB、CTR)
- NONE
- CBC
- CCM
- CFB, CFBx
- CTR / CTS
- ECB
- GCM
- OFB, OFBx
- PCBC
padding取值:(分组算法的时候若数据不是块的整数倍,需要进行填充)具体可查看
分组加密中的填充介绍
- NoPadding
- ISO10126Padding
- OAEPPadding / OAEPWithAndPadding
- PKCS1Padding / PKCS5Padding
- SSL3Padding
2 init:Cipher对象初始化
根据以下几种重载方法进行Cipher对象初始化
// opmode 操作模式,有四种
// key 密钥,Key 的子类很多,根据具体的加密算法来选择合适的密钥
public void init(int opmode, Key key);
// certificate 身份(一个主体对另一个主体证明的公钥的绑定)
public void init(int opmode, Certificate certificate);
// random 加密强随机数
public void init(int opmode, Key key, SecureRandom random);
public void init(int opmode, Certificate certificate,
SecureRandom random);
// params 加密参数规范 用于加密的参数必须用于解密
public void init(int opmode, Key key,
AlgorithmParameterSpec params);
public void init(int opmode, Key key,
AlgorithmParameterSpec params, SecureRandom random);
public void init(int opmode, Key key,
AlgorithmParameters params);
public void init(int opmode, Key key,
AlgorithmParameters params, SecureRandom random);
Cipher有4种操作模式(即var1有四种取值):
- ENCRYPT_MODE:加密
- DECRYPT_MODE:解密
- WRAP_MODE:将key包装成字节,以便可以安全地传输密钥,导出Key
- UNWRAP_MODE:将以前包装的密钥解包到key中,导入Key
3 update:执行加密或解密数据(多步骤)
根据以下四种重载方法执行加密/解密,一般用于不知道数据的长度,用该操作
// input:加密数据,返回处理后的byte数组
public byte[] update(byte[] input);
// inputOffset:数据开始位置
// inputLen:数据加密长度 返回处理后的byte数组
public byte[] update(byte[] input, int inputOffset, int inputLen);
// output:处理后的数据存储,返回是否成功(0/1)
public int update(byte[] input, int inputOffset, int inputLen,
byte[] output);
// output:处理后的数据存储
// outputOffset :处理后的数据存储起始位置,返回是否成功(0/1)
public int update(byte[] input, int inputOffset, int inputLen,
byte[] output, int outputOffset)
4 doFinal:执行加密或解密数据(单步骤)
根据以下四种重载方法执行加密/解密
// input:加密数据,返回处理后的byte数组
public byte[] doFinal(byte[] input);
// inputOffset:数据开始位置
// inputLen:数据加密长度 返回处理后的byte数组
public byte[] doFinal(byte[] input, int inputOffset, int inputLen);
// output:处理后的数据存储,返回是否成功(0/1)
public int doFinal(byte[] input, int inputOffset,
int inputLen, byte[] output);
// output:处理后的数据存储
// outputOffset :处理后的数据存储起始位置,返回是否成功(0/1)
public int doFinal(byte[] input, int inputOffset,
int inputLen, byte[] output, int outputOffset)
5 举例
使用流程:
- 创建Cipher对象
- 初始化(指明具体操作)
- 加密/解密
加密 example:
// 用于加强的seed
private static String strKey = "diaxxxxoft@201Y10";
// 获取密钥key
private static Key getKey(String strKey) throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128 ,new SecureRandom(strKey.getBytes()));
SecretKey secretKey = keyGenerator.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
return new SecretKeySpec(enCodeFormat, "AES");
}
/**
* 根据密钥{@link #getKey()}对指定的明文 plainText进行加密.
*
* @param plainText 明文
* @return 加密后的密文.
*/
public static void encryptData(String plaintext) {
System.out.println("-------Encrypting data using AES algorithm-------");
try {
byte[] plaintTextByteArray = plaintext.getBytes("UTF8");
// 定义
Cipher cipher = Cipher.getInstance("AES");
// 初始化
cipher.init(Cipher.ENCRYPT_MODE, getKey(strKey));
// 加密
byte[] cipherText = cipher.doFinal(plaintTextByteArray);
System.out.println("Original data: " + plaintext);
System.out.println("Encrypted data:");
for (int i = 0; i < cipherText.length; i++) {
System.out.print(cipherText[i] + " ");
}
// BASE64Encoder encoder = new BASE64Encoder();
// String encoded = encoder.encode(cipherText);
// decryptData(encoded);
}catch(Exception ex){
ex.printStackTrace();
}
}
输出:
Original data: mlpan@019
Encrypted data:
96 -82 -108 -12 31 54 -24 69 94 -80 52 -93 -3 121 77 62
解密 example:
public static void decryptData(String cipherText) {
System.out.println();
System.out.println("-------Decrypting data using AES algorithm-------");
try {
BASE64Decoder decoder = new BASE64Decoder();
byte[] c = decoder.decodeBuffer(cipherText);
System.out.println("Encrypted data:" + cipherText);
// 创建
Cipher cipher = Cipher.getInstance("AES");
// 初始化
cipher.init(Cipher.DECRYPT_MODE, getKey(strKey));
// 解密
byte[] bytes = cipher.doFinal(c);
System.out.println("Original data: " + new String(bytes));
} catch (Exception ex) {
ex.printStackTrace();
}
}
输出:
Encrypted data:nEgCrS0YxLzCO+TO8ZO4ng==
Original data: mlpan@019
相关链接
1、JCA