一、SM3算法介绍

SM3算法是中国国家密码管理局(OSCCA)于2010年发布的商用密码散列函数标准,属于我国自主设计的密码算法体系之一 ,标准文档下载地址为:SM3密码杂凑算法 。SM3算法输出长度为256位(32字节),与SHA-256类似,但采用了更适合国内安全需求的优化结构。SM3基于Merkle-Damgård迭代结构,通过填充、消息分组、扩展和压缩等步骤处理输入数据,确保任意长度的消息都能生成固定长度的摘要。作为我国密码行业标准(GM/T 0004-2012),SM3在政务、金融、物联网等领域广泛应用,是我国信息安全国产化的重要支撑。

SM3算法的核心流程包括消息填充、消息扩展和压缩函数三部分。首先,输入数据会被填充至512位的整数倍,并附加长度信息。随后,消息分组通过扩展算法生成132个32位字,供压缩函数使用。压缩函数采用64轮非线性迭代运算,结合与、或、异或、模2^{32}加法等操作,并引入多个常量进行混淆,确保雪崩效应(微小输入变化导致输出巨大差异)。SM3的设计在安全性和效率上取得平衡,能够有效抵抗碰撞攻击、长度扩展攻击等威胁。

二、C语言实现 

SM3算法的C语言实现主要由基础函数、核心处理流程和整体控制三部分组成。

1.  基础函数

在基础运算函数中,循环左移函数RL采用先左移再右移的组合方式实现32位字的循环移位,确保位移结果正确。Tj函数根据轮数返回不同的常量值,前16轮返回0x79cc4519,后续轮次返回0x7a879d8a。FF和GG这两个布尔函数通过条件判断自动切换运算逻辑,前者在后期采用(X&Y)|(X&Z)|(Y&Z),后者则使用(X&Y)|(~X&Z)。

2. 核心处理流程

核心处理函数sm3_one_block实现了算法的关键计算流程。消息扩展阶段先将输入的16个字存入数组,然后递归生成68个扩展字,每个新字由Wj0[i-16]、Wj0[i-9]和循环左移15位的Wj0[i-3]经过P1置换后,再与循环左移7位的Wj0[i-13]和Wj0[i-6]异或得到。

压缩阶段执行64轮迭代,每轮计算SS1和SS2两个中间值,其中SS1需要对A、E变量和Tj常量进行多重位移和模加运算。工作变量的更新采用级联方式,B、C、D依次赋值,F、G、H也类似处理,而A和E则分别接收TT1和P0(TT2)的新值。

3. 整体控制

主控函数sm3_get_hash负责处理输入数据的组织工作。对于完整的数据块直接调用sm3_one_block处理,对最后不足64字节的数据需要特殊处理。填充过程首先计算剩余数据长度,确定填充位的位置,在数据末尾添加0x80标志位,并用0x00填充剩余空间,最后64位存放原始消息长度的二进制表示。当剩余空间不足64位时,函数会先处理一个填充块,再单独处理一个包含长度信息的块。

具体代码如下:

