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

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();
	}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

链上的羁绊,数据与节点的暗涌心跳

公主请阅 1. 合并两个有序链表1.1 题目说明示例 1示例 2示例 3 1.2 题目分析1.3 代码部分1.4 代码分析 2. 链表的中间节点2.1 题目说明示例 1示例 2 2.2 题目分析2.3 代码部分2.4 代码分析 1. 合并两个有序链表 题目传送门 1.1 题目说明 这个问题要求将两个升序链表合并成一个…

安装谷歌JSON可视化插件-JSON-Handle

背景&#xff1a; 最近在学习node开发&#xff0c;返回的数据看起来太难受&#xff0c;非常需要浏览器自动格式化接口返回的json数据。以下介绍一下怎么在浏览器安装JSON-Handle插件。 步骤&#xff1a; 1、下载扩展文件 地址&#xff1a;JSON-Handle 官网 - 打开json格式文…

健康推荐系统:SpringBoot技术革新

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

音频分割:长语音音频 分割为 短语音音频 - python 实现

在做语音任务时&#xff0c;有是会用到的语音音频是长音频&#xff0c;这就需要我们将长音频分割为短音频。 该示例将声音的音量和静默时间结合作为语音的分割条件。 使用音量和静默时间结合的分割条件&#xff0c;能够比较好的进行自然断句&#xff0c;不会话语没有说完就切断…

Pycharm下载安装教程(详细步骤)+汉化设置教程

今天讲解的是Pycharm安装教程和配置汉化设置&#xff0c;希望能够帮助到大家。 创作不易&#xff0c;还请各位同学三连点赞&#xff01;&#xff01;收藏&#xff01;&#xff01;转发&#xff01;&#xff01;&#xff01; 对于刚入门学习Python还找不到方向的小伙伴可以试试…

搭建mongodb单机部署-认证使用

搭建mongodb单机部署-认证使用 实现思路 先将配置文件配置好&#xff0c;使用不用认证的启动命令启动docker&#xff0c;然后创建账号并制定角色。在使用开启认证的命令重新启动容器就好。 这里我并没有说先停止容器&#xff0c;删掉容器重新创建容器。是因为我的启动命令中…

MyBatis 用法详解

文章目录 一、普通 SQL1.1 注解实现&#xff1a;1.1.1 参数传递&#xff1a;1.1.2 增&#xff08;Insert&#xff09;&#xff1a;1.1.3 删&#xff08;Delete&#xff09;&#xff1a;1.1.4 改&#xff08;Update&#xff09;&#xff1a;1.1.5 查&#xff08;Select&#xff…

OpenCV高级图形用户界面(15)注册一个回调函数来处理鼠标事件的函数setMouseCallback()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 为指定的窗口设置鼠标处理器。 setMouseCallback 是 OpenCV 中的一个功能&#xff0c;允许开发者注册一个回调函数来处理鼠标事件。当用户在窗口…

自监督学习:引领机器学习的新革命

引言 自监督学习&#xff08;Self-Supervised Learning&#xff09;近年来在机器学习领域取得了显著进展&#xff0c;成为人工智能研究的热门话题。不同于传统的监督学习和无监督学习&#xff0c;自监督学习通过利用未标注数据生成标签&#xff0c;从而大幅降低对人工标注数据…

champ模型部署指南

一、介绍 champ是由阿里巴巴、复旦大学和南京大学的研究人员共同提出的一种基于3D的将人物图片转换为视频动画的模型&#xff0c;该方法结合了3D参数化模型(特别是SMPL模型)和潜在扩散模型&#xff0c;能够精确地捕捉和再现人体的3D形状和动态&#xff0c;同时保持动画的时间一…

用SVM做时间序列预测真绝!最新思路无敌了,卷不动的进来看!

