Skip to content

Roydl/Crypto

Repository files navigation

.NET Core Cross-platform License

Build+Test Commits Releases Source

NuGet NuGet Website Mirror

Roydl.Crypto

Roydl.Crypto provides a simple, generic way to hash virtually any .NET type. Generic extensions are available for almost every type, and a growing set of algorithms is offered — some of which are performance-optimized and likely more powerful than any other pure C# library of their kind.

Table of Contents


Prerequisites

  • .NET 10 LTS or higher
  • Supported platforms: Windows, Linux, macOS
  • Hardware acceleration (optional): SSE4.2, SSSE3, AVX2, or AVX-512 capable CPU

Install

$ dotnet add package Roydl.Crypto

Checksum Algorithms

Name Bit Width Algorithm Type Hardware Support
Adler-32 32-bit Standard Cyclic AVX-512
AVX2
SSSE3
CRC from 8-bit
to 82-bit
88 presets available + customizable Cyclic iSCSI @ SSE4.2 CPU
iSCSI+PKZip @ ARM
MD5 128-bit Built-in + HMAC keyed-hash support Cryptographic See ¹
SHA1 160-bit Built-in + HMAC keyed-hash support Cryptographic See ¹
SHA2 256-bit
384-bit
512-bit
Built-in + HMAC keyed-hash support Cryptographic See ¹
SHA3 256-bit
384-bit
512-bit
Built-in + HMAC keyed-hash support Cryptographic See ¹

¹ Hardware acceleration for cryptographic algorithms is handled transparently by the .NET runtime and depends on the underlying platform (e.g. Intel SHA Extensions for SHA1 and SHA2-256 on supported CPUs).


Checksum Performance

Especially for Adler and CRC, the performance in software mode should be much better than with any other pure C# library, but similar to libraries that work with C/C++ imports. However, I couldn't find any other library with hardware support, not even with imports.

Algorithm Library Mode Speed
Adler-32 This Software 3028.4 MiB/s
Adler-32 This Hardware (SSSE3) 36449.9 MiB/s
Adler-32 This Hardware (AVX2) 73427.1 MiB/s
CRC-32 Crc32.NET Software 2334.3 MiB/s
CRC-32 This Software 3098.6 MiB/s
CRC-32 This Hardware 12910.5 MiB/s
SHA2-256 Built-in Software 2282.7 MiB/s
SHA3-256 Built-in Software 670.5 MiB/s
Benchmark methodology
Component Details
CPU AMD Ryzen 5 7600 (6C/12T, 5.1 GHz boost)
RAM 32 GB DDR5
OS Manjaro Linux (Kernel 6.19.2-1)
Runtime .NET 10
Build Release (dotnet run -c Release)

In the test case, a 64 KiB packet with random bytes is generated, which is sent over and over again within 9 seconds by the function that computes the hash. During this process, it is determined several times how much data could be hashed within 1 second. 9 seconds proved to be the optimal duration — increasing this time does not provide more accurate results. Running multiple repetitions yields more reliable results: all individual values are recorded, outliers identified via min/max comparison, and the final result taken as the average of 20 runs. You can find the test case here.


Usage

GetChecksum & GetCipher

The GetChecksum extension method retrieves a string representation of the computed hash.

The value can be almost anything: bool, sbyte, byte, short, ushort, char, int, uint, long, ulong, Half, float, double, decimal, Enum, IntPtr, UIntPtr, Vector{T}, Vector2, Vector3, Vector4, Matrix3x2, Matrix4x4, Plane, Quaternion, Complex, BigInteger, DateTime, DateTimeOffset, TimeSpan, Guid, Rune, Stream, StreamReader, FileInfo, any IEnumerable{T} byte sequence (e.g. Array), any IEnumerable{T} char sequence (e.g. string), and many more.

Not every type is a meaningful candidate for hashing, but all are supported for completeness.

string hash = value.GetChecksum(ChecksumAlgo.Sha1);
Console.WriteLine(hash);

// Output:
// 12a5ba5baa1664f73e6279f23354bd90c8981a81

A string containing a file path has an additional method:

