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 integrityData) const 45 { 46 auto output = generateHMAC( 47 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, length); 48 49 // Verify if the generated integrity data for the packet and the received 50 // integrity data matches. 51 return (std::equal(output.begin(), output.end(), integrityData)); 52 } 53 54 std::vector<uint8_t> 55 AlgoSHA1::generateIntegrityData(const std::vector<uint8_t>& packet) const 56 { 57 return generateHMAC( 58 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, 59 packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE); 60 } 61 62 std::vector<uint8_t> AlgoSHA1::generateKn(const std::vector<uint8_t>& sik, 63 const rmcp::Const_n& const_n) const 64 { 65 unsigned int mdLen = 0; 66 std::vector<uint8_t> Kn(sik.size()); 67 68 // Generated Kn for the integrity algorithm with the additional key keyed 69 // with SIK. 70 if (HMAC(EVP_sha1(), sik.data(), sik.size(), const_n.data(), const_n.size(), 71 Kn.data(), &mdLen) == NULL) 72 { 73 throw std::runtime_error("Generating KeyN for integrity " 74 "algorithm failed"); 75 } 76 return Kn; 77 } 78 79 AlgoSHA256::AlgoSHA256(const std::vector<uint8_t>& sik) : 80 Interface(SHA256_128_AUTHCODE_LENGTH) 81 { 82 k1 = generateKn(sik, rmcp::const_1); 83 } 84 85 std::vector<uint8_t> AlgoSHA256::generateHMAC(const uint8_t* input, 86 const size_t len) const 87 { 88 std::vector<uint8_t> output(SHA256_DIGEST_LENGTH); 89 unsigned int mdLen = 0; 90 91 if (HMAC(EVP_sha256(), k1.data(), k1.size(), input, len, output.data(), 92 &mdLen) == NULL) 93 { 94 throw std::runtime_error("Generating HMAC_SHA256_128 failed"); 95 } 96 97 // HMAC generates Message Digest to the size of SHA256_DIGEST_LENGTH, the 98 // AuthCode field length is based on the integrity algorithm. So we are 99 // interested only in the AuthCode field length of the generated Message 100 // digest. 101 output.resize(authCodeLength); 102 103 return output; 104 } 105 106 bool AlgoSHA256::verifyIntegrityData( 107 const std::vector<uint8_t>& packet, const size_t length, 108 std::vector<uint8_t>::const_iterator integrityData) const 109 { 110 auto output = generateHMAC( 111 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, length); 112 113 // Verify if the generated integrity data for the packet and the received 114 // integrity data matches. 115 return (std::equal(output.begin(), output.end(), integrityData)); 116 } 117 118 std::vector<uint8_t> 119 AlgoSHA256::generateIntegrityData(const std::vector<uint8_t>& packet) const 120 { 121 return generateHMAC( 122 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, 123 packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE); 124 } 125 126 std::vector<uint8_t> AlgoSHA256::generateKn(const std::vector<uint8_t>& sik, 127 const rmcp::Const_n& const_n) const 128 { 129 unsigned int mdLen = 0; 130 std::vector<uint8_t> Kn(sik.size()); 131 132 // Generated Kn for the integrity algorithm with the additional key keyed 133 // with SIK. 134 if (HMAC(EVP_sha256(), sik.data(), sik.size(), const_n.data(), 135 const_n.size(), Kn.data(), &mdLen) == NULL) 136 { 137 throw std::runtime_error("Generating KeyN for integrity " 138 "algorithm HMAC_SHA256 failed"); 139 } 140 return Kn; 141 } 142 143 } // namespace integrity 144 145 } // namespace cipher 146