Openssl-AES加密

2023-10-29

AES加密算法

此次介绍AES两种加密算法,其他的暂不使用

1、ECB模式
按照块密码的块大小被分为数个块,并对每个块进行独立加密。
  优点:
  1.简单;
  2.有利于并行计算;
  3.误差不会被传送;
  缺点:
  1.不能隐藏明文的模式;
  2.可能对明文进行主动攻击;
2、CBC模式:
每个平文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有平文块。同时,为了保证每条消息的唯一性,在第一个块中需要使用初始化向量。
  优点:
  1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
  缺点:
  1.不利于并行计算;
  2.误差传递;
  3.需要初始化向量IV

AES Padding

None // 不填充。
PKCS7 // 填充字符串由一个字节序列组成,每个字节填充该字节序列的长度。
Zeros // 填充字符串由设置为零的字节组成。
此处采用PKCS7进行填充
AES块大小为16,即以16字节为单位进行加密或解密,不足16字节是需要进行填充
假如当前有9个字节为[31 32 33 34 35 36 37 38 39],缺少7个字节,那么就需要填充7个字节的07
填充后就是[31 32 33 34 35 36 37 38 39 07 07 07 07 07 07 07]
需注意当为15个字节时,填充为01,但存在可能16个字节,最后一个字节加密为01(未证明过,可以查看openssl源码)
代码如下

std::shared_ptr<ByteBuffer> Aes::PKCS7Padding(const uint8_t *in, uint32_t inLen)
{
    std::shared_ptr<ByteBuffer> ptr(new ByteBuffer(in, inLen));
    uint8_t remainderSize = inLen % AES_BLOCK_SIZE;
    if (remainderSize == 0) {
        return ptr;
    }

    uint8_t buf[AES_BLOCK_SIZE] = {0};
    uint8_t paddingSize = AES_BLOCK_SIZE - remainderSize;

    memset(buf, paddingSize, paddingSize);	// memset是以一个字节为单位格式化
    if (ptr != nullptr) {
        ptr->append(buf, paddingSize);
    }

    return ptr;
}
使用Openssl AES进行加密和解密
// aes.h
#ifndef __CRYPTO_AES_H__
#define __CRYPTO_AES_H__

#include "crypto.h"
#include <utils/Buffer.h>
#include <openssl/aes.h>
#include <memory>

#define MAX_USER_KEY_SIZE 32
#define CBC_VECTOR_SIZE 16

namespace eular {
class Aes : public CryptoBase
{
public:
    enum KeyType {
        AES128 = 16,
        AES256 = 32,
    };

    enum EncodeType {
        AESECB = 0,
        AESCBC = 1,
    };

    Aes(const uint8_t *userKey, Aes::KeyType userKeytype, Aes::EncodeType encodeType);
    virtual ~Aes();

    bool reinit(const uint8_t *userKey, Aes::KeyType userKeytype, Aes::EncodeType encodeType);

    virtual int encode(uint8_t *out, const uint8_t *src, const uint32_t &srcLen);
    virtual int decode(uint8_t *out, const uint8_t *src, const uint32_t &srcLen);

protected:
    std::shared_ptr<ByteBuffer> PKCS7Padding(const uint8_t *in, uint32_t inLen);

protected:
    AES_KEY mAesKey;
    uint8_t mUserKey[MAX_USER_KEY_SIZE];
    uint8_t mUserKeyType;
    uint8_t mEncodeType;
    uint8_t vecForCBC[CBC_VECTOR_SIZE];
};

} // namespace eular

#endif // __CRYPTO_AES_H__
// aes.cpp
#include "aes.h"
#include <utils/Errors.h>
#include <utils/exception.h>
#include <utils/string8.h>
#include <log/log.h>

#define LOG_TAG "AES"