string hash = value.GetFileChecksum(); // SHA-256 is used when `ChecksumAlgo` is undefined

The GetCipher extension method retrieves an unsigned 64-bit integer representation of the computed hash. It follows the same rules outlined above. This can be useful with cyclic computed hashes.

ulong hash = value.GetCipher(ChecksumAlgo.Crc64);

HMAC Keyed-Hashing

Note that HMAC keyed-hashing is only supported for cryptographic algorithms via instances by setting a secret key.

Sha3 instance = Sha3.Create(new byte[128] { /* some bytes */ });

The ComputeHash methods use the secret key until DestroySecretKey is called.

instance.ComputeHash(value);

An instance provides a computed hash in several variants:

ReadOnlySpan<byte> rawHash = instance.RawHash;
BigInteger cipher = instance.CipherHash; // The integral type depends on the bit length, e.g. CRC-32 is `UInt32`
string lowercase = instance.Hash;
string uppercase = instance.ToString(true);

Casting is also supported to get a hash:

byte[] copyOfRawHash = (byte[])instance;
ulong cipher = (ulong)instance; // Numeric conversions are unchecked conversions of the `instance.CipherHash` field
string lowercase = (string)instance;

Instances also provide equality operators for quick comparison:

bool equ = (instance1 == instance2);
bool neq = (instance1 != instance2);

CRC Customization

If you need a different CRC algorithm, you can easily create your own variation.

This is an example for CRC-32/POSIX, but it should support many others from 8-bit to almost infinite bits.

const int width = 32;
const uint check = 0x765e7680u;
const uint poly = 0x04c11db7u;
const uint init = 0x00000000u;
const bool refIn = false;
const bool refOut = false;
const uint xorOut = 0xffffffffu;
const uint mask = 0xffffffffu;
const bool skipValidation = false;

Sets a new CrcConfig with the constants from above. The data are automatically validated with the given check.

var cfg = new CrcConfig32(width, check, poly, init, refIn, refOut, xorOut, mask, skipValidation);

Compute the hash directly via the configuration structure:

cfg.ComputeHash(stream, out uint cipher);

Or load it into the CRC class which has more features, and compute the hash code from there.

The value can be of type Stream, byte[], string, FileInfo, or a string containing a file path.

var crc = new Crc<uint>(config);
crc.ComputeHash(value);

As mentioned earlier, instances offer computed hashes in several variants:

ReadOnlyMemory<byte> rawHash = crc.RawHash;
uint cipher = crc.CipherHash;
string lowercase = crc.Hash;

Check out the CRC configuration manager to see more examples.


Encryption Algorithms

Name Algorithm
Rijndael (AES) 128-bit block size; optional: 128, 192, or 256-bit key size, configurable cipher and padding modes

Rijndael (AES)

Note: Rijndael with a 128-bit block size is equivalent to AES. For modern applications, prefer SymmetricKeySize.Large (256-bit) and an authenticated cipher mode such as GCM where possible.

byte[] password = new byte[] { /* some bytes */ };
byte[] salt = new byte[] { /* some bytes */ };
using var aes = new Rijndael(password, salt, 1000, SymmetricKeySize.Large);
aes.Encrypt(streamToEncrypt, encryptedStream);
aes.Decrypt(streamToDecrypt, decryptedStream);

Would you like to help?

  • Star this Project ⭐ and show me that this project interests you 🤗
  • Open an Issue ☕ to give me your feedback and tell me your ideas and wishes for the future 😎
  • Open a Ticket 📫 if you don't have a GitHub account, you can contact me directly on my website 😉
  • Donate by PayPal 💸 to buy me some cakes 🍰

About

📚 Provides a handy way to hash data using Adler32, CRC (8-bit to 82-bit, and customizable without bit restriction), MD5, SHA-1, SHA-2 and SHA-3 (256-bit, 384-bit and 512-bit), including HMAC keyed hashing for some types. Functions for encrypting and decrypting data with Rijndael (128-bit, 192-bit and 256-bit) are also offered

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

  •  

Packages

 
 
 

Contributors

Languages