unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ePasModLib_TLB, OleCtrls,comobj,ePsMod;

type
  TForm1 = class(TForm)
    ePass: TePas;
    Hash: THash;
    MeoMsg: TMemo;
    BtnDevice: TButton;
    BtnFileDemo: TButton;
    BtnCryptDemo: TButton;
    BtnClear: TButton;
    BtnCloseDevice: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure BtnDeviceClick(Sender: TObject);
    procedure BtnClearClick(Sender: TObject);
    procedure BtnCloseDeviceClick(Sender: TObject);
    procedure BtnFileDemoClick(Sender: TObject);
    procedure BtnCryptDemoClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    function  memcmp(var buf1,buf2:array of byte;count:integer):integer;
    procedure HexStrToBuf(strData:string;var binBuf:array of byte);
    procedure StrToBuf(strData:string;var binBuf:array of byte);
    procedure PrintStr(strMsg:string);
    procedure PrintStrLn(strMsg:string);
    function  ErrToStr(ErrCode:integer):string;
    function  ErrToCode(ErrCode:integer):integer;
    procedure ReportErr(ErrCode:integer);
    procedure ReportSucc();
    procedure QueryDeviceInfo();
    procedure DumpBuf(var pData:array of Byte;len:Integer);
    function  AccessToString(AccessCode:integer):string;
    function  CapToString(CapCode:integer):string;
    function  CreateDemoDir():boolean;
    procedure RemoveDemoDir();
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}
var
    epsGUID:array [0..15] of byte;
    pVarType:^TGUID;
    pByteData:PBYTE;
    epsDirInfo:WDirInfo;
    epsFileInfo:WFileInfo;
    epsAppName:array[0..EPAS_APP_NAME_SIZE - 1] of byte;
    pNullByte:PByte;

function TForm1.CreateDemoDir():boolean;
begin
    try
        pVarType := @epsDirInfo;

        PrintStr('Create a directory for demo');
        ePass.CreateDir( (EPAS_DIR_BY_GUID Or EPAS_CREATE_AUTO_ID), epsAppName[0], epsGUID[0],epsDirInfo);
        ReportSucc;
        result := true;        
    except
        on e:EOleSysError do
        begin
            ReportErr(e.ErrorCode);
            result := false;
        end
    end;
end;

procedure TForm1.RemoveDemoDir();
begin
 try
        PrintStr('Remove the demo-directory');
        ePass.DeleteDir(EPAS_DIR_BY_GUID, 0, epsGUID[0]);

        ReportSucc;
    except
        on e:EOleSysError do
        begin
            ReportErr(e.ErrorCode);
        end
    end;
end;

function  TForm1.CapToString(CapCode:integer):string;
begin
    If EPAS_CAPS_MD5HMAC = (CapCode And EPAS_CAPS_MD5HMAC) Then
        CapToString := 'MD5-HMAC'
    else
        CapToString := 'N/A';
end;

function  TForm1.AccessToString(AccessCode:integer):string;
begin
    If AccessCode = EPAS_ACCESS_ANYONE Then
        AccessToString := 'ALWAYS'
    Else If AccessCode = EPAS_ACCESS_USER Then
        AccessToString := 'PIN'
    Else If AccessCode = EPAS_ACCESS_OFFICER Then
        AccessToString := 'MASTER'
    Else If AccessCode = EPAS_ACCESS_NONE Then
        AccessToString := 'NONE'
end;

function  TForm1.ErrToCode(ErrCode:integer):integer;
begin
    result := ErrCode and $ffff;
end;

procedure TForm1.DumpBuf(var pData:array of Byte;len:Integer);
var
    i:integer;
begin
    for i := 0 to len-1 do
    begin
        if(i+1 mod 8)=0 then
        begin
            PrintStrLn('');
        end;
        PrintStr(' '+IntToHex(pData[i],2));
    end;
    PrintStrLn('');
end;

procedure TForm1.ReportSucc();
begin
    PrintStrLn(' [successful] ');
end;

procedure TForm1.ReportErr(ErrCode:integer);
begin
    ErrCode :=  ErrCode and $ffff;
    PrintStr(' [failed] ');
    PrintStrLn(' =====> ' + ErrToStr(ErrCode));
end;

