CryptoSys Home > Using Delphi and FreePascal

Using Delphi and Free Pascal with CryptoSys Products


It is possible to call all the functions in our cryptographic products CryptoSys API, CryptoSys PKI, FirmaSAT and SC14N from Delphi and Free Pascal. This page explains what we know and gives some sample code.

Summary | Changes since 2010 | CryptoSys API | CryptoSys PKI | FirmaSAT | SC14N | Notes for programmers | Compiling | Acknowledgements | Disclaimer | Contact

New 2023-11-012023-11-01: Added interface for CryptoSys PKI (code dated 2023-10-12)

New 2023-04-142023-04-14: Added interface for SC14N.

2023-04-14: All the code on this page has been re-tested as of April 2023. It all compiles for us using the Free Pascal Compiler version 3.2.2 for i386 in Delphi compatibility mode. YMMV. Please read the Disclaimer below.

2021-01-16: Added recommendations on pointers by Christian Aymon [**].

If it works for you, please use it. If you have any corrections or useful suggestions, we'd be delighted to hear from you. Please send us a message.

 

The code and links on this page are all the Delphi code we have. For more info on creating interfaces see Writing an interface in another programming language.

The test code samples give a small set of tests to demonstrate representative functions for each interface. You should be able to figure out how to use the other functions from the examples given.

Summary of source code files

  CryptoSys API CryptoSys PKI FirmaSAT SC14N
Unit diCryptoSys.pas diCrPKI.pas diFirmaSat.pas diSc14n.pas
Tests TestCrSysAPI.pas TestCrSysPKI.pas TestFirmaSat.pas TestSc14n.pas
Download zip zip zip zip
Last updated 2016-01-27 2023-10-12 2016-01-27 2023-04-14

Doesn't compile for you? See compiling.

Changes since 2010

2016-01-27: Changes since we first published the Delphi interface in 2010.

CryptoSys API

Here is a Delphi/FreePascal interface to all the functions in CryptoSys API with some representative tests: diCryptoSys.pas.zip. The function declarations and associated constants are in the file diCryptoSys.pas. Please read the Disclaimer below.

For more information on the CryptoSys API function parameters and return values, see the C include file diCryptoSys.h and the Main manual.

You need to have installed CryptoSys API on your system. See the CryptoSys API home page.

Another example: This sample code shows how to use the functions CIPHER_EncryptBytesPad and CIPHER_DecryptBytesPad using Aes128/CBC/pkcs5, along with some utilities for converting between arrays of bytes, hex-encoded strings and AnsiStrings. Note that this particular code will also work in CryptoSys PKI Pro if you replace uses SysUtils, diCryptoSys; by uses SysUtils, diCrPKI;.

CryptoSys PKI Pro

NewNew v22.0: Here is a Delphi/FreePascal interface to all the functions in CryptoSys PKI with some representative tests: diCrPKI.pas.zip. The function declarations and associated constants are in the file diCrPKI.pas. Please read the Disclaimer below.

For more information on the CryptoSys PKI function parameters and return values, see the C include file diCrPKI.h and the Main manual.

You need to have installed CryptoSys PKI on your system. See the CryptoSys PKI home page.

Pedro Miguel Martins has provided some code in Delphi that uses the Delphi interface to CryptoSys PKI to compute an RSA signature using the test key for the Portugal General Directorate of Taxes (Direcção Geral dos Impostos). See Portugal DGCI Delphi Code.

FirmaSAT

Here is a Delphi/FreePascal interface to all the functions in FirmaSAT with some representative tests: diFirmaSat.pas.zip. The function declarations and associated constants are in the file diFirmaSat.pas. Please read the Disclaimer below.

For more information on the FirmaSAT function parameters and return values, see the C include file diFirmaSat2.h and the manual.

You need to have installed FirmaSAT on your system. For more information see the FirmaSAT home page.

Note that the tests in TestFirmaSat require certain files to exist in a specified directory. The test files are provided in the zip file above. The directory is hardcoded in the code.

const
  TEST_DIR = 'C:\Test\Muestra';

- please edit this to suit your system.

Note also that these test files are now old (2016), but the Pascal functions are still compatible with the latest versions of FirmaSAT.

SC14N

Here is a Delphi/FreePascal interface to all the functions in SC14N with some representative tests. The function declarations and associated constants are in the file diSc14n.pas and the tests are in TestSc14n.pas.

These are included in diSc14n.pas.zip along with a test XML file. Please read the Disclaimer below.

For more information on the SC14N function parameters and return values, see the C include file diSc14n.h and the Documentation.

Note that all strings used in this Delphi interface are single-byte AnsiString. To pass UTF-8 XML data in a string, you must encode any Wide or Unicode string to UTF-8 bytes in an AnsiString.

You need to have installed SC14N on your system. See the SC14N home page.

Notes for programmers

Variable types used in the interface:

