1. 程式人生 > >C/C++: 3DES-ECB模式加密,可以與C#和Java互通

C/C++: 3DES-ECB模式加密,可以與C#和Java互通

在開發過程中經常會射擊到對資料的加密處理,常用的加密方式有Aes和Des,Aes/Des加密速度快,適合大量資料,Des容易破解,一般用3重Des即TripleDes。

在專案開發時從網上找了很多例子,大部分只能單平臺執行,或者檔案不全,本人這樣的新手來說對於加密演算法還是望而生畏的。後來找了一些資料,然後整合了一下別人的程式碼(加密核心程式碼的原作者:黃雙全,如有侵權請告知,會及時處理),實現了3DES-ECB的加密方法。

最喜歡的就是:直接上程式碼

1、標頭檔案des.h

#ifndef _DES_H_
#define _DES_H_
#include <string>
#include <sstream>
using namespace std; //為了提高程式效率,把這兩個位操作功能定義在巨集。 //讀取緩衝區的指定位. #define GET_BIT(p_array, bit_index) \ ((p_array[(bit_index) >> 3] >> (7 - ((bit_index) & 0x07))) & 0x01) //設定緩衝區的指定位. #define SET_BIT(p_array, bit_index, bit_val) \ if (1 == (bit_val)) \ {\ p_array[(bit_index) >> 3] |= 0x01
<< (7 - ((bit_index) & 0x07));\ }\ else\ {\ p_array[(bit_index) >> 3] &= ~(0x01 << (7 - ((bit_index) & 0x07)));\ } //加解密標識,這兩個標識涉及到對錶的讀取位置, //必須保證DES_ENCRYPT = 0 DES_DECRYPT = 1 typedef enum { DES_ENCRYPT = 0, DES_DECRYPT = 1 } DES_MODE; //key typedef enum { //1key模式 等同於des KEY_16, //2key模式 key1 = key3
KEY_32, //3key模式 KEY_48, KEY_ERROR } KEYMODE; class Des { private: std::string deskey; private: //字元輸出處理 void print_binary(char * tip, unsigned char * buff, unsigned char bits); void print_hex(char * tip, unsigned char * buff, unsigned char bytes); /////////////////////////////////////////////////////////////// // 函 數 名 : des // 函式功能 : DES加解密 // 處理過程 : 根據標準的DES加密演算法用輸入的64位金鑰對64位密文進行加/解密 // 並將加/解密結果儲存到p_output裡 // 時 間 : 2006年9月2日 // 返 回 值 : // 引數說明 : const char * p_data 輸入, 加密時輸入明文, 解密時輸入密文, 64位(8位元組) // const char * p_key 輸入, 金鑰, 64位(8位元組) // char * p_output 輸出, 加密時輸出密文, 解密時輸入明文, 64位(8位元組) // unsigned char mode 0 加密 1 解密 /////////////////////////////////////////////////////////////// void des(const char * p_data, const char * p_key, const char * p_output, DES_MODE mode); //對兩塊大小相同的記憶體區進行異或 //異或結果儲存到第一塊記憶體 //unsigned char * p_buf_1 記憶體區1 //const unsigned char * p_buf_2 記憶體區2 //unsigned char bytes 記憶體區大小(單位:位元組) void Xor(unsigned char * p_buf_1, const unsigned char * p_buf_2, unsigned char bytes); //將緩衝區從第bit_start位到第bit_end進行迴圈左移 //offset只能是1,2 void move_left(unsigned char * p_input, unsigned char bit_start, unsigned char bit_end, unsigned char offset); //將緩衝區從第bit_start位到第bit_end進行迴圈右移 //offset只能是1,2 void move_right(unsigned char * p_input, unsigned char bit_start, unsigned char bit_end, unsigned char offset); //緩衝區移位 //offset大於0時左移 //offset小於0時右移 void move_bits(unsigned char * p_input, unsigned char bit_start, unsigned char bit_end, char offset); //通用置換函式, bits <= 64 //p_input與p_output不能指向同一個地址,否則置換會出錯。 void Permutation(unsigned char * p_input, unsigned char * p_output, const unsigned char * Table, unsigned char bits); //獲取從bit_s為起始的第1, 6 位組成行 unsigned char S_GetLine(unsigned char * p_data_ext, unsigned char bit_s); //獲取從bit_s為起始的第2,3,4,5位組成列 unsigned char S_GetRow(unsigned char * p_data_ext, unsigned char bit_s); /************************************************************************ *功能:字串轉換為16進製表示,每兩位為一組 ************************************************************************/ unsigned char* str_to_hex(const std::string& str); /************************************************************************ *功能:獲得3DES分組的key ************************************************************************/ unsigned char *getKey1(std::string key); unsigned char *getKey2(std::string key); unsigned char *getKey3(std::string key); /************************************************************************ *功能:陣列清空 ************************************************************************/ void clearBuff(char *buff, int length); /*編碼 DataByte [in]輸入的資料長度,以位元組為單位 */ std::string base64Encode(const unsigned char* Data, int DataByte); /*解碼 DataByte [in]輸入的資料長度,以位元組為單位 OutByte [out]輸出的資料長度,以位元組為單位,請不要通過返回值計算 輸出資料的長度 */ std::string base64Decode(const char* Data, int DataByte, int& OutByte); //功能:URL字元轉換 unsigned char ToHex(unsigned char x); unsigned char FromHex(unsigned char x); //功能:URL-ENCODE編碼 std::string UrlEncode(const std::string& str); //功能:URL-DECODE解碼 std::string UrlDecode(const std::string& str); //替換字串 std::string replaceAllSubStr(string &str, string &oldStr, string &newStr); //檢查key的長度,返回加密模式 KEYMODE checkKey(); KEYMODE checkKey(std::string key); public: Des() { } ; Des(std::string key) { deskey = key; } ; ~Des() { deskey = nullptr; } ; /************************************************************************ *功能:3DES-ECB加密 ************************************************************************/ std::string desEncrypt(std::string str); /************************************************************************ *功能:3DES-ECB解密 ************************************************************************/ std::string desDecrypt(std::string str); }; #endif //#ifndef _DES_H_

