溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

c語言怎么實現DES加密解密

發布時間:2023-04-28 15:47:24 來源:億速云 閱讀:177 作者:iii 欄目:開發技術

這篇文章主要介紹“c語言怎么實現DES加密解密”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“c語言怎么實現DES加密解密”文章能幫助大家解決問題。

    c語言實現DES加密解密

    #include "des.h"
    //移位表
    static Table_size const shiftTable[NumberOfKeys] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
    //E擴展表
    static Table_size const eTable[des_key_pc2_standard]={
    	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置換表
    static Table_size const pTable[des_data_rl]={
    	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
    };
    //數據初始置換表
    static Table_size const ip0Table[des_standard] = {
        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
    };
    //ip1表
    static Table_size const ip1Table[des_standard]={              
    	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 
    };
    //子密鑰pc1置換表
    static Table_size const desSubkeyPc1[des_key_pc1_standard] = {
        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
    };
    //子密鑰pc2置換表
    static Table_size const desSubkeyPc2[des_key_pc2_standard]={
    	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, 34, 33, 48, 44, 49, 39, 56,
        34, 53, 46, 42, 50, 36, 29, 32 
    };
    //S盒表
    static Table_size const sBoxTable[8][4][16]={
     //S1
    	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,
     //S2
    	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,
     //S3
    	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,
     //S4
    	 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,
     //S5
    	 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,
     //S6
    	12,  1, 10, 15, 9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
    	10, 15,  4,  2, 7, 12,  0,  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,
     //S7
    	 4, 11,  2, 14, 15, 0,  8, 13,  3, 12, 9,  7,  5, 10, 6,  1,
    	13,  0, 11,  7,  4, 0,  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,
     //S8
    	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
    };
    /*
     *  函數功能:生成16個6字節子密鑰
     *  參數:<key>傳入8字節密鑰,<key_lenght>密鑰長度必須是8字節
     *  返回值:返回16*(48/8)字節大小的16個子密鑰
     *  注釋:返回值要釋放
     */
    subkey_size __desSubKeyGeneration(subkey_size key, data_lenght_size key_lenght)
    {
        //如果傳入空或長度不為8字節則返回空
        if(key==NULL || key_lenght!=8)
            return NULL;
        //申請堆內存
        subkey_size subkey16 = (subkey_size)malloc(NumberOfKeys * (des_key_pc2_standard / systemBit));
        //清空初始化,按照申請內存大小來清空這塊堆內存
        memset(subkey16, 0, NumberOfKeys * (des_key_pc2_standard / systemBit));
        //創建布爾型的數組,讓移位代碼實現更簡單
        int count = 0;
        bool tmp = 0;
        bool bit_table_pc1[des_key_pc1_standard]={0};   //pc1的56位數據
        bool bit_table[des_standard]={0};   //64位數據
        //將數據賦值到布爾型數組里面
        for(int i=0; i<des_standard; i++)
            bit_table[i] = BIT_JUDGE(*(key + i / systemBit), (i % systemBit));
        //進行PC1轉換
        for(int i=0; i<des_key_pc1_standard; i++)
            bit_table_pc1[i] = bit_table[desSubkeyPc1[i]-1];
        //進行十六次密鑰生成
        for(int num=0; num<NumberOfKeys; num++)
        {
            //保存移位次數
            count = shiftTable[num];
            //進行移位
            while(count--)
            {
                //前二十八位移位
                tmp = bit_table_pc1[0];
                for(int i=0; i<28; i++)
                    bit_table_pc1[i]=bit_table_pc1[i+1];
                bit_table_pc1[27]=tmp;
                //后二十八位移位
                tmp = bit_table_pc1[28];
                for(int i=28; i<56; i++)
                    bit_table_pc1[i]=bit_table_pc1[i+1];
                bit_table_pc1[55]=tmp;
            }
            //進行判斷寫入新的數據
            for(int i=0; i<des_key_pc2_standard; i++)
            {
                if(bit_table_pc1[desSubkeyPc2[i]-1])
                    SET_BIT_NUMBER(*(subkey16 + (num * (des_key_pc2_standard / systemBit)) + (i / systemBit)), (i % systemBit));
                else RESET_BIT_NUMBER(*(subkey16 + (num * (des_key_pc2_standard / systemBit)) + (i / systemBit)), (i % systemBit));
            }
        }
        //返回子密鑰
        return subkey16;
    }
    /*
     *  函數功能:進行數據加密
     *  參數:<data>傳入8整數倍字節數據,<data_lenght>數據長度,<key>16*(48/8)字節大小的16個子密鑰,<key_lenght>必須是6*16長度
     *  返回值:返回加密后的數據
     *  注釋:返回值要釋放
     */
    data_size __desDataEncryption(data_size data, data_lenght_size data_lenght, subkey_size key, data_lenght_size key_lenght)
    {
        //如果傳入空或長度不為8字節則返回空
        if(key==NULL || key_lenght!=(NumberOfKeys*(des_key_pc2_standard/systemBit)) || data==NULL || data_lenght!=8)
            return NULL;
        //申請堆內存
        data_size Data16 = (data_size)malloc(des_standard/8);
        //清空初始化,按照申請內存大小來清空這塊堆內存
        memset(Data16, 0, (des_standard/8));
        //創建一個布爾型的數組,將移位操作變得簡單
        bool bit_table[des_standard]={0};   //64位數據
        bool data64_table[des_standard]={0};    //64位數據
        bool extend48_table[des_key_pc2_standard]={0};  //pc2表的48位數據
        bool dataL32_table[des_data_rl]={0};    //64位數據的左32
        bool dataR32_table[des_data_rl]={0};    //64位數據的右32
        bool tmpL32_table[des_data_rl]={0}; //臨時64位數據的左32
        bool tmpR32_table[des_data_rl]={0}; //臨時64位數據的右32
        //將數據賦值到布爾型數組里面
        for(int i=0; i<des_standard; i++)
            bit_table[i] = BIT_JUDGE(*(data + (i / systemBit)), (i % systemBit));
        //進行初始置換
        for(int i=0; i<des_standard; i++)
            data64_table[i] = bit_table[ip0Table[i]-1];
        //將64位一分為二
        for(int i=0; i<des_data_rl; i++)
            dataL32_table[i] = data64_table[i];
        for(int i=0; i<des_data_rl; i++)
            dataR32_table[i] = data64_table[i+32];
        //   列    行
        int row=0, col=0;
        //進行十六次輪函數
        for(int num=0; num<NumberOfKeys; num++)
        {
            //將R數組賦值給L的臨時數組
            for(int i=0; i<des_data_rl; i++) 
                tmpL32_table[i] = dataR32_table[i];
            //將R數組進行E擴展
            for(int i=0; i<des_key_pc2_standard; i++)
                extend48_table[i] = dataR32_table[(eTable[i]-1)];
            //將E擴展后48位和子密鑰進行異或
            for(int i=0; i<des_key_pc2_standard; i++) 
                extend48_table[i] = extend48_table[i] ^ (BIT_JUDGE(*(key + (num * (des_key_pc2_standard / systemBit)) + i / systemBit), (i % systemBit)));  
            //將48位轉換成32位
            for(int j=0; j<des_key_pc2_standard; j+=6) 
            {
                //計算出行列
                row = extend48_table[j+0]*2 + extend48_table[j+5]*1;
                col = extend48_table[j+1]*8 + extend48_table[j+2]*4 + extend48_table[j+3]*2 + extend48_table[j+4]*1;
                //進行查表,并將10進制轉換為四位二進制
                for(int i=0; i<4; i++) 
                    dataR32_table[((j/6)*4)+i] = BIT_JUDGE(sBoxTable[j/6][row][col], i);
            }
            //將R進行轉換并存入R臨時數組
            for(int i=0; i<des_data_rl; i++) 
                tmpR32_table[i] = dataR32_table[pTable[i]-1];
            //在用臨時數組進行異或
            for(int i=0; i<des_data_rl; i++)
            {
                dataR32_table[i] = (dataL32_table[i] ^ tmpR32_table[i]);
            }
            //最后將剛才的L臨時數組賦值
            for(int i=0; i<des_data_rl; i++)
                dataL32_table[i] = tmpL32_table[i];
        }
        //將兩個32位進行拼接
        for(int i=0; i<des_data_rl; i++)
            data64_table[i] = dataL32_table[i];
        for(int i=des_data_rl; i<des_standard; i++)
            data64_table[i] = dataR32_table[i-32];
        //進行判斷寫入新的數據
        for(int i=0; i<des_standard; i++)
        {
            if(data64_table[ip1Table[i]-1])
                SET_BIT_NUMBER(*(Data16 + (i / systemBit)), (i % systemBit));
            else RESET_BIT_NUMBER(*(Data16 + (i / systemBit)), (i % systemBit));
        }
        //返回數據
        return Data16;
    }
    /*
     *  函數功能:進行數據解密
     *  參數:<data>傳入加密后數據,<data_lenght>加密后數據長度,<key>16*(48/8)字節大小的16個子密鑰,<key_lenght>必須是6*16長度
     *  返回值:返回解密后的數據
     *  注釋:返回值要釋放
     */
    data_size __desDataDecrypt(data_size data, data_lenght_size data_lenght, subkey_size key, data_lenght_size key_lenght)
    {
        //如果傳入空或長度不為8字節則返回空
        if(key==NULL || key_lenght!=(NumberOfKeys*(des_key_pc2_standard/systemBit)) || data==NULL || data_lenght!=8)
            return NULL;
        //申請堆內存
        data_size Data16 = (data_size)malloc(des_standard/8);
        //清空初始化,按照申請內存大小來清空這塊堆內存
        memset(Data16, 0, (des_standard/8));
        //創建一堆布爾型的數組,將移位操作變得簡單
        bool bit_table[des_standard]={0};   //64位數據
        bool data64_table[des_standard]={0};    //64位數據
        bool extend48_table[des_key_pc2_standard]={0};  //pc2表48位數據
        bool dataL32_table[des_data_rl]={0};    //64位數據的左32位
        bool dataR32_table[des_data_rl]={0};    //64位數據的右32位
        bool tmpL32_table[des_data_rl]={0}; //臨時64位數據的左32位
        bool tmpR32_table[des_data_rl]={0}; //臨時64位數據的右32位
        //將數據賦值到布爾型數組里面
        for(int i=0; i<des_standard; i++)
            bit_table[i] = BIT_JUDGE(*(data + (i / systemBit)), (i % systemBit));
        //進行初始置換
        for(int i=0; i<des_standard; i++)
            data64_table[i] = bit_table[ip0Table[i]-1];
        //將64位一分為二
        for(int i=0; i<des_data_rl; i++)
            dataR32_table[i] = data64_table[i];
        for(int i=0; i<des_data_rl; i++)
            dataL32_table[i] = data64_table[i+32];
        //   列    行
        int row=0, col=0;
        //進行十六次輪函數(反著來)
        for(int num=(NumberOfKeys-1); num>=0; num--)
        {
            //將R數組賦值給L的臨時數組
            for(int i=0; i<des_data_rl; i++) 
                tmpL32_table[i] = dataR32_table[i];
            //將R數組進行E擴展
            for(int i=0; i<des_key_pc2_standard; i++)
                extend48_table[i] = dataR32_table[(eTable[i]-1)];
            //將E擴展后48位和子密鑰進行異或
            for(int i=0; i<des_key_pc2_standard; i++) 
                extend48_table[i] = extend48_table[i] ^ (BIT_JUDGE(*(key + (num * (des_key_pc2_standard / systemBit)) + i / systemBit), (i % systemBit)));  
            //將48位轉換成32位
            for(int j=0; j<des_key_pc2_standard; j+=6) 
            {
                //計算出行列
                row = extend48_table[j+0]*2 + extend48_table[j+5]*1;
                col = extend48_table[j+1]*8 + extend48_table[j+2]*4 + extend48_table[j+3]*2 + extend48_table[j+4]*1;
                //進行查表,并將10進制轉換為四位二進制
                for(int i=0; i<4; i++) 
                    dataR32_table[((j/6)*4)+i] = BIT_JUDGE(sBoxTable[j/6][row][col], i);
            }
            //將R進行轉換并存入R臨時數組
            for(int i=0; i<des_data_rl; i++) 
                tmpR32_table[i] = dataR32_table[pTable[i]-1];
            //在用臨時數組進行異或
            for(int i=0; i<des_data_rl; i++) 
            {
                dataR32_table[i] = (dataL32_table[i] ^ tmpR32_table[i]);
            }
            //最后將剛才的L臨時數組賦值
            for(int i=0; i<des_data_rl; i++) 
                dataL32_table[i] = tmpL32_table[i];
        }
        //將兩個32位進行拼接
        for(int i=0; i<des_data_rl; i++)
            data64_table[i] = dataR32_table[i];
        for(int i=des_data_rl; i<des_standard; i++)
            data64_table[i] = dataL32_table[i-32];
        //進行判斷寫入新的數據
        for(int i=0; i<des_standard; i++)
        {
            if(data64_table[ip1Table[i]-1])
                SET_BIT_NUMBER(*(Data16 + (i / systemBit)), (i % systemBit));
            else RESET_BIT_NUMBER(*(Data16 + (i / systemBit)), (i % systemBit));
        }
        //返回數據
        return Data16;
    }
    /*
     *  函數功能:將數據進行DES加密
     *  參數:<data>要加密的數據,<data_lenght>要加密的數據長度,<key>進行加密的密鑰,<key_lenght>密鑰的長度(8字節),<fillingMode>數據補位的模式選擇
     *  返回值:返回一個結構體,結構體內有加密后數據和加密后數據長度
     */
    p_desRetStruct desEncryption(data_size data, data_lenght_size data_lenght, subkey_size key, data_lenght_size key_lenght, enumFillingMode fillingMode)
    {
        if(key_lenght != 8 || (fillingMode != NOPADDING && fillingMode != PKCS5PADDING))
        {
            return NULL;
        }
        //申請堆內存
        p_desRetStruct retData = (p_desRetStruct)malloc(sizeof(desRetStruct));
        //清空這塊內存
        memset(retData, 0, sizeof(desRetStruct));
        //計算出長度
        data_lenght_size mallocLenght = ((data_lenght%8==0)?(data_lenght):(((data_lenght/8)*8)+8));
        //申請堆內存
        retData->data = (data_size)malloc(mallocLenght);
        //長度進行賦值
        retData->dataLenght = mallocLenght;
        //清空這塊內存
        memset(retData->data, 0, mallocLenght);
        //進行賦值
        memcpy(retData->data, data, data_lenght);
        //如果是長度是8的整數倍
        if(fillingMode == PKCS5PADDING && data_lenght % 8 != 0)
        {
            for(int i=0;i<8-(data_lenght%8);i++)
            {
                unsigned char num = (8 - (data_lenght % 8));
                //進行拷貝
                memcpy(retData->data + data_lenght + i, &num, 1);
            }
        }
        //獲取16個子密鑰
        subkey_size subkey16 = __desSubKeyGeneration(key, key_lenght);
        //進行循環每8字節進行加密
        for(int i=0; i<mallocLenght; i+=8)
        {
            //將8字節進行加密
            data_size mData = __desDataEncryption(retData->data + i, 8, subkey16, 96);
            //將加密后字節拷貝到返回值上
            memcpy(retData->data + i, mData, 8);
            //釋放
            free(mData);
        }
        //釋放16個子密鑰
        free(subkey16);
        //返回加密后的數據
        return retData;
    }
    /*
     *  函數功能:將DES加密數據進行解密
     *  參數:<data>要解密的數據,<data_lenght>要解密的數據長度(8的整數倍字節),<key>進行解密的密鑰,<key_lenght>密鑰的長度(8字節),<fillingMode>數據補位的模式選擇
     *  返回值:返回一個結構體,結構體內有解密后數據和解密后數據長度
     */
    p_desRetStruct desDecrypt(data_size data, data_lenght_size data_lenght, data_size key, data_lenght_size key_lenght, enumFillingMode fillingMode)
    {
        if(key_lenght != 8 || (fillingMode != NOPADDING && fillingMode != PKCS5PADDING) || data_lenght%8 != 0 || data_lenght == 0)
        {
            return NULL;
        }
        //申請堆內存
        p_desRetStruct retData = (p_desRetStruct)malloc(sizeof(desRetStruct));
        //清空這塊內存
        memset(retData, 0, sizeof(desRetStruct));
        //申請堆內存
        retData->data = (data_size)malloc(data_lenght);
        //長度進行賦值
        retData->dataLenght = data_lenght;
        //清空這塊內存
        memset(retData->data, 0, data_lenght);
        //獲取16個子密鑰
        subkey_size subkey16 = __desSubKeyGeneration(key, key_lenght);
        //進行循環每8字節進行解密
        for(int i=0; i<data_lenght; i+=8)
        {
            //將8字節進行解密
            data_size mData = __desDataDecrypt(data + i, 8, subkey16, 96);
            //將解密后字節拷貝到返回值上
            memcpy(retData->data + i, mData, 8);
            //釋放
            free(mData);
        }
        //按照8-(n%8)補位方式解密
        if(fillingMode == PKCS5PADDING)
        {
            //如果最后一位是0x01~0x07
            if(0x01 <= *(retData->data + (data_lenght - 1)) && *(retData->data + (data_lenght - 1)) <= 0x07)
            {
                //進行8-模次循環
                for(int count=1; count<=*(retData->data + (data_lenght - 1)); count++)
                {
                    //判斷是否和最后一字節相等
                    if(*(retData->data + (data_lenght - 1)) == *(retData->data + (data_lenght - count)))
                    {
                        retData->dataLenght--;
                    }
                    else
                    {
                        //如果有一次不相等就說明該數據沒有補位
                        retData->dataLenght = data_lenght;
                        //退出循環
                        break;
                    }
                }
            }
        }
        //按照\0補位方式解密
        else if(fillingMode == NOPADDING)
        {
            //從尾部開始進行8次判斷
            for(int count=1; count<=8; count++)
            {
                //如果這一字節等于0就位去掉
                if(0x00 == *(retData->data + (data_lenght - count)))
                {
                    //將長度進行減1
                    retData->dataLenght--;
                }
                else
                {
                    //遇到正常數據進行退出循環
                    break;
                }
            }
        }
        //釋放16個子密鑰
        free(subkey16);
        //返回加密后的數據
        return retData;
    }
    /*
     *  函數功能:將數據進行3DES加密
     *  參數:<data>要加密的數據,<data_lenght>要加密的數據長度,<key>進行加密的密鑰,<key_lenght>密鑰的長度(24字節),<fillingMode>數據補位的模式選擇
     *  返回值:返回一個結構體,結構體內有加密后數據和加密后數據長度
     */
    p_desRetStruct _3desEncryption(data_size data, data_lenght_size data_lenght, subkey_size key, data_lenght_size key_lenght, enumFillingMode fillingMode)
    {
        if(key_lenght != 24 || (fillingMode != NOPADDING && fillingMode != PKCS5PADDING))
        {
            return NULL;
        }
        //申請堆內存
        p_desRetStruct retData = (p_desRetStruct)malloc(sizeof(desRetStruct));
        //清空這塊內存
        memset(retData, 0, sizeof(desRetStruct));
        //計算出長度
        data_lenght_size mallocLenght = ((data_lenght%8==0)?(data_lenght):(((data_lenght/8)*8)+8));
        //申請堆內存
        retData->data = (data_size)malloc(mallocLenght);
        //長度進行賦值
        retData->dataLenght = mallocLenght;
        //清空這塊內存
        memset(retData->data, 0, mallocLenght);
        //進行賦值
        memcpy(retData->data, data, data_lenght);
        //如果是長度是8的整數倍
        if(fillingMode == PKCS5PADDING && data_lenght % 8 != 0)
        {
            for(int i=0;i<8-(data_lenght%8);i++)
            {
                unsigned char num = (8 - (data_lenght % 8));
                //進行拷貝
                memcpy(retData->data + data_lenght + i, &num, 1);
            }
        }
        //獲取16個子密鑰
        subkey_size subkey1 = __desSubKeyGeneration(key, 8);
        //獲取16個子密鑰
        subkey_size subkey2 = __desSubKeyGeneration(key+(key_lenght/3), 8);
        //獲取16個子密鑰
        subkey_size subkey3 = __desSubKeyGeneration(key+((key_lenght/3)*2), 8);
        //進行循環每8字節進行加密
        for(int i=0; i<mallocLenght; i+=8)
        {
            //將8字節進行加密
            data_size mData1 = __desDataEncryption(retData->data + i, 8, subkey1, 96);
            data_size mData2 = __desDataDecrypt(mData1, 8, subkey2, 96);
            data_size mData3 = __desDataEncryption(mData2, 8, subkey3, 96);
            //將加密后字節拷貝到返回值上
            memcpy(retData->data + i, mData3, 8);
            //釋放
            free(mData1);
            free(mData2);
            free(mData3);
        }
        //釋放子密鑰
        free(subkey1);
        free(subkey2);
        free(subkey3);
        //返回加密后的數據
        return retData;
    }
    /*
     *  函數功能:將3DES加密數據進行解密
     *  參數:<data>要解密的數據,<data_lenght>要解密的數據長度(8的整數倍字節),<key>進行解密的密鑰,<key_lenght>密鑰的長度(24字節),<fillingMode>數據補位的模式選擇
     *  返回值:返回一個結構體,結構體內有解密后數據和解密后數據長度
     */
    p_desRetStruct _3desDecrypt(data_size data, data_lenght_size data_lenght, data_size key, data_lenght_size key_lenght, enumFillingMode fillingMode)
    {
        if(key_lenght != 24 || (fillingMode != NOPADDING && fillingMode != PKCS5PADDING) || data_lenght%8 != 0 || data_lenght == 0)
        {
            return NULL;
        }
        //申請堆內存
        p_desRetStruct retData = (p_desRetStruct)malloc(sizeof(desRetStruct));
        //清空這塊內存
        memset(retData, 0, sizeof(desRetStruct));
        //申請堆內存
        retData->data = (data_size)malloc(data_lenght);
        //長度進行賦值
        retData->dataLenght = data_lenght;
        //清空這塊內存
        memset(retData->data, 0, data_lenght);
        //獲取16個子密鑰
        subkey_size subkey1 = __desSubKeyGeneration(key, 8);
        //獲取16個子密鑰
        subkey_size subkey2 = __desSubKeyGeneration(key+(key_lenght/3), 8);
        //獲取16個子密鑰
        subkey_size subkey3 = __desSubKeyGeneration(key+((key_lenght/3)*2), 8);
        //進行循環每8字節進行解密
        for(int i=0; i<data_lenght; i+=8)
        {
            //將8字節進行加密
            data_size mData1 = __desDataDecrypt(data + i, 8, subkey3, 96);
            data_size mData2 = __desDataEncryption(mData1, 8, subkey2, 96);
            data_size mData3 = __desDataDecrypt(mData2, 8, subkey1, 96);
            //將解密后字節拷貝到返回值上
            memcpy(retData->data + i, mData3, 8);
            //釋放
            free(mData1);
            free(mData2);
            free(mData3);
        }
        //按照8-(n%8)補位方式解密
        if(fillingMode == PKCS5PADDING)
        {
            //如果最后一位是0x01~0x07
            if(0x01 <= *(retData->data + (data_lenght - 1)) && *(retData->data + (data_lenght - 1)) <= 0x07)
            {
                //進行(8-模)次循環
                for(int count=1; count<=*(retData->data + (data_lenght - 1)); count++)
                {
                    //判斷是否和最后一字節相等
                    if(*(retData->data + (data_lenght - 1)) == *(retData->data + (data_lenght - count)))
                    {
                        retData->dataLenght--;
                    }
                    else
                    {
                        //如果有一次不相等就說明該數據沒有補位
                        retData->dataLenght = data_lenght;
                        //退出循環
                        break;
                    }
                }
            }
        }
        //按照\0補位方式解密
        else if(fillingMode == NOPADDING)
        {
            //從尾部開始進行8次判斷
            for(int count=1; count<=8; count++)
            {
                //如果這一字節等于0就位去掉
                if(0x00 == *(retData->data + (data_lenght - count)))
                {
                    //將長度進行減1
                    retData->dataLenght--;
                }
                else
                {
                    //遇到正常數據進行退出循環
                    break;
                }
            }
        }
        //釋放16個子密鑰
        free(subkey1);
        free(subkey2);
        free(subkey3);
        //返回加密后的數據
        return retData;
    }
    /*                        DES全稱->數據加密標準->它出自IBM的研究工作(本描述大致步驟細節需要看代碼)
     *    數據=由8的整數倍構成(單位字節)(不足8字節可以補位)      密鑰=固定由64位(即8字節)組成(其中8位為校驗位不影響結果)
     *            (每個字節(0~255)任意選取)                            (每個字節(0~255)任意選取)
     *                       ↓                                                ↓
     *         進行ip置換將64位數據每個位進行移位             進行PC1轉換(轉換前64)(轉換后將8位校驗位舍棄)(并且進行移位)
     *                       ↓                           →→→→→→→→→→→→→→→→→→→→→↓→→→→→→→→→→→→→→→→→→→→→↓
     *     將64位數據一分為二變成左右兩個部分(分別32位)         ↓   一分為二(分別28位)分別移位(每輪移位次數不同) ↓ 
     *           ↓                     ↓                  ↓                   ↓                     ↓
     *         左32位                 右32位                ↓ 進行PC2轉換(轉換前56)(轉換后48)(并且進行移位)↓
     *           ↓                     ↓                   ↓←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←↓
     *        (左32位      異或    f(右32位, key))←←←←←←←←←←←進行16次循環(每一次產生48位key與右32位進行輪函數)            
     *        (左32位和f(右32位, key))進行異或運算)                 (解密時將16個48位key反著進行輪函數)
     *      運算結果成為新的右32位并將右32位賦值給左32位
     *             產生新的左32位和右32位                             f(右32位, key)f輪函數步驟
     *           ↓                      ↓                             右32位進行E擴展為48位  
     *新左32位=舊左32位^f(舊右32位, key))  新右32位=舊左32位             擴展后48位和48位key進行異或
     *    (進行16次循環結束后將兩個32進行合并并且進行終止置換)            將異或后48位進入S盒壓縮為32結束
     *           (終止置換完,成為des加密數據)
     *            解密的兩個條件  =  (解密時將16個48位key反著進行輪函數)  +  (圖上的左右32位反著運算)
     *                    不足8整數倍字節時可以全部補位0,也可以補位(8-(數據長度(單位字節)%8))
     */
    /*                                              3DES
     * E表示加密 D表示解密 K1表示密鑰1 K2表示密鑰2 K3表示密鑰3 P表示明文 C表示密文 EK1表示使用K1密鑰進行加密 DK1表示使用K1密鑰進行解密
     * 加密:C = EK3( DK2( EK1(P)) ),即對明文數據進行,加密 -> 解密 -> 加密的過程,最后得到密文數據;
     * 解密:P = DK1( EK2( DK3(C)) ),即對密文數據進行,解密 -> 加密 -> 解密的過程,最后得到明文數據;
     */
    #ifndef DES_H
    #define DES_H
    #ifdef __cplusplus
    extern "C"
    {
    #endif
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdbool.h>
    /*程序示例*//*
    unsigned char key[24] = {'1','2','3','4','5','6','7','8', 0x34, 0x45, 0xA4, 0x34, 0x45, 0xA4, 0x45, 0xA4, 0x45, 0xA4, 0x34, 0x45, 0x45, 0xA4, 0x34, 0x45,};
    unsigned char _data[33] = {'1','2','3','4','5','6', '7', '8', '1','2','3','4','5','6', '7', '8',
    '1','2','3','4','5','6', '7', '8','1','2','3','4','5','6', '7', '8', '1'
    };
    p_desRetStruct retData = _3desEncryption(_data, 33, key, 24, NOPADDING);
    p_desRetStruct mData = _3desDecrypt(retData->data, retData->dataLenght, key, 24, NOPADDING);
    printf("加密后數據十六進制:");
    for(int num=0; num<retData->dataLenght; num++)
        printf("0x%02X ", *(retData->data+num));
    printf("\n");
    printf("解密后原數據:");
    for(int num=0; num<mData->dataLenght; num++)
        printf("%c ",*(mData->data+num));
    printf("\n");
    *//*程序示例*/
    //將某個位清零
    #define RESET_BIT_NUMBER(UA, BIT_NUMBER) ( (UA) &= ( ~ ( 1 << (BIT_NUMBER) ) ) )
    //將某個位置一
    #define SET_BIT_NUMBER(UA, BIT_NUMBER) ( (UA) |= ( 1 << (BIT_NUMBER) ) )
    //判斷某個位是1還是0
    #define BIT_JUDGE(UA, BIT_NUMBER) ( ( (UA) >> (BIT_NUMBER) ) & 1 )
    //des標準下各種位數
    #define des_standard 64
    #define des_key_pc1_standard 56
    #define des_key_pc2_standard 48 
    #define des_data_rl 32 
    #define NumberOfKeys 16
    #define systemBit 8
    //數據類型
    #define Table_size unsigned char 
    #define data_lenght_size unsigned int 
    #define data_size unsigned char *
    #define subkey_size unsigned char *
    //補位方式
    typedef enum
    {
        NOPADDING    = 0,   //按照\0補位
        PKCS5PADDING = 1    //按照余8取(模)補位
    }enumFillingMode;
    //枚舉
    typedef struct desNode
    {
        data_size data;                 //返回的數據指針
        data_lenght_size dataLenght;    //返回的數據長度
    }desRetStruct, *p_desRetStruct;
    //  結構體別名    結構體指針別名
    /*
     *  函數功能:將數據進行DES加密
     *  參數:<data>要加密的數據,<data_lenght>要加密的數據長度,<key>進行加密的密鑰,<key_lenght>密鑰的長度(8字節),<fillingMode>數據補位的模式選擇
     *  返回值:返回一個結構體,結構體內有加密后數據和加密后數據長度
     */
    p_desRetStruct desEncryption(data_size data, data_lenght_size data_lenght, subkey_size key, data_lenght_size key_lenght, enumFillingMode fillingMode);
    /*
     *  函數功能:將DES加密數據進行解密
     *  參數:<data>要解密的數據,<data_lenght>要解密的數據長度(8的整數倍字節),<key>進行解密的密鑰,<key_lenght>密鑰的長度(8字節),<fillingMode>數據補位的模式選擇
     *  返回值:返回一個結構體,結構體內有解密后數據和解密后數據長度
     */
    p_desRetStruct desDecrypt(data_size data, data_lenght_size data_lenght, subkey_size key, data_lenght_size key_lenght, enumFillingMode fillingMode);
    /*
     *  函數功能:將數據進行3DES加密
     *  參數:<data>要加密的數據,<data_lenght>要加密的數據長度,<key>進行加密的密鑰,<key_lenght>密鑰的長度(24字節),<fillingMode>數據補位的模式選擇
     *  返回值:返回一個結構體,結構體內有加密后數據和加密后數據長度
     */
    p_desRetStruct _3desEncryption(data_size data, data_lenght_size data_lenght, subkey_size key, data_lenght_size key_lenght, enumFillingMode fillingMode);
    /*
     *  函數功能:將3DES加密數據進行解密
     *  參數:<data>要解密的數據,<data_lenght>要解密的數據長度(8的整數倍字節),<key>進行解密的密鑰,<key_lenght>密鑰的長度(24字節),<fillingMode>數據補位的模式選擇
     *  返回值:返回一個結構體,結構體內有解密后數據和解密后數據長度
     */
    p_desRetStruct _3desDecrypt(data_size data, data_lenght_size data_lenght, subkey_size key, data_lenght_size key_lenght, enumFillingMode fillingMode);
    #ifdef __cplusplus
    }
    #endif
    #endif //DES_H

    C語言DES加密解密的認識以及解密出現亂碼的分析

    在工作中遇到的Des解密問題,第三方發來的數據需要我們進行des解密,但是解密的結果前幾位始終是亂碼。廢了半天勁,終于找到了問題所在。

    下面先介紹一下des,了解des的同學可以直接看下面的解決辦法。

    Des加密

    DES全稱為Data EncryptionStandard,即數據加密標準。Des加密算法是一種對稱加密算法,所謂對稱加密算法就是指對明文的加密以及對密文的解密用的是同一個密鑰。

    Des使用一個56位的密鑰以及附加的8位奇偶校驗位,產生最大64位的分組大小。這是一個迭代的分組密碼,使用稱為 Feistel 的技術,其中將加密的文本塊分成兩半。使用子密鑰對其中一半應用循環功能,然后將輸出與另一半進行“異或”運算;接著交換這兩半,這一過程會繼續下去,但最后一個循環不交換。DES 使用 16 個循環,使用異或,置換,代換,移位操作四種基本運算。

    特點:數據加密標準,速度較快,適用于加密大量數據的場合。

    Des算法的入口參數有三個:Key、Data、Mode。

    • Key: 為8個字節共64位,Des算法規定,其中第8、16、24、......64位是奇偶校驗位,不參與Des運算,所以常說Des的密鑰為56位。 在Des加密和解密的過程當中,密鑰的長度都必須是8字節的倍數。

    • Data: 8個字節64位,是要被加密后解密的數據。

    • Mode: Des的工作方式:加密、解密。

    Des加密模式

    Des的加密模式主要有CBC模式,ECB模式,它們分別使用不同的加密方式加密。

    ECB模式指的是電子密碼本模式,是一種最古老,最簡單的模式,將加密的數據分成若干組,每組的大小跟加密密鑰長度相同;然后每組都用相同的密鑰加密, 如果最后一個分組長度不夠64位,要補齊64位。

    ECB模式的特點是:

    • 每次Key、明文、密文的長度都必須是64位;

    • 數據塊重復排序不需要檢測;

    • 相同的明文塊(使用相同的密鑰)產生相同的密文塊,容易遭受字典攻擊;

    • 一個錯誤僅僅會對一個密文塊產生影響;

    CBC模式指的是加密塊鏈模式,與ECB模式最大的不同是加入了初始向量。

    CBC模式的特點是:

    • 每次加密的密文長度為64位(8個字節);

    • 當相同的明文使用相同的密鑰和初始向量的時候CBC模式總是產生相同的密文;

    • 密文塊要依賴以前的操作結果,所以,密文塊不能進行重新排列;

    • 可以使用不同的初始化向量來避免相同的明文產生相同的密文,一定程度上抵抗字典攻擊;

    • 一個錯誤發生以后,當前和以后的密文都會被影響;

    填充方式

    常見的填充方式PKCS5Padding,PKCS5Padding表示當數據位數不足的時候要采用的數據補齊方式,也可以叫做數據填充方式。PKCS5Padding這種填充方式,具體來說就是“填充的數字代表所填字節的總數”

    比如說,差兩個字節,就是######22,差5個字節就是###55555,這樣根據最后一個自己就可以知道填充的數字和數量。

    保證加密解密的一致性 

    在不同的平臺上,只要能保證這幾個參數的一致,就可以實現加密和解密的一致性。

    • 加密和解密的密鑰一致

    • 采用CBC模式的時候,要保證初始向量一致

    • 采用相同的填充模式

    python中的des加密

    在python中,我們使用pyDes對數據進行des加密:

    # pyDes.des(key, [mode], [IV], [pad], [padmode])
    • key:des的加密解密密鑰。

    • mode: 加密模式:支持CBC,ECB兩種模式

    • IV: 初始化向量,這是CBC模式專有的,長度為8 bytes。使用不同的初始化向量加密避免產生相同的密文,一定程度上抵抗字典攻擊。

    • pad: 當padmode設置為PAD_NORMAL時,用pad參數來指定填充方式。

    • padmode: 填充方式,默認為PAD_PKCS5填充模式。

    Example
    -------
    from pyDes import *
    data = "Please encrypt my data"
    k = des("DESCRYPT", CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
    # For Python3, you'll need to use bytes, i.e.:
    # data = b"Please encrypt my data"
    # k = des(b"DESCRYPT", CBC, b"\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
    d = k.encrypt(data)
    print "Encrypted: %r" % d
    print "Decrypted: %r" % k.decrypt(d)
    assert k.decrypt(d, padmode=PAD_PKCS5) == data
    des加密后(CBC模式)使用相同的密鑰,初始向量,填充模式解密,解密后的字符前幾位是亂碼,其他位正常的解決辦法
    des_key = 'ucgtchdp'
    IV = '12345678'
    k = des(des_key, mode=CBC, IV='12345678', padmode=PAD_PKCS5)

    傳遞過來的加密數據: xUjw0iO7uhymZ+h/VB9kvhubiAEv4Kzz

    通過k解密出來的數據:@IDX_^\x10Ys powerful

    這種情況通常發生在不同語言(java加密、python解密)對初始向量的處理方式不同造成的解密不完全。

    解決辦法:檢查初始向量的表現形式。

    k1 = des(des_key, mode=CBC, IV='\1\2\3\4\5\6\7\x08', padmode=PAD_PKCS5)

    通過k1解密出來的數據:python is powerful

    關于“c語言怎么實現DES加密解密”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女