function  TForm1.ErrToStr(ErrCode:integer):string;
begin
	If FT_CANNOT_OPEN_DRIVER = ErrCode Then
        Result := 'Can''t open the driver.'
    else if FT_INVALID_DRVR_VERSION = ErrCode Then
        Result := 'Driver version not supported.'
    else if FT_INVALID_COMMAND = ErrCode Then
        Result := 'Invalid command sent to API.'
    else if FT_ACCESS_DENIED = ErrCode Then
        Result := 'Access denied.'
    else if FT_ALREADY_ZERO = ErrCode Then
        Result := 'Counter already zero.'
    else if FT_UNIT_NOT_FOUND = ErrCode Then
        Result := 'Device not found.'
    else if FT_DEVICE_REMOVED = ErrCode Then
        Result := 'Device removed.'
    else if FT_COMMUNICATIONS_ERROR = ErrCode Then
        Result := 'Device communication error.'
    else if FT_DIR_NOT_FOUND = ErrCode Then
        Result := 'Directory does not exist.'
    else if FT_FILE_NOT_FOUND = ErrCode Then
        Result := 'File not found.'
    else if FT_MEM_CORRUPT = ErrCode Then
        Result := 'Device memory is corrupted.'
    else if FT_INTERNAL_HW_ERROR = ErrCode Then
        Result := 'Internal hardware error.'
    else if FT_INVALID_RESP_SIZE = ErrCode Then
        Result := 'Invalid response received from the device.'
    else if FT_PIN_EXPIRED = ErrCode Then
        Result := 'PIN retry attempts has expired.'
    else if FT_ALREADY_EXISTS = ErrCode Then
        Result := 'Directory or file already exist.'
    else if FT_NOT_ENOUGH_MEMORY = ErrCode Then
        Result := 'Not enough memory to perform the operation.'
    else if FT_INVALID_PARAMETER = ErrCode Then
        Result := 'Invalid parameter sent to API.'
    else if FT_INPUT_TOO_LONG = ErrCode Then
        Result := 'Input data is too long.'
    else if FT_INVALID_FILE_SELECTED = ErrCode Then
        Result := 'Invalid file selected or operation.'
    else if FT_DEVICE_IN_USE = ErrCode Then
        Result := 'The device is currently in use.'
    else if FT_INVALID_API_VERSION = ErrCode Then
        Result := 'The version of this library is not supported.'
    else if FT_TIME_OUT_ERROR = ErrCode Then
        Result := 'Communication time-out.'
    else if FT_ITEM_NOT_FOUND = ErrCode Then
        Result := 'Item not found.'
    else if FT_COMMAND_ABORTED = ErrCode Then
        Result := 'Communication error, command aborted.'
    else if FT_INVALID_STATUS = ErrCode Then
        Result := 'Invalid status.'
    Else
        Result := 'An unknown error occurred.'
end;

procedure TForm1.PrintStr(strMsg:string);
begin
    MeoMsg.Lines[MeoMsg.Lines.Count-1] := MeoMsg.Lines[MeoMsg.Lines.Count-1] +
        strMsg;
end;

procedure TForm1.PrintStrLn(strMsg:string);
begin
    PrintStr(strMsg);
    MeoMsg.Lines.Add(' ');
end;

procedure TForm1.FormCreate(Sender: TObject);
var
    LibVer:integer;
    Major,Minor:integer;
    Build:WORD;

    DrvVer:integer;
begin
        pNullByte:=nil;
        epsGUID[0] := $3F  ;
        epsGUID[1] := $85  ;
        epsGUID[2] := $28  ;
        epsGUID[3] := $B   ;

        epsGUID[4] := $C1  ;
        epsGUID[5] := $E4  ;

        epsGUID[6] := $DE  ;
        epsGUID[7] := $4A  ;

        epsGUID[8] := $AC  ;
        epsGUID[9] := $61  ;
        epsGUID[10] := $A6 ;
        epsGUID[11] := $6  ;
        epsGUID[12] := $2E ;
        epsGUID[13] := $A8 ;
        epsGUID[14] := $F0 ;
        epsGUID[15] := $99 ;

    LibVer := ePass.GetLibVersion;

    Major := (LibVer and $ff000000) shr 24;
    Minor := ((LibVer and $ff0000) shr 16);
    Build := (LibVer and $ffff);
    PrintStrLn(Format('Library Version: %d.%d.%d',[Major,Minor,Build]));

    DrvVer := ePass.GetDriverVersion;

    Major := (DrvVer and $ff000000) shr 24;
    Minor := ((DrvVer and $ff0000) shr 16);
    Build := (DrvVer and $ffff);
    PrintStrLn(Format('Driver Version: %d.%d.%d',[Major,Minor,Build]));
    try
        PrintStr('Create Context... ');
        ePass.CreateContext( 0, EPAS_API_VERSION);
        ReportSucc;
    except
        on e:EOleSysError do
        begin
            ReportErr(e.ErrorCode);
        end
    end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
    ePass.CloseDevice;
    ePass.DeleteContext;
