天天看點

DES實作

C++語言: Codee#13635

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <assert.h>

typedef unsigned char uchar;

//初始換位IP

char IP [ 64 ] =

{

    58 , 50 , 42 , 34 , 26 , 18 , 10 , 2 ,

    60 , 52 , 44 , 36 , 28 , 20 , 12 , 4 ,

    62 , 54 , 46 , 38 , 30 , 22 , 14 , 6 ,

    64 , 56 , 48 , 40 , 32 , 24 , 16 , 8 ,

    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

};

//逆初始換位IP-1

char IP_1 [ 64 ] =

{

    40 , 8 , 48 , 16 , 56 , 24 , 64 , 32 ,

    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

};

//置換選擇1

char PC_1 [ 56 ] =

{

    57 , 49 , 41 , 33 , 25 , 17 , 9 ,

    1 , 58 , 50 , 42 , 34 , 26 , 18 ,

    10 , 2 , 59 , 51 , 43 , 35 , 27 ,

    19 , 11 , 3 , 60 , 52 , 44 , 36 ,

    63 , 55 , 47 , 39 , 31 , 23 , 15 ,

    7 , 62 , 54 , 46 , 38 , 30 , 22 ,

    14 , 6 , 61 , 53 , 45 , 37 , 29 ,

    21 , 13 , 5 , 28 , 20 , 12 , 4

};

//置換選擇2

char PC_2 [ 48 ] =

{

    14 , 17 , 11 , 24 , 1 , 5 ,

    3 , 28 , 15 , 6 , 21 , 10 ,

    23 , 19 , 12 , 4 , 26 , 8 ,

    16 , 7 , 27 , 20 , 13 , 2 ,

    41 , 52 , 31 , 37 , 47 , 55 ,

    30 , 40 , 51 , 45 , 33 , 48 ,

    44 , 49 , 39 , 56 , 34 , 53 ,

    46 , 42 , 50 , 36 , 29 , 32

};

//擴充置換Expansion

char Expansion [ 48 ] =

{

    32 , 1 , 2 , 3 , 4 , 5 ,

    4 , 5 , 6 , 7 , 8 , 9 ,

    8 , 9 , 10 , 11 , 12 , 13 ,

    12 , 13 , 14 , 15 , 16 , 17 ,

    16 , 17 , 18 , 19 , 20 , 21 ,

    20 , 21 , 22 , 23 , 24 , 25 ,

    24 , 25 , 26 , 27 , 28 , 29 ,

    28 , 29 , 30 , 31 , 32 , 1

};

//P盒置換

char PBox [ 32 ] = { 16 , 7 , 20 , 21 , 29 , 12 , 28 , 17 , 1 , 15 , 23 , 26 , 5 , 18 , 31 , 10 , 2 , 8 , 24 , 14 , 32 , 27 , 3 , 9 , 19 , 13 , 30 , 6 , 22 , 11 , 4 , 25 };

//S盒子

char SBox [ 8 ][ 4 ][ 16 ] =

{

    {

        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

    }

};

//密鑰移位次序(循環左移),左右28位分别循環左移的

char LM [ 16 ] = { 1 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 1 };

//按位輸出n個位元組

void printBit( uchar a [], int n)

{

    int i , j , bit;

    for( i = 0; i <n; i ++ ){

        for( j = 0; j < 8; j ++ ){

            bit = ( a [ i ] >> ( 7 - j)) & 0x01;

            printf( "%d" , bit);

        }

        if( i == n - 1) printf( " /n ");

        else printf( ",");

    }

}

//輸出n個位元組大小的數的16進制

void printHex( uchar a [], int n)

{

    int i , t;

    printf( "0x");

    for( i = 0; i <n; i ++ ){

        t = a [ i ]; //考慮到int在記憶體中的存儲(低低高高),就一個位元組一個位元組的存儲。

        if( t > 16 )

            printf( "%x" , t);

        else

            printf( "0%x" , t);

    }

    printf( " /n ");

}

//取bits位數的某位,為0傳回0,為1就傳回1

