// The full password hashing interface. bool TwoCats_HashPasswordFull(TwoCats_HashType hashType, uint8_t *hash, uint8_t *password, uint32_t passwordSize, const uint8_t *salt, uint32_t saltSize, uint8_t memCost, uint8_t timeCost, uint8_t parallelism, bool clearPassword) { uint8_t multiplies = 3; // Decent match for Intel Sandy Bridge through Haswell if(memCost <= 4) { multiplies = 1; // Assume it fits in L1 cache } else if(memCost < 10) { multiplies = 2; // Assume it fits in L2 or L3 cache } uint32_t blockSize = TWOCATS_BLOCKSIZE; uint32_t subBlockSize = TWOCATS_SUBBLOCKSIZE; uint64_t memSize = (uint64_t)1024 << memCost; while(blockSize >= 64 && memSize/(parallelism*blockSize) < TWOCATS_MINBLOCKS) { blockSize >>= 1; } if(subBlockSize > blockSize) { subBlockSize = blockSize; } while(parallelism > 1 && memSize/(parallelism*blockSize) < TWOCATS_MINBLOCKS) { parallelism--; } return TwoCats_HashPasswordExtended(hashType, hash, password, passwordSize, salt, saltSize, NULL, 0, memCost, memCost, timeCost, multiplies, TWOCATS_LANES, parallelism, TWOCATS_BLOCKSIZE, TWOCATS_SUBBLOCKSIZE, TWOCATS_OVERWRITECOST, clearPassword, false); }
// The SkinnyCat API. bool SkinnyCat_HashPassword(TwoCats_HashType hashType, uint8_t *hash, uint8_t *password, uint8_t passwordSize, const uint8_t *salt, uint8_t saltSize, uint8_t memCost, bool clearPassword) { uint32_t blockSize = TWOCATS_BLOCKSIZE; while(blockSize > 32 && ((uint64_t)1024 << memCost)/blockSize < TWOCATS_MINBLOCKS) { blockSize >>= 1; } printf("blockSize:%u\n", blockSize); return TwoCats_HashPasswordExtended(hashType, hash, password, passwordSize, salt, saltSize, NULL, 0, memCost, memCost, 0, 0, TWOCATS_LANES, 1, blockSize, blockSize, 0, clearPassword, false); }
// Just measure the time for a given memCost and timeCost. Return -1 if memory allocation fails. static clock_t findRuntime(TwoCats_HashType hashType, uint8_t memCost, uint8_t timeCost, uint8_t multiplies, uint8_t lanes) { uint32_t keySize = TwoCats_GetHashTypeSize(hashType); uint8_t buf[keySize]; clock_t start = clock(); if(!TwoCats_HashPasswordExtended(hashType, buf, NULL, 0, NULL, 0, NULL, 0, memCost, memCost, timeCost, multiplies, lanes, TWOCATS_PARALLELISM, TWOCATS_BLOCKSIZE, TWOCATS_SUBBLOCKSIZE, 0, false, false)) { fprintf(stderr, "Memory hashing failed\n"); return -1; } clock_t end = clock(); return (end - start) * 1000 / CLOCKS_PER_SEC; }
int main(int argc, char **argv) { if(argc != 3) { usage("Invalid number of arguments"); } uint32_t passwordSize = strlen(argv[1]); char *password = malloc(passwordSize); memcpy(password, argv[1], passwordSize); char *inFileName = argv[2]; uint8_t salt[SALT_SIZE]; uint8_t key[KEY_SIZE]; if(strlen(inFileName) < 5 || strcmp(inFileName + strlen(inFileName) - 4, ".enc")) { fprintf(stderr, "Input file must end in .enc\n"); return 1; } FILE *inFile = fopen(inFileName, "r"); if(inFile == NULL) { fprintf(stderr, "Unable to open file %s\n", inFileName); return 1; } char outFileName[strlen(inFileName)]; strcpy(outFileName, inFileName); outFileName[strlen(inFileName) - 4] = '\0'; FILE *outFile = fopen(outFileName, "w"); if(outFile == NULL) { fprintf(stderr, "Unable to open file %s for writing\n", outFileName); return 1; } // Read the file header: salt, key, memCost uint8_t memCost, multiplies, lanes; if(fread(salt, sizeof(uint8_t), SALT_SIZE, inFile) != SALT_SIZE || fread(&memCost, sizeof(uint8_t), 1, inFile) != 1 || fread(&multiplies, sizeof(uint8_t), 1, inFile) != 1 || fread(&lanes, sizeof(uint8_t), 1, inFile) != 1) { fprintf(stderr, "Input file too short\n"); return 1; } if(!TwoCats_HashPasswordExtended(NULL, TWOCATS_HASHTYPE, key, (uint8_t *)password, strlen(password), salt, SALT_SIZE, NULL, 0, memCost, memCost, multiplies, lanes, TWOCATS_PARALLELISM, TWOCATS_BLOCKSIZE, TWOCATS_SUBBLOCKSIZE, TWOCATS_OVERWRITECOST, false, false)) { fprintf(stderr, "Unable to hash password - memory allocation failed\n"); return 1; } // Initialize encrpytion EVP_CIPHER_CTX ctx; uint8_t out[32]; /* at least one block longer than in[] */ EVP_DecryptInit(&ctx, EVP_aes_256_cbc(), key, salt); // Encrypt input stream to output stream int outlen; int c; while((c = getc(inFile)) != EOF) { uint8_t buf = c; EVP_DecryptUpdate(&ctx, out, &outlen, &buf, sizeof(uint8_t)); if(outlen != 0) { fwrite(out, sizeof(uint8_t), outlen, outFile); } } // Finalize encryption EVP_DecryptFinal(&ctx, out, &outlen); if(outlen != 0) { fwrite(out, sizeof(uint8_t), outlen, outFile); } fclose(outFile); fclose(inFile); return 0; }