<?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: gabinotech22-cmyk</title>
    <description>The latest articles on DEV Community by gabinotech22-cmyk (@gabinotech22cmyk).</description>
    <link>https://dev.to/gabinotech22cmyk</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3989776%2Fe1319d4c-60e2-4a8d-9ee3-b98913804062.png</url>
      <title>DEV Community: gabinotech22-cmyk</title>
      <link>https://dev.to/gabinotech22cmyk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gabinotech22cmyk"/>
    <language>en</language>
    <item>
      <title>AegisLink is now installable — shipping a zero-metadata messenger to Android Closed Testing"</title>
      <dc:creator>gabinotech22-cmyk</dc:creator>
      <pubDate>Tue, 07 Jul 2026 18:33:59 +0000</pubDate>
      <link>https://dev.to/gabinotech22cmyk/aegislink-is-now-installable-shipping-a-zero-metadata-messenger-to-android-closed-testing-1m5e</link>
      <guid>https://dev.to/gabinotech22cmyk/aegislink-is-now-installable-shipping-a-zero-metadata-messenger-to-android-closed-testing-1m5e</guid>
      <description>&lt;p&gt;For months this project lived on an emulator on my desk. As of this week, it lives on other people's phones: &lt;strong&gt;AegisLink is now in Closed Testing on Google Play&lt;/strong&gt; — the first build someone who isn't me can actually install.&lt;/p&gt;

&lt;p&gt;If you're new here: AegisLink is an open-source, end-to-end encrypted messenger built around one obsession — the server should learn &lt;em&gt;as close to nothing as possible&lt;/em&gt;. No account (no email, phone, or name), sealed sender so the relay never sees who a message is from, an embedded Tor path, Double Ratchet + X3DH with a hybrid post-quantum handshake, and a fully encrypted local DB. The earlier posts in this series go deep on each piece.&lt;/p&gt;

&lt;p&gt;This post is about the less glamorous part: what it actually takes to &lt;em&gt;ship&lt;/em&gt; something like this, honestly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Data Safety form is a feature, not a chore
&lt;/h2&gt;

&lt;p&gt;Google Play makes you fill in a "Data Safety" section — enumerate, row by row, exactly what your app collects and shares. For most apps it's an exercise in phrasing data collection as gently as possible.&lt;/p&gt;

&lt;p&gt;For AegisLink the honest answer to almost every row is &lt;strong&gt;"no data collected, no data shared"&lt;/strong&gt; — because there genuinely is nothing on the server to declare. No IP logs, no access timestamps, no message sizes, no analytics SDK. Zero metadata stops being a slogan the moment a platform forces you to state, under policy, exactly what you keep.&lt;/p&gt;

&lt;h2&gt;
  
  
  I dropped 32-bit, and I'll say the floor out loud
&lt;/h2&gt;

&lt;p&gt;I tested on a genuinely low-end device (2GB RAM, 32-bit ARM). The result was honest and useful: identity generation didn't freeze, the crypto ran — but the device swapped itself into uselessness and the OS killed the process repeatedly. That's not a bug in the app; it's a hardware floor.&lt;/p&gt;

&lt;p&gt;So the minimum supported spec is now &lt;strong&gt;arm64 with ~3GB+ RAM&lt;/strong&gt;, and I dropped the 32-bit ABIs. I'd rather state the floor plainly than ship a "supported" build that quietly isn't. Most phones from the last few years clear it easily.&lt;/p&gt;

&lt;h2&gt;
  
  
  The crypto runs in JS — on purpose, with eyes open
&lt;/h2&gt;

&lt;p&gt;The primitives run in JavaScript (Hermes). That's a deliberate trade-off: one auditable codebase over raw KDF speed. It works, but it's a known performance ceiling on low-end hardware, and I'm not going to pretend otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's still not done
&lt;/h2&gt;

&lt;p&gt;Being honest is the whole point of doing this in the open: &lt;strong&gt;the crypto has not had an independent third-party audit yet.&lt;/strong&gt; That's a planned next step. Until it happens, every claim here is something to verify in the source — not to take on faith.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to break it? Be a tester
&lt;/h2&gt;

&lt;p&gt;That's exactly what Closed Testing is for — real phones, real feedback, before anything gets called done. Two steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Join the testers group: &lt;a href="https://groups.google.com/g/aegislink-testers" rel="noopener noreferrer"&gt;https://groups.google.com/g/aegislink-testers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Then install from Play: &lt;a href="https://play.google.com/store/apps/details?id=com.aegislink.app" rel="noopener noreferrer"&gt;https://play.google.com/store/apps/details?id=com.aegislink.app&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;(Order matters — Play only shows "Install" once you're in the group.)&lt;/p&gt;

