Category Archives: Encryption

Minimal dnscrypt-proxy DoH Config

dnscrypt-proxy has a lot of features and can be intimidating to setup. Issues range from understanding what dnscrypt is to how to pick list of sources to understanding what a stamp is.

While it’s not a recommended configuration, I wanted to setup a very simple/minimal dnscrypt-proxy that uses a few well known DoH servers.


  1. Install dnscrypt-proxy.
  2. Edit the configuration file (/etc/dnscrypt-proxy.toml or /etc/dnscrypt-proxy/dnscrypt-proxy.toml on Linux/UNIX systems).
    1. Delete or comment out server_names
      # server_names = ['scaleway-fr', 'google', 'yandex', 'cloudflare']
    2. Delete or comment out the entries under [sources]
    3. If present, ensure doh_servers = true
    4. Depending on the servers you configure, you might need to edit require_dnssec, require_nolog, and require_nofilter to be compatible with the servers. Since I’m explicitly configuring a small list of servers, it’s easier to turn off all restrictions
      require_* = false
    5. Add your desired servers to the [static] section (for this you should get a basic understanding of stamps)
      static entry
      Note: each static entry requires a unique name.


While you don’t need a detailed understanding of stamps, it’s good to have a basic understanding; so you can audit the servers you are adding and you can add custom servers.

A stamp is just dnscrypt-proxy’s format for encoding all relevant parameters for a DNS server. For a DoH server, that consists of:

  • Properties (required) – flags indicating if the server is DNSSEC capable, logs queries, or filters results.
  • IP address (optional) – If an IP address is not provided the Host will be used.
    Note: The spec says the port (if not 443) should be provided in this field; however, the public lists and the stamp calculator include the port in the Host field
  • Host (required) – self-explanatory
  • Hashes (optional) – doesn’t appear to be working. This should allow trusting custom cert chains; however, dnscrypt-proxy is only using the platform’s trust store to validate certificate chains.
  • Path (required) – for DoH servers this is generally “/dns-query”. This should be well documented with the information about each DoH server.

You have three options:

  1. Generate your own stamps using the stamp calculator
  2. Use stamps below
  3. Copy stamps from a public list:

For any pre-generated stamps, you can check the contents by pasting the stamp into to Stamp field of the stamp calculator.

DoH Server Stamps

Some stamps for common DoH servers. While I have verified these stamps work, I make no claim to the accuracy of the properties.



Properties: DNSSEC, Filter (malicious domain blocking), No Logging (limited per the Quad9 FAQ):

# Quad9 Secured DoH
stamp = 'sdns://AgMAAAAAAAAABzkuOS45LjkADmRuczkucXVhZDkubmV0Ci9kbnMtcXVlcnk'

# Quad9 Secured DoH
stamp = 'sdns://AgMAAAAAAAAADTE0OS4xMTIuMTEyLjkADmRuczkucXVhZDkubmV0Ci9kbnMtcXVlcnk'

# Quad9 Secured 2620:fe::9 DoH
stamp = 'sdns://AgMAAAAAAAAADFsyNjIwOmZlOjo5XQAOZG5zOS5xdWFkOS5uZXQKL2Rucy1xdWVyeQ'

# Quad9 Secured 2620:fe::fe:9 DoH
stamp = 'sdns://AgMAAAAAAAAAD1syNjIwOmZlOjpmZTo5XQAOZG5zOS5xdWFkOS5uZXQKL2Rucy1xdWVyeQ'

Properties: DNSSEC, No Filter, No Logging (limited per the Quad9 FAQ):

# Quad9 Unsecured DoH
stamp = 'sdns://AgMAAAAAAAAACDkuOS45LjEwAA9kbnMxMC5xdWFkOS5uZXQKL2Rucy1xdWVyeQ'

# Quad9 Unsecured DoH
stamp = 'sdns://AgMAAAAAAAAADjE0OS4xMTIuMTEyLjEwAA9kbnMxMC5xdWFkOS5uZXQKL2Rucy1xdWVyeQ'

# Quad9 Unsecured 2620:fe::10 DoH
stamp = 'sdns://AgMAAAAAAAAADVsyNjIwOmZlOjoxMF0AD2RuczEwLnF1YWQ5Lm5ldAovZG5zLXF1ZXJ5'

