openssl-AES-128-CTR加解密结构体

news2024/11/15 12:21:28

源码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/rand.h>

#define length 1024

typedef struct {
    char id[length];
    char pwd[length];
    int age;
    int number;
} info;

void handleErrors(void) {
    fprintf(stderr, "An error occurred.\n");
    //abort();
    exit(1);
}

// Serialize the structure into a byte array
void serialize(info *data, unsigned char *buffer) {
    size_t id_len = strlen(data->id) + 1;
    size_t pwd_len = strlen(data->pwd) + 1;
    memcpy(buffer, &id_len, sizeof(size_t));
    memcpy(buffer + sizeof(size_t), data->id, id_len);
    memcpy(buffer + sizeof(size_t) + id_len, &pwd_len, sizeof(size_t));
    memcpy(buffer + 2 * sizeof(size_t) + id_len, data->pwd, pwd_len);
    memcpy(buffer + 2 * sizeof(size_t) + id_len + pwd_len, &data->age, sizeof(data->age));
    memcpy(buffer + 2 * sizeof(size_t) + id_len + pwd_len + sizeof(data->age), &data->number, sizeof(data->number));
}

// Deserialize the byte array back into the structure
void deserialize(unsigned char *buffer, info *data) {
    size_t id_len, pwd_len;
    memcpy(&id_len, buffer, sizeof(size_t));
    memcpy(data->id, buffer + sizeof(size_t), id_len);
    data->id[id_len - 1] = '\0'; // Ensure null-termination

    memcpy(&pwd_len, buffer + sizeof(size_t) + id_len, sizeof(size_t));
    memcpy(data->pwd, buffer + 2 * sizeof(size_t) + id_len, pwd_len);
    data->pwd[pwd_len - 1] = '\0'; // Ensure null-termination

    memcpy(&data->age, buffer + 2 * sizeof(size_t) + id_len + pwd_len, sizeof(data->age));
    memcpy(&data->number, buffer + 2 * sizeof(size_t) + id_len + pwd_len + sizeof(data->age), sizeof(data->number));
}

int main() {
    info config = {
        .id = "ags",
        .pwd = "asg",
        .age = 25,
        .number = 12345
    };

    unsigned char key[AES_BLOCK_SIZE];
    unsigned char iv[AES_BLOCK_SIZE];
    unsigned char buffer[sizeof(config)];
    unsigned char enc_out[sizeof(config)];
    unsigned char dec_out[sizeof(config)];
    int len, enc_len;

    if (!RAND_bytes(key, sizeof(key)) || !RAND_bytes(iv, sizeof(iv))) {
        handleErrors();
    }

    // Serialize
    serialize(&config, buffer);

    // Encrypt
    EVP_CIPHER_CTX *ctx;
    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, enc_out, &enc_len, buffer, sizeof(config))) handleErrors();
    len = enc_len;
    if (1 != EVP_EncryptFinal_ex(ctx, enc_out + enc_len, &enc_len)) handleErrors();
    len += enc_len;
    EVP_CIPHER_CTX_free(ctx);

    // Write encrypted data to file
    FILE *fencrypt = fopen("configEncrypt.bin", "wb");
    if (!fencrypt) handleErrors();
    fwrite(enc_out, 1, len, fencrypt);
    fclose(fencrypt);

    // Decrypt
    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, dec_out, &enc_len, enc_out, len)) handleErrors();
    len = enc_len;
    if (1 != EVP_DecryptFinal_ex(ctx, dec_out + enc_len, &enc_len)) handleErrors();
    len += enc_len;
    EVP_CIPHER_CTX_free(ctx);

    // Deserialize
    info decrypted_config;
    deserialize(dec_out, &decrypted_config);

    // Write decrypted data to file
    FILE *fdecrypt = fopen("configDecrypt.txt", "w");
    if (!fdecrypt) handleErrors();
    fprintf(fdecrypt, "ID: %s\n", decrypted_config.id);
    fprintf(fdecrypt, "Password: %s\n", decrypted_config.pwd);
    fprintf(fdecrypt, "Age: %d\n", decrypted_config.age);
    fprintf(fdecrypt, "Number: %d\n", decrypted_config.number);
    fclose(fdecrypt);

    // Read and print decrypted data from file
    // FILE *fread = fopen("configDecrypt.txt", "r");
    // if (!fread) handleErrors();
    // char line[1024];
    // while (fgets(line, sizeof(line), fread)) {
    //     printf("%s", line);
    // }
    // fclose(fread);

    return 0;
}

