2023/11/10学习记录-C/C++对称分组加密DES

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 本文介绍了对称分组加密的常见算法(如DES、3DES、AES和国密SM4)及其应用场景,包括文件和视频加密、比特币私钥加密、消息和配置项加密及SSL通信加密。文章还详细展示了如何使用异或实现一个简易的对称加密算法,并通过示例代码演示了DES算法在ECB和CBC模式下的加密和解密过程,以及如何封装DES实现CBC和ECB的PKCS7Padding分块填充。

image.png

image.png

image.png

image.png

image.png

  • 对称分组加密常用算法:

·DES
·3DES
·AES

·国密SM4

  • 对称分组加密应用场景:

文件或者视频加密

加密比特币私钥

消息或者配置项加密

SSL通信加密

对称分组加密

使用异或实现一个简易的对称加密算法

A明文 B秘钥
A^B=密文A^B
(A^B)^B =A

密码补全和初始化
数据补全策略:PADDING_PKCS7(补其他) PADDING_ZERO(补0)

举例:

block = 8

12345678 9
12345678 90000000 ZERO

12345678 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

using namespace std;

bool XSec::Init(XSecType type, const std::string& pass, bool isen)
{
this->type
= type;
this->isen = is_en;
this->blocksize = DES_KEYSZ;
//初始化iv

memset(iv, 0, sizeof(iv));
const_DES_cblock key = { 0 };
//密码策略,超出8字节丢弃,少的补充0
int key_size = pass.size();
if (key_size > blocksize) key_size = blocksize;
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 (isen)
{
return EnDesECB(in, in_size, out);
}
else {
return DeDesECB(in, insize, out);
}
else if (type
== XDES_CBC)
if (isen)
{
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 = blocksize - (in_size % blocksize);
//填入补充的字节大小
memset(padding, padding_size, sizeof(padding));
int i = 0;
for ( ; i < in_size; i += blocksize)
{
//最后一块数据,小于blocksize 需要填充
if ( in_size-i<blocksize)
{
//填入数据
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 += blocksize)
{
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 = blocksize - (in_size % blocksize);
//填入补充的字节大小
memset(padding, padding_size, sizeof(padding));
//ncbc保留iv修改 减去需要补充的数据
DES_ncbc_encrypt(in, out, in_size - (in_size % blocksize),&ks_,(DEScblock*)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, insize, &ks, (DEScblock*)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();
}

}

相关文章
|
3月前
|
存储 安全 数据安全/隐私保护
浅谈对称加密(AES与DES)
浅谈对称加密(AES与DES)
78 1
|
21小时前
|
算法 数据安全/隐私保护 Python
DES加密初探
本文介绍了Python中常用的DES和3DES加解密方法,包括ECB和CBC模式。通过示例代码展示了如何使用`Crypto`和`pyDes`库实现加解密,并讨论了不同的填充方式。最后,通过一道CTF例题,详细解析了从图像中提取密文、进行ASCII转换、Base64解码、凯撒解码和最终的DES解密过程。
17 4
DES加密初探
|
4月前
|
算法 C语言 C++
C++语言学习指南:从新手到高手,一文带你领略系统编程的巅峰技艺!
【8月更文挑战第22天】C++由Bjarne Stroustrup于1985年创立,凭借卓越性能与灵活性,在系统编程、游戏开发等领域占据重要地位。它继承了C语言的高效性,并引入面向对象编程,使代码更模块化易管理。C++支持基本语法如变量声明与控制结构;通过`iostream`库实现输入输出;利用类与对象实现面向对象编程;提供模板增强代码复用性;具备异常处理机制确保程序健壮性;C++11引入现代化特性简化编程;标准模板库(STL)支持高效编程;多线程支持利用多核优势。虽然学习曲线陡峭,但掌握后可开启高性能编程大门。随着新标准如C++20的发展,C++持续演进,提供更多开发可能性。
89 0
|
2月前
|
编译器 C语言 C++
配置C++的学习环境
【10月更文挑战第18天】如果想要学习C++语言,那就需要配置必要的环境和相关的软件,才可以帮助自己更好的掌握语法知识。 一、本地环境设置 如果您想要设置 C++ 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C++ 编译器。 二、文本编辑器 通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。 C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。 在开始编程之前,请确保您有一个文本编辑器,且有足够的经验来编写一个计算机程序,然后把它保存在一个文件中,编译并执行它。 Visual Studio Code:虽然它是一个通用的文本编辑器,但它有很多插
|
2月前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
37 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
|
2月前
|
Java 编译器 C++
c++学习,和友元函数
本文讨论了C++中的友元函数、继承规则、运算符重载以及内存管理的重要性,并提到了指针在C++中的强大功能和使用时需要注意的问题。
26 1
|
2月前
|
存储 安全 Java
shiro学习二:shiro的加密认证详解,加盐与不加盐两个版本。
这篇文章详细介绍了Apache Shiro安全框架中密码的加密认证机制,包括不加盐和加盐两种加密方式的实现和测试。
118 0
|
2月前
|
数据安全/隐私保护 Python
python学习十一:python常用模块使用,如 加密模块pyarmor,时间模块time等
这篇文章介绍了Python中两个常用模块的使用:加密模块pyarmor用于保护代码,以及时间模块time用于处理时间相关的功能。
85 0
|
3月前
|
算法 数据安全/隐私保护 C++
超级好用的C++实用库之Des加解密
超级好用的C++实用库之Des加解密
61 0
|
20天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
30 2