Page 1 of 1

PCSC Wrapper to access smartcards

Posted: Mon Mar 29, 2004 7:20 pm
by Leo
Hello,

I wrote a little PCSC wrapper to access smartcards. Only the basic functions of the winscard.dll are implemented. I did use the Interface command that is new in PureBasic 3.81. The source code is listed below

Code: Select all

;*******************************************************
;
;  PureBasic : PCSC Wrapper
;  Author : Leo Mijnders
;  Date : 29 March 2004
;  Doc : http://msdn.microsoft.com/library/en-us/security/security/authentication_functions.asp?frame=true#smart_card_functions
;
;*******************************************************

#SCARD_SHARE_EXCLUSIVE = 1 ; This application is not willing To share this
                           ; // card with other applications.
#SCARD_SHARE_SHARED = 2    ; This application is willing To share this
                           ; // card with other applications.
#SCARD_SHARE_DIRECT = 3    ; // This application demands direct control of

#SCARD_PROTOCOL_T0               =$0001   ;/* T=0 active protocol. */
#SCARD_PROTOCOL_T1               =$0002   ;/* T=1 active protocol. */
#SCARD_PROTOCOL_RAW              =$0004   ;/* Raw active protocol. */


#SCARD_UNKNOWN                   =$0001   ;/* Unknown state */
#SCARD_ABSENT                    =$0002   ;/* Card is absent */
#SCARD_PRESENT                   =$0004   ;/* Card is present */
#SCARD_SWALLOWED                 =$0008   ;/* Card not powered */
#SCARD_POWERED                   =$0010   ;/* Card is powered */
#SCARD_NEGOTIABLE                =$0020   ;/* Ready For PTS */
#SCARD_SPECIFIC                  =$0040   ;/* PTS has been set */

#SCARD_LEAVE_CARD                =$0000   ;/* Do nothing on close */
#SCARD_RESET_CARD                =$0001   ;/* Reset on close */
#SCARD_UNPOWER_CARD              =$0002   ;/* Power down on close */
#SCARD_EJECT_CARD                =$0003   ;/* Eject on close */

#SCARD_S_SUCCESS                 =$00000000
#SCARD_E_CANCELLED               =$80100002
#SCARD_E_CANT_DISPOSE            =$8010000E
#SCARD_E_INSUFFICIENT_BUFFER     =$80100008
#SCARD_E_INVALID_ATR             =$80100015
#SCARD_E_INVALID_HANDLE          =$80100003
#SCARD_E_INVALID_PARAMETER       =$80100004
#SCARD_E_INVALID_TARGET          =$80100005
#SCARD_E_INVALID_VALUE           =$80100011
#SCARD_E_NO_MEMORY               =$80100006
#SCARD_F_COMM_ERROR              =$80100013
#SCARD_F_INTERNAL_ERROR          =$80100001
#SCARD_F_UNKNOWN_ERROR           =$80100014
#SCARD_F_WAITED_TOO_LONG         =$80100007
#SCARD_E_UNKNOWN_READER          =$80100009
#SCARD_E_TIMEOUT                 =$8010000A
#SCARD_E_SHARING_VIOLATION       =$8010000B
#SCARD_E_NO_SMARTCARD            =$8010000C
#SCARD_E_UNKNOWN_CARD            =$8010000D
#SCARD_E_PROTO_MISMATCH          =$8010000F
#SCARD_E_NOT_READY               =$80100010
#SCARD_E_SYSTEM_CANCELLED        =$80100012
#SCARD_E_NOT_TRANSACTED          =$80100016
#SCARD_E_READER_UNAVAILABLE      =$80100017


Enumeration
  #SCARD_SCOPE_USER            ;    0x0000/* Scope in user space */
  #SCARD_SCOPE_TERMINAL        ;    0x0001/* Scope in terminal */
  #SCARD_SCOPE_SYSTEM          ;    0x0002/* Scope in system */
EndEnumeration 


Global fSCardEstablishContext, fSCardConnect, fSCardStatus, fSCardDisconnect, fSCardTransmit
Global fSCardListReaders

Global g_rgSCardT0Pci, g_rgSCardT1Pci, g_rgSCardRawPci

Procedure.l InitPCSC(Lib.l)
  If OpenLibrary(Lib, "winscard.dll")

    ; Pointers to SCARD_IO_REQUEST structures
    
    g_rgSCardT0Pci=IsFunction(Lib,"g_rgSCardT0Pci")
    g_rgSCardT1Pci=IsFunction(Lib,"g_rgSCardT1Pci")
    g_rgSCardRawPci=IsFunction(Lib,"g_rgSCardRawPci")

    ; Pointers to Basic PCSC Functions
    
    fSCardEstablishContext=IsFunction(Lib,"SCardEstablishContext")
    fSCardConnect=IsFunction(Lib,"SCardConnectA")
    fSCardStatus=IsFunction(Lib,"SCardStatusA")
    fSCardDisconnect=IsFunction(Lib,"SCardDisconnect")
    fSCardTransmit=IsFunction(Lib,"SCardTransmit")
    fSCardListReaders=IsFunction(Lib,"SCardListReadersA")
    
    ProcedureReturn 0
  EndIf
  ProcedureReturn -1
EndProcedure 

Procedure.l sSCardEstablishContext(self.l, a.l, b.l, c.l, d.l)
  ProcedureReturn CallFunctionFast(fSCardEstablishContext, a, b, c, d)
EndProcedure

