/* scrypt-jane by Andrew M, https://github.com/floodyberry/scrypt-jane Public Domain or MIT License, whichever is easier */ #include #include "scryptjane.h" #include "scryptjane/scrypt-jane-portable.h" #include "scryptjane/scrypt-jane-hash.h" #include "scryptjane/scrypt-jane-romix.h" #include "scryptjane/scrypt-jane-test-vectors.h" #define scrypt_maxN 30 /* (1 << (30 + 1)) = ~2 billion */ #if (SCRYPT_BLOCK_BYTES == 64) #define scrypt_r_32kb 8 /* (1 << 8) = 256 * 2 blocks in a chunk * 64 bytes = Max of 32kb in a chunk */ #elif (SCRYPT_BLOCK_BYTES == 128) #define scrypt_r_32kb 7 /* (1 << 7) = 128 * 2 blocks in a chunk * 128 bytes = Max of 32kb in a chunk */ #elif (SCRYPT_BLOCK_BYTES == 256) #define scrypt_r_32kb 6 /* (1 << 6) = 64 * 2 blocks in a chunk * 256 bytes = Max of 32kb in a chunk */ #elif (SCRYPT_BLOCK_BYTES == 512) #define scrypt_r_32kb 5 /* (1 << 5) = 32 * 2 blocks in a chunk * 512 bytes = Max of 32kb in a chunk */ #endif #define scrypt_maxr scrypt_r_32kb /* 32kb */ #define scrypt_maxp 25 /* (1 << 25) = ~33 million */ #include #include static void scrypt_fatal_error_default(const char *msg) { fprintf(stderr, "%s\n", msg); exit(1); } static scrypt_fatal_errorfn scrypt_fatal_error = scrypt_fatal_error_default; void scrypt_set_fatal_error_default(scrypt_fatal_errorfn fn) { scrypt_fatal_error = fn; } static int scrypt_power_on_self_test() { const scrypt_test_setting *t; uint8_t test_digest[64]; uint32_t i; int res = 7, scrypt_valid; if (!scrypt_test_mix()) { #if !defined(SCRYPT_TEST) scrypt_fatal_error("scrypt: mix function power-on-self-test failed"); #endif res &= ~1; } if (!scrypt_test_hash()) { #if !defined(SCRYPT_TEST) scrypt_fatal_error("scrypt: hash function power-on-self-test failed"); #endif res &= ~2; } for (i = 0, scrypt_valid = 1; post_settings[i].pw; i++) { t = post_settings + i; scrypt((uint8_t *)t->pw, strlen(t->pw), (uint8_t *)t->salt, strlen(t->salt), t->Nfactor, t->rfactor, t->pfactor, test_digest, sizeof(test_digest)); scrypt_valid &= scrypt_verify(post_vectors[i], test_digest, sizeof(test_digest)); } if (!scrypt_valid) { #if !defined(SCRYPT_TEST) scrypt_fatal_error("scrypt: scrypt power-on-self-test failed"); #endif res &= ~4; } return res; } typedef struct scrypt_aligned_alloc_t { uint8_t *mem, *ptr; } scrypt_aligned_alloc; #if defined(SCRYPT_TEST_SPEED) static uint8_t *mem_base = (uint8_t *)0; static size_t mem_bump = 0; /* allocations are assumed to be multiples of 64 bytes and total allocations not to exceed ~1.01gb */ static scrypt_aligned_alloc scrypt_alloc(uint64_t size) { scrypt_aligned_alloc aa; if (!mem_base) { mem_base = (uint8_t *)malloc((1024 * 1024 * 1024) + (1024 * 1024) + (SCRYPT_BLOCK_BYTES - 1)); if (!mem_base) scrypt_fatal_error("scrypt: out of memory"); mem_base = (uint8_t *)(((size_t)mem_base + (SCRYPT_BLOCK_BYTES - 1)) & ~(SCRYPT_BLOCK_BYTES - 1)); } aa.mem = mem_base + mem_bump; aa.ptr = aa.mem; mem_bump += (size_t)size; return aa; } static void scrypt_free(scrypt_aligned_alloc *aa) { mem_bump = 0; } #else static scrypt_aligned_alloc scrypt_alloc(uint64_t size) { static const size_t max_alloc = (size_t)-1; scrypt_aligned_alloc aa; size += (SCRYPT_BLOCK_BYTES - 1); if (size > max_alloc) scrypt_fatal_error("scrypt: not enough address space on this CPU to allocate required memory"); aa.mem = (uint8_t *)malloc((size_t)size); aa.ptr = (uint8_t *)(((size_t)aa.mem + (SCRYPT_BLOCK_BYTES - 1)) & ~(SCRYPT_BLOCK_BYTES - 1)); if (!aa.mem) scrypt_fatal_error("scrypt: out of memory"); return aa; } static void scrypt_free(scrypt_aligned_alloc *aa) { free(aa->mem); } #endif void scrypt(const uint8_t *password, size_t password_len, const uint8_t *salt, size_t salt_len, uint8_t Nfactor, uint8_t rfactor, uint8_t pfactor, uint8_t *out, size_t bytes) { scrypt_aligned_alloc YX, V; uint8_t *X, *Y; uint32_t N, r, p, chunk_bytes, i; #if !defined(SCRYPT_CHOOSE_COMPILETIME) scrypt_ROMixfn scrypt_ROMix = scrypt_getROMix(); #endif #if !defined(SCRYPT_TEST) static int power_on_self_test = 0; if (!power_on_self_test) { power_on_self_test = 1; if (!scrypt_power_on_self_test()) scrypt_fatal_error("scrypt: power on self test failed"); } #endif if (Nfactor > scrypt_maxN) scrypt_fatal_error("scrypt: N out of range"); if (rfactor > scrypt_maxr) scrypt_fatal_error("scrypt: r out of range"); if (pfactor > scrypt_maxp) scrypt_fatal_error("scrypt: p out of range"); N = (1 << (Nfactor + 1)); r = (1 << rfactor); p = (1 << pfactor); chunk_bytes = SCRYPT_BLOCK_BYTES * r * 2; V = scrypt_alloc((uint64_t)N * chunk_bytes); YX = scrypt_alloc((p + 1) * chunk_bytes); /* 1: X = PBKDF2(password, salt) */ Y = YX.ptr; X = Y + chunk_bytes; scrypt_pbkdf2(password, password_len, salt, salt_len, 1, X, chunk_bytes * p); /* 2: X = ROMix(X) */ for (i = 0; i < p; i++) scrypt_ROMix((scrypt_mix_word_t *)(X + (chunk_bytes * i)), (scrypt_mix_word_t *)Y, (scrypt_mix_word_t *)V.ptr, N, r); /* 3: Out = PBKDF2(password, X) */ scrypt_pbkdf2(password, password_len, X, chunk_bytes * p, 1, out, bytes); scrypt_ensure_zero(YX.ptr, (p + 1) * chunk_bytes); scrypt_free(&V); scrypt_free(&YX); } #define max(a,b) (((a) > (b)) ? (a) : (b)) #define min(a,b) (((a) < (b)) ? (a) : (b)) unsigned char GetNfactorJane(int nTimestamp, int nChainStartTime, int nMin, int nMax) { const unsigned char minNfactor = nMin;//4; const unsigned char maxNfactor = nMax;//30; int l = 0, s, n; unsigned char N; if (nTimestamp <= nChainStartTime) return 4; s = nTimestamp - nChainStartTime; while ((s >> 1) > 3) { l += 1; s >>= 1; } s &= 3; n = (l * 170 + s * 25 - 2320) / 100; if (n < 0) n = 0; if (n > 255) printf("GetNfactor(%d) - something wrong(n == %d)\n", nTimestamp, n); N = (unsigned char)n; //printf("GetNfactor: %d -> %d %d : %d / %d\n", nTimestamp - nChainStartTime, l, s, n, min(max(N, minNfactor), maxNfactor)); return min(max(N, minNfactor), maxNfactor); } void scryptjane_hash(const void* input, size_t inputlen, uint32_t *res, unsigned char Nfactor) { return scrypt((const unsigned char*)input, inputlen, (const unsigned char*)input, inputlen, Nfactor, 0, 0, (unsigned char*)res, 32); }