# Quad9 Unsecured 2620:fe::fe:10 DoH
stamp = 'sdns://AgMAAAAAAAAAEFsyNjIwOmZlOjpmZToxMF0AD2RuczEwLnF1YWQ5Lm5ldAovZG5zLXF1ZXJ5'

Cloudflare DNS


Properties: DNSSEC, Filter (malicious content blocking), No Logging (limited per Privacy):

# Cloudflare Security DoH
stamp = 'sdns://AgMAAAAAAAAABzEuMS4xLjIAG3NlY3VyaXR5LmNsb3VkZmxhcmUtZG5zLmNvbQovZG5zLXF1ZXJ5'

# Cloudflare Security DoH
stamp = 'sdns://AgMAAAAAAAAABzEuMC4wLjIAG3NlY3VyaXR5LmNsb3VkZmxhcmUtZG5zLmNvbQovZG5zLXF1ZXJ5'

# Cloudflare Security 2606:4700:4700::1112 DoH
stamp = 'sdns://AgMAAAAAAAAAFlsyNjA2OjQ3MDA6NDcwMDo6MTExMl0AG3NlY3VyaXR5LmNsb3VkZmxhcmUtZG5zLmNvbQovZG5zLXF1ZXJ5'

# Cloudflare Security 2606:4700:4700::1002 DoH
stamp = 'sdns://AgMAAAAAAAAAFlsyNjA2OjQ3MDA6NDcwMDo6MTAwMl0AG3NlY3VyaXR5LmNsb3VkZmxhcmUtZG5zLmNvbQovZG5zLXF1ZXJ5'

Properties: DNSSEC, No Filter, No Logging (limited per Privacy):

# Cloudflare DNS DoH
stamp = 'sdns://AgMAAAAAAAAABzEuMS4xLjEAEmNsb3VkZmxhcmUtZG5zLmNvbQovZG5zLXF1ZXJ5'

# Cloudflare DNS DoH
stamp = 'sdns://AgMAAAAAAAAABzEuMC4wLjEAEmNsb3VkZmxhcmUtZG5zLmNvbQovZG5zLXF1ZXJ5'

# Cloudflare DNS 2606:4700:4700::1111 DoH
stamp = 'sdns://AgMAAAAAAAAAFlsyNjA2OjQ3MDA6NDcwMDo6MTExMV0AEmNsb3VkZmxhcmUtZG5zLmNvbQovZG5zLXF1ZXJ5'

# Cloudflare DNS 2606:4700:4700::1001 DoH
stamp = 'sdns://AgMAAAAAAAAAFlsyNjA2OjQ3MDA6NDcwMDo6MTAwMV0AEmNsb3VkZmxhcmUtZG5zLmNvbQovZG5zLXF1ZXJ5'

Google DNS


Properties: DNSSEC, No Filter, Logging (generally full logs are only temporary per the Privacy Statement):

# Google DNS DoH
stamp = 'sdns://AgMAAAAAAAAABzguOC44LjgACmRucy5nb29nbGUKL2Rucy1xdWVyeQ'

# Google DNS DoH
stamp = 'sdns://AgMAAAAAAAAABzguOC40LjQACmRucy5nb29nbGUKL2Rucy1xdWVyeQ'

# Google DNS 2001:4860:4860::8888 DoH
stamp = 'sdns://AgMAAAAAAAAAFlsyMDAxOjQ4NjA6NDg2MDo6ODg4OF0ACmRucy5nb29nbGUKL2Rucy1xdWVyeQ'

# Google DNS 2001:4860:4860::8844 DoH
stamp = 'sdns://AgMAAAAAAAAAFlsyMDAxOjQ4NjA6NDg2MDo6ODg0NF0ACmRucy5nb29nbGUKL2Rucy1xdWVyeQ'

Adding OIDs to XCA

Adding OIDs to XCA is a straightforward process. I was able to follow the official guide at with minimal issues.

First, ensure you download XCA v2.x from the official download page The instructions didn’t make sense at first since I was running xca v1.4.1.

