<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>rss.livelink.threads-in-node</title>
    <link>https://techcommunity.microsoft.com/t5/post-quantum-crypto-tech/ct-p/post-quantum-crypto-tech</link>
    <description>rss.livelink.threads-in-node</description>
    <pubDate>Thu, 27 Aug 2026 10:15:50 GMT</pubDate>
    <dc:creator>post-quantum-crypto-tech</dc:creator>
    <dc:date>2026-08-27T10:15:50Z</dc:date>
    <item>
      <title>Threat Modeling and Post Quantum Cryptography</title>
      <link>https://techcommunity.microsoft.com/t5/post-quantum-crypto-tech-blog/threat-modeling-and-post-quantum-cryptography/ba-p/4546832</link>
      <description>&lt;P&gt;&lt;EM&gt;&lt;STRONG&gt;By Michael Howard (Azure Security PQC) and Simone Curzi (Azure Data Platform Security)&lt;/STRONG&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;The transition to post-quantum cryptography (PQC) introduces a new challenge: organizations must first understand where cryptography is used before they can assess its suitability in a post-quantum world. Cryptographic functionality may be implemented through operating system libraries such as CNG, SymCrypt, or OpenSSL, third-party dependencies, frameworks, or application code. As quantum-resistant algorithms become necessary, organizations need to identify these usages, determine the algorithms involved, and plan migrations where required.&lt;/P&gt;
&lt;P&gt;Building a complete cryptographic inventory is difficult. Automated discovery and code scanning can identify many dependencies, but they often miss architectural assumptions, platform-provided capabilities, indirect dependencies, and design-level controls. This article shows how threat modeling can uncover those gaps and contribute findings to a PQC migration inventory.&lt;/P&gt;
&lt;H2&gt;What is Threat Modeling?&lt;/H2&gt;
&lt;P&gt;This article assumes a basic familiarity with threat modeling. Readers who are new to the topic should refer to the &lt;A href="https://www.threatmodelingmanifesto.org/" target="_blank" rel="noopener"&gt;Threat Modeling Manifesto&lt;/A&gt;, the works of Adam Shostack, Brook S. E. Schoenfield, Izar Tarandach, and Matthew J. Coles, (and dare we say, the authors of this post!), as well as the extensive online training and documentation available. Our focus here is on a specific application of threat modeling: helping organizations build a more complete cryptographic inventory to support PQC migration.&lt;/P&gt;
&lt;H1&gt;Pulling out the Crypto&lt;/H1&gt;
&lt;P&gt;At first glance, threat modeling and cryptography seem to operate at different levels. Threat modeling focuses on system design, while cryptography is often viewed as an implementation detail. As a result, cryptographic controls typically appear in a threat model as mitigations: data is encrypted in transit, encrypted at rest, or signed to provide integrity and authenticity. The specific implementation details are often omitted.&lt;/P&gt;
&lt;P&gt;For example, threat models rarely record which protocol versions and algorithms are used, whether they originate from operating system libraries such as CNG, SymCrypt, or OpenSSL, from third-party dependencies, or from custom code. Details such as cryptographic key sizes, cipher suites, block modes, or signature algorithms are also frequently absent.&lt;/P&gt;
&lt;P&gt;At the same time, threat modeling often captures information that is highly valuable for PQC migration.&lt;/P&gt;
&lt;P&gt;A good threat modeler asks where cryptography is used, which assets and trust boundaries it protects, how keys are managed, and which components provide the capability. Each answer should be followed by questions such as: How is it implemented? Which operating-system, library, cloud, hardware, or custom-code dependency provides it? What assumptions and external dependencies does the design rely on?&lt;/P&gt;
&lt;P&gt;These questions often reveal information that would otherwise remain undocumented, helping organizations build a more complete understanding of their cryptographic dependencies and better prepare for PQC migration.&lt;/P&gt;
&lt;P&gt;By asking a small number of additional, &lt;EM&gt;low-level&lt;/EM&gt; questions during the threat-modeling process, organizations can close much of the gap between a threat model and a cryptographic inventory. Here are some examples:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Which cryptographic algorithms are used?&lt;/LI&gt;
&lt;LI&gt;What key sizes or security parameters are configured?&lt;/LI&gt;
&lt;LI&gt;Which protocols, protocol versions and cipher suites are in use?&lt;/LI&gt;
&lt;LI&gt;Are cryptographic functions provided by the operating system, third-party libraries, cloud services, or custom code?&lt;/LI&gt;
&lt;LI&gt;Are RSA or elliptic-curve algorithms used for key exchange, certificates, or digital signatures?&lt;/LI&gt;
&lt;LI&gt;Can the cryptographic implementation be upgraded or replaced without significant architectural changes?&lt;/LI&gt;
&lt;LI&gt;Are there external dependencies whose migration to PQC is controlled by another party?&lt;/LI&gt;
&lt;LI&gt;How long must the protected data remain confidential or trustworthy, and is it exposed to harvest-now-decrypt-later risk?&lt;/LI&gt;
&lt;LI&gt;Where are keys generated, provisioned, stored, distributed, backed up, recovered, rotated, revoked, and destroyed?&lt;/LI&gt;
&lt;LI&gt;Which identities, authentication flows, authorization decisions, or trust anchors depend on public-key cryptography?&lt;/LI&gt;
&lt;LI&gt;Are certificates, certificate chains, PKI services, code-signing systems, tokens, or firmware-update mechanisms quantum-vulnerable?&lt;/LI&gt;
&lt;LI&gt;Are secrets or keys protected by TPMs, HSMs, secure enclaves, smart cards, or other hardware, and can that hardware support PQC?&lt;BR /&gt;&lt;EM&gt;Note: PQC migrations are often constrained by hardware platforms whose firmware, key formats, or cryptographic APIs may not yet support post-quantum algorithms.&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;Does the system use cryptography in file formats, databases, backups, logs, messages, APIs, queues, or inter-service protocols?&lt;/LI&gt;
&lt;LI&gt;Are cryptographic algorithms, parameters, or protocol versions hard-coded, negotiated, configured, or controlled by policy?&lt;/LI&gt;
&lt;LI&gt;Can algorithms and key formats be changed independently, or are they tightly coupled to schemas, APIs, storage formats, or hardware?&lt;/LI&gt;
&lt;LI&gt;Could an attacker force use of a weaker algorithm, legacy protocol, non-PQC path, or insecure compatibility mode?&lt;/LI&gt;
&lt;LI&gt;Who owns each cryptographic dependency?&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;The questions we have listed here are far from being exhaustive, but they represent a good starting point.&lt;/P&gt;
&lt;H1&gt;But is it PQC?&lt;/H1&gt;
&lt;P&gt;Ok, so now we have our list of cryptographic algorithms or protocols used in your solution, now you must look at each algorithm to determine if it is quantum resistant, and if not, determine the replacement.&lt;/P&gt;
&lt;P&gt;Here is a quick cheat sheet summarizing Microsoft’s most recent migration recommendations.&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="width: 87.963%; border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;
&lt;H5&gt;&lt;STRONG&gt;Current Scenario&lt;/STRONG&gt;&lt;/H5&gt;
&lt;/td&gt;&lt;td&gt;
&lt;H5&gt;&lt;STRONG&gt;Current Algorithm/Protocol&lt;/STRONG&gt;&lt;/H5&gt;
&lt;/td&gt;&lt;td&gt;
&lt;H5&gt;&lt;STRONG&gt;PQ Algorithm/Protocol&lt;/STRONG&gt;&lt;/H5&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Network traffic&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;TLS 1.2&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;TLS 1.3 (required foundation)&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Network traffic&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;TLS 1.3 with classical key agreement (Elliptic Curve)&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;TLS 1.3 hybrid (Elliptic Curve + ML-KEM)&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Key establishment&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;RSA/ECDH/DH&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;ML-KEM&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Data at Rest Bulk Encryption&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Anything that is not AES256&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;AES256&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Asymmetric Key Wrapping&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;RSA/ECC&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Use an ML-KEM-based key establishment mechanism or wrap with a symmetric key already established through a PQ-safe mechanism.&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Symmetric Key Wrapping&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;AES128&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;AES256&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Hashing&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;&amp;lt;= SHA256&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;SHA384&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Digital Signature&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;RSA/ECC&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;ML-DSA or SLH-DSA or composite signatures&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;col style="width: 33.33%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;A note on TLS 1.3 – you &lt;EM&gt;must&lt;/EM&gt; use TLS 1.3 to support post-quantum hybrid key establishment. Prior versions of TLS &lt;EM&gt;do not&lt;/EM&gt; support PQC.&lt;/P&gt;
&lt;P&gt;The biggest band-for-the-buck PQC improvement is to move TLS 1.2 to TLS 1.3 and support hybrid groups; you can learn more at a previous post &lt;A href="https://techcommunity.microsoft.com/blog/post-quantum-crypto-tech-blog/asp-net-kestrel-and-schannel-ga-with-tls-1-3-post-quantum-cryptography/4536649" target="_blank" rel="noopener"&gt;here&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;We must also add a note related to SHA256: this hash algorithm is still a suitable option at the time of writing and is still used by some PQC algorithms like SLH‑DSA. The recommendation to migrate to SHA384 is aligned with Microsoft’s most recent internal guidance for PQC and is based on the need to adopt stronger algorithms offering superior security for longer.&lt;/P&gt;
&lt;H1&gt;Short, Worked Example&lt;/H1&gt;
&lt;P&gt;Some people are more visual, so let’s look at a small section of a worked example.&lt;/P&gt;
&lt;P&gt;The following diagram represents a system that accepts job requests and allows users to retrieve their status. The front-end validates each request and submits a job definition to an enterprise queue shared with other applications. The back-end retrieves and executes the job, updating a status repository that the front-end queries on behalf of the user. The job-execution logic is omitted because it is not relevant to this example.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;A threat modeler should begin by clarifying the assets and required security properties. The job definition may require confidentiality, integrity, origin authentication, authorization, and protection against replay.&lt;/P&gt;
&lt;P&gt;The status information may have similar requirements. Because the queue is shared, the threat modeler should also understand the isolation and authorization guarantees provided by the queue rather than assuming either that they are sufficient or that they are inadequate.&lt;/P&gt;
&lt;P&gt;For the enqueue and dequeue flows, initial questions might include:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Which identities do the front-end and back-end use?&lt;/LI&gt;
&lt;LI&gt;Which identities are authorized to enqueue, dequeue, or inspect messages?&lt;/LI&gt;
&lt;LI&gt;What isolation guarantees does the enterprise queue provide?&lt;/LI&gt;
&lt;LI&gt;What protocol and minimum version protect each connection?&lt;/LI&gt;
&lt;LI&gt;Which cryptographic key-establishment and authentication algorithms are negotiated?&lt;/LI&gt;
&lt;LI&gt;How does each client perform server certificate validation, including server identity, key usage, validity dates, issuer, certificate signature etc?&lt;/LI&gt;
&lt;LI&gt;Which public-key and signature algorithms are used throughout the certificate chain?&lt;/LI&gt;
&lt;LI&gt;Who owns the TLS endpoint, certificates, issuing PKI, and migration of those dependencies?&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;For the worked example, the threat model must record both the minimum protocol version and the negotiated key-establishment group.&lt;/P&gt;
&lt;P&gt;A TLS 1.3 connection is post-quantum resilient only when it uses a supported PQ or hybrid group, such as x25519_MLKEM768; the corresponding cipher-suite configuration, such as TLS_AES_256_GCM_SHA384, should also be captured.&lt;/P&gt;
&lt;P&gt;The threat modeler should then examine protection of the queued job definition. Infrastructure-level cryptography may protect the queue’s storage without necessarily providing application-specific confidentiality, integrity, origin authentication, or isolation from other authorized queue clients. Whether additional application-level protection is needed depends on the security requirements and the guarantees provided by the queue.&lt;/P&gt;
&lt;P&gt;If the back end must verify job origin independently of the queue, the design needs an appropriate authenticity mechanism. This might be a digital signature or, where the trust model permits shared secrets, a message authentication code. If confidentiality from other queue clients or operators is required, application-level cryptography may also be necessary.&lt;/P&gt;
&lt;P&gt;Once a cryptographic control is identified in the worked example, the threat modeler should record the details that are specific to that control: the algorithm and parameters, the exact content protected, the implementation provider, the message format, replay handling, separation of key purposes, algorithm and key-version metadata, quantum-vulnerability status, and required confidentiality or trust lifetime.&lt;/P&gt;
&lt;P&gt;The resulting information should be added to the cryptographic inventory together with the protected asset, security objective, implementation provider, dependency owner, quantum-vulnerability status, and migration constraints. Contradictory or incomplete answers should be investigated because they may reveal either a security weakness or a dependency that has not yet been assigned a migration owner.&lt;/P&gt;
&lt;P&gt;You might use a table like the following one to track your findings.&lt;/P&gt;
&lt;DIV class="styles_lia-table-wrapper__h6Xo9 styles_table-responsive__MW0lN"&gt;&lt;table border="1" style="border-width: 1px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Asset&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Job Definition&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Objective&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Integrity / Origin Authentication&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Algorithm&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;ECDSA P-256&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Implementation&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;OpenSSL&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Owner&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Team X&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;PQ Status&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;Vulnerable&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;
&lt;P&gt;&lt;STRONG&gt;Migration Target&lt;/STRONG&gt;&lt;/P&gt;
&lt;/td&gt;&lt;td&gt;
&lt;P&gt;ML-DSA&lt;/P&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;colgroup&gt;&lt;col style="width: 50.00%" /&gt;&lt;col style="width: 50.00%" /&gt;&lt;/colgroup&gt;&lt;/table&gt;&lt;/DIV&gt;
&lt;H1&gt;A Note on PaaS&lt;/H1&gt;
&lt;P&gt;If your solution uses PaaS components like Azure SQL DB, Azure Front Door, Azure Storage and you are relying on their security features, then the implementation and operation of PQC-capable cryptography is generally the responsibility of the provider under the Shared Responsibility Model, although customers remain responsible for understanding their dependencies and adopting platform capabilities where required. Your own client-side platforms should embrace crypto-agility so they can move to new crypto algorithms as needed in case algorithms show weakness over time. You can read more about crypto-agility &lt;A href="https://techcommunity.microsoft.com/blog/post-quantum-crypto-tech-blog/post-quantum-cryptography-and-crypto-agility/4530365" target="_blank" rel="noopener"&gt;here&lt;/A&gt;.&lt;/P&gt;
&lt;H1&gt;Summary&lt;/H1&gt;
&lt;P&gt;PQC readiness begins with knowing where cryptography is used, what it protects, who owns it, and which dependencies constrain its replacement with PQC algorithms. Threat modeling complements automated discovery and code analysis by exposing design-level controls, trust relationships, and assumptions that those techniques can miss. Feeding these findings into a maintained cryptographic inventory helps organizations identify migration risks earlier and adapt their systems with greater confidence.&lt;/P&gt;
&lt;H1&gt;Thanks&lt;/H1&gt;
&lt;P&gt;We’d like to thank the following for their review and comments on this post:&lt;/P&gt;
&lt;P&gt;-&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Jack Richins – Microsoft PQC team&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 13 Aug 2026 20:02:59 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/post-quantum-crypto-tech-blog/threat-modeling-and-post-quantum-cryptography/ba-p/4546832</guid>
      <dc:creator>MichaelHoward-MSFT</dc:creator>
      <dc:date>2026-08-13T20:02:59Z</dc:date>
    </item>
    <item>
      <title>Azure Key Vault Premium and AES-KW Post Quantum Resistant Key Wrapping in Public Preview</title>
      <link>https://techcommunity.microsoft.com/t5/post-quantum-crypto-tech-blog/azure-key-vault-premium-and-aes-kw-post-quantum-resistant-key/ba-p/4544358</link>
      <description>&lt;H1&gt;Introduction&lt;/H1&gt;
