AES加解密

密钥是AES算法实现加密和解密的根本。对称加密算法之所以对称,是因为这类算法对明文的加密和解密需要使用同一个密钥。

AES支持三种长度的密钥: 128位,192位,256位

平时大家所说的AES128AES192AES256,实际上就是指AES算法对不同长度密钥的使用。

三种密钥的区别:

从安全性来看,AES256安全性最高。从性能看,AES128性能最高。本质原因是它们的加密处理轮数不同。

AES原理:AES是对数据按128位,也就是16个字节进行分组进行加密的,每次对一组数据加密需要运行多轮,而输入密钥的长度可以为128、192和256位,也就是16个字节、24个字节和32个字节,如果用户输入的密钥长度不是这几种长度,也会补成这几种长度。

  无论输入密钥是多少字节,加密还是以16字节的数据一组来进行的,密钥长度的不同仅仅影响加密运行的轮数。

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;


public class TestController {
    public static void main(String[] args) {
        try {
            //根据指定字符串生成秘钥
            KeyGenerator kg = KeyGenerator.getInstance("AES");
            kg.init(128,new SecureRandom("ceshi".getBytes()));
            SecretKey sk = kg.generateKey();
            String keyStr = Base64.getEncoder().encodeToString(sk.getEncoded());

            byte[] iv = Base64.getDecoder().decode(keyStr);
            byte[] key = Base64.getDecoder().decode(keyStr);
            String content = "测试";

            String encrypted = Base64.getEncoder().encodeToString(encrypt(iv, key, content.getBytes()));
            System.out.println("加密后: " + encrypted);

            String raw = new String(decrypt(iv, key, Base64.getDecoder().decode(encrypted)));
            System.out.println("解密后: " + raw);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    public static byte[] encrypt(byte[] iv, byte[] key, byte[] raw) {

        try {
            SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//"算法/模式/补码方式"
            IvParameterSpec ips = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ips);
            return cipher.doFinal(raw);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static byte[] decrypt(byte[] iv, byte[] key, byte[] encryptContent) {

        try {
            SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec ips = new IvParameterSpec(iv);
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, ips);
            return cipher.doFinal(encryptContent);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

填充模式:

PKCS1Padding:PKCS#1(v1.5)中规定当RSA的密钥长度是1024b,如果使用PKCS1Padding填充,则原文数据最多117B。如果原文不满足长度要求,则在加密前需要进行填充。

PKCS5Padding:PKCS#5填充是将数据填充到8的倍数,填充后数据长度的计算公式是 定于元数据长度为x, 填充后的长度是 x + (8 - (x % 8)), 填充的数据是 8 - (x % 8),块大小固定为8字节

PKCS7Padding:假设数据长度需要填充n(n>0)个字节才对齐,那么填充n个字节,每个字节都是n;如果数据本身就已经对齐了,则填充一块长度为块大小的数据,每个字节都是块大小;PKCS5只填充到8字节,而PKCS7可以在1-255之间任意填充。

ZeroPadding:数据长度不对齐时使用0填充,否则不填充。

NoPadding:待补充