错误处理函数

void handleErrors(void) {
    fprintf(stderr, "An error occurred.\n");
    //abort();
    exit(1);
}

abort()和exit()都是stdlib库中的函数,这两个函数的功能都有很多相似之处,都是用于退出程序的函数,然而细细追查其中也是有着不小的差别的,以下是这两种方法的主要区别:

使用 exit(1);

  • exit 函数请求程序终止,并可以指定一个退出状态码,通常用于指示程序是正常结束还是由于错误而结束。
  • exit 被调用时,它会触发几个清理操作:
    • 刷新并关闭所有打开的文件流(stdio流)。
    • 调用所有注册的 atexit() 函数。
    • 释放分配的资源,如内存。
    • 终止进程。
  • 它提供了一种优雅的方式退出程序,允许程序在退出前进行必要的清理工作。

使用 abort();

  • abort 函数立即终止程序,并向操作系统报告一个异常终止信号(通常是 SIGABRT)。
  • abort 被调用时,它不会执行任何清理操作,如关闭文件流或调用 atexit() 注册的函数。
  • 它通常用于指示程序遇到了严重错误,无法正常退出。
  • abort 会导致操作系统生成一个核心转储文件(core dump),如果操作系统配置了核心转储,这可以用于后续的调试和分析。

区别总结

  • 清理操作exit 执行清理操作,而 abort 不会。
  • 退出状态exit 允许你指定一个退出状态码,而 abort 通常不提供这个功能。
  • 调试abort 可能会生成核心转储文件,有助于调试,而 exit 不会。
  • 使用场景exit 用于正常的程序退出或错误退出,而 abort 用于遇到严重错误,需要立即终止程序的情况。

序列化函数

序列化是将程序中的数据结构或对象状态转换成可以存储或传输的格式的过程。在C语言中,序列化通常意味着将结构体中的字段按一定顺序转换成字节流。在提供的代码中,serialize 函数将 info 结构体的内容序列化到一个字节缓冲区。以下是序列化过程的详细分析:

序列化函数
buffer只有config的大小,那么其实在序列化时却将ID的长度和pwd的长度数据也写入到了buffer,那么如果id和pwd刚好用完了自己的内存,没有多的给ID的长度和pwd的长度数据就会出现数据越界。

#define length 4
typedef struct {
    char id[length];
    char pwd[length];
    int age;
    int number;
} info;
info config = {
        .id = "agsd",
        .pwd = "asgg",
        .age = 25,
        .number = 12345
    };

这种情况我们只能尽可能的多开辟空间。
在这里插入图片描述

unsigned char buffer[sizeof(config)];
void serialize(info *data, unsigned char *buffer) {
    size_t id_len = strlen(data->id) + 1; // 计算ID的长度,包括空字符'\0'
    size_t pwd_len = strlen(data->pwd) + 1; // 计算密码的长度,包括空字符'\0'

    // 将ID的长度复制到缓冲区
    memcpy(buffer, &id_len, sizeof(size_t));
    // 将ID复制到缓冲区,紧接着ID长度之后
    memcpy(buffer + sizeof(size_t), data->id, id_len);
    // 将密码的长度复制到缓冲区,紧接着ID之后
    memcpy(buffer + sizeof(size_t) + id_len, &pwd_len, sizeof(size_t));
    // 将密码复制到缓冲区,紧接着密码长度之后
    memcpy(buffer + 2 * sizeof(size_t) + id_len, data->pwd, pwd_len);
    // 将年龄复制到缓冲区,紧接着密码之后
    memcpy(buffer + 2 * sizeof(size_t) + id_len + pwd_len, &data->age, sizeof(data->age));
    // 将编号复制到缓冲区,紧接着年龄之后
    memcpy(buffer + 2 * sizeof(size_t) + id_len + pwd_len + sizeof(data->age), &data->number, sizeof(data->number));
}