&lt;P&gt;Post-quantum cryptography, like any cryptographic system, depends on strong foundational components.&lt;/P&gt;
&lt;P&gt;Key management is one of those critical foundations.&lt;/P&gt;
&lt;P&gt;Azure Key Vault is Azure’s most popular key-management service, and Azure Key Vault Premium now supports quantum-resistant AES key wrapping (AES-KW) in Public Preview.&lt;/P&gt;
&lt;P&gt;AES-KW lets services replace quantum-vulnerable RSA key wrapping with a quantum-resistant alternative.&lt;/P&gt;
&lt;P&gt;For most readers, that is the key takeaway; you can read the announcement &lt;A href="https://azure.microsoft.com/en-us/updates/?id=566746" target="_blank" rel="noopener"&gt;update here&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;For people who want to learn more, keep going!&lt;/P&gt;
&lt;H1&gt;Key-wrapping&lt;/H1&gt;
&lt;P&gt;Ok, let’s back up a little now that we have the core message out of the way!&lt;/P&gt;
&lt;P&gt;Azure Key Vault offers the following services:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Key/Secret/Certificate management&lt;/LI&gt;
&lt;LI&gt;Encryption and decryption&lt;/LI&gt;
&lt;LI&gt;Signing and signature verification&lt;/LI&gt;
&lt;LI&gt;Key-wrapping and unwrapping&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;For the purposes of this post, we will focus only on the last bullet – Key-wrapping.&lt;/P&gt;
&lt;P&gt;Key-wrapping is simply the process of protecting one cryptographic key by encrypting it with another key. The key doing the protecting is commonly called a key-encryption key (KEK), while the protected result is called a wrapped key, and is often used as a data-encryption-key (DEK) – it is that final DEK that performs the bulk data encryption.&lt;/P&gt;
&lt;P&gt;Wrapping is encryption, but the term more precisely describes its purpose: protecting one key with another.&lt;/P&gt;
&lt;P&gt;A good example of key wrapping is &lt;A href="https://learn.microsoft.com/en-us/azure/azure-sql/database/transparent-data-encryption-tde-overview?view=azuresql&amp;amp;tabs=azure-portal" target="_blank" rel="noopener"&gt;Transparent Data Encryption&lt;/A&gt; (TDE) in Azure SQL DB and SQL Server. TDE uses a KEK to protect (wrap) a DEK that is used to perform the low-level, high-speed encryption and decryption of data on disk, as noted in the image below.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Historically, and commonly, the KEK is an RSA key, and RSA is used to wrap and unwrap the DEK, which is usually AES today. The problem lies with the RSA KEK; RSA breaks in a post-quantum world because of Shor’s Algorithm, so RSA must be replaced by a quantum-resistant algorithm, and AES Key Wrap (AES-KW) is a solution.&lt;/P&gt;
&lt;P&gt;Note, AES-KW is nothing more than a standardized way to use AES to wrap keys, it is defined in &lt;A href="https://www.rfc-editor.org/info/rfc3394/" target="_blank" rel="noopener"&gt;RFC 3394&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;AES-KW can support quantum-resistant key management when used with appropriately sized AES keys and sound operational controls.&lt;/P&gt;
&lt;P&gt;For this scenario, use AES-256 to provide an appropriate post-quantum security margin; AES-128 is not recommended.&lt;/P&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;&lt;STRONG&gt;Sidebar: &lt;/STRONG&gt;Shor’s algorithm breaks today’s public-key cryptography (RSA, Elliptic Curve, Diffie-Hellman); Grover’s algorithm weakens symmetric cryptography (AES, SHA-2).&lt;/P&gt;
&lt;P&gt;Applications use key-wrapping when they need to store or transport key material without exposing the plaintext key. During wrapping, the KEK transforms the key into protected key material. During unwrapping, the same KEK reverses that operation and returns the original key.&lt;/P&gt;
&lt;P&gt;The change is to switch out the KEK from RSA to use AES-KW. The existing DEK can remain unchanged, so the encrypted data - such as TDE-protected data - does not need to be decrypted and re-encrypted. Only the DEK is unwrapped with the RSA KEK and then rewrapped with AES-KW.&lt;/P&gt;
&lt;P&gt;You may rotate the DEK separately if desired, but this migration does not require it.&lt;/P&gt;
&lt;P&gt;The process looks like this:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I have been a little more precise (to keep the cryptographers happy) in the diagram! When wrapping keys with RSA (or any other wrapping mechanism), you use a padding and encoding scheme; in this case we use RSA Optimal Asymmetric Encryption Padding (OAEP) which adds randomness to the plaintext before encryption, ensuring that the same plaintext produces different ciphertexts each time; the ‘256’ part in OAEP-256 is a SHA256 hash used to provide randomness.&lt;/P&gt;
&lt;P&gt;Let’s get back on track.&lt;/P&gt;
&lt;H1&gt;Azure Key Vault and AES-KW&lt;/H1&gt;
&lt;P&gt;AKV now supports AES key wrapping (AES-KW) in Public Preview, providing a quantum-resistant alternative to the RSA-based key wrapping previously available. RSA could be broken by a Cryptographically Relevant Quantum Computer (CRQC).&lt;/P&gt;
&lt;P&gt;This is a big deal, because AKV is used by just about every application running on Azure to protect secrets and keys, and will allow services to become more post-Quantum resilient when protecting data at rest.&lt;/P&gt;
&lt;P&gt;For Post-Quantum protection of data on the wire, services must use TLS 1.3 with hybrid groups, see my&amp;nbsp;&lt;A href="https://techcommunity.microsoft.com/blog/post-quantum-crypto-tech-blog/asp-net-kestrel-and-schannel-ga-with-tls-1-3-post-quantum-cryptography/4536649" target="_blank" rel="noopener"&gt;previous post&lt;/A&gt; on this topic.&amp;nbsp;&lt;/P&gt;
&lt;H2&gt;It’s not a good blog post without some code!&lt;/H2&gt;
&lt;P&gt;So, let’s look at some simple code that uses AKV and AES-KW to protect an AES-256 key.&lt;/P&gt;
&lt;LI-CODE lang="csharp"&gt;async Task&amp;lt;WrapResult&amp;gt; GetWrappedKey()
{
    AzureKeyVaultSettings settings = await LoadAzureKeyVaultSettingsAsync();
    CryptoPolicy policy = CryptoPolicy.ResolveForEncryption(settings.KeyWrapAlgorithm);
    var credential = new DefaultAzureCredential();
    var keyClient = new KeyClient(settings.Uri, credential);
    KeyVaultKey wrappingKey = await keyClient.GetKeyAsync(settings.WrappingKeyName);
    var cryptoClient = new CryptographyClient(wrappingKey.Id, credential);
    byte[] aesKey = RandomNumberGenerator.GetBytes(settings.KeySizeBytes);

    try
    {
        return await cryptoClient.WrapKeyAsync(policy.KeyWrapAlgorithm, aesKey);
    }
    finally
    {
        CryptographicOperations.ZeroMemory(aesKey);
    }
}
&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This code requires a little explaining because there is no reference to any crypto settings! This is to support crypto-agility. All the config is resolved by LoadAzureKeyVaultSettingsAsync() and ResolveForEncryption() and the settings are pulled from an appsettings,json file:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;LI-CODE lang="json"&gt;{
  "AzureKeyVault": {
    "Uri": "https://akv-&amp;lt;snip&amp;gt;-tst.vault.azure.net/",
    "WrappingKeyName": "key-wrapping-key",
    "KeySizeBytes": 32,
    "KeyWrapAlgorithm": "A256KW"
  }
}
&lt;/LI-CODE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;These settings can change if needed depending on your DEK key size and key wrap algorithm.&lt;/P&gt;
&lt;P&gt;DefaultAzureCredential(), KeyClient(), GetKeyAsync() and CryptographyClient() are the standard ceremony to set up a connection to AKV to use keys. RandomNumberGenerator.GetBytes() creates a new random 32-byte AES key and WrapKeyAsync() wraps the newly minted AES key in AKV.&lt;/P&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;&lt;STRONG&gt;Note &lt;/STRONG&gt;Be careful with&amp;nbsp;&lt;A href="https://learn.microsoft.com/en-us/dotnet/api/azure.identity.defaultazurecredential?view=azure-dotnet" target="_blank" rel="noopener"&gt;DefaultAzureCredential&lt;/A&gt;() as it runs through multiple ways to gather your Azure logon credentials and this can be time consuming!&lt;/P&gt;
&lt;P&gt;The function returns a wrapped AES key wrapped with AES256KW; you can now save that key safely with your application!&lt;/P&gt;
&lt;P&gt;To unwrap the AES key, just pass the wrapped key to:&lt;/P&gt;
&lt;LI-CODE lang="csharp"&gt;UnwrapResult unwrapResult = await cryptoClient.UnwrapKeyAsync(
      policy.KeyWrapAlgorithm,
      wrapResult.EncryptedKey);
