Skip to content

Instantly share code, notes, and snippets.

@marcomagdy
Last active May 30, 2023 17:43
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save marcomagdy/6bd4d8dc41e77b37dc74 to your computer and use it in GitHub Desktop.
Google MFA in C#
class Program
{
static void Main(string[] args) {
var secretByets = Base32Encoding.ToBytes("supersecretpassword");
var input = GetEpoch() / 30;
var hmac = new HMACSHA1(secretByets);
var output = hmac.ComputeHash(toBytes(input));
Console.WriteLine("{0:d6}", calculate(output));
// print value for the past 30 seconds as well for user convenience
output = hmac.ComputeHash(toBytes(--input));
Console.WriteLine("{0:d6}", calculate(output));
}
private static uint calculate(byte[] output) {
// Slim down the value from 20 bytes to 4 bytes.
// But, instead of always using the first 4 bytes,
// use the value of last byte of the 20-bytes
// to determine the start index of the 4-bytes we're interested in.
var index = output[output.Length - 1] & 0x0f;
var slimmed = new byte[4];
slimmed[0] = output[index++];
slimmed[1] = output[index++];
slimmed[2] = output[index++];
slimmed[3] = output[index];
slimmed[0] &= 0x7f; // ignore the most significant bit as per RFC 4226
var large = ToUint32(slimmed);
// modulus 1 million to ensure the values are 6 digits or less
return large % 1000000;
}
// convert to/from byte arrays to/from uint using Big-Endian
// BitConverter class is will use Little-Endian on Windows
private static byte[] toBytes(UInt64 input) {
var result = new byte[8];
var shifts = new UInt16[] {56, 48, 40, 32, 24, 16, 8, 0};
for (int i = 0; i < shifts.Length; i++) {
result[i] = (byte)((input >> shifts[i]) & 0xFF);
}
return result;
}
private static UInt32 ToUint32(byte[] bytes) {
return (UInt32)((bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | (bytes[3]));
}
private static UInt64 GetEpoch() {
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return (UInt64)((DateTime.UtcNow - epoch).TotalSeconds);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment