本文将利用C语言和VHDL语言分别实现DES加密,并在8051和FPGA上测试。
终于有机会阅读《深入浅出密码学一书》,趁此机会深入研究了DES加密的思想与实现。本文将分为两部分,第一部分为简单的C语言实现,第二部分为FPGA实现并在NIOS II
核上测试该模块。
DES加密的思想
DES加密的由来网络上资料非常了,这里给出wikipedia
链接: 维基百科
DES加密主要利用了两个工具
利用替换来实现混淆,如DES加密中的
S_box
,即将明文和密文之间存在的关系尽可能模糊。利用位置换来实现扩散,如DES加密中的
IP
。实现扩散之后,可以隐藏明文的统计属性,即一个明文符号的改变会涉及到多个密文符号的加密操作。
DES利用的流程为 Feistel网络
该网络主要特点为加密过程和解密过程几乎完全相同。
DES加密的C语言实现
利用C语言实现DES加密分为几个步骤:
第一步先将上文中所描述的
替换
与位置换
先实现。第二步实现
f函数
以及子密钥生成
最后实现完整的
DES加密
操作
下面分步骤实现这些部分
替换实现
替换利用C语言来实现并不复杂,可以直接用数组实现,例如 S-box
实现可以如下
for (i = 0; i < 8; i++){
e_string[i] = (e_string[i] ^ round_key[i]) & 0x3F;
e_string[i] = s[i] [e_string[i]];
}
位置换实现
位置换相对就复杂,抽象出一个函数,传入置换表和置换位数。根据置换表中描述的位数查看对应位是否为1。若为1,则在输出表中将对应位置为1。
/** transpose
* This function is going to use table to transpose trans_in_data into trans_out_data,
* while n is the number of bit which trans_out_data have.
* @Author Liu Nian, 2017
*/
void transpose(unsigned char *trans_in_data, unsigned char *trans_out_data,
unsigned char *table, unsigned char n){
int i, bit_change;
//clear trans_out_data
for(i = 0; i < 8;i++)
trans_out_data[i] = 0;
//To transpose the bit_change bit
for(i = 0; i < n;i++){
bit_change = *table++;
//find the bit and check whether it is 1
if (trans_in_data[bit_change>>3] & (0x80>>(bit_change & 7)))
trans_out_data[i>>3] |= (0x80>>(i & 7));
}
}
f函数实现
利用上述两个方法可以实现f函数,f函数实现如下:
/** f
* This function is going to mix round_key with 32-bit string.
* @Author Liu Nian, 2017
*/
void f(unsigned char *round_key, unsigned char *in_string, unsigned char *xor_string){
unsigned char e_string[8];
int i;
transpose(in_string, e_string, E_table, 64);
//Use S box for confussion
for (i = 0; i < 8; i++){
e_string[i] = (e_string[i] ^ round_key[i]) & 0x3F;
e_string[i] = s[i] [e_string[i]];
}
transpose(e_string, xor_string, P_table, 32);
}
16轮子密钥生成
子密钥生成时,还用到了另一个工具,就是1,2,9,16轮加密时,左右32-bit密钥向左轮转1位,剩余情况则轮转2位。轮转用rotate_left
函数来实现。
/** rotate_left
* This function is going to make both left (32-bit) and right part of key rotate 1 bit.
* @Author Liu Nian, 2017
*/
void rotate_left(unsigned char *key){
unsigned char str_x[8];
unsigned char i;
for (i=0; i < 8; ++i)
str_x[i] = key[i];
for (i=0; i < 7; ++i){
key[i] = (key[i] << 1);
if ((i < 6) && ((str_x[i+1] & 128) == 128))
key[i] |= 1;
}
if (str_x[0] & 0x80 )
key[3] |= 0x10;
else
key[3] &= ~0x10;
if (str_x[3] & 0x08 )
key[6] |= 0x01;
else
key[6] &= ~0x01;
}
计算子密钥函数如下:
/** compute_subkeys
* This function is going to generate sub_keys.
* @Author Liu Nian, 2017
*/
void compute_subkeys(unsigned char *key){
unsigned char i, j, in_key[8], out_key[8];
// Store key in main_key
for (i=0; i < 8; i++)
main_key[i] = key[i];
// Use PC_1_table to transpose 64-bit key into 56-bit in_key
transpose(key, in_key, PC_1_table, 56);
//Generate sub_keys for every round
for (i=0; i < 16; i++){
//For round 1,2,9,16 , key has to be rotate left 1 bit
//For other rounds, key has to rotate left 2 bit
for (j=0; j < round_turn[i]; j++)
rotate_left(in_key);
// Use PC_2_table to transpose in_key to out_key
transpose(in_key, out_key, PC_2_table, 64);
for (j=0; j < 8; j++)
sub_keys[i][j] = out_key[j];
}
}
DES加密函数
将上述模块连接起来,完整整体DES加密。
/** DES function
* This function is used for DES encryption
* Input parameter
* unsigned char *plain_strng : pointer to 64 bits input string
* unsigned char *key : pointer to 64 bits key string
* unsigned char *ciph_strng : pointer to a 64 bits output string
* @Author Liu Nian, 2017
*/
void des(unsigned char *plain_strng, unsigned char *key, unsigned char *ciph_strng){
unsigned char in_string[8], round_string[8], xor_string[8];
unsigned char i, j, *round_key, temp;
// compute subkeys which will be used in every round
compute_subkeys(key);
// Use transpose plain_strng into in_string
transpose(plain_strng, in_string, IP_table, 64);
// Encrypt for 16 round
for (i = 0; i < 16; i++){
// round_string is string which we will deal with in this round.
for (j=0; j < 8; j++)
round_string[j] = in_string[j];
// round_key is the key which will be used in this round
round_key = &sub_keys[i][0];
// The first 32-bit of the next round string is the same as the last 32-bit of
// this round.
for (j=0; j < 4; j++)
in_string[j] = round_string[j+4];
// Use f box to generate xor_string
f(round_key, in_string, xor_string);
// The last 32-bit of the next round string is the result of XOR between
// the fist 32-bit of this round and xor_string
for (j=0; j < 4; j++)
in_string[j+4] = round_string[j] ^ xor_string[j];
}
// change the sequence of first 32-bit and last 32-bit
for (j=0; j < 4; j++) {
temp = in_string[j];
in_string[j] = in_string[j+4];
in_string[j+4] = temp;
}
// Use IP_1_table to transpose in_string into ciph_strng
transpose(in_string, ciph_strng, IP_1_table, 64);
}
完整代码见附
DES加密的FPGA实现
DES加密的FPGA实现参考CoreTex Systems
公司的版本。
主要思想是利用状态机来在各个状态之间进行转移。详细代码可以参见CoreTex Systems
详细分析待后补充。
接入NIOS II核心并测试
由于NIOS II
核心只支持 32-bit
的 PIO
的外设,故输入输出拆成2个32位
端口实现。
Qsys
编辑界面如下:
在顶层图上添加DES加密模块
如下:
测试代码如下:
#include <stdio.h>
#include "system.h"
#include "altera_avalon_pio_regs.h"
int main(){
int i = 0x0A;
unsigned int key_low = 0x12341234;
unsigned int key_high = 0x12341234;
unsigned int data_high = 0x01020304 ;
unsigned int data_low = 0x05060708;
unsigned int out_low;
unsigned int out_high;
int des_state = 0;
printf("Des_test\n");
IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE,i);
IOWR_ALTERA_AVALON_PIO_DATA(KEY_OUT_LOW_BASE,key_low);
IOWR_ALTERA_AVALON_PIO_DATA(KEY_OUT_HIGH_BASE,key_high);
IOWR_ALTERA_AVALON_PIO_DATA(DATA_OUT_HIGH_BASE,data_high);
IOWR_ALTERA_AVALON_PIO_DATA(DATA_OUT_LOW_BASE,data_low);
printf("Start des\n");
//密钥明文传输完成,LD_DATA置1通知DES加密元件
IOWR_ALTERA_AVALON_PIO_DATA(LD_DATA_BASE,1);
//等待加密完成
des_state = IORD_ALTERA_AVALON_PIO_DATA(DES_STATE_BASE);
printf("des_state:%d\n",des_state);
while(des_state & 0x1 == 0){
printf("des_state:%d\n",des_state);
usleep(10000);
des_state = IORD_ALTERA_AVALON_PIO_DATA(DES_STATE_BASE);
}
//输出加密结果
out_low = IORD_ALTERA_AVALON_PIO_DATA(DATA_IN_LOW_BASE);
out_high = IORD_ALTERA_AVALON_PIO_DATA(DATA_IN_HIGH_BASE);
printf("%x",out_high);
printf("%x",out_low);
return 0;
}
DES 加密C语言完整代码
#include <stdio.h>
/****************************************************************************************/
/* Translation Table */
/****************************************************************************************/
xdata const unsigned char IP_table[64] =
{
57, 49, 41, 33, 25, 17, 9, 1,
59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7,
56, 48, 40, 32, 24, 16, 8, 0,
58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6
};
xdata const unsigned char IP_1_table[64] =
{
39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30,
37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28,
35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26,
33, 1, 41, 9, 49, 17, 57, 25,
32, 0, 40, 8, 48, 16, 56, 24
};
xdata const unsigned char swap[64] =
{
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,
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
};
xdata const unsigned char PC_1_table[56] =
{
56, 48, 40, 32, 24, 16, 8,
0, 57, 49, 41, 33, 25, 17,
9, 1, 58, 50, 42, 34, 26,
18, 10, 2, 59, 51, 43, 35,
62, 54, 46, 38, 30, 22, 14,
6, 61, 53, 45, 37, 29, 21,
13, 5, 60, 52, 44, 36, 28,
20, 12, 4, 27, 19, 11, 3
};
xdata const unsigned char PC_2_table[64] =
{
0, 0, 13, 4, 16, 10, 23, 0,
0, 0, 2, 9, 27, 14, 5, 20,
0, 0, 22, 7, 18, 11, 3, 25,
0, 0, 15, 1, 6, 26, 19, 12,
0, 0, 40, 54, 51, 30, 36, 46,
0, 0, 29, 47, 39, 50, 44, 32,
0, 0, 43, 52, 48, 38, 55, 33,
0, 0, 45, 31, 41, 49, 35, 28
};
xdata const unsigned char E_table[64] =
{
0, 0, 31, 4, 0, 1, 2, 3,
0, 0, 3, 8, 4, 5, 6, 7,
0, 0, 7, 12, 8, 9, 10, 11,
0, 0, 11, 16, 12, 13, 14, 15,
0, 0, 15, 20, 16, 17, 18, 19,
0, 0, 19, 24, 20, 21, 22, 23,
0, 0, 23, 28, 24, 25, 26, 27,
0, 0, 27, 0, 28, 29, 30, 31
};
xdata const unsigned char P_table[32] =
{
31, 14, 39, 44, 60, 23, 55, 36,
4, 30, 46, 53, 12, 37, 62, 21,
5, 15, 47, 29, 63, 54, 6, 20,
38, 28, 61, 13, 45, 22, 7, 52
};
/****************************************************************************************/
/* S Box */
/****************************************************************************************/
xdata const unsigned char s[8][64] ={
{
14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13
},
{
15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9
},
{
10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12
},
{
7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14
},
{
2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3
},
{
12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13
},
{
4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12
},
{
13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
}
};
xdata const unsigned char round_turn[16] ={
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};
unsigned char DES_Encrypt_key[8];
unsigned char DES_Decrypt_key[8];
unsigned char sub_keys[16][8];
unsigned char main_key[8];
void des(unsigned char*, unsigned char*, unsigned char*);
static void transpose (unsigned char*, unsigned char*, const unsigned char*, unsigned char);
static void rotate_left (unsigned char*);
static void compute_subkeys (unsigned char*);
static void f (unsigned char*, unsigned char*, unsigned char*);
/** DES function
* This function is used for DES encryption
* Input parameter
* unsigned char *plain_strng : pointer to 64 bits input string
* unsigned char *key : pointer to 64 bits key string
* unsigned char *ciph_strng : pointer to a 64 bits output string
* @Author Liu Nian, 2017
*/
void des(unsigned char *plain_strng, unsigned char *key, unsigned char *ciph_strng){
unsigned char in_string[8], round_string[8], xor_string[8];
unsigned char i, j, *round_key, temp;
// compute subkeys which will be used in every round
compute_subkeys(key);
// Use transpose plain_strng into in_string
transpose(plain_strng, in_string, IP_table, 64);
// Encrypt for 16 round
for (i = 0; i < 16; i++){
// round_string is string which we will deal with in this round.
for (j=0; j < 8; j++)
round_string[j] = in_string[j];
// round_key is the key which will be used in this round
round_key = &sub_keys[i][0];
// The first 32-bit of the next round string is the same as the last 32-bit of
// this round.
for (j=0; j < 4; j++)
in_string[j] = round_string[j+4];
// Use f box to generate xor_string
f(round_key, in_string, xor_string);
// The last 32-bit of the next round string is the result of XOR between
// the fist 32-bit of this round and xor_string
for (j=0; j < 4; j++)
in_string[j+4] = round_string[j] ^ xor_string[j];
}
// change the sequence of first 32-bit and last 32-bit
for (j=0; j < 4; j++) {
temp = in_string[j];
in_string[j] = in_string[j+4];
in_string[j+4] = temp;
}
// Use IP_1_table to transpose in_string into ciph_strng
transpose(in_string, ciph_strng, IP_1_table, 64);
}
/** transpose
* This function is going to use table to transpose trans_in_data into trans_out_data,
* while n is the number of bit which trans_out_data have.
* @Author Liu Nian, 2017
*/
void transpose(unsigned char *trans_in_data, unsigned char *trans_out_data,
unsigned char *table, unsigned char n){
int i, bit_change;
//clear trans_out_data
for(i = 0; i < 8;i++)
trans_out_data[i] = 0;
//To transpose the bit_change bit
for(i = 0; i < n;i++){
bit_change = *table++;
//find the bit and check whether it is 1
if (trans_in_data[bit_change>>3] & (0x80>>(bit_change & 7)))
trans_out_data[i>>3] |= (0x80>>(i & 7));
}
}
/** rotate_left
* This function is going to make both left (32-bit) and right part of key rotate 1 bit.
* @Author Liu Nian, 2017
*/
void rotate_left(unsigned char *key){
unsigned char str_x[8];
unsigned char i;
for (i=0; i < 8; ++i)
str_x[i] = key[i];
for (i=0; i < 7; ++i){
key[i] = (key[i] << 1);
if ((i < 6) && ((str_x[i+1] & 128) == 128))
key[i] |= 1;
}
if (str_x[0] & 0x80 )
key[3] |= 0x10;
else
key[3] &= ~0x10;
if (str_x[3] & 0x08 )
key[6] |= 0x01;
else
key[6] &= ~0x01;
}
/** compute_subkeys
* This function is going to generate sub_keys.
* @Author Liu Nian, 2017
*/
void compute_subkeys(unsigned char *key){
unsigned char i, j, in_key[8], out_key[8];
// Store key in main_key
for (i=0; i < 8; i++)
main_key[i] = key[i];
// Use PC_1_table to transpose 64-bit key into 56-bit in_key
transpose(key, in_key, PC_1_table, 56);
//Generate sub_keys for every round
for (i=0; i < 16; i++){
//For round 1,2,9,16 , key has to be rotate left 1 bit
//For other rounds, key has to rotate left 2 bit
for (j=0; j < round_turn[i]; j++)
rotate_left(in_key);
// Use PC_2_table to transpose in_key to out_key
transpose(in_key, out_key, PC_2_table, 64);
for (j=0; j < 8; j++)
sub_keys[i][j] = out_key[j];
}
}
/** f
* This function is going to mix round_key with 32-bit string.
* @Author Liu Nian, 2017
*/
void f(unsigned char *round_key, unsigned char *in_string, unsigned char *xor_string){
unsigned char e_string[8];
int i;
transpose(in_string, e_string, E_table, 64);
//Use S box for confussion
for (i = 0; i < 8; i++){
e_string[i] = (e_string[i] ^ round_key[i]) & 0x3F;
e_string[i] = s[i] [e_string[i]];
}
transpose(e_string, xor_string, P_table, 32);
}