1*9e801a2bSVernon Mauery #include "integrity_algo.hpp"
2*9e801a2bSVernon Mauery 
3*9e801a2bSVernon Mauery #include "message_parsers.hpp"
4*9e801a2bSVernon Mauery 
59b307be6SVernon Mauery #include <openssl/evp.h>
677531db5STom Joseph #include <openssl/hmac.h>
777531db5STom Joseph #include <openssl/sha.h>
877531db5STom Joseph 
977531db5STom Joseph namespace cipher
1077531db5STom Joseph {
1177531db5STom Joseph 
1277531db5STom Joseph namespace integrity
1377531db5STom Joseph {
1477531db5STom Joseph 
15*9e801a2bSVernon Mauery AlgoSHA1::AlgoSHA1(const std::vector<uint8_t>& sik) :
16*9e801a2bSVernon Mauery     Interface(SHA1_96_AUTHCODE_LENGTH)
1777531db5STom Joseph {
189b307be6SVernon Mauery     k1 = generateKn(sik, rmcp::const_1);
1977531db5STom Joseph }
2077531db5STom Joseph 
2170fd29cfSVernon Mauery std::vector<uint8_t> AlgoSHA1::generateHMAC(const uint8_t* input,
2270fd29cfSVernon Mauery                                             const size_t len) const
23d212a6dcSTom Joseph {
2470fd29cfSVernon Mauery     std::vector<uint8_t> output(SHA_DIGEST_LENGTH);
25d212a6dcSTom Joseph     unsigned int mdLen = 0;
26d212a6dcSTom Joseph 
27*9e801a2bSVernon Mauery     if (HMAC(EVP_sha1(), k1.data(), k1.size(), input, len, output.data(),
28*9e801a2bSVernon Mauery              &mdLen) == NULL)
29d212a6dcSTom Joseph     {
30d212a6dcSTom Joseph         throw std::runtime_error("Generating integrity data failed");
31d212a6dcSTom Joseph     }
32d212a6dcSTom Joseph 
33d212a6dcSTom Joseph     // HMAC generates Message Digest to the size of SHA_DIGEST_LENGTH, the
34d212a6dcSTom Joseph     // AuthCode field length is based on the integrity algorithm. So we are
35d212a6dcSTom Joseph     // interested only in the AuthCode field length of the generated Message
36d212a6dcSTom Joseph     // digest.
37d212a6dcSTom Joseph     output.resize(authCodeLength);
38d212a6dcSTom Joseph 
39d212a6dcSTom Joseph     return output;
40d212a6dcSTom Joseph }
41d212a6dcSTom Joseph 
4270fd29cfSVernon Mauery bool AlgoSHA1::verifyIntegrityData(
43*9e801a2bSVernon Mauery     const std::vector<uint8_t>& packet, const size_t length,
4470fd29cfSVernon Mauery     std::vector<uint8_t>::const_iterator integrityData) const
45d212a6dcSTom Joseph {
46d212a6dcSTom Joseph 
47d212a6dcSTom Joseph     auto output = generateHMAC(
48*9e801a2bSVernon Mauery         packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, length);
49d212a6dcSTom Joseph 
50d212a6dcSTom Joseph     // Verify if the generated integrity data for the packet and the received
51d212a6dcSTom Joseph     // integrity data matches.
52d212a6dcSTom Joseph     return (std::equal(output.begin(), output.end(), integrityData));
53d212a6dcSTom Joseph }
54d212a6dcSTom Joseph 
55*9e801a2bSVernon Mauery std::vector<uint8_t>
56*9e801a2bSVernon Mauery     AlgoSHA1::generateIntegrityData(const std::vector<uint8_t>& packet) const
57d212a6dcSTom Joseph {
58d212a6dcSTom Joseph     return generateHMAC(
59d212a6dcSTom Joseph         packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
60d212a6dcSTom Joseph         packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE);
61d212a6dcSTom Joseph }
62d212a6dcSTom Joseph 
639b307be6SVernon Mauery std::vector<uint8_t> AlgoSHA1::generateKn(const std::vector<uint8_t>& sik,
649b307be6SVernon Mauery                                           const rmcp::Const_n& const_n) const
659b307be6SVernon Mauery {
669b307be6SVernon Mauery     unsigned int mdLen = 0;
679b307be6SVernon Mauery     std::vector<uint8_t> Kn(sik.size());
689b307be6SVernon Mauery 
699b307be6SVernon Mauery     // Generated Kn for the integrity algorithm with the additional key keyed
709b307be6SVernon Mauery     // with SIK.
71*9e801a2bSVernon Mauery     if (HMAC(EVP_sha1(), sik.data(), sik.size(), const_n.data(), const_n.size(),
72*9e801a2bSVernon Mauery              Kn.data(), &mdLen) == NULL)
739b307be6SVernon Mauery     {
749b307be6SVernon Mauery         throw std::runtime_error("Generating KeyN for integrity "
759b307be6SVernon Mauery                                  "algorithm failed");
769b307be6SVernon Mauery     }
779b307be6SVernon Mauery     return Kn;
789b307be6SVernon Mauery }
799b307be6SVernon Mauery 
80*9e801a2bSVernon Mauery AlgoSHA256::AlgoSHA256(const std::vector<uint8_t>& sik) :
81*9e801a2bSVernon Mauery     Interface(SHA256_128_AUTHCODE_LENGTH)
827e9e2ef6SVernon Mauery {
837e9e2ef6SVernon Mauery     k1 = generateKn(sik, rmcp::const_1);
847e9e2ef6SVernon Mauery }
857e9e2ef6SVernon Mauery 
867e9e2ef6SVernon Mauery std::vector<uint8_t> AlgoSHA256::generateHMAC(const uint8_t* input,
877e9e2ef6SVernon Mauery                                               const size_t len) const
887e9e2ef6SVernon Mauery {
897e9e2ef6SVernon Mauery     std::vector<uint8_t> output(SHA256_DIGEST_LENGTH);
907e9e2ef6SVernon Mauery     unsigned int mdLen = 0;
917e9e2ef6SVernon Mauery 
92*9e801a2bSVernon Mauery     if (HMAC(EVP_sha256(), k1.data(), k1.size(), input, len, output.data(),
93*9e801a2bSVernon Mauery              &mdLen) == NULL)
947e9e2ef6SVernon Mauery     {
957e9e2ef6SVernon Mauery         throw std::runtime_error("Generating HMAC_SHA256_128 failed");
967e9e2ef6SVernon Mauery     }
977e9e2ef6SVernon Mauery 
987e9e2ef6SVernon Mauery     // HMAC generates Message Digest to the size of SHA256_DIGEST_LENGTH, the
997e9e2ef6SVernon Mauery     // AuthCode field length is based on the integrity algorithm. So we are
1007e9e2ef6SVernon Mauery     // interested only in the AuthCode field length of the generated Message
1017e9e2ef6SVernon Mauery     // digest.
1027e9e2ef6SVernon Mauery     output.resize(authCodeLength);
1037e9e2ef6SVernon Mauery 
1047e9e2ef6SVernon Mauery     return output;
1057e9e2ef6SVernon Mauery }
1067e9e2ef6SVernon Mauery 
1077e9e2ef6SVernon Mauery bool AlgoSHA256::verifyIntegrityData(
108*9e801a2bSVernon Mauery     const std::vector<uint8_t>& packet, const size_t length,
1097e9e2ef6SVernon Mauery     std::vector<uint8_t>::const_iterator integrityData) const
1107e9e2ef6SVernon Mauery {
1117e9e2ef6SVernon Mauery 
1127e9e2ef6SVernon Mauery     auto output = generateHMAC(
113*9e801a2bSVernon Mauery         packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, length);
1147e9e2ef6SVernon Mauery 
1157e9e2ef6SVernon Mauery     // Verify if the generated integrity data for the packet and the received
1167e9e2ef6SVernon Mauery     // integrity data matches.
1177e9e2ef6SVernon Mauery     return (std::equal(output.begin(), output.end(), integrityData));
1187e9e2ef6SVernon Mauery }
1197e9e2ef6SVernon Mauery 
120*9e801a2bSVernon Mauery std::vector<uint8_t>
121*9e801a2bSVernon Mauery     AlgoSHA256::generateIntegrityData(const std::vector<uint8_t>& packet) const
1227e9e2ef6SVernon Mauery {
1237e9e2ef6SVernon Mauery     return generateHMAC(
1247e9e2ef6SVernon Mauery         packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
1257e9e2ef6SVernon Mauery         packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE);
1267e9e2ef6SVernon Mauery }
1277e9e2ef6SVernon Mauery 
1287e9e2ef6SVernon Mauery std::vector<uint8_t> AlgoSHA256::generateKn(const std::vector<uint8_t>& sik,
1297e9e2ef6SVernon Mauery                                             const rmcp::Const_n& const_n) const
1307e9e2ef6SVernon Mauery {
1317e9e2ef6SVernon Mauery     unsigned int mdLen = 0;
1327e9e2ef6SVernon Mauery     std::vector<uint8_t> Kn(sik.size());
1337e9e2ef6SVernon Mauery 
1347e9e2ef6SVernon Mauery     // Generated Kn for the integrity algorithm with the additional key keyed
1357e9e2ef6SVernon Mauery     // with SIK.
1367e9e2ef6SVernon Mauery     if (HMAC(EVP_sha256(), sik.data(), sik.size(), const_n.data(),
1377e9e2ef6SVernon Mauery              const_n.size(), Kn.data(), &mdLen) == NULL)
1387e9e2ef6SVernon Mauery     {
1397e9e2ef6SVernon Mauery         throw std::runtime_error("Generating KeyN for integrity "
1407e9e2ef6SVernon Mauery                                  "algorithm HMAC_SHA256 failed");
1417e9e2ef6SVernon Mauery     }
1427e9e2ef6SVernon Mauery     return Kn;
1437e9e2ef6SVernon Mauery }
1447e9e2ef6SVernon Mauery 
14577531db5STom Joseph } // namespace integrity
14677531db5STom Joseph 
14777531db5STom Joseph } // namespace cipher
148