19b307be6SVernon Mauery #include <openssl/evp.h> 277531db5STom Joseph #include <openssl/hmac.h> 377531db5STom Joseph #include <openssl/sha.h> 477531db5STom Joseph #include "integrity_algo.hpp" 577531db5STom Joseph #include "message_parsers.hpp" 677531db5STom Joseph 777531db5STom Joseph namespace cipher 877531db5STom Joseph { 977531db5STom Joseph 1077531db5STom Joseph namespace integrity 1177531db5STom Joseph { 1277531db5STom Joseph 139b307be6SVernon Mauery AlgoSHA1::AlgoSHA1(const std::vector<uint8_t>& sik) 149b307be6SVernon Mauery : Interface(SHA1_96_AUTHCODE_LENGTH) 1577531db5STom Joseph { 169b307be6SVernon Mauery k1 = generateKn(sik, rmcp::const_1); 1777531db5STom Joseph } 1877531db5STom Joseph 1970fd29cfSVernon Mauery std::vector<uint8_t> AlgoSHA1::generateHMAC(const uint8_t* input, 2070fd29cfSVernon Mauery const size_t len) const 21d212a6dcSTom Joseph { 2270fd29cfSVernon Mauery std::vector<uint8_t> output(SHA_DIGEST_LENGTH); 23d212a6dcSTom Joseph unsigned int mdLen = 0; 24d212a6dcSTom Joseph 259b307be6SVernon Mauery if (HMAC(EVP_sha1(), k1.data(), k1.size(), input, len, 26d212a6dcSTom Joseph output.data(), &mdLen) == NULL) 27d212a6dcSTom Joseph { 28d212a6dcSTom Joseph throw std::runtime_error("Generating integrity data failed"); 29d212a6dcSTom Joseph } 30d212a6dcSTom Joseph 31d212a6dcSTom Joseph // HMAC generates Message Digest to the size of SHA_DIGEST_LENGTH, the 32d212a6dcSTom Joseph // AuthCode field length is based on the integrity algorithm. So we are 33d212a6dcSTom Joseph // interested only in the AuthCode field length of the generated Message 34d212a6dcSTom Joseph // digest. 35d212a6dcSTom Joseph output.resize(authCodeLength); 36d212a6dcSTom Joseph 37d212a6dcSTom Joseph return output; 38d212a6dcSTom Joseph } 39d212a6dcSTom Joseph 4070fd29cfSVernon Mauery bool AlgoSHA1::verifyIntegrityData( 4170fd29cfSVernon Mauery const std::vector<uint8_t>& packet, 42d212a6dcSTom Joseph const size_t length, 4370fd29cfSVernon Mauery std::vector<uint8_t>::const_iterator integrityData) const 44d212a6dcSTom Joseph { 45d212a6dcSTom Joseph 46d212a6dcSTom Joseph auto output = generateHMAC( 47d212a6dcSTom Joseph packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, 48d212a6dcSTom Joseph 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 5570fd29cfSVernon Mauery std::vector<uint8_t> AlgoSHA1::generateIntegrityData( 5670fd29cfSVernon Mauery 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. 719b307be6SVernon Mauery if (HMAC(EVP_sha1(), sik.data(), sik.size(), const_n.data(), 729b307be6SVernon Mauery const_n.size(), 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*7e9e2ef6SVernon Mauery AlgoSHA256::AlgoSHA256(const std::vector<uint8_t>& sik) 81*7e9e2ef6SVernon Mauery : Interface(SHA256_128_AUTHCODE_LENGTH) 82*7e9e2ef6SVernon Mauery { 83*7e9e2ef6SVernon Mauery k1 = generateKn(sik, rmcp::const_1); 84*7e9e2ef6SVernon Mauery } 85*7e9e2ef6SVernon Mauery 86*7e9e2ef6SVernon Mauery std::vector<uint8_t> AlgoSHA256::generateHMAC(const uint8_t* input, 87*7e9e2ef6SVernon Mauery const size_t len) const 88*7e9e2ef6SVernon Mauery { 89*7e9e2ef6SVernon Mauery std::vector<uint8_t> output(SHA256_DIGEST_LENGTH); 90*7e9e2ef6SVernon Mauery unsigned int mdLen = 0; 91*7e9e2ef6SVernon Mauery 92*7e9e2ef6SVernon Mauery if (HMAC(EVP_sha256(), k1.data(), k1.size(), input, len, 93*7e9e2ef6SVernon Mauery output.data(), &mdLen) == NULL) 94*7e9e2ef6SVernon Mauery { 95*7e9e2ef6SVernon Mauery throw std::runtime_error("Generating HMAC_SHA256_128 failed"); 96*7e9e2ef6SVernon Mauery } 97*7e9e2ef6SVernon Mauery 98*7e9e2ef6SVernon Mauery // HMAC generates Message Digest to the size of SHA256_DIGEST_LENGTH, the 99*7e9e2ef6SVernon Mauery // AuthCode field length is based on the integrity algorithm. So we are 100*7e9e2ef6SVernon Mauery // interested only in the AuthCode field length of the generated Message 101*7e9e2ef6SVernon Mauery // digest. 102*7e9e2ef6SVernon Mauery output.resize(authCodeLength); 103*7e9e2ef6SVernon Mauery 104*7e9e2ef6SVernon Mauery return output; 105*7e9e2ef6SVernon Mauery } 106*7e9e2ef6SVernon Mauery 107*7e9e2ef6SVernon Mauery bool AlgoSHA256::verifyIntegrityData( 108*7e9e2ef6SVernon Mauery const std::vector<uint8_t>& packet, 109*7e9e2ef6SVernon Mauery const size_t length, 110*7e9e2ef6SVernon Mauery std::vector<uint8_t>::const_iterator integrityData) const 111*7e9e2ef6SVernon Mauery { 112*7e9e2ef6SVernon Mauery 113*7e9e2ef6SVernon Mauery auto output = generateHMAC( 114*7e9e2ef6SVernon Mauery packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, 115*7e9e2ef6SVernon Mauery length); 116*7e9e2ef6SVernon Mauery 117*7e9e2ef6SVernon Mauery // Verify if the generated integrity data for the packet and the received 118*7e9e2ef6SVernon Mauery // integrity data matches. 119*7e9e2ef6SVernon Mauery return (std::equal(output.begin(), output.end(), integrityData)); 120*7e9e2ef6SVernon Mauery } 121*7e9e2ef6SVernon Mauery 122*7e9e2ef6SVernon Mauery std::vector<uint8_t> AlgoSHA256::generateIntegrityData( 123*7e9e2ef6SVernon Mauery const std::vector<uint8_t>& packet) const 124*7e9e2ef6SVernon Mauery { 125*7e9e2ef6SVernon Mauery return generateHMAC( 126*7e9e2ef6SVernon Mauery packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, 127*7e9e2ef6SVernon Mauery packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE); 128*7e9e2ef6SVernon Mauery } 129*7e9e2ef6SVernon Mauery 130*7e9e2ef6SVernon Mauery std::vector<uint8_t> AlgoSHA256::generateKn(const std::vector<uint8_t>& sik, 131*7e9e2ef6SVernon Mauery const rmcp::Const_n& const_n) const 132*7e9e2ef6SVernon Mauery { 133*7e9e2ef6SVernon Mauery unsigned int mdLen = 0; 134*7e9e2ef6SVernon Mauery std::vector<uint8_t> Kn(sik.size()); 135*7e9e2ef6SVernon Mauery 136*7e9e2ef6SVernon Mauery // Generated Kn for the integrity algorithm with the additional key keyed 137*7e9e2ef6SVernon Mauery // with SIK. 138*7e9e2ef6SVernon Mauery if (HMAC(EVP_sha256(), sik.data(), sik.size(), const_n.data(), 139*7e9e2ef6SVernon Mauery const_n.size(), Kn.data(), &mdLen) == NULL) 140*7e9e2ef6SVernon Mauery { 141*7e9e2ef6SVernon Mauery throw std::runtime_error("Generating KeyN for integrity " 142*7e9e2ef6SVernon Mauery "algorithm HMAC_SHA256 failed"); 143*7e9e2ef6SVernon Mauery } 144*7e9e2ef6SVernon Mauery return Kn; 145*7e9e2ef6SVernon Mauery } 146*7e9e2ef6SVernon Mauery 14777531db5STom Joseph }// namespace integrity 14877531db5STom Joseph 14977531db5STom Joseph }// namespace cipher 150