AES加解密以及源碼分析

AES加解密簡單實現

    //密鑰
    private static String secretKey = "12345678123456781234567812345678";

    //加密串字符編碼方式
    private static String charset = "utf8";

    //偏移量
    private static int offset = 16;

    //算法(AES)、工作模式(CBC)、填充方式(PKCS5Padding)
    private static String transformation = "AES/CBC/PKCS5Padding";

    //算法
    private static String algorithm = "AES";

    /**
     *@desc: 加密
     *
     *@date: 10:19
    */
    public static String encrypt(String content){
        return encrypt(content,secretKey);
    }

    /**
     *@desc: 解密
     *
     *@date: 10:18
    */
    public static String decrypt(String content){
        return decrypt(content,secretKey);
    }

    /**
     *@desc: 帶密鑰加密
     *
     *@date: 10:19
    */
    public static String encrypt(String content,String secretKey){

        try {
            Cipher cipher = getCipher(Cipher.ENCRYPT_MODE,secretKey);
            byte[] bytes = content.getBytes(charset);
            byte[] res = cipher.doFinal(bytes);
            return Base64.getEncoder().encodeToString(res);
        } catch (Exception e) {
            log.error("AES encrypt failed!reason:{}",e);
        }
        return null;
    }

    /**
     *@desc: 帶密鑰解密
     *
     *@date: 10:20
    */
    public static String decrypt(String content,String secretKey){
        try {
            Cipher cipher = getCipher(Cipher.DECRYPT_MODE,secretKey);
            byte[] res = cipher.doFinal(Base64.getDecoder().decode(content));
            return new String(res);
        } catch (Exception e) {
            log.error("AES decrypt failed!reason:{}",e);
        }
        return null;
}

    /**
     *@desc: 獲取Cipher密碼管理器
     *
     *@date: 11:04
    */
    public static Cipher getCipher(int type,String secretKey) throws Exception {
        SecretKeySpec sks = new SecretKeySpec(secretKey.getBytes(),algorithm);
        IvParameterSpec iv = new IvParameterSpec(secretKey.getBytes(),0,offset);
        Cipher cipher = Cipher.getInstance(transformation);
        cipher.init(type,sks,iv);
        return cipher;
    }

    public static void main(String[] args) {
        String content = "Admin123Admin123Admin123Admin123Admin123Admin123Admin123Admin123Admin123Admin123";
        String encryptString = encrypt(content);
        String decryptString = decrypt(encryptString);
        System.out.println("encrypt===>"+encryptString+"\ndecrypt===>"+decryptString);
    }

下面是幫助理解AES加解密算法的源碼方法:

這個方法在Cipher類中,將var0轉換爲我們使用的算法(AES)、工作模式(CBC)、填充方式(PKCS5Padding)

