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