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