//------------------------------------------------------------------------------------------------- //--- Check if a provided OTP is valid for the provided GUID (allow 3 past + 3 future ones) //------------------------------------------------------------------------------------------------- public static async Task <bool> IsValidOTPFromGuid(Guid TheGuid, int TheOTPToCheck, bool UseNetworkTime = false) { bool success = false; int myNumberOfOTPs = 7; Int64 myTimeStamp; byte[] mySecret; byte[] myHmac; byte[] myData; int myOffset; int myOneTimePassword; Int64 MyUnixTimestamp; int[] myAllowedOTPArray = new int[myNumberOfOTPs]; mySecret = StringToBytes(TheGuid.ToString("N")); #if WINDOWS_UWP var myCryptprovider = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha1); #else HMACSHA1 myCryptprovider = new HMACSHA1(mySecret); #endif MyUnixTimestamp = await GetUnixTimestamp(UseNetworkTime); myTimeStamp = Convert.ToInt64(MyUnixTimestamp / 30); for (int i = 0; i < myNumberOfOTPs; i++) { //current timestamp = myTimeStamp(-0) //So we allow the previous 3 values and future 3 values as well myData = BitConverter.GetBytes(myTimeStamp + i - 3).Reverse().ToArray(); #if WINDOWS_UWP var myBuffer = CryptographicBuffer.CreateFromByteArray(myData); var myKeyBuffer = CryptographicBuffer.CreateFromByteArray(mySecret); var myKey = myCryptprovider.CreateKey(myKeyBuffer); var mySignedBuffer = CryptographicEngine.Sign(myKey, myBuffer); CryptographicBuffer.CopyToByteArray(mySignedBuffer, out myHmac); #else myHmac = new HMACSHA1(mySecret).ComputeHash(myData); #endif myOffset = myHmac.Last() & 0x0F; myOneTimePassword = ( ((myHmac[myOffset + 0] & 0x7f) << 24) | ((myHmac[myOffset + 1] & 0xff) << 16) | ((myHmac[myOffset + 2] & 0xff) << 8) | (myHmac[myOffset + 3] & 0xff) ) % 1000000; myAllowedOTPArray[i] = myOneTimePassword; } //do the check int index = 0; while ((index < myNumberOfOTPs) & (!success)) { success = myAllowedOTPArray[index] == TheOTPToCheck; index++; } return(success); }