2、實現des.cpp

#include "des.h"

// 初始置換
const unsigned char Table_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 };

// 末置換
const unsigned char Table_InverseIP[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 };

// 擴充套件置換
const unsigned char Table_E[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 };

// 金鑰初始置換
const unsigned char Table_PC1[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 };

// 左右移運算
const signed char Table_Move[2][16] = {
//加密左移
        { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 },

        //解密右移
        { 0, -1, -2, -2, -2, -2, -2, -2, -1, -2, -2, -2, -2, -2, -2, -1 } };

// 金鑰壓縮置換
const unsigned char Table_PC2[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 };

// S盒
const unsigned char Table_SBOX[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, 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,
        // S7
        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,
        // 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 };

// P盒置換
const unsigned char Table_P[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 };

//檢查key的長度,返回加密模式
KEYMODE Des::checkKey() {
    if (deskey.length() != 0) {
        if (deskey.length() != 32 && deskey.length() != 48) {
            printf("key輸入不正確,請輸入32位key或者48位key");
            return KEY_ERROR;
        }

        if (deskey.length() % 2 != 0) {
            printf("請檢查輸入的位數是否是偶數位");
            return KEY_ERROR;
        }

        if (deskey.length() == 32) {
            return KEY_32;
        }

        if (deskey.length() == 48) {
            return KEY_48;
        }
    } else {
        return KEY_ERROR;
    }
    return KEY_ERROR;
}

KEYMODE Des::checkKey(std::string key) {
    deskey = key;

    if (deskey.length() != 32 && deskey.length() != 48) {
        printf("key輸入不正確,請輸入32位key或者48位key");
        return KEY_ERROR;
    }

    if (deskey.length() % 2 != 0) {
        printf("請檢查輸入的位數是否是偶數位");
        return KEY_ERROR;
    }

    if (deskey.length() == 32) {
        return KEY_32;
    }

    if (deskey.length() == 48) {
        return KEY_48;
    }
    return KEY_ERROR;
}

void Des::print_binary(char * tip, unsigned char * buff, unsigned char bits) {
    unsigned char bit_index = 0;

    printf("\r\n****** start %s ******\r\n", tip);

    for (bit_index = 0; bit_index < bits; bit_index++) {
        printf("%d", (buff[bit_index >> 3] >> (7 - (bit_index % 8))) & 0x01);

        if ((bit_index + 1) % 4 == 0) {
            printf(" ");
        }

        if ((bit_index + 1) % 64 == 0) {
            printf("\r\n");
        }
    }

    printf("\r\n****** end %s ******\r\n", tip);
}

void Des::print_hex(char * tip, unsigned char * buff, unsigned char bytes) {
    unsigned char byte_index = 0;

    printf("\r\n %s", tip);

    for (byte_index = 0; byte_index < bytes; byte_index++) {
        //LOGI("0x%0.2X ", buff[byte_index]);
    }
}

//對兩塊大小相同的記憶體區進行異或
//異或結果儲存到第一塊記憶體
//unsigned char * p_buf_1       記憶體區1
//const unsigned char * p_buf_2 記憶體區2
//unsigned char bytes           記憶體區大小(單位:位元組)
void Des::Xor(unsigned char * p_buf_1, const unsigned char * p_buf_2,
        unsigned char bytes) {
    while (bytes > 0) {
        bytes--;

        p_buf_1[bytes] ^= p_buf_2[bytes];
    }
}

//將緩衝區從第bit_start位到第bit_end進行迴圈左移
//offset只能是1,2
//本段程式碼還可以優化。
void Des::move_left(unsigned char * p_input, unsigned char bit_start,
        unsigned char bit_end, unsigned char offset) {
    unsigned char b_val = 0;
    unsigned char b_tmp1 = 0;
    unsigned char b_tmp2 = 0;

    //讀取bit_start位
    b_tmp1 = GET_BIT(p_input, bit_start);
    b_tmp2 = GET_BIT(p_input, bit_start + 1);

    //迴圈左移offset位
    for (; bit_start <= (bit_end - offset); bit_start++) {
        b_val = GET_BIT(p_input, bit_start + offset);
        SET_BIT(p_input, bit_start, b_val);
    }

    //將bit_start開始的offset位移到bit_end後頭來
    if (1 == offset) {
        SET_BIT(p_input, bit_end, b_tmp1);
    } else {
        SET_BIT(p_input, bit_end, b_tmp2);
        SET_BIT(p_input, bit_end - 1, b_tmp1);
    }
}

//將緩衝區從第bit_start位到第bit_end進行迴圈右移
//offset只能是1,2
//本段程式碼在效能上還可以優化。
void Des::move_right(unsigned char * p_input, unsigned char bit_start,
        unsigned char bit_end, unsigned char offset) {
    unsigned char b_val = 0;
    unsigned char b_tmp1 = 0;
    unsigned char b_tmp2 = 0;

    //讀取bit_end位
    b_tmp1 = GET_BIT(p_input, bit_end);
    b_tmp2 = GET_BIT(p_input, bit_end - 1);

    //迴圈左移offset位
    for (; bit_end >= (bit_start + offset); bit_end--) {
        b_val = GET_BIT(p_input, bit_end - offset);
        SET_BIT(p_input, bit_end, b_val);
    }

    //將bit_end倒數的offset位移到bit_start來
    if (1 == offset) {
        SET_BIT(p_input, bit_start, b_tmp1);
    } else {
        SET_BIT(p_input, bit_start, b_tmp2);
        SET_BIT(p_input, bit_start + 1, b_tmp1);
    }
}

//緩衝區移位
//offset大於0時左移
//offset小於0時右移
void Des::move_bits(unsigned char * p_input, unsigned char bit_start,
        unsigned char bit_end, char offset) {
    if (0 < offset) //左移
            {
        move_left(p_input, bit_start, bit_end, offset);
    } else if (0 > offset) //右移
            {
        move_right(p_input, bit_start, bit_end, -offset);
    }
}

//通用置換函式, bits <= 64
//p_input與p_output不能指向同一個地址,否則置換會出錯。
void Des::Permutation(unsigned char * p_input, unsigned char * p_output,
        const unsigned char * Table, unsigned char bits) {
    unsigned char b_val = false;
    unsigned char bit_index = 0;

    for (bit_index = 0; bit_index < bits; bit_index++) {
        b_val = GET_BIT(p_input, Table[bit_index] - 1);

        SET_BIT(p_output, bit_index, b_val);
    }
}

//獲取從bit_s為起始的第1, 6 位組成行
unsigned char Des::S_GetLine(unsigned char * p_data_ext, unsigned char bit_s) {
    return (GET_BIT(p_data_ext, bit_s + 0) << 1)
            + GET_BIT(p_data_ext, bit_s + 5);
}

//獲取從bit_s為起始的第2,3,4,5位組成列
unsigned char Des::S_GetRow(unsigned char * p_data_ext, unsigned char bit_s) {
    unsigned char row;

    //2,3,4,5位組成列
    row = GET_BIT(p_data_ext, bit_s + 1);
    row <<= 1;
    row += GET_BIT(p_data_ext, bit_s + 2);
    row <<= 1;
    row += GET_BIT(p_data_ext, bit_s + 3);
    row <<= 1;
    row += GET_BIT(p_data_ext, bit_s + 4);

    return row;
}

///////////////////////////////////////////////////////////////
//  函 數 名 : des
//  函式功能 : DES加解密
//  處理過程 : 根據標準的DES加密演算法用輸入的64位金鑰對64位密文進行加/解密
//              並將加/解密結果儲存到p_output裡
//  時    間 : 2006年9月2日
//  返 回 值 :
//  引數說明 :  const char * p_data     輸入, 加密時輸入明文, 解密時輸入密文, 64位(8位元組)
//              const char * p_key      輸入, 金鑰, 64位(8位元組)
//              char * p_output         輸出, 加密時輸出密文, 解密時輸入明文, 64位(8位元組)
//              unsigned char mode              DES_ENCRYPT 加密  DES_DECRYPT 解密
///////////////////////////////////////////////////////////////
void Des::des(const char * p_data, const char * p_key, const char * p_output,
        DES_MODE mode) {
    unsigned char loop = 0; //16輪運算的迴圈計數器
    unsigned char key_tmp[8]; //金鑰運算時儲存中間結果
    unsigned char sub_key[6]; //用於儲存子金鑰

    unsigned char * p_left;
    const char* p_right;

    unsigned char p_right_ext[8]; //R[i]經過擴充套件置換生成的48位資料(6位元組), 及最終結果的儲存
    unsigned char p_right_s[4]; //經過S_BOX置換後的32位資料(4位元組)

    unsigned