跳转到主内容一文学会密码学应用 | 物联网民工

一文学会密码学应用

IoT 密码学的"够用就好"

目标:会应用、能理解并能设计方案。不讲复杂数学,只讲必要概念、参数与避坑清单。

必要概念

  • 机密性(Confidentiality):防止被看懂(加密)
  • 完整性(Integrity):防止被悄悄改(认证)
  • 身份不可否认性(Identity):谁在对话(签名/证书)
  • 对称密钥(Symmetric):同一把密钥加解密(AES/ChaCha20-Poly1305)
  • 非对称密钥(Asymmetric):私钥/公钥(ECDSA/Ed25519、ECDH/X25519)
  • AEAD(Authenticated Encryption with Associated Data):一次完成加密+认证(GCM/CCM、ChaCha20-Poly1305)
  • MAC(Message Authentication Code):只做认证(HMAC/AES-CMAC),不加密
  • KDF(Key Derivation Function):把"原始秘密"(如 ECDH/X25519 共享秘密)变成"可用密钥"
  • 密钥格式:SPKI(公钥)/PKCS8(私钥)容器,DER(二进制)/PEM(文本)编码

一张图

[A私钥 + B公钥] --(ECDH/X25519)--> [共享秘密S]
[S] --(HKDF salt, info, L)--> [对称密钥K]
[消息M, AAD] --(AEAD:K, nonce)--> [C || tag]
[M] --(HMAC/CMAC:K)--> [tag]
[M] --(签名:私钥)--> [signature]
  • AEAD 输出总是"密文+标签",解密前先验标签
  • MAC/签名不加密数据
  • 共享秘密不能直接当密钥,必须 KDF

参数小抄(长度与格式)

  • Nonce/IV:GCM=12字节;ChaCha20-Poly1305=12字节;CCM=13字节(常用);CBC=16字节
  • Key:AES=16/24/32字节;ChaCha20-Poly1305=32字节
  • 签名编码:ECDSA=DER 或 RAW(r||s 64字节);Ed25519=RAW
  • 公钥/私钥容器:SPKI(公钥)/PKCS8(私钥),DER 字节可转 PEM 文本

何时用什么

  • 受限设备/无线协议:AES-CCM(硬件加速) 或 ChaCha20-Poly1305(软实现友好)
  • Web/通用:AES-GCM(Galois/Counter Mode) 或 ChaCha20-Poly1305
  • 只要完整性:HMAC-SHA256(Hash-based Message Authentication Code) 或 AES-CMAC
  • 固件/长消息签名:Ed25519 或 ECDSA-P256
  • 会话建立:ECDH-P256 或 X25519 → HKDF → AEAD

攻防小卡片

  • 绝不在同一密钥下复用 AEAD nonce
  • CBC 本身不认证,必须"加 MAC",推荐改用 AEAD
  • 密钥交换一定要带签名,防止中间人攻击(MITM)

快速上手

CryptoBox网页版 快速验证:

  • 打开网页,按页面完成对应任务:
    • Symmetric:对称/AEAD(AES-GCM/CCM/CBC、ChaCha20-Poly1305)
    • Hash:哈希(SHA-256)
    • MAC:消息认证码(HMAC-SHA256、AES-CMAC)
    • KDF:密钥派生(HKDF-SHA256、PBKDF2-SHA256)
    • Sign/Verify:签名/验签(ECDSA P-256、Ed25519)
    • Key Exchange:密钥交换(ECDH P-256、X25519)
    • X.509:证书解析与转换
    • Codec:编码转换(Text/Hex/Base64、PEM/DER)
    • Random:随机数生成
  • 输入与输出默认用 HEX(页面支持 text/hex/base64 三态切换)
  • 若向量里给的是 Base64,请用 Codec 页先转为 HEX 再粘贴到对应页面

哈希(Hash)

SHA-256

原理

  • 将任意长度输入压缩成固定 32 字节(256位)“指纹”,小改动引起大变化(雪崩效应)
  • 只能检出"是否被改",不提供"是谁改的"
[消息 bytes] --(SHA-256)--> [32字节摘要]

