Skip to content

Commit

Permalink
Add possibility to specify encoding when hashing strings (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kralizek committed Feb 11, 2021
1 parent 6f102e1 commit 438d702
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 11 deletions.
9 changes: 9 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,12 @@ deploy:
- master
- main
appveyor_repo_tag: true
- provider: GitHub
on:
branch:
- master
- main
appveyor_repo_tag: true
auth_token:
secure: Qv4tMB9BvNni2+v69vK38jQq2ga1+GiI/YqCWkiA1fZN72v2NtaZo6UpwmXQNkop
artifact: /.*.nupkg/
29 changes: 25 additions & 4 deletions src/StringExtensions/HashStringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,21 @@ public static class HashStringExtensions
/// Calculates an hashed representation of <paramref name="input"/> using the given <paramref name="algorithm"/> and the <paramref name="byteFormat"/>.
/// </summary>
/// <param name="input">The <see cref="string"/> to hash.</param>
/// <param name="encoding">The <see cref="Encoding" /> used to read the string.</param>
/// <param name="algorithm">An instance of <see cref="HashAlgorithm" /> used to calculate the hash <paramref name="input"/>.</param>
/// <param name="byteFormat">The format string used to convert each byte into a string. Default is <c>x2</c>.</param>
/// <returns>The hash of input string.</returns>
public static string Hash(this string input, HashAlgorithm algorithm, string byteFormat = "x2")
public static string Hash(this string input, Encoding encoding, HashAlgorithm algorithm, string byteFormat = "x2")
{
_ = input ?? throw new ArgumentNullException(nameof(input));

_ = encoding ?? throw new ArgumentNullException(nameof(encoding));

_ = algorithm ?? throw new ArgumentNullException(nameof(algorithm));

_ = byteFormat ?? throw new ArgumentNullException(nameof(byteFormat));

var inputBytes = Encoding.UTF8.GetBytes(input);
var inputBytes = encoding.GetBytes(input);

var hashBytes = algorithm.ComputeHash(inputBytes);

Expand All @@ -39,19 +42,37 @@ public static string Hash(this string input, HashAlgorithm algorithm, string byt
return sb.ToString();
}

/// <summary>
/// Calculates an hashed representation of <paramref name="input"/> using the given <paramref name="algorithm"/> and the <paramref name="byteFormat"/>. The string will be interpreted using <see cref="Encoding.UTF8" />.
/// </summary>
/// <param name="input">The <see cref="string"/> to hash.</param>
/// <param name="algorithm">An instance of <see cref="HashAlgorithm" /> used to calculate the hash <paramref name="input"/>.</param>
/// <param name="byteFormat">The format string used to convert each byte into a string. Default is <c>x2</c>.</param>
/// <returns>The hash of input string.</returns>
public static string Hash(this string input, HashAlgorithm algorithm, string byteFormat = "x2") => Hash(input, Encoding.UTF8, algorithm, byteFormat);

/// <summary>
/// Calculates an hashed representation of <paramref name="input"/> using MD5 and the <paramref name="byteFormat"/>.
/// </summary>
/// <param name="input">The <see cref="string"/> to hash.</param>
/// <param name="encoding">The <see cref="Encoding" /> used to read the string.</param>
/// <param name="byteFormat">The format string used to convert each byte into a string. Default is <c>x2</c>.</param>
/// <returns>The MD5 hash of input string.</returns>
public static string MD5(this string input, string byteFormat = "x2")
public static string MD5(this string input, Encoding encoding, string byteFormat = "x2")
{
#pragma warning disable CA5351 // Do Not Use Broken Cryptographic Algorithms
using var hasher = System.Security.Cryptography.MD5.Create();
#pragma warning restore CA5351 // Do Not Use Broken Cryptographic Algorithms

return Hash(input, hasher, byteFormat);
return Hash(input, encoding, hasher, byteFormat);
}

/// <summary>
/// Calculates an hashed representation of <paramref name="input"/> using MD5 and the <paramref name="byteFormat"/>. The string will be interpreted using <see cref="Encoding.UTF8" />.
/// </summary>
/// <param name="input">The <see cref="string"/> to hash.</param>
/// <param name="byteFormat">The format string used to convert each byte into a string. Default is <c>x2</c>.</param>
/// <returns>The MD5 hash of input string.</returns>
public static string MD5(this string input, string byteFormat = "x2") => MD5(input, Encoding.UTF8, byteFormat);
}
}
4 changes: 2 additions & 2 deletions tests/Tests.Clock/SystemClockTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class SystemClockTests
[Test, AutoData]
public void UtcNow_returns_current_time()
{
Assert.That(SystemClock.Instance.UtcNow, Is.EqualTo(DateTimeOffset.UtcNow).Within(TimeSpan.FromTicks(100)));
Assert.That(SystemClock.Instance.UtcNow, Is.EqualTo(DateTimeOffset.UtcNow).Within(TimeSpan.FromSeconds(1)));
}
}
}
}
46 changes: 41 additions & 5 deletions tests/Tests.StringExtensions/HashStringExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using NUnit.Framework;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;

namespace Tests
{
Expand All @@ -11,28 +12,63 @@ public class HashStringExtensionsTests
{
[Test]
[TestCaseSource(nameof(GetAlgorithms))]
public void Hash_returns_correct_hash(HashAlgorithm algorithm, string expected)
public void Hash_returns_correct_hash_with_specified_encoding(string input, HashAlgorithm algorithm, string expected)
{
var result = "Hello world".Hash(algorithm);
var result = input.Hash(Encoding.UTF8, algorithm);

Assert.That(result, Is.EqualTo(expected));
}

[Test]
[TestCaseSource(nameof(GetAlgorithms))]
public void Hash_returns_correct_hash_with_default_encoding(string input, HashAlgorithm algorithm, string expected)
{
var result = input.Hash(algorithm);

Assert.That(result, Is.EqualTo(expected));
}

public static IEnumerable<object[]> GetAlgorithms()
{
yield return new object[] { MD5.Create(), "3e25960a79dbc69b674cd4ec67a72c62" };
yield return new object[] { "Hello world", MD5.Create(), "3e25960a79dbc69b674cd4ec67a72c62" };

yield return new object[] { SHA1.Create(), "7b502c3a1f48c8609ae212cdfb639dee39673f5e" };
yield return new object[] { "Hello world", SHA1.Create(), "7b502c3a1f48c8609ae212cdfb639dee39673f5e" };
}

[Test]
public void MD5_returns_correct_hash()
public void MD5_returns_correct_hash_with_specified_encoding()
{
var result = "Hello world".MD5(Encoding.UTF8);

const string expected = "3e25960a79dbc69b674cd4ec67a72c62";

Assert.That(result, Is.EqualTo(expected));
}

[Test]
public void MD5_returns_correct_hash_with_default_encoding()
{
var result = "Hello world".MD5();

const string expected = "3e25960a79dbc69b674cd4ec67a72c62";

Assert.That(result, Is.EqualTo(expected));
}

[Test]
[TestCaseSource(nameof(GetEncodings))]
public void MD5_returns_correct_hash_with_specified_encoding(string input, Encoding encoding, string expected)
{
var result = input.MD5(encoding);

Assert.That(result, Is.EqualTo(expected));
}

public static IEnumerable<object[]> GetEncodings()
{
yield return new object[] { "string with swedish characters: ö ä å", Encoding.UTF8, "29f815f91399c52782a11e5206ae2b9f" };

yield return new object[] { "string with swedish characters: ö ä å", Encoding.ASCII, "b65d919f7a01ca0ca25b694c50a77c35" };
}
}
}

0 comments on commit 438d702

Please sign in to comment.