CryptoAlgorithmHKDFGCrypt.cpp [plain text]
#include "config.h"
#include "CryptoAlgorithmHKDF.h"
#if ENABLE(SUBTLE_CRYPTO)
#include "CryptoAlgorithmHkdfParams.h"
#include "CryptoKeyRaw.h"
#include "GCryptUtilities.h"
namespace WebCore {
static std::optional<Vector<uint8_t>> gcryptDeriveBits(const Vector<uint8_t>& key, const Vector<uint8_t>& salt, const Vector<uint8_t>& info, size_t lengthInBytes, CryptoAlgorithmIdentifier identifier)
{
auto macAlgorithm = hmacAlgorithm(identifier);
if (!macAlgorithm)
return std::nullopt;
size_t macLength = gcry_mac_get_algo_maclen(*macAlgorithm);
if (lengthInBytes > macLength * 255)
return std::nullopt;
PAL::GCrypt::Handle<gcry_mac_hd_t> handle;
gcry_error_t error = gcry_mac_open(&handle, *macAlgorithm, 0, nullptr);
if (error != GPG_ERR_NO_ERROR) {
PAL::GCrypt::logError(error);
return std::nullopt;
}
Vector<uint8_t> pseudoRandomKey(macLength);
{
if (salt.isEmpty()) {
Vector<uint8_t> zeroedKey(macLength, 0);
error = gcry_mac_setkey(handle, zeroedKey.data(), zeroedKey.size());
} else
error = gcry_mac_setkey(handle, salt.data(), salt.size());
if (error != GPG_ERR_NO_ERROR) {
PAL::GCrypt::logError(error);
return std::nullopt;
}
error = gcry_mac_write(handle, key.data(), key.size());
if (error != GPG_ERR_NO_ERROR) {
PAL::GCrypt::logError(error);
return std::nullopt;
}
size_t pseudoRandomKeySize = pseudoRandomKey.size();
error = gcry_mac_read(handle, pseudoRandomKey.data(), &pseudoRandomKeySize);
if (error != GPG_ERR_NO_ERROR) {
PAL::GCrypt::logError(error);
return std::nullopt;
}
if (pseudoRandomKeySize != macLength)
return std::nullopt;
}
Vector<uint8_t> output;
{
size_t numIterations = (lengthInBytes + macLength) / macLength;
Vector<uint8_t> lastBlock(macLength);
for (size_t i = 0; i < numIterations; ++i) {
error = gcry_mac_reset(handle);
if (error != GPG_ERR_NO_ERROR) {
PAL::GCrypt::logError(error);
return std::nullopt;
}
error = gcry_mac_setkey(handle, pseudoRandomKey.data(), pseudoRandomKey.size());
if (error != GPG_ERR_NO_ERROR) {
PAL::GCrypt::logError(error);
return std::nullopt;
}
Vector<uint8_t> blockData;
if (i)
blockData.appendVector(lastBlock);
blockData.appendVector(info);
blockData.append(i + 1);
error = gcry_mac_write(handle, blockData.data(), blockData.size());
if (error != GPG_ERR_NO_ERROR) {
PAL::GCrypt::logError(error);
return std::nullopt;
}
size_t blockSize = lastBlock.size();
error = gcry_mac_read(handle, lastBlock.data(), &blockSize);
if (error != GPG_ERR_NO_ERROR) {
PAL::GCrypt::logError(error);
return std::nullopt;
}
if (blockSize != lastBlock.size())
return std::nullopt;
output.appendVector(lastBlock);
}
}
output.resize(lengthInBytes);
return output;
}
ExceptionOr<Vector<uint8_t>> CryptoAlgorithmHKDF::platformDeriveBits(const CryptoAlgorithmHkdfParams& parameters, const CryptoKeyRaw& key, size_t length)
{
auto output = gcryptDeriveBits(key.key(), parameters.saltVector(), parameters.infoVector(), length / 8, parameters.hashIdentifier);
if (!output)
return Exception { OperationError };
return WTFMove(*output);
}
}
#endif // ENABLE(SUBTLE_CRYPTO)