namespace eular {

Aes::Aes(const uint8_t *userKey, Aes::KeyType userKeytype, Aes::EncodeType encodeType)
{
    memset(mUserKey, 0, MAX_USER_KEY_SIZE);
    memset(vecForCBC, 0, CBC_VECTOR_SIZE);
    reinit(userKey, userKeytype, encodeType);
}

Aes::~Aes()
{

}

bool Aes::reinit(const uint8_t *userKey, Aes::KeyType userKeytype, Aes::EncodeType encodeType)
{
    switch (userKeytype) {
    case Aes::KeyType::AES128:
    case Aes::KeyType::AES256:
        break;
    default:
        throw(Exception(String8::format("Invalid AES Type: %d", userKeytype)));
        break;
    }
    memcpy(mUserKey, userKey, userKeytype);
    mUserKeyType = userKeytype;
    mEncodeType = encodeType;
}

int Aes::encode(uint8_t *out, const uint8_t *src, const uint32_t &srcLen)
{
    LOG_ASSERT(out || src || srcLen, "");
    std::shared_ptr<ByteBuffer> ptr = PKCS7Padding(src, srcLen);
    if (ptr == nullptr) {
        return NO_MEMORY;
    }

    AES_set_encrypt_key(mUserKey, mUserKeyType * 8, &mAesKey);
    if (mEncodeType == AESECB) {
        AES_ecb_encrypt(ptr->const_data(), out, &mAesKey, AES_ENCRYPT);
    } else if (mEncodeType == AESCBC) {
        memset(vecForCBC, 0, AES_BLOCK_SIZE);   // 加密和解密时初始vecForCBC内容须一致,一般设置为全0
        AES_cbc_encrypt(ptr->const_data(), out, ptr->size(), &mAesKey, vecForCBC, AES_ENCRYPT);
    }

    return ptr->size();
}

int Aes::decode(uint8_t *out, const uint8_t *src, const uint32_t &srcLen)
{
    LOG_ASSERT(out || src || srcLen, "");

    AES_set_decrypt_key(mUserKey, mUserKeyType * 8, &mAesKey);
    if (mEncodeType == AESECB) {
        AES_ecb_encrypt(src, out, &mAesKey, AES_DECRYPT);
    } else if (mEncodeType == AESCBC) {
        memset(vecForCBC, 0, AES_BLOCK_SIZE);
        AES_cbc_encrypt(src, out, srcLen, &mAesKey, vecForCBC, AES_DECRYPT);
    }

    uint8_t paddingSize = 0;
    if (out[srcLen - 1] == 0x1) {    // 填充了一个
        paddingSize = 0x1;
    } else if (out[srcLen - 1] == out[srcLen - 2]) {
        paddingSize = out[srcLen - 1];
    }

    out[srcLen - paddingSize] = '\0';
    return srcLen - paddingSize;
}

std::shared_ptr<ByteBuffer> Aes::PKCS7Padding(const uint8_t *in, uint32_t inLen)
{
    std::shared_ptr<ByteBuffer> ptr(new ByteBuffer(in, inLen));
    uint8_t remainderSize = inLen % AES_BLOCK_SIZE;
    if (remainderSize == 0) {
        return ptr;
    }

    uint8_t buf[AES_BLOCK_SIZE] = {0};
    uint8_t paddingSize = AES_BLOCK_SIZE - remainderSize;

    memset(buf, paddingSize, paddingSize);
    if (ptr != nullptr) {
        ptr->append(buf, paddingSize);
    }

    return ptr;
}

} // namespace eular

// testaes.cc
#include "aes.h"
#include <assert.h>
#include <iostream>

using namespace eular;
using namespace std;

