加解密相关

目录

 1.hash算法(摘要认证)

1.1MD5

1.1.1填充对齐

1.1.2分块分组

1.1.3对分组进行计算(每块进行多轮压缩)

1.1.4解释问题

1.2 SHA-2安全散列算法

2.对称加密:DES、AES、RC4

2.1DES

2.2 AES

...

2.3 对称流加密算法RC4

3.非对称

3.1RSA:非对称

 1.hash算法(摘要认证)

1.1MD5

MD5 具有很高的安全性,可以产生出一个128位(16字节)的散列值(hash value),它对应任何字符串都可以加密成一段唯一的固定长度的代码,用于确保信息传输完整一致。

目前MD5加密算法是不可逆的,当然这种方式加密的密文也不需要解密,需要的时候直接发送原始密文就好。

实现步骤:

1.1.1填充对齐

对源数据进行填充,使其变成一个(N*512-64)位大小的数据
填充方法:在消息后面进行填充,填充第一位为1,其余为0。

再加上64位表示原数据的长度,填充后就是512整数倍。

1.1.2分块分组

按每个512位为一组进行分组,每组里面分成16个32位,也就是16个int。

  • 四个常量
A=0x01234567 
B=0x89abcdef 
C=0xfedcba98 
D=0x76543210 
  • 四个基础线性函数
F(X,Y,Z) = (X & Y) | ((~X) & Z);
G(X,Y,Z) = (X & Z) | (Y & (~Z)); 
H(X,Y,Z) = X ^ Y ^ Z; 
I(X,Y,Z) = Y ^ (X | (~Z));

(&是与,|是或,~是非,^是异或) 
  • 四个数据处理函数
    Mj表示第M组第j个int数
FF(a,b,c,d,Mj,s,ti)表示a=b+((a+F(b,c,d)+Mj+ti)<<<s)
GG(a,b,c,d,Mj,s,ti)表示a=b+((a+G(b,c,d)+Mj+ti)<<<s)
HH(a,b,c,d,Mj,s,ti)表示a=b+((a+H(b,c,d)+Mj+ti)<<<s)
II(a,b,c,d,Mj,s,ti)表示a=b+((a+I(b,c,d)+Mj+ti)<<<s)

1.1.3对分组进行计算(每块进行多轮压缩)

第一轮
a=FF(a,b,c,d,M0,7,0xd76aa478)
b=FF(d,a,b,c,M1,12,0xe8c7b756)
c=FF(c,d,a,b,M2,17,0x242070db)
d=FF(b,c,d,a,M3,22,0xc1bdceee)
a=FF(a,b,c,d,M4,7,0xf57c0faf)
b=FF(d,a,b,c,M5,12,0x4787c62a)
c=FF(c,d,a,b,M6,17,0xa8304613)
d=FF(b,c,d,a,M7,22,0xfd469501)
a=FF(a,b,c,d,M8,7,0x698098d8)
b=FF(d,a,b,c,M9,12,0x8b44f7af)
c=FF(c,d,a,b,M10,17,0xffff5bb1)
d=FF(b,c,d,a,M11,22,0x895cd7be)
a=FF(a,b,c,d,M12,7,0x6b901122)
b=FF(d,a,b,c,M13,12,0xfd987193)
c=FF(c,d,a,b,M14,17,0xa679438e)
d=FF(b,c,d,a,M15,22,0x49b40821)

