0%

块加密模式之CBC和CTR

块加密(block cipher),也叫分组加密,与之前说的流加密相对应。它将明文分成多个等长的模块(block),使用确定的算法和密钥对每组进行加密解密。典型的块加密算法有DES和AES。而其中AES是我们现今最常用的对称加密算法。

而这里要介绍的是,各种块加密的模式。

块加密模式介绍

为什么要用块加密?

为了更好理解什么是块加密,先看看为什么需要不同的块加密模式吧。

原图
图1 原图
简单块加密,即EBC
图2 简单块加密

由图中可以看出来,在进行块加密后,加密图片虽然对原图进行了信息模糊,但是依旧能够看到图片的大致轮廓。这里的根本原因是对于相同内容的块的信息,经过加密后得到的结果依旧是一样的。 这就好比恺撒密码一对一对应的密码可以通过统计的方式进行破解。这种简单的模式就是ECB(Eletronic code book)模式,它的优点是简单直接,但缺点显而易见,对加密信息的整体保留了信息,无法使得明文的每一比特信息对加密后产生影响,给人一种“没有搅匀”的感觉。

什么是块加密模式

明白了为什么要引入其他块加密模式后,块加密模式是什么就明显了—— 在原有的单个块的块加密的基础上,将每个块以级联的方式进行连接,前一个块的加密结果会对后面的块加密产生“随机效果”,进一步破坏信息的结构。

常用的块加密模式

CBC类型

CBC(Ciphier block chaining),是我们上述说的级联的典范。其他的模式PCBC、CFB和OFB等都是这种类型的,只是它们在级联时和取异或操作时的输入不同而已。

CBC加密
CBC加密
CBC解密
CBC解密

CTR类型

CTR(Counter mode)是利用计数器的计数作为每次块加密的随机种子,这种模式可以结合上面几个模式进行推广。

CTR加密
CTR加密
CTR解密
CTR解密

关于IV

IV是Initial vector或Initial value,它的作用是用于块加密的首轮加密的输入,也有可能是计数器的初始值设定,一般是个固定值,但是也可以根据具体需要设置成需要的值。

实现(C++)

ModernBlockCipher.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef MODERNBLOCKCYPHER_H
#define MODERNBLOCKCYPHER_H
#include "AES.h"
#include <string>
using namespace std;
void counterModeDecryption(string stream, Byte* IV, Byte* fullKey);
void cipherBlockChainingEncryption(string stream, Byte* IV, Byte* fullKey);
void cipherBlockChainingDecryption(string stream, Byte* IV, Byte* fullKey);
void padding(string* ct, string mode);
void inititalizeIV(string& ct, Byte* IV);
void str2Bytes(string s, Byte* b);
void bytes2Matrix(Byte* b, Byte matrix[][4]);
void matrix2Bytes(Byte matrix[][4], Byte* b);
void printBytes(Byte* b);
void printChar(Byte* b);
void byteCopy(Byte* c, Byte* copy);
void xorBytes(Byte* a, Byte* b, Byte* result);
void printMatrix(Byte matrix[][4]);
void IVUpdate(Byte* IV);
#endif
ModernBlockCipher.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include "ModernBlockCypher.h"
#include "AES.h"
#include <stdio.h>
#include <string>
#include <iostream>
using namespace std;

void counterModeDecryption(string stream, Byte* IV, Byte* fullKey)
{
int lenOfStream = stream.length();
if(lenOfStream > 0) {
Byte* c = new Byte[16];
str2Bytes(stream.substr(0,32), c);
Byte* tmp = new Byte[16];
Byte matrix[4][4]={};
bytes2Matrix(IV, matrix);
Byte p[16];
AES_Encryption(matrix, fullKey);
matrix2Bytes(matrix, tmp);
xorBytes(tmp, c, p);
printChar(p);
delete tmp;
delete c;
IVUpdate(IV);
counterModeDecryption(stream.substr(32), IV, fullKey);
}
}

void cipherBlockChainingDecryption(string stream, Byte* IV, Byte* fullKey)
{
int lenOfStream = stream.length();
if(lenOfStream > 0) {
Byte* c = new Byte[16];
str2Bytes(stream.substr(0,32), c);
Byte* tmpC = new Byte[16];
byteCopy(c, tmpC);
Byte matrix[4][4]={};
bytes2Matrix(c, matrix);
Byte p[16];
AES_Decryption(matrix, fullKey);
matrix2Bytes(matrix, tmpC);
xorBytes(tmpC, IV, p);
printChar(p);
cipherBlockChainingDecryption(stream.substr(32), c, fullKey);
delete tmpC;
delete c;
}
}


