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

 

 

 

 

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