177531db5STom Joseph #include <openssl/hmac.h>
277531db5STom Joseph #include <openssl/sha.h>
377531db5STom Joseph #include "integrity_algo.hpp"
477531db5STom Joseph #include "message_parsers.hpp"
577531db5STom Joseph 
677531db5STom Joseph namespace cipher
777531db5STom Joseph {
877531db5STom Joseph 
977531db5STom Joseph namespace integrity
1077531db5STom Joseph {
1177531db5STom Joseph 
12*70fd29cfSVernon Mauery Interface::Interface(const std::vector<uint8_t>& sik,
13*70fd29cfSVernon Mauery                      const Key& addKey, size_t authLength)
1477531db5STom Joseph {
1577531db5STom Joseph     unsigned int mdLen = 0;
1677531db5STom Joseph 
1777531db5STom Joseph     // Generated K1 for the integrity algorithm with the additional key keyed
1877531db5STom Joseph     // with SIK.
1977531db5STom Joseph     if (HMAC(EVP_sha1(), sik.data(), sik.size(), addKey.data(),
2077531db5STom Joseph              addKey.size(), K1.data(), &mdLen) == NULL)
2177531db5STom Joseph     {
2277531db5STom Joseph         throw std::runtime_error("Generating Key1 for integrity "
2377531db5STom Joseph                                  "algorithm failed");
2477531db5STom Joseph     }
2577531db5STom Joseph 
2677531db5STom Joseph     authCodeLength = authLength;
2777531db5STom Joseph }
2877531db5STom Joseph 
29*70fd29cfSVernon Mauery std::vector<uint8_t> AlgoSHA1::generateHMAC(const uint8_t* input,
30*70fd29cfSVernon Mauery         const size_t len) const
31d212a6dcSTom Joseph {
32*70fd29cfSVernon Mauery     std::vector<uint8_t> output(SHA_DIGEST_LENGTH);
33d212a6dcSTom Joseph     unsigned int mdLen = 0;
34d212a6dcSTom Joseph 
35d212a6dcSTom Joseph     if (HMAC(EVP_sha1(), K1.data(), K1.size(), input, len,
36d212a6dcSTom Joseph              output.data(), &mdLen) == NULL)
37d212a6dcSTom Joseph     {
38d212a6dcSTom Joseph         throw std::runtime_error("Generating integrity data failed");
39d212a6dcSTom Joseph     }
40d212a6dcSTom Joseph 
41d212a6dcSTom Joseph     // HMAC generates Message Digest to the size of SHA_DIGEST_LENGTH, the
42d212a6dcSTom Joseph     // AuthCode field length is based on the integrity algorithm. So we are
43d212a6dcSTom Joseph     // interested only in the AuthCode field length of the generated Message
44d212a6dcSTom Joseph     // digest.
45d212a6dcSTom Joseph     output.resize(authCodeLength);
46d212a6dcSTom Joseph 
47d212a6dcSTom Joseph     return output;
48d212a6dcSTom Joseph }
49d212a6dcSTom Joseph 
50*70fd29cfSVernon Mauery bool AlgoSHA1::verifyIntegrityData(
51*70fd29cfSVernon Mauery         const std::vector<uint8_t>& packet,
52d212a6dcSTom Joseph         const size_t length,
53*70fd29cfSVernon Mauery         std::vector<uint8_t>::const_iterator integrityData) const
54d212a6dcSTom Joseph {
55d212a6dcSTom Joseph 
56d212a6dcSTom Joseph     auto output = generateHMAC(
57d212a6dcSTom Joseph             packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
58d212a6dcSTom Joseph             length);
59d212a6dcSTom Joseph 
60d212a6dcSTom Joseph     // Verify if the generated integrity data for the packet and the received
61d212a6dcSTom Joseph     // integrity data matches.
62d212a6dcSTom Joseph     return (std::equal(output.begin(), output.end(), integrityData));
63d212a6dcSTom Joseph }
64d212a6dcSTom Joseph 
65*70fd29cfSVernon Mauery std::vector<uint8_t> AlgoSHA1::generateIntegrityData(
66*70fd29cfSVernon Mauery         const std::vector<uint8_t>& packet) const
67d212a6dcSTom Joseph {
68d212a6dcSTom Joseph     return generateHMAC(
69d212a6dcSTom Joseph             packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
70d212a6dcSTom Joseph             packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE);
71d212a6dcSTom Joseph }
72d212a6dcSTom Joseph 
7377531db5STom Joseph }// namespace integrity
7477531db5STom Joseph 
7577531db5STom Joseph }// namespace cipher
76