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