openssl-AES-128-CTR加解密char型数组分析
本文章通过对一个unsigned char*类型的数据做简单的加解密操作来学习如何使用openssl库函数。
openssl为3.0.0,对此前版本的很多函数都不兼容。
加解密源码
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>
#include <openssl/rand.h>
#include <openssl/aes.h>
#include <stdlib.h>void handleErrors(void) {ERR_print_errors_fp(stderr);abort();
}int main() {ERR_load_crypto_strings();OpenSSL_add_all_algorithms();// 密钥和初始化向量unsigned char key[AES_BLOCK_SIZE];unsigned char iv[AES_BLOCK_SIZE];// 随机生成密钥和初始化向量RAND_bytes(key, sizeof(key));RAND_bytes(iv, sizeof(iv));// 要加密的数据unsigned char plaintext[] = "The quick brown fox jumps over the lazy dog";// 加密后的数据unsigned char ciphertext[sizeof(plaintext)];// 解密后的数据unsigned char decryptedtext[sizeof(plaintext)];// 创建并初始化加解密上下文EVP_CIPHER_CTX *ctx;int len;// 初始化加密上下文if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();// 初始化加密操作if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, key, iv)) handleErrors();// 执行加密操作if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, sizeof(plaintext))) handleErrors();EVP_EncryptFinal_ex(ctx, ciphertext + len, &len);// 清理加密上下文EVP_CIPHER_CTX_free(ctx);// 初始化解密上下文if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();// 初始化解密操作if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, key, iv)) handleErrors();// 执行解密操作if (1 != EVP_DecryptUpdate(ctx, decryptedtext, &len, ciphertext, sizeof(ciphertext))) handleErrors();EVP_DecryptFinal_ex(ctx, decryptedtext + len, &len);// 清理解密上下文EVP_CIPHER_CTX_free(ctx);// 打印解密后的数据printf("Decrypted text: %s\n", decryptedtext);// 清理 OpenSSLERR_free_strings();return 0;
}
运行脚本
#!/bin/bash
gcc aesctr.c -o aesctr -lcrypto
./aesctr
输出的数据与加密前的数据一样,当然这只是加密字符串可以如此简单,但是如果数据是结构体呢?
代码整体分析
这段代码是一个使用 OpenSSL 库进行 AES-128-CTR 模式加密和解密的 C 程序。下面是代码的详细解析:
-
包含头文件:
<openssl/evp.h>
:提供加密算法的封装。<openssl/err.h>
:提供错误处理功能。<openssl/rand.h>
:提供随机数生成功能。<openssl/aes.h>
:提供 AES 加密算法的函数。<stdlib.h>
:提供标准库函数,如abort()
。
-
错误处理函数:
handleErrors
:当遇到错误时,打印错误信息并终止程序。
-
主函数
main
:ERR_load_crypto_strings
:加载错误字符串,以便ERR_print_errors_fp
函数可以打印出可读的错误信息。OpenSSL_add_all_algorithms
:注册所有 OpenSSL 加密算法。
-
密钥和初始化向量:
unsigned char key[AES_BLOCK_SIZE]
:定义一个 128 位(16 字节)的密钥数组。unsigned char iv[AES_BLOCK_SIZE]
:定义一个 128 位(16 字节)的初始化向量(IV)数组。
-
生成密钥和 IV:
RAND_bytes(key, sizeof(key))
:生成随机密钥。RAND_bytes(iv, sizeof(iv))
:生成随机 IV。
-
定义数据:
unsigned char plaintext[]
:定义要加密的明文数据。unsigned char ciphertext[sizeof(plaintext)]
:定义存储加密后数据的数组。unsigned char decryptedtext[sizeof(plaintext)]
:定义存储解密后数据的数组。
-
加密和解密上下文:
EVP_CIPHER_CTX *ctx
:定义一个加密上下文指针,用于存储加密和解密过程中的状态信息。
-
加密过程:
EVP_CIPHER_CTX_new
:创建一个新的加密上下文。EVP_EncryptInit_ex
:初始化加密操作,设置加密算法为 AES-128-CTR,使用密钥和 IV。EVP_EncryptUpdate
:执行加密操作,将明文数据加密到ciphertext
数组中。EVP_EncryptFinal_ex
:完成加密操作,处理任何剩余的数据。
-
解密过程:
- 与加密过程类似,但使用
EVP_DecryptInit_ex
、EVP_DecryptUpdate
和EVP_DecryptFinal_ex
函数进行解密。
- 与加密过程类似,但使用
-
打印解密后的数据:
printf
:打印解密后的文本。
-
清理 OpenSSL:
ERR_free_strings
:释放加载的错误字符串。
-
返回:
return 0
:程序正常退出。
这个程序演示了如何使用 OpenSSL 库进行 AES-128-CTR 模式的加密和解密。它首先生成随机的密钥和 IV,然后使用这些密钥和 IV 对明文数据进行加密,最后使用相同的密钥和 IV 对密文数据进行解密,以验证加密和解密过程的正确性。
EVP_CIPHER_CTX_new()初始化加密上下文
EVP_CIPHER_CTX_new
是 OpenSSL 库中的一个函数,用于创建一个新的加密上下文(EVP_CIPHER_CTX
)。这个上下文用于存储加密或解密操作的状态,包括算法特定的信息、密钥、初始化向量(IV)、加密模式等。
函数原型如下:
EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void);
这个函数不接受任何参数,并返回一个指向新创建的 EVP_CIPHER_CTX
结构的指针。如果内存分配失败,将返回 NULL
。
EVP_EncryptInit_ex加密初始化
EVP_EncryptInit_ex
是 OpenSSL 库中的一个函数,用于初始化加密操作。这个函数是加密过程中的第一步,它准备加密上下文(EVP_CIPHER_CTX
)以便后续的加密操作。这个函数非常灵活,可以用于多种不同的加密算法和模式。
函数原型如下:
int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv);
参数说明:
ctx
:指向EVP_CIPHER_CTX
结构的指针,这个结构用于存储加密过程中的状态信息。cipher
:指向EVP_CIPHER
结构的指针,这个结构指定了要使用的加密算法和模式。impl
:指向ENGINE
结构的指针,用于指定加密操作可能使用的硬件加速引擎。如果为NULL
,则使用默认的软件实现。key
:指向密钥的指针。密钥的长度和格式取决于所选的加密算法。iv
:指向初始化向量的指针。初始化向量用于某些加密模式(如 CBC、CTR 等),以确保即使相同的明文也不会产生相同的密文。如果加密模式不需要 IV,这个参数可以为NULL
。
返回值:
- 成功时返回
1
。 - 失败时返回
0
,并可通过ERR_get_error
函数获取错误信息。
EVP_EncryptUpdate执行加密操作
EVP_EncryptUpdate
是 OpenSSL 库中的一个函数,用于执行加密操作的中间步骤。这个函数用于处理要加密的数据块,通常在初始化加密操作(使用 EVP_EncryptInit_ex
)之后和完成加密操作(使用 EVP_EncryptFinal_ex
)之前调用。
函数原型如下:
int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl);
参数说明:
ctx
:指向之前通过EVP_EncryptInit_ex
初始化的EVP_CIPHER_CTX
结构的指针。out
:指向用于存储加密数据的缓冲区的指针。加密的数据将被写入这个缓冲区。outl
:一个整数指针,用于在输入时指定out
缓冲区的大小,并在输出时存储实际写入out
缓冲区的数据大小。in
:指向要加密的数据的指针。inl
:指定in
指向的数据的大小(以字节为单位)。
返回值:
- 成功时返回
1
。 - 失败时返回
0
,并可通过ERR_get_error
函数获取错误信息。
EVP_EncryptFinal_ex完成剩余加密操作
EVP_EncryptFinal_ex
是 OpenSSL 库中的一个函数,它用于完成加密操作。在调用 EVP_EncryptUpdate
处理完所有要加密的数据后,你会调用这个函数来完成加密过程,它会处理任何剩余的数据块并确保加密过程正确结束。
函数原型如下:
int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
参数说明:
ctx
:指向之前通过EVP_EncryptInit_ex
和EVP_EncryptUpdate
进行初始化和更新的EVP_CIPHER_CTX
结构的指针。out
:指向用于存储最后一部分加密数据的缓冲区的指针。如果加密算法在最后需要填充(如块加密模式),填充的数据也会被写入这个缓冲区。outl
:一个整数指针,用于在输入时指定out
缓冲区的大小,并在输出时存储实际写入out
缓冲区的数据大小。
返回值:
- 成功时返回
1
。 - 失败时返回
0
,并可通过ERR_get_error
函数获取错误信息。
EVP_CIPHER_CTX_free释放初始化上下文
EVP_CIPHER_CTX_free
是 OpenSSL 库中的一个函数,用于释放之前通过 EVP_CIPHER_CTX_new
创建的加密上下文(EVP_CIPHER_CTX
)所占用的内存资源。这个函数是管理 OpenSSL 加密操作中内存使用的重要部分,确保在完成加密或解密操作后,及时释放分配的内存,避免内存泄漏。
函数原型如下:
void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx);
参数说明:
ctx
:指向EVP_CIPHER_CTX
结构的指针。这个结构是在之前通过EVP_CIPHER_CTX_new
创建的,用于存储加密或解密操作的状态和参数。
解密
解密与加密差不多
// 初始化解密上下文if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();// 初始化解密操作if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, key, iv)) handleErrors();// 执行解密操作if (1 != EVP_DecryptUpdate(ctx, decryptedtext, &len, ciphertext, sizeof(ciphertext))) handleErrors();EVP_DecryptFinal_ex(ctx, decryptedtext + len, &len);// 清理解密上下文EVP_CIPHER_CTX_free(ctx);
错误处理函数
您提供的代码是一个简单的错误处理函数,通常用于 OpenSSL 或其他需要处理错误堆栈的库。这个函数的作用是打印错误信息到标准错误输出(stderr
),然后终止程序。下面是对这段代码的详细解释:
-
ERR_print_errors_fp(stderr);
- 这行代码调用
ERR_print_errors_fp
函数,该函数是 OpenSSL 库中的一个函数,用于打印错误信息。 stderr
是标准错误输出流,它用于输出错误信息和调试信息。- 这个函数会打印出所有未被处理的错误到
stderr
。
- 这行代码调用
-
abort();
- 这行代码调用
abort
函数,该函数是 C 标准库中的一个函数,用于立即终止程序。 - 当
abort
被调用时,它会生成一个SIGABRT
信号,如果没有捕获该信号的信号处理函数,程序将被终止。
- 这行代码调用
这个错误处理函数通常在 OpenSSL 函数调用失败时调用,以确保程序在遇到错误时能够优雅地终止,并提供足够的错误信息供调试使用。
相关文章:

