private async Task AuthenticateWithSmartCardAsync(SmartCard card) { var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings; String m_selectedDeviceId = localSettings.Values["SelectedDevice"] as String; string m_selectedDeviceFriendlyName = string.Empty; string m_selectedDeviceAddDate = string.Empty; string deviceConfigString = string.Empty; char[] deviceConfigCharArray; byte[] deviceIdArray = new byte[16]; byte[] deviceDlockState = new byte[1]; bool foundCompanionDevice = false; byte[] response = { 0 }; string sw1sw2 = null; SecondaryAuthenticationFactorAuthenticationStageInfo authStageInfo = await SecondaryAuthenticationFactorAuthentication.GetAuthenticationStageInfoAsync(); if ((authStageInfo.Stage != SecondaryAuthenticationFactorAuthenticationStage.CollectingCredential) && (authStageInfo.Stage != SecondaryAuthenticationFactorAuthenticationStage.WaitingForUserConfirmation)) { throw new Exception("Unexpected! Stage: " + authStageInfo.Stage); } //ShowToastNotification("Post Collecting Credential"); System.Diagnostics.Debug.WriteLine("[AuthenticateWithSmartCardAsync] Post Collecting Credential"); IReadOnlyList <SecondaryAuthenticationFactorInfo> deviceList = await SecondaryAuthenticationFactorRegistration.FindAllRegisteredDeviceInfoAsync( SecondaryAuthenticationFactorDeviceFindScope.AllUsers); if (deviceList.Count == 0) { //ShowToastNotification("Unexpected exception, device list = 0"); throw new Exception("Unexpected exception, device list = 0"); } SmartCardConnection connection = await card.ConnectAsync(); System.Diagnostics.Debug.WriteLine("[AuthenticateWithSmartCardAsync] Connection"); response = await Apdu.TransmitApduAsync(connection, Apdu.getDeviceGuidCmdApdu); sw1sw2 = Apdu.ApduResponseParser(response, out response); deviceIdArray = response; string deviceId = BitConverter.ToString(response).Replace("-", ""); response = await Apdu.TransmitApduAsync(connection, Apdu.getDlockStateCmdApdu); sw1sw2 = Apdu.ApduResponseParser(response, out response); deviceDlockState = response; //string deviceFriendlyName = null; byte[] deviceConfigDataArray = new byte[18]; //16 bytes for GUID and 1 byte for dLockstate IBuffer deviceConfigData; byte[] deviceConfigurationDataArray; //List<byte[]> deviceConfigList = new List<byte[]>(); foreach (SecondaryAuthenticationFactorInfo device in deviceList) { CryptographicBuffer.CopyToByteArray(device.DeviceConfigurationData, out deviceConfigurationDataArray); //deviceConfigList.Add(deviceConfigurationDataArray); //deviceFriendlyName = device.DeviceFriendlyName; if (device.DeviceId == deviceId) { m_selectedDeviceId = deviceId; m_selectedDeviceFriendlyName = device.DeviceFriendlyName; deviceConfigString = CryptographicBuffer.ConvertBinaryToString(0, device.DeviceConfigurationData); //deviceConfigCharArray = new char[deviceConfigString.Count()]; //deviceConfigCharArray = deviceConfigString.ToCharArray(); int count = device.DeviceFriendlyName.Count(); m_selectedDeviceAddDate = deviceConfigString.Substring(35 + 1 + count + 1 + 1); foundCompanionDevice = true; //continue; } } //Debugger.Break(); if (!foundCompanionDevice) { throw new CompanionDeviceNotFoundException(); } System.Diagnostics.Debug.WriteLine("[AuthenticateWithSmartCardAsync] Start Nonce APDU sending"); response = await Apdu.TransmitApduAsync(connection, Apdu.getNonceCmdApdu); sw1sw2 = Apdu.ApduResponseParser(response, out response); if (sw1sw2 != "9000") { throw new UnableTogetNonceFromDeviceException(); } System.Diagnostics.Debug.WriteLine("[AuthenticateWithSmartCardAsync] Nonce APDU recieved without error"); string nonce = BitConverter.ToString(response).Replace("-", ""); IBuffer svcNonce = CryptographicBuffer.DecodeFromHexString(nonce); System.Diagnostics.Debug.WriteLine("[AuthenticateWithSmartCardAsync] Start Authentication"); SecondaryAuthenticationFactorAuthenticationResult authResult = await SecondaryAuthenticationFactorAuthentication.StartAuthenticationAsync( m_selectedDeviceId, svcNonce); if (authResult.Status != SecondaryAuthenticationFactorAuthenticationStatus.Started) { //ShowToastNotification("Unexpected! Could not start authentication!"); throw new Exception("Unexpected! Could not start authentication! Status: " + authResult.Status); } byte[] devNonce = { 0 }; byte[] svcHmac = { 0 }; byte[] sessNonce = { 0 }; CryptographicBuffer.CopyToByteArray(authResult.Authentication.ServiceAuthenticationHmac, out svcHmac); CryptographicBuffer.CopyToByteArray(authResult.Authentication.SessionNonce, out sessNonce); CryptographicBuffer.CopyToByteArray(authResult.Authentication.DeviceNonce, out devNonce); byte[] cmd = new byte[Apdu.challengeCmdApdu.Length + svcHmac.Length + sessNonce.Length + devNonce.Length]; System.Buffer.BlockCopy(Apdu.challengeCmdApdu, 0, cmd, 0, Apdu.challengeCmdApdu.Length); System.Buffer.BlockCopy(svcHmac, 0, cmd, Apdu.challengeCmdApdu.Length, svcHmac.Length); System.Buffer.BlockCopy(sessNonce, 0, cmd, Apdu.challengeCmdApdu.Length + svcHmac.Length, sessNonce.Length); System.Buffer.BlockCopy(devNonce, 0, cmd, Apdu.challengeCmdApdu.Length + svcHmac.Length + sessNonce.Length, devNonce.Length); System.Diagnostics.Debug.WriteLine("[AuthenticateWithSmartCardAsync] Send Challenge"); string str = "\"" + m_selectedDeviceFriendlyName + "\""; await SecondaryAuthenticationFactorAuthentication.ShowNotificationMessageAsync( str, SecondaryAuthenticationFactorAuthenticationMessage.DeviceNeedsAttention); response = await Apdu.TransmitApduAsync(connection, cmd); sw1sw2 = Apdu.ApduResponseParser(response, out response); if (sw1sw2 == "6985") { throw new UnauthorizedUserException(); } else if (sw1sw2 == "6984") { //ShowToastNotification("Log-in denied by user"); throw new LogInDeniedByUserException(); } System.Diagnostics.Debug.WriteLine("[AuthenticateWithSmartCardAsync] Response recieved"); byte[] HMACdk = new byte[32]; byte[] HMACsk = new byte[32]; System.Buffer.BlockCopy(response, 0, HMACdk, 0, 32); System.Buffer.BlockCopy(response, 32, HMACsk, 0, 32); IBuffer deviceHmac = CryptographicBuffer.CreateFromByteArray(HMACdk); IBuffer sessionHmac = CryptographicBuffer.CreateFromByteArray(HMACsk); SecondaryAuthenticationFactorFinishAuthenticationStatus authStatus = await authResult.Authentication.FinishAuthenticationAsync(deviceHmac, sessionHmac); if (authStatus != SecondaryAuthenticationFactorFinishAuthenticationStatus.Completed) { //ShowToastNotification("Unable to complete authentication!"); System.Diagnostics.Debug.WriteLine("[AuthenticateWithSmartCardAsync] Unable to complete authentication"); throw new Exception("Unable to complete authentication!"); } deviceConfigString = ""; if (deviceDlockState[0] == 0) { deviceConfigString = deviceId + "-0-1-" + m_selectedDeviceFriendlyName + "-" + m_selectedDeviceAddDate; } else { deviceConfigString = deviceId + "-1-1-" + m_selectedDeviceFriendlyName + "-" + m_selectedDeviceAddDate; } deviceConfigCharArray = new char[deviceConfigString.Count()]; deviceConfigString.CopyTo(0, deviceConfigCharArray, 0, deviceConfigString.Count()); // because deviceConfigString is readonly deviceConfigCharArray[35] = '1'; // to indicate that device was not used for last login string deviceConfigStringNew = new string(deviceConfigCharArray); //Debugger.Break(); deviceConfigData = CryptographicBuffer.ConvertStringToBinary(deviceConfigStringNew, 0); await SecondaryAuthenticationFactorRegistration.UpdateDeviceConfigurationDataAsync(deviceId, deviceConfigData); //update deviceConfigData foreach (SecondaryAuthenticationFactorInfo device in deviceList) { if (device.DeviceId != deviceId) { deviceConfigString = CryptographicBuffer.ConvertBinaryToString(0, device.DeviceConfigurationData); deviceConfigCharArray = new char[deviceConfigString.Count()]; deviceConfigString.CopyTo(0, deviceConfigCharArray, 0, deviceConfigString.Count()); // decause deviceConfigString is readonly deviceConfigCharArray[35] = '0'; // to indicate that device was not used for last login deviceConfigStringNew = new string(deviceConfigCharArray); deviceConfigData = CryptographicBuffer.ConvertStringToBinary(deviceConfigStringNew, 0); //Debugger.Break(); await SecondaryAuthenticationFactorRegistration.UpdateDeviceConfigurationDataAsync(device.DeviceId, deviceConfigData); //update deviceConfigData } } System.Diagnostics.Debug.WriteLine("[AuthenticateWithSmartCardAsync] Auth completed"); connection.Dispose(); }
private async void Auth(DeviceAuthSession session) { if (session == null) { await SecondaryAuthenticationFactorAuthentication.ShowNotificationMessageAsync("", SecondaryAuthenticationFactorAuthenticationMessage.Invalid); return; } var deviceInDb = session.DeviceInDb; await SecondaryAuthenticationFactorAuthentication.ShowNotificationMessageAsync(deviceInDb.DeviceFriendlyName, SecondaryAuthenticationFactorAuthenticationMessage.ReadyToSignIn); IBuffer svcAuthNonce = CryptographicBuffer.GenerateRandom(256 / 8); SecondaryAuthenticationFactorAuthenticationResult authResult = await SecondaryAuthenticationFactorAuthentication.StartAuthenticationAsync( session.DeviceID, svcAuthNonce); if (authResult.Status != SecondaryAuthenticationFactorAuthenticationStatus.Started) { var message = SecondaryAuthenticationFactorAuthenticationMessage.Invalid; switch (authResult.Status) { case SecondaryAuthenticationFactorAuthenticationStatus.DisabledByPolicy: message = SecondaryAuthenticationFactorAuthenticationMessage.DisabledByPolicy; break; case SecondaryAuthenticationFactorAuthenticationStatus.InvalidAuthenticationStage: break; default: return; } await SecondaryAuthenticationFactorAuthentication.ShowNotificationMessageAsync(null, message); return; } var auth = authResult.Authentication; CurrentSession = session; for (int retries = 0; retries < 3; retries++) { var svcAuthHmac = auth.ServiceAuthenticationHmac; var deviceNonce = auth.DeviceNonce; var sessionNonce = auth.SessionNonce; var arr = new byte[3 + svcAuthHmac.Length + deviceNonce.Length + sessionNonce.Length]; arr[0] = (byte)svcAuthHmac.Length; arr[1] = (byte)deviceNonce.Length; arr[2] = (byte)sessionNonce.Length; Array.Copy(svcAuthHmac.ToArray(), 0, arr, 3, svcAuthHmac.Length); Array.Copy(deviceNonce.ToArray(), 0, arr, 3 + svcAuthHmac.Length, deviceNonce.Length); Array.Copy(sessionNonce.ToArray(), 0, arr, 3 + svcAuthHmac.Length + deviceNonce.Length, sessionNonce.Length); var payload = Convert.ToBase64String(arr); UDPListener.Send(session.LastIP, Encoding.UTF8.GetBytes(DeviceDiscoverPrefix + payload)); AuthResultReceivedEvent = new ManualResetEvent(false); try { AuthResultReceivedEvent.WaitOne(20000); } catch (Exception) { // ignored } var result = session.ResultBytes; if (result == null || result.Length <= 2 || result.Length != 2 + result[0] + result[1]) { return; /*await SecondaryAuthenticationFactorAuthentication.ShowNotificationMessageAsync("", * SecondaryAuthenticationFactorAuthenticationMessage.TryAgain); * await auth.AbortAuthenticationAsync("No data got."); * continue;*/ } var deviceHmac = new Buffer(result[0]); var sessionHmac = new Buffer(result[1]); result.CopyTo(2, deviceHmac, 0, result[0]); result.CopyTo(2 + result[0], sessionHmac, 0, result[1]); var status = await auth.FinishAuthenticationAsync(deviceHmac, sessionHmac); switch (status) { case SecondaryAuthenticationFactorFinishAuthenticationStatus.Completed: // The credential data is collected and ready for unlock CurrentSession = null; return; default: await SecondaryAuthenticationFactorAuthentication.ShowNotificationMessageAsync("", SecondaryAuthenticationFactorAuthenticationMessage.TryAgain); break; } } await SecondaryAuthenticationFactorAuthentication.ShowNotificationMessageAsync(deviceInDb.DeviceFriendlyName, SecondaryAuthenticationFactorAuthenticationMessage.UnauthorizedUser); CurrentSession = null; }
async void PerformAuthentication() { ShowToastNotification("Performing Auth!"); //Get the selected device from app settings var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings; String m_selectedDeviceId = localSettings.Values["SelectedDevice"] as String; SecondaryAuthenticationFactorAuthenticationStageInfo authStageInfo = await SecondaryAuthenticationFactorAuthentication.GetAuthenticationStageInfoAsync(); if (authStageInfo.Stage != SecondaryAuthenticationFactorAuthenticationStage.CollectingCredential) { ShowToastNotification("Unexpected!"); throw new Exception("Unexpected!"); } ShowToastNotification("Post Collecting Credential"); IReadOnlyList <SecondaryAuthenticationFactorInfo> deviceList = await SecondaryAuthenticationFactorRegistration.FindAllRegisteredDeviceInfoAsync( SecondaryAuthenticationFactorDeviceFindScope.AllUsers); if (deviceList.Count == 0) { ShowToastNotification("Unexpected exception, device list = 0"); throw new Exception("Unexpected exception, device list = 0"); } ShowToastNotification("Found companion devices"); SecondaryAuthenticationFactorInfo deviceInfo = deviceList.ElementAt(0); m_selectedDeviceId = deviceInfo.DeviceId; ShowToastNotification("Device ID: " + m_selectedDeviceId); //a nonce is an arbitrary number that may only be used once - a random or pseudo-random number issued in an authentication protocol to ensure that old communications cannot be reused in replay attacks. IBuffer svcNonce = CryptographicBuffer.GenerateRandom(32); //Generate a nonce and do a HMAC operation with the nonce //In real world, you would need to take this nonce and send to companion device to perform an HMAC operation with it //You will have only 20 second to get the HMAC from the companion device SecondaryAuthenticationFactorAuthenticationResult authResult = await SecondaryAuthenticationFactorAuthentication.StartAuthenticationAsync( m_selectedDeviceId, svcNonce); if (authResult.Status != SecondaryAuthenticationFactorAuthenticationStatus.Started) { ShowToastNotification("Unexpected! Could not start authentication!"); throw new Exception("Unexpected! Could not start authentication!"); } ShowToastNotification("Auth Started"); // // WARNING: Test code // The HAMC calculation SHOULD be done on companion device // byte[] combinedDataArray; CryptographicBuffer.CopyToByteArray(authResult.Authentication.DeviceConfigurationData, out combinedDataArray); byte[] deviceKeyArray = new byte[32]; byte[] authKeyArray = new byte[32]; for (int index = 0; index < deviceKeyArray.Length; index++) { deviceKeyArray[index] = combinedDataArray[index]; } for (int index = 0; index < authKeyArray.Length; index++) { authKeyArray[index] = combinedDataArray[deviceKeyArray.Length + index]; } // Create device key and authentication key IBuffer deviceKey = CryptographicBuffer.CreateFromByteArray(deviceKeyArray); IBuffer authKey = CryptographicBuffer.CreateFromByteArray(authKeyArray); // Calculate the HMAC MacAlgorithmProvider hMACSha256Provider = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha256); CryptographicKey deviceHmacKey = hMACSha256Provider.CreateKey(deviceKey); IBuffer deviceHmac = CryptographicEngine.Sign(deviceHmacKey, authResult.Authentication.DeviceNonce); // sessionHmac = HMAC(authKey, deviceHmac || sessionNonce) IBuffer sessionHmac; byte[] deviceHmacArray = { 0 }; CryptographicBuffer.CopyToByteArray(deviceHmac, out deviceHmacArray); byte[] sessionNonceArray = { 0 }; CryptographicBuffer.CopyToByteArray(authResult.Authentication.SessionNonce, out sessionNonceArray); combinedDataArray = new byte[deviceHmacArray.Length + sessionNonceArray.Length]; for (int index = 0; index < deviceHmacArray.Length; index++) { combinedDataArray[index] = deviceHmacArray[index]; } for (int index = 0; index < sessionNonceArray.Length; index++) { combinedDataArray[deviceHmacArray.Length + index] = sessionNonceArray[index]; } // Get a Ibuffer from combinedDataArray IBuffer sessionMessage = CryptographicBuffer.CreateFromByteArray(combinedDataArray); // Calculate sessionHmac CryptographicKey authHmacKey = hMACSha256Provider.CreateKey(authKey); sessionHmac = CryptographicEngine.Sign(authHmacKey, sessionMessage); ShowToastNotification("Before finish auth"); SecondaryAuthenticationFactorFinishAuthenticationStatus authStatus = await authResult.Authentication.FinishAuthenticationAsync(deviceHmac, sessionHmac); if (authStatus != SecondaryAuthenticationFactorFinishAuthenticationStatus.Completed) { ShowToastNotification("Unable to complete authentication!"); throw new Exception("Unable to complete authentication!"); } ShowToastNotification("Auth completed"); }