Created
February 9, 2020 09:30
-
-
Save mwgamera/b228cbf3afb2059699ea0521de859789 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env nickle | |
# klg, Jul 2015 | |
int[16] ChaCha20(int[16] x) | |
/* ChaCha20 hash function. */ | |
{ | |
int[16] s = x; | |
const int M = 0xffffffff; | |
void arx(int a, int b, int c, int r) { | |
s[c] ^= s[a] = (s[a] + s[b]) & M; | |
s[c] = (s[c] << r | s[c] >> (32 - r)) & M; | |
} | |
void qround(int a, int b, int c, int d) { | |
arx(a, b, d, 16); | |
arx(c, d, b, 12); | |
arx(a, b, d, 8); | |
arx(c, d, b, 7); | |
} | |
for (int i = 0; i < 10; i++) { | |
qround(0, 4, 8,12); | |
qround(1, 5, 9,13); | |
qround(2, 6,10,14); | |
qround(3, 7,11,15); | |
qround(0, 5,10,15); | |
qround(1, 6,11,12); | |
qround(2, 7, 8,13); | |
qround(3, 4, 9,14); | |
} | |
for (int i = 0; i < 16; i++) | |
s[i] = (s[i] + x[i]) & M; | |
return s; | |
} | |
namespace Random { | |
global int[16] state = { | |
0x61707865, 0x3320646e, 0x79622d32, 0x6b206574, 0, ... }; | |
global int buffer = 0, buffill = 0; | |
void reseed() { | |
twixt(file f = File::open("/dev/urandom", "r"); File::close(f)) { | |
for (int i = 4; i < 12+3; i++) { | |
int s = 0; | |
for (int k = 0; k < 4; k++) | |
s <<= 8, s |= File::getb(f); | |
state[i] = s; | |
} | |
state[15] = 0; | |
} | |
} | |
int getbits(int n) { | |
while (buffill < n) { | |
if (state[15] == 0) | |
reseed(); | |
int[] b = ChaCha20(state); | |
state[15] = (state[15] + 1) & 0xffffffff; | |
for (int i = 0; i < dim(b); i++) { | |
buffer <<= 32; | |
buffer ^= b[i]; | |
buffill += 32; | |
} | |
} | |
int r = buffer & ((1 << n) - 1); | |
buffer >>= n; | |
buffill -= n; | |
return r; | |
} | |
public int randint(int range) | |
/* Return random integer in 0 .. 'range'-1 */ | |
{ | |
int x, b = 16 + bit_width(range), | |
W = (1 << b) - 1, M = W - (W % range); | |
do { | |
x = getbits(b); | |
} while (x >= M); | |
return x % range; | |
} | |
} | |
real log2(real a) | |
/* Base-2 logarithm of a with exact integer results. */ | |
{ | |
real c = Math::log2(a); | |
int z = floor(c + 0.5); | |
if (is_rational(a) && 2 ** z == a) | |
return z; | |
return c; | |
} | |
string mkpass(real strength, string alpha) | |
/* Create random password of given strength in bits. */ | |
{ | |
int N = String::length(alpha); | |
int L = ceil(strength / log2(N)); | |
return String::new((int[L]){ | |
[i] = alpha[Random::randint(N)] }); | |
} | |
string alphabet(string desc) | |
/* Expand ranges in short description of the alphabet. */ | |
{ | |
void[int] h = { => <> }; | |
for (int i = 0; i < String::length(desc); i++) | |
if (desc[i] == '-' && | |
i-1 >= 0 && i+1 < String::length(desc)) { | |
for (int j = desc[i-1]; j < desc[i+1]; j++) | |
h[j] = <>; | |
} else { | |
h[desc[i]] = <>; | |
} | |
return String::new(hash_keys(h)); | |
} | |
if (dim(argv) > 0) { | |
void die(string s ...) { | |
for (int i = 0; i < dim(s); i++) | |
File::fprintf(stderr, "%s: %s\n", argv[0], s[i]); | |
File::fprintf(stderr, "Usage: %s [strength] [alphabet]\n", argv[0]); | |
exit(1); | |
} | |
poly a = <>, s = <>; | |
if (dim(argv) > 2) { | |
s = string_to_real(argv[1]); | |
a = alphabet(argv[2]); | |
} | |
else if (dim(argv) > 1) { | |
bool q = String::length(argv[1]) > 0; | |
q &&= argv[1][0] != '0'; | |
for (int i = 0; i < String::length(argv[1]); i++) | |
q &&= String::inchars(argv[1][i], "0123456789"); | |
if (q) | |
s = string_to_real(argv[1]); | |
else | |
a = alphabet(argv[1]); | |
} | |
if (is_void(a)) | |
a = alphabet("0-9A-Za-z"); | |
else if (String::length(a) < 2) | |
die("Alphabet must have at least 2 symbols."); | |
if (is_void(s)) | |
s = max(floor(15 * log2(String::length(a))), 80); | |
else if (s <= 0) | |
die("Strength must be a positive integer in bits."); | |
if (s <= 40) | |
File::fprintf(stderr, | |
"%s: Warning: Creating a very weak password.\n", argv[0]); | |
printf("%s\n", mkpass(s, a)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment