Showing posts with label smartcards. Show all posts
Showing posts with label smartcards. Show all posts

Wednesday, July 22, 2009

Mifare 1K Memory Structure

To complete the task I'm working on and read/write to smart cards, I had to understand the memory structure of the Mifare Standard 1K card. This was no easy task for a weak and small brain of mine! I figured it out finally and here is a very short summary of my understanding:

The total memory of 1024 bytes is divided into 16 sectors of 64 bytes, each of the sectors is divided into 4 blocks of 16 bytes. Blocks 0, 1 and 2 of each sector can store data and block 3 is used to store keys and access bits (the exception is the ‘Manufacturer Block’ which can not store data).

The data in any sector can be protected by either Key A or both Key A and Key B security keys. I do not need to use Key B, and in this case the bytes in the trailer can be used for data. If the sector is protected by the security key, this key has to be loaded before data can be accessed by using a special command.

Access bits define the way the data in the sector trailer and the data blocks can be accessed. Access bits are stored twice – inverted and non-inverted in the sector trailer as shown in the images.

Some examples:

Data stored in the sector trailer:
01 02 03 04 05 06 FF 07 80 69 11 12 13 14 15 16
01 02 03 04 05 06 – Key A
FF 07 80 69 – Access bits
11 12 13 14 15 16 – Key B (or data if Key B is not used)

Bytes 6, 7, 8 are access data
FF 07 80

Binary representation:
11111111 = FF
00000111 = 07
10000000 = 80

The bits that are bolded and underscored are the ones that define access to keys (C13, C23, C33 in the image above) and they form the 001 sequence. The bits that are bolded and not underscored are the same bits inverted. They form, as expected, the sequence 110.

From the table above I can see that 001 means that Key A can not be read, but can be written and Key B may be read. This is the "transport configuration" and was read from the card that was never used.

A bit more on Mifare 1K commands next time.

by . Also posted on my website

Sunday, July 19, 2009

Smart Cards Do Not Hurt Anymore

Ah, the great mystery of talking to the smart card is solved. The tool that helped me to do it is called CHIPDRIVE Smartcard Commander. It is a free tool and can easily be found, downloaded and installed.

When I positioned the card in the reader and started the Smartcard Commander, I could immediately see that it knows a lot of stuff about the card.

But what's more important, it has some sample scripts that can be loaded when I select "CPU Card" from the System tree and use the Load Script button. The sample script shows me how to construct commands that can be send to the card, I can also run them immediately and see the results.

I only need to send the proper commands now...

by . Also posted on my website

Friday, July 17, 2009

Smart Cards Hurt - 3

Resolved the problem with the Smart Card reader. After everything else failed, I tried installing the pritner and reader on the clean PC. Surprisingly, it worked. Then I tried uninstalling all drivers from my PC, restarting and reinstalling again. Unsurprisingly, it did not work (I tried doing this before).

Next thing, I decided to compare the driver versions between my PC and clean PC. And here it was - my driver said "SCM Microsystems 4.35.00.01" and the one on the clean PC said "SCM Microsystems 5.15". And, of course, the S331DICL.sys files had different dates. So, I copied the S331DICL.sys and installed the drivers again. That did not quite help though, the driver version was now the proper one, but the device version itself was not.

Why are the versions different? Only when I searched for S331DICL.sys on the whole computer I could figure out what was the most likely reason for my problem - looks like the old the driver version was installed by the 3M scanner installer. I found the old S331DICL.sys in one of the subfolders under its Program Files folder. Now, when I was installing the driver, it remembered the location and used the old file that came with the 3M scanner. So I uninstalled the 3M application, made sure that the S331DICL.sys file is deleted completely from my computer, copied over the new version and pointed to the new version of S331DICL.sys file when installing the smart card drivers. Now it finally worked.

Next thing is to actually implement communication to the smart card ...

by . Also posted on my website

Friday, July 10, 2009

Smart Cards Hurt - 2

Now, the slightly harder part is communicating with the Smart Card reader. Most, if not all, of the functionality resides within the winscard.dll. For functions reference, this MSDN page could be a start.

Smart Card Functions

I also found a nice example using google code search which resides here

ACR120Driver.cs

and using this code as a template, I used the following code to test the functionality of my SCM reader.

long retCode;
int hContext = 0;
int ReaderCount = 0;
int Protocol = 0;
int hCard = 0;
string defaultReader = null;
int SendLen, RecvLen;

byte[] SendBuff = new byte[262];
byte[] RecvBuff = new byte[262];

ModWinsCard.SCARD_IO_REQUEST ioRequest;

retCode = ModWinsCard.SCardEstablishContext(ModWinsCard.SCARD_SCOPE_USER, 0, 0, ref hContext);
if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
System.Diagnostics.Debug.WriteLine(ModWinsCard.GetScardErrMsg(retCode));
}

retCode = ModWinsCard.SCardListReaders(hContext, null, null, ref ReaderCount);

if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
System.Diagnostics.Debug.WriteLine(ModWinsCard.GetScardErrMsg(retCode));
}

byte[] retData = new byte[ReaderCount];
byte[] sReaderGroup = new byte[0];

