DNSCurve: Usable security for DNS
How to implement a DNSCurve cacheAre you the author of a DNS cache: software to "resolve" DNS names, talking to DNS servers around the Internet? This page explains how to add support for DNSCurve to your software, adding link-level public-key protection to DNS packets.
Overview of the DNSCurve protocolWhen you're about to contact a DNS server, check the DNS server name to see whether it contains a correctly formatted DNSCurve public key. If it does, you can and should encrypt and authenticate the packets that you send to the server.
For example, when you're about to contact the DNS server ns1t.nytimes.com for the zone nytimes.com, go ahead and send packets the way you normally do: the name ns1t.nytimes.com does not contain a DNSCurve public key. However, when you're about to contact the DNS server uz5xgm1kx1zj8xsh51zp315k0rw7dcsgyxqh2sl7g8tjg25ltcvhyw.nytimes.com for the zone nytimes.com, encrypt and authenticate your packets; this name does contain a DNSCurve public key.
You need your own DNSCurve secret key and a corresponding DNSCurve public key. You can generate these when your program starts and then reuse the keys for talking to any number of servers. To prevent tracking of keys you may wish to regenerate keys frequently, for example once per minute or once per change of IP address, but if you are not concerned with tracking then there is no danger in using a single key for a long time (even years!).
You also need, for each outgoing DNSCurve packet, a 96-bit nonce. Nonce means "number used once." Once you have used a particular nonce to encrypt a packet, you must never use the same nonce to encrypt another packet. This requirement is essential for cryptographic security, and lasts as long as you are continuing to use the same secret key.
You can, for example, choose the nonce as a simple counter: 1 for the first packet, 2 for the second packet, etc. However, it is better to choose the nonce as a 64-bit counter followed by a 32-bit cryptographically generated random number; then blind attackers will have more trouble consuming your CPU time. It is even better to increase the counter to, e.g., the number of nanoseconds that have passed since the standard C epoch (the beginning of 1970 GMT) in your local clock, so that the current value of the counter does not leak your traffic rate. Do not decrease the counter if the clock jumps backwards! Another way to hide the counter, without using a clock, is to encrypt the counter under a secret key.
What you send to the server, instead of the original packet, is an expanded packet containing
The server will open the box using your DNSCurve public key, the server's DNSCurve secret key, and this packet's nonce. What you receive back from the server will also be an expanded packet containing
If the opening fails, the packet is forged; discard the packet and continue waiting for packets from the legitimate server. If the opening succeeds, inside the box you will find the original response packet; handle the packet exactly the same way that you would handle a normal DNS response packet.
AnchorsYour cache begins with the list of root servers as an anchor. You are encouraged to allow users to configure this anchor with DNSCurve keys. DNSCurve server names for the root servers protect your packets to and from those servers, so you securely learn the DNSCurve server names for .com and other top-level domains, so your packets to and from the .com servers are protected, so you securely learn the DNSCurve server names for nytimes.com, etc.
Perhaps your cache also allows users to configure anchors for various DNS subtrees: e.g., an anchor that specifies DNS servers for chase.com, immunizing the chase.com and *.chase.com lookups against outages of .com and of the DNS roots. Presumably these users are interested in immunizing the chase.com and *.chase.com lookups against all behavior of .com and of the DNS roots, not just outages, so you are encouraged to allow every anchor to be configured with DNSCurve keys.
Base-32 encodingSometimes DNSCurve communicates byte strings inside DNS query names. A byte string is interpreted as a number in little-endian form. Each 5-bit sequence of this number, from least significant to most significant, is encoded as one of the standard "digits" 0123456789bcdfghjklmnpqrstuvwxyz. A final sequence of fewer than 5 bits is zero-extended before encoding. Decoders must accept BCDFGHJKLMNPQRSTUVWXYZ as synonyms for bcdfghjklmnpqrstuvwxyz.
For example, the two-byte string with bytes 0x64,0x88 (i.e., 100,136 decimal) is interpreted as the integer 0x8864 (i.e., 34916). The bits 1000100001100100 of this integer are divided into 5-bit parts 00100, 00011, 00010, 00001, which in turn are encoded as 4, 3, 2, 1. The original string is therefore encoded as the string 4321.
DNSCurve public keysDNSCurve public keys are 32-byte strings. These strings represent 255-bit numbers in little-endian form; the last byte is always between 0 and 127.
When a DNSCurve public key is communicated as part of a DNS server name it is first encoded as a 54-byte alphanumeric string. The first 3 bytes are the magic string uz5. The remaining 51 bytes are the base-32 encoding of the 255-bit public key (i.e., the 52-byte base-32 encoding of the 32-byte public key, with the final 0 removed).
To recognize a DNSCurve public key inside a DNS name, check each label of the name (after conversion from uppercase to lowercase) to see whether the label is
DNSCurve implementation optionsYou have a choice of two different ways to send expanded DNS query packets:
Every DNSCurve server is required to accept streamlined query packets. You can write a DNSCurve cache that uses only streamlined packets and that does not know anything about TXT-format packets; this cache will be suitable for users with direct Internet connections.
Every DNSCurve server is also required to accept TXT-format query packets. You can write a DNSCurve cache that uses only TXT-format packets and that does not know anything about streamlined packets.
You can also write a DNSCurve cache that uses TXT format by default but that gives users the option of switching to streamlined format to leak less information.
Implementation option 1: Streamlined DNSCurveAn expanded query packet in streamlined format has the following bytes:
An expanded response packet in streamlined format has the following bytes:
If you send an expanded DNS query packet in streamlined format then you are free to assume that the expanded response packet also uses streamlined format. If you send a non-DNSCurve DNS query packet then you are free to assume that the response is also a non-DNSCurve packet. The server is responsible for following these rules.
Implementation option 2: TXT DNSCurveAn expanded query packet in TXT format is, from the perspective of the original DNS protocol, a DNS TXT query packet. It has the following bytes:
An expanded response packet in TXT format is, from the perspective of the original DNS protocol, a DNS TXT response packet. It has the following bytes:
If you send an expanded DNS query packet in TXT format then you are free to assume that the expanded response packet also uses TXT format. The server is responsible for following this rule.
UDP and TCPIf a normal DNS response packet is larger than 512 bytes then the server replaces it by an explicitly truncated packet. The client then tries again through TCP. Servers are not required to support TCP if no responses are above 512 bytes; clients are permitted to try TCP only if the server has explicitly indicated truncation.
DNSCurve does not require TCP support from servers that were not already supporting TCP. If the original DNS response packet is at most 512 bytes then the server is permitted to send the expanded response packet as a UDP packet. DNSCurve clients are required to set aside a 4096-byte buffer for receiving a UDP response packet.
If the original DNS response packet is above 512 bytes then it is replaced by an explicitly truncated packet and the truncated packet is protected by DNSCurve. In this case the client tries again by TCP, sending its DNSCurve query packet through TCP and receiving the DNSCurve response through TCP.
TCP is considerably more expensive for clients and servers than UDP is, and TCP has no protection against denial of service, so server administrators are advised to stay below 512 bytes if possible. DNSCurve adds some denial-of-service protection for UDP but cannot do anything to help TCP.
VersionThis is version 2017.01.22 of the in-implement.html web page.