第二轮
a=GG(a,b,c,d,M1,5,0xf61e2562)
b=GG(d,a,b,c,M6,9,0xc040b340)
c=GG(c,d,a,b,M11,14,0x265e5a51)
d=GG(b,c,d,a,M0,20,0xe9b6c7aa)
a=GG(a,b,c,d,M5,5,0xd62f105d)
b=GG(d,a,b,c,M10,9,0x02441453)
c=GG(c,d,a,b,M15,14,0xd8a1e681)
d=GG(b,c,d,a,M4,20,0xe7d3fbc8)
a=GG(a,b,c,d,M9,5,0x21e1cde6)
b=GG(d,a,b,c,M14,9,0xc33707d6)
c=GG(c,d,a,b,M3,14,0xf4d50d87)
d=GG(b,c,d,a,M8,20,0x455a14ed)
a=GG(a,b,c,d,M13,5,0xa9e3e905)
b=GG(d,a,b,c,M2,9,0xfcefa3f8)
c=GG(c,d,a,b,M7,14,0x676f02d9)
d=GG(b,c,d,a,M12,20,0x8d2a4c8a)

第三轮
a=HH(a,b,c,d,M5,4,0xfffa3942)
b=HH(d,a,b,c,M8,11,0x8771f681)
c=HH(c,d,a,b,M11,16,0x6d9d6122)
d=HH(b,c,d,a,M14,23,0xfde5380c)
a=HH(a,b,c,d,M1,4,0xa4beea44)
b=HH(d,a,b,c,M4,11,0x4bdecfa9)
c=HH(c,d,a,b,M7,16,0xf6bb4b60)
d=HH(b,c,d,a,M10,23,0xbebfbc70)
a=HH(a,b,c,d,M13,4,0x289b7ec6)
b=HH(d,a,b,c,M0,11,0xeaa127fa)
c=HH(c,d,a,b,M3,16,0xd4ef3085)
d=HH(b,c,d,a,M6,23,0x04881d05)
a=HH(a,b,c,d,M9,4,0xd9d4d039)
b=HH(d,a,b,c,M12,11,0xe6db99e5)
c=HH(c,d,a,b,M15,16,0x1fa27cf8)
d=HH(b,c,d,a,M2,23,0xc4ac5665)

第四轮
a=II(a,b,c,d,M0,6,0xf4292244)
b=II(d,a,b,c,M7,10,0x432aff97)
c=II(c,d,a,b,M14,15,0xab9423a7)
d=II(b,c,d,a,M5,21,0xfc93a039)
a=II(a,b,c,d,M12,6,0x655b59c3)
b=II(d,a,b,c,M3,10,0x8f0ccc92)
c=II(c,d,a,b,M10,15,0xffeff47d)
d=II(b,c,d,a,M1,21,0x85845dd1)
a=II(a,b,c,d,M8,6,0x6fa87e4f)
b=II(d,a,b,c,M15,10,0xfe2ce6e0)
c=II(c,d,a,b,M6,15,0xa3014314)
d=II(b,c,d,a,M13,21,0x4e0811a1)
a=II(a,b,c,d,M4,6,0xf7537e82)
b=II(d,a,b,c,M11,10,0xbd3af235)
c=II(c,d,a,b,M2,15,0x2ad7d2bb)
d=II(b,c,d,a,M9,21,0xeb86d391)

每轮循环后,将A,B,C,D分别加上a,b,c,d,然后进入下一循环

1.1.4解释问题

  • MD5为什么能把一个不管多长的文件都变成定长的
MD5使用4个32位的数据,和数据中的每个32位的数据进行计算,最终输出这4个32位数

1.2 SHA-2安全散列算法

步骤:

①常量的初始化

SHA256算法中用到了8个哈希初值以及64个哈希常量

其中,SHA256算法的8个哈希初值如下:

h0 := 0x6a09e667
h1 := 0xbb67ae85
h2 := 0x3c6ef372
h3 := 0xa54ff53a
h4 := 0x510e527f
h5 := 0x9b05688c
h6 := 0x1f83d9ab
h7 := 0x5be0cd19

这些初值是对自然数中前8个质数(2,3,5,7,11,13,17,19)的平方根的小数部分取前32bit而来。

举个例子来说,$ \sqrt{2} $小数部分约为0.414213562373095048,而
0.414213562373095048 ≈ 6 ∗ 1 6 − 1 + a ∗ 1 6 − 2 + 0 ∗ 1 6 − 3 + . . . 0.414213562373095048 0.414213562373095048≈6*16^{-1} + a*16^{-2} + 0*16^{-3} + ...