#include<stdio.h>
#include<stdint.h>static const uint32_t IV[8] = {0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600,0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e
};uint32_t Tj(uint8_t j) {if (j < 16)return 0x79cc4519;return 0x7a879d8a;
}uint32_t FF(uint32_t X, uint32_t Y, uint32_t Z, uint8_t j) {if (j < 16)return X ^ Y ^ Z;return (X & Y) | (X & Z) | (Y & Z);
}uint32_t GG(uint32_t X, uint32_t Y, uint32_t Z, uint8_t j) {if (j < 16)return X ^ Y ^ Z;return (X & Y) | ((~X) & Z);
}uint32_t RL(uint32_t a, uint8_t k) {k = k % 32;return ((a << k) & 0xFFFFFFFF) | ((a & 0xFFFFFFFF) >> (32 - k));
}uint32_t P0(uint32_t X) {return X ^ (RL(X, 9)) ^ (RL(X, 17));
}uint32_t P1(uint32_t X) {return X ^ (RL(X, 15)) ^ (RL(X, 23));
}void sm3_one_block(uint32_t *hash, const uint32_t *block) {uint32_t Wj0[68];uint32_t Wj1[64];uint32_t A = hash[0], B = hash[1], C = hash[2], D = hash[3];uint32_t E = hash[4], F = hash[5], G = hash[6], H = hash[7];uint32_t SS1, SS2, TT1, TT2;uint8_t i, j;for (i = 0; i < 16; i++) {Wj0[i] = block[i];}for (i = 16; i < 68; i++) {Wj0[i] = P1(Wj0[i - 16] ^ Wj0[i - 9] ^ RL(Wj0[i - 3], 15)) ^ RL(Wj0[i - 13], 7) ^ Wj0[i - 6];}for (i = 0; i < 64; i++) {Wj1[i] = Wj0[i] ^ Wj0[i + 4];}for (j = 0; j < 64; j++) {SS1 = RL((RL(A, 12) + E + RL(Tj(j), j)) & 0xFFFFFFFF, 7);SS2 = SS1 ^ (RL(A, 12));TT1 = (FF(A, B, C, j) + D + SS2 + Wj1[j]) & 0xFFFFFFFF;TT2 = (GG(E, F, G, j) + H + SS1 + Wj0[j]) & 0xFFFFFFFF;D = C;C = RL(B, 9);B = A;A = TT1;H = G;G = RL(F, 19);F = E;E = P0(TT2);}hash[0] = (A ^ hash[0]);hash[1] = (B ^ hash[1]);hash[2] = (C ^ hash[2]);hash[3] = (D ^ hash[3]);hash[4] = (E ^ hash[4]);hash[5] = (F ^ hash[5]);hash[6] = (G ^ hash[6]);hash[7] = (H ^ hash[7]);
}void sm3_get_hash(uint32_t *src, uint32_t *hash, uint32_t len) {uint8_t last_block[64] = {0};uint32_t i = 0;for (i = 0; i < 8; i++) {hash[i] = IV[i];}for (i = 0; i < len; i = i + 64) {if (len - i < 64)break;sm3_one_block(hash, src + i);}uint32_t last_block_len = len - i;uint32_t word_len = ((last_block_len + 3) >> 2) << 2;uint32_t last_word_len = last_block_len & 3;for (int j = 0; j < word_len; j++)last_block[j] = *((uint8_t *) src + i + j);switch (last_word_len) {case 0:last_block[word_len + 3] = 0x80;break;case 1:last_block[word_len - 4] = 0;last_block[word_len - 3] = 0;last_block[word_len - 2] = 0x80;break;case 2:last_block[word_len - 4] = 0;last_block[word_len - 3] = 0x80;break;case 3:last_block[word_len - 4] = 0x80;break;default:break;}if (last_block_len < 56) {uint32_t bit_len = len << 3;last_block[63] = (bit_len >> 24) & 0xff;last_block[62] = (bit_len >> 16) & 0xff;last_block[61] = (bit_len >> 8) & 0xff;last_block[60] = (bit_len) & 0xff;sm3_one_block(hash, (uint32_t *) last_block);} else {sm3_one_block(hash, (uint32_t *) last_block);unsigned char lblock[64] = {0};uint32_t bit_len = len << 3;lblock[63] = (bit_len >> 24) & 0xff;lblock[62] = (bit_len >> 16) & 0xff;lblock[61] = (bit_len >> 8) & 0xff;lblock[60] = (bit_len) & 0xff;sm3_one_block(hash, (uint32_t *) lblock);}
}

三、正确性测试

我们编写了下面的代码进行正确性验证,这是SM3标准文档中的两个测试向量:

void test_case1() {uint32_t src[1] = {0x61626300};uint32_t hash[8];uint32_t len = 3;sm3_get_hash(src, hash, len);printf("hash(hex): ");for (int i = 0; i < 8; i++) {printf("%08x ", hash[i]);}printf("\n");
}void test_case2() {uint32_t src[16] = {0x61626364, 0x61626364, 0x61626364, 0x61626364, 0x61626364, 0x61626364, 0x61626364, 0x61626364,0x61626364, 0x61626364, 0x61626364, 0x61626364, 0x61626364, 0x61626364, 0x61626364, 0x61626364};uint32_t hash[8];uint32_t len = 64;sm3_get_hash(src, hash, len);printf("hash(hex): ");for (int i = 0; i < 8; i++) {printf("%08x ", hash[i]);}printf("\n");
}int main() {test_case1();test_case2();return 0;
}

代码执行结果如下,我们的代码通过了测试。

四、总结

