112 lines
3.1 KiB
C
112 lines
3.1 KiB
C
typedef struct scrypt_hmac_state_t {
|
|
scrypt_hash_state inner, outer;
|
|
} scrypt_hmac_state;
|
|
|
|
|
|
static void
|
|
scrypt_hash(scrypt_hash_digest hash, const uint8_t *m, size_t mlen) {
|
|
scrypt_hash_state st;
|
|
scrypt_hash_init(&st);
|
|
scrypt_hash_update(&st, m, mlen);
|
|
scrypt_hash_finish(&st, hash);
|
|
}
|
|
|
|
/* hmac */
|
|
static void
|
|
scrypt_hmac_init(scrypt_hmac_state *st, const uint8_t *key, size_t keylen) {
|
|
uint8_t pad[SCRYPT_HASH_BLOCK_SIZE] = {0};
|
|
size_t i;
|
|
|
|
scrypt_hash_init(&st->inner);
|
|
scrypt_hash_init(&st->outer);
|
|
|
|
if (keylen <= SCRYPT_HASH_BLOCK_SIZE) {
|
|
/* use the key directly if it's <= blocksize bytes */
|
|
memcpy(pad, key, keylen);
|
|
} else {
|
|
/* if it's > blocksize bytes, hash it */
|
|
scrypt_hash(pad, key, keylen);
|
|
}
|
|
|
|
/* inner = (key ^ 0x36) */
|
|
/* h(inner || ...) */
|
|
for (i = 0; i < SCRYPT_HASH_BLOCK_SIZE; i++)
|
|
pad[i] ^= 0x36;
|
|
scrypt_hash_update(&st->inner, pad, SCRYPT_HASH_BLOCK_SIZE);
|
|
|
|
/* outer = (key ^ 0x5c) */
|
|
/* h(outer || ...) */
|
|
for (i = 0; i < SCRYPT_HASH_BLOCK_SIZE; i++)
|
|
pad[i] ^= (0x5c ^ 0x36);
|
|
scrypt_hash_update(&st->outer, pad, SCRYPT_HASH_BLOCK_SIZE);
|
|
|
|
scrypt_ensure_zero(pad, sizeof(pad));
|
|
}
|
|
|
|
static void
|
|
scrypt_hmac_update(scrypt_hmac_state *st, const uint8_t *m, size_t mlen) {
|
|
/* h(inner || m...) */
|
|
scrypt_hash_update(&st->inner, m, mlen);
|
|
}
|
|
|
|
static void
|
|
scrypt_hmac_finish(scrypt_hmac_state *st, scrypt_hash_digest mac) {
|
|
/* h(inner || m) */
|
|
scrypt_hash_digest innerhash;
|
|
scrypt_hash_finish(&st->inner, innerhash);
|
|
|
|
/* h(outer || h(inner || m)) */
|
|
scrypt_hash_update(&st->outer, innerhash, sizeof(innerhash));
|
|
scrypt_hash_finish(&st->outer, mac);
|
|
|
|
scrypt_ensure_zero(st, sizeof(*st));
|
|
}
|
|
|
|
static void
|
|
scrypt_pbkdf2(const uint8_t *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint64_t N, uint8_t *out, size_t bytes) {
|
|
scrypt_hmac_state hmac_pw, hmac_pw_salt, work;
|
|
scrypt_hash_digest ti, u;
|
|
uint8_t be[4];
|
|
uint32_t i, j, blocks;
|
|
uint64_t c;
|
|
|
|
/* bytes must be <= (0xffffffff - (SCRYPT_HASH_DIGEST_SIZE - 1)), which they will always be under scrypt */
|
|
|
|
/* hmac(password, ...) */
|
|
scrypt_hmac_init(&hmac_pw, password, password_len);
|
|
|
|
/* hmac(password, salt...) */
|
|
hmac_pw_salt = hmac_pw;
|
|
scrypt_hmac_update(&hmac_pw_salt, salt, salt_len);
|
|
|
|
blocks = ((uint32_t)bytes + (SCRYPT_HASH_DIGEST_SIZE - 1)) / SCRYPT_HASH_DIGEST_SIZE;
|
|
for (i = 1; i <= blocks; i++) {
|
|
/* U1 = hmac(password, salt || be(i)) */
|
|
U32TO8_BE(be, i);
|
|
work = hmac_pw_salt;
|
|
scrypt_hmac_update(&work, be, 4);
|
|
scrypt_hmac_finish(&work, ti);
|
|
memcpy(u, ti, sizeof(u));
|
|
|
|
/* T[i] = U1 ^ U2 ^ U3... */
|
|
for (c = 0; c < N - 1; c++) {
|
|
/* UX = hmac(password, U{X-1}) */
|
|
work = hmac_pw;
|
|
scrypt_hmac_update(&work, u, SCRYPT_HASH_DIGEST_SIZE);
|
|
scrypt_hmac_finish(&work, u);
|
|
|
|
/* T[i] ^= UX */
|
|
for (j = 0; j < sizeof(u); j++)
|
|
ti[j] ^= u[j];
|
|
}
|
|
|
|
memcpy(out, ti, (bytes > SCRYPT_HASH_DIGEST_SIZE) ? SCRYPT_HASH_DIGEST_SIZE : bytes);
|
|
out += SCRYPT_HASH_DIGEST_SIZE;
|
|
bytes -= SCRYPT_HASH_DIGEST_SIZE;
|
|
}
|
|
|
|
scrypt_ensure_zero(ti, sizeof(ti));
|
|
scrypt_ensure_zero(u, sizeof(u));
|
|
scrypt_ensure_zero(&hmac_pw, sizeof(hmac_pw));
|
|
scrypt_ensure_zero(&hmac_pw_salt, sizeof(hmac_pw_salt));
|
|
}
|