int GetBit( const uchar * number , int pos , int bits)

{

    assert( pos > 0 && pos <= bits);

    int i , j;

    pos --;

    i = pos / 8;

    j = pos % 8;

    return ( number [ i ] >> ( 7 - j)) & 0x01;

}

//使用bit數組來設定number的各位的值(共更改bits位)

void SetBit( uchar * number , int * bit , int bits)

{

    uchar t;

    int i , j , bytes;

    if( bits % 8 == 0) bytes = bits / 8;

    else bytes = bits / 8  + 1;

    for( i = 0; i < bytes; i ++ ){

        t = 0;

        for( j = 0; ( j < 8) && ( i * 8 + j < bits); j ++)

            t |= ( char)( bit [ i * 8 + j ] << ( 7 - j));

        number [ i ] = t;

    }

}

//初始換位

void ip( uchar LR [ 8 ])

{

    int i , bit [ 64 ];

    for( i = 0; i < 64; i ++)

        bit [ i ] = GetBit( LR , IP [ i ], 64);

    SetBit( LR , bit , 64);

}

//逆初始換位

void ip_1( uchar LR [ 8 ])

{

    int i , bit [ 64 ];

    for( i = 0; i < 64; i ++)

        bit [ i ] = GetBit( LR , IP_1 [ i ], 64);

    SetBit( LR , bit , 64);

}

//置換選擇1,從初始的64位密鑰中選取56位

void pc_1( const uchar password [ 8 ], uchar key [])

{

    int i , bit [ 56 ];

    for( i = 0; i < 56; i ++)

        bit [ i ] = GetBit( password , PC_1 [ i ], 64);

    SetBit( key , bit , 56);

}

//置換選擇2,從56位的CD(28b+28b)導出48為密鑰

void pc_2( const uchar CD [ 7 ], uchar K [ 6 ])

{

    int i , bit [ 48 ];

    for( i = 0; i < 48; i ++)

        bit [ i ] = GetBit( CD , PC_2 [ i ], 56);

    SetBit( K , bit , 48);

}

//對28位數循環左移n位,num[28]是01字元數組

void LeftMoveOf28Bit( int num [ 28 ], int n)

{

    int i , t;

    while(n -- ){

        t = num [ 0 ];

        for( i = 0; i < 27; i ++)

            num [ i ] = num [ i + 1 ];

        num [ 27 ] = t;

    }

}

//把56為的cd分成兩個28位,分别循環左移n位

void lm( uchar CD [ 7 ], int n)

{

    int i , bit [ 56 ], * C , * D;

    for( i = 0; i < 56; i ++)

        bit [ i ] = GetBit( CD , i + 1 , 56);

    C = bit;

    D = bit + 28;

    LeftMoveOf28Bit( C , n);

    LeftMoveOf28Bit( D , n);

    SetBit( CD , bit , 56);

}

//擴充置換,把Ri從32為擴充到48位

void expansion( const uchar Ri [ 4 ], uchar Re [ 6 ])

{

    int i , bit [ 48 ];

    for( i = 0; i < 48; i ++)

        bit [ i ] = GetBit( Ri , Expansion [ i ], 32);

    SetBit( Re , bit , 48);

}

//對前bits位進行異或操作,X=A^B

void XOR( const uchar * A , const uchar *B , uchar * X , int bits)

{

    int i , bytes;

    if( bits % 8 == 0) bytes = bits / 8;

    else bytes = bits / 8 + 1;

    //memset(X, 0, bytes);

    for( i = 0; i < bytes; i ++)

        X [ i ] = A [ i ] ^ B [ i ];

}

//設定a[1]~a[4],表示為二進制的x, x>=0 && x<=15

void sboxSetBit( int a [], int x)

{

    assert( x >= 0 && x <= 15);

    a [ 0 ] = ( x & 8) >> 3;

    a [ 1 ] = ( x & 4) >> 2;

    a [ 2 ] = ( x & 2) >> 1;

    a [ 3 ] = ( x & 1);

}

//S盒子操作

void sbox( uchar A [ 6 ], uchar B [ 4 ])

{

    int i , t , row , column , bitA [ 48 ], bitB [ 32 ];

    for( i = 0; i < 48; i ++)

        bitA [ i ] = GetBit( A , i + 1 , 48);

    //s盒子代換,由bitA[48]得到bitB[32]

    for( i = 0; i < 8; i ++ ){

        row = bitA [ i * 6 ] * 2 + bitA [ i * 6 + 5 ];

        column = bitA [ i * 6 + 1 ] * 8 + bitA [ i * 6 + 2 ] * 4 + bitA [ i * 6 + 3 ] * 2 + bitA [ i * 6 + 4 ];

        t = SBox [ i ][ row ][ column ];

        sboxSetBit( bitB + i * 4 , t); //t>=0 && t=<15,占4bit

    }

    SetBit(B , bitB , 32);

}

//P盒子操作

void pbox( uchar A [ 4 ])

{

    int i , bit [ 32 ];

    for( i = 0; i < 32; i ++)

        bit [ i ] = GetBit( A , PBox [ i ], 32);

    SetBit( A , bit , 32);

}

//輸入的明文是8個位元組長的帶加密字元,和密鑰

uchar * DES( const char str [ 8 ], const char password [ 8 ])

{

    int i;

    uchar LR [ 8 ], key [ 8 ], CD [ 7 ], K [ 16 ][ 6 ], LRi [ 16 ][ 8 ], Rie [ 6 ], xorResult [ 6 ], sResult [ 4 ];

    memcpy( LR , str , 8);

    memcpy( key , password , 8);

    //1、初始置換

    ip( LR);

    //2、置換選擇1

    //密鑰産生,置換選擇1,64位->56位

    pc_1( key , CD);

    //3、依次産生16組密鑰

    for( i = 0; i < 16; i ++ ){

        //3.1、把CD分成兩個28位,并分别循環移位

        lm( CD , LM [ i ]);

        //3.2、經過置換選擇2,從56位選出48為的K

        pc_2( CD , K [ i ]);

        //輸入子密鑰

        //printf("K%d=",i); printHex(K[i], 6);

    }

    //4、進行16輪的擴充置換和S盒子代換

    for( i = 0; i < 16; i ++ ){

        //4.1 設定Li = Ri-1

        if( i == 0) {

            memcpy( LRi [ 0 ], LR + 4 , 4);

        } else {

            memcpy( LRi [ i ], LRi [ i - 1 ] + 4 , 4); //Li=Ri-1

        }

        //4.2、擴充Ri

        if( i == 0 ){

            expansion( LR + 4 , Rie);

        } else {

            expansion( LRi [ i - 1 ] + 4 , Rie); //擴充Ri-1

        }

        //4.3、密鑰Ki與擴充後的分組異或

        XOR( K [ i ], Rie , xorResult , 48);

        //4.4、進行S盒子運算,将上步得到的48位的xorResult轉換成32位

        sbox( xorResult , sResult);

        //4.5、将上步得到的sResult做p盒子置換

        pbox( sResult);

        //4.6、繼續和Li-1做異或運算,結果儲存到Ri

        if( i == 0 ){

            XOR( sResult , LR , LRi [ 0 ] + 4 , 32);

        } else {

            XOR( sResult , LRi [ i - 1 ], LRi [ i ] + 4 , 32);

        }

        //輸出每輪的加密結果

        //printf("i=%-2d:",i); printHex(LRi[i],8);

    }

    //5、需要把最後一輪的左右兩部分互換一下

    uchar t_uchar [ 4 ];

    memcpy( t_uchar ,   LRi [ 15 ],   4);

    memcpy( LRi [ 15 ],   LRi [ 15 ] + 4 , 4);

    memcpy( LRi [ 15 ] + 4 , t_uchar ,   4);

    //6、逆初始置換

    ip_1( LRi [ 15 ]);

    uchar * EncryptStr = ( uchar *) malloc( 8);

    memcpy( EncryptStr , LRi [ 15 ], 8);

    return EncryptStr;

}

