diff --git a/Fire.Authentication.Private/Base32Encoding.cs b/Fire.Authentication.Private/Base32Encoding.cs index d6d82858..00ab5ca3 100644 --- a/Fire.Authentication.Private/Base32Encoding.cs +++ b/Fire.Authentication.Private/Base32Encoding.cs @@ -91,34 +91,20 @@ private static int CharToValue(char c) { int value = c; - if ((value >= 'A' && value <= 'Z')) + if (value is >= 'A' and <= 'Z') { return value - 'A'; } - if ((value >= '2' && value <= '7')) - { - return value - ('2' - 26); - } - if ((value >= 'a' && value <= 'z')) - { - return value - 'a'; - } - - throw new ArgumentException("Character is not a Base32 character.", nameof(c)); + return value is >= '2' and <= '7' + ? value - ('2' - 26) + : value is >= 'a' and <= 'z' ? value - 'a' : throw new ArgumentException("Character is not a Base32 character.", nameof(c)); } private static char ValueToChar(byte b) { - if (b < 26) - { - return (char)(b + 'A'); - } - if (b < 32) - { - return (char)(b + ('2' - 26)); - } - - throw new ArgumentException("Byte is not a Base32 value.", nameof(b)); + return b < 26 + ? (char)(b + 'A') + : b < 32 ? (char)(b + ('2' - 26)) : throw new ArgumentException("Byte is not a Base32 value.", nameof(b)); } } } \ No newline at end of file diff --git a/Fire.Authentication.Private/Hotp.cs b/Fire.Authentication.Private/Hotp.cs index 13a564f0..acc53498 100644 --- a/Fire.Authentication.Private/Hotp.cs +++ b/Fire.Authentication.Private/Hotp.cs @@ -3,39 +3,43 @@ namespace Fire.Authentication.Private; public class Hotp : Otp { - private readonly int _hotpSize; - - public int HotpSize => _hotpSize; + public int HotpSize { get; } public Hotp(byte[] secretKey, OtpHashMode mode = OtpHashMode.Sha1, int hotpSize = 6) : base(secretKey, mode) { VerifyParameters(hotpSize); - _hotpSize = hotpSize; + HotpSize = hotpSize; } public Hotp(IKeyProvider key, OtpHashMode mode = OtpHashMode.Sha1, int hotpSize = 6) : base(key, mode) { VerifyParameters(hotpSize); - _hotpSize = hotpSize; + HotpSize = hotpSize; } private static void VerifyParameters(int hotpSize) { - if (hotpSize < 6 || hotpSize > 8) + if (hotpSize is < 6 or > 8) { throw new ArgumentOutOfRangeException(nameof(hotpSize)); } } - public string ComputeHOTP(long counter) => Compute(counter, _hashMode); + public string ComputeHOTP(long counter) + { + return Compute(counter, _hashMode); + } - public bool VerifyHotp(string hotp, long counter) => hotp == ComputeHOTP(counter); + public bool VerifyHotp(string hotp, long counter) + { + return hotp == ComputeHOTP(counter); + } protected override string Compute(long counter, OtpHashMode mode) { - var otp = CalculateOtp(KeyUtilities.GetBigEndianBytes(counter), mode); - return Digits(otp, _hotpSize); + long otp = CalculateOtp(KeyUtilities.GetBigEndianBytes(counter), mode); + return Digits(otp, HotpSize); } } \ No newline at end of file diff --git a/Fire.Authentication.Private/InMemoryKey.cs b/Fire.Authentication.Private/InMemoryKey.cs index 53b24598..eee36e72 100644 --- a/Fire.Authentication.Private/InMemoryKey.cs +++ b/Fire.Authentication.Private/InMemoryKey.cs @@ -16,12 +16,15 @@ public InMemoryKey(byte[] key) } } - internal byte[] GetCopyOfKey() => (byte[])_keyData.Clone(); + internal byte[] GetCopyOfKey() + { + return (byte[])_keyData.Clone(); + } public byte[] ComputeHmac(OtpHashMode mode, byte[] data) { - using var hmac = CreateHmacHash(mode); - var key = GetCopyOfKey(); + using HMAC hmac = CreateHmacHash(mode); + byte[] key = GetCopyOfKey(); try { hmac.Key = key; @@ -33,11 +36,13 @@ public byte[] ComputeHmac(OtpHashMode mode, byte[] data) } } - private static HMAC CreateHmacHash(OtpHashMode otpHashMode) => - otpHashMode switch + private static HMAC CreateHmacHash(OtpHashMode otpHashMode) + { + return otpHashMode switch { OtpHashMode.Sha256 => new HMACSHA256(), OtpHashMode.Sha512 => new HMACSHA512(), _ => new HMACSHA1() // OtpHashMode.Sha1 or default }; + } } \ No newline at end of file diff --git a/Fire.Authentication.Private/KeyGeneration.cs b/Fire.Authentication.Private/KeyGeneration.cs index 7142377f..e2d57b63 100644 --- a/Fire.Authentication.Private/KeyGeneration.cs +++ b/Fire.Authentication.Private/KeyGeneration.cs @@ -8,7 +8,7 @@ public static class KeyGeneration public static byte[] GenerateRandomKey(int length) { byte[] key = new byte[length]; - using var rnd = RandomNumberGenerator.Create(); + using RandomNumberGenerator rnd = RandomNumberGenerator.Create(); rnd.GetBytes(key); return key; } @@ -20,15 +20,13 @@ public static byte[] GenerateRandomKey(OtpHashMode mode = OtpHashMode.Sha1) public static byte[] DeriveKeyFromMaster(IKeyProvider masterKey, byte[] identifier, OtpHashMode mode = OtpHashMode.Sha1) { - if (masterKey == null) - { - throw new ArgumentNullException(nameof(masterKey)); - } - return masterKey.ComputeHmac(mode, identifier); + return masterKey == null ? throw new ArgumentNullException(nameof(masterKey)) : masterKey.ComputeHmac(mode, identifier); } - public static byte[] DeriveKeyFromMaster(IKeyProvider masterKey, int serialNumber, OtpHashMode mode = OtpHashMode.Sha1) => - DeriveKeyFromMaster(masterKey, KeyUtilities.GetBigEndianBytes(serialNumber), mode); + public static byte[] DeriveKeyFromMaster(IKeyProvider masterKey, int serialNumber, OtpHashMode mode = OtpHashMode.Sha1) + { + return DeriveKeyFromMaster(masterKey, KeyUtilities.GetBigEndianBytes(serialNumber), mode); + } private static int LengthForMode(OtpHashMode mode) { diff --git a/Fire.Authentication.Private/KeyUtilities.cs b/Fire.Authentication.Private/KeyUtilities.cs index b7eee87c..805be6f2 100644 --- a/Fire.Authentication.Private/KeyUtilities.cs +++ b/Fire.Authentication.Private/KeyUtilities.cs @@ -11,13 +11,13 @@ internal static void Destroy(byte[] sensitiveData) throw new ArgumentNullException(nameof(sensitiveData)); } - var rng = new Random(); + Random rng = new(); rng.NextBytes(sensitiveData); } internal static byte[] GetBigEndianBytes(long input) { - var data = BitConverter.GetBytes(input); + byte[] data = BitConverter.GetBytes(input); if (BitConverter.IsLittleEndian) { Array.Reverse(data); @@ -27,7 +27,7 @@ internal static byte[] GetBigEndianBytes(long input) internal static byte[] GetBigEndianBytes(int input) { - var data = BitConverter.GetBytes(input); + byte[] data = BitConverter.GetBytes(input); if (BitConverter.IsLittleEndian) { Array.Reverse(data); diff --git a/Fire.Authentication.Private/Otp.cs b/Fire.Authentication.Private/Otp.cs index f6fb5f9f..d829bb35 100644 --- a/Fire.Authentication.Private/Otp.cs +++ b/Fire.Authentication.Private/Otp.cs @@ -25,25 +25,27 @@ public Otp(IKeyProvider key, OtpHashMode mode) protected internal long CalculateOtp(byte[] data, OtpHashMode mode) { - var hmacComputedHash = _secretKey.ComputeHmac(mode, data); + byte[] hmacComputedHash = _secretKey.ComputeHmac(mode, data); - int offset = hmacComputedHash[hmacComputedHash.Length - 1] & 0x0F; - return (hmacComputedHash[offset] & 0x7f) << 24 - | (hmacComputedHash[offset + 1] & 0xff) << 16 - | (hmacComputedHash[offset + 2] & 0xff) << 8 - | (hmacComputedHash[offset + 3] & 0xff) % 1000000; + int offset = hmacComputedHash[^1] & 0x0F; + return ((hmacComputedHash[offset] & 0x7f) << 24) + | ((hmacComputedHash[offset + 1] & 0xff) << 16) + | ((hmacComputedHash[offset + 2] & 0xff) << 8) + | ((hmacComputedHash[offset + 3] & 0xff) % 1000000); } - protected internal static string Digits(long input, int digitCount) => - (input % (long)Math.Pow(10, digitCount)).ToString().PadLeft(digitCount, '0'); + protected internal static string Digits(long input, int digitCount) + { + return (input % (long)Math.Pow(10, digitCount)).ToString().PadLeft(digitCount, '0'); + } protected bool Verify(long initialStep, string valueToVerify, out long matchedStep, VerificationWindow window) { window ??= new VerificationWindow(); - foreach (var frame in window.ValidationCandidates(initialStep)) + foreach (long frame in window.ValidationCandidates(initialStep)) { - var comparisonValue = Compute(frame, _hashMode); + string comparisonValue = Compute(frame, _hashMode); if (ValuesEqual(comparisonValue, valueToVerify)) { matchedStep = frame; @@ -58,11 +60,15 @@ protected bool Verify(long initialStep, string valueToVerify, out long matchedSt private bool ValuesEqual(string a, string b) { if (a.Length != b.Length) + { return false; + } - var result = 0; - for (var i = 0; i < a.Length; i++) + int result = 0; + for (int i = 0; i < a.Length; i++) + { result |= a[i] ^ b[i]; + } return result == 0; } diff --git a/Fire.Authentication.Private/OtpUri.cs b/Fire.Authentication.Private/OtpUri.cs index 106cf94e..26cc2215 100644 --- a/Fire.Authentication.Private/OtpUri.cs +++ b/Fire.Authentication.Private/OtpUri.cs @@ -28,7 +28,9 @@ public OtpUri( _ = secret ?? throw new ArgumentNullException(nameof(secret)); _ = user ?? throw new ArgumentNullException(nameof(user)); if (digits < 0) + { throw new ArgumentOutOfRangeException(nameof(digits)); + } Type = schema; Secret = secret; @@ -60,17 +62,22 @@ public OtpUri( : this(schema, Base32Encoding.ToString(secret), user, issuer, algorithm, digits, period, counter) { } - public Uri ToUri() => new Uri(ToString()); + public Uri ToUri() + { + return new Uri(ToString()); + } public override string ToString() { - var parameters = new Dictionary + Dictionary parameters = new() { { "secret", Secret.TrimEnd('=') } }; if (!string.IsNullOrWhiteSpace(Issuer)) + { parameters.Add("issuer", Uri.EscapeDataString(Issuer)); + } parameters.Add("algorithm", Algorithm.ToString().ToUpper()); parameters.Add("digits", Digits.ToString()); @@ -85,28 +92,28 @@ public override string ToString() break; } - var uriBuilder = new StringBuilder("otpauth://"); - uriBuilder.Append(Type.ToString().ToLowerInvariant()); + StringBuilder uriBuilder = new("otpauth://"); + _ = uriBuilder.Append(Type.ToString().ToLowerInvariant()); if (!string.IsNullOrWhiteSpace(Issuer)) { - uriBuilder.Append("/"); - uriBuilder.Append(Uri.EscapeDataString(Issuer)); + _ = uriBuilder.Append("/"); + _ = uriBuilder.Append(Uri.EscapeDataString(Issuer)); } - uriBuilder.Append(":"); - uriBuilder.Append(Uri.EscapeDataString(User)); - uriBuilder.Append("?"); + _ = uriBuilder.Append(":"); + _ = uriBuilder.Append(Uri.EscapeDataString(User)); + _ = uriBuilder.Append("?"); - foreach (var pair in parameters) + foreach (KeyValuePair pair in parameters) { - uriBuilder.Append(pair.Key); - uriBuilder.Append("="); - uriBuilder.Append(pair.Value); - uriBuilder.Append("&"); + _ = uriBuilder.Append(pair.Key); + _ = uriBuilder.Append("="); + _ = uriBuilder.Append(pair.Value); + _ = uriBuilder.Append("&"); } - uriBuilder.Remove(uriBuilder.Length - 1, 1); + _ = uriBuilder.Remove(uriBuilder.Length - 1, 1); return uriBuilder.ToString(); } } \ No newline at end of file diff --git a/Fire.Authentication.Private/TimeCorrection.cs b/Fire.Authentication.Private/TimeCorrection.cs index e9015a16..c48c6232 100644 --- a/Fire.Authentication.Private/TimeCorrection.cs +++ b/Fire.Authentication.Private/TimeCorrection.cs @@ -4,15 +4,27 @@ namespace Fire.Authentication.Private; public class TimeCorrection { - public static readonly TimeCorrection UncorrectedInstance = new TimeCorrection(); - - private TimeCorrection() => CorrectionFactor = TimeSpan.FromSeconds(0); - - public TimeCorrection(DateTime correctUtc) => CorrectionFactor = DateTime.UtcNow - correctUtc; - - public TimeCorrection(DateTime correctTime, DateTime referenceTime) => CorrectionFactor = referenceTime - correctTime; - - public DateTime GetCorrectedTime(DateTime referenceTime) => referenceTime - CorrectionFactor; + public static readonly TimeCorrection UncorrectedInstance = new(); + + private TimeCorrection() + { + CorrectionFactor = TimeSpan.FromSeconds(0); + } + + public TimeCorrection(DateTime correctUtc) + { + CorrectionFactor = DateTime.UtcNow - correctUtc; + } + + public TimeCorrection(DateTime correctTime, DateTime referenceTime) + { + CorrectionFactor = referenceTime - correctTime; + } + + public DateTime GetCorrectedTime(DateTime referenceTime) + { + return referenceTime - CorrectionFactor; + } public DateTime CorrectedUtcNow => GetCorrectedTime(DateTime.UtcNow); diff --git a/Fire.Authentication.Private/Totp.cs b/Fire.Authentication.Private/Totp.cs index 6da91093..0a9895cc 100644 --- a/Fire.Authentication.Private/Totp.cs +++ b/Fire.Authentication.Private/Totp.cs @@ -7,72 +7,103 @@ public class Totp : Otp private const long UnicEpocTicks = 621355968000000000L; private const long TicksToSeconds = 10000000L; - private readonly int _step; - private readonly int _totpSize; - private readonly TimeCorrection _correctedTime; - - public int Step => _step; - public int TotpSize => _totpSize; - public TimeCorrection TimeCorrection => _correctedTime; + public int Step { get; } + public int TotpSize { get; } + public TimeCorrection TimeCorrection { get; } public Totp(byte[] secretKey, int step = 30, OtpHashMode mode = OtpHashMode.Sha1, int totpSize = 6, TimeCorrection timeCorrection = null) : base(secretKey, mode) { VerifyParameters(step, totpSize); - _step = step; - _totpSize = totpSize; - _correctedTime = timeCorrection ?? TimeCorrection.UncorrectedInstance; + Step = step; + TotpSize = totpSize; + TimeCorrection = timeCorrection ?? TimeCorrection.UncorrectedInstance; } public Totp(IKeyProvider key, int step = 30, OtpHashMode mode = OtpHashMode.Sha1, int totpSize = 6, TimeCorrection timeCorrection = null) : base(key, mode) { VerifyParameters(step, totpSize); - _step = step; - _totpSize = totpSize; - _correctedTime = timeCorrection ?? TimeCorrection.UncorrectedInstance; + Step = step; + TotpSize = totpSize; + TimeCorrection = timeCorrection ?? TimeCorrection.UncorrectedInstance; } private static void VerifyParameters(int step, int totpSize) { if (step <= 0 || totpSize <= 0 || totpSize > 10) + { throw new ArgumentOutOfRangeException(step <= 0 ? nameof(step) : nameof(totpSize)); + } } - public string ComputeTotp(DateTime timestamp) => - ComputeTotpFromSpecificTime(_correctedTime.GetCorrectedTime(timestamp)); + public string ComputeTotp(DateTime timestamp) + { + return ComputeTotpFromSpecificTime(TimeCorrection.GetCorrectedTime(timestamp)); + } - public string ComputeTotp() => ComputeTotpFromSpecificTime(_correctedTime.CorrectedUtcNow); + public string ComputeTotp() + { + return ComputeTotpFromSpecificTime(TimeCorrection.CorrectedUtcNow); + } - private string ComputeTotpFromSpecificTime(DateTime timestamp) => - Compute(CalculateTimeStepFromTimestamp(timestamp), _hashMode); + private string ComputeTotpFromSpecificTime(DateTime timestamp) + { + return Compute(CalculateTimeStepFromTimestamp(timestamp), _hashMode); + } - public bool VerifyTotp(string totp, out long timeStepMatched, VerificationWindow window = null) => - VerifyTotpForSpecificTime(_correctedTime.CorrectedUtcNow, totp, window, out timeStepMatched); + public bool VerifyTotp(string totp, out long timeStepMatched, VerificationWindow window = null) + { + return VerifyTotpForSpecificTime(TimeCorrection.CorrectedUtcNow, totp, window, out timeStepMatched); + } - public bool VerifyTotp(DateTime timestamp, string totp, out long timeStepMatched, VerificationWindow window = null) => - VerifyTotpForSpecificTime(_correctedTime.GetCorrectedTime(timestamp), totp, window, out timeStepMatched); + public bool VerifyTotp(DateTime timestamp, string totp, out long timeStepMatched, VerificationWindow window = null) + { + return VerifyTotpForSpecificTime(TimeCorrection.GetCorrectedTime(timestamp), totp, window, out timeStepMatched); + } - private bool VerifyTotpForSpecificTime(DateTime timestamp, string totp, VerificationWindow window, out long timeStepMatched) => - Verify(CalculateTimeStepFromTimestamp(timestamp), totp, out timeStepMatched, window); + private bool VerifyTotpForSpecificTime(DateTime timestamp, string totp, VerificationWindow window, out long timeStepMatched) + { + return Verify(CalculateTimeStepFromTimestamp(timestamp), totp, out timeStepMatched, window); + } - private long CalculateTimeStepFromTimestamp(DateTime timestamp) => - (timestamp.Ticks - UnicEpocTicks) / TicksToSeconds / _step; + private long CalculateTimeStepFromTimestamp(DateTime timestamp) + { + return (timestamp.Ticks - UnicEpocTicks) / TicksToSeconds / Step; + } - public int RemainingSeconds() => RemainingSecondsForSpecificTime(_correctedTime.CorrectedUtcNow); + public int RemainingSeconds() + { + return RemainingSecondsForSpecificTime(TimeCorrection.CorrectedUtcNow); + } - public int RemainingSeconds(DateTime timestamp) => RemainingSecondsForSpecificTime(_correctedTime.GetCorrectedTime(timestamp)); + public int RemainingSeconds(DateTime timestamp) + { + return RemainingSecondsForSpecificTime(TimeCorrection.GetCorrectedTime(timestamp)); + } - private int RemainingSecondsForSpecificTime(DateTime timestamp) => - _step - (int)(((timestamp.Ticks - UnicEpocTicks) / TicksToSeconds) % _step); + private int RemainingSecondsForSpecificTime(DateTime timestamp) + { + return Step - (int)((timestamp.Ticks - UnicEpocTicks) / TicksToSeconds % Step); + } - public DateTime WindowStart() => WindowStartForSpecificTime(_correctedTime.CorrectedUtcNow); + public DateTime WindowStart() + { + return WindowStartForSpecificTime(TimeCorrection.CorrectedUtcNow); + } - public DateTime WindowStart(DateTime timestamp) => WindowStartForSpecificTime(_correctedTime.GetCorrectedTime(timestamp)); + public DateTime WindowStart(DateTime timestamp) + { + return WindowStartForSpecificTime(TimeCorrection.GetCorrectedTime(timestamp)); + } - private DateTime WindowStartForSpecificTime(DateTime timestamp) => - timestamp.AddTicks(-(timestamp.Ticks - UnicEpocTicks) % (TicksToSeconds * _step)); + private DateTime WindowStartForSpecificTime(DateTime timestamp) + { + return timestamp.AddTicks(-(timestamp.Ticks - UnicEpocTicks) % (TicksToSeconds * Step)); + } - protected override string Compute(long counter, OtpHashMode mode) => - Digits(CalculateOtp(KeyUtilities.GetBigEndianBytes(counter), mode), _totpSize); + protected override string Compute(long counter, OtpHashMode mode) + { + return Digits(CalculateOtp(KeyUtilities.GetBigEndianBytes(counter), mode), TotpSize); + } } \ No newline at end of file diff --git a/Fire.Authentication.Private/VerificationWindow.cs b/Fire.Authentication.Private/VerificationWindow.cs index 64870e33..c7f189ab 100644 --- a/Fire.Authentication.Private/VerificationWindow.cs +++ b/Fire.Authentication.Private/VerificationWindow.cs @@ -2,7 +2,6 @@ namespace Fire.Authentication.Private; -#pragma warning disable CS8618 public class VerificationWindow { private readonly int _previous; @@ -21,9 +20,9 @@ public VerificationWindow(int previous = 0, int future = 0) public IEnumerable ValidationCandidates(long initialFrame) { yield return initialFrame; - for (var i = 1; i <= _previous; i++) + for (int i = 1; i <= _previous; i++) { - var val = initialFrame - i; + long val = initialFrame - i; if (val < 0) { break; @@ -31,7 +30,7 @@ public IEnumerable ValidationCandidates(long initialFrame) yield return val; } - for (var i = 1; i <= _future; i++) + for (int i = 1; i <= _future; i++) { yield return initialFrame + i; } @@ -41,5 +40,5 @@ public IEnumerable ValidationCandidates(long initialFrame) /// The verification window that accommodates network delay that is recommended in the RFC /// public static readonly VerificationWindow RfcSpecifiedNetworkDelay = - new VerificationWindow(previous: 1, future: 1); + new(previous: 1, future: 1); } \ No newline at end of file