&lt;/LI-CODE&gt;
&lt;P&gt;Now you have the plaintext AES key, the DEK, and you can encrypt and decrypt your data.&lt;/P&gt;
&lt;P&gt;The flow looks a little like this:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;img /&gt;
&lt;H1&gt;A note on RBAC&lt;/H1&gt;
&lt;P&gt;Like other Azure services, Azure Key Vault supports role-based access control (RBAC) for both control-plane and data-plane operations. Although key wrapping is conceptually similar to encrypting a DEK, the &lt;A href="https://learn.microsoft.com/en-us/rest/api/keyvault/" target="_blank" rel="noopener"&gt;REST&lt;/A&gt; API exposes wrapKey and encrypt as separate operations. This distinction allows permissions to be granted independently - for example, an identity can be authorized to wrap keys without receiving broader cryptographic permissions.&lt;/P&gt;
&lt;P&gt;Use least-privilege access policies and audit them regularly.&lt;/P&gt;
&lt;H1&gt;What is oct-HSM?&lt;/H1&gt;
&lt;P&gt;When working with AES keys in AKV and Managed HSM you will see the term oct-HSM. What is it?&lt;/P&gt;
&lt;P&gt;If you dump key metadata using code like this:&lt;/P&gt;
&lt;LI-CODE lang="csharp"&gt;using Azure.Identity;
using Azure.Security.KeyVault.Keys;

