/// <summary> /// Takes a secret key, a time step and a hash mode to compute a TOTP code /// </summary> /// <param name="secretKey">The secret key</param> /// <param name="timeStep">The time step</param> /// <param name="hashMmode">The hash mode to use</param> /// <returns>TOTP calculated code</returns> private string Compute(byte[] secretKey, long timeStep, OtpHashModeEnum hashMmode) { var bigEndianTimeStep = Utils.Utils.GetBigEndianBytes(timeStep); var otp = this.CalculateOtp(secretKey, bigEndianTimeStep, hashMmode); return(Utils.Utils.Digits(otp, this.totpSize)); }
/// <summary> /// Takes a secretKey and a timestamp and then computes a TOTP(Time based one time password) value /// </summary> /// <param name="secretKey">The secretKey to use for the TOTP calculation</param> /// <param name="timestamp">The timestamp to use for the TOTP calculation</param> /// <param name="hashMode">The hash mode to use for the TOTP calculation</param> /// <returns>a TOTP value</returns> public string ComputeTotp(byte[] secretKey, DateTime timestamp, OtpHashModeEnum hashMode = OtpHashModeEnum.Sha1) { DateTime univDateTime = timestamp.ToUniversalTime(); var timeStep = CalculateTimeStepFromTimestamp(univDateTime); return(this.Compute(secretKey, timeStep, hashMode)); }
/// <summary> /// Uses the key to get an HMAC using the specified algorithm and time step /// </summary> /// <param name="secretKey">The secret key used to compute the HMAC</param> /// <param name="timeStep">The time step used to compute the HMAC</param> /// <param name="hashMode">The HMAC algorithm to use</param> public static byte[] ComputeHmac(byte[] secretKey, byte[] timeStep, OtpHashModeEnum hashMode) { byte[] hashedValue = null; using (HMAC hmac = CreateHmacHash(hashMode)) { hmac.Key = secretKey; hashedValue = hmac.ComputeHash(timeStep); } return(hashedValue); }
/// <summary> /// Helper method that calculates OTPs /// </summary> /// <param name="secretKey">The secret key</param> /// <param name="data">The secret key</param> private long CalculateOtp(byte[] secretKey, byte[] timeStep, OtpHashModeEnum mode) { byte[] hmacComputedHash = Utils.Utils.ComputeHmac(secretKey, timeStep, mode); 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); }
public void ComputeTOTPTest(string secret, OtpHashModeEnum hashMode, long timestamp, string expectedOtp) { //Arrange var timeBasedOtpService = this.ServiceProvider.GetService <ITimeBasedOtp>(); DateTime time = DateTimeOffset.FromUnixTimeSeconds(timestamp).DateTime; //Act var otp = timeBasedOtpService.ComputeTotp(Encoding.UTF8.GetBytes(secret), time, hashMode); //Assert Assert.AreEqual(otp, expectedOtp); }
/// <summary> /// Create an HMAC object for the specified algorithm /// </summary> private static HMAC CreateHmacHash(OtpHashModeEnum otpHashMode) { HMAC hmacAlgorithm = null; switch (otpHashMode) { case OtpHashModeEnum.Sha256: hmacAlgorithm = new HMACSHA256(); break; case OtpHashModeEnum.Sha512: hmacAlgorithm = new HMACSHA512(); break; default: //case OtpHashMode.Sha1: hmacAlgorithm = new HMACSHA1(); break; } return(hmacAlgorithm); }