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