目录
1、前言
算是第一个开发任务了,C++写一个DES 加解密类用来解密序列号,加解密适用ecb/cbc模式,最好调用OpenSSL库。
DES是一种对称分组加密算法,只是用它加解密的话,我认为不需要理解得特别深刻,只要知道以下几点就好了:
(1)分组:每八字节为一组,利用密钥进行加密,最后将密文拼接;
(2)对称:加解密使用同一种算法,在openssl中使用的是同一个函数,只是参数不同;
(3)主要有ecb(电子密码)和cbc(密码分组)两种模式,两种模式是密钥产生方式不同,ecb对分组八字节明文组密钥相同,cbc循环产生密钥,也就是对分组八字节明文密钥不一定相同;
(4)明文长度不满足八字节整数倍要求,需要padding,使用末尾补零的方式。
2、分析实现
(1)类组成:
写一个des加解密类,首先从大局观来看这个类的组成:
其实内容很简单,主要就是加解密的四个函数以及加解密的整合。
(2)类分解:
简单介绍一下各个函数的成分:
a.构造函数+析构函数:
两个构造函数,一个默认构造,其中包含默认密钥;另一个构造可以类外指定密钥。
b.ecb加密函数:
输入明文,调用openssl中的DES_ecb_encrypt函数进行加密,输出密文。
c.ecb解密函数:
输入密文,调用openssl中的DES_ecb_encrypt函数进行解密,输出明文。
d.cbc加密函数:
输入明文,调用openssl中的DES_ncbc_encrypt函数进行解密,输出密文。
e.cbc解密函数:
输入密文,调用openssl中的DES_ncbc_encrypt函数进行解密,输出明文。
f.des加密函数:
输入明文,输出密文,用户可指定模式。
g.des解密函数:
输入密文,输出明文,用户可指定模式。
—————本来想在这里贴个代码的,但是发现代码太占地儿了,所以决定贴在最后了—————
3、补充优化
(1)实现了DES加解密类,在实际业务应用中,需要从文件中读取处理再写入文件,大概如下图:
所以还要再添加四个global函数:
a.从文件中读取字符串;
b.字符串转01比特串;
c.01比特串转字符串;
d.字符串写入文件;
————————————同样,实现代码贴在最后————————————————————
(2)目前是写到了这里,我考虑以下几个优化方向:
a.我要将加密的文件传给云端,这个加密文件是不是应该包含加密模式信息(ecb/cbc);
b.异常处理;
c.这个字符串和比特串的转换写的还比较鸡肋,从网上借鉴的,得再重写一下,用bitset看看;
4、鸡毛蒜皮
————————————以下语言会比较混乱————————————————————
——20230328——
万事开头难:
1、网上资料太多了,讲的内容差异也比较大,需要慢慢挑,很容易花了眼;
2、道心也不坚定,总是觉得能用就好了,没必要搞清楚理论,所以半拉瓶子晃啊晃的;
3、第一天感觉就是摸鱼摸鱼再摸鱼,没啥进展->:)
4、快下班了,我有一个大胆的想法,直接读OpenSSL里的des.h库,看网上的讲解太难受了。
——20230229——
今天转换策略
1、让AI帮我写个代码;(不大行,跑都跑不起来)
2、看看OpenSSL的des.h;
先看实现再看原理。
咱们先装个openssl库:
(1)装库:
哭死真的,装个库类似爹了
windows下VS2017使用openssl库的环境搭建https://www.jianshu.com/p/12b748bdedd2 LNK2019错误搞死我了,结果是链接器没配,我以为是openssl库安装的问题,来来回回装了好几次,哭死!openssl安装1.1.1,别安装3.0,那玩意儿用不起来!
哭死,写出来了,亲娘啊!
-——20230331——
让我测试一下des加密的正确性,比对在线des加密解密结果,我登了四个网站,各个网站加密结果都不一样,而且是base64编码,我输出的是Unicode乱码,人都麻了,后边儿又把结果进行base64编码,跟其中一个网站的结果接近,把那个网站贴过来。编解码这块儿太搞了......
在线des加解密https://www.mklab.cn/utils/des
5、贴个代码
代码实现都是从网上各处借鉴的,感谢万能网络,感谢前辈大佬!
理论:
DES加密算法实现https://zhuanlan.zhihu.com/p/94208042
实践:
C++ 使用openssl库实现 DES 加密——CBC模式 && RSA加密——公加私解——私加公解https://www.cnblogs.com/azbane/p/10178729.html
OPENSSL库的使用-DES篇https://blog.csdn.net/m0_46577050/article/details/121711502
字符串转二进制
https://www.techiedelight.com/zh/convert-string-to-binary-in-cpp/
#include<iostream>
#include<openssl/des.h>
#include<string>
#include<vector>
#include<stdlib.h>
#include<stdio.h>
#include<exception>
//#define DES_ECB 0
//#define DES_CBC 1
static int DES_ECB = 0;
static int DES_CBC = 1;
class DES {
public:
/**
* 构造函数,传入加密密钥
* @param key 加密密钥,长度为8字节
*/
DES(const std::string& key) {
//转换字符串为DES_cblock
memset(keyEncrypt, 0, 8);
//补齐密钥
if (key.length() <= 8)
memcpy(keyEncrypt, key.c_str(), key.length());
else
memcpy(keyEncrypt, key.c_str(), 8);
// 将密钥转换为DES_key_schedule结构体
DES_set_key_unchecked(&keyEncrypt, &key_schedule_);
}
/**
* DES加密函数(ecb模式 padding 0)
* @param plaintext 明文
* @return 密文
*/
std::string ecb_encrypt(const std::string& plaintext) {
const_DES_cblock inputblock;//输入的8字节
memset(inputblock, 0, 8);
DES_cblock outputblock;//输出的8字节
memset(outputblock, 0, 8);
std::vector<unsigned char> vecciphertext;//存放加密的密文
// 创建一个与明文长度相同的字符串,用于存放密文
unsigned char tmp[8];
// 调用OpenSSL库的DES_ecb_encrypt函数进行加密,循环加密,每8字节一次
for (int i = 0; i < plaintext.length() / 8; ++i)
{
memcpy(inputblock, plaintext.c_str() + i * 8, 8);
DES_ecb_encrypt(&inputblock, &outputblock, &key_schedule_, DES_ENCRYPT); //加密
memcpy(tmp, outputblock, 8);
//将加密的八字节加入容器
for (int j = 0; j < 8; j++)
vecciphertext.push_back(tmp[j]);
}
//明文
if (plaintext.length() % 8 != 0)
{
size_t tmp1 = plaintext.length() / 8 * 8;
size_t tmp2 = plaintext.length() - tmp1;
memset(inputblock, 0, 8);
memcpy(inputblock, plaintext.c_str() + tmp1, tmp2);
// 加密函数
DES_ecb_encrypt(&inputblock, &outputblock, &key_schedule_, DES_ENCRYPT);
memcpy(tmp, outputblock, 8);
for (int j = 0; j < 8; j++)
vecciphertext.push_back(tmp[j]);
}
std::string ciphertext;
//std::string ciphertext(plaintext.size(), 0);
//ciphertext.clear();
ciphertext.assign(vecciphertext.begin(), vecciphertext.end());
return ciphertext;
}
/**
* DES解密函数(ecb模式)
* @param ciphertext 密文
* @return 密文
*/
std::string ecb_decrypt(const std::string& ciphertext)
{
const_DES_cblock inputblock;
DES_cblock outputblock;
std::vector<unsigned char> vecplaintext;
unsigned char tmp[8];
for (int i = 0; i < ciphertext.length() / 8; i++)
{
memcpy(inputblock, ciphertext.c_str() + i * 8, 8);
DES_ecb_encrypt(&inputblock, &outputblock, &key_schedule_, DES_DECRYPT);
memcpy(tmp, outputblock, 8);
for (int j = 0; j < 8; j++)
vecplaintext.push_back(tmp[j]);
}
if (ciphertext.length() % 8 != 0)
{
size_t tmp1 = ciphertext.length() / 8 * 8;
size_t tmp2 = ciphertext.length() - tmp1;
memset(inputblock, 0, 8);
memcpy(inputblock, ciphertext.c_str() + tmp1, tmp2);
// 解密函数
DES_ecb_encrypt(&inputblock, &outputblock, &key_schedule_, DES_DECRYPT);
memcpy(tmp, outputblock, 8);
for (int j = 0; j < 8; j++)
vecplaintext.push_back(tmp[j]);
}
std::string plaintext; // 明文
//std::string plaintext(ciphertext.size(), 0);
//plaintext.clear();
plaintext.assign(vecplaintext.begin(), vecplaintext.end());
return plaintext;
}
/**
* DES加密函数(cbc模式 padding 0)
* @param plaintext 明文
* @return 密文
*/
std::string cbc_encrypt(const std::string& plaintext)
{
//初始化IV向量
DES_cblock ivec;
memcpy(ivec, keyEncrypt, sizeof(keyEncrypt));
// 循环加密,每8字节一次
const_DES_cblock inputblock;
DES_cblock outputblock;
std::vector<unsigned char> vecciphertext;
unsigned char tmp[8];
for (int i = 0; i < plaintext.length() / 8; i++)
{
memcpy(inputblock, plaintext.c_str() + i * 8, 8);
DES_ncbc_encrypt(inputblock, outputblock, 8, &key_schedule_, &ivec, DES_ENCRYPT); //加密
memcpy(tmp, outputblock, 8);
for (int j = 0; j < 8; j++)
vecciphertext.push_back(tmp[j]);
//重置ivec
memcpy(ivec, outputblock, 8);
}
if (plaintext.length() % 8 != 0)
{
size_t tmp1 = plaintext.length() / 8 * 8;
size_t tmp2 = plaintext.length() - tmp1;
memset(inputblock, 0, 8);
memcpy(inputblock, plaintext.c_str() + tmp1, tmp2);
// 加密函数
DES_ncbc_encrypt(inputblock, outputblock, 8, &key_schedule_, &ivec, DES_ENCRYPT); //加密
memcpy(tmp, outputblock, 8);
for (int j = 0; j < 8; j++)
vecciphertext.push_back(tmp[j]);
}
std::string ciphertext;
ciphertext.assign(vecciphertext.begin(), vecciphertext.end());
return ciphertext;
}
/**
* DES解密函数(ecb模式)
* @param ciphertext 密文
* @return 密文
*/
std::string cbc_decrypt(const std::string& ciphertext)
{
//初始化IV向量
DES_cblock ivec;
memcpy(ivec, keyEncrypt, sizeof(keyEncrypt));
// 循环解密,每8字节一次
const_DES_cblock inputblock;
DES_cblock outputblock;
std::vector<unsigned char> vecplaintext;
unsigned char tmp[8];
for (int i = 0; i < ciphertext.length() / 8; i++)
{
memcpy(inputblock, ciphertext.c_str() + i * 8, 8);
DES_ncbc_encrypt(inputblock, outputblock, 8, &key_schedule_, &ivec, DES_DECRYPT); //解密
memcpy(tmp, outputblock, 8);
for (int j = 0; j < 8; j++)
vecplaintext.push_back(tmp[j]);
}
if (ciphertext.length() % 8 != 0)
{
size_t tmp1 = ciphertext.length() / 8 * 8;
size_t tmp2 = ciphertext.length() - tmp1;
memset(inputblock, 0, tmp2);
memcpy(inputblock, ciphertext.c_str() + tmp1, tmp2);
DES_ncbc_encrypt(inputblock, outputblock, long(tmp2), &key_schedule_, &ivec, DES_DECRYPT); //解密
memcpy(tmp, outputblock, tmp2);
for (int j = 0; j < 8; j++)
vecplaintext.push_back(tmp[j]);
}
std::string plaintext;
plaintext.assign(vecplaintext.begin(), vecplaintext.end());
return plaintext;
}
std::string DESencrypt(const std::string& plaintext, int mode)
{
switch (mode)
{
case 0:return ecb_encrypt(plaintext);
case 1:return cbc_encrypt(plaintext);
}
std::cerr << "模式选择错了!" << std::endl;
exit(1);
}
std::string DESdecrypt(const std::string& ciphertext, int mode)
{
switch (mode)
{
case 0:return ecb_decrypt(ciphertext);
case 1:return cbc_decrypt(ciphertext);
}
std::cerr << "模式选择错了!" << std::endl;
exit(1);
}
private:
DES_cblock keyEncrypt; //密钥
DES_key_schedule key_schedule_; // 存放加密密钥的结构体
};
int main()
{
std::string key = "jzysg";
DES des(key);
std::string plaintext = "上班太快乐了!";
std::cout << "输入明文为:" << plaintext << std::endl;
//ecb 模式
std::string ecb_ciphertext = des.DESencrypt(plaintext,DES_ECB);
std::cout << "ecb加密密文为:" << ecb_ciphertext << std::endl;
std::string ecb_decrpyttext = des.DESdecrypt(ecb_ciphertext,3);
std::cout << "ecb解密明文为:" << ecb_decrpyttext << std::endl;
//cbc模式
std::string cbc_ciphertext = des.DESencrypt(plaintext,DES_CBC);
std::cout << "cbc加密密文为:" << cbc_ciphertext << std::endl;
std::string cbc_decrpyttext = des.DESdecrypt(cbc_ciphertext,DES_CBC);
std::cout << "cbc解密明文为:" << cbc_decrpyttext << std::endl;
//std::string ecb_ciphertext = des.ecb_encrypt(plaintext);
//std::cout << "ecb加密密文为:" << ecb_ciphertext << std::endl;
//std::string ecb_decrpyttext = des.ecb_decrypt(ecb_ciphertext);
//std::cout << "ecb解密明文为:" << ecb_decrpyttext << std::endl;
//std::string cbc_ciphertext = des.cbc_encrypt(plaintext);
//std::cout << "cbc加密密文为:" << cbc_ciphertext << std::endl;
//std::string cbc_decrpyttext = des.cbc_decrypt(cbc_ciphertext);
//std::cout << "cbc解密明文为:" << cbc_decrpyttext << std::endl;
}
#include "global_func.h"
std::string readFileinfotoString(const std::string& filename)
{
std::ifstream ifile(filename, std::ios::binary);
std::ostringstream buf;
char ch;
while (buf && ifile.get(ch))
buf.put(ch);
return buf.str();
}
void writeStringtoFile(const std::string& s, const std::string& write_filename)
{
std::ofstream os(write_filename, std::ios_base::out);
os.open(write_filename,std::ios::binary);
os << s;
os.close();
}
std::string byte2bit(const std::string& byte)
{
size_t length = byte.length();
std::string bit(length * 8, 0);
for (int i = 0; i < length; i++) {
for (int j = 0; j < 8; j++) {
bit[i * 8 + j] = (byte[i] >> (7 - j)) & 1;
}
}
return bit;
}
std::string bit2byte(const std::string& bit)
{
size_t length = bit.length() / 8;
std::string byte(length, 0);
for (int i = 0; i < length; i++)
{
byte[i] = 0;
for (int j = 0; j < 8; j++)
byte[i] = (byte[i] << 1) + bit[i * 8 + j];
}
return byte;
}