资讯动态

哈希算法双雄:SHA-256与SHA-3的对比与选型

发布时间:2026/9/10 7:16:20 来源:尧图企业网站定制
SHA-256和SHA-3两个词在开发者社区里出镜率极高。有人把它们当成同一件事的两代版本觉得SHA-3一定更好有人以为哈希算法就是加密能把密码变成一串看不懂的字符串还有人到现在都分不清大写的SHA-3和以太坊里那个Keccak-256到底差在哪。我参与过不少系统安全评审几乎每次都要先花几分钟把这些概念捋直因为很多所谓的安全隐患根源不在代码而在对哈希算法本质的误解。这篇文章不绕弯子把SHA-256和SHA-3这两套当今最重要的哈希算法家族从头拆开它们各自怎么来的、内部结构有什么根本差异、性能和安全性如何对比、项目选型到底该听谁的。适合所有写代码会碰到哈希的开发者、做架构决策的技术负责人以及想系统理解哈希算法的安全从业者。1. 哈希函数到底在做什么先把这个基础说透1.1 四个核心性质决定了哈希的人设哈希函数做的事情一句话就能说清把任意长度的输入压缩成固定长度的输出这个输出一般叫摘要digest。但压缩不是它的全部真正让它变成密码学工具的是下面四个性质。第一是确定性。同一个输入不管跑到哪台机器上算永远得到同一个摘要。这是所有校验类应用的地基。第二是抗原像单向性。给你一个摘要你几乎不可能反推出原始输入。第三是抗第二原像。已知某个输入和它的摘要你找不到另一个不同输入使得摘要相同。第四是抗碰撞。你找不到任意两个不同输入让它们的摘要一样。这四个性质听起来简单实际含义很深。比如抗碰撞这件事重点不在于很难碰巧撞上而在于刻意去找也找不到。哪怕设计者本人想伪造一对碰撞在安全强度足够的前提下也是计算上不可行的。还有个常被忽略的雪崩效应输入哪怕只翻转一个bit输出的摘要都会面目全非。这个特性保证了局部的微小差异不会被局部地反映到摘要里否则哈希函数很容易被统计分析攻破。1.2 哈希不是加密两者方向完全相反很多人把哈希和加密混在一谈。加密是可逆的你有密钥就能把密文还原成明文。哈希是不可逆的输入到摘要是一条单行道没有密钥一说也没有还原操作。你可以把哈希理解成一个粉碎机而不是一个保险箱文件进去出来的是固定长度的指纹原始内容已经无法恢复。这个误解带来一个非常典型的错误有些系统把用户密码直接做一次SHA-256就存进数据库以为这就是安全存储了。问题是SHA-256太快了普通GPU一秒钟能算几十亿次拿到哈希值列表的攻方可以瞬间跑完整个字典。诚实的建议是存密码要用专门的慢速KDF比如bcrypt、scrypt、argon2它们故意设计成计算成本高昂让暴力破解的性价比降到极低。SHA-256这样的通用哈希在密码存储场景里反而不合适。这是我在评审中见到最多的认知偏差先在这里敲个警钟。1.3 哈希真实落地的地方在正确理解了哈希的本质之后它的应用场景其实非常广文件完整性与数据校验下载镜像后比对摘要确认文件没有被篡改或传输损坏。数字签名先对消息做哈希摘要再对摘要签名。签名算法处理固定长度的摘要性能和安全边界都更好控制。Merkle树与区块链把一批数据的哈希逐层归并成一棵哈希树根哈希可以代表整批数据。比特币、Git、分布式存储都用这个思路。消息认证码HMAC用密钥参与哈希计算验证消息的来源和完整性。去重与内容寻址内容相同即摘要相同可以直接用摘要作为地址节省存储。对这些场景SHA-256和SHA-3都是合格的选手。但合格背后两者的设计哲学和工程特征差异巨大这就是下面要展开的核心内容。2. SHA-256的身世从MD5到行业默认的演进路径2.1 前辈们是怎么倒下的SHA-256不是从石头缝里蹦出来的。它是哈希算法谱系里的后辈这个谱系最早是MD4、MD5和SHA-1。MD5在上世纪90年代一度是绝对主流128位摘要速度快到处都是。2004年王小云团队给出了MD5的碰撞攻击方法此后攻击不断改进。2007年前后选择前缀碰撞也从理论变成现实攻击者甚至可以构造两个攻击者自选内容的文件让它们的MD5相同。2012年的Flame恶意软件利用伪造的MD5签名证书让整个业界彻底正视了MD5的死亡。SHA-1是接替MD5的正统传承160位摘要同样采用Merkle-Damgård迭代结构身处同一套设计框架内。2005年出现了理论攻击2017年Google和CWI研究所发布了SHAttered两个内容不同的PDF文件拥有同一个完整SHA-1哈希。这是全世界第一次看到完整的SHA-1碰撞也宣告了SHA-1在抗碰撞层面已经失去意义。回头看这段历史教训很清楚设计者的智力再高也挡不住后来者几十年的持续分析。所以哈希算法领域形成了一条潜规则——不要只押注一种结构要在安全边际上留足余量。2.2 SHA-2家族和SHA-256为什么笑到了最后SHA-2是NSA设计、NIST发布的家族包含SHA-224、SHA-256、SHA-384、SHA-512等变体2001年正式进入FIPS 180-2标准。它延续了Merkle-Damgård的迭代思路但在细节上做了大量加固更长的摘要长度、更强的消息扩展算法、更复杂的压缩函数轮函数。SHA-256之所以成为行业默认有几个很现实的推力。首先是安全强度的甜点位256位摘要意味着128位的碰撞安全强度刚好和AES-128密钥强度对齐被业界广泛接受。其次是硬件生态近十年来的x86处理器普遍内置了SHA-NI指令集SHA-256在有硬件加速的CPU上速度快得离谱这在软件层面对其他哈希形成了碾压性优势。再其次是协议生态TLS 1.2/1.3、X.509证书、Git、Bitcoin全都深度绑定了SHA-256一旦成了事实标准迁移成本就不是单个项目能承受的了。有个细节值得展开SHA-512在纯软件环境下的速度其实经常比SHA-256还快因为它一次处理64位字和更大的消息块轮数与数据块的比例更优。但SHA-512的摘要太长不是所有场景都方便。于是标准里还有个冷门变体SHA-512/256取SHA-512的输出截断为256位既保留了64位路径的高性能又规避了传统Merkle-Damgård结构在输出与内部状态一致时带来的长度扩展问题。如果你的项目想在纯软件环境里用SHA-2家族SHA-512/256值得多看一眼。2.3 安全强度的标尺生日界与128位碰撞安全为什么要强调256位摘要只提供128位碰撞安全这里面的数学很关键。按生日悖论给定一个n位输出的哈希函数随机找大约2^(n/2)个输入就有很大概率发生一次碰撞。所以对256位输出来说找碰撞的通用攻击复杂度是2^128。这依然是天文数字但和很多人直觉里256位就是2^256强度的想象差了一倍。记住这条标尺摘要位数减半才是实际的碰撞安全强度。量子计算的影响也顺带提一句Grover算法可以把抗原像搜索从2^256降低到2^128虽然对现代密码系统还构不成现实威胁但这也意味着密码学家在设计新算法时普遍会刻意拉高安全边际而不是算着刚好够用就行。3. SHA-3诞生的真正原因一场没有受害者的危机3.1 2000年代中期哈希算法的危机前夜SHA-3的诞生背景可能是整个密码学史上最特别的一幕它不是因为有谁被攻破了才启动的而是在SHA-256依然安全的时期学术界和标准化机构主动发起的备胎计划。2004到2008年是哈希算法的多事之秋。MD5碎了SHA-1的理论进展不断更麻烦的是针对Merkle-Damgård这个框架本身的结构性攻击陆续出现Joux的多碰撞攻击、Kelsey-Schneier的多次原像攻击、herding攻击牧群攻击。这些攻击当时还没有威胁到SHA-256的实际安全但它们揭示了一个令人不安的事实所有采用Merkle-Damgård结构的迭代哈希理论上共享某些结构弱点。如果有一天攻击者找到一个能同时打穿Merkle-Damgård家族的通杀方法整个基于SHA-2的生态都会瞬间暴露。这个风险比单个算法被攻破更让密码学家睡不着。3.2 五年的公开竞赛Keccak如何胜出NIST在2007年宣布举办哈希算法公开竞赛目的非常明确选出一个结构上与SHA-2完全不同、能长期作为平行替补的新标准。全球共收到64份候选设计第一轮过后剩51个第二轮收敛到14个第三轮留下5个决赛选手BLAKE、Grøstl、JH、Keccak和Skein。2012年10月NIST宣布Keccak胜出2015年8月发布正式标准FIPS 202也就是我们今天说的SHA-3。Keccak由Guido Bertoni、Joan Daemen、Michaël Peeters和Gilles Van Assche设计。Joan Daemen正是AES加密标准的设计者之一这个出身让它天然带了一层光环。它在五个决赛选手里是结构差异最大的一位不依赖Merkle-Damgård链式迭代而是基于一种全新的海绵构造Sponge Construction。它的轮函数Keccak-f极度规整分析者可以把攻击焦点集中在一个纯粹置换上安全性论证非常清晰。再加上它可以输出任意长度摘要、支持可扩展输出函数设计弹性远超其他决赛者。最终NIST选择它很大程度上就是看中了这种换个活法的结构多样性。3.3 备胎逻辑不是替代逻辑理解SHA-3的存在价值必须放下新版替代旧版的思维惯性。NIST从未宣布SHA-256退休直到今天FIPS 180-4和FIPS 202并列有效SHA-256和SHA-3是平等的两个标准。SHA-3的定位从一开始就是平行备胎万一未来真的出现了针对Merkle-Damgård家族的通用攻击整个社会还能无缝切换到一点也不一样的SHA-3。这也是双雄并立这个说法的真正来源。双雄不是新旧之争而是两条不同的技术路线并行服役互为备份。今天你用SHA-256不代表你比用SHA-3的人落后你用SHA-3也不意味着你比前者激进多少。理解这层背景后面的选型章节才讲得通。4. Merkle-Damgård与海绵构造两代设计的分水岭4.1 SHA-256内部一台链式压路机SHA-256的处理过程可以拆成三步。首先做填充在消息末尾先补一个bit的1再补一串0最后补64位的原始消息长度按bit计让总长度正好是512的整数倍。注意即便消息长度恰好命中512的倍数也必须执行填充这是为了消除长度边界歧义。然后按512位一块切分消息。最后逐块送入压缩函数当前512位块和上一轮得到的256位链值一起经过64轮轮函数运算得到新的256位链值。内部细节是这样的压缩函数把512位消息块扩展成64个32位字的消息调度表然后每一轮用Ch、Maj、Σ0、Σ1这些位运算组合配合64个预先定义好的K常量做混合。本质上SHA-256是把一个精心设计的密码学轮函数反复碾压64次再与上一轮的链值相加。每一块的输出都依赖前面所有块的状态这就是Merkle-Damgård的链的含义任何一块被篡改后续所有链值都会变最终摘要必然不同。但也正因为如此SHA-256没法天然并行只能老老实实一块接一块地跑。4.2 SHA-3内部一块会吸水的海绵SHA-3的路子完全不同。它维护一个1600位的宽状态这个状态在概念上被分成两部分收取输入的rate部分和负责安全保障的capacity部分。rate加capacity等于1600不同变体切分比例不同。海绵构造分两个阶段。吸收阶段把消息填充后按rate大小切块每块先与rate部分做异或再对整个1600位状态执行一次Keccak-f置换如此循环直到消息全部吸收完毕。挤压阶段从状态中抽取rate位作为输出如果输出长度超出rate就再执行一次置换继续抽取直到凑够想要的长度。这个设计直观理解就是海绵吸水再挤水简单、优雅而且天然支持任意长度输出。具体到标准变体参数分配如下表算法rate字节capacity字节目标安全强度SHA3-22414428112位碰撞/224位原像SHA3-25613664128位碰撞/256位原像SHA3-38410496192位碰撞/384位原像SHA3-51272128256位碰撞/512位原像SHAKE12816832128位安全SHAKE25613664256位安全Keccak-f置换的核心是24轮完全相同的轮函数每轮由θ、ρ、π、χ、ι五个步骤组成基本操作就是64位字的异或、循环移位和按位逻辑。整个轮函数没有加法进位没有条件分支非常适合硬件并行化也方便写成抗侧信道的恒定时间实现。SHA-3的安全论证从来没有把宝押在复杂的消息扩展上而是押在一个纯粹置换的混淆扩散能力上——这跟SHA-256的哲学是根本性的不同。4.3 长度扩展攻击MD结构绕不过去的坎Merkle-Damgård结构有个著名的结构性缺陷长度扩展攻击。因为哈希函数的输出就是内部链值的最终态攻击者在不知道原始消息m的情况下只要拿到H(m)就能构造出H(m‖填充‖追加内容)。这个攻击不需要破解任何东西纯粹是结构上的洞。最常见的受害场景是密钥消息的朴素MAC构造MACH(secret‖message)。攻击者虽然不知道secret但可以根据已获知的MAC值在消息后面拼接内容并计算出合法的拼接后MAC等于绕过了完整性验证。这也是为什么业界必须发明HMAC它要做两次哈希包裹就是为了消除长度扩展攻击的可能性。如果你坚持用SHA-256并想避免这个坑可以选择HMAC-SHA-256或者改用SHA-512/256这类输出不等于内部全状态的截断变体。SHA-3天然免疫长度扩展攻击。原因是输出只来自状态里的rate部分capacity部分从不公开。攻击者从摘要里只能反向恢复rate那部分无法拼齐整个1600位状态自然也就没法在海绵上续写。这是我个人认为SHA-3最值得称道的设计成果它从源头消灭了一整类攻击而不是通过外部包装来修补。5. 工程视角下的实测对比性能、安全性与生态位5.1 性能SHA-NI让SHA-256在通用CPU上开挂聊性能不能脱离硬件谈。在通用x86 CPU上SHA-256是吃了硬件加速红利的SHA-NI指令集让它在不碰内存的情况下完成核心轮运算吞吐量可以做到每秒数GB级别。SHA-3目前没有这么普及的原生硬件指令支持纯软件优化下它的吞吐量通常在每秒几百MB到1GB出头的量级视实现质量而定。也就是说在大多数服务器和桌面场景里SHA-256实测更快这个差距在大规模哈希场景下是能明显感知的。这里有三个补充观察。第一SHA-512在64位平台上的纯软件速度往往超过SHA-256因为它一轮处理64位字轮数相对更少。如果不介意摘要太长SHA-512是纯软件场景里SHA-2家族中性能更优的选择。第二SHA-3在嵌入式平台上的表现比在PC上更值得期待。Keccak置换全是位运算和小状态操作对硬件面积和功耗非常友好在一些MCU和FPGA上SHA-3的性能反而不输甚至超过SHA-256。当然32位MCU处理1600位状态里的64位lane需要额外小心搞不好就要做位交织优化否则吞吐量会掉得很厉害。第三SHA-3软件实现的上限很大程度上取决于对Keccak-f置换的优化程度。用最普通的朴素写法跑结果一定难看用了成熟的位切片或向量化实现差距会缩小很多。所以比较性能时别拿一个没优化的开源小库当结论多测两个成熟实现再下判断。5.2 安全边际一个赌经验一个赌结构SHA-256的安全背书来自二十年以上的持续分析和实战检验。到今天完整轮数的SHA-256没有任何可行的攻击方法这一点基本可以放心。但它的软肋在于结构层面长度扩展、多碰撞、牧群攻击等对Merkle-Damgård家族的通用分析虽然还没伤到它却在理论上留下了阴影。SHA-512/256这类截断变体能缓解一部分但改变不了家族基因。SHA-3的处境刚好相反。它在结构上做到了换赛道1600位的宽状态提供了异常充沛的安全冗余免疫长度扩展设计清晰到可以针对单一置换做严格分析。但它的服役时间比SHA-256短实战样本量也少。宽状态和大冗余虽然令人安心但密码学的核心经验之一就是一个算法真正的安全最终要靠时间的检验。一个公道话是对绝大多数业务场景SHA-256和SHA-3的实际安全性差距约等于零你没有必要为了更安全而强行从SHA-256切到SHA-3。真正的差异体现在功能弹性和面向未来的结构多样性上而不是谁能防住今天的攻击。5.3 一个容易踩的坑以太坊的Keccak-256不是SHA3-256这个坑我见过太多人踩值得单独拎出来说。NIST最终版的SHA-3在Keccak原始提交版的基础上对填充规则做了微小调整——给消息加上了一个域分隔后缀用来区分SHA-3、SHAKE等不同功能。调整后的标准SHA-3和竞赛时期的原始Keccak已经不兼容了。以太坊在标准还没定稿时就采纳了原始Keccak所以Solidity里的keccak256、web3.utils.sha3以及大量智能合约工具链里默认的sha3函数使用的都是原始Keccak而不是FIPS 202定义的SHA3-256。这两者对空字符串的摘要差别是这样的函数空字符串摘要SHA3-256FIPS 202a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a以太坊Keccak-256c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470如果你在合约项目里用OpenSSL的openssl dgst -sha3-256去核对链上哈希永远对不上。排查这类问题的时候先搞清楚目标平台到底用的是标准SHA-3还是原始Keccak再验证测试向量能省掉大半天无头苍蝇式的排查。5.4 SHA-3家族的扩展能力SHAKE、cSHAKE、KMACSHA-3真正的差异化优势在于它能输出任意长度。SHAKE128和SHAKE256是可扩展输出函数需要32字节就拿32字节需要64字节就拿64字节输出的长度上限只受实际使用约束。这在设计密钥派生、挑战响应、流密码类应用时非常顺手SHA-2家族完全没有对应能力。更进一步SHA-3家族还有cSHAKE和KMAC。cSHAKE允许你给哈希配置一个自定义字符串实现域分离同一套底层置换不同的上下文因为自定义字符串不同而互不等效这比手动拼前缀这种民间做法安全得多也标准得多。KMAC则是基于cSHAKE构造的消息认证码天然抗长度扩展接口比HMAC更简单。如果你的新协议需要同时解决摘要可变长度输出认证域分离这四件事SHA-3家族可以一套体系全部覆盖这是它真正的杀手锏。6. 双雄并立的现实格局选型与落地建议6.1 存量系统别为了新而迁移接手现有系统时我的第一原则是如果系统里的SHA-256跑得好好的没有安全告警没有兼容性需求就不要动它。这里说的不动包括两层意思不要为了追赶潮流把接口拆了换SHA-3也不要自作主张搞什么双哈希增强。迁移一个哈希算法绝不只是换个函数名。文件摘要格式、协议字段、证书链、数据库里已存的摘要值、跨系统对接方的实现版本全部要跟着变。只要有一端没跟上线下算的和线上验的就不会对。SHA-256今天依然是NIST在册标准、依然是TLS和证书生态的默认选择你因为感觉它不够新而迁移属于给自己找事。真正值得做的是密码学敏捷性设计把哈希调用封装在接口后面在协议字段里带上算法标识确保未来某个时刻万一真要切换不需要推翻整个架构。这是花小钱买保险比一次性大迁移划算得多。6.2 新系统与特定场景这些时候优先考虑SHA-3如果你正在设计一个没有历史包袱的新系统下面几个场景我会认真建议你用SHA-3第一你需要可变长度输出。密钥派生、随机挑战、流式签名场景里SHAKE256比SHA-256加一堆手工截断操作干净得多也安全得多。第二你需要域分离。同一份数据要哈希成多种用途或者同一个协议里要区分多个上下文cSHAKE和KMAC提供的规范域分离能有效防止跨上下文的字节复用攻击。第三你在做硬件或嵌入式设计。Keccak置换的资源占用低、并行度高在ASIC或FPGA上实现起来非常顺手很多低功耗场景里反而更适合。第四你对长期风险特别敏感。数据要保存十年以上协议要服役很久你希望尽量降低Merkle-Damgård家族某天被通杀这种黑天鹅事件的影响。SHA-3的宽状态和异质结构给了你在SHA-2之外的第二条生路。6.3 关于混用的提醒和我的经验一个常见的误解是把SHA-256(m)和SHA-3(m)拼接起来安全性是不是就叠加了答案没这么简单。Joux在2004年就证明过迭代哈希的多碰撞攻击让简单拼接的组合强度远低于直觉预期。除非协议标准里有明确规定的组合构造否则不要自己发明双哈希加固这种民间配方往往只给你心理安慰还给实现和验证带来双倍复杂度。真想在协议里同时保留两条路线正确做法是设计成可选算法而不是在同一处同时上两个哈希。最后分享几条实操层面的经验。工具上Python的hashlib直接支持sha3_256和sha3_512也有shake_128和shake_256OpenSSL用openssl dgst -sha3-256 file就能算Go在较新版本的标准库里已经直接提供crypto/sha3更早的版本用golang.org/x/crypto/sha3。无论用哪个语言上线前都拿NIST官方测试向量对一遍尤其是截断变体和SHAKE这种带域分隔的错一个padding字节都会导致全线对不上。实现层面在嵌入式或低层环境手写Keccak时务必保证恒定时间避免分支依赖输入数据。一个诚恳的建议是去理解这两个算法的结构差异比记住十组性能数字更有价值。结构决定了你面对的安全威胁类别也决定了你在协议里能怎么用它性能数字过两年就会变结构哲学不会轻易过时。这大概就是SHA-256与SHA-3双雄并立给我的最大启示。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价