diff --git a/extension-utils/CMakeLists.txt b/extension-utils/CMakeLists.txt index 785d24cb34..c08777b667 100644 --- a/extension-utils/CMakeLists.txt +++ b/extension-utils/CMakeLists.txt @@ -5,21 +5,18 @@ file(GLOB SOURCES src/controllers/*.cpp src/io/*.cpp src/serialization/*.cpp - src/utils/crypto/ciphers/*.cpp - src/utils/property_encryption/*.cpp - src/utils/crypto/*.cpp src/utils/file/*.cpp src/utils/net/*.cpp src/utils/tls/*.cpp src/utils/*.cpp) -add_library(minifi-extension-utils STATIC ${SOURCES}) +add_minifi_library(minifi-extension-utils STATIC ${SOURCES}) target_include_directories(minifi-extension-utils PUBLIC include) target_link_libraries(minifi-extension-utils PUBLIC minifi-core) include(RangeV3) include(Asio) include(MagicEnum) -list(APPEND CORE_LIBRARIES ZLIB::ZLIB concurrentqueue RapidJSON spdlog Threads::Threads gsl-lite libsodium range-v3 expected-lite date::date date::tz asio magic_enum OpenSSL::Crypto OpenSSL::SSL CURL::libcurl RapidJSON) +list(APPEND CORE_LIBRARIES ZLIB::ZLIB concurrentqueue RapidJSON spdlog Threads::Threads gsl-lite range-v3 expected-lite date::date date::tz asio magic_enum OpenSSL::Crypto OpenSSL::SSL CURL::libcurl RapidJSON) if(NOT WIN32) list(APPEND CORE_LIBRARIES OSSP::libuuid++) endif() diff --git a/libminifi/CMakeLists.txt b/libminifi/CMakeLists.txt index 060dafac5f..3870ced66e 100644 --- a/libminifi/CMakeLists.txt +++ b/libminifi/CMakeLists.txt @@ -42,7 +42,7 @@ endif() set(TLS_SOURCES "src/utils/tls/*.cpp" "src/io/tls/*.cpp") -file(GLOB SOURCES "src/agent/*.cpp" "src/properties/*.cpp" "src/utils/file/*.cpp" "src/sitetosite/*.cpp" "src/core/logging/*.cpp" "src/core/logging/internal/*.cpp" "src/core/logging/alert/*.cpp" "src/core/state/*.cpp" "src/core/state/nodes/*.cpp" "src/c2/protocols/*.cpp" "src/c2/triggers/*.cpp" "src/c2/*.cpp" "src/io/*.cpp" ${SOCKET_SOURCES} ${TLS_SOURCES} "src/core/controller/*.cpp" "src/controllers/*.cpp" "src/controllers/keyvalue/*.cpp" "src/core/*.cpp" "src/core/repository/*.cpp" "src/core/flow/*.cpp" "src/core/json/*.cpp" "src/core/yaml/*.cpp" "src/core/reporting/*.cpp" "src/core/extension/*.cpp" "src/serialization/*.cpp" "src/provenance/*.cpp" "src/utils/*.cpp" "src/utils/crypto/*.cpp" "src/utils/crypto/ciphers/*.cpp" "src/utils/crypto/property_encryption/*.cpp" "src/*.cpp" "src/utils/net/*.cpp" "src/http/*.cpp") +file(GLOB SOURCES "src/agent/*.cpp" "src/properties/*.cpp" "src/utils/file/*.cpp" "src/sitetosite/*.cpp" "src/core/logging/*.cpp" "src/core/logging/internal/*.cpp" "src/core/logging/alert/*.cpp" "src/core/state/*.cpp" "src/core/state/nodes/*.cpp" "src/c2/protocols/*.cpp" "src/c2/triggers/*.cpp" "src/c2/*.cpp" "src/io/*.cpp" ${SOCKET_SOURCES} ${TLS_SOURCES} "src/core/controller/*.cpp" "src/controllers/*.cpp" "src/core/*.cpp" "src/core/repository/*.cpp" "src/core/flow/*.cpp" "src/core/json/*.cpp" "src/core/yaml/*.cpp" "src/core/reporting/*.cpp" "src/core/extension/*.cpp" "src/serialization/*.cpp" "src/provenance/*.cpp" "src/utils/*.cpp" "src/*.cpp") # manually add this as it might not yet be present when this executes list(APPEND SOURCES "${CMAKE_CURRENT_BINARY_DIR}/agent_version.cpp") diff --git a/libminifi/include/utils/crypto/EncryptionManager.h b/libminifi/include/utils/crypto/EncryptionManager.h deleted file mode 100644 index bdcede1dc8..0000000000 --- a/libminifi/include/utils/crypto/EncryptionManager.h +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include -#include - -#include "utils/crypto/EncryptionUtils.h" -#include "utils/crypto/ciphers/XSalsa20.h" -#include "utils/crypto/ciphers/Aes256Ecb.h" -#include "core/logging/Logger.h" -#include "core/logging/LoggerFactory.h" - -namespace org::apache::nifi::minifi::utils::crypto { - -const auto DEFAULT_NIFI_BOOTSTRAP_FILE = std::filesystem::path("conf") / "bootstrap.conf"; - -class EncryptionManager { - public: - explicit EncryptionManager(std::filesystem::path key_dir) : key_dir_(std::move(key_dir)) {} - - template [[nodiscard]] std::optional getOptionalKey(const std::string& key_name) const; - template [[nodiscard]] std::optional getOptionalKeyCreateIfBlank(const std::string& key_name) const; - template [[nodiscard]] Cipher getRequiredKey(const std::string& key_name) const; - - protected: - [[nodiscard]] virtual std::optional readKey(const std::string& key_name) const; - [[nodiscard]] virtual bool writeKey(const std::string& key_name, const Bytes& key) const; - - std::filesystem::path key_dir_; - - private: - std::shared_ptr logger_ = core::logging::LoggerFactory::getLogger(); -}; - -template -std::optional EncryptionManager::getOptionalKey(const std::string& key_name) const { - return readKey(key_name) - | utils::transform([] (const Bytes& key) { return Cipher{key}; }); -} - -template -std::optional EncryptionManager::getOptionalKeyCreateIfBlank(const std::string& key_name) const { - auto key = readKey(key_name); - if (!key) { - logger_->log_info("No encryption key found for '{}'", key_name); - return std::nullopt; - } - if (key->empty()) { - logger_->log_info("Generating encryption key for '{}'", key_name); - key = Cipher::generateKey(); - if (!writeKey(key_name, key.value())) { - logger_->log_warn("Failed to write key for '{}'", key_name); - return std::nullopt; - } - } else { - logger_->log_info("Using existing encryption key for '{}'", key_name); - } - return Cipher{key.value()}; -} - -template -Cipher EncryptionManager::getRequiredKey(const std::string& key_name) const { - auto key = readKey(key_name); - if (!key || key->empty()) { - logger_->log_info("Generating encryption key for '{}'", key_name); - key = Cipher::generateKey(); - if (!writeKey(key_name, key.value())) { - throw Exception(GENERAL_EXCEPTION, utils::string::join_pack("Failed to write the encryption key for ", key_name, " to ", (key_dir_ / DEFAULT_NIFI_BOOTSTRAP_FILE).string())); - } - } else { - logger_->log_info("Using existing encryption key for '{}'", key_name); - } - return Cipher{key.value()}; -} - -} // namespace org::apache::nifi::minifi::utils::crypto diff --git a/libminifi/include/utils/crypto/EncryptionProvider.h b/libminifi/include/utils/crypto/EncryptionProvider.h deleted file mode 100644 index b72c38134f..0000000000 --- a/libminifi/include/utils/crypto/EncryptionProvider.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "utils/crypto/EncryptionUtils.h" -#include "utils/crypto/ciphers/XSalsa20.h" -#include "core/logging/Logger.h" - -namespace org::apache::nifi::minifi::utils::crypto { - -class EncryptionProvider { - public: - explicit EncryptionProvider(Bytes key) : cipher_impl_(std::move(key)) {} - explicit EncryptionProvider(XSalsa20Cipher cipher_impl) : cipher_impl_(std::move(cipher_impl)) {} - - static std::optional create(const std::filesystem::path& home_path); - static EncryptionProvider createSensitivePropertiesEncryptor(const std::filesystem::path& home_path); - - [[nodiscard]] std::string encrypt(std::string_view data) const { - return cipher_impl_.encrypt(data); - } - - [[nodiscard]] std::string decrypt(std::string_view data) const { - return cipher_impl_.decrypt(data); - } - - private: - XSalsa20Cipher cipher_impl_; -}; - -} // namespace org::apache::nifi::minifi::utils::crypto diff --git a/libminifi/include/utils/crypto/EncryptionUtils.h b/libminifi/include/utils/crypto/EncryptionUtils.h deleted file mode 100644 index 66b95cd173..0000000000 --- a/libminifi/include/utils/crypto/EncryptionUtils.h +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -#include -#include -#include - -#include "utils/OptionalUtils.h" - -namespace org::apache::nifi::minifi::utils::crypto { - -using Bytes = std::vector; - -Bytes stringToBytes(std::string_view text); - -std::string bytesToString(const Bytes& bytes); - -Bytes generateKey(); - -Bytes randomBytes(size_t num_bytes); - -struct EncryptionType { - static std::string name(); - static size_t keyLength(); - static size_t nonceLength(); - static size_t macLength(); - static std::string separator(); -}; - -struct EncryptedData { - Bytes nonce; - Bytes ciphertext_plus_mac; -}; - -struct EncryptionError : public std::runtime_error { - using runtime_error::runtime_error; -}; - -/** - * Encrypt the input (raw version). - * - * Uses libsodium's secretbox encryption. - * Takes the plaintext as input, and returns the ciphertext (encrypted plaintext) plus the MAC (message authentication - * code), in binary form. - * The ciphertext has the same length as the plaintext, and the MAC is always EncryptionType::macLength() bytes long, - * so the output is EncryptionType::macLength() bytes longer than the input. - * - * @param plaintext plaintext - * @param key secret key of EncryptionType::keyLength() bytes, should be generated by a CSPRNG - * @param nonce random data freshly generated for each encryption to break rainbow table-type attacks; - * not encrypted and not secret, but included when computing the ciphertext; - * the length is EncryptionType::nonceLength() bytes, should be generated by a CSPRNG - * @return ciphertext plus MAC - * @throws std::exception if the input is incorrect (wrong lengths) - */ -Bytes encryptRaw(const Bytes& plaintext, const Bytes& key, const Bytes& nonce); - -/** - * Encrypt the plaintext using a randomly-generated nonce. - * - * * Generates a random nonce, - * * calls encryptRaw(), - * * base64-encodes the nonce and the ciphertext-plus-MAC, and - * * returns . - */ -std::string encrypt(std::string_view plaintext, const Bytes& key); - -/** - * Decrypt the input (raw version). - * - * Uses libsodium's secretbox decryption. - * Takes the (binary) ciphertext plus MAC as input, and returns the plaintext. It also authenticates the input by - * checking the MAC. - * The plaintext has the same length as the ciphertext, and the MAC is always EncryptionType::macLength() bytes long, - * so the output is EncryptionType::macLength() bytes shorter than the input. - * - * @param input ciphertext plus MAC - * @param key secret key of EncryptionType::keyLength() bytes, must be the same as used when encrypting - * @param nonce random data freshly generated for each encryption to break rainbow table-type attacks; - * EncryptionType::nonceLength() bytes, must be the same as used when encrypting - * @return plaintext - * @throws std::exception if either the decryption or the authentication fails - */ -Bytes decryptRaw(const Bytes& input, const Bytes& key, const Bytes& nonce); - -/** - * Decrypt an input of the form nonce + EncryptionType::separator() + ciphertext_plus_MAC. - * - * * Splits the input at EncryptionType::separator(), - * * base64-decodes the two parts of the input (nonce and ciphertext-plus-MAC), - * * calls deryptRaw(), - * * returns the decrypted plaintext. - */ -std::string decrypt(std::string_view input, const Bytes& key); - -/** - * Checks if the input of the form nonce + EncryptionType::separator() + ciphertext_plus_MAC, - * indicating that it is most likely encrypted. - */ -bool isEncrypted(std::string_view input); - -EncryptedData parseEncrypted(std::string_view input); - -} // namespace org::apache::nifi::minifi::utils::crypto diff --git a/libminifi/include/utils/crypto/ciphers/Aes256Ecb.h b/libminifi/include/utils/crypto/ciphers/Aes256Ecb.h deleted file mode 100644 index 0e920afeca..0000000000 --- a/libminifi/include/utils/crypto/ciphers/Aes256Ecb.h +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -#include "utils/crypto/EncryptionUtils.h" -#include "Exception.h" -#include "core/logging/Logger.h" - -namespace org { -namespace apache { -namespace nifi { -namespace minifi { -namespace utils { -namespace crypto { - -class CipherError : public Exception { - public: - explicit CipherError(const std::string& error_msg) : Exception(ExceptionType::GENERAL_EXCEPTION, error_msg) {} -}; - -/** - * This cipher in itself is unsafe to use to encrypt sensitive data. - * Consider this cipher as a building block for more secure modes - * of operations (CTR, CBC, etc.) - */ -class Aes256EcbCipher { - static std::shared_ptr logger_; - - public: - static constexpr size_t BLOCK_SIZE = 16; - static constexpr size_t KEY_SIZE = 32; - - explicit Aes256EcbCipher(Bytes encryption_key); - void encrypt(std::span data) const; - void decrypt(std::span data) const; - - static Bytes generateKey(); - - bool operator==(const Aes256EcbCipher& other) const; - - private: - static void handleError(const std::string& error_msg) { - logger_->log_error("{}", error_msg); - throw CipherError(error_msg); - } - - static void handleOpenSSLError(const char* msg); - - const Bytes encryption_key_; -}; - -} // namespace crypto -} // namespace utils -} // namespace minifi -} // namespace nifi -} // namespace apache -} // namespace org diff --git a/libminifi/include/utils/crypto/ciphers/XSalsa20.h b/libminifi/include/utils/crypto/ciphers/XSalsa20.h deleted file mode 100644 index 5ce17d14d2..0000000000 --- a/libminifi/include/utils/crypto/ciphers/XSalsa20.h +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include "utils/crypto/EncryptionUtils.h" - -namespace org::apache::nifi::minifi::utils::crypto { - -class XSalsa20Cipher { - public: - explicit XSalsa20Cipher(Bytes encryption_key) : encryption_key_(std::move(encryption_key)) {} - - static Bytes generateKey() { - return utils::crypto::generateKey(); - } - - [[nodiscard]] std::string encrypt(std::string_view data) const { - return utils::crypto::encrypt(data, encryption_key_); - } - - [[nodiscard]] std::string decrypt(std::string_view data) const { - return utils::crypto::decrypt(data, encryption_key_); - } - - private: - Bytes encryption_key_; -}; - -} // namespace org::apache::nifi::minifi::utils::crypto diff --git a/libminifi/include/utils/crypto/property_encryption/PropertyEncryptionUtils.h b/libminifi/include/utils/crypto/property_encryption/PropertyEncryptionUtils.h deleted file mode 100644 index 0ccaf002a7..0000000000 --- a/libminifi/include/utils/crypto/property_encryption/PropertyEncryptionUtils.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include "utils/crypto/EncryptionProvider.h" - -namespace org::apache::nifi::minifi::utils::crypto::property_encryption { - -std::string decrypt(std::string_view input, const EncryptionProvider& encryption_provider); -std::string encrypt(std::string_view input, const EncryptionProvider& encryption_provider); - -} // namespace org::apache::nifi::minifi::utils::crypto::property_encryption diff --git a/libminifi/src/utils/crypto/EncryptionManager.cpp b/libminifi/src/utils/crypto/EncryptionManager.cpp deleted file mode 100644 index 205c407dc0..0000000000 --- a/libminifi/src/utils/crypto/EncryptionManager.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "utils/crypto/EncryptionManager.h" -#include "properties/Properties.h" -#include "utils/StringUtils.h" - -namespace org::apache::nifi::minifi::utils::crypto { - -std::optional EncryptionManager::readKey(const std::string& key_name) const { - auto bootstrap_conf = minifi::Properties::create(); - bootstrap_conf->setHome(key_dir_); - bootstrap_conf->loadConfigureFile(DEFAULT_NIFI_BOOTSTRAP_FILE); - return bootstrap_conf->getString(key_name) - | utils::transform([](const std::string &encryption_key_hex) { return utils::string::from_hex(encryption_key_hex); }); -} - -bool EncryptionManager::writeKey(const std::string &key_name, const Bytes& key) const { - auto bootstrap_conf = minifi::Properties::create(); - bootstrap_conf->setHome(key_dir_); - bootstrap_conf->loadConfigureFile(DEFAULT_NIFI_BOOTSTRAP_FILE); - bootstrap_conf->set(key_name, utils::string::to_hex(key)); - return bootstrap_conf->commitChanges(); -} - -} // namespace org::apache::nifi::minifi::utils::crypto diff --git a/libminifi/src/utils/crypto/EncryptionProvider.cpp b/libminifi/src/utils/crypto/EncryptionProvider.cpp deleted file mode 100644 index f9c8c940bc..0000000000 --- a/libminifi/src/utils/crypto/EncryptionProvider.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "utils/crypto/EncryptionProvider.h" -#include "utils/OptionalUtils.h" -#include "utils/crypto/ciphers/XSalsa20.h" -#include "utils/crypto/EncryptionManager.h" - -namespace org::apache::nifi::minifi::utils::crypto { - -inline constexpr std::string_view CONFIG_ENCRYPTION_KEY_PROPERTY_NAME = "nifi.bootstrap.sensitive.key"; -inline constexpr std::string_view CONFIG_SENSITIVE_PROPERTIES_ENCRYPTION_KEY_PROPERTY_NAME = "nifi.bootstrap.sensitive.properties.key"; - -std::optional EncryptionProvider::create(const std::filesystem::path& home_path) { - return EncryptionManager{home_path}.getOptionalKey(std::string{CONFIG_ENCRYPTION_KEY_PROPERTY_NAME}) - | utils::transform([] (const XSalsa20Cipher& cipher) { return EncryptionProvider{cipher}; }); -} - -EncryptionProvider EncryptionProvider::createSensitivePropertiesEncryptor(const std::filesystem::path &home_path) { - const auto cipher = EncryptionManager{home_path}.getRequiredKey(std::string{CONFIG_SENSITIVE_PROPERTIES_ENCRYPTION_KEY_PROPERTY_NAME}); - return EncryptionProvider{cipher}; -} - -} // namespace org::apache::nifi::minifi::utils::crypto diff --git a/libminifi/src/utils/crypto/EncryptionUtils.cpp b/libminifi/src/utils/crypto/EncryptionUtils.cpp deleted file mode 100644 index 6d1b8fd128..0000000000 --- a/libminifi/src/utils/crypto/EncryptionUtils.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "utils/crypto/EncryptionUtils.h" - -#include - -#include -#include - -#include "utils/StringUtils.h" -#include "utils/span.h" - -namespace org::apache::nifi::minifi::utils::crypto { - -Bytes stringToBytes(std::string_view text) { - return utils::span_to(utils::as_span(std::span(text))); -} - -std::string bytesToString(const Bytes& bytes) { - return utils::span_to(utils::as_span(std::span(bytes))); -} - -Bytes generateKey() { - Bytes key(EncryptionType::keyLength()); - crypto_secretbox_keygen(reinterpret_cast(key.data())); - return key; -} - -Bytes randomBytes(size_t num_bytes) { - Bytes random_bytes(num_bytes); - randombytes_buf(random_bytes.data(), num_bytes); - return random_bytes; -} - -std::string EncryptionType::name() { return crypto_secretbox_primitive(); } - -size_t EncryptionType::keyLength() { return crypto_secretbox_keybytes(); } - -size_t EncryptionType::nonceLength() { return crypto_secretbox_noncebytes(); } - -size_t EncryptionType::macLength() { return crypto_secretbox_macbytes(); } - -std::string EncryptionType::separator() { return "||"; } - -Bytes encryptRaw(const Bytes& plaintext, const Bytes& key, const Bytes& nonce) { - if (key.size() != EncryptionType::keyLength()) { - throw EncryptionError{"Expected key of " + std::to_string(EncryptionType::keyLength()) + - " bytes, but got " + std::to_string(key.size()) + " bytes during encryption"}; - } - if (nonce.size() != EncryptionType::nonceLength()) { - throw EncryptionError{"Expected nonce of " + std::to_string(EncryptionType::nonceLength()) + - " bytes, but got " + std::to_string(nonce.size()) + " bytes during encryption"}; - } - - Bytes ciphertext_plus_mac(plaintext.size() + EncryptionType::macLength()); - crypto_secretbox_easy(reinterpret_cast(ciphertext_plus_mac.data()), reinterpret_cast(plaintext.data()), plaintext.size(), - reinterpret_cast(nonce.data()), reinterpret_cast(key.data())); - return ciphertext_plus_mac; -} - -std::string encrypt(std::string_view plaintext, const Bytes& key) { - Bytes nonce = randomBytes(EncryptionType::nonceLength()); - Bytes ciphertext_plus_mac = encryptRaw(stringToBytes(plaintext), key, nonce); - - std::string nonce_base64 = utils::string::to_base64(nonce); - std::string ciphertext_plus_mac_base64 = utils::string::to_base64(ciphertext_plus_mac); - return nonce_base64 + EncryptionType::separator() + ciphertext_plus_mac_base64; -} - -Bytes decryptRaw(const Bytes& input, const Bytes& key, const Bytes& nonce) { - if (key.size() != EncryptionType::keyLength()) { - throw EncryptionError{"Expected key of " + std::to_string(EncryptionType::keyLength()) + - " bytes, but got " + std::to_string(key.size()) + " bytes during decryption"}; - } - if (nonce.size() != EncryptionType::nonceLength()) { - throw EncryptionError{"Expected a nonce of " + std::to_string(EncryptionType::nonceLength()) + - " bytes, but got " + std::to_string(nonce.size()) + " bytes during decryption"}; - } - if (input.size() < EncryptionType::macLength()) { - throw EncryptionError{"Input is too short: expected at least " + std::to_string(EncryptionType::macLength()) + - " bytes, but got " + std::to_string(input.size()) + " bytes during decryption"}; - } - - Bytes plaintext(input.size() - EncryptionType::macLength()); - if (crypto_secretbox_open_easy(reinterpret_cast(plaintext.data()), reinterpret_cast(input.data()), input.size(), - reinterpret_cast(nonce.data()), reinterpret_cast(key.data()))) { - throw EncryptionError{"Decryption failed; the input may be forged!"}; - } - return plaintext; -} - -std::string decrypt(std::string_view input, const Bytes& key) { - auto data = parseEncrypted(input); - Bytes plaintext = decryptRaw(data.ciphertext_plus_mac, key, data.nonce); - return bytesToString(plaintext); -} - -EncryptedData parseEncrypted(std::string_view input) { - std::vector nonce_and_rest = utils::string::split(input, EncryptionType::separator()); - if (nonce_and_rest.size() != 2) { - throw EncryptionError{"Incorrect input; expected '" + EncryptionType::separator() + "'"}; - } - - Bytes nonce = utils::string::from_base64(nonce_and_rest[0]); - Bytes ciphertext_plus_mac = utils::string::from_base64(nonce_and_rest[1]); - - return EncryptedData{nonce, ciphertext_plus_mac}; -} - -bool isEncrypted(std::string_view input) { - try { - parseEncrypted(input); - return true; - } catch (...) { - return false; - } -} - -} // namespace org::apache::nifi::minifi::utils::crypto diff --git a/libminifi/src/utils/crypto/ciphers/Aes256Ecb.cpp b/libminifi/src/utils/crypto/ciphers/Aes256Ecb.cpp deleted file mode 100644 index d7fc0425e7..0000000000 --- a/libminifi/src/utils/crypto/ciphers/Aes256Ecb.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/** - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "utils/crypto/ciphers/Aes256Ecb.h" -#include "openssl/conf.h" -#include "openssl/evp.h" -#include "openssl/err.h" -#include "openssl/rand.h" -#include "core/logging/LoggerFactory.h" - -namespace org::apache::nifi::minifi::utils::crypto { - -using EVP_CIPHER_CTX_ptr = std::unique_ptr; - -std::shared_ptr Aes256EcbCipher::logger_{core::logging::LoggerFactory::getLogger()}; - -Aes256EcbCipher::Aes256EcbCipher(Bytes encryption_key) : encryption_key_(std::move(encryption_key)) { - if (encryption_key_.size() != KEY_SIZE) { - handleError(fmt::format("Invalid key length {} bytes, expected {} bytes", encryption_key_.size(), static_cast(KEY_SIZE))); - } -} - -void Aes256EcbCipher::handleOpenSSLError(const char* msg) { - std::array errmsg = {0}; - const auto errcode = ERR_peek_last_error(); - if (!errcode) { - handleError(fmt::format("{}: {}", msg, "Unknown OpenSSL error")); - } - ERR_error_string_n(errcode, errmsg.data(), errmsg.size()); - handleError(fmt::format("{}: {}", msg, errmsg.data())); -} - -Bytes Aes256EcbCipher::generateKey() { - return utils::crypto::randomBytes(KEY_SIZE); -} - -void Aes256EcbCipher::encrypt(std::span data) const { - gsl_Expects(data.size() == BLOCK_SIZE); - EVP_CIPHER_CTX_ptr ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free); - if (!ctx) { - handleOpenSSLError("Could not create cipher context"); - } - - if (1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_256_ecb(), nullptr, reinterpret_cast(encryption_key_.data()), nullptr)) { - handleOpenSSLError("Could not initialize encryption cipher context"); - } - - // EVP_EncryptFinal_ex pads the data even if there is none thus data that - // is exactly BLOCK_SIZE long would result in 2*BLOCK_SIZE ciphertext - if (1 != EVP_CIPHER_CTX_set_padding(ctx.get(), 0)) { - handleOpenSSLError("Could not disable padding for cipher"); - } - - int ciphertext_len = 0; - int len = 0; - - if (1 != EVP_EncryptUpdate(ctx.get(), data.data(), &len, data.data(), gsl::narrow(data.size()))) { - handleOpenSSLError("Could not update cipher content"); - } - ciphertext_len += len; - - if (1 != EVP_EncryptFinal_ex(ctx.get(), data.data() + len, &len)) { - handleOpenSSLError("Could not finalize encryption"); - } - ciphertext_len += len; - - gsl_Expects(ciphertext_len == BLOCK_SIZE); -} - -void Aes256EcbCipher::decrypt(std::span data) const { - gsl_Expects(data.size() == BLOCK_SIZE); - EVP_CIPHER_CTX_ptr ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free); - if (!ctx) { - handleOpenSSLError("Could not create cipher context"); - } - - if (1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_ecb(), nullptr, reinterpret_cast(encryption_key_.data()), nullptr)) { - handleOpenSSLError("Could not initialize decryption cipher context"); - } - - // as we did not use padding during encryption - if (1 != EVP_CIPHER_CTX_set_padding(ctx.get(), 0)) { - handleOpenSSLError("Could not disable padding for cipher"); - } - - int plaintext_len = 0; - int len = 0; - - if (1 != EVP_DecryptUpdate(ctx.get(), data.data(), &len, data.data(), gsl::narrow(data.size()))) { - handleOpenSSLError("Could not update cipher content"); - } - plaintext_len += len; - - if (1 != EVP_DecryptFinal_ex(ctx.get(), data.data() + len, &len)) { - handleOpenSSLError("Could not finalize decryption"); - } - plaintext_len += len; - - gsl_Expects(plaintext_len == BLOCK_SIZE); -} - -bool Aes256EcbCipher::operator==(const Aes256EcbCipher &other) const { - gsl_Expects(encryption_key_.size() == KEY_SIZE); - if (encryption_key_.size() != other.encryption_key_.size()) return false; - return CRYPTO_memcmp(encryption_key_.data(), other.encryption_key_.data(), KEY_SIZE) == 0; -} - -} // namespace org::apache::nifi::minifi::utils::crypto diff --git a/libminifi/src/utils/crypto/property_encryption/PropertyEncryptionUtils.cpp b/libminifi/src/utils/crypto/property_encryption/PropertyEncryptionUtils.cpp deleted file mode 100644 index 7f9cbdb74f..0000000000 --- a/libminifi/src/utils/crypto/property_encryption/PropertyEncryptionUtils.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "utils/crypto/property_encryption/PropertyEncryptionUtils.h" -#include "utils/StringUtils.h" - -namespace org::apache::nifi::minifi::utils::crypto::property_encryption { - -namespace { -inline constexpr std::string_view WrapperBegin = "enc{"; -inline constexpr std::string_view WrapperEnd = "}"; - -bool isEncrypted(std::string_view value) { - return (value.starts_with(WrapperBegin) && value.ends_with(WrapperEnd)); -} -} // namespace - -std::string decrypt(std::string_view input, const utils::crypto::EncryptionProvider& encryption_provider) { - if (!isEncrypted(input)) { - // this is normal: sensitive properties come from the C2 server in cleartext over TLS - return std::string{input}; - } - auto unwrapped_input = input.substr(WrapperBegin.size(), input.length() - (WrapperBegin.size() + WrapperEnd.size())); - return encryption_provider.decrypt(unwrapped_input); -} - -std::string encrypt(std::string_view input, const utils::crypto::EncryptionProvider& encryption_provider) { - if (isEncrypted(input)) { - return std::string{input}; - } - return utils::string::join_pack("enc{", encryption_provider.encrypt(input), "}"); -} - -} // namespace org::apache::nifi::minifi::utils::crypto::property_encryption diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index bce5b3712d..138aaec3e8 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -5,10 +5,13 @@ file(GLOB SOURCES src/io/*.cpp src/http/*.cpp src/utils/*.cpp + src/utils/crypto/*.cpp + src/utils/crypto/ciphers/*.cpp + src/utils/crypto/property_encryption/*.cpp src/utils/net/*.cpp src/utils/file/*.cpp) -add_library(minifi-utils STATIC ${SOURCES}) +add_minifi_library(minifi-utils STATIC ${SOURCES}) target_include_directories(minifi-utils PUBLIC include) #target_link_libraries(minifi-utils PUBLIC minifi-core magic_enum gsl-lite range-v3 expected-lite spdlog) target_link_libraries(minifi-utils PUBLIC minifi-core ZLIB::ZLIB concurrentqueue RapidJSON spdlog Threads::Threads gsl-lite libsodium range-v3 expected-lite date::date date::tz asio magic_enum OpenSSL::Crypto OpenSSL::SSL CURL::libcurl RapidJSON) diff --git a/extension-utils/include/utils/crypto/EncryptionManager.h b/utils/include/utils/crypto/EncryptionManager.h similarity index 100% rename from extension-utils/include/utils/crypto/EncryptionManager.h rename to utils/include/utils/crypto/EncryptionManager.h diff --git a/extension-utils/include/utils/crypto/EncryptionProvider.h b/utils/include/utils/crypto/EncryptionProvider.h similarity index 100% rename from extension-utils/include/utils/crypto/EncryptionProvider.h rename to utils/include/utils/crypto/EncryptionProvider.h diff --git a/extension-utils/include/utils/crypto/EncryptionUtils.h b/utils/include/utils/crypto/EncryptionUtils.h similarity index 100% rename from extension-utils/include/utils/crypto/EncryptionUtils.h rename to utils/include/utils/crypto/EncryptionUtils.h diff --git a/extension-utils/include/utils/crypto/ciphers/Aes256Ecb.h b/utils/include/utils/crypto/ciphers/Aes256Ecb.h similarity index 100% rename from extension-utils/include/utils/crypto/ciphers/Aes256Ecb.h rename to utils/include/utils/crypto/ciphers/Aes256Ecb.h diff --git a/extension-utils/include/utils/crypto/ciphers/XSalsa20.h b/utils/include/utils/crypto/ciphers/XSalsa20.h similarity index 100% rename from extension-utils/include/utils/crypto/ciphers/XSalsa20.h rename to utils/include/utils/crypto/ciphers/XSalsa20.h diff --git a/extension-utils/include/utils/crypto/property_encryption/PropertyEncryptionUtils.h b/utils/include/utils/crypto/property_encryption/PropertyEncryptionUtils.h similarity index 100% rename from extension-utils/include/utils/crypto/property_encryption/PropertyEncryptionUtils.h rename to utils/include/utils/crypto/property_encryption/PropertyEncryptionUtils.h diff --git a/extension-utils/src/utils/crypto/EncryptionManager.cpp b/utils/src/utils/crypto/EncryptionManager.cpp similarity index 97% rename from extension-utils/src/utils/crypto/EncryptionManager.cpp rename to utils/src/utils/crypto/EncryptionManager.cpp index 205c407dc0..3cedac44c2 100644 --- a/extension-utils/src/utils/crypto/EncryptionManager.cpp +++ b/utils/src/utils/crypto/EncryptionManager.cpp @@ -19,7 +19,7 @@ #include #include "utils/crypto/EncryptionManager.h" -#include "properties/Properties.h" +#include "minifi-cpp/properties/Properties.h" #include "utils/StringUtils.h" namespace org::apache::nifi::minifi::utils::crypto { diff --git a/extension-utils/src/utils/crypto/EncryptionProvider.cpp b/utils/src/utils/crypto/EncryptionProvider.cpp similarity index 100% rename from extension-utils/src/utils/crypto/EncryptionProvider.cpp rename to utils/src/utils/crypto/EncryptionProvider.cpp diff --git a/extension-utils/src/utils/crypto/EncryptionUtils.cpp b/utils/src/utils/crypto/EncryptionUtils.cpp similarity index 100% rename from extension-utils/src/utils/crypto/EncryptionUtils.cpp rename to utils/src/utils/crypto/EncryptionUtils.cpp diff --git a/extension-utils/src/utils/crypto/ciphers/Aes256Ecb.cpp b/utils/src/utils/crypto/ciphers/Aes256Ecb.cpp similarity index 100% rename from extension-utils/src/utils/crypto/ciphers/Aes256Ecb.cpp rename to utils/src/utils/crypto/ciphers/Aes256Ecb.cpp diff --git a/extension-utils/src/utils/crypto/property_encryption/PropertyEncryptionUtils.cpp b/utils/src/utils/crypto/property_encryption/PropertyEncryptionUtils.cpp similarity index 100% rename from extension-utils/src/utils/crypto/property_encryption/PropertyEncryptionUtils.cpp rename to utils/src/utils/crypto/property_encryption/PropertyEncryptionUtils.cpp