var keyVaultUrl = "https://akv-&amp;lt;snip&amp;gt;-tst.vault.azure.net/";
var client = new KeyClient(new Uri(keyVaultUrl), new DefaultAzureCredential());
await foreach (var keyProperties in client.GetPropertiesOfKeysAsync()) {
    var key = (await client.GetKeyAsync(keyProperties.Name)).Value;
    Console.WriteLine($"Name: {key.Name}");
    Console.WriteLine($"Type: {key.KeyType}");
}
&lt;/LI-CODE&gt;
&lt;P&gt;you will see output like this:&lt;/P&gt;
&lt;LI-CODE lang="markdown"&gt;Name: key-wrapping-key
Type: oct-HSM&lt;/LI-CODE&gt;
&lt;P&gt;And there it is – ‘oct-HSM’, it means:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;oct for Octet string, or a series of 8-bit values.&lt;/LI&gt;
&lt;LI&gt;HSM because it's an HSM key.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;It is the object data type, oct-HSM simply means it's a symmetric key of a length (in bits) divisible by 8 because it is byte aligned. The term ‘octet’ is used extensively in standards documentation such as Distinguished Encoding Rules (DER) which is used by X.509 certificates.&lt;/P&gt;
&lt;H1&gt;Azure Portal UI&lt;/H1&gt;
&lt;P&gt;The UI updates that reflect AES-KW are in flight and you might not see the updates yet! Programmatic, JSON, ARM and Bicep config all work, however.&lt;/P&gt;
&lt;H1&gt;What about Managed HSM?&lt;/H1&gt;
&lt;P&gt;&lt;A href="https://learn.microsoft.com/en-us/azure/key-vault/managed-hsm/overview" target="_blank" rel="noopener"&gt;Azure Key Vault Managed HSM&lt;/A&gt; is Azure Key Vault’s significantly bigger brother and has supported AES key wrapping since inception.&lt;/P&gt;
&lt;P&gt;The main difference between AKV and Managed HSM is tenancy and scope: AKV is a multitenant service that manages keys, secrets, and certificates, while Managed HSM provides a dedicated single-tenant HSM for cryptographic keys only, with stronger isolation and customer-controlled administration for high-value or compliance-sensitive workloads.&lt;/P&gt;
&lt;P&gt;Client code to wrap and unwrap keys is the same across both services; you only need to update the URI to point to your AKV or Managed HSM instance.&lt;/P&gt;
&lt;P&gt;Pieter Vanhove wrote about using Managed HSM for TDE key-wrapping in this blog post &lt;A href="https://techcommunity.microsoft.com/blog/azuresqlblog/transparent-data-encryption-in-azure-sql-database-now-supports-aes-keys-public-p/4523240" target="_blank"&gt;Transparent data encryption in Azure SQL Database now supports AES keys (Public Preview) | Microsoft Community Hub&lt;/A&gt; and he will need to update it to include AKV now!&lt;/P&gt;
&lt;H1&gt;But wait, there is more!&lt;/H1&gt;
&lt;P&gt;AKV now supports AES encryption and decryption in addition to AES key wrapping, capabilities that have long been available in Managed HSM. However, neither AKV nor Managed HSM is intended for encrypting or decrypting large volumes of data; use these operations only for small payloads. I may explore AES encryption and decryption in a future post-let me know if that would be useful.&lt;/P&gt;
&lt;H1&gt;Thanks&lt;/H1&gt;
&lt;P&gt;A big ‘Thank you’ to the following for their review, suggestions and comments.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Jack Richins – Azure Security&lt;/LI&gt;
&lt;LI&gt;Pieter Vanhove – Azure Data&lt;/LI&gt;
&lt;LI&gt;Dan Bullock – Azure Data&lt;/LI&gt;
&lt;LI&gt;Raul Garcia – Microsoft Crypto Board&lt;/LI&gt;
&lt;/UL&gt;</description>
      <pubDate>Wed, 05 Aug 2026 14:41:52 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/post-quantum-crypto-tech-blog/azure-key-vault-premium-and-aes-kw-post-quantum-resistant-key/ba-p/4544358</guid>
      <dc:creator>MichaelHoward-MSFT</dc:creator>
      <dc:date>2026-08-05T14:41:52Z</dc:date>
    </item>
    <item>
      <title>ASP.NET, Kestrel and Schannel GA with TLS 1.3 Post-Quantum Cryptography</title>
      <link>https://techcommunity.microsoft.com/t5/post-quantum-crypto-tech-blog/asp-net-kestrel-and-schannel-ga-with-tls-1-3-post-quantum/ba-p/4536649</link>
      <description>&lt;H1&gt;IMPORTANT&lt;/H1&gt;
&lt;P&gt;Before I get to the body of this post, there is an important update you must be aware of:&lt;/P&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;My colleague, Aabha Thipsay from Windows Security has published an update to her June post on PQC in Windows. Hybrid TLS using ML-KEM key exchange groups is now generally available (GA) in Windows 11 and Windows Server 2025. This allows TLS connections to combine classical and post-quantum key establishment mechanisms, providing cryptographic agility and protection against future quantum-enabled attacks.&amp;nbsp;&lt;/P&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;Read more, including the update details &lt;A class="lia-internal-link lia-internal-url lia-internal-url-content-type-blog" href="https://techcommunity.microsoft.com/blog/microsoft-security-blog/new-windows-features-to-secure-today%E2%80%99s-data-in-a-post-quantum-world/4523370" data-lia-auto-title="here" data-lia-auto-title-active="0" target="_blank"&gt;here&lt;/A&gt;.&amp;nbsp;&lt;/P&gt;
&lt;H1&gt;Introduction&lt;/H1&gt;
&lt;P&gt;All organizations &lt;STRONG&gt;&lt;U&gt;must&lt;/U&gt;&lt;/STRONG&gt; move to TLS 1.3 to support post-quantum cryptography (PQC) for network data.&lt;/P&gt;
&lt;P&gt;Prior versions of TLS, such as 1.0, 1.1 and 1.2 DO NOT support and WILL NOT support PQC. TLS 1.0 and 1.1 are already deprecated, and 1.2 will eventually go the same fate, too.&lt;/P&gt;
&lt;P&gt;Also note that TLS 1.0 and 1.1 are officially deprecated by the IETF via &lt;A href="https://datatracker.ietf.org/doc/rfc8996/" target="_blank" rel="noopener"&gt;RFC 8996&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;The security technology most used to protect (encryption and integrity checks) data on the wire is TLS, which is so pervasive that almost nothing else is used to authenticate servers (and optionally authenticate clients) and then provide encryption and integrity protection for network traffic.&lt;/P&gt;
&lt;P&gt;To be honest, in a distant 2&lt;SUP&gt;nd&lt;/SUP&gt; lies SSH.&lt;/P&gt;
&lt;P&gt;The beauty of TLS is that it supports crypto-agility (see my previous post &lt;A class="lia-internal-link lia-internal-url lia-internal-url-content-type-blog" href="https://techcommunity.microsoft.com/blog/post-quantum-crypto-tech-blog/post-quantum-cryptography-and-crypto-agility/4530365" data-lia-auto-title="here" data-lia-auto-title-active="0" target="_blank"&gt;here&lt;/A&gt;) by design by allowing a server and client to negotiate to a mutually agreed-upon ciphersuite.&lt;/P&gt;
&lt;P&gt;Note that this blog post focuses on Windows, I will write a follow-up post about Linux, OpenSSL, and nginx.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;If you are happy with that level of detail, and you don’t need to understand how TLS supports PQC and crypto-agility, then jump straight to the section below titled ‘ASP.NET and Kestrel’ where I explain using hybrid TLS 1.3 with ASP.NET and the Kestrel web server.&lt;/P&gt;
&lt;P&gt;From here on, all references to TLS are TLS 1.3 and later.&lt;/P&gt;
&lt;H1&gt;TLS 1.3 and Crypto-Agility&lt;/H1&gt;
&lt;P&gt;The diagram and text below explain how TLS negotiates to a mutually agreed-upon ciphersuite and hence supports crypto-agility.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;The client (such as a web browser) sends a list of its supported ciphersuites in a ClientHello message to the server which is the first message sent by the client during a TLS negotiation.&lt;/P&gt;
&lt;P&gt;The server selects which ciphersuite to use and that is sent back in the ServerHello message.&lt;/P&gt;
&lt;P&gt;Here both the client and server list contain TLS_AES_256_GCM_SHA384, and since it sits at the top of the server's list, the server selects it even though TLS_AES_128_GCM_SHA256 was first in the client list.&lt;/P&gt;
&lt;P&gt;Note that &lt;A href="https://www.rfc-editor.org/rfc/rfc8446" target="_blank" rel="noopener"&gt;RFC 8446&lt;/A&gt; “The Transport Layer Security (TLS) Protocol Version 1.3” §4.1.1 leaves the selection algorithm to the server. The client's list order is a hint, but most production servers ignore it and walk their own preference list top-down - picking the first entry that also appears in the client's offering.&lt;/P&gt;
&lt;P&gt;If there were zero overlap between the client and server ciphersuite lists, the server would usually send a handshake_failure alert (40) and tear down the connection.&lt;/P&gt;
&lt;H2 class="lia-indent-padding-left-30px"&gt;Important sidenote about TLS 1.3 ciphersuite strings&lt;/H2&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;TLS 1.3 cleaned up the ciphersuite strings substantially from prior versions. In TLS 1.2 and earlier, a single ciphersuite name bundled together multiple concerns: the key exchange algorithm, the authentication algorithm, the bulk encryption algorithm, and the hash or message authentication function. That made the names more difficult to reason about and more rigid.&lt;/P&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;TLS 1.3 simplified this model by reducing the ciphersuite to just the symmetric encryption and hash components, such as TLS_AES_256_GCM_SHA384.&lt;/P&gt;
&lt;H1&gt;TLS 1.3, ciphersuites, groups and PQC&lt;/H1&gt;
&lt;P&gt;TLS key exchange, establishment or agreement is negotiated separately through the supported_groups and key_share TLS extensions, and authentication is handled through the signature_algorithms TLS extension.&lt;/P&gt;
&lt;P&gt;This separation is important because it makes the protocol easier to evolve, new key exchange mechanisms can be introduced, including post-quantum or hybrid key establishment methods, without having to redefine the entire ciphersuite structure.&lt;/P&gt;
&lt;H2 class="lia-indent-padding-left-30px"&gt;Important&lt;/H2&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;From a PQC perspective, the ciphersuites used by TLS 1.3 are largely unchanged, it's the supported groups we care about most.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;In TLS 1.3, the ClientHello message uses supported_groups, key_share and signature_algorithms extensions to add PQC algorithms. I want to keep this simplified so the post doesn’t become a treatise on TLS 1.3, so I will elide many details!&lt;/P&gt;
&lt;P&gt;When using hybrid (ie; PQC + classic crypto) the supported_groups and key_share data structures might look something like this:&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;The supported_groups order is a preference, highest first, and most commonly today, hybrids (PQC + classical) are at the top, then classic groups below as a fallback for servers that don't yet speak PQC. As an optimization, the client also sends a key_share for its top choice in the same ClientHello — the actual ephemeral public keys — so that if the server accepts that group, the handshake completes in one round trip rather than triggering a HelloRetryRequest and a second one.&lt;/P&gt;
&lt;P&gt;In this example, the client is saying "I'd really like to use hybrid crypto, but I'll downgrade to plain X25519 or secp256r1 if you can't." And it doesn't just say it - and as an optimization, the client sends a key_share, pre-generating and attaching the ephemeral public keys for its top pick (X25519MLKEM768) so the handshake can finish in one round trip if the server agrees. The fallback groups are listed but not pre-computed, so falling back to one of them costs an extra round trip.&lt;/P&gt;
&lt;P&gt;The key_share sizes in the diagram show the hybrid is just two key exchanges glued together: the client's 1216-byte share is a 32-byte X25519 public key plus a 1184-byte ML-KEM-768 key. The server's reply is a slightly different size because the ML-KEM half returns a ciphertext rather than a matching public key.&lt;/P&gt;
&lt;P&gt;It is up to the server to determine what algorithms to use, however. We know what the client can support, because the client told us in the ClientHello message.&lt;/P&gt;
&lt;P class="lia-indent-padding-left-30px"&gt;As a side note, the word "group" isn't arbitrary - it comes from the underlying algebra (elliptic-curve groups, finite-field multiplicative groups). It's mathematically precise; but it's just opaque to anyone who isn't thinking about group theory! However, ML-KEM isn't built on a group at all - its hardness comes, in part, from lattices, but let’s not go down that rabbit hole!&lt;/P&gt;
&lt;P&gt;Now let’s switch to why we are here – ASP.NET, Kestrel and PQC.&lt;/P&gt;
&lt;H1&gt;ASP.NET and Kestrel&lt;/H1&gt;
&lt;P&gt;ASP.NET is Microsoft's open-source web framework for building web apps, APIs, and real-time services on .NET.&lt;/P&gt;
&lt;P&gt;Kestrel is the cross-platform, high-performance HTTP[S] server built into .NET that handles raw TCP connections and HTTP protocol processing.&lt;/P&gt;
&lt;P&gt;ASP.NET and Kestrel relate in that Kestrel is the default in-process web server that listens for and handles HTTP requests for an ASP.NET.&lt;/P&gt;
&lt;P&gt;Below is some minimal C# Kestrel code that listens for HTTPS connections:&lt;/P&gt;
&lt;LI-CODE lang="csharp"&gt;using System.Net;
using Microsoft.AspNetCore.Connections.Features;

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(o =&amp;gt; o.ListenAnyIP(8443, l =&amp;gt; l.UseHttps()));
var app = builder.Build();

