Skip to content

Commit

Permalink
Add password hashing
Browse files Browse the repository at this point in the history
  • Loading branch information
jedisct1 committed Dec 27, 2017
1 parent d266f9e commit 8b3ba35
Show file tree
Hide file tree
Showing 5 changed files with 319 additions and 17 deletions.
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -15,6 +15,7 @@ SRC = \
impl/hydrogen_p.h \
impl/kdf.h \
impl/kx.h \
impl/pwhash.h \
impl/random.h \
impl/secretbox.h \
impl/sign.h \
Expand Down
1 change: 1 addition & 0 deletions hydrogen.c
Expand Up @@ -14,4 +14,5 @@
#include "impl/x25519.h"

#include "impl/kx.h"
#include "impl/pwhash.h"
#include "impl/sign.h"
50 changes: 41 additions & 9 deletions hydrogen.h
Expand Up @@ -87,18 +87,17 @@ int hydro_secretbox_decrypt(void *m_, const uint8_t *c, size_t clen,
const uint8_t key[hydro_secretbox_KEYBYTES])
__attribute__((warn_unused_result));

void
hydro_secretbox_probe_create(uint8_t probe[hydro_secretbox_PROBEBYTES],
const uint8_t *c, size_t c_len,
const char ctx[hydro_secretbox_CONTEXTBYTES],
const uint8_t key[hydro_secretbox_KEYBYTES]);
void hydro_secretbox_probe_create(uint8_t probe[hydro_secretbox_PROBEBYTES],
const uint8_t *c, size_t c_len,
const char ctx[hydro_secretbox_CONTEXTBYTES],
const uint8_t key[hydro_secretbox_KEYBYTES]);

int
hydro_secretbox_probe_verify(const uint8_t probe[hydro_secretbox_PROBEBYTES],
hydro_secretbox_probe_verify(const uint8_t probe[hydro_secretbox_PROBEBYTES],
const uint8_t *c, size_t c_len,
const char ctx[hydro_secretbox_CONTEXTBYTES],
const uint8_t key[hydro_secretbox_KEYBYTES])
__attribute__((warn_unused_result));
__attribute__((warn_unused_result));

/* ---------------- */

Expand Down Expand Up @@ -217,6 +216,39 @@ int hydro_kx_xx_4(hydro_kx_state *state, hydro_kx_session_keypair *kp,

/* ---------------- */

#define hydro_pwhash_CONTEXTBYTES 8
#define hydro_pwhash_KEYBYTES 32
#define hydro_pwhash_STOREDBYTES 128

void hydro_pwhash_keygen(uint8_t key[hydro_pwhash_KEYBYTES]);

int hydro_pwhash_deterministic(uint8_t *h, size_t h_len, const char *passwd,
size_t passwd_len,
const char ctx[hydro_pwhash_CONTEXTBYTES],
const uint8_t key[hydro_pwhash_KEYBYTES],
uint64_t opslimit, size_t memlimit,
uint8_t threads);

int hydro_pwhash_create(uint8_t stored[hydro_pwhash_STOREDBYTES],
const char *passwd, size_t passwd_len,
const uint8_t key[hydro_pwhash_KEYBYTES],
uint64_t opslimit, size_t memlimit, uint8_t threads);

int hydro_pwhash_verify(const uint8_t stored[hydro_pwhash_STOREDBYTES],
const char *passwd, size_t passwd_len,
const uint8_t key[hydro_pwhash_KEYBYTES],
uint64_t opslimit_max, size_t memlimit_max,
uint8_t threads);

int hydro_pwhash_derive_static_key(
uint8_t *static_key, size_t static_key_len,
const uint8_t stored[hydro_pwhash_STOREDBYTES], const char *passwd,
size_t passwd_len, const char ctx[hydro_pwhash_CONTEXTBYTES],
const uint8_t key[hydro_pwhash_KEYBYTES], uint64_t opslimit_max,
size_t memlimit_max, uint8_t threads_max);

/* ---------------- */

void hydro_memzero(void *pnt, size_t len);

void hydro_increment(uint8_t *n, size_t len);
Expand All @@ -233,10 +265,10 @@ int hydro_hex2bin(uint8_t *bin, size_t bin_maxlen, const char *hex,
const char **hex_end);

int hydro_pad(size_t *padded_buflen_p, unsigned char *buf,
size_t unpadded_buflen, size_t blocksize, size_t max_buflen);
size_t unpadded_buflen, size_t blocksize, size_t max_buflen);

int hydro_unpad(size_t *unpadded_buflen_p, const unsigned char *buf,
size_t padded_buflen, size_t blocksize);
size_t padded_buflen, size_t blocksize);

/* ---------------- */

