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]={//S114, 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,//S215, 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,//S310, 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,//S47, 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,//S52, 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,//S612, 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,//S74, 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,//S813, 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位数据的左32bool dataR32_table[des_data_rl]={0}; //64位数据的右32bool tmpL32_table[des_data_rl]={0}; //临时64位数据的左32bool 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~0x07if(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))){//将长度进行减1retData->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~0x07if(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))){//将长度进行减1retData->dataLenght--;}else{//遇到正常数据进行退出循环break;}}}//释放16个子密钥free(subkey1);free(subkey2);free(subkey3);//返回加密后的数据return retData;
}
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加密与解密
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, …...
【笔记】优先队列(priority_queue/set)
目录 大根堆 小根堆 set(小根堆) 大根堆 题目链接:洛谷 P3243 菜肴制作 题目描述 知名美食家小 A 被邀请至 ATM 大酒店,为其品评菜肴。ATM 酒店为小 A 准备了 n 道菜肴,酒店按照为菜肴预估的质量从高到低给予 1 到…...
看看安森美深力科NSI45090JDT4G 是如何点亮汽车内外照明系统解决方案
关于线性恒流调节器(CCR):是一种用于控制电流的稳定输出。它通常由一个功率晶体管和一个参考电流源组成。CCR的工作原理是通过不断调节功率晶体管的导通时间来维持输出电流的恒定。当输出电流超过设定值时,CCR会减少功率晶体管的导…...
Linux进阶之Shell-sed
基本用法: sed 选项 “指令” 文件 常用选项: -e --它告诉sed将下一个参数解释为一个sed指令,只有当命令行上给出多个sed指令时使用 -f --后跟保存了sed指令的文件 -i --直接对内容进行修改,不加 i 时默认只是预…...
前端高频面试题 Day02
面试题 var 和 let const 的区别 var 是 ES5 及之前的语法,let const 是 ES6 语法var 和 let 是变量,可修改;const 是常量,不可修改var 有变量提升,let const 没有var 没有块级作用域,let const 有 &…...
MYSQL完全卸载、安装与账号创建、权限控制
一、卸载mysql CentOS 卸载 MySQL 1. 查看安装情况 使用以下命令查看当前安装mysql情况,查找以前是否装有mysql rpm -qa|grep -i mysql这里显示我安装的 MySQL 服务有有: 2. 停止 mysql 服务、删除之前安装的 mysql 删除命令:rpm -e –n…...
get与post如何拼接url与数据的灵活处理,循环的重要性。
get与post拼接url地址不同: let postData {method: "post",data: {op: "/api/setting/maintenanceperiod?period"this.authorizationCode,loadingConfig: {},data: {period:this.authorizationCode}}}; if(this.editData.id){let postData …...
Remote Sensing,2023 | 基于SBL的分布式毫米波相干雷达成像的高效实现
Remote Sensing,2023 | 基于SBL的分布式毫米波相干雷达成像的高效实现 注1:本文系“无线感知论文速递”系列之一,致力于简洁清晰完整地介绍、解读无线感知领域最新的顶会/顶刊论文(包括但不限于 Nature/Science及其子刊; MobiCom, Sigcom, MobiSys, NSDI…...
Android学习之路(5) UI控件之Button (按钮)与 ImageButton (图像按钮)
本节引言: 今天给大家介绍的Android基本控件中的两个按钮控件,Button普通按钮和ImageButton图像按钮; 其实ImageButton和Button的用法基本类似,至于与图片相关的则和后面ImageView相同,所以本节 只对Button进行讲解&am…...
Day 31 C++ STL常用算法(下)
文章目录 常用拷贝和替换算法copy——容器内指定范围的元素拷贝到另一容器中函数原型注意——利用copy算法在拷贝时,目标容器要提前开辟空间示例 replace——将容器内指定范围的第一个旧元素修改为新元素函数原型注意——replace只会替换区间内满足条件的第一个旧元…...
【Android Studio】 win11 安装配置 jdk17 超详细
概述 一个好的安装教程能够帮助开发者完成更便捷、更快速的开发。书山有路勤为径,学海无涯苦作舟。我是秋知叶i、期望每一个阅读了我的文章的开发者都能够有所成长。 一、下载JDK JDK官网 这里下载 JDK17 windows x64 installer 二、安装JDK 双击打开下载的 j…...
IDEA下方工具栏SideBar没有Services解决方法 IDEA配合微服务学习多端口管理打开Services栏方法
问题 微服务学习时,一次要打开多个端口,比如8080给order模块、8081给user模块……这就需要用idea管理多端口。 这时候就可以用到Services栏进行管理。 解决 首先看下方Sidebar没有Services。 打开Services 打开方式一:手动打开 在IDEA中…...
[Vue warn]: Error in render: “SyntaxError: “undefined“ is not valid JSON“
[Vue warn]: Error in render: “SyntaxError: “undefined” is not valid JSON” 这说明出现了undefined这个变量类型,比如JSON.parse()时候会出现,可以先尝试打印JSON.parse()括号中的内容是否是undefined,如果是,那问题的根源…...
ui设计师工作总结及计划范文模板
ui设计师工作总结及计划范文模板【篇一】 白驹过隙,转眼间某某年已近结尾,时间伴随着我们的脚步急驰而去,到了个人工作总结的时候,蓦然回首,才发现过去的一年不还能画上圆满的句号,内心感慨万千,…...
【Kafka】2.在SpringBoot中使用官方原生java版Kafka客户端
目 录 1. 新建一个消息生产者2. 新建一个消息消费者3. 测 试 在开始之前,需要先做点准备工作,用 IDEA 新建一个 Maven 项目,取名 kafka-study,然后删掉它的 src 目录,接着在 pom.xml 里面引入下面的依赖。这个项目的作…...
使用腾讯云轻量服务器Matomo应用模板建网站流量统计系统
腾讯云百科分享使用腾讯云轻量应用服务器Matomo应用模板搭建网站流量统计系统,Matomo 是一款开源的网站数据统计软件,可以用于跟踪、分析您的网站的流量,同时充分保障数据安全性、隐私性。该镜像基于 CentOS 7.6 64位操作系统,已预…...
clickhouse-监控配置
一、概述 监控是运维的一大利器,要想运维好clickhouse,首先就要对其进行监控,clickhouse有几种监控数据的方式,一种是系统本身监控,一种是通过exporter来监控,下面分别描述一下 二、系统自带监控 我下面会对监控做一…...
C++11并发与多线程笔记(5)互斥量概念、用法、死锁演示及解决详解
C11并发与多线程笔记(5)互斥量概念、用法、死锁演示及解决详解 1、互斥量(mutex)的基本概念2、互斥量的用法2.1 lock(),unlock()2.2 lock_guard类模板 3、死锁3.1 死锁演示3.2 死锁的一般解决方案:3.3 std:…...
华为云classroom赋能--Devstar使应用开发无需从零开始
华为云DevStar为开发者提供业界主流框架代码初始化能力,通过GUI、API、CLI等多种方式,将按模板生成框架代码的能力推送至用户桌面。同时基于华为云服务资源、成熟的DevOps开发工具链和面向多场景的众多开发模板,提供一站式创建代码仓、自动生…...
软件的数据回滚
原理:所谓的数据回滚,就是数据备份 增量备份: 全量备份: 最简单的事全量备份。 就是spoon工具,完成把所有的表每天定时复制一份,表名“_日期”。 所以有实时表,每日备份表。 回滚就是把之前…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
WebRTC从入门到实践 - 零基础教程
WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC? WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音…...
