blob: bac87d70e07961779ffd23b80c9f94d298e4ccac [file] [log] [blame]
Vernon Mauery9e801a22018-10-12 13:20:49 -07001#include "integrity_algo.hpp"
2
3#include "message_parsers.hpp"
4
Vernon Mauery9b307be2017-11-22 09:28:16 -08005#include <openssl/evp.h>
Tom Joseph77531db2017-01-10 15:44:44 +05306#include <openssl/hmac.h>
7#include <openssl/sha.h>
Tom Joseph77531db2017-01-10 15:44:44 +05308
9namespace cipher
10{
11
12namespace integrity
13{
14
Vernon Mauery9e801a22018-10-12 13:20:49 -070015AlgoSHA1::AlgoSHA1(const std::vector<uint8_t>& sik) :
16 Interface(SHA1_96_AUTHCODE_LENGTH)
Tom Joseph77531db2017-01-10 15:44:44 +053017{
Vernon Mauery9b307be2017-11-22 09:28:16 -080018 k1 = generateKn(sik, rmcp::const_1);
Tom Joseph77531db2017-01-10 15:44:44 +053019}
20
Vernon Mauery70fd29c2017-11-30 13:11:43 -080021std::vector<uint8_t> AlgoSHA1::generateHMAC(const uint8_t* input,
Vernon Mauery9e801a22018-10-12 13:20:49 -070022 const size_t len) const
Tom Josephd212a6d2017-01-10 15:48:40 +053023{
Vernon Mauery70fd29c2017-11-30 13:11:43 -080024 std::vector<uint8_t> output(SHA_DIGEST_LENGTH);
Tom Josephd212a6d2017-01-10 15:48:40 +053025 unsigned int mdLen = 0;
26
Vernon Mauery9e801a22018-10-12 13:20:49 -070027 if (HMAC(EVP_sha1(), k1.data(), k1.size(), input, len, output.data(),
28 &mdLen) == NULL)
Tom Josephd212a6d2017-01-10 15:48:40 +053029 {
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
Vernon Mauery70fd29c2017-11-30 13:11:43 -080042bool AlgoSHA1::verifyIntegrityData(
Vernon Mauery9e801a22018-10-12 13:20:49 -070043 const std::vector<uint8_t>& packet, const size_t length,
44 std::vector<uint8_t>::const_iterator integrityData) const
Tom Josephd212a6d2017-01-10 15:48:40 +053045{
46
47 auto output = generateHMAC(
Vernon Mauery9e801a22018-10-12 13:20:49 -070048 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, length);
Tom Josephd212a6d2017-01-10 15:48:40 +053049
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
Vernon Mauery9e801a22018-10-12 13:20:49 -070055std::vector<uint8_t>
56 AlgoSHA1::generateIntegrityData(const std::vector<uint8_t>& packet) const
Tom Josephd212a6d2017-01-10 15:48:40 +053057{
58 return generateHMAC(
Vernon Mauery9e801a22018-10-12 13:20:49 -070059 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
60 packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE);
Tom Josephd212a6d2017-01-10 15:48:40 +053061}
62
Vernon Mauery9b307be2017-11-22 09:28:16 -080063std::vector<uint8_t> AlgoSHA1::generateKn(const std::vector<uint8_t>& sik,
Vernon Mauery9e801a22018-10-12 13:20:49 -070064 const rmcp::Const_n& const_n) const
Vernon Mauery9b307be2017-11-22 09:28:16 -080065{
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.
Vernon Mauery9e801a22018-10-12 13:20:49 -070071 if (HMAC(EVP_sha1(), sik.data(), sik.size(), const_n.data(), const_n.size(),
72 Kn.data(), &mdLen) == NULL)
Vernon Mauery9b307be2017-11-22 09:28:16 -080073 {
74 throw std::runtime_error("Generating KeyN for integrity "
75 "algorithm failed");
76 }
77 return Kn;
78}
79
Vernon Mauery9e801a22018-10-12 13:20:49 -070080AlgoSHA256::AlgoSHA256(const std::vector<uint8_t>& sik) :
81 Interface(SHA256_128_AUTHCODE_LENGTH)
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -080082{
83 k1 = generateKn(sik, rmcp::const_1);
84}
85
86std::vector<uint8_t> AlgoSHA256::generateHMAC(const uint8_t* input,
Vernon Mauery9e801a22018-10-12 13:20:49 -070087 const size_t len) const
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -080088{
89 std::vector<uint8_t> output(SHA256_DIGEST_LENGTH);
90 unsigned int mdLen = 0;
91
Vernon Mauery9e801a22018-10-12 13:20:49 -070092 if (HMAC(EVP_sha256(), k1.data(), k1.size(), input, len, output.data(),
93 &mdLen) == NULL)
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -080094 {
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
107bool AlgoSHA256::verifyIntegrityData(
Vernon Mauery9e801a22018-10-12 13:20:49 -0700108 const std::vector<uint8_t>& packet, const size_t length,
109 std::vector<uint8_t>::const_iterator integrityData) const
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800110{
111
112 auto output = generateHMAC(
Vernon Mauery9e801a22018-10-12 13:20:49 -0700113 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, length);
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800114
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
Vernon Mauery9e801a22018-10-12 13:20:49 -0700120std::vector<uint8_t>
121 AlgoSHA256::generateIntegrityData(const std::vector<uint8_t>& packet) const
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800122{
123 return generateHMAC(
Vernon Mauery9e801a22018-10-12 13:20:49 -0700124 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
125 packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE);
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800126}
127
128std::vector<uint8_t> AlgoSHA256::generateKn(const std::vector<uint8_t>& sik,
Vernon Mauery9e801a22018-10-12 13:20:49 -0700129 const rmcp::Const_n& const_n) const
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800130{
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
Vernon Mauery9e801a22018-10-12 13:20:49 -0700145} // namespace integrity
Tom Joseph77531db2017-01-10 15:44:44 +0530146
Vernon Mauery9e801a22018-10-12 13:20:49 -0700147} // namespace cipher