blob: d1e39403c55044cfe3641212f18a4beb0256c242 [file] [log] [blame]
Tom Josephd08b5232017-01-24 18:15:39 +05301#pragma once
2
3#include <openssl/sha.h>
4#include <array>
5#include <vector>
6
7namespace cipher
8{
9
10namespace crypt
11{
12
13using buffer = std::vector<uint8_t>;
14using 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 */
28enum 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 */
41class 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 Joseph2f0bd0e2017-01-24 18:24:27 +053083 /**
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 Josephd08b5232017-01-24 18:15:39 +0530103 protected:
104
Tom Joseph54690652017-02-16 20:25:23 +0530105 /**
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 Josephd08b5232017-01-24 18:15:39 +0530110 key k2;
111};
112
Tom Joseph06f7a3c2017-01-25 14:32:05 +0530113/**
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 */
125class 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 Josephd08b5232017-01-24 18:15:39 +0530229}// namespace crypt
230
231}// namespace cipher
232