于是,质数2的平方根的小数部分取前32bit就对应出了0x6a09e667
 

在SHA256算法中,用到的64个常量如下:

428a2f98 71374491 b5c0fbcf e9b5dba5
3956c25b 59f111f1 923f82a4 ab1c5ed5
d807aa98 12835b01 243185be 550c7dc3
72be5d74 80deb1fe 9bdc06a7 c19bf174
e49b69c1 efbe4786 0fc19dc6 240ca1cc
2de92c6f 4a7484aa 5cb0a9dc 76f988da
983e5152 a831c66d b00327c8 bf597fc7
c6e00bf3 d5a79147 06ca6351 14292967
27b70a85 2e1b2138 4d2c6dfc 53380d13
650a7354 766a0abb 81c2c92e 92722c85
a2bfe8a1 a81a664b c24b8b70 c76c51a3
d192e819 d6990624 f40e3585 106aa070
19a4c116 1e376c08 2748774c 34b0bcb5
391c0cb3 4ed8aa4a 5b9cca4f 682e6ff3
748f82ee 78a5636f 84c87814 8cc70208
90befffa a4506ceb bef9a3f7 c67178f2

和8个哈希初值类似,这些常量是对自然数中前64个质数(2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97…)的立方根的小数部分取前32bit而来。

②信息预处理

SHA256算法中的预处理就是在想要Hash的消息后面补充需要的信息,使整个消息满足指定的结构。

信息的预处理分为两个步骤:附加填充比特附加长度。

STEP1:附加填充比特

在报文末尾进行填充,使报文长度在对512取模以后的余数是448

填充是这样进行的:先补第一个比特为1,然后都补0,直到长度满足对512取模后余数是448。

需要注意的是,信息必须进行填充,也就是说,即使长度已经满足对512取模后余数是448,补位也必须要进行,这时要填充512个比特。

因此,填充是至少补一位,最多补512位。

例:以信息“abc”为例显示补位的过程。

a,b,c对应的ASCII码分别是97,98,99

于是原始信息的二进制编码为:01100001 01100010 01100011

补位第一步,首先补一个“1” : 0110000101100010 01100011 1

补位第二步,补423个“0”:01100001 01100010 01100011 10000000 00000000 … 00000000

补位完成后的数据如下(为了简介用16进制表示):

61626380 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000

为什么是448?

因为在第一步的预处理后,第二步会再附加上一个64bit的数据,用来表示原始报文的长度信息。而448+64=512,正好拼成了一个完整的结构。

STEP2:附加长度值

就是补充64bit原始数据:

SHA256用一个64位的数据来表示原始消息的长度。

③逻辑运算

SHA256散列函数中涉及的操作全部是逻辑的位运算

包括如下的逻辑函数:

包括如下的逻辑函数:

 ③计算消息摘要

主体计算:

step1 将消息分解成512-bit大小的块

图::消息分为n个块1

假设消息M可以被分解为n个块,于是整个算法需要做的就是完成n次迭代,n次迭代的结果就是最终的哈希值,即256bit的数字摘要。

一个256-bit的摘要的初始值H0,经过第一个数据块进行运算,得到H1,即完成了第一次迭代

H1经过第二个数据块得到H2,……,依次处理,最后得到Hn,Hn即为最终的256-bit消息摘要

将每次迭代进行的映射用$ Map(H_{i-1}) = H_{i} $表示,于是迭代可以更形象的展示为:

图::迭代过程2

图中256-bit的Hi被描述8个小块,这是因为SHA256算法中的最小运算单元称为“字”(Word),一个字是32位。

此外,第一次迭代中,映射的初值设置为前面介绍的8个哈希初值,如下图所示:

 图::哈希初值3

 下面开始介绍每一次迭代的内容,即映射$ Map(H_{i-1}) = H_{i} $的具体算法。

