#include #include #include #include "util.h" #include "sha2.h" #include "scrypt.h" /** * Name RFC Description * pass P Passphrase, an octet string. * salt S Salt, an octet string. * cost N CPU/Memory cost parameter * bs r Block size parameter. * par p Parallelization parameter * len? dkLen Intended output length * in B Input data * out B' Output data */ /* Types */ typedef void hash_t(uint8_t *out, const uint8_t *in, int len); /* Helpers */ #if 0 static int mod(uint8_t out[64], uint8_t in[64]) { } static void copy(uint8_t out[64], uint8_t in[64]) { } static void xor(uint8_t out[64], uint8_t a[64], uint8_t b[64]) { } #endif /* HMAC */ static void hmac_gen(hash_t hash, uint8_t *out, int nout, const uint8_t *key, int nkey, const uint8_t *msg, int nmsg) { uint8_t *fix = alloc0(nout); uint8_t *ipad = alloc0(nout+nmsg); uint8_t *opad = alloc0(nout+nout); /* Fixup key */ if (nkey > nout) hash(fix, key, nkey); else memcpy(fix, key, nkey); /* Create pad strings */ for (int i = 0; i < nout; i++) { opad[i] = 0x5c ^ fix[i]; ipad[i] = 0x36 ^ fix[i]; } /* Run hashes - hash(o+hash(i+msg)) */ memcpy(ipad+nout, msg, nmsg); hash(opad+nout, ipad, nout+nmsg); hash(out, opad, nout+nout); /* Cleanup */ free(fix); free(opad); free(ipad); } /* PBKDF2 */ static void pbkdf2_gen(uint8_t *out, int nout, const uint8_t *pass, int npass, const uint8_t *salt, int nsalt, int iter) { int nbuf = nsalt + 4; uint8_t *buf = alloc0(nbuf); memcpy(buf, salt, nsalt); const int nptr = 256/8; for (int i = 0; i < nout/nptr; i++) { uint8_t *ptr = &out[i*nptr]; buf[nsalt+0] = ((i+1) & 0xFF000000) >> 030; buf[nsalt+1] = ((i+1) & 0x00FF0000) >> 020; buf[nsalt+2] = ((i+1) & 0x0000FF00) >> 010; buf[nsalt+3] = ((i+1) & 0x000000FF) >> 000; hmac_gen(sha256_hash, ptr, nptr, pass, npass, buf, nbuf); for (int j = 1; j < iter; j++) hmac_gen(sha256_hash, ptr, nptr, pass, npass, ptr, nptr); } free(buf); } static void pbkdf2_gen_str(uint8_t *out, int nout, const char *pass, const char *salt, int iter) { pbkdf2_gen(out, nout, (const uint8_t *)pass, strlen(pass), (const uint8_t *)salt, strlen(salt), iter); } /* Salsa20/8 */ static void salsa(uint8_t out[64], uint8_t in[64]) { } /* scrypt */ #if 0 static void block_mix(uint8_t *out[64], uint8_t *in[64], int bs) { // xor each block with the last block // alternat first/second half for result uint8_t tmp[64] for (int i = 0; i < 2*r; i++) { int o = bs*(i%2) + (i/2); xor(tmp, in[2*r - 1], in[i]); salsa(out[o], tmp); } } static void ro_mix(uint8_t *out[128], uint8_t *in[128], int cost, int bs) { // generate vector of size cost // randomly collapse vector as output uint8_t *state[64]; uint8_t *mixed[64]; uint8_t *tmp[64]; copy(state, in); for (i = 0; i < cost; i++) { copy(mixed[i], state); block_mix(state, state); } for (i = 0; i < cost; i++) { int j = mod(state, cost); xor(tmp, state, mixed[j]); block_mix(state, tmp); } copy(out, state); } static void scrypt_run(uint8_t out[64], char *pass, char *salt, int cost, int bs, int par, int len) { // hash pass/salt into large buffer // mix each buffer (in parallel) // combine bubers into output sha256_hmac(buf, pass, salt, 1, par * 128 * bs); for (i = 0; i < par; i++) buf[i] = ro_mix(buf[i], cost, bs); sha256_hmac(out, pass, buf, 1, len); } #endif /* Entry point */ void scrypt_hash(uint8_t *in, uint8_t *sum) { *sum = 0; } /* Tests */ #if 0 static void test_script(void) { /* Parameters */ const int cost = 1024; const int bs = 1; const int par = 1; const int len = 32; /* Input data */ const char *pass = "hello"; const char *salt = "world"; /* Output data */ static uint8_t out[32]; /* Run the hash */ scrypt_hash(out, pass, salt, par, bs, len); /* Print output */ } #endif static void test_keygen(void) { const uint8_t truth0[] = { 0x55, 0xac, 0x04, 0x6e, 0x56, 0xe3, 0x08, 0x9f, 0xec, 0x16, 0x91, 0xc2, 0x25, 0x44, 0xb6, 0x05, 0xf9, 0x41, 0x85, 0x21, 0x6d, 0xde, 0x04, 0x65, 0xe6, 0x8b, 0x9d, 0x57, 0xc2, 0x0d, 0xac, 0xbc, 0x49, 0xca, 0x9c, 0xcc, 0xf1, 0x79, 0xb6, 0x45, 0x99, 0x16, 0x64, 0xb3, 0x9d, 0x77, 0xef, 0x31, 0x7c, 0x71, 0xb8, 0x45, 0xb1, 0xe3, 0x0b, 0xd5, 0x09, 0x11, 0x20, 0x41, 0xd3, 0xa1, 0x97, 0x83, }; const uint8_t truth1[] = { 0x4d, 0xdc, 0xd8, 0xf6, 0x0b, 0x98, 0xbe, 0x21, 0x83, 0x0c, 0xee, 0x5e, 0xf2, 0x27, 0x01, 0xf9, 0x64, 0x1a, 0x44, 0x18, 0xd0, 0x4c, 0x04, 0x14, 0xae, 0xff, 0x08, 0x87, 0x6b, 0x34, 0xab, 0x56, 0xa1, 0xd4, 0x25, 0xa1, 0x22, 0x58, 0x33, 0x54, 0x9a, 0xdb, 0x84, 0x1b, 0x51, 0xc9, 0xb3, 0x17, 0x6a, 0x27, 0x2b, 0xde, 0xbb, 0xa1, 0xd0, 0x78, 0x47, 0x8f, 0x62, 0xb3, 0x97, 0xf3, 0x3c, 0x8d, }; uint8_t out0[64] = {}; uint8_t out1[64] = {}; // output password salt iters pbkdf2_gen_str(out0, 64, "passwd", "salt", 1); //pbkdf2_gen_str(out1, 64, "Password", "NaCl", 80000); hexdump("\nTest #1", NULL, truth0, 64); hexdump("", NULL, out0, 64); hexdump("\nTest #2", NULL, truth1, 64); hexdump("", NULL, out1, 64); (void)salsa; (void)pbkdf2_gen; (void)hmac_gen; } void scrypt_test(void) { test_keygen(); }