3DES文件加密程序
参照<<密码学引论>> 第二版 张焕国 王张宜编著这本书,用MFC编写的框架,实现的使用3DES对文件进行加解密的程序
转载请说明来源 : enjoy5512的博客 http://blog.csdn.net/enjoy5512
DES加密算法简介
1977年1月,美国政府颁布:采纳IBM公司设计的方案作为非机密数据的正式数据加密标准(DESData Encryption Standard) 。
目前在国内,随着三金工程尤其是金卡工程的启动,DES算法在POS、ATM、磁卡及智能卡(IC卡)、加油站、高速公路收费站等领域被广泛应用,以此来实现关键数据的保密,如信用卡持卡人的PIN的加密传输,IC卡与POS间的双向认证、金融交易数据包的MAC校验等,均用到DES算法。
DES算法的入口参数有三个:Key、Data、Mode。
其中Key为8个字节共64位,是DES算法的工作密钥;
Data也为8个字节64位,是要被加密或被解密的数据;
Mode为DES的工作方式,有两种:加密或解密。
DES算法是这样工作的:
如Mode为加密,则用Key 去把数据Data进行加密, 生成Data的密码形式(64位)作为DES的输出结果;
如Mode为解密,则用Key去把密码形式的数据Data解密,还原为Data的明码形式(64位)作为DES的输出结果。
在通信网络的两端,双方约定一致的Key,在通信的源点用Key对核心数据进行DES加密,然后以密码形式在公共通信网(如电话网)中传输到通信网络的终点,数据到达目的地后,用同样的Key对密码数据进行解密,便再现了明码形式的核心数据。这样,便保证了核心数据(如PIN、MAC等)在公共通信网中传输的安全性和可靠性。
通过定期在通信网络的源端和目的端同时改用新的Key,便能更进一步提高数据的保密性,这正是现在金融交易网络的流行做法。
3DES简介
3DES是DES加密算法的一种模式,它使用3条64位的密钥对数据进行三次加密。数据加密标准(DES)是美国的一种由来已久的加密标准,它使用对称密钥加密法。
3DES(即Triple DES)是DES向AES过渡的加密算法(1999年,NIST将3-DES指定为过渡的加密标准),是DES的一个更安全的变形。它以DES为基本模块,通过组合分组方法设计出分组加密算法。
设Ek()和Dk()代表DES算法的加密和解密过程,K代表DES算法使用的密钥,P代表明文,C代表密表,这样,
3DES加密过程为:C=Ek3(Dk2(Ek1(P)))
3DES解密过程为:P=Dk1((EK2(Dk3(C)))
K1、K2、K3决定了算法的安全性,若三个密钥互不相同,本质上就相当于用一个长为168位的密钥进行加密。多年来,它在对付强力攻击时是比较安全的。若数据对安全性要求不那么高,K1可以等于K3。在这种情况下,密钥的有效长度为112位
3DES加密流程图
子密钥产生
16轮加密
3DES加解密
代码实现
(所有源码在我的github上可以得到github.com/whu-enjoy/3DES)
因为注释挺详细了,这里就不细说
下面是我作的一个函数调用图
其中对八字节的数据,调用EncryptBlock()三次
加密
解密
我的密钥一跟密钥三用的一样的
加解密的类的实现
/////////////////////////////////////////////////////////////////////////////
// DES class used for Encrypt/Decrypt
class DES : public CDialog{
public://公共静态成员数组static int s_ia56PC_1[56]; //子密钥产生算法中的PC1矩阵static int s_ia16MoveTimes[16]; //子密钥产生算法中的左移次数表static int s_ia48PC_2[48]; //子密钥产生算法中的PC2矩阵static int s_ia64IP[64]; //加密算法中的初始置换IP矩阵static int s_ia48E[48]; //加密算法中的扩展置换E矩阵static int s_ia8_4_16S_Box[8][4][16]; //加密算法中的S盒static int s_ia32P[32]; //加密算法中的P矩阵static int s_ia64IP_1[64]; //加密算法中的逆初始置换IP^-1矩阵int ia2_16_48K[2][16][48]; //子密钥public://程序说明开始//==================================================================================// 功能 : 将输入的无符号字符数组转化为相应的二进制,转换c_iCount个字节// 参数 : const unsigned char c_ucaByte[], int iaBin[], const int c_iCount// (入口) c_ucaByte : 需要转换的无符号字符数组// c_iCount : 需要转换的字节数// (出口) iaBin : 转换后的二进制流,用整型数组保存结果// 返回 : 无// 主要思路 : 对每个字节循环八次,第j次循环左移j次,再将最高位提取出来,就能获取这个// 字节的八位上的所有数据// 调用举例 : unsigned char uca5Pwd[5] = "test";// int ia32Bin[32];// ByteToBin(uca5Pwd, ia32Bin, 4);// 日期 : 2016年5月30日 19:17:10(注释日期)//==================================================================================//程序说明结束void ByteToBin(const unsigned char c_ucaByte[], int iaBin[], const int c_iCount){int i = 0;int j = 0;//循环转化c_iCount个字节for ( i = 0; i < c_iCount; i++) {for(j = 0; j < 8; j++) {//第j次循环时,左移j次,再检查最高位是否是1,如果是,则赋值为1,否则赋值为0if (0x80 == ((c_ucaByte[i]<<j)&0x80)){iaBin[i*8+j] = 1;}else{iaBin[i*8+j] = 0;}}} }//程序说明开始//==================================================================================// 功能 : 将输入的二进制转化为相应的无符号字符数组,转换c_iCount个字节// 参数 : const int c_iaBin[], unsigned char ucaByte[], const int c_iCount// (入口) c_iaBin : 需要转换的二进制流// c_iCount : 需要转换的字节数// (出口) ucaByte : 转换后的无符号字符数组// 返回 : 无// 主要思路 : 对每个字节循环八次,第j次循环将原来的值左移一位,并将新的值加到最低位// 调用举例 : unsigned char uca5Pwd[5] = "";// int ia32Bin[32] = {0,0,1,1,0,0,0,1,0,0,1,1,0,0,1,0,0,0,1,1,0,0,1,1,0,0,1,1,0,1,0,0};// BinToByte(ia32Bin, uca5Pwd, 4);// 日期 : 2016年5月30日 19:24:25(注释日期)//==================================================================================//程序说明结束void BinToByte(const int c_iaBin[], unsigned char ucaByte[], const int c_iCount){int i = 0;int j = 0;//转换c_iCount个字节for ( i = 0; i < c_iCount; i++) {for(j = 0; j < 8; j++) {//每次将原来的值左移一位,并加上新提取的ucaByte[i] = ucaByte[i] * 2 + c_iaBin[i*8+j];}} }//程序说明开始//==================================================================================// 功能 : 根据输入的第二个矩阵将第一个矩阵进行转换,转换的结果保存在第三个矩阵里,// 转换c_iCount个数据// 参数 : const int c_iaSource[], const int c_iaReplaceTable[]// int iaReplaced[], const int c_iCount// (入口) c_iaSource : 需要转换的矩阵// c_iaDisplaceTable : 转换参考矩阵// c_iCount : 需要转换的数据个数// (出口) iaReplaced : 转换后的矩阵// 返回 : 无// 主要思路 : iaReplaced矩阵的第i个位置上的数是c_iaSource矩阵中// 第c_iaReplaceTable[i]个位置的数据// 调用举例 : int ia64Source[64] = {xxxxx};// int ia48Replace[48] = {xxxx};// int ia48Replaced[48] = {0};// Replacement(ia64Source, ia48Replace, ia48Replaced, 48);// 日期 : 2016年5月30日 19:39:24(注释日期)//==================================================================================//程序说明结束void Replacement(const int c_iaSource[], const int c_iaReplaceTable[], int iaReplaced[], const int c_iCount){int i = 0;//循环c_iCount次for (i = 0; i < c_iCount; i++){//根据c_iaReplaceTable[]置换原表iaReplaced[i] = c_iaSource[c_iaReplaceTable[i]-1];}}//程序说明开始//==================================================================================// 功能 : 将输入矩阵里面的数据左移c_iCount次,用ia28Output保存左移后的结果// 参数 : const int c_ia28Input[28], int ia28Output[28], const int c_iCount// (入口) c_ia28Input : 需要左移的数组// c_iCount : 需要左移的数据个数// (出口) ia28Output : 左移后的数组// 返回 : 无// 主要思路 : 先将原数组前c_iCount个数据保存在局部变量i2Temp中,然后输出数组的// 前28-c_iCount数据左移c_iCount位,再将i2Temp中的数据接到输出数组中// 这样做的时候,输入数组盒输出数组可以是同一个数组,减少内存空间使用量// 调用举例 : int ia28C[28] = {xxxxx};// LeftMove(ia28C, ia28C, 2);// 日期 : 2016年5月30日 19:49:46(注释日期)//==================================================================================//程序说明结束void LeftMove(const int c_ia28Input[28], int ia28Output[28], const int c_iCount){int i2Temp[2] = {0}; //用于保存要移动的输入数组前c_iCount个变量int i = 0;//保存前c_iCount个变量for (i = 0; i < c_iCount; i++){i2Temp[i] = c_ia28Input[i];}//将原数组后28-c_iCount个数前移c_iCount个位置for (i = 0; i < 28-c_iCount; i++){ia28Output[i] = c_ia28Input[i+c_iCount];}//将原数组前c_iCount个数接到输出数组后for (; i < 28; i++){ia28Output[i] = i2Temp[c_iCount + i - 28];}}//程序说明开始//==================================================================================// 功能 : 根据输入的64位密钥,输出16组48位的子密钥// 参数 : const int c_ia64Pwd[64], int ia16_48K[16][48]// (入口) c_ia64Pwd : 输入64位密钥// (出口) ia16_64K : 16组48位子密钥// 返回 : 无// 主要思路 : 先将64位密钥通过PC1矩阵得到56位密钥,再将密钥分为左右两部分,根据左移表// 循环左移16轮,每轮循环后合并成56位中间数据,然后在通过PC2矩阵得到48位子密钥// 调用举例 : int ia64Pwd[64] = {xxxxx};// int ia16_48K[16][48] = {0}// SubKey(ia64Pwd, ia16_48K);// 日期 : 2016年5月30日 19:58:32(注释日期)//==================================================================================//程序说明结束void SubKey(const int c_ia64Pwd[64], int ia16_48K[16][48]){int ia56Key[56] = {0}; //保存56位的密钥int ia28C[28] = {0}; //保存28位的密钥左部分int ia28D[28] = {0}; //保存28位的密钥右部分int i = 0;int j = 0;//先从给定的64位密钥中通过PC_1矩阵获取56位的密钥Replacement(c_ia64Pwd, s_ia56PC_1, ia56Key, 56); //得到密钥左右部分for (i = 0; i < 28; i++){ia28C[i] = ia56Key[i];ia28D[i] = ia56Key[28+i];}//循环获取16轮密钥for (i = 0; i < 16; i++){//分别左移左右部分的密钥LeftMove(ia28C,ia28C,s_ia16MoveTimes[i]);LeftMove(ia28D,ia28D,s_ia16MoveTimes[i]);//密钥合并for (j = 0; j < 28; j++){ia56Key[j] = ia28C[j];ia56Key[28+j] = ia28D[j];}//通过置换选择2矩阵获取每一轮产生的密钥Replacement(ia56Key,s_ia48PC_2,ia16_48K[i],48);}}//程序说明开始//==================================================================================// 功能 : 加密函数,在第i次迭代中用子密钥Ki对Ri-1进行加密// 参数 : const int c_ia32A[32], const int c_ia48K[48], int ia32Output[32]// (入口) c_ia32A : 输入32位数据// c_ia48K : 48位子密钥// (出口) ia32Output : 32位加密结果// 返回 : 无// 主要思路 : 先用选择运算矩阵E对输入数据进行选择和排列,输出48位中间结果,这个结果和// 48位子密钥异或,然后送入S盒,得到32位输出结果,这个结果再经过置换运算P,// 将每一位打乱重排,得到加密结果// 调用举例 : int ia32Pwd[32] = {xxxxx};// int ia48K[48] = {xxx}// int ia32Output[32] = {0};// F(ia32Pwd, ia48K, iaOutput);// 日期 : 2016年5月30日 20:07:24(注释日期)//==================================================================================//程序说明结束void F(const int c_ia32A[32], const int c_ia48K[48], int ia32Output[32]){int ia48Temp[48] = {0}; //48位的中间数据int iRow = 0; //S盒的行int iCol = 0; //S盒的列int i = 0;//先将32位输入通过选择运算E扩展成48位Replacement(c_ia32A, s_ia48E, ia48Temp, 48);//48位中间结果与子密钥异或for (i = 0; i < 48; i++){ia48Temp[i] = ia48Temp[i] ^ c_ia48K[i];}//循环从S盒中获取32位的输出结果for (i = 0; i < 8; i++){//获取行列iRow = ia48Temp[i*6]*2 + ia48Temp[i*6+5];iCol = ia48Temp[i*6+1]*8 + ia48Temp[i*6+2]*4 + ia48Temp[i*6+3]*2 + ia48Temp[i*6+4];//获取S盒中的数据,并转化成四位输出ia48Temp[i*4+0] = (s_ia8_4_16S_Box[i][iRow][iCol]&8)/8;ia48Temp[i*4+1] = (s_ia8_4_16S_Box[i][iRow][iCol]&4)/4;ia48Temp[i*4+2] = (s_ia8_4_16S_Box[i][iRow][iCol]&2)/2;ia48Temp[i*4+3] = (s_ia8_4_16S_Box[i][iRow][iCol]&1);}//将S盒的32位输出通过P矩阵获取最终的32位输出Replacement(ia48Temp, s_ia32P, ia32Output, 32);}//程序说明开始//==================================================================================// 功能 : 对8字节的数据进行加解密,c_bFlag为false代表加密操作,为true代表解密操作// 参数 : unsigned char uc9PlainText[9], const int c_ia16_48K[16][48], const bool c_bFlag// (入口) c_ia_16_48K : 16轮子密钥// c_bFlag : 加解密标志// (出口) uc9Data : 32位加密结果// 返回 : 无// 主要思路 : 先将输入的八字节数据转化为64位二进制,然后将64位二进制明文用初始置换// 矩阵IP打乱,获取左右半部分,然后进行16轮加密,每轮加密中,下一轮的左部分// 是上一轮的右部分,然后用F函数实现密钥K对上一轮右部分加密,得到的结果再// 与上一轮的左部分异或,得到下一轮的右部分数据,这样循环16次.第十六次迭代// 结束后,将结果的左部分接到右部分上,得到64位的输出,然后将64位数据经过逆// 初始化矩阵IP^-1重新排列,得到最终密文// 调用举例 : unsigned char uc9Str = "12346578";// int ia16_48K[16][48] = {xxx}// EncryptBlock(uc9Str, ia16_48K, false); //加密// EncryptBlock(uc9Str, ia16_48K, true); //解密// 日期 : 2016年5月30日 20:20:41(注释日期)//==================================================================================void EncryptBlock(unsigned char uc9Data[9], const int c_ia16_48K[16][48], const bool c_bFlag){int ia64Data[64] = {0}; //加密的数据的64位二进制int ia64Bin[64] = {0}; //临时保存64位二进制数据int ia32L_BK[32] = {0}; //每轮加密的左部分int ia32R_BK[32] = {0}; //每轮加密的右部分int ia32L[32] = {0}; //每轮加密结果的左部分int ia32R[32] = {0}; //每轮加密结果的右部分int i = 0;int j = 0;//将输入的8字节转换成64位二进制ByteToBin(uc9Data, ia64Data, 8);//将64位二进制明文通过初始置换矩阵IP打乱Replacement(ia64Data,s_ia64IP,ia64Bin,64);//获取每轮加密的64位数据的左右部分for (i = 0; i < 32; i++){ia32L_BK[i] = ia64Bin[i];ia32R_BK[i] = ia64Bin[32+i];}//16轮加密for (i = 0; i < 16; i++){//获取每轮加密后的左部分for (j = 0; j < 32; j++){ia32L[j] = ia32R_BK[j];}//如果c_bFlag为false,则加密,为true则解密if (0 == c_bFlag){F(ia32R_BK,c_ia16_48K[i],ia32R); //加密}else{F(ia32R_BK,c_ia16_48K[15-i],ia32R); //解密}//获取每轮加密后的右部分for (j = 0; j < 32; j++){ia32R[j] = ia32R[j] ^ ia32L_BK[j];}//保存当前左右部分的数据for (j = 0; j < 32; j++){ia32L_BK[j] = ia32L[j];ia32R_BK[j] = ia32R[j];}}//16轮加密后,把加密结果的左部分接到右部分后面for (i = 0; i < 32; i++){ia64Bin[i] = ia32R[i];ia64Bin[i+32] = ia32L[i];}//通过逆初始化矩阵,获取加密后的64位数据Replacement(ia64Bin, s_ia64IP_1, ia64Data, 64);//将64位数据转化为8位输出BinToByte(ia64Data, uc9Data, 8);}//程序说明开始//==================================================================================// 功能 : 对文件进行加密// 参数 : const CString c_csOpenFilePath, const CString c_csSaveFilePath// const unsigned char c_uca9Pwd1[9], const unsigned char c_uca9Pwd2[9]// (入口) c_csOpenFilePath : 要加密的文件路径// c_csSaveFilePath : 加密后的文件保存路径// c_uca9Pwd1 : 密钥一// c_uca9Pwd2 : 密钥二// (出口) 无// 返回 : true代表加密成功, false代表打开加密文件或创建保存加密结果的文件失败// 主要思路 : 1.先打开文件指针// 2.根据输入的两个密钥,获取两组16*48位的子密钥// 3.获取加密文件长度,写入保存文件的前八字节// 4.获取加密文件类型,写入保存文件的9-16字节// 5.循环读取加密文件,每次读取八字节,文件尾不够的用0填充到8字节.// 在每轮循环里,先用子密钥一对数据加密,然后用密钥二对数据解密// 然后再用密钥一对数据加密,之后将加密后的数据写入文件// 调用举例 : CString csOpenFilePath = L"c:\test.txt";// CString csSaveFilePath = L"c:\test.ept":// unsigned char uca9Pwd1[9] = "12345678";// unsigned char uca9Pwd2[9] = "98756412";// DES CcmDes;// CcmDes.FileEncrypt(csOpenFilePath, csSaveFilePath, uca9Pwd1, uca9Pwd2);// 日期 : 2016年5月30日 20:36:32(注释日期)//==================================================================================bool FileEncrypt(const CString c_csOpenFilePath, const CString c_csSaveFilePath, const unsigned char c_uca9Pwd1[9], const unsigned char c_uca9Pwd2[9]){CString csFileExt = L""; //保存加密后的文件的后缀名unsigned char uc9PlainText[9] = {0}; //保存8字节的数据int ia64Bin[64] = {0}; //保存64位中间结果bool bStatus = true; //设置返回状态为trueFILE *pOpenFile = NULL; //加密文件指针FILE *pSaveFile = NULL; //加密结果文件指针int iCharNum = 0; //读取的字节数int i = 0; int j = 0;int iFileLen = 0; //加密文件长度//打开加密文件指针if (NULL == (pOpenFile = fopen(c_csOpenFilePath,"rb"))){MessageBox("打开解密文件失败!");return false;}//打开加密后的文件指针if (NULL == (pSaveFile = fopen(c_csSaveFilePath,"wb"))){MessageBox("创建文件失败!");return false;}//将8字节密钥一转化为64位二进制ByteToBin(c_uca9Pwd1, ia64Bin, 8);//获取16轮子密钥一SubKey(ia64Bin,ia2_16_48K[0]);//将8字节密钥二转化为64位二进制ByteToBin(c_uca9Pwd2, ia64Bin, 8);//获取16轮子密钥2SubKey(ia64Bin,ia2_16_48K[1]);//将文件指针移动到文件尾fseek(pOpenFile, 0, SEEK_END);//获取文件长度iFileLen = ftell(pOpenFile);//将文件指针设置回文件头fseek(pOpenFile, 0, SEEK_SET);//将文件长度保存,为了满足八字节,所以写了两次fwrite(&iFileLen,4,1,pSaveFile);fwrite(&iFileLen,4,1,pSaveFile);//获取加密文件的后缀名csFileExt = c_csOpenFilePath.Mid(c_csOpenFilePath.ReverseFind('.')+1);//将加密文件后缀名写入加密后的文件,以便于解密时恢复源文件fwrite(csFileExt,1,8,pSaveFile);//设置读取的字节数为0iCharNum = 0;//循环读取加密文件,直到文件尾while(0 != (iCharNum = fread(uc9PlainText,1,8,pOpenFile))){//如果读取到的不是8个字节,说明到文件尾了,填充0到八字节长if (8 != iCharNum){for (i = iCharNum; i < 8; i++){uc9PlainText[i] = 0;}}//用密钥一加密EncryptBlock(uc9PlainText, ia2_16_48K[0], false);//用密钥二解密EncryptBlock(uc9PlainText, ia2_16_48K[1], true);//再用密钥一加密EncryptBlock(uc9PlainText, ia2_16_48K[0], false);//将加密结果写入文件fwrite(uc9PlainText, 1, 8, pSaveFile);}//关闭文件指针,返回fclose(pOpenFile);fclose(pSaveFile);return bStatus;}//程序说明开始//==================================================================================// 功能 : 对文件进行解密// 参数 : const CString c_csOpenFilePath, CString csSaveFilePath// const unsigned char c_uca9Pwd1[9], const unsigned char c_uca9Pwd2[9]// (入口) c_csOpenFilePath : 要解密的文件路径// c_uca9Pwd1 : 密钥一// c_uca9Pwd2 : 密钥二// (出口) csSaveFilePath : 解密后的文件保存路径// 返回 : true代表解密成功, false代表打开解密文件或创建保存解密结果的文件失败// 主要思路 : 1.先打开解密文件指针// 2.读取解密文件前4字节获取解密后的文件大小// 3.读取解密文件8-16字节获取解密后的文件类型// 4.创建解密后的文件// 5.根据输入的两个密钥,获取两组16*48位的子密钥// 8.循环读取解密文件,每次读取八字节,已解密的数据长度加8// 在每轮循环里,先用子密钥一对数据解密,然后用密钥二对数据加密// 然后再用密钥一对数据解密// 如果已解密的数据长度小于文件长,则写入后继续解密// 否则,写入数据到原文件长度(原文件并不一定是8字节对齐// 但是加密后的文件却填充到8字节对齐状态),并退出解密// 调用举例 : CString csOpenFilePath = L"c:\test.ept";// CString csSaveFilePath = L"c:\test.":// unsigned char uca9Pwd1[9] = "12345678";// unsigned char uca9Pwd2[9] = "98756412";// DES CcmDes;// CcmDes.FileDecrypt(csOpenFilePath, csSaveFilePath, uca9Pwd1, uca9Pwd2);// 日期 : 2016年5月30日 20:49:46(注释日期)//==================================================================================bool FileDecrypt(const CString c_csOpenFilePath, CString csSaveFilePath, const unsigned char c_uca9Pwd1[9], const unsigned char c_uca9Pwd2[9]){char ca8FileExt[8] = {0}; //保存解密后的文件的后缀名unsigned char uc9PlainText[9] = {0}; //保存8字节数据int ia64PlainText[64] = {0}; //保存64位数据int ia64Bin[64] = {0}; //保存64为中间数据bool bStatus = true; //设置返回状态为trueFILE *pOpenFile = NULL; //要解密的文件指针FILE *pSaveFile = NULL; //解密后的文件指针int iFileLen = 0; //文件长度int iDecryptedCharNum = 0; //已解密的数据长度int i = 0;int j = 0;//打开要解密的文件指针if (NULL == (pOpenFile = fopen(c_csOpenFilePath,"rb"))){MessageBox("打开解密文件失败!");return false;}//读取要解密的文件头四个字节,获取解密后的文件的长度//读取两遍是为了8字节对齐fread(&iFileLen,4,1,pOpenFile);fread(&iFileLen,4,1,pOpenFile);//读取要解密的文件的9-16字节数据,获取解密后的文件后缀名fread(ca8FileExt,1,8,pOpenFile);//将后缀名连接到解密后的文件路径中csSaveFilePath = csSaveFilePath + ca8FileExt;//打开解密后的文件指针if (NULL == (pSaveFile = fopen(csSaveFilePath,"wb"))){MessageBox("创建文件失败!");return false;}//将密钥一转化为64位二进制ByteToBin(c_uca9Pwd1, ia64Bin, 8);//获取16轮子密钥一SubKey(ia64Bin, ia2_16_48K[0]);//将密钥二转化为64位二进制ByteToBin(c_uca9Pwd2, ia64Bin, 8);//获取16轮子密钥二SubKey(ia64Bin, ia2_16_48K[1]);//设置已解密的数据长度为0iDecryptedCharNum = 0;//循环解密while(1){//读取8字节密文fread(uc9PlainText,1,8,pOpenFile);//已解密数据长度加8iDecryptedCharNum += 8;//用子密钥一解密EncryptBlock(uc9PlainText, ia2_16_48K[0], true);//用子密钥二加密EncryptBlock(uc9PlainText, ia2_16_48K[1], false);//用子密钥一解密EncryptBlock(uc9PlainText, ia2_16_48K[0], true);//如果已解密的数据长度小于文件长,则写入后继续解密//否则,写入数据到原文件长度(原文件并不一定是8字节对齐//但是加密后的文件却填充到8字节对齐状态),并退出解密if (iDecryptedCharNum < iFileLen){fwrite(uc9PlainText, 1, 8, pSaveFile);}else{fwrite(uc9PlainText, 1, 8 + iFileLen - iDecryptedCharNum, pSaveFile);break;}}//关闭文件指针,并退出fclose(pOpenFile);fclose(pSaveFile);return bStatus;}
};//子密钥产生算法中的置换选择2矩阵
int DES::s_ia56PC_1[56] =
{57, 49, 41, 33, 25, 17, 9,1, 58, 50, 42, 34, 26, 18,10, 2, 59, 51, 43, 35, 27,19, 11, 3, 60, 52, 44, 36,63, 55, 47, 39, 31, 23, 15,7, 62, 54, 46, 38, 30, 22,14, 6, 61, 53, 45, 37, 29,21, 13, 5, 28, 20, 12, 4
};//子密钥产生算法中左移位数表
int DES::s_ia16MoveTimes[16] = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};//子密钥产生算法中的置换选择2矩阵
int DES::s_ia48PC_2[48] =
{14, 17, 11, 24, 1, 5,3, 28, 15, 6, 21, 10,23, 19, 12, 4, 26, 8,16, 7, 27, 20, 13, 2,41, 52, 31, 37, 47, 55,30, 40, 51, 45, 33, 48,44, 49, 39, 56, 34, 53,46, 42, 50, 36, 29, 32
};//初始置换IP矩阵
int DES::s_ia64IP[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
};//扩展置换E矩阵
int DES::s_ia48E[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
};//S盒
int DES::s_ia8_4_16S_Box[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矩阵
int DES::s_ia32P[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
};//逆初始置换IP^-1
int DES::s_ia64IP_1[64] =
{40, 8, 48, 16, 56, 24, 64, 32,39, 7, 47, 15, 55, 23, 63, 31,38, 6, 46, 14, 54, 22, 62, 30,37, 5, 45, 13, 53, 21, 61, 29,36, 4, 44, 12, 52, 20, 60, 28,35, 3, 43, 11, 51, 19, 59, 27,34, 2, 42, 10, 50, 18, 58, 26,33, 1, 41, 9, 49, 17, 57, 25
};
3DES文件加密程序相关推荐
- 贴别人的一个文件加密程序!
代码下载 using System; using System.Collections.Generic; using System.Linq; using System.Text; using Sys ...
- Android破解之Lic文件加密程序(首例)
我不会写Android,这是我第一个破解Android的例子,耗时接近一天,希望大神不要见笑! 本程序为商业软件,不便发布APK程序. 不要给我发消息,我不得回,有问题,直接回帖就可以了. 准备工作 ...
- C语言实现DES,3DES以及基于3DES的文件加密系统
C语言实现3DES文件加密系统 DES算法 密钥操作 明文操作 3DES算法 C语言代码实现 代码效果展示 DES算法 DES(数据加密标准)是一种分组密码.明文,密文和密钥的分组长度都是64位. D ...
- python编写加密程序_用Python实现一个简单的加密程序
生活中,有时候我们需要对一些重要的文件进行加密,Python 提供了诸如 hashlib,base64 等便于使用的加密库. 对于日常学习而言,我们可以借助异或操作,实现一个简单的文件加密程序,从而强 ...
- c语言文件加密大写字母,C语言 文件加密解密
#includejiemi() { int k,l; char fn[40],fs[40]; char ch,mima[40],x; file *f1,*f2; printf("输入要解密的 ...
- Zxy97Encryption 加密程序
Zxy97Encryption 加密程序 ,支持国际化语言(中/英),使用方法: java -jar jar包路径 <文件输入路径> <文件输出路径> <数字密码,0表示 ...
- c语言文件加密解密单词统计,C语言文件加密解密及单词统计程序.doc
C语言文件加密解密及单词统计程序.doc (10页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 15.9 积分 高级语言程序设计 课程设计学 院 计算 ...
- php 3des 兼容java,java版3des加密程序,可与php兼容
java版3des加密程序,可与php兼容 时间:2009-03-29 22:35来源:未知 作者:admin 点击:次 代码: import java.io.UnsupportedEncodingE ...
- C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统
基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于C#+asp.net+C++的RSA文件加密系统设计与实现,文章末尾附有本毕业设计的论文 ...
最新文章
- python使用matplotlib可视化线图(line plot)、使用arrow函数在matplotlib可视化图像中添加箭头(drawing arrows in matplotlib)
- bash命令行常用快捷键
- linux redis php,Linux下编译redis和phpredis的方法
- leader选举的源码分析-Messenger
- 华为p40pro怎么用鸿蒙系统,华为p40pro鸿蒙系统正式版
- windows下的workon env
- Kubernetes vs OpenStack
- 编辑器安卓手机版_手机上最专业的视频编辑器,内购版!
- Java练手项目(好玩又有趣)
- vue使用wangeditor自定义表情替换QQ表情
- 人工智能知识全面讲解:最简单的神经元模型
- 王者荣耀李白王昭君情侣头像故事: “风雨如晦,鸡鸣不已。既见君子,云胡不喜。”...
- html submit修改名称,HTML Input Submit name用法及代码示例
- nas 软件 性能测试,NAS性能测试器(NAS performance tester)
- 【SIFT算法】极值检测关键点精确定位
- auto CAD 二次开发 c#.net 之JIG画多段线(polyline)
- 计量经济学及Stata应用 第七章 异方差
- Kotlin中的数据存储
- 蓝桥杯真题系列:第十一届蓝桥杯C语言B组集锦
- Oracle中查询用户表/索引/视图的创建语句