Java 实现 AES/CBC/PKCS7Padding 对称加密算法

AES,高级加密标准(英语:Advanced Encryption Standard,缩写:AES)

在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。严格地说,AES 和 Rijndael加密法并不完全一样(虽然在实际应用中二者可以互换),因为Rijndael加密法可以支持更大范围的区块和密钥长度:AES的区块长度固定为128 比特,密钥长度则可以是128,192或256比特;而Rijndael使用的密钥和区块长度可以是32位的整数倍,以128位为下限,256比特为上限。包括AES-ECB,AES-CBC,AES-CTR,AES-OFB,AES-CFB

AES 加密实现(ECB)

AES-ECB 加密模式实现

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

/**
 * AES 加密
 */
public final class AESCoder2 {
    public static final String ALGORITHM = "AES";

    /**
     * 加密
     */
    public static byte[] encrypt(byte[] data, String key) throws Exception {
        SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        return cipher.doFinal(data);
    }

    /**
     * 加密+Base64
     */
    public static String encryptString(byte[] data, String key) throws Exception {
        SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] bytes = cipher.doFinal(data);
        return Base64Utils.encode(bytes);
    }

    /**
     * 解密
     */
    public static byte[] decrypt(byte[] data, String key) throws Exception {
        SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        return cipher.doFinal(data);
    }

    /**
     * 解密 + Base64
     */
    public static String decryptString(byte[] data, String key) throws Exception {
        SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] bytes = cipher.doFinal(data);
        return new String(bytes, "UTF-8");
    }

    public static void main(String[] args) throws Exception {
        String key = "A3EAC779D508B83583C3C2DB906E8CFA";
        String data = "八百里逐日听风,抖音账号:Lrk1056";

//        byte[] encrypt = encrypt(data.getBytes(StandardCharsets.UTF_8), key);
//        System.out.println("encrypt = " + new String(encrypt, StandardCharsets.UTF_8));
//        byte[] decrypt = decrypt(encrypt, key);
//        System.out.println("decrypt = " + new String(decrypt));

        String encrypt = encryptString(data.getBytes(StandardCharsets.UTF_8), key);
        System.out.println("encrypt = " + encrypt);
        String decrypt = decryptString(Base64Utils.decode(encrypt), key);
        System.out.println("decrypt = " + decrypt);
    }
}

加密结果

encrypt = N3CXWqUZOXV8/lBG3ZRjgfOgGTaKNFjk7e8qvEafsM4Lwz0HLnFE3PhAlvMasheB

decrypt = 八百里逐日听风,抖音账号:Lrk1056

iShot2021-05-08 10.19.22.jpg

AES 加密实现(CBC/PKCS7Padding)

这里使用 CBC 模式,PKCS7Padding 填充方式实现,首先需要导入三方包依赖(java自带的是PKCS5Padding填充,不支持PKCS7Padding填充),否者会出现异常情况。

java.security.NoSuchAlgorithmException:Cannot find any provider supporting AES/CBC/PKCS7Padding

解决办法:添加静态代码块,通过BouncyCastle组件来让java里面支持PKCS7Padding填充。

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Security;

/**
 * AES 加密 CBC 模式
 */
public final class AESCoder {

    /**
     * 算法/模式/补码方式
     */
    public static final String AES_CBC_PKCS7 = "AES/CBC/PKCS7Padding";

    /**
     * 解决java不支持AES/CBC/PKCS7Padding模式解密
     */
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 加密 + Base64
     *
     * @param iv 初始向量
     */
    public static String encryptString(byte[] data, String key, String iv) throws Exception {
        SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), AES_CBC_PKCS7);
        Cipher cipher = Cipher.getInstance(AES_CBC_PKCS7);
        // CBC模式,需要向量iv,增加算法强度
        IvParameterSpec spec = new IvParameterSpec(iv.getBytes());
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, spec);
        byte[] bytes = cipher.doFinal(data);
        return Base64Utils.encode(bytes);
    }

    /**
     * 解密 + Base64
     *
     * @param iv 初始向量
     */
    public static String decryptString(byte[] data, String key, String iv) throws Exception {
        SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), AES_CBC_PKCS7);
        Cipher cipher = Cipher.getInstance(AES_CBC_PKCS7);
        IvParameterSpec spec = new IvParameterSpec(iv.getBytes());
        cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);
        byte[] bytes = cipher.doFinal(data);
        return new String(bytes, "UTF-8");
    }

    public static void main(String[] args) throws Exception {
        String key = "A3EAC779D508B83583C3C2DB906E8CFA";
        String data = "八百里逐日听风,抖音账号:Lrk1056";
        String iv = "023a0cee22cecabe";

        String encrypt = encryptString(data.getBytes(StandardCharsets.UTF_8), key, iv);
        System.out.println("encrypt = " + encrypt);
        String decrypt = decryptString(Base64Utils.decode(encrypt), key, iv);
        System.out.println("decrypt = " + decrypt);
    }
}

加密结果

encrypt = cQF/KoEE/B34BRcRSClq0WmyDi4AxJItCvzRxexj/VTO6khBFQOarZpem8r0/uUR

decrypt = 八百里逐日听风,抖音账号:Lrk1056

iShot2021-05-08 10.28.18.png

相关阅读

DES/3DES/AES 三种对称加密算法在 Java 中的实现:http://www.ibloger.net/article/1980.html

漫画:什么是AES算法:http://www.ibloger.net/article/2785.html 

漫画:AES算法的底层原理:http://www.ibloger.net/article/2786.html 


未经允许请勿转载:程序喵 » Java 实现 AES/CBC/PKCS7Padding 对称加密算法

点  赞 (2) 打  赏
分享到: