AES加密算法原理及java android實現

AES當今最流行的對稱加密算法之一,是DES的替代者。

密鑰是AES算法實現加密和解密的根本。對稱加密算法之所以對稱,是因爲這類算法對明文的加密和解密需要使用同一個密鑰
AES支持三種長度的密鑰:
128位,192位,256位
平時大家所說的AES128,AES192,AES256,實際上就是指的AES算法對不同長度密鑰的使用。

他們本質的區別是加密處理輪數不同。

AES加密原理:分組加密

AES算法在對明文加密的時候,並不是把整個明文一股腦加密成一整段密文,而是把明文拆分成一個個獨立的明文塊,每一個明文塊長度128bit。
這些明文塊經過AES加密器的複雜處理,生成一個個獨立的密文塊,這些密文塊拼接在一起,就是最終的AES加密結果。
但是這裏涉及到一個問題:
假如一段明文長度是192bit,如果按每128bit一個明文塊來拆分的話,第二個明文塊只有64bit,不足128bit。這時候怎麼辦呢?就需要對明文塊進行填充(Padding)。

舉例幾種填充形式:

NoPadding: 不做任何填充,但是要求明文必須是16字節的整數倍。 
PKCS5Padding(默認): 如果明文塊少於16個字節(128bit),在明文塊末尾補足相應數量的字符,且每個字節的值等於缺少的字符數。 比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6個字節,則補全爲{1,2,3,4,5,a,b,c,d,e,6,6,6,6,6,6} ISO10126Padding: 如果明文塊少於16個字節(128bit),在明文塊末尾補足相應數量的字節,最後一個字符值等於缺少的字符數,其他字符填充隨機數。 比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6個字節,則可能補全爲{1,2,3,4,5,a,b,c,d,e,5,c,3,G,$,6} 

模式
AES的工作模式,體現在把明文塊加密成密文塊的處理過程中。AES加密算法提供了五種不同的工作模式:
ECB、CBC、CTR、CFB、OFB
模式之間的主題思想是近似的,在處理細節上有一些差別。模式的基本定義:
ECB模式(默認):
電碼本模式 Electronic Codebook Book,是最簡單的工作模式,在該模式下,每一個明文塊的加密都是完全獨立,互不干涉的。

好處:
1.簡單
2.有利於並行計算
缺點:
相同的明文塊經過加密會變成相同的密文塊,因此安全性較差。

CBC模式:
密碼分組鏈接模式 Cipher Block Chaining,引入了一個新的概念:初始向量IV(Initialization Vector)。
IV是做什麼用的呢?它的作用和MD5的“加鹽”有些類似,目的是防止同樣的明文塊始終加密成同樣的密文塊。

從圖中可以看出,CBC模式在每一個明文塊加密前會讓明文塊和一個值先做異或操作。IV作爲初始化變量,參與第一個明文塊的異或,後續的每一個明文塊和它前一個明文塊所加密出的密文塊相異或。
這樣以來,相同的明文塊加密出的密文塊顯然是不一樣的。
CBC模式的好處是什麼呢?
安全性更高
壞處也很明顯:
1.無法並行計算,性能上不如ECB
2.引入初始化向量IV,增加複雜度
CTR模式:
計算器模式 Counter
CFB模式:
密碼反饋模式 Cipher FeedBack
OFB模式:
輸出反饋模式 Output FeedBack

================================================================================================

java android 實現:

String encryptStr;

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn1:
                try {
                    byte[] encrypt = EncryptorAES.encrypt("AES hello world!恭喜發財", EncryptorAES.key);
                    encryptStr = Base64.encodeToString(encrypt,0);
                    LogUtil.i(encryptStr);
                } catch (Exception e) {
                }
                break;
            case R.id.btn2:
                try {
                    byte[] decrypt = EncryptorAES.decrypt(Base64.decode(encryptStr,0), EncryptorAES.key);
                    LogUtil.i(new String(decrypt,"UTF-8"));
                } catch (Exception e) {
                    LogUtil.i(e);
                }
                break;
        }
    }