Procedure.l sSCardConnect(self.l, a.l, b.l, c.l, d.l, e.l, f.l)
  ProcedureReturn CallFunctionFast(fSCardConnect, a, b, c, d, e, f)
EndProcedure

Procedure.l sSCardStatus(self.l, a.l, b.l, c.l, d.l, e.l, f.l, g.l)
  ProcedureReturn CallFunctionFast(fSCardStatus, a, b, c, d, e, f, g)
EndProcedure

Procedure.l sSCardDisconnect(self.l, a.l, b.l)
  ProcedureReturn CallFunctionFast(fSCardDisconnect, a, b)
EndProcedure

Procedure.l sSCardTransmit(self.l, a.l, b.l, c.l, d.l, e.l, f.l, g.l)
  ProcedureReturn CallFunctionFast(fSCardTransmit, a, b, c, d, e, f, g)
EndProcedure

Procedure.l sSCardListReaders(self.l, a.l, b.l, c.l, d.l)
  ProcedureReturn CallFunctionFast(fSCardListReaders, a, b, c, d)
EndProcedure

Interface IF_PCSC
  EstablishContext(a.l, b.l, c.l, d.l)
  Connect(a.l, b.l, c.l, d.l, e.l, f.l)
  Status(a.l, b.l, c.l, d.l, e.l, f.l, g.l)
  Disconnect(a.l, b.l)
  Transmit(a.l, b.l, c.l, d.l, e.l, f.l, g.l)
  ListReaders(a.l, b.l, c.l, d.l)
EndInterface

Structure strucInterface
  a.l
  b.l
  c.l
  d.l
  e.l
  f.l
EndStructure

SCard.IF_PCSC
Struc.strucInterface

Struc\a=@sSCardEstablishContext()
Struc\b=@sSCardConnect()
Struc\c=@sSCardStatus()
Struc\d=@sSCardDisconnect()
Struc\e=@sSCardTransmit()
Struc\f=@sSCardListReaders()

AddStruc.l=@Struc
PokeL(@SCard,@AddStruc)

Structure IO_REQ
  P.l
  A.l
  B.b[512]
EndStructure

outPCI_T0.IO_REQ

outPCI_T0\P=1
outPCI_T0\A=512


; *************************** CompilerIf 0 if used as IncludeFile  or  1 = if test IncludeFile

CompilerIf 0

  Procedure.s HexString(Source.l, L.l) 
    result.s = ""
    For i = 0 To L-1
        result = result + Right("00" + Hex(PeekB(Source+i)), 2) 
    Next i
    ProcedureReturn result
  EndProcedure
  
  hCTX.l
  Buf.s=Space(1000)
  ATRL.l
  ATR.l=AllocateMemory(2,100)
  hCARD.l
  AP.l
  L.l
  S.L
  In.l=AllocateMemory(3,100)
  Out.l=AllocateMemory(4,100)
  OutL.l

  ; APDU to genarate 8 byte Random at TB100 smartcard

  PokeB(In,$BC)
  PokeB(In+1,$C4)
  PokeB(In+2,$00)
  PokeB(In+3,$00)
  PokeB(In+4,$08)

  If InitPCSC(10)=0
    A=SCard\EstablishContext(0,0,0,@hCTX)
    MessageRequester("hCTX", Hex(A)+" "+Hex(hCTX),0)
    L.l=1000
    A=SCard\ListReaders(hCTX,0,@Buf,@L)
    MessageRequester("Reader", Hex(A)+" "+Buf,0)
    A=SCard\Connect(hCTX,@"TOWITOKO CHIPDRIVE 0",#SCARD_SHARE_SHARED,#SCARD_PROTOCOL_T0 | #SCARD_PROTOCOL_T1,@hCARD,@AP)
    MessageRequester("Connect", Hex(A),0)
    A=SCard\Status(hCARD,@Buf,@L,@S,@AP,ATR,@ATRL)
    MessageRequester("Status", Hex(A)+" "+Hex(S)+" "+Hex(AP)+" "+Hex(ATRL)+" "+Hex(PeekL(ATR)),0)
    A=SCard\DisConnect(hCARD,#SCARD_RESET_CARD)
    MessageRequester("Disconnect", Hex(A))
    A=SCard\Connect(hCTX,@"TOWITOKO CHIPDRIVE 0",#SCARD_SHARE_SHARED,#SCARD_PROTOCOL_T0 | #SCARD_PROTOCOL_T1,@hCARD,@AP)
    MessageRequester("Connect", Hex(A),0)
    A=SCard\Status(hCARD,@Buf,@L,@S,@AP,ATR,@ATRL)
    MessageRequester("Status", Hex(A)+" "+Hex(S)+" "+Hex(AP)+" "+Hex(ATRL)+" "+HexString(ATR,ATRL),0)
    For I=1 To 10
      OutL=10
      A=SCard\Transmit(hCARD, g_rgSCardT0Pci, In, 5, @outPCI_T0, Out, @OutL)
      MessageRequester("Transmit", Hex(A)+" "+HexString(Out,OutL)+" "+Hex(OutL),0)
    Next  
    A=SCard\DisConnect(hCARD,#SCARD_RESET_CARD)
    MessageRequester("Disconnect", Hex(A))
  Else
    MessageRequester("Error", "Lib not loaded",0)
  EndIf  
  
CompilerEndIf
Have fun

Greetings

Leo

Posted: Fri Nov 07, 2008 7:27 pm
by Lazarus404
I've modified this, now, to work with Tikitag. Does anyone have any examples of doing this for Linux and Mac OS's?