OpenSSL AES对称加密

一、对称加密
对称加密也被称为共享密钥加密,是一种将相同密钥用于加密和解密的加密方式。在对称加密中,加密和解密使用的是相同的密钥,因此需要确保密钥的安全性。

1.工作原理
对称加密使用一个密钥来加密和解密数据。发送方使用该密钥对数据进行加密,接收方使用相同的密钥对数据进行解密。这种加密方式非常快速,因为它只需要一个密钥来加密和解密数据。
以下是对称加密的基本过程:
发送方使用密钥对明文进行加密。
发送方将加密后的数据发送给接收方。
接收方使用相同的密钥对加密后的数据进行解密。
2. 优缺点
优点:
加密和解密速度快。
加密强度高,因为使用的是相同的密钥。
适合用于大量数据的加密。
缺点:
密钥管理困难,需要确保密钥的安全性。
不适合用于跨网络的通信,因为需要将密钥传输给接收方。
3. 应用场景
对称加密广泛应用于保护本地数据的安全,例如:
文件和文件夹加密
数据库加密
本地存储设备加密

EVP_CipherInit_ex()、EVP_CipherUpdate() 和 EVP_CipherFinal_ex() 是可用于解密或加密的函数。执行的操作取决于enc参数的值。加密时应设置为 1,解密时设置为 0,保持值不变为 -1。

// 创建密码上下文
EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void);
// 清除密码上下文中的所有信息并释放与其关联的任何已分配内存,包括ctx本身。
// 应在使用密码的所有操作完成后调用此函数,以便敏感信息不会保留在内存中。
void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx)
/**
函数作用:初始化密码上下文ctx
ctx  : 由 EVP_CIPHER_CTX_new() 创建
type : 使用的算法类型,例如:EVP_aes_256_cbc()、EVP_aes_128_cbc()
impl :密码类型,如果impl为 NULL,则使用默认实现。一般都设置为NULL
key  : 加密密钥
iv   : 偏移量
enc  : 1 - 加密;0 - 解密
**/
int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
                       ENGINE *impl, const unsigned char *key, const unsigned char *iv, int enc);
/**
输入 in 缓冲区中的 inl 字节的数据并将加/解密数据写入 out。可以多次调用此函数来加/解密连续的数据块。
**/
int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
                      int *outl, const unsigned char *in, int inl);
/**
输出 缓冲区中剩余的数据。必须在 EVP_CipherUpdate() 之后调用。
outm : 为输出缓冲区中剩余部分
**/
int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);

/**
启用或禁用填充。在使用 EVP_EncryptInit_ex()、EVP_DecryptInit_ex() 或 EVP_CipherInit_ex() 为加密或解密设置上下文后,应调用此函数。
默认情况下,加密操作使用标准块填充进行填充,并且在解密时检查并删除填充。
如果填充参数 padding 设置为零,则不执行填充,此时加密或解密的数据总量必须是块大小的倍数,否则将发生错误。
默认情况下填充是启用的。padding 为0 则禁用填充,否则启用填充
**/
int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *x, int padding);

#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/bn.h>

unsigned char key[] = "0123456789abcdeF";
unsigned char iv[] = "1234567887654321";

/**
inBuf : 输入数据
inl   : 输入数据长度
out   : 输出缓冲区,由调用者确定其大小
cipher:算法类型。例如:EVP_aes_128_cbc()、EVP_aes_256_cbc()
enc: operator type , 1 is enc and 0 is dec
**/
int do_crypt(const char *inBuf, int inl, char *out,  const EVP_CIPHER *cipher, int enc)
{
    if(NULL == inBuf || NULL == out)
    {
        return -1;
    }
    int templ, total;
    // 创建上下文
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    // 初始化.设置算法类型和加解密类型以及加密密钥和偏移量
    EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc);
    // 设置是否启用填充.默认是启用的
    // 如果填充参数为零,则不执行填充,此时加密或解密的数据总量必须是块大小的倍数,否则将发生错误。
    EVP_CIPHER_CTX_set_padding(ctx, 1);
    // key 和 iv 长度断言检查。断言长度随着 cipher 的不同而不同
	OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == 16);
    OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == 16);
    templ= 0;
    total = 0;
    if (!EVP_CipherUpdate(ctx, out, &templ, inBuf, inl))
    {
        printf("EVP_CipherUpdate fail...");
        goto err;
    }
    total += templ;

    if (!EVP_CipherFinal_ex(ctx, out + total, &templ))
    {
        printf("EVP_CipherFinal_ex fail...");
        goto err;
    }
    total += templ;
    EVP_CIPHER_CTX_free(ctx);
    return 0;
    err:
    EVP_CIPHER_CTX_free(ctx);
    return -1;
}

