openssl+sm3开发实例C++

一、SM3 介绍

SM3 是中国国家密码管理局(State Cryptography Administration,SCA)发布的一种密码散列函数,属于SHA-3 候选算法,也是我国的商用密码算法标准之一。SM3 是一种密码学安全性较高的密码散列函数,广泛应用于数字签名、消息认证码(MAC)等安全领域。

以下是 SM3 密码散列函数的主要知识点:

    1. 密码散列函数(Cryptographic Hash Function)
      SM3 是一种密码学安全性较高的密码散列函数,用于将任意长度的消息映射成固定长度的散列值(256 位)。它具有防碰撞(collision resistance)和前像抗性(pre-image resistance)等性质,能够抵抗碰撞攻击和查找原像攻击。
    1. 数据结构和运算规则
      SM3 使用了Merkle-Damgard结构,将消息分成512位的分组进行处理。它采用了置换(Substitution)和混淆(Permutation)运算,包括置换运算、非线性变换运算、消息扩展运算等。
    1. 消息填充
      SM3 使用了Bit Padding方式对消息进行填充,确保消息长度是512位的整数倍。
    1. 初始向量和常量
      SM3 使用了初始向量(IV)和常量,这些值在算法中起到了重要的作用,确保了算法的随机性和安全性。
    1. 算法安全性
      SM3 经过了广泛的密码学分析和测试,具有很高的安全性,适用于商用密码应用。它的安全性主要基于非线性置换运算和密集的非线性变换运算。
    1. 应用领域:
      SM3 算法被广泛应用于数字签名、消息认证码(MAC)、随机数生成、密钥派生等安全领域。它是中国国内的商用密码算法,也是一些国际标准中的选项之一。
    1. 国际标准:
      SM3 算法已经被ISO/IEC 中国国家标准(GB/T 32905-2016)采纳为国际标准,用于数字签名和验证。

二、SM3代码实例

2.1 SM3内容 hash

在 OpenSSL 中,你可以使用 EVP(Envelope)接口来进行 SM3 哈希计算。以下是一个简单的 OpenSSL SM3 哈希计算的示例代码:

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

void handleErrors(void)
{
    ERR_print_errors_fp(stderr);
    abort();
}

void sm3_hash(const unsigned char *input, size_t input_len, unsigned char *output)
{
    EVP_MD_CTX *mdctx;
    const EVP_MD *md;
    int md_len;

    md = EVP_sm3(); // 使用 SM3 算法
    mdctx = EVP_MD_CTX_new();
    if (mdctx == NULL)
        handleErrors();

    if (1 != EVP_DigestInit_ex(mdctx, md, NULL))
        handleErrors();

    if (1 != EVP_DigestUpdate(mdctx, input, input_len))
        handleErrors();

    if (1 != EVP_DigestFinal_ex(mdctx, output, &md_len))
        handleErrors();

    EVP_MD_CTX_free(mdctx);
}

int main(void)
{
    unsigned char data[] = "Hello, SM3!";
    unsigned char hash_value[EVP_MAX_MD_SIZE];
    int i;

    printf("Original Data: %s\n", data);

    sm3_hash(data, strlen((char *)data), hash_value);

    printf("SM3 Hash Value: ");
    for (i = 0; i < EVP_MD_size(EVP_sm3()); i++)
        printf("%02x", hash_value[i]);
    printf("\n");

    return 0;
}
  • 代码编译
g++ -o main main.cpp -lssl -lcrypto
  • 执行结果
    在这里插入图片描述

在此代码中,我们使用了 OpenSSL 的 EVP 接口来计算 SM3 哈希值。函数 sm3_hash 接受输入数据和其长度,然后计算 SM3 哈希值并将结果存储在 output 中。在 main 函数中,我们提供了一个简单的字符串作为输入数据,计算它的 SM3 哈希值并将结果输出。请确保你的系统上已经正确安装了 OpenSSL 库。

2.2 SM3文件 hash

要使用 OpenSSL 计算文件的 SM3 哈希值,你可以使用以下的代码示例。这个示例会读取文件的内容并计算它的 SM3 哈希值:

#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/err.h>
#include <stdio.h>
#include <stdlib.h>