动手

  • 页面:Hash
  • 输入(HEX):68656c6c6f(“hello”)
  • 点击 Compute
  • 期望输出(HEX):2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

消息认证码(MAC)

HMAC-SHA256

原理

  • 基于哈希的认证码:证明"持有密钥且消息未改"
  • 结构直觉:两层哈希,内层混入密钥(ipad),外层再混一次(opad)
tag = H( K ⊕ opad || H( K ⊕ ipad || msg ) )

动手

  • 页面:MAC → HMAC-SHA256
  • Key(HEX):0102030405060708090a0b0c0d0e0f1011121314
  • Input(HEX):48656c6c6f(“Hello”)
  • 点击 Compute
  • 期望 Tag(HEX): 6a14dddf21c1cda3ed32da7461cecad54717d31dcfcdc9be4a11d25086df696f

AES-CMAC

原理

  • 基于 AES 的消息认证码。先生成子密钥 K1/K2,对最后一个块做轻微"调整",再用 AES-CBC 的方式聚合得到标签
[msg] --(分块/填充)--> [M1..Mn]
last = (完整块? K1 : K2) ⊕ Mn
tag = AES-CBC-Encrypt(key, IV=0, M1..M{n-1}, last) 的最后 16 字节

动手

  • 页面:MAC → AES-CMAC
  • Key(HEX):2b7e151628aed2a6abf7158809cf4f3c
  • Input(HEX):6bc1bee22e409f96e93d7e117393172a
  • 点击 Compute
  • 输出: 070a16b46b4d4144f79bdd9dd04a287c

对称与 AEAD

AES-GCM

原理

  • 使用 CTR 方式加密 + GHASH 计算认证标签(tag)。nonce 必须 12 字节;同一密钥下绝不复用 nonce
密钥K, nonceN
C = CTR_Encrypt(K, N, P)
tag = GHASH(K, AAD, C)
输出 = C || tag

动手

  • 页面:Symmetric → AES-GCM
  • Input(HEX):00112233445566778899aabbccddeeff0001020304050607
  • Key(HEX):000102030405060708090a0b0c0d0e0f
  • Nonce(HEX):000102030405060708090a0b(12 字节)
  • AAD(HEX,可选):0c0d0e0f101112131415161718191a1b
  • 点击 Encrypt
  • 输出(HEX,ciphertext||tag):
    937d85fd224e9123c34bcb31fa7e9ef7b32718e557e8fbf14c987e199c7d4d165cb8826e52c2d1f0
    

ChaCha20-Poly1305

原理

  • ChaCha20 负责加密(流密码),Poly1305 负责标签(认证)。key=32 字节,nonce=12 字节