Create a file named “oids.txt” in the user’s XCA directory:

  • Windows: C:\Users\<username>\AppData\Roaming\xca
  • macOS: ~/Library/Application Support/data/xca
  • Linux: ~/.xca
oids.txt on Windows

Add the OID(s) to oids.txt using the format “<oid> : <short_name> : <long_name>”. In the example below, I added a (Microsoft) Remote Desktop Authentication OID ( rdpAuth: Remote Desktop Authentication
oids.txt content

Copy the eku.txt file from the XCA installation location to the user’s XCA directory:

  • Windows: C:\Program Files\xca
  • macOS: /Applications/
    This can be accessed through the command line or right clicking on the xca application and selecting “Show Package Contents”
  • Linux: /usr/share/xca or /usr/local/share/xca

Note: The whole file eku.txt file must be copied, because xca only parses the first eku.txt it encounters.

Add a line to the user’s eku.txt referencing your new EKU:

Add the new EKU to the list of pre-defined EKUs

Close and re-open XCA and your new EKU will be available:

xca: Remote Desktop Authentication EKU
XCA Key Usage Tab

After adding the Remote Desktop Authentication EKU, I found out it is no longer supported/recognized. The Microsoft Remote Desktop 10 app on macOS and Windows 10 both report the EKU as invalid/unknown.

Unknown Key Usage
Unknown Key Usage

How to Verify OpenSSH Source

Download the source, signature, and old key from I picked 3 different mirrors:

Download the current key from the MIT PGP Public Key Server at 0xD3E5F56B6D920D30.

Verify the current key is signed with the old key:

Kenjis-MacBook-Air:ssh kenji$ gpg --import DJM-GPG-KEY.asc

gpg: key 86FF9C48: "Damien Miller (Personal Key) <[email-removed]>" not changed
gpg: Total number processed: 1
gpg:              unchanged: 1

Kenjis-MacBook-Air:ssh kenji$ gpg --import 0xD3E5F56B6D920D30.asc

gpg: key 6D920D30: public key "Damien Miller <[email-removed]>" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u

Kenjis-MacBook-Air:ssh kenji$ gpg --check-sigs 0xD3E5F56B6D920D30

pub   3200R/6D920D30 2013-12-10 [expires: 2021-01-01]
uid                  Damien Miller <[email-removed]>
sig!         86FF9C48 2013-12-10  Damien Miller (Personal Key) <[email-removed]>
sig!3        6D920D30 2013-12-10  Damien Miller <[email-removed]>
sub   3200R/672A1105 2013-12-10 [expires: 2021-01-01]
sig!         6D920D30 2013-12-10  Damien Miller <[email-removed]>

Verify the signature of the openssh source.

Kenjis-MacBook-Air:ssh kenji$ gpg --verify openssh-7.1p2.tar.gz.asc openssh-7.1p2.tar.gz

gpg: Signature made Wed Jan 13 17:13:46 2016 PST using RSA key ID 6D920D30
gpg: Good signature from "Damien Miller <[email-removed]>"
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 59C2 118E D206 D927 E667  EBE3 D3E5 F56B 6D92 0D30

Full Process

Download the OpenSSH source, signature, and old key as described above.

Use pgpdump to determine the full Key ID used to sign the tarball.

Kenjis-MacBook-Air:pgpdump-0.29 kenji$ ./pgpdump openssh-7.1p2.tar.gz.asc 
Old: Signature Packet(tag 2)(428 bytes)
	Ver 4 - new
	Sig type - Signature of a binary document(0x00).
	Pub alg - RSA Encrypt or Sign(pub 1)
	Hash alg - SHA512(hash 10)
	Hashed Sub: signature creation time(sub 2)(4 bytes)
		Time - Wed Jan 13 17:13:46 PST 2016
	Sub: issuer key ID(sub 16)(8 bytes)
		Key ID - 0xD3E5F56B6D920D30
	Hash left 2 bytes - d2 4c 
	RSA m^d mod n(3197 bits) - ...
		-> PKCS-1

If you don’t have pgp dump, you can use gpg --verify to see the short key ID:

Kenjis-MacBook-Air:ssh kenji$ gpg --verify openssh-7.1p2.tar.gz.asc openssh-7.1p2.tar.gz
gpg: Signature made Wed Jan 13 17:13:46 2016 PST using RSA key ID 6D920D30
gpg: Can't check signature: public key not found

OR you can manually parse the signature packet as described below.

Download the signature key from the MIT PGP Public Key Server at 0xD3E5F56B6D920D30.

The OpenSSH mailing list ( shows that Damien Miller is the signer of the portable source. Search for all of his keys on the MIT Key Server This shows 0xD3E5F56B6D920D30 and 0xCE8ECB0386FF9C48 (i.e. DJM-GPG-KEY.asc) belonging to Damien Miller. Even though the 0xCE8ECB0386FF9C48 is listed as revoked, I think the keys can be trusted; because DJM-GPG-KEY.asc continues to be posted on the OpenSSH mirrors, and the creation date for 0xD3E5F56B6D920D30 is consistent with the mailing list announcement.

Verify the signature on the current key and the source as described above.

PGP Signature Parsing

Extract the raw signature:

Version: GnuPG v2


Copy this into a file.

Convert the base64 to binary and then view in a hex editor:

base64 -D <file> | xxd
0000000: 8901 ac04 0001 0a00 0605 0256 96f6 4a00  ...........V..J.
0000010: 0a09 10d3 e5f5 6b6d 920d 30d2 4c0c 7d17}.
0000020: 7cbb 53fc f910 d7a0 5df6 ba1b 4ec1 0018  |.S.....]...N...
0000030: df57 09cf 6801 7f68 e705 5fc1 133c 4134  .W..h..h.._..<A4
0000040: 2be9 39b1 3d10 208c c962 b445 20a3 1d00  +.9.=. ..b.E ...
0000050: 717f 0a16 e187 6400 0ac1 6716 dec5 7b54  q.....d...g...{T
0000060: 7d73 a551 d701 d5c7 383a a82f bee7 e4b4  }s.Q....8:./....
0000070: cb79 b718 35ed 548a bfcb 48db 7982 4f42  .y..5.T...H.y.OB
0000080: 1bb3 7769 a73f 8f34 01f6 2f37 0a59 35db  ..wi.?.4../7.Y5.
0000090: 1ebe cf43 3638 aae7 d9df 7e91 e800 cab9  ...C68....~.....
00000a0: 7a9f 5050 cdc7 ba0b 1227 a14e b482 ec08  z.PP.....'.N....
00000b0: 4833 759a 82ab f675 1049 3645 bf0a 2df0  H3u....u.I6E..-.
00000c0: a969 d343 a20e 0f90 3ffc 40cb 556d 12a9  .i.C....?.@.Um..
00000d0: 0d7f e27e e658 19a4 a224 70d3 1cc5 c519  ...~.X...$p.....
00000e0: e71c a8e1 c081 aac2 3e68 3a80 c5cd 939a  ........>h:.....
00000f0: e97b 4e70 8c21 f555 de99 3979 1aaf 996a  .{Np.!.U..9y...j
0000100: 2691 140d 5344 7b15 5d54 f54e 0494 801d  &...SD{.]T.N....
0000110: ccbb 2dcf c8e1 4798 7119 94bc 9f3e b355  ..-...G.q....>.U
0000120: fd68 e857 5f33 a2c5 4677 67a0 181f 232b  .h.W_3..Fwg...#+
0000130: ac73 7eda 4f7a 8567 7625 8fc1 2233 e761  .s~.Oz.gv%.."3.a
0000140: 3ac4 1b68 0955 ebd2 4b23 cf7c 1b83 1fbd  :..h.U..K#.|....
0000150: 34e5 45e7 c668 d7d7 8de8 d7f5 1f81 0fdc  4.E..h..........
0000160: ad1a 3439 e333 996c 072a 6118 6939 5bbb  ..49.3.l.*a.i9[.
0000170: 1051 cd2e e18b f0e1 16dc f551 95f0 8fd9  .Q.........Q....
0000180: 49d7 70e5 63eb a0d4 179a c3b4 e9e3 b67b  I.p.c..........{
0000190: 2f0f 3942 3809 a293 7bc5 167d cef8 3179  /.9B8...{..}..1y
00001a0: 05f7 79bc 303e d576 6078 9580 ac16 2f    ..y.0>.v`x..../
Packet Tag: 0x89 = Old Format Packet, Tag = 2, 2 octet packet length
Packet Length: 0x01AC = 428 bytes
Signature Version: 0x04 = Version 4
Signature Type: 0x00 = Binary Signature
Signature Algorithm: 0x01 = RSA
Hash Algorithm: 0x0A = SHA-512
Hashed Subpacket(s) Size: 0x0006 = 6 bytes
Hashed Subpacket: 0x05025696f64A
   Size: 0x05 = 5 bytes
   Type: 0x02 = Signature Creation Time
   Time: 0x5696f64a = Wed Jan 13 17:13:46 PST 2016
Unhashed subpacket(s) size: 0x000A = 10 bytes
Unhashed subpacket: 0x09 10D3 E5F5 6B6D 920D 30
   Size: 0x09 = 9 bytes
   Type: 0x10 = placeholder for backwards compatibility
   Key ID: D3E5F56B6D920D30
Left 16 bits of hash: 0xD24C
MPI Length: 0x0C7D = 3197 bits = 400 bytes

DreamHost Private Key Format

When renewing my SSL/TLS certificate for my DreamHost shared hosting account, I generated a new 4096-bit RSA Private Key using OpenSSL 1.0.1e. I was surprised and confused when DreamHost reported "Invalid private key". I initially thought it was a problem with the 4096-bit key but found documentation indicating 4096 is a supported option.

I checked the that my key was PEM formatted as expected, and finally realized it was an incompatibility between the "-----BEGIN RSA PRIVATE KEY-----" and the "-----BEGIN PRIVATE KEY-----" variants of the PEM format when I couldn’t create a self-signed cert using OpenSSL 0.9.8za and my brand new key. Once I realized this, it was a simple conversion using the command

openssl rsa -in private.key -inform PEM -out outfile.key -outform PEM

with OpenSSL 1.0.1. The in/out forms aren’t strictly necessary, but make the command a little clearer to read.

Musings on Password Lengths

I’ve been thinking about password lengths, complexity, and how much strength is really required.

Random Passwords

I use LastPass for all of my passwords an never really calculated how long I need to make my passwords secure assuming they’re fully random. Since AES with a 128-bit key is considered sufficiently secure, I want my passwords to have at least 128-bits of strength. Doing some quick math based on a standard US ASCII Keyboard, the bits in strength in each character classes are as follows:

  • lowercase – 26 ≈ 4.7
  • uppesrcase – 26 ≈ 4.7
  • numbers – 10 ≈ 3.3
  • symbols – 30 ≈ 4.9

I assume that every website will accept alphanumeric passwords, so that gives 62 possibilities. Each character has just short of 6 bits of strength. 128 / 6 ≈ 21.3, so a random 22 character alphanumeric password has more than 128 bits of strength.

If the website accepts all special characters, that 92 possibilities. Each character then has just over 6.5 bits of strength. 128 / 6.5 ≈ 19.7, so a random 20 character password has more than 128 bits of strength.

"Human" Passwords

Human passwords are much more difficult to estimate the strength of. I like to use a variant of the xkcd: Password Strength method of using a combination of words, numbers and symbols. This changes/adds the number of possibilities based on the number of words. The Oxford English Dictionary indicates that there are about 600,000 words in the English language. Assuming that half of these are between 3 and 6 characters, each word between 3 and 6 characters has about 18.2 bits of strength.

If an attacker knew the composition of a password that followed the pattern word, symbol, word, number, word, symbol, word; this password would have 18.2 + 4.9 + 18.2 + 3.3 + 18.2 + 4.9 + 18.2 = 87.7. While a password like this doesn’t quite reach 128 bits of strength; it is reasonably strong, should be easy to remember, and fairly easy to type. Also, an attacker probably wouldn’t know the password composition method, making the actual strength a bit higher. If science and technical terms are included, that will increase the strength per word. Just make sure you pick your words randomly.


The 24+ character random passwords for websites are unnecessary, especially when the password reset functions generally have limited security.

I should add a little more length for my master passwords that are susceptible to an offline attack (e.g. LastPass). Fortunately most passwords like this use PBKDF2 to increase the computing power necessary to perform a brute force attack.