summaryrefslogtreecommitdiffstats
path: root/crypt_algo.cpp
diff options
context:
space:
mode:
authorTom Joseph <tomjoseph@in.ibm.com>2017-01-25 14:34:19 +0530
committerPatrick Williams <patrick@stwcx.xyz>2017-02-24 17:02:45 +0000
commit518eccea1365f9f6301e796382ed51c83bc5c2e7 (patch)
tree7319151d5b4e38835b22a8bb90fffa59bc53909b /crypt_algo.cpp
parent4c766eb1ec6700ca709cf39fefafdd4465165aa4 (diff)
downloadphosphor-net-ipmid-518eccea1365f9f6301e796382ed51c83bc5c2e7.tar.gz
phosphor-net-ipmid-518eccea1365f9f6301e796382ed51c83bc5c2e7.zip
Implementation of AES-CBC-128 Decryption & Encryption function
Change-Id: I4680f1eb7a19bffb9c336caf03b0aaa9ae0421fc Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
Diffstat (limited to 'crypt_algo.cpp')
-rw-r--r--crypt_algo.cpp188
1 files changed, 188 insertions, 0 deletions
diff --git a/crypt_algo.cpp b/crypt_algo.cpp
index 6bd5d94..3aab7e3 100644
--- a/crypt_algo.cpp
+++ b/crypt_algo.cpp
@@ -1,6 +1,7 @@
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
+#include <algorithm>
#include <numeric>
#include "crypt_algo.hpp"
#include "message_parsers.hpp"
@@ -25,6 +26,193 @@ Interface::Interface(const buffer& sik, const key& addKey)
}
}
+constexpr key AlgoAES128::const2;
+
+constexpr std::array<uint8_t, AlgoAES128::AESCBC128BlockSize - 1>
+ AlgoAES128::confPadBytes;
+
+buffer AlgoAES128::decryptPayload(const buffer& packet,
+ const size_t sessHeaderLen,
+ const size_t payloadLen) const
+{
+ auto plainPayload = decryptData(
+ packet.data() + sessHeaderLen,
+ packet.data() + sessHeaderLen + AESCBC128ConfHeader,
+ payloadLen - AESCBC128ConfHeader);
+
+ /*
+ * The confidentiality pad length is the last byte in the payload, it would
+ * tell the number of pad bytes in the payload. We added a condition, so
+ * that buffer overrun does't happen.
+ */
+ size_t confPadLength = plainPayload.back();
+ auto padLength = std::min(plainPayload.size() -1, confPadLength);
+
+ auto plainPayloadLen = plainPayload.size() - padLength - 1;
+
+ // Additional check if the confidentiality pad bytes are as expected
+ if(!std::equal(plainPayload.begin() + plainPayloadLen,
+ plainPayload.begin() + plainPayloadLen + padLength,
+ confPadBytes.begin()))
+ {
+ throw std::runtime_error("Confidentiality pad bytes check failed");
+ }
+
+ plainPayload.resize(plainPayloadLen);
+
+ return plainPayload;
+}
+
+buffer AlgoAES128::encryptPayload(buffer& payload) const
+{
+ auto payloadLen = payload.size();
+
+ /*
+ * The following logic calculates the number of padding bytes to be added to
+ * the payload data. This would ensure that the length is a multiple of the
+ * block size of algorithm being used. For the AES algorithm, the block size
+ * is 16 bytes.
+ */
+ auto paddingLen = AESCBC128BlockSize - ((payloadLen + 1) & 0xF);
+
+ /*
+ * The additional field is for the Confidentiality Pad Length field. For the
+ * AES algorithm, this number will range from 0 to 15 bytes. This field is
+ * mandatory.
+ */
+ payload.resize(payloadLen + paddingLen + 1);
+
+ /*
+ * If no Confidentiality Pad bytes are required, the Confidentiality Pad
+ * Length field is set to 00h. If present, the value of the first byte of
+ * Confidentiality Pad shall be one (01h) and all subsequent bytes shall
+ * have a monotonically increasing value (e.g., 02h, 03h, 04h, etc).
+ */
+ if (0 != paddingLen)
+ {
+ std::iota(payload.begin() + payloadLen,
+ payload.begin() + payloadLen + paddingLen,
+ 1);
+ }
+
+ payload.back() = paddingLen;
+
+ return encryptData(payload.data(), payload.size());
+}
+
+buffer AlgoAES128::decryptData(const uint8_t* iv,
+ const uint8_t* input,
+ const int inputLen) const
+{
+ EVP_CIPHER_CTX ctx;
+
+ // Initializes Cipher context
+ EVP_CIPHER_CTX_init(&ctx);
+
+ /*
+ * EVP_DecryptInit_ex sets up cipher context ctx for encryption with type
+ * AES-CBC-128. ctx must be initialized before calling this function. K2 is
+ * the symmetric key used and iv is the initialization vector used.
+ */
+ if (!EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, k2.data(), iv))
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ throw std::runtime_error("EVP_DecryptInit_ex failed for type "
+ "AES-CBC-128");
+ }
+
+ /*
+ * EVP_CIPHER_CTX_set_padding() enables or disables padding. If the pad
+ * parameter is zero then no padding is performed. This function always
+ * returns 1.
+ */
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ buffer output(inputLen + AESCBC128BlockSize);
+
+ int outputLen = 0;
+
+ /*
+ * If padding is disabled then EVP_DecryptFinal_ex() will not encrypt any
+ * more data and it will return an error if any data remains in a partial
+ * block: that is if the total data length is not a multiple of the block
+ * size. Since AES-CBC-128 encrypted payload format adds padding bytes and
+ * ensures that payload is a multiple of block size, we are not making the
+ * call to EVP_DecryptFinal_ex().
+ */
+ if (!EVP_DecryptUpdate(&ctx, output.data(), &outputLen, input, inputLen))
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ throw std::runtime_error("EVP_DecryptUpdate failed");
+ }
+
+ output.resize(outputLen);
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ return output;
+}
+
+buffer AlgoAES128::encryptData(const uint8_t* input, const int inputLen) const
+{
+ buffer output(inputLen + AESCBC128BlockSize);
+
+ // Generate the initialization vector
+ if (!RAND_bytes(output.data(), AESCBC128ConfHeader))
+ {
+ throw std::runtime_error("RAND_bytes failed");
+ }
+
+ EVP_CIPHER_CTX ctx;
+
+ // Initializes Cipher context
+ EVP_CIPHER_CTX_init(&ctx);
+
+ /*
+ * EVP_EncryptInit_ex sets up cipher context ctx for encryption with type
+ * AES-CBC-128. ctx must be initialized before calling this function. K2 is
+ * the symmetric key used and iv is the initialization vector used.
+ */
+ if (!EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, k2.data(),
+ output.data()))
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ throw std::runtime_error("EVP_EncryptInit_ex failed for type "
+ "AES-CBC-128");
+ }
+
+ /*
+ * EVP_CIPHER_CTX_set_padding() enables or disables padding. If the pad
+ * parameter is zero then no padding is performed. This function always
+ * returns 1.
+ */
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ int outputLen = 0;
+
+ /*
+ * If padding is disabled then EVP_EncryptFinal_ex() will not encrypt any
+ * more data and it will return an error if any data remains in a partial
+ * block: that is if the total data length is not a multiple of the block
+ * size. Since we are adding padding bytes and ensures that payload is a
+ * multiple of block size, we are not making the call to
+ * EVP_DecryptFinal_ex()
+ */
+ if (!EVP_EncryptUpdate(&ctx,
+ output.data() + AESCBC128ConfHeader,
+ &outputLen,
+ input, inputLen))
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ throw std::runtime_error("EVP_EncryptUpdate failed for type "
+ "AES-CBC-128");
+ }
+
+ output.resize(AESCBC128ConfHeader + outputLen);
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ return output;
+}
+
}// namespace crypt
}// namespace cipher
OpenPOWER on IntegriCloud