From 400ff37f04b87d9a589126784916b6ec32b7e743 Mon Sep 17 00:00:00 2001 From: Haik Date: Sat, 19 Oct 2024 14:14:42 +0400 Subject: [PATCH] HMAC-SHA256 support added --- Readme.md | 178 +++++++++---------- src/Pandatech.Crypto/Pandatech.Crypto.csproj | 4 +- src/Pandatech.Crypto/Sha2.cs | 27 +++ test/Pandatech.Crypto.Tests/Sha2Tests.cs | 64 +++++++ 4 files changed, 181 insertions(+), 92 deletions(-) create mode 100644 src/Pandatech.Crypto/Sha2.cs create mode 100644 test/Pandatech.Crypto.Tests/Sha2Tests.cs diff --git a/Readme.md b/Readme.md index 5c8747e..f397cf0 100644 --- a/Readme.md +++ b/Readme.md @@ -1,69 +1,36 @@ -# 1. PandaTech.Crypto - -- [1. PandaTech.Crypto](#1-pandatechcrypto) - - [1.1. Introduction](#11-introduction) - - [1.2. Features](#12-features) - - [1.3. Installation](#13-installation) - - [1.4. How to Use](#14-how-to-use) - - [1.4.1. Configuring Dependency Injection](#141-configuring-dependency-injection) - - [1.4.2. AES256 Class](#142-aes256-class) - - [1.4.2.1. Immutable Configurations](#1421-immutable-configurations) - - [1.4.2.2. Encryption/Decryption methods with hashing](#1422-encryptiondecryption-methods-with-hashing) - - [1.4.2.3. Encryption/Decryption methods without hashing](#1423-encryptiondecryption-methods-without-hashing) - - [1.4.2.4. Encryption/Decryption methods with custom key (overriding options for one time)](#1424-encryptiondecryption-methods-with-custom-key-overriding-options-for-one-time) - - [1.4.2.5. Stream-based Encryption/Decryption methods](#1425-stream-based-encryptiondecryption-methods) - - [1.4.3. Argon2id Class](#143-argon2id-class) - - [1.4.3.1. Default Configurations](#1431-default-configurations) - - [1.4.3.2 Hash password and verify hash](#1432-hash-password-and-verify-hash) - - [1.4.4. Random Class](#144-random-class) - - [1.4.5. Password Class](#145-password-class) - - [1.4.6. Sha3 Class](#146-sha3-class) - - [1.4.7. GZip Class](#147-gzip-class) - - [1.4.8. Mask Class](#148-mask-class) - - [1.4.8.1. Masking Email Addresses](#1481-masking-email-addresses) - - [1.5. License](#15-license) - -## 1.1. Introduction - -Pandatech.Crypto is a powerful cryptographic utility library backed by 99% test coverage through unit tests. The library -offers an array of static methods for secure data operations, including AES256 encryption and decryption, Argon2Id -password hashing and verification, as well as utilities for generating cryptographic random bytes and passwords. Now, it -also includes GZip compression and decompression functionalities. - -Designed to work efficiently in containerized environments, the library performs effectively even with limited -resources—hash generation takes under 500ms on a container with 1 vCore and 1GB of RAM. - -## 1.2. Features - -* **AES 256-bit Encryption/Decryption:** Encrypt your data and get the IV and encrypted bytes in one array. Decrypt it - back to its original form, seamlessly handling the IV. Note that you have option to encrypt with hash and decrypt - ignoring hash. (for cases where you want to apply filtering on the encrypted data or check uniqueness of the encrypted - data) -* **Argon2Id Hashing:** Perform password hashing and verification with a focus on security and performance, leveraging - the Argon2Id algorithm. -* **SHA-3 Hashing:** Utilize 512-bit SHA-3 hashing for various applications. -* **Random Number/Password Generation:** Generate cryptographic random bytes, AES256 keys, or strong passwords with - specific character sets. -* **GZip Compression/Decompression:** Efficiently compress and decompress data using GZip, with support for byte arrays - and streams. -* **Masking:** Mask sensitive information like email addresses and phone numbers, ensuring that they are partially - hidden and thus safeguarded. -* **Performance Optimized:** Tested to run efficiently in resource-constrained environments. -* **High Test Coverage:** Confidence backed by 99% unit test coverage. - -## 1.3. Installation - -To use `PandaTech.Crypto` in your project, install the NuGet package using the following command in the Package Manager -Console: -`Install-Package PandaTech.Crypto` or, search for "PandaTech.Crypto" in the NuGet Package Manager and install it from -there. - -## 1.4. How to Use - -### 1.4.1. Configuring Dependency Injection - -First, you'll need to configure Aes256 and Argon2Id in your application. To do so, add the following code to -your `Program.cs` file: +# PandaTech.Crypto + +## Introduction + +PandaTech.Crypto is a **wrapper library** that consolidates several widely used cryptographic libraries and tools into +one +**simple-to-use package**. It eliminates the need for multiple dependencies, excessive `using` directives, and +duplicated +code, offering an **intuitive API** to streamline **most popular** cryptographic tasks. + +Whether you need to **encrypt data**, **hash passwords**, or **generate secure random tokens**, PandaTech.Crypto +provides +lightweight abstractions over popular cryptographic solutions, ensuring simplicity and usability without sacrificing +performance. + +The **Argon2Id** password hashing is optimized to run efficiently even in **resource-constrained environments** (e.g., +hash +generation under 500ms on a container with 1 vCore and 1GB of RAM). Other operations such as **AES encryption**, **SHA** +hashing, and **GZip** compression are lightweight enough for almost any environment. + +## Installation + +Install the NuGet package via the Package Manager Console: + +```bash +Install-Package Pandatech.Crypto +``` + +## How to Use + +### Configuring Dependency Injection + +Add the following code to your Program.cs file to configure AES256 and Argon2Id services with minimal setup: ```csharp using Pandatech.Crypto; @@ -74,6 +41,9 @@ builder.services.AddPandatechCryptoAes256(options => options.Key = "YourAes256KeyHere"; // Make sure to use a secure key }); +// For Argon2Id default configuration +builder.services.AddPandatechCryptoArgon2Id(); + // For Argon2Id overriding default configurations builder.services.AddPandatechCryptoArgon2Id(options => { @@ -84,37 +54,34 @@ builder.services.AddPandatechCryptoAes256(options => }); ``` -### 1.4.2. AES256 Class - -#### 1.4.2.1. Immutable Configurations - -1. **IV**: A random IV is generated for each Encryption, enhancing security. -2. **PaddingMode**: PKCS7 +### AES256 Class -#### 1.4.2.2. Encryption/Decryption methods with hashing +**Encryption/Decryption methods with hashing** ```csharp byte[] cipherText = aes256.Encrypt("your-plaintext"); string plainText = aes256.Decrypt(cipherText); ``` -#### 1.4.2.3. Encryption/Decryption methods without hashing +**Encryption/Decryption methods without hashing** ```csharp -byte[] cipherText = aes256.EncryptWithout("your-plaintext"); -string plainText = aes256.DecryptWithout(cipherText); +byte[] cipherText = aes256.EncryptWithoutHash("your-plaintext"); +string plainText = aes256.DecryptWithoutHash(cipherText); ``` -#### 1.4.2.4. Encryption/Decryption methods with custom key (overriding options for one time) +**Encryption/Decryption methods with custom key (overriding options for one time)** ```csharp string customKey = "your-custom-base64-encoded-key"; byte[] cipherText = aes256.Encrypt("your-plaintext", customKey); string plainText = aes256.Decrypt(cipherText, customKey); ``` -#### 1.4.2.5. Stream-based Encryption/Decryption methods -The AES256 class also supports stream-based operations, allowing for encryption and decryption directly on streams, which is ideal for handling large files or data streams efficiently. +**Stream-based Encryption/Decryption methods** + +The AES256 class also supports stream-based operations, allowing for encryption and decryption directly on streams, +which is ideal for handling large files or data streams efficiently. ```csharp using var inputStream = new MemoryStream(Encoding.UTF8.GetBytes("your-plaintext")); @@ -128,16 +95,26 @@ aes256.DecryptStream(inputStream, outputStream, "your-custom-base64-encoded-key" string decryptedText = Encoding.UTF8.GetString(outputStream.ToArray()); ``` -### 1.4.3. Argon2id Class +**Notes** + +1. **IV**: A random IV is generated for each Encryption, enhancing security. +2. **PaddingMode**: PKCS7 +3. **Hashing**: The AES256 class by defaults also uses SHA3 512 hash before encryption and stores it in front of byte + array in order to be able to do unique cheques and other operations on encrypted fields. For example imagine you are + encrypting emails in your software and also want that emails to be unique. With our Aes256 class by default your + emails will be unique as in front will be the unique hash. + + +### Argon2id Class -#### 1.4.3.1. Default Configurations +**Default Configurations** 1. **Salt**: A random salt is generated for each password hash, enhancing security. 2. **DegreeOfParallelism**: 8 3. **Iterations**: 5 4. **MemorySize**: 128 MB -#### 1.4.3.2 Hash password and verify hash +**Examples on usage** ```csharp // Example usage for hashing @@ -147,7 +124,7 @@ var hashedPassword = _argon2Id.HashPassword("yourPassword"); var isPasswordValid = _argon2Id.VerifyHash("yourPassword", hashedPassword); ``` -### 1.4.4. Random Class +### Random Class ```csharp var randomBytes = Random.GenerateBytes(16); @@ -155,7 +132,7 @@ var aesKey = Random.GenerateAes256KeyString(); var unimaginableUniqueAndRandomToken = Random.GenerateSecureToken() //256-bit token in string format ``` -### 1.4.5. Password Class +### Password Class ```csharp var includeUppercase = true; @@ -170,7 +147,28 @@ string password = Password.GenerateRandom(16, includeUppercase, includeLowercase bool isValid = Password.Validate(password, 16, includeUppercase, includeLowercase, includeDigits, includeSpecialChars); ``` -### 1.4.6. Sha3 Class +### Sha2 Class + +The `Sha2` class simplifies HMAC-SHA256 operations by offering byte array, hex, and Base64 outputs. + +```csharp +// Prepare the key and message +var key = Encoding.UTF8.GetBytes("your-secret-key"); +var message = "HelloWorld"; + +// Compute HMAC-SHA256 as a byte array +byte[] hashBytes = Sha2.ComputeHmacSha256(key, message); + +// Get HMAC-SHA256 as a hex string +string hexHash = Sha2.GetHmacSha256Hex(key, message); +// Output: 2e91612bb72b29d82f32789d063de62d5897a4ee5d3b5d34459801b94397b099 + +// Get HMAC-SHA256 as a Base64 string +string base64Hash = Sha2.GetHmacSha256Base64(key, message); +// Output: LpFhK7crKdgvMnidBj3mLViXpO5dO100RZgBuUOXsJk= +``` + +### Sha3 Class ```csharp // Example usage for generating hash @@ -180,7 +178,7 @@ var sha3Hash = Sha3.Hash("yourPlainText"); var isHashValid = Sha3.VerifyHash("yourPlainText", sha3Hash); ``` -### 1.4.7. GZip Class +### GZip Class Compression and Decompression The `GZip` class provides methods for compressing and decompressing data using GZip. It supports operations on strings, @@ -200,7 +198,7 @@ string decompressedData = Encoding.UTF8.GetString(GZip.Decompress(compressedData ``` Example usage for compressing and decompressing with streams: - + ```csharp using var inputStream = new MemoryStream(Encoding.UTF8.GetBytes("Sample Data")); using var compressedStream = new MemoryStream(); @@ -213,12 +211,12 @@ GZip.Decompress(inputStream, decompressedStream); string decompressedData = Encoding.UTF8.GetString(decompressedStream.ToArray()); ``` -### 1.4.8. Mask Class +### Mask Class The `Mask` class in the PandaTech.Crypto library provides methods to mask sensitive information like email addresses and phone numbers, ensuring that they are partially hidden and thus safeguarded. -#### 1.4.8.1. Masking Email Addresses +#### Masking Email Addresses The `MaskEmail` method masks the local part of an email address, showing only the first two characters and replacing the rest with asterisks (*), keeping the domain part intact. @@ -241,6 +239,6 @@ string maskedEmail = maskedEmail.MaskEmail(); string maskedPhone = maskedPhone.MaskPhoneNumber(); ``` -## 1.5. License +## License PandaTech.Crypto is licensed under the MIT License. \ No newline at end of file diff --git a/src/Pandatech.Crypto/Pandatech.Crypto.csproj b/src/Pandatech.Crypto/Pandatech.Crypto.csproj index cede8cf..0018885 100644 --- a/src/Pandatech.Crypto/Pandatech.Crypto.csproj +++ b/src/Pandatech.Crypto/Pandatech.Crypto.csproj @@ -8,12 +8,12 @@ MIT pandatech.png Readme.md - 2.5.1 + 2.6.0 Pandatech.Crypto Pandatech, library, encryption, hash, algorythms, security PandaTech.Crypto is a .NET library simplifying common cryptograhic functions. https://github.com/PandaTechAM/be-lib-pandatech-crypto - Secure token generate method added + HMAC-SHA256 support added diff --git a/src/Pandatech.Crypto/Sha2.cs b/src/Pandatech.Crypto/Sha2.cs new file mode 100644 index 0000000..4f0e9e6 --- /dev/null +++ b/src/Pandatech.Crypto/Sha2.cs @@ -0,0 +1,27 @@ +using System.Security.Cryptography; +using System.Text; + +namespace Pandatech.Crypto; + +public static class Sha2 +{ + public static byte[] ComputeHmacSha256(byte[] key, params string[] messages) + { + using var hmac = new HMACSHA256(key); + + var concatenatedMessage = Encoding.UTF8.GetBytes(string.Concat(messages)); + return hmac.ComputeHash(concatenatedMessage); + } + + public static string GetHmacSha256Hex(byte[] key, params string[] messages) + { + var hash = ComputeHmacSha256(key, messages); + return BitConverter.ToString(hash).Replace("-", "").ToLower(); + } + + public static string GetHmacSha256Base64(byte[] key, params string[] messages) + { + var hash = ComputeHmacSha256(key, messages); + return Convert.ToBase64String(hash); + } +} \ No newline at end of file diff --git a/test/Pandatech.Crypto.Tests/Sha2Tests.cs b/test/Pandatech.Crypto.Tests/Sha2Tests.cs new file mode 100644 index 0000000..9a60e11 --- /dev/null +++ b/test/Pandatech.Crypto.Tests/Sha2Tests.cs @@ -0,0 +1,64 @@ +namespace Pandatech.Crypto.Tests; + +public class Sha2Tests +{ + [Fact] + public void HmacSha256_ValidInput_ReturnsExpectedHash() + { + // Arrange + var key = "secret"u8.ToArray(); + var messages = new[] { "Hello", "World" }; + const string expectedHashHex = "2e91612bb72b29d82f32789d063de62d5897a4ee5d3b5d34459801b94397b099"; + + // Act + var hashHex = Sha2.GetHmacSha256Hex(key, messages); + + // Assert + Assert.Equal(expectedHashHex, hashHex); + } + + [Fact] + public void HmacSha256_EmptyMessage_ReturnsHash() + { + // Arrange + var key = "secret"u8.ToArray(); + var messages = Array.Empty(); + + // Act + var hash = Sha2.ComputeHmacSha256(key, messages); + + // Assert + Assert.NotNull(hash); + Assert.NotEmpty(hash); + } + + [Fact] + public void HmacSha256_ConsistentOutput_ForSameInputs() + { + // Arrange + var key = "secret"u8.ToArray(); + var messages = new[] { "Test", "Message" }; + + // Act + var hash1 = Sha2.GetHmacSha256Hex(key, messages); + var hash2 = Sha2.GetHmacSha256Hex(key, messages); + + // Assert + Assert.Equal(hash1, hash2); + } + + [Fact] + public void HmacSha256Base64_ValidInput_ReturnsExpectedBase64() + { + // Arrange + var key = "secret"u8.ToArray(); + var messages = new[] { "Hello", "World" }; + const string expectedBase64 = "LpFhK7crKdgvMnidBj3mLViXpO5dO100RZgBuUOXsJk="; + + // Act + var base64Hash = Sha2.GetHmacSha256Base64(key, messages); + + // Assert + Assert.Equal(expectedBase64, base64Hash); + } +} \ No newline at end of file