diff --git a/src/data/blogPosts.json b/src/data/blogPosts.json index d9e1e213..9741c888 100644 --- a/src/data/blogPosts.json +++ b/src/data/blogPosts.json @@ -1254,8 +1254,8 @@ }, { "slug": "zero-dependency-encryption-x25519-aes-gcm", - "title": "Zero-Dependency Agent Encryption: X25519 + AES-256-GCM in Pure Go", - "description": "How Pilot implements authenticated key exchange, tunnel encryption, nonce management, and replay protection using only Go's standard library.", + "title": "AES-256-GCM Encryption: Zero-Dependency Go Implementation Guide", + "description": "AES-256-GCM encryption explained with code: X25519 key exchange, GCM authenticated encryption, nonce handling, and wire format in zero-dependency Go.", "date": "Feb 12", "category": "Security", "tags": [ diff --git a/src/pages/blog/zero-dependency-encryption-x25519-aes-gcm.astro b/src/pages/blog/zero-dependency-encryption-x25519-aes-gcm.astro index d53d98e1..37c30676 100644 --- a/src/pages/blog/zero-dependency-encryption-x25519-aes-gcm.astro +++ b/src/pages/blog/zero-dependency-encryption-x25519-aes-gcm.astro @@ -1,7 +1,7 @@ --- import BlogLayout from '../../layouts/BlogLayout.astro'; -const bodyContent = `
Pilot Protocol implements its entire encryption stack -- X25519 key exchange plus AES-256-GCM authenticated encryption -- using nothing but Go's standard library. No OpenSSL, no libsodium, no third-party crypto module. This article shows exactly how that implementation works: the key exchange code, the wire format, nonce handling, and the security properties you get as a result.
+const bodyContent = `AES-256-GCM encryption is the authenticated-encryption mode that protects every message in transit on Pilot Protocol -- implemented, together with X25519 key exchange, using nothing but Go's standard library. No OpenSSL, no libsodium, no third-party crypto module. This article shows exactly how that AES-256-GCM encryption works end to end: the key exchange code, the wire format, nonce handling, and the security properties you get as a result.
Every encryption library is a dependency. Every dependency is an attack surface. When OpenSSL disclosed Heartbleed in 2014, it affected a large share of TLS servers on the internet -- not because of a flaw in the cryptographic algorithms, but because of a buffer over-read in a library that virtually every project imported without auditing. The xz Utils backdoor in 2024 demonstrated that even compression libraries can become supply chain weapons when a determined attacker gains commit access.
@@ -84,10 +84,14 @@ Agent A Agent BThe X25519 computation itself is sub-millisecond; the dominant setup cost is the one network round-trip for the handshake, which is bounded by the peers' RTT. The crypto cost is paid once per tunnel, not per packet.
-After key exchange, all tunnel frames are encrypted with AES-256-GCM (RFC 5288). GCM (Galois/Counter Mode) is an authenticated encryption mode that provides both confidentiality (the data is encrypted) and integrity (any modification is detected). It is the same cipher suite used by TLS 1.3 for HTTPS traffic worldwide.
+GCM is built from two operations. The first is AES in counter mode (CTR): the block cipher encrypts an incrementing counter, and the resulting keystream is XORed with the plaintext. That is how a block cipher encrypts arbitrary-length data. The second is GHASH, a universal hash function computed over the ciphertext that produces the authentication tag. Because the tag is a function of the ciphertext, an attacker who flips a single bit in transit must also forge a valid tag for the modified message. Without the key, that forgery is detected and the packet is rejected before any plaintext is released. This is what makes GCM "authenticated": confidentiality and integrity arrive in one pass, with one key, from one Seal call.
The construction also explains the two invariants an implementation must enforce. First, a nonce must never be reused under the same key -- the counter mode makes the keystream identical for identical nonces, which is why Pilot uses the two-part nonce construction described below. Second, the authentication tag must be verified before the plaintext is trusted. Go's Open function does both atomically: it returns an error on tag mismatch and never yields unauthenticated plaintext.
The implementation uses Go's crypto/aes package for the AES block cipher and crypto/cipher for the GCM mode. Here is the simplified flow: