“Good Enough” IoT Cryptography
Goal: Application, understanding, and ability to design solutions. No complex math, just essential concepts, parameters, and a checklist of pitfalls to avoid.
Essential Concepts
- Confidentiality: Prevent unauthorized access (encryption)
- Integrity: Prevent undetected modification (authentication)
- Identity Non-repudiation: Who is in the conversation (signatures/certificates)
- Symmetric Key: Same key for encryption/decryption (AES/ChaCha20-Poly1305)
- Asymmetric Key: Private/Public keys (ECDSA/Ed25519, ECDH/X25519)
- AEAD (Authenticated Encryption with Associated Data): Encryption + authentication in one go (GCM/CCM, ChaCha20-Poly1305)
- MAC (Message Authentication Code): Authentication only (HMAC/AES-CMAC), no encryption
- KDF (Key Derivation Function): Transform “raw secrets” (e.g., ECDH/X25519 shared secret) into “usable keys”
- Key Formats: SPKI (public key)/PKCS8 (private key) containers, DER (binary)/PEM (text) encoding
Diagram
[A private key + B public key] --(ECDH/X25519)--> [Shared secret S]
[S] --(HKDF salt, info, L)--> [Symmetric key K]
[Message M, AAD] --(AEAD:K, nonce)--> [C || tag]
[M] --(HMAC/CMAC:K)--> [tag]
[M] --(Sign:Private Key)--> [signature]
- AEAD output is always “ciphertext + tag”, verify tag before decryption
- MAC/signature does not encrypt data
- Shared secrets cannot be used directly as keys, must use KDF
Parameter Cheat Sheet (Length & Format)
- Nonce/IV: GCM=12 bytes; ChaCha20-Poly1305=12 bytes; CCM=13 bytes (common); CBC=16 bytes
- Key: AES=16/24/32 bytes; ChaCha20-Poly1305=32 bytes
- Signature Encoding: ECDSA=DER or RAW(r||s 64 bytes); Ed25519=RAW
- Public/Private Key Containers: SPKI (public key)/PKCS8 (private key), DER bytes can be converted to PEM text
When to Use What
- Constrained devices/wireless protocols: AES-CCM (hardware accelerated) or ChaCha20-Poly1305 (software-friendly)
- Web/general purpose: AES-GCM (Galois/Counter Mode) or ChaCha20-Poly1305
- Integrity only: HMAC-SHA256 (Hash-based Message Authentication Code) or AES-CMAC
- Firmware/long message signing: Ed25519 or ECDSA-P256
- Session establishment: ECDH-P256 or X25519 → HKDF → AEAD
Attack/Defense Quick Cards
- Never reuse AEAD nonce under the same key
- CBC itself doesn’t authenticate, must “add MAC”, recommend switching to AEAD
- Key exchange must include signatures to prevent man-in-the-middle attacks (MITM)
Quick Start
Quickly verify on CryptoBox web version:
- Open the webpage and complete corresponding tasks by page:
- Symmetric: Symmetric/AEAD (AES-GCM/CCM/CBC, ChaCha20-Poly1305)
- Hash: Hashing (SHA-256)
- MAC: Message Authentication Codes (HMAC-SHA256, AES-CMAC)
- KDF: Key Derivation (HKDF-SHA256, PBKDF2-SHA256)
- Sign/Verify: Sign/Verify (ECDSA P-256, Ed25519)
- Key Exchange: Key Exchange (ECDH P-256, X25519)
- X.509: Certificate parsing and conversion
- Codec: Encoding conversion (Text/Hex/Base64, PEM/DER)
- Random: Random number generation
- Input and output default to HEX (page supports text/hex/base64 tri-state switching)
- If vectors provide Base64, please use the Codec page to convert to HEX first before pasting to the corresponding page
Hash
SHA-256
Principle
- Compresses input of arbitrary length into a fixed 32-byte (256-bit) “fingerprint”, small changes cause large differences (avalanche effect)
- Can only detect “whether it was modified”, does not provide “who modified it”
[message bytes] --(SHA-256)--> [32-byte digest]
Hands-on
- Page: Hash
- Input (HEX): 68656c6c6f (“hello”)
- Click Compute
- Expected Output (HEX): 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
Message Authentication Code (MAC)
HMAC-SHA256
Principle
- Hash-based authentication code: Proves “possessing the key and message unchanged”
- Intuitive structure: Two-layer hash, inner layer mixes key (ipad), outer layer mixes again (opad)
tag = H( K ⊕ opad || H( K ⊕ ipad || msg ) )
Hands-on
- Page: MAC → HMAC-SHA256
- Key (HEX): 0102030405060708090a0b0c0d0e0f1011121314
- Input (HEX): 48656c6c6f (“Hello”)
- Click Compute
- Expected Tag (HEX): 6a14dddf21c1cda3ed32da7461cecad54717d31dcfcdc9be4a11d25086df696f
AES-CMAC
Principle
- AES-based message authentication code. First generates subkeys K1/K2, makes slight “adjustments” to the last block, then aggregates using AES-CBC-like approach to get tag
[msg] --(block/padding)--> [M1..Mn]
last = (full block? K1 : K2) ⊕ Mn
tag = Last 16 bytes of AES-CBC-Encrypt(key, IV=0, M1..M{n-1}, last)
Hands-on
- Page: MAC → AES-CMAC
- Key (HEX): 2b7e151628aed2a6abf7158809cf4f3c
- Input (HEX): 6bc1bee22e409f96e93d7e117393172a
- Click Compute
- Output: 070a16b46b4d4144f79bdd9dd04a287c
Symmetric and AEAD
AES-GCM
Principle
- Uses CTR encryption + GHASH to compute authentication tag. Nonce must be 12 bytes; never reuse nonce under the same key
Key K, nonce N
C = CTR_Encrypt(K, N, P)
tag = GHASH(K, AAD, C)
Output = C || tag
Hands-on
- Page: Symmetric → AES-GCM
- Input (HEX): 00112233445566778899aabbccddeeff0001020304050607
- Key (HEX): 000102030405060708090a0b0c0d0e0f
- Nonce (HEX): 000102030405060708090a0b (12 bytes)
- AAD (HEX, optional): 0c0d0e0f101112131415161718191a1b
- Click Encrypt
- Output (HEX, ciphertext||tag):
937d85fd224e9123c34bcb31fa7e9ef7b32718e557e8fbf14c987e199c7d4d165cb8826e52c2d1f0
ChaCha20-Poly1305
Principle
- ChaCha20 handles encryption (stream cipher), Poly1305 handles tag (authentication). Key=32 bytes, nonce=12 bytes
C = ChaCha20_Encrypt(key, nonce, P)
tag = Poly1305(key', AAD || C)
Output = C || tag
Hands-on
- Page: Symmetric → ChaCha20-Poly1305
- Input (HEX): 0102030405060708
- Key (HEX): 0000…00 (32 bytes all 00)
- Nonce (HEX): 0000…00 (12 bytes all 00)
- Click Encrypt
- Output (HEX, ciphertext||tag): 9e05e4ba50573f7216b4569116f74ad2ff14a1f5698d0dda
AES-CCM
Principle
- CCM = CTR encryption + CBC-MAC tag. Commonly used in protocols, nonce fixed at 13 bytes, tag can be 4/8/16 bytes
tag = CBC-MAC(key, B0 || AAD' || PT')
C = CTR_Encrypt(key, nonce, P)
Output = C || tag
Hands-on
- Page: Symmetric → AES-CCM
- Input (HEX): 00112233445566778899aabbccddeeff
- Key (HEX): 00000000000000000000000000000000
- Nonce (HEX): 0f0e0d0c0b0a09080706050403 (13 bytes)
- AAD (HEX): aabbccdd
- Tag Length: 8 (i.e., 64 bits)
- Click Encrypt
- Output (HEX, ciphertext||tag): 0b351eb48bc68b348aca2cd428d4864dedec3573620d52d5
AES-CBC (PKCS7/NoPadding)
Principle
- CBC is cipher block chaining: Each plaintext block is XORed with the previous ciphertext block before encryption. Default PKCS7 padding; NoPadding requires 16-byte alignment. CBC itself doesn’t authenticate, recommend AEAD
- AES is a block cipher with fixed block size of 128 bits (16 bytes), so padding is needed or input data length must be a multiple of 16 bytes
C1 = E( K, P1 ⊕ IV )
Ci = E( K, Pi ⊕ Ci-1 )
Hands-on
- Page: Symmetric → AES-CBC (default PKCS7)
- Input (HEX): 00112233
- Key (HEX): 000102030405060708090a0b0c0d0e0f
- IV (HEX): 000102030405060708090a0b0c0d0e0f
- Click Encrypt
- Expected bbd0ba9d822962f9d25c344801fe195d
Hands-on
- Check NoPadding; change input to 16 bytes:
- Input (HEX): 00112233445566778899aabbccddeeff
- Expected 76d0627da1d290436e21a4af7fca94b7
Key Derivation (KDF)
HKDF-SHA256
Principle
- HKDF = Extract + Expand: First “purify” raw secret (mixed with salt), then expand to desired length, bind info to distinguish purposes
PRK = HMAC(salt, IKM)
OKM = HMAC(PRK, info || 0x01) || ... # Concatenate segments to desired length
Hands-on
- Page: KDF → HKDF-SHA256
- IKM (HEX): 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
- Salt (HEX): (leave blank)
- Info (HEX): (leave blank)
- Length: 32
- Click Derive
- OKM (HEX): 37ad29109f43265287804b674e2653d0a513718907f97fca97c95bded8104bbf
PBKDF2-SHA256
Principle
- Password stretching: Multiple HMAC iterations significantly increase brute force cracking costs. Salt is random and not reused
DK = PBKDF2( password, salt, iterations, length )
Hands-on
- Page: KDF → PBKDF2-SHA256
- Password (HEX): 70617373776f7264 (“password”)
- Salt (HEX): 73616c74 (“salt”)
- Iterations: 4096
- Length: 32
- Click Derive
- DK (HEX): c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a
Sign/Verify
Principle
- Sign with private key, verify with public key. ECDSA (Elliptic Curve Digital Signature Algorithm) outputs (r,s) commonly in DER/RAW encodings; Ed25519 has a more direct interface
sig = Sign(privateKey, H(message))
ok = Verify(publicKey, H(message), sig)
ECDSA-P256 (DER/RAW)
Principle
- Use private key to provide “non-repudiable” authentication of a message; verified with public key. ECDSA results contain two large integers r,s, commonly in two encodings: DER, RAW(r||s 64 bytes)
Hands-on
Page: Sign/Verify → ECDSA-P256
Message (HEX): 616263 (“abc”)
Public Key (SPKI, HEX):
3059301306072a8648ce3d020106082a8648ce3d030107034200047a593180860c4037c83c12749845c8ee1424dd297fadcb895e358255d2c7d2b2a8ca25580f2626fe579062ff1b99ff91c24a0da06fb32b5be20148c9249f5650Sig Encoding: DER
Signature (HEX):
30440220334d7ae5ce7dfa1f69c24acd19601442bda82b4c3dd0a26890f0053066325f72022046cfb76d8f55b0da16e3f82f34ea7264abc85305333ce6db49f48e9c4587d3a9Click Verify
Verify Result: Success
Ed25519
Principle
- Modern curve signature, direct interface, good performance. Unlike ECDSA, no DER/RAW switching confusion
Hands-on
- Page: Sign/Verify → Ed25519
- Message (HEX): 68656c6c6f (“hello”)
- Public Key (SPKI, HEX):
302a300506032b657003210003a107bff3ce10be1d70dd18e74bc09967e4d6309ba50d5f1ddc8664125531b8 - Signature (HEX):
e1a7fca94a835127885b99e2eba733d6ee5bf5dc463ed8385eb6f1dcaa1117c0f151750a10f46f5b3796a91203578f702c85c67c334b5689a516284d499f710f - Click Verify
- Verify Result: Success
Key Exchange
Principle
- Both parties use “my private key + your public key” to obtain the same shared secret; this secret must be processed through HKDF (HMAC-based Key Derivation Function) to derive session keys
S = ECDH(a_priv, b_pub) = ECDH(b_priv, a_pub)
or S = X25519(a_priv, b_pub) = X25519(b_priv, a_pub)
ECDH-P256
Principle
- A uses private key, B uses public key, each independently computes the same shared secret. This secret is not directly used for encryption, needs HKDF derivation to become AEAD key
Hands-on
- Page: Key Exchange → ECDH-P256
- A Private Key (PKCS8.DER):
308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420009f3d9f3d9f3d9f3d9f3d9f3d9f3d9f3d9f3d9f3d9f3d9f3d9f3d9f3d9f3d9fa1440342000408fb02eb998e991b5a615279ac576b5524fcd6b5a26e685aa0c96e88867625a59a106cd6a63087ff2a27c31c392647d18cc5fa8ba9f196e60a04eace8de6f38d - B Public Key (SPKI.DER):
3059301306072a8648ce3d020106082a8648ce3d030107034200045bc3633e112acf5d0abb90f486776ba3500c19b5d095d7ea7163c7846f61f10cce93315c6c3b4dbfee3557a6677f58721c14a18bafc1fe253678e32b7a8337bf - Click Derive
- Shared Secret (HEX): 22a91d018252d0169da3bcb269c2e3852f08b27d2ef5e6c27e4f2ecd4b8e7463
X25519
Principle
- Modern key exchange curve, direct interface, good performance. Like ECDH, outputs shared secret, needs HKDF→AEAD to encrypt
Hands-on
- Page: Key Exchange → X25519
- A Private Key (PKCS8.DER):
302e020100300506032b656e04220420000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f - B Public Key (SPKI.DER):
302a300506032b656e03210087968c1c1642bd0600f6ad869b88f92c9623d0dfc44f01deffe21c9add3dca5f - Click Derive
- Shared Secret (HEX): dae0079aea6e6d02ca215a60d5d8f6689c3ed6009d41882b9181ff2481d9e27a
Certificates and Key Formats
X.509 Certificates
- Certificates are carriers of “public key + identity + validity period + extensions” (X.509 v3)
- Public keys are usually placed in SPKI; private keys are usually placed in PKCS8. Encoding can be DER (binary) or PEM (text)
[Certificate] = { Public Key(SPKI), Subject/Issuer, Validity, Extensions, Signature }
DER(bytes) ⇄ PEM(text wrapper)
Hands-on
Page: X.509
Paste the following PEM into the input area:
-----BEGIN CERTIFICATE----- MIICjTCCAjSgAwIBAgIUQ6eSZ5V2VDhwWNpPYbkmhbNO6JkwCgYIKoZIzj0EAwIw gYQxCzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdCZWlqaW5nMRAwDgYDVQQHDAdCZWlq aW5nMQwwCgYDVQQKDANJb1QxDDAKBgNVBAsMA0RldjEUMBIGA1UEAwwLZXhhbXBs ZS5jb20xHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20wHhcNMjUwODEw MTcwODE3WhcNMzUwODA4MTcwODE3WjCBhDELMAkGA1UEBhMCQ04xEDAOBgNVBAgM B0JlaWppbmcxEDAOBgNVBAcMB0JlaWppbmcxDDAKBgNVBAoMA0lvVDEMMAoGA1UE CwwDRGV2MRQwEgYDVQQDDAtleGFtcGxlLmNvbTEfMB0GCSqGSIb3DQEJARYQdGVz dEBleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCE1SJx84gOs MdT3I7UGLlrKZpHSuRc2mnoeepHkWGfo72iiLr5DJoxCyJJrxsnNvYQEhBg6vsum JyHMX6mVylGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDAdBgNVHSUEFjAU BggrBgEFBQcDAQYIKwYBBQUHAwIwJwYDVR0RBCAwHoILZXhhbXBsZS5jb22CD3d3 dy5leGFtcGxlLmNvbTAdBgNVHQ4EFgQU8+X7PvzqGxEGxEaCcjN5Evp6NC0wCgYI KoZIzj0EAwIDRwAwRAIgO5/F8Mu2KSP3zzxhp6n9HgZT0LIvOjXbMILZF94arY0C IG8cF+T8wn1VyGgbwqFvFLy36qufJ2TgeL/l4mkrj9az -----END CERTIFICATE-----Click Parse and Convert
Parse text includes: Public-Key: (256 bit), Subject/Issuer, Validity, extension OIDs, etc.
Convert can switch between PEM and DER-HEX
Encoding Conversion (Codec)
- Data = bytes; display/exchange requires encoding. Hex/Base64 are representations of bytes to strings; PEM is a Base64 wrapper for DER (binary)
bytes ⇄ hex / base64
DER(bytes) ⇄ PEM("-----BEGIN ..." + base64 + "-----END ...")
Hands-on
- Page: Codec
- Convert Base64 PKCS8/SPKI to HEX before pasting to other pages
- Commonly used: Base64 → HEX; or HEX → Base64
Random Numbers (RNG)
- CSPRNG (Cryptographically Secure Pseudo-Random Number) used to generate keys/nonces/salts
- Length must match purpose: keys (16/24/32 bytes), GCM/ChaCha20-Poly1305 nonces (12 bytes), CCM nonces (13 bytes)
Random(n) → [n byte random] → (key/nonce/salt)
Hands-on
- Page: Random
- Select 16/32/64 bytes; click Generate; paste to other pages as needed
Glossary
| Acronym | Full Name | Description |
|---|---|---|
| AEAD | Authenticated Encryption with Associated Data | Authenticated encryption with associated data, providing both encryption and authentication |
| MAC | Message Authentication Code | Message authentication code, used to verify message integrity and authenticity |
| HMAC | Hash-based Message Authentication Code | Hash-based message authentication code |
| KDF | Key Derivation Function | Key derivation function, generates working keys from raw key material |
| HKDF | HMAC-based Key Derivation Function | HMAC-based key derivation function |
| PBKDF2 | Password-Based Key Derivation Function 2 | Password-based key derivation function version 2 |
| AES | Advanced Encryption Standard | Advanced encryption standard, symmetric encryption algorithm |
| GCM | Galois/Counter Mode | Galois/Counter mode, an AEAD implementation |
| CCM | Counter with CBC-MAC | Counter with CBC-MAC, another AEAD implementation |
| CBC | Cipher Block Chaining | Cipher block chaining mode, traditional block encryption mode |
| CTR | Counter Mode | Counter mode, a mode of operation for block ciphers |
| GHASH | Galois Hash Function | Hash function used in AES-GCM |
| SHA | Secure Hash Algorithm | Secure hash algorithm |
| ECDSA | Elliptic Curve Digital Signature Algorithm | Elliptic curve digital signature algorithm |
| ECDH | Elliptic Curve Diffie-Hellman | Elliptic curve Diffie-Hellman key exchange |
| SPKI | Subject Public Key Info | Subject public key info, public key container format |
| PKCS8 | Private-Key Information Syntax Standard | Private key information syntax standard, private key container format |
| DER | Distinguished Encoding Rules | Distinguished encoding rules, binary encoding format |
| PEM | Privacy-Enhanced Mail | Privacy-enhanced mail, text encoding format based on Base64 |
| RSA | Rivest-Shamir-Adleman | A public-key encryption algorithm name |
| ChaCha20 | Chaotic Cipher 20 | Stream cipher algorithm |
| Poly1305 | Polynomial Evaluation in a 1305-bit finite field | One-time authenticator, often used with ChaCha20 |
| Ed25519 | Edwards Curve 25519 | Signature algorithm based on Edwards 25519 curve |
| X.509 | ITU-T standard | Public key certificate format standard, a digital certificate format |
| X25519 | Edwards Curve 25519 | Key exchange algorithm based on Curve25519 curve |
| CSPRNG | Cryptographically Secure Pseudo-Random Number Generator | Cryptographically secure pseudo-random number generator |
| MITM | Man-in-the-Middle | Man-in-the-middle attack, attacker secretly relays communication between two parties |