DataJuggler.Cryptography 8.0.1

dotnet add package DataJuggler.Cryptography --version 8.0.1
NuGet\Install-Package DataJuggler.Cryptography -Version 8.0.1
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DataJuggler.Cryptography" Version="8.0.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add DataJuggler.Cryptography --version 8.0.1
#r "nuget: DataJuggler.Cryptography, 8.0.1"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install DataJuggler.Cryptography as a Cake Addin
#addin nuget:?package=DataJuggler.Cryptography&version=8.0.1

// Install DataJuggler.Cryptography as a Cake Tool
#tool nuget:?package=DataJuggler.Cryptography&version=8.0.1

Nuget Package Name: DataJuggler.Cryptography

This version is for .NET 8. Use a 7.x version for .NET 7, a 6.x for .NET 6.

News

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:

  1. Encryption / Decryption, with or without an encryption key using System.Security.Cryptography.AesManaged
  2. 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:

https://github.com/DataJuggler/Blazor.Crypto

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (3)

Showing the top 3 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.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.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.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
8.0.1 1,643 11/20/2023
8.0.0 1,120 11/14/2023
7.1.1 1,856 8/14/2023
7.1.0 1,800 7/16/2023
7.0.0 26,195 11/8/2022
7.0.0-rc1 786 10/19/2022
6.0.5 640 6/17/2022
6.0.4 588 6/8/2022
6.0.3 2,181 1/23/2022
6.0.2 521 11/18/2021
6.0.1 314 11/18/2021
6.0.0 265 11/18/2021

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.