STEP1:构造64个字(word)

对于每一块,将块分解为16个32-bit的big-endian的字,记为w[0], …, w[15]

也就是说,前16个字直接由消息的第i个块分解得到

其余的字由如下迭代公式得到:

STEP2:进行64次循环

映射 $ Map(H_{i-1}) = H_{i} $ 包含了64次加密循环

即进行64次加密循环即可完成一次迭代

每次加密循环可以由下图描述:

图::加密循环4

SHA-256伪代码:

//前 8 个素数(2, 3, 5, 7, 11, 13, 17, 19),依次通过 floor(sqrt_小数部分(x) * 2^32) 运算
//比如:h0 = floor(sqrt_小数部分(2) * 2^32) = floor(0.414213562373095 * 2^32) 
//        = floor(1779033703.952099) = 1779033703 = 0x6a09e667
h0 := 0x6a09e667
h1 := 0xbb67ae85
h2 := 0x3c6ef372
h3 := 0xa54ff53a
h4 := 0x510e527f
h5 := 0x9b05688c
h6 := 0x1f83d9ab
h7 := 0x5be0cd19

//前 64 个素数,依次通过 floor(cbrt_小数部分(x) * 2^32) 运算
//比如:k[0] = floor(cbrt_小数部分(2) * 2^32) = floor(0.259921049894873 * 2^32) 
//          = floor(1116352408.840464) = 1116352408 = 0x428a2f98
k[0..63] :=
   0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
   0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
   0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
   0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
   0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
   0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
   0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
   0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2


// 跟 SHA-1 一样的处理
append "1" bit to message
append "0" bits until message length in bits ≡ 448 (mod 512)
append original length in bits as 64-bit big-endian integer to message

for each 512-bit chunk of message
    break chunk into sixteen 32-bit big-endian words w[i], 0 ≤ i ≤ 15
    
    for i from 16 to 63
        s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor(w[i-15] rightshift 3)
        s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor(w[i-2] rightshift 10)
        w[i] := w[i-16] + s0 + w[i-7] + s1

    a := h0
    b := h1
    c := h2
    d := h3
    e := h4
    f := h5
    g := h6
    h := h7
    
    for i from 0 to 63
        s0 := (a rightrotate 2) xor (a rightrotate 13) xor(a rightrotate 22)
        maj := (a and b) xor (a and c) xor(b and c)
        t2 := s0 + maj
        s1 := (e rightrotate 6) xor (e rightrotate 11) xor(e rightrotate 25)
        ch := (e and f) xor ((not e) and g)
        t1 := h + s1 + ch + k[i] + w[i]
        
        h := g
        g := f
        f := e
        e := d + t1
        d := c
        c := b
        b := a
        a := t1 + t2
        
    h0 := h0 + a
    h1 := h1 + b
    h2 := h2 + c
    h3 := h3 + d
    h4 := h4 + e
    h5 := h5 + f
    h6 := h6 + g
    h7 := h7 + h
    
digest = hash = h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7

签名原理:非对称中将私钥加密后的数据+公钥公开,验证方通过公钥和加密数据解密和原保存的记录做对比(原始签名数据),相同则为签名正确。

补位、补长度、使用的常量、计算消息摘要,加密不解密

  1. SHA加密算法用途

   数字签名、数字时间戳、数字证书

2.对称加密:DES、AES、RC4

2.1DES

加密过程

①将明文分为64位的分组,首先对64位码做初始IP置换,再进行16论迭代变换,其中包括ESP三种运算,最后进行逆初始置换。

加密步骤:

①IP置换:

 右上角是置换表,也就是座位表,例如:置换表第一个位置为58,也就是说原始数据第58位的二进制数据放在第一个位置,成为置换后数据。

②E扩展置换 