C = ChaCha20_Encrypt(key, nonce, P)
tag = Poly1305(key', AAD || C)
输出 = C || tag

动手

  • 页面:Symmetric → ChaCha20-Poly1305
  • Input(HEX):0102030405060708
  • Key(HEX):0000…00(32 字节全 00)
  • Nonce(HEX):0000…00(12 字节全 00)
  • 点击 Encrypt
  • 输出(HEX,ciphertext||tag):9e05e4ba50573f7216b4569116f74ad2ff14a1f5698d0dda

AES-CCM

原理

  • CCM = CTR 加密 + CBC-MAC 标签。协议常用,nonce 固定 13 字节,tag 可为 4/8/16 字节
tag = CBC-MAC(key, B0 || AAD' || PT')
C = CTR_Encrypt(key, nonce, P)
输出 = C || tag

动手

  • 页面:Symmetric → AES-CCM
  • Input(HEX):00112233445566778899aabbccddeeff
  • Key(HEX):00000000000000000000000000000000
  • Nonce(HEX):0f0e0d0c0b0a09080706050403(13 字节)
  • AAD(HEX):aabbccdd
  • Tag Length:8(即 64 bit)
  • 点击 Encrypt
  • 输出(HEX,ciphertext||tag): 0b351eb48bc68b348aca2cd428d4864dedec3573620d52d5

AES-CBC(PKCS7/NoPadding)

原理

  • CBC 是分组链接加密:每块明文先与前一块密文异或再加密。默认 PKCS7 填充;NoPadding 需 16 字节对齐。CBC 本身不认证,推荐 AEAD
  • AES 是分组密码,分组大小固定为 128 位(16 字节),所以需要填充或要求输入数据长度为 16 字节的整数倍
C1 = E( K, P1 ⊕ IV )
Ci = E( K, Pi ⊕ Ci-1 )

动手

  • 页面:Symmetric → AES-CBC(默认 PKCS7)
  • Input(HEX):00112233
  • Key(HEX):000102030405060708090a0b0c0d0e0f
  • IV(HEX):000102030405060708090a0b0c0d0e0f
  • 点击 Encrypt
  • 期望 bbd0ba9d822962f9d25c344801fe195d

动手

  • 勾选 NoPadding;将输入改为 16 字节:
  • Input(HEX):00112233445566778899aabbccddeeff
  • 期望 76d0627da1d290436e21a4af7fca94b7

密钥派生(KDF)

HKDF-SHA256

原理

  • HKDF = Extract + Expand:先"提纯"原始秘密(与盐混合),再按需求长度扩展,绑定 info 以区分用途
PRK = HMAC(salt, IKM)
OKM = HMAC(PRK, info || 0x01) || ...  # 分段拼接至所需长度

动手

  • 页面:KDF → HKDF-SHA256
  • IKM(HEX):000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
  • Salt(HEX):(留空)
  • Info(HEX):(留空)
  • Length:32
  • 点击 Derive
  • OKM(HEX): 37ad29109f43265287804b674e2653d0a513718907f97fca97c95bded8104bbf

PBKDF2-SHA256

原理

  • 口令拉伸:多次迭代 HMAC,显著增加暴力破解成本。盐随机且不复用
DK = PBKDF2( password, salt, iterations, length )

动手

  • 页面:KDF → PBKDF2-SHA256
  • Password(HEX):70617373776f7264(“password”)
  • Salt(HEX):73616c74(“salt”)
  • Iterations:4096
  • Length:32
  • 点击 Derive
  • DK(HEX): c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a

签名/验签

原理

  • 用私钥签名、公钥验证。ECDSA(Elliptic Curve Digital Signature Algorithm) 输出 (r,s) 常见 DER/RAW 两种编码;Ed25519 接口更直接
sig = Sign(privateKey, H(message))
ok = Verify(publicKey, H(message), sig)

ECDSA-P256(DER/RAW)

原理

  • 用私钥对消息做"不可否认"的认证;公钥验证。ECDSA 结果含两个大整数 r,s,常见两种编码:DER、RAW(r||s 64字节)

动手

  • 页面:Sign/Verify → ECDSA-P256

  • Message(HEX):616263(“abc”)

  • Public Key(SPKI,HEX):

    3059301306072a8648ce3d020106082a8648ce3d030107034200047a593180860c4037c83c12749845c8ee1424dd297fadcb895e358255d2c7d2b2a8ca25580f2626fe579062ff1b99ff91c24a0da06fb32b5be20148c9249f5650
    
  • Sig Encoding:DER

  • Signature(HEX):

    30440220334d7ae5ce7dfa1f69c24acd19601442bda82b4c3dd0a26890f0053066325f72022046cfb76d8f55b0da16e3f82f34ea7264abc85305333ce6db49f48e9c4587d3a9
    
  • 点击 Verify

  • Verify Result:成功

Ed25519

原理

  • 现代曲线签名,接口直接、性能好。与 ECDSA 不同,无 DER/RAW 切换困扰

动手

  • 页面:Sign/Verify → Ed25519
  • Message(HEX):68656c6c6f(“hello”)
  • Public Key(SPKI,HEX):
    302a300506032b657003210003a107bff3ce10be1d70dd18e74bc09967e4d6309ba50d5f1ddc8664125531b8
    
  • Signature(HEX):
    e1a7fca94a835127885b99e2eba733d6ee5bf5dc463ed8385eb6f1dcaa1117c0f151750a10f46f5b3796a91203578f702c85c67c334b5689a516284d499f710f
    
  • 点击 Verify
  • Verify Result:成功

密钥交换

原理

  • 双方各自使用"我的私钥 + 你的公钥"得到相同共享秘密;该秘密必须再经 HKDF(HMAC-based Key Derivation Function) 派生成会话密钥
S = ECDH(a_priv, b_pub) = ECDH(b_priv, a_pub)
或 S = X25519(a_priv, b_pub) = X25519(b_priv, a_pub)

ECDH-P256

原理

  • A 用私钥、B 用公钥,各自独立计算同一个共享秘密。该秘密不直接用于加密,需 HKDF 派生成 AEAD 密钥

动手

  • 页面:Key Exchange 页 → ECDH-P256
  • A 私钥(PKCS8.DER):
    308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420009f3d9f3d9f3d9f3d9f3d9f3d9f3d9f3d9f3d9f3d9f3d9f3d9f3d9f3d9f3d9fa1440342000408fb02eb998e991b5a615279ac576b5524fcd6b5a26e685aa0c96e88867625a59a106cd6a63087ff2a27c31c392647d18cc5fa8ba9f196e60a04eace8de6f38d
    
  • B 公钥(SPKI.DER):
    3059301306072a8648ce3d020106082a8648ce3d030107034200045bc3633e112acf5d0abb90f486776ba3500c19b5d095d7ea7163c7846f61f10cce93315c6c3b4dbfee3557a6677f58721c14a18bafc1fe253678e32b7a8337bf
    
  • 点击 Derive
  • Shared Secret(HEX): 22a91d018252d0169da3bcb269c2e3852f08b27d2ef5e6c27e4f2ecd4b8e7463

X25519

原理

  • 现代密钥交换曲线,接口直接、性能好。与 ECDH 同理,输出共享秘密,需 HKDF→AEAD 才能加密

动手

  • 页面:Key Exchange 页 → X25519
  • A 私钥(PKCS8.DER):
    302e020100300506032b656e04220420000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
    
  • B 公钥(SPKI.DER):
    302a300506032b656e03210087968c1c1642bd0600f6ad869b88f92c9623d0dfc44f01deffe21c9add3dca5f
    
  • 点击 Derive
  • Shared Secret(HEX): dae0079aea6e6d02ca215a60d5d8f6689c3ed6009d41882b9181ff2481d9e27a

证书与密钥格式

X.509证书

  • 证书是"公钥+身份+有效期+扩展"的载体(X.509 v3)
  • 公钥通常放在 SPKI;私钥通常放在 PKCS8。编码可为 DER(二进制)或 PEM(文本)
[证书] = { 公钥(SPKI), 主题/颁发者, 有效期, 扩展, 签名 }
DER(字节) ⇄ PEM(文本包裹)

动手

  • 页面:X.509

  • 将下方 PEM 粘贴到输入区:

    -----BEGIN CERTIFICATE-----
    MIICjTCCAjSgAwIBAgIUQ6eSZ5V2VDhwWNpPYbkmhbNO6JkwCgYIKoZIzj0EAwIw
    gYQxCzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdCZWlqaW5nMRAwDgYDVQQHDAdCZWlq
    aW5nMQwwCgYDVQQKDANJb1QxDDAKBgNVBAsMA0RldjEUMBIGA1UEAwwLZXhhbXBs
    ZS5jb20xHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20wHhcNMjUwODEw
    MTcwODE3WhcNMzUwODA4MTcwODE3WjCBhDELMAkGA1UEBhMCQ04xEDAOBgNVBAgM
    B0JlaWppbmcxEDAOBgNVBAcMB0JlaWppbmcxDDAKBgNVBAoMA0lvVDEMMAoGA1UE
    CwwDRGV2MRQwEgYDVQQDDAtleGFtcGxlLmNvbTEfMB0GCSqGSIb3DQEJARYQdGVz
    dEBleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCE1SJx84gOs
    MdT3I7UGLlrKZpHSuRc2mnoeepHkWGfo72iiLr5DJoxCyJJrxsnNvYQEhBg6vsum
    JyHMX6mVylGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDAdBgNVHSUEFjAU
    BggrBgEFBQcDAQYIKwYBBQUHAwIwJwYDVR0RBCAwHoILZXhhbXBsZS5jb22CD3d3
    dy5leGFtcGxlLmNvbTAdBgNVHQ4EFgQU8+X7PvzqGxEGxEaCcjN5Evp6NC0wCgYI
    KoZIzj0EAwIDRwAwRAIgO5/F8Mu2KSP3zzxhp6n9HgZT0LIvOjXbMILZF94arY0C
    IG8cF+T8wn1VyGgbwqFvFLy36qufJ2TgeL/l4mkrj9az
    -----END CERTIFICATE-----
    
  • 点击 Parse(解析)与 Convert(转换)

  • 解析文本包含:Public-Key: (256 bit)、Subject/Issuer、Validity、扩展 OID 等

  • Convert 能在 PEM 与 DER-HEX 间互转

编码转换(Codec)

  • 数据=字节;显示/交换需要编码。Hex/Base64 是字节到字符串的表示;PEM 是对 DER(二进制)的 Base64 外壳
bytes ⇄ hex / base64
DER(bytes) ⇄ PEM("-----BEGIN ..." + base64 + "-----END ...")

动手

  • 页面:Codec
  • 将 Base64 的 PKCS8/SPKI 转成 HEX 后再粘贴到其他页面使用
  • 常用:Base64 → HEX;或 HEX → Base64

随机数(RNG)

  • CSPRNG(密码学安全随机数)用于生成密钥/nonce/salt
  • 长度要与用途匹配:密钥(16/24/32字节)、GCM/ChaCha20-Poly1305 nonce(12字节)、CCM nonce(13字节)
Random(n) → [n字节随机] → (key/nonce/salt)

动手

  • 页面:Random
  • 选择 16/32/64 字节;点击 Generate;根据需要在其他页面粘贴使用

术语表

缩略语全称说明
AEADAuthenticated Encryption with Associated Data带关联数据的认证加密,同时提供加密和认证
MACMessage Authentication Code消息认证码,用于验证消息完整性和真实性
HMACHash-based Message Authentication Code基于哈希的消息认证码
KDFKey Derivation Function密钥派生函数,从原始密钥材料生成工作密钥
HKDFHMAC-based Key Derivation Function基于HMAC的密钥派生函数
PBKDF2Password-Based Key Derivation Function 2基于密码的密钥派生函数版本2
AESAdvanced Encryption Standard高级加密标准,对称加密算法
GCMGalois/Counter Mode伽罗瓦/计数器模式,AEAD的一种实现
CCMCounter with CBC-MAC使用CBC-MAC的计数器模式,另一种AEAD实现
CBCCipher Block Chaining密码块链接模式,传统分组加密模式
CTRCounter Mode计数器模式,分组密码的一种工作模式
GHASHGalois Hash Function用于AES-GCM的哈希函数
SHASecure Hash Algorithm安全哈希算法
ECDSAElliptic Curve Digital Signature Algorithm椭圆曲线数字签名算法
ECDHElliptic Curve Diffie-Hellman椭圆曲线迪菲-赫尔曼密钥交换
SPKISubject Public Key Info主体公钥信息,公钥容器格式
PKCS8Private-Key Information Syntax Standard私钥信息语法标准,私钥容器格式
DERDistinguished Encoding Rules区别编码规则,二进制编码格式
PEMPrivacy-Enhanced Mail隐私增强邮件,基于Base64的文本编码格式
RSARivest-Shamir-Adleman一种公钥加密算法名称
ChaCha20Chaotic Cipher 20流加密算法
Poly1305Polynomial Evaluation in a 1305-bit finite field一次性认证器,常与ChaCha20结合使用
Ed25519Edwards Curve 25519基于Edwards 25519曲线的签名算法
X.509ITU-T standard公钥证书格式标准,一种数字证书格式
X25519Edwards Curve 25519基于Curve25519曲线的密钥交换算法
CSPRNGCryptographically Secure Pseudo-Random Number Generator密码学安全伪随机数生成器
MITMMan-in-the-Middle中间人攻击,攻击者秘密中转通信双方的数据