openssl-AES-128-CTR加解密char型数组分析
本文章通过对一个unsigned char*类型的数据做简单的加解密操作来学习如何使用openssl库函数。 openssl为3.0.0,对此前版本的很多函数都不兼容。 加解密源码 #include <openssl/evp.h> #include <openssl/err.h> #include <string.h> #include …...
自动化生成与更新 Changelog 文件
在软件开发中,保持 Changelog 文件的更新是一项至关重要的任务。 Changelog 文件记录了项目的每一个重要变更,包括新功能、修复的问题以及任何可能破坏现有功能的变更。对于维护者、贡献者和最终用户来说,这都是一个宝贵的资源。然而&#x…...
(六)WebAPI方法的调用
1.WebAPI中定义的GET、POST方法 [HttpGet(Name "GetWeatherForecast")]public IEnumerable<WeatherForecast> Get(){return Enumerable.Range(1, 5).Select(index > new WeatherForecast{Date DateTime.Now.AddDays(index),TemperatureC Random.Shared.N…...
运维工程师面试整理-故障排查常见故障的排查步骤及方法
故障排查是运维工程师的重要技能之一。在面试中,面试官通常会通过故障排查相关的问题来评估你解决问题的能力和系统思维。以下是关于常见故障的排查步骤及方法的详细内容,帮助你更好地准备面试。 1. 故障排查的基本步骤 1. 问题识别 a. 描述问题:明确问题的具体表现...

OpenAI o1解决了「Quiet-STaR」的挑战吗?
随着OpenAI o1近期的发布,业界讨论o1关联论文最多之一可能是早前这篇斯坦福大学和Notbad AI Inc的研究人员开发的Quiet-STaR,即让AI学会先安静的“思考”再“说话” ,回想自己一年前对于这一领域的思考和探索,当初也将这篇论文进行…...

PDF产品册营销推广利器FLBOOK
在互联网高速发展的时代,营销推广已成为企业拓展市场的重要手段。而一款优秀的营销工具,可以为企业带来事半功倍的推广效果。今天,就为大家介绍一款集创意与实用于一体的PDF产品册营销推广利器——FLBOOK,帮助企业轻松提升品牌影响…...

华为OD机试 - 字符串划分(Python/JS/C/C++ 2024 E卷 100分)
华为OD机试 2024E卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试真题(Python/JS/C/C)》。 刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,…...
nginx和php-fpm连接超时的相关配置以及Nginx中的try_files以及root、alias的使用
一、nginx和php-fpm连接超时的相关配置 线上的PHP服务器架构大都是nginx proxy->nginx web->php-fpm。在服务器运行正常,服务器之间的连接正常,未被防火墙阻止的情况下,对这种架构排查504报错时需要注意以下几个地方的参数。 1是nginx…...

在MAC中Ollama开放其他电脑访问
ollama安装完毕后默认只能在本地访问,之前我都是安装其他的软件之后可以结合开放其他端口访问,其实是可以新增或修改下电脑的系统配置,就可以打开端口允许除本机IP或localhost访问。 步骤如下: 1、查看端口(默认是&…...

NE555芯片制作的节拍器
NE555芯片的节拍器,以一定的频率发出声音和闪烁灯光,起到节拍指示的作用。...
如何使用 Next.js 进行服务端渲染(Server-Side Rendering, SSR)
文章目录 前言步骤 1: 创建 Next.js 应用步骤 2: 创建页面组件示例页面组件 步骤 3: 自定义 _app.js 文件步骤 4: 自定义 _document.js 文件步骤 5: 运行应用步骤 6: 构建和部署总结 前言 Next.js 本身就支持 SSR 并提供了一系列内置的方法来简化这个过程。下面将详细介绍如何使…...

【machine learning-八-可视化loss funciton】
可视化lossfunction loss funciton可视化损失函数等高图 loss funciton 上一节讲过损失函数,也就是代价函数,它是衡量模型训练好坏的指标,对于线性回归来说,模型、参数、损失函数以及目标如下:、 损失函数的目标当然…...
Android 将EasyPermissions进一步封装,使得动态权限申请更加简明
1.引入依赖: implementation pub.devrel:easypermissions:3.0.0 2.在BaseActivity处理统一的结果回调和请求Code 核心内容: (1)处理Activity本身继承的方法onRequestPermissionsResult (2)实现接口EasyPermissions.PermissionCallbacks来接收请求结果 (3)定义申请权…...

我的AI工具箱Tauri版-VideoReapeat视频解说复述克隆
本教程基于自研的AI工具箱Tauri版进行VideoReapeat视频解说复述克隆。 VideoReapeat视频解说复述克隆 是自研的AI工具箱Tauri版中的一款专用模块,旨在通过AI技术对视频解说内容进行复述和克隆。该工具可自动洗稿并重新生成视频解说,通过简单配置即可对大…...

MySQL5.7.42高可用MHA搭建及故障切换演示
系列文章目录 rpmbuild构建mysql5.7RPM安装包 MySQL基于GTID同步模式搭建主从复制 文章目录 系列文章目录前言一、MHA架构介绍1.MHA的功能2.MHA组成3.MHA故障转移过程4.MHA架构优缺点 二、环境准备1.服务器免密2.基于GTID主从复制搭建3.下载mha组件 三、MHA组件安装1.安装依赖…...

快速搭建最简单的前端项目vue+View UI Plus
1 引言 Vue是一套用于构建Web前端界面的渐进式JavaScript框架。它以其易学易用、性能出色、灵活多变而深受开发者喜爱,并且与其他前端框架(如React和Angular)相比,在国内市场上受到了广泛的认可和使用。点击进入官方…...

倍增练习(1)
A - ST 表 && RMQ 问题 题目思路:st表的板子题用于静态区间求最值,通过倍增的思想,先通过预处理将各个区间的最大值通过转移式求出f[i][j] max(f[i][j - 1], f[i (1 << (j - 1))][j - 1]);然后再进行重叠查询查询,k log2(r - l 1);,max(f[l][k], f[r - (1 &l…...

MATLAB 在数学建模中的深入应用:从基础到高级实践
目录 前言 一、MATLAB基础知识 1.1 MATLAB工作环境简介 1.1.1 命令窗口(Command Window) 1.1.2 工作区(Workspace) 1.1.3 命令历史(Command History) 1.1.4 编辑器(Editor) 1…...

Unity 设计模式 之 【什么是设计模式】/ 【为什么要使用设计模式】/ 【架构和设计模式的区别】
Unity 设计模式 之 【什么是设计模式】/ 【为什么要使用设计模式】/ 【架构和设计模式的区别】 目录 Unity 设计模式 之 【什么是设计模式】/ 【为什么要使用设计模式】/ 【架构和设计模式的区别】 一、简单介绍 二、 Unity 设计模式 1、Unity 开发中使用设计模式的特点 2…...

[数据集][目标检测]智慧交通铁路异物入侵检测数据集VOC+YOLO格式802张7类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):802 标注数量(xml文件个数):802 标注数量(txt文件个数):802 标注类别…...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...

Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...

DBLP数据库是什么?
DBLP(Digital Bibliography & Library Project)Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高,数据库文献更新速度很快,很好地反映了国际计算机科学学术研…...