1
0
mirror of synced 2025-01-25 15:53:43 +01:00

fix: AES ECB mode in Data processor not working at all (#1986)

Fix the AES ECB mode in the data processor along with some other misc
fixes:
- Fixed nullpointer node not working
- Fixed crypto module incorrectly using mbedtls api
- Fixed crypto module ignoring mbedtls errors
- Fixed silently ignoring of errors in AES node
This commit is contained in:
Justus Garbe 2024-12-05 20:56:43 +01:00 committed by GitHub
parent 8acdc19be4
commit 3c73f88a52
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 82 additions and 22 deletions

View File

@ -2,10 +2,15 @@
#include <hex.hpp>
#include <wolv/utils/expected.hpp>
#include <array>
#include <string>
#include <vector>
#define CRYPTO_ERROR_INVALID_KEY_LENGTH (-1)
#define CRYPTO_ERROR_INVALID_MODE (-2)
namespace hex::prv {
class Provider;
}
@ -60,5 +65,5 @@ namespace hex::crypt {
Key256Bits = 2
};
std::vector<u8> aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input);
wolv::util::Expected<std::vector<u8>, int> aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input);
}

View File

@ -35,9 +35,6 @@ namespace hex::dp {
auto &outputData = attribute->getOutputData();
if (outputData.empty())
throwNodeError("No data available at connected attribute");
return outputData;
}

View File

@ -1,8 +1,10 @@
#include <algorithm>
#include <hex/helpers/crypto.hpp>
#include <hex/providers/provider.hpp>
#include <wolv/utils/guards.hpp>
#include <wolv/utils/expected.hpp>
#include <mbedtls/version.h>
#include <mbedtls/base64.h>
@ -496,8 +498,8 @@ namespace hex::crypt {
return encodeLeb128<i128>(value);
}
static std::vector<u8> aes(mbedtls_cipher_type_t type, mbedtls_operation_t operation, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input) {
std::vector<u8> output;
static wolv::util::Expected<std::vector<u8>, int> aes(mbedtls_cipher_type_t type, mbedtls_operation_t operation, const std::vector<u8> &key,
std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::span<const u8> &input) {
if (input.empty())
return {};
@ -507,38 +509,65 @@ namespace hex::crypt {
mbedtls_cipher_context_t ctx;
auto cipherInfo = mbedtls_cipher_info_from_type(type);
if (cipherInfo == nullptr)
return {};
mbedtls_cipher_setup(&ctx, cipherInfo);
mbedtls_cipher_setkey(&ctx, key.data(), key.size() * 8, operation);
int setupResult = mbedtls_cipher_setup(&ctx, cipherInfo);
if (setupResult != 0)
return wolv::util::Unexpected(setupResult);
int setKeyResult = mbedtls_cipher_setkey(&ctx, key.data(), key.size() * 8, operation);
if (setKeyResult != 0)
return wolv::util::Unexpected(setKeyResult);
std::array<u8, 16> nonceCounter = { 0 };
std::copy(nonce.begin(), nonce.end(), nonceCounter.begin());
std::copy(iv.begin(), iv.end(), nonceCounter.begin() + 8);
auto mode = mbedtls_cipher_get_cipher_mode(&ctx);
// if we are in ECB mode, we don't need to set the nonce
if (mode != MBEDTLS_MODE_ECB) {
std::ranges::copy(nonce, nonceCounter.begin());
std::ranges::copy(iv, nonceCounter.begin() + 8);
}
size_t outputSize = input.size() + mbedtls_cipher_get_block_size(&ctx);
output.resize(outputSize, 0x00);
mbedtls_cipher_crypt(&ctx, nonceCounter.data(), nonceCounter.size(), input.data(), input.size(), output.data(), &outputSize);
std::vector<u8> output(outputSize, 0x00);
int cryptResult = 0;
if (mode == MBEDTLS_MODE_ECB) {
cryptResult = mbedtls_cipher_crypt(&ctx, nullptr, 0, input.data(), input.size(), output.data(), &outputSize);
} else {
cryptResult = mbedtls_cipher_crypt(&ctx, nonceCounter.data(), nonceCounter.size(), input.data(), input.size(), output.data(), &outputSize);
}
// free regardless of the result
mbedtls_cipher_free(&ctx);
if (cryptResult != 0) {
return wolv::util::Unexpected(cryptResult);
}
output.resize(input.size());
return output;
}
std::vector<u8> aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input) {
wolv::util::Expected<std::vector<u8>, int> aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input) {
switch (keyLength) {
case KeyLength::Key128Bits:
if (key.size() != 128 / 8) return {};
if (key.size() != 128 / 8)
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
break;
case KeyLength::Key192Bits:
if (key.size() != 192 / 8) return {};
if (key.size() != 192 / 8)
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
break;
case KeyLength::Key256Bits:
if (key.size() != 256 / 8) return {};
if (key.size() != 256 / 8)
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
break;
default:
return {};
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
}
mbedtls_cipher_type_t type;
@ -568,7 +597,7 @@ namespace hex::crypt {
type = MBEDTLS_CIPHER_AES_128_XTS;
break;
default:
return {};
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_MODE);
}
type = mbedtls_cipher_type_t(type + u8(keyLength));

View File

@ -1,9 +1,13 @@
#include <algorithm>
#include <hex/api/content_registry.hpp>
#include <hex/api/localization_manager.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/crypto.hpp>
#include <hex/data_processor/node.hpp>
#include <mbedtls/cipher.h>
#include <mbedtls/error.h>
#include <nlohmann/json.hpp>
namespace hex::plugin::builtin {
@ -25,6 +29,9 @@ namespace hex::plugin::builtin {
}
void process() override {
const auto mode = static_cast<crypt::AESMode>(m_mode);
const auto keyLength = static_cast<crypt::KeyLength>(m_keyLength);
const auto &key = this->getBufferOnInput(0);
const auto &iv = this->getBufferOnInput(1);
const auto &nonce = this->getBufferOnInput(2);
@ -38,12 +45,34 @@ namespace hex::plugin::builtin {
std::array<u8, 8> ivData = { 0 }, nonceData = { 0 };
std::copy(iv.begin(), iv.end(), ivData.begin());
std::copy(nonce.begin(), nonce.end(), nonceData.begin());
if (mode != crypt::AESMode::ECB) {
if (iv.empty())
throwNodeError("IV cannot be empty");
auto output = crypt::aesDecrypt(static_cast<crypt::AESMode>(m_mode), static_cast<crypt::KeyLength>(m_keyLength), key, nonceData, ivData, input);
if (nonce.empty())
throwNodeError("Nonce cannot be empty");
this->setBufferOnOutput(4, output);
std::ranges::copy(iv, ivData.begin());
std::ranges::copy(nonce, nonceData.begin());
}
auto output = crypt::aesDecrypt(mode, keyLength, key, nonceData, ivData, input);
if (!output) {
switch (output.error()) {
case CRYPTO_ERROR_INVALID_KEY_LENGTH:
throwNodeError("Invalid key length");
case CRYPTO_ERROR_INVALID_MODE:
throwNodeError("Invalid mode");
default: {
std::array<char, 128> errorBuffer = { 0 };
mbedtls_strerror(output.error(), errorBuffer.data(), errorBuffer.size());
throwNodeError(std::string(errorBuffer.data()));
}
}
}
this->setBufferOnOutput(4, output.value());
}
void store(nlohmann::json &j) const override {