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 */ Interface(const std::vector<uint8_t> & k2)46 explicit Interface(const std::vector<uint8_t>& k2) : k2(k2) {} 47 48 Interface() = delete; 49 virtual ~Interface() = default; 50 Interface(const Interface&) = default; 51 Interface& operator=(const Interface&) = default; 52 Interface(Interface&&) = default; 53 Interface& operator=(Interface&&) = default; 54 55 /** 56 * @brief Decrypt the incoming payload 57 * 58 * @param[in] packet - Incoming IPMI packet 59 * @param[in] sessHeaderLen - Length of the IPMI Session Header 60 * @param[in] payloadLen - Length of the encrypted IPMI payload 61 * 62 * @return decrypted payload if the operation is successful 63 */ 64 virtual std::vector<uint8_t> decryptPayload( 65 const std::vector<uint8_t>& packet, const size_t sessHeaderLen, 66 const size_t payloadLen) const = 0; 67 68 /** 69 * @brief Encrypt the outgoing payload 70 * 71 * @param[in] payload - plain payload for the outgoing IPMI packet 72 * 73 * @return encrypted payload if the operation is successful 74 * 75 */ 76 virtual std::vector<uint8_t> 77 encryptPayload(std::vector<uint8_t>& payload) const = 0; 78 79 /** 80 * @brief Check if the Confidentiality algorithm is supported 81 * 82 * @param[in] algo - confidentiality algorithm 83 * 84 * @return true if algorithm is supported else false 85 * 86 */ isAlgorithmSupported(Algorithms algo)87 static bool isAlgorithmSupported(Algorithms algo) 88 { 89 if (algo == Algorithms::AES_CBC_128) 90 { 91 return true; 92 } 93 else 94 { 95 return false; 96 } 97 } 98 99 protected: 100 /** 101 * @brief The Cipher Key is the first 128-bits of key “K2”, K2 is 102 * generated by processing a pre-defined constant keyed by Session 103 * Integrity Key (SIK) that was created during session activation. 104 */ 105 std::vector<uint8_t> k2; 106 }; 107 108 /** 109 * @class AlgoAES128 110 * 111 * @brief Implementation of the AES-CBC-128 Confidentiality algorithm 112 * 113 * AES-128 uses a 128-bit Cipher Key. The Cipher Key is the first 128-bits of 114 * key “K2”.Once the Cipher Key has been generated it is used to encrypt 115 * the payload data. The payload data is padded to make it an integral numbers 116 * of blocks in length (a block is 16 bytes for AES). The payload is then 117 * encrypted one block at a time from the lowest data offset to the highest 118 * using Cipher_Key as specified in AES. 119 */ 120 class AlgoAES128 final : public Interface 121 { 122 public: 123 static constexpr size_t AESCBC128ConfHeader = 16; 124 static constexpr size_t AESCBC128BlockSize = 16; 125 126 /** 127 * If confidentiality bytes are present, the value of the first byte is 128 * one (01h). and all subsequent bytes shall have a monotonically 129 * increasing value (e.g., 02h, 03h, 04h, etc). The receiver, as an 130 * additional check for proper decryption, shall check the value of each 131 * byte of Confidentiality Pad. For AES algorithm, the pad bytes will 132 * range from 0 to 15 bytes. This predefined array would help in 133 * doing the additional check. 134 */ 135 static constexpr std::array<uint8_t, AESCBC128BlockSize - 1> confPadBytes = 136 {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 137 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; 138 139 /** 140 * @brief Constructor for AlgoAES128 141 * 142 * @param[in] - Session Integrity key 143 */ AlgoAES128(const std::vector<uint8_t> & k2)144 explicit AlgoAES128(const std::vector<uint8_t>& k2) : Interface(k2) {} 145 146 AlgoAES128() = delete; 147 ~AlgoAES128() = default; 148 AlgoAES128(const AlgoAES128&) = default; 149 AlgoAES128& operator=(const AlgoAES128&) = default; 150 AlgoAES128(AlgoAES128&&) = default; 151 AlgoAES128& operator=(AlgoAES128&&) = default; 152 153 /** 154 * @brief Decrypt the incoming payload 155 * 156 * @param[in] packet - Incoming IPMI packet 157 * @param[in] sessHeaderLen - Length of the IPMI Session Header 158 * @param[in] payloadLen - Length of the encrypted IPMI payload 159 * 160 * @return decrypted payload if the operation is successful 161 */ 162 std::vector<uint8_t> decryptPayload(const std::vector<uint8_t>& packet, 163 const size_t sessHeaderLen, 164 const size_t payloadLen) const override; 165 166 /** 167 * @brief Encrypt the outgoing payload 168 * 169 * @param[in] payload - plain payload for the outgoing IPMI packet 170 * 171 * @return encrypted payload if the operation is successful 172 * 173 */ 174 std::vector<uint8_t> 175 encryptPayload(std::vector<uint8_t>& payload) const override; 176 177 private: 178 /** 179 * @brief Decrypt the passed data 180 * 181 * @param[in] iv - Initialization vector 182 * @param[in] input - Pointer to input data 183 * @param[in] inputLen - Length of input data 184 * 185 * @return decrypted data if the operation is successful 186 */ 187 std::vector<uint8_t> decryptData(const uint8_t* iv, const uint8_t* input, 188 const int inputLen) const; 189 190 /** 191 * @brief Encrypt the passed data 192 * 193 * @param[in] input - Pointer to input data 194 * @param[in] inputLen - Length of input data 195 * 196 * @return encrypted data if the operation is successful 197 */ 198 std::vector<uint8_t> encryptData(const uint8_t* input, 199 const int inputLen) const; 200 }; 201 202 } // namespace crypt 203 204 } // namespace cipher 205