序列化步骤

  1. 计算长度

    • id_lenpwd_len 分别计算 data->iddata->pwd 的长度,包括字符串末尾的空字符 \0
  2. 复制长度

    • 使用 memcpy 函数将 id_lenpwd_len 的值复制到 buffer 的开始位置。memcpy 函数的第一个参数是目标地址,第二个参数是源地址,第三个参数是要复制的字节数。
  3. 复制字符串

    • 紧接着长度信息之后,使用 memcpydata->iddata->pwd 的内容复制到 buffer 中。字符串的复制包括了字符串的长度和空字符。
  4. 复制数值

    • data->agedata->number 的值复制到 buffer 中,它们紧跟在字符串之后。这些是整数值,所以直接使用 memcpy 复制它们的内存表示。

反序列化函数

这段代码是 deserialize 函数的实现,它的作用是将序列化后的数据(存储在 buffer 中)反序列化回 info 结构体。这个过程是 serialize 函数的逆过程,用于从字节流中恢复原始数据结构。以下是对这段代码的详细解释:

void deserialize(unsigned char *buffer, info *data) {
    size_t id_len, pwd_len;
    memcpy(&id_len, buffer, sizeof(size_t));
    memcpy(data->id, buffer + sizeof(size_t), id_len);
    data->id[id_len - 1] = '\0'; // Ensure null-termination

    memcpy(&pwd_len, buffer + sizeof(size_t) + id_len, sizeof(size_t));
    memcpy(data->pwd, buffer + 2 * sizeof(size_t) + id_len, pwd_len);
    data->pwd[pwd_len - 1] = '\0'; // Ensure null-termination

    memcpy(&data->age, buffer + 2 * sizeof(size_t) + id_len + pwd_len, sizeof(data->age));
    memcpy(&data->number, buffer + 2 * sizeof(size_t) + id_len + pwd_len + sizeof(data->age), sizeof(data->number));
}

函数定义

void deserialize(unsigned char *buffer, info *data) {
    size_t id_len, pwd_len;
  • buffer:指向包含序列化数据的字节缓冲区的指针。
  • data:指向 info 结构体的指针,该结构体将存储反序列化的数据。

读取并存储长度信息

    memcpy(&id_len, buffer, sizeof(size_t));
    memcpy(&pwd_len, buffer + sizeof(size_t) + id_len, sizeof(size_t));
  • 使用 memcpy 函数从 buffer 中复制 size_t 大小的数据到 id_lenpwd_len 变量中。这些变量存储了 idpwd 字段的长度,包括字符串的空字符。

读取并存储字符串数据

    memcpy(data->id, buffer + sizeof(size_t), id_len);
    data->id[id_len - 1] = '\0'; // Ensure null-termination

    memcpy(data->pwd, buffer + 2 * sizeof(size_t) + id_len, pwd_len);
    data->pwd[pwd_len - 1] = '\0'; // Ensure null-termination
  • 再次使用 memcpyidpwd 的数据从 buffer 复制到 data 结构体中。注意,字符串数据紧跟在它们的长度信息之后。
  • 为了确保字符串正确终止,将最后一个字符设置为 null 字符('\0')。这是必要的,因为 C 字符串以 null 字符结束。

读取并存储数值数据

    memcpy(&data->age, buffer + 2 * sizeof(size_t) + id_len + pwd_len, sizeof(data->age));
    memcpy(&data->number, buffer + 2 * sizeof(size_t) + id_len + pwd_len + sizeof(data->age), sizeof(data->number));
  • 使用 memcpyagenumber 的数据从 buffer 复制到 data 结构体中。这些数据紧跟在 pwd 字符串之后。

加密函数

EVP_CIPHER_CTX *ctx;
    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, enc_out, &enc_len, buffer, sizeof(config))) handleErrors();
    len = enc_len;
    if (1 != EVP_EncryptFinal_ex(ctx, enc_out + enc_len, &enc_len)) handleErrors();
    len += enc_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, dec_out, &enc_len, enc_out, len)) handleErrors();
    len = enc_len;
    if (1 != EVP_DecryptFinal_ex(ctx, dec_out + enc_len, &enc_len)) handleErrors();
    len += enc_len;
    EVP_CIPHER_CTX_free(ctx);

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

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

