diff --git a/README.md b/README.md index 387ac08..9319bcb 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Modern, easy-to-use, symmetric (AES-256) and asymmetric (RSA) encryption and als * [How to add it to my project](#how-to-add-it-to-my-project) * [How to use? (Symmetric Encryption with AES)](#how-to-use-symmetric-encryption-with-aes) +* [How to use? (Hash with SHA-256)](#how-to-use-hash-with-sha-256) * [How to use? (Asymmetric Encryption with RSA)](#how-to-use-asymmetric-encryption-with-rsa) * [How do I generate Public/Private Keys?](#how-do-i-generate-publicprivate-keys) * [Relationship between key size and max text length that can be encrypted](#relationship-between-key-size-and-max-text-length-that-can-be-encrypted) @@ -80,6 +81,27 @@ int main() { > amount of "0" to the end of keys shorter than 32 characters, and ignores the last parts of keys longer than > 32 characters, allowing you to use the key you want without any errors. +## How to use? (Hash with SHA-256) + +All you need to do is call the static **"hash"** method to hash the given text with SHA-256. + +```cpp +#include "libcpp-crypto.hpp" + +using namespace lklibs; + +int main() { + + auto plainText = "This text will be hashed soon"; + + auto hashText = CryptoService::hash(plainText); + + std::cout << "Hash: " << hashText << std::endl; + + return 0; +} +``` + ## How to use? (Asymmetric Encryption with RSA) To encrypt and decrypt the given text with RSA, all you need to do is call the static **"encryptWithRSA"** and @@ -185,7 +207,7 @@ character sets can take up twice. I am sharing the table below for a quick refer | 65536 | 8181 | > [!IMPORTANT] -> Do not think that you can easily create a longer key to encrypt a longer text with RSA. Each row in the table above consumes +> Do not think that you can easily create a longer key to encrypt a longer text with RSA. Each row in the table consumes > 4 times more CPU power during encryption/decryption process than the row above. Additionally, generating a 65K bit key takes > time and requires a lot of patience, even for a high-end computer. @@ -252,7 +274,7 @@ int main() { The exception part for the RSA side is a little different. If the public and private keys used are not correct, **"InvalidPublicKeyException"** and **"InvalidPrivateKeyException"** are thrown. However, the structure of the keys -used must be corrupt to throw these exceptions. If you use incompatible but structurally valid keys, no exception +used must be corrupt to throw these exceptions. If you use incompatible but structurally valid keys, no exception will be thrown. However, the text obtained after decryption will consist of just meaningless characters. ```cpp @@ -293,7 +315,6 @@ int main() { } ``` - ## Semantic Versioning Versioning of the library is done using conventional semantic versioning. Accordingly, @@ -325,6 +346,8 @@ static std::string decryptWithAES(const std::string& ciphertext, const std::stri static std::string encryptWithRSA(const std::string& plaintext, const std::string& publicKeyStr); static std::string decryptWithRSA(const std::string& ciphertext, const std::string& privateKeyStr); + +static std::string hash(const std::string& text); ``` ## License diff --git a/examples/main.cpp b/examples/main.cpp index 70c98e1..4d2cb8a 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -214,6 +214,15 @@ void CorruptedTextExceptionWithRSA() } } +void hash() +{ + auto plainText = "This text will be hashed soon"; + + auto hashText = CryptoService::hash(plainText); + + std::cout << "Hash: " << hashText << std::endl; +} + int main() { // Symmetric Encryption with AES @@ -241,5 +250,10 @@ int main() CorruptedTextExceptionWithRSA(); + + // Hashing + + hash(); + return 0; } diff --git a/src/libcpp-crypto.hpp b/src/libcpp-crypto.hpp index 6c77a36..0c5bc8b 100644 --- a/src/libcpp-crypto.hpp +++ b/src/libcpp-crypto.hpp @@ -1,7 +1,7 @@ /* Modern, easy-to-use, symmetric (AES-256) and asymmetric (RSA) encryption and also hash (SHA-256) library for C++ (17+) -version 1.1.0 +version 1.2.0 https://github.com/leventkaragol/libcpp-crypto If you encounter any issues, please submit a ticket at https://github.com/leventkaragol/libcpp-crypto/issues @@ -37,6 +37,8 @@ SOFTWARE. #include #include #include +#include +#include #include #include #include @@ -442,12 +444,58 @@ namespace lklibs return std::string(plaintext.begin(), plaintext.begin() + outlen); } + /** + * @brief Hashes the given string with SHA-256 + * + * @param text String to hash + * + * @return Hashed string + */ + static std::string hash(const std::string& text) + { + unsigned char hash[EVP_MAX_MD_SIZE]; + unsigned int lengthOfHash = 0; + + std::unique_ptr context(EVP_MD_CTX_new()); + + if (context) + { + if (EVP_DigestInit_ex(context.get(), EVP_sha256(), nullptr)) + { + if (EVP_DigestUpdate(context.get(), text.c_str(), text.size())) + { + if (EVP_DigestFinal_ex(context.get(), hash, &lengthOfHash)) + { + std::stringstream ss; + + for (unsigned int i = 0; i < lengthOfHash; ++i) + { + ss << std::hex << std::setw(2) << std::setfill('0') << static_cast(hash[i]); + } + + return ss.str(); + } + } + } + } + + return ""; + } + private: struct EVP_CIPHER_CTX_Deleter { void operator()(EVP_CIPHER_CTX* ptr) const { EVP_CIPHER_CTX_free(ptr); } }; + struct EVP_MD_CTX_Deleter + { + void operator()(EVP_MD_CTX* ctx) const + { + EVP_MD_CTX_free(ctx); + } + }; + static int encrypt(const unsigned char* plaintext, int plaintext_len, const unsigned char* key, unsigned char* iv, unsigned char* ciphertext) { std::unique_ptr ctx(EVP_CIPHER_CTX_new()); diff --git a/test/test.cpp b/test/test.cpp index ed6967e..1555882 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -5,8 +5,8 @@ using namespace lklibs; TEST(EncryptWithAESTest, EncryptionWithAESMustBeCompletedSuccessfullyWithAValidKey) { - std::string plainText = "Test message to be used during tests"; - std::string key = "mySecretKey"; + auto plainText = "Test message to be used during tests"; + auto key = "mySecretKey"; auto encryptedText = CryptoService::encryptWithAES(plainText, key); @@ -15,8 +15,8 @@ TEST(EncryptWithAESTest, EncryptionWithAESMustBeCompletedSuccessfullyWithAValidK TEST(DecryptWithAESTest, DecryptionWithAESMustBeCompletedSuccessfullyWithAValidKey) { - std::string plainText = "Test message to be used during tests"; - std::string key = "mySecretKey"; + auto plainText = "Test message to be used during tests"; + auto key = "mySecretKey"; auto encryptedText = CryptoService::encryptWithAES(plainText, key); auto decryptedText = CryptoService::decryptWithAES(encryptedText, key); @@ -26,8 +26,8 @@ TEST(DecryptWithAESTest, DecryptionWithAESMustBeCompletedSuccessfullyWithAValidK TEST(DecryptWithAESTest, DecryptionWithAESMustBeCompletedSuccessfullyForSpecialCharsWithAValidKey) { - std::string plainText = "Test message to be used during tests with special characters: !@#$%^&*()_+{}|:<>?~`-=[]\\;',./öçşığüÖÇŞİĞÜ"; - std::string key = "mySecretKey"; + auto plainText = "Test message to be used during tests with special characters: !@#$%^&*()_+{}|:<>?~`-=[]\\;',./öçşığüÖÇŞİĞÜ"; + auto key = "mySecretKey"; auto encryptedText = CryptoService::encryptWithAES(plainText, key); auto decryptedText = CryptoService::decryptWithAES(encryptedText, key); @@ -37,9 +37,9 @@ TEST(DecryptWithAESTest, DecryptionWithAESMustBeCompletedSuccessfullyForSpecialC TEST(DecryptWithAESTest, DecryptionWithAESMustBeFailedWithAnInvalidKey) { - std::string plainText = "Test message to be used during tests"; - std::string key = "mySecretKey"; - std::string invalidKey = "invalidKey"; + auto plainText = "Test message to be used during tests"; + auto key = "mySecretKey"; + auto invalidKey = "invalidKey"; auto encryptedText = CryptoService::encryptWithAES(plainText, key); @@ -62,7 +62,7 @@ TEST(DecryptWithAESTest, DecryptionWithAESMustBeFailedWithAnInvalidKey) TEST(DecryptWithAESTest, DecryptionWithAESMustBeFailedWithAnCorruptedEncryptedText) { auto encryptedText = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; - std::string key = "mySecretKey"; + auto key = "mySecretKey"; try { @@ -82,8 +82,8 @@ TEST(DecryptWithAESTest, DecryptionWithAESMustBeFailedWithAnCorruptedEncryptedTe TEST(AESKeyTest, AESEncryptionShouldBePossibleWithAKeyLessThan32Characters) { - std::string plainText = "Test message to be used during tests"; - std::string key = "123"; + auto plainText = "Test message to be used during tests"; + auto key = "123"; auto encryptedText = CryptoService::encryptWithAES(plainText, key); auto decryptedText = CryptoService::decryptWithAES(encryptedText, key); @@ -93,8 +93,8 @@ TEST(AESKeyTest, AESEncryptionShouldBePossibleWithAKeyLessThan32Characters) TEST(AESKeyTest, AESEncryptionShouldBePossibleWithAKeyLargerThan32Characters) { - std::string plainText = "Test message to be used during tests"; - std::string key = "abcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()_+{}|:<>?~`-=[]\\;',./"; + auto plainText = "Test message to be used during tests"; + auto key = "abcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()_+{}|:<>?~`-=[]\\;',./"; auto encryptedText = CryptoService::encryptWithAES(plainText, key); auto decryptedText = CryptoService::decryptWithAES(encryptedText, key); @@ -104,8 +104,8 @@ TEST(AESKeyTest, AESEncryptionShouldBePossibleWithAKeyLargerThan32Characters) TEST(AESKeyTest, AESEncryptionShouldBePossibleWithA32CharactersKey) { - std::string plainText = "Test message to be used during tests"; - std::string key = "abcdefghijklmnopqrstuvwxyz123456"; + auto plainText = "Test message to be used during tests"; + auto key = "abcdefghijklmnopqrstuvwxyz123456"; auto encryptedText = CryptoService::encryptWithAES(plainText, key); auto decryptedText = CryptoService::decryptWithAES(encryptedText, key); @@ -115,8 +115,8 @@ TEST(AESKeyTest, AESEncryptionShouldBePossibleWithA32CharactersKey) TEST(AESKeyTest, AESEncryptionMustBePossibleWithAKeyContainingSpecialCharacters) { - std::string plainText = "Test message to be used during tests"; - std::string key = "!@#$%^&*()_+{}|:<>?~`-=[]\\;',./"; + auto plainText = "Test message to be used during tests"; + auto key = "!@#$%^&*()_+{}|:<>?~`-=[]\\;',./"; auto encryptedText = CryptoService::encryptWithAES(plainText, key); auto decryptedText = CryptoService::decryptWithAES(encryptedText, key); @@ -331,6 +331,15 @@ TEST(DecryptWithRSATest, DecryptionWithRSAMustBeFailedWithAnCorruptedEncryptedTe } } +TEST(HashTest, HashWithSHA256MustBeCompletedSuccessfully) +{ + auto plainText = "This text will be hashed soon"; + + auto hashText = CryptoService::hash(plainText); + + ASSERT_EQ(hashText, "d32448bab2777b376a5592e384146c3c0182ba589e2521bd0275f2cef6a50546") << "Hash is invalid"; +} + int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv);