-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPBEncryption.cs
109 lines (94 loc) · 4.37 KB
/
PBEncryption.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
using System;
using System.Security.Cryptography;
using Org.BouncyCastle.Crypto.Generators;
using CryptoShark.Engine;
using System.Text;
using CryptoShark.Interfaces;
using CryptoShark.Enums;
namespace CryptoShark
{
/// <summary>
/// Password Based Encryption
/// </summary>
public class PBEncryption
{
private const int _keySize = 256;
private readonly Random _random = new Random();
private IHash _hash => Utilities.Instance;
/// <summary>
/// Encrypts the specified data with specified algorithm
/// and specified key size
/// </summary>
/// <param name="clearData">Data to Encrypt</param>
/// <param name="password">Password to use for Encryption</param>
/// <param name="encryptionAlgorithm">Encryption Algorithm to use</param>
/// <returns>Encryption Results</returns>
public Dto.PBEncryptionResult Encrypt(ReadOnlySpan<byte> clearData, string password,
EncryptionAlgorithm encryptionAlgorithm)
{
var engine = new EncryptionEngine(encryptionAlgorithm);
// Create our paramaters
var gcmNonce = GenerateSalt();
var pbkdfSalt = GenerateSalt();
var itterations = _random.Next(100000, 500000);
var key = PasswordDeriveBytes(password, pbkdfSalt, _keySize, itterations);
var hash = _hash.Hmac(clearData.ToArray(), key, Enums.HashAlgorithm.SHA2_384);
// Encrypt
var encrypted = engine.Encrypt(clearData, key, gcmNonce);
return new Dto.PBEncryptionResult
{
EncryptedData = encrypted.ToArray(),
GcmNonce = gcmNonce.ToArray(),
Algorithm = encryptionAlgorithm,
Sha384Hmac = hash.ToArray(),
Itterations = itterations,
PbkdfSalt = pbkdfSalt.ToArray()
};
}
/// <summary>
/// Decrypts the previously encypted data
/// </summary>
/// <param name="encryptedData">Encrypted Data</param>
/// <param name="password">Password</param>
/// <param name="algorithm">Encryption Algorithm</param>
/// <param name="gcmNonce">GCM Nonce Token</param>
/// <param name="pbkdfSalt">PBKDF2 Salt</param>
/// <param name="sha384Hmac">Hash of Decrypted Data</param>
/// <param name="itterations">Itterations for the PBKDF2 Key Derivation</param>
/// <returns></returns>
public ReadOnlySpan<byte> Decrypt(ReadOnlySpan<byte> encryptedData,
string password,
EncryptionAlgorithm algorithm,
ReadOnlySpan<byte> gcmNonce,
ReadOnlySpan<byte> pbkdfSalt,
ReadOnlySpan<byte> sha384Hmac,
int itterations)
{
// Create the Engine
var engine = new EncryptionEngine(algorithm);
// Generate the Key
var key = PasswordDeriveBytes(password, pbkdfSalt, _keySize, itterations);
// Decrypt the Data
var decrypted = engine.Decrypt(encryptedData, key, gcmNonce);
// Validate Hash
var verify = _hash.Hmac(decrypted, key, Enums.HashAlgorithm.SHA2_384);
if (!verify.SequenceEqual(sha384Hmac))
throw new CryptographicException($"Hash Of Decrypoted Data Does Not Match: Got 0x{BitConverter.ToString(verify.ToArray()).Replace("-", String.Empty)} Exptected {BitConverter.ToString(sha384Hmac.ToArray()).Replace("-", String.Empty)}");
return decrypted;
}
#region PrivateMethods
private ReadOnlySpan<byte> PasswordDeriveBytes(string password, ReadOnlySpan<byte> salt, int keySize, int itterations)
{
using (var deriveyutes = new Rfc2898DeriveBytes(password, salt.ToArray(), itterations, HashAlgorithmName.SHA512))
return deriveyutes.GetBytes(keySize / 8);
}
private ReadOnlySpan<byte> GenerateSalt(int size = 16)
{
var salt = new byte[size];
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
rng.GetNonZeroBytes(salt);
return salt;
}
#endregion
}
}