EVP_EncodeBlock -- 转换ASCII 字符串

EVP_EncodeBlock 介绍

在 OpenSSL 库中,EVP_EncodeBlock 函数用于将二进制数据编码为 Base64 格式。这是特别有用的,因为 Base64 编码将二进制数据转换为 ASCII 字符串,这在需要通过文本协议传输二进制数据时非常有用。下面是 EVP_EncodeBlock 函数的详细介绍、示例代码及其编译方法。

EVP_EncodeBlock 函数

函数原型

int EVP_EncodeBlock(unsigned char *out, const unsigned char *in, int in_len);

参数

  • out:指向输出缓冲区的指针,输出缓冲区需要足够大以存储 Base64 编码后的字符串。输出缓冲区大小至少应为 4 * ((in_len + 2) / 3) + 1 字节,以保证足够的空间。
  • in:指向输入二进制数据的指针。
  • in_len:输入二进制数据的长度(字节数)。

返回值
返回编码后的数据长度(不包括终止符)。

示例代码

下面是一个完整的示例程序,展示了如何使用 EVP_EncodeBlock 函数将二进制数据编码为 Base64 格式:

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

int main() {
    // 原始二进制数据
    const unsigned char input[] = "Hello, world!";
    int input_len = strlen((const char *)input);

    // 计算输出缓冲区大小并分配内存
    int output_len = 4 * ((input_len + 2) / 3);
    unsigned char output[output_len + 1];  // 加1是为了存储'\0'

    // 使用EVP_EncodeBlock编码
    int actual_output_len = EVP_EncodeBlock(output, input, input_len);
    output[actual_output_len] = '\0';  // 添加空终止符

    // 输出Base64编码后的字符串
    printf("Base64 encoded: %s\n", output);

    return 0;
}

编译和运行

确保系统上已安装 OpenSSL 库,并使用以下命令编译和运行该程序:

gcc -o base64_example base64_example.c -lssl -lcrypto
./base64_example

详细说明

  • 输入数据:定义了一个包含字符串 “Hello, world!” 的二进制数据。
  • 计算输出缓冲区大小:Base64 编码后的数据长度至少是 4 * ((input_len + 2) / 3)。该公式确保输出缓冲区足够大以容纳编码后的数据。
  • 分配输出缓冲区:分配了一个足够大的缓冲区以存储编码后的字符串,并留出一个字节用于终止符 \0。
  • 编码过程:调用 EVP_EncodeBlock 函数将输入数据编码为 Base64。
  • 终止符:在编码后的数据末尾添加空终止符 \0,以便它可以作为字符串打印。
  • 打印结果:输出 Base64 编码后的字符串。

注意事项

  • 内存分配:确保输出缓冲区足够大,以避免缓冲区溢出。
  • 输入数据长度:EVP_EncodeBlock 不处理输入数据长度为零的情况,因此在调用前应确保输入数据非空。
  • 安全性:Base64 编码只是数据的表示形式转换,不提供任何加密或安全功能。对于安全需求,应结合加密算法使用。

总结

在EVP_EncodeBlock函数的使用,会和上期所提到的SHA-1算法一起搭配使用,先使用SHA-1算法计算散列值,然后再通过EVP_EncodeBlock转换成ASCII 字符串,最后再配合自己的特殊LOG,产生安全性高的密码。

0、此例程调试环境 运行uname -a的结果如下: Linux freescale 3.0.35-2666-gbdde708-g6f31253 #1 SMP PREEMPT Thu Nov 30 15:45:33 CST 2017 armv7l GNU/Linux 简称2017 armv7l GNU/Linux 1、openssl 直接处理AES的API 在openssl/aes.h定义。是基本的AES库函数接口,可以直接调用,但是那个接口是没有填充的。而如果要与Java通信,必须要有填充模式。所以看第2条。 2、利用openssl EVP接口 在openssl/evp.h中定义。在这个接口中提供的AES是默认是pkcs5padding方式填充方案。 3、注意openssl新老版本的区别 看如下这段 One of the primary differences between master (OpenSSL 1.1.0) and the 1.0.2 version is that many types have been made opaque, i.e. applications are no longer allowed to look inside the internals of the structures. The biggest impact on applications is that: 1)You cannot instantiate these structures directly on the stack. So instead of: EVP_CIPHER_CTX ctx; you must instead do: EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); .... EVP_CIPHER_CTX_free(ctx); 2)You must only use the provided accessor functions to access the internals of the structure. 4、注意加密的内容是数据不限制是否为字符串 openssl接口加密的是数据,不限制是否为字符串,我看到有些人在加密时使用strlen(),来获取要加密的长度,如果是对字符串加密的话没有问题,如果不是字符串的话,用它获取的长度是到第一个0处,因为这个函数获取的是字符串长度,字符串是以零为终止的。 5、在调用EVP_EncryptFinal_ex时不要画蛇添足 正常加解密处理过程,引用网友的代码如下,经测试正确。 int kk_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_EncryptInit_ex(ctx, EVP_aes_128_ecb(), 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); return ciphertext_len; } int kk_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_DecryptInit_ex(ctx, EVP_aes_128_ecb(), 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); return plaintext_len; } 我看到有人提供的代码在加密长度正好是16字节的整数倍时特意不去调用EVP_EncryptFinal_ex,这实在是画蛇添足啊,不论什么情况下,最后一定要调用EVP_EncryptFinal_ex一次,然后结束加密过程。 6、Base64陷阱 如果用到了base64,要注意如下: 1)base64算法是将3个字节变成4个可显示字符。所以在如果数据长度不是3字节对齐时,会补0凑齐。 2)在解密时先要解base64,再解AES。在解base64后,要减掉补上的0。算法就去查看base64后的字符串尾处有几个=号,最多是2个,如果正好要加密的数据是3的倍数,不需要补0,那么base64后的数据尾处就没有=,如果补了1个0,就有一个=号。 算法如下: int encode_str_size = EVP_EncodeBlock(base64, en, el); int length = EVP_DecodeBlock(base64_out, base64, encode_str_size ); //EVP_DecodeBlock内部同样调用EVP_DecodeInit + EVP_DecodeUpdate + Evp_DecodeFinal实现,但是并未处理尾部的'='字符,因此结果字符串长度总是为3的倍数 while(base64[--encode_str_size] == '=') length--; 算法网友提供,测试正确。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值