blob: 3fa985c50f6951fc8418dc67f3b1f47bc530bbca [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"
Vernon Mauery9b307be2017-11-22 09:28:16 -080010#include "rmcp.hpp"
Tom Joseph1e5a76a2017-01-30 19:25:06 +053011#include <gtest/gtest.h>
12
13TEST(IntegrityAlgo, HMAC_SHA1_96_GenerateIntegrityDataCheck)
14{
15 /*
16 * Step-1 Generate Integrity Data for the packet, using the implemented API
17 */
18 // Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
19 std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
20
21 // Hardcoded Session Integrity Key
22 std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
Vernon Mauery9b307be2017-11-22 09:28:16 -080023 13, 14, 15, 16, 17, 18, 19, 20 };
Tom Joseph1e5a76a2017-01-30 19:25:06 +053024
25 auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA1>(sik);
26
27 ASSERT_EQ(true, (algoPtr != NULL));
28
29 // Generate the Integrity Data
30 auto response = algoPtr->generateIntegrityData(packet);
31
32 EXPECT_EQ(true, (response.size() ==
33 cipher::integrity::AlgoSHA1::SHA1_96_AUTHCODE_LENGTH));
34
35 /*
36 * Step-2 Generate Integrity data using OpenSSL SHA1 algorithm
37 */
Vernon Mauery9b307be2017-11-22 09:28:16 -080038 std::vector<uint8_t> k1(SHA_DIGEST_LENGTH);
39 constexpr rmcp::Const_n const1 = { 0x01, 0x01, 0x01, 0x01, 0x01,
40 0x01, 0x01, 0x01, 0x01, 0x01,
41 0x01, 0x01, 0x01, 0x01, 0x01,
42 0x01, 0x01, 0x01, 0x01, 0x01
43 };
Tom Joseph1e5a76a2017-01-30 19:25:06 +053044
45 // Generated K1 for the integrity algorithm with the additional key keyed
46 // with SIK.
47 unsigned int mdLen = 0;
48 if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
Vernon Mauery9b307be2017-11-22 09:28:16 -080049 const1.size(), k1.data(), &mdLen) == NULL)
Tom Joseph1e5a76a2017-01-30 19:25:06 +053050 {
51 FAIL() << "Generating Key1 failed";
52 }
53
54 mdLen = 0;
Vernon Mauery70fd29c2017-11-30 13:11:43 -080055 std::vector<uint8_t> output(SHA_DIGEST_LENGTH);
Tom Joseph1e5a76a2017-01-30 19:25:06 +053056 size_t length = packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE;
57
Vernon Mauery9b307be2017-11-22 09:28:16 -080058 if (HMAC(EVP_sha1(), k1.data(), k1.size(),
Tom Joseph1e5a76a2017-01-30 19:25:06 +053059 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
60 length,
61 output.data(), &mdLen) == NULL)
62 {
63 FAIL() << "Generating integrity data failed";
64 }
65
66 output.resize(cipher::integrity::AlgoSHA1::SHA1_96_AUTHCODE_LENGTH);
67
68 /*
69 * Step-3 Check if the integrity data we generated using the implemented API
70 * matches with one generated by OpenSSL SHA1 algorithm.
71 */
72 auto check = std::equal(output.begin(), output.end(), response.begin());
73 EXPECT_EQ(true, check);
74}
75
76TEST(IntegrityAlgo, HMAC_SHA1_96_VerifyIntegrityDataPass)
77{
78 /*
79 * Step-1 Generate Integrity data using OpenSSL SHA1 algorithm
80 */
81
82 // Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
83 std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
84
85 // Hardcoded Session Integrity Key
86 std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
Vernon Mauery9b307be2017-11-22 09:28:16 -080087 13, 14, 15, 16, 17, 18, 19, 20 };
Tom Joseph1e5a76a2017-01-30 19:25:06 +053088
Vernon Mauery9b307be2017-11-22 09:28:16 -080089 std::vector<uint8_t> k1(SHA_DIGEST_LENGTH);
90 constexpr rmcp::Const_n const1 = { 0x01, 0x01, 0x01, 0x01, 0x01,
91 0x01, 0x01, 0x01, 0x01, 0x01,
92 0x01, 0x01, 0x01, 0x01, 0x01,
93 0x01, 0x01, 0x01, 0x01, 0x01
94 };
Tom Joseph1e5a76a2017-01-30 19:25:06 +053095
96 // Generated K1 for the integrity algorithm with the additional key keyed
97 // with SIK.
98 unsigned int mdLen = 0;
99 if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
Vernon Mauery9b307be2017-11-22 09:28:16 -0800100 const1.size(), k1.data(), &mdLen) == NULL)
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530101 {
102 FAIL() << "Generating Key1 failed";
103 }
104
105 mdLen = 0;
Vernon Mauery70fd29c2017-11-30 13:11:43 -0800106 std::vector<uint8_t> output(SHA_DIGEST_LENGTH);
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530107 size_t length = packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE;
108
Vernon Mauery9b307be2017-11-22 09:28:16 -0800109 if (HMAC(EVP_sha1(), k1.data(), k1.size(),
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530110 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
111 length,
112 output.data(), &mdLen) == NULL)
113 {
114 FAIL() << "Generating integrity data failed";
115 }
116
117 output.resize(cipher::integrity::AlgoSHA1::SHA1_96_AUTHCODE_LENGTH);
118
119 /*
120 * Step-2 Insert the integrity data into the packet
121 */
122 auto packetSize = packet.size();
123 packet.insert(packet.end(), output.begin(), output.end());
124
125 // Point to the integrity data in the packet
126 auto integrityIter = packet.cbegin();
127 std::advance(integrityIter, packetSize);
128
129 /*
130 * Step-3 Invoke the verifyIntegrityData API and validate the response
131 */
132
133 auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA1>(sik);
134 ASSERT_EQ(true, (algoPtr != NULL));
135
136 auto check = algoPtr->verifyIntegrityData(
137 packet,
138 packetSize - message::parser::RMCP_SESSION_HEADER_SIZE,
139 integrityIter);
140
141 EXPECT_EQ(true, check);
142}
143
144TEST(IntegrityAlgo, HMAC_SHA1_96_VerifyIntegrityDataFail)
145{
146 /*
147 * Step-1 Add hardcoded Integrity data to the packet
148 */
149
150 // Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
151 std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
152
153 std::vector<uint8_t> integrity = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
154
155 packet.insert(packet.end(), integrity.begin(), integrity.end());
156
157 // Point to the integrity data in the packet
158 auto integrityIter = packet.cbegin();
159 std::advance(integrityIter, packet.size());
160
161 /*
162 * Step-2 Invoke the verifyIntegrityData API and validate the response
163 */
164
165 // Hardcoded Session Integrity Key
166 std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
Vernon Mauery9b307be2017-11-22 09:28:16 -0800167 13, 14, 15, 16, 17, 18, 19, 20 };
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530168
169 auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA1>(sik);
170
171 ASSERT_EQ(true, (algoPtr != NULL));
172
173
174 // Verify the Integrity Data
175 auto check = algoPtr->verifyIntegrityData(
176 packet,
177 packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE,
178 integrityIter);
179
180 EXPECT_EQ(false, check);
181}
182
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800183TEST(IntegrityAlgo, HMAC_SHA256_128_GenerateIntegrityDataCheck)
184{
185 /*
186 * Step-1 Generate Integrity Data for the packet, using the implemented API
187 */
188 // Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
189 std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
190
191 // Hardcoded Session Integrity Key
192 std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
193 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
194 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 };
195
196 auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA256>(sik);
197
198 ASSERT_EQ(true, (algoPtr != NULL));
199
200 // Generate the Integrity Data
201 auto response = algoPtr->generateIntegrityData(packet);
202
203 EXPECT_EQ(true, (response.size() ==
204 cipher::integrity::AlgoSHA256::SHA256_128_AUTHCODE_LENGTH));
205
206 /*
207 * Step-2 Generate Integrity data using OpenSSL SHA256 algorithm
208 */
209 std::vector<uint8_t> k1(SHA256_DIGEST_LENGTH);
210 constexpr rmcp::Const_n const1 = { 0x01, 0x01, 0x01, 0x01, 0x01,
211 0x01, 0x01, 0x01, 0x01, 0x01,
212 0x01, 0x01, 0x01, 0x01, 0x01,
213 0x01, 0x01, 0x01, 0x01, 0x01
214 };
215
216 // Generated K1 for the integrity algorithm with the additional key keyed
217 // with SIK.
218 unsigned int mdLen = 0;
219 if (HMAC(EVP_sha256(), sik.data(), sik.size(), const1.data(),
220 const1.size(), k1.data(), &mdLen) == NULL)
221 {
222 FAIL() << "Generating Key1 failed";
223 }
224
225 mdLen = 0;
226 std::vector<uint8_t> output(SHA256_DIGEST_LENGTH);
227 size_t length = packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE;
228
229 if (HMAC(EVP_sha256(), k1.data(), k1.size(),
230 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
231 length,
232 output.data(), &mdLen) == NULL)
233 {
234 FAIL() << "Generating integrity data failed";
235 }
236
237 output.resize(cipher::integrity::AlgoSHA256::SHA256_128_AUTHCODE_LENGTH);
238
239 /*
240 * Step-3 Check if the integrity data we generated using the implemented API
241 * matches with one generated by OpenSSL SHA256 algorithm.
242 */
243 auto check = std::equal(output.begin(), output.end(), response.begin());
244 EXPECT_EQ(true, check);
245}
246
247TEST(IntegrityAlgo, HMAC_SHA256_128_VerifyIntegrityDataPass)
248{
249 /*
250 * Step-1 Generate Integrity data using OpenSSL SHA256 algorithm
251 */
252
253 // Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
254 std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
255
256 // Hardcoded Session Integrity Key
257 std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
258 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
259 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 };
260
261 std::vector<uint8_t> k1(SHA256_DIGEST_LENGTH);
262 constexpr rmcp::Const_n const1 = { 0x01, 0x01, 0x01, 0x01, 0x01,
263 0x01, 0x01, 0x01, 0x01, 0x01,
264 0x01, 0x01, 0x01, 0x01, 0x01,
265 0x01, 0x01, 0x01, 0x01, 0x01
266 };
267
268 // Generated K1 for the integrity algorithm with the additional key keyed
269 // with SIK.
270 unsigned int mdLen = 0;
271 if (HMAC(EVP_sha256(), sik.data(), sik.size(), const1.data(),
272 const1.size(), k1.data(), &mdLen) == NULL)
273 {
274 FAIL() << "Generating Key1 failed";
275 }
276
277 mdLen = 0;
278 std::vector<uint8_t> output(SHA256_DIGEST_LENGTH);
279 size_t length = packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE;
280
281 if (HMAC(EVP_sha256(), k1.data(), k1.size(),
282 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
283 length,
284 output.data(), &mdLen) == NULL)
285 {
286 FAIL() << "Generating integrity data failed";
287 }
288
289 output.resize(cipher::integrity::AlgoSHA256::SHA256_128_AUTHCODE_LENGTH);
290
291 /*
292 * Step-2 Insert the integrity data into the packet
293 */
294 auto packetSize = packet.size();
295 packet.insert(packet.end(), output.begin(), output.end());
296
297 // Point to the integrity data in the packet
298 auto integrityIter = packet.cbegin();
299 std::advance(integrityIter, packetSize);
300
301 /*
302 * Step-3 Invoke the verifyIntegrityData API and validate the response
303 */
304
305 auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA256>(sik);
306 ASSERT_EQ(true, (algoPtr != NULL));
307
308 auto check = algoPtr->verifyIntegrityData(
309 packet,
310 packetSize - message::parser::RMCP_SESSION_HEADER_SIZE,
311 integrityIter);
312
313 EXPECT_EQ(true, check);
314}
315
316TEST(IntegrityAlgo, HMAC_SHA256_128_VerifyIntegrityDataFail)
317{
318 /*
319 * Step-1 Add hardcoded Integrity data to the packet
320 */
321
322 // Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
323 std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
324
325 std::vector<uint8_t> integrity = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
326
327 packet.insert(packet.end(), integrity.begin(), integrity.end());
328
329 // Point to the integrity data in the packet
330 auto integrityIter = packet.cbegin();
331 std::advance(integrityIter, packet.size());
332
333 /*
334 * Step-2 Invoke the verifyIntegrityData API and validate the response
335 */
336
337 // Hardcoded Session Integrity Key
338 std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
339 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
340 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 };
341
342 auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA256>(sik);
343
344 ASSERT_EQ(true, (algoPtr != NULL));
345
346
347 // Verify the Integrity Data
348 auto check = algoPtr->verifyIntegrityData(
349 packet,
350 packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE,
351 integrityIter);
352
353 EXPECT_EQ(false, check);
354}
355
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530356TEST(CryptAlgo, AES_CBC_128_EncryptPayloadValidate)
357{
358 /*
359 * Step-1 Generate the encrypted data using the implemented API for
360 * AES-CBC-128
361 */
362 std::vector<uint8_t> payload = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
363
364 // Hardcoded Session Integrity Key
365 std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
Vernon Mauery9b307be2017-11-22 09:28:16 -0800366 13, 14, 15, 16, 17, 18, 19, 20 };
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530367
Vernon Mauery9b307be2017-11-22 09:28:16 -0800368 std::vector<uint8_t> k2(SHA_DIGEST_LENGTH);
369 unsigned int mdLen = 0;
370 constexpr rmcp::Const_n const1 = { 0x02, 0x02, 0x02, 0x02, 0x02,
371 0x02, 0x02, 0x02, 0x02, 0x02,
372 0x02, 0x02, 0x02, 0x02, 0x02,
373 0x02, 0x02, 0x02, 0x02, 0x02
374 };
375
376 // Generated K2 for the confidentiality algorithm with the additional key
377 // keyed with SIK.
378 if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
379 const1.size(), k2.data(), &mdLen) == NULL)
380 {
381 FAIL() << "Generating K2 for confidentiality algorithm failed";
382 }
383
384 auto cryptPtr = std::make_unique<cipher::crypt::AlgoAES128>(k2);
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530385
386 ASSERT_EQ(true, (cryptPtr != NULL));
387
388 auto cipher = cryptPtr->encryptPayload(payload);
389
390 /*
391 * Step-2 Decrypt the encrypted payload using OpenSSL EVP_aes_128_cbc()
392 * implementation
393 */
394
395 EVP_CIPHER_CTX ctx;
396 EVP_CIPHER_CTX_init(&ctx);
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530397 if (!EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, k2.data(),
398 cipher.data()))
399 {
400 EVP_CIPHER_CTX_cleanup(&ctx);
401 FAIL() << "EVP_DecryptInit_ex failed for type AES-CBC-128";
402 }
403
404 EVP_CIPHER_CTX_set_padding(&ctx, 0);
405 std::vector<uint8_t> output(
406 cipher.size() + cipher::crypt::AlgoAES128::AESCBC128BlockSize);
407 int outputLen = 0;
408
409 if (!EVP_DecryptUpdate(&ctx, output.data(), &outputLen,
410 cipher.data() +
411 cipher::crypt::AlgoAES128::AESCBC128ConfHeader,
412 cipher.size() -
413 cipher::crypt::AlgoAES128::AESCBC128ConfHeader))
414 {
415 EVP_CIPHER_CTX_cleanup(&ctx);
416 FAIL() << "EVP_DecryptUpdate failed";
417 }
418
419 output.resize(outputLen);
420 EVP_CIPHER_CTX_cleanup(&ctx);
421
422 /*
423 * Step -3 Check if the plain payload matches with the decrypted one
424 */
425 auto check = std::equal(payload.begin(), payload.end(), output.begin());
426 EXPECT_EQ(true, check);
427}
428
429TEST(CryptAlgo, AES_CBC_128_DecryptPayloadValidate)
430{
431 /*
432 * Step-1 Encrypt the payload using OpenSSL EVP_aes_128_cbc()
433 * implementation
434 */
435
436 std::vector<uint8_t> payload = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
437 13, 14, 15, 16};
438 payload.resize(payload.size() + 1);
439 payload.back() = 0;
440
441 // Hardcoded Session Integrity Key
442 std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
Vernon Mauery9b307be2017-11-22 09:28:16 -0800443 13, 14, 15, 16, 17, 18, 19, 20 };
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530444 EVP_CIPHER_CTX ctx;
445 EVP_CIPHER_CTX_init(&ctx);
Vernon Mauery9b307be2017-11-22 09:28:16 -0800446 std::vector<uint8_t> k2(SHA_DIGEST_LENGTH);
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530447 unsigned int mdLen = 0;
Vernon Mauery9b307be2017-11-22 09:28:16 -0800448 constexpr rmcp::Const_n const1 = { 0x02, 0x02, 0x02, 0x02, 0x02,
449 0x02, 0x02, 0x02, 0x02, 0x02,
450 0x02, 0x02, 0x02, 0x02, 0x02,
451 0x02, 0x02, 0x02, 0x02, 0x02
452 };
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530453 std::vector<uint8_t> output(
454 payload.size() + cipher::crypt::AlgoAES128::AESCBC128BlockSize);
455
456 if (!RAND_bytes(output.data(),
457 cipher::crypt::AlgoAES128::AESCBC128ConfHeader))
458 {
459 FAIL() << "RAND_bytes failed";
460 }
461
462 // Generated K2 for the confidentiality algorithm with the additional key
463 // keyed with SIK.
464 if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
465 const1.size(), k2.data(), &mdLen) == NULL)
466 {
467 FAIL() << "Generating K2 for confidentiality algorithm failed";
468 }
469
470 if (!EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, k2.data(),
471 output.data()))
472 {
473 EVP_CIPHER_CTX_cleanup(&ctx);
474 FAIL() << "EVP_EncryptInit_ex failed for type AES-CBC-128";
475 }
476
477 EVP_CIPHER_CTX_set_padding(&ctx, 0);
478 int outputLen = 0;
479
480 if (!EVP_EncryptUpdate(&ctx,
481 output.data() +
482 cipher::crypt::AlgoAES128::AESCBC128ConfHeader,
483 &outputLen,
484 payload.data(),
485 payload.size()))
486 {
487 EVP_CIPHER_CTX_cleanup(&ctx);
488 FAIL() << "EVP_EncryptUpdate failed";
489 }
490
491 output.resize(cipher::crypt::AlgoAES128::AESCBC128ConfHeader + outputLen);
492 EVP_CIPHER_CTX_cleanup(&ctx);
493
494 /*
495 * Step-2 Decrypt the encrypted payload using the implemented API for
496 * AES-CBC-128
497 */
498
Vernon Mauery9b307be2017-11-22 09:28:16 -0800499 auto cryptPtr = std::make_unique<cipher::crypt::AlgoAES128>(k2);
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530500
501 ASSERT_EQ(true, (cryptPtr != NULL));
502
503 auto plain = cryptPtr->decryptPayload(output, 0, output.size());
504
505 /*
506 * Step -3 Check if the plain payload matches with the decrypted one
507 */
508 auto check = std::equal(payload.begin(), payload.end(), plain.begin());
509 EXPECT_EQ(true, check);
510}