DataJuggler.Cryptography
9.0.1
dotnet add package DataJuggler.Cryptography --version 9.0.1
NuGet\Install-Package DataJuggler.Cryptography -Version 9.0.1
<PackageReference Include="DataJuggler.Cryptography" Version="9.0.1" />
paket add DataJuggler.Cryptography --version 9.0.1
#r "nuget: DataJuggler.Cryptography, 9.0.1"
// Install DataJuggler.Cryptography as a Cake Addin #addin nuget:?package=DataJuggler.Cryptography&version=9.0.1 // Install DataJuggler.Cryptography as a Cake Tool #tool nuget:?package=DataJuggler.Cryptography&version=9.0.1
Nuget Package Name: DataJuggler.Cryptography
This version is for .NET 9. Use a 8.x version for .NET 8, a 7.x for .NET 7.
News
Update 11.19.2024: DataJuggler.Cryptography has been updated to .NET 9.
Update 11.20.2023: DataJuggler.UltimateHelper was updated.
Update 11.14.2023: DataJuggler.Cryptography has been updated to .NET 8.
Update 8.13.2023: DataJuggler.UltimateHelper was updated.
Update: 7.16.2023 I opened this project for the first time in a long time, and discovered the constructor for Rfc2898DeriveBytes was deemed obsolete. I changed the HashAlgorithm name to HashAlgorithmName.SHA512. This probably breaks any existing users, and for that I apologize.
DataJuggler.Cryptography
This is a port of CryptographyHelper from DataJuggler.Core.UltimateHelper for dot net framework. This class uses System.Security.AesManaged for encrypt / decryption and Konscious.Security.Cryptography.Argon2 by Keef Aragon for password hashing.
This is a copy of CryptographyHelper class from DataJuggler.Core.UltimateHelper for the .Net Framework. Originally I added this class to the Dot Net Core version of UltimateHelper called DataJuggler.UltimateHelper.Core, but Nuget needs to add about 50 or 60 packages for Argon2, so I moved this class to its own library.
To use this package:
Install Package: DataJuggler.Cryptography
There are two main functions for the project:
- Encryption / Decryption, with or without an encryption key using System.Security.Cryptography.AesManaged
- Password Hashing using Konscious.Security.Cryptography.Argon2
To use in your own projects after you install the package via Nuget
using DataJuggler.Cryptography;
There is a constant available called DefaultPassword. The Encryption / Decryption methods and the GeneratePasswordHash methods contain overrides that allow you to supply your own keyCode or you may use the DefaultPassword:
Default Password
public const string DefaultPassword = "NotASecret";
Encryption
public static string EncryptString(string stringToEncrypt, string password)
To encrypt a string, call the EncryptString method
To use your own password
string encrypted = CryptographyHelper.EncryptString(stringToEncrypt, password);
To use default password
string encrypted = CryptographyHelper.EncryptString(stringToEncrypt);
The encryption algorithm will return a different result every time you encrypt a string.
Decryption
public static string DecryptString(string stringToDecrypt, string password)
You muse use the same password key to decrypt a string that you used to encrypt.
To use your own password
string decrypted = CryptographyHelper.DecryptString(stringToDecrypt, password);
To use default password
string decrypted = CryptographyHelper.DecryptString(stringToDecrypt);
Password Hashing
public static string GeneratePasswordHash(string password, string keyCode)
This method hashes the password using Konscious.Security.Cryptography's implementation of Argon2 by Keef Aragon.
Salt
Source: https://learncryptography.com/hash-functions/password-salting
Password salting is the process of securing password hashes from something called a Rainbow Table attack. The problem with non-salted passwords is that they do not have a property that is unique to themselves – that is, if someone had a precomputed rainbow table of common password hashes, they could easily compare them to a database and see who had used which common password. A rainbow table is a pre-generated list of hash inputs to outputs, to quickly be able to look up an input (in this case, a password), from its hash. However, a rainbow table attack is only possible because the output of a hash function is always the same with the same input.
(I didn't want to try and define salt because I knew I would not do it justice).
The salt is returned with the password separated by 4 | pipe characters.
You can decrypt the encrypted password hash to determine the password hash and salt, but you cannot decrypt from password hash back to the original password.
To generate a Password Hash using your own keyCode
string passwordHash = CryptographyHelper.GeneratePasswordHash(password, keyCode);
To generate a Password Hash using your the default keyCode
string passwordHash = CryptographyHelper.GeneratePasswordHash(password);
VerifyHash
public static bool VerifyHash(string userTypedPassword, string keyCode, string storedPasswordHash)
To implement login functionality you need to verify the user typed in password can verify against your stored password hash.
If you supplied a keyCode to generate a password hash you must supply the same keyCode to verify.
To verify using your own keyCode
bool verifiedLogin = CryptographyHelper.VerifyHash(userTypedInPassword, keyCode, storedPasswordHash);
To verify using default keyCode
bool verifiedLogin = CryptographyHelper.VerifyHash(userTypedInPassword, storedPasswordHash);
How VerifyHash works
Your storedPasswordHash is first decrypted using either the supplied keyCode or the DefaultPassword of NotASecret depending on which override you called.
The result will then contain a string made up of the passwordHash followed by a separator of 4 pipe characters in a row |||| and then the salt.
This is an example, just to show the decrypted text of the password hash uses Unicode characters
憭紷줧悐纴Ꮄ⫘||||䣿別坵ࠀ恆쁿냞
Next the PasswordHash is determined from the left half of the 4 pipe characters.
The salty string is the characters after the 4 pipe characters.
Both salt and storedHash are both byte arrays.
byte[] salt = null;<br/> byte[] storedHash = null;
// get the index<br/> int index = decryptedHash.IndexOf("||||");
// if the index was found<br/> if (index >= 0)<br/> {<br/> // get the password<br/> password = decryptedHash.Substring(0, index);<br/> salty = decryptedHash.Substring(index + 4);<br/> salt = Encoding.Unicode.GetBytes(salty);<br/> storedHash = Encoding.Unicode.GetBytes(password);<br/> }<br/> <br/> At this point, the salt and storedHash should be loaded, so we can call another verifyHash override.
public static bool VerifyHash(string password, byte[] salt, byte[] storedHash)
The verifyHash method creates a new passwordHash and compares it to the storedHash using Linq.
// generate the loginHash again<br/><br/> var newHash = HashPassword(password, salt);<br/>
// set the return value<br/> verified = storedHash.SequenceEqual(newHash);<br/> <br/> I just built a Blazor.Crypto sample, but I wanted to publish the Nuget package first.
The sample is located here:
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net9.0 is compatible. |
-
net9.0
- DataJuggler.UltimateHelper (>= 9.0.2)
- Konscious.Security.Cryptography.Argon2 (>= 1.3.1)
NuGet packages (4)
Showing the top 4 NuGet packages that depend on DataJuggler.Cryptography:
Package | Downloads |
---|---|
DataJuggler.Net7
This class is for .NET7 and is a port of DataJuggler.Net for the .Net Framework, which is used by DataTier.Net and DB Compare to read SQL Server database schema and code generate stored procedure driven data tiers. Breaking Change: Now that this project uses Microsoft.Data.SqlClient 5.0, connection strings must set Encrypt = False if your database is not encrypted. The two main classes are: SQLDatabaseConnector - A wrapper for SqlDatabaseConnection that reads database schema. CSharpClassWriter - A class that is useful in code generating C# classes. |
|
DataJuggler.Net8
This class is for .NET8 and is a port of DataJuggler.Net for the .Net Framework, which is used by DataTier.Net and DB Compare to read SQL Server database schema and code generate stored procedure driven data tiers. Breaking Change: Now that this project uses Microsoft.Data.SqlClient 5.0+, connection strings must set Encrypt = False if your database is not encrypted. The two main classes are: SQLDatabaseConnector - A wrapper for SqlDatabaseConnection that reads database schema. CSharpClassWriter - A class that is useful in code generating C# classes. |
|
DataJuggler.Net6
This class is for .NET6 and is a port of DataJuggler.Net for the .Net Framework, which is used by DataTier.Net and DB Compare to read SQL Server database schema and code generate stored procedure driven data tiers. The two main classes are: SQLDatabaseConnector - A wrapper for SqlDatabaseConnection that reads database schema. CSharpClassWriter - A class that is useful in code generating C# classes. |
|
DataJuggler.Net9
This class is for .NET9 and is a port of DataJuggler.Net for the .Net Framework, which is used by DataTier.Net and DB Compare to read SQL Server database schema and code generate stored procedure driven data tiers. -- Notes for .NET 8 carried over. Still Apply. Breaking Change: Now that this project uses Microsoft.Data.SqlClient 5.0+, connection strings must set Encrypt = False if your database is not encrypted. The two main classes are: SQLDatabaseConnector - A wrapper for SqlDatabaseConnection that reads database schema. CSharpClassWriter - A class that is useful in code generating C# classes. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
9.0.1 | 319 | 11/22/2024 |
9.0.0 | 118 | 11/19/2024 |
8.0.1 | 5,678 | 11/20/2023 |
8.0.0 | 1,736 | 11/14/2023 |
7.1.1 | 2,019 | 8/14/2023 |
7.1.0 | 1,967 | 7/16/2023 |
7.0.0 | 27,102 | 11/8/2022 |
7.0.0-rc1 | 851 | 10/19/2022 |
6.0.5 | 689 | 6/17/2022 |
6.0.4 | 629 | 6/8/2022 |
6.0.3 | 2,296 | 1/23/2022 |
6.0.2 | 581 | 11/18/2021 |
6.0.1 | 344 | 11/18/2021 |
6.0.0 | 302 | 11/18/2021 |
11.19.2024: This project was updated to .NET 9.
11.20.2023: DataJuggler.UltimateHelper was updated.
11.14.2023: DataJuggler.Cryptography has been updated to .NET 8.
8.13.2023: DataJuggler.UltimateHelper was updated.
7.16.2023: The constructor for Rfc2898DeriveBytes was obsolete, so I had to add a parameter for
HaslAlgorithmName.SHA512. Apologies if this breaks anything.
11.8.2022
v7.00: .NET 7 is out of preview, so this version is out of preview.
10.19.2022: v7.0.0-rc1 is the same code base as v6.0.5. The only difference
is the TargetFramework is now .NET 7.
6.17.2022 v6.0.5: Updated DataJuggler.UltimateHelper.
6.8.2022 v6.0.4: Updated DataJuggler.UltimateHelper and Argon Nuget package.
1.23.2022: DataJuggler.UltimateHelper was updated, so I updated this project.
11.17.2021 (Take Three)
x64 is kind of useless if you can only use it in x64 projects, so I had to switch back to any cpu.
11.17.2021 (Take Two)
Verion 6.0.1: Changing the package name doesn't change the namespace, so I had to do a global search and replace.
The namespace is now correct at DataJuggler.Cryptography.
11.17.2021
Version 6.0.0: I updated to version 6.0.0, and I dropped the name. I am going to try and multi-target
.Net 5 and 6 with this version. We will see the results soon.
Version 1.5.0 - I ported this to .Net 5. Not sure if there are any advantages for doing that or not.
Version 1.0.11 - I added a new optional parameter for VerifyHash that allows you to state that the userTypedPassword is actually a PasswordHash itself. This use case is designed for use with ProtectedLocalStorage to allow you to store the password hash on the client browser.
This validation compares two encrypted passowrd hash strings that they are equal. As a test of security, it is verified that the encryptedPasswordHash stored can be used to create the salt. If the string decrypts with the keycode given and the salt is valid 16 bytes and the strings match exactly then this is considered verified also.
Version 1.0.10 - I started testing today for the first time using the Nuget package and I couldn't get the class to show up. Trying again with the code set to Debug mode as it worked before I switched to Release.
Version 1.0.9 - I am trying recreating the salt every time. Some password fail up to max retires
count, and perhaps the salt is the problem. I noticed NotASecret default password is where this
problem occurs. I might change it to something else if this still fails.
Version 1.0.8 - I added a verifyRetries parameter to GeneratePasswordHash method. If set to true,
the method will try and verify if it cannot be verified a new hash will be created and tried again up
to the verirfyRetries count.
Version 1.0.7 - I added try catches to all the methods.
The first release had the wrong namespace.