文章介绍
- 本文章介绍了OpenSSL计算摘要算法(MD5、SHA1、SHA256、SHA512、SM3等)和Base64编解码的相关接口,并使用C语言实现了MD5摘要算法和Base64编解码算法。
摘要算法介绍
Base64编解码算法介绍
- Base64编码是一种将二进制数据转换为文本字符串的表示方法,常用于在电子邮件、网页以及其他使用ASCII字符的环境传输二进制数据。它通过将每3个字节(24位)的数据转换为4个可打印的ASCII字符来实现。如果原始数据不是3的倍数,会在末尾填充0位以达到长度要求。Base64编码表使用了A-Z、a-z、0-9以及+和/共64个字符。
OpenSSL介绍
- openssl是一个功能丰富且自包含的开源安全工具箱。它提供的主要功能有:SSL协议实现、对称/非对称加密算法、大数运算、非对称算法密钥生成、ASN.1编解码库、证书请求(PKCS10)编解码、数字证书编解码、CRL编解码、OCSP协议、数字证书验证、PKCS7标准实现和PKCS12个人数字证书格式实现等功能。
- openssl采用C语言作为开发语言,这使得它具有优秀的跨平台性能。openssl支持Linux、UNIX、windows、Mac等平台。
- github源码地址
- openssl_1.1.1u工程: 不知道如何集成Openssl工程的话, 可以下载我集成好的测试工程使用。
摘要算法相关API
EVP_MD_CTX_new
/* * @brief 创建摘要算法上下文 * @return 成功: 返回一个指向新分配的EVP_MD_CTX结构体的指针 * 失败: 返回NULL */ EVP_MD_CTX *EVP_MD_CTX_new();
EVP_DigestInit_ex
/* * @brief 摘要算法初始化 * @param [IN] ctx EVP_MD_CTX_new接口创建的上下文 * @param [IN] type 摘要算法类型, 较常用的有以下几种 * EVP_md5()、EVP_sha1()、EVP_sha256()、EVP_sha512()、EVP_sm3() * @param [IN] impl 用于指定一个特定的加密引擎实现。通常设置为NULL。 * @return 成功: 返回1 * 失败: 返回0 */ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl);
EVP_DigestUpdate
/* * @brief 计算摘要数据 * @param [IN] ctx EVP_MD_CTX_new接口创建的上下文 * @param [IN] d 需要计算的摘要原始数据 * @param [IN] cnt 原始数据长度 * @return 成功: 返回1 * 失败: 返回0 */ int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt);
EVP_DigestFinal_ex
/* * @brief 输出计算完成的摘要数据 * @param [IN] ctx EVP_MD_CTX_new接口创建的上下文 * @param [OUT] md 输出摘要数据缓冲区s * @param [OUT] s 输出摘要数据长度 * @return 成功: 返回1 * 失败: 返回0 */ int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s);
EVP_MD_CTX_free
/* * @brief 释放摘要上下文 * @param [IN] ctx EVP_MD_CTX_new接口创建的上下文 */ void EVP_MD_CTX_free(EVP_MD_CTX *ctx);
Base64编解码相关API
EVP_ENCODE_CTX_new
/* * @brief 创建Base64编解码算法上下文 * @return 成功: 返回一个指向新分配的EVP_ENCODE_CTX结构体的指针 * 失败: 返回NULL */ EVP_ENCODE_CTX *EVP_ENCODE_CTX_new();
EVP_EncodeInit
/* * @brief Base64 编码初始化 * @param [IN] ctx EVP_ENCODE_CTX_new 接口创建的上下文 */ void EVP_EncodeInit(EVP_ENCODE_CTX *ctx);
EVP_EncodeUpdate
/* * @brief 将数据分块进行 Base64 编码 * @param [IN] ctx EVP_ENCODE_CTX_new 接口创建的上下文 * @param [OUT] out 编码后的Base64数据 * @param [OUT] outl 编码后的Base64数据长度 * @param [IN] in 需要编码的原始数据 * @param [IN] inl 需要编码的原始数据长度 * @return 成功: 返回大于0的值 */ int EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl);
EVP_EncodeFinal
/* * @brief 处理剩余的编码数据和清理编码上下文 * @param [IN] ctx EVP_ENCODE_CTX_new 接口创建的上下文 * @param [OUT] out 剩余的Base64编码数据 * @param [OUT] outl 剩余的Base64编码数据长度 */ void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl);
EVP_DecodeInit
/* * @brief Base64 解码初始化 * @param [IN] ctx EVP_ENCODE_CTX_new 接口创建的上下文 */ void EVP_DecodeInit(EVP_ENCODE_CTX *ctx);
EVP_DecodeUpdate
/* * @brief 将数据分块进行 Base64 解码 * @param [IN] ctx EVP_ENCODE_CTX_new 接口创建的上下文 * @param [OUT] out 解码后的数据 * @param [OUT] outl 解码后的数据长度 * @param [IN] in 需要解码的Base64数据 * @param [IN] inl 需要解码的Base64数据长度 * @return 成功: 返回大于0的值 */ int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl);
EVP_DecodeFinal
/* * @brief 处理剩余的Base64解码数据和清理编码上下文 * @param [IN] ctx EVP_ENCODE_CTX_new 接口创建的上下文 * @param [OUT] out 剩余的解码后的数据 * @param [OUT] outl 剩余的解码后的数据长度 * @return 成功: 返回大于0的值 */ int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl);
/* * @brief 释放Base64编解码算法上下文 * @param [IN] ctx EVP_ENCODE_CTX_new接口创建的编解码算法上下文 */ void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx);
摘要算法实现代码
#include <openssl/evp.h> #include <stdio.h> #include <string.h> int main(){ EVP_MD_CTX* ctx = EVP_MD_CTX_new(); if(ctx == NULL){ printf("EVP_MD_CTX_new failed.\n"); return -1; } //设置摘要算法 if(EVP_DigestInit_ex(ctx, EVP_md5(), NULL) != 1){ printf("EVP_MD_CTX_new failed.\n"); EVP_MD_CTX_free(ctx); return -1; } //计算摘要 char inbuf[1024] = "Hello World"; if(EVP_DigestUpdate(ctx, inbuf, strlen((char*)inbuf)) != 1){ printf("EVP_DigestUpdate failed.\n"); EVP_MD_CTX_free(ctx); return -1; } //输出摘要值 unsigned char outbuf[1024] = { 0 }; unsigned int length = 0; if(EVP_DigestFinal_ex(ctx, outbuf, &length) != 1){ printf("EVP_DigestFinal_ex failed.\n"); EVP_MD_CTX_free(ctx); return -1; } // 16进制打印 for(int i = 0; i < length; i++){ printf("%.02x", outbuf[i]); } printf("\n"); EVP_MD_CTX_free(ctx); return 0; }
Base64编解码实现代码
#include <openssl/evp.h> #include <stdio.h> #include <string.h> int main(){ EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new(); if(ctx == NULL){ printf("EVP_ENCODE_CTX_new failed.\n"); return -1; } EVP_EncodeInit(ctx); char srcData[1024] = "Hello World"; int srcDataLen = strlen(srcData); char base64EnData[1024] = { 0 }; printf("srcData : %s\n", srcData); // 编码数据长度 int encryLength = 0; // 临时编码长度 int tempEncryLength = 0; // Base64编码 EVP_EncodeUpdate(ctx, (unsigned char*)base64EnData, &tempEncryLength, (unsigned char*)srcData, srcDataLen); encryLength = tempEncryLength; EVP_EncodeFinal(ctx, (unsigned char*)(base64EnData + tempEncryLength), &tempEncryLength); encryLength += tempEncryLength; printf("base64EnData : %s\n", base64EnData); EVP_DecodeInit(ctx); char base64DeData[1024] = { 0 }; // 解码数据长度 int decodeLength = 0; // 临时解码长度 int tempDecodeLength = 0; // Base64解码 EVP_DecodeUpdate(ctx, (unsigned char*)base64DeData, &tempDecodeLength, (unsigned char*)base64EnData, encryLength); decodeLength = tempDecodeLength; EVP_DecodeFinal(ctx, (unsigned char*)base64DeData + tempDecodeLength, &tempDecodeLength); decodeLength += tempDecodeLength; printf("base64DeData : %s\n", base64DeData); EVP_ENCODE_CTX_free(ctx); return 0; }