- 对称分组加密常用算法:
·DES
·3DES
·AES
·国密SM4
- 对称分组加密应用场景:
文件或者视频加密
加密比特币私钥
消息或者配置项加密
SSL通信加密
对称分组加密
使用异或实现一个简易的对称加密算法
A明文 B秘钥
AB=密文AB
(AB)B =A
密码补全和初始化
数据补全策略:PADDING_PKCS7(补其他) PADDING_ZERO(补0)举例:
block = 8
12345678 9
12345678 90000000 ZERO12345678 97777777 PKCS7
更详细请看:DES加密初探 - 乙太的小屋 (52ying.top)DES算法填充方式
#include <iostream>
using namespace std;
//对称加解密数据
//@para data 输入数据
//@para data_size 输入数据大小
//@para out 输出数据
//@para pass 密钥
//@para pass_size 密钥长度
//@return 加解密后数据大小
#define XOR_BLOCK 8
int XorCipher(const unsigned char* data, int data_size,
unsigned char* out,
const unsigned char* pass,
int pass_size
)
{
static const char iv[] = "abcdefgt";
//初始化密钥
auto p = *(unsigned long long*)iv;
//密钥补全,并且异或初始化向量
//密钥小于XOR_BLOCK或者大于XOR_BLOCK
for (int i = 0; i < pass_size; i += XOR_BLOCK)
{
unsigned long long tmp = 0;
int size = XOR_BLOCK;
//密钥小于 XOR_BLOCK
if (pass_size - i < XOR_BLOCK) {
size = pass_size - i;
}
memcpy(&tmp, (pass + i), size);
p = (p ^ tmp);
}
//数据源转换成8字节数据类型
auto d = (unsigned long long*)data;
//输出数据
auto o = (unsigned long long*)out;
//数据分组处理
int i = 0;
for (; i < data_size / XOR_BLOCK; i++)
{
o[i] = (d[i] ^ p);
}
//输入数据的补充
int mod = data_size % XOR_BLOCK;
if (mod != 0)
{
unsigned long long tmp = 0;
memcpy(&tmp, (d + i), mod);
}
int re_size = data_size;
return re_size;
}
int main1(int argc, char* argv[])
{
unsigned char data[] = "测试加解密数据TEST123测试";
unsigned char out[1024] = { 0 };
unsigned char out2[1024] = { 0 };
unsigned char pass[] = "12345678";
int pass_size = strlen((char*)pass);
int len = XorCipher(data, sizeof(data),out, pass, pass_size);
cout << len << "|"<<out << endl;
len = XorCipher(out, len, out2, pass, pass_size);
cout << len << "|" << out2 << endl;
return 0;
}
DES_ECB攻击
#include <iostream>
#include <openssl/des.h>
using namespace std;
//交易数据
struct Slip
{
char from[16] = { 0 }; //A=>B 10000
char to[16] = { 0 }; //篡改为B=> 10000
long long amount = 0;
};
static const_DES_cblock key = "1234567";
static DES_key_schedule key_sch;
void EnSlip(const Slip& s, unsigned char* out, int& out_size)
{
const int size = sizeof(s);
auto p = (const unsigned char*)&s;
auto o = out;
DES_set_key(&key, &key_sch);
for(int i = 0; i < size; i += 8)
{
DES_ecb_encrypt((const_DES_cblock*)p, (DES_cblock*)o, &key_sch, DES_ENCRYPT);
p += 8;
o += 8;
out_size += 8;
}
}
void AttackSlip(unsigned char* out)
{
//修改秘文的from和to对调
unsigned char tmp[1024] = { 0 };
//from
memcpy(tmp, out, 16);
memcpy(out, out + 16, 16);
memcpy(out + 16, tmp, 16);
}
void DeSlip(const unsigned char* in, int size, Slip& s)
{
auto p = (const unsigned char*)in;
auto o = (unsigned char*)&s;
DES_set_key(&key, &key_sch);
for (int i = 0; i < size; i += 8)
{
DES_ecb_encrypt((const_DES_cblock*)p, (DES_cblock*)o, &key_sch, DES_DECRYPT);
p += 8;
o += 8;
}
}
int main()
{
{
unsigned char out[1024] = { 0 };
int out_size = 0;
Slip s1 = { "USER_A","USER_B",10000 };
cout << "s2 from: " << s1.from << endl;
cout << "s2 to: " << s1.to << endl;
cout << "s2 ammout: " << s1.amount << endl;
EnSlip(s1, out, out_size);
cout << "En:"<< out_size <<"---->" << out << endl;
//攻击密文1
AttackSlip(out);
Slip s2;
DeSlip(out, out_size, s2);
cout << "s2 from: " << s2.from << endl;
cout << "s2 to: " << s2.to << endl;
cout << "s2 ammout: " << s2.amount << endl;
}
unsigned char data[] = "1234567";//数据
unsigned char out[1024] = { 0 };//输出数据
unsigned char out2[1024] = { 0 };
//1.设置密钥
DES_set_key(&key, &key_sch);
//数据加密
DES_ecb_encrypt((const_DES_cblock*)data, (DES_cblock*)out, &key_sch, DES_ENCRYPT);
cout << "加密:" << out << endl;
//解密
DES_ecb_encrypt((const_DES_cblock*)out, (DES_cblock*)out2, &key_sch, DES_DECRYPT);
cout << "解密:" << out2 << endl;
getchar();
return 0;
}
DES_CBC
void EnSlipCBC(const Slip& s, unsigned char* out, int& out_size)
{
int size = sizeof(s);
auto p = (const unsigned char*)&s;
auto o = out;
DES_set_key(&key, &key_sch);
DES_cblock iv = { 0 };//初始化向量
//初始化向量 DES_cbc_encrypt 调用后值不变 DES_ncbc_encrypt保存上次的值
//如果数据不是8的倍数,会自动补0
if (size % 8!= 0)
{
out_size = size + (8 - size % 8);
}
DES_cbc_encrypt(p, o, sizeof(s), &key_sch, &iv,DES_ENCRYPT);
}
void DeSlipCBC(const unsigned char* in, int size, Slip& s)
{
DES_cblock iv = { 0 };
DES_set_key(&key, &key_sch);
//如果补0了,解密后无法知道实际大小,需要用户存储原数据大小
DES_cbc_encrypt(in, (unsigned char*)&s, size, &key_sch, &iv, DES_DECRYPT);
}
int main()
{
Slip s3;
EnSlipCBC(s1, out, out_size);
//AttackSlip(out);
DeSlipCBC(out, out_size, s3);
cout << "s3 from: " << s3.from << endl;
cout << "s3 to: " << s3.to << endl;
cout << "s3 ammout: " << s3.amount << endl;
}
封装DES实现CBC和ECB的PKCS7Padding分块填充
#pragma once
#include <string>
#include <openssl/des.h>
//枚举类型
enum XSecType
{
XDES_ECB,
XDES_CBC
};
/*
Xsec sec;
sec.Init(XDES_ECB,"12345678",ture);
*/
class XSec
{
public:
/// 初始化加密对象
/// <param name="type">加密类型</param>
/// <param name="pass">密钥,可以是二进制</param>
/// <param name="is_en">true加密,false解密</param>
/// 是否成功
virtual bool Init(XSecType type, const std::string& pass, bool is_en);
/// <summary>
/// 加解密数据
/// </summary>
/// <param name="in">输入数据</param>
/// <param name="in_size">数据大小</param>
/// <param name="out">输出数据</param>
/// <returns>成功返回加解密后数据大小,失败返回0</returns>
virtual int Encrypt(const unsigned char* in, int in_size, unsigned char* out);
private:
/// <summary>
///DES_ECB加密模式
/// </summary>
int EnDesECB(const unsigned char* in, int in_size, unsigned char* out);
//DES_ECB解密模式
int DeDesECB(const unsigned char* in, int in_size, unsigned char* out);
///DES_CBC加密模式
/// </summary>
int EnDesCBC(const unsigned char* in, int in_size, unsigned char* out);
//DES_CBC解密模式
int DeDesCBC(const unsigned char* in, int in_size, unsigned char* out);
//加密算法密钥
DES_key_schedule ks_;
//加秘算法类型
XSecType type_;
bool is_en_;
//数据块分组大小
int block_size_ = 0;
//初始化向量
unsigned char iv_[128] = { 0 };
};
#include "xsec.h"
#include <iostream>
using namespace std;
bool XSec::Init(XSecType type, const std::string& pass, bool is_en)
{
this->type_ = type;
this->is_en_ = is_en;
this->block_size_ = DES_KEY_SZ;
//初始化iv_
memset(iv_, 0, sizeof(iv_));
const_DES_cblock key = { 0 };
//密码策略,超出8字节丢弃,少的补充0
int key_size = pass.size();
if (key_size > block_size_) key_size = block_size_;
memcpy(&key, pass.data(), key_size);
DES_set_key(&key, &ks_);
return true;
}
int XSec::Encrypt(const unsigned char* in, int in_size, unsigned char* out)
{
if(type_ == XDES_ECB)
if (is_en_)
{
return EnDesECB(in, in_size, out);
}
else {
return DeDesECB(in, in_size, out);
}
else if (type_ == XDES_CBC)
if (is_en_)
{
return EnDesCBC(in, in_size, out);
}
else {
return DeDesCBC(in, in_size, out);
}
return 0;
}
int XSec::EnDesECB(const unsigned char* in, int in_size, unsigned char* out)
{
//数据填充PKCS7 Padding
//PKCS7Padding:假设数据长度需要填充n(n>0)个字节才对齐,那么填充n个字节,每个字节都是n;如果数据本身就已经对齐了,则填充一块长度为块大小的数据,每个字节都是块大小。
unsigned char padding[8] = { 0 };
int padding_size = block_size_ - (in_size % block_size_);
//填入补充的字节大小
memset(padding, padding_size, sizeof(padding));
int i = 0;
for ( ; i < in_size; i += block_size_)
{
//最后一块数据,小于block_size_ 需要填充
if ( in_size-i<block_size_)
{
//填入数据
memcpy(padding, in + i, in_size - i);
break;
}
DES_ecb_encrypt((const_DES_cblock*)(in + i), (DES_cblock*)(out + i), &ks_, DES_ENCRYPT);
}
//补充 PKCS7结尾
DES_ecb_encrypt((const_DES_cblock*)padding, (DES_cblock*)(out + i), &ks_, DES_ENCRYPT);
return in_size + padding_size;
}
int XSec::DeDesECB(const unsigned char* in, int in_size, unsigned char* out)
{
for (int i = 0; i < in_size; i += block_size_)
{
DES_ecb_encrypt((const_DES_cblock*)(in + i), (DES_cblock*)(out + i), &ks_, DES_DECRYPT);
}
return in_size - out[in_size - 1];
}
int XSec::EnDesCBC(const unsigned char* in, int in_size, unsigned char* out)
{
//数据填充PKCS7 Padding
unsigned char padding[8] = { 0 };
int padding_size = block_size_ - (in_size % block_size_);
//填入补充的字节大小
memset(padding, padding_size, sizeof(padding));
//ncbc保留iv修改 减去需要补充的数据
DES_ncbc_encrypt(in, out, in_size - (in_size % block_size_),&ks_,(DES_cblock*)iv_,DES_ENCRYPT);
//PKCS7 Padding
if (in_size % block_size_ != 0)
{
memcpy(padding, in + (in_size - (in_size % block_size_)), in_size % block_size_);
}
DES_ncbc_encrypt(padding, out+(in_size - (in_size % block_size_)),sizeof(padding), &ks_, (DES_cblock*)iv_, DES_ENCRYPT);
return in_size+padding_size;
}
int XSec::DeDesCBC(const unsigned char* in, int in_size, unsigned char* out)
{
DES_ncbc_encrypt(in, out, in_size, &ks_, (DES_cblock*)iv_, DES_DECRYPT);
return in_size - out[in_size-1];
}
int main(int argc, char* argv[])
{
{
unsigned char data[] = "123456789";
unsigned char out[1024] = { 0 };
unsigned char out2[1024] = { 0 };
XSec sec;
//ECB加密
sec.Init(XDES_ECB, "12345678", true);
cout <<"============== DES_ECB==================" << endl;
cout << sizeof(data) << "[" << data << "]" << endl;
int size = sec.Encrypt(data, sizeof(data), out);
cout << size << ":" << out << endl;
//ECB解密
sec.Init(XDES_ECB, "12345678", false);
size = sec.Encrypt(out, size, out2);
cout << size << "[" << out2 << "]" << endl;
//CBC解密
sec.Init(XDES_CBC, "12345678", true);
cout << "============== DES_CBC==================" << endl;
cout << sizeof(data) << "[" << data << "]" << endl;
size = sec.Encrypt(data, sizeof(data), out);
cout << size << ":" << out << endl;
//CBC解密
sec.Init(XDES_CBC, "12345678", false);
size = sec.Encrypt(out, size, out2);
cout << size << "[" << out2 << "]" << endl;
getchar();
}
}