Skip to main contentA Practical Guide to Cryptography for IoT | IoT Worker

A Practical Guide to Cryptography for IoT

IoT Cryptography: “Good Enough”

The goal is to use cryptography well enough to understand it and design with it. This article skips heavy mathematics and focuses on the concepts, parameters, and common mistakes that actually matter.

Core Concepts

  • Confidentiality: prevent data from being read without permission
  • Integrity: prevent data from being changed silently
  • Identity: know who is talking to whom
  • Symmetric keys: one key encrypts and decrypts, such as AES or ChaCha20-Poly1305
  • Asymmetric keys: public/private key pairs, such as ECDSA, Ed25519, ECDH, or X25519
  • AEAD: authenticated encryption with associated data, combining encryption and authentication in one step
  • MAC: message authentication code, which authenticates but does not encrypt
  • KDF: key derivation function, which turns raw secrets into usable keys
  • Key formats: SPKI for public keys, PKCS8 for private keys, DER for binary encoding, PEM for text encoding

One Picture

[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] --(signature: private key)--> [signature]
  • AEAD always produces ciphertext plus tag, and the tag must be checked before decryption
  • MACs and signatures do not encrypt data
  • A shared secret is not a final key; it must go through a KDF first

Parameter Cheat Sheet

  • Nonce / IV:
    • GCM: 12 bytes
    • ChaCha20-Poly1305: 12 bytes
    • CCM: commonly 13 bytes
    • CBC: 16 bytes
  • Key sizes:
    • AES: 16 / 24 / 32 bytes
    • ChaCha20-Poly1305: 32 bytes
  • Signature encodings:
    • ECDSA: DER or raw (r || s) form
    • Ed25519: raw form
  • Key containers:
    • SPKI for public keys
    • PKCS8 for private keys

When to Use What

  • Constrained devices or wireless protocols: AES-CCM for hardware acceleration, or ChaCha20-Poly1305 for software-friendly performance
  • Web and general-purpose systems: AES-GCM or ChaCha20-Poly1305
  • Integrity only: HMAC-SHA256 or AES-CMAC
  • Firmware signing or long messages: Ed25519 or ECDSA P-256
  • Session establishment: ECDH P-256 or X25519, then HKDF, then AEAD

Attack and Defense Notes

  • Never reuse an AEAD nonce under the same key
  • CBC does not authenticate data, so it must be paired with a MAC or replaced by AEAD
  • Key exchange must be signed to prevent man-in-the-middle attacks

Quick Start

You can verify these operations quickly in the CryptoBox web page:

  • Symmetric: 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: certificate parsing and conversion
  • Codec: text / hex / base64 / PEM / DER conversion
  • Random: random number generation

Use HEX by default. If a test vector is given in Base64, convert it to HEX first.

Hash

SHA-256

Principle

  • Compresses input of arbitrary length into a fixed 32-byte digest. A small change in the input produces a large change in the output.
  • It can tell you whether data changed, but not who changed 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

HMAC-SHA256

Principle

  • A hash-based MAC: it proves that the sender knows the secret key and that the message was not altered.
  • Intuition: two rounds of hashing, with the key mixed in on the inner pass and again on the outer pass.
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

  • A MAC built on AES. It derives subkeys K1 and K2, adjusts the last block, and then aggregates with AES-CBC-style processing.
[msg] --(split / pad)--> [M1..Mn]
last = (full block? K1 : K2) ⊕ Mn
tag = the 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 Encryption and AEAD

AES-GCM

Principle

  • Uses counter-mode encryption plus GHASH authentication. The nonce must be 12 bytes, and it must never be reused with 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 provides encryption, and Poly1305 provides authentication. It fits software implementations and constrained systems without AES acceleration.
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 of zero)
  • Nonce (HEX): 0000...00 (12 bytes of zero)
  • Click Encrypt
  • Output (HEX, ciphertext||tag): 9e05e4ba50573f7216b4569116f74ad2ff14a1f5698d0dda

AES-CCM

Principle

  • CCM combines CTR encryption with CBC-MAC authentication. It is common in embedded and wireless systems.
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 (64 bits)
  • Click Encrypt
  • Output (HEX, ciphertext||tag): 0b351eb48bc68b348aca2cd428d4864dedec3573620d52d5

AES-CBC (PKCS7/NoPadding)

Principle

  • CBC is a block-chaining mode: each plaintext block is XORed with the previous ciphertext block before encryption. By default it uses PKCS7 padding; NoPadding requires 16-byte alignment. CBC does not provide integrity by itself, so AEAD is preferred.
  • AES is a block cipher with a fixed 128-bit block size, so you must pad the input or make it a multiple of 16 bytes.
P0 = AES-Decrypt(K, C0) ⊕ IV
Pi = AES-Decrypt(K, Ci) ⊕ C{i-1}

Hands-On

  • Page: Symmetric -> AES-CBC
  • Input: 00112233445566778899aabbccddeeff
  • Key: 000102030405060708090a0b0c0d0e0f
  • IV: 0f0e0d0c0b0a09080706050403020100
  • Click Encrypt
  • Then switch to NoPadding if your input is already 16-byte aligned

Key Derivation (KDF)

HKDF-SHA256

Principle

  • HKDF extracts and expands key material. It turns a raw secret, such as an ECDH/X25519 shared secret, into a usable symmetric key.
OKM = HKDF( IKM, salt, info, L )

Hands-On

  • Page: KDF -> HKDF-SHA256
  • Input (HEX): 000102030405060708090a0b0c0d0e0f
  • Salt (HEX): leave empty
  • Info (HEX): leave empty
  • Length: 32
  • Click Derive
  • OKM (HEX): 37ad29109f43265287804b674e2653d0a513718907f97fca97c95bded8104bbf

