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