&lt;p&gt;Code, protocol docs, and threat model: &lt;a href="https://github.com/gabinotech22-cmyk/AegisLink" rel="noopener noreferrer"&gt;https://github.com/gabinotech22-cmyk/AegisLink&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you find something wrong — in the app or the code — that's the best thing you can do for the project. Tell me in the comments.&lt;/p&gt;

</description>
      <category>android</category>
      <category>opensource</category>
      <category>privacy</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Shipped this week: the mailbox transport now routes through an embedded Tor client built into the app itself, instead of depending on a separate Orbot install. That removes a real adoption barrier â€” most people won't install a second app just for IP-laye</title>
      <dc:creator>gabinotech22-cmyk</dc:creator>
      <pubDate>Sun, 28 Jun 2026 19:31:01 +0000</pubDate>
      <link>https://dev.to/gabinotech22cmyk/shipped-this-week-the-mailbox-transport-now-routes-through-an-embedded-tor-client-built-into-the-2c6p</link>
      <guid>https://dev.to/gabinotech22cmyk/shipped-this-week-the-mailbox-transport-now-routes-through-an-embedded-tor-client-built-into-the-2c6p</guid>
      <description></description>
      <category>mobile</category>
      <category>privacy</category>
      <category>showdev</category>
      <category>ux</category>
    </item>
    <item>
      <title>How AegisLink's handshake survives a quantum computer (X3DH + ML-KEM-768)</title>
      <dc:creator>gabinotech22-cmyk</dc:creator>
      <pubDate>Fri, 26 Jun 2026 16:56:56 +0000</pubDate>
      <link>https://dev.to/aegislink/how-aegislinks-handshake-survives-a-quantum-computer-x3dh-ml-kem-768-5259</link>
      <guid>https://dev.to/aegislink/how-aegislinks-handshake-survives-a-quantum-computer-x3dh-ml-kem-768-5259</guid>
      <description>&lt;p&gt;In my first post in this series I said the next one would go deep on the&lt;br&gt;
handshake. This is it. If you've ever wondered what actually happens in the&lt;br&gt;
half-second before two strangers can exchange an encrypted message, read on. As&lt;br&gt;
always: this is &lt;strong&gt;pre-release, unaudited&lt;/strong&gt; — the point of writing it down is so&lt;br&gt;
you can check it.&lt;/p&gt;
&lt;h2&gt;
  
  
  The job of a handshake
&lt;/h2&gt;

&lt;p&gt;Before any messages flow, two devices that have never talked need to agree on a&lt;br&gt;
shared secret — over a relay that sees everything and is assumed hostile. The&lt;br&gt;
relay can drop, reorder, replay, and inject traffic, and it can try to swap the&lt;br&gt;
keys it hands you. The handshake has to produce the same secret on both sides&lt;br&gt;
&lt;em&gt;and&lt;/em&gt; detect tampering.&lt;/p&gt;

&lt;p&gt;AegisLink uses &lt;strong&gt;X3DH&lt;/strong&gt; (the Signal construction) for this, then adds a&lt;br&gt;
post-quantum layer on top. Let's take them in order.&lt;/p&gt;
&lt;h2&gt;
  
  
  Part 1: classical X3DH
&lt;/h2&gt;

&lt;p&gt;Each user has a long-term &lt;strong&gt;Ed25519&lt;/strong&gt; signing key and &lt;strong&gt;X25519&lt;/strong&gt; Diffie-Hellman&lt;br&gt;
keys. To receive messages, Bob publishes a &lt;em&gt;prekey bundle&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;his identity key,&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;signed prekey&lt;/strong&gt; (X25519, signed with his Ed25519 identity key),&lt;/li&gt;
&lt;li&gt;optionally a &lt;strong&gt;one-time prekey&lt;/strong&gt; (consumed once, then gone).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alice fetches Bob's bundle and does the critical first step: &lt;strong&gt;she verifies the&lt;br&gt;
Ed25519 signature on the signed prekey before doing anything else.&lt;/strong&gt; If it&lt;br&gt;
doesn't check out, she aborts. This is what closes the classic&lt;br&gt;
prekey-substitution MITM — a malicious relay can hand Alice a fake prekey, but&lt;br&gt;
it can't forge Bob's signature over it.&lt;/p&gt;

