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

你可能感兴趣的:(openssl,openssl,加密解密)