Skip to content

Instantly share code, notes, and snippets.

@mholt
Created August 12, 2018 19:27
Show Gist options
  • Save mholt/1b05760370cefaf42e062b6428efac71 to your computer and use it in GitHub Desktop.
Save mholt/1b05760370cefaf42e062b6428efac71 to your computer and use it in GitHub Desktop.
Use Go to check if a password has been pwned
// checkPasswordPwned checks if the password is "pwned" according
// to the API offered by https://haveibeenpwned.com/. (The password
// is not sent to their servers to do the check.)
//
// This function returns the number of times the password appears in
// their data set. A password is pwned, or compromised, if the return
// value is greater than 0.
//
// API Docs: https://haveibeenpwned.com/API/v2#SearchingPwnedPasswordsByRange
//
// Written by Matthew Holt (@mholt6) for the Relica code base: https://relicabackup.com
func checkPasswordPwned(plaintextPass string) (int, error) {
pwdSha1 := fmt.Sprintf("%X", sha1.Sum([]byte(plaintextPass)))
prefix := pwdSha1[:5]
endpoint := fmt.Sprintf("https://api.pwnedpasswords.com/range/%s", prefix)
resp, err := http.Get(endpoint)
if err != nil {
return 0, err
}
defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
parts := strings.SplitN(scanner.Text(), ":", 2)
if len(parts) < 2 {
continue
}
suffix := parts[0]
countStr := parts[1]
if prefix+suffix == pwdSha1 {
count, err := strconv.Atoi(countStr)
if err != nil {
return 0, fmt.Errorf("invalid count value received: %v", err)
}
return count, nil
}
}
if err := scanner.Err(); err != nil {
return 0, fmt.Errorf("scanning response body: %v", err)
}
return 0, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment