栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

OpenSSL-3.0.3编程—计算数据摘要

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

OpenSSL-3.0.3编程—计算数据摘要

文章目录
  • 直接使用openssl API进行摘要计算
  • 封装 openssl API 摘要计算C++
    • 定义摘要算法枚举,文件名DigestAlgo.h
    • 实现枚举类头文件中的全局函数,重载 << 运算符,文件名DigestAlgo.cpp
    • 封装摘要类,文件名Digest.h
    • 摘要类实现,文件名Digest.cpp
    • `摘要实现类简要说明`
  • 使用 Digest 类计算摘要
  • 总结

直接使用openssl API进行摘要计算

直接使用openssl API 计算摘要一般包含如下三个步骤

  1. 初始化指定摘要算法的上下文
  2. 更新数据。可以添加多次,比如"hello, world" 可以分两次更新,可以参考如下代码
  3. 计算摘要值。对第2步更新的所有的数据计算摘要,通过传出参数返回摘要值
  4. 将第3步计算的二进制摘要值转换为十六进制或Base64输出,本步骤可省略,看具体需要采用合适的方式

对下面的代码进行简单说明。SHA_DIGEST_LENGTH 是 openssl 里面定义的一个宏,表示SHA1算法的摘要值字节数20。将二进制字节流数据转换为十六进制字符串,该字符串的长度是二进制字节流长度的二倍,所以字符串数组(指针) result 的长度 = SHA_DIGEST_LENGTH * 2 + 1,多出来的 1 是 C 字符串的结尾符

#include 
#include 
#include 

void sha1Test(){
    // 1.初始化
    SHA_CTX ctx;
    SHA1_Init(&ctx);
    // 2.添加数据
    SHA1_Update(&ctx, "hello", strlen("hello"));
    SHA1_Update(&ctx, ", world", strlen(", world"));
    // 3.哈希计算
    unsigned char* md = new unsigned char[SHA_DIGEST_LENGTH];
    SHA1_Final(md, &ctx);
    // 4.将 md 二进制数据转十六进制
    char* result = new char[SHA_DIGEST_LENGTH * 2 + 1];
    for (int i = 0; i < SHA_DIGEST_LENGTH; ++i) {
        sprintf(&result[i * 2], "%02x", md[i]);
    }
    std::cout << "sha1: " << result << std::endl;
    delete[] md;
    delete[] result;
}

int main(int argc, char* argv[]){
    sha1Test();
	return 0;
}
封装 openssl API 摘要计算C++ 定义摘要算法枚举,文件名DigestAlgo.h
#ifndef OPENSSL_01_DIGESTALGO_H
#define OPENSSL_01_DIGESTALGO_H

#include 

enum class DigestAlgo {
    MD5,
    SHA1,
    SHA224,
    SHA256,
    SHA384,
    SHA512
};


std::ostream& operator<<(std::ostream& os, const DigestAlgo& algo);

#endif //OPENSSL_01_DIGESTALGO_H
实现枚举类头文件中的全局函数,重载 << 运算符,文件名DigestAlgo.cpp
#include "DigestAlgo.h"

std::ostream& operator<<(std::ostream& os, const DigestAlgo& algo){
    switch (algo) {
        case DigestAlgo::MD5:
            os << "MD5";
            break;
        case DigestAlgo::SHA1:
            os << "SHA1";
            break;
        case DigestAlgo::SHA224:
            os << "SHA224";
            break;
        case DigestAlgo::SHA256:
            os << "SHA256";
            break;
        case DigestAlgo::SHA384:
            os << "SHA384";
            break;
        case DigestAlgo::SHA512:
            os << "SHA512";
            break;
        default:
            os << "摘要算法名错误!";
            break;
    }
    os << std::endl;
    return os;
}
封装摘要类,文件名Digest.h
#ifndef OPENSSL_01_DIGEST_H
#define OPENSSL_01_DIGEST_H

#include 
#include 
#include 
#include "DigestAlgo.h"

class Digest {
public:
    
    explicit Digest(DigestAlgo algo);

    ~Digest();

    
    int digest_update(const std::string& str);

    
    int digest_final();

    
    void showDigestHex();

private:
    MD5_CTX md5Ctx;
    SHA_CTX shaCtx;
    SHA256_CTX sha224Ctx;
    SHA256_CTX sha256Ctx;
    SHA512_CTX sha384Ctx;
    SHA512_CTX sha512Ctx;

    unsigned char* md;
    char* mdHex;
    int digestLength;

    DigestAlgo digestAlgo;
};

#endif //OPENSSL_01_DIGEST_H
摘要类实现,文件名Digest.cpp
#include 
#include 
#include "Digest.h"

using std::string;
using std::cout;
using std::endl;

Digest::Digest(DigestAlgo algo) : digestAlgo(algo) {
    cout << "构造函数调用,摘要算法: " << algo;
    int ret = 0;
    switch (algo) {
        case DigestAlgo::MD5:
            ret = MD5_Init(&md5Ctx);
            break;
        case DigestAlgo::SHA1:
            ret = SHA1_Init(&shaCtx);
            break;
        case DigestAlgo::SHA224:
            ret = SHA224_Init(&sha224Ctx);
            break;
        case DigestAlgo::SHA256:
            ret = SHA256_Init(&sha256Ctx);
            break;
        case DigestAlgo::SHA384:
            ret = SHA384_Init(&sha384Ctx);
            break;
        case DigestAlgo::SHA512:
            ret = SHA512_Init(&sha512Ctx);
            break;
        default:
            cout << "摘要算法类型错误..." << endl;
            exit(EXIT_FAILURE);
    }
    if (ret != 1) {
        cout << "初始化摘要算法上下午错误,错误码: " << ret << endl;
        exit(EXIT_FAILURE);
    }
}

