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加密 的相关文章

  • 使用 Json.NET 序列化子类

    我正在尝试使用 Json NET 序列化子类 生成的 json 包含超类的序列化属性 但是not子类对象的属性 这似乎与我发现的一个问题有关这里就这样 https stackoverflow com q 5863496 498969 但必须
  • NDK 应用 onDestroy 清理 - 如何 DetachCurrentThread

    因此 如果我们连接 我们必须在完成后分离线程 对吗 JNIEnv get jni env JNIEnv res JAVA VM gt GetEnv void res JNI VERSION 1 6 Using cached JavaVM J
  • PyPI 上的轮子平台约束有什么限制吗?

    是否有任何地方 PEP 或其他地方 声明关于 Linux 轮子上传范围的限制 PyPI http pypi io 应该有 具体来说 上传是否被认为是可接受的做法linux x86 64轮子到 PyPI 而不是manylinux1 x86 6
  • 如何在C中同时运行两个子进程?

    所以我开始学习并发编程 但由于某种原因我什至无法掌握基础知识 我有一个名为 fork c 的文件 其中包含一个 main 方法 在此方法中 我将 main 分叉两次 分别进入子进程 1 和 2 在孩子 1 中 我打印了字符 A 50 次 在
  • ContentDialog 未与 UWP 中心对齐

    据我所知 ContentDialog的默认行为应该是使其在 PC 上居中并在移动设备上与顶部对齐 但就我而言 即使在 PC 上我也将其与顶部对齐 但我不明白发生了什么 我正在使用代码隐藏来创建它 这是我正在使用的代码片段 Creates t
  • Monotouch全局异常处理

    我在野外发现了一只令人讨厌的虫子 但我无法确定它的具体情况 有没有办法拥有全局 Try Catch 块 或者有办法处理 Monotouch 中未处理的任何异常 我可以包起来吗UIApplication Main args 在 try cat
  • 组合框下拉位置

    我有一个最大化的表单 其中包含 500px 的组合框控件 停靠在右上角 Width 尝试打开组合框后 列表的一半超出了屏幕 如何强制列表显示在表单中 棘手的问题 我找不到解决这个问题的好办法 只是一个解决方法 添加一个新类并粘贴如下所示的代
  • 对作为函数参数传递的指针使用删除

    删除作为函数参数传递的指针是否可以 并且合法 如下所示 include
  • 如何将STL容器数据转储到gdb中?

    我无法在 gdb 中转储 STL 无序映射容器值 变量类型是 std unordered map var 我的 gdb 版本 7 7 1 GDB配置 configure host x86 64 linux gnu target x86 64
  • C#:自定义转换为值类型

    是否可以将自定义类转换为值类型 这是一个例子 var x new Foo var y int x Does not compile 是否有可能实现上述情况 我需要超载一些东西吗Foo 您将必须重载强制转换运算符 public class F
  • 如何在 C# 中更改公共 IP 地址

    我正在创建一个 C winform 应用程序 我想在其中更改公共 IP 地址 而不是像 Hotspot Shield ZenMate OpenVPN 等那样更改 IPv4 地址 我已经检查了以下链接 但没有找到足够的帮助 所以我发布了这个问
  • 从 DataRow 单元格解析 int [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 如何从 DataRow 单元格解析 int 值 Int32 Parse item QuestionId ToString 这段代码可以工作 但看
  • valgrind 在 Raspberry Pi 上返回未处理的指令

    我最近一直在尝试在运行 Debian GNU Linux7 0 喘息 的树莓派 型号 b 上使用 valgrind 来调试分段错误 每次我在编译的 C 程序上运行 valgrind 时 都会得到类似以下内容的信息 disInstr arm
  • 如何同步nosql db(ravendb)中的更改

    我已经开始在 RavenDB 的示例上学习 NoSQL 我从一个最简单的模型开始 假设我们有由用户创建的主题 public class Topic public string Id get protected set public stri
  • 如何检测应用程序正在运行的 .NET 版本?

    我尝试使用Environment Version ToString 确定目标计算机上正在使用什么 NET 框架 但安装了 4 0 版本时 它说我正在使用 NET 2 0 如何检测目标计算机上正在运行的 NET Framework 版本 En
  • linux下写入后崩溃

    如果我使用 write 将一些数据写入磁盘上的文件会发生什么 但我的应用程序在刷新之前崩溃了 如果没有系统故障 是否可以保证我的数据最终会刷新到磁盘 如果您正在使用write 并不是fwrite or std ostream write 那
  • 为什么在构造函数中设置字段是(或不是)线程安全的?

    假设您有一个像这样的简单类 class MyClass private readonly int a private int b public MyClass int a int b this a a this b b public int
  • 如何在c#中创建多线程

    我需要监听机器中的所有串行端口 假设我的机器有 4 个串行端口 我必须创建 4 个线程并开始分别使用附加线程监听每个端口 我使用此代码来获取我的机器中的端口数量 private SerialPort comPort new SerialPo
  • 使用 CodeDOM 将程序集添加到 BuildManager 会导致间歇性错误

    我正在使用 CodeDOM 在运行时创建内存中程序集 如下所示 public Assembly Compile CodeCompileUnit targetUnit string path Path GetDirectoryName new
  • 实体框架代码首次日期字段创建

    我正在使用实体框架代码优先方法来创建我的数据库表 下面的代码 创建一个DATETIME数据库中的列 但我想创建一个DATE柱子 DataType DataType Date DisplayFormatAttribute ApplyForma

随机推荐

  • 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 可能对明文进行主动