blob: 90ba26a10c33cb1346595c7362186d4b9e14d1f6 [file] [log] [blame]
Tom Josephd08b5232017-01-24 18:15:39 +05301#include <openssl/evp.h>
2#include <openssl/hmac.h>
3#include <openssl/rand.h>
Tom Joseph518ecce2017-01-25 14:34:19 +05304#include <algorithm>
Tom Josephd08b5232017-01-24 18:15:39 +05305#include <numeric>
6#include "crypt_algo.hpp"
7#include "message_parsers.hpp"
8
9namespace cipher
10{
11
12namespace crypt
13{
14
Tom Joseph518ecce2017-01-25 14:34:19 +053015constexpr std::array<uint8_t, AlgoAES128::AESCBC128BlockSize - 1>
16 AlgoAES128::confPadBytes;
17
Vernon Mauery70fd29c2017-11-30 13:11:43 -080018std::vector<uint8_t> AlgoAES128::decryptPayload(
19 const std::vector<uint8_t>& packet,
20 const size_t sessHeaderLen,
21 const size_t payloadLen) const
Tom Joseph518ecce2017-01-25 14:34:19 +053022{
23 auto plainPayload = decryptData(
24 packet.data() + sessHeaderLen,
25 packet.data() + sessHeaderLen + AESCBC128ConfHeader,
26 payloadLen - AESCBC128ConfHeader);
27
28 /*
29 * The confidentiality pad length is the last byte in the payload, it would
30 * tell the number of pad bytes in the payload. We added a condition, so
Gunnar Mills62ec6222018-04-08 16:28:23 -050031 * that buffer overrun doesn't happen.
Tom Joseph518ecce2017-01-25 14:34:19 +053032 */
33 size_t confPadLength = plainPayload.back();
34 auto padLength = std::min(plainPayload.size() -1, confPadLength);
35
36 auto plainPayloadLen = plainPayload.size() - padLength - 1;
37
38 // Additional check if the confidentiality pad bytes are as expected
39 if(!std::equal(plainPayload.begin() + plainPayloadLen,
40 plainPayload.begin() + plainPayloadLen + padLength,
41 confPadBytes.begin()))
42 {
43 throw std::runtime_error("Confidentiality pad bytes check failed");
44 }
45
46 plainPayload.resize(plainPayloadLen);
47
48 return plainPayload;
49}
50
Vernon Mauery70fd29c2017-11-30 13:11:43 -080051std::vector<uint8_t> AlgoAES128::encryptPayload(
52 std::vector<uint8_t>& payload) const
Tom Joseph518ecce2017-01-25 14:34:19 +053053{
54 auto payloadLen = payload.size();
55
56 /*
57 * The following logic calculates the number of padding bytes to be added to
58 * the payload data. This would ensure that the length is a multiple of the
59 * block size of algorithm being used. For the AES algorithm, the block size
60 * is 16 bytes.
61 */
62 auto paddingLen = AESCBC128BlockSize - ((payloadLen + 1) & 0xF);
63
64 /*
65 * The additional field is for the Confidentiality Pad Length field. For the
66 * AES algorithm, this number will range from 0 to 15 bytes. This field is
67 * mandatory.
68 */
69 payload.resize(payloadLen + paddingLen + 1);
70
71 /*
72 * If no Confidentiality Pad bytes are required, the Confidentiality Pad
73 * Length field is set to 00h. If present, the value of the first byte of
74 * Confidentiality Pad shall be one (01h) and all subsequent bytes shall
75 * have a monotonically increasing value (e.g., 02h, 03h, 04h, etc).
76 */
77 if (0 != paddingLen)
78 {
79 std::iota(payload.begin() + payloadLen,
80 payload.begin() + payloadLen + paddingLen,
81 1);
82 }
83
84 payload.back() = paddingLen;
85
86 return encryptData(payload.data(), payload.size());
87}
88
Vernon Mauery70fd29c2017-11-30 13:11:43 -080089std::vector<uint8_t> AlgoAES128::decryptData(const uint8_t* iv,
Tom Joseph518ecce2017-01-25 14:34:19 +053090 const uint8_t* input,
91 const int inputLen) const
92{
Tom Joseph518ecce2017-01-25 14:34:19 +053093 // Initializes Cipher context
Adriana Kobylak584fa882018-09-06 15:52:05 -050094 EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
Tom Joseph518ecce2017-01-25 14:34:19 +053095
Tom Josephf6c97e12017-08-03 00:23:57 +053096 auto cleanupFunc = [](EVP_CIPHER_CTX* ctx)
97 {
Adriana Kobylak584fa882018-09-06 15:52:05 -050098 EVP_CIPHER_CTX_free(ctx);
Tom Josephf6c97e12017-08-03 00:23:57 +053099 };
100
101 std::unique_ptr<EVP_CIPHER_CTX, decltype(cleanupFunc)>
Adriana Kobylak584fa882018-09-06 15:52:05 -0500102 ctxPtr(ctx, cleanupFunc);
Tom Josephf6c97e12017-08-03 00:23:57 +0530103
Tom Joseph518ecce2017-01-25 14:34:19 +0530104 /*
105 * EVP_DecryptInit_ex sets up cipher context ctx for encryption with type
106 * AES-CBC-128. ctx must be initialized before calling this function. K2 is
107 * the symmetric key used and iv is the initialization vector used.
108 */
Tom Josephf6c97e12017-08-03 00:23:57 +0530109 if (!EVP_DecryptInit_ex(ctxPtr.get(), EVP_aes_128_cbc(), NULL, k2.data(),
110 iv))
Tom Joseph518ecce2017-01-25 14:34:19 +0530111 {
Tom Joseph518ecce2017-01-25 14:34:19 +0530112 throw std::runtime_error("EVP_DecryptInit_ex failed for type "
113 "AES-CBC-128");
114 }
115
116 /*
117 * EVP_CIPHER_CTX_set_padding() enables or disables padding. If the pad
118 * parameter is zero then no padding is performed. This function always
119 * returns 1.
120 */
Tom Josephf6c97e12017-08-03 00:23:57 +0530121 EVP_CIPHER_CTX_set_padding(ctxPtr.get(), 0);
Tom Joseph518ecce2017-01-25 14:34:19 +0530122
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800123 std::vector<uint8_t> output(inputLen + AESCBC128BlockSize);
Tom Joseph518ecce2017-01-25 14:34:19 +0530124
125 int outputLen = 0;
126
127 /*
128 * If padding is disabled then EVP_DecryptFinal_ex() will not encrypt any
129 * more data and it will return an error if any data remains in a partial
130 * block: that is if the total data length is not a multiple of the block
131 * size. Since AES-CBC-128 encrypted payload format adds padding bytes and
132 * ensures that payload is a multiple of block size, we are not making the
133 * call to EVP_DecryptFinal_ex().
134 */
Tom Josephf6c97e12017-08-03 00:23:57 +0530135 if (!EVP_DecryptUpdate(ctxPtr.get(), output.data(), &outputLen, input,
136 inputLen))
Tom Joseph518ecce2017-01-25 14:34:19 +0530137 {
Tom Joseph518ecce2017-01-25 14:34:19 +0530138 throw std::runtime_error("EVP_DecryptUpdate failed");
139 }
140
141 output.resize(outputLen);
Tom Joseph518ecce2017-01-25 14:34:19 +0530142
143 return output;
144}
145
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800146std::vector<uint8_t> AlgoAES128::encryptData(const uint8_t* input,
147 const int inputLen) const
Tom Joseph518ecce2017-01-25 14:34:19 +0530148{
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800149 std::vector<uint8_t> output(inputLen + AESCBC128BlockSize);
Tom Joseph518ecce2017-01-25 14:34:19 +0530150
151 // Generate the initialization vector
152 if (!RAND_bytes(output.data(), AESCBC128ConfHeader))
153 {
154 throw std::runtime_error("RAND_bytes failed");
155 }
156
Tom Joseph518ecce2017-01-25 14:34:19 +0530157 // Initializes Cipher context
Adriana Kobylak584fa882018-09-06 15:52:05 -0500158 EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
Tom Joseph518ecce2017-01-25 14:34:19 +0530159
Tom Josephf6c97e12017-08-03 00:23:57 +0530160 auto cleanupFunc = [](EVP_CIPHER_CTX* ctx)
161 {
Adriana Kobylak584fa882018-09-06 15:52:05 -0500162 EVP_CIPHER_CTX_free(ctx);
Tom Josephf6c97e12017-08-03 00:23:57 +0530163 };
164
165 std::unique_ptr<EVP_CIPHER_CTX, decltype(cleanupFunc)>
Adriana Kobylak584fa882018-09-06 15:52:05 -0500166 ctxPtr(ctx, cleanupFunc);
Tom Josephf6c97e12017-08-03 00:23:57 +0530167
Tom Joseph518ecce2017-01-25 14:34:19 +0530168 /*
169 * EVP_EncryptInit_ex sets up cipher context ctx for encryption with type
170 * AES-CBC-128. ctx must be initialized before calling this function. K2 is
171 * the symmetric key used and iv is the initialization vector used.
172 */
Tom Josephf6c97e12017-08-03 00:23:57 +0530173 if (!EVP_EncryptInit_ex(ctxPtr.get(), EVP_aes_128_cbc(), NULL, k2.data(),
Tom Joseph518ecce2017-01-25 14:34:19 +0530174 output.data()))
175 {
Tom Joseph518ecce2017-01-25 14:34:19 +0530176 throw std::runtime_error("EVP_EncryptInit_ex failed for type "
177 "AES-CBC-128");
178 }
179
180 /*
181 * EVP_CIPHER_CTX_set_padding() enables or disables padding. If the pad
182 * parameter is zero then no padding is performed. This function always
183 * returns 1.
184 */
Tom Josephf6c97e12017-08-03 00:23:57 +0530185 EVP_CIPHER_CTX_set_padding(ctxPtr.get(), 0);
Tom Joseph518ecce2017-01-25 14:34:19 +0530186
187 int outputLen = 0;
188
189 /*
190 * If padding is disabled then EVP_EncryptFinal_ex() will not encrypt any
191 * more data and it will return an error if any data remains in a partial
192 * block: that is if the total data length is not a multiple of the block
193 * size. Since we are adding padding bytes and ensures that payload is a
194 * multiple of block size, we are not making the call to
195 * EVP_DecryptFinal_ex()
196 */
Tom Josephf6c97e12017-08-03 00:23:57 +0530197 if (!EVP_EncryptUpdate(ctxPtr.get(),
Tom Joseph518ecce2017-01-25 14:34:19 +0530198 output.data() + AESCBC128ConfHeader,
199 &outputLen,
200 input, inputLen))
201 {
Tom Joseph518ecce2017-01-25 14:34:19 +0530202 throw std::runtime_error("EVP_EncryptUpdate failed for type "
203 "AES-CBC-128");
204 }
205
206 output.resize(AESCBC128ConfHeader + outputLen);
Tom Joseph518ecce2017-01-25 14:34:19 +0530207
208 return output;
209}
210
Tom Josephd08b5232017-01-24 18:15:39 +0530211}// namespace crypt
212
213}// namespace cipher
214
215