app.MapGet("/", (HttpContext ctx) =&amp;gt;
{
    var tls = ctx.Features.Get&amp;lt;ITlsHandshakeFeature&amp;gt;();
    return Results.Json(new
    {
        Timestamp = DateTime.UtcNow,
        Protocol = tls?.Protocol.ToString() ?? "Unknown",
        CipherSuite = tls?.NegotiatedCipherSuite?.ToString() ?? "Unknown"
    });
});
app.Run();&lt;/LI-CODE&gt;
&lt;P&gt;This code is correctly written because it makes no assertions about TLS protocol version, nor ciphersuites, nor groups. Rather, these settings are made outside the application is some form of configuration.&lt;/P&gt;
&lt;P&gt;The anti-pattern to the code above is this:&lt;/P&gt;
&lt;LI-CODE lang="csharp"&gt;var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(o =&amp;gt; o.ListenAnyIP(8443, l =&amp;gt; l.UseHttps(h =&amp;gt;
{
    h.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13;
    h.OnAuthenticate = (_, sslOptions) =&amp;gt;
    {
        sslOptions.CipherSuitesPolicy = new CipherSuitesPolicy(new[]
        {
            TlsCipherSuite.TLS_AES_256_GCM_SHA384,
            TlsCipherSuite.TLS_AES_128_GCM_SHA256,
            TlsCipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
        });
    };
})));
var app = builder.Build();
&lt;/LI-CODE&gt;
&lt;P&gt;This code is NOT crypto-agile and should be considered an anti-pattern because it embeds cryptographic details like TLS protocol versions and ciphersuites in the code, and if any of these must change in the future then the code needs updating, too. This code will not necessarily negotiate to a PQC connection.&lt;/P&gt;
&lt;P&gt;Note: CipherSuitesPolicy is Linux-only. On Windows/macOS the constructor throws PlatformNotSupportedException - ciphersuites on those platforms are governed by the OS (SChannel on Windows). The TLS protocol restriction works cross-platform, however.&lt;/P&gt;
&lt;P&gt;And that is a nice segue to SChannel!&lt;/P&gt;
&lt;H1&gt;Schannel Configuration on Windows&lt;/H1&gt;
&lt;P&gt;Windows uses a component named schannel.dll to perform TLS communication. Today, July 14th, 2026, schannel is GA with PQC support, see the note about Aabha's update on the topic.&amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Even though this version supports TLS hybrid groups today, the PQC groups are not enabled by default, so you must set them up.&lt;/P&gt;
&lt;H2&gt;Setting up Schannel&lt;/H2&gt;
&lt;P&gt;There are three main ways to configure schannel:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Modify the Registry directly&lt;/LI&gt;
&lt;LI&gt;Use Group Policy&lt;/LI&gt;
&lt;LI&gt;Use PowerShell cmdlets&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;We will focus on (3), but ultimately, all methods directly or indirectly update the Registry.&lt;/P&gt;
&lt;P&gt;Use the following &lt;A href="https://learn.microsoft.com/en-us/powershell/module/tls/?view=windowsserver2025-ps" target="_blank" rel="noopener"&gt;site &lt;/A&gt;as a reference for the various PowerShell TLS cmdlets.&lt;/P&gt;
&lt;P&gt;Get-TlsCipherSuite dumps all the supported ciphersuites irrespective of TLS protocol version. You can disable a ciphersuite using Disable-TlsCipherSuite.&lt;/P&gt;
&lt;P&gt;What we’re interested in is setting up a group for PQC, and for that we use:&lt;/P&gt;
&lt;LI-CODE lang="powershell"&gt;Enable-TlsEccCurve -Name "X25519_MLKEM768" -Position 0&lt;/LI-CODE&gt;
&lt;P&gt;The -position option is &lt;STRONG&gt;important&lt;/STRONG&gt; as it places the hybrid group at the top of the preferred group list. If you do not do this, you might not negotiate to the hybrid PQC group.&lt;/P&gt;
&lt;P&gt;You can use Get-TlsEccCurve to verify the setting, as noted below:&lt;/P&gt;
&lt;LI-CODE lang=""&gt;x25519_mlkem768
curve25519
NistP256
NistP384&lt;/LI-CODE&gt;
&lt;P&gt;Now that we have set the group, we can run the server code and connect with a browser such as Edge or Chrome. When you do this, you can see the connection details under Developer Tools à Security.&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;This shows the protocol version (TLS 1.3), the group (X25519MLKEM768) and the ciphersuite (AES_256_GCM).&lt;/P&gt;
&lt;H4 class="lia-indent-padding-left-30px"&gt;&lt;STRONG&gt;Congratulations&lt;/STRONG&gt;, you just connected to Kestrel or ASP.NET using a quantum resilient group! You are officially living in the future!&lt;/H4&gt;
&lt;P&gt;You can also use OpenSSL as a client to determine the group:&lt;/P&gt;
&lt;LI-CODE lang=""&gt;openssl s_client -connect 127.0.0.1:8443 -tls1_3 -brief
Connecting to 127.0.0.1
depth=0 CN=localhost
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Peer certificate: CN=localhost
Hash used: SHA256
Signature type: rsa_pss_rsae_sha256
Negotiated TLS1.3 group: X25519MLKEM768
&lt;/LI-CODE&gt;
&lt;H1&gt;A note about server authentication&lt;/H1&gt;
&lt;P&gt;It’s important I bring this up. The key negotiation process used post-quantum cryptography, but the server authentication used a classic certificate. That's by design for now: the immediate goal is encrypting data on the wire to defend against harvest-now, decrypt-later attacks, where an adversary records traffic today hoping to decrypt it once quantum computers mature. Authentication is a different threat model - an attacker would need a quantum computer during the live session to forge the certificate, not years later. So, protecting confidentiality first, with PQC key exchange, addresses the more&amp;nbsp;urgent risk while the ecosystem catches up on PQC certificates and CA migration.&lt;/P&gt;
&lt;H1&gt;Wrap-up&lt;/H1&gt;
&lt;P&gt;Post-quantum TLS 1.3 is no longer theoretical — you can experiment with it on Windows today. By moving your services to TLS 1.3, avoiding hard-coded cryptographic choices in application code, and letting SChannel negotiate hybrid groups such as X25519MLKEM768, you can start validating how ASP.NET and Kestrel behave in a quantum-resilient configuration. If you build or operate services on Windows, now is the time to get the latest Windows Insider or preview build, enable the hybrid TLS group, run your Kestrel workloads, and inspect the negotiated connection. The best way to prepare for post-quantum cryptography is to start testing it now.&lt;/P&gt;
&lt;H1&gt;Thanks&lt;/H1&gt;
&lt;P&gt;As usual, a big thanks to all the people who reviewed the drafts of this post and provided valuable input and feedback.&lt;/P&gt;
&lt;P&gt;Aabha Thipsay - Windows Security&lt;/P&gt;
&lt;P&gt;Jessica Krynitsky - Windows Security&lt;/P&gt;
&lt;P&gt;Andrei Popov - Window Security&lt;/P&gt;
&lt;P&gt;Barry Dorrans - .NET Security&lt;/P&gt;
&lt;P&gt;Jeremy Barton - .NET Security&lt;/P&gt;
&lt;P&gt;Raul Garcia – Microsoft Crypto Board&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 14 Jul 2026 19:06:42 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/post-quantum-crypto-tech-blog/asp-net-kestrel-and-schannel-ga-with-tls-1-3-post-quantum/ba-p/4536649</guid>
      <dc:creator>MichaelHoward-MSFT</dc:creator>
      <dc:date>2026-07-14T19:06:42Z</dc:date>
    </item>
    <item>
      <title>Post-Quantum Cryptography and Crypto-Agility</title>
      <link>https://techcommunity.microsoft.com/t5/post-quantum-crypto-tech-blog/post-quantum-cryptography-and-crypto-agility/ba-p/4530365</link>
      <description>&lt;H1&gt;Introduction&lt;/H1&gt;
