/// <summary> /// This method performs the full PLAID authentication sequence, given a valid, selected PLAID SAM /// and a collection of keysets /// </summary> /// <param name="sam">The instance of a PLAID SAM</param> /// <param name="keysets">The collection of keyset identifiers to request</param> /// <param name="opMode">The requested opMode</param> /// <returns>The ACSRecord associated with the requested OpMode</returns> public byte[] Authenticate(IPlaidSAM sam, KeysetList keysets, short samId, short opMode) { // Initial Authenticate #if PLAIDEXPLICITSELECT SelectApplication(); #endif byte[] estr1 = InitialAuthenticate(keysets); #if PLAIDEXPLICITSELECT sam.SelectApplication(); // REMOVE #endif byte[] estr2 = sam.InitialAuthenticate(samId, estr1, opMode); // Final Authenticate #if PLAIDEXPLICITSELECT SelectApplication(); #endif byte[] estr3 = FinalAuthenticate(estr2); #if PLAIDEXPLICITSELECT sam.SelectApplication(); // REMOVE #endif return(sam.FinalAuthenticate(estr3)); }
public void Personalise(IPlaidSAM sam, PlaidTemplate template, Dictionary <string, byte[]> parameters = null) { SelectApplication(); // Validate the PLAID applet status is STATE_SELECTABLE var status = GetStatus(); if (status.AppletState != PlaidAppletState.Selectable) { RaiseOnMessage(@"PLAID: Already personalised (performing factory reset)"); // During debugging, perform a factory reset if (status.AppletState == PlaidAppletState.Terminated) { throw new ApplicationException(@"Invalid applet state for factory reset"); } // Authenticate using the administrative key var adminKeyset = template.Keysets.First(x => x.Id == PlaidApplication.KEYSET_ADMIN); Authenticate(sam, adminKeyset.Id, adminKeyset.SamId, 0); // Perform a FACTORY_RESET command { var request = new FactoryResetRequest(); #if PLAIDEXPLICITSELECT sam.SelectApplication(); #endif byte[] cryptogram = sam.SetData(request.Encode()); #if PLAIDEXPLICITSELECT SelectApplication(); #endif SetData(cryptogram); } } // Retrieve and load the FA KEY cryptogram RaiseOnMessage(@"PLAID: Retrieving transport cryptogram"); byte[] faKey = GetData(0x00); #if PLAIDEXPLICITSELECT sam.SelectApplication(); #endif sam.LoadFAKey(template.TransportKey.SamId, faKey); // Authenticate using the TransportKey key // NOTE: We don't care which OpMode we request since this is an administrative authentication RaiseOnMessage(@"PLAID: Authenticating with transport admin keyset"); byte[] acsRecord = Authenticate(sam, template.TransportKey.Id, template.TransportKey.SamId, 0); // Load all ACSRecords foreach (var record in template.ACSRecords) { // Create the request object var request = new AcsrCreateRequest(); request.Id = record.OpModeId; if (record.IsTemplate()) { request.Data = parameters[record.Data]; } else { request.Data = record.DataToArray(); } RaiseOnMessage($"PLAID: Writing ACSRecord {request.Id} ({request.Data.ToHexString()})"); // Generate the cryptogram #if PLAIDEXPLICITSELECT sam.SelectApplication(); #endif byte[] cryptogram = sam.SetData(request.Encode()); // Transmit to the ICC #if PLAIDEXPLICITSELECT SelectApplication(); #endif SetData(cryptogram); } // Load all Keysets in descending order so that KEYSET_ADMIN is last foreach (var keyset in template.Keysets.OrderByDescending(x => x.Id)) { // Create the request object var request = new KeyCreateRequest(); request.Id = keyset.Id; request.SamId = keyset.SamId; foreach (var rule in keyset.AccessRules) { request.Rules.Add(rule); } // Generate the cryptogram #if PLAIDEXPLICITSELECT sam.SelectApplication(); #endif RaiseOnMessage($"PLAID: Loading keyset {keyset.Id:X4}"); byte[] cryptogram = sam.SetData(request.Encode()); // Transmit to the ICC #if PLAIDEXPLICITSELECT SelectApplication(); #endif SetData(cryptogram); } // Re-authenticate with the Administrative key // NOTE: We don't care which OpMode we request since this is an administrative authentication RaiseOnMessage(@"PLAID: Authenticating with admin keyset"); Authenticate(sam, template.AdminKey.Id, template.AdminKey.SamId, 0); // Activate the instance { RaiseOnMessage(@"PLAID: Updating applet state to PERSONALISED"); var request = new ActivateRequest(); #if PLAIDEXPLICITSELECT sam.SelectApplication(); #endif byte[] cryptogram = sam.SetData(request.Encode()); #if PLAIDEXPLICITSELECT SelectApplication(); #endif SetData(cryptogram); } // If required, Block the instance if (template.Blocked) { RaiseOnMessage(@"PLAID: Updating applet state to BLOCKED"); var request = new BlockRequest(); #if PLAIDEXPLICITSELECT sam.SelectApplication(); #endif byte[] cryptogram = sam.SetData(request.Encode()); #if PLAIDEXPLICITSELECT SelectApplication(); #endif SetData(cryptogram); } // Done! }