By the end of this chapter, you should be able to:
Implement symmetric encryption (AES) for IoT data protection
Apply asymmetric encryption (RSA, ECC) for key exchange and digital signatures
Verify message integrity using cryptographic hash functions (SHA-256, BLAKE2)
Select appropriate cryptographic algorithms based on device constraints
Implement HMAC for authenticated messages
In 60 Seconds
IoT cryptography applies symmetric encryption (AES) for fast bulk data protection and asymmetric encryption (ECC/RSA) for secure key exchange, with hash functions (SHA-256) ensuring data integrity across resource-constrained devices.
For Beginners: Understanding Cryptography
What is Cryptography? Cryptography is the science of protecting information by transforming it into an unreadable format (encryption) that can only be converted back (decryption) by someone with the correct key. It’s like a secret code that only authorized parties can understand.
Why does it matter for IoT? IoT devices transmit sensitive data (health readings, location, home activities) over networks where attackers can intercept traffic. Cryptography ensures that even if attackers capture the data, they cannot read or modify it.
Key terms: | Term | Definition | |——|————| | Encryption | Converting readable data (plaintext) into unreadable format (ciphertext) | | Decryption | Converting ciphertext back to plaintext using a key | | Symmetric encryption | Same key for encryption and decryption (fast, for bulk data) | | Asymmetric encryption | Different keys for encryption (public) and decryption (private) | | Hash function | One-way function that creates a fixed-size fingerprint of data |
Sensor Squad: The Secret Code Club!
“I need to send my temperature reading to Max, but the network is not safe!” Sammy the Sensor worried. “Anyone listening could steal my data!”
Max the Microcontroller smiled. “That is what cryptography is for! Think of it like a secret code between friends. With symmetric encryption, we both share the same secret key – like a codebook that only we have. I scramble my message using the key, send it, and you unscramble it with the same key. It is super fast, which is perfect for us IoT devices with limited power.”
“But how do you share the codebook safely in the first place?” Lila the LED asked. “That is where asymmetric encryption comes in! You create TWO keys – a public key and a private key. Anyone can use your public key to lock a message, but ONLY your private key can unlock it. It is like a mailbox slot: anyone can drop a letter in, but only you have the key to open it.”
“And hash functions are like fingerprints!” Bella the Battery added. “Feed any data into a hash function, and you get a unique fixed-size fingerprint. Change even one tiny bit of the data and the fingerprint looks completely different. So when Sammy sends data with its hash, Max can verify nothing was tampered with along the way. Secret codes, locked mailboxes, and fingerprints – that is cryptography in a nutshell!”
4.2 Prerequisites
Before diving into this chapter, you should be familiar with:
Defense in Depth: How encryption fits into the layered security model
Key Concepts
Symmetric Encryption: Encryption where the same secret key is used for both encryption and decryption; fast and suitable for bulk IoT data (e.g., AES-128-GCM).
Asymmetric Encryption: Encryption using a public/private key pair; the public key encrypts, the private key decrypts. Used for key exchange and digital signatures (e.g., RSA, ECC).
AES-GCM: Advanced Encryption Standard in Galois/Counter Mode — provides both encryption and authentication in one operation, widely used in IoT.
HMAC: Hash-based Message Authentication Code — combines a cryptographic hash with a secret key to authenticate messages and detect tampering.
SHA-256: A 256-bit cryptographic hash function producing a fixed-size fingerprint of data; even a 1-bit change in input produces a completely different output.
ECC (Elliptic Curve Cryptography): A form of public-key cryptography offering equivalent security to RSA with much smaller key sizes, making it ideal for constrained IoT devices.
Nonce / IV: A number used once (nonce) or initialization vector — a unique random value that must never be reused with the same key to prevent cryptographic attacks.
4.3 How It Works: AES-GCM Authenticated Encryption
AES-GCM (Galois/Counter Mode) combines encryption and authentication in a single operation:
Encryption Phase:
Generate random IV (Initialization Vector): 12 random bytes (MUST be unique per message)
XOR with plaintext: Plaintext ⊕ keystream = ciphertext (reversible)
Galois authentication: Compute authentication tag over ciphertext + additional data
Decryption Phase:
Verify authentication tag FIRST: Prevents processing tampered ciphertext
If tag invalid: Reject message immediately, log potential attack
If tag valid: Decrypt ciphertext using same IV and key
Return plaintext: Only if authentication succeeded
Key Components:
Symmetric key (128/192/256-bit): Shared secret between sender and receiver
IV (nonce) (96-bit): Random value, different for EVERY message
Additional Authenticated Data (AAD): Unencrypted metadata also protected by tag
Authentication tag (128-bit): Proves message came from holder of key and was not modified
Real-World Example: ESP32 encrypting sensor data
Plaintext:"temperature=25.5,humidity=60"Key:128-bit AES key (pre-shared or negotiated via ECDH)IV: Random 12 bytes generated per messageAAD:"sensor_id=42,timestamp=1735689600"Process:1. Generate random IV:0xa3f8b2c1d4e5f6a7b8c9d0e12. Encrypt with AES-GCM → Ciphertext3. Compute tag over (ciphertext + AAD)4. Send: IV || ciphertext || tag (total +28 bytes overhead)Receiver:1. Extract IV, ciphertext, tag2. Verify tag using key + IV + ciphertext + AAD3. If valid → decrypt ciphertext4. If invalid → reject (message tampered or wrong key)
Why GCM mode? Older modes (ECB, CBC) provide ONLY confidentiality. GCM provides confidentiality + integrity + authenticity. A message with flipped bits is detected and rejected BEFORE decryption.
4.4 Symmetric Encryption
Definition: Same key for encryption and decryption
Use Cases: Data confidentiality, session encryption, bulk data protection
Common Algorithms:
AES: Advanced Encryption Standard (128/192/256-bit)
ChaCha20: Fast on devices without AES hardware acceleration
ChaCha20: Devices without AES hardware acceleration
Try It: Symmetric Cipher Throughput Estimator
Estimate how long it takes to encrypt a batch of IoT sensor readings with different symmetric ciphers and key sizes. Adjust the payload size and device clock speed to see the impact on throughput and latency.
Public Key: Can be shared with anyone
Private Key: Must be kept secret
Encryption: Plaintext + Public Key → Ciphertext
Decryption: Ciphertext + Private Key → Plaintext
Digital Signature:
Sign: Hash + Private Key → Signature
Verify: Signature + Public Key → Valid/Invalid
4.5.2 RSA Digital Signature Implementation
Signing – hash the firmware, then sign the hash with the private key:
Recommendation: Use ECC (specifically Ed25519 or ECDSA P-256) for IoT devices due to smaller key sizes and faster operations.
Try It: ECC vs RSA Key Size and Performance Comparison
Compare how ECC and RSA scale with increasing security levels. Observe the dramatic difference in key sizes, signature sizes, and verification times – the reason ECC dominates IoT cryptography.
Definition: One-way functions that produce a fixed-size output (digest) from any input
Use Cases: Message integrity, password storage, checksums, digital signatures
Common Algorithms:
SHA-256: 256-bit hash, standard choice
SHA-3: Latest NIST standard
BLAKE2: Faster alternative to SHA-2
4.6.1 Properties of Good Hash Functions
Property
Description
Example
Deterministic
Same input always produces same output
SHA256(“hello”) always = 2cf24…
One-way
Cannot reverse hash to get original input
Cannot get “hello” from 2cf24…
Collision-resistant
Hard to find two inputs with same hash
SHA256(“a”) ≠ SHA256(“b”)
Avalanche effect
Small input change = completely different output
SHA256(“hello”) ≠ SHA256(“hellp”)
4.6.2 SHA-256 Implementation for Message Integrity
// SHA-256 for message integrity#include "mbedtls/sha256.h"String computeHash(constuint8_t* data,size_t len){uint8_t hash[32]; mbedtls_sha256(data, len, hash,0);// Convert to hex String hashStr ="";for(int i =0; i <32; i++){ hashStr += String(hash[i], HEX);}return hashStr;}// Example usagevoid verifyDataIntegrity(){ String sensorData ="temperature=25.5,humidity=60"; String hash = computeHash((uint8_t*)sensorData.c_str(), sensorData.length()); Serial.println("Data: "+ sensorData); Serial.println("Hash: "+ hash);// Send both data and hash// Receiver computes hash and compares to verify integrity}
Try It: Hash Avalanche Effect Explorer
Type two messages below to see how even a tiny change in input produces a completely different hash output. This demonstrates the avalanche effect – a critical property of cryptographic hash functions that makes them useful for integrity verification.
Show code
viewof hashMsg1 = Inputs.text({value:"temperature=25.5",label:"Message 1:",placeholder:"Enter first message",width:"100%"})viewof hashMsg2 = Inputs.text({value:"temperature=25.6",label:"Message 2:",placeholder:"Enter second message",width:"100%"})
Show code
{asyncfunctionsha256Hex(message) {const encoder =newTextEncoder();const data = encoder.encode(message);const hashBuffer =await crypto.subtle.digest("SHA-256", data);const hashArray =Array.from(newUint8Array(hashBuffer));return hashArray.map(b => b.toString(16).padStart(2,"0")).join(""); }functionhexToBinary(hex) {return hex.split("").map(h =>parseInt(h,16).toString(2).padStart(4,"0")).join(""); }functioncountDiffBits(bin1, bin2) {let diff =0;for (let i =0; i <Math.min(bin1.length, bin2.length); i++) {if (bin1[i] !== bin2[i]) diff++; }return diff; }const hash1 =awaitsha256Hex(hashMsg1 ||"");const hash2 =awaitsha256Hex(hashMsg2 ||"");const bin1 =hexToBinary(hash1);const bin2 =hexToBinary(hash2);const diffBits =countDiffBits(bin1, bin2);const totalBits =256;const diffPct = ((diffBits / totalBits) *100).toFixed(1);const identical = hashMsg1 === hashMsg2;const coloredHash2 = hash2.split("").map((ch, i) => ch !== hash1[i]?`<span style="color:#E74C3C;font-weight:bold;">${ch}</span>`:`<span>${ch}</span>` ).join("");const inputDiffChars =Math.abs(hashMsg1.length- hashMsg2.length);let charDiffs =0;const minLen =Math.min(hashMsg1.length, hashMsg2.length);for (let i =0; i < minLen; i++) {if (hashMsg1[i] !== hashMsg2[i]) charDiffs++; } charDiffs +=Math.abs(hashMsg1.length- hashMsg2.length);returnhtml`<div style="padding:16px;background:linear-gradient(135deg,#f5f0ff,#f0f5ff);border:1px solid #3498DB;border-radius:8px;line-height:1.8;font-size:0.95em;"> <h4 style="margin:0 0 12px;color:#2C3E50;">SHA-256 Avalanche Effect</h4> <div style="font-family:monospace;padding:10px;background:#fff;border-radius:4px;margin-bottom:8px;word-break:break-all;font-size:0.85em;"> <div><strong style="color:#16A085;">Hash 1:</strong> ${hash1}</div> <div><strong style="color:#E67E22;">Hash 2:</strong> ${coloredHash2}</div> </div> <div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px;margin-bottom:12px;"> <div style="text-align:center;padding:10px;background:#e8f8f5;border-radius:6px;"> <div style="font-size:0.8em;color:#7F8C8D;">Input difference</div> <div style="font-size:1.4em;font-weight:bold;color:#16A085;">${charDiffs} char${charDiffs !==1?"s":""}</div> </div> <div style="text-align:center;padding:10px;background:${identical ?"#fef2f2": diffPct >40&& diffPct <60?"#f0fdf4":"#fefce8"};border-radius:6px;"> <div style="font-size:0.8em;color:#7F8C8D;">Bits changed</div> <div style="font-size:1.4em;font-weight:bold;color:${identical ?"#E74C3C":"#2C3E50"};">${diffBits} / ${totalBits}</div> </div> <div style="text-align:center;padding:10px;background:${identical ?"#fef2f2": diffPct >40&& diffPct <60?"#f0fdf4":"#fefce8"};border-radius:6px;"> <div style="font-size:0.8em;color:#7F8C8D;">Change ratio</div> <div style="font-size:1.4em;font-weight:bold;color:${identical ?"#E74C3C":"#2C3E50"};">${diffPct}%</div> </div> </div> <div style="background:#fff;border-radius:4px;overflow:hidden;height:16px;margin-bottom:8px;"> <div style="background:linear-gradient(90deg,#E74C3C,#E67E22);height:100%;width:${diffPct}%;transition:width 0.3s;border-radius:4px;"></div> </div> <div style="padding:8px;background:#fff;border-radius:4px;border-left:3px solid ${identical ?"#E74C3C": diffPct >40&& diffPct <60?"#16A085":"#E67E22"};font-size:0.9em;">${identical?"<strong>Identical inputs produce identical hashes</strong> -- this is the deterministic property.": diffPct >40&& diffPct <60?`<strong>Ideal avalanche!</strong> Changing ${charDiffs} character${charDiffs !==1?"s":""} in the input flipped ${diffPct}% of output bits (ideal is ~50%). This makes it impossible to predict how a hash will change from input changes.`:`<strong>Avalanche in action:</strong> ${diffPct}% of bits changed. With many trials, the average converges to ~50% -- each output bit has roughly equal probability of flipping.`} </div> </div>`;}
4.6.3 HMAC for Authenticated Messages
HMAC (Hash-based Message Authentication Code) combines a hash function with a secret key to provide both integrity AND authentication.
Simulate how HMAC protects IoT messages. See what happens when an attacker tries to tamper with the message or forge an authentication tag without the secret key.
Show code
viewof hmacMessage = Inputs.text({value:"temperature=25.5,humidity=60",label:"Original sensor message:",placeholder:"Enter sensor data",width:"100%"})viewof hmacKey = Inputs.text({value:"my-secret-key-42",label:"Shared secret key:",placeholder:"Enter HMAC key",width:"100%"})viewof hmacScenario = Inputs.radio( ["Normal (no tampering)","Attacker modifies message","Attacker forges with wrong key"], {value:"Normal (no tampering)",label:"Scenario:"})
Show code
{asyncfunctionhmacSha256(key, message) {const enc =newTextEncoder();const keyData =await crypto.subtle.importKey("raw", enc.encode(key), {name:"HMAC",hash:"SHA-256"},false, ["sign"] );const sig =await crypto.subtle.sign("HMAC", keyData, enc.encode(message));returnArray.from(newUint8Array(sig)).map(b => b.toString(16).padStart(2,"0")).join(""); }const originalTag =awaithmacSha256(hmacKey ||"key", hmacMessage ||"");let receivedMsg = hmacMessage;let receivedTag = originalTag;let verifyKey = hmacKey;let tamperedDetail ="";if (hmacScenario ==="Attacker modifies message") { receivedMsg = (hmacMessage ||"") +",malicious=true"; receivedTag = originalTag; tamperedDetail ="Attacker appended ',malicious=true' to the message but cannot recompute the HMAC without the key."; } elseif (hmacScenario ==="Attacker forges with wrong key") { receivedMsg = hmacMessage; verifyKey ="wrong-key-99"; receivedTag =awaithmacSha256("wrong-key-99", hmacMessage ||""); tamperedDetail ="Attacker computed HMAC with a guessed key 'wrong-key-99'. The tag will not match the receiver's computation."; }const recomputedTag =awaithmacSha256(hmacKey ||"key", receivedMsg ||"");const tagMatch = receivedTag === recomputedTag;returnhtml`<div style="padding:16px;background:linear-gradient(135deg,#f0fff4,#f0f8ff);border:1px solid ${tagMatch ?"#16A085":"#E74C3C"};border-radius:8px;line-height:1.8;font-size:0.95em;"> <h4 style="margin:0 0 12px;color:#2C3E50;">HMAC-SHA256 Verification</h4> <div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:12px;"> <div style="padding:10px;background:#fff;border-radius:6px;border:1px solid #ddd;"> <div style="font-weight:bold;color:#16A085;margin-bottom:4px;">Sender</div> <div style="font-size:0.85em;word-break:break-all;"><strong>Message:</strong> ${hmacMessage}</div> <div style="font-size:0.85em;font-family:monospace;word-break:break-all;margin-top:4px;"><strong>HMAC tag:</strong> ${originalTag.substring(0,32)}...</div> </div> <div style="padding:10px;background:#fff;border-radius:6px;border:1px solid #ddd;"> <div style="font-weight:bold;color:#E67E22;margin-bottom:4px;">Receiver gets</div> <div style="font-size:0.85em;word-break:break-all;"><strong>Message:</strong> ${receivedMsg}</div> <div style="font-size:0.85em;font-family:monospace;word-break:break-all;margin-top:4px;"><strong>Attached tag:</strong> ${receivedTag.substring(0,32)}...</div> </div> </div> <div style="padding:10px;background:#fff;border-radius:6px;border:1px solid #ddd;margin-bottom:12px;"> <div style="font-weight:bold;color:#3498DB;margin-bottom:4px;">Receiver recomputes HMAC</div> <div style="font-size:0.85em;font-family:monospace;word-break:break-all;"><strong>Recomputed:</strong> ${recomputedTag.substring(0,32)}...</div> <div style="font-size:0.85em;font-family:monospace;word-break:break-all;"><strong>Received tag:</strong> ${receivedTag.substring(0,32)}...</div> </div> <div style="padding:12px;background:${tagMatch ?"#f0fdf4":"#fef2f2"};border-radius:6px;border-left:4px solid ${tagMatch ?"#16A085":"#E74C3C"};"> <div style="font-size:1.1em;font-weight:bold;color:${tagMatch ?"#16A085":"#E74C3C"};">${tagMatch ?"VERIFIED -- Tags match! Message is authentic and unmodified.":"REJECTED -- Tags do NOT match! Message may be tampered or forged."} </div>${tamperedDetail ?`<div style="margin-top:6px;font-size:0.9em;color:#7F8C8D;">${tamperedDetail}</div>`:""} </div> <div style="margin-top:10px;padding:8px;background:#fff;border-radius:4px;border-left:3px solid #9B59B6;font-size:0.85em;"> <strong>Key point:</strong> Unlike a plain hash, HMAC requires the secret key to compute. An attacker who intercepts the message cannot forge a valid tag, and any modification to the message invalidates the tag. This is why IoT devices use HMAC for sensor data authentication. </div> </div>`;}
Knowledge Check: Cryptography Selection
Question: An IoT temperature sensor needs to send encrypted readings every 30 seconds to a cloud server. Which cryptographic approach provides the BEST balance of security and performance?
A. RSA-2048 asymmetric encryption for all sensor readings B. SHA-256 hashing without encryption C. AES-128 symmetric encryption with periodic key rotation D. No encryption but send over HTTPS only
Click to reveal answer
Answer: C - AES-128 symmetric encryption with periodic key rotation
Why?
AES-128 is fast (50-100 MB/s), uses minimal CPU, and provides strong security
RSA is too slow for frequent encryption (every 30 seconds)
SHA-256 provides integrity but NOT confidentiality (anyone can read the data)
HTTPS adds overhead; a persistent encrypted MQTT session is more efficient
Periodic key rotation (e.g., daily) maintains security even if a key is compromised.
4.7 Per-Device vs Global Keys
Tradeoff: Per-Device Keys vs Global Keys
Option A (Global Key): All 1,000 sensors share one AES encryption key - Simpler key management - Single key to rotate - Risk: If ANY sensor is compromised, ALL sensor data is exposed
Option B (Per-Device Keys): Each sensor has unique AES key - More complex key management (1,000 keys) - Requires automated provisioning - Benefit: Compromised sensor only exposes that one device’s data
Decision: Always use per-device keys. The complexity is worth the isolation benefit. Modern IoT platforms (AWS IoT Core, Azure IoT Hub) enforce per-device credentials.
4.8 Case Study: Philips Hue Bridge Cryptographic Vulnerability (CVE-2020-6007)
In February 2020, researchers at Check Point discovered a vulnerability chain in the Philips Hue smart lighting ecosystem that demonstrated why cryptographic implementation details matter as much as algorithm selection.
The Setup: Philips Hue uses Zigbee (IEEE 802.15.4) with AES-128 encryption for bulb-to-bridge communication, and TLS 1.2 with ECC certificates for bridge-to-cloud. On paper, the cryptographic choices were sound.
Touchlink used a known factory-default AES key for “easy pairing”
2
Compromise one Hue bulb with malicious firmware
Firmware signed but bulb accepted unsigned Zigbee OTA updates
3
Trigger buffer overflow in bridge when processing bulb color data
Bridge trusted AES-encrypted data without input validation
4
Gain root access to bridge on home network
Bridge stored network credentials in plaintext flash
Impact Assessment:
Affected devices: Over 15 million Philips Hue bulbs and 3+ million bridges worldwide
Attack range: Zigbee radio range (~100m line of sight), extendable via compromised bulbs daisy-chaining
Consequence: Full home network access from a compromised light bulb
Patch timeline: Signify (Philips parent) released firmware 1935144040 within 2 weeks
Cryptographic Lessons:
Principle
What Philips Did Wrong
Correct Approach
Key management
Factory-default touchlink key shared across all devices
Per-device unique pairing keys generated during manufacturing
Firmware signing
Zigbee OTA updates accepted without signature verification
Require Ed25519/ECDSA signature on ALL firmware paths, not just cloud-to-bridge
Trust boundary
Bridge trusted encrypted data from bulbs without validation
Encrypt AND validate: AES protects confidentiality, but input sanitization prevents exploitation
Credential storage
Wi-Fi password stored in plaintext on bridge flash
Use hardware security module or encrypted keystore
Key lesson: The Philips Hue ecosystem used strong algorithms (AES-128, TLS 1.2, ECC) but made implementation errors that rendered the cryptography ineffective. A factory-default shared key is equivalent to no key. Signing firmware on one path but not another creates a bypass. Trusting encrypted data without validation confuses confidentiality with integrity. Cryptographic security requires correct implementation across every interface, not just the primary data path.
Worked Example: Securing an ESP32 Temperature Sensor Network
Scenario: You’re deploying 50 ESP32 temperature sensors in an industrial facility. Each sensor transmits data every 10 seconds to a cloud MQTT broker. You need to implement end-to-end encryption while minimizing CPU overhead on the constrained devices.
Implementation Steps:
Symmetric Encryption for Bulk Data: Use AES-128-GCM (authenticated encryption) for sensor readings:
ESP32 has hardware AES acceleration → 50 MB/s throughput
Battery impact: Minimal (0.02% of transmission energy)
Asymmetric Key Exchange: Use ECDH (Elliptic Curve Diffie-Hellman) with P-256 curve for session key establishment:
Device generates ephemeral ECC key pair (256-bit)
Exchanges public keys with cloud server
Both derive shared secret (32 bytes), then use HKDF to produce AES-128 session key (16 bytes)
Key exchange time: ~8 ms on ESP32
Performed once per connection, reused for 1000+ messages
Per-Device Unique Keys: Each ESP32 has unique device certificate (ECC P-256) burned into flash during manufacturing:
Device private key: stored in ESP32 flash encryption partition
Device public certificate: uploaded to cloud during provisioning
Cloud verifies device identity during TLS handshake
Compromising one sensor does NOT expose other 49 sensors
Performance Measurements (on ESP32 @ 240 MHz): - AES-128-GCM encryption: 1.3 ms per 64-byte payload - ECDH key exchange: 8 ms (once per session) - Total CPU time per message: 1.3 ms encryption + 0.4 ms TLS overhead = 1.7 ms - CPU utilization: (1.7 ms / 10,000 ms) × 100 = 0.017% per message - Power consumption: Encryption adds <0.5 mAh per day to battery
Cost-Benefit Analysis:
Security benefit: Prevents eavesdropping, replay attacks, data tampering
Performance cost: 1.7 ms CPU time per message (negligible on 10-second interval)
Implementation cost: ~$0.50 per device for ECC secure element (ATECC608)
Alternative cost: Data breach after sensor compromise = $50K+ in downtime and investigation
Result: With hardware-accelerated AES-128-GCM and ECDH key exchange, the ESP32 sensor network achieves strong encryption with less than 0.02% CPU overhead. The $25 additional cost ($0.50 x 50 devices) prevents potential $50K+ breach costs – a 2000x return on investment.
Interactive Encryption Overhead Calculator: Adjust parameters to see how encryption impacts your IoT deployment.
{const encryptionMs = payload_bytes *0.02;// ~0.02 ms per byte for AES-GCM on ESP32const tlsOverheadMs =0.4;const totalMsPerMsg = encryptionMs + tlsOverheadMs;const cpuPercent = (totalMsPerMsg / (msg_interval *1000)) *100;const msgsPerDay = (86400/ msg_interval) * num_sensors;const overheadBytes =28;// IV (12) + tag (16)const dailyOverheadKB = (msgsPerDay * overheadBytes) /1024;const totalCost = num_sensors * secure_element_cost;returnhtml`<div style="padding:16px;background:#eff6ff;border:1px solid #93c5fd;border-radius:8px;line-height:1.8;"> <div><strong>Encryption time per message:</strong> ${encryptionMs.toFixed(2)} ms (AES-GCM) + ${tlsOverheadMs} ms (TLS) = <strong>${totalMsPerMsg.toFixed(2)} ms</strong></div> <div><strong>CPU utilization per sensor:</strong> ${totalMsPerMsg.toFixed(2)} ms / ${(msg_interval *1000).toLocaleString()} ms = <strong>${cpuPercent.toFixed(4)}%</strong></div> <div><strong>Messages per day (all sensors):</strong> <strong>${msgsPerDay.toLocaleString()}</strong></div> <div><strong>Daily encryption overhead (bandwidth):</strong> <strong>${dailyOverheadKB.toFixed(1)} KB</strong> (${overheadBytes} bytes IV+tag per message)</div> <div><strong>Secure element cost (${num_sensors} devices):</strong> <strong>$${totalCost.toFixed(2)}</strong></div> <div style="margin-top:8px;padding:8px;background:${cpuPercent <1?'#f0fdf4': cpuPercent <10?'#fefce8':'#fef2f2'};border-radius:4px;"> <strong>Assessment:</strong> ${cpuPercent <0.1?"Negligible CPU impact -- encryption is effectively free.": cpuPercent <1?"Very low CPU impact -- well within budget for most IoT devices.": cpuPercent <10?"Moderate CPU impact -- consider increasing message interval or using hardware acceleration.":"High CPU impact -- reduce message frequency or use a device with AES hardware acceleration."} </div> </div>`;}
Decision Framework: Choosing Cryptographic Algorithms for IoT Devices
Selection Criteria Comparison Table:
Device Profile
Symmetric Cipher
Asymmetric Cipher
Hash Function
Best For
Justification
High-End Gateway (1+ GHz CPU, 512+ MB RAM)
AES-256-GCM
RSA-2048 or ECC P-384
SHA-256
TLS 1.3 with full certificate chain
Full cryptographic suite; supports all modern protocols
Microcontroller (160-240 MHz, 64-256 KB RAM)
AES-128-GCM (hardware accel)
ECC P-256 (ECDH/ECDSA)
SHA-256
MQTT over TLS, CoAP over DTLS
Hardware AES acceleration on ESP32/STM32; ECC has 10× smaller keys than RSA
Severely Constrained (<32 KB RAM, <8 MHz)
ChaCha20-Poly1305 or AES-128-CCM
Ed25519
BLAKE2s
Custom lightweight protocols
ChaCha20 is fast in software; Ed25519 is fastest signature algorithm
Sensor with Crypto Chip (TPM/ATECC608)
AES-128 (in hardware)
ECC P-256 (in hardware)
SHA-256
Medical IoT, payment terminals
Hardware security module prevents key extraction; FIPS 140-2 compliant
Legacy Device (no crypto support)
None (upgrade or replace)
None
None
Isolated VLAN with gateway encryption
Cannot secure device itself; compensate with network-level encryption at gateway
Decision Tree:
Does the device have AES hardware acceleration?
YES → Use AES-128-GCM for symmetric encryption
NO → Use ChaCha20-Poly1305 (faster in software than AES)
Does the device have >64 KB RAM?
YES → Use ECC P-256 for asymmetric (supports TLS/DTLS)
NO → Use Ed25519 (smaller stack footprint than ECDSA)
Does the device transmit sensitive regulated data (HIPAA, PCI-DSS)?
YES → Use AES-256-GCM + hardware secure element (ATECC608) for key storage
NO → AES-128-GCM is sufficient for commercial IoT
What is the device operational lifespan?
<5 years → AES-128, RSA-2048, SHA-256 (current standards)
5-10 years → AES-256, ECC P-384, SHA-384 (future-proofing)
10+ years → Plan for post-quantum cryptography transition (CRYSTALS-Kyber, CRYSTALS-Dilithium)
Upgrade to AES-256 for: Medical devices, financial IoT, government deployments (FIPS compliance)
Use hardware crypto chips when: Device stores long-term keys, compliance required, or attack risk is high
Common Mistake: Using ECB Mode for IoT Sensor Data Encryption
What Developers Do Wrong: Many IoT projects use AES in ECB (Electronic Codebook) mode because it’s the simplest mode to implement — no initialization vector (IV) required, deterministic output, easy to parallelize. A developer encrypts temperature sensor readings with AES-128-ECB, sends ciphertext over MQTT, and assumes the data is secure.
Why It Fails Catastrophically: ECB mode encrypts each 16-byte block independently with the same key. Identical plaintext blocks always produce identical ciphertext blocks, revealing patterns even without decryption:
Temperature sensor sends: {"temp":22} → Ciphertext A
10 minutes later, sends: {"temp":22} → Same Ciphertext A
Attacker observes: “Ciphertext A repeated 50 times today = temperature hasn’t changed”
Even worse: Attacker can recognize “22°C” ciphertext vs “28°C” ciphertext without knowing the key, then replay the “22°C” ciphertext when AC should be off, tricking the HVAC controller
Real-World Example: In 2020, a smart thermostat manufacturer used AES-ECB for temperature setpoint commands. Security researchers captured encrypted “set to 16°C” commands and replayed them to chill buildings to 16°C during summer heatwaves. Despite AES-128 encryption, the system was completely broken.
Correct Approach: Always use authenticated encryption modes with randomized IVs: - AES-128-GCM (best for IoT): Provides encryption + authentication in one pass, prevents tampering - AES-128-CCM (alternative): Designed for resource-constrained devices, used in Zigbee/Thread - ChaCha20-Poly1305: Fast on devices without AES hardware acceleration
Implementation Fix (ESP32 example):
// WRONG: ECB mode (deterministic)mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_ENCRYPT, plaintext, ciphertext);// CORRECT: GCM mode (random IV, authenticated)unsignedchar iv[12];mbedtls_ctr_drbg_random(&ctr_drbg, iv,12);// Generate random IVmbedtls_gcm_crypt_and_tag(&gcm, MBEDTLS_GCM_ENCRYPT, len, iv,12, NULL,0, plaintext, ciphertext,16, tag);// Send: IV || ciphertext || tag
The Cost: Using ECB instead of GCM on a 100-device industrial IoT deployment allowed attackers to infer production schedules from traffic patterns and launch a ransomware attack targeting high-production periods. Loss: $2.3M in downtime. The 5-line code change to GCM would have prevented the entire attack.
Concept Relationships
Concept
Related To
Relationship Type
Symmetric Encryption
AES-GCM, ChaCha20
Implements - Fast bulk data encryption using shared secret keys
Asymmetric Encryption
RSA, ECC, Key Exchange
Enables - Secure key distribution without pre-shared secrets
Hash Functions
SHA-256, Integrity Checking
Provides - One-way fingerprints for data verification
HMAC
Message Authentication
Combines - Hash + secret key for authenticated messages
Digital Signatures
Public Key, Non-Repudiation
Proves - Message origin and prevents sender denial
Key Management
Secure Elements, TPM
Protects - Cryptographic keys in tamper-resistant hardware
Security: Factoring \(N=3233\) is trivial (\(61 \times 53\)). Real RSA-2048 uses 1024-bit primes – factoring a 2048-bit modulus requires \(\approx 2^{112}\) operations using the best known algorithms (infeasible with current technology).
Result: RSA-2048 provides ~112-bit security. ECC P-256 provides ~128-bit security with 256-bit keys (8× smaller than RSA-2048). For IoT, ECC wins on efficiency.
In practice: RSA-2048 signatures require 2048-bit keys, 256-byte signatures, and slow verification (~10-50ms on ESP32). ECDSA P-256 uses 256-bit keys, 64-byte signatures, and fast verification (~5-10ms). For firmware signing on constrained devices, ECC’s smaller keys and faster operations reduce OTA update time and energy consumption.
Interactive RSA Explorer: Try different small primes to see how RSA key generation works.
{functionisPrime(n) {if (n <2) returnfalse;if (n <4) returntrue;if (n %2===0|| n %3===0) returnfalse;for (let i =5; i * i <= n; i +=6) {if (n % i ===0|| n % (i +2) ===0) returnfalse; }returntrue; }functiongcd(a, b) { while (b) { [a, b] = [b, a % b]; } return a; }functionmodPow(base, exp, mod) {let result =1n; base =BigInt(base) %BigInt(mod);let e =BigInt(exp);let m =BigInt(mod);while (e >0n) {if (e %2n ===1n) result = (result * base) % m; e = e /2n; base = (base * base) % m; }returnNumber(result); }functionmodInverse(a, m) {let [old_r, r] = [a, m];let [old_s, s] = [1,0];while (r !==0) {let q =Math.floor(old_r / r); [old_r, r] = [r, old_r - q * r]; [old_s, s] = [s, old_s - q * s]; }return old_r ===1? ((old_s % m) + m) % m :-1; }const p = rsa_p;const q = rsa_q;const m = rsa_message;const pIsPrime =isPrime(p);const qIsPrime =isPrime(q);if (!pIsPrime ||!qIsPrime) {returnhtml`<div style="padding:12px;background:#fef2f2;border:1px solid #fca5a5;border-radius:6px;"> <strong>Error:</strong> ${!pIsPrime ?`p = ${p} is not prime.`:""}${!qIsPrime ?`q = ${q} is not prime.`:""} Both p and q must be prime numbers.</div>`; }if (p === q) {returnhtml`<div style="padding:12px;background:#fef2f2;border:1px solid #fca5a5;border-radius:6px;"> <strong>Error:</strong> p and q must be different primes.</div>`; }const N = p * q;const phi = (p -1) * (q -1);// Find smallest valid elet e =3;while (e < phi &&gcd(e, phi) !==1) e +=2;if (e >= phi) {returnhtml`<div style="padding:12px;background:#fef2f2;border:1px solid #fca5a5;border-radius:6px;"> <strong>Error:</strong> Cannot find valid public exponent for these primes.</div>`; }const d =modInverse(e, phi);if (m >= N) {returnhtml`<div style="padding:12px;background:#fef2f2;border:1px solid #fca5a5;border-radius:6px;"> <strong>Error:</strong> Message m = ${m} must be less than N = ${N}.</div>`; }const ciphertext =modPow(m, e, N);const decrypted =modPow(ciphertext, d, N);returnhtml`<div style="padding:16px;background:#f0fdf4;border:1px solid #86efac;border-radius:8px;font-family:monospace;line-height:1.8;"> <div><strong>Step 1:</strong> N = p x q = ${p} x ${q} = <strong>${N}</strong></div> <div><strong>Step 2:</strong> phi(N) = (${p}-1)(${q}-1) = ${p-1} x ${q-1} = <strong>${phi}</strong></div> <div><strong>Step 3:</strong> e = <strong>${e}</strong> (smallest coprime to phi(N))</div> <div><strong>Step 4:</strong> d = e<sup>-1</sup> mod phi(N) = <strong>${d}</strong></div> <div><strong>Verify:</strong> e x d mod phi(N) = ${e} x ${d} mod ${phi} = <strong>${(e * d) % phi}</strong> ${(e * d) % phi ===1?"✓":"✗"}</div> <hr style="margin:8px 0;border-color:#86efac;"> <div><strong>Public key:</strong> (N=${N}, e=${e})</div> <div><strong>Private key:</strong> (N=${N}, d=${d})</div> <hr style="margin:8px 0;border-color:#86efac;"> <div><strong>Encrypt:</strong> c = m<sup>e</sup> mod N = ${m}<sup>${e}</sup> mod ${N} = <strong>${ciphertext}</strong></div> <div><strong>Decrypt:</strong> m = c<sup>d</sup> mod N = ${ciphertext}<sup>${d}</sup> mod ${N} = <strong>${decrypted}</strong> ${decrypted === m ?"✓":"✗"}</div> </div>`;}
Match the Cryptographic Concept to Its Purpose
Order the Steps to Secure an IoT Sensor Message
4.9 Chapter Summary
Cryptography provides the technical foundation for IoT data protection. Symmetric encryption (AES) offers fast, efficient bulk data encryption suitable for resource-constrained devices. Asymmetric encryption (RSA, ECC) enables secure key exchange and digital signatures without pre-shared secrets. Hash functions provide data integrity verification, while HMAC adds authentication to ensure messages come from authorized senders.
Algorithm selection depends on device capabilities and security requirements: use AES-128 or ChaCha20 for data encryption, ECC (Ed25519 or ECDSA P-256) for signatures, and SHA-256 for hashing. Always use per-device keys rather than global keys to limit the blast radius of any single device compromise.
4.10 Knowledge Check
Quiz: Cryptography for IoT
Common Pitfalls
1. Confusing Encryption with Authentication
Mistake: Assuming AES-128 encryption alone proves the sender is legitimate. Why it happens: Encryption ensures confidentiality, not identity. Fix: Always pair encryption with HMAC or digital signatures; use authenticated encryption modes like AES-GCM that provide both in one operation.
2. Using ECB Mode for Block Ciphers
Mistake: Selecting AES-ECB for device data because it is simpler to implement. Why it happens: ECB requires no IV management, but identical plaintext blocks produce identical ciphertext, leaking patterns. Fix: Always use AES-CBC with a random IV, or preferably AES-GCM for authenticated encryption.
3. Hardcoding Cryptographic Keys
Mistake: Embedding symmetric keys directly in firmware or configuration files. Why it happens: Simplicity during development carries over to production. Fix: Use hardware security modules (HSM), Trusted Execution Environments (TEE), or secure element chips (ATECC608) to store keys outside readable memory.
4. Neglecting Key Rotation
Mistake: Using the same session key for months or years. Why it happens: Key rotation adds operational complexity. Fix: Implement automatic key rotation schedules — hourly for high-security applications, daily for standard IoT deployments — using derived keys from a master secret.
5. Choosing RSA Over ECC for Constrained Devices
Mistake: Deploying RSA-2048 on microcontrollers with limited RAM and CPU. Why it happens: RSA is more familiar than ECC. Fix: Use Curve25519 or NIST P-256 ECC which provide equivalent security to RSA-3072 at 10x less computational cost, critical for battery-powered IoT devices.
Label the Diagram
4.11 What’s Next
With cryptographic fundamentals in place, the next chapter examines Authentication Methods where you’ll learn to implement password-based, certificate-based, and token-based authentication systems for IoT devices.