| Tom Joseph | d08b523 | 2017-01-24 18:15:39 +0530 | [diff] [blame] | 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 |  | 
| Tom Joseph | 2f0bd0e | 2017-01-24 18:24:27 +0530 | [diff] [blame] | 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 |  | 
| Tom Joseph | d08b523 | 2017-01-24 18:15:39 +0530 | [diff] [blame] | 103 | protected: | 
|  | 104 |  | 
| Tom Joseph | 5469065 | 2017-02-16 20:25:23 +0530 | [diff] [blame] | 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 | */ | 
| Tom Joseph | d08b523 | 2017-01-24 18:15:39 +0530 | [diff] [blame] | 110 | key k2; | 
|  | 111 | }; | 
|  | 112 |  | 
| Tom Joseph | 06f7a3c | 2017-01-25 14:32:05 +0530 | [diff] [blame] | 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 |  | 
| Tom Joseph | d08b523 | 2017-01-24 18:15:39 +0530 | [diff] [blame] | 229 | }// namespace crypt | 
|  | 230 |  | 
|  | 231 | }// namespace cipher | 
|  | 232 |  |