public void Personalise(uint esn, string pin, PACSAMKeyFile keys) { /* * Input validation */ // Validate the ESN if (esn == 0) { throw new ArgumentException("The ESN must not be zero"); } // Validate the PIN if (String.IsNullOrEmpty(pin)) { throw new ArgumentException("The PIN must not be empty"); } // Trim the PIN pin = pin.Trim(); // Validate the PIN (Numeric check) if (!pin.All(Char.IsDigit)) { throw new ArgumentException("The PIN must be numeric"); } // Validate the PIN length if (pin.Length != PinLength) { throw new ArgumentException($"The PIN must be {PinLength} digits in length exactly"); } // Validate the key record file if (keys == null) { throw new ArgumentException("The key container is empty"); } // Validate the key integrity foreach (PACSAMKeyRecord r in keys.Records) { if (!r.VerifyHash()) { throw new InvalidDataException(string.Format("The key record '{0}' failed it's hash check")); } } /* * Personalisation steps * * NOTE: * We don't check whether this PACSAM instance is actually in the correct state to personalise. * We just try it and if it fails it fails. */ // Select the PACSAM Application try { SelectApplication(); } catch (Exception ex) { throw new InvalidOperationException("The call to SelectApplication failed", ex); } // Validate the PACSAM is in the SELECTABLE state try { var status = GetStatus(); if (status.AppletState != PACSAMAppletState.Selectable) { throw new InvalidOperationException("This PACSAM instance is not in the SELECTABLE state"); } } catch (Exception ex) { throw new InvalidOperationException("The call to GetStatus failed", ex); } // Set the ESN try { SetData(SetDataElement.ESN, BinaryParser.ConvertUInt32(esn, ByteEndianess.BigEndian)); } catch (Exception ex) { throw new InvalidOperationException("The call to SET DATA failed (esn)", ex); } // Set the PIN try { byte[] pinData = ASCIIEncoding.ASCII.GetBytes(pin); SetData(SetDataElement.PIN, pinData); } catch (Exception ex) { throw new InvalidOperationException("The call to SET DATA failed (PIN)", ex); } // Set the Profile Identifier try { SetData(SetDataElement.Profile, keys.IdBytes); } catch (Exception ex) { throw new InvalidOperationException("The call to SET DATA failed (Profile Identifier)", ex); } // Set the System Diversifier try { SetData(SetDataElement.SystemDiversifier, keys.SystemDiversifier); } catch (Exception ex) { throw new InvalidOperationException("The call to SET DATA failed (System Diversifier)", ex); } // Write the keys foreach (PACSAMKeyRecord r in keys.Records) { // TDEA2KEY if (typeof(PACSAMTDEA2KeyRecord).IsAssignableFrom(r.GetType())) { LoadKey(PACSAMKeyType.DES, 0, r.PackRecord()); } // AES128 else if (typeof(PACSAMAES128KeyRecord).IsAssignableFrom(r.GetType())) { LoadKey(PACSAMKeyType.AES, 0, r.PackRecord()); } // PLAID else if (typeof(PACSAMPlaidKeyRecord).IsAssignableFrom(r.GetType())) { LoadKey(PACSAMKeyType.PLAID, PACSAMPlaidKeyRecord.IAKeyPElement, r.PackRecord("IAKEY_P")); LoadKey(PACSAMKeyType.PLAID, PACSAMPlaidKeyRecord.IAKeyQElement, r.PackRecord("IAKEY_Q")); LoadKey(PACSAMKeyType.PLAID, PACSAMPlaidKeyRecord.IAKeyPQElement, r.PackRecord("IAKEY_PQ")); LoadKey(PACSAMKeyType.PLAID, PACSAMPlaidKeyRecord.IAKeyDPElement, r.PackRecord("IAKEY_DP")); LoadKey(PACSAMKeyType.PLAID, PACSAMPlaidKeyRecord.IAKeyDQElement, r.PackRecord("IAKEY_DQ")); LoadKey(PACSAMKeyType.PLAID, PACSAMPlaidKeyRecord.IAKeyModulusElement, r.PackRecord("IAKEY_MODULUS")); LoadKey(PACSAMKeyType.PLAID, PACSAMPlaidKeyRecord.IAKeyExponentElement, r.PackRecord("IAKEY_EXPONENT")); LoadKey(PACSAMKeyType.PLAID, PACSAMPlaidKeyRecord.FAKeyElement, r.PackRecord("FAKEY")); } } // Activate this PACSAM instance Activate(); }