Pregunta

Estoy tratando de leer la información fuera de una tarjeta inteligente, usando un contacto de la tarjeta menos OmniKey 5321 lector.

Editar . Ha añadido un botín

Estoy escribiendo un programa en C # 3 en .NET 3.5, por lo que esta es una aplicación de Windows.

La tarjeta tiene alguna información estampada en ella, que yo asumiría, de alguna manera, está presente en los datos de la tarjeta (hay una foto de la tarjeta y el lector a continuación.)

La tarjeta tiene la siguiente información estampada en él:

1* 00447   21091328-32

Cuando se utiliza la aplicación de diagnóstico que viene con el lector de tarjetas OmniKey, me da la siguiente información:

Smart Card Name: iCLASS 16KS UID:EE 74 0E 00 FB FF 12 E0
ATR            : 3B 8F 80 01 80 4F 0C A0 00 00 03 06 0A 00 1A 00 00 00 00 78
Protocol       : ISO 15693 (Part 2)

Ahora, aquí hay algunas conversiones he considerado:

  • 447 decimal = 1BF hexadecimal (no encontrado)
  • 447 octal = 295 decimal (no encontrado como de tipo codificación BCD)
  • 447 octal = 127 hexadecimal (no encontrado)
  • 447 hexadecimal no se encuentra

Aquí está mi pregunta:

  • Es el número "UID" un número único que puedo confiar? Realmente no importa el número 447, todo lo que hay que saber es que la información que recoger de esta tarjeta identificará de forma única más tarde, de modo que pueda vincularlo al titular de la tarjeta
  • ¿Cómo hago para leer el número de UID? Usando WINSCARD.DLL en Windows que se puede ver que consigo los datos "ATR", todas de un solo byte, pero el UID no es aparentemente presentes en esa parte.

Aquí está la foto, si eso te da ninguna información.

back lector OmniKey con la tarjeta

¿Fue útil?

Solución

Usted puede confiar en UID pero parece truncado en su caso:

UID:EE 74 0E 00 FB FF 12 E0

Uid son por lo general de 16 bytes de longitud.

Puede leer este Identificador único (UID): Todas las tarjetas inteligentes ISO compatibles se proporcionan con un número UID (similar a un número VIN de un vehículo). por fines de interoperabilidad, el UID de una tarjeta está abierta y disponible para ser leído por todos los lectores compatibles. Dado que este número único no está asegurada por las teclas, leyendo el UID de una tarjeta inteligente es comparable a la lectura de una tarjeta de proximidad, tarjeta de banda magnética o cualquier otra tecnología que utiliza los números abiertos, sin garantía.

http://www.xceedid.com/pdf/XC5937_Smart_whitepaper.pdf

Otros consejos

Hace poco pasar demasiadas horas en busca de un completa ejemplo de cómo sacar el ATR de tarjeta de proximidad y OMNIKEY ...

Ahora que tengo mi código de trabajo, me gustaría compartir para que otros puedan beneficiarse.

El mejor código que encontré fue de SpringCard. (Gracias!)

Otros ejemplos que encontré eran una pérdida de tiempo y engañosa, y no funcionó debido a que el DllImport estaba mal ...

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;

namespace Test
{
    public delegate void VoidDelegate();
    public delegate void CardPresented(string reader, byte[] cardData);

    public class ReaderList : IDisposable, IEnumerable<string>
    {
        public ReaderList()
        { }

        public void Dispose()
        {
            StopThread();
        }

        private Thread thread;
        private void StartThread()
        {
            if (thread != null)
                StopThread();

            thread = new Thread(Run);
            thread.IsBackground = true;
            bStopThread = false;
            thread.Start();
        }

        private void StopThread()
        {
            if (thread != null)
            {
                bStopThread = true;
                Thread.Sleep(50);
            }
            if (thread != null)
                thread.Abort();
            if (thread != null)
                thread.Join();
            thread = null;
        }

        private List<string> readerNames = new List<string>();
        private Dictionary<string, string> lastCardFound = new Dictionary<string, string>();
        public int ReaderCount
        { get { return readerNames.Count; } }

        public void Refresh()
        {
            if (thread == null)
                StartThread();
        }

        public event VoidDelegate ListChanged;
        public event CardPresented CardPresented;