int main(int argc, char **argv)
{
    uint8_t userKey[16] = {
        '1', '2', '3', '4', '5', '6',
        '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
    Aes aes(userKey, Aes::KeyType::AES128, Aes::EncodeType::AESCBC);
    uint8_t in[1024] = {0};
    uint8_t out[1024] = {0};
    uint8_t tmp[1024] = {0};

    printf("input one string:\n");
    scanf("%[^\n]", in);

    int encodeSize = aes.encode(out, in, strlen((char *)in));
    if (encodeSize < 0) {
        return -1;
    }
    printf("after encode: %d\n", encodeSize);
    for (int i = 0; i < encodeSize; ++i) {
        if (i != 0 && i % 16 == 0) {
            printf("\n");
        }
        printf("%02x ", out[i]);
    }
    printf("\n");

    int decodeSize = aes.decode(tmp, out, encodeSize);
    printf("after decrypt: %s\n", tmp);
    for (int i = 0; i < decodeSize; ++i) {
        if (i != 0 && i % 16 == 0) {
            printf("\n");
        }
        printf("%02x ", tmp[i]);
    }
    printf("\n");

    assert(memcmp(in, tmp, decodeSize) == 0);
    return 0;
}

参考:https://www.cnblogs.com/solohac/p/4284424.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Openssl-AES加密 的相关文章

  • 必须打开存储才能执行此操作 - System.IO.Packaging.Package

    我正在使用 System IO Packaing Package 类来压缩文件 我的应用程序的多个实例可以同时运行 并读取和保存文件 当处理小文件时 一切似乎都很好 但是当涉及大文件时 如果应用程序的两个实例同时保存 我会收到一个异常 消息
  • C修改printf()输出到文件

    有没有办法修改printf为了将字符串输出到文件而不是控制台 我尝试在互联网上查找一些内容 发现了类似的电话dup dup2 and fflush这可能与此有关 EDIT 也许我不清楚 问题是这是C考试问题 问题如下 解释一个通常将字符串输
  • 通过单个 GPIO 引脚转储闪存

    我正在使用 Infineon 的 XMC4500 Relax Kit 并尝试通过单个 GPIO 引脚提取固件 我非常天真的想法是通过 GPIO 引脚一次转储一位 然后用逻辑分析仪以某种方式 嗅探 数据 伪代码 while word by w
  • 关闭 XDOCUMENT 的实例

    我收到这个错误 该进程无法访问文件 C test Person xml 因为它是 被另一个进程使用 IOException 未处理 保存文件内容后如何关闭 xml 文件的实例 using System using System Collec
  • C# 中附加/分离事件处理程序的不同方式有什么区别

    我的问题有两个部分 首先 我们可以通过以下两种方式附加事件处理程序 myObject MyEvent new EventHandler MyHandler myObject MyEvent MyHandler 据我了解 这两者是等价的 在第
  • 通过引用传递时取消引用指针

    当通过引用传递给函数时取消引用指针时会发生什么 这是一个简单的例子 int returnSame int example return example int main int inum 3 int pinum inum std cout
  • 为什么假设 send 可能返回的数据少于在阻塞套接字上传输的请求数据?

    在流套接字上发送数据的标准方法始终是调用 send 并写入一大块数据 检查返回值以查看是否发送了所有数据 然后再次调用 send 直到整个消息被接受 例如 这是一个常见方案的简单示例 int send all int sock unsign
  • rand() 播种与 time() 问题

    我很难弄清楚如何使用 rand 并使用 Xcode 用 time 为其播种 我想生成 0 到 1 之间的随机十进制数 该代码为我提供了元素 1 和 2 看似随机的数字 但元素 0 始终在 0 077 左右 有什么想法吗 我的代码是 incl
  • F10键没被抓住

    I have a Windows Form and there overriden ProcessCmdKey However this works with all of the F Keys except for F10 I am tr
  • 将成员函数作为参数传递/c++

    我想用 C 实现一个类b可以通过封装该迭代器类型的成员集进行某种迭代 喜欢 b object for each x do function f so 函数 f会得到每个人的x成员并做任何事情 比方说 void function f x me
  • 抽象类或接口。哪种方式是正确的?

    有两种方法可以选择抽象类或接口 微软解决方案和Oracle解决方案 微软 设计指南 请使用抽象 在 Visual Basic 中为 MustInherit 类而不是接口来将协定与实现分离 http msdn microsoft com en
  • 在“using”语句中使用各种类型 (C#)

    自从C usingstatements只是try finally dispose 的语法糖 为什么它接受多个对象仅当它们属于同一类型时 我不明白 因为它们需要的只是 IDisposable 如果它们都实现 IDisposable 应该没问题
  • 为什么重载方法在 ref 仅符合 CLS 方面有所不同

    公共语言规范对方法重载非常严格 仅允许根据其参数的数量和类型来重载方法 如果是泛型方法 则根据其泛型参数的数量进行重载 根据 csc 为什么此代码符合 CLS 无 CS3006 警告 using System assembly CLSCom
  • 如何在 C# 中使用 XmlDsigC14NTransform 类

    我正在尝试使用规范化 xml 节点System Security Cryptography Xml XMLDsigC14nTransformC net Framework 2 0 的类 该实例需要三种不同的输入类型 NodeList Str
  • C# 中处理 SQL 死锁的模式?

    我正在用 C 编写一个访问 SQL Server 2005 数据库的应用程序 该应用程序是数据库密集型的 即使我尝试优化所有访问 设置适当的索引等 我预计迟早会遇到死锁 我知道为什么会发生数据库死锁 但我怀疑我能否在某个时候发布不发生死锁的
  • 当在 Repository/UnitOrWork 之上使用 Service 类时,我应该在哪里放置逻辑不适合 Repository 的常用数据访问代码?

    In my 先前的问题 https stackoverflow com questions 24906548 using the generic repository unit of work pattern in large projec
  • 如何查找哪个 Yocto 项目配方填充图像根文件系统上的特定文件

    我经常与 Yocto 项目合作 一个常见的挑战是确定文件为何 或来自什么配方 包含在 rootfs 中 这有望从构建系统的环境 日志和元数据中得出 理想情况下 一组命令将允许将文件链接回源 即配方 我通常的策略是对元数据执行搜索 例如gre
  • 将 bignum 类型结构转换为人类可读字符串的有效方法是什么?

    我有一点问题 为了增长我的 C 知识 我决定尝试实现一个基本的 bigint 库 bigint 结构的核心将是一个 32 位整数数组 选择它们是因为它们适合寄存器 这将允许我在数字之间进行操作 这些操作将在 64 位整数中溢出 这也将适合寄
  • 是否有任何不使用公共虚拟方法的正当理由? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 是否有任何不使用公共虚拟方法的正当理由 我在某处读到我们应该避免使用公共虚拟方法 但我想向专家确认这是否是有效的声明 对于良好且稳定的 API
  • 通过 cmake 链接作为外部项目包含的 opencv 库[重复]

    这个问题在这里已经有答案了 我对 cmake 比较陌生 经过几天的努力无法弄清楚以下事情 我有一个依赖于 opencv 的项目 它本身就是一个 cmake 项目 我想静态链接 opencv 库 我正在做的是我的项目中有一份 opencv 源

随机推荐

  • MPLS实验

    MPLS第一次试验 公网地址配置 R2 GigabitEthernet0 0 1 23 1 1 1 24 LoopBack0 2 2 2 2 24 R3 GigabitEthernet0 0 0 23 1 1 2 24 GigabitEth
  • C语言文件读入---跳过第一行和最后一行

    include
  • 【FreeRtos学习笔记】STM32 CubeMx——Timers(定时器)

    目录 1 软件定时器 2 示例程序 2 1 例程功能 2 2 步骤 2 3 实验结果 2 4 函数讲解 1 软件定时器 定时器是MCU常用的外设 我们在学习各种单片机时必然会学习它的硬件定时器 但是 MCU自带的硬件定时器资源是有限的 而且
  • Android Fragment 生命周期图

    http www cnblogs com purediy p 3276545 html
  • 开发技术--浅谈python数据类型

    开发 浅谈python数据类型 在回顾Python基础的时候 遇到最大的问题就是内容很多 而我的目的是回顾自己之前学习的内容 进行相应的总结 所以我就不玩基础了 很多在我实际生活中使用的东西 我会在文章中提一下 并且我自己会根据这些内容进行
  • C++从入门到放弃之:Hello.cpp

    C 从入门到放弃 Hello cpp 1 创建c 程序源代码 2 C 程序的编译 3 C 扩展名 4 C 头文件 5 C 输入输出流 Hello cpp 1 创建c 程序源代码 vim hello cpp include
  • Unity3D+EasyAR实现AR效果的案例

    1 下载EasyAR的压缩包以及下面我要用到的霸王龙模型 链接 https pan baidu com s 12q4Jp11BMxnIW1DB48yy0Q 密码 1y3y 2 新建一个Unity3D的项目 然后双击下载好的EasyAR 将其
  • 分支-07. 比较大小(10)

    本题要求将输入的任意3个整数从小到大输出 输入格式 输入在一行中给出3个整数 其间以空格分隔 输出格式 在一行中将3个整数从小到大输出 其间以 gt 相连 输入样例 4 2 8 输出样例 2 gt 4 gt 8 程序 include int
  • 吃透Chisel语言.15.Chisel模块详解(二)——Chisel模块嵌套和ALU实现

    Chisel模块详解 二 Chisel模块嵌套和ALU实现 稍微复杂点的硬件设计就需要用嵌套的模块层级来构建了 上一篇文章中实现的计数器其实就是个例子 计数器内部嵌套了一个寄存器 一个Mux和一个加法器 这一篇文章就仔细讲解模块之间是怎么连
  • 结构体注入VS setter 注入

    结构体注入 setter注入是比较常用的依赖注入方式 都有各自的优缺点 setter注入是Spring推荐的依赖注入方式 首先结构体注入有什么问题 1 不能重新配置和重新注入 在Spring参考文档 中基于结构体注入和setter注入有以下
  • 利用visual studio 2017创建mfc程序,来输出hello world。

    1 点击文件 选择新建 再点击项目 2 选择visual C 选择MFC应用 位置和名称根据需要可适当更改 再点击创建 如果没有MFC应用 需要在工具那里点击获取工具和功能 3 在单个组件里面添加关于MFC的组件 4 进入以下视图 5 点击
  • 深度学习笔记 —— 批量归一化

    梯度在上面 损失处 的时候比较大 越到下面越容易变小 因为很多时候都是n个很小的数相乘 乘到最后梯度就比较小了 所以就导致上面参数更新快 而下面参数更新慢 下面参数在小范围内变化时 抽取的底层特征变化不大 此时上层的参数是针对这些底层特征进
  • pyaudio安装过程中出现Error: failed building wheel for pyaudio(其实正常安装portaudio就能解决)

    pyaudio安装过程中出现Error failed building wheel for pyaudio 问题发生与解决过程 发现问题 安装pyudio 寻找解决问题的方法 定位依赖包 解决问题 安装portaudio19 dev 新问题
  • CGSS2015问卷数据STATA重编码命令(部分)

    今天在写论文时处理的CGSS数据 保存下来以待以后用 选取城市样本 drop if s1 2 选取18 45岁的样本 drop if a301 gt 1997 drop if a301 lt 1970 计算年龄 gen nianling 2
  • Qt Creator下载和安装(详细教程)

    简介 Qt是跨平台的图形开发库 目前由Digia全资子公司 Qt Company 独立运营 官方网址 http www qt io 也可以访问Qt项目域名 http qt project org Qt本身支持众多操作系统 从通用操作系统Li
  • 为什么下载pytorch时,总是下载cpu版本,而不是gpu版本?

    首先 查看一下自己cuda与cudnn版本 创建的虚拟环境python版本 我的python3 10 cuda 11 2 cudnn8 0 因为我们下载都是通过清华源下载的 所以 当清华源里面 没有我们指定python3 10 cuda 1
  • video 标签设置样式

    设置video标签的默认样式 在这里插入图片描述 全屏按钮 video webkit media controls fullscreen button display none 播放按钮 video webkit media control
  • 算法导论

    好像在豆瓣上看到一句话 算法导论之所以经典 是因为它选取的算法每个都是常用的 是精中选精 于是我就有了重读算法导论的冲动 自己非计算机科班出身 所以对于算法这个基础真的比较薄弱 虽然学过算法 但是基础真的太差了 再说学习算法完全是为了锻炼思
  • Java卸载删除(2023最强版)

    Java卸载删除 2023最强版 卸载程序 删除相关环境变量 删除编辑注册表相关 检查C盘相关文件是否删除 收尾 看了网上很多教程 结果还是提示没卸载干净 做了以下整理 希望对大家有所帮助 卸载程序 在应用和功能中 或控制面板的卸载程序中卸
  • Openssl-AES加密

    AES加密算法 此次介绍AES两种加密算法 其他的暂不使用 1 ECB模式 按照块密码的块大小被分为数个块 并对每个块进行独立加密 优点 1 简单 2 有利于并行计算 3 误差不会被传送 缺点 1 不能隐藏明文的模式 2 可能对明文进行主动