1 #include "integrity_algo.hpp" 2 3 #include "message_parsers.hpp" 4 5 #include <openssl/evp.h> 6 #include <openssl/hmac.h> 7 #include <openssl/sha.h> 8 9 namespace cipher 10 { 11 12 namespace integrity 13 { 14 15 AlgoSHA1::AlgoSHA1(const std::vector<uint8_t>& sik) : 16 Interface(SHA1_96_AUTHCODE_LENGTH) 17 { 18 k1 = generateKn(sik, rmcp::const_1); 19 } 20 21 std::vector<uint8_t> AlgoSHA1::generateHMAC(const uint8_t* input, 22 const size_t len) const 23 { 24 std::vector<uint8_t> output(SHA_DIGEST_LENGTH); 25 unsigned int mdLen = 0; 26 27 if (HMAC(EVP_sha1(), k1.data(), k1.size(), input, len, output.data(), 28 &mdLen) == NULL) 29 { 30 throw std::runtime_error("Generating integrity data failed"); 31 } 32 33 // HMAC generates Message Digest to the size of SHA_DIGEST_LENGTH, the 34 // AuthCode field length is based on the integrity algorithm. So we are 35 // interested only in the AuthCode field length of the generated Message 36 // digest. 37 output.resize(authCodeLength); 38 39 return output; 40 } 41 42 bool AlgoSHA1::verifyIntegrityData( 43 const std::vector<uint8_t>& packet, const size_t length, 44 std::vector<uint8_t>::const_iterator integrityDataBegin, 45 std::vector<uint8_t>::const_iterator integrityDataEnd) const 46 { 47 auto output = generateHMAC( 48 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, length); 49 50 // Verify if the generated integrity data for the packet and the received 51 // integrity data matches. 52 return (std::equal(output.begin(), output.end(), integrityDataBegin, 53 integrityDataEnd)); 54 } 55 56 std::vector<uint8_t> 57 AlgoSHA1::generateIntegrityData(const std::vector<uint8_t>& packet) const 58 { 59 return generateHMAC( 60 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, 61 packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE); 62 } 63 64 std::vector<uint8_t> AlgoSHA1::generateKn(const std::vector<uint8_t>& sik, 65 const rmcp::Const_n& const_n) const 66 { 67 unsigned int mdLen = 0; 68 std::vector<uint8_t> Kn(sik.size()); 69 70 // Generated Kn for the integrity algorithm with the additional key keyed 71 // with SIK. 72 if (HMAC(EVP_sha1(), sik.data(), sik.size(), const_n.data(), const_n.size(), 73 Kn.data(), &mdLen) == NULL) 74 { 75 throw std::runtime_error("Generating KeyN for integrity " 76 "algorithm failed"); 77 } 78 return Kn; 79 } 80 81 AlgoSHA256::AlgoSHA256(const std::vector<uint8_t>& sik) : 82 Interface(SHA256_128_AUTHCODE_LENGTH) 83 { 84 k1 = generateKn(sik, rmcp::const_1); 85 } 86 87 std::vector<uint8_t> AlgoSHA256::generateHMAC(const uint8_t* input, 88 const size_t len) const 89 { 90 std::vector<uint8_t> output(SHA256_DIGEST_LENGTH); 91 unsigned int mdLen = 0; 92 93 if (HMAC(EVP_sha256(), k1.data(), k1.size(), input, len, output.data(), 94 &mdLen) == NULL) 95 { 96 throw std::runtime_error("Generating HMAC_SHA256_128 failed"); 97 } 98 99 // HMAC generates Message Digest to the size of SHA256_DIGEST_LENGTH, the 100 // AuthCode field length is based on the integrity algorithm. So we are 101 // interested only in the AuthCode field length of the generated Message 102 // digest. 103 output.resize(authCodeLength); 104 105 return output; 106 } 107 108 bool AlgoSHA256::verifyIntegrityData( 109 const std::vector<uint8_t>& packet, const size_t length, 110 std::vector<uint8_t>::const_iterator integrityDataBegin, 111 std::vector<uint8_t>::const_iterator integrityDataEnd) const 112 { 113 auto output = generateHMAC( 114 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, length); 115 116 // Verify if the generated integrity data for the packet and the received 117 // integrity data matches. 118 return (std::equal(output.begin(), output.end(), integrityDataBegin, 119 integrityDataEnd)); 120 } 121 122 std::vector<uint8_t> 123 AlgoSHA256::generateIntegrityData(const std::vector<uint8_t>& packet) const 124 { 125 return generateHMAC( 126 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, 127 packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE); 128 } 129 130 std::vector<uint8_t> AlgoSHA256::generateKn(const std::vector<uint8_t>& sik, 131 const rmcp::Const_n& const_n) const 132 { 133 unsigned int mdLen = 0; 134 std::vector<uint8_t> Kn(sik.size()); 135 136 // Generated Kn for the integrity algorithm with the additional key keyed 137 // with SIK. 138 if (HMAC(EVP_sha256(), sik.data(), sik.size(), const_n.data(), 139 const_n.size(), Kn.data(), &mdLen) == NULL) 140 { 141 throw std::runtime_error("Generating KeyN for integrity " 142 "algorithm HMAC_SHA256 failed"); 143 } 144 return Kn; 145 } 146 147 } // namespace integrity 148 149 } // namespace cipher 150