DES实现

C++语言: Codee#13635
/*
DES加密,主要参考1:《网络安全:加密原理、算法与协议》,金名等译,清华大学出版社
主要参考2:《口令破解与加密技术》 胡志远
*/

#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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

piaopiaolanghua

感谢老板鼓励~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值