internal byte[] RunGsmAlgo(byte[] rand) { if (!aSim.SelectDFTelecom()) { MessageBox.Show("Error reading GSM SIM card!"); _DisposeSim(aSim); aSim = null; return(null); } CardResponseAPDU sres = aSim.RunGsmAlgo(rand); if (sres != null && sres.GetData() != null) { txtLog.AppendText("SRES resp " + CardHex.FromByteArray(rand) + "[" + rand.Length + "] -> " + CardHex.FromByteArray(sres.GetData()) + Environment.NewLine); return(sres.GetData()); } txtLog.AppendText("SRES fail " + CardHex.FromByteArray(rand) + "[" + rand.Length + "] -> <failed> " + CardHex.FromByte(sres.SW1) + " " + CardHex.FromByte(sres.SW2) + Environment.NewLine); return(null); }
/// <summary> /// /// </summary> /// <param name="aCardSlot"></param> public void AnalyzeCard(CardTerminalSlot aCardSlot) { // Acquire any processor card (T=0 or T=1) that may be present in the given card // terminal slot string readerName = aCardSlot.CardTerminalName; CardActivationResult nActivationResult; DisplayText("Reader Name: " + readerName); //aCardSlot.CardTerminal.Config CardHandle aCard = aCardSlot.AcquireCard((CardTypes.T0 | CardTypes.T1), out nActivationResult); if (nActivationResult != CardActivationResult.Success) { Debug.Assert(aCard == null); switch (nActivationResult) { case CardActivationResult.NoCard: m_aPromptLabel.Text = readerName + ": Please insert card ..."; break; case CardActivationResult.UnresponsiveCard: m_aPromptLabel.Text = readerName + ": Unresponsive card."; break; case CardActivationResult.InUse: m_aPromptLabel.Text = readerName + ": Card in use"; break; default: m_aPromptLabel.Text = readerName + ": Can't power up card!"; break; } return; } m_aPromptLabel.Text = aCardSlot.CardTerminalName + ": Found card"; DisplayText("Found card in reader " + aCardSlot.CardTerminalName); DisplayReaderProperties(aCardSlot); aCardSlot.BeginTransaction(); try // We are doing a few things here that any card system should support. // Note that the CardHandle represents the combination of card terminal and // powered-up card. { // =========================== ATR DETECTION ====================================== // Every card accessed through PC/SC must return an Answer To Reset (ATR). // So let's see what we've got here. byte[] atr = aCard.GetATR(); if (atr.Length == 0) { throw new Exception("Invalid ATR"); } DisplayText("ATR: " + CardHex.FromByteArray(atr, 0, atr.Length)); // ================================================================================ // Go a little deeper: is this a contact or contactless card system we are dealing with? CardHelper cardHelper = new CardHelper(aCard); DisplayText(cardHelper.cardInfo); if (cardHelper.isContactless) { // =========================== APDU EXCHANGE ================================== // Now we can try to get a unique identifier (UID). Any contactless card with a // PC/C 2.01 compliant card reader should be able to generate a UID. But never mind, // even if this fails it still shows how to create a command APDU with our SmartCardAPI // frameqwork and get a response APDU back from a card. // // Known issues: // SendCommand with CLA=0xFF can cause an exception with some smart card systems, // triggered by an "Unknown Error" (-2146435025) on PC/SC level. // Therefore this code should only be run if we are accessing a contactless reader // interface that is PC/SC 2.01 compliant // ============================================================================ byte CL_CLA = 0xFF; byte CL_INS_GET_UID = 0xCA; byte P1 = 0; byte P2 = 0; CardCommandAPDU aCmdAPDU = new CardCommandAPDU(CL_CLA, CL_INS_GET_UID, P1, P2, 256); CardResponseAPDU aRespAPDU; aRespAPDU = aCard.SendCommand(aCmdAPDU); if (!aRespAPDU.IsSuccessful) { DisplayText("WARNING: can't get a UID - this might be a contact card."); } else { byte[] uidWithSw12 = aRespAPDU.GenerateBytes(); if (uidWithSw12.Length < 2) { throw new Exception("Invalid UID"); } var uid = CardHex.FromByteArray(uidWithSw12, 0, uidWithSw12.Length - 2); DisplayText("UID: " + uid); if (uid.Length > 0) { _reader.SendRFID(uid); } } } aCardSlot.EndTransaction(); } catch (Exception x) { Trace.WriteLine(x.ToString()); DisplayText(x.ToString()); m_aPromptLabel.Text = "Card access error"; } finally { aCard.Dispose(); // release card handle } }
private void btnReadDetails_Click(object sender, System.EventArgs e) { if (aSim == null) { aSim = _ObtainSim(); if (aSim == null) { return; } } try { byte[] data = aSim.ReadIccIdentification(); if (data == null) { MessageBox.Show("Error reading GSM SIM card!"); _DisposeSim(aSim); aSim = null; return; } txtLog.AppendText("ICCID: " + CardHex.FromByteArray(data) + Environment.NewLine); /* check access to SIM card. fails if CHV required */ if (aSim.ReadImsi() == null) { CardResponseAPDU aRespAPDU = aSim.VerifyChv(this, m_aCardForm, "PIN Verification", "In order to access your SIM the PIN is required."); if (aRespAPDU == null) { // The PIN entry has been cancelled by the user. _DisposeSim(aSim); aSim = null; return; } if (!aRespAPDU.IsSuccessful) { string sHeading = "Failed to verify PIN!"; switch (aRespAPDU.SW) { case 0x9804: m_aCardForm.Notify(this, MessageBoxIcon.Warning, sHeading, "Wrong PIN!"); break; case 0x9840: m_aCardForm.Notify(this, MessageBoxIcon.Warning, sHeading, "Wrong PIN! The SIM has been blocked."); break; case 0x9808: m_aCardForm.Notify(this, MessageBoxIcon.Warning, sHeading, "The SIM is blocked. Please use mobile phone " + "in order to unblock the SIM with the PUK."); break; default: m_aCardForm.Notify(this, MessageBoxIcon.Warning, sHeading, "Unknown reason: (" + aRespAPDU.SW + ")"); break; } _DisposeSim(aSim); aSim = null; return; } } data = aSim.ReadImsi(); if (data == null) { MessageBox.Show("Error reading IMSI!"); _DisposeSim(aSim); aSim = null; return; } txtLog.AppendText("IMSI: " + CardHex.FromByteArray(data) + Environment.NewLine); if (!aSim.SelectDFTelecom()) { MessageBox.Show("Error selecting GSM file!"); _DisposeSim(aSim); aSim = null; return; } byte[] rand = CardHex.ToByteArray(txtRand.Text); byte[] resp = RunGsmAlgo(rand); /**/ } catch (Exception) { _DisposeSim(aSim); aSim = null; } }