Skip to content

Commit

Permalink
Merge pull request #37 from coders-school/encryption
Browse files Browse the repository at this point in the history
Encryption
  • Loading branch information
skwarq authored Mar 10, 2024
2 parents fe217ef + 3b24e24 commit c62e072
Show file tree
Hide file tree
Showing 16 changed files with 420 additions and 0 deletions.
1 change: 1 addition & 0 deletions encrypt/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build/
62 changes: 62 additions & 0 deletions encrypt/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
cmake_minimum_required(VERSION 3.14)

# # Basic Files
file(GLOB project_src
"symCrypt/*.cpp"
"hash/*.cpp"
)

project(encrpyt)

option(USE_SYSTEM_OPENSSL "Use the system's OpenSSL if available" OFF)

include(FindPackageHandleStandardArgs)
find_package(OpenSSL QUIET)
if(NOT OpenSSL_FOUND)
if(USE_SYSTEM_OPENSSL)
message(FATAL_ERROR "System OpenSSL not found. Set USE_SYSTEM_OPENSSL to OFF or install OpenSSL.")
else()
set(OPENSSL_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/openssl-src) # default path by CMake
set(OPENSSL_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/openssl)
set(OPENSSL_INCLUDE_DIR ${OPENSSL_INSTALL_DIR}/include)
set(OPENSSL_CONFIGURE_COMMAND ${OPENSSL_SOURCE_DIR}/config)
include(ExternalProject)
ExternalProject_Add(
OpenSSL
SOURCE_DIR ${OPENSSL_SOURCE_DIR}
GIT_REPOSITORY https://github.com/openssl/openssl.git
GIT_TAG openssl-3.2.1
USES_TERMINAL_DOWNLOAD TRUE
CONFIGURE_COMMAND
${OPENSSL_CONFIGURE_COMMAND}
--prefix=${OPENSSL_INSTALL_DIR}
--openssldir=${OPENSSL_INSTALL_DIR}
BUILD_COMMAND make
TEST_COMMAND ""
INSTALL_COMMAND make install
INSTALL_DIR ${OPENSSL_INSTALL_DIR}
)

file(MAKE_DIRECTORY ${OPENSSL_INCLUDE_DIR})

add_library(OpenSSL::SSL STATIC IMPORTED GLOBAL)
set_property(TARGET OpenSSL::SSL PROPERTY IMPORTED_LOCATION ${OPENSSL_INSTALL_DIR}/lib/libssl.${OPENSSL_LIBRARY_SUFFIX})
set_property(TARGET OpenSSL::SSL PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${OPENSSL_INCLUDE_DIR})
add_dependencies(OpenSSL::SSL OpenSSL)

add_library(OpenSSL::Crypto STATIC IMPORTED GLOBAL)
set_property(TARGET OpenSSL::Crypto PROPERTY IMPORTED_LOCATION ${OPENSSL_INSTALL_DIR}/lib/libcrypto.${OPENSSL_LIBRARY_SUFFIX})
set_property(TARGET OpenSSL::Crypto PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${OPENSSL_INCLUDE_DIR})
add_dependencies(OpenSSL::Crypto OpenSSL)
endif()
endif()

add_library(encrpyt ${project_src})
target_link_libraries(encrpyt PUBLIC OpenSSL::SSL OpenSSL::Crypto)
target_include_directories(encrpyt PUBLIC "../")
target_compile_options(encrpyt PRIVATE -Wall -Wextra -Wpedantic -Werror)

if((CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME OR MODERN_CMAKE_BUILD_TESTING) AND(BUILD_TESTING))
enable_testing()
add_subdirectory(uTests)
endif()
57 changes: 57 additions & 0 deletions encrypt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# encrypt

`encrypt` is a straightforward wrapper library built on top of the OpenSSL library, offering implementations of cryptographic algorithms such as SHA-512 hashing and AES-256-CBC encryption.

## Features

- Efficient implementation of SHA-512 hashing.
- Implementation of AES-256-CBC encryption with OpenSSL.
- Utilizes `std::span` for handling input and output data efficiently.

## Usage

### SHA512

To compute the SHA-512 hash of a message, you can use the `SHA512` class:

```cpp
#include "encrypt/hash/SHA512.hpp"

using namespace encrypt;

int main() {
std::string message = "Hello, World!";
SHA512 sha512;
std::string hash = sha512.hash({message.begin(), message.end()});
std::cout << "SHA-512 hash of '" << message << "': " << hash << std::endl;
return 0;
}
```
### AES256CBC
To perform AES-256-CBC encryption and decryption, you can use the `AES256CBC` class:

