AES 的 EVP_CIPHER_CTX_set_padding 的padding设置

该博客探讨了AES对称加密中EVP_CIPHER_CTX_set_padding函数的作用,指出默认填充方式为EVP_PADDING_PKCS7。如果不设置或设置为0,对于不足128位的数据块会引发错误。尽管可以设置为ISO7816_4、ANSI923、ISO10126,但对AES加密的影响与PKCS7相同。作者提供了相关文档链接和在线加密工具以供参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 函数全称:

int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *c, int pad);

可以设置在加密数据时对不够长的数据进行填充的方式,pad可以设置为以下几个

//in file openssl/evp.h
#define EVP_PADDING_PKCS7       1
#define EVP_PADDING_ISO7816_4   2
#define EVP_PADDING_ANSI923     3
#define EVP_PADDING_ISO10126    4
#define EVP_PADDING_ZERO        5

在AES对称加密中,不写这个函数,默认是有padding的,应该是EVP_PADDING_PKCS7。如果设置为0,若你的数据的一个分组(一般时最后一个分组)不够AES数据块长度128bits时,就会报错。

最最重要的是,就算设置为ISO7816_4、ANSI923、ISO10126三种,对AES加密来说,结果和设置为PKCS7是一样的,原因还未知,可以看下面的例子,修改 EVP_CIPHER_CTX_set_padding的pad参数看看。

先附一个链接,讲了这个函数的作用。https://github.com/openssl/openssl/blob/67c81ec311d696464bdbf4c6d6f8a887a3ddf9f8/doc/man3/EVP_EncryptInit.pod

http://tool.chacuo.net/cryptaes  这个网址实现在线AES加密,将结果和下面这个比对

windows 10,VS2019,openssl1.1.1c

#define  _CRT_SECURE_NO_WARNINGS

#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>

#ifdef __cplusplus
#include <openssl/applink.c>
#endif // __cplusplus


void handleErrors(void);
int encrypt(unsigned char* plaintext, int plaintext_len, unsigned char* key,
	unsigned char* iv, unsigned char* ciphertext);
int decrypt(unsigned char* ciphertext, int ciphertext_len, unsigned char* key,
	unsigned char* iv, unsigned char* plaintext);

int main(void)
{
	/*
	 * Set up the key and iv. Do I need to say to not hard code these in a
	 * real application? :-)
	 */

	 /* A 256 bit key */
	unsigned char* key = (unsigned char*)"01234567890123456789012345678901";

	/* A 128 bit IV */
	unsigned char* iv = (unsigned char*)"0123456789012345";

	/* Message to be encrypted */
	unsigned char* plaintext =
		(unsigned char*)"he quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy dog123456789";

	/*
	 * Buffer for ciphertext. Ensure the buffer is long enough for the
	 * ciphertext which may be longer than the plaintext, depending on the
	 * algorithm and mode.
	 */
	unsigned char ciphertext[128*8];

	/* Buffer for the decrypted text */
	unsigned char decryptedtext[128 * 8];
	memset(decryptedtext,'v',128 * 8);


	int decryptedtext_len, ciphertext_len;

	/* Encrypt the plaintext */
	ciphertext_len = encrypt(plaintext, strlen((char*)plaintext), key, iv,
		ciphertext);

	/* Do something useful with the ciphertext here */
	printf("Ciphertext is:\n");
	BIO_dump_fp(stdout, (const char*)ciphertext, ciphertext_len);

	/* Decrypt the ciphertext */
	decryptedtext_len = decrypt(ciphertext, ciphertext_len, key, iv,
		decryptedtext);

	/* Add a NULL terminator. We are expecting printable text */
	decryptedtext[decryptedtext_len] = '\0';

	/* Show the decrypted text */
	printf("Decrypted text is:\n");
	printf("%s\n", decryptedtext);


	return 0;
}


void handleErrors(void)
{
	ERR_print_errors_fp(stderr);
	abort();
}

int 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;

	/* Create and initialise the context */
	if (!(ctx = EVP_CIPHER_CTX_new()))
		handleErrors();


	/*
	 * Initialise the encryption operation. IMPORTANT - ensure you use a key
	 * and IV size appropriate for your cipher
	 * In this example we are using 256 bit AES (i.e. a 256 bit key). The
	 * IV size for *most* modes is the same as the block size. For AES this
	 * is 128 bits
	 */
	if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
		handleErrors();

	


	/*
	 * Provide the message to be encrypted, and obtain the encrypted output.
	 * EVP_EncryptUpdate can be called multiple times if necessary
	 */
	if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
		handleErrors();
	ciphertext_len = len;

	/*
	 *
	 *
	 */
	EVP_CIPHER_CTX_set_padding(ctx, EVP_PADDING_ZERO);

	/*
	 * Finalise the encryption. Further ciphertext bytes may be written at
	 * this stage.
	 */
	if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
		handleErrors();
	ciphertext_len += len;

	/* Clean up */
	EVP_CIPHER_CTX_free(ctx);

	return ciphertext_len;
}


int 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;

	/* Create and initialise the context */
	if (!(ctx = EVP_CIPHER_CTX_new()))
		handleErrors();

	/*
	 * Initialise the decryption operation. IMPORTANT - ensure you use a key
	 * and IV size appropriate for your cipher
	 * In this example we are using 256 bit AES (i.e. a 256 bit key). The
	 * IV size for *most* modes is the same as the block size. For AES this
	 * is 128 bits
	 */
	if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
		handleErrors();

	/*
	 *
	 *
	 */
	EVP_CIPHER_CTX_set_padding(ctx, EVP_PADDING_ZERO);

	/*
	 * Provide the message to be decrypted, and obtain the plaintext output.
	 * EVP_DecryptUpdate can be called multiple times if necessary.
	 */
	if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
		handleErrors();
	plaintext_len = len;

	/*
	 * Finalise the decryption. Further plaintext bytes may be written at
	 * this stage.
	 */
	if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
		handleErrors();
	plaintext_len += len;

	/* Clean up */
	EVP_CIPHER_CTX_free(ctx);

	return plaintext_len;
}

 

