Create Shared Project for OTP handling

In Visual Studio 2015, there is a way to share code between different projects, without relying on creating DLL’s.

This has the advantage that you can maintain one codebase for your Classes and related programming logic, and this will be compiled directly into your application.

Using Conditional Compilation Directives, you can make your code run on the different platforms like in a WebService, WPF application and the newer Windows 10 UAP platform, so you can target Server Side Code, Regular Windows applications and Native Windows 10 Apps, which also tun on Mobile Devices and IOT Windows 10 Core devices, like a Raspberry PI2.


As base for my functionality, I selected to implement the Google Authenticator and used the article by Rick Bassham on Implementing Two Factor Authentication in ASP.NET MVC with Google Authenticator as base for my library.


This is how to create a Shared Project in VS2015: In the Solution Explorer window,  right-click and select Add | New Project and choose Shared Project as in below screenshot and name it OTPSharedProject.

OTPSharedProject

In the Solution Explorer Window, select the OTPShared Project, right-click and select Add | New Item and chose Class as in below screenshot, and name it OTPAuthenticator.

OTPAuthenticator

We make the class a Static class, as it is not intended to be initiates, and serves only to provide the methods:

public static int OTPFromGuid(Guid TheGuid)
public static bool IsValidOTPFromGuid(Guid TheGuid, int TheOTPToCheck)

The first method: OTPFromGuid creates a OneTimePassword, based upon a provided Guid.
This OTP is different every 30 secs (based upon the clock of the decive it runs on)

The second method IsValidOTPFromGuid, verifies if the provided OTP, is a valid OTP for the provided Guid.
In order to handle time differences between the client and the service that verifies the validity, we allow the OTP which is calculated for the current system time, as well as the 3 previous and 3 next OTP values.


This is the complete code:

using System;
using System.Linq;

#if WINDOWS_UWP
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.core;
#else
using System.Security.Cryptography;
#endif

namespace OTPSharedProject
{

public static class OTPAuthenticator
{

private static byte[] StringToBytes(string TheString)
{

string myHexString = TheString;

//The binary key cannot have an odd number of digits, so Add a trailing 0
if (myHexString.Length % 2 == 1) myHexString = TheString + “0”;
byte[] myArray = new byte[myHexString.Length >> 1];
for (int i = 0; i < myHexString.Length >> 1; ++i)
{

myArray[i] = (byte)((GetHexVal(myHexString[i << 1]) << 4) + (GetHexVal(myHexString[(i << 1) + 1])));

}

return myArray;

}

private static int GetHexVal(char TheHexChar)

{

int myValue = (int)TheHexChar;
//For uppercase A-F letters:
//return myValue – (myValue < 58 ? 48 : 55);
//For lowercase a-f letters:
//return myValue – (myValue < 58 ? 48 : 87);
//Or the two combined, but a bit slower:
return myValue – (myValue < 58 ? 48 : (myValue < 97 ? 55 : 87));

}

private static Int64 GetUnixTimestamp()

{

return Convert.ToInt64(Math.Round((DateTime.UtcNow – new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds));

}

public static int OTPFromGuid(Guid TheGuid)

{

Int64 myTimeStamp;
byte[] mySecret;
byte[] myHmac;
byte[] myData;
int myOffset;
int myOneTimePassword;
mySecret = StringToBytes(TheGuid.ToString(“N”));

#if WINDOWS_UWP

var myCryptprovider = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha1);

#else

HMACSHA1 crypt = new HMACSHA1(mySecret);

#endif

myTimeStamp = Convert.ToInt64(GetUnixTimestamp() / 30);
myData = BitConverter.GetBytes(myTimeStamp).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;

return myOneTimePassword;

 }

public static bool IsValidOTPFromGuid(Guid TheGuid, int TheOTPToCheck)

{

bool success = false;
int myNumberOfOTPs = 7;
Int64 myTimeStamp;
byte[] mySecret;
byte[] myHmac;
byte[] myData;
int myOffset;
int myOneTimePassword;
int[] myAllowedOTPArray = new int[myNumberOfOTPs];
mySecret = StringToBytes(TheGuid.ToString(“N”));

#if WINDOWS_UWP

var myCryptprovider = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha1);

#else

HMACSHA1 crypt = new HMACSHA1(mySecret);

#endif

myTimeStamp = Convert.ToInt64(GetUnixTimestamp() / 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;

}

}

}

Advertisements

Post a comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s