1. 程式人生 > >DES加密:8051實現(C語言) & FPGA實現(VHDL+NIOS II)

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-bitPIO 的外設,故輸入輸出拆成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