天天看點

AES加密解密的Java(調用javax.crypto庫)實作

原理不難,但是要清楚自己用的什麼加密模式,本文用的CBC模式。

看CSDN的估計也沒人去糾結原理,直接上代碼。

package AES;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.UUID;

/**
 * 本文中使用AES的最大秘鑰,32位元組=256位
 */
public class AES {
    /**
     * 生成秘鑰,傳回BASE64 處理之後的密鑰字元串
     */
    public static String generateAESKey(){
        UUID uuid = UUID.randomUUID();
        String aesKey = Base64.getEncoder().encodeToString(uuid.toString().getBytes()).substring(2,34);
        return aesKey;
    }
    /**
     * 獲得一個初始化向量,傳回長度為16位元組大小的BASE64編碼字元串
     * 至于為何要這個iv向量,因為本文使用的是CBC模式
     */
    public static String generateAESIv(){
        UUID uuid = UUID.randomUUID();
        String iv = Base64.getEncoder().encodeToString(uuid.toString().getBytes()).substring(2,18);
        return iv;
    }
    /**
     * 加密
     * @param content 待加密内容
     * @param secretKeyStr 加密使用的 AES 密鑰,BASE64 編碼後的字元串
     * @param iv 初始化向量,長度為 16 個位元組
     * @return 加密後的密文,進行 BASE64 處理之後傳回
     */
    public static String encryptAES(byte[] content, String secretKeyStr, String iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
        // 獲得一個加密規則 SecretKeySpec
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyStr.getBytes(), "AES");
        // 獲得加密算法執行個體對象 Cipher
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //"算法/模式/補碼方式"
        // 獲得一個 IvParameterSpec
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());  // 使用 CBC 模式,需要一個向量 iv, 可增加加密算法的強度
        // 根據參數初始化算法
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);

        // 執行加密并傳回經 BASE64 處助理之後的密文
        return Base64.getEncoder().encodeToString(cipher.doFinal(content));
    }

    /**
     * 解密
     * @param content: 待解密内容,是 BASE64 編碼後的位元組數組
     * @param secretKeyStr: 解密使用的 AES 密鑰,BASE64 編碼後的字元串
     * @param iv: 初始化向量,長度 16 位元組,16*8 = 128 位
     * @return 解密後的明文,直接傳回經 UTF-8 編碼轉換後的明文
     */
    public static String decryptAES(byte[] content, String secretKeyStr, String iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, UnsupportedEncodingException {
        // 密文進行 BASE64 解密處理
        byte[] contentDecByBase64 = Base64.getDecoder().decode(content);
        // 獲得一個 SecretKeySpec
        // SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(secretKeyStr), "AES");
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyStr.getBytes(), "AES");
        // 獲得加密算法執行個體對象 Cipher
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //"算法/模式/補碼方式"
        // 獲得一個初始化 IvParameterSpec
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
        // 根據參數初始化算法
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
        // 解密
        return new String(cipher.doFinal(contentDecByBase64), "utf8");
    }


    public static void main(String[] args) throws NoSuchPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
        //原文
        String context = "當我們建立一個node項目,意味着建立一個module子產品,這個子產品的描述檔案,叫package.json。";
        //秘鑰
        String key  = generateAESKey();
        //向量
        String iv = generateAESIv();
        //加密
        String encryptContext = encryptAES(context.getBytes(),key,iv);
        //解密
        String decryptContext = decryptAES(encryptContext.getBytes(),key,iv);

        System.out.println("原文:"+context);
        System.out.println("密文:"+encryptContext);
        System.out.println("解密文:"+decryptContext);
    }


}

           

測試結果:注意,秘鑰以及向量每次都是随機的,是以加密後的密文每次都會不一樣。然後就産生了秘鑰保管的問題。

AES加密解密的Java(調用javax.crypto庫)實作