YOUSEFUL / DELPHI / COMPONENTS

TAtlasEcdsa

ECDSA signatures on the NIST P-256 curve with SHA-256, and conversion of public keys to and from X/Y coordinates.

Class Unit Atlas.CryptoKeys · Inherits TObject · Product Atlas Crypto

Description

Sign with the private key, verify with the public key. The data is hashed with SHA-256 inside Sign and Verify; pass the data itself, not a digest. Signatures are 64 bytes, r followed by s (the IEEE P1363 form CNG produces); DER-encoded signatures, as some libraries and certificate formats use, are not supported. ECDSA signatures are randomised, so signing the same data twice gives different signatures, both valid.

Verify returns False for a signature that does not match, but raises EAtlasCryptoError when the public key itself is unusable, so a configuration fault cannot look like a bad signature. The tests verify the published RFC 6979 appendix A.2.5 signature. ECDSA keys cannot be used with TAtlasEcdh, nor the other way round.

Members

MemberKindWhat it does
SignatureSizefieldThe signature length in bytes: 32 for r, 32 for s.
GenerateKeyPairmethodReturns a new P-256 key pair (72-byte public blob, 104-byte private blob).
SignmethodReturns the 64-byte signature of the SHA-256 digest of Data.
VerifymethodTrue when Signature was made over Data by the private key matching PublicKey.
PublicKeyFromXYmethodBuilds a public key blob from the affine coordinates of a point, 32 bytes each, big-endian, as other systems publish them.
PublicKeyToXYmethodSplits a P-256 ECDSA public key blob into its 32-byte X and Y coordinates.

Methods

GenerateKeyPair method

class function GenerateKeyPair: TAtlasKeyPair; static;

Returns a new P-256 key pair (72-byte public blob, 104-byte private blob).

pascal
Pair := TAtlasEcdsa.GenerateKeyPair;

Sign method

class function Sign(const PrivateKey, Data: TBytes): TBytes; static;

Returns the 64-byte signature of the SHA-256 digest of Data. Data may be empty. A blob that is not a P-256 ECDSA private key raises EAtlasCryptoError.

pascal
Signature := TAtlasEcdsa.Sign(Pair.PrivateKey, Data);

Verify method

class function Verify(const PublicKey, Data, Signature: TBytes): Boolean; static;

True when Signature was made over Data by the private key matching PublicKey. False for altered data, another key, an altered signature or a signature that is not 64 bytes. Raises EAtlasCryptoError when PublicKey is not a usable P-256 ECDSA public key.

pascal
Valid := TAtlasEcdsa.Verify(Pair.PublicKey, Data, Signature);

PublicKeyFromXY method

class function PublicKeyFromXY(const X, Y: TBytes): TBytes; static;

Builds a public key blob from the affine coordinates of a point, 32 bytes each, big-endian, as other systems publish them. The key is imported once to prove the point is on the curve; a point that is not, or coordinates of another length, raise EAtlasCryptoError.

pascal
Data := TAtlasEcdsa.PublicKeyFromXY(X, Y);

PublicKeyToXY method

class procedure PublicKeyToXY(const PublicKey: TBytes; out X, Y: TBytes); static;

Splits a P-256 ECDSA public key blob into its 32-byte X and Y coordinates. Anything else, an ECDH public key included, raises EAtlasCryptoError (Not a P-256 ECDSA public key).

pascal
TAtlasEcdsa.PublicKeyToXY(Pair.PublicKey, X, Y);

Fields

SignatureSize field

const SignatureSize = 64;

The signature length in bytes: 32 for r, 32 for s.

Examples

Verify a signature published by another implementation

RFC 6979 appendix A.2.5 gives a P-256 public key as coordinates and a SHA-256 signature of sample. Prints TRUE, then FALSE for a different message.

pascal
uses System.SysUtils, Atlas.Crypto, Atlas.CryptoKeys;

procedure VerifyPublishedSignature;
var
  PublicKey, Signature: TBytes;
begin
  PublicKey := TAtlasEcdsa.PublicKeyFromXY(
    TAtlasBytes.FromHex('60FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB6'),
    TAtlasBytes.FromHex('7903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299'));
  Signature := TAtlasBytes.FromHex('EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716' +
    'F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8');
  WriteLn(TAtlasEcdsa.Verify(PublicKey, TAtlasBytes.OfString('sample'), Signature));
  WriteLn(TAtlasEcdsa.Verify(PublicKey, TAtlasBytes.OfString('Sample'), Signature));
end;

Sign a file and publish the public key as coordinates

Signs the bytes of a file and prints the public key as two 64-digit hexadecimal numbers that anyone can use to rebuild it with PublicKeyFromXY. Prints the coordinates and TRUE.

pascal
uses System.SysUtils, System.IOUtils, Atlas.Crypto, Atlas.CryptoKeys;

procedure SignAFile;
var
  Pair: TAtlasKeyPair;
  FileName: string;
  Signature, X, Y: TBytes;
begin
  FileName := TPath.Combine(TPath.GetTempPath, 'atlas-crypto-release.txt');
  TFile.WriteAllBytes(FileName, TAtlasBytes.OfString('release 4.2'));
  Pair := TAtlasEcdsa.GenerateKeyPair;
  try
    Signature := TAtlasEcdsa.Sign(Pair.PrivateKey, TFile.ReadAllBytes(FileName));
    TAtlasEcdsa.PublicKeyToXY(Pair.PublicKey, X, Y);
    WriteLn('X = ', TAtlasBytes.ToHex(X));
    WriteLn('Y = ', TAtlasBytes.ToHex(Y));
    WriteLn(TAtlasEcdsa.Verify(TAtlasEcdsa.PublicKeyFromXY(X, Y), TFile.ReadAllBytes(FileName), Signature));
  finally
    Pair.Wipe;
    TFile.Delete(FileName);
  end;
end;

TAtlasKeyPair · TAtlasEcdh · TAtlasRsa

Also in Atlas Crypto

TAtlasHashCalculator · TAtlasFileProtector