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