public class EncryptorAES {

    public static String key = "i53jsdjfhaisf23u";
    public static String key_iv = "0vnghiower7twhjm";

    public static byte[] encrypt(String content, String password) throws Exception {
        // 創建AES祕鑰
        SecretKeySpec key = new SecretKeySpec(password.getBytes("UTF-8"), "AES/CBC/PKCS5PADDING");
        // 創建密碼器
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        // 初始化加密器
        cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(key_iv.getBytes("UTF-8")));
        // 加密
        return cipher.doFinal(content.getBytes("UTF-8"));
    }

    public static byte[] decrypt(byte[] content, String password) throws Exception {
        // 創建AES祕鑰
        SecretKeySpec key = new SecretKeySpec(password.getBytes("UTF-8"), "AES/CBC/PKCS5PADDING");
        // 創建密碼器
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        // 初始化解密器
        cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(key_iv.getBytes("UTF-8")));
        // 解密
        return cipher.doFinal(content);
    }

}

加密後的字節數組可以轉化爲base64或者hex來展示,轉化後hex體積多了一倍,base64多了三分之一,相對體積更小一點,所以我這裏用的base64。

================================================================================================

具體加密操作:

AES不是一次性把明文變成密文,而是經過很多輪加密。

具體分成多少輪呢?
初始輪(Initial Round) 1次
普通輪(Rounds) N次
最終輪(Final Round) 1次
AES的Key支持三種長度:AES128,AES192,AES256。Key的長度決定了AES加密的輪數。
除去初始輪,各種Key長度對應的輪數如下:
AES128:10輪
AES192:12輪
AES256:14輪
不同階段的Round有不同的處理步驟。
初始輪只有一個步驟:
加輪密鑰(AddRoundKey)
普通輪有四個步驟:
字節代替(SubBytes)
行移位(ShiftRows)
列混淆(MixColumns)
加輪密鑰(AddRoundKey)
最終輪有三個步驟:
字節代替(SubBytes)
行移位(ShiftRows)
加輪密鑰(AddRoundKey)

1.字節替代(SubBytes)

首先需要說明的是,16字節的明文塊在每一個處理步驟中都被排列成4X4的二維數組。
所謂字節替代,就是把明文塊的每一個字節都替代成另外一個字節。替代的依據是什麼呢?依據一個被稱爲S盒(Subtitution Box)的16X16大小的二維常量數組。
假設明文塊當中a[2,2] = 5B(一個字節是兩位16進制),那麼輸出值b[2,2] = S[5][11]。
2.行移位(ShiftRows)

這一步很簡單,就像圖中所描述的:
第一行不變
第二行循環左移1個字節
第三行循環左移2個字節
第四行循環左移3個字節
3.列混淆(MixColumns)

這一步,輸入數組的每一列要和一個名爲修補矩陣(fixed matrix)的二維常量數組做矩陣相乘,得到對應的輸出列。
4.加輪密鑰(AddRoundKey)

這一步是唯一利用到密鑰的一步,128bit的密鑰也同樣被排列成4X4的矩陣。
讓輸入數組的每一個字節a[i,j]與密鑰對應位置的字節k[i,j]異或一次,就生成了輸出值b[i,j]。
需要補充一點,加密的每一輪所用到的密鑰並不是相同的。這裏涉及到一個概念:擴展密鑰(KeyExpansions)。
擴展密鑰(KeyExpansions)
AES源代碼中用長度 4 * 4 *(10+1) 字節的數組W來存儲所有輪的密鑰。W{0-15}的值等同於原始密鑰的值,用於爲初始輪做處理。
後續每一個元素W[i]都是由W[i-4]和W[i-1]計算而來,直到數組W的所有元素都賦值完成。
W數組當中,W{0-15}用於初始輪的處理,W{16-31}用於第1輪的處理,W{32-47}用於第2輪的處理 ......一直到W{160-175}用於最終輪(第10輪)的處理。

轉載原始文章https://zhuanlan.zhihu.com/p/45155135

 

 

 

 

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