144 lines
4.5 KiB
C#
144 lines
4.5 KiB
C#
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
* 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
|
|
{
|
|
/// <summary>
|
|
/// Helpers to work with key generations.
|
|
/// <code> since: v0.0.0 </code>
|
|
/// </summary>
|
|
public static class KeyGeneration
|
|
{
|
|
//-------------------------------------------------
|
|
#region static Method's Region
|
|
/// <summary>
|
|
/// Generates a random key in accordance with the RFC recommened
|
|
/// length for each algorithm.
|
|
/// <code> since: v0.0.0 </code>
|
|
/// </summary>
|
|
/// <param name="length">the key length</param>
|
|
/// <returns>The generated key</returns>
|
|
public static byte[] GenerateRandomKey(int length)
|
|
{
|
|
byte[] key = new byte[length];
|
|
using(var rnd = RandomNumberGenerator.Create())
|
|
{
|
|
rnd.GetBytes(key);
|
|
return key;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Generates a random key in accordance with the RFC recommened
|
|
/// length for each algorithm.
|
|
/// <code> since: v0.0.0 </code>
|
|
/// </summary>
|
|
/// <param name="mode">HashMode</param>
|
|
/// <returns>Key</returns>
|
|
public static byte[] GenerateRandomKey(OtpHashMode mode = OtpHashMode.Sha1) =>
|
|
GenerateRandomKey(LengthForMode(mode));
|
|
/// <summary>
|
|
/// Uses the procedure defined in RFC 4226 section 7.5 to derive a key
|
|
/// from the master key.
|
|
/// <code> since: v0.0.0 </code>
|
|
/// </summary>
|
|
/// <param name="masterKey">
|
|
/// The master key from which to derive a device specific key.
|
|
/// </param>
|
|
/// <param name="publicIdentifier">
|
|
/// The public identifier that is unique to the authenticating device.
|
|
/// </param>
|
|
/// <param name="mode">
|
|
/// 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
|
|
/// </param>
|
|
/// <returns>Derived key</returns>
|
|
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);
|
|
}
|
|
/// <summary>
|
|
/// Uses the procedure defined in RFC 4226 section 7.5 to derive a key
|
|
/// from the master key.
|
|
/// </summary>
|
|
/// <param name="masterKey">The master key from which to derive a device specific key</param>
|
|
/// <param name="serialNumber">A serial number that is unique to the authenticating device</param>
|
|
/// <param name="mode">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</param>
|
|
/// <returns>Derived key</returns>
|
|
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
|
|
//-------------------------------------------------
|
|
}
|
|
}
|