Digest::~Digest() {
    cout << "析构函数调用..." << endl;
    delete[] md;
    delete[] mdHex;
}

int Digest::digest_update(const string& str) {
    int ret = 0;
    switch (digestAlgo) {
        case DigestAlgo::MD5:
            ret = MD5_Update(&md5Ctx, str.c_str(), str.size());
            break;
        case DigestAlgo::SHA1:
            ret = SHA1_Update(&shaCtx, str.c_str(), str.size());
            break;
        case DigestAlgo::SHA224:
            ret = SHA224_Update(&sha224Ctx, str.c_str(), str.size());
            break;
        case DigestAlgo::SHA256:
            ret = SHA256_Update(&sha256Ctx, str.c_str(), str.size());
            break;
        case DigestAlgo::SHA384:
            ret = SHA384_Update(&sha384Ctx, str.c_str(), str.size());
            break;
        case DigestAlgo::SHA512:
            ret = SHA512_Update(&sha512Ctx, str.c_str(), str.size());
            break;
        default:
            cout << "摘要算法类型错误..." << endl;
            exit(EXIT_FAILURE);
    }
    if (ret != 1) {
        cout << "更新摘要数据错误,错误码: " << ret << endl;
        exit(EXIT_FAILURE);
    }
    return ret;
}

int Digest::digest_final() {
    int ret = 0;
    switch (digestAlgo) {
        case DigestAlgo::MD5:
            digestLength = MD5_DIGEST_LENGTH;
            md = new unsigned char[MD5_DIGEST_LENGTH];
            ret = MD5_Final(md, &md5Ctx);
            break;
        case DigestAlgo::SHA1:
            digestLength = SHA_DIGEST_LENGTH;
            md = new unsigned char[SHA_DIGEST_LENGTH];
            ret = SHA1_Final(md, &shaCtx);
            break;
        case DigestAlgo::SHA224:
            digestLength = SHA224_DIGEST_LENGTH;
            md = new unsigned char[SHA224_DIGEST_LENGTH];
            ret = SHA224_Final(md, &sha224Ctx);
            break;
        case DigestAlgo::SHA256:
            digestLength = SHA256_DIGEST_LENGTH;
            md = new unsigned char[SHA256_DIGEST_LENGTH];
            ret = SHA256_Final(md, &sha256Ctx);
            break;
        case DigestAlgo::SHA384:
            digestLength = SHA384_DIGEST_LENGTH;
            md = new unsigned char[SHA384_DIGEST_LENGTH];
            ret = SHA384_Final(md, &sha384Ctx);
            break;
        case DigestAlgo::SHA512:
            digestLength = SHA512_DIGEST_LENGTH;
            md = new unsigned char[SHA512_DIGEST_LENGTH];
            ret = SHA512_Final(md, &sha512Ctx);
            break;
        default:
            cout << "摘要算法类型错误..." << endl;
            exit(EXIT_FAILURE);
    }
    if (ret != 1) {
        cout << "计算摘要值错误,错误码: " << ret << endl;
        exit(EXIT_FAILURE);
    }
    return ret;
}

void Digest::showDigestHex() {
    mdHex = new char[digestLength * 2 + 1];
    for (int i = 0; i < digestLength; ++i) {
        sprintf(&mdHex[i * 2], "%02x", md[i]);
    }
    cout << "摘要值: " << mdHex << std::endl;
}
摘要实现类简要说明

Digest 类在原始 API 基础上封装了 MD5、SHA1、SHA224、SHA256、SHA384、SHA512 这些基本的摘要算法,其他的如 MD2、MD4 没记录进去,不过写法都类似

函数 XXX_Init 接收一个上下文参数地址,返回值 1 表示成功,其他值失败

函数 XXX_Update 接收三个参数

  • 参数1: 上下文参数
  • 参数2: 原文数据,类型为 const void *
  • 参数3: 原文数据字节长度,如果为C风格字符串,不包含结尾符

函数 XXX_Final 接收两个参数

  • 参数1: 传出参数,类型为 unsigned char *
  • 参数2: 上下文参数
使用 Digest 类计算摘要
#include "Digest.h"

int main(int argc, char* argv[]){
    using std::string;
    using std::cout;
    using std::endl;

    Digest digest(DigestAlgo::SHA256);
    string plaintext = "123456";
    digest.digest_update(plaintext);
    digest.digest_final();
    digest.showDigestHex();
	return 0;
}

通过修改构造函数参数,可以进行 MD5、SHA1、SHA224、SHA256、SHA384、SHA512 摘要计算,其他地方不变


总结

记录了 openssl 摘要相关 API 的使用,并将摘要计算封装成 C++ 类,以及如何使用。遗憾的是 OpenSSL已经不推荐直接使用 XXX_Init、XXX_Update、XXX_Final 这些底层的 API 了,应该是都封装成各种 EVP 函数了,我正在研究 openssl, 后续的博文中会将新的使用方法记录上

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/994398.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号