Chapter 06: Hybrid Cryptography Migration Strategies
Migrating to PQC isn't an overnight switch. Because new algorithms might have unforeseen classical flaws (as happened with SIKE during the NIST competition), the industry best practice is Hybrid Cryptography.
1. The Concept (ELI5)β
Imagine you are holding up your pants. You usually use a strong leather belt (Classical Crypto like ECC). Itβs worked for decades. Now, scientists tell you that soon, a "quantum laser" will easily slice your belt, dropping your pants. They offer you a brand new, high-tech pair of suspenders (Post-Quantum Crypto). But the suspenders are so new, maybe there's a manufacturing defect we don't know about yet. What's the safest approach? Wear the belt AND the suspenders. If the laser cuts the belt, the suspenders hold your pants up. If the suspenders have a defect and snap, your trusty belt is still there. Hybrid Cryptography combines a classical key with a quantum key. An attacker has to break BOTH to read your data.
2. The Visualβ
3. The Codeβ
Implementing a hybrid KEM wrapper around existing libraries.
Goβ
Vulnerable Code β (Relying solely on one algorithm)
// Relying only on PQC or only on ECC is risky during the transition period.
Production-Ready Secure Code β (Hybrid KEM logic)
package main
import (
"crypto/ecdh"
"crypto/rand"
"fmt"
"golang.org/x/crypto/hkdf"
"crypto/sha256"
"github.com/cloudflare/circl/kem/kyber/kyber768"
"io"
)
// Conceptual Hybrid Combiner
func deriveHybridKey(eccSecret, pqcSecret []byte) []byte {
combined := append(eccSecret, pqcSecret...)
// HKDF combines both secrets into a single strong 32-byte key
hkdfReader := hkdf.New(sha256.New, combined, nil, nil)
finalKey := make([]byte, 32)
io.ReadFull(hkdfReader, finalKey)
return finalKey
}
func main() {
// 1. Classical ECC
curve := ecdh.P256()
eccPrivate, _ := curve.GenerateKey(rand.Reader)
// 2. Post-Quantum Kyber
pqcPublic, pqcPrivate, _ := kyber768.GenerateKeyPair(nil)
fmt.Println("Keys generated, ready for hybrid combination!")
_ = eccPrivate
_ = pqcPublic
_ = pqcPrivate
}
Pythonβ
Vulnerable Code β
# Standard key derivation with just one secret
pass
Production-Ready Secure Code β
import hashlib
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
def hybrid_kdf(ecc_shared_secret: bytes, pqc_shared_secret: bytes) -> bytes:
# Concatenate secrets
combined_secret = ecc_shared_secret + pqc_shared_secret
# Derive unified master key
hkdf = HKDF(
algorithm=hashlib.sha256(),
length=32,
salt=None,
info=b"hybrid-handshake"
)
return hkdf.derive(combined_secret)
TypeScript / Node.jsβ
Vulnerable Code β
// Single secret dependency
Production-Ready Secure Code β
import { createHmac } from 'crypto';
function combineSecrets(eccSecret: Buffer, pqcSecret: Buffer): Buffer {
const combined = Buffer.concat([eccSecret, pqcSecret]);
// Simple HKDF-Expand concept
const hmac = createHmac('sha256', Buffer.alloc(32));
hmac.update(combined);
return hmac.digest();
}
4. The Guardrailβ
Semgrep Rule: Enforce the use of HKDF when combining secrets, rather than just simple hashing or XORing, which can be vulnerable.
rules:
- id: require-hkdf-for-hybrid
message: "When combining multiple cryptographic secrets (e.g., in a hybrid PQC scheme), always use an industry-standard KDF like HKDF."
severity: WARNING
languages:
- go
pattern: |
append($X, $Y...)
...
sha256.Sum256(...)
fix: "Use golang.org/x/crypto/hkdf instead of raw sha256."