Files
git.stella-ops.org/src/__Libraries/StellaOps.Auth.Security/Dpop/DpopNonceUtilities.cs

72 lines
2.4 KiB
C#

using System;
using System.Security.Cryptography;
using System.Text;
using static StellaOps.Localization.T;
namespace StellaOps.Auth.Security.Dpop;
internal static class DpopNonceUtilities
{
private static readonly char[] _base64Padding = { '=' };
internal static string GenerateNonce()
{
Span<byte> buffer = stackalloc byte[32];
RandomNumberGenerator.Fill(buffer);
return Convert.ToBase64String(buffer)
.TrimEnd(_base64Padding)
.Replace('+', '-')
.Replace('/', '_');
}
internal static byte[] ComputeNonceHash(string nonce)
{
ArgumentException.ThrowIfNullOrWhiteSpace(nonce);
var bytes = Encoding.UTF8.GetBytes(nonce);
return SHA256.HashData(bytes);
}
internal static string EncodeHash(ReadOnlySpan<byte> hash)
=> Convert.ToHexString(hash);
internal static string ComputeStorageKey(string audience, string clientId, string keyThumbprint)
{
ArgumentException.ThrowIfNullOrWhiteSpace(audience);
ArgumentException.ThrowIfNullOrWhiteSpace(clientId);
ArgumentException.ThrowIfNullOrWhiteSpace(keyThumbprint);
var normalizedAudience = audience.Trim().ToLowerInvariant();
var normalizedClientId = clientId.Trim().ToLowerInvariant();
var normalizedThumbprint = keyThumbprint.Trim().ToLowerInvariant();
return string.Create(
"dpop-nonce:".Length + normalizedAudience.Length + normalizedClientId.Length + normalizedThumbprint.Length + 2,
(normalizedAudience, normalizedClientId, normalizedThumbprint),
static (span, parts) =>
{
var index = 0;
const string Prefix = "dpop-nonce:";
Prefix.CopyTo(span);
index += Prefix.Length;
index = Append(span, index, parts.Item1);
span[index++] = ':';
index = Append(span, index, parts.Item2);
span[index++] = ':';
_ = Append(span, index, parts.Item3);
});
static int Append(Span<char> span, int index, string value)
{
if (value.Length == 0)
{
throw new ArgumentException(_t("common.validation.empty_after_trim", "Value"));
}
value.AsSpan().CopyTo(span[index..]);
return index + value.Length;
}
}
}