Skip to content

Commit

Permalink
HMAC-SHA256 support added
Browse files Browse the repository at this point in the history
  • Loading branch information
HaikAsatryan committed Oct 19, 2024
1 parent 233f932 commit 400ff37
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 92 deletions.
178 changes: 88 additions & 90 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 =>
{
Expand All @@ -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"));
Expand All @@ -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
Expand All @@ -147,15 +124,15 @@ var hashedPassword = _argon2Id.HashPassword("yourPassword");
var isPasswordValid = _argon2Id.VerifyHash("yourPassword", hashedPassword);
```

### 1.4.4. Random Class
### Random Class

```csharp
var randomBytes = Random.GenerateBytes(16);
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;
Expand All @@ -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
Expand All @@ -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,
Expand All @@ -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();
Expand All @@ -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.
Expand All @@ -241,6 +239,6 @@ string maskedEmail = maskedEmail.MaskEmail();
string maskedPhone = maskedPhone.MaskPhoneNumber();
```

## 1.5. License
## License

PandaTech.Crypto is licensed under the MIT License.
4 changes: 2 additions & 2 deletions src/Pandatech.Crypto/Pandatech.Crypto.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
<Copyright>MIT</Copyright>
<PackageIcon>pandatech.png</PackageIcon>
<PackageReadmeFile>Readme.md</PackageReadmeFile>
<Version>2.5.1</Version>
<Version>2.6.0</Version>
<Title>Pandatech.Crypto</Title>
<PackageTags>Pandatech, library, encryption, hash, algorythms, security</PackageTags>
<Description>PandaTech.Crypto is a .NET library simplifying common cryptograhic functions.</Description>
<RepositoryUrl>https://github.com/PandaTechAM/be-lib-pandatech-crypto</RepositoryUrl>
<PackageReleaseNotes>Secure token generate method added</PackageReleaseNotes>
<PackageReleaseNotes>HMAC-SHA256 support added</PackageReleaseNotes>
</PropertyGroup>

<ItemGroup>
Expand Down
27 changes: 27 additions & 0 deletions src/Pandatech.Crypto/Sha2.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
64 changes: 64 additions & 0 deletions test/Pandatech.Crypto.Tests/Sha2Tests.cs
Original file line number Diff line number Diff line change
@@ -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<string>();

// 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);
}
}

0 comments on commit 400ff37

Please sign in to comment.