AES块加密与解密
解密目标
在CBC和CTR两种模式下分别给出十篇加密的样例密文,求解密一篇特定的密文
解密前提
- 全部密文及其加密使用的key都已给出
- 加密的方法遵循AES的标准
解密过程分析
实验中给出了密文及其对应Key。
CBC模式观察下图:
这幅图就是CBC解密的整个流程图,注意到Key指的是已经给出了的
Key的Expansion形式,也就是经过了扩展成44个Byte的Key,给出的Key是4个Byte的形式。这里的Initialization Vector实际上就是给出的密文中的前16位。Ciphertext的一个单位长度是16个Byte,最后的操作如果不足16个Byte的,需要补足16个Byte,再进行AES块解密操作。中间的Block Cipher Decryption在此处是一个黑盒子,用于AES的解密操作,后面再说AES的认识和理解。注意到,AES算法中的数据类型都是定义好的,详细可以看教材的P194页,总的来说分为四个部分:Byte、Word、Block和State。
在这里,四种数据类型之间是可以转换的,但是遵循一定的规则。
在实验中主要用到了Block转State和State转Block两种数据类型,对应的转换规则为:
可以看到,Block是按照人类阅读规则,从左往右的顺序排列的,但是State是反人类规则,竖式排列的规则,这个坑好累。
解密的时候,第一个块解密使用的是Initialization Vector进行异或操作,后续的块解密使用的是前一个块的密文来进行异或操作,也就是说CBC模式加密解密是前后文关联的。
CTR模式观察下图:
CTR模式与CBC模式相比,不同的地方在于,进行AES解密的时候,使用的是一个Counter来进行AES加密,Counter的初始值就是Initialization Vector,每一轮加密就对Counter的值进行+1操作。最后通过AES加密后的结果,与密文进行异或操作,从而得到对应的原文。注意,这里是解密的过程,但是中间的黑盒子也是使用AES加密操作来进行。
AES加密解密解析
(证明我有好好学习)
主要就是四个操作:SubBytes、ShiftRows、MixColumns和AddRoundKey
SubBytes:
这个操作就是查表,进行一个新的映射,在一个4x4的State中,每一个格子都是一个Byte,一个Byte由两个16进制字符组成,通过查询一个16x16的表格,将一个Byte映射成另一个Byte。
ShiftRows:
这个操作是对State进行行的移位操作,第n行向左移动n位,循环移动,n大于等于0且n小于4。
MixColumns:
这个操作是有一个固定的4x4矩阵,对于State的每一列都和这个矩阵进行乘法操作,得到一个新的列。最终得到一个新的State。
AddRoundKey:
这个操作是将当前的State与当前这一轮的Key进行异或操作,得到新的State。
整个流程可以看这样一幅图:
代码分析
根据流程,将密钥进行扩展,然后按照16分块操作,进行解密,再输出。以CBC解密为栗子:
void CBC() {
// Declare the key and stream
Byte key[16] = {
0x14, 0x0b, 0x41, 0xb2, 0x2a, 0x29, 0xbe, 0xb4, 0x06, 0x1b, 0xda, 0x66, 0xb6, 0x74, 0x7e, 0x14
};
Byte IV[16] = {
0x4c, 0xa0, 0x0f, 0xf4, 0xc8, 0x98, 0xd6, 0x1e, 0x1e, 0xdb, 0xf1, 0x80, 0x06, 0x18, 0xfb, 0x28
};
Byte stream[100] = {
0x63, 0xcb, 0x8d, 0x05, 0x3b, 0xe7, 0xfc, 0xf1, 0x11, 0xcf, 0x4a, 0x6e, 0x04, 0x43, 0x01, 0x07,
0x2a, 0x86, 0x36, 0xca, 0x9b, 0xea, 0x59, 0xa7, 0xb6, 0x50, 0x58, 0xe6, 0x52, 0xe4, 0x8a, 0xbd,
0xcd, 0x46, 0x1b, 0x97, 0x1b, 0xec, 0xdf, 0xdc, 0xb1, 0xf4, 0x4b, 0x36, 0x02, 0x25, 0x5e, 0x2d,
0x61, 0x6b, 0xdd, 0x10, 0x71, 0xa5, 0x47, 0x55, 0xc3, 0x06, 0x88, 0x79, 0x3d, 0xbf, 0x1a, 0x4a
};
// Decryption
Byte *fullKey = keyExpansion(key);
cipherBlockChainingDecryption(stream, IV, fullKey, 16 * 3);
// Show the result
for(int i = 0; i < 16 * 3; i++)
printf("%c", stream[i]);
printf("
");
free(fullKey);
}
void cipherBlockChainingDecryption(Byte *stream, Byte *IV, Byte *key, int length) {
int times = length / CIPHERTEXT_LENGTH;
if (length > times * CIPHERTEXT_LENGTH) {
times++;
}
Byte streamOrgin[100];
for (int i = 0; i < 100; i++) {
streamOrgin[i] = stream[i];
}
Byte ciphertext[4][4];
for (int i = 0; i < times; i++) {
if (i == 0) {
oneD2twoD(stream + i * CIPHERTEXT_LENGTH, ciphertext);
AES_Decryption(ciphertext, key);
twoD2oneD(ciphertext, stream + i * CIPHERTEXT_LENGTH);
exclusiveOr(stream + i * CIPHERTEXT_LENGTH, IV);
} else {
oneD2twoD(stream + i * CIPHERTEXT_LENGTH, ciphertext);
AES_Decryption(ciphertext, key);
twoD2oneD(ciphertext, stream + i * CIPHERTEXT_LENGTH);
exclusiveOr(stream + i * CIPHERTEXT_LENGTH, streamOrgin + (i - 1) * CIPHERTEXT_LENGTH);
}
}
}
后记
在一般情况下,128位的Key加密后的内容,通过暴力的方式进行解密,需要n年的时间才能完全解密(刚才和TA讨论了一下,包括Key和Initialization Vector共32位,枚举每一位0~F共16个变化,大概是10^32次方的数据),因此才说,暴力破解很难,更何况是如果不是128呢?
加密方式的角度上来说,CBC和CTR在加密方式上来说,最大的区别在于块加密上,前后的块是否关联,关联的块带来的是更好的加密,但同时也带来了性能的开销,如CBC。CTR使用的是计数器模式,块加密前后不关联,能够很好地同时进行加密,大大提高了加密和解密的速度。
传送门:下载