3. 固件签名生成与验证

任务说明

本案例实现固件签名与验证的最小闭环:使用私钥对固件哈希进行签名,并在设备端使用公钥验证签名,确保固件来源可信且未被篡改。案例基于 Python + cryptography 库,采用 ECDSA P-256 签名算法,完整覆盖密钥生成、签名生成与验签判定三个环节。

环境依赖

  • Python 3.8+
  • 安装依赖:pip install cryptography

完整实现代码

from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.exceptions import InvalidSignature
import hashlib

# ---------- 1. 密钥生成(实际部署时私钥保存在签名服务器) ----------
def generate_keypair():
    private_key = ec.generate_private_key(ec.SECP256R1())
    # 私钥序列化(PEM格式)
    private_pem = private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption()
    )
    # 公钥序列化(PEM格式)
    public_pem = private_key.public_key().public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo
    )
    return private_pem, public_pem

# ---------- 2. 固件签名(在签名服务器执行) ----------
def sign_firmware(private_pem, firmware_bytes):
    private_key = serialization.load_pem_private_key(private_pem, password=None)
    # 计算固件SHA-256哈希
    firmware_hash = hashlib.sha256(firmware_bytes).digest()
    # 对哈希签名
    signature = private_key.sign(firmware_hash, ec.ECDSA(hashes.SHA256()))
    return signature

# ---------- 3. 固件验签(在设备端执行) ----------
def verify_firmware(public_pem, firmware_bytes, signature):
    public_key = serialization.load_pem_public_key(public_pem)
    # 重新计算固件哈希
    firmware_hash = hashlib.sha256(firmware_bytes).digest()
    try:
        public_key.verify(signature, firmware_hash, ec.ECDSA(hashes.SHA256()))
        return True
    except InvalidSignature:
        return False

# ---------- 4. 最小验证闭环 ----------
if __name__ == "__main__":
    # 模拟固件数据
    firmware = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09" * 100  # 1KB固件

    # 生成密钥对
    priv_pem, pub_pem = generate_keypair()

    # 签名
    sig = sign_firmware(priv_pem, firmware)

    # 验签(原始固件)
    result_ok = verify_firmware(pub_pem, firmware, sig)
    print(f"原始固件验签结果: {'通过' if result_ok else '失败'}")

    # 验签(篡改固件)
    tampered = firmware + b"\xFF"
    result_tampered = verify_firmware(pub_pem, tampered, sig)
    print(f"篡改固件验签结果: {'通过' if result_tampered else '失败'}")

    # 预期输出(确定性结果):
    # 原始固件验签结果: 通过
    # 篡改固件验签结果: 失败

运行方式

python firmware_sign_verify.py

验证方法与判定标准

  • 通过条件:程序输出两行结果,第一行为“原始固件验签结果: 通过”,第二行为“篡改固件验签结果: 失败”。
  • 逻辑说明:签名过程对固件哈希(SHA-256)进行ECDSA签名;验签时重新计算哈希并与签名比对。原始固件哈希一致,验签通过;篡改后哈希变化,验签失败。
  • 安全边界:本案例演示签名与验签核心流程。实际OTA系统中,私钥应存储在硬件安全模块(HSM)或隔离的签名服务器中,公钥需在设备出厂时安全烧录,防止被替换。

常见问题

  • 验签失败:确认公钥与签名所用私钥是否匹配;确认固件字节在签名与验签之间未被修改(包括文件读取时的换行符差异)。
  • 算法选择:ECDSA P-256 在资源受限的嵌入式设备上性能优于RSA-2048,且签名长度更短(64字节),适合OTA场景。