www.pudn.com > agsm2-1.2_src.zip > PcScCtrl.cpp
// PcScCtrl.cpp: implementation of the CPcScCtrl class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "agsm2.h"
#include "PcScCtrl.h"
#include "Helper.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
ISO7816_CMD SimCmd =
{
0xA0, //GSM SIM CLASS
0xa4, //Select
0xf2, //Status
0xb0, //Read Binary
0xd6, //UpdateBinary;
0xb2, //ReadRecord;
0xdc, //UpdateRecord;
0xa2, //Seek;
0x32, //Increase;
0x20, //VerifyChv;
0x24, //ChangeChv;
0x26, //DisableChv;
0x28, //EnableChv;
0x2c, //UnblockChv;
0x04, //Invalidate;
0x44, //Rehabilitate;
0x88, //RunGsmAlgorithm;
0xfa, //Sleep;
0xc0, //GetResponse;
};
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CPcScCtrl::CPcScCtrl()
{
m_bGetRes = TRUE;
m_nCurReader = 0;
hCard = NULL;
hContext = NULL;
LONG lResult = EstablishContext();
if(lResult != SCARD_S_SUCCESS)
Helper::ShowLastError(lResult);
}
CPcScCtrl::~CPcScCtrl()
{
LONG lReturn;
if(hCard)
{
lReturn = SCardDisconnect(hCard, SCARD_LEAVE_CARD);
ASSERT(lReturn == SCARD_S_SUCCESS);
}
if (hContext != NULL)
{
lReturn = SCardReleaseContext(hContext);
ASSERT(lReturn == SCARD_S_SUCCESS);
}
}
LONG CPcScCtrl::ListReaders()
{
LONG lResult;
LPTSTR lpmszReaderNames;
LONG nReaders = 0;
m_asReaderNames.RemoveAll();
EstablishContext();
if(hContext == NULL)
return nReaders;
//__try
{
//
// Get the list of registered readers associated with the specified
// group(s).
// Note: The buffer is automatically allocated and must be freed
// by SCFree().
//
lResult = SCListReaders(hContext,
NULL,
(LPTSTR *) &lpmszReaderNames);
//Helper::ShowLastError(lResult);
if (lResult != SCARD_S_SUCCESS)
{
//__leave;
}else{
DWORD dwNumReaders = 0;
LPTSTR lpszReaderName = lpmszReaderNames;
TRACE(_T("\n"));
TRACE(_T("Registered Reader(s)\n"));
TRACE(_T("====================\n"));
//
// Walk through the list of readers and print out some information.
// Note: The list of readers are in a multi-string structure.
//
while (*lpszReaderName != _T('\0'))
{
++dwNumReaders;
TRACE(_T("%02d: %s\n"), dwNumReaders, lpszReaderName);
CString ts(lpszReaderName);
m_asReaderNames.Add(ts);
lpszReaderName += lstrlen(lpszReaderName) + 1;
nReaders++;
}
//
// Inform the user if no reader was found.
//
if (dwNumReaders == 0)
{
TRACE(_T("No registered reader was found"));
AfxMessageBox(_T("No registered reader was found"));
}
}
}
// Don't forget to release memory, if allocated.
//
if (lpmszReaderNames != NULL)
SCFree((LPVOID) lpmszReaderNames);
return nReaders;
}
LONG CPcScCtrl::DoAPDU(LPBYTE cmdAPDU, DWORD len, LPBYTE resAPDU,DWORD &reslen)
{
LONG lResult;
if(hCard == NULL)
{
lResult = SCARD_E_NO_SMARTCARD;
throw lResult;
}
//
// Send APDU to card
//
lResult = SCardTransmit(hCard,
SCARD_PCI_T0,
cmdAPDU,
len,
NULL,
resAPDU,
&reslen);
//
// If API successful but card operation failed, then
// return SW1 and SW2 as error code
//
if (lResult == SCARD_S_SUCCESS)
{
//
// Sanity check
//
if(len == 5)//Must be Read
{
ASSERT(reslen >= 2);
}else{
//ASSERT(reslen == 2);
}
if(reslen == 2)
{
if ( m_bGetRes &&
(resAPDU[0] == 0x61 || resAPDU[0] == 0x9f)
)
{
BYTE len = resAPDU[1];
DWORD dwStatusLen = len + 2;
//BYTE apdu[5] = {0xa0, 0xc0, 0x00, 0x00, len};
CMDAPDU cmdApdu;
cmdApdu.klass = SimCmd.Klass;
cmdApdu.inc = SimCmd.GetResponse;
cmdApdu.p1 = 0;
cmdApdu.p2 = 0;
cmdApdu.p3 = len;
//
// Send APDU to card.
//
lResult = SCardTransmit(hCard,
SCARD_PCI_T0,
(LPBYTE)&cmdApdu,
5,
NULL,
resAPDU,
&dwStatusLen);
if (lResult == SCARD_S_SUCCESS)
{
reslen = dwStatusLen;
TRACE(_T("%d response bytes available\n"),reslen);
}
}
}
#ifdef _DEBUG
if (reslen>=2)
{
BYTE errseq[2];
errseq[0] = resAPDU[reslen-2];
errseq[1] = resAPDU[reslen-1];
TRACE("%s\n",FormatErrMsg(errseq));
}
#endif
if(reslen >= 2)
{
UCHAR SW1 = resAPDU[reslen-2];
LONG lRet = MAKELONG(MAKEWORD(resAPDU[reslen-1],SW1), 0x0000);
if(SW1 != 0x90 && SW1 != 0x9f && SW1 != 0x61)
throw lRet;
else
return lRet;
}
}
throw lResult;
return lResult;
}
LPVOID CPcScCtrl::SCMalloc(DWORD dwSize)
{
return(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize));
}
LONG CPcScCtrl::SCFree(LPVOID lpMemory)
{
LONG lResult;
//
// Parameters sanity check.
//
ASSERT(lpMemory != NULL);
if (HeapFree(GetProcessHeap(), 0, lpMemory))
{
lResult = SCARD_S_SUCCESS;
}
else
{
lResult = GetLastError();
}
return lResult;
}
LONG CPcScCtrl::SCListReaders(SCARDCONTEXT hContext, LPCTSTR lpmszReaderGroups, LPTSTR *lplpmszReaderNames)
{
LONG lResult;
DWORD dwReaders;
//
// Parameters sanity check.
//
ASSERT(lplpmszReaderNames != NULL);
//
// Initialize returned info.
//
* lplpmszReaderNames = NULL;
//
// First find the required buffer length.
//
lResult = SCardListReaders(hContext,
lpmszReaderGroups,
NULL, // NULL to indicate we want to
&dwReaders); // know the length of the buffer
if (lResult != SCARD_S_SUCCESS)
{
return lResult;
}
//
// Allocate memory.
//
LPTSTR lpmszReaderNames = (LPTSTR) SCMalloc(dwReaders * sizeof(_TCHAR));
if (lpmszReaderNames == NULL)
{
return ERROR_OUTOFMEMORY;
}
//
// Now actually get the list of reader names.
//
lResult = SCardListReaders(hContext,
lpmszReaderGroups,
lpmszReaderNames,
&dwReaders);
if (lResult == SCARD_S_SUCCESS)
{
//
// Successful, so return pointer to reader names.
//
*lplpmszReaderNames = lpmszReaderNames;
}
else
{
//
// Error occurred, so free memory.
//
SCFree((LPVOID) lpmszReaderNames);
}
return lResult;
}
DWORD CPcScCtrl::TrackingCard(DWORD dwCurrentState)
{
LONG lResult;
EstablishContext();
if(m_asReaderNames.GetSize() == 0 || hContext == NULL)
return SCARD_STATE_UNKNOWN;
SCARD_READERSTATE rsReaders;
ZeroMemory((LPVOID)&rsReaders, sizeof(rsReaders));
rsReaders.szReader = (LPCTSTR)m_asReaderNames[m_nCurReader];
rsReaders.dwCurrentState = dwCurrentState;
//
// Now check state of the current reader
//
lResult = SCardGetStatusChange(hContext,
INFINITE,
&rsReaders,
1);
if (lResult != SCARD_S_SUCCESS)
return SCARD_STATE_UNKNOWN;
return rsReaders.dwEventState;
}
LONG CPcScCtrl::SetCurReader(INT n)
{
if (m_asReaderNames.GetSize() == 0 || m_asReaderNames.GetSize() < n)
return -1;
m_nCurReader = n;
if(hCard)
{
LONG lResult = SCardEndTransaction(
hCard,
SCARD_LEAVE_CARD
);
// if(lResult != SCARD_S_SUCCESS)
// {
// Helper::ShowLastError(lResult);
// return lResult;
// }
lResult = SCardDisconnect(hCard, SCARD_LEAVE_CARD);
if(lResult != SCARD_S_SUCCESS)
{
Helper::ShowLastError(lResult);
return lResult;
}
hCard = NULL;
}
DWORD dwActiveProtocol;
//
// Connect to the card
//
LONG lResult = SCardConnect(hContext,
m_asReaderNames[m_nCurReader],
SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
&hCard,
&dwActiveProtocol);
//if(lResult != SCARD_S_SUCCESS)
// Helper::ShowLastError(lResult);
if(lResult == SCARD_S_SUCCESS)
lResult = SCardBeginTransaction(hCard);
return lResult;
}
INT CPcScCtrl::GetCurReader()
{
return m_nCurReader;
}
void CPcScCtrl::SetCLA(UCHAR cla)
{
SimCmd.Klass = cla;
}
LONG CPcScCtrl::Select(UCHAR id[],RESAPDU &resApdu, UCHAR P1, UCHAR P2 )
{
CMDAPDU cmdApdu;
cmdApdu.klass = SimCmd.Klass;
cmdApdu.inc = SimCmd.Select;
cmdApdu.p1 = P1;
cmdApdu.p2 = P2;
cmdApdu.p3 = 2;
cmdApdu.data[0] = id[0];
cmdApdu.data[1] = id[1];
return DoAPDU((LPBYTE)&cmdApdu,5+2,resApdu.data,resApdu.len);
}
LONG CPcScCtrl::Select(ULONG id, RESAPDU &resApdu, UCHAR P1, UCHAR P2)
{
UCHAR aid[2];
aid[0] = (UCHAR)((id >> 8) & 0xff);
aid[1] = (UCHAR)(id & 0xff);
return Select(aid,resApdu,P1,P2);
}
LONG CPcScCtrl::Status(RESAPDU &resApdu)
{
CMDAPDU cmdApdu;
cmdApdu.klass = SimCmd.Klass;
cmdApdu.inc = SimCmd.Status;
cmdApdu.p1 = 0;
cmdApdu.p2 = 0;
cmdApdu.p3 = (BYTE)(resApdu.len-2);
return DoAPDU((LPBYTE)&cmdApdu,5,resApdu.data,resApdu.len);
}
LONG CPcScCtrl::ReadBinary(UCHAR OffHi, UCHAR OffLo, RESAPDU &resApdu)
{
CMDAPDU cmdApdu;
cmdApdu.klass = SimCmd.Klass;
cmdApdu.inc = SimCmd.ReadBinary;
cmdApdu.p1 = OffHi;
cmdApdu.p2 = OffLo;
cmdApdu.p3 = (BYTE)(resApdu.len-2);
return DoAPDU((LPBYTE)&cmdApdu,5,resApdu.data,resApdu.len);
}
LONG CPcScCtrl::UpdateBinary(UCHAR OffHi, UCHAR OffLo, LPBYTE data, UCHAR len)
{
CMDAPDU cmdApdu;
cmdApdu.klass = SimCmd.Klass;
cmdApdu.inc = SimCmd.UpdateBinary;
cmdApdu.p1 = OffHi;
cmdApdu.p2 = OffLo;
cmdApdu.p3 = len;
memcpy(cmdApdu.data,data,len);
BYTE sw[2];
RESAPDU resApdu;
resApdu.data = sw;
resApdu.len = 2;
return DoAPDU((LPBYTE)&cmdApdu,5+len,resApdu.data,resApdu.len);
}
LONG CPcScCtrl::ReadRecord(UCHAR RecNo, UCHAR mode, RESAPDU &resApdu)
{
CMDAPDU cmdApdu;
cmdApdu.klass = SimCmd.Klass;
cmdApdu.inc = SimCmd.ReadRecord;
cmdApdu.p1 = RecNo;
cmdApdu.p2 = mode;
cmdApdu.p3 = (BYTE)(resApdu.len-2);
return DoAPDU((LPBYTE)&cmdApdu,5,resApdu.data,resApdu.len);
}
LONG CPcScCtrl::UpdateRecord(UCHAR RecNo, UCHAR mode, LPBYTE Rec, UCHAR len)
{
CMDAPDU cmdApdu;
cmdApdu.klass = SimCmd.Klass;
cmdApdu.inc = SimCmd.UpdateRecord;
cmdApdu.p1 = RecNo;
cmdApdu.p2 = mode;
cmdApdu.p3 = len;
memcpy(cmdApdu.data,Rec,len);
BYTE sw[2];
RESAPDU resApdu;
resApdu.data = sw;
resApdu.len = 2;
return DoAPDU((LPBYTE)&cmdApdu,5+len,resApdu.data,resApdu.len);
}
LONG CPcScCtrl::Seek(UCHAR mode, LPBYTE patten, UCHAR len,RESAPDU &resApdu)
{
CMDAPDU cmdApdu;
cmdApdu.klass = SimCmd.Klass;
cmdApdu.inc = SimCmd.Seek;
cmdApdu.p1 = 0;
cmdApdu.p2 = mode;
cmdApdu.p3 = len;
memcpy(cmdApdu.data,patten,len);
return DoAPDU((LPBYTE)&cmdApdu,5+len,resApdu.data,resApdu.len);
}
LONG CPcScCtrl::Increase(LPBYTE data, UCHAR len,RESAPDU &resApdu)
{
CMDAPDU cmdApdu;
cmdApdu.klass = SimCmd.Klass;
cmdApdu.inc = SimCmd.Increase;
cmdApdu.p1 = 0;
cmdApdu.p2 = 0;
cmdApdu.p3 = len;
memcpy(cmdApdu.data,data,len);
return DoAPDU((LPBYTE)&cmdApdu,5+len,resApdu.data,resApdu.len);
}
LONG CPcScCtrl::VerifyChv(UCHAR ChvNo, LPBYTE data, UCHAR len)
{
ASSERT(len == 8);
return DoChv(SimCmd.VerifyChv,ChvNo,data,len);
}
LONG CPcScCtrl::ChangeChv(UCHAR ChvNo, LPBYTE data, UCHAR len)
{
ASSERT(len == 16);
return DoChv(SimCmd.ChangeChv,ChvNo,data,len);
}
LONG CPcScCtrl::UnblockChv(UCHAR ChvNo, LPBYTE data, UCHAR len)
{
ASSERT(len == 16);
return DoChv(SimCmd.UnblockChv,ChvNo,data,len);
}
LONG CPcScCtrl::DisableChv(UCHAR ChvNo, LPBYTE data, UCHAR len)
{
ASSERT(len == 8);
return DoChv(SimCmd.DisableChv,ChvNo,data,len);
}
LONG CPcScCtrl::EnableChv(UCHAR ChvNo, LPBYTE data, UCHAR len)
{
ASSERT(len == 8);
return DoChv(SimCmd.EnableChv,ChvNo,data,len);
}
LONG CPcScCtrl::Invalidate()
{
CMDAPDU cmdApdu;
cmdApdu.klass = SimCmd.Klass;
cmdApdu.inc = SimCmd.Invalidate;
cmdApdu.p1 = 0;
cmdApdu.p2 = 0;
cmdApdu.p3 = 0;
BYTE sw[2];
RESAPDU resApdu;
resApdu.data = sw;
resApdu.len = 2;
return DoAPDU((LPBYTE)&cmdApdu,5,resApdu.data,resApdu.len);
}
LONG CPcScCtrl::Rehabilitate()
{
CMDAPDU cmdApdu;
cmdApdu.klass = SimCmd.Klass;
cmdApdu.inc = SimCmd.Rehabilitate;
cmdApdu.p1 = 0;
cmdApdu.p2 = 0;
cmdApdu.p3 = 0;
BYTE sw[2];
RESAPDU resApdu;
resApdu.data = sw;
resApdu.len = 2;
return DoAPDU((LPBYTE)&cmdApdu,5,resApdu.data,resApdu.len);
}
LONG CPcScCtrl::RunGsmAlgorithm(LPBYTE rnd, UCHAR len,RESAPDU &resApdu)
{
ASSERT(len == 16);
CMDAPDU cmdApdu;
cmdApdu.klass = SimCmd.Klass;
cmdApdu.inc = SimCmd.RunGsmAlgorithm;
cmdApdu.p1 = 0;
cmdApdu.p2 = 0;
cmdApdu.p3 = 16;
memcpy(cmdApdu.data,rnd,len);
return DoAPDU((LPBYTE)&cmdApdu,5+len,resApdu.data,resApdu.len);
}
LONG CPcScCtrl::GetResponse(RESAPDU &resApdu)
{
CMDAPDU cmdApdu;
cmdApdu.klass = SimCmd.Klass;
cmdApdu.inc = SimCmd.GetResponse;
cmdApdu.p1 = 0;
cmdApdu.p2 = 0;
cmdApdu.p3 = (BYTE)(resApdu.len - 2);
return DoAPDU((LPBYTE)&cmdApdu,5,resApdu.data,resApdu.len);
}
LONG CPcScCtrl::DoChv(UCHAR cmd, UCHAR ChvNo, LPBYTE data, UCHAR len)
{
CMDAPDU cmdApdu;
cmdApdu.klass = SimCmd.Klass;
cmdApdu.inc = cmd;
cmdApdu.p1 = 0;
cmdApdu.p2 = ChvNo;
cmdApdu.p3 = len;
memcpy(cmdApdu.data,data,len);
BYTE sw[2];
RESAPDU resApdu;
resApdu.data = sw;
resApdu.len = 2;
return DoAPDU((LPBYTE)&cmdApdu,5+len,resApdu.data,resApdu.len);
}
LONG CPcScCtrl::SCardControl(DWORD dwControlCode, LPCVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned)
{
ULONG lReturn = ::SCardControl( hCard,
dwControlCode,
lpInBuffer,
nInBufferSize,
lpOutBuffer,
nOutBufferSize,
lpBytesReturned );
if ( SCARD_S_SUCCESS != lReturn )
TRACE("Failed SCardControl\n");
return lReturn;
}
LONG CPcScCtrl::SCardStatus(LPTSTR szReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
{
ULONG lReturn = ::SCardStatus(hCard,
szReaderName,
pcchReaderLen,
pdwState,
pdwProtocol,
pbAtr,
pcbAtrLen);
if ( SCARD_S_SUCCESS != lReturn )
{
TRACE("Failed SCardStatus\n");
}
return lReturn;
}
LONG CPcScCtrl::SCardGetAttrib(DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
{
LONG lReturn;
// Retrieve an attribute.
// hCardHandle was set by a previous call to SCardConnect.
lReturn = ::SCardGetAttrib(hCard,
dwAttrId,
pbAttr,
pcbAttrLen);
if ( SCARD_S_SUCCESS != lReturn )
{
TRACE("Failed SCardGetAttrib\n");
}
return lReturn;
}
LONG CPcScCtrl::SCardSetAttrib(DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
{
LONG lReturn;
// Retrieve an attribute.
// hCardHandle was set by a previous call to SCardConnect.
lReturn = ::SCardSetAttrib(hCard,
dwAttrId,
pbAttr,
cbAttrLen);
if ( SCARD_S_SUCCESS != lReturn )
{
TRACE("Failed SCardSetAttrib\n");
}
return lReturn;
}
CString CPcScCtrl::GetCardState()
{
if(hCard == NULL || m_asReaderNames.GetSize() == 0)
return (LPCSTR)IDS_STRING_ABSENT;
TCHAR szReader[200];
DWORD cch = 200;
BYTE bAttr[32];
DWORD cByte = 32;
DWORD dwState, dwProtocol;
LONG lReturn;
// Determine the status.
// hCardHandle was set by an earlier call to SCardConnect.
lReturn = ::SCardStatus(hCard,
szReader,
&cch,
&dwState,
&dwProtocol,
(LPBYTE)&bAttr,
&cByte);
if ( SCARD_S_SUCCESS != lReturn )
{
Helper::ShowLastError(lReturn);
return (LPCSTR)IDS_STRING_ABSENT;
}
// Examine retrieved status elements.
// Here, we'll look at the reader name and card state.
switch ( dwState )
{
case SCARD_ABSENT:
return (LPCSTR)IDS_STRING_ABSENT;
case SCARD_PRESENT:
return (LPCSTR)IDS_STRING_PRESENT;
case SCARD_SWALLOWED:
return (LPCSTR)IDS_STRING_SWALLOWED;
case SCARD_POWERED:
return (LPCSTR)IDS_STRING_POWERD;
case SCARD_NEGOTIABLE:
return (LPCSTR)IDS_STRING_NEGOTIABLE;
case SCARD_SPECIFIC:
{
CString str;
switch(dwProtocol)
{
case SCARD_PROTOCOL_UNDEFINED:
str = (LPCSTR)IDS_STRING_UNDEFINED;
break;
case SCARD_PROTOCOL_T0:
str = _T("(T0)");
break;
case SCARD_PROTOCOL_T1:
str = _T("(T1)");
break;
case SCARD_PROTOCOL_RAW:
str = _T("(RAW)");
break;
}
return (LPCSTR)IDS_STRING_PROTOCOL+str;
}
}
return IDS_STRING_UNKNOWN;
}
CString CPcScCtrl::FormatErrMsg(LONG errcode)
{
BYTE errseq[2] = { ((errcode >> 8) & 0xff), (errcode & 0xff) };
return FormatErrMsg(errseq);
}
CString CPcScCtrl::FormatErrMsg(BYTE errseq[])
{
for(int j=0; j< sizeof(C_response)/sizeof(C_response[0]); j++)
{
for(int i=sizeof(C_response[j].MASK)-1; i>=0; i--)
if (C_response[j].SW[i] != (C_response[j].MASK[i] & errseq[i]))
break;
if (i==-1)
{
CString str;
CString strsw;
strsw.Format("(%02x%02x)",errseq[0],errseq[1]);
str.Format(C_response[j].text, (int)errseq[1]);
return str+strsw;
}
}
return _T("Unknow error.");
}
LONG CPcScCtrl::EstablishContext()
{
LONG lResult = SCARD_S_SUCCESS;
if(hContext == NULL)
{
lResult = SCardEstablishContext(SCARD_SCOPE_USER,
NULL,
NULL,
&hContext);
}
return lResult;
}
LONG CPcScCtrl::ConnectCurCard()
{
if (m_asReaderNames.GetSize() == 0 || m_asReaderNames.GetSize() < m_nCurReader)
return -1;
if(hCard == NULL)
{
DWORD dwActiveProtocol;
//
// Connect to the card
//
LONG lResult = SCardConnect(hContext,
m_asReaderNames[m_nCurReader],
SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
&hCard,
&dwActiveProtocol);
if(lResult != SCARD_S_SUCCESS)
Helper::ShowLastError(lResult);
return lResult;
}
return 0;
}
LONG CPcScCtrl::DisconnectCurCard()
{
LONG lResult;
if(hCard)
{
lResult = SCardDisconnect(hCard, SCARD_LEAVE_CARD);
if(lResult != SCARD_S_SUCCESS)
Helper::ShowLastError(lResult);
hCard = NULL;
}
return lResult;
}