Implementation of HMAC-SHA1-96 Integrity Algorithm

Change-Id: Id301f0cb6e7cc9cde79385a18f3999d8d9c0feab
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
diff --git a/integrity_algo.cpp b/integrity_algo.cpp
index b765e06..16d0863 100644
--- a/integrity_algo.cpp
+++ b/integrity_algo.cpp
@@ -25,6 +25,47 @@
     authCodeLength = authLength;
 }
 
+Buffer AlgoSHA1::generateHMAC(const uint8_t* input, const size_t len) const
+{
+    Buffer output(SHA_DIGEST_LENGTH);
+    unsigned int mdLen = 0;
+
+    if (HMAC(EVP_sha1(), K1.data(), K1.size(), input, len,
+             output.data(), &mdLen) == NULL)
+    {
+        throw std::runtime_error("Generating integrity data failed");
+    }
+
+    // HMAC generates Message Digest to the size of SHA_DIGEST_LENGTH, the
+    // AuthCode field length is based on the integrity algorithm. So we are
+    // interested only in the AuthCode field length of the generated Message
+    // digest.
+    output.resize(authCodeLength);
+
+    return output;
+}
+
+bool AlgoSHA1::verifyIntegrityData(const Buffer& packet,
+                                   const size_t length,
+                                   Buffer::const_iterator integrityData) const
+{
+
+    auto output = generateHMAC(
+            packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
+            length);
+
+    // Verify if the generated integrity data for the packet and the received
+    // integrity data matches.
+    return (std::equal(output.begin(), output.end(), integrityData));
+}
+
+Buffer AlgoSHA1::generateIntegrityData(const Buffer& packet) const
+{
+    return generateHMAC(
+            packet.data() + message::parser::RMCP_SESSION_HEADER_SIZE,
+            packet.size() - message::parser::RMCP_SESSION_HEADER_SIZE);
+}
+
 }// namespace integrity
 
 }// namespace cipher
diff --git a/integrity_algo.hpp b/integrity_algo.hpp
index b9d935a..ac06e06 100644
--- a/integrity_algo.hpp
+++ b/integrity_algo.hpp
@@ -115,6 +115,76 @@
         Key K1;
 };
 
+/*
+ * @class AlgoSHA1
+ *
+ * @brief Implementation of the HMAC-SHA1-96 Integrity algorithm
+ *
+ * HMAC-SHA1-96 take the Session Integrity Key and use it to generate K1. K1 is
+ * then used as the key for use in HMAC to produce the AuthCode field.
+ * For “one-key” logins, the user’s key (password) is used in the creation of
+ * the Session Integrity Key. When the HMAC-SHA1-96 Integrity Algorithm is used
+ * the resulting AuthCode field is 12 bytes (96 bits).
+ */
+class AlgoSHA1 final : public Interface
+{
+    public:
+        static constexpr size_t SHA1_96_AUTHCODE_LENGTH = 12;
+
+        /*
+         * @brief Constructor for AlgoSHA1
+         *
+         * @param[in] - Session Integrity Key
+         */
+        explicit AlgoSHA1(const Buffer& sik) :
+            Interface(sik, const1, SHA1_96_AUTHCODE_LENGTH) {}
+
+        AlgoSHA1() = delete;
+        ~AlgoSHA1() = default;
+        AlgoSHA1(const AlgoSHA1&) = default;
+        AlgoSHA1& operator=(const AlgoSHA1&) = default;
+        AlgoSHA1(AlgoSHA1&&) = default;
+        AlgoSHA1& operator=(AlgoSHA1&&) = default;
+
+        /*
+         * @brief Verify the integrity data of the packet
+         *
+         * @param[in] packet - Incoming IPMI packet
+         * @param[in] length - Length of the data in the packet to calculate
+         *                     the integrity data
+         * @param[in] integrityData - Iterator to the authCode in the packet
+         *
+         * @return true if authcode in the packet is equal to one generated
+         *         using integrity algorithm on the packet data, false otherwise
+         */
+        bool verifyIntegrityData(
+                const Buffer& packet,
+                const size_t length,
+                Buffer::const_iterator integrityData) const override;
+
+        /*
+         * @brief Generate integrity data for the outgoing IPMI packet
+         *
+         * @param[in] input - Outgoing IPMI packet
+         *
+         * @return on success return the integrity data for the outgoing IPMI
+         *         packet
+         */
+        Buffer generateIntegrityData(const Buffer& packet) const override;
+
+    private:
+        /*
+         * @brief Generate HMAC based on HMAC-SHA1-96 algorithm
+         *
+         * @param[in] input - pointer to the message
+         * @param[in] length - length of the message
+         *
+         * @return on success returns the message authentication code
+         *
+         */
+        Buffer generateHMAC(const uint8_t* input, const size_t len) const;
+};
+
 }// namespace integrity
 
 }// namespace cipher