10ac341f1SConrad Meyer 
20ac341f1SConrad Meyer #include <errno.h>
30ac341f1SConrad Meyer #include <limits.h>
40ac341f1SConrad Meyer #include <stddef.h>
50ac341f1SConrad Meyer #include <stdint.h>
60ac341f1SConrad Meyer #include <string.h>
70ac341f1SConrad Meyer 
80ac341f1SConrad Meyer #include "argon2-core.h"
90ac341f1SConrad Meyer #include "argon2.h"
100ac341f1SConrad Meyer #include "crypto_pwhash_argon2id.h"
110ac341f1SConrad Meyer #include "private/common.h"
120ac341f1SConrad Meyer #include "randombytes.h"
130ac341f1SConrad Meyer #include "utils.h"
140ac341f1SConrad Meyer 
150ac341f1SConrad Meyer #define STR_HASHBYTES 32U
160ac341f1SConrad Meyer 
170ac341f1SConrad Meyer int
crypto_pwhash_argon2id_alg_argon2id13(void)180ac341f1SConrad Meyer crypto_pwhash_argon2id_alg_argon2id13(void)
190ac341f1SConrad Meyer {
200ac341f1SConrad Meyer     return crypto_pwhash_argon2id_ALG_ARGON2ID13;
210ac341f1SConrad Meyer }
220ac341f1SConrad Meyer 
230ac341f1SConrad Meyer size_t
crypto_pwhash_argon2id_bytes_min(void)240ac341f1SConrad Meyer crypto_pwhash_argon2id_bytes_min(void)
250ac341f1SConrad Meyer {
260ac341f1SConrad Meyer     COMPILER_ASSERT(crypto_pwhash_argon2id_BYTES_MIN >= ARGON2_MIN_OUTLEN);
270ac341f1SConrad Meyer     return crypto_pwhash_argon2id_BYTES_MIN;
280ac341f1SConrad Meyer }
290ac341f1SConrad Meyer 
300ac341f1SConrad Meyer size_t
crypto_pwhash_argon2id_bytes_max(void)310ac341f1SConrad Meyer crypto_pwhash_argon2id_bytes_max(void)
320ac341f1SConrad Meyer {
330ac341f1SConrad Meyer     COMPILER_ASSERT(crypto_pwhash_argon2id_BYTES_MAX <= ARGON2_MAX_OUTLEN);
340ac341f1SConrad Meyer     return crypto_pwhash_argon2id_BYTES_MAX;
350ac341f1SConrad Meyer }
360ac341f1SConrad Meyer 
370ac341f1SConrad Meyer size_t
crypto_pwhash_argon2id_passwd_min(void)380ac341f1SConrad Meyer crypto_pwhash_argon2id_passwd_min(void)
390ac341f1SConrad Meyer {
400ac341f1SConrad Meyer     COMPILER_ASSERT(crypto_pwhash_argon2id_PASSWD_MIN >= ARGON2_MIN_PWD_LENGTH);
410ac341f1SConrad Meyer     return crypto_pwhash_argon2id_PASSWD_MIN;
420ac341f1SConrad Meyer }
430ac341f1SConrad Meyer 
440ac341f1SConrad Meyer size_t
crypto_pwhash_argon2id_passwd_max(void)450ac341f1SConrad Meyer crypto_pwhash_argon2id_passwd_max(void)
460ac341f1SConrad Meyer {
470ac341f1SConrad Meyer     COMPILER_ASSERT(crypto_pwhash_argon2id_PASSWD_MAX <= ARGON2_MAX_PWD_LENGTH);
480ac341f1SConrad Meyer     return crypto_pwhash_argon2id_PASSWD_MAX;
490ac341f1SConrad Meyer }
500ac341f1SConrad Meyer 
510ac341f1SConrad Meyer size_t
crypto_pwhash_argon2id_saltbytes(void)520ac341f1SConrad Meyer crypto_pwhash_argon2id_saltbytes(void)
530ac341f1SConrad Meyer {
540ac341f1SConrad Meyer     COMPILER_ASSERT(crypto_pwhash_argon2id_SALTBYTES >= ARGON2_MIN_SALT_LENGTH);
550ac341f1SConrad Meyer     COMPILER_ASSERT(crypto_pwhash_argon2id_SALTBYTES <= ARGON2_MAX_SALT_LENGTH);
560ac341f1SConrad Meyer     return crypto_pwhash_argon2id_SALTBYTES;
570ac341f1SConrad Meyer }
580ac341f1SConrad Meyer 
590ac341f1SConrad Meyer size_t
crypto_pwhash_argon2id_strbytes(void)600ac341f1SConrad Meyer crypto_pwhash_argon2id_strbytes(void)
610ac341f1SConrad Meyer {
620ac341f1SConrad Meyer     return crypto_pwhash_argon2id_STRBYTES;
630ac341f1SConrad Meyer }
640ac341f1SConrad Meyer 
650ac341f1SConrad Meyer const char*
crypto_pwhash_argon2id_strprefix(void)660ac341f1SConrad Meyer crypto_pwhash_argon2id_strprefix(void)
670ac341f1SConrad Meyer {
680ac341f1SConrad Meyer     return crypto_pwhash_argon2id_STRPREFIX;
690ac341f1SConrad Meyer }
700ac341f1SConrad Meyer 
710ac341f1SConrad Meyer size_t
crypto_pwhash_argon2id_opslimit_min(void)720ac341f1SConrad Meyer crypto_pwhash_argon2id_opslimit_min(void)
730ac341f1SConrad Meyer {
740ac341f1SConrad Meyer     COMPILER_ASSERT(crypto_pwhash_argon2id_OPSLIMIT_MIN >= ARGON2_MIN_TIME);
750ac341f1SConrad Meyer     return crypto_pwhash_argon2id_OPSLIMIT_MIN;
760ac341f1SConrad Meyer }
770ac341f1SConrad Meyer 
780ac341f1SConrad Meyer size_t
crypto_pwhash_argon2id_opslimit_max(void)790ac341f1SConrad Meyer crypto_pwhash_argon2id_opslimit_max(void)
800ac341f1SConrad Meyer {
810ac341f1SConrad Meyer     COMPILER_ASSERT(crypto_pwhash_argon2id_OPSLIMIT_MAX <= ARGON2_MAX_TIME);
820ac341f1SConrad Meyer     return crypto_pwhash_argon2id_OPSLIMIT_MAX;
830ac341f1SConrad Meyer }
840ac341f1SConrad Meyer 
850ac341f1SConrad Meyer size_t
crypto_pwhash_argon2id_memlimit_min(void)860ac341f1SConrad Meyer crypto_pwhash_argon2id_memlimit_min(void)
870ac341f1SConrad Meyer {
880ac341f1SConrad Meyer     COMPILER_ASSERT((crypto_pwhash_argon2id_MEMLIMIT_MIN / 1024U) >= ARGON2_MIN_MEMORY);
890ac341f1SConrad Meyer     return crypto_pwhash_argon2id_MEMLIMIT_MIN;
900ac341f1SConrad Meyer }
910ac341f1SConrad Meyer 
920ac341f1SConrad Meyer size_t
crypto_pwhash_argon2id_memlimit_max(void)930ac341f1SConrad Meyer crypto_pwhash_argon2id_memlimit_max(void)
940ac341f1SConrad Meyer {
950ac341f1SConrad Meyer     COMPILER_ASSERT((crypto_pwhash_argon2id_MEMLIMIT_MAX / 1024U) <= ARGON2_MAX_MEMORY);
960ac341f1SConrad Meyer     return crypto_pwhash_argon2id_MEMLIMIT_MAX;
970ac341f1SConrad Meyer }
980ac341f1SConrad Meyer 
990ac341f1SConrad Meyer size_t
crypto_pwhash_argon2id_opslimit_interactive(void)1000ac341f1SConrad Meyer crypto_pwhash_argon2id_opslimit_interactive(void)
1010ac341f1SConrad Meyer {
1020ac341f1SConrad Meyer     return crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE;
1030ac341f1SConrad Meyer }
1040ac341f1SConrad Meyer 
1050ac341f1SConrad Meyer size_t
crypto_pwhash_argon2id_memlimit_interactive(void)1060ac341f1SConrad Meyer crypto_pwhash_argon2id_memlimit_interactive(void)
1070ac341f1SConrad Meyer {
1080ac341f1SConrad Meyer     return crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE;
1090ac341f1SConrad Meyer }
1100ac341f1SConrad Meyer 
1110ac341f1SConrad Meyer size_t
crypto_pwhash_argon2id_opslimit_moderate(void)1120ac341f1SConrad Meyer crypto_pwhash_argon2id_opslimit_moderate(void)
1130ac341f1SConrad Meyer {
1140ac341f1SConrad Meyer     return crypto_pwhash_argon2id_OPSLIMIT_MODERATE;
1150ac341f1SConrad Meyer }
1160ac341f1SConrad Meyer 
1170ac341f1SConrad Meyer size_t
crypto_pwhash_argon2id_memlimit_moderate(void)1180ac341f1SConrad Meyer crypto_pwhash_argon2id_memlimit_moderate(void)
1190ac341f1SConrad Meyer {
1200ac341f1SConrad Meyer     return crypto_pwhash_argon2id_MEMLIMIT_MODERATE;
1210ac341f1SConrad Meyer }
1220ac341f1SConrad Meyer 
1230ac341f1SConrad Meyer size_t
crypto_pwhash_argon2id_opslimit_sensitive(void)1240ac341f1SConrad Meyer crypto_pwhash_argon2id_opslimit_sensitive(void)
1250ac341f1SConrad Meyer {
1260ac341f1SConrad Meyer     return crypto_pwhash_argon2id_OPSLIMIT_SENSITIVE;
1270ac341f1SConrad Meyer }
1280ac341f1SConrad Meyer 
1290ac341f1SConrad Meyer size_t
crypto_pwhash_argon2id_memlimit_sensitive(void)1300ac341f1SConrad Meyer crypto_pwhash_argon2id_memlimit_sensitive(void)
1310ac341f1SConrad Meyer {
1320ac341f1SConrad Meyer     return crypto_pwhash_argon2id_MEMLIMIT_SENSITIVE;
1330ac341f1SConrad Meyer }
1340ac341f1SConrad Meyer 
1350ac341f1SConrad Meyer int
crypto_pwhash_argon2id(unsigned char * const out,unsigned long long outlen,const char * const passwd,unsigned long long passwdlen,const unsigned char * const salt,unsigned long long opslimit,size_t memlimit,int alg)1360ac341f1SConrad Meyer crypto_pwhash_argon2id(unsigned char *const out, unsigned long long outlen,
1370ac341f1SConrad Meyer                        const char *const passwd, unsigned long long passwdlen,
1380ac341f1SConrad Meyer                        const unsigned char *const salt,
1390ac341f1SConrad Meyer                        unsigned long long opslimit, size_t memlimit, int alg)
1400ac341f1SConrad Meyer {
1410ac341f1SConrad Meyer     memset(out, 0, outlen);
1420ac341f1SConrad Meyer     if (outlen > crypto_pwhash_argon2id_BYTES_MAX) {
1430ac341f1SConrad Meyer         errno = EFBIG;
1440ac341f1SConrad Meyer         return -1;
1450ac341f1SConrad Meyer     }
1460ac341f1SConrad Meyer     if (outlen < crypto_pwhash_argon2id_BYTES_MIN) {
1470ac341f1SConrad Meyer         errno = EINVAL;
1480ac341f1SConrad Meyer         return -1;
1490ac341f1SConrad Meyer     }
1500ac341f1SConrad Meyer     if (passwdlen > crypto_pwhash_argon2id_PASSWD_MAX ||
1510ac341f1SConrad Meyer         opslimit > crypto_pwhash_argon2id_OPSLIMIT_MAX ||
1520ac341f1SConrad Meyer         memlimit > crypto_pwhash_argon2id_MEMLIMIT_MAX) {
1530ac341f1SConrad Meyer         errno = EFBIG;
1540ac341f1SConrad Meyer         return -1;
1550ac341f1SConrad Meyer     }
1560ac341f1SConrad Meyer     if (passwdlen < crypto_pwhash_argon2id_PASSWD_MIN ||
1570ac341f1SConrad Meyer         opslimit < crypto_pwhash_argon2id_OPSLIMIT_MIN ||
1580ac341f1SConrad Meyer         memlimit < crypto_pwhash_argon2id_MEMLIMIT_MIN) {
1590ac341f1SConrad Meyer         errno = EINVAL;
1600ac341f1SConrad Meyer         return -1;
1610ac341f1SConrad Meyer     }
1620ac341f1SConrad Meyer     switch (alg) {
1630ac341f1SConrad Meyer     case crypto_pwhash_argon2id_ALG_ARGON2ID13:
1640ac341f1SConrad Meyer         if (argon2id_hash_raw((uint32_t) opslimit, (uint32_t) (memlimit / 1024U),
1650ac341f1SConrad Meyer                               (uint32_t) 1U, passwd, (size_t) passwdlen, salt,
1660ac341f1SConrad Meyer                               (size_t) crypto_pwhash_argon2id_SALTBYTES, out,
1670ac341f1SConrad Meyer                               (size_t) outlen) != ARGON2_OK) {
1680ac341f1SConrad Meyer             return -1; /* LCOV_EXCL_LINE */
1690ac341f1SConrad Meyer         }
1700ac341f1SConrad Meyer         return 0;
1710ac341f1SConrad Meyer     default:
1720ac341f1SConrad Meyer         errno = EINVAL;
1730ac341f1SConrad Meyer         return -1;
1740ac341f1SConrad Meyer     }
1750ac341f1SConrad Meyer }
1760ac341f1SConrad Meyer 
1770ac341f1SConrad Meyer int
crypto_pwhash_argon2id_str(char out[crypto_pwhash_argon2id_STRBYTES],const char * const passwd,unsigned long long passwdlen,unsigned long long opslimit,size_t memlimit)1780ac341f1SConrad Meyer crypto_pwhash_argon2id_str(char out[crypto_pwhash_argon2id_STRBYTES],
1790ac341f1SConrad Meyer                            const char *const passwd,
1800ac341f1SConrad Meyer                            unsigned long long passwdlen,
1810ac341f1SConrad Meyer                            unsigned long long opslimit, size_t memlimit)
1820ac341f1SConrad Meyer {
1830ac341f1SConrad Meyer     unsigned char salt[crypto_pwhash_argon2id_SALTBYTES];
1840ac341f1SConrad Meyer 
1850ac341f1SConrad Meyer     memset(out, 0, crypto_pwhash_argon2id_STRBYTES);
1860ac341f1SConrad Meyer     if (passwdlen > crypto_pwhash_argon2id_PASSWD_MAX ||
1870ac341f1SConrad Meyer         opslimit > crypto_pwhash_argon2id_OPSLIMIT_MAX ||
1880ac341f1SConrad Meyer         memlimit > crypto_pwhash_argon2id_MEMLIMIT_MAX) {
1890ac341f1SConrad Meyer         errno = EFBIG;
1900ac341f1SConrad Meyer         return -1;
1910ac341f1SConrad Meyer     }
1920ac341f1SConrad Meyer     if (passwdlen < crypto_pwhash_argon2id_PASSWD_MIN ||
1930ac341f1SConrad Meyer         opslimit < crypto_pwhash_argon2id_OPSLIMIT_MIN ||
1940ac341f1SConrad Meyer         memlimit < crypto_pwhash_argon2id_MEMLIMIT_MIN) {
1950ac341f1SConrad Meyer         errno = EINVAL;
1960ac341f1SConrad Meyer         return -1;
1970ac341f1SConrad Meyer     }
1980ac341f1SConrad Meyer     randombytes_buf(salt, sizeof salt);
1990ac341f1SConrad Meyer     if (argon2id_hash_encoded((uint32_t) opslimit, (uint32_t) (memlimit / 1024U),
2000ac341f1SConrad Meyer                               (uint32_t) 1U, passwd, (size_t) passwdlen, salt,
2010ac341f1SConrad Meyer                               sizeof salt, STR_HASHBYTES, out,
2020ac341f1SConrad Meyer                               crypto_pwhash_argon2id_STRBYTES) != ARGON2_OK) {
2030ac341f1SConrad Meyer         return -1; /* LCOV_EXCL_LINE */
2040ac341f1SConrad Meyer     }
2050ac341f1SConrad Meyer     return 0;
2060ac341f1SConrad Meyer }
2070ac341f1SConrad Meyer 
2080ac341f1SConrad Meyer int
crypto_pwhash_argon2id_str_verify(const char str[crypto_pwhash_argon2id_STRBYTES],const char * const passwd,unsigned long long passwdlen)2090ac341f1SConrad Meyer crypto_pwhash_argon2id_str_verify(const char str[crypto_pwhash_argon2id_STRBYTES],
2100ac341f1SConrad Meyer                                   const char *const  passwd,
2110ac341f1SConrad Meyer                                   unsigned long long passwdlen)
2120ac341f1SConrad Meyer {
2130ac341f1SConrad Meyer     int verify_ret;
2140ac341f1SConrad Meyer 
2150ac341f1SConrad Meyer     if (passwdlen > crypto_pwhash_argon2id_PASSWD_MAX) {
2160ac341f1SConrad Meyer         errno = EFBIG;
2170ac341f1SConrad Meyer         return -1;
2180ac341f1SConrad Meyer     }
2190ac341f1SConrad Meyer     /* LCOV_EXCL_START */
2200ac341f1SConrad Meyer     if (passwdlen < crypto_pwhash_argon2id_PASSWD_MIN) {
2210ac341f1SConrad Meyer         errno = EINVAL;
2220ac341f1SConrad Meyer         return -1;
2230ac341f1SConrad Meyer     }
2240ac341f1SConrad Meyer     /* LCOV_EXCL_STOP */
2250ac341f1SConrad Meyer 
2260ac341f1SConrad Meyer     verify_ret = argon2id_verify(str, passwd, (size_t) passwdlen);
2270ac341f1SConrad Meyer     if (verify_ret == ARGON2_OK) {
2280ac341f1SConrad Meyer         return 0;
2290ac341f1SConrad Meyer     }
2300ac341f1SConrad Meyer     if (verify_ret == ARGON2_VERIFY_MISMATCH) {
2310ac341f1SConrad Meyer         errno = EINVAL;
2320ac341f1SConrad Meyer     }
2330ac341f1SConrad Meyer     return -1;
2340ac341f1SConrad Meyer }
235