1
0
mirror of synced 2025-01-26 16:23:44 +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 <hex.hpp>
#include <wolv/utils/expected.hpp>
#include <array> #include <array>
#include <string> #include <string>
#include <vector> #include <vector>
#define CRYPTO_ERROR_INVALID_KEY_LENGTH (-1)
#define CRYPTO_ERROR_INVALID_MODE (-2)
namespace hex::prv { namespace hex::prv {
class Provider; class Provider;
} }
@ -60,5 +65,5 @@ namespace hex::crypt {
Key256Bits = 2 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(); auto &outputData = attribute->getOutputData();
if (outputData.empty())
throwNodeError("No data available at connected attribute");
return outputData; return outputData;
} }

View File

@ -1,8 +1,10 @@
#include <algorithm>
#include <hex/helpers/crypto.hpp> #include <hex/helpers/crypto.hpp>
#include <hex/providers/provider.hpp> #include <hex/providers/provider.hpp>
#include <wolv/utils/guards.hpp> #include <wolv/utils/guards.hpp>
#include <wolv/utils/expected.hpp>
#include <mbedtls/version.h> #include <mbedtls/version.h>
#include <mbedtls/base64.h> #include <mbedtls/base64.h>
@ -496,8 +498,8 @@ namespace hex::crypt {
return encodeLeb128<i128>(value); 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) { static wolv::util::Expected<std::vector<u8>, int> aes(mbedtls_cipher_type_t type, mbedtls_operation_t operation, const std::vector<u8> &key,
std::vector<u8> output; std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::span<const u8> &input) {
if (input.empty()) if (input.empty())
return {}; return {};
@ -507,38 +509,65 @@ namespace hex::crypt {
mbedtls_cipher_context_t ctx; mbedtls_cipher_context_t ctx;
auto cipherInfo = mbedtls_cipher_info_from_type(type); auto cipherInfo = mbedtls_cipher_info_from_type(type);
if (cipherInfo == nullptr)
return {};
mbedtls_cipher_setup(&ctx, cipherInfo); int setupResult = mbedtls_cipher_setup(&ctx, cipherInfo);
mbedtls_cipher_setkey(&ctx, key.data(), key.size() * 8, operation); 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::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); size_t outputSize = input.size() + mbedtls_cipher_get_block_size(&ctx);
output.resize(outputSize, 0x00); std::vector<u8> output(outputSize, 0x00);
mbedtls_cipher_crypt(&ctx, nonceCounter.data(), nonceCounter.size(), input.data(), input.size(), output.data(), &outputSize);
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); mbedtls_cipher_free(&ctx);
if (cryptResult != 0) {
return wolv::util::Unexpected(cryptResult);
}
output.resize(input.size()); output.resize(input.size());
return output; 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) { switch (keyLength) {
case KeyLength::Key128Bits: case KeyLength::Key128Bits:
if (key.size() != 128 / 8) return {}; if (key.size() != 128 / 8)
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
break; break;
case KeyLength::Key192Bits: case KeyLength::Key192Bits:
if (key.size() != 192 / 8) return {}; if (key.size() != 192 / 8)
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
break; break;
case KeyLength::Key256Bits: case KeyLength::Key256Bits:
if (key.size() != 256 / 8) return {}; if (key.size() != 256 / 8)
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
break; break;
default: default:
return {}; return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
} }
mbedtls_cipher_type_t type; mbedtls_cipher_type_t type;
@ -568,7 +597,7 @@ namespace hex::crypt {
type = MBEDTLS_CIPHER_AES_128_XTS; type = MBEDTLS_CIPHER_AES_128_XTS;
break; break;
default: default:
return {}; return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_MODE);
} }
type = mbedtls_cipher_type_t(type + u8(keyLength)); 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/content_registry.hpp>
#include <hex/api/localization_manager.hpp> #include <hex/api/localization_manager.hpp>
#include <hex/helpers/utils.hpp> #include <hex/helpers/utils.hpp>
#include <hex/helpers/crypto.hpp> #include <hex/helpers/crypto.hpp>
#include <hex/data_processor/node.hpp> #include <hex/data_processor/node.hpp>
#include <mbedtls/cipher.h>
#include <mbedtls/error.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
@ -25,6 +29,9 @@ namespace hex::plugin::builtin {
} }
void process() override { 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 &key = this->getBufferOnInput(0);
const auto &iv = this->getBufferOnInput(1); const auto &iv = this->getBufferOnInput(1);
const auto &nonce = this->getBufferOnInput(2); const auto &nonce = this->getBufferOnInput(2);
@ -38,12 +45,34 @@ namespace hex::plugin::builtin {
std::array<u8, 8> ivData = { 0 }, nonceData = { 0 }; std::array<u8, 8> ivData = { 0 }, nonceData = { 0 };
std::copy(iv.begin(), iv.end(), ivData.begin()); if (mode != crypt::AESMode::ECB) {
std::copy(nonce.begin(), nonce.end(), nonceData.begin()); 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 { void store(nlohmann::json &j) const override {