&lt;p&gt;Then she runs the Diffie-Hellman ladder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DH1 = DH(IK_A, SPK_B)
DH2 = DH(EK_A, IK_B)
DH3 = DH(EK_A, SPK_B)
DH4 = DH(EK_A, OPK_B)   // only if a one-time prekey was available
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every DH output is checked against all-zero and rejected if it matches — that's&lt;br&gt;
the guard against low-order / identity-point injection, where an attacker tries&lt;br&gt;
to force a known shared value.&lt;/p&gt;

&lt;p&gt;The results are concatenated and run through a KDF:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SK = HKDF-SHA256( IKM = 0xFF×32 ‖ DH1 ‖ DH2 ‖ DH3 [‖ DH4],
                  info = "AegisLinkX3DH" )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bob, on receipt, mirrors the exact same DH order, the same zero-guards, and the&lt;br&gt;
same HKDF parameters — so both sides land on an identical &lt;code&gt;SK&lt;/code&gt; without ever&lt;br&gt;
sending it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: making it quantum-resistant
&lt;/h2&gt;

&lt;p&gt;X25519 is great today, but it falls to a large enough quantum computer. And the&lt;br&gt;
threat isn't hypothetical-someday — it's &lt;strong&gt;harvest now, decrypt later&lt;/strong&gt;: an&lt;br&gt;
adversary records your encrypted traffic today and decrypts it in 2035. For a&lt;br&gt;
privacy tool, that's the threat that matters.&lt;/p&gt;

&lt;p&gt;So handshake &lt;strong&gt;v2&lt;/strong&gt; adds &lt;strong&gt;ML-KEM-768&lt;/strong&gt; (FIPS 203, the standardized Kyber) &lt;em&gt;on&lt;br&gt;
top of&lt;/em&gt; X3DH — it does not replace it. Bob publishes one more prekey: a &lt;strong&gt;signed&lt;br&gt;
PQ prekey (PQSPK)&lt;/strong&gt;, an ML-KEM-768 public key signed by his identity key, just&lt;br&gt;
like the classical one.&lt;/p&gt;

&lt;p&gt;Alice, after finishing classical X3DH:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;encapsulates against Bob's PQ prekey: &lt;code&gt;(ct, ss) = ML-KEM-768.encapsulate(PQSPK_B)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;appends the 32-byte ML-KEM secret &lt;code&gt;ss&lt;/code&gt; to the classical material:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   SK = HKDF-SHA256( IKM = 0xFF×32 ‖ DH1 ‖ DH2 ‖ DH3 [‖ DH4] ‖ ss,
                     info = "AegisLinkPQXDH" )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;sends the 1088-byte ML-KEM ciphertext &lt;code&gt;ct&lt;/code&gt; &lt;strong&gt;inside the sealed message&lt;/strong&gt;,
never as a field the relay can see.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bob decapsulates &lt;code&gt;ss = ML-KEM-768.decapsulate(ct, PQSPK_secret_B)&lt;/code&gt; and derives&lt;br&gt;
the identical &lt;code&gt;SK&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The payoff is the "hybrid" property: &lt;strong&gt;breaking a v2 session requires breaking&lt;br&gt;
both X25519 and ML-KEM-768.&lt;/strong&gt; A future quantum attacker who cracks the elliptic&lt;br&gt;
curve still hits a wall at the lattice, and a classical attacker who finds a flaw&lt;br&gt;
in the (newer, less battle-tested) lattice scheme still hits the curve. You only&lt;br&gt;
lose if both fall.&lt;/p&gt;

&lt;h2&gt;
  
  
  One subtle bit: implicit rejection
&lt;/h2&gt;

&lt;p&gt;ML-KEM uses implicit rejection (per FIPS 203): feed it a tampered ciphertext and&lt;br&gt;
it doesn't throw an error — it returns a &lt;em&gt;different&lt;/em&gt; shared secret. That's by&lt;br&gt;
design. In our handshake it means a tampered &lt;code&gt;ct&lt;/code&gt; simply yields a different &lt;code&gt;SK&lt;/code&gt;,&lt;br&gt;
and the first real message fails to decrypt, rather than leaking a&lt;br&gt;
distinguishable "decapsulation failed" signal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to look
&lt;/h2&gt;

