Openssl 对称加解密函数 - EVP_Cipher、EVP_Encrypt、EVP_Decryp 系列

 实验环境:openssl 1.1.1k

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);
/**
这是一个示例代码
**/

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

/**
inBuf : 输入数据
inl   : 输入数据长度
out   : 输出缓冲区,由调用者确定其大小
outl  : 输出数据的长度
cipher:算法类型。例如:EVP_aes_128_cbc()、EVP_aes_256_cbc()
**/
int do_crypt(const char *inBuf, int inl, char *out, int *outl, 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);
#if 0
	// key 和 iv 长度断言检查。断言长度随着 cipher 的不同而不同
	OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == 16);
    OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == 16);
#endif

	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;
    *outl = total;

	EVP_CIPHER_CTX_free(ctx);
	return 0;
err:
	EVP_CIPHER_CTX_free(ctx);
	return -1;
}

EVP_CipherInit_ex 中可支持的算法类型(详细请见 openssl/evp.h 头文件)

const EVP_CIPHER *EVP_aes_128_ecb(void);
const EVP_CIPHER *EVP_aes_128_cbc(void);
const EVP_CIPHER *EVP_aes_128_cfb1(void);
const EVP_CIPHER *EVP_aes_128_cfb8(void);
const EVP_CIPHER *EVP_aes_128_cfb128(void);

const EVP_CIPHER *EVP_aes_128_ofb(void);
const EVP_CIPHER *EVP_aes_128_ctr(void);
const EVP_CIPHER *EVP_aes_128_ccm(void);
const EVP_CIPHER *EVP_aes_128_gcm(void);
const EVP_CIPHER *EVP_aes_128_xts(void);
const EVP_CIPHER *EVP_aes_128_wrap(void);
const EVP_CIPHER *EVP_aes_128_wrap_pad(void);

const EVP_CIPHER *EVP_aes_128_ocb(void);

const EVP_CIPHER *EVP_aes_192_ecb(void);
const EVP_CIPHER *EVP_aes_192_cbc(void);
const EVP_CIPHER *EVP_aes_192_cfb1(void);
const EVP_CIPHER *EVP_aes_192_cfb8(void);
const EVP_CIPHER *EVP_aes_192_cfb128(void);

const EVP_CIPHER *EVP_aes_192_ofb(void);
const EVP_CIPHER *EVP_aes_192_ctr(void);
const EVP_CIPHER *EVP_aes_192_ccm(void);
const EVP_CIPHER *EVP_aes_192_gcm(void);
const EVP_CIPHER *EVP_aes_192_wrap(void);
const EVP_CIPHER *EVP_aes_192_wrap_pad(void);

const EVP_CIPHER *EVP_aes_192_ocb(void);

const EVP_CIPHER *EVP_aes_256_ecb(void);
const EVP_CIPHER *EVP_aes_256_cbc(void);
const EVP_CIPHER *EVP_aes_256_cfb1(void);
const EVP_CIPHER *EVP_aes_256_cfb8(void);
const EVP_CIPHER *EVP_aes_256_cfb128(void);

const EVP_CIPHER *EVP_aes_256_ofb(void);
const EVP_CIPHER *EVP_aes_256_ctr(void);
const EVP_CIPHER *EVP_aes_256_ccm(void);
const EVP_CIPHER *EVP_aes_256_gcm(void);
const EVP_CIPHER *EVP_aes_256_xts(void);
const EVP_CIPHER *EVP_aes_256_wrap(void);
const EVP_CIPHER *EVP_aes_256_wrap_pad(void);

const EVP_CIPHER *EVP_aes_256_ocb(void);

const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha1(void);
const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha1(void);
const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha256(void);
const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha256(void);

const EVP_CIPHER *EVP_aria_128_ecb(void);
const EVP_CIPHER *EVP_aria_128_cbc(void);
const EVP_CIPHER *EVP_aria_128_cfb1(void);
const EVP_CIPHER *EVP_aria_128_cfb8(void);
const EVP_CIPHER *EVP_aria_128_cfb128(void);

const EVP_CIPHER *EVP_aria_128_ctr(void);
const EVP_CIPHER *EVP_aria_128_ofb(void);
const EVP_CIPHER *EVP_aria_128_gcm(void);
const EVP_CIPHER *EVP_aria_128_ccm(void);
const EVP_CIPHER *EVP_aria_192_ecb(void);
const EVP_CIPHER *EVP_aria_192_cbc(void);
const EVP_CIPHER *EVP_aria_192_cfb1(void);
const EVP_CIPHER *EVP_aria_192_cfb8(void);
const EVP_CIPHER *EVP_aria_192_cfb128(void);