//Get the list of reader present again but this time add sReaderGroup, retData as 2rd & 3rd parameter respectively.
retCode = ModWinsCard.SCardListReaders(hContext, sReaderGroup, retData, ref ReaderCount);

if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
System.Diagnostics.Debug.WriteLine(ModWinsCard.GetScardErrMsg(retCode));
}

//Convert retData(Hexadecimal) value to String
string readerStr = System.Text.ASCIIEncoding.ASCII.GetString(retData);
string[] rList = readerStr.Split('\0');

foreach (string readerName in rList)
{
if (readerName != null && readerName.Length > 1)
{
defaultReader = readerName;
break;
}
}

if (defaultReader != null)
{
retCode = ModWinsCard.SCardConnect(hContext, defaultReader, ModWinsCard.SCARD_SHARE_DIRECT,
ModWinsCard.SCARD_PROTOCOL_UNDEFINED, ref hCard, ref Protocol);
//Check if it connects successfully
if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
string error = ModWinsCard.GetScardErrMsg(retCode);
}
else
{
int pcchReaderLen = 256;
int state = 0;
byte atr = 0;
int atrLen = 255;

//get card status
retCode = ModWinsCard.SCardStatus(hCard, defaultReader, ref pcchReaderLen, ref state, ref Protocol, ref atr, ref atrLen);

if (retCode != ModWinsCard.SCARD_S_SUCCESS)
{
return;
}

//read/write data etc.

.....
}
}

ModWinsCard.cs is, again, a wrapper for the winscard.dll functions, data structures, and declares all required constants.

Anyway, this code actually worked fine, except one little detail - the state variable that gets returned by the SCardStatus returned the value of 2. And the possible values are explained here:

SCardStatus

"2" is SCARD_PRESENT, which means "A card is present in the card reader, but it is not in position for use". A better result would be something like SCARD_NEGOTIABLE which is "The card has been reset and is waiting for protocol negotiation".

Also, using SCardConnect with preferred protocol set to T0 or T1 returned SCARD_W_UNRESPONSIVE_CARD error.

Now this is the point where I had to consult with the printer manufacturer because there's a number of possible reasons for the errors - hardware, firmware, drivers or incompatible card. Work still in progress.

by . Also posted on my website

Tuesday, July 7, 2009

Smart Cards Hurt - 1

So here's the new toy I've got to play with - the DataCard CP40 Plus card printer with the SCM SCR331-DI Smart Card reader.

Datacard CP40 Plus

Developing the application for the printer consists mostly of two parts - communicating with the printer and communicating with the smart card reader. You tell the printer to pick up the card, you tell the printer to position the card for smart card processing, you tell the smart card reader to write data to the smart card, you tell the printer to encode the magstripe and print something on the card, you tell the printer to finish with the print job.

It does not look so easy when you read the manual. This is how the programming flow looks like:

In reality, though, the whole printer communication is mostly done by the following code:

printer.Hdc = PrintDoc.PrinterSettings.CreateMeasurementGraphics().GetHdc().ToInt32();

/* Set Interactive mode */
if (ICE_API.SetInteractiveMode(printer.Hdc, true) > 0)
{
ICE_API.DOCINFO di = new ICE_API.DOCINFO();
/* Initialize DOCINFO */
di.cbSize = 16;
di.lpszDocName = "Card Printer SDK Test";
di.lpszDataType = string.Empty;
di.lpszOutput = string.Empty;

/* Start document and page */
if (ICE_API.StartDoc(printer.Hdc, ref di) > 0)
{
if (ICE_API.StartPage(printer.Hdc) > 0)
{
/* Set card rotation on */
ICE_API.RotateCardSide(printer.Hdc, 1);
/* Feed the card into the smart card reader */
if (ICE_API.FeedCard(printer.Hdc, ICE_API.ICE_SMARTCARD_FRONT + ICE_API.ICE_GRAPHICS_FRONT) > 0)
{
/* Put any SmartCard processing/communication here */
TalkToSmartCard();
}
/* Remove the card from the reader and continue printing */
ICE_API.SmartCardContinue(printer.Hdc, ICE_API.ICE_SMART_CARD_GOOD);
/* End the page */
ICE_API.EndPage(printer.Hdc);
}
/* End job */
ICE_API.EndDoc(printer.Hdc);
}
}

The ICE_API mostly contains wrappings for the functions from the ICE_API.dll which comes with the printer and defines some constants and data structures, like this

[StructLayout(LayoutKind.Sequential)]
public struct DOCINFO
{
public int cbSize;
public string lpszDocName;
public string lpszOutput;
public string lpszDataType;
}

........

[DllImport("ICE_API.dll")]
public static extern int FeedCard(int hdc, int dwCardData);

[DllImport("ICE_API.dll")]
public static extern int GetCardId(int hdc, CARDIDTYPE pCardId);

[DllImport("ICE_API.dll")]
public static extern int SmartCardContinue(int hdc, int dwCommand);

.........

public const int ICE_SMARTCARD_FRONT = 0x10;
public const int ICE_GRAPHICS_FRONT = 0x1;

public const int ICE_SMART_CARD_GOOD = 0;
public const int ICE_SMART_CARD_ABORT = 1;

Now that was the easy part.

by . Also posted on my website