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