C++ TypeVBA TypeDelphi TypeDescription
long, int Long LongInt A signed 32-bit integer, passed by value
const char *sz String AnsiString ANSI string: a string of single-byte non-zero characters terminated by a zero byte
unsigned char *lp Byte Array of Byte Byte array: an ordered sequence of single-byte values of any value in the range [0,255]
  1. All integer variables passed to our DLLs (and return values from them) must be of type LongInt, a 32-bit signed integer.
  2. All strings are of type AnsiString. Attempting to pass a "default" Unicode or Wide String will not work.
  3. Byte arrays should be of type Array of Byte.
  4. Strings and byte arrays that receive output need to be pre-dimensioned to the correct length before calling a DLL function. Then pass a Pointer as the parameter (but see [**/1] below).
    function FOO_StringFunction(szOutput : PAnsiChar; nMaxChars : LongInt; szData : AnsiString) : LongInt;
    function FOO_ByteFunction(lpOutput : PByte; nOutBytes : LongInt; lpInput : PByte; nInputLen : LongInt) : LongInt;
    
    strbuf : AnsiString;
    //...
    strbuf := AnsiString(StringOfChar(#0, nchars));
    ret := FOO_StringFunction(Pointer(strbuf), nchars, ...);  // See [**/2] below
    ret := FOO_StringFunction(PAnsiChar(strbuf), nchars, ...);
    
    
    arrbytes : Array of Byte;
    //...
    SetLength(arrbytes, nbytes);
    ret := FOO_ByteFunction(Pointer(arrbytes), nbytes, ...);
    // OR - See [**/3] below.
    ret := FOO_ByteFunction(Addr(arrbytes[0]), nbytes, ...);
    
    These output parameters are expected as PAnsiChar and PByte respectively.
  5. Constant strings passed as input can be simply passed as an AnsiString type. Constant byte arrays passed as input still need to be passed as a pointer.
    szData : AnsiString;
    //...
    ret := FOO_StringFunction(PAnsiChar(strbuf), nchars, szData);
    
    lpData : Array of Byte;
    //...
    ret := FOO_ByteFunction(Pointer(arrbytes), nbytes, Pointer(lpData), Length(lpData));
    
    In fact, you can pass a pointer to an AnsiString as an argument to a function expecting a byte array as input.
    S : AnsiString;
    //...
    S = 'abc';
    ret := FOO_ByteFunction(Pointer(arrbytes), nbytes, Pointer(S), Length(S));
    
  6. To pass a null pointer to either an AnsiString or Array of Byte, use the Delphi NIL value, as in
    nchars := SAT_CompileTime(NIL, 0);
    
  7. Depending on how you've defined your byte arrays, you pass pointers to them differently,
    abKey : Array of Byte;
    tag   : Array[0..15] of Byte;
    //...
    ret := GCM_Encrypt(NIL, 0, @tag[0], Length(tag), NIL, 0,
      Pointer(abKey), Length(abKey),...);
    
    Update: [**/4] - You can use Addr(x[0]) in both cases.
  8. For a reason we haven't worked out yet, re-using a dynamic byte array variable after writing to it in a DLL function can give erroneous results unless you re-do the SetLength operation
    SetLength(abOut, Length(abIn));
    
  9. The _UpdateHex functions which update a string parameter in situ don't work properly in Delphi/Pascal, so don't use them.
  10. CAUTION: When pre-dimensioning string types to receive output, we recommend you always use the construction
    strbuf := AnsiString(StringOfChar(#0, nchars));
    
    where nchars is the maximum number of characters you require in the string. The above code will automatically add the extra character to the storage for the null byte, which will be added automatically by the DLL. This is equivalent to the VBA code used in the manual
    strbuf = String(nchars, " ")
    

    BUT if instead you use

    SetLength(strbuf, nchars);
    
    the buffer will be too short by one and will (eventually, maybe, sometimes) cause a GPF error (you should have used nchars+1). However, using SetLength for a byte array is OK, though
  11. [**] Updated where noted on recommendations from Christian Aymon. Thanks, Christian.
    1. I would avoid the Pointer(x) construction.
    2. I would use PAnsiChar(strbuf) instead of Pointer(strbuf).
    3. Instead of Pointer(arrbytes) I would use Addr(arrbytes[0]).
    4. You can use Addr(x[0]) in both cases.

Compiling

We compiled and ran all these examples using FPC version 3.2.2 on the command line. All the interface unit files were in the current working directory.


>fpc TestCrSysAPI.pas
Free Pascal Compiler version 3.2.2 [2021/05/15] for i386
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling TestCrSysAPI.pas
Linking TestCrSysAPI.exe
537 lines compiled, 0.2 sec, 89760 bytes code, 4756 bytes data

>TestCrSysAPI
Running testcrsysapi.exe at 14/04/2023 19:08:33

GENERAL:
Interrogate the core diCryptoSys DLL:
API_Version=62000
...

If you run the tests in an IDE you may need to add a ReadLn statement to the main procedure.

Acknowledgements

Thanks to Sebastian Jäschke and Humberto Souza for their help in providing example Delphi interfaces to CryptoSys API, without which we would not have been able to get started, and to Cesar Ruiz for his feedback, and Dr Richard Koch and Christian Aymon. Thanks, too, to Neil Moffatt for his excellent Delphi Basics site.

Disclaimer

We do not offer to support or maintain any code on this page or provide any updates to reflect changes in the underlying CryptoSys libraries. We just provide this sample code as is. We will try and help if we can (if you ask nicely). Use at your own risk with no warranties. The code on this page is offered for free in good faith but may contain traces of nuts and/or errors. Before purchasing any of our products, please carry out whatever checks with the free Trial Edition to satisfy yourself it does what you require.

Contact

For more information or to comment on this page, please send us a message.

This page first published 13 March 2010. Last updated 1 November 2023.