源码SHA算法底层原理?

访客 源码剖析 1

本文目录导读:

  1. 第一步:消息预处理
  2. 第二步:初始化哈希值 (Initialization)
  3. 第三步:核心压缩函数 (Compression Function)
  4. 第四步:输出
  5. 为什么SHA算法安全(抗碰撞)?
  6. 与其他SHA算法的区别

我们来深入探讨一下SHA(安全散列算法)系列的底层原理,SHA家族中最常用的是SHA-256和SHA-1(已不再安全),它们的核心逻辑类似,但细节不同,这里我们以SHA-256为例进行讲解,因为它是现代应用最广、安全性也足够高的代表,SHA-1和SHA-512的原理可以视为其变体(主要是参数不同)。

SHA算法的核心目标:将任意长度的消息(输入)压缩成一个固定长度的、看似随机的散列值(输出,SHA-256的输出是256位,即32个字节),这个过程是单向的,即无法从散列值反推出原始消息。

SHA-256的底层原理可以拆解为以下几个关键步骤:

第一步:消息预处理

这一步是为了让输入消息的长度适合后续的分块处理。

  1. 消息填充 (Padding)

    • 目的:将消息长度补足到 512 位的整数倍(SHA-256的分块大小)。
    • 过程:
      • 在消息末尾添加一个 1 位。
      • 然后添加足够多的 0 位,直到消息长度满足 (原消息长度 + 填充长度 + 64) mod 512 = 0
      • 64位的大端序整数表示原始消息的长度(bit数),附加在末尾。
    • 为什么这么麻烦? 填充保证了即使消息长度很短,也能进行后续的压缩循环,附加原始长度可以增强算法的安全性。
  2. 消息分块 (Message Block)

    • 将填充后的消息分割成若干个512位的块,每个块又可以进一步划分为16个32位的字(称为 W[0]W[15])。

第二步:初始化哈希值 (Initialization)

SHA-256使用8个固定的初始哈希值(常量),它们是通过取前8个质数(2, 3, 5, 7, 11, 13, 17, 19)的平方根的小数部分的前32位得到的,这些值称为 H[0]H[7],本质上是算法的初始状态。

  • H[0] = 0x6a09e667
  • H[1] = 0xbb67ae85
  • H[2] = 0x3c6ef372
  • H[3] = 0xa54ff53a
  • H[4] = 0x510e527f
  • H[5] = 0x9b05688c
  • H[6] = 0x1f83d9ab
  • H[7] = 0x5be0cd19

第三步:核心压缩函数 (Compression Function)

这是整个算法的核心,对于每一个512位的消息块,SHA-256执行64轮(轮次)的复杂运算。

  1. 消息扩展 (Message Schedule)

    • 将当前处理的512位块(16个字 W[0..15])扩展成64个32位的字W[0]W[63])。
    • 扩展公式:
      • 对于 t 从 16 到 63:
      • W[t] = σ1(W[t-2]) + W[t-7] + σ0(W[t-15]) + W[t-16]
    • σ0σ1 是特定的位运算函数(循环右移、异或等),这个扩展过程将16个字的信息“扩散”到64个字中,增加了算法的混淆性和雪崩效应。
  2. 工作变量 (Working Variables)

    • 初始化8个工作变量 a, b, c, d, e, f, g, h 为当前块的初始哈希值(H[0]H[7])。
  3. 64轮循环 (Main Loop)

    • 对于每一轮 t (0 到 63):
      • 计算两个临时变量 T1T2
        • T1 = h + Σ1(e) + Ch(e,f,g) + K[t] + W[t]
        • T2 = Σ0(a) + Maj(a,b,c)
      • 更新工作变量
        • h = g
        • g = f
        • f = e
        • e = d + T1
        • d = c
        • c = b
        • b = a
        • a = T1 + T2
    • 关键函数解释
      • Σ0(x)Σ1(x):对32位字进行循环右移和异或操作,用于混淆。
      • Ch(x,y,z):选择函数 ((x & y) ^ (~x & z)),如果x的某一位是1,选择y的对应位;否则选择z的对应位。
      • Maj(x,y,z):多数函数 ((x & y) ^ (x & z) ^ (y & z)),对于每一位,选择x,y,z中出现次数多的那个值(0或1)。
      • K[t]:64个常量,取自前64个质数的立方根的小数部分的前32位,为每轮加入不同的随机性。
      • W[t]:64个扩展后的消息字。
  4. 更新哈希值 (Update Hash Values)

    • 64轮循环结束后,将工作变量 ah 的值与上一轮的哈希值 H[0..7] 相加(模2^32加法):
      • H[0] = H[0] + a
      • H[1] = H[1] + b
      • H[7] = H[7] + h

第四步:输出

当所有消息块都处理完毕后,最终的 H[0]H[7] 就是256位的散列值,通常以32个十六进制数字的形式输出。

为什么SHA算法安全(抗碰撞)?

  1. 单向性:复杂的运算、模加法、非线性函数(Ch, Maj)使得从散列值反推输入在计算上不可行。
  2. 雪崩效应:输入中任意一位的变化,都会导致输出中大约一半的位发生变化,由于64轮循环和消息扩展,这种变化会被迅速放大和扩散。
  3. 抗碰撞性:找到两个不同的输入产生相同散列值的难度极高(理论上需要2^128次尝试),SHA-256的抗碰撞性至今(2025年)未被攻破。
  4. 抗第一原像攻击:给定一个散列值,找到一个输入使其散列为该值,难度极高(2^256)。

与其他SHA算法的区别

算法 输出长度 消息块大小 轮数 状态字 安全性现状
SHA-1 160位 512位 80轮 5个32位字 已被攻破(找到实际碰撞),不推荐使用
SHA-224 224位 512位 64轮 8个32位字 安全,是SHA-256的截断版
SHA-256 256位 512位 64轮 8个32位字 安全,广泛使用
SHA-384 384位 1024位 80轮 8个64位字 安全,是SHA-512的截断版
SHA-512 512位 1024位 80轮 8个64位字 安全,适用于需要更高安全性的场景

SHA-256的底层原理可以概括为:

  1. 填充消息使之成为512位的倍数,并附加原始长度。
  2. 初始化8个哈希状态
  3. 对每个512位块:
    • 扩展消息:将16个字扩展成64个字。
    • 执行64轮压缩循环:利用非线性函数、循环移位、异或、模加法,并混合当前轮次的常量和扩展后的消息字,持续更新8个工作变量。
    • 累积结果:将本轮的结果加到之前的哈希状态上。
  4. 输出最终的256位状态

这个精巧的设计确保了其不可逆性和抗碰撞性,现在你可以在代码层面去实现它,或者利用LibTomCrypt等开源库直接调用。

标签: SHA算法 底层原理

抱歉,评论功能暂时关闭!