PBKDF2-SHA256

Principle

  • Password stretching: repeated HMAC iterations significantly increase brute-force cost. The salt should be random and must not be 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 the private key and verify with the public key. ECDSA (Elliptic Curve Digital Signature Algorithm) commonly uses DER or RAW encoding for (r, s), while Ed25519 has a simpler interface.
sig = Sign(privateKey, H(message))
ok = Verify(publicKey, H(message), sig)

ECDSA-P256 (DER/RAW)

Principle

  • Uses the private key to authenticate a message in a non-repudiable way; the public key verifies it. ECDSA produces two large integers, r and s, and common encodings are DER and RAW (r || s, 64 bytes).

Hands-On

  • Page: Sign / Verify -> ECDSA-P256

  • Message (HEX): 616263 ("abc")

  • Public Key (SPKI, HEX):

    3059301306072a8648ce3d020106082a8648ce3d030107034200047a593180860c4037c83c12749845c8ee1424dd297fadcb895e358255d2c7d2b2a8ca25580f2626fe579062ff1b99ff91c24a0da06fb32b5be20148c9249f5650
    
  • Sig Encoding: DER

  • Signature (HEX):

    30440220334d7ae5ce7dfa1f69c24acd19601442bda82b4c3dd0a26890f0053066325f72022046cfb76d8f55b0da16e3f82f34ea7264abc85305333ce6db49f48e9c4587d3a9
    
  • Click Verify

  • Verify result: success

Ed25519

Principle

  • A modern curve signature with a direct interface and good performance. Unlike ECDSA, there is no DER/RAW encoding split to worry about.

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 sides use “my private key + your public key” to derive the same shared secret. That secret must then be expanded through HKDF (HMAC-based Key Derivation Function) into a session key.
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 a private key and B uses a public key, and both independently compute the same shared secret. The secret is not used directly for encryption; it must be expanded with HKDF into an 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

  • A modern key-exchange curve with a direct interface and good performance. Like ECDH, it outputs a shared secret, which must go through HKDF -> AEAD before it can be used for encryption.

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 Certificate

  • A certificate is the carrier for a public key, identity, validity period, and extensions (X.509 v3).
  • Public keys are usually stored in SPKI, and private keys are usually stored in PKCS8. The 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 PEM below 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

  • Parsed text includes: Public-Key: (256 bit), Subject/Issuer, Validity, extension OIDs, and more

  • Convert can round-trip between PEM and DER-HEX

Codec Conversion

  • Data is bytes; display and exchange need encodings. Hex/Base64 are string representations of bytes, and PEM is a Base64 wrapper around DER (binary).
bytes ⇄ hex / base64
DER(bytes) ⇄ PEM("-----BEGIN ..." + base64 + "-----END ...")

Hands-On

  • Page: Codec
  • Convert Base64 PKCS8/SPKI to HEX before pasting into other pages
  • Common flow: Base64 -> HEX, or HEX -> Base64

Random Numbers (RNG)

  • CSPRNGs (cryptographically secure pseudo-random number generators) are used to generate keys, nonces, and salts.
  • Length must match the purpose: keys (16/24/32 bytes), GCM/ChaCha20-Poly1305 nonces (12 bytes), CCM nonces (13 bytes).
Random(n) -> [n random bytes] -> (key / nonce / salt)

Hands-On

  • Page: Random
  • Choose 16 / 32 / 64 bytes, click Generate, and paste the output into other pages as needed

Glossary

AbbreviationFull NameDescription
AEADAuthenticated Encryption with Associated DataAuthenticated encryption with associated data, providing both encryption and authentication
MACMessage Authentication CodeA message authentication code used to verify integrity and authenticity
HMACHash-based Message Authentication CodeA MAC built on a hash function
KDFKey Derivation FunctionA function that derives working keys from raw key material
HKDFHMAC-based Key Derivation FunctionA key derivation function based on HMAC
PBKDF2Password-Based Key Derivation Function 2Version 2 of the password-based key derivation function
AESAdvanced Encryption StandardA symmetric encryption standard
GCMGalois/Counter ModeA Galois/Counter mode, one AEAD construction
CCMCounter with CBC-MACCounter mode with CBC-MAC, another AEAD construction
CBCCipher Block ChainingA classic block-cipher mode
CTRCounter ModeA block-cipher mode that turns a block cipher into a stream-like construction
GHASHGalois Hash FunctionThe hash function used by AES-GCM
SHASecure Hash AlgorithmA family of secure hash algorithms
ECDSAElliptic Curve Digital Signature AlgorithmElliptic-curve digital signature algorithm
ECDHElliptic Curve Diffie-HellmanElliptic-curve Diffie-Hellman key exchange
SPKISubject Public Key InfoSubject public key information, a public-key container format
PKCS8Private-Key Information Syntax StandardPrivate-key information syntax standard, a private-key container format
DERDistinguished Encoding RulesA binary encoding format
PEMPrivacy-Enhanced MailA text encoding format based on Base64
RSARivest-Shamir-AdlemanA public-key algorithm family
ChaCha20Chaotic Cipher 20A stream cipher
Poly1305Polynomial Evaluation in a 1305-bit finite fieldA one-time authenticator, often used with ChaCha20
Ed25519Edwards Curve 25519A signature scheme based on the Edwards 25519 curve
X.509ITU-T standardA public-key certificate standard
X25519Edwards Curve 25519A key-exchange algorithm based on Curve25519
CSPRNGCryptographically Secure Pseudo-Random Number GeneratorA cryptographically secure pseudo-random number generator
MITMMan-in-the-MiddleAn attack in which the attacker secretly relays data between two parties