forked from synopse/mORMot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SynEcc.pas
5558 lines (5111 loc) · 214 KB
/
SynEcc.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/// certificate-based public-key cryptography using ECC-secp256r1
// - this unit is a part of the freeware Synopse mORMot framework,
// licensed under a MPL/GPL/LGPL tri-license; version 1.18
unit SynEcc;
(*
This file is part of Synopse framework.
Synopse framework. Copyright (C) 2021 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
Version: MPL 1.1/GPL 2.0/LGPL 2.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.
The Original Code is Synopse framework.
The Initial Developer of the Original Code is Arnaud Bouchez.
Portions created by the Initial Developer are Copyright (C) 2021
the Initial Developer. All Rights Reserved.
Contributor(s):
- Kenneth MacKay (easy-ecc source code)
Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
in which case the provisions of the GPL or the LGPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of either the GPL or the LGPL, and not to allow others to
use your version of this file under the terms of the MPL, indicate your
decision by deleting the provisions above and replace them with the notice
and other provisions required by the GPL or the LGPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****
Using secp256r1 curve from "simple and secure ECDH and ECDSA library"
Copyright (c) 2013, Kenneth MacKay - BSD 2-clause license
https://github.com/esxgx/easy-ecc
*** BEGIN LICENSE BLOCK *****
Copyright (c) 2013, Kenneth MacKay
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
***** END LICENSE BLOCK *****
TODO:
- secure sign-then-crypt by signing the destination name with the plain content
to avoid "Surreptitious Forwarding" (reuse of the plain content to another
recipier) - see http://world.std.com/~dtd/sign_encrypt/sign_encrypt7.html
*)
{$I Synopse.inc} // define HASINLINE CPU32 CPU64 OWNNORMTOUPPER
interface
uses
{$ifdef MSWINDOWS}
Windows, // for CriticalSection API inling
{$else} // for GetFileSize emulated API
{$ifdef KYLIX3}
SynKylix,
{$endif}
{$ifdef FPC}
SynFPCLinux,
{$endif}
{$endif MSWINDOWS}
SysUtils,
Classes,
Contnrs,
SynCommons,
SynTable,
SynCrypto;
{ *********** low-level ECC secp256r1 ECDSA and ECDH functions *********** }
{$ifdef CPUINTEL}
{$ifdef CPUX86}
{$ifdef KYLIX3}
{$define ECC_STATICLIB_AVAILABLE}
{$define ECC_32ASM} // gcc -g -O1 -c ecc.c
{$else}
{$ifndef BSD}
{$define ECC_STATICLIB_AVAILABLE}
{.$define ECC_32ASM} // gcc -g -O1 -c ecc.c
{.$define ECC_O1} // gcc -g -O1 -c ecc.c
{$define ECC_O2} // gcc -g -O2 -c ecc.c
{.$define ECC_O3} // gcc -g -O3 -c ecc.c
{$endif}
{$endif KYLIX}
{$endif CPUX86}
{$ifdef CPUX64}
{$ifndef BSD}
{$define ECC_STATICLIB_AVAILABLE}
{.$define ECC_O1} // gcc -g -O1 -c ecc.c
{$define ECC_O2} // gcc -g -O2 -c ecc.c
{.$define ECC_O3} // gcc -g -O3 -c ecc.c
{$endif}
{$endif CPUX64}
{$endif CPUINTEL}
const
/// the size of the 256-bit memory structure used for secp256r1
// - map 32 bytes of memory
ECC_BYTES = sizeof(THash256);
type
/// store a public key for ECC secp256r1 cryptography
// - use ecc_make_key() to generate such a key
// - stored in compressed form with its standard byte header, i.e. each
// public key consumes 33 bytes of memory
TECCPublicKey = array[0..ECC_BYTES] of byte;
/// store a public key for ECC secp256r1 cryptography
// - use ecc_uncompress_key_pas() to compute such a key from a TECCPublicKey
// - stored in uncompressed form, consuming 64 bytes of memory
TECCPublicKeyUncompressed = array[0..(ECC_BYTES*2)-1] of byte;
/// store a private key for ECC secp256r1 cryptography
// - use ecc_make_key() to generate such a key
// - stored in compressed form, i.e. each private key consumes 32 bytes of memory
TECCPrivateKey = array[0..ECC_BYTES-1] of byte;
/// store a 256-bit hash, as expected by ECC secp256r1 cryptography
// - see e.g. ecdsa_sign() and ecdsa_verify() functions
TECCHash = THash256;
/// store a signature, as generated by ECC secp256r1 cryptography
// - see e.g. ecdsa_sign() and ecdsa_verify() functions
// - contains ECDSA's R and S integers
// - each ECC signature consumes 64 bytes of memory
TECCSignature = array[0..(ECC_BYTES*2)-1] of byte;
/// store a signature, in the DER format
// - static allocated buffer as returned by EccSignToDer()
TEccSignatureDer = array[0..(ECC_BYTES * 2) + 7] of byte;
/// store an encryption key, as generated by ECC secp256r1 cryptography
// - use ecdh_shared_secret() to compute such a key from public/private keys
// - 256-bit / 32 bytes derivation from secp256r1 ECDH is expected to have at
// least 247 bits of entropy so could better be derivated via a KDF before used
// as encryption secret - see @http://crypto.stackexchange.com/a/9428/40200
TECCSecretKey = THash256;
PECCPublicKey = ^TECCPublicKey;
PECCPrivateKey = ^TECCPrivateKey;
PECCHash = ^TECCHash;
PECCSignature = ^TECCSignature;
PECCSecretKey = ^TECCSecretKey;
{$ifdef ECC_32ASM}
var
/// create a public/private key pair for further ECC cryptographic process
// - using secp256r1 curve, i.e. NIST P-256, or OpenSSL prime256v1
// - returns true if the key pair was generated successfully in pub/priv
// - returns false if an error occurred
ecc_make_key: function(out pub: TECCPublicKey; out priv: TECCPrivateKey): boolean; cdecl;
/// compute an ECDH shared secret given your secret key and someone else's public key
// - using secp256r1 curve, i.e. NIST P-256, or OpenSSL prime256v1
// - note: it is recommended that you hash the result of ecdh_shared_secret
// before using it for symmetric encryption or HMAC (via an intermediate KDF)
// - returns true if the shared secret was generated successfully in secret
// - returns false if an error occurred
ecdh_shared_secret: function(const pub: TECCPublicKey; const priv: TECCPrivateKey;
out secret: TECCSecretKey): boolean; cdecl;
/// generate an ECDSA signature for a given hash value
// - using secp256r1 curve, i.e. NIST P-256, or OpenSSL prime256v1
// - returns true if the signature generated successfully in sign
// - returns false if an error occurred
ecdsa_sign: function(const priv: TECCPrivateKey; const hash: TECCHash;
out sign: TECCSignature): boolean; cdecl;
/// verify an ECDSA signature
// - using secp256r1 curve, i.e. NIST P-256, or OpenSSL prime256v1
// - returns true if the signature is valid
// - returns false if it is invalid
ecdsa_verify: function(const pub: TECCPublicKey; const hash: TECCHash;
const sign: TECCSignature): boolean; cdecl;
{$else}
/// create a public/private key pair
// - using secp256r1 curve, i.e. NIST P-256, or OpenSSL prime256v1
// - directly low-level access to the statically linked easy-ecc library function
// - returns true if the key pair was generated successfully in pub/priv
// - returns false if an error occurred
// - this function is thread-safe and does not perform any memory allocation
function ecc_make_key(out pub: TECCPublicKey; out priv: TECCPrivateKey): boolean;
{$ifdef ECC_STATICLIB_AVAILABLE}cdecl;{$else}{$ifdef HASINLINE}inline;{$endif}{$endif}
/// compute a shared secret given your secret key and someone else's public key
// - using secp256r1 curve, i.e. NIST P-256, or OpenSSL prime256v1
// - directly low-level access to the statically linked easy-ecc library function
// - note: it is recommended that you hash the result of ecdh_shared_secret
// before using it for symmetric encryption or HMAC (via an intermediate KDF)
// - returns true if the shared secret was generated successfully in secret
// - returns false if an error occurred
// - this function is thread-safe and does not perform any memory allocation
function ecdh_shared_secret(const pub: TECCPublicKey; const priv: TECCPrivateKey;
out secret: TECCSecretKey): boolean;
{$ifdef ECC_STATICLIB_AVAILABLE}cdecl;{$else}{$ifdef HASINLINE}inline;{$endif}{$endif}
/// generate an ECDSA signature for a given hash value
// - using secp256r1 curve, i.e. NIST P-256, or OpenSSL prime256v1
// - directly low-level access to the statically linked easy-ecc library function
// - returns true if the signature generated successfully in sign
// - returns false if an error occurred
// - this function is thread-safe and does not perform any memory allocation
function ecdsa_sign(const priv: TECCPrivateKey; const hash: TECCHash;
out sign: TECCSignature): boolean;
{$ifdef ECC_STATICLIB_AVAILABLE}cdecl;{$else}{$ifdef HASINLINE}inline;{$endif}{$endif}
/// verify an ECDSA signature
// - using secp256r1 curve, i.e. NIST P-256, or OpenSSL prime256v1
// - directly low-level access to the statically linked easy-ecc library function
// - returns true if the signature is valid
// - returns false if an error occurred
// - this function is thread-safe and does not perform any memory allocation
function ecdsa_verify(const pub: TECCPublicKey; const hash: TECCHash;
const sign: TECCSignature): boolean;
{$ifdef ECC_STATICLIB_AVAILABLE}cdecl;{$else}{$ifdef HASINLINE}inline;{$endif}{$endif}
{$endif ECC_32ASM}
/// pascal function to create a secp256r1 public/private key pair
// - used only on targets (e.g. ARM/PPC) when the static .o version is not available
function ecc_make_key_pas(out PublicKey: TECCPublicKey; out PrivateKey: TECCPrivateKey): boolean;
/// pascal function to compute a secp256r1 shared secret given your secret key
// and someone else's public key (in compressed format)
// - used only on targets (e.g. ARM/PPC) when the static .o version is not available
function ecdh_shared_secret_pas(const PublicKey: TECCPublicKey;
const PrivateKey: TECCPrivateKey; out Secret: TECCSecretKey): boolean; overload;
/// pascal function to compute a secp256r1 shared secret given your secret key
// and someone else's public key (in uncompressed/flat format)
// - this overloaded function is slightly faster than the one using TECCPublicKey,
// since public key doesn't need to be uncompressed
function ecdh_shared_secret_pas(const PublicPoint: TECCPublicKeyUncompressed;
const PrivateKey: TECCPrivateKey; out Secret: TEccSecretKey): boolean; overload;
/// pascal function to generate an ECDSA secp256r1 signature for a given hash value
// - used only on targets (e.g. ARM/PPC) when the static .o version is not available
function ecdsa_sign_pas(const PrivateKey: TECCPrivateKey; const Hash: TECCHash;
out Signature: TECCSignature): boolean;
/// pascal function to verify an ECDSA secp256r1 signature from someone else's
// public key (in compressed format)
// - used only on targets (e.g. ARM/PPC) when the static .o version is not available
function ecdsa_verify_pas(const PublicKey: TECCPublicKey; const Hash: TECCHash;
const Signature: TECCSignature): boolean; overload;
/// pascal function to verify an ECDSA secp256r1 signature from someone else's
// public key (in uncompressed/flat format)
// - this overloaded function is slightly faster than the one using TECCPublicKey,
// since public key doesn't need to be uncompressed
function ecdsa_verify_pas(const PublicKey: TECCPublicKeyUncompressed;
const Hash: TECCHash; const Signature: TECCSignature): boolean; overload;
/// uncompress a public key for ECC secp256r1 cryptography
// - convert from its compressed form with its standard byte header
// (33 bytes of memory) into uncompressed/flat form (64 bytes of memory)
procedure ecc_uncompress_key_pas(const Compressed: TECCPublicKey;
out Uncompressed: TECCPublicKeyUncompressed);
{ *********** middle-level certificate-based public-key cryptography *********** }
type
/// used to identify a TECCCertificate
// - could be generated by TAESPRNG.Fill() method
TECCCertificateID = type THash128;
/// used to identify a TECCCertificate issuer
// - could be generated by AsciiToBaudot(), with truncation to 16 bytes
// (up to 25 Ascii-7 characters)
TECCCertificateIssuer = type THash128;
/// used to store a date in a TECCCertificate
// - i.e. 16-bit number of days since 1 August 2016
// - use NowECCDate, ECCDate(), ECCToDateTime() or ECCText() functions
TECCDate = word;
PECCCertificateID = ^TECCCertificateID;
PECCCertificateIssuer = ^TECCCertificateIssuer;
PECCDate = ^TECCDate;
/// the certification information of a TECCCertificate
// - as stored in TECCCertificateContent.Signed
// - defined in a separate record, to be digitaly signed in the Signature field
// - map TECCCertificate.Version 1 of the binary format
// - "self-signed" certificates may be used as "root" certificates in the
// TECCCertificateChain list
TECCCertificateSigned = packed record
/// when this certificate was generated
IssueDate: TECCDate;
/// certificate valid not before
ValidityStart: TECCDate;
/// certificate valid not after
ValidityEnd: TECCDate;
/// a genuine identifier for this certificate
// - is used later on to validate other certificates in chain
Serial: TECCCertificateID;
/// identify the certificate issuer
// - is either geniune random bytes, or some Baudot-encoded text
Issuer: TECCCertificateIssuer;
/// genuine identifier of the authority certificate used for signing
// - should be used to retrieve the associated PublicKey used to compute
// the Signature field
// - may equal Serial, if was self-signed
AuthoritySerial: TECCCertificateID;
/// identify the authoritify issuer used for signing
// - is either geniune random bytes, or some Baudot-encoded text
// - may equal Issuer, if was self-signed
AuthorityIssuer: TECCCertificateIssuer;
/// the ECDSA secp256r1 public key of this certificate
// - may be used later on for signing or key derivation
PublicKey: TECCPublicKey;
end;
/// points to certification information of a TECCCertificate
PECCCertificateSigned = ^TECCCertificateSigned;
/// store a TECCCertificate binary buffer for ECC secp256r1 cryptography
// - i.e. a certificate public key, with its ECDSA signature
// - would be stored in 173 bytes
TECCCertificateContent = packed record
/// the TECCCertificate format version
Version: word;
/// the certification information, digitaly signed in the Signature field
Signed: TECCCertificateSigned;
/// SHA-256 + ECDSA secp256r1 signature of the Certificate record
Signature: TECCSignature;
/// FNV-1a checksum of all previous fields
// - we use fnv32 and not crc32c here to avoid colision with crc64c hashing
// - avoiding to compute slow ECDSA verification in case of corruption,
// due e.g. to unexpected transmission/bug/fuzzing
// - should be the very last field in the record
CRC: cardinal;
end;
/// points to a TECCCertificate binary buffer for ECC secp256r1 cryptography
PECCCertificateContent = ^TECCCertificateContent;
/// store a TECCSignatureCertified binary buffer for ECDSA secp256r1 signature
// - i.e. the digital signature of some content
TECCSignatureCertifiedContent = packed record
/// the TECCSignatureCertificated format version
Version: word;
/// when this signature was generated
Date: TECCDate;
/// genuine identifier of the authority certificate used for signing
// - should be used to retrieve the associated PublicKey used to compute
// the Signature field
AuthoritySerial: TECCCertificateID;
/// identify the authoritify issuer used for signing
// - is either geniune random bytes, or some Baudot-encoded text
AuthorityIssuer: TECCCertificateIssuer;
/// SHA-256 + ECDSA secp256r1 digital signature of the content
Signature: TECCSignature;
end;
/// points to a TECCSignatureCertified buffer for ECDSA secp256r1 signature
PECCSignatureCertifiedContent = ^TECCSignatureCertifiedContent;
/// the known algorithms implemented in ECIES encryption
// - supports AES 256-bit encryption with safe block modes (weack ECB mode
// is not available) - or AES 128-bit if needed (e.g. for regulatory issues)
// - safe HMAC SHA-256 is used as Message Authentication Code algorithm
// - optional SynLZ compression can be enabled
TECIESAlgo = (
ecaUnknown,
ecaPBKDF2_HMAC_SHA256_AES256_CFB,
ecaPBKDF2_HMAC_SHA256_AES256_CBC,
ecaPBKDF2_HMAC_SHA256_AES256_OFB,
ecaPBKDF2_HMAC_SHA256_AES256_CTR,
ecaPBKDF2_HMAC_SHA256_AES256_CFB_SYNLZ,
ecaPBKDF2_HMAC_SHA256_AES256_CBC_SYNLZ,
ecaPBKDF2_HMAC_SHA256_AES256_OFB_SYNLZ,
ecaPBKDF2_HMAC_SHA256_AES256_CTR_SYNLZ,
ecaPBKDF2_HMAC_SHA256_AES128_CFB_SYNLZ,
ecaPBKDF2_HMAC_SHA256_AES128_CBC_SYNLZ,
ecaPBKDF2_HMAC_SHA256_AES128_OFB_SYNLZ,
ecaPBKDF2_HMAC_SHA256_AES128_CTR_SYNLZ,
ecaPBKDF2_HMAC_SHA256_AES128_CFB,
ecaPBKDF2_HMAC_SHA256_AES128_CBC,
ecaPBKDF2_HMAC_SHA256_AES128_OFB,
ecaPBKDF2_HMAC_SHA256_AES128_CTR);
/// binary header of a .synecc file, encrypted via ECC secp256r1
// - as generated by TECCCertificate.Encrypt/EncryptFile, and decoded by
// TECCCertificateSecret.Decrypt
// - a sign-then-encrypt pattern may have been implemented for additional safety
TECIESHeader = packed record
/// contains 'SynEccEncrypted'#26
// - so every .synecc file starts with those characters as signature
magic: THash128;
/// TECCCertificate.Issuer of the recipient public key used for encryption
// - is either geniune random bytes, or some Baudot-encoded text
rec: TECCCertificateIssuer;
/// TECCCertificate.Serial of the recipient public key used for encryption
recid: TECCCertificateID;
/// the size of the plain content (may be compressed before encryption)
size: cardinal;
/// when this encryption was performed
date: TECCDate;
/// optional timestamp, in Unix seconds since 1970, of the source file
unixts: cardinal;
/// actual encryption algorithm used
algo: TECIESAlgo;
/// the genuine random public key used for encryption
rndpub: TECCPublicKey;
/// optional ECDSA secp256r1 digital signature of the plain content
sign: TECCSignatureCertifiedContent;
/// the Message Authentication Code of the encrypted content
hmac: THash256;
/// a crc32c hash of the header (excluding this field)
crc: cardinal;
end;
/// points to the binary header of a .synecc encrypted file
PECIESHeader = ^TECIESHeader;
/// indicate the validity state of a ECDSA signature against a certificate
// - as returned by low-level ECCVerify() function, and
// TECCSignatureCertified.Verify, TECCCertificateChain.IsValid or
// TECCCertificateChain.IsSigned methods
// - see also ECC_VALIDSIGN constant
TECCValidity = (
ecvUnknown,
ecvValidSigned, ecvValidSelfSigned,
ecvNotSupported, ecvBadParameter, ecvCorrupted,
ecvInvalidDate, ecvUnknownAuthority, ecvDeprecatedAuthority,
ecvInvalidSignature);
/// the error codes returned by TECCCertificateSecret.Decrypt()
// - see also ECC_VALIDDECRYPT constant
TECCDecrypt = (
ecdDecrypted, ecdDecryptedWithSignature,
ecdNoContent, ecdCorrupted, ecdInvalidSerial, ecdNoPrivateKey,
ecdInvalidMAC, ecdDecryptError, ecdWriteFileError);
type
/// the Authentication schemes recognized by TECDHEProtocol
// - specifying the authentication allows a safe one-way handshake
TECDHEAuth = (authMutual, authServer, authClient);
/// set of Authentication schemes recognized by TECDHEProtocolServer
TECDHEAuths = set of TECDHEAuth;
/// the Key Derivation Functions recognized by TECDHEProtocol
// - used to compute the EF secret and MAC secret from shared ephemeral secret
// - only HMAC SHA-256 safe algorithm is proposed currently
TECDHEKDF = (kdfHmacSha256);
/// the Encryption Functions recognized by TECDHEProtocol
// - all supported AES chaining blocks have their 128-bit and 256-bit flavours
// - default efAesCrc128 will use the dedicated TAESCFBCRC class, i.e.
// AES-CFB encryption with on-the-fly 256-bit CRC computation of the plain and
// encrypted blocks, and AES-encryption of the CRC to ensure cryptographic
// level message authentication and integrity - associated TECDHEMAC
// property should be macDuringEF
// - other values will define TAESCFB/TAESOFB/TAESCTR/TAESCBC in 128-bit or
// 256-bit mode, in conjunction with a TECDHEMAC setting
// - AES-NI hardware acceleration will be used, if available - under x86-64,
// efAesOfb128 will potentially give the best performance
// - of course, weack ECB mode is not available
TECDHEEF = (efAesCrc128, efAesCfb128, efAesOfb128, efAesCtr128, efAesCbc128,
efAesCrc256, efAesCfb256, efAesOfb256, efAesCtr256, efAesCbc256);
/// the Message Authentication Codes recognized by TECDHEProtocol
// - default macDuringEF (680MB/s for efAesCrc128 with SSE4.2 and AES-NI)
// means that no separated MAC is performed, but done during encryption step:
// only supported by efAesCrc128 or efAesCrc256 (may be a future AES-GCM)
// - macHmacSha256 is the safest, but slow, especially when used as MAC for
// AES-NI accellerated encryption (110MB/s with efAesCfb128, to be compared
// with macDuringEF, which produces a similar level of MAC)
// - macHmacCrc256c and macHmacCrc32c are faster (550-650MB/s with efAesCfb128),
// and prevent transmission errors but not message integrity or authentication
// since composition of two crcs is a multiplication by a polynomial - see
// http://mslc.ctf.su/wp/boston-key-party-ctf-2016-hmac-crc-crypto-5pts
// - macXxHash32 will use the xxhash32() algorithm, fastest without SSE4.2
// - macNone (800MB/s, which is the speed of AES-NI encryption itself for a
// random set of small messages) won't check errors, but only replay attacks
TECDHEMAC = (macDuringEF, macHmacSha256, macHmacCrc256c, macHmacCrc32c,
macXxHash32, macNone);
/// defines one protocol Algorithm recognized by TECDHEProtocol
// - only safe and strong parameters are allowed, and the default values
// (i.e. all fields set to 0) will ensure a very good combination
// - in current implementation, there is no negociation between nodes:
// client and server should have the very same algorithm
TECDHEAlgo = packed record
/// the current Authentication scheme
auth: TECDHEAuth;
/// the current Key Derivation Function
kdf: TECDHEKDF;
/// the current Encryption Function
ef: TECDHEEF;
/// the current Message Authentication Code
mac: TECDHEMAC;
end;
/// points to one protocol Algorithm recognized by TECDHEProtocol
PECDHEAlgo = ^TECDHEAlgo;
/// the binary handshake message, sent by client to server
// - the frame will always have the same fixed size of 290 bytes (i.e. 388
// base64-encoded chars, which could be transmitted in a HTTP header),
// for both mutual or unilateral authentication
// - ephemeral keys may be included for perfect forward security
TECDHEFrameClient = packed record
/// expected algorithm used
algo: TECDHEAlgo;
/// a client-generated random seed
RndA: THash128;
/// client public key, with its certificate
// - may be zero, in case of unilateral authentication (algo=authServer)
QCA: TECCCertificateContent;
/// client-generated ephemeral public key
// - may be zero, in case of unilateral authentication (algo=authClient)
QE: TECCPublicKey;
/// SHA-256 + ECDSA secp256r1 signature of the previous fields, computed
// with the client private key
// - i.e. ECDSASign(dA,sha256(algo|RndA|QCA|QE))
// - may be zero, in case of unilateral authentication (algo=authServer)
Sign: TECCSignature;
end;
/// the binary handshake message, sent back from server to client
// - the frame will always have the same fixed size of 306 bytes (i.e. 408
// base64-encoded chars, which could be transmitted in a HTTP header),
// for both mutual or unilateral authentication
// - ephemeral keys may be included for perfect forward security
TECDHEFrameServer = packed record
/// algorithm used by the server
algo: TECDHEAlgo;
/// client-generated random seed
RndA: THash128;
/// a server-generated random seed
RndB: THash128;
/// server public key, with its certificate
// - may be zero, in case of unilateral authentication (algo=authClient)
QCB: TECCCertificateContent;
/// server-generated ephemeral public key
// - may be zero, in case of unilateral authentication (algo=authServer)
QF: TECCPublicKey;
/// SHA-256 + ECDSA secp256r1 signature of the previous fields, computed
// with the server private key
// - i.e. ECDSASign(dB,sha256(algo|RndA|RndB|QCB|QF))
// - may be zero, in case of unilateral authentication (algo=authClient)
Sign: TECCSignature;
end;
const
/// TECCValidity results indicating a valid digital signature
ECC_VALIDSIGN = [ecvValidSigned, ecvValidSelfSigned];
/// TECCDecrypt results indicating a valid decryption process
ECC_VALIDDECRYPT = [ecdDecrypted, ecdDecryptedWithSignature];
/// fill all bytes of this ECC private key buffer with zero
// - may be used to cleanup stack-allocated content
// ! ... finally FillZero(PrivateKey); end;
procedure FillZero(out Priv: TECCPrivateKey); overload;
/// returns the current UTC date, as a TECCDate integer value
// - i.e. 16-bit number of days since 1 August 2016
function NowECCDate: TECCDate;
{$ifdef HASINLINE}inline;{$endif}
/// convert a supplied TDateTime value into a TECCDate integer value
// - i.e. 16-bit number of days since 1 August 2016
// - returns 0 if the supplied value is invalid, i.e. out of range
function ECCDate(const DateTime: TDateTime): TECCDate;
/// convert a supplied a TECCDate integer value into a TDateTime value
// - i.e. 16-bit number of days since 1 August 2016
function ECCToDateTime(ECCDate: TECCDate): TDateTime;
{$ifdef HASINLINE}inline;{$endif}
/// convert a supplied a TECCDate integer value into a ISO-8601 text value
// - i.e. 16-bit number of days since 1 August 2016
function ECCText(ECCDate: TECCDate; Expanded: boolean=true): RawUTF8; overload;
{$ifdef HASINLINE}inline;{$endif}
/// compare two TECCCertificateIssuer binary buffer values
function IsEqual(const issuer1,issuer2: TECCCertificateIssuer): boolean; overload;
{$ifdef HASINLINE}inline;{$endif}
/// compare two TECCCertificateID binary buffer values
function IsEqual(const id1,id2: TECCCertificateID): boolean; overload;
{$ifdef HASINLINE}inline;{$endif}
/// ensure a TECCCertificateIssuer binary buffer is not void, i.e. filled with 0
function IsZero(const issuer: TECCCertificateIssuer): boolean; overload;
{$ifdef HASINLINE}inline;{$endif}
/// ensure a TECCCertificateID binary buffer is not void, i.e. filled with 0
function IsZero(const id: TECCCertificateID): boolean; overload;
{$ifdef HASINLINE}inline;{$endif}
/// convert a supplied TECCCertificateIssuer binary buffer into proper text
// - returns Ascii-7 text if was stored using Baudot encoding
// - or returns hexadecimal values, if it was 16 bytes of random binary
function ECCText(const Issuer: TECCCertificateIssuer): RawUTF8; overload;
/// convert some Ascii-7 text into a TECCCertificateIssuer binary buffer
// - using Emile Baudot encoding
// - returns TRUE on Text truncation to fit into the 16 bytes
function ECCIssuer(const Text: RawUTF8; out Issuer: TECCCertificateIssuer): boolean;
/// convert a supplied TECCCertificateID binary buffer into proper text
// - returns hexadecimal values, or '' if the ID is filled with zeros
function ECCText(const ID: TECCCertificateID): RawUTF8; overload;
/// convert a supplied hexadecimal buffer into a TECCCertificateID binary buffer
// - returns TRUE if the supplied Text was a valid hexadecimal buffer
function ECCID(const Text: RawUTF8; out ID: TECCCertificateID): boolean;
/// fast check of the binary buffer storage of a certificate
// - ensure content.CRC has the expected value, using FNV-1a checksum
// - does not validate the certificate against the certificates chain, nor
// perform any ECC signature: use TECCCertificateChain.IsValid instead
function ECCCheck(const content: TECCCertificateContent): boolean; overload;
/// fast check of the dates stored in a certificate binary buffer
// - could be validated against ECCCheck()
function ECCCheckDate(const content: TECCCertificateContent): boolean;
/// fast check if the binary buffer storage of a certificate was self-signed
// - a self-signed certificate will have its AuthoritySerial/AuthorityIssuer
// fields matching Serial/Issuer
function ECCSelfSigned(const content: TECCCertificateContent): boolean;
/// fast check of the binary buffer storage of a signature
// - just check that the date and authority are set
function ECCCheck(const content: TECCSignatureCertifiedContent): boolean; overload;
/// convert a supplied base-64 text into a TECCSignatureCertifiedContent binary buffer
function ECCSign(const base64: RawUTF8; out content: TECCSignatureCertifiedContent): boolean;
/// convert a raw signature into a DER compatible content
// - returns the number of bytes encoded into der[] buffer
function EccSignToDer(const sign: TEccSignature; out der: TEccSignatureDer): integer;
/// convert a supplied TECCSignatureCertifiedContent binary buffer into proper text
// - returns base-64 encoded text, or '' if the signature was filled with zeros
function ECCText(const sign: TECCSignatureCertifiedContent): RawUTF8; overload;
/// convert a supplied TECCSignature binary buffer into proper text
// - returns base-64 encoded text, or '' if the signature was filled with zeros
function ECCText(const sign: TECCSignature): RawUTF8; overload;
/// low-level verification of a TECCSignatureCertifiedContent binary buffer
// - will verify all internal signature fields according to a supplied authority,
// then will perform the ECDSA verification of the supplied 256-bit hash with
// the authority public key
// - as used by TECCSignatureCertified.Verify and TECCCertificateChain.IsValid
function ECCVerify(const sign: TECCSignatureCertifiedContent;
const hash: THash256; const auth: TECCCertificateContent): TECCValidity;
/// validate the binary header of a .synecc file buffer, encrypted via ECC secp256r1
// - will check against the expected layout, and values stored (e.g. crc)
// - returns true if head is a valid .synecc header, false otherwise
function ECIESHeader(const head: TECIESHeader): boolean; overload;
/// extract the binary header of a .synecc file buffer, encrypted via ECC secp256r1
// - match the format generated by TECCCertificate.Encrypt/EncryptFile
// - returns true on success, false otherwise
function ECIESHeader(const encrypted: RawByteString; out head: TECIESHeader): boolean; overload;
/// extract the binary header of a .synecc file, encrypted via ECC secp256r1
// - match the format generated by TECCCertificate.Encrypt/EncryptFile
// - returns true on success, false otherwise
// - if rawencryptedfile is specified, will also create such a file with the
// raw encrypted content (i.e. excluding the encryptedfile header)
function ECIESHeaderFile(const encryptedfile: TFileName; out head: TECIESHeader;
const rawencryptedfile: TFileName=''): boolean;
/// convert the binary header of a .synecc file buffer into a JSON object
// - returns '' if the header is not a valid .synecc file
function ECIESHeaderText(const head: TECIESHeader): RawUTF8; overload;
/// convert the header of a .synecc file into a JSON object
// - returns '' if the header is not a valid .synecc file
// - if rawencryptedfile is specified, will also create such a file with the
// raw encrypted content (i.e. excluding the encryptedfile header)
function ECIESHeaderText(const encryptedfile: TFileName;
const rawencryptedfile: TFileName=''): RawUTF8; overload;
{ *********** high-level certificate-based public-key cryptography *********** }
const
DEFAULT_ECCROUNDS = 60000;
type
/// exception class associated with this SynEcc unit
EECCException = class(ESynException);
TECCSignatureCertified = class;
/// a public certificate using ECC secp256r1 cryptography
// - implements a custom binary format, with validation period, and chaining
// - could be used for safe data signing, and authentication
// - in fact, Base64 published property is enough to persist this instance:
// but consider also ToBase64/FromBase64/LoadFromStream/SaveToStream methods
TECCCertificate = class(TSynPersistent)
protected
fContent: TECCCertificateContent;
fStoreOnlyPublicKey: boolean;
function GetAuthorityIssuer: RawUTF8;
function GetAuthoritySerial: RawUTF8;
function GetIssueDate: RawUTF8;
function GetIssuer: RawUTF8;
function GetSerial: RawUTF8;
function GetValidityEnd: RawUTF8;
function GetValidityStart: RawUTF8;
function GetIsSelfSigned: boolean;
function InternalLoad(const data: RawByteString): boolean; virtual;
function InternalSave: RawByteString; virtual;
procedure SetBase64(const base64: RawUTF8);
public
/// initialize this certificate
constructor Create; override;
/// initialize this certificate from a supplied certificate binary
// - will raise an EECCException if the supplied binary is incorrect
constructor CreateFrom(const binary: TECCCertificateContent); virtual;
/// initialize this certificate from a supplied base-64 encoded binary
// - will raise an EECCException if the supplied base64 is incorrect
constructor CreateFromBase64(const base64: RawUTF8); virtual;
/// initialize this certificate from a set of potential inputs
// - will first search from a .public file name, base-64 encoded binary,
// or a serial number which be used to search for a local .public file
// (as located by ECCKeyFileFind)
// - will raise an EECCException if no supplied media is correct
constructor CreateFromAuth(const AuthPubKey: TFileName;
const AuthBase64, AuthSerial: RawUTF8); virtual;
/// the certification information, digitaly signed in the Signature field
property Signed: TECCCertificateSigned read fContent.Signed;
/// SHA-256 + ECDSA secp256r1 signature of the Certificate record
property Signature: TECCSignature read fContent.Signature;
/// persist the certificate as some base-64 encoded binary
// - will use SaveToStream serialization
function ToBase64: RawUTF8;
/// retrieve the certificate from some base-64 encoded binary
// - will use LoadFromStream serialization
// - returns true on success, false otherwise
function FromBase64(const base64: RawUTF8): boolean;
/// retrieve the certificate from the "Base64": JSON entry of a .public file
// - will use FromBase64/LoadFromStream serialization
// - returns true on success, false otherwise
function FromFile(const filename: TFileName): boolean;
/// retrieve the certificate from a set of potential inputs
// - will first search from a .public file name, base-64 encoded binary,
// or a serial number which be used to search for a local .public file in
// the current folder or ECCKeyFileFolder (as located by ECCKeyFileFind)
// - returns true on success, false otherwise
function FromAuth(const AuthPubKey: TFileName;
const AuthBase64, AuthSerial: RawUTF8): boolean;
/// persist only the public certificate as some base-64 encoded binary
// - will follow TECCCertificate.SaveToStream/ToBase64 serialization,
// even when called from a TECCCertificateSecret instance
// - could be used to safely publish the public information of a newly
// created certificate
function PublicToBase64: RawUTF8;
/// persist the certificate as some binary
// - returns true on success (i.e. this class stores a certificate),
// false otherwise
function SaveToStream(Stream: TStream): boolean;
/// retrieve the certificate from some base-64 encoded binary
// - returns true on success, false otherwise
function LoadFromStream(Stream: TStream): boolean;
/// fast check of the binary buffer storage of this certificate
// - ensure Content.CRC has the expected value, using FNV-1a checksum
// - does not validate the certificate against the certificates chain, nor
// perform any ECC signature: use TECCCertificateChain.IsValid instead
function CheckCRC: boolean;
/// encrypt using the ECIES scheme, using this public certificate as key,
// via AES-256-CFB/PKCS7 over PBKDF2_HMAC_SHA256, and HMAC_SHA256
// - returns the encrypted content, in the .synecc optimized format
// - optional salt information used for PBKDF2 or HMAC can be customized
// - ecaUnknown algorithm will use either ecaPBKDF2_HMAC_SHA256_AES256_CFB
// or ecaPBKDF2_HMAC_SHA256_AES256_CFB_SYNLZ depending if the supplied
// contain is compressible or not - but you may force another algorithm
// - you can optionally associate an ECDSA secp256r1 digital signature,
// and a timestamp which may be used when re-creating a decyphered file
// - use TECCCertificateSecret.Decrypt to uncypher the resulting content
function Encrypt(const Plain: RawByteString;
Signature: TECCSignatureCertified=nil; FileDateTime: TDateTime=0;
const KDFSalt: RawUTF8='salt'; KDFRounds: integer=DEFAULT_ECCROUNDS;
const MACSalt: RawUTF8='hmac'; MACRounds: integer=100;
Algo: TECIESAlgo=ecaUnknown): RawByteString;
/// encrypt a file using the ECIES scheme, using this public certificate as
// key,via AES-256-CFB/PKCS7 over PBKDF2_HMAC_SHA256, and HMAC_SHA256
// - by default, will create a FileToCrypt.synecc encrypted file
// - ecaUnknown algorithm will use either ecaPBKDF2_HMAC_SHA256_AES256_CFB
// or ecaPBKDF2_HMAC_SHA256_AES256_CFB_SYNLZ depending if the supplied
// contain is compressible or not - but you may force another algorithm
// - any available .sign ECDSA secp256r1 digital signature file will be
// recognized and embedded to the resulting .synecc content
// - optional salt information used for PBKDF2 can be customized, to lock
// the encryted file with the supplied password
function EncryptFile(const FileToCrypt: TFileName; const DestFile: TFileName='';
const Salt: RawUTF8='salt'; SaltRounds: integer=DEFAULT_ECCROUNDS;
Algo: TECIESAlgo=ecaUnknown; IncludeSignFile: boolean=true): boolean;
{$ifndef NOVARIANTS}
/// returns a TDocVariant object of all published properties of this instance
// - excludes the Base64 property content if withBase64 is set to false
function ToVariant(withBase64: boolean=true): variant;
/// save the public key as a .public json file
// - i.e. a json containing all published properties of this instance
// - persist ToVariant() as an human-readable JSON file
function ToFile(const filename: TFileName): boolean;
{$endif}
/// low-level access to the binary buffer used ECC secp256r1 cryptography
// - you should not use this property, but other methods
property Content: TECCCertificateContent read fContent write fContent;
published
/// the TECCCertificate format version
// - currently equals 1
property Version: word read fContent.Version;
/// the genuine identifier of this certificate, as hexadecimal text
property Serial: RawUTF8 read GetSerial;
/// identify the certificate issuer, as text
property Issuer: RawUTF8 read GetIssuer;
/// when this certificate was generated, as ISO-8601 text
property IssueDate: RawUTF8 read GetIssueDate;
/// valid not before this date, as ISO-8601 text
property ValidityStart: RawUTF8 read GetValidityStart;
/// valid not after this date, as ISO-8601 text
property ValidityEnd: RawUTF8 read GetValidityEnd;
/// hexadecimal text of the authority certificate identifier used for signing
property AuthoritySerial: RawUTF8 read GetAuthoritySerial;
/// identify the authoritify issuer used for signing, as text
property AuthorityIssuer: RawUTF8 read GetAuthorityIssuer;
/// if this certificate has been signed by itself
// - a self-signed certificate will have its AuthoritySerial/AuthorityIssuer
// fields matching Serial/Issuer, and should be used as "root" certificates
property IsSelfSigned: boolean read GetIsSelfSigned;
/// base-64 encoded text of the whole certificate binary information
// - only the public part of the certificate will be shown: any private key
// of a TECCCertificateSecret instance would be trimmed
property Base64: RawUTF8 read PublicToBase64 write SetBase64;
end;
/// used to store a list of TECCCertificate instances
// - e.g. in TECCCertificateChain.Items
// - TJSONSerializer.RegisterObjArrayForJSON done in dddInfraApps and not
// in this unit to avoid dependency to mORMot.pas
TECCCertificateObjArray = array of TECCCertificate;
/// a public/private certificate using ECC secp256r1 cryptography
// - will store TECCCertificate public and associated private secret key
// - implements a custom binary format, with validation period, and chaining
// - could be used for safe data signing via SignToBase64/SignFile, and
// authentication / key derivation
// - allows optional anti-forensic diffusion during storage via AFSplitStripes
TECCCertificateSecret = class(TECCCertificate)
protected
fPrivateKey: TECCPrivateKey;
fAFSplitStripes: integer;
function InternalLoad(const data: RawByteString): boolean; override;
function InternalSave: RawByteString; override;
public
/// generate a new certificate, signed using the supplied Authority
// - if Authority is nil, will generate a self-signed certificate
// - the supplied Issuer name would be stored using AsciiToBaudot(),
// truncated to the Issuer buffer size, i.e. 16 bytes - if Issuer is '',
// TAESPRNG.Fill() will be used
// - you may specify some validity time range, if needed
// - default ParanoidVerify=true will validate the certificate digital
// signature via a call ecdsa_verify() to ensure its usefulness
// - would take around 4 ms under a 32-bit compiler, and 1 ms under 64-bit
constructor CreateNew(Authority: TECCCertificateSecret; const IssuerText: RawUTF8='';
ExpirationDays: integer=0; StartDate: TDateTime=0; ParanoidVerify: boolean=true);
/// create a certificate with its private secret key from a password-protected
// secure binary buffer
// - perform all reverse steps from SaveToSecureBinary() method
// - will raise an EECCException if the supplied Binary is incorrect
constructor CreateFromSecureBinary(const Binary: RawByteString; const PassWord: RawUTF8;
PBKDF2Rounds: integer=DEFAULT_ECCROUNDS; AES: TAESAbstractClass=nil); overload;
/// create a certificate with its private secret key from a password-protected
// secure binary buffer
// - may be used on a constant array in executable, created via SaveToSource()
// - perform all reverse steps from SaveToSecureBinary() method
// - will raise an EECCException if the supplied Binary is incorrect
constructor CreateFromSecureBinary(Data: pointer; Len: integer; const PassWord: RawUTF8;
PBKDF2Rounds: integer=DEFAULT_ECCROUNDS; AES: TAESAbstractClass=nil); overload;
/// create a certificate with its private secret key from an encrypted
// secure .private binary file and its associated password
// - perform all reverse steps from SaveToSecureFile() method
// - will raise an EECCException if the supplied file is incorrect
constructor CreateFromSecureFile(const FileName: TFileName; const PassWord: RawUTF8;
PBKDF2Rounds: integer=DEFAULT_ECCROUNDS; AES: TAESAbstractClass=nil); overload;
/// create a certificate with its private secret key from an encrypted
// secure .private binary file stored in a given folder
// - overloaded constructor retrieving the file directly from its folder
// - perform all reverse steps from SaveToSecureFile() method
// - will raise an EECCException if the supplied file is incorrect
constructor CreateFromSecureFile(const FolderName: TFileName;
const Serial, PassWord: RawUTF8; PBKDF2Rounds: integer=DEFAULT_ECCROUNDS;
AES: TAESAbstractClass=nil); overload;
/// finalize the instance, and safe erase fPrivateKey stored buffer
destructor Destroy; override;
/// returns TRUE if the private secret key is not filled with zeros
function HasSecret: boolean;
/// computes the 'Serial.private' file name of this certificate
// - as used by SaveToSecureFile()
function SaveToSecureFileName(FileNumber: integer=0): TFileName;
/// backup the private secret key into an encrypted .private binary file
// - you should keep all your private keys in a safe dedicated folder
// - filename will be the certificate hexadecimal as 'Serial.private'
// - will use anti-forensic diffusion of the private key (64 stripes = 2KB)
// - then AES-256-CFB encryption (or the one specified in AES parameter) will
// be performed from PBKDF2_HMAC_SHA256 derivation of an user-supplied password
function SaveToSecureFile(const PassWord: RawUTF8; const DestFolder: TFileName;
AFStripes: integer=64; PBKDF2Rounds: integer=DEFAULT_ECCROUNDS; AES: TAESAbstractClass=nil;
NoHeader: boolean=false): boolean;
/// backup the private secret key into several encrypted -###.private binary files
// - secret sharing can be used to store keys at many different places, e.g.
// on several local or remote drives, and therefore enhance privacy and safety
// - it will use anti-forensic diffusion of the private key to distribute it
// into pieces, in a manner that a subset of files can not regenerate the key:
// as a result, a compromission of one sub-file won't affect the secret key
// - filename will be the certificate hexadecimal as 'Serial-###.private'
// - AES-256-CFB encryption (or the one specified in AES parameter) will be
// performed from PBKDF2_HMAC_SHA256 derivation of an user-supplied password
function SaveToSecureFiles(const PassWord: RawUTF8; const DestFolder: TFileName;
DestFileCount: integer; AFStripes: integer=64; PBKDF2Rounds: integer=DEFAULT_ECCROUNDS;
AES: TAESAbstractClass=nil; NoHeader: boolean=false): boolean;
/// read a private secret key from an encrypted .private binary file
// - perform all reverse steps from SaveToSecureFile() method
// - returns TRUE on success, FALSE otherwise
function LoadFromSecureFile(const FileName: TFileName; const PassWord: RawUTF8;
PBKDF2Rounds: integer=DEFAULT_ECCROUNDS; AES: TAESAbstractClass=nil): boolean;
/// backup the private secret key into an encrypted secure binary buffer
// - you should keep all your private keys in a safe place
// - will use anti-forensic diffusion of the private key (64 stripes = 2KB)
// - then AES-256-CFB encryption (or the one specified in AES parameter) will
// be performed from PBKDF2_HMAC_SHA256 derivation of an user-supplied password
function SaveToSecureBinary(const PassWord: RawUTF8; AFStripes: integer=64;
PBKDF2Rounds: integer=DEFAULT_ECCROUNDS; AES: TAESAbstractClass=nil; NoHeader: boolean=false): RawByteString;
/// backup the private secret key into an encrypted source code constant
// - may be used to integrate some private keys within an executable
// - if ConstName='', _HEXASERIAL will be used, from 24 first chars of Serial
// - the password may also be included as ConstName_PASS associated constant,
// and as ConstName_CYPH in TSynPersistentWithPassword/TECCCertificateSecretSetting
// encrypted format
function SaveToSource(const ConstName, Comment, PassWord: RawUTF8;
IncludePassword: boolean=true; AFStripes: integer=0; PBKDF2Rounds: integer=100;
AES: TAESAbstractClass=nil; IncludeRaw: boolean=true): RawUTF8;
/// read a private secret key from an encrypted secure binary buffer
// - perform all reverse steps from SaveToSecureBinary() method
// - returns TRUE on success, FALSE otherwise
function LoadFromSecureBinary(const Binary: RawByteString; const PassWord: RawUTF8;
PBKDF2Rounds: integer=DEFAULT_ECCROUNDS; AES: TAESAbstractClass=nil): boolean; overload;
/// read a private secret key from an encrypted secure binary buffer
// - perform all reverse steps from SaveToSecureBinary() method
// - returns TRUE on success, FALSE otherwise
function LoadFromSecureBinary(Data: pointer; Len: integer; const PassWord: RawUTF8;
PBKDF2Rounds: integer=DEFAULT_ECCROUNDS; AES: TAESAbstractClass=nil): boolean; overload;
public
/// compute a base-64 encoded signature of some digital content
// - memory buffer will be hashed using SHA-256, then will be signed using
// ECDSA over the private secret key of this certificate instance
// - you could later on verify this text signature according to the public
// key of this certificate, calling TECCCertificateChain.IsSigned()
// - create internally a temporary TECCSignatureCertified instance
function SignToBase64(Data: pointer; Len: integer): RawUTF8; overload;
/// compute a base-64 encoded signature of some digital content hash