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
21*8425624aSPatrick Williams std::vector<uint8_t>
generateHMAC(const uint8_t * input,const size_t len) const22*8425624aSPatrick Williams AlgoSHA1::generateHMAC(const uint8_t* input, 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,
44198b0f81SGeorge Liu std::vector<uint8_t>::const_iterator integrityDataBegin,
45198b0f81SGeorge 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.
52198b0f81SGeorge Liu return (std::equal(output.begin(), output.end(), integrityDataBegin,
53198b0f81SGeorge 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
87*8425624aSPatrick Williams std::vector<uint8_t>
generateHMAC(const uint8_t * input,const size_t len) const88*8425624aSPatrick Williams AlgoSHA256::generateHMAC(const uint8_t* input, 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,
110198b0f81SGeorge Liu std::vector<uint8_t>::const_iterator integrityDataBegin,
111198b0f81SGeorge 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.
118198b0f81SGeorge Liu return (std::equal(output.begin(), output.end(), integrityDataBegin,
119198b0f81SGeorge 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