<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Haven Messenger</title>
    <description>The latest articles on DEV Community by Haven Messenger (@havenmessenger).</description>
    <link>https://dev.to/havenmessenger</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3891528%2F1736c7dd-a6a7-443a-863c-0abb7d56e358.png</url>
      <title>DEV Community: Haven Messenger</title>
      <link>https://dev.to/havenmessenger</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/havenmessenger"/>
    <language>en</language>
    <item>
      <title>SRP: The Password Protocol That Never Sends Your Password</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Thu, 04 Jun 2026 08:17:33 +0000</pubDate>
      <link>https://dev.to/havenmessenger/srp-the-password-protocol-that-never-sends-your-password-54nh</link>
      <guid>https://dev.to/havenmessenger/srp-the-password-protocol-that-never-sends-your-password-54nh</guid>
      <description>&lt;p&gt;The Secure Remote Password protocol, designed by Thomas Wu at Stanford in 1998 and standardized for TLS in RFC 2945 and RFC 5054, belongs to a family called &lt;strong&gt;augmented PAKE&lt;/strong&gt; — Password-Authenticated Key Exchange. The promise is unusual enough to sound like marketing, but it is a provable property: the server learns nothing it could use to impersonate you, an eavesdropper learns nothing useful, and an attacker who steals the server's entire database still cannot log in by replaying what they found. They would have to crack each password offline, one user at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem With "Just Hash It"
&lt;/h2&gt;

&lt;p&gt;The conventional advice — never store plaintext passwords, always store a salted &lt;a href="https://havenmessenger.com/blog/posts/password-hashing-compared/" rel="noopener noreferrer"&gt;slow hash&lt;/a&gt; — is correct and necessary, but it protects only the database at rest. The password still travels from client to server on every login. That means it exists, in plaintext, at several moments of risk:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In transit, protected only by TLS — which fails the instant a certificate is mis-issued, a CA is compromised, or a corporate middlebox terminates the connection.&lt;/li&gt;
&lt;li&gt;In server memory, where a logging bug, a crash dump, or a memory-scraping intrusion can capture it before hashing.&lt;/li&gt;
&lt;li&gt;At the application boundary, where reverse proxies and load balancers can inadvertently log request bodies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SRP's design goal was to remove the password from &lt;em&gt;all&lt;/em&gt; of these surfaces by never transmitting it at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Registration: Storing a Verifier, Not a Password
&lt;/h2&gt;

&lt;p&gt;When you create an account, your client picks a random salt &lt;em&gt;s&lt;/em&gt; and computes a private value &lt;em&gt;x&lt;/em&gt; from your salt, username, and password (via a hash). It then computes a &lt;strong&gt;verifier&lt;/strong&gt; &lt;em&gt;v = g^x mod N&lt;/em&gt;, where &lt;em&gt;g&lt;/em&gt; and &lt;em&gt;N&lt;/em&gt; are agreed group parameters (a generator and a large safe prime). The client sends the server only the salt and the verifier &lt;em&gt;v&lt;/em&gt;. It never sends &lt;em&gt;x&lt;/em&gt;, and never sends the password.&lt;/p&gt;

&lt;p&gt;The verifier is a one-way function of your password in the same spirit as a hash, but it is a public key, not a secret to be checked by comparison. The server stores &lt;em&gt;(salt, v)&lt;/em&gt;. Critically, knowing &lt;em&gt;v&lt;/em&gt; does not let the server — or a thief who steals &lt;em&gt;v&lt;/em&gt; — authenticate as you. They would still need to recover the password by brute force, exactly as with a stolen password hash.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The key distinction:&lt;/strong&gt; A stolen password &lt;em&gt;hash&lt;/em&gt; and a stolen SRP &lt;em&gt;verifier&lt;/em&gt; are equally useless for an immediate login — both force an offline cracking attack. But SRP additionally guarantees the password never reached the server in the first place, closing the in-transit and in-memory exposure that hashing alone leaves open.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Login: A Zero-Knowledge Handshake
&lt;/h2&gt;

&lt;p&gt;Authentication is a short challenge-response built on Diffie-Hellman. Both sides generate random ephemeral values and exchange public components: the client sends &lt;em&gt;A&lt;/em&gt;, the server sends &lt;em&gt;B&lt;/em&gt; (which is blended with the stored verifier). Each side then independently computes the &lt;em&gt;same&lt;/em&gt; shared session key — but only if the client's password matches the password baked into the verifier the server holds.&lt;/p&gt;

&lt;p&gt;Finally, each side sends a proof (an HMAC over the handshake values) demonstrating it derived the same key. If the client typed the wrong password, the two computed keys diverge and the proofs do not match — so the server rejects the login without ever having seen, or needed, the password itself. This is why SRP is often described as a zero-knowledge password proof: you prove knowledge of the secret without revealing it.&lt;/p&gt;

&lt;p&gt;As a bonus, that shared session key is a strong, mutually authenticated secret both sides now hold — usable to key an encrypted channel, which is what some end-to-end systems do with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What SRP Resists — and What It Doesn't
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Threat&lt;/th&gt;
&lt;th&gt;SRP outcome&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Passive eavesdropper on the wire&lt;/td&gt;
&lt;td&gt;Learns nothing usable; no offline-crackable value is sent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stolen server database&lt;/td&gt;
&lt;td&gt;No instant login; attacker must crack each verifier offline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phishing site / wrong server&lt;/td&gt;
&lt;td&gt;A fake server can't complete the handshake without the verifier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weak, guessable passwords&lt;/td&gt;
&lt;td&gt;Offline guessing still works once the verifier is stolen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Malware on the client device&lt;/td&gt;
&lt;td&gt;Captures the password as you type it — SRP can't help&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The honest summary: SRP raises the floor dramatically against network and server-side attacks, but it cannot rescue a weak password from offline cracking, and it cannot protect a compromised endpoint. It moves the attacker's cost, not their possibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where SRP Actually Lives
&lt;/h2&gt;

&lt;p&gt;SRP is not a museum piece. Apple has used SRP-6a in iCloud Key Vault and in the authentication for some of its services; the 1Password and ProtonMail authentication flows have used SRP to keep the master password off the server; and it appears in a long tail of VPNs, enterprise systems, and TLS-SRP deployments. The reason it never became the universal web login is mostly inertia and tooling: the modern web standardized on bearer tokens and OAuth flows, and browser-native PAKE never shipped.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;SRP's quiet insight is that "don't store plaintext" was always the wrong place to stop. The password shouldn't reach the server at all.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  SRP, OPAQUE, and the Modern PAKE Landscape
&lt;/h2&gt;

&lt;p&gt;SRP has a known wart: its security proof is less clean than newer designs, it bakes in specific group assumptions, and its augmented-but-not-quite handling of the salt leaks the salt to anyone who asks, enabling some pre-computation. The current state of the art is &lt;a href="https://havenmessenger.com/blog/posts/opaque-password-authentication/" rel="noopener noreferrer"&gt;OPAQUE&lt;/a&gt;, an aPAKE selected by the IETF's CFRG that fixes the salt-exposure issue and rests on stronger, modern security proofs. If you are designing a new system today, OPAQUE is generally the better default; SRP remains a perfectly defensible choice in systems that already deploy it well.&lt;/p&gt;

&lt;p&gt;Both belong to the same broader idea as &lt;a href="https://havenmessenger.com/blog/posts/privacy-preserving-authentication/" rel="noopener noreferrer"&gt;privacy-preserving authentication&lt;/a&gt;: the server should be able to check that you are you without accumulating secrets that turn it into a high-value breach target.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Pattern Matters for Encrypted Apps
&lt;/h2&gt;

&lt;p&gt;For any service that holds your encrypted data, the password problem is doubly important: the password often doubles as the root of your &lt;a href="https://havenmessenger.com/blog/posts/hkdf-key-derivation-explained/" rel="noopener noreferrer"&gt;key-derivation chain&lt;/a&gt;. If it ever reaches the server in a usable form, the server could, in principle, derive your keys. That is exactly the property a credible end-to-end system must avoid.&lt;/p&gt;

&lt;p&gt;At Haven, the design rule is that your passphrase never leaves your device — encryption keys are derived locally and only a derived credential is presented to the server, which is the same instinct that motivates SRP and OPAQUE. The protocol you pick matters less than the invariant it enforces: the server should never be in a position to know your password. SRP was one of the first practical ways to guarantee that, and understanding it makes every authentication design decision that follows clearer.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/srp-secure-remote-password-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Constant-Time Programming: Why Crypto Code Can't Branch on Secrets</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Wed, 03 Jun 2026 08:18:45 +0000</pubDate>
      <link>https://dev.to/havenmessenger/constant-time-programming-why-crypto-code-cant-branch-on-secrets-35d0</link>
      <guid>https://dev.to/havenmessenger/constant-time-programming-why-crypto-code-cant-branch-on-secrets-35d0</guid>
      <description>&lt;p&gt;Ordinary code is judged on whether it produces the right answer. Cryptographic code is held to a stranger standard: it must produce the right answer in exactly the same amount of time, no matter what the secret data is. Violate that rule and an attacker who can only measure how long your code runs can, given enough samples, recover the key it was protecting. This is why crypto libraries are full of code that looks needlessly convoluted — and why that convolution is the point.&lt;/p&gt;

&lt;p&gt;Imagine a function that checks whether a submitted password matches a stored one by comparing them character by character and returning &lt;code&gt;false&lt;/code&gt; the instant it finds a mismatch. It's correct. It's also leaking. A comparison that fails on the first character returns faster than one that fails on the tenth. An attacker measuring response times can learn how many leading characters they guessed correctly, turning an exponential brute-force problem into a linear one. The function gives the right answer and still betrays the secret — through &lt;em&gt;time&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This is a &lt;strong&gt;timing side channel&lt;/strong&gt;, and defending against it is the discipline of constant-time programming: writing code whose execution time, memory access pattern, and control flow do not depend on secret values. It's one specific, code-level corner of the broader family of &lt;a href="https://havenmessenger.com/blog/posts/side-channel-attacks-explained/" rel="noopener noreferrer"&gt;side-channel attacks&lt;/a&gt;, and it's the one application developers are most likely to get wrong themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  The threat model: an attacker with a stopwatch
&lt;/h2&gt;

&lt;p&gt;The unsettling part of timing attacks is how little the attacker needs. They don't need to read your memory, exploit a buffer overflow, or break the math behind the cipher. They only need to measure something observable — wall-clock response latency over a network, cache behavior on a shared machine, even power draw — and correlate it with secret-dependent work your program does.&lt;/p&gt;

&lt;p&gt;Individual measurements are noisy, especially over a network. But statistics defeat noise. In 2003, researchers David Brumley and Dan Boneh demonstrated a practical timing attack that extracted an RSA private key from an OpenSSL-based server over a network connection. The defense — and the reason modern RSA implementations use a technique called blinding — exists precisely because "it's only a few microseconds" is not a safe assumption when an attacker can collect millions of samples.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The core rule:&lt;/strong&gt; Execution time, branch decisions, and memory access addresses must be independent of secret data. If an attacker measuring any of these can distinguish one secret from another, the secret is leaking — no matter how strong the underlying cipher is.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The three things that leak
&lt;/h2&gt;

&lt;p&gt;Constant-time programming targets three distinct sources of secret-dependent timing variation, and a real implementation has to neutralize all of them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Secret-dependent branches
&lt;/h3&gt;

&lt;p&gt;Any &lt;code&gt;if&lt;/code&gt; statement whose condition depends on a secret can leak, because the two paths take different amounts of time and may prime the CPU's branch predictor differently. The fix is to compute both possibilities and select between them with arithmetic rather than a jump. Instead of "if the bit is set, add X," you compute a mask (all-ones or all-zeros depending on the bit) and AND it with X — the addition always happens, but contributes nothing when the bit is clear.&lt;/p&gt;

&lt;h3&gt;
  
  
  Secret-dependent memory access
&lt;/h3&gt;

&lt;p&gt;If your code uses a secret value as an index into a table — as naive AES implementations do with S-box lookups — then which memory address you touch depends on the secret. An attacker sharing the same CPU can observe, through the cache, which table entries were accessed, and work backward to the key. Constant-time code either avoids table lookups on secret indices entirely or accesses &lt;em&gt;every&lt;/em&gt; entry so the access pattern carries no information. This is why modern CPUs added dedicated AES instructions (AES-NI): they perform the round function in hardware without secret-dependent memory access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Secret-dependent loop bounds and early exit
&lt;/h3&gt;

