/* * Calculate a uniformly distributed random number less than upper_bound * avoiding "modulo bias". * * Uniformity is achieved by generating new random numbers until the one * returned is outside the range [0, 2**32 % upper_bound). This * guarantees the selected random number will be inside * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) * after reduction modulo upper_bound. */ crypto_uint4 alt_arc4random_uniform(crypto_uint4 upper_bound) { crypto_uint4 r, min; if (upper_bound < 2U) { return 0U; } /* 2**32 % x == (2**32 - x) % x */ min = (crypto_uint4) (- upper_bound % upper_bound); /* * This could theoretically loop forever but each retry has * p > 0.5 (worst case, usually far better) of selecting a * number inside the range we need, so it should rarely need * to re-roll. */ for (;;) { r = alt_arc4random(); if (r >= min) { break; } } return r % upper_bound; }
/* * Calculate a uniformly distributed random number less than upper_bound * avoiding "modulo bias". * * Uniformity is achieved by generating new random numbers until the one * returned is outside the range [0, 2**32 % upper_bound). This * guarantees the selected random number will be inside * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) * after reduction modulo upper_bound. */ unsigned int alt_arc4random_uniform(unsigned int upper_bound) { unsigned int r, min; if (upper_bound < 2U) { return 0U; } #if (ULONG_MAX > 0xffffffffUL) min = (unsigned int) (0x100000000UL % upper_bound); #else /* Calculate (2**32 % upper_bound) avoiding 64-bit math */ if (upper_bound > 0x80000000) min = 1 + ~upper_bound; /* 2**32 - upper_bound */ else { /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */ min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound; } #endif /* * This could theoretically loop forever but each retry has * p > 0.5 (worst case, usually far better) of selecting a * number inside the range we need, so it should rarely need * to re-roll. */ for (;;) { r = alt_arc4random(); if (r >= min) { break; } } return r % upper_bound; }
static unsigned int pw_zrand(void) { return (unsigned int) alt_arc4random(); }
static char *best_crypt(const char * const pwd, const unsigned long max_concurrent_logins, const unsigned long long max_auth_memory) { #if defined(crypto_pwhash_STRBYTES) || defined(crypto_pwhash_scryptsalsa208sha256_STRBYTES) # ifndef crypto_pwhash_STRBYTES # define crypto_pwhash_STRBYTES crypto_pwhash_scryptsalsa208sha256_STRBYTES # define crypto_pwhash_str crypto_pwhash_scryptsalsa208sha256_str # endif static char hash[crypto_pwhash_STRBYTES]; struct timeval tv_start, tv_now; struct timezone tz; unsigned long long probe_ops = MIN_AUTH_OPS; unsigned long long ops = 0ULL; unsigned long long auth_memory = max_auth_memory / (unsigned long long) max_concurrent_logins; unsigned long long elapsed; unsigned long long auth_time_ms = DEFAULT_AUTH_TIME_MS; if (max_concurrent_logins > AUTH_CORES) { auth_time_ms /= (unsigned long long) max_concurrent_logins / AUTH_CORES; } if (auth_time_ms < MIN_AUTH_TIME_MS) { auth_time_ms = MIN_AUTH_TIME_MS; } if (auth_memory < MIN_AUTH_MEMORY) { auth_memory = MIN_AUTH_MEMORY; } gettimeofday(&tv_start, &tz); for (;;) { if (crypto_pwhash_str(hash, pwd, strlen(pwd), probe_ops, auth_memory) != 0) { no_mem(); } ops += probe_ops; probe_ops *= 2; gettimeofday(&tv_now, &tz); elapsed = (tv_now.tv_sec * 1000ULL + tv_now.tv_usec / 1000ULL) - (tv_start.tv_sec * 1000ULL + tv_start.tv_usec / 1000ULL); if (elapsed >= auth_time_ms) { break; } } if (ops < MIN_AUTH_OPS) { ops = MIN_AUTH_OPS; } if (crypto_pwhash_str(hash, pwd, strlen(pwd), ops, auth_memory) != 0) { no_mem(); } return hash; #else static const char crcars[64] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"; const char *crypted; if ((crypted = (const char *) /* bcrypt */ crypt("test", "$2a$08$1234567890123456789012")) != NULL && strcmp(crypted, "$2a$08$123456789012345678901uBdmsfIXjJcWQwz1wT/IZrWhimJ6xy6a") == 0) { char salt[] = "$2a$10$0000000000000000000000"; int c = 28; do { c--; salt[c] = crcars[alt_arc4random() & 63]; } while (c > 7); return (char *) crypt(pwd, salt); } else if ((crypted = (const char *) /* SHA-512 */ crypt("test", "$6$1234567890123456$")) != NULL && strcmp(crypted, "$6$1234567890123456$d.pgKQFaiD8bRiExg5NesbGR/" "3u51YvxeYaQXPzx4C6oSYREw8VoReiuYZjx0V9OhGVTZF" "qhc6emAxT1RC5BV.") == 0) { char salt[] = "$6$0000000000000000"; int c = 18; do { c--; salt[c] = crcars[alt_arc4random() & 63]; } while (c > 3); return (char *) crypt(pwd, salt); } else if ((crypted = (const char *) /* MD5 */ crypt("test", "$1$12345678$")) != NULL && strcmp(crypted, "$1$12345678$oEitTZYQtRHfNGmsFvTBA/") == 0) { char salt[] = "$1$00000000"; int c = 10; do { c--; salt[c] = crcars[alt_arc4random() & 63]; } while (c > 3); return (char *) crypt(pwd, salt); } else { fprintf(stderr, "No useable password hashing function found\n" "Please install libsodium (https://libsodium.org) and recompile pure-ftpd.\n"); exit(EXIT_FAILURE); } #endif }