OpenSSL之API编程 - C/C++实现摘要算法和Base64编解码算法

发布于:2024-05-19 ⋅ 阅读:(160) ⋅ 点赞:(0)

文章介绍

  • 本文章介绍了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;
      }
    

网站公告

今日签到

点亮在社区的每一天
去签到