前文<openssl-base64编码> 对base64原理和命令使用做了说明,本文对 openssl 的接口调用实现 base64 编解码操作。
openssl 提供两类 EVP 封装接口可进行 base64 编码,一种像摘要计算调用 EVP 接口一样,需要 init、update 等操作,此接口对于最终输出会进行格式化操作,每64个字符就会进行换行,具体示例代码如下:
// 省略错误判断
int base64_encode(unsigned char *p_in, size_t inlen, unsigned char *p_out, size_t *outlen)
{
EVP_ENCODE_CTX *ctx = NULL;
int total_len = 0;
int tmp_len = 0;
ctx = EVP_ENCODE_CTX_new();
EVP_EncodeInit(ctx);
EVP_EncodeUpdate(ctx, p_out, &tmp_len, p_in, inlen);
total_len += tmp_len;
EVP_EncodeFinal(ctx, p_out+total_len, &tmp_len);
total_len += tmp_len;
*outlen = total_len;
EVP_ENCODE_CTX_free(ctx);
return 0;
}
int base64_decode(unsigned char *p_in, size_t inlen, unsigned char *p_out, size_t *outlen)
{
EVP_ENCODE_CTX *ctx = NULL;
int total_len = 0;
int tmp_len = 0;
ctx = EVP_ENCODE_CTX_new();
EVP_DecodeInit(ctx);
EVP_DecodeUpdate(ctx, p_out, &tmp_len, p_in, inlen);
total_len += tmp_len;
EVP_DecodeFinal(ctx, p_out+total_len, &tmp_len); // 无实际数据要处理,tmp_len为0
total_len += tmp_len;
*outlen = total_len;
EVP_ENCODE_CTX_free(ctx);
return 0;
}
测试代码及执行结果:
int main(int argc, char const *argv[]) {
unsigned char str[] = {"1234567812345678123456781234567812345678123456781234567812345678"};
unsigned char in[1024] = {0};
unsigned char out[1024] = {0};
int outlen = sizeof(out);
int inlen = sizeof(in);
base64_encode(str, strlen(str), out, &outlen);
printf("out:\n%s\n", out);
base64_decode(out, outlen, in, &inlen);
printf("in:\n%s\n", in);
return 0;
}
// 运行结果
base64 $ ./a.out
out:
MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4
MTIzNDU2NzgxMjM0NTY3OA==
in:
1234567812345678123456781234567812345678123456781234567812345678
实际常用场景并不需要对输出结果进行格式化输出,所以编程会直接调用 EVP_EncodeBlock 完整编码操作,但解码操作结果长度,需要自己根据输入数据有多少字节进行了填充,进行相减,具体如下:
// 省略错误判断
int base64_encode(unsigned char *p_in, size_t inlen, unsigned char *p_out, size_t *outlen)
{
*outlen = EVP_EncodeBlock(p_out, p_in, inlen);
return 0;
}
int base64_decode(unsigned char *p_in, size_t inlen, unsigned char *p_out, size_t *outlen)
{
unsigned char *p = NULL;
int i = 0;
int pad = 0;
int len = 0;
p = p_in + inlen - 1;
for (i = 0; i < 4; i++)
{
if (*p == '=')
pad++;
p--;
}
printf("padlen:%d\n", pad);
len = EVP_DecodeBlock(p_out, p_in, inlen);
printf("len:%d\n", len);
*outlen = len - pad;
return 0;
}
测试代码及执行结果:
int main(int argc, char const *argv[]) {
unsigned char str[] = {"1234567812345678123456781234567812345678123456781234567812345678"};
unsigned char in[1024] = {0};
unsigned char out[1024] = {0};
int outlen = sizeof(out);
int inlen = sizeof(in);
base64_encode(str, strlen(str), out, &outlen);
printf("out:\n%s\n", out);
base64_decode(out, outlen, in, &inlen);
printf("inlen:%d; in:\n%s\n", inlen, in);
return 0;
}
// 运行结果
base64 $ ./a.out
out:
MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3OA==
padlen:2
len:66
inlen:64; in:
1234567812345678123456781234567812345678123456781234567812345678