&lt;P&gt;This post focuses on a topic critical to help move to post-quantum cryptographic (PQC) algorithms and that topic is crypto-agility for applications that use cryptography.&lt;/P&gt;
&lt;P&gt;This post does not discuss the implications of quantum computers on cryptography; you can read that elsewhere such as:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A class="lia-external-url" href="https://www.nist.gov/cybersecurity-and-privacy/what-post-quantum-cryptography" target="_blank" rel="noopener"&gt;What Is Post-Quantum Cryptography? | NIST&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A class="lia-external-url" href="https://www.ssh.com/academy/how-quantum-computing-threats-impact-cryptography-and-cybersecurity" target="_blank" rel="noopener"&gt;How Quantum Computing Threats Impact Cryptography and Cybersecurity&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A class="lia-external-url" href="https://www.philadelphiafed.org/the-economy/banking-and-financial-markets/how-quantum-computing-threatens-cryptography" target="_blank" rel="noopener"&gt;How Quantum Computing Threatens Cryptography&lt;/A&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H1&gt;What is Crypto-Agility?&lt;/H1&gt;
&lt;P&gt;As &lt;A class="lia-external-url" href="https://csrc.nist.gov/projects/crypto-agility" target="_blank" rel="noopener"&gt;NIST&lt;/A&gt; explains, crypto-agility is about changing cryptographic algorithms without interrupting the flow of a running system, which is exactly why it is foundational to long-term resilience in the PQC era.&lt;/P&gt;
&lt;P&gt;However, crypto-agility is not simply the ability to swap one algorithm for another; it is the engineering discipline of designing protocols, applications, services, and infrastructure so cryptographic mechanisms can be updated repeatedly, safely, and with minimal disruption. In practical terms, that means avoiding hard-coded algorithm choices, understanding where cryptography is used, and building abstraction, configuration, and testing into systems so transitions—such as the move to post-quantum cryptography—do not become expensive, brittle, one-time rewrites.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Note&lt;/STRONG&gt;: This post assumes you know how to build a correct cryptographic system, if you do not, you should not, rather you should seek help from cryptographic professionals.&lt;/P&gt;
&lt;H1&gt;The Need for Crypto-Agility NOW&lt;/H1&gt;
&lt;P&gt;The industry has known for at least 15 years that crypto-agility is a solid engineering practice, but sadly, few products support it for their own crypto. The looming threat from PQC makes crypto-agility not just a good idea, but an important forcing function – everyone designing and developing applications must move to use crypto-agility to help migrate to PQC and beyond.&lt;/P&gt;
&lt;P&gt;The main threat posed by quantum computers is the potential to break asymmetric algorithms like RSA, Elliptic Curve and Diffie-Hellman, these algorithms are used extensively to:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Wrap, exchange, or agree-upon symmetric encryption keys that are then used to bulk encrypt data&lt;/LI&gt;
&lt;LI&gt;Sign data and code&lt;/LI&gt;
&lt;LI&gt;Authenticate principals&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;We will focus primarily on the first bullet as this is an endemic problem today and it is the core of the Harvest Now, Decrypt Later (HNDL) threat.&lt;/P&gt;
&lt;H1&gt;What Makes This Post Different&lt;/H1&gt;
&lt;P&gt;There are many articles about the importance of crypto-agility, but few focus on HOW to achieve crypto-agility, and that is where this article is different, we will focus on real-world designs and coding mechanics.&lt;/P&gt;
&lt;H1&gt;Step 0 – Don’t Do Your Own Crypto Agility!&lt;/H1&gt;
&lt;P&gt;Think about the shared responsibility model, if you use Infrastructure as a Service (IaaS) you need to do more work, but you have more control.&lt;/P&gt;
&lt;P&gt;If you use Platform as a Service (PaaS) then PaaS pushes more of the responsibility to the provider, rather than you.&lt;/P&gt;
&lt;P&gt;The same applies to cryptography.&lt;/P&gt;
&lt;P&gt;Where possible, you should offload tasks like signing and encryption to a service or product you trust has a PQC plan to do the crypto work for you. For example, rather than writing your own code to encrypt backups, use a backup service that performs that task (or has plans to do so) and allows you to control the key wrapping keys.&lt;/P&gt;
&lt;P&gt;However, if you must use your own crypto, then read on!&lt;/P&gt;
&lt;H1&gt;Crypto-Agile Designs&lt;/H1&gt;
&lt;P&gt;Many applications that protect data with encryption do so without regard for the cryptography used. For example, plaintext is passed to encryption code and is then encrypted with a key, or a key derived from some key material, and then the code writes out the ciphertext.&lt;/P&gt;
&lt;P&gt;Something like this:&lt;/P&gt;
&lt;LI-CODE lang="csharp"&gt;using System.Security.Cryptography; using var aes = Aes.Create(); aes.Key = SHA256.HashData(Encoding.UTF8.GetBytes(args[1])); byte[] ciphertext = aes.EncryptEcb( await File.ReadAllBytesAsync(args[0]), PaddingMode.Zeros); await File.WriteAllBytesAsync(args[0] + ".enc", ciphertext);&lt;/LI-CODE&gt;
&lt;P&gt;This code is problematic on many fronts, including:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Encryption algorithm details are hard-coded in the core code path. This makes crypto agility impossible.&lt;/LI&gt;
&lt;LI&gt;The crypto is weak:
&lt;UL&gt;
&lt;LI&gt;Using Electronic Code Book (ECB) block cipher mode&lt;/LI&gt;
&lt;LI&gt;No data authentication&lt;/LI&gt;
&lt;LI&gt;Not using an appropriate Key Derivation Function (KDF).&amp;nbsp;&lt;/LI&gt;
&lt;LI&gt;You might also say there is no Initialization Vector (IV) but an IV is not used by ECB.&lt;/LI&gt;
&lt;/UL&gt;
&lt;/LI&gt;
&lt;LI&gt;The ciphertext is just a blob of bytes, there is no metadata to indicate how this blob was created and what cryptographic parameters are used.&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Hard-coded algorithm assumptions are a strong anti-pattern for crypto-agility and usually make safe migration to newer algorithms harder or more expensive.&lt;/P&gt;
&lt;P&gt;To be crypto-agile, a system must support new ciphersuite metadata and store that metadata with the ciphertext; there are several ways to do this.&lt;/P&gt;
&lt;H2&gt;Crypto-agility in Microsoft Products&lt;/H2&gt;
&lt;P&gt;To get a better understanding of how to create crypto-agile solutions, let’s look at how Microsoft has addressed this in some products, notably:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Microsoft Office&lt;/LI&gt;
&lt;LI&gt;SQL Server and Azure SQL DB&lt;/LI&gt;
&lt;LI&gt;Azure Blob Storage&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;There is no single crypto-agility pattern that fits every application’s needs for agility, but these should give you some ideas.&lt;/P&gt;
&lt;H3&gt;Microsoft Office&lt;/H3&gt;
&lt;P&gt;In its Open Office XML (&lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/office/open-xml/open-xml-sdk" target="_blank" rel="noopener"&gt;OOXML&lt;/A&gt;) file &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/openspecs/office_standards/ms-docx/9113c11f-7d77-4cae-8fe1-3c63cea830a4" target="_blank" rel="noopener"&gt;structure&lt;/A&gt;, Microsoft Office embeds every aspect of the &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-offcrypto/3c34d72a-1a61-4b52-a893-196f9157f083?redirectedfrom=MSDN" target="_blank" rel="noopener"&gt;crypto&lt;/A&gt; used to protect a document as metadata in the XML payload. Microsoft Office refers to this structure as Agile Encryption. OOXML is primarily a symmetric key solution, so that is all we will cover here.&lt;/P&gt;
&lt;P&gt;I have some C# code that dumps the main crypto metadata from an encrypted OOXML file, you can find it &lt;A class="lia-external-url" href="https://github.com/x509cert/OOXML/tree/main" target="_blank" rel="noopener"&gt;here&lt;/A&gt; and the output looks a little like this:&lt;/P&gt;
&lt;LI-CODE lang="textile"&gt;Key Data: saltSize : 16 blockSize : 16 keyBits : 256 hashSize : 64 cipherAlgorithm : AES cipherChaining : ChainingModeCBC hashAlgorithm : SHA512 saltValue (or IV) : ktwu3iMe57cJ0LTDJHwf7g== Password Encryptor: spinCount : 100000 saltSize : 16 blockSize : 16 keyBits : 256 hashSize : 64 cipherAlgorithm : AES cipherChaining : ChainingModeCBC hashAlgorithm : SHA512 saltValue (or IV) : p8MRLOBj/a5MOYG1tvfA/Q== encryptedVerifierHashInput : D8jQbWvjyPK8uWa1Z/0hiw== encryptedVerifierHashValue : ikHKt4eXn&amp;lt;snip&amp;gt;QsfCKVqQaawWe1celUw== encryptedKeyValue : p0lVCnKVd&amp;lt;snip&amp;gt;KrmggpYbeH69p8MBvahw=&lt;/LI-CODE&gt;
&lt;P&gt;This is enough data to create the various cryptographic objects needed to decrypt this document. Of course, this code needs to unwrap the data encryption key (DEK) using a user-provided password.&lt;/P&gt;
&lt;P&gt;Depending on the language and crypto libraries you use, you could use code like this pseudo code to decrypt data given a block of crypto-metadata:&lt;/P&gt;
&lt;LI-CODE lang=""&gt;descriptor = parse(encryption_metadata) cipherName = descriptor.cipherAlgorithm chainMode = descriptor.cipherChaining paddingMode = descriptor.padding keyBits = descriptor.keyBits blockSize = descriptor.blockSize hashName = descriptor.hashAlgorithm hashSize = descriptor.hashSize spinCount = descriptor.spinCount IV = decodeBase64(descriptor.saltValue) cipher = GetAlgFromAlgName(cipherName) hash = GetAlgFromAlgName(hashName) ) if cipher is null: fail("unsupported cipher") if hash is null: fail("unsupported hash") cipher.build(keyBits, chainMode, blockSize, paddingMode) plaintext = cipher.decrypt(ciphertext, IV, key) function GetAlgFromAlgName (name): switch name: case "AES": return new Aes() case "TripleDES": return new TripleDes() case "SHA256": return new Sha256() case "SHA384": return new Sha384() case "SHA512": return new Sha512() default: return null&lt;/LI-CODE&gt;
&lt;P&gt;This pattern works well for documents because even though the metadata is large, it’s probably smaller than the document. But it does not work so well with rows of data, such as database platforms.&lt;/P&gt;
&lt;P&gt;So, let’s look at that.&lt;/P&gt;
&lt;H3&gt;SQL Server and Azure SQL DB&lt;/H3&gt;
&lt;P&gt;SQL Server and Azure SQL DB offer a feature called &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/sql/relational-databases/security/encryption/always-encrypted-database-engine?view=sql-server-ver17" target="_blank" rel="noopener"&gt;Always Encrypted&lt;/A&gt; (AE) that also supports crypto agility, but rather than store metadata, it has a version number at the start of the ciphertext that maps to set of cryptographic primitives.&lt;/P&gt;
&lt;P&gt;Currently, SQL Server only has one version of AE, version 1, but if the SQL team added a new set of cryptographic primitives, then the version number would be bumped to 2.&lt;/P&gt;
&lt;P&gt;You can see this version number if you dump the hex-encoded ciphertext, below is an example.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Look at the first byte of each NationalIDNumber, it’s always 0x01, that’s the version number, and that maps to the following ciphersuite:&lt;/P&gt;
&lt;DIV class="lia-align-center"&gt;
&lt;H5&gt;AEAD_AES_256_CBC_HMAC_SHA_256&lt;/H5&gt;
&lt;/DIV&gt;
&lt;P&gt;Which, when translated to English means:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;AEAD — Authenticated Encryption with Associated Data: Provides both encryption (confidentiality) + authentication (integrity + authenticity) in one step. It can also protect "associated data" (e.g., metadata) that isn't encrypted.&lt;/LI&gt;
&lt;LI&gt;AES_256 — Advanced Encryption Standard with a 256-bit key (strong symmetric encryption).&lt;/LI&gt;
&lt;LI&gt;CBC — Cipher Block Chaining mode (handles padding and chaining blocks; requires an Initialization Vector/IV).&lt;/LI&gt;
&lt;LI&gt;HMAC_SHA_256 — Hash-based Message Authentication Code (MAC) using SHA-256 (provides the authentication tag/MAC).&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;This is an Encrypt-then-MAC construction: encrypt the data first, then compute a MAC over the ciphertext (plus associated plaintext data) to authenticate it.&lt;/P&gt;
&lt;P&gt;If you look at the .NET SqlClient driver &lt;A class="lia-external-url" href="https://github.com/dotnet/SqlClient/blob/4dc47c9921eda02c9fb272de686316febb75d6de/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/AlwaysEncrypted/EncryptedColumnEncryptionKeyParameters.cs#L46" target="_blank" rel="noopener"&gt;source code&lt;/A&gt;, you can see the version number is held in the AlgorithmVersion member variable, and the ciphersuite details are gated on that version number. When a new version is introduced, the code is updated to support it while continuing to read version 1 data and writing new data with the latest version, such as version 2.&lt;/P&gt;
&lt;H3&gt;Azure Blob Storage Client-side Encryption&lt;/H3&gt;
&lt;P&gt;The Azure Blob Storage client library for .NET supports &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/storage/blobs/client-side-encryption?tabs=dotnet" target="_blank" rel="noopener"&gt;encrypting&lt;/A&gt; data within client applications before uploading to Azure Storage, and decrypting data while downloading to the client. The library also supports integration with Azure Key Vault for key management.&lt;/P&gt;
&lt;P&gt;At the time of writing this, there are &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/azure/storage/blobs/client-side-encryption?tabs=dotnet#about-client-side-encryption" target="_blank" rel="noopener"&gt;two ciphersuite versions&lt;/A&gt; supported by the client library. Version 2 came into being because of a &lt;A class="lia-external-url" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-30187" target="_blank" rel="noopener"&gt;Padding Oracle vulnerability&lt;/A&gt; (read more &lt;A class="lia-internal-link lia-internal-url lia-internal-url-content-type-blog" href="https://techcommunity.microsoft.com/blog/azurestorageblog/ga-azure-storage-updating-client-side-encryption-in-sdk-to-address-security-vuln/3563013" target="_blank" rel="noopener" data-lia-auto-title="here" data-lia-auto-title-active="0"&gt;here&lt;/A&gt;) in v1, rendering v1 obsolete.&lt;/P&gt;
&lt;P&gt;Blob Storage client-side encryption supports various key wrapping mechanisms, you can learn more &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/java/api/com.azure.security.keyvault.keys.cryptography.models.keywrapalgorithm?view=azure-java-stable" target="_blank" rel="noopener"&gt;here&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;You can see how this code is managed in a crypto-agile manner by looking at the Azure SDK &lt;A class="lia-external-url" href="https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/storage/Azure.Storage.Blobs/src/BlobClientSideDecryptor.cs" target="_blank" rel="noopener"&gt;source code&lt;/A&gt;.&lt;/P&gt;
&lt;H2&gt;Post Quantum Crypto and Version Numbering&lt;/H2&gt;
&lt;P&gt;Imagine over the years, you started with a version 1 ciphersuite, then in 2020 you added a newer version 2, and finally, today with Q-Day around the corner, you want to add a version 3 that is quantum safe. &amp;nbsp;&lt;/P&gt;
&lt;P&gt;This is the pattern you might use using version numbers:&lt;/P&gt;
&lt;LI-CODE lang="csharp"&gt;public enum CryptoVersion : byte { V1 = 1, V2 = 2, V3 = 3, Latest = V3, } public static byte[] Encrypt( ReadOnlySpan&amp;lt;byte&amp;gt; plaintext, ReadOnlySpan&amp;lt;char&amp;gt; password, CryptoVersion version = CryptoVersion.Latest) { switch (version) { case CryptoVersion.V1: return EncryptV1(plaintext, password); case CryptoVersion.V2: case CryptoVersion.V3: return EncryptGcm(plaintext, password, version); default: throw new ArgumentOutOfRangeException( nameof(version), version, "Unknown crypto version."); } } public static byte[] Decrypt(ReadOnlySpan&amp;lt;byte&amp;gt; blob, ReadOnlySpan&amp;lt;char&amp;gt; password) { CryptoBlobHeader header = ParseHeader(blob); return header.Version switch { CryptoVersion.V1 =&amp;gt; DecryptV1(blob, password, header), CryptoVersion.V2 =&amp;gt; DecryptGcm(blob, password, header), CryptoVersion.V3 =&amp;gt; DecryptGcm(blob, password, header), _ =&amp;gt; throw new CryptographicException( $"Unsupported blob version {(byte)header.Version}."), }; }&lt;/LI-CODE&gt;
&lt;P&gt;This code is simple; when encrypting you pass in (or generate) appropriate cryptographic parameters and then an Encrypt method that then passes it off the correct encryption handler that varies by ciphersuite.&lt;/P&gt;
&lt;P&gt;For decrypt, the only parameter you need is the password to derive the key encryption key (KEK) that decrypts the embedded wrapped data encryption key (DEK) and the rest is read from the header metadata that is written as part of the encryption operation.&lt;/P&gt;
&lt;P&gt;Over time, if you add more ciphersuite versions, you just bump up the version number and call the Encrypt or Decrypt handler function. Easy! I have a version of this &lt;A class="lia-external-url" href="https://github.com/x509cert/CryptoAgility42" target="_blank" rel="noopener"&gt;here&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;In a future installment, I will add a v4 that also digitally signs the ciphertext blob using ML-DSA, but for the moment, V3 is quantum-safe because it uses quantum-safe symmetric algorithms and key sizes.&lt;/P&gt;
&lt;P&gt;I have left out setting the block size, key size, IV, nonce, padding mode, block cipher mode and so on, to keep the code smaller. Store all IVs, salts, and nonces alongside the ciphertext as metadata, and ensure their integrity and authenticity by including them as associated data in an AEAD (Authenticated Encryption with Associated Data) scheme. They are not encrypted, but because they are authenticated by the AEAD construction, any tampering is detected&lt;/P&gt;
&lt;P&gt;When your code reads encrypted data, it reads the version number and decrypts the data using the correct set of algorithms and configuration. When your code writes ciphertext it always uses the latest supported version. So, you could read a v1 blob, edit the data and then upon write, use v3 algorithms and settings.&lt;/P&gt;
&lt;P&gt;The ciphertext blob has a 4-byte ‘magic’ header, in this case ‘CA42’ for Crypto Agility 42. The ‘42’ is there for no specific reason. Your ‘magic’ header, if you decide to use one, is totally up to you!&lt;/P&gt;
&lt;P&gt;The ciphertext blob looks like this on disk across the various example versions:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;img /&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Versions 2 and 3 are functionally identical; the only difference is the AES key size, visible in the wrapped DEK blocks; v3 increases the symmetric key from 128-bit to 256-bit, raising the effective security margin against Grover’s algorithm.&lt;/P&gt;
&lt;P&gt;Sample code can be found &lt;A class="lia-external-url" href="https://github.com/x509cert/CryptoAgility42" target="_blank" rel="noopener"&gt;here&lt;/A&gt;.&lt;/P&gt;
&lt;H1&gt;JOSE and Crypto Agility&lt;/H1&gt;
&lt;P&gt;Another option, especially for greenfield solutions, is to use JOSE.&lt;/P&gt;
&lt;P&gt;JOSE (JSON Object Signing and Encryption) provides a strong foundation for crypto agility through its explicit separation of key wrapping (alg) and content encryption (enc) algorithm identifiers in the JWE protected header.&lt;/P&gt;
&lt;P&gt;Because algorithm selection is declarative and self-describing, migrating between cipher suites requires no structural changes to the payload format, only a header update and corresponding key material rotation.&lt;/P&gt;
&lt;P&gt;This makes JOSE well suited to versioned algorithm tiers, where each version maps cleanly to a distinct alg/enc pairing and older versions can be deprecated without breaking the envelope format.&lt;/P&gt;
&lt;P&gt;Looking ahead, the IETF JOSE working group is actively developing &lt;A href="https://datatracker.ietf.org/doc/rfc9864/" target="_blank" rel="noopener"&gt;algorithm registrations&lt;/A&gt; for post-quantum primitives - particularly ML-KEM for key encapsulation and ML-DSA for signatures - meaning the same JWE envelope structure will carry forward into a post-quantum world once those identifiers are standardized, with no changes required to parsing or storage infrastructure. Until then, implementations targeting PQC can use private x-prefixed header parameters as a forward-compatibility shim, accepting the loss of interoperability as a temporary trade-off.&lt;/P&gt;
&lt;P&gt;Here's a highly abridged JOSE serialization example using the x- shim for ML-KEM and ML-DSA:&lt;/P&gt;
&lt;LI-CODE lang="json"&gt;{ // Key wrapping: // ML-KEM-1024 (via x- private header) + HKDF-SHA-512 → AES-256-KW // Content encryption: AES-256-GCM // Signing: ML-DSA-87 (JWS wrapper — see outer envelope) "protected": { // Standard JOSE fields "enc": "A256GCM", // content encryption algorithm "alg": "A256KW", // key wrapping algorithm (KEK → DEK) "kid": "key-2024-v3", // key identifier "cty": "application/json", // content type // PQC shim — private parameters (x- prefix = non-registered, bespoke) "x-kem-alg": "ML-KEM-1024", // FIPS 203; encapsulate the KEK "x-kem-kid": "mlkem-pub-001", // recipient ML-KEM public key id "x-kdf": "HKDF-SHA-512", // derives AES-256-KW KEK from ML-KEM shared secret "x-kdf-info": "v3-kek-derive", // HKDF info string (context binding) "x-sig-alg": "ML-DSA-87", // FIPS 204; signs outer JWS envelope }&lt;/LI-CODE&gt;
&lt;H1&gt;CMS and Crypto Agility&lt;/H1&gt;
&lt;P&gt;CMS is especially relevant for PQC migration because ML-KEM use in CMS is now standardized using _KEMRecipientInfo_, allowing post-quantum key establishment to be incorporated without changing the overall CMS envelope grammar. You can read more&amp;nbsp;&lt;A class="lia-external-url" href="https://datatracker.ietf.org/doc/rfc9936/" target="_blank" rel="noopener"&gt;here&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;CMS and JOSE solve similar problems, but they use different serialization models. CMS is defined with &lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-introduction-to-asn-1-syntax-and-encoding" target="_blank" rel="noopener"&gt;ASN.1&lt;/A&gt; and is usually encoded as a compact binary structure (commonly DER, though BER is also used in some contexts), much like X.509-related formats. JOSE, by contrast, uses JSON-based serializations, often with base64url-encoded components in JWS/JWE, which usually makes it easier for developers to inspect and debug but can increase message size relative to a compact binary encoding.&lt;/P&gt;
&lt;P&gt;&lt;A class="lia-external-url" href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/distinguished-encoding-rules" target="_blank" rel="noopener"&gt;DER&lt;/A&gt; (Distinguished Encoding Rules) and BER (Basic Encoding Rules) are simply encoding rules, DER is stricter than BER.&lt;/P&gt;
&lt;H1&gt;The Fly in the Ointment – Existing code&lt;/H1&gt;
&lt;P&gt;So far, we have spoken about creating &lt;U&gt;new&lt;/U&gt; systems that use crypto agility. But what about systems we already have in place that simply create a blob of ciphertext data and nothing to describe its crypto settings?&lt;/P&gt;
&lt;P&gt;You really have two options.&lt;/P&gt;
&lt;P&gt;The first is to use one of the patterns above to wrap the ciphertext blob and call that version 1 or describe all the parameters&lt;/P&gt;
&lt;P&gt;The second is to add a distinct header at the start of new ciphertext and include the metadata, and for old data (let’s call it v1) if that header is missing, then it’s old ciphertext with no metadata.&lt;/P&gt;
&lt;P&gt;Think of the header as a magic number like that used in a JPEG (0xFF 0xD8 0xFF), GIF89a (GIF89a), PNG (0x89 PNG\r\n\1x1a\n) or PDF (%PDF-) file. You could use something like 0x00 0xC1 PH 3R 0x01, which is a null followed by ‘CIPHER’ and then the version number, 0x01. Of course, there is a small, but non-zero chance that some ciphertext could include this series of magic values, so make sure you code gracefully fails when it does not decrypt legacy data.&lt;/P&gt;
&lt;H1&gt;Summary&lt;/H1&gt;
&lt;P&gt;To be honest, this post is about 8 pages longer than I wanted, but I would rather err on the side of completeness. Besides, as JRR Tolkien said of The Lord of the Rings, “This tale grew in the telling.”&lt;/P&gt;
&lt;P&gt;Crypto-agility is the engineering capability to change cryptographic primitives safely and repeatedly without redesigning systems, and it is now essential for post-quantum migration.&lt;/P&gt;
&lt;P&gt;Crypto-agility requires either self-describing cryptographic metadata or versioned ciphertext formats so implementations can read legacy data while writing with the newest approved algorithms. A well-designed crypto-agile system should aim to read older ciphertext formats long enough to support migration, while writing new data with the newest approved configuration.&lt;/P&gt;
&lt;P&gt;Practical patterns range from Office-style embedded metadata, to SQL-style and Azure Blob Storage version numbers, to JOSE/CMS headers and metadata that separate key wrapping from content encryption.&lt;/P&gt;
&lt;P&gt;The design rule is simple: remove hard-coded algorithm assumptions, persist enough information to reconstruct the cryptographic context, and build systems so algorithm upgrades become routine engineering rather than emergency rewrites.&lt;/P&gt;
&lt;H1&gt;Thanks&lt;/H1&gt;
&lt;P&gt;I would like to thank the following people for their valuable input and review of this post:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Jack Richins – Azure Security, PQC&lt;/LI&gt;
&lt;LI&gt;Jessica Krynitsky – Windows Security&lt;/LI&gt;
&lt;LI&gt;Andrei Popov – Windows Security&lt;/LI&gt;
&lt;LI&gt;Pieter Vanhove – Azure Data&lt;/LI&gt;
&lt;LI&gt;Jeremy Barton – .NET Crypto&lt;/LI&gt;
&lt;LI&gt;Raul Garcia – Microsoft Crypto Board&lt;/LI&gt;
&lt;/UL&gt;</description>
      <pubDate>Thu, 06 Aug 2026 01:04:18 GMT</pubDate>
      <guid>https://techcommunity.microsoft.com/t5/post-quantum-crypto-tech-blog/post-quantum-cryptography-and-crypto-agility/ba-p/4530365</guid>
      <dc:creator>MichaelHoward-MSFT</dc:creator>
      <dc:date>2026-08-06T01:04:18Z</dc:date>
    </item>
  </channel>
</rss>

