1 #include <openssl/evp.h>
2 #include <openssl/hmac.h>
3 #include <openssl/sha.h>
4 #include "integrity_algo.hpp"
5 #include "message_parsers.hpp"
6 
7 namespace cipher
8 {
9 
10 namespace integrity
11 {
12 
13 AlgoSHA1::AlgoSHA1(const std::vector<uint8_t>& sik)
14     : Interface(SHA1_96_AUTHCODE_LENGTH)
15 {
16     k1 = generateKn(sik, rmcp::const_1);
17 }
18 
19 std::vector<uint8_t> AlgoSHA1::generateHMAC(const uint8_t* input,
20         const size_t len) const
21 {
22     std::vector<uint8_t> output(SHA_DIGEST_LENGTH);
23     unsigned int mdLen = 0;
24 
25     if (HMAC(EVP_sha1(), k1.data(), k1.size(), input, len,
26              output.data(), &mdLen) == NULL)
27     {
28         throw std::runtime_error("Generating integrity data failed");
29     }
30 
31     // HMAC generates Message Digest to the size of SHA_DIGEST_LENGTH, the
32     // AuthCode field length is based on the integrity algorithm. So we are
33     // interested only in the AuthCode field length of the generated Message
34     // digest.
35     output.resize(authCodeLength);
36 
37     return output;
38 }
39 
40 bool AlgoSHA1::verifyIntegrityData(
41         const std::vector<uint8_t>& packet,
42         const size_t length,
43         std::vector<uint8_t>::const_iterator integrityData) const
44 {
45 
46     auto output = generateHMAC(
47             packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
48             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> AlgoSHA1::generateIntegrityData(
56         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(),
72              const_n.size(), Kn.data(), &mdLen) == NULL)
73     {
74         throw std::runtime_error("Generating KeyN for integrity "
75                                  "algorithm failed");
76     }
77     return Kn;
78 }
79 
80 }// namespace integrity
81 
82 }// namespace cipher
83