private static List<Cipher.Transform> getTransforms(String var0) throws NoSuchAlgorithmException {
    String[] var1 = tokenizeTransformation(var0);
    String var2 = var1[0];
    String var3 = var1[1];
    String var4 = var1[2];
    if (var3 != null && var3.length() == 0) {
        var3 = null;
    }

    if (var4 != null && var4.length() == 0) {
        var4 = null;
    }

    if (var3 == null && var4 == null) {
        Cipher.Transform var6 = new Cipher.Transform(var2, "", (String)null, (String)null);
        return Collections.singletonList(var6);
    } else {
        ArrayList var5 = new ArrayList(4);
        var5.add(new Cipher.Transform(var2, "/" + var3 + "/" + var4, (String)null, (String)null));
        var5.add(new Cipher.Transform(var2, "/" + var3, (String)null, var4));
        var5.add(new Cipher.Transform(var2, "//" + var4, var3, (String)null));
        var5.add(new Cipher.Transform(var2, "", var3, var4));
        return var5;
    }

這倆方法在AESCipher和CipherCore類中,可以看出PKCS5Padding填充塊大小blockSize爲固定16

protected AESCipher(int var1) {
    this.core = new CipherCore(new AESCrypt(), 16);
    this.fixedKeySize = var1;
}

CipherCore(SymmetricCipher var1, int var2) {
    this.blockSize = var2;
    this.unitBytes = var2;
    this.diffBlocksize = var2;
    this.buffer = new byte[this.blockSize * 2];
    this.cipher = new ElectronicCodeBook(var1);
    this.padding = new PKCS5Padding(this.blockSize);
}

此方法在CipherCore 類中,根據工作模式設置相應的密碼管理器

void setMode(String var1) throws NoSuchAlgorithmException {
    if (var1 == null) {
        throw new NoSuchAlgorithmException("null mode");
    } else {
        String var2 = var1.toUpperCase(Locale.ENGLISH);
        if (!var2.equals("ECB")) {
            SymmetricCipher var3 = this.cipher.getEmbeddedCipher();
            if (var2.equals("CBC")) {
                this.cipherMode = 1;
                this.cipher = new CipherBlockChaining(var3);
            } else if (var2.equals("CTS")) {
                this.cipherMode = 6;
                this.cipher = new CipherTextStealing(var3);
                this.minBytes = this.blockSize + 1;
                this.padding = null;
            } else if (var2.equals("CTR")) {
                this.cipherMode = 5;
                this.cipher = new CounterMode(var3);
                this.unitBytes = 1;
                this.padding = null;
            } else if (var2.equals("GCM")) {
                if (this.blockSize != 16) {
                    throw new NoSuchAlgorithmException("GCM mode can only be used for AES cipher");
                }

                this.cipherMode = 7;
                this.cipher = new GaloisCounterMode(var3);
                this.padding = null;
            } else if (var2.startsWith("CFB")) {
                this.cipherMode = 2;
                this.unitBytes = getNumOfUnit(var1, "CFB".length(), this.blockSize);
                this.cipher = new CipherFeedback(var3, this.unitBytes);
            } else if (var2.startsWith("OFB")) {
                this.cipherMode = 3;
                this.unitBytes = getNumOfUnit(var1, "OFB".length(), this.blockSize);
                this.cipher = new OutputFeedback(var3, this.unitBytes);
            } else {
                if (!var2.equals("PCBC")) {
                    throw new NoSuchAlgorithmException("Cipher mode: " + var1 + " not found");
                }

                this.cipherMode = 4;
                this.cipher = new PCBC(var3);
            }

        }
    }
}

 

此方法在Cipher類中,設置填充方式

void setModePadding(CipherSpi var1) throws NoSuchAlgorithmException, NoSuchPaddingException {
    if (this.mode != null) {
        var1.engineSetMode(this.mode);
    }

    if (this.pad != null) {
        var1.engineSetPadding(this.pad);
    }

}

 此方法在IvParameterSpec類中,可以看出向量不能小於偏移量長度

public IvParameterSpec(byte[] var1, int var2, int var3) {
    if (var1 == null) {
        throw new IllegalArgumentException("IV missing");
    } else if (var1.length - var2 < var3) {
        throw new IllegalArgumentException("IV buffer too short for given offset/length combination");
    } else if (var3 < 0) {
        throw new ArrayIndexOutOfBoundsException("len is negative");
    } else {
        this.iv = new byte[var3];
        System.arraycopy(var1, var2, this.iv, 0, var3);
    }
}

在AESCrypt類和AESConstants 接口中,可以判斷出密鑰長度是否合理

static final boolean isKeySizeValid(int var0) {
    for(int var1 = 0; var1 < AES_KEYSIZES.length; ++var1) {
        if (var0 == AES_KEYSIZES[var1]) {
            return true;
        }
    }

    return false;
}

//AES要塊大小,以及AES密鑰要求的長度類型
interface AESConstants {
    int AES_BLOCK_SIZE = 16;
    int[] AES_KEYSIZES = new int[]{16, 24, 32};
}

此方法在CipherCore類中,可以判斷出向量長度是否合理

else if (var3 instanceof IvParameterSpec) {
    var7 = ((IvParameterSpec)var3).getIV();
    if (var7 == null || var7.length != this.blockSize) {
        throw new InvalidAlgorithmParameterException("Wrong IV length: must be " + this.blockSize + " bytes long");
    }
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章