SmartCards in C# on Windows 10

3

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 ---------------------------

  1. Create a new project using "Blank App (Universal Windows)"

  2. Add a button to MainPage.xml and add a Click Event to it

  3. 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;
     }
    
  4. For the Button click event add this one line of code

     private void Card_OnClick(object sender, RoutedEventArgs e)
     {
         Task.Run(async () => await CardAuth());
     }
    
  5. 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;
         }
     }
    
  6. Put a break point in CardAuth()'s catch.

  7. Run the app, press the button, see the exception caused by GetChallengeContextAsync:

"The system cannot find the file specified."

c#
.net
windows
uwp
smartcard
asked on Stack Overflow Aug 14, 2020 by John Mc • edited Aug 17, 2020 by John Mc

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0