本次实现的SM3算法C语言版本完整呈现了该密码哈希算法的核心机制。实现过程严格遵循标准规范,通过模块化设计将算法分解为初始化、消息扩展、压缩函数等关键组件。代码采用高效的位运算和指针操作,正确处理了消息填充、分组处理等边界情况。两个标准测试用例的验证结果表明,该实现正确产生了符合预期的哈希值。整体实现既保证了算法准确性,又展现了良好的代码结构和可读性,为后续的性能优化和应用集成奠定了坚实基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/85547.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/85547.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/85547.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

搜索二叉数(c++)

前言 在学习数据结构的时候我们学习过二叉树&#xff0c;那啥是搜索二叉树呢&#xff1f;我们知道单纯的二叉树没有增删查改的实际意义&#xff0c;因为没有任何限制条件的二叉树其实用处很局限。但是堆就不一样了&#xff0c;他就是一个二叉树加上了大小堆的限制条件&#xf…

vc MFC在opencv的Mat图像上显示中文:Mat转位MFC的CImage,画图写文字,再转回Mat

vc MFC在opencv的Mat图像上显示中文&#xff1a;Mat转位MFC的CImage&#xff0c;画图写文字&#xff0c;再转回Mat // Step 1 创建CImage获取dc int iImgW matImgSized.cols; int iImgH matImgSized.rows; int iChannel matImgSized.channels(); bool bCon matImgSized.is…

Docker环境部署

目录 一&#xff1a;Docker 概述 1.什么是 Docker 2:Docker 的优势 3.Docker 的应用场景 4:Docker 核心概念 二:Docker 安装 1:本安装方式使用阿里的软件仓库 三:Docker 镜像操作 1:获取镜像 2.查看镜像信息 3.查看镜像详细信息 4.修改镜像标签(老名字新名字) 5:删…

Axios 拦截器实现原理深度剖析:构建优雅的请求处理管道

在构建现代前端应用时&#xff0c;网络请求处理是关键环节。作为最流行的HTTP客户端库之一&#xff0c;Axios通过其拦截器机制&#xff08;Interceptors&#xff09;提供了强大的请求/响应处理能力。本文将深入Axios源码&#xff0c;揭示拦截器背后的精妙设计与实现原理。 一、…

宝塔安装nginx-http-flv-module,音视频直播,第二篇

1&#xff0c;先安装环境安装nginx 先卸载原有nigix nigix 大于等于 1.2.6 cd /www/server # 进入宝塔目录 yum install git -y git clone https://gitee.com/winshining/nginx-http-flv-module.git 使用源码安装nigix 在 自定义模块 区域点击「添加」&#xff0c;填写以下参…

低延迟4G专网:保障关键业务的实时通信

在工业互联网、智慧园区、应急通信等对“实时性”要求极高的场景中&#xff0c;网络延迟的高低&#xff0c;直接决定了业务运行的可靠性与安全性。IPLOOK依托多年核心网研发经验&#xff0c;推出的低延迟4G专网解决方案&#xff0c;正是为此类关键业务打造的“通信专线”&#…

NLP语言发展路径分享

自然语言处理初期发展历程 早期&#xff1a;离散表示 one-hot&#xff08;只表达“有/无”&#xff0c;语义完全丢失&#xff09;→ n-gram&#xff08;局部上下文&#xff0c;但高维稀疏&#xff09;→ TF-IDF&#xff08;考虑词频与权重&#xff0c;但不能表达词关联&#x…

如何将文件从安卓设备传输到电脑?

将文件从 Android 手机传输到 PC 是例行公事吗&#xff1f;想让文件传输更轻松吗&#xff1f;幸运的是&#xff0c;您可以从本文中获得 7 种方法&#xff0c;其中包含详细的步骤&#xff0c;帮助您轻松了解如何将文件从 Android 传输到 PC&#xff0c;涵盖了从无线工具到传统 U…

【经验分享】浅谈京东商品SKU接口的技术实现原理

京东商品 SKU 接口的技术实现原理涉及数据建模、架构设计、接口协议、安全机制及性能优化等多个技术层面。以下从技术角度详细拆解其实现逻辑&#xff1a; 一、SKU 数据模型与存储架构 1. SKU 数据模型设计 核心字段定义&#xff1a; 基础属性&#xff1a;SKU ID、商品名称、…

虚拟机配置node.js(前端环境搭建)