//DES解密

uchar * DES_1( const uchar str [ 8 ], const char password [ 8 ])

{

    int i;

    uchar LR [ 8 ], key [ 8 ], CD [ 7 ], K [ 16 ][ 6 ], LRi [ 16 ][ 8 ], Rie [ 6 ], xorResult [ 6 ], sResult [ 4 ];

    memcpy( LR , str , 8);

    memcpy( key , password , 8);

    //1、初始置換

    ip( LR);

    //2、置換選擇1

    //密鑰産生,置換選擇1,64位->56位

    pc_1( key , CD);

    //3、依次産生16組密鑰

    for( i = 0; i < 16; i ++ ){

        //3.1、把CD分成兩個28位,并分别循環移位

        lm( CD , LM [ i ]);

        //3.2、經過置換選擇2,從56位選出48為的K

        pc_2( CD , K [ i ]);

        //輸入子密鑰

        //printf("K%d=",i); printHex(K[i], 6);

    }

    //4、進行16輪的擴充置換和S盒子代換

    for( i = 0; i < 16; i ++ ){

        //4.1 設定Li = Ri-1

        if( i == 0) {

            memcpy( LRi [ 0 ], LR + 4 , 4);

        } else {

            memcpy( LRi [ i ], LRi [ i - 1 ] + 4 , 4); //Li=Ri-1

        }

        //4.2、擴充Ri

        if( i == 0 ){

            expansion( LR + 4 , Rie);

        } else {

            expansion( LRi [ i - 1 ] + 4 , Rie); //擴充Ri-1

        }

        //4.3、密鑰Ki與擴充後的分組異或

        XOR( K [ 15 - i ], Rie , xorResult , 48);

        //4.4、進行S盒子運算,将上步得到的48位的xorResult轉換成32位

        sbox( xorResult , sResult);

        //4.5、将上步得到的sResult做p盒子置換

        pbox( sResult);

        //4.6、繼續和Li-1做異或運算,結果儲存到Ri

        if( i == 0 ){

            XOR( sResult , LR , LRi [ 0 ] + 4 , 32);

        } else {

            XOR( sResult , LRi [ i - 1 ], LRi [ i ] + 4 , 32);

        }

        //輸出每輪的加密結果

        //printf("i=%-2d:",i); printHex(LRi[i],8);

    }

    //5、需要把最後一輪的左右兩部分互換一下

    uchar t_uchar [ 4 ];

    memcpy( t_uchar ,   LRi [ 15 ],   4);

    memcpy( LRi [ 15 ],   LRi [ 15 ] + 4 , 4);

    memcpy( LRi [ 15 ] + 4 , t_uchar ,   4);

    //6、逆初始置換

    ip_1( LRi [ 15 ]);

    uchar * EncryptStr = ( uchar *) malloc( 8);

    memcpy( EncryptStr , LRi [ 15 ], 8);

    return EncryptStr;

}

int main()

{

    char str [ 9 ], pass [ 9 ], str2 [ 9 ];

    uchar * result , * result2;

    while( 1 ){

        memset( str , 0 , 9);

        memset( str2 , 0 , 9);

        memset( pass , 0 , 9);

        scanf( "%s%s" , str , pass);

        //加密

        result = DES( str , pass);

        //解密

        result2 = DES_1( result , pass);

        uchar t;

        memcpy( & t , str , 8);

        printf( "明文的16進制  :");

        printHex( & t , 8); //輸出原文的16進制

        printf( "密文的16進制  :");

        printHex( result , 8); //輸出密文

        printf( "解密後的16進制:");

        printHex( result2 , 8); //輸出解密後的16進制

        printf( "解密後的字元  :");

        memcpy( str2 , result2 , 8); //輸出解密的結果(字元)

        printf( "%s /n/n " , str2);

        free( result2); result2 = NULL;

        free( result); result = NULL;

    }

    return 0;

}

上一篇: DES CBC