| 466 | // * last line of defense against "evil little brothers" |
| 467 | |
| 468 | void passphrase2key(const char *pass, const uchar *salt, int saltlen, uchar *key, int keylen, int *iterations, int maxtime, int memusage) |
| 469 | { |
| 470 | memset(key, 0, keylen); |
| 471 | if(!*pass) return; // password "" -> |
| 472 | memusage = clamp(memusage, 2, 1024); // keep memory usage between 2MB and 1GB |
| 473 | int memsize = (1<<20) * memusage, passlen = strlen(pass), tmpbuflen = 2 * SHA512SIZE, pplen = 2 * (saltlen + passlen); |
| 474 | |
| 475 | // prepare the passphrase (including salt) |
| 476 | uchar *pp = new uchar[pplen]; |
| 477 | memcpy(pp, salt, saltlen); |
| 478 | memcpy(pp + saltlen, pass, passlen); |
| 479 | memcpy(pp + saltlen + passlen, pass, passlen); |
| 480 | memcpy(pp + saltlen + 2 * passlen, salt, saltlen); |
| 481 | if((memusage & 1) && passlen + saltlen >= 8) identhash((uint64_t *)(pp + saltlen + passlen)); |
| 482 | |
| 483 | // mix up the passphrase a bit |
| 484 | uchar *tmpbuf = new uchar[tmpbuflen + sizeof(uint)]; |
| 485 | memset(tmpbuf, 0, tmpbuflen + sizeof(uint)); |
| 486 | sha512(tmpbuf, pp, pplen); |
| 487 | xor_block(pp, tmpbuf, min(pplen, tmpbuflen)); |
| 488 | sha512(tmpbuf + SHA512SIZE, pp, pplen); |
| 489 | tiger::hash(pp, pplen, *((tiger::hashval *)tmpbuf)); |
| 490 | |
| 491 | // initialise the huge buffer |
| 492 | uchar *hugebuf = new uchar[memsize]; |
| 493 | memset(hugebuf, 0, memsize); |
| 494 | int memchunk = memsize / tmpbuflen; |
| 495 | loopi(tmpbuflen) seedMT_do(*((uint*)(tmpbuf + i)), (uint*)(hugebuf + memchunk * i), memchunk / sizeof(uint)); // spread the passphrase all over the huge buffer |
| 496 | |
| 497 | // start mixing |
| 498 | #define mixit(x, y) (((((uint*)tmpbuf)[(roundsdone ^ (x)) % (tmpbuflen / sizeof(uint))]) % ((y) / 8 - (x) % 11)) * 8) |
| 499 | stopwatch watch; |
| 500 | watch.start(); |
| 501 | int roundsdone = 0; |
| 502 | uint shortseed = 0; |
| 503 | do |
| 504 | { |
| 505 | loopirev(memsize / 127) shortseed = ((uint*)hugebuf)[shortseed % (memsize / sizeof(uint))]; |
| 506 | seedMT_do(shortseed, (uint*)tmpbuf, tmpbuflen / sizeof(uint)); |
| 507 | loopi(2999) sha512_compress((uint64_t*)(hugebuf + mixit(i * 5, memsize - SHA512SIZE)), hugebuf + mixit(i * 17, memsize - 128)); |
| 508 | roundsdone++; |
| 509 | } |
| 510 | while((!*iterations && watch.elapsed() < maxtime) || (*iterations && *iterations > roundsdone)); // *iterations == 0: time-limited, otherwise rounds-limited |
| 511 | |
| 512 | // extract the key |
| 513 | if(keylen * 8 > 192) sha512(tmpbuf, hugebuf, memsize); |
| 514 | else tiger::hash(hugebuf, memsize, *((tiger::hashval *)tmpbuf)); |
| 515 | loopi(SHA512SIZE) sha512_compress(((uint64_t*)tmpbuf) + (i / 8), hugebuf + (((tmpbuf[i] * 68111) % (memsize - 128)) & ~7)); |
| 516 | memcpy(key, tmpbuf, min(keylen, tmpbuflen)); // max keylen is 2 * SHA512SIZE |
| 517 | DEBUG("passphrase2key: " << watch.elapsed() << " ms, " << roundsdone << " rounds, " << memsize << " bytes used"); |
| 518 | *iterations = roundsdone; |
| 519 | delete[] hugebuf; |
| 520 | delete[] tmpbuf; |
| 521 | delete[] pp; |
| 522 | #undef mixit |
| 523 | } |
| 524 | #endif |
| 525 | |