相关文章

Kubelet 核心指标监控

How to Monitor the Kubelet | Sysdig Kubernetes / Kubelet | Grafana Labs https://github.com/flashcatcloud/categraf/blob/main/inputs/kubelet/dashboard-by-ident.json 在生产环境中运行 Kubernetes 时&#xff0c;监控 Kubelet 至关重要。Kubelet 是 Kubernetes 集群…

自制网络连接工具(支持tcpudp,客户端服务端)

自制网络连接工具&#xff08;支持tcp/udp,客户端/服务端&#xff09; 将网络连接工具制作成共享库 network.h #ifndef NETWORK_H #define NETWORK_H#include<netinet/in.h> #include<sys/socket.h> #include<stdbool.h> typedef struct Network {int type…

AI是否会带来一场认知革命?Reid Hoffman 的独特见解

随着人工智能&#xff08;AI&#xff09;技术的迅猛发展&#xff0c;关于AI对人类社会及认知的影响&#xff0c;已经成为了学术界和业界热议的话题。硅谷著名投资人、LinkedIn联合创始人Reid Hoffman&#xff0c;在斯坦福大学的演讲中分享了他对AI的深刻看法。他认为&#xff0…

系统优化工具 | Windows Manager v2.0.5 便携版

Windows Manager 是一款专为Microsoft Windows 10/11设计的系统优化和管理软件。它集成了多种实用程序&#xff0c;旨在帮助用户更好地管理和优化Windows操作系统。该软件的功能包括系统清理、系统优化、系统修复、硬件信息查看和系统设置调整等。 系统清理&#xff1a;Window…

队列基础概念

文章目录 &#x1f34a;自我介绍&#x1f34a;现实生活中的例子&#x1f34a;队列的介绍&#x1f34a;循环队列&#x1f34a;小结 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以&#xff1a;点赞关注评论收藏&#xff08;一键四连&#xff09;哦~ &#x1f34a;自我介…

简明linux系统编程--互斥锁--TCP--UDP初识

目录 1.互斥锁 2.信号 2.1介绍 2.2信号的内核机制 3.linux网络编程概述 3.1一览七层协议 3.2一览数据传输过程 3.3四层网络模型 3.4服务端和客户端的数据交互 4.TCP服务端编程 5.TCP客户端编程 6.UDP服务端编程 7.UDP客户端编程 1.互斥锁 互斥锁也是和信号量一样&a…

我与Linux的爱恋:命令行参数|环境变量

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;Linux的学习 文章目录 一.命令行参数二.环境变量1.环境变量的基本概念2.查看环境变量的方法3.环境变量相关命令 一.命令行参数 【示例1】main函数也是函数&#xff0c;main函数可以带参…

Paragon NTFS for Mac和Tuxera NTFS for Mac,那么两种工具有什么区别呢?

我们在使用Mac系统读取U盘的过程中往往会遇到一个问题&#xff0c;那就是U盘插进电脑无法显示&#xff0c;或者只能读取不能编辑。出现这种情况的原因就一般是格式错误。 很多小伙伴在解决这种问题的时候会选择使用U盘读写工具&#xff0c;那么哪一种读写工具比较好呢&#xf…

Windows下利用MSYS2和VS的nmake编译nginx源码

目录 一、使用说明 二、安装软件 2.1 下载依赖库 2.3 下载并安装 StrawberryPerl 2.4 下载并安装 MSYS 2 2.5 nginx源代码下载 三、编译配置 3.1 设置NGX_MSVC_VER 3.2 配置 Makefile 3.3 编译代码 3.4 整理Nginx发布环境 四、错误处理 一、使用说明 本文章主要记…

Hash入门

