校验算法基础:CRC、MD5、SHA-1、SHA-256的原理与对比

做量产烧录的朋友,最怕什么?镜像烧进去,板子跑不起来。查半天,发现是镜像在传输过程中坏了一个 bit。嗯,这时候你就需要校验算法了。

今天咱们就把 CRC、MD5、SHA-1、SHA-256 这四位兄弟拉出来遛遛。我做了十年量产,每种算法都踩过坑,今天一次性说清楚。

CRC:硬件工程师的老朋友

CRC(循环冗余校验)是我最早接触的校验算法。说白了,它就是个多项式除法。把数据当成一个大数,除以一个约定的多项式,余数就是 CRC 值。

为什么量产烧录里 CRC 用得最多?因为它快,硬件实现极其简单。我记得有一次做 STM32 的批量烧录,用 CRC32 校验整个 512KB 镜像,耗时不到 10ms。换 MD5 的话,得 200ms 往上。

CRC 的核心特点:

  • 计算速度快,硬件支持好(很多 MCU 内置 CRC 外设)
  • 检错能力强,能检测出所有奇数个错误、所有双 bit 错误
  • 但它是检错码,不是防篡改码——有人故意改数据,CRC 可以轻松绕过

常见的 CRC 变体有 CRC-8、CRC-16、CRC-32。量产场景下,CRC-32 是主流。你想想看,一个 32 位的校验值,碰撞概率已经很低了。

// 一个简单的 CRC-32 实现(查表法)
uint32_t crc32(const uint8_t *data, size_t len) {
    uint32_t crc = 0xFFFFFFFF;
    for (size_t i = 0; i < len; i++) {
        crc ^= data[i];
        for (int j = 0; j < 8; j++) {
            if (crc & 1) {
                crc = (crc >> 1) ^ 0xEDB88320;
            } else {
                crc >>= 1;
            }
        }
    }
    return crc ^ 0xFFFFFFFF;
}

我的经验:量产烧录时,CRC 适合做快速完整性检查。比如烧录器每烧完一页,立即回读 CRC 对比。但千万别拿 CRC 做安全校验——我曾经见过有人用 CRC 做固件加密验证,结果被轻松破解。

MD5:曾经的王者,现在的弃子

MD5 是 90 年代的明星算法。它把任意长度的数据,压缩成 128 位(16 字节)的摘要。原理上,它通过四轮非线性函数、移位和加法操作,把数据搅得面目全非。

但 MD5 有个致命伤——碰撞。2004 年,中国密码学家王小云团队找到了 MD5 的快速碰撞方法。什么意思?就是你能构造两个不同的文件,但它们的 MD5 值一模一样。

警告:量产场景下,绝对不要用 MD5 做安全相关的校验。我曾经接手过一个项目,前任工程师用 MD5 校验固件签名,结果被攻击者伪造了合法固件。那次事故直接导致产品召回,损失惨重。

那 MD5 现在还能干嘛?说实话,我只在内部调试时偶尔用用。比如对比两个临时文件是否一致,图它快。但正式量产?我建议你直接跳过。

SHA-1:正在退役的老将

SHA-1 是 MD5 的升级版,输出 160 位(20 字节)摘要。它的设计思路和 MD5 类似,但轮数更多、操作更复杂。安全性上,SHA-1 比 MD5 强不少。

但好景不长。2017 年,Google 和 CWI 研究所宣布了 SHAttered 攻击——他们找到了 SHA-1 的碰撞实例。虽然攻击成本很高(需要约 110 年 GPU 计算时间),但理论上已经不安全了。

算法 输出长度 安全性状态 量产推荐度
CRC-32 32 bit 检错,不安全 ⭐⭐⭐(快速校验)
MD5 128 bit 已破解 ⭐(不推荐)
SHA-1 160 bit 理论不安全 ⭐⭐(过渡期)
SHA-256 256 bit 安全 ⭐⭐⭐⭐⭐(首选)

我个人习惯,SHA-1 现在只用在一些老旧的 legacy 项目上。新项目?直接上 SHA-256。

SHA-256:量产校验的黄金标准

SHA-256 是 SHA-2 家族的一员,输出 256 位(32 字节)摘要。它的安全性经过十几年考验,至今没有有效的碰撞攻击方法。

为什么量产烧录推荐 SHA-256?三个理由:

  1. 安全性足够——防篡改、防伪造,满足绝大多数量产场景
  2. 硬件加速普及——现在主流 MCU(如 STM32H7、i.MX RT 系列)都内置 SHA-256 硬件加速器
  3. 生态成熟——各种工具链、烧录器原生支持
// 使用 mbedTLS 计算 SHA-256(量产常用方案)
#include "mbedtls/sha256.h"

int compute_sha256(const uint8_t *data, size_t len, uint8_t output[32]) {
    mbedtls_sha256_context ctx;
    mbedtls_sha256_init(&ctx);
    mbedtls_sha256_starts(&ctx, 0);  // 0 = SHA-256, 1 = SHA-224
    mbedtls_sha256_update(&ctx, data, len);
    mbedtls_sha256_finish(&ctx, output);
    mbedtls_sha256_free(&ctx);
    return 0;
}

避坑指南:我曾经在量产线上遇到过一个问题——SHA-256 计算太慢,导致烧录节拍跟不上。后来发现是软件实现,换成硬件加速后,速度提升了 20 倍。所以,如果你的 MCU 支持硬件 SHA,一定要用起来。

四种算法的核心对比

下面这张图,是我自己总结的算法选型决策流程。你照着走,基本不会出错。

量产校验算法选型决策流程 开始:需要校验镜像 是否需要防篡改/安全校验? 否 CRC-32 快速校验 是 需要安全校验 MCU 是否支持硬件 SHA-256? 是 SHA-256 硬件加速 否 SHA-256 软件实现 说明: CRC 适合快速完整性检查;SHA-256 适合安全校验。MD5 和 SHA-1 已不推荐用于量产场景。

量产场景下的选型建议

说了这么多,到底怎么选?我直接给结论:

  • 场景一:烧录过程中的快速校验——用 CRC-32。每烧完一页,回读 CRC 对比,发现错误立即重烧。速度快,不影响产线节拍。
  • 场景二:固件完整性验证(无安全要求)——用 CRC-32 或 SHA-256 都行。我个人倾向 SHA-256,因为更通用,万一以后要升级安全策略,不用改代码。
  • 场景三:固件签名/防篡改——必须用 SHA-256。配合 RSA 或 ECDSA 签名,确保固件不被篡改。
  • 场景四:老项目维护——如果原来用 MD5 或 SHA-1,建议尽快升级。我见过太多因为算法过时导致的安全事故。

我的最终建议:新项目直接上 SHA-256。别纠结。CRC 作为辅助校验可以保留,但主校验算法用 SHA-256。这样既保证了安全性,又兼容了未来的扩展需求。