unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,Variants,
  StdCtrls,  OleCtrls,comobj, OleServer,  ePsMod,
  ePasModLib_TLB;
//  EPASSMDLibFull_TLB;
//ePasModLib_TLB,
type
  TForm1 = class(TForm)
    MeoMsg: TMemo;
    BtnDevice: TButton;
    BtnFileDemo: TButton;
    BtnCryptDemo: TButton;
    BtnClear: TButton;
    BtnCloseDevice: TButton;
    Hash1: THash;
    ePas11: TePas1;
    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;
    function HexStrToBuf(strData:string;var binBuf:array of byte):integer;

    function StrToBuf(strData:string;var binBuf:array of byte):integer;

    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(DirID : integer):boolean;
    procedure RemoveDemoDir(DirID : integer);
  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;
    epsAppName1:WideString;
    epsGUID1:Variant;

function TForm1.CreateDemoDir(DirID : integer):boolean;
begin
    try
        pVarType := @epsDirInfo;
        epsAppName1:='';
        epsDirInfo.lID := DirID;

        PrintStr('Create a directory for demo');
        ePas11.CreateDir( 0, epsAppName1, epsGUID1,epsDirInfo);
        //(EPAS_DIR_BY_GUID Or EPAS_CREATE_AUTO_ID)
        ReportSucc;
        result := true;
    except
        on e:EOleSysError do
        begin
            ReportErr(e.ErrorCode);
            result := false;
        end
    end;
end;

var
    dName : WideString;

procedure TForm1.RemoveDemoDir(DirID : integer);
begin
 try
        PrintStr('Remove the demo-directory');
        epsDirInfo.lID:= $100;
        dName:='';
        ePas11.ChangeDir($20, 0, dName);
        ePas11.DeleteDir($200, DirID, dName);
        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,Minor1:integer;
    Build:WORD;
    DrvVer:integer;
    Flag : 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 := ePas11.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 := ePas11.GetDriverVersion();
    //PrintStr(Format('DrvVer: %d', DrvVer));
    Major := (DrvVer and $ff000000) shr 24;
    Minor := ((DrvVer and $ff0000) shr 16);
    Minor1 := ((DrvVer and $ff00) shr 8);
    Build := (DrvVer and $ffff);
    PrintStrLn(Format('Driver Version: %d.%d.%d.%d',[Major,Minor,Minor1,Build]));
    try
        PrintStr('Create Context... ');
        ePas11.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
  ePas11.CloseDevice();
  ePas11.DeleteContext();
end;

procedure TForm1.BtnDeviceClick(Sender: TObject);
var
    AppID:OleVariant;
    pAppID:^BYTE;
begin
    pAppID := nil;
    try
        PrintStr('Open Device...');
        ePas11.OpenDevice(EPAS_OPEN_FIRST,AppID );
        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..40] of BYTE;
    Prop:array [0..40] of BYTE;
    RefData:WideString;
    SerialNum1:WideString;
    Prop1:WideString;
    Prop2:WideString;
    Prop3:WideString;
    RefDataLen:Integer;

    VerInfo:WVersionInfo;
    SysInfo:WSysInfo;
    AccessInfo:WAccessInfo;
    pGuid:^TGUID;
    pIntValue:^integer;
begin
    RefDataLen := 128;
    RefData:='';
    try
        PrintStr('Get Serial Number...');
        SerialNum1 := ePas11.GetProperty(EPAS_PROP_SERNUM,RefData,RefDataLen);
        ReportSucc;
//        DumpBuf(SerialNum,8);
        PrintStrLn(SerialNum1);

        try
            PrintStr('Get token name...');
            Prop1 := ePas11.GetProperty(EPAS_PROP_FRIENDLY_NAME,RefData,RefDataLen);
            ReportSucc();
