Sample code for 30+ languages & platforms
Pascal (Lazarus/Delphi)

ECDSA Sign and Verify

See more ECC Examples

Demonstrates how to create an ECDSA signature on the SHA256 hash of some data, and then verify.

Chilkat Pascal (Lazarus/Delphi) Downloads

Pascal (Lazarus/Delphi)
program ChilkatDemo;

// Demonstrates using the Chilkat Pascal wrapper via the C bridge DLL.
// Builds as a console application under Lazarus (FPC) or Delphi.

{$IFDEF FPC}
  {$MODE DELPHI}
{$ENDIF}
{$APPTYPE CONSOLE}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  SysUtils,
  CkDllLoader,
  Chilkat.Asn,
  Chilkat.Prng,
  Chilkat.BinData,
  Chilkat.PrivateKey,
  Chilkat.PublicKey,
  Chilkat.Xml,
  Chilkat.Crypt2,
  Chilkat.Ecc;

// ---------------------------------------------------------------------------

procedure RunDemo;
var
  success: Boolean;
  privKey: TPrivateKey;
  bd: TBinData;
  crypt: TCrypt2;
  hashStr: string;
  ecdsa: TEcc;
  prng: TPrng;
  sig: string;
  asn: TAsn;
  xml: TXml;
  r: string;
  s: string;
  pubKey: TPublicKey;
  ecc2: TEcc;
  result: Integer;
  xml2: TXml;
  asn2: TAsn;
  encodedSig: string;

begin
  success := False;

  //  This example assumes the Chilkat API to have been previously unlocked.
  //  See Global Unlock Sample for sample code.

  //  First load an ECDSA private key to be used for signing.
  privKey := TPrivateKey.Create;
  success := privKey.LoadEncryptedPemFile('qa_data/ecc/secp256r1-key-pkcs8-secret.pem','secret');
  if (success = False) then
    begin
      WriteLn(privKey.LastErrorText);
      Exit;
    end;

  //  Sign the SHA256 hash of some data.
  bd := TBinData.Create;
  success := bd.LoadFile('qa_data/hamlet.xml');
  if (success = False) then
    begin
      WriteLn('Failed to load file to be hashed.');
      Exit;
    end;

  crypt := TCrypt2.Create;
  crypt.HashAlgorithm := 'sha256';
  crypt.EncodingMode := 'base64';
  hashStr := crypt.HashBdENC(bd);

  ecdsa := TEcc.Create;
  prng := TPrng.Create;
  //  Returns ASN.1 signature as a base64 string.
  sig := ecdsa.SignHashENC(hashStr,'base64',privKey,prng);
  WriteLn('sig = ' + sig);

  //  The signature is in ASN.1 format (which may be described as the "encoded DSS signature").
  //  SEQUENCE (2 elem)
  //    INTEGER (255 bit) 4849395540832462044300553275435608522154141569743642905628579547100940...
  //    INTEGER (255 bit) 3680701124244788134409868118208591399799457104230118295614152238560005...

  //  If you wish, you can get the r and s components of the signature like this:
  asn := TAsn.Create;
  asn.LoadEncoded(sig,'base64');
  xml := TXml.Create;
  xml.LoadXml(asn.AsnToXml());

  WriteLn(xml.GetXml());

  //  We now have this:
  //  <?xml version="1.0" encoding="utf-8"?>
  //  <sequence>
  //      <int>6650D422D86BA4A228B5617604E59052591B9B2C32EF324C44D09EF67E5F0060</int>
  //      <int>0CFD9F6AC85042FC70F672C141BA6B2A4CAFBB906C3D907BCCC1BED62B28326F</int>
  //  </sequence>

  //  Get the "r" and "s" as hex strings
  r := xml.GetChildContentByIndex(0);
  s := xml.GetChildContentByIndex(1);

  WriteLn('r = ' + r);
  WriteLn('s = ' + s);

  //  --------------------------------------------------------------------
  //  Now verify against the hash of the original data.

  //  Get the corresponding public key.
  pubKey := TPublicKey.Create;
  success := pubKey.LoadFromFile('qa_data/ecc/secp256r1-pub.pem');
  if (success = False) then
    begin
      WriteLn(pubKey.LastErrorText);
      Exit;
    end;

  //  We already have the SHA256 hash of the original data (hashStr) so no need to re-do it..
  ecc2 := TEcc.Create;
  result := ecc2.VerifyHashENC(hashStr,sig,'base64',pubKey);
  if (result <> 1) then
    begin
      WriteLn(ecc2.LastErrorText);
      Exit;
    end;

  WriteLn('Verified!');

  //  Note: If we have only r,s and wish to reconstruct the ASN.1 signature, we do it like this:
  xml2 := TXml.Create;
  xml2.Tag := 'sequence';
  xml2.NewChild2('int',r);
  xml2.NewChild2('int',s);

  asn2 := TAsn.Create;
  asn2.LoadAsnXml(xml2.GetXml());
  encodedSig := asn2.GetEncodedDer('base64');
  WriteLn('encoded DSS signature: ' + encodedSig);

  //  You can go to https://lapo.it/asn1js/  and copy/paste the base64 encodedSig into the online tool, then press the "decode" button.
  //  You will see the ASN.1 such as this:

  //  SEQUENCE (2 elem)
  //    INTEGER (255 bit) 4849395540832462044300553275435608522154141569743642905628579547100940...
  //    INTEGER (255 bit) 3680701124244788134409868118208591399799457104230118295614152238560005...


  privKey.Free;
  bd.Free;
  crypt.Free;
  ecdsa.Free;
  prng.Free;
  asn.Free;
  xml.Free;
  pubKey.Free;
  ecc2.Free;
  xml2.Free;
  asn2.Free;

end;

// ---------------------------------------------------------------------------

begin

  try
    RunDemo;
  except
    on E: Exception do
      WriteLn('Unhandled exception: ', E.ClassName, ': ', E.Message);
  end;

  WriteLn;
  {$IFDEF MSWINDOWS}
  WriteLn('Press Enter to exit...');
  ReadLn;
  {$ENDIF}
end.