Add doxygen style comments

This commit is contained in:
Michele Rodolfi 2020-12-13 22:15:30 +01:00
parent aa6f287a19
commit e02f4507fc
3 changed files with 159 additions and 43 deletions

View File

@ -12,7 +12,9 @@
#include "utils.h" #include "utils.h"
namespace horcrux { namespace horcrux {
/** Cipher context class
* This is a wrapper for OpenSSL context object, just for RAII pattern
*/
class EvpCipherCtx { class EvpCipherCtx {
EVP_CIPHER_CTX *ptr; EVP_CIPHER_CTX *ptr;
@ -158,15 +160,7 @@ std::vector<unsigned char> AES256_CBC::encrypt(
return output; return output;
} }
/*
int AES256_CBC::encrypt(const std::vector<unsigned char>& key,
const std::vector<unsigned char>& iv,
const std::vector<unsigned char>& input,
std::vector<unsigned char>& 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<unsigned char>& key, int AES256_CBC::encrypt(const std::vector<unsigned char>& key,
const std::vector<unsigned char>& iv, const std::vector<unsigned char>& iv,
@ -183,14 +177,7 @@ int AES256_CBC::encrypt(const std::vector<unsigned char>& key,
return 0; return 0;
} }
int AES256_CBC::decrypt(const std::vector<unsigned char>& key, */
const std::vector<unsigned char>& iv,
const std::vector<unsigned char>& input,
std::vector<unsigned char>& output) {
auto ctx = init(Mode::kDecrypt, key, iv);
process_all(Mode::kDecrypt, ctx, input.begin(), input.end(), output, 0);
return 0;
}
std::vector<unsigned char> AES256_CBC::decrypt( std::vector<unsigned char> AES256_CBC::decrypt(
const std::vector<unsigned char>& key, const std::vector<unsigned char>& key,
const std::vector<unsigned char>& ciphertext) { const std::vector<unsigned char>& ciphertext) {
@ -198,6 +185,14 @@ std::vector<unsigned char> AES256_CBC::decrypt(
ciphertext.begin() + kIvSize); ciphertext.begin() + kIvSize);
return decrypt(key, iv, ciphertext.begin() + kIvSize, ciphertext.end()); return decrypt(key, iv, ciphertext.begin() + kIvSize, ciphertext.end());
} }
std::vector<unsigned char> AES256_CBC::decrypt(
const std::vector<unsigned char>& key,
const std::vector<unsigned char>& iv,
const std::vector<unsigned char>& ciphertext) {
return decrypt(key, iv, ciphertext.begin(), ciphertext.end());
}
std::vector<unsigned char> AES256_CBC::decrypt( std::vector<unsigned char> AES256_CBC::decrypt(
const std::vector<unsigned char>& key, const std::vector<unsigned char>& key,
const std::vector<unsigned char>& iv, const std::vector<unsigned char>& iv,

View File

@ -10,89 +10,171 @@ namespace horcrux {
enum class Mode { kEncrypt, kDecrypt }; enum class Mode { kEncrypt, kDecrypt };
/** @brief Base Class for Ciphers.
* @details Derive from this class to add other Cipher implementations
*/
class Cipher { class Cipher {
public: public:
/** @brief default constructor */
Cipher() = delete; Cipher() = delete;
/** @brief create Cipher
* @param m Cipher mode (encrypt/decrypt) */
explicit Cipher(Mode m) : mode(m) { } 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<unsigned char>& key) : Cipher(Mode m, const std::vector<unsigned char>& key) :
mode(m), encryption_key(key) {} mode(m), encryption_key(key) {}
Cipher(Mode m, std::vector<unsigned char>&& key) : /** @brief default destructor */
mode(m), encryption_key(key) {}
virtual ~Cipher() = default; virtual ~Cipher() = default;
protected: protected:
/** @brief key used for encryption / decryption */
std::vector<unsigned char> encryption_key; std::vector<unsigned char> encryption_key;
public: public:
/** @brief Cipher mode (encrypt or decrypt) */
const Mode mode; const Mode mode;
/** @brief get Cipher encryption key
* @return the encryption key
*/
const std::vector<unsigned char>& get_encryption_key() { const std::vector<unsigned char>& get_encryption_key() {
return 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<unsigned char> process( virtual std::vector<unsigned char> process(
const std::vector<unsigned char>& inputdata) = 0; const std::vector<unsigned char>& inputdata) = 0;
/** @brief encrypt the content of a buffer using Cipher key
* @param plaintext the input buffer
* @return encrypted data
*/
virtual std::vector<unsigned char> encrypt( virtual std::vector<unsigned char> encrypt(
const std::vector<unsigned char>& plaintext) = 0; const std::vector<unsigned char>& plaintext) = 0;
/** @brief decrypt the content of a buffer using Cipher key
* @param decrypt the input buffer
* @return decrypted data
*/
virtual std::vector<unsigned char> decrypt( virtual std::vector<unsigned char> decrypt(
const std::vector<unsigned char>& ciphertext) = 0; const std::vector<unsigned char>& ciphertext) = 0;
}; };
// forward declaration
class EvpCipherCtx; 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 { class AES256_CBC : public Cipher {
/** AES256 CBC key size, from AES256 specs */
const size_t kKeySize = 32; const size_t kKeySize = 32;
/** AES256 CBC initialization vector size, from AES256 specs */
const size_t kIvSize = 16; const size_t kIvSize = 16;
public: public:
/** @brief Create cipher in encrypt mode with random key */
AES256_CBC() : Cipher(Mode::kEncrypt) { AES256_CBC() : Cipher(Mode::kEncrypt) {
encryption_key = horcrux::generate_random(kKeySize); 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<unsigned char>& key) explicit AES256_CBC(const std::vector<unsigned char>& key)
: Cipher(Mode::kDecrypt, key) { : Cipher(Mode::kDecrypt, key) {
if (key.size() != kKeySize) if (key.size() != kKeySize)
throw std::invalid_argument("Invalid key size"); throw std::invalid_argument("Invalid key size");
} }
explicit AES256_CBC(std::vector<unsigned char>&& key) /** @brief default virtual destructor */
: Cipher(Mode::kDecrypt, key) {
if (key.size() != kKeySize)
throw std::invalid_argument("Invalid key size");
}
virtual ~AES256_CBC() = default; virtual ~AES256_CBC() = default;
/** @brief process inputdata according to Cipher mode
* @param inputdata buffer containing data to process
* @return processed data
*/
std::vector<unsigned char> process( std::vector<unsigned char> process(
const std::vector<unsigned char>& inputdata) override; const std::vector<unsigned char>& inputdata) override;
/** @brief encrypt the content of a buffer using Cipher key
* @param plaintext the input buffer
* @return encrypted data
*/
std::vector<unsigned char> encrypt( std::vector<unsigned char> encrypt(
const std::vector<unsigned char>& plaintext) override; const std::vector<unsigned char>& plaintext) override;
/** @brief decrypt the content of a buffer using Cipher key
* @param decrypt the input buffer
* @return decrypted data
*/
std::vector<unsigned char> decrypt( std::vector<unsigned char> decrypt(
const std::vector<unsigned char>& ciphertext) override; const std::vector<unsigned char>& 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<unsigned char> encrypt(const std::vector<unsigned char>& key, std::vector<unsigned char> encrypt(const std::vector<unsigned char>& key,
const std::vector<unsigned char>& iv, const std::vector<unsigned char>& iv,
const std::vector<unsigned char>& input); const std::vector<unsigned char>& input);
int encrypt(const std::vector<unsigned char>& key, /*
const std::vector<unsigned char>& iv,
const std::vector<unsigned char>& input,
std::vector<unsigned char>& output);
int encrypt(const std::vector<unsigned char>& key, int encrypt(const std::vector<unsigned char>& key,
const std::vector<unsigned char>& iv, const std::vector<unsigned char>& iv,
std::istream input, const size_t input_len, std::istream input, const size_t input_len,
std::ostream output, size_t& output_len); std::ostream output, size_t& output_len);
int decrypt(const std::vector<unsigned char>& key, */
const std::vector<unsigned char>& iv, /** @brief Read the whole input and return a buffer with the decrypted data.
const std::vector<unsigned char>& input, * Read the iv from the beginning of ciphertext
std::vector<unsigned char>& output); * @param key the encryption key
* @param ciphertext the input buffer
* @return the encrypted data buffer
*/
std::vector<unsigned char> decrypt( std::vector<unsigned char> decrypt(
const std::vector<unsigned char>& key, const std::vector<unsigned char>& key,
const std::vector<unsigned char>& ciphertext); const std::vector<unsigned char>& 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<unsigned char> decrypt(
const std::vector<unsigned char>& key,
const std::vector<unsigned char>& iv,
const std::vector<unsigned char>& 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<unsigned char> decrypt( std::vector<unsigned char> decrypt(
const std::vector<unsigned char>& key, const std::vector<unsigned char>& key,
const std::vector<unsigned char>& iv, const std::vector<unsigned char>& iv,
@ -100,9 +182,27 @@ public:
std::vector<unsigned char>::const_iterator end); std::vector<unsigned char>::const_iterator end);
private: 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<unsigned char>& key, EvpCipherCtx init(Mode mode, const std::vector<unsigned char>& key,
const std::vector<unsigned char>& iv); const std::vector<unsigned char>& 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, size_t process_chunk(Mode mode, EvpCipherCtx& ctx,
std::vector<unsigned char>::const_iterator begin, std::vector<unsigned char>::const_iterator begin,
std::vector<unsigned char>::const_iterator end, std::vector<unsigned char>::const_iterator end,
@ -110,11 +210,34 @@ private:
size_t output_offset, size_t output_offset,
bool resize_in = true, bool resize_out = true); 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, size_t process_final(Mode mode, EvpCipherCtx& ctx,
std::vector<unsigned char>& output, std::vector<unsigned char>& output,
size_t output_offset, size_t output_offset,
bool resize_in = true, bool resize_out = true); 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, size_t process_all(Mode mode, EvpCipherCtx& ctx,
std::vector<unsigned char>::const_iterator begin, std::vector<unsigned char>::const_iterator begin,
std::vector<unsigned char>::const_iterator end, std::vector<unsigned char>::const_iterator end,

View File

@ -7,13 +7,13 @@
using namespace horcrux; using namespace horcrux;
TEST(CryptoTest, encrypt1){ TEST(CryptoTest, encrypt1){
const std::vector<unsigned char> plaintext(test1_str.begin(), test1_str.end()); const std::vector<unsigned char> plaintext(test1_str.begin(), test1_str.end());
size_t output_len = plaintext.size() + 16;
std::vector<unsigned char> output(output_len);
const std::vector<unsigned char> key(test1_key.begin(), test1_key.end()); const std::vector<unsigned char> key(test1_key.begin(), test1_key.end());
const std::vector<unsigned char> iv(test1_iv.begin(), test1_iv.end()); const std::vector<unsigned char> iv(test1_iv.begin(), test1_iv.end());
AES256_CBC a; 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); EXPECT_EQ(test1_enc, output);
} }
@ -51,13 +51,11 @@ TEST(CryptoTest, encrypt3){
TEST(CryptoTest, decrypt1){ TEST(CryptoTest, decrypt1){
const std::vector<unsigned char> plaintext(test1_str.begin(), test1_str.end()); const std::vector<unsigned char> plaintext(test1_str.begin(), test1_str.end());
size_t output_len = test1_enc.size();
std::vector<unsigned char> output(output_len);
const std::vector<unsigned char> key(test1_key.begin(), test1_key.end()); const std::vector<unsigned char> key(test1_key.begin(), test1_key.end());
const std::vector<unsigned char> iv(test1_iv.begin(), test1_iv.end()); const std::vector<unsigned char> iv(test1_iv.begin(), test1_iv.end());
AES256_CBC a; AES256_CBC a;
a.decrypt(key, iv, test1_enc, output); auto output = a.decrypt(key, iv, test1_enc);
EXPECT_EQ(plaintext, output); EXPECT_EQ(plaintext, output);
} }