Expand Down
221 changes: 221 additions & 0 deletions impl/pwhash.h
@@ -0,0 +1,221 @@
#define hydro_pwhash_ENC_ALGBYTES 1
#define hydro_pwhash_HASH_ALGBYTES 1
#define hydro_pwhash_THREADSBYTES 1
#define hydro_pwhash_OPSLIMITBYTES 8
#define hydro_pwhash_MEMLIMITBYTES 8
#define hydro_pwhash_HASHBYTES 32
#define hydro_pwhash_SALTBYTES 16
#define hydro_pwhash_PARAMSBYTES \
(hydro_pwhash_HASH_ALGBYTES + hydro_pwhash_THREADSBYTES + \
hydro_pwhash_OPSLIMITBYTES + hydro_pwhash_MEMLIMITBYTES + \
hydro_pwhash_SALTBYTES + hydro_pwhash_HASHBYTES)
#define hydro_pwhash_ENC_ALG 0x01
#define hydro_pwhash_HASH_ALG 0x01
#define hydro_pwhash_CONTEXT "hydro_pw"

static int
_hydro_pwhash_hash(uint8_t out[randombytes_SEEDBYTES], size_t h_len,
const uint8_t salt[hydro_pwhash_SALTBYTES],
const char *passwd, size_t passwd_len,
const char ctx[hydro_pwhash_CONTEXTBYTES],
const uint8_t key[hydro_pwhash_KEYBYTES], uint64_t opslimit,
size_t memlimit, uint8_t threads)
{
hydro_hash_state h_st;
uint8_t state[gimli_BLOCKBYTES];
uint8_t tmp64_u8[8];
uint64_t i;
uint8_t tmp8;

hydro_hash_init(&h_st, ctx, key, hydro_pwhash_KEYBYTES);

STORE64_LE(tmp64_u8, (uint64_t) passwd_len);
hydro_hash_update(&h_st, tmp64_u8, sizeof tmp64_u8);
hydro_hash_update(&h_st, passwd, passwd_len);

hydro_hash_update(&h_st, salt, hydro_pwhash_SALTBYTES);

tmp8 = hydro_pwhash_HASH_ALG;
hydro_hash_update(&h_st, &tmp8, 1);

hydro_hash_update(&h_st, &threads, 1);

STORE64_LE(tmp64_u8, (uint64_t) opslimit);
hydro_hash_update(&h_st, tmp64_u8, sizeof tmp64_u8);

STORE64_LE(tmp64_u8, (uint64_t) memlimit);
hydro_hash_update(&h_st, tmp64_u8, sizeof tmp64_u8);

STORE64_LE(tmp64_u8, (uint64_t) h_len);
hydro_hash_update(&h_st, tmp64_u8, sizeof tmp64_u8);

hydro_hash_final(&h_st, (uint8_t *) (void *) &state, sizeof state);

gimli_core_u8(state, 0);
for (i = 0; i < opslimit; i++) {
mem_zero(state, gimli_RATE);
gimli_core_u8(state, 1);
}
gimli_core_u8(state, 2);

COMPILER_ASSERT(randombytes_SEEDBYTES <= gimli_BLOCKBYTES);
mem_cpy(out, state, randombytes_SEEDBYTES);
mem_zero(state, sizeof state);

return 0;
}

void
hydro_pwhash_keygen(uint8_t key[hydro_pwhash_KEYBYTES])
{
randombytes_buf(key, hydro_pwhash_KEYBYTES);
}

int
hydro_pwhash_deterministic(uint8_t *h, size_t h_len, const char *passwd,
size_t passwd_len,
const char ctx[hydro_pwhash_CONTEXTBYTES],
const uint8_t key[hydro_pwhash_KEYBYTES],
uint64_t opslimit, size_t memlimit, uint8_t threads)
{
uint8_t seed[randombytes_SEEDBYTES];

COMPILER_ASSERT(sizeof zero >= hydro_pwhash_SALTBYTES);
COMPILER_ASSERT(sizeof zero >= hydro_pwhash_KEYBYTES);

(void) memlimit;
if (_hydro_pwhash_hash(seed, h_len, zero, passwd, passwd_len, ctx, key,
opslimit, memlimit, threads) != 0) {
return -1;
}
randombytes_buf_deterministic(h, h_len, seed);
mem_zero(seed, sizeof seed);

return 0;
}

int
hydro_pwhash_create(uint8_t stored[hydro_pwhash_STOREDBYTES],
const char *passwd, size_t passwd_len,
const uint8_t key[hydro_pwhash_KEYBYTES], uint64_t opslimit,
size_t memlimit, uint8_t threads)
{
uint8_t *const enc_alg = &stored[0];
uint8_t *const secretbox = &enc_alg[hydro_pwhash_ENC_ALGBYTES];
uint8_t *const hash_alg = &secretbox[hydro_secretbox_HEADERBYTES];
uint8_t *const threads_u8 = &hash_alg[hydro_pwhash_HASH_ALGBYTES];
uint8_t *const opslimit_u8 = &threads_u8[hydro_pwhash_THREADSBYTES];
uint8_t *const memlimit_u8 = &opslimit_u8[hydro_pwhash_OPSLIMITBYTES];
uint8_t *const salt = &memlimit_u8[hydro_pwhash_MEMLIMITBYTES];
uint8_t *const h = &salt[hydro_pwhash_SALTBYTES];

COMPILER_ASSERT(hydro_pwhash_STOREDBYTES >=
hydro_pwhash_ENC_ALGBYTES + hydro_secretbox_HEADERBYTES +
hydro_pwhash_PARAMSBYTES);
(void) memlimit;
mem_zero(stored, hydro_pwhash_STOREDBYTES);
*enc_alg = hydro_pwhash_ENC_ALG;
*hash_alg = hydro_pwhash_HASH_ALG;
*threads_u8 = threads;
STORE64_LE(opslimit_u8, opslimit);
STORE64_LE(memlimit_u8, (uint64_t) memlimit);
randombytes_buf(salt, hydro_pwhash_SALTBYTES);

if (_hydro_pwhash_hash(h, hydro_pwhash_HASHBYTES, salt, passwd, passwd_len,
hydro_pwhash_CONTEXT, key, opslimit, memlimit,
threads) != 0) {
return -1;
}
COMPILER_ASSERT(hydro_pwhash_KEYBYTES == hydro_secretbox_KEYBYTES);

return hydro_secretbox_encrypt(
secretbox, hash_alg, hydro_pwhash_PARAMSBYTES, (uint64_t) *enc_alg,
hydro_pwhash_CONTEXT, key);
}

