c語言如何實現(xiàn)DES加密解密
c語言實現(xiàn)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 }; //數(shù)據(jù)初始置換表 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 }; /* * 函數(shù)功能:生成16個6字節(jié)子密鑰 * 參數(shù):<key>傳入8字節(jié)密鑰,<key_lenght>密鑰長度必須是8字節(jié) * 返回值:返回16*(48/8)字節(jié)大小的16個子密鑰 * 注釋:返回值要釋放 */ subkey_size __desSubKeyGeneration(subkey_size key, data_lenght_size key_lenght) { //如果傳入空或長度不為8字節(jié)則返回空 if(key==NULL || key_lenght!=8) return NULL; //申請堆內(nèi)存 subkey_size subkey16 = (subkey_size)malloc(NumberOfKeys * (des_key_pc2_standard / systemBit)); //清空初始化,按照申請內(nèi)存大小來清空這塊堆內(nèi)存 memset(subkey16, 0, NumberOfKeys * (des_key_pc2_standard / systemBit)); //創(chuàng)建布爾型的數(shù)組,讓移位代碼實現(xiàn)更簡單 int count = 0; bool tmp = 0; bool bit_table_pc1[des_key_pc1_standard]={0}; //pc1的56位數(shù)據(jù) bool bit_table[des_standard]={0}; //64位數(shù)據(jù) //將數(shù)據(jù)賦值到布爾型數(shù)組里面 for(int i=0; i<des_standard; i++) bit_table[i] = BIT_JUDGE(*(key + i / systemBit), (i % systemBit)); //進行PC1轉(zhuǎn)換 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++) { //保存移位次數(shù) 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; } //進行判斷寫入新的數(shù)據(jù) 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; } /* * 函數(shù)功能:進行數(shù)據(jù)加密 * 參數(shù):<data>傳入8整數(shù)倍字節(jié)數(shù)據(jù),<data_lenght>數(shù)據(jù)長度,<key>16*(48/8)字節(jié)大小的16個子密鑰,<key_lenght>必須是6*16長度 * 返回值:返回加密后的數(shù)據(jù) * 注釋:返回值要釋放 */ data_size __desDataEncryption(data_size data, data_lenght_size data_lenght, subkey_size key, data_lenght_size key_lenght) { //如果傳入空或長度不為8字節(jié)則返回空 if(key==NULL || key_lenght!=(NumberOfKeys*(des_key_pc2_standard/systemBit)) || data==NULL || data_lenght!=8) return NULL; //申請堆內(nèi)存 data_size Data16 = (data_size)malloc(des_standard/8); //清空初始化,按照申請內(nèi)存大小來清空這塊堆內(nèi)存 memset(Data16, 0, (des_standard/8)); //創(chuàng)建一個布爾型的數(shù)組,將移位操作變得簡單 bool bit_table[des_standard]={0}; //64位數(shù)據(jù) bool data64_table[des_standard]={0}; //64位數(shù)據(jù) bool extend48_table[des_key_pc2_standard]={0}; //pc2表的48位數(shù)據(jù) bool dataL32_table[des_data_rl]={0}; //64位數(shù)據(jù)的左32 bool dataR32_table[des_data_rl]={0}; //64位數(shù)據(jù)的右32 bool tmpL32_table[des_data_rl]={0}; //臨時64位數(shù)據(jù)的左32 bool tmpR32_table[des_data_rl]={0}; //臨時64位數(shù)據(jù)的右32 //將數(shù)據(jù)賦值到布爾型數(shù)組里面 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; //進行十六次輪函數(shù) for(int num=0; num<NumberOfKeys; num++) { //將R數(shù)組賦值給L的臨時數(shù)組 for(int i=0; i<des_data_rl; i++) tmpL32_table[i] = dataR32_table[i]; //將R數(shù)組進行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位轉(zhuǎn)換成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進制轉(zhuǎn)換為四位二進制 for(int i=0; i<4; i++) dataR32_table[((j/6)*4)+i] = BIT_JUDGE(sBoxTable[j/6][row][col], i); } //將R進行轉(zhuǎn)換并存入R臨時數(shù)組 for(int i=0; i<des_data_rl; i++) tmpR32_table[i] = dataR32_table[pTable[i]-1]; //在用臨時數(shù)組進行異或 for(int i=0; i<des_data_rl; i++) { dataR32_table[i] = (dataL32_table[i] ^ tmpR32_table[i]); } //最后將剛才的L臨時數(shù)組賦值 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]; //進行判斷寫入新的數(shù)據(jù) 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)); } //返回數(shù)據(jù) return Data16; } /* * 函數(shù)功能:進行數(shù)據(jù)解密 * 參數(shù):<data>傳入加密后數(shù)據(jù),<data_lenght>加密后數(shù)據(jù)長度,<key>16*(48/8)字節(jié)大小的16個子密鑰,<key_lenght>必須是6*16長度 * 返回值:返回解密后的數(shù)據(jù) * 注釋:返回值要釋放 */ data_size __desDataDecrypt(data_size data, data_lenght_size data_lenght, subkey_size key, data_lenght_size key_lenght) { //如果傳入空或長度不為8字節(jié)則返回空 if(key==NULL || key_lenght!=(NumberOfKeys*(des_key_pc2_standard/systemBit)) || data==NULL || data_lenght!=8) return NULL; //申請堆內(nèi)存 data_size Data16 = (data_size)malloc(des_standard/8); //清空初始化,按照申請內(nèi)存大小來清空這塊堆內(nèi)存 memset(Data16, 0, (des_standard/8)); //創(chuàng)建一堆布爾型的數(shù)組,將移位操作變得簡單 bool bit_table[des_standard]={0}; //64位數(shù)據(jù) bool data64_table[des_standard]={0}; //64位數(shù)據(jù) bool extend48_table[des_key_pc2_standard]={0}; //pc2表48位數(shù)據(jù) bool dataL32_table[des_data_rl]={0}; //64位數(shù)據(jù)的左32位 bool dataR32_table[des_data_rl]={0}; //64位數(shù)據(jù)的右32位 bool tmpL32_table[des_data_rl]={0}; //臨時64位數(shù)據(jù)的左32位 bool tmpR32_table[des_data_rl]={0}; //臨時64位數(shù)據(jù)的右32位 //將數(shù)據(jù)賦值到布爾型數(shù)組里面 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; //進行十六次輪函數(shù)(反著來) for(int num=(NumberOfKeys-1); num>=0; num--) { //將R數(shù)組賦值給L的臨時數(shù)組 for(int i=0; i<des_data_rl; i++) tmpL32_table[i] = dataR32_table[i]; //將R數(shù)組進行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位轉(zhuǎn)換成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進制轉(zhuǎn)換為四位二進制 for(int i=0; i<4; i++) dataR32_table[((j/6)*4)+i] = BIT_JUDGE(sBoxTable[j/6][row][col], i); } //將R進行轉(zhuǎn)換并存入R臨時數(shù)組 for(int i=0; i<des_data_rl; i++) tmpR32_table[i] = dataR32_table[pTable[i]-1]; //在用臨時數(shù)組進行異或 for(int i=0; i<des_data_rl; i++) { dataR32_table[i] = (dataL32_table[i] ^ tmpR32_table[i]); } //最后將剛才的L臨時數(shù)組賦值 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]; //進行判斷寫入新的數(shù)據(jù) 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)); } //返回數(shù)據(jù) return Data16; } /* * 函數(shù)功能:將數(shù)據(jù)進行DES加密 * 參數(shù):<data>要加密的數(shù)據(jù),<data_lenght>要加密的數(shù)據(jù)長度,<key>進行加密的密鑰,<key_lenght>密鑰的長度(8字節(jié)),<fillingMode>數(shù)據(jù)補位的模式選擇 * 返回值:返回一個結(jié)構(gòu)體,結(jié)構(gòu)體內(nèi)有加密后數(shù)據(jù)和加密后數(shù)據(jù)長度 */ 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; } //申請堆內(nèi)存 p_desRetStruct retData = (p_desRetStruct)malloc(sizeof(desRetStruct)); //清空這塊內(nèi)存 memset(retData, 0, sizeof(desRetStruct)); //計算出長度 data_lenght_size mallocLenght = ((data_lenght%8==0)?(data_lenght):(((data_lenght/8)*8)+8)); //申請堆內(nèi)存 retData->data = (data_size)malloc(mallocLenght); //長度進行賦值 retData->dataLenght = mallocLenght; //清空這塊內(nèi)存 memset(retData->data, 0, mallocLenght); //進行賦值 memcpy(retData->data, data, data_lenght); //如果是長度是8的整數(shù)倍 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); //進行循環(huán)每8字節(jié)進行加密 for(int i=0; i<mallocLenght; i+=8) { //將8字節(jié)進行加密 data_size mData = __desDataEncryption(retData->data + i, 8, subkey16, 96); //將加密后字節(jié)拷貝到返回值上 memcpy(retData->data + i, mData, 8); //釋放 free(mData); } //釋放16個子密鑰 free(subkey16); //返回加密后的數(shù)據(jù) return retData; } /* * 函數(shù)功能:將DES加密數(shù)據(jù)進行解密 * 參數(shù):<data>要解密的數(shù)據(jù),<data_lenght>要解密的數(shù)據(jù)長度(8的整數(shù)倍字節(jié)),<key>進行解密的密鑰,<key_lenght>密鑰的長度(8字節(jié)),<fillingMode>數(shù)據(jù)補位的模式選擇 * 返回值:返回一個結(jié)構(gòu)體,結(jié)構(gòu)體內(nèi)有解密后數(shù)據(jù)和解密后數(shù)據(jù)長度 */ 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; } //申請堆內(nèi)存 p_desRetStruct retData = (p_desRetStruct)malloc(sizeof(desRetStruct)); //清空這塊內(nèi)存 memset(retData, 0, sizeof(desRetStruct)); //申請堆內(nèi)存 retData->data = (data_size)malloc(data_lenght); //長度進行賦值 retData->dataLenght = data_lenght; //清空這塊內(nèi)存 memset(retData->data, 0, data_lenght); //獲取16個子密鑰 subkey_size subkey16 = __desSubKeyGeneration(key, key_lenght); //進行循環(huán)每8字節(jié)進行解密 for(int i=0; i<data_lenght; i+=8) { //將8字節(jié)進行解密 data_size mData = __desDataDecrypt(data + i, 8, subkey16, 96); //將解密后字節(jié)拷貝到返回值上 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-模次循環(huán) for(int count=1; count<=*(retData->data + (data_lenght - 1)); count++) { //判斷是否和最后一字節(jié)相等 if(*(retData->data + (data_lenght - 1)) == *(retData->data + (data_lenght - count))) { retData->dataLenght--; } else { //如果有一次不相等就說明該數(shù)據(jù)沒有補位 retData->dataLenght = data_lenght; //退出循環(huán) break; } } } } //按照\0補位方式解密 else if(fillingMode == NOPADDING) { //從尾部開始進行8次判斷 for(int count=1; count<=8; count++) { //如果這一字節(jié)等于0就位去掉 if(0x00 == *(retData->data + (data_lenght - count))) { //將長度進行減1 retData->dataLenght--; } else { //遇到正常數(shù)據(jù)進行退出循環(huán) break; } } } //釋放16個子密鑰 free(subkey16); //返回加密后的數(shù)據(jù) return retData; } /* * 函數(shù)功能:將數(shù)據(jù)進行3DES加密 * 參數(shù):<data>要加密的數(shù)據(jù),<data_lenght>要加密的數(shù)據(jù)長度,<key>進行加密的密鑰,<key_lenght>密鑰的長度(24字節(jié)),<fillingMode>數(shù)據(jù)補位的模式選擇 * 返回值:返回一個結(jié)構(gòu)體,結(jié)構(gòu)體內(nèi)有加密后數(shù)據(jù)和加密后數(shù)據(jù)長度 */ 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; } //申請堆內(nèi)存 p_desRetStruct retData = (p_desRetStruct)malloc(sizeof(desRetStruct)); //清空這塊內(nèi)存 memset(retData, 0, sizeof(desRetStruct)); //計算出長度 data_lenght_size mallocLenght = ((data_lenght%8==0)?(data_lenght):(((data_lenght/8)*8)+8)); //申請堆內(nèi)存 retData->data = (data_size)malloc(mallocLenght); //長度進行賦值 retData->dataLenght = mallocLenght; //清空這塊內(nèi)存 memset(retData->data, 0, mallocLenght); //進行賦值 memcpy(retData->data, data, data_lenght); //如果是長度是8的整數(shù)倍 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); //進行循環(huán)每8字節(jié)進行加密 for(int i=0; i<mallocLenght; i+=8) { //將8字節(jié)進行加密 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); //將加密后字節(jié)拷貝到返回值上 memcpy(retData->data + i, mData3, 8); //釋放 free(mData1); free(mData2); free(mData3); } //釋放子密鑰 free(subkey1); free(subkey2); free(subkey3); //返回加密后的數(shù)據(jù) return retData; } /* * 函數(shù)功能:將3DES加密數(shù)據(jù)進行解密 * 參數(shù):<data>要解密的數(shù)據(jù),<data_lenght>要解密的數(shù)據(jù)長度(8的整數(shù)倍字節(jié)),<key>進行解密的密鑰,<key_lenght>密鑰的長度(24字節(jié)),<fillingMode>數(shù)據(jù)補位的模式選擇 * 返回值:返回一個結(jié)構(gòu)體,結(jié)構(gòu)體內(nèi)有解密后數(shù)據(jù)和解密后數(shù)據(jù)長度 */ 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; } //申請堆內(nèi)存 p_desRetStruct retData = (p_desRetStruct)malloc(sizeof(desRetStruct)); //清空這塊內(nèi)存 memset(retData, 0, sizeof(desRetStruct)); //申請堆內(nèi)存 retData->data = (data_size)malloc(data_lenght); //長度進行賦值 retData->dataLenght = data_lenght; //清空這塊內(nèi)存 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); //進行循環(huán)每8字節(jié)進行解密 for(int i=0; i<data_lenght; i+=8) { //將8字節(jié)進行加密 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); //將解密后字節(jié)拷貝到返回值上 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-模)次循環(huán) for(int count=1; count<=*(retData->data + (data_lenght - 1)); count++) { //判斷是否和最后一字節(jié)相等 if(*(retData->data + (data_lenght - 1)) == *(retData->data + (data_lenght - count))) { retData->dataLenght--; } else { //如果有一次不相等就說明該數(shù)據(jù)沒有補位 retData->dataLenght = data_lenght; //退出循環(huán) break; } } } } //按照\0補位方式解密 else if(fillingMode == NOPADDING) { //從尾部開始進行8次判斷 for(int count=1; count<=8; count++) { //如果這一字節(jié)等于0就位去掉 if(0x00 == *(retData->data + (data_lenght - count))) { //將長度進行減1 retData->dataLenght--; } else { //遇到正常數(shù)據(jù)進行退出循環(huán) break; } } } //釋放16個子密鑰 free(subkey1); free(subkey2); free(subkey3); //返回加密后的數(shù)據(jù) return retData; }
/* DES全稱->數(shù)據(jù)加密標準->它出自IBM的研究工作(本描述大致步驟細節(jié)需要看代碼) * 數(shù)據(jù)=由8的整數(shù)倍構(gòu)成(單位字節(jié))(不足8字節(jié)可以補位) 密鑰=固定由64位(即8字節(jié))組成(其中8位為校驗位不影響結(jié)果) * (每個字節(jié)(0~255)任意選取) (每個字節(jié)(0~255)任意選取) * ↓ ↓ * 進行ip置換將64位數(shù)據(jù)每個位進行移位 進行PC1轉(zhuǎn)換(轉(zhuǎn)換前64)(轉(zhuǎn)換后將8位校驗位舍棄)(并且進行移位) * ↓ →→→→→→→→→→→→→→→→→→→→→↓→→→→→→→→→→→→→→→→→→→→→↓ * 將64位數(shù)據(jù)一分為二變成左右兩個部分(分別32位) ↓ 一分為二(分別28位)分別移位(每輪移位次數(shù)不同) ↓ * ↓ ↓ ↓ ↓ ↓ * 左32位 右32位 ↓ 進行PC2轉(zhuǎn)換(轉(zhuǎn)換前56)(轉(zhuǎn)換后48)(并且進行移位)↓ * ↓ ↓ ↓←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←↓ * (左32位 異或 f(右32位, key))←←←←←←←←←←←進行16次循環(huán)(每一次產(chǎn)生48位key與右32位進行輪函數(shù)) * (左32位和f(右32位, key))進行異或運算) (解密時將16個48位key反著進行輪函數(shù)) * 運算結(jié)果成為新的右32位并將右32位賦值給左32位 * 產(chǎn)生新的左32位和右32位 f(右32位, key)f輪函數(shù)步驟 * ↓ ↓ 右32位進行E擴展為48位 *新左32位=舊左32位^f(舊右32位, key)) 新右32位=舊左32位 擴展后48位和48位key進行異或 * (進行16次循環(huán)結(jié)束后將兩個32進行合并并且進行終止置換) 將異或后48位進入S盒壓縮為32結(jié)束 * (終止置換完,成為des加密數(shù)據(jù)) * 解密的兩個條件 = (解密時將16個48位key反著進行輪函數(shù)) + (圖上的左右32位反著運算) * 不足8整數(shù)倍字節(jié)時可以全部補位0,也可以補位(8-(數(shù)據(jù)長度(單位字節(jié))%8)) */ /* 3DES * E表示加密 D表示解密 K1表示密鑰1 K2表示密鑰2 K3表示密鑰3 P表示明文 C表示密文 EK1表示使用K1密鑰進行加密 DK1表示使用K1密鑰進行解密 * 加密:C = EK3( DK2( EK1(P)) ),即對明文數(shù)據(jù)進行,加密 -> 解密 -> 加密的過程,最后得到密文數(shù)據(jù); * 解密:P = DK1( EK2( DK3(C)) ),即對密文數(shù)據(jù)進行,解密 -> 加密 -> 解密的過程,最后得到明文數(shù)據(jù); */ #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("加密后數(shù)據(jù)十六進制:"); for(int num=0; num<retData->dataLenght; num++) printf("0x%02X ", *(retData->data+num)); printf("\n"); printf("解密后原數(shù)據(jù):"); 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標準下各種位數(shù) #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 //數(shù)據(jù)類型 #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; //返回的數(shù)據(jù)指針 data_lenght_size dataLenght; //返回的數(shù)據(jù)長度 }desRetStruct, *p_desRetStruct; // 結(jié)構(gòu)體別名 結(jié)構(gòu)體指針別名 /* * 函數(shù)功能:將數(shù)據(jù)進行DES加密 * 參數(shù):<data>要加密的數(shù)據(jù),<data_lenght>要加密的數(shù)據(jù)長度,<key>進行加密的密鑰,<key_lenght>密鑰的長度(8字節(jié)),<fillingMode>數(shù)據(jù)補位的模式選擇 * 返回值:返回一個結(jié)構(gòu)體,結(jié)構(gòu)體內(nèi)有加密后數(shù)據(jù)和加密后數(shù)據(jù)長度 */ p_desRetStruct desEncryption(data_size data, data_lenght_size data_lenght, subkey_size key, data_lenght_size key_lenght, enumFillingMode fillingMode); /* * 函數(shù)功能:將DES加密數(shù)據(jù)進行解密 * 參數(shù):<data>要解密的數(shù)據(jù),<data_lenght>要解密的數(shù)據(jù)長度(8的整數(shù)倍字節(jié)),<key>進行解密的密鑰,<key_lenght>密鑰的長度(8字節(jié)),<fillingMode>數(shù)據(jù)補位的模式選擇 * 返回值:返回一個結(jié)構(gòu)體,結(jié)構(gòu)體內(nèi)有解密后數(shù)據(jù)和解密后數(shù)據(jù)長度 */ p_desRetStruct desDecrypt(data_size data, data_lenght_size data_lenght, subkey_size key, data_lenght_size key_lenght, enumFillingMode fillingMode); /* * 函數(shù)功能:將數(shù)據(jù)進行3DES加密 * 參數(shù):<data>要加密的數(shù)據(jù),<data_lenght>要加密的數(shù)據(jù)長度,<key>進行加密的密鑰,<key_lenght>密鑰的長度(24字節(jié)),<fillingMode>數(shù)據(jù)補位的模式選擇 * 返回值:返回一個結(jié)構(gòu)體,結(jié)構(gòu)體內(nèi)有加密后數(shù)據(jù)和加密后數(shù)據(jù)長度 */ p_desRetStruct _3desEncryption(data_size data, data_lenght_size data_lenght, subkey_size key, data_lenght_size key_lenght, enumFillingMode fillingMode); /* * 函數(shù)功能:將3DES加密數(shù)據(jù)進行解密 * 參數(shù):<data>要解密的數(shù)據(jù),<data_lenght>要解密的數(shù)據(jù)長度(8的整數(shù)倍字節(jié)),<key>進行解密的密鑰,<key_lenght>密鑰的長度(24字節(jié)),<fillingMode>數(shù)據(jù)補位的模式選擇 * 返回值:返回一個結(jié)構(gòu)體,結(jié)構(gòu)體內(nèi)有解密后數(shù)據(jù)和解密后數(shù)據(jù)長度 */ 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加密解密的認識以及解密出現(xiàn)亂碼的分析
在工作中遇到的Des解密問題,第三方發(fā)來的數(shù)據(jù)需要我們進行des解密,但是解密的結(jié)果前幾位始終是亂碼。廢了半天勁,終于找到了問題所在。
下面先介紹一下des,了解des的同學(xué)可以直接看下面的解決辦法。
Des加密
DES全稱為Data EncryptionStandard,即數(shù)據(jù)加密標準。Des加密算法是一種對稱加密算法,所謂對稱加密算法就是指對明文的加密以及對密文的解密用的是同一個密鑰。
Des使用一個56位的密鑰以及附加的8位奇偶校驗位,產(chǎn)生最大64位的分組大小。這是一個迭代的分組密碼,使用稱為 Feistel 的技術(shù),其中將加密的文本塊分成兩半。使用子密鑰對其中一半應(yīng)用循環(huán)功能,然后將輸出與另一半進行“異或”運算;接著交換這兩半,這一過程會繼續(xù)下去,但最后一個循環(huán)不交換。DES 使用 16 個循環(huán),使用異或,置換,代換,移位操作四種基本運算。
特點:數(shù)據(jù)加密標準,速度較快,適用于加密大量數(shù)據(jù)的場合。
Des算法的入口參數(shù)有三個:Key、Data、Mode。
Key
: 為8個字節(jié)共64位,Des算法規(guī)定,其中第8、16、24、......64位是奇偶校驗位,不參與Des運算,所以常說Des的密鑰為56位。 在Des加密和解密的過程當中,密鑰的長度都必須是8字節(jié)的倍數(shù)。Data
: 8個字節(jié)64位,是要被加密后解密的數(shù)據(jù)。Mode
: Des的工作方式:加密、解密。
Des加密模式
Des的加密模式主要有CBC模式,ECB模式,它們分別使用不同的加密方式加密。
ECB模式指的是電子密碼本模式,是一種最古老,最簡單的模式,將加密的數(shù)據(jù)分成若干組,每組的大小跟加密密鑰長度相同;然后每組都用相同的密鑰加密, 如果最后一個分組長度不夠64位,要補齊64位。
ECB模式的特點是:
- 每次Key、明文、密文的長度都必須是64位;
- 數(shù)據(jù)塊重復(fù)排序不需要檢測;
- 相同的明文塊(使用相同的密鑰)產(chǎn)生相同的密文塊,容易遭受字典攻擊;
- 一個錯誤僅僅會對一個密文塊產(chǎn)生影響;
CBC模式指的是加密塊鏈模式,與ECB模式最大的不同是加入了初始向量。
CBC模式的特點是:
- 每次加密的密文長度為64位(8個字節(jié));
- 當相同的明文使用相同的密鑰和初始向量的時候CBC模式總是產(chǎn)生相同的密文;
- 密文塊要依賴以前的操作結(jié)果,所以,密文塊不能進行重新排列;
- 可以使用不同的初始化向量來避免相同的明文產(chǎn)生相同的密文,一定程度上抵抗字典攻擊;
- 一個錯誤發(fā)生以后,當前和以后的密文都會被影響;
填充方式
常見的填充方式PKCS5Padding,PKCS5Padding表示當數(shù)據(jù)位數(shù)不足的時候要采用的數(shù)據(jù)補齊方式,也可以叫做數(shù)據(jù)填充方式。PKCS5Padding這種填充方式,具體來說就是“填充的數(shù)字代表所填字節(jié)的總數(shù)”
比如說,差兩個字節(jié),就是######22,差5個字節(jié)就是###55555,這樣根據(jù)最后一個自己就可以知道填充的數(shù)字和數(shù)量。
保證加密解密的一致性
在不同的平臺上,只要能保證這幾個參數(shù)的一致,就可以實現(xiàn)加密和解密的一致性。
- 加密和解密的密鑰一致
- 采用CBC模式的時候,要保證初始向量一致
- 采用相同的填充模式
python中的des加密
在python中,我們使用pyDes對數(shù)據(jù)進行des加密:
# pyDes.des(key, [mode], [IV], [pad], [padmode])
key
:des的加密解密密鑰。mode
: 加密模式:支持CBC,ECB兩種模式IV
: 初始化向量,這是CBC模式專有的,長度為8 bytes。使用不同的初始化向量加密避免產(chǎn)生相同的密文,一定程度上抵抗字典攻擊。pad
: 當padmode設(shè)置為PAD_NORMAL時,用pad參數(shù)來指定填充方式。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)
傳遞過來的加密數(shù)據(jù): xUjw0iO7uhymZ+h/VB9kvhubiAEv4Kzz
通過k解密出來的數(shù)據(jù):@IDX_^\x10Ys powerful
這種情況通常發(fā)生在不同語言(java加密、python解密)對初始向量的處理方式不同造成的解密不完全。
解決辦法:檢查初始向量的表現(xiàn)形式。
k1 = des(des_key, mode=CBC, IV='\1\2\3\4\5\6\7\x08', padmode=PAD_PKCS5)
通過k1解密出來的數(shù)據(jù):python is powerful
OK!
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
數(shù)據(jù)結(jié)構(gòu) 雙向鏈表的創(chuàng)建和讀取詳解及實例代碼
這篇文章主要介紹了數(shù)據(jù)結(jié)構(gòu) 雙向鏈表的創(chuàng)建和讀取詳解及實例代碼的相關(guān)資料,需要的朋友可以參考下2017-03-03C++實現(xiàn)LeetCode(35.搜索插入位置)
這篇文章主要介紹了C++實現(xiàn)LeetCode(35.搜索插入位置),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-07-07