blob: 432612e7d85a997f8f14ea54421595bb78cbcd19 [file] [log] [blame]
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <iostream>
#include <vector>
#include "crypt_algo.hpp"
#include "integrity_algo.hpp"
#include "message_parsers.hpp"
#include "rmcp.hpp"
#include <gtest/gtest.h>
TEST(IntegrityAlgo, HMAC_SHA1_96_GenerateIntegrityDataCheck)
{
/*
* Step-1 Generate Integrity Data for the packet, using the implemented API
*/
// Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
// Hardcoded Session Integrity Key
std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20 };
auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA1>(sik);
ASSERT_EQ(true, (algoPtr != NULL));
// Generate the Integrity Data
auto response = algoPtr->generateIntegrityData(packet);
EXPECT_EQ(true, (response.size() ==
cipher::integrity::AlgoSHA1::SHA1_96_AUTHCODE_LENGTH));
/*
* Step-2 Generate Integrity data using OpenSSL SHA1 algorithm
*/
std::vector<uint8_t> k1(SHA_DIGEST_LENGTH);
constexpr rmcp::Const_n const1 = { 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01
};
// Generated K1 for the integrity algorithm with the additional key keyed
// with SIK.
unsigned int mdLen = 0;
if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
const1.size(), k1.data(), &mdLen) == NULL)
{
FAIL() << "Generating Key1 failed";
}
mdLen = 0;
std::vector<uint8_t> output(SHA_DIGEST_LENGTH);
size_t length = packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE;
if (HMAC(EVP_sha1(), k1.data(), k1.size(),
packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
length,
output.data(), &mdLen) == NULL)
{
FAIL() << "Generating integrity data failed";
}
output.resize(cipher::integrity::AlgoSHA1::SHA1_96_AUTHCODE_LENGTH);
/*
* Step-3 Check if the integrity data we generated using the implemented API
* matches with one generated by OpenSSL SHA1 algorithm.
*/
auto check = std::equal(output.begin(), output.end(), response.begin());
EXPECT_EQ(true, check);
}
TEST(IntegrityAlgo, HMAC_SHA1_96_VerifyIntegrityDataPass)
{
/*
* Step-1 Generate Integrity data using OpenSSL SHA1 algorithm
*/
// Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
// Hardcoded Session Integrity Key
std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20 };
std::vector<uint8_t> k1(SHA_DIGEST_LENGTH);
constexpr rmcp::Const_n const1 = { 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01
};
// Generated K1 for the integrity algorithm with the additional key keyed
// with SIK.
unsigned int mdLen = 0;
if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
const1.size(), k1.data(), &mdLen) == NULL)
{
FAIL() << "Generating Key1 failed";
}
mdLen = 0;
std::vector<uint8_t> output(SHA_DIGEST_LENGTH);
size_t length = packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE;
if (HMAC(EVP_sha1(), k1.data(), k1.size(),
packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
length,
output.data(), &mdLen) == NULL)
{
FAIL() << "Generating integrity data failed";
}
output.resize(cipher::integrity::AlgoSHA1::SHA1_96_AUTHCODE_LENGTH);
/*
* Step-2 Insert the integrity data into the packet
*/
auto packetSize = packet.size();
packet.insert(packet.end(), output.begin(), output.end());
// Point to the integrity data in the packet
auto integrityIter = packet.cbegin();
std::advance(integrityIter, packetSize);
/*
* Step-3 Invoke the verifyIntegrityData API and validate the response
*/
auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA1>(sik);
ASSERT_EQ(true, (algoPtr != NULL));
auto check = algoPtr->verifyIntegrityData(
packet,
packetSize - message::parser::RMCP_SESSION_HEADER_SIZE,
integrityIter);
EXPECT_EQ(true, check);
}
TEST(IntegrityAlgo, HMAC_SHA1_96_VerifyIntegrityDataFail)
{
/*
* Step-1 Add hardcoded Integrity data to the packet
*/
// Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
std::vector<uint8_t> integrity = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
packet.insert(packet.end(), integrity.begin(), integrity.end());
// Point to the integrity data in the packet
auto integrityIter = packet.cbegin();
std::advance(integrityIter, packet.size());
/*
* Step-2 Invoke the verifyIntegrityData API and validate the response
*/
// Hardcoded Session Integrity Key
std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20 };
auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA1>(sik);
ASSERT_EQ(true, (algoPtr != NULL));
// Verify the Integrity Data
auto check = algoPtr->verifyIntegrityData(
packet,
packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE,
integrityIter);
EXPECT_EQ(false, check);
}
TEST(IntegrityAlgo, HMAC_SHA256_128_GenerateIntegrityDataCheck)
{
/*
* Step-1 Generate Integrity Data for the packet, using the implemented API
*/
// Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
// Hardcoded Session Integrity Key
std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32 };
auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA256>(sik);
ASSERT_EQ(true, (algoPtr != NULL));
// Generate the Integrity Data
auto response = algoPtr->generateIntegrityData(packet);
EXPECT_EQ(true, (response.size() ==
cipher::integrity::AlgoSHA256::SHA256_128_AUTHCODE_LENGTH));
/*
* Step-2 Generate Integrity data using OpenSSL SHA256 algorithm
*/
std::vector<uint8_t> k1(SHA256_DIGEST_LENGTH);
constexpr rmcp::Const_n const1 = { 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01
};
// Generated K1 for the integrity algorithm with the additional key keyed
// with SIK.
unsigned int mdLen = 0;
if (HMAC(EVP_sha256(), sik.data(), sik.size(), const1.data(),
const1.size(), k1.data(), &mdLen) == NULL)
{
FAIL() << "Generating Key1 failed";
}
mdLen = 0;
std::vector<uint8_t> output(SHA256_DIGEST_LENGTH);
size_t length = packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE;
if (HMAC(EVP_sha256(), k1.data(), k1.size(),
packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
length,
output.data(), &mdLen) == NULL)
{
FAIL() << "Generating integrity data failed";
}
output.resize(cipher::integrity::AlgoSHA256::SHA256_128_AUTHCODE_LENGTH);
/*
* Step-3 Check if the integrity data we generated using the implemented API
* matches with one generated by OpenSSL SHA256 algorithm.
*/
auto check = std::equal(output.begin(), output.end(), response.begin());
EXPECT_EQ(true, check);
}
TEST(IntegrityAlgo, HMAC_SHA256_128_VerifyIntegrityDataPass)
{
/*
* Step-1 Generate Integrity data using OpenSSL SHA256 algorithm
*/
// Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
// Hardcoded Session Integrity Key
std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32 };
std::vector<uint8_t> k1(SHA256_DIGEST_LENGTH);
constexpr rmcp::Const_n const1 = { 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01
};
// Generated K1 for the integrity algorithm with the additional key keyed
// with SIK.
unsigned int mdLen = 0;
if (HMAC(EVP_sha256(), sik.data(), sik.size(), const1.data(),
const1.size(), k1.data(), &mdLen) == NULL)
{
FAIL() << "Generating Key1 failed";
}
mdLen = 0;
std::vector<uint8_t> output(SHA256_DIGEST_LENGTH);
size_t length = packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE;
if (HMAC(EVP_sha256(), k1.data(), k1.size(),
packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
length,
output.data(), &mdLen) == NULL)
{
FAIL() << "Generating integrity data failed";
}
output.resize(cipher::integrity::AlgoSHA256::SHA256_128_AUTHCODE_LENGTH);
/*
* Step-2 Insert the integrity data into the packet
*/
auto packetSize = packet.size();
packet.insert(packet.end(), output.begin(), output.end());
// Point to the integrity data in the packet
auto integrityIter = packet.cbegin();
std::advance(integrityIter, packetSize);
/*
* Step-3 Invoke the verifyIntegrityData API and validate the response
*/
auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA256>(sik);
ASSERT_EQ(true, (algoPtr != NULL));
auto check = algoPtr->verifyIntegrityData(
packet,
packetSize - message::parser::RMCP_SESSION_HEADER_SIZE,
integrityIter);
EXPECT_EQ(true, check);
}
TEST(IntegrityAlgo, HMAC_SHA256_128_VerifyIntegrityDataFail)
{
/*
* Step-1 Add hardcoded Integrity data to the packet
*/
// Packet = RMCP Session Header (4 bytes) + Packet (8 bytes)
std::vector<uint8_t> packet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
std::vector<uint8_t> integrity = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
packet.insert(packet.end(), integrity.begin(), integrity.end());
// Point to the integrity data in the packet
auto integrityIter = packet.cbegin();
std::advance(integrityIter, packet.size());
/*
* Step-2 Invoke the verifyIntegrityData API and validate the response
*/
// Hardcoded Session Integrity Key
std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32 };
auto algoPtr = std::make_unique<cipher::integrity::AlgoSHA256>(sik);
ASSERT_EQ(true, (algoPtr != NULL));
// Verify the Integrity Data
auto check = algoPtr->verifyIntegrityData(
packet,
packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE,
integrityIter);
EXPECT_EQ(false, check);
}
TEST(CryptAlgo, AES_CBC_128_EncryptPayloadValidate)
{
/*
* Step-1 Generate the encrypted data using the implemented API for
* AES-CBC-128
*/
std::vector<uint8_t> payload = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
// Hardcoded Session Integrity Key
std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20 };
std::vector<uint8_t> k2(SHA_DIGEST_LENGTH);
unsigned int mdLen = 0;
constexpr rmcp::Const_n const1 = { 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02
};
// Generated K2 for the confidentiality algorithm with the additional key
// keyed with SIK.
if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
const1.size(), k2.data(), &mdLen) == NULL)
{
FAIL() << "Generating K2 for confidentiality algorithm failed";
}
auto cryptPtr = std::make_unique<cipher::crypt::AlgoAES128>(k2);
ASSERT_EQ(true, (cryptPtr != NULL));
auto cipher = cryptPtr->encryptPayload(payload);
/*
* Step-2 Decrypt the encrypted payload using OpenSSL EVP_aes_128_cbc()
* implementation
*/
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, k2.data(),
cipher.data()))
{
EVP_CIPHER_CTX_free(ctx);
FAIL() << "EVP_DecryptInit_ex failed for type AES-CBC-128";
}
EVP_CIPHER_CTX_set_padding(ctx, 0);
std::vector<uint8_t> output(
cipher.size() + cipher::crypt::AlgoAES128::AESCBC128BlockSize);
int outputLen = 0;
if (!EVP_DecryptUpdate(ctx, output.data(), &outputLen,
cipher.data() +
cipher::crypt::AlgoAES128::AESCBC128ConfHeader,
cipher.size() -
cipher::crypt::AlgoAES128::AESCBC128ConfHeader))
{
EVP_CIPHER_CTX_free(ctx);
FAIL() << "EVP_DecryptUpdate failed";
}
output.resize(outputLen);
EVP_CIPHER_CTX_free(ctx);
/*
* Step -3 Check if the plain payload matches with the decrypted one
*/
auto check = std::equal(payload.begin(), payload.end(), output.begin());
EXPECT_EQ(true, check);
}
TEST(CryptAlgo, AES_CBC_128_DecryptPayloadValidate)
{
/*
* Step-1 Encrypt the payload using OpenSSL EVP_aes_128_cbc()
* implementation
*/
std::vector<uint8_t> payload = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16};
payload.resize(payload.size() + 1);
payload.back() = 0;
// Hardcoded Session Integrity Key
std::vector<uint8_t> sik = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20 };
EVP_CIPHER_CTX* ctx;
ctx = EVP_CIPHER_CTX_new();
std::vector<uint8_t> k2(SHA_DIGEST_LENGTH);
unsigned int mdLen = 0;
constexpr rmcp::Const_n const1 = { 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02
};
std::vector<uint8_t> output(
payload.size() + cipher::crypt::AlgoAES128::AESCBC128BlockSize);
if (!RAND_bytes(output.data(),
cipher::crypt::AlgoAES128::AESCBC128ConfHeader))
{
FAIL() << "RAND_bytes failed";
}
// Generated K2 for the confidentiality algorithm with the additional key
// keyed with SIK.
if (HMAC(EVP_sha1(), sik.data(), sik.size(), const1.data(),
const1.size(), k2.data(), &mdLen) == NULL)
{
FAIL() << "Generating K2 for confidentiality algorithm failed";
}
if (!EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, k2.data(),
output.data()))
{
EVP_CIPHER_CTX_free(ctx);
FAIL() << "EVP_EncryptInit_ex failed for type AES-CBC-128";
}
EVP_CIPHER_CTX_set_padding(ctx, 0);
int outputLen = 0;
if (!EVP_EncryptUpdate(ctx,
output.data() +
cipher::crypt::AlgoAES128::AESCBC128ConfHeader,
&outputLen,
payload.data(),
payload.size()))
{
EVP_CIPHER_CTX_free(ctx);
FAIL() << "EVP_EncryptUpdate failed";
}
output.resize(cipher::crypt::AlgoAES128::AESCBC128ConfHeader + outputLen);
EVP_CIPHER_CTX_free(ctx);
/*
* Step-2 Decrypt the encrypted payload using the implemented API for
* AES-CBC-128
*/
auto cryptPtr = std::make_unique<cipher::crypt::AlgoAES128>(k2);
ASSERT_EQ(true, (cryptPtr != NULL));
auto plain = cryptPtr->decryptPayload(output, 0, output.size());
/*
* Step -3 Check if the plain payload matches with the decrypted one
*/
auto check = std::equal(payload.begin(), payload.end(), plain.begin());
EXPECT_EQ(true, check);
}