static int
_hydro_pwhash_verify(uint8_t computed_h[hydro_pwhash_HASHBYTES],
const uint8_t stored[hydro_pwhash_STOREDBYTES],
const char *passwd, size_t passwd_len,
const uint8_t key[hydro_pwhash_KEYBYTES],
uint64_t opslimit_max, size_t memlimit_max,
uint8_t threads_max)
{
const uint8_t *const enc_alg = &stored[0];
const uint8_t *const secretbox = &enc_alg[hydro_pwhash_ENC_ALGBYTES];
uint8_t params[hydro_pwhash_PARAMSBYTES];
uint8_t *const hash_alg = &params[0];
uint8_t *const threads_u8 = &hash_alg[hydro_pwhash_HASH_ALGBYTES];
uint8_t *const opslimit_u8 = &threads_u8[hydro_pwhash_THREADSBYTES];
uint8_t *const memlimit_u8 = &opslimit_u8[hydro_pwhash_OPSLIMITBYTES];
uint8_t *const salt = &memlimit_u8[hydro_pwhash_MEMLIMITBYTES];
uint8_t *const h = &salt[hydro_pwhash_SALTBYTES];
uint64_t opslimit;
size_t memlimit;
uint8_t threads;

(void) memlimit;
if (*enc_alg != hydro_pwhash_ENC_ALG) {
return -1;
}
if (hydro_secretbox_decrypt(
params, secretbox,
hydro_secretbox_HEADERBYTES + hydro_pwhash_PARAMSBYTES,
(uint64_t) *enc_alg, hydro_pwhash_CONTEXT, key) != 0) {
return -1;
}
if (*hash_alg != hydro_pwhash_HASH_ALG ||
(opslimit = LOAD64_LE(opslimit_u8)) > opslimit_max ||
(memlimit = (size_t) LOAD64_LE(memlimit_u8)) > memlimit_max ||
(threads = *threads_u8) > threads_max) {
return -1;
}
if (_hydro_pwhash_hash(computed_h, hydro_pwhash_HASHBYTES, salt, passwd,
passwd_len, hydro_pwhash_CONTEXT, key, opslimit,
memlimit, threads) == 0 &&
hydro_equal(computed_h, h, hydro_pwhash_HASHBYTES) == 1) {
return 0;
}
return -1;
}

int
hydro_pwhash_verify(const uint8_t stored[hydro_pwhash_STOREDBYTES],
const char *passwd, size_t passwd_len,
const uint8_t key[hydro_pwhash_KEYBYTES],
uint64_t opslimit_max, size_t memlimit_max,
uint8_t threads_max)
{
uint8_t computed_h[hydro_pwhash_HASHBYTES];
int ret;

ret = _hydro_pwhash_verify(computed_h, stored, passwd, passwd_len, key,
opslimit_max, memlimit_max, threads_max);
hydro_memzero(computed_h, sizeof computed_h);

return ret;
}

int
hydro_pwhash_derive_static_key(uint8_t *static_key, size_t static_key_len,
const uint8_t stored[hydro_pwhash_STOREDBYTES],
const char *passwd, size_t passwd_len,
const char ctx[hydro_pwhash_CONTEXTBYTES],
const uint8_t key[hydro_pwhash_KEYBYTES],
uint64_t opslimit_max, size_t memlimit_max,
uint8_t threads_max)
{
uint8_t computed_h[hydro_pwhash_HASHBYTES];

if (_hydro_pwhash_verify(computed_h, stored, passwd, passwd_len, key,
opslimit_max, memlimit_max, threads_max) != 0) {
hydro_memzero(computed_h, sizeof computed_h);
return -1;
}
COMPILER_ASSERT(hydro_kdf_CONTEXTBYTES <= hydro_pwhash_CONTEXTBYTES);
COMPILER_ASSERT(hydro_kdf_KEYBYTES <= hydro_pwhash_HASHBYTES);
hydro_kdf_derive_from_key(static_key, static_key_len, 0, ctx, computed_h);
hydro_memzero(computed_h, sizeof computed_h);

return 0;
}

0 comments on commit 8b3ba35

Please sign in to comment.