时间序列预测算法如今也算是百花齐放了&#xff0c;不过最近大家都在卷爆火的Transformer-based&#xff0c;卷不动的盆友其实也可以考虑从传统方法下手找创新&#xff0c;比如用SVM做时间序列预测。 SVM是一种经典的机器学习算法&#xff0c;在处理非线性及高维模式识别方面很…

k8s中的微服务

一、什么是微服务 用控制器来完成集群的工作负载&#xff0c;那么应用如何暴漏出去&#xff1f;需要通过微服务暴漏出去后才能被访问 Service是一组提供相同服务的Pod对外开放的接口。 借助Service&#xff0c;应用可以实现服务发现和负载均衡。 service默认只支持4层负载均…

黑马程序员-redis项目实践笔记2

目录 三、 Redis实现全局唯一ID 实现优惠卷秒杀下单 超卖问题 一人一单&#xff08;单例项目线程安全问题&#xff09; 一人一单&#xff08;集群环境下的并发问题&#xff09; 分布式锁的基本原理和实现方式对比 Redis分布式锁 实现核心思路 实现代码 Redis分布式锁…

供应商管理是什么?

你是一家制造业的老板&#xff0c;在需求旺盛的时段&#xff0c;却找不到一家合适的供应商&#xff0c;出现供应商突然退出合作&#xff1b;杀熟&#xff0c;供应的产品质量不过关等情况&#xff0c;企业的利益空间瞬间被压榨&#xff0c;急需一套管理系统来帮助选择供应商&…

《七度荒域:混沌之树》风灵月影二十二项游戏辅助:上帝模式/无限HP和EP/金币不减

《七度荒域:混沌之树》是款国产Roguelike银河恶魔城横版动作游戏&#xff0c;融合刷宝玩法。玩家将扮演修补世界的命运之子&#xff0c;探寻碎裂世界的秘密&#xff0c;在战斗轮回中成长&#xff0c;挑战未知与隐秘力量。风灵月影版修改器提供更多自定义和游戏体验调整选项&…

关于MyBatis的一些面试题

mybatis的执行流程 MyBatis 的执行流程主要包括 SQL 解析、参数绑定、执行查询/更新、结果映射等几个步骤。下面详细解释每个步骤的执行流程&#xff1a; 1. 加载配置文件和映射文件 加载 MyBatis 配置文件&#xff1a;启动时&#xff0c;MyBatis 通过 SqlSessionFactoryBui…

Transformer图解以及相关的概念

前言 transformer是目前NLP甚至是整个深度学习领域不能不提到的框架&#xff0c;同时大部分LLM也是使用其进行训练生成模型&#xff0c;所以transformer几乎是目前每一个机器人开发者或者人工智能开发者不能越过的一个框架。接下来本文将从顶层往下去一步步掀开transformer的面…

2018年计算机网络408真题解析

第一题&#xff1a; 解析&#xff1a;TCP/IP体系结构应用层常用协议及其相应的运输层协议 TCP协议是面向连接可靠数据传输服务&#xff0c;UDP无连接不可靠的数据传输服务&#xff0c;IP无连接不可靠的数据连接服务。 FTP协议&#xff0c;SMTP协议和HTTP协议使用TCP协议提供的面…

SaaS架构:中央库存系统架构设计

大家好&#xff0c;我是汤师爷~ 近年来&#xff0c;越来越多的零售企业大力发展全渠道业务。在销售额增长上&#xff0c;通过线上的小程序、直播、平台渠道等方式&#xff0c;拓展流量变现渠道。在会员增长方面&#xff0c;通过多样的互动方式&#xff0c;全渠道触达消费者&am…

Power BI - 设置Waterfall Chart第一个Pillar的颜色

1.简单介绍 有的用户可能会单独设置Column Chart&#xff08;条形图&#xff09;的第一个柱子的颜色&#xff0c;如下图所示&#xff0c; 这种其实可以通过Column Chart的Conditional formating进行设置&#xff0c; - SWICH SELECTEDVALUE 或者也可以直接对单独的Column进行…