```cpp
#include "encrypt/symCrypt/AES256CBC.hpp"

using namespace encrypt;

int main() {
std::string key = "YourKeyHere";
std::string iv = "YourInitializationVectorHere";
AES256CBC aes256cbc({iv.begin(), iv.end()});

std::string plaintext = "YourPlainTextHere";
std::string ciphertext(plaintext.size() + AES_BLOCK_SIZE, '\0');

// Encryption
aes256cbc.encrypt(key, {plaintext.begin(), plaintext.end()}, {ciphertext.begin(), ciphertext.end()});
std::cout << "Encrypted text: " << ciphertext << std::endl;

// Decryption
std::string decryptedtext(plaintext.size(), '\0');
aes256cbc.decrypt(key, {ciphertext.begin(), ciphertext.end()}, {decryptedtext.begin(), decryptedtext.end()});
std::cout << "Decrypted text: " << decryptedtext << std::endl;

return 0;
}
```
6 changes: 6 additions & 0 deletions encrypt/hash/FakeHash.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "FakeHash.hpp"
using namespace encrypt;

std::string FakeHash::hash(std::span<const unsigned char> input) const {
return std::string(input.begin(), input.end());
}
10 changes: 10 additions & 0 deletions encrypt/hash/FakeHash.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include "IHash.hpp"

namespace encrypt {
class FakeHash : public IHash {
public:
std::string hash(std::span<const unsigned char> input) const override;
};
} // namespace encrypt
11 changes: 11 additions & 0 deletions encrypt/hash/IHash.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once
#include <span>
#include <string>

namespace encrypt {
class IHash {
public:
virtual ~IHash() = default;
virtual std::string hash(std::span<const unsigned char> input) const = 0;
};
} // namespace encrypt
31 changes: 31 additions & 0 deletions encrypt/hash/SHA512.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "SHA512.hpp"

#include <openssl/evp.h>
#include <openssl/sha.h>

#include <memory>
#include <stdexcept>
#include <vector>

using namespace encrypt;

using EVP_MD_CTX_ptr =
std::unique_ptr<EVP_MD_CTX, decltype(&::EVP_MD_CTX_free)>;

std::string SHA512::hash(std::span<const unsigned char> input) const {
EVP_MD_CTX_ptr ctx(EVP_MD_CTX_new(), ::EVP_MD_CTX_free);
if (!ctx) {
throw std::runtime_error("Error creating EVP_MD_CTX");
}
if (!EVP_DigestInit_ex(ctx.get(), EVP_sha512(), nullptr)) {
throw std::runtime_error("Error initializing SHA-512 digest");
}
if (!EVP_DigestUpdate(ctx.get(), input.data(), input.size())) {
throw std::runtime_error("Error updating SHA-512 digest");
}
std::vector<unsigned char> hash(SHA512_DIGEST_LENGTH);
if (!EVP_DigestFinal_ex(ctx.get(), hash.data(), nullptr)) {
throw std::runtime_error("Error finalizing SHA-512 digest");
}
return std::string(hash.begin(), hash.end());
}
10 changes: 10 additions & 0 deletions encrypt/hash/SHA512.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include "IHash.hpp"

namespace encrypt {
class SHA512 : public IHash {
public:
std::string hash(std::span<const unsigned char> input) const override;
};
} // namespace encrypt
76 changes: 76 additions & 0 deletions encrypt/symCrypt/AES256CBC.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include "AES256CBC.hpp"

#include <openssl/aes.h>
#include <openssl/evp.h>

#include <memory>

using namespace encrypt;

using EVP_CIPHER_CTX_t =
std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>;

AES256CBC::AES256CBC(std::span<const unsigned char> iv) : iv(iv) {}

