1*9b307be6SVernon 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 13*9b307be6SVernon Mauery AlgoSHA1::AlgoSHA1(const std::vector<uint8_t>& sik) 14*9b307be6SVernon Mauery : Interface(SHA1_96_AUTHCODE_LENGTH) 1577531db5STom Joseph { 16*9b307be6SVernon 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 25*9b307be6SVernon 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 63*9b307be6SVernon Mauery std::vector<uint8_t> AlgoSHA1::generateKn(const std::vector<uint8_t>& sik, 64*9b307be6SVernon Mauery const rmcp::Const_n& const_n) const 65*9b307be6SVernon Mauery { 66*9b307be6SVernon Mauery unsigned int mdLen = 0; 67*9b307be6SVernon Mauery std::vector<uint8_t> Kn(sik.size()); 68*9b307be6SVernon Mauery 69*9b307be6SVernon Mauery // Generated Kn for the integrity algorithm with the additional key keyed 70*9b307be6SVernon Mauery // with SIK. 71*9b307be6SVernon Mauery if (HMAC(EVP_sha1(), sik.data(), sik.size(), const_n.data(), 72*9b307be6SVernon Mauery const_n.size(), Kn.data(), &mdLen) == NULL) 73*9b307be6SVernon Mauery { 74*9b307be6SVernon Mauery throw std::runtime_error("Generating KeyN for integrity " 75*9b307be6SVernon Mauery "algorithm failed"); 76*9b307be6SVernon Mauery } 77*9b307be6SVernon Mauery return Kn; 78*9b307be6SVernon Mauery } 79*9b307be6SVernon Mauery 8077531db5STom Joseph }// namespace integrity 8177531db5STom Joseph 8277531db5STom Joseph }// namespace cipher 83