/*
 * 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;
}
예제 #2
0
/*
 * 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;
}
예제 #3
0
static unsigned int pw_zrand(void)
{
    return (unsigned int) alt_arc4random();
}
예제 #4
0
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
}