end;

procedure TForm1.BtnDeviceClick(Sender: TObject);
var
    pAppID:^BYTE;
begin
    pAppID := nil;
    try
        PrintStr('Open Device...');
        ePass.OpenDevice(EPAS_OPEN_FIRST, pAppID^);
        BtnFileDemo.Enabled := true;
        BtnCryptDemo.Enabled := true;
        BtnCloseDevice.Enabled := true;
        ReportSucc;
        QueryDeviceInfo();
    except
        on e:EOleSysError do
        begin
            BtnFileDemo.Enabled := false;
            BtnCryptDemo.Enabled := false;
            ReportErr(e.ErrorCode);
        end
    end;
end;

procedure TForm1.BtnClearClick(Sender: TObject);
var
    binBuf:array [0..25] of byte;
begin
    MeoMsg.Lines.Clear;
end;

procedure TForm1.QueryDeviceInfo();
var
    SerialNum: array [0..7] of BYTE;
    Prop:array [0..31] of BYTE;
    VerInfo:WVersionInfo;
    SysInfo:WSysInfo;
    AccessInfo:WAccessInfo;
    pGuid:^TGUID;
    pIntValue:^integer;
begin
    try
        PrintStr('Get Serial Number...');
        ePass.GetProperty(EPAS_PROP_SERNUM,pNullByte^, SerialNum[0], 8);
        ReportSucc;
        DumpBuf(SerialNum,8);

        try
            PrintStr('Get token name...');
            ePass.GetProperty(EPAS_PROP_FRIENDLY_NAME, pNullByte^, Prop[0], EPAS_FRIENDLY_NAME_SIZE);
            ReportSucc();
            DumpBuf(prop,EPAS_FRIENDLY_NAME_SIZE);
        except
           on e:EOleSysError do
            begin
                 ReportErr(e.ErrorCode);
            end;
        end;
        PrintStr('Get the version information');
        ZeroMemory(@SysInfo,SizeOf(SysInfo));
        pGuid := @VerInfo;
        ePass.GetVersionInfo(VerInfo);
        ReportSucc();
        PrintStrLn(Format('Driver API version ...... :%d.%d.%d.%d',
            [(VerInfo.lDriverVersion and $ff000000)shr 24,
            (VerInfo.lDriverVersion and $ff0000) shr 16,
            (VerInfo.lDriverVersion and $ff00) shr 8,
            (VerInfo.lDriverVersion and $ff)
            ]));

        PrintStrLn(Format('Firmware Version ........ :%d.%d',
            [VerInfo.ucFwVerMajor,VerInfo.ucFwVerMinor]));

        PrintStrLn(Format('Product code ............ : %x',
            [VerInfo.ucProductCode]));

        PrintStr('Get Memory Size');
        ePass.GetProperty(EPAS_PROP_MEM_SIZE, pNullByte^, Prop[0], 4);
        ReportSucc();
        pIntValue := @Prop[0];
        PrintStrLn(Format('Memory size ............. :%d',[pIntValue^]));
        PrintStr('Get system information');
        ZeroMemory(@SysInfo,SizeOf(SysInfo));
        pGuid := @SysInfo;
        ePass.GetSysInfo(SysInfo);
        ReportSucc();
        PrintStrLn(Format('Flags ................... :%d',[SysInfo.lFlags]));
        PrintStrLn(Format('Free space .............. :%d',[SysInfo.lFreeSpace]));
        PrintStrLn(Format('File system type ........ :%d',[SysInfo.ucFileSysType]));
        PrintStrLn(Format('Max directory levels .... :%d',[SysInfo.ucMaxDirLevels]));

        PrintStr('Get access information');
        pGuid := @AccessInfo;
        ePass.GetAccessInfo(EPAS_PROP_ACCESSINFO,AccessInfo);
        ReportSucc;

        PrintStrLn(Format('lMax PIN retries ......... :%d',[AccessInfo.ucMaxPinRetries]));
        PrintStrLn(Format('Current PIN retries .....  :%d',[AccessInfo.ucCurPinCounter]));
        PrintStrLn(Format('Create access ...........  :%s',[AccessToString(AccessInfo.ucCreateAccess)]));
        PrintStrLn(Format('Delete access ...........  :%s',[AccessToString(AccessInfo.ucDeleteAccess)]));

        PrintStr('Get capabilities');
        ePass.GetProperty(EPAS_PROP_CAPABILITIES, pNullByte^, Prop[0], 4);
        ReportSucc;
        pIntValue := @Prop[0];

        PrintStrLn(Format('Capabilities ............ :%s',[CapToString(pIntValue^)]));

        //pByteData := @SysInfo;
        //DumpBuf(pByteData^,SizeOf(SysInfo));
    except
        on e:EOleSysError do
        begin
            ReportErr(e.ErrorCode);
        end
    end;
