C语言实现数据保护算法(1)——DES&3DES加解密

最近简单的学习了一些常用的数据处理算法,在这里我简单的做一个系列笔记和大家一起学习国内外一些常见的数据处理算法,之前也做了java的实现,但是由于考虑到性能问题最终还是采用的C语言实现(文章末尾附带VC6.0 源码)。好了废话不多说,进入我们本次主角的正题——DES。

初识DES:

DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。随着攻击技术的发展,DES本身又有发展,如衍生出可抗差分分析攻击的变形DES以及密钥长度为128比特的三重DES等。需要注意的是DES算法已经在2000年1月19日被电子边疆基金会组织成功的破解,所以单纯地DES已经不是一种安全的算法。

DES是一个分组加密算法,它以64位为分组对数据加密。64位一组的明文从算法的一端输入,64位的密文从另一段输出。它是一个对称算法:加密和解密用的是同一个算法。   密钥通常表示为64位的数,但每个第8位都用作奇偶校验,可以忽略,所以密钥长度为56位。密钥可以是任意的56位的数,且可在任意的时候改变。DES算法只不过是加密的两个基本技术——混乱和扩散的组合,即先代替后置换,它基于密钥作用于明文,这是一轮(round),DES在明文分组上实施16轮相同的组合技术。

DES对64位明文分组进行操作。通过一个初始置换,将明文分组分成左半部分和右半部分,各32位长。然后进行16轮完全相同的运算,这些运算被称为函数 f,在运算过程中数据与密钥结合。经过16轮后,左、右半部分合在一起经过一个末置换(初始置换的逆置换),算法就完成了。在每一轮中,密钥位移位,然后再从密钥的56位中选出48位。通过一个扩展置换将数据的右半部分扩展成48位,并通过一个异或操作与48位密钥结合,通过 8个S盒将这48位替代成新的32位数据,再将其置换一次。这四步运算构成了函数f。然后,通过另一个异或运算,函数f的输出与左半部分结合,其结果即成为新的左半部分。将该操作重复16次,便实现了DES的16轮运算。假设Bi是第i次迭代的结果,Li和Ri是Bi的左半部分和右半部分,Ki是第i轮的48位密钥,且f是实现代替、置换及密钥异或等运算的函数,那么每一轮就是:

     Li=Ri-1

     Ri=Li-1⊕f(Ri-1,Ki)


DES运算包含初始置换、密钥置换、扩展置换、S盒代替、P盒置换和末置换等操作,解密函数和加密函数使用相同的函数区别在于调用的顺序相反。下面详细说下各个过程的原理。

初始置换

初始置换在第一轮运算之前进行,对输入分组实施如下表所示的变换。初始置换把明文的第58位换到第1位的位置,把第50位换到第2位的位置,把第42位换到第3位的位置,依此类推。

intIP_Table[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 };

初始置换和对应的末置换并不影响DES的安全性,它们的主要目的是为了更容易地将明文和密文数据以字节大小放入DES芯片中。

密钥置换:

由于不考虑每个字节的第8位,DES的密钥由64位减至56位,每个字节第8位作为奇偶校验以确保密钥不发生错误。如下表所示:

intPC1_Table[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 };

在DES的每一轮中,从56位密钥产生出不同的48位子密钥(subkey),这些子密钥是这样确定的:首先,56位密钥被分成两部分,每部分28位。然后,根据轮数,这两部分分别循环左移1位或2位。每轮移动的位数如下表:

轮      1 2  3  4 5  6  7 8  9  10 11  12  13 14  15  16

位数   1 1  2  2 2  2  2 2  1   2  2    2    2   2    2    1

移动后,就从56位中选出48位。这个运算既置换了每位的顺序,也选择了子密钥,被称为压缩置换(compressionpermutation)。下表即定义了压缩置换:

   int PC2_Table[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}; 

可以看出,第33位的那一位在输出时移到了第35位,而处于第18位的那一位被忽略了。

扩展置换:

扩展置换将数据的右半部分从32位扩展到48位。这个操作两方面的目的:它产生了与密钥同长度的数据以进行异或运算;它提供了更长的结果,使得在替代运算中能进行压缩。对每个4位输入分组,第1位和第4位分别表示输出分组中的两位,而第2位和第3位分别表示输出分组中的一位,下表给出了哪一输出位对应哪一输入位:

    int E_Table[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};

处于输入分组中第3位的位置移到了输出分组中的第4位,而输入分组的第21位则移到了输出分组的第30位和第32位。尽管输出分组大于输入分组,但每一个输入分组产生唯一的输出分组。

S盒代替:

压缩后的密钥与扩展分组异或以后,将48位的结果送入,进行代替运算。替代由8个S盒完成,每一个S盒都由6位输入,4位输出,且这8个S盒是不同的。48 位的输入被分为8个6位的分组,每一个分组对应一个S盒代替操作:分组1由S盒1操作,分组2由S盒2操作等等。

每一个S盒是一个4行、16列的表。盒中的每一项都是一个4位的数。S盒的6个位输入确定了其对应的输出在哪一行哪一列。下表列出所有8个S盒:

intS_Box[8][4][16] = {                    //8个S盒   三维数组 

        // 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};

假定将S盒的6位的输入标记位b1、b2、b3、b4、b5、b6。则b1和b6组合构成了一个2位数,从0到3,它对应着表的一行。从b2到b5构成了一个4位数,从0到15,对应着表中的一列。例如,假设第6个S盒的输入为110011,第1位和第6位组合形成了11,对应着第6个S盒的第三行,中间4位组合形成了1001,它对应着同一个S盒的第9列,S盒6在第三行第9列的数是14,则用值1110来代替110011。这是DES算法的关键步骤,所有其他的运算都是线性的,易于分析,而S盒是非线性的,它比DES的其他任何一步提供了更好的安全性。这个代替过程的结果是8个4位的分组,他们重新合在一起形成了一个32位的分组。

P盒置换:

S盒代替运算的32位输出依照P盒进行置换。该置换把每输入位映射到输出位,任一位不能被映射两次,也不能被略去,下表给出了每位移至的位置:

    int P_Table[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}; 

第21位移到了第4位,同时第4位移到了第31位。最后,将P盒置换的结果与最初的64位分组的左半部分异或,然后左、右半部分交换,接着开始另一轮。

末置换:

末置换是初始置换的逆过程。DES在最后一轮后,左半部分和右半部分并未交换,而是将两部分并在一起形成一个分组作为末置换的输入,该置换如下表如示:

    int IPR_Table[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 };


随着DES被成功的破解人们为了增加密钥的长度,人们建议将一种分组密码进行级联,在不同的密钥作用下,连续多次对一组明文进行加密,通常把这种技术称为多重加密技术。对DES,建议使用3DES增强加密强度。3DES算法是扩展DES密钥长度的一种方法,可使加密密钥长度扩展到128比特(112比特有效)或192比特(168比特有效)。

3DES可以用两个密钥对明文进行三次加密,假设两个密钥是K1和K2,

a.用密钥K1对数据进行DES加密。

b.用K2对步骤a的结果进行DES解密。

c.对b的结果使用密钥K1进行DES加密。

3DES的缺点是加、解密速度比DES慢。


本次测试的代码是DES算法的C语言实现(VC 6.0):

(1)加密
 输入:8个明文字符,8个密钥字符(例如“12345678”,“12345678”)
 将输入密钥和明文的8个字符各自转换为二进制,然后进行DES加密,输出加密结果
 将加密过程中第1,2轮E盒扩展,S盒置换,P盒替代中间结果输出
(2)解密
 输入:将加密之后得到的64比特密文作为输入
 输出:经过DES解密之后,输出8比特字符

具体代码如下:

 

/********************************Copyright ( c ) ********************************
**							   Shenzhen, China
** 					   http://blog.csdn.net/u011502387
**                        
**
** Created By:		崔龙龙
** Created Date:	2017-08-25
** Description:	    C语言实现数据DES&3DES加解密
** Version:         V1.0
** History:         NULL
** Declaration:		引用请注明出处,谢谢。
** 
****************************************************************************/
#include "stdafx.h"
#include<string.h>  

    int IP_Table[64] = {                                     //IP置换矩阵  
        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 };
		
    int E_Table[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}; 
		
    int P_Table[32] = {                                             //  P 盒  
        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};  

    int IPR_Table[64] = {                                    //逆IP置换矩阵  
        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 };
		
    int PC1_Table[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 PC2_Table[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};  

    int S_Box[8][4][16] = {                     //8个S盒   三维数组  
        // 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}; 

/****************************************************************************
Description:			把字符型数据转换为二进制整形数据(CharToBit)
Input parameters:		
                        char input[]:需要转换的char数组
						int bits:需要转换的字节位数
Output parameters:	    
                        int output[]:转换之后存放二进制的数组
                        
Returned value:		
                        NULL
Created by:			
                        崔龙龙 (2017-08-25)
Modified by:		   	
                        NULL
****************************************************************************/	

static void CharToBit(const char input[],int output[],int bits)
{  
    int i,j;  
    for(j=0;j<bits;j++)  
    {  
        for(i=0;i<8;i++)  
        {  
            output[7*(j+1)-i+j] = (input[j] >> i) & 1 ;  
        }  
    }  
};  

/****************************************************************************
Description:			把二进制整形数据转换为字符型数据(BitToChar)
Input parameters:		
                        int input[]:需要转换的二进制int数据
						int bits:需要转换的字节位数
Output parameters:	    
                        char output[]:转换后的char数组
                        
Returned value:		
                        NULL
Created by:			
                        崔龙龙 (2017-08-25)
Modified by:		   	
                        NULL
****************************************************************************/	
static void BitToChar(const int intput[],char output[],int bits)
{  
    int i,j;  
    for(j=0;j<bits;j++)  
    {  
        for(i=0;i<8;i++)  
        {  
            output[j]=output[j]*2+intput[i+8*j];  
        }  
    }  
}; 

/****************************************************************************
Description:			数组异或运算(Xor)
Input parameters:		
                        int *INA:异或的源数据1
						int *INB:异或的源数据2
						int len:异或的长度

Output parameters:	    
                        int *INA:异或的结果
                        
Returned value:		
                        NULL
Created by:			
                        崔龙龙 (2017-08-25)
Modified by:		   	
                        NULL
****************************************************************************/	 
static void Xor(int *INA,int *INB,int len)
{  
    int i;  
    for(i=0;i<len;i++)  
    {  
        *(INA+i) = *(INA+i)^*(INB+i);  
    }  
};  

/****************************************************************************
Description:			初始IP置换(IP)
Input parameters:		
                        int input[64]:IP置换输入的64比特数据
						int table[64]:IP置换表

Output parameters:	    
                        int output[64]:IP置换输出64比特数据
                        
Returned value:		
                        NULL
Created by:			
                        崔龙龙 (2017-08-25)
Modified by:		   	
                        NULL
****************************************************************************/
static  void IP(const int input[64],int output[64],int table[64])  
{  
    int i;  
    for(i=0;i<64;i++)  
    {  
        output[i]=input[table[i]-1];//减1操作不可少!!  
    }   
}; 

/****************************************************************************
Description:			E盒扩展(E)
Input parameters:		
                        int input[32]:E置换输入的32比特数据
						int table[48]:E扩展表

Output parameters:	    
                        int output[48]:E置换输出48比特数据
                        
Returned value:		
                        NULL
Created by:			
                        崔龙龙 (2017-08-25)
Modified by:		   	
                        NULL
****************************************************************************/ 
static  void E(const int input[32],int output[48],int table[48])
{  
    int i;  
    for(i=0;i<48;i++)  
    {  
        output[i]=input[table[i]-1];  
    }  
};  

/****************************************************************************
Description:			P盒置换(P)
Input parameters:		
                        int input[32]:P盒输入的32比特数据
						int table[32]:P盒替代表

Output parameters:	    
                        int output[32]:P盒输出32比特数据
                        
Returned value:		
                        NULL
Created by:			
                        崔龙龙 (2017-08-25)
Modified by:		   	
                        NULL
****************************************************************************/ 
static  void P(const int input[32],int output[32],int table[32]) 
{  
    int i;  
    for(i=0;i<32;i++)  
    {  
        output[i]=input[table[i]-1];  
    }  
}; 

/****************************************************************************
Description:			IP逆置换(IP_In)
Input parameters:		
                        int input[64]:IP逆置输入64比特
						int table[64]:IP逆置换表

Output parameters:	    
                        int output[64]:IP逆置换输出64比特
                        
Returned value:		
                        NULL
Created by:			
                        崔龙龙 (2017-08-25)
Modified by:		   	
                        NULL
****************************************************************************/  
static  void IP_In(const int input[64],int output[64],int table[64]) 
{  
    int i;  
    for(i=0;i<64;i++)  
    {  
        output[i]=input[table[i]-1];  
    }   
}; 

/****************************************************************************
Description:			密钥扩展中PC_1置换选择(PC_1)
Input parameters:		
                        int input[64]:PC-1置换选择输入64比特
						int table[56]:PC-1置换选择表

Output parameters:	    
                        int output[56]:PC-1置换选择输出56比特
                        
Returned value:		
                        NULL
Created by:			
                        崔龙龙 (2017-08-25)
Modified by:		   	
                        NULL
****************************************************************************/   
static  void PC_1(const int input[64],int output[56],int table[56])  
{  
    int i;  
    for(i=0;i<56;i++)  
    {  
        output[i]=input[table[i]-1];  
    }   
};  

/****************************************************************************
Description:			密钥扩展中PC_2置换选择(PC_2)
Input parameters:		
                        int input[56]:PC-2置换选择输入56比特
						int table[48]:PC-2置换选择表

Output parameters:	    
                        int output[48]:PC-2置换选择输出48比特
                        
Returned value:		
                        NULL
Created by:			
                        崔龙龙 (2017-08-25)
Modified by:		   	
                        NULL
****************************************************************************/   
static  void PC_2(const int input[56],int output[48],int table[48])
{  
    int i;  
    for(i=0;i<48;i++)  
    {  
        output[i]=input[table[i]-1];  
    }   
}; 

/****************************************************************************
Description:			S盒压缩(S)
Input parameters:		
                        int input[48]:S盒压缩的输入48比特
						int table[8][4][16]:8个S盒,每个S盒4行16列

Output parameters:	    
                        int output[32]:S盒压缩输出32比特
                        
Returned value:		
                        NULL
Created by:			
                        崔龙龙 (2017-08-25)
Modified by:		   	
                        NULL
****************************************************************************/  
static  void S(const int input[48],int output[32],int table[8][4][16])  
{  
    int i=0;  
    int j=0;  
    int INT[8];  
    for(;i<48;i=i+6)  
    {  
        INT[j]=table[j][(input[i]<<1)+(input[i+5])][(input[i+1]<<3)+(input[i+2]<<2)+(input[i+3]<<1)+(input[i+4])];  
        j++;  
    }  
    for(j=0;j<8;j++)  
    {  
        for(i=0;i<4;i++)  
        {  
            output[3*(j+1)-i+j]=(INT[j]>>i)&1;  
        }  
    }  
}; 

/****************************************************************************
Description:			完成DES算法轮变换(F_func)
Input parameters:		
                        int input[32]:F轮函数的输入32比特
						int subkey[48]:F轮变换需要的子密钥

Output parameters:	    
                        int output[32]:F轮变换输出32比特
                        
Returned value:		
                        NULL
Created by:			
                        崔龙龙 (2017-08-25)
Modified by:		   	
                        NULL
****************************************************************************/  
static void F_func( int input[32],int output[32], int subkey[48])
{  
    int len=48;  
    int temp[48]={0};  
    int temp_1[32]={0};  
    E(input,temp,E_Table);  
    Xor(temp,subkey,len);  
    S(temp,temp_1,S_Box);  
    P(temp_1,output,P_Table);  
};  

/****************************************************************************
Description:			完成子密钥扩展的循环左移功能(RotateL)
Input parameters:		
                        int input[28]:循环左移输入28比特
						int leftCount:每轮子密钥需要循环左移的位数

Output parameters:	    
                        int output[28]:循环左移输出28比特
                        
Returned value:		
                        NULL
Created by:			
                        崔龙龙 (2017-08-25)
Modified by:		   	
                        NULL
****************************************************************************/ 
static void RotateL(const int input[28],int output[28], int leftCount)
{  
    int i;  
    int len = 28 ;  
    for(i=0;i<len;i++)  
    {  
        output[i]=input[(i+leftCount)%len];  
    }  
};  

/****************************************************************************
Description:			完成16轮子密钥生成(subKey_fun)
Input parameters:		
                        int input[64]:输入的64比特密钥

Output parameters:	    
                        int Subkey[16][48]:输出的16轮子密钥
                        
Returned value:		
                        NULL
Created by:			
                        崔龙龙 (2017-08-25)
Modified by:		   	
                        NULL
****************************************************************************/ 
static void  subKey_fun(const int input[64],int Subkey[16][48])
{  
    int loop=1,loop_2=2;  
    int i,j;  
    int c[28],d[28];  
    int pc_1[56]={0};  
    int pc_2[16][56]={0};  
    int rotatel_c[16][28]={0};  
    int rotatel_d[16][28]={0};  
    PC_1(input,pc_1,PC1_Table);  
    for(i=0;i<28;i++)  
    {  
        c[i]=pc_1[i];  
        d[i]=pc_1[i+28];  
    }  
    int leftCount = 0 ;  
    for(i=1;i<17;i++)  
    {  
        if(i==1||i==2||i==9||i==16)  
        {  
             leftCount += loop;  
             RotateL(c,rotatel_c[i-1],leftCount);  
             RotateL(d,rotatel_d[i-1],leftCount);  
        }  
        else  
        {  
             leftCount += loop_2;  
             RotateL(c,rotatel_c[i-1],leftCount);  
             RotateL(d,rotatel_d[i-1],leftCount);  
        }  
    }  
    for(i=0;i<16;i++)  
    {  
        for(j=0;j<28;j++)  
        {  
            pc_2[i][j]=rotatel_c[i][j];  
            pc_2[i][j+28]=rotatel_d[i][j];  
        }  
    }  
    for(i=0;i<16;i++)  
    {  
        PC_2(pc_2[i],Subkey[i],PC2_Table);  
    }  
}; 

/****************************************************************************
Description:			完成DES加密运算(DES_Efun)
Input parameters:		
                        int input[8]:输入的需要加密的8个字符
						char key_in[8]:输入的加密密钥8个字符

Output parameters:	    
                        int output[48]:输出密文64比特
                        
Returned value:		
                        NULL
Created by:			
                        崔龙龙 (2017-08-25)
Modified by:		   	
                        NULL
****************************************************************************/  
static void  DES_Efun(char input[8],char key_in[8],int output[64])  
{  
    int Ip[64]={0};//存储初始置换后的矩阵  
    int output_1[64]={0};  
    int subkeys[16][48];  
    int chartobit[64]={0};  
    int key[64];  
    int l[17][32],r[17][32];  
    CharToBit(input,chartobit,8);//正确,转换为64个二进制数的操作正确!  
    IP(chartobit,Ip,IP_Table);//正确,IP初始置换!  
    CharToBit(key_in,key,8);//正确!  
    subKey_fun(key,subkeys);//正确!  
    for(int i=0;i<32;i++)  
    {  
        l[0][i]=Ip[i];  
        r[0][i]=Ip[32+i];  
    }  
    for(int j=1;j<16;j++)//前15轮的操作  
    {  
        for(int k=0;k<32;k++)  
        {  
            l[j][k]=r[j-1][k];  
        }  
            F_func(r[j-1],r[j],subkeys[j-1]);  
            Xor(r[j],l[j-1],32);  
    }  
    int t=0;  
    for(t=0;t<32;t++)//最后一轮的操作  
    {  
        r[16][t]=r[15][t];  
    }  
        F_func(r[15],l[16],subkeys[15]);  
        Xor(l[16],l[15],32);  
        for(t=0;t<32;t++)  
    {  
        output_1[t]=l[16][t];  
        output_1[32+t]=r[16][t];  
    }  
        IP_In(output_1,output,IPR_Table);  
};  

/****************************************************************************
Description:			DES解密(DES_Dfun)
Input parameters:		
                        int input[64]:输入需要解密64比特
						char key_in[8]:输入的解密密钥8个字符

Output parameters:	    
                        int output[8]:输出解密之后明文的8个字符
                        
Returned value:		
                        NULL
Created by:			
                        崔龙龙 (2017-08-25)
Modified by:		   	
                        NULL
****************************************************************************/ 
static void  DES_Dfun(int input[64],char key_in[8],char output[8])  
{  
    int Ip[64]={0};//存储初始置换后的矩阵  
    int output_1[64]={0};  
    int output_2[64]={0};  
    int subkeys[16][48];  
    int chartobit[64]={0};  
    int key[64];  
    int l[17][32],r[17][32];  
    IP(input,Ip,IP_Table);//正确,IP初始置换!  
    CharToBit(key_in,key,8);//正确!  
    subKey_fun(key,subkeys);//正确!  
    for(int i=0;i<32;i++)  
    {  
        l[0][i]=Ip[i];  
        r[0][i]=Ip[32+i];  
    }  
    for(int j=1;j<16;j++)//前15轮的操作  
    {  
        for(int k=0;k<32;k++)  
        {  
            l[j][k]=r[j-1][k];  
        }  
            F_func(r[j-1],r[j],subkeys[16-j]);  
            Xor(r[j],l[j-1],32);  
    }  
    int t=0;  
    for(t=0;t<32;t++)//最后一轮的操作  
    {  
        r[16][t]=r[15][t];  
    }  
        F_func(r[15],l[16],subkeys[0]);  
        Xor(l[16],l[15],32);  
        for(t=0;t<32;t++)  
    {  
        output_1[t]=l[16][t];  
        output_1[32+t]=r[16][t];  
    }  
        IP_In(output_1,output_2,IPR_Table);  
        BitToChar(output_2,output,8);  
};  

/****************************************************************************
Description:			主函数,测试des(main)
Input parameters:		
                        NULL

Output parameters:	    
                        NULL
                        
Returned value:		
                        0
Created by:			
                        崔龙龙 (2017-08-25)
Modified by:		   	
                        NULL

Test data:				plain:12345678(作者测试数据,注意这里为字符,转换16进制应该是3132333435363738)
						key:  12345678
						out:  96D0028878D58C89(16进制数据)

****************************************************************************/ 
int main()  
{  
	int i = 0;
    int output[64]={0};  
    char MIN[9]={0};  
    char MI[9]={0};  
	unsigned char out[9]={0};

    printf("请输入8位字符明文\n");  
    gets(MIN);  
    printf("请输入8位字符秘钥\n");  
    gets(MI); 
	
    DES_Efun(MIN,MI,output);  //加密
    printf("密文二进制如下:\n");  
    for(i=0;i<64;i++)  
    {  
        printf("%d",output[i]);  
        if((i+1)%4==0)  
            printf(" ");  
    } 
	BitToChar(output,(char *)out,8);
	printf("密文如下:\n");  
	for(i=0;i<8;i++) 
	{
		printf("0x%02x ",out[i]);
	}

    printf("\n");  
    printf("\n解密功能\n");  
    DES_Dfun(output,MI,MIN);  
    printf("明文如下:\n");  
    for(i=0;i<8;i++)  
    {  
        printf("%c",MIN[i]);  
    }  
    printf("\n");  
    return 0;  
}

各位有需要源码的也可以去github上去下载,期望给个star,谢谢

地址:https://github.com/cuilonglong/PC_VC6.0_DataPro_DES_ForC


纯手打,有帮助就回复下,有什么问题也可留言,我们共同讨论下。

转载请注明出处!谢谢!

  • 8
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值