        private bool bStopThread = true;
        private void Run()
        {
            IntPtr hContext = IntPtr.Zero;

            try
            {
                uint result = SCARD.EstablishContext(SCARD.SCOPE_SYSTEM, IntPtr.Zero, IntPtr.Zero, ref hContext);
                if (result != SCARD.S_SUCCESS)
                {
                    thread = null;
                    return;
                }

                uint notification_state = SCARD.STATE_UNAWARE;

                while (!bStopThread)    // loop 1 - build list, then iterate
                {
                    SCARD.ReaderState[] states = new SCARD.ReaderState[ReaderCount + 1];
                    states[0] = new SCARD.ReaderState(@"\\?PNP?\NOTIFICATION");
                    states[0].dwCurrentState = notification_state;

                    int iState = 0;
                    if (readerNames != null)
                        foreach (string s in readerNames)
                        {
                            iState++;
                            states[iState] = new SCARD.ReaderState(s);
                            states[iState].dwCurrentState = SCARD.STATE_UNAWARE;
                        }

                    while (!bStopThread)    // loop 2 - iterate over list built above
                    {
                        result = SCARD.GetStatusChange(hContext, 250, states, (uint)states.Length);
                        if (result == SCARD.E_TIMEOUT)
                            continue;
                        if (result != SCARD.S_SUCCESS)
                            break;

                        bool bReaderListChanged = false;
                        for (int i = 0; i < states.Length; i++)
                            if ((states[i].dwEventState & SCARD.STATE_CHANGED) != 0)
                                if (i == 0)
                                {
                                    // reader added or removed
                                    notification_state = states[0].dwEventState;

                                    // we want to replace the member in one step, rather than modifying it...
                                    List<string> tmp = GetReaderList(hContext, SCARD.GROUP_ALL_READERS);
                                    if (tmp == null)
                                        readerNames.Clear();
                                    else
                                        readerNames = tmp;

                                    if (ListChanged != null)
                                        ListChanged();
                                    bReaderListChanged = true;
                                }
                                else
                                {
                                    // card added or removed
                                    states[i].dwCurrentState = states[i].dwEventState;

                                    if ((states[i].dwEventState & SCARD.STATE_PRESENT) != 0)
                                    {
                                        byte[] cardData = new byte[states[i].cbATR];
                                        for (int j=0; j<cardData.Length; j++)
                                            cardData[j] = states[i].rgbATR[j];
                                        string thisCard = SCARD.ToHex(cardData, "");
                                        string lastCard;
                                        lastCardFound.TryGetValue(states[i].szReader, out lastCard);
                                        if (thisCard != lastCard)
                                        {
                                            lastCardFound[states[i].szReader] = thisCard;
                                            if (CardPresented != null)
                                                CardPresented(states[i].szReader, cardData);
                                        }
                                    }
                                    else
                                        lastCardFound[states[i].szReader] = "";                                        
                                }

                        if (bReaderListChanged)
                            break;  // break out of loop 2, and re-build our 'states' list

                    } // end loop 2
                } // end loop 1
            }
            catch (Exception ex)
            {
                //TODO: error logging
            }
            finally
            {
                if (hContext != IntPtr.Zero)
                    SCARD.ReleaseContext(hContext);
                thread = null;
            }
        }

        private List<string> GetReaderList(IntPtr hContext, string sGroup)
        {
            uint nStringLength = 0;
            uint result = SCARD.ListReaders(hContext, sGroup, null, ref nStringLength);
            if (result != SCARD.S_SUCCESS)
                return null;

            string sReaders = new string(' ', (int)nStringLength);
            result = SCARD.ListReaders(hContext, sGroup, sReaders, ref nStringLength);
            if (result != SCARD.S_SUCCESS)
                return null;
            List<string> list = new List<string> (sReaders.Split('\0'));
            for (int i = 0; i < list.Count; )
                if (list[i].Trim().Length > 0)
                    i++;
                else
                    list.RemoveAt(i);
            return list;
        }

        public IEnumerator<string> GetEnumerator()
        { return readerNames.GetEnumerator(); }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        { return readerNames.GetEnumerator(); }

    }

    public class SCARD
    {
        [DllImport("WinScard.dll", EntryPoint = "SCardEstablishContext")]
        public static extern uint EstablishContext(
            uint dwScope,
            IntPtr nNotUsed1,
            IntPtr nNotUsed2,
            ref IntPtr phContext);