void padding(string* ct, string mode){
int lenOfBytes = ct->length() / 2;
int lenOfPadding = (16 - lenOfBytes % 16) % 16;
if(!lenOfPadding)
return;
string padding = "";
if(mode == "CBC") {
char tmp[3];
sprintf(tmp, "0%x", lenOfPadding);
padding = string(tmp);
} else if(mode == "CTR") {
padding = "00";
}
for (int i=0; i<lenOfPadding; i++) {
ct->append(padding);
}
}

void inititalizeIV(string& ct, Byte* IV) {
str2Bytes(ct.substr(0,32), IV);
ct = ct.substr(32); //去除密文中的IV
}

// Str:32字符-> Bytes:16
void str2Bytes(string s, Byte* b) {
for (int i=0; i<16; ++i) {
b[i] = (isdigit(s[i*2]) ? s[i*2]-'0' : s[i*2] - 'a'+10) * 16;
b[i] += isdigit(s[i*2+1]) ? s[i*2+1] - '0' : s[i*2+1] -'a'+10;
}
}

void bytes2Matrix(Byte* b, Byte matrix[][4]) {
for(int i=0; i<4; ++i) {
for(int j=0; j<4; ++j) {
matrix[j][i] = b[i*4+j];
}
}
}

void matrix2Bytes(Byte matrix[][4], Byte* b){
for (int i=0; i<16; ++i) {
b[i] = matrix[i%4][i/4];
}
}

// Bytes b[16] -> 00 01 02
void printBytes(Byte* b) {
for (int i=0; i<16; i++) {
printf("%02x ",b[i]);
}
printf("\n");
}

// Bytes b[16] -> a b c
void printChar(Byte* b) {
// printBytes(b);
for (int i=0; i<16; ++i) {
printf("%c", b[i]);
}
// printf("\n");
}

void printMatrix(Byte matrix[][4]) {
for (int i=0; i<4; ++i) {
for (int j=0; j<4; ++j) {
printf("0x%02x ",matrix[i][j]);
}
printf("\n");
}
}


void byteCopy(Byte* c, Byte* copy){
for (int i=0; i<16; ++i) {
copy[i] = c[i];
}
}

void xorBytes(Byte* a, Byte* b, Byte* result){
for (int i=0; i<16; ++i) {
result[i] = a[i] ^ b[i];
}
}


// IV = IV + 1
void IVUpdate(Byte* IV) {
int ptr = 15;
int cf = 0;
while(ptr>=0) {
int tmp = IV[ptr]+1+cf;
cf = tmp / 0x100;
IV[ptr] = tmp % 0x100;
if(cf > 0)
ptr--;
else if(cf == 0 || ptr < 0)
break;
}
}

AES调用了往届师兄写的一些接口函数

AES.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//
// AES.h
// SymmetricKeyCipher
//
// Created by szxjzhou on 3/24/15.
// Copyright (c) 2015 szxjzhou. All rights reserved.
//

#ifndef __SymmetricKeyCipher__AES__
#define __SymmetricKeyCipher__AES__

#include <stdio.h>

typedef unsigned char Byte;

// Each word is 4 Bytes
#define BYTES_IN_WORD (4)
// Each round of key is 4 words
#define WORD_IN_ROUND (4)
// Each byte has 8 bits
#define BIT_IN_BYTE (8)
// Each round of key is 4 words, say 4 * 4 = 16 Bytes
#define BYTES_IN_ROUND (16)
// Expended key length is 11 words, say 11 * 16 = 176 Bytes
#define BYTES_IN_EXPANDED_KEY (176)
// In AES128 has 10 rounds except the initialization round
#define NUM_OF_ROUNDS (10)
Byte *keyExpansion(Byte *cipherKey);
void AES_Encryption(Byte state[][BYTES_IN_WORD], Byte* key);
void AES_Decryption(Byte state[][BYTES_IN_WORD], Byte* key);
void rotateWord(Byte *word, int offset);
void substitutionWord(Byte *word);
void substitutionWord(Byte state[][BYTES_IN_WORD]);
void substitutionWordInv(Byte state[][BYTES_IN_WORD]);
void shiftRow(Byte state[][BYTES_IN_WORD]);
void shiftRowInv(Byte state[][BYTES_IN_WORD]);
void mixColumn(Byte state[][BYTES_IN_WORD]);
void mixColumnInv(Byte state[][BYTES_IN_WORD]);
Byte GF_Multiplication(Byte a, Byte b);
void addRoundKey(Byte state[][BYTES_IN_WORD], Byte* key, int round);
void printState(Byte state[][BYTES_IN_WORD]);

#endif /* defined(__SymmetricKeyCipher__AES__) */