//            DumpBuf(prop,EPAS_FRIENDLY_NAME_SIZE);
            PrintStrLn(Prop1);
        except
           on e:EOleSysError do
            begin
                 ReportErr(e.ErrorCode);
            end;
        end;
        PrintStr('Get the version information');
        ZeroMemory(@SysInfo,SizeOf(SysInfo));
        pGuid := @VerInfo;
        ePas11.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]));

        Prop1:='';
        try
          PrintStr('Get Memory Size');
          Prop1 :=ePas11.GetProperty(EPAS_PROP_MEM_SIZE, RefData,RefDataLen);
          ReportSucc();
//          pIntValue := @Prop[0];
          PrintStrLn('Memory size ............. :'+Prop1);
        except
           on e:EOleSysError do
            begin
                 ReportErr(e.ErrorCode);
           end;
        end;
        PrintStr('Get system information');
        ZeroMemory(@SysInfo,SizeOf(SysInfo));
        pGuid := @SysInfo;
        ePas11.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;
        ePas11.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');
        Prop3:=ePas11.GetProperty(EPAS_PROP_CAPABILITIES, RefData,RefDataLen);
        ReportSucc;
//        pIntValue := @Prop[0];

        PrintStrLn('Capabilities ............ :'+Prop3);

        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;
    DemoWrite:Variant;
    DemoRead:Variant;
begin
//    RemoveDemoDir();
    try

        if(not CreateDemoDir($400)) 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');
        ePas11.CreateFile(0,epsFileInfo);
        ReportSucc;

        DemoWrite := VarArrayCreate([0,512], varByte	);
        DemoWrite[0]:=$31;
        DemoWrite[1]:=$32;
        DemoWrite[2]:=$33;
        DemoWrite[3]:=$34;
        DemoWrite[4]:=$35;
        DemoWrite[5]:=$36;

        PrintStr('Write something to the demo-file');
        ePas11.Write(0,0,DemoWrite, 6, cbWritten);
        ReportSucc;


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

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

        PrintStr('Read from the demo-file');
        DemoRead := ePas11.Read(0,0,epsFileInfo.lFileSize,cbRead);
        ReportSucc;

        DumpBuf(demoStrArray,length(demoStr));

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

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

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

function TForm1.HexStrToBuf(strData:string;var binBuf:array of byte):integer;
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;
    result := i;
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,hDigest:OleVariant;
    key1,key2,digest,softDigest:array [0..15] of byte;
    text:array[0..55] of byte;
    cbWritten:integer;
    cbKey1:integer;
    cbKey2:integer;
    i : integer;
    varKey1:Variant;
    varKey2:Variant;

begin
    try
        CreateDemoDir($800);

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

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

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

        cbKey1 := HexStrToBuf(strKey1,key1);
        cbKey2 :=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;
        epsFileInfo.ucGrantedAccess:=EPAS_ACCESS_CRYPT;

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

        pByteData := @key1;
        DumpBuf(pByteData^,16);
        varKey1 := VarArrayCreate([0,256], varByte);
        for i := 0 to cbKey1-1 do
        begin
            varKey1[i] :=  key1[i];
        end;
        PrintStr('Save to first key file');
        ePas11.Write(0,0,varKey1, 16, cbWritten);
        ReportSucc;

        PrintStr('Close the demo-file');
        ePas11.CloseFile;
        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;
        epsFileInfo.ucGrantedAccess:=EPAS_ACCESS_CRYPT;

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

        pByteData := @key2;
        DumpBuf(pByteData^,16);
        varKey2 := VarArrayCreate([0,256], varByte);
        for i := 0 to cbKey2-1 do
        begin
            varKey2[i] :=  key2[i];
        end;
        PrintStr('Save to second key file');
        ePas11.Write(0,0,varKey2, 16, cbWritten);
        ReportSucc;


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

        wstrText := 'Rndtext';
        PrintStr('MD5_HMAC compute by software');
        strDigest := 'Empty';
        Hash1.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');
        ePas11.MD5HMAC($1234,$2345,wstrText,length(wstrText),hDigest);
        ReportSucc;
        HexStrToBuf(hDigest,digest);

        DumpBuf(digest,16);

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

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

end.