        [DllImport("WinScard.dll", EntryPoint = "SCardReleaseContext")]
        public static extern uint ReleaseContext(
            IntPtr hContext);

        [DllImport("winscard.dll", EntryPoint = "SCardGetStatusChangeW", CharSet = CharSet.Unicode)]
        public static extern uint GetStatusChange(
            IntPtr hContext,
            uint dwTimeout,
            [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)]
                SCARD.ReaderState[] rgReaderState,
            uint cReaders);

        [DllImport("winscard.dll", EntryPoint = "SCardListReadersW", CharSet = CharSet.Unicode)]
        public static extern uint ListReaders(
            IntPtr hContext,
            string groups,
            string readers,
            ref uint size);

        #region Error codes
        public const uint S_SUCCESS = 0x00000000;
        public const uint F_INTERNAL_ERROR = 0x80100001;
        public const uint E_CANCELLED = 0x80100002;
        public const uint E_INVALID_HANDLE = 0x80100003;
        public const uint E_INVALID_PARAMETER = 0x80100004;
        public const uint E_INVALID_TARGET = 0x80100005;
        public const uint E_NO_MEMORY = 0x80100006;
        public const uint F_WAITED_TOO_LONG = 0x80100007;
        public const uint E_INSUFFICIENT_BUFFER = 0x80100008;
        public const uint E_UNKNOWN_READER = 0x80100009;
        public const uint E_TIMEOUT = 0x8010000A;
        public const uint E_SHARING_VIOLATION = 0x8010000B;
        public const uint E_NO_SMARTCARD = 0x8010000C;
        public const uint E_UNKNOWN_CARD = 0x8010000D;
        public const uint E_CANT_DISPOSE = 0x8010000E;
        public const uint E_PROTO_MISMATCH = 0x8010000F;
        public const uint E_NOT_READY = 0x80100010;
        public const uint E_INVALID_VALUE = 0x80100011;
        public const uint E_SYSTEM_CANCELLED = 0x80100012;
        public const uint F_COMM_ERROR = 0x80100013;
        public const uint F_UNKNOWN_ERROR = 0x80100014;
        public const uint E_INVALID_ATR = 0x80100015;
        public const uint E_NOT_TRANSACTED = 0x80100016;
        public const uint E_READER_UNAVAILABLE = 0x80100017;
        public const uint P_SHUTDOWN = 0x80100018;
        public const uint E_PCI_TOO_SMALL = 0x80100019;
        public const uint E_READER_UNSUPPORTED = 0x8010001A;
        public const uint E_DUPLICATE_READER = 0x8010001B;
        public const uint E_CARD_UNSUPPORTED = 0x8010001C;
        public const uint E_NO_SERVICE = 0x8010001D;
        public const uint E_SERVICE_STOPPED = 0x8010001E;
        public const uint E_UNEXPECTED = 0x8010001F;
        public const uint E_ICC_INSTALLATION = 0x80100020;
        public const uint E_ICC_CREATEORDER = 0x80100021;
        public const uint E_UNSUPPORTED_FEATURE = 0x80100022;
        public const uint E_DIR_NOT_FOUND = 0x80100023;
        public const uint E_FILE_NOT_FOUND = 0x80100024;
        public const uint E_NO_DIR = 0x80100025;
        public const uint E_NO_FILE = 0x80100026;
        public const uint E_NO_ACCESS = 0x80100027;
        public const uint E_WRITE_TOO_MANY = 0x80100028;
        public const uint E_BAD_SEEK = 0x80100029;
        public const uint E_INVALID_CHV = 0x8010002A;
        public const uint E_UNKNOWN_RES_MNG = 0x8010002B;
        public const uint E_NO_SUCH_CERTIFICATE = 0x8010002C;
        public const uint E_CERTIFICATE_UNAVAILABLE = 0x8010002D;
        public const uint E_NO_READERS_AVAILABLE = 0x8010002E;
        public const uint E_COMM_DATA_LOST = 0x8010002F;
        public const uint E_NO_KEY_CONTAINER = 0x80100030;
        public const uint W_UNSUPPORTED_CARD = 0x80100065;
        public const uint W_UNRESPONSIVE_CARD = 0x80100066;
        public const uint W_UNPOWERED_CARD = 0x80100067;
        public const uint W_RESET_CARD = 0x80100068;
        public const uint W_REMOVED_CARD = 0x80100069;
        public const uint W_SECURITY_VIOLATION = 0x8010006A;
        public const uint W_WRONG_CHV = 0x8010006B;
        public const uint W_CHV_BLOCKED = 0x8010006C;
        public const uint W_EOF = 0x8010006D;
        public const uint W_CANCELLED_BY_USER = 0x8010006E;
        public const uint W_CARD_NOT_AUTHENTICATED = 0x8010006F;
        #endregion