end;

procedure TForm1.BtnCloseDeviceClick(Sender: TObject);
begin
    BtnFileDemo.Enabled := false;
    BtnCryptDemo.Enabled := false;
    BtnCloseDevice.Enabled := false;
    ePass.CloseDevice;
end;

procedure TForm1.BtnFileDemoClick(Sender: TObject);
var
    demoStrArray:array[0..512] of byte;
    cbWritten,cbRead:Integer;
    DemoStr:string;
    pDemoPChar:PChar;
begin
    RemoveDemoDir();
    try

        if(not CreateDemoDir()) then
            Exit;
        epsFileInfo.lID := $32F5        ;//Create a file which ID is 0x32F5.
        epsFileInfo.lFileSize := $20    ;//Size of demo-file set to 0x20 (32 bytes).
        epsFileInfo.lFlags := 0         ;
        epsFileInfo.ucFileType := EPAS_FILETYPE_DATA;
        epsFileInfo.ucReadAccess := EPAS_ACCESS_ANYONE;
        epsFileInfo.ucWriteAccess := EPAS_ACCESS_ANYONE;
        epsFileInfo.ucCryptAccess := EPAS_ACCESS_ANYONE;

        pVarType := @epsFileInfo;
        PrintStr('Create a file for demo');
        ePass.CreateFile(0,epsFileInfo);
        ReportSucc;

        DemoStr := 'This is a demo';
        pDemoPChar:= PChar(DemoStr);
        pByteData := PBYTE(pDemoPChar);
        DumpBuf(pByteData^,length(demoStr));
        PrintStr('Write something to the demo-file');
        ePass.Write(0,0,pByteData^, length(demoStr), cbWritten);
        ReportSucc;


        PrintStr('Close the demo-file');
        ePass.CloseFile;
        ReportSucc;

        PrintStr('Re-open the demo-file');
        pVarType := @epsFileInfo;
        ePass.OpenFile(0,$32F5,epsFileInfo);
        ReportSucc;

        PrintStr('Read from the demo-file');
        ePass.Read(0,0,demoStrArray[0],epsFileInfo.lFileSize,cbRead);
        ReportSucc;

        DumpBuf(demoStrArray,length(demoStr));

        PrintStr('Remove the demo-file');
        ePass.DeleteFile(0,$32F5);
        ReportSucc;

        RemoveDemoDir();
    except
        on e:EOleSysError do
        begin
            ReportErr(e.ErrorCode);
        end
    end;
end;

procedure TForm1.StrToBuf(strData:string;var binBuf:array of byte);
var
    i:integer;
    strTemp:string;
begin
    for i:= 1 to length(strData) do
    begin
        binBuf[i-1] := ord(strData[i]);
    end;
end;

procedure TForm1.HexStrToBuf(strData:string;var binBuf:array of byte);
var
    i,nCount:integer;
    strTemp:string;
