blob: dc876255ae748ac8f074332592ca7e133def4707 [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,
George Liu198b0f82022-08-04 20:22:48 +080044 std::vector<uint8_t>::const_iterator integrityDataBegin,
45 std::vector<uint8_t>::const_iterator integrityDataEnd) const
Tom Josephd212a6d2017-01-10 15:48:40 +053046{
Tom Josephd212a6d2017-01-10 15:48:40 +053047 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.
George Liu198b0f82022-08-04 20:22:48 +080052 return (std::equal(output.begin(), output.end(), integrityDataBegin,
53 integrityDataEnd));
Tom Josephd212a6d2017-01-10 15:48:40 +053054}
55
Vernon Mauery9e801a22018-10-12 13:20:49 -070056std::vector<uint8_t>
57 AlgoSHA1::generateIntegrityData(const std::vector<uint8_t>& packet) const
Tom Josephd212a6d2017-01-10 15:48:40 +053058{
59 return generateHMAC(
Vernon Mauery9e801a22018-10-12 13:20:49 -070060 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
61 packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE);
Tom Josephd212a6d2017-01-10 15:48:40 +053062}
63
Vernon Mauery9b307be2017-11-22 09:28:16 -080064std::vector<uint8_t> AlgoSHA1::generateKn(const std::vector<uint8_t>& sik,
Vernon Mauery9e801a22018-10-12 13:20:49 -070065 const rmcp::Const_n& const_n) const
Vernon Mauery9b307be2017-11-22 09:28:16 -080066{
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.
Vernon Mauery9e801a22018-10-12 13:20:49 -070072 if (HMAC(EVP_sha1(), sik.data(), sik.size(), const_n.data(), const_n.size(),
73 Kn.data(), &mdLen) == NULL)
Vernon Mauery9b307be2017-11-22 09:28:16 -080074 {
75 throw std::runtime_error("Generating KeyN for integrity "
76 "algorithm failed");
77 }
78 return Kn;
79}
80
Vernon Mauery9e801a22018-10-12 13:20:49 -070081AlgoSHA256::AlgoSHA256(const std::vector<uint8_t>& sik) :
82 Interface(SHA256_128_AUTHCODE_LENGTH)
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -080083{
84 k1 = generateKn(sik, rmcp::const_1);
85}
86
87std::vector<uint8_t> AlgoSHA256::generateHMAC(const uint8_t* input,
Vernon Mauery9e801a22018-10-12 13:20:49 -070088 const size_t len) const
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -080089{
90 std::vector<uint8_t> output(SHA256_DIGEST_LENGTH);
91 unsigned int mdLen = 0;
92
Vernon Mauery9e801a22018-10-12 13:20:49 -070093 if (HMAC(EVP_sha256(), k1.data(), k1.size(), input, len, output.data(),
94 &mdLen) == NULL)
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -080095 {
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
108bool AlgoSHA256::verifyIntegrityData(
Vernon Mauery9e801a22018-10-12 13:20:49 -0700109 const std::vector<uint8_t>& packet, const size_t length,
George Liu198b0f82022-08-04 20:22:48 +0800110 std::vector<uint8_t>::const_iterator integrityDataBegin,
111 std::vector<uint8_t>::const_iterator integrityDataEnd) const
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800112{
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800113 auto output = generateHMAC(
Vernon Mauery9e801a22018-10-12 13:20:49 -0700114 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE, length);
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800115
116 // Verify if the generated integrity data for the packet and the received
117 // integrity data matches.
George Liu198b0f82022-08-04 20:22:48 +0800118 return (std::equal(output.begin(), output.end(), integrityDataBegin,
119 integrityDataEnd));
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800120}
121
Vernon Mauery9e801a22018-10-12 13:20:49 -0700122std::vector<uint8_t>
123 AlgoSHA256::generateIntegrityData(const std::vector<uint8_t>& packet) const
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800124{
125 return generateHMAC(
Vernon Mauery9e801a22018-10-12 13:20:49 -0700126 packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
127 packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE);
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800128}
129
130std::vector<uint8_t> AlgoSHA256::generateKn(const std::vector<uint8_t>& sik,
Vernon Mauery9e801a22018-10-12 13:20:49 -0700131 const rmcp::Const_n& const_n) const
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -0800132{
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
Vernon Mauery9e801a22018-10-12 13:20:49 -0700147} // namespace integrity
Tom Joseph77531db2017-01-10 15:44:44 +0530148
Vernon Mauery9e801a22018-10-12 13:20:49 -0700149} // namespace cipher