#pragma once #include #include #include namespace cipher { namespace crypt { /** * @enum Confidentiality Algorithms * * The Confidentiality Algorithm Number specifies the encryption/decryption * algorithm field that is used for encrypted payload data under the session. * The ‘encrypted’ bit in the payload type field being set identifies packets * with payloads that include data that is encrypted per this specification. * When payload data is encrypted, there may be additional “Confidentiality * Header” and/or “Confidentiality Trailer” fields that are included within the * payload. The size and definition of those fields is specific to the * particular confidentiality algorithm. Based on security recommendations * encrypting IPMI traffic is preferred, so NONE is not supported. */ enum class Algorithms : uint8_t { NONE, /**< No encryption (mandatory , not supported) */ AES_CBC_128, /**< AES-CBC-128 Algorithm (mandatory option) */ xRC4_128, /**< xRC4-128 Algorithm (optional option) */ xRC4_40, /**< xRC4-40 Algorithm (optional option) */ }; /** * @class Interface * * Interface is the base class for the Confidentiality Algorithms. */ class Interface { public: /** * @brief Constructor for Interface */ explicit Interface(const std::vector& k2) : k2(k2) { } Interface() = delete; virtual ~Interface() = default; Interface(const Interface&) = default; Interface& operator=(const Interface&) = default; Interface(Interface&&) = default; Interface& operator=(Interface&&) = default; /** * @brief Decrypt the incoming payload * * @param[in] packet - Incoming IPMI packet * @param[in] sessHeaderLen - Length of the IPMI Session Header * @param[in] payloadLen - Length of the encrypted IPMI payload * * @return decrypted payload if the operation is successful */ virtual std::vector decryptPayload(const std::vector& packet, const size_t sessHeaderLen, const size_t payloadLen) const = 0; /** * @brief Encrypt the outgoing payload * * @param[in] payload - plain payload for the outgoing IPMI packet * * @return encrypted payload if the operation is successful * */ virtual std::vector encryptPayload(std::vector& payload) const = 0; /** * @brief Check if the Confidentiality algorithm is supported * * @param[in] algo - confidentiality algorithm * * @return true if algorithm is supported else false * */ static bool isAlgorithmSupported(Algorithms algo) { if (algo == Algorithms::AES_CBC_128) { return true; } else { return false; } } protected: /** * @brief The Cipher Key is the first 128-bits of key “K2”, K2 is * generated by processing a pre-defined constant keyed by Session * Integrity Key (SIK) that was created during session activation. */ std::vector k2; }; /** * @class AlgoAES128 * * @brief Implementation of the AES-CBC-128 Confidentiality algorithm * * AES-128 uses a 128-bit Cipher Key. The Cipher Key is the first 128-bits of * key “K2”.Once the Cipher Key has been generated it is used to encrypt * the payload data. The payload data is padded to make it an integral numbers * of blocks in length (a block is 16 bytes for AES). The payload is then * encrypted one block at a time from the lowest data offset to the highest * using Cipher_Key as specified in AES. */ class AlgoAES128 final : public Interface { public: static constexpr size_t AESCBC128ConfHeader = 16; static constexpr size_t AESCBC128BlockSize = 16; /** * If confidentiality bytes are present, the value of the first byte is * one (01h). and all subsequent bytes shall have a monotonically * increasing value (e.g., 02h, 03h, 04h, etc). The receiver, as an * additional check for proper decryption, shall check the value of each * byte of Confidentiality Pad. For AES algorithm, the pad bytes will * range from 0 to 15 bytes. This predefined array would help in * doing the additional check. */ static constexpr std::array confPadBytes = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; /** * @brief Constructor for AlgoAES128 * * @param[in] - Session Integrity key */ explicit AlgoAES128(const std::vector& k2) : Interface(k2) { } AlgoAES128() = delete; ~AlgoAES128() = default; AlgoAES128(const AlgoAES128&) = default; AlgoAES128& operator=(const AlgoAES128&) = default; AlgoAES128(AlgoAES128&&) = default; AlgoAES128& operator=(AlgoAES128&&) = default; /** * @brief Decrypt the incoming payload * * @param[in] packet - Incoming IPMI packet * @param[in] sessHeaderLen - Length of the IPMI Session Header * @param[in] payloadLen - Length of the encrypted IPMI payload * * @return decrypted payload if the operation is successful */ std::vector decryptPayload(const std::vector& packet, const size_t sessHeaderLen, const size_t payloadLen) const override; /** * @brief Encrypt the outgoing payload * * @param[in] payload - plain payload for the outgoing IPMI packet * * @return encrypted payload if the operation is successful * */ std::vector encryptPayload(std::vector& payload) const override; private: /** * @brief Decrypt the passed data * * @param[in] iv - Initialization vector * @param[in] input - Pointer to input data * @param[in] inputLen - Length of input data * * @return decrypted data if the operation is successful */ std::vector decryptData(const uint8_t* iv, const uint8_t* input, const int inputLen) const; /** * @brief Encrypt the passed data * * @param[in] input - Pointer to input data * @param[in] inputLen - Length of input data * * @return encrypted data if the operation is successful */ std::vector encryptData(const uint8_t* input, const int inputLen) const; }; } // namespace crypt } // namespace cipher