
第四版《加密与解密》
加解密
- 安全领域的重要分支和基础设施
传输互联网重要数据需要加解密- TCP/IP协议本身是明确的,不安全
- 例如,用户名和密码
- 比如收发的电子邮件。
- QQ聊天内容(对公安机关开放解密接口,可以看到聊天记录),曾经恐怖分子列出了一份
安全IM工具列表 - 加密方案包括:https/tls/ssl等
- http是明文(所以可能是明文)
钓鱼网站),https它是加密的,即使被嗅探,解密也可能需要10个时间W年级,几乎不可能。
- http是明文(所以可能是明文)
存储重要数据也需要加密:- NTFS的EFS(合法用户只有登录系统才能看到硬盘的内容。如果硬盘被拆下并安装在其他计算机上,则加密的密文将被看到。破解需要10个时间W年的级别,
对称加密和非对称加密组合是目前最安全的加密方法) - WINRAR文件加密等
- res加密算法,美国推荐的标准加密算法
- 随机密钥包括数字、字母、符号
- 备份自己的密码(显示几个密码作为提示),避免忘记,解决不了。
- NTFS的EFS(合法用户只有登录系统才能看到硬盘的内容。如果硬盘被拆下并安装在其他计算机上,则加密的密文将被看到。破解需要10个时间W年的级别,
还需要数字签名来防止文件被篡改- dll文件等
- 保存公安犯罪记录,防止篡改
1.加解密算法的分类
1. 对称加密
- 单钥密码系统的加密方法,同一钥匙可同时用作信息的加密和解密,称为
对称加密,也称为单密钥加密。- 密钥是控制加密和解密过程的指令。在对称加密中,数据发送人使用加密密钥和特殊加密算法对明文(原始数据)进行加密,并将其发送到复杂的加密文本中。接收人收到密文后,如果想解释原文,需要使用加密密钥和相同的算法
逆算法解密,使其恢复为可读明文。 - 在对称加密算法中,只使用一个密钥,双方都使用该密钥加密和解密数据。
- 优点:算法开放,计算量小,加密速度快,加密效率高
- 缺点:密钥管理
- 密钥是控制加密和解密过程的指令。在对称加密中,数据发送人使用加密密钥和特殊加密算法对明文(原始数据)进行加密,并将其发送到复杂的加密文本中。接收人收到密文后,如果想解释原文,需要使用加密密钥和相同的算法
2. 非对称加密
- 非对称加密算法需要两个密钥来加密和解密,这两个密钥是公共密钥( public key,简称
公钥)和私有密钥(private key,简称私钥) - 如果用公钥加密数据,只能解密相应的私钥。如果用私钥加密数据,只能解密相应的公钥。由于加密和解密使用两个不同的密钥,该算法被称为
非对称加密算法。 - eg: A,B非对称加密通信:
- 1)A生成一对密钥(公钥和私钥)并向其他方公开,私钥单独严格保密。
- 2)获得公钥的B使用密钥加密机密信息,然后发送给A方。
- 3)A然后用自己保存的另一把专用密钥(私钥)解密加密信息。A方只能用其专用密钥(私钥)解密相应公钥加密的信息。
- 在传输过程中,即使攻击者截获了传输密文并获得了A的公钥,也无法破解密文,因为只有A的私钥才能解密文。
- 同样,如果A回复加密信息B,然后B先公布B公钥加密,B保存B的私钥用于解密。
- 优点:密钥管理更安全(不需要像对称加密那样告诉很多人密钥,只需要告诉别人公钥)
- 缺点:加密和解密时间长,速度慢,只适合加密少量数据。因此,对称加密通常与非对称加密相结合。
- 加密:用对称加密数据获取密文A,用非对称加密对称加密密钥获得密文B,把AB放到一起
- 解密:先用非对称解密文B获得对称加密密钥,再用此密钥解密文A获取原始数据
3. 散列算法
- 散列(Hash)函数对不同长度的输入信息产生固定长度(例如MD5是16字节(128位)的输出
- 这种固定长度的输出称为原输入消想
散列"或“消息摘要”(Message digest)。
- 这种固定长度的输出称为原输入消想
- 安全的哈希函数H必须具有以下属性:
- 1)可应用
大小不一的数据上。 - 2)H能够生成
大小固定的输出 - 3)任意给定x,H(×)的计算
相对简单。 - 4)任意给定的代码h,要发现满足H(x)=hx在计算上是不可行的。hash值不能反向推出原始数据,但可以破解。例如,每个单词都可以通过设置字典来计算hash值,加密前的原文通过一一碰撞获得)
- 5)任意给定的块x,要发现满足H=H(x)而y=×计算不可行。hash值相同,但不能推断原来的两个值也相同)
- 1)可应用
- 应用:错误校正、文件校准(奇偶校准、CRC,无防篡改功能)、数字签名等
4. 侧重点
- 对称加密:
XORDES、3DESAES Advanced Encryption Standard(工业标准)- Blowfish
- twofish
- 非对称加密:
RSA(两个大素数(几十个字节的长度)的积累因式分解难以恢复原来的两个素数)- Elgamal
- 背包算法
- Rabin
- D-H
- ECC(圆曲线加密算法)
- 散列HASH算法:
- MD5 Message-Digest Algorithm5
- SHA1 SHA2 (SHA-256,512)Secure Hash Algorithm.
- 重点是加密解密
接口调用与应用,而不是加密解密算法本身实现(数论、矩阵等)
二、详解加解密算法
1. 对称加密:异或算法
- A为明文,B为密文
- 加密:B=A^key
- 解密:A=B^key
- 丑闻:360密盘号称10W年不能破解,但突然破解,当时360个密集磁盘项目外包,外包人员方便使用不同或算法,把钥匙放在密文前面,最离谱的是代码提交给360审计也通过了。
#include <stdio.h> #include <string.h> #include <tchar.h>
/// 异或加密解密是一样的操作
void f(char *data, int datalen,char *key, int keylen)
{
int i;
for (i = 0; i < datalen; i++)
data[i] = (char) (data[i] ^ key[i%keylen]); ///data轮流和key对应的字节进行异或
}
int _tmain(int argc, _TCHAR* argv[])
{
char buff[]="hello encrypt&decrypt";
char key[]="1234abcd";
f(buff,strlen(buff),key,strlen(key)); //XOR加密
printf("encrypted:%s\n",buff);
f(buff,strlen(buff),key,strlen(key)); //XOR解密
printf("decrypted:%s\n",buff);
return 0;
}
2. 对称加密:DES算法
- DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的
块算法。- DES是可以被破解的,可能一本书的某一句话就是密钥。
- DES算法的入口参数有三个:Key、Data、Mode。其中Key为7个字节共64位,是DES算法的工作密钥; Data为8个字节64位(加密以8Byte为基本单位),是要被加密或被解密的数据;Mode为DES的工作方式,有两种:加密或解密
- 比如加密数据有20Byte,以8Byte为基本单位,后面4个Byte不足8个Byte,填4Byte的0组成8个Byte进行加密。
- 3DES (即Triple DES是DES向AES过渡的加密算法,它使用
3条56位的密钥对数据进行三次加密。是DES的个更安全的变形。它以DES为基本模块,通过组合分组方法设计出分组加密算法。比起最初的DES,3DES更为安全。 - 纯C写的和OpenSSL都是可移植的,比微软的CryptoAPI好(只能在windows下使用),des.c和des.h是des加解密算法的实现
// des_test.c
//
#include "stdio.h"
#include "stdlib.h"
#include "des.h"
#include <conio.h>
#pragma warning(disable:4996)
int main()
{
char *file_In = "in.txt";
char *file_Out = "out.txt";
char *file_tmp = "des.dat";
char *key = "key.txt";
//DES加密
DES_Encrypt_File(file_In,key,file_tmp);
printf("DES_E OK!\n");
//DES解密
DES_Decrypt_File(file_tmp,key,file_Out);
if(remove(file_tmp)){
}
printf("DES_D OK!\n");
//3重DES加密
D3DES_Encrypt_File(file_In,key,file_tmp);
printf("D3DES_E OK!\n");
//3重DES解密
D3DES_Decrypt_File(file_tmp,key,file_Out);
if(remove(file_tmp)){
}
printf("D3DES_D OK!\n");
/// 1.getchar()先将输入的字符保存在缓冲区,然后再从缓冲区读取这个字符,是间接读取;
/// 2.getche()和getch()不需要将输入的字符保存在缓冲区,而是即输即取,也就是说,一输入一个字符,它立即直接读取;
/// 1.执行到getchar()函数时,光标闪动,等待输入字符:输入字符后无变化,需要按回车键, 按回车键后,getchar读取了这个字符,并将其赋值给变量a。
/// 2.执行到getche()函数时,光标闪动,等待输入字符:输入字符后,不需按回车键,在输入后,getche立即读入并赋值给b。
/// 3.执行到getch()函数时,光标闪动,等待输入字符:输入字符,并不能看到你输入的字符,屏幕仍是; 但在输入后瞬间,getch()函数就读取并赋值给了c。
getchar();
return 0;
}
/// des.h #include "stdio.h" #include "memory.h" #include "stdlib.h" #define PLAIN_FILE_OPEN_ERROR -1 #define KEY_FILE_OPEN_ERROR -2 #define CIPHER_FILE_OPEN_ERROR -3 #define DES_OK 1 #define BUFFER_SIZE 1024 #define ROUND 16//迭代次数,16次以上破解时只能使用穷举法 typedef char ElemType; int ByteToBit(ElemType ch,ElemType bit[8]);//字节转换成二进制 int BitToByte(ElemType bit[8],ElemType *ch);//二进制转换成字节 int Char8ToBit64(ElemType ch[8],ElemType bit[64]);//将长度为8的字符串转为二进制位串 int Bit64ToChar8(ElemType bit[64],ElemType ch[8]);//将二进制位串转为长度为8的字符串 int DES_MakeSubKeys(ElemType key[64],ElemType subKeys[16][48]);//生成子密钥 int DES_PC1_Transform(ElemType key[64], ElemType tempbts[56]);//密钥置换1 int DES_PC2_Transform(ElemType key[56], ElemType tempbts[48]);//密钥置换2 int DES_ROL(ElemType data[56], int time);//循环左移 int DES_IP_Transform(ElemType data[64]);//IP置换 int DES_IP_1_Transform(ElemType data[64]);//IP逆置换 int DES_E_Transform(ElemType data[48]);//扩展置换 int DES_P_Transform(ElemType data[32]);//P置换 int DES_SBOX(ElemType data[48]);//S盒置换 int DES_XOR(ElemType R[48], ElemType L[48],int count);//异或 int DES_Swap(ElemType left[32],ElemType right[32]);//交换 int DES_EncryptBlock(ElemType plainBlock[8], ElemType subKeys[16][48], ElemType cipherBlock[8]);//加密单个分组 int DES_DecryptBlock(ElemType cipherBlock[8], ElemType subKeys[16][48], ElemType plainBlock[8]);//解密单个分组 //DES算法 int DES_Encrypt(ElemType *plainBuffer, ElemType *keyBuffer, ElemType *cipherBuffer, int n);//加密数据 int DES_Decrypt(ElemType *cipherBuffer, ElemType *keyBuffer, ElemType *plainBuffer, int n);//解密数据 int DES_Encrypt_File(char *plainFile, char *keyStr,char *cipherFile);//加密文件 int DES_Decrypt_File(char *cipherFile, char *keyStr,char *plainFile);//解密文件 //3DES算法 int D3DES_Encrypt(ElemType *plainBuffer, ElemType *keyBuffer, ElemType *cipherBuffer, int n);//加密数据 int D3DES_Decrypt(ElemType *cipherBuffer, ElemType *keyBuffer, ElemType *plainBuffer, int n);//解密数据 int D3DES_Encrypt_File(char *plainFile, char *keyStr,char *cipherFile);//加密文件 int D3DES_Decrypt_File(char *cipherFile, char *keyStr,char *plainFile);//解密文件 //初始置换表IP static int IP_Table[64] = { 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, 56,48,40,32,24,16,8,0, 58,50,42,34,26,18,10,2, 60,52,44,36,28,20,12,4, 62,54,46,38,30,22,14,6}; //逆初始置换表IP^-1 static int IP_1_Table[64] = { 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, 32,0,40,8,48,16,56,24}; //扩充置换表E static int E_Table[48] = { 31, 0, 1, 2, 3, 4, 3, 4, 5, 6, 7, 8, 7, 8,9,10,11,12, 11,12,13,14,15,16, 15,16,17,18,19,20, 19,20,21,22,23,24, 23,24,25,26,27,28, 27,28,29,30,31, 0}; //置换函数P static int P_Table[32] = { 15,6,19,20,28,11,27,16, 0,14,22,25,4,17,30,9, 1,7,23,13,31,26,2,8, 18,12,29,5,21,10,3,24}; //S盒 static int S[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,