I have a badge reader in my laptop and a smartcard badge.
Following this guide from Microsoft, I can get the reader and set its CardAdded event.
In the part about getting an authentication response, the guide mentions a rootPage that stores an already inserted card. Since I'm still learning this code, I don't have that yet. Also the article doesn't mention where to put this fragment:
bool verifyResult = false;
SmartCard card = await rootPage.GetSmartCard();
SmartCardProvisioning provisioning = await SmartCardProvisioning.FromSmartCardAsync(card);
using (SmartCardChallengeContext context = await provisioning.GetChallengeContextAsync())
{
IBuffer response = ChallengeResponseAlgorithm.CalculateResponse(
context.Challenge,
rootPage.AdminKey);
verifyResult = await context.VerifyResponseAsync(response);
}
Since Reader_CardAdded event supplies what I need, I just put the code there and insert my badge to test it.
Note: Aside from getting the card from the args, the try/catch, and supposing the adminKey is the pin, the meat of it is copied directly from the guide.
private async void Reader_CardAdded(SmartCardReader sender, CardAddedEventArgs args)
{
bool verifyResult = false;
SmartCard card = args.SmartCard;
if (card != null)
{
try
{
SmartCardProvisioning provisioning = await SmartCardProvisioning.FromSmartCardAsync(card);
using (SmartCardChallengeContext context = await provisioning.GetChallengeContextAsync())
{
IBuffer adminKey = new Windows.Storage.Streams.Buffer(pinText);
IBuffer response = ChallengeResponseAlgorithm.CalculateResponse(context.Challenge, adminKey);
verifyResult = await context.VerifyResponseAsync(response);
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
}
Upon inserting my badge, the Reader_CardAdded event fires no problem. But when it comes to this line:
using (SmartCardChallengeContext context = await provisioning.GetChallengeContextAsync())
An exception is thrown
Message: The system cannot find the file specified. (Exception from HRESULT: 0x80070002)
Source: System.Private.CoreLib
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at FEOD.UWP.FEODSmartCard.<Reader_CardAdded>d__5.MoveNext()
I didn't expect that at all since the guide makes no mention of a potential exception, let alone one about a missing file.
The guide uses this example. I downloaded that code and fixed Scenario1_ProvisionTMP.xaml.cs to use my actual reader and card instead of virtual ones. The sample then throws the same exception.
e.g. in Create_Click, I only made these modifications
//SmartCardPinPolicy pinPolicy = ParsePinPolicy();
IBuffer adminkey = CryptographicBuffer.GenerateRandom(MainPage.ADMIN_KEY_LENGTH_IN_BYTES);
//SmartCardProvisioning provisioning = await SmartCardProvisioning.RequestVirtualSmartCardCreationAsync(FriendlyName.Text, adminkey, pinPolicy);
string selector = SmartCardReader.GetDeviceSelector();
DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(selector);
DeviceInformation device = devices[0];
SmartCardReader reader = await SmartCardReader.FromIdAsync(device.Id);
SmartCard card = reader.FindAllCardsAsync().GetResults().First();
SmartCardProvisioning provisioning = await SmartCardProvisioning.FromSmartCardAsync(card);
Has anyone successfully implemented this functionality?
--------------- SIMPLE REPRO ---------------------------
Create a new project using "Blank App (Universal Windows)"
Add a button to MainPage.xml and add a Click Event to it
In MainPage.xaml.cs add the following methods
public async Task CardAuth() { try { IBuffer adminkey = CryptographicBuffer.GenerateRandom(24); //SmartCardProvisioning provisioning = await SmartCardProvisioning.RequestVirtualSmartCardCreationAsync(FriendlyName.Text, adminkey, pinPolicy); string selector = SmartCardReader.GetDeviceSelector(); DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(selector); DeviceInformation device = devices[0]; SmartCardReader reader = await SmartCardReader.FromIdAsync(device.Id); SmartCard card = reader.FindAllCardsAsync().GetResults().First(); SmartCardProvisioning provisioning = await SmartCardProvisioning.FromSmartCardAsync(card); reader.CardAdded += Reader_CardAdded; using (var context = await provisioning.GetChallengeContextAsync()) { IBuffer response = ChallengeResponseAlgorithm.CalculateResponse(context.Challenge, adminkey); await context.ProvisionAsync(response, true); } } catch (Exception e) { Console.WriteLine(e); } } private void Reader_CardAdded(SmartCardReader sender, CardAddedEventArgs args) { var a = 1; }
For the Button click event add this one line of code
private void Card_OnClick(object sender, RoutedEventArgs e) { Task.Run(async () => await CardAuth()); }
Add one class to the solution
static class ChallengeResponseAlgorithm { /// <summary> /// Calculates the response by encrypting the challenge by using Triple DES (3DES). /// If the resulting values are the same, the authentication is successful. /// </summary> /// <param name="challenge">a block of challenge data generated by smart card using its admin key</param> /// <param name="adminkey">the admin key of the smart card, which is normally saved on the server side or management tool.</param> /// <returns>the response</returns> public static IBuffer CalculateResponse(IBuffer challenge, IBuffer adminkey) { if (challenge == null) { throw new ArgumentNullException("challenge"); } if (adminkey == null) { throw new ArgumentNullException("adminkey"); } SymmetricKeyAlgorithmProvider objAlg = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.TripleDesCbc); var symmetricKey = objAlg.CreateSymmetricKey(adminkey); var buffEncrypted = CryptographicEngine.Encrypt(symmetricKey, challenge, null); return buffEncrypted; } }
Put a break point in CardAuth()'s catch.
Run the app, press the button, see the exception caused by GetChallengeContextAsync:
"The system cannot find the file specified."