// Finalize a hash and convert to an array of uint32_t. static bool finalUint32(TwoCats_H *H, uint32_t *hash32) { uint8_t buf[H->size]; if(!H->Final(H, buf)) { secureZeroMemory(buf, H->size); return false; } decodeLittleEndian(hash32, buf, H->size); secureZeroMemory(buf, H->size); return true; }
// Scramble the hash value. static bool scrambleHash(TwoCats_H *H, uint32_t *hash32) { uint8_t buf[H->size]; encodeLittleEndian(buf, hash32, H->size); if(!H->Init(H) || !H->Update(H, buf, H->size) || !H->Final(H, buf)) { secureZeroMemory(buf, H->size); return false; } decodeLittleEndian(hash32, buf, H->size); secureZeroMemory(buf, H->size); return true; }
// Scramble the 32-bit hash state, including a single uint32_t value. static bool hashState(TwoCats_H *H, uint32_t *state, uint32_t value) { uint8_t buf[H->size]; encodeLittleEndian(buf, state, H->size); if(!H->Init(H) || !H->Update(H, buf, H->size) || !H->UpdateUint32(H, value) || !H->Final(H, buf)) { secureZeroMemory(buf, H->size); return false; } decodeLittleEndian(state, buf, H->size); secureZeroMemory(buf, H->size); return true; }
// Client-side portion of work for server-relief mode. Return true if there are no memory // allocation errors. The password and data are not cleared if there is an error. bool TwoCats_ClientHashPassword(TwoCats_HashType hashType, uint8_t *hash, uint8_t *password, uint32_t passwordSize, const uint8_t *salt, uint32_t saltSize, uint8_t *data, uint32_t dataSize, uint8_t startMemCost, uint8_t stopMemCost, uint8_t timeCost, uint8_t multiplies, uint8_t lanes, uint8_t parallelism, uint32_t blockSize, uint32_t subBlockSize, uint8_t overwriteCost, bool clearPassword, bool clearData) { TwoCats_H H; TwoCats_InitHash(&H, hashType); if(!verifyParameters(&H, startMemCost, stopMemCost, timeCost, multiplies, lanes, parallelism, blockSize, subBlockSize)) { return false; } // Convert overwiteCost from relative to startMemCost to absolute if(overwriteCost >= startMemCost) { overwriteCost = 0; } else if(overwriteCost != 0) { overwriteCost = startMemCost - overwriteCost; } // Add all the inputs, other than stopMemCost uint32_t hash32[H.len]; if(!H.Init(&H) || !H.UpdateUint32(&H, passwordSize) || !H.UpdateUint32(&H, saltSize) || !H.UpdateUint32(&H, dataSize) || !H.UpdateUint32(&H, blockSize) || !H.UpdateUint32(&H, subBlockSize) || !H.Update(&H, &startMemCost, 1) || !H.Update(&H, &timeCost, 1) || !H.Update(&H, &multiplies, 1) || !H.Update(&H, &lanes, 1) || !H.Update(&H, ¶llelism, 1) || !H.Update(&H, &overwriteCost, 1) || !H.Update(&H, password, passwordSize) || !H.Update(&H, salt, saltSize) || !H.Update(&H, data, dataSize) || !H.FinalUint32(&H, hash32)) { return false; } // Now clear the password and data if allowed if(clearPassword && passwordSize != 0) { secureZeroMemory(password, passwordSize); } if(clearData && dataSize != 0) { secureZeroMemory(data, dataSize); } if(!TwoCats(&H, hash32, startMemCost, stopMemCost, timeCost, multiplies, lanes, parallelism, blockSize, subBlockSize, overwriteCost)) { return false; } encodeLittleEndian(hash, hash32, H.size); secureZeroMemory(hash32, H.size); return true; }
TEST(SecureZeroMemoryTest, zeroZeroLengthNull) { void* ptr = nullptr; secureZeroMemory(ptr, 0); ASSERT_TRUE(true); }