unordered_set void test_unordered_set() {unordered_set<int> us;us.insert(4);us.insert(2);us.insert(1);us.insert(5);us.insert(6);us.insert(2);us.insert(2);//去重unordered_set<int>::iterator it us.begin();while (it ! us.end()){cout << *it…

​OpenAI最强模型o1系列:开启人工智能推理新时代

前不久OpenAI发布全新模型——o1模型&#xff0c;也就是业界说的“草莓模型”&#xff0c;包含三款型号&#xff1a;OpenAI o1、OpenAI o1-preview和OpenAI o1-mini。 其中&#xff0c;OpenAI o1-mini和 o1-preview已经对用户开放使用&#xff1a; OpenAI o1&#xff1a;高级推…

mysql笔记—sql性能分析

1.查看数据库各个语句的执行频次 show global/session status like ‘com__’ 2.慢查询 默认没有开启&#xff0c;需要手动开启&#xff08;在/etc/my.cnf中开启&#xff09; 开启后在localhost-slow.log中可以查询到慢查询的语句的相关信息&#xff1a; 3.explain 用法&…

<<编码>> 第 16 章 存储器组织(1)--比特锁存器 示例电路

1 比特锁存器 info::操作说明 鼠标单击逻辑输入切换 0|1 状态 就是前面的电平触发的 D 型锁存器. 写入(Write) 就是时钟信号 primary::在线交互操作链接 https://cc.xiaogd.net/?startCircuitLinkhttps://book.xiaogd.net/code-hlchs-examples/assets/circuit/code-hlchs-ch16…

2025年最新大数据毕业设计选题-Hadoop综合项目

选题思路 回忆学过的知识(Python、Java、Hadoop、Hive、Sqoop、Spark、算法等等。。。) 结合学过的知识确定大的方向 a. 确定技术方向&#xff0c;比如基于Hadoop、基于Hive、基于Spark 等等。。。 b. 确定业务方向&#xff0c;比如民宿分析、电商行为分析、天气分析等等。。。…

OpenCV特征检测(6)对初步检测到的角点位置进行亚像素级别的精炼函数cornerSubPix()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 细化角点的位置。 该函数迭代以找到角点或径向鞍点的亚像素级准确位置&#xff0c;如 93中所述&#xff0c;并如下图所示。 亚像素级准确的角点…

TryHackMe 第2天 | Pre Security (上)

该学习路径讲解了网络安全入门的必备技术知识&#xff0c;比如计算机网络、网络协议、Linux命令、Windows设置等内容。本篇博客将记录第一项&#xff1a;计算机网络。 Network Fundamentals What is networking? 网络就是相互连接的事物&#xff0c;我们的人际关系也可以抽…

Liveweb视频汇聚平台支持GB28181转RTMP、HLS、RTSP、FLV格式播放方案

GB28181协议凭借其在安防流媒体行业独有的大统一地位&#xff0c;目前已经在各种安防项目上使用。雪亮工程、幼儿园监控、智慧工地、物流监控等等项目上目前都需要接入安防摄像头或平台进行直播、回放。而GB28181协议作为国家推荐标准&#xff0c;目前基本所有厂家的安防摄像头…

[Unity Demo]从零开始制作空洞骑士Hollow Knight第六集:制作小骑士完整的跳跃落地行为

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、制作一个完整的小骑士跳跃落地行为 1.制作动画以及UNITY编辑器编辑2.使用代码实现完整的跳跃落地行为控制3.更多要考虑到的点总结 前言 大家好久不见&…

【CSS Tricks】如何做一个粒子效果的logo

效果展示 代码展示 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>粒子效果Logo</title>…

VUE面试题(单页应用及其首屏加载速度慢的问题)

目录 一、单页应用 1.概念 2.单页面应用的优缺点 二、多页面应用&#xff1a; 1.概念 2.区别 三、SPA的实现 1.原理 2.方式&#xff1a; 3.Hash与History模式有什么区别 四、首屏加载速度慢如何优化 1.什么是首屏加载&#xff1f; 2.首屏加载慢的原因 3.如何解决…