How to Implement Long DKIM Keys (4096-bit) in DNS While Overcoming UDP and TXT Record Size Limits


1 views

When working with enhanced security requirements, many administrators need to implement 4096-bit DKIM keys (which produce ~800-character base64 strings). The standard DNS infrastructure presents two main constraints:

; Example of a typical 2048-bit DKIM record
default._domainkey IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."

The primary constraints we face are:

  • UDP 512-byte limit: Traditional DNS responses shouldn't exceed 512 bytes over UDP (per RFC 1035)
  • TXT record length limits: While theoretically up to 64KB (with EDNS0), most DNS implementations enforce smaller practical limits (often 255-1024 characters per string segment)

Here are proven methods to deploy large DKIM keys:

Method 1: Chunked TXT Records

; For a 4096-bit key split into two parts
default._domainkey IN TXT (
    "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."
    "uQIDAQAB"
)

Most modern DNS servers (BIND, PowerDNS, etc.) automatically reassemble chunks. Verify with:

dig +short txt default._domainkey.example.com

Method 2: DNS Provider-Specific Approaches

Major cloud providers handle large records differently:

AWS Route 53:

; Use separate quoted strings (automatically concatenated)
"v=DKIM1; k=rsa; p=MI..." "w0BAQEFAAOCAQ8AMII..." "BCgKCAQEA..."

Google Cloud DNS:

; Single record with escaped newlines
"v=DKIM1; k=rsa; p=MI...\nw0BAQEFAAOCAQ8AMII...\nBCgKCAQEA..."

After implementation, verify with these tools:

# Using dig for raw verification
dig +short txt default._domainkey.example.com | sed 's/" "/""/g'

# Using dedicated DKIM tools
opendkim-testkey -d example.com -s default -vvv

For extreme cases where even chunking fails:

  1. Consider rotating to ED25519 keys (smaller footprint with comparable security)
  2. Implement DNSSEC-enabled TCP fallback for large responses
  3. Use DNS-over-HTTPS/TLS which bypasses traditional size limitations

While 4096-bit keys provide enhanced security, they impact:

  • DNS lookup times (larger payloads)
  • CPU usage during DKIM verification
  • Email delivery latency (especially with multiple receiving MTAs)

Benchmark with tools like dnsperf before full deployment.


When working with 4028-bit DKIM keys, we immediately hit two fundamental DNS limitations:

1. Traditional UDP DNS responses capped at 512 bytes (RFC 1035)
2. TXT record length restrictions imposed by DNS providers

A 4028-bit RSA key typically encodes to about 800-900 characters when base64 encoded. Standard DNS implementations struggle with this because:

; Typical DKIM record example (2048-bit)
example._domainkey IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgk..."

The problem compounds when we need the full chain of:

- Key rotation pairs
- Multiple algorithms
- Extended key usage flags

Solution 1: Chunked TXT Records

Most modern DNS servers support chunking:

; 4028-bit DKIM implementation
dkim4028._domainkey IN TXT (
    "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCA"
    "K8AMIIBCgKCAQEAzxt5gIqFSRZYU3Cx4R7E0uQ2Xw9mJmK"
    "...[additional chunks]..."
    "1eRzQIDAQAB"
)

Key implementation notes:

1. Use parentheses for multi-line TXT
2. Keep each chunk under 255 characters
3. Maintain proper ordering

Solution 2: DNS-over-TCP Fallback

When UDP limitations hit, proper resolvers should automatically switch to TCP:

# Python DNS query example forcing TCP
import dns.resolver
resolver = dns.resolver.Resolver()
resolver.use_tcp = True
answer = resolver.resolve('large-dkim.example.com', 'TXT')
Provider Max TXT Length Chunking Support
Cloudflare 7200 bytes Yes (auto-concat)
Route 53 6144 bytes Manual required
Google Cloud DNS 2048 bytes Yes

Always validate large DKIM deployments:

# Using dig for verification
dig +tcp +short txt dkim4028._domainkey.example.com

# OpenDKIM test command
opendkim-testkey -d example.com -s dkim4028 -vvv

When creating large DKIM keys:

openssl genrsa -out dkim.key 4028
openssl rsa -in dkim.key -pubout -out dkim.pub
# Then carefully format the public key:
awk '{printf "%s", $0}' dkim.pub | sed 's/-----.*-----//g' | tr -d '\n'