Testing Password Strength

by Oct 7, 2019

In previous tips, we already talked about services such as haveIbeenpwned.com. They harvest leaked passwords from previous hacker attacks so you can check whether your password has been compromised and is likely to be included in future dictionary attacks.

Below, you find two useful functions: Test-Password asks for a SecureString so when you get prompted, your input is masked. Convert-SecureStringToText then converts the entered password to plain text. Test-Password then hashes your entered password and sends only the first 5 bytes to the web service. Your original password is never compromised.

The web service returns all compromised password hashes that start with your 5 bytes, so you can check whether one of the returned hashes matches your hash.

If your password has been seen in previous attacks, you’ll receive the number of times it was involved in attacks. Any password that returns a number greater than 0 must be considered insecure, and should not be used.

Please remember: when a password returns a number greater than 0, this does not mean that your own password was compromised. It does mean that anywhere in the world, your password surfaced during an attack, so either you or anyone else has used it and was hacked. No matter whether it was you or someone else: this password is now insecure because it became part of attack dictionaries that hacker will try on accounts. If you continue to use this password, chances are high that hackers will break into it using simple (and fast) dictionary attacks anytime soon in the future.

function Convert-SecureStringToText
{
  param
  (
    [Parameter(Mandatory,ValueFromPipeline)]
    [System.Security.SecureString]
    $Password
  )
  
  process
  {
    $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
    [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
  }
}

function Test-Password
{
  [CmdletBinding()]
  param
  (
    [Parameter(Mandatory, Position=0)]
    [System.Security.SecureString]
    $Password
  )
  
  $plain = $Password | Convert-SecureStringToText
  
  $bytes = [Text.Encoding]::UTF8.GetBytes($plain)
  $stream = [IO.MemoryStream]::new($bytes)
  $hash = Get-FileHash -Algorithm 'SHA1' -InputStream $stream
  $stream.Close()
  $stream.Dispose()
  
  $first5hashChars,$remainingHashChars = $hash.Hash -split '(?<=^.{5})'
  
  $url = "https://api.pwnedpasswords.com/range/$first5hashChars"
  [Net.ServicePointManager]::SecurityProtocol = 'Tls12'
  $response = Invoke-RestMethod -Uri $url -UseBasicParsing
  
  $lines = $response -split '\r\n'
  $filteredLines = $lines -like "$remainingHashChars*"
  
  [int]($filteredLines -split ':')[-1]
}


Twitter This Tip! ReTweet this Tip!