A-A+

JAVA AES算法

2021年04月11日 00:00 汪洋大海 暂无评论 共3233字 (阅读178 views次)

.前言

AES(Advanced Encryption Standard),高级加密标准,是美国政府用于替换DES的一种加密算法标准,Java SDK中包含了部分AES的实现,但javadoc对于算法的描述非常少,本文将解释Java AES实现的使用和原理。

.示例代码

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AesECB {
    public static byte[] Encrypt(byte[] text, byte[] key) throws Exception {
        SecretKeySpec aesKey = new SecretKeySpec(key, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); // default, same as "AES"
        // Cipher cipher = Cipher.getInstance("AES"); // same as above
        cipher.init(Cipher.ENCRYPT_MODE, aesKey);
        return cipher.doFinal(text);
    }
    public static byte[] Decrypt(byte[] text, byte[] key) throws Exception {
        SecretKeySpec aesKey = new SecretKeySpec(key, "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, aesKey);
        return cipher.doFinal(text);
    }
    public static String bytes2hex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String temp = (Integer.toHexString(bytes[i] & 0XFF));
            if (temp.length() == 1) {
                temp = "0" + temp;
            }
            sb.append(temp);
            sb.append(" ");
        }
        return sb.toString().toUpperCase();
    }
    public static void main(String[] args) {
        try {
            String key = args[0];
            String text = args[1];
            System.out.printf("text   : %s\n", bytes2hex(text.getBytes()));
            byte[] enc = AesECB.Encrypt(text.getBytes(), key.getBytes());
            System.out.printf("encrypt: %s\n", bytes2hex(enc));
            byte[] dec =  AesECB.Decrypt(enc, key.getBytes());
            System.out.printf("decrypt: %s\n", bytes2hex(dec));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

.代码分析

JDK AES加密主要是几个步骤:

1.key变换

将传入的明文key做变换,AES的key固定为128bit,但变换后的key为加密位数的一倍,128bit的加密变换后key为256bit。注意加密和解密的key变换不一样。

2.加密解密

选择加密的模式和补齐填充方法生成加密实例,加密得到密文。

.密码块工作模式

块密码工作模式(Block cipher mode of operation),是对于按块处理密码的加密方式的一种扩充,不仅仅适用于AES,包括DES, RSA等加密方法同样适用。

名称 英文 全名 方法 优点 缺点
ECB Electronic codebook 电子密码本 每块独立加密 1.分块可以并行处理 1.同样的原文得到相同的密文,容易被攻击
CBC Cipher-block chaining 密码分组链接 每块加密依赖于前一块的密文 1.同样的原文得到不同的密文
2.原文微小改动影响后面全部密文
1.加密需要串行处理
2.误差传递
PCBC Propagating cipher-block chaining 填充密码块链接 CBC的扩种,较少使用 1.同样的原文得到不同的密文
2.互换两个邻接的密文块不会对后续块的解密造成影响
1.加密需要串行处理
CFB Cipher feedback 密文反馈
OFB Output feedback 输出反馈模式 加密后密文与原文异或XOR 1.能够对密文进行校验
CTR Counter mode 计数器模式 增加一个序列函数对所有密文快做XOR

.填充

填充(Padding),是对需要按块处理的数据,当数据长度不符合块处理需求时,按照一定方法填充满块长的一种规则。

名称 方法 示例
Zero padding 最常见的方式,全填充0x00 AA AA AA AA 00 00 00 00
ANSI X.923 Zero的改进,最后一个字节为填充字节个数 AA AA AA AA 00 00 00 04
ISO 10126 随机填充 AA AA AA AA 81 A6 23 04
PKCS7 ANSI X.923的变体
填充1个字符就全0x01
填充2个字符就全0x02
不需要填充就增加一个块,填充块长度,块长为8就填充0x08,块长为16就填充0x10
AA AA AA AA AA AA AA 01
AA AA AA AA 04 04 04 04
AA AA AA AA AA AA AA AA 08 08 08 08 08 08 08 08
ISO/IEC 7816-4 以0x80开始作为填充开始标记,后续全填充0x00 AA AA AA AA AA AA AA 80
AA AA AA AA 80 00 00 00

.JDK AES实现

1.实现支持

AES理论上支持128,192,256三种长度的密钥,几乎全部密码块工作模式和填充方法,但JDK 7中只实现如下四种AES加密算法:

(1)AES/CBC/NoPadding (128)
(2)AES/CBC/PKCS5Padding (128)
(3)AES/ECB/NoPadding (128)
(4)AES/ECB/PKCS5Padding (128)

2.使用须知

(1)缺省模式和填充为“AES/ECB/PKCS5Padding”,Cipher.getInstance(“AES”)与Cipher.getInstance(“AES/ECB/PKCS5Padding”)等效。

(2)JDK的PKCS5Padding实际是上述的PKCS7的实现。

(3)由于AES是按照16Byte为块进行处理,对于NoPadding而言,如果需要加密的原文长度不是16Byte的倍数,将无法处理抛出异常,其实是由用户自己选择Padding的算法。密文则必然是16Byte的倍数,否则密文肯定异常。

(4)如果加密为PKCS5Padding,解密可以选择NoPadding,也能解密成功,内容为原文加上PKCS5Padding之后的结果。

(5)如果原文最后一个字符为>=0x00&&<=0x10的内容,PKCS5Padding的解密将会出现异常,要么是符合PKCS5Padding,最后的内容被删除,要么不符合,则解密失败抛出异常。对此有两种思路,一是原文通过Base64编码为可见字符,二是原文自带长度使用NoPadding解密。

.参考

(1)AES(Wiki)
(2)Block cipher mode of operation(Wiki)
(3)块密码的工作模式(Wiki)
(4)Padding(Wiki)
(5)PKCS(Wiki)
(6)JAVA 7 Cipher

文章来源:https://blog.51cto.com/qiaofengzxq/1748687

布施恩德可便相知重

微信扫一扫打赏

支付宝扫一扫打赏

×

给我留言