DES加密:8051實現(C語言) & FPGA實現(VHDL+NIOS II)
本文將利用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 roun