using System.Security.Cryptography;
using System.Text;
namespace MijnBesluit.Application.Security;
///
/// Genereert uitnodigings- en sessietokens. Alleen de hash gaat de database in;
/// het token zelf bestaat maar één keer, in de e-mail of bij de client.
///
public static class TokenGenerator
{
/// Nieuw token als URL-veilige base64-tekst.
public static string Create(int byteLength = 32) =>
Convert.ToBase64String(RandomNumberGenerator.GetBytes(byteLength))
.Replace('+', '-').Replace('/', '_').TrimEnd('=');
/// SHA-256 van het token, zoals het in de database wordt bewaard.
public static byte[] HashToken(string token) =>
SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(token));
/// Vergelijking in constante tijd van een aangeboden token met een opgeslagen hash.
public static bool Matches(string token, byte[] storedHash) =>
storedHash.Length == 32 && CryptographicOperations.FixedTimeEquals(HashToken(token), storedHash);
///
/// Leidt uit het token zelf een 256-bit sleutel af, los van .
///
/// Dat "los van" is de reden dat dit een aparte methode is en geen hergebruik van de hash:
/// die hash staat in de database om het token te herkennen. Was de afgeleide sleutel
/// daaraan gelijk, dan lag de sleutel waarmee een bericht is versleuteld gewoon naast de
/// hash in diezelfde database - dat maakt de versleuteling zinloos.
/// zorgt er bovendien voor dat twee sleutels voor hetzelfde token, voor iets anders
/// gebruikt, elkaar niet gelijk zijn.
///
public static byte[] DeriveKey(string token, string doel) =>
HMACSHA256.HashData(Encoding.UTF8.GetBytes(token), Encoding.UTF8.GetBytes(doel));
}