Public/Test-HibpPwnedPassword.ps1
function Test-HibpPwnedPassword { <# .SYNOPSIS Checks if a password has been exposed in a data breach. .DESCRIPTION Checks if a password has been exposed in a data breach by querying the Pwned Passwords API using the k-Anonymity model. The function hashes the password with SHA-1, sends the first 5 characters of the hash to the API, and then checks the returned list of hash suffixes for a match. This function does NOT send your plain text password over the internet. .PARAMETER Password The password to check, as a SecureString because Microsoft doesn't like it when you publish to the Gallery with clear text. .EXAMPLE Test-HibpPwnedPassword -Password (Read-Host -AsSecureString) Prompts for a password securely and checks if it has been pwned. .EXAMPLE 'password' | ConvertTo-SecureString -AsPlainText -Force | Test-HibpPwnedPassword Checks the password 'password' to see if it has been pwned. .LINK https://haveibeenpwned.com/API/v3#PwnedPasswords #> [CmdletBinding()] Param( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline)] [System.Security.SecureString]$Password ) begin { $sha1 = [System.Security.Cryptography.SHA1]::Create() } process { $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password) $plainTextPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr) [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) $passwordBytes = [System.Text.Encoding]::UTF8.GetBytes($plainTextPassword) $hashBytes = $sha1.ComputeHash($passwordBytes) $hashString = ($hashBytes | ForEach-Object { $_.ToString('X2') }) -join '' $prefix = $hashString.Substring(0, 5) $suffix = $hashString.Substring(5) $uri = 'https://api.pwnedpasswords.com/range/{0}' -f $prefix $headers = @{ 'Add-Padding' = 'true' } try { $response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers -ErrorAction Stop $pwnedSuffixes = $response.Split([Environment]::NewLine) | ForEach-Object { $_.Split(':')[0] } if ($pwnedSuffixes -contains $suffix) { $true } else { $false } } catch { Write-Error "Failed to query the Pwned Passwords API: $_" Write-Output $false } } end { $sha1.Dispose() } } |