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

news2024/10/18 22:25:37

image.png

image.png

image.png

image.png

image.png

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

·DES
·3DES
·AES

·国密SM4

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

文件或者视频加密

加密比特币私钥

消息或者配置项加密

SSL通信加密

对称分组加密

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

A明文 B秘钥
AB=密文AB
(AB)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 <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();
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2218059.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在Access中执行SQL语句

1.新建一个查询 2. 关闭弹出的窗口&#xff0c;创建一个空查询 3. 在“设计”页中点击“数据定义”进入输入SQL语句界面 4. “执行”后就能看到执行结果 5.如果想再次执行SQL&#xff0c;则可在MDI窗口标题栏右键&#xff0c;在弹出的菜单中选择“SQL 视图”即可

Vue向上滚动加载数据时防止内容闪动

目前的需求&#xff1a;当前组件向上滚动加载数据&#xff0c;dom加载完后&#xff0c;页面的元素位置不能发生变化 遇到的问题&#xff1a;加载完数据后&#xff0c;又把滚轮滚到之前记录的位置时&#xff0c;内容发生闪动 现在的方案&#xff1a; 加载数据之前记录整体滚动条…

Spring AI 整体介绍_关键组件快速入门_prompt_embedding等

Spring AI&#xff1a;Java开发者的AI集成新利器 在过去&#xff0c;Java开发者在构建AI应用时面临着缺乏统一框架的问题&#xff0c;导致不同AI服务的集成过程复杂且耗时。Spring AI应运而生&#xff0c;旨在为基于Java的应用程序提供一个标准化、高效且易于使用的AI开发平台…

51单片机的超声波视力保护仪【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块温度传感器光照传感器超声波传感器按键、LED、蜂鸣器等模块构成。适用于视力保护仪、坐姿矫正器、超声波防近视等相似项目。 可实现功能: 1、LCD1602显示温度、光照、距离和学习时间 2、超声波传感器采集头部与探…

如何做好SQL 数据库安全

随着信息技术的迅猛发展&#xff0c;数据库在现代信息系统中的重要性日益凸显。无论是电子商务平台、金融系统还是社交媒体应用&#xff0c;数据库都是其核心组件之一。其中&#xff0c;SQL&#xff08;Structured Query Language&#xff0c;结构化查询语言&#xff09;数据库…

效率飞跃 | SOLIDWORKS 2025:草图与装配体设计再升级!

一年一度的SOLIDWORKS新版本已经发布&#xff0c;快来看看SOLIDWORKS 2025这些让您眼前一亮的新功能&#xff0c;它们将为您的研发过程增添强大助力。 一、草图绘制 1、通过 XYZ 点生成的曲线可以选取坐标系统 新版本可选择曲线起点位置 2、转换实体作为构造几何体 转换实体…

Science Robotics 通过新材料打造FiBa软机器人 可实现四种形态进化

近几年由于材料科学的进步&#xff0c;软机器人相关技术近几年研究成果显著&#xff0c;与传统的刚性机器人相比&#xff0c;软机器人的设计灵感来源于自然界中的生物系统&#xff0c;如蠕虫、章鱼、壁虎和青蛙等。这些生物利用柔软、有弹性的材料&#xff0c;在复杂环境中展现…

微服务基础架构(图)

微服务基础架构是一种现代化的软件架构模式&#xff0c;旨在将大型复杂的应用程序拆分为多个小型、独立的服务。每个微服务专注于特定的业务功能&#xff0c;可独立开发、部署和扩展。 在微服务基础架构中&#xff0c;通常会使用轻量级的通信机制&#xff0c;如 RESTful API 或…

C++简易日志系统:打造高效、线程安全的日志记录工具

目录 引言&#xff1a; 1.日志的基本概念 1.1.什么是日志&#xff1f; 1.2.我们为什么需要日志&#xff1f; 2.自己实现一个简易日志 2.1.日志的等级 2.2日志的格式 2.3.获取时间的方法 2.4.日志的主体实现 参数&#xff1a; 代码解析&#xff1a; 问题&#xff1a…

C++新手入门指南:从基础概念到实践之路

