blob: ed8ccb70ce226f79603dc876a34487d7bba3ae67 [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
183TEST(CryptAlgo, AES_CBC_128_EncryptPayloadValidate)
184{
185 /*
186 * Step-1 Generate the encrypted data using the implemented API for
187 * AES-CBC-128
188 */
189 std::vector<uint8_t> payload = { 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,
Vernon Mauery9b307be2017-11-22 09:28:16 -0800193 13, 14, 15, 16, 17, 18, 19, 20 };
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530194
Vernon Mauery9b307be2017-11-22 09:28:16 -0800195 std::vector<uint8_t> k2(SHA_DIGEST_LENGTH);
196 unsigned int mdLen = 0;
197 constexpr rmcp::Const_n const1 = { 0x02, 0x02, 0x02, 0x02, 0x02,
198 0x02, 0x02, 0x02, 0x02, 0x02,
199 0x02, 0x02, 0x02, 0x02, 0x02,
200 0x02, 0x02, 0x02, 0x02, 0x02
201 };
202
203 // Generated K2 for the confidentiality algorithm with the additional key
204 // keyed with SIK.
205 if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
206 const1.size(), k2.data(), &mdLen) == NULL)
207 {
208 FAIL() << "Generating K2 for confidentiality algorithm failed";
209 }
210
211 auto cryptPtr = std::make_unique<cipher::crypt::AlgoAES128>(k2);
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530212
213 ASSERT_EQ(true, (cryptPtr != NULL));
214
215 auto cipher = cryptPtr->encryptPayload(payload);
216
217 /*
218 * Step-2 Decrypt the encrypted payload using OpenSSL EVP_aes_128_cbc()
219 * implementation
220 */
221
222 EVP_CIPHER_CTX ctx;
223 EVP_CIPHER_CTX_init(&ctx);
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530224 if (!EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, k2.data(),
225 cipher.data()))
226 {
227 EVP_CIPHER_CTX_cleanup(&ctx);
228 FAIL() << "EVP_DecryptInit_ex failed for type AES-CBC-128";
229 }
230
231 EVP_CIPHER_CTX_set_padding(&ctx, 0);
232 std::vector<uint8_t> output(
233 cipher.size() + cipher::crypt::AlgoAES128::AESCBC128BlockSize);
234 int outputLen = 0;
235
236 if (!EVP_DecryptUpdate(&ctx, output.data(), &outputLen,
237 cipher.data() +
238 cipher::crypt::AlgoAES128::AESCBC128ConfHeader,
239 cipher.size() -
240 cipher::crypt::AlgoAES128::AESCBC128ConfHeader))
241 {
242 EVP_CIPHER_CTX_cleanup(&ctx);
243 FAIL() << "EVP_DecryptUpdate failed";
244 }
245
246 output.resize(outputLen);
247 EVP_CIPHER_CTX_cleanup(&ctx);
248
249 /*
250 * Step -3 Check if the plain payload matches with the decrypted one
251 */
252 auto check = std::equal(payload.begin(), payload.end(), output.begin());
253 EXPECT_EQ(true, check);
254}
255
256TEST(CryptAlgo, AES_CBC_128_DecryptPayloadValidate)
257{
258 /*
259 * Step-1 Encrypt the payload using OpenSSL EVP_aes_128_cbc()
260 * implementation
261 */
262
263 std::vector<uint8_t> payload = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
264 13, 14, 15, 16};
265 payload.resize(payload.size() + 1);
266 payload.back() = 0;
267
268 // Hardcoded Session Integrity Key
269 std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
Vernon Mauery9b307be2017-11-22 09:28:16 -0800270 13, 14, 15, 16, 17, 18, 19, 20 };
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530271 EVP_CIPHER_CTX ctx;
272 EVP_CIPHER_CTX_init(&ctx);
Vernon Mauery9b307be2017-11-22 09:28:16 -0800273 std::vector<uint8_t> k2(SHA_DIGEST_LENGTH);
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530274 unsigned int mdLen = 0;
Vernon Mauery9b307be2017-11-22 09:28:16 -0800275 constexpr rmcp::Const_n const1 = { 0x02, 0x02, 0x02, 0x02, 0x02,
276 0x02, 0x02, 0x02, 0x02, 0x02,
277 0x02, 0x02, 0x02, 0x02, 0x02,
278 0x02, 0x02, 0x02, 0x02, 0x02
279 };
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530280 std::vector<uint8_t> output(
281 payload.size() + cipher::crypt::AlgoAES128::AESCBC128BlockSize);
282
283 if (!RAND_bytes(output.data(),
284 cipher::crypt::AlgoAES128::AESCBC128ConfHeader))
285 {
286 FAIL() << "RAND_bytes failed";
287 }
288
289 // Generated K2 for the confidentiality algorithm with the additional key
290 // keyed with SIK.
291 if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
292 const1.size(), k2.data(), &mdLen) == NULL)
293 {
294 FAIL() << "Generating K2 for confidentiality algorithm failed";
295 }
296
297 if (!EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, k2.data(),
298 output.data()))
299 {
300 EVP_CIPHER_CTX_cleanup(&ctx);
301 FAIL() << "EVP_EncryptInit_ex failed for type AES-CBC-128";
302 }
303
304 EVP_CIPHER_CTX_set_padding(&ctx, 0);
305 int outputLen = 0;
306
307 if (!EVP_EncryptUpdate(&ctx,
308 output.data() +
309 cipher::crypt::AlgoAES128::AESCBC128ConfHeader,
310 &outputLen,
311 payload.data(),
312 payload.size()))
313 {
314 EVP_CIPHER_CTX_cleanup(&ctx);
315 FAIL() << "EVP_EncryptUpdate failed";
316 }
317
318 output.resize(cipher::crypt::AlgoAES128::AESCBC128ConfHeader + outputLen);
319 EVP_CIPHER_CTX_cleanup(&ctx);
320
321 /*
322 * Step-2 Decrypt the encrypted payload using the implemented API for
323 * AES-CBC-128
324 */
325
Vernon Mauery9b307be2017-11-22 09:28:16 -0800326 auto cryptPtr = std::make_unique<cipher::crypt::AlgoAES128>(k2);
Tom Joseph1e5a76a2017-01-30 19:25:06 +0530327
328 ASSERT_EQ(true, (cryptPtr != NULL));
329
330 auto plain = cryptPtr->decryptPayload(output, 0, output.size());
331
332 /*
333 * Step -3 Check if the plain payload matches with the decrypted one
334 */
335 auto check = std::equal(payload.begin(), payload.end(), plain.begin());
336 EXPECT_EQ(true, check);
337}