int main(){
    const char plaintext[] = "Hello World!";
    char ciphertext[128];
    char decryptedtext[128];
    printf("plain text: %s\n",plaintext);
    do_crypt(plaintext, strlen((const char*)plaintext),ciphertext,EVP_aes_128_cbc(),1);
    printf("enc text: %s\n",ciphertext);
    do_crypt(ciphertext, strlen((const char*)ciphertext),decryptedtext,EVP_aes_128_cbc(),0);
    printf("dec text: %s\n",decryptedtext);
}

EVP_Encryp 和 EVP_Decryp 系列:

/**
设置密码上下文ctx以使用来自 ENGINE impl 的密码类型进行加密。ctx必须在调用此函数之前创建。类型通常由诸如 EVP_aes_256_cbc() 之类的函数提供。如果impl为 NULL,则使用默认实现。key是要使用的对称密钥,iv是要使用的 IV(如有必要),用于密钥和 IV 的实际字节数取决于密码。可以在初始调用中将除type之外的所有参数设置为 NULL ,并在后续调用中提供其余参数.
**/
int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
                        ENGINE *impl, const unsigned char *key, const unsigned char *iv);
/**
加密inl缓冲区中的inl字节in并将加密版本写入out。可以多次调用此函数来加密连续的数据块。
写入的数据量取决于加密数据的块对齐。对于大多数密码和模式,写入的数据量可以是从零字节到 (inl + cipher_block_size - 1) 字节的任何内容。对于包装密码模式,写入的数据量可以是从零字节到 (inl + cipher_block_size) 字节的任何内容。
对于流密码,写入的数据量可以是从零字节到 inl 字节的任何内容。因此,out应该为正在执行的操作包含足够的空间。实际写入的字节数放在outl中
**/
int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
                       int *outl, const unsigned char *in, int inl);
/**
必须在 EVP_EncryptUpdate 之后调用,用来加密原文剩余部分。
**/
int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);

EVP_DecryptInit_ex()、EVP_DecryptUpdate()和EVP_DecryptFinal_ex()是对应的解密操作。如果启用了填充并且最终块的格式不正确,则 EVP_DecryptFinal() 将返回错误代码。

#include <iostream>
#include <cstring>
#include <openssl/evp.h>
using namespace std;

void symmetric_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
                       unsigned char *iv, unsigned char *ciphertext) {
    EVP_CIPHER_CTX *ctx;
    int len;
    int ciphertext_len;
    ctx = EVP_CIPHER_CTX_new();
    EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv);
    EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len);
    ciphertext_len = len;
    EVP_EncryptFinal_ex(ctx, ciphertext + len, &len);
    ciphertext_len += len;
    EVP_CIPHER_CTX_free(ctx);
}

void symmetric_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
                       unsigned char *iv, unsigned char *plaintext) {
    EVP_CIPHER_CTX *ctx;
    int len;
    int plaintext_len;
    ctx = EVP_CIPHER_CTX_new();
    EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv);
    EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len);
    plaintext_len = len;
    EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
    plaintext_len += len;
    EVP_CIPHER_CTX_free(ctx);
}

int main() {
    unsigned char key[] = "01234567890123456789012345678901";
    unsigned char iv[] = "0123456789012345";
    unsigned char plaintext[] = "Hello World!";
    unsigned char ciphertext[128];
    unsigned char decryptedtext[128];
    symmetric_encrypt(plaintext, strlen((char *) plaintext), key, iv, ciphertext);
    symmetric_decrypt(ciphertext, strlen((char *) ciphertext), key, iv, decryptedtext);
    cout << "Plaintext: " << plaintext << endl;
    cout << "Ciphertext: " << ciphertext << endl;
    cout << "Decrypted text: " << decryptedtext << endl;
    return 0;
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OpenSSL提供了AES加密算法,可以使用AES_cbc_encrypt函数进行加密操作。这个函数需要传入明文数据、密钥、初始向量(ivec)等参数进行加密。其中,初始向量(ivec)的内容可以任意指定,但加密和解密操作必须使用相同的数据。在AES_cbc_encrypt的底层实现中,每16个字节进行一次处理,先与初始向量进行异或运算,然后调用AES_encrypt函数进行加密。在加密过程中,AES_cbc_encrypt会修改初始向量的内容,因此初始向量参数不能是一个常量,也不能在传递给加密函数后立即传递给解密函数,必须重新赋值后再传递给解密函数。 需要注意的是,对称加密算法的优势是算法公开、计算量小、加密速度快、加密效率高,而安全性主要取决于密钥的保护。对称加密的缺点主要体现在多用户通信场景中,密钥分发和管理比较困难。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [基于openssl库实现AES加密(C语言)](https://blog.csdn.net/ylgcgbd/article/details/117931518)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [OpenSSLAES加密的用法](https://blog.csdn.net/m0_46577050/article/details/121302115)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值