        public const uint SCOPE_USER = 0;
        public const uint SCOPE_TERMINAL = 1;
        public const uint SCOPE_SYSTEM = 2;

        public const string GROUP_ALL_READERS = "SCard$AllReaders\0\0";
        public const string GROUP_DEFAULT_READERS = "SCard$DefaultReaders\0\0";
        public const string GROUP_LOCAL_READERS = "SCard$LocalReaders\0\0";
        public const string GROUP_SYSTEM_READERS = "SCard$SystemReaders\0\0";

        public const uint STATE_UNAWARE = 0x00000000;
        public const uint STATE_IGNORE = 0x00000001;
        public const uint STATE_CHANGED = 0x00000002;
        public const uint STATE_UNKNOWN = 0x00000004;
        public const uint STATE_UNAVAILABLE = 0x00000008;
        public const uint STATE_EMPTY = 0x00000010;
        public const uint STATE_PRESENT = 0x00000020;
        public const uint STATE_ATRMATCH = 0x00000040;
        public const uint STATE_EXCLUSIVE = 0x00000080;
        public const uint STATE_INUSE = 0x00000100;
        public const uint STATE_MUTE = 0x00000200;
        public const uint STATE_UNPOWERED = 0x00000400;

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct ReaderState
        {
            public ReaderState(string sName)
            {
                szReader = sName;
                pvUserData = IntPtr.Zero;
                dwCurrentState = 0;
                dwEventState = 0;
                cbATR = 0;
                rgbATR = null;
            }

            internal string szReader;
            internal IntPtr pvUserData;
            internal uint dwCurrentState;
            internal uint dwEventState;
            internal uint cbATR;    // count of bytes in rgbATR
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x24, ArraySubType = UnmanagedType.U1)]
            internal byte[] rgbATR;
        }

        public static string ToHex(byte[] ab, string sDelim)
        {
            if (ab == null) return "<NULL>";
            return ToHex(ab, 0, ab.Length, sDelim);
        }

        public static string ToHex(byte[] ab, int offset, int len, string sDelim)
        {
            if (ab == null) return "<NULL>";
            StringBuilder sb = new StringBuilder();
            len = Math.Min(offset + len, ab.Length);
            for (int i = offset; i < len; i++)
                sb.Append(String.Format("{0:x02}", ab[i]).ToUpper() + sDelim);
            return sb.ToString();
        }

    }
}

UID se puede leer a través de PC / SC 2.01 llamada de función compatible contra winscard.dll. Para las tarjetas iCLASS es típicamente de 8 bytes de longitud. Otras tarjetas devuelven un UID 4 a 8 bytes (que actúa como un número de teléfono para identificar varias tarjetas en el campo y en última instancia, seleccione uno). La APDU se puede intercambiar a través de SCardTransmit() estándar con CLA=0xFF para indicar el acceso a la tarjeta de almacenamiento sin contacto.

Marc

http://www.smartcard-api.com

NOTA: El UID no refleja el número de la tarjeta impresa en la tarjeta. El número de tarjeta es parte de los datos Wiegand almacenados en la aplicación HID PAC de aplicación 1 en la página 0 de la tarjeta.

  1. identificador único (UID): Todas ISO-compatible tarjetas inteligentes están provistos de un número de UID (Similar a un número VIN en un vehículo). Fuente: http://www.accentalarms.com/specsheets/xceed/XceedIDSmartcardOverview.pdf
  2. Acerca de la lectura de UID: http://www.hidglobal.com/faqs.php ? techCat = 19 , parece mostrar cómo hacerlo.

