xref: /openbmc/phosphor-net-ipmid/integrity_algo.cpp (revision 7e9e2ef68a1c53e022970d85566945d5bdc5a78e)
19b307be6SVernon Mauery #include <openssl/evp.h>
277531db5STom Joseph #include <openssl/hmac.h>
377531db5STom Joseph #include <openssl/sha.h>
477531db5STom Joseph #include "integrity_algo.hpp"
577531db5STom Joseph #include "message_parsers.hpp"
677531db5STom Joseph 
777531db5STom Joseph namespace cipher
877531db5STom Joseph {
977531db5STom Joseph 
1077531db5STom Joseph namespace integrity
1177531db5STom Joseph {
1277531db5STom Joseph 
139b307be6SVernon Mauery AlgoSHA1::AlgoSHA1(const std::vector<uint8_t>& sik)
149b307be6SVernon Mauery     : Interface(SHA1_96_AUTHCODE_LENGTH)
1577531db5STom Joseph {
169b307be6SVernon Mauery     k1 = generateKn(sik, rmcp::const_1);
1777531db5STom Joseph }
1877531db5STom Joseph 
1970fd29cfSVernon Mauery std::vector<uint8_t> AlgoSHA1::generateHMAC(const uint8_t* input,
2070fd29cfSVernon Mauery         const size_t len) const
21d212a6dcSTom Joseph {
2270fd29cfSVernon Mauery     std::vector<uint8_t> output(SHA_DIGEST_LENGTH);
23d212a6dcSTom Joseph     unsigned int mdLen = 0;
24d212a6dcSTom Joseph 
259b307be6SVernon Mauery     if (HMAC(EVP_sha1(), k1.data(), k1.size(), input, len,
26d212a6dcSTom Joseph              output.data(), &mdLen) == NULL)
27d212a6dcSTom Joseph     {
28d212a6dcSTom Joseph         throw std::runtime_error("Generating integrity data failed");
29d212a6dcSTom Joseph     }
30d212a6dcSTom Joseph 
31d212a6dcSTom Joseph     // HMAC generates Message Digest to the size of SHA_DIGEST_LENGTH, the
32d212a6dcSTom Joseph     // AuthCode field length is based on the integrity algorithm. So we are
33d212a6dcSTom Joseph     // interested only in the AuthCode field length of the generated Message
34d212a6dcSTom Joseph     // digest.
35d212a6dcSTom Joseph     output.resize(authCodeLength);
36d212a6dcSTom Joseph 
37d212a6dcSTom Joseph     return output;
38d212a6dcSTom Joseph }
39d212a6dcSTom Joseph 
4070fd29cfSVernon Mauery bool AlgoSHA1::verifyIntegrityData(
4170fd29cfSVernon Mauery         const std::vector<uint8_t>& packet,
42d212a6dcSTom Joseph         const size_t length,
4370fd29cfSVernon Mauery         std::vector<uint8_t>::const_iterator integrityData) const
44d212a6dcSTom Joseph {
45d212a6dcSTom Joseph 
46d212a6dcSTom Joseph     auto output = generateHMAC(
47d212a6dcSTom Joseph             packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
48d212a6dcSTom Joseph             length);
49d212a6dcSTom Joseph 
50d212a6dcSTom Joseph     // Verify if the generated integrity data for the packet and the received
51d212a6dcSTom Joseph     // integrity data matches.
52d212a6dcSTom Joseph     return (std::equal(output.begin(), output.end(), integrityData));
53d212a6dcSTom Joseph }
54d212a6dcSTom Joseph 
5570fd29cfSVernon Mauery std::vector<uint8_t> AlgoSHA1::generateIntegrityData(
5670fd29cfSVernon Mauery         const std::vector<uint8_t>& packet) const
57d212a6dcSTom Joseph {
58d212a6dcSTom Joseph     return generateHMAC(
59d212a6dcSTom Joseph             packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
60d212a6dcSTom Joseph             packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE);
61d212a6dcSTom Joseph }
62d212a6dcSTom Joseph 
639b307be6SVernon Mauery std::vector<uint8_t> AlgoSHA1::generateKn(const std::vector<uint8_t>& sik,
649b307be6SVernon Mauery         const rmcp::Const_n& const_n) const
659b307be6SVernon Mauery {
669b307be6SVernon Mauery     unsigned int mdLen = 0;
679b307be6SVernon Mauery     std::vector<uint8_t> Kn(sik.size());
689b307be6SVernon Mauery 
699b307be6SVernon Mauery     // Generated Kn for the integrity algorithm with the additional key keyed
709b307be6SVernon Mauery     // with SIK.
719b307be6SVernon Mauery     if (HMAC(EVP_sha1(), sik.data(), sik.size(), const_n.data(),
729b307be6SVernon Mauery              const_n.size(), Kn.data(), &mdLen) == NULL)
739b307be6SVernon Mauery     {
749b307be6SVernon Mauery         throw std::runtime_error("Generating KeyN for integrity "
759b307be6SVernon Mauery                                  "algorithm failed");
769b307be6SVernon Mauery     }
779b307be6SVernon Mauery     return Kn;
789b307be6SVernon Mauery }
799b307be6SVernon Mauery 
80*7e9e2ef6SVernon Mauery AlgoSHA256::AlgoSHA256(const std::vector<uint8_t>& sik)
81*7e9e2ef6SVernon Mauery     : Interface(SHA256_128_AUTHCODE_LENGTH)
82*7e9e2ef6SVernon Mauery {
83*7e9e2ef6SVernon Mauery     k1 = generateKn(sik, rmcp::const_1);
84*7e9e2ef6SVernon Mauery }
85*7e9e2ef6SVernon Mauery 
86*7e9e2ef6SVernon Mauery std::vector<uint8_t> AlgoSHA256::generateHMAC(const uint8_t* input,
87*7e9e2ef6SVernon Mauery         const size_t len) const
88*7e9e2ef6SVernon Mauery {
89*7e9e2ef6SVernon Mauery     std::vector<uint8_t> output(SHA256_DIGEST_LENGTH);
90*7e9e2ef6SVernon Mauery     unsigned int mdLen = 0;
91*7e9e2ef6SVernon Mauery 
92*7e9e2ef6SVernon Mauery     if (HMAC(EVP_sha256(), k1.data(), k1.size(), input, len,
93*7e9e2ef6SVernon Mauery              output.data(), &mdLen) == NULL)
94*7e9e2ef6SVernon Mauery     {
95*7e9e2ef6SVernon Mauery         throw std::runtime_error("Generating HMAC_SHA256_128 failed");
96*7e9e2ef6SVernon Mauery     }
97*7e9e2ef6SVernon Mauery 
98*7e9e2ef6SVernon Mauery     // HMAC generates Message Digest to the size of SHA256_DIGEST_LENGTH, the
99*7e9e2ef6SVernon Mauery     // AuthCode field length is based on the integrity algorithm. So we are
100*7e9e2ef6SVernon Mauery     // interested only in the AuthCode field length of the generated Message
101*7e9e2ef6SVernon Mauery     // digest.
102*7e9e2ef6SVernon Mauery     output.resize(authCodeLength);
103*7e9e2ef6SVernon Mauery 
104*7e9e2ef6SVernon Mauery     return output;
105*7e9e2ef6SVernon Mauery }
106*7e9e2ef6SVernon Mauery 
107*7e9e2ef6SVernon Mauery bool AlgoSHA256::verifyIntegrityData(
108*7e9e2ef6SVernon Mauery         const std::vector<uint8_t>& packet,
109*7e9e2ef6SVernon Mauery         const size_t length,
110*7e9e2ef6SVernon Mauery         std::vector<uint8_t>::const_iterator integrityData) const
111*7e9e2ef6SVernon Mauery {
112*7e9e2ef6SVernon Mauery 
113*7e9e2ef6SVernon Mauery     auto output = generateHMAC(
114*7e9e2ef6SVernon Mauery             packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
115*7e9e2ef6SVernon Mauery             length);
116*7e9e2ef6SVernon Mauery 
117*7e9e2ef6SVernon Mauery     // Verify if the generated integrity data for the packet and the received
118*7e9e2ef6SVernon Mauery     // integrity data matches.
119*7e9e2ef6SVernon Mauery     return (std::equal(output.begin(), output.end(), integrityData));
120*7e9e2ef6SVernon Mauery }
121*7e9e2ef6SVernon Mauery 
122*7e9e2ef6SVernon Mauery std::vector<uint8_t> AlgoSHA256::generateIntegrityData(
123*7e9e2ef6SVernon Mauery         const std::vector<uint8_t>& packet) const
124*7e9e2ef6SVernon Mauery {
125*7e9e2ef6SVernon Mauery     return generateHMAC(
126*7e9e2ef6SVernon Mauery             packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
127*7e9e2ef6SVernon Mauery             packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE);
128*7e9e2ef6SVernon Mauery }
129*7e9e2ef6SVernon Mauery 
130*7e9e2ef6SVernon Mauery std::vector<uint8_t> AlgoSHA256::generateKn(const std::vector<uint8_t>& sik,
131*7e9e2ef6SVernon Mauery         const rmcp::Const_n& const_n) const
132*7e9e2ef6SVernon Mauery {
133*7e9e2ef6SVernon Mauery     unsigned int mdLen = 0;
134*7e9e2ef6SVernon Mauery     std::vector<uint8_t> Kn(sik.size());
135*7e9e2ef6SVernon Mauery 
136*7e9e2ef6SVernon Mauery     // Generated Kn for the integrity algorithm with the additional key keyed
137*7e9e2ef6SVernon Mauery     // with SIK.
138*7e9e2ef6SVernon Mauery     if (HMAC(EVP_sha256(), sik.data(), sik.size(), const_n.data(),
139*7e9e2ef6SVernon Mauery              const_n.size(), Kn.data(), &mdLen) == NULL)
140*7e9e2ef6SVernon Mauery     {
141*7e9e2ef6SVernon Mauery         throw std::runtime_error("Generating KeyN for integrity "
142*7e9e2ef6SVernon Mauery                                  "algorithm HMAC_SHA256 failed");
143*7e9e2ef6SVernon Mauery     }
144*7e9e2ef6SVernon Mauery     return Kn;
145*7e9e2ef6SVernon Mauery }
146*7e9e2ef6SVernon Mauery 
14777531db5STom Joseph }// namespace integrity
14877531db5STom Joseph 
14977531db5STom Joseph }// namespace cipher
150