1.在windows下安装node.js&#xff08;以及npm&#xff09; 修改npm镜像为阿里云的 npm install --registryhttps://registry.npmmirror.com 2.在Linux下安装node.js&#xff08;Centos7 只支持16版本之前的&#xff09; wget https://npmmirror.com/mirrors/node/v15.14.0/n…

多模态大语言模型arxiv论文略读(129)

Task Success Prediction for Open-Vocabulary Manipulation Based on Multi-Level Aligned Representations ➡️ 论文标题&#xff1a;Task Success Prediction for Open-Vocabulary Manipulation Based on Multi-Level Aligned Representations ➡️ 论文作者&#xff1a;M…

【Redis】Redis 关于 BigKey 的实践规约

目录 一、BigKey 的概念 1.1 普通 key 的设计规则 1.2 BigKey 的定义 1.3 BigKey 存在的问题 二、BigKey 的发现与解决方案 第一种方式&#xff1a;redis-cli --bigkeys 第二种方式&#xff1a;scan扫描 第三种方式&#xff1a;第三方工具 第四种方式&#xff1a;网络…

Golang 与 C/C++ 交互实践

在软件开发的实际场景中&#xff0c;我们常常会遇到需要将不同语言的优势结合起来的情况。Golang 凭借其高效的并发性能和简洁的语法&#xff0c;在网络编程和系统开发领域备受青睐&#xff1b;而 C/C 则以其强大的底层操作能力&#xff0c;在系统资源管理方面具有独特优势。那…

五子棋流量主小程序单模式多模式开源版

功能和特点&#xff1a; 核心游戏功能&#xff1a; 1515 标准棋盘 黑白棋交替落子 自动判断胜负和平局 悔棋功能 计时功能 UI 设计&#xff1a; 木纹风格棋盘 立体感棋子&#xff08;使用阴影和渐变&#xff09; 响应式布局&#xff0c;适配不同屏幕尺寸 胜利弹窗动画 交互体验…

Python古代文物成分分析与鉴别研究:灰色关联度、岭回归、K-means聚类、决策树分析

原文链接&#xff1a;tecdat.cn/?p42718分析师&#xff1a;Gan Tian 在文化遗产保护领域&#xff0c;古代玻璃制品的成分分析一直是研究中西方文化交流的关键课题。作为数据科学家&#xff0c;我们在处理某博物馆委托的古代玻璃文物保护咨询项目时&#xff0c;发现传统分析方法…

RabbitMQ消息队列实战指南

RabbitMQ 是什么&#xff1f; RabbitMQ是一个遵循AMQP协议的消息中间件&#xff0c;它从生产者接收消息并传递给消费者&#xff0c;在这个过程中&#xff0c;根据路由规则进行消息的路由、缓存和持久化。 AMQP&#xff0c;高级消息队列协议&#xff0c;是应用层协议的一个开放…

用Java将PDF转换成GIF

为什么要将 PDF 文件转换为 GIF 图片&#xff1f; PDF 是一种矢量图像格式&#xff08;因此可以根据指定的尺寸进行渲染&#xff09;&#xff0c;而 GIF 是一种有损的、固定尺寸的位图文件&#xff0c;像素值固定。因此&#xff0c;将 PDF 转换为 GIF 文件时&#xff0c;我们需…

Redis之分布式锁(2)

上一篇文章我们介绍了什么是分布式锁和分布式锁的一些基本概念。这篇文章我们来讲解一下基于数据库如何实现分布式锁。 基于数据库实现分布式锁 基于数据库实现分布式锁可以分为两种方式&#xff0c;分别是基于数据库表和基于数据库排他锁。 基于数据库表 要实现分布式锁&…

智能检测护航电池产业:容量设备如何提升效率与安全?

电池容量是衡量其储能能力的重要指标&#xff0c;直接影响设备续航与使用寿命。电池容量检测设备通过模拟真实使用场景&#xff0c;精准测量电池的充放电性能&#xff0c;为电池生产、质检及回收环节提供关键数据支持&#xff0c;成为保障电池品质与安全的核心工具。 核心功能…

介绍一款免费MES、开源MES系统、MES源码

一、系统概述&#xff1a; 万界星空科技免费MES、开源MES、商业开源MES、市面上最好的开源MES、MES源代码、适合二开的开源MES。 1.万界星空开源MES制造执行系统的Java开源版本。 开源mes系统包括系统管理&#xff0c;车间基础数据管理&#xff0c;计划管理&#xff0c;物料控制…