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 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 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 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 4270fd29cfSVernon 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> 579e801a2bSVernon 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 649b307be6SVernon 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 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 877e9e2ef6SVernon 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 1087e9e2ef6SVernon 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> 1239e801a2bSVernon 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 1307e9e2ef6SVernon 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