CryptoAlgorithmAES_CTRGCrypt.cpp [plain text]
#include "config.h"
#include "CryptoAlgorithmAES_CTR.h"
#if ENABLE(WEB_CRYPTO)
#include "CryptoAlgorithmAesCtrParams.h"
#include "CryptoKeyAES.h"
#include <pal/crypto/gcrypt/Handle.h>
#include <pal/crypto/gcrypt/Utilities.h>
namespace WebCore {
static Optional<Vector<uint8_t>> callOperation(PAL::GCrypt::CipherOperation operation, gcry_cipher_hd_t handle, const Vector<uint8_t>& counter, const uint8_t* data, const size_t size)
{
gcry_error_t error = gcry_cipher_reset(handle);
if (error != GPG_ERR_NO_ERROR) {
PAL::GCrypt::logError(error);
return WTF::nullopt;
}
error = gcry_cipher_setctr(handle, counter.data(), counter.size());
if (error != GPG_ERR_NO_ERROR) {
PAL::GCrypt::logError(error);
return WTF::nullopt;
}
error = gcry_cipher_final(handle);
if (error != GPG_ERR_NO_ERROR) {
PAL::GCrypt::logError(error);
return WTF::nullopt;
}
Vector<uint8_t> output(size);
error = operation(handle, output.data(), output.size(), data, size);
if (error != GPG_ERR_NO_ERROR) {
PAL::GCrypt::logError(error);
return WTF::nullopt;
}
return output;
}
static Optional<Vector<uint8_t>> gcryptAES_CTR(PAL::GCrypt::CipherOperation operation, const Vector<uint8_t>& key, const Vector<uint8_t>& counter, size_t counterLength, const Vector<uint8_t>& inputText)
{
constexpr size_t blockSize = 16;
auto algorithm = PAL::GCrypt::aesAlgorithmForKeySize(key.size() * 8);
if (!algorithm)
return WTF::nullopt;
PAL::GCrypt::Handle<gcry_cipher_hd_t> handle;
gcry_error_t error = gcry_cipher_open(&handle, *algorithm, GCRY_CIPHER_MODE_CTR, 0);
if (error != GPG_ERR_NO_ERROR) {
PAL::GCrypt::logError(error);
return WTF::nullopt;
}
error = gcry_cipher_setkey(handle, key.data(), key.size());
if (error != GPG_ERR_NO_ERROR) {
PAL::GCrypt::logError(error);
return WTF::nullopt;
}
PAL::GCrypt::Handle<gcry_mpi_t> blockCountMPI(gcry_mpi_new(0));
{
PAL::GCrypt::Handle<gcry_mpi_t> blockSizeMPI(gcry_mpi_set_ui(nullptr, blockSize));
PAL::GCrypt::Handle<gcry_mpi_t> roundedUpSize(gcry_mpi_set_ui(nullptr, inputText.size()));
gcry_mpi_add_ui(roundedUpSize, roundedUpSize, blockSize - 1);
gcry_mpi_div(blockCountMPI, nullptr, roundedUpSize, blockSizeMPI, 0);
}
PAL::GCrypt::Handle<gcry_mpi_t> counterLimitMPI(gcry_mpi_set_ui(nullptr, 1));
gcry_mpi_mul_2exp(counterLimitMPI, counterLimitMPI, counterLength);
if (gcry_mpi_cmp(counterLimitMPI, blockCountMPI) < 0)
return WTF::nullopt;
if (counterLength == counter.size() * 8)
return callOperation(operation, handle, counter, inputText.data(), inputText.size());
PAL::GCrypt::Handle<gcry_mpi_t> counterDataMPI;
error = gcry_mpi_scan(&counterDataMPI, GCRYMPI_FMT_USG, counter.data(), counter.size(), nullptr);
if (error != GPG_ERR_NO_ERROR) {
PAL::GCrypt::logError(error);
return WTF::nullopt;
}
PAL::GCrypt::Handle<gcry_mpi_t> counterMPI(gcry_mpi_new(0));
gcry_mpi_mod(counterMPI, counterDataMPI, counterLimitMPI);
{
PAL::GCrypt::Handle<gcry_mpi_t> counterLeewayMPI(gcry_mpi_new(0));
gcry_mpi_sub(counterLeewayMPI, counterLimitMPI, counterMPI);
if (gcry_mpi_cmp(counterLeewayMPI, blockCountMPI) >= 0)
return callOperation(operation, handle, counter, inputText.data(), inputText.size());
}
PAL::GCrypt::Handle<gcry_mpi_t> nonceMPI(gcry_mpi_new(0));
gcry_mpi_sub(nonceMPI, counterDataMPI, counterMPI);
Vector<uint8_t> output;
Vector<uint8_t> blockCounterData(16);
size_t inputTextSize = inputText.size();
for (size_t i = 0; i < inputTextSize; i += 16) {
size_t blockInputSize = std::min<size_t>(16, inputTextSize - i);
PAL::GCrypt::Handle<gcry_mpi_t> blockCounterMPI(gcry_mpi_new(0));
gcry_mpi_add(blockCounterMPI, nonceMPI, counterMPI);
error = gcry_mpi_print(GCRYMPI_FMT_USG, blockCounterData.data(), blockCounterData.size(), nullptr, blockCounterMPI);
if (error != GPG_ERR_NO_ERROR) {
PAL::GCrypt::logError(error);
return WTF::nullopt;
}
auto blockOutput = callOperation(operation, handle, blockCounterData, inputText.data() + i, blockInputSize);
if (!blockOutput)
return WTF::nullopt;
output.appendVector(*blockOutput);
PAL::GCrypt::Handle<gcry_mpi_t> counterIncrementMPI(gcry_mpi_new(0));
gcry_mpi_add_ui(counterIncrementMPI, counterMPI, 1);
gcry_mpi_mod(counterMPI, counterIncrementMPI, counterLimitMPI);
}
return output;
}
ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CTR::platformEncrypt(const CryptoAlgorithmAesCtrParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& plainText)
{
auto output = gcryptAES_CTR(gcry_cipher_encrypt, key.key(), parameters.counterVector(), parameters.length, plainText);
if (!output)
return Exception { OperationError };
return WTFMove(*output);
}
ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_CTR::platformDecrypt(const CryptoAlgorithmAesCtrParams& parameters, const CryptoKeyAES& key, const Vector<uint8_t>& cipherText)
{
auto output = gcryptAES_CTR(gcry_cipher_decrypt, key.key(), parameters.counterVector(), parameters.length, cipherText);
if (!output)
return Exception { OperationError };
return WTFMove(*output);
}
}
#endif // ENABLE(WEB_CRYPTO)