Initial commit: scadaproj umbrella — sister-project index, auth component normalization (design + GAPS), and the built ZB.MOM.WW.Auth shared library (0.1.0, flattened in).
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
using ZB.MOM.WW.Auth.ApiKeys;
|
||||
|
||||
namespace ZB.MOM.WW.Auth.ApiKeys.Tests;
|
||||
|
||||
public class ApiKeySecretHasherTests
|
||||
{
|
||||
private const string Secret = "mysecret";
|
||||
private const string Pepper = "mypepper";
|
||||
|
||||
// --- Hash determinism ---
|
||||
|
||||
[Fact]
|
||||
public void Hash_SameInputs_ProducesIdenticalHashes()
|
||||
{
|
||||
byte[] first = ApiKeySecretHasher.Hash(Secret, Pepper);
|
||||
byte[] second = ApiKeySecretHasher.Hash(Secret, Pepper);
|
||||
|
||||
Assert.Equal(first, second);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Hash_DifferentPepper_ProducesDifferentHash()
|
||||
{
|
||||
byte[] withPepper1 = ApiKeySecretHasher.Hash(Secret, "pepper1");
|
||||
byte[] withPepper2 = ApiKeySecretHasher.Hash(Secret, "pepper2");
|
||||
|
||||
Assert.NotEqual(withPepper1, withPepper2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Hash_DifferentSecret_ProducesDifferentHash()
|
||||
{
|
||||
byte[] hash1 = ApiKeySecretHasher.Hash("secret1", Pepper);
|
||||
byte[] hash2 = ApiKeySecretHasher.Hash("secret2", Pepper);
|
||||
|
||||
Assert.NotEqual(hash1, hash2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Hash_ReturnsThirtyTwoBytes()
|
||||
{
|
||||
// HMAC-SHA256 output is 256 bits = 32 bytes
|
||||
byte[] hash = ApiKeySecretHasher.Hash(Secret, Pepper);
|
||||
|
||||
Assert.Equal(32, hash.Length);
|
||||
}
|
||||
|
||||
// --- Verify happy path ---
|
||||
|
||||
[Fact]
|
||||
public void Verify_CorrectSecretAndPepper_ReturnsTrue()
|
||||
{
|
||||
byte[] hash = ApiKeySecretHasher.Hash(Secret, Pepper);
|
||||
|
||||
Assert.True(ApiKeySecretHasher.Verify(Secret, Pepper, hash));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Verify_WrongSecret_ReturnsFalse()
|
||||
{
|
||||
byte[] hash = ApiKeySecretHasher.Hash(Secret, Pepper);
|
||||
|
||||
Assert.False(ApiKeySecretHasher.Verify("wrongsecret", Pepper, hash));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Verify_WrongPepper_ReturnsFalse()
|
||||
{
|
||||
byte[] hash = ApiKeySecretHasher.Hash(Secret, Pepper);
|
||||
|
||||
Assert.False(ApiKeySecretHasher.Verify(Secret, "wrongpepper", hash));
|
||||
}
|
||||
|
||||
// --- Constant-time: length mismatch must not throw ---
|
||||
|
||||
[Fact]
|
||||
public void Verify_HashOfDifferentLength_ReturnsFalseWithoutThrowing()
|
||||
{
|
||||
// A hash of a completely different length — FixedTimeEquals must handle it
|
||||
// without throwing and return false.
|
||||
byte[] shortHash = [1, 2, 3];
|
||||
|
||||
var exception = Record.Exception(() => ApiKeySecretHasher.Verify(Secret, Pepper, shortHash));
|
||||
|
||||
Assert.Null(exception);
|
||||
Assert.False(ApiKeySecretHasher.Verify(Secret, Pepper, shortHash));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Verify_EmptyHash_ReturnsFalseWithoutThrowing()
|
||||
{
|
||||
byte[] emptyHash = [];
|
||||
|
||||
var exception = Record.Exception(() => ApiKeySecretHasher.Verify(Secret, Pepper, emptyHash));
|
||||
|
||||
Assert.Null(exception);
|
||||
Assert.False(ApiKeySecretHasher.Verify(Secret, Pepper, emptyHash));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user