zxcvbn icon indicating copy to clipboard operation
zxcvbn copied to clipboard

Repeated combining diacritics cause unexpected zero score

Open rwelin opened this issue 4 years ago • 2 comments

When a combining diacritic character is repeated in consecutive runes, the PasswordStrength function gives a score of 0. For example the string below where the \u0300 rune appears twice after the initial A:

s := "A\u0300\u0300HLUMoB8g3kqgpjc3"
result := zxcvbn.PasswordStrength(s, nil)
// result.Score == 0

However, if the repeated combining characters are at the end of the string the score is still high:

s := "HLUMoB8g3kqgpjc3A\u0300\u0300"
result := zxcvbn.PasswordStrength(s, nil)
// result.Score == 4

I've not been able to look into this very deeply but disabling the repeatMatch in Omnimatch results in score of 4.

rwelin avatar Mar 11 '20 19:03 rwelin

Hi,

Our handling of non-ascii passwords is indeed not ideal. The bug might be either in repeatMatch or in the way we compute the scoring... Both parts should probably be rewritten to work on runes (but the rewrite is probably not trivial).

By curiosity: have you tried running this test with the "upstream" dropbox zxcvbn library ? I'm curious about the result.

vanackere avatar Nov 18 '20 22:11 vanackere

Hi! It seems the dropbox zxcvbn node package gives score of 4 for both strings I used in the description:

{
  "requires": true,
  "lockfileVersion": 1,
  "dependencies": {
    "zxcvbn": {
      "version": "4.4.2",
      "resolved": "https://registry.npmjs.org/zxcvbn/-/zxcvbn-4.4.2.tgz",
      "integrity": "sha1-KOwXzwl0PtyrBW3dixsGJizHPDA="
    }
  }
}
> var zxcvbn = require('zxcvbn');
undefined
> zxcvbn('HLUMoB8g3kqgpjc3A\u0300\u0300');
{
  password: 'HLUMoB8g3kqgpjc3À̀',
  guesses: 10000000000000000000,
  guesses_log10: 19,
  sequence: [
    {
      pattern: 'bruteforce',
      token: 'HLUMoB8g3kqgpjc3À̀',
      i: 0,
      j: 18,
      guesses: 10000000000000000000,
      guesses_log10: 19
    }
  ],
  calc_time: 6,
  crack_times_seconds: {
    online_throttling_100_per_hour: 360000000000000000000,
    online_no_throttling_10_per_second: 1000000000000000000,
    offline_slow_hashing_1e4_per_second: 1000000000000000,
    offline_fast_hashing_1e10_per_second: 1000000000
  },
  crack_times_display: {
    online_throttling_100_per_hour: 'centuries',
    online_no_throttling_10_per_second: 'centuries',
    offline_slow_hashing_1e4_per_second: 'centuries',
    offline_fast_hashing_1e10_per_second: '31 years'
  },
  score: 4,
  feedback: { warning: '', suggestions: [] }
}
> zxcvbn('A\u0300\u0300HLUMoB8g3kqgpjc3');
{
  password: 'À̀HLUMoB8g3kqgpjc3',
  guesses: 10000000000000000000,
  guesses_log10: 19,
  sequence: [
    {
      pattern: 'bruteforce',
      token: 'À̀HLUMoB8g3kqgpjc3',
      i: 0,
      j: 18,
      guesses: 10000000000000000000,
      guesses_log10: 19
    }
  ],
  calc_time: 4,
  crack_times_seconds: {
    online_throttling_100_per_hour: 360000000000000000000,
    online_no_throttling_10_per_second: 1000000000000000000,
    offline_slow_hashing_1e4_per_second: 1000000000000000,
    offline_fast_hashing_1e10_per_second: 1000000000
  },
  crack_times_display: {
    online_throttling_100_per_hour: 'centuries',
    online_no_throttling_10_per_second: 'centuries',
    offline_slow_hashing_1e4_per_second: 'centuries',
    offline_fast_hashing_1e10_per_second: '31 years'
  },
  score: 4,
  feedback: { warning: '', suggestions: [] }
}

rwelin avatar Nov 19 '20 07:11 rwelin