Skip to content

Instantly share code, notes, and snippets.

@Kir-Antipov
Created August 23, 2019 22:02
Show Gist options
  • Save Kir-Antipov/17ee3265bf4eaf7252393233334d734c to your computer and use it in GitHub Desktop.
Save Kir-Antipov/17ee3265bf4eaf7252393233334d734c to your computer and use it in GitHub Desktop.
Quick check of 6-digit totp code
public static bool Verify(string digits, string secret)
{
if (string.IsNullOrEmpty(digits) || string.IsNullOrEmpty(secret))
return false;
long iterations = DateTimeOffset.Now.ToUnixTimeSeconds() / 30L;
byte[] secretBytes = Base32ToBytes(secret);
if (Verify(digits, secretBytes, iterations))
return true;
else
return Verify(digits, secretBytes, iterations - 1);
}
private static bool Verify(string digits, byte[] secret, long iterations)
{
byte[] buffer = BitConverter.GetBytes(iterations);
Array.Reverse(buffer);
using (HMACSHA1 sha1 = new HMACSHA1(secret))
{
byte[] hash = sha1.ComputeHash(buffer);
byte[] result = new byte[4];
Array.Copy(hash, hash[hash.Length - 1] & 0x0F, result, 0, 4);
result[0] = (byte)(result[0] & 0b01111111);
Array.Reverse(result);
int resultDigits = BitConverter.ToInt32(result) % 1000000; // Take last 6 digits
return $"{resultDigits:d6}" == digits;
}
}
public static byte[] Base32ToBytes(string base32)
{
const string charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
if (base32 is null)
throw new ArgumentNullException(nameof(base32));
if (base32 == string.Empty)
return new byte[0];
base32 = base32.TrimEnd('=').ToUpper();
int count = base32.Length * 5 / 8;
byte[] result = new byte[count];
byte current = 0;
int bitsRemaining = 8;
int i = 0;
foreach (char c in base32)
{
int val = charset.IndexOf(c);
if (bitsRemaining > 5)
{
int mask = val << (bitsRemaining - 5);
current = (byte)(current | mask);
bitsRemaining -= 5;
}
else
{
int mask = val >> (5 - bitsRemaining);
current = (byte)(current | mask);
result[i++] = current;
current = (byte)(val << (3 + bitsRemaining));
bitsRemaining += 3;
}
}
if (i != count)
result[i] = current;
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment