{"id":17249,"date":"2026-08-03T16:34:31","date_gmt":"2026-08-03T16:34:31","guid":{"rendered":"https:\/\/dmsretail.com\/RetailNews\/a-different-road-to-quantum-safety-the-ppk-ipsec-series-part-5\/"},"modified":"2026-08-03T16:34:31","modified_gmt":"2026-08-03T16:34:31","slug":"a-different-road-to-quantum-safety-the-ppk-ipsec-series-part-5","status":"publish","type":"post","link":"https:\/\/dmsretail.com\/RetailNews\/a-different-road-to-quantum-safety-the-ppk-ipsec-series-part-5\/","title":{"rendered":"A Different Road to Quantum Safety: The PPK &#8211; IPsec Series, Part 5"},"content":{"rendered":"<p> <p><a href=\"https:\/\/dmsretail.com\/online-workshops-list\/\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-496\" src=\"https:\/\/dmsretail.com\/RetailNews\/wp-content\/uploads\/2022\/05\/RETAIL-ONLINE-TRAINING-728-X-90.png\" alt=\"Retail Online Training\" width=\"729\" height=\"91\" srcset=\"https:\/\/dmsretail.com\/RetailNews\/wp-content\/uploads\/2022\/05\/RETAIL-ONLINE-TRAINING-728-X-90.png 729w, https:\/\/dmsretail.com\/RetailNews\/wp-content\/uploads\/2022\/05\/RETAIL-ONLINE-TRAINING-728-X-90-300x37.png 300w\" sizes=\"auto, (max-width: 729px) 100vw, 729px\" \/><\/a><\/p><br \/>\n<\/p>\n<div>\n<p class=\"code-line\" dir=\"auto\" data-line=\"6\">So far in this pillar we made the\u00a0<em>key exchange itself<\/em> quantum-safe by bolting a post-quantum algorithm (ML-KEM) onto it. That\u2019s the headline approach, and in Part 4 we watched it run. But it\u2019s not the only way to beat \u201charvest now, decrypt later.\u201d There\u2019s an alternative road that gets you to the <em>same<\/em>\u00a0destination without any new crypto algorithm at all.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"8\">It\u2019s called a\u00a0<strong>Postquantum Preshared Key (PPK)<\/strong>, defined in\u00a0<strong>RFC 8784<\/strong>. Let\u2019s understand it, then prove it works.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"8\">Note: this Part uses the same <code>key-exchange\/<\/code>\u00a0lab as Part 4.<\/p>\n<hr class=\"code-line\" dir=\"auto\" data-line=\"12\"\/>\n<h2 id=\"the-idea-mix-in-a-secret-that-never-travels\" class=\"code-line\" dir=\"auto\" data-line=\"14\">The idea: mix in a secret that never travels<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"16\">RFC 8784 takes a completely different route to the harvest-now-decrypt-later problem. Instead of a new algorithm, it mixes a\u00a0<strong>static, out-of-band preshared key<\/strong>\u00a0into the IKE key schedule. The key property:\u00a0<strong>the PPK never travels on the wire.<\/strong>\u00a0It\u2019s distributed ahead of time, so both peers already know it.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"18\">Here\u2019s why that defeats a future quantum computer. Suppose an attacker records your handshake today and, years from now, uses a quantum computer to recover the X25519 shared secret from it. They\u00a0<em>still<\/em>\u00a0can\u2019t derive your traffic keys, because those keys also depend on the PPK, which was never transmitted and which their recording therefore doesn\u2019t contain. No PPK, no keys. The recorded session stays locked.<\/p>\n<blockquote class=\"code-line\" dir=\"auto\" data-line=\"20\">\n<p class=\"code-line\" dir=\"auto\" data-line=\"20\"><strong>Two roads, one destination.<\/strong>\u00a0ML-KEM (RFC 9370) makes the\u00a0<em>math<\/em>\u00a0quantum-hard and is negotiated like any other algorithm. PPK (RFC 8784) makes\u00a0<em>no new cryptographic assumption<\/em> about the exchange; it just requires that a high-entropy secret stays secret and is shared out of band. That means PPK works even on legacy gear that cannot negotiate ML-KEM, which makes it a practical <strong>first step<\/strong>: get post-quantum confidentiality today, migrate to ML-KEM once both ends support it.<\/p>\n<\/blockquote>\n<p class=\"code-line\" dir=\"auto\" data-line=\"22\">The catch is operational, and it\u2019s a big one: every peer\u00a0<em>pair<\/em>\u00a0needs the same secret pre-shared and rotated, which is exactly the key-distribution headache public-key crypto was invented to avoid. (At scale, the secrets are either managed manually or generated by Quantum Key Distribution appliances needing a full mesh of point-to-point fibers, none of which scales gracefully.) So PPK is a transitional step, not a destination. Also note: PPK protects only the\u00a0<em>derived keys<\/em>; authentication here is still a classical PSK.<\/p>\n<hr class=\"code-line\" dir=\"auto\" data-line=\"24\"\/>\n<h2 id=\"set-up-the-lab\" class=\"code-line\" dir=\"auto\" data-line=\"26\">Set up the lab<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"28\">This uses the same two-container key-exchange lab as Part 4. If you don\u2019t already have it running, clone the repo, build, and start both peers (only Docker required):<\/p>\n<pre><code class=\"code-line language-bash\" dir=\"auto\" data-line=\"30\">git <span class=\"hljs-built_in\">clone<\/span> https:\/\/github.com\/juliogomez\/pqc.git&#13;\n<span class=\"hljs-built_in\">cd<\/span> pqc\/key-exchange&#13;\n&#13;\n&#13;\ndocker compose build&#13;\ndocker compose up -d&#13;\ndocker compose ps        &#13;\n<\/code><\/pre>\n<hr class=\"code-line\" dir=\"auto\" data-line=\"40\"\/>\n<h2 id=\"lets-prove-it-drop-to-classical-ke-and-let-the-ppk-carry-it\" class=\"code-line\" dir=\"auto\" data-line=\"42\">Let\u2019s prove it: drop to classical KE and let the PPK carry it<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"44\">To make the \u201calternative to ML-KEM\u201d point crystal clear, this exercise drops the key exchange back to\u00a0<strong>classical-only X25519<\/strong> on purpose (standing in for a legacy device that does not support ML-KEM) and lets the PPK provide the quantum resistance entirely on its own.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"46\">Shell into the initiator (<code>docker exec -it ike-initiator bash<\/code>) and edit\u00a0<code>swanctl.conf<\/code>. First, switch the proposal to classical-only (same toggle as Part 4):<\/p>\n<pre><code class=\"code-line\" dir=\"auto\" data-line=\"48\"># proposals = aes256gcm16-prfsha256-x25519-ke1_mlkem768&#13;\nproposals = aes256gcm16-prfsha256-x25519&#13;\n<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"53\">Then uncomment the two PPK lines in the connection:<\/p>\n<pre><code class=\"code-line\" dir=\"auto\" data-line=\"55\">        ppk_id = pqc-lab-ppk&#13;\n        ppk_required = yes&#13;\n<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"60\">And uncomment the secret block at the bottom:<\/p>\n<pre><code class=\"code-line\" dir=\"auto\" data-line=\"62\">    ppk-lab {&#13;\n        id = pqc-lab-ppk&#13;\n        secret = 0x5c9a3f1e8b7d4602af19e3c8d05b6f27a4e91d83c2b7f0a6e5d4c3b2a1908f7e&#13;\n    }&#13;\n<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"69\">Make the same edits in the responder, then reload both with\u00a0<code>swanctl --load-all<\/code>. The output now lists the PPK alongside the auth PSK:<\/p>\n<pre><code class=\"code-line\" dir=\"auto\" data-line=\"71\">loaded ike secret 'ike-psk'&#13;\nloaded ppk secret 'ppk-lab'&#13;\n<\/code><\/pre>\n<blockquote class=\"code-line\" dir=\"auto\" data-line=\"76\">\n<p class=\"code-line\" dir=\"auto\" data-line=\"76\"><strong>Reminder: these are lab secrets.<\/strong>\u00a0That hex value is a throwaway for learning. In the real world a PPK is a high-entropy secret you\u2019d generate securely, distribute out of band, store carefully, and rotate. Never reuse lab keys anywhere that matters.<\/p>\n<\/blockquote>\n<hr class=\"code-line\" dir=\"auto\" data-line=\"78\"\/>\n<h2 id=\"initiate-and-confirm-the-ppk-is-in-play\" class=\"code-line\" dir=\"auto\" data-line=\"80\">Initiate and confirm the PPK is in play<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"82\">From the initiator:<\/p>\n<pre><code class=\"code-line language-bash\" dir=\"auto\" data-line=\"84\">swanctl --initiate --child pqc-child&#13;\n<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"88\">Four lines in the log tell the whole story:<\/p>\n<pre><code class=\"code-line\" dir=\"auto\" data-line=\"90\">[ENC] generating IKE_SA_INIT request 0 [ SA KE No ... N(USE_PPK) ]&#13;\n[CFG] selected proposal: IKE:AES_GCM_16_256\/PRF_HMAC_SHA2_256\/CURVE_25519&#13;\n[ENC] generating IKE_AUTH request 1 [ IDi AUTH SA TSi TSr ... N(PPK_ID) ]&#13;\n[CFG] using PPK for PPK_ID 'pqc-lab-ppk'&#13;\n<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"97\">Notice what\u2019s\u00a0<em>missing<\/em>\u00a0compared to Part 4: the selected proposal is plain\u00a0<code>CURVE_25519<\/code>: no\u00a0<code>KE1_ML_KEM_768<\/code>, no\u00a0<code>IKE_INTERMEDIATE<\/code>, no fragments. This is an old-fashioned classical handshake.\u00a0<strong>And yet it\u2019s now quantum-resistant<\/strong>, entirely thanks to the PPK:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"99\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"99\"><code>N(USE_PPK)<\/code>\u00a0rides in the\u00a0<em>cleartext<\/em>\u00a0<code>IKE_SA_INIT<\/code>, each peer advertising support.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"100\"><code>N(PPK_ID)<\/code>\u00a0rides inside the\u00a0<em>encrypted<\/em>\u00a0<code>IKE_AUTH<\/code>, signalling which PPK is in use.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"101\"><code>using PPK for PPK_ID 'pqc-lab-ppk'<\/code>\u00a0is strongSwan confirming the secret was found and mixed into the key schedule.<\/li>\n<\/ul>\n<p class=\"code-line\" dir=\"auto\" data-line=\"103\">If you capture the run (same\u00a0<code>tcpdump<\/code>\u00a0recipe as Part 4), three contrasts with the ML-KEM runs stand out:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"105\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"105\"><strong>No\u00a0<code>#43<\/code>, no fragments.<\/strong>\u00a0Just the plain two-round-trip classical handshake. The quantum resistance is riding entirely on the PPK, invisible in the packets.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"106\"><strong><code>USE_PPK<\/code>\u00a0is public;\u00a0<code>PPK_ID<\/code>\u00a0is private.<\/strong>\u00a0Discovery (\u201cdo we both support it?\u201d) is in the cleartext\u00a0<code>IKE_SA_INIT<\/code>;\u00a0<em>which<\/em>\u00a0PPK is selected travels encrypted inside\u00a0<code>IKE_AUTH<\/code>.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"107\"><strong>The PPK itself appears nowhere.<\/strong>\u00a0That\u2019s the whole point: mixed into the keys on both ends, never sent.<\/li>\n<\/ul>\n<hr class=\"code-line\" dir=\"auto\" data-line=\"109\"\/>\n<h2 id=\"prove-its-actually-required-not-just-for-show\" class=\"code-line\" dir=\"auto\" data-line=\"111\">Prove it\u2019s actually required<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"113\">Because we set\u00a0<code>ppk_required = yes<\/code>, a peer that doesn\u2019t hold the matching PPK can\u2019t complete the handshake. Let\u2019s prove the secret is genuinely folded into the keys. Terminate the tunnel, then,\u00a0<em>in the initiator only<\/em>, change its\u00a0<code>ppk-lab<\/code>\u00a0secret to a different value (simulating a peer that doesn\u2019t know the real one):<\/p>\n<pre><code class=\"code-line\" dir=\"auto\" data-line=\"115\">    ppk-lab {&#13;\n        id = pqc-lab-ppk&#13;\n        secret = 0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef&#13;\n    }&#13;\n<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"122\">Reload just the initiator and re-initiate. This time it\u00a0<strong>fails<\/strong>: the mismatched PPK changes the\u00a0<code>SK_pi<\/code>\/<code>SK_pr<\/code>\u00a0keys, so the responder can\u2019t verify the initiator\u2019s AUTH payload and rejects it:<\/p>\n<pre><code class=\"code-line\" dir=\"auto\" data-line=\"124\">[ENC] parsed IKE_AUTH response 1 [ N(AUTH_FAILED) ]&#13;\n[IKE] received AUTHENTICATION_FAILED notify error&#13;\ninitiate failed: establishing CHILD_SA 'pqc-child' failed&#13;\n<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"130\">There\u2019s your proof: the PPK isn\u2019t decorative; it\u2019s baked into the keys. Get it wrong and the tunnel simply won\u2019t come up.<\/p>\n<blockquote class=\"code-line\" dir=\"auto\" data-line=\"132\">\n<p class=\"code-line\" dir=\"auto\" data-line=\"132\"><strong>Tidy up your clone.<\/strong>\u00a0Because\u00a0<code>config\/<\/code>\u00a0is bind-mounted, your\u00a0<code>vi<\/code>\u00a0edits were written to your repo files. Since they\u2019re git-tracked, one command from the host (in\u00a0<code>key-exchange\/<\/code>) snaps both peers back to the shipped state:\u00a0<code>git restore config\/<\/code>. That re-comments the PPK lines, restores the secret, and switches the proposal back to hybrid: a clean slate for the next run.<\/p>\n<\/blockquote>\n<hr class=\"code-line\" dir=\"auto\" data-line=\"134\"\/>\n<h2 id=\"when-would-you-actually-use-this\" class=\"code-line\" dir=\"auto\" data-line=\"136\">When would you actually use this?<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"138\">Mainly as a\u00a0<strong>stepping stone<\/strong>. Equipment that can\u2019t negotiate RFC 9370 \/ ML-KEM yet, but needs harvest-now-decrypt-later protection\u00a0<em>today<\/em>, can deploy a PPK now and migrate to ML-KEM once both ends support it. The price is the classic preshared-key burden (secure distribution, storage, and rotation of a \u2265256-bit secret across every peer pair), which is exactly why it\u2019s a transition, not a home.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"140\">So the two roads complement each other: PPK for \u201cI need protection now on legacy gear,\u201d ML-KEM for \u201cI can negotiate it and want it to scale.\u201d Plenty of real deployments will use <em>both<\/em>\u00a0during the migration years ahead.<\/p>\n<hr class=\"code-line\" dir=\"auto\" data-line=\"142\"\/>\n<h2 id=\"thats-a-wrap-on-key-exchange\" class=\"code-line\" dir=\"auto\" data-line=\"144\">That\u2019s a wrap on key exchange<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"146\">Over the last four posts we\u2019ve taken the urgent pillar end to end: the threat, the contenders, the hybrid showdown, a real captured handshake, and now a second independent road to the same safety. You\u2019ve seen, really\u00a0<em>seen<\/em>, that quantum-safe key exchange is here, practical, and affordable today.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"148\">Now we flip to the\u00a0<strong>other<\/strong>\u00a0pillar, and it behaves\u00a0<em>completely<\/em>\u00a0differently. No \u201charvest now, decrypt later\u201d here, but a sneakier deadline that catches almost everyone off guard. In\u00a0<strong>Part 6<\/strong>\u00a0we start the authentication story and meet the post-quantum signatures. See you there, and bring your curiosity, because this half has a twist.<\/p>\n<\/p><\/div>\n<p><p><a href=\"https:\/\/dmsretail.com\/online-workshops-list\/\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-496\" src=\"https:\/\/dmsretail.com\/RetailNews\/wp-content\/uploads\/2022\/05\/RETAIL-ONLINE-TRAINING-728-X-90.png\" alt=\"Retail Online Training\" width=\"729\" height=\"91\" srcset=\"https:\/\/dmsretail.com\/RetailNews\/wp-content\/uploads\/2022\/05\/RETAIL-ONLINE-TRAINING-728-X-90.png 729w, https:\/\/dmsretail.com\/RetailNews\/wp-content\/uploads\/2022\/05\/RETAIL-ONLINE-TRAINING-728-X-90-300x37.png 300w\" sizes=\"auto, (max-width: 729px) 100vw, 729px\" \/><\/a><\/p><br \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>So far in this pillar we made the\u00a0key exchange itself quantum-safe by bolting a post-quantum algorithm (ML-KEM) onto it. That\u2019s the headline approach, and in [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":17250,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-17249","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-technology"],"_links":{"self":[{"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/posts\/17249","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/comments?post=17249"}],"version-history":[{"count":0,"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/posts\/17249\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/media\/17250"}],"wp:attachment":[{"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/media?parent=17249"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/categories?post=17249"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dmsretail.com\/RetailNews\/wp-json\/wp\/v2\/tags?post=17249"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}