19e801a2bSVernon Mauery #include "integrity_algo.hpp"
29e801a2bSVernon Mauery 
39e801a2bSVernon Mauery #include "message_parsers.hpp"
49e801a2bSVernon 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 
AlgoSHA1(const std::vector<uint8_t> & sik)159e801a2bSVernon Mauery AlgoSHA1::AlgoSHA1(const std::vector<uint8_t>& sik) :
169e801a2bSVernon Mauery     Interface(SHA1_96_AUTHCODE_LENGTH)
1777531db5STom Joseph {
189b307be6SVernon Mauery     k1 = generateKn(sik, rmcp::const_1);
1977531db5STom Joseph }
2077531db5STom Joseph 
generateHMAC(const uint8_t * input,const size_t len) const2170fd29cfSVernon 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 
279e801a2bSVernon Mauery     if (HMAC(EVP_sha1(), k1.data(), k1.size(), input, len, output.data(),
289e801a2bSVernon 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 
verifyIntegrityData(const std::vector<uint8_t> & packet,const size_t length,std::vector<uint8_t>::const_iterator integrityDataBegin,std::vector<uint8_t>::const_iterator integrityDataEnd) const4270fd29cfSVernon Mauery bool AlgoSHA1::verifyIntegrityData(
439e801a2bSVernon Mauery     const std::vector<uint8_t>& packet, const size_t length,
44*198b0f81SGeorge Liu     std::vector<uint8_t>::const_iterator integrityDataBegin,
45*198b0f81SGeorge Liu     std::vector<uint8_t>::const_iterator integrityDataEnd) const
46d212a6dcSTom Joseph {
47d212a6dcSTom Joseph     auto output = generateHMAC(
489e801a2bSVernon 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.
52*198b0f81SGeorge Liu     return (std::equal(output.begin(), output.end(), integrityDataBegin,
53*198b0f81SGeorge Liu                        integrityDataEnd));
54d212a6dcSTom Joseph }
55d212a6dcSTom Joseph 
569e801a2bSVernon Mauery std::vector<uint8_t>
generateIntegrityData(const std::vector<uint8_t> & packet) const579e801a2bSVernon Mauery     AlgoSHA1::generateIntegrityData(const std::vector<uint8_t>& packet) const
58d212a6dcSTom Joseph {
59d212a6dcSTom Joseph     return generateHMAC(
60d212a6dcSTom Joseph         packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
61d212a6dcSTom Joseph         packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE);
62d212a6dcSTom Joseph }
63d212a6dcSTom Joseph 
generateKn(const std::vector<uint8_t> & sik,const rmcp::Const_n & const_n) const649b307be6SVernon Mauery std::vector<uint8_t> AlgoSHA1::generateKn(const std::vector<uint8_t>& sik,
659b307be6SVernon Mauery                                           const rmcp::Const_n& const_n) const
669b307be6SVernon Mauery {
679b307be6SVernon Mauery     unsigned int mdLen = 0;
689b307be6SVernon Mauery     std::vector<uint8_t> Kn(sik.size());
699b307be6SVernon Mauery 
709b307be6SVernon Mauery     // Generated Kn for the integrity algorithm with the additional key keyed
719b307be6SVernon Mauery     // with SIK.
729e801a2bSVernon Mauery     if (HMAC(EVP_sha1(), sik.data(), sik.size(), const_n.data(), const_n.size(),
739e801a2bSVernon Mauery              Kn.data(), &mdLen) == NULL)
749b307be6SVernon Mauery     {
759b307be6SVernon Mauery         throw std::runtime_error("Generating KeyN for integrity "
769b307be6SVernon Mauery                                  "algorithm failed");
779b307be6SVernon Mauery     }
789b307be6SVernon Mauery     return Kn;
799b307be6SVernon Mauery }
809b307be6SVernon Mauery 
AlgoSHA256(const std::vector<uint8_t> & sik)819e801a2bSVernon Mauery AlgoSHA256::AlgoSHA256(const std::vector<uint8_t>& sik) :
829e801a2bSVernon Mauery     Interface(SHA256_128_AUTHCODE_LENGTH)
837e9e2ef6SVernon Mauery {
847e9e2ef6SVernon Mauery     k1 = generateKn(sik, rmcp::const_1);
857e9e2ef6SVernon Mauery }
867e9e2ef6SVernon Mauery 
generateHMAC(const uint8_t * input,const size_t len) const877e9e2ef6SVernon Mauery std::vector<uint8_t> AlgoSHA256::generateHMAC(const uint8_t* input,
887e9e2ef6SVernon Mauery                                               const size_t len) const
897e9e2ef6SVernon Mauery {
907e9e2ef6SVernon Mauery     std::vector<uint8_t> output(SHA256_DIGEST_LENGTH);
917e9e2ef6SVernon Mauery     unsigned int mdLen = 0;
927e9e2ef6SVernon Mauery 
939e801a2bSVernon Mauery     if (HMAC(EVP_sha256(), k1.data(), k1.size(), input, len, output.data(),
949e801a2bSVernon Mauery              &mdLen) == NULL)
957e9e2ef6SVernon Mauery     {
967e9e2ef6SVernon Mauery         throw std::runtime_error("Generating HMAC_SHA256_128 failed");
977e9e2ef6SVernon Mauery     }
987e9e2ef6SVernon Mauery 
997e9e2ef6SVernon Mauery     // HMAC generates Message Digest to the size of SHA256_DIGEST_LENGTH, the
1007e9e2ef6SVernon Mauery     // AuthCode field length is based on the integrity algorithm. So we are
1017e9e2ef6SVernon Mauery     // interested only in the AuthCode field length of the generated Message
1027e9e2ef6SVernon Mauery     // digest.
1037e9e2ef6SVernon Mauery     output.resize(authCodeLength);
1047e9e2ef6SVernon Mauery 
1057e9e2ef6SVernon Mauery     return output;
1067e9e2ef6SVernon Mauery }
1077e9e2ef6SVernon Mauery 
verifyIntegrityData(const std::vector<uint8_t> & packet,const size_t length,std::vector<uint8_t>::const_iterator integrityDataBegin,std::vector<uint8_t>::const_iterator integrityDataEnd) const1087e9e2ef6SVernon Mauery bool AlgoSHA256::verifyIntegrityData(
1099e801a2bSVernon Mauery     const std::vector<uint8_t>& packet, const size_t length,
110*198b0f81SGeorge Liu     std::vector<uint8_t>::const_iterator integrityDataBegin,
111*198b0f81SGeorge Liu     std::vector<uint8_t>::const_iterator integrityDataEnd) const
1127e9e2ef6SVernon Mauery {
1137e9e2ef6SVernon Mauery     auto output = generateHMAC(
1149e801a2bSVernon Mauery         packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, length);
1157e9e2ef6SVernon Mauery 
1167e9e2ef6SVernon Mauery     // Verify if the generated integrity data for the packet and the received
1177e9e2ef6SVernon Mauery     // integrity data matches.
118*198b0f81SGeorge Liu     return (std::equal(output.begin(), output.end(), integrityDataBegin,
119*198b0f81SGeorge Liu                        integrityDataEnd));
1207e9e2ef6SVernon Mauery }
1217e9e2ef6SVernon Mauery 
1229e801a2bSVernon Mauery std::vector<uint8_t>
generateIntegrityData(const std::vector<uint8_t> & packet) const1239e801a2bSVernon Mauery     AlgoSHA256::generateIntegrityData(const std::vector<uint8_t>& packet) const
1247e9e2ef6SVernon Mauery {
1257e9e2ef6SVernon Mauery     return generateHMAC(
1267e9e2ef6SVernon Mauery         packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
1277e9e2ef6SVernon Mauery         packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE);
1287e9e2ef6SVernon Mauery }
1297e9e2ef6SVernon Mauery 
generateKn(const std::vector<uint8_t> & sik,const rmcp::Const_n & const_n) const1307e9e2ef6SVernon Mauery std::vector<uint8_t> AlgoSHA256::generateKn(const std::vector<uint8_t>& sik,
1317e9e2ef6SVernon Mauery                                             const rmcp::Const_n& const_n) const
1327e9e2ef6SVernon Mauery {
1337e9e2ef6SVernon Mauery     unsigned int mdLen = 0;
1347e9e2ef6SVernon Mauery     std::vector<uint8_t> Kn(sik.size());
1357e9e2ef6SVernon Mauery 
1367e9e2ef6SVernon Mauery     // Generated Kn for the integrity algorithm with the additional key keyed
1377e9e2ef6SVernon Mauery     // with SIK.
1387e9e2ef6SVernon Mauery     if (HMAC(EVP_sha256(), sik.data(), sik.size(), const_n.data(),
1397e9e2ef6SVernon Mauery              const_n.size(), Kn.data(), &mdLen) == NULL)
1407e9e2ef6SVernon Mauery     {
1417e9e2ef6SVernon Mauery         throw std::runtime_error("Generating KeyN for integrity "
1427e9e2ef6SVernon Mauery                                  "algorithm HMAC_SHA256 failed");
1437e9e2ef6SVernon Mauery     }
1447e9e2ef6SVernon Mauery     return Kn;
1457e9e2ef6SVernon Mauery }
1467e9e2ef6SVernon Mauery 
14777531db5STom Joseph } // namespace integrity
14877531db5STom Joseph 
14977531db5STom Joseph } // namespace cipher
150