Skip to content

Commit

Permalink
Add DESFire authentication tool with SAM AV
Browse files Browse the repository at this point in the history
  • Loading branch information
Maxhy committed Mar 27, 2024
1 parent 4339916 commit 9f6cb03
Show file tree
Hide file tree
Showing 11 changed files with 486 additions and 53 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Collections.ObjectModel;

namespace Leosac.KeyManager.Library.KeyStore.NXP_SAM.UI.Domain
{
public class LLAReaderViewModel
{
private readonly LibLogicalAccess.LibraryManager _lla;

public LLAReaderViewModel()
{
_lla = LibLogicalAccess.LibraryManager.getInstance();
ReaderProviders = new ObservableCollection<string>(_lla.getAvailableReaders().ToArray());
ReaderUnits = new ObservableCollection<string>();
}

public ObservableCollection<string> ReaderProviders { get; set; }

public ObservableCollection<string> ReaderUnits { get; set; }

public void RefreshReaderList(LLAReaderControl config)
{
var prevru = config!.ReaderUnit;
ReaderUnits.Clear();
var rp = _lla.getReaderProvider(config.ReaderProvider);
var ruList = rp.getReaderList();
foreach (var ru in ruList)
{
ReaderUnits.Add(ru.getName());
}
if (ReaderUnits.Contains(prevru))
{
config.ReaderUnit = prevru;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ public class SAMKeyStorePropertiesControlViewModel : KeyStorePropertiesControlVi
public SAMKeyStorePropertiesControlViewModel()
{
_properties = new SAMKeyStoreProperties();
_lla = LibLogicalAccess.LibraryManager.getInstance();
ReaderProviders = new ObservableCollection<string>(_lla.getAvailableReaders().ToArray());
ReaderUnits = new ObservableCollection<string>();
KeyTypes = new ObservableCollection<DESFireKeyType>(Enum.GetValues<DESFireKeyType>());
CardTypes = new ObservableCollection<string>(new[]
{
Expand All @@ -21,35 +18,13 @@ public SAMKeyStorePropertiesControlViewModel()
});
}

private readonly LibLogicalAccess.LibraryManager _lla;

public SAMKeyStoreProperties? SAMProperties
{
get { return Properties as SAMKeyStoreProperties; }
}

public ObservableCollection<string> ReaderProviders { get; set; }

public ObservableCollection<string> ReaderUnits { get; set; }

public ObservableCollection<DESFireKeyType> KeyTypes { get; set; }

public ObservableCollection<string> CardTypes { get; set; }

public void RefreshReaderList()
{
var prevru = SAMProperties!.ReaderUnit;
ReaderUnits.Clear();
var rp = _lla.getReaderProvider(SAMProperties.ReaderProvider);
var ruList = rp.getReaderList();
foreach (var ru in ruList)
{
ReaderUnits.Add(ru.getName());
}
if (ReaderUnits.Contains(prevru))
{
SAMProperties.ReaderUnit = prevru;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
using LibLogicalAccess.Reader;
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.Input;
using LibLogicalAccess;
using System.Configuration.Provider;
using LibLogicalAccess.Card;

namespace Leosac.KeyManager.Library.KeyStore.NXP_SAM.UI.Domain
{
Expand All @@ -28,11 +31,15 @@ public SAMKeyStoreToolsControlViewModel()
LibLogicalAccess.Card.SAMLockUnlock.SwitchAV2Mode
});

_samDESFireKeyId = 2;
_rfidReaderProvider = "PCSC";

SAMAuthCommand = new RelayCommand(SAMAuthenticate);
SAMSwitchAV2Command = new AsyncRelayCommand(SAMSwitchAV2);
SAMLockUnlockCommand = new RelayCommand(SAMLockUnlock);
SAMGetVersionCommand = new RelayCommand(SAMGetVersion);
SAMActivateMifareSAMCommand = new RelayCommand(SAMActivateMifareSAM);
DESFireAuthenticateCommand = new RelayCommand(DESFireAuthenticate);
}

private KeyVersion _samAuthKey;
Expand Down Expand Up @@ -77,6 +84,76 @@ public LibLogicalAccess.Card.SAMLockUnlock SAMUnlockAction
set => SetProperty(ref _samUnlockAction, value);
}

private byte _samDESFireKeyId;
public byte SAMDESFireKeyId
{
get => _samDESFireKeyId;
set => SetProperty(ref _samDESFireKeyId, value);
}

private byte _samDESFireKeyVersion;
public byte SAMDESFireKeyVersion
{
get => _samDESFireKeyVersion;
set => SetProperty(ref _samDESFireKeyVersion, value);
}

private string _rfidReaderProvider;
public string RFIDReaderProvider
{
get => _rfidReaderProvider;
set => SetProperty(ref _rfidReaderProvider, value);
}

private string _rfidReaderUnit;
public string RFIDReaderUnit
{
get => _rfidReaderUnit;
set => SetProperty(ref _rfidReaderUnit, value);
}

private byte[] _desfireAID = new byte[3];
public byte[] DESFireAID
{
get => _desfireAID;
set => SetProperty(ref _desfireAID, value);
}

private byte _desfireKeyNum;
public byte DESFireKeyNum
{
get => _desfireKeyNum;
set => SetProperty(ref _desfireKeyNum, value);
}

private bool _desfireUseDiversification;
public bool DESFireUseDiversification
{
get => _desfireUseDiversification;
set => SetProperty(ref _desfireUseDiversification, value);
}

private byte[] _desfireDivInput = Array.Empty<byte>();
public byte[] DESFireDivInput
{
get => _desfireDivInput;
set => SetProperty(ref _desfireDivInput, value);
}

private bool _desfireReadFile;
public bool DESFireReadFile
{
get => _desfireReadFile;
set => SetProperty(ref _desfireReadFile, value);
}

private byte _desfireFileNo;
public byte DESFireFileNo
{
get => _desfireFileNo;
set => SetProperty(ref _desfireFileNo, value);
}

public ObservableCollection<LibLogicalAccess.Card.SAMKeyType> KeyTypes { get; set; }

public ObservableCollection<LibLogicalAccess.Card.SAMLockUnlock> UnlockActions { get; set; }
Expand All @@ -91,6 +168,8 @@ public LibLogicalAccess.Card.SAMLockUnlock SAMUnlockAction

public RelayCommand SAMActivateMifareSAMCommand { get; }

public RelayCommand DESFireAuthenticateCommand { get; }

private void SAMGetVersion()
{
try
Expand Down Expand Up @@ -251,5 +330,136 @@ private void SAMLockUnlock()
SnackbarHelper.EnqueueError(SnackbarMessageQueue, ex);
}
}

private void DESFireAuthenticate()
{
try
{
if (!string.IsNullOrEmpty(RFIDReaderProvider))
{
var ks = KeyStore as SAMKeyStore;
var cmd = ks?.Chip?.getCommands();
if (cmd is SAMAV2ISO7816Commands samav2cmd)
{
var lla = LibLogicalAccess.LibraryManager.getInstance();
var rp = lla.getReaderProvider(RFIDReaderProvider);
if (rp == null)
{
log.Error(string.Format("Cannot initialize the RFID Reader Provider `{0}`.", RFIDReaderProvider));
throw new KeyStoreException("Cannot initialize the RFID Reader Provider.");
}

ReaderUnit? ru = null;
if (string.IsNullOrEmpty(RFIDReaderUnit))
{
ru = rp.createReaderUnit();
}
else
{
var readers = rp.getReaderList();
foreach (var reader in readers)
{
if (reader.getName() == RFIDReaderUnit)
{
ru = reader;
break;
}
}
}
if (ru == null)
{
log.Error("Cannot initialize the RFID Reader Unit.");
throw new KeyStoreException("Cannot initialize the RFID Reader Unit.");
}

if (!ru.connectToReader())
{
log.Error("Cannot connect to the RFID Reader Unit.");
throw new KeyStoreException("Cannot connect to the RFID Reader Unit.");
}

if (ru is not ISO7816ReaderUnit isoru)
{
throw new KeyStoreException("The RFID Reader Unit needs to implement ISO7816 interface.");
}

isoru.setSAMReaderUnit(ks.ReaderUnit as ISO7816ReaderUnit);
isoru.setSAMChip(ks.Chip as SAMChip);

try
{
ru.setCardType("DESFireEV1");

if (!ru.waitInsertion(5000))
{
throw new KeyStoreException("No RFID card inserted.");
}
if (!ru.connect())
{
throw new KeyStoreException("Cannot connect to the RFID card.");
}

var chip = ru.getSingleChip();
if (chip == null)
{
throw new KeyStoreException("Cannot retrieve the chip for inserted RFID card.");
}
if (chip.getCommands() is not DESFireEV1ISO7816Commands ev1cmd)
{
throw new KeyStoreException("Unexpected commands type for the inserted RFID card.");
}

uint aid = BitConverter.ToUInt32(DESFireAID);
ev1cmd.selectApplication(aid);

var key = new DESFireKey();
key.setKeyType(DESFireKeyType.DF_KEY_AES);
var kss = new SAMKeyStorage();
kss.setKeySlot(SAMDESFireKeyId);
key.setKeyVersion(SAMDESFireKeyVersion);
key.setKeyStorage(kss);

if (DESFireUseDiversification)
{
var div = new NXPAV2KeyDiversification();
if (DESFireDivInput != null && DESFireDivInput.Length > 0)
{
div.setDivInput(new ByteVector(DESFireDivInput));
}
key.setKeyDiversification(div);
}

ev1cmd.authenticate(DESFireKeyNum, key);
SnackbarHelper.EnqueueMessage(SnackbarMessageQueue, "DESFire authentication with SAM succeeded.");

if (DESFireReadFile)
{
var data = ev1cmd.readData(DESFireFileNo, 0, 0, EncryptionMode.CM_ENCRYPT);
if (data != null)
{
var datastr = Convert.ToHexString(data.ToArray());
SnackbarHelper.EnqueueMessage(SnackbarMessageQueue, string.Format("Data read: {0}", datastr));
}
}

ru.disconnect();
ru.waitRemoval(1);
}
finally
{
isoru.setSAMChip(null);
isoru.setSAMReaderUnit(null);

ru.disconnectFromReader();
}
}
}
}
catch(Exception ex)
{
log.Error("DESFire authentication failed.", ex);
SnackbarHelper.EnqueueError(SnackbarMessageQueue, ex);
}
}
}
}
29 changes: 29 additions & 0 deletions KeyManager.Library.KeyStore.NXP_SAM.UI/LLAReaderControl.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<UserControl x:Class="Leosac.KeyManager.Library.KeyStore.NXP_SAM.UI.LLAReaderControl"
x:Name="llaControl"
xmlns="http:https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http:https://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http:https://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http:https://schemas.microsoft.com/expression/blend/2008"
xmlns:domain="clr-namespace:Leosac.KeyManager.Library.KeyStore.NXP_SAM.UI.Domain"
xmlns:local="clr-namespace:Leosac.KeyManager.Library.KeyStore.NXP_SAM.UI"
xmlns:materialDesign="http:https://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:properties="clr-namespace:Leosac.KeyManager.Library.KeyStore.NXP_SAM.UI.Properties"
xmlns:wpfappctrls="clr-namespace:Leosac.WpfApp.Controls;assembly=WpfApp"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance domain:LLAReaderViewModel}"
d:DesignHeight="250" d:DesignWidth="400">
<StackPanel>
<ComboBox ItemsSource="{Binding ReaderProviders}" SelectedItem="{Binding ReaderProvider, ElementName=llaControl}"
materialDesign:HintAssist.HelperText="{x:Static properties:Resources.ReaderProviderHelper}"
materialDesign:HintAssist.Hint="{x:Static properties:Resources.ReaderProvider}" Margin="5,5,5,10" SelectionChanged="cbReaderProvider_SelectionChanged" />
<DockPanel LastChildFill="True">
<Button DockPanel.Dock="Right" x:Name="btnRefreshReaderUnits" Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}" Width="24" Height="24" Margin="3" ToolTip="{x:Static properties:Resources.RefreshReaderUnits}" Click="btnRefreshReaderUnits_Click">
<materialDesign:PackIcon Kind="Refresh" Height="16" Width="16"/>
</Button>
<ComboBox ItemsSource="{Binding ReaderUnits}" SelectedItem="{Binding ReaderUnit, ElementName=llaControl}"
materialDesign:HintAssist.HelperText="{x:Static properties:Resources.ReaderUnitHelper}"
materialDesign:HintAssist.Hint="{x:Static properties:Resources.ReaderUnit}"
materialDesign:TextFieldAssist.HasClearButton="True" Margin="5,5,5,10" />
</DockPanel>
</StackPanel>
</UserControl>
Loading

0 comments on commit 9f6cb03

Please sign in to comment.