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