C 继承了 C 语言的高效性和灵活性&#xff0c;同时新增了面向对象编程的特点。这使得 C 既可以进行底层系统编程&#xff0c;又能进行面向对象的软件设计。在面向对象编程方面&#xff0c;C 支持封装、继承和多态三大特性。 &#x1f4af;C 初印象 语言的发展就像是练功打怪…

用Java爬虫API,轻松获取电商商品SKU信息

在电子商务的精细化运营时代&#xff0c;SKU信息的重要性不言而喻。SKU&#xff08;Stock Keeping Unit&#xff09;信息不仅包含了商品的规格、价格、库存等关键数据&#xff0c;还直接影响到库存管理、价格策略和市场分析等多个方面。如何高效、准确地获取这些信息&#xff0…

STM32—SPI通信外设

1.SPI外设简介 STM32内部集成了硬件SPI收发电路&#xff0c;可以由硬件自动执行时钟生成、数据收发等功能&#xff0c;减轻CPU的负担可配置8位/16位数据帧、高位先行/低位先行时钟频率&#xff1a;fpclk/(2,4,8,16,32,64,128,256)支持多主机模型、主或从操作可精简为半双工/单…

【GESP】C++一级练习BCQM3049,细胞分裂

GESP一级知识点整形int和for循环练习。 题目题解详见&#xff1a;【GESP】C一级练习BCQM3049&#xff0c;细胞分裂 | OneCoder 【GESP】C一级练习BCQM3049&#xff0c;细胞分裂 | OneCoderGESP一级知识点整形int和for循环练习。https://www.coderli.com/gesp-1-bcqm3049/ C …

微服务--Ribbon负载均衡器

Nacos 本身里面就内置了Rabbion&#xff0c; 所以 不需要额外添加 添加LoadBalanced注解&#xff1a; Rabbion 内置的有好几种 负载均衡器 可以根据业务去选择&#xff0c;我们一般不会额外配置 都是默认的轮询&#xff0c;因为我们是基于docker发布的 大家的资源都是平等的 若…

Vue.js + Element UI 实现多方式登录功能(账号/手机号验证码登录)

引言 在现代Web应用中&#xff0c;提供多种登录方式已成为一种标准做法&#xff0c;这不仅能提升用户体验&#xff0c;还能满足不同用户的需求。本文将详细介绍如何使用Vue.js框架结合Element UI组件库&#xff0c;实现一个包含账号登录和手机号验证码登录两种方式的登录页面。…

Leetcode 单词规律

即判断给定的模式字符串&#xff08;pattern&#xff09;和单词字符串&#xff08;s&#xff09;是否遵循相同的对应规则。具体来说&#xff0c;就是要判断 pattern 中的字符与 s 中的单词是否存在一一对应的关系&#xff0c;即双射&#xff08;bijection&#xff09;。 算法思…

ant design vue TimePicker时间选择器不点击确认也可以设置值

文章目录 前言一、背景二、操作步骤1.复现前的准备工作&#xff08;1&#xff09;vue版本和ant design vue 版本&#xff08;2&#xff09;任意ant design vue TimePicker的demo 2.解决问题&#xff08;1&#xff09;使用change时间&#xff08;无效&#xff09;&#xff08;2&…

【学习】word保存图片

word中有想保存的照片 直接右键另存为的话&#xff0c;文件总是不清晰&#xff0c;截屏的话&#xff0c;好像也欠妥。 怎么办? 可以另存为 网页 .html 可以得到&#xff1a; 原图就放到了文件夹里面

在线白板:为远程课堂注入活力的协作工具

在线白板作为一种协作平台&#xff0c;极大地丰富了远程教学的互动性和创造性。在即时白板的帮助下&#xff0c;教师能够与学生共同在虚拟空间中创作和交流&#xff0c;实现知识的共享与思维的碰撞。 https://js.design/?sourcecsdn&planjh1018 首先&#xff0c;在线白板…

Spring Security 基础配置详解(附Demo)

目录 前言1. 基本知识2. Demo3. 实战 前言 基本的Java知识推荐阅读&#xff1a; java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&#xff09;【Java项目】实战CRUD的功能整理&#xff08;持续更新&#xff09; 1. 基本知识 HttpSecurity 是 Spri…