admin管理员组

文章数量:1639675

参照<<密码学引论>> 第二版 张焕国 王张宜编著这本书,用MFC编写的框架,实现的使用3DES对文件进行加解密的程序
转载请说明来源 : enjoy5512的博客 http://blog.csdn/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/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,否则赋值为0
                if (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(注释日期)
    //==================================================================================
    

本文标签: 文件加密程序des