每一组64位数据,上下分成两组,一个叫左32位数据,一个叫右32位数据,但是密钥是48位,要和右32位数据进行异或运算,所以右32位数据显得不足,这时候就要扩充,详细扩充步骤如下:

 把32位数据-》48位:图左上角为32位数据,每一组4位,共8组。例如:第一组数据 1101,要扩充两位,分别在最前和最后各扩充一位, _1101_,前面那个,找该4位数据的前一个4位数的最后一个,没有就找第8组最后一位,所以11101_,四位中最后一位,找下一组第一个,所以111010。

密钥本来64位=密钥(58位)+(8位)校验位。58要通过一定手段-》48位。然后扩充明文和48位密钥异或操作为密文,然后将密文压缩为32位。

③密文压缩(46-》32)

 一组原始密文头和尾组成十进制,为压缩表的行。中间四位转成十进制,即为压缩表的列。下图为压缩表:

.第一轮为s1,第二轮为s2。。。。 s1中,(3,15)所以为13,13-》(二进制)1101。

④将压缩后的密文用P盒置换表换座位

 到这里第一轮就结束了。

然后这里为第一个f,如上图,然后再异或。就这样经过16轮,最后生成为密文。

、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

(对称)涉及到了15个表,前三个用来计算子密钥,然后接着两个初始化表计算初始数据的置换,完成之后有一个F和(8个表)、P和最后一次置换表,把初始密钥经过计算转换,然后经过循环,然后经过置换,得到16位子密钥,初始数据块通过初始置换和扩展置换得到数据块,然后通过s和,一共八块的置换,得到结果,再通过p和置换,最后得到左右右左32个,一共64个,得到最终置换,最终得到最终数据;算法为密码体制中的对称密码体制,主要用于明文的加密或密文的解密,是一种效率较高的加密算法; CBC模式通过对分组密码增加简单的操作和反馈,避免ECB出现的密文和明文一一对应的问题,也就是后面的加密解密与前面有依赖关系,在CBC模式中用之前的密文分组进行反馈,这样就不会出现一对一的问题,在加密时,用前一个输出的密文分组与当前明文进行异或,然后再加密,当解密时将前一个输出的明文分组与密文分组求异或,再解密可以简单表示(计算子密钥、初始化数据块、对数据块进行加密)效率好,速度快(结果64位)


#include <iostream>
#include <string>
#include <algorithm>
#include <bitset>
using namespace std;


string desKeys[20];
/**
 *数据初始置换表
 */
int T1[8][8] = { 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 T2[8][7] = { 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,
              3,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 T3[16] = { 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1 };

/**
 *密钥压缩置换表
 */
int T4[8][6] = { 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 T5[8][6] = { 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 S[8][4][16] = { {{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}},
                {{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}},
                {{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}},
                {{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}},
                {{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}},
                {{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}},
                {{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}},
                {{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 P[4][8] = { 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 T6[8][8] = { 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 };

/**

 *最终置换函数 64位->64位

 *函数说明:s为完成最后一轮循环得到的64为数据

 *返回值为密文或明文

 */
string final_permutation(string s)
{
    string rs = "";
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            rs += s[T6[i][j] - 1];
        }
    }
    return rs;
}

/**

 *P盒置换函数 32位->32位

 *函数说明:s为S盒的输出

 */
string P_box(string s)
{
    string rs = "";
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            rs += (s[P[i][j] - 1]);
        }
    }
    return rs;
}

/**

 *S盒置换函数 48位->32位

 *函数说明:s为48位数据

 *返回值为32位

 */
string S_box(string s)
{
    string rs = "";
    string s1;
    int k1, k2;//S盒的行号和列号
    int h = 1;//决定使用那个S盒
    for (int i = 0; i <= 42; i = i + 6, h++)
    {
        k1 = (s[i] - '0') * 2 + (s[i + 5] - '0') * 1;
        k2 = (s[i + 1] - '0') * 8 + (s[i + 2] - '0') * 4 + (s[i + 3] - '0') * 2 + (s[i + 4] - '0') * 1;
        int x = S[h - 1][k1][k2];
        s1 = "";
        int y = 8;
        for (int j = 1; j <= 4; j++)
        {
            if (x < y)
            {
                s1 += "0";
                y /= 2;
            }
            else
            {
                s1 += "1";
                x = x % y;
                y /= 2;
            }
        }
        rs += s1;
    }
    return rs;
}

/**

 *异或运算函数

 *要求位数相同

 */
string desXOR(string s1, string s2)
{
    string rs = "";
    for (int i = 0; i < s1.length() && i < s2.length(); i++)
    {
        rs += ((s1[i] - '0') ^ (s2[i] - '0')) + '0';
    }
    return rs;
}

/**

 *数据扩展函数 32->48

 *函数说明:s为数据的右半部分 32位

 *扩展成48位的输出

 */
string plaintext_righthalf_extended_permutation(string s)
{
    string rs = "";
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 6; j++)
        {
            rs += s[T5[i][j] - 1];
        }
    }
    return rs;
}

/**

 *密钥压缩置换函数 56位->48位

 *函数说明:s为56为的密钥

 *输出为48位的子密钥

 */
string secret_key_compression_replacement(string s)
{
    string rs = "";
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 6; j++)
        {
            rs += s[T4[i][j] - 1];
        }
    }
    return rs;
}

