1 #pragma once 2 3 #include <array> 4 #include <cstddef> 5 #include <cstdint> 6 #include <vector> 7 8 namespace cipher 9 { 10 11 namespace crypt 12 { 13 14 /** 15 * @enum Confidentiality Algorithms 16 * 17 * The Confidentiality Algorithm Number specifies the encryption/decryption 18 * algorithm field that is used for encrypted payload data under the session. 19 * The ‘encrypted’ bit in the payload type field being set identifies packets 20 * with payloads that include data that is encrypted per this specification. 21 * When payload data is encrypted, there may be additional “Confidentiality 22 * Header” and/or “Confidentiality Trailer” fields that are included within the 23 * payload. The size and definition of those fields is specific to the 24 * particular confidentiality algorithm. Based on security recommendations 25 * encrypting IPMI traffic is preferred, so NONE is not supported. 26 */ 27 enum class Algorithms : uint8_t 28 { 29 NONE, /**< No encryption (mandatory , not supported) */ 30 AES_CBC_128, /**< AES-CBC-128 Algorithm (mandatory option) */ 31 xRC4_128, /**< xRC4-128 Algorithm (optional option) */ 32 xRC4_40, /**< xRC4-40 Algorithm (optional option) */ 33 }; 34 35 /** 36 * @class Interface 37 * 38 * Interface is the base class for the Confidentiality Algorithms. 39 */ 40 class Interface 41 { 42 public: 43 /** 44 * @brief Constructor for Interface 45 */ 46 explicit Interface(const std::vector<uint8_t>& k2) : k2(k2) 47 { 48 } 49 50 Interface() = delete; 51 virtual ~Interface() = default; 52 Interface(const Interface&) = default; 53 Interface& operator=(const Interface&) = default; 54 Interface(Interface&&) = default; 55 Interface& operator=(Interface&&) = default; 56 57 /** 58 * @brief Decrypt the incoming payload 59 * 60 * @param[in] packet - Incoming IPMI packet 61 * @param[in] sessHeaderLen - Length of the IPMI Session Header 62 * @param[in] payloadLen - Length of the encrypted IPMI payload 63 * 64 * @return decrypted payload if the operation is successful 65 */ 66 virtual std::vector<uint8_t> 67 decryptPayload(const std::vector<uint8_t>& packet, 68 const size_t sessHeaderLen, 69 const size_t payloadLen) const = 0; 70 71 /** 72 * @brief Encrypt the outgoing payload 73 * 74 * @param[in] payload - plain payload for the outgoing IPMI packet 75 * 76 * @return encrypted payload if the operation is successful 77 * 78 */ 79 virtual std::vector<uint8_t> 80 encryptPayload(std::vector<uint8_t>& payload) const = 0; 81 82 /** 83 * @brief Check if the Confidentiality algorithm is supported 84 * 85 * @param[in] algo - confidentiality algorithm 86 * 87 * @return true if algorithm is supported else false 88 * 89 */ 90 static bool isAlgorithmSupported(Algorithms algo) 91 { 92 if (algo == Algorithms::AES_CBC_128) 93 { 94 return true; 95 } 96 else 97 { 98 return false; 99 } 100 } 101 102 protected: 103 /** 104 * @brief The Cipher Key is the first 128-bits of key “K2”, K2 is 105 * generated by processing a pre-defined constant keyed by Session 106 * Integrity Key (SIK) that was created during session activation. 107 */ 108 std::vector<uint8_t> k2; 109 }; 110 111 /** 112 * @class AlgoAES128 113 * 114 * @brief Implementation of the AES-CBC-128 Confidentiality algorithm 115 * 116 * AES-128 uses a 128-bit Cipher Key. The Cipher Key is the first 128-bits of 117 * key “K2”.Once the Cipher Key has been generated it is used to encrypt 118 * the payload data. The payload data is padded to make it an integral numbers 119 * of blocks in length (a block is 16 bytes for AES). The payload is then 120 * encrypted one block at a time from the lowest data offset to the highest 121 * using Cipher_Key as specified in AES. 122 */ 123 class AlgoAES128 final : public Interface 124 { 125 public: 126 static constexpr size_t AESCBC128ConfHeader = 16; 127 static constexpr size_t AESCBC128BlockSize = 16; 128 129 /** 130 * If confidentiality bytes are present, the value of the first byte is 131 * one (01h). and all subsequent bytes shall have a monotonically 132 * increasing value (e.g., 02h, 03h, 04h, etc). The receiver, as an 133 * additional check for proper decryption, shall check the value of each 134 * byte of Confidentiality Pad. For AES algorithm, the pad bytes will 135 * range from 0 to 15 bytes. This predefined array would help in 136 * doing the additional check. 137 */ 138 static constexpr std::array<uint8_t, AESCBC128BlockSize - 1> confPadBytes = 139 {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 140 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; 141 142 /** 143 * @brief Constructor for AlgoAES128 144 * 145 * @param[in] - Session Integrity key 146 */ 147 explicit AlgoAES128(const std::vector<uint8_t>& k2) : Interface(k2) 148 { 149 } 150 151 AlgoAES128() = delete; 152 ~AlgoAES128() = default; 153 AlgoAES128(const AlgoAES128&) = default; 154 AlgoAES128& operator=(const AlgoAES128&) = default; 155 AlgoAES128(AlgoAES128&&) = default; 156 AlgoAES128& operator=(AlgoAES128&&) = default; 157 158 /** 159 * @brief Decrypt the incoming payload 160 * 161 * @param[in] packet - Incoming IPMI packet 162 * @param[in] sessHeaderLen - Length of the IPMI Session Header 163 * @param[in] payloadLen - Length of the encrypted IPMI payload 164 * 165 * @return decrypted payload if the operation is successful 166 */ 167 std::vector<uint8_t> decryptPayload(const std::vector<uint8_t>& packet, 168 const size_t sessHeaderLen, 169 const size_t payloadLen) const override; 170 171 /** 172 * @brief Encrypt the outgoing payload 173 * 174 * @param[in] payload - plain payload for the outgoing IPMI packet 175 * 176 * @return encrypted payload if the operation is successful 177 * 178 */ 179 std::vector<uint8_t> 180 encryptPayload(std::vector<uint8_t>& payload) const override; 181 182 private: 183 /** 184 * @brief Decrypt the passed data 185 * 186 * @param[in] iv - Initialization vector 187 * @param[in] input - Pointer to input data 188 * @param[in] inputLen - Length of input data 189 * 190 * @return decrypted data if the operation is successful 191 */ 192 std::vector<uint8_t> decryptData(const uint8_t* iv, const uint8_t* input, 193 const int inputLen) const; 194 195 /** 196 * @brief Encrypt the passed data 197 * 198 * @param[in] input - Pointer to input data 199 * @param[in] inputLen - Length of input data 200 * 201 * @return encrypted data if the operation is successful 202 */ 203 std::vector<uint8_t> encryptData(const uint8_t* input, 204 const int inputLen) const; 205 }; 206 207 } // namespace crypt 208 209 } // namespace cipher 210