&lt;p&gt;It's all in the open — the X3DH implementation lives in&lt;br&gt;
&lt;code&gt;mobile/src/crypto/signal/x3dh.ts&lt;/code&gt;, and the full spec (with the threat model and&lt;br&gt;
the parts that are still in progress) is in&lt;br&gt;
&lt;a href="https://github.com/gabinotech22-cmyk/AegisLink/blob/main/docs/PROTOCOL.md" rel="noopener noreferrer"&gt;docs/PROTOCOL.md&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/gabinotech22-cmyk/AegisLink" rel="noopener noreferrer"&gt;https://github.com/gabinotech22-cmyk/AegisLink&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you spot a mistake in the construction above — wrong, weak, or just unclear —&lt;br&gt;
that's exactly the feedback I'm after. Next in the series: how the Double Ratchet&lt;br&gt;
takes over once this handshake hands off the first key.&lt;/p&gt;

</description>
      <category>cryptography</category>
      <category>privacy</category>
      <category>opensource</category>
      <category>security</category>
    </item>
    <item>
      <title>Building a messenger that hides metadata, not just messages</title>
      <dc:creator>gabinotech22-cmyk</dc:creator>
      <pubDate>Sun, 21 Jun 2026 09:02:37 +0000</pubDate>
      <link>https://dev.to/aegislink/building-a-messenger-that-hides-metadata-not-just-messages-1f99</link>
      <guid>https://dev.to/aegislink/building-a-messenger-that-hides-metadata-not-just-messages-1f99</guid>
      <description>&lt;p&gt;Most "encrypted" apps protect &lt;em&gt;what&lt;/em&gt; you say. They do far less about &lt;em&gt;who you&lt;br&gt;
talk to, when, and how often&lt;/em&gt; — the metadata. And metadata is often the part&lt;br&gt;
that actually gets people in trouble.&lt;/p&gt;

&lt;p&gt;I'm building &lt;strong&gt;AegisLink&lt;/strong&gt;, an open-source end-to-end encrypted messenger, with&lt;br&gt;
that as the central obsession. This is the first post in a build-in-public&lt;br&gt;
series. Everything here is &lt;strong&gt;pre-release and has had no independent audit yet&lt;/strong&gt;,&lt;br&gt;
so treat it as claims to verify — not promises. That's exactly why the code and&lt;br&gt;
protocol are public.&lt;/p&gt;

&lt;h2&gt;
  
  
  The threat I actually care about
&lt;/h2&gt;

&lt;p&gt;End-to-end encryption is table stakes now. The interesting question is what the&lt;br&gt;
&lt;em&gt;server&lt;/em&gt; learns even when it can't read your messages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;who is talking to whom&lt;/li&gt;
&lt;li&gt;when, and how often&lt;/li&gt;
&lt;li&gt;from which IP, on which device&lt;/li&gt;
&lt;li&gt;message and attachment sizes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A server that logs those can reconstruct your entire social graph without ever&lt;br&gt;
decrypting a word. So the design rule for AegisLink's relay is simple: &lt;strong&gt;know as&lt;br&gt;
little as possible.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How that translates into code
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No account.&lt;/strong&gt; No email, no phone, no name. Identity is generated on-device
(Ed25519 + X25519); your address is a random ID.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dumb relay.&lt;/strong&gt; It forwards opaque ciphertext and keeps no logs of who
messages whom — no IPs, no access timestamps, no message sizes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern crypto.&lt;/strong&gt; Double Ratchet + X3DH, with a hybrid post-quantum layer
(PQXDH). Private keys never leave the device.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sealed signaling for calls.&lt;/strong&gt; WebRTC SDP/ICE is sealed with NaCl box before
it reaches the relay, so the server never sees IPs or DTLS fingerprints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encrypted at rest.&lt;/strong&gt; The local DB is encrypted (SQLCipher); backups use an
Argon2id-derived key only the user holds.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's NOT done yet
&lt;/h2&gt;

&lt;p&gt;Being honest is the whole point of doing this in the open:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transport-level sealed-sender&lt;/strong&gt; — hiding the sender from the relay &lt;em&gt;process
itself&lt;/em&gt; — is in active development, not shipped.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No third-party audit&lt;/strong&gt; has happened. The protocol and threat model are in
the repo precisely so people who know more than me can check the work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Follow along / tear it apart
&lt;/h2&gt;

&lt;p&gt;Code, protocol docs and threat model:&lt;br&gt;
&lt;a href="https://github.com/gabinotech22-cmyk/AegisLink" rel="noopener noreferrer"&gt;https://github.com/gabinotech22-cmyk/AegisLink&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next post I'll go deep on one piece — probably the X3DH/PQXDH handshake. If&lt;br&gt;
there's something you'd rather I break down, tell me in the comments.&lt;/p&gt;

</description>
      <category>buildinpublic</category>
      <category>opensource</category>
      <category>privacy</category>
      <category>security</category>
    </item>
  </channel>
</rss>
