From e02f4507fcf5f3df4e811ca780485a07c04badbf Mon Sep 17 00:00:00 2001 From: Michele Rodolfi Date: Sun, 13 Dec 2020 22:15:30 +0100 Subject: [PATCH] Add doxygen style comments --- src/crypto.cpp | 31 ++++----- src/crypto.h | 161 ++++++++++++++++++++++++++++++++++++++----- test/crypto-test.cpp | 10 ++- 3 files changed, 159 insertions(+), 43 deletions(-) diff --git a/src/crypto.cpp b/src/crypto.cpp index c52766b..cbb06c1 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -12,7 +12,9 @@ #include "utils.h" namespace horcrux { - +/** Cipher context class + * This is a wrapper for OpenSSL context object, just for RAII pattern + */ class EvpCipherCtx { EVP_CIPHER_CTX *ptr; @@ -158,15 +160,7 @@ std::vector AES256_CBC::encrypt( return output; } - -int AES256_CBC::encrypt(const std::vector& key, - const std::vector& iv, - const std::vector& input, - std::vector& output) { - auto ctx = init(Mode::kEncrypt, key, iv); - process_all(Mode::kEncrypt, ctx, input.begin(), input.end(), output, 0); - return 0; -} +/* int AES256_CBC::encrypt(const std::vector& key, const std::vector& iv, @@ -183,14 +177,7 @@ int AES256_CBC::encrypt(const std::vector& key, return 0; } -int AES256_CBC::decrypt(const std::vector& key, - const std::vector& iv, - const std::vector& input, - std::vector& output) { - auto ctx = init(Mode::kDecrypt, key, iv); - process_all(Mode::kDecrypt, ctx, input.begin(), input.end(), output, 0); - return 0; -} +*/ std::vector AES256_CBC::decrypt( const std::vector& key, const std::vector& ciphertext) { @@ -198,6 +185,14 @@ std::vector AES256_CBC::decrypt( ciphertext.begin() + kIvSize); return decrypt(key, iv, ciphertext.begin() + kIvSize, ciphertext.end()); } + +std::vector AES256_CBC::decrypt( + const std::vector& key, + const std::vector& iv, + const std::vector& ciphertext) { + return decrypt(key, iv, ciphertext.begin(), ciphertext.end()); +} + std::vector AES256_CBC::decrypt( const std::vector& key, const std::vector& iv, diff --git a/src/crypto.h b/src/crypto.h index 039771c..95587c4 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -10,89 +10,171 @@ namespace horcrux { enum class Mode { kEncrypt, kDecrypt }; +/** @brief Base Class for Ciphers. + * @details Derive from this class to add other Cipher implementations + */ class Cipher { public: + /** @brief default constructor */ Cipher() = delete; + + /** @brief create Cipher + * @param m Cipher mode (encrypt/decrypt) */ explicit Cipher(Mode m) : mode(m) { } + + /** @brief create Cipher + * @param m Cipher mode (encrypt/decrypt) + * @param key use provided key for encryption/decryption */ Cipher(Mode m, const std::vector& key) : mode(m), encryption_key(key) {} - Cipher(Mode m, std::vector&& key) : - mode(m), encryption_key(key) {} - + /** @brief default destructor */ virtual ~Cipher() = default; protected: + /** @brief key used for encryption / decryption */ std::vector encryption_key; public: + /** @brief Cipher mode (encrypt or decrypt) */ const Mode mode; + + /** @brief get Cipher encryption key + * @return the encryption key + */ const std::vector& get_encryption_key() { return encryption_key; } + /** @brief process inputdata according to Cipher mode + * @param inputdata buffer containing data to process + * @return processed data + */ virtual std::vector process( const std::vector& inputdata) = 0; + /** @brief encrypt the content of a buffer using Cipher key + * @param plaintext the input buffer + * @return encrypted data + */ virtual std::vector encrypt( const std::vector& plaintext) = 0; + /** @brief decrypt the content of a buffer using Cipher key + * @param decrypt the input buffer + * @return decrypted data + */ virtual std::vector decrypt( const std::vector& ciphertext) = 0; }; +// forward declaration class EvpCipherCtx; + +/** @brief AES256 Cipher + * @details + * This Cipher uses an encryption key and an initilization vector. + * The initialization vector is as large as the cipher block size (16 bytes). + * The initialization vector is stored as the first 16 bytes of the encrypted + * data and it is always randomly generated in order to always produce different + * encrypted data. + * The encryption key must be kept secret and it is randomly generated if not + * provided + * The encrypted data is always slightly bigger than the plaintext data because + * it contains the initialization vector at the beginning and it may cointain + * some cipher block padding at the end. + */ class AES256_CBC : public Cipher { + /** AES256 CBC key size, from AES256 specs */ const size_t kKeySize = 32; + /** AES256 CBC initialization vector size, from AES256 specs */ const size_t kIvSize = 16; public: + /** @brief Create cipher in encrypt mode with random key */ AES256_CBC() : Cipher(Mode::kEncrypt) { encryption_key = horcrux::generate_random(kKeySize); } + /** @brief Create cipher in decrypt mode using provided key + * @param key 256 bit key + */ explicit AES256_CBC(const std::vector& key) : Cipher(Mode::kDecrypt, key) { if (key.size() != kKeySize) throw std::invalid_argument("Invalid key size"); } - explicit AES256_CBC(std::vector&& key) - : Cipher(Mode::kDecrypt, key) { - if (key.size() != kKeySize) - throw std::invalid_argument("Invalid key size"); - } - + /** @brief default virtual destructor */ virtual ~AES256_CBC() = default; + /** @brief process inputdata according to Cipher mode + * @param inputdata buffer containing data to process + * @return processed data + */ std::vector process( const std::vector& inputdata) override; + + /** @brief encrypt the content of a buffer using Cipher key + * @param plaintext the input buffer + * @return encrypted data + */ std::vector encrypt( const std::vector& plaintext) override; + + /** @brief decrypt the content of a buffer using Cipher key + * @param decrypt the input buffer + * @return decrypted data + */ std::vector decrypt( const std::vector& ciphertext) override; + /** @brief Read the whole input and return a buffer with the encrypted data + * @param key the encryption key + * @param iv the initialization vector that will be copied to the beginning + * of the output + * @param input the input buffer + * @return the encrypted data buffer + */ std::vector encrypt(const std::vector& key, const std::vector& iv, const std::vector& input); - int encrypt(const std::vector& key, - const std::vector& iv, - const std::vector& input, - std::vector& output); - +/* int encrypt(const std::vector& key, const std::vector& iv, std::istream input, const size_t input_len, std::ostream output, size_t& output_len); - int decrypt(const std::vector& key, - const std::vector& iv, - const std::vector& input, - std::vector& output); - +*/ + /** @brief Read the whole input and return a buffer with the decrypted data. + * Read the iv from the beginning of ciphertext + * @param key the encryption key + * @param ciphertext the input buffer + * @return the encrypted data buffer + */ std::vector decrypt( const std::vector& key, const std::vector& ciphertext); + /** @brief Read the whole input and return a buffer with the decrypted data. + * ciphertext does not contain the iv. + * @param key the encryption key + * @param iv the initialization vector + * @param ciphertext the input buffer + * @return the encrypted data buffer + */ + std::vector decrypt( + const std::vector& key, + const std::vector& iv, + const std::vector& ciphertext); + + /** @brief Read some input from begin to end and return a buffer with the + * decrypted data. Output data is finalized. + * @param key the encryption key + * @param iv the initialization vector + * @param begin beginning of the input buffer + * @param end end of the input buffer + * @return the encrypted data buffer + */ std::vector decrypt( const std::vector& key, const std::vector& iv, @@ -100,9 +182,27 @@ public: std::vector::const_iterator end); private: + /** @brief Create a Cipher context object needed for enc/dec operations + * @param mode encrypt or decrypt + * @param key the enc/dec key + * @param the initialization vector + * @return the Cipher context object + */ EvpCipherCtx init(Mode mode, const std::vector& key, const std::vector& iv); + /** @brief process a chunk of input + * @param mode encrypt or decrypt + * @param ctx the Cipher context object + * @param begin beginning of the input chunk + * @param end end of the input chunk + * @param output output buffer + * @param output_offset where to start to append the processed data within + * the output buffer + * @param resize_in resize the output buffer before appending data to it in + * order to make sure there is enough room. + * @param resize_out shrink the output buffer at the end + */ size_t process_chunk(Mode mode, EvpCipherCtx& ctx, std::vector::const_iterator begin, std::vector::const_iterator end, @@ -110,11 +210,34 @@ private: size_t output_offset, bool resize_in = true, bool resize_out = true); + /** @brief Finalize a encryption/decryption process. Write remaining bytes + * to the output + * @param mode encrypt or decrypt + * @param ctx the Cipher context object + * @param output output buffer + * @param output_offset where to start to append the last data within + * the output buffer + * @param resize_in resize the output buffer before appending data to it in + * order to make sure there is enough room. + * @param resize_out shrink the output buffer at the end + */ size_t process_final(Mode mode, EvpCipherCtx& ctx, std::vector& output, size_t output_offset, bool resize_in = true, bool resize_out = true); + /** @brief process a input and finalize it. + * @param mode encrypt or decrypt + * @param ctx the Cipher context object + * @param begin beginning of the input chunk + * @param end end of the input chunk + * @param output output buffer + * @param output_offset where to start to append the processed data within + * the output buffer + * @param resize_in resize the output buffer before appending data to it in + * order to make sure there is enough room. + * @param resize_out shrink the output buffer at the end + */ size_t process_all(Mode mode, EvpCipherCtx& ctx, std::vector::const_iterator begin, std::vector::const_iterator end, diff --git a/test/crypto-test.cpp b/test/crypto-test.cpp index 05cd05c..907ffbc 100644 --- a/test/crypto-test.cpp +++ b/test/crypto-test.cpp @@ -7,13 +7,13 @@ using namespace horcrux; TEST(CryptoTest, encrypt1){ const std::vector plaintext(test1_str.begin(), test1_str.end()); - size_t output_len = plaintext.size() + 16; - std::vector output(output_len); const std::vector key(test1_key.begin(), test1_key.end()); const std::vector iv(test1_iv.begin(), test1_iv.end()); AES256_CBC a; - a.encrypt(key, iv, plaintext, output); + auto output = a.encrypt(key, iv, plaintext); + //remove iv from output + output.erase(output.begin(), output.begin() + iv.size()); EXPECT_EQ(test1_enc, output); } @@ -51,13 +51,11 @@ TEST(CryptoTest, encrypt3){ TEST(CryptoTest, decrypt1){ const std::vector plaintext(test1_str.begin(), test1_str.end()); - size_t output_len = test1_enc.size(); - std::vector output(output_len); const std::vector key(test1_key.begin(), test1_key.end()); const std::vector iv(test1_iv.begin(), test1_iv.end()); AES256_CBC a; - a.decrypt(key, iv, test1_enc, output); + auto output = a.decrypt(key, iv, test1_enc); EXPECT_EQ(plaintext, output); }