Blog
Go, Rust, Linux, cryptography and UK privacy law. One properly researched article a day.
Working notes from a software engineer who spends the day in Go, Rust and Linux and the evening reading legislation. Each post takes one specific question and answers it properly: why a worker pool deadlocks, what fsync really promises, how to enrol a TPM into LUKS without locking yourself out, what a technical capability notice can actually compel. Step-by-step how-tos sit alongside the deep dives, everything is checked against source code or primary legislation, and nothing is padded to hit a word count.
Subscribe with the Atom feed to get each post as it lands.
-
A Go worker pool that deadlocks under load, traced back to an unbuffered results channel, with the fix and why bigger buffers only postpone the problem.
-
A walkthrough of sshd_config's KexAlgorithms, Ciphers and MACs directives: what to strip out, why, and how to verify the change without locking yourself out.
-
sync.Once does not retry after f() panics: it quietly marks itself done, while OnceValue re-panics forever. Verified against the Go source.
-
Certificate Transparency Logs: What They Actually Prove About a TLS Certificate, and What They Don't
CT logs make TLS certificate issuance publicly auditable, but they do not validate domain control, check revocation or stop mis-issuance. The actual guarantee.
-
Create, enrol and maintain your own UEFI Secure Boot signing keys on Linux with sbctl, without turning the next reboot into a recovery exercise.
-
Rust has no async destructor, and it isn't an oversight. Why Drop::drop can't await, and the spawn/block_on/explicit-close patterns people use instead.
-
A single %v where you meant %w compiles cleanly and passes go vet, but it quietly severs the error chain that errors.Is depends on.
-
Configure BorgBackup with a server-enforced append-only repository, so a compromised client can add backups but never delete or rewrite them.
-
A Go service capped at 0.5 CPU in Kubernetes still spins up dozens of OS threads and gets throttled. Why GOMAXPROCS cannot see the limit, and how to fix it.
-
The DPA 2018 exemptions that let organisations lawfully redact a subject access request, and the patterns of overreach that turn a redaction into a breach.
-
A step-by-step guide to embedding a minimal Dropbear SSH server in initramfs so you can type a LUKS passphrase over the network on a headless server reboot.
-
Binding to port 80 as a non-root Go process without setuid tricks, using Linux capabilities, CAP_NET_BIND_SERVICE, setcap and systemd's AmbientCapabilities.
-
bcrypt silently ignores everything past the 72nd byte of a password. Why the limit exists, how it produces real collisions, and how to handle it properly in Go.
-
A practical guide to generating resident FIDO2 SSH keys with ssh-keygen, setting a PIN, and recovering the credential onto a new machine with ssh-keygen -K.
-
Comparing a computed HMAC with == looks correct and compiles fine, but it leaks timing information an attacker can use to forge a valid MAC byte by byte.
-
How SCM_RIGHTS lets one Unix process hand an open file descriptor to another, with a working Go example and a look at where systemd genuinely uses it.
-
Install and configure fail2ban on Linux to block SSH brute-force attempts automatically: jail.local, the systemd journal backend and the common pitfalls.
-
Binding to 127.0.0.1 feels private, but loopback TCP has no concept of "who's asking". Unix domain sockets do, and Go makes using them easy.
-
Rust drops locals in reverse order but struct fields in declaration order. That asymmetry is a documented footgun for locks, file handles and temp directories.
-
Build a minimal private CA in Go and configure two services to authenticate each other with mutual TLS, including the identity check most tutorials skip.
-
os.Exit ends a Go process immediately without unwinding the stack, so no deferred function runs. Why, and how to structure main() so it does not bite you.
-
Why lexical path checks cannot stop symlink escapes, and how Linux openat2 provides race-resistant directory confinement for Go services.
-
Build, test and persist a default-deny nftables firewall without breaking IPv6, flushing container rules or locking yourself out of SSH.
-
http.Get and http.DefaultClient have no timeout at all. Here's exactly which phases of a request are bounded, which aren't, and how to fix it properly.
-
AES-GCM fails catastrophically, not gracefully, if a nonce is ever reused. Here's what actually breaks, why, and how to stop it happening.
-
Join two LANs over WireGuard: key generation, subnet routing, firewall rules, MTU pitfalls and how to verify the tunnel is actually carrying traffic.
-
The Data (Use and Access) Act 2025 amends UK GDPR rather than replacing it: new lawful bases, looser automated decision rules and a new transfer test.
-
A look at why sha256(sha256(secret)) is not key derivation, what HKDF's extract-and-expand construction actually buys you, and how to use it correctly in Go.
-
Run Unbound as a validating, caching DNS-over-TLS resolver on Linux so every device on the network gets encrypted, DNSSEC-checked lookups with no per-app setup.
-
context cancellation in Go is cooperative, not preemptive: it closes a channel and nothing more. Here's where that quietly fails, and how to actually stop work.
-
io_uring's benchmarks are real, but most of its wins are in storage and syscall-bound workloads. Why bolting it onto a network service often buys nothing.
-
A practical guide to backing up a Linux machine with restic over SFTP: repository setup, password handling, systemd timers, retention, and verifying restores.
-
What a technical capability notice under the Investigatory Powers Act can require, why the Apple ADP dispute turned on one phrase, and why it is secret.
-
Why UK cookie banners with a working 'reject all' button still breach PECR, from consent-timing bugs to IAB TCF legitimate interest loopholes.
-
A Practical Guide to GPG Subkeys: Keeping Your Master Key Offline While Signing and Encrypting Daily
How to split a GPG identity into an offline certify-only master key and day-to-day sign, encrypt and auth subkeys, with backup and rotation steps.
-
TLS encrypts the contents of your connections, but packet sizes, timing, SNI and DNS still leak enough to fingerprint sites, videos and even keystrokes.
-
WAL mode lets SQLite readers and writers coexist, but writers still queue for one lock. Go's connection pool can turn that into 'database is locked' errors.
-
Replace sprawling authorized_keys files with a small self-hosted SSH certificate authority: user and host certificates, principals and revocation.
-
Section 87 retention notices under the Investigatory Powers Act 2016: what UK ISPs must log, the 12-month cap, entity versus events data, and why it is secret.
-
fsync() returning zero feels like a promise the bytes are safe. Page cache, errseq_t, directory entries and disk caches make that promise weaker than it looks.
-
Enrolling a TPM2 chip into a LUKS2 volume with systemd-cryptenroll: PCR selection, PIN protection and the kernel-update trap that locks people out.
-
Ofcom's section 121 powers under the Online Safety Act, what client-side CSAM scanning would involve, and why 'technically feasible' may be a category error.
-
A byte-level look at what a WebAuthn assertion signs: the origin, the challenge and the RP ID hash, and why that binding defeats classic phishing proxies.
-
How to set up LUKS2 disk encryption with the header on a separate USB key: the commands, the backup steps, and what it does and does not protect against.
-
tokio::select! drops the losing branch's future, and for some Tokio methods that means silently lost bytes and desynced protocols. How to spot and fix it.
-
How to choose Argon2id memory, time and parallelism parameters in Go that you can actually defend, with a working hash-and-verify implementation.