Skip to content

Commit 400ff37

Browse files
committed
HMAC-SHA256 support added
1 parent 233f932 commit 400ff37

File tree

4 files changed

+181
-92
lines changed

4 files changed

+181
-92
lines changed

Readme.md

Lines changed: 88 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,36 @@
1-
# 1. PandaTech.Crypto
2-
3-
- [1. PandaTech.Crypto](#1-pandatechcrypto)
4-
- [1.1. Introduction](#11-introduction)
5-
- [1.2. Features](#12-features)
6-
- [1.3. Installation](#13-installation)
7-
- [1.4. How to Use](#14-how-to-use)
8-
- [1.4.1. Configuring Dependency Injection](#141-configuring-dependency-injection)
9-
- [1.4.2. AES256 Class](#142-aes256-class)
10-
- [1.4.2.1. Immutable Configurations](#1421-immutable-configurations)
11-
- [1.4.2.2. Encryption/Decryption methods with hashing](#1422-encryptiondecryption-methods-with-hashing)
12-
- [1.4.2.3. Encryption/Decryption methods without hashing](#1423-encryptiondecryption-methods-without-hashing)
13-
- [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)
14-
- [1.4.2.5. Stream-based Encryption/Decryption methods](#1425-stream-based-encryptiondecryption-methods)
15-
- [1.4.3. Argon2id Class](#143-argon2id-class)
16-
- [1.4.3.1. Default Configurations](#1431-default-configurations)
17-
- [1.4.3.2 Hash password and verify hash](#1432-hash-password-and-verify-hash)
18-
- [1.4.4. Random Class](#144-random-class)
19-
- [1.4.5. Password Class](#145-password-class)
20-
- [1.4.6. Sha3 Class](#146-sha3-class)
21-
- [1.4.7. GZip Class](#147-gzip-class)
22-
- [1.4.8. Mask Class](#148-mask-class)
23-
- [1.4.8.1. Masking Email Addresses](#1481-masking-email-addresses)
24-
- [1.5. License](#15-license)
25-
26-
## 1.1. Introduction
27-
28-
Pandatech.Crypto is a powerful cryptographic utility library backed by 99% test coverage through unit tests. The library
29-
offers an array of static methods for secure data operations, including AES256 encryption and decryption, Argon2Id
30-
password hashing and verification, as well as utilities for generating cryptographic random bytes and passwords. Now, it
31-
also includes GZip compression and decompression functionalities.
32-
33-
Designed to work efficiently in containerized environments, the library performs effectively even with limited
34-
resources—hash generation takes under 500ms on a container with 1 vCore and 1GB of RAM.
35-
36-
## 1.2. Features
37-
38-
* **AES 256-bit Encryption/Decryption:** Encrypt your data and get the IV and encrypted bytes in one array. Decrypt it
39-
back to its original form, seamlessly handling the IV. Note that you have option to encrypt with hash and decrypt
40-
ignoring hash. (for cases where you want to apply filtering on the encrypted data or check uniqueness of the encrypted
41-
data)
42-
* **Argon2Id Hashing:** Perform password hashing and verification with a focus on security and performance, leveraging
43-
the Argon2Id algorithm.
44-
* **SHA-3 Hashing:** Utilize 512-bit SHA-3 hashing for various applications.
45-
* **Random Number/Password Generation:** Generate cryptographic random bytes, AES256 keys, or strong passwords with
46-
specific character sets.
47-
* **GZip Compression/Decompression:** Efficiently compress and decompress data using GZip, with support for byte arrays
48-
and streams.
49-
* **Masking:** Mask sensitive information like email addresses and phone numbers, ensuring that they are partially
50-
hidden and thus safeguarded.
51-
* **Performance Optimized:** Tested to run efficiently in resource-constrained environments.
52-
* **High Test Coverage:** Confidence backed by 99% unit test coverage.
53-
54-
## 1.3. Installation
55-
56-
To use `PandaTech.Crypto` in your project, install the NuGet package using the following command in the Package Manager
57-
Console:
58-
`Install-Package PandaTech.Crypto` or, search for "PandaTech.Crypto" in the NuGet Package Manager and install it from
59-
there.
60-
61-
## 1.4. How to Use
62-
63-
### 1.4.1. Configuring Dependency Injection
64-
65-
First, you'll need to configure Aes256 and Argon2Id in your application. To do so, add the following code to
66-
your `Program.cs` file:
1+
# PandaTech.Crypto
2+
3+
## Introduction
4+
5+
PandaTech.Crypto is a **wrapper library** that consolidates several widely used cryptographic libraries and tools into
6+
one
7+
**simple-to-use package**. It eliminates the need for multiple dependencies, excessive `using` directives, and
8+
duplicated
9+
code, offering an **intuitive API** to streamline **most popular** cryptographic tasks.
10+
11+
Whether you need to **encrypt data**, **hash passwords**, or **generate secure random tokens**, PandaTech.Crypto
12+
provides
13+
lightweight abstractions over popular cryptographic solutions, ensuring simplicity and usability without sacrificing
14+
performance.
15+
16+
The **Argon2Id** password hashing is optimized to run efficiently even in **resource-constrained environments** (e.g.,
17+
hash
18+
generation under 500ms on a container with 1 vCore and 1GB of RAM). Other operations such as **AES encryption**, **SHA**
19+
hashing, and **GZip** compression are lightweight enough for almost any environment.
20+
21+
## Installation
22+
23+
Install the NuGet package via the Package Manager Console:
24+
25+
```bash
26+
Install-Package Pandatech.Crypto
27+
```
28+
29+
## How to Use
30+
31+
### Configuring Dependency Injection
32+
33+
Add the following code to your Program.cs file to configure AES256 and Argon2Id services with minimal setup:
6734

6835
```csharp
6936
using Pandatech.Crypto;
@@ -74,6 +41,9 @@ builder.services.AddPandatechCryptoAes256(options =>
7441
options.Key = "YourAes256KeyHere"; // Make sure to use a secure key
7542
});
7643

44+
// For Argon2Id default configuration
45+
builder.services.AddPandatechCryptoArgon2Id();
46+
7747
// For Argon2Id overriding default configurations
7848
builder.services.AddPandatechCryptoArgon2Id(options =>
7949
{
@@ -84,37 +54,34 @@ builder.services.AddPandatechCryptoAes256(options =>
8454
});
8555
```
8656

87-
### 1.4.2. AES256 Class
88-
89-
#### 1.4.2.1. Immutable Configurations
90-
91-
1. **IV**: A random IV is generated for each Encryption, enhancing security.
92-
2. **PaddingMode**: PKCS7
57+
### AES256 Class
9358

94-
#### 1.4.2.2. Encryption/Decryption methods with hashing
59+
**Encryption/Decryption methods with hashing**
9560

9661
```csharp
9762
byte[] cipherText = aes256.Encrypt("your-plaintext");
9863
string plainText = aes256.Decrypt(cipherText);
9964
```
10065

101-
#### 1.4.2.3. Encryption/Decryption methods without hashing
66+
**Encryption/Decryption methods without hashing**
10267

10368
```csharp
104-
byte[] cipherText = aes256.EncryptWithout("your-plaintext");
105-
string plainText = aes256.DecryptWithout(cipherText);
69+
byte[] cipherText = aes256.EncryptWithoutHash("your-plaintext");
70+
string plainText = aes256.DecryptWithoutHash(cipherText);
10671
```
10772

108-
#### 1.4.2.4. Encryption/Decryption methods with custom key (overriding options for one time)
73+
**Encryption/Decryption methods with custom key (overriding options for one time)**
10974

11075
```csharp
11176
string customKey = "your-custom-base64-encoded-key";
11277
byte[] cipherText = aes256.Encrypt("your-plaintext", customKey);
11378
string plainText = aes256.Decrypt(cipherText, customKey);
11479
```
115-
#### 1.4.2.5. Stream-based Encryption/Decryption methods
11680

117-
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.
81+
**Stream-based Encryption/Decryption methods**
82+
83+
The AES256 class also supports stream-based operations, allowing for encryption and decryption directly on streams,
84+
which is ideal for handling large files or data streams efficiently.
11885

11986
```csharp
12087
using var inputStream = new MemoryStream(Encoding.UTF8.GetBytes("your-plaintext"));
@@ -128,16 +95,26 @@ aes256.DecryptStream(inputStream, outputStream, "your-custom-base64-encoded-key"
12895
string decryptedText = Encoding.UTF8.GetString(outputStream.ToArray());
12996
```
13097

131-
### 1.4.3. Argon2id Class
98+
**Notes**
99+
100+
1. **IV**: A random IV is generated for each Encryption, enhancing security.
101+
2. **PaddingMode**: PKCS7
102+
3. **Hashing**: The AES256 class by defaults also uses SHA3 512 hash before encryption and stores it in front of byte
103+
array in order to be able to do unique cheques and other operations on encrypted fields. For example imagine you are
104+
encrypting emails in your software and also want that emails to be unique. With our Aes256 class by default your
105+
emails will be unique as in front will be the unique hash.
106+
107+
108+
### Argon2id Class
132109

133-
#### 1.4.3.1. Default Configurations
110+
**Default Configurations**
134111

135112
1. **Salt**: A random salt is generated for each password hash, enhancing security.
136113
2. **DegreeOfParallelism**: 8
137114
3. **Iterations**: 5
138115
4. **MemorySize**: 128 MB
139116

140-
#### 1.4.3.2 Hash password and verify hash
117+
**Examples on usage**
141118

142119
```csharp
143120
// Example usage for hashing
@@ -147,15 +124,15 @@ var hashedPassword = _argon2Id.HashPassword("yourPassword");
147124
var isPasswordValid = _argon2Id.VerifyHash("yourPassword", hashedPassword);
148125
```
149126

150-
### 1.4.4. Random Class
127+
### Random Class
151128

152129
```csharp
153130
var randomBytes = Random.GenerateBytes(16);
154131
var aesKey = Random.GenerateAes256KeyString();
155132
var unimaginableUniqueAndRandomToken = Random.GenerateSecureToken() //256-bit token in string format
156133
```
157134

158-
### 1.4.5. Password Class
135+
### Password Class
159136

160137
```csharp
161138
var includeUppercase = true;
@@ -170,7 +147,28 @@ string password = Password.GenerateRandom(16, includeUppercase, includeLowercase
170147
bool isValid = Password.Validate(password, 16, includeUppercase, includeLowercase, includeDigits, includeSpecialChars);
171148
```
172149

173-
### 1.4.6. Sha3 Class
150+
### Sha2 Class
151+
152+
The `Sha2` class simplifies HMAC-SHA256 operations by offering byte array, hex, and Base64 outputs.
153+
154+
```csharp
155+
// Prepare the key and message
156+
var key = Encoding.UTF8.GetBytes("your-secret-key");
157+
var message = "HelloWorld";
158+
159+
// Compute HMAC-SHA256 as a byte array
160+
byte[] hashBytes = Sha2.ComputeHmacSha256(key, message);
161+
162+
// Get HMAC-SHA256 as a hex string
163+
string hexHash = Sha2.GetHmacSha256Hex(key, message);
164+
// Output: 2e91612bb72b29d82f32789d063de62d5897a4ee5d3b5d34459801b94397b099
165+
166+
// Get HMAC-SHA256 as a Base64 string
167+
string base64Hash = Sha2.GetHmacSha256Base64(key, message);
168+
// Output: LpFhK7crKdgvMnidBj3mLViXpO5dO100RZgBuUOXsJk=
169+
```
170+
171+
### Sha3 Class
174172

175173
```csharp
176174
// Example usage for generating hash
@@ -180,7 +178,7 @@ var sha3Hash = Sha3.Hash("yourPlainText");
180178
var isHashValid = Sha3.VerifyHash("yourPlainText", sha3Hash);
181179
```
182180

183-
### 1.4.7. GZip Class
181+
### GZip Class
184182

185183
Compression and Decompression
186184
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
200198
```
201199

202200
Example usage for compressing and decompressing with streams:
203-
201+
204202
```csharp
205203
using var inputStream = new MemoryStream(Encoding.UTF8.GetBytes("Sample Data"));
206204
using var compressedStream = new MemoryStream();
@@ -213,12 +211,12 @@ GZip.Decompress(inputStream, decompressedStream);
213211
string decompressedData = Encoding.UTF8.GetString(decompressedStream.ToArray());
214212
```
215213

216-
### 1.4.8. Mask Class
214+
### Mask Class
217215

218216
The `Mask` class in the PandaTech.Crypto library provides methods to mask sensitive information like email addresses and
219217
phone numbers, ensuring that they are partially hidden and thus safeguarded.
220218

221-
#### 1.4.8.1. Masking Email Addresses
219+
#### Masking Email Addresses
222220

223221
The `MaskEmail` method masks the local part of an email address, showing only the first two characters and replacing the
224222
rest with asterisks (*), keeping the domain part intact.
@@ -241,6 +239,6 @@ string maskedEmail = maskedEmail.MaskEmail();
241239
string maskedPhone = maskedPhone.MaskPhoneNumber();
242240
```
243241

244-
## 1.5. License
242+
## License
245243

246244
PandaTech.Crypto is licensed under the MIT License.

src/Pandatech.Crypto/Pandatech.Crypto.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
<Copyright>MIT</Copyright>
99
<PackageIcon>pandatech.png</PackageIcon>
1010
<PackageReadmeFile>Readme.md</PackageReadmeFile>
11-
<Version>2.5.1</Version>
11+
<Version>2.6.0</Version>
1212
<Title>Pandatech.Crypto</Title>
1313
<PackageTags>Pandatech, library, encryption, hash, algorythms, security</PackageTags>
1414
<Description>PandaTech.Crypto is a .NET library simplifying common cryptograhic functions.</Description>
1515
<RepositoryUrl>https://github.com/PandaTechAM/be-lib-pandatech-crypto</RepositoryUrl>
16-
<PackageReleaseNotes>Secure token generate method added</PackageReleaseNotes>
16+
<PackageReleaseNotes>HMAC-SHA256 support added</PackageReleaseNotes>
1717
</PropertyGroup>
1818

1919
<ItemGroup>

src/Pandatech.Crypto/Sha2.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System.Security.Cryptography;
2+
using System.Text;
3+
4+
namespace Pandatech.Crypto;
5+
6+
public static class Sha2
7+
{
8+
public static byte[] ComputeHmacSha256(byte[] key, params string[] messages)
9+
{
10+
using var hmac = new HMACSHA256(key);
11+
12+
var concatenatedMessage = Encoding.UTF8.GetBytes(string.Concat(messages));
13+
return hmac.ComputeHash(concatenatedMessage);
14+
}
15+
16+
public static string GetHmacSha256Hex(byte[] key, params string[] messages)
17+
{
18+
var hash = ComputeHmacSha256(key, messages);
19+
return BitConverter.ToString(hash).Replace("-", "").ToLower();
20+
}
21+
22+
public static string GetHmacSha256Base64(byte[] key, params string[] messages)
23+
{
24+
var hash = ComputeHmacSha256(key, messages);
25+
return Convert.ToBase64String(hash);
26+
}
27+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
namespace Pandatech.Crypto.Tests;
2+
3+
public class Sha2Tests
4+
{
5+
[Fact]
6+
public void HmacSha256_ValidInput_ReturnsExpectedHash()
7+
{
8+
// Arrange
9+
var key = "secret"u8.ToArray();
10+
var messages = new[] { "Hello", "World" };
11+
const string expectedHashHex = "2e91612bb72b29d82f32789d063de62d5897a4ee5d3b5d34459801b94397b099";
12+
13+
// Act
14+
var hashHex = Sha2.GetHmacSha256Hex(key, messages);
15+
16+
// Assert
17+
Assert.Equal(expectedHashHex, hashHex);
18+
}
19+
20+
[Fact]
21+
public void HmacSha256_EmptyMessage_ReturnsHash()
22+
{
23+
// Arrange
24+
var key = "secret"u8.ToArray();
25+
var messages = Array.Empty<string>();
26+
27+
// Act
28+
var hash = Sha2.ComputeHmacSha256(key, messages);
29+
30+
// Assert
31+
Assert.NotNull(hash);
32+
Assert.NotEmpty(hash);
33+
}
34+
35+
[Fact]
36+
public void HmacSha256_ConsistentOutput_ForSameInputs()
37+
{
38+
// Arrange
39+
var key = "secret"u8.ToArray();
40+
var messages = new[] { "Test", "Message" };
41+
42+
// Act
43+
var hash1 = Sha2.GetHmacSha256Hex(key, messages);
44+
var hash2 = Sha2.GetHmacSha256Hex(key, messages);
45+
46+
// Assert
47+
Assert.Equal(hash1, hash2);
48+
}
49+
50+
[Fact]
51+
public void HmacSha256Base64_ValidInput_ReturnsExpectedBase64()
52+
{
53+
// Arrange
54+
var key = "secret"u8.ToArray();
55+
var messages = new[] { "Hello", "World" };
56+
const string expectedBase64 = "LpFhK7crKdgvMnidBj3mLViXpO5dO100RZgBuUOXsJk=";
57+
58+
// Act
59+
var base64Hash = Sha2.GetHmacSha256Base64(key, messages);
60+
61+
// Assert
62+
Assert.Equal(expectedBase64, base64Hash);
63+
}
64+
}

0 commit comments

Comments
 (0)