将以下函数改写为 使用 CTR/OFB/CFB 加密方式。 #include "aes_crypto.h" #include <openssl/err.h> #include <string.h> #include <stdio.h> int aes_init() { // 初始化OpenSSL库 if (!OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL)) { return AES_ERR_INIT_FAILED; } return AES_SUCCESS; } void aes_cleanup() { // 清理OpenSSL资源 EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); } int aes_generate_key(int key_len, AES_KEY *key) { if (!key || (key_len != 128 && key_len != 192 && key_len != 256)) { return AES_ERR_INVALID_INPUT; } // 生成随机密钥 if (RAND_bytes(key->key, key_len / 8) != 1) { return AES_ERR_KEY_GEN_FAILED; } // 生成随机初始化向量 if (RAND_bytes(key->iv, sizeof(key->iv)) != 1) { return AES_ERR_KEY_GEN_FAILED; } key->key_len = key_len; return AES_SUCCESS; } int aes_save_key(const AES_KEY *key, const char *filename) { if (!key || !filename) { return AES_ERR_INVALID_INPUT; } FILE *fp = fopen(filename, "wb"); if (!fp) { return AES_ERR_KEY_SAVE_FAILED; } // 写入密钥长度 if (fwrite(&key->key_len, sizeof(int), 1, fp) != 1) { fclose(fp); return AES_ERR_KEY_SAVE_FAILED; } // 写入密钥 int key_bytes = key->key_len / 8; if (fwrite(key->key, 1, key_bytes, fp) != key_bytes) { fclose(fp); return AES_ERR_KEY_SAVE_FAILED; } // 写入IV if (fwrite(key->iv, 1, sizeof(key->iv), fp) != sizeof(key->iv)) { fclose(fp); return AES_ERR_KEY_SAVE_FAILED; } fclose(fp); return AES_SUCCESS; } int aes_load_key(AES_KEY *key, const char *filename) { if (!key || !filename) { return AES_ERR_INVALID_INPUT; } FILE *fp = fopen(filename, "rb"); if (!fp) { return AES_ERR_KEY_LOAD_FAILED; } // 读取密钥长度 if (fread(&key->key_len, sizeof(int), 1, fp) != 1) { fclose(fp); return AES_ERR_KEY_LOAD_FAILED; } // 验证密钥长度有效性 if (key->key_len != 128 && key->key_len != 192 && key->key_len != 256) { fclose(fp); return AES_ERR_KEY_LOAD_FAILED; } // 读取密钥 int key_bytes = key->key_len / 8; if (fread(key->key, 1, key_bytes, fp) != key_bytes) { fclose(fp); return AES_ERR_KEY_LOAD_FAILED; } // 读取IV if (fread(key->iv, 1, sizeof(key->iv), fp) != sizeof(key->iv)) { fclose(fp); return AES_ERR_KEY_LOAD_FAILED; } fclose(fp); return AES_SUCCESS; } int aes_encrypt(const AES_KEY *key, const unsigned char *plaintext, int pt_len, unsigned char *ciphertext) { if (!key || !plaintext || !ciphertext || pt_len <= 0) { return -AES_ERR_INVALID_INPUT; } EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); if (!ctx) { return -AES_ERR_ENCRYPT_FAILED; } // 根据密钥长度选择算法 const EVP_CIPHER *cipher = NULL; switch (key->key_len) { case 128: cipher = EVP_aes_128_cbc(); break; case 192: cipher = EVP_aes_192_cbc(); break; case 256: cipher = EVP_aes_256_cbc(); break; default: EVP_CIPHER_CTX_free(ctx); return -AES_ERR_INVALID_INPUT; } int len; int ciphertext_len; // 初始化加密操作 if (EVP_EncryptInit_ex(ctx, cipher, NULL, key->key, key->iv) != 1) { EVP_CIPHER_CTX_free(ctx); return -AES_ERR_ENCRYPT_FAILED; } // 执行加密 if (EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, pt_len) != 1) { EVP_CIPHER_CTX_free(ctx); return -AES_ERR_ENCRYPT_FAILED; } ciphertext_len = len; // 完成加密 if (EVP_EncryptFinal_ex(ctx, ciphertext + len, &len) != 1) { EVP_CIPHER_CTX_free(ctx); return -AES_ERR_ENCRYPT_FAILED; } ciphertext_len += len; EVP_CIPHER_CTX_free(ctx); return ciphertext_len; } int aes_decrypt(const AES_KEY *key, const unsigned char *ciphertext, int ct_len, unsigned char *plaintext) { if (!key || !ciphertext || !plaintext || ct_len <= 0) { return -AES_ERR_INVALID_INPUT; } EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); if (!ctx) { return -AES_ERR_DECRYPT_FAILED; } // 根据密钥长度选择算法 const EVP_CIPHER *cipher = NULL; switch (key->key_len) { case 128: cipher = EVP_aes_128_cbc(); break; case 192: cipher = EVP_aes_192_cbc(); break; case 256: cipher = EVP_aes_256_cbc(); break; default: EVP_CIPHER_CTX_free(ctx); return -AES_ERR_INVALID_INPUT; } int len; int plaintext_len; // 初始化解密操作 if (EVP_DecryptInit_ex(ctx, cipher, NULL, key->key, key->iv) != 1) { EVP_CIPHER_CTX_free(ctx); return -AES_ERR_DECRYPT_FAILED; } // 执行解密 if (EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ct_len) != 1) { EVP_CIPHER_CTX_free(ctx); return -AES_ERR_DECRYPT_FAILED; } plaintext_len = len; // 完成解密 if (EVP_DecryptFinal_ex(ctx, plaintext + len, &len) != 1) { EVP_CIPHER_CTX_free(ctx); return -AES_ERR_DECRYPT_FAILED; } plaintext_len += len; EVP_CIPHER_CTX_free(ctx); return plaintext_len; }
最新发布
08-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值