Recent

Author Topic: TCryptManager Proposal for the FPC RTL  (Read 5973 times)

abouchez

  • Full Member
  • ***
  • Posts: 110
    • Synopse
TCryptManager Proposal for the FPC RTL
« on: November 16, 2021, 05:41:58 pm »
Following a discussion with Michael.
https://gitlab.com/freepascal.org/fpc/source/-/commit/3229cb712e33374b85258aed43726058be633bed#note_734503343

Here is a proposal of RTL-level hooks for cryptography.
Idea is to propose a default pascal and cross-platform implementation, with an optional overwrite with optimized alternatives (GnuTLS, OpenSSL, mORMot).
It is implemented as a set of classes, and an internal thread-safe list of case-insensitive identifiers to register the actual implementations.

Here is a first draft, to something which may be possible:
Code: Pascal  [Select][+][-]
  1. type
  2.   ECrypt = class(Exception);
  3.   TCryptIDClass = class of TCryptID;
  4.  
  5.   // abstract class implemented e.g. by TCryptRandom/TCryptSymmetric
  6.   TCryptID = class(TObject)
  7.   protected
  8.     fName: string;
  9.     // case-insensitive quick lookup of the algorithms
  10.     class function InternalFind(const aName: string): TCryptID; virtual; abstract;
  11.   public
  12.     // internal constructor: use Find() instead
  13.     constructor Create(const aName: string); virtual; abstract;
  14.     /// register this class to override one or several identifiers implementation
  15.     class procedure Implements(const aName: array of string); virtual; abstract;
  16.     // typical values may follow OpenSSL naming, e.g. 'MD5', 'AES-128-GCM' or
  17.     // 'prime256v1'
  18.     property Name: string read fName;
  19.   end;
  20.  
  21.   // abstract class implemented e.g. by TCryptHash/TCryptCipher/TCryptKey
  22.   TCryptInstance = class(TObject)
  23.   protected
  24.     fCryptID: TCryptID;
  25.   public
  26.     constructor Create(aCryptID: TCryptID); overload; virtual; abstract;
  27.     constructor Create(const aName: string); overload; virtual; abstract;
  28.     /// register this class to override one or several identifiers implementation
  29.     class procedure Implements(const aName: array of string); virtual; abstract;
  30.     function Clone: TCryptInstance; virtual; abstract;
  31.     property CryptID: TCryptID read fCryptID;
  32.   end;
  33.  
  34.   TCryptRandom = class(TCryptID)
  35.   public
  36.     // case-insensitive quick lookup of the algorithms
  37.     // use TCryptRandom.Find('rnd-entropy').GetRandom() gather OS entropy
  38.     class function Find(const aName: string = 'rnd-default'): TCryptRandom; virtual; abstract;
  39.     procedure GetRandom(dst: pointer; dstlen: PtrInt); virtual; abstract;
  40.   end;
  41.  
  42.   TCryptHash = class(TCryptInstance)
  43.   public
  44.     // hashing methods
  45.     procedure Update(buf: pointer; buflen: PtrInt); virtual; abstract;
  46.     procedure Final(digest: pointer; digestlen: PtrInt); virtual; abstract;
  47.   end;
  48.  
  49.   TCryptCipher = class(TCryptInstance)
  50.   public
  51.     // dst=nil for AEAD
  52.     function Process(src, dst: pointer; srclen, dstlen: PtrInt): PtrInt; virtual; abstract;
  53.     function Final(dst, tag: pointer; dstlen, taglen: PtrInt): PtrInt; virtual; abstract;
  54.   end;
  55.  
  56.   TCryptKey = class(TCryptInstance)
  57.   public
  58.     function Retrieve(buf: pointer; buflen: PtrInt): boolean; virtual; abstract;
  59.    { TODO: other persistence methods, and overloaded Create }
  60.   end;
  61.   { NOTE: as alternative, we may just use TCryptKey = TBytes }
  62.  
  63.   TCryptSymmetric = class(TCryptID)
  64.   public
  65.     // case-insensitive quick lookup of the algorithms
  66.     class function Find(const aName: string): TCryptSymmetric; virtual; abstract;
  67.     // public key cryptography methods
  68.     function MakeKeyPair(pub, priv: pointer; publen, privlen: PtrInt): boolean; virtual; abstract;
  69.     function NewKey(key: pointer; keylen: PtrInt; pub: boolean): TCryptKey; virtual; abstract;
  70.     procedure Sign(priv: TCryptKey; hash, sign: pointer; hashlen, signlen: PtrInt); virtual; abstract;
  71.     function Verify(pub: TCryptKey; hash, sign: pointer; hashlen, signlen: PtrInt): boolean; virtual; abstract;
  72.     procedure SharedSecret(priv, pub: TCryptKey; secret: pointer; secretlen: PtrInt); virtual; abstract;
  73.   end;
  74.  
  75.   { TODO: abstract PKI manager? }
  76.  
« Last Edit: November 16, 2021, 05:44:31 pm by abouchez »

MvC

  • New Member
  • *
  • Posts: 25
    • Free Pascal Core team member
Re: TCryptManager Proposal for the FPC RTL
« Reply #1 on: November 16, 2021, 06:19:08 pm »
Looks good at first sight.
Maybe an extra init for the hash, so a single instance can be reused.

We can add some overloads with TBytes/String for convenience.

What would you put in the PKI manager ?

abouchez

  • Full Member
  • ***
  • Posts: 110
    • Synopse
Re: TCryptManager Proposal for the FPC RTL
« Reply #2 on: November 18, 2021, 10:04:04 pm »
I have implemented a full set of classes and interfaces in mORMot 2.
It could be used as a reference - the dependencies with mORMot are very small, and could easily be replaced for the RTL.

There is abstract classes, then a set of inherited classes which calls the mORMot engines.
It should cover most usecases about random generators, hashing, signing, encryption and public key cryptography.
The use of interfaces for hash and encryption instances allow a fluent and simple call in end user code.
The classes and methods have been designed to reuse as much code as possible, but also been safe from use.

Please check this commit:
https://github.com/synopse/mORMot2/commit/2b5ca9ae4162bfd65ffa7e61fac1ffdb6dd46350

MvC

  • New Member
  • *
  • Posts: 25
    • Free Pascal Core team member
Re: TCryptManager Proposal for the FPC RTL
« Reply #3 on: November 24, 2021, 11:54:35 am »
This looks good.

I will do some refactoring - mostly remove the JSON support but in essence these classes look good.

The global functions can maybe be moved/copied to class methods of  TCryptAlgo

There is some other new news: DCPCrypt is abandoned.

I have received permission from the original author to distribute it under FPC with the standard FPC license,
 so this can serve as the 'basic' implementation for many of the algorithms.
With the factory methods, we can always register more performant algorithms, but by default FPC will come with a pretty complete hash/cypher suite.

 

TinyPortal © 2005-2018