blob: f10c8a0fee380841cbd4664b6878ca8992e9f0ee [file] [log] [blame]
Tom Joseph1e5a76a2017-01-30 19:25:06 +05301#include <openssl/evp.h>
2#include <openssl/hmac.h>
3#include <openssl/rand.h>
4#include <openssl/sha.h>
5#include <iostream>
6#include <vector>
7#include "crypt_algo.hpp"
8#include "integrity_algo.hpp"
9#include "message_parsers.hpp"
10#include <gtest/gtest.h>
11
12TEST(IntegrityAlgo, HMAC_SHA1_96_GenerateIntegrityDataCheck)
13{
14 /*
15 * Step-1 Generate Integrity Data for the packet, using the implemented API
16 */
17 // Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
18 std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
19
20 // Hardcoded Session Integrity Key
21 std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
22 13, 14, 15, 16};
23
24 auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA1>(sik);
25
26 ASSERT_EQ(true, (algoPtr != NULL));
27
28 // Generate the Integrity Data
29 auto response = algoPtr->generateIntegrityData(packet);
30
31 EXPECT_EQ(true, (response.size() ==
32 cipher::integrity::AlgoSHA1::SHA1_96_AUTHCODE_LENGTH));
33
34 /*
35 * Step-2 Generate Integrity data using OpenSSL SHA1 algorithm
36 */
37 cipher::integrity::Key K1;
38 constexpr cipher::integrity::Key const1 = { 0x01, 0x01, 0x01, 0x01, 0x01,
39 0x01, 0x01, 0x01, 0x01, 0x01,
40 0x01, 0x01, 0x01, 0x01, 0x01,
41 0x01, 0x01, 0x01, 0x01, 0x01
42 };
43
44 // Generated K1 for the integrity algorithm with the additional key keyed
45 // with SIK.
46 unsigned int mdLen = 0;
47 if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
48 const1.size(), K1.data(), &mdLen) == NULL)
49 {
50 FAIL() << "Generating Key1 failed";
51 }
52
53 mdLen = 0;
Vernon Mauery70fd29c2017-11-30 13:11:43 -080054 std::vector<uint8_t> output(SHA_DIGEST_LENGTH);
Tom Joseph1e5a76a2017-01-30 19:25:06 +053055 size_t length = packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE;
56
57 if (HMAC(EVP_sha1(), K1.data(), K1.size(),
58 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
59 length,
60 output.data(), &mdLen) == NULL)
61 {
62 FAIL() << "Generating integrity data failed";
63 }
64
65 output.resize(cipher::integrity::AlgoSHA1::SHA1_96_AUTHCODE_LENGTH);
66
67 /*
68 * Step-3 Check if the integrity data we generated using the implemented API
69 * matches with one generated by OpenSSL SHA1 algorithm.
70 */
71 auto check = std::equal(output.begin(), output.end(), response.begin());
72 EXPECT_EQ(true, check);
73}
74
75TEST(IntegrityAlgo, HMAC_SHA1_96_VerifyIntegrityDataPass)
76{
77 /*
78 * Step-1 Generate Integrity data using OpenSSL SHA1 algorithm
79 */
80
81 // Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
82 std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
83
84 // Hardcoded Session Integrity Key
85 std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
86 13, 14, 15, 16};
87
88 cipher::integrity::Key K1;
89 constexpr cipher::integrity::Key const1 = { 0x01, 0x01, 0x01, 0x01, 0x01,
90 0x01, 0x01, 0x01, 0x01, 0x01,
91 0x01, 0x01, 0x01, 0x01, 0x01,
92 0x01, 0x01, 0x01, 0x01, 0x01
93 };
94
95 // Generated K1 for the integrity algorithm with the additional key keyed
96 // with SIK.
97 unsigned int mdLen = 0;
98 if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
99 const1.size(), K1.data(), &mdLen) == NULL)
100 {
101 FAIL() << "Generating Key1 failed";
102 }
103
104 mdLen = 0;
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800105 std::vector<uint8_t> output(SHA_DIGEST_LENGTH);
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530106 size_t length = packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE;
107
108 if (HMAC(EVP_sha1(), K1.data(), K1.size(),
109 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
110 length,
111 output.data(), &mdLen) == NULL)
112 {
113 FAIL() << "Generating integrity data failed";
114 }
115
116 output.resize(cipher::integrity::AlgoSHA1::SHA1_96_AUTHCODE_LENGTH);
117
118 /*
119 * Step-2 Insert the integrity data into the packet
120 */
121 auto packetSize = packet.size();
122 packet.insert(packet.end(), output.begin(), output.end());
123
124 // Point to the integrity data in the packet
125 auto integrityIter = packet.cbegin();
126 std::advance(integrityIter, packetSize);
127
128 /*
129 * Step-3 Invoke the verifyIntegrityData API and validate the response
130 */
131
132 auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA1>(sik);
133 ASSERT_EQ(true, (algoPtr != NULL));
134
135 auto check = algoPtr->verifyIntegrityData(
136 packet,
137 packetSize - message::parser::RMCP_SESSION_HEADER_SIZE,
138 integrityIter);
139
140 EXPECT_EQ(true, check);
141}
142
143TEST(IntegrityAlgo, HMAC_SHA1_96_VerifyIntegrityDataFail)
144{
145 /*
146 * Step-1 Add hardcoded Integrity data to the packet
147 */
148
149 // Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
150 std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
151
152 std::vector<uint8_t> integrity = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
153
154 packet.insert(packet.end(), integrity.begin(), integrity.end());
155
156 // Point to the integrity data in the packet
157 auto integrityIter = packet.cbegin();
158 std::advance(integrityIter, packet.size());
159
160 /*
161 * Step-2 Invoke the verifyIntegrityData API and validate the response
162 */
163
164 // Hardcoded Session Integrity Key
165 std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
166 13, 14, 15, 16};
167
168 auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA1>(sik);
169
170 ASSERT_EQ(true, (algoPtr != NULL));
171
172
173 // Verify the Integrity Data
174 auto check = algoPtr->verifyIntegrityData(
175 packet,
176 packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE,
177 integrityIter);
178
179 EXPECT_EQ(false, check);
180}
181
182TEST(CryptAlgo, AES_CBC_128_EncryptPayloadValidate)
183{
184 /*
185 * Step-1 Generate the encrypted data using the implemented API for
186 * AES-CBC-128
187 */
188 std::vector<uint8_t> payload = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
189
190 // Hardcoded Session Integrity Key
191 std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
192 13, 14, 15, 16};
193
194 auto cryptPtr = std::make_unique<cipher::crypt::AlgoAES128>(sik);
195
196 ASSERT_EQ(true, (cryptPtr != NULL));
197
198 auto cipher = cryptPtr->encryptPayload(payload);
199
200 /*
201 * Step-2 Decrypt the encrypted payload using OpenSSL EVP_aes_128_cbc()
202 * implementation
203 */
204
205 EVP_CIPHER_CTX ctx;
206 EVP_CIPHER_CTX_init(&ctx);
207 cipher::crypt::key k2;
208 unsigned int mdLen = 0;
209 constexpr cipher::crypt::key const1 = { 0x02, 0x02, 0x02, 0x02, 0x02,
210 0x02, 0x02, 0x02, 0x02, 0x02,
211 0x02, 0x02, 0x02, 0x02, 0x02,
212 0x02, 0x02, 0x02, 0x02, 0x02
213 };
214
215 // Generated K2 for the confidentiality algorithm with the additional key
216 // keyed with SIK.
217 if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
218 const1.size(), k2.data(), &mdLen) == NULL)
219 {
220 FAIL() << "Generating K2 for confidentiality algorithm failed";
221 }
222
223 if (!EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, k2.data(),
224 cipher.data()))
225 {
226 EVP_CIPHER_CTX_cleanup(&ctx);
227 FAIL() << "EVP_DecryptInit_ex failed for type AES-CBC-128";
228 }
229
230 EVP_CIPHER_CTX_set_padding(&ctx, 0);
231 std::vector<uint8_t> output(
232 cipher.size() + cipher::crypt::AlgoAES128::AESCBC128BlockSize);
233 int outputLen = 0;
234
235 if (!EVP_DecryptUpdate(&ctx, output.data(), &outputLen,
236 cipher.data() +
237 cipher::crypt::AlgoAES128::AESCBC128ConfHeader,
238 cipher.size() -
239 cipher::crypt::AlgoAES128::AESCBC128ConfHeader))
240 {
241 EVP_CIPHER_CTX_cleanup(&ctx);
242 FAIL() << "EVP_DecryptUpdate failed";
243 }
244
245 output.resize(outputLen);
246 EVP_CIPHER_CTX_cleanup(&ctx);
247
248 /*
249 * Step -3 Check if the plain payload matches with the decrypted one
250 */
251 auto check = std::equal(payload.begin(), payload.end(), output.begin());
252 EXPECT_EQ(true, check);
253}
254
255TEST(CryptAlgo, AES_CBC_128_DecryptPayloadValidate)
256{
257 /*
258 * Step-1 Encrypt the payload using OpenSSL EVP_aes_128_cbc()
259 * implementation
260 */
261
262 std::vector<uint8_t> payload = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
263 13, 14, 15, 16};
264 payload.resize(payload.size() + 1);
265 payload.back() = 0;
266
267 // Hardcoded Session Integrity Key
268 std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
269 13, 14, 15, 16};
270 EVP_CIPHER_CTX ctx;
271 EVP_CIPHER_CTX_init(&ctx);
272 cipher::crypt::key k2;
273 unsigned int mdLen = 0;
274 constexpr cipher::crypt::key const1 = { 0x02, 0x02, 0x02, 0x02, 0x02,
275 0x02, 0x02, 0x02, 0x02, 0x02,
276 0x02, 0x02, 0x02, 0x02, 0x02,
277 0x02, 0x02, 0x02, 0x02, 0x02
278 };
279 std::vector<uint8_t> output(
280 payload.size() + cipher::crypt::AlgoAES128::AESCBC128BlockSize);
281
282 if (!RAND_bytes(output.data(),
283 cipher::crypt::AlgoAES128::AESCBC128ConfHeader))
284 {
285 FAIL() << "RAND_bytes failed";
286 }
287
288 // Generated K2 for the confidentiality algorithm with the additional key
289 // keyed with SIK.
290 if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
291 const1.size(), k2.data(), &mdLen) == NULL)
292 {
293 FAIL() << "Generating K2 for confidentiality algorithm failed";
294 }
295
296 if (!EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, k2.data(),
297 output.data()))
298 {
299 EVP_CIPHER_CTX_cleanup(&ctx);
300 FAIL() << "EVP_EncryptInit_ex failed for type AES-CBC-128";
301 }
302
303 EVP_CIPHER_CTX_set_padding(&ctx, 0);
304 int outputLen = 0;
305
306 if (!EVP_EncryptUpdate(&ctx,
307 output.data() +
308 cipher::crypt::AlgoAES128::AESCBC128ConfHeader,
309 &outputLen,
310 payload.data(),
311 payload.size()))
312 {
313 EVP_CIPHER_CTX_cleanup(&ctx);
314 FAIL() << "EVP_EncryptUpdate failed";
315 }
316
317 output.resize(cipher::crypt::AlgoAES128::AESCBC128ConfHeader + outputLen);
318 EVP_CIPHER_CTX_cleanup(&ctx);
319
320 /*
321 * Step-2 Decrypt the encrypted payload using the implemented API for
322 * AES-CBC-128
323 */
324
325 auto cryptPtr = std::make_unique<cipher::crypt::AlgoAES128>(sik);
326
327 ASSERT_EQ(true, (cryptPtr != NULL));
328
329 auto plain = cryptPtr->decryptPayload(output, 0, output.size());
330
331 /*
332 * Step -3 Check if the plain payload matches with the decrypted one
333 */
334 auto check = std::equal(payload.begin(), payload.end(), plain.begin());
335 EXPECT_EQ(true, check);
336}