void handleErrors(void)
{
    ERR_print_errors_fp(stderr);
    abort();
}

void sm3_file_hash(const char *file_path, unsigned char *output)
{
    FILE *file = fopen(file_path, "rb");
    if (file == NULL)
    {
        perror("Error opening file");
        handleErrors();
    }

    EVP_MD_CTX *mdctx;
    const EVP_MD *md;
    unsigned int md_len;
    unsigned char buffer[1024];

    md = EVP_sm3(); // 使用 SM3 算法
    mdctx = EVP_MD_CTX_new();
    if (mdctx == NULL)
        handleErrors();

    if (1 != EVP_DigestInit_ex(mdctx, md, NULL))
        handleErrors();

    size_t bytes;
    while ((bytes = fread(buffer, 1, sizeof(buffer), file)) != 0)
    {
        if (1 != EVP_DigestUpdate(mdctx, buffer, bytes))
            handleErrors();
    }

    if (1 != EVP_DigestFinal_ex(mdctx, output, &md_len))
        handleErrors();

    fclose(file);
    EVP_MD_CTX_free(mdctx);
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s <file_path>\n", argv[0]);
        return 1;
    }

    const char *file_path = argv[1];
    unsigned char hash_value[EVP_MAX_MD_SIZE];
    int i;

    sm3_file_hash(file_path, hash_value);

    printf("SM3 Hash Value: ");
    for (i = 0; i < EVP_MD_size(EVP_sm3()); i++)
        printf("%02x", hash_value[i]);
    printf("\n");

    return 0;
}

在这个示例中,sm3_file_hash 函数接受文件路径作为输入,然后计算文件的 SM3 哈希值并将结果存储在 output 中。在 main 函数中,我们通过命令行参数传递文件路径,并计算文件的 SM3 哈希值。

请确保在编译时链接 OpenSSL 库。你可以使用以下命令进行编译:

g++ -o main main.cpp -lssl -lcrypto
  • 运行结果
    在这里插入图片描述

其中,sm3hash.c 是包含上述代码的源文件,-lssl-lcrypto 用于链接 OpenSSL 库。编译后,你可以通过命令行运行可执行文件,指定要计算 SM3 哈希值的文件路径。

三、代码地址

https://gitcode.net/arv002/qt/-/tree/master/Openssl/hash/sm3

三、补充知识

1、Bit Padding

Bit Padding(比特填充)是一种在密码学中常用的数据填充方式,通常用于将不定长的数据(比如消息)扩展为固定长度的块,以便进行加密或哈希处理。在使用密码散列函数(如MD5、SHA-1、SHA-256、SM3等)处理不定长数据时,需要将数据填充至块的整数倍长度,而Bit Padding是其中一种填充方法。

Bit Padding 的具体步骤如下:

  1. 在消息末尾加入一个比特"1"。例如,如果原始消息以0110 1101结尾,添加比特"1"后为0110 1101 1

  2. 在上一步骤的结果后面填充零(“0”),直到消息的总长度(包括填充位)满足块长度的要求。例如,如果块长度为512比特,而消息长度(包括填充位和"1"位)为510比特,那么还需填充2个零。

  3. 在填充的零位之后,附加一个整数(以二进制形式表示)来表示原始消息的长度。通常,这个整数是原始消息的比特数,以64位(或128位,具体取决于算法)的形式表示。这一步骤确保了在处理时可以知道原始消息的实际长度。

举个例子,如果原始消息的长度为417比特,算法需要使用512比特的块进行处理,那么Bit Padding的步骤如下:

  1. 原始消息末尾添加比特"1":...111 0101 01 1

  2. 在上一步骤的结果后填充零,直到总长度为512比特:...111 0101 01 1000 0000

  3. 在填充的零位之后附加消息的长度,长度为417的二进制表示为1101 0001,所以填充后的消息为:...111 0101 01 1000 0000 0000 0000 1101 0001

这样,填充后的消息长度满足块长度(512比特)的要求,并且算法在处理时可以知道原始消息的实际长度。填充的过程保证了消息在进行密码学操作时的标准化处理,确保了数据的完整性和安全性。

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

N阶二进制

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值