int main(void) { char *str_out; char *str_out2; char *salt; const char *passwd = "Correct Horse Battery Staple"; tv(); tv2(); salt = (char *) sodium_malloc(crypto_pwhash_SALTBYTES); str_out = (char *) sodium_malloc(crypto_pwhash_STRBYTES); str_out2 = (char *) sodium_malloc(crypto_pwhash_STRBYTES); memcpy(salt, ">A 16-bytes salt", crypto_pwhash_SALTBYTES); if (crypto_pwhash_str(str_out, passwd, strlen(passwd), OPSLIMIT, MEMLIMIT) != 0) { printf("pwhash_str failure\n"); } if (crypto_pwhash_str(str_out2, passwd, strlen(passwd), OPSLIMIT, MEMLIMIT) != 0) { printf("pwhash_str(2) failure\n"); } if (strcmp(str_out, str_out2) == 0) { printf("pwhash_str doesn't generate different salts\n"); } if (crypto_pwhash_str_verify(str_out, passwd, strlen(passwd)) != 0) { printf("pwhash_str_verify failure\n"); } if (crypto_pwhash_str_verify(str_out, passwd, strlen(passwd)) != 0) { printf("pwhash_str_verify failure\n"); } str_out[14]++; if (crypto_pwhash_str_verify(str_out, passwd, strlen(passwd)) == 0) { printf("pwhash_str_verify(2) failure\n"); } str_out[14]--; assert(str_out[crypto_pwhash_STRBYTES - 1U] == 0); assert(crypto_pwhash_saltbytes() > 0U); assert(crypto_pwhash_strbytes() > 1U); assert(crypto_pwhash_strbytes() > strlen(crypto_pwhash_strprefix())); assert(crypto_pwhash_opslimit_interactive() > 0U); assert(crypto_pwhash_memlimit_interactive() > 0U); assert(crypto_pwhash_opslimit_moderate() > 0U); assert(crypto_pwhash_memlimit_moderate() > 0U); assert(crypto_pwhash_opslimit_sensitive() > 0U); assert(crypto_pwhash_memlimit_sensitive() > 0U); sodium_free(salt); sodium_free(str_out); sodium_free(str_out2); printf("OK\n"); return 0; }
static void str_tests(void) { char *str_out; char *str_out2; char *salt; const char *passwd = "Correct Horse Battery Staple"; salt = (char *) sodium_malloc(crypto_pwhash_argon2id_SALTBYTES); str_out = (char *) sodium_malloc(crypto_pwhash_argon2id_STRBYTES); str_out2 = (char *) sodium_malloc(crypto_pwhash_argon2id_STRBYTES); memcpy(salt, ">A 16-bytes salt", crypto_pwhash_argon2id_SALTBYTES); if (crypto_pwhash_str(str_out, passwd, strlen(passwd), OPSLIMIT, MEMLIMIT) != 0) { printf("pwhash_str failure\n"); } if (crypto_pwhash_str(str_out2, passwd, strlen(passwd), OPSLIMIT, MEMLIMIT) != 0) { printf("pwhash_str(2) failure\n"); } if (strcmp(str_out, str_out2) == 0) { printf("pwhash_str() doesn't generate different salts\n"); } if (crypto_pwhash_str_needs_rehash(str_out, OPSLIMIT, MEMLIMIT) != 0 || crypto_pwhash_str_needs_rehash(str_out, OPSLIMIT, MEMLIMIT) != 0) { printf("needs_rehash() false positive\n"); } if (crypto_pwhash_str_needs_rehash(str_out, OPSLIMIT, MEMLIMIT / 2) != 1 || crypto_pwhash_str_needs_rehash(str_out, OPSLIMIT - 1, MEMLIMIT) != 1 || crypto_pwhash_str_needs_rehash(str_out, OPSLIMIT, MEMLIMIT * 2) != 1 || crypto_pwhash_str_needs_rehash(str_out, OPSLIMIT + 1, MEMLIMIT) != 1) { printf("needs_rehash() false negative (0)\n"); } if (crypto_pwhash_argon2id_str_needs_rehash(str_out, OPSLIMIT, MEMLIMIT / 2) != 1 || crypto_pwhash_argon2id_str_needs_rehash(str_out, OPSLIMIT - 1, MEMLIMIT) != 1 || crypto_pwhash_argon2id_str_needs_rehash(str_out, OPSLIMIT, MEMLIMIT * 2) != 1 || crypto_pwhash_argon2id_str_needs_rehash(str_out, OPSLIMIT + 1, MEMLIMIT) != 1) { printf("needs_rehash() false negative (1)\n"); } if (crypto_pwhash_argon2i_str_needs_rehash(str_out, OPSLIMIT, MEMLIMIT / 2) != -1 || crypto_pwhash_argon2i_str_needs_rehash(str_out, OPSLIMIT - 1, MEMLIMIT) != -1 || crypto_pwhash_argon2i_str_needs_rehash(str_out, OPSLIMIT, MEMLIMIT * 2) != -1 || crypto_pwhash_argon2i_str_needs_rehash(str_out, OPSLIMIT + 1, MEMLIMIT) != -1) { printf("needs_rehash() false negative (2)\n"); } if (crypto_pwhash_str_needs_rehash(str_out, OPSLIMIT, MEMLIMIT / 2) != 1) { printf("pwhash_str_needs_rehash() didn't handle argon2id\n"); } if (crypto_pwhash_str_needs_rehash(str_out + 1, OPSLIMIT, MEMLIMIT) != -1 || crypto_pwhash_argon2id_str_needs_rehash(str_out + 1, OPSLIMIT, MEMLIMIT) != -1) { printf("needs_rehash() didn't fail with an invalid hash string\n"); } if (sodium_is_zero((const unsigned char *) str_out + strlen(str_out), crypto_pwhash_STRBYTES - strlen(str_out)) != 1 || sodium_is_zero((const unsigned char *) str_out2 + strlen(str_out2), crypto_pwhash_STRBYTES - strlen(str_out2)) != 1) { printf("pwhash_argon2id_str() doesn't properly pad with zeros\n"); } if (crypto_pwhash_argon2id_str_verify(str_out, passwd, strlen(passwd)) != 0) { printf("pwhash_argon2id_str_verify(1) failure\n"); } if (crypto_pwhash_str_verify(str_out, passwd, strlen(passwd)) != 0) { printf("pwhash_str_verify(1') failure\n"); } str_out[14]++; if (crypto_pwhash_str_verify(str_out, passwd, strlen(passwd)) != -1) { printf("pwhash_argon2id_str_verify(2) failure\n"); } str_out[14]--; assert(str_out[crypto_pwhash_argon2id_STRBYTES - 1U] == 0); if (crypto_pwhash_str(str_out2, passwd, 0x100000000ULL, OPSLIMIT, MEMLIMIT) != -1) { printf("pwhash_str() with a large password should have failed\n"); } if (crypto_pwhash_str(str_out2, passwd, strlen(passwd), 1, MEMLIMIT) != 0) { printf("pwhash_str() with a small opslimit should not have failed\n"); } if (crypto_pwhash_str(str_out2, passwd, strlen(passwd), 0, MEMLIMIT) != -1) { printf("pwhash_argon2id_str() with a null opslimit should have failed\n"); } if (crypto_pwhash_str_verify("$argon2id$m=65536,t=2,p=1c29tZXNhbHQ" "$9sTbSlTio3Biev89thdrlKKiCaYsjjYVJxGAL3swxpQ", "password", 0x100000000ULL) != -1) { printf("pwhash_str_verify(invalid(0)) failure\n"); } if (crypto_pwhash_str_verify("$argon2id$m=65536,t=2,p=1c29tZXNhbHQ" "$9sTbSlTio3Biev89thdrlKKiCaYsjjYVJxGAL3swxpQ", "password", strlen("password")) != -1) { printf("pwhash_str_verify(invalid(1)) failure %d\n", errno); } if (crypto_pwhash_str_verify("$argon2id$m=65536,t=2,p=1$c29tZXNhbHQ" "9sTbSlTio3Biev89thdrlKKiCaYsjjYVJxGAL3swxpQ", "password", strlen("password")) != -1) { printf("pwhash_str_verify(invalid(2)) failure\n"); } if (crypto_pwhash_str_verify("$argon2id$m=65536,t=2,p=1$c29tZXNhbHQ" "$b2G3seW+uPzerwQQC+/E1K50CLLO7YXy0JRcaTuswRo", "password", strlen("password")) != -1) { printf("pwhash_str_verify(invalid(3)) failure\n"); } if (crypto_pwhash_str_verify("$argon2id$v=19$m=65536,t=2,p=1c29tZXNhbHQ" "$wWKIMhR9lyDFvRz9YTZweHKfbftvj+qf+YFY4NeBbtA", "password", strlen("password")) != -1) { printf("pwhash_str_verify(invalid(4)) failure\n"); } if (crypto_pwhash_str_verify("$argon2id$v=19$m=65536,t=2,p=1$c29tZXNhbHQ" "wWKIMhR9lyDFvRz9YTZweHKfbftvj+qf+YFY4NeBbtA", "password", strlen("password")) != -1) { printf("pwhash_str_verify(invalid(5)) failure\n"); } if (crypto_pwhash_str_verify("$argon2id$v=19$m=65536,t=2,p=1$c29tZXNhbHQ" "$8iIuixkI73Js3G1uMbezQXD0b8LG4SXGsOwoQkdAQIM", "password", strlen("password")) != -1) { printf("pwhash_str_verify(invalid(6)) failure\n"); } if (crypto_pwhash_str_verify("$argon2id$v=19$m=256,t=3,p=1$MDEyMzQ1Njc" "$G5ajKFCoUzaXRLdz7UJb5wGkb2Xt+X5/GQjUYtS2+TE", "password", strlen("password")) != 0) { printf("pwhash_str_verify(valid(7)) failure\n"); } if (crypto_pwhash_str_verify("$argon2id$v=19$m=256,t=3,p=1$MDEyMzQ1Njc" "$G5ajKFCoUzaXRLdz7UJb5wGkb2Xt+X5/GQjUYtS2+TE", "passwore", strlen("passwore")) != -1 || errno != EINVAL) { printf("pwhash_str_verify(invalid(7)) failure\n"); } if (crypto_pwhash_str_verify("$Argon2id$v=19$m=256,t=3,p=1$MDEyMzQ1Njc" "$G5ajKFCoUzaXRLdz7UJb5wGkb2Xt+X5/GQjUYtS2+TE", "password", strlen("password")) != -1 || errno != EINVAL) { printf("pwhash_str_verify(invalid(8)) failure\n"); } if (crypto_pwhash_str_verify("$argon2id$v=19$m=256,t=3,p=2$MDEyMzQ1Njc" "$G5ajKFCoUzaXRLdz7UJb5wGkb2Xt+X5/GQjUYtS2+TE", "password", strlen("password")) != -1 || errno != EINVAL) { printf("pwhash_str_verify(invalid(9)) failure\n"); } assert(crypto_pwhash_str_alg(str_out, "test", 4, OPSLIMIT, MEMLIMIT, crypto_pwhash_ALG_ARGON2ID13) == 0); assert(crypto_pwhash_argon2id_str_verify(str_out, "test", 4) == 0); assert(crypto_pwhash_argon2id_str_needs_rehash(str_out, OPSLIMIT, MEMLIMIT) == 0); assert(crypto_pwhash_argon2id_str_needs_rehash(str_out, OPSLIMIT / 2, MEMLIMIT) == 1); assert(crypto_pwhash_argon2id_str_needs_rehash(str_out, OPSLIMIT, MEMLIMIT / 2) == 1); assert(crypto_pwhash_argon2id_str_needs_rehash(str_out, 0, 0) == 1); assert(crypto_pwhash_argon2i_str_needs_rehash(str_out, 0, 0) == -1); assert(crypto_pwhash_argon2id_str_needs_rehash(str_out + 1, OPSLIMIT, MEMLIMIT) == -1); assert(crypto_pwhash_argon2i_str_needs_rehash(str_out, 0, 0) == -1); assert(crypto_pwhash_argon2i_str_needs_rehash("", OPSLIMIT, MEMLIMIT) == -1); assert(crypto_pwhash_str_alg(str_out, "test", 4, OPSLIMIT, MEMLIMIT, crypto_pwhash_ALG_ARGON2I13) == 0); assert(crypto_pwhash_argon2i_str_verify(str_out, "test", 4) == 0); assert(crypto_pwhash_argon2i_str_needs_rehash(str_out, OPSLIMIT, MEMLIMIT) == 0); assert(crypto_pwhash_argon2i_str_needs_rehash(str_out, OPSLIMIT / 2, MEMLIMIT) == 1); assert(crypto_pwhash_argon2i_str_needs_rehash(str_out, OPSLIMIT, MEMLIMIT / 2) == 1); assert(crypto_pwhash_argon2i_str_needs_rehash(str_out, 0, 0) == 1); assert(crypto_pwhash_argon2id_str_needs_rehash(str_out, 0, 0) == -1); assert(crypto_pwhash_argon2i_str_needs_rehash("", OPSLIMIT, MEMLIMIT) == -1); assert(crypto_pwhash_argon2i_str_needs_rehash(str_out + 1, OPSLIMIT, MEMLIMIT) == -1); sodium_free(salt); sodium_free(str_out); sodium_free(str_out2); }
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 }