Aunque el número UID es parte de la norma y la norma dice que debe ser único en el mundo que tiene que tener en cuenta que a menudo hay fabricantes que producen tarjetas no conformes (pero que trabajan).

Conclusión:. En tanto no se pone algo único en la tarjeta no se puede estar seguro de que el enlace de tarjeta a un dueño de la tarjeta es satisfecha

El ATR ( A espuesta T o R eset) de una tarjeta sólo indica lo que el formato de la tarjeta es, el protocolo, y las sumas de comprobación de esos datos. Ver ATR de análisis en línea

Ahora usted sabe lo que la tarjeta es usted entonces tiene que aplicar el apropiado (RS232 / RS485 / ZPL II / APDU - Tarjeta inteligente plicación P rotocolo D ATA u nit como se define en ISO / IEC 7816-4) comandos para obtener el UID (dependiendo de si se trata de cascada de 1, 2 o 3, ver ACG HF Multi ISO Lector RFID v1.0 página 50 aka Omnikey5553 RS232) - 14443 es de hasta 14 bytes de longitud, ocupando los dos primeros bloques en el primer sector de byte 16 (sector 0), y tiene incrustados sumas de comprobación. (Ver los protocolos ISO14443 o la página de especificaciones NXP Semiconductors MF1ICS50 8).

En 15693, los / RS485 comandos RS232 devolverá un total de UID 16 bytes en (S) elegir (Omnikey5553 RS232 y USB), pero en la APDU sólo devolverá los últimos 8 bytes (0xFF 0xCA 0x00 0x00 0x00 en un Omnikey5022) a pesar siendo la norma, como para el 15693 la tarjeta sólo responde con 8 bytes a la vez. Por 14443 se puede leer un sector a la vez (32 bytes de 4 bloques de 8 bytes, ingresando en el sector antes de la lectura / escritura para el S50) pero por 15693 sólo puede leer / escribir un bloque de 8 bytes a la vez , y tiene otros datos en el búfer devuelto. Tienes que el código sea que 'bloquear' los datos a 32 o en 8. Se trata de utilizar el protocolo de tarjetas inteligentes SCardTransmit estándar para la API de Windows. Como la aplicación de diagnóstico ha vuelto 16 bytes, que es la UID de la tarjeta. Además, algunos decoro 15693 uso la clave invertida 14.443 a ofuscar y prevenir la modificación, otros tienen una micro-programa que realiza la validación -. Ya sea en la PC o en la propia tarjeta

En todos los casos, esto no tiene relación con lo que está impreso en la tarjeta - utilizamos códigos de barras impresos en CODE128C EV1 tarjetas de plástico que contienen un GUID que a su vez se refiere a la UID correspondiente en una base de datos para las transacciones. Otros (como Wiegand, etc) se imprimen otros datos tales como códigos de área, el juego de llaves, etc.

Otros problemas se producen cuando se intenta escribir datos al 15693 - Asegúrese de que terminan sus datos en la interfaz 4 Char más tiene problemas con los datos anteriores cuando se intenta escribir un nulo '0x00' más de un carácter existente en una bloquear - lo que el código para el cinturón, tirantes y un trozo de cuerda después de la actualización / escribir en una tarjeta para asegurarse de que los datos son según sea necesario. Si todo el bloque es de 'nulo de, no hay problema, ya que los datos se escriben como un bloque de 4 caracteres. NO en blanco del área usuario de la tarjeta de forma innecesaria, ya que se basan NAND y tienen escrituras finitos. (Después de lectura y escritura de la tarjeta de nuevo para asegurar que los datos escritos es como está escrito!)

El UID debe ser único dentro del conjunto de expedición de la tarjeta, sino que también depende de la orden de la cantidad de tarjetas que se trate - por lo que el número de serie ha sido ampliada 2 veces (el número de cascada) y por primera vez se debe moderar su confianza en el UID de un teléfono de Apple, ya que viola la U en UID -. se puede configurar para emular otra UID

NDEF es otro aspecto de las tarjetas que debe ser entendido -. Que está bien explicado en las normas NFC NDEF, pero tenga cuidado con las áreas OTP y de LOCK de 14443, ya que son de un solo sentido, una vez conjunto

Siempre se puede utilizar un teléfono Android con NFC y la aplicación para verificar tagdata.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top