&lt;p&gt;The password-comparison example above is this category. A loop that stops early when it finds a difference reveals where the difference is. The constant-time version always examines every byte, accumulating differences into a single value with OR, and only checks that accumulator at the very end. Standard libraries ship vetted versions of this — for example, &lt;code&gt;crypto_memcmp&lt;/code&gt;-style functions and language-level helpers like Python's &lt;code&gt;hmac.compare_digest&lt;/code&gt; — and you should use them rather than rolling your own equality check on any secret.&lt;/p&gt;

&lt;h2&gt;
  
  
  A concrete before-and-after
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Leaky pattern&lt;/th&gt;
&lt;th&gt;Constant-time replacement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Return &lt;code&gt;false&lt;/code&gt; on first byte mismatch&lt;/td&gt;
&lt;td&gt;OR all byte-differences together; compare the total to zero once at the end&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;if secret_bit: result = a else: result = b&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mask-based select: `result = (mask &amp;amp; a) \&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Table lookup {% raw %}&lt;code&gt;sbox[secret]&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Hardware AES instructions, or scan the whole table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loop runs &lt;code&gt;secret_length&lt;/code&gt; times&lt;/td&gt;
&lt;td&gt;Loop runs a fixed maximum number of times&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why the compiler is your adversary too
&lt;/h2&gt;

&lt;p&gt;Here's the genuinely hard part: even if you write constant-time source code, an optimizing compiler may quietly undo it. Compilers are designed to make code faster, and a "redundant" full-table scan or a branchless construct that looks like a missed optimization is exactly the kind of thing they rewrite. The C language has no portable notion of "constant time," so there is no standard way to tell the compiler "do not optimize this for timing's sake."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Writing constant-time code in a language that doesn't understand the concept means fighting your own toolchain — and the toolchain doesn't promise to lose.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is why serious cryptographic code is often written in assembly, generated by specialized tools, or formally verified (projects like HACL* and the assembly in libsodium and BoringSSL exist for this reason). It's also a quiet argument for &lt;a href="https://havenmessenger.com/blog/posts/memory-safe-languages-cve-crisis/" rel="noopener noreferrer"&gt;modern systems languages&lt;/a&gt;: ecosystems like Rust's have crates such as &lt;code&gt;subtle&lt;/code&gt; that provide constant-time primitives with explicit barriers to discourage the optimizer from collapsing them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for the software you trust
&lt;/h2&gt;

&lt;p&gt;The practical lesson for anyone evaluating a security product is not that you should audit assembly. It's that &lt;strong&gt;cryptography is an implementation discipline, not just a choice of algorithm&lt;/strong&gt;. "We use AES-256" tells you almost nothing about whether the AES is implemented without timing leaks. Two products can use the identical cipher and have wildly different real-world security depending on whether their developers respected constant-time rules and, crucially, whether they used well-audited libraries instead of writing their own primitives.&lt;/p&gt;

&lt;p&gt;That's the rule we follow at Haven, and that anyone building secure software should: don't hand-roll cryptographic primitives. Use vetted, constant-time libraries for the dangerous parts — comparison, key handling, the cipher core — and keep secret-dependent logic out of branches and table indices. The flashy part of cryptography is the math. The part that actually gets broken in the field is almost always the implementation. Constant-time programming is where a surprising amount of that battle is won or lost.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/constant-time-programming-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>SS7 Attacks: How Your Phone Number Betrays You</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Tue, 02 Jun 2026 08:17:30 +0000</pubDate>
      <link>https://dev.to/havenmessenger/ss7-attacks-how-your-phone-number-betrays-you-j8e</link>
      <guid>https://dev.to/havenmessenger/ss7-attacks-how-your-phone-number-betrays-you-j8e</guid>
      <description>&lt;p&gt;Somewhere underneath the apps and the LTE bars sits a signaling network from the 1970s that quietly coordinates every call, text, and roaming handoff on Earth. It was designed for a closed club of national telecoms who trusted each other completely. That club no longer exists — but the trust assumption was never removed.&lt;/p&gt;

&lt;p&gt;When you send a text or your phone latches onto a tower in a foreign country, two separate things happen. There's the &lt;em&gt;voice and data&lt;/em&gt; path — the actual content moving across the network — and there's the &lt;strong&gt;signaling&lt;/strong&gt; path, the out-of-band control messages that tell the network where you are, how to route a call to you, and which carrier should bill whom. That second path runs on a protocol family called Signaling System No. 7, or SS7.&lt;/p&gt;

&lt;p&gt;SS7 was standardized in the mid-1970s and built out globally through the 1980s. Its security model was simple because the world it served was simple: a small number of state-owned or heavily regulated monopoly carriers, physically interconnected, who had every commercial and legal reason to behave. There was no authentication between network elements because there didn't need to be. If a message arrived on the SS7 network claiming to come from a legitimate carrier, it was treated as if it did.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trust Model That Quietly Collapsed
&lt;/h2&gt;

&lt;p&gt;Deregulation changed the membership of the club without changing the locks. Over the following decades, the number of entities with some form of SS7 connectivity exploded — hundreds of mobile operators, virtual operators, SMS aggregators, roaming hubs, and interconnect resellers. Access to the network, once the exclusive privilege of national monopolies, became something you could effectively lease. Researchers have repeatedly demonstrated that obtaining a &lt;em&gt;global title&lt;/em&gt; (an SS7 network address) and sending traffic is within reach of a determined, modestly funded attacker.&lt;/p&gt;

&lt;p&gt;Once you can speak SS7 and the network trusts you by default, a handful of standard, legitimate messages become weapons. These aren't exploits of buggy code — they're the protocol working exactly as designed, asked the wrong question by the wrong party.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The core flaw:&lt;/strong&gt; SS7 has no meaningful authentication of the messages flowing between carriers. The network answers a request based on what the request claims to be, not on any cryptographic proof of who actually sent it. Everything below follows from that single missing check.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What an Attacker Can Actually Do
&lt;/h2&gt;

&lt;p&gt;The capabilities cluster into three families, all built from ordinary mobility-management messages:&lt;/p&gt;

&lt;h3&gt;
  
  
  Locating you
&lt;/h3&gt;

&lt;p&gt;Mobility messages such as &lt;code&gt;anyTimeInterrogation&lt;/code&gt; and &lt;code&gt;provideSubscriberInfo&lt;/code&gt; exist so a network can answer "which switch is this subscriber currently attached to?" — a legitimate need for routing. Abused, they let an outsider query a subscriber's approximate location, sometimes down to the serving cell tower, with nothing more than the target's phone number. No malware on the device, no consent, no trace visible to the victim.&lt;/p&gt;

&lt;h3&gt;
  
  
  Intercepting SMS and calls
&lt;/h3&gt;

&lt;p&gt;The more dangerous attack abuses &lt;code&gt;UpdateLocation&lt;/code&gt;. By telling the home network that the target has "roamed" onto a mobile switching center the attacker controls, the attacker convinces the network to route the victim's incoming calls and texts to attacker-controlled infrastructure. The victim's phone keeps showing full bars. Their text messages — including bank confirmations and one-time login codes — can be silently diverted, read, and even forwarded on so nothing looks missing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Denial and fraud
&lt;/h3&gt;

&lt;p&gt;The same primitives support cutting a subscriber off the network entirely, or manipulating billing and roaming records. Disruption is often the crudest and least interesting use; interception is where the money and the espionage live.&lt;/p&gt;

&lt;h2&gt;
  
  
  This Is Not Theoretical
&lt;/h2&gt;

&lt;p&gt;Two well-documented episodes anchor SS7 in reality rather than research labs. In 2016, security researcher Karsten Nohl demonstrated on the CBS program &lt;em&gt;60 Minutes&lt;/em&gt; that, given only the phone number of U.S. Representative Ted Lieu — who consented to the test — he could track the congressman's movements and record his calls from a base in Berlin, purely via SS7.&lt;/p&gt;

&lt;p&gt;In 2017, German newspaper &lt;em&gt;Süddeutsche Zeitung&lt;/em&gt; reported that criminals had exploited SS7 to intercept the SMS one-time codes banks send for transaction confirmation, draining money from victims' accounts after first stealing their online-banking passwords through conventional phishing. The phone network itself became the second half of a two-stage theft.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The uncomfortable lesson of SS7 is that a code texted to your phone is not delivered over a private channel. It is delivered over a global routing system that was never engineered to keep a determined third party from reading it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Doesn't 4G and 5G Fix This?
&lt;/h2&gt;

&lt;p&gt;Partly, and not as much as you'd hope. Modern LTE and 5G core networks replaced SS7 with a newer signaling protocol called &lt;strong&gt;Diameter&lt;/strong&gt;, and 5G adds further service-based architecture on top. But Diameter inherited a similar interconnect-trust philosophy and has its own documented weaknesses, and — crucially — networks must remain backward compatible. Calls and texts still fall back to older technology for roaming and interworking, and a chain is only as strong as the legacy link an attacker can force you down to. SS7 will be reachable in the global network for years yet.&lt;/p&gt;

&lt;p&gt;Carriers are not standing still. The GSMA publishes signaling-security guidance, and many operators now deploy SS7 and Diameter &lt;em&gt;firewalls&lt;/em&gt; that screen incoming signaling for messages that have no business arriving from a given peer. These help. They are also unevenly deployed across hundreds of networks worldwide, and you, the subscriber, have no way to audit whether your carrier — or the foreign carrier you're roaming on — has done the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Can Actually Control
&lt;/h2&gt;

&lt;p&gt;You can't patch SS7. What you can do is stop relying on the phone number as a security boundary. The throughline of every serious SS7 attack is that something valuable was trusted to the telephone network.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;If you currently use…&lt;/th&gt;
&lt;th&gt;Move toward…&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SMS one-time codes for 2FA&lt;/td&gt;
&lt;td&gt;App-based TOTP, or better, a hardware security key — neither touches the cellular network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phone calls / SMS for sensitive talk&lt;/td&gt;
&lt;td&gt;End-to-end encrypted messaging, where content is unreadable even if signaling is hijacked&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Your phone number as account identity&lt;/td&gt;
&lt;td&gt;Accounts and recovery paths that don't hinge on receiving a text&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;SMS-based two-factor authentication is still meaningfully better than no second factor at all — it raises the bar against casual attackers. But against an adversary with SS7 access, it is close to no protection. If you're choosing a second factor, the case for hardware keys over authenticator apps comes down to the same principle: keep the secret off the cellular network.&lt;/p&gt;

&lt;p&gt;SS7 interception also has a close cousin in SIM swapping, where the attacker takes over your number at the carrier rather than rerouting it in the network — and in IMSI catchers, which attack you over the air rather than through the signaling core. Different mechanisms, same conclusion: a phone number is an address, not an identity, and certainly not a secret.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Haven Fits
&lt;/h2&gt;

&lt;p&gt;Haven doesn't use your phone number as your identity, and it doesn't send security codes over SMS. Accounts are built on a passphrase-derived key that never leaves your device, and messages are end-to-end encrypted — so even if an adversary reroutes your texts through SS7, there is nothing of yours sitting in that stream to read.&lt;/p&gt;

&lt;p&gt;No app can fix a 1970s signaling network. What an app can do is stop depending on it. If your threat model includes well-resourced adversaries, the move that matters most is structural: stop letting the telephone network sit on the critical path of your security.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/ss7-attacks-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>networking</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Merkle Trees Explained: One Hash to Vouch for Everything</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Mon, 01 Jun 2026 08:20:07 +0000</pubDate>
      <link>https://dev.to/havenmessenger/merkle-trees-explained-one-hash-to-vouch-for-everything-c5i</link>
      <guid>https://dev.to/havenmessenger/merkle-trees-explained-one-hash-to-vouch-for-everything-c5i</guid>
      <description>&lt;p&gt;Suppose someone hands you a single 32-byte string and claims it represents a million records exactly as they should be. Later, you want to confirm one specific record is genuinely in that set — without re-downloading the other 999,999. A Merkle tree makes this possible with a few dozen bytes of proof. It's one of those rare ideas that's simple enough to sketch on a napkin and foundational enough to sit underneath Git, Bitcoin, and the system that keeps the web's certificate authorities honest.&lt;/p&gt;

&lt;p&gt;The structure is named for Ralph Merkle, who described it in work dating to the late 1970s. The idea has aged extraordinarily well because it solves a problem that keeps reappearing in distributed systems: &lt;strong&gt;how do you commit to a large collection of data with a single small value, and then prove things about individual items efficiently?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Start With the Hash Function
&lt;/h2&gt;

&lt;p&gt;A Merkle tree is built entirely out of cryptographic hash functions, so it's worth recalling what those give us. A hash function (SHA-256, for example) takes any input and produces a fixed-size fingerprint with three properties that matter here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic&lt;/strong&gt; — the same input always yields the same hash.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collision-resistant&lt;/strong&gt; — it's computationally infeasible to find two different inputs with the same hash.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avalanche effect&lt;/strong&gt; — flip one bit of input and roughly half the output bits change, unpredictably.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together these mean a hash is a tamper-evident summary: if the data changed, the fingerprint changes, and nobody can engineer a different document that matches the same fingerprint. A Merkle tree is what you get when you apply this recursively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Tree
&lt;/h2&gt;

&lt;p&gt;Picture your data split into chunks — transactions, files, log entries, whatever. The construction goes bottom-up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Leaves.&lt;/strong&gt; Hash each data chunk. These hashes are the leaf nodes at the bottom of the tree.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pair and hash.&lt;/strong&gt; Take the leaves two at a time, concatenate each pair, and hash the result. Each pair produces one parent node one level up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repeat.&lt;/strong&gt; Keep pairing and hashing each new level until only a single node remains.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That final, lone node is the &lt;strong&gt;Merkle root&lt;/strong&gt; (or root hash). Because every parent's value depends on its children, and theirs on their children, the root is a single value that depends on every single byte of every chunk. Change one transaction at the bottom and the change cascades all the way up: a different leaf hash, a different parent, a different root. The root is a fingerprint of the entire dataset.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Merkle root is a hash of hashes of hashes. It collapses an arbitrarily large dataset into one fixed-size value such that &lt;em&gt;any&lt;/em&gt; modification, anywhere, produces a different root.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Magic Trick: Merkle Proofs
&lt;/h2&gt;

&lt;p&gt;A plain hash of all the data would also detect tampering — so why the tree? Because the tree lets you prove membership of a &lt;em&gt;single&lt;/em&gt; item without revealing or processing the rest. This is the part worth slowing down for.&lt;/p&gt;

&lt;p&gt;Say you want to prove that chunk #5 belongs to a dataset whose root you already trust. You don't need the other chunks. You need only the sibling hashes along the path from leaf #5 up to the root — called the &lt;strong&gt;Merkle proof&lt;/strong&gt; or authentication path. To verify, you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hash chunk #5 yourself to get its leaf hash.&lt;/li&gt;
&lt;li&gt;Combine it with the provided sibling hash to compute its parent.&lt;/li&gt;
&lt;li&gt;Combine that with the next provided sibling to get the grandparent, and so on up the tree.&lt;/li&gt;
&lt;li&gt;Compare the root you computed against the trusted root. Match means chunk #5 is authentic and unmodified. Mismatch means something is wrong.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The beautiful part is the cost. For a tree of &lt;em&gt;n&lt;/em&gt; items, the path from any leaf to the root has only about &lt;strong&gt;log₂(n)&lt;/strong&gt; levels. A dataset of a million items needs a proof of roughly 20 sibling hashes — well under a kilobyte — to confirm any single member. The verification doesn't grow with the size of the data; it grows with its logarithm.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dataset size&lt;/th&gt;
&lt;th&gt;Approx. proof length (sibling hashes)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1,000 items&lt;/td&gt;
&lt;td&gt;~10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,000,000 items&lt;/td&gt;
&lt;td&gt;~20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,000,000,000 items&lt;/td&gt;
&lt;td&gt;~30&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That logarithmic scaling is why Merkle trees show up wherever a lightweight client needs to trust a small piece of an enormous structure it can't hold in full.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where You're Already Relying On Them
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Git
&lt;/h3&gt;

&lt;p&gt;Every Git commit is, in effect, a Merkle structure. File contents, directory trees, and commits are all identified by the hash of their contents, and each commit's hash incorporates its parent's. That's why a commit hash uniquely pins the entire history leading to it — and why you can't quietly rewrite an old commit without every later hash changing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bitcoin and other blockchains
&lt;/h3&gt;

&lt;p&gt;Each block summarizes all its transactions in a single Merkle root stored in the block header. This lets a lightweight wallet confirm a specific transaction is in a block by checking a short Merkle proof, rather than downloading the full chain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Certificate Transparency and Key Transparency
&lt;/h3&gt;

&lt;p&gt;Merkle trees are the backbone of accountability for the web's certificate system. Certificate Transparency logs use an append-only Merkle structure so that auditors can verify a certificate was logged and that the log was never secretly rewritten. The same machinery powers key transparency for messaging apps, letting users confirm the public key they're handed is the one everyone else sees too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Distributed storage and databases
&lt;/h3&gt;

&lt;p&gt;Content-addressed systems and distributed databases use Merkle trees (and a generalization, Merkle DAGs) to compare replicas efficiently. Two nodes can find exactly where their data diverged by comparing roots, then subtree hashes, narrowing down without shipping everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Merkle Tree Does and Doesn't Promise
&lt;/h2&gt;

&lt;p&gt;It's worth being precise. A Merkle tree proves &lt;strong&gt;integrity and membership&lt;/strong&gt;: that data hasn't changed since the root was published, and that a given item is part of the committed set. It says nothing on its own about &lt;em&gt;who&lt;/em&gt; produced the data or &lt;em&gt;when&lt;/em&gt; — that requires a signature over the root, or a trusted timestamp, layered on top. And an append-only log additionally needs &lt;strong&gt;consistency proofs&lt;/strong&gt; (showing the new tree is a strict superset of the old one) to guarantee history wasn't rewritten, not just that the current state is internally consistent.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Merkle tree turns "trust me, all this data is intact" into "here are 20 hashes — check for yourself." That shift, from assertion to verification, is the whole reason it underpins so much of modern cryptographic infrastructure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The recurring theme across all of this is the one that guides how we think about trust at Haven: the strongest systems don't ask you to take their word for it. They give you a small, cheap, mathematically grounded way to verify the claim yourself. A Merkle root is one of the most elegant expressions of that idea — a single fingerprint that lets anyone, anywhere, hold an entire dataset accountable.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/merkle-trees-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Quantum Key Distribution: Encryption Secured by Physics</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Sun, 31 May 2026 08:17:30 +0000</pubDate>
      <link>https://dev.to/havenmessenger/quantum-key-distribution-encryption-secured-by-physics-2o6e</link>
      <guid>https://dev.to/havenmessenger/quantum-key-distribution-encryption-secured-by-physics-2o6e</guid>
      <description>&lt;p&gt;Almost all the cryptography you use rests on math being hard: factoring big numbers, computing discrete logarithms. Quantum key distribution makes a different bet entirely. It secures a shared key with the laws of physics — and guarantees that any eavesdropper leaves fingerprints. That sounds like a silver bullet. It isn't, and understanding why is more interesting than the marketing.&lt;/p&gt;

&lt;p&gt;First, clear up a name collision that causes endless confusion. &lt;strong&gt;Quantum key distribution (QKD)&lt;/strong&gt; and &lt;strong&gt;post-quantum cryptography (PQC)&lt;/strong&gt; are not the same thing, and they are not even the same kind of thing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Post-quantum cryptography&lt;/strong&gt; is ordinary software — new mathematical algorithms (like ML-KEM) designed to resist attack by quantum &lt;em&gt;computers&lt;/em&gt;. It runs on the hardware you already own.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quantum key distribution&lt;/strong&gt; is hardware — it uses the physical behavior of individual photons to establish a key over a special optical link. It defends against eavesdropping using quantum &lt;em&gt;physics&lt;/em&gt;, not quantum computers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are responses to a quantum future, but PQC is what's actually being deployed across the internet today. QKD is a narrower, infrastructure-heavy technology. This article is about the second one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Physical Idea
&lt;/h2&gt;

&lt;p&gt;QKD rests on two facts from quantum mechanics. First, you cannot measure a quantum system without disturbing it. Second, the &lt;strong&gt;no-cloning theorem&lt;/strong&gt; says you cannot make a perfect copy of an unknown quantum state. Together these mean that an eavesdropper who intercepts photons in transit cannot do so invisibly — measuring them changes them, and that change is statistically detectable by the legitimate parties.&lt;/p&gt;

&lt;p&gt;This is the key reframing. Classical cryptography assumes an eavesdropper can copy every bit on the wire silently and attack it later at leisure (the "harvest now, decrypt later" threat). QKD aims to make silent interception physically impossible. If someone listens, the error rate climbs and the parties know to throw the key away before using it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What QKD provides:&lt;/strong&gt; QKD does not encrypt your data. It establishes a shared secret key whose secrecy can be verified — and that key is then used with ordinary symmetric encryption. The quantum part is purely about &lt;em&gt;agreeing on a key nobody else could have learned undetected&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  BB84, Step by Step
&lt;/h2&gt;

&lt;p&gt;The original and still most-taught protocol is BB84, proposed by Charles Bennett and Gilles Brassard in 1984. Here's the shape of it, using the convention that Alice sends and Bob receives.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Alice encodes random bits on photons&lt;/strong&gt;, choosing for each one a random "basis" — think of it as two different orientations of polarization, rectilinear (+) or diagonal (×). The bit value and the basis are both random.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bob measures each photon&lt;/strong&gt; in a basis he also picks at random. When his basis matches Alice's, he reads the correct bit. When it doesn't, he gets a random result.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;They compare bases over a public channel&lt;/strong&gt; — not the bit values, just which basis each used. They keep only the photons where the bases happened to match (about half) and discard the rest. This surviving string is the "sifted key."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;They check for eavesdropping&lt;/strong&gt; by publicly comparing a random sample of the sifted bits. If an eavesdropper measured photons in transit, she had to guess bases too, and her wrong guesses introduce errors. A quantum bit error rate above a known threshold means someone was listening — abort.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;They distill a final key&lt;/strong&gt; from the remaining bits using error correction and privacy amplification, which shrinks the key while squeezing out any partial information a weak eavesdropper might have gained.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The elegance is that security comes from the public basis-comparison step combined with physics: an eavesdropper cannot avoid disturbing the photons she measures, so she cannot learn the key without being caught. Other protocols (E91, which uses entanglement; and various decoy-state schemes) refine this, but BB84 captures the core intuition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why It Hasn't Taken Over the Internet
&lt;/h2&gt;

&lt;p&gt;If QKD offers physics-grade key secrecy, why aren't we all using it? Because the practical constraints are severe, and several national security agencies — including the UK's NCSC and the US NSA — have publicly recommended post-quantum cryptography over QKD for general use. Here's the honest list of limitations.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limitation&lt;/th&gt;
&lt;th&gt;What it means in practice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Distance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Photons get absorbed in fiber. Direct QKD links are limited to roughly a few hundred kilometers; going further needs trusted relay nodes or immature quantum repeaters.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Trusted relays&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Long-distance QKD networks chain together relay nodes that see the key in the clear. You're back to trusting infrastructure — the very thing QKD was supposed to avoid.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Special hardware&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;It needs dedicated fiber or line-of-sight optics, single-photon sources and detectors. It does not run over the ordinary internet.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;No authentication&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;QKD can't tell who is on the other end. It still needs classical authentication to stop a machine-in-the-middle — so it doesn't remove the need for conventional cryptography.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Implementation attacks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Real devices aren't ideal. Attacks like detector blinding have exploited hardware imperfections to defeat deployed QKD systems without violating any physics.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;The theory of QKD is unconditionally secure. The hardware that implements it is not. Most real-world QKD breaks have attacked the gap between the two.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Authentication Catch
&lt;/h2&gt;

&lt;p&gt;This point deserves its own emphasis because it undercuts the "physics replaces math" narrative. QKD guarantees that the photons weren't read undetected — but it cannot, by itself, tell Alice she's talking to Bob and not to an impostor sitting in the middle running QKD with each of them separately. To prevent that, the public discussion channel must be authenticated, and authentication relies on classical cryptography (a shared secret or signatures).&lt;/p&gt;

&lt;p&gt;So QKD does not eliminate the need for conventional cryptography — it sits alongside it. This is part of why agencies recommend hardening systems with post-quantum algorithms and good forward secrecy instead: those defend the whole internet in software, today, without new fiber.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where It's Real
&lt;/h2&gt;

&lt;p&gt;QKD is not vaporware. China's Micius satellite demonstrated entanglement-based key distribution between ground stations over 1,000 km apart in 2017, and a Beijing-to-Shanghai fiber backbone has carried QKD traffic. Several commercial vendors sell QKD systems, and some banks and government links use them. The technology works — within its niche of point-to-point links where one party controls both ends or trusts the relays, and where the cost of dedicated optical infrastructure is justified.&lt;/p&gt;

&lt;p&gt;That niche is genuine but small. For protecting communication at internet scale — which is what most people, and most privacy tools, actually need — the answer is strong end-to-end encryption with forward secrecy, migrating to post-quantum algorithms over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;Quantum key distribution is a beautiful idea: detect eavesdropping using the fact that observation disturbs quantum states. It delivers on that idea in theory and, with caveats, in practice. But it requires special hardware, is distance-limited, still needs classical authentication, and has been broken through implementation flaws. It complements conventional cryptography rather than replacing it.&lt;/p&gt;

&lt;p&gt;If you're worried about a quantum future, the practical move is not a fiber link to your contacts — it's using tools built on modern, well-audited cryptography that are adopting post-quantum algorithms. That's a software upgrade, not a physics project.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/quantum-key-distribution-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Zero-Knowledge Proofs: Proving You Know a Secret Without Revealing It</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Fri, 29 May 2026 08:16:50 +0000</pubDate>
      <link>https://dev.to/havenmessenger/zero-knowledge-proofs-proving-you-know-a-secret-without-revealing-it-305a</link>
      <guid>https://dev.to/havenmessenger/zero-knowledge-proofs-proving-you-know-a-secret-without-revealing-it-305a</guid>
      <description>&lt;p&gt;Suppose you need to prove you are over 18 without showing your birthdate, or that you know a password without sending it, or that a financial statement balances without exposing the numbers. Zero-knowledge proofs make all three possible: they let you convince a skeptic that something is true while leaking nothing beyond that single fact.&lt;/p&gt;

&lt;p&gt;The concept dates to a 1985 paper by Shafi Goldwasser, Silvio Micali, and Charles Rackoff — work so foundational that two of the authors later won the Turing Award. Their question sounds almost philosophical: how much knowledge must change hands to prove a statement is true? Their answer was startling: for many statements, the answer is &lt;em&gt;none beyond the truth of the statement itself&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cave That Explains Everything
&lt;/h2&gt;

&lt;p&gt;The standard intuition comes from a 1990 paper by Jean-Jacques Quisquater and colleagues, "How to Explain Zero-Knowledge Protocols to Your Children." Picture a ring-shaped cave with a magic door at the back that only opens with a secret word. The cave forks into two paths, A and B, that meet at the door.&lt;/p&gt;

&lt;p&gt;Peggy (the prover) wants to convince Victor (the verifier) she knows the word, without saying it. Peggy walks into the cave and picks a path at random. Victor, who stayed outside, then shouts which path he wants her to come out of. If Peggy truly knows the word, she can always comply — opening the door if she needs to switch sides. If she does not know it, she only had a 50% chance of guessing the right starting path.&lt;/p&gt;

&lt;p&gt;Run it once and a cheater gets lucky half the time. Run it twenty times and the odds of a fraud passing every round drop below one in a million. Crucially, Victor never learns the word — he just watches Peggy emerge from the side he named, over and over.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Properties
&lt;/h2&gt;

&lt;p&gt;Every zero-knowledge proof must satisfy three properties. They are worth stating precisely, because each one is doing real work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Completeness&lt;/strong&gt; — if the statement is true and both parties follow the protocol, the verifier is convinced.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Soundness&lt;/strong&gt; — if the statement is false, no cheating prover can convince the verifier except with negligible probability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-knowledge&lt;/strong&gt; — the verifier learns nothing except that the statement is true. Formally, anything the verifier sees could have been &lt;em&gt;simulated&lt;/em&gt; without access to the secret.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;The simulator trick: zero-knowledge is proven by showing a "simulator" can produce a transcript indistinguishable from a real proof — without ever knowing the secret. If a fake transcript is indistinguishable from a real one, the real one couldn't have leaked the secret. That argument is the conceptual heart of the whole field.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  From Interactive to Non-Interactive
&lt;/h2&gt;

&lt;p&gt;The cave protocol is &lt;em&gt;interactive&lt;/em&gt;: it needs back-and-forth challenges. That is impractical when you want to publish a single proof anyone can check later, like in a blockchain transaction.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Fiat–Shamir heuristic&lt;/strong&gt; (1986) removes the interaction. Instead of waiting for the verifier to send a random challenge, the prover generates the challenge themselves by hashing the protocol transcript so far. Because a good hash function is unpredictable, the prover cannot rig the challenge in their favor. The result is a &lt;em&gt;non-interactive&lt;/em&gt; proof — a self-contained string that any verifier can check independently.&lt;/p&gt;

&lt;p&gt;A closely related building block is the &lt;strong&gt;Schnorr protocol&lt;/strong&gt;, an elegant three-message proof that you know the discrete logarithm of a public value — i.e., that you hold the private key matching a public key. Apply Fiat–Shamir to a Schnorr proof and you get the Schnorr signature scheme, which underpins modern signatures including Bitcoin's Taproot upgrade.&lt;/p&gt;

&lt;h2&gt;
  
  
  SNARKs vs STARKs
&lt;/h2&gt;

&lt;p&gt;Modern zero-knowledge systems aim to prove arbitrary computations succinctly — that you ran a program correctly, with a proof far smaller than re-running the program. Two families dominate:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;zk-SNARKs&lt;/th&gt;
&lt;th&gt;zk-STARKs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Proof size&lt;/td&gt;
&lt;td&gt;Very small (constant)&lt;/td&gt;
&lt;td&gt;Larger (logarithmic)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Trusted setup&lt;/td&gt;
&lt;td&gt;Usually required&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Post-quantum&lt;/td&gt;
&lt;td&gt;Often not&lt;/td&gt;
&lt;td&gt;Yes (hash-based)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verification speed&lt;/td&gt;
&lt;td&gt;Very fast&lt;/td&gt;
&lt;td&gt;Fast&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;zk-SNARKs&lt;/strong&gt; (Succinct Non-interactive ARguments of Knowledge) produce tiny proofs that verify in milliseconds, but many variants need a &lt;em&gt;trusted setup&lt;/em&gt; — a one-time ceremony that generates public parameters. If the secret randomness from that ceremony ("toxic waste") is not destroyed, someone could forge proofs. Multi-party "powers of tau" ceremonies mitigate this by requiring all participants to collude.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;zk-STARKs&lt;/strong&gt; (Scalable Transparent ARguments of Knowledge) eliminate the trusted setup entirely and rely only on hash functions, which makes them plausibly quantum-resistant. The trade-off is larger proof sizes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where They're Actually Used
&lt;/h2&gt;

&lt;p&gt;Zero-knowledge proofs left the theory journals and entered production over the last decade:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Private cryptocurrency&lt;/strong&gt; — Zcash uses zk-SNARKs to validate that a shielded transaction is legitimate (inputs equal outputs, no double-spend) without revealing sender, receiver, or amount.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blockchain scaling&lt;/strong&gt; — "zk-rollups" bundle thousands of transactions and post a single proof that all of them were executed correctly, cutting costs dramatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt; — protocols like OPAQUE let a server verify your password without ever seeing it, a close cousin of the zero-knowledge idea.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selective disclosure&lt;/strong&gt; — emerging digital-ID systems aim to let you prove "over 18" or "resident of this country" from a credential without exposing the underlying document.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;The privacy promise is precise: not "trust me," and not "here is all my data so you can check." Instead — "here is mathematical proof of exactly the one fact you need, and nothing else."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Limits
&lt;/h2&gt;

&lt;p&gt;Zero-knowledge proofs are not magic. Proof generation can be computationally expensive, sometimes seconds or minutes for complex statements. The soundness guarantee is probabilistic — astronomically strong, but not literally absolute. SNARK trusted setups are a genuine risk that must be handled with care. And a proof only certifies what the statement says: a flawed statement, correctly proven, is still flawed.&lt;/p&gt;

&lt;p&gt;Still, few cryptographic ideas have moved from "elegant theory" to "deployed infrastructure" as decisively. As digital identity and privacy-preserving verification grow, the ability to prove a fact while revealing nothing else is becoming one of the most valuable tools in the box. For the complementary problem — computing on data you still cannot read — see our piece on homomorphic encryption.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/zero-knowledge-proofs-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>cryptography</category>
      <category>programming</category>
    </item>
    <item>
      <title>Nonce Reuse: The Catastrophic Crypto Mistake</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Thu, 28 May 2026 08:20:01 +0000</pubDate>
      <link>https://dev.to/havenmessenger/nonce-reuse-the-catastrophic-crypto-mistake-j6l</link>
      <guid>https://dev.to/havenmessenger/nonce-reuse-the-catastrophic-crypto-mistake-j6l</guid>
      <description>&lt;p&gt;&lt;em&gt;A nonce is a "number used once." The whole security of several widely deployed encryption and signature schemes rests on that single word — once. Break the rule, even by accident, even one time, and you can hand an attacker your message contents, your forgery key, or in the worst case your private signing key. This is the bug that has sunk WEP, a game console, and more than one TLS library.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most cryptographic failures are gradual: a cipher weakens, a key gets a little too short for comfort, an attack drops from impractical to merely expensive. Nonce reuse is not like that. It's a cliff. With many modern constructions, a single repeated nonce under the same key doesn't degrade security — it eliminates it, often completely, often instantly.&lt;/p&gt;

&lt;p&gt;Understanding why turns an abstract rule ("don't reuse nonces") into something you can reason about — and it explains a string of famous breaches that all share the same root cause.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Nonce Is For
&lt;/h2&gt;

&lt;p&gt;Encrypting the same plaintext twice with the same key should not produce the same ciphertext — otherwise an eavesdropper learns when you repeat yourself, which leaks more than you'd think. The fix is to inject a unique value into each encryption so identical inputs produce different outputs. That value is the nonce (sometimes called an IV, initialization vector, depending on the construction).&lt;/p&gt;

&lt;p&gt;The nonce doesn't need to be secret. It's typically sent in the clear alongside the ciphertext. Its only job is to be &lt;em&gt;different every time&lt;/em&gt; for a given key. That's the entire contract — and it's enough to make the difference between a secure cipher and a broken one.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Reuse Breaks a Stream Cipher
&lt;/h2&gt;

&lt;p&gt;AES-GCM and ChaCha20-Poly1305, the two AEAD ciphers behind most of the modern internet, both work as &lt;em&gt;stream ciphers&lt;/em&gt; under the hood: the key and nonce generate a long pseudorandom keystream, and the plaintext is XORed with that keystream to produce ciphertext.&lt;/p&gt;

&lt;p&gt;Now suppose you encrypt two different messages, P1 and P2, with the same key &lt;em&gt;and the same nonce&lt;/em&gt;. Both get XORed with the identical keystream K:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;C1 = P1 XOR K&lt;/li&gt;
&lt;li&gt;C2 = P2 XOR K&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An attacker who captures both ciphertexts computes C1 XOR C2. The keystream cancels out perfectly, leaving P1 XOR P2 — the XOR of your two plaintexts, with no key required. From there, known structure in either message (HTTP headers, file formats, language patterns) lets an attacker peel them apart. The encryption has effectively vanished.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;It gets worse than confidentiality&lt;/strong&gt;&lt;br&gt;
For AES-GCM specifically, nonce reuse also leaks the authentication subkey (the value GCM uses inside its GHASH function). Two messages under one nonce give an attacker enough to solve for it — and once they have it, they can &lt;strong&gt;forge&lt;/strong&gt; valid authentication tags for messages you never sent. So a single repeated nonce in GCM costs you both confidentiality &lt;em&gt;and&lt;/em&gt; integrity at the same time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Signature Variant: Even Nastier
&lt;/h2&gt;

&lt;p&gt;ECDSA, the elliptic-curve signature scheme, uses a per-signature random value usually written as &lt;em&gt;k&lt;/em&gt;. It's a nonce by another name, and its reuse is the most dangerous of all. If you sign two &lt;em&gt;different&lt;/em&gt; messages with the same &lt;em&gt;k&lt;/em&gt; under the same private key, the algebra collapses: an attacker who sees both signatures can solve a pair of linear equations and recover your &lt;strong&gt;private key&lt;/strong&gt; outright.&lt;/p&gt;

&lt;p&gt;This is not theoretical. In 2010, the group fail0verflow demonstrated exactly this against the Sony PlayStation 3: Sony's code signing used a fixed &lt;em&gt;k&lt;/em&gt; instead of a fresh random value for every signature, and that let researchers extract the private key used to sign software for the console. The same class of mistake has been found in Bitcoin wallets with weak random number generators, where reused or predictable &lt;em&gt;k&lt;/em&gt; values drained funds by exposing private keys.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The deterministic-nonce construction in RFC 6979 exists precisely because trusting a device to produce a good random &lt;em&gt;k&lt;/em&gt; every single time turned out to be a losing bet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A Short History of the Same Bug
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Incident&lt;/th&gt;
&lt;th&gt;What went wrong&lt;/th&gt;
&lt;th&gt;Consequence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WEP (Wi-Fi, 2001)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;24-bit IV with RC4 — far too small, IVs repeated within hours on a busy network&lt;/td&gt;
&lt;td&gt;Keystream recovery; WEP keys cracked in minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sony PS3 (2010)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fixed ECDSA &lt;em&gt;k&lt;/em&gt; across all code signatures&lt;/td&gt;
&lt;td&gt;Master private signing key extracted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Various TLS libs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GCM nonces generated with insufficient randomness or counters that wrapped&lt;/td&gt;
&lt;td&gt;Confidentiality and forgery risk on affected connections&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Decades apart, different algorithms, different industries — one root cause. That's what makes nonce reuse worth a dedicated mental model rather than treating each incident as a one-off.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Engineers Avoid It
&lt;/h2&gt;

&lt;p&gt;There are two disciplined approaches, and they suit different situations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Counters.&lt;/strong&gt; If a single key is used by a single sender, a simple incrementing counter guarantees uniqueness — no randomness needed, no collision risk, as long as the counter never wraps or resets. This is how protocols like TLS 1.3 and the Noise Framework manage per-message nonces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Large random nonces.&lt;/strong&gt; When a counter isn't practical (multiple writers, no shared state), you can pick random nonces — but the standard 96-bit GCM nonce is risky here, because random 96-bit values start colliding (the birthday bound) after roughly 2^32 messages. Extended-nonce variants like XChaCha20 use a 192-bit nonce, making random selection safe for all practical message volumes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Nonce-misuse-resistant modes
&lt;/h3&gt;

&lt;p&gt;Because the failure is so catastrophic, cryptographers built modes designed to &lt;em&gt;fail gracefully&lt;/em&gt;. AES-GCM-SIV (RFC 8452) and the broader SIV construction derive their effective nonce from the message content itself. If you accidentally reuse a nonce, the worst that happens is an attacker learns whether two ciphertexts encrypt identical plaintexts — the keys and forgery resistance stay intact. For systems where nonce uniqueness can't be guaranteed by design, these modes are a meaningful safety net.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;"Number used once" sounds like pedantry until you see how completely the math punishes a violation. The lesson for anyone building or evaluating crypto is twofold: never hand-roll nonce management when a vetted library or counter discipline exists, and treat "we generate nonces randomly" as a claim that deserves scrutiny about &lt;em&gt;how&lt;/em&gt; random and &lt;em&gt;how&lt;/em&gt; large.&lt;/p&gt;

&lt;p&gt;It's also a reminder of why we lean on audited, high-level cryptographic constructions rather than assembling primitives by hand. The dangerous part of cryptography is rarely the cipher — it's the bookkeeping around it. For a related class of subtle-but-deadly implementation bugs, see &lt;a href="https://havenmessenger.com/blog/posts/padding-oracle-attacks-explained/" rel="noopener noreferrer"&gt;padding oracle attacks&lt;/a&gt; and &lt;a href="https://havenmessenger.com/blog/posts/side-channel-attacks-explained/" rel="noopener noreferrer"&gt;side-channel attacks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/nonce-reuse-vulnerabilities/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Memory Safety and the C/C++ CVE Crisis</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Wed, 27 May 2026 08:20:19 +0000</pubDate>
      <link>https://dev.to/havenmessenger/memory-safety-and-the-cc-cve-crisis-18a8</link>
      <guid>https://dev.to/havenmessenger/memory-safety-and-the-cc-cve-crisis-18a8</guid>
      <description>&lt;p&gt;Microsoft analyzed a decade of their security bulletins and found roughly 70 percent of critical vulnerabilities were memory safety bugs. Google found roughly the same number in Android and Chromium. The NSA published an advisory recommending memory-safe languages by name. The conclusion is industry-wide and unusually unanimous: the problem isn't bad programmers, it's the languages.&lt;/p&gt;

&lt;p&gt;In 2019, Microsoft Security Response Center engineer Matt Miller presented an analysis of roughly a decade's worth of Microsoft's published vulnerabilities. The number that travelled around the industry was 70%: of Microsoft's serious, externally exploitable bugs, about seventy percent were caused by memory safety errors. Google's Project Zero, looking at Chromium, reported a remarkably similar number. Android's security team, looking at native code, found that memory safety vulnerabilities accounted for the majority of high-severity Android security bugs as well.&lt;/p&gt;

&lt;p&gt;In late 2022, the NSA published a Cybersecurity Information Sheet titled &lt;em&gt;"Software Memory Safety,"&lt;/em&gt; recommending that organizations move to memory-safe languages where possible and listing Rust, Go, Swift, Java, C#, and Python as examples. The CISA followed in 2023 with similar guidance. When an intelligence agency publishes a software engineering style guide, the industry has reached an unusual point of consensus.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "Memory Safety" Actually Means
&lt;/h2&gt;

&lt;p&gt;Memory safety is the property that a program cannot access memory it has no right to access. In a memory-safe language, the runtime, compiler, or both prevent a series of categorical bugs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Buffer overflows&lt;/strong&gt; — writing past the end of an allocated region&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use-after-free&lt;/strong&gt; — accessing memory after it's been returned to the allocator&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Double-free&lt;/strong&gt; — freeing the same allocation twice&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Null pointer dereferences&lt;/strong&gt; — using a pointer that doesn't point at a valid object&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uninitialized memory reads&lt;/strong&gt; — reading values that were never written&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type confusion&lt;/strong&gt; — interpreting a chunk of memory as the wrong type&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these is a different mechanism, but they share a common feature: they let an attacker influence values the program treats as trusted. A buffer overflow can overwrite a return address, redirecting control flow. A use-after-free can be massaged so that the freed memory is reallocated as something attacker-controlled, then accessed as the original type. Decades of attacker craft have turned these bugs into reliable exploitation primitives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why C and C++ Are Where Most of These Live
&lt;/h2&gt;

&lt;p&gt;C and C++ trust the programmer to be correct. The languages let you take a pointer, do arithmetic on it, and dereference the result. They let you free a pointer and use it again — they don't even warn you. They let you cast between pointer types with no runtime check. Each of these features is a power, and a hazard.&lt;/p&gt;

&lt;p&gt;Programmers can write correct C. Some do, for a while, on small programs. At scale, with large teams, deadline pressure, and decades of accumulated code, mistakes are statistically inevitable. The industry's experience is consistent across companies and projects: memory safety bugs slip past code review, slip past testing, and ship.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Not a competence question.&lt;/strong&gt; The teams writing the affected code at Microsoft, Google, Mozilla, Apple, and the kernel projects are world-class. The persistence of memory safety bugs at those organizations is the clearest possible evidence that the problem isn't programmer skill — it's that the language tolerates errors a more restrictive language would refuse to compile.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Modern Memory-Safe Languages
&lt;/h2&gt;

&lt;p&gt;Memory-safe languages take one of two general approaches: a runtime checker, or compile-time enforcement.&lt;/p&gt;

&lt;p&gt;Java, C#, Python, JavaScript, Go, Ruby, and most modern application languages use garbage collection plus runtime bounds checking. Memory is managed by the runtime; the programmer cannot create dangling pointers or overrun an array without an exception. The trade-off is performance overhead and a runtime dependency — fine for application code, problematic for the lowest layers of an operating system or a cryptographic primitive.&lt;/p&gt;

&lt;p&gt;Rust takes the second approach. Its compiler enforces a system of ownership and borrowing that statically prevents the categorical memory errors. There's no garbage collector and no runtime overhead — Rust compiles to native code with performance comparable to C. The price is that you have to convince the borrow checker your code is correct, which is harder than just writing it. Once it compiles, the program is provably free of the bug classes above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Rust Is Replacing C
&lt;/h2&gt;

&lt;p&gt;The places where memory safety matters most — operating system kernels, browser engines, networking code, cryptographic libraries — are exactly where C has dominated for fifty years. Rust is the first credible challenger because it doesn't impose a garbage collector or a runtime, which is what makes C indispensable in those contexts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Linux kernel&lt;/strong&gt; — Rust support was merged in 2022; drivers and modules can now be written in Rust within the kernel tree.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Android&lt;/strong&gt; — Google has been writing new native components in Rust since 2021. Their reported result: zero memory safety vulnerabilities in Rust code shipped to production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chromium&lt;/strong&gt; — Google has begun adopting Rust for new components, with the QR code generator and others now in Rust.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Firefox&lt;/strong&gt; — Mozilla developed Rust originally; large parts of Firefox's CSS engine (Servo, Stylo) are Rust.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows&lt;/strong&gt; — Microsoft has rewritten parts of Windows kernel components in Rust, including portions of the DirectWrite font shaping library that had been a recurring source of exploits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cURL&lt;/strong&gt; — The HTTP/HTTPS backend can now optionally be backed by Rust-written libraries.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Counter-Arguments, Honestly
&lt;/h2&gt;

&lt;p&gt;No language change comes for free. The serious objections to "just rewrite in Rust" deserve direct answers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rewriting C is expensive and risky
&lt;/h3&gt;

&lt;p&gt;Absolutely true. A large, mature C codebase represents enormous accumulated effort and bug-fixing. Rewriting it from scratch loses that history. The pragmatic answer most projects have adopted is incremental: keep the existing C, write &lt;em&gt;new&lt;/em&gt; components in Rust. Android's data on this is encouraging — most of their memory safety bugs were in new code, not the long-lived components. Writing new code in Rust closes the dominant pipeline of fresh vulnerabilities without touching legacy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rust has its own complexity
&lt;/h3&gt;

&lt;p&gt;Also true. The borrow checker is hard to learn. Async Rust is harder still. Programmers who internalized C's mental model often find Rust frustrating for the first few months. The honest assessment: there is a real learning cost, and the value depends on the domain. For application code that's never going to run on the bare metal, garbage-collected languages remain easier and probably enough. For systems code where C was the only choice, Rust's complexity is a worthwhile trade against C's exploitation history.&lt;/p&gt;

&lt;h3&gt;
  
  
  What about unsafe Rust?
&lt;/h3&gt;

&lt;p&gt;Rust has an &lt;code&gt;unsafe&lt;/code&gt; escape hatch — small blocks where the borrow checker stands down so you can do things like raw pointer arithmetic, FFI, or manual memory management. Critics point out that &lt;code&gt;unsafe&lt;/code&gt; Rust is just C-with-extra-steps. Defenders point out that &lt;code&gt;unsafe&lt;/code&gt; is typically a tiny fraction of a codebase, audited separately, and grep-able. The mainline of a Rust project is safe; the unsafe blocks are the part you focus security review on.&lt;/p&gt;

&lt;h2&gt;
  
  
  What About Hardware Mitigations?
&lt;/h2&gt;

&lt;p&gt;The industry didn't sit still waiting for language change. Modern hardware has accumulated layers of mitigation — stack canaries, ASLR, DEP, control flow integrity, pointer authentication on ARM64. These make exploitation harder but don't eliminate the underlying bugs. They're a defense-in-depth layer, not a replacement for safety. The result over time is a slow arms race: each new mitigation raises the bar for exploitation, attackers adapt, the bar rises again. Memory-safe languages cut the loop by eliminating the bug class.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Industry Trajectory
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Year&lt;/th&gt;
&lt;th&gt;Milestone&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2015&lt;/td&gt;
&lt;td&gt;Rust 1.0 released&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2019&lt;/td&gt;
&lt;td&gt;Microsoft publishes "70% of CVEs are memory safety"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2021&lt;/td&gt;
&lt;td&gt;Android starts writing new native code in Rust&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022&lt;/td&gt;
&lt;td&gt;Linux kernel accepts Rust support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022&lt;/td&gt;
&lt;td&gt;NSA publishes Software Memory Safety advisory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023&lt;/td&gt;
&lt;td&gt;CISA: vendor responsibility includes memory-safe language choice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2024&lt;/td&gt;
&lt;td&gt;White House ONCD report endorses memory-safe languages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2025+&lt;/td&gt;
&lt;td&gt;Major C/C++ projects adopting incremental Rust components&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why This Matters Beyond Programmers
&lt;/h2&gt;

&lt;p&gt;Memory safety bugs aren't a programmer-only concern. They are the most common mechanism for the privilege-escalation and remote-code-execution bugs that turn into real incidents. The browser tabs you trust, the messaging clients you depend on, the operating systems your devices run — all of them have shipped exploitable memory safety vulnerabilities in the last decade. Moving the foundation toward languages where those bugs are categorically impossible is not a stylistic choice. It is the largest single available improvement in software security, and the industry's biggest names have agreed on it.&lt;/p&gt;

&lt;p&gt;The cost is real. The transition is slow. But the trajectory is clear, and twenty years from now, the share of the software stack running in C and C++ will be smaller — by deliberate engineering, not nostalgia.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/memory-safe-languages-cve-crisis/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>rust</category>
      <category>memorysafety</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Self-Hosted Password Managers Compared: Vaultwarden, KeePassXC, Pass</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Tue, 26 May 2026 08:19:56 +0000</pubDate>
      <link>https://dev.to/havenmessenger/self-hosted-password-managers-compared-vaultwarden-keepassxc-pass-39d7</link>
      <guid>https://dev.to/havenmessenger/self-hosted-password-managers-compared-vaultwarden-keepassxc-pass-39d7</guid>
      <description>&lt;p&gt;Three serious self-hosted password managers have meaningfully different threat models, operational burdens, and ergonomic trade-offs. Picking the right one depends on whether you want a Bitwarden-compatible server, an offline-first encrypted file, or a Unix-philosophy command-line tree of GPG-encrypted files. Each is the right answer for different people.&lt;/p&gt;

&lt;p&gt;Hosted password managers have a real, documented track record of being targeted. The 2022 LastPass breach disclosed encrypted vault data of every customer, and the months of analysis that followed showed that vaults with weak master passwords were brute-forceable from the stolen ciphertext. The hosted model is convenient. It also means the encrypted blob containing all your secrets exists on someone else's infrastructure, where it can be stolen even if your password is perfect.&lt;/p&gt;

&lt;p&gt;Self-hosting eliminates this category of risk by relocating the blob to infrastructure you control. It introduces a different category — your infrastructure, your problem. Three serious self-hosted password managers are widely deployed: Vaultwarden, KeePassXC, and pass. They take fundamentally different architectural approaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vaultwarden
&lt;/h2&gt;

&lt;p&gt;Vaultwarden (formerly bitwarden_rs) is a Rust implementation of the Bitwarden server API. It's fully compatible with all official Bitwarden client apps (web, desktop, mobile, browser extension) but runs as a single small binary instead of Bitwarden's heavier official server stack. A typical Vaultwarden deployment is a Docker container with a SQLite database, fronted by a reverse proxy with HTTPS.&lt;/p&gt;

&lt;p&gt;The architecture is conventional client/server. Vaults are encrypted client-side with a key derived from your master password (PBKDF2 or Argon2id, depending on configuration). The server stores ciphertext only — it cannot read your passwords. Sync between devices works through the server, so any client with network access to your Vaultwarden instance can pull the current vault.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt; Excellent client ecosystem because of API compatibility (browser autofill on all major browsers, native iOS and Android apps with biometric unlock, full Bitwarden CLI compatibility, official passkey/FIDO2 support, organizations and sharing for families and small teams). The Bitwarden clients are mature, audited, and actively maintained. The Vaultwarden server is small enough to read end-to-end and runs comfortably on a Raspberry Pi.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weaknesses:&lt;/strong&gt; You're running an internet-exposed service (or at minimum a VPN-exposed service) that holds the encrypted blob of every credential you have. Compromise of the server still gives an attacker ciphertext, but ciphertext you control is no better than ciphertext Bitwarden controls if your master password is weak. You also inherit the operational burden — TLS certificates, backups, OS updates, container updates, intrusion monitoring.&lt;/p&gt;

&lt;h2&gt;
  
  
  KeePassXC
&lt;/h2&gt;

&lt;p&gt;KeePassXC is the actively-maintained desktop fork of the original Windows-only KeePass. It is fundamentally &lt;em&gt;not&lt;/em&gt; a server — it is a desktop application that reads and writes a single encrypted database file (typically a &lt;code&gt;.kdbx&lt;/code&gt; file). The database format is open, well-documented, and supported by dozens of third-party clients on every major platform.&lt;/p&gt;

&lt;p&gt;The trust model is markedly different from Vaultwarden's. KeePassXC has no concept of a server, and the database file is just a file. Sync is whatever you make it: Syncthing, Nextcloud, Dropbox, manual USB transfer. Mobile clients (KeePassDX on Android, Strongbox or KeePassium on iOS) typically open the same database file from a sync service or local copy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt; The smallest attack surface of any option here. There is no service to compromise — only a file format. The encrypted database can be stored on any storage medium without trust assumptions about the medium. KeePassXC supports YubiKey challenge-response as a second factor on the database itself, which is dramatically stronger than most second-factor implementations because the YubiKey must be present to decrypt. Browser integration via KeePassXC's official browser extension is functional but less polished than Bitwarden's.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weaknesses:&lt;/strong&gt; Sync conflicts are real. If you edit the database on two devices simultaneously without saving in between, KeePassXC will fail to merge cleanly and you'll lose one set of changes. Mobile UX is workable but not as smooth as a native cloud-backed client. Setup of multi-device sync requires picking and configuring a separate sync mechanism.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The YubiKey hardware factor:&lt;/strong&gt; KeePassXC's YubiKey challenge-response support is one of the strongest defensive features in any password manager. The Yubikey must be physically present and respond to a challenge to decrypt the database. Without the key, even a perfectly correct password produces only gibberish. This makes the encrypted database meaningfully safer to store in untrusted locations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Pass (passwordstore.org)
&lt;/h2&gt;

&lt;p&gt;Pass takes a Unix-philosophy approach: every credential is a small GPG-encrypted file, and the entire collection lives in a directory tree, optionally versioned with git. There is no database — just files. The reference implementation is a bash script of approximately 800 lines.&lt;/p&gt;

&lt;p&gt;To retrieve a password, you run &lt;code&gt;pass show github.com/myaccount&lt;/code&gt; and pass decrypts the corresponding file with GPG, prompting for your GPG passphrase (typically cached via gpg-agent for a configurable interval). To sync between devices, you push and pull the git repository. To share credentials with a teammate, you add their GPG key to the relevant subdirectory and re-encrypt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt; The data model is extraordinarily transparent. If pass disappeared tomorrow, you'd still have a tree of GPG-encrypted files that any GPG implementation can decrypt. The git history gives you free versioning, audit trail, and conflict resolution. Multi-recipient encryption (different GPG keys for different password subtrees) provides clean per-credential access control. Browser extensions exist (browserpass), but most users access pass via terminal or via rofi/dmenu launchers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weaknesses:&lt;/strong&gt; You need to be comfortable with GPG, which is notoriously rough. Mobile support exists (Password Store on Android, Pass on iOS) but is more cumbersome than the alternatives. The browser autofill experience is functional but not as smooth. There's no built-in concept of TOTP storage (though plugins exist). Backup-and-recovery requires understanding both your git remote and your GPG key infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Side-by-side comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Vaultwarden&lt;/th&gt;
&lt;th&gt;KeePassXC&lt;/th&gt;
&lt;th&gt;Pass&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Architecture&lt;/td&gt;
&lt;td&gt;Client/server&lt;/td&gt;
&lt;td&gt;File-based&lt;/td&gt;
&lt;td&gt;Git tree of GPG files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sync mechanism&lt;/td&gt;
&lt;td&gt;Built-in (HTTP)&lt;/td&gt;
&lt;td&gt;External (Syncthing, etc.)&lt;/td&gt;
&lt;td&gt;Built-in (git)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conflict handling&lt;/td&gt;
&lt;td&gt;Strong&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Git merge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser autofill quality&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Functional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mobile UX&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Rough&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operational burden&lt;/td&gt;
&lt;td&gt;Server + TLS + backups&lt;/td&gt;
&lt;td&gt;Sync + backups&lt;/td&gt;
&lt;td&gt;GPG + git + backups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit-friendliness&lt;/td&gt;
&lt;td&gt;Codebase auditable&lt;/td&gt;
&lt;td&gt;File format auditable&lt;/td&gt;
&lt;td&gt;Files = trivially auditable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YubiKey support&lt;/td&gt;
&lt;td&gt;Login second factor&lt;/td&gt;
&lt;td&gt;Challenge-response (strong)&lt;/td&gt;
&lt;td&gt;Via GPG smartcard&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How to pick
&lt;/h2&gt;

&lt;p&gt;The decision is mostly about how much operational complexity you'll tolerate vs. how much polish you want:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vaultwarden&lt;/strong&gt; is the right answer if you want a Bitwarden-quality experience without trusting Bitwarden the company. You will run a server. The clients are excellent and your family members will not complain. Pair with a strong master password and reverse-proxy authentication (basic auth + your normal HTTPS layer) to reduce the attack surface of the server itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;KeePassXC&lt;/strong&gt; is the right answer if you want maximum simplicity in the trust model and are comfortable picking and configuring your own sync mechanism. The YubiKey integration is a significant defensive feature for users handling sensitive accounts. Sync conflicts are the main operational annoyance — Syncthing handles this better than cloud-drive options.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pass&lt;/strong&gt; is the right answer if you're already a GPG user, comfortable on the command line, and want your password manager to be readable, scriptable, and trivially auditable. It is the worst option for users who want polished mobile and browser experiences. It is the best option for users who want to be able to inspect every byte of their password storage and understand the cryptography end to end.&lt;/p&gt;

&lt;p&gt;All three are meaningful improvements over closed-source hosted password managers if you have the operational capacity to run them well. The largest mistake is choosing one and then operating it poorly — a self-hosted password manager without backups, with a weak master password, or exposed to the public internet without proper hardening is worse than a competently-run hosted alternative. The infrastructure has to be at least as well-administered as the service you're replacing.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/self-hosted-password-managers/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>selfhosting</category>
      <category>opensource</category>
    </item>
    <item>
      <title>HPKE Explained: Hybrid Public Key Encryption (RFC 9180)</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Mon, 25 May 2026 08:18:36 +0000</pubDate>
      <link>https://dev.to/havenmessenger/hpke-explained-hybrid-public-key-encryption-rfc-9180-22f3</link>
      <guid>https://dev.to/havenmessenger/hpke-explained-hybrid-public-key-encryption-rfc-9180-22f3</guid>
      <description>&lt;p&gt;Most cryptographers used to assemble public-key encryption out of spare parts — pick an ECDH curve, pick an AEAD, write your own glue, hope nobody footguns it. HPKE is the standardized version of that glue. It's now load-bearing under MLS, TLS Encrypted Client Hello, and Oblivious DNS, and it's quietly the most important new crypto primitive of the last five years.&lt;/p&gt;

&lt;p&gt;HPKE — Hybrid Public Key Encryption — is published as &lt;a href="https://www.rfc-editor.org/rfc/rfc9180.html" rel="noopener noreferrer"&gt;RFC 9180&lt;/a&gt; by the IRTF Crypto Forum Research Group. The name is plain-spoken: it does public-key encryption, hybrid in the sense that it combines an asymmetric Key Encapsulation Mechanism (KEM) with a symmetric Authenticated Encryption with Associated Data (AEAD) construction. The combination isn't new. The standardization is.&lt;/p&gt;

&lt;p&gt;Before HPKE, every protocol that needed to encrypt to a public key (without a full TLS handshake) reinvented the same pattern: generate an ephemeral keypair, do a Diffie-Hellman exchange against the recipient's static key, derive a symmetric key, and encrypt the payload with AES-GCM or ChaCha20-Poly1305. The reinventions varied in subtle and broken ways. HPKE fixes the categories of bugs by drawing the lines once.&lt;/p&gt;

&lt;h2&gt;
  
  
  What HPKE Actually Does
&lt;/h2&gt;

&lt;p&gt;Conceptually, HPKE provides a sealed-envelope API. The sender has the recipient's public key. The sender calls &lt;strong&gt;Seal&lt;/strong&gt;, gets back an encrypted message plus an encapsulated key. The recipient — who holds the private key — calls &lt;strong&gt;Open&lt;/strong&gt; on the same inputs and recovers the plaintext.&lt;/p&gt;

&lt;p&gt;Under the hood, four building blocks compose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;KEM&lt;/strong&gt; — Key Encapsulation Mechanism. Produces a shared secret and an encapsulation. Concrete choice: DHKEM over X25519, P-256, P-384, P-521, or X448. Post-quantum hybrids are being layered in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;KDF&lt;/strong&gt; — Key Derivation Function. Turns the shared secret plus context strings into the symmetric keys actually used. HKDF-SHA256, HKDF-SHA384, HKDF-SHA512.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AEAD&lt;/strong&gt; — symmetric encryption with integrity. AES-128-GCM, AES-256-GCM, or ChaCha20-Poly1305.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mode&lt;/strong&gt; — base, PSK, auth, or auth-PSK. Determines whether sender authentication or a pre-shared key is mixed in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A given HPKE "ciphersuite" is just the choice of KEM, KDF, and AEAD — a tuple registered with IANA. Implementations advertise the suites they support, and protocols pick. This is the same pattern as TLS cipher suites but scoped much smaller.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why hybrid is the right word.&lt;/strong&gt; The KEM does an expensive elliptic-curve operation once, to establish a shared secret. The AEAD does cheap symmetric encryption on the payload. You pay public-key cost once, symmetric cost per byte. This is the same shape as TLS, just stripped down to its smallest useful unit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Four Modes
&lt;/h2&gt;

&lt;p&gt;HPKE's mode parameter changes who authenticates what. Most uses pick one and stick with it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Sender&lt;/th&gt;
&lt;th&gt;Properties&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Base&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Anonymous&lt;/td&gt;
&lt;td&gt;Recipient knows nothing about who sent it; only that it was sealed to their public key. Most common mode.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PSK&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Holds a shared symmetric key&lt;/td&gt;
&lt;td&gt;Mixes a pre-shared key into derivation. Recipient learns the sender belonged to the PSK group.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Auth&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Holds a static asymmetric key&lt;/td&gt;
&lt;td&gt;Sender authenticates via their own static keypair. Recipient verifies sender identity cryptographically.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Auth-PSK&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Both static key and PSK&lt;/td&gt;
&lt;td&gt;Belt and suspenders. Both authentication mechanisms layered.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Most real-world HPKE deployments use Base mode. The sender is genuinely anonymous because the protocol provides identity elsewhere — through TLS, through an MLS commit, through an OAuth token. HPKE doesn't have to do everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Single-Shot vs Streaming
&lt;/h2&gt;

&lt;p&gt;The minimal API is single-shot: seal one message, open one message, done. Both sides derive the same key from the shared secret and pass a fixed nonce.&lt;/p&gt;

&lt;p&gt;The streaming API exposes the AEAD context directly. The sender calls Seal repeatedly; the recipient calls Open repeatedly. A monotonically increasing sequence number generates a unique nonce per message. This is how MLS uses HPKE for welcome messages, and how ECH handles its inner ClientHello — many messages, one encapsulation.&lt;/p&gt;

&lt;p&gt;The streaming form is where most subtle implementation bugs live. If the sequence number ever wraps, or if it ever resets without re-keying, AES-GCM nonce reuse breaks confidentiality and integrity simultaneously. RFC 9180 mandates explicit limits and re-keying behavior. Audit any custom HPKE wrapper against those limits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where HPKE Shows Up in 2026
&lt;/h2&gt;

&lt;h3&gt;
  
  
  MLS — Messaging Layer Security
&lt;/h3&gt;

&lt;p&gt;MLS (RFC 9420) uses HPKE for its Welcome message — the bundle a new group member receives that lets them derive the current group key. MLS could have rolled its own asymmetric encryption, but using HPKE means MLS gets the underlying construction's security analysis for free.&lt;/p&gt;

&lt;h3&gt;
  
  
  TLS Encrypted ClientHello
&lt;/h3&gt;

&lt;p&gt;ECH hides the server name a client is connecting to from passive observers. The mechanism is HPKE-Sealing the inner ClientHello to a public key the client fetches via DNS HTTPS records. ECH is the load-bearing reason HPKE got fast-tracked through the IRTF.&lt;/p&gt;

&lt;h3&gt;
  
  
  Oblivious DoH
&lt;/h3&gt;

&lt;p&gt;Oblivious DNS-over-HTTPS — ODoH (RFC 9230) — uses HPKE to encrypt DNS queries inside an envelope only the resolver can open, then relays them through a proxy that knows the client IP but not the query. The proxy and the resolver each see only half the picture. HPKE is what makes the envelope sealing efficient enough to be deployable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Privacy Pass and Anonymous Tokens
&lt;/h3&gt;

&lt;p&gt;Privacy Pass extensions and related anonymous-token systems use HPKE for the issuance-to-redemption envelope, allowing a token to be issued by one party and redeemed by another without correlation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why It Replaces Ad-Hoc KEM+AEAD Glue
&lt;/h2&gt;

&lt;p&gt;Before HPKE, the canonical reference for "encrypt to a public key" was often "look at how libsodium does sealed boxes" or "look at how Signal does X3DH." Both are fine in isolation. Neither is interoperable across protocols. Worse, both bake in specific algorithm choices that can't easily be swapped without redesigning the wire format.&lt;/p&gt;

&lt;p&gt;HPKE separates the wire format (an encapsulation followed by ciphertext) from the algorithm choice (ciphersuite ID). Hybrid post-quantum ciphersuites are being added by registering new KEMs — the rest of the construction stays put. This matters as the industry transitions to post-quantum.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The KEM-DEM paradigm dates back to Cramer and Shoup in the late 1990s. HPKE is what you get when you take twenty-five years of attacks on its naive implementations and write down the version that survived.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Common Implementation Pitfalls
&lt;/h2&gt;

&lt;p&gt;The spec is careful, but implementations are where things break:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Re-using the encapsulated key.&lt;/strong&gt; Each Seal must generate a fresh ephemeral. If you cache and reuse, you destroy forward secrecy and create deterministic ciphertexts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wrong info string.&lt;/strong&gt; The "info" parameter binds the encryption to its context (protocol name, version, purpose). If sender and recipient pass different info, Open fails — but if a system loops a malleable string into info, you can get cross-protocol attacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AAD confusion.&lt;/strong&gt; Associated Authenticated Data covers integrity but not confidentiality. Putting secrets in AAD leaks them. Putting message-binding metadata in AAD is correct.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nonce sequencing in streaming.&lt;/strong&gt; Same warning as TLS 1.3: never reset the sequence counter without re-keying. The spec mandates rekeying limits per AEAD; respect them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Picking a Library
&lt;/h2&gt;

&lt;p&gt;Implementations vetted against the RFC and its test vectors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;hpke-rs&lt;/strong&gt; (Rust) — used in MLS implementations including OpenMLS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BoringSSL&lt;/strong&gt; and &lt;strong&gt;OpenSSL 3.2+&lt;/strong&gt; — ECH and HTTP-over-QUIC use these.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CIRCL&lt;/strong&gt; (Go, by Cloudflare) — production-tested through ECH rollout.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;hpke-js&lt;/strong&gt; — the JavaScript implementation reference. Suitable for browser ECH-adjacent work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rolling your own HPKE is the kind of choice that looks reasonable on a Monday and turns into a CVE by Friday. The construction is small enough to look tractable. The boundary conditions — nonce limits, info domain separation, ciphersuite negotiation, hybrid PQ wrapping — are where the time goes. Use the library.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;Shared standards beat ten clever local solutions, every time. If you're designing a protocol that needs to encrypt to a public key, the answer in 2026 is HPKE.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/hpke-hybrid-public-key-encryption-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>JWT Security Pitfalls: The Mistakes That Keep Breaking Tokens</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Sun, 24 May 2026 08:21:47 +0000</pubDate>
      <link>https://dev.to/havenmessenger/jwt-security-pitfalls-the-mistakes-that-keep-breaking-tokens-9dj</link>
      <guid>https://dev.to/havenmessenger/jwt-security-pitfalls-the-mistakes-that-keep-breaking-tokens-9dj</guid>
      <description>&lt;p&gt;JSON Web Tokens look deceptively simple. Three base64-encoded segments, a signature, and you're authenticating users across a distributed system. The problem is that the format hands authors enough rope to hang an entire application — and the same handful of mistakes keep showing up in CVE feeds year after year.&lt;/p&gt;

&lt;p&gt;A JWT is three dot-separated chunks: a header describing the signature algorithm, a payload of claims (subject, issuer, expiry, custom data), and a signature over the first two. RFC 7519 defined the structure in 2015 and it became the default token format for OAuth, OpenID Connect, and roughly every "stateless authentication" tutorial since.&lt;/p&gt;

&lt;p&gt;Most of the trouble lives not in the spec itself but in the libraries that implement it — and in the validation code developers write around them. The fundamental issue is that JWTs are flexible: they support multiple algorithms, optional claims, and several legitimate use cases. Each axis of flexibility is a place where a mistake can let a forged token through.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "alg: none" Trap
&lt;/h2&gt;

&lt;p&gt;The JWT spec includes an algorithm called &lt;code&gt;none&lt;/code&gt;. It's intended for tokens that don't need cryptographic integrity — a stretch of use case that has never made sense in practice. When the algorithm is &lt;code&gt;none&lt;/code&gt;, the signature segment is empty. A token with &lt;code&gt;{"alg":"none"}&lt;/code&gt; in its header has no signature to verify, and a naive library will accept it.&lt;/p&gt;

&lt;p&gt;The attack writes itself. Take a legitimate token, modify the payload to escalate privileges, change the header's &lt;code&gt;alg&lt;/code&gt; to &lt;code&gt;none&lt;/code&gt;, and submit it. If the server's verifier doesn't explicitly reject &lt;code&gt;none&lt;/code&gt;, the token validates.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Mitigation:&lt;/strong&gt; Every modern JWT library lets you pin the accepted algorithms. Always pass an explicit list — &lt;code&gt;["HS256"]&lt;/code&gt; or &lt;code&gt;["RS256"]&lt;/code&gt; — never trust the library default. If your code path includes &lt;code&gt;none&lt;/code&gt; as accepted, that is the bug.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Several widely-used libraries shipped with &lt;code&gt;none&lt;/code&gt; accepted by default until around 2018. The class of bug is fixed in current versions, but old deployments persist, and the lesson generalizes: trusting the token's own description of how to verify it is the original sin of JWT validation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Algorithm Confusion Attack
&lt;/h2&gt;

&lt;p&gt;A subtler version of the same problem. JWTs support both symmetric algorithms (HMAC variants — HS256, HS384, HS512) and asymmetric ones (RSA — RS256, etc., and ECDSA — ES256, etc.). A symmetric algorithm uses a single shared secret; an asymmetric one uses a private key to sign and a public key to verify.&lt;/p&gt;

&lt;p&gt;If a server expects RS256 — verifying tokens with an RSA public key — but a library trusts the &lt;code&gt;alg&lt;/code&gt; field, an attacker can craft a token with &lt;code&gt;"alg":"HS256"&lt;/code&gt; and sign it with the server's &lt;strong&gt;public&lt;/strong&gt; key as the HMAC secret. The public key is, by definition, public. The library, asked to "verify HS256 with the configured key," dutifully validates the HMAC. The token is accepted.&lt;/p&gt;

&lt;p&gt;This is the algorithm confusion attack, and it's the canonical reason you must pin algorithms at validation time. The library cannot decide what algorithm is acceptable; the application must.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skipping Signature Verification Entirely
&lt;/h2&gt;

&lt;p&gt;Most JWT libraries have a &lt;code&gt;decode()&lt;/code&gt; function that parses the token without verifying the signature, and a separate &lt;code&gt;verify()&lt;/code&gt; function that does both. The &lt;code&gt;decode()&lt;/code&gt; function exists for legitimate reasons — inspecting a token for debugging, reading the &lt;code&gt;kid&lt;/code&gt; header to look up the correct key — but it has a habit of finding its way into production code paths where verification was the actual intent.&lt;/p&gt;

&lt;p&gt;The symptom is code that "works" — claims parse correctly, the user ID is present, requests succeed — while never actually validating the signature. A forged token with arbitrary claims gets accepted indistinguishably from a legitimate one. The bug is silent and code review catches it only if reviewers know the API surface.&lt;/p&gt;

&lt;p&gt;One memorable production failure mode: a refactor moved authentication to a middleware layer; the new layer called &lt;code&gt;decode()&lt;/code&gt; instead of &lt;code&gt;verify()&lt;/code&gt;; tests passed because the test fixtures had valid signatures; deployment passed because the integration tests didn't include any forged tokens. The bug was found by a security audit eight months later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Missing Claim Validation
&lt;/h2&gt;

&lt;p&gt;A valid signature proves the token wasn't forged. It doesn't prove the token is currently valid, was issued by the right party, or is being used by the right service. Those are claim-level checks, and they're the developer's responsibility.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Claim&lt;/th&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Failure mode if skipped&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;&lt;code&gt;exp&lt;/code&gt;&lt;/strong&gt; (expiry)&lt;/td&gt;
&lt;td&gt;Reject if past current time, with clock-skew tolerance&lt;/td&gt;
&lt;td&gt;Stolen tokens never expire&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;&lt;code&gt;nbf&lt;/code&gt;&lt;/strong&gt; (not-before)&lt;/td&gt;
&lt;td&gt;Reject if before current time&lt;/td&gt;
&lt;td&gt;Pre-dated tokens accepted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;&lt;code&gt;iss&lt;/code&gt;&lt;/strong&gt; (issuer)&lt;/td&gt;
&lt;td&gt;Reject if not your trusted issuer&lt;/td&gt;
&lt;td&gt;Tokens from another tenant or service accepted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;&lt;code&gt;aud&lt;/code&gt;&lt;/strong&gt; (audience)&lt;/td&gt;
&lt;td&gt;Reject if not your service's identifier&lt;/td&gt;
&lt;td&gt;Tokens intended for a different API accepted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;&lt;code&gt;iat&lt;/code&gt;&lt;/strong&gt; (issued-at)&lt;/td&gt;
&lt;td&gt;Sanity-check it's not far in the future&lt;/td&gt;
&lt;td&gt;Replay window confusion&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Audience validation in particular is widely skipped. If your authorization server issues tokens for three services and only one of them checks the &lt;code&gt;aud&lt;/code&gt; claim, a token issued for one service can be replayed against the others. This was the root cause of several high-profile breaches in OAuth-based architectures.&lt;/p&gt;

&lt;h2&gt;
  
  
  JWKS Key Confusion
&lt;/h2&gt;

&lt;p&gt;Asymmetric JWTs are usually verified by fetching the issuer's public keys from a JWKS (JSON Web Key Set) endpoint, often discovered through OpenID Connect metadata. The token carries a &lt;code&gt;kid&lt;/code&gt; (key ID) in its header indicating which key to use.&lt;/p&gt;

&lt;p&gt;Two recurring bugs here. First, libraries that fetch the JWKS over plain HTTP — a network attacker can swap in their own keys. Always use HTTPS, and ideally cache the keys with a short TTL. Second, applications that trust an arbitrary &lt;code&gt;jku&lt;/code&gt; (JWK Set URL) header from the token itself — an attacker provides a URL pointing to a key set they control, and the library cheerfully fetches and uses it. The &lt;code&gt;jku&lt;/code&gt; header was never safe to trust without an allowlist, but the spec doesn't make this obvious.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "Stateless" Lie
&lt;/h2&gt;

&lt;p&gt;Half the appeal of JWTs in marketing material is statelessness: the server doesn't need a session database, just a signing key. This works fine until you need to log a user out.&lt;/p&gt;

&lt;p&gt;A signed JWT is valid until its &lt;code&gt;exp&lt;/code&gt; claim says otherwise. If a user's account is compromised, or they hit "log out," the token still cryptographically validates. The options are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accept the window — tokens live for at most a few minutes, refresh tokens are revocable&lt;/li&gt;
&lt;li&gt;Maintain a server-side denylist of revoked token IDs (and at that point you have a session database)&lt;/li&gt;
&lt;li&gt;Issue very short access tokens and rely on the refresh token endpoint to enforce policy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first and third approaches are the modern norm. Long-lived JWTs — say, 24-hour access tokens — without a revocation mechanism are a security liability disguised as a feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Use Instead, When You Can
&lt;/h2&gt;

&lt;p&gt;For server-to-server authentication, mTLS often removes the entire bearer-token attack surface. For user-facing authentication, opaque session tokens stored in a database — old-school session cookies — have the property that revocation is trivial and the token itself reveals nothing.&lt;/p&gt;

&lt;p&gt;JWTs make sense when you genuinely need self-contained claims that downstream services must verify without consulting the issuer. OpenID Connect's ID tokens fit this; cross-service authorization in a microservice mesh fits this. For "logged in user has a session," they're often overkill — and the operational complexity costs more than it saves.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Validation Checklist Worth Printing
&lt;/h2&gt;

&lt;p&gt;If you must use JWTs, the non-negotiable checks before trusting any claim:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pin the algorithm.&lt;/strong&gt; Pass an explicit allowed list to your verifier. Never accept &lt;code&gt;none&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify the signature.&lt;/strong&gt; Use &lt;code&gt;verify()&lt;/code&gt;, not &lt;code&gt;decode()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check &lt;code&gt;exp&lt;/code&gt; and &lt;code&gt;nbf&lt;/code&gt;&lt;/strong&gt; with a reasonable clock-skew tolerance (a minute is generous).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check &lt;code&gt;iss&lt;/code&gt; and &lt;code&gt;aud&lt;/code&gt;&lt;/strong&gt; against an allowlist your application defines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fetch keys over HTTPS&lt;/strong&gt; from a hard-coded JWKS URL. Never honor &lt;code&gt;jku&lt;/code&gt; or &lt;code&gt;x5u&lt;/code&gt; headers from the token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a current library version.&lt;/strong&gt; Many older versions have CVEs for the bugs above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Have a revocation story.&lt;/strong&gt; Short-lived access tokens or a denylist. Pick one.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most JWT vulnerabilities are not algorithm breaks — they're implementation oversights at the validation layer. The cryptography is fine; the contract around it is the dangerous part. As with most security primitives, the failure mode is rarely the math.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/jwt-security-pitfalls/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>BGP Hijacking Explained: How Internet Traffic Gets Stolen</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Fri, 22 May 2026 08:19:54 +0000</pubDate>
      <link>https://dev.to/havenmessenger/bgp-hijacking-explained-how-internet-traffic-gets-stolen-58kj</link>
      <guid>https://dev.to/havenmessenger/bgp-hijacking-explained-how-internet-traffic-gets-stolen-58kj</guid>
      <description>&lt;p&gt;When you load a website, your packets do not travel along a fixed wire. They are handed from network to network, each one consulting a routing table that says "to reach this block of addresses, forward toward that neighbor." Those tables are built from announcements. Networks tell their neighbors which address ranges they can deliver to, the neighbors propagate the claim, and within minutes the whole internet agrees on a path.&lt;/p&gt;

&lt;p&gt;The protocol that carries those announcements is BGP, and it was designed in an era when every network operator personally knew the others. It assumes good faith. A network can announce a route for address space it does not own, and by default its neighbors will believe it. When that false announcement is more attractive than the legitimate one, traffic for a victim's addresses starts flowing to the attacker instead. That is a BGP hijack.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a Hijack Actually Works
&lt;/h2&gt;

&lt;p&gt;Every network on the internet has an Autonomous System Number — an AS number — and the address blocks it is authorized to originate. A hijack is an AS announcing a block it has no authority over. There are two flavors, and the difference matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  The more-specific route hijack
&lt;/h3&gt;

&lt;p&gt;Internet routing always prefers the most specific match. If the legitimate owner announces a large block and an attacker announces a smaller, more specific sub-block of it, every network on earth will prefer the attacker's route for that sub-block — not because it is shorter, but because it is more precise. This is why even a network "far" from the victim can pull traffic globally with a single sufficiently specific announcement.&lt;/p&gt;

&lt;h3&gt;
  
  
  The equal-specificity hijack
&lt;/h3&gt;

&lt;p&gt;If the attacker announces the same block size as the victim, there is no precision tiebreaker. The hijack only succeeds for the slice of the internet that happens to be topologically closer to the attacker. It is partial — but partial is often enough.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Hijack vs. blackhole&lt;/strong&gt; — An attacker who simply wants to take a service offline can announce the route and drop the traffic — a blackhole. An attacker who wants to &lt;em&gt;spy&lt;/em&gt; does something harder: announce the route, inspect or modify the traffic, then forward it on to the real destination so the victim never notices the detour. That second pattern is an interception hijack.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What Hijacks Have Actually Been Used For
&lt;/h2&gt;

&lt;p&gt;BGP incidents fall into a few recurring categories, and not all of them are malicious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fat-finger leaks.&lt;/strong&gt; A misconfigured router accidentally announces routes it should not. A well-known 2008 incident took a large video platform globally unreachable for hours after a telecom's attempt to block it domestically leaked worldwide.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traffic interception for surveillance.&lt;/strong&gt; Researchers have documented hijacks that route traffic through a distant country and back, holding it just long enough to inspect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cryptocurrency theft.&lt;/strong&gt; One of the most cited criminal cases involved hijacking the address space of a public DNS service in 2018, redirecting users of a cryptocurrency wallet site to a malicious clone and draining funds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spam and abuse.&lt;/strong&gt; Hijacking unused address space to send spam from "clean" IPs, then disappearing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The common thread: the attacker briefly becomes a network you never chose to trust, sitting directly in the path of your traffic. Everything that crosses an untrusted network in plaintext is readable. Everything not cryptographically authenticated can be modified.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Defenses: RPKI and BGPsec
&lt;/h2&gt;

&lt;p&gt;The internet's structural answer to hijacking is to attach cryptographic proof to routing claims. Two mechanisms matter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RPKI&lt;/strong&gt; — Resource Public Key Infrastructure — lets an address-block owner publish a signed statement called a Route Origin Authorization: "AS number X is authorized to originate this block." Networks that perform Route Origin Validation reject announcements that contradict a valid ROA. RPKI adoption has grown substantially, and it is genuinely effective against the most common case: a wrong-origin announcement, whether accidental or malicious.&lt;/p&gt;

&lt;p&gt;But RPKI only validates the &lt;em&gt;origin&lt;/em&gt; of a route, not the &lt;em&gt;path&lt;/em&gt; it claims to have taken. A sophisticated attacker can craft an announcement that lists the legitimate origin AS at the end while still inserting itself into the path — a defense-aware hijack that RPKI alone does not catch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BGPsec&lt;/strong&gt; closes that gap by cryptographically signing the entire AS path, so each hop can be verified. It is the more complete answer — and the less deployed one, because it demands far more router resources and near-universal adoption to be useful. The realistic state of the internet in 2026 is broad RPKI origin validation and very limited path validation.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Protects against&lt;/th&gt;
&lt;th&gt;Does not stop&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RPKI / ROV&lt;/td&gt;
&lt;td&gt;Wrong-origin announcements — the most common hijack and nearly all accidental leaks&lt;/td&gt;
&lt;td&gt;Path manipulation that keeps the real origin AS at the end&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BGPsec&lt;/td&gt;
&lt;td&gt;Forged AS paths, by signing every hop&lt;/td&gt;
&lt;td&gt;Limited by sparse deployment; high router cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transport encryption (TLS)&lt;/td&gt;
&lt;td&gt;Reading or altering your content on a hijacked path&lt;/td&gt;
&lt;td&gt;The hijack itself, and metadata exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why This Is Ultimately an Encryption Problem for You
&lt;/h2&gt;

&lt;p&gt;Here is the uncomfortable part: as an individual, you cannot fix routing. You do not run an AS. You cannot make your ISP deploy RPKI or audit the path your packets take. Routing security is an operator-level discipline, and you are downstream of every decision those operators make.&lt;/p&gt;

&lt;p&gt;What you &lt;em&gt;can&lt;/em&gt; control is whether a hijack matters when it happens. An attacker who diverts your traffic through their network gains a front-row seat — but only to whatever you sent in the clear. If your connection is protected by TLS 1.3, the attacker sees ciphertext. They cannot read it, and they cannot modify it without breaking the connection, because TLS authenticates both endpoints and every byte.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The internet's routing layer was built on trust and never fully retrofitted with proof. Treat every network between you and your destination as potentially hostile — because for the duration of a hijack, one of them is.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the same logic behind certificate pinning and forward secrecy: assume the path is compromised and design so it does not matter. A hijack can still hurt you in two ways encryption does not erase — it can take a service offline entirely, and it still exposes &lt;em&gt;metadata&lt;/em&gt;, the fact that you connected to a given destination at a given time. But it cannot turn your communications into the attacker's reading material.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Haven Fits
&lt;/h2&gt;

&lt;p&gt;Haven cannot patch BGP, and we would be lying if we claimed to. What we can do is assume the network is untrustworthy and build accordingly. Message content is end-to-end encrypted with keys derived on your device, so a hijacked path carries ciphertext and nothing else. Connections are authenticated, so a man-in-the-middle on a diverted route cannot silently substitute itself.&lt;/p&gt;

&lt;p&gt;Routing-layer security is a job for network operators, and the slow grind of RPKI and BGPsec adoption genuinely helps everyone. But your defense as a user does not depend on that grind finishing. It depends on never trusting the path in the first place — which is a property your tools either have or do not. Haven is one option built on that assumption; the principle holds whichever service you choose.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/bgp-hijacking-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
  </channel>
</rss>