/**

 *密钥循环左移函数 56位->56位

 *函数说明:k为左移位数 s为密钥

 *返回值位数不变

 */
string secret_ket_left_move(int k, string s)//密钥循环左移k位
{
    string s1 = s.substr(0, 28);
    string s2 = s.substr(28, 28);
    string rs = s1.substr(k, 28 - k) + s1.substr(0, k) + s2.substr(k, 28 - k) + s2.substr(0, k);
    return rs;
}

/**

 *密钥初始置换函数 64位->56位

 *函数说明:s为64位的初始密钥

 *返回值为56位

 */
string secret_key_initial_permutation(string s)
{

    string rs = "";
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 7; j++)
        {
            rs += s[T2[i][j] - 1];
        }
    }

    return rs;
}

/**

 *明文初始置换函数 64位->64位

 *函数说明:s为初始明文 64位

 *返回值为6位

 */
string plaintext_initial_permutation(string s)//明文初始置换
{
    string rs = "";
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            rs += s[T1[i][j] - 1];
        }
    }
    return rs;
}

/**

 *16进制转2进制函数

 *函数说明:s为16进制字符串

 *返回为2进制字符串

 */
string des_H(string s)
{
    string s1;
    string rs = "";
    for (int i = 0; i < s.length(); i++)
    {
        int x;
        if (s[i] >= '0' && s[i] <= '9')
        {
            x = s[i] - '0';
        }
        else
        {
            x = s[i] - 'A' + 10;
        }
        s1 = "";
        int y = 8;
        for (int j = 1; j <= 4; j++)
        {
            if (x < y)
            {
                y /= 2;
                s1 += "0";
            }
            else
            {
                s1 += "1";
                x = x % y;
                y = y / 2;
            }
        }
        rs += s1;
    }
    return rs;
}

/**

*2进制转16进制函数

*str为2进制字符串

*返回值为16进制字符串

*/
string des_G(string str)
{
    string rs = "";
    char temp;
    for (int i = 0; i <= str.length() - 4; i = i + 4)
    {
        int x = (str[i] - '0') * 8 + (str[i + 1] - '0') * 4 + (str[i + 2] - '0') * 2 + str[i + 3] - '0';

        if (x >= 10)
        {
            temp = (char)(x - 10 + 'A');
        }
        else
        {
            temp = (char)(x + '0');
        }
        rs += temp;
    }
    return rs;
}

/**

 *封装函数f

 *函数说明:接收32位数据和48位的子密钥 产生一个32位的输出

 *str1:32位数据  str2:48位的子密钥

 *返回值32位

 */

string des_f(string str1, string str2)
{
    string expendR = plaintext_righthalf_extended_permutation(str1);
    //cout<<"32位数据扩展为48位结果:"<<expendR<<endl;

    string rs = desXOR(expendR, str2);
    //cout<<"密钥和扩展数据异或结果:"<<rs<<endl;

    rs = S_box(rs);
    //cout<<"S盒替代结果(48->32):"<<rs<<endl;

    rs = P_box(rs);
    //cout<<"P盒替代结果(32->32):"<<rs<<endl;

    return rs;
}

/**

 *子密钥生成函数

 *函数说明:s为给定的密钥

 *生成16个子密钥

 */


void des_generateKeys(string s)
{
    
    s = secret_key_initial_permutation(s);

    for (int i = 1; i <= 16; i++)
    {
        s = secret_ket_left_move(T3[i - 1], s);
        desKeys[i] = secret_key_compression_replacement(s);
    }
}
/*
* 明文字符串转换成0/1字符串
*/
string des_StrToBitStr(string str)
{
    bitset<64> bstr;
    for (int i = 0; i < 8; i++)
    {
        bitset<8> bits = bitset<8>(str[i]);
        for (int j = 0; j < 8; j++)
        {
            bstr[i * 8 + j] = bits[7 - j];
        }
    }
    string s = bstr.to_string();
    //添加一个翻转操作
    reverse(begin(s), end(s));
    return s;
}
/*
* 0/1字符串装换为字符形式的字符串
*/
string des_BitStrToStr(string bstr)
{
    string str = "";
    //每八位转化成十进制,然后将数字结果转化成字符
    int sum;
    for (int i = 0; i < bstr.size(); i += 8)
    {
        sum = 0;
        for (int j = 0; j < 8; j++)
            if (bstr[i + j] == '1')
                sum = sum * 2 + 1;
            else
                sum = sum * 2;
        str = str + char(sum);
    }
    return str;

}

string chardeel(string& str1, string& str2) {
    string temp_str = "";
    int divi_times = (str1.size() % 8 ? str1.size() / 8 + 1 : str1.size() / 8);		//计算分组个数 
    for (int i = 0; i < divi_times; ++i) {										//每个分组单独转换成二进制串 
        string str1_temp = str1.substr(8 * i, 8);  //substr(start,len) 

        bool jude = false;
        int addchar = 0;
        if (str1_temp.size() % 8) {
            jude = true;
            addchar = 8 - str1_temp.size() % 8;
        }
        int sub = str1_temp.size() * 8;
        if (jude) {
            for (int i = 0; i < addchar; ++i) {
                str1_temp += 'a';
            }
        }
        str1_temp = des_StrToBitStr(str1_temp);
        if (jude) {
            for (int i = 0; i < addchar * 8; ++i) {
                str1_temp[sub+i] = '0';
            }
        }
        temp_str = temp_str + str1_temp;

    }
    str2 = des_H(str2);
    return temp_str;
}

/**

 *DES加密函数 64位->64位

 *函数说明:str1为64位的给定明文

 *返回值为64位的密文

 */

