{"id":9357,"date":"2025-11-24T09:58:54","date_gmt":"2025-11-24T09:58:54","guid":{"rendered":"https:\/\/pariswells.com\/blog\/?p=9357"},"modified":"2025-11-24T09:58:55","modified_gmt":"2025-11-24T09:58:55","slug":"powershell-to-use-cloudflare-api-to-get-dkim-records-and-report-on-keylength","status":"publish","type":"post","link":"https:\/\/pariswells.com\/blog\/research\/powershell-to-use-cloudflare-api-to-get-dkim-records-and-report-on-keylength","title":{"rendered":"Powershell to Use Cloudflare API to get DKIM records and Report on KeyLength"},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code class=\"\">&lt;#\n.SYNOPSIS\nUse Cloudflare API to check DKIM Key Lenght and Alert for 1024bit Ones\n#>\n\nparam(\n    [Parameter(Mandatory=$true)][string]$Domain,\n    [Parameter(Mandatory=$true)][string]$CloudflareApiToken\n)\n\n$headers = @{\n    \"Authorization\" = \"Bearer $CloudflareApiToken\"\n    \"Content-Type\"  = \"application\/json\"\n}\n\n# 1. Get Zone ID\n$zone = (Invoke-RestMethod \"https:\/\/api.cloudflare.com\/client\/v4\/zones?name=$Domain\" -Headers $headers -Method Get).result[0]\nif (-not $zone) { Write-Error \"Domain not found in your Cloudflare account.\"; exit 1 }\n$zoneId = $zone.id\n\n# 2. Get all DNS records\n$allRecords = @()\n$page = 1\ndo {\n    $resp = Invoke-RestMethod \"https:\/\/api.cloudflare.com\/client\/v4\/zones\/$zoneId\/dns_records?per_page=1000&amp;page=$page\" -Headers $headers -Method Get\n    $allRecords += $resp.result\n    $page++\n} while ($resp.result_info.page -lt $resp.result_info.total_pages)\n\n# 3. Find DKIM records\n$dkimRecords = $allRecords | Where-Object { $_.name -like \"*_domainkey*\" -and $_.type -in 'TXT','CNAME' } | Sort-Object name\nif ($dkimRecords.Count -eq 0) { Write-Host \"No DKIM records found.\" -ForegroundColor Yellow; exit 0 }\n\n# 4. EXACT bit length (strips leading zero byte)\nfunction Get-ExactDKIMBits {\n    param([string]$txt)\n    $txt = $txt -replace '\"','' -replace '\\s+',''\n    if ($txt -notmatch 'p=([A-Za-z0-9+\/=]+)') { return $null }\n    try {\n        $bytes = [Convert]::FromBase64String($matches[1])\n        $i = 0\n        while ($i -lt $bytes.Length - 10) {\n            if ($bytes[$i] -eq 0x02) {  # INTEGER tag\n                $i++\n                $lenByte = $bytes[$i++]\n                if ($lenByte -lt 128) {\n                    $len = $lenByte\n                } else {\n                    $n = $lenByte - 128\n                    $len = 0\n                    for ($j = 0; $j -lt $n; $j++) { $len = ($len -shl 8) + $bytes[$i++] }\n                }\n                $start = $i\n                if ($bytes[$start] -eq 0x00) { $start++; $len-- }  # strip leading zero\n                return $len * 8\n            }\n            $i++\n        }\n    } catch { }\n    return $null\n}\n\n# 5. Process records\n$weak1024 = @()\n$strong   = 0\n\nforeach ($rec in $dkimRecords) {\n    $selector = ($rec.name -split '\\._domainkey')[0] -split '\\.' | Select-Object -Last 1\n    Write-Host \"$($rec.name)  (selector: $selector)\" -ForegroundColor White\n\n    if ($rec.type -eq 'TXT') {\n        $txtValue = $rec.content\n    } else {\n        Write-Host \"    CNAME -> $($rec.content)\" -ForegroundColor Cyan\n        $result = Resolve-DnsName $rec.content -Type TXT -Server 8.8.8.8 -ErrorAction SilentlyContinue\n        $txtValue = ($result.Strings -join '')\n    }\n\n    $bits = Get-ExactDKIMBits $txtValue\n\n    if ($bits) {\n        $color = if ($bits -eq 1024) { 'Yellow' } else { 'Green' }\n        Write-Host \"    Key size: $bits-bit\" -ForegroundColor $color\n        if ($bits -eq 1024) { $weak1024 += $selector } else { $strong++ }\n    } else {\n        Write-Host \"    No valid DKIM key found\" -ForegroundColor Red\n    }\n    Write-Host \"\"\n}\n\n# 6. Final report (100% clean strings)\nWrite-Host \"==============================================\" -ForegroundColor Magenta\nWrite-Host \"DKIM KEY REPORT - $Domain\" -ForegroundColor Magenta\nWrite-Host \"==============================================\" -ForegroundColor Magenta\nWrite-Host \"1024-bit keys (weak - upgrade required) : $($weak1024.Count)\" -ForegroundColor Yellow\nWrite-Host \"2048-bit+ keys (secure)                 : $strong\" -ForegroundColor Green\nWrite-Host \"==============================================\" -ForegroundColor Magenta\n\nif ($weak1024.Count -gt 0) {\n    Write-Host \"`nWEAK 1024-bit selectors that need upgrading:\" -ForegroundColor Red\n    $weak1024 | Sort-Object | ForEach-Object { Write-Host \"    - $_\" -ForegroundColor Yellow }\n    Write-Host \"`nAction: Contact your email providers and request 2048-bit key rotation.\" -ForegroundColor Red\n} else {\n    Write-Host \"`nPERFECT! All DKIM keys are 2048-bit or stronger.\" -ForegroundColor Green\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-9357","post","type-post","status-publish","format-standard","hentry","category-research"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/posts\/9357","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/comments?post=9357"}],"version-history":[{"count":1,"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/posts\/9357\/revisions"}],"predecessor-version":[{"id":9358,"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/posts\/9357\/revisions\/9358"}],"wp:attachment":[{"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/media?parent=9357"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/categories?post=9357"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pariswells.com\/blog\/wp-json\/wp\/v2\/tags?post=9357"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}