.net - Determine Facility Code and Card Number from ATR in C# -
i have following card reader hid omnikey 5325. have contact-less card named proximity.
the number written on card 133593 42101044091-3.
by reading card, following atr hex: 3b050002f10673
using folowing applications have managed see following information.
i need extract facility code , code number in order identify card.
i have managed find following code, missing few pieces:
/// <summary> /// extract data item wiegand raw data. data item card /// number or facility code. /// </summary> /// <param name="format"></param> /// <param name="identifier"></param> /// <returns></returns> public int getdata(int format, int identifier) { int byteoffset = 0; if (m_rawwieganddata == null) { throw new exception("no raw wiegand data available"); } //self-test byte[] testdata_h10301 = {0x02,0x02,0x00,0x7a}; //cn=61, fc=1 byteoffset = 0; int bitoffset = 1; // starting count right int numberofbits = 16; int cn_h10301 = cardhex.frombytearray(testdata_h10301, byteoffset, bitoffset, numberofbits); if (cn_h10301 != 61) throw new exception("cardhex::fromarray(): system integrity error."); if (format == pacsdataformat.hid_h10301 && identifier == pacsdataidentifier.card_number) return cardhex.frombytearray(m_rawwieganddata, byteoffset, 1, 16); //if (format == pacsdataformat.hid_h10301 && identifier == pacsdataidentifier.card_number) return cardhex.frombytearray(m_rawwieganddata, byteoffset, 15, 16); //assuming 4-byte input, 6 leading 0 bits if (format == pacsdataformat.hid_h10301 && identifier == pacsdataidentifier.facility_code) return cardhex.frombytearray(m_rawwieganddata, byteoffset, 17, 8); //if (format == pacsdataformat.hid_h10301 && identifier == pacsdataidentifier.facility_code) return cardhex.frombytearray(m_rawwieganddata, byteoffset, 1, 8); if (format == pacsdataformat.hid_h10302 && identifier == pacsdataidentifier.card_number) return cardhex.frombytearray(m_rawwieganddata, byteoffset, 1, 24); if (format == pacsdataformat.hid_h10304 && identifier == pacsdataidentifier.card_number) return cardhex.frombytearray(m_rawwieganddata, byteoffset, 1, 19); if (format == pacsdataformat.hid_h10304 && identifier == pacsdataidentifier.facility_code) return cardhex.frombytearray(m_rawwieganddata, byteoffset, 20, 16); if (format == pacsdataformat.hid_h10320 && identifier == pacsdataidentifier.card_number) { long result = 0; // convert bcd encoded raw wiegand skipping least significant nibble //todo: create new method in cardhex convert bcd int (int k = 0; k < m_rawwieganddata.length; k++) { int high = (int)(m_rawwieganddata[k] >> 4); int low = (int)(m_rawwieganddata[k] & 0x0f); result *= 10; result += high; if (k < m_rawwieganddata.length - 1) // skip last digit i.e. nibble { result *= 10; result += low; } } return (int)result; } // h10320 cn=12345678 dec= 101111000110000101001110 // atr_hist(5125)=100100011010001010110011110001100 // h10320 cn=1 dec = 1 // atr_hist(5125)=10101 // h10320 cn=99999999 dec = 101111101011110000011111111 1 // atr_hist(5125)=100110011001100110011001100110010100 if (format == pacsdataformat.hid_corp1000 && identifier == pacsdataidentifier.card_number) return cardhex.frombytearray(m_rawwieganddata, byteoffset, 1, 20); if (format == pacsdataformat.hid_corp1000 && identifier == pacsdataidentifier.facility_code) return cardhex.frombytearray(m_rawwieganddata, byteoffset, 21, 12); return 0; } public static class pacsdataformat { public const int unknown = 0; public const int hid_h10301 = 1; // 26-bit, fac,cn public const int hid_h10302 = 2; // 37-bit, cn public const int hid_h10304 = 3; public const int hid_h10320 = 4; // 32-bit, clock-and-data card; cn bcd encoded public const int hid_corp1000 = 5; // 35-bit, cic,cn public const int indala_flexpass26 = 6; // 26-bit, fac,cn } public static class pacsdataidentifier { public const int unknown = 0; public const int weigand_raw = 1; // raw weigand data public const int card_number = 2; // card number printed on card public const int facility_code = 3; // facility code public const int cic = 4; // cic }
i can't figure out frombytearray function. have found description here on page 69: http://www.intraproc.com/downloads/fargo/hdp5000%20old/omnikey%20cardman%205121/manuals/ok_contactless_developer_guide_an_en.pdf
edit: solution have created frombytearray function goes code @chris haas
/// call example: frombytearray(atrbytearray, byteoffset: 0, int bitoffset: 1, int numberofbits: 16) /// call example: frombytearray(atrbytearray, byteoffset: 0, int bitoffset: 17, int numberofbits: 8) public static long frombytearray(byte[] atrbytearray, int byteoffset, int bitoffset, int numberofbits) { var hexstring = bytearraytostring(atrbytearray); var start_number = int64.parse( hexstring, numberstyles.hexnumber ); int64 a_26_only = start_number & 0x3ffffff; //26 bits, 11 1111 1111 1111 1111 1111 1111 int64 result = (a_26_only >> bitoffset) & (long)(math.pow(2,numberofbits)-1); return result; } public static string bytearraytostring(byte[] ba) { stringbuilder hex = new stringbuilder(ba.length * 2); foreach (byte b in ba) hex.appendformat("{0:x2}", b); return hex.tostring(); }
and usage:
byte[] atrbytearray = new byte[] {59, 5, 0, 2 , 241, 6, 115}; var cardnumber = frombytearray(atrbytearray, 0, 1, 16); var facilitycode = frombytearray(atrbytearray, 0, 17, 8); console.writeline(string.format("card number is: {0} , facility code is: {1}", cardnumber, facilitycode));
i'm not sure full-length number 3b050002f10673
but, per spec, you're interested in right-most 26 bits of it.
int64 start = 0x3b050002f10673; int64 a_26_only = start & 0x3ffffff; //26 bits, 11 1111 1111 1111 1111 1111 1111
then, per spec, right-most bit parity bit, after checking can discard it:
int64 a_without_parity = a_26_only >> 1;
finally, card number right-most 16 bits:
int64 card_number = a_without_parity & 0xffff;
and facility code next 8 bits:
int64 facility_code = (a_without_parity >> 16 ) & 0xff;
Comments
Post a Comment