/* * 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; namespace Socialvoid.Security.Otp { /// /// Calculate HMAC-Based One-Time-Passwords (HOTP) from a secret key. /// since: v0.0.0 /// /// /// The specifications for the methods of this class can be found in RFC 4226: /// http://tools.ietf.org/html/rfc4226 /// public sealed class Hotp : Otp { //------------------------------------------------- #region field's Region /// /// The HOTP size. /// since: v0.0.0 /// private readonly int _hotpSize; #endregion //------------------------------------------------- #region Constructor's Region /// /// Creates an HOTP instance. /// since: v0.0.0 /// /// /// The secret key to use in HOTP calculations. /// /// /// The hash mode to use. /// /// The number of digits that the returning HOTP should have. The default is 6. public Hotp(byte[] secretKey, OtpHashMode mode = OtpHashMode.Sha1, int hotpSize = 6) : base(secretKey, mode) { if (hotpSize < 6 || hotpSize > 8) { throw new ArgumentOutOfRangeException(nameof(hotpSize), "The hotpSize must be between 6 and 8"); } _hotpSize = hotpSize; } /// /// Create a HOTP instance. /// since: v0.0.0 /// /// /// The key to use in HOTP calculations. /// /// /// The hash mode to use. /// /// /// The number of digits that the returning HOTP should have. /// The default value is 6. /// public Hotp(IKeyProvider key, OtpHashMode mode = OtpHashMode.Sha1, int hotpSize = 6) : base(key, mode) { if (hotpSize < 6 || hotpSize > 8) { throw new ArgumentOutOfRangeException(nameof(hotpSize), "The hotpSize must be between 6 and 8"); } _hotpSize = hotpSize; } #endregion //------------------------------------------------- #region overrided Method's Region /// /// Takes a time step and computes a HOTP code. /// since: v0.0.0 /// /// /// the counter. This is the number of time steps that have passed. /// /// /// The hash mode to use. /// /// /// HOTP calculated code. /// protected override string Compute(long counter, OtpHashMode mode) { var data = KeyUtilities.GetBigEndianBytes(counter); var otp = this.CalculateOtp(data, mode); return Digits(otp, _hotpSize); } #endregion //------------------------------------------------- #region Get Method's Region /// /// Takes a counter and then computes a HOTP value. /// since: v0.0.0 /// /// /// The timestamp to use for the HOTP calculation. /// /// a HOTP value public string ComputeHOTP(long counter) { return this.Compute(counter, _hashMode); } /// /// Verify a value that has been provided with the calculated value. /// since: v0.0.0 /// /// the trial HOTP value. /// /// /// The counter value to verify /// /// /// true if there is a match; otherwise false. /// public bool VerifyHotp(string hotp, long counter) => hotp == ComputeHOTP(counter); #endregion //------------------------------------------------- } }