void AES256CBC::encrypt(const std::string &key,
std::span<const unsigned char> plainText,
std::span<unsigned char> &cipherText) const {
size_t blockSize = EVP_CIPHER_block_size(EVP_aes_256_cbc());
size_t paddingSize = blockSize - (plainText.size() % blockSize);
size_t expectedSize = plainText.size() + paddingSize;
if (cipherText.size() < expectedSize) {
throw std::runtime_error("cipherText buffer is too small");
}
EVP_CIPHER_CTX_t ctx(EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
int res{}, outlen{};
size_t totalOut{0};
res = EVP_EncryptInit(ctx.get(), EVP_aes_256_cbc(),
reinterpret_cast<const unsigned char *>(key.c_str()),
iv.data());
if (res != 1) {
throw std::runtime_error("Error in EVP_EncryptInit");
}
res = EVP_EncryptUpdate(ctx.get(), cipherText.data(), &outlen,
plainText.data(), plainText.size());
if (res != 1) {
throw std::runtime_error("Error in EVP_EncryptUpdate");
}
totalOut += outlen;
res = EVP_EncryptFinal(ctx.get(), cipherText.data() + totalOut, &outlen);
if (res != 1) {
throw std::runtime_error("Error in EVP_EncryptFinal");
}
totalOut += outlen;
cipherText = cipherText.first(totalOut);
}

void AES256CBC::decrypt(const std::string &key,
std::span<const unsigned char> cipherText,
std::span<unsigned char> &plainText) const {
size_t expectedSize = cipherText.size();
if (plainText.size() < expectedSize) {
throw std::runtime_error("plainText buffer is too small");
}
EVP_CIPHER_CTX_t ctx(EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
int res{}, outlen{};
size_t totalOut{0};
res = EVP_DecryptInit(ctx.get(), EVP_aes_256_cbc(),
reinterpret_cast<const unsigned char *>(key.c_str()),
iv.data());
if (res != 1) {
throw std::runtime_error("Error in EVP_DecryptInit");
}
res = EVP_DecryptUpdate(ctx.get(), plainText.data(), &outlen,
cipherText.data(), cipherText.size());
if (res != 1) {
throw std::runtime_error("Error in EVP_DecryptUpdate");
}
totalOut += outlen;

res = EVP_DecryptFinal(ctx.get(), plainText.data() + totalOut, &outlen);
if (res != 1) {
throw std::runtime_error("Error in EVP_DecryptFinal");
}
totalOut += outlen;
plainText = plainText.first(totalOut);
}
18 changes: 18 additions & 0 deletions encrypt/symCrypt/AES256CBC.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once
#include "ISymCipher.hpp"

namespace encrypt {
class AES256CBC : public ISymCipher {
public:
explicit AES256CBC(std::span<const unsigned char> iv);

void encrypt(const std::string& key, std::span<const unsigned char> plainText,
std::span<unsigned char>& secret) const override;

void decrypt(const std::string& key, std::span<const unsigned char> secret,
std::span<unsigned char>& plainText) const override;

private:
std::span<const unsigned char> iv;
};
} // namespace encrypt
24 changes: 24 additions & 0 deletions encrypt/symCrypt/FakeSymCipher.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include "FakeSymCipher.hpp"

#include <algorithm>
#include <stdexcept>

using namespace encrypt;

void FakeSymCipher::encrypt(const std::string& /* key */,
std::span<const unsigned char> plainText,
std::span<unsigned char>& cipherText) const {
if (cipherText.size() < plainText.size()) {
throw std::runtime_error("cipherText buffer is too small");
}
std::copy(plainText.begin(), plainText.end(), cipherText.begin());
}

void FakeSymCipher::decrypt(const std::string& /* key */,
std::span<const unsigned char> cipherText,
std::span<unsigned char>& plainText) const {
if (plainText.size() < cipherText.size()) {
throw std::runtime_error("plainText buffer is too small");
}
std::copy(cipherText.begin(), cipherText.end(), plainText.begin());
}
13 changes: 13 additions & 0 deletions encrypt/symCrypt/FakeSymCipher.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once
#include "ISymCipher.hpp"

namespace encrypt {
class FakeSymCipher : public ISymCipher {
public:
void encrypt(const std::string& key, std::span<const unsigned char> plainText,
std::span<unsigned char>& secret) const override;

void decrypt(const std::string& key, std::span<const unsigned char> secret,
std::span<unsigned char>& plainText) const override;
};
} // namespace encrypt
17 changes: 17 additions & 0 deletions encrypt/symCrypt/ISymCipher.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include <span>
#include <string>

namespace encrypt {
struct ISymCipher {
virtual ~ISymCipher() = default;
virtual void encrypt(const std::string &key,
std::span<const unsigned char> plainText,
std::span<unsigned char> &cipherText) const = 0;

virtual void decrypt(const std::string &key,
std::span<const unsigned char> cipherText,
std::span<unsigned char> &plainText) const = 0;
};
} // namespace encrypt
22 changes: 22 additions & 0 deletions encrypt/uTests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
include(FetchContent)

set(TEST_NAME ${PROJECT_NAME}-UT)

FetchContent_Declare(
googletest
GIT_REPOSITORY "https://github.com/google/googletest.git"
GIT_TAG release-1.11.0
)

FetchContent_MakeAvailable(googletest)

file(GLOB_RECURSE test_src
"*.cpp"
)

add_executable(${TEST_NAME} ${test_src})
target_link_libraries(${TEST_NAME} gtest_main ${PROJECT_NAME})
set_target_properties(${TEST_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test")

include(GoogleTest)
gtest_discover_tests(${TEST_NAME})
Loading

0 comments on commit c62e072

Please sign in to comment.