/*
* This file is part of Socialvoid.NET Project (https://github.com/Intellivoid/Socialvoid.NET).
* Copyright (c) 2021 Socialvoid.NET Authors.
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this source code of library.
* If not, see .
*/
/*
* Credits to Devin Martin and the original OtpSharp library:
* https://github.com/kspearrin/Otp.NET
*/
using System;
using System.Text;
using System.Security.Cryptography;
namespace Socialvoid.Security.Otp
{
///
/// Helpers to work with key generations.
/// since: v0.0.0
///
public static class KeyGeneration
{
//-------------------------------------------------
#region static Method's Region
///
/// Generates a random key in accordance with the RFC recommened
/// length for each algorithm.
/// since: v0.0.0
///
/// the key length
/// The generated key
public static byte[] GenerateRandomKey(int length)
{
byte[] key = new byte[length];
using(var rnd = RandomNumberGenerator.Create())
{
rnd.GetBytes(key);
return key;
}
}
///
/// Generates a random key in accordance with the RFC recommened
/// length for each algorithm.
/// since: v0.0.0
///
/// HashMode
/// Key
public static byte[] GenerateRandomKey(OtpHashMode mode = OtpHashMode.Sha1) =>
GenerateRandomKey(LengthForMode(mode));
///
/// Uses the procedure defined in RFC 4226 section 7.5 to derive a key
/// from the master key.
/// since: v0.0.0
///
///
/// The master key from which to derive a device specific key.
///
///
/// The public identifier that is unique to the authenticating device.
///
///
/// The hash mode to use. This will determine the resulting key lenght.
/// The default value is sha-1 (as per the RFC) which is 20 bytes
///
/// Derived key
public static byte[] DeriveKeyFromMaster(IKeyProvider masterKey,
byte[] publicIdentifier, OtpHashMode mode = OtpHashMode.Sha1)
{
if(masterKey == null)
{
throw new ArgumentNullException(nameof(masterKey),
"The master key cannot be null");
}
return masterKey.ComputeHmac(mode, publicIdentifier);
}
///
/// Uses the procedure defined in RFC 4226 section 7.5 to derive a key
/// from the master key.
///
/// The master key from which to derive a device specific key
/// A serial number that is unique to the authenticating device
/// The hash mode to use. This will determine the resulting key lenght. The default is sha-1 (as per the RFC) which is 20 bytes
/// Derived key
public static byte[] DeriveKeyFromMaster(IKeyProvider masterKey,
int serialNumber,
OtpHashMode mode = OtpHashMode.Sha1) =>
DeriveKeyFromMaster(masterKey,
KeyUtilities.GetBigEndianBytes(serialNumber), mode);
internal static HashAlgorithm GetHashAlgorithmForMode(OtpHashMode mode)
{
switch(mode)
{
case OtpHashMode.Sha256:
return SHA256.Create();
case OtpHashMode.Sha512:
return SHA512.Create();
default: //case OtpHashMode.Sha1:
return SHA1.Create();
}
}
internal static int LengthForMode(OtpHashMode mode)
{
switch(mode)
{
case OtpHashMode.Sha256:
return 32;
case OtpHashMode.Sha512:
return 64;
default: //case OtpHashMode.Sha1:
return 20;
}
}
internal static string GetSha1(string value)
{
var data = Encoding.ASCII.GetBytes(value);
var hashData = new SHA1Managed().ComputeHash(data);
var hash = string.Empty;
foreach (var b in hashData)
{
hash += b.ToString("X2");
}
return hash;
}
#endregion
//-------------------------------------------------
}
}