Understanding Encryption and KLAP Authentication
If you're like me and find encryption confusing, this guide is for you. I'll explain encryption from the ground up, then we'll see how KLAP (the protocol Tapo devices use) puts these concepts together.
Part 1: Encryption Basics 🔐
What is Encryption?
Imagine you want to send a secret message to a friend. Encryption is like putting that message in a locked box. Only someone with the right key can open it and read the message.
Simple Example:
Your message: "Hello"
Encrypted: "X7#mK" ← Looks like gibberish
Decrypted: "Hello" ← Back to readable
Two Types of Encryption
1. Symmetric Encryption (Same Key for Both)
- Like a physical lock and key
- You use the same key to lock and unlock
- Fast and efficient
- Problem: How do you share the key securely?
┌─────────────────────────────────────────┐
│ Alice Bob │
│ │
│ Message: "Hi" │
│ ↓ │
│ Lock with Key123 │
│ ↓ │
│ Encrypted: "X7mK" ─────────► │
│ ↓ │
│ Unlock with Key123 │
│ ↓ │
│ Message: "Hi" │
└─────────────────────────────────────────┘
Example in real life: AES (Advanced Encryption Standard)
2. Asymmetric Encryption (Two Different Keys)
- Like a mailbox with a slot
- Public key: Anyone can put mail in (encrypt)
- Private key: Only you can open it (decrypt)
- Slower than symmetric
- Solves the key-sharing problem!
┌────────────────────────────────────────────┐
│ Bob generates two keys: │
│ 🔓 Public Key (shares with everyone) │
│ 🔐 Private Key (keeps secret) │
│ │
│ Alice wants to send "Hi" to Bob: │
│ Message: "Hi" │
│ ↓ │
│ Encrypt with Bob's 🔓 Public Key │
│ ↓ │
│ Encrypted: "X7mK" ────────► │
│ ↓ │
│ Decrypt with Bob's │
│ 🔐 Private Key │
│ ↓ │
│ Message: "Hi" │
└────────────────────────────────────────────┘
Example in real life: RSA
Part 2: Hash Functions 🔨
A hash is like a fingerprint for data. It's a one-way function - you can't reverse it!
Properties of Hash Functions:
- Always the same output for the same input
- Can't be reversed (one-way only)
- Tiny change = completely different hash
# SHA256 Hash Example
SHA256("password") # => "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
SHA256("password") # => "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8" (same!)
SHA256("password1") # => "0b14d501a594442a01c6859541bcb3e8164d183d32937b851835442f69d5c94e" (totally different!)
Why is this useful?
1. Storing passwords:
❌ Bad: Store "mypassword123" in database
✅ Good: Store "5e884898da2804..." (the hash)
When user logs in:
1. User enters password
2. Hash it
3. Compare hashes
4. If match → correct password! (without ever storing the actual password)
2. Verifying data hasn't changed:
Download file → Hash it → Compare to expected hash
If hashes match → file is intact!
3. Creating "proofs" you know something without revealing it
Part 3: Understanding KLAP Step by Step
Now let's see how KLAP uses these concepts! KLAP stands for Key and Local Authentication Protocol.
The Challenge KLAP Solves
Problem: How do you prove you know the password without sending it over WiFi?
❌ Bad approach:
Client → "My password is: SecretPass123" → Device
Anyone listening can steal it!
✅ KLAP approach:
Use hashes and challenges to prove you know it WITHOUT sending it!
KLAP Authentication Flow
Let me break it down into digestible chunks:
Step 0: Preparation (Before handshake)
You need to create an auth_hash - this is like your "digital fingerprint" that proves you know the password.
# Your credentials
email = "you@example.com"
password = "SecretPass123"
# Create auth_hash (the proof you know the credentials)
username_hash = SHA1(email) # Hash the email
password_hash = SHA1(password) # Hash the password
auth_hash = SHA256(username_hash + password_hash) # Combine and hash again
# auth_hash = a unique 32-byte fingerprint
Why hash twice?
- First SHA1: Legacy compatibility with older Tapo systems
- Then SHA256: Modern security layer
- The device does the same calculation, so you both have the same
auth_hash
Step 1: Handshake Phase 1 (Device proves it knows your password)
Think of this as the device saying: "Prove you're the real owner!"
Client generates random bytes: local_seed (16 bytes)
↓
Client sends local_seed to Device
↓
Device receives local_seed
↓
Device generates: remote_seed (16 bytes)
Device calculates: server_hash = SHA256(local_seed + remote_seed + auth_hash)
↓
Device sends back: remote_seed + server_hash
↓
Client receives it
Client calculates: local_hash = SHA256(local_seed + remote_seed + auth_hash)
↓
Client checks: Does local_hash == server_hash?
✅ YES → Device knows the password! It's the real device!
❌ NO → Wrong device or wrong password!
Why this works:
- Only someone who knows the password can create the correct
auth_hash - The device proves it knows it by creating a hash that matches
- But we never sent the password over the network!
Visual analogy:
You and friend both know a secret word: "BANANA"
You say: "Add the word APPLE to our secret word and hash it. What do you get?"
Friend says: "I get hash: abc123xyz"
You calculate: SHA256("APPLE" + "BANANA") = "abc123xyz"
Match! → Friend knows the secret word!
But anyone listening only heard "APPLE" and "abc123xyz"
They don't know the secret word "BANANA"!
Step 2: Handshake Phase 2 (Client proves it knows the password)
Now it's YOUR turn to prove you know the password:
Client calculates: client_hash = SHA256(remote_seed + local_seed + auth_hash)
↑ Notice the order is reversed!
↓
Client sends: client_hash to Device
↓
Device calculates: expected_hash = SHA256(remote_seed + local_seed + auth_hash)
↓
Device checks: Does client_hash == expected_hash?
✅ YES → Client knows the password! Authenticated!
❌ NO → Reject the connection!
Why reverse the order?
- Creates a different hash from Phase 1
- Prevents "replay attacks" (someone recording and replaying the same message)
Step 3: Encrypted Communication (Talking securely)
Now that both sides trust each other, they create encryption keys:
# Both client and device have:
# - local_seed (16 bytes)
# - remote_seed (16 bytes)
# - auth_hash (32 bytes)
# Combine them
combined = local_seed + remote_seed + auth_hash # 64 bytes total
# Derive different keys for different purposes
encryption_key = SHA256("lsk" + combined)[0..15] # 16 bytes for AES
iv_base = SHA256("iv" + combined)[0..11] # 12 bytes for IV
signature_key = SHA256("ldk" + combined)[0..27] # 28 bytes for signatures
Why use SHA256 with prefixes?
- "lsk", "iv", "ldk" are just labels to create different keys from same source
- It's called "key derivation" - making multiple keys from one secret
Sending a Command (e.g., turn light on)
# 1. Your command
command = '{"method":"set_device_info","params":{"device_on":true}}'
# 2. Increment sequence number (prevents replay attacks)
sequence_number += 1
# 3. Create unique IV for this message
iv = iv_base + pack(sequence_number) # 12 + 4 = 16 bytes
# 4. Encrypt with AES-128-CBC
ciphertext = AES_encrypt(command, encryption_key, iv)
# 5. Create signature (proves message wasn't tampered with)
signature = SHA256(signature_key + sequence_number + ciphertext)
# 6. Send: signature + ciphertext
send_to_device(signature + ciphertext)
Breaking this down:
AES-128-CBC:
- AES = Advanced Encryption Standard (symmetric encryption)
- 128 = Key size in bits (16 bytes)
- CBC = Cipher Block Chaining (a mode that makes it more secure)
IV (Initialization Vector):
- A random starting point for encryption
- Same message encrypted twice with different IVs → different ciphertexts
- Prevents pattern analysis
Sequence number:
- Starts at a random number
- Increments with each message
- Prevents replay attacks (sending the same message twice)
Signature:
- Proves the message wasn't modified in transit
- Like a seal on an envelope
Visual Summary of Entire KLAP Flow
┌─────────────────────────────────────────────────────────┐
│ PREPARATION │
│ auth_hash = SHA256(SHA1(email) + SHA1(password)) │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ HANDSHAKE 1: Device proves identity │
│ │
│ Client: Generate local_seed → Send to device │
│ Device: Generate remote_seed │
│ Calculate SHA256(local+remote+auth_hash) │
│ Send remote_seed + hash back │
│ Client: Verify hash matches → Device is authentic! │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ HANDSHAKE 2: Client proves identity │
│ │
│ Client: Calculate SHA256(remote+local+auth_hash) │
│ Send hash to device │
│ Device: Verify hash matches → Client is authentic! │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ DERIVE ENCRYPTION KEYS │
│ │
│ combined = local_seed + remote_seed + auth_hash │
│ encryption_key = SHA256("lsk" + combined) │
│ iv_base = SHA256("iv" + combined) │
│ signature_key = SHA256("ldk" + combined) │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ ENCRYPTED COMMUNICATION │
│ │
│ For each command: │
│ 1. Increment sequence number │
│ 2. Create unique IV │
│ 3. Encrypt with AES-128-CBC │
│ 4. Add signature │
│ 5. Send encrypted message │
└─────────────────────────────────────────────────────────┘
Why is KLAP Secure?
-
Password never sent ✅
- Only hashes are exchanged
- Can't reverse a hash to get the password
-
Mutual authentication ✅
- Both sides prove they know the password
- Prevents fake devices
-
Unique session keys ✅
- Each session uses different random seeds
- Old sessions can't be reused
-
Encrypted commands ✅
- Commands are encrypted with AES
- Can't see what you're doing
-
Replay protection ✅
- Sequence numbers prevent replaying old messages
- Signatures prevent tampering
Key Takeaways
Encryption concepts:
- 🔐 Symmetric: Same key encrypts and decrypts (AES)
- 🔓🔐 Asymmetric: Public key encrypts, private key decrypts (RSA)
- 🔨 Hashing: One-way fingerprint (SHA256, SHA1)
KLAP uses:
- Hashing for password proofs (SHA256, SHA1)
- Symmetric encryption for commands (AES-128-CBC)
- Challenge-response for authentication (seeds + hashes)
- Signatures for integrity (SHA256)
- Sequence numbers for replay protection
The beauty of KLAP is it combines simple building blocks (hashing, AES) in a clever way to create secure authentication without ever sending your password!
Further Reading
- Reverse Engineering the Tapo KLAP Protocol - Technical deep dive
- Building a Tapo Client - Practical implementation guide
- Applied Cryptography - Bruce Schneier's classic book
- Cryptography I - Stanford course on Coursera