The DNSCrypt Protocol
draft-denis-dprive-dnscrypt-11
This document is an Internet-Draft (I-D).
Anyone may submit an I-D to the IETF.
This I-D is not endorsed by the IETF and has no formal standing in the
IETF standards process.
| Document | Type | Active Internet-Draft (individual) | |
|---|---|---|---|
| Author | Frank Denis | ||
| Last updated | 2026-07-23 | ||
| RFC stream | (None) | ||
| Intended RFC status | (None) | ||
| Formats | |||
| Stream | Stream state | (No stream defined) | |
| Consensus boilerplate | Unknown | ||
| RFC Editor Note | (None) | ||
| IESG | IESG state | I-D Exists | |
| Telechat date | (None) | ||
| Responsible AD | (None) | ||
| Send notices to | (None) |
draft-denis-dprive-dnscrypt-11
Network Working Group F. Denis
Internet-Draft Individual Contributor
Intended status: Informational 23 July 2026
Expires: 24 January 2027
The DNSCrypt Protocol
draft-denis-dprive-dnscrypt-11
Abstract
The DNSCrypt protocol is designed to encrypt and authenticate DNS
traffic between clients and resolvers.
This document specifies the protocol and its implementation,
providing a standardized approach to securing DNS communications.
DNSCrypt improves confidentiality, integrity, and resistance to
attacks affecting the original DNS protocol while maintaining
compatibility with existing DNS infrastructure.
About This Document
This note is to be removed before publishing as an RFC.
The latest revision of this draft can be found at
https://dnscrypt.github.io/dnscrypt-protocol/. Status information
for this document may be found at https://datatracker.ietf.org/doc/
draft-denis-dprive-dnscrypt/.
Source for this draft and an issue tracker can be found at
https://github.com/DNSCrypt/dnscrypt-protocol.
Status of This Memo
This Internet-Draft is submitted in full conformance with the
provisions of BCP 78 and BCP 79.
Internet-Drafts are working documents of the Internet Engineering
Task Force (IETF). Note that other groups may also distribute
working documents as Internet-Drafts. The list of current Internet-
Drafts is at https://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months
and may be updated, replaced, or obsoleted by other documents at any
time. It is inappropriate to use Internet-Drafts as reference
material or to cite them other than as "work in progress."
Denis Expires 24 January 2027 [Page 1]
Internet-Draft DNSCrypt July 2026
This Internet-Draft will expire on 24 January 2027.
Copyright Notice
Copyright (c) 2026 IETF Trust and the persons identified as the
document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents (https://trustee.ietf.org/
license-info) in effect on the date of publication of this document.
Please review these documents carefully, as they describe your rights
and restrictions with respect to this document.
Table of Contents
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3
2. Conventions And Definitions . . . . . . . . . . . . . . . . . 4
3. Protocol Flow . . . . . . . . . . . . . . . . . . . . . . . . 4
4. Protocol Components . . . . . . . . . . . . . . . . . . . . . 6
5. Protocol Description . . . . . . . . . . . . . . . . . . . . 9
5.1. Overview . . . . . . . . . . . . . . . . . . . . . . . . 9
5.2. Transport . . . . . . . . . . . . . . . . . . . . . . . . 11
5.3. Session Establishment . . . . . . . . . . . . . . . . . . 11
5.4. Query Processing . . . . . . . . . . . . . . . . . . . . 12
5.4.1. Padding For Client Queries Over UDP . . . . . . . . . 12
5.4.2. Client Queries Over UDP . . . . . . . . . . . . . . . 13
5.4.3. Padding For Client Queries Over TCP . . . . . . . . . 14
5.4.4. Client Queries Over TCP . . . . . . . . . . . . . . . 15
5.4.5. Padding For Resolver Responses . . . . . . . . . . . 15
5.4.6. Resolver Responses Over UDP . . . . . . . . . . . . . 16
5.4.7. Resolver Responses Over TCP . . . . . . . . . . . . . 17
5.5. Certificates . . . . . . . . . . . . . . . . . . . . . . 17
6. Conformance Checklist . . . . . . . . . . . . . . . . . . . . 23
7. Implementation Status . . . . . . . . . . . . . . . . . . . . 25
8. Security Considerations . . . . . . . . . . . . . . . . . . . 25
8.1. Protocol Security . . . . . . . . . . . . . . . . . . . . 25
8.2. Implementation Security . . . . . . . . . . . . . . . . . 26
8.3. Attack Mitigation . . . . . . . . . . . . . . . . . . . . 27
8.4. Privacy Considerations . . . . . . . . . . . . . . . . . 28
8.5. Operational Security . . . . . . . . . . . . . . . . . . 28
9. Operational Considerations . . . . . . . . . . . . . . . . . 29
10. Anonymized DNSCrypt . . . . . . . . . . . . . . . . . . . . . 31
10.1. Protocol Overview . . . . . . . . . . . . . . . . . . . 31
10.2. Client Queries . . . . . . . . . . . . . . . . . . . . . 31
10.3. Relay Behavior . . . . . . . . . . . . . . . . . . . . . 33
10.4. Operational Considerations . . . . . . . . . . . . . . . 34
11. Post-Quantum Key Exchange (PQDNSCrypt) . . . . . . . . . . . 35
11.1. Key Encapsulation Instead of Key Agreement . . . . . . . 35
Denis Expires 24 January 2027 [Page 2]
Internet-Draft DNSCrypt July 2026
11.2. PQ Certificates . . . . . . . . . . . . . . . . . . . . 36
11.3. Certificate Retrieval Amplification . . . . . . . . . . 38
11.4. PQ Key Derivation . . . . . . . . . . . . . . . . . . . 39
11.5. PQ Query and Response Format . . . . . . . . . . . . . . 40
11.6. Padding and Transport . . . . . . . . . . . . . . . . . 41
11.7. Stateless Resumption . . . . . . . . . . . . . . . . . . 41
11.7.1. Issuing a Ticket . . . . . . . . . . . . . . . . . . 42
11.7.2. Resuming . . . . . . . . . . . . . . . . . . . . . . 43
11.7.3. Resumption Considerations . . . . . . . . . . . . . 45
11.8. PQ and Anonymized DNSCrypt . . . . . . . . . . . . . . . 46
11.9. PQ Downgrade Protection . . . . . . . . . . . . . . . . 47
11.10. PQ Security Considerations . . . . . . . . . . . . . . . 47
12. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 48
13. Appendix 1: The Box-XChaChaPoly Algorithm . . . . . . . . . . 48
13.1. Conventions and Definitions . . . . . . . . . . . . . . 48
13.2. HChaCha20 . . . . . . . . . . . . . . . . . . . . . . . 49
13.3. Test Vector For The HChaCha20 Block Function . . . . . . 49
13.4. ChaCha20_DJB . . . . . . . . . . . . . . . . . . . . . . 50
13.5. XChaCha20_DJB . . . . . . . . . . . . . . . . . . . . . 50
13.6. XChaCha20_DJB-Poly1305 . . . . . . . . . . . . . . . . . 50
13.7. The Box-XChaChaPoly Algorithm . . . . . . . . . . . . . 51
14. Appendix 2: DNSCrypt Test Vectors . . . . . . . . . . . . . . 52
14.1. Pinned Inputs . . . . . . . . . . . . . . . . . . . . . 52
14.2. Public Keys and Shared Key . . . . . . . . . . . . . . . 54
14.3. Certificate . . . . . . . . . . . . . . . . . . . . . . 54
14.4. Certificate Retrieval . . . . . . . . . . . . . . . . . 55
14.5. Client Query (UDP) . . . . . . . . . . . . . . . . . . . 56
14.6. Server Response (UDP) . . . . . . . . . . . . . . . . . 58
14.7. Padding and Transport Notes . . . . . . . . . . . . . . 59
14.8. Negative Cases . . . . . . . . . . . . . . . . . . . . . 59
15. Appendix 3: PQ Test Vector Structure . . . . . . . . . . . . 60
15.1. Provisional Assignments . . . . . . . . . . . . . . . . 60
15.2. Pinned Inputs . . . . . . . . . . . . . . . . . . . . . 61
15.3. Profile Extension and Signature Input . . . . . . . . . 62
15.4. Full X-Wing Query . . . . . . . . . . . . . . . . . . . 64
15.5. Full Response and Ticket Issuance . . . . . . . . . . . 65
15.6. Resumed Query and Response . . . . . . . . . . . . . . . 66
15.7. Negative Cases . . . . . . . . . . . . . . . . . . . . . 67
15.8. Generated Values . . . . . . . . . . . . . . . . . . . . 68
16. Normative References . . . . . . . . . . . . . . . . . . . . 70
Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 71
1. Introduction
The Domain Name System (DNS) [RFC1035] is a critical component of
Internet infrastructure, but its original design did not include
security features to protect the confidentiality and integrity of
queries and responses.
Denis Expires 24 January 2027 [Page 3]
Internet-Draft DNSCrypt July 2026
This fundamental security gap exposes DNS traffic to eavesdropping,
tampering, and various attacks that can compromise user privacy and
network security.
To address these vulnerabilities, this document defines the DNSCrypt
protocol, which encrypts and authenticates DNS queries and responses,
providing strong confidentiality, integrity, and resistance to
attacks affecting the original DNS protocol.
The protocol is designed to be lightweight, extensible, and simple to
implement securely on top of existing DNS infrastructure, offering a
practical solution for securing DNS communications without requiring
significant changes to current systems.
The following sections detail the protocol's design, starting with an
overview of its operation and then progressing through the technical
specifications needed for implementation.
2. Conventions And Definitions
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
"OPTIONAL" in this document are to be interpreted as described in
BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all
capitals, as shown here.
3. Protocol Flow
The DNSCrypt protocol consists of two distinct phases:
1. *Initial Setup Phase* (one-time):
* The client requests the server's certificate
* The server responds with its certificate containing public
keys
2. *Ongoing Communication Phase* (repeated as needed):
* The client sends encrypted DNS queries
* The server responds with encrypted DNS responses
The following diagram illustrates the complete protocol flow:
Denis Expires 24 January 2027 [Page 4]
Internet-Draft DNSCrypt July 2026
+--------+ +--------+
| | | |
| Client | | Server |
| | | |
+--------+ +--------+
| |
| 1. Request Certificate |
|---------------------------->|
| |
| 2. Certificate Response |
|<----------------------------|
| |
| 3. Encrypted Query |
|---------------------------->|
| |
| 4. Encrypted Query |
|---------------------------->|
| |
| 5. Encrypted Response |
|<----------------------------|
| |
| 6. Encrypted Response |
|<----------------------------|
| |
| 7. Encrypted Query |
|---------------------------->|
| |
| 8. Encrypted Response |
|<----------------------------|
| |
| |
The initial setup phase (steps 1-2) occurs only when:
* A client first starts using a DNSCrypt server
* The client's cached certificate expires
* The client detects a certificate with a higher serial number
After the initial setup, the client and server engage in the ongoing
communication phase (steps 3-8), where encrypted queries and
responses are exchanged as needed.
This phase can be repeated indefinitely until the certificate expires
or a new certificate is available.
Denis Expires 24 January 2027 [Page 5]
Internet-Draft DNSCrypt July 2026
The ongoing communication phase operates with several important
characteristics that distinguish it from traditional DNS:
1. *Stateless Operation*: Each query and response is independent.
The server does not maintain state between queries.
2. *Out-of-Order Responses*: Responses may arrive in a different
order than the queries were sent. Each response is self-
contained and can be processed independently.
3. *Concurrent Queries*: A client can send multiple queries without
waiting for earlier responses, and responses can be processed
independently as they arrive.
With this understanding of the protocol flow, we can now examine the
specific components that make up DNSCrypt packets and their
structure.
4. Protocol Components
The DNSCrypt protocol defines specific packet structures for both
client queries and server responses.
These components work together to provide the security properties
described in the previous section.
Definitions for client queries:
* <dnscrypt-query>: <client-magic> <client-pk> <client-nonce>
<encrypted-query>
* <client-magic>: an 8 byte identifier for the resolver certificate
chosen by the client (see the Certificates section).
* <client-pk>: the client's public key, whose length depends on the
encryption algorithm defined in the chosen certificate.
* <client-sk>: the client's secret key.
* <resolver-pk>: the resolver's public key.
Denis Expires 24 January 2027 [Page 6]
Internet-Draft DNSCrypt July 2026
* <client-nonce>: a unique query identifier for a given (<client-
sk>, <resolver-pk>) tuple. Every newly encrypted DNSCrypt query
for the same (<client-sk>, <resolver-pk>) tuple MUST use a
distinct <client-nonce> value, even when the plaintext DNS query
is being retried. Retransmitting the same already-encrypted
DNSCrypt packet does not require changing its nonce. The length
of <client-nonce> is determined by the chosen encryption
algorithm.
* AE: the authenticated encryption function for the selected
certificate. For Box-XChaChaPoly and PQDNSCrypt (see the Post-
Quantum Key Exchange section), it is the XChaCha20_DJB-Poly1305
construction of Appendix 1, whose output is the 16-byte
authentication tag followed by the ciphertext. This is the NaCl
secretbox layout, in which the one-time Poly1305 key is taken from
the start of the keystream; it is not the AEAD of [RFC8439], and
the two are not interchangeable. See Appendix 1 for details.
* <encrypted-query>: AE(<shared-key>, <client-nonce> <client-nonce-
pad>, <client-query> <client-query-pad>)
* <shared-key>: the shared key derived from <resolver-pk> and
<client-sk>, using the key exchange algorithm defined in the
chosen certificate.
* <client-query>: the unencrypted client query. The query is not
modified; in particular, the query flags are not altered. The
DNS-over-TCP two-byte length prefix is transport framing and is
not part of the plaintext encrypted by DNSCrypt.
* <client-nonce-pad>: <client-nonce> length is half the nonce length
required by the encryption algorithm. In client queries, the
other half, <client-nonce-pad> is filled with NUL bytes. For <es-
version> 0x00 0x02 (the encryption-system identifier carried in
the certificate; see the Certificates section), the encryption
algorithm uses a 24-byte nonce, so <client-nonce> is 12 bytes and
<client-nonce-pad> is the remaining 12 NUL bytes.
* <client-query-pad>: the variable-length padding.
Definitions for server responses:
* <dnscrypt-response>: <resolver-magic> <nonce> <encrypted-response>
* <resolver-magic>: the 0x72 0x36 0x66 0x6e 0x76 0x57 0x6a 0x38 byte
sequence
* <nonce>: <client-nonce> <resolver-nonce>
Denis Expires 24 January 2027 [Page 7]
Internet-Draft DNSCrypt July 2026
* <client-nonce>: the nonce sent by the client in the related query.
* <client-pk>: the client's public key.
* <resolver-sk>: the resolver's secret key.
* <resolver-nonce>: a unique response identifier for a given
(<client-pk>, <resolver-sk>) tuple. The length of <resolver-
nonce> depends on the chosen encryption algorithm. It MUST NOT
consist only of NUL bytes: the response nonce would then equal the
query nonce, reusing a key and nonce pair for two different
plaintexts. A resolver that picks <resolver-nonce> uniformly at
random, as deployed resolvers do, satisfies both requirements.
* AE: the authenticated encryption function for the selected
certificate, as described for client queries above.
* <encrypted-response>: AE(<shared-key>, <nonce>, <resolver-
response> <resolver-response-pad>)
* <shared-key>: the shared key derived from <resolver-sk> and
<client-pk>, using the key exchange algorithm defined in the
chosen certificate.
* <resolver-response>: the unencrypted resolver response. The
response is not modified; in particular, the query flags are not
altered. The DNS-over-TCP two-byte length prefix is transport
framing and is not part of the plaintext encrypted by DNSCrypt.
* <resolver-response-pad>: the variable-length padding.
The following diagram shows the structure of a DNSCrypt query packet:
Denis Expires 24 January 2027 [Page 8]
Internet-Draft DNSCrypt July 2026
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Client Magic |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ Client Public Key +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ Client Nonce +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ Encrypted Query +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The following diagram shows the structure of a DNSCrypt response
packet:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Resolver Magic |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ Nonce +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ Encrypted Response +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
These packet structures form the foundation for the protocol
operations described in the next section, which details how clients
and servers use these components to establish secure communications.
5. Protocol Description
5.1. Overview
Building on the protocol flow and components described earlier, this
section provides a detailed examination of how the DNSCrypt protocol
operates.
The protocol follows a well-defined sequence of steps:
Denis Expires 24 January 2027 [Page 9]
Internet-Draft DNSCrypt July 2026
1. The DNSCrypt client sends a DNS query to a DNSCrypt server to
retrieve the server's public keys.
2. The client generates its own key pair.
3. The client encrypts unmodified DNS queries using a server's
public key, padding them as necessary, and concatenates them to a
nonce and a copy of the client's public key. The resulting
output is transmitted to the server via standard DNS transport
mechanisms [RFC1035].
4. Encrypted queries are decrypted by the server using the attached
client public key and the server's own secret key. The output is
a regular DNS packet that doesn't require any special processing.
5. To send an encrypted response, the server truncates the DNS
response and sets the TC flag if the encrypted response would not
fit within the size limit, adds padding, and encrypts the result
using the shared key and a nonce made of the client's nonce
followed by the resolver's nonce. The resulting packet is sent
to the client using standard DNS mechanisms.
6. The client authenticates and decrypts the response using the
shared key and the nonce included in the response. If the
response was truncated, the client retries over TCP [RFC7766] and
can adjust internal parameters. If not, the output is a regular
DNS response that can be directly forwarded to applications and
stub resolvers.
Key features of the DNSCrypt protocol include:
* Stateless operation: Every query can be processed independently
from other queries, with no session identifiers required.
* Flexible key management: Clients can replace their keys whenever
they want, without extra interactions with servers.
* Proxy support: DNSCrypt packets can securely be proxied without
having to be decrypted, allowing client IP addresses to be hidden
from resolvers ("Anonymized DNSCrypt").
* Shared infrastructure: Recursive DNS servers can accept DNSCrypt
queries on the same IP address and port used for regular DNS
traffic.
* Attack mitigation: DNSCrypt mitigates two common security
vulnerabilities in regular DNS over UDP: amplification [RFC5358]
and fragmentation attacks.
Denis Expires 24 January 2027 [Page 10]
Internet-Draft DNSCrypt July 2026
These key features enable DNSCrypt to provide robust security while
maintaining practical deployability.
The protocol's transport characteristics further support these goals.
5.2. Transport
The DNSCrypt protocol can use the UDP and TCP transport protocols.
DNSCrypt clients and resolvers SHOULD support the protocol via UDP,
and MUST support it over TCP.
Both TCP and UDP connections using DNSCrypt SHOULD employ port 443 by
default.
The choice of port 443 helps DNSCrypt traffic blend with HTTPS
traffic, providing some protection against traffic analysis.
A complete encrypted <dnscrypt-query> packet MUST NOT exceed 4096
bytes, and resolvers MUST accept queries up to this size over both
UDP and TCP.
This bound matches deployed implementations: clients never send
larger queries, and resolvers stop reading beyond a few kilobytes.
Once transport is established, the next step is session establishment
through certificate exchange.
5.3. Session Establishment
From the client's perspective, a DNSCrypt session is initiated when
the client sends an unauthenticated DNS query to a DNSCrypt-capable
resolver.
This DNS query contains encoded information about the certificate
versions supported by the client and a public identifier of the
desired provider.
The resolver sends back a collection of signed certificates that the
client MUST verify using the pre-distributed provider public key.
Each certificate includes a validity period, a serial number, a
version that defines a key exchange mechanism, an authenticated
encryption algorithm and its parameters, as well as a short-term
public key, known as the resolver public key.
Denis Expires 24 January 2027 [Page 11]
Internet-Draft DNSCrypt July 2026
Resolvers have the ability to support various algorithms and can
concurrently advertise multiple short-term public keys (resolver
public keys).
The client picks the one with the highest serial number among the
currently valid ones that match a supported protocol version.
Every certificate contains a unique magic number that the client MUST
include at the beginning of their queries.
This allows the resolver to identify which certificate the client
selected for crafting a particular query.
The encryption algorithm, resolver public key, and client magic
number from the chosen certificate are then used by the client to
send encrypted queries.
These queries include the client public key.
With the knowledge of the chosen certificate and corresponding secret
key, along with the client's public key, the resolver is able to
verify, decrypt the query, and then encrypt the response utilizing
identical parameters.
Once the session is established through certificate exchange, the
ongoing query processing follows specific rules for different
transport protocols and padding requirements.
5.4. Query Processing
5.4.1. Padding For Client Queries Over UDP
Before encryption takes place, queries are padded according to the
ISO/IEC 7816-4 standard.
Padding begins with a single byte holding the value 0x80, followed by
any number of NUL bytes.
The padding length MUST be at least 1 byte, because ISO/IEC 7816-4
padding always appends the initial 0x80 delimiter.
A resolver that has authenticated and decrypted a query MUST accept
this padding format; it MUST NOT reject a query solely because the
plaintext length is not a multiple of 64 bytes.
Denis Expires 24 January 2027 [Page 12]
Internet-Draft DNSCrypt July 2026
<min-query-len> is a variable target length for the complete
encrypted <dnscrypt-query> packet, including <client-magic>, <client-
pk>, <client-nonce>, the authentication tag, and the encrypted padded
DNS query.
It is initially 256 bytes, and implementations MAY use a larger
initial value, such as 512 bytes.
A client pads the plaintext so that the complete UDP DNSCrypt packet
is at least <min-query-len> bytes; when practical, the padded
plaintext <client-query> <client-query-pad> SHOULD be a multiple of
64 bytes.
This target is a sender-side anti-amplification and privacy
parameter, not an additional receiver-side validity check.
5.4.2. Client Queries Over UDP
UDP-based client queries need to follow the padding guidelines
outlined in the previous section.
Each UDP packet MUST hold one query, with the complete content
comprising the <dnscrypt-query> structure specified in the Protocol
Components section.
A DNSCrypt UDP datagram may be fragmented at the IP layer like any
other UDP datagram, and a client MAY send multiple independent
queries from the same source port.
Upon receiving a query, the resolver may choose to either disregard
it or send back a response encrypted using DNSCrypt.
The client MUST authenticate and, if authentication succeeds, decrypt
the response with the help of the resolver's public key, the shared
secret, and the response nonce.
The client MUST verify that the <client-nonce> prefix of the response
nonce matches a currently outstanding query.
In case the response fails verification, or the <client-nonce> does
not match a currently outstanding query, it MUST be disregarded by
the client.
If the response has the TC flag set, the client MUST:
1. send the query again using TCP [RFC7766]
Denis Expires 24 January 2027 [Page 13]
Internet-Draft DNSCrypt July 2026
2. update its future UDP padding target if its local size estimator
indicates that larger UDP queries would have avoided truncation
<min-query-len> MUST be capped so that the full length of a DNSCrypt
packet does not exceed the maximum size supported by the transport
path.
A client MAY increase or decrease this value over time.
The adjustment algorithm is implementation-defined.
While UDP queries require careful length management due to truncation
concerns, TCP queries follow different padding rules due to the
reliable nature of the transport.
5.4.3. Padding For Client Queries Over TCP
Queries MUST undergo padding using the ISO/IEC 7816-4 format before
being encrypted.
The padding starts with a byte valued 0x80 followed by a variable
number of NUL bytes.
TCP has no UDP amplification constraint, but padding still hides the
exact DNS query length.
A client SHOULD add a random padding component and SHOULD avoid
deterministic plaintext lengths for repeated queries.
A resolver MUST accept any authenticated plaintext that is valid ISO/
IEC 7816-4 padding and parses as a DNS message, whatever the padded
length; deployed receivers already behave this way.
For example, an originally unpadded 56-byte DNS query can be validly
padded as:
<56-bytes-query> 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00
or
<56-bytes-query> 0x80 (0x00 * 71)
or
<56-bytes-query> 0x80 (0x00 * 135)
or
Denis Expires 24 January 2027 [Page 14]
Internet-Draft DNSCrypt July 2026
<56-bytes-query> 0x80 (0x00 * 199)
5.4.4. Client Queries Over TCP
The sole differences between encrypted client queries transmitted via
TCP and those sent using UDP lie in the padding length calculation
and the inclusion of a two-byte big-endian length prefix for the
encrypted DNSCrypt packet.
Cleartext DNS query payloads are not prefixed by their length before
encryption, even when the DNSCrypt packet is sent over TCP.
The two-byte TCP length prefix is added after encryption and covers
the complete <dnscrypt-query> packet.
Unlike UDP queries, a query sent over TCP can be shorter than the
response.
After having received a response from the resolver, the client and
the resolver MUST close the TCP connection to ensure security and
comply with this revision of the protocol, which prohibits multiple
transactions over the same TCP connection.
5.4.5. Padding For Resolver Responses
Before encryption takes place, responses are padded according to the
ISO/IEC 7816-4 format.
Padding begins with a single byte holding the value 0x80, followed by
any number of NUL bytes.
When the transport size budget permits, the resolver SHOULD pad
<resolver-response> <resolver-response-pad> to a multiple of 64
bytes.
The padding length SHOULD be between 1 and 256 bytes, including the
initial 0x80 byte.
The padding length SHOULD be computed as a deterministic function of
either (<resolver-sk>, <client-nonce>) or (<shared-key>, <client-
nonce>), for example with a pseudorandom function, so that
retransmitted queries receive identically padded responses.
The requirement prevents response padding from becoming an extra
source of linkable server behavior while still allowing stateless
operation.
Denis Expires 24 January 2027 [Page 15]
Internet-Draft DNSCrypt July 2026
If the preferred padding would make an encrypted UDP response exceed
the triggering query size or the resolver's UDP maximum, the resolver
MAY use a shorter valid ISO/IEC 7816-4 padding length, or truncate
the DNS response and set the DNS TC flag before padding and
encryption.
A client MUST accept any authenticated response whose plaintext has
valid ISO/IEC 7816-4 padding and parses as a DNS response; it MUST
NOT reject a response solely because the plaintext length is not a
multiple of 64 bytes or because the padding length is outside the
preferred range above.
5.4.6. Resolver Responses Over UDP
The resolver MUST authenticate and decrypt client queries before
forwarding them to the upstream DNS resolution path.
Queries that cannot be authenticated, decrypted, unpadded, or parsed
as DNS messages MUST be ignored.
Any client-supplied nonce value MUST be accepted for decryption.
A resolver MAY ignore or refuse queries encrypted with client public
keys that are not authorized by local policy, but a public resolver
that accepts anonymous clients MUST accept arbitrary client public
keys, subject only to the cryptographic checks of Appendix 2, such as
low-order key rejection.
Responses sent over UDP MUST be padded as described in "Padding For
Resolver Responses" and encrypted as <dnscrypt-response>.
As in standard DNS, the decrypted response MUST echo the transaction
ID and question of the decrypted query; deployed clients discard
responses that do not.
The resolver MUST NOT send an encrypted DNSCrypt response over UDP
that is larger than the encrypted DNSCrypt query packet that
triggered it.
If the full encrypted response packet would be larger than the query
packet even with minimal padding, the resolver MUST truncate the DNS
response and set the DNS TC flag before padding and encryption.
A resolver MUST NOT stay silent instead: the query was authenticated,
and a dropped response leaves the client waiting out a retransmission
timeout, whereas a truncated response makes it retry over TCP
immediately.
Denis Expires 24 January 2027 [Page 16]
Internet-Draft DNSCrypt July 2026
If the resolver sends a truncated response, the encrypted truncated
response MUST still be equal to or shorter than the encrypted query
packet.
5.4.7. Resolver Responses Over TCP
The resolver MUST authenticate and decrypt client queries as
described for UDP.
Queries that cannot be authenticated, decrypted, unpadded, or parsed
as DNS messages MUST be ignored.
Responses sent over TCP MUST be padded as described in "Padding For
Resolver Responses" and encrypted as <dnscrypt-response>.
The complete encrypted response packet is then prefixed with a two-
byte big-endian length.
Cleartext DNS response payloads are not prefixed by their length
before encryption, even when the DNSCrypt packet is sent over TCP.
Unlike UDP responses, TCP responses MUST be sent unmodified even if
their encrypted length exceeds the encrypted query length.
The complete encrypted response MUST nevertheless be smaller than
4096 bytes, because deployed clients reject larger DNSCrypt packets;
a resolver whose DNS response would exceed this limit truncates it
and sets the TC flag before padding and encryption.
The query and response processing rules described above depend on the
certificate information obtained during session establishment.
The certificate format and management procedures are critical to the
protocol's security.
5.5. Certificates
The following diagram shows the structure of a DNSCrypt certificate:
Denis Expires 24 January 2027 [Page 17]
Internet-Draft DNSCrypt July 2026
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Cert Magic |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ES Version | Protocol Minor Version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ Signature +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ Resolver Public Key +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Client Magic |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Serial |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TS Start |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| TS End |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ Extensions +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
To initiate a DNSCrypt session, a client transmits an ordinary
unencrypted TXT DNS query to the resolver's IP address and DNSCrypt
port.
A client MAY use UDP or TCP according to local policy.
Clients SHOULD try UDP first and retry over TCP after failure,
timeout, or truncation. A PQ-capable client uses the rollover-sized
padding target defined in Certificate Retrieval Amplification;
although this can cause IP fragmentation, fragmented UDP works on
most paths. A client on a path already known to block fragmented UDP
MAY use TCP immediately.
A resolver MUST serve certificates over both UDP and TCP; the UDP
response MAY be truncated, with the TC flag set, to direct the client
to TCP. Deployed clients begin certificate retrieval over UDP and
only retry over TCP after a truncated response.
The standard name in the question (<provider name>) follows this
scheme:
Denis Expires 24 January 2027 [Page 18]
Internet-Draft DNSCrypt July 2026
<protocol-major-version> . dnscrypt-cert . <zone>
A major protocol version has only one certificate format.
A DNSCrypt client implementing the second version of the protocol
SHOULD send a query with the TXT type and IN class, and a name of the
form:
2.dnscrypt-cert.example.com
Clients MAY support explicitly configured provider names that do not
follow this convention.
Such names are non-standard and can fail through Anonymized DNSCrypt
relays that only recognize the standard certificate prefix.
The RD (Recursion Desired) bit MAY be set; a resolver serving a
certificate for its own provider name ignores it.
A certificate query sent over UDP MAY include an EDNS(0) [RFC6891]
OPT pseudo-RR with an EDNS(0) Padding option [RFC7830].
This padding is part of the DNS request length used for UDP anti-
amplification checks.
The padding bytes are NUL bytes and carry no protocol data.
A resolver MUST ignore the padding contents when matching the
question name and MUST NOT use the advertised EDNS(0) UDP payload
size as an amplification budget.
The zone MUST be a valid DNS name, but MAY not be registered in the
DNS hierarchy.
A single provider name can be shared by multiple resolvers operated
by the same entity, and a resolver can respond to multiple provider
names, especially to support multiple protocol versions
simultaneously.
In order to use a DNSCrypt-enabled resolver, a client must know the
following information:
* The resolver IP address and port
* The provider name
* The provider public key
Denis Expires 24 January 2027 [Page 19]
Internet-Draft DNSCrypt July 2026
The provider public key is a long-term key whose sole purpose is to
verify the certificates.
It is never used to encrypt or verify DNS queries.
A single provider public key can be employed to sign multiple
certificates.
For example, an organization operating multiple resolvers can use a
unique provider name and provider public key across all resolvers,
and just provide a list of IP addresses and ports.
Each resolver MAY have its unique set of certificates that can be
signed with the same key.
It is RECOMMENDED that certificates are signed using specialized
hardware rather than directly on the resolvers themselves.
Once signed, resolvers SHOULD make these certificates available to
clients.
Signing certificates on dedicated hardware helps ensure security and
integrity, as it isolates the process from potential vulnerabilities
present in the resolver's system.
A successful response to a certificate request contains one or more
TXT records, each record containing a certificate encoded as follows:
* <cert>: <cert-magic> <es-version> <protocol-minor-version>
<signature> <resolver-pk> <client-magic> <serial> <ts-start> <ts-
end> <extensions>
* <cert-magic>: 0x44 0x4e 0x53 0x43
* <es-version>: the cryptographic construction to use with this
certificate. For the Box-XChaChaPoly construction of Appendix 1,
that is, the X25519 key exchange with the XChaCha20_DJB-Poly1305
authenticated encryption algorithm, <es-version> MUST be 0x00
0x02. PQDNSCrypt uses 0x00 0x03; these values are summarized
below.
* <protocol-minor-version>: 0x00 0x00
* <signature>: a 64-byte signature of (<resolver-pk> <client-magic>
<serial> <ts-start> <ts-end> <extensions>) using the Ed25519
algorithm and the provider secret key. Ed25519 MUST be used in
this version of the protocol.
Denis Expires 24 January 2027 [Page 20]
Internet-Draft DNSCrypt July 2026
* <resolver-pk>: the resolver short-term public key, which is 32
bytes when using X25519.
* <client-magic>: an 8-byte value identifying this certificate; the
client copies it verbatim into the first 8 bytes of every query
built from this certificate. It is an opaque identifier and MAY
be a truncated resolver public key. A provider MUST NOT issue two
concurrently valid certificates with the same <client-magic>, MUST
NOT use a value starting with 0x00 0x00 0x00 0x00 0x00 0x00 0x00
(seven all-zero bytes) in order to avoid confusion with the QUIC
protocol [RFC9000], and MUST NOT use the reserved <resume-magic>
value defined in Stateless Resumption.
* <serial>: a 4-byte serial number in big-endian format. If more
than one certificate is valid for the encryption system the client
selected, the client MUST prefer the certificate with a higher
serial number.
* <ts-start>: the date the certificate is valid from, as a big-
endian 4-byte unsigned Unix timestamp. It MUST be strictly
earlier than <ts-end>; deployed clients reject certificates whose
validity interval is empty or inverted.
* <ts-end>: the date the certificate is valid until (inclusive), as
a big-endian 4-byte unsigned Unix timestamp.
* <extensions>: empty in the current protocol version, but may
contain additional data in future revisions, including minor
versions. The computation and verification of the signature MUST
include the extensions. An implementation not supporting these
extensions MUST ignore them.
Certificates made of this information, without extensions, are 116
bytes long.
With the addition of <cert-magic>, <es-version>, and <protocol-minor-
version>, the record is 124 bytes long.
The following encryption systems are defined by this document:
0x00 0x02, Box-XChaChaPoly: The resolver public key is 32 bytes, and
the client public key in queries is 32 bytes. The nonce is split
into a 12-byte client nonce and a 12-byte resolver nonce. The
shared key is HChaCha20(X25519(pk, sk), 16 NUL bytes). The
certificate extensions field is empty in this revision; unknown
extensions are ignored after signature verification.
0x00 0x03, X-Wing PQDNSCrypt: The resolver public key is 1216 bytes,
Denis Expires 24 January 2027 [Page 21]
Internet-Draft DNSCrypt July 2026
and the client key-exchange field (<client-kex>) in queries is
1120 bytes. The nonce is split into a 12-byte client nonce and a
12-byte resolver nonce. The shared key is derived with HKDF-
SHA256 as defined in "PQ Key Derivation". The certificate
extensions field contains the required 12-byte PQ profile
extension.
Each TXT answer record carries exactly one certificate blob.
A client reads <cert-magic>, <es-version>, and <protocol-minor-
version> first.
If <es-version> is not supported, the client MUST ignore that
certificate blob as a whole.
It MUST NOT try to guess the <resolver-pk> length.
Within a TXT record, the certificate is carried in the record's
RDATA, which is a sequence of length-prefixed character-strings
[RFC1035].
A client reconstructs the certificate by concatenating these
character-strings in order, after removing the single length octet
that precedes each one.
A 124-byte classical certificate fits in a single character-string,
whereas a larger certificate spans several character-strings that
MUST be concatenated in this way before the certificate is parsed.
After receiving a set of certificates, the client checks their
validity based on the current date and filters out certificates for
unsupported encryption systems.
The client then applies local policy for the resolver.
If local policy or provisioning says that a resolver supports or
requires a specific profile, such as PQDNSCrypt, the client MUST
select only certificates for that profile and MUST NOT fall back to a
different profile.
Otherwise, if multiple supported profiles remain, the client chooses
the most preferred supported profile according to local policy, and
then chooses the valid certificate with the highest serial number
within that profile.
A client with no profile preference MAY treat all supported profiles
as one set and choose the highest serial number among them, using
local policy to break ties.
Denis Expires 24 January 2027 [Page 22]
Internet-Draft DNSCrypt July 2026
DNSCrypt queries sent by the client MUST use the <client-magic>
header of the chosen certificate, as well as the specified encryption
system and public key.
The client MUST refresh certificates periodically and early enough to
avoid using expired certificates.
An hourly refresh interval is suitable, but not required.
After a refresh, the client switches to a new certificate if:
* The current certificate is not present or not valid anymore,
or
* A certificate with a higher serial number than the current one is
available.
The certificate management system ensures that cryptographic keys
remain fresh and that clients can smoothly transition to updated
certificates.
With the core protocol mechanics now established, we can examine
implementation considerations.
6. Conformance Checklist
A conformant DNSCrypt v2 client implementation has enough information
in this document to:
* Build and parse DNS wire-format TXT certificate queries for the
configured provider name, using UDP or TCP according to local
policy and retrying over TCP when a direct TCP retry is
appropriate.
* Reconstruct certificates from DNS TXT character-strings, verify
the Ed25519 signature with the configured provider public key,
reject unsupported or invalid certificates, and choose a valid
certificate for a supported encryption system according to serial
number and local profile policy.
* Generate a client key pair and a unique <client-nonce> for each
newly encrypted query under the same client secret key and
resolver public key.
Denis Expires 24 January 2027 [Page 23]
Internet-Draft DNSCrypt July 2026
* Pad DNS queries with ISO/IEC 7816-4 padding, encrypt them with the
selected certificate parameters, and send exactly one <dnscrypt-
query> per UDP datagram or one length-prefixed packet per TCP
connection.
* Authenticate responses, verify that the returned nonce starts with
an outstanding <client-nonce>, remove padding, and forward the
unmodified DNS response to the caller.
* Retry over TCP when an authenticated UDP response carries the DNS
TC flag, and maintain a UDP padding target that keeps later
encrypted UDP responses within the query size when practical.
A conformant DNSCrypt v2 resolver implementation has enough
information in this document to:
* Generate, sign, serve, rotate, and retire resolver certificates
without using the long-term provider key for query traffic.
* Select the certificate matching an incoming <client-magic>, derive
the shared key from the client public key, authenticate and
decrypt the query, reject bad padding or malformed DNS payloads
silently, and pass the decrypted DNS query to the resolver path.
* Pad, encrypt, and frame responses using the nonce (<client-nonce>
<resolver-nonce>), respecting the UDP anti-amplification guidance
and the TCP length-prefix rules.
* Serve classical certificate responses over UDP, and add larger PQ
certificate records over UDP only when the complete response is no
larger than the triggering request; otherwise set TC and rely on a
padded UDP query or TCP as described below.
A conformant Anonymized DNSCrypt relay implementation has enough
information in this document to:
* Accept length-prefixed TCP and unframed UDP Anonymized DNSCrypt
queries.
* Validate the target address, target port, and inner query prefix
before forwarding.
* Forward the inner query to the target resolver over UDP without
decrypting or modifying it.
* Forward only valid upstream responses that match the relayed query
and do not violate the response-size rule, adding only TCP framing
when returning a response to a TCP client.
Denis Expires 24 January 2027 [Page 24]
Internet-Draft DNSCrypt July 2026
7. Implementation Status
_Note: This section is to be removed before publishing as an RFC._
Multiple implementations of the protocol described in this document
have been developed and verified for interoperability.
A comprehensive list of known implementations can be found at
https://dnscrypt.info/implementations.
The successful deployment of multiple interoperable implementations
demonstrates the protocol's maturity.
However, proper implementation requires careful attention to security
considerations.
8. Security Considerations
This section discusses security considerations for the DNSCrypt
protocol.
8.1. Protocol Security
The DNSCrypt protocol provides several security benefits:
1. *Confidentiality*: DNS queries and responses are encrypted with
the authenticated-encryption construction selected by the
certificate. The current classical and PQ constructions in this
document use XChaCha20_DJB-Poly1305 as defined in Appendix 1,
preventing eavesdropping of DNS traffic. For example, a query
for "example.com" would be encrypted and appear as random data to
an observer.
2. *Integrity*: Message authentication using the Poly1305 tag in
Appendix 1 ensures that responses cannot be tampered with in
transit. Any modification to the encrypted response would be
detected and rejected by the client.
3. *Authentication*: The use of Ed25519 for certificate signatures,
together with the key-exchange mechanism selected by the
certificate, provides strong authentication of resolvers.
Clients can verify they are communicating with the intended
resolver and not an impostor.
4. *Short-Term Resolver Keys*: Resolver certificates carry short-
term public keys, limiting the impact of key compromise and
enabling regular key rotation.
Denis Expires 24 January 2027 [Page 25]
Internet-Draft DNSCrypt July 2026
These fundamental security properties depend on correct
implementation practices.
Several implementation-specific security aspects require particular
attention.
8.2. Implementation Security
Implementations should consider the following security aspects:
1. *Key Management*:
* Resolvers MUST rotate their short-term key pairs at most every
24 hours
* Previous resolver secret keys MUST be retained while unexpired
served certificates still refer to them, and MUST be discarded
as soon as no such certificate remains, or immediately if the
key is believed to be compromised; the full rule appears in
Operational Considerations
* Provider secret keys used for certificate signing SHOULD be
stored in hardware security modules (HSMs)
* Example: A resolver might generate new key pairs daily at
midnight UTC
2. *Nonce Management*:
* Nonces MUST NOT be reused for a given shared secret
* Clients SHOULD generate <client-nonce> values using either a
cryptographically secure random number generator with enough
entropy to make collisions negligible for the lifetime of the
shared secret, or a secret-key pseudorandom construction, such
as encrypting a timestamp and any counter or random bits
needed for uniqueness using a block cipher. Such
constructions MUST NOT expose wall-clock time or other stable
client state to observers, and MUST still provide nonce
uniqueness for the lifetime of the shared secret
* Clients SHOULD NOT include unencrypted timestamps in nonce
values, especially when Anonymized DNSCrypt, Tor, SOCKS, or
other proxying or anonymity systems are used
Denis Expires 24 January 2027 [Page 26]
Internet-Draft DNSCrypt July 2026
* Clients can quickly discard stale responses by keeping local
state for outstanding queries, including their <client-nonce>
values and expiration deadlines, and rejecting responses for
nonces that are unknown, already answered, or expired
3. *Padding*:
* Implementations MUST use the specified padding scheme to
prevent traffic analysis
* The minimum query length SHOULD be adjusted based on network
conditions
* Example: A 50-byte query might be padded to 256 bytes to
prevent size-based fingerprinting
4. *Certificate Validation*:
* Clients MUST verify certificate signatures using the
provider's public key
* Certificates MUST be checked for validity periods
* Clients MUST prefer certificates with higher serial numbers
within the selected encryption system
* Example: A client might cache valid certificates and check for
updates hourly
Proper implementation of these security measures provides the
foundation for the protocol's attack mitigation capabilities.
8.3. Attack Mitigation
DNSCrypt provides protection against several types of attacks:
1. *DNS Spoofing*: The use of authenticated encryption prevents
spoofed responses. An attacker cannot forge responses without
the server's secret key.
2. *Amplification Attacks*: UDP encrypted responses are limited by
the size of the encrypted query that triggered them, and client
padding targets help keep the amplification factor bounded
[RFC5358]. Certificate retrieval has separate rules because it
is unauthenticated and uses ordinary DNS TXT responses.
Denis Expires 24 January 2027 [Page 27]
Internet-Draft DNSCrypt July 2026
3. *Fragmentation Attacks*: The protocol mitigates fragmentation
risks by padding queries, allowing truncated UDP responses, and
retrying over TCP when necessary.
4. *Replay Exposure Reduction*: Nonces make responses query-
specific. Clients can discard late, duplicate, or unrelated
responses by checking the returned <client-nonce> against local
outstanding-query state and request deadlines, without exposing
timestamps in plaintext nonce values.
While DNSCrypt effectively mitigates these attacks, implementers
should also be aware of privacy considerations that extend beyond
basic protocol security.
8.4. Privacy Considerations
While DNSCrypt encrypts DNS traffic, there are some privacy
considerations:
1. *Resolver Knowledge*: Resolvers can still see the client's IP
address unless Anonymized DNSCrypt is used. This can reveal the
client's location and network.
2. *Query Patterns*: Even with encryption, the size and timing of
queries may reveal information. Padding helps mitigate this but
doesn't eliminate it completely.
3. *Nonce Metadata*: Client nonces are visible on the wire.
Encoding unencrypted timestamps or other stable or linkable state
in nonce values can disclose clock information or support client
fingerprinting, particularly when relays or anonymity networks
are used. Clients SHOULD prefer nonce constructions that reveal
no wall-clock time to observers.
4. *Certificate Requests*: Initial certificate requests are
unencrypted but only return public data. This is a one-time
exposure per session.
These privacy considerations complement the security measures and
should inform operational practices for DNSCrypt deployments.
8.5. Operational Security
Operators should consider:
1. *Key Distribution*: Provider public keys should be distributed
securely to clients. This might involve:
Denis Expires 24 January 2027 [Page 28]
Internet-Draft DNSCrypt July 2026
* Publishing keys on secure websites
* Using DNSSEC-signed records
* Including keys in software distributions
2. *Certificate Management*: Certificates should be signed on
dedicated hardware, not on resolvers. This provides:
* Better key protection
* Centralized certificate management
* Reduced attack surface
3. *Access Control*: Resolvers may implement access control based on
client public keys. This can:
* Prevent abuse
* Enable service differentiation
* Support business models
4. *Monitoring*: Operators should monitor for unusual patterns that
may indicate attacks:
* High query rates from single clients
* Unusual query patterns
* Certificate request anomalies
These operational security practices work together with the technical
security measures to provide comprehensive protection.
Additional operational considerations extend beyond security to
include practical deployment aspects.
9. Operational Considerations
Special attention should be paid to the uniqueness of the generated
secret keys.
Client public keys can be used by resolvers to authenticate clients,
link queries to customer accounts, and unlock business-specific
features such as redirecting specific domain names to a sinkhole.
Denis Expires 24 January 2027 [Page 29]
Internet-Draft DNSCrypt July 2026
A resolver that restricts service to known clients MAY respond only
to an allowed set of client public keys.
A resolver that serves arbitrary, anonymous clients MUST accept any
client public key as a matter of policy; cryptographic checks, such
as the rejection of low-order public keys in Appendix 2, still apply.
In particular, an anonymous client can generate a new key pair for
every session, or even for every query.
This mitigates the ability for a resolver to group queries by client
public keys and discover the set of IP addresses a user might have
been operating.
Resolvers MUST rotate each short-term key pair every 24 hours at
most.
After a key rotation, a resolver MUST continue accepting queries for
every unexpired certificate it still serves, which requires retaining
the corresponding resolver secret keys.
Once all certificates for an old resolver key have expired or been
withdrawn, the resolver MUST discard that old secret key.
If an old resolver key is believed to be compromised, the resolver
MUST withdraw the related certificates and discard the key instead of
continuing to accept it.
Provider public keys MAY be published as DNSSEC-signed TXT records
[RFC1035], in the same zone as the provider name.
For example, a query for the TXT type on the name
"2.pubkey.example.com" may return a signed record containing a
hexadecimal-encoded provider public key for the provider name
"2.dnscrypt-cert.example.com".
As a client is likely to reuse the same key pair many times, servers
are encouraged to cache shared keys instead of performing the X25519
operation for each query.
This makes the computational overhead of DNSCrypt negligible compared
to plain DNS.
While DNSCrypt provides strong encryption and authentication, some
use cases require additional privacy protection.
The Anonymized DNSCrypt extension addresses scenarios where hiding
client IP addresses from resolvers is necessary.
Denis Expires 24 January 2027 [Page 30]
Internet-Draft DNSCrypt July 2026
10. Anonymized DNSCrypt
While DNSCrypt encrypts DNS traffic, DNS server operators can still
observe client IP addresses.
Anonymized DNSCrypt is an extension to the DNSCrypt protocol that
allows queries and responses to be relayed by an intermediate server,
hiding the client's IP address from the resolver.
This extension maintains all the security properties of standard
DNSCrypt while adding an additional layer of privacy protection.
10.1. Protocol Overview
Anonymized DNSCrypt works by having the client send encrypted queries
to a relay server, which then forwards them to the actual DNSCrypt
resolver.
The relay server cannot decrypt the queries or responses, and the
resolver only sees the relay's IP address.
[Client]----(encrypted query)--->[Relay]----(encrypted query)--->[Server]
[Client]<--(encrypted response)--[Relay]<--(encrypted response)--[Server]
Key properties of Anonymized DNSCrypt:
* The relay cannot decrypt or modify queries and responses
* The resolver only sees the relay's IP address, not the client's
* A DNSCrypt server can simultaneously act as a relay
* The protocol works over both UDP and TCP
10.2. Client Queries
The following diagram shows the structure of an Anonymized DNSCrypt
query packet:
Denis Expires 24 January 2027 [Page 31]
Internet-Draft DNSCrypt July 2026
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Anon Magic |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ Server IP (IPv6) +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Server Port | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
| |
+ DNSCrypt Query +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
An Anonymized DNSCrypt query is a standard DNSCrypt query prefixed
with information about the target server:
<anondnscrypt-query> ::=
<anon-magic> <server-ip> <server-port> <dnscrypt-query>
Where:
* <anon-magic>: 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x00 0x00
* <server-ip>: 16 bytes encoded IPv6 address (IPv4 addresses are
mapped to IPv6 using ::ffff:<ipv4 address> [RFC4291])
* <server-port>: 2 bytes in big-endian format
* <dnscrypt-query>: either a standard encrypted DNSCrypt query or
the unencrypted TXT certificate query used to retrieve resolver
certificates.
For example, a query for a server at 192.0.2.1:443 would be prefixed
with:
0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0xff 0xff 0xc0 0x00 0x02 0x01 0x01 0xbb
An Anonymized DNSCrypt query sent over UDP is sent as this exact byte
string.
An Anonymized DNSCrypt query sent over TCP is prefixed with a two-
byte big-endian length that covers the complete <anondnscrypt-query>
byte string.
Denis Expires 24 January 2027 [Page 32]
Internet-Draft DNSCrypt July 2026
The relay removes the TCP length prefix before validating the packet
and adds a new TCP length prefix when returning the upstream response
to a TCP client.
10.3. Relay Behavior
Relays MUST:
1. Accept queries over both TCP and UDP
2. Communicate with upstream servers over UDP, even if client
queries were sent to the relay over TCP
3. Validate incoming packets:
* Check that the target IP is not in a private, loopback, link-
local, multicast, unspecified, or otherwise locally routed
range
* Verify the port number is in an allowed range
* Ensure the inner <dnscrypt-query> doesn't start with <anon-
magic>
* Reject the inner <dnscrypt-query> if its first 8 bytes are
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01, to avoid protocol
confusion with QUIC [RFC9000]; relays MAY reject broader
reserved prefixes by local policy
4. Forward the inner <dnscrypt-query> unmodified to the target
server over UDP, without the Anonymized DNSCrypt prefix
5. Verify server responses:
* For encrypted DNSCrypt responses, check that the response is
no larger than the inner query packet forwarded upstream
* For certificate responses, check that the response transaction
ID and query name match the relayed certificate query, and
that the response is no larger than the inner query packet
forwarded upstream
* Validate the response format (either starts with resolver
magic or is a certificate response)
* Forward valid responses unmodified to the client, adding only
the TCP length prefix when the client connection used TCP
Denis Expires 24 January 2027 [Page 33]
Internet-Draft DNSCrypt July 2026
A relay MAY briefly cache a validated certificate response and replay
it for identical certificate queries, rewriting only the DNS
transaction ID; deployed relays cache certificate responses for a few
minutes.
Address validation is performed after decoding <server-ip>.
If the decoded address is an IPv4-mapped IPv6 address, the relay
applies the IPv4 policy to the embedded IPv4 address.
Relay operators SHOULD maintain an explicit allowlist or denylist of
target ranges.
At minimum, relays MUST reject targets that are not globally
routable, including unspecified, loopback, link-local, multicast,
private-use, unique-local, documentation, benchmarking, and other
special-use addresses.
These relay requirements ensure that anonymization does not
compromise the security properties of the underlying DNSCrypt
protocol.
Proper deployment requires additional operational considerations.
10.4. Operational Considerations
When using Anonymized DNSCrypt:
1. Clients should choose relays and servers operated by different
entities
2. Having relays and servers on different networks is recommended
3. Relay operators should:
* Refuse forwarding to reserved IP ranges [RFC1918]
* Restrict allowed server ports (typically only allowing port
443)
* Monitor for abuse
These operational guidelines help ensure that Anonymized DNSCrypt
deployments provide the intended privacy benefits while maintaining
security and preventing abuse.
Denis Expires 24 January 2027 [Page 34]
Internet-Draft DNSCrypt July 2026
11. Post-Quantum Key Exchange (PQDNSCrypt)
The key exchange described so far relies on X25519 [RFC7748], which a
sufficiently capable quantum computer would be able to break.
An attacker who records DNSCrypt traffic today could therefore
decrypt it once such a computer exists.
This section defines the PQ extension, which performs the key
exchange with a hybrid post-quantum mechanism while leaving the rest
of the protocol unchanged: the certificate system, the packet
framing, the authenticated encryption, the nonces, the padding
philosophy, and Anonymized DNSCrypt all carry over.
A DNSCrypt deployment that uses this extension is referred to as
PQDNSCrypt.
PQ is introduced as a new encryption system version (<es-version>
0x00 0x03) inside the existing version 2 certificate format.
It is not a new major protocol version, and it does not change the
certificate lookup name.
A resolver MAY advertise a PQ certificate alongside a classical
certificate under the same provider name, and a client that does not
implement PQ ignores the <es-version> value it does not recognize,
exactly as already required.
The values that PQ introduces, namely the <es-version>, the resume
magic, the ticket parameters, and the profile identifiers, are
provisional assignments used by this document and by the test vectors
in Appendix 3.
They are expected to be confirmed before publication.
11.1. Key Encapsulation Instead of Key Agreement
Classical DNSCrypt uses a non-interactive key agreement: the resolver
publishes an X25519 public key in its certificate, the client places
its own X25519 public key in <client-pk>, and both sides compute the
same shared secret.
A post-quantum key encapsulation mechanism (KEM) does not offer a
non-interactive key agreement, but it fits the same single-message
exchange.
The resolver generates a KEM key pair and publishes the public
(encapsulation) key in the <resolver-pk> field of its certificate.
Denis Expires 24 January 2027 [Page 35]
Internet-Draft DNSCrypt July 2026
The client runs the KEM encapsulation against <resolver-pk>,
obtaining a ciphertext and a shared secret, and places the ciphertext
in the <client-pk> field.
The resolver runs the KEM decapsulation on the received ciphertext
using its secret key and recovers the same shared secret.
The <client-pk> field therefore carries a KEM ciphertext rather than
a client public key, and its length is determined by the <es-version>
of the chosen certificate; the PQ text refers to the value carried in
this field as <client-kex>.
The resolver remains stateless: it derives the shared secret from a
single client message, with no per-client state.
Everything after the shared secret is shared with classical DNSCrypt,
with the small additions described in this section.
PQ uses X-Wing [I-D.connolly-cfrg-xwing-kem], a hybrid KEM that
combines ML-KEM-768 [FIPS203] with X25519 [RFC7748].
Being a hybrid, the shared secret remains secure as long as either
ML-KEM-768 or X25519 is unbroken, which protects against both a
future quantum break of X25519 and an unexpected weakness in ML-KEM-
768.
The X-Wing encapsulation key is 1216 bytes, the ciphertext is 1120
bytes, and the shared secret is 32 bytes.
11.2. PQ Certificates
A PQ certificate uses the version 2 certificate format without
modification.
The <es-version> field is 0x00 0x03, and the <resolver-pk> field
holds the 1216-byte X-Wing encapsulation key.
The <client-magic> retains its role as a unique 8-byte certificate
selector that MUST NOT begin with seven zero bytes; because a KEM
ciphertext is freshly generated for every query, <client-magic> is an
opaque identifier and is never a truncated public key.
The Ed25519 signature input is unchanged.
It MUST cover (<resolver-pk> <client-magic> <serial> <ts-start> <ts-
end> <extensions>), exactly as for classical certificates, so that
provider signing procedures do not require a second code path.
Denis Expires 24 January 2027 [Page 36]
Internet-Draft DNSCrypt July 2026
The PQ profile metadata is authenticated through the already-signed
<extensions> field, which for a PQ certificate contains a profile
extension:
<pq-profile-ext> ::= "PQD" <ext-version> <es-version> <kdf-id>
<aead-id> <resolver-pk-len> <client-kex-len>
where <ext-version> is 0x01, <kdf-id> is 0x01 for HKDF-SHA256
[RFC5869], <aead-id> is 0x01 for the XChaCha20_DJB-Poly1305
construction of Appendix 1, and <resolver-pk-len> and <client-kex-
len> are the encapsulation-key and ciphertext lengths as two-byte
big-endian integers.
A client implementing PQ MUST require this extension on a PQ
certificate and MUST reject the certificate if the <es-version> on
the wire or the field lengths disagree with the signed copies in the
extension.
The existing signature already provides implicit integrity for <es-
version>, because <resolver-pk> is signed and its length follows from
<es-version>: altering the version shifts the signed region and
causes verification to fail, as long as distinct encryption systems
use distinct <resolver-pk> lengths.
The signed profile extension makes the binding explicit and preserves
it should a future encryption system reuse an existing length.
PQ certificates are approximately 1.3 KB before DNS TXT record
framing.
A single 1320-byte PQ certificate requires six TXT character-strings
and therefore about 1338 bytes as one answer RR; a response
containing one classical 124-byte certificate and one PQ certificate
is typically about 1.5 KB, depending on the provider name.
A response with two classical certificates and two PQ certificates is
typically about 3.0 KB.
A response with one classical certificate and three PQ certificates
will normally exceed 4096 octets.
A certificate response that contains a PQ certificate exceeds 512
bytes, so retrieval relies on a sufficiently padded UDP query, TCP
[RFC7766], or both.
A 4096-octet DNS response is a useful upper bound for certificate
responses, but it is not a fragmentation-avoidance target.
Denis Expires 24 January 2027 [Page 37]
Internet-Draft DNSCrypt July 2026
Operators that need maximum UDP robustness SHOULD use a lower target;
however, one PQ certificate already exceeds the common 1232-octet UDP
payload target once DNS framing is included.
11.3. Certificate Retrieval Amplification
Certificate retrieval is an unauthenticated DNS query, and PQ
certificates are much larger than classical ones, so a resolver that
returns one or more PQ certificates over UDP could be abused as a
traffic amplifier in response to queries with a spoofed source
address.
For compatibility with deployed DNSCrypt v2 clients and resolvers, a
resolver MAY return the small classical certificate response to an
ordinary UDP certificate query.
A resolver MUST NOT add PQ certificates or other large certificate
records to a UDP certificate response unless the complete response is
no larger than the request that triggered it.
A client retrieving PQ certificates over UDP therefore MUST pad its
certificate query to at least the size of the expected response,
exactly as a query that carries a ciphertext is already large enough
to cover its response.
The advertised EDNS(0) [RFC6891] UDP payload size is a fragmentation-
avoidance hint and MUST NOT be used as the amplification limit,
because a spoofed query can advertise an arbitrarily large buffer
while remaining small.
To let a client size that padding, a resolver SHOULD keep its UDP
certificate set small and predictable.
For relay-compatible PQ deployments, resolvers SHOULD use the
following certificate sets:
* Normal steady state: one classical certificate and one PQ
certificate, typically about 1.5 KB.
* Rollover window: two classical certificates and two PQ
certificates, typically about 3.0 KB.
Resolvers SHOULD NOT exceed the rollover certificate set over UDP,
and SHOULD keep certificate responses below 4096 octets.
A client cannot tell from outside whether a rotation is in progress.
A client retrieving PQ certificates over UDP therefore MUST pad its
certificate query to cover the rollover set rather than only the
Denis Expires 24 January 2027 [Page 38]
Internet-Draft DNSCrypt July 2026
steady-state set; otherwise it silently drops to the classical
certificate for the duration of every rollover window. This padding
exceeds common fragmentation-avoidance targets, but clients SHOULD
try UDP first because fragmented UDP works on most paths, and retry
over TCP only after timeout or truncation.
If the certificate response containing the PQ set would be larger
than the request, the resolver MUST NOT return that oversized PQ
response over UDP; it SHOULD instead return the classical certificate
response with the TC flag set, so a classical-only client can proceed
while a PQ-capable client learns that more certificates may be
available.
Operators MAY serve the classical certificate over UDP while
requiring a padded query or TCP for larger PQ certificate sets.
This affects neither the certificate format nor the lookup name.
Because a resolver can withhold PQ certificates from a truncated UDP
response, a PQ-capable client MUST honor the TC flag on a certificate
response and retry the certificate query over TCP when TCP to the
resolver is available.
A client that ignores the TC flag would only ever observe the
certificates present in the UDP response and could silently fail to
use PQ even against a resolver that supports it.
11.4. PQ Key Derivation
For a PQ query, the shared secret is the 32-byte X-Wing shared
secret.
It is not used directly as the encryption key.
Instead, both parties derive <shared-key> with HKDF-SHA256 [RFC5869],
binding the certificate context and the ciphertext:
cert-context ::= "DNSCrypt-PQ-v1" <es-version>
<protocol-minor-version> <resolver-pk>
<client-magic> <serial> <ts-start> <ts-end>
<extensions>
<shared-key> ::= HKDF-SHA256(IKM = <kem-ss>,
salt = <es-version> <client-magic>,
info = cert-context <client-kex>,
L = 32)
Denis Expires 24 January 2027 [Page 39]
Internet-Draft DNSCrypt July 2026
where <kem-ss> is the X-Wing shared secret and <client-kex> is the
content of the <client-pk> field, that is, the X-Wing ciphertext.
Binding <es-version> and <client-magic> separates keys across
certificates and any future encryption system; binding <resolver-pk>,
<serial>, and the validity timestamps ties the key to the exact
signed certificate; binding <client-kex> ties it to the precise
encapsulation.
The derived <shared-key> is then used with the XChaCha20_DJB-Poly1305
construction of Appendix 1 and the existing 24-byte nonce
construction: 12 client-chosen bytes followed by 12 zero bytes for
queries, and 12 client-chosen bytes followed by 12 resolver-chosen
bytes for responses.
11.5. PQ Query and Response Format
A PQ query uses the <dnscrypt-query> structure without modification;
only the length of <client-pk> changes, to the 1120-byte X-Wing
ciphertext.
A PQ response uses the <dnscrypt-response> structure without
modification on the wire, but the decrypted payload begins with a
short control block ahead of the unmodified DNS response:
<pq-response-plain> ::= <control-len> <control>
<resolver-response> <resolver-response-pad>
<control-len> is a two-byte big-endian length.
When it is zero, <control> is absent and the DNS response begins
immediately after the length.
When it is nonzero, <control> carries PQ control data, currently a
stateless resumption ticket.
The response padding is computed over the whole <control-len>
<control> <resolver-response> plaintext, so the decrypted payload
keeps the usual length alignment.
Over UDP, the complete encrypted packet is subject to the response-
size rule, so the <control-len> field, the <control> block, and the
padding all count against the size of the query that triggered the
response.
Denis Expires 24 January 2027 [Page 40]
Internet-Draft DNSCrypt July 2026
When that budget is too tight to include a control block, the
resolver MUST send the response with <control-len> zero, withholding
ticket issuance or renewal, before resorting to DNS truncation: a
withheld ticket costs at most one future key exchange, while a
truncated response always costs the client a TCP round trip.
A PQ client removes the control block after decryption and forwards
the unmodified DNS response.
Because the shared secret is symmetric, the resolver needs no
additional KEM operation to encrypt a response.
11.6. Padding and Transport
A PQ query that carries a ciphertext includes roughly 1.1 KB in
<client-pk>, so it is always far larger than its response.
The minimum query target defined for client queries over UDP exists
to prevent amplification, and that concern does not apply to a query
that is already this large.
A PQ query that carries a ciphertext is therefore not subject to the
256-byte minimum target; it only needs valid ISO/IEC 7816-4 padding
and should avoid unnecessary fragmentation.
A resumed query, described below, carries a small ticket instead of a
ciphertext, so it uses the regular UDP query-size target, initially
256 bytes for the complete DNSCrypt packet.
PQ queries and responses MUST be supported over TCP [RFC7766], and
TCP is a first-class transport for PQ rather than only a fallback.
A client SHOULD use a configurable UDP payload size target, 1232
bytes by default, and SHOULD use TCP when a query would exceed it.
A PQ query that carries a ciphertext is approximately 1220 bytes,
which fits within a single unfragmented datagram on common paths but
can exceed 1232 bytes once the Anonymized DNSCrypt prefix is added;
in that case the client SHOULD use TCP.
11.7. Stateless Resumption
Performing a KEM decapsulation for every query is significantly more
expensive than the classical X25519 operation, and because every
ciphertext is distinct there is no shared-key cache to amortize it.
Denis Expires 24 January 2027 [Page 41]
Internet-Draft DNSCrypt July 2026
To control this cost without keeping per-client state, PQ defines
stateless resumption: after an initial query that carries a
ciphertext, the resolver issues an opaque ticket that lets subsequent
queries skip both the ciphertext and the decapsulation.
A resolver maintains one or more server-wide ticket keys, denoted TK.
A TK is shared by all processes answering for a given certificate and
is rotated independently of client traffic.
A resolver MAY retain a previous TK for a short overlap so that
outstanding tickets continue to verify, but the overlap MUST NOT
exceed the advertised ticket lifetime.
11.7.1. Issuing a Ticket
After a PQ query that carries a ciphertext has been decrypted, both
parties hold <shared-key>.
They derive a resumption secret:
resume-secret ::= HKDF-SHA256(IKM = <shared-key>,
salt = <client-magic> <client-nonce>,
info = "DNSCrypt-PQ-resume-secret-v1",
L = 32)
The resolver seals the resumption secret and the metadata needed to
validate it later under TK:
ticket-plain ::= resume-secret <es-version> <client-magic>
<serial> <ts-end> <ticket-expiry>
<profile-extension-hash>
ticket ::= <ticket-key-id> <ticket-nonce>
AE(TK, <ticket-nonce>, ticket-plain)
The fields used for ticket issuance are:
* <ticket-key-id>: 4 bytes identifying the resolver ticket key TK.
* <ticket-nonce>: 24 bytes used as the nonce for sealing ticket-
plain.
* <ticket-expiry>: 4-byte big-endian Unix timestamp.
* <profile-extension-hash>: SHA-256(<extensions>), 32 bytes.
Denis Expires 24 January 2027 [Page 42]
Internet-Draft DNSCrypt July 2026
The ticket is opaque, resolver-private state: its internal format and
AEAD are an implementation choice and never need to interoperate
between resolvers.
This document's reference construction reuses the XChaCha20_DJB-
Poly1305 AEAD of Appendix 1 with no associated data; <ticket-key-id>
selects the ticket key, so its integrity follows from decryption
failing under the wrong key, and a dedicated TK keeps ticket sealing
separate from query traffic.
The client stores the ticket together with the resume-secret it
derived and an expiry it computes locally from the advertised
<ticket-lifetime> and the time the ticket was received, further
capped by the certificate expiry and local policy; the <ticket-
expiry> field itself is sealed inside the ticket and not readable by
the client.
The ticket is delivered in the response control block:
<control> ::= "PQDR" <control-version> <ticket-lifetime>
<ticket-len> <ticket>
The control fields are:
* "PQDR": the four bytes 0x50 0x51 0x44 0x52.
* <control-version>: one byte. This revision uses 0x01.
* <ticket-lifetime>: 4-byte big-endian lifetime in seconds.
* <ticket-len>: 2-byte big-endian length of <ticket> in bytes.
* <ticket>: the opaque ticket bytes.
A resolver SHOULD issue a ticket in the first PQ response and MAY
renew it on later responses; a client SHOULD adopt the most recent
valid ticket it receives.
A captured ticket is of no use on its own: deriving the per-query key
requires either the resume-secret, which only the client holds, or
TK, which only the resolver holds.
11.7.2. Resuming
A resumed query uses a distinct packet form, with the resume magic in
place of <client-magic> and the ticket in place of <client-pk>:
Denis Expires 24 January 2027 [Page 43]
Internet-Draft DNSCrypt July 2026
<pq-resume-query> ::= <resume-magic> <ticket-len> <ticket>
<client-nonce> <encrypted-query>
<resume-magic> is the reserved 8-byte value 0x50 0x51 0x52 0x65 0x73
0x75 0x6d 0x65 ("PQResume").
It MUST NOT collide with any valid <client-magic>, with <resolver-
magic>, with the Anonymized DNSCrypt <anon-magic>, or with seven
leading zero bytes.
The resumed-query <ticket-len> is a 2-byte big-endian length of
<ticket> in bytes.
On receiving a resumed query, the resolver locates the ticket key
from <ticket-key-id>, opens the ticket, and rejects the query if the
ticket cannot be opened, is expired, or if any sealed certificate-
context field does not match an acceptable current certificate.
The sealed certificate-context fields are <es-version>, <client-
magic>, <serial>, <ts-end>, and <profile-extension-hash>; <profile-
extension-hash> is compared to SHA-256(<extensions>) for the matched
certificate.
It then derives the per-query key:
<shared-key> ::= HKDF-SHA256(IKM = resume-secret,
salt = <client-magic> <client-nonce>,
info = "DNSCrypt-PQ-resumed-query-v1"
SHA-256(<ticket>),
L = 32)
The client performs the same derivation.
In this derivation, <client-nonce> is the fresh nonce carried in the
resumed query itself, not the nonce of the query that produced the
ticket, and <client-magic> is the value from the certificate under
which the ticket was issued, which the client keeps together with the
ticket and the resume-secret.
The nonce construction is unchanged.
Each resumed query thus uses a fresh key derived from its own
<client-nonce>; clients MUST still use a distinct <client-nonce> for
each resumed query, because repeating it would repeat both the key
and the AEAD nonce.
Denis Expires 24 January 2027 [Page 44]
Internet-Draft DNSCrypt July 2026
Responses to resumed queries reuse this per-query key, so the
<resolver-nonce> MUST be unique per response and MUST NOT be all NUL
bytes; a random 12-byte value satisfies this. A replayed resumed
query re-derives the same key, and answering it twice with the same
<resolver-nonce> but a different response plaintext would reuse a key
and nonce pair.
Responses to resumed queries use the <pq-response-plain> layout like
any PQ response; a resolver that issues no new ticket sets <control-
len> to zero.
If a ticket cannot be opened or validated, the resolver MUST silently
drop the query, with no response distinguishable from any other
dropped query.
A client that receives no response retries with a query that carries
a ciphertext, obtaining a fresh ticket.
11.7.3. Resumption Considerations
A ticket bounds forward secrecy for resumed traffic: an attacker who
records resumed queries and later obtains a TK can open every ticket
sealed under that TK, expired or not, and decrypt the recorded
queries, but never the queries that carried a ciphertext. Destroying
each TK when it is rotated out is what limits this exposure, so
ticket keys MUST be erased promptly at rotation.
The ticket lifetime SHOULD be short and MUST NOT exceed the resolver
certificate lifetime or the ticket-key lifetime.
A ticket is also a linkable handle for its lifetime; a client that
prioritizes unlinkability, in particular over Anonymized DNSCrypt,
SHOULD send queries that carry a ciphertext rather than resuming.
Because a ticket is a stable identifier that a client reuses across
queries, a resolver that observes the same ticket from more than one
source address can link those addresses to a single client.
A client SHOULD therefore treat a ticket as bound to the network on
which it was obtained: when it moves to a new network, it SHOULD
discard the stored ticket and resume-secret and start over with a
query that carries a ciphertext, so the new network's address cannot
be tied to the previous one through a reused ticket.
Resumed queries are replayable to the same extent as any stateless
DNSCrypt query, and clients discard stale or duplicate responses with
outstanding-query nonce tracking as usual.
Denis Expires 24 January 2027 [Page 45]
Internet-Draft DNSCrypt July 2026
A resolver implementing PQ SHOULD support ticket issuance and
resumption, since high query volumes make per-query decapsulation
costly.
A resolver SHOULD rate-limit decapsulation of queries that carry a
ciphertext and prioritize valid resumed traffic under load.
11.8. PQ and Anonymized DNSCrypt
Anonymized DNSCrypt relays forward opaque DNSCrypt queries and
require no changes for PQ.
A query that carries a ciphertext keeps the classical query shape
with a larger <client-pk> field, and a resumed query uses the resume
shape above; both are opaque to a relay.
The relay check that an encrypted response is no larger than the
query is satisfied automatically for queries that carry a ciphertext,
because they are large.
A resumed query is small, so a client using Anonymized DNSCrypt MUST
keep enough padding on the inner resumed query for the relay's
encrypted-response size check to pass.
If the client connects to the relay over TCP, the relay still
forwards the inner query upstream over UDP, so the inner query size
requirement remains.
Certificate retrieval through a relay is different: the relay
forwards the certificate query to the resolver over UDP and forwards
a matching certificate response back to the client, and it applies
the same response-size check, dropping any response larger than the
query it relayed.
A client retrieving a PQ certificate over UDP through a relay
therefore MUST pad its certificate query to at least the size of the
expected certificate response, as described in Certificate Retrieval
Amplification, so the response passes both the resolver's and the
relay's anti-amplification check.
A client that does not, or cannot, pad far enough receives only the
certificates that fit within the inner UDP query size, typically a
classical certificate with the TC flag set; if even that response is
larger than the inner query, the relay drops it.
Retrying over TCP to an Anonymized DNSCrypt relay does not make the
relay use TCP upstream: relays still forward the inner certificate
query to the resolver over UDP.
Denis Expires 24 January 2027 [Page 46]
Internet-Draft DNSCrypt July 2026
Nevertheless, carrying a rollover-sized inner certificate query over
the client-to-relay TCP connection avoids IP fragmentation on that
leg while giving the relay a large enough request to forward upstream
and a sufficient anti-amplification budget for the response. The
inner query remains EDNS(0)-padded to the expected UDP response size;
only its transport to the relay changes.
Therefore, after a rollover-sized UDP attempt times out or returns a
truncated certificate response, a client retrieving certificates
through a relay SHOULD retry over TCP to the relay with an inner
query large enough for the expected UDP certificate response.
Alternatively, it can retrieve certificates directly from the
resolver over TCP before using the relay for encrypted queries, with
the associated privacy tradeoff.
11.9. PQ Downgrade Protection
An on-path attacker cannot forge a certificate, but it can drop the
PQ records from an unauthenticated certificate response, leaving only
a classical certificate and pushing the client onto a quantum-
vulnerable exchange.
A signature cannot prevent deletion.
A client that has been provisioned with the knowledge that a resolver
supports PQ, for example through a flag in the DNS stamp that already
carries the provider name and public key, MUST NOT fall back to a
classical <es-version> for that resolver.
A client without such provisioning MAY fall back, accepting the
classical risk.
11.10. PQ Security Considerations
Confidentiality against a future quantum adversary holds as long as
either ML-KEM-768 or X25519 is unbroken, because X-Wing is a hybrid.
Resolver authentication is as in classical DNSCrypt: the client
encapsulates to a signed encapsulation key, and only the holder of
the corresponding secret key can recover the shared secret and
produce an authenticated response.
The KEM ciphertext is not separately authenticated and does not need
to be.
Denis Expires 24 January 2027 [Page 47]
Internet-Draft DNSCrypt July 2026
X-Wing, through ML-KEM-768, uses implicit rejection: a malformed but
correctly sized ciphertext yields a pseudo-random shared secret
rather than an error, so a tampered ciphertext produces a different
key and authentication fails.
A resolver MUST drop such a query exactly as it drops any query that
fails authentication, and the outcome on the wire MUST NOT reveal,
through a distinct response, error, or timing, whether decapsulation,
key derivation, or authentication failed; otherwise the resolver
becomes a decapsulation oracle.
KEM and X25519 operations SHOULD be constant-time with respect to
secret data.
Forward secrecy for queries that carry a ciphertext has the same
granularity as classical resolver-key rotation, since the resolver
KEM key is short-term and the client's encapsulation randomness is
fresh per query.
For resumed queries, recorded traffic remains decryptable until every
TK able to open its ticket has been destroyed, so their forward
secrecy follows the ticket-key lifetime.
Nonce uniqueness is required as in classical DNSCrypt.
For queries that carry a ciphertext, each has an independent key, so
cross-query collisions cannot occur; for resumed queries the per-
query key derivation uses <client-nonce>, so clients MUST keep it
unique for the lifetime of a ticket.
12. IANA Considerations
This document has no IANA actions.
13. Appendix 1: The Box-XChaChaPoly Algorithm
The Box-XChaChaPoly algorithm combines the X25519 [RFC7748] key
exchange mechanism with a variant of the ChaCha20-Poly1305
construction specified in [RFC8439].
13.1. Conventions and Definitions
* x[a..]: the subarray of x starting at index a, and extending to
the last index of x
* x[a..b]: the subarray of x starting at index a and ending
immediately before index b.
Denis Expires 24 January 2027 [Page 48]
Internet-Draft DNSCrypt July 2026
* LOAD32_LE(p): returns a 32-bit unsigned integer from the 4-byte
array p
* STORE32_LE(p, x): stores the 32-bit unsigned integer x into the
4-byte array p
13.2. HChaCha20
HChaCha20 is the subkey derivation step used by the extended-nonce
ChaCha20 construction in this appendix.
The HChaCha20 function takes the following input parameters:
* <k>: secret key
* <in>: a 128-bit input
and returns a 256-bit keyed hash.
The function can be implemented using an existing IETF-compliant
ChaCha20 implementation as follows:
block_bytes = ChaCha20(msg={0}**64, nonce=in[4..16],
counter=LOAD32_LE(in[0..4]), key=k)
block_out[0] = LOAD32_LE(block_bytes[ 0..][0..4]) - 0x61707865
block_out[1] = LOAD32_LE(block_bytes[ 4..][0..4]) - 0x3320646e
block_out[2] = LOAD32_LE(block_bytes[ 8..][0..4]) - 0x79622d32
block_out[3] = LOAD32_LE(block_bytes[12..][0..4]) - 0x6b206574
block_out[4] =
LOAD32_LE(block_bytes[48..][0..4]) - LOAD32_LE(in[ 0..][0..4])
block_out[5] =
LOAD32_LE(block_bytes[52..][0..4]) - LOAD32_LE(in[ 4..][0..4])
block_out[6] =
LOAD32_LE(block_bytes[56..][0..4]) - LOAD32_LE(in[ 8..][0..4])
block_out[7] =
LOAD32_LE(block_bytes[60..][0..4]) - LOAD32_LE(in[12..][0..4])
for i in 0..8:
STORE32_LE(out[i * 4..][0..4], block_out[i])
return out
13.3. Test Vector For The HChaCha20 Block Function
Denis Expires 24 January 2027 [Page 49]
Internet-Draft DNSCrypt July 2026
k: 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
in: 000102030405060708090a0b0c0d0e0f
out: 51e3ff45a895675c4b33b46c64f4a9ace110d34df6a2ceab486372bacbd3eff6
13.4. ChaCha20_DJB
As opposed to the version standardized for IETF protocols, ChaCha20
was originally designed to have a 8 byte nonce.
For the needs of TLS, [RFC8439] changed this by setting N_MIN and
N_MAX to 12, at the expense of a smaller internal counter.
DNSCrypt uses ChaCha20 as originally specified, with N_MIN = N_MAX =
8.
We refer to this variant as ChaCha20_DJB.
The internal counter in ChaCha20_DJB is 4 bytes larger than ChaCha20.
There are no other differences between ChaCha20_DJB and ChaCha20.
13.5. XChaCha20_DJB
XChaCha20_DJB can be constructed from an existing ChaCha20
implementation and the HChaCha20 function.
All that needs to be done is:
1. Pass the key and the first 16 bytes of the 24-byte nonce to
HChaCha20 to obtain the subkey.
2. Use the subkey and remaining 8 byte nonce with ChaCha20_DJB.
13.6. XChaCha20_DJB-Poly1305
XChaCha20 is a stream cipher and offers no integrity guarantees
without being combined with a MAC algorithm (e.g. Poly1305).
XChaCha20_DJB-Poly1305 adds an authentication tag to the ciphertext
encrypted with XChaCha20_DJB.
It is the combined mode used by the NaCl secretbox and crypto_box
constructions, instantiated with XChaCha20_DJB.
Denis Expires 24 January 2027 [Page 50]
Internet-Draft DNSCrypt July 2026
The one-time Poly1305 key is taken from the start of the keystream,
and the message is encrypted with the keystream that immediately
follows it.
No separate keystream block is reserved for the Poly1305 key, so this
layout differs from the AEAD of [RFC8439], where the message starts
at block counter 1 and the rest of the first keystream block is
discarded.
Concretely, for a key <k>, nonce <n>, and message <m>:
* <k>: encryption key
* <n>: 24-byte nonce
* <m>: message to encrypt
* <keystream>: the XChaCha20_DJB keystream produced from <k> and
<n>, starting at block counter 0.
* <poly-key>: <keystream>[0..32], the one-time Poly1305 key. These
bytes are not transmitted.
* <ct>: <m> XOR <keystream>[32..32 + length(<m>)], the ciphertext.
* <tag>: Poly1305(<poly-key>, <ct>), the 16-byte tag.
* XChaCha20_DJB-Poly1305(<k>, <n>, <m>): <tag> || <ct>
Equivalently, XChaCha20_DJB is run over the buffer <zero32> || <m>,
where <zero32> is 32 NUL bytes, starting at block counter 0; the
first 32 output bytes are taken as <poly-key>, and the remaining
length(<m>) bytes are <ct>.
13.7. The Box-XChaChaPoly Algorithm
The Box-XChaChaPoly algorithm combines the key exchange mechanism
X25519 defined [RFC7748] with the XChaCha20_DJB-Poly1305
authenticated encryption algorithm.
* <k>: encryption key
* <m>: message to encrypt
* <n>: 24-byte nonce
* <pk>: recipient's public key
Denis Expires 24 January 2027 [Page 51]
Internet-Draft DNSCrypt July 2026
* <sk>: sender's secret key
* <zero16>: 16 NUL bytes
* <sk'>: HChaCha20(X25519(<pk>, <sk>), <zero16>), the shared key
* Box-XChaChaPoly(pk, sk, n, m): XChaCha20_DJB-Poly1305(<sk'>, <n>,
<m>)
14. Appendix 2: DNSCrypt Test Vectors
This appendix provides complete, reproducible test vectors for the
regular DNSCrypt protocol with the Box-XChaChaPoly encryption system
of Appendix 1, that is, <es-version> 0x00 0x02: X25519 key exchange,
the XChaCha20_DJB-Poly1305 AEAD, and Ed25519 certificate signatures.
All randomness is pinned so the vectors are reproducible.
Every value is given in full as a hexadecimal string, wrapped to 32
bytes per line.
The field and byte order of each artifact matches the Protocol
Components and Certificates sections.
These vectors were cross-checked byte for byte against the dnscrypt-
proxy reference implementation.
14.1. Pinned Inputs
The secret keys below are the raw 32-byte X25519 scalars as stored by
an implementation; X25519 clamps them internally.
The provider signing key is given as its 32-byte Ed25519 seed.
Denis Expires 24 January 2027 [Page 52]
Internet-Draft DNSCrypt July 2026
+===============================+========+=========================+
| Input | Length | Value |
+===============================+========+=========================+
| provider Ed25519 signing seed | 32 | 00 01 02 ... 1f |
+-------------------------------+--------+-------------------------+
| resolver X25519 secret key | 32 | 20 21 22 ... 3f |
+-------------------------------+--------+-------------------------+
| client X25519 secret key | 32 | 40 41 42 ... 5f |
+-------------------------------+--------+-------------------------+
| <client-magic> | 8 | b1 b2 b3 b4 b5 b6 b7 b8 |
+-------------------------------+--------+-------------------------+
| <es-version> | 2 | 00 02 |
+-------------------------------+--------+-------------------------+
| <protocol-minor-version> | 2 | 00 00 |
+-------------------------------+--------+-------------------------+
| <serial> | 4 | 00 00 00 01 |
+-------------------------------+--------+-------------------------+
| <ts-start> | 4 | 68 00 00 00 |
+-------------------------------+--------+-------------------------+
| <ts-end> | 4 | 68 01 51 80 |
+-------------------------------+--------+-------------------------+
| query <client-nonce> | 12 | a0 a1 a2 ... ab |
+-------------------------------+--------+-------------------------+
| response <resolver-nonce> | 12 | c0 c1 c2 ... cb |
+-------------------------------+--------+-------------------------+
| <extensions> | 0 | empty |
+-------------------------------+--------+-------------------------+
Table 1
<client-magic> is chosen by the resolver and carried in the
certificate; the client copies it verbatim into the first 8 bytes of
every query.
<ts-start> and <ts-end> span exactly 86400 seconds (a one-day
validity window).
The fixed protocol constants are <cert-magic> = 44 4e 53 43, <es-
version> = 00 02, and <resolver-magic> = 72 36 66 6e 76 57 6a 38.
The example DNS messages are a query and its answer for
www.example.com:
Denis Expires 24 January 2027 [Page 53]
Internet-Draft DNSCrypt July 2026
dns-query (33 bytes), id 0x1234, RD set, A? www.example.com IN:
12340100000100000000000003777777076578616d706c6503636f6d00000100
01
dns-response (49 bytes), A 93.184.216.34, TTL 3600:
12348180000100010000000003777777076578616d706c6503636f6d00000100
01c00c0001000100000e1000045db8d822
14.2. Public Keys and Shared Key
provider-ed25519-pk = Ed25519 public key for the signing seed:
03a107bff3ce10be1d70dd18e74bc09967e4d6309ba50d5f1ddc8664125531b8
resolver-pk = X25519 base-point mult of the resolver secret key:
358072d6365880d1aeea329adf9121383851ed21a28e3b75e965d0d2cd166254
client-pk = X25519 base-point mult of the client secret key:
79a631eede1bf9c98f12032cdeadd0e7a079398fc786b88cc846ec89af85a51a
x25519-shared-point = X25519(client-sk, resolver-pk)
= X25519(resolver-sk, client-pk):
04c304fb1ca83cee75e206344231f33797e07d9929db670994b7c6fbeb1dc255
shared-key = HChaCha20(key = x25519-shared-point, in = 16 NUL bytes):
335d32f2d65e6623cbbd05b6539c9575fee16cb5405fe839ab4bd291fdf13262
The same shared-key is computed by the client from (client-sk,
resolver-pk) and by the resolver from (resolver-sk, client-pk).
14.3. Certificate
The signature covers <resolver-pk> <client-magic> <serial> <ts-start>
<ts-end> <extensions>, with <extensions> empty in this protocol
version:
signed input (52 bytes):
358072d6365880d1aeea329adf9121383851ed21a28e3b75e965d0d2cd166254
b1b2b3b4b5b6b7b8000000016800000068015180
signature = Ed25519.Sign(provider signing seed, signed input) (64 bytes):
3a570ea17f47b80217977fbb455840bfd50ab32f5fbf2aabc173a6a49b7a49ca
55362a6c5dec47657cf515e9f99382a316dfecd964b94d1c4659cac45961400c
The full certificate, as carried in a TXT record, is 124 bytes:
Denis Expires 24 January 2027 [Page 54]
Internet-Draft DNSCrypt July 2026
+========+==========================+========+=================+
| Offset | Field | Length | Value |
+========+==========================+========+=================+
| 0 | <cert-magic> | 4 | 44 4e 53 43 |
+--------+--------------------------+--------+-----------------+
| 4 | <es-version> | 2 | 00 02 |
+--------+--------------------------+--------+-----------------+
| 6 | <protocol-minor-version> | 2 | 00 00 |
+--------+--------------------------+--------+-----------------+
| 8 | <signature> | 64 | 3a 57 ... 40 0c |
+--------+--------------------------+--------+-----------------+
| 72 | <resolver-pk> | 32 | 35 80 ... 62 54 |
+--------+--------------------------+--------+-----------------+
| 104 | <client-magic> | 8 | b1 b2 b3 b4 b5 |
| | | | b6 b7 b8 |
+--------+--------------------------+--------+-----------------+
| 112 | <serial> | 4 | 00 00 00 01 |
+--------+--------------------------+--------+-----------------+
| 116 | <ts-start> | 4 | 68 00 00 00 |
+--------+--------------------------+--------+-----------------+
| 120 | <ts-end> | 4 | 68 01 51 80 |
+--------+--------------------------+--------+-----------------+
Table 2
certificate (124 bytes):
444e5343000200003a570ea17f47b80217977fbb455840bfd50ab32f5fbf2aab
c173a6a49b7a49ca55362a6c5dec47657cf515e9f99382a316dfecd964b94d1c
4659cac45961400c358072d6365880d1aeea329adf9121383851ed21a28e3b75
e965d0d2cd166254b1b2b3b4b5b6b7b8000000016800000068015180
14.4. Certificate Retrieval
The certificate lookup name is 2.dnscrypt-cert.example.com.
With DNS transaction ID 0xabcd, RD set, one TXT/IN question, and no
EDNS(0) padding, the DNS request is:
certificate query (45 bytes):
abcd0100000100000000000001320d646e7363727970742d6365727407657861
6d706c6503636f6d0000100001
The successful response carrying the 124-byte certificate above is
182 bytes.
Denis Expires 24 January 2027 [Page 55]
Internet-Draft DNSCrypt July 2026
This is the classical certificate response used by deployed DNSCrypt
v2 resolvers: the flags word 0x8180 sets QR and RA, echoes RD from
the query, and leaves RCODE at 0. The TXT record TTL is an
operational choice, 86400 seconds in this vector.
If larger PQ certificate records are also available, a resolver can
return this classical response with the TC flag set when the complete
classical-plus-PQ response would exceed the triggering UDP request.
certificate response with one TXT answer (182 bytes):
abcd8180000100010000000001320d646e7363727970742d6365727407657861
6d706c6503636f6d0000100001c00c0010000100015180007d7c444e53430002
00003a570ea17f47b80217977fbb455840bfd50ab32f5fbf2aabc173a6a49b7a
49ca55362a6c5dec47657cf515e9f99382a316dfecd964b94d1c4659cac45961
400c358072d6365880d1aeea329adf9121383851ed21a28e3b75e965d0d2cd
166254b1b2b3b4b5b6b7b8000000016800000068015180
An EDNS(0)-padded UDP certificate query for the same question and
transaction ID can be built by setting ARCOUNT = 1 and appending one
OPT pseudo-RR with UDP payload size 4096 and a Padding option.
For a 512-byte request, the Padding option data is 452 NUL bytes:
base question length = 45
OPT pseudo-RR fixed header = 11
Padding option header = 4
Padding option data = 452
total request length = 512
OPT pseudo-RR:
00002910000000000001c8000c01c4 || (452 * 00)
14.5. Client Query (UDP)
For this fixed vector, the plaintext is the DNS query padded with
ISO/IEC 7816-4 to 256 bytes: one 0x80 byte followed by NUL bytes.
The complete encrypted DNSCrypt query is 324 bytes, which is above
the initial 256-byte UDP query-size target.
The 24-byte AEAD nonce is the 12-byte client nonce followed by 12 NUL
bytes.
Denis Expires 24 January 2027 [Page 56]
Internet-Draft DNSCrypt July 2026
padded query plaintext (256 bytes):
12340100000100000000000003777777076578616d706c6503636f6d00000100
0180000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
query AEAD nonce (24 bytes):
a0a1a2a3a4a5a6a7a8a9aaab000000000000000000000000
encrypted-query = tag (16) || ciphertext (256) (272 bytes):
2dae527c26386d5cd4e61152db6dd1812ff6aaf7644fc122afc70b1b580b18f1
0fbc26577abc759152cde31cd0afc5c5f452f8654815469723300819bed5a120
15c044b94d63ec1f79e48a23968e437feb8bb8720cf4e60a0499746190c8b3eb
83aeb0d858df77794270b861f86644502be0d22d6f0b2b132e9ca68538300c8d
68b8e3c48190cbbf96d602f38dfc3b4d642016ceeaf4bc2c2ded9483b9f9d4ee
d703a0bebc252add8822d4b9152e30670bcde9ea75a0e3e67ea576e9b1262bb2
b25b4f9432311b75a2238b34bf4f868da182b85dccb1762a703bba31d04d77b4
c57ec9039663959793677588b3a74ae409b0f16374dd64cbd6d47d801725b014
ce9ddaf6f1aa30688c8efcbfde1d5d1d
Query on the wire (324 bytes):
+========+===================+========+=========================+
| Offset | Field | Length | Value |
+========+===================+========+=========================+
| 0 | <client-magic> | 8 | b1 b2 b3 b4 b5 b6 b7 b8 |
+--------+-------------------+--------+-------------------------+
| 8 | <client-pk> | 32 | 79 a6 ... a5 1a |
+--------+-------------------+--------+-------------------------+
| 40 | <client-nonce> | 12 | a0 a1 ... ab |
+--------+-------------------+--------+-------------------------+
| 52 | <encrypted-query> | 272 | 2d ae ... d5 1d |
+--------+-------------------+--------+-------------------------+
Table 3
Denis Expires 24 January 2027 [Page 57]
Internet-Draft DNSCrypt July 2026
full query wire (324 bytes):
b1b2b3b4b5b6b7b879a631eede1bf9c98f12032cdeadd0e7a079398fc786b88c
c846ec89af85a51aa0a1a2a3a4a5a6a7a8a9aaab2dae527c26386d5cd4e61152
db6dd1812ff6aaf7644fc122afc70b1b580b18f10fbc26577abc759152cde31c
d0afc5c5f452f8654815469723300819bed5a12015c044b94d63ec1f79e48a23
968e437feb8bb8720cf4e60a0499746190c8b3eb83aeb0d858df77794270b861
f86644502be0d22d6f0b2b132e9ca68538300c8d68b8e3c48190cbbf96d602f3
8dfc3b4d642016ceeaf4bc2c2ded9483b9f9d4eed703a0bebc252add8822d4b9
152e30670bcde9ea75a0e3e67ea576e9b1262bb2b25b4f9432311b75a2238b34
bf4f868da182b85dccb1762a703bba31d04d77b4c57ec9039663959793677588
b3a74ae409b0f16374dd64cbd6d47d801725b014ce9ddaf6f1aa30688c8efcbf
de1d5d1d
14.6. Server Response (UDP)
The plaintext is the DNS response padded with ISO/IEC 7816-4 to 64
bytes.
The 24-byte AEAD nonce is the client nonce followed by the resolver
nonce.
padded response plaintext (64 bytes):
12348180000100010000000003777777076578616d706c6503636f6d00000100
01c00c0001000100000e1000045db8d822800000000000000000000000000000
response AEAD nonce (24 bytes):
a0a1a2a3a4a5a6a7a8a9aaabc0c1c2c3c4c5c6c7c8c9cacb
encrypted-response = tag (16) || ciphertext (64) (80 bytes):
f2670995c6d37c2f8d2016029dd5970b893de83c02815ece9b48d9fd0b0dca87
41674142fbd8e12c1120b111f366326aa71c89823a2931ac5c860dad49685ed6
cc22cc13e829d2e51d1c00ea64d1d39d
Response on the wire (112 bytes):
+========+======================+========+=========================+
| Offset | Field | Length | Value |
+========+======================+========+=========================+
| 0 | <resolver-magic> | 8 | 72 36 66 6e 76 57 6a 38 |
+--------+----------------------+--------+-------------------------+
| 8 | <nonce> | 24 | a0..ab (client) c0..cb |
| | | | (resolver) |
+--------+----------------------+--------+-------------------------+
| 32 | <encrypted-response> | 80 | f2 67 ... d3 9d |
+--------+----------------------+--------+-------------------------+
Table 4
Denis Expires 24 January 2027 [Page 58]
Internet-Draft DNSCrypt July 2026
full response wire (112 bytes):
7236666e76576a38a0a1a2a3a4a5a6a7a8a9aaabc0c1c2c3c4c5c6c7c8c9cacb
f2670995c6d37c2f8d2016029dd5970b893de83c02815ece9b48d9fd0b0dca87
41674142fbd8e12c1120b111f366326aa71c89823a2931ac5c860dad49685ed6
cc22cc13e829d2e51d1c00ea64d1d39d
14.7. Padding and Transport Notes
The vectors fix the padded plaintext lengths so they are
reproducible:
* The query plaintext is padded to 256 bytes for this vector.
Production clients can choose larger targets for the complete
encrypted DNSCrypt packet; for example, a client can target a 512-
byte-or-larger UDP packet and compute the plaintext padding after
subtracting DNSCrypt overhead.
* The response plaintext is padded to the smallest multiple of 64
that holds the response plus at least one padding byte, here 64
bytes. The exact response padding length is otherwise an
implementation choice, subject to the encrypted UDP response being
no larger than the encrypted query.
* Over TCP the encryption is identical, but each packet is prefixed
with a two-byte big-endian length, and the query padding length is
chosen at random as described in Query Processing. For the fixed
packets above, the 324-byte query is prefixed with 01 44, and the
112-byte response is prefixed with 00 70.
14.8. Negative Cases
These vectors pin the required failure behavior.
None of them produce a distinguishable on-the-wire signal beyond "no
response" or "certificate rejected".
1. Tampered ciphertext: flipping any byte of <encrypted-query> or
<encrypted-response> makes Poly1305 verification fail. The
receiver MUST drop the packet.
2. Bad padding: after a successful decryption, the plaintext MUST
end with a 0x80 byte followed by zero or more NUL bytes. A
plaintext that does not MUST be rejected.
3. Wrong <client-magic>: a query whose first 8 bytes do not match
the <client-magic> of any certificate the resolver currently
serves is not a DNSCrypt query for this resolver. The resolver
MUST NOT treat it as one.
Denis Expires 24 January 2027 [Page 59]
Internet-Draft DNSCrypt July 2026
4. Response nonce mismatch: the client MUST verify that the <client-
nonce> prefix (first 12 bytes) of the response nonce matches an
outstanding query, and otherwise drop the response.
5. Weak public key: if the X25519 shared point is the all-zero
value, the public key is of low order and the shared key MUST be
rejected.
6. Certificate outside its validity window: a certificate whose <ts-
start>/<ts-end> does not include the current time MUST NOT be
used, and among valid certificates the client picks the highest
<serial>.
15. Appendix 3: PQ Test Vector Structure
This appendix fixes the exact field order and byte order for PQ.
Long cryptographic outputs, namely KEM keys and ciphertexts, the
Ed25519 signature, AEAD outputs, and HKDF outputs, are left as
placeholders to be filled in by a reference implementation.
Everything structural is pinned here, so that two implementations
cannot disagree about layout even before the hex values exist.
All integers are big-endian.
Every AEAD operation is XChaCha20_DJB-Poly1305 as defined in
Appendix 1, with the 16-byte tag prepended to the ciphertext.
Every key derivation is HKDF-SHA256 [RFC5869].
Placeholders are written [name: N bytes]; the concrete values they
stand for appear in the Generated Values subsection at the end of
this appendix.
15.1. Provisional Assignments
The following values are the provisional assignments used by these
vectors.
They are normative for the vectors but expected to be confirmed
before publication.
Denis Expires 24 January 2027 [Page 60]
Internet-Draft DNSCrypt July 2026
+==========================+=======================================+
| Item | Value |
+==========================+=======================================+
| <es-version> (X-Wing) | 0x00 0x03 |
+--------------------------+---------------------------------------+
| <resume-magic> | 50 51 52 65 73 75 6d 65 ("PQResume") |
+--------------------------+---------------------------------------+
| <kdf-id> | 0x01 (HKDF-SHA256) |
+--------------------------+---------------------------------------+
| <aead-id> | 0x01 (XChaCha20_DJB-Poly1305) |
+--------------------------+---------------------------------------+
| ticket AEAD | XChaCha20_DJB-Poly1305, 24-byte nonce |
+--------------------------+---------------------------------------+
| <ticket-key-id> | 4 bytes |
+--------------------------+---------------------------------------+
| <ticket-nonce> | 24 bytes |
+--------------------------+---------------------------------------+
| <ticket-expiry> | 4-byte Unix timestamp |
+--------------------------+---------------------------------------+
| <ticket-lifetime> | 4-byte seconds |
+--------------------------+---------------------------------------+
| <profile-extension-hash> | SHA-256(<extensions>), 32 bytes |
+--------------------------+---------------------------------------+
Table 5
15.2. Pinned Inputs
All randomness is fixed so the vectors are reproducible.
Short values are given concretely; values produced by a primitive are
placeholders.
+===============================+========+=========================+
| Input | Length | Value |
+===============================+========+=========================+
| provider Ed25519 signing seed | 32 | 00 01 02 ... 1f |
+-------------------------------+--------+-------------------------+
| provider Ed25519 public key | 32 | [provider-pk: 32 bytes] |
+-------------------------------+--------+-------------------------+
| resolver X-Wing secret seed | 32 | 20 21 22 ... 3f |
+-------------------------------+--------+-------------------------+
| resolver X-Wing public key | 1216 | [resolver-pk: 1216 |
| | | bytes] |
+-------------------------------+--------+-------------------------+
| client X-Wing encapsulation | 64 | 40 41 42 ... 7f |
| seed | | |
+-------------------------------+--------+-------------------------+
Denis Expires 24 January 2027 [Page 61]
Internet-Draft DNSCrypt July 2026
| <es-version> | 2 | 00 03 |
+-------------------------------+--------+-------------------------+
| <protocol-minor-version> | 2 | 00 00 |
+-------------------------------+--------+-------------------------+
| <client-magic> | 8 | a1 b2 c3 d4 e5 f6 07 18 |
+-------------------------------+--------+-------------------------+
| <serial> | 4 | 00 00 00 01 |
+-------------------------------+--------+-------------------------+
| <ts-start> | 4 | 68 00 00 00 |
+-------------------------------+--------+-------------------------+
| <ts-end> | 4 | 68 01 51 80 |
+-------------------------------+--------+-------------------------+
| query <client-nonce> | 12 | b0 b1 b2 ... bb |
+-------------------------------+--------+-------------------------+
| response <resolver-nonce> | 12 | c0 c1 c2 ... cb |
+-------------------------------+--------+-------------------------+
| ticket key TK | 32 | 80 81 82 ... 9f |
+-------------------------------+--------+-------------------------+
| <ticket-key-id> | 4 | 00 00 00 01 |
+-------------------------------+--------+-------------------------+
| <ticket-nonce> | 24 | d0 d1 d2 ... e7 |
+-------------------------------+--------+-------------------------+
| <ticket-expiry> | 4 | 68 00 02 58 |
+-------------------------------+--------+-------------------------+
| <ticket-lifetime> | 4 | 00 00 01 2c |
+-------------------------------+--------+-------------------------+
| resumed <client-nonce> | 12 | f0 f1 f2 ... fb |
+-------------------------------+--------+-------------------------+
| resumed <resolver-nonce> | 12 | 10 11 12 ... 1b |
+-------------------------------+--------+-------------------------+
| example DNS query (A? | 33 | [dns-query: 33 bytes] |
| www.example.com) | | |
+-------------------------------+--------+-------------------------+
| example DNS response | var | [dns-response] |
+-------------------------------+--------+-------------------------+
Table 6
15.3. Profile Extension and Signature Input
The PQ profile extension is the entire <extensions> field in this
revision:
Denis Expires 24 January 2027 [Page 62]
Internet-Draft DNSCrypt July 2026
pq-profile-ext =
"PQD" 50 51 44
ext-version 01
es-version 00 03
kdf-id 01 (HKDF-SHA256)
aead-id 01 (XChaCha20_DJB-Poly1305)
resolver-pk-len 04 c0 (1216)
client-kex-len 04 60 (1120)
-> 12 bytes total
The Ed25519 signature is computed over the existing field set,
unchanged:
sig-input = resolver-pk (1216) || client-magic (8) || serial (4)
|| ts-start (4) || ts-end (4) || extensions (12)
-> 1248 bytes
signature = Ed25519.Sign(provider-seed, sig-input) = [signature: 64 bytes]
The full certificate (92 fixed bytes + 1216-byte resolver key +
12-byte extensions = 1320 bytes):
Denis Expires 24 January 2027 [Page 63]
Internet-Draft DNSCrypt July 2026
+========+==========================+========+===================+
| Offset | Field | Length | Value |
+========+==========================+========+===================+
| 0 | <cert-magic> | 4 | 44 4e 53 43 |
+--------+--------------------------+--------+-------------------+
| 4 | <es-version> | 2 | 00 03 |
+--------+--------------------------+--------+-------------------+
| 6 | <protocol-minor-version> | 2 | 00 00 |
+--------+--------------------------+--------+-------------------+
| 8 | <signature> | 64 | [signature: 64 |
| | | | bytes] |
+--------+--------------------------+--------+-------------------+
| 72 | <resolver-pk> | 1216 | [resolver-pk: |
| | | | 1216 bytes] |
+--------+--------------------------+--------+-------------------+
| 1288 | <client-magic> | 8 | a1 b2 c3 d4 e5 f6 |
| | | | 07 18 |
+--------+--------------------------+--------+-------------------+
| 1296 | <serial> | 4 | 00 00 00 01 |
+--------+--------------------------+--------+-------------------+
| 1300 | <ts-start> | 4 | 68 00 00 00 |
+--------+--------------------------+--------+-------------------+
| 1304 | <ts-end> | 4 | 68 01 51 80 |
+--------+--------------------------+--------+-------------------+
| 1308 | <extensions> | 12 | 50 51 44 01 00 03 |
| | | | 01 01 04 c0 04 60 |
+--------+--------------------------+--------+-------------------+
Table 7
15.4. Full X-Wing Query
Denis Expires 24 January 2027 [Page 64]
Internet-Draft DNSCrypt July 2026
(resolver-pk, resolver-sk) = X-Wing.GenerateKeyPairDerand(resolver-seed)
(ct, kem-ss) = X-Wing.EncapsulateDerand(resolver-pk, eseed)
ct = [ct: 1120 bytes]
kem-ss = [kem-ss: 32 bytes]
cert-context = "DNSCrypt-PQ-v1" (14 bytes)
|| es-version (00 03) || protocol-minor-version (00 00)
|| resolver-pk (1216) || client-magic (8)
|| serial (4) || ts-start (4) || ts-end (4)
|| extensions (12)
shared-key = HKDF-SHA256(
IKM = kem-ss,
salt = es-version || client-magic
(10 bytes: 00 03 a1 b2 c3 d4 e5 f6 07 18),
info = cert-context || ct,
L = 32) = [shared-key: 32 bytes]
query-nonce = client-nonce || (12 * 00) (24 bytes)
plaintext = dns-query (33) || 80 || (30 * 00)
(padded to 64; ISO/IEC 7816-4)
encrypted-query = tag (16) || ciphertext (64) = [enc-query: 80 bytes]
Query on the wire (1220 bytes):
+========+===================+========+=========================+
| Offset | Field | Length | Value |
+========+===================+========+=========================+
| 0 | <client-magic> | 8 | a1 b2 c3 d4 e5 f6 07 18 |
+--------+-------------------+--------+-------------------------+
| 8 | <client-pk> = ct | 1120 | [ct: 1120 bytes] |
+--------+-------------------+--------+-------------------------+
| 1128 | <client-nonce> | 12 | b0 b1 ... bb |
+--------+-------------------+--------+-------------------------+
| 1140 | <encrypted-query> | 80 | [enc-query: 80 bytes] |
+--------+-------------------+--------+-------------------------+
Table 8
15.5. Full Response and Ticket Issuance
Denis Expires 24 January 2027 [Page 65]
Internet-Draft DNSCrypt July 2026
resume-secret = HKDF-SHA256(
IKM = shared-key,
salt = client-magic || client-nonce (20 bytes),
info = "DNSCrypt-PQ-resume-secret-v1",
L = 32) = [resume-secret: 32 bytes]
profile-extension-hash = SHA-256(extensions) = [peh: 32 bytes]
ticket-plain = resume-secret (32) || es-version (2) || client-magic (8)
|| serial (4) || ts-end (4) || ticket-expiry (4)
|| profile-extension-hash (32) (86 bytes)
ticket = ticket-key-id (4) || ticket-nonce (24)
|| AE(TK, ticket-nonce, ticket-plain)
where AE output = tag (16) || ciphertext (86)
-> 4 + 24 + 102 = 130 bytes = [ticket: 130 bytes]
control = "PQDR" (50 51 44 52) || control-version (01)
|| ticket-lifetime (00 00 01 2c) || ticket-len (00 82)
|| ticket (130) (141 bytes)
pq-response-plain = control-len (00 8d) || control (141)
|| dns-response || pad-to-64
response-nonce = client-nonce || resolver-nonce (24 bytes)
encrypted-response = tag (16) || ciphertext = [enc-response]
Response on the wire:
+======================+========+===================================+
| Field | Length | Value |
+======================+========+===================================+
| <resolver-magic> | 8 | 72 36 66 6e 76 57 6a 38 |
+----------------------+--------+-----------------------------------+
| <nonce> | 24 | b0..bb (client) c0..cb |
| | | (resolver) |
+----------------------+--------+-----------------------------------+
| <encrypted-response> | var | [enc-response] |
+----------------------+--------+-----------------------------------+
Table 9
15.6. Resumed Query and Response
Denis Expires 24 January 2027 [Page 66]
Internet-Draft DNSCrypt July 2026
resumed shared-key = HKDF-SHA256(
IKM = resume-secret,
salt = client-magic || resumed-client-nonce
(20 bytes),
info = "DNSCrypt-PQ-resumed-query-v1"
|| SHA-256(ticket),
L = 32) = [resumed-shared-key: 32 bytes]
query-nonce = resumed-client-nonce || (12 * 00) (24 bytes)
plaintext = dns-query || 80 || pad (padded to 256 for this vector)
encrypted-query = tag (16) || ciphertext (256) = [enc-query: 272 bytes]
Resumed query on the wire (424 bytes):
+========+===================+========+=========================+
| Offset | Field | Length | Value |
+========+===================+========+=========================+
| 0 | <resume-magic> | 8 | 50 51 52 65 73 75 6d 65 |
+--------+-------------------+--------+-------------------------+
| 8 | <ticket-len> | 2 | 00 82 (130) |
+--------+-------------------+--------+-------------------------+
| 10 | <ticket> | 130 | [ticket: 130 bytes] |
+--------+-------------------+--------+-------------------------+
| 140 | <client-nonce> | 12 | f0 f1 ... fb |
+--------+-------------------+--------+-------------------------+
| 152 | <encrypted-query> | 272 | [enc-query: 272 bytes] |
+--------+-------------------+--------+-------------------------+
Table 10
The resumed response reuses resumed shared-key with nonce resumed-
client-nonce || resumed-resolver-nonce.
If the resolver issues no new ticket, the control block is empty
(control-len = 00 00).
15.7. Negative Cases
These vectors pin the required failure behavior.
None of them produce a distinguishable on-the-wire signal beyond "no
response" or "certificate rejected".
1. Bad profile-extension length: resolver-pk-len or client-kex-len
in the extension disagrees with the actual field length, or pq-
profile-ext is not 12 bytes. The client MUST reject the
certificate.
Denis Expires 24 January 2027 [Page 67]
Internet-Draft DNSCrypt July 2026
2. <es-version> mismatch: the on-the-wire <es-version> differs from
the copy inside the signed extension. The client MUST reject the
certificate.
3. Corrupted ticket AEAD: one byte of the sealed region of <ticket>
in a resumed query is flipped. AEAD opening fails, and the
resolver MUST silently drop the query.
4. Expired or rotated ticket: <ticket-expiry> is in the past, or
<ticket-key-id> names a TK that has been rotated out. The
resolver MUST silently drop the query; the client re-handshakes
with a query that carries a ciphertext.
5. Ticket context mismatch: any sealed certificate-context field in
the ticket (<es-version>, <client-magic>, <serial>, <ts-end>, or
<profile-extension-hash>) does not match the resumption context.
The resolver MUST silently drop the query.
6. Malformed KEM ciphertext: one byte of <client-pk> in a query that
carries a ciphertext is flipped. X-Wing implicit rejection
yields a different shared secret, authentication fails, and the
resolver MUST silently drop the query, with no distinct error or
timing.
7. Repeated nonce (client obligation): reusing a <client-nonce>
under one ticket reuses both the derived key and the AEAD nonce;
this is a client MUST NOT. A stateless resolver cannot detect
it, so there is no wire vector; it is listed to make the
obligation explicit.
8. Under-padded resumed query: a resumed UDP query whose complete
packet is below the 256-byte query-size target decrypts correctly
but violates the anti-amplification guidance, and an Anonymized
DNSCrypt relay MAY drop its response on the response-size check.
15.8. Generated Values
The values below were produced by a reference generator from the
pinned inputs above, and are reproducible by any conformant
implementation.
Values up to 141 bytes are given in full; longer artifacts are pinned
by their SHA-256 digest.
The generator self-checks against the HChaCha20 known-answer test of
Appendix 1 and the official X-Wing known-answer test, and verifies
that X-Wing decapsulation recovers the encapsulated secret.
Denis Expires 24 January 2027 [Page 68]
Internet-Draft DNSCrypt July 2026
provider-ed25519-pk (32):
03a107bff3ce10be1d70dd18e74bc09967e4d6309ba50d5f1ddc8664125531b8
resolver-pk (1216, SHA-256):
a1f324bc0701f1234fbba7b11901023b3644f3bb8c6eb4ee4368d7e859eb6228
client-kex / ct (1120, SHA-256):
f6bf3f238e83f24cd444f2887e8fd32d630e07dbe6ca2f2b403aaf5333030c48
kem-ss (32):
8dac8602d4ce5e27e81335b54b25fdcaea86e56613214ee0522db4a5e0a38d50
shared-key (32):
e6d4ab9cffc9b49e2a64d80d7eb2dde280f806b89e834d596ad385b1dd75e9ef
signature (64):
811bab04e2e70c9d946296a93b4028d7c7bb84f32f597d3cf8aba29edc1b6b97
4acc99dd00ec62cdcae477433d10bff20e1c432e1011ad8ad5324f68a294750c
dns-query (33):
12340100000100000000000003777777076578616d706c6503636f6d00000100
01
dns-response (49):
12348180000100010000000003777777076578616d706c6503636f6d00000100
01c00c0001000100000e1000045db8d822
padded query plaintext (64):
12340100000100000000000003777777076578616d706c6503636f6d00000100
0180000000000000000000000000000000000000000000000000000000000000
encrypted-query (80):
c41764468cb42d3a837c51234c08be714af49e1a6830ea6da28178e9e280d76b
ac1b87fd7f56515f2b2cc3d4715aaa42907c282db1edff0bc3b92cd535a710e2
64859a5bdaf67c17ffa6e1c6f6e02a50
full query wire (1220, SHA-256):
65c3421776283f503779916e7b5c32d0d41c885508ad892b349688db6c901233
resume-secret (32):
df158804e3f8ddf383ff7c9d3128491b29437a894936ec72c68aed8a9553272b
profile-extension-hash = SHA-256(extensions) (32):
fab3bf4996c5d2fdfc330ec958d0a5b63624bf3fbdc0fedfa9d94b0941a4060c
ticket-plain (86):
df158804e3f8ddf383ff7c9d3128491b29437a894936ec72c68aed8a9553272b
0003a1b2c3d4e5f60718000000016801518068000258fab3bf4996c5d2fdfc33
0ec958d0a5b63624bf3fbdc0fedfa9d94b0941a4060c
ticket (130):
00000001d0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e1d90c86
474574e0e51e82d8a29938896b0999e827138f8f452f21e044d9809f65a013cf
ad8981be94c1354178b3e03dd518c28bcbaab962aa45246e446de7763288aa4a
01e207725a0ae7bc95452fef3743f6083deb10cd23e2881e8d9307fc2f43bce1
a97e
control (141):
50514452010000012c008200000001d0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0
e1e2e3e4e5e6e7e1d90c86474574e0e51e82d8a29938896b0999e827138f8f45
2f21e044d9809f65a013cfad8981be94c1354178b3e03dd518c28bcbaab962aa
Denis Expires 24 January 2027 [Page 69]
Internet-Draft DNSCrypt July 2026
45246e446de7763288aa4a01e207725a0ae7bc95452fef3743f6083deb10cd23
e2881e8d9307fc2f43bce1a97e
response plaintext, padded to 256 (256, SHA-256):
a215df14b59d272b506224ed1f6ab5956be2bf189f847dfac4f8649c5f94d99e
full response wire (304, SHA-256):
33c081503d5ead4061a30d3f095fc9f226b8c01c3bbffa8fc6f4d9b15087de5c
sha256(ticket) (32):
fb196d81022c6b480f1340c80987088a85145194c18441928a4ae8e5a153536c
resumed shared-key (32):
e61f03acb2ee2ef01b952a0c312c60653267d47a2766fcfd804747fdf2fe789f
resumed encrypted-query (272, SHA-256):
60323805036492350ee442ee4dcb097597fb586e3f2c8a1f26feb9cdd0409b29
resume query wire (424, SHA-256):
34be2e331b4d7c7e808e968c5efc9f25675a9de9064cb33f7c66950e0e4e6db7
resume response wire, no new ticket (112, SHA-256):
2bf202dd3f33d38854450e70a02bd1a317a23bf6d79c5dae406787c9c5f34f52
16. Normative References
[FIPS203] National Institute of Standards and Technology, "Module-
Lattice-Based Key-Encapsulation Mechanism Standard",
FIPS 203, August 2024,
<https://doi.org/10.6028/NIST.FIPS.203>.
[RFC1035] Mockapetris, P., "Domain names - implementation and
specification", STD 13, RFC 1035, DOI 10.17487/RFC1035,
November 1987, <https://www.rfc-editor.org/info/rfc1035>.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/info/rfc2119>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
May 2017, <https://www.rfc-editor.org/info/rfc8174>.
[RFC8439] Nir, Y. and A. Langley, "ChaCha20 and Poly1305 for IETF
Protocols", RFC 8439, DOI 10.17487/RFC8439, June 2018,
<https://www.rfc-editor.org/info/rfc8439>.
[RFC7766] Dickinson, J., Dickinson, S., Bellis, R., Mankin, A., and
D. Wessels, "DNS Transport over TCP - Implementation
Requirements", RFC 7766, DOI 10.17487/RFC7766, March 2016,
<https://www.rfc-editor.org/info/rfc7766>.
Denis Expires 24 January 2027 [Page 70]
Internet-Draft DNSCrypt July 2026
[RFC5358] Damas, J. and F. Neves, "Preventing Use of Recursive
Nameservers in Reflector Attacks", BCP 140, RFC 5358,
DOI 10.17487/RFC5358, October 2008,
<https://www.rfc-editor.org/info/rfc5358>.
[RFC6891] Damas, J., Graff, M., and P. Vixie, "Extension Mechanisms
for DNS (EDNS(0))", STD 75, RFC 6891,
DOI 10.17487/RFC6891, April 2013,
<https://www.rfc-editor.org/info/rfc6891>.
[RFC7830] Mayrhofer, A., "The EDNS(0) Padding Option", RFC 7830,
DOI 10.17487/RFC7830, May 2016,
<https://www.rfc-editor.org/info/rfc7830>.
[RFC9000] Iyengar, J., Ed. and M. Thomson, Ed., "QUIC: A UDP-Based
Multiplexed and Secure Transport", RFC 9000,
DOI 10.17487/RFC9000, May 2021,
<https://www.rfc-editor.org/info/rfc9000>.
[RFC4291] Hinden, R. and S. Deering, "IP Version 6 Addressing
Architecture", RFC 4291, DOI 10.17487/RFC4291, February
2006, <https://www.rfc-editor.org/info/rfc4291>.
[RFC1918] Rekhter, Y., Moskowitz, B., Karrenberg, D., de Groot, G.
J., and E. Lear, "Address Allocation for Private
Internets", BCP 5, RFC 1918, DOI 10.17487/RFC1918,
February 1996, <https://www.rfc-editor.org/info/rfc1918>.
[RFC7748] Langley, A., Hamburg, M., and S. Turner, "Elliptic Curves
for Security", RFC 7748, DOI 10.17487/RFC7748, January
2016, <https://www.rfc-editor.org/info/rfc7748>.
[I-D.connolly-cfrg-xwing-kem]
Connolly, D., Schwabe, P., and B. Westerbaan, "X-Wing:
general-purpose hybrid post-quantum KEM", Work in
Progress, Internet-Draft, draft-connolly-cfrg-xwing-kem-
10, 2 March 2026, <https://datatracker.ietf.org/doc/html/
draft-connolly-cfrg-xwing-kem-10>.
[RFC5869] Krawczyk, H. and P. Eronen, "HMAC-based Extract-and-Expand
Key Derivation Function (HKDF)", RFC 5869,
DOI 10.17487/RFC5869, May 2010,
<https://www.rfc-editor.org/info/rfc5869>.
Author's Address
Frank Denis
Individual Contributor
Denis Expires 24 January 2027 [Page 71]
Internet-Draft DNSCrypt July 2026
Email: fde@00f.net
Denis Expires 24 January 2027 [Page 72]