string des_encrypt(string str1, string str2)
{
    str1 = chardeel(str1, str2);  //明文分组和填充,返回01字符串 

    des_generateKeys(str2);  //生成16个子密钥


    int divi_times = str1.size() / 64;  //分成多少组去进行des
    string rs_temp = "";

    for (int i = 0; i < divi_times; ++i) {
        string str1_temp = str1.substr(i * 64, 64);
 
        //第一步:明文初始置换 64->64
        str1_temp = plaintext_initial_permutation(str1_temp);

        //第二步:数据分组
        string left = str1_temp.substr(0, 32);
        string right = str1_temp.substr(32, 32);
        string newleft;

        //第三步:16轮迭代
        for (int i = 1; i <= 16; i++)
        {
            newleft = right;
            right = desXOR(left, des_f(right, desKeys[i]));
            left = newleft;
        }

        //第四步:合并数据 注意位R16L16
        string rs = right + left;

        //结尾置换
        rs = final_permutation(rs);
        rs_temp = rs_temp + rs;
    }

    return rs_temp;

}
/**

*解密函数

*str为密文

*输出明文

*/
string des_decrypt(string str)
{
    int divi_times = str.size() / 64;  //分成多少组去进行des
    string rs_temp = "";

    for (int i = 0; i < divi_times; ++i) {
        string str_temp = str.substr(i * 64, 64);
        //把密文当作明文进行初始明文置换
        str_temp = plaintext_initial_permutation(str_temp);

        //左右分组
        string left = str_temp.substr(0, 32);
        string right = str_temp.substr(32, 32);

        string newleft;

        //逆序的子密钥使用 16轮迭代
        for (int i = 16; i >= 1; i--)
        {
            newleft = right;
            right = desXOR(left, des_f(right, desKeys[i]));
            left = newleft;
        }

        //合并
        string rs = right + left;

        //最后置换
        rs = final_permutation(rs);
        rs_temp = rs_temp + rs;
    }
    rs_temp = des_BitStrToStr(rs_temp);
    return rs_temp;
}


int main()
{
    /*string str1 = "abc";
    cout << str1.max_size();*/
    
    string str1 = "";
    cout << "请输入明文:";
    getline(cin, str1);

    string str2 = "";
    cout << "请输入密钥(16位):";
    getline(cin, str2);

    //加密
    string rs = des_encrypt(str1, str2);
    cout << "密文(二进制):" << rs << endl;

    //解密
    rs = des_decrypt(rs);
    cout << "明文(16进制):" << rs << endl;
    
    return 0;
}

DES加密算法用途

    DES是一种数据加密标准,主要用于明文的加密或密文的解密,是一种效率较高的加密

2.2 AES

...

2.3 对称流加密算法RC4

RC4不是对明文进行分组处理,而是字节流的方式依次加密明文中的每一个字节,解密的时候也是依次对密文中的每一个字节进行解密。可以给任意位加密。

  1、密钥流:RC4算法的关键是根据明文和密钥生成相应的密钥流,密钥流的长度和明文的长度是对应的,也就是说明文的长度是500字节,那么密钥流也是500字节。当然,加密生成的密文也是500字节,因为密文第i字节=明文第i字节^密钥流第i字节;

       2、状态向量S:长度为256,S[0],S[1].....S[255]。每个单元都是一个字节,算法运行的任何时候,S都包括0-255的8比特数的排列组合,只不过值的位置发生了变换;

       3、临时向量T:长度也为256,每个单元也是一个字节。如果密钥的长度是256字节,就直接把密钥的值赋给T,否则,轮转地将密钥的每个字节赋给T;

       4、密钥K:长度为1-256字节,注意密钥的长度keylen与明文长度、密钥流的长度没有必然关系,通常密钥的长度趣味16字节(128比特)。

  

是一些广泛使用的协议和标准的一部分,常用于无线通信网络加密的WEP和WPA,以及TLS(Transport Layer Security),还被集成于Microsoft Windows、Lotus notes、Apple AOCE等应用中算法简单、速度快,不管是软件还是硬件,实现起来都十分容易,因而应用广泛。

3.非对称

3.1RSA:非对称

运用模运算方式对公钥加密,防止反推。

​ RSA推算加密解密步骤:

安全性估计:

要通过公钥E-》私钥D,那么就要推出T,要推出T就要推出p和q,N是已知的,就要质因数分解出p和q,难点就是这个分解p和q,小数当然容易,但是RSA算法是1024位2进制数据,人类还做不到那么大量级的分解(可以用量子计算机算),所以目前比较安全。  

RSA加密算法用途:

     网络传输、银行系统、军事情报,数字签名等

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值