diff --git a/lib/libimhex/include/hex/helpers/crypto.hpp b/lib/libimhex/include/hex/helpers/crypto.hpp index dcad1859f..dc4c5eda2 100644 --- a/lib/libimhex/include/hex/helpers/crypto.hpp +++ b/lib/libimhex/include/hex/helpers/crypto.hpp @@ -2,10 +2,15 @@ #include +#include + #include #include #include +#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 aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector &key, std::array nonce, std::array iv, const std::vector &input); + wolv::util::Expected, int> aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector &key, std::array nonce, std::array iv, const std::vector &input); } diff --git a/lib/libimhex/source/data_processor/node.cpp b/lib/libimhex/source/data_processor/node.cpp index 67b57fbc9..59e24c51f 100644 --- a/lib/libimhex/source/data_processor/node.cpp +++ b/lib/libimhex/source/data_processor/node.cpp @@ -35,9 +35,6 @@ namespace hex::dp { auto &outputData = attribute->getOutputData(); - if (outputData.empty()) - throwNodeError("No data available at connected attribute"); - return outputData; } diff --git a/lib/libimhex/source/helpers/crypto.cpp b/lib/libimhex/source/helpers/crypto.cpp index 8e1c15378..a5d4b41f9 100644 --- a/lib/libimhex/source/helpers/crypto.cpp +++ b/lib/libimhex/source/helpers/crypto.cpp @@ -1,8 +1,10 @@ +#include #include #include #include +#include #include #include @@ -496,8 +498,8 @@ namespace hex::crypt { return encodeLeb128(value); } - static std::vector aes(mbedtls_cipher_type_t type, mbedtls_operation_t operation, const std::vector &key, std::array nonce, std::array iv, const std::vector &input) { - std::vector output; + static wolv::util::Expected, int> aes(mbedtls_cipher_type_t type, mbedtls_operation_t operation, const std::vector &key, + std::array nonce, std::array iv, const std::span &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 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 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 aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector &key, std::array nonce, std::array iv, const std::vector &input) { + wolv::util::Expected, int> aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector &key, std::array nonce, std::array iv, const std::vector &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)); diff --git a/plugins/builtin/source/content/data_processor_nodes/decode_nodes.cpp b/plugins/builtin/source/content/data_processor_nodes/decode_nodes.cpp index 09ea27afa..ea15cd734 100644 --- a/plugins/builtin/source/content/data_processor_nodes/decode_nodes.cpp +++ b/plugins/builtin/source/content/data_processor_nodes/decode_nodes.cpp @@ -1,9 +1,13 @@ +#include #include #include #include #include #include +#include +#include + #include namespace hex::plugin::builtin { @@ -25,6 +29,9 @@ namespace hex::plugin::builtin { } void process() override { + const auto mode = static_cast(m_mode); + const auto keyLength = static_cast(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 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(m_mode), static_cast(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 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 {