diff --git a/README.md b/README.md index 58f84b7..5c66415 100644 --- a/README.md +++ b/README.md @@ -1 +1,7 @@ -# HashingHandler \ No newline at end of file +# HashingHandler + +A C# library containing abstract classes for hashing data of various types. + +View & Download this project on [NuGet](https://www.nuget.org/packages/HashingHandler/) + +View the documentation for this project at [the website](https://simon-techkid.github.io/HashingHandler/). diff --git a/docfx/docs/toc.yml b/docfx/docs/toc.yml deleted file mode 100644 index d7e9ea8..0000000 --- a/docfx/docs/toc.yml +++ /dev/null @@ -1,4 +0,0 @@ -- name: Introduction - href: introduction.md -- name: Getting Started - href: getting-started.md \ No newline at end of file diff --git a/docfx/toc.yml b/docfx/toc.yml index 061acc6..8990cd9 100644 --- a/docfx/toc.yml +++ b/docfx/toc.yml @@ -1,4 +1,4 @@ - name: Docs - href: docs/ + href: ../docs/ - name: API href: api/ \ No newline at end of file diff --git a/docs/IHashingAlgorithm.md b/docs/IHashingAlgorithm.md new file mode 100644 index 0000000..36dd4e8 --- /dev/null +++ b/docs/IHashingAlgorithm.md @@ -0,0 +1,153 @@ +# IHashingAlgorithm and IHashingAlgorithmAsync + +`HashingAlgorithmBase` is the primary base class for implementations of `IHashingAlgorithm` and `IHashingAlgorithmAsync`. It provides support for both synchronous and asynchronous hash computation, using `protected` methods `byte[] ComputeHash()` and `Task ComputeHashAsync()`, as well as synchronous and asynchronous checksum computation of those hashes, using `public` methods `string ComputeHash()` and `Task ComputeHashAsync()`. + +## Variants + +### IHashingAlgorithm + +`IHashingAlgorithm` is used for accessing hash algorithm classes. These classes allow the hashing of byte arrays (`byte[]`), producing `string` checksums of the given data. + +### IHashingAlgorithmAsync + +`IHashingAlgorithmAsync` allows the asynchronous use of `IHashingAlgorithm`. It implements `IHashingAlgorithm`, so objects capable of asynchronous computation are also able to leverage synchronous methods. + +## HashingCrypto and HashingNonCrypto + +HashingHandler contains base classes for creating hashes using its `HashingCrypto` and `HashingNonCrypto` classes, allowing hash creation using [HashAlgorithm](https://learn.microsoft.com/dotnet/api/system.security.cryptography.hashalgorithm) and [NonCryptographicHashAlgorithm](https://learn.microsoft.com/dotnet/api/system.io.hashing.noncryptographichashalgorithm), respectively. + +Both of these classes implement `IHashingAlgorithm` and `IHashingAlgorithmAsync` because they inherit `HashingNonCrypto` and `HashingAlgorithmBase`. This allows you to create common functionality across your program by using the shared methods in different contexts. + +### Getting Started + +To get started using `HashingCrypto` and `HashingNonCrypto` abstract classes in your program, you must create a class that implements one of these. Below are samples that allow calculation of SHA256 and XXH3 hashes using both `HashAlgorithm` and `NonCryptographicHashAlgorithm` abstract classes. + +In your class implementing `HashingCrypto` or `HashingNonCrypto`, you must provide a method, `GetAlgorithm()`, that returns an instance of a hashing class (ie. `SHA256` or `XxHash3`) derived from either `HashAlgorithm` or `NonCryptographicHashAlgorithm`, respectively. This instance will then be used by the base, implemented class to create hashes using those algorithms. + +See the sample implementations below of each. + +## Samples + +After creating a class that inherits `IHashingAlgorithm` (including the below samples), you are able to compute hashes for data of type `T`, using the `IHashingAlgorithm.ComputeHash()` method. This method returns a `string` of the hash of the data. + +#### HashingCrypto + +``` +class SHA256Hasher : HashingCrypto +{ + protected override HashAlgorithm GetAlgorithm() + { + return SHA256.Create(); // Returns new SHA256 object + } +} +``` + +To create a hash using the SHA256 algorithm, construct this `SHA256Hasher` class. + +It can be cast to `IHashingAlgorithm`: +``` +IHashingAlgorithm sha256 = new SHA256Hasher(); +``` + +It can also be cast to `IHashingAlgorithmAsync` for asynchronous use, because `HashingCrypto` implements it. +``` +IHashingAlgorithmAsync sha256Async = new SHA256Hasher(); +``` + +#### HashingNonCrypto + +``` +class XXH3Hasher(long seed = 0) : HashingNonCrypto +{ + private readonly long _seed = seed; // XxHash3 allows a seed, so we will add seed support to our class + + protected override NonCryptographicHashAlgorithm GetAlgorithm() + { + return new XxHash3(_seed); + } +} +``` + +To create a hash using the XXH3 algorithm, construct this `XXH3Hasher` class. + +It can be cast to `IHashingAlgorithm`: +``` +IHashingAlgorithm xxh3 = new XXH3Hasher(); +``` + +It can also be cast to `IHashingAlgorithmAsync` for asynchronous use, because `HashingNonCrypto` implements it. +``` +IHashingAlgorithmAsync xxh3Async = new XXH3Hasher(); +``` + +#### Create Your Own + +To create your own hashing algorithm, create a class implementing `IHashingAlgorithm` or `IHashingAlgorithmAsync`. Remember, `IHashingAlgorithmAsync` implements `IHashingAlgorithm`, so you must provide a synchronous implementation for it! + +I've chosen to inherit `HashingAlgorithmBase`, because it provides both asynchronous and synchronous support in the base class. The below example provides a synchronous implementation. + +By inheriting `HashingAlgorithmBase`, you make this `XORHash` class an `IHashingAlgorithm` and `IHashingAlgorithmAsync`. + +The below example is a simple XOR hash algorithm: + +``` +class XORHash : HashingAlgorithmBase +{ + protected override byte[] ComputeHash(byte[] bytes) + { + // Specify the length of the payload to be hashed. + int payloadLength = bytes.Length; // Let's hash the entire payload. + + // Specify the length of the returned hash. + int hashLength = 8; // 8 bytes, 16 characters + + // Initialize result array to hold the hash of specified length + byte[] result = new byte[hashLength]; + + // Perform XOR on the bytes, distributing across each position in result + for (int i = 0; i < payloadLength; i++) + { + result[i % hashLength] ^= bytes[i]; + } + + return result; + } +} +``` + +To create a hash using this sample algorithm, construct this `XORHash` class. + +It can be cast to `IHashingAlgorithm`: +``` +IHashingAlgorithm xor = new XORHash(); +``` + +It can also be cast to `IHashingAlgorithmAsync` for asynchronous use, because `HashingAlgorithmBase` implements it. +``` +IHashingAlgorithmAsync xor = new XORHash(); +``` + +Because we didn't override `HashingAlgorithmBase.ComputeHashAsync()` in the above sample implementation, any calls to `xor.ComputeHashAsync()` will use the default implementation, a `Task.Run()` of the synchronous implementation, `ComputeHash()`. If you'd like to create a specific asynchronous implementation, override `ComputeHashAsync()`. + +### Conclusion + +After creating the `IHashingAlgorithm` or `IHashingAlgorithmAsync` implementing object, you can perform hashing using the methods of `IHashingAlgorithm` or `IHashingAlgorithmAsync`, respectively. + +``` +// Create an IHashingProvider, where T matches the type of your IHashingAlgorithm. +// Assume we have instantiated an IHashingProvider called 'provider' +// See the above samples on how to create an IHashingAlgorithm. +// Assume we have instantiated an IHashingAlgorithm called 'algorithm' + +string textPayload = "Hello World!"; +return algorithm.ComputeHash(textPayload, provider); +``` + +We can also do it asynchronously, if our `algorithm` instance is `IHashingAlgorithmAsync` + +``` +// Simulated asynchronous method below by using GetAwaiter().GetResult() +return algorithm.ComputeHashAsync(textPayload, provider).GetAwaiter().GetResult(); +``` + +Remember, `IHashingAlgorithmAsync` implements `IHashingAlgorithm`, so you can perform synchronous hashing using an asynchronous hashing capable object using the methods of `IHashingAlgorithm` on an `IHashingAlgorithmAsync`. \ No newline at end of file diff --git a/docs/IHashingProvider.md b/docs/IHashingProvider.md new file mode 100644 index 0000000..b9fbb74 --- /dev/null +++ b/docs/IHashingProvider.md @@ -0,0 +1,60 @@ +# IHashingProvider and IHashingProviderAsync + +## Variants + +### IHashingProvider + +`IHashingProvider` is used when an object can convert the data to be hashed of type `T` to a byte array (`byte[]`), so that the byte array can serve as a common type in all hash operations. + +### IHashingProviderAsync + +`IHashingProviderAsync` is offered when an object of type `T` can be converted to a byte array asynchronously. `IHashingProviderAsync` implements `IHashingProvider`, so objects that are capable of handling asynchronous conversions are also able to leverage the synchronous methods of `IHashingProvider`. + +## Examples + +You can find several examples of data types that you may want to create hashes for. + +### Strings + +HashingHandler contains a built-in base class to serve as an `IHashingProvider` for `string` types, `StringHashProviderBase`. Implementers of `StringHashProviderBase` must define how to convert the data of type `T` to a `string`. The base class, `StringHashProviderBase` handles conversion of this string (using the method `ConvertToString`) to bytes, using a byte encoding. + +Adding the below class to your program, which implements `StringHashProviderBase`, will provide a structure for hashing `string` instances. + +``` +class StringProvider : StringHashProviderBase +{ + protected override string ConvertToString(string data) + { + return data; // Already string, no conversion necessary + } + + // Below is not a required field, but overriding it in your class will allow you to use other byte encodings than the default, UTF8. + protected override Encoding HashedDataEncoding => Encoding.UTF16 +} +``` + +Because this `StringProvider` class inherits `StringHashProviderBase`, it also implements `IHashingProvider`. + +To create a provider for converting the `string` data type to `byte[]` for hashing later, construct the example `StringProvider` class. + +``` +IHashingProvider provider = new StringProvider(); +``` + +You now have an `IHashingProvider` that can be passed to an `IHashingAlgorithm` to create a hash. + +``` +// Assume we have initialized the provider as well as an IHashingAlgorithm above. +// The IHashingProvider instance is called 'provider' +// The IHashingAlgorithm instance is called 'algorithm' + +string testPayload = "Hello World!"; +string testHash = algorithm.ComputeHash(testPayload, provider); +Console.WriteLine(testHash); +``` + +We can compute the hash on another thread, if you've got an `IHashingAlgorithmAsync`. Let's call the instance of the algorithm `algorithm`. + +``` +string testHash = algorithm.ComputeHashAsync(testPayload, provider).GetAwaiter().GetResult(); +``` \ No newline at end of file diff --git a/docfx/docs/getting-started.md b/docs/getting-started.md similarity index 100% rename from docfx/docs/getting-started.md rename to docs/getting-started.md diff --git a/docfx/docs/introduction.md b/docs/introduction.md similarity index 100% rename from docfx/docs/introduction.md rename to docs/introduction.md diff --git a/docs/toc.yml b/docs/toc.yml new file mode 100644 index 0000000..a81b27a --- /dev/null +++ b/docs/toc.yml @@ -0,0 +1,8 @@ +- name: Introduction + href: introduction.md +- name: Getting Started + href: getting-started.md +- name: IHashingAlgorithm and IHashingAlgorithmAsync + href: IHashingAlgorithm.md +- name: IHashingProvider and IHashingProviderAsync + href: IHashingProvider.md \ No newline at end of file diff --git a/src/IHashVerifierAsync.cs b/src/IHashVerifierAsync.cs index 2fd6f6c..667db34 100644 --- a/src/IHashVerifierAsync.cs +++ b/src/IHashVerifierAsync.cs @@ -18,6 +18,6 @@ public interface IHashVerifierAsync : IHashVerifier /// A representing the expected hash for the given of type . /// The algorithm used to hash the given data of type . /// A cancellation token allowing the canceling of asynchronous jobs. - /// + /// True, if the hashes match. Otherwise, false. public Task VerifyHashAsync(T data, string expectedHash, IHashingAlgorithm algorithm, CancellationToken cancellationToken = default); }