The idea was to create a simple way to hash any type of data. So, there are generic extensions for almost any type. A handful algorithms are currently offered, but more will be added over time. Some algorithms are performance optimized and probably more powerful than any other pure C# library of its kind.
$ dotnet add package Roydl.Crypto
Name | Bit Width | Algorithm | Type | Hardware Support |
---|---|---|---|---|
Adler-32 | 32-bit | Standard | Cyclic | |
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 | ✖️ |
SHA-1 | 160-bit | Built-in + HMAC keyed-hash support | Cryptographic | ✖️ |
SHA-2 | 256-bit 384-bit 512-bit |
Built-in + HMAC keyed-hash support | Cryptographic | ✖️ |
Especially for Alder 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 | 1566,2 MiB/s |
Adler-32 | This | Hardware | |
CRC-32 | Crc32.NET | Software | 1602,7 MiB/s |
CRC-32 | This | Software | 2040,9 MiB/s |
CRC-32 | This | Hardware | 8393.9 MiB/s |
SHA-256 | Built-in | Software | 1846,7 MiB/s |
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. It seems like 9 seconds is the sweet spot. Increasing this time does not provide more accurate results. However, repetitions offer better results by saving all results, determining the maximum and minimum values and thus identifying fluctuations. The most accurate result seems to be the average of 20 repetitions. You can find the test case here.
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, i.e. Array, or any IEnumerable{T} char sequence, i.e. string, any many more.
Not every type makes sense, but is supported anyway.
string hash = value.GetChecksum(ChecksumAlgo.Sha1);
Console.WriteLine(hash);
// Output:
// 12a5ba5baa1664f73e6279f23354bd90c8981a81
However, 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 earlier. This can be useful with cyclic computed hashes.
ulong hash = value.GetCipher(ChecksumAlgo.Crc64);
Note that HMAC
keyed-hashing is only supported for cryptographic algorithms via instances by setting a secret key.
Sha512 instance = Sha512.Create(new byte[128] { /* some bytes */ });
The ComputeHash
methods uses 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);
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 from 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. It follows the same rules that have already been explained above.
ReadOnlyMemory<byte> rawHash = crc.RawHash;
uint cipher = crc.CipherHash;
string lowercase = crc.Hash;
Check out the CRC configuration manager to see more examples.
Name | Algorithm |
---|---|
Rijndael | 128 bit block size; optional: 128 , 192 or 256 bit key size, cipher and padding modes |
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);
- 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 🍰
Please note that I cannot fix bugs that are unknown to me. So do yourself and me the favor and get in touch with me. 🤕