const EVP_CIPHER *EVP_aria_192_ctr(void);
const EVP_CIPHER *EVP_aria_192_ofb(void);
const EVP_CIPHER *EVP_aria_192_gcm(void);
const EVP_CIPHER *EVP_aria_192_ccm(void);
const EVP_CIPHER *EVP_aria_256_ecb(void);
const EVP_CIPHER *EVP_aria_256_cbc(void);
const EVP_CIPHER *EVP_aria_256_cfb1(void);
const EVP_CIPHER *EVP_aria_256_cfb8(void);
const EVP_CIPHER *EVP_aria_256_cfb128(void);

const EVP_CIPHER *EVP_aria_256_ctr(void);
const EVP_CIPHER *EVP_aria_256_ofb(void);
const EVP_CIPHER *EVP_aria_256_gcm(void);
const EVP_CIPHER *EVP_aria_256_ccm(void);

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() 将返回错误代码。

使用 IDEA 加密字符串:

int do_crypt(char *outfile)
 {
     unsigned char outbuf[1024];
     int outlen, tmplen;
     unsigned char key[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
     unsigned char iv[] = {1,2,3,4,5,6,7,8};
     char intext[] = "Some Crypto Text";
     EVP_CIPHER_CTX *ctx;
     FILE *out;

     ctx = EVP_CIPHER_CTX_new();
     EVP_EncryptInit_ex(ctx, EVP_idea_cbc(), NULL, key, iv);

     if (!EVP_EncryptUpdate(ctx, outbuf, &outlen, intext, strlen(intext))) {
         EVP_CIPHER_CTX_free(ctx);
         return -1;
     }

     if (!EVP_EncryptFinal_ex(ctx, outbuf + outlen, &tmplen)) {
         EVP_CIPHER_CTX_free(ctx);
         return -1;
     }
     outlen += tmplen;
     EVP_CIPHER_CTX_free(ctx);

     out = fopen(outfile, "wb");
     if (out == NULL) {
         return -1;
     }
     fwrite(outbuf, 1, outlen, out);
     fclose(out);
     return 0;
 }

  • 4
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: openssl命令可以通过EVP库来解密EVP_aes_256_cbc加密的数据,具体命令如下: ``` openssl enc -d -aes-256-cbc -in [input_file] -out [output_file] -K [key_in_hex] -iv [iv_in_hex] ``` 其中: - `-d`: 指定解密操作。 - `-aes-256-cbc`: 指定使用AES-256算法和CBC模式。 - `-in [input_file]`: 指定输入文件路径。 - `-out [output_file]`: 指定输出文件路径。 - `-K [key_in_hex]`: 指定加密密钥,以16进制表示。 - `-iv [iv_in_hex]`: 指定初始化向量,以16进制表示。 例如,如果加密时使用的密钥是`0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef`,初始化向量是`0123456789abcdef0123456789abcdef`,加密后的数据保存在文件`encrypted.bin`中,解密后的数据要保存在文件`decrypted.bin`中,那么解密命令如下: ``` openssl enc -d -aes-256-cbc -in encrypted.bin -out decrypted.bin -K 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef -iv 0123456789abcdef0123456789abcdef ``` 执行命令后,输入密钥密码,即可完成解密操作。 ### 回答2: openssl是一个开放源代码的密码学工具库,它提供了各种加密和解密算法的实现。其中,EVP_aes_256_cbc是openssl库中的一个加密算法,它采用了256位的密钥长度和CBC(Cipher Block Chaining)模式。 要使用openssl解密EVP_aes_256_cbc命令,需要以下步骤: 1. 安装openssl:首先,需要在计算机上安装openssl库。可以通过下载openssl的源代码并编译安装,或者使用操作系统的包管理工具进行安装。 2. 准备密文和密钥:解密密文之前,需要获取密文和其对应的密钥。密文是通过EVP_aes_256_cbc算法加密得到的,密钥是用于解密的关键。确保密文和密钥的正确性和可用性。 3. 执行解密命令:使用openssl的命令行工具执行解密操作。打开终端或命令提示符,进入openssl的安装目录,执行以下命令: ``` openssl enc -d -aes-256-cbc -in ciphertext.txt -out plaintext.txt -pass file:secret.key ``` 其中,`ciphertext.txt`为密文文件的路径,`plaintext.txt`为解密后的明文输出文件的路径,`secret.key`为密钥文件的路径。`-d`表示解密操作,`-aes-256-cbc`指定了解密算法为EVP_aes_256_cbc。 4. 输入密钥密码:执行上述命令后,openssl会要求输入密钥密码。根据实际情况,输入正确的密钥密码并按下回车键。 5. 完成解密:执行完上述命令后,openssl会使用提供的密钥对密文进行解密,并将解密后的明文输出到指定的文件中。此时,解密操作完成。 需要注意的是,解密过程涉及到密文的保密性,在使用openssl解密时应确保密文和密钥不被泄露给不信任的第三方。此外,要保证openssl的正确安装和使用,以及密文和密钥的准确性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值