begin
    nCount := length(strData);
    nCount := nCount div 2;
    for i:= 0 to nCount - 1 do
    begin
        strTemp := strData[2*i+1];
        strTemp := '$' + strTemp + strData[2*i+2];
        binBuf[i] := StrToInt(strTemp);
    end;
end;

function  TForm1.memcmp(var buf1,buf2:array of byte;count:integer):integer;
var
    i:integer;
begin
    for i:=0 to count-1 do
        if(buf1[i]>buf2[i]) then
        begin
            result := 1;
            exit;
        end
        else if(buf1[i]<buf2[i]) then
        begin
            result := -1;
            exit;
        end;

    result := 0;
end;

procedure TForm1.BtnCryptDemoClick(Sender: TObject);
var
    wstrAuthKey,wstrEmpty,wstrText:WideString;
    strKey1,strKey2,strEmpty,strDigest:OleVariant;
    key1,key2,digest,softDigest:array [0..15] of byte;
    text:array[0..55] of byte;
    cbWritten:integer;
begin
    try
        RemoveDemoDir();
        CreateDemoDir();

        wstrAuthKey := 'FeiTian';
        strKey1 :='Empty';
        strKey2 :='Empty';

        wstrText := 'Rndtext';
        strDigest := 'Empty';

        PrintStr('Hash MD5_HMAC by software');
        Hash.MD5HMAC( wstrText, wstrAuthKey, strKey1, strKey2, strDigest);
        ReportSucc;

        HexStrToBuf(strKey1,key1);
        HexStrToBuf(strKey2,key2);

        epsFileInfo.lID := $1234        ;
        epsFileInfo.lFileSize := 16     ;
        epsFileInfo.lFlags := 0         ;
        epsFileInfo.ucFileType := EPAS_FILETYPE_KEY;
        epsFileInfo.ucReadAccess := EPAS_ACCESS_ANYONE;
        epsFileInfo.ucWriteAccess := EPAS_ACCESS_ANYONE;
        epsFileInfo.ucCryptAccess := EPAS_ACCESS_ANYONE;

        pVarType := @epsFileInfo;
        PrintStr('Create first key file');
        ePass.CreateFile(0,epsFileInfo);
        ReportSucc;

        pByteData := @key1;
        DumpBuf(pByteData^,16);
        PrintStr('Save to first key file');
        ePass.Write(0,0,pByteData^, 16, cbWritten);
        ReportSucc;

        epsFileInfo.lID := $2345        ;
        epsFileInfo.lFileSize := 16     ;
        epsFileInfo.lFlags := 0         ;
        epsFileInfo.ucFileType := EPAS_FILETYPE_KEY;
        epsFileInfo.ucReadAccess := EPAS_ACCESS_ANYONE;
        epsFileInfo.ucWriteAccess := EPAS_ACCESS_ANYONE;
        epsFileInfo.ucCryptAccess := EPAS_ACCESS_ANYONE;

        pVarType := @epsFileInfo;
        PrintStr('Create second key file');
        ePass.CreateFile(0,epsFileInfo);
        ReportSucc;

        pByteData := @key2;
        DumpBuf(pByteData^,16);
        PrintStr('Save to second key file');
        ePass.Write(0,0,pByteData^, 16, cbWritten);
        ReportSucc;


        PrintStr('Close the demo-file');
        ePass.CloseFile;
        ReportSucc;

        wstrText := 'Rndtext';
        PrintStr('MD5_HMAC compute by software');
        strDigest := 'Empty';
        Hash.MD5HMAC(wstrText,wstrAuthKey,strKey1,strKey2,strDigest);
        //AParCls1.enhMD5HMAC(wstrText,wstrAuthKey,strKey1,strKey2,strDigest);
        ReportSucc;

        StrToBuf(wstrText,text);
        HexStrToBuf(strDigest,softDigest);

        DumpBuf(softDigest,16);

        PrintStr('MD5_HMAC compute by ePass');
        ePass.MD5HMAC($1234,$2345,text[0],length(wstrText),digest[0]);
        ReportSucc;
        DumpBuf(Digest,16);

        PrintStr('Verify result');
        if memcmp(softDigest,digest,16) = 0 then
            ReportSucc
        else
            PrintStrLn(' [Failed]');

       RemoveDemoDir();
    except
        on e:EOleSysError do
        begin
            ReportErr(e.ErrorCode);
        end
    end;
end;

end.

