From dc64973f4d7f22db696544522a6e7b5255c24767 Mon Sep 17 00:00:00 2001 From: freitasjca Date: Mon, 9 Mar 2026 12:44:51 +0000 Subject: [PATCH 01/15] chore: add Boss package manifest Adds boss.json to make this library installable via boss install github.com/freitasjca/Delphi-Cross-Socket Zero source changes. browsingpath includes both Net/ and Utils/ because Net units depend on Utils units at compile time. --- boss.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 boss.json diff --git a/boss.json b/boss.json new file mode 100644 index 0000000..654b250 --- /dev/null +++ b/boss.json @@ -0,0 +1,11 @@ +{ + "name": "delphi-cross-socket", + "description": "Delphi cross-platform async socket library...", + "version": "1.0.0", + "homepage": "https://github.com/freitasjca/Delphi-Cross-Socket", + "license": "MIT", + "mainsrc": "Net/", + "browsingpath": "Net/;Utils/", + "projects": [], + "dependencies": {} +} \ No newline at end of file From f627ca0c96191f4bf35f39b32ac36b0cc84e3360 Mon Sep 17 00:00:00 2001 From: freitasjca Date: Mon, 9 Mar 2026 14:39:19 +0000 Subject: [PATCH 02/15] Update description --- boss.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boss.json b/boss.json index 654b250..3afba61 100644 --- a/boss.json +++ b/boss.json @@ -1,6 +1,6 @@ { "name": "delphi-cross-socket", - "description": "Delphi cross-platform async socket library...", + "description": "Delphi cross-platform async socket library (IOCP/epoll/kqueue) with HTTP server and OpenSSL 3.x support. Fork of winddriver/Delphi-Cross-Socket — adds Boss package manifest only. Zero source changes.", "version": "1.0.0", "homepage": "https://github.com/freitasjca/Delphi-Cross-Socket", "license": "MIT", From dfe7f6026e98e68110505afe2e2dc0802518980e Mon Sep 17 00:00:00 2001 From: freitasjca Date: Sat, 14 Mar 2026 11:06:01 +0000 Subject: [PATCH 03/15] Remove tracked .dcu files and add to .gitignore --- .gitignore | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8454266 --- /dev/null +++ b/.gitignore @@ -0,0 +1,63 @@ +modules/ +dist/ +static/ +**/Win32/ +**/Win64/ +**/Linux64/ +**/__history/ +**/__recovery/ +src/*.~* +__history/ +__recovery/ +packages/Win32/ +packages/Win64/ +packages/Linux64/ +packages/dcu/ +packages/dcp/ +packages/bpl/ +*.res +*.exe +*.dll +*.bpl +*.bpi +*.dcp +*.bpl +*.so +*.apk +*.drc +*.map +*.dres +*.rsm +*.tds +*.dcu +*.lib +*.a +*.o +*.ocx +*.local +*.identcache +*.projdata +*.tvsconfig +*.dsk +*.dcu +*.exe +*.ico +*.so +*.~* +*.a +*.stat +*.skincfg + +# Mac +*.DS_Store + +#FPC/Laz +lib/ +backup/ +*.lps + +# Code coverage reports +**/console/ +**/vcl/ +dunitx-results.xml +*.bak From e5c4457e1178970b19e6775e669755d151247307 Mon Sep 17 00:00:00 2001 From: freitasjca Date: Fri, 13 Mar 2026 19:46:49 +0000 Subject: [PATCH 04/15] Add dependent CnPack files --- CnPack/Common/CnPack.inc | 3623 ++++++++++++++++ CnPack/Crypto/CnAES.dcu | Bin 0 -> 122925 bytes CnPack/Crypto/CnAES.pas | 7569 ++++++++++++++++++++++++++++++++++ CnPack/Crypto/CnBase64.dcu | Bin 0 -> 7426 bytes CnPack/Crypto/CnBase64.pas | 547 +++ CnPack/Crypto/CnConsts.dcu | Bin 0 -> 14305 bytes CnPack/Crypto/CnConsts.pas | 250 ++ CnPack/Crypto/CnDES.dcu | Bin 0 -> 30941 bytes CnPack/Crypto/CnDES.pas | 1973 +++++++++ CnPack/Crypto/CnFloat.dcu | Bin 0 -> 15913 bytes CnPack/Crypto/CnFloat.pas | 1354 ++++++ CnPack/Crypto/CnKDF.dcu | Bin 0 -> 13854 bytes CnPack/Crypto/CnKDF.pas | 807 ++++ CnPack/Crypto/CnMD5.dcu | Bin 0 -> 15598 bytes CnPack/Crypto/CnMD5.pas | 884 ++++ CnPack/Crypto/CnNative.dcu | Bin 0 -> 48972 bytes CnPack/Crypto/CnNative.pas | 4904 ++++++++++++++++++++++ CnPack/Crypto/CnPemUtils.dcu | Bin 0 -> 16968 bytes CnPack/Crypto/CnPemUtils.pas | 1219 ++++++ CnPack/Crypto/CnRandom.dcu | Bin 0 -> 5673 bytes CnPack/Crypto/CnRandom.pas | 415 ++ CnPack/Crypto/CnSHA1.dcu | Bin 0 -> 10859 bytes CnPack/Crypto/CnSHA1.pas | 737 ++++ CnPack/Crypto/CnSHA2.dcu | Bin 0 -> 30907 bytes CnPack/Crypto/CnSHA2.pas | 2337 +++++++++++ CnPack/Crypto/CnSHA3.dcu | Bin 0 -> 31943 bytes CnPack/Crypto/CnSHA3.pas | 2700 ++++++++++++ CnPack/Crypto/CnSM3.dcu | Bin 0 -> 14942 bytes CnPack/Crypto/CnSM3.pas | 829 ++++ 29 files changed, 30148 insertions(+) create mode 100644 CnPack/Common/CnPack.inc create mode 100644 CnPack/Crypto/CnAES.dcu create mode 100644 CnPack/Crypto/CnAES.pas create mode 100644 CnPack/Crypto/CnBase64.dcu create mode 100644 CnPack/Crypto/CnBase64.pas create mode 100644 CnPack/Crypto/CnConsts.dcu create mode 100644 CnPack/Crypto/CnConsts.pas create mode 100644 CnPack/Crypto/CnDES.dcu create mode 100644 CnPack/Crypto/CnDES.pas create mode 100644 CnPack/Crypto/CnFloat.dcu create mode 100644 CnPack/Crypto/CnFloat.pas create mode 100644 CnPack/Crypto/CnKDF.dcu create mode 100644 CnPack/Crypto/CnKDF.pas create mode 100644 CnPack/Crypto/CnMD5.dcu create mode 100644 CnPack/Crypto/CnMD5.pas create mode 100644 CnPack/Crypto/CnNative.dcu create mode 100644 CnPack/Crypto/CnNative.pas create mode 100644 CnPack/Crypto/CnPemUtils.dcu create mode 100644 CnPack/Crypto/CnPemUtils.pas create mode 100644 CnPack/Crypto/CnRandom.dcu create mode 100644 CnPack/Crypto/CnRandom.pas create mode 100644 CnPack/Crypto/CnSHA1.dcu create mode 100644 CnPack/Crypto/CnSHA1.pas create mode 100644 CnPack/Crypto/CnSHA2.dcu create mode 100644 CnPack/Crypto/CnSHA2.pas create mode 100644 CnPack/Crypto/CnSHA3.dcu create mode 100644 CnPack/Crypto/CnSHA3.pas create mode 100644 CnPack/Crypto/CnSM3.dcu create mode 100644 CnPack/Crypto/CnSM3.pas diff --git a/CnPack/Common/CnPack.inc b/CnPack/Common/CnPack.inc new file mode 100644 index 0000000..cad0164 --- /dev/null +++ b/CnPack/Common/CnPack.inc @@ -0,0 +1,3623 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2025 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +{******************************************************************************} +{ } +{ עõԪΪָͱ汾Ϣļ } +{ õԪݲֲο JCL GExperts } +{ } +{******************************************************************************} + +//============================================================================== +// ѡ +//============================================================================== + +{$IFDEF FPC} + // Free Pascal Compiler 3.x Up Definitions + {$DEFINE SUPPORT_PASCAL} // Pascal + {$DEFINE SUPPORT_UINT64} // UInt64 + {$DEFINE SUPPORT_32_AND_64} // ֧ 32 64 λ NativeInt + {$DEFINE SUPPORT_ENCODING} // Unicode ַ֧ Encoding ת + {$DEFINE SUPPORT_INLINE} // ֧ inline + + {$DEFINE OBJECT_HAS_TOSTRING} // TObject.ToString + {$DEFINE TBYTES_DEFINED} + + // CPU FPC ӳ䵽 Delphi + {$IFDEF CPU386} // Intel 32 CPU + {$DEFINE CPU32BITS} + {$DEFINE CPUX86} + {$asmMode intel} + {$ENDIF} + {$IFDEF CPUi386} + {$DEFINE CPU32BITS} + {$DEFINE CPUX86} + {$asmMode intel} + {$ENDIF} + + {$IFDEF CPUAMD64} // Intel 64 CPU + {$DEFINE CPU64BITS} + {$DEFINE CPUX64} + {$asmMode intel} + {$ENDIF} + {$IFDEF CPUX86_64} + {$DEFINE CPU64BITS} + {$DEFINE CPUX64} + {$asmMode intel} + {$ENDIF} + {$IFDEF CPUIA64} + {$DEFINE CPU64BITS} + {$DEFINE CPUX64} + {$asmMode intel} + {$ENDIF} + + {$IFDEF CPUARM} // ARM 32 bit processor + {$DEFINE CPU32BITS} + {$DEFINE CPUARM} + {$DEFINE CPUARM32} + {$ENDIF} + + {$IFDEF CPUAARCH64} // ARM 64 bit processor + {$DEFINE CPU64BITS} + {$DEFINE CPUARM} + {$DEFINE CPUARM64} + {$ENDIF} + + {$mode Delphi} // Delphi Compatibility, not DelphiUnicodeעԴظ + + // ر Range Check Overflow Check + {$R- No Range checking} + {$OVERFLOWCHECKS OFF} + +{$ELSE FPC} // Below is for Delphi Compiler + +//{$DEFINE PERSONAL_EDITION} +{$DEFINE ENTERPRISE_EDITION} + +{$IFNDEF PERSONAL_EDITION} + {$DEFINE SUPPORT_DB} + {$DEFINE SUPPORT_ADO} +{$ENDIF} + +//============================================================================== +// 汾Ϣ +//============================================================================== + +{$IFDEF VER360} + {$DEFINE COMPILER29} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI29} + {$DEFINE DELPHI120_ATHENS} + {$DEFINE BCB28} + {$DEFINE BCB120_ATHENS} + {$DEFINE BDS23} +{$ENDIF} + +{$IFDEF VER350} + {$DEFINE COMPILER28} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI28} + {$DEFINE DELPHI110_ALEXANDRIA} + {$DEFINE BCB28} + {$DEFINE BCB110_ALEXANDRIA} + {$DEFINE BDS22} +{$ENDIF} + +{$IFDEF VER340} + {$DEFINE COMPILER27} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI27} + {$DEFINE DELPHI104_SYDNEY} + {$DEFINE BCB27} + {$DEFINE BCB104_SYDNEY} + {$DEFINE BDS21} +{$ENDIF} + +{$IFDEF VER330} + {$DEFINE COMPILER26} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI26} + {$DEFINE DELPHI103_RIO} + {$DEFINE BCB26} + {$DEFINE BCB103_RIO} + {$DEFINE BDS20} +{$ENDIF} + +{$IFDEF VER320} + {$DEFINE COMPILER25} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI25} + {$DEFINE DELPHI102_TOKYO} + {$DEFINE BCB25} + {$DEFINE BCB102_TOKYO} + {$DEFINE BDS19} +{$ENDIF} + +{$IFDEF VER310} + {$DEFINE COMPILER24} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI24} + {$DEFINE DELPHI101_BERLIN} + {$DEFINE BCB24} + {$DEFINE BCB101_BERLIN} + {$DEFINE BDS18} +{$ENDIF} + +{$IFDEF VER300} + {$DEFINE COMPILER23} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI23} + {$DEFINE DELPHI10_SEATTLE} + {$DEFINE BCB23} + {$DEFINE BCB10_SEATTLE} + {$DEFINE BDS17} +{$ENDIF} + +{$IFDEF VER290} + {$DEFINE COMPILER22} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI22} + {$DEFINE DELPHIXE8} + {$DEFINE BCB22} + {$DEFINE BCBXE8} + {$DEFINE BDS16} +{$ENDIF} + +{$IFDEF VER280} + {$DEFINE COMPILER21} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI21} + {$DEFINE DELPHIXE7} + {$DEFINE BCB21} + {$DEFINE BCBXE7} + {$DEFINE BDS15} +{$ENDIF} + +{$IFDEF VER270} + {$DEFINE COMPILER20} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI20} + {$DEFINE DELPHIXE6} + {$DEFINE BCB20} + {$DEFINE BCBXE6} + {$DEFINE BDS14} +{$ENDIF} + +{$IFDEF VER260} + {$DEFINE COMPILER19} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI19} + {$DEFINE DELPHIXE5} + {$DEFINE BCB19} + {$DEFINE BCBXE5} + {$DEFINE BDS12} +{$ENDIF} + +{$IFDEF VER250} + {$DEFINE COMPILER18} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI18} + {$DEFINE DELPHIXE4} + {$DEFINE BCB18} + {$DEFINE BCBXE4} + {$DEFINE BDS11} +{$ENDIF} + +{$IFDEF VER240} + {$DEFINE COMPILER17} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI17} + {$DEFINE DELPHIXE3} + {$DEFINE DELPHI2013} + {$DEFINE BCB17} + {$DEFINE BCBXE3} + {$DEFINE BCB2013} + {$DEFINE BDS10} + {$DEFINE BDS2013} +{$ENDIF} + +{$IFDEF VER230} + {$DEFINE COMPILER16} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI16} + {$DEFINE DELPHIXE2} + {$DEFINE DELPHI2012} + {$DEFINE BCB16} + {$DEFINE BCBXE2} + {$DEFINE BCB2012} + {$DEFINE BDS9} + {$DEFINE BDS2012} +{$ENDIF} + +{$IFDEF VER220} + {$DEFINE COMPILER15} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI15} + {$DEFINE DELPHIXE} + {$DEFINE DELPHI2011} + {$DEFINE BCB15} + {$DEFINE BCBXE} + {$DEFINE BCB2011} + {$DEFINE BDS8} + {$DEFINE BDS2011} +{$ENDIF} + +{$IFDEF VER210} + {$DEFINE COMPILER14} + {$DEFINE VCL71} + {$DEFINE DELPHI14} + {$DEFINE DELPHI2010} + {$DEFINE BCB14} + {$DEFINE BCB2010} + {$DEFINE BDS7} + {$DEFINE BDS2010} +{$ENDIF} + +{$IFDEF VER200} + {$DEFINE COMPILER12} + {$DEFINE VCL71} + {$DEFINE DELPHI12} + {$DEFINE DELPHI2009} + {$DEFINE BCB12} + {$DEFINE BCB2009} + {$DEFINE BDS6} + {$DEFINE BDS2009} +{$ENDIF} + +{$IFDEF VER185} + {$DEFINE COMPILER11} + {$DEFINE VCL71} + {$DEFINE DELPHI11} + {$DEFINE DELPHI2007} + {$DEFINE BCB11} + {$DEFINE BCB2007} + {$DEFINE BDS5} + {$DEFINE BDS2007} + {$UNDEF VER180} +{$ENDIF} + +{$IFDEF VER180} + {$DEFINE COMPILER10} + {$DEFINE VCL71} + {$DEFINE DELPHI10} + {$DEFINE DELPHI2006} + {$DEFINE BCB10} + {$DEFINE BCB2006} + {$DEFINE BDS4} + {$DEFINE BDS2006} +{$ENDIF} + +{$IFDEF VER170} + {$DEFINE COMPILER9} + {$DEFINE VCL71} + {$DEFINE DELPHI9} + {$DEFINE DELPHI2005} + {$DEFINE BDS3} + {$DEFINE BDS2005} +{$ENDIF} + +{$IFDEF VER160} + {$DEFINE COMPILER8} + {$DEFINE VCL71} + {$DEFINE DELPHI8} + {$DEFINE BDS2} +{$ENDIF} + +{$IFDEF VER150} + {$DEFINE COMPILER7} + {$IFDEF LINUX} + {$DEFINE CLX10} + {$ELSE} + {$DEFINE VCL70} + {$DEFINE CLX10} + {$IFDEF BCB} + {$DEFINE BCB7} + {$ELSE} + {$DEFINE DELPHI7} + {$ENDIF} + {$ENDIF} +{$ENDIF} + +{$IFDEF VER140} + {$DEFINE COMPILER6} + {$IFDEF LINUX} + {$DEFINE CLX10} + {$IFDEF CONDITIONALEXPRESSIONS} + {$IFDEF CompilerVersion} + {$IF System.RTLVersion = 14.1} + {$DEFINE KYLIX2} + {$IFEND} + {$IF System.RTLVersion = 14.5} + {$DEFINE KYLIX3} + {$IFEND} + {$ELSE} + {$DEFINE KYLIX1} + {$ENDIF} + {$ENDIF} + {$ELSE} + {$DEFINE VCL60} + {$DEFINE CLX10} + {$IFDEF BCB} + {$DEFINE BCB6} + {$ELSE} + {$DEFINE DELPHI6} + {$ENDIF} + {$ENDIF} +{$ENDIF} + +{$IFDEF VER130} + {$DEFINE COMPILER5} + {$DEFINE VCL50} + {$IFDEF BCB} + {$DEFINE BCB5} + {$ELSE} + {$DEFINE DELPHI5} + {$ENDIF} +{$ENDIF} + +{$IFDEF VER125} + {$DEFINE COMPILER4} + {$DEFINE VCL40} + {$DEFINE BCB4} +{$ENDIF} + +{$IFDEF VER120} + {$DEFINE COMPILER4} + {$DEFINE VCL40} + {$DEFINE DELPHI4} +{$ENDIF} + +{$IFDEF VER110} + {$DEFINE COMPILER35} + {$DEFINE VCL30} + {$DEFINE BCB3} +{$ENDIF} + +{$IFDEF VER100} + {$DEFINE COMPILER3} + {$DEFINE VCL30} + {$DEFINE DELPHI3} +{$ENDIF} + +{$IFDEF VER93} + {$DEFINE COMPILER2} + {$DEFINE VCL20} + {$DEFINE BCB1} +{$ENDIF} + +{$IFDEF VER90} + {$DEFINE COMPILER2} + {$DEFINE VCL20} + {$DEFINE DELPHI2} +{$ENDIF} + +{$IFDEF VER80} + {$DEFINE COMPILER1} + {$DEFINE VCL10} + {$DEFINE DELPHI1} +{$ENDIF} + +// DELPHIX_UP from DELPHIX mappings + +{$IFDEF DELPHI29} + {$DEFINE DELPHI} + {$DEFINE DELPHI29_UP} + {$DEFINE DELPHI28_UP} + {$DEFINE DELPHI27_UP} + {$DEFINE DELPHI26_UP} + {$DEFINE DELPHI25_UP} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI120_ATHENS} + {$DEFINE DELPHI120_ATHENS_UP} + {$DEFINE DELPHI110_ALEXANDRIA_UP} + {$DEFINE DELPHI104_SYDNEY_UP} + {$DEFINE DELPHI103_RIO_UP} + {$DEFINE DELPHI102_TOKYO_UP} + {$DEFINE DELPHI101_BERLIN_UP} + {$DEFINE DELPHI10_SEATTLE_UP} + {$DEFINE DELPHIXE8_UP} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI28} + {$DEFINE DELPHI} + {$DEFINE DELPHI28_UP} + {$DEFINE DELPHI27_UP} + {$DEFINE DELPHI26_UP} + {$DEFINE DELPHI25_UP} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI110_ALEXANDRIA} + {$DEFINE DELPHI110_ALEXANDRIA_UP} + {$DEFINE DELPHI104_SYDNEY_UP} + {$DEFINE DELPHI103_RIO_UP} + {$DEFINE DELPHI102_TOKYO_UP} + {$DEFINE DELPHI101_BERLIN_UP} + {$DEFINE DELPHI10_SEATTLE_UP} + {$DEFINE DELPHIXE8_UP} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI27} + {$DEFINE DELPHI} + {$DEFINE DELPHI27_UP} + {$DEFINE DELPHI26_UP} + {$DEFINE DELPHI25_UP} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI104_SYDNEY} + {$DEFINE DELPHI104_SYDNEY_UP} + {$DEFINE DELPHI103_RIO_UP} + {$DEFINE DELPHI102_TOKYO_UP} + {$DEFINE DELPHI101_BERLIN_UP} + {$DEFINE DELPHI10_SEATTLE_UP} + {$DEFINE DELPHIXE8_UP} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI26} + {$DEFINE DELPHI} + {$DEFINE DELPHI26_UP} + {$DEFINE DELPHI25_UP} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI103_RIO} + {$DEFINE DELPHI103_RIO_UP} + {$DEFINE DELPHI102_TOKYO_UP} + {$DEFINE DELPHI101_BERLIN_UP} + {$DEFINE DELPHI10_SEATTLE_UP} + {$DEFINE DELPHIXE8_UP} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI25} + {$DEFINE DELPHI} + {$DEFINE DELPHI25_UP} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI102_TOKYO} + {$DEFINE DELPHI102_TOKYO_UP} + {$DEFINE DELPHI101_BERLIN_UP} + {$DEFINE DELPHI10_SEATTLE_UP} + {$DEFINE DELPHIXE8_UP} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI24} + {$DEFINE DELPHI} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI101_BERLIN} + {$DEFINE DELPHI101_BERLIN_UP} + {$DEFINE DELPHI10_SEATTLE_UP} + {$DEFINE DELPHIXE8_UP} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI23} + {$DEFINE DELPHI} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI10_SEATTLE} + {$DEFINE DELPHI10_SEATTLE_UP} + {$DEFINE DELPHIXE8_UP} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI22} + {$DEFINE DELPHI} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHIXE8} + {$DEFINE DELPHIXE8_UP} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI21} + {$DEFINE DELPHI} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHIXE7} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI20} + {$DEFINE DELPHI} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHIXE6} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI19} + {$DEFINE DELPHI} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHIXE5} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI18} + {$DEFINE DELPHI} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHIXE4} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI17} + {$DEFINE DELPHI} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHIXE3} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} +{$ENDIF} + +{$IFDEF DELPHI2013} + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI16} + {$DEFINE DELPHI} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHIXE2} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} +{$ENDIF} + +{$IFDEF DELPHI2012} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI15} + {$DEFINE DELPHI} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHIXE} + {$DEFINE DELPHIXE_UP} +{$ENDIF} + +{$IFDEF DELPHI2011} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI14} + {$DEFINE DELPHI} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI2010} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI12} + {$DEFINE DELPHI} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI2009} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI11} + {$DEFINE DELPHI} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI2007} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI10} + {$DEFINE DELPHI} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI2006} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI9} + {$DEFINE DELPHI} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI2005} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI8} + {$DEFINE DELPHI} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI7} + {$DEFINE DELPHI} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI6} + {$DEFINE DELPHI} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI5} + {$DEFINE DELPHI} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI4} + {$DEFINE DELPHI} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI3} + {$DEFINE DELPHI} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI2} + {$DEFINE DELPHI} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI1} + {$DEFINE DELPHI} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +// BCBX_UP from BCBX mappings + +{$IFDEF BCB29} + {$DEFINE BCB} + {$DEFINE BCB29_UP} + {$DEFINE BCB28_UP} + {$DEFINE BCB27_UP} + {$DEFINE BCB26_UP} + {$DEFINE BCB25_UP} + {$DEFINE BCB24_UP} + {$DEFINE BCB23_UP} + {$DEFINE BCB22_UP} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB120_ATHENS} + {$DEFINE BCB120_ATHENS_UP} + {$DEFINE BCB110_ALEXANDRIA_UP} + {$DEFINE BCB104_SYDNEY_UP} + {$DEFINE BCB103_RIO_UP} + {$DEFINE BCB102_TOKYO_UP} + {$DEFINE BCB101_BERLIN_UP} + {$DEFINE BCB10_SEATTLE_UP} + {$DEFINE BCBXE8_UP} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB28} + {$DEFINE BCB} + {$DEFINE BCB28_UP} + {$DEFINE BCB27_UP} + {$DEFINE BCB26_UP} + {$DEFINE BCB25_UP} + {$DEFINE BCB24_UP} + {$DEFINE BCB23_UP} + {$DEFINE BCB22_UP} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB110_ALEXANDRIA} + {$DEFINE BCB110_ALEXANDRIA_UP} + {$DEFINE BCB104_SYDNEY_UP} + {$DEFINE BCB103_RIO_UP} + {$DEFINE BCB102_TOKYO_UP} + {$DEFINE BCB101_BERLIN_UP} + {$DEFINE BCB10_SEATTLE_UP} + {$DEFINE BCBXE8_UP} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB27} + {$DEFINE BCB} + {$DEFINE BCB27_UP} + {$DEFINE BCB26_UP} + {$DEFINE BCB25_UP} + {$DEFINE BCB24_UP} + {$DEFINE BCB23_UP} + {$DEFINE BCB22_UP} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB104_SYDNEY} + {$DEFINE BCB104_SYDNEY_UP} + {$DEFINE BCB103_RIO_UP} + {$DEFINE BCB102_TOKYO_UP} + {$DEFINE BCB101_BERLIN_UP} + {$DEFINE BCB10_SEATTLE_UP} + {$DEFINE BCBXE8_UP} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB26} + {$DEFINE BCB} + {$DEFINE BCB26_UP} + {$DEFINE BCB25_UP} + {$DEFINE BCB24_UP} + {$DEFINE BCB23_UP} + {$DEFINE BCB22_UP} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB103_RIO} + {$DEFINE BCB103_RIO_UP} + {$DEFINE BCB102_TOKYO_UP} + {$DEFINE BCB101_BERLIN_UP} + {$DEFINE BCB10_SEATTLE_UP} + {$DEFINE BCBXE8_UP} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB25} + {$DEFINE BCB} + {$DEFINE BCB25_UP} + {$DEFINE BCB24_UP} + {$DEFINE BCB23_UP} + {$DEFINE BCB22_UP} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB102_TOKYO} + {$DEFINE BCB102_TOKYO_UP} + {$DEFINE BCB101_BERLIN_UP} + {$DEFINE BCB10_SEATTLE_UP} + {$DEFINE BCBXE8_UP} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + + +{$IFDEF BCB24} + {$DEFINE BCB} + {$DEFINE BCB24_UP} + {$DEFINE BCB23_UP} + {$DEFINE BCB22_UP} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB101_BERLIN} + {$DEFINE BCB101_BERLIN_UP} + {$DEFINE BCB10_SEATTLE_UP} + {$DEFINE BCBXE8_UP} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB23} + {$DEFINE BCB} + {$DEFINE BCB23_UP} + {$DEFINE BCB22_UP} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB10_SEATTLE} + {$DEFINE BCB10_SEATTLE_UP} + {$DEFINE BCBXE8_UP} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB22} + {$DEFINE BCB} + {$DEFINE BCB22_UP} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCBXE8} + {$DEFINE BCBXE8_UP} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB21} + {$DEFINE BCB} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCBXE7} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB20} + {$DEFINE BCB} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCBXE6} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB19} + {$DEFINE BCB} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCBXE5} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB18} + {$DEFINE BCB} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCBXE4} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB17} + {$DEFINE BCB} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCBXE3} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} +{$ENDIF} + +{$IFDEF BCB2013} + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB16} + {$DEFINE BCB} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCBXE2} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} +{$ENDIF} + +{$IFDEF BCB2012} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB15} + {$DEFINE BCB} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCBXE} + {$DEFINE BCBXE_UP} +{$ENDIF} + +{$IFDEF BCB2011} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB14} + {$DEFINE BCB} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB2010} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB12} + {$DEFINE BCB} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB2009} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB11} + {$DEFINE BCB} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB2007} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB10} + {$DEFINE BCB} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB2006} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB7} + {$DEFINE BCB} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB6} + {$DEFINE BCB} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB5} + {$DEFINE BCB} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB4} + {$DEFINE BCB} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB3} + {$DEFINE BCB} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB1} + {$DEFINE BCB} + {$DEFINE BCB1_UP} +{$ENDIF} + +// KYLIXX_UP from KYLIXX mappings + +{$IFDEF KYLIX3} + {$DEFINE KYLIX} + {$DEFINE KYLIX3_UP} + {$DEFINE KYLIX2_UP} + {$DEFINE KYLIX1_UP} +{$ENDIF} + +{$IFDEF KYLIX2} + {$DEFINE KYLIX} + {$DEFINE KYLIX2_UP} + {$DEFINE KYLIX1_UP} +{$ENDIF} + +{$IFDEF KYLIX1} + {$DEFINE KYLIX} + {$DEFINE KYLIX1_UP} +{$ENDIF} + +// BDSXX_UP from BDSXX mappings + +{$IFDEF BDS23} // 12.0 ATHENS + {$DEFINE BDS} + {$DEFINE BDS23_UP} + {$DEFINE BDS22_UP} + {$DEFINE BDS21_UP} + {$DEFINE BDS20_UP} + {$DEFINE BDS19_UP} + {$DEFINE BDS18_UP} + {$DEFINE BDS17_UP} + {$DEFINE BDS16_UP} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS22} // 11.0 ALEXANDRIA + {$DEFINE BDS} + {$DEFINE BDS22_UP} + {$DEFINE BDS21_UP} + {$DEFINE BDS20_UP} + {$DEFINE BDS19_UP} + {$DEFINE BDS18_UP} + {$DEFINE BDS17_UP} + {$DEFINE BDS16_UP} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS21} // 10.4 SYDNEY + {$DEFINE BDS} + {$DEFINE BDS21_UP} + {$DEFINE BDS20_UP} + {$DEFINE BDS19_UP} + {$DEFINE BDS18_UP} + {$DEFINE BDS17_UP} + {$DEFINE BDS16_UP} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS20} // 10.3 RIO + {$DEFINE BDS} + {$DEFINE BDS20_UP} + {$DEFINE BDS19_UP} + {$DEFINE BDS18_UP} + {$DEFINE BDS17_UP} + {$DEFINE BDS16_UP} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS19} // 10.2 Tokyo + {$DEFINE BDS} + {$DEFINE BDS19_UP} + {$DEFINE BDS18_UP} + {$DEFINE BDS17_UP} + {$DEFINE BDS16_UP} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS18} // 10.1 Berlin + {$DEFINE BDS} + {$DEFINE BDS18_UP} + {$DEFINE BDS17_UP} + {$DEFINE BDS16_UP} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS17} // 10 Seattle + {$DEFINE BDS} + {$DEFINE BDS17_UP} + {$DEFINE BDS16_UP} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS16} + {$DEFINE BDS} + {$DEFINE BDS16_UP} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS15} + {$DEFINE BDS} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS14} + {$DEFINE BDS} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS12} + {$DEFINE BDS} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS11} + {$DEFINE BDS} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS10} + {$DEFINE BDS} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS2013} + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS9} + {$DEFINE BDS} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS2012} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS8} + {$DEFINE BDS} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS2011} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS7} + {$DEFINE BDS} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS2010} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS6} + {$DEFINE BDS} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS2009} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS5} + {$DEFINE BDS} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS2007} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS4} + {$DEFINE BDS} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS2006} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS3} + {$DEFINE BDS} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS2005} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS2} + {$DEFINE BDS} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS1} + {$DEFINE BDS} + {$DEFINE BDS1_UP} +{$ENDIF} + +// COMPILERX_UP from COMPILERX mappings + +{$IFDEF COMPILER29} // 12.0 ATHENS + {$DEFINE COMPILER29_UP} + {$DEFINE COMPILER28_UP} + {$DEFINE COMPILER27_UP} + {$DEFINE COMPILER26_UP} + {$DEFINE COMPILER25_UP} + {$DEFINE COMPILER24_UP} + {$DEFINE COMPILER23_UP} + {$DEFINE COMPILER22_UP} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER28} // 11.0 ALEXANDRIA + {$DEFINE COMPILER28_UP} + {$DEFINE COMPILER27_UP} + {$DEFINE COMPILER26_UP} + {$DEFINE COMPILER25_UP} + {$DEFINE COMPILER24_UP} + {$DEFINE COMPILER23_UP} + {$DEFINE COMPILER22_UP} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER27} // 10.4 SYDNEY + {$DEFINE COMPILER27_UP} + {$DEFINE COMPILER26_UP} + {$DEFINE COMPILER25_UP} + {$DEFINE COMPILER24_UP} + {$DEFINE COMPILER23_UP} + {$DEFINE COMPILER22_UP} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER26} // 10.3 RIO + {$DEFINE COMPILER26_UP} + {$DEFINE COMPILER25_UP} + {$DEFINE COMPILER24_UP} + {$DEFINE COMPILER23_UP} + {$DEFINE COMPILER22_UP} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER25} // 10.2 Tokyo + {$DEFINE COMPILER25_UP} + {$DEFINE COMPILER24_UP} + {$DEFINE COMPILER23_UP} + {$DEFINE COMPILER22_UP} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER24} // 10.1 Berlin + {$DEFINE COMPILER24_UP} + {$DEFINE COMPILER23_UP} + {$DEFINE COMPILER22_UP} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER23} // 10 Seattle + {$DEFINE COMPILER23_UP} + {$DEFINE COMPILER22_UP} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER22} + {$DEFINE COMPILER22_UP} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER21} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER20} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER19} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER18} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER17} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER16} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER15} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER14} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER12} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER11} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER10} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER9} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER8} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER7} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER6} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER5} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER4} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER35} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER3} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER2} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER1} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +// VCLXX_UP from VCLXX mappings + +{$IFDEF UCL10} + {$DEFINE UCL10_UP} +{$ENDIF} + +{$IFDEF VCL71} + {$DEFINE VCL71_UP} + {$DEFINE VCL70_UP} + {$DEFINE VCL60_UP} + {$DEFINE VCL50_UP} + {$DEFINE VCL40_UP} + {$DEFINE VCL30_UP} + {$DEFINE VCL20_UP} + {$DEFINE VCL10_UP} +{$ENDIF} + +{$IFDEF VCL70} + {$DEFINE VCL70_UP} + {$DEFINE VCL60_UP} + {$DEFINE VCL50_UP} + {$DEFINE VCL40_UP} + {$DEFINE VCL30_UP} + {$DEFINE VCL20_UP} + {$DEFINE VCL10_UP} +{$ENDIF} + +{$IFDEF VCL60} + {$DEFINE VCL60_UP} + {$DEFINE VCL50_UP} + {$DEFINE VCL40_UP} + {$DEFINE VCL30_UP} + {$DEFINE VCL20_UP} + {$DEFINE VCL10_UP} +{$ENDIF} + +{$IFDEF VCL50} + {$DEFINE VCL50_UP} + {$DEFINE VCL40_UP} + {$DEFINE VCL30_UP} + {$DEFINE VCL20_UP} + {$DEFINE VCL10_UP} +{$ENDIF} + +{$IFDEF VCL40} + {$DEFINE VCL40_UP} + {$DEFINE VCL30_UP} + {$DEFINE VCL20_UP} + {$DEFINE VCL10_UP} +{$ENDIF} + +{$IFDEF VCL30} + {$DEFINE VCL30_UP} + {$DEFINE VCL20_UP} + {$DEFINE VCL10_UP} +{$ENDIF} + +{$IFDEF VCL20} + {$DEFINE VCL20_UP} + {$DEFINE VCL10_UP} +{$ENDIF} + +{$IFDEF VCL10} + {$DEFINE VCL10_UP} +{$ENDIF} + +// CLXXX_UP from CLXXX mappings + +{$IFDEF CLX10} + {$DEFINE CLX10_UP} +{$ENDIF} + +//============================================================================== +// ƽ̨ض +//============================================================================== + +{$IFDEF COMPILER1} + {$DEFINE WIN16} + {$DEFINE MSWINDOWS} +{$ENDIF} + +{$IFDEF BDS} + {$DEFINE DOTNET} +{$ENDIF} + +{$IFDEF WIN32} + {$DEFINE MSWINDOWS} +{$ENDIF} + +{$IFDEF LINUX} + {$DEFINE UNIX} + {$DEFINE COMPLIB_CLX} +{$ENDIF} + +{$IFNDEF COMPLIB_CLX} + {$DEFINE COMPLIB_VCL} +{$ENDIF} + +//============================================================================== +// ӳ汾ϢѺõָ +//============================================================================== + +{$IFDEF DELPHI} + {$DEFINE SUPPORT_PASCAL} +{$ENDIF} + +{$IFDEF BCB} + {$DEFINE SUPPORT_PASCAL} + {$DEFINE SUPPORT_CPLUSPLUS} +{$ENDIF} + +{$IFDEF DELPHI120_ATHENS_UP} + {$DEFINE LIST_INDEX_NATIVEINT} // Athens 12 TList use NativeInt for Index and Count instead of Integer + {$DEFINE IDE_HAS_TABMENU_COPY_PATH} // Athens 12 editor tab menu has item to copy path or filename + {$DEFINE IDE_HAS_DBCLICK_HIGHLIGHT} // Athens 12 editor double click selection highlight + {$DEFINE OTA_CODEEDITOR_SERVICE} // 11.3 ToolsAPI.Editor ӿڣʱ޷ 11.0/1/2 ֻ֣ܼӵ 12 +{$ENDIF} + +{$IFDEF DELPHI110_ALEXANDRIA_UP} + {$DEFINE NO_OLDCREATEORDER} // Alexandria 11 removed OldCreateOrder + {$DEFINE IDE_SUPPORT_HDPI} // Alexandria 11 supports HDPI using TVirtualImageList, etc. + {$DEFINE IDE_HAS_AUTO_READONLY} // Alexandria 11 supports auto open VCL source readonly + {$DEFINE IDE_HAS_MEMORY_VISUALIZAER} // Alexandria 11 has Memory Visualizer for Debug + {$DEFINE TSTRINGS_SETTEXTSTR_CANNULL} // Alexandria 11 TStrings.SetTextStr Ignore #0 Terminated Char + {$DEFINE MEMORYSTREAM_CAPACITY_NATIVEINT} // Alexandria 11 TMemoryStream Capacity is NativeInt instead of Longint +{$ENDIF} + +{$IFDEF DELPHI104_SYDNEY_UP} + {$DEFINE IDE_SUPPORT_LSP} // Sydney 10.4 ֧ LSP Է + {$DEFINE IDE_HAS_ERRORINSIGHT} // Sydney 10.4.2 ֱ֧༭ ErrorInsight + {$DEFINE IDE_EDITOR_CUSTOM_COLUMN} // Sydney 10.4 ϱ༭ Gutter ֧Զ壬ûӿڲݣԼ + {$DEFINE IDE_SWITCH_BUG} // Sydney 10.4.2 ڴļʱĪл̨ Bug +{$ENDIF} + +{$IFDEF DELPHI103_RIO_UP} + {$DEFINE SUPPORT_MACOS64} // Rio 10.3.2 ֧ 64 λ MacOS +{$ENDIF} + +{$IFDEF DELPHI102_TOKYO_UP} + {$DEFINE SUPPORT_LINUX64} // Tokyo 10.2 ֧ Linux 64 λ Server + {$DEFINE IDE_SUPPORT_THEMING} // Tokyo 10.2.2 ֧ IDE л +{$ENDIF} + +{$IFDEF DELPHI101_BERLIN_UP} + {$DEFINE IDE_NEW_EMBEDDED_DESIGNER} // 101B Re-opens "Embedded Designer" Option and Gives a New Container. +{$ENDIF} + +{$IFDEF DELPHI10_SEATTLE_UP} + {$DEFINE IDE_HAS_OWN_STRUCTUAL_HIGHLIGHT} // 10S has own Structual Highlight + {$DEFINE IDE_HAS_HIDE_NONVISUAL} // 10S has "Hide Nonvisual" Feature. +{$ENDIF} + +{$IFDEF DELPHIXE8_UP} + {$DEFINE INIFILE_READWRITE_INTEGER} // XE8 IniFile ReadInteger WriteInteger ʼ LongInt Ϊ Integer + {$DEFINE IDE_INTEGRATE_CASTALIA} // XE8/10S and above integrate Castalia. +{$ENDIF} + +{$IFDEF COMPILER21_UP} // COMPILER21 = XE7 + {$DEFINE NOT_SUPPORT_BDE} // BDE +{$ENDIF} + +{$IFDEF DELPHIXE7_UP} + {$DEFINE SUPPORT_TBYTES_OPERATION} // XE7 TBytes ʼ֧ӡȲ + {$DEFINE FMX_CONTROL_HAS_SIZE} // XE7 FMX Control Size +{$ENDIF} + +{$IFDEF DELPHIXE6_UP} + {$DEFINE SUPPORT_JSON} // XE6 System.JSON ⣬ DBX/REST +{$ENDIF} + +{$IFDEF DELPHIXE5_UP} + {$DEFINE SUPPORT_MOBILE} // XE5 ʼ֧ƶ + {$DEFINE IDE_HAS_INSIGHT} // XE5 has IDE Insight Bar +{$ENDIF} + +{$IFDEF DELPHIXE4_UP} + {$IFNDEF DISABLE_FMX} + {$DEFINE SUPPORT_FMX_FRAME} // XE4 FMX Supports FMX Frame + {$ENDIF} +{$ELSE} + {$DEFINE MEMO_CARETPOS_BUG} // Memo CaretPos Get Negative Error Value for Large File under XE3 or below +{$ENDIF} + +{$IFDEF DELPHIXE3_UP} + {$DEFINE SUPPORT_ATOMIC} // XE3 has Atomic Routines + {$DEFINE TCONTROL_HAS_STYLEELEMENTS} // XE3 TControl has StyleElements Property + {$DEFINE IDE_NP_FMX_DESIGN_BUG} // XE3 FMX Designer Cut/Copy/Paste cause AV Bug for -np switch +{$ENDIF} + +{$IFDEF DELPHIXE2_UP} + {$DEFINE SUPPORT_WIN64} // XE2 Supports Win64 + {$DEFINE SUPPORT_MACOS32} // XE2 Supports MacOS 32 + {$DEFINE SUPPORT_UNITNAME_DOT} + {$DEFINE SUPPORT_ENHANCED_INDEXEDPROPERTY} // XE2 New RTTI Supports IndexedProperty + {$DEFINE SUPPORT_ZLIB_WINDOWBITS} // XE2 ZLib Supports WindowBits + {$DEFINE SUPPORT_GDIPLUS} // XE2 Supports GDI+ + {$DEFINE SUPPORT_INT64ARRAY} // XE2 Defined Int64Array + {$DEFINE SUPPORT_ALPHACOLOR} // XE2 System.UITypes Has TAlphaColors +{$ENDIF} + +{$IFDEF DELPHIXE_UP} + {$DEFINE TSTRINGS_HAS_WRITEBOM} // XE TStrings has WriteBOM property. + {$DEFINE IDE_HAS_DEBUGGERVISUALIZER} // XE ToolsAPI has Debugger Visualizer Interfaces. + {$DEFINE IDE_HAS_STRINGS_VISUALIZAER} // XE has TStrings Visualizer for Debug +{$ENDIF} + +{$IFDEF BDS2012_UP} // 2012 = XE2 + {$DEFINE SUPPORT_32_AND_64} // XE2 Support Win32 and Win64 + {$IFNDEF DISABLE_FMX} + {$DEFINE SUPPORT_FMX} + {$ENDIF} + {$DEFINE SUPPORT_CROSS_PLATFORM} // XE2 ֿ֧ƽ̨ + {$DEFINE VERSIONINFO_PER_CONFIGURATION} // Every Configuruation can have a Version Info. + {$DEFINE OTA_ENVOPTIONS_PLATFORM_BUG} + // A Bug Can't get Correct Env Option Values for Current Platform. + {$DEFINE LIST_NEW_POINTER} +{$ENDIF} + +{$IFDEF BDS2010_UP} + {$DEFINE SUPPORT_INTERFACE_AS_OBJECT} + {$DEFINE SUPPORT_ENHANCED_RTTI} // New enhanced RTTI. + {$DEFINE SUPPORT_EXTERNAL_DELAYED} // External functions can be declared as 'delayed'. + {$DEFINE SUPPORT_CLASS_CONSTRUCTOR} // 2010 and above Supports class constructor and destructor + {$DEFINE SUPPORT_CLASS_DESTRUCTOR} + {$DEFINE IMAGELIST_BEGINENDUPDATE} // 2010 ʼImageList й BeginUpdate EndUpdate + {$DEFINE OTA_DEBUG_HAS_EVENTS} // 2010 µ DebuggerService ProcessDebugEvents + {$DEFINE IDE_HAS_NEW_COMPONENT_PALETTE} // IDE has a new style Component Palette. + {$DEFINE IDE_HAS_EDITOR_SEARCHPANEL} // Editor has a Search Panel + {$DEFINE IDE_HAS_DATETIME_HINT} // TDate/TTime/TDateTime shows Normally in Debug Hint +{$ENDIF} + +{$IFDEF BDS2010} + // 2010 EditView CursorPos EditPosition.InsertText ƫ + {$DEFINE EDITVIEW_SETCURSORPOS_BUG} +{$ENDIF} + +{$IFDEF BDS2009_UP} + {$DEFINE UNICODE_STRING} + {$DEFINE SUPPORT_ATTRIBUTE} // ֧ Attribute + {$DEFINE SUPPORT_GENERIC} // ַ֧ + {$DEFINE SUPPORT_ANSISTRING_CODEPAGE} // AnsiString ָ֧ҳ + {$DEFINE SUPPORT_ENCODING} // Unicode with TEncoding + {$DEFINE SUPPORT_PUINT64} // Has Pointer of UInt64 + {$DEFINE OBJECT_HAS_TOSTRING} // TObject.ToString Function + {$DEFINE OBJECT_HAS_EQUAL} // TObject.Equal Function + {$DEFINE OBJECT_HAS_GETHASHCODE} // TObject.GetHashCode Function + {$DEFINE TGRAPHIC_SUPPORT_PARTIALTRANSPARENCY} // TGraphic ֧ Alpha ͨ͸ + {$DEFINE SUPPORT_OTA_PROJECT_CONFIGURATION} + + {$DEFINE IDE_MAINFORM_EAT_MOUSEWHEEL} + // MainForm of 2009 or Above will eat Message in MouseWheelHandler + {$DEFINE IDE_CODEINSIGHT_AUTOINVOKE} + // IDE Code Insight has Auto Invoke Option + {$DEFINE EDITVIEW_CONVERTPOS_BUG} + // 2009 or Above IEditView.ConvertPos Incorrect when Meeting Unicode Chars. + + {$IFNDEF DELPHIXE2_UP} // 2009/2010/XE has a Project Version Number Bug. + {$DEFINE PROJECT_VERSION_NUMBER_BUG} + {$ENDIF} + {$DEFINE OTA_DPKOPTION_SETVALUE_CORRUPT_BUG} + // A OpenTools API Bug IOTAProjectOptions.SetOptionValue under 2009 or above: + // Set an Option Value to DPK Project Options maybe cause DPK Source Corrupt. +{$ELSE} + {$DEFINE ZLIB_STREAM_NOSIZE} // 2007 µ Zlib Ľѹ֧ Size +{$ENDIF} + +{$IFDEF BDS2009} + // 2009 CreateParams пܵѭ + {$DEFINE CREATE_PARAMS_BUG} + // 2009 EditView CursorPos EditPosition.InsertText ƫ + {$DEFINE EDITVIEW_SETCURSORPOS_BUG} +{$ENDIF} + +{$IFDEF BDS2007_UP} + {$DEFINE IDE_CONF_MANAGER} + {$DEFINE TBYTES_DEFINED} // 2007 Defined TBytes = array of Byte; + {$DEFINE PROJECT_FILENAME_DPROJ} // Project File is .dproj +{$ENDIF} + +{$IFDEF BDS2007} + // RAD Studio 2007 ¿ AutoComplete ᵼĺ˸ + {$DEFINE COMBOBOX_CHS_BUG} +{$ENDIF} + +{$IFDEF BDS2006_UP} + {$DEFINE SUPPORT_CLASS_VAR} // 2006 and above Supports class var + {$DEFINE TCONTROL_HAS_MARGINS} // 2006 and above TControl has Margins + {$DEFINE TCONTROL_HAS_EXPLICIT_BOUNDS} // 2006 and above TControl has Explicit Bounds + {$DEFINE TCONTROL_HAS_MOUSEENTERLEAVE} // 2006 and above TControl has Mouse Enter/Leave Events + {$DEFINE OTA_CODE_TEMPLATE_API} // 2006 and above Provides CodeTemplateAPI. + {$DEFINE OTA_DEBUG_HAS_ERBUSY} // 2006 µ Evaluate зֵ erBusy + {$DEFINE IDE_HAS_GUIDE_LINE} // 2006 and above has Designer Guide Line + {$DEFINE IDE_SYNC_EDIT_BLOCK} // 2006 and above Editor Supports Sync Block Edit + {$DEFINE EDITOR_TAB_ONLYFROM_WINCONTROL} + // From BDS 2006 IDEGraident Editor Tab is Only From WinControl, not TabSet/TabControl +{$ENDIF} + +{$IFDEF BDS2005_UP} + {$DEFINE OTA_PALETTE_API} // 2005 and above Provides PaletteAPI. + {$DEFINE IDE_EDITOR_ELIDE} // 2005 ϱ༭֧۵ + {$DEFINE IDE_FILE_HISTORY} // 2005 ϰ汾洢ļʷ汾 +{$ENDIF} + +{$IFDEF BDS2006} + {$DEFINE PROJECT_FILENAME_BDSPROJ} // Project File is .bdsproj +{$ENDIF} + +{$IFDEF BDS2005} + {$DEFINE PROJECT_FILENAME_BDSPROJ} // Project File is .bdsproj +{$ENDIF} + +{$IFDEF BDS} // 2005 + {$DEFINE SUPPORT_PASCAL} + {$DEFINE SUPPORT_CSHARP} + {$DEFINE SUPPORT_INLINE} + {$DEFINE SUPPORT_UINT64} + {$DEFINE IDE_WIDECONTROL} // 2005 ϵı༭ڲǿַ UTF-8Ƿ Unicode + {$DEFINE IDE_EDITOR_SUPPORT_FOLDING} // 2005 ϵı༭֧۵ + {$DEFINE OTA_NEW_BREAKPOINT_NOBUG} // 2005 ϵ NewBreakpoint ܹ + {$DEFINE IDE_ACTION_UPDATE_DELAY} // IDE's Action Menu Update will Delay in 2005 or Up. + {$DEFINE SUPPORT_WIDECHAR_IDENTIFIER} + + {$IFNDEF COMPILER12_UP} + // 2005~2007 Compiler is Ansi but Editor String is UTF-8 + {$DEFINE IDE_STRING_ANSI_UTF8} + {$ENDIF} +{$ENDIF} + +{$IFDEF DELPHI7_UP} + {$DEFINE SUPPORT_FORMAT_SETTINGS} // Delphi 7 ʼ֧ FormatSettings + {$DEFINE IDE_MENUBAR_VERTICAL_POSITION_BUG} + // Delphi 7 ϵ MenuBar ֱϵĵλü׳Ͻ + {$DEFINE IDE_MENUBAR_VERTICAL_NOSCROLL_BUG} + // Delphi 7 ϵ MenuBar ֱʱ +{$ENDIF} + +{$IFDEF COMPILER6_UP} + {$DEFINE SUPPORT_DEPRECATED} +{$ENDIF} + +{$IFDEF COMPILER6_UP} + {$DEFINE SUPPORT_ENUMVALUES} + {$DEFINE SUPPORT_VARIANTS} + {$DEFINE SUPPORT_IFDIRECTIVE} +{$ENDIF} + +{$IFDEF DELPHI5_UP} + {$IFNDEF BDS2005_UP} + {$DEFINE PROJECT_FILENAME_DPR} // Delphi 5/6/7 Project File is .dpr + {$ENDIF} +{$ENDIF} + +{$IFDEF COMPILER5} + {$DEFINE TSTREAM_LONGINT} // D6 ϵ TStream Int64 +{$ENDIF} + +{$IFDEF BCB5} + {$DEFINE BCB5OR6} // һ BCB5OR6 Է BCB5 BCB6 ʹ +{$ENDIF} + +{$IFDEF BCB6} + {$DEFINE BCB5OR6} +{$ENDIF} + +{$IFDEF BCB5OR6} + {$DEFINE NO_ZLIB} +{$ENDIF} + +{$IFDEF DELPHI5} + {$DEFINE DELPHI5OR6} // һ DELPHI5OR6 Է DELPHI5 DELPHI6 ʹ +{$ENDIF} + +{$IFDEF DELPHI6} + {$DEFINE DELPHI5OR6} +{$ENDIF} + +{$IFDEF COMPILER4_UP} + {$DEFINE SUPPORT_INT64} + {$DEFINE SUPPORT_DYNAMICARRAYS} + {$DEFINE SUPPORT_DEFAULTPARAMS} + {$DEFINE SUPPORT_REINTRODUCE} + {$DEFINE SUPPORT_OVERLOAD} +{$ENDIF} + +{$IFDEF COMPILER35_UP} + {$DEFINE SUPPORT_EXTSYM} + {$DEFINE SUPPORT_NODEFINE} +{$ENDIF} + +{$IFDEF COMPILER3_UP} + {$DEFINE SUPPORT_WIDESTRING} + {$DEFINE SUPPORT_INTERFACE} +{$ENDIF} + +{$IFDEF WIN64} + {$DEFINE EXTENDED_SIZE_8} // Win64 Extended ͳ 8 ֽ +{$ENDIF} + +{$IFDEF CPUARM} + {$DEFINE EXTENDED_SIZE_8} // ARM ƽ̨ Extended ͳ 8 ֽ +{$ENDIF} + +{$IFDEF WIN32} + {$DEFINE EXTENDED_SIZE_10} // Win32 Extended ͳ 10 ֽ +{$ENDIF} + +{$IFDEF MACOS64} + {$DEFINE EXTENDED_SIZE_16} // MacOS64 Extended ͳ 16 ֽ +{$ENDIF} + +{$IFDEF LINUX64} + {$DEFINE EXTENDED_SIZE_16} // Linux64 Extended ͳ 16 ֽ +{$ENDIF} + +//============================================================================== +// PascalScript ĵ +//============================================================================== + +{.$DEFINE ALLDEBUG} // òƲҪȽ + +//============================================================================== +// ֶ +//============================================================================== + +{$DEFINE GB2312} +{.$DEFINE BIG5} +{.$DEFINE ENGLISH} + +//============================================================================== +// ıָ +//============================================================================== + +{$A+ Force alignment on word/dword boundaries} +{$S+ stack checking} + +{$B- Short evaluation of boolean values} +{$H+ Long string support} +{$V- No var string checking} +{$X+ Extended syntax} +{$P+ Open string parameters} +{$J+ Writeable typed constants} +{$R- No Range checking} +{$OVERFLOWCHECKS OFF} + +{$IFDEF COMPILER6_UP} + {$WARN SYMBOL_PLATFORM OFF} + {$WARN UNIT_PLATFORM OFF} + {$WARN SYMBOL_DEPRECATED OFF} + {$WARN UNIT_DEPRECATED OFF} +{$ENDIF} + +{$IFDEF COMPILER7_UP} + {$WARN UNSAFE_CAST OFF} + {$WARN UNSAFE_CODE OFF} + {$WARN UNSAFE_TYPE OFF} +{$ENDIF} + +{$IFDEF BCB} + {$OBJEXPORTALL ON} +{$ENDIF} + +{$DEFINE CN_USE_MSXML} + +{$ENDIF FPC} + diff --git a/CnPack/Crypto/CnAES.dcu b/CnPack/Crypto/CnAES.dcu new file mode 100644 index 0000000000000000000000000000000000000000..ebc666a410074a233b156bd06d693c171451fb02 GIT binary patch literal 122925 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 +================================================================================ +* ƣ +* ԪƣAES ԳƼӽ㷨ʵֵԪ +* ԪߣCnPack (master@cnpack.org) +* EldoS, Alexander Ionov ĵԪֲ书ܣԭаȨϢ +* עԪʵ AES 128/192/256 ԳƼӽ㷨ֿС̶ 16 ֽڣģʽ +* Ķ뷽ʽĩβ 0Ԫڲ֧ PKCS ȿ뷽ʽҪⲿ +* CnPemUtils.pas Ԫе PKCS ϵкԼӽݽж⴦ +* +* ߰汾 Delphi 뾡ʹ AnsiString 汾ĺʮƳ⣩ +* ⲻַӰӽܽ +* +* 䣺============= Java Ĭϵ AES Ӧ˴ AES256 ============ +* ⣬C++Builder 5/6 ¶ overload ĺʴжϴӶ +* ҵΣʱԪ˴ overload Delphi ´ڣ +* ٷװ˲ֲͬĺ֧ C++Builder 5/6 ±С +* +* ECB/CBC ǿģʽҪ롣CFB/OFB/CTR ĵģʽ뵽顣 +* +* ⣬CTR ģʽ RFC 3686 淶紫ݵ 4 ֽ Nonce8 ֽ +* ʼ4 ֽֽļƴ 16 ֽڵijʼ +* AES 㣬ӽܾΪĶ +* +* ƽ̨Delphi5 + Win 7 +* ޸ļ¼2024.07.25 V1.3 +* CTR ģʽ֧֣ѭ RFC 3686 淶 +* 2024.05.26 V1.2 +* 䲿֧ C++Builder ĺ +* 2022.06.21 V1.1 +* 뼸ֽ鵽ʮַ֮ļӽܺ +* 2021.12.11 V1.2 +* CFB/OFB ģʽ֧ +* 2019.04.15 V1.1 +* ֧ Win32/Win64/MacOS +* 2015.01.21 V1.0 +* Ԫ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + Classes, SysUtils, CnNative; + +const + CN_AES_BLOCKSIZE = 16; + {* AES ķܿСλ٣Ϊ 16 ֽ} + +type + TCnKeyBitType = (kbt128, kbt192, kbt256); + {* AES λ16 ֽڡ24 ֽں 32 ֽ} + + ECnAESException = class(Exception); + {* AES 쳣} + + TCnAESBuffer = array [0..15] of Byte; + {* AES ӽܿ 16 ֽ} + + TCnAESKey128 = array [0..15] of Byte; + {* AES128 Կṹ16 ֽ} + + TCnAESKey192 = array [0..23] of Byte; + {* AES192 Կṹ24 ֽ} + + TCnAESKey256 = array [0..31] of Byte; + {* AES256 Կṹ32 ֽ} + + TCnAESExpandedKey128 = array [0..43] of Cardinal; + {* AES128 չԿṹ} + + TCnAESExpandedKey192 = array [0..53] of Cardinal; + {* AES192 չԿṹ} + + TCnAESExpandedKey256 = array [0..63] of Cardinal; + {* AES256 չԿṹ} + + PCnAESBuffer = ^TCnAESBuffer; + PCnAESKey128 = ^TCnAESKey128; + PCnAESKey192 = ^TCnAESKey192; + PCnAESKey256 = ^TCnAESKey256; + PCnAESExpandedKey128 = ^TCnAESExpandedKey128; + PCnAESExpandedKey192 = ^TCnAESExpandedKey192; + PCnAESExpandedKey256 = ^TCnAESExpandedKey256; + + TCnAESCTRNonce = array[0..3] of Byte; + {* CTR ģʽµ Nonce ṹ4 ֽ} + TCnAESCTRIv = array[0..7] of Byte; + {* CTR ģʽµijʼṹ8 ֽ} + +// Key Expansion Routines for Encryption + +procedure ExpandAESKeyForEncryption128(const Key: TCnAESKey128; + var ExpandedKey: TCnAESExpandedKey128); +{* ڼܳչ AES128 Կ + + + const Key: TCnAESKey128 - չ AES128 Կ + var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForEncryption192(const Key: TCnAESKey192; + var ExpandedKey: TCnAESExpandedKey192); +{* ڼܳչ AES192 Կ + + + const Key: TCnAESKey192 - չ AES192 Կ + var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForEncryption256(const Key: TCnAESKey256; + var ExpandedKey: TCnAESExpandedKey256); +{* ڼܳչ AES256 Կ + + + const Key: TCnAESKey256 - չ AES256 Կ + var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ + + ֵޣ +} + +// Block Encryption Routines ܣInBuf OutBuf ͬһ + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); overload; +{* AES128 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey128 - չ AES128 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); overload; +{* AES192 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey192 - չ AES192 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); overload; +{* AES256 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey256 - չ AES256 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +{* AES128 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey128 - չ AES128 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure EncryptAES192(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +{* AES192 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey192 - չ AES192 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure EncryptAES256(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +{* AES256 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey256 - չ AES256 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +// Stream Encryption Routines (ECB mode) ECB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); overload; +{* AES128 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); overload; +{* AES128 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); overload; +{* AES256 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); overload; +{* AES192 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); overload; +{* AES256 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); overload; +{* AES256 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +{* AES128 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES128StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +{* AES128 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES192StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +{* AES192 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +{* AES192 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES256StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +{* AES256 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +{* AES256 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + Dest: TStream - + + ֵޣ +} + +// Stream Encryption Routines (CBC mode) CBC + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES128StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES192StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES256StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Encryption Routines (CFB mode) CFB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES128StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Encryption Routines (OFB mode) OFB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES128StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES192StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - ?? + + ֵޣ +} +procedure EncryptAES192StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES256StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Encryption Routines (CTR mode) CTR + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES128 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES128 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES192 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES192 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES256 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES256 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES128 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES128StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES128 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES192 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES192 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES256 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES256 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Key Transformation Routines for Decryption + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey128); overload; +{* ڽܳչ AES128 Կ + + + var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey128; + var ExpandedKey: TCnAESExpandedKey128); overload; +{* ڽܳչ AES128 Կ + + + const Key: TCnAESKey128 - չ AES128 Կ + var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey192); overload; +{* ڽܳչ AES192 Կ + + + var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ + + ֵޣ +} +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey192; + var ExpandedKey: TCnAESExpandedKey192); overload; +{* ڽܳչ AES192 Կ + + + const Key: TCnAESKey192 - չ AES192 Կ + var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey256); overload; +{* ڽܳչ AES256 Կ + + + var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ + + ֵޣ +} +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey256; + var ExpandedKey: TCnAESExpandedKey256); overload; +{* ڽܳչ AES256 Կ + + + const Key: TCnAESKey256 - չ AES256 Կ + var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure ExpandAESKeyForDecryption128(var ExpandedKey: TCnAESExpandedKey128); +{* ڽܳչ AES128 Կ + + + var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ + + ֵޣ +} +procedure ExpandAESKeyForDecryption128Expanded(const Key: TCnAESKey128; + var ExpandedKey: TCnAESExpandedKey128); +{* ڽܳչ AES128 Կ + + + const Key: TCnAESKey128 - չ AES128 Կ + var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForDecryption192(var ExpandedKey: TCnAESExpandedKey192); +{* ڽܳչ AES192 Կ + + + var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ + + ֵޣ +} +procedure ExpandAESKeyForDecryption192Expanded(const Key: TCnAESKey192; + var ExpandedKey: TCnAESExpandedKey192); +{* ڽܳչ AES192 Կ + + + const Key: TCnAESKey192 - չ AES192 Կ + var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForDecryption256(var ExpandedKey: TCnAESExpandedKey256); +{* ڽܳչ AES256 Կ + + + var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ + + ֵޣ +} +procedure ExpandAESKeyForDecryption256Expanded(const Key: TCnAESKey256; + var ExpandedKey: TCnAESExpandedKey256); +{* ڽܳչ AES256 Կ + + + const Key: TCnAESKey256 - չ AES256 Կ + var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ + + ֵޣ +} + +// Block Decryption Routines + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); overload; +{* AES128 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey128 - չ AES128 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); overload; +{* AES192 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey192 - չ AES192 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); overload; +{* AES256 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey256 - չ AES256 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +{* AES128 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey128 - չ AES128 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure DecryptAES192(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +{* AES192 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey192 - չ AES192 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure DecryptAES256(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +{* AES256 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey256 - չ AES256 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +// Stream Decryption Routines (ECB mode) ECB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); overload; +{* AES128 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); overload; +{* AES128 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); overload; +{* AES192 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); overload; +{* AES192 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); overload; +{* AES256 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); overload; +{* AES256 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +{* AES128 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES128StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +{* AES128 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAES192StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +{* AES192 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +{* AES192 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAES256StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +{* AES256 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +{* AES156 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + Dest: TStream - + + ֵޣ +} + +// Stream Decryption Routines (CBC mode) CBC + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES128StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Decryption Routines (CFB mode) CFB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES128StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Decryption Routines (OFB mode) OFB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES128StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Decryption Routines (CTR mode) CTR + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES128 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES128 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES192 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES192 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES256 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES256 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES128 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES128StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES128 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES192 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES192 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES256 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES256 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// ============== ַʮַ֮ļӽ =================== + +function AESEncryptEcbStrToHex(Value: AnsiString; Key: AnsiString; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES ECB ģʽַתʮơ + + + Value: AnsiString - ַܵ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptEcbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES ECB ʮַ + + + const HexStr: AnsiString - ܵʮַ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ַ +} + +function AESEncryptCbcStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CBC ģʽַתʮơ + + + Value: AnsiString - ַܵ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCbcStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CBC ʮַ + + + const HexStr: AnsiString - ܵʮַ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ַ +} + +function AESEncryptCfbStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CFB ģʽַתʮơ + + + Value: AnsiString - ַܵ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCfbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CFB ʮַ + + + const HexStr: AnsiString - ܵʮַ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ַ +} + +function AESEncryptOfbStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES OFB ģʽַתʮơ + + + Value: AnsiString - ַܵ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptOfbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES OFB ʮַ + + + const HexStr: AnsiString - ܵʮַ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ַ +} + +function AESEncryptCtrStrToHex(Value: AnsiString; Key: AnsiString; + const Nonce: TCnAESCTRNonce; const Iv: TCnAESCTRIv; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CTR ģʽַתʮơ + + + Value: AnsiString - ַܵ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const Iv: TCnAESCTRIv - 8 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCtrStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Nonce: TCnAESCTRNonce; const Iv: TCnAESCTRIv; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CTR ʮַ + + + const HexStr: AnsiString - ܵʮַ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const Iv: TCnAESCTRIv - 8 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ַ +} + +// ================= ֽֽ֮ļӽ ==================== + +function AESEncryptEcbBytes(Value: TBytes; Key: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES ECB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESDecryptEcbBytes(Value: TBytes; Key: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES ECB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCbcBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CBC ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESDecryptCbcBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CBC ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCfbBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CFB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESDecryptCfbBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CFB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptOfbBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES OFB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESDecryptOfbBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES OFB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCtrBytes(Value: TBytes; Key: TBytes; Nonce: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CTR ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Nonce: TBytes - 4 ֽ Nonce 飬̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESDecryptCtrBytes(Value: TBytes; Key: TBytes; Nonce: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CTR ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Nonce: TBytes - 4 ֽ Nonce 飬̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +// ============== ֽʮַ֮ļӽ ================= + +function AESEncryptEcbBytesToHex(Value: TBytes; Key: TBytes; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES ECB ģʽֽ鲢תʮơ + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptEcbBytesFromHex(const HexStr: AnsiString; Key: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES ECB ʮַֽ顣 + + + const HexStr: AnsiString - ܵʮַ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCbcBytesToHex(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CBC ģʽֽ鲢תʮơ + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCbcBytesFromHex(const HexStr: AnsiString; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CBC ʮַֽ顣 + + + const HexStr: AnsiString - ܵʮַ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCfbBytesToHex(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CFB ģʽֽ鲢תʮơ + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCfbBytesFromHex(const HexStr: AnsiString; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CFB ʮַֽ顣 + + + const HexStr: AnsiString - ܵʮַ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptOfbBytesToHex(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES OFB ģʽֽ鲢תʮơ + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptOfbBytesFromHex(const HexStr: AnsiString; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES OFB ʮַֽ顣 + + + const HexStr: AnsiString - ܵʮַ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCtrBytesToHex(Value: TBytes; Key: TBytes; Nonce: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CTR ģʽֽ鲢תʮơ + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Nonce: TBytes - 4 ֽ Nonce ֽ飬̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCtrBytesFromHex(const HexStr: AnsiString; Key: TBytes; Nonce: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CTR ʮַֽ顣 + + + const HexStr: AnsiString - ܵʮַ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Nonce: TBytes - 4 ֽ Nonce ֽ飬̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +implementation + +resourcestring + SCnErrorAESInvalidInBufSize = 'Invalid Buffer Size for Decryption'; + SCnErrorAESReadError = 'Stream Read Error'; + SCnErrorAESWriteError = 'Stream Write Error'; + +function Min(A, B: Integer): Integer; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + if A < B then + Result := A + else + Result := B; +end; + +const + Rcon: array [1..30] of Cardinal = ( + $00000001, $00000002, $00000004, $00000008, $00000010, $00000020, + $00000040, $00000080, $0000001B, $00000036, $0000006C, $000000D8, + $000000AB, $0000004D, $0000009A, $0000002F, $0000005E, $000000BC, + $00000063, $000000C6, $00000097, $00000035, $0000006A, $000000D4, + $000000B3, $0000007D, $000000FA, $000000EF, $000000C5, $00000091 + ); + + ForwardTable: array [0..255] of Cardinal = ( + $A56363C6, $847C7CF8, $997777EE, $8D7B7BF6, $0DF2F2FF, $BD6B6BD6, $B16F6FDE, $54C5C591, + $50303060, $03010102, $A96767CE, $7D2B2B56, $19FEFEE7, $62D7D7B5, $E6ABAB4D, $9A7676EC, + $45CACA8F, $9D82821F, $40C9C989, $877D7DFA, $15FAFAEF, $EB5959B2, $C947478E, $0BF0F0FB, + $ECADAD41, $67D4D4B3, $FDA2A25F, $EAAFAF45, $BF9C9C23, $F7A4A453, $967272E4, $5BC0C09B, + $C2B7B775, $1CFDFDE1, $AE93933D, $6A26264C, $5A36366C, $413F3F7E, $02F7F7F5, $4FCCCC83, + $5C343468, $F4A5A551, $34E5E5D1, $08F1F1F9, $937171E2, $73D8D8AB, $53313162, $3F15152A, + $0C040408, $52C7C795, $65232346, $5EC3C39D, $28181830, $A1969637, $0F05050A, $B59A9A2F, + $0907070E, $36121224, $9B80801B, $3DE2E2DF, $26EBEBCD, $6927274E, $CDB2B27F, $9F7575EA, + $1B090912, $9E83831D, $742C2C58, $2E1A1A34, $2D1B1B36, $B26E6EDC, $EE5A5AB4, $FBA0A05B, + $F65252A4, $4D3B3B76, $61D6D6B7, $CEB3B37D, $7B292952, $3EE3E3DD, $712F2F5E, $97848413, + $F55353A6, $68D1D1B9, $00000000, $2CEDEDC1, $60202040, $1FFCFCE3, $C8B1B179, $ED5B5BB6, + $BE6A6AD4, $46CBCB8D, $D9BEBE67, $4B393972, $DE4A4A94, $D44C4C98, $E85858B0, $4ACFCF85, + $6BD0D0BB, $2AEFEFC5, $E5AAAA4F, $16FBFBED, $C5434386, $D74D4D9A, $55333366, $94858511, + $CF45458A, $10F9F9E9, $06020204, $817F7FFE, $F05050A0, $443C3C78, $BA9F9F25, $E3A8A84B, + $F35151A2, $FEA3A35D, $C0404080, $8A8F8F05, $AD92923F, $BC9D9D21, $48383870, $04F5F5F1, + $DFBCBC63, $C1B6B677, $75DADAAF, $63212142, $30101020, $1AFFFFE5, $0EF3F3FD, $6DD2D2BF, + $4CCDCD81, $140C0C18, $35131326, $2FECECC3, $E15F5FBE, $A2979735, $CC444488, $3917172E, + $57C4C493, $F2A7A755, $827E7EFC, $473D3D7A, $AC6464C8, $E75D5DBA, $2B191932, $957373E6, + $A06060C0, $98818119, $D14F4F9E, $7FDCDCA3, $66222244, $7E2A2A54, $AB90903B, $8388880B, + $CA46468C, $29EEEEC7, $D3B8B86B, $3C141428, $79DEDEA7, $E25E5EBC, $1D0B0B16, $76DBDBAD, + $3BE0E0DB, $56323264, $4E3A3A74, $1E0A0A14, $DB494992, $0A06060C, $6C242448, $E45C5CB8, + $5DC2C29F, $6ED3D3BD, $EFACAC43, $A66262C4, $A8919139, $A4959531, $37E4E4D3, $8B7979F2, + $32E7E7D5, $43C8C88B, $5937376E, $B76D6DDA, $8C8D8D01, $64D5D5B1, $D24E4E9C, $E0A9A949, + $B46C6CD8, $FA5656AC, $07F4F4F3, $25EAEACF, $AF6565CA, $8E7A7AF4, $E9AEAE47, $18080810, + $D5BABA6F, $887878F0, $6F25254A, $722E2E5C, $241C1C38, $F1A6A657, $C7B4B473, $51C6C697, + $23E8E8CB, $7CDDDDA1, $9C7474E8, $211F1F3E, $DD4B4B96, $DCBDBD61, $868B8B0D, $858A8A0F, + $907070E0, $423E3E7C, $C4B5B571, $AA6666CC, $D8484890, $05030306, $01F6F6F7, $120E0E1C, + $A36161C2, $5F35356A, $F95757AE, $D0B9B969, $91868617, $58C1C199, $271D1D3A, $B99E9E27, + $38E1E1D9, $13F8F8EB, $B398982B, $33111122, $BB6969D2, $70D9D9A9, $898E8E07, $A7949433, + $B69B9B2D, $221E1E3C, $92878715, $20E9E9C9, $49CECE87, $FF5555AA, $78282850, $7ADFDFA5, + $8F8C8C03, $F8A1A159, $80898909, $170D0D1A, $DABFBF65, $31E6E6D7, $C6424284, $B86868D0, + $C3414182, $B0999929, $772D2D5A, $110F0F1E, $CBB0B07B, $FC5454A8, $D6BBBB6D, $3A16162C + ); + + LastForwardTable: array [0..255] of Cardinal = ( + $00000063, $0000007C, $00000077, $0000007B, $000000F2, $0000006B, $0000006F, $000000C5, + $00000030, $00000001, $00000067, $0000002B, $000000FE, $000000D7, $000000AB, $00000076, + $000000CA, $00000082, $000000C9, $0000007D, $000000FA, $00000059, $00000047, $000000F0, + $000000AD, $000000D4, $000000A2, $000000AF, $0000009C, $000000A4, $00000072, $000000C0, + $000000B7, $000000FD, $00000093, $00000026, $00000036, $0000003F, $000000F7, $000000CC, + $00000034, $000000A5, $000000E5, $000000F1, $00000071, $000000D8, $00000031, $00000015, + $00000004, $000000C7, $00000023, $000000C3, $00000018, $00000096, $00000005, $0000009A, + $00000007, $00000012, $00000080, $000000E2, $000000EB, $00000027, $000000B2, $00000075, + $00000009, $00000083, $0000002C, $0000001A, $0000001B, $0000006E, $0000005A, $000000A0, + $00000052, $0000003B, $000000D6, $000000B3, $00000029, $000000E3, $0000002F, $00000084, + $00000053, $000000D1, $00000000, $000000ED, $00000020, $000000FC, $000000B1, $0000005B, + $0000006A, $000000CB, $000000BE, $00000039, $0000004A, $0000004C, $00000058, $000000CF, + $000000D0, $000000EF, $000000AA, $000000FB, $00000043, $0000004D, $00000033, $00000085, + $00000045, $000000F9, $00000002, $0000007F, $00000050, $0000003C, $0000009F, $000000A8, + $00000051, $000000A3, $00000040, $0000008F, $00000092, $0000009D, $00000038, $000000F5, + $000000BC, $000000B6, $000000DA, $00000021, $00000010, $000000FF, $000000F3, $000000D2, + $000000CD, $0000000C, $00000013, $000000EC, $0000005F, $00000097, $00000044, $00000017, + $000000C4, $000000A7, $0000007E, $0000003D, $00000064, $0000005D, $00000019, $00000073, + $00000060, $00000081, $0000004F, $000000DC, $00000022, $0000002A, $00000090, $00000088, + $00000046, $000000EE, $000000B8, $00000014, $000000DE, $0000005E, $0000000B, $000000DB, + $000000E0, $00000032, $0000003A, $0000000A, $00000049, $00000006, $00000024, $0000005C, + $000000C2, $000000D3, $000000AC, $00000062, $00000091, $00000095, $000000E4, $00000079, + $000000E7, $000000C8, $00000037, $0000006D, $0000008D, $000000D5, $0000004E, $000000A9, + $0000006C, $00000056, $000000F4, $000000EA, $00000065, $0000007A, $000000AE, $00000008, + $000000BA, $00000078, $00000025, $0000002E, $0000001C, $000000A6, $000000B4, $000000C6, + $000000E8, $000000DD, $00000074, $0000001F, $0000004B, $000000BD, $0000008B, $0000008A, + $00000070, $0000003E, $000000B5, $00000066, $00000048, $00000003, $000000F6, $0000000E, + $00000061, $00000035, $00000057, $000000B9, $00000086, $000000C1, $0000001D, $0000009E, + $000000E1, $000000F8, $00000098, $00000011, $00000069, $000000D9, $0000008E, $00000094, + $0000009B, $0000001E, $00000087, $000000E9, $000000CE, $00000055, $00000028, $000000DF, + $0000008C, $000000A1, $00000089, $0000000D, $000000BF, $000000E6, $00000042, $00000068, + $00000041, $00000099, $0000002D, $0000000F, $000000B0, $00000054, $000000BB, $00000016 + ); + + InverseTable: array [0..255] of Cardinal = ( + $50A7F451, $5365417E, $C3A4171A, $965E273A, $CB6BAB3B, $F1459D1F, $AB58FAAC, $9303E34B, + $55FA3020, $F66D76AD, $9176CC88, $254C02F5, $FCD7E54F, $D7CB2AC5, $80443526, $8FA362B5, + $495AB1DE, $671BBA25, $980EEA45, $E1C0FE5D, $02752FC3, $12F04C81, $A397468D, $C6F9D36B, + $E75F8F03, $959C9215, $EB7A6DBF, $DA595295, $2D83BED4, $D3217458, $2969E049, $44C8C98E, + $6A89C275, $78798EF4, $6B3E5899, $DD71B927, $B64FE1BE, $17AD88F0, $66AC20C9, $B43ACE7D, + $184ADF63, $82311AE5, $60335197, $457F5362, $E07764B1, $84AE6BBB, $1CA081FE, $942B08F9, + $58684870, $19FD458F, $876CDE94, $B7F87B52, $23D373AB, $E2024B72, $578F1FE3, $2AAB5566, + $0728EBB2, $03C2B52F, $9A7BC586, $A50837D3, $F2872830, $B2A5BF23, $BA6A0302, $5C8216ED, + $2B1CCF8A, $92B479A7, $F0F207F3, $A1E2694E, $CDF4DA65, $D5BE0506, $1F6234D1, $8AFEA6C4, + $9D532E34, $A055F3A2, $32E18A05, $75EBF6A4, $39EC830B, $AAEF6040, $069F715E, $51106EBD, + $F98A213E, $3D06DD96, $AE053EDD, $46BDE64D, $B58D5491, $055DC471, $6FD40604, $FF155060, + $24FB9819, $97E9BDD6, $CC434089, $779ED967, $BD42E8B0, $888B8907, $385B19E7, $DBEEC879, + $470A7CA1, $E90F427C, $C91E84F8, $00000000, $83868009, $48ED2B32, $AC70111E, $4E725A6C, + $FBFF0EFD, $5638850F, $1ED5AE3D, $27392D36, $64D90F0A, $21A65C68, $D1545B9B, $3A2E3624, + $B1670A0C, $0FE75793, $D296EEB4, $9E919B1B, $4FC5C080, $A220DC61, $694B775A, $161A121C, + $0ABA93E2, $E52AA0C0, $43E0223C, $1D171B12, $0B0D090E, $ADC78BF2, $B9A8B62D, $C8A91E14, + $8519F157, $4C0775AF, $BBDD99EE, $FD607FA3, $9F2601F7, $BCF5725C, $C53B6644, $347EFB5B, + $7629438B, $DCC623CB, $68FCEDB6, $63F1E4B8, $CADC31D7, $10856342, $40229713, $2011C684, + $7D244A85, $F83DBBD2, $1132F9AE, $6DA129C7, $4B2F9E1D, $F330B2DC, $EC52860D, $D0E3C177, + $6C16B32B, $99B970A9, $FA489411, $2264E947, $C48CFCA8, $1A3FF0A0, $D82C7D56, $EF903322, + $C74E4987, $C1D138D9, $FEA2CA8C, $360BD498, $CF81F5A6, $28DE7AA5, $268EB7DA, $A4BFAD3F, + $E49D3A2C, $0D927850, $9BCC5F6A, $62467E54, $C2138DF6, $E8B8D890, $5EF7392E, $F5AFC382, + $BE805D9F, $7C93D069, $A92DD56F, $B31225CF, $3B99ACC8, $A77D1810, $6E639CE8, $7BBB3BDB, + $097826CD, $F418596E, $01B79AEC, $A89A4F83, $656E95E6, $7EE6FFAA, $08CFBC21, $E6E815EF, + $D99BE7BA, $CE366F4A, $D4099FEA, $D67CB029, $AFB2A431, $31233F2A, $3094A5C6, $C066A235, + $37BC4E74, $A6CA82FC, $B0D090E0, $15D8A733, $4A9804F1, $F7DAEC41, $0E50CD7F, $2FF69117, + $8DD64D76, $4DB0EF43, $544DAACC, $DF0496E4, $E3B5D19E, $1B886A4C, $B81F2CC1, $7F516546, + $04EA5E9D, $5D358C01, $737487FA, $2E410BFB, $5A1D67B3, $52D2DB92, $335610E9, $1347D66D, + $8C61D79A, $7A0CA137, $8E14F859, $893C13EB, $EE27A9CE, $35C961B7, $EDE51CE1, $3CB1477A, + $59DFD29C, $3F73F255, $79CE1418, $BF37C773, $EACDF753, $5BAAFD5F, $146F3DDF, $86DB4478, + $81F3AFCA, $3EC468B9, $2C342438, $5F40A3C2, $72C31D16, $0C25E2BC, $8B493C28, $41950DFF, + $7101A839, $DEB30C08, $9CE4B4D8, $90C15664, $6184CB7B, $70B632D5, $745C6C48, $4257B8D0 + ); + + LastInverseTable: array [0..255] of Cardinal = ( + $00000052, $00000009, $0000006A, $000000D5, $00000030, $00000036, $000000A5, $00000038, + $000000BF, $00000040, $000000A3, $0000009E, $00000081, $000000F3, $000000D7, $000000FB, + $0000007C, $000000E3, $00000039, $00000082, $0000009B, $0000002F, $000000FF, $00000087, + $00000034, $0000008E, $00000043, $00000044, $000000C4, $000000DE, $000000E9, $000000CB, + $00000054, $0000007B, $00000094, $00000032, $000000A6, $000000C2, $00000023, $0000003D, + $000000EE, $0000004C, $00000095, $0000000B, $00000042, $000000FA, $000000C3, $0000004E, + $00000008, $0000002E, $000000A1, $00000066, $00000028, $000000D9, $00000024, $000000B2, + $00000076, $0000005B, $000000A2, $00000049, $0000006D, $0000008B, $000000D1, $00000025, + $00000072, $000000F8, $000000F6, $00000064, $00000086, $00000068, $00000098, $00000016, + $000000D4, $000000A4, $0000005C, $000000CC, $0000005D, $00000065, $000000B6, $00000092, + $0000006C, $00000070, $00000048, $00000050, $000000FD, $000000ED, $000000B9, $000000DA, + $0000005E, $00000015, $00000046, $00000057, $000000A7, $0000008D, $0000009D, $00000084, + $00000090, $000000D8, $000000AB, $00000000, $0000008C, $000000BC, $000000D3, $0000000A, + $000000F7, $000000E4, $00000058, $00000005, $000000B8, $000000B3, $00000045, $00000006, + $000000D0, $0000002C, $0000001E, $0000008F, $000000CA, $0000003F, $0000000F, $00000002, + $000000C1, $000000AF, $000000BD, $00000003, $00000001, $00000013, $0000008A, $0000006B, + $0000003A, $00000091, $00000011, $00000041, $0000004F, $00000067, $000000DC, $000000EA, + $00000097, $000000F2, $000000CF, $000000CE, $000000F0, $000000B4, $000000E6, $00000073, + $00000096, $000000AC, $00000074, $00000022, $000000E7, $000000AD, $00000035, $00000085, + $000000E2, $000000F9, $00000037, $000000E8, $0000001C, $00000075, $000000DF, $0000006E, + $00000047, $000000F1, $0000001A, $00000071, $0000001D, $00000029, $000000C5, $00000089, + $0000006F, $000000B7, $00000062, $0000000E, $000000AA, $00000018, $000000BE, $0000001B, + $000000FC, $00000056, $0000003E, $0000004B, $000000C6, $000000D2, $00000079, $00000020, + $0000009A, $000000DB, $000000C0, $000000FE, $00000078, $000000CD, $0000005A, $000000F4, + $0000001F, $000000DD, $000000A8, $00000033, $00000088, $00000007, $000000C7, $00000031, + $000000B1, $00000012, $00000010, $00000059, $00000027, $00000080, $000000EC, $0000005F, + $00000060, $00000051, $0000007F, $000000A9, $00000019, $000000B5, $0000004A, $0000000D, + $0000002D, $000000E5, $0000007A, $0000009F, $00000093, $000000C9, $0000009C, $000000EF, + $000000A0, $000000E0, $0000003B, $0000004D, $000000AE, $0000002A, $000000F5, $000000B0, + $000000C8, $000000EB, $000000BB, $0000003C, $00000083, $00000053, $00000099, $00000061, + $00000017, $0000002B, $00000004, $0000007E, $000000BA, $00000077, $000000D6, $00000026, + $000000E1, $00000069, $00000014, $00000063, $00000055, $00000021, $0000000C, $0000007D + ); + +procedure ExpandAESKeyForEncryption128(const Key: TCnAESKey128; var ExpandedKey: + TCnAESExpandedKey128); +var + I, J: Integer; + T: Cardinal; + W0, W1, W2, W3: Cardinal; +begin + ExpandedKey[0] := PCardinal(@Key[0])^; + ExpandedKey[1] := PCardinal(@Key[4])^; + ExpandedKey[2] := PCardinal(@Key[8])^; + ExpandedKey[3] := PCardinal(@Key[12])^; + I := 0; J := 1; + repeat + T := (ExpandedKey[I + 3] shl 24) or (ExpandedKey[I + 3] shr 8); + W0 := LastForwardTable[Byte(T)]; W1 := LastForwardTable[Byte(T shr 8)]; + W2 := LastForwardTable[Byte(T shr 16)]; W3 := LastForwardTable[Byte(T shr 24)]; + ExpandedKey[I + 4] := ExpandedKey[I] xor + (W0 xor ((W1 shl 8) or (W1 shr 24)) xor + ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8))) xor Rcon[J]; + Inc(J); + ExpandedKey[I + 5] := ExpandedKey[I + 1] xor ExpandedKey[I + 4]; + ExpandedKey[I + 6] := ExpandedKey[I + 2] xor ExpandedKey[I + 5]; + ExpandedKey[I + 7] := ExpandedKey[I + 3] xor ExpandedKey[I + 6]; + Inc(I, 4); + until I >= 40; +end; + +procedure ExpandAESKeyForEncryption192(const Key: TCnAESKey192; var ExpandedKey: + TCnAESExpandedKey192); +var + I, J: Integer; + T: Cardinal; + W0, W1, W2, W3: Cardinal; +begin + ExpandedKey[0] := PCardinal(@Key[0])^; + ExpandedKey[1] := PCardinal(@Key[4])^; + ExpandedKey[2] := PCardinal(@Key[8])^; + ExpandedKey[3] := PCardinal(@Key[12])^; + ExpandedKey[4] := PCardinal(@Key[16])^; + ExpandedKey[5] := PCardinal(@Key[20])^; + I := 0; J := 1; + repeat + T := (ExpandedKey[I + 5] shl 24) or (ExpandedKey[I + 5] shr 8); + W0 := LastForwardTable[Byte(T)]; W1 := LastForwardTable[Byte(T shr 8)]; + W2 := LastForwardTable[Byte(T shr 16)]; W3 := LastForwardTable[Byte(T shr 24)]; + ExpandedKey[I + 6] := ExpandedKey[I] xor + (W0 xor ((W1 shl 8) or (W1 shr 24)) xor + ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8))) xor Rcon[J]; + Inc(J); + ExpandedKey[I + 7] := ExpandedKey[I + 1] xor ExpandedKey[I + 6]; + ExpandedKey[I + 8] := ExpandedKey[I + 2] xor ExpandedKey[I + 7]; + ExpandedKey[I + 9] := ExpandedKey[I + 3] xor ExpandedKey[I + 8]; + ExpandedKey[I + 10] := ExpandedKey[I + 4] xor ExpandedKey[I + 9]; + ExpandedKey[I + 11] := ExpandedKey[I + 5] xor ExpandedKey[I + 10]; + Inc(I, 6); + until I >= 46; +end; + +procedure ExpandAESKeyForEncryption256(const Key: TCnAESKey256; var ExpandedKey: + TCnAESExpandedKey256); +var + I, J: Integer; + T: Cardinal; + W0, W1, W2, W3: Cardinal; +begin + ExpandedKey[0] := PCardinal(@Key[0])^; + ExpandedKey[1] := PCardinal(@Key[4])^; + ExpandedKey[2] := PCardinal(@Key[8])^; + ExpandedKey[3] := PCardinal(@Key[12])^; + ExpandedKey[4] := PCardinal(@Key[16])^; + ExpandedKey[5] := PCardinal(@Key[20])^; + ExpandedKey[6] := PCardinal(@Key[24])^; + ExpandedKey[7] := PCardinal(@Key[28])^; + I := 0; J := 1; + repeat + T := (ExpandedKey[I + 7] shl 24) or (ExpandedKey[I + 7] shr 8); + W0 := LastForwardTable[Byte(T)]; W1 := LastForwardTable[Byte(T shr 8)]; + W2 := LastForwardTable[Byte(T shr 16)]; W3 := LastForwardTable[Byte(T shr 24)]; + ExpandedKey[I + 8] := ExpandedKey[I] xor + (W0 xor ((W1 shl 8) or (W1 shr 24)) xor + ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8))) xor Rcon[J]; + Inc(J); + ExpandedKey[I + 9] := ExpandedKey[I + 1] xor ExpandedKey[I + 8]; + ExpandedKey[I + 10] := ExpandedKey[I + 2] xor ExpandedKey[I + 9]; + ExpandedKey[I + 11] := ExpandedKey[I + 3] xor ExpandedKey[I + 10]; + W0 := LastForwardTable[Byte(ExpandedKey[I + 11])]; + W1 := LastForwardTable[Byte(ExpandedKey[I + 11] shr 8)]; + W2 := LastForwardTable[Byte(ExpandedKey[I + 11] shr 16)]; + W3 := LastForwardTable[Byte(ExpandedKey[I + 11] shr 24)]; + ExpandedKey[I + 12] := ExpandedKey[I + 4] xor + (W0 xor ((W1 shl 8) or (W1 shr 24)) xor + ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8))); + ExpandedKey[I + 13] := ExpandedKey[I + 5] xor ExpandedKey[I + 12]; + ExpandedKey[I + 14] := ExpandedKey[I + 6] xor ExpandedKey[I + 13]; + ExpandedKey[I + 15] := ExpandedKey[I + 7] xor ExpandedKey[I + 14]; + Inc(I, 8); + until I >= 52; +end; + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +begin + EncryptAES128(InBuf, Key, OutBuf); +end; + +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +begin + EncryptAES192(InBuf, Key, OutBuf); +end; + +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +begin + EncryptAES256(InBuf, Key, OutBuf); +end; + +{$ENDIF} + +procedure EncryptAES128(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[0]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[1]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[2]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[3]; + + // performing transformation 9 times + // round 1 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // round 2 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 3 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 4 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 5 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 6 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 7 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 8 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 9 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // last round of transformations + W0 := LastForwardTable[Byte(T1[0])]; W1 := LastForwardTable[Byte(T1[1] shr 8)]; + W2 := LastForwardTable[Byte(T1[2] shr 16)]; W3 := LastForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; + W0 := LastForwardTable[Byte(T1[1])]; W1 := LastForwardTable[Byte(T1[2] shr 8)]; + W2 := LastForwardTable[Byte(T1[3] shr 16)]; W3 := LastForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; + W0 := LastForwardTable[Byte(T1[2])]; W1 := LastForwardTable[Byte(T1[3] shr 8)]; + W2 := LastForwardTable[Byte(T1[0] shr 16)]; W3 := LastForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; + W0 := LastForwardTable[Byte(T1[3])]; W1 := LastForwardTable[Byte(T1[0] shr 8)]; + W2 := LastForwardTable[Byte(T1[1] shr 16)]; W3 := LastForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +procedure EncryptAES192(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[0]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[1]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[2]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[3]; + + // performing transformation 11 times + // round 1 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // round 2 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 3 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 4 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 5 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 6 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 7 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 8 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 9 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // round 10 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; + // round 11 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[44]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[45]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[46]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[47]; + // last round of transformations + W0 := LastForwardTable[Byte(T1[0])]; W1 := LastForwardTable[Byte(T1[1] shr 8)]; + W2 := LastForwardTable[Byte(T1[2] shr 16)]; W3 := LastForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[48]; + W0 := LastForwardTable[Byte(T1[1])]; W1 := LastForwardTable[Byte(T1[2] shr 8)]; + W2 := LastForwardTable[Byte(T1[3] shr 16)]; W3 := LastForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[49]; + W0 := LastForwardTable[Byte(T1[2])]; W1 := LastForwardTable[Byte(T1[3] shr 8)]; + W2 := LastForwardTable[Byte(T1[0] shr 16)]; W3 := LastForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[50]; + W0 := LastForwardTable[Byte(T1[3])]; W1 := LastForwardTable[Byte(T1[0] shr 8)]; + W2 := LastForwardTable[Byte(T1[1] shr 16)]; W3 := LastForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[51]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +procedure EncryptAES256(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[0]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[1]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[2]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[3]; + + // performing transformation 13 times + // round 1 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // round 2 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 3 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 4 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 5 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 6 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 7 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 8 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 9 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // round 10 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; + // round 11 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[44]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[45]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[46]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[47]; + // round 12 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[48]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[49]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[50]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[51]; + // round 13 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[52]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[53]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[54]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[55]; + // last round of transformations + W0 := LastForwardTable[Byte(T1[0])]; W1 := LastForwardTable[Byte(T1[1] shr 8)]; + W2 := LastForwardTable[Byte(T1[2] shr 16)]; W3 := LastForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[56]; + W0 := LastForwardTable[Byte(T1[1])]; W1 := LastForwardTable[Byte(T1[2] shr 8)]; + W2 := LastForwardTable[Byte(T1[3] shr 16)]; W3 := LastForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[57]; + W0 := LastForwardTable[Byte(T1[2])]; W1 := LastForwardTable[Byte(T1[3] shr 8)]; + W2 := LastForwardTable[Byte(T1[0] shr 16)]; W3 := LastForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[58]; + W0 := LastForwardTable[Byte(T1[3])]; W1 := LastForwardTable[Byte(T1[0] shr 8)]; + W2 := LastForwardTable[Byte(T1[1] shr 16)]; W3 := LastForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[59]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey128); +begin + ExpandAESKeyForDecryption128(ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey128; + var ExpandedKey: TCnAESExpandedKey128); +begin + ExpandAESKeyForDecryption128Expanded(Key, ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey192); +begin + ExpandAESKeyForDecryption192(ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey192; + var ExpandedKey: TCnAESExpandedKey192); +begin + ExpandAESKeyForDecryption192Expanded(Key, ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey256); +begin + ExpandAESKeyForDecryption256(ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey256; + var ExpandedKey: TCnAESExpandedKey256); +begin + ExpandAESKeyForDecryption256Expanded(Key, ExpandedKey); +end; + +{$ENDIF} + +procedure ExpandAESKeyForDecryption128(var ExpandedKey: TCnAESExpandedKey128); +var + I: Integer; + U, F2, F4, F8, F9: Cardinal; +begin + for I := 1 to 9 do + begin + F9 := ExpandedKey[I * 4]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 1]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 1] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 2]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 2] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 3]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 3] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + end; +end; + +procedure ExpandAESKeyForDecryption128Expanded(const Key: TCnAESKey128; var ExpandedKey: + TCnAESExpandedKey128); +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + ExpandAESKeyForDecryption128(ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption192(var ExpandedKey: TCnAESExpandedKey192); +var + I: Integer; + U, F2, F4, F8, F9: Cardinal; +begin + for I := 1 to 11 do + begin + F9 := ExpandedKey[I * 4]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 1]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 1] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 2]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 2] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 3]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 3] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + end; +end; + +procedure ExpandAESKeyForDecryption192Expanded(const Key: TCnAESKey192; var ExpandedKey: + TCnAESExpandedKey192); +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + ExpandAESKeyForDecryption192(ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption256(var ExpandedKey: TCnAESExpandedKey256); +var + I: Integer; + U, F2, F4, F8, F9: Cardinal; +begin + for I := 1 to 13 do + begin + F9 := ExpandedKey[I * 4]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 1]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 1] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 2]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 2] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 3]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 3] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + end; +end; + +procedure ExpandAESKeyForDecryption256Expanded(const Key: TCnAESKey256; var ExpandedKey: + TCnAESExpandedKey256); +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + ExpandAESKeyForDecryption256(ExpandedKey); +end; + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +begin + DecryptAES128(InBuf, Key, OutBuf); +end; + +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +begin + DecryptAES192(InBuf, Key, OutBuf); +end; + +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +begin + DecryptAES256(InBuf, Key, OutBuf); +end; + +{$ENDIF} + +procedure DecryptAES128(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[40]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[41]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[42]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[43]; + + // performing transformations 9 times + // round 1 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // round 2 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 3 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 4 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 5 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 6 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 7 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 8 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 9 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // last round of transformations + W0 := LastInverseTable[Byte(T1[0])]; W1 := LastInverseTable[Byte(T1[3] shr 8)]; + W2 := LastInverseTable[Byte(T1[2] shr 16)]; W3 := LastInverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[0]; + W0 := LastInverseTable[Byte(T1[1])]; W1 := LastInverseTable[Byte(T1[0] shr 8)]; + W2 := LastInverseTable[Byte(T1[3] shr 16)]; W3 := LastInverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[1]; + W0 := LastInverseTable[Byte(T1[2])]; W1 := LastInverseTable[Byte(T1[1] shr 8)]; + W2 := LastInverseTable[Byte(T1[0] shr 16)]; W3 := LastInverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[2]; + W0 := LastInverseTable[Byte(T1[3])]; W1 := LastInverseTable[Byte(T1[2] shr 8)]; + W2 := LastInverseTable[Byte(T1[1] shr 16)]; W3 := LastInverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[3]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +procedure DecryptAES192(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[48]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[49]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[50]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[51]; + + // performing transformations 11 times + // round 1 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[44]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[45]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[46]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[47]; + // round 2 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; + // round 3 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // round 4 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 5 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 6 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 7 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 8 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 9 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 10 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 11 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // last round of transformations + W0 := LastInverseTable[Byte(T1[0])]; W1 := LastInverseTable[Byte(T1[3] shr 8)]; + W2 := LastInverseTable[Byte(T1[2] shr 16)]; W3 := LastInverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[0]; + W0 := LastInverseTable[Byte(T1[1])]; W1 := LastInverseTable[Byte(T1[0] shr 8)]; + W2 := LastInverseTable[Byte(T1[3] shr 16)]; W3 := LastInverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[1]; + W0 := LastInverseTable[Byte(T1[2])]; W1 := LastInverseTable[Byte(T1[1] shr 8)]; + W2 := LastInverseTable[Byte(T1[0] shr 16)]; W3 := LastInverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[2]; + W0 := LastInverseTable[Byte(T1[3])]; W1 := LastInverseTable[Byte(T1[2] shr 8)]; + W2 := LastInverseTable[Byte(T1[1] shr 16)]; W3 := LastInverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[3]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +procedure DecryptAES256(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[56]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[57]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[58]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[59]; + + // performing transformations 13 times + // round 1 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[52]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[53]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[54]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[55]; + // round 2 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[48]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[49]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[50]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[51]; + // round 3 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[44]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[45]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[46]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[47]; + // round 4 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; + // round 5 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // round 6 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 7 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 8 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 9 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 10 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 11 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 12 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 13 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // last round of transformations + W0 := LastInverseTable[Byte(T1[0])]; W1 := LastInverseTable[Byte(T1[3] shr 8)]; + W2 := LastInverseTable[Byte(T1[2] shr 16)]; W3 := LastInverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[0]; + W0 := LastInverseTable[Byte(T1[1])]; W1 := LastInverseTable[Byte(T1[0] shr 8)]; + W2 := LastInverseTable[Byte(T1[3] shr 16)]; W3 := LastInverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[1]; + W0 := LastInverseTable[Byte(T1[2])]; W1 := LastInverseTable[Byte(T1[1] shr 8)]; + W2 := LastInverseTable[Byte(T1[0] shr 16)]; W3 := LastInverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[2]; + W0 := LastInverseTable[Byte(T1[3])]; W1 := LastInverseTable[Byte(T1[2] shr 8)]; + W2 := LastInverseTable[Byte(T1[1] shr 16)]; W3 := LastInverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[3]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +// Stream Encryption Routines (ECB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +begin + EncryptAES128StreamECB(Source, Count, Key, Dest); +end; + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +begin + EncryptAES128StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +begin + EncryptAES192StreamECB(Source, Count, Key, Dest); +end; + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +begin + EncryptAES192StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +begin + EncryptAES256StreamECB(Source, Count, Key, Dest); +end; + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +begin + EncryptAES256StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +{$ENDIF} + +procedure EncryptAES128StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + EncryptAES128StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure EncryptAES192StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + EncryptAES192StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure EncryptAES256StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + EncryptAES256StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure EncryptAES128StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + EncryptAES128(TempIn, ExpandedKey, TempOut); + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + EncryptAES128(TempIn, ExpandedKey, TempOut); + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES192StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + EncryptAES192(TempIn, ExpandedKey, TempOut); + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + EncryptAES192(TempIn, ExpandedKey, TempOut); + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES256StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + EncryptAES256(TempIn, ExpandedKey, TempOut); + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + EncryptAES256(TempIn, ExpandedKey, TempOut); + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +// Stream Decryption Routines (ECB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +begin + DecryptAES128StreamECB(Source, Count, Key, Dest); +end; + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +begin + DecryptAES128StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +begin + DecryptAES192StreamECB(Source, Count, Key, Dest); +end; + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +begin + DecryptAES192StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +begin + DecryptAES256StreamECB(Source, Count, Key, Dest); +end; + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +begin + DecryptAES256StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +{$ENDIF} + +procedure DecryptAES128StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForDecryption128Expanded(Key, ExpandedKey); + DecryptAES128StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure DecryptAES128StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + if (Count mod SizeOf(TCnAESBuffer)) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + DecryptAES128(TempIn, ExpandedKey, TempOut); + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +procedure DecryptAES192StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForDecryption192Expanded(Key, ExpandedKey); + DecryptAES192StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure DecryptAES192StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + if (Count mod SizeOf(TCnAESBuffer)) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + DecryptAES192(TempIn, ExpandedKey, TempOut); + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +procedure DecryptAES256StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForDecryption256Expanded(Key, ExpandedKey); + DecryptAES256StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure DecryptAES256StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + if (Count mod SizeOf(TCnAESBuffer)) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + DecryptAES256(TempIn, ExpandedKey, TempOut); + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +// Stream Encryption Routines (CBC mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES128StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES128StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES192StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES192StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES256StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES256StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure EncryptAES128StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + EncryptAES128StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES128StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); // Ҫÿһ鶼 + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; // ԭʼ IV + EncryptAES128(TempIn, ExpandedKey, TempOut); // ټ + Done := Dest.Write(TempOut, SizeOf(TempOut)); // д + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + Vector := TempOut; // ݴԭʼ IV һʹ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + EncryptAES128(TempIn, ExpandedKey, TempOut); + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES192StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + EncryptAES192StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES192StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + EncryptAES192(TempIn, ExpandedKey, TempOut); + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + EncryptAES192(TempIn, ExpandedKey, TempOut); + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES256StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + EncryptAES256StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES256StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + EncryptAES256(TempIn, ExpandedKey, TempOut); + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + EncryptAES256(TempIn, ExpandedKey, TempOut); + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +// Stream Decryption Routines (CBC mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES128StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES128StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES192StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES192StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES256StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES256StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure DecryptAES128StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForDecryption128Expanded(Key, ExpandedKey); + DecryptAES128StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES128StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector1, Vector2: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + if (Count mod SizeOf(TCnAESBuffer)) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); + Vector1 := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + Vector2 := TempIn; + DecryptAES128(TempIn, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@Vector1[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@Vector1[12])^; + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + Vector1 := Vector2; + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +procedure DecryptAES192StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForDecryption192Expanded(Key, ExpandedKey); + DecryptAES192StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES192StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector1, Vector2: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + if (Count mod SizeOf(TCnAESBuffer)) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); + Vector1 := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + Vector2 := TempIn; + DecryptAES192(TempIn, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@Vector1[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@Vector1[12])^; + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + Vector1 := Vector2; + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +procedure DecryptAES256StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForDecryption256Expanded(Key, ExpandedKey); + DecryptAES256StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES256StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector1, Vector2: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + if (Count mod SizeOf(TCnAESBuffer)) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); // CBC Ϊ AES ֿܲģԱ + Vector1 := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + Vector2 := TempIn; + DecryptAES256(TempIn, ExpandedKey, TempOut); // Ƚ + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; // ܺݺ Iv õ + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@Vector1[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@Vector1[12])^; + Done := Dest.Write(TempOut, SizeOf(TempOut)); // дȥ + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + Vector1 := Vector2; // ȡ Iv Ϊһκͽ + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +// Stream Encryption Routines (CFB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES128StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES128StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES192StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES192StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES256StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES256StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure EncryptAES128StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + EncryptAES128StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES128StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + EncryptAES128(Vector, ExpandedKey, TempOut); // Key ȼ Iv + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempOut, SizeOf(TempOut)); // ĽдĽ + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + Vector := TempOut; // Ľȡ Iv һּ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + EncryptAES128(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempOut, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES192StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + EncryptAES192StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES192StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempOut, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES256StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + EncryptAES256StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES256StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempOut, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +// Stream Decryption Routines (CFB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES128StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES128StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES192StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES192StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES256StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES256StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure DecryptAES128StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + DecryptAES128StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES128StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + // CFB Ϊ AES ֿܲĶ򣨳Ŀɶ + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); // + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + EncryptAES128(Vector, ExpandedKey, TempOut); // Iv ȼܡעǼܣǽܣ + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; // ܺݺõ + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + Done := Dest.Write(TempOut, SizeOf(TempOut)); // дȥ + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + Vector := TempIn; // ȡ Iv Ϊһμ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then // һ鲻Ϊ + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + EncryptAES128(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; // ܺݺõ + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + Done := Dest.Write(TempOut, Count); // дȥ + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +procedure DecryptAES192StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + DecryptAES192StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES192StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + Vector := TempIn; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + Done := Dest.Write(TempOut, Count); + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +procedure DecryptAES256StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + DecryptAES256StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES256StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + Vector := TempIn; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + Done := Dest.Write(TempOut, Count); + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +// Stream Encryption Routines (OFB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES128StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES128StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES192StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES192StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES256StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES256StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure EncryptAES128StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + EncryptAES128StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES128StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + EncryptAES128(Vector, ExpandedKey, TempOut); // Key ȼ Iv + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + Vector := TempOut; // ܽȡ Iv һּܣעⲻ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + EncryptAES128(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES192StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + EncryptAES192StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES192StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES256StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + EncryptAES256StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES256StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +// Stream Decryption Routines (OFB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES128StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES128StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES192StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES192StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES256StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES256StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure DecryptAES128StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + DecryptAES128StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES128StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + // OFB Ϊ AES ֿܲĶ򣨳Ŀɶ + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); // + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + EncryptAES128(Vector, ExpandedKey, TempOut); // Iv ȼܡעǼܣǽܣ + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; // ܺݺõ + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + Done := Dest.Write(TempIn, SizeOf(TempIn)); // дȥ + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESWriteError); + Vector := TempOut; // ȡ Iv Ϊһǰ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then // һ鲻Ϊ + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + EncryptAES128(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; // ܺݺõ + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + Done := Dest.Write(TempIn, Count); // дȥ + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +procedure DecryptAES192StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + DecryptAES192StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES192StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + Done := Dest.Write(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESWriteError); + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + Done := Dest.Write(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +procedure DecryptAES256StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + DecryptAES256StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES256StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + Done := Dest.Write(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESWriteError); + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + Done := Dest.Write(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +// Stream Encryption Routines (CTR mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES128StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES192StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES256StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +{$ENDIF} + +procedure EncryptAES128StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + EncryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure EncryptAES128StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done, Cnt, T: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + Cnt := 1; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES128(Vector, ExpandedKey, TempOut); // Key ȼƴ Iv + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Inc(Cnt); // һ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES128(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES192StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + EncryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure EncryptAES192StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done, Cnt, T: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + Cnt := 1; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES192(Vector, ExpandedKey, TempOut); // Key ȼƴ Iv + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Inc(Cnt); // һ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES256StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + EncryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure EncryptAES256StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done, Cnt, T: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then Exit; + + Cnt := 1; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES256(Vector, ExpandedKey, TempOut); // Key ȼƴ Iv + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Inc(Cnt); // һ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +// Stream Decryption Routines (CTR mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES128StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES192StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES256StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +{$ENDIF} + +procedure DecryptAES128StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + DecryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAES128StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAES192StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + DecryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAES192StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAES256StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + DecryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAES256StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +// AES ECB ַתʮ +function AESEncryptEcbStrToHex(Value: AnsiString; Key: AnsiString; + KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[1])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamECB(SS, 0, AESKey128, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamECB(SS, 0, AESKey192, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamECB(SS, 0, AESKey256, DS); + end; + end; + + Result := AnsiString(DataToHex(DS.Memory, DS.Size)); + finally + SS.Free; + DS.Free; + end; +end; + +// AES ECB ʮַ +function AESDecryptEcbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + Tmp: TBytes; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + Tmp := HexToBytes(string(HexStr)); + SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamECB(SS, SS.Size - SS.Position, AESKey128, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamECB(SS, SS.Size - SS.Position, AESKey192, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamECB(SS, SS.Size - SS.Position, AESKey256, DS); + end; + end; + + SetLength(Result, DS.Size); + Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CBC ַתʮ +function AESEncryptCbcStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[1])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCBC(SS, 0, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCBC(SS, 0, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCBC(SS, 0, AESKey256, Iv, DS); + end; + end; + + Result := AnsiString(DataToHex(DS.Memory, DS.Size)); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CBC ʮַ +function AESDecryptCbcStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + Tmp: TBytes; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + Tmp := HexToBytes(string(HexStr)); + SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCBC(SS, SS.Size - SS.Position, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCBC(SS, SS.Size - SS.Position, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCBC(SS, SS.Size - SS.Position, AESKey256, Iv, DS); + end; + end; + + SetLength(Result, DS.Size); + Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CFB ģʽַתʮ +function AESEncryptCfbStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[1])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCFB(SS, 0, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCFB(SS, 0, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCFB(SS, 0, AESKey256, Iv, DS); + end; + end; + + Result := AnsiString(DataToHex(DS.Memory, DS.Size)); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CFB ʮַ +function AESDecryptCfbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + Tmp: TBytes; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + Tmp := HexToBytes(string(HexStr)); + SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCFB(SS, SS.Size - SS.Position, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCFB(SS, SS.Size - SS.Position, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCFB(SS, SS.Size - SS.Position, AESKey256, Iv, DS); + end; + end; + + SetLength(Result, DS.Size); + Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES OFB ģʽַתʮ +function AESEncryptOfbStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[1])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamOFB(SS, 0, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamOFB(SS, 0, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamOFB(SS, 0, AESKey256, Iv, DS); + end; + end; + + Result := AnsiString(DataToHex(DS.Memory, DS.Size)); + finally + SS.Free; + DS.Free; + end; +end; + +// AES OFB ʮַ +function AESDecryptOfbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + Tmp: TBytes; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + Tmp := HexToBytes(string(HexStr)); + SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamOFB(SS, SS.Size - SS.Position, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamOFB(SS, SS.Size - SS.Position, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamOFB(SS, SS.Size - SS.Position, AESKey256, Iv, DS); + end; + end; + + SetLength(Result, DS.Size); + Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CTR ģʽַתʮ +function AESEncryptCtrStrToHex(Value: AnsiString; Key: AnsiString; + const Nonce: TCnAESCTRNonce; const Iv: TCnAESCTRIv; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[1])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCTR(SS, 0, AESKey128, Nonce, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCTR(SS, 0, AESKey192, Nonce, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCTR(SS, 0, AESKey256, Nonce, Iv, DS); + end; + end; + + Result := AnsiString(DataToHex(DS.Memory, DS.Size)); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CTR ʮַ +function AESDecryptCtrStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Nonce: TCnAESCTRNonce; const Iv: TCnAESCTRIv; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + Tmp: TBytes; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + Tmp := HexToBytes(string(HexStr)); + SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCTR(SS, SS.Size - SS.Position, AESKey128, Nonce, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCTR(SS, SS.Size - SS.Position, AESKey192, Nonce, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCTR(SS, SS.Size - SS.Position, AESKey256, Nonce, Iv, DS); + end; + end; + + SetLength(Result, DS.Size); + Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES ECB ģʽֽ +function AESEncryptEcbBytes(Value, Key: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamECB(SS, 0, AESKey128, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamECB(SS, 0, AESKey192, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamECB(SS, 0, AESKey256, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES ECB ģʽֽ +function AESDecryptEcbBytes(Value, Key: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamECB(SS, SS.Size - SS.Position, AESKey128, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamECB(SS, SS.Size - SS.Position, AESKey192, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamECB(SS, SS.Size - SS.Position, AESKey256, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CBC ģʽֽ +function AESEncryptCbcBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCBC(SS, 0, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCBC(SS, 0, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCBC(SS, 0, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CBC ģʽֽ +function AESDecryptCbcBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCBC(SS, SS.Size - SS.Position, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCBC(SS, SS.Size - SS.Position, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCBC(SS, SS.Size - SS.Position, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CFB ģʽֽ +function AESEncryptCfbBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCFB(SS, 0, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCFB(SS, 0, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCFB(SS, 0, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CFB ģʽֽ +function AESDecryptCfbBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCFB(SS, SS.Size - SS.Position, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCFB(SS, SS.Size - SS.Position, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCFB(SS, SS.Size - SS.Position, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES OFB ģʽֽ +function AESEncryptOfbBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamOFB(SS, 0, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamOFB(SS, 0, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamOFB(SS, 0, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES OFB ģʽֽ +function AESDecryptOfbBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamOFB(SS, SS.Size - SS.Position, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamOFB(SS, SS.Size - SS.Position, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamOFB(SS, SS.Size - SS.Position, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CTR ģʽֽ +function AESEncryptCtrBytes(Value, Key, Nonce, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESCTRIv; + AESNonce: TCnAESCTRNonce; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + + FillChar(AESNonce, SizeOF(AESNonce), 0); + Move(PAnsiChar(Nonce)^, AESNonce, Min(SizeOf(AESNonce), Length(Nonce))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCTR(SS, 0, AESKey128, AESNonce, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCTR(SS, 0, AESKey192, AESNonce, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCTR(SS, 0, AESKey256, AESNonce, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CTR ģʽֽ +function AESDecryptCtrBytes(Value, Key, Nonce, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESCTRIv; + AESNonce: TCnAESCTRNonce; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + + FillChar(AESNonce, SizeOF(AESNonce), 0); + Move(PAnsiChar(Nonce)^, AESNonce, Min(SizeOf(AESNonce), Length(Nonce))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCTR(SS, SS.Size - SS.Position, AESKey128, AESNonce, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCTR(SS, SS.Size - SS.Position, AESKey192, AESNonce, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCTR(SS, SS.Size - SS.Position, AESKey256, AESNonce, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES ECB ģʽֽ鲢תʮ +function AESEncryptEcbBytesToHex(Value, Key: TBytes; KeyBit: TCnKeyBitType): AnsiString; +begin + Result := AnsiString(BytesToHex(AESEncryptEcbBytes(Value, Key, KeyBit))); +end; + +// AES ECB ʮַֽ +function AESDecryptEcbBytesFromHex(const HexStr: AnsiString; Key: TBytes; + KeyBit: TCnKeyBitType): TBytes; +begin + Result := AESDecryptEcbBytes(HexToBytes(string(HexStr)), Key, KeyBit); +end; + +// AES CBC ģʽֽ鲢תʮ +function AESEncryptCbcBytesToHex(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): AnsiString; +begin + Result := AnsiString(BytesToHex(AESEncryptCbcBytes(Value, Key, Iv, KeyBit))); +end; + +// AES CBC ʮַֽ +function AESDecryptCbcBytesFromHex(const HexStr: AnsiString; Key, Iv: TBytes; + KeyBit: TCnKeyBitType): TBytes; +begin + Result := AESDecryptCbcBytes(HexToBytes(string(HexStr)), Key, Iv, KeyBit); +end; + +// AES CFB ģʽֽ鲢תʮ +function AESEncryptCfbBytesToHex(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): AnsiString; +begin + Result := AnsiString(BytesToHex(AESEncryptCfbBytes(Value, Key, Iv, KeyBit))); +end; + +// AES CFB ʮַֽ +function AESDecryptCfbBytesFromHex(const HexStr: AnsiString; Key, Iv: TBytes; + KeyBit: TCnKeyBitType): TBytes; +begin + Result := AESDecryptCfbBytes(HexToBytes(string(HexStr)), Key, Iv, KeyBit); +end; + +// AES OFB ģʽֽ鲢תʮ +function AESEncryptOfbBytesToHex(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): AnsiString; +begin + Result := AnsiString(BytesToHex(AESEncryptOfbBytes(Value, Key, Iv, KeyBit))); +end; + +// AES OFB ʮַֽ +function AESDecryptOfbBytesFromHex(const HexStr: AnsiString; Key, Iv: TBytes; + KeyBit: TCnKeyBitType): TBytes; +begin + Result := AESDecryptOfbBytes(HexToBytes(string(HexStr)), Key, Iv, KeyBit); +end; + +// AES CTR ģʽֽ鲢תʮ +function AESEncryptCtrBytesToHex(Value, Key, Nonce, Iv: TBytes; KeyBit: TCnKeyBitType): AnsiString; +begin + Result := AnsiString(BytesToHex(AESEncryptCtrBytes(Value, Key, Nonce, Iv, KeyBit))); +end; + +// AES CTR ʮַֽ +function AESDecryptCtrBytesFromHex(const HexStr: AnsiString; Key, Nonce, Iv: TBytes; + KeyBit: TCnKeyBitType): TBytes; +begin + Result := AESDecryptCtrBytes(HexToBytes(string(HexStr)), Key, Nonce, Iv, KeyBit); +end; + +end. + diff --git a/CnPack/Crypto/CnBase64.dcu b/CnPack/Crypto/CnBase64.dcu new file mode 100644 index 0000000000000000000000000000000000000000..3b1d931f16324cb1df37a96014462e88b915a17e GIT binary patch literal 7426 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 U5XKli4!pF literal 0 HcmV?d00001 diff --git a/CnPack/Crypto/CnBase64.pas b/CnPack/Crypto/CnBase64.pas new file mode 100644 index 0000000..cfe7dc1 --- /dev/null +++ b/CnPack/Crypto/CnBase64.pas @@ -0,0 +1,547 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2025 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +{ -----------------------------------------------------------------------------} +{ uTBase64 v1.0 - Simple Base64 encoding/decoding class } +{ Base64 described in RFC2045, Page 24, (w) 1996 Freed & Borenstein } +{ Delphi implementation (w) 1999 Dennis D. Spreen (dennis@spreendigital.de) } +{ This unit is freeware. Just drop me a line if this unit is useful for you. } +{ -----------------------------------------------------------------------------} + +unit CnBase64; +{* |
+================================================================================
+* ƣ
+* ԪƣBase64 㷨ʵֵԪ
+* ԪߣղSolin solin@21cn.com; http://www.ilovezhuzhu.net
+*           wr960204
+*           CnPack  (master@cnpack.org)
+*           ݻ Dennis D. Spreen  UTBASE64.pas дԭаȨϢ
+*     עԪʵ˱׼ Base64  Base64URL ı빦ܡ
+*           Base64URL ڱ׼ Base64ѷ + / 滻 - _  URL 
+*           Ѻãɾβ =
+*
+* ƽ̨PWin2003Std + Delphi 6.0
+* ݲԣδ
+*   õԪ豾ػ
+* ޸ļ¼2023.10.04 V1.6
+*               ɾʵ֡Base64Encode  Base64Decode ֧ Base64URL ı
+*           2019.12.12 V1.5
+*               ֧ TBytes
+*           2019.04.15 V1.4
+*               ֧ Win32/Win64/MacOS
+*           2018.06.22 V1.3
+*               ԭʼݿܰ #0 ԭʼβ #0 Ƴ
+*           2016.05.03 V1.2
+*               ַа #0 ʱܻᱻضϵ
+*           2006.10.25 V1.1
+*                wr960204 Ż汾
+*           2003.10.14 V1.0
+*               Ԫ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes, CnNative, CnConsts; + +const + ECN_BASE64_OK = ECN_OK; // תɹ + {* Base64 ϵд룺޴ֵΪ 0} + ECN_BASE64_ERROR_BASE = ECN_CUSTOM_ERROR_BASE + $500; + {* Base64 ϵдĻ׼ʼֵΪ ECN_CUSTOM_ERROR_BASE $500} + + ECN_BASE64_LENGTH = ECN_BASE64_ERROR_BASE + 1; + {* Base64 ֮ݳȷǷ} + +function Base64Encode(InputData: TStream; var OutputData: string; + URL: Boolean = False): Integer; overload; +{* Base64 Base64URL 룬ɹ ECN_BASE64_OK + + + InputData: TStream - + var OutputData: string - ַ + URL: Boolean - URL ǡTrue ʹ Base64URL 룬False ʹñ׼ Base64 + + ֵInteger - رǷɹɹ򷵻 ECN_BASE64_OK +} + +function Base64Encode(const InputData: AnsiString; var OutputData: string; + URL: Boolean = False): Integer; overload; +{* ַ Base64 Base64URL 룬ɹ ECN_BASE64_OK + + + const InputData: AnsiString - ַ + var OutputData: string - ַ + URL: Boolean - URL ǡTrue ʹ Base64URL 룬False ʹñ׼ Base64 + + ֵInteger - رǷɹɹ򷵻 ECN_BASE64_OK +} + +function Base64Encode(InputData: Pointer; DataByteLen: Integer; var OutputData: string; + URL: Boolean = False): Integer; overload; +{* ݿ Base64 Base64URL 룬ɹ ECN_BASE64_OK + + + InputData: Pointer - ݿַ + DataByteLen: Integer - ݿֽڳ + var OutputData: string - ַ + URL: Boolean - URL ǡTrue ʹ Base64URL 룬False ʹñ׼ Base64 + + ֵInteger - رǷɹɹ򷵻 ECN_BASE64_OK +} + +function Base64Encode(InputData: TBytes; var OutputData: string; + URL: Boolean = False): Integer; overload; +{* ֽ Base64 Base64URL 룬ɹ ECN_BASE64_OK + + + InputData: TBytes - ֽ + var OutputData: string - ַ + URL: Boolean - URL ǡTrue ʹ Base64URL 룬False ʹñ׼ Base64 + + ֵInteger - رǷɹɹ򷵻 ECN_BASE64_OK +} + +function Base64Decode(const InputData: string; OutputData: TStream; + FixZero: Boolean = True): Integer; overload; +{* ַ Base64 루 Base64URL 룩дɹ ECN_BASE64_OK + + + const InputData: string - ַ + OutputData: TStream - + FixZero: Boolean - Ƿȥβ #0 + + ֵInteger - ؽǷɹɹ򷵻 ECN_BASE64_OK +} + +function Base64Decode(const InputData: string; var OutputData: AnsiString; + FixZero: Boolean = True): Integer; overload; +{* ַ Base64 루 Base64URL 룩дַɹ ECN_BASE64_OK + + + const InputData: string - ַ + var OutputData: AnsiString - ַ + FixZero: Boolean - Ƿȥβ #0 + + ֵInteger - ؽǷɹɹ򷵻 ECN_BASE64_OK +} + +function Base64Decode(const InputData: string; OutputData: Pointer; + DataByteLen: Integer; FixZero: Boolean = True): Integer; overload; +{* ַ Base64 루 Base64URL 룩дڴɹ ECN_BASE64_OK + + + const InputData: string - ַ + OutputData: Pointer - ڴַ + DataByteLen: Integer - ڴֽڳȣӦΪ 1 + (Length(InputData) * 3 / 4) + FixZero: Boolean - Ƿȥβ #0 + + ֵInteger - OutputData nilĽֽڳȡؽǷɹɹ򷵻 ECN_BASE64_OK +} + +function Base64Decode(const InputData: string; out OutputData: TBytes; + FixZero: Boolean = True): Integer; overload; +{* ַ Base64 루 Base64URL 룩дֽ顣ɹ ECN_BASE64_OK + + + const InputData: string - ַ + out OutputData: TBytes - ֽ + FixZero: Boolean - Ƿȥβ #0 + + ֵInteger - ؽǷɹɹ򷵻 ECN_BASE64_OK +} + +implementation + +var + FilterDecodeInput: Boolean = True; + +//------------------------------------------------------------------------------ +// IJο +//------------------------------------------------------------------------------ + + EnCodeTab: array[0..64] of AnsiChar = + ( + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/', + '='); + + EnCodeTabURL: array[0..64] of AnsiChar = + ( + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '-', '_', + '='); + +//------------------------------------------------------------------------------ +// IJο +//------------------------------------------------------------------------------ + + { Base64 ֱַӸ㣬Ҳȡ} + DecodeTable: array[#0..#127] of Byte = + ( + Byte('='), 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 62, 00, 62, 00, 63, // ĵһ 62 63 + / - 62 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 00, 00, 00, 00, 00, 00, + 00, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 00, 00, 00, 00, 63, // _ 63 + 00, 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, 00, 00, 00, 00, 00 + ); + +function Base64Encode(InputData: TStream; var OutputData: string; URL: Boolean): Integer; +var + Mem: TMemoryStream; +begin + Mem := TMemoryStream.Create; + try + Mem.CopyFrom(InputData, InputData.Size); + Result := Base64Encode(Mem.Memory, Mem.Size, OutputData, URL); + finally + Mem.Free; + end; +end; + +// Ϊ wr960204 ĽĿ Base64 㷨 +function Base64Encode(InputData: Pointer; DataByteLen: Integer; var OutputData: string; + URL: Boolean): Integer; +var + Times, I: Integer; + X1, X2, X3, X4: AnsiChar; + XT: Byte; +begin + if (InputData = nil) or (DataByteLen <= 0) then + begin + Result := ECN_BASE64_LENGTH; + Exit; + end; + + if DataByteLen mod 3 = 0 then + Times := DataByteLen div 3 + else + Times := DataByteLen div 3 + 1; + SetLength(OutputData, Times * 4); // һηڴ,һδַ,һδͷŷڴ + FillChar(OutputData[1], Length(OutputData) * SizeOf(Char), 0); + + if URL then + begin + for I := 0 to Times - 1 do + begin + if DataByteLen >= (3 + I * 3) then + begin + X1 := EnCodeTabURL[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + XT := XT or (Ord(PAnsiChar(InputData)[1 + I * 3]) shr 4); + X2 := EnCodeTabURL[XT]; + XT := (Ord(PAnsiChar(InputData)[1 + I * 3]) shl 2) and 60; + XT := XT or (Ord(PAnsiChar(InputData)[2 + I * 3]) shr 6); + X3 := EnCodeTabURL[XT]; + XT := (Ord(PAnsiChar(InputData)[2 + I * 3]) and 63); + X4 := EnCodeTabURL[XT]; + end + else if DataByteLen >= (2 + I * 3) then + begin + X1 := EnCodeTabURL[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + XT := XT or (Ord(PAnsiChar(InputData)[1 + I * 3]) shr 4); + X2 := EnCodeTabURL[XT]; + XT := (Ord(PAnsiChar(InputData)[1 + I * 3]) shl 2) and 60; + X3 := EnCodeTabURL[XT ]; + X4 := '='; + end + else + begin + X1 := EnCodeTabURL[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + X2 := EnCodeTabURL[XT]; + X3 := '='; + X4 := '='; + end; + OutputData[I shl 2 + 1] := Char(X1); + OutputData[I shl 2 + 2] := Char(X2); + OutputData[I shl 2 + 3] := Char(X3); + OutputData[I shl 2 + 4] := Char(X4); + end; + end + else + begin + for I := 0 to Times - 1 do + begin + if DataByteLen >= (3 + I * 3) then + begin + X1 := EnCodeTab[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + XT := XT or (Ord(PAnsiChar(InputData)[1 + I * 3]) shr 4); + X2 := EnCodeTab[XT]; + XT := (Ord(PAnsiChar(InputData)[1 + I * 3]) shl 2) and 60; + XT := XT or (Ord(PAnsiChar(InputData)[2 + I * 3]) shr 6); + X3 := EnCodeTab[XT]; + XT := (Ord(PAnsiChar(InputData)[2 + I * 3]) and 63); + X4 := EnCodeTab[XT]; + end + else if DataByteLen >= (2 + I * 3) then + begin + X1 := EnCodeTab[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + XT := XT or (Ord(PAnsiChar(InputData)[1 + I * 3]) shr 4); + X2 := EnCodeTab[XT]; + XT := (Ord(PAnsiChar(InputData)[1 + I * 3]) shl 2) and 60; + X3 := EnCodeTab[XT ]; + X4 := '='; + end + else + begin + X1 := EnCodeTab[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + X2 := EnCodeTab[XT]; + X3 := '='; + X4 := '='; + end; + OutputData[I shl 2 + 1] := Char(X1); + OutputData[I shl 2 + 2] := Char(X2); + OutputData[I shl 2 + 3] := Char(X3); + OutputData[I shl 2 + 4] := Char(X4); + end; + end; + + OutputData := Trim(OutputData); + if URL then + begin + // ɾ OutputData β = ַ + if (Length(OutputData) > 0) and (OutputData[Length(OutputData)] = '=') then + begin + Delete(OutputData, Length(OutputData), 1); + if (Length(OutputData) > 0) and (OutputData[Length(OutputData)] = '=') then + begin + Delete(OutputData, Length(OutputData), 1); + if (Length(OutputData) > 0) and (OutputData[Length(OutputData)] = '=') then + Delete(OutputData, Length(OutputData), 1); + end; + end; + end; + Result := ECN_BASE64_OK; +end; + +function Base64Encode(const InputData: AnsiString; var OutputData: string; URL: Boolean): Integer; +begin + if InputData <> '' then + Result := Base64Encode(@InputData[1], Length(InputData), OutputData, URL) + else + Result := ECN_BASE64_LENGTH; +end; + +function Base64Encode(InputData: TBytes; var OutputData: string; URL: Boolean): Integer; +begin + if Length(InputData) > 0 then + Result := Base64Encode(@InputData[0], Length(InputData), OutputData, URL) + else + Result := ECN_BASE64_LENGTH; +end; + +function Base64Decode(const InputData: string; OutputData: TStream; FixZero: Boolean): Integer; +var + Data: TBytes; +begin + Result := Base64Decode(InputData, Data, FixZero); + if (Result = ECN_BASE64_OK) and (Length(Data) > 0) then + begin + OutputData.Size := Length(Data); + OutputData.Position := 0; + OutputData.Write(Data[0], Length(Data)); + end; +end; + +function Base64Decode(const InputData: string; out OutputData: TBytes; + FixZero: Boolean): Integer; +var + SrcLen, DstLen, Times, I: Integer; + X1, X2, X3, X4, XT: Byte; + C, ToDec: Integer; + Data: AnsiString; + + function FilterLine(const Source: AnsiString): AnsiString; + var + P, PP: PAnsiChar; + I, FL: Integer; + begin + FL := Length(Source); + if FL > 0 then + begin + GetMem(P, FL); // һηڴ,һδַ,һδͷŷڴ + PP := P; + FillChar(P^, FL, 0); + for I := 1 to FL do + begin + if Source[I] in ['0'..'9', 'A'..'Z', 'a'..'z', '+', '/', '=', '-', '_'] then + begin + PP^ := Source[I]; + Inc(PP); + end; + end; + SetString(Result, P, PP - P); // ȡЧ + FreeMem(P); + end; + end; + +begin + if InputData = '' then + begin + Result := ECN_BASE64_OK; + Exit; + end; + OutPutData := nil; + + // D5 ²֪ôIJ AnsiString(InputData)ܻڴֿ + if FilterDecodeInput then + begin +{$IFDEF UNICODE} + Data := FilterLine(AnsiString(InputData)); +{$ELSE} + Data := FilterLine(InputData); +{$ENDIF} + end + else + begin +{$IFDEF UNICODE} + Data := AnsiString(InputData); +{$ELSE} + Data := InputData; +{$ENDIF} + end; + + // Base64URL Ľȥβ =ҪݳǷ 4 ı + if (Length(Data) and $03) <> 0 then + Data := Data + StringOfChar(AnsiChar('='), 4 - (Length(Data) and $03)); + + SrcLen := Length(Data); + DstLen := SrcLen * 3 div 4; + ToDec := 0; + + // βһȺζԭʼݲ˸ #0ȺζŲ #0ҪȥҲ̳ + // עⲻͬԭʼݵβ #0 ȥ + if Data[SrcLen] = '=' then + begin + Inc(ToDec); + if (SrcLen > 1) and (Data[SrcLen - 1] = '=') then + Inc(ToDec); + end; + + SetLength(OutputData, DstLen); // һηڴ,һδַ,һδͷŷڴ + Times := SrcLen div 4; + C := 0; + + for I := 0 to Times - 1 do + begin + X1 := DecodeTable[Data[1 + I shl 2]]; + X2 := DecodeTable[Data[2 + I shl 2]]; + X3 := DecodeTable[Data[3 + I shl 2]]; + X4 := DecodeTable[Data[4 + I shl 2]]; + X1 := X1 shl 2; + XT := X2 shr 4; + X1 := X1 or XT; + X2 := X2 shl 4; + OutputData[C] := X1; + Inc(C); + if X3 = 64 then + Break; + XT := X3 shr 2; + X2 := X2 or XT; + X3 := X3 shl 6; + OutputData[C] := X2; + Inc(C); + if X4 = 64 then + Break; + X3 := X3 or X4; + OutputData[C] := X3; + Inc(C); + end; + + // ݲĵȺĿǷɾβ #0 + while (ToDec > 0) and (OutputData[DstLen - 1] = 0) do + begin + Dec(ToDec); + Dec(DstLen); + end; + SetLength(OutputData, DstLen); + + // ٸⲿҪɾβ #0ʵ̫ʵ + if FixZero then + begin + while (DstLen > 0) and (OutputData[DstLen - 1] = 0) do + Dec(DstLen); + SetLength(OutputData, DstLen); + end; + + Result := ECN_BASE64_OK; +end; + +function Base64Decode(const InputData: string; var OutputData: AnsiString; FixZero: Boolean): Integer; +var + Data: TBytes; +begin + Result := Base64Decode(InputData, Data, FixZero); + if (Result = ECN_BASE64_OK) and (Length(Data) > 0) then + begin + SetLength(OutputData, Length(Data)); + Move(Data[0], OutputData[1], Length(Data)); + end; +end; + +function Base64Decode(const InputData: string; OutputData: Pointer; + DataByteLen: Integer; FixZero: Boolean): Integer; +var + Data: TBytes; +begin + Result := Base64Decode(InputData, Data, FixZero); + if (Result = ECN_BASE64_OK) and (Length(Data) > 0) then + begin + if OutputData = nil then + begin + Result := Length(Data); + Exit; + end; + + if DataByteLen < Length(Data) then + begin + Result := ECN_BASE64_LENGTH; + Exit; + end; + + Move(Data[0], OutPutData^, Length(Data)); + end; +end; + +end. diff --git a/CnPack/Crypto/CnConsts.dcu b/CnPack/Crypto/CnConsts.dcu new file mode 100644 index 0000000000000000000000000000000000000000..c867ed279f4c00fe26ff633e118584d938e5bedb GIT binary patch literal 14305 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 e3USNw2)Y>N%(KXha^|S(k2<+r=u|5s literal 0 HcmV?d00001 diff --git a/CnPack/Crypto/CnConsts.pas b/CnPack/Crypto/CnConsts.pas new file mode 100644 index 0000000..f4f50aa --- /dev/null +++ b/CnPack/Crypto/CnConsts.pas @@ -0,0 +1,250 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2025 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnConsts; +{* |
+================================================================================
+* ƣ
+* ԪƣԴַ嵥Ԫ
+* ԪߣCnPack 
+*     ע
+* ƽ̨PWin98SE + Delphi 5.0
+* ݲԣPWin9X/2000/XP + Delphi 5/6
+*   õԪеַϱػʽ
+* ޸ļ¼2005.12.24 V1.0
+*                ԪֲӢַ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +const + ECN_OK = 0; // OK޴ + + ECN_FILE_NOT_FOUND = $10; // ļ + + ECN_CUSTOM_ERROR_BASE = $1000; // 趨Ĵʼֵ + +//============================================================================== +// Strings DO NOT Localize: +//============================================================================== + +resourcestring + + // CnPack Reg Path + SCnPackRegPath = '\Software\CnPack'; + + // Tools Reg Path + SCnPackToolRegPath = 'CnTools'; + +//============================================================================== +// Strings to be Localized: +//============================================================================== + + +var + // Common Information + SCnInformation: string = 'Information'; + SCnWarning: string = 'Warning'; + SCnError: string = 'Error'; + SCnEnabled: string = 'Enabled'; + SCnDisabled: string = 'Disabled'; + SCnMsgDlgOK: string = '&OK'; + SCnMsgDlgCancel: string = '&Cancel'; + SCnMsgDlgYes: string = '&Yes'; + SCnMsgDlgNo: string = '&No'; + SCnMsgDlgYesToAll: string = 'Yes to &All'; + SCnMsgDlgNoToAll: string = 'No to A&ll'; + SCnVersion: string = 'Version'; + SCnNeedAdmin: string = 'Maybe Need Administrator.'; + +const + // CnPack Information + SCnPackAbout = 'CnPack'; + SCnPackVer = 'Ver 0.1.5.2'; + SCnPackStr = SCnPackAbout + ' ' + SCnPackVer; + SCnPackUrl = 'https://www.cnpack.org'; + SCnPackBbsUrl = 'https://bbs.cnpack.org'; + SCnPackNewsUrl = 'news://news.cnpack.org'; + SCnPackSourceUrl = 'https://github.com/cnpack'; + SCnPackEmail = 'master@cnpack.org'; + SCnPackBugEmail = 'bugs@cnpack.org'; + SCnPackSuggestionsEmail = 'suggestions@cnpack.org'; + + SCnPackDonationUrl = 'https://www.cnpack.org/foundation.php'; + SCnPackDonationUrlSF = 'http://sourceforge.net/donate/index.php?group_id=110999'; + SCnPackGroup = 'CnPack Team'; + SCnPackCopyright = '(C)Copyright 2001-2025 ' + SCnPackGroup; + + // CnPropEditors + SCopyrightFmtStr = + SCnPackStr + #13#10#13#10 + + 'Component Name: %s' + #13#10 + + 'Author: %s(%s)' + #13#10 + + 'Comment: %s' + #13#10 + + 'HomePage: ' + SCnPackUrl + #13#10 + + 'Email: ' + SCnPackEmail + #13#10#13#10 + + SCnPackCopyright; + +resourcestring + + // Component Palette Name + SCnNonVisualPalette = 'CnPack Tools'; + SCnGraphicPalette = 'CnPack VCL'; + SCnNetPalette = 'CnPack Net'; + SCnDatabasePalette = 'CnPack DB'; + SCnReportPalette = 'CnPack Report'; + + // CnPack Developers Added from Last. +var + SCnPack_Team: string = 'CnPack Team'; + SCnPack_Zjy: string = 'Zhou JingYu'; + SCnPack_Shenloqi: string = 'Chinbo'; + SCnPack_xiaolv: string = 'xiaolv'; + SCnPack_Flier: string = 'Flier Lu'; + SCnPack_LiuXiao: string = 'Liu Xiao'; + SCnPack_PanYing: string = 'Pan Ying'; + SCnPack_Hubdog: string = 'Hubdog'; + SCnPack_Wyb_star: string = 'wyb_star'; + SCnPack_Licwing: string = 'Licwing zue'; + SCnPack_Alan: string = 'Alan'; + SCnPack_GuYueChunQiu: string = 'GuYueChunQiu'; + SCnPack_Aimingoo: string = 'Aimingoo'; + SCnPack_QSoft: string = 'QSoft'; + SCnPack_Hospitality: string = 'ZhangJiongXuan (Hospitality)'; + SCnPack_SQuall: string = 'SQUALL'; + SCnPack_Hhha: string = 'Hhha'; + SCnPack_Beta: string = 'beta'; + SCnPack_Leeon: string = 'Leeon'; + SCnPack_SuperYoyoNc: string = 'SuperYoyoNC'; + SCnPack_JohnsonZhong: string = 'Johnson Zhong'; + SCnPack_DragonPC: string = 'Dragon P.C.'; + SCnPack_Kendling: string = 'Kending'; + SCnPack_ccrun: string = 'ccrun'; + SCnPack_Dingbaosheng: string = 'dingbaosheng'; + SCnPack_LuXiaoban: string = 'Zhou Yibo(Lu Xiaoban)'; + SCnPack_Savetime: string = 'savetime'; + SCnPack_solokey: string = 'solokey'; + SCnPack_Bahamut: string = 'Bahamut'; + SCnPack_Sesame: string = 'Sesame'; + SCnPack_BuDeXian: string = 'BuDeXian'; + SCnPack_XiaoXia: string = 'Summer'; + SCnPack_ZiMin: string = 'ZiMin'; + SCnPack_rarnu: string = 'rarnu'; + SCnPack_dejoy: string = 'dejoy'; + SCnPack_Rain: string = 'Rain'; + SCnPack_cnwinds: string = 'cnwinds'; + + // CnCommon + SUnknowError: string = 'Unknow error'; + SErrorCode: string = 'Error code:'; + +const + SCnPack_TeamEmail = 'master@cnpack.org'; + SCnPack_ZjyEmail = 'zjy@cnpack.org'; + SCnPack_ShenloqiEmail = 'Shenloqi@hotmail.com'; + SCnPack_xiaolvEmail = 'xiaolv888@etang.com'; + SCnPack_FlierEmail = 'flier_lu@sina.com'; + SCnPack_LiuXiaoEmail = 'liuxiao@cnpack.org'; + SCnPack_PanYingEmail = 'panying@sina.com'; + SCnPack_HubdogEmail = 'hubdog@263.net'; + SCnPack_Wyb_starMail = 'wyb_star@sina.com'; + SCnPack_LicwingEmail = 'licwing@chinasystemsn.com'; + SCnPack_AlanEmail = 'BeyondStudio@163.com'; + SCnPack_GuYueChunQiuEmail = 'guyuechunqiu@cnpack.org'; + SCnPack_AimingooEmail = 'aim@263.net'; + SCnPack_QSoftEmail = 'hq.com@263.net'; + SCnPack_HospitalityEmail = 'Hospitality_ZJX@msn.com'; + SCnPack_SQuallEmail = 'squall_sa@163.com'; + SCnPack_HhhaEmail = 'Hhha@eyou.com'; + SCnPack_BetaEmail = 'beta@01cn.net'; + SCnPack_LeeonEmail = 'real-like@163.com'; + SCnPack_SuperYoyoNcEmail = 'superyoyonc@sohu.com'; + SCnPack_JohnsonZhongEmail = 'zhongs@tom.com'; + SCnPack_DragonPCEmail = 'dragonpc@21cn.com'; + SCnPack_KendlingEmail = 'kendling@21cn.com'; + SCnPack_ccRunEmail = 'info@ccrun.com'; + SCnPack_DingbaoshengEmail = 'yzdbs@msn.com'; + SCnPack_LuXiaobanEmail = 'zhouyibo2000@sina.com'; + SCnPack_SavetimeEmail = 'savetime2k@hotmail.com'; + SCnPack_solokeyEmail = 'crh611@163.com'; + SCnPack_BahamutEmail = 'fantasyfinal@126.com'; + SCnPack_SesameEmail = 'sesamehch@163.com'; + SCnPack_BuDeXianEmail = 'appleak46@yahoo.com.cn'; + SCnPack_XiaoXiaEmail = 'summercore@163.com'; + SCnPack_ZiMinEmail = '441414288@qq.com'; + SCnPack_rarnuEmail = 'rarnu@cnpack.org'; + SCnPack_dejoyEmail = 'dejoybbs@163.com'; + SCnPack_RainEmail = SCnPack_TeamEmail; // Emailÿ + SCnPack_cnwindsEmail = SCnPack_TeamEmail; + + // CnMemProf + SCnPackMemMgr = 'CnMemProf'; + SMemLeakDlgReport = 'Found %d memory leaks. [There are %d allocated before replace memory manager.]'; + SMemMgrODSReport = 'Get = %d Free = %d Realloc = %d'; + SMemMgrOverflow = 'Memory Manager''s list capability overflow, Please enlarge it!'; + SMemMgrRunTime = '%d hour(s) %d minute(s) %d second(s)'; + SOldAllocMemCount = 'There are %d allocated before replace memory manager.'; + SAppRunTime = 'Application total run time: '; + SMemSpaceCanUse = 'HeapStatus.TotalAddrSpace: %d KB'; + SUncommittedSpace = 'HeapStatus.TotalUncommitted: %d KB'; + SCommittedSpace = 'HeapStatus.TotalCommitted: %d KB'; + SFreeSpace = 'HeapStatus.TotalFree: %d KB'; + SAllocatedSpace = 'HeapStatus.TotalAllocated: %d KB'; + SAllocatedSpacePercent = 'TotalAllocated div TotalAddrSpace: %d%%'; + SFreeSmallSpace = 'HeapStatus.FreeSmall: %d KB'; + SFreeBigSpace = 'HeapStatus.FreeBig: %d KB'; + SUnusedSpace = 'HeapStatus.Unused: %d KB'; + SOverheadSpace = 'HeapStatus.Overhead: %d KB'; + SObjectCountInMemory = 'Objects count in memory: '; + SNoMemLeak = ' No memory leak.'; + SNoName = '(no name)'; + SNotAnObject = ' Not an object'; + SByte = 'Byte'; + SCommaString = ','; + SPeriodString = '.'; + +resourcestring + SCnErrorMapViewOfFile = 'MapViewOfFile Failed. '; + SCnErrorCreateFileMapping = 'CreateFileMapping Failed. '; + +function CnGetLastError: Integer; + +procedure _CnSetLastError(Err: Integer); + +implementation + +threadvar + CnErrorCode: Integer; + +function CnGetLastError: Integer; +begin + Result := CnErrorCode; +end; + +procedure _CnSetLastError(Err: Integer); +begin + CnErrorCode := Err; +end; + +end. + diff --git a/CnPack/Crypto/CnDES.dcu b/CnPack/Crypto/CnDES.dcu new file mode 100644 index 0000000000000000000000000000000000000000..86e855f0e249b9d709daafffd26601b8f2c8b4ab GIT binary patch literal 30941 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 +================================================================================ +* ƣ +* ԪƣDES ԳƼӽ㷨ʵֵԪ +* ԪߣCnPack (master@cnpack.org) +* /ֲ䲿ֹܡ +* עԪʵ DES/3DES ԳƼӽ㷨ֿС 8 ֽڣʵ +* ECB/CBC ģʽ֧ģʽ +* +* ƽ̨PWin2000Pro + Delphi 5.0 +* ݲԣPWin9X/2000/XP + Delphi 5/6 +* õԪеַϱػʽ +* ޸ļ¼2024.11.30 V1.7 +* ɾ淶 DESEncryptStrToHex DESDecryptStrToHex +* ɾ淶 TripleDESEncryptStrToHex TripleDESDecryptStrToHex +* ECB 汾 +* Ż PAnsiChar ʽ Iv Ĵ +* 2024.10.12 V1.6 +* 3DES ²Խ⣬Ż Key Iv Ķ봦 +* 2022.08.13 V1.5 +* Կݼܷؿ +* 2021.02.07 V1.4 +* Ӷ TBytes ֧ +* 2020.03.25 V1.3 +* 3DES ֧ +* 2020.03.24 V1.2 +* ECB/CBC ַӽܺɾԭеַܺ +* 2019.04.15 V1.1 +* ֧ Win32/Win64/MacOS +* 2008.05.30 V1.0 +* Ԫ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes, CnNative; + +const + CN_DES_KEYSIZE = 8; + {* DES Կȣ8 ֽ} + + CN_DES_BLOCKSIZE = 8; + {* DES ļܿ鳤ȣ8 ֽ} + + CN_TRIPLE_DES_KEYSIZE = CN_DES_KEYSIZE * 3; + {* 3DES Կȣ DES 24 ֽ} + + CN_TRIPLE_DES_BLOCKSIZE = CN_DES_BLOCKSIZE; + {* 3DES ļܿ鳤ȣ 8 ֽ} + +type + ECnDESException = class(Exception); + {* DES 쳣} + + TCnDESKey = array[0..CN_DES_KEYSIZE - 1] of Byte; + {* DES ļ Key8 ֽ} + + TCnDESBuffer = array[0..CN_DES_BLOCKSIZE - 1] of Byte; + {* DES ļܿ飬8 ֽ} + + TCnDESIv = array[0..CN_DES_BLOCKSIZE - 1] of Byte; + {* DES CBC ijʼ8 ֽ} + + TCn3DESKey = array[0..CN_TRIPLE_DES_KEYSIZE - 1] of Byte; + {* 3DES Կȣ DES 24 ֽ} + + TCn3DESBuffer = TCnDESBuffer; + {* 3DES ļܿ飬 DES ļܿ飬8 ֽ} + + TCn3DESIv = TCnDESIv; + {* 3DES CBC ijʼ DES CBC ijʼ8 ֽ} + +// ================================= DES ======================================= + +function DESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +{* ֽڳȼ DES ȡǿ + + + InputByteLength: Integer - ֽڳ + + ֵInteger - DES ij +} + +procedure DESEncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +{* AnsiString DES ܣʹ ECB ģʽ + + + Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure DESDecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +{* AnsiString DES ܣʹ ECB ģʽ + + + Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure DESEncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; const Input: AnsiString; + Output: PAnsiChar); +{* AnsiString DES ܣʹ CBC ģʽ + + + Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + Iv: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure DESDecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; const Input: AnsiString; + Output: PAnsiChar); +{* AnsiString DES ܣʹ CBC ģʽ + + + Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + Iv: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +function DESEncryptEcbStrToHex(const Str: AnsiString; const Key: AnsiString): AnsiString; +{* KeyDES ܷתʮƵģʹ ECB ģʽĩβܲ #0 + + + const Str: AnsiString - ַܵ + const Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + + ֵAnsiString - ؼܺʮַ +} + +function DESDecryptEcbStrFromHex(const HexStr: AnsiString; const Key: AnsiString): AnsiString; +{* ʮƵ KeyDES ܷģʹ ECB ģʽ + + + const HexStr: AnsiString - ܵʮַ + const Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + + ֵAnsiString - ؽַܺ +} + +function DESEncryptCbcStrToHex(const Str: AnsiString; const Key: AnsiString; const Iv: AnsiString): AnsiString; +{* Key IvDES ܷתʮƵģʹ CBC ģʽĩβܲ #0 + + + const Str: AnsiString - ַܵ + const Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + const Iv: AnsiString - 8 ֽڳʼ + + ֵAnsiString - ؼܺʮַ +} + +function DESDecryptCbcStrFromHex(const HexStr: AnsiString; const Key: AnsiString; + const Iv: AnsiString): AnsiString; +{* ʮƵ Key IvDES ܷģʹ ECB ģʽ + + + const HexStr: AnsiString - ܵʮַ + const Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + const Iv: AnsiString - 8 ֽڳʼ + + ֵAnsiString - ؽַܺ +} + +function DESEncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +{* ֽ DES ܣʹ ECB ģʽ + + + Key: TBytes - 8 ֽ DES Կ̫ضϣ 0 + Input: TBytes - ֽܵ飬䳤粻 8 ʱᱻ 0 ȴﵽ 8 ı + + ֵTBytes - ؼֽܺ +} + +function DESDecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +{* ֽ DES ܣʹ ECB ģʽ + + + Key: TBytes - 8 ֽ DES Կ̫ضϣ 0 + Input: TBytes - ֽܵ飬䳤粻 8 ʱᱻ 0 ȴﵽ 8 ı + + ֵTBytes - ؽֽܺ +} + +function DESEncryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ DES ܣʹ CBC ģʽ + + + Key: TBytes - 8 ֽ DES Կ̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؼֽܺ +} + +function DESDecryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ DES ܣʹ CBC ģʽ + + + Key: TBytes - 8 ֽ DES Կ̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؽֽܺ +} + +procedure DESEncryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; Dest: TStream); overload; +{* DES ܣʹ ECB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 8 ֽ DES Կ + Dest: TStream - + + ֵޣ +} + +procedure DESDecryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; Dest: TStream); overload; +{* DES ܣʹ ECB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 8 ֽ DES Կ + Dest: TStream - + + ֵޣ +} + +procedure DESEncryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +{* DES ܣʹ CBC ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 8 ֽ DES Կ + const InitVector: TCnDESIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure DESDecryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +{* DES ܣʹ CBC ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 8 ֽ DES Կ + const InitVector: TCnDESIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// =========================== 3-DES (Triple DES) ============================== + +function TripleDESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +{* ֽڳȼȡǿ + + + InputByteLength: Integer - ֽڳ + + ֵInteger - 3DES ֽڳ +} + +procedure TripleDESEncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +{* AnsiString 3DES ܣʹ ECB ģʽ + + + Key: AnsiString - 24ֽ 3DES Կ̫ضϣ #0 + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure TripleDESDecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +{* AnsiString 3DES ܣʹ ECB ģʽ + + + Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure TripleDESEncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString 3DES ܣʹ CBC ģʽ + + + Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + Iv: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure TripleDESDecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString 3DES ܣʹ CBC ģʽ + + + Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + Iv: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +function TripleDESEncryptEcbStrToHex(const Str: AnsiString; const Key: AnsiString): AnsiString; +{* Key3DES ܷתʮƵģʹ ECB ģʽĩβܲ #0 + + + const Str: AnsiString - ַܵ + const Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + + ֵAnsiString - ؼܺʮַ +} + +function TripleDESDecryptEcbStrFromHex(const HexStr: AnsiString; const Key: AnsiString): AnsiString; +{* ʮƵ Key3DES ܷģʹ ECB ģʽ + + + const HexStr: AnsiString - ܵʮַ + const Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + + ֵAnsiString - ؽַܺ +} + +function TripleDESEncryptCbcStrToHex(const Str: AnsiString; const Key: AnsiString; + const Iv: AnsiString): AnsiString; +{* Key Iv3DES ܷתʮƵģʹ CBC ģʽĩβܲ #0 + + + const Str: AnsiString - ַܵ + const Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + const Iv: AnsiString - 8 ֽڳʼ + + ֵAnsiString - ؼܺʮַ +} + +function TripleDESDecryptCbcStrFromHex(const HexStr: AnsiString; + const Key: AnsiString; const Iv: AnsiString): AnsiString; +{* ʮƵ Key Iv3DES ܷģʹ CBC ģʽ + + + const HexStr: AnsiString - ܵʮַ + const Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + const Iv: AnsiString - 8 ֽڳʼ + + ֵAnsiString - ؽַܺ +} + +function TripleDESEncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +{* ֽ 3DES ܣʹ ECB ģʽ + + + Key: TBytes - 24 ֽ 3DES Կ̫ضϣ 0 + Input: TBytes - ֽܵ飬䳤粻 8 ʱᱻ 0 ȴﵽ 8 ı + + ֵTBytes - ؼֽܺ +} + +function TripleDESDecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +{* ֽ 3DES ܣʹ ECB ģʽ + + + Key: TBytes - 24 ֽ 3DES Կ̫ضϣ 0 + Input: TBytes - ֽܵ飬䳤粻 8 ʱᱻ 0 ȴﵽ 8 ı + + ֵTBytes - ؽֽܺ +} + +function TripleDESEncryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ 3DES ܣʹ CBC ģʽ + + + Key: TBytes - 24 ֽ 3DES Կ̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؼֽܺ +} + +function TripleDESDecryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ 3DES ܣʹ CBC ģʽ + + + Key: TBytes - 24 ֽ 3DES Կ̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؽֽܺ +} + +procedure TripleDESEncryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; Dest: TStream); overload; +{* 3DES ܣʹ ECB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 24 ֽ 3DES Կ + Dest: TStream - + + ֵޣ +} + +procedure TripleDESDecryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; Dest: TStream); overload; +{* 3DES ܣʹ ECB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 24 ֽ 3DES Կ + Dest: TStream - + + ֵޣ +} + +procedure TripleDESEncryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +{* 3DES ܣʹ CBC ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCn3DESKey - 24 ֽ 3DES Կ + const InitVector: TCnDESIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure TripleDESDecryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +{* 3DES ܣʹ CBC ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCn3DESKey - 24 ֽ 3DES Կ + const InitVector: TCnDESIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +implementation + +resourcestring + SCnErrorDESInvalidInBufSize = 'Invalid Buffer Size for Decryption'; + SCnErrorDESReadError = 'Stream Read Error'; + SCnErrorDESWriteError = 'Stream Write Error'; + +type + TKeyByte = array[0..5] of Byte; + TDesMode = (dmEncry, dmDecry); + TSubKey = array[0..15] of TKeyByte; + +const + BitIP: array[0..63] of Byte = + (57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7, + 56, 48, 40, 32, 24, 16, 8, 0, + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6); + + BitCP: array[0..63] of Byte = + (39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25, + 32, 0, 40, 8, 48, 16, 56, 24); + + BitExp: array[0..47] of Integer = + (31, 0, 1, 2, 3, 4, 3, 4, 5, 6, 7, 8, 7, 8, 9, 10, + 11, 12, 11, 12, 13, 14, 15, 16, 15, 16, 17, 18, 19, 20, 19, 20, + 21, 22, 23, 24, 23, 24, 25, 26, 27, 28, 27, 28, 29, 30, 31, 0); + + BitPM: array[0..31] of Byte = + (15, 6, 19, 20, 28, 11, 27, 16, 0, 14, 22, 25, 4, 17, 30, 9, + 1, 7, 23, 13, 31, 26, 2, 8, 18, 12, 29, 5, 21, 10, 3, 24); + + sBox: array[0..7] of array[0..63] of Byte = + ((14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13), + + (15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9), + + (10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12), + + (7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14), + + (2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3), + + (12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13), + + (4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12), + + (13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11)); + + BitPMC1: array[0..55] of Byte = + (56, 48, 40, 32, 24, 16, 8, + 0, 57, 49, 41, 33, 25, 17, + 9, 1, 58, 50, 42, 34, 26, + 18, 10, 2, 59, 51, 43, 35, + 62, 54, 46, 38, 30, 22, 14, + 6, 61, 53, 45, 37, 29, 21, + 13, 5, 60, 52, 44, 36, 28, + 20, 12, 4, 27, 19, 11, 3); + + BitPMC2: array[0..47] of Byte = + (13, 16, 10, 23, 0, 4, + 2, 27, 14, 5, 20, 9, + 22, 18, 11, 3, 25, 7, + 15, 6, 26, 19, 12, 1, + 40, 51, 30, 36, 46, 54, + 29, 39, 50, 44, 32, 47, + 43, 48, 38, 55, 33, 52, + 45, 41, 49, 35, 28, 31); + +function Min(A, B: Integer): Integer; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + if A < B then + Result := A + else + Result := B; +end; + +procedure InitPermutation(var InData: array of Byte); +var + NewData: array[0..7] of Byte; + I: Integer; +begin + FillChar(NewData, 8, 0); + for I := 0 to 63 do + if (InData[BitIP[I] shr 3] and (1 shl (7 - (BitIP[I] and $07)))) <> 0 then + NewData[I shr 3] := NewData[I shr 3] or (1 shl (7 - (I and $07))); + for I := 0 to 7 do InData[I] := NewData[I]; +end; + +procedure ConversePermutation(var InData: array of Byte); +var + NewData: array[0..7] of Byte; + I: Integer; +begin + FillChar(NewData, 8, 0); + for I := 0 to 63 do + if (InData[BitCP[I] shr 3] and (1 shl (7 - (BitCP[I] and $07)))) <> 0 then + NewData[I shr 3] := NewData[I shr 3] or (1 shl (7 - (I and $07))); + for I := 0 to 7 do InData[I] := NewData[I]; +end; + +procedure Expand(const InData: array of Byte; var OutData: array of Byte); +var + I: Integer; +begin + FillChar(OutData, 6, 0); + for I := 0 to 47 do + if (InData[BitExp[I] shr 3] and (1 shl (7 - (BitExp[I] and $07)))) <> 0 then + OutData[I shr 3] := OutData[I shr 3] or (1 shl (7 - (I and $07))); +end; + +procedure Permutation(var InData: array of Byte); +var + NewData: array[0..3] of Byte; + I: Integer; +begin + FillChar(NewData, 4, 0); + for I := 0 to 31 do + if (InData[BitPM[I] shr 3] and (1 shl (7 - (BitPM[I] and $07)))) <> 0 then + NewData[I shr 3] := NewData[I shr 3] or (1 shl (7 - (I and $07))); + for I := 0 to 3 do InData[I] := NewData[I]; +end; + +function Si(S, InByte: Byte): Byte; +var + c: Byte; +begin + c := (InByte and $20) or ((InByte and $1E) shr 1) or + ((InByte and $01) shl 4); + Result := (sBox[S][c] and $0F); +end; + +procedure PermutationChoose1(const InData: array of Byte; var OutData: array of Byte); +var + I: Integer; +begin + FillChar(OutData, 7, 0); + for I := 0 to 55 do + if (InData[BitPMC1[I] shr 3] and (1 shl (7 - (BitPMC1[I] and $07)))) <> 0 then + OutData[I shr 3] := OutData[I shr 3] or (1 shl (7 - (I and $07))); +end; + +procedure PermutationChoose2(const InData: array of Byte; var OutData: array of Byte); +var + I: Integer; +begin + FillChar(OutData, 6, 0); + for I := 0 to 47 do + if (InData[BitPMC2[I] shr 3] and (1 shl (7 - (BitPMC2[I] and $07)))) <> 0 then + OutData[I shr 3] := OutData[I shr 3] or (1 shl (7 - (I and $07))); +end; + +procedure CycleMove(var InData: array of Byte; bitMove: Byte); +var + I: Integer; +begin + for I := 0 to bitMove - 1 do + begin + InData[0] := (InData[0] shl 1) or (InData[1] shr 7); + InData[1] := (InData[1] shl 1) or (InData[2] shr 7); + InData[2] := (InData[2] shl 1) or (InData[3] shr 7); + InData[3] := (InData[3] shl 1) or ((InData[0] and $10) shr 4); + InData[0] := (InData[0] and $0F); + end; +end; + +procedure MakeKey(const InKey: array of Byte; var OutKey: array of TKeyByte); +const + bitDisplace: array[0..15] of Byte = + (1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1); +var + OutData56: array[0..6] of Byte; + Key28l: array[0..3] of Byte; + Key28r: array[0..3] of Byte; + Key56o: array[0..6] of Byte; + I: Integer; +begin + PermutationChoose1(InKey, OutData56); + Key28l[0] := OutData56[0] shr 4; + Key28l[1] := (OutData56[0] shl 4) or (OutData56[1] shr 4); + Key28l[2] := (OutData56[1] shl 4) or (OutData56[2] shr 4); + Key28l[3] := (OutData56[2] shl 4) or (OutData56[3] shr 4); + Key28r[0] := OutData56[3] and $0F; + Key28r[1] := OutData56[4]; + Key28r[2] := OutData56[5]; + Key28r[3] := OutData56[6]; + for I := 0 to 15 do + begin + CycleMove(Key28l, bitDisplace[I]); + CycleMove(Key28r, bitDisplace[I]); + Key56o[0] := (Key28l[0] shl 4) or (Key28l[1] shr 4); + Key56o[1] := (Key28l[1] shl 4) or (Key28l[2] shr 4); + Key56o[2] := (Key28l[2] shl 4) or (Key28l[3] shr 4); + Key56o[3] := (Key28l[3] shl 4) or (Key28r[0]); + Key56o[4] := Key28r[1]; + Key56o[5] := Key28r[2]; + Key56o[6] := Key28r[3]; + PermutationChoose2(Key56o, OutKey[I]); + end; +end; + +procedure Encry(const InData, ASubKey: array of Byte; var OutData: array of Byte); +var + OutBuf: array[0..5] of Byte; + Buf: array[0..7] of Byte; + I: Integer; +begin + Expand(InData, OutBuf); + for I := 0 to 5 do OutBuf[I] := OutBuf[I] xor ASubKey[I]; + Buf[0] := OutBuf[0] shr 2; + Buf[1] := ((OutBuf[0] and $03) shl 4) or (OutBuf[1] shr 4); + Buf[2] := ((OutBuf[1] and $0F) shl 2) or (OutBuf[2] shr 6); + Buf[3] := OutBuf[2] and $3F; + Buf[4] := OutBuf[3] shr 2; + Buf[5] := ((OutBuf[3] and $03) shl 4) or (OutBuf[4] shr 4); + Buf[6] := ((OutBuf[4] and $0F) shl 2) or (OutBuf[5] shr 6); + Buf[7] := OutBuf[5] and $3F; + for I := 0 to 7 do Buf[I] := si(I, Buf[I]); + for I := 0 to 3 do OutBuf[I] := (Buf[I * 2] shl 4) or Buf[I * 2 + 1]; + Permutation(OutBuf); + for I := 0 to 3 do OutData[I] := OutBuf[I]; +end; + +// InData OutData Ҫ 8 ֽ +procedure DesData(DesMode: TDesMode; SubKey: TSubKey; const InData: array of Byte; + var OutData: array of Byte); +var + I, J: Integer; + Temp, Buf: array[0..3] of Byte; +begin + for I := 0 to 7 do OutData[I] := InData[I]; + InitPermutation(OutData); + if DesMode = dmEncry then + begin + for I := 0 to 15 do + begin + for J := 0 to 3 do Temp[J] := OutData[J]; + for J := 0 to 3 do OutData[J] := OutData[J + 4]; + Encry(OutData, SubKey[I], Buf); + for J := 0 to 3 do OutData[J + 4] := Temp[J] xor Buf[J]; + end; + for J := 0 to 3 do Temp[J] := OutData[J + 4]; + for J := 0 to 3 do OutData[J + 4] := OutData[J]; + for J := 0 to 3 do OutData[J] := Temp[J]; + end + else if DesMode = dmDecry then + begin + for I := 15 downto 0 do + begin + for J := 0 to 3 do Temp[J] := OutData[J]; + for J := 0 to 3 do OutData[J] := OutData[J + 4]; + Encry(OutData, SubKey[I], Buf); + for J := 0 to 3 do OutData[J + 4] := Temp[J] xor Buf[J]; + end; + for J := 0 to 3 do Temp[J] := OutData[J + 4]; + for J := 0 to 3 do OutData[J + 4] := OutData[J]; + for J := 0 to 3 do OutData[J] := Temp[J]; + end; + ConversePermutation(OutData); +end; + +// Key #0 ճ 8 ֽ +procedure MakeKeyAlign(var Key: AnsiString); +begin + if Length(Key) < CN_DES_KEYSIZE then + while Length(Key) < CN_DES_KEYSIZE do + Key := Key + Chr(0); +end; + +// ַ #0 ճ 8 ıעմ +procedure MakeInputAlign(var Str: AnsiString); +begin + while Length(Str) mod CN_DES_KEYSIZE <> 0 do + Str := Str + Chr(0); +end; + +// ֽ鲹 0 ճ 8 ıע鲻 +procedure MakeInputBytesAlign(var Input: TBytes); +var + I, Len, NL: Integer; +begin + Len := Length(Input); + if Len mod CN_DES_BLOCKSIZE <> 0 then + begin + NL := ((Len div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE; + SetLength(Input, NL); + for I := Len to NL - 1 do + Input[I] := 0; + end; +end; + +function DESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +begin + Result := (((InputByteLength - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE; +end; + +procedure DESEncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + Str: AnsiString; + I: Integer; + SubKey: TSubKey; +begin + MakeKeyAlign(Key); + + Str := Input; + MakeInputAlign(Str); // Str 8 ı + + if Str = '' then // մֱӷؿ + begin + if Output <> nil then + Output[0] := #0; + Exit; + end; + + Move(Key[1], KeyByte[0], SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + for I := 0 to Length(Str) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Str[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + DesData(dmEncry, SubKey, StrByte, OutByte); + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +procedure DESDecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + I: Integer; + SubKey: TSubKey; +begin + MakeKeyAlign(Key); + Move(Key[1], KeyByte[0], SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + DesData(dmDecry, SubKey, StrByte, OutByte); + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; + + // ĩβ 0 ⲿжɾ +end; + +procedure DESEncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + Vector: TCnDESIv; + Str: AnsiString; + I: Integer; + SubKey: TSubKey; +begin + MakeKeyAlign(Key); + + Str := Input; + MakeInputAlign(Str); + + if Str = '' then // մֱӷؿ + begin + if Output <> nil then + Output[0] := #0; + Exit; + end; + + Move(Key[1], KeyByte[0], SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + Move(Iv^, Vector[0], SizeOf(TCnDESIv)); + + for I := 0 to Length(Str) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Str[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + + // CBC ݿֵȸ Iv + PCardinal(@StrByte[0])^ := PCardinal(@StrByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@StrByte[4])^ := PCardinal(@StrByte[4])^ xor PCardinal(@Vector[4])^; + + // ټ + DesData(dmEncry, SubKey, StrByte, OutByte); + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ܽµ Iv + Move(OutByte[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +procedure DESDecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + Vector, TV: TCnDESIv; + I: Integer; + SubKey: TSubKey; +begin + MakeKeyAlign(Key); + Move(Key[1], KeyByte[0], SizeOf(TCnDESKey)); + + MakeKey(KeyByte, SubKey); + Move(Iv^, Vector[0], SizeOf(TCnDESIv)); + + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + Move(StrByte[0], TV[0], SizeOf(TCnDESIv)); // ȴһ + + // Ƚ + DesData(dmDecry, SubKey, StrByte, OutByte); + + // CBC ݿֵܺٸ Iv + PCardinal(@OutByte[0])^ := PCardinal(@OutByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@OutByte[4])^ := PCardinal(@OutByte[4])^ xor PCardinal(@Vector[4])^; + + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ĸµ Iv + Move(TV[0], Vector[0], SizeOf(TCnDESIv)); + end; + + // ĩβ 0 ⲿжɾ +end; + +procedure SetResultLengthUsingInput(const Str: AnsiString; var Res: AnsiString); +var + Len: Integer; +begin + Len := Length(Str); + if Len < CN_DES_BLOCKSIZE then + Len := CN_DES_BLOCKSIZE + else + Len := (((Len - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE; + SetLength(Res, Len); +end; + +function DESEncryptEcbStrToHex(const Str, Key: AnsiString): AnsiString; +var + TempResult: AnsiString; +begin + Result := ''; + if Str = '' then + Exit; + + SetResultLengthUsingInput(Str, TempResult); + DESEncryptEcbStr(Key, Str, @TempResult[1]); + Result := AnsiStrToHex(TempResult); +end; + +function DESDecryptEcbStrFromHex(const HexStr, Key: AnsiString): AnsiString; +var + Str: AnsiString; +begin + Str := HexToAnsiStr(HexStr); + SetResultLengthUsingInput(Str, Result); + DESDecryptEcbStr(Key, Str, @(Result[1])); +end; + +function DESEncryptCbcStrToHex(const Str, Key, Iv: AnsiString): AnsiString; +var + TempResult: AnsiString; +begin + Result := ''; + if Str = '' then + Exit; + + SetResultLengthUsingInput(Str, TempResult); + DESEncryptCbcStr(Key, PAnsiChar(Iv), Str, @TempResult[1]); + Result := AnsiStrToHex(TempResult); +end; + +function DESDecryptCbcStrFromHex(const HexStr, Key, Iv: AnsiString): AnsiString; +var + Str: AnsiString; +begin + Str := HexToAnsiStr(HexStr); + SetResultLengthUsingInput(Str, Result); + DESDecryptCbcStr(Key, PAnsiChar(Iv), Str, @(Result[1])); +end; + +function DESEncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + I: Integer; + SubKey: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + MakeInputBytesAlign(Input); + + FillChar(KeyByte[0], SizeOf(TCnDESKey), 0); + MoveMost(Key[0], KeyByte[0], Length(Key), SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + DesData(dmEncry, SubKey, StrByte, OutByte); + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +function DESDecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + I: Integer; + SubKey: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + FillChar(KeyByte[0], SizeOf(TCnDESKey), 0); + MoveMost(Key[0], KeyByte[0], Length(Key), SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + DesData(dmDecry, SubKey, StrByte, OutByte); + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +function DESEncryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + Vector: TCnDESIv; + I: Integer; + SubKey: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + MakeInputBytesAlign(Input); + + FillChar(KeyByte[0], SizeOf(TCnDESKey), 0); + MoveMost(Key[0], KeyByte[0], Length(Key), SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + FillChar(Vector[0], SizeOf(TCnDESIv), 0); + MoveMost(Iv[0], Vector[0], Length(Iv), SizeOf(TCnDESIv)); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + + // CBC ݿֵȸ Iv + PCardinal(@StrByte[0])^ := PCardinal(@StrByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@StrByte[4])^ := PCardinal(@StrByte[4])^ xor PCardinal(@Vector[4])^; + + // ټ + DesData(dmEncry, SubKey, StrByte, OutByte); + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ܽµ Iv + Move(OutByte[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +function DESDecryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + Vector, TV: TCnDESIv; + I: Integer; + SubKey: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + FillChar(KeyByte[0], SizeOf(TCnDESKey), 0); + MoveMost(Key[0], KeyByte[0], Length(Key), SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + FillChar(Vector[0], SizeOf(TCnDESIv), 0); + MoveMost(Iv[0], Vector[0], Length(Iv), SizeOf(TCnDESIv)); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + Move(StrByte[0], TV[0], SizeOf(TCnDESIv)); // ȴһ + + // Ƚ + DesData(dmDecry, SubKey, StrByte, OutByte); + + // CBC ݿֵܺٸ Iv + PCardinal(@OutByte[0])^ := PCardinal(@OutByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@OutByte[4])^ := PCardinal(@OutByte[4])^ xor PCardinal(@Vector[4])^; + + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ĸµ Iv + Move(TV[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +procedure DESEncryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; Dest: TStream); overload; +var + TempIn, TempOut: TCnDESBuffer; + Done: Cardinal; + SubKey: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + MakeKey(Key, SubKey); + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + DesData(dmEncry, SubKey, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Dec(Count, SizeOf(TCnDESBuffer)); + end; + + if Count > 0 then // β 0 + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorDESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + + DesData(dmEncry, SubKey, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + end; +end; + +procedure DESDecryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; Dest: TStream); overload; +var + TempIn, TempOut: TCnDESBuffer; + Done: Cardinal; + SubKey: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + if (Count mod SizeOf(TCnDESBuffer)) > 0 then + raise ECnDESException.Create(SCnErrorDESInvalidInBufSize); + + MakeKey(Key, SubKey); + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + DesData(dmDecry, SubKey, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Dec(Count, SizeOf(TCnDESBuffer)); + end; +end; + +procedure DESEncryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +var + TempIn, TempOut: TCnDESBuffer; + Vector: TCnDESIv; + Done: Cardinal; + SubKey: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + MakeKey(Key, SubKey); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + + DesData(dmEncry, SubKey, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Move(TempOut[0], Vector[0], SizeOf(TCnDESIv)); + Dec(Count, SizeOf(TCnDESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorDESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + + DesData(dmEncry, SubKey, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + end; +end; + +procedure DESDecryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +var + TempIn, TempOut: TCnDESBuffer; + Vector1, Vector2: TCnDESIv; + Done: Cardinal; + SubKey: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + if (Count mod SizeOf(TCnDESBuffer)) > 0 then + raise ECnDESException.Create(SCnErrorDESInvalidInBufSize); + + Vector1 := InitVector; + MakeKey(Key, SubKey); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorDESReadError); + + Move(TempIn[0], Vector2[0], SizeOf(TCnDESIv)); + DesData(dmDecry, SubKey, TempIn, TempOut); + + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorDESWriteError); + + Vector1 := Vector2; + Dec(Count, SizeOf(TCnDESBuffer)); + end; +end; + +procedure Make3DESKeys(Keys: AnsiString; var K1, K2, K3: TCnDESKey); overload; +var + I: Integer; +begin + if Length(Keys) < CN_TRIPLE_DES_KEYSIZE then + while Length(Keys) < CN_TRIPLE_DES_KEYSIZE do + Keys := Keys + Chr(0); + + for I := 0 to CN_DES_KEYSIZE - 1 do + begin + K1[I] := Ord(Keys[I + 1]); + K2[I] := Ord(Keys[I + 1 + CN_DES_KEYSIZE]); + K3[I] := Ord(Keys[I + 1 + CN_DES_KEYSIZE * 2]); + end; +end; + +procedure Make3DESKeys(Keys: TCn3DESKey; var K1, K2, K3: TCnDESKey); overload; +var + I: Integer; +begin + for I := 0 to CN_DES_KEYSIZE - 1 do + begin + K1[I] := Keys[I]; + K2[I] := Keys[I + CN_DES_KEYSIZE]; + K3[I] := Keys[I + CN_DES_KEYSIZE * 2]; + end; +end; + +procedure Make3DESKeys(Keys: TBytes; var K1, K2, K3: TCnDESKey); overload; +var + I, Len: Integer; +begin + Len := Length(Keys); + if Len < CN_TRIPLE_DES_KEYSIZE then + begin + SetLength(Keys, CN_TRIPLE_DES_KEYSIZE); + for I := Len to CN_TRIPLE_DES_KEYSIZE - 1 do + Keys[I] := 0; + end; + + for I := 0 to CN_DES_KEYSIZE - 1 do + begin + K1[I] := Ord(Keys[I]); + K2[I] := Ord(Keys[I + CN_DES_KEYSIZE]); + K3[I] := Ord(Keys[I + CN_DES_KEYSIZE * 2]); + end; +end; + +function TripleDESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +begin + Result := (((InputByteLength - 1) div CN_TRIPLE_DES_BLOCKSIZE) + 1) * CN_TRIPLE_DES_BLOCKSIZE; +end; + +procedure TripleDESEncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + Str: AnsiString; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + Str := Input; + MakeInputAlign(Str); + + if Str = '' then // մֱӷؿ + begin + if Output <> nil then + Output[0] := #0; + Exit; + end; + + for I := 0 to Length(Str) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Str[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + + DesData(dmEncry, SubKey1, StrByte, OutByte); + DesData(dmDecry, SubKey2, OutByte, StrByte); + DesData(dmEncry, SubKey3, StrByte, OutByte); + + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +procedure TripleDESDecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + + DesData(dmDecry, SubKey3, StrByte, OutByte); + DesData(dmEncry, SubKey2, OutByte, StrByte); + DesData(dmDecry, SubKey1, StrByte, OutByte); + + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; + + // ĩβ 0 ⲿжɾ +end; + +procedure TripleDESEncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + Vector: TCnDESIv; + Str: AnsiString; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + Str := Input; + MakeInputAlign(Str); + + if Str = '' then // մֱӷؿ + begin + if Output <> nil then + Output[0] := #0; + Exit; + end; + + Move(Iv^, Vector[0], SizeOf(TCnDESIv)); + + for I := 0 to Length(Str) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Str[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + + // CBC ݿֵȸ Iv + PCardinal(@StrByte[0])^ := PCardinal(@StrByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@StrByte[4])^ := PCardinal(@StrByte[4])^ xor PCardinal(@Vector[4])^; + + // ټ + DesData(dmEncry, SubKey1, StrByte, OutByte); + DesData(dmDecry, SubKey2, OutByte, StrByte); + DesData(dmEncry, SubKey3, StrByte, OutByte); + + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ܽµ Iv + Move(OutByte[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +procedure TripleDESDecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + Vector, TV: TCnDESIv; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + Move(Iv^, Vector[0], SizeOf(TCnDESIv)); + + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + Move(StrByte[0], TV[0], SizeOf(TCnDESIv)); // ȴһ + + // Ƚ + DesData(dmDecry, SubKey3, StrByte, OutByte); + DesData(dmEncry, SubKey2, OutByte, StrByte); + DesData(dmDecry, SubKey1, StrByte, OutByte); + + // CBC ݿֵܺٸ Iv + PCardinal(@OutByte[0])^ := PCardinal(@OutByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@OutByte[4])^ := PCardinal(@OutByte[4])^ xor PCardinal(@Vector[4])^; + + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ĸµ Iv + Move(TV[0], Vector[0], SizeOf(TCnDESIv)); + end; + + // ĩβ 0 ⲿжɾ +end; + +function TripleDESEncryptEcbStrToHex(const Str, Key: AnsiString): AnsiString; +var + TempResult, Temp: AnsiString; + I: Integer; +begin + SetResultLengthUsingInput(Str, TempResult); + TripleDESEncryptEcbStr(Key, Str, @TempResult[1]); + + Result := ''; + for I := 0 to Length(TempResult) - 1 do + begin + Temp := AnsiString(Format('%x', [Ord(TempResult[I + 1])])); + if Length(Temp) = 1 then + Temp := '0' + Temp; + Result := Result + Temp; + end; +end; + +function TripleDESDecryptEcbStrFromHex(const HexStr, Key: AnsiString): AnsiString; +var + Str: AnsiString; +begin + Str := HexToAnsiStr(HexStr); + SetResultLengthUsingInput(Str, Result); + TripleDESDecryptEcbStr(Key, Str, @(Result[1])); +end; + +function TripleDESEncryptCbcStrToHex(const Str, Key, Iv: AnsiString): AnsiString; +var + TempResult, Temp: AnsiString; + I: Integer; +begin + SetResultLengthUsingInput(Str, TempResult); + TripleDESEncryptCbcStr(Key, PAnsiChar(Iv), Str, @TempResult[1]); + + Result := ''; + for I := 0 to Length(TempResult) - 1 do + begin + Temp := AnsiString(Format('%x', [Ord(TempResult[I + 1])])); + if Length(Temp) = 1 then + Temp := '0' + Temp; + Result := Result + Temp; + end; +end; + +function TripleDESDecryptCbcStrFromHex(const HexStr, Key, Iv: AnsiString): AnsiString; +var + Str: AnsiString; +begin + Str := HexToAnsiStr(HexStr); + SetResultLengthUsingInput(Str, Result); + TripleDESDecryptCbcStr(Key, PAnsiChar(Iv), Str, @(Result[1])); +end; + +function TripleDESEncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + MakeInputBytesAlign(Input); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + + DesData(dmEncry, SubKey1, StrByte, OutByte); + DesData(dmDecry, SubKey2, OutByte, StrByte); + DesData(dmEncry, SubKey3, StrByte, OutByte); + + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +function TripleDESDecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + + DesData(dmDecry, SubKey3, StrByte, OutByte); + DesData(dmEncry, SubKey2, OutByte, StrByte); + DesData(dmDecry, SubKey1, StrByte, OutByte); + + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +function TripleDESEncryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + Vector: TCnDESIv; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + MakeInputBytesAlign(Input); + FillChar(Vector[0], SizeOf(TCnDESIv), 0); + MoveMost(Iv[0], Vector[0], Length(Iv), SizeOf(TCnDESIv)); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + + // CBC ݿֵȸ Iv + PCardinal(@StrByte[0])^ := PCardinal(@StrByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@StrByte[4])^ := PCardinal(@StrByte[4])^ xor PCardinal(@Vector[4])^; + + // ټ + DesData(dmEncry, SubKey1, StrByte, OutByte); + DesData(dmDecry, SubKey2, OutByte, StrByte); + DesData(dmEncry, SubKey3, StrByte, OutByte); + + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ܽµ Iv + Move(OutByte[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +function TripleDESDecryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + Vector, TV: TCnDESIv; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + FillChar(Vector[0], SizeOf(TCnDESIv), 0); + MoveMost(Iv[0], Vector[0], Length(Iv), SizeOf(TCnDESIv)); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + Move(StrByte[0], TV[0], SizeOf(TCnDESIv)); // ȴһ + + // Ƚ + DesData(dmDecry, SubKey3, StrByte, OutByte); + DesData(dmEncry, SubKey2, OutByte, StrByte); + DesData(dmDecry, SubKey1, StrByte, OutByte); + + // CBC ݿֵܺٸ Iv + PCardinal(@OutByte[0])^ := PCardinal(@OutByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@OutByte[4])^ := PCardinal(@OutByte[4])^ xor PCardinal(@Vector[4])^; + + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ĸµ Iv + Move(TV[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +procedure TripleDESEncryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; Dest: TStream); overload; +var + K1, K2, K3: TCnDESKey; + TempIn, TempOut: TCnDESBuffer; + Done: Cardinal; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + DesData(dmEncry, SubKey1, TempIn, TempOut); + DesData(dmDecry, SubKey2, TempOut, TempIn); + DesData(dmEncry, SubKey3, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Dec(Count, SizeOf(TCnDESBuffer)); + end; + + if Count > 0 then // β 0 + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorDESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + + DesData(dmEncry, SubKey1, TempIn, TempOut); + DesData(dmDecry, SubKey2, TempOut, TempIn); + DesData(dmEncry, SubKey3, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + end; +end; + +procedure TripleDESDecryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; Dest: TStream); overload; +var + K1, K2, K3: TCnDESKey; + TempIn, TempOut: TCnDESBuffer; + Done: Cardinal; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + if (Count mod SizeOf(TCnDESBuffer)) > 0 then + raise ECnDESException.Create(SCnErrorDESInvalidInBufSize); + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + DesData(dmDecry, SubKey3, TempIn, TempOut); + DesData(dmEncry, SubKey2, TempOut, TempIn); + DesData(dmDecry, SubKey1, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Dec(Count, SizeOf(TCnDESBuffer)); + end; +end; + +procedure TripleDESEncryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +var + K1, K2, K3: TCnDESKey; + TempIn, TempOut: TCnDESBuffer; + Vector: TCnDESIv; + Done: Cardinal; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + + DesData(dmEncry, SubKey1, TempIn, TempOut); + DesData(dmDecry, SubKey2, TempOut, TempIn); + DesData(dmEncry, SubKey3, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Move(TempOut[0], Vector[0], SizeOf(TCnDESIv)); + Dec(Count, SizeOf(TCnDESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorDESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + + DesData(dmEncry, SubKey1, TempIn, TempOut); + DesData(dmDecry, SubKey2, TempOut, TempIn); + DesData(dmEncry, SubKey3, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + end; +end; + +procedure TripleDESDecryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +var + K1, K2, K3: TCnDESKey; + TempIn, TempOut: TCnDESBuffer; + Vector1, Vector2: TCnDESIv; + Done: Cardinal; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + if (Count mod SizeOf(TCnDESBuffer)) > 0 then + raise ECnDESException.Create(SCnErrorDESInvalidInBufSize); + + Vector1 := InitVector; + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorDESReadError); + + Move(TempIn[0], Vector2[0], SizeOf(TCnDESIv)); + + DesData(dmDecry, SubKey3, TempIn, TempOut); + DesData(dmEncry, SubKey2, TempOut, TempIn); + DesData(dmDecry, SubKey1, TempIn, TempOut); + + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorDESWriteError); + + Vector1 := Vector2; + Dec(Count, SizeOf(TCnDESBuffer)); + end; +end; + +end. diff --git a/CnPack/Crypto/CnFloat.dcu b/CnPack/Crypto/CnFloat.dcu new file mode 100644 index 0000000000000000000000000000000000000000..609c33e673b3341b651478b135b8b56c24b5cb19 GIT binary patch literal 15913 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 +================================================================================ +* ƣ +* Ԫƣת +* ԪߣǬԪ(wqyfavor@163.com) +* עõԪʵ Extended תΪˡʮַĺ +* 㷨Ƕȡ Extended ڴеĶݽת Extended ͵˵ +* ԲοϡDouble Single Ϊϵͳֵ֧ͨĸͣ Delphi е +* Extended ڴ洢ʽвͬ߾β񻯣 Double Single β +* Ĭϵ 1βΪ 1.001 Double Single д洢Ϊ 001ȥ +* Сǰ 1 Extended 洢Ϊ 1001 +* NaN Ϊ "not a number"Ǹο Math.pas Ԫеij NaN +* Infinity Ϊ󣬶ο Math.pas Ԫеij Infinity NegInfinity. +* һ DecimalExp AlwaysUseExponent +* ʮƸתʱָʽѧ㷨Щ +* Ҳָֻʽ 1E-1000ָʱ 0.0000000...0001תָ +* ҲӦӦƱʾʱʮƱʾָ֣ƴ +* 1.001E101ֵΪ 100100ָʮƱһЩ 1.001D5ʾС +* 5 λDecimalExp ָǷʮƱֵָġע⣬ʮ +* ʾָ޹涨﷨ʹ "D" ʾ"E" ΪӦƱʾ⣬ +* ʮƱȽ⣬"D" "E" ΪʮַʮƱʱʹ "^" +* ַ 3.BD^D(12)A.BD^E(ABCE)粻ϲָʽ޸ġ +* AlwaysUseExponent ָǷһÿѧ 100.111 λȽ٣ +* ԶжϲҪʹÿѧ AlwaysUseExponent ΪʱһΪָ +* ʽ 1.00111E2 +* const +* MaxBinDigits = 120; +* MaxHexDigits = 30; +* MaxOctDigits = 40; +* ָλʱһʹÿѧ +* +* ⣬Extended ֻ Win32 10 ֽڣMacOS/Linux x64 ¾ 16 ֽڣWin64 ARM ƽ̨ 8 ֽ +* ңMacOS64 µ 16 ֽչȲ IEEE 754-2008 й涨 Quadruple ʽǰ 10 ֽڽضϣ +* ڲṹͬ Win32 µչ 10 ֽ +* +* ƽ̨WinXP + Delphi 2009 +* ݲԣDelphi 2007 Extended ֻ֧Сģʽ +* õԪеַϱػʽ +* ޸ļ¼2023.01.13 +* ݴ Win64 Extended 8 ֽ Double 10 ֽչȵ +* ݴ MacOS64/Linux64 µ 16 ֽ Extendedֻضϴǰ 10 ֽڣ +* 2022.02.17 +* FPC ı֧֣ +* 2021.09.05 +* תΪ UInt64֧ UInt64 Int64 棩ĺ +* 2020.11.11 +* UInt64֧ UInt64 Int64 棩תΪĺ +* 2020.06.24 +* ⿪ƴյĺ +* 2009.1.12 +* Ԫ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes, SysConst, {$IFDEF MSWINDOWS} Windows, {$ENDIF} CnNative; + +{ + IEEE 754 涨ָʽЧڵλ 0 + + Single 1 λ S8 λָ E23 λЧ M 4 ֽ 32 λ + ˫ Double 1 λ S11 λָ E52 λЧ M 8 ֽ 64 λ + չ˫ Extended 1 λ S15 λָ E64 λЧ M 10 ֽ 80 λ + + IEEE 754-2008 + ı Quadruple 1 λ S15 λָ E112 λЧ M 16 ֽ 128 λ + ˱ Octuple 1 λ S19 λָ E236 λЧ M 32 ֽ 256 λ + + Уλ S0 ʾ1 ʾE Ҫȥ 127/1023/16383/16383 ָ + M: 淶/˫ȵĶ M ĸλӸ 1. Чչӣ 1. + ֵЧ 1.xxxx ʽ 2 E ηעⲻ 10 E η + + ʽ ֽ 1 ֽ 2 ֽ 3 ֽ 4 ... ֽ nÿֽڵұߵλ 0 + 4 SXXXXXXX XMMMMMMM MMMMMMMM MMMMMMMM + ˫ 8 SXXXXXXX XXXXMMMM MMMMMMMM MMMMMMMM ... MMMMMMMM + չ˫ 10 SXXXXXXX XXXXXXXX 1MMMMMMM MMMMMMMM ... MMMMMMMM // עЧְ 1඼ʡ 1 + ı 16 SXXXXXXX XXXXXXXX MMMMMMMM MMMMMMMM ... MMMMMMMM + ˱ 32 SXXXXXXX XXXXXXXX XXXXMMMM MMMMMMMM ... MMMMMMMM + + ע⣺Little Endian ϣֽ 1 n 򡣱Ԫѵ + + 0ȫ 0 + -0ȫ 0 λΪ 1 + ָȫ 1Чȫ 0 0 1 +} + +type + TCnQuadruple = packed record + {* Delphi ıͣýṹָ} + Lo: TUInt64; + Hi0: Cardinal; + case Boolean of + True: (Hi1: Cardinal); + False: (W0, W1: Word); // С˻ϣźָ W1 + end; + PCnQuadruple = ^TCnQuadruple; + + TCnOctuple = packed record + {* Delphi ް˱ͣ Int64 ָ} + F0: Int64; + F1: Int64; + F2: Int64; + F3: Int64; + end; + PCnOctuple = ^TCnOctuple; + + ECnFloatSizeError = class(Exception); + +const + CN_EXTENDED_SIZE_8 = 8; // Win64 µ Extended ֻ 8 ֽ + CN_EXTENDED_SIZE_10 = 10; // Win32 µ Extended DZ׼ 10 ֽ + CN_EXTENDED_SIZE_16 = 16; // MACOS64/Linux64 16 ֽ + + CN_SIGN_SINGLE_MASK = $80000000; + CN_SIGN_DOUBLE_MASK = $8000000000000000; + CN_SIGN_EXTENDED_MASK = $8000; // ȥ 8 ֽЧ + CN_SIGN_QUADRUPLE_MASK = $80000000; // ֻǰֽڣȥ˺ + + CN_EXPONENT_SINGLE_MASK = $7F800000; // Ҫ 23 λ + CN_EXPONENT_DOUBLE_MASK = $7FF0000000000000; // Ҫ 52 λ + CN_EXPONENT_EXTENDED_MASK = $7FFF; // ȥ 8 ֽЧ + CN_EXPONENT_QUADRUPLE_MASK = $7FFF; // ȥ 14 ֽЧ + + CN_SIGNIFICAND_SINGLE_MASK = $007FFFFF; // 23 λ + CN_SIGNIFICAND_DOUBLE_MASK = $000FFFFFFFFFFFFF; // 52 λ + CN_SIGNIFICAND_EXTENDED_MASK = $FFFFFFFFFFFFFFFF; // 64 λʵȫ 8 ֽ + CN_SIGNIFICAND_QUADRUPLE_MASK = $FFFF; + + CN_SINGLE_SIGNIFICAND_BITLENGTH = 23; + CN_DOUBLE_SIGNIFICAND_BITLENGTH = 52; + CN_EXTENDED_SIGNIFICAND_BITLENGTH = 63; + + CN_EXPONENT_OFFSET_SINGLE = 127; // ʵֵָҪܴ浽ڴָ + CN_EXPONENT_OFFSET_DOUBLE = 1023; + CN_EXPONENT_OFFSET_EXTENDED = 16383; // 10 16 ֽչȸΪ + + CN_SINGLE_MIN_EXPONENT = -127; + CN_SINGLE_MAX_EXPONENT = 127; // Max ָȫ 1 Σ + CN_DOUBLE_MIN_EXPONENT = -1023; + CN_DOUBLE_MAX_EXPONENT = 1023; + CN_EXTENDED_MIN_EXPONENT = -16383; + CN_EXTENDED_MAX_EXPONENT = 16383; + +procedure ExtractFloatSingle(Value: Single; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: Cardinal); +{* ӵȸнλָЧ֡ + עָΪʵָЧΪ 24 λԭʼΪ 0~22 λ 23 λΪȥ 1 + + + Value: Single - ⿪ĵȸ + out SignNegative: Boolean - λTrue Ϊ + out Exponent: Integer - ָ + out Mantissa: Cardinal - Ч + + ֵޣ +} + +procedure ExtractFloatDouble(Value: Double; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: TUInt64); +{* ˫ȸнλָЧ֡ + עָΪʵָЧΪ 53 λԭʼΪ 0~51 λ 52 λΪȥ 1 + + + Value: Double - ⿪˫ȸ + out SignNegative: Boolean - λTrue Ϊ + out Exponent: Integer - ָ + out Mantissa: TUInt64 - Ч + + ֵޣ +} + +procedure ExtractFloatExtended(Value: Extended; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: TUInt64); +{* չȸнλָЧ֣֧ 10 ֽڡ + Լ 16 ֽڽضΪ 10 ֽڵ Extended ʽ + עָΪʵָЧΪȫ 64 λλ 63 λΪԴ 1 + + + Value: Extended - ⿪չȸ + out SignNegative: Boolean - λTrue Ϊ + out Exponent: Integer - ָ + out Mantissa: TUInt64 - Ч + + ֵޣ +} + +procedure ExtractFloatQuadruple(Value: Extended; out SignNegative: Boolean; + out Exponent: Integer; out MantissaLo: TUInt64; out MantissaHi: TUInt64); +{* ʮֽھȸнλָЧֻ֣ Extended Ϊ 16 ֽ + Ҹʽ IEEE 754-2008 ıȸʱЧĿǰ Delphi ָ֧øʽ + עָΪʵָЧ 112 λΪߵ֡ + + + Value: Extended - ⿪ʮֽھȸ + out SignNegative: Boolean - λTrue Ϊ + out Exponent: Integer - ָ + out MantissaLo: TUInt64 - Чֵ 64 λ + out MantissaHi: TUInt64 - Чָ 64 λ + + ֵޣ +} + +procedure CombineFloatSingle(SignNegative: Boolean; Exponent: Integer; + Mantissa: Cardinal; var Value: Single); +{* ѷλָЧƴɵȸ + + + SignNegative: Boolean - λTrue Ϊ + Exponent: Integer - ָ + Mantissa: Cardinal - Ч + var Value: Single - ϵĵȸ + + ֵޣ +} + +procedure CombineFloatDouble(SignNegative: Boolean; Exponent: Integer; + Mantissa: TUInt64; var Value: Double); +{* ѷλָЧƴ˫ȸ + + + SignNegative: Boolean - λTrue Ϊ + Exponent: Integer - ָ + Mantissa: TUInt64 - Ч + var Value: Double - ϵ˫ȸ + + ֵޣ +} + +procedure CombineFloatExtended(SignNegative: Boolean; Exponent: Integer; + Mantissa: TUInt64; var Value: Extended); +{* ѷλָЧƴչȸ֧ 10 ֽڡ + Լ 16 ֽڽضΪ 10 ֽڵ Extended ʽ + + + SignNegative: Boolean - λTrue Ϊ + Exponent: Integer - ָ + Mantissa: TUInt64 - Ч + var Value: Extended - ϵչȸ + + ֵޣ + +} + +procedure CombineFloatQuadruple(SignNegative: Boolean; Exponent: Integer; + MantissaLo: TUInt64; MantissaHi: TUInt64; var Value: Extended); +{* ѷλָЧƴչȸֻ Extended Ϊ 16 ֽ + Ҹʽ IEEE 754-2008 ıȸʱЧĿǰ Delphi ָ֧øʽ + + + SignNegative: Boolean - λTrue Ϊ + Exponent: Integer - ָ + MantissaLo: TUInt64 - Чֵ 64 λ + MantissaHi: TUInt64 - Чָ 64 λ + var Value: Extended - ϵʮֽھȸ + + ֵޣ +} + +function UInt64ToSingle(U: TUInt64): Single; +{* Int64 зģ 64 λ޷͸ֵ Singleʵͬ + + + U: TUInt64 - ֵ 64 λ޷ֵ + + ֵSingle - صĵȸ +} + +function UInt64ToDouble(U: TUInt64): Double; +{* Int64 зģ 64 λ޷͸ֵ Doubleʵͬ + + + U: TUInt64 - ֵ 64 λ޷ֵ + + ֵDouble - ص˫ȸ +} + +function UInt64ToExtended(U: TUInt64): Extended; +{* Int64 зģ 64 λ޷͸ֵ Extendedʵͬ + + + U: TUInt64 - ֵ 64 λ޷ֵ + + ֵExtended - صչȸ +} + +function SingleToUInt64(F: Single): TUInt64; +{* Single ֵ Int64 зģ 64 λ޷ͣʵͬ + + + F: Single - ֵĵȸ + + ֵTUInt64 - ص 64 λ޷ֵ +} + +function DoubleToUInt64(F: Double): TUInt64; +{* Double ֵ Int64 зģ 64 λ޷ͣʵͬ + + + F: Double - ֵ˫ȸ + + ֵTUInt64 - ص 64 λ޷ֵ +} + +function ExtendedToUInt64(F: Extended): TUInt64; +{* Extended ֵ Int64 зģ 64 λ޷ͣʵͬ + + + F: Extended - ֵ˫ȸ + + ֵTUInt64 - ص 64 λ޷ֵ +} + +function SingleIsInfinite(AValue: Single): Boolean; +{* ȸǷ + + + AValue: Single - жϵĵȸ + + ֵBoolean - Ƿ +} + +function DoubleIsInfinite(AValue: Double): Boolean; +{* ˫ȸǷ + + + AValue: Double - жϵ˫ȸ + + ֵBoolean - Ƿ +} + +function ExtendedIsInfinite(AValue: Extended): Boolean; +{* չȸǷ + + + AValue: Extended - жϵչȸ + + ֵBoolean - Ƿ +} + +function SingleIsNan(AValue: Single): Boolean; +{* ȸǷʵ + + + AValue: Single - жϵĵȸ + + ֵBoolean - Ƿʵ +} + +function DoubleIsNan(AValue: Double): Boolean; +{* ˫ȸǷʵ + + + AValue: Double - жϵ˫ȸ + + ֵBoolean - Ƿʵ +} + +function ExtendedIsNan(AValue: Extended): Boolean; +{* չȸǷʵ + + + AValue: Extended - жϵչȸ + + ֵBoolean - Ƿʵ +} + +// FPCWindows 64/Linux 64 ƽ̨Լ Delphi 56 ֧ +{$IFDEF WIN32} +{$IFDEF COMPILER7_UP} + +{ FloatDecimalToBinExtended, FloatDecimalToOctExtendedFloatDecimalToHexExtended + FloatDecimalToBinaryExtended ̣FloatDecimalToBinaryExtended } + +function FloatDecimalToBinExtended(fIn: Extended; DecimalExp: Boolean; + AlwaysUseExponent: Boolean): AnsiString; // Convert to binary + +function FloatDecimalToOctExtended(fIn: Extended; DecimalExp: Boolean; + AlwaysUseExponent: Boolean): AnsiString; // Convert to octal + +function FloatDecimalToHexExtended(fIn: Extended; DecimalExp: Boolean; + AlwaysUseExponent: Boolean): AnsiString; // Convert to hexdecimal + +{$ENDIF} +{$ENDIF} + +implementation + +const + UINT64_EXTENDED_EXP_MAX = $4040; // UINT64 Ӧ Extended ָ + +resourcestring + SCN_ERROR_EXTENDED_SIZE = 'Extended Size Error'; + +type + TExtendedRec10 = packed record + {* 10 ֽڵչȸֻ Win32 Ч} + Mantissa: TUInt64; + ExpSign: Word; + end; + PExtendedRec10 = ^TExtendedRec10; + +{$IFDEF WIN32} +{$IFDEF COMPILER7_UP} + +type + PConvertFloatSystem = ^TConvertFloatSystem; + TConvertFloatSystem = record + Negative: Boolean; + ExpFlag, ExponentI: Integer; + end; + +const + MaxBinDigits = 120; + MaxHexDigits = 30; + MaxOctDigits = 40; + +function FloatDecimalToBinaryExtended(fIn: Extended; DecimalExp, + AlwaysUseExponent: Boolean; var ForHexOct: PConvertFloatSystem): AnsiString; +var + Neg: Boolean; + i, Flag, IntExp: Integer; + Exp: AnsiString; +label UseExponent; +begin +{ +Extended(32.125) in memory: +0 100000000000100 10000000 10000000 00000000 00000000 00000000 00000000 00000000 00000000 + 9 8 7 6 5 4 3 2nd Byte 1stByte 0 +sign exponent digits +0 111111111111111 1000000000000000000000000000000000000000000000000000000000000000 + Inf +1 111111111111111 1000000000000000000000000000000000000000000000000000000000000000 - Inf +1 111111111111111 1100000000000000000000000000000000000000000000000000000000000000 Nan +0 111111111111111 1100000000000000000000000000000000000000000000000000000000000000 -Nan +} + SetLength(Result, 255); + SetLength(Exp, 2 * SizeOf(Extended) + 1); + Neg := False; + asm + push EBX + push ESI + mov EBX, Result // Address of Result + mov EBX, [EBX] + mov EAX, 0 + // Test if fIN equals 0 + lea ESI, fIn[7] // get the first byte of digits + mov AL, [ESI] + test AL, 128 // 10000000B + jz @Zero + mov ECX, 0 + lea ESI, fIn[8] + mov AX, [ESI] // Get first two bytes + test AX, 32768 // 32768D = 1000000000000000B + jz @Positive + mov Neg, 1 + sub AX, 32768 // Sign bit <- 0 + @Positive: + // Test if fIn is NaN or Infinity + cmp AX, 32767 + jnz @NotNAN_INF + mov DL, [ESI - 1] + test DL, 64 // 01000000B + jz @INF + mov Flag, 4 // NaN + jmp @Done + @INF: + mov Flag, 3 // INF + jmp @Done + @NotNAN_INF: + sub AX, 16383 // AX = AX - 011111111111111B + jns @ExpPositive + sub AX, 1 + not AX + mov Flag, 2 // // Exponent sign negative + jmp @JudgeDecimalExp + @ExpPositive: + mov Flag, 1 // Exponent sign positive + @JudgeDecimalExp: + mov IntExp, EAX + cmp DecimalExp, 1 + je @MoveDigits + // Binary string exponent. Convert AX to binary string and store it in Exp + lea EBX, Exp + mov EBX, [EBX] + push ECX + mov [EBX], 69 // 'E' // "D" for decimal exponent + mov ECX, 1 + cmp Flag, 2 + jnz @NoNegativeInExp + mov [EBX + 1], 45 // '-' // Add a "-" to exponent string + mov ECX, 2 + @NoNegativeInExp: + mov ESI, 0 // flag whehter "1" appears + // Move exponent digits to Exp + mov DX, 32768 // 1000000000000000 + @NextExpDigit: + test AX, DX + jz @AppendExp0 + mov [EBX + ECX], 49 // '1' + mov ESI, 1 + jmp @NextExpIncECX + @AppendExp0: + cmp ESI, 0 + jz @NextExpNoIncECX // do not append this "0" + mov [EBX + ECX], 48 // '0' + @NextExpIncECX: + inc ECX + @NextExpNoIncECX: + shr DX, 1 + cmp DX, 0 + jne @NextExpDigit + pop ECX + mov EBX, Result + mov EBX, [EBX] + jmp @MoveDigits + @MoveDigits: + // Move digits to Result + mov ESI, 8 + @NextByte: + dec ESI + mov EAX, EBX + lea EBX, fIn[ESI] + mov DL, [EBX] + mov EBX, EAX + mov AL, 128 // 10000000 + @NextDigit: + test DL, AL + jz @Append0 + mov [EBX + ECX], 49 // '1' + mov i, ECX + jmp @Next + @Append0: + mov [EBX + ECX], 48 // '0' + @Next: + inc ECX + shr AL, 1 + cmp AL, 0 + jne @NextDigit + cmp ESI, 0 // if the last byte + jne @NextByte + jmp @Done + @Zero: + mov Flag, 0 + @Done: + pop ESI + pop EBX + end; + case Flag of + 0: + begin + ForHexOct := nil; + Result := '0'; + Exit; + end; + 1, 2: + begin + // Delete redundant "0" in Result + Delete(Result, i + 2, MaxInt); // i stores the position of the last 1 in Result + if Assigned(ForHexOct) then + begin + // Copy to ForHexOct + with ForHexOct^ do + begin + Negative := Neg; + ExpFlag := Flag; + ExponentI := IntExp; + end; + Exit; + end; + // Add dot and exponent to Result + if (IntExp = 0) then + begin + if (Length(Result) > 1) then + Insert('.', Result, 2); + end + else + begin + { Decide whether use exponent. For example "1000.101" shouldn't be output + as 1.000101E11 when AlwaysUseExponent is False. } + if AlwaysUseExponent then + begin +UseExponent: + if DecimalExp then + if Flag = 1 then + Exp := 'D' + {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(IntExp)) + else + Exp := 'D-' + {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(IntExp)); + if Length(Result) >=2 then + Insert('.', Result, 2); + Result := Result + Exp; + end + else + begin + // IntExp may be negative. + if Flag = 1 then + begin + // Calculate all digits required without exponent + if IntExp <= Length(Result) - 2 then + begin + // Do not use exponent + Insert('.', Result, IntExp + 2); + end + else if IntExp = Length(Result) - 1 then + { 1.001, Exp = 3, output 1001 } + else + begin + if IntExp + 1> MaxBinDigits then + goto UseExponent + else + begin + Inc(IntExp); + i := Length(Result); + // Add zeros at tail + SetLength(Result, IntExp); + for i := i + 1 to IntExp do + Result := '0'; + end; + end; + end + else + begin + if IntExp + Length(Result) > MaxBinDigits then + goto UseExponent + else + begin + // Add leading zeros and place "." + SetLength(Exp, 1 + IntExp); + Exp[1] := '0'; + Exp[2] := '.'; + for i := 3 to IntExp + 1 do + Exp := '0'; //} + Result := Exp + Result; + end; + end; + end; + end; + end; + 3: // INF + begin + ForHexOct := nil; + Result := 'INF'; + end; + 4: // NaN + begin + ForHexOct := nil; + Result := 'NaN'; + Exit; + end; + end; + if Neg then + Result := '-' + Result; +end; + +function FloatDecimalToBinExtended(fIn: Extended; DecimalExp, + AlwaysUseExponent: Boolean): AnsiString; +var + PTmp: PConvertFloatSystem; +begin + PTmp := nil; + Result := FloatDecimalToBinaryExtended(fIn, DecimalExp, AlwaysUseExponent, PTmp); +end; + +function FloatDecimalToHexExtended(fIn: Extended; DecimalExp, + AlwaysUseExponent: Boolean): AnsiString; +const + DecToHex: array[0..15] of AnsiChar = + ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); + BinPow: array[0..3] of Integer = (8, 4, 2, 1); + + function IntToHex(Int: Integer): AnsiString; + var + k ,t: Integer; + Buf: array[1..5] of AnsiChar; + begin + k := 1; + while (Int <> 0) do + begin + Buf[k] := DecToHex[Int mod 16]; + Inc(k); + Int := Int div 16; + end; + Dec(k); + SetLength(Result, k); + t := 1; + while (k > 0) do + begin + Result[t] := Buf[k]; + Inc(t); + Dec(k); + end; + end; + + function ToHex(const S: AnsiString; LeftToDot: Boolean): AnsiString; + var + i, l, t, m, k: Integer; + Buf: array[1..20] of AnsiChar; + begin + { LeftToDot = True, S will be patched with zeroes on its left side. + For example, S = '110', after patching, S = '0110'. + LeftToDot = False, S will be patched with zeroes on its right side. + S = '110', after patching, S = '1100'. } + l := Length(S); + if LeftToDot then + t := (4 - (l mod 4)) mod 4 + else + t := 0; + i := 1; + m := 1; + k := 0; + while i <= l do + begin + k := k + BinPow[t] * (Ord(S[i]) - Ord('0')); + Inc(t); + if (t = 4) or (i = l) then + begin + Buf[m] := DecToHex[k]; + Inc(m); + k := 0; + t := 0; + end; + Inc(i); + end; + Dec(m); + SetLength(Result, m); + + while (m > 0) do + begin + Result[m] := Buf[m]; + Dec(m); + end; + end; + +var + PConvertData: PConvertFloatSystem; + ConvertData: TConvertFloatSystem; + tmpS: AnsiString; + k, t, i, m: Integer; +label UseExponent; +begin + PConvertData := @ConvertData; + Result := FloatDecimalToBinaryExtended(fIn, True, True, PConvertData); + // See FloatDecimalToBinaryExtended, PConvertData is set to nil when result is definite. + if PConvertData = nil then + Exit; + with ConvertData do + begin + { 3.BD^D(12) + A.BD^E(ABCE) + AB.FFFF } + k := Length(Result) - 1; + if AlwaysUseExponent then + begin +UseExponent: + { Algorithm: + X.XXXXXXXX^Y Shift Count Exp + 1.00000001^0 = 1.00000001 = 1.01^0 (16) + 1.00000001^1 = 10.0000001 = 2.02^0 (16) + 1.00000001^2 = 100.000001 = 4.04^0 (16) + 1.00000001^3 = 1000.00001 = 8.08^0 (16) + 1.00000001^4 = 1.00000001^100 = 1.01^1 (16) + 1.00000001^5 = 10.0000001^100 = 2.02^1 (16) + Shift Count = Y mod 4 + Exp = Y div 4 + X.XXXXXXXXX^Y Y < 0 Exp + 1.00000001^-1 = 0.100000001 = 1000.00001^-100 = 8.08^-1 + 1.00000001^-2 = 0.0100000001 = 100.000001^-100 = 4.04^-1 + 1.00000001^-3 = 0.00100000001 = 10.0000001^-100 = 2.02^-1 + 1.00000001^-4 = 0.000100000001 = 1.00000001^-100 = 1.01^-1 + 1.00000001^-5 = 0.0000100000001 = 1000.00001^-100 = 8.08^-2 + Shift Count = 4 - (Abs(Y) mod 4) + Exp = -(Abs(Y) div 4 + 1) } + if ExpFlag = 1 then + begin + t := ExponentI div 4; // Exp + i := ExponentI mod 4; // Shift Count + end + else + begin + t := -((ExponentI - 1) div 4 + 1); // Exp + i := (4 - (ExponentI mod 4)) mod 4; // Shift Count + end; + // Get hex digits + if k < i then + begin + // Add extra zeroes + SetLength(Result, i + 1); + for m := k + 2 to i + 1 do + Result[m] := '0'; + Result := ToHex(Result, True); + end + else if k = i then + Result := ToHex(Result, True) + else + begin + tmpS := Copy(Result, 1, i + 1); + Delete(Result, 1, i + 1); + Result := ToHex(tmpS, True) + '.' + ToHex(Result, False); + end; + if t <> 0 then + begin + // Format exponent + if DecimalExp then + Result := Result + '^D(' + {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(t)) + ')' + else + begin + if ExpFlag = 1 then + Result := Result + '^E(' + IntToHex(t) + ')' + else // t < 0 + Result := Result + '^E(-' + IntToHex(-t) + ')'; + end; + end; + end + else + begin + { Always remember that Result equals "XXXXXXXX" not "X.XXXXXXX". + Judge whether to use exponent: + There are K "X" after '.', K = Length(Result) - 1, no "." in Result originally. + X.XXXXXXX^Y (Binary string, ExponentI = Abs(Y)) + case Y >= 0 (Condition: ExpFlag = 2) + Y <= K: + Y+1 binary digits on left side of '.', K-Y digits on right side + totally requires ((Y+1 - 1) div 4 + 1) + ((K-Y - 1) div 4 + 1) hex digits + Y > K: + Y+1 binary digits on left side, totally ((Y+1 - 1) div 4 + 1) hex digits + case Y<0 (Condition: ExpFlag = 1) 0.XXXX or 0.000XXXX + One digit '0' on left side and K+1+Abs(Y)-1 digits on right side, + totally 1 + ((K+1+Abs(Y)-1-1) div 4 + 1) hex digits. + Compare hdc = hex digit count with MaxHexDigits. If hdc > MaxHexDigits, + goto UseExponent. } + if ExponentI = 0 then + begin + if (Length(Result) > 1) then + Result := '1.' + ToHex(Copy(Result, 2, MaxInt), False); + end + else + begin + if ExpFlag = 1 then + begin + if ExponentI < k then + begin + // No possible that "ExponentI div 4 + (k - ExponentI - 1) div 4 + 2" > MaxHexDigits + tmpS := Copy(Result, 1, ExponentI + 1); + Delete(Result, 1, ExponentI + 1); + Result := ToHex(tmpS, True) + '.' + ToHex(Result, False); + end + else if ExponentI = k then + // 1.01^2 = 101, no ".", no extra "0". + Result := ToHex(Result, True) + else + begin + t := ExponentI div 4 + 1; + if t > MaxHexDigits then + goto UseExponent + else + begin + // Append "0" after Result + Inc(ExponentI); + // Add '0' to Result + SetLength(Result, ExponentI); + for t := k + 2{original Length(Result) + 1} to ExponentI do + Result[t] := '0'; + Result := ToHex(Result, True); + end; + end; + end + else + begin + // ExpFlag = 2, X.XXXXXXX^Y, Y < 0 + t := 2 + (k + ExponentI - 1) div 4; {1 + ((K+1+Abs(Y)-1-1) div 4 + 1)} + if t > MaxHexDigits then + goto UseExponent + else + begin + // Add leading zeroes before Result + SetLength(tmpS, ExponentI - 1); // tmpS stores extra zeroes + for t := 1 to ExponentI - 1 do + tmpS[t] := '0'; + Result := '0.' + ToHex(tmpS + Result, False); + end; + end; + end; + end; + if Negative then + Result := '-' + Result; + end; +end; + +function FloatDecimalToOctExtended(fIn: Extended; DecimalExp, + AlwaysUseExponent: Boolean): AnsiString; +const + DecToOct: array[0..7] of AnsiChar = + ('0', '1', '2', '3', '4', '5', '6', '7'); + BinPow: array[0..2] of Integer = (4, 2, 1); + + function IntToOct(Int: Integer): AnsiString; + var + k ,t: Integer; + Buf: array[1..10] of AnsiChar; + begin + k := 1; + while (Int <> 0) do + begin + Buf[k] := DecToOct[Int mod 8]; + Inc(k); + Int := Int div 8; + end; + Dec(k); + SetLength(Result, k); + t := 1; + while (k > 0) do + begin + Result[t] := Buf[k]; + Inc(t); + Dec(k); + end; + end; + + function ToOct(const S: AnsiString; LeftToDot: Boolean): AnsiString; + var + i, l, t, m, k: Integer; + Buf: array[1..30] of AnsiChar; + begin + { LeftToDot = True, S will be patched with zeroes on its left side. + For example, S = '110', after patching, S = '0110'. + LeftToDot = False, S will be patched with zeroes on its right side. + S = '110', after patching, S = '1100'. } + l := Length(S); + if LeftToDot then + t := (3 - (l mod 3)) mod 3 + else + t := 0; + i := 1; + m := 1; + k := 0; + while i <= l do + begin + k := k + BinPow[t] * (Ord(S[i]) - Ord('0')); + Inc(t); + if (t = 3) or (i = l) then + begin + Buf[m] := DecToOct[k]; + Inc(m); + k := 0; + t := 0; + end; + Inc(i); + end; + Dec(m); + SetLength(Result, m); + + while (m > 0) do + begin + Result[m] := Buf[m]; + Dec(m); + end; + end; + +var + PConvertData: PConvertFloatSystem; + ConvertData: TConvertFloatSystem; + tmpS: AnsiString; + k, t, i, m: Integer; +label UseExponent; +begin + PConvertData := @ConvertData; + Result := FloatDecimalToBinaryExtended(fIn, True, True, PConvertData); + // See FloatDecimalToBinaryExtended, PConvertData is set to nil when result is definite. + if PConvertData = nil then + Exit; + with ConvertData do + begin + { 3.333D12 // 12 is decimal + 2.22E33 // 33 is octal} + k := Length(Result) - 1; + if AlwaysUseExponent then + begin +UseExponent: + if ExpFlag = 1 then + begin + t := ExponentI div 3; // Exp + i := ExponentI mod 3; // Shift Count + end + else + begin + t := -((ExponentI - 1) div 3 + 1); // Exp + i := (3 - (ExponentI mod 3)) mod 3; // Shift Count + end; + // Get hex digits + if k < i then + begin + // Add extra zeroes + SetLength(Result, i + 1); + for m := k + 2 to i + 1 do + Result[m] := '0'; + Result := ToOct(Result, True); + end + else if k = i then + Result := ToOct(Result, True) + else + begin + tmpS := Copy(Result, 1, i + 1); + Delete(Result, 1, i + 1); + Result := ToOct(tmpS, True) + '.' + ToOct(Result, False); + end; + if t <> 0 then + begin + // Format exponent + if DecimalExp then + Result := Result + 'D' + {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(t)) + else + begin + if ExpFlag = 1 then + Result := Result + 'E' + IntToOct(t) + else // t < 0 + Result := Result + 'E-' + IntToOct(-t); + end; + end; + end + else + begin + if ExponentI = 0 then + begin + if (Length(Result) > 1) then + Result := '1.' + ToOct(Copy(Result, 2, MaxInt), False); + end + else + begin + if ExpFlag = 1 then + begin + if ExponentI < k then + begin + tmpS := Copy(Result, 1, ExponentI + 1); + Delete(Result, 1, ExponentI + 1); + Result := ToOct(tmpS, True) + '.' + ToOct(Result, False); + end + else if ExponentI = k then + // 1.01^2 = 101, no ".", no extra "0". + Result := ToOct(Result, True) + else + begin + t := ExponentI div 3 + 1; + if t > MaxHexDigits then + goto UseExponent + else + begin + // Append "0" after Result + Inc(ExponentI); + // Add '0' to Result + SetLength(Result, ExponentI); + for t := k + 2{original Length(Result) + 1} to ExponentI do + Result[t] := '0'; + Result := ToOct(Result, True); + end; + end; + end + else + begin + // ExpFlag = 2, X.XXXXXXX^Y, Y < 0 + t := 2 + (k + ExponentI - 1) div 3; + if t > MaxHexDigits then + goto UseExponent + else + begin + // Add leading zeroes before Result + SetLength(tmpS, ExponentI - 1); // tmpS stores extra zeroes + for t := 1 to ExponentI - 1 do + tmpS[t] := '0'; + Result := '0.' + ToOct(tmpS + Result, False); + end; + end; + end; + end; + if Negative then + Result := '-' + Result; + end; +end; + +{$ENDIF} +{$ENDIF} + +procedure ExtractFloatSingle(Value: Single; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: Cardinal); +begin + SignNegative := (PCardinal(@Value)^ and CN_SIGN_SINGLE_MASK) <> 0; + Exponent := ((PCardinal(@Value)^ and CN_EXPONENT_SINGLE_MASK) shr 23) - CN_EXPONENT_OFFSET_SINGLE; + Mantissa := PCardinal(@Value)^ and CN_SIGNIFICAND_SINGLE_MASK; + Mantissa := Mantissa or (1 shl 23); // λټӸ 1 +end; + +procedure ExtractFloatDouble(Value: Double; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: TUInt64); +begin + SignNegative := (PUInt64(@Value)^ and CN_SIGN_DOUBLE_MASK) <> 0; + Exponent := ((PUInt64(@Value)^ and CN_EXPONENT_DOUBLE_MASK) shr 52) - CN_EXPONENT_OFFSET_DOUBLE; + Mantissa := PUInt64(@Value)^ and CN_SIGNIFICAND_DOUBLE_MASK; + Mantissa := Mantissa or (TUInt64(1) shl 52); // λټӸ 1 +end; + +procedure ExtractFloatExtended(Value: Extended; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: TUInt64); +begin + if (SizeOf(Extended) = CN_EXTENDED_SIZE_10) or (SizeOf(Extended) = CN_EXTENDED_SIZE_16) then + begin + SignNegative := (PExtendedRec10(@Value)^.ExpSign and CN_SIGN_EXTENDED_MASK) <> 0; + Exponent := (PExtendedRec10(@Value)^.ExpSign and CN_EXPONENT_EXTENDED_MASK) - CN_EXPONENT_OFFSET_EXTENDED; + Mantissa := PExtendedRec10(@Value)^.Mantissa; // 1ü + end + else if SizeOf(Extended) = CN_EXTENDED_SIZE_8 then + ExtractFloatDouble(Value, SignNegative, Exponent, Mantissa) + else + raise ECnFloatSizeError.Create(SCN_ERROR_EXTENDED_SIZE); +end; + +procedure ExtractFloatQuadruple(Value: Extended; out SignNegative: Boolean; + out Exponent: Integer; out MantissaLo, MantissaHi: TUInt64); +begin + if SizeOf(Extended) <> CN_EXTENDED_SIZE_16 then + raise ECnFloatSizeError.Create(SCN_ERROR_EXTENDED_SIZE); + + SignNegative := (PCnQuadruple(@Value)^.W1 and CN_SIGN_QUADRUPLE_MASK) <> 0; + Exponent := (PCnQuadruple(@Value)^.W1 and CN_EXPONENT_QUADRUPLE_MASK) - CN_EXPONENT_OFFSET_EXTENDED; + + // Extract 16 Bytes to Mantissas + MantissaLo := PCnQuadruple(@Value)^.Lo; + MantissaHi := TUInt64(PCnQuadruple(@Value)^.Hi0) or (TUInt64(PCnQuadruple(@Value)^.W0) shl 32) or (TUInt64(1) shl 48); // λټӸ 1 +end; + +procedure CombineFloatSingle(SignNegative: Boolean; Exponent: Integer; + Mantissa: Cardinal; var Value: Single); +begin + Mantissa := Mantissa and not (1 shl 23); // ȥ 23 λϵ 1еĻ + PCardinal(@Value)^ := Mantissa and CN_SIGNIFICAND_SINGLE_MASK; + Inc(Exponent, CN_EXPONENT_OFFSET_SINGLE); + + PCardinal(@Value)^ := PCardinal(@Value)^ or (LongWord(Exponent) shl 23); + if SignNegative then + PCardinal(@Value)^ := PCardinal(@Value)^ or CN_SIGN_SINGLE_MASK + else + PCardinal(@Value)^ := PCardinal(@Value)^ and not CN_SIGN_SINGLE_MASK; +end; + +procedure CombineFloatDouble(SignNegative: Boolean; Exponent: Integer; + Mantissa: TUInt64; var Value: Double); +begin + Mantissa := Mantissa and not (TUInt64(1) shl 52); // ȥ 52 λϵ 1еĻ + PUInt64(@Value)^ := Mantissa and CN_SIGNIFICAND_DOUBLE_MASK; + Inc(Exponent, CN_EXPONENT_OFFSET_DOUBLE); + + PUInt64(@Value)^ := PUInt64(@Value)^ or (TUInt64(Exponent) shl 52); + if SignNegative then + PUInt64(@Value)^ := PUInt64(@Value)^ or CN_SIGN_DOUBLE_MASK + else + PUInt64(@Value)^ := PUInt64(@Value)^ and not CN_SIGN_DOUBLE_MASK; +end; + +{$HINTS OFF} + +procedure CombineFloatExtended(SignNegative: Boolean; Exponent: Integer; + Mantissa: TUInt64; var Value: Extended); +var + D: Double; +begin + if (SizeOf(Extended) = CN_EXTENDED_SIZE_10) or (SizeOf(Extended) = CN_EXTENDED_SIZE_16) then + begin + PExtendedRec10(@Value)^.Mantissa := Mantissa; + Inc(Exponent, CN_EXPONENT_OFFSET_EXTENDED); + + PExtendedRec10(@Value)^.ExpSign := Exponent and CN_EXPONENT_EXTENDED_MASK; + if SignNegative then + PExtendedRec10(@Value)^.ExpSign := PExtendedRec10(@Value)^.ExpSign or CN_SIGN_EXTENDED_MASK + else + PExtendedRec10(@Value)^.ExpSign := PExtendedRec10(@Value)^.ExpSign and not CN_SIGN_EXTENDED_MASK; + end + else if SizeOf(Extended) = CN_EXTENDED_SIZE_8 then + begin + CombineFloatDouble(SignNegative, Exponent, Mantissa, D); + Value := D; + end + else + raise ECnFloatSizeError.Create(SCN_ERROR_EXTENDED_SIZE); +end; + +{$HINTS ON} + +procedure CombineFloatQuadruple(SignNegative: Boolean; Exponent: Integer; + MantissaLo, MantissaHi: TUInt64; var Value: Extended); +begin + if SizeOf(Extended) <> CN_EXTENDED_SIZE_16 then + raise ECnFloatSizeError.Create(SCN_ERROR_EXTENDED_SIZE); + + MantissaHi := MantissaHi and not (TUInt64(1) shl 48); // ȥ 112 λϵ 1еĻ + PCnQuadruple(@Value)^.Lo := MantissaLo; + PCnQuadruple(@Value)^.Hi0 := Cardinal(MantissaHi and $FFFFFFFF); + PCnQuadruple(@Value)^.Hi1 := (MantissaHi shr 32) and CN_SIGNIFICAND_QUADRUPLE_MASK; + + Inc(Exponent, CN_EXPONENT_OFFSET_EXTENDED); + PCnQuadruple(@Value)^.W1 := Exponent and CN_EXPONENT_QUADRUPLE_MASK; + if SignNegative then + PCnQuadruple(@Value)^.Hi1 := PCnQuadruple(@Value)^.Hi1 or CN_SIGN_QUADRUPLE_MASK + else + PCnQuadruple(@Value)^.Hi1 := PCnQuadruple(@Value)^.Hi1 and not CN_SIGN_QUADRUPLE_MASK; +end; + +// UInt64 Ϊ +function UFloat(U: TUInt64): Extended; +{$IFNDEF SUPPORT_UINT64} +var + L, H: Cardinal; +{$ENDIF} +begin +{$IFDEF SUPPORT_UINT64} + Result := U; +{$ELSE} + if U < 0 then // Int64 С 0 ʱ UInt64 Ǵ Int64 ֵ + begin + H := Int64Rec(U).Hi; + L := Int64Rec(U).Lo; + Result := Int64(H) * Int64(CN_MAX_UINT16 + 1); // + Result := Result * (CN_MAX_UINT16 + 1); + Result := Result + L; + end + else + Result := U; +{$ENDIF} +end; + +function UInt64ToSingle(U: TUInt64): Single; +begin + Result := UFloat(U); +end; + +function UInt64ToDouble(U: TUInt64): Double; +begin + Result := UFloat(U); +end; + +function UInt64ToExtended(U: TUInt64): Extended; +begin + Result := UFloat(U); +end; + +// ͨ Trunc ֻܷ Int64 UInt64 +function UTrunc(F: Extended): TUInt64; +var + T: Integer; + SignNeg: Boolean; + Exponent: Integer; + Mantissa: TUInt64; +begin + // õʵָ 1 ͷЧ֣С 1 + ExtractFloatExtended(F, SignNeg, Exponent, Mantissa); + if SignNeg then + raise ERangeError.Create(SRangeError); // ֧ + + // Mantissa 64 λЧ֣С 63 λָС 0 ˵СҪƣôֵ 0 + if Exponent < 0 then + Result := 0 + else + begin + // С Exponent λСߵ + T := 63 - Exponent; // С 0 63 λ 63 λұߣСƺ T λұ + if T < 0 then + raise ERangeError.Create(SRangeError); // Exponent ̫ + + Result := Mantissa shr T; + end; +end; + +function SingleToUInt64(F: Single): TUInt64; +begin + Result := UTrunc(F); +end; + +function DoubleToUInt64(F: Double): TUInt64; +begin + Result := UTrunc(F); +end; + +function ExtendedToUInt64(F: Extended): TUInt64; +begin + Result := UTrunc(F); +end; + +function SingleIsInfinite(AValue: Single): Boolean; +begin + Result := ((PCardinal(@AValue)^ and $7F800000) = $7F800000) and + ((PCardinal(@AValue)^ and $007FFFFF) = $00000000); +end; + +function DoubleIsInfinite(AValue: Double): Boolean; +begin + Result := ((PUInt64(@AValue)^ and $7FF0000000000000) = $7FF0000000000000) and + ((PUInt64(@AValue)^ and $000FFFFFFFFFFFFF) = $0000000000000000); +end; + +function ExtendedIsInfinite(AValue: Extended): Boolean; +begin + if SizeOf(Extended) = CN_EXTENDED_SIZE_10 then + Result := ((PExtendedRec10(@AValue)^.ExpSign and $7FFF) = $7FFF) and + ((PExtendedRec10(@AValue)^.Mantissa) = 0) + else if SizeOf(Extended) = CN_EXTENDED_SIZE_8 then + Result := DoubleIsInfinite(AValue) + else + raise ECnFloatSizeError.Create(SCN_ERROR_EXTENDED_SIZE); +end; + +function SingleIsNan(AValue: Single): Boolean; +begin + Result := ((PCardinal(@AValue)^ and $7F800000) = $7F800000) and + ((PCardinal(@AValue)^ and $007FFFFF) <> $00000000); +end; + +function DoubleIsNan(AValue: Double): Boolean; +begin + Result := ((PUInt64(@AValue)^ and $7FF0000000000000) = $7FF0000000000000) and + ((PUInt64(@AValue)^ and $000FFFFFFFFFFFFF) <> $0000000000000000); +end; + +function ExtendedIsNan(AValue: Extended): Boolean; +begin + if SizeOf(Extended) = CN_EXTENDED_SIZE_10 then + Result := ((PExtendedRec10(@AValue)^.ExpSign and $7FFF) = $7FFF) and + ((PExtendedRec10(@AValue)^.Mantissa and $7FFFFFFFFFFFFFFF) <> 0) + else if SizeOf(Extended) = CN_EXTENDED_SIZE_8 then + Result := DoubleIsNan(AValue) + else + raise ECnFloatSizeError.Create(SCN_ERROR_EXTENDED_SIZE); +end; + +end. diff --git a/CnPack/Crypto/CnKDF.dcu b/CnPack/Crypto/CnKDF.dcu new file mode 100644 index 0000000000000000000000000000000000000000..ab8a24ef0bda87b06579270c031782ff29ce117e GIT binary patch literal 13854 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

GjU1lO-!A@MOz*mL zk-Gj!-RqIMz67tk4skxc*I|n>dmVNPQe>KCjM`HsD%@3flg^&Dvi^!w+b8c};+RtI?`sDq~mozdF9E(z)B^q_;Pr50Yd@w&7R z8H$M3nEMFY0*=QnVorAJx|L{6Fg+< z7;|^UJ08+Il8Fbf3+yXbx}voM`Q>wuO{fDM?E@KY7bev66Yeu@KZvR#T%)~!64hci z79&rggoBMp<3FI2(lEa6_=6Mf-t^9qaT4Ykg0e)E6~1C})eE=5R;yH2iT5g85?0WXyV2pxeT?4D8&@ zvvpo)4{iR!L8QS9&iLOaEn4FCP4aa3@0175PT|@ z;lQyp9#Ohu;fU@&ZZy>M*Qo<-dAr-+WNo>)k5rx>Q26=5inSTp^Ok_RrsI`?l9+m& zugS$L66HYW*@QDE)FGZ|`qMkNAjXYF?FGg}LmKfiXb64Cg~T!FGQvE#gsbj3(~U$# z%YT?Ek;BLN`xJlo@b?-1?&a@S=`HR9JRG}JpsQ{4BMs}BW0bWilt@Q9+UILkXGeR6 zR&~%J_bwbdoa`=s)NRL!fV7(2Cr0fl9#q(~Po3x(mDBJ25IJySap#Lzu%F|h9f>^k zA3MTxoM%DRz5ihiXWndY?7o&uQjA_O~?dh=4sVNc5(aBhj0t>FT2nr1g zzHig897SdVJ&xr9>|fi)g?_g&CK)@?%XoXR^Ic@F{D4q}z)^!;FjCp95E3taBKW zlkG(`j826K*Tqs{EY3|d7M-0bM$HhYJp}?zZ^iJ9>Cz}&E_cn0su{S}#FHs9o#RKc z183cHR?&B8+7xWJs^= zS6Gl-%zK6XI`v%o{p2d~DL*Wxd^4sO!m|(0V|ZS`(~n0x9uDw*nd`}}0Cn1ROq=gC|#35~lGT;1ZghXDFj035(G zjE5!TA2smg;DKLZ=J@DISozDieVf}?$8?h#B8y|4nkfy^tXQXJLY;(D0{j$9DB_4K z7oh`*eeUxmU3N*wmwvAn1TDa`7tc{Vr}3P}lWZgF33TxwAmzfkA_xq=76b;Lff|L12g^1VLN`L12g^1c4!GQh&v<>_1YZ--XuuI3FT+} zob43n>~rFrjpIZ75pm;#fgpI83i0df~7W!ROF;4bThM>`~qaC+JzI zLsX|g4EfZ=91$M~aSA^liqS+*e9(-%CMaC(5K`O#9(;tUp2Nda9zNDYK%Ljqr*ZJI z0c{N59ZbHbsgCJR-*3>Ttadhmq`=rq9am9dc?p@3&6+dK*JIGle`aZA{GSQ&4ac_M z!|_L%Ji1yQUCTaU@+Yh1Pu8+ACXcO_$ExtHmOQ>(9&ce5d>3VrT(TlLP>N@_O}5$O zRGYlZCfjZDOq=Ym$+K;8hE1MllbtsCPMds(O}=Y6!xwDmxdc6J@{U}VhGxjd=89s0 zD6*xEY=v}#yg~{n`3_~(Y-PDaxpuy?e4etZSSg>U6fKq)NU6%|OsGj!x>A*j`AX$t zWz|Am+^H;|sT9pq4pk^cmCEvkdVTFQGS5M#l*`Olo?E9Bg#Wd%! z1J(lhfHhy|AFvt*!RkF}El^&wI`ECbwGhZ)uc6)OkYBUrDw`KiUMVL*KWohdd(s$Z z0qv}A$|(r70T)6%+C@5EQOSh;qo^4Ln{vDMRZo>{3pGlf&3T)Rr?E>gOu=bS83PEOBxai#Ji zmNYS7H3!O5ii(95DnyY#4Sbps%#))$1{cdwp2<))7bxBQeUiUl+;N#+OO+yo#Y+8e z-Q~p~Q>6bby^Pp=rN~9@s{Q3EMQbl3`Ppa-&?~{QGuci#2Tmvcwtqc}-eP$*aeIaLK=P$a%N5w#pBo3^$|9cy8q=T?)I{Cn%D-*cb}? z{cIe??4#HXP&$W@*HNy%iKR$M605Kwv7?Q0E|qI-Yyp+)Z4CbwE3u7~-%-|B>?}r= zXKE#6QB- +================================================================================ +* ƣ +* ԪƣԿ㷨KDFԪ +* ԪߣCnPack (master@cnpack.org) +* עԪʵ˻ RFC2898 PBKDF1 PBKDF2 Կ㷨 PBKDF1 ֧ MD2 㷨 +* ͬʱҲʵ˻ RFC5869 HKDF HMac Կ㷨 +* SM2/SM9 㷨й涨㷨 +* ƽ̨WinXP + Delphi 5.0 +* ݲԣδ +* õԪ豾ػ +* ޸ļ¼2025.01.09 V1.5 +* HKDF ʵֺ +* 2022.06.21 V1.4 +* ϲһֽ CnSM2SM9KDF AnsiString ڸ߰汾 Delphi ¿ +* 2022.04.26 V1.3 +* ޸ LongWord Integer ַת֧ MacOS64 +* 2022.01.02 V1.2 +* CnPBKDF2 һԼ Unicode µļ +* 2021.11.25 V1.1 +* CnSM2KDF Unicode µļ +* 2020.03.30 V1.0 +* Ԫ CnPemUtils ж +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes, CnNative, CnMD5, CnSHA1, CnSHA2, CnSHA3, CnSM3; + +type + TCnKeyDeriveHash = (ckdMd5, ckdSha256, ckdSha1); + {* CnGetDeriveKey ʹõӴշ} + + TCnPBKDF1KeyHash = (cpdfMd2, cpdfMd5, cpdfSha1); + {* PBKDF1 涨Ӵշ MD2 Dz֧} + + TCnPBKDF2KeyHash = (cpdfSha1Hmac, cpdfSha256Hmac); + {* PBKDF2 涨Ӵշ} + + TCnHKDFHash = (chkMd5, chkSha1, chkSha256, chkSha3_256, chkSm3); + {* HKDFHMAC-based Key Derivation Functionֵ֧Ӵ} + + ECnKDFException = class(Exception); + {* KDF 쳣} + +function CnGetDeriveKey(const Password: AnsiString; const Salt: AnsiString; + OutKey: PAnsiChar; KeyLength: Cardinal; KeyHash: TCnKeyDeriveHash = ckdMd5): Boolean; +{* Openssl е BytesToKeyָӴ㷨ɼ Key + Ŀǰ KeyLength ֧ HashҲ MD5 32 ֽڣSHA256 64 ֽڡ + + + const Password: AnsiString - + const Salt: AnsiString - ֵ + OutKey: PAnsiChar - Կݿַ + KeyLength: Cardinal - Կݿֽڳ + KeyHash: TCnKeyDeriveHash - Ӵ㷨 + + ֵBoolean - Ƿɳɹ +} + +function CnPBKDF1(const Password: AnsiString; const Salt: AnsiString; Count: Integer; + DerivedKeyByteLength: Integer; KeyHash: TCnPBKDF1KeyHash = cpdfMd5): AnsiString; +{* Password Based KDF 1 ʵ֣򵥵Ĺ̶Ӵյֻ֧ MD5 SHA1뷵ֵΪ AnsiString + DerivedKeyByteLength Կֽȹ̶ + + + const Password: AnsiString - + const Salt: AnsiString - ֵ + Count: Integer - + DerivedKeyByteLength: Integer - ɵԿֽڳ + KeyHash: TCnPBKDF1KeyHash - Ӵ㷨 + + ֵAnsiString - ɵԿ +} + +function CnPBKDF2(const Password: AnsiString; const Salt: AnsiString; Count: Integer; + DerivedKeyByteLength: Integer; KeyHash: TCnPBKDF2KeyHash = cpdfSha1Hmac): AnsiString; +{* Password Based KDF 2 ʵ֣ HMAC-SHA1 HMAC-SHA256뷵ֵΪ AnsiString + DerivedKeyByteLength Կֽȿɱ䣬 + + + const Password: AnsiString - + const Salt: AnsiString - ֵ + Count: Integer - + DerivedKeyByteLength: Integer - ɵԿֽڳ + KeyHash: TCnPBKDF2KeyHash - Ӵ㷨 + + ֵAnsiString - ɵԿ +} + +function CnPBKDF1Bytes(const Password: TBytes; const Salt: TBytes; Count: Integer; + DerivedKeyByteLength: Integer; KeyHash: TCnPBKDF1KeyHash = cpdfMd5): TBytes; +{* Password Based KDF 1 ʵ֣򵥵Ĺ̶Ӵյֻ֧ MD5 SHA1뷵ֵΪֽ顣 + DerivedKeyByteLength Կֽȹ̶ + + + const Password: TBytes - + const Salt: TBytes - ֵ + Count: Integer - + DerivedKeyByteLength: Integer - ɵԿֽڳ + KeyHash: TCnPBKDF1KeyHash - Ӵ㷨 + + ֵTBytes - ɵԿ +} + +function CnPBKDF2Bytes(const Password: TBytes; const Salt: TBytes; Count: Integer; + DerivedKeyByteLength: Integer; KeyHash: TCnPBKDF2KeyHash = cpdfSha1Hmac): TBytes; +{* Password Based KDF 2 ʵ֣ HMAC-SHA1 HMAC-SHA256뷵ֵΪֽ顣 + DerivedKeyByteLength Կֽȿɱ䣬 + + + const Password: TBytes - + const Salt: TBytes - ֵ + Count: Integer - + DerivedKeyByteLength: Integer - ɵԿֽڳ + KeyHash: TCnPBKDF2KeyHash - Ӵ㷨 + + ֵTBytes - ɵԿ +} + +// ============ SM2/SM9 й涨ͬһԿַװʵ =============== + +function CnSM2KDF(const Data: AnsiString; DerivedKeyByteLength: Integer): AnsiString; +{* SM2 Բ߹Կ㷨й涨ԿDerivedKeyLength Կֽ + AnsiStringͬʱƺҲû SharedInfo ANSI-X9.63-KDF + + + const Data: AnsiString - Կԭʼݣ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵAnsiString - ɵԿ +} + +function CnSM9KDF(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): AnsiString; +{* SM9 ʶ㷨й涨ԿDerivedKeyLength Կֽ + AnsiStringͬʱƺҲû SharedInfo ANSI-X9.63-KDF + + + Data: Pointer - Կԭʼݿַ + DataByteLen: Integer - Կԭʼݵֽڳ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵAnsiString - ɵԿ +} + +function CnSM2KDFBytes(const Data: TBytes; DerivedKeyByteLength: Integer): TBytes; +{* Ϊֽʽ SM2 Բ߹Կ㷨й涨Կ + DerivedKeyLength Կֽɵֽ顣 + + + const Data: TBytes - Կԭʼݵֽ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +function CnSM9KDFBytes(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): TBytes; +{* Ϊڴʽ SM9 ʶ㷨й涨Կ + DerivedKeyLength Կֽɵֽ顣 + + + Data: Pointer - Կԭʼݿַ + DataByteLen: Integer - Կԭʼݵֽڳ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +function CnSM2SM9KDF(Data: TBytes; DerivedKeyByteLength: Integer): TBytes; overload; +{* Ϊֽʽ SM2 Բ߹Կ㷨 SM9 ʶ㷨й涨Կ + DerivedKeyLength ԿֽɵԿֽ顣 + + + Data: TBytes - Կԭʼݵֽ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +function CnSM2SM9KDF(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): TBytes; overload; +{* Ϊڴʽ SM2 Բ߹Կ㷨 SM9 ʶ㷨й涨Կ + DerivedKeyLength ԿֽԿֽ顣 + + + Data: Pointer - Կԭʼݿַ + DataByteLen: Integer - Կԭʼݵֽڳ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +function CnHKDF(HKDF: TCnHKDFHash; IKM: Pointer; IKMByteLen: Integer; + Salt: Pointer; SaltByteLen: Integer; Info: Pointer; InfoByteLen: Integer; + DerivedKeyByteLength: Integer): TBytes; overload; +{* HMAC KDF Կ IKMSalt InfoָȵԿ + Salt Ϊգڲʹù̶Ӵսȵȫ 0Info ΪաɵԿ + + + HKDF: TCnHKDFHash - Ӵ㷨 + IKM: Pointer - ԿݣInput Keying Materialַ + IKMByteLen: Integer - Կݵֽڳ + Salt: Pointer - Կֵݿַ + SaltByteLen: Integer - Կֵݵֽڳ + Info: Pointer - ԿĿѡϢݿַ + InfoByteLen: Integer - ԿĿѡϢݵֽڳ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +function CnHKDFBytes(HKDF: TCnHKDFHash; IKM: TBytes; Salt: TBytes; Info: TBytes; + DerivedKeyByteLength: Integer): TBytes; overload; +{* HMAC KDF Կ IKMSalt Info ֽ飬ָȵԿ + Salt Ϊգڲʹù̶Ӵսȵȫ 0Info ΪաɵԿ + + HKDF: TCnHKDFHash - Ӵ㷨 + IKM: TBytes - Կ + Salt: TBytes - Կֵ + Info: TBytes - ԿĿѡϢ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +implementation + +resourcestring + SCnErrorKDFKeyTooLong = 'Derived Key Too Long.'; + SCnErrorKDFParam = 'Invalid Parameters.'; + SCnErrorKDFHashNOTSupport = 'Hash Method NOT Support.'; + +function Min(A, B: Integer): Integer; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + if A < B then + Result := A + else + Result := B; +end; + +function CnGetDeriveKey(const Password, Salt: AnsiString; OutKey: PAnsiChar; KeyLength: Cardinal; + KeyHash: TCnKeyDeriveHash): Boolean; +var + Md5Dig, Md5Dig2: TCnMD5Digest; + Sha256Dig, Sha256Dig2: TCnSHA256Digest; + SaltBuf, PS, PSMD5, PSSHA256: AnsiString; +begin + Result := False; + + if (Password = '') or (OutKey = nil) or (KeyLength < 8) then + Exit; + + SetLength(SaltBuf, 8); + FillChar(SaltBuf[1], Length(SaltBuf), 0); + if Salt <> '' then + Move(Salt[1], SaltBuf[1], Min(Length(Salt), 8)); + + if not (KeyHash in [ckdMd5, ckdSha256]) then + raise ECnKDFException.Create(SCnErrorKDFHashNOTSupport); + + PS := AnsiString(Password) + SaltBuf; // 涨ǰ 8 ֽΪ Salt + if KeyHash = ckdMd5 then + begin + SetLength(PSMD5, SizeOf(TCnMD5Digest) + Length(PS)); + Move(PS[1], PSMD5[SizeOf(TCnMD5Digest) + 1], Length(PS)); + Md5Dig := MD5StringA(PS); + // Salt ƴ MD5 16 ByteΪһ + + Move(Md5Dig[0], OutKey^, Min(KeyLength, SizeOf(TCnMD5Digest))); + if KeyLength <= SizeOf(TCnMD5Digest) then + begin + Result := True; + Exit; + end; + + KeyLength := KeyLength - SizeOf(TCnMD5Digest); + OutKey := PAnsiChar(TCnNativeInt(OutKey) + SizeOf(TCnMD5Digest)); + + Move(Md5Dig[0], PSMD5[1], SizeOf(TCnMD5Digest)); + Md5Dig2 := MD5StringA(PSMD5); + Move(Md5Dig2[0], OutKey^, Min(KeyLength, SizeOf(TCnMD5Digest))); + if KeyLength <= SizeOf(TCnMD5Digest) then + Result := True; + + // KeyLength ̫㲻 + end + else if KeyHash = ckdSha256 then + begin + SetLength(PSSHA256, SizeOf(TCnSHA256Digest) + Length(PS)); + Move(PS[1], PSSHA256[SizeOf(TCnSHA256Digest) + 1], Length(PS)); + Sha256Dig := SHA256StringA(PS); + // Salt ƴ SHA256 32 ByteΪһ + + Move(Sha256Dig[0], OutKey^, Min(KeyLength, SizeOf(TCnSHA256Digest))); + if KeyLength <= SizeOf(TCnSHA256Digest) then + begin + Result := True; + Exit; + end; + + KeyLength := KeyLength - SizeOf(TCnSHA256Digest); + OutKey := PAnsiChar(TCnNativeInt(OutKey) + SizeOf(TCnSHA256Digest)); + + Move(Sha256Dig[0], PSSHA256[1], SizeOf(TCnSHA256Digest)); + Sha256Dig2 := SHA256StringA(PSSHA256); + Move(Sha256Dig2[0], OutKey^, Min(KeyLength, SizeOf(TCnSHA256Digest))); + if KeyLength <= SizeOf(TCnSHA256Digest) then + Result := True; + + // KeyLength ̫㲻 + end; +end; + +(* + T_1 = Hash (P || S) , + T_2 = Hash (T_1) , + ... + T_c = Hash (T_{c-1}) , + DK = Tc<0..dkLen-1> +*) +function CnPBKDF1(const Password, Salt: AnsiString; Count, DerivedKeyByteLength: Integer; + KeyHash: TCnPBKDF1KeyHash): AnsiString; +var + P, S, Res: TBytes; +begin + P := AnsiToBytes(Password); + S := AnsiToBytes(Salt); + Res := CnPBKDF1Bytes(P, S, Count, DerivedKeyByteLength, KeyHash); + Result := BytesToAnsi(Res); +end; + +{ + DK = T1 + T2 + ... + Tdklen/hlen + Ti = F(Password, Salt, c, i) + + F(Password, Salt, c, i) = U1 ^ U2 ^ ... ^ Uc + + U1 = PRF(Password, Salt + INT_32_BE(i)) + U2 = PRF(Password, U1) + ... + Uc = PRF(Password, Uc-1) +} +function CnPBKDF2(const Password, Salt: AnsiString; Count, DerivedKeyByteLength: Integer; + KeyHash: TCnPBKDF2KeyHash): AnsiString; +var + P, S, Res: TBytes; +begin + P := AnsiToBytes(Password); + S := AnsiToBytes(Salt); + Res := CnPBKDF2Bytes(P, S, Count, DerivedKeyByteLength, KeyHash); + Result := BytesToAnsi(Res); +end; + +function CnPBKDF1Bytes(const Password, Salt: TBytes; Count, DerivedKeyByteLength: Integer; + KeyHash: TCnPBKDF1KeyHash = cpdfMd5): TBytes; +var + I: Integer; + Md5Dig, TM: TCnMD5Digest; + Sha1Dig, TS: TCnSHA1Digest; + Ptr: PAnsiChar; +begin + Result := nil; + if (Password = nil) or (Count <= 0) or (DerivedKeyByteLength <= 0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + case KeyHash of + cpdfMd5: + begin + if DerivedKeyByteLength > SizeOf(TCnMD5Digest) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + SetLength(Result, DerivedKeyByteLength); + Md5Dig := MD5Bytes(ConcatBytes(Password, Salt)); // Got T1 + if Count > 1 then + begin + Ptr := PAnsiChar(@TM[0]); + for I := 2 to Count do + begin + TM := Md5Dig; + Md5Dig := MD5Buffer(Ptr, SizeOf(TCnMD5Digest)); // Got T_c + end; + end; + + Move(Md5Dig[0], Result[0], DerivedKeyByteLength); + end; + cpdfSha1: + begin + if DerivedKeyByteLength > SizeOf(TCnSHA1Digest) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + SetLength(Result, DerivedKeyByteLength); + Sha1Dig := SHA1Bytes(ConcatBytes(Password, Salt)); // Got T1 + if Count > 1 then + begin + Ptr := PAnsiChar(@TS[0]); + for I := 2 to Count do + begin + TS := Sha1Dig; + Sha1Dig := SHA1Buffer(Ptr, SizeOf(TCnSHA1Digest)); // Got T_c + end; + end; + + Move(Sha1Dig[0], Result[0], DerivedKeyByteLength); + end; + else + raise ECnKDFException.Create(SCnErrorKDFHashNOTSupport); + end; +end; + +function CnPBKDF2Bytes(const Password, Salt: TBytes; Count, DerivedKeyByteLength: Integer; + KeyHash: TCnPBKDF2KeyHash = cpdfSha1Hmac): TBytes; +var + HLen, D, I, J, K: Integer; + Sha1Dig1, Sha1Dig, T1: TCnSHA1Digest; + Sha256Dig1, Sha256Dig, T256: TCnSHA256Digest; + S, S1, S256, Pad: TBytes; + PAddr: Pointer; +begin + Result := nil; + if (Salt = nil) or (Count <= 0) or (DerivedKeyByteLength <=0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + if (Password = nil) or (Length(Password) = 0) then + PAddr := nil + else + PAddr := @Password[0]; + + case KeyHash of + cpdfSha1Hmac: + HLen := 20; + cpdfSha256Hmac: + HLen := 32; + else + raise ECnKDFException.Create(SCnErrorKDFParam); + end; + + D := (DerivedKeyByteLength div HLen) + 1; + SetLength(S1, SizeOf(TCnSHA1Digest)); + SetLength(S256, SizeOf(TCnSHA256Digest)); + + SetLength(Pad, 4); + if KeyHash = cpdfSha1Hmac then + begin + for I := 1 to D do + begin + Pad[0] := I shr 24; + Pad[1] := I shr 16; + Pad[2] := I shr 8; + Pad[3] := I; + S := ConcatBytes(Salt, Pad); + + SHA1Hmac(PAddr, Length(Password), PAnsiChar(@S[0]), Length(S), Sha1Dig1); + T1 := Sha1Dig1; + + for J := 2 to Count do + begin + SHA1Hmac(PAddr, Length(Password), PAnsiChar(@T1[0]), SizeOf(TCnSHA1Digest), Sha1Dig); + T1 := Sha1Dig; + for K := Low(TCnSHA1Digest) to High(TCnSHA1Digest) do + Sha1Dig1[K] := Sha1Dig1[K] xor T1[K]; + end; + + Move(Sha1Dig1[0], S1[0], Length(S1)); + Result := ConcatBytes(Result, S1); + end; + Result := Copy(Result, 0, DerivedKeyByteLength); + end + else if KeyHash = cpdfSha256Hmac then + begin + for I := 1 to D do + begin + Pad[0] := I shr 24; + Pad[1] := I shr 16; + Pad[2] := I shr 8; + Pad[3] := I; + S := ConcatBytes(Salt, Pad); + + SHA256Hmac(PAddr, Length(Password), PAnsiChar(@S[0]), Length(S), Sha256Dig1); + T256 := Sha256Dig1; + + for J := 2 to Count do + begin + SHA256Hmac(PAddr, Length(Password), PAnsiChar(@T256[0]), SizeOf(TCnSHA256Digest), Sha256Dig); + T256 := Sha256Dig; + for K := Low(TCnSHA256Digest) to High(TCnSHA256Digest) do + Sha256Dig1[K] := Sha256Dig1[K] xor T256[K]; + end; + + Move(Sha256Dig1[0], S256[0], SizeOf(TCnSHA256Digest)); + Result := ConcatBytes(Result, S256); + end; + Result := Copy(Result, 0, DerivedKeyByteLength); + end; +end; + +function CnSM2KDF(const Data: AnsiString; DerivedKeyByteLength: Integer): AnsiString; +var + Res: TBytes; +begin + if (Data = '') or (DerivedKeyByteLength <= 0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + Res := CnSM2SM9KDF(@Data[1], Length(Data), DerivedKeyByteLength); + Result := BytesToAnsi(Res); +end; + +function CnSM9KDF(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): AnsiString; +var + Res: TBytes; +begin + Res := CnSM2SM9KDF(Data, DataByteLen, DerivedKeyByteLength); + Result := BytesToAnsi(Res); +end; + +function CnSM2KDFBytes(const Data: TBytes; DerivedKeyByteLength: Integer): TBytes; +begin + Result := CnSM2SM9KDF(Data, DerivedKeyByteLength); +end; + +function CnSM9KDFBytes(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): TBytes; +begin + Result := CnSM2SM9KDF(Data, DataByteLen, DerivedKeyByteLength); +end; + +function CnSM2SM9KDF(Data: TBytes; DerivedKeyByteLength: Integer): TBytes; +begin + if (Data = nil) or (Length(Data) <= 0) or (DerivedKeyByteLength <= 0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + Result := CnSM2SM9KDF(@Data[0], Length(Data), DerivedKeyByteLength); +end; + +function CnSM2SM9KDF(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): TBytes; overload; +var + DArr: TBytes; + CT, SCT: Cardinal; + I, CeilLen: Integer; + IsInt: Boolean; + SM3D: TCnSM3Digest; +begin + Result := nil; + if (Data = nil) or (DataByteLen <= 0) or (DerivedKeyByteLength <= 0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + DArr := nil; + CT := 1; + + try + SetLength(DArr, DataByteLen + SizeOf(Cardinal)); + Move(Data^, DArr[0], DataByteLen); + + IsInt := DerivedKeyByteLength mod SizeOf(TCnSM3Digest) = 0; + CeilLen := (DerivedKeyByteLength + SizeOf(TCnSM3Digest) - 1) div SizeOf(TCnSM3Digest); + + SetLength(Result, DerivedKeyByteLength); + for I := 1 to CeilLen do + begin + SCT := UInt32HostToNetwork(CT); // Ȼĵû˵Ҫһ + Move(SCT, DArr[DataByteLen], SizeOf(Cardinal)); + SM3D := SM3(@DArr[0], Length(DArr)); + + if (I = CeilLen) and not IsInt then + begin + // һ 32 ʱֻƶһ + Move(SM3D[0], Result[(I - 1) * SizeOf(TCnSM3Digest)], (DerivedKeyByteLength mod SizeOf(TCnSM3Digest))); + end + else + Move(SM3D[0], Result[(I - 1) * SizeOf(TCnSM3Digest)], SizeOf(TCnSM3Digest)); + + Inc(CT); + end; + finally + SetLength(DArr, 0); + end; +end; + +function CnHKDF(HKDF: TCnHKDFHash; IKM: Pointer; IKMByteLen: Integer; + Salt: Pointer; SaltByteLen: Integer; Info: Pointer; InfoByteLen: Integer; + DerivedKeyByteLength: Integer): TBytes; +const + MAX_BYTE = 255; +var + PRKMd5, Md5T: TCnMD5Digest; + PRKSha1, Sha1T: TCnSHA1Digest; + PRKSha256, Sha256T: TCnSHA256Digest; + PRKSha3256, Sha3256T: TCnSHA3_256Digest; + PRKSm3, Sm3T: TCnSM3Digest; + T0, T: TBytes; + N, I, Start, HashLen: Integer; +begin + if IKM = nil then + IKMByteLen := 0; + + if Salt = nil then + SaltByteLen := 0; + + if Info = nil then + InfoByteLen := 0; + + if (IKMByteLen < 0) or (SaltByteLen < 0) or (InfoByteLen < 0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + // Extract HMac(Salt, IKM)ע IKM ݣ HMac Key + case HKDF of + chkMd5: + begin + if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnMD5Digest)) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + HashLen := SizeOf(TCnMD5Digest); + if (Salt = nil) or (SaltByteLen <= 0) then + begin + FillChar(PRKMd5[0], HashLen, 0); + MD5Hmac(@PRKMd5[0], HashLen, IKM, IKMByteLen, PRKMd5); + end + else + MD5Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKMd5); + end; + chkSha1: + begin + if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnSHA1Digest)) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + HashLen := SizeOf(TCnSHA1Digest); + if (Salt = nil) or (SaltByteLen <= 0) then + begin + FillChar(PRKSha1[0], HashLen, 0); + SHA1Hmac(@PRKSha1[0], HashLen, IKM, IKMByteLen, PRKSha1); + end + else + SHA1Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKSha1); + end; + chkSha256: + begin + if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnSHA256Digest)) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + HashLen := SizeOf(TCnSHA256Digest); + if (Salt = nil) or (SaltByteLen <= 0) then + begin + FillChar(PRKSha256[0], HashLen, 0); + SHA256Hmac(@PRKSha256[0], HashLen, IKM, IKMByteLen, PRKSha256); + end + else + SHA256Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKSha256); + end; + chkSha3_256: + begin + if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnSHA3_256Digest)) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + HashLen := SizeOf(TCnSHA3_256Digest); + if (Salt = nil) or (SaltByteLen <= 0) then + begin + FillChar(PRKSha3256[0], HashLen, 0); + SHA3_256Hmac(@PRKSha3256[0], HashLen, IKM, IKMByteLen, PRKSha3256); + end + else + SHA3_256Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKSha3256); + end; + chkSm3: + begin + if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnSM3Digest)) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + HashLen := SizeOf(TCnSM3Digest); + if (Salt = nil) or (SaltByteLen <= 0) then + begin + FillChar(PRKSm3[0], HashLen, 0); + SM3Hmac(@PRKSm3[0], HashLen, IKM, IKMByteLen, PRKSm3); + end + else + SM3Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKSm3); + end; + else + raise ECnKDFException.Create(SCnErrorKDFHashNOTSupport); + end; + + // ʼ Expand + SetLength(T0, InfoByteLen + 1); + if InfoByteLen > 0 then + Move(Info^, T0[0], InfoByteLen); + T0[InfoByteLen] := 1; // ƴװ T0 + + // ʼÿֵļ + SetLength(T, HashLen + InfoByteLen + 1); + + // ýȲ + N := (DerivedKeyByteLength + HashLen - 1) div HashLen; + SetLength(Result, DerivedKeyByteLength); + + // T0 һ T1 + case HKDF of + chkMd5: MD5Hmac(@PRKMd5[0], HashLen, @T0[0], Length(T0), Md5T); + chkSha1: SHA1Hmac(@PRKSha1[0], HashLen, @T0[0], Length(T0), Sha1T); + chkSha256: SHA256Hmac(@PRKSha256[0], HashLen, @T0[0], Length(T0), Sha256T); + chkSha3_256: SHA3_256Hmac(@PRKSha3256[0], HashLen, @T0[0], Length(T0), Sha3256T); + chkSm3: SM3Hmac(@PRKSm3[0], HashLen, @T0[0], Length(T0), Sm3T); + end; + + Start := 0; + for I := 1 to N do + begin + // T1 ƴڽ + if DerivedKeyByteLength > HashLen then + begin + case HKDF of + chkMd5: Move(Md5T[0], Result[Start], HashLen); + chkSha1: Move(Sha1T[0], Result[Start], HashLen); + chkSha256: Move(Sha256T[0], Result[Start], HashLen); + chkSha3_256: Move(Sha3256T[0], Result[Start], HashLen); + chkSm3: Move(Sm3T[0], Result[Start], HashLen); + end; + Inc(Start, HashLen); + Dec(DerivedKeyByteLength, HashLen); + end + else + begin + case HKDF of + chkMd5: Move(Md5T[0], Result[Start], DerivedKeyByteLength); + chkSha1: Move(Sha1T[0], Result[Start], DerivedKeyByteLength); + chkSha256: Move(Sha256T[0], Result[Start], DerivedKeyByteLength); + chkSha3_256: Move(Sha3256T[0], Result[Start], DerivedKeyByteLength); + chkSm3: Move(Sm3T[0], Result[Start], DerivedKeyByteLength); + end; + Break; + end; + + // T1 Info ƴһ𲢼һ + case HKDF of + chkMd5: Move(Md5T[0], T[0], HashLen); + chkSha1: Move(Sha1T[0], T[0], HashLen); + chkSha256: Move(Sha256T[0], T[0], HashLen); + chkSha3_256: Move(Sha3256T[0], T[0], HashLen); + chkSm3: Move(Sm3T[0], T[0], HashLen); + end; + Move(Info^, T[HashLen], InfoByteLen); + T[HashLen + InfoByteLen] := I + 1; + + // Ӵ T2 T1 + case HKDF of + chkMd5: MD5Hmac(@PRKMd5[0], HashLen, @T[0], Length(T), Md5T); + chkSha1: SHA1Hmac(@PRKSha1[0], HashLen, @T[0], Length(T), Sha1T); + chkSha256: SHA256Hmac(@PRKSha256[0], HashLen, @T[0], Length(T), Sha256T); + chkSha3_256: SHA3_256Hmac(@PRKSha3256[0], HashLen, @T[0], Length(T), Sha3256T); + chkSm3: SM3Hmac(@PRKSm3[0], HashLen, @T[0], Length(T), Sm3T); + end; + end; +end; + +function CnHKDFBytes(HKDF: TCnHKDFHash; IKM: TBytes; Salt: TBytes; Info: TBytes; + DerivedKeyByteLength: Integer): TBytes; +var + IKMP, SaltP, InfoP: Pointer; + IKML, SaltL, InfoL: Integer; +begin + IKMP := nil; + SaltP := nil; + InfoP := nil; + IKML := 0; + SaltL := 0; + InfoL := 0; + + if Length(IKM) > 0 then + begin + IKMP := @IKM[0]; + IKML := Length(IKM); + end; + if Length(Salt) > 0 then + begin + SaltP := @Salt[0]; + SaltL := Length(Salt); + end; + if Length(Info) > 0 then + begin + InfoP := @Info[0]; + InfoL := Length(Info); + end; + + Result := CnHKDF(HKDF, IKMP, IKML, SaltP, SaltL, InfoP, InfoL, DerivedKeyByteLength); +end; + +end. diff --git a/CnPack/Crypto/CnMD5.dcu b/CnPack/Crypto/CnMD5.dcu new file mode 100644 index 0000000000000000000000000000000000000000..cb8d6620407415739e0d60166eaf5935ca4734ae GIT binary patch literal 15598 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 WtWPF_AP}eC1XBtgT&1reuKxu#%R$fp literal 0 HcmV?d00001 diff --git a/CnPack/Crypto/CnMD5.pas b/CnPack/Crypto/CnMD5.pas new file mode 100644 index 0000000..e859993 --- /dev/null +++ b/CnPack/Crypto/CnMD5.pas @@ -0,0 +1,884 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2025 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +{******************************************************************************} +{ } +{ MD5 Message-Digest for Delphi 4 } +{ } +{ Delphi 4 Unit implementing the } +{ RSA Data Security, Inc. MD5 Message-Digest Algorithm } +{ } +{ Implementation of Ronald L. Rivest's RFC 1321 } +{ } +{ Copyright ?1997-1999 Medienagentur Fichtner & Meyer } +{ Written by Matthias Fichtner } +{ } +{ -----------------------------------------------------------------------------} +{ See RFC 1321 for RSA Data Security's copyright and license notice! } +{ -----------------------------------------------------------------------------} +{ The latest release of md5.pas will always be available from } +{ the distribution site at: http://www.fichtner.net/delphi/md5/ } +{ -----------------------------------------------------------------------------} +{ Please send questions, bug reports and suggestions } +{ regarding this code to: mfichtner@fichtner-meyer.com } +{ -----------------------------------------------------------------------------} +{ This code is provided "as is" without express or } +{ implied warranty of any kind. Use it at your own risk. } +{******************************************************************************} + +unit CnMD5; +{* |

+================================================================================
+* ƣ
+* ԪƣMD5 Ӵ㷨ʵֵԪ
+* Ԫߣ壨QSoft hq.com@263.net; http://qsoft.51.net
+*            Ronald L. Rivest  MD5.pas дԭʼ
+*     עԪʵ MD5 Ӵ㷨Ӧ HMAC 㷨
+* ƽ̨PWin2000Pro + Delphi 5.0
+* ݲԣPWin9X/2000/XP + Delphi 5/6
+*   õԪеַϱػʽ
+* ޸ļ¼2019.12.12 V1.4
+*               ֧ TBytes
+*           2019.04.15 V1.3
+*               ֧ Win32/Win64/MacOS
+*           2014.11.14 V1.2
+*               л Pascal ֿ֧ƽ̨
+*           2003.09.18 V1.1
+*               òҵ˸õԪԭߵİȨ
+*           2003.09.18 V1.0
+*               Ԫ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + Classes, SysUtils, CnConsts, CnNative {$IFDEF MSWINDOWS}, Windows {$ENDIF}; + +type + PMD5Digest = ^TCnMD5Digest; + TCnMD5Digest = array[0..15] of Byte; + {* MD5 Ӵս16 ֽ} + + TCnMD5Count = array[0..1] of Cardinal; + TCnMD5State = array[0..3] of Cardinal; + TCnMD5Block = array[0..15] of Cardinal; + + TCnMD5Buffer = array[0..63] of Byte; + + TCnMD5Context = record + {* MD5 Ľṹ} + State : TCnMD5State; + Count : TCnMD5Count; + Buffer : TCnMD5Buffer; + Ipad : array[0..63] of Byte; {!< HMAC: inner padding } + Opad : array[0..63] of Byte; {!< HMAC: outer padding } + end; + + TCnMD5CalcProgressFunc = procedure (ATotal, AProgress: Int64; + var Cancel: Boolean) of object; + {* Ȼص¼} + +//---------------------------------------------------------------- +// û API +//---------------------------------------------------------------- + +function MD5(Input: PAnsiChar; ByteLength: Cardinal): TCnMD5Digest; +{* ݿ MD5 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5Buffer(const Buffer; Count: Cardinal): TCnMD5Digest; +{* ݿ MD5 㡣 + + + const Buffer - ݿַ + Count: Cardinal - ݿֽڳ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5Bytes(Data: TBytes): TCnMD5Digest; +{* ֽ MD5 㡣 + + + Data: TBytes - ֽ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5String(const Str: string): TCnMD5Digest; +{* String ݽ MD5 㡣ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + + const Str: string - ַ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5StringA(const Str: AnsiString): TCnMD5Digest; +{* AnsiString ݽ MD5 㣬ֱӼڲݣޱ봦 + + + const Str: AnsiString - ַ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5StringW(const Str: WideString): TCnMD5Digest; +{* WideString ַת MD5 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +{$IFDEF UNICODE} + +function MD5UnicodeString(const Str: string): TCnMD5Digest; +{* UnicodeString ݽֱӵ MD5 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +{$ELSE} + +function MD5UnicodeString(const Str: WideString ): TCnMD5Digest; +{* UnicodeString ݽֱӵ MD5 㣬ֱӼڲ UTF16 ݣת + + + + const Str: WideString - Ŀַ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +{$ENDIF} + +function MD5File(const FileName: string; + CallBack: TCnMD5CalcProgressFunc = nil): TCnMD5Digest; +{* ָļݽ MD5 㡣 + + + const FileName: string - ļ + CallBack: TCnMD5CalcProgressFunc - ȻصĬΪ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5Stream(Stream: TStream; + CallBack: TCnMD5CalcProgressFunc = nil): TCnMD5Digest; +{* ָݽ MD5 㡣 + + + Stream: TStream - + CallBack: TCnMD5CalcProgressFunc - ȻصĬΪ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +// ⲿݽɢ MD5 㣬MD5Update ɶα + +procedure MD5Init(var Context: TCnMD5Context); +{* ʼһ MD5 ģ׼ MD5 + + + var Context: TCnMD5Context - ʼ MD5 + + ֵޣ +} + +procedure MD5Update(var Context: TCnMD5Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ MD5 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnMD5Context - MD5 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure MD5Final(var Context: TCnMD5Context; var Digest: TCnMD5Digest); +{* ּ㣬 MD5 Digest С + + + var Context: TCnMD5Context - MD5 + var Digest: TCnMD5Digest - ص MD5 Ӵֵ + + ֵޣ +} + +function MD5Print(const Digest: TCnMD5Digest): string; +{* ʮƸʽ MD5 Ӵֵ + + + const Digest: TCnMD5Digest - ָ MD5 Ӵֵ + + ֵstring - ʮַ +} + +function MD5Match(const D1: TCnMD5Digest; const D2: TCnMD5Digest): Boolean; +{* Ƚ MD5 ӴֵǷȡ + + + const D1: TCnMD5Digest - Ƚϵ MD5 Ӵֵһ + const D2: TCnMD5Digest - Ƚϵ MD5 Ӵֵ + + ֵBoolean - Ƿ +} + +function MD5DigestToStr(const Digest: TCnMD5Digest): string; +{* MD5 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnMD5Digest - ת MD5 Ӵֵ + + ֵstring - صַ +} + +procedure MD5Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnMD5Digest); +{* MD5 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - MD5 Կݿַ + KeyByteLength: Integer - MD5 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnMD5Digest - ص MD5 Ӵֵ + + ֵޣ +} + +implementation + +const + MAX_FILE_SIZE = 512 * 1024 * 1024; + // If file size <= this size (bytes), using Mapping, else stream + + HMAC_MD5_BLOCK_SIZE_BYTE = 64; + HMAC_MD5_OUTPUT_LENGTH_BYTE = 16; + +type + TMD5CBits = array[0..7] of Byte; + +var + PADDING: TCnMD5Buffer = ( + $80, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00 + ); + +function F(X, y, z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and y) or ((not X) and z); +end; + +function G(X, y, z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and z) or (y and (not z)); +end; + +function H(X, y, z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor y xor z; +end; + +function I(X, y, z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := y xor (X or (not z)); +end; + +procedure ROT(var X: Cardinal; N: BYTE); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + X := (X shl N) or (X shr (32 - N)); +end; + +procedure FF(var A: Cardinal; B, C, D, X: Cardinal; S: BYTE; AC: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Inc(A, F(B, C, D) + X + AC); + ROT(A, S); + Inc(A, B); +end; + +procedure GG(var A: Cardinal; B, C, D, X: Cardinal; S: BYTE; AC: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Inc(A, G(B, C, D) + X + AC); + ROT(A, S); + Inc(A, B); +end; + +procedure HH(var A: Cardinal; B, C, D, X: Cardinal; S: BYTE; AC: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Inc(A, H(B, C, D) + X + AC); + ROT(A, S); + Inc(A, B); +end; + +procedure II(var A: Cardinal; B, C, D, X: Cardinal; S: BYTE; AC: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Inc(A, I(B, C, D) + X + AC); + ROT(A, S); + Inc(A, B); +end; + +// Encode Count bytes at Source into (Count / 4) DWORDs at Target +procedure Encode(Source, Target: Pointer; Count: Cardinal); +var + S: PByte; + T: PCardinal; + I: Cardinal; +begin + S := Source; + T := Target; + for I := 1 to Count div 4 do + begin + T^ := S^; + Inc(S); + T^ := T^ or (S^ shl 8); + Inc(S); + T^ := T^ or (S^ shl 16); + Inc(S); + T^ := T^ or (S^ shl 24); + Inc(S); + Inc(T); + end; +end; + +// Decode Count DWORDs at Source into (Count * 4) Bytes at Target +procedure Decode(Source, Target: Pointer; Count: Cardinal); +var + S: PCardinal; + T: PByte; + I: Cardinal; +begin + S := Source; + T := Target; + for I := 1 to Count do + begin + T^ := S^ and $ff; + Inc(T); + T^ := (S^ shr 8) and $ff; + Inc(T); + T^ := (S^ shr 16) and $ff; + Inc(T); + T^ := (S^ shr 24) and $ff; + Inc(T); + Inc(S); + end; +end; + +// Transform State according to first 64 bytes at Buffer +procedure Transform(Buffer: Pointer; var State: TCnMD5State); +var + A, B, C, D: Cardinal; + Block: TCnMD5Block; +begin + Encode(Buffer, @Block, 64); + A := State[0]; + B := State[1]; + C := State[2]; + D := State[3]; + FF (A, B, C, D, Block[ 0], 7, $d76aa478); + FF (D, A, B, C, Block[ 1], 12, $e8c7b756); + FF (C, D, A, B, Block[ 2], 17, $242070db); + FF (B, C, D, A, Block[ 3], 22, $c1bdceee); + FF (A, B, C, D, Block[ 4], 7, $f57c0faf); + FF (D, A, B, C, Block[ 5], 12, $4787c62a); + FF (C, D, A, B, Block[ 6], 17, $a8304613); + FF (B, C, D, A, Block[ 7], 22, $fd469501); + FF (A, B, C, D, Block[ 8], 7, $698098d8); + FF (D, A, B, C, Block[ 9], 12, $8b44f7af); + FF (C, D, A, B, Block[10], 17, $ffff5bb1); + FF (B, C, D, A, Block[11], 22, $895cd7be); + FF (A, B, C, D, Block[12], 7, $6b901122); + FF (D, A, B, C, Block[13], 12, $fd987193); + FF (C, D, A, B, Block[14], 17, $a679438e); + FF (B, C, D, A, Block[15], 22, $49b40821); + GG (A, B, C, D, Block[ 1], 5, $f61e2562); + GG (D, A, B, C, Block[ 6], 9, $c040b340); + GG (C, D, A, B, Block[11], 14, $265e5a51); + GG (B, C, D, A, Block[ 0], 20, $e9b6c7aa); + GG (A, B, C, D, Block[ 5], 5, $d62f105d); + GG (D, A, B, C, Block[10], 9, $2441453); + GG (C, D, A, B, Block[15], 14, $d8a1e681); + GG (B, C, D, A, Block[ 4], 20, $e7d3fbc8); + GG (A, B, C, D, Block[ 9], 5, $21e1cde6); + GG (D, A, B, C, Block[14], 9, $c33707d6); + GG (C, D, A, B, Block[ 3], 14, $f4d50d87); + GG (B, C, D, A, Block[ 8], 20, $455a14ed); + GG (A, B, C, D, Block[13], 5, $a9e3e905); + GG (D, A, B, C, Block[ 2], 9, $fcefa3f8); + GG (C, D, A, B, Block[ 7], 14, $676f02d9); + GG (B, C, D, A, Block[12], 20, $8d2a4c8a); + HH (A, B, C, D, Block[ 5], 4, $fffa3942); + HH (D, A, B, C, Block[ 8], 11, $8771f681); + HH (C, D, A, B, Block[11], 16, $6d9d6122); + HH (B, C, D, A, Block[14], 23, $fde5380c); + HH (A, B, C, D, Block[ 1], 4, $a4beea44); + HH (D, A, B, C, Block[ 4], 11, $4bdecfa9); + HH (C, D, A, B, Block[ 7], 16, $f6bb4b60); + HH (B, C, D, A, Block[10], 23, $bebfbc70); + HH (A, B, C, D, Block[13], 4, $289b7ec6); + HH (D, A, B, C, Block[ 0], 11, $eaa127fa); + HH (C, D, A, B, Block[ 3], 16, $d4ef3085); + HH (B, C, D, A, Block[ 6], 23, $4881d05); + HH (A, B, C, D, Block[ 9], 4, $d9d4d039); + HH (D, A, B, C, Block[12], 11, $e6db99e5); + HH (C, D, A, B, Block[15], 16, $1fa27cf8); + HH (B, C, D, A, Block[ 2], 23, $c4ac5665); + II (A, B, C, D, Block[ 0], 6, $f4292244); + II (D, A, B, C, Block[ 7], 10, $432aff97); + II (C, D, A, B, Block[14], 15, $ab9423a7); + II (B, C, D, A, Block[ 5], 21, $fc93a039); + II (A, B, C, D, Block[12], 6, $655b59c3); + II (D, A, B, C, Block[ 3], 10, $8f0ccc92); + II (C, D, A, B, Block[10], 15, $ffeff47d); + II (B, C, D, A, Block[ 1], 21, $85845dd1); + II (A, B, C, D, Block[ 8], 6, $6fa87e4f); + II (D, A, B, C, Block[15], 10, $fe2ce6e0); + II (C, D, A, B, Block[ 6], 15, $a3014314); + II (B, C, D, A, Block[13], 21, $4e0811a1); + II (A, B, C, D, Block[ 4], 6, $f7537e82); + II (D, A, B, C, Block[11], 10, $bd3af235); + II (C, D, A, B, Block[ 2], 15, $2ad7d2bb); + II (B, C, D, A, Block[ 9], 21, $eb86d391); + Inc(State[0], A); + Inc(State[1], B); + Inc(State[2], C); + Inc(State[3], D); +end; + +// Initialize given Context +procedure MD5Init(var Context: TCnMD5Context); +begin + with Context do + begin + State[0] := $67452301; + State[1] := $EFCDAB89; + State[2] := $98BADCFE; + State[3] := $10325476; + Count[0] := 0; + Count[1] := 0; + // ZeroMemory(@Buffer, SizeOf(TMD5Buffer)); + FillChar(Buffer, SizeOf(TCnMD5Buffer), 0); + end; +end; + +// Update given Context to include Length bytes of Input +procedure MD5Update(var Context: TCnMD5Context; Input: PAnsiChar; ByteLength: Cardinal); +var + Index: Cardinal; + PartLen: Cardinal; + I: Cardinal; +begin + with Context do + begin + Index := (Count[0] shr 3) and $3F; + Inc(Count[0], ByteLength shl 3); + if Count[0] < (ByteLength shl 3) then Inc(Count[1]); + Inc(Count[1], ByteLength shr 29); + end; + + PartLen := 64 - Index; + if ByteLength >= PartLen then + begin + Move(Input^, Context.Buffer[Index], PartLen); + Transform(@Context.Buffer, Context.State); + I := PartLen; + while I + 63 < ByteLength do + begin + Transform(@Input[I], Context.State); + Inc(I, 64); + end; + Index := 0; + end + else + I := 0; + + Move(Input[I], Context.Buffer[Index], ByteLength - I); +end; + +procedure MD5UpdateW(var Context: TCnMD5Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + pContent: PAnsiChar; + iLen: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(pContent, CharLength * SizeOf(WideChar)); + try + iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(pContent), CharLength * SizeOf(WideChar), nil, nil); + MD5Update(Context, pContent, iLen); + finally + FreeMem(pContent); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + MD5Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +// Finalize given Context, create Digest +procedure MD5Final(var Context: TCnMD5Context; var Digest: TCnMD5Digest); +var + Bits: TMD5CBits; + Index: Cardinal; + PadLen: Cardinal; +begin + Decode(@Context.Count, @Bits, 2); + Index := (Context.Count[0] shr 3) and $3f; + if Index < 56 then + PadLen := 56 - Index + else + PadLen := 120 - Index; + MD5Update(Context, @PADDING, PadLen); + MD5Update(Context, @Bits, 8); + Decode(@Context.State, @Digest, 4); +end; + +function InternalMD5Stream(Stream: TStream; const BufSize: Cardinal; var D: + TCnMD5Digest; CallBack: TCnMD5CalcProgressFunc = nil): Boolean; +var + Context: TCnMD5Context; + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; +begin + Result := False; + Size := Stream.Size; + if Size = 0 then + Exit; + + SavePos := Stream.Position; + TotalBytes := 0; + + if Size < BufSize then + BufLen := Size + else + BufLen := BufSize; + + CancelCalc := False; + MD5Init(Context); + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + MD5Update(Context, Buf, ReadBytes); + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + MD5Final(Context, D); + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +// ݿ MD5 +function MD5(Input: PAnsiChar; ByteLength: Cardinal): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5Update(Context, Input, ByteLength); + MD5Final(Context, Result); +end; + +// ݿ MD5 +function MD5Buffer(const Buffer; Count: Cardinal): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5Update(Context, PAnsiChar(Buffer), Count); + MD5Final(Context, Result); +end; + +function MD5Bytes(Data: TBytes): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5Update(Context, PAnsiChar(@Data[0]), Length(Data)); + MD5Final(Context, Result); +end; + +// String ݽ MD5 +function MD5String(const Str: string): TCnMD5Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := MD5StringA(AStr); +end; + +// AnsiString ݽ MD5 +function MD5StringA(const Str: AnsiString): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5Update(Context, PAnsiChar(Str), Length(Str)); + MD5Final(Context, Result); +end; + +// WideString ݽ MD5 +function MD5StringW(const Str: WideString): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5UpdateW(Context, PWideChar(Str), Length(Str)); + MD5Final(Context, Result); +end; + +// UnicodeString ݽֱӵ MD5 㣬ת +{$IFDEF UNICODE} +function MD5UnicodeString(const Str: string): TCnMD5Digest; +{$ELSE} +function MD5UnicodeString(const Str: WideString): TCnMD5Digest; +{$ENDIF} +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + MD5Final(Context, Result); +end; + +// ָļݽ MD5 +function MD5File(const FileName: string; + CallBack: TCnMD5CalcProgressFunc): TCnMD5Digest; +var +{$IFDEF MSWINDOWS} + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; + Context: TCnMD5Context; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; + + function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; +{$IFDEF MSWINDOWS} + var + H: THandle; + Info: BY_HANDLE_FILE_INFORMATION; + Rec : Int64Rec; +{$ENDIF} + begin +{$IFDEF MSWINDOWS} + Result := False; + IsEmpty := False; + H := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); + if H = INVALID_HANDLE_VALUE then Exit; + try + if not GetFileInformationByHandle(H, Info) then Exit; + finally + CloseHandle(H); + end; + Rec.Lo := Info.nFileSizeLow; + Rec.Hi := Info.nFileSizeHigh; + Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); + IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); +{$ELSE} + Result := True; // Windows ƽ̨ Trueʾ Mapping +{$ENDIF} + end; + +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣ Windows ƽ̨ʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalMD5Stream(Stream, 4096 * 1024, Result, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + MD5Init(Context); + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + MD5Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise Exception.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise Exception.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + MD5Final(Context, Result); +{$ENDIF} + end; +end; + +// ָ MD5 +function MD5Stream(Stream: TStream; + CallBack: TCnMD5CalcProgressFunc = nil): TCnMD5Digest; +begin + InternalMD5Stream(Stream, 4096 * 1024, Result, CallBack); +end; + +// ʮƸʽ MD5 Ӵֵ +function MD5Print(const Digest: TCnMD5Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnMD5Digest)); +end; + +// Ƚ MD5 ӴֵǷ +function MD5Match(const D1, D2: TCnMD5Digest): Boolean; +begin + Result := CompareMem(@D1[0], @D2[0], SizeOf(TCnMD5Digest)); +end; + +// MD5 Ӵֵת string +function MD5DigestToStr(const Digest: TCnMD5Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnMD5Digest)); +end; + +procedure MD5HmacInit(var Ctx: TCnMD5Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnMD5Digest; +begin + if KeyLength > HMAC_MD5_BLOCK_SIZE_BYTE then + begin + Sum := MD5Buffer(Key, KeyLength); + KeyLength := HMAC_MD5_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Ctx.Ipad, HMAC_MD5_BLOCK_SIZE_BYTE, $36); + FillChar(Ctx.Opad, HMAC_MD5_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Ctx.Ipad[I] := Byte(Ctx.Ipad[I] xor Byte(Key[I])); + Ctx.Opad[I] := Byte(Ctx.Opad[I] xor Byte(Key[I])); + end; + + MD5Init(Ctx); + MD5Update(Ctx, @(Ctx.Ipad[0]), HMAC_MD5_BLOCK_SIZE_BYTE); +end; + +procedure MD5HmacUpdate(var Ctx: TCnMD5Context; Input: PAnsiChar; Length: Cardinal); +begin + MD5Update(Ctx, Input, Length); +end; + +procedure MD5HmacFinal(var Ctx: TCnMD5Context; var Output: TCnMD5Digest); +var + Len: Integer; + TmpBuf: TCnMD5Digest; +begin + Len := HMAC_MD5_OUTPUT_LENGTH_BYTE; + MD5Final(Ctx, TmpBuf); + MD5Init(Ctx); + MD5Update(Ctx, @(Ctx.Opad[0]), HMAC_MD5_BLOCK_SIZE_BYTE); + MD5Update(Ctx, @(TmpBuf[0]), Len); + MD5Final(Ctx, Output); +end; + +procedure MD5Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnMD5Digest); +var + Ctx: TCnMD5Context; +begin + MD5HmacInit(Ctx, Key, KeyByteLength); + MD5HmacUpdate(Ctx, Input, ByteLength); + MD5HmacFinal(Ctx, Output); +end; + +end. diff --git a/CnPack/Crypto/CnNative.dcu b/CnPack/Crypto/CnNative.dcu new file mode 100644 index 0000000000000000000000000000000000000000..6b75b118ea19893f0e12fe282c3f47c9989c3dbf GIT binary patch literal 48972 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 literal 0 HcmV?d00001 diff --git a/CnPack/Crypto/CnNative.pas b/CnPack/Crypto/CnNative.pas new file mode 100644 index 0000000..972f9e4 --- /dev/null +++ b/CnPack/Crypto/CnNative.pas @@ -0,0 +1,4904 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2025 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnNative; +{* |
+================================================================================
+* ƣCnPack 
+* Ԫƣ32 λ 64 λƽ̨һЩͳһԼһʵֵԪ
+* ԪߣCnPack  (master@cnpack.org)
+*     עԪһ 32 λ 64 λƽ̨һЩͳһʵ֡
+*           Delphi XE 2 ֧ 32  64 ų NativeInt  NativeUInt 
+*           ǰ 32 λ 64 ̬仯Ӱ쵽 PointerReferenceȶ
+*           ǵԣ̶ȵ 32 λ Cardinal/Integer Ⱥ Pointer Щ
+*           ͨˣʹ 32 λҲֹ˱Ԫ˼ͣ
+*           ͬʱڵͰ汾͸߰汾 Delphi ʹá
+*
+*           ԪҲڲ֧ UInt64 ı Delphi 5/6/7  Int64 ģ UInt64
+*           ĸ㣬ӼȻ֧֣˳Ҫģ div  mod
+*           ַ Integer(APtr)  64 λ MacOS ׳ֽضϣҪ NativeInt
+*
+*           ʵ˴Сءֽת̶ʱȷĴײ㺯빤ࡣ
+*
+* ƽ̨PWin2000 + Delphi 5.0
+* ݲԣPWin9X/2000/XP + Delphi 5/6/7 XE 2
+*   õԪеַϱػʽ
+* ޸ļ¼2023.08.14 V2.4
+*               ϼʱ̶ĺ
+*           2022.11.11 V2.3
+*               ϼ޷ֽ˳
+*           2022.07.23 V2.2
+*               Ӽڴλ㺯תַΪ CnNative
+*           2022.06.08 V2.1
+*               ĸʱ̶ĽԼڴ浹ź
+*           2022.03.14 V2.0
+*               Ӽʮת
+*           2022.02.17 V1.9
+*                FPC ı֧
+*           2022.02.09 V1.8
+*               ڵĴСжϺ
+*           2021.09.05 V1.7
+*                Int64/UInt64 㺯
+*           2020.10.28 V1.6
+*                UInt64 صж㺯
+*           2020.09.06 V1.5
+*                UInt64 ƽĺ
+*           2020.07.01 V1.5
+*               ж 32 λ 64 λ޷Ƿĺ
+*           2020.06.20 V1.4
+*                32 λ 64 λȡ͵ 1 λλõĺ
+*           2020.01.01 V1.3
+*                32 λ޷͵ mul 㣬ڲ֧ UInt64 ϵͳ Int64 Ա
+*           2018.06.05 V1.2
+*                64 λ͵ div/mod 㣬ڲ֧ UInt64 ϵͳ Int64  
+*           2016.09.27 V1.1
+*                64 λ͵һЩ
+*           2011.07.06 V1.0
+*               Ԫʵֹ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + Classes, SysUtils, SysConst, Math {$IFDEF COMPILER5}, Windows {$ENDIF}; + // D5 Ҫ Windows е PByte +type + ECnNativeException = class(Exception); + {* Native 쳣} + +{$IFDEF COMPILER5} + PCardinal = ^Cardinal; + {* D5 System Ԫδ壬} + PByte = Windows.PByte; + {* D5 PByte Windows У汾 System У + ͳһһ¹ʹ PByte ʱ uses Windowsڿƽ̨} +{$ENDIF} + +{$IFDEF BCB5OR6} + PInt64 = ^Int64; + {* C++Builder 5/6 sysmac.h û PInt64 Ķ壨е PUINT64 Сдͬ㣩} +{$ENDIF} + +{$IFDEF SUPPORT_32_AND_64} + TCnNativeInt = NativeInt; + TCnNativeUInt = NativeUInt; + TCnNativePointer = NativeInt; + TCnNativeIntPtr = PNativeInt; + TCnNativeUIntPtr = PNativeUInt; +{$ELSE} + TCnNativeInt = Integer; + TCnNativeUInt = Cardinal; + TCnNativePointer = Integer; + TCnNativeIntPtr = PInteger; + TCnNativeUIntPtr = PCardinal; +{$ENDIF} + +{$IFDEF CPU64BITS} + TCnUInt64 = NativeUInt; + TCnInt64 = NativeInt; +{$ELSE} + {$IFDEF SUPPORT_UINT64} + TCnUInt64 = UInt64; + {$ELSE} + TCnUInt64 = packed record // ֻĽṹ + case Boolean of + True: (Value: Int64); + False: (Lo32, Hi32: Cardinal); + end; + {$ENDIF} + TCnInt64 = Int64; +{$ENDIF} + +// TUInt64 cnvcl в֧ UInt64 div mod +{$IFDEF SUPPORT_UINT64} + TUInt64 = UInt64; + {$IFNDEF SUPPORT_PUINT64} + PUInt64 = ^UInt64; + {$ENDIF} +{$ELSE} + TUInt64 = Int64; + PUInt64 = ^TUInt64; +{$ENDIF} + +{$IFNDEF SUPPORT_INT64ARRAY} + // ϵͳûж Int64Array + Int64Array = array[0..$0FFFFFFE] of Int64; + PInt64Array = ^Int64Array; +{$ENDIF} + + TUInt64Array = array of TUInt64; // ̬ƺ׺;̬гͻ + + ExtendedArray = array[0..65537] of Extended; + PExtendedArray = ^ExtendedArray; + + PCnWord16Array = ^TCnWord16Array; + TCnWord16Array = array [0..0] of Word; + +{$IFDEF POSIX64} + TCnLongWord32 = Cardinal; // Linux64/MacOS64 (or POSIX64?) LongWord is 64 Bits +{$ELSE} + TCnLongWord32 = LongWord; +{$ENDIF} + PCnLongWord32 = ^TCnLongWord32; + + TCnLongWord32Array = array [0..MaxInt div SizeOf(Integer) - 1] of TCnLongWord32; + + PCnLongWord32Array = ^TCnLongWord32Array; + +{$IFNDEF TBYTES_DEFINED} + TBytes = array of Byte; + {* ޷ֽڶ̬飬δʱ} +{$ENDIF} + + TShortInts = array of ShortInt; + {* зֽڶ̬} + + TSmallInts = array of SmallInt; + {* з˫ֽڶ̬} + + TWords = array of Word; + {* ޷˫ֽڶ̬} + + TIntegers = array of Integer; + {* зֽڶ̬} + + TCardinals = array of Cardinal; + {* ޷ֽڶ̬} + + PCnByte = ^Byte; + PCnWord = ^Word; + + TCnBitOperation = (boAnd, boOr, boXor, boNot); + {* λ} + +type + TCnMemSortCompareProc = function (P1, P2: Pointer; ElementByteSize: Integer): Integer; + {* ڴ̶ߴȽϺԭ} + +const + CN_MAX_SQRT_INT64: Cardinal = 3037000499; + CN_MAX_INT8: ShortInt = $7F; + CN_MIN_INT8: ShortInt = -128; + CN_MAX_INT16: SmallInt = $7FFF; + CN_MIN_INT16: SmallInt = -32768; + CN_MAX_INT32: Integer = $7FFFFFFF; + CN_MIN_INT32: Integer = $80000000; // 뾯棬 -2147483648 + CN_MIN_INT32_IN_INT64: Int64 = $0000000080000000; + CN_MAX_INT64: Int64 = $7FFFFFFFFFFFFFFF; + CN_MIN_INT64: Int64 = $8000000000000000; + CN_MAX_UINT8: Byte = $FF; + CN_MAX_UINT16: Word = $FFFF; + CN_MAX_UINT32: Cardinal = $FFFFFFFF; + CN_MAX_TUINT64: TUInt64 = $FFFFFFFFFFFFFFFF; + CN_MAX_SIGNED_INT64_IN_TUINT64: TUInt64 = $7FFFFFFFFFFFFFFF; + +{* + D567 Ȳ֧ UInt64 ıȻ Int64 UInt64 мӼ洢 + ˳޷ֱɣװ System е _lludiv _llumod + ʵ Int64 ʾ UInt64 ݵ div mod ܡ +} +function UInt64Mod(A: TUInt64; B: TUInt64): TUInt64; +{* 64 λ޷ࡣ + + + A: TUInt64 - + B: TUInt64 - + + ֵTUInt64 - +} + +function UInt64Div(A: TUInt64; B: TUInt64): TUInt64; +{* 64 λ޷ + + + A: TUInt64 - + B: TUInt64 - + + ֵTUInt64 - +} + +function UInt64Mul(A: Cardinal; B: Cardinal): TUInt64; +{* 32 λ޷ˡڲ֧ UInt64 ƽ̨ϣ UInt64 ʽ Int64  + ֱʹ Int64 п + + + A: Cardinal - һ + B: Cardinal - + + ֵTUInt64 - +} + +procedure UInt64AddUInt64(A: TUInt64; B: TUInt64; var ResLo: TUInt64; var ResHi: TUInt64); +{* 64 λ޷ӣ ResLo ResHi С + עڲʵְ㷨ΪӣʵResHi Ȼ 1ֱж 1 + + + A: TUInt64 - һ + B: TUInt64 - + var ResLo: TUInt64 - ͵λ + var ResHi: TUInt64 - ͸λ + + ֵޣ +} + +procedure UInt64MulUInt64(A: TUInt64; B: TUInt64; var ResLo: TUInt64; var ResHi: TUInt64); +{* 64 λ޷ˣ ResLo ResHi СWin 64 λûʵ֣Լһϡ + + + A: TUInt64 - һ + B: TUInt64 - + var ResLo: TUInt64 - λ + var ResHi: TUInt64 - λ + + ֵޣ +} + +function UInt64ToHex(N: TUInt64): string; +{* 64 λ޷תΪʮַ + + + N: TUInt64 - תֵ + + ֵstring - ʮַ +} + +function UInt64ToStr(N: TUInt64): string; +{* 64 λ޷תΪʮַ + + + N: TUInt64 - תֵ + + ֵstring - ʮַ +} + +function StrToUInt64(const S: string): TUInt64; +{* ַתΪ 64 λ޷ + + + const S: string - תַ + + ֵTUInt64 - ת +} + +function UInt64Compare(A: TUInt64; B: TUInt64): Integer; +{* Ƚ 64 λ޷ֱֵݱȽϵĽǴڡڻС 10-1 + + + A: TUInt64 - Ƚϵһ + B: TUInt64 - Ƚϵ + + ֵInteger - رȽϽ +} + +function UInt64Sqrt(N: TUInt64): TUInt64; +{* 64 λ޷ƽ֡ + + + N: TUInt64 - ƽ + + ֵTUInt64 - ƽ +} + +function UInt32IsNegative(N: Cardinal): Boolean; +{* ж 32 λ޷ 32 λзʱǷС 0 + + + N: Cardinal - жϵֵ + + ֵBoolean - ǷС 0 +} + +function UInt64IsNegative(N: TUInt64): Boolean; +{* ж 64 λ޷ 64 λзʱǷС 0 + + + N: TUInt64 - жϵֵ + + ֵBoolean - ǷС 0 +} + +procedure UInt64SetBit(var B: TUInt64; Index: Integer); +{* 64 λijһλ 1λ Index 0 ʼ 63 + + + var B: TUInt64 - λֵ + Index: Integer - 1 λ + + ֵޣ +} + +procedure UInt64ClearBit(var B: TUInt64; Index: Integer); +{* 64 λijһλ 0λ Index 0 ʼ 63 + + + var B: TUInt64 - λֵ + Index: Integer - 0 λ + + ֵޣ +} + +function GetUInt64BitSet(B: TUInt64; Index: Integer): Boolean; +{* 64 λijһλǷ 1λ Index 0 ʼ 63 + + + B: TUInt64 - жϵֵ + Index: Integer - жϵλ + + ֵBoolean - ظλǷ 1 +} + +function GetUInt64HighBits(B: TUInt64): Integer; +{* 64 λ 1 ߶λǵڼλλ 0û 1 -1 + + + B: TUInt64 - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt32HighBits(B: Cardinal): Integer; +{* 32 λ 1 ߶λǵڼλλ 0û 1 -1 + + + B: Cardinal - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt16HighBits(B: Word): Integer; +{* 16 λ 1 ߶λǵڼλλ 0û 1 -1 + + + B: Word - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt8HighBits(B: Byte): Integer; +{* 8 λ 1 ߶λǵڼλλ 0û 1 -1 + + + B: Byte - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt64LowBits(B: TUInt64): Integer; +{* 64 λ 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 + + + B: TUInt64 - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt32LowBits(B: Cardinal): Integer; +{* 32 λ 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 + + + B: Cardinal - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt16LowBits(B: Word): Integer; +{* 16 λ 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 + + + B: Word - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt8LowBits(B: Byte): Integer; +{* 8 λ 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 + + + B: Byte - жϵֵ + + ֵInteger - 1 λ +} + +function Int64Mod(M: Int64; N: Int64): Int64; +{* װ Int64 ModM ֵʱȡģģ N Ҫס + + + M: Int64 - + N: Int64 - + + ֵInt64 - +} + +function IsUInt32PowerOf2(N: Cardinal): Boolean; +{* жһ 32 λ޷Ƿ 2 ݡ + + + N: Cardinal - жϵֵ + + ֵBoolean - Ƿ 2 +} + +function IsUInt64PowerOf2(N: TUInt64): Boolean; +{* жһ 64 λ޷Ƿ 2 ݡ + + + N: TUInt64 - жϵֵ + + ֵBoolean - Ƿ 2 +} + +function GetUInt32PowerOf2GreaterEqual(N: Cardinal): Cardinal; +{* õһָ 32 λ޷ȵ 2 ݣ򷵻 0 + + + N: Cardinal - ֵ + + ֵCardinal - ط 2 ݻ 0 +} + +function GetUInt64PowerOf2GreaterEqual(N: TUInt64): TUInt64; +{* õһָ 64 λ޷ȵ 2 ݣ򷵻 0 + + + N: TUInt64 - ֵ + + ֵTUInt64 - ط 2 ݻ 0 +} + +function IsInt32AddOverflow(A: Integer; B: Integer): Boolean; +{* ж 32 λзǷ 32 λзޡ + + + A: Integer - һ + B: Integer - + + ֵBoolean - Ƿ +} + +function IsUInt32AddOverflow(A: Cardinal; B: Cardinal): Boolean; +{* ж 32 λ޷Ƿ 32 λ޷ޡ + + + A: Cardinal - һ + B: Cardinal - + + ֵBoolean - Ƿ +} + +function IsInt64AddOverflow(A: Int64; B: Int64): Boolean; +{* ж 64 λзǷ 64 λзޡ + + + A: Int64 - һ + B: Int64 - + + ֵBoolean - Ƿ +} + +function IsUInt64AddOverflow(A: TUInt64; B: TUInt64): Boolean; +{* ж 64 λ޷Ƿ 64 λ޷ޡ + + + A: TUInt64 - һ + B: TUInt64 - + + ֵBoolean - Ƿ +} + +function IsUInt64SubOverflowInt32(A: TUInt64; B: TUInt64): Boolean; +{* жһ 64 λ޷ȥһ 64 λ޷ĽǷ񳬳 32 λзΧ + 64 λе JMP תжϡ + + + A: TUInt64 - + B: TUInt64 - + + ֵBoolean - Ƿ񳬳 32 λзΧ +} + +procedure UInt64Add(var R: TUInt64; A: TUInt64; B: TUInt64; out Carry: Integer); +{* 64 λ޷ӣA + B => R 1 ýλλ㡣 + + + var R: TUInt64 - + A: TUInt64 - һ + B: TUInt64 - + out Carry: Integer - λ + + ֵޣ +} + +procedure UInt64Sub(var R: TUInt64; A: TUInt64; B: TUInt64; out Carry: Integer); +{* 64 λ޷A - B => Rнλ 1 ýλλ㡣 + + + var R: TUInt64 - + A: TUInt64 - + B: TUInt64 - + out Carry: Integer - λ + + ֵޣ +} + +function IsInt32MulOverflow(A: Integer; B: Integer): Boolean; +{* ж 32 λзǷ 32 λзޡ + + + A: Integer - һ + B: Integer - + + ֵBoolean - Ƿ +} + +function IsUInt32MulOverflow(A: Cardinal; B: Cardinal): Boolean; +{* ж 32 λ޷Ƿ 32 λ޷ + + + A: Cardinal - һ + B: Cardinal - + + ֵBoolean - Ƿ +} + +function IsUInt32MulOverflowInt64(A: Cardinal; B: Cardinal; out R: TUInt64): Boolean; +{* ж 32 λ޷Ƿ 64 λзޣδҲ False ʱR ֱӷؽ + Ҳ TrueҪµ UInt64Mul ʵʩˡ + + + A: Cardinal - һ + B: Cardinal - + out R: TUInt64 - δʱػ + + ֵBoolean - Ƿ +} + +function IsInt64MulOverflow(A: Int64; B: Int64): Boolean; +{* ж 64 λзǷ 64 λзޡ + + + A: Int64 - һ + B: Int64 - + + ֵBoolean - Ƿ +} + +function PointerToInteger(P: Pointer): Integer; +{* ָת֧ͣ 32/64 λע 64 λ¿ܻᶪ 32 λݡ + + + P: Pointer - תָ + + ֵInteger - ת +} + +function IntegerToPointer(I: Integer): Pointer; +{* תָ֧ͣ 32/64 λ + + + I: Integer - ת + + ֵPointer - תָ +} + +function Int64NonNegativeAddMod(A: Int64; B: Int64; N: Int64): Int64; +{* 64 λзΧĺ࣬Ҫ N 0 + + + A: Int64 - һ + B: Int64 - һ + N: Int64 - ģ + + ֵInt64 - Ľ +} + +function UInt64NonNegativeAddMod(A: TUInt64; B: TUInt64; N: TUInt64): TUInt64; +{* 64 λ޷Χĺ࣬Ҫ N 0 + + + A: TUInt64 - һ + B: TUInt64 - + N: TUInt64 - ģ + + ֵTUInt64 - Ľ +} + +function Int64NonNegativeMulMod(A: Int64; B: Int64; N: Int64): Int64; +{* 64 λзΧڵֱ࣬Ӽ㣬Ҫ N 0 + + + A: Int64 - һ + B: Int64 - + N: Int64 - ģ + + ֵInt64 - Ľ +} + +function UInt64NonNegativeMulMod(A: TUInt64; B: TUInt64; N: TUInt64): TUInt64; +{* 64 λ޷Χڵֱ࣬Ӽ㣬 + + + A: TUInt64 - һ + B: TUInt64 - + N: TUInt64 - ģ + + ֵTUInt64 - Ľ +} + +function Int64NonNegativeMod(N: Int64; P: Int64): Int64; +{* װ 64 λзķǸຯҲΪʱӸ豣֤ P 0 + + + N: Int64 - + P: Int64 - + + ֵInt64 - طǸĽ +} + +function Int64NonNegativPower(N: Int64; Exp: Integer): Int64; +{* 64 λзķǸָݣ + + + N: Int64 - + Exp: Integer - ָҪ 0 + + ֵInt64 - ݵĽ +} + +function Int64NonNegativeRoot(N: Int64; Exp: Integer): Int64; +{* 64 λзķǸη֣ + + + N: Int64 - + Exp: Integer - + + ֵInt64 - ؿֽ +} + +function UInt64NonNegativPower(N: TUInt64; Exp: Integer): TUInt64; +{* 64 λ޷ķǸָݣ + + + N: TUInt64 - + Exp: Integer - ָҪ 0 + + ֵTUInt64 - ݵĽ +} + +function UInt64NonNegativeRoot(N: TUInt64; Exp: Integer): TUInt64; +{* 64 λ޷ķǸη֣ + + + N: TUInt64 - + Exp: Integer - + + ֵTUInt64 - ؿֽ +} + +function CurrentByteOrderIsBigEndian: Boolean; +{* صǰڻǷǴˣҲǷеĸֽڴ洢ڽϵ͵ʼַ + ϴҵĶϰߣ粿ָ ARM MIPS + + + ޣ + + ֵBoolean - صǰڻǷǴ +} + +function CurrentByteOrderIsLittleEndian: Boolean; +{* صǰڻǷСˣҲǷеĸֽڴ洢ڽϸߵʼַ x86 벿Ĭ ARM + + + ޣ + + ֵBoolean - صǰڻǷС +} + +function Int64ToBigEndian(Value: Int64): Int64; +{* ȷ 64 λзֵΪˣС˻лת + + + Value: Int64 - ת 64 λз + + ֵInt64 - شֵ +} + +function Int32ToBigEndian(Value: Integer): Integer; +{* ȷ 32 λзֵΪˣС˻лת + + + Value: Integer - ת 32 λз + + ֵInteger - شֵ +} + +function Int16ToBigEndian(Value: SmallInt): SmallInt; +{* ȷ 16 λзֵΪˣС˻лת + + + Value: SmallInt - ת 16 λз + + ֵSmallInt - شֵ +} + +function Int64ToLittleEndian(Value: Int64): Int64; +{* ȷ 64 λзֵΪСˣڴ˻лת + + + Value: Int64 - ת 64 λз + + ֵInt64 - شֵ +} + +function Int32ToLittleEndian(Value: Integer): Integer; +{* ȷ 32 λзֵΪСˣڴ˻лת + + + Value: Integer - ת 32 λз + + ֵInteger - Сֵ +} + +function Int16ToLittleEndian(Value: SmallInt): SmallInt; +{* ȷ 16 λзֵΪСˣڴ˻лת + + + Value: SmallInt - ת 16 λз + + ֵSmallInt - Сֵ +} + +function UInt64ToBigEndian(Value: TUInt64): TUInt64; +{* ȷ 64 λ޷ֵΪˣС˻лת + + + Value: TUInt64 - ת 64 λ޷ + + ֵTUInt64 - شֵ +} + +function UInt32ToBigEndian(Value: Cardinal): Cardinal; +{* ȷ 32 λ޷ֵΪˣС˻лת + + + Value: Cardinal - ת 32 λ޷ + + ֵCardinal - شֵ +} + +function UInt16ToBigEndian(Value: Word): Word; +{* ȷ 16 λ޷ֵΪˣС˻лת + + + Value: Word - ת 16 λ޷ + + ֵWord - شֵ +} + +function UInt64ToLittleEndian(Value: TUInt64): TUInt64; +{* ȷ 64 λ޷ֵΪСˣڴ˻лת + + + Value: TUInt64 - ת 64 λ޷ + + ֵTUInt64 - شֵ +} + +function UInt32ToLittleEndian(Value: Cardinal): Cardinal; +{* ȷ 32 λ޷ֵΪСˣڴ˻лת + + + Value: Cardinal - ת 32 λ޷ + + ֵCardinal - Сֵ +} + +function UInt16ToLittleEndian(Value: Word): Word; +{* ȷ 16 λ޷ֵΪСˣڴ˻лת + + + Value: Word - ת 16 λ޷ + + ֵWord - Сֵ +} + +function Int64HostToNetwork(Value: Int64): Int64; +{* 64 λзֵֽ˳תΪֽ˳С˻лת + + + Value: Int64 - ת 64 λз + + ֵInt64 - ֽ˳ֵ +} + +function Int32HostToNetwork(Value: Integer): Integer; +{* 32 λзֵֽ˳תΪֽ˳С˻лת + + + Value: Integer - ת 32 λз + + ֵInteger - ֽ˳ֵ +} + +function Int16HostToNetwork(Value: SmallInt): SmallInt; +{* 16 λзֵֽ˳תΪֽ˳С˻лת + + + Value: SmallInt - ת 16 λз + + ֵSmallInt - ֽ˳ֵ +} + +function Int64NetworkToHost(Value: Int64): Int64; +{* 64 λзֵֽ˳תΪֽ˳С˻лת + + + Value: Int64 - ת 64 λз + + ֵInt64 - ֽ˳ֵ +} + +function Int32NetworkToHost(Value: Integer): Integer; +{* 32 λзֵֽ˳תΪֽ˳С˻лת + + + Value: Integer - ת 32 λз + + ֵInteger - ֽ˳ֵ +} + +function Int16NetworkToHost(Value: SmallInt): SmallInt; +{* 16 λзֵֽ˳תΪֽ˳С˻лת + + + Value: SmallInt - ת 16 λз + + ֵSmallInt - ֽ˳ֵ +} + +function UInt64HostToNetwork(Value: TUInt64): TUInt64; +{* 64 λ޷ֵֽ˳תΪֽ˳С˻лת + + + Value: TUInt64 - ת 64 λ޷ + + ֵTUInt64 - ֽ˳ֵ +} + +function UInt32HostToNetwork(Value: Cardinal): Cardinal; +{* 32 λ޷ֵֽ˳תΪֽ˳С˻лת + + + Value: Cardinal - ת 32 λ޷ + + ֵCardinal - ֽ˳ֵ +} + +function UInt16HostToNetwork(Value: Word): Word; +{* 16 λ޷ֵֽ˳תΪֽ˳С˻лת + + + Value: Word - ת 16 λ޷ + + ֵWord - ֽ˳ֵ +} + +function UInt64NetworkToHost(Value: TUInt64): TUInt64; +{* 64 λ޷ֵֽ˳תΪֽ˳С˻лת + + + Value: TUInt64 - ת 64 λ޷ + + ֵTUInt64 - ֽ˳ֵ +} + +function UInt32NetworkToHost(Value: Cardinal): Cardinal; +{* 32 λ޷ֵֽ˳תΪֽ˳С˻лת + + + Value: Cardinal - ת 32 λ޷ + + ֵCardinal - ֽ˳ֵ +} + +function UInt16NetworkToHost(Value: Word): Word; +{* 16 λ޷ֵֽ˳תΪֽ˳С˻лת + + + Value: Word - ת 16 λ޷ + + ֵWord - ֽ˳ֵ +} + +procedure MemoryNetworkToHost(Mem: Pointer; MemByteLen: Integer); +{* һƬڴֽ˳תΪֽ˳С˻лת + ÷ӦóϽ٣¶ġֽתѾ㹻 + + + Mem: Pointer - תݿַ + MemByteLen: Integer - תݿֽڳ + + ֵޣ +} + +procedure MemoryHostToNetwork(Mem: Pointer; MemByteLen: Integer); +{* һƬڴֽ˳תΪֽ˳С˻лת + ÷ӦóϽ٣¶ġֽתѾ㹻 + + + Mem: Pointer - תݿַ + MemByteLen: Integer - תݿֽڳ + + ֵޣ +} + +procedure ReverseMemory(Mem: Pointer; MemByteLen: Integer); +{* ֽ˳һڴ飬ֽڲ䡣 + + + Mem: Pointer - õݿַ + MemByteLen: Integer - õݿֽڳ + + ֵޣ +} + +function ReverseBitsInInt8(V: Byte): Byte; +{* һֽڲλݡ + + + V: Byte - õһֽ + + ֵByte - صֵ +} + +function ReverseBitsInInt16(V: Word): Word; +{* öֽڼڲλݡ + + + V: Word - õĶֽ + + ֵWord - صֵ +} + +function ReverseBitsInInt32(V: Cardinal): Cardinal; +{* ֽڼڲλݡ + + + V: Cardinal - õֽ + + ֵCardinal - صֵ +} + +function ReverseBitsInInt64(V: Int64): Int64; +{* ðֽڼڲλݡ + + + V: Int64 - õİֽ + + ֵInt64 - صֵ +} + +procedure ReverseMemoryWithBits(Mem: Pointer; MemByteLen: Integer); +{* ֽ˳һڴ飬ÿֽҲ + + + Mem: Pointer - õݿַ + MemByteLen: Integer - õݿֽڳ + + ֵޣ +} + +procedure MemoryAnd(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +{* 鳤ͬڴ AMem BMem λ룬 ResMem У߿ͬ + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + ResMem: Pointer - ݿַ + + ֵޣ +} + +procedure MemoryOr(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +{* 鳤ͬڴ AMem BMem λ򣬽 ResMem У߿ͬ + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + ResMem: Pointer - ݿַ + + ֵޣ +} + +procedure MemoryXor(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +{* 鳤ͬڴ AMem BMem λ򣬽 ResMem У߿ͬ + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + ResMem: Pointer - ݿַ + + ֵޣ +} + +procedure MemoryNot(Mem: Pointer; MemByteLen: Integer; ResMem: Pointer); +{* һڴ AMem ȡ ResMem У߿ͬ + + + Mem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + ResMem: Pointer - ݿַ + + ֵޣ +} + +procedure MemoryShiftLeft(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; BitCount: Integer); +{* AMem ڴ BitCount λ BMemڴַλƣλ 0߿ȡ + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + BitCount: Integer - Ƶλ + + ֵޣ +} + +procedure MemoryShiftRight(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; BitCount: Integer); +{* AMem ڴ BitCount λ BMemڴַλƣλ 0߿ȡ + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + BitCount: Integer - Ƶλ + + ֵޣ +} + +function MemoryIsBitSet(Mem: Pointer; N: Integer): Boolean; +{* ڴij Bit λǷ 1ڴַλ 0ֽڻұΪ 0 + + + Mem: Pointer - ݿַ + N: Integer - λ + + ֵBoolean - Ƿ 1 +} + +procedure MemorySetBit(Mem: Pointer; N: Integer); +{* ڴij Bit λ 1ڴַλ 0ֽڻұΪ 0 + + + Mem: Pointer - ݿַ + N: Integer - λ + + ֵޣ +} + +procedure MemoryClearBit(Mem: Pointer; N: Integer); +{* ڴij Bit λ 0ڴַλ 0ֽڻұΪ 0 + + + Mem: Pointer - ݿַ + N: Integer - λ + + ֵޣ +} + +function MemoryToBinStr(Mem: Pointer; MemByteLen: Integer; Sep: Boolean = False): string; +{* һڴݴӵ͵ֽ˳ΪַSep ʾֽ֮Ƿոָ + + + Mem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + Sep: Boolean - ֽ֮Ƿÿոָ + + ֵstring - ضַ +} + +procedure MemorySwap(AMem: Pointer; BMem: Pointer; MemByteLen: Integer); +{* ͬȵڴݣͬڴʲô + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + + ֵޣ +} + +function MemoryCompare(AMem: Pointer; BMem: Pointer; MemByteLen: Integer): Integer; +{* ޷ķʽȽڴ棬 10-1ͬڴֱӷ 0 + + + AMem: Pointer - Ƚϵݿַһ + BMem: Pointer - Ƚϵݿַ + MemByteLen: Integer - Ƚϵݿֽڳ + + ֵInteger - رȽϵĽ +} + +procedure MemoryQuickSort(Mem: Pointer; ElementByteSize: Integer; + ElementCount: Integer; CompareProc: TCnMemSortCompareProc = nil); +{* Թ̶СԪص + + + Mem: Pointer - ݿַ + ElementByteSize: Integer - Ԫֽڳ + ElementCount: Integer - ݿԪصĸ + CompareProc: TCnMemSortCompareProc - ԪرȽϵĻص + + ֵޣ +} + +function UInt8ToBinStr(V: Byte): string; +{* һ 8 λ޷תΪַ + + + V: Byte - ת 8 λ޷ + + ֵstring - ضַ +} + +function UInt16ToBinStr(V: Word): string; +{* һ 16 λ޷תΪַ + + + V: Word - ת 16 λ޷ + + ֵstring - ضַ +} + +function UInt32ToBinStr(V: Cardinal): string; +{* һ 32 λ޷תΪַ + + + V: Cardinal - ת 32 λ޷ + + ֵstring - ضַ +} + +function UInt32ToStr(V: Cardinal): string; +{* һ 32 λ޷תΪʮַ + + + V: Cardinal - ת 32 λ޷ + + ֵstring - ʮַ +} + +function UInt64ToBinStr(V: TUInt64): string; +{* һ 64 λ޷תΪַ + + + V: TUInt64 - ת 64 λ޷ + + ֵstring - ضַ +} + +function HexToInt(const Hex: string): Integer; overload; +{* һʮַתΪͣʺϽ϶ 2 ַַ + + + const Hex: string - תʮַ + + ֵInteger - +} + +function HexToInt(Hex: PChar; CharLen: Integer): Integer; overload; +{* һʮַָָתΪͣʺϽ϶ 2 ַַ + + + Hex: PChar - תʮַַ + CharLen: Integer - ַ + + ֵInteger - +} + +function IsHexString(const Hex: string): Boolean; +{* жһַǷϷʮִַСд + + + const Hex: string - жϵʮַ + + ֵBoolean - ǷǺϷʮַ +} + +function DataToHex(InData: Pointer; ByteLength: Integer; UseUpperCase: Boolean = True): string; +{* ڴתΪʮַڴλݳַ󷽣൱ֽ˳ + UseUpperCase ݵĴСд + + + InData: Pointer - תݿַ + ByteLength: Integer - תݿֽڳ + UseUpperCase: Boolean - ʮַڲǷд + + ֵstring - ʮַ +} + +function HexToData(const Hex: string; OutData: Pointer = nil): Integer; +{* ʮַתΪڴ飬ַ󷽵ݳڴλ൱ֽ˳ + ʮַΪתʧʱ׳쳣תɹֽ + ע OutData Ӧָ㹻תݵֽڳΪ Length(Hex) div 2 + nilֻֽڳȣʽת + + + const Hex: string - תʮַ + OutData: Pointer - ֽڳӦΪ Length(Hex) div 2 + + ֵInteger - תֽڳ +} + +function StringToHex(const Data: string; UseUpperCase: Boolean = True): string; +{* ַתΪʮַUseUpperCase ݵĴСд + + + const Data: string - תַ + UseUpperCase: Boolean - ʮַڲǷд + + ֵstring - תʮַ +} + +function HexToString(const Hex: string): string; +{* ʮַתΪַʮַΪתʧʱ׳쳣 + + + const Hex: string - תʮַ + + ֵstring - תַ +} + +function HexToAnsiStr(const Hex: AnsiString): AnsiString; +{* ʮַתΪַʮַΪתʧʱ׳쳣 + + + const Hex: AnsiString - תʮַ + + ֵAnsiString - תַ +} + +function AnsiStrToHex(const Data: AnsiString; UseUpperCase: Boolean = True): AnsiString; +{* AnsiString תΪʮַUseUpperCase ݵĴСд + + + const Data: AnsiString - תַ + UseUpperCase: Boolean - ʮַڲǷд + + ֵAnsiString - ʮַ +} + +function BytesToHex(Data: TBytes; UseUpperCase: Boolean = True): string; +{* ֽתΪʮַ±λݳַ󷽣൱ֽ˳ + UseUpperCase ݵĴСд + + + Data: TBytes - תֽ + UseUpperCase: Boolean - ʮַڲǷд + + ֵstring - ʮַ +} + +function HexToBytes(const Hex: string): TBytes; +{* ʮַתΪֽ飬ַߵݳ±λ൱ֽ˳ + ַΪתʧʱ׳쳣 + + + const Hex: string - תʮַ + + ֵTBytes - ½ֽ +} + +function StreamToHex(Stream: TStream; UseUpperCase: Boolean = True): string; +{* еȫݴͷתΪʮַ + + + Stream: TStream - + UseUpperCase: Boolean - ʮַڲǷд + + ֵstring - ʮַ +} + +function HexToStream(const Hex: string; Stream: TStream): Integer; +{* ʮַתдУдֽ + + + const Hex: string - תʮַ + Stream: TStream - д + + ֵInteger - дֽ +} + +procedure ReverseBytes(Data: TBytes); +{* ֽ˳һֽ顣 + + + Data: TBytes - õֽ + + ֵޣ +} + +function CloneBytes(Data: TBytes): TBytes; +{* һµֽ + + + Data: TBytes - Ƶֽ + + ֵTBytes - ½ֽ +} + +function StreamToBytes(Stream: TStream): TBytes; +{* ͷȫֽ飬½ֽ顣 + + + Stream: TStream - + + ֵTBytes - ½ֽ +} + +function BytesToStream(Data: TBytes; OutStream: TStream): Integer; +{* ֽдԭʼдֽ + + + Data: TBytes - дֽ + OutStream: TStream - д + + ֵInteger - дֽ +} + +function AnsiToBytes(const Str: AnsiString): TBytes; +{* AnsiString ֱתΪֽ飬롣 + + + const Str: AnsiString - תַ + + ֵTBytes - תֽ +} + +function BytesToAnsi(Data: TBytes): AnsiString; +{* ֱֽתΪ AnsiString롣 + + + Data: TBytes - תֽ + + ֵAnsiString - תַ +} + +function BytesToString(Data: TBytes): string; +{* ֽתΪ stringڲ Byte ֵΪ Char롣 + + + Data: TBytes - תֽ + + ֵstring - תַ +} + +function MemoryToString(Mem: Pointer; MemByteLen: Integer): string; +{* ڴתΪ stringڲֽڸֵ롣 + + + Mem: Pointer - תݿַ + MemByteLen: Integer - תݿֽڳ + + ֵstring - תַ +} + +function BitsToString(Bits: TBits): string; +{* λתΪ 0 1 ַ + + + Bits: TBits - תλ + + ֵstring - תַ +} + +function ConcatBytes(A: TBytes; B: TBytes): TBytes; +{* A B ֽ˳ƴ÷һֽ飬A B ֲ䡣 + + + A: TBytes - ƴӵֽһ + B: TBytes - ƴӵֽ + + ֵTBytes - ƴӵֽ +} + +function NewBytesFromMemory(Data: Pointer; DataByteLen: Integer): TBytes; +{* ½һֽ飬һƬڴݹ + + + Data: Pointer - ݿַ + DataByteLen: Integer - ݿֽڳ + + ֵTBytes - ½ֽ +} + +function CompareBytes(A: TBytes; B: TBytes): Boolean; overload; +{* ȽֽǷͬ + + + A: TBytes - Ƚϵֽһ + B: TBytes - Ƚϵֽ + + ֵBoolean - رȽϽǷͬ +} + +function CompareBytes(A: TBytes; B: TBytes; MaxLength: Integer): Boolean; overload; +{* Ƚֽǰ MaxLength ֽڵǷͬ + + + A: TBytes - Ƚϵֽһ + B: TBytes - Ƚϵֽ + MaxLength: Integer - Ƚϵֽ + + ֵBoolean - رȽϽǷͬ +} + +function MoveMost(const Source; var Dest; ByteLen: Integer; MostLen: Integer): Integer; +{* Source ƶ ByteLen Ҳ MostLen ֽڵ Dest Уʵƶֽ + ByteLen С MostLen Dest 0Ҫ Dest MostLen + + + const Source - ƶԴλáַ + var Dest - ƶĿλáַҪ MostLen ֽ + ByteLen: Integer - ƶֽ + MostLen: Integer - ƶֽ + + ֵInteger - ʵƶֽ +} + +// =============================== =================================== + +function SarInt8(var V: Byte; ShiftCount: Integer): Byte; +{* һ 8 λƣҲDZλơ + + + var V: Byte - Ƶ 8 λ + ShiftCount: Integer - Ƶλ + + ֵByte - λֵ +} + +function SarInt16(var V: Word; ShiftCount: Integer): Word; +{* һ 16 λƣҲDZλơ + + + var V: Word - Ƶ 16 λ + ShiftCount: Integer - Ƶλ + + ֵWord - λֵ +} + +function SarInt32(var V: Cardinal; ShiftCount: Integer): Cardinal; +{* һ 32 λƣҲDZλơ + + + var V: Cardinal - Ƶ 32 λ + ShiftCount: Integer - Ƶλ + + ֵCardinal - λֵ +} + +function SarInt64(var V: TUInt64; ShiftCount: Integer): TUInt64; +{* һ 64 λƣҲDZλơ + + + var V: TUInt64 - Ƶ 64 λ + ShiftCount: Integer - Ƶλ + + ֵTUInt64 - λֵ +} + +// ================ ִʱ̶ if жϵIJ߼ =============== + +procedure ConstTimeConditionalSwap8(CanSwap: Boolean; var A: Byte; var B: Byte); +{* 8 λͱִʱ̶CanSwap Ϊ True ʱʵʩ A B + + + CanSwap: Boolean - Ƿ񽻻 + var A: Byte - 8 λͱһ + var B: Byte - 8 λͱ + + ֵޣ +} + +procedure ConstTimeConditionalSwap16(CanSwap: Boolean; var A: Word; var B: Word); +{* 16 λͱִʱ̶CanSwap Ϊ True ʱʵʩ A B + + + CanSwap: Boolean - Ƿ񽻻 + var A: Word - 16 λͱһ + var B: Word - 16 λͱ + + ֵޣ +} + +procedure ConstTimeConditionalSwap32(CanSwap: Boolean; var A: Cardinal; var B: Cardinal); +{* 32 λͱִʱ̶CanSwap Ϊ True ʱʵʩ A B + + + CanSwap: Boolean - Ƿ񽻻 + var A: Cardinal - 32 λͱһ + var B: Cardinal - 32 λͱ + + ֵޣ +} + +procedure ConstTimeConditionalSwap64(CanSwap: Boolean; var A: TUInt64; var B: TUInt64); +{* 64 λͱִʱ̶CanSwap Ϊ True ʱʵʩ A B + + + CanSwap: Boolean - Ƿ񽻻 + var A: TUInt64 - 64 λͱһ + var B: TUInt64 - 64 λͱ + + ֵޣ +} + +function ConstTimeEqual8(A: Byte; B: Byte): Boolean; +{* ֽڵִʱ̶ıȽϣ CPU ָתԤ⵼µִʱ죬ͬʱ True + + + A: Byte - Ƚϵ 8 λͱһ + B: Byte - Ƚϵ 8 λͱ + + ֵBoolean - Ƿ +} + +function ConstTimeEqual16(A: Word; B: Word): Boolean; +{* ˫ֽڵִʱ̶ıȽϣ CPU ָתԤ⵼µִʱ죬ͬʱ True + + + A: Word - Ƚϵ 16 λͱһ + B: Word - Ƚϵ 16 λͱ + + ֵBoolean - Ƿ +} + +function ConstTimeEqual32(A: Cardinal; B: Cardinal): Boolean; +{* ֽڵִʱ̶ıȽϣ CPU ָתԤ⵼µִʱ죬ͬʱ True + + + A: Cardinal - Ƚϵ 32 λͱһ + B: Cardinal - Ƚϵ 32 λͱ + + ֵBoolean - Ƿ +} + +function ConstTimeEqual64(A: TUInt64; B: TUInt64): Boolean; +{* ֽڵִʱ̶ıȽϣ CPU ָתԤ⵼µִʱ죬ͬʱ True + + + A: TUInt64 - Ƚϵ 64 λͱһ + B: TUInt64 - Ƚϵ 64 λͱ + + ֵBoolean - Ƿ +} + +function ConstTimeBytesEqual(A: TBytes; B: TBytes): Boolean; +{* ͬȵִֽʱ̶ıȽϣͬʱ True + + + A: TBytes - Ƚϵֽһ + B: TBytes - Ƚϵֽ + + ֵBoolean - Ƿ +} + +function ConstTimeExpandBoolean8(V: Boolean): Byte; +{* V ֵ 8 λȫ 1 ȫ 0 + + + V: Boolean - Ƿ񷵻ȫ 1 + + ֵByte - $FF 0 +} + +function ConstTimeExpandBoolean16(V: Boolean): Word; +{* V ֵ 16 λȫ 1 ȫ 0 + + + V: Boolean - Ƿ񷵻ȫ 1 + + ֵWord - $FFFF 0 +} + +function ConstTimeExpandBoolean32(V: Boolean): Cardinal; +{* V ֵ 32 λȫ 1 ȫ 0 + + + V: Boolean - Ƿ񷵻ȫ 1 + + ֵCardinal - $FFFFFFFF 0 +} + +function ConstTimeExpandBoolean64(V: Boolean): TUInt64; +{* V ֵ 64 λȫ 1 ȫ 0 + + + V: Boolean - Ƿ񷵻ȫ 1 + + ֵTUInt64 - $FFFFFFFFFFFFFFFF 0 +} + +function ConstTimeConditionalSelect8(Condition: Boolean; A: Byte; B: Byte): Byte; +{* ֽڱִʱ̶жѡCondtion Ϊ True ʱ A򷵻 B + + + Condition: Boolean - Ƿѡ A ҲDzһ + A: Byte - ѡ 8 λһ + B: Byte - ѡ 8 λ + + ֵByte - ѡ 8 λ +} + +function ConstTimeConditionalSelect16(Condition: Boolean; A: Word; B: Word): Word; +{* ˫ֽڱִʱ̶жѡCondtion Ϊ True ʱ A򷵻 B + + + Condition: Boolean - Ƿѡ A ҲDzһ + A: Word - ѡ 16 λһ + B: Word - ѡ 16 λ + + ֵWord - ѡ 16 λ +} + +function ConstTimeConditionalSelect32(Condition: Boolean; A: Cardinal; B: Cardinal): Cardinal; +{* ֽڱִʱ̶жѡCondtion Ϊ True ʱ A򷵻 B + + + Condition: Boolean - Ƿѡ A ҲDzһ + A: Cardinal - ѡ 32 λһ + B: Cardinal - ѡ 32 λ + + ֵCardinal - ѡ 32 λ +} + +function ConstTimeConditionalSelect64(Condition: Boolean; A: TUInt64; B: TUInt64): TUInt64; +{* ֽڱִʱ̶жѡCondtion Ϊ True ʱ A򷵻 B + + + Condition: Boolean - Ƿѡ A ҲDzһ + A: TUInt64 - ѡ 64 λһ + B: TUInt64 - ѡ 64 λ + + ֵTUInt64 - ѡ 64 λ +} + +// ================ ִʱ̶ if жϵIJ߼ =============== + +{$IFDEF MSWINDOWS} + +// ĸΪ Intel ֻ֧࣬ 32 λ 64 λ Intel CPUӦCPUX86 CPUX64 + +procedure Int64DivInt32Mod(A: Int64; B: Integer; + var DivRes: Integer; var ModRes: Integer); +{* 64 λз 32 λз̷ DivRes ModRes + б֤ 32 λΧڣ쳣 + + + A: Int64 - + B: Integer - + var DivRes: Integer - + var ModRes: Integer - + + ֵޣ +} + +procedure UInt64DivUInt32Mod(A: TUInt64; B: Cardinal; + var DivRes: Cardinal; var ModRes: Cardinal); +{* 64 λ޷ 32 λ޷̷ DivRes ModRes + б֤ 32 λΧڣ쳣 + + + A: TUInt64 - + B: Cardinal - + var DivRes: Cardinal - + var ModRes: Cardinal - + + ֵޣ +} + +procedure Int128DivInt64Mod(ALo: Int64; AHi: Int64; B: Int64; + var DivRes: Int64; var ModRes: Int64); +{* 128 λз 64 λз̷ DivRes ModRes + б֤ 64 λΧڣ쳣 + + + ALo: Int64 - 64 λ + AHi: Int64 - 64 λ + B: Int64 - + var DivRes: Int64 - + var ModRes: Int64 - + + ֵޣ +} + +procedure UInt128DivUInt64Mod(ALo: TUInt64; AHi: TUInt64; B: TUInt64; + var DivRes: TUInt64; var ModRes: TUInt64); +{* 128 λ޷ 64 λ޷̷ DivRes ModRes + б֤ 64 λΧڣ쳣 + + + ALo: TUInt64 - 64 λ + AHi: TUInt64 - 64 λ + B: TUInt64 - + var DivRes: TUInt64 - + var ModRes: TUInt64 - + + ֵޣ +} + +{$ENDIF} + +function IsUInt128BitSet(Lo: TUInt64; Hi: TUInt64; N: Integer): Boolean; +{* Int64 ƴɵ 128 λ֣ص N λǷΪ 1N 0 127 + + + Lo: TUInt64 - жϵĵ 64 λ + Hi: TUInt64 - жϵĸ 64 λ + N: Integer - жϵλ + + ֵBoolean - ǷΪ 1 +} + +procedure SetUInt128Bit(var Lo: TUInt64; var Hi: TUInt64; N: Integer); +{* Int64 ƴɵ 128 λ֣õ N λΪ 1N 0 127 + + + var Lo: TUInt64 - õĵ 64 λ + var Hi: TUInt64 - õĸ 64 λ + N: Integer - õλ + + ֵޣ +} + +procedure ClearUInt128Bit(var Lo: TUInt64; var Hi: TUInt64; N: Integer); +{* Int64 ƴɵ 128 λ֣ N λN 0 127 + + + var Lo: TUInt64 - õĵ 64 λ + var Hi: TUInt64 - õĸ 64 λ + N: Integer - õλ + + ֵޣ +} + +function UnsignedAddWithLimitRadix(A: Cardinal; B: Cardinal; C: Cardinal; + var R: Cardinal; L: Cardinal; H: Cardinal): Cardinal; +{* Ƶ޷żӷA + B + C R Уؽλֵ + ȷ L H ıڣûȷ H LΡ + úַӳ䣬 C һǽλ + + + A: Cardinal - һ + B: Cardinal - + C: Cardinal - һǽλ + var R: Cardinal - + L: Cardinal - ͵ + H: Cardinal - ͵ + + ֵCardinal - Ƿнλ +} + +// =========================== ѭλ ==================================== + +// ע N Ӧ (0, A λ) ڣ N Ϊ 0 A λʱֵӦΪ A +// N ʱࣨΪͲȲͬ 32 λ AN Ϊ 33 ʱֵ N Ϊ 1 ʱķֵ + +function RotateLeft16(A: Word; N: Integer): Word; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 16 λѭ N λ + + + A: Word - ѭƵ 16 λ + N: Integer - ѭƵλ + + ֵWord - λֵ +} + +function RotateRight16(A: Word; N: Integer): Word; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 16 λѭ N λ + + + A: Word - ѭƵ 16 λ + N: Integer - ѭƵλ + + ֵWord - λֵ +} + +function RotateLeft32(A: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 32 λѭ N λ + + + A: Cardinal - ѭƵ 32 λ + N: Integer - ѭƵλ + + ֵCardinal - λֵ +} + +function RotateRight32(A: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 32 λѭ N λ + + + A: Cardinal - ѭƵ 32 λ + N: Integer - ѭƵλ + + ֵCardinal - λֵ +} + +function RotateLeft64(A: TUInt64; N: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 64 λѭ N λ + + + A: TUInt64 - ѭƵ 64 λ + N: Integer - ѭƵλ + + ֵTUInt64 - λֵ +} + +function RotateRight64(A: TUInt64; N: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 64 λѭ N λ + + + A: TUInt64 - ѭƵ 64 λ + N: Integer - ѭƵλ + + ֵTUInt64 - λֵ +} + +{$IFDEF COMPILER5} + +function BoolToStr(Value: Boolean; UseBoolStrs: Boolean = False): string; +{* תΪַDelphi 5 ûи BoolToStr ϡ + + + Value: Boolean - תIJֵ + UseBoolStrs: Boolean - Ƿ񷵻Ӣĵ + + ֵstring - UseBoolStrs Ϊ False ʱ -1 0򷵻 True False +} + +{$ENDIF} + +implementation + +uses + CnFloat; + +resourcestring + SCnErrorNotAHexPChar = 'Error: NOT a Hex PChar: %c'; + SCnErrorLengthNotHex = 'Error Length %d: NOT a Hex String'; + SCnErrorLengthNotHexAnsi = 'Error Length %d: NOT a Hex AnsiString'; + +var + FByteOrderIsBigEndian: Boolean = False; + +function CurrentByteOrderIsBigEndian: Boolean; +type + TByteOrder = packed record + case Boolean of + False: (C: array[0..1] of Byte); + True: (W: Word); + end; +var + T: TByteOrder; +begin + T.W := $00CC; + Result := T.C[1] = $CC; +end; + +function CurrentByteOrderIsLittleEndian: Boolean; +begin + Result := not CurrentByteOrderIsBigEndian; +end; + +function ReverseInt64(Value: Int64): Int64; +var + Lo, Hi: Cardinal; + Rec: Int64Rec; +begin + Lo := Int64Rec(Value).Lo; + Hi := Int64Rec(Value).Hi; + Lo := ((Lo and $000000FF) shl 24) or ((Lo and $0000FF00) shl 8) + or ((Lo and $00FF0000) shr 8) or ((Lo and $FF000000) shr 24); + Hi := ((Hi and $000000FF) shl 24) or ((Hi and $0000FF00) shl 8) + or ((Hi and $00FF0000) shr 8) or ((Hi and $FF000000) shr 24); + Rec.Lo := Hi; + Rec.Hi := Lo; + Result := Int64(Rec); +end; + +function ReverseUInt64(Value: TUInt64): TUInt64; +var + Lo, Hi: Cardinal; + Rec: Int64Rec; +begin + Lo := Int64Rec(Value).Lo; + Hi := Int64Rec(Value).Hi; + Lo := ((Lo and $000000FF) shl 24) or ((Lo and $0000FF00) shl 8) + or ((Lo and $00FF0000) shr 8) or ((Lo and $FF000000) shr 24); + Hi := ((Hi and $000000FF) shl 24) or ((Hi and $0000FF00) shl 8) + or ((Hi and $00FF0000) shr 8) or ((Hi and $FF000000) shr 24); + Rec.Lo := Hi; + Rec.Hi := Lo; + Result := TUInt64(Rec); +end; + +function Int64ToBigEndian(Value: Int64): Int64; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := ReverseInt64(Value); +end; + +function Int32ToBigEndian(Value: Integer): Integer; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := Integer((Value and $000000FF) shl 24) or Integer((Value and $0000FF00) shl 8) + or Integer((Value and $00FF0000) shr 8) or Integer((Value and $FF000000) shr 24); +end; + +function Int16ToBigEndian(Value: SmallInt): SmallInt; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := SmallInt((Value and $00FF) shl 8) or SmallInt((Value and $FF00) shr 8); +end; + +function Int64ToLittleEndian(Value: Int64): Int64; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := ReverseInt64(Value); +end; + +function Int32ToLittleEndian(Value: Integer): Integer; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := Integer((Value and $000000FF) shl 24) or Integer((Value and $0000FF00) shl 8) + or Integer((Value and $00FF0000) shr 8) or Integer((Value and $FF000000) shr 24); +end; + +function Int16ToLittleEndian(Value: SmallInt): SmallInt; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := SmallInt((Value and $00FF) shl 8) or SmallInt((Value and $FF00) shr 8); +end; + +function UInt64ToBigEndian(Value: TUInt64): TUInt64; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := ReverseUInt64(Value); +end; + +function UInt32ToBigEndian(Value: Cardinal): Cardinal; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := Cardinal((Value and $000000FF) shl 24) or Cardinal((Value and $0000FF00) shl 8) + or Cardinal((Value and $00FF0000) shr 8) or Cardinal((Value and $FF000000) shr 24); +end; + +function UInt16ToBigEndian(Value: Word): Word; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := Word((Value and $00FF) shl 8) or Word((Value and $FF00) shr 8); +end; + +function UInt64ToLittleEndian(Value: TUInt64): TUInt64; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := ReverseUInt64(Value); +end; + +function UInt32ToLittleEndian(Value: Cardinal): Cardinal; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := Cardinal((Value and $000000FF) shl 24) or Cardinal((Value and $0000FF00) shl 8) + or Cardinal((Value and $00FF0000) shr 8) or Cardinal((Value and $FF000000) shr 24); +end; + +function UInt16ToLittleEndian(Value: Word): Word; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := Word((Value and $00FF) shl 8) or Word((Value and $FF00) shr 8); +end; + +function Int64HostToNetwork(Value: Int64): Int64; +begin + if not FByteOrderIsBigEndian then + Result := ReverseInt64(Value) + else + Result := Value; +end; + +function Int32HostToNetwork(Value: Integer): Integer; +begin + if not FByteOrderIsBigEndian then + Result := Integer((Value and $000000FF) shl 24) or Integer((Value and $0000FF00) shl 8) + or Integer((Value and $00FF0000) shr 8) or Integer((Value and $FF000000) shr 24) + else + Result := Value; +end; + +function Int16HostToNetwork(Value: SmallInt): SmallInt; +begin + if not FByteOrderIsBigEndian then + Result := SmallInt((Value and $00FF) shl 8) or SmallInt((Value and $FF00) shr 8) + else + Result := Value; +end; + +function Int64NetworkToHost(Value: Int64): Int64; +begin + if not FByteOrderIsBigEndian then + REsult := ReverseInt64(Value) + else + Result := Value; +end; + +function Int32NetworkToHost(Value: Integer): Integer; +begin + if not FByteOrderIsBigEndian then + Result := Integer((Value and $000000FF) shl 24) or Integer((Value and $0000FF00) shl 8) + or Integer((Value and $00FF0000) shr 8) or Integer((Value and $FF000000) shr 24) + else + Result := Value; +end; + +function Int16NetworkToHost(Value: SmallInt): SmallInt; +begin + if not FByteOrderIsBigEndian then + Result := SmallInt((Value and $00FF) shl 8) or SmallInt((Value and $FF00) shr 8) + else + Result := Value; +end; + +function UInt64HostToNetwork(Value: TUInt64): TUInt64; +begin + if CurrentByteOrderIsBigEndian then + Result := Value + else + Result := ReverseUInt64(Value); +end; + +function UInt32HostToNetwork(Value: Cardinal): Cardinal; +begin + if not FByteOrderIsBigEndian then + Result := Cardinal((Value and $000000FF) shl 24) or Cardinal((Value and $0000FF00) shl 8) + or Cardinal((Value and $00FF0000) shr 8) or Cardinal((Value and $FF000000) shr 24) + else + Result := Value; +end; + +function UInt16HostToNetwork(Value: Word): Word; +begin + if not FByteOrderIsBigEndian then + Result := ((Value and $00FF) shl 8) or ((Value and $FF00) shr 8) + else + Result := Value; +end; + +function UInt64NetworkToHost(Value: TUInt64): TUInt64; +begin + if CurrentByteOrderIsBigEndian then + Result := Value + else + Result := ReverseUInt64(Value); +end; + +function UInt32NetworkToHost(Value: Cardinal): Cardinal; +begin + if not FByteOrderIsBigEndian then + Result := Cardinal((Value and $000000FF) shl 24) or Cardinal((Value and $0000FF00) shl 8) + or Cardinal((Value and $00FF0000) shr 8) or Cardinal((Value and $FF000000) shr 24) + else + Result := Value; +end; + +function UInt16NetworkToHost(Value: Word): Word; +begin + if not FByteOrderIsBigEndian then + Result := ((Value and $00FF) shl 8) or ((Value and $FF00) shr 8) + else + Result := Value; +end; + +function ReverseBitsInInt8(V: Byte): Byte; +begin + // 0 1 2 3 4 5 6 7 + V := ((V and $AA) shr 1) or ((V and $55) shl 1); + // 01 23 45 67 + V := ((V and $CC) shr 2) or ((V and $33) shl 2); + // 0123 4567 + V := (V shr 4) or (V shl 4); + Result := V; +end; + +function ReverseBitsInInt16(V: Word): Word; +begin + Result := (ReverseBitsInInt8(V and $00FF) shl 8) + or ReverseBitsInInt8((V and $FF00) shr 8); +end; + +function ReverseBitsInInt32(V: Cardinal): Cardinal; +begin + Result := (ReverseBitsInInt16(V and $0000FFFF) shl 16) + or ReverseBitsInInt16((V and $FFFF0000) shr 16); +end; + +function ReverseBitsInInt64(V: Int64): Int64; +begin + Result := (Int64(ReverseBitsInInt32(V and $00000000FFFFFFFF)) shl 32) + or ReverseBitsInInt32((V and $FFFFFFFF00000000) shr 32); +end; + +procedure ReverseMemory(Mem: Pointer; MemByteLen: Integer); +var + I, L: Integer; + P: PByteArray; + T: Byte; +begin + if (Mem = nil) or (MemByteLen < 2) then + Exit; + + L := MemByteLen div 2; + P := PByteArray(Mem); + for I := 0 to L - 1 do + begin + // I ͵ MemLen - I - 1 + T := P^[I]; + P^[I] := P^[MemByteLen - I - 1]; + P^[MemByteLen - I - 1] := T; + end; +end; + +procedure ReverseMemoryWithBits(Mem: Pointer; MemByteLen: Integer); +var + I: Integer; + P: PByteArray; +begin + if (Mem = nil) or (MemByteLen <= 0) then + Exit; + + ReverseMemory(Mem, MemByteLen); + P := PByteArray(Mem); + + for I := 0 to MemByteLen - 1 do + P^[I] := ReverseBitsInInt8(P^[I]); +end; + +procedure MemoryNetworkToHost(Mem: Pointer; MemByteLen: Integer); +begin + if not FByteOrderIsBigEndian then + ReverseMemory(Mem, MemByteLen); +end; + +procedure MemoryHostToNetwork(Mem: Pointer; MemByteLen: Integer); +begin + if not FByteOrderIsBigEndian then + ReverseMemory(Mem, MemByteLen); +end; + +// N ֽڳȵڴλ +procedure MemoryBitOperation(AMem, BMem, RMem: Pointer; N: Integer; Op: TCnBitOperation); +var + A, B, R: PCnLongWord32Array; + BA, BB, BR: PByteArray; +begin + if N <= 0 then + Exit; + + if (AMem = nil) or ((BMem = nil) and (Op <> boNot)) or (RMem = nil) then + Exit; + + A := PCnLongWord32Array(AMem); + B := PCnLongWord32Array(BMem); + R := PCnLongWord32Array(RMem); + + while (N and (not 3)) <> 0 do + begin + case Op of + boAnd: + R^[0] := A^[0] and B^[0]; + boOr: + R^[0] := A^[0] or B^[0]; + boXor: + R^[0] := A^[0] xor B^[0]; + boNot: // ʱ B + R^[0] := not A^[0]; + end; + + A := PCnLongWord32Array(TCnNativeInt(A) + SizeOf(Cardinal)); + B := PCnLongWord32Array(TCnNativeInt(B) + SizeOf(Cardinal)); + R := PCnLongWord32Array(TCnNativeInt(R) + SizeOf(Cardinal)); + + Dec(N, SizeOf(Cardinal)); + end; + + if N > 0 then + begin + BA := PByteArray(A); + BB := PByteArray(B); + BR := PByteArray(R); + + while N <> 0 do + begin + case Op of + boAnd: + BR^[0] := BA^[0] and BB^[0]; + boOr: + BR^[0] := BA^[0] or BB^[0]; + boXor: + BR^[0] := BA^[0] xor BB^[0]; + boNot: + BR^[0] := not BA^[0]; + end; + + BA := PByteArray(TCnNativeInt(BA) + SizeOf(Byte)); + BB := PByteArray(TCnNativeInt(BB) + SizeOf(Byte)); + BR := PByteArray(TCnNativeInt(BR) + SizeOf(Byte)); + Dec(N); + end; + end; +end; + +procedure MemoryAnd(AMem, BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +begin + MemoryBitOperation(AMem, BMem, ResMem, MemByteLen, boAnd); +end; + +procedure MemoryOr(AMem, BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +begin + MemoryBitOperation(AMem, BMem, ResMem, MemByteLen, boOr); +end; + +procedure MemoryXor(AMem, BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +begin + MemoryBitOperation(AMem, BMem, ResMem, MemByteLen, boXor); +end; + +procedure MemoryNot(Mem: Pointer; MemByteLen: Integer; ResMem: Pointer); +begin + MemoryBitOperation(Mem, nil, ResMem, MemByteLen, boNot); +end; + +procedure MemoryShiftLeft(AMem, BMem: Pointer; MemByteLen: Integer; BitCount: Integer); +var + I, L, N, LB, RB: Integer; + PF, PT: PByteArray; +begin + if (AMem = nil) or (MemByteLen <= 0) or (BitCount = 0) then + Exit; + + if BitCount < 0 then + begin + MemoryShiftRight(AMem, BMem, MemByteLen, -BitCount); + Exit; + end; + + if BMem = nil then + BMem := AMem; + + if (MemByteLen * 8) <= BitCount then // ̫಻ȫ 0 + begin + FillChar(BMem^, MemByteLen, 0); + Exit; + end; + + N := BitCount div 8; // λֽ + RB := BitCount mod 8; // ȥֽںʣµλ + LB := 8 - RB; // ʣµλһֽʣµλ + + PF := PByteArray(AMem); + PT := PByteArray(BMem); + + if RB = 0 then // 飬ð죬Ҫλֽ MemLen - NW + begin + Move(PF^[N], PT^[0], MemByteLen - N); + FillChar(PT^[MemByteLen - N], N, 0); + end + else + begin + // PF^[N] PT^[0] MemLen - N ֽڣֽڼн + L := MemByteLen - N; + PF := PByteArray(TCnNativeInt(PF) + N); + + for I := 1 to L do // ӵλƶȴ͵ + begin + PT^[0] := Byte(PF^[0] shl RB); + if I < L then // һֽ PF^[1] ᳬ + PT^[0] := (PF^[1] shr LB) or PT^[0]; + + PF := PByteArray(TCnNativeInt(PF) + 1); + PT := PByteArray(TCnNativeInt(PT) + 1); + end; + + // ʣµҪ 0 + if N > 0 then + FillChar(PT^[0], N, 0); + end; +end; + +procedure MemoryShiftRight(AMem, BMem: Pointer; MemByteLen: Integer; BitCount: Integer); +var + I, L, N, LB, RB: Integer; + PF, PT: PByteArray; +begin + if (AMem = nil) or (MemByteLen <= 0) or (BitCount = 0) then + Exit; + + if BitCount < 0 then + begin + MemoryShiftLeft(AMem, BMem, MemByteLen, -BitCount); + Exit; + end; + + if BMem = nil then + BMem := AMem; + + if (MemByteLen * 8) <= BitCount then // ̫಻ȫ 0 + begin + FillChar(BMem^, MemByteLen, 0); + Exit; + end; + + N := BitCount div 8; // λֽ + RB := BitCount mod 8; // ȥֽںʣµλ + LB := 8 - RB; // ʣµλһֽʣµλ + + if RB = 0 then // 飬ð죬Ҫλֽ MemLen - N + begin + PF := PByteArray(AMem); + PT := PByteArray(BMem); + + Move(PF^[0], PT^[N], MemByteLen - N); + FillChar(PT^[0], N, 0); + end + else + begin + // PF^[0] PT^[N] MemLen - N ֽڣôӸߴʼֽڼн + L := MemByteLen - N; + + PF := PByteArray(TCnNativeInt(AMem) + L - 1); + PT := PByteArray(TCnNativeInt(BMem) + MemByteLen - 1); + + for I := L downto 1 do // Ӹλλƶȴ + begin + PT^[0] := Byte(PF^[0] shr RB); + if I > 1 then // һֽ PF^[-1] ᳬ + begin + PF := PByteArray(TCnNativeInt(PF) - 1); + PT^[0] := (PF^[0] shl LB) or PT^[0]; + end + else + PF := PByteArray(TCnNativeInt(PF) - 1); + + PT := PByteArray(TCnNativeInt(PT) - 1); + end; + + // ʣµǰҪ 0 + if N > 0 then + FillChar(BMem^, N, 0); + end; +end; + +function MemoryIsBitSet(Mem: Pointer; N: Integer): Boolean; +var + P: PByte; + A, B: Integer; + V: Byte; +begin + if (Mem = nil) or (N < 0) then + raise ERangeError.Create(SRangeError); + + A := N div 8; + B := N mod 8; + P := PByte(TCnNativeInt(Mem) + A); + + V := Byte(1 shl B); + Result := (P^ and V) <> 0; +end; + +procedure MemorySetBit(Mem: Pointer; N: Integer); +var + P: PByte; + A, B: Integer; + V: Byte; +begin + if (Mem = nil) or (N < 0) then + raise ERangeError.Create(SRangeError); + + A := N div 8; + B := N mod 8; + P := PByte(TCnNativeInt(Mem) + A); + + V := Byte(1 shl B); + P^ := P^ or V; +end; + +procedure MemoryClearBit(Mem: Pointer; N: Integer); +var + P: PByte; + A, B: Integer; + V: Byte; +begin + if (Mem = nil) or (N < 0) then + raise ERangeError.Create(SRangeError); + + A := N div 8; + B := N mod 8; + P := PByte(TCnNativeInt(Mem) + A); + + V := not Byte(1 shl B); + P^ := P^ and V; +end; + +function MemoryToBinStr(Mem: Pointer; MemByteLen: Integer; Sep: Boolean): string; +var + J, L: Integer; + P: PByteArray; + B: PChar; + + procedure FillAByteToBuf(V: Byte; Buf: PChar); + const + M = $80; + var + I: Integer; + begin + for I := 0 to 7 do + begin + if (V and M) <> 0 then + Buf[I] := '1' + else + Buf[I] := '0'; + V := V shl 1; + end; + end; + +begin + Result := ''; + if (Mem = nil) or (MemByteLen <= 0) then + Exit; + + L := MemByteLen * 8; + if Sep then + L := L + MemByteLen - 1; // мÿոָ + + SetLength(Result, L); + B := PChar(@Result[1]); + P := PByteArray(Mem); + + for J := 0 to MemByteLen - 1 do + begin + FillAByteToBuf(P^[J], B); + if Sep then + begin + B[8] := ' '; + Inc(B, 9); + end + else + Inc(B, 8); + end; +end; + +procedure MemorySwap(AMem, BMem: Pointer; MemByteLen: Integer); +var + A, B: PCnLongWord32Array; + BA, BB: PByteArray; + TC: Cardinal; + TB: Byte; +begin + if (AMem = nil) or (BMem = nil) or (MemByteLen <= 0) then + Exit; + + A := PCnLongWord32Array(AMem); + B := PCnLongWord32Array(BMem); + + if A = B then + Exit; + + while (MemByteLen and (not 3)) <> 0 do + begin + TC := A^[0]; + A^[0] := B^[0]; + B^[0] := TC; + + A := PCnLongWord32Array(TCnNativeInt(A) + SizeOf(Cardinal)); + B := PCnLongWord32Array(TCnNativeInt(B) + SizeOf(Cardinal)); + + Dec(MemByteLen, SizeOf(Cardinal)); + end; + + if MemByteLen > 0 then + begin + BA := PByteArray(A); + BB := PByteArray(B); + + while MemByteLen <> 0 do + begin + TB := BA^[0]; + BA^[0] := BB^[0]; + BB^[0] :=TB; + + BA := PByteArray(TCnNativeInt(BA) + SizeOf(Byte)); + BB := PByteArray(TCnNativeInt(BB) + SizeOf(Byte)); + + Dec(MemByteLen); + end; + end; +end; + +function MemoryCompare(AMem, BMem: Pointer; MemByteLen: Integer): Integer; +var + A, B: PCnLongWord32Array; + BA, BB: PByteArray; +begin + Result := 0; + if ((AMem = nil) and (BMem = nil)) or (AMem = BMem) then // ͬһ + Exit; + + if MemByteLen <= 0 then + Exit; + + if AMem = nil then + begin + Result := -1; + Exit; + end; + if BMem = nil then + begin + Result := 1; + Exit; + end; + + A := PCnLongWord32Array(AMem); + B := PCnLongWord32Array(BMem); + + while (MemByteLen and (not 3)) <> 0 do + begin + if A^[0] > B^[0] then + begin + Result := 1; + Exit; + end + else if A^[0] < B^[0] then + begin + Result := -1; + Exit; + end; + + A := PCnLongWord32Array(TCnNativeInt(A) + SizeOf(Cardinal)); + B := PCnLongWord32Array(TCnNativeInt(B) + SizeOf(Cardinal)); + + Dec(MemByteLen, SizeOf(Cardinal)); + end; + + if MemByteLen > 0 then + begin + BA := PByteArray(A); + BB := PByteArray(B); + + while MemByteLen <> 0 do + begin + if BA^[0] > BB^[0] then + begin + Result := 1; + Exit; + end + else if BA^[0] < BB^[0] then + begin + Result := -1; + Exit; + end; + + BA := PByteArray(TCnNativeInt(BA) + SizeOf(Byte)); + BB := PByteArray(TCnNativeInt(BB) + SizeOf(Byte)); + + Dec(MemByteLen); + end; + end; +end; + +function UInt8ToBinStr(V: Byte): string; +const + M = $80; +var + I: Integer; +begin + SetLength(Result, 8 * SizeOf(V)); + for I := 1 to 8 * SizeOf(V) do + begin + if (V and M) <> 0 then + Result[I] := '1' + else + Result[I] := '0'; + V := V shl 1; + end; +end; + +function UInt16ToBinStr(V: Word): string; +const + M = $8000; +var + I: Integer; +begin + SetLength(Result, 8 * SizeOf(V)); + for I := 1 to 8 * SizeOf(V) do + begin + if (V and M) <> 0 then + Result[I] := '1' + else + Result[I] := '0'; + V := V shl 1; + end; +end; + +function UInt32ToBinStr(V: Cardinal): string; +const + M = $80000000; +var + I: Integer; +begin + SetLength(Result, 8 * SizeOf(V)); + for I := 1 to 8 * SizeOf(V) do + begin + if (V and M) <> 0 then + Result[I] := '1' + else + Result[I] := '0'; + V := V shl 1; + end; +end; + +function UInt32ToStr(V: Cardinal): string; +begin + Result := Format('%u', [V]); +end; + +function UInt64ToBinStr(V: TUInt64): string; +const + M = $8000000000000000; +var + I: Integer; +begin + SetLength(Result, 8 * SizeOf(V)); + + for I := 1 to 8 * SizeOf(V) do + begin + if (V and M) <> 0 then + Result[I] := '1' + else + Result[I] := '0'; + V := V shl 1; + end; +end; + +const + HiDigits: array[0..15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); +const + LoDigits: array[0..15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); + +const + AnsiHiDigits: array[0..15] of AnsiChar = ('0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); +const + AnsiLoDigits: array[0..15] of AnsiChar = ('0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); + +function HexToInt(Hex: PChar; CharLen: Integer): Integer; +var + I, Res: Integer; + C: Char; +begin + Res := 0; + for I := 0 to CharLen - 1 do + begin + C := Hex[I]; + if (C >= '0') and (C <= '9') then + Res := Res * 16 + Ord(C) - Ord('0') + else if (C >= 'A') and (C <= 'F') then + Res := Res * 16 + Ord(C) - Ord('A') + 10 + else if (C >= 'a') and (C <= 'f') then + Res := Res * 16 + Ord(C) - Ord('a') + 10 + else + raise ECnNativeException.CreateFmt(SCnErrorNotAHexPChar, [C]); + end; + Result := Res; +end; + +function HexToInt(const Hex: string): Integer; +begin + Result := HexToInt(PChar(Hex), Length(Hex)); +end; + +{$WARNINGS OFF} + +function IsHexString(const Hex: string): Boolean; +var + I, L: Integer; +begin + Result := False; + L := Length(Hex); + if (L <= 0) or ((L and 1) <> 0) then // ջżȶ + Exit; + + for I := 1 to L do + begin + // ע˴ Unicode Ȼ Warningǽ Hex[I] WideChar ֱӽض AnsiChar + // ٽжϣᵼ¡޻ޡ $66$66$66$66 ַУ + // ֱͨ WideChar ֵ ax ˫ֽڵģӼжϣ + if not (Hex[I] in ['0'..'9', 'A'..'F', 'a'..'f']) then + Exit; + end; + Result := True; +end; + +{$WARNINGS ON} + +function DataToHex(InData: Pointer; ByteLength: Integer; UseUpperCase: Boolean = True): string; +var + I: Integer; + B: Byte; +begin + Result := ''; + if ByteLength <= 0 then + Exit; + + SetLength(Result, ByteLength * 2); + if UseUpperCase then + begin + for I := 0 to ByteLength - 1 do + begin + B := PByte(TCnNativeInt(InData) + I * SizeOf(Byte))^; + Result[I * 2 + 1] := HiDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := HiDigits[B and $0F]; + end; + end + else + begin + for I := 0 to ByteLength - 1 do + begin + B := PByte(TCnNativeInt(InData) + I * SizeOf(Byte))^; + Result[I * 2 + 1] := LoDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := LoDigits[B and $0F]; + end; + end; +end; + +function HexToData(const Hex: string; OutData: Pointer): Integer; +var + I, L: Integer; + H: PChar; +begin + L := Length(Hex); + if (L mod 2) <> 0 then + raise ECnNativeException.CreateFmt(SCnErrorLengthNotHex, [L]); + + if OutData = nil then + begin + Result := L div 2; + Exit; + end; + + Result := 0; + H := PChar(Hex); + for I := 1 to L div 2 do + begin + PByte(TCnNativeInt(OutData) + I - 1)^ := Byte(HexToInt(@H[(I - 1) * 2], 2)); + Inc(Result); + end; +end; + +function StringToHex(const Data: string; UseUpperCase: Boolean): string; +var + I, L: Integer; + B: Byte; + Buffer: PChar; +begin + Result := ''; + L := Length(Data); + if L = 0 then + Exit; + + SetLength(Result, L * 2); + Buffer := @Data[1]; + + if UseUpperCase then + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnNativeInt(Buffer) + I * SizeOf(Char))^; + Result[I * 2 + 1] := HiDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := HiDigits[B and $0F]; + end; + end + else + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnNativeInt(Buffer) + I * SizeOf(Char))^; + Result[I * 2 + 1] := LoDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := LoDigits[B and $0F]; + end; + end; +end; + +function HexToString(const Hex: string): string; +var + I, L: Integer; + H: PChar; +begin + L := Length(Hex); + if (L mod 2) <> 0 then + raise ECnNativeException.CreateFmt(SCnErrorLengthNotHex, [L]); + + SetLength(Result, L div 2); + H := PChar(Hex); + for I := 1 to L div 2 do + Result[I] := Chr(HexToInt(@H[(I - 1) * 2], 2)); +end; + +function HexToAnsiStr(const Hex: AnsiString): AnsiString; +var + I, L: Integer; + S: string; +begin + L := Length(Hex); + if (L mod 2) <> 0 then + raise ECnNativeException.CreateFmt(SCnErrorLengthNotHexAnsi, [L]); + + SetLength(Result, L div 2); + for I := 1 to L div 2 do + begin + S := string(Copy(Hex, I * 2 - 1, 2)); + Result[I] := AnsiChar(Chr(HexToInt(S))); + end; +end; + +function AnsiStrToHex(const Data: AnsiString; UseUpperCase: Boolean): AnsiString; +var + I, L: Integer; + B: Byte; + Buffer: PAnsiChar; +begin + Result := ''; + L := Length(Data); + if L = 0 then + Exit; + + SetLength(Result, L * 2); + Buffer := @Data[1]; + + if UseUpperCase then + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnNativeInt(Buffer) + I)^; + Result[I * 2 + 1] := AnsiHiDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := AnsiHiDigits[B and $0F]; + end; + end + else + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnNativeInt(Buffer) + I)^; + Result[I * 2 + 1] := AnsiLoDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := AnsiLoDigits[B and $0F]; + end; + end; +end; + +function BytesToHex(Data: TBytes; UseUpperCase: Boolean): string; +var + I, L: Integer; + B: Byte; + Buffer: PAnsiChar; +begin + Result := ''; + L := Length(Data); + if L = 0 then + Exit; + + SetLength(Result, L * 2); + Buffer := @Data[0]; + + if UseUpperCase then + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnNativeInt(Buffer) + I)^; + Result[I * 2 + 1] := HiDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := HiDigits[B and $0F]; + end; + end + else + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnNativeInt(Buffer) + I)^; + Result[I * 2 + 1] := LoDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := LoDigits[B and $0F]; + end; + end; +end; + +function HexToBytes(const Hex: string): TBytes; +var + I, L: Integer; + H: PChar; +begin + L := Length(Hex); + if (L mod 2) <> 0 then + raise ECnNativeException.CreateFmt(SCnErrorLengthNotHex, [L]); + + SetLength(Result, L div 2); + H := PChar(Hex); + + for I := 1 to L div 2 do + Result[I - 1] := Byte(HexToInt(@H[(I - 1) * 2], 2)); +end; + +function StreamToHex(Stream: TStream; UseUpperCase: Boolean): string; +var + B: Byte; + I: Integer; +begin + Result := ''; + if Stream.Size > 0 then + begin + Stream.Position := 0; + SetLength(Result, Stream.Size * 2); + I := 1; + if UseUpperCase then + begin + while Stream.Read(B, 1) = 1 do + begin + Result[I] := HiDigits[(B shr 4) and $0F]; + Inc(I); + Result[I] := HiDigits[B and $0F]; + Inc(I); + end; + end + else + begin + while Stream.Read(B, 1) = 1 do + begin + Result[I] := LoDigits[(B shr 4) and $0F]; + Inc(I); + Result[I] := LoDigits[B and $0F]; + Inc(I); + end; + end; + end; +end; + +function HexToStream(const Hex: string; Stream: TStream): Integer; +var + I, L: Integer; + H: PChar; + B: Byte; +begin + Result := 0; + L := Length(Hex); + if (L mod 2) <> 0 then + raise ECnNativeException.CreateFmt(SCnErrorLengthNotHex, [L]); + + H := PChar(Hex); + for I := 1 to L div 2 do + begin + B := Byte(HexToInt(@H[(I - 1) * 2], 2)); + Inc(Result, Stream.Write(B, 1)); + end; +end; + +procedure ReverseBytes(Data: TBytes); +var + I, L, M: Integer; + T: Byte; +begin + if (Data = nil) or (Length(Data) <= 1) then + Exit; + L := Length(Data); + M := L div 2; + for I := 0 to M - 1 do + begin + // I L - I - 1 + T := Data[I]; + Data[I] := Data[L - I - 1]; + Data[L - I - 1] := T; + end; +end; + +function CloneBytes(Data: TBytes): TBytes; +begin + if Length(Data) = 0 then + Result := nil + else + begin + SetLength(Result, Length(Data)); + Move(Data[0], Result[0], Length(Data)); + end; +end; + +function StreamToBytes(Stream: TStream): TBytes; +begin + Result := nil; + if (Stream <> nil) and (Stream.Size > 0) then + begin + SetLength(Result, Stream.Size); + Stream.Position := 0; + Stream.Read(Result[0], Stream.Size); + end; +end; + +function BytesToStream(Data: TBytes; OutStream: TStream): Integer; +begin + Result := 0; + if (Data <> nil) and (Length(Data) > 0) and (OutStream <> nil) then + begin + OutStream.Size := 0; + Result := OutStream.Write(Data[0], Length(Data)); + end; +end; + +function AnsiToBytes(const Str: AnsiString): TBytes; +begin + SetLength(Result, Length(Str)); + if Length(Str) > 0 then + Move(Str[1], Result[0], Length(Str)); +end; + +function BytesToAnsi(Data: TBytes): AnsiString; +begin + SetLength(Result, Length(Data)); + if Length(Data) > 0 then + Move(Data[0], Result[1], Length(Data)); +end; + +function BytesToString(Data: TBytes): string; +var + I: Integer; +begin + SetLength(Result, Length(Data)); + for I := 1 to Length(Data) do + Result[I] := Chr(Data[I - 1]); +end; + +function MemoryToString(Mem: Pointer; MemByteLen: Integer): string; +var + P: PByteArray; + I: Integer; +begin + if (Mem = nil) or (MemByteLen <= 0) then + begin + Result := ''; + Exit; + end; + + P := PByteArray(Mem); + SetLength(Result, MemByteLen); + for I := 1 to MemByteLen do + Result[I] := Chr(P^[I - 1]); +end; + +function BitsToString(Bits: TBits): string; +var + I: Integer; +begin + if (Bits = nil) or (Bits.Size = 0) then + Result := '' + else + begin + SetLength(Result, Bits.Size); + for I := 0 to Bits.Size - 1 do + begin + if Bits.Bits[I] then + Result[I + 1] := '1' + else + Result[I + 1] := '0'; + end; + end; +end; + +function ConcatBytes(A, B: TBytes): TBytes; +begin + // XE7 ҲֱӣΪ A B Ϊʱ᷵һֽ + if (A = nil) or (Length(A) = 0) then + begin + SetLength(Result, Length(B)); + if Length(B) > 0 then + Move(B[0], Result[0], Length(B)); + end + else if (B = nil) or (Length(B) = 0) then + begin + SetLength(Result, Length(A)); + if Length(A) > 0 then + Move(A[0], Result[0], Length(A)); + end + else + begin + SetLength(Result, Length(A) + Length(B)); + Move(A[0], Result[0], Length(A)); + Move(B[0], Result[Length(A)], Length(B)); + end; +end; + +function NewBytesFromMemory(Data: Pointer; DataByteLen: Integer): TBytes; +begin + if (Data = nil) or (DataByteLen <= 0) then + Result := nil + else + begin + SetLength(Result, DataByteLen); + Move(Data^, Result[0], DataByteLen); + end; +end; + +function CompareBytes(A, B: TBytes): Boolean; +var + L: Integer; +begin + Result := False; + + L := Length(A); + if Length(B) <> L then // Ȳ˳ + Exit; + + if L = 0 then // + Result := True // 綼 0 + else + Result := CompareMem(@A[0], @B[0], L); +end; + +function CompareBytes(A, B: TBytes; MaxLength: Integer): Boolean; +var + LA, LB: Integer; +begin + Result := False; + + LA := Length(A); + LB := Length(B); + + if LA > MaxLength then + LA := MaxLength; + if LB > MaxLength then + LB := MaxLength; + + if LA <> LB then + Exit; + + if LA = 0 then + Result := True + else + Result := CompareMem(@A[0], @B[0], LA); +end; + +function MoveMost(const Source; var Dest; ByteLen, MostLen: Integer): Integer; +begin + if (MostLen <= 0) or (ByteLen <= 0) then + begin + Result := 0; + Exit; + end; + + if ByteLen > MostLen then + ByteLen := MostLen + else if ByteLen < MostLen then + begin + FillChar(Dest, MostLen, 0); + + // TODO: ҪΪ FillChar(Dest + ByteLen, MostLen - ByteLen, 0); ֻ䲻IJ + end; + + Move(Source, Dest, ByteLen); + Result := ByteLen; +end; + +// =============================== =================================== + +function SarInt8(var V: Byte; ShiftCount: Integer): Byte; +begin + Result := V shr ShiftCount; + if (V and $80) <> 0 then + Result := Result or $80; +end; + +function SarInt16(var V: Word; ShiftCount: Integer): Word; +begin + Result := V shr ShiftCount; + if (V and $8000) <> 0 then + Result := Result or $8000; +end; + +function SarInt32(var V: Cardinal; ShiftCount: Integer): Cardinal; +begin + Result := V shr ShiftCount; + if (V and $80000000) <> 0 then + Result := Result or $80000000; +end; + +function SarInt64(var V: TUInt64; ShiftCount: Integer): TUInt64; +begin + Result := V shr ShiftCount; + if (V and $8000000000000000) <> 0 then + Result := Result or $8000000000000000; +end; + +procedure ConstTimeConditionalSwap8(CanSwap: Boolean; var A, B: Byte); +var + T, V: Byte; +begin + T := ConstTimeExpandBoolean8(CanSwap); + V := (A xor B) and T; + A := A xor V; + B := B xor V; +end; + +procedure ConstTimeConditionalSwap16(CanSwap: Boolean; var A, B: Word); +var + T, V: Word; +begin + T := ConstTimeExpandBoolean16(CanSwap); + V := (A xor B) and T; + A := A xor V; + B := B xor V; +end; + +procedure ConstTimeConditionalSwap32(CanSwap: Boolean; var A, B: Cardinal); +var + T, V: Cardinal; +begin + T := ConstTimeExpandBoolean32(CanSwap); + V := (A xor B) and T; + A := A xor V; + B := B xor V; +end; + +procedure ConstTimeConditionalSwap64(CanSwap: Boolean; var A, B: TUInt64); +var + T, V: TUInt64; +begin + T := ConstTimeExpandBoolean64(CanSwap); + V := (A xor B) and T; + A := A xor V; + B := B xor V; +end; + +function ConstTimeEqual8(A, B: Byte): Boolean; +var + R: Byte; +begin + R := not (A xor B); // + R := R and (R shr 4); // һһ + R := R and (R shr 2); // һλ 0 + R := R and (R shr 1); // 0 + Result := Boolean(R); // ֻȫ 1 1 +end; + +function ConstTimeEqual16(A, B: Word): Boolean; +begin + Result := ConstTimeEqual8(Byte(A shr 8), Byte(B shr 8)) + and ConstTimeEqual8(Byte(A and $FF), Byte(B and $FF)); +end; + +function ConstTimeEqual32(A, B: Cardinal): Boolean; +begin + Result := ConstTimeEqual16(Word(A shr 16), Word(B shr 16)) + and ConstTimeEqual16(Word(A and $FFFF), Word(B and $FFFF)); +end; + +function ConstTimeEqual64(A, B: TUInt64): Boolean; +begin + Result := ConstTimeEqual32(Cardinal(A shr 32), Cardinal(B shr 32)) + and ConstTimeEqual32(Cardinal(A and $FFFFFFFF), Cardinal(B and $FFFFFFFF)); +end; + +function ConstTimeBytesEqual(A, B: TBytes): Boolean; +var + I: Integer; +begin + Result := False; + if Length(A) <> Length(B) then + Exit; + + Result := True; + for I := 0 to Length(A) - 1 do // ÿֽڶȽϣͬ˳ + Result := Result and (ConstTimeEqual8(A[I], B[I])); +end; + +function ConstTimeExpandBoolean8(V: Boolean): Byte; +begin + Result := Byte(V); + Result := not Result; // V True 0˲ R Ǵ $FFR ͷ 0 + Result := Result and (Result shr 4); // һһ + Result := Result and (Result shr 2); // һλ 0 + Result := Result and (Result shr 1); // 00000000 00000001 + Result := Result or (Result shl 1); // True õ 00000000False õ 00000001λ + Result := Result or (Result shl 2); + Result := Result or (Result shl 4); // ȫ 0 ȫ 1 + Result := not Result; // ȫ 1 ȫ 0 +end; + +function ConstTimeExpandBoolean16(V: Boolean): Word; +var + R: Byte; +begin + R := ConstTimeExpandBoolean8(V); + Result := R; + Result := (Result shl 8) or R; // ֽȫ 1 ȫ 0 ˫ֽ +end; + +function ConstTimeExpandBoolean32(V: Boolean): Cardinal; +var + R: Word; +begin + R := ConstTimeExpandBoolean16(V); + Result := R; + Result := (Result shl 16) or R; // ˫ֽȫ 1 ȫ 0 ֽ +end; + +function ConstTimeExpandBoolean64(V: Boolean): TUInt64; +var + R: Cardinal; +begin + R := ConstTimeExpandBoolean32(V); + Result := R; + Result := (Result shl 32) or R; // ֽȫ 1 ȫ 0 ɰֽ +end; + +function ConstTimeConditionalSelect8(Condition: Boolean; A, B: Byte): Byte; +begin + ConstTimeConditionalSwap8(Condition, A, B); + Result := B; +end; + +function ConstTimeConditionalSelect16(Condition: Boolean; A, B: Word): Word; +begin + ConstTimeConditionalSwap16(Condition, A, B); + Result := B; +end; + +function ConstTimeConditionalSelect32(Condition: Boolean; A, B: Cardinal): Cardinal; +begin + ConstTimeConditionalSwap32(Condition, A, B); + Result := B; +end; + +function ConstTimeConditionalSelect64(Condition: Boolean; A, B: TUInt64): TUInt64; +begin + ConstTimeConditionalSwap64(Condition, A, B); + Result := B; +end; + +{$IFDEF MSWINDOWS} + +{$IFDEF CPUX64} + +// 64 λ IDIV IDIV ָʵ֣ A RCX B EDX/RDX DivRes ַ R8 ModRes ַ R9 +procedure Int64DivInt32Mod(A: Int64; B: Integer; var DivRes, ModRes: Integer); assembler; +asm + PUSH RCX // RCX A + MOV RCX, RDX // B RCX + POP RAX // A RAX + XOR RDX, RDX // 64 λ + IDIV RCX + MOV [R8], EAX // ̷ R8 ָ DivRes + MOV [R9], EDX // R9 ָ ModRes +end; + +procedure UInt64DivUInt32Mod(A: TUInt64; B: Cardinal; var DivRes, ModRes: Cardinal); assembler; +asm + PUSH RCX // RCX A + MOV RCX, RDX // B RCX + POP RAX // A RAX + XOR RDX, RDX // 64 λ + DIV RCX + MOV [R8], EAX // ̷ R8 ָ DivRes + MOV [R9], EDX // R9 ָ ModRes +end; + +// 64 λ IDIV IDIV ָʵ֣ALo RCXAHi RDXB R8DivRes ĵַ R9 +procedure Int128DivInt64Mod(ALo, AHi: Int64; B: Int64; var DivRes, ModRes: Int64); assembler; +asm + MOV RAX, RCX // ALo RAXAHi Ѿ RDX + MOV RCX, R8 // B RCX + IDIV RCX + MOV [R9], RAX // ̷ R9 ָ DivRes + MOV RAX, [RBP + $30] // ModRes ַ RAX + MOV [RAX], RDX // RAX ָ ModRes +end; + +procedure UInt128DivUInt64Mod(ALo, AHi: UInt64; B: UInt64; var DivRes, ModRes: UInt64); assembler; +asm + MOV RAX, RCX // ALo RAXAHi Ѿ RDX + MOV RCX, R8 // B RCX + DIV RCX + MOV [R9], RAX // ̷ R9 ָ DivRes + MOV RAX, [RBP + $30] // ModRes ַ RAX + MOV [RAX], RDX // RAX ָ ModRes +end; + +{$ELSE} + +// 32 λ IDIV IDIV ָʵ֣ A ڶջϣB EAXDivRes ַ EDXModRes ַ ECX +procedure Int64DivInt32Mod(A: Int64; B: Integer; var DivRes, ModRes: Integer); assembler; +asm + PUSH ECX // ECX ModRes ַȱ + MOV ECX, B // B EAX УƵ ECX + PUSH EDX // DivRes ĵַ EDX УҲ + MOV EAX, [EBP + $8] // A Lo + MOV EDX, [EBP + $C] // A Hi + IDIV ECX + POP ECX // ECXõ DivRes ַ + MOV [ECX], EAX + POP ECX // ECXõ ModRes ַ + MOV [ECX], EDX +end; + +procedure UInt64DivUInt32Mod(A: TUInt64; B: Cardinal; var DivRes, ModRes: Cardinal); assembler; +asm + PUSH ECX // ECX ModRes ַȱ + MOV ECX, B // B EAX УƵ ECX + PUSH EDX // DivRes ĵַ EDX УҲ + MOV EAX, [EBP + $8] // A Lo + MOV EDX, [EBP + $C] // A Hi + DIV ECX + POP ECX // ECXõ DivRes ַ + MOV [ECX], EAX + POP ECX // ECXõ ModRes ַ + MOV [ECX], EDX +end; + +// 32 λµʵ +procedure Int128DivInt64Mod(ALo, AHi: Int64; B: Int64; var DivRes, ModRes: Int64); +var + C: Integer; +begin + if B = 0 then + raise EDivByZero.Create(SDivByZero); + + if (AHi = 0) or (AHi = $FFFFFFFFFFFFFFFF) then // 64 λΪ 0 ֵֵ + begin + DivRes := ALo div B; + ModRes := ALo mod B; + end + else + begin + if B < 0 then // Ǹ + begin + Int128DivInt64Mod(ALo, AHi, -B, DivRes, ModRes); + DivRes := -DivRes; + Exit; + end; + + if AHi < 0 then // Ǹ + begin + // AHi, ALo 󷴼 1Եõֵ + AHi := not AHi; + ALo := not ALo; +{$IFDEF SUPPORT_UINT64} + UInt64Add(UInt64(ALo), UInt64(ALo), 1, C); +{$ELSE} + UInt64Add(ALo, ALo, 1, C); +{$ENDIF} + if C > 0 then + AHi := AHi + C; + + // ת + Int128DivInt64Mod(ALo, AHi, B, DivRes, ModRes); + + // ٵ + if ModRes = 0 then + DivRes := -DivRes + else + begin + DivRes := -DivRes - 1; + ModRes := B - ModRes; + end; + Exit; + end; + + // ȫ󣬰޷ +{$IFDEF SUPPORT_UINT64} + UInt128DivUInt64Mod(TUInt64(ALo), TUInt64(AHi), TUInt64(B), TUInt64(DivRes), TUInt64(ModRes)); +{$ELSE} + UInt128DivUInt64Mod(ALo, AHi, B, DivRes, ModRes); +{$ENDIF} + end; +end; + +procedure UInt128DivUInt64Mod(ALo, AHi: TUInt64; B: TUInt64; var DivRes, ModRes: TUInt64); +var + I, Cnt: Integer; + Q, R: TUInt64; +begin + if B = 0 then + raise EDivByZero.Create(SDivByZero); + + if AHi = 0 then + begin + DivRes := UInt64Div(ALo, B); + ModRes := UInt64Mod(ALo, B); + end + else + begin + // иλеλզ죿жǷ AHi >= BʾҪ 64 λ + if UInt64Compare(AHi, B) >= 0 then + raise EIntOverflow.Create(SIntOverflow); + + Q := 0; + R := 0; + Cnt := GetUInt64LowBits(AHi) + 64; + for I := Cnt downto 0 do + begin + R := R shl 1; + if IsUInt128BitSet(ALo, AHi, I) then // ĵ I λǷ 0 + R := R or 1 + else + R := R and TUInt64(not 1); + + if UInt64Compare(R, B) >= 0 then + begin + R := R - B; + Q := Q or (TUInt64(1) shl I); + end; + end; + DivRes := Q; + ModRes := R; + end; +end; + +{$ENDIF} + +{$ENDIF} + +{$IFDEF SUPPORT_UINT64} + +// ֻҪ֧ 64 λ޷ 32/64 λ Intel ARM Delphi FPCʲôϵͳ + +function UInt64Mod(A, B: TUInt64): TUInt64; +begin + Result := A mod B; +end; + +function UInt64Div(A, B: TUInt64): TUInt64; +begin + Result := A div B; +end; + +{$ELSE} +{ + ֧ UInt64 ĵͰ汾 Delphi Int64 A mod/div B + + õջ˳ A ĸλA ĵλB ĸλB ĵλ push ϲ뺯 + ESP ǷصַESP+4 B ĵλESP + 8 B ĸλESP + C A ĵλESP + 10 A ĸλ + push esp ESP 4Ȼ mov ebp esp֮ EBP ѰַȫҪ 4 + + System.@_llumod ҪڸսʱEAX <- A ĵλEDX <- A ĸλSystem Դע EAX/EDX дˣ + [ESP + 8]Ҳ EBP + C<- B ĸλ[ESP + 4] Ҳ EBP + 8<- B ĵλ + + CALL ǰľƴ롣UInt64 Div Ҳ +} +function UInt64Mod(A, B: TUInt64): TUInt64; +asm + // PUSH ESP ESP 4Ҫ + MOV EAX, [EBP + $10] // A Lo + MOV EDX, [EBP + $14] // A Hi + PUSH DWORD PTR[EBP + $C] // B Hi + PUSH DWORD PTR[EBP + $8] // B Lo + CALL System.@_llumod; +end; + +function UInt64Div(A, B: TUInt64): TUInt64; +asm + // PUSH ESP ESP 4Ҫ + MOV EAX, [EBP + $10] // A Lo + MOV EDX, [EBP + $14] // A Hi + PUSH DWORD PTR[EBP + $C] // B Hi + PUSH DWORD PTR[EBP + $8] // B Lo + CALL System.@_lludiv; +end; + +{$ENDIF} + +{$IFDEF SUPPORT_UINT64} + +// ֻҪ֧ 64 λ޷ 32/64 λ Intel ARM Delphi FPCʲôϵͳ + +function UInt64Mul(A, B: Cardinal): TUInt64; +begin + Result := TUInt64(A) * B; +end; + +{$ELSE} // ֻеͰ汾 Delphi Win32 x86 + +{ + ޷ 32 λˣֱʹ Int64 ģ 64 λ޷ + + üĴԼ A -> EAXB -> EDXʹöջ + System.@_llmul ҪڸսʱEAX <- A ĵλEDX <- A ĸλ 0 + [ESP + 8]Ҳ EBP + C<- B ĸλ 0[ESP + 4] Ҳ EBP + 8<- B ĵλ +} +function UInt64Mul(A, B: Cardinal): TUInt64; +asm + PUSH 0 // PUSH B λ 0 + PUSH EDX // PUSH B λ + // EAX A λѾ + XOR EDX, EDX // EDX A λ 0 + CALL System.@_llmul; // EAX 32 λEDX 32 λ +end; + +{$ENDIF} + +// ޷ 64 λӣ ResLo ResHi +procedure UInt64AddUInt64(A, B: TUInt64; var ResLo, ResHi: TUInt64); +var + X, Y, Z, T, R0L, R0H, R1L, R1H: Cardinal; + R0, R1, R01, R12: TUInt64; +begin + // ˼룺2^32 ϵ M (xM+y) + (zM+t) = (x+z) M + (y+t) + // y+t R0 ռ 01x+z R1 ռ 12 R0, R1 ٲӳ R01, R12 + if IsUInt64AddOverflow(A, B) then + begin + X := Int64Rec(A).Hi; + Y := Int64Rec(A).Lo; + Z := Int64Rec(B).Hi; + T := Int64Rec(B).Lo; + + R0 := TUInt64(Y) + TUInt64(T); + R1 := TUInt64(X) + TUInt64(Z); + + R0L := Int64Rec(R0).Lo; + R0H := Int64Rec(R0).Hi; + R1L := Int64Rec(R1).Lo; + R1H := Int64Rec(R1).Hi; + + R01 := TUInt64(R0H) + TUInt64(R1L); + R12 := TUInt64(R1H) + TUInt64(Int64Rec(R01).Hi); + + Int64Rec(ResLo).Lo := R0L; + Int64Rec(ResLo).Hi := Int64Rec(R01).Lo; + Int64Rec(ResHi).Lo := Int64Rec(R12).Lo; + Int64Rec(ResHi).Hi := Int64Rec(R12).Hi; + end + else + begin + ResLo := A + B; + ResHi := 0; + end; +end; + +{$IFDEF WIN64} // ע Linux 64 ²֧ ASMֻ WIN64 + +// 64 λ޷ 64 λˣ ResLo ResHi Уֱûʵ֣һ +procedure UInt64MulUInt64(A, B: UInt64; var ResLo, ResHi: UInt64); assembler; +asm + PUSH RAX + MOV RAX, RCX + MUL RDX // ޷ţзŵ IMUL + MOV [R8], RAX + MOV [R9], RDX + POP RAX +end; + +{$ELSE} + +// ޷ 64 λˣ ResLo ResHi +procedure UInt64MulUInt64(A, B: TUInt64; var ResLo, ResHi: TUInt64); +var + X, Y, Z, T: Cardinal; + YT, XT, ZY, ZX: TUInt64; + P, R1Lo, R1Hi, R2Lo, R2Hi: TUInt64; +begin + // ˼룺2^32 ϵ M (xM+y)*(zM+t) = xzM^2 + (xt+yz)M + yt + // ϵ UInt64xz ռ 234xt+yz ռ 123yt ռ 01Ȼۼ + X := Int64Rec(A).Hi; + Y := Int64Rec(A).Lo; + Z := Int64Rec(B).Hi; + T := Int64Rec(B).Lo; + + YT := UInt64Mul(Y, T); + XT := UInt64Mul(X, T); + ZY := UInt64Mul(Y, Z); + ZX := UInt64Mul(X, Z); + + Int64Rec(ResLo).Lo := Int64Rec(YT).Lo; + + P := Int64Rec(YT).Hi; + UInt64AddUInt64(P, XT, R1Lo, R1Hi); + UInt64AddUInt64(ZY, R1Lo, R2Lo, R2Hi); + + Int64Rec(ResLo).Hi := Int64Rec(R2Lo).Lo; + + P := TUInt64(Int64Rec(R2Lo).Hi) + TUInt64(Int64Rec(ZX).Lo); + + Int64Rec(ResHi).Lo := Int64Rec(P).Lo; + Int64Rec(ResHi).Hi := Int64Rec(R1Hi).Lo + Int64Rec(R2Hi).Lo + Int64Rec(ZX).Hi + Int64Rec(P).Hi; +end; + +{$ENDIF} + +{$HINTS OFF} + +function _ValUInt64(const S: string; var Code: Integer): TUInt64; +const + FirstIndex = 1; +var + I: Integer; + Dig: Integer; + Sign: Boolean; + Empty: Boolean; +begin + I := FirstIndex; + Dig := 0; + Result := 0; + + if S = '' then + begin + Code := 1; + Exit; + end; + + while S[I] = Char(' ') do + Inc(I); + Sign := False; + + if S[I] = Char('-') then + begin + Sign := True; + Inc(I); + end + else if S[I] = Char('+') then + Inc(I); + Empty := True; + + if (S[I] = Char('$')) or (UpCase(S[I]) = Char('X')) + or ((S[I] = Char('0')) and (I < Length(S)) and (UpCase(S[I+1]) = Char('X'))) then + begin + if S[I] = Char('0') then + Inc(I); + Inc(I); + while True do + begin + case Char(S[I]) of + Char('0').. Char('9'): Dig := Ord(S[I]) - Ord('0'); + Char('A').. Char('F'): Dig := Ord(S[I]) - (Ord('A') - 10); + Char('a').. Char('f'): Dig := Ord(S[I]) - (Ord('a') - 10); + else + Break; + end; + + if Result > (CN_MAX_TUINT64 shr 4) then + Break; + if Sign and (Dig <> 0) then + Break; + + Result := Result shl 4 + TUInt64(Dig); + Inc(I); + Empty := False; + end; + end + else + begin + while True do + begin + case Char(S[I]) of + Char('0').. Char('9'): Dig := Ord(S[I]) - Ord('0'); + else + Break; + end; + + if Result > UInt64Div(CN_MAX_TUINT64, 10) then + Break; + if Sign and (Dig <> 0) then + Break; + + Result := Result * 10 + TUInt64(Dig); + Inc(I); + Empty := False; + end; + end; + + if (S[I] <> Char(#0)) or Empty then + Code := I + 1 - FirstIndex + else + Code := 0; +end; + +{$HINTS ON} + +function UInt64ToHex(N: TUInt64): string; +const + Digits: array[0..15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); + + function HC(B: Byte): string; + begin + Result := string(Digits[(B shr 4) and $0F] + Digits[B and $0F]); + end; + +begin + Result := + HC(Byte((N and $FF00000000000000) shr 56)) + + HC(Byte((N and $00FF000000000000) shr 48)) + + HC(Byte((N and $0000FF0000000000) shr 40)) + + HC(Byte((N and $000000FF00000000) shr 32)) + + HC(Byte((N and $00000000FF000000) shr 24)) + + HC(Byte((N and $0000000000FF0000) shr 16)) + + HC(Byte((N and $000000000000FF00) shr 8)) + + HC(Byte((N and $00000000000000FF))); +end; + +function UInt64ToStr(N: TUInt64): string; +begin + Result := Format('%u', [N]); +end; + +function StrToUInt64(const S: string): TUInt64; +{$IFNDEF DELPHIXE6_UP} +var + E: Integer; +{$ENDIF} +begin +{$IFDEF DELPHIXE6_UP} + Result := SysUtils.StrToUInt64(S); // StrToUInt64 only exists under XE6 or above +{$ELSE} + Result := _ValUInt64(S, E); + if E <> 0 then raise EConvertError.CreateResFmt(@SInvalidInteger, [S]); +{$ENDIF} +end; + +function UInt64Compare(A, B: TUInt64): Integer; +{$IFNDEF SUPPORT_UINT64} +var + HiA, HiB, LoA, LoB: Cardinal; +{$ENDIF} +begin +{$IFDEF SUPPORT_UINT64} + if A > B then + Result := 1 + else if A < B then + Result := -1 + else + Result := 0; +{$ELSE} + HiA := (A and $FFFFFFFF00000000) shr 32; + HiB := (B and $FFFFFFFF00000000) shr 32; + if HiA > HiB then + Result := 1 + else if HiA < HiB then + Result := -1 + else + begin + LoA := Cardinal(A and $00000000FFFFFFFF); + LoB := Cardinal(B and $00000000FFFFFFFF); + if LoA > LoB then + Result := 1 + else if LoA < LoB then + Result := -1 + else + Result := 0; + end; +{$ENDIF} +end; + +function UInt64Sqrt(N: TUInt64): TUInt64; +var + Rem, Root: TUInt64; + I: Integer; +begin + Result := 0; + if N = 0 then + Exit; + + if UInt64Compare(N, 4) < 0 then + begin + Result := 1; + Exit; + end; + + Rem := 0; + Root := 0; + + for I := 0 to 31 do + begin + Root := Root shl 1; + Inc(Root); + + Rem := Rem shl 2; + Rem := Rem or (N shr 62); + N := N shl 2; + + if UInt64Compare(Root, Rem) <= 0 then + begin + Rem := Rem - Root; + Inc(Root); + end + else + Dec(Root); + end; + Result := Root shr 1; +end; + +function UInt32IsNegative(N: Cardinal): Boolean; +begin + Result := (N and (1 shl 31)) <> 0; +end; + +function UInt64IsNegative(N: TUInt64): Boolean; +begin +{$IFDEF SUPPORT_UINT64} + Result := (N and (UInt64(1) shl 63)) <> 0; +{$ELSE} + Result := N < 0; +{$ENDIF} +end; + +// UInt64 ijһλ 1λ Index 0 ʼ +procedure UInt64SetBit(var B: TUInt64; Index: Integer); +begin + B := B or (TUInt64(1) shl Index); +end; + +// UInt64 ijһλ 0λ Index 0 ʼ +procedure UInt64ClearBit(var B: TUInt64; Index: Integer); +begin + B := B and not (TUInt64(1) shl Index); +end; + +// UInt64 ĵڼλǷ 10 ʼ +function GetUInt64BitSet(B: TUInt64; Index: Integer): Boolean; +begin + B := B and (TUInt64(1) shl Index); + Result := B <> 0; +end; + +// UInt64 1 ߶λǵڼλλ 0û 1 -1 +function GetUInt64HighBits(B: TUInt64): Integer; +begin + if B = 0 then + begin + Result := -1; + Exit; + end; + + Result := 1; + if B shr 32 = 0 then + begin + Inc(Result, 32); + B := B shl 32; + end; + if B shr 48 = 0 then + begin + Inc(Result, 16); + B := B shl 16; + end; + if B shr 56 = 0 then + begin + Inc(Result, 8); + B := B shl 8; + end; + if B shr 60 = 0 then + begin + Inc(Result, 4); + B := B shl 4; + end; + if B shr 62 = 0 then + begin + Inc(Result, 2); + B := B shl 2; + end; + Result := Result - Integer(B shr 63); // õǰ 0 + Result := 63 - Result; +end; + +// Cardinal 1 ߶λǵڼλλ 0û 1 -1 +function GetUInt32HighBits(B: Cardinal): Integer; +begin + if B = 0 then + begin + Result := -1; + Exit; + end; + + Result := 1; + if B shr 16 = 0 then + begin + Inc(Result, 16); + B := B shl 16; + end; + if B shr 24 = 0 then + begin + Inc(Result, 8); + B := B shl 8; + end; + if B shr 28 = 0 then + begin + Inc(Result, 4); + B := B shl 4; + end; + if B shr 30 = 0 then + begin + Inc(Result, 2); + B := B shl 2; + end; + Result := Result - Integer(B shr 31); // õǰ 0 + Result := 31 - Result; +end; + +function GetUInt16HighBits(B: Word): Integer; +begin + if B = 0 then + begin + Result := -1; + Exit; + end; + + Result := 1; + if B shr 8 = 0 then + begin + Inc(Result, 8); + B := B shl 8; + end; + if B shr 12 = 0 then + begin + Inc(Result, 4); + B := B shl 4; + end; + if B shr 14 = 0 then + begin + Inc(Result, 2); + B := B shl 2; + end; + Result := Result - Integer(B shr 15); // õǰ 0 + Result := 15 - Result; +end; + +function GetUInt8HighBits(B: Byte): Integer; +begin + if B = 0 then + begin + Result := -1; + Exit; + end; + + Result := 1; + if B shr 4 = 0 then + begin + Inc(Result, 4); + B := B shl 4; + end; + if B shr 6 = 0 then + begin + Inc(Result, 2); + B := B shl 2; + end; + Result := Result - Integer(B shr 7); // õǰ 0 + Result := 7 - Result; +end; + +// Int64 1 Ͷλǵڼλλ 0û 1 -1 +function GetUInt64LowBits(B: TUInt64): Integer; +var + Y: TUInt64; + N: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + N := 63; + Y := B shl 32; + if Y <> 0 then + begin + Dec(N, 32); + B := Y; + end; + Y := B shl 16; + if Y <> 0 then + begin + Dec(N, 16); + B := Y; + end; + Y := B shl 8; + if Y <> 0 then + begin + Dec(N, 8); + B := Y; + end; + Y := B shl 4; + if Y <> 0 then + begin + Dec(N, 4); + B := Y; + end; + Y := B shl 2; + if Y <> 0 then + begin + Dec(N, 2); + B := Y; + end; + B := B shl 1; + Result := N - Integer(B shr 63); +end; + +// Cardinal 1 Ͷλǵڼλλ 0û 1 -1 +function GetUInt32LowBits(B: Cardinal): Integer; +var + Y, N: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + N := 31; + Y := B shl 16; + if Y <> 0 then + begin + Dec(N, 16); + B := Y; + end; + Y := B shl 8; + if Y <> 0 then + begin + Dec(N, 8); + B := Y; + end; + Y := B shl 4; + if Y <> 0 then + begin + Dec(N, 4); + B := Y; + end; + Y := B shl 2; + if Y <> 0 then + begin + Dec(N, 2); + B := Y; + end; + B := B shl 1; + Result := N - Integer(B shr 31); +end; + +// Word 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 +function GetUInt16LowBits(B: Word): Integer; +var + Y, N: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + N := 15; + Y := B shl 8; + if Y <> 0 then + begin + Dec(N, 8); + B := Y; + end; + Y := B shl 4; + if Y <> 0 then + begin + Dec(N, 4); + B := Y; + end; + Y := B shl 2; + if Y <> 0 then + begin + Dec(N, 2); + B := Y; + end; + B := B shl 1; + Result := N - Integer(B shr 15); +end; + +// Byte 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 +function GetUInt8LowBits(B: Byte): Integer; +var + N: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + N := 7; + if B shr 4 = 0 then + begin + Dec(N, 4); + B := B shl 4; + end; + if B shr 6 = 0 then + begin + Dec(N, 2); + B := B shl 2; + end; + B := B shl 1; + Result := N - Integer(B shr 7); +end; + +// װ Int64 Modֵʱȡģģ +function Int64Mod(M, N: Int64): Int64; +begin + if M > 0 then + Result := M mod N + else + Result := N - ((-M) mod N); +end; + +// жһ 32 λ޷Ƿ 2 +function IsUInt32PowerOf2(N: Cardinal): Boolean; +begin + Result := (N and (N - 1)) = 0; +end; + +// жһ 64 λ޷Ƿ 2 +function IsUInt64PowerOf2(N: TUInt64): Boolean; +begin + Result := (N and (N - 1)) = 0; +end; + +// õһָ 32 λ޷ȵ 2 ݣ򷵻 0 +function GetUInt32PowerOf2GreaterEqual(N: Cardinal): Cardinal; +begin + Result := N - 1; + Result := Result or (Result shr 1); + Result := Result or (Result shr 2); + Result := Result or (Result shr 4); + Result := Result or (Result shr 8); + Result := Result or (Result shr 16); + Inc(Result); +end; + +// õһָ 64 λ޷ 2 ݣ򷵻 0 +function GetUInt64PowerOf2GreaterEqual(N: TUInt64): TUInt64; +begin + Result := N - 1; + Result := Result or (Result shr 1); + Result := Result or (Result shr 2); + Result := Result or (Result shr 4); + Result := Result or (Result shr 8); + Result := Result or (Result shr 16); + Result := Result or (Result shr 32); + Inc(Result); +end; + +// ж 32 λзǷ 32 λз +function IsInt32AddOverflow(A, B: Integer): Boolean; +var + C: Integer; +begin + C := A + B; + Result := ((A > 0) and (B > 0) and (C < 0)) or // ͬҽ˵ + ((A < 0) and (B < 0) and (C > 0)); +end; + +// ж 32 λ޷Ƿ 32 λ޷ +function IsUInt32AddOverflow(A, B: Cardinal): Boolean; +begin + Result := (A + B) < A; // ޷ӣֻҪСһ˵ +end; + +// ж 64 λзǷ 64 λз +function IsInt64AddOverflow(A, B: Int64): Boolean; +var + C: Int64; +begin + C := A + B; + Result := ((A > 0) and (B > 0) and (C < 0)) or // ͬҽ˵ + ((A < 0) and (B < 0) and (C > 0)); +end; + +// ж 64 λ޷Ƿ 64 λ޷ +function IsUInt64AddOverflow(A, B: TUInt64): Boolean; +begin + Result := UInt64Compare(A + B, A) < 0; // ޷ӣֻҪСһ˵ +end; + +function IsUInt64SubOverflowInt32(A: TUInt64; B: TUInt64): Boolean; +var + GT: Boolean; + R: TUInt64; +begin + GT := UInt64Compare(A, B) >= 0; // GT ʾ A >= B + if GT then + begin + R := A - B; + // ж 64 λ޷ŷΧ R Ƿ񳬹 MaxInt32 + Result := UInt64Compare(R, TUInt64(CN_MAX_INT32)) > 0; + end + else + begin + R := B - A; + // ж 64 λзŷΧ -R ǷС MinInt32Ҳж 64 λ޷ R Ƿ񳬹 MinInt32 ޷ʽ + Result := UInt64Compare(R, CN_MIN_INT32_IN_INT64) > 0; + end; +end; + +// 64 λ޷ӣA + B => R 1 λ +procedure UInt64Add(var R: TUInt64; A, B: TUInt64; out Carry: Integer); +begin + R := A + B; + if UInt64Compare(R, A) < 0 then // ޷ӣֻҪСһ˵ + Carry := 1 + else + Carry := 0; +end; + +// 64 λ޷A - B => Rнλ 1 λ +procedure UInt64Sub(var R: TUInt64; A, B: TUInt64; out Carry: Integer); +begin + R := A - B; + if UInt64Compare(R, A) > 0 then // ޷ֻҪڱ˵λ + Carry := 1 + else + Carry := 0; +end; + +// ж 32 λзǷ 32 λз +function IsInt32MulOverflow(A, B: Integer): Boolean; +var + T: Integer; +begin + T := A * B; + Result := (B <> 0) and ((T div B) <> A); +end; + +// ж 32 λ޷Ƿ 32 λ޷ +function IsUInt32MulOverflow(A, B: Cardinal): Boolean; +var + T: TUInt64; +begin + T := TUInt64(A) * TUInt64(B); + Result := (T = Cardinal(T)); +end; + +// ж 32 λ޷Ƿ 64 λзδҲ False ʱR ֱӷؽ +function IsUInt32MulOverflowInt64(A, B: Cardinal; out R: TUInt64): Boolean; +var + T: Int64; +begin + T := Int64(A) * Int64(B); + Result := T < 0; // Int64 ֵ˵ + if not Result then + R := TUInt64(T); +end; + +// ж 64 λзǷ 64 λз +function IsInt64MulOverflow(A, B: Int64): Boolean; +var + T: Int64; +begin + T := A * B; + Result := (B <> 0) and ((T div B) <> A); +end; + +// ָת֧ͣ 32/64 λ +function PointerToInteger(P: Pointer): Integer; +begin +{$IFDEF CPU64BITS} + // ôд Pointer ĵ 32 λ Integer + Result := Integer(P); +{$ELSE} + Result := Integer(P); +{$ENDIF} +end; + +// תָ֧ͣ 32/64 λ +function IntegerToPointer(I: Integer): Pointer; +begin +{$IFDEF CPU64BITS} + // ôд Pointer ĵ 32 λ Integer + Result := Pointer(I); +{$ELSE} + Result := Pointer(I); +{$ENDIF} +end; + +// Int64 Χĺ࣬Ҫ N 0 +function Int64NonNegativeAddMod(A, B, N: Int64): Int64; +begin + if IsInt64AddOverflow(A, B) then // Int64 + begin + if A > 0 then + begin + // A B 0 UInt64 ȡģδ UInt64 ޣע N δ Int64 ȡģС Int64 ޣɸֵ + Result := UInt64NonNegativeAddMod(A, B, N); + end + else + begin + // A B С 0ȡ UInt64 ȡģĺδ UInt64 ޣģٱһ +{$IFDEF SUPPORT_UINT64} + Result := UInt64(N) - UInt64NonNegativeAddMod(-A, -B, N); +{$ELSE} + Result := N - UInt64NonNegativeAddMod(-A, -B, N); +{$ENDIF} + end; + end + else // ֱӼ + Result := Int64NonNegativeMod(A + B, N); +end; + +// UInt64 Χĺ࣬Ҫ N 0 +function UInt64NonNegativeAddMod(A, B, N: TUInt64): TUInt64; +var + C, D: TUInt64; +begin + if IsUInt64AddOverflow(A, B) then // + begin + C := UInt64Mod(A, N); // ͸ģ + D := UInt64Mod(B, N); + if IsUInt64AddOverflow(C, D) then + begin + // ˵ģ󣬸ģûá + // һڵ 2^63N 2^63 + 1 + // = + 2^64 + // mod N = mod N + (2^64 - 1) mod N) + 1 + // N 2^63 + 1 2^64 - 2ǰӲֱӺһģ + Result := UInt64Mod(UInt64Mod(A + B, N) + UInt64Mod(CN_MAX_TUINT64, N) + 1, N); + end + else + Result := UInt64Mod(C + D, N); + end + else + begin + Result := UInt64Mod(A + B, N); + end; +end; + +function Int64NonNegativeMulMod(A, B, N: Int64): Int64; +var + Neg: Boolean; +begin + if N <= 0 then + raise EDivByZero.Create(SDivByZero); + + // ΧСֱ + if not IsInt64MulOverflow(A, B) then + begin + Result := A * B mod N; + if Result < 0 then + Result := Result + N; + Exit; + end; + + // ŵ + Result := 0; + if (A = 0) or (B = 0) then + Exit; + + Neg := False; + if (A < 0) and (B > 0) then + begin + A := -A; + Neg := True; + end + else if (A > 0) and (B < 0) then + begin + B := -B; + Neg := True; + end + else if (A < 0) and (B < 0) then + begin + A := -A; + B := -B; + end; + + // λѭ + while B <> 0 do + begin + if (B and 1) <> 0 then + Result := ((Result mod N) + (A mod N)) mod N; + + A := A shl 1; + if A >= N then + A := A mod N; + + B := B shr 1; + end; + + if Neg then + Result := N - Result; +end; + +function UInt64NonNegativeMulMod(A, B, N: TUInt64): TUInt64; +begin + Result := 0; + if (UInt64Compare(A, CN_MAX_UINT32) <= 0) and (UInt64Compare(B, CN_MAX_UINT32) <= 0) then + begin + Result := UInt64Mod(A * B, N); // 㹻СĻֱӳ˺ģ + end + else + begin + while B <> 0 do + begin + if (B and 1) <> 0 then + Result := UInt64NonNegativeAddMod(Result, A, N); + + A := UInt64NonNegativeAddMod(A, A, N); + // ôͳ㷨 A := A shl 1 N mod NΪ + + B := B shr 1; + end; + end; +end; + +// װķǸຯҲΪʱӸ豣֤ P 0 +function Int64NonNegativeMod(N: Int64; P: Int64): Int64; +begin + if P <= 0 then + raise EDivByZero.Create(SDivByZero); + + Result := N mod P; + if Result < 0 then + Inc(Result, P); +end; + +// Int64 ķǸָ +function Int64NonNegativPower(N: Int64; Exp: Integer): Int64; +var + T: Int64; +begin + if Exp < 0 then + raise ERangeError.Create(SRangeError) + else if Exp = 0 then + begin + if N <> 0 then + Result := 1 + else + raise EDivByZero.Create(SDivByZero); + end + else if Exp = 1 then + Result := N + else + begin + Result := 1; + T := N; + + while Exp > 0 do + begin + if (Exp and 1) <> 0 then + Result := Result * T; + + Exp := Exp shr 1; + T := T * T; + end; + end; +end; + +function Int64NonNegativeRoot(N: Int64; Exp: Integer): Int64; +var + I: Integer; + X: Int64; + X0, X1: Extended; +begin + if (Exp < 0) or (N < 0) then + raise ERangeError.Create(SRangeError) + else if Exp = 0 then + raise EDivByZero.Create(SDivByZero) + else if (N = 0) or (N = 1) then + Result := N + else if Exp = 2 then + Result := UInt64Sqrt(N) + else + begin + // ţٵ + I := GetUInt64HighBits(N) + 1; // õԼ Log2 N ֵ + I := (I div Exp) + 1; + X := 1 shl I; // õһϴ X0 ֵΪʼֵ + + X0 := X; + X1 := X0 - (Power(X0, Exp) - N) / (Exp * Power(X0, Exp - 1)); + + while True do + begin + if (Trunc(X0) = Trunc(X1)) and (Abs(X0 - X1) < 0.001) then + begin + Result := Trunc(X1); // Trunc ֻ֧ Int64˻ + Exit; + end; + + X0 := X1; + X1 := X0 - (Power(X0, Exp) - N) / (Exp * Power(X0, Exp - 1)); + end; + end; +end; + +function UInt64NonNegativPower(N: TUInt64; Exp: Integer): TUInt64; +var + T, RL, RH: TUInt64; +begin + if Exp < 0 then + raise ERangeError.Create(SRangeError) + else if Exp = 0 then + begin + if N <> 0 then + Result := 1 + else + raise EDivByZero.Create(SDivByZero); + end + else if Exp = 1 then + Result := N + else + begin + Result := 1; + T := N; + + while Exp > 0 do + begin + if (Exp and 1) <> 0 then + begin + UInt64MulUInt64(Result, T, RL, RH); + Result := RL; + end; + + Exp := Exp shr 1; + UInt64MulUInt64(T, T, RL, RH); + T := RL; + end; + end; +end; + +function UInt64NonNegativeRoot(N: TUInt64; Exp: Integer): TUInt64; +var + I: Integer; + X: TUInt64; + XN, X0, X1: Extended; +begin + if Exp < 0 then + raise ERangeError.Create(SRangeError) + else if Exp = 0 then + raise EDivByZero.Create(SDivByZero) + else if (N = 0) or (N = 1) then + Result := N + else if Exp = 2 then + Result := UInt64Sqrt(N) + else + begin + // ţٵ + I := GetUInt64HighBits(N) + 1; // õԼ Log2 N ֵ + I := (I div Exp) + 1; + X := 1 shl I; // õһϴ X0 ֵΪʼֵ + + X0 := UInt64ToExtended(X); + XN := UInt64ToExtended(N); + X1 := X0 - (Power(X0, Exp) - XN) / (Exp * Power(X0, Exp - 1)); + + while True do + begin + if (ExtendedToUInt64(X0) = ExtendedToUInt64(X1)) and (Abs(X0 - X1) < 0.001) then + begin + Result := ExtendedToUInt64(X1); + Exit; + end; + + X0 := X1; + X1 := X0 - (Power(X0, Exp) - XN) / (Exp * Power(X0, Exp - 1)); + end; + end; +end; + +function IsUInt128BitSet(Lo, Hi: TUInt64; N: Integer): Boolean; +begin + if N < 64 then + Result := (Lo and (TUInt64(1) shl N)) <> 0 + else + begin + Dec(N, 64); + Result := (Hi and (TUInt64(1) shl N)) <> 0; + end; +end; + +procedure SetUInt128Bit(var Lo, Hi: TUInt64; N: Integer); +begin + if N < 64 then + Lo := Lo or (TUInt64(1) shl N) + else + begin + Dec(N, 64); + Hi := Hi or (TUInt64(1) shl N); + end; +end; + +procedure ClearUInt128Bit(var Lo, Hi: TUInt64; N: Integer); +begin + if N < 64 then + Lo := Lo and not (TUInt64(1) shl N) + else + begin + Dec(N, 64); + Hi := Hi and not (TUInt64(1) shl N); + end; +end; + +function UnsignedAddWithLimitRadix(A, B, C: Cardinal; var R: Cardinal; + L, H: Cardinal): Cardinal; +begin + R := A + B + C; + if R > H then // нλ + begin + A := H - L + 1; // õ + B := R - L; // õ L ֵ + + Result := B div A; // Ƶĵڼͽ + R := L + (B mod A); // ȥƺ + end + else + Result := 0; +end; + +procedure InternalQuickSort(Mem: Pointer; L, R: Integer; ElementByteSize: Integer; + CompareProc: TCnMemSortCompareProc); +var + I, J, P: Integer; +begin + repeat + I := L; + J := R; + P := (L + R) shr 1; + repeat + while CompareProc(Pointer(TCnNativeInt(Mem) + I * ElementByteSize), + Pointer(TCnNativeInt(Mem) + P * ElementByteSize), ElementByteSize) < 0 do + Inc(I); + while CompareProc(Pointer(TCnNativeInt(Mem) + J * ElementByteSize), + Pointer(TCnNativeInt(Mem) + P * ElementByteSize), ElementByteSize) > 0 do + Dec(J); + + if I <= J then + begin + MemorySwap(Pointer(TCnNativeInt(Mem) + I * ElementByteSize), + Pointer(TCnNativeInt(Mem) + J * ElementByteSize), ElementByteSize); + + if P = I then + P := J + else if P = J then + P := I; + Inc(I); + Dec(J); + end; + until I > J; + + if L < J then + InternalQuickSort(Mem, L, J, ElementByteSize, CompareProc); + L := I; + until I >= R; +end; + +function DefaultCompareProc(P1, P2: Pointer; ElementByteSize: Integer): Integer; +begin + Result := MemoryCompare(P1, P2, ElementByteSize); +end; + +procedure MemoryQuickSort(Mem: Pointer; ElementByteSize: Integer; + ElementCount: Integer; CompareProc: TCnMemSortCompareProc); +begin + if (Mem <> nil) and (ElementCount > 0) and (ElementCount > 0) then + begin + if Assigned(CompareProc) then + InternalQuickSort(Mem, 0, ElementCount - 1, ElementByteSize, CompareProc) + else + InternalQuickSort(Mem, 0, ElementCount - 1, ElementByteSize, DefaultCompareProc); + end; +end; + +{$IFDEF COMPILER5} + +function BoolToStr(Value: Boolean; UseBoolStrs: Boolean): string; +begin + if UseBoolStrs then + begin + if Value then + Result := 'True' + else + Result := 'False'; + end + else + begin + if Value then + Result := '-1' + else + Result := '0'; + end; +end; + +{$ENDIF} + +// =========================== ѭλ ==================================== + +function RotateLeft16(A: Word; N: Integer): Word; +begin + Result := (A shl N) or (A shr (16 - N)); +end; + +function RotateRight16(A: Word; N: Integer): Word; +begin + Result := (A shr N) or (A shl (16 - N)); +end; + +function RotateLeft32(A: Cardinal; N: Integer): Cardinal; +begin + Result := (A shl N) or (A shr (32 - N)); +end; + +function RotateRight32(A: Cardinal; N: Integer): Cardinal; +begin + Result := (A shr N) or (A shl (32 - N)); +end; + +function RotateLeft64(A: TUInt64; N: Integer): TUInt64; +begin + Result := (A shl N) or (A shr (64 - N)); +end; +function RotateRight64(A: TUInt64; N: Integer): TUInt64; +begin + Result := (A shr N) or (A shl (64 - N)); +end; + +initialization + FByteOrderIsBigEndian := CurrentByteOrderIsBigEndian; + +end. diff --git a/CnPack/Crypto/CnPemUtils.dcu b/CnPack/Crypto/CnPemUtils.dcu new file mode 100644 index 0000000000000000000000000000000000000000..b14a181ea709064b3476fff66071bca6173099f8 GIT binary patch literal 16968 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 HV0HfoxNO-h literal 0 HcmV?d00001 diff --git a/CnPack/Crypto/CnPemUtils.pas b/CnPack/Crypto/CnPemUtils.pas new file mode 100644 index 0000000..f4d5719 --- /dev/null +++ b/CnPack/Crypto/CnPemUtils.pas @@ -0,0 +1,1219 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2025 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnPemUtils; +{* |
+================================================================================
+* ƣ
+* ԪƣPEM ʽ뵥Ԫ
+* ԪߣCnPack 
+*     עԪʵ PEM ʽĶȡ뱣棬ӽܻơ
+*           Ҳʵ PKCS1/PKCS5/PKCS7/ISO10126 ȶ봦ơ
+*           ע֧ PKCS12 淶֤鼰Կװʽ
+* ƽ̨WinXP + Delphi 5.0
+* ݲԣδ
+*   õԪ豾ػ
+* ޸ļ¼2024.05.27 V1.6
+*                ISO10126 Ĵ
+*           2023.12.14 V1.5
+*                SaveMemoryToPemStream δ
+*           2022.03.09 V1.4
+*                PKCS5 Ĵ
+*           2021.05.14 V1.3
+*               ĸ PKCS7 Ĵ
+*           2020.03.27 V1.2
+*               ģ Openssl ʵ PEM ļд룬ֲֻּ֧㷨
+*               Ŀǰд des/3des/aes128/192/256 PKCS7 룬 Openssl 1.0.2g
+*           2020.03.23 V1.1
+*               ģ Openssl ʵ PEM ļܶȡֲֻּ֧㷨
+*               Ŀǰȡ des/3des/aes128/192/256 PKCS7 룬 Openssl 1.0.2g
+*           2020.03.18 V1.0
+*               Ԫ CnRSA ж
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes, CnNative, CnRandom, CnKDF, CnBase64, CnAES, CnDES; + +const + CN_PKCS1_BLOCK_TYPE_PRIVATE_00 = 00; + {* PKCS1 ʱĿֵֶһĬӦ RSA ˽Կܳ} + + CN_PKCS1_BLOCK_TYPE_PRIVATE_FF = 01; + {* PKCS1 ʱĿֵֶĬӦ RSA ˽Կǩ} + + CN_PKCS1_BLOCK_TYPE_PUBLIC_RANDOM = 02; + {* PKCS1 ʱĿֵֶĬӦ RSA ĹԿܳ} + +type + TCnKeyHashMethod = (ckhMd5, ckhSha256); + {* PEM ʽֵ֧Ӵ} + + TCnKeyEncryptMethod = (ckeNone, ckeDES, cke3DES, ckeAES128, ckeAES192, ckeAES256); + {* PEM ʽֵ֧ļ} + +// ======================= PEM ļдּ֧ӽ ======================== + +function LoadPemFileToMemory(const FileName: string; const ExpectHead: string; + const ExpectTail: string; MemoryStream: TMemoryStream; const Password: string = ''; + KeyHashMethod: TCnKeyHashMethod = ckhMd5): Boolean; +{* PEM ʽļָ֤ͷβʵݲܽ Base64 롣 + + + const FileName: string - ļ + const ExpectHead: string - ͷ + const ExpectTail: string - β + MemoryStream: TMemoryStream - ڴ + const Password: string - ļܣڴṩ + KeyHashMethod: TCnKeyHashMethod - ļʹõӴ + + ֵBoolean - ضǷɹ +} + +function LoadPemStreamToMemory(Stream: TStream; const ExpectHead: string; + const ExpectTail: string; MemoryStream: TMemoryStream; const Password: string = ''; + KeyHashMethod: TCnKeyHashMethod = ckhMd5): Boolean; +{* PEM ʽļָ֤ͷβʵݲܽ Base64 롣 + + + Stream: TStream - + const ExpectHead: string - ͷ + const ExpectTail: string - β + MemoryStream: TMemoryStream - ڴ + const Password: string - ܣڴṩ + KeyHashMethod: TCnKeyHashMethod - ʹõӴ + + ֵBoolean - ضǷɹ +} + +function SaveMemoryToPemFile(const FileName: string; const Head: string; const Tail: string; + MemoryStream: TMemoryStream; KeyEncryptMethod: TCnKeyEncryptMethod = ckeNone; + KeyHashMethod: TCnKeyHashMethod = ckhMd5; const Password: string = ''; Append: Boolean = False): Boolean; +{* Stream ݽ Base64 ܷвļͷβдļAppend Ϊ True ʱʾ׷ӡ + + + const FileName: string - дļ + const Head: string - дͷ + const Tail: string - дβ + MemoryStream: TMemoryStream - д + KeyEncryptMethod: TCnKeyEncryptMethod - üͣĬϲ + KeyHashMethod: TCnKeyHashMethod - Ӵ + const Password: string - 룬򴫿 + Append: Boolean - Ƿ׷ӵķʽд + + ֵBoolean - Ƿдɹ +} + +function SaveMemoryToPemStream(Stream: TStream; const Head: string; const Tail: string; + MemoryStream: TMemoryStream; KeyEncryptMethod: TCnKeyEncryptMethod = ckeNone; + KeyHashMethod: TCnKeyHashMethod = ckhMd5; const Password: string = ''; Append: Boolean = False): Boolean; +{* Stream ݽ Base64 ܷвͷβдAppend Ϊ True ʱʾ׷ӡ + + + Stream: TStream - д + const Head: string - дͷ + const Tail: string - дβ + MemoryStream: TMemoryStream - д + KeyEncryptMethod: TCnKeyEncryptMethod - üͣĬϲ + KeyHashMethod: TCnKeyHashMethod - ӴͣĬϲӴ + const Password: string - 룬򴫿 + Append: Boolean - Ƿ׷ӵķʽд + + ֵBoolean - Ƿдɹ +} + +// ===================== PKCS1 / PKCS7 Padding 봦 ==================== + +function AddPKCS1Padding(PaddingType: Integer; BlockSize: Integer; Data: Pointer; + DataByteLen: Integer; OutStream: TStream): Boolean; +{* ݿ鲹д Stream Уسɹڲô롣 + PaddingType ȡ 012BlockLen ֽ 128 ȡʽ + EB = 00 || BT || PS || 00 || D + 00 ǰ涨ֽڣBT 1 ֽڵ PaddingType0 1 2 ֱ 00 FF + PS Ķֽݣ 00 ǹ涨Ľβֽڡ + + + PaddingType: Integer - ͣȡ 0 1 2 + BlockSize: Integer - ֽڳ + Data: Pointer - ݿĵַ + DataByteLen: Integer - ݿֽڳ + OutStream: TStream - + + ֵBoolean - ضǷӳɹ +} + +function RemovePKCS1Padding(InData: Pointer; InDataByteLen: Integer; OutBuf: Pointer; + out OutByteLen: Integer): Boolean; +{* ȥݿ PKCS1 PaddingسɹOutBuf ָĿóб֤ + ɹOutLen ԭݳȡ + + + InData: Pointer - ȥݿĵַ + InDataByteLen: Integer - ȥݿֽڳ + OutBuf: Pointer - ȥݵ䳤ȱ㹻 + out OutByteLen: Integer - ȥݳ + + ֵBoolean - ضǷȥɹ +} + +function GetPKCS7PaddingByteLength(OrignalByteLen: Integer; BlockSize: Integer): Integer; +{* ԭʼ鳤ȼ PKCS7 ijȡ + + + OrignalByteLen: Integer - ԭʼֽڳ + BlockSize: Integer - PKCS7 ֽڳ + + ֵInteger - PKCS7 ֽڳ +} + +procedure AddPKCS7Padding(Stream: TMemoryStream; BlockSize: Integer); +{* ĩβ PKCS7 涨䡰ݡ + + + Stream: TMemoryStream - ڴݣݽ׷дβ + BlockSize: Integer - PKCS7 ֽڳ + + ֵޣ +} + +procedure RemovePKCS7Padding(Stream: TMemoryStream); +{* ȥ PKCS7 涨ĩβ䡰ݡ + + + Stream: TMemoryStream - ȥڴ + + ֵޣ} + +function StrAddPKCS7Padding(const Str: AnsiString; BlockSize: Integer): AnsiString; +{* ַĩβ PKCS7 涨䡰ݡ + + + const Str: AnsiString - ַ + BlockSize: Integer - PKCS7 ֽڳ + + ֵAnsiString - ضַ +} + +function StrRemovePKCS7Padding(const Str: AnsiString): AnsiString; +{* ȥ PKCS7 涨ַĩβ䡰ݡ + + + const Str: AnsiString - ȥַ + + ֵAnsiString - ȥַ +} + +procedure BytesAddPKCS7Padding(var Data: TBytes; BlockSize: Integer); +{* ֽĩβ PKCS7 涨䡰ݡ + + + var Data: TBytes - ֽ飬ݽ׷β + BlockSize: Integer - PKCS7 ֽڳ + + ֵޣ +} + +procedure BytesRemovePKCS7Padding(var Data: TBytes); +{* ȥ PKCS7 涨ֽĩβ䡰ݡ + + + var Data: TBytes - ȥֽ + + ֵޣ +} + +procedure AddPKCS5Padding(Stream: TMemoryStream); +{* ĩβ PKCS5 涨䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + Stream: TMemoryStream - ڴݽ׷β + + ֵޣ +} + +procedure RemovePKCS5Padding(Stream: TMemoryStream); +{* ȥ PKCS7 涨ĩβ䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + Stream: TMemoryStream - ȥڴ + + ֵޣ +} + +function StrAddPKCS5Padding(const Str: AnsiString): AnsiString; +{* ַĩβ PKCS5 涨䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + const Str: AnsiString - ַ + + ֵAnsiString - ضַ +} + +function StrRemovePKCS5Padding(const Str: AnsiString): AnsiString; +{* ȥ PKCS5 涨ַĩβ䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + const Str: AnsiString - ȥַ + + ֵAnsiString - ȥַ +} + +procedure BytesAddPKCS5Padding(var Data: TBytes); +{* ֽĩβ PKCS5 涨䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + var Data: TBytes - ֽ飬ݽ׷β + + ֵޣ +} + +procedure BytesRemovePKCS5Padding(var Data: TBytes); +{* ȥ PKCS7 涨ֽĩβ䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + var Data: TBytes - ȥֽ + + ֵޣ +} + +function GetISO10126PaddingByteLength(OrignalByteLen: Integer; BlockSize: Integer): Integer; +{* ԭʼ鳤ȼ ISO10126Padding ijȡ + + + OrignalByteLen: Integer - ԭʼֽڳ + BlockSize: Integer - ISO10126 ֽڳ + + ֵInteger - PKCS7 ֽڳ +} + +procedure AddISO10126Padding(Stream: TMemoryStream; BlockSize: Integer); +{* ĩβ ISO10126Padding 涨䡰ͼݡ + + + Stream: TMemoryStream - ڴݽ׷β + BlockSize: Integer - ISO10126 ֽڳ + + ֵޣ +} + +procedure RemoveISO10126Padding(Stream: TMemoryStream); +{* ȥ ISO10126Padding 涨ĩβ䡰ͼݡ + + + Stream: TMemoryStream - ȥڴ + + ֵޣ +} + +function StrAddISO10126Padding(const Str: AnsiString; BlockSize: Integer): AnsiString; +{* ַĩβ ISO10126Padding 涨䡰ͼݡ + + + const Str: AnsiString - ַ + BlockSize: Integer - ISO10126 ֽڴС + + ֵAnsiString - ضַ +} + +function StrRemoveISO10126Padding(const Str: AnsiString): AnsiString; +{* ȥ ISO10126Padding 涨ַĩβ䡰ͼݡ + + + const Str: AnsiString - ȥַ + + ֵAnsiString - ȥַ +} + +procedure BytesAddISO10126Padding(var Data: TBytes; BlockSize: Integer); +{* ֽĩβ ISO10126Padding 涨䡰ͼݡ + + + var Data: TBytes - ֽ飬ݽ׷β + BlockSize: Integer - ISO10126 ֽڳ + + ֵޣ +} + +procedure BytesRemoveISO10126Padding(var Data: TBytes); +{* ȥ ISO10126Padding 涨ֽĩβ䡰ͼݡ + + + var Data: TBytes - ȥֽ + + ֵޣ +} + +implementation + +const + PKCS1_PADDING_SIZE = 11; // һǰ 00һֽڡ 8 ֽ䣬һ 00 β + PKCS5_BLOCK_SIZE = 8; + + ENC_HEAD_PROCTYPE = 'Proc-Type:'; + ENC_HEAD_PROCTYPE_NUM = '4'; + ENC_HEAD_ENCRYPTED = 'ENCRYPTED'; + ENC_HEAD_DEK = 'DEK-Info:'; + + ENC_TYPE_AES128 = 'AES-128'; + ENC_TYPE_AES192 = 'AES-192'; + ENC_TYPE_AES256 = 'AES-256'; + ENC_TYPE_DES = 'DES'; + ENC_TYPE_3DES = 'DES-EDE3'; + + ENC_BLOCK_CBC = 'CBC'; + + ENC_TYPE_STRS: array[TCnKeyEncryptMethod] of string = + ('', ENC_TYPE_DES, ENC_TYPE_3DES, ENC_TYPE_AES128, ENC_TYPE_AES192, ENC_TYPE_AES256); + + ENC_TYPE_BLOCK_SIZE: array[TCnKeyEncryptMethod] of Byte = + (0, 8, 8, 16, 16, 16); + +function Min(A, B: Integer): Integer; +begin + if A < B then + Result := A + else + Result := B; +end; + +function AddPKCS1Padding(PaddingType, BlockSize: Integer; Data: Pointer; + DataByteLen: Integer; OutStream: TStream): Boolean; +var + I: Integer; + B, F: Byte; +begin + Result := False; + if (Data = nil) or (DataByteLen <= 0) then + Exit; + + // + if DataByteLen > BlockSize - PKCS1_PADDING_SIZE then + Exit; + + B := 0; + OutStream.Write(B, 1); // дǰֽ 00 + B := PaddingType; + F := BlockSize - DataByteLen - 3; // 3 ʾһǰ 00һֽڡһ 00 β + + OutStream.Write(B, 1); + case PaddingType of + CN_PKCS1_BLOCK_TYPE_PRIVATE_00: + begin + B := 0; + for I := 1 to F do + OutStream.Write(B, 1); + end; + CN_PKCS1_BLOCK_TYPE_PRIVATE_FF: + begin + B := $FF; + for I := 1 to F do + OutStream.Write(B, 1); + end; + CN_PKCS1_BLOCK_TYPE_PUBLIC_RANDOM: + begin + Randomize; + for I := 1 to F do + begin + B := Trunc(Random(255)); + if B = 0 then + Inc(B); + OutStream.Write(B, 1); + end; + end; + else + Exit; + end; + + B := 0; + OutStream.Write(B, 1); + OutStream.Write(Data^, DataByteLen); + Result := True; +end; + +function RemovePKCS1Padding(InData: Pointer; InDataByteLen: Integer; OutBuf: Pointer; + out OutByteLen: Integer): Boolean; +var + P: PAnsiChar; + I, J, Start: Integer; +begin + Result := False; + OutByteLen := 0; + I := 0; + + P := PAnsiChar(InData); + while P[I] = #0 do // ַһ #0Ѿȥ + Inc(I); + + if I >= InDataByteLen then + Exit; + + Start := 0; + case Ord(P[I]) of + CN_PKCS1_BLOCK_TYPE_PRIVATE_00: + begin + // P[I + 1] ʼѰҷ 00 + J := I + 1; + while J < InDataByteLen do + begin + if P[J] <> #0 then + begin + Start := J; + Break; + end; + Inc(J); + end; + end; + CN_PKCS1_BLOCK_TYPE_PRIVATE_FF, + CN_PKCS1_BLOCK_TYPE_PUBLIC_RANDOM: + begin + // P[I + 1] ʼѰҵһ 00 ı + J := I + 1; + while J < InDataByteLen do + begin + if P[J] = #0 then + begin + Start := J; + Break; + end; + Inc(J); + end; + + if Start <> 0 then + Inc(Start); + end; + end; + + if Start > 0 then + begin + Move(P[Start], OutBuf^, InDataByteLen - Start); + OutByteLen := InDataByteLen - Start; + Result := True; + end; +end; + +function GetPKCS7PaddingByteLength(OrignalByteLen: Integer; BlockSize: Integer): Integer; +var + R: Byte; +begin + R := OrignalByteLen mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + Result := OrignalByteLen + R; +end; + +procedure AddPKCS7Padding(Stream: TMemoryStream; BlockSize: Integer); +var + R: Byte; + Buf: array[0..255] of Byte; +begin + R := Stream.Size mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + FillChar(Buf[0], R, R); + Stream.Position := Stream.Size; + Stream.Write(Buf[0], R); +end; + +procedure RemovePKCS7Padding(Stream: TMemoryStream); +var + L: Byte; + Len: Cardinal; + Mem: Pointer; +begin + // ȥ Stream ĩβ 9 9 Padding + if Stream.Size > 1 then + begin + Stream.Position := Stream.Size - 1; + Stream.Read(L, 1); + + if Stream.Size - L < 0 then // ߴ粻ף + Exit; + + Len := Stream.Size - L; + Mem := GetMemory(Len); + if Mem <> nil then + begin + Move(Stream.Memory^, Mem^, Len); + Stream.Clear; + Stream.Write(Mem^, Len); + FreeMemory(Mem); + end; + end; +end; + +function StrAddPKCS7Padding(const Str: AnsiString; BlockSize: Integer): AnsiString; +var + I, L: Integer; + R: Byte; +begin + L := Length(Str); + R := L mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + SetLength(Result, L + R); + if L > 0 then + Move(Str[1], Result[1], L); + + for I := 1 to R do + Result[L + I] := AnsiChar(R); +end; + +function StrRemovePKCS7Padding(const Str: AnsiString): AnsiString; +var + L: Integer; + V: Byte; +begin + Result := Str; + if Result = '' then + Exit; + + L := Length(Result); + V := Ord(Result[L]); // ĩǼʾ˼ + + if V <= L then + Delete(Result, L - V + 1, V); +end; + +procedure AddPKCS5Padding(Stream: TMemoryStream); +begin + AddPKCS7Padding(Stream, PKCS5_BLOCK_SIZE); +end; + +procedure RemovePKCS5Padding(Stream: TMemoryStream); +begin + RemovePKCS7Padding(Stream); +end; + +function StrAddPKCS5Padding(const Str: AnsiString): AnsiString; +begin + Result := StrAddPKCS7Padding(Str, PKCS5_BLOCK_SIZE); +end; + +function StrRemovePKCS5Padding(const Str: AnsiString): AnsiString; +begin + Result := StrRemovePKCS7Padding(Str); +end; + +procedure BytesAddPKCS7Padding(var Data: TBytes; BlockSize: Integer); +var + R: Byte; + L, I: Integer; +begin + L := Length(Data); + R := L mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + SetLength(Data, L + R); + for I := 0 to R - 1 do + Data[L + I] := R; +end; + +procedure BytesRemovePKCS7Padding(var Data: TBytes); +var + L: Integer; + V: Byte; +begin + L := Length(Data); + if L = 0 then + Exit; + + V := Ord(Data[L - 1]); // ĩǼʾ˼ֽ + + if V <= L then + SetLength(Data, L - V); +end; + +procedure BytesAddPKCS5Padding(var Data: TBytes); +begin + BytesAddPKCS7Padding(Data, PKCS5_BLOCK_SIZE); +end; + +procedure BytesRemovePKCS5Padding(var Data: TBytes); +begin + BytesRemovePKCS7Padding(Data); +end; + +function GetISO10126PaddingByteLength(OrignalByteLen: Integer; BlockSize: Integer): Integer; +begin + Result := GetPKCS7PaddingByteLength(OrignalByteLen, BlockSize); // Ϊֱͬӵ +end; + +procedure AddISO10126Padding(Stream: TMemoryStream; BlockSize: Integer); +var + R: Byte; + Buf: array[0..255] of Byte; +begin + R := Stream.Size mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + FillChar(Buf[0], R, 0); + Buf[R - 1] := R; + Stream.Position := Stream.Size; + Stream.Write(Buf[0], R); +end; + +procedure RemoveISO10126Padding(Stream: TMemoryStream); +begin + RemovePKCS7Padding(Stream); // Ϊֱͬӵ +end; + +function StrAddISO10126Padding(const Str: AnsiString; BlockSize: Integer): AnsiString; +var + I, L: Integer; + R: Byte; +begin + L := Length(Str); + R := L mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + SetLength(Result, L + R); + if L > 0 then + Move(Str[1], Result[1], L); + + if R > 1 then + begin + for I := 1 to R - 1 do + Result[L + I] := #0; + end; + Result[L + R] := AnsiChar(R); +end; + +function StrRemoveISO10126Padding(const Str: AnsiString): AnsiString; +begin + Result := StrRemovePKCS7Padding(Str); // Ϊֱͬӵ +end; + +procedure BytesAddISO10126Padding(var Data: TBytes; BlockSize: Integer); +var + R: Byte; + L, I: Integer; +begin + L := Length(Data); + R := L mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + SetLength(Data, L + R); + if R > 1 then + begin + for I := 0 to R - 2 do + Data[L + I] := 0; + end; + Data[L - 1 + R] := R; +end; + +procedure BytesRemoveISO10126Padding(var Data: TBytes); +begin + BytesRemovePKCS7Padding(Data); // Ϊֱͬӵ +end; + +function EncryptPemStream(KeyHash: TCnKeyHashMethod; KeyEncrypt: TCnKeyEncryptMethod; + Stream: TStream; const Password: string; out EncryptedHead: string): Boolean; +const + CRLF = #13#10; +var + ES: TMemoryStream; + Keys: array[0..31] of Byte; //  Key Ҳֻ 32 ֽ + IvStr: AnsiString; + HexIv: string; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AesIv: TCnAESBuffer; + DesKey: TCnDESKey; + Des3Key: TCn3DESKey; + DesIv: TCnDESIv; +begin + Result := False; + + // + if (KeyEncrypt = ckeNone) or (Password = '') then + Exit; + + // Iv + SetLength(IvStr, ENC_TYPE_BLOCK_SIZE[KeyEncrypt]); + CnRandomFillBytes(@(IvStr[1]), ENC_TYPE_BLOCK_SIZE[KeyEncrypt]); + HexIv := DataToHex(@(IvStr[1]), ENC_TYPE_BLOCK_SIZE[KeyEncrypt], True); // Ҫд + + EncryptedHead := ENC_HEAD_PROCTYPE + ' ' + ENC_HEAD_PROCTYPE_NUM + ',' + ENC_HEAD_ENCRYPTED + CRLF; + EncryptedHead := EncryptedHead + ENC_HEAD_DEK + ' ' + ENC_TYPE_STRS[KeyEncrypt] + + '-' + ENC_BLOCK_CBC + ',' + HexIv + CRLF; + + ES := TMemoryStream.Create; + Stream.Position := 0; + + try + if KeyHash = ckhMd5 then + begin + if not CnGetDeriveKey(AnsiString(Password), IvStr, @Keys[0], SizeOf(Keys)) then + Exit; + end + else if KeyHash = ckhSha256 then + begin + if not CnGetDeriveKey(AnsiString(Password), IvStr, @Keys[0], SizeOf(Keys), ckdSha256) then + Exit; + end + else + Exit; + + case KeyEncrypt of + ckeDES: + begin + Move(Keys[0], DesKey[0], SizeOf(TCnDESKey)); + Move(IvStr[1], DesIv[0], SizeOf(TCnDESIv)); + + DESEncryptStreamCBC(Stream, Stream.Size, DesKey, DesIv, ES); + Result := True; + end; + cke3DES: + begin + Move(Keys[0], Des3Key[0], SizeOf(TCn3DESKey)); + Move(IvStr[1], DesIv[0], SizeOf(TCn3DESIv)); + + TripleDESEncryptStreamCBC(Stream, Stream.Size, Des3Key, DesIv, ES); + Result := True; + end; + ckeAES128: + begin + Move(Keys[0], AESKey128[0], SizeOf(TCnAESKey128)); + Move(IvStr[1], AesIv[0], SizeOf(TCnAESBuffer)); + + EncryptAES128StreamCBC(Stream, Stream.Size, AESKey128, AesIv, ES); + Result := True; + end; + ckeAES192: + begin + Move(Keys[0], AESKey192[0], SizeOf(TCnAESKey192)); + Move(IvStr[1], AesIv[0], SizeOf(TCnAESBuffer)); + + EncryptAES192StreamCBC(Stream, Stream.Size, AESKey192, AesIv, ES); + Result := True; + end; + ckeAES256: + begin + Move(Keys[0], AESKey256[0], SizeOf(TCnAESKey256)); + Move(IvStr[1], AesIv[0], SizeOf(TCnAESBuffer)); + + EncryptAES256StreamCBC(Stream, Stream.Size, AESKey256, AesIv, ES); + Result := True; + end; + end; + finally + if ES.Size > 0 then + begin + // ES д Stream + Stream.Size := 0; + Stream.Position := 0; + ES.SaveToStream(Stream); + Stream.Position := 0; + end; + ES.Free; + end; +end; + +// ü㷨㡢ʼ⿪ Base64 Sд Stream +function DecryptPemString(const S, M1, M2, HexIv, Password: string; Stream: TMemoryStream; + KeyHash: TCnKeyHashMethod): Boolean; +var + DS: TMemoryStream; + Keys: array[0..31] of Byte; //  Key Ҳֻ 32 ֽ + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + IvStr: AnsiString; + AesIv: TCnAESBuffer; + DesKey: TCnDESKey; + Des3Key: TCn3DESKey; + DesIv: TCnDESIv; +begin + Result := False; + DS := nil; + + if (M1 = '') or (M2 = '') or (HexIv = '') or (Password = '') then + Exit; + + try + DS := TMemoryStream.Create; + if ECN_BASE64_OK <> Base64Decode(AnsiString(S), DS, False) then + Exit; + + DS.Position := 0; + SetLength(IvStr, HexToData(HexIv)); + if Length(IvStr) > 0 then + HexToData(HexIv, @IvStr[1]); + + // Salt Լ Hash 㷨ӽܵ Key + FillChar(Keys[0], SizeOf(Keys), 0); + if KeyHash = ckhMd5 then + begin + if not CnGetDeriveKey(AnsiString(Password), IvStr, @Keys[0], SizeOf(Keys)) then + Exit; + end + else if KeyHash = ckhSha256 then + begin + if not CnGetDeriveKey(AnsiString(Password), IvStr, @Keys[0], SizeOf(Keys), ckdSha256) then + Exit; + end + else + Exit; + + // DS ģҪ⵽ Stream + if (M1 = ENC_TYPE_AES256) and (M2 = ENC_BLOCK_CBC) then + begin + // ⿪ AES-256-CBC ܵ + Move(Keys[0], AESKey256[0], SizeOf(TCnAESKey256)); + Move(IvStr[1], AesIv[0], Min(SizeOf(TCnAESBuffer), Length(IvStr))); + + DecryptAES256StreamCBC(DS, DS.Size, AESKey256, AesIv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end + else if (M1 = ENC_TYPE_AES192) and (M2 = ENC_BLOCK_CBC) then + begin + // ⿪ AES-192-CBC ܵ + Move(Keys[0], AESKey192[0], SizeOf(TCnAESKey192)); + Move(IvStr[1], AesIv[0], Min(SizeOf(TCnAESBuffer), Length(IvStr))); + + DecryptAES192StreamCBC(DS, DS.Size, AESKey192, AesIv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end + else if (M1 = ENC_TYPE_AES128) and (M2 = ENC_BLOCK_CBC) then + begin + // ⿪ AES-128-CBC ܵģ D5 òƿ Bug ³ AV + Move(Keys[0], AESKey128[0], SizeOf(TCnAESKey128)); + Move(IvStr[1], AesIv[0], Min(SizeOf(TCnAESBuffer), Length(IvStr))); + + DecryptAES128StreamCBC(DS, DS.Size, AESKey128, AesIv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end + else if (M1 = ENC_TYPE_DES) and (M2 = ENC_BLOCK_CBC) then + begin + // ⿪ DES-CBC ܵ + Move(Keys[0], DesKey[0], SizeOf(TCnDESKey)); + Move(IvStr[1], DesIv[0], Min(SizeOf(TCnDESIv), Length(IvStr))); + + DESDecryptStreamCBC(DS, DS.Size, DesKey, DesIv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end + else if (M1 = ENC_TYPE_3DES) and (M2 = ENC_BLOCK_CBC) then + begin + // ⿪ 3DES-CBC ܵ + Move(Keys[0], Des3Key[0], SizeOf(TCn3DESKey)); + Move(IvStr[1], DesIv[0], Min(SizeOf(TCn3DESIv), Length(IvStr))); + + TripleDESDecryptStreamCBC(DS, DS.Size, Des3Key, DesIv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end; + finally + DS.Free; + end; +end; + +function LoadPemStreamToMemory(Stream: TStream; const ExpectHead, ExpectTail: string; + MemoryStream: TMemoryStream; const Password: string; KeyHashMethod: TCnKeyHashMethod): Boolean; +var + I, J, HeadIndex, TailIndex: Integer; + S, L1, L2, M1, M2, M3: string; + Sl: TStringList; +begin + Result := False; + + if (Stream <> nil) and (Stream.Size > 0) and (ExpectHead <> '') and (ExpectTail <> '') then + begin + Sl := TStringList.Create; + try + Sl.LoadFromStream(Stream); + if Sl.Count > 2 then + begin + HeadIndex := -1; + for I := 0 to Sl.Count - 1 do + begin + if Trim(Sl[I]) = ExpectHead then + begin + HeadIndex := I; + Break; + end; + end; + + if HeadIndex < 0 then + Exit; + + if HeadIndex > 0 then + for I := 0 to HeadIndex - 1 do + Sl.Delete(0); + + // ҵͷˣβ + + TailIndex := -1; + for I := 0 to Sl.Count - 1 do + begin + if Trim(Sl[I]) = ExpectTail then + begin + TailIndex := I; + Break; + end; + end; + + if TailIndex > 0 then // ҵβͣɾβͺĶ + begin + if TailIndex < Sl.Count - 1 then + for I := Sl.Count - 1 downto TailIndex + 1 do + Sl.Delete(Sl.Count - 1); + end + else + Exit; + + if Sl.Count < 2 then // ûݣ˳ + Exit; + + // ͷβ֤ͨǰжǷ + L1 := Sl[1]; + if Pos(ENC_HEAD_PROCTYPE, L1) = 1 then // Ǽܵ + begin + Delete(L1, 1, Length(ENC_HEAD_PROCTYPE)); + I := Pos(',', L1); + if I <= 1 then + Exit; + + if Trim(Copy(L1, 1, I - 1)) <> ENC_HEAD_PROCTYPE_NUM then + Exit; + + if Trim(Copy(L1, I + 1, MaxInt)) <> ENC_HEAD_ENCRYPTED then + Exit; + + // ProcType: 4,ENCRYPTED жͨ + + L2 := Sl[2]; + if Pos(ENC_HEAD_DEK, L2) <> 1 then + Exit; + + Delete(L2, 1, Length(ENC_HEAD_DEK)); + I := Pos(',', L2); + if I <= 1 then + Exit; + + M1 := Trim(Copy(L2, 1, I - 1)); // õ AES256-CBC + M3 := UpperCase(Trim(Copy(L2, I + 1, MaxInt))); // õʱʹõijʼ + I := Pos('-', M1); + if I <= 1 then + Exit; + J := Pos('-', Copy(M1, I + 1, MaxInt)); + if J > 0 then + I := I + J; // AES-256-CBC + + M2 := UpperCase(Trim(Copy(M1, I + 1, MaxInt))); // õģʽ ECB CBC + M1 := UpperCase(Trim(Copy(M1, 1, I - 1))); // õ㷨 DES AES + + // ͷβȫɾ + Sl.Delete(Sl.Count - 1); + Sl.Delete(0); + Sl.Delete(0); + Sl.Delete(0); + + S := ''; + for I := 0 to Sl.Count - 1 do + S := S + Sl[I]; + + S := Trim(S); + + Result := DecryptPemString(S, M1, M2, M3, Password, MemoryStream, KeyHashMethod); + end + else // δܵģƴճ Base64 + begin + Sl.Delete(Sl.Count - 1); + Sl.Delete(0); + S := ''; + for I := 0 to Sl.Count - 1 do + S := S + Sl[I]; + + S := Trim(S); + + // To De Base64 S + MemoryStream.Clear; +{$IFDEF UNICODE} + Result := (ECN_BASE64_OK = Base64Decode(AnsiString(S), MemoryStream, False)); +{$ELSE} + Result := (ECN_BASE64_OK = Base64Decode(S, MemoryStream, False)); +{$ENDIF} + end; + end; + finally + Sl.Free; + end; + end; +end; + +function LoadPemFileToMemory(const FileName, ExpectHead, ExpectTail: string; + MemoryStream: TMemoryStream; const Password: string; KeyHashMethod: TCnKeyHashMethod): Boolean; +var + Stream: TStream; +begin + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + Result := LoadPemStreamToMemory(Stream, ExpectHead, ExpectTail, MemoryStream, Password, KeyHashMethod); + finally + Stream.Free; + end; +end; + +procedure SplitStringToList(const S: string; List: TStrings); +const + LINE_WIDTH = 64; +var + C, R: string; +begin + if List = nil then + Exit; + + List.Clear; + if S <> '' then + begin + R := S; + while R <> '' do + begin + C := Copy(R, 1, LINE_WIDTH); + Delete(R, 1, LINE_WIDTH); + List.Add(C); + end; + end; +end; + +function SaveMemoryToPemFile(const FileName, Head, Tail: string; + MemoryStream: TMemoryStream; KeyEncryptMethod: TCnKeyEncryptMethod; + KeyHashMethod: TCnKeyHashMethod; const Password: string; Append: Boolean): Boolean; +var + S, EH: string; + List, Sl: TStringList; +begin + Result := False; + if (MemoryStream <> nil) and (MemoryStream.Size <> 0) then + begin + MemoryStream.Position := 0; + + if (KeyEncryptMethod <> ckeNone) and (Password <> '') then + begin + // MemoryStream + AddPKCS7Padding(MemoryStream, ENC_TYPE_BLOCK_SIZE[KeyEncryptMethod]); + + // ټ + if not EncryptPemStream(KeyHashMethod, KeyEncryptMethod, MemoryStream, Password, EH) then + Exit; + end; + + if ECN_BASE64_OK = Base64Encode(MemoryStream, S) then + begin + List := TStringList.Create; + try + SplitStringToList(S, List); + + List.Insert(0, Head); // ͨͷ + if EH <> '' then // ͷ + List.Insert(1, EH); + List.Add(Tail); // ͨβ + + if Append and FileExists(FileName) then + begin + Sl := TStringList.Create; + try + Sl.LoadFromFile(FileName); + Sl.AddStrings(List); + Sl.SaveToFile(FileName); + finally + Sl.Free; + end; + end + else + List.SaveToFile(FileName); + + Result := True; + finally + List.Free; + end; + end; + end; +end; + +function SaveMemoryToPemStream(Stream: TStream; const Head, Tail: string; + MemoryStream: TMemoryStream; KeyEncryptMethod: TCnKeyEncryptMethod; + KeyHashMethod: TCnKeyHashMethod; const Password: string; Append: Boolean): Boolean; +var + S, EH: string; + List: TStringList; +begin + Result := False; + if (MemoryStream <> nil) and (MemoryStream.Size <> 0) then + begin + MemoryStream.Position := 0; + + if (KeyEncryptMethod <> ckeNone) and (Password <> '') then + begin + // MemoryStream + AddPKCS7Padding(MemoryStream, ENC_TYPE_BLOCK_SIZE[KeyEncryptMethod]); + + // ټ + if not EncryptPemStream(KeyHashMethod, KeyEncryptMethod, MemoryStream, Password, EH) then + Exit; + end; + + if ECN_BASE64_OK = Base64Encode(MemoryStream, S) then + begin + List := TStringList.Create; + try + SplitStringToList(S, List); + + List.Insert(0, Head); // ͨͷ + if EH <> '' then // ͷ + List.Insert(1, EH); + List.Add(Tail); // ͨβ + + if not Append then + Stream.Size := 0; + + List.SaveToStream(Stream); + + Result := True; + finally + List.Free; + end; + end; + end; +end; + +end. diff --git a/CnPack/Crypto/CnRandom.dcu b/CnPack/Crypto/CnRandom.dcu new file mode 100644 index 0000000000000000000000000000000000000000..c89e954877a4cd1e8e54c20ff7c9e1f2ca04318b GIT binary patch literal 5673 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 literal 0 HcmV?d00001 diff --git a/CnPack/Crypto/CnRandom.pas b/CnPack/Crypto/CnRandom.pas new file mode 100644 index 0000000..de6a2c3 --- /dev/null +++ b/CnPack/Crypto/CnRandom.pas @@ -0,0 +1,415 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2025 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnRandom; +{* |
+================================================================================
+* ƣ
+* Ԫƣ䵥Ԫ
+* ԪߣCnPack  (master@cnpack.org)
+*     עԪװ Windows ƽ̨ MacOS/Linux ƽ̨µİȫ
+*           ṩȫ书ܡ
+* ƽ̨Win7 + Delphi 5.0
+* ݲԣWin32/Win64/MacOS/Linux + Unicode/NonUnicode
+*   õԪ豾ػ
+* ޸ļ¼2023.01.15 V1.3
+*                Windows ȫ urandom ֧ Linux
+*           2023.01.08 V1.2
+*                Win64  API 
+*           2022.08.22 V1.1
+*               ʹòϵͳṩ
+*           2020.03.27 V1.0
+*               Ԫ CnPrime ж
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + SysUtils {$IFDEF MSWINDOWS}, Windows {$ENDIF}, Classes, CnNative; + +type + ECnRandomAPIError = class(Exception); + +function RandomUInt64: TUInt64; +{* UInt64 Χڵڲ֧ UInt64 ƽ̨ Int64 档 + + + ޣ + + ֵTUInt64 - UInt64 Χڵ +} + +function RandomUInt64LessThan(HighValue: TUInt64): TUInt64; +{* شڵ 0 Сָ UInt64 ֵ + + + HighValue: TUInt64 - ָ UInt64 + + ֵTUInt64 - شڵ 0 Сָ HighValue +} + +function RandomInt64: Int64; +{* شڵ 0 С Int64 ޵ + + + ޣ + + ֵInt64 - شڵ 0 С Int64 ޵ +} + +function RandomInt64LessThan(HighValue: Int64): Int64; +{* شڵ 0 Сָ Int64 ֵб֤ HighValue 0 + + + HighValue: Int64 - ָ Int64 + + ֵInt64 - شڵ 0 Сָ HighValue +} + +function RandomUInt32: Cardinal; +{* UInt32 Χڵ + + + ޣ + + ֵCardinal - UInt32 Χڵ +} + +function RandomUInt32LessThan(HighValue: Cardinal): Cardinal; +{* شڵ 0 Сָ UInt32 ֵ + + + HighValue: Cardinal - ָ UInt32 + + ֵCardinal - شڵ 0 Сָ HighValue +} + +function RandomInt32: Integer; +{* شڵ 0 С Int32 ޵ + + + ޣ + + ֵInteger - شڵ 0 С Int32 ޵ +} + +function RandomInt32LessThan(HighValue: Integer): Integer; +{* شڵ 0 Сָ Int32 б֤ HighValue 0 + + + HighValue: Integer - ָ Int32 + + ֵInteger - شڵ 0 Сָ HighValue +} + +function CnKnuthShuffle(ArrayBase: Pointer; ElementByteSize: Integer; + ElementCount: Integer): Boolean; +{* ߵϴ㷨 ArrayBase ָԪسߴΪ ElementSize ElementCount Ԫؾϴơ + + + ArrayBase: Pointer - ϴƵڴַ + ElementByteSize: Integer - ϴƵÿڴԪҲÿһƵֽڴС + ElementCount: Integer - ڴԪҲƵ + + ֵBoolean - ϴǷɹ +} + +function CnRandomFillBytes(Buf: PAnsiChar; BufByteLen: Integer): Boolean; +{* ʹ Windows API /dev/random 豸ʵ䣬ڲγʼ沢ͷš + + + Buf: PAnsiChar - ڴַ + BufByteLen: Integer - ڴֽڳ + + ֵBoolean - Ƿɹ +} + +function CnRandomFillBytes2(Buf: PAnsiChar; BufByteLen: Integer): Boolean; +{* ʹ Windows API /dev/urandom 豸ʵ䣬 + Windows ʹԤȳʼõ١ + + + Buf: PAnsiChar - ڴַ + BufByteLen: Integer - ڴֽڳ + + ֵBoolean - Ƿɹ +} + +implementation + +{$IFDEF MSWINDOWS} + +const + ADVAPI32 = 'advapi32.dll'; + + CRYPT_VERIFYCONTEXT = $F0000000; + CRYPT_NEWKEYSET = $8; + CRYPT_DELETEKEYSET = $10; + + PROV_RSA_FULL = 1; + NTE_BAD_KEYSET = $80090016; + +function CryptAcquireContext(phProv: PHandle; pszContainer: PAnsiChar; + pszProvider: PAnsiChar; dwProvType: LongWord; dwFlags: LongWord): BOOL; + stdcall; external ADVAPI32 name 'CryptAcquireContextA'; + +function CryptReleaseContext(hProv: THandle; dwFlags: LongWord): BOOL; + stdcall; external ADVAPI32 name 'CryptReleaseContext'; + +function CryptGenRandom(hProv: THandle; dwLen: LongWord; pbBuffer: PAnsiChar): BOOL; + stdcall; external ADVAPI32 name 'CryptGenRandom'; + +var + FHProv: THandle = 0; + +{$ELSE} + +const + DEV_FILE = '/dev/urandom'; + +{$ENDIF} + +function CnRandomFillBytes(Buf: PAnsiChar; BufByteLen: Integer): Boolean; +var +{$IFDEF MSWINDOWS} + HProv: THandle; + Res: DWORD; + B: Boolean; +{$ELSE} + F: TFileStream; +{$ENDIF} +begin + Result := False; +{$IFDEF MSWINDOWS} + // ʹ Windows API ʵ + HProv := 0; + B := CryptAcquireContext(@HProv, nil, nil, PROV_RSA_FULL, 0); + if not B then + B := CryptAcquireContext(@HProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + + if not B then + begin + Res := GetLastError; + if Res = NTE_BAD_KEYSET then // KeyContainer ڣ½ķʽ + begin + if not CryptAcquireContext(@HProv, nil, nil, PROV_RSA_FULL, CRYPT_NEWKEYSET) then + raise ECnRandomAPIError.CreateFmt('Error CryptAcquireContext NewKeySet $%8.8x', [GetLastError]); + end + else + raise ECnRandomAPIError.CreateFmt('Error CryptAcquireContext $%8.8x', [Res]); + end; + + if HProv <> 0 then + begin + try + Result := CryptGenRandom(HProv, BufByteLen, Buf); + if not Result then + raise ECnRandomAPIError.CreateFmt('Error CryptGenRandom $%8.8x', [GetLastError]); + finally + CryptReleaseContext(HProv, 0); + end; + end; +{$ELSE} + // MacOS/Linux µʵ֣öȡ /dev/urandom ݵķʽ + F := nil; + try + F := TFileStream.Create(DEV_FILE, fmOpenRead); + Result := F.Read(Buf^, BufByteLen) = BufByteLen; + finally + F.Free; + end; +{$ENDIF} +end; + +function CnRandomFillBytes2(Buf: PAnsiChar; BufByteLen: Integer): Boolean; +{$IFNDEF MSWINDOWS} +var + F: TFileStream; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + Result := CryptGenRandom(FHProv, BufByteLen, Buf); +{$ELSE} + // MacOS/Linux µʵ֣öȡ /dev/urandom ݵķʽ + F := nil; + try + F := TFileStream.Create(DEV_FILE, fmOpenRead); + Result := F.Read(Buf^, BufByteLen) = BufByteLen; + finally + F.Free; + end; +{$ENDIF} +end; + +function RandomUInt64: TUInt64; +var + HL: array[0..1] of Cardinal; +begin + // ϵͳ + if not CnRandomFillBytes2(@HL[0], SizeOf(TUInt64)) then + begin + // ֱ Random * High(TUInt64) ܻᾫȲ Lo ȫ FF˷ֿ + Randomize; + HL[0] := Trunc(Random * High(Cardinal) - 1) + 1; + HL[1] := Trunc(Random * High(Cardinal) - 1) + 1; + end; + + Result := (TUInt64(HL[0]) shl 32) + HL[1]; +end; + +function RandomUInt64LessThan(HighValue: TUInt64): TUInt64; +begin + Result := UInt64Mod(RandomUInt64, HighValue); +end; + +function RandomInt64LessThan(HighValue: Int64): Int64; +var + HL: array[0..1] of Cardinal; +begin + // ϵͳ + if not CnRandomFillBytes2(@HL[0], SizeOf(Int64)) then + begin + // ֱ Random * High(Int64) ܻᾫȲ Lo ȫ FF˷ֿ + Randomize; + HL[0] := Trunc(Random * High(Integer) - 1) + 1; // Int64 λ 1⸺ + HL[1] := Trunc(Random * High(Cardinal) - 1) + 1; + end + else + HL[0] := HL[0] mod (Cardinal(High(Integer)) + 1); // Int64 λ 1⸺ + + Result := (Int64(HL[0]) shl 32) + HL[1]; + Result := Result mod HighValue; // δ HighValue Сڵ 0 +end; + +function RandomInt64: Int64; +begin + Result := RandomInt64LessThan(High(Int64)); +end; + +function RandomUInt32: Cardinal; +var + D: Cardinal; +begin + // ϵͳ + if not CnRandomFillBytes2(@D, SizeOf(Cardinal)) then + begin + Randomize; + D := Trunc(Random * High(Cardinal) - 1) + 1; + end; + + Result := D; +end; + +function RandomUInt32LessThan(HighValue: Cardinal): Cardinal; +begin + Result := RandomUInt32 mod HighValue; +end; + +function RandomInt32: Integer; +begin + Result := RandomInt32LessThan(High(Integer)); +end; + +function RandomInt32LessThan(HighValue: Integer): Integer; +var + D: Cardinal; +begin + // ϵͳ + if not CnRandomFillBytes2(@D, SizeOf(Cardinal)) then + begin + Randomize; + D := Trunc(Random * High(Integer) - 1) + 1; + end + else + D := D mod (Cardinal(High(Integer)) + 1); + + Result := Integer(Int64(D) mod Int64(HighValue)); // δ HighValue Сڵ 0 +end; + +function CnKnuthShuffle(ArrayBase: Pointer; ElementByteSize: Integer; + ElementCount: Integer): Boolean; +var + I, R: Integer; + B1, B2: Pointer; +begin + Result := False; + if (ArrayBase = nil) or (ElementByteSize <= 0) or (ElementCount < 0) then // Ȳ + Exit; + + Result := True; + if ElementCount <= 1 then // ûԪػֻһԪʱϴ + Exit; + + for I := ElementCount - 1 downto 0 do + begin + R := RandomInt32LessThan(I + 1); // 0 I ڵҪ 1 + B1 := Pointer(TCnNativeUInt(ArrayBase) + TCnNativeUInt(I * ElementByteSize)); + B2 := Pointer(TCnNativeUInt(ArrayBase) + TCnNativeUInt(R * ElementByteSize)); + MemorySwap(B1, B2, ElementByteSize); + end; + Result := True; +end; + +{$IFDEF MSWINDOWS} + +procedure StartRandom; +var + Res: DWORD; + B: Boolean; +begin + FHProv := 0; + B := CryptAcquireContext(@FHProv, nil, nil, PROV_RSA_FULL, 0); + if not B then + B := CryptAcquireContext(@FHProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + + if not B then + begin + Res := GetLastError; + if Res = NTE_BAD_KEYSET then // KeyContainer ڣ½ķʽ + begin + if not CryptAcquireContext(@FHProv, nil, nil, PROV_RSA_FULL, CRYPT_NEWKEYSET) then + raise ECnRandomAPIError.CreateFmt('Error CryptAcquireContext NewKeySet $%8.8x', [GetLastError]); + end + else + raise ECnRandomAPIError.CreateFmt('Error CryptAcquireContext $%8.8x', [Res]); + end; +end; + +procedure StopRandom; +begin + if FHProv <> 0 then + begin + CryptReleaseContext(FHProv, 0); + FHProv := 0; + end; +end; + +initialization + StartRandom; + +finalization + StopRandom; + +{$ENDIF} + +end. diff --git a/CnPack/Crypto/CnSHA1.dcu b/CnPack/Crypto/CnSHA1.dcu new file mode 100644 index 0000000000000000000000000000000000000000..a3f75043eb9f12c9d50a84dbf880dc9592c6e5f6 GIT binary patch literal 10859 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 QlTU=35CcrI#ct;Ke<$eb%>V!Z literal 0 HcmV?d00001 diff --git a/CnPack/Crypto/CnSHA1.pas b/CnPack/Crypto/CnSHA1.pas new file mode 100644 index 0000000..4daf51e --- /dev/null +++ b/CnPack/Crypto/CnSHA1.pas @@ -0,0 +1,737 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2025 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnSHA1; +{* |
+================================================================================
+* ƣ
+* ԪƣSHA1 Ӵ㷨ʵֵԪ
+* ԪߣCnPack  (master@cnpack.org)
+*           /ֲ䲿ֹܡ
+*     עԪʵ SHA1 Ӵ㷨Ӧ HMAC 㷨
+* ƽ̨PWin2000Pro + Delphi 5.0
+* ݲԣPWin9X/2000/XP + Delphi 5/6
+*   õԪеַϱػʽ
+* ޸ļ¼2022.04.26 V1.5
+*               ޸ LongWord  Integer ַת֧ MacOS64
+*           2019.12.12 V1.4
+*               ֧ TBytes
+*           2019.04.15 V1.3
+*               ֧ Win32/Win64/MacOS32
+*           2015.08.14 V1.2
+*               л Pascal ֿ֧ƽ̨
+*           2014.10.22 V1.1
+*                HMAC 
+*           2010.07.14 V1.0
+*               Ԫ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes {$IFDEF MSWINDOWS}, Windows {$ENDIF}, CnNative, CnConsts; + +type + PCnSHA1Digest = ^TCnSHA1Digest; + TCnSHA1Digest = array[0..19] of Byte; + {* SHA1 Ӵս20 ֽ} + + TCnSHA1Context = record + {* SHA1 Ľṹ} + Hash: array[0..4] of Cardinal; + Hi, Lo: Cardinal; + Buffer: array[0..63] of Byte; + Index: Integer; + Ipad: array[0..63] of Byte; {!< HMAC: inner padding } + Opad: array[0..63] of Byte; {!< HMAC: outer padding } + end; + + TCnSHA1CalcProgressFunc = procedure (ATotal, AProgress: Int64; + var Cancel: Boolean) of object; + {* SHA1 ӴսȻص¼} + +function SHA1(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA1Digest; +{* ݿ SHA1 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1Buffer(const Buffer; Count: Cardinal): TCnSHA1Digest; +{* ݿ SHA1 㡣 + + + const Buffer - ݿַ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1Bytes(Data: TBytes): TCnSHA1Digest; +{* ֽ SHA1 㡣 + + + Data: TBytes - ֽ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1String(const Str: string): TCnSHA1Digest; +{* String ݽ SHA1 㡣ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1StringA(const Str: AnsiString): TCnSHA1Digest; +{* AnsiString ַ SHA1 㣬ֱӼڲݣޱ봦 + + + const Str: AnsiString - ַ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1StringW(const Str: WideString): TCnSHA1Digest; +{* WideString ַת SHA1 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +{$IFDEF UNICODE} + +function SHA1UnicodeString(const Str: string): TCnSHA1Digest; +{* UnicodeString ݽֱӵ SHA1 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +{$ELSE} + +function SHA1UnicodeString(const Str: WideString): TCnSHA1Digest; +{* UnicodeString ݽֱӵ SHA1 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +{$ENDIF} + +function SHA1File(const FileName: string; + CallBack: TCnSHA1CalcProgressFunc = nil): TCnSHA1Digest; +{* ָļݽ SHA1 㡣 + + + const FileName: string - ļ + CallBack: TCnSHA1CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1Stream(Stream: TStream; + CallBack: TCnSHA1CalcProgressFunc = nil): TCnSHA1Digest; +{* ָݽ SHA1 㡣 + + + Stream: TStream - + CallBack: TCnSHA1CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +// ⲿݽɢ SHA1 㣬SHA1Update ɶα + +procedure SHA1Init(var Context: TCnSHA1Context); +{* ʼһ SHA1 ģ׼ SHA1 + + + var Context: TCnSHA1Context - ʼ SHA1 + + ֵޣ +} + +procedure SHA1Update(var Context: TCnSHA1Context; Input: PAnsiChar; ByteLength: Integer); +{* ԳʼĶһݽ SHA1 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA1Context - SHA1 + Input: PAnsiChar - ݿַ + ByteLength: Integer - ݿֽڳ + + ֵޣ +} + +procedure SHA1Final(var Context: TCnSHA1Context; var Digest: TCnSHA1Digest); +{* ּ㣬 SHA1 Digest С + + + var Context: TCnSHA1Context - SHA1 + var Digest: TCnSHA1Digest - ص SHA1 Ӵֵ + + ֵޣ +} + +function SHA1Print(const Digest: TCnSHA1Digest): string; +{* ʮƸʽ SHA1 Ӵֵ + + + const Digest: TCnSHA1Digest - ָ SHA1 Ӵֵ + + ֵstring - ʮַ +} + +function SHA1Match(const D1: TCnSHA1Digest; const D2: TCnSHA1Digest): Boolean; +{* Ƚ SHA1 ӴֵǷȡ + + + const D1: TCnSHA1Digest - Ƚϵ SHA1 Ӵֵһ + const D2: TCnSHA1Digest - Ƚϵ SHA1 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA1DigestToStr(const Digest: TCnSHA1Digest): string; +{* SHA1 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA1Digest - ת SHA1 Ӵֵ + + ֵstring - صַ +} + +procedure SHA1Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA1Digest); +{* SHA1 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA1 Կݿַ + KeyByteLength: Integer - SHA1 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA1Digest - ص SHA1 Ӵֵ + + ֵޣ +} + +implementation + +const + MAX_FILE_SIZE = 512 * 1024 * 1024; + // If file size <= this size (bytes), using Mapping, else stream + + HMAC_SHA1_BLOCK_SIZE_BYTE = 64; + HMAC_SHA1_OUTPUT_LENGTH_BYTE = 20; + +function LRot32(X: Cardinal; C: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X shl (C and 31) + X shr (32 - C and 31); +end; + +function F1(x, y, z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := z xor (x and (y xor z)); +end; + +function F2(x, y, z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := x xor y xor z; +end; + +function F3(x, y, z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (x and y) or (z and (x or y)); +end; + +function RB(A: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (A shr 24) or ((A shr 8) and $FF00) or ((A shl 8) and $FF0000) or (A shl 24); +end; + +procedure SHA1Compress(var Data: TCnSHA1Context); +var + A, B, C, D, E, T: Cardinal; + W: array[0..79] of Cardinal; + I: Integer; +begin + Move(Data.Buffer, W, Sizeof(Data.Buffer)); + for I := 0 to 15 do + W[I] := RB(W[I]); + for I := 16 to 79 do + W[I] := LRot32(W[I - 3] xor W[I - 8] xor W[I - 14] xor W[I - 16], 1); + A := Data.Hash[0]; + B := Data.Hash[1]; + C := Data.Hash[2]; + D := Data.Hash[3]; + E := Data.Hash[4]; + for I := 0 to 19 do + begin + T := LRot32(A, 5) + F1(B, C, D) + E + W[I] + $5A827999; + E := D; + D := C; + C := LRot32(B, 30); + B := A; + A := T; + end; + for I := 20 to 39 do + begin + T := LRot32(A, 5) + F2(B, C, D) + E + W[I] + $6ED9EBA1; + E := D; + D := C; + C := LRot32(B, 30); + B := A; + A := T; + end; + for I := 40 to 59 do + begin + T := LRot32(A, 5) + F3(B, C, D) + E + W[I] + $8F1BBCDC; + E := D; + D := C; + C := LRot32(B, 30); + B := A; + A := T; + end; + for I := 60 to 79 do + begin + T := LRot32(A, 5) + F2(B, C, D) + E + W[I] + $CA62C1D6; + E := D; + D := C; + C := LRot32(B, 30); + B := A; + A := T; + end; + Data.Hash[0] := Data.Hash[0] + A; + Data.Hash[1] := Data.Hash[1] + B; + Data.Hash[2] := Data.Hash[2] + C; + Data.Hash[3] := Data.Hash[3] + D; + Data.Hash[4] := Data.Hash[4] + E; + FillChar(W, Sizeof(W), 0); + FillChar(Data.Buffer, Sizeof(Data.Buffer), 0); +end; + +procedure SHA1Init(var Context: TCnSHA1Context); +begin + Context.Hi := 0; + Context.Lo := 0; + Context.Index := 0; + FillChar(Context.Buffer, Sizeof(Context.Buffer), 0); + Context.Hash[0] := $67452301; + Context.Hash[1] := $EFCDAB89; + Context.Hash[2] := $98BADCFE; + Context.Hash[3] := $10325476; + Context.Hash[4] := $C3D2E1F0; +end; + +procedure SHA1UpdateLen(var Context: TCnSHA1Context; Len: Integer); +var + I: Cardinal; + K: Integer; +begin + for K := 0 to 7 do + begin + I := Context.Lo; + Inc(Context.Lo, Len); + if Context.Lo < I then + Inc(Context.Hi); + end; +end; + +procedure SHA1Update(var Context: TCnSHA1Context; Input: PAnsiChar; ByteLength: Integer); +begin + SHA1UpdateLen(Context, ByteLength); + while ByteLength > 0 do + begin + Context.Buffer[Context.Index] := PByte(Input)^; + Inc(PByte(Input)); + Inc(Context.Index); + Dec(ByteLength); + if Context.Index = 64 then + begin + Context.Index := 0; + SHA1Compress(Context); + end; + end; +end; + +procedure SHA1UpdateW(var Context: TCnSHA1Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + pContent: PAnsiChar; + iLen: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(pContent, CharLength * SizeOf(WideChar)); + try + iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(pContent), CharLength * SizeOf(WideChar), nil, nil); + SHA1Update(Context, pContent, iLen); + finally + FreeMem(pContent); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + SHA1Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +procedure SHA1Final(var Context: TCnSHA1Context; var Digest: TCnSHA1Digest); +type + PDWord = ^Cardinal; +begin + Context.Buffer[Context.Index] := $80; + if Context.Index >= 56 then + SHA1Compress(Context); + PDWord(@Context.Buffer[56])^ := RB(Context.Hi); + PDWord(@Context.Buffer[60])^ := RB(Context.Lo); + SHA1Compress(Context); + Context.Hash[0] := RB(Context.Hash[0]); + Context.Hash[1] := RB(Context.Hash[1]); + Context.Hash[2] := RB(Context.Hash[2]); + Context.Hash[3] := RB(Context.Hash[3]); + Context.Hash[4] := RB(Context.Hash[4]); + Move(Context.Hash, Digest, Sizeof(Digest)); +end; + +// ݿ SHA1 +function SHA1(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1Update(Context, Input, ByteLength); + SHA1Final(Context, Result); +end; + +// ݿ SHA1 +function SHA1Buffer(const Buffer; Count: Cardinal): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1Update(Context, PAnsiChar(Buffer), Count); + SHA1Final(Context, Result); +end; + +function SHA1Bytes(Data: TBytes): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA1Final(Context, Result); +end; + +// String ݽ SHA1 +function SHA1String(const Str: string): TCnSHA1Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA1StringA(AStr); +end; + +// AnsiString ݽ SHA1 +function SHA1StringA(const Str: AnsiString): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1Update(Context, PAnsiChar(Str), Length(Str)); + SHA1Final(Context, Result); +end; + +// WideString ݽ SHA1 +function SHA1StringW(const Str: WideString): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1UpdateW(Context, PWideChar(Str), Length(Str)); + SHA1Final(Context, Result); +end; + +{$IFDEF UNICODE} +function SHA1UnicodeString(const Str: string): TCnSHA1Digest; +{$ELSE} +function SHA1UnicodeString(const Str: WideString): TCnSHA1Digest; +{$ENDIF} +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA1Final(Context, Result); +end; + +function InternalSHA1Stream(Stream: TStream; const BufSize: Cardinal; var D: + TCnSHA1Digest; CallBack: TCnSHA1CalcProgressFunc = nil): Boolean; +var + Context: TCnSHA1Context; + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; +begin + Result := False; + Size := Stream.Size; + SavePos := Stream.Position; + TotalBytes := 0; + if Size = 0 then Exit; + if Size < BufSize then BufLen := Size + else BufLen := BufSize; + + CancelCalc := False; + SHA1Init(Context); + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + SHA1Update(Context, Buf, ReadBytes); + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + SHA1Final(Context, D); + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +// ָ SHA1 +function SHA1Stream(Stream: TStream; + CallBack: TCnSHA1CalcProgressFunc = nil): TCnSHA1Digest; +begin + InternalSHA1Stream(Stream, 4096 * 1024, Result, CallBack); +end; + +// ָļݽ SHA1 +function SHA1File(const FileName: string; + CallBack: TCnSHA1CalcProgressFunc): TCnSHA1Digest; +var +{$IFDEF MSWINDOWS} + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; + Context: TCnSHA1Context; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; + + function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; +{$IFDEF MSWINDOWS} + var + H: THandle; + Info: BY_HANDLE_FILE_INFORMATION; + Rec : Int64Rec; +{$ENDIF} + begin +{$IFDEF MSWINDOWS} + Result := False; + IsEmpty := False; + H := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); + if H = INVALID_HANDLE_VALUE then Exit; + try + if not GetFileInformationByHandle(H, Info) then Exit; + finally + CloseHandle(H); + end; + Rec.Lo := Info.nFileSizeLow; + Rec.Hi := Info.nFileSizeHigh; + Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); + IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); +{$ELSE} + Result := True; // Windows ƽ̨ Trueʾ Mapping +{$ENDIF} + end; + +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣ Windows ƽ̨ʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalSHA1Stream(Stream, 4096 * 1024, Result, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + SHA1Init(Context); + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + SHA1Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise Exception.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise Exception.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + SHA1Final(Context, Result); +{$ENDIF} + end; +end; + +// ʮƸʽ SHA1 Ӵֵ +function SHA1Print(const Digest: TCnSHA1Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA1Digest)); +end; + +// Ƚ SHA1 ӴֵǷ +function SHA1Match(const D1, D2: TCnSHA1Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 20) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// SHA1 Ӵֵת string +function SHA1DigestToStr(const Digest: TCnSHA1Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA1Digest)); +end; + +procedure SHA1HmacInit(var Ctx: TCnSHA1Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA1Digest; +begin + if KeyLength > HMAC_SHA1_BLOCK_SIZE_BYTE then + begin + Sum := SHA1Buffer(Key, KeyLength); + KeyLength := HMAC_SHA1_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Ctx.Ipad, HMAC_SHA1_BLOCK_SIZE_BYTE, $36); + FillChar(Ctx.Opad, HMAC_SHA1_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Ctx.Ipad[I] := Byte(Ctx.Ipad[I] xor Byte(Key[I])); + Ctx.Opad[I] := Byte(Ctx.Opad[I] xor Byte(Key[I])); + end; + + SHA1Init(Ctx); + SHA1Update(Ctx, @(Ctx.Ipad[0]), HMAC_SHA1_BLOCK_SIZE_BYTE); +end; + +procedure SHA1HmacUpdate(var Ctx: TCnSHA1Context; Input: PAnsiChar; Length: Cardinal); +begin + SHA1Update(Ctx, Input, Length); +end; + +procedure SHA1HmacFinal(var Ctx: TCnSHA1Context; var Output: TCnSHA1Digest); +var + Len: Integer; + TmpBuf: TCnSHA1Digest; +begin + Len := HMAC_SHA1_OUTPUT_LENGTH_BYTE; + SHA1Final(Ctx, TmpBuf); + SHA1Init(Ctx); + SHA1Update(Ctx, @(Ctx.Opad[0]), HMAC_SHA1_BLOCK_SIZE_BYTE); + SHA1Update(Ctx, @(TmpBuf[0]), Len); + SHA1Final(Ctx, Output); +end; + +procedure SHA1Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA1Digest); +var + Ctx: TCnSHA1Context; +begin + SHA1HmacInit(Ctx, Key, KeyByteLength); + SHA1HmacUpdate(Ctx, Input, ByteLength); + SHA1HmacFinal(Ctx, Output); +end; + +end. diff --git a/CnPack/Crypto/CnSHA2.dcu b/CnPack/Crypto/CnSHA2.dcu new file mode 100644 index 0000000000000000000000000000000000000000..b080c2a50656f8ebf30bc3076405071038294457 GIT binary patch literal 30907 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 +================================================================================ +* ƣ +* ԪƣSHA2 Ӵ㷨ʵֵԪ +* ԪߣCnPack (master@cnpack.org) +* / C Pascal ֲ䲿ֹܡ +* עԪʵ SHA2 ϵӴ㷨Ӧ HMAC 㷨 SHA224/256/384/512 +* עDelphi 5/6/7 Ԫз Int64 ޷ UInt64 SHA512/384 +* ԭǻڲ޷ļӼλԼƵȶͬΨһ +* ͬDZȽϣԪûƵıȽϡ +* ƽ̨PWinXP + Delphi 5.0 +* ݲԣPWinXP/7 + Delphi 5/6 +* õԪеַϱػʽ +* ޸ļ¼2022.04.26 V1.4 +* ޸ LongWord Integer ַת֧ MacOS64 +* 2019.04.15 V1.3 +* ֧ Win32/Win64/MacOS32 +* 2017.10.31 V1.2 +* SHA512/384 HMAC +* 2016.09.30 V1.1 +* ʵ SHA512/384D567з Int64 ޷ UInt64 +* 2016.09.27 V1.0 +* Ԫ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes {$IFDEF MSWINDOWS}, Windows {$ENDIF}, CnNative, CnConsts; + +type + PCnSHAGeneralDigest = ^TCnSHAGeneralDigest; + TCnSHAGeneralDigest = array[0..63] of Byte; + + PCnSHA224Digest = ^TCnSHA224Digest; + TCnSHA224Digest = array[0..27] of Byte; + {* SHA224 Ӵս28 ֽ} + + PCnSHA256Digest = ^TCnSHA256Digest; + TCnSHA256Digest = array[0..31] of Byte; + {* SHA256 Ӵս32 ֽ} + + PCnSHA384Digest = ^TCnSHA384Digest; + TCnSHA384Digest = array[0..47] of Byte; + {* SHA384 Ӵս48 ֽ} + + PCnSHA512Digest = ^TCnSHA512Digest; + TCnSHA512Digest = array[0..63] of Byte; + {* SHA512 Ӵս64 ֽ} + + TCnSHA256Context = packed record + {* SHA256 Ľṹ} + DataLen: Cardinal; + Data: array[0..63] of Byte; + BitLen: Int64; + State: array[0..7] of Cardinal; + Ipad: array[0..63] of Byte; {!< HMAC: inner padding } + Opad: array[0..63] of Byte; {!< HMAC: outer padding } + end; + + TCnSHA224Context = TCnSHA256Context; + {* SHA224 Ľṹ} + + TCnSHA512Context = packed record + {* SHA512 Ľṹ} + DataLen: Cardinal; + Data: array[0..127] of Byte; + TotalLen: Int64; + State: array[0..7] of Int64; + Ipad: array[0..127] of Byte; {!< HMAC: inner padding } + Opad: array[0..127] of Byte; {!< HMAC: outer padding } + end; + + TCnSHA384Context = TCnSHA512Context; + {* SHA512 Ľṹ} + + TCnSHACalcProgressFunc = procedure(ATotal, AProgress: Int64; var Cancel: + Boolean) of object; + {* SHA2 ϵӴսȻص¼} + +function SHA224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA224Digest; +{* ݿ SHA224 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA256Digest; +{* ݿ SHA256 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA384Digest; +{* ݿ SHA384 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA512Digest; +{* ݿ SHA512 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA224Buffer(const Buffer; Count: Cardinal): TCnSHA224Digest; +{* ݿ SHA224 㡣 + + + const Buffer - ݿַ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256Buffer(const Buffer; Count: Cardinal): TCnSHA256Digest; +{* ݿ SHA256 㡣 + + + const Buffer - ݿַ + Count: Cardinal - + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384Buffer(const Buffer; Count: Cardinal): TCnSHA384Digest; +{* ݿ SHA384 㡣 + + + const Buffer - ݿַ + Count: Cardinal - + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512Buffer(const Buffer; Count: Cardinal): TCnSHA512Digest; +{* ݿ SHA512 㡣 + + + const Buffer - ݿַ + Count: Cardinal - + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA224Bytes(Data: TBytes): TCnSHA224Digest; +{* ֽ SHA224 㡣 + + + Data: TBytes - ֽ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256Bytes(Data: TBytes): TCnSHA256Digest; +{* ֽ SHA256 㡣 + + + Data: TBytes - ֽ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384Bytes(Data: TBytes): TCnSHA384Digest; +{* ֽ SHA384 㡣 + + Data: TBytes - ֽ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512Bytes(Data: TBytes): TCnSHA512Digest; +{* ֽ SHA512 㡣 + + + Data: TBytes - ֽ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA224String(const Str: string): TCnSHA224Digest; +{* String ݽ SHA224 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256String(const Str: string): TCnSHA256Digest; +{* String ݽ SHA256 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384String(const Str: string): TCnSHA384Digest; +{* String ݽ SHA384 㣬ע D2009ϰ汾string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512String(const Str: string): TCnSHA512Digest; +{* String ݽ SHA512 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + + +function SHA224StringA(const Str: AnsiString): TCnSHA224Digest; +{* AnsiString ݽ SHA224 㡣 + + + const Str: AnsiString - + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA224StringW(const Str: WideString): TCnSHA224Digest; +{* WideString ݽ SHA224 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256StringA(const Str: AnsiString): TCnSHA256Digest; +{* AnsiString ݽ SHA256 㡣 + + + const Str: AnsiString - + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA256StringW(const Str: WideString): TCnSHA256Digest; +{* WideString ݽ SHA256 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384StringA(const Str: AnsiString): TCnSHA384Digest; +{* AnsiString ݽ SHA384 㡣 + + + const Str: AnsiString - + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA384StringW(const Str: WideString): TCnSHA384Digest; +{* WideString ݽ SHA384 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512StringA(const Str: AnsiString): TCnSHA512Digest; +{* AnsiString ݽ SHA512 㡣 + + + const Str: AnsiString - + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512StringW(const Str: WideString): TCnSHA512Digest; +{* WideString ݽ SHA512 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +{$IFDEF UNICODE} + +function SHA224UnicodeString(const Str: string): TCnSHA224Digest; +{* UnicodeString ݽֱӵ SHA224 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256UnicodeString(const Str: string): TCnSHA256Digest; +{* UnicodeString ݽֱӵ SHA256 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384UnicodeString(const Str: string): TCnSHA384Digest; +{* UnicodeString ݽֱӵ SHA384 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512UnicodeString(const Str: string): TCnSHA512Digest; +{* UnicodeString ݽֱӵ SHA512 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +{$ELSE} + +function SHA224UnicodeString(const Str: WideString): TCnSHA224Digest; +{* UnicodeString ݽֱӵ SHA224 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256UnicodeString(const Str: WideString): TCnSHA256Digest; +{* UnicodeString ݽֱӵ SHA256 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384UnicodeString(const Str: WideString): TCnSHA384Digest; +{* UnicodeString ݽֱӵ SHA384 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512UnicodeString(const Str: WideString): TCnSHA512Digest; +{* UnicodeString ݽֱӵ SHA512 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +{$ENDIF} + +function SHA224File(const FileName: string; CallBack: TCnSHACalcProgressFunc = + nil): TCnSHA224Digest; +{* ָļݽ SHA256 㡣 + + + const FileName: string - ļ + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA224Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA224Digest; +{* ָݽ SHA224 㡣 + + + Stream: TStream - + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256File(const FileName: string; CallBack: TCnSHACalcProgressFunc = + nil): TCnSHA256Digest; +{* ָļݽ SHA256 㡣 + + + const FileName: string - ļ + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA256Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA256Digest; +{* ָݽ SHA256 㡣 + + + Stream: TStream - + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384File(const FileName: string; CallBack: TCnSHACalcProgressFunc = + nil): TCnSHA384Digest; +{* ָļݽ SHA384 㡣 + + + const FileName: string - ļ + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA384Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA384Digest; +{* ָݽ SHA384 㡣 + + + Stream: TStream - + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512File(const FileName: string; CallBack: TCnSHACalcProgressFunc = + nil): TCnSHA512Digest; +{* ָļݽ SHA512 㡣 + + + const FileName: string - ļ + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA512Digest; +{* ָݽ SHA512 㡣 + + + Stream: TStream - + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +// ⲿݽɢ SHA224 㣬SHA224Update ɶα + +procedure SHA224Init(var Context: TCnSHA224Context); +{* ʼһ SHA224 ģ׼ SHA224 + + + var Context: TCnSHA224Context - ʼ SHA224 + + ֵޣ +} + +procedure SHA224Update(var Context: TCnSHA224Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA224 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA224Context - SHA224 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA224Final(var Context: TCnSHA224Context; var Digest: TCnSHA224Digest); +{* ּ㣬 SHA224 Digest С + + + var Context: TCnSHA224Context - SHA224 + var Digest: TCnSHA224Digest - ص SHA224 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA256 㣬SHA256Update ɶα + +procedure SHA256Init(var Context: TCnSHA256Context); +{* ʼһ SHA256 ģ׼ SHA256 + + + var Context: TCnSHA256Context - ʼ SHA256 + + ֵޣ +} + +procedure SHA256Update(var Context: TCnSHA256Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA256 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA256Context - SHA256 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA256Final(var Context: TCnSHA256Context; var Digest: TCnSHA256Digest); +{* ּ㣬 SHA256 Digest С + + + var Context: TCnSHA256Context - SHA256 + var Digest: TCnSHA256Digest - ص SHA256 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA384 㣬SHA384Update ɶα + +procedure SHA384Init(var Context: TCnSHA384Context); +{* ʼһ SHA384 ģ׼ SHA384 + + + var Context: TCnSHA384Context - ʼ SHA384 + + ֵޣ +} + +procedure SHA384Update(var Context: TCnSHA384Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA384 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA384Context - SHA384 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA384Final(var Context: TCnSHA384Context; var Digest: TCnSHA384Digest); +{* ּ㣬 SHA384 Digest С + + + var Context: TCnSHA384Context - SHA384 + var Digest: TCnSHA384Digest - ص SHA384 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA512 㣬SHA512Update ɶα + +procedure SHA512Init(var Context: TCnSHA512Context); +{* ʼһ SHA512 ģ׼ SHA512 + + + var Context: TCnSHA512Context - ʼ SHA512 + + ֵޣ +} + +procedure SHA512Update(var Context: TCnSHA512Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA512 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA512Context - SHA512 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA512Final(var Context: TCnSHA512Context; var Digest: TCnSHA512Digest); +{* ּ㣬 SHA512 Digest + + + var Context: TCnSHA512Context - SHA512 + var Digest: TCnSHA512Digest - ص SHA512 Ӵֵ + + ֵޣ +} + +function SHA224Print(const Digest: TCnSHA224Digest): string; +{* ʮƸʽ SHA224 Ӵֵ + + + const Digest: TCnSHA224Digest - ָ SHA224 Ӵֵ + + ֵstring - ʮַ +} + +function SHA256Print(const Digest: TCnSHA256Digest): string; +{* ʮƸʽ SHA256 Ӵֵ + + + const Digest: TCnSHA256Digest - ָ SHA256 Ӵֵ + + ֵstring - ʮַ +} + +function SHA384Print(const Digest: TCnSHA384Digest): string; +{* ʮƸʽ SHA384 Ӵֵ + + + const Digest: TCnSHA384Digest - ָ SHA384 Ӵֵ + + ֵstring - ʮַ +} + +function SHA512Print(const Digest: TCnSHA512Digest): string; +{* ʮƸʽ SHA512 Ӵֵ + + + const Digest: TCnSHA512Digest - ָ SHA512 Ӵֵ + + ֵstring - ʮַ +} + +function SHA224Match(const D1: TCnSHA224Digest; const D2: TCnSHA224Digest): Boolean; +{* Ƚ SHA224 ӴֵǷȡ + + + const D1: TCnSHA224Digest - Ƚϵ SHA224 Ӵֵһ + const D2: TCnSHA224Digest - Ƚϵ SHA224 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA256Match(const D1: TCnSHA256Digest; const D2: TCnSHA256Digest): Boolean; +{* Ƚ SHA256 ӴֵǷȡ + + + const D1: TCnSHA256Digest - Ƚϵ SHA256 Ӵֵһ + const D2: TCnSHA256Digest - Ƚϵ SHA256 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA384Match(const D1: TCnSHA384Digest; const D2: TCnSHA384Digest): Boolean; +{* Ƚ SHA384 ӴֵǷȡ + + + const D1: TCnSHA384Digest - Ƚϵ SHA384 Ӵֵһ + const D2: TCnSHA384Digest - Ƚϵ SHA384 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA512Match(const D1: TCnSHA512Digest; const D2: TCnSHA512Digest): Boolean; +{* Ƚ SHA512 ӴֵǷȡ + + + const D1: TCnSHA512Digest - Ƚϵ SHA512 Ӵֵһ + const D2: TCnSHA512Digest - Ƚϵ SHA512 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA224DigestToStr(const Digest: TCnSHA224Digest): string; +{* SHA224 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA224Digest - ת SHA224 Ӵֵ + + ֵstring - صַ +} + +function SHA256DigestToStr(const Digest: TCnSHA256Digest): string; +{* SHA256 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA256Digest - ת SHA256 Ӵֵ + + ֵstring - صַ +} + +function SHA384DigestToStr(const Digest: TCnSHA384Digest): string; +{* SHA384 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA384Digest - ת SHA384 Ӵֵ + + ֵstring - صַ +} + +function SHA512DigestToStr(const Digest: TCnSHA512Digest): string; +{* SHA512 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA512Digest - ת SHA512 Ӵֵ + + ֵstring - صַ +} + +procedure SHA224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA224Digest); +{* SHA224 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA224 Կݿַ + KeyByteLength: Integer - SHA224 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA224Digest - ص SHA224 Ӵֵ + + ֵޣ +} + +procedure SHA256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA256Digest); +{* SHA256 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA256 Կݿַ + KeyByteLength: Integer - SHA256 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA256Digest - ص SHA256 Ӵֵ + + ֵޣ +} + +procedure SHA384Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA384Digest); +{* SHA384 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA384 Կݿַ + KeyByteLength: Integer - SHA384 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA384Digest - ص SHA384 Ӵֵ + + ֵޣ +} + +procedure SHA512Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA512Digest); +{* SHA512 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA512 Կݿַ + KeyByteLength: Integer - SHA512 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA512Digest - ص SHA512 Ӵֵ + + ֵޣ +} + +implementation + +const + HMAC_SHA2_224_256_BLOCK_SIZE_BYTE = 64; + HMAC_SHA2_384_512_BLOCK_SIZE_BYTE = 128; + + HMAC_SHA2_224_OUTPUT_LENGTH_BYTE = 28; + HMAC_SHA2_256_OUTPUT_LENGTH_BYTE = 32; + HMAC_SHA2_384_OUTPUT_LENGTH_BYTE = 48; + HMAC_SHA2_512_OUTPUT_LENGTH_BYTE = 64; + +type + TSHA2Type = (stSHA2_224, stSHA2_256, stSHA2_384, stSHA2_512); + +const + MAX_FILE_SIZE = 512 * 1024 * 1024; + // If file size <= this size (bytes), using Mapping, else stream + + KEYS256: array[0..63] of Cardinal = ($428A2F98, $71374491, $B5C0FBCF, $E9B5DBA5, + $3956C25B, $59F111F1, $923F82A4, $AB1C5ED5, $D807AA98, $12835B01, $243185BE, + $550C7DC3, $72BE5D74, $80DEB1FE, $9BDC06A7, $C19BF174, $E49B69C1, $EFBE4786, + $0FC19DC6, $240CA1CC, $2DE92C6F, $4A7484AA, $5CB0A9DC, $76F988DA, $983E5152, + $A831C66D, $B00327C8, $BF597FC7, $C6E00BF3, $D5A79147, $06CA6351, $14292967, + $27B70A85, $2E1B2138, $4D2C6DFC, $53380D13, $650A7354, $766A0ABB, $81C2C92E, + $92722C85, $A2BFE8A1, $A81A664B, $C24B8B70, $C76C51A3, $D192E819, $D6990624, + $F40E3585, $106AA070, $19A4C116, $1E376C08, $2748774C, $34B0BCB5, $391C0CB3, + $4ED8AA4A, $5B9CCA4F, $682E6FF3, $748F82EE, $78A5636F, $84C87814, $8CC70208, + $90BEFFFA, $A4506CEB, $BEF9A3F7, $C67178F2); + + KEYS512: array[0..79] of TUInt64 = ($428A2F98D728AE22, $7137449123EF65CD, + $B5C0FBCFEC4D3B2F, $E9B5DBA58189DBBC, $3956C25BF348B538, $59F111F1B605D019, + $923F82A4AF194F9B, $AB1C5ED5DA6D8118, $D807AA98A3030242, $12835B0145706FBE, + $243185BE4EE4B28C, $550C7DC3D5FFB4E2, $72BE5D74F27B896F, $80DEB1FE3B1696B1, + $9BDC06A725C71235, $C19BF174CF692694, $E49B69C19EF14AD2, $EFBE4786384F25E3, + $0FC19DC68B8CD5B5, $240CA1CC77AC9C65, $2DE92C6F592B0275, $4A7484AA6EA6E483, + $5CB0A9DCBD41FBD4, $76F988DA831153B5, $983E5152EE66DFAB, $A831C66D2DB43210, + $B00327C898FB213F, $BF597FC7BEEF0EE4, $C6E00BF33DA88FC2, $D5A79147930AA725, + $06CA6351E003826F, $142929670A0E6E70, $27B70A8546D22FFC, $2E1B21385C26C926, + $4D2C6DFC5AC42AED, $53380D139D95B3DF, $650A73548BAF63DE, $766A0ABB3C77B2A8, + $81C2C92E47EDAEE6, $92722C851482353B, $A2BFE8A14CF10364, $A81A664BBC423001, + $C24B8B70D0F89791, $C76C51A30654BE30, $D192E819D6EF5218, $D69906245565A910, + $F40E35855771202A, $106AA07032BBD1B8, $19A4C116B8D2D0C8, $1E376C085141AB53, + $2748774CDF8EEB99, $34B0BCB5E19B48A8, $391C0CB3C5C95A63, $4ED8AA4AE3418ACB, + $5B9CCA4F7763E373, $682E6FF3D6B2B8A3, $748F82EE5DEFB2FC, $78A5636F43172F60, + $84C87814A1F0AB72, $8CC702081A6439EC, $90BEFFFA23631E28, $A4506CEBDE82BDE9, + $BEF9A3F7B2C67915, $C67178F2E372532B, $CA273ECEEA26619C, $D186B8C721C0C207, + $EADA7DD6CDE0EB1E, $F57D4F7FEE6ED178, $06F067AA72176FBA, $0A637DC5A2C898A6, + $113F9804BEF90DAE, $1B710B35131C471B, $28DB77F523047D84, $32CAAB7B40C72493, + $3C9EBE0A15C9BEBC, $431D67C49C100D4C, $4CC5D4BECB3E42B6, $597F299CFC657E2A, + $5FCB6FAB3AD6FAEC, $6C44198C4A475817); + +function ROTRight256(A, B: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (A shr B) or (A shl (32 - B)); +end; + +function ROTRight512(X: TUInt64; Y: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X shr Y) or (X shl (64 - Y)); +end; + +function SHR512(X: TUInt64; Y: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and $FFFFFFFFFFFFFFFF) shr Y; +end; + +function CH256(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Y) xor ((not X) and Z); +end; + +function CH512(X, Y, Z: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (((Y xor Z) and X) xor Z); +end; + +function MAJ256(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Y) xor (X and Z) xor (Y and Z); +end; + +function MAJ512(X, Y, Z: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ((X or Y) and Z) or (X and Y); +end; + +function EP0256(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight256(X, 2) xor ROTRight256(X, 13) xor ROTRight256(X, 22); +end; + +function EP1256(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight256(X, 6) xor ROTRight256(X, 11) xor ROTRight256(X, 25); +end; + +function SIG0256(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight256(X, 7) xor ROTRight256(X, 18) xor (X shr 3); +end; + +function SIG1256(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight256(X, 17) xor ROTRight256(X, 19) xor (X shr 10); +end; + +function SIG0512(X: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight512(X, 28) xor ROTRight512(X, 34) xor ROTRight512(X, 39); +end; + +function SIG1512(X: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight512(X, 14) xor ROTRight512(X, 18) xor ROTRight512(X, 41); +end; + +function Gamma0512(X: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight512(X, 1) xor ROTRight512(X, 8) xor SHR512(X, 7); +end; + +function Gamma1512(X: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight512(X, 19) xor ROTRight512(X, 61) xor SHR512(X, 6); +end; + +procedure SHA256Transform(var Context: TCnSHA256Context; Data: PAnsiChar); +var + A, B, C, D, E, F, G, H, T1, T2: Cardinal; + M: array[0..63] of Cardinal; + I, J: Integer; +begin + I := 0; + J := 0; + while I < 16 do + begin + M[I] := (Cardinal(Data[J]) shl 24) or (Cardinal(Data[J + 1]) shl 16) or (Cardinal(Data + [J + 2]) shl 8) or Cardinal(Data[J + 3]); + Inc(I); + Inc(J, 4); + end; + + while I < 64 do + begin + M[I] := SIG1256(M[I - 2]) + M[I - 7] + SIG0256(M[I - 15]) + M[I - 16]; + Inc(I); + end; + + A := Context.State[0]; + B := Context.State[1]; + C := Context.State[2]; + D := Context.State[3]; + E := Context.State[4]; + F := Context.State[5]; + G := Context.State[6]; + H := Context.State[7]; + + I := 0; + while I < 64 do + begin + T1 := H + EP1256(E) + CH256(E, F, G) + KEYS256[I] + M[I]; + T2 := EP0256(A) + MAJ256(A, B, C); + H := G; + G := F; + F := E; + E := D + T1; + D := C; + C := B; + B := A; + A := T1 + T2; + Inc(I); + end; + + Context.State[0] := Context.State[0] + A; + Context.State[1] := Context.State[1] + B; + Context.State[2] := Context.State[2] + C; + Context.State[3] := Context.State[3] + D; + Context.State[4] := Context.State[4] + E; + Context.State[5] := Context.State[5] + F; + Context.State[6] := Context.State[6] + G; + Context.State[7] := Context.State[7] + H; +end; + +{$WARNINGS OFF} + +procedure SHA512Transform(var Context: TCnSHA512Context; Data: PAnsiChar; BlockCount: Integer); +var + A, B, C, D, E, F, G, H, T1, T2: TUInt64; + M: array[0..79] of TUInt64; + I, J, K: Integer; + OrigData: PAnsiChar; +begin + OrigData := Data; + for K := 0 to BlockCount - 1 do + begin + Data := PAnsiChar(TCnNativeInt(OrigData) + (K shl 7)); + + I := 0; + J := 0; + while I < 16 do + begin + M[I] := (TUInt64(Data[J]) shl 56) or (TUInt64(Data[J + 1]) shl 48) or + (TUInt64(Data[J + 2]) shl 40) or (TUInt64(Data[J + 3]) shl 32) or + (TUInt64(Data[J + 4]) shl 24) or (TUInt64(Data[J + 5]) shl 16) or + (TUInt64(Data[J + 6]) shl 8) or TUInt64(Data[J + 7]); + Inc(I); + Inc(J, 8); + end; + + while I < 80 do + begin + M[I] := Gamma1512(M[I - 2]) + M[I - 7] + Gamma0512(M[I - 15]) + M[I - 16]; + Inc(I); + end; + + A := Context.State[0]; + B := Context.State[1]; + C := Context.State[2]; + D := Context.State[3]; + E := Context.State[4]; + F := Context.State[5]; + G := Context.State[6]; + H := Context.State[7]; + + I := 0; + while I < 80 do + begin + T1 := H + SIG1512(E) + CH512(E, F, G) + KEYS512[I] + M[I]; + T2 := SIG0512(A) + MAJ512(A, B, C); + H := G; + G := F; + F := E; + E := D + T1; + D := C; + C := B; + B := A; + A := T1 + T2; + Inc(I); + end; + + // з޷ WarningӰ + Context.State[0] := Context.State[0] + A; + Context.State[1] := Context.State[1] + B; + Context.State[2] := Context.State[2] + C; + Context.State[3] := Context.State[3] + D; + Context.State[4] := Context.State[4] + E; + Context.State[5] := Context.State[5] + F; + Context.State[6] := Context.State[6] + G; + Context.State[7] := Context.State[7] + H; + end; +end; + +{$WARNINGS ON} + +procedure SHA224Init(var Context: TCnSHA224Context); +begin + Context.DataLen := 0; + Context.BitLen := 0; + Context.State[0] := $C1059ED8; + Context.State[1] := $367CD507; + Context.State[2] := $3070DD17; + Context.State[3] := $F70E5939; + Context.State[4] := $FFC00B31; + Context.State[5] := $68581511; + Context.State[6] := $64F98FA7; + Context.State[7] := $BEFA4FA4; + FillChar(Context.Data, SizeOf(Context.Data), 0); +end; + +procedure SHA224Update(var Context: TCnSHA224Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA256Update(Context, Input, ByteLength); +end; + +procedure SHA256UpdateW(var Context: TCnSHA256Context; Input: PWideChar; CharLength: Cardinal); forward; + +procedure SHA224UpdateW(var Context: TCnSHA224Context; Input: PWideChar; CharLength: Cardinal); +begin + SHA256UpdateW(Context, Input, CharLength); +end; + +procedure SHA224Final(var Context: TCnSHA224Context; var Digest: TCnSHA224Digest); +var + Dig: TCnSHA256Digest; +begin + SHA256Final(Context, Dig); + Move(Dig[0], Digest[0], SizeOf(TCnSHA224Digest)); +end; + +procedure SHA256Init(var Context: TCnSHA256Context); +begin + Context.DataLen := 0; + Context.BitLen := 0; + Context.State[0] := $6A09E667; + Context.State[1] := $BB67AE85; + Context.State[2] := $3C6EF372; + Context.State[3] := $A54FF53A; + Context.State[4] := $510E527F; + Context.State[5] := $9B05688C; + Context.State[6] := $1F83D9AB; + Context.State[7] := $5BE0CD19; + FillChar(Context.Data, SizeOf(Context.Data), 0); +end; + +procedure SHA256Update(var Context: TCnSHA256Context; Input: PAnsiChar; ByteLength: Cardinal); +var + I: Integer; +begin + for I := 0 to ByteLength - 1 do + begin + Context.Data[Context.DataLen] := Byte(Input[I]); + Inc(Context.DataLen); + if Context.DataLen = 64 then + begin + SHA256Transform(Context, @Context.Data[0]); + Context.BitLen := Context.BitLen + 512; + Context.DataLen := 0; + end; + end; +end; + +procedure SHA256UpdateW(var Context: TCnSHA256Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + Content: PAnsiChar; + iLen: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(Content, CharLength * SizeOf(WideChar)); + try + iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(Content), CharLength * SizeOf(WideChar), nil, nil); + SHA256Update(Context, Content, iLen); + finally + FreeMem(Content); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + SHA256Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +procedure SHA256Final(var Context: TCnSHA256Context; var Digest: TCnSHA256Digest); +var + I: Integer; +begin + I := Context.DataLen; + Context.Data[I] := $80; + Inc(I); + + if Context.Datalen < 56 then + begin + while I < 56 do + begin + Context.Data[I] := 0; + Inc(I); + end; + end + else + begin + while I < 64 do + begin + Context.Data[I] := 0; + Inc(I); + end; + + SHA256Transform(Context, @(Context.Data[0])); + FillChar(Context.Data, 56, 0); + end; + + Context.BitLen := Context.BitLen + Context.DataLen * 8; + Context.Data[63] := Context.Bitlen; + Context.Data[62] := Context.Bitlen shr 8; + Context.Data[61] := Context.Bitlen shr 16; + Context.Data[60] := Context.Bitlen shr 24; + Context.Data[59] := Context.Bitlen shr 32; + Context.Data[58] := Context.Bitlen shr 40; + Context.Data[57] := Context.Bitlen shr 48; + Context.Data[56] := Context.Bitlen shr 56; + SHA256Transform(Context, @(Context.Data[0])); + + for I := 0 to 3 do + begin + Digest[I] := (Context.State[0] shr (24 - I * 8)) and $000000FF; + Digest[I + 4] := (Context.State[1] shr (24 - I * 8)) and $000000FF; + Digest[I + 8] := (Context.State[2] shr (24 - I * 8)) and $000000FF; + Digest[I + 12] := (Context.State[3] shr (24 - I * 8)) and $000000FF; + Digest[I + 16] := (Context.State[4] shr (24 - I * 8)) and $000000FF; + Digest[I + 20] := (Context.State[5] shr (24 - I * 8)) and $000000FF; + Digest[I + 24] := (Context.State[6] shr (24 - I * 8)) and $000000FF; + Digest[I + 28] := (Context.State[7] shr (24 - I * 8)) and $000000FF; + end; +end; + +{$WARNINGS OFF} + +procedure SHA384Init(var Context: TCnSHA384Context); +begin + Context.DataLen := 0; + Context.TotalLen := 0; + Context.State[0] := $CBBB9D5DC1059ED8; + Context.State[1] := $629A292A367CD507; + Context.State[2] := $9159015A3070DD17; + Context.State[3] := $152FECD8F70E5939; + Context.State[4] := $67332667FFC00B31; + Context.State[5] := $8EB44A8768581511; + Context.State[6] := $DB0C2E0D64F98FA7; + Context.State[7] := $47B5481DBEFA4FA4; + FillChar(Context.Data, SizeOf(Context.Data), 0); +end; + +{$WARNINGS ON} + +procedure SHA384Update(var Context: TCnSHA384Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA512Update(Context, Input, ByteLength); +end; + +procedure SHA512UpdateW(var Context: TCnSHA512Context; Input: PWideChar; CharLength: Cardinal); forward; + +procedure SHA384UpdateW(var Context: TCnSHA384Context; Input: PWideChar; CharLength: Cardinal); +begin + SHA512UpdateW(Context, Input, CharLength); +end; + +procedure SHA384Final(var Context: TCnSHA384Context; var Digest: TCnSHA384Digest); +var + Dig: TCnSHA512Digest; +begin + SHA512Final(Context, Dig); + Move(Dig[0], Digest[0], SizeOf(TCnSHA384Digest)); +end; + +{$WARNINGS OFF} + +procedure SHA512Init(var Context: TCnSHA512Context); +begin + Context.DataLen := 0; + Context.TotalLen := 0; + Context.State[0] := $6A09E667F3BCC908; + Context.State[1] := $BB67AE8584CAA73B; + Context.State[2] := $3C6EF372FE94F82B; + Context.State[3] := $A54FF53A5F1D36F1; + Context.State[4] := $510E527FADE682D1; + Context.State[5] := $9B05688C2B3E6C1F; + Context.State[6] := $1F83D9ABFB41BD6B; + Context.State[7] := $5BE0CD19137E2179; + FillChar(Context.Data, SizeOf(Context.Data), 0); +end; + +{$WARNINGS ON} + +procedure SHA512Update(var Context: TCnSHA512Context; Input: PAnsiChar; ByteLength: Cardinal); +var + TempLength, RemainLength, NewLength, BlockCount: Cardinal; +begin + TempLength := 128 - Context.DataLen; + if ByteLength < TempLength then + RemainLength := ByteLength + else + RemainLength := TempLength; + + Move(Input^, Context.Data[Context.DataLen], RemainLength); + if Context.DataLen + ByteLength < 128 then + begin + Inc(Context.DataLen, ByteLength); + Exit; + end; + + NewLength := Cardinal(ByteLength) - RemainLength; + BlockCount := NewLength div 128; + Input := PAnsiChar(TCnNativeUInt(Input) + RemainLength); + + SHA512Transform(Context, @Context.Data[0], 1); + SHA512Transform(Context, Input, BlockCount); + + RemainLength := NewLength mod 128; + Input := PAnsiChar(TCnNativeUInt(Input) + (BlockCount shl 7)); + Move(Input^, Context.Data[Context.DataLen], RemainLength); + + Context.DataLen := RemainLength; + Inc(Context.TotalLen, (BlockCount + 1) shl 7); +end; + +procedure SHA512UpdateW(var Context: TCnSHA512Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + Content: PAnsiChar; + iLen: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(Content, CharLength * SizeOf(WideChar)); + try + iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(Content), CharLength * SizeOf(WideChar), nil, nil); + SHA512Update(Context, Content, iLen); + finally + FreeMem(Content); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + SHA512Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +procedure SHA512Final(var Context: TCnSHA512Context; var Digest: TCnSHA512Digest); +var + I: Integer; + BlockCount, BitLength, PmLength: Cardinal; +begin + if (Context.DataLen mod 128) > 111 then + BlockCount := 2 + else + BlockCount := 1; + + BitLength := (Context.TotalLen + Context.DataLen) shl 3; + PmLength := BlockCount shl 7; + FillChar(Context.Data[Context.DataLen], PmLength - Context.DataLen, 0); + Context.Data[Context.DataLen] := $80; + + Context.Data[PmLength - 1] := Byte(BitLength); + Context.Data[PmLength - 2] := Byte(BitLength shr 8); + Context.Data[PmLength - 3] := Byte(BitLength shr 16); + Context.Data[PmLength - 4] := Byte(BitLength shr 24); + + SHA512Transform(Context, @(Context.Data[0]), BlockCount); + + for I := 0 to 7 do + begin + Digest[I] := (Context.State[0] shr (56 - I * 8)) and $000000FF; + Digest[I + 8] := (Context.State[1] shr (56 - I * 8)) and $000000FF; + Digest[I + 16] := (Context.State[2] shr (56 - I * 8)) and $000000FF; + Digest[I + 24] := (Context.State[3] shr (56 - I * 8)) and $000000FF; + Digest[I + 32] := (Context.State[4] shr (56 - I * 8)) and $000000FF; + Digest[I + 40] := (Context.State[5] shr (56 - I * 8)) and $000000FF; + Digest[I + 48] := (Context.State[6] shr (56 - I * 8)) and $000000FF; + Digest[I + 56] := (Context.State[7] shr (56 - I * 8)) and $000000FF; + end; +end; + +// ݿ SHA224 +function SHA224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224Update(Context, Input, ByteLength); + SHA224Final(Context, Result); +end; + +// ݿ SHA256 +function SHA256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256Update(Context, Input, ByteLength); + SHA256Final(Context, Result); +end; + +// ݿ SHA384 +function SHA384(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384Update(Context, Input, ByteLength); + SHA384Final(Context, Result); +end; + +// ݿ SHA512 +function SHA512(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512Update(Context, Input, ByteLength); + SHA512Final(Context, Result); +end; + +// ݿ SHA224 +function SHA224Buffer(const Buffer; Count: Cardinal): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224Update(Context, PAnsiChar(Buffer), Count); + SHA224Final(Context, Result); +end; + +// ݿ SHA256 +function SHA256Buffer(const Buffer; Count: Cardinal): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256Update(Context, PAnsiChar(Buffer), Count); + SHA256Final(Context, Result); +end; + +// ݿ SHA384 +function SHA384Buffer(const Buffer; Count: Cardinal): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384Update(Context, PAnsiChar(Buffer), Count); + SHA384Final(Context, Result); +end; + +// ݿ SHA512 +function SHA512Buffer(const Buffer; Count: Cardinal): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512Update(Context, PAnsiChar(Buffer), Count); + SHA512Final(Context, Result); +end; + +// ֽ SHA224 +function SHA224Bytes(Data: TBytes): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA224Final(Context, Result); +end; + +// ֽ SHA256 +function SHA256Bytes(Data: TBytes): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA256Final(Context, Result); +end; + +// ֽ SHA384 +function SHA384Bytes(Data: TBytes): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA384Final(Context, Result); +end; + +// ֽ SHA512 +function SHA512Bytes(Data: TBytes): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA512Final(Context, Result); +end; + +// String ݽ SHA224 +function SHA224String(const Str: string): TCnSHA224Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA224StringA(AStr); +end; + +// String ݽ SHA256 +function SHA256String(const Str: string): TCnSHA256Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA256StringA(AStr); +end; + +// String ݽ SHA384 +function SHA384String(const Str: string): TCnSHA384Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA384StringA(AStr); +end; + +// String ݽ SHA512 +function SHA512String(const Str: string): TCnSHA512Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA512StringA(AStr); +end; + +// UnicodeString ݽֱӵ SHA224 㣬ת +{$IFDEF UNICODE} +function SHA224UnicodeString(const Str: string): TCnSHA224Digest; +{$ELSE} +function SHA224UnicodeString(const Str: WideString): TCnSHA224Digest; +{$ENDIF} +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA224Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SHA256 㣬ת +{$IFDEF UNICODE} +function SHA256UnicodeString(const Str: string): TCnSHA256Digest; +{$ELSE} +function SHA256UnicodeString(const Str: WideString): TCnSHA256Digest; +{$ENDIF} +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA256Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SHA384 㣬ת +{$IFDEF UNICODE} +function SHA384UnicodeString(const Str: string): TCnSHA384Digest; +{$ELSE} +function SHA384UnicodeString(const Str: WideString): TCnSHA384Digest; +{$ENDIF} +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA384Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SHA512 㣬ת +{$IFDEF UNICODE} +function SHA512UnicodeString(const Str: string): TCnSHA512Digest; +{$ELSE} +function SHA512UnicodeString(const Str: WideString): TCnSHA512Digest; +{$ENDIF} +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA512Final(Context, Result); +end; + +// AnsiString ݽ SHA224 +function SHA224StringA(const Str: AnsiString): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224Update(Context, PAnsiChar(Str), Length(Str)); + SHA224Final(Context, Result); +end; + +// WideString ݽ SHA224 +function SHA224StringW(const Str: WideString): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224UpdateW(Context, PWideChar(Str), Length(Str)); + SHA224Final(Context, Result); +end; + +// AnsiString ݽ SHA256 +function SHA256StringA(const Str: AnsiString): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256Update(Context, PAnsiChar(Str), Length(Str)); + SHA256Final(Context, Result); +end; + +// WideString ݽ SHA256 +function SHA256StringW(const Str: WideString): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256UpdateW(Context, PWideChar(Str), Length(Str)); + SHA256Final(Context, Result); +end; + +// AnsiString ݽ SHA384 +function SHA384StringA(const Str: AnsiString): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384Update(Context, PAnsiChar(Str), Length(Str)); + SHA384Final(Context, Result); +end; + +// WideString ݽ SHA384 +function SHA384StringW(const Str: WideString): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384UpdateW(Context, PWideChar(Str), Length(Str)); + SHA384Final(Context, Result); +end; + +// AnsiString ݽ SHA512 +function SHA512StringA(const Str: AnsiString): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512Update(Context, PAnsiChar(Str), Length(Str)); + SHA512Final(Context, Result); +end; + +// WideString ݽ SHA512 +function SHA512StringW(const Str: WideString): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512UpdateW(Context, PWideChar(Str), Length(Str)); + SHA512Final(Context, Result); +end; + +function InternalSHAStream(Stream: TStream; const BufSize: Cardinal; var D: + TCnSHAGeneralDigest; SHA2Type: TSHA2Type; CallBack: TCnSHACalcProgressFunc = nil): Boolean; +var + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; + + Context224: TCnSHA224Context; + Context256: TCnSHA256Context; + Context384: TCnSHA384Context; + Context512: TCnSHA512Context; + Dig224: TCnSHA224Digest; + Dig256: TCnSHA256Digest; + Dig384: TCnSHA384Digest; + Dig512: TCnSHA512Digest; + + procedure _SHAInit; + begin + case SHA2Type of + stSHA2_224: + SHA224Init(Context224); + stSHA2_256: + SHA256Init(Context256); + stSHA2_384: + SHA384Init(Context384); + stSHA2_512: + SHA512Init(Context512); + end; + end; + + procedure _SHAUpdate; + begin + case SHA2Type of + stSHA2_224: + SHA224Update(Context224, Buf, ReadBytes); + stSHA2_256: + SHA256Update(Context256, Buf, ReadBytes); + stSHA2_384: + SHA384Update(Context384, Buf, ReadBytes); + stSHA2_512: + SHA512Update(Context512, Buf, ReadBytes); + end; + end; + + procedure _SHAFinal; + begin + case SHA2Type of + stSHA2_224: + SHA224Final(Context224, Dig224); + stSHA2_256: + SHA256Final(Context256, Dig256); + stSHA2_384: + SHA384Final(Context384, Dig384); + stSHA2_512: + SHA512Final(Context512, Dig512); + end; + end; + + procedure _CopyResult; + begin + case SHA2Type of + stSHA2_224: + Move(Dig224[0], D[0], SizeOf(TCnSHA224Digest)); + stSHA2_256: + Move(Dig256[0], D[0], SizeOf(TCnSHA256Digest)); + stSHA2_384: + Move(Dig384[0], D[0], SizeOf(TCnSHA384Digest)); + stSHA2_512: + Move(Dig512[0], D[0], SizeOf(TCnSHA512Digest)); + end; + end; + +begin + Result := False; + Size := Stream.Size; + SavePos := Stream.Position; + TotalBytes := 0; + if Size = 0 then + Exit; + if Size < BufSize then + BufLen := Size + else + BufLen := BufSize; + + CancelCalc := False; + _SHAInit; + + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + _SHAUpdate; + + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then + Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + _SHAFinal; + _CopyResult; + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +// ָ SHA224 +function SHA224Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA224Digest; +var + Dig: TCnSHAGeneralDigest; +begin + InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_224, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA224Digest)); +end; + +// ָ SHA256 +function SHA256Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA256Digest; +var + Dig: TCnSHAGeneralDigest; +begin + InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_256, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA256Digest)); +end; + +// ָ SHA384 +function SHA384Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA384Digest; +var + Dig: TCnSHAGeneralDigest; +begin + InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_384, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA384Digest)); +end; + +// ָ SHA512 +function SHA512Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA512Digest; +var + Dig: TCnSHAGeneralDigest; +begin + InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_512, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA512Digest)); +end; + +function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; +{$IFDEF MSWINDOWS} +var + H: THandle; + Info: BY_HANDLE_FILE_INFORMATION; + Rec: Int64Rec; +{$ENDIF} + begin +{$IFDEF MSWINDOWS} + Result := False; + IsEmpty := False; + H := CreateFile(PChar(AFileName), GENERIC_READ, FILE_SHARE_READ, nil, + OPEN_EXISTING, 0, 0); + if H = INVALID_HANDLE_VALUE then + Exit; + try + if not GetFileInformationByHandle(H, Info) then + Exit; + finally + CloseHandle(H); + end; + Rec.Lo := Info.nFileSizeLow; + Rec.Hi := Info.nFileSizeHigh; + Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); + IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); +{$ELSE} + Result := True; // Windows ƽ̨ Trueʾ Mapping +{$ENDIF} +end; + +function InternalSHAFile(const FileName: string; SHA2Type: TSHA2Type; + CallBack: TCnSHACalcProgressFunc): TCnSHAGeneralDigest; +var + Context224: TCnSHA224Context; + Context256: TCnSHA256Context; + Context384: TCnSHA384Context; + Context512: TCnSHA512Context; + Dig224: TCnSHA224Digest; + Dig256: TCnSHA256Digest; + Dig384: TCnSHA384Digest; + Dig512: TCnSHA512Digest; + +{$IFDEF MSWINDOWS} + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; + + procedure _SHAInit; + begin + case SHA2Type of + stSHA2_224: + SHA224Init(Context224); + stSHA2_256: + SHA256Init(Context256); + stSHA2_384: + SHA384Init(Context384); + stSHA2_512: + SHA512Init(Context512); + end; + end; + +{$IFDEF MSWINDOWS} + procedure _SHAUpdate; + begin + case SHA2Type of + stSHA2_224: + SHA224Update(Context224, ViewPointer, GetFileSize(FileHandle, nil)); + stSHA2_256: + SHA256Update(Context256, ViewPointer, GetFileSize(FileHandle, nil)); + stSHA2_384: + SHA384Update(Context384, ViewPointer, GetFileSize(FileHandle, nil)); + stSHA2_512: + SHA512Update(Context512, ViewPointer, GetFileSize(FileHandle, nil)); + end; + end; +{$ENDIF} + + procedure _SHAFinal; + begin + case SHA2Type of + stSHA2_224: + SHA224Final(Context224, Dig224); + stSHA2_256: + SHA256Final(Context256, Dig256); + stSHA2_384: + SHA384Final(Context384, Dig384); + stSHA2_512: + SHA512Final(Context512, Dig512); + end; + end; + + procedure _CopyResult(var D: TCnSHAGeneralDigest); + begin + case SHA2Type of + stSHA2_224: + Move(Dig224[0], D[0], SizeOf(TCnSHA224Digest)); + stSHA2_256: + Move(Dig256[0], D[0], SizeOf(TCnSHA256Digest)); + stSHA2_384: + Move(Dig384[0], D[0], SizeOf(TCnSHA384Digest)); + stSHA2_512: + Move(Dig512[0], D[0], SizeOf(TCnSHA512Digest)); + end; + end; + +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣ Windows ƽ̨ʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalSHAStream(Stream, 4096 * 1024, Result, SHA2Type, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + _SHAInit; + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + _SHAUpdate; + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise Exception.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise Exception.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + _SHAFinal; + _CopyResult(Result); +{$ENDIF} + end; +end; + +// ָļݽ SHA224 +function SHA224File(const FileName: string; CallBack: TCnSHACalcProgressFunc): + TCnSHA224Digest; +var + Dig: TCnSHAGeneralDigest; +begin + Dig := InternalSHAFile(FileName, stSHA2_224, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA224Digest)); +end; + +// ָļݽ SHA256 +function SHA256File(const FileName: string; CallBack: TCnSHACalcProgressFunc): + TCnSHA256Digest; +var + Dig: TCnSHAGeneralDigest; +begin + Dig := InternalSHAFile(FileName, stSHA2_256, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA256Digest)); +end; + +// ָļݽ SHA384 +function SHA384File(const FileName: string; CallBack: TCnSHACalcProgressFunc): + TCnSHA384Digest; +var + Dig: TCnSHAGeneralDigest; +begin + Dig := InternalSHAFile(FileName, stSHA2_384, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA384Digest)); +end; + +// ָļݽ SHA512 +function SHA512File(const FileName: string; CallBack: TCnSHACalcProgressFunc): + TCnSHA512Digest; +var + Dig: TCnSHAGeneralDigest; +begin + Dig := InternalSHAFile(FileName, stSHA2_512, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA512Digest)); +end; + +// ʮƸʽ SHA224 Ӵֵ +function SHA224Print(const Digest: TCnSHA224Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA224Digest)); +end; + +// ʮƸʽ SHA256 Ӵֵ +function SHA256Print(const Digest: TCnSHA256Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA256Digest)); +end; + +// ʮƸʽ SHA384 Ӵֵ +function SHA384Print(const Digest: TCnSHA384Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA384Digest)); +end; + +// ʮƸʽ SHA512 Ӵֵ +function SHA512Print(const Digest: TCnSHA512Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA512Digest)); +end; + +// Ƚ SHA224 ӴֵǷ +function SHA224Match(const D1, D2: TCnSHA224Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 28) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// Ƚ SHA256 ӴֵǷ +function SHA256Match(const D1, D2: TCnSHA256Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 32) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// Ƚ SHA384 ӴֵǷ +function SHA384Match(const D1, D2: TCnSHA384Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 48) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// Ƚ SHA512 ӴֵǷ +function SHA512Match(const D1, D2: TCnSHA512Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 64) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// SHA224 Ӵֵת string +function SHA224DigestToStr(const Digest: TCnSHA224Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA224Digest)); +end; + +// SHA256 Ӵֵת string +function SHA256DigestToStr(const Digest: TCnSHA256Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA256Digest)); +end; + +// SHA384 Ӵֵת string +function SHA384DigestToStr(const Digest: TCnSHA384Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA384Digest)); +end; + +// SHA512 Ӵֵת string +function SHA512DigestToStr(const Digest: TCnSHA512Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA512Digest)); +end; + +procedure SHA224HmacInit(var Context: TCnSHA224Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA224Digest; +begin + if KeyLength > HMAC_SHA2_224_256_BLOCK_SIZE_BYTE then + begin + Sum := SHA224Buffer(Key, KeyLength); + KeyLength := HMAC_SHA2_224_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA2_224_256_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA2_224_256_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA224Init(Context); + SHA224Update(Context, @(Context.Ipad[0]), HMAC_SHA2_224_256_BLOCK_SIZE_BYTE); +end; + +procedure SHA224HmacUpdate(var Context: TCnSHA224Context; Input: PAnsiChar; Length: + Cardinal); +begin + SHA224Update(Context, Input, Length); +end; + +procedure SHA224HmacFinal(var Context: TCnSHA224Context; var Output: TCnSHA224Digest); +var + Len: Integer; + TmpBuf: TCnSHA224Digest; +begin + Len := HMAC_SHA2_224_OUTPUT_LENGTH_BYTE; + SHA224Final(Context, TmpBuf); + SHA224Init(Context); + SHA224Update(Context, @(Context.Opad[0]), HMAC_SHA2_224_256_BLOCK_SIZE_BYTE); + SHA224Update(Context, @(TmpBuf[0]), Len); + SHA224Final(Context, Output); +end; + +procedure SHA256HmacInit(var Context: TCnSHA256Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA256Digest; +begin + if KeyLength > HMAC_SHA2_224_256_BLOCK_SIZE_BYTE then + begin + Sum := SHA256Buffer(Key, KeyLength); + KeyLength := HMAC_SHA2_256_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA2_224_256_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA2_224_256_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA256Init(Context); + SHA256Update(Context, @(Context.Ipad[0]), HMAC_SHA2_224_256_BLOCK_SIZE_BYTE); +end; + +procedure SHA256HmacUpdate(var Context: TCnSHA256Context; Input: PAnsiChar; Length: + Cardinal); +begin + SHA256Update(Context, Input, Length); +end; + +procedure SHA256HmacFinal(var Context: TCnSHA256Context; var Output: TCnSHA256Digest); +var + Len: Integer; + TmpBuf: TCnSHA256Digest; +begin + Len := HMAC_SHA2_256_OUTPUT_LENGTH_BYTE; + SHA256Final(Context, TmpBuf); + SHA256Init(Context); + SHA256Update(Context, @(Context.Opad[0]), HMAC_SHA2_224_256_BLOCK_SIZE_BYTE); + SHA256Update(Context, @(TmpBuf[0]), Len); + SHA256Final(Context, Output); +end; + +procedure SHA224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA224Digest); +var + Context: TCnSHA224Context; +begin + SHA224HmacInit(Context, Key, KeyByteLength); + SHA224HmacUpdate(Context, Input, ByteLength); + SHA224HmacFinal(Context, Output); +end; + +procedure SHA256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA256Digest); +var + Context: TCnSHA256Context; +begin + SHA256HmacInit(Context, Key, KeyByteLength); + SHA256HmacUpdate(Context, Input, ByteLength); + SHA256HmacFinal(Context, Output); +end; + +procedure SHA384HmacInit(var Context: TCnSHA384Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA384Digest; +begin + if KeyLength > HMAC_SHA2_384_512_BLOCK_SIZE_BYTE then + begin + Sum := SHA384Buffer(Key, KeyLength); + KeyLength := HMAC_SHA2_384_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA384Init(Context); + SHA384Update(Context, @(Context.Ipad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); +end; + +procedure SHA384HmacUpdate(var Context: TCnSHA384Context; Input: PAnsiChar; + Length: Cardinal); +begin + SHA384Update(Context, Input, Length); +end; + +procedure SHA384HmacFinal(var Context: TCnSHA384Context; var Output: TCnSHA384Digest); +var + Len: Integer; + TmpBuf: TCnSHA384Digest; +begin + Len := HMAC_SHA2_384_OUTPUT_LENGTH_BYTE; + SHA384Final(Context, TmpBuf); + SHA384Init(Context); + SHA384Update(Context, @(Context.Opad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); + SHA384Update(Context, @(TmpBuf[0]), Len); + SHA384Final(Context, Output); +end; + +procedure SHA384Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA384Digest); +var + Context: TCnSHA384Context; +begin + SHA384HmacInit(Context, Key, KeyByteLength); + SHA384HmacUpdate(Context, Input, ByteLength); + SHA384HmacFinal(Context, Output); +end; + +procedure SHA512HmacInit(var Context: TCnSHA512Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA512Digest; +begin + if KeyLength > HMAC_SHA2_384_512_BLOCK_SIZE_BYTE then + begin + Sum := SHA512Buffer(Key, KeyLength); + KeyLength := HMAC_SHA2_512_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA512Init(Context); + SHA512Update(Context, @(Context.Ipad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); +end; + +procedure SHA512HmacUpdate(var Context: TCnSHA512Context; Input: PAnsiChar; + Length: Cardinal); +begin + SHA512Update(Context, Input, Length); +end; + +procedure SHA512HmacFinal(var Context: TCnSHA512Context; var Output: TCnSHA512Digest); +var + Len: Integer; + TmpBuf: TCnSHA512Digest; +begin + Len := HMAC_SHA2_512_OUTPUT_LENGTH_BYTE; + SHA512Final(Context, TmpBuf); + SHA512Init(Context); + SHA512Update(Context, @(Context.Opad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); + SHA512Update(Context, @(TmpBuf[0]), Len); + SHA512Final(Context, Output); +end; + +procedure SHA512Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA512Digest); +var + Context: TCnSHA512Context; +begin + SHA512HmacInit(Context, Key, KeyByteLength); + SHA512HmacUpdate(Context, Input, ByteLength); + SHA512HmacFinal(Context, Output); +end; + +end. diff --git a/CnPack/Crypto/CnSHA3.dcu b/CnPack/Crypto/CnSHA3.dcu new file mode 100644 index 0000000000000000000000000000000000000000..ab48000027067f61ba76ba27ee6468164f3d3a11 GIT binary patch literal 31943 zcmeHw3w%`7)$g7&=S*gXBn%iRAoxuvL5PqK2%-2uCy#+dlMs>_UWyo#$q>u~^HA|K z8X9N`V=T1N3I#9p>R0jc>kSnPUhM@60*V%_w$N$|tyHYw7i!c{k=*~<`@H6nkSO}Q zzu)~v4||=p*Iuu^*4q2LpuoyTA9#SVZu}ViBwKb(Np5EP#Vfi${xP%Nu*{iVQ&d`Z zS6XFF*=J2lZ<7c?1Zm4k>pjg&Z)4@QlI8Ucfocp6I*Wbza|3ntm9;g0`0k>z3OQ?e zL*O4{Kawkyyqbn-Q~z?$3;(FFXP4HMSJsqPecHW3s));~t*r`_)=XdV(w!BKqRg85 z%IqbjbxrqmU0GqPZ>X!R2~Kz^{D zE8-wC5De69d82+uh0V`3Skf|~BWU+5uBvLRUsCtM9n1Cy+OVwv;)O&5c z-j^6m^yHS-lvf32k~6E8ll~QUUuIoh>GC@!-<_W52|7vw4f%nZV8arw)nHG~@*3W+ z|2)B9+()-R4hD3lF}SVr)~AB9_rA&oZmvDEzP>V86Da3rvahZ&@H{30n)~XO zt4l$Jl+^#0_atD?FDz76CAYL?Hdt856wKluLS z3Wrc0d0e%|Rv2`q>F2X=fA4<;iKVZWJpaI{Um0gV*gs`&(4~{6Wg{ON0-K+{^6$`9 zxJ&4jSd#lt(3xFZy$q5O+;NK^n^#tzs5&9Ls^*!Q z+RQ^*EvrmJQ(k*7X%oCcOH*HML1R@zB~3;9!Op8I;(Q_#-z!-9bj66Q1&ebt3v=?l zi)ZHHkG#T}vx^HdeR;DB58eB20_^5)Ay6W^KvwCIPrTIeiob&903=RfV`TD z+Pdme@>JGxq2t2A*X|7t$gZlb4+z99$CgbAx=bSH73cZ9+eyF>j?MJ>iu1DkKJVf} zG9>@mHRu}7yJqHR&RSgJo#Xcw`tmaK7nfvb7XEwP`-g&q3?mClmn}o0yz{pov;-51 zGG_^!W*6o!;4%`>KesY)@9YXv_;=q~^8H`}=UtFl#I4^+nha14qB{JK2a=x)4)oVl zn+HBNWseW8M7=AmZ}8UD)z-b{{>jF&a(i}7A?&{=Kq(ccW(=(Y74hncD46eG929iq zls1(5YI6hk-SFJVxS*4#8b5D%f8@Ggyc)0^ePHVHA;Cn%Zf)Iio(eGWz^<#T!31@b zi1%fWC9dX5WY^ZzH}EJLQj%T66$~@Hva-Sx9Ikamd5^lwGStO+C1ZjL%lGaGBlKoA)C=yksDNNJO2GB%f`IO`i|t4G#58JmxZH&7YV z1WM9T&|9En9R;NX%BG_D{0o#_M`4Zy%9-l$kwD+_Wt6V-QxXa?=Zhj*lDE(cqJ@kN zM2|aVV2KaqvS4wRf97JNFAjN-GJxw`JlkKGQ-UFgr%5STa9~G?FH=ODKu<}zQZsMy zY`?F_?^7d@N2Q>duF)V4d!q5EG;lzVGp@JNp|7E8)7U7@V}+1a;n(==^vV=PnB zD4N*Gq!3{NR^lr$$~=UYBUA(*eayl;-&PANdY}ZD+1UkK_u-*t_%70>qNPn(L&VQVFMI!m_98Ozvo zSF(jDlDgbB>}Ro~!O8R!Wt$xB(pXEo#Jb0cyz$kQ*3{ERf*2&kORSuYj#JADh7@{l+S6`JF|{Y$mV9cDxh+L#D~`A=KD5(!yQQpb083U}bX(FYm_;7CMFo-` zD;sC0m{GUJtW}N{m&_@sN`T4yPm^7uDAK|!E>M8Boldc&A%|^HdE*z-d8urillc0V zm19pzhMbpTaK?4&vPSZQvm=?W|0agQD%%OSHLv_W5^=0-94|J4=R9KiuikhL15dh; zG4m9Dtl=WT8C@!82WiW%Qi$(UlEq!lUdXV9JASlHn2s@?j>Oy1;3Wr~yr^rPF|Ds!XH2_HT4zktv|d|z ze#RxV&W)ut>P8>62Ib|^8jLipH~zTd%^rmF(I^ zzFOJ(?s1iS#x$LK)4WhSanJ1&_uhRjxWnf<_g_qZE{(Y7_lbM&UKiZqb)CEWhv&

NA(3P9!?JiueiT3|zuV96ev0!$^2X$c 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 IRjl;?0`Q@bKL7v# literal 0 HcmV?d00001 diff --git a/CnPack/Crypto/CnSHA3.pas b/CnPack/Crypto/CnSHA3.pas new file mode 100644 index 0000000..3e0ade0 --- /dev/null +++ b/CnPack/Crypto/CnSHA3.pas @@ -0,0 +1,2700 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2025 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnSHA3; +{* |

+================================================================================
+* ƣ
+* ԪƣSHA3 Ӵ㷨ʵֵԪ
+* ԪߣCnPack  (master@cnpack.org)
+*           / Keccak C  Pascal ֲ䲿ֹܡ
+*     עԪʵ SHA3 ϵӴ㷨Ӧ HMAC 㷨 SHA3-224/256/384/512
+*           ɱ䳤ժҪ SHAKE128/SHAKE256ȡ
+*           SHA3 淶 NIST.FIPS.202
+*           SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions
+*           жⶨ Bit  Byte ת
+*           ֮ Bit ܹ 8 ʱÿ 8  Bit λþһֽڣֽڼ˳򱣳ֲ䡣
+*
+* ƽ̨PWinXP + Delphi 5.0
+* ݲԣPWinXP/7 + Delphi 5/6
+*   õԪеַϱػʽ
+* ޸ļ¼2023.08.02 V1.4
+*                SHAKE128/SHAKE256 Ŀɱ䳤ժҪļ
+*           2022.04.26 V1.3
+*               ޸ LongWord  Integer ַת֧ MacOS64
+*           2019.12.12 V1.2
+*               ֧ TBytes
+*           2019.04.15 V1.1
+*               ֧ Win32/Win64/MacOS
+*           2017.11.10 V1.0
+*               Ԫ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes {$IFDEF MSWINDOWS}, Windows {$ENDIF}, CnNative, CnConsts; + +const + CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH = 32; + {* SHAKE128 ĬӴսֽڳ} + + CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH = 64; + {* SHAKE256 ĬӴսֽڳ} + +type + PCnSHA3GeneralDigest = ^TCnSHA3GeneralDigest; + TCnSHA3GeneralDigest = array[0..63] of Byte; + {* SHA3 ϵͨõӴս 64 ֽΪ׼} + + PCnSHA3_224Digest = ^TCnSHA3_224Digest; + TCnSHA3_224Digest = array[0..27] of Byte; + {* SHA3_224 Ӵս28 ֽ} + + PCnSHA3_256Digest = ^TCnSHA3_256Digest; + TCnSHA3_256Digest = array[0..31] of Byte; + {* SHA3_256 Ӵս32 ֽ} + + PCnSHA3_384Digest = ^TCnSHA3_384Digest; + TCnSHA3_384Digest = array[0..47] of Byte; + {* SHA3_384 Ӵս48 ֽ} + + PCnSHA3_512Digest = ^TCnSHA3_512Digest; + TCnSHA3_512Digest = array[0..63] of Byte; + {* SHA3_512 Ӵս64 ֽ} + + TCnSHA3Context = packed record + {* SHA3 ϵͨõĽṹ} + State: array[0..24] of Int64; + Index: Cardinal; + DigestLen: Cardinal; + Round: Cardinal; + BlockLen: Cardinal; + Block: array[0..255] of Byte; + Ipad: array[0..143] of Byte; {!< HMAC: inner padding } + Opad: array[0..143] of Byte; {!< HMAC: outer padding } + end; + + TCnSHA3CalcProgressFunc = procedure(ATotal, AProgress: Int64; var Cancel: + Boolean) of object; + {* SHA3 ϵͨõļȻص¼} + +function SHA3_224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_224Digest; +{* ݿ SHA3_224 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_256Digest; +{* ݿ SHA3_256 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_384Digest; +{* ݿ SHA3_384 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_512Digest; +{* ݿ SHA3_512 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHA3_224Buffer(const Buffer; Count: Cardinal): TCnSHA3_224Digest; +{* ݿ SHA3_224 㡣 + + + const Buffer - ݿַ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256Buffer(const Buffer; Count: Cardinal): TCnSHA3_256Digest; +{* ݿ SHA3_256 㡣 + + + const Buffer - ݿַ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384Buffer(const Buffer; Count: Cardinal): TCnSHA3_384Digest; +{* ݿ SHA3_384 㡣 + + + const Buffer - ݿַ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512Buffer(const Buffer; Count: Cardinal): TCnSHA3_512Digest; +{* ݿ SHA3_512 㡣 + + + const Buffer - ݿַ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128Buffer(const Buffer; Count: Cardinal; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* ݿӴճȿɱ SHAKE128 㣬سΪ DigestByteLength ֽΪӴս + + + const Buffer - ݿַ + Count: Cardinal - ݿֽڳ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256Buffer(const Buffer; Count: Cardinal; + DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* ݿӴճȿɱ SHAKE128 㣬سΪ DigestByteLength ֽΪӴս + + + const Buffer - ݿַ + Count: Cardinal - ݿֽڳ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +function SHA3_224Bytes(Data: TBytes): TCnSHA3_224Digest; +{* ֽ SHA3_224 㡣 + + + Data: TBytes - ֽ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256Bytes(Data: TBytes): TCnSHA3_256Digest; +{* ֽ SHA3_256 㡣 + + + Data: TBytes - ֽ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384Bytes(Data: TBytes): TCnSHA3_384Digest; +{* ֽ SHA3_384 㡣 + + + Data: TBytes - ֽ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512Bytes(Data: TBytes): TCnSHA3_512Digest; +{* ֽ SHA3_512 㡣 + + + Data: TBytes - ֽ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128Bytes(Data: TBytes; DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* ֽӴճȿɱ SHAKE128 㣬سΪ DigestByteLength ֽΪӴս + + + Data: TBytes - ֽ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256Bytes(Data: TBytes; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* ֽӴճȿɱ SHAKE256 㣬سΪ DigestByteLength ֽΪӴս + + + Data: TBytes - ֽ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +function SHA3_224String(const Str: string): TCnSHA3_224Digest; +{* String ݽ SHA3_224 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256String(const Str: string): TCnSHA3_256Digest; +{* String ݽ SHA3_256 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384String(const Str: string): TCnSHA3_384Digest; +{* String ݽ SHA3_384 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512String(const Str: string): TCnSHA3_512Digest; +{* String ݽ SHA3_512 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128String(const Str: string; DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* String ݽӴճȿɱ SHAKE128 㣬سΪ DigestByteLength ֽΪӴս + ע D2009 ϰ汾 string Ϊ UnicodeStringлὫǿת AnsiString м㡣 + + + const Str: string - ַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256String(const Str: string; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* String ݽӴճȿɱ SHAKE256 㣬سΪ DigestByteLength ֽΪӴս + ע D2009 ϰ汾 string Ϊ UnicodeStringлὫǿת AnsiString м㡣 + + + const Str: string - ַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +function SHA3_224StringA(const Str: AnsiString): TCnSHA3_224Digest; +{* AnsiString ݽ SHA3_224 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_224StringW(const Str: WideString): TCnSHA3_224Digest; +{* WideString ݽ SHA3_224 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256StringA(const Str: AnsiString): TCnSHA3_256Digest; +{* AnsiString ݽ SHA3_256 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_256StringW(const Str: WideString): TCnSHA3_256Digest; +{* WideStringݽ SHA3_256 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384StringA(const Str: AnsiString): TCnSHA3_384Digest; +{* AnsiString ݽ SHA3_384 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_384StringW(const Str: WideString): TCnSHA3_384Digest; +{* WideString ݽ SHA3_384 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512StringA(const Str: AnsiString): TCnSHA3_512Digest; +{* AnsiString ݽ SHA3_512 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHA3_512StringW(const Str: WideString): TCnSHA3_512Digest; +{* WideString ݽ SHA512 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128StringA(const Str: AnsiString; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* AnsiString ݽӴճȿɱֱ SHAKE128 㣬 + سΪ DigestByteLength ֽΪӴս + + + const Str: AnsiString - ַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE128StringW(const Str: WideString; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* WideString ݽӴճȿɱֱ SHAKE128 㣬 + سΪ DigestByteLength ֽΪӴս + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256StringA(const Str: AnsiString; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* AnsiString ݽӴճȿɱֱ SHAKE128 㣬 + سΪ DigestByteLength ֽΪӴս + + + const Str: AnsiString - ַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +function SHAKE256StringW(const Str: WideString; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* WideString ݽӴճȿɱֱ SHAKE256 㣬 + سΪ DigestByteLength ֽΪӴս + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +{$IFDEF UNICODE} + +function SHA3_224UnicodeString(const Str: string): TCnSHA3_224Digest; +{* UnicodeString ݽֱӵ SHA3_224 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256UnicodeString(const Str: string): TCnSHA3_256Digest; +{* UnicodeString ݽֱӵ SHA3_256 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384UnicodeString(const Str: string): TCnSHA3_384Digest; +{* UnicodeString ݽֱӵ SHA3_384 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512UnicodeString(const Str: string): TCnSHA3_512Digest; +{* UnicodeString ݽֱӵ SHA3_512 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128UnicodeString(const Str: string; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* UnicodeString ݽӴճȿɱֱ SHAKE128 㣬ֱӼڲ UTF16 ݣת + سΪ DigestByteLength ֽΪӴս + + + const Str: string - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256UnicodeString(const Str: string; + DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* UnicodeString ݽӴճȿɱֱ SHAKE256 㣬ֱӼڲ UTF16 ݣת + سΪ DigestByteLength ֽΪӴս + + + const Str: string - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +{$ELSE} + +function SHA3_224UnicodeString(const Str: WideString): TCnSHA3_224Digest; +{* UnicodeString ݽֱӵ SHA3_224 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256UnicodeString(const Str: WideString): TCnSHA3_256Digest; +{* UnicodeString ݽֱӵ SHA3_256 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384UnicodeString(const Str: WideString): TCnSHA3_384Digest; +{* UnicodeString ݽֱӵ SHA3_384 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512UnicodeString(const Str: WideString): TCnSHA3_512Digest; +{* UnicodeString ݽֱӵ SHA3_512 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128UnicodeString(const Str: WideString; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* UnicodeString ݽӴճȿɱֱ SHAKE128 㣬ֱӼڲ UTF16 ݣת + سΪ DigestByteLength ֽΪӴս + + + const Str: WideString - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256UnicodeString(const Str: WideString; + DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* UnicodeString ݽӴճȿɱֱ SHAKE256 㣬ֱӼڲ UTF16 ݣת + سΪ DigestByteLength ֽΪӴս + + + const Str: WideString - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +{$ENDIF} + +function SHA3_224File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc = + nil): TCnSHA3_224Digest; +{* ָļݽ SHA3_224 㡣 + + + const FileName: string - ļ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_224Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc = nil): + TCnSHA3_224Digest; +{* ָݽ SHA3_224 㡣 + + + Stream: TStream - + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc = + nil): TCnSHA3_256Digest; +{* ָļݽ SHA3_256 㡣 + + + const FileName: string - ļ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_256Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc = nil): + TCnSHA3_256Digest; +{* ָݽ SHA3_256 㡣 + + + Stream: TStream - + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc = + nil): TCnSHA3_384Digest; +{* ָļݽ SHA3_384 㡣 + + + const FileName: string - ļ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_384Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc = nil): + TCnSHA3_384Digest; +{* ָݽ SHA3_384 㡣 + + + Stream: TStream - + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc = + nil): TCnSHA3_512Digest; +{* ָļݽ SHA3_512 㡣 + + + const FileName: string - ļ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHA3_512Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc = nil): + TCnSHA3_512Digest; +{* ָݽ SHA3_512 㡣 + + + Stream: TStream - + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128File(const FileName: string; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH; + CallBack: TCnSHA3CalcProgressFunc = nil): TBytes; +{* ָļݽӴճȿɱ SHAKE128 㣬 + سΪ DigestByteLength ֽΪӴս + + + const FileName: string - ļ + DigestByteLength: Cardinal - Ӵսֽڳ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTBytes - SHAKE128Ӵֵ +} + +function SHAKE128Stream(Stream: TStream; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH; + CallBack: TCnSHA3CalcProgressFunc = nil): TBytes; +{* ָӴճȿɱ SHAKE128 㣬 + سΪ DigestByteLength ֽΪӴս + + + Stream: TStream - + DigestByteLength: Cardinal - Ӵսֽڳ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256File(const FileName: string; + DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH; + CallBack: TCnSHA3CalcProgressFunc = nil): TBytes; +{* ָļݽӴճȿɱ SHAKE256 㣬 + سΪ DigestByteLength ֽΪӴս + + + const FileName: string - ļ + DigestByteLength: Cardinal - Ӵսֽڳ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTBytes - SHAKE256 Ӵֵ +} + +function SHAKE256Stream(Stream: TStream; + DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH; + CallBack: TCnSHA3CalcProgressFunc = nil): TBytes; +{* ָӴճȿɱ SHAKE256 㣬 + سΪ DigestByteLength ֽΪӴս + + + Stream: TStream - + DigestByteLength: Cardinal - Ӵսֽڳ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTBytes - SHAKE256 Ӵֵ +} + +// ⲿݽɢ SHA3_224 㣬SHA3_224Update ɶα + +procedure SHA3_224Init(var Context: TCnSHA3Context); +{* ʼһ SHA3_224 ģ׼ SHA3_224 + + + var Context: TCnSHA3Context - ʼͨ SHA3 + + ֵޣ +} + +procedure SHA3_224Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA3_224 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA3_224Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_224Digest); +{* ּ㣬 SHA3_224 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + var Digest: TCnSHA3_224Digest - ص SHA3_224 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA3_256 㣬SHA3_256Update ɶα + +procedure SHA3_256Init(var Context: TCnSHA3Context); +{* ʼһ SHA3_256 ģ׼ SHA3_256 + + + var Context: TCnSHA3Context - ʼͨ SHA3 + + ֵޣ +} + +procedure SHA3_256Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA3_256 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA3_256Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_256Digest); +{* ּ㣬 SHA3_256 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + var Digest: TCnSHA3_256Digest - ص SHA3_256 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA3_384 㣬SHA3_384Update ɶα + +procedure SHA3_384Init(var Context: TCnSHA3Context); +{* ʼһ SHA3_384 ģ׼ SHA3_384 + + + var Context: TCnSHA3Context - ʼͨ SHA3 + + ֵޣ +} + +procedure SHA3_384Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA3_384 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA3_384Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_384Digest); +{* ּ㣬 SHA3_384 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + var Digest: TCnSHA3_384Digest - ص SHA3_384 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA3_512 㣬SHA3_512Update ɶα + +procedure SHA3_512Init(var Context: TCnSHA3Context); +{* ʼһ SHA3_512 ģ׼ SHA3_512 + + + var Context: TCnSHA3Context - ʼͨ SHA3 + + ֵޣ +} + +procedure SHA3_512Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA3_512 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA3_512Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_512Digest); +{* ּ㣬 SHA3_512 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + var Digest: TCnSHA3_512Digest - ص SHA3_512 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHAKE128 㣬SHAKE128Update ɶα + +procedure SHAKE128Init(var Context: TCnSHA3Context; DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH); +{* ʼһ SHAKE128 ģ׼ SHAKE128 + DigestByteLength ΪӴյֽڳȡ + + + var Context: TCnSHA3Context - ʼͨ SHA3 + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵޣ +} + +procedure SHAKE128Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHAKE128 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHAKE128Final(var Context: TCnSHA3Context; out Digest: TBytes); +{* ּ㣬 SHAKE128 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + out Digest: TBytes - ص SHAKE128 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHAKE128 㣬SHAKE128Update ɶα + +procedure SHAKE256Init(var Context: TCnSHA3Context; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH); +{* ʼһ SHAKE256 ģ׼ SHAKE256 + DigestByteLength ΪӴյֽڳȡ + + + var Context: TCnSHA3Context - ʼͨ SHA3 + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵޣ +} + +procedure SHAKE256Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHAKE256 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHAKE256Final(var Context: TCnSHA3Context; out Digest: TBytes); +{* ּ㣬 SHAKE256 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + out Digest: TBytes - ص SHAKE256 Ӵֵ + + ֵޣ +} + +function SHA3_224Print(const Digest: TCnSHA3_224Digest): string; +{* ʮƸʽ SHA3_224 Ӵֵ + + + const Digest: TCnSHA3_224Digest - ָ SHA3_224 Ӵֵ + + ֵstring - ʮַ +} + +function SHA3_256Print(const Digest: TCnSHA3_256Digest): string; +{* ʮƸʽ SHA3_256 Ӵֵ + + + const Digest: TCnSHA3_256Digest - ָ SHA3_256 Ӵֵ + + ֵstring - ʮַ +} + +function SHA3_384Print(const Digest: TCnSHA3_384Digest): string; +{* ʮƸʽ SHA3_384 Ӵֵ + + const Digest: TCnSHA3_384Digest - ָ SHA3_384 Ӵֵ + + ֵstring - ʮַ +} + +function SHA3_512Print(const Digest: TCnSHA3_512Digest): string; +{* ʮƸʽ SHA3_512 Ӵֵ + + + const Digest: TCnSHA3_512Digest - ָ SHA3_512 Ӵֵ + + ֵstring - ʮַ +} + +function SHAKE128Print(const Digest: TBytes): string; +{* ʮƸʽ SHAKE128 Ӵֵ + + + const Digest: TBytes - ָ SHAKE128 Ӵֵ + + ֵstring - ʮַ +} + +function SHAKE256Print(const Digest: TBytes): string; +{* ʮƸʽ SHAKE256 Ӵֵ + + + const Digest: TBytes - ָ SHAKE128 Ӵֵ + + ֵstring - ʮַ +} + +function SHA3_224Match(const D1: TCnSHA3_224Digest; const D2: TCnSHA3_224Digest): Boolean; +{* Ƚ SHA3_224 ӴֵǷȡ + + + const D1: TCnSHA3_224Digest - Ƚϵ SHA3_224 Ӵֵһ + const D2: TCnSHA3_224Digest - Ƚϵ SHA3_224 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA3_256Match(const D1: TCnSHA3_256Digest; const D2: TCnSHA3_256Digest): Boolean; +{* Ƚ SHA3_256 ӴֵǷȡ + + + const D1: TCnSHA3_256Digest - Ƚϵ SHA3_256 Ӵֵһ + const D2: TCnSHA3_256Digest - Ƚϵ SHA3_256 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA3_384Match(const D1: TCnSHA3_384Digest; const D2: TCnSHA3_384Digest): Boolean; +{* Ƚ SHA3_384 ӴֵǷȡ + + + const D1: TCnSHA3_384Digest - Ƚϵ SHA3_384 Ӵֵһ + const D2: TCnSHA3_384Digest - Ƚϵ SHA3_384 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA3_512Match(const D1: TCnSHA3_512Digest; const D2: TCnSHA3_512Digest): Boolean; +{* Ƚ SHA3_512 ӴֵǷȡ + + + const D1: TCnSHA3_512Digest - Ƚϵ SHA3_512 Ӵֵһ + const D2: TCnSHA3_512Digest - Ƚϵ SHA3_512 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHAKE128Match(const D1: TBytes; const D2: TBytes): Boolean; +{* Ƚ SHAKE128 ӴֵǷȡ + + + const D1: TBytes - Ƚϵ SHAKE128 Ӵֵһ + const D2: TBytes - Ƚϵ SHAKE128 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHAKE256Match(const D1: TBytes; const D2: TBytes): Boolean; +{* Ƚ SHAKE256 ӴֵǷȡ + + + const D1: TBytes - Ƚϵ SHAKE256 Ӵֵһ + const D2: TBytes - Ƚϵ SHAKE256 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA3_224DigestToStr(const Digest: TCnSHA3_224Digest): string; +{* SHA3_224 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA3_224Digest - ת SHA3_224 Ӵֵ + + ֵstring - صַ +} + +function SHA3_256DigestToStr(const Digest: TCnSHA3_256Digest): string; +{* SHA3_256 Ӵֱֵת stringÿֽڶӦһַ + |
+   Digest: TSHA3_256Digest   - Ҫ
+ |
+ + + const Digest: TCnSHA3_256Digest - ת SHA3_256 Ӵֵ + + ֵstring - صַ +} + +function SHA3_384DigestToStr(const Digest: TCnSHA3_384Digest): string; +{* SHA3_384 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA3_384Digest - ת SHA3_384 Ӵֵ + + ֵstring - صַ +} + +function SHA3_512DigestToStr(const Digest: TCnSHA3_512Digest): string; +{* SHA3_512 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA3_512Digest - ת SHA3_512 Ӵֵ + + ֵstring - صַ +} + +function SHAKE128DigestToStr(const Digest: TBytes): string; +{* SHAKE128 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TBytes - ת SHAKE128 Ӵֵ + + ֵstring - صַ +} + +function SHAKE256DigestToStr(const Digest: TBytes): string; +{* SHAKE256 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TBytes - ת SHAKE256 Ӵֵ + + ֵstring - صַ +} + +procedure SHA3_224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_224Digest); +{* SHA3_224 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA3_224 Կݿַ + KeyByteLength: Integer - SHA3_224 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA3_224Digest - ص SHA3_224 Ӵֵ + + ֵޣ +} + +procedure SHA3_256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_256Digest); +{* SHA3_256 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA3_256 Կݿַ + KeyByteLength: Integer - SHA3_256 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA3_256Digest - ص SHA3_256 Ӵֵ + + ֵޣ +} + +procedure SHA3_384Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_384Digest); +{* SHA3_384 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA3_384 Կݿַ + KeyByteLength: Integer - SHA3_384 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA3_384Digest - ص SHA3_384 Ӵֵ + + ֵޣ +} + +procedure SHA3_512Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_512Digest); +{* SHA3_512 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA3_512 Կݿַ + KeyByteLength: Integer - SHA3_512 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA3_512Digest - ص SHA3_512 Ӵֵ + + ֵޣ +} + +implementation + +type + TSHA3Type = (stSHA3_224, stSHA3_256, stSHA3_384, stSHA3_512, stSHAKE128, stSHAKE256); + +const + MAX_FILE_SIZE = 512 * 1024 * 1024; + STREAM_BUF_SIZE = 4096 * 1024; + // If file size <= this size (bytes), using Mapping, else stream + + SHA3_ROUNDS = 24; + SHA3_STATE_LEN = 25; + + SHA3_224_OUTPUT_LENGTH_BYTE = 28; + SHA3_256_OUTPUT_LENGTH_BYTE = 32; + SHA3_384_OUTPUT_LENGTH_BYTE = 48; + SHA3_512_OUTPUT_LENGTH_BYTE = 64; + + SHA3_224_BLOCK_SIZE_BYTE = 144; + SHA3_256_BLOCK_SIZE_BYTE = 136; + SHA3_384_BLOCK_SIZE_BYTE = 104; + SHA3_512_BLOCK_SIZE_BYTE = 72; + + SHAKE128_BLOCK_SIZE_BYTE = 168; + SHAKE256_BLOCK_SIZE_BYTE = 136; + + HMAC_SHA3_224_BLOCK_SIZE_BYTE = SHA3_224_BLOCK_SIZE_BYTE; + HMAC_SHA3_256_BLOCK_SIZE_BYTE = SHA3_256_BLOCK_SIZE_BYTE; + HMAC_SHA3_384_BLOCK_SIZE_BYTE = SHA3_384_BLOCK_SIZE_BYTE; + HMAC_SHA3_512_BLOCK_SIZE_BYTE = SHA3_512_BLOCK_SIZE_BYTE; + + HMAC_SHA3_224_OUTPUT_LENGTH_BYTE = SHA3_224_OUTPUT_LENGTH_BYTE; + HMAC_SHA3_256_OUTPUT_LENGTH_BYTE = SHA3_256_OUTPUT_LENGTH_BYTE; + HMAC_SHA3_384_OUTPUT_LENGTH_BYTE = SHA3_384_OUTPUT_LENGTH_BYTE; + HMAC_SHA3_512_OUTPUT_LENGTH_BYTE = SHA3_512_OUTPUT_LENGTH_BYTE; + + KECCAKF_ROUND_CONSTS: array[0..23] of TUInt64 = ( + $0000000000000001, $0000000000008082, $800000000000808A, + $8000000080008000, $000000000000808B, $0000000080000001, + $8000000080008081, $8000000000008009, $000000000000008A, + $0000000000000088, $0000000080008009, $000000008000000A, + $000000008000808B, $800000000000008B, $8000000000008089, + $8000000000008003, $8000000000008002, $8000000000000080, + $000000000000800A, $800000008000000A, $8000000080008081, + $8000000000008080, $0000000080000001, $8000000080008008 + ); + + KECCAKF_ROT_CONSTS: array[0..23] of Integer = ( + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 + ); + + KECCAKF_PILN: array[0..23] of Integer = ( + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 + ); + +function ROTL64(Q: TUInt64; N: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (Q shl N) xor (Q shr (64 - N)); +end; + +// һ SHA3 㣬 Block ݣ State +procedure SHA3_Transform(var Context: TCnSHA3Context); +type + PUInt64Array = ^TUInt64Array; + TUInt64Array = array[0..4095] of TUInt64; +var + I, J, R, L: Integer; + P: PUInt64Array; + T: TUInt64; + BC: array[0..4] of TUInt64; +begin + P := PUInt64Array(@(Context.Block[0])); + I := 0; + L := Integer(Context.BlockLen div 8); + while I < L do + begin + Context.State[I] := Context.State[I] xor P^[I]; + Inc(I); + end; + + for R := 0 to Context.Round - 1 do + begin + // Theta + for I := 0 to 4 do + begin + BC[I] := Context.State[I] xor Context.State[I + 5] xor Context.State[I + 10] + xor Context.State[I + 15] xor Context.State[I + 20]; + end; + for I := 0 to 4 do + begin + T := BC[(I + 4) mod 5] xor ROTL64(BC[(I + 1) mod 5], 1); + for J := 0 to 4 do + Context.State[5 * J + I] := Context.State[5 * J + I] xor T; + end; + + // Rho Pi + T := Context.State[1]; + for I := 0 to 23 do + begin + J := KECCAKF_PILN[I]; + BC[0] := Context.State[J]; + Context.State[J] := ROTL64(T, KECCAKF_ROT_CONSTS[I]); + T := BC[0]; + end; + + // Chi + for J := 0 to 4 do + begin + for I := 0 to 4 do + BC[I] := Context.State[5 * J + I]; + + for I := 0 to 4 do + Context.State[5 * J + I] := Context.State[5 * J + I] xor + ((not BC[(I + 1) mod 5]) and BC[(I + 2) mod 5]); + end; + + // Iota + Context.State[0] := Context.State[0] xor KECCAKF_ROUND_CONSTS[R]; + end; +end; + +procedure SHA3Init(var Context: TCnSHA3Context; SHA3Type: TSHA3Type; + DigestByteLength: Cardinal = 0); +begin + FillChar(Context.State, SizeOf(Context.State), 0); + FillChar(Context.Block, SizeOf(Context.Block), 0); + Context.Index := 0; + Context.Round := SHA3_ROUNDS; + + case SHA3Type of + stSHA3_224: + begin + Context.BlockLen := SHA3_224_BLOCK_SIZE_BYTE; + Context.DigestLen := SHA3_224_OUTPUT_LENGTH_BYTE; + end; + stSHA3_256: + begin + Context.BlockLen := SHA3_256_BLOCK_SIZE_BYTE; + Context.DigestLen := SHA3_256_OUTPUT_LENGTH_BYTE; + end; + stSHA3_384: + begin + Context.BlockLen := SHA3_384_BLOCK_SIZE_BYTE; + Context.DigestLen := SHA3_384_OUTPUT_LENGTH_BYTE; + end; + stSHA3_512: + begin + Context.BlockLen := SHA3_512_BLOCK_SIZE_BYTE; + Context.DigestLen := SHA3_512_OUTPUT_LENGTH_BYTE; + end; + stSHAKE128: + begin + Context.BlockLen := SHAKE128_BLOCK_SIZE_BYTE; + Context.DigestLen := DigestByteLength; + end; + stSHAKE256: + begin + Context.BlockLen := SHAKE256_BLOCK_SIZE_BYTE; + Context.DigestLen := DigestByteLength; + end; + end; +end; + +procedure SHA3Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +var + R, Idx: Cardinal; +begin + Idx := Context.Index; // Index Block еijʼλָ + repeat + if ByteLength < Context.BlockLen - Idx then + R := ByteLength //  + else + R := Context.BlockLen - Idx; // ܻʣ + + FillChar(Context.Block[Idx], SizeOf(Context.Block) - Idx, 0); // ȷβΪ 0 + Move(Input^, Context.Block[Idx], R); // Block ǰ벿ֲ + + if (Idx + R) < Context.BlockLen then // ûֲ + begin // ֻ Index λָ + Idx := Idx + R; + Break; + end; + + SHA3_Transform(Context); + Dec(ByteLength, R); + Idx := 0; + Inc(Input, R); + until False; + Context.Index := Idx; +end; + +procedure SHA3UpdateW(var Context: TCnSHA3Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + Content: PAnsiChar; + Len: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(Content, CharLength * SizeOf(WideChar)); + try + Len := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(Content), CharLength * SizeOf(WideChar), nil, nil); + SHA3Update(Context, Content, Len); + finally + FreeMem(Content); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + SHA3Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +// SHA3_224/256/384/512 ר +procedure SHA3Final(var Context: TCnSHA3Context; var Digest: TCnSHA3GeneralDigest); overload; +begin + Context.Block[Context.Index] := 6; + Context.Block[Context.BlockLen - 1] := Context.Block[Context.BlockLen - 1] or $80; + SHA3_Transform(Context); + Move(Context.State[0], Digest[0], Context.DigestLen); +end; + +// SHAKE128 SHAKE256 ר +procedure SHA3Final(var Context: TCnSHA3Context; out Digest: TBytes); overload; +var + Idx, DL: Cardinal; +begin + Context.Block[Context.Index] := $1F; + Context.Block[Context.BlockLen - 1] := Context.Block[Context.BlockLen - 1] or $80; + SHA3_Transform(Context); + + SetLength(Digest, Context.DigestLen); + if Context.DigestLen <= Context.BlockLen then + Move(Context.State[0], Digest[0], Context.DigestLen) + else + begin + DL := Context.DigestLen; + Idx := 0; + + while DL >= Context.BlockLen do + begin + Move(Context.State[0], Digest[Idx], Context.BlockLen); + Inc(Idx, Context.BlockLen); + Dec(DL, Context.BlockLen); + + if DL > 0 then + begin + FillChar(Context.Block[0], SizeOf(Context.Block), 0); + SHA3_Transform(Context); + end; + end; + + if DL > 0 then + Move(Context.State[0], Digest[Idx], DL); + end; +end; + +procedure SHA3_224Init(var Context: TCnSHA3Context); +begin + SHA3Init(Context, stSHA3_224); +end; + +procedure SHA3_224Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_224Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_224Digest); +var + Res: TCnSHA3GeneralDigest; +begin + SHA3Final(Context, Res); + Move(Res[0], Digest[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +procedure SHA3_256Init(var Context: TCnSHA3Context); +begin + SHA3Init(Context, stSHA3_256); +end; + +procedure SHA3_256Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_256Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_256Digest); +var + Res: TCnSHA3GeneralDigest; +begin + SHA3Final(Context, Res); + Move(Res[0], Digest[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +procedure SHA3_384Init(var Context: TCnSHA3Context); +begin + SHA3Init(Context, stSHA3_384); +end; + +procedure SHA3_384Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_384Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_384Digest); +var + Res: TCnSHA3GeneralDigest; +begin + SHA3Final(Context, Res); + Move(Res[0], Digest[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +procedure SHA3_512Init(var Context: TCnSHA3Context); +begin + SHA3Init(Context, stSHA3_512); +end; + +procedure SHA3_512Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_512Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_512Digest); +var + Res: TCnSHA3GeneralDigest; +begin + SHA3Final(Context, Res); + Move(Res[0], Digest[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +procedure SHAKE128Init(var Context: TCnSHA3Context; DigestByteLength: Cardinal); +begin + SHA3Init(Context, stSHAKE128, DigestByteLength); +end; + +procedure SHAKE128Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHAKE128Final(var Context: TCnSHA3Context; out Digest: TBytes); +begin + SHA3Final(Context, Digest); +end; + +procedure SHAKE256Init(var Context: TCnSHA3Context; DigestByteLength: Cardinal); +begin + SHA3Init(Context, stSHAKE256, DigestByteLength); +end; + +procedure SHAKE256Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHAKE256Final(var Context: TCnSHA3Context; out Digest: TBytes); +begin + SHA3Final(Context, Digest); +end; + +// ݿ SHA3_224λ +function SHA3_224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, Input, ByteLength); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_256λ +function SHA3_256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, Input, ByteLength); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_384λ +function SHA3_384(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, Input, ByteLength); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_512λ +function SHA3_512(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, Input, ByteLength); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_224 +function SHA3_224Buffer(const Buffer; Count: Cardinal): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, PAnsiChar(Buffer), Count); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_256 +function SHA3_256Buffer(const Buffer; Count: Cardinal): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, PAnsiChar(Buffer), Count); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_384 +function SHA3_384Buffer(const Buffer; Count: Cardinal): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, PAnsiChar(Buffer), Count); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_512 +function SHA3_512Buffer(const Buffer; Count: Cardinal): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, PAnsiChar(Buffer), Count); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHAKE128 +function SHAKE128Buffer(const Buffer; Count: Cardinal; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE128Init(Context, DigestByteLength); + SHAKE128Update(Context, PAnsiChar(Buffer), Count); + SHAKE128Final(Context, Result); +end; + +// ݿ SHAKE256 +function SHAKE256Buffer(const Buffer; Count: Cardinal; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE256Init(Context, DigestByteLength); + SHAKE256Update(Context, PAnsiChar(Buffer), Count); + SHAKE256Final(Context, Result); +end; + +// ֽ SHA3_224 +function SHA3_224Bytes(Data: TBytes): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// ֽ SHA3_256 +function SHA3_256Bytes(Data: TBytes): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// ֽ SHA3_384 +function SHA3_384Bytes(Data: TBytes): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// ֽ SHA3_512 +function SHA3_512Bytes(Data: TBytes): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// ֽ SHAKE128 +function SHAKE128Bytes(Data: TBytes; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE128Init(Context, DigestByteLength); + SHAKE128Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHAKE128Final(Context, Result); +end; + +// ֽ SHAKE256 +function SHAKE256Bytes(Data: TBytes; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE256Init(Context, DigestByteLength); + SHAKE256Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHAKE256Final(Context, Result); +end; + +// String ݽ SHA3_224 +function SHA3_224String(const Str: string): TCnSHA3_224Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA3_224StringA(AStr); +end; + +// String ݽ SHA3_256 +function SHA3_256String(const Str: string): TCnSHA3_256Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA3_256StringA(AStr); +end; + +// String ݽ SHA3_384 +function SHA3_384String(const Str: string): TCnSHA3_384Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA3_384StringA(AStr); +end; + +// String ݽ SHA3_512 +function SHA3_512String(const Str: string): TCnSHA3_512Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA3_512StringA(AStr); +end; + +// String ݽ SHAKE128 +function SHAKE128String(const Str: string; DigestByteLength: Cardinal): TBytes; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHAKE128StringA(AStr, DigestByteLength); +end; + +// String ݽ SHAKE256 +function SHAKE256String(const Str: string; DigestByteLength: Cardinal): TBytes; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHAKE256StringA(AStr, DigestByteLength); +end; + +// UnicodeString ݽֱӵ SHA3_224 㣬ת +{$IFDEF UNICODE} +function SHA3_224UnicodeString(const Str: string): TCnSHA3_224Digest; +{$ELSE} +function SHA3_224UnicodeString(const Str: WideString): TCnSHA3_224Digest; +{$ENDIF} +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// UnicodeString ݽֱӵ SHA3_256 㣬ת +{$IFDEF UNICODE} +function SHA3_256UnicodeString(const Str: string): TCnSHA3_256Digest; +{$ELSE} +function SHA3_256UnicodeString(const Str: WideString): TCnSHA3_256Digest; +{$ENDIF} +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// UnicodeString ݽֱӵ SHA3_384 㣬ת +{$IFDEF UNICODE} +function SHA3_384UnicodeString(const Str: string): TCnSHA3_384Digest; +{$ELSE} +function SHA3_384UnicodeString(const Str: WideString): TCnSHA3_384Digest; +{$ENDIF} +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// UnicodeString ݽֱӵ SHA3_512 㣬ת +{$IFDEF UNICODE} +function SHA3_512UnicodeString(const Str: string): TCnSHA3_512Digest; +{$ELSE} +function SHA3_512UnicodeString(const Str: WideString): TCnSHA3_512Digest; +{$ENDIF} +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// UnicodeString ݽֱӵ SHAKE128 㣬ת +{$IFDEF UNICODE} +function SHAKE128UnicodeString(const Str: string; DigestByteLength: Cardinal): TBytes; +{$ELSE} +function SHAKE128UnicodeString(const Str: WideString; DigestByteLength: Cardinal): TBytes; +{$ENDIF} +var + Context: TCnSHA3Context; +begin + SHAKE128Init(Context, DigestByteLength); + SHAKE128Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHAKE128Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SHAKE256 㣬ת +{$IFDEF UNICODE} +function SHAKE256UnicodeString(const Str: string; DigestByteLength: Cardinal): TBytes; +{$ELSE} +function SHAKE256UnicodeString(const Str: WideString; DigestByteLength: Cardinal): TBytes; +{$ENDIF} +var + Context: TCnSHA3Context; +begin + SHAKE256Init(Context, DigestByteLength); + SHAKE256Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHAKE256Final(Context, Result); +end; + +// AnsiString ݽSHA224 +function SHA3_224StringA(const Str: AnsiString): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, PAnsiChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// WideString ݽ SHA3_224 +function SHA3_224StringW(const Str: WideString): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// AnsiString ݽ SHA3_256 +function SHA3_256StringA(const Str: AnsiString): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, PAnsiChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// WideString ݽ SHA3_256 +function SHA3_256StringW(const Str: WideString): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// AnsiString ݽ SHA3_384 +function SHA3_384StringA(const Str: AnsiString): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, PAnsiChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// WideString ݽ SHA3_384 +function SHA3_384StringW(const Str: WideString): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// AnsiString ݽ SHA3_512 +function SHA3_512StringA(const Str: AnsiString): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, PAnsiChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// WideString ݽ SHA3_512 +function SHA3_512StringW(const Str: WideString): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// AnsiString ݽ SHAKE128 +function SHAKE128StringA(const Str: AnsiString; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE128Init(Context, DigestByteLength); + SHAKE128Update(Context, PAnsiChar(Str), Length(Str)); + SHAKE128Final(Context, Result); +end; + +// WideString ݽ SHAKE128 +function SHAKE128StringW(const Str: WideString; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE128Init(Context, DigestByteLength); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); // SHAKE128UpdateW = SHA3UpdateW + SHAKE128Final(Context, Result); +end; + +// AnsiString ݽ SHAKE256 +function SHAKE256StringA(const Str: AnsiString; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE256Init(Context, DigestByteLength); + SHAKE256Update(Context, PAnsiChar(Str), Length(Str)); + SHAKE256Final(Context, Result); +end; + +// WideString ݽ SHAKE256 +function SHAKE256StringW(const Str: WideString; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE256Init(Context, DigestByteLength); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); // SHAKE256UpdateW = SHA3UpdateW + SHAKE256Final(Context, Result); +end; + +// SHA3Type ֻ stSHA3_224, stSHA3_256, stSHA3_384, stSHA3_512 +function InternalSHA3Stream(Stream: TStream; const BufSize: Cardinal; var D: + TCnSHA3GeneralDigest; SHA3Type: TSHA3Type; CallBack: TCnSHA3CalcProgressFunc): Boolean; overload; +var + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; + Context: TCnSHA3Context; +begin + Result := False; + Size := Stream.Size; + SavePos := Stream.Position; + TotalBytes := 0; + if Size = 0 then + Exit; + if Size < BufSize then + BufLen := Size + else + BufLen := BufSize; + + CancelCalc := False; + SHA3Init(Context, SHA3Type); + + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + SHA3Update(Context, Buf, ReadBytes); + + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then + Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + SHA3Final(Context, D); + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +// SHA3Type ֻ stSHAKE128 stSHAKE256 +function InternalSHA3Stream(Stream: TStream; const BufSize: Cardinal; + SHA3Type: TSHA3Type; DigestByteLength: Cardinal; out D: TBytes; + CallBack: TCnSHA3CalcProgressFunc): Boolean; overload; +var + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; + Context: TCnSHA3Context; +begin + Result := False; + Size := Stream.Size; + SavePos := Stream.Position; + TotalBytes := 0; + if Size = 0 then + Exit; + if Size < BufSize then + BufLen := Size + else + BufLen := BufSize; + + CancelCalc := False; + SHA3Init(Context, SHA3Type, DigestByteLength); + + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + SHA3Update(Context, Buf, ReadBytes); + + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then + Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + SHA3Final(Context, D); + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +// ָ SHA3_224 +function SHA3_224Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_224Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Dig, stSHA3_224, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_224Digest)); +end; + +// ָ SHA3_256 +function SHA3_256Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_256Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Dig, stSHA3_256, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_256Digest)); +end; + +// ָ SHA3_384 +function SHA3_384Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_384Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Dig, stSHA3_384, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_384Digest)); +end; + +// ָ SHA3_512 +function SHA3_512Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_512Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Dig, stSHA3_512, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_512Digest)); +end; + +// ָӴճȿɱ SHAKE128 +function SHAKE128Stream(Stream: TStream; DigestByteLength: Cardinal; + CallBack: TCnSHA3CalcProgressFunc): TBytes; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, stSHAKE128, DigestByteLength, Result, CallBack); +end; + +// ָӴճȿɱ SHAKE256 +function SHAKE256Stream(Stream: TStream; DigestByteLength: Cardinal; + CallBack: TCnSHA3CalcProgressFunc): TBytes; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, stSHAKE256, DigestByteLength, Result, CallBack); +end; + +function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; +{$IFDEF MSWINDOWS} +var + H: THandle; + Info: BY_HANDLE_FILE_INFORMATION; + Rec: Int64Rec; +{$ENDIF} + begin +{$IFDEF MSWINDOWS} + Result := False; + IsEmpty := False; + H := CreateFile(PChar(AFileName), GENERIC_READ, FILE_SHARE_READ, nil, + OPEN_EXISTING, 0, 0); + if H = INVALID_HANDLE_VALUE then + Exit; + try + if not GetFileInformationByHandle(H, Info) then + Exit; + finally + CloseHandle(H); + end; + Rec.Lo := Info.nFileSizeLow; + Rec.Hi := Info.nFileSizeHigh; + Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); + IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); +{$ELSE} + Result := True; // Windows ƽ̨ Trueʾ Mapping +{$ENDIF} +end; + +function InternalSHA3File(const FileName: string; SHA3Type: TSHA3Type; + CallBack: TCnSHA3CalcProgressFunc): TCnSHA3GeneralDigest; overload; +var +{$IFDEF MSWINDOWS} + Context: TCnSHA3Context; + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Result, SHA3Type, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + SHA3Init(Context, SHA3Type); + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + SHA3Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise Exception.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise Exception.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + SHA3Final(Context, Result); +{$ENDIF} + end; +end; + +function InternalSHA3File(const FileName: string; SHA3Type: TSHA3Type; + DigestByteLength: Cardinal; CallBack: TCnSHA3CalcProgressFunc): TBytes; overload; +var +{$IFDEF MSWINDOWS} + Context: TCnSHA3Context; + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, SHA3Type, DigestByteLength, Result, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + SHA3Init(Context, SHA3Type, DigestByteLength); + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + SHA3Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise Exception.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise Exception.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + SHA3Final(Context, Result); +{$ENDIF} + end; +end; + +// ָļݽ SHA3_224 +function SHA3_224File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_224Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + Dig := InternalSHA3File(FileName, stSHA3_224, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_224Digest)); +end; + +// ָļݽ SHA3_256 +function SHA3_256File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_256Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + Dig := InternalSHA3File(FileName, stSHA3_256, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_256Digest)); +end; + +// ָļݽ SHA3_384 +function SHA3_384File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_384Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + Dig := InternalSHA3File(FileName, stSHA3_384, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_384Digest)); +end; + +// ָļݽ SHA3_512 +function SHA3_512File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_512Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + Dig := InternalSHA3File(FileName, stSHA3_512, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_512Digest)); +end; + +// ָļݽӴճȿɱ SHAKE128 +function SHAKE128File(const FileName: string; DigestByteLength: Cardinal; + CallBack: TCnSHA3CalcProgressFunc): TBytes; +begin + Result := InternalSHA3File(FileName, stSHAKE128, DigestByteLength, CallBack); +end; + +// ָļݽӴճȿɱ SHAKE256 +function SHAKE256File(const FileName: string; DigestByteLength: Cardinal; + CallBack: TCnSHA3CalcProgressFunc): TBytes; +begin + Result := InternalSHA3File(FileName, stSHAKE256, DigestByteLength, CallBack); +end; + +// ʮƸʽ SHA3_224 Ӵֵ +function SHA3_224Print(const Digest: TCnSHA3_224Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA3_224Digest)); +end; + +// ʮƸʽ SHA3_256 Ӵֵ +function SHA3_256Print(const Digest: TCnSHA3_256Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA3_256Digest)); +end; + +// ʮƸʽ SHA3_384 Ӵֵ +function SHA3_384Print(const Digest: TCnSHA3_384Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA3_384Digest)); +end; + +// ʮƸʽ SHA3_512 Ӵֵ +function SHA3_512Print(const Digest: TCnSHA3_512Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA3_512Digest)); +end; + +// ʮƸʽ SHAKE128 Ӵֵ +function SHAKE128Print(const Digest: TBytes): string; +begin + Result := BytesToHex(Digest); +end; + +// ʮƸʽ SHAKE256 Ӵֵ +function SHAKE256Print(const Digest: TBytes): string; +begin + Result := BytesToHex(Digest); +end; + +// Ƚ SHA3_224 ӴֵǷ +function SHA3_224Match(const D1, D2: TCnSHA3_224Digest): Boolean; +begin + Result := CompareMem(@D1[0], @D2[0], SizeOf(TCnSHA3_224Digest)); +end; + +// Ƚ SHA3_256 ӴֵǷ +function SHA3_256Match(const D1, D2: TCnSHA3_256Digest): Boolean; +begin + Result := CompareMem(@D1[0], @D2[0], SizeOf(TCnSHA3_256Digest)); +end; + +// Ƚ SHA3_384 ӴֵǷ +function SHA3_384Match(const D1, D2: TCnSHA3_384Digest): Boolean; +begin + Result := CompareMem(@D1[0], @D2[0], SizeOf(TCnSHA3_384Digest)); +end; + +// Ƚ SHA3_512 ӴֵǷ +function SHA3_512Match(const D1, D2: TCnSHA3_512Digest): Boolean; +begin + Result := CompareMem(@D1[0], @D2[0], SizeOf(TCnSHA3_512Digest));; +end; + +// Ƚ SHAKE128 ӴֵǷ +function SHAKE128Match(const D1, D2: TBytes): Boolean; +begin + Result := CompareBytes(D1, D2); +end; + +// Ƚ SHAKE256 ӴֵǷ +function SHAKE256Match(const D1, D2: TBytes): Boolean; +begin + Result := CompareBytes(D1, D2); +end; + +// SHA3_224 Ӵֵת string +function SHA3_224DigestToStr(const Digest: TCnSHA3_224Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA3_224Digest)); +end; + +// SHA3_256 Ӵֵת string +function SHA3_256DigestToStr(const Digest: TCnSHA3_256Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA3_256Digest));; +end; + +// SHA3_384 Ӵֵת string +function SHA3_384DigestToStr(const Digest: TCnSHA3_384Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA3_384Digest)); +end; + +// SHA3_512 Ӵֵת string +function SHA3_512DigestToStr(const Digest: TCnSHA3_512Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA3_512Digest)); +end; + +// SHAKE128 Ӵֵת string +function SHAKE128DigestToStr(const Digest: TBytes): string; +begin + Result := BytesToString(Digest); +end; + +// SHAKE256 Ӵֵת string +function SHAKE256DigestToStr(const Digest: TBytes): string; +begin + Result := BytesToString(Digest); +end; + +procedure SHA3_224HmacInit(var Context: TCnSHA3Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA3_224Digest; +begin + if KeyLength > HMAC_SHA3_224_BLOCK_SIZE_BYTE then + begin + Sum := SHA3_224Buffer(Key, KeyLength); + KeyLength := HMAC_SHA3_224_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA3_224_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA3_224_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, @(Context.Ipad[0]), HMAC_SHA3_224_BLOCK_SIZE_BYTE); +end; + +procedure SHA3_256HmacInit(var Context: TCnSHA3Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA3_256Digest; +begin + if KeyLength > HMAC_SHA3_256_BLOCK_SIZE_BYTE then + begin + Sum := SHA3_256Buffer(Key, KeyLength); + KeyLength := HMAC_SHA3_256_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA3_256_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA3_256_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, @(Context.Ipad[0]), HMAC_SHA3_256_BLOCK_SIZE_BYTE); +end; + +procedure SHA3_384HmacInit(var Context: TCnSHA3Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA3_384Digest; +begin + if KeyLength > HMAC_SHA3_384_BLOCK_SIZE_BYTE then + begin + Sum := SHA3_384Buffer(Key, KeyLength); + KeyLength := HMAC_SHA3_384_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA3_384_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA3_384_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, @(Context.Ipad[0]), HMAC_SHA3_384_BLOCK_SIZE_BYTE); +end; + +procedure SHA3_512HmacInit(var Context: TCnSHA3Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA3_512Digest; +begin + if KeyLength > HMAC_SHA3_512_BLOCK_SIZE_BYTE then + begin + Sum := SHA3_512Buffer(Key, KeyLength); + KeyLength := HMAC_SHA3_512_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA3_512_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA3_512_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, @(Context.Ipad[0]), HMAC_SHA3_512_BLOCK_SIZE_BYTE); +end; + +procedure SHA3_224HmacUpdate(var Context: TCnSHA3Context; Input: PAnsiChar; + ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_256HmacUpdate(var Context: TCnSHA3Context; Input: PAnsiChar; + ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_384HmacUpdate(var Context: TCnSHA3Context; Input: PAnsiChar; + ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_512HmacUpdate(var Context: TCnSHA3Context; Input: PAnsiChar; + ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_224HmacFinal(var Context: TCnSHA3Context; var Output: TCnSHA3GeneralDigest); +var + Len: Integer; + TmpBuf: TCnSHA3GeneralDigest; +begin + Len := HMAC_SHA3_224_OUTPUT_LENGTH_BYTE; + SHA3Final(Context, TmpBuf); + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, @(Context.Opad[0]), HMAC_SHA3_224_BLOCK_SIZE_BYTE); + SHA3Update(Context, @(TmpBuf[0]), Len); + SHA3Final(Context, Output); +end; + +procedure SHA3_256HmacFinal(var Context: TCnSHA3Context; var Output: TCnSHA3GeneralDigest); +var + Len: Integer; + TmpBuf: TCnSHA3GeneralDigest; +begin + Len := HMAC_SHA3_256_OUTPUT_LENGTH_BYTE; + SHA3Final(Context, TmpBuf); + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, @(Context.Opad[0]), HMAC_SHA3_256_BLOCK_SIZE_BYTE); + SHA3Update(Context, @(TmpBuf[0]), Len); + SHA3Final(Context, Output); +end; + +procedure SHA3_384HmacFinal(var Context: TCnSHA3Context; var Output: TCnSHA3GeneralDigest); +var + Len: Integer; + TmpBuf: TCnSHA3GeneralDigest; +begin + Len := HMAC_SHA3_384_OUTPUT_LENGTH_BYTE; + SHA3Final(Context, TmpBuf); + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, @(Context.Opad[0]), HMAC_SHA3_384_BLOCK_SIZE_BYTE); + SHA3Update(Context, @(TmpBuf[0]), Len); + SHA3Final(Context, Output); +end; + +procedure SHA3_512HmacFinal(var Context: TCnSHA3Context; var Output: TCnSHA3GeneralDigest); +var + Len: Integer; + TmpBuf: TCnSHA3GeneralDigest; +begin + Len := HMAC_SHA3_512_OUTPUT_LENGTH_BYTE; + SHA3Final(Context, TmpBuf); + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, @(Context.Opad[0]), HMAC_SHA3_512_BLOCK_SIZE_BYTE); + SHA3Update(Context, @(TmpBuf[0]), Len); + SHA3Final(Context, Output); +end; + +procedure SHA3_224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_224Digest); +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_224HmacInit(Context, Key, KeyByteLength); + SHA3_224HmacUpdate(Context, Input, ByteLength); + SHA3_224HmacFinal(Context, Dig); + Move(Dig[0], Output[0], Context.DigestLen); +end; + +procedure SHA3_256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_256Digest); +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_256HmacInit(Context, Key, KeyByteLength); + SHA3_256HmacUpdate(Context, Input, ByteLength); + SHA3_256HmacFinal(Context, Dig); + Move(Dig[0], Output[0], Context.DigestLen); +end; + +procedure SHA3_384Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_384Digest); +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_384HmacInit(Context, Key, KeyByteLength); + SHA3_384HmacUpdate(Context, Input, ByteLength); + SHA3_384HmacFinal(Context, Dig); + Move(Dig[0], Output[0], Context.DigestLen); +end; + +procedure SHA3_512Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_512Digest); +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_512HmacInit(Context, Key, KeyByteLength); + SHA3_512HmacUpdate(Context, Input, ByteLength); + SHA3_512HmacFinal(Context, Dig); + Move(Dig[0], Output[0], Context.DigestLen); +end; + +end. diff --git a/CnPack/Crypto/CnSM3.dcu b/CnPack/Crypto/CnSM3.dcu new file mode 100644 index 0000000000000000000000000000000000000000..5702308fecc90851e7e1705244d10cf62f426a3c GIT binary patch literal 14942 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 hoP3Lj*(N*248(j>HZvNH_!X!X +================================================================================ +* ƣ +* Ԫƣ SM3 Ӵ㷨ʵֵԪ +* ԪߣCnPack 飨master@cnpack.org) +* οֲ goldboar C +* עԪʵ˹ SM3 Ӵ㷨Ӧ HMAC 㷨 +* ο㷨ĵSM3 Cryptographic Hash Algorith +* http://www.oscca.gov.cn/UpFile/20101222141857786.pdf +* +* ƽ̨Windows 7 + Delphi 5.0 +* ݲԣPWin9X/2000/XP/7 + Delphi 5/6 +* õԪеַϱػʽ +* ޸ļ¼2019.12.12 V1.2 +* ֧ TBytes +* 2019.04.15 V1.1 +* ֧ Win32/Win64/MacOS +* 2014.09.23 V1.0 +* ֲԪ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + Classes, SysUtils, CnNative, CnConsts {$IFDEF MSWINDOWS}, Windows {$ENDIF}; + +type + PCnSM3Digest = ^TCnSM3Digest; + TCnSM3Digest = array[0..31] of Byte; + {* SM3 Ӵս32 ֽ} + + TCnSM3Context = packed record + {* SM3 Ľṹ} + Total: array[0..1] of Cardinal; {!< number of bytes processed } + State: array[0..7] of Cardinal; {!< intermediate digest state } + Buffer: array[0..63] of Byte; {!< data block being processed } + Ipad: array[0..63] of Byte; {!< HMAC: inner padding } + Opad: array[0..63] of Byte; {!< HMAC: outer padding } + end; + PCnSM3Context = ^TCnSM3Context; + + TCnSM3CalcProgressFunc = procedure (ATotal, AProgress: Int64; + var Cancel: Boolean) of object; + {* SM3 ӴսȻص¼} + +function SM3(Input: PAnsiChar; ByteLength: Cardinal): TCnSM3Digest; +{* ݿ SM3 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSM3Digest - ص SM3 Ӵֵ + + } + +function SM3Buffer(const Buffer; Count: Cardinal): TCnSM3Digest; +{* ݿ SM3 㡣 + + + const Buffer - ݿַ + Count: Cardinal - ݿֽڳ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3Bytes(Data: TBytes): TCnSM3Digest; +{* ֽ SM3 㡣 + + + Data: TBytes - ֽ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3String(const Str: string): TCnSM3Digest; +{* String ݽ SM3 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3StringA(const Str: AnsiString): TCnSM3Digest; +{* AnsiString ݽ SM3 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3StringW(const Str: WideString): TCnSM3Digest; +{* WideString ַת SM3 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +{$IFDEF UNICODE} + +function SM3UnicodeString(const Str: string): TCnSM3Digest; +{* UnicodeString ݽֱӵ SM3 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +{$ELSE} + +function SM3UnicodeString(const Str: WideString): TCnSM3Digest; +{* UnicodeString ݽֱӵ SM3 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +{$ENDIF} + +function SM3File(const FileName: string; CallBack: TCnSM3CalcProgressFunc = nil): TCnSM3Digest; +{* ָļݽ SM3 㡣 + + + const FileName: string - ļ + CallBack: TCnSM3CalcProgressFunc - ȻصĬΪ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3Stream(Stream: TStream; CallBack: TCnSM3CalcProgressFunc = nil): TCnSM3Digest; +{* ָݽ SM3 㡣 + + + Stream: TStream - + CallBack: TCnSM3CalcProgressFunc - ȻصĬΪ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +// ⲿݽɢ SM3 㣬SM3Update ɶα + +procedure SM3Init(var Context: TCnSM3Context); +{* ʼһ SM3 ģ׼ SM3 + + + var Context: TCnSM3Context - ʼ SM3 + + ֵޣ +} + +procedure SM3Update(var Context: TCnSM3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SM3 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSM3Context - SM3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SM3Final(var Context: TCnSM3Context; var Digest: TCnSM3Digest); +{* ּ㣬 SM3 Digest + + + var Context: TCnSM3Context - SM3 + var Digest: TCnSM3Digest - ص SM3 Ӵֵ + + ֵޣ +} + +function SM3Print(const Digest: TCnSM3Digest): string; +{* ʮƸʽ SM3 Ӵֵ + + + const Digest: TCnSM3Digest - ָ SM3 Ӵֵ + + ֵstring - ʮַ +} + +function SM3Match(const D1: TCnSM3Digest; const D2: TCnSM3Digest): Boolean; +{* Ƚ SM3 ӴֵǷȡ + + + const D1: TCnSM3Digest - Ƚϵ SM3 Ӵֵһ + const D2: TCnSM3Digest - Ƚϵ SM3 Ӵֵ + + ֵBoolean - Ƿ +} + +function SM3DigestToStr(const Digest: TCnSM3Digest): string; +{* SM3 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSM3Digest - ת SM3 Ӵֵ + + ֵstring - صַ +} + +procedure SM3Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSM3Digest); +{* SM3 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SM3 Կݿַ + KeyByteLength: Integer - SM3 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSM3Digest - ص SM3 Ӵֵ + + ֵޣ +} + +implementation + +const + SM3Padding: array[0..63] of Byte = + ( + $80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ); + + SM3_T: array[0..63] of Cardinal = ( + $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, + $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A + ); + + MAX_FILE_SIZE = 512 * 1024 * 1024; + // If file size <= this size (bytes), using Mapping, else stream + + HMAC_SM3_BLOCK_SIZE_BYTE = 64; + HMAC_SM3_OUTPUT_LENGTH_BYTE = 32; + +type + TSM3ProcessData = array[0..63] of Byte; + +procedure GetULongBe(var N: Cardinal; B: PAnsiChar; I: Integer); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +var + D: Cardinal; +begin + D := (Cardinal(B[I]) shl 24) or (Cardinal(B[I + 1]) shl 16) or + (Cardinal(B[I + 2]) shl 8) or (Cardinal(B[I + 3])); + N := D; +end; + +procedure PutULongBe(N: Cardinal; B: PAnsiChar; I: Integer); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + B[I] := AnsiChar(N shr 24); + B[I + 1] := AnsiChar(N shr 16); + B[I + 2] := AnsiChar(N shr 8); + B[I + 3] := AnsiChar(N); +end; + +function FF0(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor Y xor Z; +end; + +function FF1(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Y) or (Y and Z) or (X and Z); +end; + +function GG0(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor Y xor Z; +end; + +function GG1(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Y) or ((not X) and Z); +end; + +function SM3Shl(X: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and $FFFFFFFF) shl N; +end; + +// ѭơע N Ϊ 0 32 ʱֵΪ XN Ϊ 33 ʱֵ N Ϊ 1 ʱķֵ +function ROTL(X: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := SM3Shl(X, N) or (X shr (32 - N)); +end; + +function P0(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor ROTL(X, 9) xor ROTL(X, 17); +end; + +function P1(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor ROTL(X, 15) xor ROTL(X, 23); +end; + +procedure SM3Init(var Context: TCnSM3Context); +begin + Context.Total[0] := 0; + Context.Total[1] := 0; + + Context.State[0] := $7380166F; + Context.State[1] := $4914B2B9; + Context.State[2] := $172442D7; + Context.State[3] := $DA8A0600; + Context.State[4] := $A96F30BC; + Context.State[5] := $163138AA; + Context.State[6] := $E38DEE4D; + Context.State[7] := $B0FB0E4E; + + FillChar(Context.Buffer, SizeOf(Context.Buffer), 0); +end; + +// һδ 64 ֽҲ 512 λݿ +procedure SM3Process(var Context: TCnSM3Context; Data: PAnsiChar); +var + SS1, SS2, TT1, TT2: Cardinal; + W: array[0..67] of Cardinal; + W1: array[0..63] of Cardinal; + A, B, C, D, E, F, G, H: Cardinal; + Temp1, Temp2: Cardinal; + J: Integer; +begin + GetULongBe(W[ 0], Data, 0); + GetULongBe(W[ 1], Data, 4); + GetULongBe(W[ 2], Data, 8); + GetULongBe(W[ 3], Data, 12); + GetULongBe(W[ 4], Data, 16); + GetULongBe(W[ 5], Data, 20); + GetULongBe(W[ 6], Data, 24); + GetULongBe(W[ 7], Data, 28); + GetULongBe(W[ 8], Data, 32); + GetULongBe(W[ 9], Data, 36); + GetULongBe(W[10], Data, 40); + GetULongBe(W[11], Data, 44); + GetULongBe(W[12], Data, 48); + GetULongBe(W[13], Data, 52); + GetULongBe(W[14], Data, 56); + GetULongBe(W[15], Data, 60); + + for J := 16 to 67 do + begin + Temp1 := W[J - 16] xor W[J - 9]; + Temp2 := ROTL(W[J - 3], 15); + W[J] := P1(Temp1 xor Temp2) xor (ROTL(W[J - 13], 7) xor W[J - 6]); + end; + + for J := 0 to 63 do + W1[J] := W[J] xor W[J + 4]; + + // ѾW/W1ֵ + + A := Context.State[0]; + B := Context.State[1]; + C := Context.State[2]; + D := Context.State[3]; + E := Context.State[4]; + F := Context.State[5]; + G := Context.State[6]; + H := Context.State[7]; + + for J := 0 to 15 do + begin + SS1 := ROTL((ROTL(A, 12) + E + ROTL(SM3_T[J], J)), 7); + SS2 := SS1 xor ROTL(A, 12); + TT1 := FF0(A, B, C) + D + SS2 + W1[J]; + TT2 := GG0(E, F, G) + H + SS1 + W[J]; + D := C; + C := ROTL(B, 9); + B := A; + A := TT1; + H := G; + G := ROTL(F, 19); + F := E; + E := P0(TT2); + end; + + for J := 16 to 63 do + begin + SS1 := ROTL((ROTL(A, 12) + E + ROTL(SM3_T[J], J)), 7); + SS2 := SS1 xor ROTL(A, 12); + TT1 := FF1(A, B, C) + D + SS2 + W1[J]; + TT2 := GG1(E, F, G) + H + SS1 + W[J]; + D := C; + C := ROTL(B,9); + B := A; + A := TT1; + H := G; + G := ROTL(F,19); + F := E; + E := P0(TT2); + end; + + Context.State[0] := Context.State[0] xor A; + Context.State[1] := Context.State[1] xor B; + Context.State[2] := Context.State[2] xor C; + Context.State[3] := Context.State[3] xor D; + Context.State[4] := Context.State[4] xor E; + Context.State[5] := Context.State[5] xor F; + Context.State[6] := Context.State[6] xor G; + Context.State[7] := Context.State[7] xor H; + + // +end; + +procedure SM3UpdateW(var Context: TCnSM3Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + pContent: PAnsiChar; + iLen: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(pContent, CharLength * SizeOf(WideChar)); + try + iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(pContent), CharLength * SizeOf(WideChar), nil, nil); + SM3Update(Context, pContent, iLen); + finally + FreeMem(pContent); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + SM3Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +procedure SM3Update(var Context: TCnSM3Context; Input: PAnsiChar; ByteLength: Cardinal); +var + Fill, Left: Cardinal; +begin + if (Input = nil) or (ByteLength <= 0) then + Exit; + + Left := Context.Total[0] and $3F; + Fill := 64 - Left; + + Context.Total[0] := Context.Total[0] + ByteLength; + Context.Total[0] := Context.Total[0] and $FFFFFFFF; + + if Context.Total[0] < ByteLength then + Context.Total[1] := Context.Total[1] + 1; + + if (Left <> 0) and (ByteLength >= Fill) then + begin + Move(Input^, Context.Buffer[Left], Fill); + SM3Process(Context, @(Context.Buffer[0])); + Input := Input + Fill; + ByteLength := ByteLength - Fill; + Left := 0; + end; + + while ByteLength >= 64 do + begin + SM3Process(Context, Input); + Input := Input + 64; + ByteLength := ByteLength - 64; + end; + + if ByteLength > 0 then + Move(Input^, Context.Buffer[Left], ByteLength); +end; + +procedure SM3Final(var Context: TCnSM3Context; var Digest: TCnSM3Digest); +var + Last, Padn: Cardinal; + High, Low: Cardinal; + MsgLen: array[0..7] of Byte; +begin + High := (Context.Total[0] shr 29) or (Context.Total[1] shl 3); + Low := Context.Total[0] shl 3; + + PutULongBe(High, @(MsgLen[0]), 0); + PutULongBe(Low, @(MsgLen[0]), 4); + + Last := Context.Total[0] and $3F; + if Last < 56 then + Padn := 56 - Last + else + Padn := 120 - Last; + + SM3Update(Context, @(SM3Padding[0]), Padn); + SM3Update(Context, @(MsgLen[0]), 8); + + PutULongBe(Context.State[0], @Digest, 0); + PutULongBe(Context.State[1], @Digest, 4); + PutULongBe(Context.State[2], @Digest, 8); + PutULongBe(Context.State[3], @Digest, 12); + PutULongBe(Context.State[4], @Digest, 16); + PutULongBe(Context.State[5], @Digest, 20); + PutULongBe(Context.State[6], @Digest, 24); + PutULongBe(Context.State[7], @Digest, 28); +end; + +function SM3(Input: PAnsiChar; ByteLength: Cardinal): TCnSM3Digest; +var + Ctx: TCnSM3Context; +begin + SM3Init(Ctx); + SM3Update(Ctx, Input, ByteLength); + SM3Final(Ctx, Result); +end; + +procedure SM3HmacStarts(var Ctx: TCnSM3Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSM3Digest; +begin + if KeyLength > HMAC_SM3_BLOCK_SIZE_BYTE then + begin + Sum := SM3(Key, KeyLength); + KeyLength := HMAC_SM3_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Ctx.Ipad, HMAC_SM3_BLOCK_SIZE_BYTE, $36); + FillChar(Ctx.Opad, HMAC_SM3_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Ctx.Ipad[I] := Byte(Ctx.Ipad[I] xor Byte(Key[I])); + Ctx.Opad[I] := Byte(Ctx.Opad[I] xor Byte(Key[I])); + end; + + SM3Init(Ctx); + SM3Update(Ctx, @(Ctx.Ipad[0]), HMAC_SM3_BLOCK_SIZE_BYTE); +end; + +procedure SM3HmacUpdate(var Ctx: TCnSM3Context; Input: PAnsiChar; Length: Cardinal); +begin + SM3Update(Ctx, Input, Length); +end; + +procedure SM3HmacFinish(var Ctx: TCnSM3Context; var Output: TCnSM3Digest); +var + Len: Integer; + TmpBuf: TCnSM3Digest; +begin + Len := HMAC_SM3_OUTPUT_LENGTH_BYTE; + SM3Final(Ctx, TmpBuf); + SM3Init(Ctx); + SM3Update(Ctx, @(Ctx.Opad[0]), HMAC_SM3_BLOCK_SIZE_BYTE); + SM3Update(Ctx, @(TmpBuf[0]), Len); + SM3Final(Ctx, Output); +end; + +procedure SM3Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSM3Digest); +var + Ctx: TCnSM3Context; +begin + SM3HmacStarts(Ctx, Key, KeyByteLength); + SM3HmacUpdate(Ctx, Input, ByteLength); + SM3HmacFinish(Ctx, Output); +end; + +function SM3Buffer(const Buffer; Count: Cardinal): TCnSM3Digest; +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3Update(Context, PAnsiChar(Buffer), Count); + SM3Final(Context, Result); +end; + +function SM3Bytes(Data: TBytes): TCnSM3Digest; +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SM3Final(Context, Result); +end; + +// String ݽ SM3 ת +function SM3String(const Str: string): TCnSM3Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SM3StringA(AStr); +end; + +// AnsiString ݽ SM3 ת +function SM3StringA(const Str: AnsiString): TCnSM3Digest; +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3Update(Context, PAnsiChar(Str), Length(Str)); + SM3Final(Context, Result); +end; + +// WideString ݽ SM3 ת +function SM3StringW(const Str: WideString): TCnSM3Digest; +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3UpdateW(Context, PWideChar(Str), Length(Str)); + SM3Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SM3 㣬ת +{$IFDEF UNICODE} +function SM3UnicodeString(const Str: string): TCnSM3Digest; +{$ELSE} +function SM3UnicodeString(const Str: WideString): TCnSM3Digest; +{$ENDIF} +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SM3Final(Context, Result); +end; + +function InternalSM3Stream(Stream: TStream; const BufSize: Cardinal; var D: + TCnSM3Digest; CallBack: TCnSM3CalcProgressFunc = nil): Boolean; +var + Context: TCnSM3Context; + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; +begin + Result := False; + Size := Stream.Size; + SavePos := Stream.Position; + TotalBytes := 0; + if Size = 0 then Exit; + if Size < BufSize then BufLen := Size + else BufLen := BufSize; + + CancelCalc := False; + SM3Init(Context); + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + SM3Update(Context, Buf, ReadBytes); + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + SM3Final(Context, D); + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +// ָļݽSM3ת +function SM3File(const FileName: string; + CallBack: TCnSM3CalcProgressFunc): TCnSM3Digest; +var +{$IFDEF MSWINDOWS} + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; + Context: TCnSM3Context; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; + + function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; +{$IFDEF MSWINDOWS} + var + H: THandle; + Info: BY_HANDLE_FILE_INFORMATION; + Rec : Int64Rec; +{$ENDIF} + begin +{$IFDEF MSWINDOWS} + Result := False; + IsEmpty := False; + H := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); + if H = INVALID_HANDLE_VALUE then Exit; + try + if not GetFileInformationByHandle(H, Info) then Exit; + finally + CloseHandle(H); + end; + Rec.Lo := Info.nFileSizeLow; + Rec.Hi := Info.nFileSizeHigh; + Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); + IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); +{$ELSE} + Result := True; // Windows ƽ̨ Trueʾ Mapping +{$ENDIF} + end; + +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣ Windows ƽ̨ʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalSM3Stream(Stream, 4096 * 1024, Result, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + SM3Init(Context); + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + SM3Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise Exception.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise Exception.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + SM3Final(Context, Result); +{$ENDIF} + end; +end; + +// ָ SM3 +function SM3Stream(Stream: TStream; + CallBack: TCnSM3CalcProgressFunc = nil): TCnSM3Digest; +begin + InternalSM3Stream(Stream, 4096 * 1024, Result, CallBack); +end; + +function SM3Print(const Digest: TCnSM3Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSM3Digest)); +end; + +function SM3Match(const D1, D2: TCnSM3Digest): Boolean; +begin + Result := CompareMem(@D1[0], @D2[0], SizeOf(TCnSM3Digest)); +end; + +function SM3DigestToStr(const Digest: TCnSM3Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSM3Digest)); +end; + +end. From ffbdb4e7ae8c02c483cf13f5d9070f2ca04c0047 Mon Sep 17 00:00:00 2001 From: freitasjca Date: Thu, 23 Apr 2026 16:07:23 +0100 Subject: [PATCH 05/15] chore: fix browsingpath, remove Demos and DelphiToFPC paths --- boss.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/boss.json b/boss.json index 3afba61..82a6aaf 100644 --- a/boss.json +++ b/boss.json @@ -1,11 +1,11 @@ -{ - "name": "delphi-cross-socket", - "description": "Delphi cross-platform async socket library (IOCP/epoll/kqueue) with HTTP server and OpenSSL 3.x support. Fork of winddriver/Delphi-Cross-Socket — adds Boss package manifest only. Zero source changes.", - "version": "1.0.0", - "homepage": "https://github.com/freitasjca/Delphi-Cross-Socket", - "license": "MIT", - "mainsrc": "Net/", - "browsingpath": "Net/;Utils/", - "projects": [], - "dependencies": {} +{ + "name": "delphi-cross-socket", + "description": "Delphi cross-platform async socket library (IOCP/epoll/kqueue) with HTTP server and OpenSSL 3.x support. Fork of winddriver/Delphi-Cross-Socket — adds Boss package manifest only. Zero source changes.", + "version": "1.0.1", + "homepage": "https://github.com/freitasjca/Delphi-Cross-Socket", + "license": "MIT", + "mainsrc": "Net/", + "browsingpath": "Net/;Utils/;CnPack/Common/;CnPack/Crypto/", + "projects": [], + "dependencies": {} } \ No newline at end of file From f27b01ee6d82a1b459ef2c486010b90cd3d70c22 Mon Sep 17 00:00:00 2001 From: freitasjca Date: Fri, 29 May 2026 11:44:38 +0100 Subject: [PATCH 06/15] feat(ssl): add mTLS server API (SetCACertificate / SetVerifyPeer) --- Net/Net.CrossSslSocket.Base.pas | 41 +++++++++++++ Net/Net.CrossSslSocket.OpenSSL.pas | 97 ++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) diff --git a/Net/Net.CrossSslSocket.Base.pas b/Net/Net.CrossSslSocket.Base.pas index 040a520..8bb369f 100644 --- a/Net/Net.CrossSslSocket.Base.pas +++ b/Net/Net.CrossSslSocket.Base.pas @@ -186,6 +186,30 @@ TCrossSslSocketBase = class(TCrossSocket, ICrossSslSocket) procedure SetPrivateKey(const APKeyStr: string); overload; virtual; procedure SetPrivateKeyFile(const APKeyFile: string); virtual; + { ── MTLS-1: CA certificate loading for client-certificate verification ── + Loads a CA certificate that the server will use to verify presented + client certificates during the TLS handshake (mutual TLS). Mirrors + the SetCertificate overload family above so consumers have the same + file/string/bytes/buffer surface they're already used to. + + Concrete implementation in TCrossOpenSslSocket calls + SSL_CTX_add_client_CA + X509_STORE_add_cert to register the cert in + both the CertificateRequest CA list (sent to clients during the + handshake) and the trust store used to verify the presented chain. } + procedure SetCACertificate(const ACACertBuf: Pointer; const ACACertBufSize: Integer); overload; virtual; abstract; + procedure SetCACertificate(const ACACertBytes: TBytes); overload; virtual; + procedure SetCACertificate(const ACACertStr: string); overload; virtual; + procedure SetCACertificateFile(const ACACertFile: string); virtual; + + { ── MTLS-2: enable / disable peer (client) certificate verification ── + When AVerify=True the server sets SSL_VERIFY_PEER | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT — the handshake fails if the client + does not present a certificate signed by one of the CAs registered + above. When False, reverts to SSL_VERIFY_NONE (the default). + Must be called AFTER SetCACertificate so the trust store is + populated before verify mode is enabled. } + procedure SetVerifyPeer(const AVerify: Boolean); virtual; abstract; + property Ssl: Boolean read GetSsl; property SslMaxPendingWriteBytes: Int64 read GetSslMaxPendingWriteBytes write SetSslMaxPendingWriteBytes; @@ -262,6 +286,23 @@ procedure TCrossSslSocketBase.SetPrivateKeyFile(const APKeyFile: string); SetPrivateKey(TFileUtils.ReadAllBytes(APKeyFile)); end; +{ ── MTLS-1: SetCACertificate overload chain (file → string → bytes → buffer) ── } + +procedure TCrossSslSocketBase.SetCACertificate(const ACACertBytes: TBytes); +begin + SetCACertificate(Pointer(ACACertBytes), Length(ACACertBytes)); +end; + +procedure TCrossSslSocketBase.SetCACertificate(const ACACertStr: string); +begin + SetCACertificate(TEncoding.ANSI.GetBytes(ACACertStr)); +end; + +procedure TCrossSslSocketBase.SetCACertificateFile(const ACACertFile: string); +begin + SetCACertificate(TFileUtils.ReadAllBytes(ACACertFile)); +end; + { TCrossSslConnectionBase } function TCrossSslConnectionBase.GetSsl: Boolean; diff --git a/Net/Net.CrossSslSocket.OpenSSL.pas b/Net/Net.CrossSslSocket.OpenSSL.pas index 5f357c6..9ded76a 100644 --- a/Net/Net.CrossSslSocket.OpenSSL.pas +++ b/Net/Net.CrossSslSocket.OpenSSL.pas @@ -19,6 +19,26 @@ 传输层安全协议: https://zh.wikipedia.org/wiki/%E5%82%B3%E8%BC%B8%E5%B1%A4%E5%AE%89%E5%85%A8%E5%8D%94%E8%AD%B0 + + ── mTLS additions ─────────────────────────────────────────────────────────── + [MTLS-1] SetCACertificate(Pointer, Integer) override added. + Loads a CA certificate from a memory buffer and registers it with + the SSL context for client-certificate verification (mTLS server + mode). Uses BIO_new_mem_buf + PEM_read_bio_X509 to parse the PEM + data, then calls SSL_CTX_add_client_CA (populates the CA list sent + to clients in the CertificateRequest handshake message) and + X509_STORE_add_cert (adds the cert to the trust store used to + verify the presented certificate chain). + Companion overloads (TBytes / string / file) inherited from the + base class (Net.CrossSslSocket.Base) mirror the SetCertificate + overload family. + + [MTLS-2] SetVerifyPeer(Boolean) override added. + When AVerify=True, sets SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT + so the server demands a valid client certificate. + When AVerify=False, reverts to SSL_VERIFY_NONE (default). + Must be called AFTER SetCACertificate — the trust store must be + populated before verify mode is enabled. } interface @@ -166,6 +186,19 @@ TCrossOpenSslSocket = class(TCrossSslSocketBase) procedure SetCertificate(const ACertBuf: Pointer; const ACertBufSize: Integer); overload; override; procedure SetPrivateKey(const APKeyBuf: Pointer; const APKeyBufSize: Integer); overload; override; + + { ── MTLS-1: load a CA certificate (PEM buffer) for client-cert verification. + Calls SSL_CTX_add_client_CA to register the CA name in the + CertificateRequest list the server sends to clients during the + handshake, and X509_STORE_add_cert to populate the trust store used to + verify the certificate chain presented by the client. } + procedure SetCACertificate(const ACACertBuf: Pointer; const ACACertBufSize: Integer); overload; override; + + { ── MTLS-2: enable / disable client-certificate verification. + AVerify=True → SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT + (handshake fails without a valid client cert) + AVerify=False → SSL_VERIFY_NONE (default) } + procedure SetVerifyPeer(const AVerify: Boolean); override; end; {$IFDEF CROSS_OPENSSL_SELFTEST} @@ -1115,6 +1148,70 @@ procedure TCrossOpenSslSocket.SetPrivateKey(const APKeyBuf: Pointer; TSSLTools.SetPrivateKey(FSslCtx, APKeyBuf, APKeyBufSize); end; +{ ── MTLS-1: load a CA certificate (PEM buffer) into the SSL context ────────── + Registers the certificate with both the CertificateRequest CA list (sent to + clients in the TLS handshake to indicate which CAs the server trusts) and + the X509 trust store (used to verify the certificate chain presented by the + client). Must be called before SetVerifyPeer(True). } +procedure TCrossOpenSslSocket.SetCACertificate(const ACACertBuf: Pointer; + const ACACertBufSize: Integer); +var + LBio: PBIO; + LCACert: PX509; + LStore: PX509_STORE; +begin + if not Ssl or (FSslCtx = nil) then Exit; + + // Wrap the caller's buffer in a read-only memory BIO — no copy is made. + LBio := BIO_new_mem_buf(ACACertBuf, ACACertBufSize); + if LBio = nil then + raise ESsl.Create('SetCACertificate: BIO_new_mem_buf failed'); + try + // Parse the PEM-encoded X.509 certificate. + LCACert := PEM_read_bio_X509(LBio, nil, nil, nil); + if LCACert = nil then + raise ESsl.Create( + 'SetCACertificate: PEM_read_bio_X509 failed — ' + + 'ensure the buffer contains a valid PEM certificate'); + try + // Register the CA name in the CertificateRequest list. + SSL_CTX_add_client_CA(FSslCtx, LCACert); + + // Add the cert to the trust store for chain verification. + LStore := SSL_CTX_get_cert_store(FSslCtx); + if Assigned(LStore) then + X509_STORE_add_cert(LStore, LCACert); + // X509_STORE_add_cert returns 0 if the cert is already in the store + // (duplicate) — this is benign, so we do not raise on <= 0 here. + finally + // Decrement our local ref-count. The context and store hold their own. + X509_free(LCACert); + end; + finally + BIO_free(LBio); + end; +end; + +{ ── MTLS-2: enable or disable mandatory client-certificate verification ────── + SSL_VERIFY_NONE — no client certificate is requested (default). + SSL_VERIFY_PEER — request and verify, but allow connections + without a cert (or with an invalid cert). + SSL_VERIFY_FAIL_IF_NO_PEER_CERT — combined with PEER, requires the client + to present a valid cert; handshake fails + otherwise. + This implementation uses PEER | FAIL_IF_NO_PEER_CERT for AVerify=True so + the server demands a valid mTLS handshake. } +procedure TCrossOpenSslSocket.SetVerifyPeer(const AVerify: Boolean); +begin + if not Ssl or (FSslCtx = nil) then Exit; + + if AVerify then + SSL_CTX_set_verify(FSslCtx, + SSL_VERIFY_PEER or SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nil) + else + SSL_CTX_set_verify(FSslCtx, SSL_VERIFY_NONE, nil); +end; + procedure TCrossOpenSslSocket.TriggerConnected(const AConnection: ICrossConnection); var LConnection: TCrossOpenSslConnection; From 13d54e3b080b6e3f8a3464ce32a1d864f416b591 Mon Sep 17 00:00:00 2001 From: freitasjca Date: Fri, 29 May 2026 11:45:21 +0100 Subject: [PATCH 07/15] chore(release): bump version to 1.0.3 --- boss.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boss.json b/boss.json index 82a6aaf..2586ea6 100644 --- a/boss.json +++ b/boss.json @@ -1,7 +1,7 @@ { "name": "delphi-cross-socket", "description": "Delphi cross-platform async socket library (IOCP/epoll/kqueue) with HTTP server and OpenSSL 3.x support. Fork of winddriver/Delphi-Cross-Socket — adds Boss package manifest only. Zero source changes.", - "version": "1.0.1", + "version": "1.0.3", "homepage": "https://github.com/freitasjca/Delphi-Cross-Socket", "license": "MIT", "mainsrc": "Net/", From 8c7df13d0df9fb9f52d3df01242f92860c2d79cf Mon Sep 17 00:00:00 2001 From: freitasjca Date: Mon, 8 Jun 2026 12:40:17 +0100 Subject: [PATCH 08/15] chore: stop tracking Delphi build/IDE artifacts (.dcu/.res/.dproj.local/.dsv) --- .gitignore | 20 ++++++++++++++++++ CnPack/Crypto/CnAES.dcu | Bin 122925 -> 0 bytes CnPack/Crypto/CnBase64.dcu | Bin 7426 -> 0 bytes CnPack/Crypto/CnConsts.dcu | Bin 14305 -> 0 bytes CnPack/Crypto/CnDES.dcu | Bin 30941 -> 0 bytes CnPack/Crypto/CnFloat.dcu | Bin 15913 -> 0 bytes CnPack/Crypto/CnKDF.dcu | Bin 13854 -> 0 bytes CnPack/Crypto/CnMD5.dcu | Bin 15598 -> 0 bytes CnPack/Crypto/CnNative.dcu | Bin 48972 -> 0 bytes CnPack/Crypto/CnPemUtils.dcu | Bin 16968 -> 0 bytes CnPack/Crypto/CnRandom.dcu | Bin 5673 -> 0 bytes CnPack/Crypto/CnSHA1.dcu | Bin 10859 -> 0 bytes CnPack/Crypto/CnSHA2.dcu | Bin 30907 -> 0 bytes CnPack/Crypto/CnSHA3.dcu | Bin 31943 -> 0 bytes CnPack/Crypto/CnSM3.dcu | Bin 14942 -> 0 bytes .../Delphi/HttpServer/HttpServer.dproj.local | 2 -- Net/Demos/Delphi/HttpServer/HttpServer.res | Bin 109940 -> 0 bytes .../WebSocketClient.dproj.local | 2 -- .../WebSocketClient/WebSocketClient.res | Bin 109940 -> 0 bytes .../WebSocketServer.dproj.local | 2 -- .../WebSocketServer/WebSocketServer.res | Bin 109940 -> 0 bytes .../Old/CrossHttpConsole/CrossHttpConsole.res | Bin 32 -> 0 bytes .../CrossWebSocket/CrossWebSocketServer.res | Bin 59484 -> 0 bytes .../Old/TestCrossSocket/TestCrossSocket.res | Bin 59556 -> 0 bytes 24 files changed, 20 insertions(+), 6 deletions(-) delete mode 100644 CnPack/Crypto/CnAES.dcu delete mode 100644 CnPack/Crypto/CnBase64.dcu delete mode 100644 CnPack/Crypto/CnConsts.dcu delete mode 100644 CnPack/Crypto/CnDES.dcu delete mode 100644 CnPack/Crypto/CnFloat.dcu delete mode 100644 CnPack/Crypto/CnKDF.dcu delete mode 100644 CnPack/Crypto/CnMD5.dcu delete mode 100644 CnPack/Crypto/CnNative.dcu delete mode 100644 CnPack/Crypto/CnPemUtils.dcu delete mode 100644 CnPack/Crypto/CnRandom.dcu delete mode 100644 CnPack/Crypto/CnSHA1.dcu delete mode 100644 CnPack/Crypto/CnSHA2.dcu delete mode 100644 CnPack/Crypto/CnSHA3.dcu delete mode 100644 CnPack/Crypto/CnSM3.dcu delete mode 100644 Net/Demos/Delphi/HttpServer/HttpServer.dproj.local delete mode 100644 Net/Demos/Delphi/HttpServer/HttpServer.res delete mode 100644 Net/Demos/Delphi/WebSocketClient/WebSocketClient.dproj.local delete mode 100644 Net/Demos/Delphi/WebSocketClient/WebSocketClient.res delete mode 100644 Net/Demos/Delphi/WebSocketServer/WebSocketServer.dproj.local delete mode 100644 Net/Demos/Delphi/WebSocketServer/WebSocketServer.res delete mode 100644 Net/Demos/Old/CrossHttpConsole/CrossHttpConsole.res delete mode 100644 Net/Demos/Old/CrossWebSocket/CrossWebSocketServer.res delete mode 100644 Net/Demos/Old/TestCrossSocket/TestCrossSocket.res diff --git a/.gitignore b/.gitignore index 8454266..5c8da91 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,23 @@ backup/ **/vcl/ dunitx-results.xml *.bak + +# Claude Code +.claude/settings.local.json +.claude.json +CLAUDE.md + +# Delphi build output +__history/ +__recovery/ +*.dcu +*.exe +*.dll +*.bpl +*.dcp +*.local +*.identcache +*.tvsconfig +*.dsk +*.dproj.local +*.dsv diff --git a/CnPack/Crypto/CnAES.dcu b/CnPack/Crypto/CnAES.dcu deleted file mode 100644 index ebc666a410074a233b156bd06d693c171451fb02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 122925 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 U5XKli4!pF diff --git a/CnPack/Crypto/CnConsts.dcu b/CnPack/Crypto/CnConsts.dcu deleted file mode 100644 index c867ed279f4c00fe26ff633e118584d938e5bedb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14305 zcmeHOeRNbsmcQw|ghvxXK!||OoW^4y%z>DIXk@|Zd=envogiUw;!F2Sr=h!Fr#}c` zM+b1g&-I||@hGDVxDL)ZtOp!*(Dk@}uZNv=#53bKuIqy9y6SrHb6rLe_IIngUU$EA zbaeOZKfB>{-Rf6Wzq)nn)~{~WYuXCwyyF)WoxvaRpG$9uHdxU_GI9E>GauhZu4OTI zL$uTIZ>$PM{r`F8hV`ykiKmVwSjpcHPVS9{{8qs9Wgbmf8BLl&GrsqQ#6v;d+l!)xaD4rJzqmA5>TNNi zfw0*eiW=eY=sQ=$p7jSNpr@75P?Ecv*s>Cu8d1Ob(J!yQFF3)w!c6vr6NhHaFZVC8 z2l6AL{=+x@#^qm<(Ngm-$pV_@uPAP6Xz%Y>eLc~EEB~!V2YSUce$>3OwW+_oqo=>Q zqqn^g#jnX?PsI!_Zs_&(bhPz1b$54k_t)3?nowimc^}ufi3+@nOMTLG-Da@UNDgf! z3WWx}8dVfjp##mm{-EX(rZ2f?!HloJjX=%J3%L*&IDgwTscb z$Epk4eGI27!8T=frFJW)&eS3al(t{m`&BoG(xos1YuRp^fx18>WE;PxShn8ks^D^7 zYjp!wDhXG5=qF{Bn z{*8!#RdDJko=WGgf{Vr}$a+mqkEnhiAtCRL-v8!TKn~CV;Kzkj>#*G%Nn`$Ma^)`_ zm{AyN#8y&$8yAzEfer7oQgOd2H9hO#u5WAZt!nVI@(eymAsAzbQqY*OEsDS-*`|OA zlp8cfj1U|3^AD$Q)!bJo+^N8gz;Fp5@#K1Q+Gm-P*A44fp9(6dE#JUu<6tX_T1uyn(o;-uz2srtpvXuGd; z-h{x7!{VmsgPqpIOtQZuF_Qr?UhdPxw~)}lq|K-y`~EKK#|1`=`cWRBOj@o>CKm5F0iX{35a;Wf~0#;o|bx^yax$zw3Op$j`-TxcXVY-Z5@9@B`Z4gKZ` z_IA%3~VYnqmc9l*e+LsmFeVD0YE7Fo02v~Obw{4QGh&`Ok zMhE&4c-y)Zl#K1DHRK=3>geWl6~sttd+V6#|{fpu-`t+Ixq2`jp8$jZd>AExVNTdy&01g&UigTmT(mW^dk_-Yde zv8>swn=b2Qd#B$YPubJ?WV!+@Y%A0VfC0lwU@h3*RWm~ZK_TWLVZc`5!~+@MIG(N) z%bIhavB^w^BBs*%Xt@N+_Vt7nwlsf=S}s@TiHXC{nHKgLWO z#I{a-s?o%{vj=}XT_;-?UYGbNb%$r!F!sc+3$z<_pzI1Xm^LNI1agzO3d zbAx3M_h_bq?R(uuriZ$7YyjIF{wUULz&=17N>>r?-5cE)wMKHze>LYy2+W?_CrTP{ zx>sX7o-S>1RoHXOJgS1nZyMIxb_eMytk*wTj6*_?BKA@c`xe@O;AY&Yc7}2{#mx%p zyElCi)7)VNH62hs1PC0Agt0RWBUyI8l{f@7 zveE42nBFWD-rC=3&pJ+kjFz(X9M_UIVtQ{;i0^-VYMJAbgU@?W%nEB2%&(tqK)DSm zu-HolrelKTDT*U*hFU}y(PBFihuLhk)Na)#Pg9TY+@~vMq5?NJeSVk28S62_qZl+F zZhTNU1231%rD&)!KD^ymM4_#Mr?S-IrdaLFLRM)5JBJzF;_yqz5> z`-GZx!n7BW+JY6hyXn;xjzfz9EhG6R%Jy%uM=OL03zkhCGvULw!SYP_Of}l9tz4l! zG-1Uq$6)y!kU+4<2XaHKoFoR{PwQwEt%aUrCdl?o83QQjmGk}(bof&Oc1sD+u<$A) z-{jcy-GYEYf&G(f%9WZsCqQk%R15)(*@5RhW!nHVY=dxAp+Fu#UFUUx44^R&(<@GQ zJe%swnoTew^iU`V_Li-3jEiq2*;EUKxi;ck9;dUXAuCQ%n6oC8U+QpYzAuOYDJ}*l z9or9FK54TLW^t?S&e@@jg1+Y5g}8Zg>;QZ|WTxTUjU@7sY&hF_RRpA4UOcjy~^8nf_!|(4-*_=?&{|`GH zBV`P}^5BK)hpN1EvlO!pmmPvB3xJ+ycS^ zmA9*`8Om^rh&C1IU+>)imcwxp7;FNNJm?`z_E0`0ZA+@qQ~~Z=Ht%eQB@H-q41UN< zdm~*4y}Z!Y5Vo{z9a+~XCN#6HrXyN~{NlEaw>jbmUfL0%C|{WIp*k;N*j_FIV1>8m z-V4?{qK6BiT}}G4C>=2kgKD$vXk&?3Sz&c-*?)rriT$wjjR^_)cv9-)QbJS1oNA zX9V|Ve1SR0zA)8?CatEi5pQnfl?xib`;#MR{BxJ0fp*kvMhkfz>%kpeK-`%z7W>2~ zzA5kHOMDM~4_BHTaI?R7#5}Q-?Rfj)Fx-#le96jKyty&^$@-kKKl7UfZpRBH(-Ys- zaYW2Fe{uA7Igg`^$AO`DH2Ume+}pDh`^jE4iaDsa0&Vy{aydRy8xKat{c%6pPrLCX zqiLoLeN9n)Z8GD7VQT~yo8-Rh_nLc-ZL#I(OWIo5r!7b8c_09`SqPH#VOwxyJ%A_t zl;ao=?7{pPhh^AaBeVd|I+171m_$7I@R5es0b9c(TFzm6l%{pWrqhEnHdK7ngeBY$ zDr?N;TEg~{-s8C0OyEjc*(CxjURyjvxh32)a{=#tvSc6q6{Ah{b%X0Zc z(T=N50Bm3W^wW+2pb}j(0B@eWrOxLjC1{eYi^{Q~-MW%PxRlB{gvpLsdER(=TgnU% z2t~g7(Ij`d@3~z#MlVpd)&O6ReT+Fqbi|xu$R7@&cFWO=pTT>rwfMOJmQ2VB*d^_< zWc^}}fyJFYaWG$Z7rUxznu$tj z(InL^Zd;3qim9>`@9@lItC2_webD_gC$4RyYS;8)@)UQQiBvd=kgfQnzj8`{L)4dB z_u$e;wxBMR(VRlGPgg7vKfDTU5%1-J$UnfMKkBYIyUNJF$5mLugo<^=c3b% z4-30EUxNIE<9LoAS(Wnd54KLhkI#O%*DD~xqfB(-k6&A= zx#3^3tb}1?l*fdlUg|SorrrePFGDFu_R^5Kdk%5Hjyo4wBZ4Q z+;MX2xlvE9eU3>ys52M+vj(~K*mm;WJRi+DLdz}ZpR=%&@+pVc1HZQAwZMo0u~DyYo15e<9EVT=|0rXT5deRGLDctJ3q^2X4&O6AJ=(^1_v`9QZFA zhs(3?-ks$<&&{xpyh-=q?Kbz2i@|kTQG+#E3(5ER`Ra6{gh{V2t*x^T>(T<00a%c) zv7P1IkMnZcS%>Y%x@0b#J-EK%OWa(Y*~i#FSR?++wh8A~pbcBo6xQP%r%Q~`S(kOH zLy3&>`ATf;*m<3GAtaSQXw2=4qh_8*)*~q9QQpz5Mc>j|mEt!VWAA2p%gM!J`}xpQ zFEnb!KW90QS>2!JD^u5^&N9}&6_zkD0_Qqld;6fPytM2?4ZgH&ht+a*;~y8SLdg&i z_%f6IK>9C_JGU-lHi~s4uNe8HRs}>}KiTudYjicV;?vW3{Fb=^%x%j!s?`82&9~ni zuSjij>+;oIX05UJ@=B_NO|m_nQKBLc$kvhlgE=z$b`FomjDu~$(J|kIj^-(^2L^jd z1by<)L$dpj^Paf~bK{G4 zw~YO<8)M?Rw25N+_06?>zYp8&~&Qr@~8PZzR059Q`ha{Qu%!G6TL%Au(b!yR0po}oM9`_ zlpQ*r9OkTO^8dO2%hp)@#Jaw|z;$Iq%it7i&m4P){o>z0z5MB`7jmxP>B!Ak1Lu=A zT?d_Tx`4DQovK>!VoF=2)1q2j@M;(7bWt^Kc(tWEEv=*j-zt)2eDvlh&?NdnK4t>(;5e1qWemjZSM?zyR7hoz~Uj7xmirb^88Rx=M7t zU8Fljdc8<*66r0Z-Kx{AEp!`cx9fC!3+*QDPMz+or9GtW)oE`n-A&p(I^E-?{iOX& zr=NN0KGF{8bihmZlXg(2gSGSkX%Fi3pqCyd?XXUVTj){J9@FWuYI>ZsCv-6hg^a5!w>hxkQy+qn?b^2{Jy-eCGI=xa&uafqfPOnwd z>!cmi=~xTBLE4)-z1c}`k@mJuZ@199q`jxpd$n|ev=4Oppqf4+?Gv3o>7-9dJE_yj z7=1?CDV08LpL4FRNS0Fzh z`T4GDT8MlN@-@hVD6~tEzXbW^$k!oXhkO(AE0JG`wr$9FA>ZZdq+aCvkneM~P*J@3D zNLxhOD$-7o_K0+?NY{(>7Lnd2(%mB6BhtG?x?iOCiS&MvJ|NPEMf#{n9~bFUB7IJz zM@0I9NM91^%OZVMq_2zg4UxVj(sxCALZlyw^iz?3CeqU)EpiDlS&A7_d`pT7DHckx zM2h87G)d7WMK6olFlAX$SsA%B7__9owTo^pcC8}UUA3-OOv7Ii9dZ{{CC$xA?V+;b zs!%#tR29GvHnl&LX;lM>gmwpHG7LHWffMKBKerH8IfRB~4xwY6LzG~xLzH5%LrlYh zhnS8P4>1#~9%43@J;b-M^dUT0`w-`2{X@(J0YH2QBml7hEC5jrCV&8etbzb{v_jN^ z4%5r}I+BM>)& zN+50mmq6SCK7qIugaUCpNCjdySOsDam<3`ls0HF4&O zIMXEf3>hY+IsBvxbt*X1izo9rbGhI)WDGp1;U^)%aL7dPSF#w=I8u`Gl!5d3X5Iz2r_0N;w{dE e3USNw2)Y>N%(KXha^|S(k2<+r=u|5s diff --git a/CnPack/Crypto/CnDES.dcu b/CnPack/Crypto/CnDES.dcu deleted file mode 100644 index 86e855f0e249b9d709daafffd26601b8f2c8b4ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30941 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

NA(3P9!?JiueiT3|zuV96ev0!$^2X$c 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 IRjl;?0`Q@bKL7v# diff --git a/CnPack/Crypto/CnSM3.dcu b/CnPack/Crypto/CnSM3.dcu deleted file mode 100644 index 5702308fecc90851e7e1705244d10cf62f426a3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14942 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 hoP3Lj*(N*248(j>HZvNH_!X!X - diff --git a/Net/Demos/Delphi/HttpServer/HttpServer.res b/Net/Demos/Delphi/HttpServer/HttpServer.res deleted file mode 100644 index f319bd8c09e7c0f4d14bbc6df8daf7655db98f89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 109940 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
8{ANffi>JY8gRp~PmZm^D|e2D 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 diff --git a/Net/Demos/Delphi/WebSocketClient/WebSocketClient.dproj.local b/Net/Demos/Delphi/WebSocketClient/WebSocketClient.dproj.local deleted file mode 100644 index b3811b7..0000000 --- a/Net/Demos/Delphi/WebSocketClient/WebSocketClient.dproj.local +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/Net/Demos/Delphi/WebSocketClient/WebSocketClient.res b/Net/Demos/Delphi/WebSocketClient/WebSocketClient.res deleted file mode 100644 index f319bd8c09e7c0f4d14bbc6df8daf7655db98f89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 109940 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
Q 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
8{ANffi>JY8gRp~PmZm^D|e2D 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 diff --git a/Net/Demos/Delphi/WebSocketServer/WebSocketServer.dproj.local b/Net/Demos/Delphi/WebSocketServer/WebSocketServer.dproj.local deleted file mode 100644 index b3811b7..0000000 --- a/Net/Demos/Delphi/WebSocketServer/WebSocketServer.dproj.local +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/Net/Demos/Delphi/WebSocketServer/WebSocketServer.res b/Net/Demos/Delphi/WebSocketServer/WebSocketServer.res deleted file mode 100644 index f319bd8c09e7c0f4d14bbc6df8daf7655db98f89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 109940 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
Q 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
8{ANffi>JY8gRp~PmZm^D|e2D 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 diff --git a/Net/Demos/Old/CrossHttpConsole/CrossHttpConsole.res b/Net/Demos/Old/CrossHttpConsole/CrossHttpConsole.res deleted file mode 100644 index 36f26e234a8ac66a47e95cec6d496cf2f1442471..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32 UcmZQzU|>)H;{X347|28c09i@|9RL6T diff --git a/Net/Demos/Old/CrossWebSocket/CrossWebSocketServer.res b/Net/Demos/Old/CrossWebSocket/CrossWebSocketServer.res deleted file mode 100644 index 1446e4cc6e9fe9e970eb5627469e4db7cfc208ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59484 zcmce81wd6v`}ZXTL{yBm6;u#JkPsCM5J3S01VNCL5JgH!rKLnE=?-a-?(UNA?o_(# z-g~~8%U)%D-Cg&6_y3K~opWa9%sdn4nJ0b+6bgl+1`$CvBDnlR;3veFQ-V4KxH1;h zR$_c5enNI|DUK3F$$?)!lnA&IKnbDlfqMb)dlOv4kV8C;MWNvH8*SiIE?g-J1slYd z{GNr102u_JJss3b)H9R@N(Hp`45fxr1}$r#o}e^AMN3>A78E;*1$7BTc0dE9NCfp8 zcotuu7d)elQpB~R1=@QCp4Gs0a|7gQf--H?Lr_Nn^ri{wJqOo1;941!>fwH2Wfm0K zrZ&ZK`P!S>Vnv+=b?^}dD5M4Tg>gNofZxX`bwD{Uu3tsak2`nO}kC7cW#y__8<4AuTCmaz0SbaDO{EUBJAry)R zx4I8-GoS%xS`F0Pyaro|hlrno4L}XrK@g&E`;3zE`#z%wWt1SoIs~|1aPbR4ROA7r zzOJ6CrkYx;ytH(MytGUOxQ=`1&Fa?@AEX)9v4$!#|HtVVT|A0&HYh7-Ik4P71d1?w#F^ zNJ6{Gj`%=GBf;w$Vv=?*n(}WuSdc|!=)4A;=;4iix4I-#<)+jNLKnhVrMgs z^mMP{o=s1kM?ybNBWh2Ek&)qb%XRI3HcN;i+d&_bOy=J zm`6&B7ZGpwNn~(f4dLSGhIO$?v8kAZm{`xe>>Sz8rKMnfYp_Q8V@P<&3=$eNjhGvK zK@_A1k?`Od91V{|2M~XsDdf5GFd{BgwO(3KfF#Bzh{VSyZf&To9Z8I>#NOuZz|jur z|Fd}KW+yg2x*T0oS=nP~XiNh4Kto;qgYJ$FE+YMXBiORieoT4U0A`?n6f-+B1J-}ItF5K=*5+q^yl$v(Aeo+? z7F}Fia$j3pOIclAOTznY#rNlT=wqbv8$=533;tu10^WQ1s{sv-)qvbd-Lu1#LQ z2K>tgYi4ZHprokuXzNyTF#5j_Dk{&80UlEr_Awao0esEX$qDiH2teMLgkp8IqOdw3 zni~gWz1)0pywSte6}%%Jh=rMX_MJO-5C2sU2KukgI@vpn_<4IHLH+@VpLZ^zB-etl z(6@YhKk@tu<|)cFf_~DmL4JNnAmEc993A^*W#vx)tdG~PjgGoFIgNO@xFC^X(TI*_ z0~Ycde0zVE!a6UWS7W2XqY&7StFud=sHhlR`fq`Yi<{8f(<={_C&i~Aa+1w|+wPD3 z$vmvbCMP5#F;P(n;QPr$L`2`#-PgxgGATYD$<59|^k25%c-oK8|H{3NW<9p7xES!* z9OTU#%X@GDtgOrg$%#pI#enZ5C$!*r@UOJ>vpR6DQWBf7fNwz_Rt%aa@bK_Hn+N)< zC@n*tJZ{6$UXZ(hRDE8;#gf8B#LI0G;l9)Z&c^{moI_6Fol~_ zCD|ryQ$qt%QC5agQhIVCIx1Q#Gc64%DXK)6={M$mb_R_M53Pam%pv)puay-nGC6@p z?(p>?ncy5+U&kU6faf#Qbs#m>OUNQP0|a<_aqTnHHDfDEDzT+tp1eH06`~>{z2iQ8 zLOuqRe4BUJernR(w>1_M>PJ>ru}DtV0&Wt^?5uLo z34rF%z>j|59E^tT+XMLkUk}osmOO`WgEI@x13W+L>z0v)c?|9v(hKJZ26#p@(Qe2q z_~+kQWTE50J`D}}=o=gT$vrkY8u9ha`9u3<;B4HG2?i0<*I$seH7r=OCGgG;Ap`wu zxO2NOe*rfRcs`yz^}P=-m$dby*jOYiIK(C?G3i+rn5*oJJS;O^Bd!lf|I{QJsj6H; znwwT|w8Hg$p*DhB7f83myK!7!a4jZ5UARV&{S_k^4A?)DNP1cg z_W6?{%-x&KK(4{dG#lyNTP+x^=N0SO8TISKgF{GrOAFH6*i?~`p1JpDZR7LmYU_3m z4h#fOO-y3v=jRb9^YnE0VKdVkF%e-6=*aL!barOTdVk*_W`1rCnHV2Oh6V>Q9qsMz z2?>cmr5oS&=5%Oqh!e;|DN9RB>p&Jl&}cMxm$0}9uUD3rft)+H`eke^rlY+Bs>1(O zXl-rV4`erSFc$OWZ@$vhWl~ud{u2C$?6t#k)Ld~FdqWVyzsC*O= z$_z+MF#bxw*M-l)2-|>dp;25Y1pJEt${;mpXhTlh5Mh3l(_lF_i2tpe1|I!GIC${T zc0s}0yyD^yb;TcuIXw^&@pvF2>LD&B?)X6Tfi@4%jqBUCZKL?ZL;w2?!Gi~4+`8I2 zQ6@%4^CpIdi0+FQ$TMZ-Z*rX~xYm355-|nxp5d!kGtX6@hu*lsdj)j;Ym@yaG)hQ3 zVzRWb%z<*5mzx{lt?z)mXM*TxX(3OQl#$0WGKhkVERGhKX9{S0XKjs>4S{Zq)zQ{T z;pV;$Rrh}y2y}JyG(Fwimf;x|;Nycp`OVGQ1qlm@1oCAfkTr9$uXKyCuXKvAriR&A zC%ZUoXiymF`vU^?b*Ov$d3hm@cJ}j+A1gco1pLxmP*G74nVFb*K=~EQmT>Ih!J*(x zDg}B_80*t!>Ie+%Q?;B6U1<=N)$Z~9AY#bO5kmmw}rUe89seYs(C@?5B0mvR{ zNy$h_VZ;A4ZhYVPl=ET}wji$(TL|O>D1*DYxQ1=+|NVRW3z_NZxU!n68szzt)^9Qu zzK#Dih5G@V??8^J1hR4NI^bd7^rh&iPXUGb`8ZiUBees2<|NbyI)I$qxhZ~^)9|!F znF-d}EW_c;Hb1{1N46sAsm+*XAgh408p_xXa1MlpMYg0Sr%V@sxv4C#05+!$T|rKA z5GNx-c^4m{ybg5&ZH*D!yI}Ha3|F?aghB4y?EAy}5eDQ}_#D&+F0ppu%2bsbaQ)W- znJh6ru@`htOdJK4ehH`W>7Kb${&9zG2Kb}Ja5Obqj&O%2X9q^rDi z5m(j%WdIIPh z>QTPlKE_dzQ5Mk=5r9WUBJZug>zerfp&s*4cmUWI2ERq9!@&S`AeayL0n|fb_%gP! z_QeH@2nWl?zTe!xrAhW$QcMhz2%@)_k4DU=*vHAh#sK3-|NQ^hf6&${^KcLsp$_*k zU>d=oaa|!F>?e@NQbR~@&nhkh_NlEgiqpGchKI`}!twjNw?RWY;_H#R2G<_$fe#;C z?gR&ioz2O}1bSWu(47hqR)$*K9>9+uzC&|B|Ai5a-WVfn8|wJbCY%sE3vY3H;giQh zxV#|$js3Z_hylEG_#1y>p|3^fq-WxE!0hyNjI^}OAw@++LZDNPlmI(OX<-qtJC)=1 z0PKHh3A-s`aJGcXiY3J6%~zZbXs9=avm-;+kg zq7|qk7J~OLB`LWM@E@E^l9!X`SW{7f)PDYqM1~du{@aYRwM*Owy5i;tbVq2j#z&kU z`FlA&51(!>yUE#$oS|vKh6HA>lou5tpG!)R*qB%Y$bVq~Hs@1y)ivlQz?Y#OC?k=N zfp+bOpzVJn!guGWNSf&B@NO+1xk0PEAeU-_q1P-r3rU^mcUtevps3%~uEP=l@LK zh5Gd7XYSoFVgf!2X8^2LVqm#E9PejJG;8tV4bQ&WHsj{$pEKhoXR)%p2z<%K`%=dbd?bGyby$DBa_%dmf-^8-G=3eMSe z1Opf&Uhjw3>uYP^+*<~=!j1mFe)%%j+tX_v9v=D2wuL{V1^8eNPE1S~0y^qffKm0Q z{R5homzL0At;$D6Mznx$X4jv!_rK&96cp_n85!l9oS0Mwwh67dxp}Se@d<^2fr0CQ zkNx95kv>u!^Z|eqOjl4Ssu>h&XCDeh3S&Ny4`DO|d>Tg7F9v-5{NJDN18u=}Vf$zl ziVOCIm=Pez%uXbN7KNfl;q4e3?yMi}7%ZS%9>jmkjscqb(?CE#u;s{+qX*BQzi=okCU?QGTp|JXcXcG}P3v&sA0Dfv>IR{(TV#c6N4d;BEt+ zzyH61j*f2Mqes$40H4tP*2)_D{_R`D(##ClK=l!AO-&rF%7Fe2JBthguOa;}H8c<- zP{+#L9D&aO9~(wZRjuXr?K|2O6cm4Hr~EfY2>gr`3JQvb)>hV&(5?V55(x0I0W89I z`XP;~Po5x(a&m~gloSH67eKa>!{xnDS4RwVba4JjTPrJ|ch~`+i8JEt=!od)>JQ(& zdru4aCAa+>wEoZru%(G}nwpq3K|2GqEkWNMw0A%}haK>lZp^;{u(7>FUg_!~z)uSD z%;6jZ`<5}FTNlv-WyY^wZvs?X0 z>mTkJ8JWoR^$q-7KRDxTV$dc9=N-}xY-2$8O+hl#ngDI>*sJGju?#@|-K?|x>>AoA zu3o4Cw!ao^Qv7Eu@JE5U_r%d3@Vng&+TPqnD z2yKu!nt^T68}t?TDHh4iYQ-wcHvydm+6Dj9M)E6pOtekFN7{f*N&Jk3dMKoOa|C^1 zpFB}<+p=W~$uE+PuSRHQYVHl+Eu2je&=2>Dzqc>Iuv7qSO&jp7HT>6f|2Q@l`bNN$ z>M_|F*$CXDo5$ee<%LyHP_hDqee-YQiTtw^$jL7}0KIVDVT3kl;2Q)sh8E!8s{5v^ z{z%9FcHfQwxfz?2RSs;IVE~T+_UiA^$IBZnCid{B_RAl~@ZyE`MSu-hg8K#cP60j{ z6ZHuxE$KjbIX86N|BcSS-fMhZb=aKDDr_8hFT#O+1@gKGkh;6MPjYZ@F#JgG=6i7N zlX-f0)rJHG0lP*J?)jwn1f;sE>;DVw_<7;us>K%NS7V_~7UCchfqgas*extAtTF&j z;!ocNU{BSGiHgSAw4hBlBQ+i9K5f76nZKSleBb|8DkfBet^QntEy&FSIF4+boe|(J zure~TlAGroe|_(s@b-xCh_Un($P?3WHsQMJI>ZLNt7m?<4gOoS{aQQi;GC<&)YsGk zy}cZPI1(7a{%8iW;(y3Yz^0=CZK-)+tVO`4Tv`4ZU>N!VpQ-=X_{^`-{e7L80beS} zYsEm@GqnBIR#hQI1%(JW7sT-M4pV@MA&QFp)CBGHMZg~PxvU&%Zw2;TxeffmKkfJ5 ztgj$bi|Ov@M4-PP+RtHhadFE6WPdxG-@LIppOuk`f%KOEI}e=u;=(?_C%?}<#MpSc zPX0%PwqrAZX@EFGh>yY34zUdoQ-OcR+Wb342VV!Do&&g0h!w@xh4>GA86!;-*vrkB zR$za@(GToQ>1i2DtgLJ&@M{nl@X;LD;&6K&U^9@K%4&dD`|b;Yc36lZ`Kti!(0#pY zKtBGCy|FO;@`p!swMIA5^?j^-nFy|4ZkpFs)6^*cxDmgFXltU7TGb0sREvY$lJ7jhjhJP6mFO6d>1R z1Af(pWjOI&KKPM-Xy1LRFpP^DPe*WTKQ#Eq^$81}#?c8eN6;>g4@Ce2g!da=WCr#o zux9x1XTAd{^Q9zKtXBa0C44_2b}jg0a68~bBo-D{rxN4hf$STLJ1d}1$J@OL*mA%7 zYJa3(9nida4&gQQFXa60(}DB=NCooX-UfyUVs$sqv4zRT{)V_v0ePV z!@JV;BJh6ZW@RC{V4naPa)Fli)Nih??tF3JY>NhdfY|6LBt1D5=opRP{1Nc^U!fmA z28gZ32mBhqGI)&-kXHCUZyu8+cvtYW{w#f|UbdDCe3j{7pQHgBesX*Q7O36~fq}u| zkoE|GMURRIM>0~53%Q6og4lJd^tXam_PiU`Wfvo zPhP5gEgPJz$-m1IDL}4~las#`78da+68NA(gM)FhQbuYTA}d+@kLkY%d@c~HXA5xa z_%ILrRI(BSxCnhn&|d>_ahn6gs=;^U&*;YIKfGVQnwgl0^It*CXcF*itEi}QLi(W( zE$nyt(^FDGe>J~EKlIbxgC)e+a%zO=TE|tdi&`Iqx=_jdf7Pj9n-PX+j~Ag&P~Am$Wb4$s!j z0b(KX0q!aNm!k+fz>RLEdGocJO5QT0ANv2GEDh!#4e$^r?Cl+oB_||eVIGv3;d|j^ zUk2#^bN=aMH-S5M@OV#{!t5;mU)Pn9wkaTs0Te=Pv|36#;^+P)LQ)9>#e zaI&PZXbs92&_`Mc;UDqGKg-)(2Vag)H<$h0^|cEdXPU^}%mpx~0ApW*lmq<{ z(iIi;$@e?u8&`>m$s$m`hJI-1kA^WODi?G1)MqT@3IB#a`k%A`aU4vvHR$NDj3wx! zuLg8OA9hv6XN*>8BDlaQQ^#XfS>O9c1&^RA5#0LOc!1rw{c6Rp6Kh8b=-rU@rpz?ENOb77gL)syJ z9s1PMQ}VFauV$b{@AM%LfS>;VGC~XhFK6CTc1FPp#2i4q5z^Dy)(+?17EkM+rGS?n z0(gXxF5tU|-}3bXKl%{xC&$NRVg&gz&>~vynCw|qa>HSoRXBk z0_SIBXb6Gx1^FNRW(#~Hx|o@fdH>Jo`<490#wIzio~!UZfbHXO8Q>ez`T05c9Vr|K zT17ErU63yeeVexxU_*X}5y4|d09J&r9pFXsRyEb)mT+{BjDYWozXI&!2oC$w0p=dQ zx8VDXsm#pm8^1#1-_-%%h+G*Q80>{}1p9((FbD7&cx(ww+uPc((NSsZmgdoGDoWvN z5)UHQMD9hcirkA{c_bdS`dlS?`JGMTa#BL>GQieg7QnYA@LO7llYwmxgSqJgYupR= zDtPy*z_%r*{*JDHQl6Wew`ZV#z!$s&=*{#)YzmA39|CmSwQm>|h!uf(FrvXV4yyvv zRd5gRBH-JzP4ol25u6(^hNb4_77M`R|HHogPiXzCx=l^Zm%ogC$pIJ=EFN34nSS^! z4IX0yWy)_@8;}pj1aUY&(hsmN=>ER`NPsWD{}v|tf8Ut;@7X^L0}xy5dZVz z{6o6`ihlT=64*PVLqkI!0A`2oPdoZQE&y`h_MV>Jy8z4MG&3_(2Iv|GbBu;-fDiB* zjBg!`b#!uaDi>g*tikxNySloP{U4L}kDCt;4kbxSO8Kp{w1O7!Uk30E8bd)r@ySo0 z;`Z3vJN)ao83f5E`UYfzf6E1ejbPdbz(+7O1Hv9m;Yh#_z#st>5(<1z1p*fee5(Zl z)%O(Ol>lN1h3bPT@SNk*e0UE$4*1jz-UBJ}rztG^mxCE>?EZ%kjeqNCc(VGB82ECZlFC(77#|3z=KQQQ+FxK~#e)wuhyCy?@P0efa zQHod^tyJpJ8#U<{cUVe-OlHi9inp%v6Vf{}elJxL79FRt^c%SMg|7RZ^ z2r=1KvmT_UuW#5pv({=O)zQJjnU{BbZ298an}Wb%32tYayZ86rZD6g-&O~z5n zZP)KKvNP3e7j1R9$>znr{bZ2Oh>?z-p5ALcJyi`5b(EAwW>x&XjvYJZK=77`a`Bch zso9!DSHan=i9~Ck*qqdyn5?X<<9i<+B)4*3&&Gzz287>eOx|~Qp7@%qqntBM^WbdZ z;4HU0t*~H$C-LW}C0wOUJ1W@{bl_;Z$GO-fdXjYKF<)Y*Ph6>&QB7qB$<`;+dV3OI&5yVpRaZZJ;zM~D zH%t0iN;1afbqtd^cm5u7o1kZh=tJYyDqhxn;HP0Zcg;Q{BVz@?B3HV)q^B2}n)*dg zo-`ENv3;^PL9uMMjLOt#FZV~R!8l5oD&xlL$~0oK?7jW)*=Ntxb3P^{%+3jOWS`ng zo^s*ViKgjg3(Dm(8s5bY{RBm^msgLQq2oL*r>(BO@;!EV&pFXXMbSplTcxF?vd0b` zY)@D(*{^RpO3F1x#3E;k)ZjmCm(?h&$lO$y$D+CSjLIUjDC`J~!sfb>x~dGcfyIHjpN7YnyJqAM@v zCWP-G(M54+mX>j0XZ}Imn zj2)=jLqM6rWn;&M;tdJ`(*|ny?gZ=7*N+CeiG_H4c($gM{ z;dTzO(_^`E&Y~wb*UQD&xN~``eLml~7c&*-aO4u(gMe3HiN(s~&?R!8vc^8X@5xd7 z(x9)$B$=3+lXKLy!7hKl=(OB>R9`9+70Q?UI+*|g0g>X;du@jgA9gJ)FCM*OFjj}C z_2y!*nx^ZWS>uncA4S!SIOWcjFz4o~Om^(lWtN=tIV1jw;C zUl%3en(#s~dODa2)1`jxj5u0jxgoUmtW2gIo4^}ouN?(xblRt{8^;iu`D_(Fjp9f< zR|;BIl6*rWz;btwaZb)aTY_S3-rQW}vdJtJGOIE;ICygLpcJW@w_RH9Vod+Vyf1e( zrzKOqo&+?vb@kK}n%VHtQY+~I?3l)mWujbYA7IhUVPb8LfJ{Q~cp?}vA z&X)$gl~?q8=3~~U)~7M+%K@Ki`@qW88+4D$?qBiSX*_0pEn3`Ir#VV&+~?#jsp^YN z5?u@ullu>&Y9=|%1PKCXl2i$(qmL?8JP>dWq-Rr-BsoqTE)-B2WI^gU)s-^NmAeqi zj2W$~tCKgr*-8-jF+r`JZStHcc63@c<@I8jc$`dDWJbn8Uv1AY<*XUvID_-DWT*$@ zBT_~v`eR!p&M@bDq0AcHz7i9DK2Qo8&do90nVYOwmS;LOAAp#!A37RSJ98PeH)lUG zmlD^Vs?nXvC6)4|T1;JivhPh1`yJ27Dh{&~N7F<|&5~{rx|5o*%WI*C6B)0I{YL+e zQ1J9Ud*8yI97DZpm?lv&jk@ZH^YtQ*NJA?jvNm zOBD7j^px1;PbrsC^t5)P0b8{+2+c%A`Au!Kw^>q_CsN!M4WcI}BYSOVm|(bk#_`%( z-3>W(DOjuLP2Dze>ZtVjnk$`}xwEB0v65L!HDb}?>jwa%2JIFOtVVHilT{a|c}NYP z!JzN(=bx*mlvPJXSnUrKLB&_I6I3SNB@%NBdUlNd9Ytlb*2+xK%Iz!q*ipC@n7QVw z&XE$#v_?_Hw|><%#f-}#`PCP@b*6uND6?4Vu(YFOV4t(VQR~M;WTuz1s&`1y?q@{# zYMe{63z1777~OqwXcgS*=r-E@XsN}SQ~U|iOSx28sWqOvIU0baJqlV1FVEEG20LV_qW(V6!| z`3hwOuIr5ZBR)%-ePkfmv#t1@s)JaC=J2%W)0Z4+d$cr;f8Z}C;RKtw0FBFK#~S;zC0`MedWcax0M)Oe~@Kc|I`YDrD{WjnBGw+NLbnT-(9eaJl;0>`GiN`b*Z-nhGkM zS&2Gbo}f<%J0#>Tm!;n6aX~$ED26G9iRI27Ti)H78u^m0h3b4&cU?HQ80-k0!+wDO%exZnC2c_X{k zvqSEWy}Q`%`X3^+B$J{hqd#uRD(FcgD(UP=bLPPZ+OPFjABdhGsAu0zzQwk8ld&F)Rbne<5p1&fvzE{$7bxbhAntlmwL9dL~Q}*OsDTO-!at85f=Ucy5q#0 z0sBqzb|x|^E;OCKx;~MVm%W_3jvc7KMb*7Ezi^8LA?6LSS)9?A+nVi0?aGM3Z0X%f zTFE!Dhu@a%VY$1_Za8j@W^jPW>9nL<)|v`I{^YzBp_z7yP~3#82pQ_N2t0#J%jj4x zU$zzvzsbtUdOS=etfUL=%YVw{s@EM)TZ1Z=JzIJP%UFGjgaXDGWq)qj6B5QcRblFXm58p(`X3p9(AS|sgDSG^_yc^G>HYl`MqQn z{laf=diw}Gmpb$8xjG+BgPlAJ8DGK;?aAGPA0yUdJ;Q_}57(WpOC{+eA(`sn=A?{x z_eP!tb+=Le0Eu4i!oZA0-b#s_@oc3WmeZ`wDr~#7Fe)Ch?4$t9gpAJx^|eNSw=>F> ziB9~db~%nmzS*M{fstIlu$?6IZ9b0&^*&9^P5$&Thd4KLM*$A!cGrRj%lnm!? z?iD<~i`;g1*4hp-`U>MU9+Whh7MTQ3{s5tM9}CBR0S#N4{o*`iCvVDEi7HgFJ*g3> z5_}3!N93cj%=a+_F+oA~olR{aeBR!n4oeq0y1VTi9Q4@PEraL$1)pc8p?Ee zRG;HicG9}FlqP1h+Cv5#W?f1$mgyi-m1^#H#yGb-;5;dLMIJli;to)a`DhxQUT^_P^F=V+O(oxto~lG{PB{D<* zJ;GS&YsG(OHw_()KtS`}Yg4llWW*uz>Bs9j8ooZ)RCn{xV-7td&UnMn@QM+qrnOt` z%iY^Z&2*@R9~~~=f||-)8>Kqu*D<;Hnv$F(FoHbnRCqila#F|yo+U#rLY%8}RtmeN zDN!?4wWe6_$}|m3Y1nOMnUj@lfX{ub=U{vvZkbMrO5_om7hhX2^e&5Pe5Z(N=!Wm_;&Q;c(1Ew1KymhfV@(ZBbwx$U)pNHj5;&f-QM6E;u%eON@tJLw zbt{9Su*jRU=4QLvcr@g;`@Uc2p^7hGe_qzMRqOF>Gq;8V6vx>DSt^;T9=UVg<5hF5 zU-68hQQ(X#d2>DHQp2IIYMRSu$ETh|i^r5Y)5^pfQc(vV9C9|h>Udx;ZHA?^0$cU= zw^xPBHJFL_DkbkZPOK!rLx04qY|#AK0fT<4{cF>veda>l+O^lXwgd)DcjUj?iGq>_ zW=UBp6+M`#JI>>)UA#x2Skbo1l8M-iCrCebsa-73XsctckkfrG&GsoO7TEdCBn!#+<0|45Ejv`z5oteD2?~ z*I_@Y{8oZJ7pM>LP-|EaoU-C~5UJW(!Kn90RQC*}{9UG)pjd~R{CC4=LUfNQ`1=R z5%Wb<( -&zzk9IU>a$?9-`Y^u)b^LO?nNDu<1ZrQLmXheEe`=P!ROVSgw>f}AG z&AkHH;q~5mg8U3;mQrvQm6qNc9IGGXc)dV>&)#pKUc$93EX;XeA$^yppW>vz4b`AK z&zx!YIV%~^TM5!Dy>Y!9Ak$v!Q6M^EL5mV48{?rq&GFG!(OLVs-D4AO_mP|I=YvSm zA|WX;FJ3LP^?El)w|k$D-et>fAwp8gMy{r(|F{~%b!O!PoxJ21^&{@IY|pwSg|-|y z#q&7Vf|AfAkFgBoS<%!hfoB$G3_!X9iMD)_&W6So?tu%tC2WC0e)=9Pc`mQf5 zFTaoUdgkvLaBi`_-qKXnI+ac*(q1^!R)CR4U`B-ew_@?}idDK9H$t966uW&-o+3WA zCGF+`zww8|?V`t+1P&MG#yZ57ik*2FxnCyPoKYr|I4Y`;J;pcewACT*eZ=I~P#KTR zlx4LIGLSK_g`f4-=8zGuiHb2Sj59EFMYcA?h4;)TYk(`*TfO9KOHPc zcRrSXDqO5EFCE}7D6iC{>gOonx6k9GUB&i0Z=zNaXxHd0V){5bxH2{W+b^!+y865lOp-h z>up`dH^>MC6v%9D%sgdKsHgWg7_c49gRfPA!_g~x;oN=M$4P6Wh5Lj|2lhm3zAidE zl{fJDOxy>tEw;Rb^-qsTzrFgnI;DP|fI3G|#X^mLtA0S%By+iJR80x*RuYas<@{}cPY0>MGY}ebY8I?Q_W8x*_L`DZCwylEnS7mp)Gt2cfcXu0C zH-S$^2Xk^p#dzvp5ux;ZjhAWT@~~@EGT@Edzef;QQ+B8VY?k3+< zS#GIQr$60Id}z2+*+~?;`ubqlfH%QOVzwaR(^eiLmRmwn4cO|A36VU#dTiRyn?qOU zY2ATi2kRMK8m+Ba9*9*WOPzV}q@g1~tLnpmxK_f=v#)N-Ju#uxIcjDWMK6)4BoGmu zG*42Q_|HM%udqcfFCqboVGGEqd*DD%E+O*tv5b42BAG$+%SC2jJ& zb3BZZbT7v0cBz?uJw3r?zM=1FwT`bXO?4X{88yhSyR;o;x}IigI6t1MzTR*B zo>?P>oeZ$VVrfD^Yd$pOp&{dKow*e-#aW&*;eiEjIxbc>kRxbO;#Et$|un@-PR)|2+gCVto$ z*rYFL9M^;mT@vW#+Irz(Ul0X>8J`+8nMB1(SAV2!eNX@63+JxItQm3crXW_+m7Td7 zxBay0iS*i&7lq6^l{=o;#UAc^bHkZNM@Q#%XXhi$6Rta^dUDpwGbWC5s1Wo44J>!b zTfNi7px%0Wb=SaKIvvk2$$}2^Bf6Xq`<|J94bUYRiF*I6KipDYRh8t5Ubf}YE3)}B zV`Pr@_OxzAWedNBmkytoHgFdZR4qxf(36P#E$=}8$f>4K%k(aNL35kVS9|v?h>XgT zcL~ZUhOQ405eN_w@R?cgDcH)>>|3rXQQTuwT2@MW>t199ugKPmmO+t+i1p`)ifPB$ z)En9Z_P4O}63{taseNhtq$vKm07IhX($Ws5-L}%2G}S%Eq)SJyJ-lw_7hGt%c)l|g zBVS~_J;uG{L!GYYlh6@Y49kJwS9)C4?f$=ErE|Hd4TI5zPmf%<#lQqVR82ZmpiUBr7opDw^tfi!4i== zoIENZLuxiKc+PZ5#X|#V*GNzL3q_A-l6o><{klt+mzFN3Xsd;-AjAN#QSwnz0o!QdnGUl|zEo{__4{gAp$kR+g*uA6@obUYZa(d-RxF%l(Q*rZdU5fbomdE!UV| z-)ipKKynqOE=WUEUGJ&Mc!BHnQw5{fuT?Jxo<6kAswmaE?A7(Thn!?XyUp9(ILD9E z%h0!w5cqFB1h5+mDZJik_V#uYQ6*4Ow94!*+T2ctOB$%Xb(MCN=P?(s;8=@^jh$OZewFx8yTPY5#`=(<6J{=a~fgh zdx&2aaOX?jXt*G?MaecODd}8WSHsJapduT6J9~S3|1;ED_fYwFFLv*Jy?mv2HK&rf zH*x!EwvuFn=E9xS!E@(E?x91+$1W9d5y)$49jN7;Ke9%$M(N{sp~{b$?(#Zm==P}A z#+axObAg$V3G^CA+A4vYumKsZz4er)U8xa~_PHBnDyM=Io?fLSBaY~uuGG=3VK(vB zT)(ouP3b&=ie+H=AdzL!k@7cYGy-E^Csb9{pS3S^&DU}rw!cYNyM>ZtKZ+YWp0^fl z+MB35-l@dLso1X{gSHAYD=BIbG z*Paty&k##}Xng4?^#fDC`M6IP@+m2Kp4roS?@mfeG7P7)elnuS$tUir#X&*XDdVZJ z?moVqM>6;9_;vcJqw%8>f_sFObaZuflT%WdOjr7C0!Ua8Rg3)S9Vi4Fhpc79Jd~a_ zMVlaR#7#!Y1GdjSzC^&q&x-!yet*{B$QAvmLUW7tUAK!r6;I``_B!|top7wpYM=_V zcP+Sa`l)d}7jp{1O)^*43zV!?@hW=mlZUCUv3kEfccSmPnwn*Ch^qkgOOb+Y?>+aC z=X7fkZ|NaO(|OUD%)Qn8>;3xnp8Cd?hTX3RD(C{Nx*)c*OFI?ER;&J0TwCded`126S(kxvt=0Bdz3pq7IXT7# ztHUy$_SIW4L)={}6}8pJ8s}t^l}I?Q;hK4S2Rki*s zWLsCSa+XldsJydO8oxQ@O(@Ao&38Tj?w;~YUs2^!vg;wVCoZ19AZs!<(|g>Z?;~D)K*7A>Ylzj*; zi#J7Nix<-Qk8m6)5u)1r{Cu3L`m)F&1q#6^w79W!8#VPV!n@9O3>C*;WP9YWpEr?s zsFe3`@oA7SOL(L}%kv?cE%Q>P8GKK(hCP%-ZMUF!wsv%Myt&&y(;$9|owJiG1`rK)GOub(2BTR`m0^X07OiCfkyNkv>tS{k8hrsg+DcMg`< z-{3!RStvXGoFJ8vYs}7zE8@&Df`oR;53q>>XG0hAyIf+hS;~U84;Nl#gaiu4svlo} zxVAq0@;5;l{ZPI;?}ly)^H38A({8Ok<|ucqXVmnC&I)%`bj2~rc^jVNJ}moIsi}|H z?7I|gq;co^3lzVFjbF;sGP2~o1&c;fo zQsmy@m9xEbAx+&)sX}bMTV#FTl{687D{jZqyvLc+OhfagbJg5)J(~Bio+jY6Y)c{C zD|yqUHGFk#?Xcc<|Eui#X9}Vtf`lUoh>HmbpY2biFQ=+N#??4nybI2Tej#g^+?yl2 z^N^4C*;EQeom$|P5Dn?G+Jd6O%-DFy8BeD4%C$E(DtU+9Sh?*HS5sXdezq9=UHF|& zYU-~D4p=jxi7YTIOfF@|)|<2En$CS*D?L>UtlRxAA+7gJ7uK}SZ#{tG6Q`Ve?Z(~9 ztyG&|QIr&97I|9r28Zu9!h5x%XIUi<{N{O^WQ63ZJ00VO|;zx zPQ)83?{{)Y&C6km98J+&7t}j+td1H#JfJJK6_qZwr0c$#Y9$w9*_#i%KdkI*WEx)L z3qiL&c4%K|S}br%)meRMa6Uz2x|Otn!ucaTSya^CLkHB_uhp3xzuLoBQ6}mcJ>61wva_Z_gW+-i%!i@_oac!jOSYhEkJ&{r zPdsQ{BUD{(&{#ne2;Wx~971%77)6GR&-c>OI*3hVm6*hJt-7sm7a6)J;MIFpf9JfT z00UYh!%%FZZP+AQi%Mz_wQ$ZcgXZ**x(Q_n+~Q z!}xhUvMQE)Jv{2AchCJ<|H`c5flKEpG`y~^CE0wOn`eIZJV!PqI^{Pke{sEljjLBk z$iz^j(VW}5y`c3U+Un~px1VD|--6C~Pk+HlTlXg`*K&nf zD9gX_4jp41+YzEsC|9n&TcV3cTQup&%(^%iws?=wA!}A!zE8&iEn2PNTo~JG4-IVm zr}92(Zn0=C>G@B7xeqFLAMD>REibP{SyW`v$NRQTQHZx>Fi*V2!01udN9wlbEm6;Q z#K#66lcPPq_%5MdW4~zZlI&@{E2aVGlrgsxCY#-N>zhir^~MRBCi(6UlFli5S$lc9 zhmFsif{^K$3O3TK+&`hd=wlAw4g(_-)BK$UeD4bO|7Lk_e+Oo@*^;e8Ad_u7hquqk zn5eM+j8T8XW84Y}cg*>S%p8p;6g{L9l*cbhbv`;@x!dfdQJPM>a@vSb#@H7%l-JoI z*2|aQ6$H7&zvV_ps*Em@Qn`yimlevQIa$|4oDq4tq$x04E~6pSaM&_&H%mmAzieoq zu)Slp_w-&OdRKyGh2`jmUdH{mgjJ<3#WTD_XyZs3_t~^2($s#LE%j>@C2ev@<<1{p z4k@zUQroP=SAQy|*y^y>MLDvdKKCtmMR$=Ax9r?WF)_~dYK~*y=?4Z0C~gd2!a9r*C0CHy7iH!0GnG?|YDwi6Y`Te(%Wh zqIf1JP>*$Onp!8W zIGIZnJo1vKybt*(Io=vKnd!GN^_wG?0CokV{%vwA`LsS4FbQRYmx!A4;$!oqGQxCN z9amTB@A*$y2yhr66+=yFxr$7?X7ryQLR)g%^K#!PcxnB}xak)59r4GAK%k?@+%jWz z>@gJSiA%gu5EhmyPhGAgKxo1!}|Ldd-?u(Rv136APbb);ys zW)q$#HPg>q?>^e9(Wxh=udm;h$iY2yLfK7tj%067$frs^Eh&uPDP0QR37Z<-w-u)q z(c{ZwO!N19$sIk2=`B9dJ6-8$G|oShGzX_p}1N$IVm_bUgr9PH)>poTQRA_J0cCyh)wi)y;nNw+Q&%pHP0nt4>d9KpV|M;x7Wk9WYG^^V zGQsET59cIlS+T=vORAO$B0D~c6vXbO7ksgE*uYV+CTO=)w0ju=_uefh_K`Mj=eIll z^wD-q4&5o0%&b!uSZwJ`N5W18oT$vDOVjM#LH+19Q(zcs zCeqQ=XnX{S8LEnk!Btzh>9wWp=!;x4Ex7Lu_qfh%BlG3F=HS(Sno_WM0mJp~-F`Xo z))k_cE;Q}eR%l2fb8ER>JE**}D9p87HKXRRDL!Dt+51^EIG7Z8?;Sr{XAq{i?pOsPBHAP6d85=xkhZ} z9lE`h0)<^;M&_7&E@)&{jxX-IPEQs&Q8yKnz3m$D7x%7;5QqBu`(^|KLuQ;y_J-9v zc#Lm9`0dzdky#9}h}4<4VSDM6?-y7yrtXY9)X31eq*Nxa^^hMqZY9?wuEz79j zd**U+a`glcH6@u&sbWG9hIGe-z^*sj9%`w+aI!yqaqac%*Vs>&b_eYnP3??RNEA!o zZT!VFX*g^0Gw0x*J*a+aTg&rHeu$v;zza=}sKVQk#;iPM5#$lI7I$)$jho5{uMx5z zh&M->-64B(rxB zRu;I^g9QISnyxY|s_*OG83q`7=n&~fx}{4(5TsF3Qjm}aiJ?J|loTleagaukE|u<* zZU&If1daAe7SSaJ!h}I_FC(dRLH<_;c08d6Yx6HLp=pZGp!skAs^3OgN$!-KkFimy0r zl+gVNMn(}qrvl}t0V82GzD8SGGJ+kZ!zL&z zf?dKb=+j!5hgu@38eAWnV{6RUPn;wJjZLm;xv}&8d|Ev_MO9EbjlJoUFcsCGt5N;I z18ER%UU|_lvXQ+w+&YeQFR}h3#jl88@DDaty7&p^Lr#_@%<|_?*e$ITh3WL-+PNR? z7s5jIu%tK-kb`=4ZKL|I3kPJO2BRmiiuaa3Kbz3uAd3}xG|Gn=i(d5}q7I@3+OF25 z*F9v90R4&S4*C0+HA1;ZKF$nlLx1m0i|ot!8uvoP z%4>LETbjQp=O*U*9nqfSo@QM9-mUTvw(&vEa1o_n@r=O`a!M}R>G1QsxF*2g;b1SE zr~fw_9u2cAY|l%q+-7(~C{Z6Evs5SaX~Il&=0SQHUeTpz36*sC`|*%QI~EH3NUiP| zj4;U=m&!!xjUs&qU&F%q&${N@FTr_?uN(3v>;*1(>aIN-zA6VvQNz+Z0=s^4|;X4=}d!K8XVB;iI>AF4nz~8AVrS|*`W*SmoyWb|7w|%?&XOX zA~dTWk(U`)x`v#7S~{ZwIwO0JX+w_R^HxAHg0{2E`%vH~jJCm&zuWYRhXhP-){$^g zE4gKJY9$<=`DtBw`8IS3icqzkKk#j3(&m-^w!ooY9lIg^RufN8jNGdrwSJ-A18Gd` z*uPk&+3_Xi){xksA7sndQMYjZH#IH{p&9Da2V8M=YnmQoGltY`Ud594e5v-ATzuC^ z=Pm?W$?7+{Ajl%ye0|;L2nv?3XgTSh#|rI0MEXI7X@I4xKN3sROJmi^FR7quJmN~4 zp$ggiI?Hes7Gh>XUDK|+?nHJ!xAwW6k{jta5`|pe=k0P-eUwSrmi)>b5N6ZP>_(Hz zBY|Mj&mV?HcA^rzrt$+XErnbkJ<64hB>!D%k~peFH9QgOspZho zq~aTu^2FcWfGWSH!#gg;=#sJF#oP45<@50|$2YkIxrRZWcFgj%Q+?P+IdmDrmn_9D zp8PQUNcXAfa<|k_I|l@I4k>Uq%PH^g;{0;nFlU~*{h-WWXw?@Nl>DS|l1QCxEk7O( zygEan6P(9Nrx9GECuYIe(9ai22A=};wXI`4Tw68&?mG$JA>IlYc|1%LpDz`EjhHKB zaahy%HYsL$aBcWl;6&c$H~9h$^zLJUTGF2lf{@f-I4lQy^cyy2 z4$bnEBMdMABk5&jWu4uc&ZqwYSHmghU(8QdQWH4Ll2yIIW^?9c1`Nqrmlwb=sc z2k2H$n>o@!;kqU{Um6>;%skJh+^|P+6kd1%SEJE#b#28z&LwIrIsLZ{ca`uJJA6`Y zV@W!(Qv$##k3fAzG&i010SeF`8Yu-I-wSF{+Y4A0SIh0%fPzKzjPe6NT4xpcZF1I2 zz@BZOMdy0%mM?v7#M7K;x(Z7nuH-;^fS_JBVwc5^`N9zBp< z^gc6ge_Z~l$@;Cx=9-TQhzkcCSq*xoqi94>yr;E+EE_>I$b+=OzcyY_rK|q zY4r{Bnn$y7Z+P_kHjN zE=-mTR&t$^`K8Qba<3sCcr}>%8-uef$|7!lFEJWgkXuB)dq>==hy9p`mW&zNE8Nuc zb?%uAs*D@U47uO|ZU02ebVBzbhQ%IE4x#z^du(xWF<^p7!YrD{JZuU8_P6%}eYq%V zZi`4?RNox>bk?uT3*Mk)wWbYWm@GpzzI(6|L0l zpI>l~gWnZtQU3tMkHfzG)G(;Bq?zUGXH3q-Q0m6DgvX#rI(QKDC4=!J%i!Z|F=uh`s1rt{ zUT%s0gc&N^no@ z?fq%u=Q>_?JahS;g;1ZY*RbYZ+uu_$&aGinS8Xs;oNcLbH=$O*D!D=j`Yzb;cwzj7 z!a%R%K=s!=DVoOpAs0xPROAvjwQC@N1d8d0Q~VoWcZ<`OBIu?o&EFBhp8;Q=E6!HE z2Ufxv?^b>jefW@Jcb~{&IQuK>m%io$Rw;FdOQWaX6oH>rE5}^$-@kiD7{+CDoUI+w z@^~iY7~;aYgq04P9!~yyH>IFpLKX2^iOu`Sks{EQVS148YEtxjmg&*8e@qcE)YU;i zxc+At8^p0Aabr4?{=m!n(n-*lwYaXo$obW!4Ol8*5cenYB(jXfv*z{SQ_A5=j z{ediUu(Lf?J_Sl*Nw2oMCQ9&6`;}o*7@3j7bsHT{*x?-?WEoYT{cz&3Y{D!f3d&}u z_uiJQOSEiyp~#?6SKlpUpxW4Cr+MRjS(g&*g&CGR0zG@#XdX4b82kFk5@sLL#rD2z zaBa1psW2zO%2dwsd6fph=O!n;;tIK{9`T-MswNxC$C(^}{OkAEREYQ`WwOCtH1>H{ zKZaik6*I#S9fyZ+Ukr|u2ve-V%N!0{AWT=wv=$GNL{`V|~%rOYEv zQwTs#?0DK=8ChF)dgYRa!dGPcuC~WAFfN>g4u1N8Eem)qC2xiE8^1ZND_uyrSiL^+5HE5Njr6EB4CkOA3gpQX>5bq&G_Cpc> zZ9#j+tLpNg;!u$+NaF92%%65lN19~WU+w8|a)VqGGzSOYxAt;}=Cyse?mA32PSv-C zKyo})Ua*{O4Si|=LqDb-djL#gVq%M!%%#s?^De(cCWl;~5Bv39MgWKsa0&M_*^8&< z*hPSy6()vR396#k;PQjONcwvnM8Sh(Hx@oHQ8NH2R(#(S!(lkd)nLEH9+eyo#y5z-1;f4S0Er2VEO zIB#T@y_33#n>36{Bc+%3osx!r-j`p=>d|+ErmITetpQRGJD86wk)dHV;ww@Z;Nv2v zFd+M1(^#Rv5njn=x90u%;v|F=x%Da*vtW(B{QZN-+QT zc!k|dR`+?g!t+D<=#}|pCyDaGyrfM%o6qwOs%E ztU$CTZ^pa{IvWnP)!yAAhKGmKxKbbJk^%quHKZu;>;FD~H=Fv_h&hb6x z-MX|zT_y`{MADm$cJ~o{uNm;q=9c0?c)I$pkUk7gX8jeKDguV9>rec{LRndu+N{!j z_~n0~A*Hhvt1I(^#D*ffM2Ri+)pp;06pK)w8uxB%An$|zT|>v~0eQ9U&+T^er4AiL zFhfjC7_G5}xFkIwBAj1GdGcSH6_y=?6Um<~1ISpk$1tOj%-(!3} z5AdTaUkyGJUtuRF_ZxGeO;QJ`;FmBBklAWuN9i1YQ&v+~e_pETXkJrBW`$jF*+wuF zau;n?0E@7uGA@XF82(%<1levyNHjA{abBe^?OD%J#QjP;qRWW>=!^n-}8{*fpsdZHYuOR?sa?iy*@^Mo*3ex|a64DuV6%E?Ps zjK-wQ=)1}D_qbg6fU|LV6B`W_G9lKt`d+*x0!O!{p7u-q4ao%T%ZNrCxRJf~o@2*&o5e^=#`U$-fI<%%fhX3`?p9MQy_63#;juL+5* zx0;s);#=4tEOe1#LZ+uMmn@j5VC=ZE+Fg^K3a!oS-#_8kz7yd7zL!n$e)=|FntZyW z&Z}70)D3~r$%U3F_`mP7#}5#k|=EuN3;tPY6YEI zn23l}D7hx&Aa-{1HYr_1Iz$9vl2gm_>;qc1k@K%lzd%TI@gZ**I*_N<7~jl4YX{sK zCqRJ+0?yFWd^*Wi7JRN_`4NGzLV*8Wy>-=krm3hAW;TOz{t_%9UU;p8;<6*ooEp?T z@}o~(zM}GzvG^3rK*$ouz+FF`y3<$c{S(DvTRk=If2} zW}4@=)Ksv`LSpOHhJz$=iy;h&_%JJbB!6la$Ej{qK;HYHwE4JhMB`Oe25!r0p{VjM;)fxh2IJaSjl3&3f0$PGq(A0(-r&2 zj@kQYr2Edor?QeFH!H<-E4gg~g>*YE1ei1~t~$f_6N0VG330vFD5@fpkaZ{zFvJ-i zqS+x4&tZnx=eM17bWA@)!&O?4FKYy<_b9Mct0?z+?IiCx>n7#tGG_ zmTw+NS~rw2`G@!Dz?Z4<5Qs0ZPBQRa)Vzh2AS~t(As=d_{YBsJxGfPRPu8xs?JRRZ zZbk)FWZFu1X5#^nM%d*1VdC(}h(^lB*hBkI(li@5P^nFR`RjykpY~{F=8%#1lmj|> za^*&Zzz`qbgS${bJ7b^c&8DHre7kPg$*fKa9x9mvdut^rCYQd*+LYr&suvYkl(3zu z6RM*dvlHQ?wJkz19;eA-Q3zY);b@D1njYYm^qlMG%*OzR1PcQZnhiU-oq zWiGo2mOlO&82~E?!v2;boJ#opQG>&khn731Y!O8ZA!Of|f?bD(ge!XpeE6Nv-=>mE zHHSFDV>t6K&z0qUz^92QGCel%{>jkM;!yw>Z@NIg9R@Osvt2T(ob-+j?!H`#O0ps* zve}YGNB)t&Qr8|1f3PI^Ui!$%KwaZS*5KumPh$#`6Vx@GJ++!A*r)DFF zgEKOG7PhF$1&a$PNuU=qt}q|LWBxumjk_T1B1P^0TQP|>?zITU0p?ZTAQ1hT=GO_R z!^Pe?IM0o!xUK``E6(fwj*=avXQik=77_s)JY04o8+gT_Ibwd>J}tJ%g`La>)5d;I zVWO{}8FFMDf4_+oyw*Y2bNO&SH;j-!TH1@KJTi+dVQRX6t&$grut$;w%(y99On)At zxb+5)OA0`?=01U`~9{nA` z_bk1=?g%NI9C=%k67myX$YoVSC?p|Z|BP56mF*OBU4beVQ?CaGn=(Hxna!n!`)| zDn|y-*<<%RwFEoUC{4JG&zy8nK%j*WEalo&0ok7y6wxUB!X&(#nC|5EKD45u!bd_! zp_5XLCApX(QH@-wgNJr*AZ`nb;wQfU9J&&&N%re+W)%nLH?>z*-j|lSPx6^id#5z$ zJ9N0zW25G&l5eD_Pj2546|zb1$ri4Kw-^J8e5}qA=9vX7w}^R^;DS*{xG3tXFb#th1Av zGnmeX=be2Rk-;aPY!`b2)ACxRA%8lU23J>&izSr#NfcJFO65cg1x?rD$H1MwaS$ym zMO0YM2!T64#zmf;ojqrTgnWbmTgQG)v^LximUzkzsN;YL5q1-(plR46-j$Nr+4Ua2 zC){b6@QLwkc-Tf;cqVH2(&;Oubvjyoi4X~wPc4hg?_ZA@st(%nslOi$(jPlyLwQ(IrA$!GAw zvc$7w4BxR*;Hv^xNg3oxB!Gpg;XK~TE_jgIkMri|CZQxb_5a-O3c}p>QBjeDG~d3W zjc~wYmU5wgYXv4Z{7%MQOUsOMO+lopoeKgCPcSIqN7kK1azzSiV^+R{?x8ei#PT0DaOCr(V>~{pICi$!#xraM3vniT8AT)FQ$>~s z@(L@Lw+~iQC_Z8V11zMNsq_$7UF_)5AbO-GK}JWG`wjZD(Q_t1^|=B&4ryZC-<`Ky zWUPB;xNwi4t%Z8(`G&b*Z{qU@5msBcm-DU&I@pIf%9p}YV7q_N$IJTo)-N*KE~R}^ zlj#V(y92J=8fo?3Nh=-RlxNE}{a51GF}q;9n?^;3_`bJVRpZcHkW`(k=(?2tbC!nY zH>+|prI8P-)chwso^7eFZ3IAYp1{hnUsx{zYM_z4OyUi6poU(n2cY<8o$DOF!D?VF z2ZzH8d-LN#BA#8@d0+8mF=4FO4SQ3pi;i_P3I;XhDI=P2l4Q2baOKR9y<@uBW$NaJ z5gtQR$sqn3+uB|9b@*HsxS^d^JMStyJ5sgBwdo&zpDK0&GH)n?VW0Da!{8RzOdA#7+hs*1og{F7WHL z>Wbu-Q|cKbX)kG*5bw7u^HlbB9Gq+MalpC(M$=o>+FDjOZHFZu;*j`I#cj33*|)gJ zl?c`S?byWE@;c5A@8@LhAgrIguYA7j<8SDSX%pdu7mL9am_|F;G=`Xq6rL)5{t+jOsTwfTlY%G)jvHMEniFp{7#Z3fRxwYF#GdL#n%hK-~ zM~~jj_j=Pp?7tNg%h#3Je|R1(93eAN7nfGK4AGD)dQj!K3TB?2sP-6O&UZnGk zltXA00(|9OF)@$x+8{evsQ65-fEB91g$?|o1Ol_E((PtTDE+L_CtXdOg;ylfP7n1p znFoZS#e#o0BLw+8Ec^gHCcA_L7XKC9dWBzQVp&kdy;&sCc9b&TpPd^CqO-YhdUxnc zwNPGa#Cr296;m)|FoY2s2|YM3SBldx*q8yxpWb_9lfuSTjLqxs>aJT*wW$Vd0nk0s zI|U{fX3-FcC|lFv?`se)lg-acd6nrK*}yD$eteh^9t7Oir=iF+90V3jl&sY#`Xc!3 zY;L#ci}N5YY51_=H+s^{XQRos+nhIheixBo1!L;co|k?M7{hQ2Iu^l#8s{IBKlxjR ziow8A3=3kh-ILh8Eq}f1{Kn8pA0HSTlpPez-;hPD}TF_s-Q%zqv^}A!& z26zVAv_h3E9FZAD(hCN_?QgC~HX$f~QfBsQ1gr~w%8SD!c0DvEg!#7-{!XHiu4jWW ziVd!k>@gi5E1(!6&wu-%?RJ$`^PxoY4S>B7{ zX7$T#nnN`wQ?bw3d%C}ih7Pz?%@1qhH#(Iw?~ipxZob4E`r)ObZ@hK2WfPI9+K?1S zvoJf;VfPgorJ>&xFx8mOH_~#Q*ifjgY5G$z{Lz3%cIaTD;;Fq8*RW3- zp5rqlc4u4owE}d6>2Fvq5=i=%IkX7$FN42wRO6?`ABSAwliglWr=QEADFA8SX~9wq zE$tH3Tzr)-L3E;Y-dRgf?ecQ8kPcv1>96BfV(vpypaRR8u!wsF_?+^YAQdadxRFErLyj66ek1%vbTC@TY5GpC$X^_9cDZ za0b6!dk>obTfI)#{xM^NJ%M0~i4X^?geH~+&p_90{&sKpS^Ig;De9-M{lVv&xwI$a znuDt%j=uIjTj{5_sJ3?Epygo4W}j~Qyeg+7Za$}Pkt#SmGMt21-*J?lC>Ojkshy)a z#x4>iH;ob!jo*+Zp+9~4*?*0jE%>c~BavEoo(YVJiGwr#RO*E@fx#}NZvW(BC8g~H zvSLpxAg4|F`Qsv3^!==Num3gfcbHXhSb4?EK$VqA^LpK5EvhG$@^ufJt?2h^*T%1V zJI8dHhM7Io@)~+4@vy`#Vn4zKXnl$$n_}P8*$^oR}4joo)B+1Wtkx{al zF%j~7ha5^g11lO|ZbGJG`An?h+lRh9GLKJ&=_>6(l=UQc^aD1_M!gm_Ip%7q=Z4J% zqoX=SW?6BuLgxk-Qa5c_6uJbR$i9`UR?zIB1XsRXQM~-^CN%}+m4CXnO|&}g5@3A2)`A8M9J!TW>1c-9EAK( zhq5Qn8Q)t4u4;&+(SIa1Ol4f*787Tf7@)bYO~e?LIc!5NzfY}f7#w4%lQBnh(tTCW zY3T^S<^BMMQGA6^#>e&t)GPHG=N<-cF5Ivgv`r#k>+w0UN zW-bVzfs{;a`q?ZxGguhcsQA`N% z^E)A?`u))n;qH81S1MbJwt+?P{{D-g7); zkh}kdHhzUPvm}(1y#$^L`g#2m2IfG1pVU|Z1F4?+6l)j7-YnPLMZZw59OCB`rSVzw zPYL1hd7}QMkP|j?zA%kh|Ya&pSb`A3UP(Vb?gP z#p1TP?7NR&99#(pI^_8)@oWF1MoD}ue_3!S@2AIsjR$pi@AyZ`kQn{g!S(Ux5Q~&Q zm4ewpfyZro1d0GOAxf*c8~+*)YxMJ68&j|Qu)DxAkkIf^2>45=1O+~lRW6h8R_R8= zSznakE$^m@y$#%nzUkEGK2jl*$->e3+9_gsWJauH$j3L5$@(dxi7`TuuGziifxPv zr^_z!95%Pq)#Nl=v5NC=dmD915ciw~?0QLE^s#GsK`U~F^Iy;lNPQt3Jw#1^kIdv4 zJbpV+t^Un!cxWm$zmR+^!r`}YUC<^0rwp~c-z>W$DlRe1c~`?v2gCu9Nrq;Wsz^ET zUvq~6Z{eV~vPh%9?pToT{L3#$0Ui+`Tqw=cm7q56Un6msoiFSo0=1@pp(vE9=uXU{ zan$fbZ&+2M)jDX%_pAD5f zhGjrke@fy41kk!&3WN1)ZNUQJdTagEtVJp1I=q-CxFVDE>K;Yf0wvZPS`&5cnN5Wt z*M7zKqbX>;o{TS}ha)}^kFpPvT%nZ(p)iH2rYnKKFEltU4xd4XJ7o#EC=w#ZDFv+x zL=38rk@>FPnL6>)uS2!l&z6ys3kInkJL^b*LJ$~@f_hS~8Coqye7wR{?{j8P2Hm1d zUMo$AQUYcDfJdX*oFE}g$?TqQ;Y}6Wxa9|sByo}_j=gkB%YJ!;W{u!K3wR_JVB_eA z)E0~NcW(9xFH^(h7*w#jcYYc@Y19#Da^8?$_o@poOl_Qg9D14X=*_T{qh$O=vuow-nT6fDy%u_%#M!5u z&h4E%=IgWFl*)m`DJo=?V$4EeLeFT{`L8`6qx;Q8>kxVQ`K5UIJCDbAyzHL=y%-07 zx2U(${>=uN4jcCn3Jb)YDD(HQ`1cGGCi0>K8w1+ZgXJZDmKqAYm%srW>FAcx(Mj_! z6LUT6g-7e#EpoCN6!w=-X7a+&+Ro0(A+@Hz+O8k|3b`BUMFj`B@KY5#-tJPbm@YXF zJv7_n0H_69Ev82o*@e3E{b~Cp#;b!lDv)fkKT$*Sc_He0$CyTCLNr(V>jW@}0AO*y zQ<_Tb$_M3l^T{TkQ10Heo`g49eDw(dEk2Vj9@73r9t-^}a@1rtqO+|J5 z(TDsd?W4%Zz&A}dcqwT>S@5q?`D{c^uhugTy(4}GiV?mzds=1n&_m-C~t z&VJN^sZ~LmR|#HYGr_)ZV57bNWh1rapS_SfieHDdH~0thi93hW!xT`YO82DNo*YJ=Le?S_OO0&knyG+X}xH0SqAU+1Xjlh*tzq!29vi zH<|1AeWp&`m4QC3f%2Kbm`?Mdnc#Z|%Qac-Mrv$C4mPMn%bw70tMT3um zVir6+hlX9Yn&l&!90X!!R->z&wO=jY;W{5E@hyOop^p!m77?FU;zqVNz@w7k3yXIB zHCo<_RpflJPs=iHz?yayAB8s1OI>cEm`8&oNq`VwIOa=J!yG#_K=~azwpv~sN+0&3 z=)RcCo+fG&3V}(wU^9QjH=q0f-|edGuJyue3O+M0d*`MtXTaorh(%Bn8|m8NJDuft z-#jw4w;-&8B947`Q2BQxu~!(=q5o<-U(B98z`QNxQwRA*E>nOUj1L@+yDAGRYNgJ8 zWITnT^g_Sdl}LjyyKU|GiV*(jJC}kXV6~%VKU&D_K1+KY{Tu42F`k&F`63@R3eCw2=u5ZTKU%@m913vxf>O2jOZr_xpNpxAiJQm|VpW;yzza+&xW z_lr~;K~4_R+dmD+N6YM?!1zA~<=p}`C!Ygt^gkU~(}7cr>K2J$Bz!m7v>TBYk;So@ zBOO6AF?>&#HBZ~qXJ;dh*sl}QA6W&<&tWcOKS!au50%nST%EJDum6!ThPnAhr*KK;+Ujj-JEMjF~l zt?H-?jM9d0zmfRV+;rFEQb-|-t{bFw_q%PsdeIiG@c6U6erhT?P}dFaI9P1%@oZf1 z^53g|k4&cO4xYj%J&`Yak3US~$fWRiSn8#?mj1SzI{+)eE8sfHZKE?sBXPIyh9#I) zzx=o-HvD~diSE-({G52rhWrJrwab^NFv|twTIaE&+?Qil zs7wC$qfF#rsZ>Ra>V+e0a7u|&Le3{WTBWQb<9-77>)i;kRp~4(`yNituRKCzb>RdzF+AldnEVuH4kAooSu-S<-$w}x{6p41>>E4U^~xI z-o{bDYbi4>Jgz6nKfXW2{-Bc3H^YuXX6Q<^i?=g?yELU;Z@ZSengi^H6!2kq=4(4Sy?nfIZTxKdkxb z=%dlD5sH>-0whSD*dwMLH%kb33IjlvEsuAHXx0FPYij$MTI3hWvFFsfuJ|-jc-j-7 zKP$4QUMy-|TGsS|)irR<+AOLQuCqZACIcd~=S+lHdQU}I4g+zUP}kAh=DzaTs5_m6 ztRv^-z30tl8p(jTdzCBbd;ePxpOyxnlPn>+CusT^aZk`^u$)%We222cz1^INg�x!4 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 diff --git a/Net/Demos/Old/TestCrossSocket/TestCrossSocket.res b/Net/Demos/Old/TestCrossSocket/TestCrossSocket.res deleted file mode 100644 index f1a190ace86b1a64d3156ca0928779921302230a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59556 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 Date: Mon, 8 Jun 2026 12:40:17 +0100 Subject: [PATCH 09/15] chore(cnpack): re-sync vendored CnPack subset from updated cnvcl Foundation units moved CnPack/Crypto -> CnPack/Common (CnConsts, CnFloat); added CnStrings, CnWideStrings, CnSM4 to match the current cnvcl layout. Keeps the boss-installable transitive closure complete (CnPack.inc + 17 units). --- CnPack/{Crypto => Common}/CnConsts.pas | 502 +- CnPack/{Crypto => Common}/CnFloat.pas | 2882 +++-- CnPack/Common/CnStrings.pas | 2927 +++++ CnPack/Common/CnWideStrings.pas | 2215 ++++ CnPack/Crypto/CnAES.pas | 15332 ++++++++++++----------- CnPack/Crypto/CnBase64.pas | 1617 ++- CnPack/Crypto/CnDES.pas | 3946 +++--- CnPack/Crypto/CnKDF.pas | 1611 ++- CnPack/Crypto/CnMD5.pas | 1792 +-- CnPack/Crypto/CnNative.pas | 10402 +++++++-------- CnPack/Crypto/CnPemUtils.pas | 2551 ++-- CnPack/Crypto/CnRandom.pas | 989 +- CnPack/Crypto/CnSHA1.pas | 1494 +-- CnPack/Crypto/CnSHA2.pas | 5631 +++++---- CnPack/Crypto/CnSHA3.pas | 5617 +++++---- CnPack/Crypto/CnSM3.pas | 1671 +-- CnPack/Crypto/CnSM4.pas | 2202 ++++ 17 files changed, 36856 insertions(+), 26525 deletions(-) rename CnPack/{Crypto => Common}/CnConsts.pas (93%) rename CnPack/{Crypto => Common}/CnFloat.pas (73%) create mode 100644 CnPack/Common/CnStrings.pas create mode 100644 CnPack/Common/CnWideStrings.pas create mode 100644 CnPack/Crypto/CnSM4.pas diff --git a/CnPack/Crypto/CnConsts.pas b/CnPack/Common/CnConsts.pas similarity index 93% rename from CnPack/Crypto/CnConsts.pas rename to CnPack/Common/CnConsts.pas index f4f50aa..792eb93 100644 --- a/CnPack/Crypto/CnConsts.pas +++ b/CnPack/Common/CnConsts.pas @@ -1,250 +1,252 @@ -{******************************************************************************} -{ CnPack For Delphi/C++Builder } -{ йԼĿԴ } -{ (C)Copyright 2001-2025 CnPack } -{ ------------------------------------ } -{ } -{ ǿԴ CnPack ķЭ } -{ ĺ·һ } -{ } -{ һĿϣãûκεû } -{ ʺضĿĶĵϸ CnPack Э顣 } -{ } -{ ӦѾͿһյһ CnPack Эĸ } -{ ûУɷǵվ } -{ } -{ վַhttps://www.cnpack.org } -{ ʼmaster@cnpack.org } -{ } -{******************************************************************************} - -unit CnConsts; -{* |

-================================================================================
-* ƣ
-* ԪƣԴַ嵥Ԫ
-* ԪߣCnPack 
-*     ע
-* ƽ̨PWin98SE + Delphi 5.0
-* ݲԣPWin9X/2000/XP + Delphi 5/6
-*   õԪеַϱػʽ
-* ޸ļ¼2005.12.24 V1.0
-*                ԪֲӢַ
-================================================================================
-|
} - -interface - -{$I CnPack.inc} - -const - ECN_OK = 0; // OK޴ - - ECN_FILE_NOT_FOUND = $10; // ļ - - ECN_CUSTOM_ERROR_BASE = $1000; // 趨Ĵʼֵ - -//============================================================================== -// Strings DO NOT Localize: -//============================================================================== - -resourcestring - - // CnPack Reg Path - SCnPackRegPath = '\Software\CnPack'; - - // Tools Reg Path - SCnPackToolRegPath = 'CnTools'; - -//============================================================================== -// Strings to be Localized: -//============================================================================== - - -var - // Common Information - SCnInformation: string = 'Information'; - SCnWarning: string = 'Warning'; - SCnError: string = 'Error'; - SCnEnabled: string = 'Enabled'; - SCnDisabled: string = 'Disabled'; - SCnMsgDlgOK: string = '&OK'; - SCnMsgDlgCancel: string = '&Cancel'; - SCnMsgDlgYes: string = '&Yes'; - SCnMsgDlgNo: string = '&No'; - SCnMsgDlgYesToAll: string = 'Yes to &All'; - SCnMsgDlgNoToAll: string = 'No to A&ll'; - SCnVersion: string = 'Version'; - SCnNeedAdmin: string = 'Maybe Need Administrator.'; - -const - // CnPack Information - SCnPackAbout = 'CnPack'; - SCnPackVer = 'Ver 0.1.5.2'; - SCnPackStr = SCnPackAbout + ' ' + SCnPackVer; - SCnPackUrl = 'https://www.cnpack.org'; - SCnPackBbsUrl = 'https://bbs.cnpack.org'; - SCnPackNewsUrl = 'news://news.cnpack.org'; - SCnPackSourceUrl = 'https://github.com/cnpack'; - SCnPackEmail = 'master@cnpack.org'; - SCnPackBugEmail = 'bugs@cnpack.org'; - SCnPackSuggestionsEmail = 'suggestions@cnpack.org'; - - SCnPackDonationUrl = 'https://www.cnpack.org/foundation.php'; - SCnPackDonationUrlSF = 'http://sourceforge.net/donate/index.php?group_id=110999'; - SCnPackGroup = 'CnPack Team'; - SCnPackCopyright = '(C)Copyright 2001-2025 ' + SCnPackGroup; - - // CnPropEditors - SCopyrightFmtStr = - SCnPackStr + #13#10#13#10 + - 'Component Name: %s' + #13#10 + - 'Author: %s(%s)' + #13#10 + - 'Comment: %s' + #13#10 + - 'HomePage: ' + SCnPackUrl + #13#10 + - 'Email: ' + SCnPackEmail + #13#10#13#10 + - SCnPackCopyright; - -resourcestring - - // Component Palette Name - SCnNonVisualPalette = 'CnPack Tools'; - SCnGraphicPalette = 'CnPack VCL'; - SCnNetPalette = 'CnPack Net'; - SCnDatabasePalette = 'CnPack DB'; - SCnReportPalette = 'CnPack Report'; - - // CnPack Developers Added from Last. -var - SCnPack_Team: string = 'CnPack Team'; - SCnPack_Zjy: string = 'Zhou JingYu'; - SCnPack_Shenloqi: string = 'Chinbo'; - SCnPack_xiaolv: string = 'xiaolv'; - SCnPack_Flier: string = 'Flier Lu'; - SCnPack_LiuXiao: string = 'Liu Xiao'; - SCnPack_PanYing: string = 'Pan Ying'; - SCnPack_Hubdog: string = 'Hubdog'; - SCnPack_Wyb_star: string = 'wyb_star'; - SCnPack_Licwing: string = 'Licwing zue'; - SCnPack_Alan: string = 'Alan'; - SCnPack_GuYueChunQiu: string = 'GuYueChunQiu'; - SCnPack_Aimingoo: string = 'Aimingoo'; - SCnPack_QSoft: string = 'QSoft'; - SCnPack_Hospitality: string = 'ZhangJiongXuan (Hospitality)'; - SCnPack_SQuall: string = 'SQUALL'; - SCnPack_Hhha: string = 'Hhha'; - SCnPack_Beta: string = 'beta'; - SCnPack_Leeon: string = 'Leeon'; - SCnPack_SuperYoyoNc: string = 'SuperYoyoNC'; - SCnPack_JohnsonZhong: string = 'Johnson Zhong'; - SCnPack_DragonPC: string = 'Dragon P.C.'; - SCnPack_Kendling: string = 'Kending'; - SCnPack_ccrun: string = 'ccrun'; - SCnPack_Dingbaosheng: string = 'dingbaosheng'; - SCnPack_LuXiaoban: string = 'Zhou Yibo(Lu Xiaoban)'; - SCnPack_Savetime: string = 'savetime'; - SCnPack_solokey: string = 'solokey'; - SCnPack_Bahamut: string = 'Bahamut'; - SCnPack_Sesame: string = 'Sesame'; - SCnPack_BuDeXian: string = 'BuDeXian'; - SCnPack_XiaoXia: string = 'Summer'; - SCnPack_ZiMin: string = 'ZiMin'; - SCnPack_rarnu: string = 'rarnu'; - SCnPack_dejoy: string = 'dejoy'; - SCnPack_Rain: string = 'Rain'; - SCnPack_cnwinds: string = 'cnwinds'; - - // CnCommon - SUnknowError: string = 'Unknow error'; - SErrorCode: string = 'Error code:'; - -const - SCnPack_TeamEmail = 'master@cnpack.org'; - SCnPack_ZjyEmail = 'zjy@cnpack.org'; - SCnPack_ShenloqiEmail = 'Shenloqi@hotmail.com'; - SCnPack_xiaolvEmail = 'xiaolv888@etang.com'; - SCnPack_FlierEmail = 'flier_lu@sina.com'; - SCnPack_LiuXiaoEmail = 'liuxiao@cnpack.org'; - SCnPack_PanYingEmail = 'panying@sina.com'; - SCnPack_HubdogEmail = 'hubdog@263.net'; - SCnPack_Wyb_starMail = 'wyb_star@sina.com'; - SCnPack_LicwingEmail = 'licwing@chinasystemsn.com'; - SCnPack_AlanEmail = 'BeyondStudio@163.com'; - SCnPack_GuYueChunQiuEmail = 'guyuechunqiu@cnpack.org'; - SCnPack_AimingooEmail = 'aim@263.net'; - SCnPack_QSoftEmail = 'hq.com@263.net'; - SCnPack_HospitalityEmail = 'Hospitality_ZJX@msn.com'; - SCnPack_SQuallEmail = 'squall_sa@163.com'; - SCnPack_HhhaEmail = 'Hhha@eyou.com'; - SCnPack_BetaEmail = 'beta@01cn.net'; - SCnPack_LeeonEmail = 'real-like@163.com'; - SCnPack_SuperYoyoNcEmail = 'superyoyonc@sohu.com'; - SCnPack_JohnsonZhongEmail = 'zhongs@tom.com'; - SCnPack_DragonPCEmail = 'dragonpc@21cn.com'; - SCnPack_KendlingEmail = 'kendling@21cn.com'; - SCnPack_ccRunEmail = 'info@ccrun.com'; - SCnPack_DingbaoshengEmail = 'yzdbs@msn.com'; - SCnPack_LuXiaobanEmail = 'zhouyibo2000@sina.com'; - SCnPack_SavetimeEmail = 'savetime2k@hotmail.com'; - SCnPack_solokeyEmail = 'crh611@163.com'; - SCnPack_BahamutEmail = 'fantasyfinal@126.com'; - SCnPack_SesameEmail = 'sesamehch@163.com'; - SCnPack_BuDeXianEmail = 'appleak46@yahoo.com.cn'; - SCnPack_XiaoXiaEmail = 'summercore@163.com'; - SCnPack_ZiMinEmail = '441414288@qq.com'; - SCnPack_rarnuEmail = 'rarnu@cnpack.org'; - SCnPack_dejoyEmail = 'dejoybbs@163.com'; - SCnPack_RainEmail = SCnPack_TeamEmail; // Emailÿ - SCnPack_cnwindsEmail = SCnPack_TeamEmail; - - // CnMemProf - SCnPackMemMgr = 'CnMemProf'; - SMemLeakDlgReport = 'Found %d memory leaks. [There are %d allocated before replace memory manager.]'; - SMemMgrODSReport = 'Get = %d Free = %d Realloc = %d'; - SMemMgrOverflow = 'Memory Manager''s list capability overflow, Please enlarge it!'; - SMemMgrRunTime = '%d hour(s) %d minute(s) %d second(s)'; - SOldAllocMemCount = 'There are %d allocated before replace memory manager.'; - SAppRunTime = 'Application total run time: '; - SMemSpaceCanUse = 'HeapStatus.TotalAddrSpace: %d KB'; - SUncommittedSpace = 'HeapStatus.TotalUncommitted: %d KB'; - SCommittedSpace = 'HeapStatus.TotalCommitted: %d KB'; - SFreeSpace = 'HeapStatus.TotalFree: %d KB'; - SAllocatedSpace = 'HeapStatus.TotalAllocated: %d KB'; - SAllocatedSpacePercent = 'TotalAllocated div TotalAddrSpace: %d%%'; - SFreeSmallSpace = 'HeapStatus.FreeSmall: %d KB'; - SFreeBigSpace = 'HeapStatus.FreeBig: %d KB'; - SUnusedSpace = 'HeapStatus.Unused: %d KB'; - SOverheadSpace = 'HeapStatus.Overhead: %d KB'; - SObjectCountInMemory = 'Objects count in memory: '; - SNoMemLeak = ' No memory leak.'; - SNoName = '(no name)'; - SNotAnObject = ' Not an object'; - SByte = 'Byte'; - SCommaString = ','; - SPeriodString = '.'; - -resourcestring - SCnErrorMapViewOfFile = 'MapViewOfFile Failed. '; - SCnErrorCreateFileMapping = 'CreateFileMapping Failed. '; - -function CnGetLastError: Integer; - -procedure _CnSetLastError(Err: Integer); - -implementation - -threadvar - CnErrorCode: Integer; - -function CnGetLastError: Integer; -begin - Result := CnErrorCode; -end; - -procedure _CnSetLastError(Err: Integer); -begin - CnErrorCode := Err; -end; - -end. - +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnConsts; +{* |
+================================================================================
+* ƣ
+* ԪƣԴַ嵥Ԫ
+* ԪߣCnPack 
+*     ע
+* ƽ̨PWin98SE + Delphi 5.0
+* ݲԣPWin9X/2000/XP + Delphi 5/6
+*   õԪеַϱػʽ
+* ޸ļ¼2005.12.24 V1.0
+*                ԪֲӢַ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +const + ECN_OK = 0; // OK޴ + + ECN_FILE_NOT_FOUND = $10; // ļ + + ECN_CUSTOM_ERROR_BASE = $1000; // 趨Ĵʼֵ + +//============================================================================== +// Strings DO NOT Localize: +//============================================================================== + +resourcestring + + // CnPack Reg Path + SCnPackRegPath = '\Software\CnPack'; + + // Tools Reg Path + SCnPackToolRegPath = 'CnTools'; + +//============================================================================== +// Strings to be Localized: +//============================================================================== + + +var + // Common Information + SCnHint: string = 'Hint'; + SCnInformation: string = 'Information'; + SCnWarning: string = 'Warning'; + SCnError: string = 'Error'; + SCnEnabled: string = 'Enabled'; + SCnDisabled: string = 'Disabled'; + SCnMsgDlgOK: string = '&OK'; + SCnMsgDlgCancel: string = '&Cancel'; + SCnMsgDlgYes: string = '&Yes'; + SCnMsgDlgNo: string = '&No'; + SCnMsgDlgYesToAll: string = 'Yes to &All'; + SCnMsgDlgNoToAll: string = 'No to A&ll'; + SCnVersion: string = 'Version'; + SCnNeedAdmin: string = 'Maybe Need Administrator'; + SCnNotSupport: string = 'Operation Not Supported'; + +const + // CnPack Information + SCnPackAbout = 'CnPack'; + SCnPackVer = 'Ver 0.1.8.0'; + SCnPackStr = SCnPackAbout + ' ' + SCnPackVer; + SCnPackUrl = 'https://www.cnpack.org'; + SCnPackBbsUrl = 'https://bbs.cnpack.org'; + SCnPackNewsUrl = 'news://news.cnpack.org'; + SCnPackSourceUrl = 'https://github.com/cnpack'; + SCnPackEmail = 'master@cnpack.org'; + SCnPackBugEmail = 'bugs@cnpack.org'; + SCnPackSuggestionsEmail = 'suggestions@cnpack.org'; + + SCnPackDonationUrl = 'https://www.cnpack.org/donation.php'; + SCnPackDonationUrlSF = 'http://sourceforge.net/donate/index.php?group_id=110999'; + SCnPackGroup = 'CnPack Team'; + SCnPackCopyright = '(C)Copyright 2001-2026 ' + SCnPackGroup; + + // CnPropEditors + SCopyrightFmtStr = + SCnPackStr + #13#10#13#10 + + 'Component Name: %s' + #13#10 + + 'Author: %s(%s)' + #13#10 + + 'Comment: %s' + #13#10 + + 'HomePage: ' + SCnPackUrl + #13#10 + + 'Email: ' + SCnPackEmail + #13#10#13#10 + + SCnPackCopyright; + +resourcestring + + // Component Palette Name + SCnNonVisualPalette = 'CnPack Tools'; + SCnGraphicPalette = 'CnPack VCL'; + SCnNetPalette = 'CnPack Net'; + SCnDatabasePalette = 'CnPack DB'; + SCnReportPalette = 'CnPack Report'; + + // CnPack Developers Added from Last. +var + SCnPack_Team: string = 'CnPack Team'; + SCnPack_Zjy: string = 'Zhou JingYu'; + SCnPack_Shenloqi: string = 'Chinbo'; + SCnPack_xiaolv: string = 'xiaolv'; + SCnPack_Flier: string = 'Flier Lu'; + SCnPack_LiuXiao: string = 'Liu Xiao'; + SCnPack_PanYing: string = 'Pan Ying'; + SCnPack_Hubdog: string = 'Hubdog'; + SCnPack_Wyb_star: string = 'wyb_star'; + SCnPack_Licwing: string = 'Licwing zue'; + SCnPack_Alan: string = 'Alan'; + SCnPack_GuYueChunQiu: string = 'GuYueChunQiu'; + SCnPack_Aimingoo: string = 'Aimingoo'; + SCnPack_QSoft: string = 'QSoft'; + SCnPack_Hospitality: string = 'ZhangJiongXuan (Hospitality)'; + SCnPack_SQuall: string = 'SQUALL'; + SCnPack_Hhha: string = 'Hhha'; + SCnPack_Beta: string = 'beta'; + SCnPack_Leeon: string = 'Leeon'; + SCnPack_SuperYoyoNc: string = 'SuperYoyoNC'; + SCnPack_JohnsonZhong: string = 'Johnson Zhong'; + SCnPack_DragonPC: string = 'Dragon P.C.'; + SCnPack_Kendling: string = 'Kending'; + SCnPack_ccrun: string = 'ccrun'; + SCnPack_Dingbaosheng: string = 'dingbaosheng'; + SCnPack_LuXiaoban: string = 'Zhou Yibo(Lu Xiaoban)'; + SCnPack_Savetime: string = 'savetime'; + SCnPack_solokey: string = 'solokey'; + SCnPack_Bahamut: string = 'Bahamut'; + SCnPack_Sesame: string = 'Sesame'; + SCnPack_BuDeXian: string = 'BuDeXian'; + SCnPack_XiaoXia: string = 'Summer'; + SCnPack_ZiMin: string = 'ZiMin'; + SCnPack_rarnu: string = 'rarnu'; + SCnPack_dejoy: string = 'dejoy'; + SCnPack_Rain: string = 'Rain'; + SCnPack_cnwinds: string = 'cnwinds'; + + // CnCommon + SUnknowError: string = 'Unknow error'; + SErrorCode: string = 'Error code:'; + +const + SCnPack_TeamEmail = 'master@cnpack.org'; + SCnPack_ZjyEmail = 'zjy@cnpack.org'; + SCnPack_ShenloqiEmail = 'Shenloqi@hotmail.com'; + SCnPack_xiaolvEmail = 'xiaolv888@etang.com'; + SCnPack_FlierEmail = 'flier_lu@sina.com'; + SCnPack_LiuXiaoEmail = 'liuxiao@cnpack.org'; + SCnPack_PanYingEmail = 'panying@sina.com'; + SCnPack_HubdogEmail = 'hubdog@263.net'; + SCnPack_Wyb_starMail = 'wyb_star@sina.com'; + SCnPack_LicwingEmail = 'licwing@chinasystemsn.com'; + SCnPack_AlanEmail = 'BeyondStudio@163.com'; + SCnPack_GuYueChunQiuEmail = 'guyuechunqiu@cnpack.org'; + SCnPack_AimingooEmail = 'aim@263.net'; + SCnPack_QSoftEmail = 'hq.com@263.net'; + SCnPack_HospitalityEmail = 'Hospitality_ZJX@msn.com'; + SCnPack_SQuallEmail = 'squall_sa@163.com'; + SCnPack_HhhaEmail = 'Hhha@eyou.com'; + SCnPack_BetaEmail = 'beta@01cn.net'; + SCnPack_LeeonEmail = 'real-like@163.com'; + SCnPack_SuperYoyoNcEmail = 'superyoyonc@sohu.com'; + SCnPack_JohnsonZhongEmail = 'zhongs@tom.com'; + SCnPack_DragonPCEmail = 'dragonpc@21cn.com'; + SCnPack_KendlingEmail = 'kendling@21cn.com'; + SCnPack_ccRunEmail = 'info@ccrun.com'; + SCnPack_DingbaoshengEmail = 'yzdbs@msn.com'; + SCnPack_LuXiaobanEmail = 'zhouyibo2000@sina.com'; + SCnPack_SavetimeEmail = 'savetime2k@hotmail.com'; + SCnPack_solokeyEmail = 'crh611@163.com'; + SCnPack_BahamutEmail = 'fantasyfinal@126.com'; + SCnPack_SesameEmail = 'sesamehch@163.com'; + SCnPack_BuDeXianEmail = 'appleak46@yahoo.com.cn'; + SCnPack_XiaoXiaEmail = 'summercore@163.com'; + SCnPack_ZiMinEmail = '441414288@qq.com'; + SCnPack_rarnuEmail = 'rarnu@cnpack.org'; + SCnPack_dejoyEmail = 'dejoybbs@163.com'; + SCnPack_RainEmail = SCnPack_TeamEmail; // Emailÿ + SCnPack_cnwindsEmail = SCnPack_TeamEmail; + + // CnMemProf + SCnPackMemMgr = 'CnMemProf'; + SMemLeakDlgReport = 'Found %d memory leaks. [There are %d allocated before replace memory manager.]'; + SMemMgrODSReport = 'Get = %d Free = %d Realloc = %d'; + SMemMgrOverflow = 'Memory Manager''s list capability overflow, Please enlarge it!'; + SMemMgrRunTime = '%d hour(s) %d minute(s) %d second(s)'; + SOldAllocMemCount = 'There are %d allocated before replace memory manager.'; + SAppRunTime = 'Application total run time: '; + SMemSpaceCanUse = 'HeapStatus.TotalAddrSpace: %d KB'; + SUncommittedSpace = 'HeapStatus.TotalUncommitted: %d KB'; + SCommittedSpace = 'HeapStatus.TotalCommitted: %d KB'; + SFreeSpace = 'HeapStatus.TotalFree: %d KB'; + SAllocatedSpace = 'HeapStatus.TotalAllocated: %d KB'; + SAllocatedSpacePercent = 'TotalAllocated div TotalAddrSpace: %d%%'; + SFreeSmallSpace = 'HeapStatus.FreeSmall: %d KB'; + SFreeBigSpace = 'HeapStatus.FreeBig: %d KB'; + SUnusedSpace = 'HeapStatus.Unused: %d KB'; + SOverheadSpace = 'HeapStatus.Overhead: %d KB'; + SObjectCountInMemory = 'Objects count in memory: '; + SNoMemLeak = ' No memory leak.'; + SNoName = '(no name)'; + SNotAnObject = ' Not an object'; + SByte = 'Byte'; + SCommaString = ','; + SPeriodString = '.'; + +resourcestring + SCnErrorMapViewOfFile = 'MapViewOfFile Failed. '; + SCnErrorCreateFileMapping = 'CreateFileMapping Failed. '; + +function CnGetLastError: Integer; + +procedure _CnSetLastError(Err: Integer); + +implementation + +threadvar + CnErrorCode: Integer; + +function CnGetLastError: Integer; +begin + Result := CnErrorCode; +end; + +procedure _CnSetLastError(Err: Integer); +begin + CnErrorCode := Err; +end; + +end. + diff --git a/CnPack/Crypto/CnFloat.pas b/CnPack/Common/CnFloat.pas similarity index 73% rename from CnPack/Crypto/CnFloat.pas rename to CnPack/Common/CnFloat.pas index a727541..c1df9ab 100644 --- a/CnPack/Crypto/CnFloat.pas +++ b/CnPack/Common/CnFloat.pas @@ -1,1354 +1,1528 @@ -{******************************************************************************} -{ CnPack For Delphi/C++Builder } -{ йԼĿԴ } -{ (C)Copyright 2001-2025 CnPack } -{ ------------------------------------ } -{ } -{ ǿԴ CnPack ķЭ } -{ ĺ·һ } -{ } -{ һĿϣãûκεû } -{ ʺضĿĶĵϸ CnPack Э顣 } -{ } -{ ӦѾͿһյһ CnPack Эĸ } -{ ûУɷǵվ } -{ } -{ վַhttps://www.cnpack.org } -{ ʼmaster@cnpack.org } -{ } -{******************************************************************************} - -unit CnFloat; -{* |
-================================================================================
-* ƣ
-* Ԫƣת
-* ԪߣǬԪ(wqyfavor@163.com)
-*     עõԪʵ Extended תΪˡʮַĺ
-*           㷨Ƕȡ Extended ڴеĶݽת Extended ͵˵
-*           ԲοϡDouble  Single Ϊϵͳֵ֧ͨĸͣ Delphi е
-*           Extended ڴ洢ʽвͬ߾β񻯣 Double  Single β
-*           Ĭϵ 1βΪ 1.001 Double  Single д洢Ϊ 001ȥ
-*           Сǰ 1 Extended 洢Ϊ 1001
-*           NaN Ϊ "not a number"Ǹο Math.pas Ԫеij NaN
-*           Infinity Ϊ󣬶ο Math.pas Ԫеij Infinity  NegInfinity.
-*           һ DecimalExp  AlwaysUseExponent 
-*           ʮƸתʱָʽѧ㷨Щ
-*           Ҳָֻʽ 1E-1000ָʱ 0.0000000...0001תָ
-*           ҲӦӦƱʾʱʮƱʾָ֣ƴ
-*           1.001E101ֵΪ 100100ָʮƱһЩ 1.001D5ʾС
-*            5 λDecimalExp ָǷʮƱֵָġע⣬ʮ
-*           ʾָ޹涨﷨ʹ "D" ʾ"E" ΪӦƱʾ⣬
-*           ʮƱȽ⣬"D"  "E" ΪʮַʮƱʱʹ "^"
-*           ַ 3.BD^D(12)A.BD^E(ABCE)粻ϲָʽ޸ġ
-*           AlwaysUseExponent ָǷһÿѧ 100.111 λȽ٣
-*           ԶжϲҪʹÿѧ AlwaysUseExponent ΪʱһΪָ
-*           ʽ 1.00111E2
-*           const
-*             MaxBinDigits = 120;
-*             MaxHexDigits = 30;
-*             MaxOctDigits = 40;
-*           ָλʱһʹÿѧ
-*
-*           ⣬Extended ֻ Win32  10 ֽڣMacOS/Linux x64 ¾ 16 ֽڣWin64  ARM ƽ̨ 8 ֽ
-*           ңMacOS64 µ 16 ֽչȲ  IEEE 754-2008 й涨 Quadruple ʽǰ 10 ֽڽضϣ
-*           ڲṹͬ Win32 µչ 10 ֽ
-*
-* ƽ̨WinXP + Delphi 2009
-* ݲԣDelphi 2007 Extended ֻ֧Сģʽ
-*   õԪеַϱػʽ
-* ޸ļ¼2023.01.13
-*               ݴ Win64  Extended  8 ֽ Double  10 ֽչȵ
-*               ݴ MacOS64/Linux64 µ 16 ֽ Extendedֻضϴǰ 10 ֽڣ
-*           2022.02.17
-*                FPC ı֧֣
-*           2021.09.05
-*               תΪ UInt64֧ UInt64  Int64 棩ĺ
-*           2020.11.11
-*                UInt64֧ UInt64  Int64 棩תΪĺ
-*           2020.06.24
-*               ⿪ƴյĺ
-*           2009.1.12
-*               Ԫ
-================================================================================
-|
} - -interface - -{$I CnPack.inc} - -uses - SysUtils, Classes, SysConst, {$IFDEF MSWINDOWS} Windows, {$ENDIF} CnNative; - -{ - IEEE 754 涨ָʽЧڵλ 0 - - Single 1 λ S8 λָ E23 λЧ M 4 ֽ 32 λ - ˫ Double 1 λ S11 λָ E52 λЧ M 8 ֽ 64 λ - չ˫ Extended 1 λ S15 λָ E64 λЧ M 10 ֽ 80 λ - - IEEE 754-2008 - ı Quadruple 1 λ S15 λָ E112 λЧ M 16 ֽ 128 λ - ˱ Octuple 1 λ S19 λָ E236 λЧ M 32 ֽ 256 λ - - Уλ S0 ʾ1 ʾE Ҫȥ 127/1023/16383/16383 ָ - M: 淶/˫ȵĶ M ĸλӸ 1. Чչӣ 1. - ֵЧ 1.xxxx ʽ 2 E ηעⲻ 10 E η - - ʽ ֽ 1 ֽ 2 ֽ 3 ֽ 4 ... ֽ nÿֽڵұߵλ 0 - 4 SXXXXXXX XMMMMMMM MMMMMMMM MMMMMMMM - ˫ 8 SXXXXXXX XXXXMMMM MMMMMMMM MMMMMMMM ... MMMMMMMM - չ˫ 10 SXXXXXXX XXXXXXXX 1MMMMMMM MMMMMMMM ... MMMMMMMM // עЧְ 1඼ʡ 1 - ı 16 SXXXXXXX XXXXXXXX MMMMMMMM MMMMMMMM ... MMMMMMMM - ˱ 32 SXXXXXXX XXXXXXXX XXXXMMMM MMMMMMMM ... MMMMMMMM - - ע⣺Little Endian ϣֽ 1 n 򡣱Ԫѵ - - 0ȫ 0 - -0ȫ 0 λΪ 1 - ָȫ 1Чȫ 0 0 1 -} - -type - TCnQuadruple = packed record - {* Delphi ıͣýṹָ} - Lo: TUInt64; - Hi0: Cardinal; - case Boolean of - True: (Hi1: Cardinal); - False: (W0, W1: Word); // С˻ϣźָ W1 - end; - PCnQuadruple = ^TCnQuadruple; - - TCnOctuple = packed record - {* Delphi ް˱ͣ Int64 ָ} - F0: Int64; - F1: Int64; - F2: Int64; - F3: Int64; - end; - PCnOctuple = ^TCnOctuple; - - ECnFloatSizeError = class(Exception); - -const - CN_EXTENDED_SIZE_8 = 8; // Win64 µ Extended ֻ 8 ֽ - CN_EXTENDED_SIZE_10 = 10; // Win32 µ Extended DZ׼ 10 ֽ - CN_EXTENDED_SIZE_16 = 16; // MACOS64/Linux64 16 ֽ - - CN_SIGN_SINGLE_MASK = $80000000; - CN_SIGN_DOUBLE_MASK = $8000000000000000; - CN_SIGN_EXTENDED_MASK = $8000; // ȥ 8 ֽЧ - CN_SIGN_QUADRUPLE_MASK = $80000000; // ֻǰֽڣȥ˺ - - CN_EXPONENT_SINGLE_MASK = $7F800000; // Ҫ 23 λ - CN_EXPONENT_DOUBLE_MASK = $7FF0000000000000; // Ҫ 52 λ - CN_EXPONENT_EXTENDED_MASK = $7FFF; // ȥ 8 ֽЧ - CN_EXPONENT_QUADRUPLE_MASK = $7FFF; // ȥ 14 ֽЧ - - CN_SIGNIFICAND_SINGLE_MASK = $007FFFFF; // 23 λ - CN_SIGNIFICAND_DOUBLE_MASK = $000FFFFFFFFFFFFF; // 52 λ - CN_SIGNIFICAND_EXTENDED_MASK = $FFFFFFFFFFFFFFFF; // 64 λʵȫ 8 ֽ - CN_SIGNIFICAND_QUADRUPLE_MASK = $FFFF; - - CN_SINGLE_SIGNIFICAND_BITLENGTH = 23; - CN_DOUBLE_SIGNIFICAND_BITLENGTH = 52; - CN_EXTENDED_SIGNIFICAND_BITLENGTH = 63; - - CN_EXPONENT_OFFSET_SINGLE = 127; // ʵֵָҪܴ浽ڴָ - CN_EXPONENT_OFFSET_DOUBLE = 1023; - CN_EXPONENT_OFFSET_EXTENDED = 16383; // 10 16 ֽչȸΪ - - CN_SINGLE_MIN_EXPONENT = -127; - CN_SINGLE_MAX_EXPONENT = 127; // Max ָȫ 1 Σ - CN_DOUBLE_MIN_EXPONENT = -1023; - CN_DOUBLE_MAX_EXPONENT = 1023; - CN_EXTENDED_MIN_EXPONENT = -16383; - CN_EXTENDED_MAX_EXPONENT = 16383; - -procedure ExtractFloatSingle(Value: Single; out SignNegative: Boolean; - out Exponent: Integer; out Mantissa: Cardinal); -{* ӵȸнλָЧ֡ - עָΪʵָЧΪ 24 λԭʼΪ 0~22 λ 23 λΪȥ 1 - - - Value: Single - ⿪ĵȸ - out SignNegative: Boolean - λTrue Ϊ - out Exponent: Integer - ָ - out Mantissa: Cardinal - Ч - - ֵޣ -} - -procedure ExtractFloatDouble(Value: Double; out SignNegative: Boolean; - out Exponent: Integer; out Mantissa: TUInt64); -{* ˫ȸнλָЧ֡ - עָΪʵָЧΪ 53 λԭʼΪ 0~51 λ 52 λΪȥ 1 - - - Value: Double - ⿪˫ȸ - out SignNegative: Boolean - λTrue Ϊ - out Exponent: Integer - ָ - out Mantissa: TUInt64 - Ч - - ֵޣ -} - -procedure ExtractFloatExtended(Value: Extended; out SignNegative: Boolean; - out Exponent: Integer; out Mantissa: TUInt64); -{* չȸнλָЧ֣֧ 10 ֽڡ - Լ 16 ֽڽضΪ 10 ֽڵ Extended ʽ - עָΪʵָЧΪȫ 64 λλ 63 λΪԴ 1 - - - Value: Extended - ⿪չȸ - out SignNegative: Boolean - λTrue Ϊ - out Exponent: Integer - ָ - out Mantissa: TUInt64 - Ч - - ֵޣ -} - -procedure ExtractFloatQuadruple(Value: Extended; out SignNegative: Boolean; - out Exponent: Integer; out MantissaLo: TUInt64; out MantissaHi: TUInt64); -{* ʮֽھȸнλָЧֻ֣ Extended Ϊ 16 ֽ - Ҹʽ IEEE 754-2008 ıȸʱЧĿǰ Delphi ָ֧øʽ - עָΪʵָЧ 112 λΪߵ֡ - - - Value: Extended - ⿪ʮֽھȸ - out SignNegative: Boolean - λTrue Ϊ - out Exponent: Integer - ָ - out MantissaLo: TUInt64 - Чֵ 64 λ - out MantissaHi: TUInt64 - Чָ 64 λ - - ֵޣ -} - -procedure CombineFloatSingle(SignNegative: Boolean; Exponent: Integer; - Mantissa: Cardinal; var Value: Single); -{* ѷλָЧƴɵȸ - - - SignNegative: Boolean - λTrue Ϊ - Exponent: Integer - ָ - Mantissa: Cardinal - Ч - var Value: Single - ϵĵȸ - - ֵޣ -} - -procedure CombineFloatDouble(SignNegative: Boolean; Exponent: Integer; - Mantissa: TUInt64; var Value: Double); -{* ѷλָЧƴ˫ȸ - - - SignNegative: Boolean - λTrue Ϊ - Exponent: Integer - ָ - Mantissa: TUInt64 - Ч - var Value: Double - ϵ˫ȸ - - ֵޣ -} - -procedure CombineFloatExtended(SignNegative: Boolean; Exponent: Integer; - Mantissa: TUInt64; var Value: Extended); -{* ѷλָЧƴչȸ֧ 10 ֽڡ - Լ 16 ֽڽضΪ 10 ֽڵ Extended ʽ - - - SignNegative: Boolean - λTrue Ϊ - Exponent: Integer - ָ - Mantissa: TUInt64 - Ч - var Value: Extended - ϵչȸ - - ֵޣ - -} - -procedure CombineFloatQuadruple(SignNegative: Boolean; Exponent: Integer; - MantissaLo: TUInt64; MantissaHi: TUInt64; var Value: Extended); -{* ѷλָЧƴչȸֻ Extended Ϊ 16 ֽ - Ҹʽ IEEE 754-2008 ıȸʱЧĿǰ Delphi ָ֧øʽ - - - SignNegative: Boolean - λTrue Ϊ - Exponent: Integer - ָ - MantissaLo: TUInt64 - Чֵ 64 λ - MantissaHi: TUInt64 - Чָ 64 λ - var Value: Extended - ϵʮֽھȸ - - ֵޣ -} - -function UInt64ToSingle(U: TUInt64): Single; -{* Int64 зģ 64 λ޷͸ֵ Singleʵͬ - - - U: TUInt64 - ֵ 64 λ޷ֵ - - ֵSingle - صĵȸ -} - -function UInt64ToDouble(U: TUInt64): Double; -{* Int64 зģ 64 λ޷͸ֵ Doubleʵͬ - - - U: TUInt64 - ֵ 64 λ޷ֵ - - ֵDouble - ص˫ȸ -} - -function UInt64ToExtended(U: TUInt64): Extended; -{* Int64 зģ 64 λ޷͸ֵ Extendedʵͬ - - - U: TUInt64 - ֵ 64 λ޷ֵ - - ֵExtended - صչȸ -} - -function SingleToUInt64(F: Single): TUInt64; -{* Single ֵ Int64 зģ 64 λ޷ͣʵͬ - - - F: Single - ֵĵȸ - - ֵTUInt64 - ص 64 λ޷ֵ -} - -function DoubleToUInt64(F: Double): TUInt64; -{* Double ֵ Int64 зģ 64 λ޷ͣʵͬ - - - F: Double - ֵ˫ȸ - - ֵTUInt64 - ص 64 λ޷ֵ -} - -function ExtendedToUInt64(F: Extended): TUInt64; -{* Extended ֵ Int64 зģ 64 λ޷ͣʵͬ - - - F: Extended - ֵ˫ȸ - - ֵTUInt64 - ص 64 λ޷ֵ -} - -function SingleIsInfinite(AValue: Single): Boolean; -{* ȸǷ - - - AValue: Single - жϵĵȸ - - ֵBoolean - Ƿ -} - -function DoubleIsInfinite(AValue: Double): Boolean; -{* ˫ȸǷ - - - AValue: Double - жϵ˫ȸ - - ֵBoolean - Ƿ -} - -function ExtendedIsInfinite(AValue: Extended): Boolean; -{* չȸǷ - - - AValue: Extended - жϵչȸ - - ֵBoolean - Ƿ -} - -function SingleIsNan(AValue: Single): Boolean; -{* ȸǷʵ - - - AValue: Single - жϵĵȸ - - ֵBoolean - Ƿʵ -} - -function DoubleIsNan(AValue: Double): Boolean; -{* ˫ȸǷʵ - - - AValue: Double - жϵ˫ȸ - - ֵBoolean - Ƿʵ -} - -function ExtendedIsNan(AValue: Extended): Boolean; -{* չȸǷʵ - - - AValue: Extended - жϵչȸ - - ֵBoolean - Ƿʵ -} - -// FPCWindows 64/Linux 64 ƽ̨Լ Delphi 56 ֧ -{$IFDEF WIN32} -{$IFDEF COMPILER7_UP} - -{ FloatDecimalToBinExtended, FloatDecimalToOctExtendedFloatDecimalToHexExtended - FloatDecimalToBinaryExtended ̣FloatDecimalToBinaryExtended } - -function FloatDecimalToBinExtended(fIn: Extended; DecimalExp: Boolean; - AlwaysUseExponent: Boolean): AnsiString; // Convert to binary - -function FloatDecimalToOctExtended(fIn: Extended; DecimalExp: Boolean; - AlwaysUseExponent: Boolean): AnsiString; // Convert to octal - -function FloatDecimalToHexExtended(fIn: Extended; DecimalExp: Boolean; - AlwaysUseExponent: Boolean): AnsiString; // Convert to hexdecimal - -{$ENDIF} -{$ENDIF} - -implementation - -const - UINT64_EXTENDED_EXP_MAX = $4040; // UINT64 Ӧ Extended ָ - -resourcestring - SCN_ERROR_EXTENDED_SIZE = 'Extended Size Error'; - -type - TExtendedRec10 = packed record - {* 10 ֽڵչȸֻ Win32 Ч} - Mantissa: TUInt64; - ExpSign: Word; - end; - PExtendedRec10 = ^TExtendedRec10; - -{$IFDEF WIN32} -{$IFDEF COMPILER7_UP} - -type - PConvertFloatSystem = ^TConvertFloatSystem; - TConvertFloatSystem = record - Negative: Boolean; - ExpFlag, ExponentI: Integer; - end; - -const - MaxBinDigits = 120; - MaxHexDigits = 30; - MaxOctDigits = 40; - -function FloatDecimalToBinaryExtended(fIn: Extended; DecimalExp, - AlwaysUseExponent: Boolean; var ForHexOct: PConvertFloatSystem): AnsiString; -var - Neg: Boolean; - i, Flag, IntExp: Integer; - Exp: AnsiString; -label UseExponent; -begin -{ -Extended(32.125) in memory: -0 100000000000100 10000000 10000000 00000000 00000000 00000000 00000000 00000000 00000000 - 9 8 7 6 5 4 3 2nd Byte 1stByte 0 -sign exponent digits -0 111111111111111 1000000000000000000000000000000000000000000000000000000000000000 + Inf -1 111111111111111 1000000000000000000000000000000000000000000000000000000000000000 - Inf -1 111111111111111 1100000000000000000000000000000000000000000000000000000000000000 Nan -0 111111111111111 1100000000000000000000000000000000000000000000000000000000000000 -Nan -} - SetLength(Result, 255); - SetLength(Exp, 2 * SizeOf(Extended) + 1); - Neg := False; - asm - push EBX - push ESI - mov EBX, Result // Address of Result - mov EBX, [EBX] - mov EAX, 0 - // Test if fIN equals 0 - lea ESI, fIn[7] // get the first byte of digits - mov AL, [ESI] - test AL, 128 // 10000000B - jz @Zero - mov ECX, 0 - lea ESI, fIn[8] - mov AX, [ESI] // Get first two bytes - test AX, 32768 // 32768D = 1000000000000000B - jz @Positive - mov Neg, 1 - sub AX, 32768 // Sign bit <- 0 - @Positive: - // Test if fIn is NaN or Infinity - cmp AX, 32767 - jnz @NotNAN_INF - mov DL, [ESI - 1] - test DL, 64 // 01000000B - jz @INF - mov Flag, 4 // NaN - jmp @Done - @INF: - mov Flag, 3 // INF - jmp @Done - @NotNAN_INF: - sub AX, 16383 // AX = AX - 011111111111111B - jns @ExpPositive - sub AX, 1 - not AX - mov Flag, 2 // // Exponent sign negative - jmp @JudgeDecimalExp - @ExpPositive: - mov Flag, 1 // Exponent sign positive - @JudgeDecimalExp: - mov IntExp, EAX - cmp DecimalExp, 1 - je @MoveDigits - // Binary string exponent. Convert AX to binary string and store it in Exp - lea EBX, Exp - mov EBX, [EBX] - push ECX - mov [EBX], 69 // 'E' // "D" for decimal exponent - mov ECX, 1 - cmp Flag, 2 - jnz @NoNegativeInExp - mov [EBX + 1], 45 // '-' // Add a "-" to exponent string - mov ECX, 2 - @NoNegativeInExp: - mov ESI, 0 // flag whehter "1" appears - // Move exponent digits to Exp - mov DX, 32768 // 1000000000000000 - @NextExpDigit: - test AX, DX - jz @AppendExp0 - mov [EBX + ECX], 49 // '1' - mov ESI, 1 - jmp @NextExpIncECX - @AppendExp0: - cmp ESI, 0 - jz @NextExpNoIncECX // do not append this "0" - mov [EBX + ECX], 48 // '0' - @NextExpIncECX: - inc ECX - @NextExpNoIncECX: - shr DX, 1 - cmp DX, 0 - jne @NextExpDigit - pop ECX - mov EBX, Result - mov EBX, [EBX] - jmp @MoveDigits - @MoveDigits: - // Move digits to Result - mov ESI, 8 - @NextByte: - dec ESI - mov EAX, EBX - lea EBX, fIn[ESI] - mov DL, [EBX] - mov EBX, EAX - mov AL, 128 // 10000000 - @NextDigit: - test DL, AL - jz @Append0 - mov [EBX + ECX], 49 // '1' - mov i, ECX - jmp @Next - @Append0: - mov [EBX + ECX], 48 // '0' - @Next: - inc ECX - shr AL, 1 - cmp AL, 0 - jne @NextDigit - cmp ESI, 0 // if the last byte - jne @NextByte - jmp @Done - @Zero: - mov Flag, 0 - @Done: - pop ESI - pop EBX - end; - case Flag of - 0: - begin - ForHexOct := nil; - Result := '0'; - Exit; - end; - 1, 2: - begin - // Delete redundant "0" in Result - Delete(Result, i + 2, MaxInt); // i stores the position of the last 1 in Result - if Assigned(ForHexOct) then - begin - // Copy to ForHexOct - with ForHexOct^ do - begin - Negative := Neg; - ExpFlag := Flag; - ExponentI := IntExp; - end; - Exit; - end; - // Add dot and exponent to Result - if (IntExp = 0) then - begin - if (Length(Result) > 1) then - Insert('.', Result, 2); - end - else - begin - { Decide whether use exponent. For example "1000.101" shouldn't be output - as 1.000101E11 when AlwaysUseExponent is False. } - if AlwaysUseExponent then - begin -UseExponent: - if DecimalExp then - if Flag = 1 then - Exp := 'D' + {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(IntExp)) - else - Exp := 'D-' + {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(IntExp)); - if Length(Result) >=2 then - Insert('.', Result, 2); - Result := Result + Exp; - end - else - begin - // IntExp may be negative. - if Flag = 1 then - begin - // Calculate all digits required without exponent - if IntExp <= Length(Result) - 2 then - begin - // Do not use exponent - Insert('.', Result, IntExp + 2); - end - else if IntExp = Length(Result) - 1 then - { 1.001, Exp = 3, output 1001 } - else - begin - if IntExp + 1> MaxBinDigits then - goto UseExponent - else - begin - Inc(IntExp); - i := Length(Result); - // Add zeros at tail - SetLength(Result, IntExp); - for i := i + 1 to IntExp do - Result := '0'; - end; - end; - end - else - begin - if IntExp + Length(Result) > MaxBinDigits then - goto UseExponent - else - begin - // Add leading zeros and place "." - SetLength(Exp, 1 + IntExp); - Exp[1] := '0'; - Exp[2] := '.'; - for i := 3 to IntExp + 1 do - Exp := '0'; //} - Result := Exp + Result; - end; - end; - end; - end; - end; - 3: // INF - begin - ForHexOct := nil; - Result := 'INF'; - end; - 4: // NaN - begin - ForHexOct := nil; - Result := 'NaN'; - Exit; - end; - end; - if Neg then - Result := '-' + Result; -end; - -function FloatDecimalToBinExtended(fIn: Extended; DecimalExp, - AlwaysUseExponent: Boolean): AnsiString; -var - PTmp: PConvertFloatSystem; -begin - PTmp := nil; - Result := FloatDecimalToBinaryExtended(fIn, DecimalExp, AlwaysUseExponent, PTmp); -end; - -function FloatDecimalToHexExtended(fIn: Extended; DecimalExp, - AlwaysUseExponent: Boolean): AnsiString; -const - DecToHex: array[0..15] of AnsiChar = - ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); - BinPow: array[0..3] of Integer = (8, 4, 2, 1); - - function IntToHex(Int: Integer): AnsiString; - var - k ,t: Integer; - Buf: array[1..5] of AnsiChar; - begin - k := 1; - while (Int <> 0) do - begin - Buf[k] := DecToHex[Int mod 16]; - Inc(k); - Int := Int div 16; - end; - Dec(k); - SetLength(Result, k); - t := 1; - while (k > 0) do - begin - Result[t] := Buf[k]; - Inc(t); - Dec(k); - end; - end; - - function ToHex(const S: AnsiString; LeftToDot: Boolean): AnsiString; - var - i, l, t, m, k: Integer; - Buf: array[1..20] of AnsiChar; - begin - { LeftToDot = True, S will be patched with zeroes on its left side. - For example, S = '110', after patching, S = '0110'. - LeftToDot = False, S will be patched with zeroes on its right side. - S = '110', after patching, S = '1100'. } - l := Length(S); - if LeftToDot then - t := (4 - (l mod 4)) mod 4 - else - t := 0; - i := 1; - m := 1; - k := 0; - while i <= l do - begin - k := k + BinPow[t] * (Ord(S[i]) - Ord('0')); - Inc(t); - if (t = 4) or (i = l) then - begin - Buf[m] := DecToHex[k]; - Inc(m); - k := 0; - t := 0; - end; - Inc(i); - end; - Dec(m); - SetLength(Result, m); - - while (m > 0) do - begin - Result[m] := Buf[m]; - Dec(m); - end; - end; - -var - PConvertData: PConvertFloatSystem; - ConvertData: TConvertFloatSystem; - tmpS: AnsiString; - k, t, i, m: Integer; -label UseExponent; -begin - PConvertData := @ConvertData; - Result := FloatDecimalToBinaryExtended(fIn, True, True, PConvertData); - // See FloatDecimalToBinaryExtended, PConvertData is set to nil when result is definite. - if PConvertData = nil then - Exit; - with ConvertData do - begin - { 3.BD^D(12) - A.BD^E(ABCE) - AB.FFFF } - k := Length(Result) - 1; - if AlwaysUseExponent then - begin -UseExponent: - { Algorithm: - X.XXXXXXXX^Y Shift Count Exp - 1.00000001^0 = 1.00000001 = 1.01^0 (16) - 1.00000001^1 = 10.0000001 = 2.02^0 (16) - 1.00000001^2 = 100.000001 = 4.04^0 (16) - 1.00000001^3 = 1000.00001 = 8.08^0 (16) - 1.00000001^4 = 1.00000001^100 = 1.01^1 (16) - 1.00000001^5 = 10.0000001^100 = 2.02^1 (16) - Shift Count = Y mod 4 - Exp = Y div 4 - X.XXXXXXXXX^Y Y < 0 Exp - 1.00000001^-1 = 0.100000001 = 1000.00001^-100 = 8.08^-1 - 1.00000001^-2 = 0.0100000001 = 100.000001^-100 = 4.04^-1 - 1.00000001^-3 = 0.00100000001 = 10.0000001^-100 = 2.02^-1 - 1.00000001^-4 = 0.000100000001 = 1.00000001^-100 = 1.01^-1 - 1.00000001^-5 = 0.0000100000001 = 1000.00001^-100 = 8.08^-2 - Shift Count = 4 - (Abs(Y) mod 4) - Exp = -(Abs(Y) div 4 + 1) } - if ExpFlag = 1 then - begin - t := ExponentI div 4; // Exp - i := ExponentI mod 4; // Shift Count - end - else - begin - t := -((ExponentI - 1) div 4 + 1); // Exp - i := (4 - (ExponentI mod 4)) mod 4; // Shift Count - end; - // Get hex digits - if k < i then - begin - // Add extra zeroes - SetLength(Result, i + 1); - for m := k + 2 to i + 1 do - Result[m] := '0'; - Result := ToHex(Result, True); - end - else if k = i then - Result := ToHex(Result, True) - else - begin - tmpS := Copy(Result, 1, i + 1); - Delete(Result, 1, i + 1); - Result := ToHex(tmpS, True) + '.' + ToHex(Result, False); - end; - if t <> 0 then - begin - // Format exponent - if DecimalExp then - Result := Result + '^D(' + {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(t)) + ')' - else - begin - if ExpFlag = 1 then - Result := Result + '^E(' + IntToHex(t) + ')' - else // t < 0 - Result := Result + '^E(-' + IntToHex(-t) + ')'; - end; - end; - end - else - begin - { Always remember that Result equals "XXXXXXXX" not "X.XXXXXXX". - Judge whether to use exponent: - There are K "X" after '.', K = Length(Result) - 1, no "." in Result originally. - X.XXXXXXX^Y (Binary string, ExponentI = Abs(Y)) - case Y >= 0 (Condition: ExpFlag = 2) - Y <= K: - Y+1 binary digits on left side of '.', K-Y digits on right side - totally requires ((Y+1 - 1) div 4 + 1) + ((K-Y - 1) div 4 + 1) hex digits - Y > K: - Y+1 binary digits on left side, totally ((Y+1 - 1) div 4 + 1) hex digits - case Y<0 (Condition: ExpFlag = 1) 0.XXXX or 0.000XXXX - One digit '0' on left side and K+1+Abs(Y)-1 digits on right side, - totally 1 + ((K+1+Abs(Y)-1-1) div 4 + 1) hex digits. - Compare hdc = hex digit count with MaxHexDigits. If hdc > MaxHexDigits, - goto UseExponent. } - if ExponentI = 0 then - begin - if (Length(Result) > 1) then - Result := '1.' + ToHex(Copy(Result, 2, MaxInt), False); - end - else - begin - if ExpFlag = 1 then - begin - if ExponentI < k then - begin - // No possible that "ExponentI div 4 + (k - ExponentI - 1) div 4 + 2" > MaxHexDigits - tmpS := Copy(Result, 1, ExponentI + 1); - Delete(Result, 1, ExponentI + 1); - Result := ToHex(tmpS, True) + '.' + ToHex(Result, False); - end - else if ExponentI = k then - // 1.01^2 = 101, no ".", no extra "0". - Result := ToHex(Result, True) - else - begin - t := ExponentI div 4 + 1; - if t > MaxHexDigits then - goto UseExponent - else - begin - // Append "0" after Result - Inc(ExponentI); - // Add '0' to Result - SetLength(Result, ExponentI); - for t := k + 2{original Length(Result) + 1} to ExponentI do - Result[t] := '0'; - Result := ToHex(Result, True); - end; - end; - end - else - begin - // ExpFlag = 2, X.XXXXXXX^Y, Y < 0 - t := 2 + (k + ExponentI - 1) div 4; {1 + ((K+1+Abs(Y)-1-1) div 4 + 1)} - if t > MaxHexDigits then - goto UseExponent - else - begin - // Add leading zeroes before Result - SetLength(tmpS, ExponentI - 1); // tmpS stores extra zeroes - for t := 1 to ExponentI - 1 do - tmpS[t] := '0'; - Result := '0.' + ToHex(tmpS + Result, False); - end; - end; - end; - end; - if Negative then - Result := '-' + Result; - end; -end; - -function FloatDecimalToOctExtended(fIn: Extended; DecimalExp, - AlwaysUseExponent: Boolean): AnsiString; -const - DecToOct: array[0..7] of AnsiChar = - ('0', '1', '2', '3', '4', '5', '6', '7'); - BinPow: array[0..2] of Integer = (4, 2, 1); - - function IntToOct(Int: Integer): AnsiString; - var - k ,t: Integer; - Buf: array[1..10] of AnsiChar; - begin - k := 1; - while (Int <> 0) do - begin - Buf[k] := DecToOct[Int mod 8]; - Inc(k); - Int := Int div 8; - end; - Dec(k); - SetLength(Result, k); - t := 1; - while (k > 0) do - begin - Result[t] := Buf[k]; - Inc(t); - Dec(k); - end; - end; - - function ToOct(const S: AnsiString; LeftToDot: Boolean): AnsiString; - var - i, l, t, m, k: Integer; - Buf: array[1..30] of AnsiChar; - begin - { LeftToDot = True, S will be patched with zeroes on its left side. - For example, S = '110', after patching, S = '0110'. - LeftToDot = False, S will be patched with zeroes on its right side. - S = '110', after patching, S = '1100'. } - l := Length(S); - if LeftToDot then - t := (3 - (l mod 3)) mod 3 - else - t := 0; - i := 1; - m := 1; - k := 0; - while i <= l do - begin - k := k + BinPow[t] * (Ord(S[i]) - Ord('0')); - Inc(t); - if (t = 3) or (i = l) then - begin - Buf[m] := DecToOct[k]; - Inc(m); - k := 0; - t := 0; - end; - Inc(i); - end; - Dec(m); - SetLength(Result, m); - - while (m > 0) do - begin - Result[m] := Buf[m]; - Dec(m); - end; - end; - -var - PConvertData: PConvertFloatSystem; - ConvertData: TConvertFloatSystem; - tmpS: AnsiString; - k, t, i, m: Integer; -label UseExponent; -begin - PConvertData := @ConvertData; - Result := FloatDecimalToBinaryExtended(fIn, True, True, PConvertData); - // See FloatDecimalToBinaryExtended, PConvertData is set to nil when result is definite. - if PConvertData = nil then - Exit; - with ConvertData do - begin - { 3.333D12 // 12 is decimal - 2.22E33 // 33 is octal} - k := Length(Result) - 1; - if AlwaysUseExponent then - begin -UseExponent: - if ExpFlag = 1 then - begin - t := ExponentI div 3; // Exp - i := ExponentI mod 3; // Shift Count - end - else - begin - t := -((ExponentI - 1) div 3 + 1); // Exp - i := (3 - (ExponentI mod 3)) mod 3; // Shift Count - end; - // Get hex digits - if k < i then - begin - // Add extra zeroes - SetLength(Result, i + 1); - for m := k + 2 to i + 1 do - Result[m] := '0'; - Result := ToOct(Result, True); - end - else if k = i then - Result := ToOct(Result, True) - else - begin - tmpS := Copy(Result, 1, i + 1); - Delete(Result, 1, i + 1); - Result := ToOct(tmpS, True) + '.' + ToOct(Result, False); - end; - if t <> 0 then - begin - // Format exponent - if DecimalExp then - Result := Result + 'D' + {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(t)) - else - begin - if ExpFlag = 1 then - Result := Result + 'E' + IntToOct(t) - else // t < 0 - Result := Result + 'E-' + IntToOct(-t); - end; - end; - end - else - begin - if ExponentI = 0 then - begin - if (Length(Result) > 1) then - Result := '1.' + ToOct(Copy(Result, 2, MaxInt), False); - end - else - begin - if ExpFlag = 1 then - begin - if ExponentI < k then - begin - tmpS := Copy(Result, 1, ExponentI + 1); - Delete(Result, 1, ExponentI + 1); - Result := ToOct(tmpS, True) + '.' + ToOct(Result, False); - end - else if ExponentI = k then - // 1.01^2 = 101, no ".", no extra "0". - Result := ToOct(Result, True) - else - begin - t := ExponentI div 3 + 1; - if t > MaxHexDigits then - goto UseExponent - else - begin - // Append "0" after Result - Inc(ExponentI); - // Add '0' to Result - SetLength(Result, ExponentI); - for t := k + 2{original Length(Result) + 1} to ExponentI do - Result[t] := '0'; - Result := ToOct(Result, True); - end; - end; - end - else - begin - // ExpFlag = 2, X.XXXXXXX^Y, Y < 0 - t := 2 + (k + ExponentI - 1) div 3; - if t > MaxHexDigits then - goto UseExponent - else - begin - // Add leading zeroes before Result - SetLength(tmpS, ExponentI - 1); // tmpS stores extra zeroes - for t := 1 to ExponentI - 1 do - tmpS[t] := '0'; - Result := '0.' + ToOct(tmpS + Result, False); - end; - end; - end; - end; - if Negative then - Result := '-' + Result; - end; -end; - -{$ENDIF} -{$ENDIF} - -procedure ExtractFloatSingle(Value: Single; out SignNegative: Boolean; - out Exponent: Integer; out Mantissa: Cardinal); -begin - SignNegative := (PCardinal(@Value)^ and CN_SIGN_SINGLE_MASK) <> 0; - Exponent := ((PCardinal(@Value)^ and CN_EXPONENT_SINGLE_MASK) shr 23) - CN_EXPONENT_OFFSET_SINGLE; - Mantissa := PCardinal(@Value)^ and CN_SIGNIFICAND_SINGLE_MASK; - Mantissa := Mantissa or (1 shl 23); // λټӸ 1 -end; - -procedure ExtractFloatDouble(Value: Double; out SignNegative: Boolean; - out Exponent: Integer; out Mantissa: TUInt64); -begin - SignNegative := (PUInt64(@Value)^ and CN_SIGN_DOUBLE_MASK) <> 0; - Exponent := ((PUInt64(@Value)^ and CN_EXPONENT_DOUBLE_MASK) shr 52) - CN_EXPONENT_OFFSET_DOUBLE; - Mantissa := PUInt64(@Value)^ and CN_SIGNIFICAND_DOUBLE_MASK; - Mantissa := Mantissa or (TUInt64(1) shl 52); // λټӸ 1 -end; - -procedure ExtractFloatExtended(Value: Extended; out SignNegative: Boolean; - out Exponent: Integer; out Mantissa: TUInt64); -begin - if (SizeOf(Extended) = CN_EXTENDED_SIZE_10) or (SizeOf(Extended) = CN_EXTENDED_SIZE_16) then - begin - SignNegative := (PExtendedRec10(@Value)^.ExpSign and CN_SIGN_EXTENDED_MASK) <> 0; - Exponent := (PExtendedRec10(@Value)^.ExpSign and CN_EXPONENT_EXTENDED_MASK) - CN_EXPONENT_OFFSET_EXTENDED; - Mantissa := PExtendedRec10(@Value)^.Mantissa; // 1ü - end - else if SizeOf(Extended) = CN_EXTENDED_SIZE_8 then - ExtractFloatDouble(Value, SignNegative, Exponent, Mantissa) - else - raise ECnFloatSizeError.Create(SCN_ERROR_EXTENDED_SIZE); -end; - -procedure ExtractFloatQuadruple(Value: Extended; out SignNegative: Boolean; - out Exponent: Integer; out MantissaLo, MantissaHi: TUInt64); -begin - if SizeOf(Extended) <> CN_EXTENDED_SIZE_16 then - raise ECnFloatSizeError.Create(SCN_ERROR_EXTENDED_SIZE); - - SignNegative := (PCnQuadruple(@Value)^.W1 and CN_SIGN_QUADRUPLE_MASK) <> 0; - Exponent := (PCnQuadruple(@Value)^.W1 and CN_EXPONENT_QUADRUPLE_MASK) - CN_EXPONENT_OFFSET_EXTENDED; - - // Extract 16 Bytes to Mantissas - MantissaLo := PCnQuadruple(@Value)^.Lo; - MantissaHi := TUInt64(PCnQuadruple(@Value)^.Hi0) or (TUInt64(PCnQuadruple(@Value)^.W0) shl 32) or (TUInt64(1) shl 48); // λټӸ 1 -end; - -procedure CombineFloatSingle(SignNegative: Boolean; Exponent: Integer; - Mantissa: Cardinal; var Value: Single); -begin - Mantissa := Mantissa and not (1 shl 23); // ȥ 23 λϵ 1еĻ - PCardinal(@Value)^ := Mantissa and CN_SIGNIFICAND_SINGLE_MASK; - Inc(Exponent, CN_EXPONENT_OFFSET_SINGLE); - - PCardinal(@Value)^ := PCardinal(@Value)^ or (LongWord(Exponent) shl 23); - if SignNegative then - PCardinal(@Value)^ := PCardinal(@Value)^ or CN_SIGN_SINGLE_MASK - else - PCardinal(@Value)^ := PCardinal(@Value)^ and not CN_SIGN_SINGLE_MASK; -end; - -procedure CombineFloatDouble(SignNegative: Boolean; Exponent: Integer; - Mantissa: TUInt64; var Value: Double); -begin - Mantissa := Mantissa and not (TUInt64(1) shl 52); // ȥ 52 λϵ 1еĻ - PUInt64(@Value)^ := Mantissa and CN_SIGNIFICAND_DOUBLE_MASK; - Inc(Exponent, CN_EXPONENT_OFFSET_DOUBLE); - - PUInt64(@Value)^ := PUInt64(@Value)^ or (TUInt64(Exponent) shl 52); - if SignNegative then - PUInt64(@Value)^ := PUInt64(@Value)^ or CN_SIGN_DOUBLE_MASK - else - PUInt64(@Value)^ := PUInt64(@Value)^ and not CN_SIGN_DOUBLE_MASK; -end; - -{$HINTS OFF} - -procedure CombineFloatExtended(SignNegative: Boolean; Exponent: Integer; - Mantissa: TUInt64; var Value: Extended); -var - D: Double; -begin - if (SizeOf(Extended) = CN_EXTENDED_SIZE_10) or (SizeOf(Extended) = CN_EXTENDED_SIZE_16) then - begin - PExtendedRec10(@Value)^.Mantissa := Mantissa; - Inc(Exponent, CN_EXPONENT_OFFSET_EXTENDED); - - PExtendedRec10(@Value)^.ExpSign := Exponent and CN_EXPONENT_EXTENDED_MASK; - if SignNegative then - PExtendedRec10(@Value)^.ExpSign := PExtendedRec10(@Value)^.ExpSign or CN_SIGN_EXTENDED_MASK - else - PExtendedRec10(@Value)^.ExpSign := PExtendedRec10(@Value)^.ExpSign and not CN_SIGN_EXTENDED_MASK; - end - else if SizeOf(Extended) = CN_EXTENDED_SIZE_8 then - begin - CombineFloatDouble(SignNegative, Exponent, Mantissa, D); - Value := D; - end - else - raise ECnFloatSizeError.Create(SCN_ERROR_EXTENDED_SIZE); -end; - -{$HINTS ON} - -procedure CombineFloatQuadruple(SignNegative: Boolean; Exponent: Integer; - MantissaLo, MantissaHi: TUInt64; var Value: Extended); -begin - if SizeOf(Extended) <> CN_EXTENDED_SIZE_16 then - raise ECnFloatSizeError.Create(SCN_ERROR_EXTENDED_SIZE); - - MantissaHi := MantissaHi and not (TUInt64(1) shl 48); // ȥ 112 λϵ 1еĻ - PCnQuadruple(@Value)^.Lo := MantissaLo; - PCnQuadruple(@Value)^.Hi0 := Cardinal(MantissaHi and $FFFFFFFF); - PCnQuadruple(@Value)^.Hi1 := (MantissaHi shr 32) and CN_SIGNIFICAND_QUADRUPLE_MASK; - - Inc(Exponent, CN_EXPONENT_OFFSET_EXTENDED); - PCnQuadruple(@Value)^.W1 := Exponent and CN_EXPONENT_QUADRUPLE_MASK; - if SignNegative then - PCnQuadruple(@Value)^.Hi1 := PCnQuadruple(@Value)^.Hi1 or CN_SIGN_QUADRUPLE_MASK - else - PCnQuadruple(@Value)^.Hi1 := PCnQuadruple(@Value)^.Hi1 and not CN_SIGN_QUADRUPLE_MASK; -end; - -// UInt64 Ϊ -function UFloat(U: TUInt64): Extended; -{$IFNDEF SUPPORT_UINT64} -var - L, H: Cardinal; -{$ENDIF} -begin -{$IFDEF SUPPORT_UINT64} - Result := U; -{$ELSE} - if U < 0 then // Int64 С 0 ʱ UInt64 Ǵ Int64 ֵ - begin - H := Int64Rec(U).Hi; - L := Int64Rec(U).Lo; - Result := Int64(H) * Int64(CN_MAX_UINT16 + 1); // - Result := Result * (CN_MAX_UINT16 + 1); - Result := Result + L; - end - else - Result := U; -{$ENDIF} -end; - -function UInt64ToSingle(U: TUInt64): Single; -begin - Result := UFloat(U); -end; - -function UInt64ToDouble(U: TUInt64): Double; -begin - Result := UFloat(U); -end; - -function UInt64ToExtended(U: TUInt64): Extended; -begin - Result := UFloat(U); -end; - -// ͨ Trunc ֻܷ Int64 UInt64 -function UTrunc(F: Extended): TUInt64; -var - T: Integer; - SignNeg: Boolean; - Exponent: Integer; - Mantissa: TUInt64; -begin - // õʵָ 1 ͷЧ֣С 1 - ExtractFloatExtended(F, SignNeg, Exponent, Mantissa); - if SignNeg then - raise ERangeError.Create(SRangeError); // ֧ - - // Mantissa 64 λЧ֣С 63 λָС 0 ˵СҪƣôֵ 0 - if Exponent < 0 then - Result := 0 - else - begin - // С Exponent λСߵ - T := 63 - Exponent; // С 0 63 λ 63 λұߣСƺ T λұ - if T < 0 then - raise ERangeError.Create(SRangeError); // Exponent ̫ - - Result := Mantissa shr T; - end; -end; - -function SingleToUInt64(F: Single): TUInt64; -begin - Result := UTrunc(F); -end; - -function DoubleToUInt64(F: Double): TUInt64; -begin - Result := UTrunc(F); -end; - -function ExtendedToUInt64(F: Extended): TUInt64; -begin - Result := UTrunc(F); -end; - -function SingleIsInfinite(AValue: Single): Boolean; -begin - Result := ((PCardinal(@AValue)^ and $7F800000) = $7F800000) and - ((PCardinal(@AValue)^ and $007FFFFF) = $00000000); -end; - -function DoubleIsInfinite(AValue: Double): Boolean; -begin - Result := ((PUInt64(@AValue)^ and $7FF0000000000000) = $7FF0000000000000) and - ((PUInt64(@AValue)^ and $000FFFFFFFFFFFFF) = $0000000000000000); -end; - -function ExtendedIsInfinite(AValue: Extended): Boolean; -begin - if SizeOf(Extended) = CN_EXTENDED_SIZE_10 then - Result := ((PExtendedRec10(@AValue)^.ExpSign and $7FFF) = $7FFF) and - ((PExtendedRec10(@AValue)^.Mantissa) = 0) - else if SizeOf(Extended) = CN_EXTENDED_SIZE_8 then - Result := DoubleIsInfinite(AValue) - else - raise ECnFloatSizeError.Create(SCN_ERROR_EXTENDED_SIZE); -end; - -function SingleIsNan(AValue: Single): Boolean; -begin - Result := ((PCardinal(@AValue)^ and $7F800000) = $7F800000) and - ((PCardinal(@AValue)^ and $007FFFFF) <> $00000000); -end; - -function DoubleIsNan(AValue: Double): Boolean; -begin - Result := ((PUInt64(@AValue)^ and $7FF0000000000000) = $7FF0000000000000) and - ((PUInt64(@AValue)^ and $000FFFFFFFFFFFFF) <> $0000000000000000); -end; - -function ExtendedIsNan(AValue: Extended): Boolean; -begin - if SizeOf(Extended) = CN_EXTENDED_SIZE_10 then - Result := ((PExtendedRec10(@AValue)^.ExpSign and $7FFF) = $7FFF) and - ((PExtendedRec10(@AValue)^.Mantissa and $7FFFFFFFFFFFFFFF) <> 0) - else if SizeOf(Extended) = CN_EXTENDED_SIZE_8 then - Result := DoubleIsNan(AValue) - else - raise ECnFloatSizeError.Create(SCN_ERROR_EXTENDED_SIZE); -end; - -end. +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnFloat; +{* |
+================================================================================
+* ƣ
+* ԪƣתԪ
+* ԪߣǬԪ(wqyfavor@163.com)
+*     עõԪʵ˵ȡ˫ȡչȸĽת
+*
+*           ע Extended ֻ Win32  10 ֽڣMacOS/Linux x64 ¾ 16 ֽڣWin64  ARM ƽ̨ 8 ֽ
+*           ңMacOS64 µ 16 ֽչȲ  IEEE 754-2008 й涨 Quadruple ʽǰ 10 ֽڽضϣ
+*           ڲṹͬ Win32 µչ 10 ֽڡ
+*
+* ƽ̨WinXP + Delphi 2009
+* ݲԣDelphi 2007 Extended ֻ֧Сģʽ
+*   õԪеַϱػʽ
+* ޸ļ¼2023.01.13
+*               ݴ Win64  Extended  8 ֽ Double  10 ֽչȵ
+*               ݴ MacOS64/Linux64 µ 16 ֽ Extendedֻضϴǰ 10 ֽڣ
+*           2022.02.17
+*                FPC ı֧֣
+*           2021.09.05
+*               תΪ UInt64֧ UInt64  Int64 棩ĺ
+*           2020.11.11
+*                UInt64֧ UInt64  Int64 棩תΪĺ
+*           2020.06.24
+*               ⿪ƴյĺ
+*           2009.1.12
+*               Ԫ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes, SysConst, {$IFDEF MSWINDOWS} Windows, {$ENDIF} CnNative; + +{ + IEEE 754 涨ָʽЧڵλ 0 + + Single 1 λ S8 λָ E23 λЧ M 24 λ 1 4 ֽ 32 λ + ˫ Double 1 λ S11 λָ E52 λЧ M 53 λ 1 8 ֽ 64 λ + չ˫ Extended 1 λ S15 λָ E64 λЧ M 64 λʽ 1 10 ֽ 80 λ + + IEEE 754-2008 + ı Quadruple 1 λ S15 λָ E112 λЧ M 16 ֽ 128 λ + ˱ Octuple 1 λ S19 λָ E236 λЧ M 32 ֽ 256 λ + + Уλ S0 ʾ1 ʾE Ҫȥ 127/1023/16383/16383 ָ + M: 淶/˫ȵĶ M ĸλӸ 1. Чչӣ 1. + ֵЧ 1.xxxx ʽ 2 E ηעⲻ 10 E η + + S λX ָM ЧֵʵֵΪ滯˲ҿС㣩 + + ʽ ֽ 1 ֽ 2 ֽ 3 ֽ 4 ... ֽ nÿֽڵұߵλ 0 + + 4 SXXXXXXX XMMMMMMM MMMMMMMM MMMMMMMM + 01000110 00011100 01000000 00000000 + 4 6 1 C 4 0 0 0 ڴΪСˣȫֵ򣩸ʵֵ 10000 + Ϊ 0 10001100 00111000100000000000000 + S0X140Ҫȥ 127 õʵ 13Mԭʼֵ 1C4000 + λ 1 С㣬õ 100111000100000000000000 ΪʵЧ֣ʵֵ 1.001110001 + ʵֵ1.001110001 13 λõʮ 2710.00Сȫ 0ʮ 10000 ʵʽ + + ˫ 8 SXXXXXXX XXXXMMMM MMMMMMMM MMMMMMMM ... MMMMMMMM + 01000000 11000011 10001000 0000000000000000000000000000000000000000 + 4 0 C 3 8 8 0 0 ڴΪСˣȫֵ򣩸ʵֵ 10000 + Ϊ 0 10000001100 0011100010000000000000000000000000000000000000000000 + S0X1036Ҫȥ 1023 õʵ 13Mԭʼֵ 3 88 00 00 00 00 00 + λ 1 Сõ 10011100010000000000000000000000000000000000000000000 ΪʵЧ֣ʵֵ 1.001110001 + ʵֵ1.001110001 13 λõʮ 2710.00Сȫ 0ʮ 10000 ʵʽ + + չ˫ 10 SXXXXXXX XXXXXXXX 1MMMMMMM MMMMMMMM ... MMMMMMMM // עЧְ 1඼ʡ 1 + 01000000 00001100 10011100 01000000 ... + 4 0 0 C 9 C 4 0 ڴΪСˣȫֵ򣩸ʵֵ 10000 + Ϊ 0 100000000001100 1001110000100000 ... + S0X16396Ҫȥ 16383 õʵ 13Mԭʼֵ 9C 40 00 ... + λö 1ֻҪСõ 10011100 01000000 ... ΪʵЧ֣ʵֵ 1.001110001 + ʵֵ1.001110001 13 λõʮ 2710.00Сȫ 0ʮ 10000 ʵʽ + + ı 16 SXXXXXXX XXXXXXXX MMMMMMMM MMMMMMMM ... MMMMMMMM + ˱ 32 SXXXXXXX XXXXXXXX XXXXMMMM MMMMMMMM ... MMMMMMMM + + ע⣺Little Endian ϣֽ 1 n 򡣱Ԫѵ + + 0ȫ 0 + -0ȫ 0 λΪ 1 + ָȫ 1Чȫ 0 0 1 +} + +type + TCnQuadruple = packed record + {* Delphi ıͣýṹָ} + Lo: TUInt64; + Hi0: Cardinal; + case Boolean of + True: (Hi1: Cardinal); + False: (W0, W1: Word); // С˻ϣźָ W1 + end; + PCnQuadruple = ^TCnQuadruple; + {* ָıȽṹָ} + + TCnOctuple = packed record + {* Delphi ް˱ͣ Int64 ָ棬޴} + F0: Int64; + F1: Int64; + F2: Int64; + F3: Int64; + end; + PCnOctuple = ^TCnOctuple; + {* ָ˱Ƚṹָ} + + ECnFloatSizeError = class(Exception); + {* 쳣} + +const + CN_EXTENDED_SIZE_8 = 8; + {* Win64 µ Extended ͵ijȣֻ 8 ֽ} + + CN_EXTENDED_SIZE_10 = 10; + {* Win32 µ Extended ͵ijȣDZ׼ 10 ֽ} + + CN_EXTENDED_SIZE_16 = 16; + {* MACOS64/Linux64 µ Extended ͵ijȣ 16 ֽ} + + CN_SIGN_SINGLE_MASK = $80000000; + {* ȸķλ} + + CN_SIGN_DOUBLE_MASK = $8000000000000000; + {* ˫ȸķλ} + + CN_SIGN_EXTENDED_MASK = $8000; + {* չȸķλ룬Ѿȥ 8 ֽЧ} + + CN_SIGN_QUADRUPLE_MASK = $80000000; + {* ıȸķλ룬ֻǰֽڣȥ˺} + + CN_EXPONENT_SINGLE_MASK = $7F800000; + {* ȸָ룬Ҫ 23 λ} + + CN_EXPONENT_DOUBLE_MASK = $7FF0000000000000; + {* ˫ȸָ룬Ҫ 52 λ} + + CN_EXPONENT_EXTENDED_MASK = $7FFF; + {* չȸָ룬ȥ 8 ֽЧ} + + CN_EXPONENT_QUADRUPLE_MASK = $7FFF; + {* ıȸָ룬ȥ 14 ֽЧ} + + CN_SIGNIFICAND_SINGLE_MASK = $007FFFFF; + {* ȸЧ룬 23 λ} + + CN_SIGNIFICAND_DOUBLE_MASK = $000FFFFFFFFFFFFF; + {* ˫ȸЧ룬 52 λ} + + CN_SIGNIFICAND_EXTENDED_MASK = $FFFFFFFFFFFFFFFF; + {* չȸЧ룬 64 λʵȫ 8 ֽ} + + CN_SIGNIFICAND_QUADRUPLE_MASK = $FFFF; + {* ıȸЧ룬ֻǰֽڣмϺ} + + CN_SINGLE_SIGNIFICAND_BITLENGTH = 23; + {* ȸЧλ} + + CN_DOUBLE_SIGNIFICAND_BITLENGTH = 52; + {* ˫ȸЧλ} + + CN_EXTENDED_SIGNIFICAND_BITLENGTH = 63; + {* չȸЧλ} + + CN_EXPONENT_OFFSET_SINGLE = 127; + {* ȸָƫֵʵֵָҪϸֵܴ뵥ȸָ} + + CN_EXPONENT_OFFSET_DOUBLE = 1023; + {* ˫ȸָƫֵʵֵָҪϸֵܴ˫ȸָ} + + CN_EXPONENT_OFFSET_EXTENDED = 16383; + {* չȸָƫֵʵֵָҪϸֵܴչȸָ10 16 ֽչȸΪֵ} + + // Max ָȫ 1 Σ + CN_SINGLE_MIN_EXPONENT = -127; + {* ȸСָ} + + CN_SINGLE_MAX_EXPONENT = 127; + {* ȸָ} + + CN_DOUBLE_MIN_EXPONENT = -1023; + {* ˫ȸСָ} + + CN_DOUBLE_MAX_EXPONENT = 1023; + {* ˫ȸָ} + + CN_EXTENDED_MIN_EXPONENT = -16383; + {* չȸСָ} + + CN_EXTENDED_MAX_EXPONENT = 16383; + {* չȸָ} + +procedure ExtractFloatSingle(Value: Single; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: Cardinal); +{* ӵȸнλָλ 1 ȥСЧ֡ + ע⣺ָΪʵָЧΪ 24 λԭʼΪ 0~22 λ 23 λΪȥ 1 + + + Value: Single - ⿪ĵȸ + out SignNegative: Boolean - λTrue Ϊ + out Exponent: Integer - ָ + out Mantissa: Cardinal - Ч + + ֵޣ +} + +procedure ExtractFloatDouble(Value: Double; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: TUInt64); +{* ˫ȸнλָλ 1 ȥСЧ֡ + ע⣺ָΪʵָЧΪ 53 λԭʼΪ 0~51 λ 52 λΪȥ 1 + + + Value: Double - ⿪˫ȸ + out SignNegative: Boolean - λTrue Ϊ + out Exponent: Integer - ָ + out Mantissa: TUInt64 - Ч + + ֵޣ +} + +procedure ExtractFloatExtended(Value: Extended; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: TUInt64); overload; +{* չȸнλָȥСЧ֣֧ 8 ֽڡ10 ֽڡ + Լ 16 ֽڽضΪ 10 ֽڵ Extended ʽúʵƽ̨ Extended ߴ硣 + ע⣺ָΪʵָЧΪȫ 64 λλ 63 λΪԴ 1 + + + Value: Extended - ⿪չȸ + out SignNegative: Boolean - λTrue Ϊ + out Exponent: Integer - ָ + out Mantissa: TUInt64 - Ч + + ֵޣ +} + +procedure ExtractFloatExtended(ValueAddr: Pointer; ExtendedSize: Integer; + out SignNegative: Boolean; out Exponent: Integer; out Mantissa: TUInt64); overload; +{* ӲȵչȸڵַнλָȥСЧ֣֧ 8 ֽڡ10 ֽڡ + Լ 16 ֽڽضΪ 10 ֽڵ Extended ʽúʵ뱾ƽ̨ Extended ߴ޹ء + ע⣺ָΪʵָЧΪȫ 64 λλ 63 λΪԴ 1 + + + ValueAddr: Pointer - ⿪չȸڵַ + ExtendedSize: Integer - չȵĴСֻ֧ 81016 ֵ + out SignNegative: Boolean - λTrue Ϊ + out Exponent: Integer - ָ + out Mantissa: TUInt64 - Ч + + ֵޣ +} + +procedure ExtractFloatQuadruple(Value: Extended; out SignNegative: Boolean; + out Exponent: Integer; out MantissaLo: TUInt64; out MantissaHi: TUInt64); +{* ʮֽھȸнλָȥСЧֻ֣ Extended Ϊ 16 ֽ + Ҹʽ IEEE 754-2008 ıȸʱЧĿǰ Delphi ָ֧øʽ + ע⣺ָΪʵָЧ 112 λΪߵ֣ԭʼΪ 0~110 λ 111 λΪȥ 1 + + + Value: Extended - ⿪ʮֽھȸ + out SignNegative: Boolean - λTrue Ϊ + out Exponent: Integer - ָ + out MantissaLo: TUInt64 - Чֵ 64 λ + out MantissaHi: TUInt64 - Чָ 64 λ + + ֵޣ +} + +procedure CombineFloatSingle(SignNegative: Boolean; Exponent: Integer; + Mantissa: Cardinal; var Value: Single); +{* ѷλָЧƴɵȸҪЧΪ滯ģҲ 24 λλΪ 1 + + + SignNegative: Boolean - λTrue Ϊ + Exponent: Integer - ָ + Mantissa: Cardinal - Ч֣ 24 λЧ + var Value: Single - ϵĵȸ + + ֵޣ +} + +procedure CombineFloatDouble(SignNegative: Boolean; Exponent: Integer; + Mantissa: TUInt64; var Value: Double); +{* ѷλָЧƴ˫ȸҪЧΪ滯ģҲ 53 λλΪ 1 + + + SignNegative: Boolean - λTrue Ϊ + Exponent: Integer - ָ + Mantissa: TUInt64 - Ч֣ 53 λЧ + var Value: Double - ϵ˫ȸ + + ֵޣ +} + +procedure CombineFloatExtended(SignNegative: Boolean; Exponent: Integer; + Mantissa: TUInt64; var Value: Extended); overload; +{* ѷλָЧƴչȸ֧ 10 ֽڡ + Լ 16 ֽڽضΪ 10 ֽڵ Extended ʽúʵƽ̨ Extended ߴ硣 + ҪЧΪ滯ģҲ 64 λλΪ 1 + + + SignNegative: Boolean - λTrue Ϊ + Exponent: Integer - ָ + Mantissa: TUInt64 - Ч֣64 λȫЧ + var Value: Extended - ϵչȸ + + ֵޣ +} + +procedure CombineFloatExtended(SignNegative: Boolean; Exponent: Integer; + Mantissa: TUInt64; ValueAddr: Pointer; ExtendedSize: Integer); overload; +{* ѷλָЧƴչȸ֧ 10 ֽڡ + Լ 16 ֽڽضΪ 10 ֽڵ Extended ʽúʵ뱾ƽ̨ Extended ߴ޹ء + ҪЧΪ滯ģҲ 64 λλΪ 1 + + + SignNegative: Boolean - λTrue Ϊ + Exponent: Integer - ָ + Mantissa: TUInt64 - Ч֣64 λȫЧ + ValueAddr: Pointer - ϵչȸĵַ + ExtendedSize: Integer - չȵĴСֻ֧ 81016 ֵ + + ֵޣ +} + +procedure CombineFloatQuadruple(SignNegative: Boolean; Exponent: Integer; + MantissaLo: TUInt64; MantissaHi: TUInt64; var Value: Extended); +{* ѷλָЧƴչȸֻ Extended Ϊ 16 ֽ + Ҹʽ IEEE 754-2008 ıȸʱЧĿǰ Delphi ָ֧øʽ + ҪЧΪ滯ģҲ 112 λλΪ 1 + + + SignNegative: Boolean - λTrue Ϊ + Exponent: Integer - ָ + MantissaLo: TUInt64 - Чֵ 64 λ64 λȫЧ + MantissaHi: TUInt64 - Чָ 64 λ 48 λЧ + var Value: Extended - ϵʮֽھȸ + + ֵޣ +} + +function UInt64ToSingle(U: TUInt64): Single; +{* Int64 зģ 64 λ޷͸ֵ Singleʵͬ + + + U: TUInt64 - ֵ 64 λ޷ֵ + + ֵSingle - صĵȸ +} + +function UInt64ToDouble(U: TUInt64): Double; +{* Int64 зģ 64 λ޷͸ֵ Doubleʵͬ + + + U: TUInt64 - ֵ 64 λ޷ֵ + + ֵDouble - ص˫ȸ +} + +function UInt64ToExtended(U: TUInt64): Extended; +{* Int64 зģ 64 λ޷͸ֵ Extendedʵͬ + + + U: TUInt64 - ֵ 64 λ޷ֵ + + ֵExtended - صչȸ +} + +function SingleToUInt64(F: Single): TUInt64; +{* Single ֵ Int64 зģ 64 λ޷ͣʵͬ + + + F: Single - ֵĵȸ + + ֵTUInt64 - ص 64 λ޷ֵ +} + +function DoubleToUInt64(F: Double): TUInt64; +{* Double ֵ Int64 зģ 64 λ޷ͣʵͬ + + + F: Double - ֵ˫ȸ + + ֵTUInt64 - ص 64 λ޷ֵ +} + +function ExtendedToUInt64(F: Extended): TUInt64; +{* Extended ֵ Int64 зģ 64 λ޷ͣʵͬ + + + F: Extended - ֵ˫ȸ + + ֵTUInt64 - ص 64 λ޷ֵ +} + +function SingleIsInfinite(AValue: Single): Boolean; +{* ȸǷ + + + AValue: Single - жϵĵȸ + + ֵBoolean - Ƿ +} + +function DoubleIsInfinite(AValue: Double): Boolean; +{* ˫ȸǷ + + + AValue: Double - жϵ˫ȸ + + ֵBoolean - Ƿ +} + +function ExtendedIsInfinite(AValue: Extended): Boolean; +{* չȸǷ + + + AValue: Extended - жϵչȸ + + ֵBoolean - Ƿ +} + +function SingleIsNan(AValue: Single): Boolean; +{* ȸǷʵ + + + AValue: Single - жϵĵȸ + + ֵBoolean - Ƿʵ +} + +function DoubleIsNan(AValue: Double): Boolean; +{* ˫ȸǷʵ + + + AValue: Double - жϵ˫ȸ + + ֵBoolean - Ƿʵ +} + +function ExtendedIsNan(AValue: Extended): Boolean; +{* չȸǷʵ + + + AValue: Extended - жϵչȸ + + ֵBoolean - Ƿʵ +} + +function ExtendedToStr(AValue: Extended): string; +{* չȸתΪַ֧ľȡ + Delphi Ĭ 15 λС 18Ҳ֧ 1234567899876543.21 + + + AValue: Extended - жϵչȸ + + ֵstring - ת +} + +// FPCWindows 64/Linux 64 ƽ̨Լ Delphi 56 ֧ +{$IFDEF WIN32} +{$IFDEF COMPILER7_UP} +{ + ˴ʵ Extended תΪˡʮַĺ + 㷨Ƕȡ Extended ڴеĶݽת Extended ͵˵ + ԲοϡDouble Single Ϊϵͳֵ֧ͨĸͣ Delphi е + Extended ڴ洢ʽвͬ߾β񻯣 Double Single β + Ĭϵ 1βΪ 1.001 Double Single д洢Ϊ 001ȥ + Сǰ 1 Extended 洢Ϊ 1001 + NaN Ϊ "not a number"Ǹο Math.pas Ԫеij NaN + Infinity Ϊ󣬶ο Math.pas Ԫеij Infinity NegInfinity. + һ DecimalExp AlwaysUseExponent + ʮƸתʱָʽѧ㷨Щ + Ҳָֻʽ 1E-1000ָʱ 0.0000000...0001תָ + ҲӦӦƱʾʱʮƱʾָ֣ƴ + 1.001E101ֵΪ 100100ָʮƱһЩ 1.001D5ʾС + 5 λDecimalExp ָǷʮƱֵָġע⣬ʮ + ʾָ޹涨﷨ʹ "D" ʾ"E" ΪӦƱʾ⣬ + ʮƱȽ⣬"D" "E" ΪʮַʮƱʱʹ "^" + ַ 3.BD^D(12)A.BD^E(ABCE)粻ϲָʽ޸ġ + AlwaysUseExponent ָǷһÿѧ 100.111 λȽ٣ + ԶжϲҪʹÿѧ AlwaysUseExponent ΪʱһΪָ + ʽ 1.00111E2 + const + MaxBinDigits = 120; + MaxHexDigits = 30; + MaxOctDigits = 40; + ָλʱһʹÿѧ +} + +{ FloatDecimalToBinExtended, FloatDecimalToOctExtendedFloatDecimalToHexExtended + FloatDecimalToBinaryExtended ̣FloatDecimalToBinaryExtended } + +function FloatDecimalToBinExtended(fIn: Extended; DecimalExp: Boolean; + AlwaysUseExponent: Boolean): AnsiString; deprecated; // Convert to binary + +function FloatDecimalToOctExtended(fIn: Extended; DecimalExp: Boolean; + AlwaysUseExponent: Boolean): AnsiString; deprecated; // Convert to octal + +function FloatDecimalToHexExtended(fIn: Extended; DecimalExp: Boolean; + AlwaysUseExponent: Boolean): AnsiString; deprecated; // Convert to hexdecimal + +{$ENDIF} +{$ENDIF} + +implementation + +const + UINT64_EXTENDED_EXP_MAX = $4040; // UINT64 Ӧ Extended ָ + +resourcestring + SCnErrorExtendedSizeFmt = 'Extended Size Error %d'; + +type + TExtendedRec10 = packed record + {* 10 ֽڵչȸֻ Win32 Ч} + Mantissa: TUInt64; + ExpSign: Word; + end; + PExtendedRec10 = ^TExtendedRec10; + +{$IFDEF WIN32} +{$IFDEF COMPILER7_UP} + +type + PConvertFloatSystem = ^TConvertFloatSystem; + TConvertFloatSystem = record + Negative: Boolean; + ExpFlag, ExponentI: Integer; + end; + +const + MaxBinDigits = 120; + MaxHexDigits = 30; + MaxOctDigits = 40; + +function FloatDecimalToBinaryExtended(fIn: Extended; DecimalExp, + AlwaysUseExponent: Boolean; var ForHexOct: PConvertFloatSystem): AnsiString; +var + Neg: Boolean; + i, Flag, IntExp: Integer; + Exp: AnsiString; +label UseExponent; +begin +{ +Extended(32.125) in memory: +0 100000000000100 10000000 10000000 00000000 00000000 00000000 00000000 00000000 00000000 + 9 8 7 6 5 4 3 2nd Byte 1stByte 0 +sign exponent digits +0 111111111111111 1000000000000000000000000000000000000000000000000000000000000000 + Inf +1 111111111111111 1000000000000000000000000000000000000000000000000000000000000000 - Inf +1 111111111111111 1100000000000000000000000000000000000000000000000000000000000000 Nan +0 111111111111111 1100000000000000000000000000000000000000000000000000000000000000 -Nan +} + SetLength(Result, 255); + SetLength(Exp, 2 * SizeOf(Extended) + 1); + Neg := False; + asm + push EBX + push ESI + mov EBX, Result // Address of Result + mov EBX, [EBX] + mov EAX, 0 + // Test if fIN equals 0 + lea ESI, fIn[7] // get the first byte of digits + mov AL, [ESI] + test AL, 128 // 10000000B + jz @Zero + mov ECX, 0 + lea ESI, fIn[8] + mov AX, [ESI] // Get first two bytes + test AX, 32768 // 32768D = 1000000000000000B + jz @Positive + mov Neg, 1 + sub AX, 32768 // Sign bit <- 0 + @Positive: + // Test if fIn is NaN or Infinity + cmp AX, 32767 + jnz @NotNAN_INF + mov DL, [ESI - 1] + test DL, 64 // 01000000B + jz @INF + mov Flag, 4 // NaN + jmp @Done + @INF: + mov Flag, 3 // INF + jmp @Done + @NotNAN_INF: + sub AX, 16383 // AX = AX - 011111111111111B + jns @ExpPositive + sub AX, 1 + not AX + mov Flag, 2 // // Exponent sign negative + jmp @JudgeDecimalExp + @ExpPositive: + mov Flag, 1 // Exponent sign positive + @JudgeDecimalExp: + mov IntExp, EAX + cmp DecimalExp, 1 + je @MoveDigits + // Binary string exponent. Convert AX to binary string and store it in Exp + lea EBX, Exp + mov EBX, [EBX] + push ECX + mov [EBX], 69 // 'E' // "D" for decimal exponent + mov ECX, 1 + cmp Flag, 2 + jnz @NoNegativeInExp + mov [EBX + 1], 45 // '-' // Add a "-" to exponent string + mov ECX, 2 + @NoNegativeInExp: + mov ESI, 0 // flag whehter "1" appears + // Move exponent digits to Exp + mov DX, 32768 // 1000000000000000 + @NextExpDigit: + test AX, DX + jz @AppendExp0 + mov [EBX + ECX], 49 // '1' + mov ESI, 1 + jmp @NextExpIncECX + @AppendExp0: + cmp ESI, 0 + jz @NextExpNoIncECX // do not append this "0" + mov [EBX + ECX], 48 // '0' + @NextExpIncECX: + inc ECX + @NextExpNoIncECX: + shr DX, 1 + cmp DX, 0 + jne @NextExpDigit + pop ECX + mov EBX, Result + mov EBX, [EBX] + jmp @MoveDigits + @MoveDigits: + // Move digits to Result + mov ESI, 8 + @NextByte: + dec ESI + mov EAX, EBX + lea EBX, fIn[ESI] + mov DL, [EBX] + mov EBX, EAX + mov AL, 128 // 10000000 + @NextDigit: + test DL, AL + jz @Append0 + mov [EBX + ECX], 49 // '1' + mov i, ECX + jmp @Next + @Append0: + mov [EBX + ECX], 48 // '0' + @Next: + inc ECX + shr AL, 1 + cmp AL, 0 + jne @NextDigit + cmp ESI, 0 // if the last byte + jne @NextByte + jmp @Done + @Zero: + mov Flag, 0 + @Done: + pop ESI + pop EBX + end; + case Flag of + 0: + begin + ForHexOct := nil; + Result := '0'; + Exit; + end; + 1, 2: + begin + // Delete redundant "0" in Result + Delete(Result, i + 2, MaxInt); // i stores the position of the last 1 in Result + if Assigned(ForHexOct) then + begin + // Copy to ForHexOct + with ForHexOct^ do + begin + Negative := Neg; + ExpFlag := Flag; + ExponentI := IntExp; + end; + Exit; + end; + // Add dot and exponent to Result + if (IntExp = 0) then + begin + if (Length(Result) > 1) then + Insert('.', Result, 2); + end + else + begin + { Decide whether use exponent. For example "1000.101" shouldn't be output + as 1.000101E11 when AlwaysUseExponent is False. } + if AlwaysUseExponent then + begin +UseExponent: + if DecimalExp then + if Flag = 1 then + Exp := 'D' + {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(IntExp)) + else + Exp := 'D-' + {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(IntExp)); + if Length(Result) >=2 then + Insert('.', Result, 2); + Result := Result + Exp; + end + else + begin + // IntExp may be negative. + if Flag = 1 then + begin + // Calculate all digits required without exponent + if IntExp <= Length(Result) - 2 then + begin + // Do not use exponent + Insert('.', Result, IntExp + 2); + end + else if IntExp = Length(Result) - 1 then + { 1.001, Exp = 3, output 1001 } + else + begin + if IntExp + 1> MaxBinDigits then + goto UseExponent + else + begin + Inc(IntExp); + i := Length(Result); + // Add zeros at tail + SetLength(Result, IntExp); + for i := i + 1 to IntExp do + Result := '0'; + end; + end; + end + else + begin + if IntExp + Length(Result) > MaxBinDigits then + goto UseExponent + else + begin + // Add leading zeros and place "." + SetLength(Exp, 1 + IntExp); + Exp[1] := '0'; + Exp[2] := '.'; + for i := 3 to IntExp + 1 do + Exp := '0'; //} + Result := Exp + Result; + end; + end; + end; + end; + end; + 3: // INF + begin + ForHexOct := nil; + Result := 'INF'; + end; + 4: // NaN + begin + ForHexOct := nil; + Result := 'NaN'; + Exit; + end; + end; + if Neg then + Result := '-' + Result; +end; + +function FloatDecimalToBinExtended(fIn: Extended; DecimalExp, + AlwaysUseExponent: Boolean): AnsiString; +var + PTmp: PConvertFloatSystem; +begin + PTmp := nil; + Result := FloatDecimalToBinaryExtended(fIn, DecimalExp, AlwaysUseExponent, PTmp); +end; + +function FloatDecimalToHexExtended(fIn: Extended; DecimalExp, + AlwaysUseExponent: Boolean): AnsiString; +const + DecToHex: array[0..15] of AnsiChar = + ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); + BinPow: array[0..3] of Integer = (8, 4, 2, 1); + + function IntToHex(Int: Integer): AnsiString; + var + k ,t: Integer; + Buf: array[1..5] of AnsiChar; + begin + k := 1; + while (Int <> 0) do + begin + Buf[k] := DecToHex[Int mod 16]; + Inc(k); + Int := Int div 16; + end; + Dec(k); + SetLength(Result, k); + t := 1; + while (k > 0) do + begin + Result[t] := Buf[k]; + Inc(t); + Dec(k); + end; + end; + + function ToHex(const S: AnsiString; LeftToDot: Boolean): AnsiString; + var + i, l, t, m, k: Integer; + Buf: array[1..20] of AnsiChar; + begin + { LeftToDot = True, S will be patched with zeroes on its left side. + For example, S = '110', after patching, S = '0110'. + LeftToDot = False, S will be patched with zeroes on its right side. + S = '110', after patching, S = '1100'. } + l := Length(S); + if LeftToDot then + t := (4 - (l mod 4)) mod 4 + else + t := 0; + i := 1; + m := 1; + k := 0; + while i <= l do + begin + k := k + BinPow[t] * (Ord(S[i]) - Ord('0')); + Inc(t); + if (t = 4) or (i = l) then + begin + Buf[m] := DecToHex[k]; + Inc(m); + k := 0; + t := 0; + end; + Inc(i); + end; + Dec(m); + SetLength(Result, m); + + while (m > 0) do + begin + Result[m] := Buf[m]; + Dec(m); + end; + end; + +var + PConvertData: PConvertFloatSystem; + ConvertData: TConvertFloatSystem; + tmpS: AnsiString; + k, t, i, m: Integer; +label UseExponent; +begin + PConvertData := @ConvertData; + Result := FloatDecimalToBinaryExtended(fIn, True, True, PConvertData); + // See FloatDecimalToBinaryExtended, PConvertData is set to nil when result is definite. + if PConvertData = nil then + Exit; + with ConvertData do + begin + { 3.BD^D(12) + A.BD^E(ABCE) + AB.FFFF } + k := Length(Result) - 1; + if AlwaysUseExponent then + begin +UseExponent: + { Algorithm: + X.XXXXXXXX^Y Shift Count Exp + 1.00000001^0 = 1.00000001 = 1.01^0 (16) + 1.00000001^1 = 10.0000001 = 2.02^0 (16) + 1.00000001^2 = 100.000001 = 4.04^0 (16) + 1.00000001^3 = 1000.00001 = 8.08^0 (16) + 1.00000001^4 = 1.00000001^100 = 1.01^1 (16) + 1.00000001^5 = 10.0000001^100 = 2.02^1 (16) + Shift Count = Y mod 4 + Exp = Y div 4 + X.XXXXXXXXX^Y Y < 0 Exp + 1.00000001^-1 = 0.100000001 = 1000.00001^-100 = 8.08^-1 + 1.00000001^-2 = 0.0100000001 = 100.000001^-100 = 4.04^-1 + 1.00000001^-3 = 0.00100000001 = 10.0000001^-100 = 2.02^-1 + 1.00000001^-4 = 0.000100000001 = 1.00000001^-100 = 1.01^-1 + 1.00000001^-5 = 0.0000100000001 = 1000.00001^-100 = 8.08^-2 + Shift Count = 4 - (Abs(Y) mod 4) + Exp = -(Abs(Y) div 4 + 1) } + if ExpFlag = 1 then + begin + t := ExponentI div 4; // Exp + i := ExponentI mod 4; // Shift Count + end + else + begin + t := -((ExponentI - 1) div 4 + 1); // Exp + i := (4 - (ExponentI mod 4)) mod 4; // Shift Count + end; + // Get hex digits + if k < i then + begin + // Add extra zeroes + SetLength(Result, i + 1); + for m := k + 2 to i + 1 do + Result[m] := '0'; + Result := ToHex(Result, True); + end + else if k = i then + Result := ToHex(Result, True) + else + begin + tmpS := Copy(Result, 1, i + 1); + Delete(Result, 1, i + 1); + Result := ToHex(tmpS, True) + '.' + ToHex(Result, False); + end; + if t <> 0 then + begin + // Format exponent + if DecimalExp then + Result := Result + '^D(' + {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(t)) + ')' + else + begin + if ExpFlag = 1 then + Result := Result + '^E(' + IntToHex(t) + ')' + else // t < 0 + Result := Result + '^E(-' + IntToHex(-t) + ')'; + end; + end; + end + else + begin + { Always remember that Result equals "XXXXXXXX" not "X.XXXXXXX". + Judge whether to use exponent: + There are K "X" after '.', K = Length(Result) - 1, no "." in Result originally. + X.XXXXXXX^Y (Binary string, ExponentI = Abs(Y)) + case Y >= 0 (Condition: ExpFlag = 2) + Y <= K: + Y+1 binary digits on left side of '.', K-Y digits on right side + totally requires ((Y+1 - 1) div 4 + 1) + ((K-Y - 1) div 4 + 1) hex digits + Y > K: + Y+1 binary digits on left side, totally ((Y+1 - 1) div 4 + 1) hex digits + case Y<0 (Condition: ExpFlag = 1) 0.XXXX or 0.000XXXX + One digit '0' on left side and K+1+Abs(Y)-1 digits on right side, + totally 1 + ((K+1+Abs(Y)-1-1) div 4 + 1) hex digits. + Compare hdc = hex digit count with MaxHexDigits. If hdc > MaxHexDigits, + goto UseExponent. } + if ExponentI = 0 then + begin + if (Length(Result) > 1) then + Result := '1.' + ToHex(Copy(Result, 2, MaxInt), False); + end + else + begin + if ExpFlag = 1 then + begin + if ExponentI < k then + begin + // No possible that "ExponentI div 4 + (k - ExponentI - 1) div 4 + 2" > MaxHexDigits + tmpS := Copy(Result, 1, ExponentI + 1); + Delete(Result, 1, ExponentI + 1); + Result := ToHex(tmpS, True) + '.' + ToHex(Result, False); + end + else if ExponentI = k then + // 1.01^2 = 101, no ".", no extra "0". + Result := ToHex(Result, True) + else + begin + t := ExponentI div 4 + 1; + if t > MaxHexDigits then + goto UseExponent + else + begin + // Append "0" after Result + Inc(ExponentI); + // Add '0' to Result + SetLength(Result, ExponentI); + for t := k + 2{original Length(Result) + 1} to ExponentI do + Result[t] := '0'; + Result := ToHex(Result, True); + end; + end; + end + else + begin + // ExpFlag = 2, X.XXXXXXX^Y, Y < 0 + t := 2 + (k + ExponentI - 1) div 4; {1 + ((K+1+Abs(Y)-1-1) div 4 + 1)} + if t > MaxHexDigits then + goto UseExponent + else + begin + // Add leading zeroes before Result + SetLength(tmpS, ExponentI - 1); // tmpS stores extra zeroes + for t := 1 to ExponentI - 1 do + tmpS[t] := '0'; + Result := '0.' + ToHex(tmpS + Result, False); + end; + end; + end; + end; + if Negative then + Result := '-' + Result; + end; +end; + +function FloatDecimalToOctExtended(fIn: Extended; DecimalExp, + AlwaysUseExponent: Boolean): AnsiString; +const + DecToOct: array[0..7] of AnsiChar = + ('0', '1', '2', '3', '4', '5', '6', '7'); + BinPow: array[0..2] of Integer = (4, 2, 1); + + function IntToOct(Int: Integer): AnsiString; + var + k ,t: Integer; + Buf: array[1..10] of AnsiChar; + begin + k := 1; + while (Int <> 0) do + begin + Buf[k] := DecToOct[Int mod 8]; + Inc(k); + Int := Int div 8; + end; + Dec(k); + SetLength(Result, k); + t := 1; + while (k > 0) do + begin + Result[t] := Buf[k]; + Inc(t); + Dec(k); + end; + end; + + function ToOct(const S: AnsiString; LeftToDot: Boolean): AnsiString; + var + i, l, t, m, k: Integer; + Buf: array[1..30] of AnsiChar; + begin + { LeftToDot = True, S will be patched with zeroes on its left side. + For example, S = '110', after patching, S = '0110'. + LeftToDot = False, S will be patched with zeroes on its right side. + S = '110', after patching, S = '1100'. } + l := Length(S); + if LeftToDot then + t := (3 - (l mod 3)) mod 3 + else + t := 0; + i := 1; + m := 1; + k := 0; + while i <= l do + begin + k := k + BinPow[t] * (Ord(S[i]) - Ord('0')); + Inc(t); + if (t = 3) or (i = l) then + begin + Buf[m] := DecToOct[k]; + Inc(m); + k := 0; + t := 0; + end; + Inc(i); + end; + Dec(m); + SetLength(Result, m); + + while (m > 0) do + begin + Result[m] := Buf[m]; + Dec(m); + end; + end; + +var + PConvertData: PConvertFloatSystem; + ConvertData: TConvertFloatSystem; + tmpS: AnsiString; + k, t, i, m: Integer; +label UseExponent; +begin + PConvertData := @ConvertData; + Result := FloatDecimalToBinaryExtended(fIn, True, True, PConvertData); + // See FloatDecimalToBinaryExtended, PConvertData is set to nil when result is definite. + if PConvertData = nil then + Exit; + with ConvertData do + begin + { 3.333D12 // 12 is decimal + 2.22E33 // 33 is octal} + k := Length(Result) - 1; + if AlwaysUseExponent then + begin +UseExponent: + if ExpFlag = 1 then + begin + t := ExponentI div 3; // Exp + i := ExponentI mod 3; // Shift Count + end + else + begin + t := -((ExponentI - 1) div 3 + 1); // Exp + i := (3 - (ExponentI mod 3)) mod 3; // Shift Count + end; + // Get hex digits + if k < i then + begin + // Add extra zeroes + SetLength(Result, i + 1); + for m := k + 2 to i + 1 do + Result[m] := '0'; + Result := ToOct(Result, True); + end + else if k = i then + Result := ToOct(Result, True) + else + begin + tmpS := Copy(Result, 1, i + 1); + Delete(Result, 1, i + 1); + Result := ToOct(tmpS, True) + '.' + ToOct(Result, False); + end; + if t <> 0 then + begin + // Format exponent + if DecimalExp then + Result := Result + 'D' + {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(t)) + else + begin + if ExpFlag = 1 then + Result := Result + 'E' + IntToOct(t) + else // t < 0 + Result := Result + 'E-' + IntToOct(-t); + end; + end; + end + else + begin + if ExponentI = 0 then + begin + if (Length(Result) > 1) then + Result := '1.' + ToOct(Copy(Result, 2, MaxInt), False); + end + else + begin + if ExpFlag = 1 then + begin + if ExponentI < k then + begin + tmpS := Copy(Result, 1, ExponentI + 1); + Delete(Result, 1, ExponentI + 1); + Result := ToOct(tmpS, True) + '.' + ToOct(Result, False); + end + else if ExponentI = k then + // 1.01^2 = 101, no ".", no extra "0". + Result := ToOct(Result, True) + else + begin + t := ExponentI div 3 + 1; + if t > MaxHexDigits then + goto UseExponent + else + begin + // Append "0" after Result + Inc(ExponentI); + // Add '0' to Result + SetLength(Result, ExponentI); + for t := k + 2{original Length(Result) + 1} to ExponentI do + Result[t] := '0'; + Result := ToOct(Result, True); + end; + end; + end + else + begin + // ExpFlag = 2, X.XXXXXXX^Y, Y < 0 + t := 2 + (k + ExponentI - 1) div 3; + if t > MaxHexDigits then + goto UseExponent + else + begin + // Add leading zeroes before Result + SetLength(tmpS, ExponentI - 1); // tmpS stores extra zeroes + for t := 1 to ExponentI - 1 do + tmpS[t] := '0'; + Result := '0.' + ToOct(tmpS + Result, False); + end; + end; + end; + end; + if Negative then + Result := '-' + Result; + end; +end; + +{$ENDIF} +{$ENDIF} + +procedure ExtractFloatSingle(Value: Single; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: Cardinal); +begin + SignNegative := (PCardinal(@Value)^ and CN_SIGN_SINGLE_MASK) <> 0; + Exponent := ((PCardinal(@Value)^ and CN_EXPONENT_SINGLE_MASK) shr 23) - CN_EXPONENT_OFFSET_SINGLE; + Mantissa := PCardinal(@Value)^ and CN_SIGNIFICAND_SINGLE_MASK; + Mantissa := Mantissa or (1 shl 23); // λټӸ 1 +end; + +procedure ExtractFloatDouble(Value: Double; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: TUInt64); +begin + SignNegative := (PUInt64(@Value)^ and CN_SIGN_DOUBLE_MASK) <> 0; + Exponent := ((PUInt64(@Value)^ and CN_EXPONENT_DOUBLE_MASK) shr 52) - CN_EXPONENT_OFFSET_DOUBLE; + Mantissa := PUInt64(@Value)^ and CN_SIGNIFICAND_DOUBLE_MASK; + Mantissa := Mantissa or (TUInt64(1) shl 52); // λټӸ 1 +end; + +procedure ExtractFloatExtended(Value: Extended; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: TUInt64); +begin + if (SizeOf(Extended) = CN_EXTENDED_SIZE_10) or (SizeOf(Extended) = CN_EXTENDED_SIZE_16) then + begin + SignNegative := (PExtendedRec10(@Value)^.ExpSign and CN_SIGN_EXTENDED_MASK) <> 0; + Exponent := (PExtendedRec10(@Value)^.ExpSign and CN_EXPONENT_EXTENDED_MASK) - CN_EXPONENT_OFFSET_EXTENDED; + Mantissa := PExtendedRec10(@Value)^.Mantissa; // 1ü + end + else if SizeOf(Extended) = CN_EXTENDED_SIZE_8 then + ExtractFloatDouble(Value, SignNegative, Exponent, Mantissa) + else + raise ECnFloatSizeError.CreateFmt(SCnErrorExtendedSizeFmt, [SizeOf(Extended)]); +end; + +procedure ExtractFloatExtended(ValueAddr: Pointer; ExtendedSize: Integer; + out SignNegative: Boolean; out Exponent: Integer; out Mantissa: TUInt64); +var + D: Double; +begin + if (ExtendedSize = CN_EXTENDED_SIZE_10) or (ExtendedSize = CN_EXTENDED_SIZE_16) then + begin + SignNegative := (PExtendedRec10(ValueAddr)^.ExpSign and CN_SIGN_EXTENDED_MASK) <> 0; + Exponent := (PExtendedRec10(ValueAddr)^.ExpSign and CN_EXPONENT_EXTENDED_MASK) - CN_EXPONENT_OFFSET_EXTENDED; + Mantissa := PExtendedRec10(ValueAddr)^.Mantissa; // 1ü + end + else if ExtendedSize = CN_EXTENDED_SIZE_8 then + begin + Move(ValueAddr^, D, SizeOf(Double)); + ExtractFloatDouble(D, SignNegative, Exponent, Mantissa); + end + else + raise ECnFloatSizeError.CreateFmt(SCnErrorExtendedSizeFmt, [SizeOf(Extended)]); +end; + +procedure ExtractFloatQuadruple(Value: Extended; out SignNegative: Boolean; + out Exponent: Integer; out MantissaLo, MantissaHi: TUInt64); +begin + if SizeOf(Extended) <> CN_EXTENDED_SIZE_16 then + raise ECnFloatSizeError.CreateFmt(SCnErrorExtendedSizeFmt, [SizeOf(Extended)]); + + SignNegative := (PCnQuadruple(@Value)^.W1 and CN_SIGN_QUADRUPLE_MASK) <> 0; + Exponent := (PCnQuadruple(@Value)^.W1 and CN_EXPONENT_QUADRUPLE_MASK) - CN_EXPONENT_OFFSET_EXTENDED; + + // Extract 16 Bytes to Mantissas + MantissaLo := PCnQuadruple(@Value)^.Lo; + MantissaHi := TUInt64(PCnQuadruple(@Value)^.Hi0) or (TUInt64(PCnQuadruple(@Value)^.W0) shl 32) or (TUInt64(1) shl 48); // λټӸ 1 +end; + +procedure CombineFloatSingle(SignNegative: Boolean; Exponent: Integer; + Mantissa: Cardinal; var Value: Single); +begin + Mantissa := Mantissa and not (1 shl 23); // ȥ 23 λϵ 1еĻ + PCardinal(@Value)^ := Mantissa and CN_SIGNIFICAND_SINGLE_MASK; + Inc(Exponent, CN_EXPONENT_OFFSET_SINGLE); + + PCardinal(@Value)^ := PCardinal(@Value)^ or (LongWord(Exponent) shl 23); + if SignNegative then + PCardinal(@Value)^ := PCardinal(@Value)^ or CN_SIGN_SINGLE_MASK + else + PCardinal(@Value)^ := PCardinal(@Value)^ and not CN_SIGN_SINGLE_MASK; +end; + +procedure CombineFloatDouble(SignNegative: Boolean; Exponent: Integer; + Mantissa: TUInt64; var Value: Double); +begin + Mantissa := Mantissa and not (TUInt64(1) shl 52); // ȥ 52 λϵ 1еĻ + PUInt64(@Value)^ := Mantissa and CN_SIGNIFICAND_DOUBLE_MASK; + Inc(Exponent, CN_EXPONENT_OFFSET_DOUBLE); + + PUInt64(@Value)^ := PUInt64(@Value)^ or (TUInt64(Exponent) shl 52); + if SignNegative then + PUInt64(@Value)^ := PUInt64(@Value)^ or CN_SIGN_DOUBLE_MASK + else + PUInt64(@Value)^ := PUInt64(@Value)^ and not CN_SIGN_DOUBLE_MASK; +end; + +{$HINTS OFF} + +procedure CombineFloatExtended(SignNegative: Boolean; Exponent: Integer; + Mantissa: TUInt64; var Value: Extended); +var + D: Double; +begin + if (SizeOf(Extended) = CN_EXTENDED_SIZE_10) or (SizeOf(Extended) = CN_EXTENDED_SIZE_16) then + begin + PExtendedRec10(@Value)^.Mantissa := Mantissa; + Inc(Exponent, CN_EXPONENT_OFFSET_EXTENDED); + + PExtendedRec10(@Value)^.ExpSign := Exponent and CN_EXPONENT_EXTENDED_MASK; + if SignNegative then + PExtendedRec10(@Value)^.ExpSign := PExtendedRec10(@Value)^.ExpSign or CN_SIGN_EXTENDED_MASK + else + PExtendedRec10(@Value)^.ExpSign := PExtendedRec10(@Value)^.ExpSign and not CN_SIGN_EXTENDED_MASK; + end + else if SizeOf(Extended) = CN_EXTENDED_SIZE_8 then + begin + CombineFloatDouble(SignNegative, Exponent, Mantissa, D); + Value := D; + end + else + raise ECnFloatSizeError.CreateFmt(SCnErrorExtendedSizeFmt, [SizeOf(Extended)]); +end; + +procedure CombineFloatExtended(SignNegative: Boolean; Exponent: Integer; + Mantissa: TUInt64; ValueAddr: Pointer; ExtendedSize: Integer); +var + D: Double; +begin + if (ExtendedSize = CN_EXTENDED_SIZE_10) or (ExtendedSize = CN_EXTENDED_SIZE_16) then + begin + PExtendedRec10(ValueAddr)^.Mantissa := Mantissa; + Inc(Exponent, CN_EXPONENT_OFFSET_EXTENDED); + + PExtendedRec10(ValueAddr)^.ExpSign := Exponent and CN_EXPONENT_EXTENDED_MASK; + if SignNegative then + PExtendedRec10(ValueAddr)^.ExpSign := PExtendedRec10(ValueAddr)^.ExpSign or CN_SIGN_EXTENDED_MASK + else + PExtendedRec10(ValueAddr)^.ExpSign := PExtendedRec10(ValueAddr)^.ExpSign and not CN_SIGN_EXTENDED_MASK; + end + else if ExtendedSize = CN_EXTENDED_SIZE_8 then + begin + CombineFloatDouble(SignNegative, Exponent, Mantissa, D); + Move(D, ValueAddr^, SizeOf(Double)); + end + else + raise ECnFloatSizeError.CreateFmt(SCnErrorExtendedSizeFmt, [SizeOf(Extended)]); +end; + +{$HINTS ON} + +procedure CombineFloatQuadruple(SignNegative: Boolean; Exponent: Integer; + MantissaLo, MantissaHi: TUInt64; var Value: Extended); +begin + if SizeOf(Extended) <> CN_EXTENDED_SIZE_16 then + raise ECnFloatSizeError.CreateFmt(SCnErrorExtendedSizeFmt, [SizeOf(Extended)]); + + MantissaHi := MantissaHi and not (TUInt64(1) shl 48); // ȥ 112 λϵ 1еĻ + PCnQuadruple(@Value)^.Lo := MantissaLo; + PCnQuadruple(@Value)^.Hi0 := Cardinal(MantissaHi and $FFFFFFFF); + PCnQuadruple(@Value)^.Hi1 := (MantissaHi shr 32) and CN_SIGNIFICAND_QUADRUPLE_MASK; + + Inc(Exponent, CN_EXPONENT_OFFSET_EXTENDED); + PCnQuadruple(@Value)^.W1 := Exponent and CN_EXPONENT_QUADRUPLE_MASK; + if SignNegative then + PCnQuadruple(@Value)^.Hi1 := PCnQuadruple(@Value)^.Hi1 or CN_SIGN_QUADRUPLE_MASK + else + PCnQuadruple(@Value)^.Hi1 := PCnQuadruple(@Value)^.Hi1 and not CN_SIGN_QUADRUPLE_MASK; +end; + +// UInt64 Ϊ +function UFloat(U: TUInt64): Extended; +{$IFNDEF SUPPORT_UINT64} +var + L, H: Cardinal; +{$ENDIF} +begin +{$IFDEF SUPPORT_UINT64} + Result := U; +{$ELSE} + if U < 0 then // Int64 С 0 ʱ UInt64 Ǵ Int64 ֵ + begin + H := Int64Rec(U).Hi; + L := Int64Rec(U).Lo; + Result := Int64(H) * Int64(CN_MAX_UINT16 + 1); // + Result := Result * (CN_MAX_UINT16 + 1); + Result := Result + L; + end + else + Result := U; +{$ENDIF} +end; + +function UInt64ToSingle(U: TUInt64): Single; +begin + Result := UFloat(U); +end; + +function UInt64ToDouble(U: TUInt64): Double; +begin + Result := UFloat(U); +end; + +function UInt64ToExtended(U: TUInt64): Extended; +begin + Result := UFloat(U); +end; + +// ͨ Trunc ֻܷ Int64 UInt64 +function UTrunc(F: Extended): TUInt64; +var + T: Integer; + SignNeg: Boolean; + Exponent: Integer; + Mantissa: TUInt64; +begin + // õʵָ 1 ͷЧ֣С 1 + ExtractFloatExtended(F, SignNeg, Exponent, Mantissa); + if SignNeg then + raise ERangeError.Create(SRangeError); // ֧ + + // Mantissa 64 λЧ֣С 63 λָС 0 ˵СҪƣôֵ 0 + if Exponent < 0 then + Result := 0 + else + begin + // С Exponent λСߵ + T := 63 - Exponent; // С 0 63 λ 63 λұߣСƺ T λұ + if T < 0 then + raise ERangeError.Create(SRangeError); // Exponent ̫ + + Result := Mantissa shr T; + end; +end; + +function SingleToUInt64(F: Single): TUInt64; +begin + Result := UTrunc(F); +end; + +function DoubleToUInt64(F: Double): TUInt64; +begin + Result := UTrunc(F); +end; + +function ExtendedToUInt64(F: Extended): TUInt64; +begin + Result := UTrunc(F); +end; + +function SingleIsInfinite(AValue: Single): Boolean; +begin + Result := ((PCardinal(@AValue)^ and $7F800000) = $7F800000) and + ((PCardinal(@AValue)^ and $007FFFFF) = $00000000); +end; + +function DoubleIsInfinite(AValue: Double): Boolean; +begin + Result := ((PUInt64(@AValue)^ and $7FF0000000000000) = $7FF0000000000000) and + ((PUInt64(@AValue)^ and $000FFFFFFFFFFFFF) = $0000000000000000); +end; + +function ExtendedIsInfinite(AValue: Extended): Boolean; +begin + if (SizeOf(Extended) = CN_EXTENDED_SIZE_10) or (SizeOf(Extended) = CN_EXTENDED_SIZE_16) then + Result := ((PExtendedRec10(@AValue)^.ExpSign and $7FFF) = $7FFF) and + ((PExtendedRec10(@AValue)^.Mantissa) = 0) + else if SizeOf(Extended) = CN_EXTENDED_SIZE_8 then + Result := DoubleIsInfinite(AValue) + else + raise ECnFloatSizeError.CreateFmt(SCnErrorExtendedSizeFmt, [SizeOf(Extended)]); +end; + +function SingleIsNan(AValue: Single): Boolean; +begin + Result := ((PCardinal(@AValue)^ and $7F800000) = $7F800000) and + ((PCardinal(@AValue)^ and $007FFFFF) <> $00000000); +end; + +function DoubleIsNan(AValue: Double): Boolean; +begin + Result := ((PUInt64(@AValue)^ and $7FF0000000000000) = $7FF0000000000000) and + ((PUInt64(@AValue)^ and $000FFFFFFFFFFFFF) <> $0000000000000000); +end; + +function ExtendedIsNan(AValue: Extended): Boolean; +begin + if (SizeOf(Extended) = CN_EXTENDED_SIZE_10) or (SizeOf(Extended) = CN_EXTENDED_SIZE_16) then + Result := ((PExtendedRec10(@AValue)^.ExpSign and $7FFF) = $7FFF) and + ((PExtendedRec10(@AValue)^.Mantissa and $7FFFFFFFFFFFFFFF) <> 0) + else if SizeOf(Extended) = CN_EXTENDED_SIZE_8 then + Result := DoubleIsNan(AValue) + else + raise ECnFloatSizeError.CreateFmt(SCnErrorExtendedSizeFmt, [SizeOf(Extended)]); +end; + +function ExtendedToStr(AValue: Extended): string; +var + Buffer: array[0..63] of Char; +begin + SetString(Result, Buffer, FloatToText(Buffer, AValue, {$IFNDEF FPC} fvExtended, {$ENDIF} + ffGeneral, 18, 0)); // ڲ 18 +end; + +end. diff --git a/CnPack/Common/CnStrings.pas b/CnPack/Common/CnStrings.pas new file mode 100644 index 0000000..504f43a --- /dev/null +++ b/CnPack/Common/CnStrings.pas @@ -0,0 +1,2927 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnStrings; +{* |
+================================================================================
+* ƣCnPack 
+* ԪƣCnStrings ʵֵԪ AnsiStringList ԼһӴ㷨
+*           ֧ Win32/64  Posix
+* ԪߣCnPack  (master@cnpack.org)
+* ƽ̨PWinXPPro + Delphi 5.01
+* ݲԣPWin9X/2000/XP + Delphi 5/6/7/2005 + C++Build 5/6
+*     עAnsiStringList ֲ Delphi 7  StringList
+* £2025.08.14
+*               һָָȫƥʵֺ
+*           2022.10.25
+*                StringBuilder ʵ֣֧ Ansi  Unicode ģʽ
+*           2022.04.25
+*               ַ滻֧ƥ
+*           2017.01.09
+*               ֲ Forrest Smith ַģƥ㷨
+*               һƥַڿ⡣
+*           2015.06.01
+*               ӿӴ㷨 FastPosition
+*           2013.03.04
+*               Ԫʵֹ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + Classes, SysUtils, {$IFDEF MSWINDOWS} Windows, {$ENDIF} CnNative; + +const + SCN_BOM_UTF8: array[0..2] of Byte = ($EF, $BB, $BF); + + SCN_BOM_UTF16_LE: array[0..1] of Byte = ($FF, $FE); + + SCN_BOM_UTF16_BE: array[0..1] of Byte = ($FE, $FF); + +type + TCnMatchMode = (mmStart, mmAnywhere, mmFuzzy); + {* ַƥģʽͷƥ䣬мƥ䣬ȫΧģƥ} + + TCnAnsiStrings = class; + + ICnStringsAdapter = interface + ['{E32A5BD7-9A80-4DDE-83D7-2EE050BF476A}'] + procedure ReferenceStrings(S: TCnAnsiStrings); + procedure ReleaseStrings; + end; + + TCnAnsiStringsDefined = set of (sdDelimiter, sdQuoteChar, sdNameValueSeparator); + + TCnAnsiStrings = class(TPersistent) + {* Ansi TStrings Unicode ṩ Ansi TStrings } + private + FDefined: TCnAnsiStringsDefined; + FDelimiter: AnsiChar; + FQuoteChar: AnsiChar; + FNameValueSeparator: AnsiChar; + FUpdateCount: Integer; + FAdapter: ICnStringsAdapter; + FUseSingleLF: Boolean; + function GetCommaText: AnsiString; + function GetDelimitedText: AnsiString; + function GetName(Index: Integer): AnsiString; + function GetValue(const Name: AnsiString): AnsiString; + procedure ReadData(Reader: TReader); + procedure SetCommaText(const Value: AnsiString); + procedure SetDelimitedText(const Value: AnsiString); + procedure SetStringsAdapter(const Value: ICnStringsAdapter); + procedure SetValue(const Name, Value: AnsiString); + procedure WriteData(Writer: TWriter); + function GetDelimiter: AnsiChar; + procedure SetDelimiter(const Value: AnsiChar); + function GetQuoteChar: AnsiChar; + procedure SetQuoteChar(const Value: AnsiChar); + function GetNameValueSeparator: AnsiChar; + procedure SetNameValueSeparator(const Value: AnsiChar); + function GetValueFromIndex(Index: Integer): AnsiString; + procedure SetValueFromIndex(Index: Integer; const Value: AnsiString); + protected + procedure DefineProperties(Filer: TFiler); override; + procedure Error(const Msg: AnsiString; Data: Integer); overload; + procedure Error(Msg: PResStringRec; Data: Integer); overload; + function ExtractName(const S: AnsiString): AnsiString; + function Get(Index: Integer): AnsiString; virtual; abstract; + function GetCapacity: Integer; virtual; + function GetCount: Integer; virtual; abstract; + function GetObject(Index: Integer): TObject; virtual; + function GetTextStr: AnsiString; virtual; + procedure Put(Index: Integer; const S: AnsiString); virtual; + procedure PutObject(Index: Integer; AObject: TObject); virtual; + procedure SetCapacity(NewCapacity: Integer); virtual; + procedure SetTextStr(const Value: AnsiString); virtual; + procedure SetUpdateState(Updating: Boolean); virtual; + property UpdateCount: Integer read FUpdateCount; + function CompareStrings(const S1, S2: AnsiString): Integer; virtual; + public + destructor Destroy; override; + function Add(const S: AnsiString): Integer; virtual; + function AddObject(const S: AnsiString; AObject: TObject): Integer; virtual; + procedure Append(const S: AnsiString); + procedure AddStrings(Strings: TCnAnsiStrings); virtual; + procedure Assign(Source: TPersistent); override; + procedure BeginUpdate; + procedure Clear; virtual; abstract; + procedure Delete(Index: Integer); virtual; abstract; + procedure EndUpdate; + function Equals(Strings: TCnAnsiStrings): Boolean; reintroduce; + procedure Exchange(Index1, Index2: Integer); virtual; + function GetText: PAnsiChar; virtual; + function IndexOf(const S: AnsiString): Integer; virtual; + function IndexOfName(const Name: AnsiString): Integer; virtual; + function IndexOfObject(AObject: TObject): Integer; virtual; + procedure Insert(Index: Integer; const S: AnsiString); virtual; abstract; + procedure InsertObject(Index: Integer; const S: AnsiString; + AObject: TObject); virtual; + procedure LoadFromFile(const FileName: AnsiString); virtual; + procedure LoadFromStream(Stream: TStream); virtual; + procedure Move(CurIndex, NewIndex: Integer); virtual; + procedure SaveToFile(const FileName: AnsiString); virtual; + procedure SaveToStream(Stream: TStream); virtual; + procedure SetText(Text: PAnsiChar); virtual; + property Capacity: Integer read GetCapacity write SetCapacity; + property CommaText: AnsiString read GetCommaText write SetCommaText; + property Count: Integer read GetCount; + property Delimiter: AnsiChar read GetDelimiter write SetDelimiter; + property DelimitedText: AnsiString read GetDelimitedText write SetDelimitedText; + property Names[Index: Integer]: AnsiString read GetName; + property Objects[Index: Integer]: TObject read GetObject write PutObject; + property QuoteChar: AnsiChar read GetQuoteChar write SetQuoteChar; + property Values[const Name: AnsiString]: AnsiString read GetValue write SetValue; + property ValueFromIndex[Index: Integer]: AnsiString read GetValueFromIndex write SetValueFromIndex; + property NameValueSeparator: AnsiChar read GetNameValueSeparator write SetNameValueSeparator; + property Strings[Index: Integer]: AnsiString read Get write Put; default; + property Text: AnsiString read GetTextStr write SetTextStr; + property StringsAdapter: ICnStringsAdapter read FAdapter write SetStringsAdapter; + property UseSingleLF: Boolean read FUseSingleLF write FUseSingleLF; + {* ӵԣ GetTextStr ʱʹõĻǷǵ #10 dz #13#10} + end; + + TCnAnsiStringList = class; + + PCnAnsiStringItem = ^TCnAnsiStringItem; + TCnAnsiStringItem = record + FString: AnsiString; + FObject: TObject; + end; + + PCnAnsiStringItemList = ^TCnAnsiStringItemList; + TCnAnsiStringItemList = array[0..MaxListSize div 2] of TCnAnsiStringItem; + TCnAnsiStringListSortCompare = function(List: TCnAnsiStringList; Index1, Index2: Integer): Integer; + + TCnAnsiStringList = class(TCnAnsiStrings) + {* Ansi TStringList Unicode ṩ Ansi TStringList } + private + FList: PCnAnsiStringItemList; + FCount: Integer; + FCapacity: Integer; + FSorted: Boolean; + FDuplicates: TDuplicates; + FCaseSensitive: Boolean; + FOnChange: TNotifyEvent; + FOnChanging: TNotifyEvent; + procedure ExchangeItems(Index1, Index2: Integer); + procedure Grow; + procedure QuickSort(L, R: Integer; SCompare: TCnAnsiStringListSortCompare); + procedure SetSorted(Value: Boolean); + procedure SetCaseSensitive(const Value: Boolean); + protected + procedure Changed; virtual; + procedure Changing; virtual; + function Get(Index: Integer): AnsiString; override; + function GetCapacity: Integer; override; + function GetCount: Integer; override; + function GetObject(Index: Integer): TObject; override; + procedure Put(Index: Integer; const S: AnsiString); override; + procedure PutObject(Index: Integer; AObject: TObject); override; + procedure SetCapacity(NewCapacity: Integer); override; + procedure SetUpdateState(Updating: Boolean); override; + function CompareStrings(const S1, S2: AnsiString): Integer; override; + procedure InsertItem(Index: Integer; const S: AnsiString; AObject: TObject); virtual; + public + destructor Destroy; override; + function Add(const S: AnsiString): Integer; override; + function AddObject(const S: AnsiString; AObject: TObject): Integer; override; + procedure Clear; override; + procedure Delete(Index: Integer); override; + procedure Exchange(Index1, Index2: Integer); override; + function Find(const S: AnsiString; var Index: Integer): Boolean; virtual; + function IndexOf(const S: AnsiString): Integer; override; + procedure Insert(Index: Integer; const S: AnsiString); override; + procedure InsertObject(Index: Integer; const S: AnsiString; + AObject: TObject); override; + procedure Sort; virtual; + procedure CustomSort(Compare: TCnAnsiStringListSortCompare); virtual; + property Duplicates: TDuplicates read FDuplicates write FDuplicates; + property Sorted: Boolean read FSorted write SetSorted; + property CaseSensitive: Boolean read FCaseSensitive write SetCaseSensitive; + property OnChange: TNotifyEvent read FOnChange write FOnChange; + property OnChanging: TNotifyEvent read FOnChanging write FOnChanging; + end; + + PPCnAnsiHashItem = ^PCnAnsiHashItem; + PCnAnsiHashItem = ^TCnAnsiHashItem; + TCnAnsiHashItem = record + Next: PCnAnsiHashItem; + Key: AnsiString; + Value: Integer; + end; + + TCnAnsiStringHash = class + private + Buckets: array of PCnAnsiHashItem; + protected + function Find(const Key: AnsiString): PPCnAnsiHashItem; + function HashOf(const Key: AnsiString): Cardinal; virtual; + public + constructor Create(Size: Cardinal = 256); + destructor Destroy; override; + procedure Add(const Key: AnsiString; Value: Integer); + procedure Clear; + procedure Remove(const Key: AnsiString); + function Modify(const Key: AnsiString; Value: Integer): Boolean; + function ValueOf(const Key: AnsiString): Integer; + end; + + TCnHashedAnsiStringList = class(TCnAnsiStringList) + {* Ansi THashedStringList Unicode ṩ Ansi THashedStringList } + private + FValueHash: TCnAnsiStringHash; + FNameHash: TCnAnsiStringHash; + FValueHashValid: Boolean; + FNameHashValid: Boolean; + procedure UpdateValueHash; + procedure UpdateNameHash; + protected + procedure Changed; override; + public + destructor Destroy; override; + function IndexOf(const S: AnsiString): Integer; override; + function IndexOfName(const Name: AnsiString): Integer; override; + end; + + TCnStringBuilder = class + {* ʽ StringBuilderʱֻ֧ӣ֧ɾ + Unicode 汾֧ string WideStringUnicode 汾֧ AnsiString string} + private + FModeIsFromOut: Boolean; + FOutMode: Boolean; + FAnsiMode: Boolean; // Unicode 汾Ĭ TrueUnicode 汾Ĭ Falseɴʱָ + FCharLength: Integer; // ַΪλij + FMaxCharCapacity: Integer; +{$IFDEF UNICODE} + FAnsiData: AnsiString; // AnsiMode True ʱʹ + FData: string; // AnsiMode False ʱʹ +{$ELSE} + FData: string; // AnsiMode True ʱʹ + FWideData: WideString; // AnsiMode False ʱʹ +{$ENDIF} + function GetCharCapacity: Integer; + procedure SetCharCapacity(const Value: Integer); + procedure SetCharLength(const Value: Integer); + protected + procedure ExpandCharCapacity; + {* CharLength Ҫչڲ洢Ϊ CharLength * 2 CharLength ̶̫չ Capacity 0.5 } + + function AppendString(const Value: string): TCnStringBuilder; + {* string ӵ FDataǷ Unicode ɵ߸ AnsiMode ơ + + + const Value: string - ӵַ + + ֵTCnStringBuilder - ر󹩽һӵ + } + public + constructor Create; overload; + {* 캯ڲʵĬ string} + + constructor Create(IsAnsi: Boolean); overload; + {* ָڲ Ansi Wide Ĺ캯 + + + IsAnsi: Boolean - ָڲǷʹ Ansi ģʽ + + ֵޣ + } + + destructor Destroy; override; + {* } + + procedure Clear; + {* } + +{$IFDEF UNICODE} + function AppendAnsi(const Value: AnsiString): TCnStringBuilder; + {* AnsiString ӵ Unicode µ FAnsiDataɵ߸ AnsiMode ơ + + + const Value: AnsiString - ӵĵַֽ + + ֵTCnStringBuilder - ر󹩽һӵ + } + +{$ELSE} + function AppendWide(const Value: WideString): TCnStringBuilder; + {* WideString ӵ Unicode е FWideDataɵ߸ AnsiMode ơ + + + const Value: WideString - ӵĿַ + + ֵTCnStringBuilder - ر󹩽һӵ + } +{$ENDIF} + + function Append(const Value: string): TCnStringBuilder; overload; + {* ַͨ Append ڣڲݵǰԼ AnsiMode úʵƴӡ + + + const Value: string - ӵַ + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function Append(Value: Boolean): TCnStringBuilder; overload; + {* һֵ + + + Value: Boolean - ӵIJֵ + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function AppendChar(Value: Char): TCnStringBuilder; + {* һַע Char ͵ַ String ǵͬģܺ Append overload + + + Value: Char - ӵַ + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function AppendAnsiChar(Value: AnsiChar): TCnStringBuilder; + {* һַֽ + + + Value: AnsiChar - ӵĵַֽ + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function AppendWideChar(Value: WideChar): TCnStringBuilder; + {* һַ + + + Value: WideChar - ӵĿַ + + ֵTCnStringBuilder - ر󹩽һӵ + } + + + function AppendCurrency(Value: Currency): TCnStringBuilder; + {* һ Currency ֵע Currency ڵͰ汾 Delphi к Double ǵͬģ + ܺ Append overload + + + Value: Currency - ӵ Currency ֵ + + ֵTCnStringBuilder - ر󹩽һӵ + } + + + function Append(Value: Single): TCnStringBuilder; overload; + {* һȸ + + + Value: Single - ӵĵȸ + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function Append(Value: Double): TCnStringBuilder; overload; + {* һ˫ȸ + + + Value: Double - ӵ˫ȸ + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function Append(Value: ShortInt): TCnStringBuilder; overload; + {* һ 8 λз + + + Value: ShortInt - ӵ 8 λз + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function Append(Value: SmallInt): TCnStringBuilder; overload; + {* һ 16 λз + + + Value: SmallInt - ӵ 16 λз + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function Append(Value: Integer): TCnStringBuilder; overload; + {* һ 32 λз + + + Value: Integer - ӵ 32 λз + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function Append(Value: Int64): TCnStringBuilder; overload; + {* һ 64 λз + + + Value: Int64 - ӵ 64 λз + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function Append(Value: Byte): TCnStringBuilder; overload; + {* һ 8 λ޷ + + + Value: Byte - ӵ 8 λ޷ + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function Append(Value: Word): TCnStringBuilder; overload; + {* һ 16 λ޷ + + + Value: Word - ӵ 16 λ޷ + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function Append(Value: Cardinal): TCnStringBuilder; overload; + {* һ 32 λ޷ + + + Value: Cardinal - ӵ 32 λ޷ + + ֵTCnStringBuilder - ر󹩽һӵ + } + +{$IFDEF SUPPORT_UINT64} + function Append(Value: UInt64): TCnStringBuilder; overload; + {* һ 64 λ޷ + + + Value: UInt64 - ӵ 64 λ޷ + + ֵTCnStringBuilder - ر󹩽һӵ + } +{$ENDIF} + + function Append(Value: TObject): TCnStringBuilder; overload; + {* һ + + + Value: TObject - ӵĶڲʹ ToStringʹöʮƵַ + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function Append(Value: PAnsiChar): TCnStringBuilder; overload; + {* һַֽ + + + Value: PAnsiChar - ӵĵַַֽ + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function Append(Value: Char; RepeatCount: Integer): TCnStringBuilder; overload; + {* һظַͬ + + + Value: Char - ӵַ + RepeatCount: Integer - ַ + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function Append(const Value: string; StartIndex: Integer; Count: Integer): TCnStringBuilder; overload; + {* һַӴ + + + const Value: string - ӵַ + StartIndex: Integer - ʼλ + Count: Integer - ַ + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function Append(const AFormat: string; const Args: array of const): TCnStringBuilder; overload; + {* һʽַ + + + const AFormat: string - ʽַ + const Args: array of const - ʽб + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function AppendLine: TCnStringBuilder; overload; + {* һС + + + ޣ + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function AppendLine(const Value: string): TCnStringBuilder; overload; + {* һַϻس + + + const Value: string - ӵַ + + ֵTCnStringBuilder - ر󹩽һӵ + } + + function ToString: string; {$IFDEF OBJECT_HAS_TOSTRING} override; {$ENDIF} + {* ݵ string ʽǷ Unicode ֻҪ AnsiMode Unicode ֧һ¡ + 仰˵ Unicode AnsiMode Ϊ True ʱŷ AnsiString + Unicode AnsiMode Ϊ False ʱŷ UnicodeStringؿա + + + ޣ + + ֵstring - ݵַʽ + } + + function ToAnsiString: AnsiString; + {* ǿзݵ AnsiString ʽ AnsiMode Ρ + Unicode ʹãڷ Unicode ʹãͬ ToString + + + ޣ + + ֵAnsiString - ݵĵַֽʽ + } + + function ToWideString: WideString; + {* ǿзݵ WideString ʽ AnsiMode Ρ + ڷ Unicode ʹã Unicode ʹãͬ ToString + + + ޣ + + ֵWideString - ݵĿַʽ + } + + property CharCapacity: Integer read GetCharCapacity write SetCharCapacity; + {* ַΪλڲ} + property CharLength: Integer read FCharLength write SetCharLength; + {* ַΪλڲѾƴյݳ} + property MaxCharCapacity: Integer read FMaxCharCapacity; + {* ַΪλĿõ} + end; + + TCnReplaceFlags = set of (crfReplaceAll, crfIgnoreCase, crfWholeWord); + {* ַ滻} + +{$IFNDEF COMPILER7_UP} + +function PosEx(const SubStr: string; const S: string; Offset: Cardinal = 1): Integer; +{* D5/6 BCB5/6 StrUtils ԪĴ˺ֲ PosEx ʹο PosEx + + + const SubStr: string - ҵӴ + const S: string - ԭַ + Offset: Cardinal - ҵʼƫ + + ֵInteger - شʼƫһγӴλ +} + +{$ENDIF} + +function FastPosition(const Str: PChar; const Pattern: PChar; FromIndex: Integer = 0): Integer; +{* Ӵ Pattern Str еĵһγֵţ򷵻 -1 + + + const Str: PChar - ַ + const Pattern: PChar - ƥӴ + FromIndex: Integer - Ӻδʼ + + ֵInteger - ƥĵһγֵţ򷵻 -1 +} + +function FuzzyMatchStr(const Pattern: string; const Str: string; MatchedIndexes: TList = nil; + CaseSensitive: Boolean = False): Boolean; +{* ģƥӴMatchedIndexes з Str ƥ±š + + + const Pattern: string - ƥӴ + const Str: string - ַ + MatchedIndexes: TList - ַиַƥ± + CaseSensitive: Boolean - ǷִСд + + ֵBoolean - Ƿģƥ +} + +function FuzzyMatchStrWithScore(const Pattern: string; const Str: string; out Score: Integer; + MatchedIndexes: TList = nil; CaseSensitive: Boolean = False): Boolean; +{* ģƥӴScore ƥ̶ȣMatchedIndexes з Str ƥ±ţ + ע Score ıȽֻӴԼСдһʱ塣 + + + const Pattern: string - ƥӴ + const Str: string - ַ + out Score: Integer - ƥ̶ + MatchedIndexes: TList - ַиַƥ± + CaseSensitive: Boolean - ǷִСд + + ֵBoolean - Ƿģƥ +} + +function AnyWhereSepMatchStr(const Pattern: string; const Str: string; SepContainer: TStringList; + MatchedIndexes: TList = nil; CaseSensitive: Boolean = False; SepChar: Char = ' '): Boolean; +{* ָӴƥӴҲǰ Pattern SepChar ֳɶַƥ䣬ȫƥŷƥ䡣 + MatchedIndexes з Str ƥ±ţSepContainer 紫 TStringList Լٴ + + + const Pattern: string - ƥӴ + const Str: string - ַ + SepContainer: TStringList; - 紫 TStringList Լڲ + MatchedIndexes: TList - ַиַƥ± + CaseSensitive: Boolean - ǷִСд + + ֵBoolean - Ƿƥɹ +} + +function CnStringReplace(const S: string; const OldPattern: string; + const NewPattern: string; Flags: TCnReplaceFlags): string; +{* ֧ƥַ滻 Unicode Unicode ¶Ч + + + const S: string - 滻ַ + const OldPattern: string - 滻ַ + const NewPattern: string - 滻ַ + Flags: TCnReplaceFlags - 滻ǣ֧ƥ + + ֵstring - ַ滻 +} + +{$IFDEF UNICODE} + +function CnStringReplaceA(const S: AnsiString; const OldPattern: AnsiString; + const NewPattern: AnsiString; Flags: TCnReplaceFlags): AnsiString; +{* ֧ƥ Ansi ַ滻 Unicode Ч + + + const S: AnsiString - 滻ĵַֽ + const OldPattern: AnsiString - 滻ĵַֽ + const NewPattern: AnsiString - 滻ĵַֽ + Flags: TCnReplaceFlags - 滻ǣ֧ƥ + + ֵAnsiString - صַֽ滻 +} + +{$ELSE} + +function CnStringReplaceW(const S: WideString; const OldPattern: WideString; + const NewPattern: WideString; Flags: TCnReplaceFlags): WideString; +{* ֧ƥ Wide ַ滻ڷ Unicode Ч + + + const S: WideString - 滻Ŀַ + const OldPattern: WideString - 滻Ŀַ + const NewPattern: WideString - 滻Ŀַ + Flags: TCnReplaceFlags - 滻ǣ֧ƥ + + ֵWideString - ؿַ滻 +} + +{$ENDIF} + +function CnPosEx(const SubStr, S: string; CaseSensitive: Boolean; WholeWords: + Boolean; StartCount: Integer = 1): Integer; +{* ǿַҺֲ֧ҵڼ׸ StartCount Ϊ 1} + +procedure CnSplitString(const Sub: string; const Str: string; Strings: TStrings); +{* ַַֺ} + +function NativeStringToUIString(const Str: string): string; +{* Lazarus/FPC Ansi ģʽרãΪ Lazarus/FPC Ansi ģʽºͽйصַ Utf8 ʽ + ڲַͨ Ansi Utf16һηװת} + +function UIStringToNativeString(const Str: string): string; +{* Lazarus/FPC Ansi ģʽרãΪ Lazarus/FPC Ansi ģʽºͽйصַ Utf8 ʽ + ڲַͨ Ansi Utf16һηװת} + +implementation + +uses + CnWideStrings; + +const + SLineBreak = #13#10; + SLineBreakLF = #10; + STRING_BUILDER_DEFAULT_CAPACITY = 16; + +resourcestring + SDuplicateString = 'AnsiString list does not allow duplicates'; + SListIndexError = 'AnsiString List index out of bounds (%d)'; + SSortedListError = 'Operation not allowed on sorted AnsiString list'; + SListCapacityError = 'Error New Capacity or Length Value %d'; + +function NativeStringToUIString(const Str: string): string; +begin +{$IFDEF FPC} + Result := CnAnsiToUtf82(Str); +{$ELSE} + Result := Str; +{$ENDIF} +end; + +function UIStringToNativeString(const Str: string): string; +begin +{$IFDEF FPC} + Result := CnUtf8ToAnsi2(Str); +{$ELSE} + Result := Str; +{$ENDIF} +end; + +{$IFNDEF COMPILER7_UP} + +function PosEx(const SubStr, S: string; Offset: Cardinal = 1): Integer; +var + I,X: Integer; + Len, LenSubStr: Integer; +begin + if Offset = 1 then + Result := Pos(SubStr, S) + else + begin + I := Offset; + LenSubStr := Length(SubStr); + Len := Length(S) - LenSubStr + 1; + while I <= Len do + begin + if S[I] = SubStr[1] then + begin + X := 1; + while (X < LenSubStr) and (S[I + X] = SubStr[X + 1]) do + Inc(X); + if (X = LenSubStr) then + begin + Result := I; + exit; + end; + end; + Inc(I); + end; + Result := 0; + end; +end; + +{$ENDIF} + +// Ӵ Pattern Str еĵһγֵţ򷵻 -1 +function FastPosition(const Str, Pattern: PChar; FromIndex: Integer): Integer; +var + C: Char; + I, L, X, Y, PLen, SLen: Integer; + BCS: array[0..255] of Integer; +begin + Result := -1; + if (Str = nil) or (Pattern = nil) then + Exit; + + PLen := StrLen(Pattern); + if PLen = 0 then + Exit; + SLen := StrLen(Str); + + // ǵַģʽ + if PLen = 1 then + begin + for I := FromIndex to SLen - 1 do + begin + if Str[I] = Pattern[0] then + begin + Result := I; + Exit; + end; + end; + Exit; + end; + + // Ծ + for I := Low(BCS) to High(BCS) do + BCS[I] := PLen; + + for I := 0 to PLen - 2 do + begin + C := Pattern[I]; + L := Ord(C) and $FF; + if PLen - I - 1 < BCS[L] then + BCS[L] := PLen - I - 1; + end; + + // ٽ + I := FromIndex + PLen - 1; + while I < SLen do + begin + X := I; + Y := PLen - 1; + while True do + begin + if Pattern[Y] <> Str[X] then + begin + Inc(I, BCS[Ord(Str[X]) and $FF]); + Break; + end; + + if Y = 0 then + begin + Result := X; + Exit; + end; + + Dec(X); + Dec(Y); + end; + end; +end; + +{$WARNINGS OFF} + +function LowChar(AChar: Char): Char; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + if AChar in ['A'..'Z'] then + Result := Chr(Ord(AChar) + 32) + else + Result := AChar; +end; + +// ģƥӴ +function FuzzyMatchStr(const Pattern: string; const Str: string; + MatchedIndexes: TList; CaseSensitive: Boolean): Boolean; +var + PIdx, SIdx: Integer; +begin + Result := False; + if (Pattern = '') or (Str = '') then + Exit; + + PIdx := 1; + SIdx := 1; + if MatchedIndexes <> nil then + MatchedIndexes.Clear; + + if CaseSensitive then + begin + while (PIdx <= Length(Pattern)) and (SIdx <= Length(Str)) do + begin + if Pattern[PIdx] = Str[SIdx] then + begin + Inc(PIdx); + if MatchedIndexes <> nil then + MatchedIndexes.Add(Pointer(SIdx)); + end; + Inc(SIdx); + end; + end + else + begin + while (PIdx <= Length(Pattern)) and (SIdx <= Length(Str)) do + begin + if LowChar(Pattern[PIdx]) = LowChar(Str[SIdx]) then + begin + Inc(PIdx); + if MatchedIndexes <> nil then + MatchedIndexes.Add(Pointer(SIdx)); + end; + Inc(SIdx); + end; + end; + Result := PIdx > Length(Pattern); +end; + +// ģƥӴScore ƥ̶ȣע Score ıȽֻӴԼСдһʱ +function FuzzyMatchStrWithScore(const Pattern: string; const Str: string; + out Score: Integer; MatchedIndexes: TList; CaseSensitive: Boolean): Boolean; +const + ADJACENCY_BONUS = 4; // ÿһַĽƥʱӷ + SEPARATOR_BONUS = 10; // ÿһַƥ䷢һָźļӷ + CAMEL_BONUS = 5; // ǰһƥСдǴдʱӷ + LEADING_LETTER_PENALTY = -3; // һƥĸԽĸԽ۷ + MAX_LEADING_LETTER_PENALTY = -9; // һƥĸ󣬷ⶥֻô + UNMATCHED_LETTER_PENALTY = -1; // ƥĿ۷ + START_BONUS = 6; +var + PIdx, SIdx: Integer; + PrevMatch, PrevLow, PrevSep: Boolean; + BestLetterPtr: PChar; + BestLetterScore, NewScore, Penalty: Integer; + PatternLetter, StrLetter: Char; // ֱӴĸַ + ThisMatch, Rematch, Advanced, PatternRepeat: Boolean; +begin + Score := 0; + Result := False; + if (Pattern = '') or (Str = '') then + Exit; + + if MatchedIndexes <> nil then + MatchedIndexes.Clear; + + PrevMatch := False; + PrevLow := False; + PrevSep := True; + + PIdx := 1; + SIdx := 1; + + BestLetterPtr := nil; + BestLetterScore := 0; + + while SIdx <= Length(Str) do // SIdx ĸλã1 ʼ + begin + if PIdx <= Length(Pattern) then + PatternLetter := Pattern[PIdx] + else + PatternLetter := #0; + StrLetter := Str[SIdx]; + + if CaseSensitive then + begin + ThisMatch := (PatternLetter <> #0) and (PatternLetter = StrLetter); + Rematch := (BestLetterPtr <> nil) and (BestLetterPtr^ = StrLetter); + Advanced := ThisMatch and (BestLetterPtr <> nil); + PatternRepeat := (BestLetterPtr <> nil) and (PatternLetter <> #0) and (BestLetterPtr^ = PatternLetter); + end + else + begin + ThisMatch := (PatternLetter <> #0) and (LowChar(PatternLetter) = LowChar(StrLetter)); + Rematch := (BestLetterPtr <> nil) and (LowChar(BestLetterPtr^) = LowChar(StrLetter)); + Advanced := ThisMatch and (BestLetterPtr <> nil); + PatternRepeat := (BestLetterPtr <> nil) and (PatternLetter <> #0) and (LowChar(BestLetterPtr^) = LowChar(PatternLetter)); + end; + + if ThisMatch and (MatchedIndexes <> nil) then + begin + MatchedIndexes.Add(Pointer(SIdx)); + if SIdx <= START_BONUS then // ߿ĸǰͷƥַķ + Inc(Score, (START_BONUS - SIdx + 1) * 2); + end; + + if Advanced or PatternRepeat then + begin + Inc(Score, BestLetterScore); + BestLetterPtr := nil; + BestLetterScore := 0; + end; + + if ThisMatch or Rematch then + begin + NewScore := 0; + if PIdx = 1 then + begin + Penalty := LEADING_LETTER_PENALTY * (SIdx - 1); // ͷƥ䲻۷ + if Penalty < MAX_LEADING_LETTER_PENALTY then + Penalty := MAX_LEADING_LETTER_PENALTY; + + Inc(Score, Penalty); + end; + + if PrevMatch then + Inc(NewScore, ADJACENCY_BONUS); + if PrevSep then + Inc(NewScore, SEPARATOR_BONUS); + if PrevLow and (strLetter in ['A'..'Z']) then + Inc(NewScore, CAMEL_BONUS); + + if ThisMatch then + Inc(PIdx); + + if NewScore >= BestLetterScore then + begin + if BestLetterPtr <> nil then + Inc(Score, UNMATCHED_LETTER_PENALTY); + BestLetterPtr := @(Str[SIdx]); + BestLetterScore := NewScore; + end; + PrevMatch := True; + end + else + begin + Inc(Score, UNMATCHED_LETTER_PENALTY); + PrevMatch := False; + end; + + PrevLow := StrLetter in ['a'..'z']; + PrevSep := strLetter in ['_', ' ', '/', '\', '.']; + + Inc(SIdx); + end; + + if BestLetterPtr <> nil then + Inc(Score, BestLetterScore); + + Result := PIdx > Length(Pattern); +end; + +function MatchedIndexesCompare(Item1, Item2: Pointer): Integer; +var + R1, R2: Integer; +begin + R1 := Integer(Item1); + R2 := Integer(Item2); + Result := R1 - R2; +end; + +function AnyWhereSepMatchStr(const Pattern: string; const Str: string; SepContainer: TStringList; + MatchedIndexes: TList; CaseSensitive: Boolean; SepChar: Char): Boolean; +var + IsNil: Boolean; + D, I, J: Integer; + ToFind: string; + SepChars: TSysCharSet; +begin + Result := False; + + if Pos(SepChar, Pattern) <= 0 then + begin + // ûиַɱ Pos + if CaseSensitive then + D := Pos(Pattern, Str) + else + D := Pos(UpperCase(Pattern), UpperCase(Str)); + + if D > 0 then + begin + Result := True; + if MatchedIndexes <> nil then + begin + MatchedIndexes.Clear; + for I := 0 to Length(Pattern) - 1 do + MatchedIndexes.Add(Pointer(D + I)); + end; + end; + end + else + begin + IsNil := SepContainer = nil; + if IsNil then + SepContainer := TStringList.Create + else + SepContainer.Clear; + + try + SepChars := []; + Include(SepChars, AnsiChar(SepChar)); + if CaseSensitive then + begin + ExtractStrings(SepChars, [], PChar(Pattern), SepContainer); + ToFind := Str; + end + else + begin + ExtractStrings(SepChars, [], PChar(UpperCase(Pattern)), SepContainer); + ToFind := UpperCase(Str); + end; + + if MatchedIndexes <> nil then + MatchedIndexes.Clear; + for I := 0 to SepContainer.Count - 1 do + begin + D := Pos(SepContainer[I], ToFind); + if D <= 0 then + begin + if MatchedIndexes <> nil then + MatchedIndexes.Clear; + Exit; + end + else + begin + if MatchedIndexes <> nil then + begin + for J := 0 to Length(SepContainer[I]) - 1 do + MatchedIndexes.Add(Pointer(D + J)); + end; + end; + end; + + if (MatchedIndexes <> nil) and (MatchedIndexes.Count > 1) then + MatchedIndexes.Sort(MatchedIndexesCompare); + Result := True; + finally + if IsNil then + SepContainer.Free; + end; + end; +end; + +{ TCnAnsiStrings } + +destructor TCnAnsiStrings.Destroy; +begin + StringsAdapter := nil; + inherited Destroy; +end; + +function TCnAnsiStrings.Add(const S: AnsiString): Integer; +begin + Result := GetCount; + Insert(Result, S); +end; + +function TCnAnsiStrings.AddObject(const S: AnsiString; AObject: TObject): Integer; +begin + Result := Add(S); + PutObject(Result, AObject); +end; + +procedure TCnAnsiStrings.Append(const S: AnsiString); +begin + Add(S); +end; + +procedure TCnAnsiStrings.AddStrings(Strings: TCnAnsiStrings); +var + I: Integer; +begin + BeginUpdate; + try + for I := 0 to Strings.Count - 1 do + AddObject(Strings[I], Strings.Objects[I]); + finally + EndUpdate; + end; +end; + +procedure TCnAnsiStrings.Assign(Source: TPersistent); +begin + if Source is TCnAnsiStrings then + begin + BeginUpdate; + try + Clear; + FDefined := TCnAnsiStrings(Source).FDefined; + FNameValueSeparator := TCnAnsiStrings(Source).FNameValueSeparator; + FQuoteChar := TCnAnsiStrings(Source).FQuoteChar; + FDelimiter := TCnAnsiStrings(Source).FDelimiter; + AddStrings(TCnAnsiStrings(Source)); + finally + EndUpdate; + end; + Exit; + end; + inherited Assign(Source); +end; + +procedure TCnAnsiStrings.BeginUpdate; +begin + if FUpdateCount = 0 then SetUpdateState(True); + Inc(FUpdateCount); +end; + +procedure TCnAnsiStrings.DefineProperties(Filer: TFiler); + + function DoWrite: Boolean; + begin + if Filer.Ancestor <> nil then + begin + Result := True; + if Filer.Ancestor is TCnAnsiStrings then + Result := not Equals(TCnAnsiStrings(Filer.Ancestor)) + end + else Result := Count > 0; + end; + +begin + Filer.DefineProperty('Strings', ReadData, WriteData, DoWrite); +end; + +procedure TCnAnsiStrings.EndUpdate; +begin + Dec(FUpdateCount); + if FUpdateCount = 0 then SetUpdateState(False); +end; + +function TCnAnsiStrings.Equals(Strings: TCnAnsiStrings): Boolean; +var + I, Count: Integer; +begin + Result := False; + Count := GetCount; + if Count <> Strings.GetCount then Exit; + for I := 0 to Count - 1 do if Get(I) <> Strings.Get(I) then Exit; + Result := True; +end; + +procedure TCnAnsiStrings.Error(const Msg: AnsiString; Data: Integer); + +{$IFDEF MSWINDOWS} + function ReturnAddr: Pointer; + asm + MOV EAX,[EBP+4] + end; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + raise EStringListError.CreateFmt(string(Msg), [Data]) at ReturnAddr; +{$ELSE} + raise EStringListError.CreateFmt(string(Msg), [Data]); +{$ENDIF} +end; + +procedure TCnAnsiStrings.Error(Msg: PResStringRec; Data: Integer); +begin + Error(AnsiString(LoadResString(Msg)), Data); +end; + +procedure TCnAnsiStrings.Exchange(Index1, Index2: Integer); +var + TempObject: TObject; + TempString: AnsiString; +begin + BeginUpdate; + try + TempString := Strings[Index1]; + TempObject := Objects[Index1]; + Strings[Index1] := Strings[Index2]; + Objects[Index1] := Objects[Index2]; + Strings[Index2] := TempString; + Objects[Index2] := TempObject; + finally + EndUpdate; + end; +end; + +function TCnAnsiStrings.ExtractName(const S: AnsiString): AnsiString; +var + P: Integer; +begin + Result := S; + P := AnsiPos(string(NameValueSeparator), string(S)); + if P <> 0 then + SetLength(Result, P-1) else + SetLength(Result, 0); +end; + +function TCnAnsiStrings.GetCapacity: Integer; +begin // descendents may optionally override/replace this default implementation + Result := Count; +end; + +function TCnAnsiStrings.GetCommaText: AnsiString; +var + LOldDefined: TCnAnsiStringsDefined; + LOldDelimiter: AnsiChar; + LOldQuoteChar: AnsiChar; +begin + LOldDefined := FDefined; + LOldDelimiter := FDelimiter; + LOldQuoteChar := FQuoteChar; + Delimiter := ','; + QuoteChar := '"'; + try + Result := GetDelimitedText; + finally + FDelimiter := LOldDelimiter; + FQuoteChar := LOldQuoteChar; + FDefined := LOldDefined; + end; +end; + +function TCnAnsiStrings.GetDelimitedText: AnsiString; +var + S: AnsiString; + P: PAnsiChar; + I, Count: Integer; +begin + Count := GetCount; + if (Count = 1) and (Get(0) = '') then + Result := QuoteChar + QuoteChar + else + begin + Result := ''; + for I := 0 to Count - 1 do + begin + S := Get(I); + P := PAnsiChar(S); + while not (P^ in [#0..' ', QuoteChar, Delimiter]) do + {$IFDEF MSWINDOWS} + P := CharNextA(P); + {$ELSE} + Inc(P); + {$ENDIF} + if (P^ <> #0) then S := AnsiString(AnsiQuotedStr(string(S), Char(QuoteChar))); + Result := Result + S + Delimiter; + end; + System.Delete(Result, Length(Result), 1); + end; +end; + +function TCnAnsiStrings.GetName(Index: Integer): AnsiString; +begin + Result := ExtractName(Get(Index)); +end; + +function TCnAnsiStrings.GetObject(Index: Integer): TObject; +begin + Result := nil; +end; + +function TCnAnsiStrings.GetText: PAnsiChar; +begin + Result := StrNew(PAnsiChar(GetTextStr)); +end; + +function TCnAnsiStrings.GetTextStr: AnsiString; +var + I, L, Size, Count: Integer; + P: PAnsiChar; + S, LB: AnsiString; +begin + Count := GetCount; + Size := 0; + + if FUseSingleLF then + LB := SLineBreakLF + else + LB := SLineBreak; + + for I := 0 to Count - 1 do Inc(Size, Length(Get(I)) + Length(LB)); + SetString(Result, nil, Size); + P := Pointer(Result); + for I := 0 to Count - 1 do + begin + S := Get(I); + L := Length(S); + if L <> 0 then + begin + System.Move(Pointer(S)^, P^, L); + Inc(P, L); + end; + L := Length(LB); + if L <> 0 then + begin + System.Move(Pointer(LB)^, P^, L); + Inc(P, L); + end; + end; +end; + +function TCnAnsiStrings.GetValue(const Name: AnsiString): AnsiString; +var + I: Integer; +begin + I := IndexOfName(Name); + if I >= 0 then + Result := Copy(Get(I), Length(Name) + 2, MaxInt) else + Result := ''; +end; + +function TCnAnsiStrings.IndexOf(const S: AnsiString): Integer; +begin + for Result := 0 to GetCount - 1 do + if CompareStrings(Get(Result), S) = 0 then Exit; + Result := -1; +end; + +function TCnAnsiStrings.IndexOfName(const Name: AnsiString): Integer; +var + P: Integer; + S: AnsiString; +begin + for Result := 0 to GetCount - 1 do + begin + S := Get(Result); + P := AnsiPos(string(NameValueSeparator), string(S)); + if (P <> 0) and (CompareStrings(Copy(S, 1, P - 1), Name) = 0) then Exit; + end; + Result := -1; +end; + +function TCnAnsiStrings.IndexOfObject(AObject: TObject): Integer; +begin + for Result := 0 to GetCount - 1 do + if GetObject(Result) = AObject then Exit; + Result := -1; +end; + +procedure TCnAnsiStrings.InsertObject(Index: Integer; const S: AnsiString; + AObject: TObject); +begin + Insert(Index, S); + PutObject(Index, AObject); +end; + +procedure TCnAnsiStrings.LoadFromFile(const FileName: AnsiString); +var + Stream: TStream; +begin + Stream := TFileStream.Create(string(FileName), fmOpenRead or fmShareDenyWrite); + try + LoadFromStream(Stream); + finally + Stream.Free; + end; +end; + +procedure TCnAnsiStrings.LoadFromStream(Stream: TStream); +var + Size: Integer; + S: AnsiString; +begin + BeginUpdate; + try + Size := Stream.Size - Stream.Position; + SetString(S, nil, Size); + Stream.Read(Pointer(S)^, Size); + SetTextStr(S); + finally + EndUpdate; + end; +end; + +procedure TCnAnsiStrings.Move(CurIndex, NewIndex: Integer); +var + TempObject: TObject; + TempString: AnsiString; +begin + if CurIndex <> NewIndex then + begin + BeginUpdate; + try + TempString := Get(CurIndex); + TempObject := GetObject(CurIndex); + Delete(CurIndex); + InsertObject(NewIndex, TempString, TempObject); + finally + EndUpdate; + end; + end; +end; + +procedure TCnAnsiStrings.Put(Index: Integer; const S: AnsiString); +var + TempObject: TObject; +begin + TempObject := GetObject(Index); + Delete(Index); + InsertObject(Index, S, TempObject); +end; + +procedure TCnAnsiStrings.PutObject(Index: Integer; AObject: TObject); +begin +end; + +procedure TCnAnsiStrings.ReadData(Reader: TReader); +begin + Reader.ReadListBegin; + BeginUpdate; + try + Clear; + while not Reader.EndOfList do Add(AnsiString(Reader.ReadString)); + finally + EndUpdate; + end; + Reader.ReadListEnd; +end; + +procedure TCnAnsiStrings.SaveToFile(const FileName: AnsiString); +var + Stream: TStream; +begin + Stream := TFileStream.Create(string(FileName), fmCreate); + try + SaveToStream(Stream); + finally + Stream.Free; + end; +end; + +procedure TCnAnsiStrings.SaveToStream(Stream: TStream); +var + S: AnsiString; +begin + S := GetTextStr; + Stream.WriteBuffer(Pointer(S)^, Length(S)); +end; + +procedure TCnAnsiStrings.SetCapacity(NewCapacity: Integer); +begin + // do nothing - descendents may optionally implement this method +end; + +procedure TCnAnsiStrings.SetCommaText(const Value: AnsiString); +begin + Delimiter := ','; + QuoteChar := '"'; + SetDelimitedText(Value); +end; + +procedure TCnAnsiStrings.SetStringsAdapter(const Value: ICnStringsAdapter); +begin + if FAdapter <> nil then FAdapter.ReleaseStrings; + FAdapter := Value; + if FAdapter <> nil then FAdapter.ReferenceStrings(Self); +end; + +procedure TCnAnsiStrings.SetText(Text: PAnsiChar); +begin + SetTextStr(Text); +end; + +procedure TCnAnsiStrings.SetTextStr(const Value: AnsiString); +var + P, Start: PAnsiChar; + S: AnsiString; +begin + BeginUpdate; + try + Clear; + P := Pointer(Value); + if P <> nil then + while P^ <> #0 do + begin + Start := P; + while not (P^ in [#0, #10, #13]) do Inc(P); + SetString(S, Start, P - Start); + Add(S); + if P^ = #13 then Inc(P); + if P^ = #10 then Inc(P); + end; + finally + EndUpdate; + end; +end; + +procedure TCnAnsiStrings.SetUpdateState(Updating: Boolean); +begin +end; + +procedure TCnAnsiStrings.SetValue(const Name, Value: AnsiString); +var + I: Integer; +begin + I := IndexOfName(Name); + if Value <> '' then + begin + if I < 0 then I := Add(''); + Put(I, Name + NameValueSeparator + Value); + end else + begin + if I >= 0 then Delete(I); + end; +end; + +procedure TCnAnsiStrings.WriteData(Writer: TWriter); +var + I: Integer; +begin + Writer.WriteListBegin; + for I := 0 to Count - 1 do Writer.WriteString(string(Get(I))); + Writer.WriteListEnd; +end; + +procedure TCnAnsiStrings.SetDelimitedText(const Value: AnsiString); +var + P, P1: PAnsiChar; + S: AnsiString; +begin + BeginUpdate; + try + Clear; + P := PAnsiChar(Value); + while P^ in [#1..' '] do + {$IFDEF MSWINDOWS} + P := CharNextA(P); + {$ELSE} + Inc(P); + {$ENDIF} + while P^ <> #0 do + begin + if P^ = QuoteChar then + S := AnsiExtractQuotedStr(P, QuoteChar) + else + begin + P1 := P; + while (P^ > ' ') and (P^ <> Delimiter) do + {$IFDEF MSWINDOWS} + P := CharNextA(P); + {$ELSE} + Inc(P); + {$ENDIF} + SetString(S, P1, P - P1); + end; + Add(S); + while P^ in [#1..' '] do + {$IFDEF MSWINDOWS} + P := CharNextA(P); + {$ELSE} + Inc(P); + {$ENDIF} + if P^ = Delimiter then + begin + P1 := P; + {$IFDEF MSWINDOWS} + if CharNextA(P1)^ = #0 then + {$ELSE} + Inc(P1); + if P1^ = #0 then + {$ENDIF} + Add(''); + repeat + {$IFDEF MSWINDOWS} + P := CharNextA(P); + {$ELSE} + Inc(P); + {$ENDIF} + until not (P^ in [#1..' ']); + end; + end; + finally + EndUpdate; + end; +end; + +function TCnAnsiStrings.GetDelimiter: AnsiChar; +begin + if not (sdDelimiter in FDefined) then + Delimiter := ','; + Result := FDelimiter; +end; + +function TCnAnsiStrings.GetQuoteChar: AnsiChar; +begin + if not (sdQuoteChar in FDefined) then + QuoteChar := '"'; + Result := FQuoteChar; +end; + +procedure TCnAnsiStrings.SetDelimiter(const Value: AnsiChar); +begin + if (FDelimiter <> Value) or not (sdDelimiter in FDefined) then + begin + Include(FDefined, sdDelimiter); + FDelimiter := Value; + end +end; + +procedure TCnAnsiStrings.SetQuoteChar(const Value: AnsiChar); +begin + if (FQuoteChar <> Value) or not (sdQuoteChar in FDefined) then + begin + Include(FDefined, sdQuoteChar); + FQuoteChar := Value; + end +end; + +function TCnAnsiStrings.CompareStrings(const S1, S2: AnsiString): Integer; +begin + Result := AnsiCompareText(string(S1), string(S2)); +end; + +function TCnAnsiStrings.GetNameValueSeparator: AnsiChar; +begin + if not (sdNameValueSeparator in FDefined) then + NameValueSeparator := '='; + Result := FNameValueSeparator; +end; + +procedure TCnAnsiStrings.SetNameValueSeparator(const Value: AnsiChar); +begin + if (FNameValueSeparator <> Value) or not (sdNameValueSeparator in FDefined) then + begin + Include(FDefined, sdNameValueSeparator); + FNameValueSeparator := Value; + end +end; + +function TCnAnsiStrings.GetValueFromIndex(Index: Integer): AnsiString; +begin + if Index >= 0 then + Result := Copy(Get(Index), Length(Names[Index]) + 2, MaxInt) else + Result := ''; +end; + +procedure TCnAnsiStrings.SetValueFromIndex(Index: Integer; const Value: AnsiString); +begin + if Value <> '' then + begin + if Index < 0 then Index := Add(''); + Put(Index, Names[Index] + NameValueSeparator + Value); + end + else + if Index >= 0 then Delete(Index); +end; + +{ TCnAnsiStringList } + +destructor TCnAnsiStringList.Destroy; +begin + FOnChange := nil; + FOnChanging := nil; + inherited Destroy; + if FCount <> 0 then Finalize(FList^[0], FCount); + FCount := 0; + SetCapacity(0); +end; + +function TCnAnsiStringList.Add(const S: AnsiString): Integer; +begin + Result := AddObject(S, nil); +end; + +function TCnAnsiStringList.AddObject(const S: AnsiString; AObject: TObject): Integer; +begin + if not Sorted then + Result := FCount + else + if Find(S, Result) then + case Duplicates of + dupIgnore: Exit; + dupError: Error(@SDuplicateString, 0); + end; + InsertItem(Result, S, AObject); +end; + +procedure TCnAnsiStringList.Changed; +begin + if (FUpdateCount = 0) and Assigned(FOnChange) then + FOnChange(Self); +end; + +procedure TCnAnsiStringList.Changing; +begin + if (FUpdateCount = 0) and Assigned(FOnChanging) then + FOnChanging(Self); +end; + +procedure TCnAnsiStringList.Clear; +begin + if FCount <> 0 then + begin + Changing; + Finalize(FList^[0], FCount); + FCount := 0; + SetCapacity(0); + Changed; + end; +end; + +procedure TCnAnsiStringList.Delete(Index: Integer); +begin + if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index); + Changing; + Finalize(FList^[Index]); + Dec(FCount); + if Index < FCount then + System.Move(FList^[Index + 1], FList^[Index], + (FCount - Index) * SizeOf(TCnAnsiStringItem)); + Changed; +end; + +procedure TCnAnsiStringList.Exchange(Index1, Index2: Integer); +begin + if (Index1 < 0) or (Index1 >= FCount) then Error(@SListIndexError, Index1); + if (Index2 < 0) or (Index2 >= FCount) then Error(@SListIndexError, Index2); + Changing; + ExchangeItems(Index1, Index2); + Changed; +end; + +procedure TCnAnsiStringList.ExchangeItems(Index1, Index2: Integer); +var + Temp: TCnNativeInt; + Item1, Item2: PStringItem; +begin + Item1 := @FList^[Index1]; + Item2 := @FList^[Index2]; + Temp := TCnNativeInt(Item1^.FString); + TCnNativeInt(Item1^.FString) := TCnNativeInt(Item2^.FString); + TCnNativeInt(Item2^.FString) := Temp; + Temp := TCnNativeInt(Item1^.FObject); + TCnNativeInt(Item1^.FObject) := TCnNativeInt(Item2^.FObject); + TCnNativeInt(Item2^.FObject) := Temp; +end; + +function TCnAnsiStringList.Find(const S: AnsiString; var Index: Integer): Boolean; +var + L, H, I, C: Integer; +begin + Result := False; + L := 0; + H := FCount - 1; + while L <= H do + begin + I := (L + H) shr 1; + C := CompareStrings(FList^[I].FString, S); + if C < 0 then L := I + 1 else + begin + H := I - 1; + if C = 0 then + begin + Result := True; + if Duplicates <> dupAccept then L := I; + end; + end; + end; + Index := L; +end; + +function TCnAnsiStringList.Get(Index: Integer): AnsiString; +begin + if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index); + Result := FList^[Index].FString; +end; + +function TCnAnsiStringList.GetCapacity: Integer; +begin + Result := FCapacity; +end; + +function TCnAnsiStringList.GetCount: Integer; +begin + Result := FCount; +end; + +function TCnAnsiStringList.GetObject(Index: Integer): TObject; +begin + if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index); + Result := FList^[Index].FObject; +end; + +procedure TCnAnsiStringList.Grow; +var + Delta: Integer; +begin + if FCapacity > 64 then Delta := FCapacity div 4 else + if FCapacity > 8 then Delta := 16 else + Delta := 4; + SetCapacity(FCapacity + Delta); +end; + +function TCnAnsiStringList.IndexOf(const S: AnsiString): Integer; +begin + if not Sorted then Result := inherited IndexOf(S) else + if not Find(S, Result) then Result := -1; +end; + +procedure TCnAnsiStringList.Insert(Index: Integer; const S: AnsiString); +begin + InsertObject(Index, S, nil); +end; + +procedure TCnAnsiStringList.InsertObject(Index: Integer; const S: AnsiString; + AObject: TObject); +begin + if Sorted then Error(@SSortedListError, 0); + if (Index < 0) or (Index > FCount) then Error(@SListIndexError, Index); + InsertItem(Index, S, AObject); +end; + +procedure TCnAnsiStringList.InsertItem(Index: Integer; const S: AnsiString; AObject: TObject); +begin + Changing; + if FCount = FCapacity then Grow; + if Index < FCount then + System.Move(FList^[Index], FList^[Index + 1], + (FCount - Index) * SizeOf(TCnAnsiStringItem)); + with FList^[Index] do + begin + Pointer(FString) := nil; + FObject := AObject; + FString := S; + end; + Inc(FCount); + Changed; +end; + +procedure TCnAnsiStringList.Put(Index: Integer; const S: AnsiString); +begin + if Sorted then Error(@SSortedListError, 0); + if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index); + Changing; + FList^[Index].FString := S; + Changed; +end; + +procedure TCnAnsiStringList.PutObject(Index: Integer; AObject: TObject); +begin + if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index); + Changing; + FList^[Index].FObject := AObject; + Changed; +end; + +procedure TCnAnsiStringList.QuickSort(L, R: Integer; SCompare: TCnAnsiStringListSortCompare); +var + I, J, P: Integer; +begin + repeat + I := L; + J := R; + P := (L + R) shr 1; + repeat + while SCompare(Self, I, P) < 0 do Inc(I); + while SCompare(Self, J, P) > 0 do Dec(J); + if I <= J then + begin + ExchangeItems(I, J); + if P = I then + P := J + else if P = J then + P := I; + Inc(I); + Dec(J); + end; + until I > J; + if L < J then QuickSort(L, J, SCompare); + L := I; + until I >= R; +end; + +procedure TCnAnsiStringList.SetCapacity(NewCapacity: Integer); +begin + ReallocMem(FList, NewCapacity * SizeOf(TCnAnsiStringItem)); + FCapacity := NewCapacity; +end; + +procedure TCnAnsiStringList.SetSorted(Value: Boolean); +begin + if FSorted <> Value then + begin + if Value then Sort; + FSorted := Value; + end; +end; + +procedure TCnAnsiStringList.SetUpdateState(Updating: Boolean); +begin + if Updating then Changing else Changed; +end; + +function StringListCompareStrings(List: TCnAnsiStringList; Index1, Index2: Integer): Integer; +begin + Result := List.CompareStrings(List.FList^[Index1].FString, + List.FList^[Index2].FString); +end; + +procedure TCnAnsiStringList.Sort; +begin + CustomSort(StringListCompareStrings); +end; + +procedure TCnAnsiStringList.CustomSort(Compare: TCnAnsiStringListSortCompare); +begin + if not Sorted and (FCount > 1) then + begin + Changing; + QuickSort(0, FCount - 1, Compare); + Changed; + end; +end; + +function TCnAnsiStringList.CompareStrings(const S1, S2: AnsiString): Integer; +begin + if CaseSensitive then + Result := AnsiCompareStr(string(S1), string(S2)) + else + Result := AnsiCompareText(string(S1), string(S2)); +end; + +procedure TCnAnsiStringList.SetCaseSensitive(const Value: Boolean); +begin + if Value <> FCaseSensitive then + begin + FCaseSensitive := Value; + if Sorted then Sort; + end; +end; + +{ TCnAnsiStringHash } + +procedure TCnAnsiStringHash.Add(const Key: AnsiString; Value: Integer); +var + Hash: Integer; + Bucket: PCnAnsiHashItem; +begin + Hash := HashOf(Key) mod Cardinal(Length(Buckets)); + New(Bucket); + Bucket^.Key := Key; + Bucket^.Value := Value; + Bucket^.Next := Buckets[Hash]; + Buckets[Hash] := Bucket; +end; + +procedure TCnAnsiStringHash.Clear; +var + I: Integer; + P, N: PCnAnsiHashItem; +begin + for I := 0 to Length(Buckets) - 1 do + begin + P := Buckets[I]; + while P <> nil do + begin + N := P^.Next; + Dispose(P); + P := N; + end; + Buckets[I] := nil; + end; +end; + +constructor TCnAnsiStringHash.Create(Size: Cardinal); +begin + inherited Create; + SetLength(Buckets, Size); +end; + +destructor TCnAnsiStringHash.Destroy; +begin + Clear; + inherited Destroy; +end; + +function TCnAnsiStringHash.Find(const Key: AnsiString): PPCnAnsiHashItem; +var + Hash: Integer; +begin + Hash := HashOf(Key) mod Cardinal(Length(Buckets)); + Result := @Buckets[Hash]; + while Result^ <> nil do + begin + if Result^.Key = Key then + Exit + else + Result := @Result^.Next; + end; +end; + +function TCnAnsiStringHash.HashOf(const Key: AnsiString): Cardinal; +var + I: Integer; +begin + Result := 0; + for I := 1 to Length(Key) do + Result := ((Result shl 2) or (Result shr (SizeOf(Result) * 8 - 2))) xor + Ord(Key[I]); +end; + +function TCnAnsiStringHash.Modify(const Key: AnsiString; Value: Integer): Boolean; +var + P: PCnAnsiHashItem; +begin + P := Find(Key)^; + if P <> nil then + begin + Result := True; + P^.Value := Value; + end + else + Result := False; +end; + +procedure TCnAnsiStringHash.Remove(const Key: AnsiString); +var + P: PCnAnsiHashItem; + Prev: PPCnAnsiHashItem; +begin + Prev := Find(Key); + P := Prev^; + if P <> nil then + begin + Prev^ := P^.Next; + Dispose(P); + end; +end; + +function TCnAnsiStringHash.ValueOf(const Key: AnsiString): Integer; +var + P: PCnAnsiHashItem; +begin + P := Find(Key)^; + if P <> nil then + Result := P^.Value + else + Result := -1; +end; + +{ TCnHashedAnsiStringList } + +procedure TCnHashedAnsiStringList.Changed; +begin + inherited Changed; + FValueHashValid := False; + FNameHashValid := False; +end; + +destructor TCnHashedAnsiStringList.Destroy; +begin + FValueHash.Free; + FNameHash.Free; + inherited Destroy; +end; + +function TCnHashedAnsiStringList.IndexOf(const S: AnsiString): Integer; +begin + UpdateValueHash; + if not CaseSensitive then + Result := FValueHash.ValueOf(AnsiString(AnsiUpperCase(string(S)))) + else + Result := FValueHash.ValueOf(S); +end; + +function TCnHashedAnsiStringList.IndexOfName(const Name: AnsiString): Integer; +begin + UpdateNameHash; + if not CaseSensitive then + Result := FNameHash.ValueOf(AnsiString(AnsiUpperCase(string(Name)))) + else + Result := FNameHash.ValueOf(Name); +end; + +procedure TCnHashedAnsiStringList.UpdateNameHash; +var + I: Integer; + P: Integer; + Key: AnsiString; +begin + if FNameHashValid then Exit; + + if FNameHash = nil then + FNameHash := TCnAnsiStringHash.Create + else + FNameHash.Clear; + for I := 0 to Count - 1 do + begin + Key := Get(I); + P := AnsiPos('=', string(Key)); + if P <> 0 then + begin + if not CaseSensitive then + Key := AnsiString(AnsiUpperCase(string(Copy(Key, 1, P - 1)))) + else + Key := Copy(Key, 1, P - 1); + FNameHash.Add(Key, I); + end; + end; + FNameHashValid := True; +end; + +procedure TCnHashedAnsiStringList.UpdateValueHash; +var + I: Integer; +begin + if FValueHashValid then Exit; + + if FValueHash = nil then + FValueHash := TCnAnsiStringHash.Create + else + FValueHash.Clear; + for I := 0 to Count - 1 do + if not CaseSensitive then + FValueHash.Add(AnsiString(AnsiUpperCase(string(Self[I]))), I) + else + FValueHash.Add(Self[I], I); + FValueHashValid := True; +end; + +// жһַǷƥķָ +function IsSepChar(AChar: Char): Boolean; +begin +{$IFDEF UNICODE} + Result := not CharInSet(AChar, ['0'..'9', 'A'..'Z', 'a'..'z', '_']); +{$ELSE} + Result := not (AChar in ['0'..'9', 'A'..'Z', 'a'..'z', '_']); +{$ENDIF} +end; + +function IsSepCharA(AChar: AnsiChar): Boolean; +begin + Result := not (AChar in ['0'..'9', 'A'..'Z', 'a'..'z', '_']); +end; + +function IsSepCharW(AChar: WideChar): Boolean; +begin + Result := (Ord(AChar) < 127) and not (AnsiChar(AChar) in ['0'..'9', 'A'..'Z', 'a'..'z', '_']); +end; + +function CnStringReplace(const S, OldPattern, NewPattern: string; + Flags: TCnReplaceFlags): string; +var + SearchStr, Patt, NewStr: string; + Offset, TailOffset: Integer; + IsWhole: Boolean; +begin + if crfIgnoreCase in Flags then + begin +{$IFDEF UNICODE} + SearchStr := UpperCase(S); + Patt := UpperCase(OldPattern); +{$ELSE} + SearchStr := AnsiUpperCase(S); + Patt := AnsiUpperCase(OldPattern); +{$ENDIF} + end + else + begin + SearchStr := S; + Patt := OldPattern; + end; + + NewStr := S; + Result := ''; + + while SearchStr <> '' do + begin +{$IFDEF UNICODE} + Offset := Pos(Patt, SearchStr); +{$ELSE} + Offset := AnsiPos(Patt, SearchStr); +{$ENDIF} + IsWhole := True; + if Offset = 0 then + begin + Result := Result + NewStr; + Break; + end + else if crfWholeWord in Flags then + begin + // ҵӴҪƥ䣬жϣ + // ͷͷǷָββǷָ + if (Offset > 1) and not IsSepChar(SearchStr[Offset - 1]) then + IsWhole := False + else + begin + TailOffset := Offset + Length(Patt); // ָƥһַ + if (TailOffset <= Length(SearchStr)) and not IsSepChar(SearchStr[TailOffset]) then + IsWhole := False; + end; + + // õǷƥĽ + end; + + if not (crfWholeWord in Flags) or IsWhole then // ͨƥƥ + begin + // 滻һ + Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern; + NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt); + if not (crfReplaceAll in Flags) then + begin + Result := Result + NewStr; + Break; + end; + end + else // ƥҪ£δƥ䣬滻 + begin + Result := Result + Copy(NewStr, 1, Offset - 1) + OldPattern; // ע OldePattern滻 + NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt); + end; + SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt); + end; +end; + +{$IFDEF UNICODE} + +function CnStringReplaceA(const S, OldPattern, NewPattern: AnsiString; + Flags: TCnReplaceFlags): AnsiString; +var + SearchStr, Patt, NewStr: AnsiString; + Offset, TailOffset: Integer; + IsWhole: Boolean; +begin + if crfIgnoreCase in Flags then + begin + SearchStr := AnsiUpperCase(S); + Patt := AnsiUpperCase(OldPattern); + end + else + begin + SearchStr := S; + Patt := OldPattern; + end; + + NewStr := S; + Result := ''; + + while SearchStr <> '' do + begin + Offset := AnsiPos(Patt, SearchStr); + IsWhole := True; + if Offset = 0 then + begin + Result := Result + NewStr; + Break; + end + else if crfWholeWord in Flags then + begin + // ҵӴҪƥ䣬жϣ + // ͷͷǷָββǷָ + if (Offset > 1) and not IsSepCharA(SearchStr[Offset - 1]) then + IsWhole := False + else + begin + TailOffset := Offset + Length(Patt); // ָƥһַ + if (TailOffset <= Length(SearchStr)) and not IsSepCharA(SearchStr[TailOffset]) then + IsWhole := False; + end; + + // õǷƥĽ + end; + + if not (crfWholeWord in Flags) or IsWhole then // ͨƥƥ + begin + // 滻һ + Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern; + NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt); + if not (crfReplaceAll in Flags) then + begin + Result := Result + NewStr; + Break; + end; + end + else // ƥҪ£δƥ䣬滻 + begin + Result := Result + Copy(NewStr, 1, Offset - 1) + OldPattern; // ע OldePattern滻 + NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt); + end; + SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt); + end; +end; + +{$ELSE} + +function CnStringReplaceW(const S, OldPattern, NewPattern: WideString; + Flags: TCnReplaceFlags): WideString; +var + SearchStr, Patt, NewStr: WideString; + Offset, TailOffset: Integer; + IsWhole: Boolean; +begin + if crfIgnoreCase in Flags then + begin + SearchStr := UpperCase(S); + Patt := UpperCase(OldPattern); + end + else + begin + SearchStr := S; + Patt := OldPattern; + end; + + NewStr := S; + Result := ''; + + while SearchStr <> '' do + begin + Offset := Pos(Patt, SearchStr); + IsWhole := True; + if Offset = 0 then + begin + Result := Result + NewStr; + Break; + end + else if crfWholeWord in Flags then + begin + // ҵӴҪƥ䣬жϣ + // ͷͷǷָββǷָ + if (Offset > 1) and not IsSepCharW(SearchStr[Offset - 1]) then + IsWhole := False + else + begin + TailOffset := Offset + Length(Patt); // ָƥһַ + if (TailOffset <= Length(SearchStr)) and not IsSepCharW(SearchStr[TailOffset]) then + IsWhole := False; + end; + + // õǷƥĽ + end; + + if not (crfWholeWord in Flags) or IsWhole then // ͨƥƥ + begin + // 滻һ + Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern; + NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt); + if not (crfReplaceAll in Flags) then + begin + Result := Result + NewStr; + Break; + end; + end + else // ƥҪ£δƥ䣬滻 + begin + Result := Result + Copy(NewStr, 1, Offset - 1) + OldPattern; // ע OldePattern滻 + NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt); + end; + SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt); + end; +end; + +{$ENDIF} + +function CnPosEx(const SubStr, S: string; CaseSensitive: Boolean; WholeWords: + Boolean; StartCount: Integer): Integer; +var + P: PChar; + I, Count, Len, SubLen: Integer; + StrUpper, SubUpper: string; +begin + Result := 0; + if (SubStr = '') or (S = '') or (StartCount < 1) then + Exit; + + Len := Length(S); + SubLen := Length(SubStr); + if SubLen > Len then + Exit; + + if not CaseSensitive then + begin + StrUpper := UpperCase(S); + SubUpper := UpperCase(SubStr); + P := PChar(StrUpper); + end + else + P := PChar(S); + + Count := 0; + for I := 1 to Len - SubLen + 1 do + begin + if (CaseSensitive and (P^ = SubStr[1]) and + (CompareMem(P, PChar(SubStr), SubLen * SizeOf(Char)))) + or + (not CaseSensitive and (P^ = SubUpper[1]) and + (CompareMem(P, PChar(SubUpper), SubLen * SizeOf(Char)))) then + begin + if WholeWords then + begin + // Ƿƥ + if ((I = 1) or IsSepChar((P - 1)^)) and + ((I + SubLen - 1 >= Len) or IsSepChar((P + SubLen)^)) then + begin + Inc(Count); + if Count = StartCount then + begin + Result := I; + Exit; + end; + end; + end + else + begin + Inc(Count); + if Count = StartCount then + begin + Result := I; + Exit; + end; + end; + end; + Inc(P); + end; +end; + +procedure CnSplitString(const Sub: string; const Str: string; Strings: TStrings); +var + S: string; + P, SubLen: Integer; +begin + if Strings = nil then + Exit; // Կָ + + Strings.Clear; // ԭ + + // ָΪյַΪһĿ + if Sub = '' then + begin + Strings.Add(Str); + Exit; + end; + + // ԴַΪյһĿ + if Str = '' then + begin + Strings.Add(''); + Exit; + end; + + SubLen := Length(Sub); + S := Str; // Դַĸ޸Ĵ˸ + + while S <> '' do + begin + P := Pos(Sub, S); // ʣַвҷָ + + if P = 0 then + begin + // ûиָʣಿΪһĿ + Strings.Add(S); + Break; + end; + + // ȡӿͷָǰݣΪգ + Strings.Add(Copy(S, 1, P - 1)); + + // ɾѴIJ֣ҵķָ + Delete(S, 1, P + SubLen - 1); + + // ɾַΪգԭַԷָβҪһĿ + if S = '' then + Strings.Add(''); + end; +end; + +{$WARNINGS ON} + +{ TCnStringBuilder } + +constructor TCnStringBuilder.Create; +begin + inherited; + if not FModeIsFromOut then // ⲿδָʱԶģʽ + begin +{$IFDEF UNICODE} + FAnsiMode := False; +{$ELSE} + FAnsiMode := True; +{$ENDIF} + end + else + FAnsiMode := FOutMode; + + if FAnsiMode then + FMaxCharCapacity := MaxInt + else + FMaxCharCapacity := MaxInt div 2; + + CharCapacity := STRING_BUILDER_DEFAULT_CAPACITY; + FCharLength := 0; +end; + +function TCnStringBuilder.Append(const Value: string): TCnStringBuilder; +begin +{$IFDEF UNICODE} + if FAnsiMode then + Result := AppendAnsi(AnsiString(Value)) + else + Result := AppendString(Value); +{$ELSE} + if FAnsiMode then + Result := AppendString(Value) + else + Result := AppendWide(WideString(Value)); +{$ENDIF} +end; + +{$IFDEF UNICODE} + +function TCnStringBuilder.AppendAnsi(const Value: AnsiString): TCnStringBuilder; +var + Delta, OL: Integer; +begin + Delta := Length(Value); + if Delta <> 0 then + begin + OL := CharLength; + CharLength := CharLength + Delta; + if CharLength > CharCapacity then + ExpandCharCapacity; + Move(Pointer(Value)^, (PAnsiChar(Pointer(FAnsiData)) + OL)^, Delta * SizeOf(AnsiChar)); + end; + Result := Self; +end; + +{$ELSE} + +function TCnStringBuilder.AppendWide(const Value: WideString): TCnStringBuilder; +var + Delta, OL: Integer; +begin + Delta := Length(Value); + if Delta <> 0 then + begin + OL := CharLength; + CharLength := CharLength + Delta; + if CharLength > CharCapacity then + ExpandCharCapacity; + Move(Pointer(Value)^, (PWideChar(Pointer(FWideData)) + OL)^, Delta * SizeOf(WideChar)); + end; + Result := Self; +end; + +{$ENDIF} + +constructor TCnStringBuilder.Create(IsAnsi: Boolean); +begin + FModeIsFromOut := True; + FOutMode := IsAnsi; // ⲿָ AnsiMode + Create; +end; + +destructor TCnStringBuilder.Destroy; +begin + inherited; + +end; + +procedure TCnStringBuilder.ExpandCharCapacity; +var + NC: Integer; +begin + NC := (CharCapacity * 3) div 2; + if CharLength > NC then + NC := CharLength * 2; + if NC > FMaxCharCapacity then + NC := FMaxCharCapacity; + if NC < 0 then + NC := CharLength; + + CharCapacity := NC; +end; + +function TCnStringBuilder.GetCharCapacity: Integer; +begin +{$IFDEF UNICODE} + if FAnsiMode then + Result := Length(FAnsiData) + else + Result := Length(FData); +{$ELSE} + if FAnsiMode then + Result := Length(FData) + else + Result := Length(FWideData); +{$ENDIF} +end; + +procedure TCnStringBuilder.SetCharCapacity(const Value: Integer); +begin + if (Value < FCharLength) or (Value > FMaxCharCapacity) then + raise ERangeError.CreateResFmt(@SListCapacityError, [Value]); + +{$IFDEF UNICODE} + if FAnsiMode then + SetLength(FAnsiData, Value) // FAnsiData + else + SetLength(FData, Value); // FData +{$ELSE} + if FAnsiMode then + SetLength(FData, Value) // FData + else + SetLength(FWideData, Value); // FWideData +{$ENDIF} +end; + +procedure TCnStringBuilder.SetCharLength(const Value: Integer); +var + OL: Integer; +begin + if (Value < 0) or (Value > FMaxCharCapacity) then + raise ERangeError.CreateResFmt(@SListCapacityError, [Value]); + + OL := FCharLength; + try + FCharLength := Value; + if FCharLength > CharCapacity then + ExpandCharCapacity; + except + on E: EOutOfMemory do + begin + FCharLength := OL; + raise; + end; + end; +end; + +function TCnStringBuilder.AppendString(const Value: string): TCnStringBuilder; +var + Delta, OL: Integer; +begin + Delta := Length(Value); + if Delta <> 0 then + begin + OL := CharLength; + FCharLength := CharLength + Delta; + if CharLength > CharCapacity then + ExpandCharCapacity; + + Move(Pointer(Value)^, (PChar(Pointer(FData)) + OL)^, Delta * SizeOf(Char)); + end; + Result := Self; +end; + +function TCnStringBuilder.ToString: string; +begin + if FCharLength = CharCapacity then + Result := FData + else + Result := Copy(FData, 1, FCharLength); +end; + +function TCnStringBuilder.ToAnsiString: AnsiString; +begin +{$IFDEF UNICODE} + if FAnsiMode then // Unicode Ansi ģʽ FAnsiDataת + begin + if FCharLength = CharCapacity then + Result := FAnsiData + else + Result := Copy(FAnsiData, 1, FCharLength); + end + else // Unicode Ƿ Ansi ģʽ FData AnsiString ת + begin + if FCharLength = CharCapacity then + Result := AnsiString(FData) + else + Result := AnsiString(Copy(FData, 1, FCharLength)); + end; +{$ELSE} + Result := ToString; // Unicode µ ToString +{$ENDIF} +end; + +function TCnStringBuilder.ToWideString: WideString; +begin +{$IFNDEF UNICODE} + if FAnsiMode then // Unicode Ansi ģʽ FData WideString ת + begin + if FCharLength = CharCapacity then + Result := WideString(FData) + else + Result := WideString(Copy(FData, 1, FCharLength)); + end + else // Unicode Ƿ Ansi ģʽ FWideDataת + begin + if FCharLength = CharCapacity then + Result := FWideData + else + Result := Copy(FWideData, 1, FCharLength); + end; +{$ELSE} + Result := ToString; // Unicode µ ToString +{$ENDIF} +end; + +function TCnStringBuilder.Append(Value: Integer): TCnStringBuilder; +begin + Result := Append(IntToStr(Value)); +end; + +function TCnStringBuilder.Append(Value: SmallInt): TCnStringBuilder; +begin + Result := Append(IntToStr(Value)); +end; + +function TCnStringBuilder.Append(Value: TObject): TCnStringBuilder; +begin +{$IFDEF OBJECT_HAS_TOSTRING} + Result := Append(Value.ToString); +{$ELSE} + Result := Append(IntToHex(TCnNativeInt(Value), 2)); +{$ENDIF} +end; + +function TCnStringBuilder.Append(Value: Int64): TCnStringBuilder; +begin + Result := Append(IntToStr(Value)); +end; + +function TCnStringBuilder.Append(Value: Double): TCnStringBuilder; +begin + Result := Append(FloatToStr(Value)); +end; + +function TCnStringBuilder.Append(Value: Byte): TCnStringBuilder; +begin + Result := Append(IntToStr(Value)); +end; + +function TCnStringBuilder.Append(Value: Boolean): TCnStringBuilder; +begin + if Value then + Result := Append('True') + else + Result := Append('False'); +end; + +function TCnStringBuilder.AppendCurrency(Value: Currency): TCnStringBuilder; +begin + Result := Append(CurrToStr(Value)); +end; + +function TCnStringBuilder.AppendChar(Value: Char): TCnStringBuilder; +var + S: string; +begin + SetLength(S, 1); + Move(Value, S[1], SizeOf(Char)); + Result := Append(S); +end; + +function TCnStringBuilder.Append(Value: ShortInt): TCnStringBuilder; +begin + Result := Append(IntToStr(Value)); +end; + +function TCnStringBuilder.Append(Value: Char; + RepeatCount: Integer): TCnStringBuilder; +begin + Result := Append(StringOfChar(Value, RepeatCount)); +end; + +function TCnStringBuilder.Append(Value: PAnsiChar): TCnStringBuilder; +begin + Result := Append(string(Value)); +end; + +function TCnStringBuilder.Append(const Value: string; StartIndex, + Count: Integer): TCnStringBuilder; +begin + Result := Append(Copy(Value, StartIndex, Count)); +end; + +function TCnStringBuilder.Append(Value: Cardinal): TCnStringBuilder; +begin + Result := Append(UInt32ToStr(Value)); +end; + +{$IFDEF SUPPORT_UINT64} + +function TCnStringBuilder.Append(Value: UInt64): TCnStringBuilder; +begin + Result := Append(UInt64ToStr(Value)); +end; + +{$ENDIF} + +function TCnStringBuilder.Append(Value: Single): TCnStringBuilder; +begin + Result := Append(FloatToStr(Value)); +end; + +function TCnStringBuilder.Append(Value: Word): TCnStringBuilder; +begin + Result := Append(IntToStr(Value)); +end; + +procedure TCnStringBuilder.Clear; +begin + CharLength := 0; + CharCapacity := STRING_BUILDER_DEFAULT_CAPACITY; +end; + +function TCnStringBuilder.AppendLine: TCnStringBuilder; +begin + Result := Append(SLineBreak); +end; + +function TCnStringBuilder.AppendLine(const Value: string): TCnStringBuilder; +begin + Result := Append(Value + SLineBreak); +end; + +function TCnStringBuilder.Append(const AFormat: string; + const Args: array of const): TCnStringBuilder; +begin + Result := Append(Format(AFormat, Args)); +end; + +function TCnStringBuilder.AppendAnsiChar(Value: AnsiChar): TCnStringBuilder; +var + S: AnsiString; +begin + SetLength(S, 1); + Move(Value, S[1], SizeOf(AnsiChar)); +{$IFDEF UNICODE} + Result := AppendAnsi(S); +{$ELSE} + Result := Append(S); // Unicode S תΪ string ܻʺ +{$ENDIF} +end; + +function TCnStringBuilder.AppendWideChar(Value: WideChar): TCnStringBuilder; +var + S: WideString; +begin + SetLength(S, 1); + Move(Value, S[1], SizeOf(WideChar)); +{$IFDEF UNICODE} + Result := Append(S); +{$ELSE} + Result := AppendWide(S); +{$ENDIF} +end; + +end. diff --git a/CnPack/Common/CnWideStrings.pas b/CnPack/Common/CnWideStrings.pas new file mode 100644 index 0000000..ae4115b --- /dev/null +++ b/CnPack/Common/CnWideStrings.pas @@ -0,0 +1,2215 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnWideStrings; +{* |
+================================================================================
+* ƣ
+* ԪƣWideStrings Ԫ֧ Win32/64  Posix
+* ԪߣCnPack 
+*     עõԪʵ˼򻯵 TCnWideStringList 벿 Unicode ַ
+*           Լչ UTF-8  UTF-16 ı뺯֧ UTF-16 еַֽ UTF8-MB4
+*
+*           ⣬Ԫڴ Ansi ַ Utf16 ַתʱ漰
+*           һַֽռпռʾȱ
+*           ͬųǰ߲ܵͬʴҪ ByteLength  DisplayLength
+*           ȡַֽ IDE Ϊ޹أ ByteLength ϵк
+*           ռпռʾȱҪ IDE Ϊйأ IDE 汾йأ
+*            DisplayLength ϵкͬط벻ͬ Calculator м
+*
+*           䣺Lazarus IDE бʱʹ LConvEncoding תƺ׵
+*
+* ƽ̨WinXP SP3 + Delphi 5.0
+* ݲԣ
+*   õԪеַϱػʽ
+* ޸ļ¼2025.08.06 V1.3
+*               Ansi תΪ Utf8 ֧ FPC
+*           2024.08.01 V1.3
+*               ַָʾȼص㲿Զ
+*               ֳ Ansi  ByteLength  DisplayLength ϵк
+*               жʾȡеȣҪ DisplayLength ϵк
+*                IDE Ҫ󣬻ô붨ƻ Calculator
+*           2022.11.25 V1.2
+*                CnGB18030 аƹ Unicode 
+*           2022.11.10 V1.1
+*               UTF-8 ֧ UTF8-MB4  UTF-16 еַֽ
+*           2010.01.16 by ZhouJingyu
+*               ʼύ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +// {$DEFINE UTF16_BE} + +// Delphi Ĭ UTF16-LEҪ UTF16-BE ַҪ UTF16_BE + +uses + {$IFDEF MSWINDOWS} Windows, {$ENDIF} SysUtils, Classes, CnNative + {$IFDEF LAZARUS}, LConvEncoding {$ENDIF}; + +const + CN_INVALID_CODEPOINT = $FFFFFFFF; + {* Ƿֵ} + + CN_ALTERNATIVE_CHAR = '?'; + {* תʱĬ滻ַ} + +type + ECnWideStringException = class(Exception); + {* ַ쳣} + +{$IFDEF UNICODE} + TCnWideString = string; +{$ELSE} + TCnWideString = WideString; +{$ENDIF} + + TCnCodePoint = type Cardinal; + {* ֵַ߽㣬ڱı뷽ʽ} + + TCn2CharRec = packed record + {* ˫ַֽṹ} + P1: AnsiChar; + P2: AnsiChar; + end; + PCn2CharRec = ^TCn2CharRec; + + TCn4CharRec = packed record + {* ַֽṹ} + P1: AnsiChar; + P2: AnsiChar; + P3: AnsiChar; + P4: AnsiChar; + end; + PCn4CharRec = ^TCn4CharRec; + +{ TCnWideStringList } + + TCnWideListFormat = (wlfAnsi, wlfUtf8, wlfUnicode); + {* 뱣ʱֱֵ֧룬AnsiUtf8Utf16} + + TCnWideStringList = class; + TCnWideStringListSortCompare = function(List: TCnWideStringList; Index1, Index2: Integer): Integer; + + PCnWideStringItem = ^TCnWideStringItem; + TCnWideStringItem = record + FString: WideString; + FObject: TObject; + end; + + TCnWideStringList = class(TPersistent) + {* WideString TStringList ʵ֣Load/Save ʱбĴ} + private + FList: TList; + FUseSingleLF: Boolean; + FLoadFormat: TCnWideListFormat; + FWriteBOM: Boolean; + function GetName(Index: Integer): WideString; + function GetValue(const Name: WideString): WideString; + procedure SetValue(const Name, Value: WideString); + procedure QuickSort(L, R: Integer; SCompare: TCnWideStringListSortCompare); + function GetObject(Index: Integer): TObject; + procedure PutObject(Index: Integer; const Value: TObject); + protected + function Get(Index: Integer): WideString; virtual; + function GetCount: Integer; virtual; + function GetTextStr: WideString; virtual; + procedure Put(Index: Integer; const S: WideString); virtual; + procedure SetTextStr(const Value: WideString); virtual; + public + constructor Create; + destructor Destroy; override; + function Add(const S: WideString): Integer; virtual; + procedure AddStrings(Strings: TCnWideStringList); virtual; + function AddObject(const S: WideString; AObject: TObject): Integer; virtual; + procedure Assign(Source: TPersistent); override; + procedure Clear; virtual; + procedure Delete(Index: Integer); virtual; + procedure Exchange(Index1, Index2: Integer); virtual; + function IndexOf(const S: WideString): Integer; virtual; + function IndexOfName(const Name: WideString): Integer; + procedure Insert(Index: Integer; const S: WideString); virtual; + procedure LoadFromFile(const FileName: WideString); virtual; + procedure LoadFromStream(Stream: TStream); virtual; + procedure SaveToFile(const FileName: WideString; AFormat: TCnWideListFormat = wlfUnicode); virtual; + procedure SaveToStream(Stream: TStream; AFormat: TCnWideListFormat = wlfUnicode); virtual; + procedure CustomSort(Compare: TCnWideStringListSortCompare); virtual; + procedure Sort; virtual; + property Count: Integer read GetCount; + property Names[Index: Integer]: WideString read GetName; + property Objects[Index: Integer]: TObject read GetObject write PutObject; + property Values[const Name: WideString]: WideString read GetValue write SetValue; + property Strings[Index: Integer]: WideString read Get write Put; default; + property Text: WideString read GetTextStr write SetTextStr; + + property UseSingleLF: Boolean read FUseSingleLF write FUseSingleLF; + {* GetTextStr ʱʹõĻǷǵ #10 dz #13#10} + property LoadFormat: TCnWideListFormat read FLoadFormat; + {* LoadFromStream ʱʶĸʽ} + property WriteBOM: Boolean read FWriteBOM write FWriteBOM; + {* Ƿд BOM ͷ} + end; + + TCnWideCharDisplayWideLengthCalculator = function(AWChar: WideChar): Boolean; + {* Կַʾȼصͣͬ Delphi IDE ༭Ҫͬʵ} + +function CnUtf8EncodeWideString(const S: TCnWideString): AnsiString; +{* WideString UTF-8 벢ݷŵ AnsiString зأ Ansi תⶪַ + ֽ֧ UTF-16 ַ UTF8-MB4 + + + const S: WideString/UnicodeString - תĿַ + + ֵAnsiString - UTF-8 ַ +} + +function CnUtf8DecodeToWideString(const S: AnsiString): TCnWideString; +{* UTF-8 AnsiString UTF-8 õ WideString Ansi תⶪַ + ֽ֧ UTF-16 ַ UTF8-MB4 + + + const S: AnsiString - ת UTF-8 ַ + + ֵWideString/UnicodeString - صĿַ +} + +function GetUtf16HighByte(Rec: PCn2CharRec): Byte; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* õһ UTF-16 ˫ַֽĸλֵֽ + + + Rec: PCn2CharRec - ȡ˫ַֽṹָ + + ֵByte - ظλֵֽ +} + +function GetUtf16LowByte(Rec: PCn2CharRec): Byte; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* õһ UTF-16 ˫ַֽĵλֵֽ + + + Rec: PCn2CharRec - ȡ˫ַֽṹָ + + ֵByte - صλֵֽ +} + +procedure SetUtf16HighByte(B: Byte; Rec: PCn2CharRec); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* һ UTF-16 ˫ַֽĸλֵֽ + + + B: Byte - õĸλֵֽ + Rec: PCn2CharRec - õ˫ַֽṹָ + + ֵޣ +} + +procedure SetUtf16LowByte(B: Byte; Rec: PCn2CharRec); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* һ UTF-16 ˫ַֽĵλֵֽ + + + B: Byte - õĵλֵֽ + Rec: PCn2CharRec - õ˫ַֽṹָ + + ֵޣ +} + +function GetCharLengthFromUtf8(Utf8Str: PAnsiChar): Integer; +{* һ UTF-8 UTF8-MB4ַַ + + + Utf8Str: PAnsiChar - UTF-8 ַַ + + ֵInteger - ظַַ +} + +function GetCharLengthFromUtf16(Utf16Str: PWideChar): Integer; +{* һ UTF-16ܻ Unicode չƽַַַֽ + + + Utf16Str: PWideChar - UTF-16 ַַ + + ֵInteger - ظַַ +} + +function GetByteWidthFromUtf8(Utf8Str: PAnsiChar): Integer; +{* һ UTF-8 UTF8-MB4ַĵǰַռֽڡ + + + Utf8Str: PAnsiChar - UTF-8 ַַ + + ֵInteger - ظַֽ +} + +function GetByteWidthFromUtf16(Utf16Str: PWideChar): Integer; +{* һ UTF-16ܻ Unicode չƽַַֽĵǰַռֽڡ + + + Utf16Str: PWideChar - UTF-16 ַַ + + ֵInteger - ظַֽ +} + +function GetCodePointFromUtf16Char(Utf16Str: PWideChar): TCnCodePoint; +{* һ UTF-16 ַıֵҲдλãע Utf16Str ָһ˫ַֽҲָһַֽ + + + Utf16Str: PWideChar - UTF-16 ַַ + + ֵTCnCodePoint - ظַıֵ +} + +function GetCodePointFromUtf164Char(PtrTo4Char: Pointer): TCnCodePoint; +{* һֽ UTF-16 ַıֵҲдλã + + + PtrTo4Char: Pointer - ֽ UTF-16 ַַ + + ֵTCnCodePoint - ظַıֵ +} + +function GetUtf16CharFromCodePoint(CP: TCnCodePoint; PtrToChars: Pointer): Integer; +{* һ Unicode ֵĶֽڻֽڱʾ PtrToChars ָλòΪգ + 򽫽 PtrToChars ָĶֽڻֽǷ򷵻 1 PtrToChars Ϊ #0#0 + CP $FFFF ʱ뱣֤ PtrToChars ָֽڣֽ֮ڼɡ + 1 2ֱʾǶֽڻֽڡ + + + CP: TCnCodePoint - Unicode ֵ + PtrToChars: Pointer - nilתĽ + + ֵInteger - 1 ַռֽڣ 2 ֽ +} + +// ============================================================================= +// +// º漰ַ UTF-8 תʱļ㣬߼ȽϹ̶ +// +// ============================================================================= + +function CalcUtf8LengthFromWideString(Text: PWideChar): Integer; +{* ַ UTF-8 ȣ Utf8Encode ȡ Lengthʵת + + + Text: PWideChar - Ŀַַ + + ֵInteger - UTF-8 ֽڳ +} + +function CalcUtf8LengthFromWideChar(AChar: WideChar): Integer; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* һ WideChar ת UTF-8 ַȡ + + + AChar: WideChar - Ŀַ + + ֵInteger - UTF-8 ֽڳ +} + +function CalcUtf8LengthFromWideStringOffset(Text: PWideChar; WideOffset: Integer): Integer; +{* Unicode ַ 1 WideOffset Ӵ UTF-8 ȣWideOffset 1 ʼ WideOffset 0 򷵻 0 + Copy(1, WideOffset) Ӵת UTF-8 ȡ Lengthʵת + + + Text: PWideChar - Ŀַַ + WideOffset: Integer - ԿַΪλƫ + + ֵInteger - ظÿַ 1 WideOffset Ӵ UTF-8 +} + +function CalcUtf8LengthFromWideStringAnsiOffset(Text: PWideChar; AnsiOffset: Integer): Integer; +{* Unicode ַת Ansi 1 AnsiOffset Ӵ UTF-8 ȣAnsiOffset 1 ʼ AnsiOffset 0 򷵻 0 + ת Ansi Copy(1, AnsiOffset) Ӵת Unicode ַת UTF-8 ȡ Lengthʵת + + + Text: PWideChar - Ŀַַ + AnsiOffset: Integer - Ansi ַΪλƫ + + ֵInteger - ظÿַת Ansi 1 AnsiOffset Ӵ UTF-8 +} + +function CalcUtf8LengthFromUtf8HeadChar(AChar: AnsiChar): Integer; +{* һ UTF-8 ǰַַȡ + + + AChar: AnsiChar - UTF-8 ַ + + ֵInteger - ַ +} + +function CalcUtf8StringLengthFromWideOffset(Utf8Text: PAnsiChar; WideOffset: Integer): Integer; +{* UTF-8 ַת WideSting ָ Wide ӴȶӦ UTF-8 ַȣWideOffset 1 ʼ + ת WideString Copy(1, WideOffset) ת UTF-8 ȡ Length UTF-8/WideString תԱı⡣ + + + Utf8Text: PAnsiChar - UTF-8 ַַ + WideOffset: Integer - ԿַΪλƫ + + ֵInteger - ظ UTF-8 ַת WideSting ָ 1 WideOffset ӴӦ UTF-8 ַ +} + +// ============================================================================= +// +// º漰ַ Ansi תʱֽռп/ռʾȱȵļ +// +// ============================================================================= + +function WideCharIsWideLength(const AWChar: WideChar): Boolean; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* жһ Unicode ַǷռַȣĬϵļªʵ֣ IDE 汾Ϊ޹ء + ºе TCnWideCharDisplayWideLengthCalculator Ĭʵ֡ + + + const AWChar: WideChar - жϵĿַ + + ֵBoolean - Ƿռַ +} + +function CalcAnsiByteLengthFromWideString(Text: PWideChar): Integer; +{* Unicode ַ Ansi ֽڳȣת Ansi Lengthת AnsiԷֹӢƽ̨¶ַ + $FF UTF-16 ַ 2 ֽڣΪ 1 ֽڡ + + + Text: PWideChar - Ŀַַ + + ֵInteger - ת Ansi ַ +} + +function CalcAnsiDisplayLengthFromWideString(Text: PWideChar; + Calculator: TCnWideCharDisplayWideLengthCalculator = nil): Integer; +{* Unicode ַ Ansi ʾȣת Ansi ʾ Lengthת AnsiԷֹӢƽ̨¶ַ + Դ Calculator ʾַȣʱĬжϡ + + + Text: PWideChar - Ŀַַ + Calculator: TCnWideCharDisplayWideLengthCalculator - Կַʾȼصͬ Delphi IDE ༭вͬ + + ֵInteger - ת Ansi ַʾ +} + +function CalcAnsiByteLengthFromWideStringOffset(Text: PWideChar; WideOffset: Integer): Integer; +{* Unicode ַ 1 WideOffset Ӵ Ansi ֽڳȣWideOffset 1 ʼ + Copy(1, WideOffset) Ӵת Ansi ֽȡ Lengthʵת AnsiԷֹӢƽ̨¶ַ + $FF UTF-16 ַ 2 ֽڣΪ 1 ֽڡ + + + Text: PWideChar - Ŀַַ + WideOffset: Integer - ԿַΪλƫ + + ֵInteger - ظÿַ 1 WideOffset Ӵ Ansi ֽڳ +} + +function CalcAnsiDisplayLengthFromWideStringOffset(Text: PWideChar; WideOffset: Integer; + Calculator: TCnWideCharDisplayWideLengthCalculator = nil): Integer; +{* Unicode ַ 1 WideOffset Ӵ Ansi ʾȣWideOffset 1 ʼ + Copy(1, WideOffset) Ӵת Ansi ȡ Lengthʵת AnsiԷֹӢƽ̨¶ַ + Դ Calculator ʾַȣʱĬжϡ + + + Text: PWideChar - Ŀַַ + WideOffset: Integer - ַĿȼصͬ Delphi IDE ༭вͬ + Calculator: TCnWideCharDisplayWideLengthCalculator - Կַʾȼصͬ Delphi IDE ༭вͬ + + ֵInteger - ظÿַ 1 WideOffset Ӵ Ansi ʾ +} + +function CalcWideStringByteLengthFromAnsiOffset(Text: PWideChar; AnsiOffset: Integer; + AllowExceedEnd: Boolean = False): Integer; +{* Unicode ַָ Ansi ӴȶӦ Unicode ӴֽڳȣAnsiOffset 1 ʼ + ת Ansi Copy(1, AnsiOffset) ת Unicode ȡ Length Ansi/Unicode תԷֹӢƽ̨¶ַ + ע Ansi Copy ܻ˫ַֽ + AllowExceedEnd Ϊ False ʱ㵽 #0 ֹ #0Ϊ True ʱԲոʽ㡣 + $FF UTF-16 ַ 2 ֽڣΪ 1 ֽڡ + + + Text: PWideChar - Ŀַַ + AnsiOffset: Integer - ԵַֽΪλƫ + AllowExceedEnd: Boolean - Ƿ #0 ʱֹ + + ֵInteger - ظÿַתΪ Ansi 1 AnsiOffset ӴȶӦ Unicode ַֽڳ +} + +function CalcWideStringDisplayLengthFromAnsiOffset(Text: PWideChar; AnsiOffset: Integer; + AllowExceedEnd: Boolean = False; Calculator: TCnWideCharDisplayWideLengthCalculator = nil): Integer; +{* Unicode ַָ Ansi ӴȶӦ Unicode ӴȣAnsiOffset 1 ʼ + ʾת Ansi Copy(1, AnsiOffset) ת Unicode ȡ Length Ansi/Unicode תԷֹӢƽ̨¶ַ + ע Ansi Copy ܻ˫ַֽ + AllowExceedEnd Ϊ False ʱ㵽 #0 ֹ #0Ϊ True ʱԲոʽ + Դ Calculator ʾַȣʱĬжϡ + + + Text: PWideChar - Ŀַַ + AnsiOffset: Integer - ԵַֽΪλƫ + AllowExceedEnd: Boolean - Ƿ #0 ʱֹ + Calculator: TCnWideCharDisplayWideLengthCalculator - Կַʾȼصͬ Delphi IDE ༭вͬ + + ֵInteger - ظÿַתΪ Ansi 1 AnsiOffset ӴȶӦ Unicode ַʾ +} + +function CalcUtf8LengthFromWideStringAnsiDisplayOffset(Text: PWideChar; AnsiDisplayOffset: Integer; + Calculator: TCnWideCharDisplayWideLengthCalculator = nil): Integer; +{* Unicode ַתʾص Ansi 1 AnsiOffset Ӵ UTF-8 ȣAnsiDisplayOffset 1 ʼ AnsiDisplayOffset 0 򷵻 0 + תʾص Ansi Copy(1, AnsiDisplayOffset) Ӵת Unicode ַת UTF-8 ȡ Lengthʵת + + + Text: PWideChar - Ŀַַ + AnsiDisplayOffset: Integer - ʾص Ansi ַΪλƫ + Calculator: TCnWideCharDisplayWideLengthCalculator - Կַʾȼصͬ Delphi IDE ༭вͬ + + ֵInteger - ظÿַתʾص Ansi 1 AnsiDisplayOffset Ӵ UTF-8 +} + +function ConvertUtf16ToAlterDisplayAnsi(WideText: PWideChar; AlterChar: AnsiChar = ' '; + Calculator: TCnWideCharDisplayWideLengthCalculator = nil): AnsiString; +{* ֶַתʾõ AnsiеĿַ Calculator ж滻һ AlterChar + ʱĬжϡڴӢϵַʾȼ㣬ַֽ֧ + + + WideText: PWideChar - תĿַַ + AlterChar: AnsiChar - 滻ַ + Calculator: TCnWideCharDisplayWideLengthCalculator - Կַʾȼصͬ Delphi IDE ༭вͬ + + ֵAnsiString - תַ +} + +function ConvertUtf8ToAlterDisplayAnsi(Utf8Text: PAnsiChar; AlterChar: AnsiChar = ' '; + Calculator: TCnWideCharDisplayWideLengthCalculator = nil): AnsiString; +{* ֶ UTF-8 ַתʾõ AnsiеĿַ Calculator ж滻һ AlterChar + ʱĬжϡڴӢϵַʾȼ㣬ַֽ֧ + + + Utf8Text: PAnsiChar - ת UTF-8 ַַ + AlterChar: AnsiChar - 滻ַ + Calculator: TCnWideCharDisplayWideLengthCalculator - Կַʾȼصͬ Delphi IDE ༭вͬ + + ֵAnsiString - תַ +} + +function CnUtf8ToAnsi(const Text: AnsiString): AnsiString; +{* Ansi ת UTF-8 Ansi ַԽ Unicode 汾 Utf8ToAnsi UnicodeString ⡣ + + + const Text: AnsiString - ת UTF-8 ַ + + ֵAnsiString - תַ +} + +function CnUtf8ToAnsi2(const Text: string): string; +{* Ansi ת UTF-8 stringԽ Unicode 汾 Utf8ToAnsi UnicodeString ⡣ + + + const Text: string - ת UTF-8 ַ + + ֵstring - תַ +} + +function CnAnsiToUtf8(const Text: AnsiString): AnsiString; +{* Ansi ת Ansi ַ UTF-8 ַԽ Unicode 汾 AnsiToUtf8 UnicodeString ⡣ + + + const Text: AnsiString - ת Ansi ַ + + ֵAnsiString - ת UTF-8 ַ +} + +function CnAnsiToUtf82(const Text: string): string; +{* Ansi ת Ansi ַ UTF-8 ַԽ Unicode 汾 AnsiToUtf8 UnicodeString ⡣ + + + const Text: string - ת Ansi ַ + + ֵstring - ת UTF-8 ַ +} + +{$IFDEF COMPILER5} + +function WideCompareText(const S1, S2: WideString): Integer; +{* Delphi 5 ûпַȽϺ˴ʵһ + + + const S1: WideString - ȽϵĿַһ + const S2: WideString - ȽϵĿַ + + ֵInteger - رȽϽ + +} + +{$ENDIF} + +// ============================================================================= +// +// ļ +// +// ============================================================================= + +type + TCnFileEncoding = (cfeUnknown, cfeUtf8, cfeUtf8Bom, cfeUtf16LE, cfeUtf16BE, cfeAnsi); + {* ļ͡ + + cfeUnknown - δ֪ + cfeUtf8 - UTF-8 BOM + cfeUtf8Bom - UTF-8 with BOM + cfeUtf16LE - UTF-16 Little Endian + cfeUtf16BE - UTF-16 Big Endian + cfeAnsi - ϵͳҳ루 Unicode + } + +function CnDetectFileEncoding(const Bytes: TBytes): TCnFileEncoding; +{* ֽļ롣ȼBOM UTF-8 ʽ Ansi + ǰ 4 ֽڵ BOM ǣ BOM ʱ UTF-8 ϷԼ顣 + + + const Bytes: TBytes - ļݵֽ + + ֵTCnFileEncoding - ⵽ı +} + +function CnIsValidUtf8(const Bytes: TBytes): Boolean; +{* ʽжֽǷΪϷ UTF-8 Сÿֽڼ UTF-8 淶 + - ֽڣ0xxxxxxx + - ˫ֽڣ110xxxxx 10xxxxxx + - ֽڣ1110xxxx 10xxxxxx 10xxxxxx + - ֽڣ11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + + + const Bytes: TBytes - ֽ + + ֵBoolean - True ʾϷ UTF-8 +} + +function CnStripBomBytes(const Bytes: TBytes): TBytes; +{* Ƴֽ鿪ͷ BOM ǰ׺UTF-8 BOM #EF#BB#BF / UTF-16 LE BOM #FF#FE / UTF-16 BE BOM #FE#FF + BOM ʱԭʼ鸱 + + + const Bytes: TBytes - ԭʼֽ + + ֵTBytes - ȥ BOM ֽ +} + +// ============================================================================= +// +// TBytes string ת Delphi 汾ȫ UTF-8 ߣ +// +// ============================================================================= + +function CnUtf8BytesToString(const Bytes: TBytes): string; +{* UTF-8 ֽתΪ string֧ Unicode ͷ Unicode + ע Delphi 2007 °汾ת AnsiString ʱַܶ + + + const Bytes: TBytes - UTF-8 ֽ + + ֵstring - תַ +} + +function CnStringToUtf8Bytes(const S: string): TBytes; +{* string תΪ UTF-8 ֽ飬֧ Unicode ͷ Unicode + + + const S: string - תַ + + ֵTBytes - UTF-8 ֽ +} + +implementation + +const + SLineBreak = #13#10; + SLineBreakLF = #10; + + CN_UTF16_4CHAR_PREFIX1_LOW = $D8; + CN_UTF16_4CHAR_PREFIX1_HIGH = $DC; + CN_UTF16_4CHAR_PREFIX2_LOW = $DC; + CN_UTF16_4CHAR_PREFIX2_HIGH = $E0; + + CN_UTF16_4CHAR_HIGH_MASK = $3; + CN_UTF16_4CHAR_SPLIT_MASK = $3FF; + + CN_UTF16_EXT_BASE = $10000; + +resourcestring + SCnErrorInvalidUtf8CharLength = 'More than UTF8-MB4 NOT Support.'; + SCnErrorInvalidModeLength = 'More than UTF32 NOT Support.'; + +{ TCnWideStringList } + +function WideCompareText(const S1, S2: WideString): Integer; +begin +{$IFDEF MSWINDOWS} + Result := CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, PWideChar(S1), + Length(S1), PWideChar(S2), Length(S2)) - 2; +{$ELSE} + Result := WideCompareStr(S1, S2); +{$ENDIF} +end; + +function TCnWideStringList.Add(const S: WideString): Integer; +begin + Result := Count; + Insert(Count, S); +end; + +function TCnWideStringList.AddObject(const S: WideString; + AObject: TObject): Integer; +begin + Result := Add(S); + PutObject(Result, AObject); +end; + +procedure TCnWideStringList.AddStrings(Strings: TCnWideStringList); +var + I: Integer; +begin + for I := 0 to Strings.Count - 1 do + Add(Strings[I]); +end; + +procedure TCnWideStringList.Assign(Source: TPersistent); +begin + if Source is TCnWideStringList then + begin + Clear; + AddStrings(TCnWideStringList(Source)); + FLoadFormat := TCnWideStringList(Source).LoadFormat; + FUseSingleLF := TCnWideStringList(Source).UseSingleLF; + FWriteBOM := TCnWideStringList(Source).WriteBOM; + Exit; + end; + inherited Assign(Source); +end; + +procedure TCnWideStringList.Clear; +var + I: Integer; + P: PCnWideStringItem; +begin + for I := 0 to Count - 1 do + begin + P := PCnWideStringItem(FList[I]); + Dispose(P); + end; + FList.Clear; +end; + +constructor TCnWideStringList.Create; +begin + inherited; + FList := TList.Create; + FLoadFormat := wlfUnicode; + FWriteBOM := True; +end; + +procedure TCnWideStringList.CustomSort(Compare: TCnWideStringListSortCompare); +begin + if Count > 1 then + QuickSort(0, Count - 1, Compare); +end; + +procedure TCnWideStringList.Delete(Index: Integer); +var + P: PCnWideStringItem; +begin + P := PCnWideStringItem(FList[Index]); + FList.Delete(Index); + Dispose(P); +end; + +destructor TCnWideStringList.Destroy; +begin + Clear; + FList.Free; + inherited; +end; + +procedure TCnWideStringList.Exchange(Index1, Index2: Integer); +begin + FList.Exchange(Index1, Index2); +end; + +function TCnWideStringList.Get(Index: Integer): WideString; +begin + Result := PCnWideStringItem(FList[Index])^.FString; +end; + +function TCnWideStringList.GetCount: Integer; +begin + Result := FList.Count; +end; + +function TCnWideStringList.GetName(Index: Integer): WideString; +var + P: Integer; +begin + Result := Get(Index); + P := Pos('=', Result); + if P <> 0 then + SetLength(Result, P - 1) else + SetLength(Result, 0); +end; + +function TCnWideStringList.GetObject(Index: Integer): TObject; +begin + Result := PCnWideStringItem(FList[Index])^.FObject; +end; + +function TCnWideStringList.GetTextStr: WideString; +var + I, L, Size, C: Integer; + P: PwideChar; + S, LB: WideString; +begin + C := GetCount; + Size := 0; + + if FUseSingleLF then + LB := SLineBreakLF + else + LB := SLineBreak; + + for I := 0 to C - 1 do Inc(Size, Length(Get(I)) + Length(LB)); + SetString(Result, nil, Size); + P := Pointer(Result); + for I := 0 to C - 1 do + begin + S := Get(I); + L := Length(S); + if L <> 0 then + begin + System.Move(Pointer(S)^, P^, L * SizeOf(WideChar)); + Inc(P, L); + end; + L := Length(LB); + if L <> 0 then + begin + System.Move(Pointer(LB)^, P^, L * SizeOf(WideChar)); + Inc(P, L); + end; + end; +end; + +function TCnWideStringList.GetValue(const Name: WideString): WideString; +var + I: Integer; +begin + I := IndexOfName(Name); + if I >= 0 then + Result := Copy(Get(I), Length(Name) + 2, MaxInt) else + Result := ''; +end; + +function TCnWideStringList.IndexOf(const S: WideString): Integer; +begin + for Result := 0 to GetCount - 1 do + begin + if WideCompareText(Get(Result), S) = 0 then + Exit; + end; + Result := -1; +end; + +function TCnWideStringList.IndexOfName(const Name: WideString): Integer; +var + P: Integer; + S: string; +begin + for Result := 0 to GetCount - 1 do + begin + S := Get(Result); + P := Pos('=', S); + if (P <> 0) and (WideCompareText(Copy(S, 1, P - 1), Name) = 0) then + Exit; + end; + Result := -1; +end; + +procedure TCnWideStringList.Insert(Index: Integer; const S: WideString); +var + P: PCnWideStringItem; +begin + New(P); + P^.FString := S; + FList.Insert(Index, P); +end; + +procedure TCnWideStringList.LoadFromFile(const FileName: WideString); +var + Stream: TStream; +begin + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + LoadFromStream(Stream); + finally + Stream.Free; + end; +end; + +procedure TCnWideStringList.LoadFromStream(Stream: TStream); +var + Size, Len: Integer; + S: WideString; + HeaderStr, SA: AnsiString; +begin + Size := Stream.Size - Stream.Position; + if Size >= 3 then + begin + SetLength(HeaderStr, 3); + Stream.Read(Pointer(HeaderStr)^, 3); + if HeaderStr = #$EF#$BB#$BF then // UTF-8 BOM + begin + SetLength(SA, Size - 3); + Stream.Read(Pointer(SA)^, Size - 3); +{$IFDEF MSWINDOWS} + Len := MultiByteToWideChar(CP_UTF8, 0, PAnsiChar(SA), -1, nil, 0); + SetLength(S, Len); + MultiByteToWideChar(CP_UTF8, 0, PAnsiChar(SA), -1, PWideChar(S), Len); +{$ELSE} + {$IFDEF FPC} + S := CnUtf8DecodeToWideString(SA); + {$ELSE} + S := UTF8ToWideString(SA); + {$ENDIF} +{$ENDIF} + SetTextStr(S); + + FLoadFormat := wlfUtf8; + Exit; + end; + Stream.Position := Stream.Position - 3; + end; + + if Size >= 2 then + begin + SetLength(HeaderStr, 2); + Stream.Read(Pointer(HeaderStr)^, 2); + if HeaderStr = #$FF#$FE then // UTF-16 BOM + begin + SetLength(S, (Size - 2) div SizeOf(WideChar)); + Stream.Read(Pointer(S)^, (Size - 2) div SizeOf(WideChar) * SizeOf(WideChar)); + SetTextStr(S); + + FLoadFormat := wlfUnicode; + Exit; + end; + Stream.Position := Stream.Position - 2; + end; + + SetString(SA, nil, Size); + Stream.Read(Pointer(SA)^, Size); + SetTextStr({$IFDEF UNICODE}string{$ENDIF}(SA)); + FLoadFormat := wlfAnsi; +end; + +procedure TCnWideStringList.Put(Index: Integer; const S: WideString); +var + P: PCnWideStringItem; +begin + P := PCnWideStringItem(FList[Index]); + P^.FString := S; +end; + +procedure TCnWideStringList.PutObject(Index: Integer; const Value: TObject); +begin + PCnWideStringItem(FList[Index])^.FObject := Value; +end; + +procedure TCnWideStringList.QuickSort(L, R: Integer; + SCompare: TCnWideStringListSortCompare); +var + I, J, P: Integer; +begin + repeat + I := L; + J := R; + P := (L + R) shr 1; + repeat + while SCompare(Self, I, P) < 0 do Inc(I); + while SCompare(Self, J, P) > 0 do Dec(J); + if I <= J then + begin + Exchange(I, J); + if P = I then + P := J + else if P = J then + P := I; + Inc(I); + Dec(J); + end; + until I > J; + if L < J then QuickSort(L, J, SCompare); + L := I; + until I >= R; +end; + +procedure TCnWideStringList.SaveToFile(const FileName: WideString; AFormat: TCnWideListFormat); +var + Stream: TStream; +begin + Stream := TFileStream.Create(FileName, fmCreate); + try + SaveToStream(Stream, AFormat); + finally + Stream.Free; + end; +end; + +procedure TCnWideStringList.SaveToStream(Stream: TStream; AFormat: TCnWideListFormat); +var + S: WideString; + HeaderStr, SA: AnsiString; + Len: Integer; +begin + S := GetTextStr; + if AFormat = wlfAnsi then + begin + SA := AnsiString(S); + Stream.WriteBuffer(Pointer(SA)^, Length(SA) * SizeOf(AnsiChar)); + end + else if AFormat = wlfUtf8 then + begin + if FWriteBOM then + begin + HeaderStr := #$EF#$BB#$BF; + Stream.WriteBuffer(Pointer(HeaderStr)^, Length(HeaderStr) * SizeOf(AnsiChar)); + end; +{$IFDEF MSWINDOWS} + Len := WideCharToMultiByte(CP_UTF8, 0, PWideChar(S), -1, nil, 0, nil, nil); + SetLength(SA, Len); + WideCharToMultiByte(CP_UTF8, 0, PWideChar(S), -1, PAnsiChar(SA), Len, nil, nil); +{$ELSE} + SA := UTF8Encode(S); +{$ENDIF} + Stream.WriteBuffer(Pointer(SA)^, Length(SA) * SizeOf(AnsiChar) - 1); + end + else if AFormat = wlfUnicode then + begin + if FWriteBOM then + begin + HeaderStr := #$FF#$FE; + Stream.WriteBuffer(Pointer(HeaderStr)^, Length(HeaderStr) * SizeOf(AnsiChar)); + end; + Stream.WriteBuffer(Pointer(S)^, Length(S) * SizeOf(WideChar)); + end; +end; + +procedure TCnWideStringList.SetTextStr(const Value: WideString); +var + P, Start: PWideChar; + S: WideString; +begin + Clear; + P := Pointer(Value); + if P <> nil then + begin + while P^ <> #0 do + begin + Start := P; + while not (Ord(P^) in [0, 10, 13]) do Inc(P); + SetString(S, Start, P - Start); + Add(S); + if P^ = #13 then Inc(P); + if P^ = #10 then Inc(P); + end; + end; +end; + +procedure TCnWideStringList.SetValue(const Name, Value: WideString); +var + I: Integer; +begin + I := IndexOfName(Name); + if Value <> '' then + begin + if I < 0 then I := Add(''); + Put(I, Name + '=' + Value); + end + else + begin + if I >= 0 then Delete(I); + end; +end; + +function StringListCompareStrings(List: TCnWideStringList; Index1, Index2: Integer): Integer; +begin + Result := WideCompareText(PCnWideStringItem(List.FList[Index1])^.FString, + PCnWideStringItem(List.FList[Index2])^.FString); +end; + +procedure TCnWideStringList.Sort; +begin + CustomSort(StringListCompareStrings); +end; + +// D5 û UTF-8/Ansi תҵͰ汾ʹҲ֧ UTF8-MB4дƷ +// Ϊ߼SourceChars ˫ֽڿַ +function InternalUnicodeToUtf8(Dest: PAnsiChar; MaxDestBytes: Cardinal; + Source: PWideChar; SourceChars: Cardinal): Cardinal; +var + I, Cnt: Cardinal; + C: Cardinal; +begin + Result := 0; + if Source = nil then + Exit; + + Cnt := 0; + I := 0; + if Dest <> nil then + begin + while (I < SourceChars) and (Cnt < MaxDestBytes) do + begin + if (SourceChars - I >= 2) and (GetByteWidthFromUtf16(@(Source[I])) = 4) then + begin + // ַֽڣҪ + C := GetCodePointFromUtf164Char(PAnsiChar(@(Source[I]))); + Inc(I, 2); // WideChar + end + else + begin + C := Cardinal(Source[I]); + Inc(I); // һ WideChar + end; + + if C <= $7F then + begin + Dest[Cnt] := AnsiChar(C); + Inc(Cnt); + end + else if C > $FFFF then + begin + if Cnt + 4 > MaxDestBytes then + Break; + + Dest[Cnt] := AnsiChar($F0 or (C shr 18)); + Dest[Cnt + 1] := AnsiChar($80 or ((C shr 12) and $3F)); + Dest[Cnt + 2] := AnsiChar($80 or ((C shr 6) and $3F)); + Dest[Cnt + 3] := AnsiChar($80 or (C and $3F)); + Inc(Cnt, 4); + end + else if C > $7FF then + begin + if Cnt + 3 > MaxDestBytes then + Break; + Dest[Cnt] := AnsiChar($E0 or (C shr 12)); + Dest[Cnt + 1] := AnsiChar($80 or ((C shr 6) and $3F)); + Dest[Cnt + 2] := AnsiChar($80 or (C and $3F)); + Inc(Cnt, 3); + end + else // $7F < Source[i] <= $7FF + begin + if Cnt + 2 > MaxDestBytes then + Break; + Dest[Cnt] := AnsiChar($C0 or (C shr 6)); + Dest[Cnt + 1] := AnsiChar($80 or (C and $3F)); + Inc(Cnt, 2); + end; + end; + + if Cnt >= MaxDestBytes then + Cnt := MaxDestBytes - 1; + Dest[Cnt] := #0; + end + else + begin + while I < SourceChars do + begin + if (SourceChars - I >= 2) and (GetByteWidthFromUtf16(@(Source[I])) = 4) then + begin + // ַֽڣҪ + C := GetCodePointFromUtf164Char(PAnsiChar(@(Source[I]))); + Inc(I, 2); // WideChar + end + else + begin + C := Cardinal(Source[I]); + Inc(I); + end; + + if C > $7F then + begin + if C > $7FF then + begin + if C > $FFFF then + Inc(Cnt); + Inc(Cnt); + end; + Inc(Cnt); + end; + Inc(Cnt); + end; + end; + Result := Cnt + 1; +end; + +function InternalUtf8ToUnicode(Dest: PWideChar; MaxDestChars: Cardinal; + Source: PAnsiChar; SourceBytes: Cardinal): Cardinal; +var + K: Integer; + I, Cnt: Cardinal; + C: Byte; + WC: Cardinal; +begin + if Source = nil then + begin + Result := 0; + Exit; + end; + + Result := Cardinal(-1); + Cnt := 0; + I := 0; + if Dest <> nil then + begin + while (I < SourceBytes) and (Cnt < MaxDestChars) do + begin + WC := Cardinal(Source[I]); + Inc(I); + + if (WC and $80) <> 0 then + begin + if I >= SourceBytes then // + Exit; + + if (WC and $F0) = $F0 then // ֽڣδ޶λ 0ٲַƴֵַֽڵ UTF-16 + begin + if SourceBytes - I < 3 then // ֽ˳ + Exit; + + // WC ǵһֽڣȡλδ޶λ 0ֽڸȡλõ + WC := ((WC and $7) shl 18) + ((Cardinal(Source[I]) and $3F) shl 12) + + ((Cardinal(Source[I + 1]) and $3F) shl 6) + (Cardinal(Source[I + 2]) and $3F); + + // UTF-16 ַ Cnt + K := GetUtf16CharFromCodePoint(WC, @(Dest[Cnt])); + if K = 2 then // ַֽȲһ WideCharһ if 󲽽 + Inc(Cnt); + Inc(I, 3); + end + else + begin + WC := WC and $3F; + if (WC and $20) <> 0 then + begin + C := Byte(Source[I]); + Inc(I); + if (C and $C0) <> $80 then // malformed trail byte or out of range char + Exit; + if I >= SourceBytes then // incomplete multibyte char + Exit; + WC := (WC shl 6) or (C and $3F); + end; + C := Byte(Source[I]); + Inc(I); + if (C and $C0) <> $80 then // malformed trail byte + Exit; + + Dest[Cnt] := WideChar((WC shl 6) or (C and $3F)); + end; + end + else + Dest[Cnt] := WideChar(WC); + Inc(Cnt); + end; + if Cnt >= MaxDestChars then Cnt := MaxDestChars - 1; + Dest[Cnt] := #0; + end + else + begin + while (I < SourceBytes) do + begin + C := Byte(Source[I]); + Inc(I); + + if (C and $80) <> 0 then // λΪ 1ٶֽ + begin + if I >= SourceBytes then // incomplete multibyte char + Exit; + + C := C and $3F; // µһֽڵĵλǰλѾ 11 + if (C and $20) <> 0 then // 1110ʾֽ + begin + if (C and $10) <> 0 then // 11110ʾֽ + begin + C := Byte(Source[I]); // ĸеĵڶֽ + Inc(I); + if (C and $C0) <> $80 then // ֽλ 10 + Exit; // malformed trail byte or out of range char + if I >= SourceBytes then + Exit; // incomplete multibyte char + + Inc(Cnt); // ֽڵ UTF8ӦӦ UTF-16 е WideCharһ + end; + + C := Byte(Source[I]); // ĸеĵֽڣеĵڶֽ + Inc(I); + if (C and $C0) <> $80 then // ֽλ 10˳ + Exit; + if I >= SourceBytes then + Exit; // incomplete multibyte char + end; + + C := Byte(Source[I]); // ĸеĵĸֽڣеĵֽڣеĵڶֽ + Inc(I); + if (C and $C0) <> $80 then // ֽλ 10˳ + Exit; // malformed trail byte + end; + + Inc(Cnt); + end; + end; + Result := Cnt + 1; +end; + +// WideString UTF-8 õ AnsiString Ansi תⶪַ +function CnUtf8EncodeWideString(const S: TCnWideString): AnsiString; +var + L: Integer; + Temp: AnsiString; +begin + Result := ''; + if S = '' then + Exit; + SetLength(Temp, Length(S) * 4); // һ˫ַֽ 4 UTF-8 ַ + + L := InternalUnicodeToUtf8(PAnsiChar(Temp), Length(Temp) + 1, PWideChar(S), Length(S)); + if L > 0 then + SetLength(Temp, L - 1) + else + Temp := ''; + Result := Temp; +end; + +// AnsiString UTF-8 õ WideString Ansi תⶪַ +function CnUtf8DecodeToWideString(const S: AnsiString): TCnWideString; +var + L: Integer; +begin + Result := ''; + if S = '' then + Exit; + SetLength(Result, Length(S)); + + L := InternalUtf8ToUnicode(PWideChar(Result), Length(Result) + 1, PAnsiChar(S), Length(S)); + if L > 0 then + SetLength(Result, L - 1) + else + Result := ''; +end; + +function GetUtf16HighByte(Rec: PCn2CharRec): Byte; +begin +{$IFDEF UTF16_BE} + Result := Byte(Rec^.P1); +{$ELSE} + Result := Byte(Rec^.P2); // UTF16-LE ĸߵλû +{$ENDIF} +end; + +function GetUtf16LowByte(Rec: PCn2CharRec): Byte; +begin +{$IFDEF UTF16_BE} + Result := Byte(Rec^.P2); +{$ELSE} + Result := Byte(Rec^.P1); // UTF16-LE ĸߵλû +{$ENDIF} +end; + +procedure SetUtf16HighByte(B: Byte; Rec: PCn2CharRec); +begin +{$IFDEF UTF16_BE} + Rec^.P1 := AnsiChar(B); +{$ELSE} + Rec^.P2 := AnsiChar(B); // UTF16-LE ĸߵλû +{$ENDIF} +end; + +procedure SetUtf16LowByte(B: Byte; Rec: PCn2CharRec); +begin +{$IFDEF UTF16_BE} + Rec^.P2 := AnsiChar(B); +{$ELSE} + Rec^.P1 := AnsiChar(B); // UTF16-LE ĸߵλû +{$ENDIF} +end; + +function GetCharLengthFromUtf8(Utf8Str: PAnsiChar): Integer; +var + L: Integer; +begin + Result := 0; + while Utf8Str^ <> #0 do + begin + L := GetByteWidthFromUtf8(Utf8Str); + Inc(Utf8Str, L); + Inc(Result); + end; +end; + +function GetCharLengthFromUtf16(Utf16Str: PWideChar): Integer; +var + L: Integer; +begin + Result := 0; + while Utf16Str^ <> #0 do + begin + L := GetByteWidthFromUtf16(Utf16Str); + Utf16Str := PWideChar(TCnIntAddress(Utf16Str) + L); + Inc(Result); + end; +end; + +function GetByteWidthFromUtf8(Utf8Str: PAnsiChar): Integer; +var + B: Byte; +begin + B := Byte(Utf8Str^); + if B >= $FC then // 6 11 0Ȳ߻ 1 + Result := 6 + else if B >= $F8 then // 5 11 0 + Result := 5 + else if B >= $F0 then // 4 11 0 + Result := 4 + else if B >= $E0 then // 3 11 0 + Result := 3 + else if B >= $B0 then // 2 11 0 + Result := 2 + else // + Result := 1; +end; + +function GetByteWidthFromUtf16(Utf16Str: PWideChar): Integer; +var + P: PCn2CharRec; + B1, B2: Byte; +begin + Result := 2; + + P := PCn2CharRec(Utf16Str); + B1 := GetUtf16HighByte(P); + + if (B1 >= CN_UTF16_4CHAR_PREFIX1_LOW) and (B1 < CN_UTF16_4CHAR_PREFIX1_HIGH) then + begin + // ַֽƴһ飬ֵ $D800 $DBFF ֮䣬ҲǸ˫ֽڵĸλֽ [$D8, $DC) + Inc(P); + B2 := GetUtf16HighByte(P); + + // ôںַֽӦ $DC00 $DFFF ֮䣬 + if (B2 >= CN_UTF16_4CHAR_PREFIX2_LOW) and (B2 < CN_UTF16_4CHAR_PREFIX2_HIGH) then + Result := 4; + + // ĸֽһֽ Unicode ַǸֵıֵ + end; +end; + +function GetCodePointFromUtf16Char(Utf16Str: PWideChar): TCnCodePoint; +var + R: Word; + C2: PCn2CharRec; +begin + if GetByteWidthFromUtf16(Utf16Str) = 4 then // ַֽ + Result := GetCodePointFromUtf164Char(PAnsiChar(Utf16Str)) + else // ͨ˫ַֽ + begin + C2 := PCn2CharRec(Utf16Str); + R := Byte(C2^.P1) shl 8 + Byte(C2^.P2); // ˫ֵַֽDZֵ + +{$IFDEF UTF16_BE} + Result := TCnCodePoint(R); +{$ELSE} + Result := TCnCodePoint(UInt16ToBigEndian(R)); // UTF16-LE Ҫֵ +{$ENDIF} + end; +end; + +function GetCodePointFromUtf164Char(PtrTo4Char: Pointer): TCnCodePoint; +var + TH, TL: Word; + C2: PCn2CharRec; +begin + C2 := PCn2CharRec(PtrTo4Char); + + // һֽڣȥλ 110110ڶֽţ 2 + 8 = 10 λ + TH := (GetUtf16HighByte(C2) and CN_UTF16_4CHAR_HIGH_MASK) shl 8 + GetUtf16LowByte(C2); + Inc(C2); + + // ֽڣȥλ 110111ĸֽţ 2 + 8 = 10 λ + TL := (GetUtf16HighByte(C2) and CN_UTF16_4CHAR_HIGH_MASK) shl 8 + GetUtf16LowByte(C2); + + // 10 λƴ 10 λ + Result := TH shl 10 + TL + CN_UTF16_EXT_BASE; + // ȥ $10000 ֵǰ 10 λӳ䵽 $D800 $DBFF ֮䣬 10 λӳ䵽 $DC00 $DFFF ֮ +end; + +function GetUtf16CharFromCodePoint(CP: TCnCodePoint; PtrToChars: Pointer): Integer; +var + C2: PCn2CharRec; + L, H: Byte; + LW, HW: Word; +begin + if CP = CN_INVALID_CODEPOINT then + begin + if PtrToChars <> nil then + begin + C2 := PCn2CharRec(PtrToChars); + SetUtf16LowByte(0, C2); + SetUtf16HighByte(0, C2); + end; + Result := 1; + Exit; + end; + + if CP >= CN_UTF16_EXT_BASE then + begin + if PtrToChars <> nil then + begin + CP := CP - CN_UTF16_EXT_BASE; + // 10 λǰֽڣ 10 λźֽ + + LW := CP and CN_UTF16_4CHAR_SPLIT_MASK; // 10 λֽ + HW := (CP shr 10) and CN_UTF16_4CHAR_SPLIT_MASK; // 10 λһֽ + + L := HW and $FF; + H := (HW shr 8) and CN_UTF16_4CHAR_HIGH_MASK; + H := H or CN_UTF16_4CHAR_PREFIX1_LOW; // 1101 1000 + C2 := PCn2CharRec(PtrToChars); + + SetUtf16LowByte(L, C2); + SetUtf16HighByte(H, C2); + + L := LW and $FF; + H := (LW shr 8) and CN_UTF16_4CHAR_HIGH_MASK; + H := H or CN_UTF16_4CHAR_PREFIX1_HIGH; // 1101 1100 + Inc(C2); + + SetUtf16LowByte(L, C2); + SetUtf16HighByte(H, C2); + end; + Result := 2; + end + else + begin + if PtrToChars <> nil then + begin + C2 := PCn2CharRec(PtrToChars); + SetUtf16LowByte(Byte(CP and $00FF), C2); + SetUtf16HighByte(Byte(CP shr 8), C2); + end; + Result := 1; + end; +end; + +// ַ UTF-8 ȣ Utf8Encode ȡ Lengthʵת +function CalcUtf8LengthFromWideString(Text: PWideChar): Integer; +begin + Result := 0; + if Text = nil then + Exit; + + while Text^ <> #0 do + begin + Inc(Result, CalcUtf8LengthFromWideChar(Text^)); + Inc(Text); + end; +end; + +// һ WideChar ת UTF-8 ַ +function CalcUtf8LengthFromWideChar(AChar: WideChar): Integer; +var + V: Cardinal; +begin + V := Ord(AChar); + if V <= $7F then + Result := 1 + else if V <= $7FF then + Result := 2 + else if V <= $FFFF then + Result := 3 + else if V <= $10FFFF then + Result := 4 + else + Result := 0; +end; + +// Unicode ַ 1 WideOffset Ӵ UTF-8 ȣWideOffset 1 ʼ +function CalcUtf8LengthFromWideStringOffset(Text: PWideChar; WideOffset: Integer): Integer; +var + Idx: Integer; +begin + Result := 0; + if (Text <> nil) and (WideOffset > 0) then + begin + Idx := 0; + while (Text^ <> #0) and (Idx < WideOffset) do // Idx 0 ʼWideOffset 1 ʼ < + begin + Inc(Result, CalcUtf8LengthFromWideChar(Text^)); + Inc(Text); + Inc(Idx); + end; + end; +end; + +// Unicode ַת Ansi 1 AnsiOffset Ӵ UTF-8 ȣAnsiOffset 1 ʼ +function CalcUtf8LengthFromWideStringAnsiOffset(Text: PWideChar; AnsiOffset: Integer): Integer; +var + Idx: Integer; +begin + Result := 0; + if (Text <> nil) and (AnsiOffset > 0) then + begin + Idx := 0; + while (Text^ <> #0) and (Idx < AnsiOffset) do // Idx 0 ʼAnsiOffset 1 ʼ < + begin + Inc(Result, CalcUtf8LengthFromWideChar(Text^)); + Inc(Text); + if Ord(Text^) > $FF then // $FF ת Ansi Ȼռֽ + Inc(Idx, 2) + else + Inc(Idx); + end; + end; +end; + +// һ UTF-8 ǰַַ +function CalcUtf8LengthFromUtf8HeadChar(AChar: AnsiChar): Integer; +var + B: Byte; +begin + B := Ord(AChar); + if B and $80 = 0 then // 0xxx xxxx + Result := 1 + else if B and $E0 = $C0 then // 110x xxxx 10xxxxxx + Result := 2 + else if B and $F0 = $E0 then // 1110 xxxx 10xxxxxx 10xxxxxx + Result := 3 + else if B and $F8 = $F0 then // 1111 0xxx 10xxxxxx 10xxxxxx 10xxxxxx + Result := 4 + else + raise ECnWideStringException.Create(SCnErrorInvalidUtf8CharLength); +end; + +// UTF-8 ַת WideSting ָ Wide ӴȶӦ UTF-8 ַȣWideOffset 1 ʼ +// ת WideString Copy(1, WideOffset) ת UTF-8 ȡ Length UTF-8/WideString תԱı +function CalcUtf8StringLengthFromWideOffset(Utf8Text: PAnsiChar; + WideOffset: Integer): Integer; +var + Utf8Len, WideIdx: Integer; +begin + Result := 0; + if (Utf8Text = nil) or (WideOffset <= 0) then + Exit; + + WideIdx := 0; + while (Utf8Text^ <> #0) and (WideIdx < WideOffset) do + begin + Utf8Len := CalcUtf8LengthFromUtf8HeadChar(Utf8Text^); + Inc(Result, Utf8Len); + + case Utf8Len of + 1: + begin + Inc(WideIdx); + Inc(Utf8Text); + end; + 2: + begin + Inc(WideIdx); + Inc(Utf8Text); + if Utf8Text^ = #0 then + Exit; + Inc(Utf8Text); + end; + 3: + begin + Inc(WideIdx); + Inc(Utf8Text); + if Utf8Text^ = #0 then + Exit; + Inc(Utf8Text); + if Utf8Text^ = #0 then + Exit; + Inc(Utf8Text); + end; + 4: // UTF8-MB4 + begin + Inc(WideIdx); + Inc(Utf8Text); + if Utf8Text^ = #0 then + Exit; + Inc(Utf8Text); + if Utf8Text^ = #0 then + Exit; + Inc(Utf8Text); + if Utf8Text^ = #0 then + Exit; + Inc(Utf8Text); + end; + else + Exit; + end; + end; +end; + +// жһ Unicode ַǷռַȣĬϵļªʵ +function WideCharIsWideLength(const AWChar: WideChar): Boolean; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +const + CN_UTF16_ANSI_WIDE_CHAR_SEP = $1100; +var + C: Integer; +begin + C := Ord(AWChar); + Result := C > CN_UTF16_ANSI_WIDE_CHAR_SEP; // Ϊ $1100 Utf16 ַƿȲռֽ +end; + +function CalcAnsiByteLengthFromWideString(Text: PWideChar): Integer; +begin + Result := 0; + if Text = nil then + Exit; + + while Text^ <> #0 do + begin + if Ord(Text^) > $FF then + Inc(Result, SizeOf(WideChar)) + else + Inc(Result, SizeOf(AnsiChar)); + Inc(Text); + end; +end; + +// Unicode ַ Ansi ȣת Ansi Lengthת AnsiԷֹӢƽ̨¶ַ +function CalcAnsiDisplayLengthFromWideString(Text: PWideChar; + Calculator: TCnWideCharDisplayWideLengthCalculator): Integer; +begin + Result := 0; + if Text = nil then + Exit; + + if not Assigned(Calculator) then + Calculator := @WideCharIsWideLength; + + while Text^ <> #0 do + begin + if Calculator(Text^) then + Inc(Result, SizeOf(WideChar)) + else + Inc(Result, SizeOf(AnsiChar)); + Inc(Text); + end; +end; + +function CalcAnsiByteLengthFromWideStringOffset(Text: PWideChar; WideOffset: Integer): Integer; +var + Idx: Integer; +begin + Result := 0; + if (Text = nil) or (WideOffset <= 0) then + Exit; + + Idx := 0; + while (Text^ <> #0) and (Idx < WideOffset) do // Idx 0 ʼWideOffset 1 ʼ < + begin + if Ord(Text^) > $FF then + Inc(Result, SizeOf(WideChar)) + else + Inc(Result, SizeOf(AnsiChar)); + Inc(Text); + Inc(Idx); + end; +end; + +// Unicode ַ 1 WideOffset Ӵ Ansi ȣWideOffset 1 ʼ +function CalcAnsiDisplayLengthFromWideStringOffset(Text: PWideChar; WideOffset: Integer; + Calculator: TCnWideCharDisplayWideLengthCalculator): Integer; +var + Idx: Integer; +begin + Result := 0; + if (Text = nil) or (WideOffset <= 0) then + Exit; + + Idx := 0; + if not Assigned(Calculator) then + Calculator := @WideCharIsWideLength; + + while (Text^ <> #0) and (Idx < WideOffset) do // Idx 0 ʼWideOffset 1 ʼ < + begin + if Calculator(Text^) then + Inc(Result, SizeOf(WideChar)) + else + Inc(Result, SizeOf(AnsiChar)); + Inc(Text); + Inc(Idx); + end; +end; + +function CalcWideStringByteLengthFromAnsiOffset(Text: PWideChar; + AnsiOffset: Integer; AllowExceedEnd: Boolean): Integer; +var + Idx: Integer; +begin + Result := 0; + if (Text <> nil) and (AnsiOffset > 0) then + begin + Idx := 0; + while (Text^ <> #0) and (Idx < AnsiOffset) do + begin + if Ord(Text^) > $FF then + Inc(Idx, SizeOf(WideChar)) + else + Inc(Idx, SizeOf(AnsiChar)); + Inc(Text); + Inc(Result); + end; + + if AllowExceedEnd and (Text^ = #0) and (Idx < AnsiOffset) then + Inc(Result, AnsiOffset - Idx); + end; +end; + +function CalcWideStringDisplayLengthFromAnsiOffset(Text: PWideChar; AnsiOffset: Integer; + AllowExceedEnd: Boolean; Calculator: TCnWideCharDisplayWideLengthCalculator): Integer; +var + Idx: Integer; +begin + Result := 0; + if (Text <> nil) and (AnsiOffset > 0) then + begin + Idx := 0; + if not Assigned(Calculator) then + Calculator := @WideCharIsWideLength; + + while (Text^ <> #0) and (Idx < AnsiOffset) do + begin + if Calculator(Text^) then + Inc(Idx, SizeOf(WideChar)) + else + Inc(Idx, SizeOf(AnsiChar)); + Inc(Text); + Inc(Result); + end; + + if AllowExceedEnd and (Text^ = #0) and (Idx < AnsiOffset) then + Inc(Result, AnsiOffset - Idx); + end; +end; + +// Unicode ַתʾص Ansi 1 AnsiOffset Ӵ UTF-8 ȣAnsiDisplayOffset 1 ʼ +function CalcUtf8LengthFromWideStringAnsiDisplayOffset(Text: PWideChar; + AnsiDisplayOffset: Integer; Calculator: TCnWideCharDisplayWideLengthCalculator): Integer; +var + Idx: Integer; +begin + Result := 0; + if (Text <> nil) and (AnsiDisplayOffset > 0) then + begin + Idx := 0; + if not Assigned(Calculator) then + Calculator := @WideCharIsWideLength; + + while (Text^ <> #0) and (Idx < AnsiDisplayOffset) do // Idx 0 ʼAnsiDisplayOffset 1 ʼ < + begin + Inc(Result, CalcUtf8LengthFromWideChar(Text^)); + Inc(Text); + if Calculator(Text^) then + Inc(Idx, SizeOf(WideChar)) + else + Inc(Idx, SizeOf(AnsiChar)); + end; + end; +end; + +// ֶַת AnsiеĿַ滻 AlterCharڴӢϵַȼ +function ConvertUtf16ToAlterDisplayAnsi(WideText: PWideChar; AlterChar: AnsiChar; + Calculator: TCnWideCharDisplayWideLengthCalculator): AnsiString; +var + Len: Integer; +begin + if WideText = nil then + begin + Result := ''; + Exit; + end; + +{$IFDEF UNICODE} + Len := StrLen(WideText); +{$ELSE} + Len := Length(WideString(WideText)); +{$ENDIF} + + if Len = 0 then + begin + Result := ''; + Exit; + end; + + SetLength(Result, Len * SizeOf(WideChar)); + + if not Assigned(Calculator) then + Calculator := @WideCharIsWideLength; + + Len := 0; + while WideText^ <> #0 do + begin + if Calculator(WideText^) then + begin + Inc(Len); + Result[Len] := AlterChar; + Inc(Len); + Result[Len] := AlterChar; + end + else + begin + Inc(Len); + if Ord(WideText^) <= $FF then // Absolutely 'Single' Char + Result[Len] := AnsiChar(WideText^) + else // Extended 'Single' Char, Replace + Result[Len] := AlterChar; + end; + Inc(WideText); + end; + SetLength(Result, Len); +end; + +// ֶ UTF-8 ַת AnsiеĿַ滻 AlterCharڴӢϵַȼ +function ConvertUtf8ToAlterDisplayAnsi(Utf8Text: PAnsiChar; AlterChar: AnsiChar; + Calculator: TCnWideCharDisplayWideLengthCalculator): AnsiString; +var + I, J, Len, ByteCount: Integer; + C: AnsiChar; + W: Word; + B, B1, B2: Byte; +begin + Result := ''; + if Utf8Text = nil then + Exit; + + Len := StrLen(Utf8Text); + if Len = 0 then + Exit; + + SetLength(Result, Len); // ԭijϳ + I := 0; + J := 1; + + if not Assigned(Calculator) then + Calculator := @WideCharIsWideLength; + + while I < Len do + begin + C := Utf8Text[I]; + B := Ord(C); + W := 0; + + // B ֵóַռλ + if B and $80 = 0 then // 0xxx xxxx + ByteCount := 1 + else if B and $E0 = $C0 then // 110x xxxx 10xxxxxx + ByteCount := 2 + else if B and $F0 = $E0 then // 1110 xxxx 10xxxxxx 10xxxxxx + ByteCount := 3 + else if B and $F8 = $F0 then // 1111 0xxx 10xxxxxx 10xxxxxx 10xxxxxx + ByteCount := 4 + else + raise ECnWideStringException.Create(SCnErrorInvalidModeLength); + + // ټӦĿַֽ + case ByteCount of + 1: + begin + W := B and $7F; + end; + 2: + begin + B1 := Ord(Utf8Text[I + 1]); + W := ((B and $1F) shl 6) or (B1 and $3F); + end; + 3: + begin + B1 := Ord(Utf8Text[I + 1]); + B2 := Ord(Utf8Text[I + 2]); + W := ((B and $0F) shl 12) or ((B1 and $3F) shl 6) or (B2 and $3F); + end; + end; + + if ByteCount = 4 then + begin + // ֽ UTF8תΪ WideCharҲĸַ + // TODO: ʾδأܿƧַ + Result[J] := AlterChar; + Inc(J); + Result[J] := AlterChar; + Inc(J); + Result[J] := AlterChar; + Inc(J); + Result[J] := AlterChar; + Inc(J); + end + else if Calculator(WideChar(W)) then // 3 ֽ UTF8жʵʿ + begin + Result[J] := AlterChar; + Inc(J); + Result[J] := AlterChar; + Inc(J); + end + else + begin + if W <= 255 then + Result[J] := AnsiChar(W) + else + Result[J] := AlterChar; + Inc(J); + end; + + Inc(I, ByteCount); + end; + + SetLength(Result, J - 1); // Inc J ׼һַģû˾ͼһ +end; + +function CnUtf8ToAnsi(const Text: AnsiString): AnsiString; +begin +{$IFDEF FPC} + {$IFDEF LAZARUS} + Result := ConvertEncoding(Text, EncodingUTF8, EncodingAnsi); + {$ELSE} + Result := Utf8ToAnsi(Text); + {$ENDIF} +{$ELSE} +{$IFDEF UNICODE} + Result := AnsiString(UTF8ToUnicodeString(PAnsiChar(Text))); +{$ELSE} + {$IFDEF COMPILER6_UP} + Result := Utf8ToAnsi(Text); + {$ELSE} + Result := AnsiString(CnUtf8DecodeToWideString(Text)); + {$ENDIF} +{$ENDIF} +{$ENDIF} +end; + +function CnUtf8ToAnsi2(const Text: string): string; +begin +{$IFDEF FPC} + {$IFDEF LAZARUS} + Result := ConvertEncoding(Text, EncodingUTF8, EncodingAnsi); + {$ELSE} + Result := Utf8ToAnsi(Text); + {$ENDIF} +{$ELSE} +{$IFDEF UNICODE} + Result := UTF8ToUnicodeString(PAnsiChar(AnsiString(Text))); +{$ELSE} + {$IFDEF COMPILER6_UP} + Result := Utf8ToAnsi(Text); + {$ELSE} + Result := AnsiString(CnUtf8DecodeToWideString(Text)); + {$ENDIF} +{$ENDIF} +{$ENDIF} +end; + +function CnAnsiToUtf8(const Text: AnsiString): AnsiString; +begin +{$IFDEF FPC} + {$IFDEF LAZARUS} + Result := ConvertEncoding(Text, EncodingAnsi, EncodingUTF8); + {$ELSE} + Result := AnsiToUtf8(Text); + {$ENDIF} +{$ELSE} +{$IFDEF UNICODE} + Result := AnsiString(Utf8Encode(Text)); // ֵɸΪ UTF8String ͣ˴תЧ +{$ELSE} + {$IFDEF COMPILER6_UP} + Result := AnsiToUtf8(Text); + {$ELSE} + Result := CnUtf8EncodeWideString(WideString(Text)); + {$ENDIF} +{$ENDIF} +{$ENDIF} +end; + +function CnAnsiToUtf82(const Text: string): string; +begin +{$IFDEF FPC} + {$IFDEF LAZARUS} + Result := ConvertEncoding(Text, EncodingAnsi, EncodingUTF8); + {$ELSE} + Result := AnsiToUtf8(Text); + {$ENDIF} +{$ELSE} +{$IFDEF UNICODE} + Result := string(Utf8Encode(Text)); +{$ELSE} + {$IFDEF COMPILER6_UP} + Result := AnsiToUtf8(Text); + {$ELSE} + Result := CnUtf8EncodeWideString(WideString(Text)); + {$ENDIF} +{$ENDIF} +{$ENDIF} +end; + +// ===================== TCnFileEncoding ʵ ============================== + +function CnDetectFileEncoding(const Bytes: TBytes): TCnFileEncoding; +begin + Result := cfeUnknown; + if Length(Bytes) = 0 then Exit; + + // BOM + if Length(Bytes) >= 3 then + begin + if (Bytes[0] = $EF) and (Bytes[1] = $BB) and (Bytes[2] = $BF) then + begin + Result := cfeUtf8Bom; + Exit; + end; + end; + + if Length(Bytes) >= 2 then + begin + if (Bytes[0] = $FF) and (Bytes[1] = $FE) then + begin + Result := cfeUtf16LE; + Exit; + end; + if (Bytes[0] = $FE) and (Bytes[1] = $FF) then + begin + Result := cfeUtf16BE; + Exit; + end; + end; + + // BOMʽ UTF-8 + if CnIsValidUtf8(Bytes) then + Result := cfeUtf8 + else + Result := cfeAnsi; +end; + +function CnIsValidUtf8(const Bytes: TBytes): Boolean; +var + I, Len, Remain: Integer; + B: Byte; +begin + Result := True; + Len := Length(Bytes); + I := 0; + while I < Len do + begin + B := Bytes[I]; + if B and $80 = 0 then + // ֽ: 0xxxxxxx + Inc(I) + else if B and $E0 = $C0 then + begin + // ˫ֽ: 110xxxxx 10xxxxxx + Inc(I); + Remain := 1; + end + else if B and $F0 = $E0 then + begin + // ֽ: 1110xxxx 10xxxxxx 10xxxxxx + Inc(I); + Remain := 2; + end + else if B and $F8 = $F0 then + begin + // ֽ: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + Inc(I); + Remain := 3; + end + else + begin + // Чǰ׺ + Result := False; + Exit; + end; + + // ֽǷ 10xxxxxx + while (Remain > 0) and (I < Len) do + begin + if Bytes[I] and $C0 <> $80 then + begin + Result := False; + Exit; + end; + Inc(I); + Dec(Remain); + end; + + // ֽڲ + if Remain > 0 then + begin + Result := False; + Exit; + end; + end; +end; + +function CnStripBomBytes(const Bytes: TBytes): TBytes; +var + Offset: Integer; +begin + Offset := 0; + if Length(Bytes) >= 3 then + begin + if (Bytes[0] = $EF) and (Bytes[1] = $BB) and (Bytes[2] = $BF) then + Offset := 3; + end; + if (Offset = 0) and (Length(Bytes) >= 2) then + begin + if ((Bytes[0] = $FF) and (Bytes[1] = $FE)) + or ((Bytes[0] = $FE) and (Bytes[1] = $FF)) then + Offset := 2; + end; + + if Offset > 0 then + begin + SetLength(Result, Length(Bytes) - Offset); + if Length(Result) > 0 then + Move(Bytes[Offset], Result[0], Length(Result)); + end + else + Result := Copy(Bytes); +end; + +// ================= TBytes string ֮תʵ =========================== + +function CnUtf8BytesToString(const Bytes: TBytes): string; +var + Utf8Str: AnsiString; +begin + SetLength(Utf8Str, Length(Bytes)); + if Length(Bytes) > 0 then + Move(Bytes[0], Utf8Str[1], Length(Bytes)); + Result := string(CnUtf8DecodeToWideString(Utf8Str)); +end; + +function CnStringToUtf8Bytes(const S: string): TBytes; +var + Utf8Str: AnsiString; +begin + Utf8Str := CnUtf8EncodeWideString(TCnWideString(S)); + SetLength(Result, Length(Utf8Str)); + if Length(Utf8Str) > 0 then + Move(Utf8Str[1], Result[0], Length(Utf8Str)); +end; + +end. diff --git a/CnPack/Crypto/CnAES.pas b/CnPack/Crypto/CnAES.pas index 8f0a8da..098c34e 100644 --- a/CnPack/Crypto/CnAES.pas +++ b/CnPack/Crypto/CnAES.pas @@ -1,7569 +1,7763 @@ -{******************************************************************************} -{ CnPack For Delphi/C++Builder } -{ йԼĿԴ } -{ (C)Copyright 2001-2025 CnPack } -{ ------------------------------------ } -{ } -{ ǿԴ CnPack ķЭ } -{ ĺ·һ } -{ } -{ һĿϣãûκεû } -{ ʺضĿĶĵϸ CnPack Э顣 } -{ } -{ ӦѾͿһյһ CnPack Эĸ } -{ ûУɷǵվ } -{ } -{ վַhttps://www.cnpack.org } -{ ʼmaster@cnpack.org } -{ } -{******************************************************************************} -(******************************************************************************) -(* *) -(* Advanced Encryption Standard (AES) *) -(* *) -(* Copyright (c) 1998-2001 *) -(* EldoS, Alexander Ionov *) -(* *) -(******************************************************************************) - -unit CnAES; -{* |
-================================================================================
-* ƣ
-* ԪƣAES ԳƼӽ㷨ʵֵԪ
-* ԪߣCnPack  (master@cnpack.org)
-*            EldoS, Alexander Ionov ĵԪֲ书ܣԭаȨϢ
-*     עԪʵ AES 128/192/256 ԳƼӽ㷨ֿС̶ 16 ֽڣģʽ
-*           Ķ뷽ʽĩβ 0Ԫڲ֧ PKCS ȿ뷽ʽҪⲿ
-*           CnPemUtils.pas Ԫе PKCS ϵкԼӽݽж⴦
-*
-*           ߰汾 Delphi 뾡ʹ AnsiString 汾ĺʮƳ⣩
-*           ⲻַӰӽܽ
-*
-*           䣺============= Java Ĭϵ AES Ӧ˴ AES256 ============
-*           ⣬C++Builder 5/6 ¶ overload ĺʴжϴӶ
-*           ҵΣʱԪ˴ overload  Delphi ´ڣ
-*           ٷװ˲ֲͬĺ֧ C++Builder 5/6 ±С
-*
-*           ECB/CBC ǿģʽҪ롣CFB/OFB/CTR ĵģʽ뵽顣
-*
-*           ⣬CTR ģʽ RFC 3686 淶紫ݵ 4 ֽ Nonce8 ֽ
-*           ʼ4 ֽֽļƴ 16 ֽڵijʼ
-*            AES 㣬ӽܾΪĶ
-*
-* ƽ̨Delphi5 + Win 7
-* ޸ļ¼2024.07.25 V1.3
-*                CTR ģʽ֧֣ѭ RFC 3686 淶
-*           2024.05.26 V1.2
-*               䲿֧ C++Builder ĺ
-*           2022.06.21 V1.1
-*               뼸ֽ鵽ʮַ֮ļӽܺ
-*           2021.12.11 V1.2
-*                CFB/OFB ģʽ֧
-*           2019.04.15 V1.1
-*               ֧ Win32/Win64/MacOS
-*           2015.01.21 V1.0
-*               Ԫ
-================================================================================
-|
} - -interface - -{$I CnPack.inc} - -uses - Classes, SysUtils, CnNative; - -const - CN_AES_BLOCKSIZE = 16; - {* AES ķܿСλ٣Ϊ 16 ֽ} - -type - TCnKeyBitType = (kbt128, kbt192, kbt256); - {* AES λ16 ֽڡ24 ֽں 32 ֽ} - - ECnAESException = class(Exception); - {* AES 쳣} - - TCnAESBuffer = array [0..15] of Byte; - {* AES ӽܿ 16 ֽ} - - TCnAESKey128 = array [0..15] of Byte; - {* AES128 Կṹ16 ֽ} - - TCnAESKey192 = array [0..23] of Byte; - {* AES192 Կṹ24 ֽ} - - TCnAESKey256 = array [0..31] of Byte; - {* AES256 Կṹ32 ֽ} - - TCnAESExpandedKey128 = array [0..43] of Cardinal; - {* AES128 չԿṹ} - - TCnAESExpandedKey192 = array [0..53] of Cardinal; - {* AES192 չԿṹ} - - TCnAESExpandedKey256 = array [0..63] of Cardinal; - {* AES256 չԿṹ} - - PCnAESBuffer = ^TCnAESBuffer; - PCnAESKey128 = ^TCnAESKey128; - PCnAESKey192 = ^TCnAESKey192; - PCnAESKey256 = ^TCnAESKey256; - PCnAESExpandedKey128 = ^TCnAESExpandedKey128; - PCnAESExpandedKey192 = ^TCnAESExpandedKey192; - PCnAESExpandedKey256 = ^TCnAESExpandedKey256; - - TCnAESCTRNonce = array[0..3] of Byte; - {* CTR ģʽµ Nonce ṹ4 ֽ} - TCnAESCTRIv = array[0..7] of Byte; - {* CTR ģʽµijʼṹ8 ֽ} - -// Key Expansion Routines for Encryption - -procedure ExpandAESKeyForEncryption128(const Key: TCnAESKey128; - var ExpandedKey: TCnAESExpandedKey128); -{* ڼܳչ AES128 Կ - - - const Key: TCnAESKey128 - չ AES128 Կ - var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ - - ֵޣ -} - -procedure ExpandAESKeyForEncryption192(const Key: TCnAESKey192; - var ExpandedKey: TCnAESExpandedKey192); -{* ڼܳչ AES192 Կ - - - const Key: TCnAESKey192 - չ AES192 Կ - var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ - - ֵޣ -} - -procedure ExpandAESKeyForEncryption256(const Key: TCnAESKey256; - var ExpandedKey: TCnAESExpandedKey256); -{* ڼܳչ AES256 Կ - - - const Key: TCnAESKey256 - չ AES256 Կ - var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ - - ֵޣ -} - -// Block Encryption Routines ܣInBuf OutBuf ͬһ - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; - var OutBuf: TCnAESBuffer); overload; -{* AES128 ܿ飬 Delphi ¿á - - - const InBuf: TCnAESBuffer - ܵݿ - const Key: TCnAESExpandedKey128 - չ AES128 Կ - var OutBuf: TCnAESBuffer - ĵݿ - - ֵޣ -} -procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; - var OutBuf: TCnAESBuffer); overload; -{* AES192 ܿ飬 Delphi ¿á - - - const InBuf: TCnAESBuffer - ܵݿ - const Key: TCnAESExpandedKey192 - չ AES192 Կ - var OutBuf: TCnAESBuffer - ĵݿ - - ֵޣ -} -procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; - var OutBuf: TCnAESBuffer); overload; -{* AES256 ܿ飬 Delphi ¿á - - - const InBuf: TCnAESBuffer - ܵݿ - const Key: TCnAESExpandedKey256 - չ AES256 Կ - var OutBuf: TCnAESBuffer - ĵݿ - - ֵޣ -} - -{$ENDIF} - -// Delphi C++Builder ¾ -procedure EncryptAES128(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; - var OutBuf: TCnAESBuffer); -{* AES128 ܿ飬InBuf OutBuf ͬһ - - - const InBuf: TCnAESBuffer - ܵݿ - const Key: TCnAESExpandedKey128 - չ AES128 Կ - var OutBuf: TCnAESBuffer - ĵݿ - - ֵޣ -} -procedure EncryptAES192(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; - var OutBuf: TCnAESBuffer); -{* AES192 ܿ飬InBuf OutBuf ͬһ - - - const InBuf: TCnAESBuffer - ܵݿ - const Key: TCnAESExpandedKey192 - չ AES192 Կ - var OutBuf: TCnAESBuffer - ĵݿ - - ֵޣ -} -procedure EncryptAES256(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; - var OutBuf: TCnAESBuffer); -{* AES256 ܿ飬InBuf OutBuf ͬһ - - - const InBuf: TCnAESBuffer - ܵݿ - const Key: TCnAESExpandedKey256 - չ AES256 Կ - var OutBuf: TCnAESBuffer - ĵݿ - - ֵޣ -} - -// Stream Encryption Routines (ECB mode) ECB - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; Dest: TStream); overload; -{* AES128 ECB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); overload; -{* AES128 ECB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; Dest: TStream); overload; -{* AES256 ECB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); overload; -{* AES192 ECB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; Dest: TStream); overload; -{* AES256 ECB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); overload; -{* AES256 ECB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - Dest: TStream - - - ֵޣ -} - -{$ENDIF} - -// Delphi C++Builder ¾ -procedure EncryptAES128StreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; Dest: TStream); -{* AES128 ECB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES128StreamECBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); -{* AES128 ECB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAES192StreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; Dest: TStream); -{* AES192 ECB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES192StreamECBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); -{* AES192 ECB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAES256StreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; Dest: TStream); -{* AES256 ECB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES256StreamECBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); -{* AES256 ECB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - Dest: TStream - - - ֵޣ -} - -// Stream Encryption Routines (CBC mode) CBC - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES128 CBC ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES128 CBC ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES192 CBC ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES192 CBC ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES256 CBC ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES256 CBC ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -{$ENDIF} - -// Delphi C++Builder ¾ -procedure EncryptAES128StreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES128 CBC ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES128StreamCBCExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES128 CBC ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAES192StreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES192 CBC ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES192StreamCBCExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES192 CBC ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAES256StreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES256 CBC ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES256StreamCBCExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES256 CBC ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -// Stream Encryption Routines (CFB mode) CFB - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES128 CFB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES128 CFB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES192 CFB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES192 CFB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES256 CFB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES256 CFB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -{$ENDIF} - -// Delphi C++Builder ¾ -procedure EncryptAES128StreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES128 CFB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES128StreamCFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES128 CFB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES192StreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES192 CFB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES192StreamCFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES192 CFB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES256StreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES256 CFB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES256StreamCFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES256 CFB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -// Stream Encryption Routines (OFB mode) OFB - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES128 OFB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES128 OFB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES192 OFB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES192 OFB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES256 OFB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES256 OFB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -{$ENDIF} - -// Delphi C++Builder ¾ -procedure EncryptAES128StreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES128 OFB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES128StreamOFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES128 OFB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAES192StreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES192 OFB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - ?? - - ֵޣ -} -procedure EncryptAES192StreamOFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES192 OFB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure EncryptAES256StreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES256 OFB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES256StreamOFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES256 OFB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -// Stream Encryption Routines (CTR mode) CTR - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); overload; -{* AES128 CTR ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); overload; -{* AES128 CTR ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); overload; -{* AES192 CTR ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); overload; -{* AES192 CTR ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); overload; -{* AES256 CTR ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); overload; -{* AES256 CTR ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -{$ENDIF} - -// Delphi C++Builder ¾ -procedure EncryptAES128StreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -{* AES128 CTR ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES128StreamCTRExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -{* AES128 CTR ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES192StreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -{* AES192 CTR ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES192StreamCTRExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -{* AES192 CTR ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES256StreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -{* AES256 CTR ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure EncryptAES256StreamCTRExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -{* AES256 CTR ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -// Key Transformation Routines for Decryption - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey128); overload; -{* ڽܳչ AES128 Կ - - - var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ - - ֵޣ -} - -procedure ExpandAESKeyForDecryption(const Key: TCnAESKey128; - var ExpandedKey: TCnAESExpandedKey128); overload; -{* ڽܳչ AES128 Կ - - - const Key: TCnAESKey128 - չ AES128 Կ - var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ - - ֵޣ -} - -procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey192); overload; -{* ڽܳչ AES192 Կ - - - var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ - - ֵޣ -} -procedure ExpandAESKeyForDecryption(const Key: TCnAESKey192; - var ExpandedKey: TCnAESExpandedKey192); overload; -{* ڽܳչ AES192 Կ - - - const Key: TCnAESKey192 - չ AES192 Կ - var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ - - ֵޣ -} - -procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey256); overload; -{* ڽܳչ AES256 Կ - - - var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ - - ֵޣ -} -procedure ExpandAESKeyForDecryption(const Key: TCnAESKey256; - var ExpandedKey: TCnAESExpandedKey256); overload; -{* ڽܳչ AES256 Կ - - - const Key: TCnAESKey256 - չ AES256 Կ - var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ - - ֵޣ -} - -{$ENDIF} - -// Delphi C++Builder ¾ -procedure ExpandAESKeyForDecryption128(var ExpandedKey: TCnAESExpandedKey128); -{* ڽܳչ AES128 Կ - - - var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ - - ֵޣ -} -procedure ExpandAESKeyForDecryption128Expanded(const Key: TCnAESKey128; - var ExpandedKey: TCnAESExpandedKey128); -{* ڽܳչ AES128 Կ - - - const Key: TCnAESKey128 - չ AES128 Կ - var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ - - ֵޣ -} - -procedure ExpandAESKeyForDecryption192(var ExpandedKey: TCnAESExpandedKey192); -{* ڽܳչ AES192 Կ - - - var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ - - ֵޣ -} -procedure ExpandAESKeyForDecryption192Expanded(const Key: TCnAESKey192; - var ExpandedKey: TCnAESExpandedKey192); -{* ڽܳչ AES192 Կ - - - const Key: TCnAESKey192 - չ AES192 Կ - var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ - - ֵޣ -} - -procedure ExpandAESKeyForDecryption256(var ExpandedKey: TCnAESExpandedKey256); -{* ڽܳչ AES256 Կ - - - var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ - - ֵޣ -} -procedure ExpandAESKeyForDecryption256Expanded(const Key: TCnAESKey256; - var ExpandedKey: TCnAESExpandedKey256); -{* ڽܳչ AES256 Կ - - - const Key: TCnAESKey256 - չ AES256 Կ - var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ - - ֵޣ -} - -// Block Decryption Routines - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; - var OutBuf: TCnAESBuffer); overload; -{* AES128 ܿ飬 Delphi ¿á - - - const InBuf: TCnAESBuffer - ܵݿ - const Key: TCnAESExpandedKey128 - չ AES128 Կ - var OutBuf: TCnAESBuffer - ĵݿ - - ֵޣ -} - -procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; - var OutBuf: TCnAESBuffer); overload; -{* AES192 ܿ飬 Delphi ¿á - - - const InBuf: TCnAESBuffer - ܵݿ - const Key: TCnAESExpandedKey192 - չ AES192 Կ - var OutBuf: TCnAESBuffer - ĵݿ - - ֵޣ -} - -procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; - var OutBuf: TCnAESBuffer); overload; -{* AES256 ܿ飬 Delphi ¿á - - - const InBuf: TCnAESBuffer - ܵݿ - const Key: TCnAESExpandedKey256 - չ AES256 Կ - var OutBuf: TCnAESBuffer - ĵݿ - - ֵޣ -} - -{$ENDIF} - -// Delphi C++Builder ¾ -procedure DecryptAES128(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; - var OutBuf: TCnAESBuffer); -{* AES128 ܿ飬InBuf OutBuf ͬһ - - - const InBuf: TCnAESBuffer - ܵݿ - const Key: TCnAESExpandedKey128 - չ AES128 Կ - var OutBuf: TCnAESBuffer - ĵݿ - - ֵޣ -} -procedure DecryptAES192(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; - var OutBuf: TCnAESBuffer); -{* AES192 ܿ飬InBuf OutBuf ͬһ - - - const InBuf: TCnAESBuffer - ܵݿ - const Key: TCnAESExpandedKey192 - չ AES192 Կ - var OutBuf: TCnAESBuffer - ĵݿ - - ֵޣ -} -procedure DecryptAES256(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; - var OutBuf: TCnAESBuffer); -{* AES256 ܿ飬InBuf OutBuf ͬһ - - - const InBuf: TCnAESBuffer - ܵݿ - const Key: TCnAESExpandedKey256 - չ AES256 Կ - var OutBuf: TCnAESBuffer - ĵݿ - - ֵޣ -} - -// Stream Decryption Routines (ECB mode) ECB - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; Dest: TStream); overload; -{* AES128 ECB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); overload; -{* AES128 ECB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - Dest: TStream - - - ֵޣ -} - -procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; Dest: TStream); overload; -{* AES192 ECB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); overload; -{* AES192 ECB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - Dest: TStream - - - ֵޣ -} - -procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; Dest: TStream); overload; -{* AES256 ECB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); overload; -{* AES256 ECB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - Dest: TStream - - - ֵޣ -} - -{$ENDIF} - -// Delphi C++Builder ¾ -procedure DecryptAES128StreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; Dest: TStream); -{* AES128 ECB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES128StreamECBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); -{* AES128 ECB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - Dest: TStream - - - ֵޣ -} - -procedure DecryptAES192StreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; Dest: TStream); -{* AES192 ECB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES192StreamECBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); -{* AES192 ECB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - Dest: TStream - - - ֵޣ -} - -procedure DecryptAES256StreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; Dest: TStream); -{* AES256 ECB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES256StreamECBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); -{* AES156 ECB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - Dest: TStream - - - ֵޣ -} - -// Stream Decryption Routines (CBC mode) CBC - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES128 CBC ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES128 CBC ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES192 CBC ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES192 CBC ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES256 CBC ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES256 CBC ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -{$ENDIF} - -// Delphi C++Builder ¾ -procedure DecryptAES128StreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES128 CBC ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES128StreamCBCExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES128 CBC ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES192StreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES192 CBC ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES192StreamCBCExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES192 CBC ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES256StreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES256 CBC ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES256StreamCBCExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES256 CBC ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -// Stream Decryption Routines (CFB mode) CFB - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES128 CFB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES128 CFB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES192 CFB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES192 CFB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES256 CFB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES256 CFB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -{$ENDIF} - -// Delphi C++Builder ¾ -procedure DecryptAES128StreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES128 CFB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES128StreamCFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES128 CFB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES192StreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES192 CFB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES192StreamCFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES192 CFB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES256StreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES256 CFB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES256StreamCFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES256 CFB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -// Stream Decryption Routines (OFB mode) OFB - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES128 OFB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES128 OFB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES192 OFB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES192 OFB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; -{* AES256 OFB ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); overload; -{* AES256 OFB ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -{$ENDIF} - -// Delphi C++Builder ¾ -procedure DecryptAES128StreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES128 OFB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES128StreamOFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES128 OFB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES192StreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES192 OFB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES192StreamOFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES192 OFB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES256StreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -{* AES256 OFB ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES256StreamOFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -{* AES256 OFB ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - const InitVector: TCnAESBuffer - 16 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -// Stream Decryption Routines (CTR mode) CTR - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); overload; -{* AES128 CTR ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); overload; -{* AES128 CTR ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); overload; -{* AES192 CTR ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); overload; -{* AES192 CTR ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); overload; -{* AES256 CTR ģʽ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); overload; -{* AES256 CTR ģʽʹչԿ Delphi ¿á - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -{$ENDIF} - -// Delphi C++Builder ¾ -procedure DecryptAES128StreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -{* AES128 CTR ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey128 - 16 ֽ AES128 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES128StreamCTRExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -{* AES128 CTR ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES192StreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -{* AES192 CTR ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey192 - 24 ֽ AES192 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES192StreamCTRExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -{* AES192 CTR ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES256StreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -{* AES256 CTR ģʽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnAESKey256 - 32 ֽ AES256 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} -procedure DecryptAES256StreamCTRExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -{* AES256 CTR ģʽʹչԿ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const InitVector: TCnAESCTRIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -// ============== ַʮַ֮ļӽ =================== - -function AESEncryptEcbStrToHex(Value: AnsiString; Key: AnsiString; - KeyBit: TCnKeyBitType = kbt128): AnsiString; -{* AES ECB ģʽַתʮơ - - - Value: AnsiString - ַܵ - Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 - KeyBit: TCnKeyBitType - AES - - ֵAnsiString - ʮַ -} - -function AESDecryptEcbStrFromHex(const HexStr: AnsiString; Key: AnsiString; - KeyBit: TCnKeyBitType = kbt128): AnsiString; -{* AES ECB ʮַ - - - const HexStr: AnsiString - ܵʮַ - Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 - KeyBit: TCnKeyBitType - AES - - ֵAnsiString - ַ -} - -function AESEncryptCbcStrToHex(Value: AnsiString; Key: AnsiString; - const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; -{* AES CBC ģʽַתʮơ - - - Value: AnsiString - ַܵ - Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 - const Iv: TCnAESBuffer - 16 ֽڳʼ - KeyBit: TCnKeyBitType - AES - - ֵAnsiString - ʮַ -} - -function AESDecryptCbcStrFromHex(const HexStr: AnsiString; Key: AnsiString; - const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; -{* AES CBC ʮַ - - - const HexStr: AnsiString - ܵʮַ - Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 - const Iv: TCnAESBuffer - 16 ֽڳʼ - KeyBit: TCnKeyBitType - AES - - ֵAnsiString - ַ -} - -function AESEncryptCfbStrToHex(Value: AnsiString; Key: AnsiString; - const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; -{* AES CFB ģʽַתʮơ - - - Value: AnsiString - ַܵ - Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 - const Iv: TCnAESBuffer - 16 ֽڳʼ - KeyBit: TCnKeyBitType - AES - - ֵAnsiString - ʮַ -} - -function AESDecryptCfbStrFromHex(const HexStr: AnsiString; Key: AnsiString; - const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; -{* AES CFB ʮַ - - - const HexStr: AnsiString - ܵʮַ - Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 - const Iv: TCnAESBuffer - 16 ֽڳʼ - KeyBit: TCnKeyBitType - AES - - ֵAnsiString - ַ -} - -function AESEncryptOfbStrToHex(Value: AnsiString; Key: AnsiString; - const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; -{* AES OFB ģʽַתʮơ - - - Value: AnsiString - ַܵ - Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 - const Iv: TCnAESBuffer - 16 ֽڳʼ - KeyBit: TCnKeyBitType - AES - - ֵAnsiString - ʮַ -} - -function AESDecryptOfbStrFromHex(const HexStr: AnsiString; Key: AnsiString; - const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; -{* AES OFB ʮַ - - - const HexStr: AnsiString - ܵʮַ - Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 - const Iv: TCnAESBuffer - 16 ֽڳʼ - KeyBit: TCnKeyBitType - AES - - ֵAnsiString - ַ -} - -function AESEncryptCtrStrToHex(Value: AnsiString; Key: AnsiString; - const Nonce: TCnAESCTRNonce; const Iv: TCnAESCTRIv; KeyBit: TCnKeyBitType = kbt128): AnsiString; -{* AES CTR ģʽַתʮơ - - - Value: AnsiString - ַܵ - Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const Iv: TCnAESCTRIv - 8 ֽڳʼ - KeyBit: TCnKeyBitType - AES - - ֵAnsiString - ʮַ -} - -function AESDecryptCtrStrFromHex(const HexStr: AnsiString; Key: AnsiString; - const Nonce: TCnAESCTRNonce; const Iv: TCnAESCTRIv; KeyBit: TCnKeyBitType = kbt128): AnsiString; -{* AES CTR ʮַ - - - const HexStr: AnsiString - ܵʮַ - Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 - const Nonce: TCnAESCTRNonce - 4 ֽ Nonce - const Iv: TCnAESCTRIv - 8 ֽڳʼ - KeyBit: TCnKeyBitType - AES - - ֵAnsiString - ַ -} - -// ================= ֽֽ֮ļӽ ==================== - -function AESEncryptEcbBytes(Value: TBytes; Key: TBytes; - KeyBit: TCnKeyBitType = kbt128): TBytes; -{* AES ECB ģʽֽ顣 - - - Value: TBytes - ֽܵ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵTBytes - ֽ -} - -function AESDecryptEcbBytes(Value: TBytes; Key: TBytes; - KeyBit: TCnKeyBitType = kbt128): TBytes; -{* AES ECB ģʽֽ顣 - - - Value: TBytes - ֽܵ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵTBytes - ֽ -} - -function AESEncryptCbcBytes(Value: TBytes; Key: TBytes; Iv: TBytes; - KeyBit: TCnKeyBitType = kbt128): TBytes; -{* AES CBC ģʽֽ顣 - - - Value: TBytes - ֽܵ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵTBytes - ֽ -} - -function AESDecryptCbcBytes(Value: TBytes; Key: TBytes; Iv: TBytes; - KeyBit: TCnKeyBitType = kbt128): TBytes; -{* AES CBC ģʽֽ顣 - - - Value: TBytes - ֽܵ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵTBytes - ֽ -} - -function AESEncryptCfbBytes(Value: TBytes; Key: TBytes; Iv: TBytes; - KeyBit: TCnKeyBitType = kbt128): TBytes; -{* AES CFB ģʽֽ顣 - - - Value: TBytes - ֽܵ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵTBytes - ֽ -} - -function AESDecryptCfbBytes(Value: TBytes; Key: TBytes; Iv: TBytes; - KeyBit: TCnKeyBitType = kbt128): TBytes; -{* AES CFB ģʽֽ顣 - - - Value: TBytes - ֽܵ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵTBytes - ֽ -} - -function AESEncryptOfbBytes(Value: TBytes; Key: TBytes; Iv: TBytes; - KeyBit: TCnKeyBitType = kbt128): TBytes; -{* AES OFB ģʽֽ顣 - - - Value: TBytes - ֽܵ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵTBytes - ֽ -} - -function AESDecryptOfbBytes(Value: TBytes; Key: TBytes; Iv: TBytes; - KeyBit: TCnKeyBitType = kbt128): TBytes; -{* AES OFB ģʽֽ顣 - - - Value: TBytes - ֽܵ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵTBytes - ֽ -} - -function AESEncryptCtrBytes(Value: TBytes; Key: TBytes; Nonce: TBytes; Iv: TBytes; - KeyBit: TCnKeyBitType = kbt128): TBytes; -{* AES CTR ģʽֽ顣 - - - Value: TBytes - ֽܵ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - Nonce: TBytes - 4 ֽ Nonce 飬̫ضϣ 0 - Iv: TBytes - 8 ֽڳʼֽ飬̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵTBytes - ֽ -} - -function AESDecryptCtrBytes(Value: TBytes; Key: TBytes; Nonce: TBytes; Iv: TBytes; - KeyBit: TCnKeyBitType = kbt128): TBytes; -{* AES CTR ģʽֽ顣 - - - Value: TBytes - ֽܵ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - Nonce: TBytes - 4 ֽ Nonce 飬̫ضϣ 0 - Iv: TBytes - 8 ֽڳʼֽ飬̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵTBytes - ֽ -} - -// ============== ֽʮַ֮ļӽ ================= - -function AESEncryptEcbBytesToHex(Value: TBytes; Key: TBytes; - KeyBit: TCnKeyBitType = kbt128): AnsiString; -{* AES ECB ģʽֽ鲢תʮơ - - - Value: TBytes - ֽܵ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵAnsiString - ʮַ -} - -function AESDecryptEcbBytesFromHex(const HexStr: AnsiString; Key: TBytes; - KeyBit: TCnKeyBitType = kbt128): TBytes; -{* AES ECB ʮַֽ顣 - - - const HexStr: AnsiString - ܵʮַ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵTBytes - ֽ -} - -function AESEncryptCbcBytesToHex(Value: TBytes; Key: TBytes; Iv: TBytes; - KeyBit: TCnKeyBitType = kbt128): AnsiString; -{* AES CBC ģʽֽ鲢תʮơ - - - Value: TBytes - ֽܵ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵAnsiString - ʮַ -} - -function AESDecryptCbcBytesFromHex(const HexStr: AnsiString; Key: TBytes; Iv: TBytes; - KeyBit: TCnKeyBitType = kbt128): TBytes; -{* AES CBC ʮַֽ顣 - - - const HexStr: AnsiString - ܵʮַ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵTBytes - ֽ -} - -function AESEncryptCfbBytesToHex(Value: TBytes; Key: TBytes; Iv: TBytes; - KeyBit: TCnKeyBitType = kbt128): AnsiString; -{* AES CFB ģʽֽ鲢תʮơ - - - Value: TBytes - ֽܵ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵAnsiString - ʮַ -} - -function AESDecryptCfbBytesFromHex(const HexStr: AnsiString; Key: TBytes; Iv: TBytes; - KeyBit: TCnKeyBitType = kbt128): TBytes; -{* AES CFB ʮַֽ顣 - - - const HexStr: AnsiString - ܵʮַ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵTBytes - ֽ -} - -function AESEncryptOfbBytesToHex(Value: TBytes; Key: TBytes; Iv: TBytes; - KeyBit: TCnKeyBitType = kbt128): AnsiString; -{* AES OFB ģʽֽ鲢תʮơ - - - Value: TBytes - ֽܵ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵAnsiString - ʮַ -} - -function AESDecryptOfbBytesFromHex(const HexStr: AnsiString; Key: TBytes; Iv: TBytes; - KeyBit: TCnKeyBitType = kbt128): TBytes; -{* AES OFB ʮַֽ顣 - - - const HexStr: AnsiString - ܵʮַ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵTBytes - ֽ -} - -function AESEncryptCtrBytesToHex(Value: TBytes; Key: TBytes; Nonce: TBytes; Iv: TBytes; - KeyBit: TCnKeyBitType = kbt128): AnsiString; -{* AES CTR ģʽֽ鲢תʮơ - - - Value: TBytes - ֽܵ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - Nonce: TBytes - 4 ֽ Nonce ֽ飬̫ضϣ 0 - Iv: TBytes - 8 ֽڳʼֽ飬̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵAnsiString - ʮַ -} - -function AESDecryptCtrBytesFromHex(const HexStr: AnsiString; Key: TBytes; Nonce: TBytes; Iv: TBytes; - KeyBit: TCnKeyBitType = kbt128): TBytes; -{* AES CTR ʮַֽ顣 - - - const HexStr: AnsiString - ܵʮַ - Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 - Nonce: TBytes - 4 ֽ Nonce ֽ飬̫ضϣ 0 - Iv: TBytes - 8 ֽڳʼֽ飬̫ضϣ 0 - KeyBit: TCnKeyBitType - AES - - ֵTBytes - ֽ -} - -implementation - -resourcestring - SCnErrorAESInvalidInBufSize = 'Invalid Buffer Size for Decryption'; - SCnErrorAESReadError = 'Stream Read Error'; - SCnErrorAESWriteError = 'Stream Write Error'; - -function Min(A, B: Integer): Integer; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - if A < B then - Result := A - else - Result := B; -end; - -const - Rcon: array [1..30] of Cardinal = ( - $00000001, $00000002, $00000004, $00000008, $00000010, $00000020, - $00000040, $00000080, $0000001B, $00000036, $0000006C, $000000D8, - $000000AB, $0000004D, $0000009A, $0000002F, $0000005E, $000000BC, - $00000063, $000000C6, $00000097, $00000035, $0000006A, $000000D4, - $000000B3, $0000007D, $000000FA, $000000EF, $000000C5, $00000091 - ); - - ForwardTable: array [0..255] of Cardinal = ( - $A56363C6, $847C7CF8, $997777EE, $8D7B7BF6, $0DF2F2FF, $BD6B6BD6, $B16F6FDE, $54C5C591, - $50303060, $03010102, $A96767CE, $7D2B2B56, $19FEFEE7, $62D7D7B5, $E6ABAB4D, $9A7676EC, - $45CACA8F, $9D82821F, $40C9C989, $877D7DFA, $15FAFAEF, $EB5959B2, $C947478E, $0BF0F0FB, - $ECADAD41, $67D4D4B3, $FDA2A25F, $EAAFAF45, $BF9C9C23, $F7A4A453, $967272E4, $5BC0C09B, - $C2B7B775, $1CFDFDE1, $AE93933D, $6A26264C, $5A36366C, $413F3F7E, $02F7F7F5, $4FCCCC83, - $5C343468, $F4A5A551, $34E5E5D1, $08F1F1F9, $937171E2, $73D8D8AB, $53313162, $3F15152A, - $0C040408, $52C7C795, $65232346, $5EC3C39D, $28181830, $A1969637, $0F05050A, $B59A9A2F, - $0907070E, $36121224, $9B80801B, $3DE2E2DF, $26EBEBCD, $6927274E, $CDB2B27F, $9F7575EA, - $1B090912, $9E83831D, $742C2C58, $2E1A1A34, $2D1B1B36, $B26E6EDC, $EE5A5AB4, $FBA0A05B, - $F65252A4, $4D3B3B76, $61D6D6B7, $CEB3B37D, $7B292952, $3EE3E3DD, $712F2F5E, $97848413, - $F55353A6, $68D1D1B9, $00000000, $2CEDEDC1, $60202040, $1FFCFCE3, $C8B1B179, $ED5B5BB6, - $BE6A6AD4, $46CBCB8D, $D9BEBE67, $4B393972, $DE4A4A94, $D44C4C98, $E85858B0, $4ACFCF85, - $6BD0D0BB, $2AEFEFC5, $E5AAAA4F, $16FBFBED, $C5434386, $D74D4D9A, $55333366, $94858511, - $CF45458A, $10F9F9E9, $06020204, $817F7FFE, $F05050A0, $443C3C78, $BA9F9F25, $E3A8A84B, - $F35151A2, $FEA3A35D, $C0404080, $8A8F8F05, $AD92923F, $BC9D9D21, $48383870, $04F5F5F1, - $DFBCBC63, $C1B6B677, $75DADAAF, $63212142, $30101020, $1AFFFFE5, $0EF3F3FD, $6DD2D2BF, - $4CCDCD81, $140C0C18, $35131326, $2FECECC3, $E15F5FBE, $A2979735, $CC444488, $3917172E, - $57C4C493, $F2A7A755, $827E7EFC, $473D3D7A, $AC6464C8, $E75D5DBA, $2B191932, $957373E6, - $A06060C0, $98818119, $D14F4F9E, $7FDCDCA3, $66222244, $7E2A2A54, $AB90903B, $8388880B, - $CA46468C, $29EEEEC7, $D3B8B86B, $3C141428, $79DEDEA7, $E25E5EBC, $1D0B0B16, $76DBDBAD, - $3BE0E0DB, $56323264, $4E3A3A74, $1E0A0A14, $DB494992, $0A06060C, $6C242448, $E45C5CB8, - $5DC2C29F, $6ED3D3BD, $EFACAC43, $A66262C4, $A8919139, $A4959531, $37E4E4D3, $8B7979F2, - $32E7E7D5, $43C8C88B, $5937376E, $B76D6DDA, $8C8D8D01, $64D5D5B1, $D24E4E9C, $E0A9A949, - $B46C6CD8, $FA5656AC, $07F4F4F3, $25EAEACF, $AF6565CA, $8E7A7AF4, $E9AEAE47, $18080810, - $D5BABA6F, $887878F0, $6F25254A, $722E2E5C, $241C1C38, $F1A6A657, $C7B4B473, $51C6C697, - $23E8E8CB, $7CDDDDA1, $9C7474E8, $211F1F3E, $DD4B4B96, $DCBDBD61, $868B8B0D, $858A8A0F, - $907070E0, $423E3E7C, $C4B5B571, $AA6666CC, $D8484890, $05030306, $01F6F6F7, $120E0E1C, - $A36161C2, $5F35356A, $F95757AE, $D0B9B969, $91868617, $58C1C199, $271D1D3A, $B99E9E27, - $38E1E1D9, $13F8F8EB, $B398982B, $33111122, $BB6969D2, $70D9D9A9, $898E8E07, $A7949433, - $B69B9B2D, $221E1E3C, $92878715, $20E9E9C9, $49CECE87, $FF5555AA, $78282850, $7ADFDFA5, - $8F8C8C03, $F8A1A159, $80898909, $170D0D1A, $DABFBF65, $31E6E6D7, $C6424284, $B86868D0, - $C3414182, $B0999929, $772D2D5A, $110F0F1E, $CBB0B07B, $FC5454A8, $D6BBBB6D, $3A16162C - ); - - LastForwardTable: array [0..255] of Cardinal = ( - $00000063, $0000007C, $00000077, $0000007B, $000000F2, $0000006B, $0000006F, $000000C5, - $00000030, $00000001, $00000067, $0000002B, $000000FE, $000000D7, $000000AB, $00000076, - $000000CA, $00000082, $000000C9, $0000007D, $000000FA, $00000059, $00000047, $000000F0, - $000000AD, $000000D4, $000000A2, $000000AF, $0000009C, $000000A4, $00000072, $000000C0, - $000000B7, $000000FD, $00000093, $00000026, $00000036, $0000003F, $000000F7, $000000CC, - $00000034, $000000A5, $000000E5, $000000F1, $00000071, $000000D8, $00000031, $00000015, - $00000004, $000000C7, $00000023, $000000C3, $00000018, $00000096, $00000005, $0000009A, - $00000007, $00000012, $00000080, $000000E2, $000000EB, $00000027, $000000B2, $00000075, - $00000009, $00000083, $0000002C, $0000001A, $0000001B, $0000006E, $0000005A, $000000A0, - $00000052, $0000003B, $000000D6, $000000B3, $00000029, $000000E3, $0000002F, $00000084, - $00000053, $000000D1, $00000000, $000000ED, $00000020, $000000FC, $000000B1, $0000005B, - $0000006A, $000000CB, $000000BE, $00000039, $0000004A, $0000004C, $00000058, $000000CF, - $000000D0, $000000EF, $000000AA, $000000FB, $00000043, $0000004D, $00000033, $00000085, - $00000045, $000000F9, $00000002, $0000007F, $00000050, $0000003C, $0000009F, $000000A8, - $00000051, $000000A3, $00000040, $0000008F, $00000092, $0000009D, $00000038, $000000F5, - $000000BC, $000000B6, $000000DA, $00000021, $00000010, $000000FF, $000000F3, $000000D2, - $000000CD, $0000000C, $00000013, $000000EC, $0000005F, $00000097, $00000044, $00000017, - $000000C4, $000000A7, $0000007E, $0000003D, $00000064, $0000005D, $00000019, $00000073, - $00000060, $00000081, $0000004F, $000000DC, $00000022, $0000002A, $00000090, $00000088, - $00000046, $000000EE, $000000B8, $00000014, $000000DE, $0000005E, $0000000B, $000000DB, - $000000E0, $00000032, $0000003A, $0000000A, $00000049, $00000006, $00000024, $0000005C, - $000000C2, $000000D3, $000000AC, $00000062, $00000091, $00000095, $000000E4, $00000079, - $000000E7, $000000C8, $00000037, $0000006D, $0000008D, $000000D5, $0000004E, $000000A9, - $0000006C, $00000056, $000000F4, $000000EA, $00000065, $0000007A, $000000AE, $00000008, - $000000BA, $00000078, $00000025, $0000002E, $0000001C, $000000A6, $000000B4, $000000C6, - $000000E8, $000000DD, $00000074, $0000001F, $0000004B, $000000BD, $0000008B, $0000008A, - $00000070, $0000003E, $000000B5, $00000066, $00000048, $00000003, $000000F6, $0000000E, - $00000061, $00000035, $00000057, $000000B9, $00000086, $000000C1, $0000001D, $0000009E, - $000000E1, $000000F8, $00000098, $00000011, $00000069, $000000D9, $0000008E, $00000094, - $0000009B, $0000001E, $00000087, $000000E9, $000000CE, $00000055, $00000028, $000000DF, - $0000008C, $000000A1, $00000089, $0000000D, $000000BF, $000000E6, $00000042, $00000068, - $00000041, $00000099, $0000002D, $0000000F, $000000B0, $00000054, $000000BB, $00000016 - ); - - InverseTable: array [0..255] of Cardinal = ( - $50A7F451, $5365417E, $C3A4171A, $965E273A, $CB6BAB3B, $F1459D1F, $AB58FAAC, $9303E34B, - $55FA3020, $F66D76AD, $9176CC88, $254C02F5, $FCD7E54F, $D7CB2AC5, $80443526, $8FA362B5, - $495AB1DE, $671BBA25, $980EEA45, $E1C0FE5D, $02752FC3, $12F04C81, $A397468D, $C6F9D36B, - $E75F8F03, $959C9215, $EB7A6DBF, $DA595295, $2D83BED4, $D3217458, $2969E049, $44C8C98E, - $6A89C275, $78798EF4, $6B3E5899, $DD71B927, $B64FE1BE, $17AD88F0, $66AC20C9, $B43ACE7D, - $184ADF63, $82311AE5, $60335197, $457F5362, $E07764B1, $84AE6BBB, $1CA081FE, $942B08F9, - $58684870, $19FD458F, $876CDE94, $B7F87B52, $23D373AB, $E2024B72, $578F1FE3, $2AAB5566, - $0728EBB2, $03C2B52F, $9A7BC586, $A50837D3, $F2872830, $B2A5BF23, $BA6A0302, $5C8216ED, - $2B1CCF8A, $92B479A7, $F0F207F3, $A1E2694E, $CDF4DA65, $D5BE0506, $1F6234D1, $8AFEA6C4, - $9D532E34, $A055F3A2, $32E18A05, $75EBF6A4, $39EC830B, $AAEF6040, $069F715E, $51106EBD, - $F98A213E, $3D06DD96, $AE053EDD, $46BDE64D, $B58D5491, $055DC471, $6FD40604, $FF155060, - $24FB9819, $97E9BDD6, $CC434089, $779ED967, $BD42E8B0, $888B8907, $385B19E7, $DBEEC879, - $470A7CA1, $E90F427C, $C91E84F8, $00000000, $83868009, $48ED2B32, $AC70111E, $4E725A6C, - $FBFF0EFD, $5638850F, $1ED5AE3D, $27392D36, $64D90F0A, $21A65C68, $D1545B9B, $3A2E3624, - $B1670A0C, $0FE75793, $D296EEB4, $9E919B1B, $4FC5C080, $A220DC61, $694B775A, $161A121C, - $0ABA93E2, $E52AA0C0, $43E0223C, $1D171B12, $0B0D090E, $ADC78BF2, $B9A8B62D, $C8A91E14, - $8519F157, $4C0775AF, $BBDD99EE, $FD607FA3, $9F2601F7, $BCF5725C, $C53B6644, $347EFB5B, - $7629438B, $DCC623CB, $68FCEDB6, $63F1E4B8, $CADC31D7, $10856342, $40229713, $2011C684, - $7D244A85, $F83DBBD2, $1132F9AE, $6DA129C7, $4B2F9E1D, $F330B2DC, $EC52860D, $D0E3C177, - $6C16B32B, $99B970A9, $FA489411, $2264E947, $C48CFCA8, $1A3FF0A0, $D82C7D56, $EF903322, - $C74E4987, $C1D138D9, $FEA2CA8C, $360BD498, $CF81F5A6, $28DE7AA5, $268EB7DA, $A4BFAD3F, - $E49D3A2C, $0D927850, $9BCC5F6A, $62467E54, $C2138DF6, $E8B8D890, $5EF7392E, $F5AFC382, - $BE805D9F, $7C93D069, $A92DD56F, $B31225CF, $3B99ACC8, $A77D1810, $6E639CE8, $7BBB3BDB, - $097826CD, $F418596E, $01B79AEC, $A89A4F83, $656E95E6, $7EE6FFAA, $08CFBC21, $E6E815EF, - $D99BE7BA, $CE366F4A, $D4099FEA, $D67CB029, $AFB2A431, $31233F2A, $3094A5C6, $C066A235, - $37BC4E74, $A6CA82FC, $B0D090E0, $15D8A733, $4A9804F1, $F7DAEC41, $0E50CD7F, $2FF69117, - $8DD64D76, $4DB0EF43, $544DAACC, $DF0496E4, $E3B5D19E, $1B886A4C, $B81F2CC1, $7F516546, - $04EA5E9D, $5D358C01, $737487FA, $2E410BFB, $5A1D67B3, $52D2DB92, $335610E9, $1347D66D, - $8C61D79A, $7A0CA137, $8E14F859, $893C13EB, $EE27A9CE, $35C961B7, $EDE51CE1, $3CB1477A, - $59DFD29C, $3F73F255, $79CE1418, $BF37C773, $EACDF753, $5BAAFD5F, $146F3DDF, $86DB4478, - $81F3AFCA, $3EC468B9, $2C342438, $5F40A3C2, $72C31D16, $0C25E2BC, $8B493C28, $41950DFF, - $7101A839, $DEB30C08, $9CE4B4D8, $90C15664, $6184CB7B, $70B632D5, $745C6C48, $4257B8D0 - ); - - LastInverseTable: array [0..255] of Cardinal = ( - $00000052, $00000009, $0000006A, $000000D5, $00000030, $00000036, $000000A5, $00000038, - $000000BF, $00000040, $000000A3, $0000009E, $00000081, $000000F3, $000000D7, $000000FB, - $0000007C, $000000E3, $00000039, $00000082, $0000009B, $0000002F, $000000FF, $00000087, - $00000034, $0000008E, $00000043, $00000044, $000000C4, $000000DE, $000000E9, $000000CB, - $00000054, $0000007B, $00000094, $00000032, $000000A6, $000000C2, $00000023, $0000003D, - $000000EE, $0000004C, $00000095, $0000000B, $00000042, $000000FA, $000000C3, $0000004E, - $00000008, $0000002E, $000000A1, $00000066, $00000028, $000000D9, $00000024, $000000B2, - $00000076, $0000005B, $000000A2, $00000049, $0000006D, $0000008B, $000000D1, $00000025, - $00000072, $000000F8, $000000F6, $00000064, $00000086, $00000068, $00000098, $00000016, - $000000D4, $000000A4, $0000005C, $000000CC, $0000005D, $00000065, $000000B6, $00000092, - $0000006C, $00000070, $00000048, $00000050, $000000FD, $000000ED, $000000B9, $000000DA, - $0000005E, $00000015, $00000046, $00000057, $000000A7, $0000008D, $0000009D, $00000084, - $00000090, $000000D8, $000000AB, $00000000, $0000008C, $000000BC, $000000D3, $0000000A, - $000000F7, $000000E4, $00000058, $00000005, $000000B8, $000000B3, $00000045, $00000006, - $000000D0, $0000002C, $0000001E, $0000008F, $000000CA, $0000003F, $0000000F, $00000002, - $000000C1, $000000AF, $000000BD, $00000003, $00000001, $00000013, $0000008A, $0000006B, - $0000003A, $00000091, $00000011, $00000041, $0000004F, $00000067, $000000DC, $000000EA, - $00000097, $000000F2, $000000CF, $000000CE, $000000F0, $000000B4, $000000E6, $00000073, - $00000096, $000000AC, $00000074, $00000022, $000000E7, $000000AD, $00000035, $00000085, - $000000E2, $000000F9, $00000037, $000000E8, $0000001C, $00000075, $000000DF, $0000006E, - $00000047, $000000F1, $0000001A, $00000071, $0000001D, $00000029, $000000C5, $00000089, - $0000006F, $000000B7, $00000062, $0000000E, $000000AA, $00000018, $000000BE, $0000001B, - $000000FC, $00000056, $0000003E, $0000004B, $000000C6, $000000D2, $00000079, $00000020, - $0000009A, $000000DB, $000000C0, $000000FE, $00000078, $000000CD, $0000005A, $000000F4, - $0000001F, $000000DD, $000000A8, $00000033, $00000088, $00000007, $000000C7, $00000031, - $000000B1, $00000012, $00000010, $00000059, $00000027, $00000080, $000000EC, $0000005F, - $00000060, $00000051, $0000007F, $000000A9, $00000019, $000000B5, $0000004A, $0000000D, - $0000002D, $000000E5, $0000007A, $0000009F, $00000093, $000000C9, $0000009C, $000000EF, - $000000A0, $000000E0, $0000003B, $0000004D, $000000AE, $0000002A, $000000F5, $000000B0, - $000000C8, $000000EB, $000000BB, $0000003C, $00000083, $00000053, $00000099, $00000061, - $00000017, $0000002B, $00000004, $0000007E, $000000BA, $00000077, $000000D6, $00000026, - $000000E1, $00000069, $00000014, $00000063, $00000055, $00000021, $0000000C, $0000007D - ); - -procedure ExpandAESKeyForEncryption128(const Key: TCnAESKey128; var ExpandedKey: - TCnAESExpandedKey128); -var - I, J: Integer; - T: Cardinal; - W0, W1, W2, W3: Cardinal; -begin - ExpandedKey[0] := PCardinal(@Key[0])^; - ExpandedKey[1] := PCardinal(@Key[4])^; - ExpandedKey[2] := PCardinal(@Key[8])^; - ExpandedKey[3] := PCardinal(@Key[12])^; - I := 0; J := 1; - repeat - T := (ExpandedKey[I + 3] shl 24) or (ExpandedKey[I + 3] shr 8); - W0 := LastForwardTable[Byte(T)]; W1 := LastForwardTable[Byte(T shr 8)]; - W2 := LastForwardTable[Byte(T shr 16)]; W3 := LastForwardTable[Byte(T shr 24)]; - ExpandedKey[I + 4] := ExpandedKey[I] xor - (W0 xor ((W1 shl 8) or (W1 shr 24)) xor - ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8))) xor Rcon[J]; - Inc(J); - ExpandedKey[I + 5] := ExpandedKey[I + 1] xor ExpandedKey[I + 4]; - ExpandedKey[I + 6] := ExpandedKey[I + 2] xor ExpandedKey[I + 5]; - ExpandedKey[I + 7] := ExpandedKey[I + 3] xor ExpandedKey[I + 6]; - Inc(I, 4); - until I >= 40; -end; - -procedure ExpandAESKeyForEncryption192(const Key: TCnAESKey192; var ExpandedKey: - TCnAESExpandedKey192); -var - I, J: Integer; - T: Cardinal; - W0, W1, W2, W3: Cardinal; -begin - ExpandedKey[0] := PCardinal(@Key[0])^; - ExpandedKey[1] := PCardinal(@Key[4])^; - ExpandedKey[2] := PCardinal(@Key[8])^; - ExpandedKey[3] := PCardinal(@Key[12])^; - ExpandedKey[4] := PCardinal(@Key[16])^; - ExpandedKey[5] := PCardinal(@Key[20])^; - I := 0; J := 1; - repeat - T := (ExpandedKey[I + 5] shl 24) or (ExpandedKey[I + 5] shr 8); - W0 := LastForwardTable[Byte(T)]; W1 := LastForwardTable[Byte(T shr 8)]; - W2 := LastForwardTable[Byte(T shr 16)]; W3 := LastForwardTable[Byte(T shr 24)]; - ExpandedKey[I + 6] := ExpandedKey[I] xor - (W0 xor ((W1 shl 8) or (W1 shr 24)) xor - ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8))) xor Rcon[J]; - Inc(J); - ExpandedKey[I + 7] := ExpandedKey[I + 1] xor ExpandedKey[I + 6]; - ExpandedKey[I + 8] := ExpandedKey[I + 2] xor ExpandedKey[I + 7]; - ExpandedKey[I + 9] := ExpandedKey[I + 3] xor ExpandedKey[I + 8]; - ExpandedKey[I + 10] := ExpandedKey[I + 4] xor ExpandedKey[I + 9]; - ExpandedKey[I + 11] := ExpandedKey[I + 5] xor ExpandedKey[I + 10]; - Inc(I, 6); - until I >= 46; -end; - -procedure ExpandAESKeyForEncryption256(const Key: TCnAESKey256; var ExpandedKey: - TCnAESExpandedKey256); -var - I, J: Integer; - T: Cardinal; - W0, W1, W2, W3: Cardinal; -begin - ExpandedKey[0] := PCardinal(@Key[0])^; - ExpandedKey[1] := PCardinal(@Key[4])^; - ExpandedKey[2] := PCardinal(@Key[8])^; - ExpandedKey[3] := PCardinal(@Key[12])^; - ExpandedKey[4] := PCardinal(@Key[16])^; - ExpandedKey[5] := PCardinal(@Key[20])^; - ExpandedKey[6] := PCardinal(@Key[24])^; - ExpandedKey[7] := PCardinal(@Key[28])^; - I := 0; J := 1; - repeat - T := (ExpandedKey[I + 7] shl 24) or (ExpandedKey[I + 7] shr 8); - W0 := LastForwardTable[Byte(T)]; W1 := LastForwardTable[Byte(T shr 8)]; - W2 := LastForwardTable[Byte(T shr 16)]; W3 := LastForwardTable[Byte(T shr 24)]; - ExpandedKey[I + 8] := ExpandedKey[I] xor - (W0 xor ((W1 shl 8) or (W1 shr 24)) xor - ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8))) xor Rcon[J]; - Inc(J); - ExpandedKey[I + 9] := ExpandedKey[I + 1] xor ExpandedKey[I + 8]; - ExpandedKey[I + 10] := ExpandedKey[I + 2] xor ExpandedKey[I + 9]; - ExpandedKey[I + 11] := ExpandedKey[I + 3] xor ExpandedKey[I + 10]; - W0 := LastForwardTable[Byte(ExpandedKey[I + 11])]; - W1 := LastForwardTable[Byte(ExpandedKey[I + 11] shr 8)]; - W2 := LastForwardTable[Byte(ExpandedKey[I + 11] shr 16)]; - W3 := LastForwardTable[Byte(ExpandedKey[I + 11] shr 24)]; - ExpandedKey[I + 12] := ExpandedKey[I + 4] xor - (W0 xor ((W1 shl 8) or (W1 shr 24)) xor - ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8))); - ExpandedKey[I + 13] := ExpandedKey[I + 5] xor ExpandedKey[I + 12]; - ExpandedKey[I + 14] := ExpandedKey[I + 6] xor ExpandedKey[I + 13]; - ExpandedKey[I + 15] := ExpandedKey[I + 7] xor ExpandedKey[I + 14]; - Inc(I, 8); - until I >= 52; -end; - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; - var OutBuf: TCnAESBuffer); -begin - EncryptAES128(InBuf, Key, OutBuf); -end; - -procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; - var OutBuf: TCnAESBuffer); -begin - EncryptAES192(InBuf, Key, OutBuf); -end; - -procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; - var OutBuf: TCnAESBuffer); -begin - EncryptAES256(InBuf, Key, OutBuf); -end; - -{$ENDIF} - -procedure EncryptAES128(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; - var OutBuf: TCnAESBuffer); -var - T0, T1: array [0..3] of Cardinal; - W0, W1, W2, W3: Cardinal; -begin - // initializing - T0[0] := PCardinal(@InBuf[0])^ xor Key[0]; - T0[1] := PCardinal(@InBuf[4])^ xor Key[1]; - T0[2] := PCardinal(@InBuf[8])^ xor Key[2]; - T0[3] := PCardinal(@InBuf[12])^ xor Key[3]; - - // performing transformation 9 times - // round 1 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; - // round 2 - W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; - W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; - W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; - W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; - W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; - W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; - W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; - W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; - // round 3 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; - // round 4 - W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; - W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; - W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; - W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; - W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; - W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; - W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; - W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; - // round 5 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; - // round 6 - W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; - W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; - W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; - W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; - W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; - W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; - W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; - W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; - // round 7 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; - // round 8 - W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; - W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; - W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; - W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; - W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; - W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; - W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; - W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; - // round 9 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; - // last round of transformations - W0 := LastForwardTable[Byte(T1[0])]; W1 := LastForwardTable[Byte(T1[1] shr 8)]; - W2 := LastForwardTable[Byte(T1[2] shr 16)]; W3 := LastForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; - W0 := LastForwardTable[Byte(T1[1])]; W1 := LastForwardTable[Byte(T1[2] shr 8)]; - W2 := LastForwardTable[Byte(T1[3] shr 16)]; W3 := LastForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; - W0 := LastForwardTable[Byte(T1[2])]; W1 := LastForwardTable[Byte(T1[3] shr 8)]; - W2 := LastForwardTable[Byte(T1[0] shr 16)]; W3 := LastForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; - W0 := LastForwardTable[Byte(T1[3])]; W1 := LastForwardTable[Byte(T1[0] shr 8)]; - W2 := LastForwardTable[Byte(T1[1] shr 16)]; W3 := LastForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; - - // finalizing - PCardinal(@OutBuf[0])^ := T0[0]; - PCardinal(@OutBuf[4])^ := T0[1]; - PCardinal(@OutBuf[8])^ := T0[2]; - PCardinal(@OutBuf[12])^ := T0[3]; -end; - -procedure EncryptAES192(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; - var OutBuf: TCnAESBuffer); -var - T0, T1: array [0..3] of Cardinal; - W0, W1, W2, W3: Cardinal; -begin - // initializing - T0[0] := PCardinal(@InBuf[0])^ xor Key[0]; - T0[1] := PCardinal(@InBuf[4])^ xor Key[1]; - T0[2] := PCardinal(@InBuf[8])^ xor Key[2]; - T0[3] := PCardinal(@InBuf[12])^ xor Key[3]; - - // performing transformation 11 times - // round 1 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; - // round 2 - W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; - W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; - W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; - W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; - W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; - W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; - W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; - W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; - // round 3 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; - // round 4 - W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; - W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; - W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; - W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; - W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; - W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; - W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; - W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; - // round 5 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; - // round 6 - W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; - W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; - W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; - W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; - W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; - W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; - W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; - W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; - // round 7 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; - // round 8 - W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; - W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; - W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; - W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; - W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; - W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; - W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; - W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; - // round 9 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; - // round 10 - W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; - W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; - W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; - W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; - W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; - W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; - W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; - W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; - // round 11 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[44]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[45]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[46]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[47]; - // last round of transformations - W0 := LastForwardTable[Byte(T1[0])]; W1 := LastForwardTable[Byte(T1[1] shr 8)]; - W2 := LastForwardTable[Byte(T1[2] shr 16)]; W3 := LastForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[48]; - W0 := LastForwardTable[Byte(T1[1])]; W1 := LastForwardTable[Byte(T1[2] shr 8)]; - W2 := LastForwardTable[Byte(T1[3] shr 16)]; W3 := LastForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[49]; - W0 := LastForwardTable[Byte(T1[2])]; W1 := LastForwardTable[Byte(T1[3] shr 8)]; - W2 := LastForwardTable[Byte(T1[0] shr 16)]; W3 := LastForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[50]; - W0 := LastForwardTable[Byte(T1[3])]; W1 := LastForwardTable[Byte(T1[0] shr 8)]; - W2 := LastForwardTable[Byte(T1[1] shr 16)]; W3 := LastForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[51]; - - // finalizing - PCardinal(@OutBuf[0])^ := T0[0]; - PCardinal(@OutBuf[4])^ := T0[1]; - PCardinal(@OutBuf[8])^ := T0[2]; - PCardinal(@OutBuf[12])^ := T0[3]; -end; - -procedure EncryptAES256(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; - var OutBuf: TCnAESBuffer); -var - T0, T1: array [0..3] of Cardinal; - W0, W1, W2, W3: Cardinal; -begin - // initializing - T0[0] := PCardinal(@InBuf[0])^ xor Key[0]; - T0[1] := PCardinal(@InBuf[4])^ xor Key[1]; - T0[2] := PCardinal(@InBuf[8])^ xor Key[2]; - T0[3] := PCardinal(@InBuf[12])^ xor Key[3]; - - // performing transformation 13 times - // round 1 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; - // round 2 - W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; - W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; - W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; - W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; - W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; - W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; - W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; - W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; - // round 3 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; - // round 4 - W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; - W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; - W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; - W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; - W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; - W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; - W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; - W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; - // round 5 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; - // round 6 - W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; - W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; - W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; - W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; - W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; - W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; - W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; - W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; - // round 7 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; - // round 8 - W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; - W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; - W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; - W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; - W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; - W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; - W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; - W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; - // round 9 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; - // round 10 - W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; - W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; - W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; - W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; - W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; - W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; - W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; - W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; - // round 11 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[44]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[45]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[46]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[47]; - // round 12 - W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; - W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[48]; - W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; - W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[49]; - W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; - W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[50]; - W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; - W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[51]; - // round 13 - W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; - W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[52]; - W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; - W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[53]; - W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; - W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[54]; - W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; - W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[55]; - // last round of transformations - W0 := LastForwardTable[Byte(T1[0])]; W1 := LastForwardTable[Byte(T1[1] shr 8)]; - W2 := LastForwardTable[Byte(T1[2] shr 16)]; W3 := LastForwardTable[Byte(T1[3] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[56]; - W0 := LastForwardTable[Byte(T1[1])]; W1 := LastForwardTable[Byte(T1[2] shr 8)]; - W2 := LastForwardTable[Byte(T1[3] shr 16)]; W3 := LastForwardTable[Byte(T1[0] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[57]; - W0 := LastForwardTable[Byte(T1[2])]; W1 := LastForwardTable[Byte(T1[3] shr 8)]; - W2 := LastForwardTable[Byte(T1[0] shr 16)]; W3 := LastForwardTable[Byte(T1[1] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[58]; - W0 := LastForwardTable[Byte(T1[3])]; W1 := LastForwardTable[Byte(T1[0] shr 8)]; - W2 := LastForwardTable[Byte(T1[1] shr 16)]; W3 := LastForwardTable[Byte(T1[2] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[59]; - - // finalizing - PCardinal(@OutBuf[0])^ := T0[0]; - PCardinal(@OutBuf[4])^ := T0[1]; - PCardinal(@OutBuf[8])^ := T0[2]; - PCardinal(@OutBuf[12])^ := T0[3]; -end; - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey128); -begin - ExpandAESKeyForDecryption128(ExpandedKey); -end; - -procedure ExpandAESKeyForDecryption(const Key: TCnAESKey128; - var ExpandedKey: TCnAESExpandedKey128); -begin - ExpandAESKeyForDecryption128Expanded(Key, ExpandedKey); -end; - -procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey192); -begin - ExpandAESKeyForDecryption192(ExpandedKey); -end; - -procedure ExpandAESKeyForDecryption(const Key: TCnAESKey192; - var ExpandedKey: TCnAESExpandedKey192); -begin - ExpandAESKeyForDecryption192Expanded(Key, ExpandedKey); -end; - -procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey256); -begin - ExpandAESKeyForDecryption256(ExpandedKey); -end; - -procedure ExpandAESKeyForDecryption(const Key: TCnAESKey256; - var ExpandedKey: TCnAESExpandedKey256); -begin - ExpandAESKeyForDecryption256Expanded(Key, ExpandedKey); -end; - -{$ENDIF} - -procedure ExpandAESKeyForDecryption128(var ExpandedKey: TCnAESExpandedKey128); -var - I: Integer; - U, F2, F4, F8, F9: Cardinal; -begin - for I := 1 to 9 do - begin - F9 := ExpandedKey[I * 4]; - U := F9 and $80808080; - F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F2 and $80808080; - F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F4 and $80808080; - F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - F9 := F9 xor F8; - ExpandedKey[I * 4] := F2 xor F4 xor F8 xor - (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor - (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); - F9 := ExpandedKey[I * 4 + 1]; - U := F9 and $80808080; - F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F2 and $80808080; - F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F4 and $80808080; - F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - F9 := F9 xor F8; - ExpandedKey[I * 4 + 1] := F2 xor F4 xor F8 xor - (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor - (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); - F9 := ExpandedKey[I * 4 + 2]; - U := F9 and $80808080; - F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F2 and $80808080; - F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F4 and $80808080; - F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - F9 := F9 xor F8; - ExpandedKey[I * 4 + 2] := F2 xor F4 xor F8 xor - (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor - (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); - F9 := ExpandedKey[I * 4 + 3]; - U := F9 and $80808080; - F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F2 and $80808080; - F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F4 and $80808080; - F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - F9 := F9 xor F8; - ExpandedKey[I * 4 + 3] := F2 xor F4 xor F8 xor - (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor - (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); - end; -end; - -procedure ExpandAESKeyForDecryption128Expanded(const Key: TCnAESKey128; var ExpandedKey: - TCnAESExpandedKey128); -begin - ExpandAESKeyForEncryption128(Key, ExpandedKey); - ExpandAESKeyForDecryption128(ExpandedKey); -end; - -procedure ExpandAESKeyForDecryption192(var ExpandedKey: TCnAESExpandedKey192); -var - I: Integer; - U, F2, F4, F8, F9: Cardinal; -begin - for I := 1 to 11 do - begin - F9 := ExpandedKey[I * 4]; - U := F9 and $80808080; - F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F2 and $80808080; - F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F4 and $80808080; - F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - F9 := F9 xor F8; - ExpandedKey[I * 4] := F2 xor F4 xor F8 xor - (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor - (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); - F9 := ExpandedKey[I * 4 + 1]; - U := F9 and $80808080; - F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F2 and $80808080; - F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F4 and $80808080; - F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - F9 := F9 xor F8; - ExpandedKey[I * 4 + 1] := F2 xor F4 xor F8 xor - (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor - (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); - F9 := ExpandedKey[I * 4 + 2]; - U := F9 and $80808080; - F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F2 and $80808080; - F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F4 and $80808080; - F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - F9 := F9 xor F8; - ExpandedKey[I * 4 + 2] := F2 xor F4 xor F8 xor - (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor - (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); - F9 := ExpandedKey[I * 4 + 3]; - U := F9 and $80808080; - F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F2 and $80808080; - F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F4 and $80808080; - F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - F9 := F9 xor F8; - ExpandedKey[I * 4 + 3] := F2 xor F4 xor F8 xor - (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor - (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); - end; -end; - -procedure ExpandAESKeyForDecryption192Expanded(const Key: TCnAESKey192; var ExpandedKey: - TCnAESExpandedKey192); -begin - ExpandAESKeyForEncryption192(Key, ExpandedKey); - ExpandAESKeyForDecryption192(ExpandedKey); -end; - -procedure ExpandAESKeyForDecryption256(var ExpandedKey: TCnAESExpandedKey256); -var - I: Integer; - U, F2, F4, F8, F9: Cardinal; -begin - for I := 1 to 13 do - begin - F9 := ExpandedKey[I * 4]; - U := F9 and $80808080; - F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F2 and $80808080; - F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F4 and $80808080; - F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - F9 := F9 xor F8; - ExpandedKey[I * 4] := F2 xor F4 xor F8 xor - (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor - (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); - F9 := ExpandedKey[I * 4 + 1]; - U := F9 and $80808080; - F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F2 and $80808080; - F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F4 and $80808080; - F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - F9 := F9 xor F8; - ExpandedKey[I * 4 + 1] := F2 xor F4 xor F8 xor - (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor - (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); - F9 := ExpandedKey[I * 4 + 2]; - U := F9 and $80808080; - F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F2 and $80808080; - F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F4 and $80808080; - F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - F9 := F9 xor F8; - ExpandedKey[I * 4 + 2] := F2 xor F4 xor F8 xor - (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor - (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); - F9 := ExpandedKey[I * 4 + 3]; - U := F9 and $80808080; - F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F2 and $80808080; - F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - U := F4 and $80808080; - F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); - F9 := F9 xor F8; - ExpandedKey[I * 4 + 3] := F2 xor F4 xor F8 xor - (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor - (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); - end; -end; - -procedure ExpandAESKeyForDecryption256Expanded(const Key: TCnAESKey256; var ExpandedKey: - TCnAESExpandedKey256); -begin - ExpandAESKeyForEncryption256(Key, ExpandedKey); - ExpandAESKeyForDecryption256(ExpandedKey); -end; - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; - var OutBuf: TCnAESBuffer); -begin - DecryptAES128(InBuf, Key, OutBuf); -end; - -procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; - var OutBuf: TCnAESBuffer); -begin - DecryptAES192(InBuf, Key, OutBuf); -end; - -procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; - var OutBuf: TCnAESBuffer); -begin - DecryptAES256(InBuf, Key, OutBuf); -end; - -{$ENDIF} - -procedure DecryptAES128(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; - var OutBuf: TCnAESBuffer); -var - T0, T1: array [0..3] of Cardinal; - W0, W1, W2, W3: Cardinal; -begin - // initializing - T0[0] := PCardinal(@InBuf[0])^ xor Key[40]; - T0[1] := PCardinal(@InBuf[4])^ xor Key[41]; - T0[2] := PCardinal(@InBuf[8])^ xor Key[42]; - T0[3] := PCardinal(@InBuf[12])^ xor Key[43]; - - // performing transformations 9 times - // round 1 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; - // round 2 - W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; - W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; - W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; - W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; - W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; - W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; - W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; - W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; - // round 3 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; - // round 4 - W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; - W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; - W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; - W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; - W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; - W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; - W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; - W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; - // round 5 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; - // round 6 - W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; - W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; - W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; - W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; - W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; - W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; - W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; - W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; - // round 7 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; - // round 8 - W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; - W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; - W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; - W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; - W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; - W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; - W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; - W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; - // round 9 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; - // last round of transformations - W0 := LastInverseTable[Byte(T1[0])]; W1 := LastInverseTable[Byte(T1[3] shr 8)]; - W2 := LastInverseTable[Byte(T1[2] shr 16)]; W3 := LastInverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[0]; - W0 := LastInverseTable[Byte(T1[1])]; W1 := LastInverseTable[Byte(T1[0] shr 8)]; - W2 := LastInverseTable[Byte(T1[3] shr 16)]; W3 := LastInverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[1]; - W0 := LastInverseTable[Byte(T1[2])]; W1 := LastInverseTable[Byte(T1[1] shr 8)]; - W2 := LastInverseTable[Byte(T1[0] shr 16)]; W3 := LastInverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[2]; - W0 := LastInverseTable[Byte(T1[3])]; W1 := LastInverseTable[Byte(T1[2] shr 8)]; - W2 := LastInverseTable[Byte(T1[1] shr 16)]; W3 := LastInverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[3]; - - // finalizing - PCardinal(@OutBuf[0])^ := T0[0]; - PCardinal(@OutBuf[4])^ := T0[1]; - PCardinal(@OutBuf[8])^ := T0[2]; - PCardinal(@OutBuf[12])^ := T0[3]; -end; - -procedure DecryptAES192(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; - var OutBuf: TCnAESBuffer); -var - T0, T1: array [0..3] of Cardinal; - W0, W1, W2, W3: Cardinal; -begin - // initializing - T0[0] := PCardinal(@InBuf[0])^ xor Key[48]; - T0[1] := PCardinal(@InBuf[4])^ xor Key[49]; - T0[2] := PCardinal(@InBuf[8])^ xor Key[50]; - T0[3] := PCardinal(@InBuf[12])^ xor Key[51]; - - // performing transformations 11 times - // round 1 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[44]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[45]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[46]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[47]; - // round 2 - W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; - W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; - W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; - W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; - W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; - W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; - W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; - W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; - // round 3 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; - // round 4 - W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; - W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; - W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; - W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; - W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; - W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; - W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; - W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; - // round 5 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; - // round 6 - W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; - W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; - W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; - W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; - W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; - W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; - W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; - W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; - // round 7 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; - // round 8 - W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; - W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; - W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; - W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; - W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; - W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; - W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; - W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; - // round 9 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; - // round 10 - W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; - W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; - W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; - W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; - W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; - W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; - W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; - W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; - // round 11 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; - // last round of transformations - W0 := LastInverseTable[Byte(T1[0])]; W1 := LastInverseTable[Byte(T1[3] shr 8)]; - W2 := LastInverseTable[Byte(T1[2] shr 16)]; W3 := LastInverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[0]; - W0 := LastInverseTable[Byte(T1[1])]; W1 := LastInverseTable[Byte(T1[0] shr 8)]; - W2 := LastInverseTable[Byte(T1[3] shr 16)]; W3 := LastInverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[1]; - W0 := LastInverseTable[Byte(T1[2])]; W1 := LastInverseTable[Byte(T1[1] shr 8)]; - W2 := LastInverseTable[Byte(T1[0] shr 16)]; W3 := LastInverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[2]; - W0 := LastInverseTable[Byte(T1[3])]; W1 := LastInverseTable[Byte(T1[2] shr 8)]; - W2 := LastInverseTable[Byte(T1[1] shr 16)]; W3 := LastInverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[3]; - - // finalizing - PCardinal(@OutBuf[0])^ := T0[0]; - PCardinal(@OutBuf[4])^ := T0[1]; - PCardinal(@OutBuf[8])^ := T0[2]; - PCardinal(@OutBuf[12])^ := T0[3]; -end; - -procedure DecryptAES256(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; - var OutBuf: TCnAESBuffer); -var - T0, T1: array [0..3] of Cardinal; - W0, W1, W2, W3: Cardinal; -begin - // initializing - T0[0] := PCardinal(@InBuf[0])^ xor Key[56]; - T0[1] := PCardinal(@InBuf[4])^ xor Key[57]; - T0[2] := PCardinal(@InBuf[8])^ xor Key[58]; - T0[3] := PCardinal(@InBuf[12])^ xor Key[59]; - - // performing transformations 13 times - // round 1 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[52]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[53]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[54]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[55]; - // round 2 - W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; - W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[48]; - W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; - W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[49]; - W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; - W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[50]; - W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; - W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[51]; - // round 3 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[44]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[45]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[46]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[47]; - // round 4 - W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; - W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; - W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; - W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; - W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; - W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; - W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; - W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; - // round 5 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; - // round 6 - W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; - W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; - W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; - W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; - W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; - W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; - W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; - W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; - // round 7 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; - // round 8 - W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; - W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; - W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; - W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; - W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; - W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; - W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; - W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; - // round 9 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; - // round 10 - W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; - W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; - W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; - W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; - W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; - W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; - W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; - W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; - // round 11 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; - // round 12 - W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; - W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; - W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; - W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; - W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; - W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; - W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; - W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; - // round 13 - W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; - W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; - T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; - W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; - W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; - T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; - W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; - W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; - T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; - W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; - W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; - T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; - // last round of transformations - W0 := LastInverseTable[Byte(T1[0])]; W1 := LastInverseTable[Byte(T1[3] shr 8)]; - W2 := LastInverseTable[Byte(T1[2] shr 16)]; W3 := LastInverseTable[Byte(T1[1] shr 24)]; - T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[0]; - W0 := LastInverseTable[Byte(T1[1])]; W1 := LastInverseTable[Byte(T1[0] shr 8)]; - W2 := LastInverseTable[Byte(T1[3] shr 16)]; W3 := LastInverseTable[Byte(T1[2] shr 24)]; - T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[1]; - W0 := LastInverseTable[Byte(T1[2])]; W1 := LastInverseTable[Byte(T1[1] shr 8)]; - W2 := LastInverseTable[Byte(T1[0] shr 16)]; W3 := LastInverseTable[Byte(T1[3] shr 24)]; - T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[2]; - W0 := LastInverseTable[Byte(T1[3])]; W1 := LastInverseTable[Byte(T1[2] shr 8)]; - W2 := LastInverseTable[Byte(T1[1] shr 16)]; W3 := LastInverseTable[Byte(T1[0] shr 24)]; - T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) - xor ((W3 shl 24) or (W3 shr 8))) xor Key[3]; - - // finalizing - PCardinal(@OutBuf[0])^ := T0[0]; - PCardinal(@OutBuf[4])^ := T0[1]; - PCardinal(@OutBuf[8])^ := T0[2]; - PCardinal(@OutBuf[12])^ := T0[3]; -end; - -// Stream Encryption Routines (ECB mode) - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; Dest: TStream); -begin - EncryptAES128StreamECB(Source, Count, Key, Dest); -end; - -procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); -begin - EncryptAES128StreamECBExpanded(Source, Count, ExpandedKey, Dest); -end; - -procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; Dest: TStream); -begin - EncryptAES192StreamECB(Source, Count, Key, Dest); -end; - -procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); -begin - EncryptAES192StreamECBExpanded(Source, Count, ExpandedKey, Dest); -end; - -procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; Dest: TStream); -begin - EncryptAES256StreamECB(Source, Count, Key, Dest); -end; - -procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); -begin - EncryptAES256StreamECBExpanded(Source, Count, ExpandedKey, Dest); -end; - -{$ENDIF} - -procedure EncryptAES128StreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey128; -begin - ExpandAESKeyForEncryption128(Key, ExpandedKey); - EncryptAES128StreamECBExpanded(Source, Count, ExpandedKey, Dest); -end; - -procedure EncryptAES192StreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey192; -begin - ExpandAESKeyForEncryption192(Key, ExpandedKey); - EncryptAES192StreamECBExpanded(Source, Count, ExpandedKey, Dest); -end; - -procedure EncryptAES256StreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey256; -begin - ExpandAESKeyForEncryption256(Key, ExpandedKey); - EncryptAES256StreamECBExpanded(Source, Count, ExpandedKey, Dest); -end; - -procedure EncryptAES128StreamECBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); -var - TempIn, TempOut: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - EncryptAES128(TempIn, ExpandedKey, TempOut); - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESReadError); - FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); - EncryptAES128(TempIn, ExpandedKey, TempOut); - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - end; -end; - -procedure EncryptAES192StreamECBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); -var - TempIn, TempOut: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - EncryptAES192(TempIn, ExpandedKey, TempOut); - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESReadError); - FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); - EncryptAES192(TempIn, ExpandedKey, TempOut); - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - end; -end; - -procedure EncryptAES256StreamECBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); -var - TempIn, TempOut: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - EncryptAES256(TempIn, ExpandedKey, TempOut); - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESReadError); - FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); - EncryptAES256(TempIn, ExpandedKey, TempOut); - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - end; -end; - -// Stream Decryption Routines (ECB mode) - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; Dest: TStream); -begin - DecryptAES128StreamECB(Source, Count, Key, Dest); -end; - -procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); -begin - DecryptAES128StreamECBExpanded(Source, Count, ExpandedKey, Dest); -end; - -procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; Dest: TStream); -begin - DecryptAES192StreamECB(Source, Count, Key, Dest); -end; - -procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); -begin - DecryptAES192StreamECBExpanded(Source, Count, ExpandedKey, Dest); -end; - -procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; Dest: TStream); -begin - DecryptAES256StreamECB(Source, Count, Key, Dest); -end; - -procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); -begin - DecryptAES256StreamECBExpanded(Source, Count, ExpandedKey, Dest); -end; - -{$ENDIF} - -procedure DecryptAES128StreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey128; -begin - ExpandAESKeyForDecryption128Expanded(Key, ExpandedKey); - DecryptAES128StreamECBExpanded(Source, Count, ExpandedKey, Dest); -end; - -procedure DecryptAES128StreamECBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); -var - TempIn, TempOut: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - if (Count mod SizeOf(TCnAESBuffer)) > 0 then - raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - DecryptAES128(TempIn, ExpandedKey, TempOut); - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - Dec(Count, SizeOf(TCnAESBuffer)); - end; -end; - -procedure DecryptAES192StreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey192; -begin - ExpandAESKeyForDecryption192Expanded(Key, ExpandedKey); - DecryptAES192StreamECBExpanded(Source, Count, ExpandedKey, Dest); -end; - -procedure DecryptAES192StreamECBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); -var - TempIn, TempOut: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - if (Count mod SizeOf(TCnAESBuffer)) > 0 then - raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - DecryptAES192(TempIn, ExpandedKey, TempOut); - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - Dec(Count, SizeOf(TCnAESBuffer)); - end; -end; - -procedure DecryptAES256StreamECB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey256; -begin - ExpandAESKeyForDecryption256Expanded(Key, ExpandedKey); - DecryptAES256StreamECBExpanded(Source, Count, ExpandedKey, Dest); -end; - -procedure DecryptAES256StreamECBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); -var - TempIn, TempOut: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - if (Count mod SizeOf(TCnAESBuffer)) > 0 then - raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - DecryptAES256(TempIn, ExpandedKey, TempOut); - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - Dec(Count, SizeOf(TCnAESBuffer)); - end; -end; - -// Stream Encryption Routines (CBC mode) - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -begin - EncryptAES128StreamCBC(Source, Count, Key, InitVector, Dest); -end; - -procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - EncryptAES128StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -begin - EncryptAES192StreamCBC(Source, Count, Key, InitVector, Dest); -end; - -procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - EncryptAES192StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -begin - EncryptAES256StreamCBC(Source, Count, Key, InitVector, Dest); -end; - -procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - EncryptAES256StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -{$ENDIF} - -procedure EncryptAES128StreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey128; -begin - ExpandAESKeyForEncryption128(Key, ExpandedKey); - EncryptAES128StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure EncryptAES128StreamCBCExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut, Vector: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - Vector := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); // Ҫÿһ鶼 - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; // ԭʼ IV - EncryptAES128(TempIn, ExpandedKey, TempOut); // ټ - Done := Dest.Write(TempOut, SizeOf(TempOut)); // д - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - Vector := TempOut; // ݴԭʼ IV һʹ - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESReadError); - FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; - EncryptAES128(TempIn, ExpandedKey, TempOut); - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - end; -end; - -procedure EncryptAES192StreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey192; -begin - ExpandAESKeyForEncryption192(Key, ExpandedKey); - EncryptAES192StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure EncryptAES192StreamCBCExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut, Vector: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - Vector := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; - EncryptAES192(TempIn, ExpandedKey, TempOut); - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - Vector := TempOut; - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESReadError); - FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; - EncryptAES192(TempIn, ExpandedKey, TempOut); - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - end; -end; - -procedure EncryptAES256StreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey256; -begin - ExpandAESKeyForEncryption256(Key, ExpandedKey); - EncryptAES256StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure EncryptAES256StreamCBCExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut, Vector: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - Vector := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; - EncryptAES256(TempIn, ExpandedKey, TempOut); - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - Vector := TempOut; - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESReadError); - FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; - EncryptAES256(TempIn, ExpandedKey, TempOut); - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - end; -end; - -// Stream Decryption Routines (CBC mode) - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -begin - DecryptAES128StreamCBC(Source, Count, Key, InitVector, Dest); -end; - -procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - DecryptAES128StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -begin - DecryptAES192StreamCBC(Source, Count, Key, InitVector, Dest); -end; - -procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - DecryptAES192StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -begin - DecryptAES256StreamCBC(Source, Count, Key, InitVector, Dest); -end; - -procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - DecryptAES256StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -{$ENDIF} - -procedure DecryptAES128StreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey128; -begin - ExpandAESKeyForDecryption128Expanded(Key, ExpandedKey); - DecryptAES128StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure DecryptAES128StreamCBCExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut: TCnAESBuffer; - Vector1, Vector2: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - if (Count mod SizeOf(TCnAESBuffer)) > 0 then - raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); - Vector1 := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError(SCnErrorAESReadError); - Vector2 := TempIn; - DecryptAES128(TempIn, ExpandedKey, TempOut); - PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; - PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; - PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@Vector1[8])^; - PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@Vector1[12])^; - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError(SCnErrorAESWriteError); - Vector1 := Vector2; - Dec(Count, SizeOf(TCnAESBuffer)); - end; -end; - -procedure DecryptAES192StreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey192; -begin - ExpandAESKeyForDecryption192Expanded(Key, ExpandedKey); - DecryptAES192StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure DecryptAES192StreamCBCExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut: TCnAESBuffer; - Vector1, Vector2: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - if (Count mod SizeOf(TCnAESBuffer)) > 0 then - raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); - Vector1 := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError(SCnErrorAESReadError); - Vector2 := TempIn; - DecryptAES192(TempIn, ExpandedKey, TempOut); - PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; - PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; - PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@Vector1[8])^; - PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@Vector1[12])^; - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError(SCnErrorAESWriteError); - Vector1 := Vector2; - Dec(Count, SizeOf(TCnAESBuffer)); - end; -end; - -procedure DecryptAES256StreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey256; -begin - ExpandAESKeyForDecryption256Expanded(Key, ExpandedKey); - DecryptAES256StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure DecryptAES256StreamCBCExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut: TCnAESBuffer; - Vector1, Vector2: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - if (Count mod SizeOf(TCnAESBuffer)) > 0 then - raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); // CBC Ϊ AES ֿܲģԱ - Vector1 := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError(SCnErrorAESReadError); - Vector2 := TempIn; - DecryptAES256(TempIn, ExpandedKey, TempOut); // Ƚ - PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; // ܺݺ Iv õ - PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; - PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@Vector1[8])^; - PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@Vector1[12])^; - Done := Dest.Write(TempOut, SizeOf(TempOut)); // дȥ - if Done < SizeOf(TempOut) then - raise EStreamError(SCnErrorAESWriteError); - Vector1 := Vector2; // ȡ Iv Ϊһκͽ - Dec(Count, SizeOf(TCnAESBuffer)); - end; -end; - -// Stream Encryption Routines (CFB mode) - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -begin - EncryptAES128StreamCFB(Source, Count, Key, InitVector, Dest); -end; - -procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - EncryptAES128StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -begin - EncryptAES192StreamCFB(Source, Count, Key, InitVector, Dest); -end; - -procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - EncryptAES192StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -begin - EncryptAES256StreamCFB(Source, Count, Key, InitVector, Dest); -end; - -procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - EncryptAES256StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -{$ENDIF} - -procedure EncryptAES128StreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey128; -begin - ExpandAESKeyForEncryption128(Key, ExpandedKey); - EncryptAES128StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure EncryptAES128StreamCFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut, Vector: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - Vector := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - EncryptAES128(Vector, ExpandedKey, TempOut); // Key ȼ Iv - PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ - PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempOut, SizeOf(TempOut)); // ĽдĽ - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - Vector := TempOut; // Ľȡ Iv һּ - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESReadError); - EncryptAES128(Vector, ExpandedKey, TempOut); - PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; - PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempOut, Count); // дֻijȵIJ֣ - if Done < Count then - raise EStreamError.Create(SCnErrorAESWriteError); - end; -end; - -procedure EncryptAES192StreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey192; -begin - ExpandAESKeyForEncryption192(Key, ExpandedKey); - EncryptAES192StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure EncryptAES192StreamCFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut, Vector: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - Vector := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - EncryptAES192(Vector, ExpandedKey, TempOut); - PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; - PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - Vector := TempOut; - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESReadError); - EncryptAES192(Vector, ExpandedKey, TempOut); - PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; - PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempOut, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESWriteError); - end; -end; - -procedure EncryptAES256StreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey256; -begin - ExpandAESKeyForEncryption256(Key, ExpandedKey); - EncryptAES256StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure EncryptAES256StreamCFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut, Vector: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - Vector := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - EncryptAES256(Vector, ExpandedKey, TempOut); - PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; - PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorAESWriteError); - Vector := TempOut; - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESReadError); - EncryptAES256(Vector, ExpandedKey, TempOut); - PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; - PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempOut, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESWriteError); - end; -end; - -// Stream Decryption Routines (CFB mode) - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -begin - DecryptAES128StreamCFB(Source, Count, Key, InitVector, Dest); -end; - -procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - DecryptAES128StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -begin - DecryptAES192StreamCFB(Source, Count, Key, InitVector, Dest); -end; - -procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - DecryptAES192StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -begin - DecryptAES256StreamCFB(Source, Count, Key, InitVector, Dest); -end; - -procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - DecryptAES256StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -{$ENDIF} - -procedure DecryptAES128StreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey128; -begin - ExpandAESKeyForEncryption128(Key, ExpandedKey); - DecryptAES128StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure DecryptAES128StreamCFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut: TCnAESBuffer; - Vector: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - // CFB Ϊ AES ֿܲĶ򣨳Ŀɶ - Vector := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); // - if Done < SizeOf(TempIn) then - raise EStreamError(SCnErrorAESReadError); - EncryptAES128(Vector, ExpandedKey, TempOut); // Iv ȼܡעǼܣǽܣ - PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; // ܺݺõ - PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; - PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; - PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; - Done := Dest.Write(TempOut, SizeOf(TempOut)); // дȥ - if Done < SizeOf(TempOut) then - raise EStreamError(SCnErrorAESWriteError); - Vector := TempIn; // ȡ Iv Ϊһμ - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then // һ鲻Ϊ - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError(SCnErrorAESReadError); - EncryptAES128(Vector, ExpandedKey, TempOut); - PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; // ܺݺõ - PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; - PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; - PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; - Done := Dest.Write(TempOut, Count); // дȥ - if Done < Count then - raise EStreamError(SCnErrorAESWriteError); - end; -end; - -procedure DecryptAES192StreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey192; -begin - ExpandAESKeyForEncryption192(Key, ExpandedKey); - DecryptAES192StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure DecryptAES192StreamCFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut: TCnAESBuffer; - Vector: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - Vector := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError(SCnErrorAESReadError); - EncryptAES192(Vector, ExpandedKey, TempOut); - PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; - PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; - PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; - PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError(SCnErrorAESWriteError); - Vector := TempIn; - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError(SCnErrorAESReadError); - EncryptAES192(Vector, ExpandedKey, TempOut); - PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; - PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; - PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; - PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; - Done := Dest.Write(TempOut, Count); - if Done < Count then - raise EStreamError(SCnErrorAESWriteError); - end; -end; - -procedure DecryptAES256StreamCFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey256; -begin - ExpandAESKeyForEncryption256(Key, ExpandedKey); - DecryptAES256StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure DecryptAES256StreamCFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut: TCnAESBuffer; - Vector: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - Vector := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError(SCnErrorAESReadError); - EncryptAES256(Vector, ExpandedKey, TempOut); - PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; - PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; - PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; - PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError(SCnErrorAESWriteError); - Vector := TempIn; - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError(SCnErrorAESReadError); - EncryptAES256(Vector, ExpandedKey, TempOut); - PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; - PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; - PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; - PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; - Done := Dest.Write(TempOut, Count); - if Done < Count then - raise EStreamError(SCnErrorAESWriteError); - end; -end; - -// Stream Encryption Routines (OFB mode) - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -begin - EncryptAES128StreamOFB(Source, Count, Key, InitVector, Dest); -end; - -procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - EncryptAES128StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -begin - EncryptAES192StreamOFB(Source, Count, Key, InitVector, Dest); -end; - -procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - EncryptAES192StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -begin - EncryptAES256StreamOFB(Source, Count, Key, InitVector, Dest); -end; - -procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - EncryptAES256StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -{$ENDIF} - -procedure EncryptAES128StreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey128; -begin - ExpandAESKeyForEncryption128(Key, ExpandedKey); - EncryptAES128StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure EncryptAES128StreamOFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut, Vector: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - Vector := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - EncryptAES128(Vector, ExpandedKey, TempOut); // Key ȼ Iv - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESWriteError); - Vector := TempOut; // ܽȡ Iv һּܣעⲻ - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESReadError); - EncryptAES128(Vector, ExpandedKey, TempOut); - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ - if Done < Count then - raise EStreamError.Create(SCnErrorAESWriteError); - end; -end; - -procedure EncryptAES192StreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey192; -begin - ExpandAESKeyForEncryption192(Key, ExpandedKey); - EncryptAES192StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure EncryptAES192StreamOFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut, Vector: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - Vector := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - EncryptAES192(Vector, ExpandedKey, TempOut); - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESWriteError); - Vector := TempOut; - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESReadError); - EncryptAES192(Vector, ExpandedKey, TempOut); - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESWriteError); - end; -end; - -procedure EncryptAES256StreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey256; -begin - ExpandAESKeyForEncryption256(Key, ExpandedKey); - EncryptAES256StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure EncryptAES256StreamOFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut, Vector: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - Vector := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - EncryptAES256(Vector, ExpandedKey, TempOut); - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESWriteError); - Vector := TempOut; - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESReadError); - EncryptAES256(Vector, ExpandedKey, TempOut); - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESWriteError); - end; -end; - -// Stream Decryption Routines (OFB mode) - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -begin - DecryptAES128StreamOFB(Source, Count, Key, InitVector, Dest); -end; - -procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - DecryptAES128StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -begin - DecryptAES192StreamOFB(Source, Count, Key, InitVector, Dest); -end; - -procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - DecryptAES192StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -begin - DecryptAES256StreamOFB(Source, Count, Key, InitVector, Dest); -end; - -procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -begin - DecryptAES256StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -{$ENDIF} - -procedure DecryptAES128StreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey128; -begin - ExpandAESKeyForEncryption128(Key, ExpandedKey); - DecryptAES128StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure DecryptAES128StreamOFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut: TCnAESBuffer; - Vector: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - // OFB Ϊ AES ֿܲĶ򣨳Ŀɶ - Vector := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); // - if Done < SizeOf(TempIn) then - raise EStreamError(SCnErrorAESReadError); - EncryptAES128(Vector, ExpandedKey, TempOut); // Iv ȼܡעǼܣǽܣ - PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; // ܺݺõ - PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; - Done := Dest.Write(TempIn, SizeOf(TempIn)); // дȥ - if Done < SizeOf(TempIn) then - raise EStreamError(SCnErrorAESWriteError); - Vector := TempOut; // ȡ Iv Ϊһǰ - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then // һ鲻Ϊ - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError(SCnErrorAESReadError); - EncryptAES128(Vector, ExpandedKey, TempOut); - PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; // ܺݺõ - PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; - Done := Dest.Write(TempIn, Count); // дȥ - if Done < Count then - raise EStreamError(SCnErrorAESWriteError); - end; -end; - -procedure DecryptAES192StreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey192; -begin - ExpandAESKeyForEncryption192(Key, ExpandedKey); - DecryptAES192StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure DecryptAES192StreamOFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut: TCnAESBuffer; - Vector: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - Vector := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError(SCnErrorAESReadError); - EncryptAES192(Vector, ExpandedKey, TempOut); - PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; - Done := Dest.Write(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError(SCnErrorAESWriteError); - Vector := TempOut; - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError(SCnErrorAESReadError); - EncryptAES192(Vector, ExpandedKey, TempOut); - PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; - Done := Dest.Write(TempIn, Count); - if Done < Count then - raise EStreamError(SCnErrorAESWriteError); - end; -end; - -procedure DecryptAES256StreamOFB(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey256; -begin - ExpandAESKeyForEncryption256(Key, ExpandedKey); - DecryptAES256StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); -end; - -procedure DecryptAES256StreamOFBExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; - Dest: TStream); -var - TempIn, TempOut: TCnAESBuffer; - Vector: TCnAESBuffer; - Done: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - Vector := InitVector; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError(SCnErrorAESReadError); - EncryptAES256(Vector, ExpandedKey, TempOut); - PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; - Done := Dest.Write(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError(SCnErrorAESWriteError); - Vector := TempOut; - Dec(Count, SizeOf(TCnAESBuffer)); - end; - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError(SCnErrorAESReadError); - EncryptAES256(Vector, ExpandedKey, TempOut); - PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; - Done := Dest.Write(TempIn, Count); - if Done < Count then - raise EStreamError(SCnErrorAESWriteError); - end; -end; - -// Stream Encryption Routines (CTR mode) - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -begin - EncryptAES128StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); -end; - -procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -begin - EncryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); -end; - -procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -begin - EncryptAES192StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); -end; - -procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -begin - EncryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); -end; - -procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -begin - EncryptAES256StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); -end; - -procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -begin - EncryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); -end; - -{$ENDIF} - -procedure EncryptAES128StreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey128; -begin - ExpandAESKeyForEncryption128(Key, ExpandedKey); - EncryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); -end; - -procedure EncryptAES128StreamCTRExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -var - TempIn, TempOut, Vector: TCnAESBuffer; - Done, Cnt, T: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - Cnt := 1; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - - Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); - Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); - T := UInt32HostToNetwork(Cnt); - Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); - - EncryptAES128(Vector, ExpandedKey, TempOut); // Key ȼƴ Iv - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESWriteError); - - Inc(Cnt); // һ - Dec(Count, SizeOf(TCnAESBuffer)); - end; - - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESReadError); - - Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); - Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); - T := UInt32HostToNetwork(Cnt); - Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); - - EncryptAES128(Vector, ExpandedKey, TempOut); - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ - if Done < Count then - raise EStreamError.Create(SCnErrorAESWriteError); - end; -end; - -procedure EncryptAES192StreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey192; -begin - ExpandAESKeyForEncryption192(Key, ExpandedKey); - EncryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); -end; - -procedure EncryptAES192StreamCTRExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -var - TempIn, TempOut, Vector: TCnAESBuffer; - Done, Cnt, T: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - Cnt := 1; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - - Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); - Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); - T := UInt32HostToNetwork(Cnt); - Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); - - EncryptAES192(Vector, ExpandedKey, TempOut); // Key ȼƴ Iv - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESWriteError); - - Inc(Cnt); // һ - Dec(Count, SizeOf(TCnAESBuffer)); - end; - - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESReadError); - - Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); - Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); - T := UInt32HostToNetwork(Cnt); - Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); - - EncryptAES192(Vector, ExpandedKey, TempOut); - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ - if Done < Count then - raise EStreamError.Create(SCnErrorAESWriteError); - end; -end; - -procedure EncryptAES256StreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey256; -begin - ExpandAESKeyForEncryption256(Key, ExpandedKey); - EncryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); -end; - -procedure EncryptAES256StreamCTRExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -var - TempIn, TempOut, Vector: TCnAESBuffer; - Done, Cnt, T: Cardinal; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else Count := Min(Count, Source.Size - Source.Position); - if Count = 0 then Exit; - - Cnt := 1; - while Count >= SizeOf(TCnAESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESReadError); - - Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); - Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); - T := UInt32HostToNetwork(Cnt); - Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); - - EncryptAES256(Vector, ExpandedKey, TempOut); // Key ȼƴ Iv - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorAESWriteError); - - Inc(Cnt); // һ - Dec(Count, SizeOf(TCnAESBuffer)); - end; - - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorAESReadError); - - Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); - Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); - T := UInt32HostToNetwork(Cnt); - Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); - - EncryptAES256(Vector, ExpandedKey, TempOut); - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; - PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; - PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; - Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ - if Done < Count then - raise EStreamError.Create(SCnErrorAESWriteError); - end; -end; - -// Stream Decryption Routines (CTR mode) - -{$IFNDEF BCB5OR6} - -// C++Builder overload ⣬ Delphi ¿ -procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -begin - DecryptAES128StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); -end; - -procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -begin - DecryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); -end; - -procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -begin - DecryptAES192StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); -end; - -procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -begin - DecryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); -end; - -procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -begin - DecryptAES256StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); -end; - -procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -begin - DecryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); -end; - -{$ENDIF} - -procedure DecryptAES128StreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey128; -begin - ExpandAESKeyForEncryption128(Key, ExpandedKey); - DecryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); -end; - -procedure DecryptAES128StreamCTRExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -begin - EncryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); -end; - -procedure DecryptAES192StreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey192; -begin - ExpandAESKeyForEncryption192(Key, ExpandedKey); - DecryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); -end; - -procedure DecryptAES192StreamCTRExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -begin - EncryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); -end; - -procedure DecryptAES256StreamCTR(Source: TStream; Count: Cardinal; - const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -var - ExpandedKey: TCnAESExpandedKey256; -begin - ExpandAESKeyForEncryption256(Key, ExpandedKey); - DecryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); -end; - -procedure DecryptAES256StreamCTRExpanded(Source: TStream; Count: Cardinal; - const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; - const InitVector: TCnAESCTRIv; Dest: TStream); -begin - EncryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); -end; - -// AES ECB ַתʮ -function AESEncryptEcbStrToHex(Value: AnsiString; Key: AnsiString; - KeyBit: TCnKeyBitType): AnsiString; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; -begin - Result := ''; - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - SS.Write(PAnsiChar(@Value[1])^, Length(Value)); - SS.Position := 0; - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - EncryptAES128StreamECB(SS, 0, AESKey128, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - EncryptAES192StreamECB(SS, 0, AESKey192, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - EncryptAES256StreamECB(SS, 0, AESKey256, DS); - end; - end; - - Result := AnsiString(DataToHex(DS.Memory, DS.Size)); - finally - SS.Free; - DS.Free; - end; -end; - -// AES ECB ʮַ -function AESDecryptEcbStrFromHex(const HexStr: AnsiString; Key: AnsiString; - KeyBit: TCnKeyBitType): AnsiString; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; - Tmp: TBytes; -begin - Result := ''; - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - Tmp := HexToBytes(string(HexStr)); - SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); - SS.Position := 0; - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - DecryptAES128StreamECB(SS, SS.Size - SS.Position, AESKey128, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - DecryptAES192StreamECB(SS, SS.Size - SS.Position, AESKey192, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - DecryptAES256StreamECB(SS, SS.Size - SS.Position, AESKey256, DS); - end; - end; - - SetLength(Result, DS.Size); - Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); - finally - SS.Free; - DS.Free; - end; -end; - -// AES CBC ַתʮ -function AESEncryptCbcStrToHex(Value: AnsiString; Key: AnsiString; - const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; -begin - Result := ''; - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - SS.Write(PAnsiChar(@Value[1])^, Length(Value)); - SS.Position := 0; - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - EncryptAES128StreamCBC(SS, 0, AESKey128, Iv, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - EncryptAES192StreamCBC(SS, 0, AESKey192, Iv, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - EncryptAES256StreamCBC(SS, 0, AESKey256, Iv, DS); - end; - end; - - Result := AnsiString(DataToHex(DS.Memory, DS.Size)); - finally - SS.Free; - DS.Free; - end; -end; - -// AES CBC ʮַ -function AESDecryptCbcStrFromHex(const HexStr: AnsiString; Key: AnsiString; - const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; - Tmp: TBytes; -begin - Result := ''; - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - Tmp := HexToBytes(string(HexStr)); - SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); - SS.Position := 0; - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - DecryptAES128StreamCBC(SS, SS.Size - SS.Position, AESKey128, Iv, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - DecryptAES192StreamCBC(SS, SS.Size - SS.Position, AESKey192, Iv, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - DecryptAES256StreamCBC(SS, SS.Size - SS.Position, AESKey256, Iv, DS); - end; - end; - - SetLength(Result, DS.Size); - Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); - finally - SS.Free; - DS.Free; - end; -end; - -// AES CFB ģʽַתʮ -function AESEncryptCfbStrToHex(Value: AnsiString; Key: AnsiString; - const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; -begin - Result := ''; - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - SS.Write(PAnsiChar(@Value[1])^, Length(Value)); - SS.Position := 0; - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - EncryptAES128StreamCFB(SS, 0, AESKey128, Iv, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - EncryptAES192StreamCFB(SS, 0, AESKey192, Iv, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - EncryptAES256StreamCFB(SS, 0, AESKey256, Iv, DS); - end; - end; - - Result := AnsiString(DataToHex(DS.Memory, DS.Size)); - finally - SS.Free; - DS.Free; - end; -end; - -// AES CFB ʮַ -function AESDecryptCfbStrFromHex(const HexStr: AnsiString; Key: AnsiString; - const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; - Tmp: TBytes; -begin - Result := ''; - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - Tmp := HexToBytes(string(HexStr)); - SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); - SS.Position := 0; - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - DecryptAES128StreamCFB(SS, SS.Size - SS.Position, AESKey128, Iv, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - DecryptAES192StreamCFB(SS, SS.Size - SS.Position, AESKey192, Iv, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - DecryptAES256StreamCFB(SS, SS.Size - SS.Position, AESKey256, Iv, DS); - end; - end; - - SetLength(Result, DS.Size); - Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); - finally - SS.Free; - DS.Free; - end; -end; - -// AES OFB ģʽַתʮ -function AESEncryptOfbStrToHex(Value: AnsiString; Key: AnsiString; - const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; -begin - Result := ''; - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - SS.Write(PAnsiChar(@Value[1])^, Length(Value)); - SS.Position := 0; - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - EncryptAES128StreamOFB(SS, 0, AESKey128, Iv, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - EncryptAES192StreamOFB(SS, 0, AESKey192, Iv, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - EncryptAES256StreamOFB(SS, 0, AESKey256, Iv, DS); - end; - end; - - Result := AnsiString(DataToHex(DS.Memory, DS.Size)); - finally - SS.Free; - DS.Free; - end; -end; - -// AES OFB ʮַ -function AESDecryptOfbStrFromHex(const HexStr: AnsiString; Key: AnsiString; - const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; - Tmp: TBytes; -begin - Result := ''; - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - Tmp := HexToBytes(string(HexStr)); - SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); - SS.Position := 0; - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - DecryptAES128StreamOFB(SS, SS.Size - SS.Position, AESKey128, Iv, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - DecryptAES192StreamOFB(SS, SS.Size - SS.Position, AESKey192, Iv, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - DecryptAES256StreamOFB(SS, SS.Size - SS.Position, AESKey256, Iv, DS); - end; - end; - - SetLength(Result, DS.Size); - Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); - finally - SS.Free; - DS.Free; - end; -end; - -// AES CTR ģʽַתʮ -function AESEncryptCtrStrToHex(Value: AnsiString; Key: AnsiString; - const Nonce: TCnAESCTRNonce; const Iv: TCnAESCTRIv; KeyBit: TCnKeyBitType): AnsiString; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; -begin - Result := ''; - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - SS.Write(PAnsiChar(@Value[1])^, Length(Value)); - SS.Position := 0; - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - EncryptAES128StreamCTR(SS, 0, AESKey128, Nonce, Iv, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - EncryptAES192StreamCTR(SS, 0, AESKey192, Nonce, Iv, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - EncryptAES256StreamCTR(SS, 0, AESKey256, Nonce, Iv, DS); - end; - end; - - Result := AnsiString(DataToHex(DS.Memory, DS.Size)); - finally - SS.Free; - DS.Free; - end; -end; - -// AES CTR ʮַ -function AESDecryptCtrStrFromHex(const HexStr: AnsiString; Key: AnsiString; - const Nonce: TCnAESCTRNonce; const Iv: TCnAESCTRIv; KeyBit: TCnKeyBitType): AnsiString; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; - Tmp: TBytes; -begin - Result := ''; - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - Tmp := HexToBytes(string(HexStr)); - SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); - SS.Position := 0; - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - DecryptAES128StreamCTR(SS, SS.Size - SS.Position, AESKey128, Nonce, Iv, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - DecryptAES192StreamCTR(SS, SS.Size - SS.Position, AESKey192, Nonce, Iv, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - DecryptAES256StreamCTR(SS, SS.Size - SS.Position, AESKey256, Nonce, Iv, DS); - end; - end; - - SetLength(Result, DS.Size); - Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); - finally - SS.Free; - DS.Free; - end; -end; - -// AES ECB ģʽֽ -function AESEncryptEcbBytes(Value, Key: TBytes; KeyBit: TCnKeyBitType): TBytes; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; -begin - if Length(Value) <= 0 then - begin - Result := nil; - Exit; - end; - - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - SS.Write(PAnsiChar(@Value[0])^, Length(Value)); - SS.Position := 0; - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - EncryptAES128StreamECB(SS, 0, AESKey128, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - EncryptAES192StreamECB(SS, 0, AESKey192, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - EncryptAES256StreamECB(SS, 0, AESKey256, DS); - end; - end; - - SetLength(Result, DS.Size); - DS.Position := 0; - DS.Read(Result[0], DS.Size); - finally - SS.Free; - DS.Free; - end; -end; - -// AES ECB ģʽֽ -function AESDecryptEcbBytes(Value, Key: TBytes; KeyBit: TCnKeyBitType): TBytes; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; -begin - if Length(Value) <= 0 then - begin - Result := nil; - Exit; - end; - - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - SS.Write(PAnsiChar(@Value[0])^, Length(Value)); - SS.Position := 0; - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - DecryptAES128StreamECB(SS, SS.Size - SS.Position, AESKey128, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - DecryptAES192StreamECB(SS, SS.Size - SS.Position, AESKey192, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - DecryptAES256StreamECB(SS, SS.Size - SS.Position, AESKey256, DS); - end; - end; - - SetLength(Result, DS.Size); - DS.Position := 0; - DS.Read(Result[0], DS.Size); - finally - SS.Free; - DS.Free; - end; -end; - -// AES CBC ģʽֽ -function AESEncryptCbcBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; - AESIv: TCnAESBuffer; -begin - if Length(Value) <= 0 then - begin - Result := nil; - Exit; - end; - - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - SS.Write(PAnsiChar(@Value[0])^, Length(Value)); - SS.Position := 0; - - FillChar(AESIv, SizeOF(AESIv), 0); - Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - EncryptAES128StreamCBC(SS, 0, AESKey128, AESIv, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - EncryptAES192StreamCBC(SS, 0, AESKey192, AESIv, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - EncryptAES256StreamCBC(SS, 0, AESKey256, AESIv, DS); - end; - end; - - SetLength(Result, DS.Size); - DS.Position := 0; - DS.Read(Result[0], DS.Size); - finally - SS.Free; - DS.Free; - end; -end; - -// AES CBC ģʽֽ -function AESDecryptCbcBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; - AESIv: TCnAESBuffer; -begin - if Length(Value) <= 0 then - begin - Result := nil; - Exit; - end; - - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - SS.Write(PAnsiChar(@Value[0])^, Length(Value)); - SS.Position := 0; - - FillChar(AESIv, SizeOF(AESIv), 0); - Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - DecryptAES128StreamCBC(SS, SS.Size - SS.Position, AESKey128, AESIv, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - DecryptAES192StreamCBC(SS, SS.Size - SS.Position, AESKey192, AESIv, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - DecryptAES256StreamCBC(SS, SS.Size - SS.Position, AESKey256, AESIv, DS); - end; - end; - - SetLength(Result, DS.Size); - DS.Position := 0; - DS.Read(Result[0], DS.Size); - finally - SS.Free; - DS.Free; - end; -end; - -// AES CFB ģʽֽ -function AESEncryptCfbBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; - AESIv: TCnAESBuffer; -begin - if Length(Value) <= 0 then - begin - Result := nil; - Exit; - end; - - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - SS.Write(PAnsiChar(@Value[0])^, Length(Value)); - SS.Position := 0; - - FillChar(AESIv, SizeOF(AESIv), 0); - Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - EncryptAES128StreamCFB(SS, 0, AESKey128, AESIv, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - EncryptAES192StreamCFB(SS, 0, AESKey192, AESIv, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - EncryptAES256StreamCFB(SS, 0, AESKey256, AESIv, DS); - end; - end; - - SetLength(Result, DS.Size); - DS.Position := 0; - DS.Read(Result[0], DS.Size); - finally - SS.Free; - DS.Free; - end; -end; - -// AES CFB ģʽֽ -function AESDecryptCfbBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; - AESIv: TCnAESBuffer; -begin - if Length(Value) <= 0 then - begin - Result := nil; - Exit; - end; - - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - SS.Write(PAnsiChar(@Value[0])^, Length(Value)); - SS.Position := 0; - - FillChar(AESIv, SizeOF(AESIv), 0); - Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - DecryptAES128StreamCFB(SS, SS.Size - SS.Position, AESKey128, AESIv, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - DecryptAES192StreamCFB(SS, SS.Size - SS.Position, AESKey192, AESIv, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - DecryptAES256StreamCFB(SS, SS.Size - SS.Position, AESKey256, AESIv, DS); - end; - end; - - SetLength(Result, DS.Size); - DS.Position := 0; - DS.Read(Result[0], DS.Size); - finally - SS.Free; - DS.Free; - end; -end; - -// AES OFB ģʽֽ -function AESEncryptOfbBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; - AESIv: TCnAESBuffer; -begin - if Length(Value) <= 0 then - begin - Result := nil; - Exit; - end; - - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - SS.Write(PAnsiChar(@Value[0])^, Length(Value)); - SS.Position := 0; - - FillChar(AESIv, SizeOF(AESIv), 0); - Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - EncryptAES128StreamOFB(SS, 0, AESKey128, AESIv, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - EncryptAES192StreamOFB(SS, 0, AESKey192, AESIv, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - EncryptAES256StreamOFB(SS, 0, AESKey256, AESIv, DS); - end; - end; - - SetLength(Result, DS.Size); - DS.Position := 0; - DS.Read(Result[0], DS.Size); - finally - SS.Free; - DS.Free; - end; -end; - -// AES OFB ģʽֽ -function AESDecryptOfbBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; - AESIv: TCnAESBuffer; -begin - if Length(Value) <= 0 then - begin - Result := nil; - Exit; - end; - - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - SS.Write(PAnsiChar(@Value[0])^, Length(Value)); - SS.Position := 0; - - FillChar(AESIv, SizeOF(AESIv), 0); - Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - DecryptAES128StreamOFB(SS, SS.Size - SS.Position, AESKey128, AESIv, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - DecryptAES192StreamOFB(SS, SS.Size - SS.Position, AESKey192, AESIv, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - DecryptAES256StreamOFB(SS, SS.Size - SS.Position, AESKey256, AESIv, DS); - end; - end; - - SetLength(Result, DS.Size); - DS.Position := 0; - DS.Read(Result[0], DS.Size); - finally - SS.Free; - DS.Free; - end; -end; - -// AES CTR ģʽֽ -function AESEncryptCtrBytes(Value, Key, Nonce, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; - AESIv: TCnAESCTRIv; - AESNonce: TCnAESCTRNonce; -begin - if Length(Value) <= 0 then - begin - Result := nil; - Exit; - end; - - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - SS.Write(PAnsiChar(@Value[0])^, Length(Value)); - SS.Position := 0; - - FillChar(AESIv, SizeOF(AESIv), 0); - Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); - - FillChar(AESNonce, SizeOF(AESNonce), 0); - Move(PAnsiChar(Nonce)^, AESNonce, Min(SizeOf(AESNonce), Length(Nonce))); - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - EncryptAES128StreamCTR(SS, 0, AESKey128, AESNonce, AESIv, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - EncryptAES192StreamCTR(SS, 0, AESKey192, AESNonce, AESIv, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - EncryptAES256StreamCTR(SS, 0, AESKey256, AESNonce, AESIv, DS); - end; - end; - - SetLength(Result, DS.Size); - DS.Position := 0; - DS.Read(Result[0], DS.Size); - finally - SS.Free; - DS.Free; - end; -end; - -// AES CTR ģʽֽ -function AESDecryptCtrBytes(Value, Key, Nonce, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; -var - SS, DS: TMemoryStream; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; - AESIv: TCnAESCTRIv; - AESNonce: TCnAESCTRNonce; -begin - if Length(Value) <= 0 then - begin - Result := nil; - Exit; - end; - - SS := nil; - DS := nil; - - try - SS := TMemoryStream.Create; - SS.Write(PAnsiChar(@Value[0])^, Length(Value)); - SS.Position := 0; - - FillChar(AESIv, SizeOF(AESIv), 0); - Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); - - FillChar(AESNonce, SizeOF(AESNonce), 0); - Move(PAnsiChar(Nonce)^, AESNonce, Min(SizeOf(AESNonce), Length(Nonce))); - DS := TMemoryStream.Create; - - case KeyBit of - kbt128: - begin - FillChar(AESKey128, SizeOf(AESKey128), 0); - Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); - DecryptAES128StreamCTR(SS, SS.Size - SS.Position, AESKey128, AESNonce, AESIv, DS); - end; - kbt192: - begin - FillChar(AESKey192, SizeOf(AESKey192), 0); - Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); - DecryptAES192StreamCTR(SS, SS.Size - SS.Position, AESKey192, AESNonce, AESIv, DS); - end; - kbt256: - begin - FillChar(AESKey256, SizeOf(AESKey256), 0); - Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); - DecryptAES256StreamCTR(SS, SS.Size - SS.Position, AESKey256, AESNonce, AESIv, DS); - end; - end; - - SetLength(Result, DS.Size); - DS.Position := 0; - DS.Read(Result[0], DS.Size); - finally - SS.Free; - DS.Free; - end; -end; - -// AES ECB ģʽֽ鲢תʮ -function AESEncryptEcbBytesToHex(Value, Key: TBytes; KeyBit: TCnKeyBitType): AnsiString; -begin - Result := AnsiString(BytesToHex(AESEncryptEcbBytes(Value, Key, KeyBit))); -end; - -// AES ECB ʮַֽ -function AESDecryptEcbBytesFromHex(const HexStr: AnsiString; Key: TBytes; - KeyBit: TCnKeyBitType): TBytes; -begin - Result := AESDecryptEcbBytes(HexToBytes(string(HexStr)), Key, KeyBit); -end; - -// AES CBC ģʽֽ鲢תʮ -function AESEncryptCbcBytesToHex(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): AnsiString; -begin - Result := AnsiString(BytesToHex(AESEncryptCbcBytes(Value, Key, Iv, KeyBit))); -end; - -// AES CBC ʮַֽ -function AESDecryptCbcBytesFromHex(const HexStr: AnsiString; Key, Iv: TBytes; - KeyBit: TCnKeyBitType): TBytes; -begin - Result := AESDecryptCbcBytes(HexToBytes(string(HexStr)), Key, Iv, KeyBit); -end; - -// AES CFB ģʽֽ鲢תʮ -function AESEncryptCfbBytesToHex(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): AnsiString; -begin - Result := AnsiString(BytesToHex(AESEncryptCfbBytes(Value, Key, Iv, KeyBit))); -end; - -// AES CFB ʮַֽ -function AESDecryptCfbBytesFromHex(const HexStr: AnsiString; Key, Iv: TBytes; - KeyBit: TCnKeyBitType): TBytes; -begin - Result := AESDecryptCfbBytes(HexToBytes(string(HexStr)), Key, Iv, KeyBit); -end; - -// AES OFB ģʽֽ鲢תʮ -function AESEncryptOfbBytesToHex(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): AnsiString; -begin - Result := AnsiString(BytesToHex(AESEncryptOfbBytes(Value, Key, Iv, KeyBit))); -end; - -// AES OFB ʮַֽ -function AESDecryptOfbBytesFromHex(const HexStr: AnsiString; Key, Iv: TBytes; - KeyBit: TCnKeyBitType): TBytes; -begin - Result := AESDecryptOfbBytes(HexToBytes(string(HexStr)), Key, Iv, KeyBit); -end; - -// AES CTR ģʽֽ鲢תʮ -function AESEncryptCtrBytesToHex(Value, Key, Nonce, Iv: TBytes; KeyBit: TCnKeyBitType): AnsiString; -begin - Result := AnsiString(BytesToHex(AESEncryptCtrBytes(Value, Key, Nonce, Iv, KeyBit))); -end; - -// AES CTR ʮַֽ -function AESDecryptCtrBytesFromHex(const HexStr: AnsiString; Key, Nonce, Iv: TBytes; - KeyBit: TCnKeyBitType): TBytes; -begin - Result := AESDecryptCtrBytes(HexToBytes(string(HexStr)), Key, Nonce, Iv, KeyBit); -end; - -end. - +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} +(******************************************************************************) +(* *) +(* Advanced Encryption Standard (AES) *) +(* *) +(* Copyright (c) 1998-2001 *) +(* EldoS, Alexander Ionov *) +(* *) +(******************************************************************************) + +unit CnAES; +{* |
+================================================================================
+* ƣ
+* ԪƣAES ԳƼӽ㷨ʵֵԪ
+* ԪߣCnPack  (master@cnpack.org)
+*            EldoS, Alexander Ionov ĵԪֲ书ܣԭаȨϢ
+*     עԪʵ AES 128/192/256 ԳƼӽ㷨ֿС̶ 16 ֽڣģʽ
+*           Ķ뷽ʽĩβ 0Ԫڲ֧ PKCS ȿ뷽ʽҪⲿ
+*           CnPemUtils.pas Ԫе PKCS ϵкԼӽݽж⴦
+*
+*           ߰汾 Delphi 뾡ʹ AnsiString 汾ĺʮƳ⣩
+*           ⲻַӰӽܽ
+*
+*           䣺Java Ĭϵ AES Ӧ˴ AES256
+*
+*           ⣬C++Builder 5/6 ¶ overload ĺʴжϴӶ
+*           ҵΣʱԪ˴ overload  Delphi ´ڣ
+*           ٷװ˲ֲͬĺ֧ C++Builder 5/6 ±С
+*
+*           ECB/CBC ǿģʽҪ롣CFB/OFB/CTR ĵģʽ뵽顣
+*
+*           ⣬CTR ģʽ RFC 3686 淶紫ݵ 4 ֽ Nonce8 ֽ
+*           ʼ4 ֽֽļƴ 16 ֽڵijʼ
+*            AES 㣬ӽܾΪĶ
+*
+* ƽ̨Delphi5 + Win 7
+* ޸ļ¼2024.07.25 V1.3
+*                CTR ģʽ֧֣ѭ RFC 3686 淶
+*           2024.05.26 V1.2
+*               䲿֧ C++Builder ĺ
+*           2022.06.21 V1.1
+*               뼸ֽ鵽ʮַ֮ļӽܺ
+*           2021.12.11 V1.2
+*                CFB/OFB ģʽ֧
+*           2019.04.15 V1.1
+*               ֧ Win32/Win64/MacOS
+*           2015.01.21 V1.0
+*               Ԫ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + Classes, SysUtils, CnNative; + +const + CN_AES_BLOCKSIZE = 16; + {* AES ķܿСλ٣Ϊ 16 ֽ} + +type + TCnKeyBitType = (kbt128, kbt192, kbt256); + {* AES λ16 ֽڡ24 ֽں 32 ֽ} + + ECnAESException = class(Exception); + {* AES 쳣} + + TCnAESBuffer = array [0..15] of Byte; + {* AES ӽܿ 16 ֽ} + + TCnAESKey128 = array [0..15] of Byte; + {* AES128 Կṹ16 ֽ} + + TCnAESKey192 = array [0..23] of Byte; + {* AES192 Կṹ24 ֽ} + + TCnAESKey256 = array [0..31] of Byte; + {* AES256 Կṹ32 ֽ} + + TCnAESExpandedKey128 = array [0..43] of Cardinal; + {* AES128 չԿṹ} + + TCnAESExpandedKey192 = array [0..53] of Cardinal; + {* AES192 չԿṹ} + + TCnAESExpandedKey256 = array [0..63] of Cardinal; + {* AES256 չԿṹ} + + PCnAESBuffer = ^TCnAESBuffer; + {* AES ӽָܿ} + + PCnAESKey128 = ^TCnAESKey128; + {* AES128 Կṹָ} + + PCnAESKey192 = ^TCnAESKey192; + {* AES192 Կṹָ} + + PCnAESKey256 = ^TCnAESKey256; + {* AES256 Կṹָ} + + PCnAESExpandedKey128 = ^TCnAESExpandedKey128; + {* AES128 չԿṹָ} + + PCnAESExpandedKey192 = ^TCnAESExpandedKey192; + {* AES192 չԿṹָ} + + PCnAESExpandedKey256 = ^TCnAESExpandedKey256; + {* AES256 չԿṹָ} + + TCnAESCTRNonce = array[0..3] of Byte; + {* CTR ģʽµ Nonce ṹ4 ֽ} + + TCnAESCTRIv = array[0..7] of Byte; + {* CTR ģʽµijʼṹ8 ֽ} + +// Key Expansion Routines for Encryption + +procedure ExpandAESKeyForEncryption128(const Key: TCnAESKey128; + var ExpandedKey: TCnAESExpandedKey128); +{* ڼܳչ AES128 Կ + + + const Key: TCnAESKey128 - չ AES128 Կ + var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForEncryption192(const Key: TCnAESKey192; + var ExpandedKey: TCnAESExpandedKey192); +{* ڼܳչ AES192 Կ + + + const Key: TCnAESKey192 - չ AES192 Կ + var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForEncryption256(const Key: TCnAESKey256; + var ExpandedKey: TCnAESExpandedKey256); +{* ڼܳչ AES256 Կ + + + const Key: TCnAESKey256 - չ AES256 Կ + var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ + + ֵޣ +} + +// Block Encryption Routines ܣInBuf OutBuf ͬһ + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); overload; +{* AES128 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey128 - չ AES128 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); overload; +{* AES192 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey192 - չ AES192 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); overload; +{* AES256 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey256 - չ AES256 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +{* AES128 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey128 - չ AES128 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure EncryptAES192(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +{* AES192 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey192 - չ AES192 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure EncryptAES256(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +{* AES256 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey256 - չ AES256 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +// Stream Encryption Routines (ECB mode) ECB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); overload; +{* AES128 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); overload; +{* AES128 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); overload; +{* AES256 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); overload; +{* AES192 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); overload; +{* AES256 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); overload; +{* AES256 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +{* AES128 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES128StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +{* AES128 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES192StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +{* AES192 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +{* AES192 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES256StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +{* AES256 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +{* AES256 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + Dest: TStream - + + ֵޣ +} + +// Stream Encryption Routines (CBC mode) CBC + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES128StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES192StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES256StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Encryption Routines (CFB mode) CFB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES128StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Encryption Routines (OFB mode) OFB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES128StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES192StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - ?? + + ֵޣ +} +procedure EncryptAES192StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES256StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Encryption Routines (CTR mode) CTR + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES128 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES128 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES192 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES192 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES256 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES256 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES128 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES128StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES128 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES192 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES192 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES256 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES256 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Key Transformation Routines for Decryption + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey128); overload; +{* ڽܳչ AES128 Կ + + + var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey128; + var ExpandedKey: TCnAESExpandedKey128); overload; +{* ڽܳչ AES128 Կ + + + const Key: TCnAESKey128 - չ AES128 Կ + var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey192); overload; +{* ڽܳչ AES192 Կ + + + var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ + + ֵޣ +} +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey192; + var ExpandedKey: TCnAESExpandedKey192); overload; +{* ڽܳչ AES192 Կ + + + const Key: TCnAESKey192 - չ AES192 Կ + var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey256); overload; +{* ڽܳչ AES256 Կ + + + var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ + + ֵޣ +} +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey256; + var ExpandedKey: TCnAESExpandedKey256); overload; +{* ڽܳչ AES256 Կ + + + const Key: TCnAESKey256 - չ AES256 Կ + var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure ExpandAESKeyForDecryption128(var ExpandedKey: TCnAESExpandedKey128); +{* ڽܳչ AES128 Կ + + + var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ + + ֵޣ +} +procedure ExpandAESKeyForDecryption128Expanded(const Key: TCnAESKey128; + var ExpandedKey: TCnAESExpandedKey128); +{* ڽܳչ AES128 Կ + + + const Key: TCnAESKey128 - չ AES128 Կ + var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForDecryption192(var ExpandedKey: TCnAESExpandedKey192); +{* ڽܳչ AES192 Կ + + + var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ + + ֵޣ +} +procedure ExpandAESKeyForDecryption192Expanded(const Key: TCnAESKey192; + var ExpandedKey: TCnAESExpandedKey192); +{* ڽܳչ AES192 Կ + + + const Key: TCnAESKey192 - չ AES192 Կ + var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForDecryption256(var ExpandedKey: TCnAESExpandedKey256); +{* ڽܳչ AES256 Կ + + + var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ + + ֵޣ +} +procedure ExpandAESKeyForDecryption256Expanded(const Key: TCnAESKey256; + var ExpandedKey: TCnAESExpandedKey256); +{* ڽܳչ AES256 Կ + + + const Key: TCnAESKey256 - չ AES256 Կ + var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ + + ֵޣ +} + +// Block Decryption Routines + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); overload; +{* AES128 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey128 - չ AES128 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); overload; +{* AES192 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey192 - չ AES192 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); overload; +{* AES256 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey256 - չ AES256 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +{* AES128 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey128 - չ AES128 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure DecryptAES192(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +{* AES192 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey192 - չ AES192 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure DecryptAES256(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +{* AES256 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey256 - չ AES256 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +// Stream Decryption Routines (ECB mode) ECB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); overload; +{* AES128 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); overload; +{* AES128 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); overload; +{* AES192 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); overload; +{* AES192 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); overload; +{* AES256 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); overload; +{* AES256 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +{* AES128 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES128StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +{* AES128 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAES192StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +{* AES192 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +{* AES192 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAES256StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +{* AES256 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +{* AES156 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + Dest: TStream - + + ֵޣ +} + +// Stream Decryption Routines (CBC mode) CBC + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES128StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Decryption Routines (CFB mode) CFB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES128StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Decryption Routines (OFB mode) OFB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES128StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Decryption Routines (CTR mode) CTR + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES128 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES128 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES192 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES192 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES256 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES256 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES128 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES128StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES128 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES192 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES192 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES256 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES256 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// ============== ַʮַ֮ļӽ =================== + +function AESEncryptEcbStrToHex(Value: AnsiString; Key: AnsiString; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES ECB ģʽַתʮơ + + + Value: AnsiString - ַܵ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptEcbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES ECB ʮַ + + + const HexStr: AnsiString - ܵʮַ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ַ +} + +function AESEncryptCbcStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CBC ģʽַתʮơ + + + Value: AnsiString - ַܵ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCbcStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CBC ʮַ + + + const HexStr: AnsiString - ܵʮַ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ַ +} + +function AESEncryptCfbStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CFB ģʽַתʮơ + + + Value: AnsiString - ַܵ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCfbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CFB ʮַ + + + const HexStr: AnsiString - ܵʮַ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ַ +} + +function AESEncryptOfbStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES OFB ģʽַתʮơ + + + Value: AnsiString - ַܵ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptOfbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES OFB ʮַ + + + const HexStr: AnsiString - ܵʮַ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ַ +} + +function AESEncryptCtrStrToHex(Value: AnsiString; Key: AnsiString; + const Nonce: TCnAESCTRNonce; const Iv: TCnAESCTRIv; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CTR ģʽַתʮơ + + + Value: AnsiString - ַܵ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const Iv: TCnAESCTRIv - 8 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCtrStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Nonce: TCnAESCTRNonce; const Iv: TCnAESCTRIv; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CTR ʮַ + + + const HexStr: AnsiString - ܵʮַ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const Iv: TCnAESCTRIv - 8 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ַ +} + +// ================= ֽֽ֮ļӽ ==================== + +function AESEncryptEcbBytes(Value: TBytes; Key: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES ECB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESDecryptEcbBytes(Value: TBytes; Key: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES ECB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCbcBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CBC ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESDecryptCbcBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CBC ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCfbBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CFB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESDecryptCfbBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CFB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptOfbBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES OFB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESDecryptOfbBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES OFB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCtrBytes(Value: TBytes; Key: TBytes; Nonce: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CTR ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Nonce: TBytes - 4 ֽ Nonce 飬̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESDecryptCtrBytes(Value: TBytes; Key: TBytes; Nonce: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CTR ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Nonce: TBytes - 4 ֽ Nonce 飬̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +// ============== ֽʮַ֮ļӽ ================= + +function AESEncryptEcbBytesToHex(Value: TBytes; Key: TBytes; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES ECB ģʽֽ鲢תʮơ + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptEcbBytesFromHex(const HexStr: AnsiString; Key: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES ECB ʮַֽ顣 + + + const HexStr: AnsiString - ܵʮַ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCbcBytesToHex(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CBC ģʽֽ鲢תʮơ + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCbcBytesFromHex(const HexStr: AnsiString; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CBC ʮַֽ顣 + + + const HexStr: AnsiString - ܵʮַ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCfbBytesToHex(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CFB ģʽֽ鲢תʮơ + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCfbBytesFromHex(const HexStr: AnsiString; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CFB ʮַֽ顣 + + + const HexStr: AnsiString - ܵʮַ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptOfbBytesToHex(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES OFB ģʽֽ鲢תʮơ + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptOfbBytesFromHex(const HexStr: AnsiString; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES OFB ʮַֽ顣 + + + const HexStr: AnsiString - ܵʮַ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCtrBytesToHex(Value: TBytes; Key: TBytes; Nonce: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CTR ģʽֽ鲢תʮơ + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Nonce: TBytes - 4 ֽ Nonce ֽ飬̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCtrBytesFromHex(const HexStr: AnsiString; Key: TBytes; Nonce: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CTR ʮַֽ顣 + + + const HexStr: AnsiString - ܵʮַ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Nonce: TBytes - 4 ֽ Nonce ֽ飬̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +implementation + +resourcestring + SCnErrorAESInvalidInBufSize = 'Invalid Buffer Size for Decryption'; + SCnErrorAESReadError = 'Stream Read Error'; + SCnErrorAESWriteError = 'Stream Write Error'; + +function Min(A, B: Integer): Integer; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + if A < B then + Result := A + else + Result := B; +end; + +const + Rcon: array [1..30] of Cardinal = ( + $00000001, $00000002, $00000004, $00000008, $00000010, $00000020, + $00000040, $00000080, $0000001B, $00000036, $0000006C, $000000D8, + $000000AB, $0000004D, $0000009A, $0000002F, $0000005E, $000000BC, + $00000063, $000000C6, $00000097, $00000035, $0000006A, $000000D4, + $000000B3, $0000007D, $000000FA, $000000EF, $000000C5, $00000091 + ); + + ForwardTable: array [0..255] of Cardinal = ( + $A56363C6, $847C7CF8, $997777EE, $8D7B7BF6, $0DF2F2FF, $BD6B6BD6, $B16F6FDE, $54C5C591, + $50303060, $03010102, $A96767CE, $7D2B2B56, $19FEFEE7, $62D7D7B5, $E6ABAB4D, $9A7676EC, + $45CACA8F, $9D82821F, $40C9C989, $877D7DFA, $15FAFAEF, $EB5959B2, $C947478E, $0BF0F0FB, + $ECADAD41, $67D4D4B3, $FDA2A25F, $EAAFAF45, $BF9C9C23, $F7A4A453, $967272E4, $5BC0C09B, + $C2B7B775, $1CFDFDE1, $AE93933D, $6A26264C, $5A36366C, $413F3F7E, $02F7F7F5, $4FCCCC83, + $5C343468, $F4A5A551, $34E5E5D1, $08F1F1F9, $937171E2, $73D8D8AB, $53313162, $3F15152A, + $0C040408, $52C7C795, $65232346, $5EC3C39D, $28181830, $A1969637, $0F05050A, $B59A9A2F, + $0907070E, $36121224, $9B80801B, $3DE2E2DF, $26EBEBCD, $6927274E, $CDB2B27F, $9F7575EA, + $1B090912, $9E83831D, $742C2C58, $2E1A1A34, $2D1B1B36, $B26E6EDC, $EE5A5AB4, $FBA0A05B, + $F65252A4, $4D3B3B76, $61D6D6B7, $CEB3B37D, $7B292952, $3EE3E3DD, $712F2F5E, $97848413, + $F55353A6, $68D1D1B9, $00000000, $2CEDEDC1, $60202040, $1FFCFCE3, $C8B1B179, $ED5B5BB6, + $BE6A6AD4, $46CBCB8D, $D9BEBE67, $4B393972, $DE4A4A94, $D44C4C98, $E85858B0, $4ACFCF85, + $6BD0D0BB, $2AEFEFC5, $E5AAAA4F, $16FBFBED, $C5434386, $D74D4D9A, $55333366, $94858511, + $CF45458A, $10F9F9E9, $06020204, $817F7FFE, $F05050A0, $443C3C78, $BA9F9F25, $E3A8A84B, + $F35151A2, $FEA3A35D, $C0404080, $8A8F8F05, $AD92923F, $BC9D9D21, $48383870, $04F5F5F1, + $DFBCBC63, $C1B6B677, $75DADAAF, $63212142, $30101020, $1AFFFFE5, $0EF3F3FD, $6DD2D2BF, + $4CCDCD81, $140C0C18, $35131326, $2FECECC3, $E15F5FBE, $A2979735, $CC444488, $3917172E, + $57C4C493, $F2A7A755, $827E7EFC, $473D3D7A, $AC6464C8, $E75D5DBA, $2B191932, $957373E6, + $A06060C0, $98818119, $D14F4F9E, $7FDCDCA3, $66222244, $7E2A2A54, $AB90903B, $8388880B, + $CA46468C, $29EEEEC7, $D3B8B86B, $3C141428, $79DEDEA7, $E25E5EBC, $1D0B0B16, $76DBDBAD, + $3BE0E0DB, $56323264, $4E3A3A74, $1E0A0A14, $DB494992, $0A06060C, $6C242448, $E45C5CB8, + $5DC2C29F, $6ED3D3BD, $EFACAC43, $A66262C4, $A8919139, $A4959531, $37E4E4D3, $8B7979F2, + $32E7E7D5, $43C8C88B, $5937376E, $B76D6DDA, $8C8D8D01, $64D5D5B1, $D24E4E9C, $E0A9A949, + $B46C6CD8, $FA5656AC, $07F4F4F3, $25EAEACF, $AF6565CA, $8E7A7AF4, $E9AEAE47, $18080810, + $D5BABA6F, $887878F0, $6F25254A, $722E2E5C, $241C1C38, $F1A6A657, $C7B4B473, $51C6C697, + $23E8E8CB, $7CDDDDA1, $9C7474E8, $211F1F3E, $DD4B4B96, $DCBDBD61, $868B8B0D, $858A8A0F, + $907070E0, $423E3E7C, $C4B5B571, $AA6666CC, $D8484890, $05030306, $01F6F6F7, $120E0E1C, + $A36161C2, $5F35356A, $F95757AE, $D0B9B969, $91868617, $58C1C199, $271D1D3A, $B99E9E27, + $38E1E1D9, $13F8F8EB, $B398982B, $33111122, $BB6969D2, $70D9D9A9, $898E8E07, $A7949433, + $B69B9B2D, $221E1E3C, $92878715, $20E9E9C9, $49CECE87, $FF5555AA, $78282850, $7ADFDFA5, + $8F8C8C03, $F8A1A159, $80898909, $170D0D1A, $DABFBF65, $31E6E6D7, $C6424284, $B86868D0, + $C3414182, $B0999929, $772D2D5A, $110F0F1E, $CBB0B07B, $FC5454A8, $D6BBBB6D, $3A16162C + ); + + LastForwardTable: array [0..255] of Cardinal = ( + $00000063, $0000007C, $00000077, $0000007B, $000000F2, $0000006B, $0000006F, $000000C5, + $00000030, $00000001, $00000067, $0000002B, $000000FE, $000000D7, $000000AB, $00000076, + $000000CA, $00000082, $000000C9, $0000007D, $000000FA, $00000059, $00000047, $000000F0, + $000000AD, $000000D4, $000000A2, $000000AF, $0000009C, $000000A4, $00000072, $000000C0, + $000000B7, $000000FD, $00000093, $00000026, $00000036, $0000003F, $000000F7, $000000CC, + $00000034, $000000A5, $000000E5, $000000F1, $00000071, $000000D8, $00000031, $00000015, + $00000004, $000000C7, $00000023, $000000C3, $00000018, $00000096, $00000005, $0000009A, + $00000007, $00000012, $00000080, $000000E2, $000000EB, $00000027, $000000B2, $00000075, + $00000009, $00000083, $0000002C, $0000001A, $0000001B, $0000006E, $0000005A, $000000A0, + $00000052, $0000003B, $000000D6, $000000B3, $00000029, $000000E3, $0000002F, $00000084, + $00000053, $000000D1, $00000000, $000000ED, $00000020, $000000FC, $000000B1, $0000005B, + $0000006A, $000000CB, $000000BE, $00000039, $0000004A, $0000004C, $00000058, $000000CF, + $000000D0, $000000EF, $000000AA, $000000FB, $00000043, $0000004D, $00000033, $00000085, + $00000045, $000000F9, $00000002, $0000007F, $00000050, $0000003C, $0000009F, $000000A8, + $00000051, $000000A3, $00000040, $0000008F, $00000092, $0000009D, $00000038, $000000F5, + $000000BC, $000000B6, $000000DA, $00000021, $00000010, $000000FF, $000000F3, $000000D2, + $000000CD, $0000000C, $00000013, $000000EC, $0000005F, $00000097, $00000044, $00000017, + $000000C4, $000000A7, $0000007E, $0000003D, $00000064, $0000005D, $00000019, $00000073, + $00000060, $00000081, $0000004F, $000000DC, $00000022, $0000002A, $00000090, $00000088, + $00000046, $000000EE, $000000B8, $00000014, $000000DE, $0000005E, $0000000B, $000000DB, + $000000E0, $00000032, $0000003A, $0000000A, $00000049, $00000006, $00000024, $0000005C, + $000000C2, $000000D3, $000000AC, $00000062, $00000091, $00000095, $000000E4, $00000079, + $000000E7, $000000C8, $00000037, $0000006D, $0000008D, $000000D5, $0000004E, $000000A9, + $0000006C, $00000056, $000000F4, $000000EA, $00000065, $0000007A, $000000AE, $00000008, + $000000BA, $00000078, $00000025, $0000002E, $0000001C, $000000A6, $000000B4, $000000C6, + $000000E8, $000000DD, $00000074, $0000001F, $0000004B, $000000BD, $0000008B, $0000008A, + $00000070, $0000003E, $000000B5, $00000066, $00000048, $00000003, $000000F6, $0000000E, + $00000061, $00000035, $00000057, $000000B9, $00000086, $000000C1, $0000001D, $0000009E, + $000000E1, $000000F8, $00000098, $00000011, $00000069, $000000D9, $0000008E, $00000094, + $0000009B, $0000001E, $00000087, $000000E9, $000000CE, $00000055, $00000028, $000000DF, + $0000008C, $000000A1, $00000089, $0000000D, $000000BF, $000000E6, $00000042, $00000068, + $00000041, $00000099, $0000002D, $0000000F, $000000B0, $00000054, $000000BB, $00000016 + ); + + InverseTable: array [0..255] of Cardinal = ( + $50A7F451, $5365417E, $C3A4171A, $965E273A, $CB6BAB3B, $F1459D1F, $AB58FAAC, $9303E34B, + $55FA3020, $F66D76AD, $9176CC88, $254C02F5, $FCD7E54F, $D7CB2AC5, $80443526, $8FA362B5, + $495AB1DE, $671BBA25, $980EEA45, $E1C0FE5D, $02752FC3, $12F04C81, $A397468D, $C6F9D36B, + $E75F8F03, $959C9215, $EB7A6DBF, $DA595295, $2D83BED4, $D3217458, $2969E049, $44C8C98E, + $6A89C275, $78798EF4, $6B3E5899, $DD71B927, $B64FE1BE, $17AD88F0, $66AC20C9, $B43ACE7D, + $184ADF63, $82311AE5, $60335197, $457F5362, $E07764B1, $84AE6BBB, $1CA081FE, $942B08F9, + $58684870, $19FD458F, $876CDE94, $B7F87B52, $23D373AB, $E2024B72, $578F1FE3, $2AAB5566, + $0728EBB2, $03C2B52F, $9A7BC586, $A50837D3, $F2872830, $B2A5BF23, $BA6A0302, $5C8216ED, + $2B1CCF8A, $92B479A7, $F0F207F3, $A1E2694E, $CDF4DA65, $D5BE0506, $1F6234D1, $8AFEA6C4, + $9D532E34, $A055F3A2, $32E18A05, $75EBF6A4, $39EC830B, $AAEF6040, $069F715E, $51106EBD, + $F98A213E, $3D06DD96, $AE053EDD, $46BDE64D, $B58D5491, $055DC471, $6FD40604, $FF155060, + $24FB9819, $97E9BDD6, $CC434089, $779ED967, $BD42E8B0, $888B8907, $385B19E7, $DBEEC879, + $470A7CA1, $E90F427C, $C91E84F8, $00000000, $83868009, $48ED2B32, $AC70111E, $4E725A6C, + $FBFF0EFD, $5638850F, $1ED5AE3D, $27392D36, $64D90F0A, $21A65C68, $D1545B9B, $3A2E3624, + $B1670A0C, $0FE75793, $D296EEB4, $9E919B1B, $4FC5C080, $A220DC61, $694B775A, $161A121C, + $0ABA93E2, $E52AA0C0, $43E0223C, $1D171B12, $0B0D090E, $ADC78BF2, $B9A8B62D, $C8A91E14, + $8519F157, $4C0775AF, $BBDD99EE, $FD607FA3, $9F2601F7, $BCF5725C, $C53B6644, $347EFB5B, + $7629438B, $DCC623CB, $68FCEDB6, $63F1E4B8, $CADC31D7, $10856342, $40229713, $2011C684, + $7D244A85, $F83DBBD2, $1132F9AE, $6DA129C7, $4B2F9E1D, $F330B2DC, $EC52860D, $D0E3C177, + $6C16B32B, $99B970A9, $FA489411, $2264E947, $C48CFCA8, $1A3FF0A0, $D82C7D56, $EF903322, + $C74E4987, $C1D138D9, $FEA2CA8C, $360BD498, $CF81F5A6, $28DE7AA5, $268EB7DA, $A4BFAD3F, + $E49D3A2C, $0D927850, $9BCC5F6A, $62467E54, $C2138DF6, $E8B8D890, $5EF7392E, $F5AFC382, + $BE805D9F, $7C93D069, $A92DD56F, $B31225CF, $3B99ACC8, $A77D1810, $6E639CE8, $7BBB3BDB, + $097826CD, $F418596E, $01B79AEC, $A89A4F83, $656E95E6, $7EE6FFAA, $08CFBC21, $E6E815EF, + $D99BE7BA, $CE366F4A, $D4099FEA, $D67CB029, $AFB2A431, $31233F2A, $3094A5C6, $C066A235, + $37BC4E74, $A6CA82FC, $B0D090E0, $15D8A733, $4A9804F1, $F7DAEC41, $0E50CD7F, $2FF69117, + $8DD64D76, $4DB0EF43, $544DAACC, $DF0496E4, $E3B5D19E, $1B886A4C, $B81F2CC1, $7F516546, + $04EA5E9D, $5D358C01, $737487FA, $2E410BFB, $5A1D67B3, $52D2DB92, $335610E9, $1347D66D, + $8C61D79A, $7A0CA137, $8E14F859, $893C13EB, $EE27A9CE, $35C961B7, $EDE51CE1, $3CB1477A, + $59DFD29C, $3F73F255, $79CE1418, $BF37C773, $EACDF753, $5BAAFD5F, $146F3DDF, $86DB4478, + $81F3AFCA, $3EC468B9, $2C342438, $5F40A3C2, $72C31D16, $0C25E2BC, $8B493C28, $41950DFF, + $7101A839, $DEB30C08, $9CE4B4D8, $90C15664, $6184CB7B, $70B632D5, $745C6C48, $4257B8D0 + ); + + LastInverseTable: array [0..255] of Cardinal = ( + $00000052, $00000009, $0000006A, $000000D5, $00000030, $00000036, $000000A5, $00000038, + $000000BF, $00000040, $000000A3, $0000009E, $00000081, $000000F3, $000000D7, $000000FB, + $0000007C, $000000E3, $00000039, $00000082, $0000009B, $0000002F, $000000FF, $00000087, + $00000034, $0000008E, $00000043, $00000044, $000000C4, $000000DE, $000000E9, $000000CB, + $00000054, $0000007B, $00000094, $00000032, $000000A6, $000000C2, $00000023, $0000003D, + $000000EE, $0000004C, $00000095, $0000000B, $00000042, $000000FA, $000000C3, $0000004E, + $00000008, $0000002E, $000000A1, $00000066, $00000028, $000000D9, $00000024, $000000B2, + $00000076, $0000005B, $000000A2, $00000049, $0000006D, $0000008B, $000000D1, $00000025, + $00000072, $000000F8, $000000F6, $00000064, $00000086, $00000068, $00000098, $00000016, + $000000D4, $000000A4, $0000005C, $000000CC, $0000005D, $00000065, $000000B6, $00000092, + $0000006C, $00000070, $00000048, $00000050, $000000FD, $000000ED, $000000B9, $000000DA, + $0000005E, $00000015, $00000046, $00000057, $000000A7, $0000008D, $0000009D, $00000084, + $00000090, $000000D8, $000000AB, $00000000, $0000008C, $000000BC, $000000D3, $0000000A, + $000000F7, $000000E4, $00000058, $00000005, $000000B8, $000000B3, $00000045, $00000006, + $000000D0, $0000002C, $0000001E, $0000008F, $000000CA, $0000003F, $0000000F, $00000002, + $000000C1, $000000AF, $000000BD, $00000003, $00000001, $00000013, $0000008A, $0000006B, + $0000003A, $00000091, $00000011, $00000041, $0000004F, $00000067, $000000DC, $000000EA, + $00000097, $000000F2, $000000CF, $000000CE, $000000F0, $000000B4, $000000E6, $00000073, + $00000096, $000000AC, $00000074, $00000022, $000000E7, $000000AD, $00000035, $00000085, + $000000E2, $000000F9, $00000037, $000000E8, $0000001C, $00000075, $000000DF, $0000006E, + $00000047, $000000F1, $0000001A, $00000071, $0000001D, $00000029, $000000C5, $00000089, + $0000006F, $000000B7, $00000062, $0000000E, $000000AA, $00000018, $000000BE, $0000001B, + $000000FC, $00000056, $0000003E, $0000004B, $000000C6, $000000D2, $00000079, $00000020, + $0000009A, $000000DB, $000000C0, $000000FE, $00000078, $000000CD, $0000005A, $000000F4, + $0000001F, $000000DD, $000000A8, $00000033, $00000088, $00000007, $000000C7, $00000031, + $000000B1, $00000012, $00000010, $00000059, $00000027, $00000080, $000000EC, $0000005F, + $00000060, $00000051, $0000007F, $000000A9, $00000019, $000000B5, $0000004A, $0000000D, + $0000002D, $000000E5, $0000007A, $0000009F, $00000093, $000000C9, $0000009C, $000000EF, + $000000A0, $000000E0, $0000003B, $0000004D, $000000AE, $0000002A, $000000F5, $000000B0, + $000000C8, $000000EB, $000000BB, $0000003C, $00000083, $00000053, $00000099, $00000061, + $00000017, $0000002B, $00000004, $0000007E, $000000BA, $00000077, $000000D6, $00000026, + $000000E1, $00000069, $00000014, $00000063, $00000055, $00000021, $0000000C, $0000007D + ); + +procedure ExpandAESKeyForEncryption128(const Key: TCnAESKey128; var ExpandedKey: + TCnAESExpandedKey128); +var + I, J: Integer; + T: Cardinal; + W0, W1, W2, W3: Cardinal; +begin + ExpandedKey[0] := PCardinal(@Key[0])^; + ExpandedKey[1] := PCardinal(@Key[4])^; + ExpandedKey[2] := PCardinal(@Key[8])^; + ExpandedKey[3] := PCardinal(@Key[12])^; + I := 0; J := 1; + repeat + T := (ExpandedKey[I + 3] shl 24) or (ExpandedKey[I + 3] shr 8); + W0 := LastForwardTable[Byte(T)]; W1 := LastForwardTable[Byte(T shr 8)]; + W2 := LastForwardTable[Byte(T shr 16)]; W3 := LastForwardTable[Byte(T shr 24)]; + ExpandedKey[I + 4] := ExpandedKey[I] xor + (W0 xor ((W1 shl 8) or (W1 shr 24)) xor + ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8))) xor Rcon[J]; + Inc(J); + ExpandedKey[I + 5] := ExpandedKey[I + 1] xor ExpandedKey[I + 4]; + ExpandedKey[I + 6] := ExpandedKey[I + 2] xor ExpandedKey[I + 5]; + ExpandedKey[I + 7] := ExpandedKey[I + 3] xor ExpandedKey[I + 6]; + Inc(I, 4); + until I >= 40; +end; + +procedure ExpandAESKeyForEncryption192(const Key: TCnAESKey192; var ExpandedKey: + TCnAESExpandedKey192); +var + I, J: Integer; + T: Cardinal; + W0, W1, W2, W3: Cardinal; +begin + ExpandedKey[0] := PCardinal(@Key[0])^; + ExpandedKey[1] := PCardinal(@Key[4])^; + ExpandedKey[2] := PCardinal(@Key[8])^; + ExpandedKey[3] := PCardinal(@Key[12])^; + ExpandedKey[4] := PCardinal(@Key[16])^; + ExpandedKey[5] := PCardinal(@Key[20])^; + I := 0; J := 1; + repeat + T := (ExpandedKey[I + 5] shl 24) or (ExpandedKey[I + 5] shr 8); + W0 := LastForwardTable[Byte(T)]; W1 := LastForwardTable[Byte(T shr 8)]; + W2 := LastForwardTable[Byte(T shr 16)]; W3 := LastForwardTable[Byte(T shr 24)]; + ExpandedKey[I + 6] := ExpandedKey[I] xor + (W0 xor ((W1 shl 8) or (W1 shr 24)) xor + ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8))) xor Rcon[J]; + Inc(J); + ExpandedKey[I + 7] := ExpandedKey[I + 1] xor ExpandedKey[I + 6]; + ExpandedKey[I + 8] := ExpandedKey[I + 2] xor ExpandedKey[I + 7]; + ExpandedKey[I + 9] := ExpandedKey[I + 3] xor ExpandedKey[I + 8]; + ExpandedKey[I + 10] := ExpandedKey[I + 4] xor ExpandedKey[I + 9]; + ExpandedKey[I + 11] := ExpandedKey[I + 5] xor ExpandedKey[I + 10]; + Inc(I, 6); + until I >= 46; +end; + +procedure ExpandAESKeyForEncryption256(const Key: TCnAESKey256; var ExpandedKey: + TCnAESExpandedKey256); +var + I, J: Integer; + T: Cardinal; + W0, W1, W2, W3: Cardinal; +begin + ExpandedKey[0] := PCardinal(@Key[0])^; + ExpandedKey[1] := PCardinal(@Key[4])^; + ExpandedKey[2] := PCardinal(@Key[8])^; + ExpandedKey[3] := PCardinal(@Key[12])^; + ExpandedKey[4] := PCardinal(@Key[16])^; + ExpandedKey[5] := PCardinal(@Key[20])^; + ExpandedKey[6] := PCardinal(@Key[24])^; + ExpandedKey[7] := PCardinal(@Key[28])^; + I := 0; J := 1; + repeat + T := (ExpandedKey[I + 7] shl 24) or (ExpandedKey[I + 7] shr 8); + W0 := LastForwardTable[Byte(T)]; W1 := LastForwardTable[Byte(T shr 8)]; + W2 := LastForwardTable[Byte(T shr 16)]; W3 := LastForwardTable[Byte(T shr 24)]; + ExpandedKey[I + 8] := ExpandedKey[I] xor + (W0 xor ((W1 shl 8) or (W1 shr 24)) xor + ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8))) xor Rcon[J]; + Inc(J); + ExpandedKey[I + 9] := ExpandedKey[I + 1] xor ExpandedKey[I + 8]; + ExpandedKey[I + 10] := ExpandedKey[I + 2] xor ExpandedKey[I + 9]; + ExpandedKey[I + 11] := ExpandedKey[I + 3] xor ExpandedKey[I + 10]; + W0 := LastForwardTable[Byte(ExpandedKey[I + 11])]; + W1 := LastForwardTable[Byte(ExpandedKey[I + 11] shr 8)]; + W2 := LastForwardTable[Byte(ExpandedKey[I + 11] shr 16)]; + W3 := LastForwardTable[Byte(ExpandedKey[I + 11] shr 24)]; + ExpandedKey[I + 12] := ExpandedKey[I + 4] xor + (W0 xor ((W1 shl 8) or (W1 shr 24)) xor + ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8))); + ExpandedKey[I + 13] := ExpandedKey[I + 5] xor ExpandedKey[I + 12]; + ExpandedKey[I + 14] := ExpandedKey[I + 6] xor ExpandedKey[I + 13]; + ExpandedKey[I + 15] := ExpandedKey[I + 7] xor ExpandedKey[I + 14]; + Inc(I, 8); + until I >= 52; +end; + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +begin + EncryptAES128(InBuf, Key, OutBuf); +end; + +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +begin + EncryptAES192(InBuf, Key, OutBuf); +end; + +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +begin + EncryptAES256(InBuf, Key, OutBuf); +end; + +{$ENDIF} + +procedure EncryptAES128(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[0]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[1]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[2]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[3]; + + // performing transformation 9 times + // round 1 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // round 2 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 3 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 4 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 5 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 6 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 7 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 8 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 9 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // last round of transformations + W0 := LastForwardTable[Byte(T1[0])]; W1 := LastForwardTable[Byte(T1[1] shr 8)]; + W2 := LastForwardTable[Byte(T1[2] shr 16)]; W3 := LastForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; + W0 := LastForwardTable[Byte(T1[1])]; W1 := LastForwardTable[Byte(T1[2] shr 8)]; + W2 := LastForwardTable[Byte(T1[3] shr 16)]; W3 := LastForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; + W0 := LastForwardTable[Byte(T1[2])]; W1 := LastForwardTable[Byte(T1[3] shr 8)]; + W2 := LastForwardTable[Byte(T1[0] shr 16)]; W3 := LastForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; + W0 := LastForwardTable[Byte(T1[3])]; W1 := LastForwardTable[Byte(T1[0] shr 8)]; + W2 := LastForwardTable[Byte(T1[1] shr 16)]; W3 := LastForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +procedure EncryptAES192(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[0]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[1]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[2]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[3]; + + // performing transformation 11 times + // round 1 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // round 2 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 3 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 4 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 5 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 6 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 7 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 8 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 9 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // round 10 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; + // round 11 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[44]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[45]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[46]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[47]; + // last round of transformations + W0 := LastForwardTable[Byte(T1[0])]; W1 := LastForwardTable[Byte(T1[1] shr 8)]; + W2 := LastForwardTable[Byte(T1[2] shr 16)]; W3 := LastForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[48]; + W0 := LastForwardTable[Byte(T1[1])]; W1 := LastForwardTable[Byte(T1[2] shr 8)]; + W2 := LastForwardTable[Byte(T1[3] shr 16)]; W3 := LastForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[49]; + W0 := LastForwardTable[Byte(T1[2])]; W1 := LastForwardTable[Byte(T1[3] shr 8)]; + W2 := LastForwardTable[Byte(T1[0] shr 16)]; W3 := LastForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[50]; + W0 := LastForwardTable[Byte(T1[3])]; W1 := LastForwardTable[Byte(T1[0] shr 8)]; + W2 := LastForwardTable[Byte(T1[1] shr 16)]; W3 := LastForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[51]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +procedure EncryptAES256(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[0]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[1]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[2]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[3]; + + // performing transformation 13 times + // round 1 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // round 2 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 3 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 4 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 5 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 6 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 7 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 8 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 9 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // round 10 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; + // round 11 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[44]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[45]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[46]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[47]; + // round 12 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[48]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[49]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[50]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[51]; + // round 13 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[52]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[53]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[54]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[55]; + // last round of transformations + W0 := LastForwardTable[Byte(T1[0])]; W1 := LastForwardTable[Byte(T1[1] shr 8)]; + W2 := LastForwardTable[Byte(T1[2] shr 16)]; W3 := LastForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[56]; + W0 := LastForwardTable[Byte(T1[1])]; W1 := LastForwardTable[Byte(T1[2] shr 8)]; + W2 := LastForwardTable[Byte(T1[3] shr 16)]; W3 := LastForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[57]; + W0 := LastForwardTable[Byte(T1[2])]; W1 := LastForwardTable[Byte(T1[3] shr 8)]; + W2 := LastForwardTable[Byte(T1[0] shr 16)]; W3 := LastForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[58]; + W0 := LastForwardTable[Byte(T1[3])]; W1 := LastForwardTable[Byte(T1[0] shr 8)]; + W2 := LastForwardTable[Byte(T1[1] shr 16)]; W3 := LastForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[59]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey128); +begin + ExpandAESKeyForDecryption128(ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey128; + var ExpandedKey: TCnAESExpandedKey128); +begin + ExpandAESKeyForDecryption128Expanded(Key, ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey192); +begin + ExpandAESKeyForDecryption192(ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey192; + var ExpandedKey: TCnAESExpandedKey192); +begin + ExpandAESKeyForDecryption192Expanded(Key, ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey256); +begin + ExpandAESKeyForDecryption256(ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey256; + var ExpandedKey: TCnAESExpandedKey256); +begin + ExpandAESKeyForDecryption256Expanded(Key, ExpandedKey); +end; + +{$ENDIF} + +procedure ExpandAESKeyForDecryption128(var ExpandedKey: TCnAESExpandedKey128); +var + I: Integer; + U, F2, F4, F8, F9: Cardinal; +begin + for I := 1 to 9 do + begin + F9 := ExpandedKey[I * 4]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 1]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 1] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 2]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 2] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 3]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 3] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + end; +end; + +procedure ExpandAESKeyForDecryption128Expanded(const Key: TCnAESKey128; var ExpandedKey: + TCnAESExpandedKey128); +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + ExpandAESKeyForDecryption128(ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption192(var ExpandedKey: TCnAESExpandedKey192); +var + I: Integer; + U, F2, F4, F8, F9: Cardinal; +begin + for I := 1 to 11 do + begin + F9 := ExpandedKey[I * 4]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 1]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 1] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 2]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 2] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 3]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 3] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + end; +end; + +procedure ExpandAESKeyForDecryption192Expanded(const Key: TCnAESKey192; var ExpandedKey: + TCnAESExpandedKey192); +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + ExpandAESKeyForDecryption192(ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption256(var ExpandedKey: TCnAESExpandedKey256); +var + I: Integer; + U, F2, F4, F8, F9: Cardinal; +begin + for I := 1 to 13 do + begin + F9 := ExpandedKey[I * 4]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 1]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 1] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 2]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 2] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 3]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 3] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + end; +end; + +procedure ExpandAESKeyForDecryption256Expanded(const Key: TCnAESKey256; var ExpandedKey: + TCnAESExpandedKey256); +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + ExpandAESKeyForDecryption256(ExpandedKey); +end; + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +begin + DecryptAES128(InBuf, Key, OutBuf); +end; + +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +begin + DecryptAES192(InBuf, Key, OutBuf); +end; + +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +begin + DecryptAES256(InBuf, Key, OutBuf); +end; + +{$ENDIF} + +procedure DecryptAES128(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[40]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[41]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[42]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[43]; + + // performing transformations 9 times + // round 1 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // round 2 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 3 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 4 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 5 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 6 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 7 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 8 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 9 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // last round of transformations + W0 := LastInverseTable[Byte(T1[0])]; W1 := LastInverseTable[Byte(T1[3] shr 8)]; + W2 := LastInverseTable[Byte(T1[2] shr 16)]; W3 := LastInverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[0]; + W0 := LastInverseTable[Byte(T1[1])]; W1 := LastInverseTable[Byte(T1[0] shr 8)]; + W2 := LastInverseTable[Byte(T1[3] shr 16)]; W3 := LastInverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[1]; + W0 := LastInverseTable[Byte(T1[2])]; W1 := LastInverseTable[Byte(T1[1] shr 8)]; + W2 := LastInverseTable[Byte(T1[0] shr 16)]; W3 := LastInverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[2]; + W0 := LastInverseTable[Byte(T1[3])]; W1 := LastInverseTable[Byte(T1[2] shr 8)]; + W2 := LastInverseTable[Byte(T1[1] shr 16)]; W3 := LastInverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[3]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +procedure DecryptAES192(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[48]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[49]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[50]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[51]; + + // performing transformations 11 times + // round 1 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[44]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[45]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[46]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[47]; + // round 2 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; + // round 3 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // round 4 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 5 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 6 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 7 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 8 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 9 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 10 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 11 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // last round of transformations + W0 := LastInverseTable[Byte(T1[0])]; W1 := LastInverseTable[Byte(T1[3] shr 8)]; + W2 := LastInverseTable[Byte(T1[2] shr 16)]; W3 := LastInverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[0]; + W0 := LastInverseTable[Byte(T1[1])]; W1 := LastInverseTable[Byte(T1[0] shr 8)]; + W2 := LastInverseTable[Byte(T1[3] shr 16)]; W3 := LastInverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[1]; + W0 := LastInverseTable[Byte(T1[2])]; W1 := LastInverseTable[Byte(T1[1] shr 8)]; + W2 := LastInverseTable[Byte(T1[0] shr 16)]; W3 := LastInverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[2]; + W0 := LastInverseTable[Byte(T1[3])]; W1 := LastInverseTable[Byte(T1[2] shr 8)]; + W2 := LastInverseTable[Byte(T1[1] shr 16)]; W3 := LastInverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[3]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +procedure DecryptAES256(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[56]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[57]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[58]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[59]; + + // performing transformations 13 times + // round 1 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[52]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[53]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[54]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[55]; + // round 2 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[48]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[49]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[50]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[51]; + // round 3 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[44]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[45]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[46]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[47]; + // round 4 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; + // round 5 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // round 6 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 7 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 8 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 9 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 10 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 11 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 12 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 13 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // last round of transformations + W0 := LastInverseTable[Byte(T1[0])]; W1 := LastInverseTable[Byte(T1[3] shr 8)]; + W2 := LastInverseTable[Byte(T1[2] shr 16)]; W3 := LastInverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[0]; + W0 := LastInverseTable[Byte(T1[1])]; W1 := LastInverseTable[Byte(T1[0] shr 8)]; + W2 := LastInverseTable[Byte(T1[3] shr 16)]; W3 := LastInverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[1]; + W0 := LastInverseTable[Byte(T1[2])]; W1 := LastInverseTable[Byte(T1[1] shr 8)]; + W2 := LastInverseTable[Byte(T1[0] shr 16)]; W3 := LastInverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[2]; + W0 := LastInverseTable[Byte(T1[3])]; W1 := LastInverseTable[Byte(T1[2] shr 8)]; + W2 := LastInverseTable[Byte(T1[1] shr 16)]; W3 := LastInverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[3]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +// Stream Encryption Routines (ECB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +begin + EncryptAES128StreamECB(Source, Count, Key, Dest); +end; + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +begin + EncryptAES128StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +begin + EncryptAES192StreamECB(Source, Count, Key, Dest); +end; + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +begin + EncryptAES192StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +begin + EncryptAES256StreamECB(Source, Count, Key, Dest); +end; + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +begin + EncryptAES256StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +{$ENDIF} + +procedure EncryptAES128StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + EncryptAES128StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure EncryptAES192StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + EncryptAES192StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure EncryptAES256StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + EncryptAES256StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure EncryptAES128StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES128(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + EncryptAES128(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES192StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES192(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + EncryptAES192(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES256StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES256(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + EncryptAES256(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +// Stream Decryption Routines (ECB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +begin + DecryptAES128StreamECB(Source, Count, Key, Dest); +end; + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +begin + DecryptAES128StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +begin + DecryptAES192StreamECB(Source, Count, Key, Dest); +end; + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +begin + DecryptAES192StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +begin + DecryptAES256StreamECB(Source, Count, Key, Dest); +end; + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +begin + DecryptAES256StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +{$ENDIF} + +procedure DecryptAES128StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForDecryption128Expanded(Key, ExpandedKey); + DecryptAES128StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure DecryptAES128StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + if (Count mod SizeOf(TCnAESBuffer)) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); + + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + DecryptAES128(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +procedure DecryptAES192StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForDecryption192Expanded(Key, ExpandedKey); + DecryptAES192StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure DecryptAES192StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + if (Count mod SizeOf(TCnAESBuffer)) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); + + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + DecryptAES192(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +procedure DecryptAES256StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForDecryption256Expanded(Key, ExpandedKey); + DecryptAES256StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure DecryptAES256StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + if (Count mod SizeOf(TCnAESBuffer)) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); + + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + DecryptAES256(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +// Stream Encryption Routines (CBC mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES128StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES128StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES192StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES192StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES256StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES256StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure EncryptAES128StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + EncryptAES128StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES128StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); // Ҫÿһ鶼 + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; // ԭʼ IV + EncryptAES128(TempIn, ExpandedKey, TempOut); // ټ + + Done := Dest.Write(TempOut, SizeOf(TempOut)); // д + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Vector := TempOut; // ݴԭʼ IV һʹ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + EncryptAES128(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES192StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + EncryptAES192StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES192StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + EncryptAES192(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + EncryptAES192(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES256StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + EncryptAES256StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES256StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + EncryptAES256(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + EncryptAES256(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +// Stream Decryption Routines (CBC mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES128StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES128StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES192StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES192StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES256StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES256StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure DecryptAES128StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForDecryption128Expanded(Key, ExpandedKey); + DecryptAES128StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES128StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector1, Vector2: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + if Count mod SizeOf(TCnAESBuffer) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); + + Vector1 := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + Vector2 := TempIn; + DecryptAES128(TempIn, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@Vector1[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@Vector1[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + + Vector1 := Vector2; + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +procedure DecryptAES192StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForDecryption192Expanded(Key, ExpandedKey); + DecryptAES192StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES192StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector1, Vector2: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + if Count mod SizeOf(TCnAESBuffer) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); + + Vector1 := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + Vector2 := TempIn; + DecryptAES192(TempIn, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@Vector1[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@Vector1[12])^; + Done := Dest.Write(TempOut, SizeOf(TempOut)); + + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + + Vector1 := Vector2; + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +procedure DecryptAES256StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForDecryption256Expanded(Key, ExpandedKey); + DecryptAES256StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES256StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector1, Vector2: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + if Count mod SizeOf(TCnAESBuffer) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); // CBC Ϊ AES ֿܲģԱ + + Vector1 := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + Vector2 := TempIn; + DecryptAES256(TempIn, ExpandedKey, TempOut); // Ƚ + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; // ܺݺ Iv õ + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@Vector1[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@Vector1[12])^; + Done := Dest.Write(TempOut, SizeOf(TempOut)); // дȥ + + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + + Vector1 := Vector2; // ȡ Iv Ϊһκͽ + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +// Stream Encryption Routines (CFB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES128StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES128StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES192StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES192StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES256StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES256StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure EncryptAES128StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + EncryptAES128StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES128StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES128(Vector, ExpandedKey, TempOut); // Key ȼ Iv + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); // ĽдĽ + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Vector := TempOut; // Ľȡ Iv һּ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES128(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES192StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + EncryptAES192StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES192StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES256StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + EncryptAES256StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES256StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +// Stream Decryption Routines (CFB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES128StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES128StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES192StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES192StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES256StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES256StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure DecryptAES128StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + DecryptAES128StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES128StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + // CFB Ϊ AES ֿܲĶ򣨳Ŀɶ + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); // + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES128(Vector, ExpandedKey, TempOut); // Iv ȼܡעǼܣǽܣ + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; // ܺݺõ + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); // дȥ + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + + Vector := TempIn; // ȡ Iv Ϊһμ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then // һ鲻Ϊ + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES128(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; // ܺݺõ + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempOut, Count); // дȥ + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +procedure DecryptAES192StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + DecryptAES192StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES192StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + + Vector := TempIn; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempOut, Count); + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +procedure DecryptAES256StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + DecryptAES256StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES256StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + + Vector := TempIn; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempOut, Count); + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +// Stream Encryption Routines (OFB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES128StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES128StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES192StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES192StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES256StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES256StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure EncryptAES128StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + EncryptAES128StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES128StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES128(Vector, ExpandedKey, TempOut); // Key ȼ Iv + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + Vector := TempOut; // ܽȡ Iv һּܣעⲻ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES128(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES192StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + EncryptAES192StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES192StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES256StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + EncryptAES256StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES256StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +// Stream Decryption Routines (OFB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES128StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES128StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES192StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES192StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES256StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES256StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure DecryptAES128StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + DecryptAES128StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES128StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + // OFB Ϊ AES ֿܲĶ򣨳Ŀɶ + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); // + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES128(Vector, ExpandedKey, TempOut); // Iv ȼܡעǼܣǽܣ + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; // ܺݺõ + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); // дȥ + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESWriteError); + + Vector := TempOut; // ȡ Iv Ϊһǰ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then // һ鲻Ϊ + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES128(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; // ܺݺõ + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempIn, Count); // дȥ + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +procedure DecryptAES192StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + DecryptAES192StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES192StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESWriteError); + + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +procedure DecryptAES256StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + DecryptAES256StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES256StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESWriteError); + + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +// Stream Encryption Routines (CTR mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES128StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES192StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES256StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +{$ENDIF} + +procedure EncryptAES128StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + EncryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure EncryptAES128StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done, Cnt, T: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Cnt := 1; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES128(Vector, ExpandedKey, TempOut); // Key ȼƴ Iv + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Inc(Cnt); // һ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES128(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES192StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + EncryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure EncryptAES192StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done, Cnt, T: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Cnt := 1; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES192(Vector, ExpandedKey, TempOut); // Key ȼƴ Iv + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Inc(Cnt); // һ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES256StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + EncryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure EncryptAES256StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done, Cnt, T: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Cnt := 1; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES256(Vector, ExpandedKey, TempOut); // Key ȼƴ Iv + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Inc(Cnt); // һ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +// Stream Decryption Routines (CTR mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES128StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES192StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES256StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +{$ENDIF} + +procedure DecryptAES128StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + DecryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAES128StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAES192StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + DecryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAES192StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAES256StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + DecryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAES256StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +// AES ECB ַתʮ +function AESEncryptEcbStrToHex(Value: AnsiString; Key: AnsiString; + KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[1])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamECB(SS, 0, AESKey128, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamECB(SS, 0, AESKey192, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamECB(SS, 0, AESKey256, DS); + end; + end; + + Result := AnsiString(DataToHex(DS.Memory, DS.Size)); + finally + SS.Free; + DS.Free; + end; +end; + +// AES ECB ʮַ +function AESDecryptEcbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + Tmp: TBytes; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + Tmp := HexToBytes(string(HexStr)); + SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamECB(SS, SS.Size - SS.Position, AESKey128, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamECB(SS, SS.Size - SS.Position, AESKey192, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamECB(SS, SS.Size - SS.Position, AESKey256, DS); + end; + end; + + SetLength(Result, DS.Size); + Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CBC ַתʮ +function AESEncryptCbcStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[1])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCBC(SS, 0, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCBC(SS, 0, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCBC(SS, 0, AESKey256, Iv, DS); + end; + end; + + Result := AnsiString(DataToHex(DS.Memory, DS.Size)); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CBC ʮַ +function AESDecryptCbcStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + Tmp: TBytes; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + Tmp := HexToBytes(string(HexStr)); + SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCBC(SS, SS.Size - SS.Position, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCBC(SS, SS.Size - SS.Position, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCBC(SS, SS.Size - SS.Position, AESKey256, Iv, DS); + end; + end; + + SetLength(Result, DS.Size); + Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CFB ģʽַתʮ +function AESEncryptCfbStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[1])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCFB(SS, 0, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCFB(SS, 0, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCFB(SS, 0, AESKey256, Iv, DS); + end; + end; + + Result := AnsiString(DataToHex(DS.Memory, DS.Size)); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CFB ʮַ +function AESDecryptCfbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + Tmp: TBytes; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + Tmp := HexToBytes(string(HexStr)); + SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCFB(SS, SS.Size - SS.Position, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCFB(SS, SS.Size - SS.Position, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCFB(SS, SS.Size - SS.Position, AESKey256, Iv, DS); + end; + end; + + SetLength(Result, DS.Size); + Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES OFB ģʽַתʮ +function AESEncryptOfbStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[1])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamOFB(SS, 0, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamOFB(SS, 0, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamOFB(SS, 0, AESKey256, Iv, DS); + end; + end; + + Result := AnsiString(DataToHex(DS.Memory, DS.Size)); + finally + SS.Free; + DS.Free; + end; +end; + +// AES OFB ʮַ +function AESDecryptOfbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + Tmp: TBytes; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + Tmp := HexToBytes(string(HexStr)); + SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamOFB(SS, SS.Size - SS.Position, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamOFB(SS, SS.Size - SS.Position, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamOFB(SS, SS.Size - SS.Position, AESKey256, Iv, DS); + end; + end; + + SetLength(Result, DS.Size); + Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CTR ģʽַתʮ +function AESEncryptCtrStrToHex(Value: AnsiString; Key: AnsiString; + const Nonce: TCnAESCTRNonce; const Iv: TCnAESCTRIv; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[1])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCTR(SS, 0, AESKey128, Nonce, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCTR(SS, 0, AESKey192, Nonce, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCTR(SS, 0, AESKey256, Nonce, Iv, DS); + end; + end; + + Result := AnsiString(DataToHex(DS.Memory, DS.Size)); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CTR ʮַ +function AESDecryptCtrStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Nonce: TCnAESCTRNonce; const Iv: TCnAESCTRIv; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + Tmp: TBytes; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + Tmp := HexToBytes(string(HexStr)); + SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCTR(SS, SS.Size - SS.Position, AESKey128, Nonce, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCTR(SS, SS.Size - SS.Position, AESKey192, Nonce, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCTR(SS, SS.Size - SS.Position, AESKey256, Nonce, Iv, DS); + end; + end; + + SetLength(Result, DS.Size); + Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES ECB ģʽֽ +function AESEncryptEcbBytes(Value, Key: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamECB(SS, 0, AESKey128, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamECB(SS, 0, AESKey192, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamECB(SS, 0, AESKey256, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES ECB ģʽֽ +function AESDecryptEcbBytes(Value, Key: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamECB(SS, SS.Size - SS.Position, AESKey128, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamECB(SS, SS.Size - SS.Position, AESKey192, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamECB(SS, SS.Size - SS.Position, AESKey256, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CBC ģʽֽ +function AESEncryptCbcBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCBC(SS, 0, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCBC(SS, 0, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCBC(SS, 0, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CBC ģʽֽ +function AESDecryptCbcBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCBC(SS, SS.Size - SS.Position, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCBC(SS, SS.Size - SS.Position, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCBC(SS, SS.Size - SS.Position, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CFB ģʽֽ +function AESEncryptCfbBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCFB(SS, 0, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCFB(SS, 0, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCFB(SS, 0, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CFB ģʽֽ +function AESDecryptCfbBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCFB(SS, SS.Size - SS.Position, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCFB(SS, SS.Size - SS.Position, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCFB(SS, SS.Size - SS.Position, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES OFB ģʽֽ +function AESEncryptOfbBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamOFB(SS, 0, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamOFB(SS, 0, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamOFB(SS, 0, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES OFB ģʽֽ +function AESDecryptOfbBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamOFB(SS, SS.Size - SS.Position, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamOFB(SS, SS.Size - SS.Position, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamOFB(SS, SS.Size - SS.Position, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CTR ģʽֽ +function AESEncryptCtrBytes(Value, Key, Nonce, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESCTRIv; + AESNonce: TCnAESCTRNonce; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + + FillChar(AESNonce, SizeOF(AESNonce), 0); + Move(PAnsiChar(Nonce)^, AESNonce, Min(SizeOf(AESNonce), Length(Nonce))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCTR(SS, 0, AESKey128, AESNonce, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCTR(SS, 0, AESKey192, AESNonce, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCTR(SS, 0, AESKey256, AESNonce, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CTR ģʽֽ +function AESDecryptCtrBytes(Value, Key, Nonce, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESCTRIv; + AESNonce: TCnAESCTRNonce; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + + FillChar(AESNonce, SizeOF(AESNonce), 0); + Move(PAnsiChar(Nonce)^, AESNonce, Min(SizeOf(AESNonce), Length(Nonce))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCTR(SS, SS.Size - SS.Position, AESKey128, AESNonce, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCTR(SS, SS.Size - SS.Position, AESKey192, AESNonce, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCTR(SS, SS.Size - SS.Position, AESKey256, AESNonce, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES ECB ģʽֽ鲢תʮ +function AESEncryptEcbBytesToHex(Value, Key: TBytes; KeyBit: TCnKeyBitType): AnsiString; +begin + Result := AnsiString(BytesToHex(AESEncryptEcbBytes(Value, Key, KeyBit))); +end; + +// AES ECB ʮַֽ +function AESDecryptEcbBytesFromHex(const HexStr: AnsiString; Key: TBytes; + KeyBit: TCnKeyBitType): TBytes; +begin + Result := AESDecryptEcbBytes(HexToBytes(string(HexStr)), Key, KeyBit); +end; + +// AES CBC ģʽֽ鲢תʮ +function AESEncryptCbcBytesToHex(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): AnsiString; +begin + Result := AnsiString(BytesToHex(AESEncryptCbcBytes(Value, Key, Iv, KeyBit))); +end; + +// AES CBC ʮַֽ +function AESDecryptCbcBytesFromHex(const HexStr: AnsiString; Key, Iv: TBytes; + KeyBit: TCnKeyBitType): TBytes; +begin + Result := AESDecryptCbcBytes(HexToBytes(string(HexStr)), Key, Iv, KeyBit); +end; + +// AES CFB ģʽֽ鲢תʮ +function AESEncryptCfbBytesToHex(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): AnsiString; +begin + Result := AnsiString(BytesToHex(AESEncryptCfbBytes(Value, Key, Iv, KeyBit))); +end; + +// AES CFB ʮַֽ +function AESDecryptCfbBytesFromHex(const HexStr: AnsiString; Key, Iv: TBytes; + KeyBit: TCnKeyBitType): TBytes; +begin + Result := AESDecryptCfbBytes(HexToBytes(string(HexStr)), Key, Iv, KeyBit); +end; + +// AES OFB ģʽֽ鲢תʮ +function AESEncryptOfbBytesToHex(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): AnsiString; +begin + Result := AnsiString(BytesToHex(AESEncryptOfbBytes(Value, Key, Iv, KeyBit))); +end; + +// AES OFB ʮַֽ +function AESDecryptOfbBytesFromHex(const HexStr: AnsiString; Key, Iv: TBytes; + KeyBit: TCnKeyBitType): TBytes; +begin + Result := AESDecryptOfbBytes(HexToBytes(string(HexStr)), Key, Iv, KeyBit); +end; + +// AES CTR ģʽֽ鲢תʮ +function AESEncryptCtrBytesToHex(Value, Key, Nonce, Iv: TBytes; KeyBit: TCnKeyBitType): AnsiString; +begin + Result := AnsiString(BytesToHex(AESEncryptCtrBytes(Value, Key, Nonce, Iv, KeyBit))); +end; + +// AES CTR ʮַֽ +function AESDecryptCtrBytesFromHex(const HexStr: AnsiString; Key, Nonce, Iv: TBytes; + KeyBit: TCnKeyBitType): TBytes; +begin + Result := AESDecryptCtrBytes(HexToBytes(string(HexStr)), Key, Nonce, Iv, KeyBit); +end; + +end. + diff --git a/CnPack/Crypto/CnBase64.pas b/CnPack/Crypto/CnBase64.pas index cfe7dc1..1aae0e4 100644 --- a/CnPack/Crypto/CnBase64.pas +++ b/CnPack/Crypto/CnBase64.pas @@ -1,547 +1,1070 @@ -{******************************************************************************} -{ CnPack For Delphi/C++Builder } -{ йԼĿԴ } -{ (C)Copyright 2001-2025 CnPack } -{ ------------------------------------ } -{ } -{ ǿԴ CnPack ķЭ } -{ ĺ·һ } -{ } -{ һĿϣãûκεû } -{ ʺضĿĶĵϸ CnPack Э顣 } -{ } -{ ӦѾͿһյһ CnPack Эĸ } -{ ûУɷǵվ } -{ } -{ վַhttps://www.cnpack.org } -{ ʼmaster@cnpack.org } -{ } -{******************************************************************************} - -{ -----------------------------------------------------------------------------} -{ uTBase64 v1.0 - Simple Base64 encoding/decoding class } -{ Base64 described in RFC2045, Page 24, (w) 1996 Freed & Borenstein } -{ Delphi implementation (w) 1999 Dennis D. Spreen (dennis@spreendigital.de) } -{ This unit is freeware. Just drop me a line if this unit is useful for you. } -{ -----------------------------------------------------------------------------} - -unit CnBase64; -{* |
-================================================================================
-* ƣ
-* ԪƣBase64 㷨ʵֵԪ
-* ԪߣղSolin solin@21cn.com; http://www.ilovezhuzhu.net
-*           wr960204
-*           CnPack  (master@cnpack.org)
-*           ݻ Dennis D. Spreen  UTBASE64.pas дԭаȨϢ
-*     עԪʵ˱׼ Base64  Base64URL ı빦ܡ
-*           Base64URL ڱ׼ Base64ѷ + / 滻 - _  URL 
-*           Ѻãɾβ =
-*
-* ƽ̨PWin2003Std + Delphi 6.0
-* ݲԣδ
-*   õԪ豾ػ
-* ޸ļ¼2023.10.04 V1.6
-*               ɾʵ֡Base64Encode  Base64Decode ֧ Base64URL ı
-*           2019.12.12 V1.5
-*               ֧ TBytes
-*           2019.04.15 V1.4
-*               ֧ Win32/Win64/MacOS
-*           2018.06.22 V1.3
-*               ԭʼݿܰ #0 ԭʼβ #0 Ƴ
-*           2016.05.03 V1.2
-*               ַа #0 ʱܻᱻضϵ
-*           2006.10.25 V1.1
-*                wr960204 Ż汾
-*           2003.10.14 V1.0
-*               Ԫ
-================================================================================
-|
} - -interface - -{$I CnPack.inc} - -uses - SysUtils, Classes, CnNative, CnConsts; - -const - ECN_BASE64_OK = ECN_OK; // תɹ - {* Base64 ϵд룺޴ֵΪ 0} - ECN_BASE64_ERROR_BASE = ECN_CUSTOM_ERROR_BASE + $500; - {* Base64 ϵдĻ׼ʼֵΪ ECN_CUSTOM_ERROR_BASE $500} - - ECN_BASE64_LENGTH = ECN_BASE64_ERROR_BASE + 1; - {* Base64 ֮ݳȷǷ} - -function Base64Encode(InputData: TStream; var OutputData: string; - URL: Boolean = False): Integer; overload; -{* Base64 Base64URL 룬ɹ ECN_BASE64_OK - - - InputData: TStream - - var OutputData: string - ַ - URL: Boolean - URL ǡTrue ʹ Base64URL 룬False ʹñ׼ Base64 - - ֵInteger - رǷɹɹ򷵻 ECN_BASE64_OK -} - -function Base64Encode(const InputData: AnsiString; var OutputData: string; - URL: Boolean = False): Integer; overload; -{* ַ Base64 Base64URL 룬ɹ ECN_BASE64_OK - - - const InputData: AnsiString - ַ - var OutputData: string - ַ - URL: Boolean - URL ǡTrue ʹ Base64URL 룬False ʹñ׼ Base64 - - ֵInteger - رǷɹɹ򷵻 ECN_BASE64_OK -} - -function Base64Encode(InputData: Pointer; DataByteLen: Integer; var OutputData: string; - URL: Boolean = False): Integer; overload; -{* ݿ Base64 Base64URL 룬ɹ ECN_BASE64_OK - - - InputData: Pointer - ݿַ - DataByteLen: Integer - ݿֽڳ - var OutputData: string - ַ - URL: Boolean - URL ǡTrue ʹ Base64URL 룬False ʹñ׼ Base64 - - ֵInteger - رǷɹɹ򷵻 ECN_BASE64_OK -} - -function Base64Encode(InputData: TBytes; var OutputData: string; - URL: Boolean = False): Integer; overload; -{* ֽ Base64 Base64URL 룬ɹ ECN_BASE64_OK - - - InputData: TBytes - ֽ - var OutputData: string - ַ - URL: Boolean - URL ǡTrue ʹ Base64URL 룬False ʹñ׼ Base64 - - ֵInteger - رǷɹɹ򷵻 ECN_BASE64_OK -} - -function Base64Decode(const InputData: string; OutputData: TStream; - FixZero: Boolean = True): Integer; overload; -{* ַ Base64 루 Base64URL 룩дɹ ECN_BASE64_OK - - - const InputData: string - ַ - OutputData: TStream - - FixZero: Boolean - Ƿȥβ #0 - - ֵInteger - ؽǷɹɹ򷵻 ECN_BASE64_OK -} - -function Base64Decode(const InputData: string; var OutputData: AnsiString; - FixZero: Boolean = True): Integer; overload; -{* ַ Base64 루 Base64URL 룩дַɹ ECN_BASE64_OK - - - const InputData: string - ַ - var OutputData: AnsiString - ַ - FixZero: Boolean - Ƿȥβ #0 - - ֵInteger - ؽǷɹɹ򷵻 ECN_BASE64_OK -} - -function Base64Decode(const InputData: string; OutputData: Pointer; - DataByteLen: Integer; FixZero: Boolean = True): Integer; overload; -{* ַ Base64 루 Base64URL 룩дڴɹ ECN_BASE64_OK - - - const InputData: string - ַ - OutputData: Pointer - ڴַ - DataByteLen: Integer - ڴֽڳȣӦΪ 1 + (Length(InputData) * 3 / 4) - FixZero: Boolean - Ƿȥβ #0 - - ֵInteger - OutputData nilĽֽڳȡؽǷɹɹ򷵻 ECN_BASE64_OK -} - -function Base64Decode(const InputData: string; out OutputData: TBytes; - FixZero: Boolean = True): Integer; overload; -{* ַ Base64 루 Base64URL 룩дֽ顣ɹ ECN_BASE64_OK - - - const InputData: string - ַ - out OutputData: TBytes - ֽ - FixZero: Boolean - Ƿȥβ #0 - - ֵInteger - ؽǷɹɹ򷵻 ECN_BASE64_OK -} - -implementation - -var - FilterDecodeInput: Boolean = True; - -//------------------------------------------------------------------------------ -// IJο -//------------------------------------------------------------------------------ - - EnCodeTab: array[0..64] of AnsiChar = - ( - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', '+', '/', - '='); - - EnCodeTabURL: array[0..64] of AnsiChar = - ( - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', '-', '_', - '='); - -//------------------------------------------------------------------------------ -// IJο -//------------------------------------------------------------------------------ - - { Base64 ֱַӸ㣬Ҳȡ} - DecodeTable: array[#0..#127] of Byte = - ( - Byte('='), 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, - 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, - 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 62, 00, 62, 00, 63, // ĵһ 62 63 + / - 62 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 00, 00, 00, 00, 00, 00, - 00, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 00, 00, 00, 00, 63, // _ 63 - 00, 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, 00, 00, 00, 00, 00 - ); - -function Base64Encode(InputData: TStream; var OutputData: string; URL: Boolean): Integer; -var - Mem: TMemoryStream; -begin - Mem := TMemoryStream.Create; - try - Mem.CopyFrom(InputData, InputData.Size); - Result := Base64Encode(Mem.Memory, Mem.Size, OutputData, URL); - finally - Mem.Free; - end; -end; - -// Ϊ wr960204 ĽĿ Base64 㷨 -function Base64Encode(InputData: Pointer; DataByteLen: Integer; var OutputData: string; - URL: Boolean): Integer; -var - Times, I: Integer; - X1, X2, X3, X4: AnsiChar; - XT: Byte; -begin - if (InputData = nil) or (DataByteLen <= 0) then - begin - Result := ECN_BASE64_LENGTH; - Exit; - end; - - if DataByteLen mod 3 = 0 then - Times := DataByteLen div 3 - else - Times := DataByteLen div 3 + 1; - SetLength(OutputData, Times * 4); // һηڴ,һδַ,һδͷŷڴ - FillChar(OutputData[1], Length(OutputData) * SizeOf(Char), 0); - - if URL then - begin - for I := 0 to Times - 1 do - begin - if DataByteLen >= (3 + I * 3) then - begin - X1 := EnCodeTabURL[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; - XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; - XT := XT or (Ord(PAnsiChar(InputData)[1 + I * 3]) shr 4); - X2 := EnCodeTabURL[XT]; - XT := (Ord(PAnsiChar(InputData)[1 + I * 3]) shl 2) and 60; - XT := XT or (Ord(PAnsiChar(InputData)[2 + I * 3]) shr 6); - X3 := EnCodeTabURL[XT]; - XT := (Ord(PAnsiChar(InputData)[2 + I * 3]) and 63); - X4 := EnCodeTabURL[XT]; - end - else if DataByteLen >= (2 + I * 3) then - begin - X1 := EnCodeTabURL[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; - XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; - XT := XT or (Ord(PAnsiChar(InputData)[1 + I * 3]) shr 4); - X2 := EnCodeTabURL[XT]; - XT := (Ord(PAnsiChar(InputData)[1 + I * 3]) shl 2) and 60; - X3 := EnCodeTabURL[XT ]; - X4 := '='; - end - else - begin - X1 := EnCodeTabURL[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; - XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; - X2 := EnCodeTabURL[XT]; - X3 := '='; - X4 := '='; - end; - OutputData[I shl 2 + 1] := Char(X1); - OutputData[I shl 2 + 2] := Char(X2); - OutputData[I shl 2 + 3] := Char(X3); - OutputData[I shl 2 + 4] := Char(X4); - end; - end - else - begin - for I := 0 to Times - 1 do - begin - if DataByteLen >= (3 + I * 3) then - begin - X1 := EnCodeTab[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; - XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; - XT := XT or (Ord(PAnsiChar(InputData)[1 + I * 3]) shr 4); - X2 := EnCodeTab[XT]; - XT := (Ord(PAnsiChar(InputData)[1 + I * 3]) shl 2) and 60; - XT := XT or (Ord(PAnsiChar(InputData)[2 + I * 3]) shr 6); - X3 := EnCodeTab[XT]; - XT := (Ord(PAnsiChar(InputData)[2 + I * 3]) and 63); - X4 := EnCodeTab[XT]; - end - else if DataByteLen >= (2 + I * 3) then - begin - X1 := EnCodeTab[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; - XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; - XT := XT or (Ord(PAnsiChar(InputData)[1 + I * 3]) shr 4); - X2 := EnCodeTab[XT]; - XT := (Ord(PAnsiChar(InputData)[1 + I * 3]) shl 2) and 60; - X3 := EnCodeTab[XT ]; - X4 := '='; - end - else - begin - X1 := EnCodeTab[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; - XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; - X2 := EnCodeTab[XT]; - X3 := '='; - X4 := '='; - end; - OutputData[I shl 2 + 1] := Char(X1); - OutputData[I shl 2 + 2] := Char(X2); - OutputData[I shl 2 + 3] := Char(X3); - OutputData[I shl 2 + 4] := Char(X4); - end; - end; - - OutputData := Trim(OutputData); - if URL then - begin - // ɾ OutputData β = ַ - if (Length(OutputData) > 0) and (OutputData[Length(OutputData)] = '=') then - begin - Delete(OutputData, Length(OutputData), 1); - if (Length(OutputData) > 0) and (OutputData[Length(OutputData)] = '=') then - begin - Delete(OutputData, Length(OutputData), 1); - if (Length(OutputData) > 0) and (OutputData[Length(OutputData)] = '=') then - Delete(OutputData, Length(OutputData), 1); - end; - end; - end; - Result := ECN_BASE64_OK; -end; - -function Base64Encode(const InputData: AnsiString; var OutputData: string; URL: Boolean): Integer; -begin - if InputData <> '' then - Result := Base64Encode(@InputData[1], Length(InputData), OutputData, URL) - else - Result := ECN_BASE64_LENGTH; -end; - -function Base64Encode(InputData: TBytes; var OutputData: string; URL: Boolean): Integer; -begin - if Length(InputData) > 0 then - Result := Base64Encode(@InputData[0], Length(InputData), OutputData, URL) - else - Result := ECN_BASE64_LENGTH; -end; - -function Base64Decode(const InputData: string; OutputData: TStream; FixZero: Boolean): Integer; -var - Data: TBytes; -begin - Result := Base64Decode(InputData, Data, FixZero); - if (Result = ECN_BASE64_OK) and (Length(Data) > 0) then - begin - OutputData.Size := Length(Data); - OutputData.Position := 0; - OutputData.Write(Data[0], Length(Data)); - end; -end; - -function Base64Decode(const InputData: string; out OutputData: TBytes; - FixZero: Boolean): Integer; -var - SrcLen, DstLen, Times, I: Integer; - X1, X2, X3, X4, XT: Byte; - C, ToDec: Integer; - Data: AnsiString; - - function FilterLine(const Source: AnsiString): AnsiString; - var - P, PP: PAnsiChar; - I, FL: Integer; - begin - FL := Length(Source); - if FL > 0 then - begin - GetMem(P, FL); // һηڴ,һδַ,һδͷŷڴ - PP := P; - FillChar(P^, FL, 0); - for I := 1 to FL do - begin - if Source[I] in ['0'..'9', 'A'..'Z', 'a'..'z', '+', '/', '=', '-', '_'] then - begin - PP^ := Source[I]; - Inc(PP); - end; - end; - SetString(Result, P, PP - P); // ȡЧ - FreeMem(P); - end; - end; - -begin - if InputData = '' then - begin - Result := ECN_BASE64_OK; - Exit; - end; - OutPutData := nil; - - // D5 ²֪ôIJ AnsiString(InputData)ܻڴֿ - if FilterDecodeInput then - begin -{$IFDEF UNICODE} - Data := FilterLine(AnsiString(InputData)); -{$ELSE} - Data := FilterLine(InputData); -{$ENDIF} - end - else - begin -{$IFDEF UNICODE} - Data := AnsiString(InputData); -{$ELSE} - Data := InputData; -{$ENDIF} - end; - - // Base64URL Ľȥβ =ҪݳǷ 4 ı - if (Length(Data) and $03) <> 0 then - Data := Data + StringOfChar(AnsiChar('='), 4 - (Length(Data) and $03)); - - SrcLen := Length(Data); - DstLen := SrcLen * 3 div 4; - ToDec := 0; - - // βһȺζԭʼݲ˸ #0ȺζŲ #0ҪȥҲ̳ - // עⲻͬԭʼݵβ #0 ȥ - if Data[SrcLen] = '=' then - begin - Inc(ToDec); - if (SrcLen > 1) and (Data[SrcLen - 1] = '=') then - Inc(ToDec); - end; - - SetLength(OutputData, DstLen); // һηڴ,һδַ,һδͷŷڴ - Times := SrcLen div 4; - C := 0; - - for I := 0 to Times - 1 do - begin - X1 := DecodeTable[Data[1 + I shl 2]]; - X2 := DecodeTable[Data[2 + I shl 2]]; - X3 := DecodeTable[Data[3 + I shl 2]]; - X4 := DecodeTable[Data[4 + I shl 2]]; - X1 := X1 shl 2; - XT := X2 shr 4; - X1 := X1 or XT; - X2 := X2 shl 4; - OutputData[C] := X1; - Inc(C); - if X3 = 64 then - Break; - XT := X3 shr 2; - X2 := X2 or XT; - X3 := X3 shl 6; - OutputData[C] := X2; - Inc(C); - if X4 = 64 then - Break; - X3 := X3 or X4; - OutputData[C] := X3; - Inc(C); - end; - - // ݲĵȺĿǷɾβ #0 - while (ToDec > 0) and (OutputData[DstLen - 1] = 0) do - begin - Dec(ToDec); - Dec(DstLen); - end; - SetLength(OutputData, DstLen); - - // ٸⲿҪɾβ #0ʵ̫ʵ - if FixZero then - begin - while (DstLen > 0) and (OutputData[DstLen - 1] = 0) do - Dec(DstLen); - SetLength(OutputData, DstLen); - end; - - Result := ECN_BASE64_OK; -end; - -function Base64Decode(const InputData: string; var OutputData: AnsiString; FixZero: Boolean): Integer; -var - Data: TBytes; -begin - Result := Base64Decode(InputData, Data, FixZero); - if (Result = ECN_BASE64_OK) and (Length(Data) > 0) then - begin - SetLength(OutputData, Length(Data)); - Move(Data[0], OutputData[1], Length(Data)); - end; -end; - -function Base64Decode(const InputData: string; OutputData: Pointer; - DataByteLen: Integer; FixZero: Boolean): Integer; -var - Data: TBytes; -begin - Result := Base64Decode(InputData, Data, FixZero); - if (Result = ECN_BASE64_OK) and (Length(Data) > 0) then - begin - if OutputData = nil then - begin - Result := Length(Data); - Exit; - end; - - if DataByteLen < Length(Data) then - begin - Result := ECN_BASE64_LENGTH; - Exit; - end; - - Move(Data[0], OutPutData^, Length(Data)); - end; -end; - -end. +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +{ -----------------------------------------------------------------------------} +{ uTBase64 v1.0 - Simple Base64 encoding/decoding class } +{ Base64 described in RFC2045, Page 24, (w) 1996 Freed & Borenstein } +{ Delphi implementation (w) 1999 Dennis D. Spreen (dennis@spreendigital.de) } +{ This unit is freeware. Just drop me a line if this unit is useful for you. } +{ -----------------------------------------------------------------------------} + +unit CnBase64; +{* |
+================================================================================
+* ƣ
+* ԪƣBase64/32 㷨ʵֵԪ
+* ԪߣղSolin solin@21cn.com; http://www.ilovezhuzhu.net
+*           wr960204
+*           CnPack  (master@cnpack.org)
+*           ݻ Dennis D. Spreen  UTBASE64.pas дԭаȨϢ
+*     עԪʵ˱׼ Base64  Base64URL ı빦ܣԼ RFC 4648 е
+*           Base32 빦ܣBase16 д HEXʵ֣
+*
+*           Base64URL ڱ׼ Base64ѷ + / 滻 - _  URL 
+*           Ѻãɾβ =
+*
+*           ע벿в FixZero ȥĩβ #0Ǽӽܵ
+*            Base64 ܺڴ˴룬ʱ FixZero ָΪ False
+*           ĩβɳ #0 ʱضӰܽ
+*
+* ƽ̨PWin2003Std + Delphi 6.0
+* ݲԣδ
+*   õԪ豾ػ
+* ޸ļ¼2026.05.11 V1.7
+*                Base32 ıʵ
+*           2023.10.04 V1.6
+*               ɾʵ֡Base64Encode  Base64Decode ֧ Base64URL ı
+*           2019.12.12 V1.5
+*               ֧ TBytes
+*           2019.04.15 V1.4
+*               ֧ Win32/Win64/MacOS
+*           2018.06.22 V1.3
+*               ԭʼݿܰ #0 ԭʼβ #0 Ƴ
+*           2016.05.03 V1.2
+*               ַа #0 ʱܻᱻضϵ
+*           2006.10.25 V1.1
+*                wr960204 Ż汾
+*           2003.10.14 V1.0
+*               Ԫ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes, CnNative, CnConsts; + +const + // + ECN_BASE64_OK = ECN_OK; + {* Base64 ϵд룺޴ֵΪ 0} + + ECN_BASE64_ERROR_BASE = ECN_CUSTOM_ERROR_BASE + $500; + {* Base64 ϵдĻ׼ʼֵΪ ECN_CUSTOM_ERROR_BASE $500} + + ECN_BASE64_LENGTH = ECN_BASE64_ERROR_BASE + 1; + {* Base64 ֮ݳȷǷ} + + ECN_BASE32_OK = ECN_OK; + {* Base32 ϵд룺޴ֵΪ 0} + + ECN_BASE32_LENGTH = ECN_BASE64_LENGTH; + {* Base32 ֮ݳȷǷ} + +function Base64Encode(InputData: TStream; var OutputData: string; + URL: Boolean = False): Integer; overload; +{* Base64 Base64URL 룬ɹ ECN_BASE64_OK + + + InputData: TStream - + var OutputData: string - ַ + URL: Boolean - URL ǡTrue ʹ Base64URL 룬False ʹñ׼ Base64 + + ֵInteger - رǷɹɹ򷵻 ECN_BASE64_OK +} + +function Base64Encode(const InputData: AnsiString; var OutputData: string; + URL: Boolean = False): Integer; overload; +{* ַ Base64 Base64URL 룬ɹ ECN_BASE64_OK + + + const InputData: AnsiString - ַ + var OutputData: string - ַ + URL: Boolean - URL ǡTrue ʹ Base64URL 룬False ʹñ׼ Base64 + + ֵInteger - رǷɹɹ򷵻 ECN_BASE64_OK +} + +function Base64Encode(InputData: Pointer; DataByteLen: Integer; var OutputData: string; + URL: Boolean = False): Integer; overload; +{* ݿ Base64 Base64URL 룬ɹ ECN_BASE64_OK + + + InputData: Pointer - ݿַ + DataByteLen: Integer - ݿֽڳ + var OutputData: string - ַ + URL: Boolean - URL ǡTrue ʹ Base64URL 룬False ʹñ׼ Base64 + + ֵInteger - رǷɹɹ򷵻 ECN_BASE64_OK +} + +function Base64Encode(const InputData: TBytes; var OutputData: string; + URL: Boolean = False): Integer; overload; +{* ֽ Base64 Base64URL 룬ɹ ECN_BASE64_OK + + + const InputData: TBytes - ֽ + var OutputData: string - ַ + URL: Boolean - URL ǡTrue ʹ Base64URL 룬False ʹñ׼ Base64 + + ֵInteger - رǷɹɹ򷵻 ECN_BASE64_OK +} + +function Base64Decode(const InputData: string; OutputData: TStream; + FixZero: Boolean = True): Integer; overload; +{* ַ Base64 루 Base64URL 룩дɹ ECN_BASE64_OK + + + const InputData: string - ַ + OutputData: TStream - + FixZero: Boolean - Ƿȥβ #0 + + ֵInteger - ؽǷɹɹ򷵻 ECN_BASE64_OK +} + +function Base64Decode(const InputData: string; var OutputData: AnsiString; + FixZero: Boolean = True): Integer; overload; +{* ַ Base64 루 Base64URL 룩дַɹ ECN_BASE64_OK + + + const InputData: string - ַ + var OutputData: AnsiString - ַ + FixZero: Boolean - Ƿȥβ #0 + + ֵInteger - ؽǷɹɹ򷵻 ECN_BASE64_OK +} + +function Base64Decode(const InputData: string; OutputData: Pointer; + DataByteLen: Integer; FixZero: Boolean = True): Integer; overload; +{* ַ Base64 루 Base64URL 룩дڴɹ ECN_BASE64_OK + + + const InputData: string - ַ + OutputData: Pointer - ڴַ + DataByteLen: Integer - ڴֽڳȣӦΪ 1 + (Length(InputData) * 3 / 4) + FixZero: Boolean - Ƿȥβ #0 + + ֵInteger - OutputData nilĽֽڳȡؽǷɹɹ򷵻 ECN_BASE64_OK +} + +function Base64Decode(const InputData: string; out OutputData: TBytes; + FixZero: Boolean = True): Integer; overload; +{* ַ Base64 루 Base64URL 룩дֽ顣ɹ ECN_BASE64_OK + + + const InputData: string - ַ + out OutputData: TBytes - ֽ + FixZero: Boolean - Ƿȥβ #0 + + ֵInteger - ؽǷɹɹ򷵻 ECN_BASE64_OK +} + +function Base64IsStrictText(const InputData: string; AllowURLSafe: Boolean = False): Boolean; +{* жַǷϸϷ Base64 ַݼ볤ȼ⡣ + + + const InputData: string - жϵַ + AllowURLSafe: Boolean - Ƿʹ URL ȫַ + + ֵBoolean - ǷϸϷ Base64 ַ +} + +function Base32Encode(InputData: TStream; var OutputData: string): Integer; overload; +{* Base32 룬ɹ ECN_BASE32_OK + + + InputData: TStream - + var OutputData: string - ַ + + ֵInteger - رǷɹɹ򷵻 ECN_BASE32_OK +} + +function Base32Encode(const InputData: AnsiString; var OutputData: string): Integer; overload; +{* ַ Base32 룬ɹ ECN_BASE32_OK + + + const InputData: AnsiString - ַ + var OutputData: string - ַ + + ֵInteger - رǷɹɹ򷵻 ECN_BASE32_OK +} + +function Base32Encode(InputData: Pointer; DataByteLen: Integer; var OutputData: string): Integer; overload; +{* ݿ Base32 룬ɹ ECN_BASE32_OK + + + InputData: Pointer - ݿַ + DataByteLen: Integer - ݿֽڳ + var OutputData: string - ַ + + ֵInteger - رǷɹɹ򷵻 ECN_BASE32_OK +} + +function Base32Encode(const InputData: TBytes; var OutputData: string): Integer; overload; +{* ֽ Base32 룬ɹ ECN_BASE32_OK + + + const InputData: TBytes - ֽ + var OutputData: string - ַ + + ֵInteger - رǷɹɹ򷵻 ECN_BASE32_OK +} + +function Base32Decode(const InputData: string; OutputData: TStream): Integer; overload; +{* ַ Base32 룬дɹ ECN_BASE32_OK + + + const InputData: string - ַ + OutputData: TStream - + + ֵInteger - ؽǷɹɹ򷵻 ECN_BASE32_OK +} + +function Base32Decode(const InputData: string; var OutputData: AnsiString): Integer; overload; +{* ַ Base32 룬дַɹ ECN_BASE32_OK + + + const InputData: string - ַ + var OutputData: AnsiString - ַ + + ֵInteger - ؽǷɹɹ򷵻 ECN_BASE32_OK +} + +function Base32Decode(const InputData: string; OutputData: Pointer; + DataByteLen: Integer): Integer; overload; +{* ַ Base32 룬дڴɹ ECN_BASE32_OK + + + const InputData: string - ַ + OutputData: Pointer - ڴַ + DataByteLen: Integer - ڴֽڳȣӦΪ 1 + (Length(InputData) * 5 / 8) + + ֵInteger - OutputData nilĽֽڳȡؽǷɹɹ򷵻 ECN_BASE32_OK +} + +function Base32Decode(const InputData: string; out OutputData: TBytes): Integer; overload; +{* ַ Base32 룬дֽ顣ɹ ECN_BASE32_OK + + + const InputData: string - ַ + out OutputData: TBytes - ֽ + + ֵInteger - ؽǷɹɹ򷵻 ECN_BASE32_OK +} + +function Base32IsStrictText(const InputData: string): Boolean; +{* жַǷϸϷ Base32 ַݼ볤ȼ⡣ + + + const InputData: string - жϵַ + + ֵBoolean - ǷϸϷ Base32 ַ +} + +implementation + +var + FilterDecodeInput: Boolean = True; + +//------------------------------------------------------------------------------ +// IJο +//------------------------------------------------------------------------------ + + EnCodeTab64: array[0..64] of AnsiChar = + ( + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/', + '='); + + EnCodeTab64URL: array[0..64] of AnsiChar = + ( + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '-', '_', + '='); + + EnCodeTab32: array[0..32] of AnsiChar = + ( + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', '2', '3', '4', '5', '6', '7', + '=' + ); + +//------------------------------------------------------------------------------ +// IJο +//------------------------------------------------------------------------------ + + { Base64 ֱַӸ㣬Ҳȡ} + DecodeTable64: array[#0..#127] of Byte = + ( + Byte('='), 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 62, 00, 62, 00, 63, // ĵһ 62 63 + / - 62 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 00, 00, 00, 00, 00, 00, + 00, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 00, 00, 00, 00, 63, // _ 63 + 00, 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, 00, 00, 00, 00, 00 + ); + +// Ϊ wr960204 ĽĿ Base64 㷨 +function Base64Encode(InputData: Pointer; DataByteLen: Integer; + var OutputData: string; URL: Boolean): Integer; +var + Times, I: Integer; + X1, X2, X3, X4: AnsiChar; + XT: Byte; +begin + if (InputData = nil) or (DataByteLen <= 0) then + begin + Result := ECN_BASE64_LENGTH; + Exit; + end; + + if DataByteLen mod 3 = 0 then + Times := DataByteLen div 3 + else + Times := DataByteLen div 3 + 1; + SetLength(OutputData, Times * 4); // һηڴ,һδַ,һδͷŷڴ + FillChar(OutputData[1], Length(OutputData) * SizeOf(Char), 0); + + if URL then + begin + for I := 0 to Times - 1 do + begin + if DataByteLen >= (3 + I * 3) then + begin + X1 := EnCodeTab64URL[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + XT := XT or (Ord(PAnsiChar(InputData)[1 + I * 3]) shr 4); + X2 := EnCodeTab64URL[XT]; + XT := (Ord(PAnsiChar(InputData)[1 + I * 3]) shl 2) and 60; + XT := XT or (Ord(PAnsiChar(InputData)[2 + I * 3]) shr 6); + X3 := EnCodeTab64URL[XT]; + XT := (Ord(PAnsiChar(InputData)[2 + I * 3]) and 63); + X4 := EnCodeTab64URL[XT]; + end + else if DataByteLen >= (2 + I * 3) then + begin + X1 := EnCodeTab64URL[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + XT := XT or (Ord(PAnsiChar(InputData)[1 + I * 3]) shr 4); + X2 := EnCodeTab64URL[XT]; + XT := (Ord(PAnsiChar(InputData)[1 + I * 3]) shl 2) and 60; + X3 := EnCodeTab64URL[XT ]; + X4 := '='; + end + else + begin + X1 := EnCodeTab64URL[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + X2 := EnCodeTab64URL[XT]; + X3 := '='; + X4 := '='; + end; + OutputData[I shl 2 + 1] := Char(X1); + OutputData[I shl 2 + 2] := Char(X2); + OutputData[I shl 2 + 3] := Char(X3); + OutputData[I shl 2 + 4] := Char(X4); + end; + end + else + begin + for I := 0 to Times - 1 do + begin + if DataByteLen >= (3 + I * 3) then + begin + X1 := EnCodeTab64[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + XT := XT or (Ord(PAnsiChar(InputData)[1 + I * 3]) shr 4); + X2 := EnCodeTab64[XT]; + XT := (Ord(PAnsiChar(InputData)[1 + I * 3]) shl 2) and 60; + XT := XT or (Ord(PAnsiChar(InputData)[2 + I * 3]) shr 6); + X3 := EnCodeTab64[XT]; + XT := (Ord(PAnsiChar(InputData)[2 + I * 3]) and 63); + X4 := EnCodeTab64[XT]; + end + else if DataByteLen >= (2 + I * 3) then + begin + X1 := EnCodeTab64[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + XT := XT or (Ord(PAnsiChar(InputData)[1 + I * 3]) shr 4); + X2 := EnCodeTab64[XT]; + XT := (Ord(PAnsiChar(InputData)[1 + I * 3]) shl 2) and 60; + X3 := EnCodeTab64[XT ]; + X4 := '='; + end + else + begin + X1 := EnCodeTab64[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + X2 := EnCodeTab64[XT]; + X3 := '='; + X4 := '='; + end; + OutputData[I shl 2 + 1] := Char(X1); + OutputData[I shl 2 + 2] := Char(X2); + OutputData[I shl 2 + 3] := Char(X3); + OutputData[I shl 2 + 4] := Char(X4); + end; + end; + + OutputData := Trim(OutputData); + if URL then + begin + // ɾ OutputData β = ַ + if (Length(OutputData) > 0) and (OutputData[Length(OutputData)] = '=') then + begin + Delete(OutputData, Length(OutputData), 1); + if (Length(OutputData) > 0) and (OutputData[Length(OutputData)] = '=') then + begin + Delete(OutputData, Length(OutputData), 1); + if (Length(OutputData) > 0) and (OutputData[Length(OutputData)] = '=') then + Delete(OutputData, Length(OutputData), 1); + end; + end; + end; + Result := ECN_BASE64_OK; +end; + +function Base64Encode(InputData: TStream; var OutputData: string; URL: Boolean): Integer; +var + Mem: TMemoryStream; +begin + Mem := TMemoryStream.Create; + try + Mem.CopyFrom(InputData, InputData.Size); + Result := Base64Encode(Mem.Memory, Mem.Size, OutputData, URL); + finally + Mem.Free; + end; +end; + +function Base64Encode(const InputData: AnsiString; var OutputData: string; URL: Boolean): Integer; +begin + if InputData <> '' then + Result := Base64Encode(@InputData[1], Length(InputData), OutputData, URL) + else + Result := ECN_BASE64_LENGTH; +end; + +function Base64Encode(const InputData: TBytes; var OutputData: string; URL: Boolean): Integer; +begin + if Length(InputData) > 0 then + Result := Base64Encode(@InputData[0], Length(InputData), OutputData, URL) + else + Result := ECN_BASE64_LENGTH; +end; + +function Base64Decode(const InputData: string; OutputData: TStream; FixZero: Boolean): Integer; +var + Data: TBytes; +begin + Result := Base64Decode(InputData, Data, FixZero); + if (Result = ECN_BASE64_OK) and (Length(Data) > 0) then + begin + OutputData.Size := Length(Data); + OutputData.Position := 0; + OutputData.Write(Data[0], Length(Data)); + end; +end; + +function Base64Decode(const InputData: string; out OutputData: TBytes; + FixZero: Boolean): Integer; +var + SrcLen, DstLen, Times, I: Integer; + X1, X2, X3, X4, XT: Byte; + C, ToDec: Integer; + Data: AnsiString; + + function FilterLine(const Source: AnsiString): AnsiString; + var + P, PP: PAnsiChar; + I, FL: Integer; + begin + FL := Length(Source); + if FL > 0 then + begin + GetMem(P, FL); // һηڴ,һδַ,һδͷŷڴ + PP := P; + FillChar(P^, FL, 0); + for I := 1 to FL do + begin + if Source[I] in ['0'..'9', 'A'..'Z', 'a'..'z', '+', '/', '=', '-', '_'] then + begin + PP^ := Source[I]; + Inc(PP); + end; + end; + SetString(Result, P, PP - P); // ȡЧ + FreeMem(P); + end; + end; + +begin + if InputData = '' then + begin + Result := ECN_BASE64_OK; + Exit; + end; + OutPutData := nil; + + // D5 ²֪ôIJ AnsiString(InputData)ܻڴֿ + if FilterDecodeInput then + begin +{$IFDEF UNICODE} + Data := FilterLine(AnsiString(InputData)); +{$ELSE} + Data := FilterLine(InputData); +{$ENDIF} + end + else + begin +{$IFDEF UNICODE} + Data := AnsiString(InputData); +{$ELSE} + Data := InputData; +{$ENDIF} + end; + + // Base64URL Ľȥβ =ҪݳǷ 4 ı + if (Length(Data) and $03) <> 0 then + Data := Data + StringOfChar(AnsiChar('='), 4 - (Length(Data) and $03)); + + SrcLen := Length(Data); + DstLen := SrcLen * 3 div 4; + ToDec := 0; + + // βһȺζԭʼݲ˸ #0ȺζŲ #0ҪȥҲ̳ + // עⲻͬԭʼݵβ #0 ȥ + if Data[SrcLen] = '=' then + begin + Inc(ToDec); + if (SrcLen > 1) and (Data[SrcLen - 1] = '=') then + Inc(ToDec); + end; + + SetLength(OutputData, DstLen); // һηڴ,һδַ,һδͷŷڴ + Times := SrcLen div 4; + C := 0; + + for I := 0 to Times - 1 do + begin + X1 := DecodeTable64[Data[1 + I shl 2]]; + X2 := DecodeTable64[Data[2 + I shl 2]]; + X3 := DecodeTable64[Data[3 + I shl 2]]; + X4 := DecodeTable64[Data[4 + I shl 2]]; + X1 := Byte(X1 shl 2); + XT := Byte(X2 shr 4); + X1 := Byte(X1 or XT); + X2 := Byte(X2 shl 4); + OutputData[C] := X1; + Inc(C); + if X3 = 64 then + Break; + XT := Byte(X3 shr 2); + X2 := Byte(X2 or XT); + X3 := Byte(X3 shl 6); + OutputData[C] := X2; + Inc(C); + if X4 = 64 then + Break; + X3 := Byte(X3 or X4); + OutputData[C] := X3; + Inc(C); + end; + + // ݲĵȺĿǷɾβ #0 + while (ToDec > 0) and (OutputData[DstLen - 1] = 0) do + begin + Dec(ToDec); + Dec(DstLen); + end; + SetLength(OutputData, DstLen); + + // ٸⲿҪɾβ #0ʵ̫ʵ + if FixZero then + begin + while (DstLen > 0) and (OutputData[DstLen - 1] = 0) do + Dec(DstLen); + SetLength(OutputData, DstLen); + end; + + Result := ECN_BASE64_OK; +end; + +function Base64Decode(const InputData: string; var OutputData: AnsiString; FixZero: Boolean): Integer; +var + Data: TBytes; +begin + Result := Base64Decode(InputData, Data, FixZero); + if (Result = ECN_BASE64_OK) and (Length(Data) > 0) then + begin + SetLength(OutputData, Length(Data)); + Move(Data[0], OutputData[1], Length(Data)); + end; +end; + +function Base64Decode(const InputData: string; OutputData: Pointer; + DataByteLen: Integer; FixZero: Boolean): Integer; +var + Data: TBytes; +begin + Result := Base64Decode(InputData, Data, FixZero); + if (Result = ECN_BASE64_OK) and (Length(Data) > 0) then + begin + if OutputData = nil then + begin + Result := Length(Data); + Exit; + end; + + if DataByteLen < Length(Data) then + begin + Result := ECN_BASE64_LENGTH; + Exit; + end; + + Move(Data[0], OutPutData^, Length(Data)); + end; +end; + +function Base64IsStrictText(const InputData: string; AllowURLSafe: Boolean): Boolean; +var + I, EqPos: Integer; + Ch: Char; +begin + Result := False; + if InputData = '' then + Exit; + + if AllowURLSafe then + begin + for I := 1 to Length(InputData) do + begin + Ch := InputData[I]; + if not (Ch in ['A'..'Z', 'a'..'z', '0'..'9', '-', '_', '=']) then + Exit; + end; + end + else + begin + for I := 1 to Length(InputData) do + begin + Ch := InputData[I]; + if not (Ch in ['A'..'Z', 'a'..'z', '0'..'9', '+', '/', '=']) then + Exit; + end; + end; + + if (Length(InputData) mod 4) <> 0 then + Exit; + + EqPos := Pos('=', InputData); + if EqPos > 0 then + begin + for I := EqPos to Length(InputData) do + if InputData[I] <> '=' then + Exit; + + if (Length(InputData) - EqPos + 1) > 2 then + Exit; + end; + + Result := True; +end; + +function Base32Encode(InputData: Pointer; DataByteLen: Integer; + var OutputData: string): Integer; +var + Times, I, J, Remain, DataPos, OutPos: Integer; + B0, B1, B2, B3, B4: Byte; + Chars: array[0..7] of Byte; +begin + if (InputData = nil) or (DataByteLen <= 0) then + begin + Result := ECN_BASE32_LENGTH; + Exit; + end; + + Times := DataByteLen div 5; + if (DataByteLen mod 5) <> 0 then + Inc(Times); + + SetLength(OutputData, Times * 8); + FillChar(OutputData[1], Length(OutputData) * SizeOf(Char), 0); + + for I := 0 to Times - 1 do + begin + DataPos := I * 5; + Remain := DataByteLen - DataPos; + if Remain > 5 then + Remain := 5; + + B0 := 0; + B1 := 0; + B2 := 0; + B3 := 0; + B4 := 0; + if Remain > 0 then B0 := Byte(PAnsiChar(InputData)[DataPos]); + if Remain > 1 then B1 := Byte(PAnsiChar(InputData)[DataPos + 1]); + if Remain > 2 then B2 := Byte(PAnsiChar(InputData)[DataPos + 2]); + if Remain > 3 then B3 := Byte(PAnsiChar(InputData)[DataPos + 3]); + if Remain > 4 then B4 := Byte(PAnsiChar(InputData)[DataPos + 4]); + + Chars[0] := (B0 shr 3) and $1F; + Chars[1] := ((B0 and $07) shl 2) or (B1 shr 6); + Chars[2] := (B1 shr 1) and $1F; + Chars[3] := ((B1 and $01) shl 4) or (B2 shr 4); + Chars[4] := ((B2 and $0F) shl 1) or (B3 shr 7); + Chars[5] := (B3 shr 2) and $1F; + Chars[6] := ((B3 and $03) shl 3) or (B4 shr 5); + Chars[7] := B4 and $1F; + + OutPos := I * 8 + 1; + for J := 0 to 7 do + OutputData[OutPos + J] := Char(EnCodeTab32[Chars[J]]); + + case Remain of + 1: + begin + OutputData[OutPos + 2] := '='; + OutputData[OutPos + 3] := '='; + OutputData[OutPos + 4] := '='; + OutputData[OutPos + 5] := '='; + OutputData[OutPos + 6] := '='; + OutputData[OutPos + 7] := '='; + end; + 2: + begin + OutputData[OutPos + 4] := '='; + OutputData[OutPos + 5] := '='; + OutputData[OutPos + 6] := '='; + OutputData[OutPos + 7] := '='; + end; + 3: + begin + OutputData[OutPos + 5] := '='; + OutputData[OutPos + 6] := '='; + OutputData[OutPos + 7] := '='; + end; + 4: + OutputData[OutPos + 7] := '='; + end; + end; + + Result := ECN_BASE32_OK; +end; + +function Base32Encode(InputData: TStream; var OutputData: string): Integer; +var + Mem: TMemoryStream; +begin + Mem := TMemoryStream.Create; + try + Mem.CopyFrom(InputData, InputData.Size); + Result := Base32Encode(Mem.Memory, Mem.Size, OutputData); + finally + Mem.Free; + end; +end; + +function Base32Encode(const InputData: AnsiString; var OutputData: string): Integer; +begin + if InputData <> '' then + Result := Base32Encode(@InputData[1], Length(InputData), OutputData) + else + Result := ECN_BASE32_LENGTH; +end; + +function Base32Encode(const InputData: TBytes; var OutputData: string): Integer; +begin + if Length(InputData) > 0 then + Result := Base32Encode(@InputData[0], Length(InputData), OutputData) + else + Result := ECN_BASE32_LENGTH; +end; + +function Base32Decode(const InputData: string; out OutputData: TBytes): Integer; +var + Data: AnsiString; + SrcLen, Times, I, J, C, PadCnt, DstLen, BlockPad: Integer; + V: array[0..7] of Byte; + Ch: AnsiChar; + + function FilterLine(const Source: AnsiString): AnsiString; + var + P, PP: PAnsiChar; + I, FL: Integer; + C: AnsiChar; + begin + Result := ''; + FL := Length(Source); + if FL > 0 then + begin + GetMem(P, FL); + PP := P; + FillChar(P^, FL, 0); + for I := 1 to FL do + begin + C := Source[I]; + if C in ['a'..'z'] then + C := AnsiChar(Ord(C) - 32); + if C in ['A'..'Z', '2'..'7', '='] then + begin + PP^ := C; + Inc(PP); + end; + end; + SetString(Result, P, PP - P); + FreeMem(P); + end; + end; + + function DecodeChar32(C: AnsiChar; out Value: Byte): Boolean; + begin + if C in ['A'..'Z'] then + begin + Value := Ord(C) - Ord('A'); + Result := True; + Exit; + end; + if C in ['2'..'7'] then + begin + Value := Ord(C) - Ord('2') + 26; + Result := True; + Exit; + end; + Result := False; + end; + +begin + OutPutData := nil; + if InputData = '' then + begin + Result := ECN_BASE32_OK; + Exit; + end; + +{$IFDEF UNICODE} + Data := FilterLine(AnsiString(InputData)); +{$ELSE} + Data := FilterLine(InputData); +{$ENDIF} + + SrcLen := Length(Data); + if (SrcLen = 0) or ((SrcLen mod 8) <> 0) then + begin + Result := ECN_BASE32_LENGTH; + Exit; + end; + +{$IFDEF UNICODE} + if not Base32IsStrictText(string(Data)) then +{$ELSE} + if not Base32IsStrictText(Data) then +{$ENDIF} + begin + Result := ECN_BASE32_LENGTH; + Exit; + end; + + PadCnt := 0; + while (PadCnt < SrcLen) and (Data[SrcLen - PadCnt] = '=') do + Inc(PadCnt); + + DstLen := (SrcLen div 8) * 5; + case PadCnt of + 0: ; + 1: Dec(DstLen, 1); + 3: Dec(DstLen, 2); + 4: Dec(DstLen, 3); + 6: Dec(DstLen, 4); + else + begin + Result := ECN_BASE32_LENGTH; + Exit; + end; + end; + + SetLength(OutputData, DstLen); + Times := SrcLen div 8; + C := 0; + + for I := 0 to Times - 1 do + begin + BlockPad := 0; + for J := 0 to 7 do + begin + Ch := Data[I * 8 + J + 1]; + if Ch = '=' then + begin + V[J] := 0; + Inc(BlockPad); + end + else if DecodeChar32(Ch, V[J]) then + begin + // do nothing + end + else + begin + Result := ECN_BASE32_LENGTH; + Exit; + end; + end; + + OutputData[C] := Byte((V[0] shl 3) or (V[1] shr 2)); + Inc(C); + if BlockPad = 6 then + Continue; + + OutputData[C] := Byte((V[1] shl 6) or (V[2] shl 1) or (V[3] shr 4)); + Inc(C); + if BlockPad = 4 then + Continue; + + OutputData[C] := Byte((V[3] shl 4) or (V[4] shr 1)); + Inc(C); + if BlockPad = 3 then + Continue; + + OutputData[C] := Byte((V[4] shl 7) or (V[5] shl 2) or (V[6] shr 3)); + Inc(C); + if BlockPad = 1 then + Continue; + + OutputData[C] := Byte((V[6] shl 5) or V[7]); + Inc(C); + end; + + Result := ECN_BASE32_OK; +end; + +function Base32Decode(const InputData: string; OutputData: TStream): Integer; +var + Data: TBytes; +begin + Result := Base32Decode(InputData, Data); + if (Result = ECN_BASE32_OK) and (Length(Data) > 0) then + begin + OutputData.Size := Length(Data); + OutputData.Position := 0; + OutputData.Write(Data[0], Length(Data)); + end; +end; + +function Base32Decode(const InputData: string; var OutputData: AnsiString): Integer; +var + Data: TBytes; +begin + Result := Base32Decode(InputData, Data); + if (Result = ECN_BASE32_OK) and (Length(Data) > 0) then + begin + SetLength(OutputData, Length(Data)); + Move(Data[0], OutputData[1], Length(Data)); + end; +end; + +function Base32Decode(const InputData: string; OutputData: Pointer; + DataByteLen: Integer): Integer; +var + Data: TBytes; +begin + Result := Base32Decode(InputData, Data); + if (Result = ECN_BASE32_OK) and (Length(Data) > 0) then + begin + if OutputData = nil then + begin + Result := Length(Data); + Exit; + end; + + if DataByteLen < Length(Data) then + begin + Result := ECN_BASE32_LENGTH; + Exit; + end; + + Move(Data[0], OutPutData^, Length(Data)); + end; +end; + +function Base32IsStrictText(const InputData: string): Boolean; +var + I, EqPos, EC: Integer; + Ch: Char; +begin + Result := False; + if InputData = '' then + Exit; + + for I := 1 to Length(InputData) do + begin + Ch := InputData[I]; + if not (Ch in ['A'..'Z', '2'..'7', '=']) then + Exit; + end; + + if (Length(InputData) mod 8) <> 0 then + Exit; + + EqPos := Pos('=', InputData); + if EqPos > 0 then + begin + for I := EqPos to Length(InputData) do + begin + if InputData[I] <> '=' then + Exit; + end; + + EC := Length(InputData) - EqPos + 1; + if (EC = 2) or (EC = 5) or (EC > 6) then + Exit; + end; + + Result := True; +end; + +end. diff --git a/CnPack/Crypto/CnDES.pas b/CnPack/Crypto/CnDES.pas index c255235..7acfcb4 100644 --- a/CnPack/Crypto/CnDES.pas +++ b/CnPack/Crypto/CnDES.pas @@ -1,1973 +1,1973 @@ -{******************************************************************************} -{ CnPack For Delphi/C++Builder } -{ йԼĿԴ } -{ (C)Copyright 2001-2025 CnPack } -{ ------------------------------------ } -{ } -{ ǿԴ CnPack ķЭ } -{ ĺ·һ } -{ } -{ һĿϣãûκεû } -{ ʺضĿĶĵϸ CnPack Э顣 } -{ } -{ ӦѾͿһյһ CnPack Эĸ } -{ ûУɷǵվ } -{ } -{ վַhttps://www.cnpack.org } -{ ʼmaster@cnpack.org } -{ } -{******************************************************************************} - -unit CnDES; -{* |
-================================================================================
-* ƣ
-* ԪƣDES ԳƼӽ㷨ʵֵԪ
-* ԪߣCnPack  (master@cnpack.org)
-*           /ֲ䲿ֹܡ
-*     עԪʵ DES/3DES ԳƼӽ㷨ֿС 8 ֽڣʵ
-*           ECB/CBC ģʽ֧ģʽ
-*
-* ƽ̨PWin2000Pro + Delphi 5.0
-* ݲԣPWin9X/2000/XP + Delphi 5/6
-*   õԪеַϱػʽ
-* ޸ļ¼2024.11.30 V1.7
-*               ɾ淶 DESEncryptStrToHex  DESDecryptStrToHex
-*               ɾ淶 TripleDESEncryptStrToHex  TripleDESDecryptStrToHex
-*                ECB 汾
-*               Ż PAnsiChar ʽ Iv Ĵ
-*           2024.10.12 V1.6
-*                3DES ²Խ⣬Ż Key  Iv Ķ봦
-*           2022.08.13 V1.5
-*               Կݼܷؿ
-*           2021.02.07 V1.4
-*               Ӷ TBytes ֧
-*           2020.03.25 V1.3
-*                3DES ֧
-*           2020.03.24 V1.2
-*                ECB/CBC ַӽܺɾԭеַܺ
-*           2019.04.15 V1.1
-*               ֧ Win32/Win64/MacOS
-*           2008.05.30 V1.0
-*               Ԫ
-================================================================================
-|
} - -interface - -{$I CnPack.inc} - -uses - SysUtils, Classes, CnNative; - -const - CN_DES_KEYSIZE = 8; - {* DES Կȣ8 ֽ} - - CN_DES_BLOCKSIZE = 8; - {* DES ļܿ鳤ȣ8 ֽ} - - CN_TRIPLE_DES_KEYSIZE = CN_DES_KEYSIZE * 3; - {* 3DES Կȣ DES 24 ֽ} - - CN_TRIPLE_DES_BLOCKSIZE = CN_DES_BLOCKSIZE; - {* 3DES ļܿ鳤ȣ 8 ֽ} - -type - ECnDESException = class(Exception); - {* DES 쳣} - - TCnDESKey = array[0..CN_DES_KEYSIZE - 1] of Byte; - {* DES ļ Key8 ֽ} - - TCnDESBuffer = array[0..CN_DES_BLOCKSIZE - 1] of Byte; - {* DES ļܿ飬8 ֽ} - - TCnDESIv = array[0..CN_DES_BLOCKSIZE - 1] of Byte; - {* DES CBC ijʼ8 ֽ} - - TCn3DESKey = array[0..CN_TRIPLE_DES_KEYSIZE - 1] of Byte; - {* 3DES Կȣ DES 24 ֽ} - - TCn3DESBuffer = TCnDESBuffer; - {* 3DES ļܿ飬 DES ļܿ飬8 ֽ} - - TCn3DESIv = TCnDESIv; - {* 3DES CBC ijʼ DES CBC ijʼ8 ֽ} - -// ================================= DES ======================================= - -function DESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; -{* ֽڳȼ DES ȡǿ - - - InputByteLength: Integer - ֽڳ - - ֵInteger - DES ij -} - -procedure DESEncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); -{* AnsiString DES ܣʹ ECB ģʽ - - - Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 - const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı - Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 - - ֵޣ -} - -procedure DESDecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); -{* AnsiString DES ܣʹ ECB ģʽ - - - Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 - const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı - Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 - - ֵޣ -} - -procedure DESEncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; const Input: AnsiString; - Output: PAnsiChar); -{* AnsiString DES ܣʹ CBC ģʽ - - - Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 - Iv: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ - const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı - Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 - - ֵޣ -} - -procedure DESDecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; const Input: AnsiString; - Output: PAnsiChar); -{* AnsiString DES ܣʹ CBC ģʽ - - - Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 - Iv: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ - const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı - Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 - - ֵޣ -} - -function DESEncryptEcbStrToHex(const Str: AnsiString; const Key: AnsiString): AnsiString; -{* KeyDES ܷתʮƵģʹ ECB ģʽĩβܲ #0 - - - const Str: AnsiString - ַܵ - const Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 - - ֵAnsiString - ؼܺʮַ -} - -function DESDecryptEcbStrFromHex(const HexStr: AnsiString; const Key: AnsiString): AnsiString; -{* ʮƵ KeyDES ܷģʹ ECB ģʽ - - - const HexStr: AnsiString - ܵʮַ - const Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 - - ֵAnsiString - ؽַܺ -} - -function DESEncryptCbcStrToHex(const Str: AnsiString; const Key: AnsiString; const Iv: AnsiString): AnsiString; -{* Key IvDES ܷתʮƵģʹ CBC ģʽĩβܲ #0 - - - const Str: AnsiString - ַܵ - const Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 - const Iv: AnsiString - 8 ֽڳʼ - - ֵAnsiString - ؼܺʮַ -} - -function DESDecryptCbcStrFromHex(const HexStr: AnsiString; const Key: AnsiString; - const Iv: AnsiString): AnsiString; -{* ʮƵ Key IvDES ܷģʹ ECB ģʽ - - - const HexStr: AnsiString - ܵʮַ - const Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 - const Iv: AnsiString - 8 ֽڳʼ - - ֵAnsiString - ؽַܺ -} - -function DESEncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; -{* ֽ DES ܣʹ ECB ģʽ - - - Key: TBytes - 8 ֽ DES Կ̫ضϣ 0 - Input: TBytes - ֽܵ飬䳤粻 8 ʱᱻ 0 ȴﵽ 8 ı - - ֵTBytes - ؼֽܺ -} - -function DESDecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; -{* ֽ DES ܣʹ ECB ģʽ - - - Key: TBytes - 8 ֽ DES Կ̫ضϣ 0 - Input: TBytes - ֽܵ飬䳤粻 8 ʱᱻ 0 ȴﵽ 8 ı - - ֵTBytes - ؽֽܺ -} - -function DESEncryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; -{* ֽ DES ܣʹ CBC ģʽ - - - Key: TBytes - 8 ֽ DES Կ̫ضϣ 0 - Iv: TBytes - 8 ֽڳʼ̫ضϣ 0 - Input: TBytes - ֽܵ - - ֵTBytes - ؼֽܺ -} - -function DESDecryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; -{* ֽ DES ܣʹ CBC ģʽ - - - Key: TBytes - 8 ֽ DES Կ̫ضϣ 0 - Iv: TBytes - 8 ֽڳʼ̫ضϣ 0 - Input: TBytes - ֽܵ - - ֵTBytes - ؽֽܺ -} - -procedure DESEncryptStreamECB(Source: TStream; Count: Cardinal; - const Key: TCnDESKey; Dest: TStream); overload; -{* DES ܣʹ ECB ģʽ - Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnDESKey - 8 ֽ DES Կ - Dest: TStream - - - ֵޣ -} - -procedure DESDecryptStreamECB(Source: TStream; Count: Cardinal; - const Key: TCnDESKey; Dest: TStream); overload; -{* DES ܣʹ ECB ģʽ - Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnDESKey - 8 ֽ DES Կ - Dest: TStream - - - ֵޣ -} - -procedure DESEncryptStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnDESKey; const InitVector: TCnDESIv; Dest: TStream); overload; -{* DES ܣʹ CBC ģʽ - Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnDESKey - 8 ֽ DES Կ - const InitVector: TCnDESIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure DESDecryptStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnDESKey; const InitVector: TCnDESIv; Dest: TStream); overload; -{* DES ܣʹ CBC ģʽ - Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnDESKey - 8 ֽ DES Կ - const InitVector: TCnDESIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -// =========================== 3-DES (Triple DES) ============================== - -function TripleDESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; -{* ֽڳȼȡǿ - - - InputByteLength: Integer - ֽڳ - - ֵInteger - 3DES ֽڳ -} - -procedure TripleDESEncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); -{* AnsiString 3DES ܣʹ ECB ģʽ - - - Key: AnsiString - 24ֽ 3DES Կ̫ضϣ #0 - const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı - Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 - - ֵޣ -} - -procedure TripleDESDecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); -{* AnsiString 3DES ܣʹ ECB ģʽ - - - Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 - const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı - Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 - - ֵޣ -} - -procedure TripleDESEncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; - const Input: AnsiString; Output: PAnsiChar); -{* AnsiString 3DES ܣʹ CBC ģʽ - - - Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 - Iv: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ - const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı - Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 - - ֵޣ -} - -procedure TripleDESDecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; - const Input: AnsiString; Output: PAnsiChar); -{* AnsiString 3DES ܣʹ CBC ģʽ - - - Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 - Iv: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ - const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı - Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 - - ֵޣ -} - -function TripleDESEncryptEcbStrToHex(const Str: AnsiString; const Key: AnsiString): AnsiString; -{* Key3DES ܷתʮƵģʹ ECB ģʽĩβܲ #0 - - - const Str: AnsiString - ַܵ - const Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 - - ֵAnsiString - ؼܺʮַ -} - -function TripleDESDecryptEcbStrFromHex(const HexStr: AnsiString; const Key: AnsiString): AnsiString; -{* ʮƵ Key3DES ܷģʹ ECB ģʽ - - - const HexStr: AnsiString - ܵʮַ - const Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 - - ֵAnsiString - ؽַܺ -} - -function TripleDESEncryptCbcStrToHex(const Str: AnsiString; const Key: AnsiString; - const Iv: AnsiString): AnsiString; -{* Key Iv3DES ܷתʮƵģʹ CBC ģʽĩβܲ #0 - - - const Str: AnsiString - ַܵ - const Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 - const Iv: AnsiString - 8 ֽڳʼ - - ֵAnsiString - ؼܺʮַ -} - -function TripleDESDecryptCbcStrFromHex(const HexStr: AnsiString; - const Key: AnsiString; const Iv: AnsiString): AnsiString; -{* ʮƵ Key Iv3DES ܷģʹ CBC ģʽ - - - const HexStr: AnsiString - ܵʮַ - const Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 - const Iv: AnsiString - 8 ֽڳʼ - - ֵAnsiString - ؽַܺ -} - -function TripleDESEncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; -{* ֽ 3DES ܣʹ ECB ģʽ - - - Key: TBytes - 24 ֽ 3DES Կ̫ضϣ 0 - Input: TBytes - ֽܵ飬䳤粻 8 ʱᱻ 0 ȴﵽ 8 ı - - ֵTBytes - ؼֽܺ -} - -function TripleDESDecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; -{* ֽ 3DES ܣʹ ECB ģʽ - - - Key: TBytes - 24 ֽ 3DES Կ̫ضϣ 0 - Input: TBytes - ֽܵ飬䳤粻 8 ʱᱻ 0 ȴﵽ 8 ı - - ֵTBytes - ؽֽܺ -} - -function TripleDESEncryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; -{* ֽ 3DES ܣʹ CBC ģʽ - - - Key: TBytes - 24 ֽ 3DES Կ̫ضϣ 0 - Iv: TBytes - 8 ֽڳʼ̫ضϣ 0 - Input: TBytes - ֽܵ - - ֵTBytes - ؼֽܺ -} - -function TripleDESDecryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; -{* ֽ 3DES ܣʹ CBC ģʽ - - - Key: TBytes - 24 ֽ 3DES Կ̫ضϣ 0 - Iv: TBytes - 8 ֽڳʼ̫ضϣ 0 - Input: TBytes - ֽܵ - - ֵTBytes - ؽֽܺ -} - -procedure TripleDESEncryptStreamECB(Source: TStream; Count: Cardinal; - const Key: TCn3DESKey; Dest: TStream); overload; -{* 3DES ܣʹ ECB ģʽ - Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnDESKey - 24 ֽ 3DES Կ - Dest: TStream - - - ֵޣ -} - -procedure TripleDESDecryptStreamECB(Source: TStream; Count: Cardinal; - const Key: TCn3DESKey; Dest: TStream); overload; -{* 3DES ܣʹ ECB ģʽ - Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCnDESKey - 24 ֽ 3DES Կ - Dest: TStream - - - ֵޣ -} - -procedure TripleDESEncryptStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCn3DESKey; const InitVector: TCnDESIv; Dest: TStream); overload; -{* 3DES ܣʹ CBC ģʽ - Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCn3DESKey - 24 ֽ 3DES Կ - const InitVector: TCnDESIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -procedure TripleDESDecryptStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCn3DESKey; const InitVector: TCnDESIv; Dest: TStream); overload; -{* 3DES ܣʹ CBC ģʽ - Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ - - - Source: TStream - ܵ - Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ - const Key: TCn3DESKey - 24 ֽ 3DES Կ - const InitVector: TCnDESIv - 8 ֽڳʼ - Dest: TStream - - - ֵޣ -} - -implementation - -resourcestring - SCnErrorDESInvalidInBufSize = 'Invalid Buffer Size for Decryption'; - SCnErrorDESReadError = 'Stream Read Error'; - SCnErrorDESWriteError = 'Stream Write Error'; - -type - TKeyByte = array[0..5] of Byte; - TDesMode = (dmEncry, dmDecry); - TSubKey = array[0..15] of TKeyByte; - -const - BitIP: array[0..63] of Byte = - (57, 49, 41, 33, 25, 17, 9, 1, - 59, 51, 43, 35, 27, 19, 11, 3, - 61, 53, 45, 37, 29, 21, 13, 5, - 63, 55, 47, 39, 31, 23, 15, 7, - 56, 48, 40, 32, 24, 16, 8, 0, - 58, 50, 42, 34, 26, 18, 10, 2, - 60, 52, 44, 36, 28, 20, 12, 4, - 62, 54, 46, 38, 30, 22, 14, 6); - - BitCP: array[0..63] of Byte = - (39, 7, 47, 15, 55, 23, 63, 31, - 38, 6, 46, 14, 54, 22, 62, 30, - 37, 5, 45, 13, 53, 21, 61, 29, - 36, 4, 44, 12, 52, 20, 60, 28, - 35, 3, 43, 11, 51, 19, 59, 27, - 34, 2, 42, 10, 50, 18, 58, 26, - 33, 1, 41, 9, 49, 17, 57, 25, - 32, 0, 40, 8, 48, 16, 56, 24); - - BitExp: array[0..47] of Integer = - (31, 0, 1, 2, 3, 4, 3, 4, 5, 6, 7, 8, 7, 8, 9, 10, - 11, 12, 11, 12, 13, 14, 15, 16, 15, 16, 17, 18, 19, 20, 19, 20, - 21, 22, 23, 24, 23, 24, 25, 26, 27, 28, 27, 28, 29, 30, 31, 0); - - BitPM: array[0..31] of Byte = - (15, 6, 19, 20, 28, 11, 27, 16, 0, 14, 22, 25, 4, 17, 30, 9, - 1, 7, 23, 13, 31, 26, 2, 8, 18, 12, 29, 5, 21, 10, 3, 24); - - sBox: array[0..7] of array[0..63] of Byte = - ((14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, - 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, - 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, - 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13), - - (15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, - 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, - 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, - 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9), - - (10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, - 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, - 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, - 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12), - - (7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, - 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, - 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, - 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14), - - (2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, - 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, - 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, - 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3), - - (12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, - 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, - 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, - 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13), - - (4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, - 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, - 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, - 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12), - - (13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, - 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, - 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, - 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11)); - - BitPMC1: array[0..55] of Byte = - (56, 48, 40, 32, 24, 16, 8, - 0, 57, 49, 41, 33, 25, 17, - 9, 1, 58, 50, 42, 34, 26, - 18, 10, 2, 59, 51, 43, 35, - 62, 54, 46, 38, 30, 22, 14, - 6, 61, 53, 45, 37, 29, 21, - 13, 5, 60, 52, 44, 36, 28, - 20, 12, 4, 27, 19, 11, 3); - - BitPMC2: array[0..47] of Byte = - (13, 16, 10, 23, 0, 4, - 2, 27, 14, 5, 20, 9, - 22, 18, 11, 3, 25, 7, - 15, 6, 26, 19, 12, 1, - 40, 51, 30, 36, 46, 54, - 29, 39, 50, 44, 32, 47, - 43, 48, 38, 55, 33, 52, - 45, 41, 49, 35, 28, 31); - -function Min(A, B: Integer): Integer; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - if A < B then - Result := A - else - Result := B; -end; - -procedure InitPermutation(var InData: array of Byte); -var - NewData: array[0..7] of Byte; - I: Integer; -begin - FillChar(NewData, 8, 0); - for I := 0 to 63 do - if (InData[BitIP[I] shr 3] and (1 shl (7 - (BitIP[I] and $07)))) <> 0 then - NewData[I shr 3] := NewData[I shr 3] or (1 shl (7 - (I and $07))); - for I := 0 to 7 do InData[I] := NewData[I]; -end; - -procedure ConversePermutation(var InData: array of Byte); -var - NewData: array[0..7] of Byte; - I: Integer; -begin - FillChar(NewData, 8, 0); - for I := 0 to 63 do - if (InData[BitCP[I] shr 3] and (1 shl (7 - (BitCP[I] and $07)))) <> 0 then - NewData[I shr 3] := NewData[I shr 3] or (1 shl (7 - (I and $07))); - for I := 0 to 7 do InData[I] := NewData[I]; -end; - -procedure Expand(const InData: array of Byte; var OutData: array of Byte); -var - I: Integer; -begin - FillChar(OutData, 6, 0); - for I := 0 to 47 do - if (InData[BitExp[I] shr 3] and (1 shl (7 - (BitExp[I] and $07)))) <> 0 then - OutData[I shr 3] := OutData[I shr 3] or (1 shl (7 - (I and $07))); -end; - -procedure Permutation(var InData: array of Byte); -var - NewData: array[0..3] of Byte; - I: Integer; -begin - FillChar(NewData, 4, 0); - for I := 0 to 31 do - if (InData[BitPM[I] shr 3] and (1 shl (7 - (BitPM[I] and $07)))) <> 0 then - NewData[I shr 3] := NewData[I shr 3] or (1 shl (7 - (I and $07))); - for I := 0 to 3 do InData[I] := NewData[I]; -end; - -function Si(S, InByte: Byte): Byte; -var - c: Byte; -begin - c := (InByte and $20) or ((InByte and $1E) shr 1) or - ((InByte and $01) shl 4); - Result := (sBox[S][c] and $0F); -end; - -procedure PermutationChoose1(const InData: array of Byte; var OutData: array of Byte); -var - I: Integer; -begin - FillChar(OutData, 7, 0); - for I := 0 to 55 do - if (InData[BitPMC1[I] shr 3] and (1 shl (7 - (BitPMC1[I] and $07)))) <> 0 then - OutData[I shr 3] := OutData[I shr 3] or (1 shl (7 - (I and $07))); -end; - -procedure PermutationChoose2(const InData: array of Byte; var OutData: array of Byte); -var - I: Integer; -begin - FillChar(OutData, 6, 0); - for I := 0 to 47 do - if (InData[BitPMC2[I] shr 3] and (1 shl (7 - (BitPMC2[I] and $07)))) <> 0 then - OutData[I shr 3] := OutData[I shr 3] or (1 shl (7 - (I and $07))); -end; - -procedure CycleMove(var InData: array of Byte; bitMove: Byte); -var - I: Integer; -begin - for I := 0 to bitMove - 1 do - begin - InData[0] := (InData[0] shl 1) or (InData[1] shr 7); - InData[1] := (InData[1] shl 1) or (InData[2] shr 7); - InData[2] := (InData[2] shl 1) or (InData[3] shr 7); - InData[3] := (InData[3] shl 1) or ((InData[0] and $10) shr 4); - InData[0] := (InData[0] and $0F); - end; -end; - -procedure MakeKey(const InKey: array of Byte; var OutKey: array of TKeyByte); -const - bitDisplace: array[0..15] of Byte = - (1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1); -var - OutData56: array[0..6] of Byte; - Key28l: array[0..3] of Byte; - Key28r: array[0..3] of Byte; - Key56o: array[0..6] of Byte; - I: Integer; -begin - PermutationChoose1(InKey, OutData56); - Key28l[0] := OutData56[0] shr 4; - Key28l[1] := (OutData56[0] shl 4) or (OutData56[1] shr 4); - Key28l[2] := (OutData56[1] shl 4) or (OutData56[2] shr 4); - Key28l[3] := (OutData56[2] shl 4) or (OutData56[3] shr 4); - Key28r[0] := OutData56[3] and $0F; - Key28r[1] := OutData56[4]; - Key28r[2] := OutData56[5]; - Key28r[3] := OutData56[6]; - for I := 0 to 15 do - begin - CycleMove(Key28l, bitDisplace[I]); - CycleMove(Key28r, bitDisplace[I]); - Key56o[0] := (Key28l[0] shl 4) or (Key28l[1] shr 4); - Key56o[1] := (Key28l[1] shl 4) or (Key28l[2] shr 4); - Key56o[2] := (Key28l[2] shl 4) or (Key28l[3] shr 4); - Key56o[3] := (Key28l[3] shl 4) or (Key28r[0]); - Key56o[4] := Key28r[1]; - Key56o[5] := Key28r[2]; - Key56o[6] := Key28r[3]; - PermutationChoose2(Key56o, OutKey[I]); - end; -end; - -procedure Encry(const InData, ASubKey: array of Byte; var OutData: array of Byte); -var - OutBuf: array[0..5] of Byte; - Buf: array[0..7] of Byte; - I: Integer; -begin - Expand(InData, OutBuf); - for I := 0 to 5 do OutBuf[I] := OutBuf[I] xor ASubKey[I]; - Buf[0] := OutBuf[0] shr 2; - Buf[1] := ((OutBuf[0] and $03) shl 4) or (OutBuf[1] shr 4); - Buf[2] := ((OutBuf[1] and $0F) shl 2) or (OutBuf[2] shr 6); - Buf[3] := OutBuf[2] and $3F; - Buf[4] := OutBuf[3] shr 2; - Buf[5] := ((OutBuf[3] and $03) shl 4) or (OutBuf[4] shr 4); - Buf[6] := ((OutBuf[4] and $0F) shl 2) or (OutBuf[5] shr 6); - Buf[7] := OutBuf[5] and $3F; - for I := 0 to 7 do Buf[I] := si(I, Buf[I]); - for I := 0 to 3 do OutBuf[I] := (Buf[I * 2] shl 4) or Buf[I * 2 + 1]; - Permutation(OutBuf); - for I := 0 to 3 do OutData[I] := OutBuf[I]; -end; - -// InData OutData Ҫ 8 ֽ -procedure DesData(DesMode: TDesMode; SubKey: TSubKey; const InData: array of Byte; - var OutData: array of Byte); -var - I, J: Integer; - Temp, Buf: array[0..3] of Byte; -begin - for I := 0 to 7 do OutData[I] := InData[I]; - InitPermutation(OutData); - if DesMode = dmEncry then - begin - for I := 0 to 15 do - begin - for J := 0 to 3 do Temp[J] := OutData[J]; - for J := 0 to 3 do OutData[J] := OutData[J + 4]; - Encry(OutData, SubKey[I], Buf); - for J := 0 to 3 do OutData[J + 4] := Temp[J] xor Buf[J]; - end; - for J := 0 to 3 do Temp[J] := OutData[J + 4]; - for J := 0 to 3 do OutData[J + 4] := OutData[J]; - for J := 0 to 3 do OutData[J] := Temp[J]; - end - else if DesMode = dmDecry then - begin - for I := 15 downto 0 do - begin - for J := 0 to 3 do Temp[J] := OutData[J]; - for J := 0 to 3 do OutData[J] := OutData[J + 4]; - Encry(OutData, SubKey[I], Buf); - for J := 0 to 3 do OutData[J + 4] := Temp[J] xor Buf[J]; - end; - for J := 0 to 3 do Temp[J] := OutData[J + 4]; - for J := 0 to 3 do OutData[J + 4] := OutData[J]; - for J := 0 to 3 do OutData[J] := Temp[J]; - end; - ConversePermutation(OutData); -end; - -// Key #0 ճ 8 ֽ -procedure MakeKeyAlign(var Key: AnsiString); -begin - if Length(Key) < CN_DES_KEYSIZE then - while Length(Key) < CN_DES_KEYSIZE do - Key := Key + Chr(0); -end; - -// ַ #0 ճ 8 ıעմ -procedure MakeInputAlign(var Str: AnsiString); -begin - while Length(Str) mod CN_DES_KEYSIZE <> 0 do - Str := Str + Chr(0); -end; - -// ֽ鲹 0 ճ 8 ıע鲻 -procedure MakeInputBytesAlign(var Input: TBytes); -var - I, Len, NL: Integer; -begin - Len := Length(Input); - if Len mod CN_DES_BLOCKSIZE <> 0 then - begin - NL := ((Len div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE; - SetLength(Input, NL); - for I := Len to NL - 1 do - Input[I] := 0; - end; -end; - -function DESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; -begin - Result := (((InputByteLength - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE; -end; - -procedure DESEncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); -var - StrByte, OutByte: TCnDESBuffer; - KeyByte: TCnDESKey; - Str: AnsiString; - I: Integer; - SubKey: TSubKey; -begin - MakeKeyAlign(Key); - - Str := Input; - MakeInputAlign(Str); // Str 8 ı - - if Str = '' then // մֱӷؿ - begin - if Output <> nil then - Output[0] := #0; - Exit; - end; - - Move(Key[1], KeyByte[0], SizeOf(TCnDESKey)); - MakeKey(KeyByte, SubKey); - - for I := 0 to Length(Str) div CN_DES_BLOCKSIZE - 1 do - begin - Move(Str[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); - DesData(dmEncry, SubKey, StrByte, OutByte); - Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); - end; -end; - -procedure DESDecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); -var - StrByte, OutByte: TCnDESBuffer; - KeyByte: TCnDESKey; - I: Integer; - SubKey: TSubKey; -begin - MakeKeyAlign(Key); - Move(Key[1], KeyByte[0], SizeOf(TCnDESKey)); - MakeKey(KeyByte, SubKey); - - for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do - begin - Move(Input[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); - DesData(dmDecry, SubKey, StrByte, OutByte); - Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); - end; - - // ĩβ 0 ⲿжɾ -end; - -procedure DESEncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; - const Input: AnsiString; Output: PAnsiChar); -var - StrByte, OutByte: TCnDESBuffer; - KeyByte: TCnDESKey; - Vector: TCnDESIv; - Str: AnsiString; - I: Integer; - SubKey: TSubKey; -begin - MakeKeyAlign(Key); - - Str := Input; - MakeInputAlign(Str); - - if Str = '' then // մֱӷؿ - begin - if Output <> nil then - Output[0] := #0; - Exit; - end; - - Move(Key[1], KeyByte[0], SizeOf(TCnDESKey)); - MakeKey(KeyByte, SubKey); - Move(Iv^, Vector[0], SizeOf(TCnDESIv)); - - for I := 0 to Length(Str) div CN_DES_BLOCKSIZE - 1 do - begin - Move(Str[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); - - // CBC ݿֵȸ Iv - PCardinal(@StrByte[0])^ := PCardinal(@StrByte[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@StrByte[4])^ := PCardinal(@StrByte[4])^ xor PCardinal(@Vector[4])^; - - // ټ - DesData(dmEncry, SubKey, StrByte, OutByte); - Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); - - // ܽµ Iv - Move(OutByte[0], Vector[0], SizeOf(TCnDESIv)); - end; -end; - -procedure DESDecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; - const Input: AnsiString; Output: PAnsiChar); -var - StrByte, OutByte: TCnDESBuffer; - KeyByte: TCnDESKey; - Vector, TV: TCnDESIv; - I: Integer; - SubKey: TSubKey; -begin - MakeKeyAlign(Key); - Move(Key[1], KeyByte[0], SizeOf(TCnDESKey)); - - MakeKey(KeyByte, SubKey); - Move(Iv^, Vector[0], SizeOf(TCnDESIv)); - - for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do - begin - Move(Input[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); - Move(StrByte[0], TV[0], SizeOf(TCnDESIv)); // ȴһ - - // Ƚ - DesData(dmDecry, SubKey, StrByte, OutByte); - - // CBC ݿֵܺٸ Iv - PCardinal(@OutByte[0])^ := PCardinal(@OutByte[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@OutByte[4])^ := PCardinal(@OutByte[4])^ xor PCardinal(@Vector[4])^; - - Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); - - // ĸµ Iv - Move(TV[0], Vector[0], SizeOf(TCnDESIv)); - end; - - // ĩβ 0 ⲿжɾ -end; - -procedure SetResultLengthUsingInput(const Str: AnsiString; var Res: AnsiString); -var - Len: Integer; -begin - Len := Length(Str); - if Len < CN_DES_BLOCKSIZE then - Len := CN_DES_BLOCKSIZE - else - Len := (((Len - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE; - SetLength(Res, Len); -end; - -function DESEncryptEcbStrToHex(const Str, Key: AnsiString): AnsiString; -var - TempResult: AnsiString; -begin - Result := ''; - if Str = '' then - Exit; - - SetResultLengthUsingInput(Str, TempResult); - DESEncryptEcbStr(Key, Str, @TempResult[1]); - Result := AnsiStrToHex(TempResult); -end; - -function DESDecryptEcbStrFromHex(const HexStr, Key: AnsiString): AnsiString; -var - Str: AnsiString; -begin - Str := HexToAnsiStr(HexStr); - SetResultLengthUsingInput(Str, Result); - DESDecryptEcbStr(Key, Str, @(Result[1])); -end; - -function DESEncryptCbcStrToHex(const Str, Key, Iv: AnsiString): AnsiString; -var - TempResult: AnsiString; -begin - Result := ''; - if Str = '' then - Exit; - - SetResultLengthUsingInput(Str, TempResult); - DESEncryptCbcStr(Key, PAnsiChar(Iv), Str, @TempResult[1]); - Result := AnsiStrToHex(TempResult); -end; - -function DESDecryptCbcStrFromHex(const HexStr, Key, Iv: AnsiString): AnsiString; -var - Str: AnsiString; -begin - Str := HexToAnsiStr(HexStr); - SetResultLengthUsingInput(Str, Result); - DESDecryptCbcStr(Key, PAnsiChar(Iv), Str, @(Result[1])); -end; - -function DESEncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; -var - StrByte, OutByte: TCnDESBuffer; - KeyByte: TCnDESKey; - I: Integer; - SubKey: TSubKey; -begin - if Length(Input) <= 0 then - begin - Result := nil; - Exit; - end; - - MakeInputBytesAlign(Input); - - FillChar(KeyByte[0], SizeOf(TCnDESKey), 0); - MoveMost(Key[0], KeyByte[0], Length(Key), SizeOf(TCnDESKey)); - MakeKey(KeyByte, SubKey); - - SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); - for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do - begin - Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); - DesData(dmEncry, SubKey, StrByte, OutByte); - Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); - end; -end; - -function DESDecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; -var - StrByte, OutByte: TCnDESBuffer; - KeyByte: TCnDESKey; - I: Integer; - SubKey: TSubKey; -begin - if Length(Input) <= 0 then - begin - Result := nil; - Exit; - end; - - FillChar(KeyByte[0], SizeOf(TCnDESKey), 0); - MoveMost(Key[0], KeyByte[0], Length(Key), SizeOf(TCnDESKey)); - MakeKey(KeyByte, SubKey); - - SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); - for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do - begin - Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); - DesData(dmDecry, SubKey, StrByte, OutByte); - Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); - end; -end; - -function DESEncryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; -var - StrByte, OutByte: TCnDESBuffer; - KeyByte: TCnDESKey; - Vector: TCnDESIv; - I: Integer; - SubKey: TSubKey; -begin - if Length(Input) <= 0 then - begin - Result := nil; - Exit; - end; - - MakeInputBytesAlign(Input); - - FillChar(KeyByte[0], SizeOf(TCnDESKey), 0); - MoveMost(Key[0], KeyByte[0], Length(Key), SizeOf(TCnDESKey)); - MakeKey(KeyByte, SubKey); - - FillChar(Vector[0], SizeOf(TCnDESIv), 0); - MoveMost(Iv[0], Vector[0], Length(Iv), SizeOf(TCnDESIv)); - - SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); - for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do - begin - Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); - - // CBC ݿֵȸ Iv - PCardinal(@StrByte[0])^ := PCardinal(@StrByte[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@StrByte[4])^ := PCardinal(@StrByte[4])^ xor PCardinal(@Vector[4])^; - - // ټ - DesData(dmEncry, SubKey, StrByte, OutByte); - Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); - - // ܽµ Iv - Move(OutByte[0], Vector[0], SizeOf(TCnDESIv)); - end; -end; - -function DESDecryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; -var - StrByte, OutByte: TCnDESBuffer; - KeyByte: TCnDESKey; - Vector, TV: TCnDESIv; - I: Integer; - SubKey: TSubKey; -begin - if Length(Input) <= 0 then - begin - Result := nil; - Exit; - end; - - FillChar(KeyByte[0], SizeOf(TCnDESKey), 0); - MoveMost(Key[0], KeyByte[0], Length(Key), SizeOf(TCnDESKey)); - MakeKey(KeyByte, SubKey); - - FillChar(Vector[0], SizeOf(TCnDESIv), 0); - MoveMost(Iv[0], Vector[0], Length(Iv), SizeOf(TCnDESIv)); - - SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); - for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do - begin - Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); - Move(StrByte[0], TV[0], SizeOf(TCnDESIv)); // ȴһ - - // Ƚ - DesData(dmDecry, SubKey, StrByte, OutByte); - - // CBC ݿֵܺٸ Iv - PCardinal(@OutByte[0])^ := PCardinal(@OutByte[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@OutByte[4])^ := PCardinal(@OutByte[4])^ xor PCardinal(@Vector[4])^; - - Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); - - // ĸµ Iv - Move(TV[0], Vector[0], SizeOf(TCnDESIv)); - end; -end; - -procedure DESEncryptStreamECB(Source: TStream; Count: Cardinal; - const Key: TCnDESKey; Dest: TStream); overload; -var - TempIn, TempOut: TCnDESBuffer; - Done: Cardinal; - SubKey: TSubKey; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else - Count := Min(Count, Source.Size - Source.Position); - - if Count = 0 then - Exit; - - MakeKey(Key, SubKey); - while Count >= SizeOf(TCnDESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorDESReadError); - - DesData(dmEncry, SubKey, TempIn, TempOut); - - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorDESWriteError); - - Dec(Count, SizeOf(TCnDESBuffer)); - end; - - if Count > 0 then // β 0 - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorDESReadError); - FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); - - DesData(dmEncry, SubKey, TempIn, TempOut); - - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorDESWriteError); - end; -end; - -procedure DESDecryptStreamECB(Source: TStream; Count: Cardinal; - const Key: TCnDESKey; Dest: TStream); overload; -var - TempIn, TempOut: TCnDESBuffer; - Done: Cardinal; - SubKey: TSubKey; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else - Count := Min(Count, Source.Size - Source.Position); - - if Count = 0 then - Exit; - if (Count mod SizeOf(TCnDESBuffer)) > 0 then - raise ECnDESException.Create(SCnErrorDESInvalidInBufSize); - - MakeKey(Key, SubKey); - while Count >= SizeOf(TCnDESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorDESReadError); - - DesData(dmDecry, SubKey, TempIn, TempOut); - - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorDESWriteError); - - Dec(Count, SizeOf(TCnDESBuffer)); - end; -end; - -procedure DESEncryptStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnDESKey; const InitVector: TCnDESIv; Dest: TStream); overload; -var - TempIn, TempOut: TCnDESBuffer; - Vector: TCnDESIv; - Done: Cardinal; - SubKey: TSubKey; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else - Count := Min(Count, Source.Size - Source.Position); - - if Count = 0 then - Exit; - - Vector := InitVector; - MakeKey(Key, SubKey); - - while Count >= SizeOf(TCnDESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorDESReadError); - - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; - - DesData(dmEncry, SubKey, TempIn, TempOut); - - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorDESWriteError); - - Move(TempOut[0], Vector[0], SizeOf(TCnDESIv)); - Dec(Count, SizeOf(TCnDESBuffer)); - end; - - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorDESReadError); - FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); - - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; - - DesData(dmEncry, SubKey, TempIn, TempOut); - - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorDESWriteError); - end; -end; - -procedure DESDecryptStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCnDESKey; const InitVector: TCnDESIv; Dest: TStream); overload; -var - TempIn, TempOut: TCnDESBuffer; - Vector1, Vector2: TCnDESIv; - Done: Cardinal; - SubKey: TSubKey; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else - Count := Min(Count, Source.Size - Source.Position); - - if Count = 0 then - Exit; - if (Count mod SizeOf(TCnDESBuffer)) > 0 then - raise ECnDESException.Create(SCnErrorDESInvalidInBufSize); - - Vector1 := InitVector; - MakeKey(Key, SubKey); - - while Count >= SizeOf(TCnDESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError(SCnErrorDESReadError); - - Move(TempIn[0], Vector2[0], SizeOf(TCnDESIv)); - DesData(dmDecry, SubKey, TempIn, TempOut); - - PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; - PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; - - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError(SCnErrorDESWriteError); - - Vector1 := Vector2; - Dec(Count, SizeOf(TCnDESBuffer)); - end; -end; - -procedure Make3DESKeys(Keys: AnsiString; var K1, K2, K3: TCnDESKey); overload; -var - I: Integer; -begin - if Length(Keys) < CN_TRIPLE_DES_KEYSIZE then - while Length(Keys) < CN_TRIPLE_DES_KEYSIZE do - Keys := Keys + Chr(0); - - for I := 0 to CN_DES_KEYSIZE - 1 do - begin - K1[I] := Ord(Keys[I + 1]); - K2[I] := Ord(Keys[I + 1 + CN_DES_KEYSIZE]); - K3[I] := Ord(Keys[I + 1 + CN_DES_KEYSIZE * 2]); - end; -end; - -procedure Make3DESKeys(Keys: TCn3DESKey; var K1, K2, K3: TCnDESKey); overload; -var - I: Integer; -begin - for I := 0 to CN_DES_KEYSIZE - 1 do - begin - K1[I] := Keys[I]; - K2[I] := Keys[I + CN_DES_KEYSIZE]; - K3[I] := Keys[I + CN_DES_KEYSIZE * 2]; - end; -end; - -procedure Make3DESKeys(Keys: TBytes; var K1, K2, K3: TCnDESKey); overload; -var - I, Len: Integer; -begin - Len := Length(Keys); - if Len < CN_TRIPLE_DES_KEYSIZE then - begin - SetLength(Keys, CN_TRIPLE_DES_KEYSIZE); - for I := Len to CN_TRIPLE_DES_KEYSIZE - 1 do - Keys[I] := 0; - end; - - for I := 0 to CN_DES_KEYSIZE - 1 do - begin - K1[I] := Ord(Keys[I]); - K2[I] := Ord(Keys[I + CN_DES_KEYSIZE]); - K3[I] := Ord(Keys[I + CN_DES_KEYSIZE * 2]); - end; -end; - -function TripleDESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; -begin - Result := (((InputByteLength - 1) div CN_TRIPLE_DES_BLOCKSIZE) + 1) * CN_TRIPLE_DES_BLOCKSIZE; -end; - -procedure TripleDESEncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); -var - StrByte, OutByte: TCnDESBuffer; - K1, K2, K3: TCnDESKey; - Str: AnsiString; - I: Integer; - SubKey1, SubKey2, SubKey3: TSubKey; -begin - Make3DESKeys(Key, K1, K2, K3); - MakeKey(K1, SubKey1); - MakeKey(K2, SubKey2); - MakeKey(K3, SubKey3); - - Str := Input; - MakeInputAlign(Str); - - if Str = '' then // մֱӷؿ - begin - if Output <> nil then - Output[0] := #0; - Exit; - end; - - for I := 0 to Length(Str) div CN_DES_BLOCKSIZE - 1 do - begin - Move(Str[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); - - DesData(dmEncry, SubKey1, StrByte, OutByte); - DesData(dmDecry, SubKey2, OutByte, StrByte); - DesData(dmEncry, SubKey3, StrByte, OutByte); - - Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); - end; -end; - -procedure TripleDESDecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); -var - StrByte, OutByte: TCnDESBuffer; - K1, K2, K3: TCnDESKey; - I: Integer; - SubKey1, SubKey2, SubKey3: TSubKey; -begin - Make3DESKeys(Key, K1, K2, K3); - MakeKey(K1, SubKey1); - MakeKey(K2, SubKey2); - MakeKey(K3, SubKey3); - - for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do - begin - Move(Input[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); - - DesData(dmDecry, SubKey3, StrByte, OutByte); - DesData(dmEncry, SubKey2, OutByte, StrByte); - DesData(dmDecry, SubKey1, StrByte, OutByte); - - Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); - end; - - // ĩβ 0 ⲿжɾ -end; - -procedure TripleDESEncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; - const Input: AnsiString; Output: PAnsiChar); -var - StrByte, OutByte: TCnDESBuffer; - K1, K2, K3: TCnDESKey; - Vector: TCnDESIv; - Str: AnsiString; - I: Integer; - SubKey1, SubKey2, SubKey3: TSubKey; -begin - Make3DESKeys(Key, K1, K2, K3); - MakeKey(K1, SubKey1); - MakeKey(K2, SubKey2); - MakeKey(K3, SubKey3); - - Str := Input; - MakeInputAlign(Str); - - if Str = '' then // մֱӷؿ - begin - if Output <> nil then - Output[0] := #0; - Exit; - end; - - Move(Iv^, Vector[0], SizeOf(TCnDESIv)); - - for I := 0 to Length(Str) div CN_DES_BLOCKSIZE - 1 do - begin - Move(Str[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); - - // CBC ݿֵȸ Iv - PCardinal(@StrByte[0])^ := PCardinal(@StrByte[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@StrByte[4])^ := PCardinal(@StrByte[4])^ xor PCardinal(@Vector[4])^; - - // ټ - DesData(dmEncry, SubKey1, StrByte, OutByte); - DesData(dmDecry, SubKey2, OutByte, StrByte); - DesData(dmEncry, SubKey3, StrByte, OutByte); - - Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); - - // ܽµ Iv - Move(OutByte[0], Vector[0], SizeOf(TCnDESIv)); - end; -end; - -procedure TripleDESDecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; - const Input: AnsiString; Output: PAnsiChar); -var - StrByte, OutByte: TCnDESBuffer; - K1, K2, K3: TCnDESKey; - Vector, TV: TCnDESIv; - I: Integer; - SubKey1, SubKey2, SubKey3: TSubKey; -begin - Make3DESKeys(Key, K1, K2, K3); - MakeKey(K1, SubKey1); - MakeKey(K2, SubKey2); - MakeKey(K3, SubKey3); - - Move(Iv^, Vector[0], SizeOf(TCnDESIv)); - - for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do - begin - Move(Input[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); - Move(StrByte[0], TV[0], SizeOf(TCnDESIv)); // ȴһ - - // Ƚ - DesData(dmDecry, SubKey3, StrByte, OutByte); - DesData(dmEncry, SubKey2, OutByte, StrByte); - DesData(dmDecry, SubKey1, StrByte, OutByte); - - // CBC ݿֵܺٸ Iv - PCardinal(@OutByte[0])^ := PCardinal(@OutByte[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@OutByte[4])^ := PCardinal(@OutByte[4])^ xor PCardinal(@Vector[4])^; - - Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); - - // ĸµ Iv - Move(TV[0], Vector[0], SizeOf(TCnDESIv)); - end; - - // ĩβ 0 ⲿжɾ -end; - -function TripleDESEncryptEcbStrToHex(const Str, Key: AnsiString): AnsiString; -var - TempResult, Temp: AnsiString; - I: Integer; -begin - SetResultLengthUsingInput(Str, TempResult); - TripleDESEncryptEcbStr(Key, Str, @TempResult[1]); - - Result := ''; - for I := 0 to Length(TempResult) - 1 do - begin - Temp := AnsiString(Format('%x', [Ord(TempResult[I + 1])])); - if Length(Temp) = 1 then - Temp := '0' + Temp; - Result := Result + Temp; - end; -end; - -function TripleDESDecryptEcbStrFromHex(const HexStr, Key: AnsiString): AnsiString; -var - Str: AnsiString; -begin - Str := HexToAnsiStr(HexStr); - SetResultLengthUsingInput(Str, Result); - TripleDESDecryptEcbStr(Key, Str, @(Result[1])); -end; - -function TripleDESEncryptCbcStrToHex(const Str, Key, Iv: AnsiString): AnsiString; -var - TempResult, Temp: AnsiString; - I: Integer; -begin - SetResultLengthUsingInput(Str, TempResult); - TripleDESEncryptCbcStr(Key, PAnsiChar(Iv), Str, @TempResult[1]); - - Result := ''; - for I := 0 to Length(TempResult) - 1 do - begin - Temp := AnsiString(Format('%x', [Ord(TempResult[I + 1])])); - if Length(Temp) = 1 then - Temp := '0' + Temp; - Result := Result + Temp; - end; -end; - -function TripleDESDecryptCbcStrFromHex(const HexStr, Key, Iv: AnsiString): AnsiString; -var - Str: AnsiString; -begin - Str := HexToAnsiStr(HexStr); - SetResultLengthUsingInput(Str, Result); - TripleDESDecryptCbcStr(Key, PAnsiChar(Iv), Str, @(Result[1])); -end; - -function TripleDESEncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; -var - StrByte, OutByte: TCnDESBuffer; - K1, K2, K3: TCnDESKey; - I: Integer; - SubKey1, SubKey2, SubKey3: TSubKey; -begin - if Length(Input) <= 0 then - begin - Result := nil; - Exit; - end; - - Make3DESKeys(Key, K1, K2, K3); - MakeKey(K1, SubKey1); - MakeKey(K2, SubKey2); - MakeKey(K3, SubKey3); - - MakeInputBytesAlign(Input); - - SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); - for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do - begin - Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); - - DesData(dmEncry, SubKey1, StrByte, OutByte); - DesData(dmDecry, SubKey2, OutByte, StrByte); - DesData(dmEncry, SubKey3, StrByte, OutByte); - - Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); - end; -end; - -function TripleDESDecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; -var - StrByte, OutByte: TCnDESBuffer; - K1, K2, K3: TCnDESKey; - I: Integer; - SubKey1, SubKey2, SubKey3: TSubKey; -begin - if Length(Input) <= 0 then - begin - Result := nil; - Exit; - end; - - Make3DESKeys(Key, K1, K2, K3); - MakeKey(K1, SubKey1); - MakeKey(K2, SubKey2); - MakeKey(K3, SubKey3); - - SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); - for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do - begin - Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); - - DesData(dmDecry, SubKey3, StrByte, OutByte); - DesData(dmEncry, SubKey2, OutByte, StrByte); - DesData(dmDecry, SubKey1, StrByte, OutByte); - - Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); - end; -end; - -function TripleDESEncryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; -var - StrByte, OutByte: TCnDESBuffer; - K1, K2, K3: TCnDESKey; - Vector: TCnDESIv; - I: Integer; - SubKey1, SubKey2, SubKey3: TSubKey; -begin - if Length(Input) <= 0 then - begin - Result := nil; - Exit; - end; - - Make3DESKeys(Key, K1, K2, K3); - MakeKey(K1, SubKey1); - MakeKey(K2, SubKey2); - MakeKey(K3, SubKey3); - - MakeInputBytesAlign(Input); - FillChar(Vector[0], SizeOf(TCnDESIv), 0); - MoveMost(Iv[0], Vector[0], Length(Iv), SizeOf(TCnDESIv)); - - SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); - for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do - begin - Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); - - // CBC ݿֵȸ Iv - PCardinal(@StrByte[0])^ := PCardinal(@StrByte[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@StrByte[4])^ := PCardinal(@StrByte[4])^ xor PCardinal(@Vector[4])^; - - // ټ - DesData(dmEncry, SubKey1, StrByte, OutByte); - DesData(dmDecry, SubKey2, OutByte, StrByte); - DesData(dmEncry, SubKey3, StrByte, OutByte); - - Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); - - // ܽµ Iv - Move(OutByte[0], Vector[0], SizeOf(TCnDESIv)); - end; -end; - -function TripleDESDecryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; -var - StrByte, OutByte: TCnDESBuffer; - K1, K2, K3: TCnDESKey; - Vector, TV: TCnDESIv; - I: Integer; - SubKey1, SubKey2, SubKey3: TSubKey; -begin - if Length(Input) <= 0 then - begin - Result := nil; - Exit; - end; - - Make3DESKeys(Key, K1, K2, K3); - MakeKey(K1, SubKey1); - MakeKey(K2, SubKey2); - MakeKey(K3, SubKey3); - - FillChar(Vector[0], SizeOf(TCnDESIv), 0); - MoveMost(Iv[0], Vector[0], Length(Iv), SizeOf(TCnDESIv)); - - SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); - for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do - begin - Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); - Move(StrByte[0], TV[0], SizeOf(TCnDESIv)); // ȴһ - - // Ƚ - DesData(dmDecry, SubKey3, StrByte, OutByte); - DesData(dmEncry, SubKey2, OutByte, StrByte); - DesData(dmDecry, SubKey1, StrByte, OutByte); - - // CBC ݿֵܺٸ Iv - PCardinal(@OutByte[0])^ := PCardinal(@OutByte[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@OutByte[4])^ := PCardinal(@OutByte[4])^ xor PCardinal(@Vector[4])^; - - Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); - - // ĸµ Iv - Move(TV[0], Vector[0], SizeOf(TCnDESIv)); - end; -end; - -procedure TripleDESEncryptStreamECB(Source: TStream; Count: Cardinal; - const Key: TCn3DESKey; Dest: TStream); overload; -var - K1, K2, K3: TCnDESKey; - TempIn, TempOut: TCnDESBuffer; - Done: Cardinal; - SubKey1, SubKey2, SubKey3: TSubKey; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else - Count := Min(Count, Source.Size - Source.Position); - - if Count = 0 then - Exit; - - Make3DESKeys(Key, K1, K2, K3); - MakeKey(K1, SubKey1); - MakeKey(K2, SubKey2); - MakeKey(K3, SubKey3); - - while Count >= SizeOf(TCnDESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorDESReadError); - - DesData(dmEncry, SubKey1, TempIn, TempOut); - DesData(dmDecry, SubKey2, TempOut, TempIn); - DesData(dmEncry, SubKey3, TempIn, TempOut); - - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorDESWriteError); - - Dec(Count, SizeOf(TCnDESBuffer)); - end; - - if Count > 0 then // β 0 - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorDESReadError); - FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); - - DesData(dmEncry, SubKey1, TempIn, TempOut); - DesData(dmDecry, SubKey2, TempOut, TempIn); - DesData(dmEncry, SubKey3, TempIn, TempOut); - - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorDESWriteError); - end; -end; - -procedure TripleDESDecryptStreamECB(Source: TStream; Count: Cardinal; - const Key: TCn3DESKey; Dest: TStream); overload; -var - K1, K2, K3: TCnDESKey; - TempIn, TempOut: TCnDESBuffer; - Done: Cardinal; - SubKey1, SubKey2, SubKey3: TSubKey; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else - Count := Min(Count, Source.Size - Source.Position); - - if Count = 0 then - Exit; - if (Count mod SizeOf(TCnDESBuffer)) > 0 then - raise ECnDESException.Create(SCnErrorDESInvalidInBufSize); - - Make3DESKeys(Key, K1, K2, K3); - MakeKey(K1, SubKey1); - MakeKey(K2, SubKey2); - MakeKey(K3, SubKey3); - - while Count >= SizeOf(TCnDESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorDESReadError); - - DesData(dmDecry, SubKey3, TempIn, TempOut); - DesData(dmEncry, SubKey2, TempOut, TempIn); - DesData(dmDecry, SubKey1, TempIn, TempOut); - - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorDESWriteError); - - Dec(Count, SizeOf(TCnDESBuffer)); - end; -end; - -procedure TripleDESEncryptStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCn3DESKey; const InitVector: TCnDESIv; Dest: TStream); overload; -var - K1, K2, K3: TCnDESKey; - TempIn, TempOut: TCnDESBuffer; - Vector: TCnDESIv; - Done: Cardinal; - SubKey1, SubKey2, SubKey3: TSubKey; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else - Count := Min(Count, Source.Size - Source.Position); - - if Count = 0 then - Exit; - - Vector := InitVector; - Make3DESKeys(Key, K1, K2, K3); - MakeKey(K1, SubKey1); - MakeKey(K2, SubKey2); - MakeKey(K3, SubKey3); - - while Count >= SizeOf(TCnDESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError.Create(SCnErrorDESReadError); - - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; - - DesData(dmEncry, SubKey1, TempIn, TempOut); - DesData(dmDecry, SubKey2, TempOut, TempIn); - DesData(dmEncry, SubKey3, TempIn, TempOut); - - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorDESWriteError); - - Move(TempOut[0], Vector[0], SizeOf(TCnDESIv)); - Dec(Count, SizeOf(TCnDESBuffer)); - end; - - if Count > 0 then - begin - Done := Source.Read(TempIn, Count); - if Done < Count then - raise EStreamError.Create(SCnErrorDESReadError); - FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); - - PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; - PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; - - DesData(dmEncry, SubKey1, TempIn, TempOut); - DesData(dmDecry, SubKey2, TempOut, TempIn); - DesData(dmEncry, SubKey3, TempIn, TempOut); - - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError.Create(SCnErrorDESWriteError); - end; -end; - -procedure TripleDESDecryptStreamCBC(Source: TStream; Count: Cardinal; - const Key: TCn3DESKey; const InitVector: TCnDESIv; Dest: TStream); overload; -var - K1, K2, K3: TCnDESKey; - TempIn, TempOut: TCnDESBuffer; - Vector1, Vector2: TCnDESIv; - Done: Cardinal; - SubKey1, SubKey2, SubKey3: TSubKey; -begin - if Count = 0 then - begin - Source.Position := 0; - Count := Source.Size; - end - else - Count := Min(Count, Source.Size - Source.Position); - - if Count = 0 then - Exit; - if (Count mod SizeOf(TCnDESBuffer)) > 0 then - raise ECnDESException.Create(SCnErrorDESInvalidInBufSize); - - Vector1 := InitVector; - Make3DESKeys(Key, K1, K2, K3); - MakeKey(K1, SubKey1); - MakeKey(K2, SubKey2); - MakeKey(K3, SubKey3); - - while Count >= SizeOf(TCnDESBuffer) do - begin - Done := Source.Read(TempIn, SizeOf(TempIn)); - if Done < SizeOf(TempIn) then - raise EStreamError(SCnErrorDESReadError); - - Move(TempIn[0], Vector2[0], SizeOf(TCnDESIv)); - - DesData(dmDecry, SubKey3, TempIn, TempOut); - DesData(dmEncry, SubKey2, TempOut, TempIn); - DesData(dmDecry, SubKey1, TempIn, TempOut); - - PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; - PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; - - Done := Dest.Write(TempOut, SizeOf(TempOut)); - if Done < SizeOf(TempOut) then - raise EStreamError(SCnErrorDESWriteError); - - Vector1 := Vector2; - Dec(Count, SizeOf(TCnDESBuffer)); - end; -end; - -end. +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnDES; +{* |
+================================================================================
+* ƣ
+* ԪƣDES ԳƼӽ㷨ʵֵԪ
+* ԪߣCnPack  (master@cnpack.org)
+*           /ֲ䲿ֹܡ
+*     עԪʵ DES/3DES ԳƼӽ㷨ֿС 8 ֽڣʵ
+*           ECB/CBC ģʽ֧ģʽ
+*
+* ƽ̨PWin2000Pro + Delphi 5.0
+* ݲԣPWin9X/2000/XP + Delphi 5/6
+*   õԪеַϱػʽ
+* ޸ļ¼2024.11.30 V1.7
+*               ɾ淶 DESEncryptStrToHex  DESDecryptStrToHex
+*               ɾ淶 TripleDESEncryptStrToHex  TripleDESDecryptStrToHex
+*                ECB 汾
+*               Ż PAnsiChar ʽ Iv Ĵ
+*           2024.10.12 V1.6
+*                3DES ²Խ⣬Ż Key  Iv Ķ봦
+*           2022.08.13 V1.5
+*               Կݼܷؿ
+*           2021.02.07 V1.4
+*               Ӷ TBytes ֧
+*           2020.03.25 V1.3
+*                3DES ֧
+*           2020.03.24 V1.2
+*                ECB/CBC ַӽܺɾԭеַܺ
+*           2019.04.15 V1.1
+*               ֧ Win32/Win64/MacOS
+*           2008.05.30 V1.0
+*               Ԫ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes, CnNative; + +const + CN_DES_KEYSIZE = 8; + {* DES Կȣ8 ֽ} + + CN_DES_BLOCKSIZE = 8; + {* DES ļܿ鳤ȣ8 ֽ} + + CN_TRIPLE_DES_KEYSIZE = CN_DES_KEYSIZE * 3; + {* 3DES Կȣ DES 24 ֽ} + + CN_TRIPLE_DES_BLOCKSIZE = CN_DES_BLOCKSIZE; + {* 3DES ļܿ鳤ȣ 8 ֽ} + +type + ECnDESException = class(Exception); + {* DES 쳣} + + TCnDESKey = array[0..CN_DES_KEYSIZE - 1] of Byte; + {* DES ļ Key8 ֽ} + + TCnDESBuffer = array[0..CN_DES_BLOCKSIZE - 1] of Byte; + {* DES ļܿ飬8 ֽ} + + TCnDESIv = array[0..CN_DES_BLOCKSIZE - 1] of Byte; + {* DES CBC ijʼ8 ֽ} + + TCn3DESKey = array[0..CN_TRIPLE_DES_KEYSIZE - 1] of Byte; + {* 3DES Կȣ DES 24 ֽ} + + TCn3DESBuffer = TCnDESBuffer; + {* 3DES ļܿ飬 DES ļܿ飬8 ֽ} + + TCn3DESIv = TCnDESIv; + {* 3DES CBC ijʼ DES CBC ijʼ8 ֽ} + +// ================================= DES ======================================= + +function DESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +{* ֽڳȼ DES ȡǿ + + + InputByteLength: Integer - ֽڳ + + ֵInteger - DES ij +} + +procedure DESEncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +{* AnsiString DES ܣʹ ECB ģʽ + + + Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure DESDecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +{* AnsiString DES ܣʹ ECB ģʽ + + + Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure DESEncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; const Input: AnsiString; + Output: PAnsiChar); +{* AnsiString DES ܣʹ CBC ģʽ + + + Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + Iv: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure DESDecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; const Input: AnsiString; + Output: PAnsiChar); +{* AnsiString DES ܣʹ CBC ģʽ + + + Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + Iv: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +function DESEncryptEcbStrToHex(const Str: AnsiString; const Key: AnsiString): AnsiString; +{* KeyDES ܷתʮƵģʹ ECB ģʽĩβܲ #0 + + + const Str: AnsiString - ַܵ + const Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + + ֵAnsiString - ؼܺʮַ +} + +function DESDecryptEcbStrFromHex(const HexStr: AnsiString; const Key: AnsiString): AnsiString; +{* ʮƵ KeyDES ܷģʹ ECB ģʽ + + + const HexStr: AnsiString - ܵʮַ + const Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + + ֵAnsiString - ؽַܺ +} + +function DESEncryptCbcStrToHex(const Str: AnsiString; const Key: AnsiString; const Iv: AnsiString): AnsiString; +{* Key IvDES ܷתʮƵģʹ CBC ģʽĩβܲ #0 + + + const Str: AnsiString - ַܵ + const Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + const Iv: AnsiString - 8 ֽڳʼ + + ֵAnsiString - ؼܺʮַ +} + +function DESDecryptCbcStrFromHex(const HexStr: AnsiString; const Key: AnsiString; + const Iv: AnsiString): AnsiString; +{* ʮƵ Key IvDES ܷģʹ ECB ģʽ + + + const HexStr: AnsiString - ܵʮַ + const Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + const Iv: AnsiString - 8 ֽڳʼ + + ֵAnsiString - ؽַܺ +} + +function DESEncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +{* ֽ DES ܣʹ ECB ģʽ + + + Key: TBytes - 8 ֽ DES Կ̫ضϣ 0 + Input: TBytes - ֽܵ飬䳤粻 8 ʱᱻ 0 ȴﵽ 8 ı + + ֵTBytes - ؼֽܺ +} + +function DESDecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +{* ֽ DES ܣʹ ECB ģʽ + + + Key: TBytes - 8 ֽ DES Կ̫ضϣ 0 + Input: TBytes - ֽܵ飬䳤粻 8 ʱᱻ 0 ȴﵽ 8 ı + + ֵTBytes - ؽֽܺ +} + +function DESEncryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ DES ܣʹ CBC ģʽ + + + Key: TBytes - 8 ֽ DES Կ̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؼֽܺ +} + +function DESDecryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ DES ܣʹ CBC ģʽ + + + Key: TBytes - 8 ֽ DES Կ̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؽֽܺ +} + +procedure DESEncryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; Dest: TStream); overload; +{* DES ܣʹ ECB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 8 ֽ DES Կ + Dest: TStream - + + ֵޣ +} + +procedure DESDecryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; Dest: TStream); overload; +{* DES ܣʹ ECB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 8 ֽ DES Կ + Dest: TStream - + + ֵޣ +} + +procedure DESEncryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +{* DES ܣʹ CBC ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 8 ֽ DES Կ + const InitVector: TCnDESIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure DESDecryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +{* DES ܣʹ CBC ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 8 ֽ DES Կ + const InitVector: TCnDESIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// =========================== 3-DES (Triple DES) ============================== + +function TripleDESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +{* ֽڳȼȡǿ + + + InputByteLength: Integer - ֽڳ + + ֵInteger - 3DES ֽڳ +} + +procedure TripleDESEncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +{* AnsiString 3DES ܣʹ ECB ģʽ + + + Key: AnsiString - 24ֽ 3DES Կ̫ضϣ #0 + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure TripleDESDecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +{* AnsiString 3DES ܣʹ ECB ģʽ + + + Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure TripleDESEncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString 3DES ܣʹ CBC ģʽ + + + Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + Iv: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure TripleDESDecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString 3DES ܣʹ CBC ģʽ + + + Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + Iv: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +function TripleDESEncryptEcbStrToHex(const Str: AnsiString; const Key: AnsiString): AnsiString; +{* Key3DES ܷתʮƵģʹ ECB ģʽĩβܲ #0 + + + const Str: AnsiString - ַܵ + const Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + + ֵAnsiString - ؼܺʮַ +} + +function TripleDESDecryptEcbStrFromHex(const HexStr: AnsiString; const Key: AnsiString): AnsiString; +{* ʮƵ Key3DES ܷģʹ ECB ģʽ + + + const HexStr: AnsiString - ܵʮַ + const Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + + ֵAnsiString - ؽַܺ +} + +function TripleDESEncryptCbcStrToHex(const Str: AnsiString; const Key: AnsiString; + const Iv: AnsiString): AnsiString; +{* Key Iv3DES ܷתʮƵģʹ CBC ģʽĩβܲ #0 + + + const Str: AnsiString - ַܵ + const Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + const Iv: AnsiString - 8 ֽڳʼ + + ֵAnsiString - ؼܺʮַ +} + +function TripleDESDecryptCbcStrFromHex(const HexStr: AnsiString; + const Key: AnsiString; const Iv: AnsiString): AnsiString; +{* ʮƵ Key Iv3DES ܷģʹ CBC ģʽ + + + const HexStr: AnsiString - ܵʮַ + const Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + const Iv: AnsiString - 8 ֽڳʼ + + ֵAnsiString - ؽַܺ +} + +function TripleDESEncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +{* ֽ 3DES ܣʹ ECB ģʽ + + + Key: TBytes - 24 ֽ 3DES Կ̫ضϣ 0 + Input: TBytes - ֽܵ飬䳤粻 8 ʱᱻ 0 ȴﵽ 8 ı + + ֵTBytes - ؼֽܺ +} + +function TripleDESDecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +{* ֽ 3DES ܣʹ ECB ģʽ + + + Key: TBytes - 24 ֽ 3DES Կ̫ضϣ 0 + Input: TBytes - ֽܵ飬䳤粻 8 ʱᱻ 0 ȴﵽ 8 ı + + ֵTBytes - ؽֽܺ +} + +function TripleDESEncryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ 3DES ܣʹ CBC ģʽ + + + Key: TBytes - 24 ֽ 3DES Կ̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؼֽܺ +} + +function TripleDESDecryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ 3DES ܣʹ CBC ģʽ + + + Key: TBytes - 24 ֽ 3DES Կ̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؽֽܺ +} + +procedure TripleDESEncryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; Dest: TStream); overload; +{* 3DES ܣʹ ECB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 24 ֽ 3DES Կ + Dest: TStream - + + ֵޣ +} + +procedure TripleDESDecryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; Dest: TStream); overload; +{* 3DES ܣʹ ECB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 24 ֽ 3DES Կ + Dest: TStream - + + ֵޣ +} + +procedure TripleDESEncryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +{* 3DES ܣʹ CBC ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCn3DESKey - 24 ֽ 3DES Կ + const InitVector: TCnDESIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure TripleDESDecryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +{* 3DES ܣʹ CBC ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCn3DESKey - 24 ֽ 3DES Կ + const InitVector: TCnDESIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +implementation + +resourcestring + SCnErrorDESInvalidInBufSize = 'Invalid Buffer Size for Decryption'; + SCnErrorDESReadError = 'Stream Read Error'; + SCnErrorDESWriteError = 'Stream Write Error'; + +type + TKeyByte = array[0..5] of Byte; + TDesMode = (dmEncry, dmDecry); + TSubKey = array[0..15] of TKeyByte; + +const + BitIP: array[0..63] of Byte = + (57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7, + 56, 48, 40, 32, 24, 16, 8, 0, + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6); + + BitCP: array[0..63] of Byte = + (39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25, + 32, 0, 40, 8, 48, 16, 56, 24); + + BitExp: array[0..47] of Integer = + (31, 0, 1, 2, 3, 4, 3, 4, 5, 6, 7, 8, 7, 8, 9, 10, + 11, 12, 11, 12, 13, 14, 15, 16, 15, 16, 17, 18, 19, 20, 19, 20, + 21, 22, 23, 24, 23, 24, 25, 26, 27, 28, 27, 28, 29, 30, 31, 0); + + BitPM: array[0..31] of Byte = + (15, 6, 19, 20, 28, 11, 27, 16, 0, 14, 22, 25, 4, 17, 30, 9, + 1, 7, 23, 13, 31, 26, 2, 8, 18, 12, 29, 5, 21, 10, 3, 24); + + sBox: array[0..7] of array[0..63] of Byte = + ((14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13), + + (15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9), + + (10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12), + + (7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14), + + (2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3), + + (12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13), + + (4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12), + + (13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11)); + + BitPMC1: array[0..55] of Byte = + (56, 48, 40, 32, 24, 16, 8, + 0, 57, 49, 41, 33, 25, 17, + 9, 1, 58, 50, 42, 34, 26, + 18, 10, 2, 59, 51, 43, 35, + 62, 54, 46, 38, 30, 22, 14, + 6, 61, 53, 45, 37, 29, 21, + 13, 5, 60, 52, 44, 36, 28, + 20, 12, 4, 27, 19, 11, 3); + + BitPMC2: array[0..47] of Byte = + (13, 16, 10, 23, 0, 4, + 2, 27, 14, 5, 20, 9, + 22, 18, 11, 3, 25, 7, + 15, 6, 26, 19, 12, 1, + 40, 51, 30, 36, 46, 54, + 29, 39, 50, 44, 32, 47, + 43, 48, 38, 55, 33, 52, + 45, 41, 49, 35, 28, 31); + +function Min(A, B: Integer): Integer; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + if A < B then + Result := A + else + Result := B; +end; + +procedure InitPermutation(var InData: array of Byte); +var + NewData: array[0..7] of Byte; + I: Integer; +begin + FillChar(NewData, 8, 0); + for I := 0 to 63 do + if (InData[BitIP[I] shr 3] and (1 shl (7 - (BitIP[I] and $07)))) <> 0 then + NewData[I shr 3] := NewData[I shr 3] or (1 shl (7 - (I and $07))); + for I := 0 to 7 do InData[I] := NewData[I]; +end; + +procedure ConversePermutation(var InData: array of Byte); +var + NewData: array[0..7] of Byte; + I: Integer; +begin + FillChar(NewData, 8, 0); + for I := 0 to 63 do + if (InData[BitCP[I] shr 3] and (1 shl (7 - (BitCP[I] and $07)))) <> 0 then + NewData[I shr 3] := NewData[I shr 3] or (1 shl (7 - (I and $07))); + for I := 0 to 7 do InData[I] := NewData[I]; +end; + +procedure Expand(const InData: array of Byte; var OutData: array of Byte); +var + I: Integer; +begin + FillChar(OutData, 6, 0); + for I := 0 to 47 do + if (InData[BitExp[I] shr 3] and (1 shl (7 - (BitExp[I] and $07)))) <> 0 then + OutData[I shr 3] := OutData[I shr 3] or (1 shl (7 - (I and $07))); +end; + +procedure Permutation(var InData: array of Byte); +var + NewData: array[0..3] of Byte; + I: Integer; +begin + FillChar(NewData, 4, 0); + for I := 0 to 31 do + if (InData[BitPM[I] shr 3] and (1 shl (7 - (BitPM[I] and $07)))) <> 0 then + NewData[I shr 3] := NewData[I shr 3] or (1 shl (7 - (I and $07))); + for I := 0 to 3 do InData[I] := NewData[I]; +end; + +function Si(S, InByte: Byte): Byte; +var + c: Byte; +begin + c := (InByte and $20) or ((InByte and $1E) shr 1) or + ((InByte and $01) shl 4); + Result := (sBox[S][c] and $0F); +end; + +procedure PermutationChoose1(const InData: array of Byte; var OutData: array of Byte); +var + I: Integer; +begin + FillChar(OutData, 7, 0); + for I := 0 to 55 do + if (InData[BitPMC1[I] shr 3] and (1 shl (7 - (BitPMC1[I] and $07)))) <> 0 then + OutData[I shr 3] := OutData[I shr 3] or (1 shl (7 - (I and $07))); +end; + +procedure PermutationChoose2(const InData: array of Byte; var OutData: array of Byte); +var + I: Integer; +begin + FillChar(OutData, 6, 0); + for I := 0 to 47 do + if (InData[BitPMC2[I] shr 3] and (1 shl (7 - (BitPMC2[I] and $07)))) <> 0 then + OutData[I shr 3] := OutData[I shr 3] or (1 shl (7 - (I and $07))); +end; + +procedure CycleMove(var InData: array of Byte; BitMove: Byte); +var + I: Integer; +begin + for I := 0 to BitMove - 1 do + begin + InData[0] := Byte((InData[0] shl 1) or (InData[1] shr 7)); + InData[1] := Byte((InData[1] shl 1) or (InData[2] shr 7)); + InData[2] := Byte((InData[2] shl 1) or (InData[3] shr 7)); + InData[3] := Byte((InData[3] shl 1) or ((InData[0] and $10) shr 4)); + InData[0] := Byte((InData[0] and $0F)); + end; +end; + +procedure MakeKey(const InKey: array of Byte; var OutKey: array of TKeyByte); +const + bitDisplace: array[0..15] of Byte = + (1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1); +var + OutData56: array[0..6] of Byte; + Key28l: array[0..3] of Byte; + Key28r: array[0..3] of Byte; + Key56o: array[0..6] of Byte; + I: Integer; +begin + PermutationChoose1(InKey, OutData56); + Key28l[0] := Byte(OutData56[0] shr 4); + Key28l[1] := Byte((OutData56[0] shl 4) or (OutData56[1] shr 4)); + Key28l[2] := Byte((OutData56[1] shl 4) or (OutData56[2] shr 4)); + Key28l[3] := Byte((OutData56[2] shl 4) or (OutData56[3] shr 4)); + Key28r[0] := Byte(OutData56[3] and $0F); + Key28r[1] := Byte(OutData56[4]); + Key28r[2] := Byte(OutData56[5]); + Key28r[3] := Byte(OutData56[6]); + for I := 0 to 15 do + begin + CycleMove(Key28l, bitDisplace[I]); + CycleMove(Key28r, bitDisplace[I]); + Key56o[0] := Byte((Key28l[0] shl 4) or (Key28l[1] shr 4)); + Key56o[1] := Byte((Key28l[1] shl 4) or (Key28l[2] shr 4)); + Key56o[2] := Byte((Key28l[2] shl 4) or (Key28l[3] shr 4)); + Key56o[3] := Byte((Key28l[3] shl 4) or (Key28r[0])); + Key56o[4] := Byte(Key28r[1]); + Key56o[5] := Byte(Key28r[2]); + Key56o[6] := Byte(Key28r[3]); + PermutationChoose2(Key56o, OutKey[I]); + end; +end; + +procedure Encry(const InData, ASubKey: array of Byte; var OutData: array of Byte); +var + OutBuf: array[0..5] of Byte; + Buf: array[0..7] of Byte; + I: Integer; +begin + Expand(InData, OutBuf); + for I := 0 to 5 do OutBuf[I] := OutBuf[I] xor ASubKey[I]; + Buf[0] := OutBuf[0] shr 2; + Buf[1] := ((OutBuf[0] and $03) shl 4) or (OutBuf[1] shr 4); + Buf[2] := ((OutBuf[1] and $0F) shl 2) or (OutBuf[2] shr 6); + Buf[3] := OutBuf[2] and $3F; + Buf[4] := OutBuf[3] shr 2; + Buf[5] := ((OutBuf[3] and $03) shl 4) or (OutBuf[4] shr 4); + Buf[6] := ((OutBuf[4] and $0F) shl 2) or (OutBuf[5] shr 6); + Buf[7] := OutBuf[5] and $3F; + for I := 0 to 7 do Buf[I] := si(I, Buf[I]); + for I := 0 to 3 do OutBuf[I] := (Buf[I * 2] shl 4) or Buf[I * 2 + 1]; + Permutation(OutBuf); + for I := 0 to 3 do OutData[I] := OutBuf[I]; +end; + +// InData OutData Ҫ 8 ֽ +procedure DesData(DesMode: TDesMode; SubKey: TSubKey; const InData: array of Byte; + var OutData: array of Byte); +var + I, J: Integer; + Temp, Buf: array[0..3] of Byte; +begin + for I := 0 to 7 do OutData[I] := InData[I]; + InitPermutation(OutData); + if DesMode = dmEncry then + begin + for I := 0 to 15 do + begin + for J := 0 to 3 do Temp[J] := OutData[J]; + for J := 0 to 3 do OutData[J] := OutData[J + 4]; + Encry(OutData, SubKey[I], Buf); + for J := 0 to 3 do OutData[J + 4] := Temp[J] xor Buf[J]; + end; + for J := 0 to 3 do Temp[J] := OutData[J + 4]; + for J := 0 to 3 do OutData[J + 4] := OutData[J]; + for J := 0 to 3 do OutData[J] := Temp[J]; + end + else if DesMode = dmDecry then + begin + for I := 15 downto 0 do + begin + for J := 0 to 3 do Temp[J] := OutData[J]; + for J := 0 to 3 do OutData[J] := OutData[J + 4]; + Encry(OutData, SubKey[I], Buf); + for J := 0 to 3 do OutData[J + 4] := Temp[J] xor Buf[J]; + end; + for J := 0 to 3 do Temp[J] := OutData[J + 4]; + for J := 0 to 3 do OutData[J + 4] := OutData[J]; + for J := 0 to 3 do OutData[J] := Temp[J]; + end; + ConversePermutation(OutData); +end; + +// Key #0 ճ 8 ֽ +procedure MakeKeyAlign(var Key: AnsiString); +begin + if Length(Key) < CN_DES_KEYSIZE then + while Length(Key) < CN_DES_KEYSIZE do + Key := Key + Chr(0); +end; + +// ַ #0 ճ 8 ıעմ +procedure MakeInputAlign(var Str: AnsiString); +begin + while Length(Str) mod CN_DES_KEYSIZE <> 0 do + Str := Str + Chr(0); +end; + +// ֽ鲹 0 ճ 8 ıע鲻 +procedure MakeInputBytesAlign(var Input: TBytes); +var + I, Len, NL: Integer; +begin + Len := Length(Input); + if Len mod CN_DES_BLOCKSIZE <> 0 then + begin + NL := ((Len div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE; + SetLength(Input, NL); + for I := Len to NL - 1 do + Input[I] := 0; + end; +end; + +function DESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +begin + Result := (((InputByteLength - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE; +end; + +procedure DESEncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + Str: AnsiString; + I: Integer; + SubKey: TSubKey; +begin + MakeKeyAlign(Key); + + Str := Input; + MakeInputAlign(Str); // Str 8 ı + + if Str = '' then // մֱӷؿ + begin + if Output <> nil then + Output[0] := #0; + Exit; + end; + + Move(Key[1], KeyByte[0], SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + for I := 0 to Length(Str) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Str[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + DesData(dmEncry, SubKey, StrByte, OutByte); + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +procedure DESDecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + I: Integer; + SubKey: TSubKey; +begin + MakeKeyAlign(Key); + Move(Key[1], KeyByte[0], SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + DesData(dmDecry, SubKey, StrByte, OutByte); + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; + + // ĩβ 0 ⲿжɾ +end; + +procedure DESEncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + Vector: TCnDESIv; + Str: AnsiString; + I: Integer; + SubKey: TSubKey; +begin + MakeKeyAlign(Key); + + Str := Input; + MakeInputAlign(Str); + + if Str = '' then // մֱӷؿ + begin + if Output <> nil then + Output[0] := #0; + Exit; + end; + + Move(Key[1], KeyByte[0], SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + Move(Iv^, Vector[0], SizeOf(TCnDESIv)); + + for I := 0 to Length(Str) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Str[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + + // CBC ݿֵȸ Iv + PCardinal(@StrByte[0])^ := PCardinal(@StrByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@StrByte[4])^ := PCardinal(@StrByte[4])^ xor PCardinal(@Vector[4])^; + + // ټ + DesData(dmEncry, SubKey, StrByte, OutByte); + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ܽµ Iv + Move(OutByte[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +procedure DESDecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + Vector, TV: TCnDESIv; + I: Integer; + SubKey: TSubKey; +begin + MakeKeyAlign(Key); + Move(Key[1], KeyByte[0], SizeOf(TCnDESKey)); + + MakeKey(KeyByte, SubKey); + Move(Iv^, Vector[0], SizeOf(TCnDESIv)); + + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + Move(StrByte[0], TV[0], SizeOf(TCnDESIv)); // ȴһ + + // Ƚ + DesData(dmDecry, SubKey, StrByte, OutByte); + + // CBC ݿֵܺٸ Iv + PCardinal(@OutByte[0])^ := PCardinal(@OutByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@OutByte[4])^ := PCardinal(@OutByte[4])^ xor PCardinal(@Vector[4])^; + + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ĸµ Iv + Move(TV[0], Vector[0], SizeOf(TCnDESIv)); + end; + + // ĩβ 0 ⲿжɾ +end; + +procedure SetResultLengthUsingInput(const Str: AnsiString; var Res: AnsiString); +var + Len: Integer; +begin + Len := Length(Str); + if Len < CN_DES_BLOCKSIZE then + Len := CN_DES_BLOCKSIZE + else + Len := (((Len - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE; + SetLength(Res, Len); +end; + +function DESEncryptEcbStrToHex(const Str, Key: AnsiString): AnsiString; +var + TempResult: AnsiString; +begin + Result := ''; + if Str = '' then + Exit; + + SetResultLengthUsingInput(Str, TempResult); + DESEncryptEcbStr(Key, Str, @TempResult[1]); + Result := AnsiStrToHex(TempResult); +end; + +function DESDecryptEcbStrFromHex(const HexStr, Key: AnsiString): AnsiString; +var + Str: AnsiString; +begin + Str := HexToAnsiStr(HexStr); + SetResultLengthUsingInput(Str, Result); + DESDecryptEcbStr(Key, Str, @(Result[1])); +end; + +function DESEncryptCbcStrToHex(const Str, Key, Iv: AnsiString): AnsiString; +var + TempResult: AnsiString; +begin + Result := ''; + if Str = '' then + Exit; + + SetResultLengthUsingInput(Str, TempResult); + DESEncryptCbcStr(Key, PAnsiChar(Iv), Str, @TempResult[1]); + Result := AnsiStrToHex(TempResult); +end; + +function DESDecryptCbcStrFromHex(const HexStr, Key, Iv: AnsiString): AnsiString; +var + Str: AnsiString; +begin + Str := HexToAnsiStr(HexStr); + SetResultLengthUsingInput(Str, Result); + DESDecryptCbcStr(Key, PAnsiChar(Iv), Str, @(Result[1])); +end; + +function DESEncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + I: Integer; + SubKey: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + MakeInputBytesAlign(Input); + + FillChar(KeyByte[0], SizeOf(TCnDESKey), 0); + MoveMost(Key[0], KeyByte[0], Length(Key), SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + DesData(dmEncry, SubKey, StrByte, OutByte); + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +function DESDecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + I: Integer; + SubKey: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + FillChar(KeyByte[0], SizeOf(TCnDESKey), 0); + MoveMost(Key[0], KeyByte[0], Length(Key), SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + DesData(dmDecry, SubKey, StrByte, OutByte); + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +function DESEncryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + Vector: TCnDESIv; + I: Integer; + SubKey: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + MakeInputBytesAlign(Input); + + FillChar(KeyByte[0], SizeOf(TCnDESKey), 0); + MoveMost(Key[0], KeyByte[0], Length(Key), SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + FillChar(Vector[0], SizeOf(TCnDESIv), 0); + MoveMost(Iv[0], Vector[0], Length(Iv), SizeOf(TCnDESIv)); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + + // CBC ݿֵȸ Iv + PCardinal(@StrByte[0])^ := PCardinal(@StrByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@StrByte[4])^ := PCardinal(@StrByte[4])^ xor PCardinal(@Vector[4])^; + + // ټ + DesData(dmEncry, SubKey, StrByte, OutByte); + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ܽµ Iv + Move(OutByte[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +function DESDecryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + Vector, TV: TCnDESIv; + I: Integer; + SubKey: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + FillChar(KeyByte[0], SizeOf(TCnDESKey), 0); + MoveMost(Key[0], KeyByte[0], Length(Key), SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + FillChar(Vector[0], SizeOf(TCnDESIv), 0); + MoveMost(Iv[0], Vector[0], Length(Iv), SizeOf(TCnDESIv)); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + Move(StrByte[0], TV[0], SizeOf(TCnDESIv)); // ȴһ + + // Ƚ + DesData(dmDecry, SubKey, StrByte, OutByte); + + // CBC ݿֵܺٸ Iv + PCardinal(@OutByte[0])^ := PCardinal(@OutByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@OutByte[4])^ := PCardinal(@OutByte[4])^ xor PCardinal(@Vector[4])^; + + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ĸµ Iv + Move(TV[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +procedure DESEncryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; Dest: TStream); overload; +var + TempIn, TempOut: TCnDESBuffer; + Done: Cardinal; + SubKey: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + MakeKey(Key, SubKey); + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + DesData(dmEncry, SubKey, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Dec(Count, SizeOf(TCnDESBuffer)); + end; + + if Count > 0 then // β 0 + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorDESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + + DesData(dmEncry, SubKey, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + end; +end; + +procedure DESDecryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; Dest: TStream); overload; +var + TempIn, TempOut: TCnDESBuffer; + Done: Cardinal; + SubKey: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + if (Count mod SizeOf(TCnDESBuffer)) > 0 then + raise ECnDESException.Create(SCnErrorDESInvalidInBufSize); + + MakeKey(Key, SubKey); + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + DesData(dmDecry, SubKey, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Dec(Count, SizeOf(TCnDESBuffer)); + end; +end; + +procedure DESEncryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +var + TempIn, TempOut: TCnDESBuffer; + Vector: TCnDESIv; + Done: Cardinal; + SubKey: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + MakeKey(Key, SubKey); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + + DesData(dmEncry, SubKey, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Move(TempOut[0], Vector[0], SizeOf(TCnDESIv)); + Dec(Count, SizeOf(TCnDESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorDESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + + DesData(dmEncry, SubKey, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + end; +end; + +procedure DESDecryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +var + TempIn, TempOut: TCnDESBuffer; + Vector1, Vector2: TCnDESIv; + Done: Cardinal; + SubKey: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + if (Count mod SizeOf(TCnDESBuffer)) > 0 then + raise ECnDESException.Create(SCnErrorDESInvalidInBufSize); + + Vector1 := InitVector; + MakeKey(Key, SubKey); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorDESReadError); + + Move(TempIn[0], Vector2[0], SizeOf(TCnDESIv)); + DesData(dmDecry, SubKey, TempIn, TempOut); + + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorDESWriteError); + + Vector1 := Vector2; + Dec(Count, SizeOf(TCnDESBuffer)); + end; +end; + +procedure Make3DESKeys(Keys: AnsiString; var K1, K2, K3: TCnDESKey); overload; +var + I: Integer; +begin + if Length(Keys) < CN_TRIPLE_DES_KEYSIZE then + while Length(Keys) < CN_TRIPLE_DES_KEYSIZE do + Keys := Keys + Chr(0); + + for I := 0 to CN_DES_KEYSIZE - 1 do + begin + K1[I] := Ord(Keys[I + 1]); + K2[I] := Ord(Keys[I + 1 + CN_DES_KEYSIZE]); + K3[I] := Ord(Keys[I + 1 + CN_DES_KEYSIZE * 2]); + end; +end; + +procedure Make3DESKeys(Keys: TCn3DESKey; var K1, K2, K3: TCnDESKey); overload; +var + I: Integer; +begin + for I := 0 to CN_DES_KEYSIZE - 1 do + begin + K1[I] := Keys[I]; + K2[I] := Keys[I + CN_DES_KEYSIZE]; + K3[I] := Keys[I + CN_DES_KEYSIZE * 2]; + end; +end; + +procedure Make3DESKeys(Keys: TBytes; var K1, K2, K3: TCnDESKey); overload; +var + I, Len: Integer; +begin + Len := Length(Keys); + if Len < CN_TRIPLE_DES_KEYSIZE then + begin + SetLength(Keys, CN_TRIPLE_DES_KEYSIZE); + for I := Len to CN_TRIPLE_DES_KEYSIZE - 1 do + Keys[I] := 0; + end; + + for I := 0 to CN_DES_KEYSIZE - 1 do + begin + K1[I] := Ord(Keys[I]); + K2[I] := Ord(Keys[I + CN_DES_KEYSIZE]); + K3[I] := Ord(Keys[I + CN_DES_KEYSIZE * 2]); + end; +end; + +function TripleDESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +begin + Result := (((InputByteLength - 1) div CN_TRIPLE_DES_BLOCKSIZE) + 1) * CN_TRIPLE_DES_BLOCKSIZE; +end; + +procedure TripleDESEncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + Str: AnsiString; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + Str := Input; + MakeInputAlign(Str); + + if Str = '' then // մֱӷؿ + begin + if Output <> nil then + Output[0] := #0; + Exit; + end; + + for I := 0 to Length(Str) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Str[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + + DesData(dmEncry, SubKey1, StrByte, OutByte); + DesData(dmDecry, SubKey2, OutByte, StrByte); + DesData(dmEncry, SubKey3, StrByte, OutByte); + + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +procedure TripleDESDecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + + DesData(dmDecry, SubKey3, StrByte, OutByte); + DesData(dmEncry, SubKey2, OutByte, StrByte); + DesData(dmDecry, SubKey1, StrByte, OutByte); + + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; + + // ĩβ 0 ⲿжɾ +end; + +procedure TripleDESEncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + Vector: TCnDESIv; + Str: AnsiString; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + Str := Input; + MakeInputAlign(Str); + + if Str = '' then // մֱӷؿ + begin + if Output <> nil then + Output[0] := #0; + Exit; + end; + + Move(Iv^, Vector[0], SizeOf(TCnDESIv)); + + for I := 0 to Length(Str) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Str[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + + // CBC ݿֵȸ Iv + PCardinal(@StrByte[0])^ := PCardinal(@StrByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@StrByte[4])^ := PCardinal(@StrByte[4])^ xor PCardinal(@Vector[4])^; + + // ټ + DesData(dmEncry, SubKey1, StrByte, OutByte); + DesData(dmDecry, SubKey2, OutByte, StrByte); + DesData(dmEncry, SubKey3, StrByte, OutByte); + + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ܽµ Iv + Move(OutByte[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +procedure TripleDESDecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + Vector, TV: TCnDESIv; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + Move(Iv^, Vector[0], SizeOf(TCnDESIv)); + + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + Move(StrByte[0], TV[0], SizeOf(TCnDESIv)); // ȴһ + + // Ƚ + DesData(dmDecry, SubKey3, StrByte, OutByte); + DesData(dmEncry, SubKey2, OutByte, StrByte); + DesData(dmDecry, SubKey1, StrByte, OutByte); + + // CBC ݿֵܺٸ Iv + PCardinal(@OutByte[0])^ := PCardinal(@OutByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@OutByte[4])^ := PCardinal(@OutByte[4])^ xor PCardinal(@Vector[4])^; + + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ĸµ Iv + Move(TV[0], Vector[0], SizeOf(TCnDESIv)); + end; + + // ĩβ 0 ⲿжɾ +end; + +function TripleDESEncryptEcbStrToHex(const Str, Key: AnsiString): AnsiString; +var + TempResult, Temp: AnsiString; + I: Integer; +begin + SetResultLengthUsingInput(Str, TempResult); + TripleDESEncryptEcbStr(Key, Str, @TempResult[1]); + + Result := ''; + for I := 0 to Length(TempResult) - 1 do + begin + Temp := AnsiString(Format('%x', [Ord(TempResult[I + 1])])); + if Length(Temp) = 1 then + Temp := '0' + Temp; + Result := Result + Temp; + end; +end; + +function TripleDESDecryptEcbStrFromHex(const HexStr, Key: AnsiString): AnsiString; +var + Str: AnsiString; +begin + Str := HexToAnsiStr(HexStr); + SetResultLengthUsingInput(Str, Result); + TripleDESDecryptEcbStr(Key, Str, @(Result[1])); +end; + +function TripleDESEncryptCbcStrToHex(const Str, Key, Iv: AnsiString): AnsiString; +var + TempResult, Temp: AnsiString; + I: Integer; +begin + SetResultLengthUsingInput(Str, TempResult); + TripleDESEncryptCbcStr(Key, PAnsiChar(Iv), Str, @TempResult[1]); + + Result := ''; + for I := 0 to Length(TempResult) - 1 do + begin + Temp := AnsiString(Format('%x', [Ord(TempResult[I + 1])])); + if Length(Temp) = 1 then + Temp := '0' + Temp; + Result := Result + Temp; + end; +end; + +function TripleDESDecryptCbcStrFromHex(const HexStr, Key, Iv: AnsiString): AnsiString; +var + Str: AnsiString; +begin + Str := HexToAnsiStr(HexStr); + SetResultLengthUsingInput(Str, Result); + TripleDESDecryptCbcStr(Key, PAnsiChar(Iv), Str, @(Result[1])); +end; + +function TripleDESEncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + MakeInputBytesAlign(Input); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + + DesData(dmEncry, SubKey1, StrByte, OutByte); + DesData(dmDecry, SubKey2, OutByte, StrByte); + DesData(dmEncry, SubKey3, StrByte, OutByte); + + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +function TripleDESDecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + + DesData(dmDecry, SubKey3, StrByte, OutByte); + DesData(dmEncry, SubKey2, OutByte, StrByte); + DesData(dmDecry, SubKey1, StrByte, OutByte); + + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +function TripleDESEncryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + Vector: TCnDESIv; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + MakeInputBytesAlign(Input); + FillChar(Vector[0], SizeOf(TCnDESIv), 0); + MoveMost(Iv[0], Vector[0], Length(Iv), SizeOf(TCnDESIv)); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + + // CBC ݿֵȸ Iv + PCardinal(@StrByte[0])^ := PCardinal(@StrByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@StrByte[4])^ := PCardinal(@StrByte[4])^ xor PCardinal(@Vector[4])^; + + // ټ + DesData(dmEncry, SubKey1, StrByte, OutByte); + DesData(dmDecry, SubKey2, OutByte, StrByte); + DesData(dmEncry, SubKey3, StrByte, OutByte); + + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ܽµ Iv + Move(OutByte[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +function TripleDESDecryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + Vector, TV: TCnDESIv; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + FillChar(Vector[0], SizeOf(TCnDESIv), 0); + MoveMost(Iv[0], Vector[0], Length(Iv), SizeOf(TCnDESIv)); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + Move(StrByte[0], TV[0], SizeOf(TCnDESIv)); // ȴһ + + // Ƚ + DesData(dmDecry, SubKey3, StrByte, OutByte); + DesData(dmEncry, SubKey2, OutByte, StrByte); + DesData(dmDecry, SubKey1, StrByte, OutByte); + + // CBC ݿֵܺٸ Iv + PCardinal(@OutByte[0])^ := PCardinal(@OutByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@OutByte[4])^ := PCardinal(@OutByte[4])^ xor PCardinal(@Vector[4])^; + + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ĸµ Iv + Move(TV[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +procedure TripleDESEncryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; Dest: TStream); overload; +var + K1, K2, K3: TCnDESKey; + TempIn, TempOut: TCnDESBuffer; + Done: Cardinal; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + DesData(dmEncry, SubKey1, TempIn, TempOut); + DesData(dmDecry, SubKey2, TempOut, TempIn); + DesData(dmEncry, SubKey3, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Dec(Count, SizeOf(TCnDESBuffer)); + end; + + if Count > 0 then // β 0 + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorDESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + + DesData(dmEncry, SubKey1, TempIn, TempOut); + DesData(dmDecry, SubKey2, TempOut, TempIn); + DesData(dmEncry, SubKey3, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + end; +end; + +procedure TripleDESDecryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; Dest: TStream); overload; +var + K1, K2, K3: TCnDESKey; + TempIn, TempOut: TCnDESBuffer; + Done: Cardinal; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + if (Count mod SizeOf(TCnDESBuffer)) > 0 then + raise ECnDESException.Create(SCnErrorDESInvalidInBufSize); + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + DesData(dmDecry, SubKey3, TempIn, TempOut); + DesData(dmEncry, SubKey2, TempOut, TempIn); + DesData(dmDecry, SubKey1, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Dec(Count, SizeOf(TCnDESBuffer)); + end; +end; + +procedure TripleDESEncryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +var + K1, K2, K3: TCnDESKey; + TempIn, TempOut: TCnDESBuffer; + Vector: TCnDESIv; + Done: Cardinal; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + + DesData(dmEncry, SubKey1, TempIn, TempOut); + DesData(dmDecry, SubKey2, TempOut, TempIn); + DesData(dmEncry, SubKey3, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Move(TempOut[0], Vector[0], SizeOf(TCnDESIv)); + Dec(Count, SizeOf(TCnDESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorDESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + + DesData(dmEncry, SubKey1, TempIn, TempOut); + DesData(dmDecry, SubKey2, TempOut, TempIn); + DesData(dmEncry, SubKey3, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + end; +end; + +procedure TripleDESDecryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +var + K1, K2, K3: TCnDESKey; + TempIn, TempOut: TCnDESBuffer; + Vector1, Vector2: TCnDESIv; + Done: Cardinal; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + if (Count mod SizeOf(TCnDESBuffer)) > 0 then + raise ECnDESException.Create(SCnErrorDESInvalidInBufSize); + + Vector1 := InitVector; + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorDESReadError); + + Move(TempIn[0], Vector2[0], SizeOf(TCnDESIv)); + + DesData(dmDecry, SubKey3, TempIn, TempOut); + DesData(dmEncry, SubKey2, TempOut, TempIn); + DesData(dmDecry, SubKey1, TempIn, TempOut); + + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorDESWriteError); + + Vector1 := Vector2; + Dec(Count, SizeOf(TCnDESBuffer)); + end; +end; + +end. diff --git a/CnPack/Crypto/CnKDF.pas b/CnPack/Crypto/CnKDF.pas index 8fc6ab4..b361ec5 100644 --- a/CnPack/Crypto/CnKDF.pas +++ b/CnPack/Crypto/CnKDF.pas @@ -1,807 +1,804 @@ -{******************************************************************************} -{ CnPack For Delphi/C++Builder } -{ йԼĿԴ } -{ (C)Copyright 2001-2025 CnPack } -{ ------------------------------------ } -{ } -{ ǿԴ CnPack ķЭ } -{ ĺ·һ } -{ } -{ һĿϣãûκεû } -{ ʺضĿĶĵϸ CnPack Э顣 } -{ } -{ ӦѾͿһյһ CnPack Эĸ } -{ ûУɷǵվ } -{ } -{ վַhttps://www.cnpack.org } -{ ʼmaster@cnpack.org } -{ } -{******************************************************************************} - -unit CnKDF; -{* |
-================================================================================
-* ƣ
-* ԪƣԿ㷨KDFԪ
-* ԪߣCnPack  (master@cnpack.org)
-*     עԪʵ˻ RFC2898  PBKDF1  PBKDF2 Կ㷨 PBKDF1 ֧ MD2 㷨
-*           ͬʱҲʵ˻ RFC5869  HKDF HMac Կ㷨
-*            SM2/SM9 㷨й涨㷨
-* ƽ̨WinXP + Delphi 5.0
-* ݲԣδ
-*   õԪ豾ػ
-* ޸ļ¼2025.01.09 V1.5
-*                HKDF ʵֺ
-*           2022.06.21 V1.4
-*               ϲһֽ CnSM2SM9KDF  AnsiString ڸ߰汾 Delphi ¿
-*           2022.04.26 V1.3
-*               ޸ LongWord  Integer ַת֧ MacOS64
-*           2022.01.02 V1.2
-*                CnPBKDF2 һԼ Unicode µļ
-*           2021.11.25 V1.1
-*                CnSM2KDF  Unicode µļ
-*           2020.03.30 V1.0
-*               Ԫ CnPemUtils ж
-================================================================================
-|
} - -interface - -{$I CnPack.inc} - -uses - SysUtils, Classes, CnNative, CnMD5, CnSHA1, CnSHA2, CnSHA3, CnSM3; - -type - TCnKeyDeriveHash = (ckdMd5, ckdSha256, ckdSha1); - {* CnGetDeriveKey ʹõӴշ} - - TCnPBKDF1KeyHash = (cpdfMd2, cpdfMd5, cpdfSha1); - {* PBKDF1 涨Ӵշ MD2 Dz֧} - - TCnPBKDF2KeyHash = (cpdfSha1Hmac, cpdfSha256Hmac); - {* PBKDF2 涨Ӵշ} - - TCnHKDFHash = (chkMd5, chkSha1, chkSha256, chkSha3_256, chkSm3); - {* HKDFHMAC-based Key Derivation Functionֵ֧Ӵ} - - ECnKDFException = class(Exception); - {* KDF 쳣} - -function CnGetDeriveKey(const Password: AnsiString; const Salt: AnsiString; - OutKey: PAnsiChar; KeyLength: Cardinal; KeyHash: TCnKeyDeriveHash = ckdMd5): Boolean; -{* Openssl е BytesToKeyָӴ㷨ɼ Key - Ŀǰ KeyLength ֧ HashҲ MD5 32 ֽڣSHA256 64 ֽڡ - - - const Password: AnsiString - - const Salt: AnsiString - ֵ - OutKey: PAnsiChar - Կݿַ - KeyLength: Cardinal - Կݿֽڳ - KeyHash: TCnKeyDeriveHash - Ӵ㷨 - - ֵBoolean - Ƿɳɹ -} - -function CnPBKDF1(const Password: AnsiString; const Salt: AnsiString; Count: Integer; - DerivedKeyByteLength: Integer; KeyHash: TCnPBKDF1KeyHash = cpdfMd5): AnsiString; -{* Password Based KDF 1 ʵ֣򵥵Ĺ̶Ӵյֻ֧ MD5 SHA1뷵ֵΪ AnsiString - DerivedKeyByteLength Կֽȹ̶ - - - const Password: AnsiString - - const Salt: AnsiString - ֵ - Count: Integer - - DerivedKeyByteLength: Integer - ɵԿֽڳ - KeyHash: TCnPBKDF1KeyHash - Ӵ㷨 - - ֵAnsiString - ɵԿ -} - -function CnPBKDF2(const Password: AnsiString; const Salt: AnsiString; Count: Integer; - DerivedKeyByteLength: Integer; KeyHash: TCnPBKDF2KeyHash = cpdfSha1Hmac): AnsiString; -{* Password Based KDF 2 ʵ֣ HMAC-SHA1 HMAC-SHA256뷵ֵΪ AnsiString - DerivedKeyByteLength Կֽȿɱ䣬 - - - const Password: AnsiString - - const Salt: AnsiString - ֵ - Count: Integer - - DerivedKeyByteLength: Integer - ɵԿֽڳ - KeyHash: TCnPBKDF2KeyHash - Ӵ㷨 - - ֵAnsiString - ɵԿ -} - -function CnPBKDF1Bytes(const Password: TBytes; const Salt: TBytes; Count: Integer; - DerivedKeyByteLength: Integer; KeyHash: TCnPBKDF1KeyHash = cpdfMd5): TBytes; -{* Password Based KDF 1 ʵ֣򵥵Ĺ̶Ӵյֻ֧ MD5 SHA1뷵ֵΪֽ顣 - DerivedKeyByteLength Կֽȹ̶ - - - const Password: TBytes - - const Salt: TBytes - ֵ - Count: Integer - - DerivedKeyByteLength: Integer - ɵԿֽڳ - KeyHash: TCnPBKDF1KeyHash - Ӵ㷨 - - ֵTBytes - ɵԿ -} - -function CnPBKDF2Bytes(const Password: TBytes; const Salt: TBytes; Count: Integer; - DerivedKeyByteLength: Integer; KeyHash: TCnPBKDF2KeyHash = cpdfSha1Hmac): TBytes; -{* Password Based KDF 2 ʵ֣ HMAC-SHA1 HMAC-SHA256뷵ֵΪֽ顣 - DerivedKeyByteLength Կֽȿɱ䣬 - - - const Password: TBytes - - const Salt: TBytes - ֵ - Count: Integer - - DerivedKeyByteLength: Integer - ɵԿֽڳ - KeyHash: TCnPBKDF2KeyHash - Ӵ㷨 - - ֵTBytes - ɵԿ -} - -// ============ SM2/SM9 й涨ͬһԿַװʵ =============== - -function CnSM2KDF(const Data: AnsiString; DerivedKeyByteLength: Integer): AnsiString; -{* SM2 Բ߹Կ㷨й涨ԿDerivedKeyLength Կֽ - AnsiStringͬʱƺҲû SharedInfo ANSI-X9.63-KDF - - - const Data: AnsiString - Կԭʼݣ - DerivedKeyByteLength: Integer - ɵԿֽڳ - - ֵAnsiString - ɵԿ -} - -function CnSM9KDF(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): AnsiString; -{* SM9 ʶ㷨й涨ԿDerivedKeyLength Կֽ - AnsiStringͬʱƺҲû SharedInfo ANSI-X9.63-KDF - - - Data: Pointer - Կԭʼݿַ - DataByteLen: Integer - Կԭʼݵֽڳ - DerivedKeyByteLength: Integer - ɵԿֽڳ - - ֵAnsiString - ɵԿ -} - -function CnSM2KDFBytes(const Data: TBytes; DerivedKeyByteLength: Integer): TBytes; -{* Ϊֽʽ SM2 Բ߹Կ㷨й涨Կ - DerivedKeyLength Կֽɵֽ顣 - - - const Data: TBytes - Կԭʼݵֽ - DerivedKeyByteLength: Integer - ɵԿֽڳ - - ֵTBytes - ɵԿ -} - -function CnSM9KDFBytes(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): TBytes; -{* Ϊڴʽ SM9 ʶ㷨й涨Կ - DerivedKeyLength Կֽɵֽ顣 - - - Data: Pointer - Կԭʼݿַ - DataByteLen: Integer - Կԭʼݵֽڳ - DerivedKeyByteLength: Integer - ɵԿֽڳ - - ֵTBytes - ɵԿ -} - -function CnSM2SM9KDF(Data: TBytes; DerivedKeyByteLength: Integer): TBytes; overload; -{* Ϊֽʽ SM2 Բ߹Կ㷨 SM9 ʶ㷨й涨Կ - DerivedKeyLength ԿֽɵԿֽ顣 - - - Data: TBytes - Կԭʼݵֽ - DerivedKeyByteLength: Integer - ɵԿֽڳ - - ֵTBytes - ɵԿ -} - -function CnSM2SM9KDF(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): TBytes; overload; -{* Ϊڴʽ SM2 Բ߹Կ㷨 SM9 ʶ㷨й涨Կ - DerivedKeyLength ԿֽԿֽ顣 - - - Data: Pointer - Կԭʼݿַ - DataByteLen: Integer - Կԭʼݵֽڳ - DerivedKeyByteLength: Integer - ɵԿֽڳ - - ֵTBytes - ɵԿ -} - -function CnHKDF(HKDF: TCnHKDFHash; IKM: Pointer; IKMByteLen: Integer; - Salt: Pointer; SaltByteLen: Integer; Info: Pointer; InfoByteLen: Integer; - DerivedKeyByteLength: Integer): TBytes; overload; -{* HMAC KDF Կ IKMSalt InfoָȵԿ - Salt Ϊգڲʹù̶Ӵսȵȫ 0Info ΪաɵԿ - - - HKDF: TCnHKDFHash - Ӵ㷨 - IKM: Pointer - ԿݣInput Keying Materialַ - IKMByteLen: Integer - Կݵֽڳ - Salt: Pointer - Կֵݿַ - SaltByteLen: Integer - Կֵݵֽڳ - Info: Pointer - ԿĿѡϢݿַ - InfoByteLen: Integer - ԿĿѡϢݵֽڳ - DerivedKeyByteLength: Integer - ɵԿֽڳ - - ֵTBytes - ɵԿ -} - -function CnHKDFBytes(HKDF: TCnHKDFHash; IKM: TBytes; Salt: TBytes; Info: TBytes; - DerivedKeyByteLength: Integer): TBytes; overload; -{* HMAC KDF Կ IKMSalt Info ֽ飬ָȵԿ - Salt Ϊգڲʹù̶Ӵսȵȫ 0Info ΪաɵԿ - - HKDF: TCnHKDFHash - Ӵ㷨 - IKM: TBytes - Կ - Salt: TBytes - Կֵ - Info: TBytes - ԿĿѡϢ - DerivedKeyByteLength: Integer - ɵԿֽڳ - - ֵTBytes - ɵԿ -} - -implementation - -resourcestring - SCnErrorKDFKeyTooLong = 'Derived Key Too Long.'; - SCnErrorKDFParam = 'Invalid Parameters.'; - SCnErrorKDFHashNOTSupport = 'Hash Method NOT Support.'; - -function Min(A, B: Integer): Integer; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - if A < B then - Result := A - else - Result := B; -end; - -function CnGetDeriveKey(const Password, Salt: AnsiString; OutKey: PAnsiChar; KeyLength: Cardinal; - KeyHash: TCnKeyDeriveHash): Boolean; -var - Md5Dig, Md5Dig2: TCnMD5Digest; - Sha256Dig, Sha256Dig2: TCnSHA256Digest; - SaltBuf, PS, PSMD5, PSSHA256: AnsiString; -begin - Result := False; - - if (Password = '') or (OutKey = nil) or (KeyLength < 8) then - Exit; - - SetLength(SaltBuf, 8); - FillChar(SaltBuf[1], Length(SaltBuf), 0); - if Salt <> '' then - Move(Salt[1], SaltBuf[1], Min(Length(Salt), 8)); - - if not (KeyHash in [ckdMd5, ckdSha256]) then - raise ECnKDFException.Create(SCnErrorKDFHashNOTSupport); - - PS := AnsiString(Password) + SaltBuf; // 涨ǰ 8 ֽΪ Salt - if KeyHash = ckdMd5 then - begin - SetLength(PSMD5, SizeOf(TCnMD5Digest) + Length(PS)); - Move(PS[1], PSMD5[SizeOf(TCnMD5Digest) + 1], Length(PS)); - Md5Dig := MD5StringA(PS); - // Salt ƴ MD5 16 ByteΪһ - - Move(Md5Dig[0], OutKey^, Min(KeyLength, SizeOf(TCnMD5Digest))); - if KeyLength <= SizeOf(TCnMD5Digest) then - begin - Result := True; - Exit; - end; - - KeyLength := KeyLength - SizeOf(TCnMD5Digest); - OutKey := PAnsiChar(TCnNativeInt(OutKey) + SizeOf(TCnMD5Digest)); - - Move(Md5Dig[0], PSMD5[1], SizeOf(TCnMD5Digest)); - Md5Dig2 := MD5StringA(PSMD5); - Move(Md5Dig2[0], OutKey^, Min(KeyLength, SizeOf(TCnMD5Digest))); - if KeyLength <= SizeOf(TCnMD5Digest) then - Result := True; - - // KeyLength ̫㲻 - end - else if KeyHash = ckdSha256 then - begin - SetLength(PSSHA256, SizeOf(TCnSHA256Digest) + Length(PS)); - Move(PS[1], PSSHA256[SizeOf(TCnSHA256Digest) + 1], Length(PS)); - Sha256Dig := SHA256StringA(PS); - // Salt ƴ SHA256 32 ByteΪһ - - Move(Sha256Dig[0], OutKey^, Min(KeyLength, SizeOf(TCnSHA256Digest))); - if KeyLength <= SizeOf(TCnSHA256Digest) then - begin - Result := True; - Exit; - end; - - KeyLength := KeyLength - SizeOf(TCnSHA256Digest); - OutKey := PAnsiChar(TCnNativeInt(OutKey) + SizeOf(TCnSHA256Digest)); - - Move(Sha256Dig[0], PSSHA256[1], SizeOf(TCnSHA256Digest)); - Sha256Dig2 := SHA256StringA(PSSHA256); - Move(Sha256Dig2[0], OutKey^, Min(KeyLength, SizeOf(TCnSHA256Digest))); - if KeyLength <= SizeOf(TCnSHA256Digest) then - Result := True; - - // KeyLength ̫㲻 - end; -end; - -(* - T_1 = Hash (P || S) , - T_2 = Hash (T_1) , - ... - T_c = Hash (T_{c-1}) , - DK = Tc<0..dkLen-1> -*) -function CnPBKDF1(const Password, Salt: AnsiString; Count, DerivedKeyByteLength: Integer; - KeyHash: TCnPBKDF1KeyHash): AnsiString; -var - P, S, Res: TBytes; -begin - P := AnsiToBytes(Password); - S := AnsiToBytes(Salt); - Res := CnPBKDF1Bytes(P, S, Count, DerivedKeyByteLength, KeyHash); - Result := BytesToAnsi(Res); -end; - -{ - DK = T1 + T2 + ... + Tdklen/hlen - Ti = F(Password, Salt, c, i) - - F(Password, Salt, c, i) = U1 ^ U2 ^ ... ^ Uc - - U1 = PRF(Password, Salt + INT_32_BE(i)) - U2 = PRF(Password, U1) - ... - Uc = PRF(Password, Uc-1) -} -function CnPBKDF2(const Password, Salt: AnsiString; Count, DerivedKeyByteLength: Integer; - KeyHash: TCnPBKDF2KeyHash): AnsiString; -var - P, S, Res: TBytes; -begin - P := AnsiToBytes(Password); - S := AnsiToBytes(Salt); - Res := CnPBKDF2Bytes(P, S, Count, DerivedKeyByteLength, KeyHash); - Result := BytesToAnsi(Res); -end; - -function CnPBKDF1Bytes(const Password, Salt: TBytes; Count, DerivedKeyByteLength: Integer; - KeyHash: TCnPBKDF1KeyHash = cpdfMd5): TBytes; -var - I: Integer; - Md5Dig, TM: TCnMD5Digest; - Sha1Dig, TS: TCnSHA1Digest; - Ptr: PAnsiChar; -begin - Result := nil; - if (Password = nil) or (Count <= 0) or (DerivedKeyByteLength <= 0) then - raise ECnKDFException.Create(SCnErrorKDFParam); - - case KeyHash of - cpdfMd5: - begin - if DerivedKeyByteLength > SizeOf(TCnMD5Digest) then - raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); - - SetLength(Result, DerivedKeyByteLength); - Md5Dig := MD5Bytes(ConcatBytes(Password, Salt)); // Got T1 - if Count > 1 then - begin - Ptr := PAnsiChar(@TM[0]); - for I := 2 to Count do - begin - TM := Md5Dig; - Md5Dig := MD5Buffer(Ptr, SizeOf(TCnMD5Digest)); // Got T_c - end; - end; - - Move(Md5Dig[0], Result[0], DerivedKeyByteLength); - end; - cpdfSha1: - begin - if DerivedKeyByteLength > SizeOf(TCnSHA1Digest) then - raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); - - SetLength(Result, DerivedKeyByteLength); - Sha1Dig := SHA1Bytes(ConcatBytes(Password, Salt)); // Got T1 - if Count > 1 then - begin - Ptr := PAnsiChar(@TS[0]); - for I := 2 to Count do - begin - TS := Sha1Dig; - Sha1Dig := SHA1Buffer(Ptr, SizeOf(TCnSHA1Digest)); // Got T_c - end; - end; - - Move(Sha1Dig[0], Result[0], DerivedKeyByteLength); - end; - else - raise ECnKDFException.Create(SCnErrorKDFHashNOTSupport); - end; -end; - -function CnPBKDF2Bytes(const Password, Salt: TBytes; Count, DerivedKeyByteLength: Integer; - KeyHash: TCnPBKDF2KeyHash = cpdfSha1Hmac): TBytes; -var - HLen, D, I, J, K: Integer; - Sha1Dig1, Sha1Dig, T1: TCnSHA1Digest; - Sha256Dig1, Sha256Dig, T256: TCnSHA256Digest; - S, S1, S256, Pad: TBytes; - PAddr: Pointer; -begin - Result := nil; - if (Salt = nil) or (Count <= 0) or (DerivedKeyByteLength <=0) then - raise ECnKDFException.Create(SCnErrorKDFParam); - - if (Password = nil) or (Length(Password) = 0) then - PAddr := nil - else - PAddr := @Password[0]; - - case KeyHash of - cpdfSha1Hmac: - HLen := 20; - cpdfSha256Hmac: - HLen := 32; - else - raise ECnKDFException.Create(SCnErrorKDFParam); - end; - - D := (DerivedKeyByteLength div HLen) + 1; - SetLength(S1, SizeOf(TCnSHA1Digest)); - SetLength(S256, SizeOf(TCnSHA256Digest)); - - SetLength(Pad, 4); - if KeyHash = cpdfSha1Hmac then - begin - for I := 1 to D do - begin - Pad[0] := I shr 24; - Pad[1] := I shr 16; - Pad[2] := I shr 8; - Pad[3] := I; - S := ConcatBytes(Salt, Pad); - - SHA1Hmac(PAddr, Length(Password), PAnsiChar(@S[0]), Length(S), Sha1Dig1); - T1 := Sha1Dig1; - - for J := 2 to Count do - begin - SHA1Hmac(PAddr, Length(Password), PAnsiChar(@T1[0]), SizeOf(TCnSHA1Digest), Sha1Dig); - T1 := Sha1Dig; - for K := Low(TCnSHA1Digest) to High(TCnSHA1Digest) do - Sha1Dig1[K] := Sha1Dig1[K] xor T1[K]; - end; - - Move(Sha1Dig1[0], S1[0], Length(S1)); - Result := ConcatBytes(Result, S1); - end; - Result := Copy(Result, 0, DerivedKeyByteLength); - end - else if KeyHash = cpdfSha256Hmac then - begin - for I := 1 to D do - begin - Pad[0] := I shr 24; - Pad[1] := I shr 16; - Pad[2] := I shr 8; - Pad[3] := I; - S := ConcatBytes(Salt, Pad); - - SHA256Hmac(PAddr, Length(Password), PAnsiChar(@S[0]), Length(S), Sha256Dig1); - T256 := Sha256Dig1; - - for J := 2 to Count do - begin - SHA256Hmac(PAddr, Length(Password), PAnsiChar(@T256[0]), SizeOf(TCnSHA256Digest), Sha256Dig); - T256 := Sha256Dig; - for K := Low(TCnSHA256Digest) to High(TCnSHA256Digest) do - Sha256Dig1[K] := Sha256Dig1[K] xor T256[K]; - end; - - Move(Sha256Dig1[0], S256[0], SizeOf(TCnSHA256Digest)); - Result := ConcatBytes(Result, S256); - end; - Result := Copy(Result, 0, DerivedKeyByteLength); - end; -end; - -function CnSM2KDF(const Data: AnsiString; DerivedKeyByteLength: Integer): AnsiString; -var - Res: TBytes; -begin - if (Data = '') or (DerivedKeyByteLength <= 0) then - raise ECnKDFException.Create(SCnErrorKDFParam); - - Res := CnSM2SM9KDF(@Data[1], Length(Data), DerivedKeyByteLength); - Result := BytesToAnsi(Res); -end; - -function CnSM9KDF(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): AnsiString; -var - Res: TBytes; -begin - Res := CnSM2SM9KDF(Data, DataByteLen, DerivedKeyByteLength); - Result := BytesToAnsi(Res); -end; - -function CnSM2KDFBytes(const Data: TBytes; DerivedKeyByteLength: Integer): TBytes; -begin - Result := CnSM2SM9KDF(Data, DerivedKeyByteLength); -end; - -function CnSM9KDFBytes(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): TBytes; -begin - Result := CnSM2SM9KDF(Data, DataByteLen, DerivedKeyByteLength); -end; - -function CnSM2SM9KDF(Data: TBytes; DerivedKeyByteLength: Integer): TBytes; -begin - if (Data = nil) or (Length(Data) <= 0) or (DerivedKeyByteLength <= 0) then - raise ECnKDFException.Create(SCnErrorKDFParam); - - Result := CnSM2SM9KDF(@Data[0], Length(Data), DerivedKeyByteLength); -end; - -function CnSM2SM9KDF(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): TBytes; overload; -var - DArr: TBytes; - CT, SCT: Cardinal; - I, CeilLen: Integer; - IsInt: Boolean; - SM3D: TCnSM3Digest; -begin - Result := nil; - if (Data = nil) or (DataByteLen <= 0) or (DerivedKeyByteLength <= 0) then - raise ECnKDFException.Create(SCnErrorKDFParam); - - DArr := nil; - CT := 1; - - try - SetLength(DArr, DataByteLen + SizeOf(Cardinal)); - Move(Data^, DArr[0], DataByteLen); - - IsInt := DerivedKeyByteLength mod SizeOf(TCnSM3Digest) = 0; - CeilLen := (DerivedKeyByteLength + SizeOf(TCnSM3Digest) - 1) div SizeOf(TCnSM3Digest); - - SetLength(Result, DerivedKeyByteLength); - for I := 1 to CeilLen do - begin - SCT := UInt32HostToNetwork(CT); // Ȼĵû˵Ҫһ - Move(SCT, DArr[DataByteLen], SizeOf(Cardinal)); - SM3D := SM3(@DArr[0], Length(DArr)); - - if (I = CeilLen) and not IsInt then - begin - // һ 32 ʱֻƶһ - Move(SM3D[0], Result[(I - 1) * SizeOf(TCnSM3Digest)], (DerivedKeyByteLength mod SizeOf(TCnSM3Digest))); - end - else - Move(SM3D[0], Result[(I - 1) * SizeOf(TCnSM3Digest)], SizeOf(TCnSM3Digest)); - - Inc(CT); - end; - finally - SetLength(DArr, 0); - end; -end; - -function CnHKDF(HKDF: TCnHKDFHash; IKM: Pointer; IKMByteLen: Integer; - Salt: Pointer; SaltByteLen: Integer; Info: Pointer; InfoByteLen: Integer; - DerivedKeyByteLength: Integer): TBytes; -const - MAX_BYTE = 255; -var - PRKMd5, Md5T: TCnMD5Digest; - PRKSha1, Sha1T: TCnSHA1Digest; - PRKSha256, Sha256T: TCnSHA256Digest; - PRKSha3256, Sha3256T: TCnSHA3_256Digest; - PRKSm3, Sm3T: TCnSM3Digest; - T0, T: TBytes; - N, I, Start, HashLen: Integer; -begin - if IKM = nil then - IKMByteLen := 0; - - if Salt = nil then - SaltByteLen := 0; - - if Info = nil then - InfoByteLen := 0; - - if (IKMByteLen < 0) or (SaltByteLen < 0) or (InfoByteLen < 0) then - raise ECnKDFException.Create(SCnErrorKDFParam); - - // Extract HMac(Salt, IKM)ע IKM ݣ HMac Key - case HKDF of - chkMd5: - begin - if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnMD5Digest)) then - raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); - - HashLen := SizeOf(TCnMD5Digest); - if (Salt = nil) or (SaltByteLen <= 0) then - begin - FillChar(PRKMd5[0], HashLen, 0); - MD5Hmac(@PRKMd5[0], HashLen, IKM, IKMByteLen, PRKMd5); - end - else - MD5Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKMd5); - end; - chkSha1: - begin - if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnSHA1Digest)) then - raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); - - HashLen := SizeOf(TCnSHA1Digest); - if (Salt = nil) or (SaltByteLen <= 0) then - begin - FillChar(PRKSha1[0], HashLen, 0); - SHA1Hmac(@PRKSha1[0], HashLen, IKM, IKMByteLen, PRKSha1); - end - else - SHA1Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKSha1); - end; - chkSha256: - begin - if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnSHA256Digest)) then - raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); - - HashLen := SizeOf(TCnSHA256Digest); - if (Salt = nil) or (SaltByteLen <= 0) then - begin - FillChar(PRKSha256[0], HashLen, 0); - SHA256Hmac(@PRKSha256[0], HashLen, IKM, IKMByteLen, PRKSha256); - end - else - SHA256Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKSha256); - end; - chkSha3_256: - begin - if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnSHA3_256Digest)) then - raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); - - HashLen := SizeOf(TCnSHA3_256Digest); - if (Salt = nil) or (SaltByteLen <= 0) then - begin - FillChar(PRKSha3256[0], HashLen, 0); - SHA3_256Hmac(@PRKSha3256[0], HashLen, IKM, IKMByteLen, PRKSha3256); - end - else - SHA3_256Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKSha3256); - end; - chkSm3: - begin - if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnSM3Digest)) then - raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); - - HashLen := SizeOf(TCnSM3Digest); - if (Salt = nil) or (SaltByteLen <= 0) then - begin - FillChar(PRKSm3[0], HashLen, 0); - SM3Hmac(@PRKSm3[0], HashLen, IKM, IKMByteLen, PRKSm3); - end - else - SM3Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKSm3); - end; - else - raise ECnKDFException.Create(SCnErrorKDFHashNOTSupport); - end; - - // ʼ Expand - SetLength(T0, InfoByteLen + 1); - if InfoByteLen > 0 then - Move(Info^, T0[0], InfoByteLen); - T0[InfoByteLen] := 1; // ƴװ T0 - - // ʼÿֵļ - SetLength(T, HashLen + InfoByteLen + 1); - - // ýȲ - N := (DerivedKeyByteLength + HashLen - 1) div HashLen; - SetLength(Result, DerivedKeyByteLength); - - // T0 һ T1 - case HKDF of - chkMd5: MD5Hmac(@PRKMd5[0], HashLen, @T0[0], Length(T0), Md5T); - chkSha1: SHA1Hmac(@PRKSha1[0], HashLen, @T0[0], Length(T0), Sha1T); - chkSha256: SHA256Hmac(@PRKSha256[0], HashLen, @T0[0], Length(T0), Sha256T); - chkSha3_256: SHA3_256Hmac(@PRKSha3256[0], HashLen, @T0[0], Length(T0), Sha3256T); - chkSm3: SM3Hmac(@PRKSm3[0], HashLen, @T0[0], Length(T0), Sm3T); - end; - - Start := 0; - for I := 1 to N do - begin - // T1 ƴڽ - if DerivedKeyByteLength > HashLen then - begin - case HKDF of - chkMd5: Move(Md5T[0], Result[Start], HashLen); - chkSha1: Move(Sha1T[0], Result[Start], HashLen); - chkSha256: Move(Sha256T[0], Result[Start], HashLen); - chkSha3_256: Move(Sha3256T[0], Result[Start], HashLen); - chkSm3: Move(Sm3T[0], Result[Start], HashLen); - end; - Inc(Start, HashLen); - Dec(DerivedKeyByteLength, HashLen); - end - else - begin - case HKDF of - chkMd5: Move(Md5T[0], Result[Start], DerivedKeyByteLength); - chkSha1: Move(Sha1T[0], Result[Start], DerivedKeyByteLength); - chkSha256: Move(Sha256T[0], Result[Start], DerivedKeyByteLength); - chkSha3_256: Move(Sha3256T[0], Result[Start], DerivedKeyByteLength); - chkSm3: Move(Sm3T[0], Result[Start], DerivedKeyByteLength); - end; - Break; - end; - - // T1 Info ƴһ𲢼һ - case HKDF of - chkMd5: Move(Md5T[0], T[0], HashLen); - chkSha1: Move(Sha1T[0], T[0], HashLen); - chkSha256: Move(Sha256T[0], T[0], HashLen); - chkSha3_256: Move(Sha3256T[0], T[0], HashLen); - chkSm3: Move(Sm3T[0], T[0], HashLen); - end; - Move(Info^, T[HashLen], InfoByteLen); - T[HashLen + InfoByteLen] := I + 1; - - // Ӵ T2 T1 - case HKDF of - chkMd5: MD5Hmac(@PRKMd5[0], HashLen, @T[0], Length(T), Md5T); - chkSha1: SHA1Hmac(@PRKSha1[0], HashLen, @T[0], Length(T), Sha1T); - chkSha256: SHA256Hmac(@PRKSha256[0], HashLen, @T[0], Length(T), Sha256T); - chkSha3_256: SHA3_256Hmac(@PRKSha3256[0], HashLen, @T[0], Length(T), Sha3256T); - chkSm3: SM3Hmac(@PRKSm3[0], HashLen, @T[0], Length(T), Sm3T); - end; - end; -end; - -function CnHKDFBytes(HKDF: TCnHKDFHash; IKM: TBytes; Salt: TBytes; Info: TBytes; - DerivedKeyByteLength: Integer): TBytes; -var - IKMP, SaltP, InfoP: Pointer; - IKML, SaltL, InfoL: Integer; -begin - IKMP := nil; - SaltP := nil; - InfoP := nil; - IKML := 0; - SaltL := 0; - InfoL := 0; - - if Length(IKM) > 0 then - begin - IKMP := @IKM[0]; - IKML := Length(IKM); - end; - if Length(Salt) > 0 then - begin - SaltP := @Salt[0]; - SaltL := Length(Salt); - end; - if Length(Info) > 0 then - begin - InfoP := @Info[0]; - InfoL := Length(Info); - end; - - Result := CnHKDF(HKDF, IKMP, IKML, SaltP, SaltL, InfoP, InfoL, DerivedKeyByteLength); -end; - -end. +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnKDF; +{* |
+================================================================================
+* ƣ
+* ԪƣԿ㷨KDFԪ
+* ԪߣCnPack  (master@cnpack.org)
+*     עԪʵ˻ RFC2898  PBKDF1  PBKDF2 Կ㷨 PBKDF1 ֧ MD2 㷨
+*           ͬʱҲʵ˻ RFC5869  HKDF HMac Կ㷨
+*            SM2/SM9 㷨й涨㷨
+* ƽ̨WinXP + Delphi 5.0
+* ݲԣδ
+*   õԪ豾ػ
+* ޸ļ¼2025.01.09 V1.5
+*                HKDF ʵֺ
+*           2022.06.21 V1.4
+*               ϲһֽ CnSM2SM9KDF  AnsiString ڸ߰汾 Delphi ¿
+*           2022.04.26 V1.3
+*               ޸ LongWord  Integer ַת֧ MacOS64
+*           2022.01.02 V1.2
+*                CnPBKDF2 һԼ Unicode µļ
+*           2021.11.25 V1.1
+*                CnSM2KDF  Unicode µļ
+*           2020.03.30 V1.0
+*               Ԫ CnPemUtils ж
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes, CnNative, CnMD5, CnSHA1, CnSHA2, CnSHA3, CnSM3; + +type + TCnKeyDeriveHash = (ckdMd5, ckdSha256, ckdSha1); + {* CnGetDeriveKey ʹõӴշ} + + TCnPBKDF1KeyHash = (cpdfMd2, cpdfMd5, cpdfSha1); + {* PBKDF1 涨Ӵշ MD2 Dz֧} + + TCnPBKDF2KeyHash = (cpdfSha1Hmac, cpdfSha256Hmac); + {* PBKDF2 涨Ӵշ} + + TCnHKDFHash = (chkMd5, chkSha1, chkSha256, chkSha3_256, chkSm3); + {* HKDFHMAC-based Key Derivation Functionֵ֧Ӵ} + + ECnKDFException = class(Exception); + {* KDF 쳣} + +function CnGetDeriveKey(const Password: AnsiString; const Salt: AnsiString; + OutKey: PAnsiChar; KeyLength: Cardinal; KeyHash: TCnKeyDeriveHash = ckdMd5): Boolean; +{* Openssl е BytesToKeyָӴ㷨ɼ Key + Ŀǰ KeyLength ֧ HashҲ MD5 32 ֽڣSHA256 64 ֽڡ + + + const Password: AnsiString - + const Salt: AnsiString - ֵ + OutKey: PAnsiChar - Կݿַ + KeyLength: Cardinal - Կݿֽڳ + KeyHash: TCnKeyDeriveHash - Ӵ㷨 + + ֵBoolean - Ƿɳɹ +} + +function CnPBKDF1(const Password: AnsiString; const Salt: AnsiString; Count: Integer; + DerivedKeyByteLength: Integer; KeyHash: TCnPBKDF1KeyHash = cpdfMd5): AnsiString; +{* Password Based KDF 1 ʵ֣򵥵Ĺ̶Ӵյֻ֧ MD5 SHA1뷵ֵΪ AnsiString + DerivedKeyByteLength Կֽȹ̶ + + + const Password: AnsiString - + const Salt: AnsiString - ֵ + Count: Integer - + DerivedKeyByteLength: Integer - ɵԿֽڳ + KeyHash: TCnPBKDF1KeyHash - Ӵ㷨 + + ֵAnsiString - ɵԿ +} + +function CnPBKDF2(const Password: AnsiString; const Salt: AnsiString; Count: Integer; + DerivedKeyByteLength: Integer; KeyHash: TCnPBKDF2KeyHash = cpdfSha1Hmac): AnsiString; +{* Password Based KDF 2 ʵ֣ HMAC-SHA1 HMAC-SHA256뷵ֵΪ AnsiString + DerivedKeyByteLength Կֽȿɱ䣬 + + + const Password: AnsiString - + const Salt: AnsiString - ֵ + Count: Integer - + DerivedKeyByteLength: Integer - ɵԿֽڳ + KeyHash: TCnPBKDF2KeyHash - Ӵ㷨 + + ֵAnsiString - ɵԿ +} + +function CnPBKDF1Bytes(const Password: TBytes; const Salt: TBytes; Count: Integer; + DerivedKeyByteLength: Integer; KeyHash: TCnPBKDF1KeyHash = cpdfMd5): TBytes; +{* Password Based KDF 1 ʵ֣򵥵Ĺ̶Ӵյֻ֧ MD5 SHA1뷵ֵΪֽ顣 + DerivedKeyByteLength Կֽȹ̶ + + + const Password: TBytes - + const Salt: TBytes - ֵ + Count: Integer - + DerivedKeyByteLength: Integer - ɵԿֽڳ + KeyHash: TCnPBKDF1KeyHash - Ӵ㷨 + + ֵTBytes - ɵԿ +} + +function CnPBKDF2Bytes(const Password: TBytes; const Salt: TBytes; Count: Integer; + DerivedKeyByteLength: Integer; KeyHash: TCnPBKDF2KeyHash = cpdfSha1Hmac): TBytes; +{* Password Based KDF 2 ʵ֣ HMAC-SHA1 HMAC-SHA256뷵ֵΪֽ顣 + DerivedKeyByteLength Կֽȿɱ䣬 + + + const Password: TBytes - + const Salt: TBytes - ֵ + Count: Integer - + DerivedKeyByteLength: Integer - ɵԿֽڳ + KeyHash: TCnPBKDF2KeyHash - Ӵ㷨 + + ֵTBytes - ɵԿ +} + +// ============ SM2/SM9 й涨ͬһԿַװʵ =============== + +function CnSM2KDF(const Data: AnsiString; DerivedKeyByteLength: Integer): AnsiString; +{* SM2 Բ߹Կ㷨й涨ԿDerivedKeyLength Կֽ + AnsiStringͬʱƺҲû SharedInfo ANSI-X9.63-KDF + + + const Data: AnsiString - Կԭʼݣ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵAnsiString - ɵԿ +} + +function CnSM9KDF(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): AnsiString; +{* SM9 ʶ㷨й涨ԿDerivedKeyLength Կֽ + AnsiStringͬʱƺҲû SharedInfo ANSI-X9.63-KDF + + + Data: Pointer - Կԭʼݿַ + DataByteLen: Integer - Կԭʼݵֽڳ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵAnsiString - ɵԿ +} + +function CnSM2KDFBytes(const Data: TBytes; DerivedKeyByteLength: Integer): TBytes; +{* Ϊֽʽ SM2 Բ߹Կ㷨й涨Կ + DerivedKeyLength Կֽɵֽ顣 + + + const Data: TBytes - Կԭʼݵֽ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +function CnSM9KDFBytes(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): TBytes; +{* Ϊڴʽ SM9 ʶ㷨й涨Կ + DerivedKeyLength Կֽɵֽ顣 + + + Data: Pointer - Կԭʼݿַ + DataByteLen: Integer - Կԭʼݵֽڳ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +function CnSM2SM9KDF(Data: TBytes; DerivedKeyByteLength: Integer): TBytes; overload; +{* Ϊֽʽ SM2 Բ߹Կ㷨 SM9 ʶ㷨й涨Կ + DerivedKeyLength ԿֽɵԿֽ顣 + + + Data: TBytes - Կԭʼݵֽ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +function CnSM2SM9KDF(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): TBytes; overload; +{* Ϊڴʽ SM2 Բ߹Կ㷨 SM9 ʶ㷨й涨Կ + DerivedKeyLength ԿֽԿֽ顣 + + + Data: Pointer - Կԭʼݿַ + DataByteLen: Integer - Կԭʼݵֽڳ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +function CnHKDF(HKDF: TCnHKDFHash; IKM: Pointer; IKMByteLen: Integer; + Salt: Pointer; SaltByteLen: Integer; Info: Pointer; InfoByteLen: Integer; + DerivedKeyByteLength: Integer): TBytes; overload; +{* HMAC KDF Կ IKMSalt InfoָȵԿ + Salt Ϊգڲʹù̶Ӵսȵȫ 0Info ΪաɵԿ + + + HKDF: TCnHKDFHash - Ӵ㷨 + IKM: Pointer - ԿݣInput Keying Materialַ + IKMByteLen: Integer - Կݵֽڳ + Salt: Pointer - Կֵݿַ + SaltByteLen: Integer - Կֵݵֽڳ + Info: Pointer - ԿĿѡϢݿַ + InfoByteLen: Integer - ԿĿѡϢݵֽڳ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +function CnHKDFBytes(HKDF: TCnHKDFHash; IKM: TBytes; Salt: TBytes; Info: TBytes; + DerivedKeyByteLength: Integer): TBytes; overload; +{* HMAC KDF Կ IKMSalt Info ֽ飬ָȵԿ + Salt Ϊգڲʹù̶Ӵսȵȫ 0Info ΪաɵԿ + + HKDF: TCnHKDFHash - Ӵ㷨 + IKM: TBytes - Կ + Salt: TBytes - Կֵ + Info: TBytes - ԿĿѡϢ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +implementation + +resourcestring + SCnErrorKDFKeyTooLong = 'Derived Key Too Long.'; + SCnErrorKDFParam = 'Invalid Parameters.'; + SCnErrorKDFHashNOTSupport = 'Hash Method NOT Support.'; + +function Min(A, B: Integer): Integer; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + if A < B then + Result := A + else + Result := B; +end; + +function CnGetDeriveKey(const Password, Salt: AnsiString; OutKey: PAnsiChar; KeyLength: Cardinal; + KeyHash: TCnKeyDeriveHash): Boolean; +var + Md5Dig, Md5Dig2: TCnMD5Digest; + Sha256Dig, Sha256Dig2: TCnSHA256Digest; + SaltBuf, PS, PSMD5, PSSHA256: AnsiString; +begin + Result := False; + + if (Password = '') or (OutKey = nil) or (KeyLength < 8) then + Exit; + + SetLength(SaltBuf, 8); + FillChar(SaltBuf[1], Length(SaltBuf), 0); + if Salt <> '' then + Move(Salt[1], SaltBuf[1], Min(Length(Salt), 8)); + + if not (KeyHash in [ckdMd5, ckdSha256]) then + raise ECnKDFException.Create(SCnErrorKDFHashNOTSupport); + + PS := AnsiString(Password) + SaltBuf; // 涨ǰ 8 ֽΪ Salt + if KeyHash = ckdMd5 then + begin + SetLength(PSMD5, SizeOf(TCnMD5Digest) + Length(PS)); + Move(PS[1], PSMD5[SizeOf(TCnMD5Digest) + 1], Length(PS)); + Md5Dig := MD5StringA(PS); + // Salt ƴ MD5 16 ByteΪһ + + Move(Md5Dig[0], OutKey^, Min(KeyLength, SizeOf(TCnMD5Digest))); + if KeyLength <= SizeOf(TCnMD5Digest) then + begin + Result := True; + Exit; + end; + + KeyLength := KeyLength - SizeOf(TCnMD5Digest); + OutKey := PAnsiChar(TCnNativeUInt(OutKey) + SizeOf(TCnMD5Digest)); + + Move(Md5Dig[0], PSMD5[1], SizeOf(TCnMD5Digest)); + Md5Dig2 := MD5StringA(PSMD5); + Move(Md5Dig2[0], OutKey^, Min(KeyLength, SizeOf(TCnMD5Digest))); + if KeyLength <= SizeOf(TCnMD5Digest) then + Result := True; + + // KeyLength ̫㲻 + end + else if KeyHash = ckdSha256 then + begin + SetLength(PSSHA256, SizeOf(TCnSHA256Digest) + Length(PS)); + Move(PS[1], PSSHA256[SizeOf(TCnSHA256Digest) + 1], Length(PS)); + Sha256Dig := SHA256StringA(PS); + // Salt ƴ SHA256 32 ByteΪһ + + Move(Sha256Dig[0], OutKey^, Min(KeyLength, SizeOf(TCnSHA256Digest))); + if KeyLength <= SizeOf(TCnSHA256Digest) then + begin + Result := True; + Exit; + end; + + KeyLength := KeyLength - SizeOf(TCnSHA256Digest); + OutKey := PAnsiChar(TCnNativeUInt(OutKey) + SizeOf(TCnSHA256Digest)); + + Move(Sha256Dig[0], PSSHA256[1], SizeOf(TCnSHA256Digest)); + Sha256Dig2 := SHA256StringA(PSSHA256); + Move(Sha256Dig2[0], OutKey^, Min(KeyLength, SizeOf(TCnSHA256Digest))); + if KeyLength <= SizeOf(TCnSHA256Digest) then + Result := True; + + // KeyLength ̫㲻 + end; +end; + +(* + T_1 = Hash (P || S) , + T_2 = Hash (T_1) , + ... + T_c = Hash (T_{c-1}) , + DK = Tc<0..dkLen-1> +*) +function CnPBKDF1(const Password, Salt: AnsiString; Count, DerivedKeyByteLength: Integer; + KeyHash: TCnPBKDF1KeyHash): AnsiString; +var + P, S, Res: TBytes; +begin + P := AnsiToBytes(Password); + S := AnsiToBytes(Salt); + Res := CnPBKDF1Bytes(P, S, Count, DerivedKeyByteLength, KeyHash); + Result := BytesToAnsi(Res); +end; + +{ + DK = T1 + T2 + ... + Tdklen/hlen + Ti = F(Password, Salt, c, i) + + F(Password, Salt, c, i) = U1 ^ U2 ^ ... ^ Uc + + U1 = PRF(Password, Salt + INT_32_BE(i)) + U2 = PRF(Password, U1) + ... + Uc = PRF(Password, Uc-1) +} +function CnPBKDF2(const Password, Salt: AnsiString; Count, DerivedKeyByteLength: Integer; + KeyHash: TCnPBKDF2KeyHash): AnsiString; +var + P, S, Res: TBytes; +begin + P := AnsiToBytes(Password); + S := AnsiToBytes(Salt); + Res := CnPBKDF2Bytes(P, S, Count, DerivedKeyByteLength, KeyHash); + Result := BytesToAnsi(Res); +end; + +function CnPBKDF1Bytes(const Password, Salt: TBytes; Count, DerivedKeyByteLength: Integer; + KeyHash: TCnPBKDF1KeyHash = cpdfMd5): TBytes; +var + I: Integer; + Md5Dig, TM: TCnMD5Digest; + Sha1Dig, TS: TCnSHA1Digest; +begin + Result := nil; + if (Password = nil) or (Count <= 0) or (DerivedKeyByteLength <= 0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + case KeyHash of + cpdfMd5: + begin + if DerivedKeyByteLength > SizeOf(TCnMD5Digest) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + SetLength(Result, DerivedKeyByteLength); + Md5Dig := MD5Bytes(ConcatBytes(Password, Salt)); // Got T1 + if Count > 1 then + begin + for I := 2 to Count do + begin + TM := Md5Dig; + Md5Dig := MD5Buffer(TM[0], SizeOf(TCnMD5Digest)); // Got T_c + end; + end; + + Move(Md5Dig[0], Result[0], DerivedKeyByteLength); + end; + cpdfSha1: + begin + if DerivedKeyByteLength > SizeOf(TCnSHA1Digest) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + SetLength(Result, DerivedKeyByteLength); + Sha1Dig := SHA1Bytes(ConcatBytes(Password, Salt)); // Got T1 + if Count > 1 then + begin + for I := 2 to Count do + begin + TS := Sha1Dig; + Sha1Dig := SHA1Buffer(TS[0], SizeOf(TCnSHA1Digest)); // Got T_c + end; + end; + + Move(Sha1Dig[0], Result[0], DerivedKeyByteLength); + end; + else + raise ECnKDFException.Create(SCnErrorKDFHashNOTSupport); + end; +end; + +function CnPBKDF2Bytes(const Password, Salt: TBytes; Count, DerivedKeyByteLength: Integer; + KeyHash: TCnPBKDF2KeyHash = cpdfSha1Hmac): TBytes; +var + HLen, D, I, J, K: Integer; + Sha1Dig1, Sha1Dig, T1: TCnSHA1Digest; + Sha256Dig1, Sha256Dig, T256: TCnSHA256Digest; + S, S1, S256, Pad: TBytes; + PAddr: Pointer; +begin + Result := nil; + if (Salt = nil) or (Count <= 0) or (DerivedKeyByteLength <=0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + if (Password = nil) or (Length(Password) = 0) then + PAddr := nil + else + PAddr := @Password[0]; + + case KeyHash of + cpdfSha1Hmac: + HLen := 20; + cpdfSha256Hmac: + HLen := 32; + else + raise ECnKDFException.Create(SCnErrorKDFParam); + end; + + D := (DerivedKeyByteLength div HLen) + 1; + SetLength(S1, SizeOf(TCnSHA1Digest)); + SetLength(S256, SizeOf(TCnSHA256Digest)); + + SetLength(Pad, 4); + if KeyHash = cpdfSha1Hmac then + begin + for I := 1 to D do + begin + Pad[0] := I shr 24; + Pad[1] := I shr 16; + Pad[2] := I shr 8; + Pad[3] := I; + S := ConcatBytes(Salt, Pad); + + SHA1Hmac(PAddr, Length(Password), PAnsiChar(@S[0]), Length(S), Sha1Dig1); + T1 := Sha1Dig1; + + for J := 2 to Count do + begin + SHA1Hmac(PAddr, Length(Password), PAnsiChar(@T1[0]), SizeOf(TCnSHA1Digest), Sha1Dig); + T1 := Sha1Dig; + for K := Low(TCnSHA1Digest) to High(TCnSHA1Digest) do + Sha1Dig1[K] := Sha1Dig1[K] xor T1[K]; + end; + + Move(Sha1Dig1[0], S1[0], Length(S1)); + Result := ConcatBytes(Result, S1); + end; + Result := Copy(Result, 0, DerivedKeyByteLength); + end + else if KeyHash = cpdfSha256Hmac then + begin + for I := 1 to D do + begin + Pad[0] := I shr 24; + Pad[1] := I shr 16; + Pad[2] := I shr 8; + Pad[3] := I; + S := ConcatBytes(Salt, Pad); + + SHA256Hmac(PAddr, Length(Password), PAnsiChar(@S[0]), Length(S), Sha256Dig1); + T256 := Sha256Dig1; + + for J := 2 to Count do + begin + SHA256Hmac(PAddr, Length(Password), PAnsiChar(@T256[0]), SizeOf(TCnSHA256Digest), Sha256Dig); + T256 := Sha256Dig; + for K := Low(TCnSHA256Digest) to High(TCnSHA256Digest) do + Sha256Dig1[K] := Sha256Dig1[K] xor T256[K]; + end; + + Move(Sha256Dig1[0], S256[0], SizeOf(TCnSHA256Digest)); + Result := ConcatBytes(Result, S256); + end; + Result := Copy(Result, 0, DerivedKeyByteLength); + end; +end; + +function CnSM2KDF(const Data: AnsiString; DerivedKeyByteLength: Integer): AnsiString; +var + Res: TBytes; +begin + if (Data = '') or (DerivedKeyByteLength <= 0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + Res := CnSM2SM9KDF(@Data[1], Length(Data), DerivedKeyByteLength); + Result := BytesToAnsi(Res); +end; + +function CnSM9KDF(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): AnsiString; +var + Res: TBytes; +begin + Res := CnSM2SM9KDF(Data, DataByteLen, DerivedKeyByteLength); + Result := BytesToAnsi(Res); +end; + +function CnSM2KDFBytes(const Data: TBytes; DerivedKeyByteLength: Integer): TBytes; +begin + Result := CnSM2SM9KDF(Data, DerivedKeyByteLength); +end; + +function CnSM9KDFBytes(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): TBytes; +begin + Result := CnSM2SM9KDF(Data, DataByteLen, DerivedKeyByteLength); +end; + +function CnSM2SM9KDF(Data: TBytes; DerivedKeyByteLength: Integer): TBytes; +begin + if (Data = nil) or (Length(Data) <= 0) or (DerivedKeyByteLength <= 0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + Result := CnSM2SM9KDF(@Data[0], Length(Data), DerivedKeyByteLength); +end; + +function CnSM2SM9KDF(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): TBytes; overload; +var + DArr: TBytes; + CT, SCT: Cardinal; + I, CeilLen: Integer; + IsInt: Boolean; + SM3D: TCnSM3Digest; +begin + Result := nil; + if (Data = nil) or (DataByteLen <= 0) or (DerivedKeyByteLength <= 0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + DArr := nil; + CT := 1; + + try + SetLength(DArr, DataByteLen + SizeOf(Cardinal)); + Move(Data^, DArr[0], DataByteLen); + + IsInt := DerivedKeyByteLength mod SizeOf(TCnSM3Digest) = 0; + CeilLen := (DerivedKeyByteLength + SizeOf(TCnSM3Digest) - 1) div SizeOf(TCnSM3Digest); + + SetLength(Result, DerivedKeyByteLength); + for I := 1 to CeilLen do + begin + SCT := UInt32HostToNetwork(CT); // Ȼĵû˵Ҫһ + Move(SCT, DArr[DataByteLen], SizeOf(Cardinal)); + SM3D := SM3(@DArr[0], Length(DArr)); + + if (I = CeilLen) and not IsInt then + begin + // һ 32 ʱֻƶһ + Move(SM3D[0], Result[(I - 1) * SizeOf(TCnSM3Digest)], (DerivedKeyByteLength mod SizeOf(TCnSM3Digest))); + end + else + Move(SM3D[0], Result[(I - 1) * SizeOf(TCnSM3Digest)], SizeOf(TCnSM3Digest)); + + Inc(CT); + end; + finally + SetLength(DArr, 0); + end; +end; + +function CnHKDF(HKDF: TCnHKDFHash; IKM: Pointer; IKMByteLen: Integer; + Salt: Pointer; SaltByteLen: Integer; Info: Pointer; InfoByteLen: Integer; + DerivedKeyByteLength: Integer): TBytes; +const + MAX_BYTE = 255; +var + PRKMd5, Md5T: TCnMD5Digest; + PRKSha1, Sha1T: TCnSHA1Digest; + PRKSha256, Sha256T: TCnSHA256Digest; + PRKSha3256, Sha3256T: TCnSHA3_256Digest; + PRKSm3, Sm3T: TCnSM3Digest; + T0, T: TBytes; + N, I, Start, HashLen: Integer; +begin + if IKM = nil then + IKMByteLen := 0; + + if Salt = nil then + SaltByteLen := 0; + + if Info = nil then + InfoByteLen := 0; + + if (IKMByteLen < 0) or (SaltByteLen < 0) or (InfoByteLen < 0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + // Extract HMac(Salt, IKM)ע IKM ݣ HMac Key + case HKDF of + chkMd5: + begin + if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnMD5Digest)) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + HashLen := SizeOf(TCnMD5Digest); + if (Salt = nil) or (SaltByteLen <= 0) then + begin + FillChar(PRKMd5[0], HashLen, 0); + MD5Hmac(@PRKMd5[0], HashLen, IKM, IKMByteLen, PRKMd5); + end + else + MD5Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKMd5); + end; + chkSha1: + begin + if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnSHA1Digest)) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + HashLen := SizeOf(TCnSHA1Digest); + if (Salt = nil) or (SaltByteLen <= 0) then + begin + FillChar(PRKSha1[0], HashLen, 0); + SHA1Hmac(@PRKSha1[0], HashLen, IKM, IKMByteLen, PRKSha1); + end + else + SHA1Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKSha1); + end; + chkSha256: + begin + if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnSHA256Digest)) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + HashLen := SizeOf(TCnSHA256Digest); + if (Salt = nil) or (SaltByteLen <= 0) then + begin + FillChar(PRKSha256[0], HashLen, 0); + SHA256Hmac(@PRKSha256[0], HashLen, IKM, IKMByteLen, PRKSha256); + end + else + SHA256Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKSha256); + end; + chkSha3_256: + begin + if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnSHA3_256Digest)) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + HashLen := SizeOf(TCnSHA3_256Digest); + if (Salt = nil) or (SaltByteLen <= 0) then + begin + FillChar(PRKSha3256[0], HashLen, 0); + SHA3_256Hmac(@PRKSha3256[0], HashLen, IKM, IKMByteLen, PRKSha3256); + end + else + SHA3_256Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKSha3256); + end; + chkSm3: + begin + if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnSM3Digest)) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + HashLen := SizeOf(TCnSM3Digest); + if (Salt = nil) or (SaltByteLen <= 0) then + begin + FillChar(PRKSm3[0], HashLen, 0); + SM3Hmac(@PRKSm3[0], HashLen, IKM, IKMByteLen, PRKSm3); + end + else + SM3Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKSm3); + end; + else + raise ECnKDFException.Create(SCnErrorKDFHashNOTSupport); + end; + + // ʼ Expand + SetLength(T0, InfoByteLen + 1); + if InfoByteLen > 0 then + Move(Info^, T0[0], InfoByteLen); + T0[InfoByteLen] := 1; // ƴװ T0 + + // ʼÿֵļ + SetLength(T, HashLen + InfoByteLen + 1); + + // ýȲ + N := (DerivedKeyByteLength + HashLen - 1) div HashLen; + SetLength(Result, DerivedKeyByteLength); + + // T0 һ T1 + case HKDF of + chkMd5: MD5Hmac(@PRKMd5[0], HashLen, @T0[0], Length(T0), Md5T); + chkSha1: SHA1Hmac(@PRKSha1[0], HashLen, @T0[0], Length(T0), Sha1T); + chkSha256: SHA256Hmac(@PRKSha256[0], HashLen, @T0[0], Length(T0), Sha256T); + chkSha3_256: SHA3_256Hmac(@PRKSha3256[0], HashLen, @T0[0], Length(T0), Sha3256T); + chkSm3: SM3Hmac(@PRKSm3[0], HashLen, @T0[0], Length(T0), Sm3T); + end; + + Start := 0; + for I := 1 to N do + begin + // T1 ƴڽ + if DerivedKeyByteLength > HashLen then + begin + case HKDF of + chkMd5: Move(Md5T[0], Result[Start], HashLen); + chkSha1: Move(Sha1T[0], Result[Start], HashLen); + chkSha256: Move(Sha256T[0], Result[Start], HashLen); + chkSha3_256: Move(Sha3256T[0], Result[Start], HashLen); + chkSm3: Move(Sm3T[0], Result[Start], HashLen); + end; + Inc(Start, HashLen); + Dec(DerivedKeyByteLength, HashLen); + end + else + begin + case HKDF of + chkMd5: Move(Md5T[0], Result[Start], DerivedKeyByteLength); + chkSha1: Move(Sha1T[0], Result[Start], DerivedKeyByteLength); + chkSha256: Move(Sha256T[0], Result[Start], DerivedKeyByteLength); + chkSha3_256: Move(Sha3256T[0], Result[Start], DerivedKeyByteLength); + chkSm3: Move(Sm3T[0], Result[Start], DerivedKeyByteLength); + end; + Break; + end; + + // T1 Info ƴһ𲢼һ + case HKDF of + chkMd5: Move(Md5T[0], T[0], HashLen); + chkSha1: Move(Sha1T[0], T[0], HashLen); + chkSha256: Move(Sha256T[0], T[0], HashLen); + chkSha3_256: Move(Sha3256T[0], T[0], HashLen); + chkSm3: Move(Sm3T[0], T[0], HashLen); + end; + Move(Info^, T[HashLen], InfoByteLen); + T[HashLen + InfoByteLen] := I + 1; + + // Ӵ T2 T1 + case HKDF of + chkMd5: MD5Hmac(@PRKMd5[0], HashLen, @T[0], Length(T), Md5T); + chkSha1: SHA1Hmac(@PRKSha1[0], HashLen, @T[0], Length(T), Sha1T); + chkSha256: SHA256Hmac(@PRKSha256[0], HashLen, @T[0], Length(T), Sha256T); + chkSha3_256: SHA3_256Hmac(@PRKSha3256[0], HashLen, @T[0], Length(T), Sha3256T); + chkSm3: SM3Hmac(@PRKSm3[0], HashLen, @T[0], Length(T), Sm3T); + end; + end; +end; + +function CnHKDFBytes(HKDF: TCnHKDFHash; IKM: TBytes; Salt: TBytes; Info: TBytes; + DerivedKeyByteLength: Integer): TBytes; +var + IKMP, SaltP, InfoP: Pointer; + IKML, SaltL, InfoL: Integer; +begin + IKMP := nil; + SaltP := nil; + InfoP := nil; + IKML := 0; + SaltL := 0; + InfoL := 0; + + if Length(IKM) > 0 then + begin + IKMP := @IKM[0]; + IKML := Length(IKM); + end; + if Length(Salt) > 0 then + begin + SaltP := @Salt[0]; + SaltL := Length(Salt); + end; + if Length(Info) > 0 then + begin + InfoP := @Info[0]; + InfoL := Length(Info); + end; + + Result := CnHKDF(HKDF, IKMP, IKML, SaltP, SaltL, InfoP, InfoL, DerivedKeyByteLength); +end; + +end. diff --git a/CnPack/Crypto/CnMD5.pas b/CnPack/Crypto/CnMD5.pas index e859993..be31d9d 100644 --- a/CnPack/Crypto/CnMD5.pas +++ b/CnPack/Crypto/CnMD5.pas @@ -1,884 +1,908 @@ -{******************************************************************************} -{ CnPack For Delphi/C++Builder } -{ йԼĿԴ } -{ (C)Copyright 2001-2025 CnPack } -{ ------------------------------------ } -{ } -{ ǿԴ CnPack ķЭ } -{ ĺ·һ } -{ } -{ һĿϣãûκεû } -{ ʺضĿĶĵϸ CnPack Э顣 } -{ } -{ ӦѾͿһյһ CnPack Эĸ } -{ ûУɷǵվ } -{ } -{ վַhttps://www.cnpack.org } -{ ʼmaster@cnpack.org } -{ } -{******************************************************************************} - -{******************************************************************************} -{ } -{ MD5 Message-Digest for Delphi 4 } -{ } -{ Delphi 4 Unit implementing the } -{ RSA Data Security, Inc. MD5 Message-Digest Algorithm } -{ } -{ Implementation of Ronald L. Rivest's RFC 1321 } -{ } -{ Copyright ?1997-1999 Medienagentur Fichtner & Meyer } -{ Written by Matthias Fichtner } -{ } -{ -----------------------------------------------------------------------------} -{ See RFC 1321 for RSA Data Security's copyright and license notice! } -{ -----------------------------------------------------------------------------} -{ The latest release of md5.pas will always be available from } -{ the distribution site at: http://www.fichtner.net/delphi/md5/ } -{ -----------------------------------------------------------------------------} -{ Please send questions, bug reports and suggestions } -{ regarding this code to: mfichtner@fichtner-meyer.com } -{ -----------------------------------------------------------------------------} -{ This code is provided "as is" without express or } -{ implied warranty of any kind. Use it at your own risk. } -{******************************************************************************} - -unit CnMD5; -{* |
-================================================================================
-* ƣ
-* ԪƣMD5 Ӵ㷨ʵֵԪ
-* Ԫߣ壨QSoft hq.com@263.net; http://qsoft.51.net
-*            Ronald L. Rivest  MD5.pas дԭʼ
-*     עԪʵ MD5 Ӵ㷨Ӧ HMAC 㷨
-* ƽ̨PWin2000Pro + Delphi 5.0
-* ݲԣPWin9X/2000/XP + Delphi 5/6
-*   õԪеַϱػʽ
-* ޸ļ¼2019.12.12 V1.4
-*               ֧ TBytes
-*           2019.04.15 V1.3
-*               ֧ Win32/Win64/MacOS
-*           2014.11.14 V1.2
-*               л Pascal ֿ֧ƽ̨
-*           2003.09.18 V1.1
-*               òҵ˸õԪԭߵİȨ
-*           2003.09.18 V1.0
-*               Ԫ
-================================================================================
-|
} - -interface - -{$I CnPack.inc} - -uses - Classes, SysUtils, CnConsts, CnNative {$IFDEF MSWINDOWS}, Windows {$ENDIF}; - -type - PMD5Digest = ^TCnMD5Digest; - TCnMD5Digest = array[0..15] of Byte; - {* MD5 Ӵս16 ֽ} - - TCnMD5Count = array[0..1] of Cardinal; - TCnMD5State = array[0..3] of Cardinal; - TCnMD5Block = array[0..15] of Cardinal; - - TCnMD5Buffer = array[0..63] of Byte; - - TCnMD5Context = record - {* MD5 Ľṹ} - State : TCnMD5State; - Count : TCnMD5Count; - Buffer : TCnMD5Buffer; - Ipad : array[0..63] of Byte; {!< HMAC: inner padding } - Opad : array[0..63] of Byte; {!< HMAC: outer padding } - end; - - TCnMD5CalcProgressFunc = procedure (ATotal, AProgress: Int64; - var Cancel: Boolean) of object; - {* Ȼص¼} - -//---------------------------------------------------------------- -// û API -//---------------------------------------------------------------- - -function MD5(Input: PAnsiChar; ByteLength: Cardinal): TCnMD5Digest; -{* ݿ MD5 㡣 - - - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵTCnMD5Digest - ص MD5 Ӵֵ -} - -function MD5Buffer(const Buffer; Count: Cardinal): TCnMD5Digest; -{* ݿ MD5 㡣 - - - const Buffer - ݿַ - Count: Cardinal - ݿֽڳ - - ֵTCnMD5Digest - ص MD5 Ӵֵ -} - -function MD5Bytes(Data: TBytes): TCnMD5Digest; -{* ֽ MD5 㡣 - - - Data: TBytes - ֽ - - ֵTCnMD5Digest - ص MD5 Ӵֵ -} - -function MD5String(const Str: string): TCnMD5Digest; -{* String ݽ MD5 㡣ע D2009 ϰ汾 string Ϊ UnicodeString - лὫǿת AnsiString м㡣 - - - - const Str: string - ַ - - ֵTCnMD5Digest - ص MD5 Ӵֵ -} - -function MD5StringA(const Str: AnsiString): TCnMD5Digest; -{* AnsiString ݽ MD5 㣬ֱӼڲݣޱ봦 - - - const Str: AnsiString - ַ - - ֵTCnMD5Digest - ص MD5 Ӵֵ -} - -function MD5StringW(const Str: WideString): TCnMD5Digest; -{* WideString ַת MD5 㡣 - ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ - ƽֱ̨תΪ AnsiString ͣٽм㡣 - - - const Str: WideString - Ŀַ - - ֵTCnMD5Digest - ص MD5 Ӵֵ -} - -{$IFDEF UNICODE} - -function MD5UnicodeString(const Str: string): TCnMD5Digest; -{* UnicodeString ݽֱӵ MD5 㣬ֱӼڲ UTF16 ݣת - - - const Str: string - Ŀַ - - ֵTCnMD5Digest - ص MD5 Ӵֵ -} - -{$ELSE} - -function MD5UnicodeString(const Str: WideString ): TCnMD5Digest; -{* UnicodeString ݽֱӵ MD5 㣬ֱӼڲ UTF16 ݣת - - - - const Str: WideString - Ŀַ - - ֵTCnMD5Digest - ص MD5 Ӵֵ -} - -{$ENDIF} - -function MD5File(const FileName: string; - CallBack: TCnMD5CalcProgressFunc = nil): TCnMD5Digest; -{* ָļݽ MD5 㡣 - - - const FileName: string - ļ - CallBack: TCnMD5CalcProgressFunc - ȻصĬΪ - - ֵTCnMD5Digest - ص MD5 Ӵֵ -} - -function MD5Stream(Stream: TStream; - CallBack: TCnMD5CalcProgressFunc = nil): TCnMD5Digest; -{* ָݽ MD5 㡣 - - - Stream: TStream - - CallBack: TCnMD5CalcProgressFunc - ȻصĬΪ - - ֵTCnMD5Digest - ص MD5 Ӵֵ -} - -// ⲿݽɢ MD5 㣬MD5Update ɶα - -procedure MD5Init(var Context: TCnMD5Context); -{* ʼһ MD5 ģ׼ MD5 - - - var Context: TCnMD5Context - ʼ MD5 - - ֵޣ -} - -procedure MD5Update(var Context: TCnMD5Context; Input: PAnsiChar; ByteLength: Cardinal); -{* ԳʼĶһݽ MD5 㡣 - ɶε㲻ͬݿ飬轫ͬݿƴڴС - - - var Context: TCnMD5Context - MD5 - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵޣ -} - -procedure MD5Final(var Context: TCnMD5Context; var Digest: TCnMD5Digest); -{* ּ㣬 MD5 Digest С - - - var Context: TCnMD5Context - MD5 - var Digest: TCnMD5Digest - ص MD5 Ӵֵ - - ֵޣ -} - -function MD5Print(const Digest: TCnMD5Digest): string; -{* ʮƸʽ MD5 Ӵֵ - - - const Digest: TCnMD5Digest - ָ MD5 Ӵֵ - - ֵstring - ʮַ -} - -function MD5Match(const D1: TCnMD5Digest; const D2: TCnMD5Digest): Boolean; -{* Ƚ MD5 ӴֵǷȡ - - - const D1: TCnMD5Digest - Ƚϵ MD5 Ӵֵһ - const D2: TCnMD5Digest - Ƚϵ MD5 Ӵֵ - - ֵBoolean - Ƿ -} - -function MD5DigestToStr(const Digest: TCnMD5Digest): string; -{* MD5 Ӵֱֵת stringÿֽڶӦһַ - - - const Digest: TCnMD5Digest - ת MD5 Ӵֵ - - ֵstring - صַ -} - -procedure MD5Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnMD5Digest); -{* MD5 HMACHash-based Message Authentication Code㣬 - ͨݵļϼԿĸҲмΡ - - - Key: PAnsiChar - MD5 Կݿַ - KeyByteLength: Integer - MD5 Կݿֽڳ - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - var Output: TCnMD5Digest - ص MD5 Ӵֵ - - ֵޣ -} - -implementation - -const - MAX_FILE_SIZE = 512 * 1024 * 1024; - // If file size <= this size (bytes), using Mapping, else stream - - HMAC_MD5_BLOCK_SIZE_BYTE = 64; - HMAC_MD5_OUTPUT_LENGTH_BYTE = 16; - -type - TMD5CBits = array[0..7] of Byte; - -var - PADDING: TCnMD5Buffer = ( - $80, $00, $00, $00, $00, $00, $00, $00, - $00, $00, $00, $00, $00, $00, $00, $00, - $00, $00, $00, $00, $00, $00, $00, $00, - $00, $00, $00, $00, $00, $00, $00, $00, - $00, $00, $00, $00, $00, $00, $00, $00, - $00, $00, $00, $00, $00, $00, $00, $00, - $00, $00, $00, $00, $00, $00, $00, $00, - $00, $00, $00, $00, $00, $00, $00, $00 - ); - -function F(X, y, z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := (X and y) or ((not X) and z); -end; - -function G(X, y, z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := (X and z) or (y and (not z)); -end; - -function H(X, y, z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := X xor y xor z; -end; - -function I(X, y, z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := y xor (X or (not z)); -end; - -procedure ROT(var X: Cardinal; N: BYTE); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - X := (X shl N) or (X shr (32 - N)); -end; - -procedure FF(var A: Cardinal; B, C, D, X: Cardinal; S: BYTE; AC: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Inc(A, F(B, C, D) + X + AC); - ROT(A, S); - Inc(A, B); -end; - -procedure GG(var A: Cardinal; B, C, D, X: Cardinal; S: BYTE; AC: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Inc(A, G(B, C, D) + X + AC); - ROT(A, S); - Inc(A, B); -end; - -procedure HH(var A: Cardinal; B, C, D, X: Cardinal; S: BYTE; AC: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Inc(A, H(B, C, D) + X + AC); - ROT(A, S); - Inc(A, B); -end; - -procedure II(var A: Cardinal; B, C, D, X: Cardinal; S: BYTE; AC: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Inc(A, I(B, C, D) + X + AC); - ROT(A, S); - Inc(A, B); -end; - -// Encode Count bytes at Source into (Count / 4) DWORDs at Target -procedure Encode(Source, Target: Pointer; Count: Cardinal); -var - S: PByte; - T: PCardinal; - I: Cardinal; -begin - S := Source; - T := Target; - for I := 1 to Count div 4 do - begin - T^ := S^; - Inc(S); - T^ := T^ or (S^ shl 8); - Inc(S); - T^ := T^ or (S^ shl 16); - Inc(S); - T^ := T^ or (S^ shl 24); - Inc(S); - Inc(T); - end; -end; - -// Decode Count DWORDs at Source into (Count * 4) Bytes at Target -procedure Decode(Source, Target: Pointer; Count: Cardinal); -var - S: PCardinal; - T: PByte; - I: Cardinal; -begin - S := Source; - T := Target; - for I := 1 to Count do - begin - T^ := S^ and $ff; - Inc(T); - T^ := (S^ shr 8) and $ff; - Inc(T); - T^ := (S^ shr 16) and $ff; - Inc(T); - T^ := (S^ shr 24) and $ff; - Inc(T); - Inc(S); - end; -end; - -// Transform State according to first 64 bytes at Buffer -procedure Transform(Buffer: Pointer; var State: TCnMD5State); -var - A, B, C, D: Cardinal; - Block: TCnMD5Block; -begin - Encode(Buffer, @Block, 64); - A := State[0]; - B := State[1]; - C := State[2]; - D := State[3]; - FF (A, B, C, D, Block[ 0], 7, $d76aa478); - FF (D, A, B, C, Block[ 1], 12, $e8c7b756); - FF (C, D, A, B, Block[ 2], 17, $242070db); - FF (B, C, D, A, Block[ 3], 22, $c1bdceee); - FF (A, B, C, D, Block[ 4], 7, $f57c0faf); - FF (D, A, B, C, Block[ 5], 12, $4787c62a); - FF (C, D, A, B, Block[ 6], 17, $a8304613); - FF (B, C, D, A, Block[ 7], 22, $fd469501); - FF (A, B, C, D, Block[ 8], 7, $698098d8); - FF (D, A, B, C, Block[ 9], 12, $8b44f7af); - FF (C, D, A, B, Block[10], 17, $ffff5bb1); - FF (B, C, D, A, Block[11], 22, $895cd7be); - FF (A, B, C, D, Block[12], 7, $6b901122); - FF (D, A, B, C, Block[13], 12, $fd987193); - FF (C, D, A, B, Block[14], 17, $a679438e); - FF (B, C, D, A, Block[15], 22, $49b40821); - GG (A, B, C, D, Block[ 1], 5, $f61e2562); - GG (D, A, B, C, Block[ 6], 9, $c040b340); - GG (C, D, A, B, Block[11], 14, $265e5a51); - GG (B, C, D, A, Block[ 0], 20, $e9b6c7aa); - GG (A, B, C, D, Block[ 5], 5, $d62f105d); - GG (D, A, B, C, Block[10], 9, $2441453); - GG (C, D, A, B, Block[15], 14, $d8a1e681); - GG (B, C, D, A, Block[ 4], 20, $e7d3fbc8); - GG (A, B, C, D, Block[ 9], 5, $21e1cde6); - GG (D, A, B, C, Block[14], 9, $c33707d6); - GG (C, D, A, B, Block[ 3], 14, $f4d50d87); - GG (B, C, D, A, Block[ 8], 20, $455a14ed); - GG (A, B, C, D, Block[13], 5, $a9e3e905); - GG (D, A, B, C, Block[ 2], 9, $fcefa3f8); - GG (C, D, A, B, Block[ 7], 14, $676f02d9); - GG (B, C, D, A, Block[12], 20, $8d2a4c8a); - HH (A, B, C, D, Block[ 5], 4, $fffa3942); - HH (D, A, B, C, Block[ 8], 11, $8771f681); - HH (C, D, A, B, Block[11], 16, $6d9d6122); - HH (B, C, D, A, Block[14], 23, $fde5380c); - HH (A, B, C, D, Block[ 1], 4, $a4beea44); - HH (D, A, B, C, Block[ 4], 11, $4bdecfa9); - HH (C, D, A, B, Block[ 7], 16, $f6bb4b60); - HH (B, C, D, A, Block[10], 23, $bebfbc70); - HH (A, B, C, D, Block[13], 4, $289b7ec6); - HH (D, A, B, C, Block[ 0], 11, $eaa127fa); - HH (C, D, A, B, Block[ 3], 16, $d4ef3085); - HH (B, C, D, A, Block[ 6], 23, $4881d05); - HH (A, B, C, D, Block[ 9], 4, $d9d4d039); - HH (D, A, B, C, Block[12], 11, $e6db99e5); - HH (C, D, A, B, Block[15], 16, $1fa27cf8); - HH (B, C, D, A, Block[ 2], 23, $c4ac5665); - II (A, B, C, D, Block[ 0], 6, $f4292244); - II (D, A, B, C, Block[ 7], 10, $432aff97); - II (C, D, A, B, Block[14], 15, $ab9423a7); - II (B, C, D, A, Block[ 5], 21, $fc93a039); - II (A, B, C, D, Block[12], 6, $655b59c3); - II (D, A, B, C, Block[ 3], 10, $8f0ccc92); - II (C, D, A, B, Block[10], 15, $ffeff47d); - II (B, C, D, A, Block[ 1], 21, $85845dd1); - II (A, B, C, D, Block[ 8], 6, $6fa87e4f); - II (D, A, B, C, Block[15], 10, $fe2ce6e0); - II (C, D, A, B, Block[ 6], 15, $a3014314); - II (B, C, D, A, Block[13], 21, $4e0811a1); - II (A, B, C, D, Block[ 4], 6, $f7537e82); - II (D, A, B, C, Block[11], 10, $bd3af235); - II (C, D, A, B, Block[ 2], 15, $2ad7d2bb); - II (B, C, D, A, Block[ 9], 21, $eb86d391); - Inc(State[0], A); - Inc(State[1], B); - Inc(State[2], C); - Inc(State[3], D); -end; - -// Initialize given Context -procedure MD5Init(var Context: TCnMD5Context); -begin - with Context do - begin - State[0] := $67452301; - State[1] := $EFCDAB89; - State[2] := $98BADCFE; - State[3] := $10325476; - Count[0] := 0; - Count[1] := 0; - // ZeroMemory(@Buffer, SizeOf(TMD5Buffer)); - FillChar(Buffer, SizeOf(TCnMD5Buffer), 0); - end; -end; - -// Update given Context to include Length bytes of Input -procedure MD5Update(var Context: TCnMD5Context; Input: PAnsiChar; ByteLength: Cardinal); -var - Index: Cardinal; - PartLen: Cardinal; - I: Cardinal; -begin - with Context do - begin - Index := (Count[0] shr 3) and $3F; - Inc(Count[0], ByteLength shl 3); - if Count[0] < (ByteLength shl 3) then Inc(Count[1]); - Inc(Count[1], ByteLength shr 29); - end; - - PartLen := 64 - Index; - if ByteLength >= PartLen then - begin - Move(Input^, Context.Buffer[Index], PartLen); - Transform(@Context.Buffer, Context.State); - I := PartLen; - while I + 63 < ByteLength do - begin - Transform(@Input[I], Context.State); - Inc(I, 64); - end; - Index := 0; - end - else - I := 0; - - Move(Input[I], Context.Buffer[Index], ByteLength - I); -end; - -procedure MD5UpdateW(var Context: TCnMD5Context; Input: PWideChar; CharLength: Cardinal); -var -{$IFDEF MSWINDOWS} - pContent: PAnsiChar; - iLen: Cardinal; -{$ELSE} - S: string; // UnicodeString - A: AnsiString; -{$ENDIF} -begin -{$IFDEF MSWINDOWS} - GetMem(pContent, CharLength * SizeOf(WideChar)); - try - iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 - PAnsiChar(pContent), CharLength * SizeOf(WideChar), nil, nil); - MD5Update(Context, pContent, iLen); - finally - FreeMem(pContent); - end; -{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ - S := StrNew(Input); - A := AnsiString(S); - MD5Update(Context, @A[1], Length(A)); -{$ENDIF} -end; - -// Finalize given Context, create Digest -procedure MD5Final(var Context: TCnMD5Context; var Digest: TCnMD5Digest); -var - Bits: TMD5CBits; - Index: Cardinal; - PadLen: Cardinal; -begin - Decode(@Context.Count, @Bits, 2); - Index := (Context.Count[0] shr 3) and $3f; - if Index < 56 then - PadLen := 56 - Index - else - PadLen := 120 - Index; - MD5Update(Context, @PADDING, PadLen); - MD5Update(Context, @Bits, 8); - Decode(@Context.State, @Digest, 4); -end; - -function InternalMD5Stream(Stream: TStream; const BufSize: Cardinal; var D: - TCnMD5Digest; CallBack: TCnMD5CalcProgressFunc = nil): Boolean; -var - Context: TCnMD5Context; - Buf: PAnsiChar; - BufLen: Cardinal; - Size: Int64; - ReadBytes: Cardinal; - TotalBytes: Int64; - SavePos: Int64; - CancelCalc: Boolean; -begin - Result := False; - Size := Stream.Size; - if Size = 0 then - Exit; - - SavePos := Stream.Position; - TotalBytes := 0; - - if Size < BufSize then - BufLen := Size - else - BufLen := BufSize; - - CancelCalc := False; - MD5Init(Context); - GetMem(Buf, BufLen); - try - Stream.Position := 0; - repeat - ReadBytes := Stream.Read(Buf^, BufLen); - if ReadBytes <> 0 then - begin - Inc(TotalBytes, ReadBytes); - MD5Update(Context, Buf, ReadBytes); - if Assigned(CallBack) then - begin - CallBack(Size, TotalBytes, CancelCalc); - if CancelCalc then Exit; - end; - end; - until (ReadBytes = 0) or (TotalBytes = Size); - MD5Final(Context, D); - Result := True; - finally - FreeMem(Buf, BufLen); - Stream.Position := SavePos; - end; -end; - -// ݿ MD5 -function MD5(Input: PAnsiChar; ByteLength: Cardinal): TCnMD5Digest; -var - Context: TCnMD5Context; -begin - MD5Init(Context); - MD5Update(Context, Input, ByteLength); - MD5Final(Context, Result); -end; - -// ݿ MD5 -function MD5Buffer(const Buffer; Count: Cardinal): TCnMD5Digest; -var - Context: TCnMD5Context; -begin - MD5Init(Context); - MD5Update(Context, PAnsiChar(Buffer), Count); - MD5Final(Context, Result); -end; - -function MD5Bytes(Data: TBytes): TCnMD5Digest; -var - Context: TCnMD5Context; -begin - MD5Init(Context); - MD5Update(Context, PAnsiChar(@Data[0]), Length(Data)); - MD5Final(Context, Result); -end; - -// String ݽ MD5 -function MD5String(const Str: string): TCnMD5Digest; -var - AStr: AnsiString; -begin - AStr := AnsiString(Str); - Result := MD5StringA(AStr); -end; - -// AnsiString ݽ MD5 -function MD5StringA(const Str: AnsiString): TCnMD5Digest; -var - Context: TCnMD5Context; -begin - MD5Init(Context); - MD5Update(Context, PAnsiChar(Str), Length(Str)); - MD5Final(Context, Result); -end; - -// WideString ݽ MD5 -function MD5StringW(const Str: WideString): TCnMD5Digest; -var - Context: TCnMD5Context; -begin - MD5Init(Context); - MD5UpdateW(Context, PWideChar(Str), Length(Str)); - MD5Final(Context, Result); -end; - -// UnicodeString ݽֱӵ MD5 㣬ת -{$IFDEF UNICODE} -function MD5UnicodeString(const Str: string): TCnMD5Digest; -{$ELSE} -function MD5UnicodeString(const Str: WideString): TCnMD5Digest; -{$ENDIF} -var - Context: TCnMD5Context; -begin - MD5Init(Context); - MD5Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); - MD5Final(Context, Result); -end; - -// ָļݽ MD5 -function MD5File(const FileName: string; - CallBack: TCnMD5CalcProgressFunc): TCnMD5Digest; -var -{$IFDEF MSWINDOWS} - FileHandle: THandle; - MapHandle: THandle; - ViewPointer: Pointer; - Context: TCnMD5Context; -{$ENDIF} - Stream: TStream; - FileIsZeroSize: Boolean; - - function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; -{$IFDEF MSWINDOWS} - var - H: THandle; - Info: BY_HANDLE_FILE_INFORMATION; - Rec : Int64Rec; -{$ENDIF} - begin -{$IFDEF MSWINDOWS} - Result := False; - IsEmpty := False; - H := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); - if H = INVALID_HANDLE_VALUE then Exit; - try - if not GetFileInformationByHandle(H, Info) then Exit; - finally - CloseHandle(H); - end; - Rec.Lo := Info.nFileSizeLow; - Rec.Hi := Info.nFileSizeHigh; - Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); - IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); -{$ELSE} - Result := True; // Windows ƽ̨ Trueʾ Mapping -{$ENDIF} - end; - -begin - FileIsZeroSize := False; - if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then - begin - // 2G ļ Map ʧܣ Windows ƽ̨ʽѭ - Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); - try - InternalMD5Stream(Stream, 4096 * 1024, Result, CallBack); - finally - Stream.Free; - end; - end - else - begin -{$IFDEF MSWINDOWS} - MD5Init(Context); - FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or - FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or - FILE_FLAG_SEQUENTIAL_SCAN, 0); - if FileHandle <> INVALID_HANDLE_VALUE then - begin - try - MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); - if MapHandle <> 0 then - begin - try - ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); - if ViewPointer <> nil then - begin - try - MD5Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); - finally - UnmapViewOfFile(ViewPointer); - end; - end - else - begin - raise Exception.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); - end; - finally - CloseHandle(MapHandle); - end; - end - else - begin - if not FileIsZeroSize then - raise Exception.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); - end; - finally - CloseHandle(FileHandle); - end; - end; - MD5Final(Context, Result); -{$ENDIF} - end; -end; - -// ָ MD5 -function MD5Stream(Stream: TStream; - CallBack: TCnMD5CalcProgressFunc = nil): TCnMD5Digest; -begin - InternalMD5Stream(Stream, 4096 * 1024, Result, CallBack); -end; - -// ʮƸʽ MD5 Ӵֵ -function MD5Print(const Digest: TCnMD5Digest): string; -begin - Result := DataToHex(@Digest[0], SizeOf(TCnMD5Digest)); -end; - -// Ƚ MD5 ӴֵǷ -function MD5Match(const D1, D2: TCnMD5Digest): Boolean; -begin - Result := CompareMem(@D1[0], @D2[0], SizeOf(TCnMD5Digest)); -end; - -// MD5 Ӵֵת string -function MD5DigestToStr(const Digest: TCnMD5Digest): string; -begin - Result := MemoryToString(@Digest[0], SizeOf(TCnMD5Digest)); -end; - -procedure MD5HmacInit(var Ctx: TCnMD5Context; Key: PAnsiChar; KeyLength: Integer); -var - I: Integer; - Sum: TCnMD5Digest; -begin - if KeyLength > HMAC_MD5_BLOCK_SIZE_BYTE then - begin - Sum := MD5Buffer(Key, KeyLength); - KeyLength := HMAC_MD5_OUTPUT_LENGTH_BYTE; - Key := @(Sum[0]); - end; - - FillChar(Ctx.Ipad, HMAC_MD5_BLOCK_SIZE_BYTE, $36); - FillChar(Ctx.Opad, HMAC_MD5_BLOCK_SIZE_BYTE, $5C); - - for I := 0 to KeyLength - 1 do - begin - Ctx.Ipad[I] := Byte(Ctx.Ipad[I] xor Byte(Key[I])); - Ctx.Opad[I] := Byte(Ctx.Opad[I] xor Byte(Key[I])); - end; - - MD5Init(Ctx); - MD5Update(Ctx, @(Ctx.Ipad[0]), HMAC_MD5_BLOCK_SIZE_BYTE); -end; - -procedure MD5HmacUpdate(var Ctx: TCnMD5Context; Input: PAnsiChar; Length: Cardinal); -begin - MD5Update(Ctx, Input, Length); -end; - -procedure MD5HmacFinal(var Ctx: TCnMD5Context; var Output: TCnMD5Digest); -var - Len: Integer; - TmpBuf: TCnMD5Digest; -begin - Len := HMAC_MD5_OUTPUT_LENGTH_BYTE; - MD5Final(Ctx, TmpBuf); - MD5Init(Ctx); - MD5Update(Ctx, @(Ctx.Opad[0]), HMAC_MD5_BLOCK_SIZE_BYTE); - MD5Update(Ctx, @(TmpBuf[0]), Len); - MD5Final(Ctx, Output); -end; - -procedure MD5Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnMD5Digest); -var - Ctx: TCnMD5Context; -begin - MD5HmacInit(Ctx, Key, KeyByteLength); - MD5HmacUpdate(Ctx, Input, ByteLength); - MD5HmacFinal(Ctx, Output); -end; - -end. +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +{******************************************************************************} +{ } +{ MD5 Message-Digest for Delphi 4 } +{ } +{ Delphi 4 Unit implementing the } +{ RSA Data Security, Inc. MD5 Message-Digest Algorithm } +{ } +{ Implementation of Ronald L. Rivest's RFC 1321 } +{ } +{ Copyright ?1997-1999 Medienagentur Fichtner & Meyer } +{ Written by Matthias Fichtner } +{ } +{ -----------------------------------------------------------------------------} +{ See RFC 1321 for RSA Data Security's copyright and license notice! } +{ -----------------------------------------------------------------------------} +{ The latest release of md5.pas will always be available from } +{ the distribution site at: http://www.fichtner.net/delphi/md5/ } +{ -----------------------------------------------------------------------------} +{ Please send questions, bug reports and suggestions } +{ regarding this code to: mfichtner@fichtner-meyer.com } +{ -----------------------------------------------------------------------------} +{ This code is provided "as is" without express or } +{ implied warranty of any kind. Use it at your own risk. } +{******************************************************************************} + +unit CnMD5; +{* |
+================================================================================
+* ƣ
+* ԪƣMD5 Ӵ㷨ʵֵԪ
+* Ԫߣ壨QSoft hq.com@263.net; http://qsoft.51.net
+*            Ronald L. Rivest  MD5.pas дԭʼ
+*     עԪʵ MD5 Ӵ㷨Ӧ HMAC 㷨
+* ƽ̨PWin2000Pro + Delphi 5.0
+* ݲԣPWin9X/2000/XP + Delphi 5/6
+*   õԪеַϱػʽ
+* ޸ļ¼2019.12.12 V1.4
+*               ֧ TBytes
+*           2019.04.15 V1.3
+*               ֧ Win32/Win64/MacOS
+*           2014.11.14 V1.2
+*               л Pascal ֿ֧ƽ̨
+*           2003.09.18 V1.1
+*               òҵ˸õԪԭߵİȨ
+*           2003.09.18 V1.0
+*               Ԫ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + Classes, SysUtils, CnConsts, CnNative {$IFDEF MSWINDOWS}, Windows {$ENDIF}; + +type + PMD5Digest = ^TCnMD5Digest; + {* MD5 Ӵսָ} + TCnMD5Digest = array[0..15] of Byte; + {* MD5 Ӵս16 ֽ} + + TCnMD5Count = array[0..1] of Cardinal; + {* MD5 ڲṹ} + TCnMD5State = array[0..3] of Cardinal; + {* MD5 ڲ״̬ṹ} + TCnMD5Block = array[0..15] of Cardinal; + {* MD5 ڲṹ} + + TCnMD5Buffer = array[0..63] of Byte; + {* MD5 ڲṹ} + + TCnMD5Context = packed record + {* MD5 Ľṹ} + State : TCnMD5State; + Count : TCnMD5Count; + Buffer : TCnMD5Buffer; + Ipad : array[0..63] of Byte; {!< HMAC: inner padding } + Opad : array[0..63] of Byte; {!< HMAC: outer padding } + end; + + TCnMD5CalcProgressFunc = procedure (ATotal, AProgress: Int64; + var Cancel: Boolean) of object; + {* Ȼص¼} + +//---------------------------------------------------------------- +// û API +//---------------------------------------------------------------- + +function MD5(Input: PAnsiChar; ByteLength: Cardinal): TCnMD5Digest; +{* ݿ MD5 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5Buffer(const Buffer; Count: Cardinal): TCnMD5Digest; +{* ݿ MD5 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5Bytes(const Data: TBytes): TCnMD5Digest; +{* ֽ MD5 㡣 + + + const Data: TBytes - ֽ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5String(const Str: string): TCnMD5Digest; +{* String ݽ MD5 㡣ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + + const Str: string - ַ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5StringA(const Str: AnsiString): TCnMD5Digest; +{* AnsiString ݽ MD5 㣬ֱӼڲݣޱ봦 + + + const Str: AnsiString - ַ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5StringW(const Str: WideString): TCnMD5Digest; +{* WideString ַת MD5 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +{$IFDEF UNICODE} + +function MD5UnicodeString(const Str: string): TCnMD5Digest; +{* UnicodeString ݽֱӵ MD5 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +{$ELSE} + +function MD5UnicodeString(const Str: WideString): TCnMD5Digest; +{* UnicodeString ݽֱӵ MD5 㣬ֱӼڲ UTF16 ݣת + + + + const Str: WideString - Ŀַ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +{$ENDIF} + +function MD5File(const FileName: string; + CallBack: TCnMD5CalcProgressFunc = nil): TCnMD5Digest; +{* ָļݽ MD5 㡣 + + + const FileName: string - ļ + CallBack: TCnMD5CalcProgressFunc - ȻصĬΪ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5Stream(Stream: TStream; + CallBack: TCnMD5CalcProgressFunc = nil): TCnMD5Digest; +{* ָݽ MD5 㡣 + + + Stream: TStream - + CallBack: TCnMD5CalcProgressFunc - ȻصĬΪ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +// ⲿݽɢ MD5 㣬MD5Update ɶα + +procedure MD5Init(var Context: TCnMD5Context); +{* ʼһ MD5 ģ׼ MD5 + + + var Context: TCnMD5Context - ʼ MD5 + + ֵޣ +} + +procedure MD5Update(var Context: TCnMD5Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ MD5 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnMD5Context - MD5 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure MD5Final(var Context: TCnMD5Context; var Digest: TCnMD5Digest); +{* ּ㣬 MD5 Digest С + + + var Context: TCnMD5Context - MD5 + var Digest: TCnMD5Digest - ص MD5 Ӵֵ + + ֵޣ +} + +function MD5Print(const Digest: TCnMD5Digest): string; +{* ʮƸʽ MD5 Ӵֵ + + + const Digest: TCnMD5Digest - ָ MD5 Ӵֵ + + ֵstring - ʮַ +} + +function MD5Match(const D1: TCnMD5Digest; const D2: TCnMD5Digest): Boolean; +{* Ƚ MD5 ӴֵǷȡ + + + const D1: TCnMD5Digest - Ƚϵ MD5 Ӵֵһ + const D2: TCnMD5Digest - Ƚϵ MD5 Ӵֵ + + ֵBoolean - Ƿ +} + +function MD5DigestToStr(const Digest: TCnMD5Digest): string; +{* MD5 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnMD5Digest - ת MD5 Ӵֵ + + ֵstring - صַ +} + +procedure MD5Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnMD5Digest); +{* MD5 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - MD5 Կݿַ + KeyByteLength: Integer - MD5 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnMD5Digest - ص MD5 Ӵֵ + + ֵޣ +} + +function MD5HmacBytes(const Key: TBytes; const Data: TBytes): TCnMD5Digest; +{* ֽл MD5 HMAC 㡣 + + + const Key: TBytes - MD5 Կֽ + const Data: TBytes - ֽ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +implementation + +const + MAX_FILE_SIZE = 512 * 1024 * 1024; + // If file size <= this size (bytes), using Mapping, else stream + + HMAC_MD5_BLOCK_SIZE_BYTE = 64; + HMAC_MD5_OUTPUT_LENGTH_BYTE = 16; + +type + TMD5CBits = array[0..7] of Byte; + +var + PADDING: TCnMD5Buffer = ( + $80, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00 + ); + +function F(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Y) or ((not X) and Z); +end; + +function G(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Z) or (Y and (not Z)); +end; + +function H(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor Y xor Z; +end; + +function I(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := Y xor (X or (not Z)); +end; + +procedure ROT(var X: Cardinal; N: BYTE); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + X := (X shl N) or (X shr (32 - N)); +end; + +procedure FF(var A: Cardinal; B, C, D, X: Cardinal; S: BYTE; AC: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Inc(A, F(B, C, D) + X + AC); + ROT(A, S); + Inc(A, B); +end; + +procedure GG(var A: Cardinal; B, C, D, X: Cardinal; S: BYTE; AC: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Inc(A, G(B, C, D) + X + AC); + ROT(A, S); + Inc(A, B); +end; + +procedure HH(var A: Cardinal; B, C, D, X: Cardinal; S: BYTE; AC: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Inc(A, H(B, C, D) + X + AC); + ROT(A, S); + Inc(A, B); +end; + +procedure II(var A: Cardinal; B, C, D, X: Cardinal; S: BYTE; AC: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Inc(A, I(B, C, D) + X + AC); + ROT(A, S); + Inc(A, B); +end; + +// Encode Count bytes at Source into (Count / 4) DWORDs at Target +procedure Encode(Source, Target: Pointer; Count: Cardinal); +var + S: PByte; + T: PCardinal; + I: Cardinal; +begin + S := Source; + T := Target; + for I := 1 to Count div 4 do + begin + T^ := S^; + Inc(S); + T^ := T^ or (S^ shl 8); + Inc(S); + T^ := T^ or (S^ shl 16); + Inc(S); + T^ := T^ or (S^ shl 24); + Inc(S); + Inc(T); + end; +end; + +// Decode Count DWORDs at Source into (Count * 4) Bytes at Target +procedure Decode(Source, Target: Pointer; Count: Cardinal); +var + S: PCardinal; + T: PByte; + I: Cardinal; +begin + S := Source; + T := Target; + for I := 1 to Count do + begin + T^ := S^ and $ff; + Inc(T); + T^ := (S^ shr 8) and $ff; + Inc(T); + T^ := (S^ shr 16) and $ff; + Inc(T); + T^ := (S^ shr 24) and $ff; + Inc(T); + Inc(S); + end; +end; + +// Transform State according to first 64 bytes at Buffer +procedure Transform(Buffer: Pointer; var State: TCnMD5State); +var + A, B, C, D: Cardinal; + Block: TCnMD5Block; +begin + Encode(Buffer, @Block, 64); + A := State[0]; + B := State[1]; + C := State[2]; + D := State[3]; + FF (A, B, C, D, Block[ 0], 7, $d76aa478); + FF (D, A, B, C, Block[ 1], 12, $e8c7b756); + FF (C, D, A, B, Block[ 2], 17, $242070db); + FF (B, C, D, A, Block[ 3], 22, $c1bdceee); + FF (A, B, C, D, Block[ 4], 7, $f57c0faf); + FF (D, A, B, C, Block[ 5], 12, $4787c62a); + FF (C, D, A, B, Block[ 6], 17, $a8304613); + FF (B, C, D, A, Block[ 7], 22, $fd469501); + FF (A, B, C, D, Block[ 8], 7, $698098d8); + FF (D, A, B, C, Block[ 9], 12, $8b44f7af); + FF (C, D, A, B, Block[10], 17, $ffff5bb1); + FF (B, C, D, A, Block[11], 22, $895cd7be); + FF (A, B, C, D, Block[12], 7, $6b901122); + FF (D, A, B, C, Block[13], 12, $fd987193); + FF (C, D, A, B, Block[14], 17, $a679438e); + FF (B, C, D, A, Block[15], 22, $49b40821); + GG (A, B, C, D, Block[ 1], 5, $f61e2562); + GG (D, A, B, C, Block[ 6], 9, $c040b340); + GG (C, D, A, B, Block[11], 14, $265e5a51); + GG (B, C, D, A, Block[ 0], 20, $e9b6c7aa); + GG (A, B, C, D, Block[ 5], 5, $d62f105d); + GG (D, A, B, C, Block[10], 9, $2441453); + GG (C, D, A, B, Block[15], 14, $d8a1e681); + GG (B, C, D, A, Block[ 4], 20, $e7d3fbc8); + GG (A, B, C, D, Block[ 9], 5, $21e1cde6); + GG (D, A, B, C, Block[14], 9, $c33707d6); + GG (C, D, A, B, Block[ 3], 14, $f4d50d87); + GG (B, C, D, A, Block[ 8], 20, $455a14ed); + GG (A, B, C, D, Block[13], 5, $a9e3e905); + GG (D, A, B, C, Block[ 2], 9, $fcefa3f8); + GG (C, D, A, B, Block[ 7], 14, $676f02d9); + GG (B, C, D, A, Block[12], 20, $8d2a4c8a); + HH (A, B, C, D, Block[ 5], 4, $fffa3942); + HH (D, A, B, C, Block[ 8], 11, $8771f681); + HH (C, D, A, B, Block[11], 16, $6d9d6122); + HH (B, C, D, A, Block[14], 23, $fde5380c); + HH (A, B, C, D, Block[ 1], 4, $a4beea44); + HH (D, A, B, C, Block[ 4], 11, $4bdecfa9); + HH (C, D, A, B, Block[ 7], 16, $f6bb4b60); + HH (B, C, D, A, Block[10], 23, $bebfbc70); + HH (A, B, C, D, Block[13], 4, $289b7ec6); + HH (D, A, B, C, Block[ 0], 11, $eaa127fa); + HH (C, D, A, B, Block[ 3], 16, $d4ef3085); + HH (B, C, D, A, Block[ 6], 23, $4881d05); + HH (A, B, C, D, Block[ 9], 4, $d9d4d039); + HH (D, A, B, C, Block[12], 11, $e6db99e5); + HH (C, D, A, B, Block[15], 16, $1fa27cf8); + HH (B, C, D, A, Block[ 2], 23, $c4ac5665); + II (A, B, C, D, Block[ 0], 6, $f4292244); + II (D, A, B, C, Block[ 7], 10, $432aff97); + II (C, D, A, B, Block[14], 15, $ab9423a7); + II (B, C, D, A, Block[ 5], 21, $fc93a039); + II (A, B, C, D, Block[12], 6, $655b59c3); + II (D, A, B, C, Block[ 3], 10, $8f0ccc92); + II (C, D, A, B, Block[10], 15, $ffeff47d); + II (B, C, D, A, Block[ 1], 21, $85845dd1); + II (A, B, C, D, Block[ 8], 6, $6fa87e4f); + II (D, A, B, C, Block[15], 10, $fe2ce6e0); + II (C, D, A, B, Block[ 6], 15, $a3014314); + II (B, C, D, A, Block[13], 21, $4e0811a1); + II (A, B, C, D, Block[ 4], 6, $f7537e82); + II (D, A, B, C, Block[11], 10, $bd3af235); + II (C, D, A, B, Block[ 2], 15, $2ad7d2bb); + II (B, C, D, A, Block[ 9], 21, $eb86d391); + Inc(State[0], A); + Inc(State[1], B); + Inc(State[2], C); + Inc(State[3], D); +end; + +// Initialize given Context +procedure MD5Init(var Context: TCnMD5Context); +begin + with Context do + begin + State[0] := $67452301; + State[1] := $EFCDAB89; + State[2] := $98BADCFE; + State[3] := $10325476; + Count[0] := 0; + Count[1] := 0; + // ZeroMemory(@Buffer, SizeOf(TMD5Buffer)); + FillChar(Buffer, SizeOf(TCnMD5Buffer), 0); + end; +end; + +// Update given Context to include Length bytes of Input +procedure MD5Update(var Context: TCnMD5Context; Input: PAnsiChar; ByteLength: Cardinal); +var + Index: Cardinal; + PartLen: Cardinal; + I: Cardinal; +begin + with Context do + begin + Index := (Count[0] shr 3) and $3F; + Inc(Count[0], ByteLength shl 3); + if Count[0] < (ByteLength shl 3) then Inc(Count[1]); + Inc(Count[1], ByteLength shr 29); + end; + + PartLen := 64 - Index; + if ByteLength >= PartLen then + begin + Move(Input^, Context.Buffer[Index], PartLen); + Transform(@Context.Buffer, Context.State); + I := PartLen; + while I + 63 < ByteLength do + begin + Transform(@Input[I], Context.State); + Inc(I, 64); + end; + Index := 0; + end + else + I := 0; + + Move(Input[I], Context.Buffer[Index], ByteLength - I); +end; + +procedure MD5UpdateW(var Context: TCnMD5Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + pContent: PAnsiChar; + iLen: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(pContent, CharLength * SizeOf(WideChar)); + try + iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(pContent), CharLength * SizeOf(WideChar), nil, nil); + MD5Update(Context, pContent, iLen); + finally + FreeMem(pContent); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + MD5Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +// Finalize given Context, create Digest +procedure MD5Final(var Context: TCnMD5Context; var Digest: TCnMD5Digest); +var + Bits: TMD5CBits; + Index: Cardinal; + PadLen: Cardinal; +begin + Decode(@Context.Count, @Bits, 2); + Index := (Context.Count[0] shr 3) and $3f; + if Index < 56 then + PadLen := 56 - Index + else + PadLen := 120 - Index; + MD5Update(Context, @PADDING, PadLen); + MD5Update(Context, @Bits, 8); + Decode(@Context.State, @Digest, 4); +end; + +function InternalMD5Stream(Stream: TStream; const BufSize: Cardinal; var D: + TCnMD5Digest; CallBack: TCnMD5CalcProgressFunc): Boolean; +var + Context: TCnMD5Context; + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; +begin + Result := False; + Size := Stream.Size; + if Size = 0 then + Exit; + + SavePos := Stream.Position; + TotalBytes := 0; + + if Size < BufSize then + BufLen := Size + else + BufLen := BufSize; + + CancelCalc := False; + MD5Init(Context); + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + MD5Update(Context, Buf, ReadBytes); + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + MD5Final(Context, D); + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +// ݿ MD5 +function MD5(Input: PAnsiChar; ByteLength: Cardinal): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5Update(Context, Input, ByteLength); + MD5Final(Context, Result); +end; + +// ݿ MD5 +function MD5Buffer(const Buffer; Count: Cardinal): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5Update(Context, PAnsiChar(@Buffer), Count); + MD5Final(Context, Result); +end; + +function MD5Bytes(const Data: TBytes): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5Update(Context, PAnsiChar(@Data[0]), Length(Data)); + MD5Final(Context, Result); +end; + +// String ݽ MD5 +function MD5String(const Str: string): TCnMD5Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := MD5StringA(AStr); +end; + +// AnsiString ݽ MD5 +function MD5StringA(const Str: AnsiString): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5Update(Context, PAnsiChar(Str), Length(Str)); + MD5Final(Context, Result); +end; + +// WideString ݽ MD5 +function MD5StringW(const Str: WideString): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5UpdateW(Context, PWideChar(Str), Length(Str)); + MD5Final(Context, Result); +end; + +// UnicodeString ݽֱӵ MD5 㣬ת +{$IFDEF UNICODE} +function MD5UnicodeString(const Str: string): TCnMD5Digest; +{$ELSE} +function MD5UnicodeString(const Str: WideString): TCnMD5Digest; +{$ENDIF} +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + MD5Final(Context, Result); +end; + +// ָļݽ MD5 +function MD5File(const FileName: string; + CallBack: TCnMD5CalcProgressFunc): TCnMD5Digest; +var +{$IFDEF MSWINDOWS} + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; + Context: TCnMD5Context; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; + + function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; +{$IFDEF MSWINDOWS} + var + H: THandle; + Info: BY_HANDLE_FILE_INFORMATION; + Rec : Int64Rec; +{$ENDIF} + begin +{$IFDEF MSWINDOWS} + Result := False; + IsEmpty := False; + H := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); + if H = INVALID_HANDLE_VALUE then Exit; + try + if not GetFileInformationByHandle(H, Info) then Exit; + finally + CloseHandle(H); + end; + Rec.Lo := Info.nFileSizeLow; + Rec.Hi := Info.nFileSizeHigh; + Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); + IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); +{$ELSE} + Result := True; // Windows ƽ̨ Trueʾ Mapping +{$ENDIF} + end; + +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣ Windows ƽ̨ʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalMD5Stream(Stream, 4096 * 1024, Result, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + MD5Init(Context); + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + MD5Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise ECnNativeException.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise ECnNativeException.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + MD5Final(Context, Result); +{$ENDIF} + end; +end; + +// ָ MD5 +function MD5Stream(Stream: TStream; + CallBack: TCnMD5CalcProgressFunc): TCnMD5Digest; +begin + InternalMD5Stream(Stream, 4096 * 1024, Result, CallBack); +end; + +// ʮƸʽ MD5 Ӵֵ +function MD5Print(const Digest: TCnMD5Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnMD5Digest)); +end; + +// Ƚ MD5 ӴֵǷ +function MD5Match(const D1, D2: TCnMD5Digest): Boolean; +begin + Result := ConstTimeCompareMem(@D1[0], @D2[0], SizeOf(TCnMD5Digest)); +end; + +// MD5 Ӵֵת string +function MD5DigestToStr(const Digest: TCnMD5Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnMD5Digest)); +end; + +procedure MD5HmacInit(var Context: TCnMD5Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnMD5Digest; +begin + if KeyLength > HMAC_MD5_BLOCK_SIZE_BYTE then + begin + Sum := MD5Buffer(Key^, KeyLength); + KeyLength := HMAC_MD5_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_MD5_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_MD5_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + MD5Init(Context); + MD5Update(Context, @(Context.Ipad[0]), HMAC_MD5_BLOCK_SIZE_BYTE); +end; + +procedure MD5HmacUpdate(var Context: TCnMD5Context; Input: PAnsiChar; Length: Cardinal); +begin + MD5Update(Context, Input, Length); +end; + +procedure MD5HmacFinal(var Context: TCnMD5Context; var Output: TCnMD5Digest); +var + Len: Integer; + TmpBuf: TCnMD5Digest; +begin + Len := HMAC_MD5_OUTPUT_LENGTH_BYTE; + MD5Final(Context, TmpBuf); + MD5Init(Context); + MD5Update(Context, @(Context.Opad[0]), HMAC_MD5_BLOCK_SIZE_BYTE); + MD5Update(Context, @(TmpBuf[0]), Len); + MD5Final(Context, Output); +end; + +procedure MD5Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnMD5Digest); +var + Context: TCnMD5Context; +begin + MD5HmacInit(Context, Key, KeyByteLength); + MD5HmacUpdate(Context, Input, ByteLength); + MD5HmacFinal(Context, Output); +end; + +function MD5HmacBytes(const Key: TBytes; const Data: TBytes): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + MD5HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + MD5HmacFinal(Context, Result); +end; + +end. diff --git a/CnPack/Crypto/CnNative.pas b/CnPack/Crypto/CnNative.pas index 972f9e4..6895190 100644 --- a/CnPack/Crypto/CnNative.pas +++ b/CnPack/Crypto/CnNative.pas @@ -1,4904 +1,5498 @@ -{******************************************************************************} -{ CnPack For Delphi/C++Builder } -{ йԼĿԴ } -{ (C)Copyright 2001-2025 CnPack } -{ ------------------------------------ } -{ } -{ ǿԴ CnPack ķЭ } -{ ĺ·һ } -{ } -{ һĿϣãûκεû } -{ ʺضĿĶĵϸ CnPack Э顣 } -{ } -{ ӦѾͿһյһ CnPack Эĸ } -{ ûУɷǵվ } -{ } -{ վַhttps://www.cnpack.org } -{ ʼmaster@cnpack.org } -{ } -{******************************************************************************} - -unit CnNative; -{* |
-================================================================================
-* ƣCnPack 
-* Ԫƣ32 λ 64 λƽ̨һЩͳһԼһʵֵԪ
-* ԪߣCnPack  (master@cnpack.org)
-*     עԪһ 32 λ 64 λƽ̨һЩͳһʵ֡
-*           Delphi XE 2 ֧ 32  64 ų NativeInt  NativeUInt 
-*           ǰ 32 λ 64 ̬仯Ӱ쵽 PointerReferenceȶ
-*           ǵԣ̶ȵ 32 λ Cardinal/Integer Ⱥ Pointer Щ
-*           ͨˣʹ 32 λҲֹ˱Ԫ˼ͣ
-*           ͬʱڵͰ汾͸߰汾 Delphi ʹá
-*
-*           ԪҲڲ֧ UInt64 ı Delphi 5/6/7  Int64 ģ UInt64
-*           ĸ㣬ӼȻ֧֣˳Ҫģ div  mod
-*           ַ Integer(APtr)  64 λ MacOS ׳ֽضϣҪ NativeInt
-*
-*           ʵ˴Сءֽת̶ʱȷĴײ㺯빤ࡣ
-*
-* ƽ̨PWin2000 + Delphi 5.0
-* ݲԣPWin9X/2000/XP + Delphi 5/6/7 XE 2
-*   õԪеַϱػʽ
-* ޸ļ¼2023.08.14 V2.4
-*               ϼʱ̶ĺ
-*           2022.11.11 V2.3
-*               ϼ޷ֽ˳
-*           2022.07.23 V2.2
-*               Ӽڴλ㺯תַΪ CnNative
-*           2022.06.08 V2.1
-*               ĸʱ̶ĽԼڴ浹ź
-*           2022.03.14 V2.0
-*               Ӽʮת
-*           2022.02.17 V1.9
-*                FPC ı֧
-*           2022.02.09 V1.8
-*               ڵĴСжϺ
-*           2021.09.05 V1.7
-*                Int64/UInt64 㺯
-*           2020.10.28 V1.6
-*                UInt64 صж㺯
-*           2020.09.06 V1.5
-*                UInt64 ƽĺ
-*           2020.07.01 V1.5
-*               ж 32 λ 64 λ޷Ƿĺ
-*           2020.06.20 V1.4
-*                32 λ 64 λȡ͵ 1 λλõĺ
-*           2020.01.01 V1.3
-*                32 λ޷͵ mul 㣬ڲ֧ UInt64 ϵͳ Int64 Ա
-*           2018.06.05 V1.2
-*                64 λ͵ div/mod 㣬ڲ֧ UInt64 ϵͳ Int64  
-*           2016.09.27 V1.1
-*                64 λ͵һЩ
-*           2011.07.06 V1.0
-*               Ԫʵֹ
-================================================================================
-|
} - -interface - -{$I CnPack.inc} - -uses - Classes, SysUtils, SysConst, Math {$IFDEF COMPILER5}, Windows {$ENDIF}; - // D5 Ҫ Windows е PByte -type - ECnNativeException = class(Exception); - {* Native 쳣} - -{$IFDEF COMPILER5} - PCardinal = ^Cardinal; - {* D5 System Ԫδ壬} - PByte = Windows.PByte; - {* D5 PByte Windows У汾 System У - ͳһһ¹ʹ PByte ʱ uses Windowsڿƽ̨} -{$ENDIF} - -{$IFDEF BCB5OR6} - PInt64 = ^Int64; - {* C++Builder 5/6 sysmac.h û PInt64 Ķ壨е PUINT64 Сдͬ㣩} -{$ENDIF} - -{$IFDEF SUPPORT_32_AND_64} - TCnNativeInt = NativeInt; - TCnNativeUInt = NativeUInt; - TCnNativePointer = NativeInt; - TCnNativeIntPtr = PNativeInt; - TCnNativeUIntPtr = PNativeUInt; -{$ELSE} - TCnNativeInt = Integer; - TCnNativeUInt = Cardinal; - TCnNativePointer = Integer; - TCnNativeIntPtr = PInteger; - TCnNativeUIntPtr = PCardinal; -{$ENDIF} - -{$IFDEF CPU64BITS} - TCnUInt64 = NativeUInt; - TCnInt64 = NativeInt; -{$ELSE} - {$IFDEF SUPPORT_UINT64} - TCnUInt64 = UInt64; - {$ELSE} - TCnUInt64 = packed record // ֻĽṹ - case Boolean of - True: (Value: Int64); - False: (Lo32, Hi32: Cardinal); - end; - {$ENDIF} - TCnInt64 = Int64; -{$ENDIF} - -// TUInt64 cnvcl в֧ UInt64 div mod -{$IFDEF SUPPORT_UINT64} - TUInt64 = UInt64; - {$IFNDEF SUPPORT_PUINT64} - PUInt64 = ^UInt64; - {$ENDIF} -{$ELSE} - TUInt64 = Int64; - PUInt64 = ^TUInt64; -{$ENDIF} - -{$IFNDEF SUPPORT_INT64ARRAY} - // ϵͳûж Int64Array - Int64Array = array[0..$0FFFFFFE] of Int64; - PInt64Array = ^Int64Array; -{$ENDIF} - - TUInt64Array = array of TUInt64; // ̬ƺ׺;̬гͻ - - ExtendedArray = array[0..65537] of Extended; - PExtendedArray = ^ExtendedArray; - - PCnWord16Array = ^TCnWord16Array; - TCnWord16Array = array [0..0] of Word; - -{$IFDEF POSIX64} - TCnLongWord32 = Cardinal; // Linux64/MacOS64 (or POSIX64?) LongWord is 64 Bits -{$ELSE} - TCnLongWord32 = LongWord; -{$ENDIF} - PCnLongWord32 = ^TCnLongWord32; - - TCnLongWord32Array = array [0..MaxInt div SizeOf(Integer) - 1] of TCnLongWord32; - - PCnLongWord32Array = ^TCnLongWord32Array; - -{$IFNDEF TBYTES_DEFINED} - TBytes = array of Byte; - {* ޷ֽڶ̬飬δʱ} -{$ENDIF} - - TShortInts = array of ShortInt; - {* зֽڶ̬} - - TSmallInts = array of SmallInt; - {* з˫ֽڶ̬} - - TWords = array of Word; - {* ޷˫ֽڶ̬} - - TIntegers = array of Integer; - {* зֽڶ̬} - - TCardinals = array of Cardinal; - {* ޷ֽڶ̬} - - PCnByte = ^Byte; - PCnWord = ^Word; - - TCnBitOperation = (boAnd, boOr, boXor, boNot); - {* λ} - -type - TCnMemSortCompareProc = function (P1, P2: Pointer; ElementByteSize: Integer): Integer; - {* ڴ̶ߴȽϺԭ} - -const - CN_MAX_SQRT_INT64: Cardinal = 3037000499; - CN_MAX_INT8: ShortInt = $7F; - CN_MIN_INT8: ShortInt = -128; - CN_MAX_INT16: SmallInt = $7FFF; - CN_MIN_INT16: SmallInt = -32768; - CN_MAX_INT32: Integer = $7FFFFFFF; - CN_MIN_INT32: Integer = $80000000; // 뾯棬 -2147483648 - CN_MIN_INT32_IN_INT64: Int64 = $0000000080000000; - CN_MAX_INT64: Int64 = $7FFFFFFFFFFFFFFF; - CN_MIN_INT64: Int64 = $8000000000000000; - CN_MAX_UINT8: Byte = $FF; - CN_MAX_UINT16: Word = $FFFF; - CN_MAX_UINT32: Cardinal = $FFFFFFFF; - CN_MAX_TUINT64: TUInt64 = $FFFFFFFFFFFFFFFF; - CN_MAX_SIGNED_INT64_IN_TUINT64: TUInt64 = $7FFFFFFFFFFFFFFF; - -{* - D567 Ȳ֧ UInt64 ıȻ Int64 UInt64 мӼ洢 - ˳޷ֱɣװ System е _lludiv _llumod - ʵ Int64 ʾ UInt64 ݵ div mod ܡ -} -function UInt64Mod(A: TUInt64; B: TUInt64): TUInt64; -{* 64 λ޷ࡣ - - - A: TUInt64 - - B: TUInt64 - - - ֵTUInt64 - -} - -function UInt64Div(A: TUInt64; B: TUInt64): TUInt64; -{* 64 λ޷ - - - A: TUInt64 - - B: TUInt64 - - - ֵTUInt64 - -} - -function UInt64Mul(A: Cardinal; B: Cardinal): TUInt64; -{* 32 λ޷ˡڲ֧ UInt64 ƽ̨ϣ UInt64 ʽ Int64  - ֱʹ Int64 п - - - A: Cardinal - һ - B: Cardinal - - - ֵTUInt64 - -} - -procedure UInt64AddUInt64(A: TUInt64; B: TUInt64; var ResLo: TUInt64; var ResHi: TUInt64); -{* 64 λ޷ӣ ResLo ResHi С - עڲʵְ㷨ΪӣʵResHi Ȼ 1ֱж 1 - - - A: TUInt64 - һ - B: TUInt64 - - var ResLo: TUInt64 - ͵λ - var ResHi: TUInt64 - ͸λ - - ֵޣ -} - -procedure UInt64MulUInt64(A: TUInt64; B: TUInt64; var ResLo: TUInt64; var ResHi: TUInt64); -{* 64 λ޷ˣ ResLo ResHi СWin 64 λûʵ֣Լһϡ - - - A: TUInt64 - һ - B: TUInt64 - - var ResLo: TUInt64 - λ - var ResHi: TUInt64 - λ - - ֵޣ -} - -function UInt64ToHex(N: TUInt64): string; -{* 64 λ޷תΪʮַ - - - N: TUInt64 - תֵ - - ֵstring - ʮַ -} - -function UInt64ToStr(N: TUInt64): string; -{* 64 λ޷תΪʮַ - - - N: TUInt64 - תֵ - - ֵstring - ʮַ -} - -function StrToUInt64(const S: string): TUInt64; -{* ַתΪ 64 λ޷ - - - const S: string - תַ - - ֵTUInt64 - ת -} - -function UInt64Compare(A: TUInt64; B: TUInt64): Integer; -{* Ƚ 64 λ޷ֱֵݱȽϵĽǴڡڻС 10-1 - - - A: TUInt64 - Ƚϵһ - B: TUInt64 - Ƚϵ - - ֵInteger - رȽϽ -} - -function UInt64Sqrt(N: TUInt64): TUInt64; -{* 64 λ޷ƽ֡ - - - N: TUInt64 - ƽ - - ֵTUInt64 - ƽ -} - -function UInt32IsNegative(N: Cardinal): Boolean; -{* ж 32 λ޷ 32 λзʱǷС 0 - - - N: Cardinal - жϵֵ - - ֵBoolean - ǷС 0 -} - -function UInt64IsNegative(N: TUInt64): Boolean; -{* ж 64 λ޷ 64 λзʱǷС 0 - - - N: TUInt64 - жϵֵ - - ֵBoolean - ǷС 0 -} - -procedure UInt64SetBit(var B: TUInt64; Index: Integer); -{* 64 λijһλ 1λ Index 0 ʼ 63 - - - var B: TUInt64 - λֵ - Index: Integer - 1 λ - - ֵޣ -} - -procedure UInt64ClearBit(var B: TUInt64; Index: Integer); -{* 64 λijһλ 0λ Index 0 ʼ 63 - - - var B: TUInt64 - λֵ - Index: Integer - 0 λ - - ֵޣ -} - -function GetUInt64BitSet(B: TUInt64; Index: Integer): Boolean; -{* 64 λijһλǷ 1λ Index 0 ʼ 63 - - - B: TUInt64 - жϵֵ - Index: Integer - жϵλ - - ֵBoolean - ظλǷ 1 -} - -function GetUInt64HighBits(B: TUInt64): Integer; -{* 64 λ 1 ߶λǵڼλλ 0û 1 -1 - - - B: TUInt64 - жϵֵ - - ֵInteger - 1 λ -} - -function GetUInt32HighBits(B: Cardinal): Integer; -{* 32 λ 1 ߶λǵڼλλ 0û 1 -1 - - - B: Cardinal - жϵֵ - - ֵInteger - 1 λ -} - -function GetUInt16HighBits(B: Word): Integer; -{* 16 λ 1 ߶λǵڼλλ 0û 1 -1 - - - B: Word - жϵֵ - - ֵInteger - 1 λ -} - -function GetUInt8HighBits(B: Byte): Integer; -{* 8 λ 1 ߶λǵڼλλ 0û 1 -1 - - - B: Byte - жϵֵ - - ֵInteger - 1 λ -} - -function GetUInt64LowBits(B: TUInt64): Integer; -{* 64 λ 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 - - - B: TUInt64 - жϵֵ - - ֵInteger - 1 λ -} - -function GetUInt32LowBits(B: Cardinal): Integer; -{* 32 λ 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 - - - B: Cardinal - жϵֵ - - ֵInteger - 1 λ -} - -function GetUInt16LowBits(B: Word): Integer; -{* 16 λ 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 - - - B: Word - жϵֵ - - ֵInteger - 1 λ -} - -function GetUInt8LowBits(B: Byte): Integer; -{* 8 λ 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 - - - B: Byte - жϵֵ - - ֵInteger - 1 λ -} - -function Int64Mod(M: Int64; N: Int64): Int64; -{* װ Int64 ModM ֵʱȡģģ N Ҫס - - - M: Int64 - - N: Int64 - - - ֵInt64 - -} - -function IsUInt32PowerOf2(N: Cardinal): Boolean; -{* жһ 32 λ޷Ƿ 2 ݡ - - - N: Cardinal - жϵֵ - - ֵBoolean - Ƿ 2 -} - -function IsUInt64PowerOf2(N: TUInt64): Boolean; -{* жһ 64 λ޷Ƿ 2 ݡ - - - N: TUInt64 - жϵֵ - - ֵBoolean - Ƿ 2 -} - -function GetUInt32PowerOf2GreaterEqual(N: Cardinal): Cardinal; -{* õһָ 32 λ޷ȵ 2 ݣ򷵻 0 - - - N: Cardinal - ֵ - - ֵCardinal - ط 2 ݻ 0 -} - -function GetUInt64PowerOf2GreaterEqual(N: TUInt64): TUInt64; -{* õһָ 64 λ޷ȵ 2 ݣ򷵻 0 - - - N: TUInt64 - ֵ - - ֵTUInt64 - ط 2 ݻ 0 -} - -function IsInt32AddOverflow(A: Integer; B: Integer): Boolean; -{* ж 32 λзǷ 32 λзޡ - - - A: Integer - һ - B: Integer - - - ֵBoolean - Ƿ -} - -function IsUInt32AddOverflow(A: Cardinal; B: Cardinal): Boolean; -{* ж 32 λ޷Ƿ 32 λ޷ޡ - - - A: Cardinal - һ - B: Cardinal - - - ֵBoolean - Ƿ -} - -function IsInt64AddOverflow(A: Int64; B: Int64): Boolean; -{* ж 64 λзǷ 64 λзޡ - - - A: Int64 - һ - B: Int64 - - - ֵBoolean - Ƿ -} - -function IsUInt64AddOverflow(A: TUInt64; B: TUInt64): Boolean; -{* ж 64 λ޷Ƿ 64 λ޷ޡ - - - A: TUInt64 - һ - B: TUInt64 - - - ֵBoolean - Ƿ -} - -function IsUInt64SubOverflowInt32(A: TUInt64; B: TUInt64): Boolean; -{* жһ 64 λ޷ȥһ 64 λ޷ĽǷ񳬳 32 λзΧ - 64 λе JMP תжϡ - - - A: TUInt64 - - B: TUInt64 - - - ֵBoolean - Ƿ񳬳 32 λзΧ -} - -procedure UInt64Add(var R: TUInt64; A: TUInt64; B: TUInt64; out Carry: Integer); -{* 64 λ޷ӣA + B => R 1 ýλλ㡣 - - - var R: TUInt64 - - A: TUInt64 - һ - B: TUInt64 - - out Carry: Integer - λ - - ֵޣ -} - -procedure UInt64Sub(var R: TUInt64; A: TUInt64; B: TUInt64; out Carry: Integer); -{* 64 λ޷A - B => Rнλ 1 ýλλ㡣 - - - var R: TUInt64 - - A: TUInt64 - - B: TUInt64 - - out Carry: Integer - λ - - ֵޣ -} - -function IsInt32MulOverflow(A: Integer; B: Integer): Boolean; -{* ж 32 λзǷ 32 λзޡ - - - A: Integer - һ - B: Integer - - - ֵBoolean - Ƿ -} - -function IsUInt32MulOverflow(A: Cardinal; B: Cardinal): Boolean; -{* ж 32 λ޷Ƿ 32 λ޷ - - - A: Cardinal - һ - B: Cardinal - - - ֵBoolean - Ƿ -} - -function IsUInt32MulOverflowInt64(A: Cardinal; B: Cardinal; out R: TUInt64): Boolean; -{* ж 32 λ޷Ƿ 64 λзޣδҲ False ʱR ֱӷؽ - Ҳ TrueҪµ UInt64Mul ʵʩˡ - - - A: Cardinal - һ - B: Cardinal - - out R: TUInt64 - δʱػ - - ֵBoolean - Ƿ -} - -function IsInt64MulOverflow(A: Int64; B: Int64): Boolean; -{* ж 64 λзǷ 64 λзޡ - - - A: Int64 - һ - B: Int64 - - - ֵBoolean - Ƿ -} - -function PointerToInteger(P: Pointer): Integer; -{* ָת֧ͣ 32/64 λע 64 λ¿ܻᶪ 32 λݡ - - - P: Pointer - תָ - - ֵInteger - ת -} - -function IntegerToPointer(I: Integer): Pointer; -{* תָ֧ͣ 32/64 λ - - - I: Integer - ת - - ֵPointer - תָ -} - -function Int64NonNegativeAddMod(A: Int64; B: Int64; N: Int64): Int64; -{* 64 λзΧĺ࣬Ҫ N 0 - - - A: Int64 - һ - B: Int64 - һ - N: Int64 - ģ - - ֵInt64 - Ľ -} - -function UInt64NonNegativeAddMod(A: TUInt64; B: TUInt64; N: TUInt64): TUInt64; -{* 64 λ޷Χĺ࣬Ҫ N 0 - - - A: TUInt64 - һ - B: TUInt64 - - N: TUInt64 - ģ - - ֵTUInt64 - Ľ -} - -function Int64NonNegativeMulMod(A: Int64; B: Int64; N: Int64): Int64; -{* 64 λзΧڵֱ࣬Ӽ㣬Ҫ N 0 - - - A: Int64 - һ - B: Int64 - - N: Int64 - ģ - - ֵInt64 - Ľ -} - -function UInt64NonNegativeMulMod(A: TUInt64; B: TUInt64; N: TUInt64): TUInt64; -{* 64 λ޷Χڵֱ࣬Ӽ㣬 - - - A: TUInt64 - һ - B: TUInt64 - - N: TUInt64 - ģ - - ֵTUInt64 - Ľ -} - -function Int64NonNegativeMod(N: Int64; P: Int64): Int64; -{* װ 64 λзķǸຯҲΪʱӸ豣֤ P 0 - - - N: Int64 - - P: Int64 - - - ֵInt64 - طǸĽ -} - -function Int64NonNegativPower(N: Int64; Exp: Integer): Int64; -{* 64 λзķǸָݣ - - - N: Int64 - - Exp: Integer - ָҪ 0 - - ֵInt64 - ݵĽ -} - -function Int64NonNegativeRoot(N: Int64; Exp: Integer): Int64; -{* 64 λзķǸη֣ - - - N: Int64 - - Exp: Integer - - - ֵInt64 - ؿֽ -} - -function UInt64NonNegativPower(N: TUInt64; Exp: Integer): TUInt64; -{* 64 λ޷ķǸָݣ - - - N: TUInt64 - - Exp: Integer - ָҪ 0 - - ֵTUInt64 - ݵĽ -} - -function UInt64NonNegativeRoot(N: TUInt64; Exp: Integer): TUInt64; -{* 64 λ޷ķǸη֣ - - - N: TUInt64 - - Exp: Integer - - - ֵTUInt64 - ؿֽ -} - -function CurrentByteOrderIsBigEndian: Boolean; -{* صǰڻǷǴˣҲǷеĸֽڴ洢ڽϵ͵ʼַ - ϴҵĶϰߣ粿ָ ARM MIPS - - - ޣ - - ֵBoolean - صǰڻǷǴ -} - -function CurrentByteOrderIsLittleEndian: Boolean; -{* صǰڻǷСˣҲǷеĸֽڴ洢ڽϸߵʼַ x86 벿Ĭ ARM - - - ޣ - - ֵBoolean - صǰڻǷС -} - -function Int64ToBigEndian(Value: Int64): Int64; -{* ȷ 64 λзֵΪˣС˻лת - - - Value: Int64 - ת 64 λз - - ֵInt64 - شֵ -} - -function Int32ToBigEndian(Value: Integer): Integer; -{* ȷ 32 λзֵΪˣС˻лת - - - Value: Integer - ת 32 λз - - ֵInteger - شֵ -} - -function Int16ToBigEndian(Value: SmallInt): SmallInt; -{* ȷ 16 λзֵΪˣС˻лת - - - Value: SmallInt - ת 16 λз - - ֵSmallInt - شֵ -} - -function Int64ToLittleEndian(Value: Int64): Int64; -{* ȷ 64 λзֵΪСˣڴ˻лת - - - Value: Int64 - ת 64 λз - - ֵInt64 - شֵ -} - -function Int32ToLittleEndian(Value: Integer): Integer; -{* ȷ 32 λзֵΪСˣڴ˻лת - - - Value: Integer - ת 32 λз - - ֵInteger - Сֵ -} - -function Int16ToLittleEndian(Value: SmallInt): SmallInt; -{* ȷ 16 λзֵΪСˣڴ˻лת - - - Value: SmallInt - ת 16 λз - - ֵSmallInt - Сֵ -} - -function UInt64ToBigEndian(Value: TUInt64): TUInt64; -{* ȷ 64 λ޷ֵΪˣС˻лת - - - Value: TUInt64 - ת 64 λ޷ - - ֵTUInt64 - شֵ -} - -function UInt32ToBigEndian(Value: Cardinal): Cardinal; -{* ȷ 32 λ޷ֵΪˣС˻лת - - - Value: Cardinal - ת 32 λ޷ - - ֵCardinal - شֵ -} - -function UInt16ToBigEndian(Value: Word): Word; -{* ȷ 16 λ޷ֵΪˣС˻лת - - - Value: Word - ת 16 λ޷ - - ֵWord - شֵ -} - -function UInt64ToLittleEndian(Value: TUInt64): TUInt64; -{* ȷ 64 λ޷ֵΪСˣڴ˻лת - - - Value: TUInt64 - ת 64 λ޷ - - ֵTUInt64 - شֵ -} - -function UInt32ToLittleEndian(Value: Cardinal): Cardinal; -{* ȷ 32 λ޷ֵΪСˣڴ˻лת - - - Value: Cardinal - ת 32 λ޷ - - ֵCardinal - Сֵ -} - -function UInt16ToLittleEndian(Value: Word): Word; -{* ȷ 16 λ޷ֵΪСˣڴ˻лת - - - Value: Word - ת 16 λ޷ - - ֵWord - Сֵ -} - -function Int64HostToNetwork(Value: Int64): Int64; -{* 64 λзֵֽ˳תΪֽ˳С˻лת - - - Value: Int64 - ת 64 λз - - ֵInt64 - ֽ˳ֵ -} - -function Int32HostToNetwork(Value: Integer): Integer; -{* 32 λзֵֽ˳תΪֽ˳С˻лת - - - Value: Integer - ת 32 λз - - ֵInteger - ֽ˳ֵ -} - -function Int16HostToNetwork(Value: SmallInt): SmallInt; -{* 16 λзֵֽ˳תΪֽ˳С˻лת - - - Value: SmallInt - ת 16 λз - - ֵSmallInt - ֽ˳ֵ -} - -function Int64NetworkToHost(Value: Int64): Int64; -{* 64 λзֵֽ˳תΪֽ˳С˻лת - - - Value: Int64 - ת 64 λз - - ֵInt64 - ֽ˳ֵ -} - -function Int32NetworkToHost(Value: Integer): Integer; -{* 32 λзֵֽ˳תΪֽ˳С˻лת - - - Value: Integer - ת 32 λз - - ֵInteger - ֽ˳ֵ -} - -function Int16NetworkToHost(Value: SmallInt): SmallInt; -{* 16 λзֵֽ˳תΪֽ˳С˻лת - - - Value: SmallInt - ת 16 λз - - ֵSmallInt - ֽ˳ֵ -} - -function UInt64HostToNetwork(Value: TUInt64): TUInt64; -{* 64 λ޷ֵֽ˳תΪֽ˳С˻лת - - - Value: TUInt64 - ת 64 λ޷ - - ֵTUInt64 - ֽ˳ֵ -} - -function UInt32HostToNetwork(Value: Cardinal): Cardinal; -{* 32 λ޷ֵֽ˳תΪֽ˳С˻лת - - - Value: Cardinal - ת 32 λ޷ - - ֵCardinal - ֽ˳ֵ -} - -function UInt16HostToNetwork(Value: Word): Word; -{* 16 λ޷ֵֽ˳תΪֽ˳С˻лת - - - Value: Word - ת 16 λ޷ - - ֵWord - ֽ˳ֵ -} - -function UInt64NetworkToHost(Value: TUInt64): TUInt64; -{* 64 λ޷ֵֽ˳תΪֽ˳С˻лת - - - Value: TUInt64 - ת 64 λ޷ - - ֵTUInt64 - ֽ˳ֵ -} - -function UInt32NetworkToHost(Value: Cardinal): Cardinal; -{* 32 λ޷ֵֽ˳תΪֽ˳С˻лת - - - Value: Cardinal - ת 32 λ޷ - - ֵCardinal - ֽ˳ֵ -} - -function UInt16NetworkToHost(Value: Word): Word; -{* 16 λ޷ֵֽ˳תΪֽ˳С˻лת - - - Value: Word - ת 16 λ޷ - - ֵWord - ֽ˳ֵ -} - -procedure MemoryNetworkToHost(Mem: Pointer; MemByteLen: Integer); -{* һƬڴֽ˳תΪֽ˳С˻лת - ÷ӦóϽ٣¶ġֽתѾ㹻 - - - Mem: Pointer - תݿַ - MemByteLen: Integer - תݿֽڳ - - ֵޣ -} - -procedure MemoryHostToNetwork(Mem: Pointer; MemByteLen: Integer); -{* һƬڴֽ˳תΪֽ˳С˻лת - ÷ӦóϽ٣¶ġֽתѾ㹻 - - - Mem: Pointer - תݿַ - MemByteLen: Integer - תݿֽڳ - - ֵޣ -} - -procedure ReverseMemory(Mem: Pointer; MemByteLen: Integer); -{* ֽ˳һڴ飬ֽڲ䡣 - - - Mem: Pointer - õݿַ - MemByteLen: Integer - õݿֽڳ - - ֵޣ -} - -function ReverseBitsInInt8(V: Byte): Byte; -{* һֽڲλݡ - - - V: Byte - õһֽ - - ֵByte - صֵ -} - -function ReverseBitsInInt16(V: Word): Word; -{* öֽڼڲλݡ - - - V: Word - õĶֽ - - ֵWord - صֵ -} - -function ReverseBitsInInt32(V: Cardinal): Cardinal; -{* ֽڼڲλݡ - - - V: Cardinal - õֽ - - ֵCardinal - صֵ -} - -function ReverseBitsInInt64(V: Int64): Int64; -{* ðֽڼڲλݡ - - - V: Int64 - õİֽ - - ֵInt64 - صֵ -} - -procedure ReverseMemoryWithBits(Mem: Pointer; MemByteLen: Integer); -{* ֽ˳һڴ飬ÿֽҲ - - - Mem: Pointer - õݿַ - MemByteLen: Integer - õݿֽڳ - - ֵޣ -} - -procedure MemoryAnd(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); -{* 鳤ͬڴ AMem BMem λ룬 ResMem У߿ͬ - - - AMem: Pointer - ݿַһ - BMem: Pointer - ݿַ - MemByteLen: Integer - ݿֽڳ - ResMem: Pointer - ݿַ - - ֵޣ -} - -procedure MemoryOr(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); -{* 鳤ͬڴ AMem BMem λ򣬽 ResMem У߿ͬ - - - AMem: Pointer - ݿַһ - BMem: Pointer - ݿַ - MemByteLen: Integer - ݿֽڳ - ResMem: Pointer - ݿַ - - ֵޣ -} - -procedure MemoryXor(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); -{* 鳤ͬڴ AMem BMem λ򣬽 ResMem У߿ͬ - - - AMem: Pointer - ݿַһ - BMem: Pointer - ݿַ - MemByteLen: Integer - ݿֽڳ - ResMem: Pointer - ݿַ - - ֵޣ -} - -procedure MemoryNot(Mem: Pointer; MemByteLen: Integer; ResMem: Pointer); -{* һڴ AMem ȡ ResMem У߿ͬ - - - Mem: Pointer - ݿַ - MemByteLen: Integer - ݿֽڳ - ResMem: Pointer - ݿַ - - ֵޣ -} - -procedure MemoryShiftLeft(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; BitCount: Integer); -{* AMem ڴ BitCount λ BMemڴַλƣλ 0߿ȡ - - - AMem: Pointer - ݿַһ - BMem: Pointer - ݿַ - MemByteLen: Integer - ݿֽڳ - BitCount: Integer - Ƶλ - - ֵޣ -} - -procedure MemoryShiftRight(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; BitCount: Integer); -{* AMem ڴ BitCount λ BMemڴַλƣλ 0߿ȡ - - - AMem: Pointer - ݿַһ - BMem: Pointer - ݿַ - MemByteLen: Integer - ݿֽڳ - BitCount: Integer - Ƶλ - - ֵޣ -} - -function MemoryIsBitSet(Mem: Pointer; N: Integer): Boolean; -{* ڴij Bit λǷ 1ڴַλ 0ֽڻұΪ 0 - - - Mem: Pointer - ݿַ - N: Integer - λ - - ֵBoolean - Ƿ 1 -} - -procedure MemorySetBit(Mem: Pointer; N: Integer); -{* ڴij Bit λ 1ڴַλ 0ֽڻұΪ 0 - - - Mem: Pointer - ݿַ - N: Integer - λ - - ֵޣ -} - -procedure MemoryClearBit(Mem: Pointer; N: Integer); -{* ڴij Bit λ 0ڴַλ 0ֽڻұΪ 0 - - - Mem: Pointer - ݿַ - N: Integer - λ - - ֵޣ -} - -function MemoryToBinStr(Mem: Pointer; MemByteLen: Integer; Sep: Boolean = False): string; -{* һڴݴӵ͵ֽ˳ΪַSep ʾֽ֮Ƿոָ - - - Mem: Pointer - ݿַ - MemByteLen: Integer - ݿֽڳ - Sep: Boolean - ֽ֮Ƿÿոָ - - ֵstring - ضַ -} - -procedure MemorySwap(AMem: Pointer; BMem: Pointer; MemByteLen: Integer); -{* ͬȵڴݣͬڴʲô - - - AMem: Pointer - ݿַһ - BMem: Pointer - ݿַ - MemByteLen: Integer - ݿֽڳ - - ֵޣ -} - -function MemoryCompare(AMem: Pointer; BMem: Pointer; MemByteLen: Integer): Integer; -{* ޷ķʽȽڴ棬 10-1ͬڴֱӷ 0 - - - AMem: Pointer - Ƚϵݿַһ - BMem: Pointer - Ƚϵݿַ - MemByteLen: Integer - Ƚϵݿֽڳ - - ֵInteger - رȽϵĽ -} - -procedure MemoryQuickSort(Mem: Pointer; ElementByteSize: Integer; - ElementCount: Integer; CompareProc: TCnMemSortCompareProc = nil); -{* Թ̶СԪص - - - Mem: Pointer - ݿַ - ElementByteSize: Integer - Ԫֽڳ - ElementCount: Integer - ݿԪصĸ - CompareProc: TCnMemSortCompareProc - ԪرȽϵĻص - - ֵޣ -} - -function UInt8ToBinStr(V: Byte): string; -{* һ 8 λ޷תΪַ - - - V: Byte - ת 8 λ޷ - - ֵstring - ضַ -} - -function UInt16ToBinStr(V: Word): string; -{* һ 16 λ޷תΪַ - - - V: Word - ת 16 λ޷ - - ֵstring - ضַ -} - -function UInt32ToBinStr(V: Cardinal): string; -{* һ 32 λ޷תΪַ - - - V: Cardinal - ת 32 λ޷ - - ֵstring - ضַ -} - -function UInt32ToStr(V: Cardinal): string; -{* һ 32 λ޷תΪʮַ - - - V: Cardinal - ת 32 λ޷ - - ֵstring - ʮַ -} - -function UInt64ToBinStr(V: TUInt64): string; -{* һ 64 λ޷תΪַ - - - V: TUInt64 - ת 64 λ޷ - - ֵstring - ضַ -} - -function HexToInt(const Hex: string): Integer; overload; -{* һʮַתΪͣʺϽ϶ 2 ַַ - - - const Hex: string - תʮַ - - ֵInteger - -} - -function HexToInt(Hex: PChar; CharLen: Integer): Integer; overload; -{* һʮַָָתΪͣʺϽ϶ 2 ַַ - - - Hex: PChar - תʮַַ - CharLen: Integer - ַ - - ֵInteger - -} - -function IsHexString(const Hex: string): Boolean; -{* жһַǷϷʮִַСд - - - const Hex: string - жϵʮַ - - ֵBoolean - ǷǺϷʮַ -} - -function DataToHex(InData: Pointer; ByteLength: Integer; UseUpperCase: Boolean = True): string; -{* ڴתΪʮַڴλݳַ󷽣൱ֽ˳ - UseUpperCase ݵĴСд - - - InData: Pointer - תݿַ - ByteLength: Integer - תݿֽڳ - UseUpperCase: Boolean - ʮַڲǷд - - ֵstring - ʮַ -} - -function HexToData(const Hex: string; OutData: Pointer = nil): Integer; -{* ʮַתΪڴ飬ַ󷽵ݳڴλ൱ֽ˳ - ʮַΪתʧʱ׳쳣תɹֽ - ע OutData Ӧָ㹻תݵֽڳΪ Length(Hex) div 2 - nilֻֽڳȣʽת - - - const Hex: string - תʮַ - OutData: Pointer - ֽڳӦΪ Length(Hex) div 2 - - ֵInteger - תֽڳ -} - -function StringToHex(const Data: string; UseUpperCase: Boolean = True): string; -{* ַתΪʮַUseUpperCase ݵĴСд - - - const Data: string - תַ - UseUpperCase: Boolean - ʮַڲǷд - - ֵstring - תʮַ -} - -function HexToString(const Hex: string): string; -{* ʮַתΪַʮַΪתʧʱ׳쳣 - - - const Hex: string - תʮַ - - ֵstring - תַ -} - -function HexToAnsiStr(const Hex: AnsiString): AnsiString; -{* ʮַתΪַʮַΪתʧʱ׳쳣 - - - const Hex: AnsiString - תʮַ - - ֵAnsiString - תַ -} - -function AnsiStrToHex(const Data: AnsiString; UseUpperCase: Boolean = True): AnsiString; -{* AnsiString תΪʮַUseUpperCase ݵĴСд - - - const Data: AnsiString - תַ - UseUpperCase: Boolean - ʮַڲǷд - - ֵAnsiString - ʮַ -} - -function BytesToHex(Data: TBytes; UseUpperCase: Boolean = True): string; -{* ֽתΪʮַ±λݳַ󷽣൱ֽ˳ - UseUpperCase ݵĴСд - - - Data: TBytes - תֽ - UseUpperCase: Boolean - ʮַڲǷд - - ֵstring - ʮַ -} - -function HexToBytes(const Hex: string): TBytes; -{* ʮַתΪֽ飬ַߵݳ±λ൱ֽ˳ - ַΪתʧʱ׳쳣 - - - const Hex: string - תʮַ - - ֵTBytes - ½ֽ -} - -function StreamToHex(Stream: TStream; UseUpperCase: Boolean = True): string; -{* еȫݴͷתΪʮַ - - - Stream: TStream - - UseUpperCase: Boolean - ʮַڲǷд - - ֵstring - ʮַ -} - -function HexToStream(const Hex: string; Stream: TStream): Integer; -{* ʮַתдУдֽ - - - const Hex: string - תʮַ - Stream: TStream - д - - ֵInteger - дֽ -} - -procedure ReverseBytes(Data: TBytes); -{* ֽ˳һֽ顣 - - - Data: TBytes - õֽ - - ֵޣ -} - -function CloneBytes(Data: TBytes): TBytes; -{* һµֽ - - - Data: TBytes - Ƶֽ - - ֵTBytes - ½ֽ -} - -function StreamToBytes(Stream: TStream): TBytes; -{* ͷȫֽ飬½ֽ顣 - - - Stream: TStream - - - ֵTBytes - ½ֽ -} - -function BytesToStream(Data: TBytes; OutStream: TStream): Integer; -{* ֽдԭʼдֽ - - - Data: TBytes - дֽ - OutStream: TStream - д - - ֵInteger - дֽ -} - -function AnsiToBytes(const Str: AnsiString): TBytes; -{* AnsiString ֱתΪֽ飬롣 - - - const Str: AnsiString - תַ - - ֵTBytes - תֽ -} - -function BytesToAnsi(Data: TBytes): AnsiString; -{* ֱֽתΪ AnsiString롣 - - - Data: TBytes - תֽ - - ֵAnsiString - תַ -} - -function BytesToString(Data: TBytes): string; -{* ֽתΪ stringڲ Byte ֵΪ Char롣 - - - Data: TBytes - תֽ - - ֵstring - תַ -} - -function MemoryToString(Mem: Pointer; MemByteLen: Integer): string; -{* ڴתΪ stringڲֽڸֵ롣 - - - Mem: Pointer - תݿַ - MemByteLen: Integer - תݿֽڳ - - ֵstring - תַ -} - -function BitsToString(Bits: TBits): string; -{* λתΪ 0 1 ַ - - - Bits: TBits - תλ - - ֵstring - תַ -} - -function ConcatBytes(A: TBytes; B: TBytes): TBytes; -{* A B ֽ˳ƴ÷һֽ飬A B ֲ䡣 - - - A: TBytes - ƴӵֽһ - B: TBytes - ƴӵֽ - - ֵTBytes - ƴӵֽ -} - -function NewBytesFromMemory(Data: Pointer; DataByteLen: Integer): TBytes; -{* ½һֽ飬һƬڴݹ - - - Data: Pointer - ݿַ - DataByteLen: Integer - ݿֽڳ - - ֵTBytes - ½ֽ -} - -function CompareBytes(A: TBytes; B: TBytes): Boolean; overload; -{* ȽֽǷͬ - - - A: TBytes - Ƚϵֽһ - B: TBytes - Ƚϵֽ - - ֵBoolean - رȽϽǷͬ -} - -function CompareBytes(A: TBytes; B: TBytes; MaxLength: Integer): Boolean; overload; -{* Ƚֽǰ MaxLength ֽڵǷͬ - - - A: TBytes - Ƚϵֽһ - B: TBytes - Ƚϵֽ - MaxLength: Integer - Ƚϵֽ - - ֵBoolean - رȽϽǷͬ -} - -function MoveMost(const Source; var Dest; ByteLen: Integer; MostLen: Integer): Integer; -{* Source ƶ ByteLen Ҳ MostLen ֽڵ Dest Уʵƶֽ - ByteLen С MostLen Dest 0Ҫ Dest MostLen - - - const Source - ƶԴλáַ - var Dest - ƶĿλáַҪ MostLen ֽ - ByteLen: Integer - ƶֽ - MostLen: Integer - ƶֽ - - ֵInteger - ʵƶֽ -} - -// =============================== =================================== - -function SarInt8(var V: Byte; ShiftCount: Integer): Byte; -{* һ 8 λƣҲDZλơ - - - var V: Byte - Ƶ 8 λ - ShiftCount: Integer - Ƶλ - - ֵByte - λֵ -} - -function SarInt16(var V: Word; ShiftCount: Integer): Word; -{* һ 16 λƣҲDZλơ - - - var V: Word - Ƶ 16 λ - ShiftCount: Integer - Ƶλ - - ֵWord - λֵ -} - -function SarInt32(var V: Cardinal; ShiftCount: Integer): Cardinal; -{* һ 32 λƣҲDZλơ - - - var V: Cardinal - Ƶ 32 λ - ShiftCount: Integer - Ƶλ - - ֵCardinal - λֵ -} - -function SarInt64(var V: TUInt64; ShiftCount: Integer): TUInt64; -{* һ 64 λƣҲDZλơ - - - var V: TUInt64 - Ƶ 64 λ - ShiftCount: Integer - Ƶλ - - ֵTUInt64 - λֵ -} - -// ================ ִʱ̶ if жϵIJ߼ =============== - -procedure ConstTimeConditionalSwap8(CanSwap: Boolean; var A: Byte; var B: Byte); -{* 8 λͱִʱ̶CanSwap Ϊ True ʱʵʩ A B - - - CanSwap: Boolean - Ƿ񽻻 - var A: Byte - 8 λͱһ - var B: Byte - 8 λͱ - - ֵޣ -} - -procedure ConstTimeConditionalSwap16(CanSwap: Boolean; var A: Word; var B: Word); -{* 16 λͱִʱ̶CanSwap Ϊ True ʱʵʩ A B - - - CanSwap: Boolean - Ƿ񽻻 - var A: Word - 16 λͱһ - var B: Word - 16 λͱ - - ֵޣ -} - -procedure ConstTimeConditionalSwap32(CanSwap: Boolean; var A: Cardinal; var B: Cardinal); -{* 32 λͱִʱ̶CanSwap Ϊ True ʱʵʩ A B - - - CanSwap: Boolean - Ƿ񽻻 - var A: Cardinal - 32 λͱһ - var B: Cardinal - 32 λͱ - - ֵޣ -} - -procedure ConstTimeConditionalSwap64(CanSwap: Boolean; var A: TUInt64; var B: TUInt64); -{* 64 λͱִʱ̶CanSwap Ϊ True ʱʵʩ A B - - - CanSwap: Boolean - Ƿ񽻻 - var A: TUInt64 - 64 λͱһ - var B: TUInt64 - 64 λͱ - - ֵޣ -} - -function ConstTimeEqual8(A: Byte; B: Byte): Boolean; -{* ֽڵִʱ̶ıȽϣ CPU ָתԤ⵼µִʱ죬ͬʱ True - - - A: Byte - Ƚϵ 8 λͱһ - B: Byte - Ƚϵ 8 λͱ - - ֵBoolean - Ƿ -} - -function ConstTimeEqual16(A: Word; B: Word): Boolean; -{* ˫ֽڵִʱ̶ıȽϣ CPU ָתԤ⵼µִʱ죬ͬʱ True - - - A: Word - Ƚϵ 16 λͱһ - B: Word - Ƚϵ 16 λͱ - - ֵBoolean - Ƿ -} - -function ConstTimeEqual32(A: Cardinal; B: Cardinal): Boolean; -{* ֽڵִʱ̶ıȽϣ CPU ָתԤ⵼µִʱ죬ͬʱ True - - - A: Cardinal - Ƚϵ 32 λͱһ - B: Cardinal - Ƚϵ 32 λͱ - - ֵBoolean - Ƿ -} - -function ConstTimeEqual64(A: TUInt64; B: TUInt64): Boolean; -{* ֽڵִʱ̶ıȽϣ CPU ָתԤ⵼µִʱ죬ͬʱ True - - - A: TUInt64 - Ƚϵ 64 λͱһ - B: TUInt64 - Ƚϵ 64 λͱ - - ֵBoolean - Ƿ -} - -function ConstTimeBytesEqual(A: TBytes; B: TBytes): Boolean; -{* ͬȵִֽʱ̶ıȽϣͬʱ True - - - A: TBytes - Ƚϵֽһ - B: TBytes - Ƚϵֽ - - ֵBoolean - Ƿ -} - -function ConstTimeExpandBoolean8(V: Boolean): Byte; -{* V ֵ 8 λȫ 1 ȫ 0 - - - V: Boolean - Ƿ񷵻ȫ 1 - - ֵByte - $FF 0 -} - -function ConstTimeExpandBoolean16(V: Boolean): Word; -{* V ֵ 16 λȫ 1 ȫ 0 - - - V: Boolean - Ƿ񷵻ȫ 1 - - ֵWord - $FFFF 0 -} - -function ConstTimeExpandBoolean32(V: Boolean): Cardinal; -{* V ֵ 32 λȫ 1 ȫ 0 - - - V: Boolean - Ƿ񷵻ȫ 1 - - ֵCardinal - $FFFFFFFF 0 -} - -function ConstTimeExpandBoolean64(V: Boolean): TUInt64; -{* V ֵ 64 λȫ 1 ȫ 0 - - - V: Boolean - Ƿ񷵻ȫ 1 - - ֵTUInt64 - $FFFFFFFFFFFFFFFF 0 -} - -function ConstTimeConditionalSelect8(Condition: Boolean; A: Byte; B: Byte): Byte; -{* ֽڱִʱ̶жѡCondtion Ϊ True ʱ A򷵻 B - - - Condition: Boolean - Ƿѡ A ҲDzһ - A: Byte - ѡ 8 λһ - B: Byte - ѡ 8 λ - - ֵByte - ѡ 8 λ -} - -function ConstTimeConditionalSelect16(Condition: Boolean; A: Word; B: Word): Word; -{* ˫ֽڱִʱ̶жѡCondtion Ϊ True ʱ A򷵻 B - - - Condition: Boolean - Ƿѡ A ҲDzһ - A: Word - ѡ 16 λһ - B: Word - ѡ 16 λ - - ֵWord - ѡ 16 λ -} - -function ConstTimeConditionalSelect32(Condition: Boolean; A: Cardinal; B: Cardinal): Cardinal; -{* ֽڱִʱ̶жѡCondtion Ϊ True ʱ A򷵻 B - - - Condition: Boolean - Ƿѡ A ҲDzһ - A: Cardinal - ѡ 32 λһ - B: Cardinal - ѡ 32 λ - - ֵCardinal - ѡ 32 λ -} - -function ConstTimeConditionalSelect64(Condition: Boolean; A: TUInt64; B: TUInt64): TUInt64; -{* ֽڱִʱ̶жѡCondtion Ϊ True ʱ A򷵻 B - - - Condition: Boolean - Ƿѡ A ҲDzһ - A: TUInt64 - ѡ 64 λһ - B: TUInt64 - ѡ 64 λ - - ֵTUInt64 - ѡ 64 λ -} - -// ================ ִʱ̶ if жϵIJ߼ =============== - -{$IFDEF MSWINDOWS} - -// ĸΪ Intel ֻ֧࣬ 32 λ 64 λ Intel CPUӦCPUX86 CPUX64 - -procedure Int64DivInt32Mod(A: Int64; B: Integer; - var DivRes: Integer; var ModRes: Integer); -{* 64 λз 32 λз̷ DivRes ModRes - б֤ 32 λΧڣ쳣 - - - A: Int64 - - B: Integer - - var DivRes: Integer - - var ModRes: Integer - - - ֵޣ -} - -procedure UInt64DivUInt32Mod(A: TUInt64; B: Cardinal; - var DivRes: Cardinal; var ModRes: Cardinal); -{* 64 λ޷ 32 λ޷̷ DivRes ModRes - б֤ 32 λΧڣ쳣 - - - A: TUInt64 - - B: Cardinal - - var DivRes: Cardinal - - var ModRes: Cardinal - - - ֵޣ -} - -procedure Int128DivInt64Mod(ALo: Int64; AHi: Int64; B: Int64; - var DivRes: Int64; var ModRes: Int64); -{* 128 λз 64 λз̷ DivRes ModRes - б֤ 64 λΧڣ쳣 - - - ALo: Int64 - 64 λ - AHi: Int64 - 64 λ - B: Int64 - - var DivRes: Int64 - - var ModRes: Int64 - - - ֵޣ -} - -procedure UInt128DivUInt64Mod(ALo: TUInt64; AHi: TUInt64; B: TUInt64; - var DivRes: TUInt64; var ModRes: TUInt64); -{* 128 λ޷ 64 λ޷̷ DivRes ModRes - б֤ 64 λΧڣ쳣 - - - ALo: TUInt64 - 64 λ - AHi: TUInt64 - 64 λ - B: TUInt64 - - var DivRes: TUInt64 - - var ModRes: TUInt64 - - - ֵޣ -} - -{$ENDIF} - -function IsUInt128BitSet(Lo: TUInt64; Hi: TUInt64; N: Integer): Boolean; -{* Int64 ƴɵ 128 λ֣ص N λǷΪ 1N 0 127 - - - Lo: TUInt64 - жϵĵ 64 λ - Hi: TUInt64 - жϵĸ 64 λ - N: Integer - жϵλ - - ֵBoolean - ǷΪ 1 -} - -procedure SetUInt128Bit(var Lo: TUInt64; var Hi: TUInt64; N: Integer); -{* Int64 ƴɵ 128 λ֣õ N λΪ 1N 0 127 - - - var Lo: TUInt64 - õĵ 64 λ - var Hi: TUInt64 - õĸ 64 λ - N: Integer - õλ - - ֵޣ -} - -procedure ClearUInt128Bit(var Lo: TUInt64; var Hi: TUInt64; N: Integer); -{* Int64 ƴɵ 128 λ֣ N λN 0 127 - - - var Lo: TUInt64 - õĵ 64 λ - var Hi: TUInt64 - õĸ 64 λ - N: Integer - õλ - - ֵޣ -} - -function UnsignedAddWithLimitRadix(A: Cardinal; B: Cardinal; C: Cardinal; - var R: Cardinal; L: Cardinal; H: Cardinal): Cardinal; -{* Ƶ޷żӷA + B + C R Уؽλֵ - ȷ L H ıڣûȷ H LΡ - úַӳ䣬 C һǽλ - - - A: Cardinal - һ - B: Cardinal - - C: Cardinal - һǽλ - var R: Cardinal - - L: Cardinal - ͵ - H: Cardinal - ͵ - - ֵCardinal - Ƿнλ -} - -// =========================== ѭλ ==================================== - -// ע N Ӧ (0, A λ) ڣ N Ϊ 0 A λʱֵӦΪ A -// N ʱࣨΪͲȲͬ 32 λ AN Ϊ 33 ʱֵ N Ϊ 1 ʱķֵ - -function RotateLeft16(A: Word; N: Integer): Word; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -{* 16 λѭ N λ - - - A: Word - ѭƵ 16 λ - N: Integer - ѭƵλ - - ֵWord - λֵ -} - -function RotateRight16(A: Word; N: Integer): Word; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -{* 16 λѭ N λ - - - A: Word - ѭƵ 16 λ - N: Integer - ѭƵλ - - ֵWord - λֵ -} - -function RotateLeft32(A: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -{* 32 λѭ N λ - - - A: Cardinal - ѭƵ 32 λ - N: Integer - ѭƵλ - - ֵCardinal - λֵ -} - -function RotateRight32(A: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -{* 32 λѭ N λ - - - A: Cardinal - ѭƵ 32 λ - N: Integer - ѭƵλ - - ֵCardinal - λֵ -} - -function RotateLeft64(A: TUInt64; N: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -{* 64 λѭ N λ - - - A: TUInt64 - ѭƵ 64 λ - N: Integer - ѭƵλ - - ֵTUInt64 - λֵ -} - -function RotateRight64(A: TUInt64; N: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -{* 64 λѭ N λ - - - A: TUInt64 - ѭƵ 64 λ - N: Integer - ѭƵλ - - ֵTUInt64 - λֵ -} - -{$IFDEF COMPILER5} - -function BoolToStr(Value: Boolean; UseBoolStrs: Boolean = False): string; -{* תΪַDelphi 5 ûи BoolToStr ϡ - - - Value: Boolean - תIJֵ - UseBoolStrs: Boolean - Ƿ񷵻Ӣĵ - - ֵstring - UseBoolStrs Ϊ False ʱ -1 0򷵻 True False -} - -{$ENDIF} - -implementation - -uses - CnFloat; - -resourcestring - SCnErrorNotAHexPChar = 'Error: NOT a Hex PChar: %c'; - SCnErrorLengthNotHex = 'Error Length %d: NOT a Hex String'; - SCnErrorLengthNotHexAnsi = 'Error Length %d: NOT a Hex AnsiString'; - -var - FByteOrderIsBigEndian: Boolean = False; - -function CurrentByteOrderIsBigEndian: Boolean; -type - TByteOrder = packed record - case Boolean of - False: (C: array[0..1] of Byte); - True: (W: Word); - end; -var - T: TByteOrder; -begin - T.W := $00CC; - Result := T.C[1] = $CC; -end; - -function CurrentByteOrderIsLittleEndian: Boolean; -begin - Result := not CurrentByteOrderIsBigEndian; -end; - -function ReverseInt64(Value: Int64): Int64; -var - Lo, Hi: Cardinal; - Rec: Int64Rec; -begin - Lo := Int64Rec(Value).Lo; - Hi := Int64Rec(Value).Hi; - Lo := ((Lo and $000000FF) shl 24) or ((Lo and $0000FF00) shl 8) - or ((Lo and $00FF0000) shr 8) or ((Lo and $FF000000) shr 24); - Hi := ((Hi and $000000FF) shl 24) or ((Hi and $0000FF00) shl 8) - or ((Hi and $00FF0000) shr 8) or ((Hi and $FF000000) shr 24); - Rec.Lo := Hi; - Rec.Hi := Lo; - Result := Int64(Rec); -end; - -function ReverseUInt64(Value: TUInt64): TUInt64; -var - Lo, Hi: Cardinal; - Rec: Int64Rec; -begin - Lo := Int64Rec(Value).Lo; - Hi := Int64Rec(Value).Hi; - Lo := ((Lo and $000000FF) shl 24) or ((Lo and $0000FF00) shl 8) - or ((Lo and $00FF0000) shr 8) or ((Lo and $FF000000) shr 24); - Hi := ((Hi and $000000FF) shl 24) or ((Hi and $0000FF00) shl 8) - or ((Hi and $00FF0000) shr 8) or ((Hi and $FF000000) shr 24); - Rec.Lo := Hi; - Rec.Hi := Lo; - Result := TUInt64(Rec); -end; - -function Int64ToBigEndian(Value: Int64): Int64; -begin - if FByteOrderIsBigEndian then - Result := Value - else - Result := ReverseInt64(Value); -end; - -function Int32ToBigEndian(Value: Integer): Integer; -begin - if FByteOrderIsBigEndian then - Result := Value - else - Result := Integer((Value and $000000FF) shl 24) or Integer((Value and $0000FF00) shl 8) - or Integer((Value and $00FF0000) shr 8) or Integer((Value and $FF000000) shr 24); -end; - -function Int16ToBigEndian(Value: SmallInt): SmallInt; -begin - if FByteOrderIsBigEndian then - Result := Value - else - Result := SmallInt((Value and $00FF) shl 8) or SmallInt((Value and $FF00) shr 8); -end; - -function Int64ToLittleEndian(Value: Int64): Int64; -begin - if not FByteOrderIsBigEndian then - Result := Value - else - Result := ReverseInt64(Value); -end; - -function Int32ToLittleEndian(Value: Integer): Integer; -begin - if not FByteOrderIsBigEndian then - Result := Value - else - Result := Integer((Value and $000000FF) shl 24) or Integer((Value and $0000FF00) shl 8) - or Integer((Value and $00FF0000) shr 8) or Integer((Value and $FF000000) shr 24); -end; - -function Int16ToLittleEndian(Value: SmallInt): SmallInt; -begin - if not FByteOrderIsBigEndian then - Result := Value - else - Result := SmallInt((Value and $00FF) shl 8) or SmallInt((Value and $FF00) shr 8); -end; - -function UInt64ToBigEndian(Value: TUInt64): TUInt64; -begin - if FByteOrderIsBigEndian then - Result := Value - else - Result := ReverseUInt64(Value); -end; - -function UInt32ToBigEndian(Value: Cardinal): Cardinal; -begin - if FByteOrderIsBigEndian then - Result := Value - else - Result := Cardinal((Value and $000000FF) shl 24) or Cardinal((Value and $0000FF00) shl 8) - or Cardinal((Value and $00FF0000) shr 8) or Cardinal((Value and $FF000000) shr 24); -end; - -function UInt16ToBigEndian(Value: Word): Word; -begin - if FByteOrderIsBigEndian then - Result := Value - else - Result := Word((Value and $00FF) shl 8) or Word((Value and $FF00) shr 8); -end; - -function UInt64ToLittleEndian(Value: TUInt64): TUInt64; -begin - if not FByteOrderIsBigEndian then - Result := Value - else - Result := ReverseUInt64(Value); -end; - -function UInt32ToLittleEndian(Value: Cardinal): Cardinal; -begin - if not FByteOrderIsBigEndian then - Result := Value - else - Result := Cardinal((Value and $000000FF) shl 24) or Cardinal((Value and $0000FF00) shl 8) - or Cardinal((Value and $00FF0000) shr 8) or Cardinal((Value and $FF000000) shr 24); -end; - -function UInt16ToLittleEndian(Value: Word): Word; -begin - if not FByteOrderIsBigEndian then - Result := Value - else - Result := Word((Value and $00FF) shl 8) or Word((Value and $FF00) shr 8); -end; - -function Int64HostToNetwork(Value: Int64): Int64; -begin - if not FByteOrderIsBigEndian then - Result := ReverseInt64(Value) - else - Result := Value; -end; - -function Int32HostToNetwork(Value: Integer): Integer; -begin - if not FByteOrderIsBigEndian then - Result := Integer((Value and $000000FF) shl 24) or Integer((Value and $0000FF00) shl 8) - or Integer((Value and $00FF0000) shr 8) or Integer((Value and $FF000000) shr 24) - else - Result := Value; -end; - -function Int16HostToNetwork(Value: SmallInt): SmallInt; -begin - if not FByteOrderIsBigEndian then - Result := SmallInt((Value and $00FF) shl 8) or SmallInt((Value and $FF00) shr 8) - else - Result := Value; -end; - -function Int64NetworkToHost(Value: Int64): Int64; -begin - if not FByteOrderIsBigEndian then - REsult := ReverseInt64(Value) - else - Result := Value; -end; - -function Int32NetworkToHost(Value: Integer): Integer; -begin - if not FByteOrderIsBigEndian then - Result := Integer((Value and $000000FF) shl 24) or Integer((Value and $0000FF00) shl 8) - or Integer((Value and $00FF0000) shr 8) or Integer((Value and $FF000000) shr 24) - else - Result := Value; -end; - -function Int16NetworkToHost(Value: SmallInt): SmallInt; -begin - if not FByteOrderIsBigEndian then - Result := SmallInt((Value and $00FF) shl 8) or SmallInt((Value and $FF00) shr 8) - else - Result := Value; -end; - -function UInt64HostToNetwork(Value: TUInt64): TUInt64; -begin - if CurrentByteOrderIsBigEndian then - Result := Value - else - Result := ReverseUInt64(Value); -end; - -function UInt32HostToNetwork(Value: Cardinal): Cardinal; -begin - if not FByteOrderIsBigEndian then - Result := Cardinal((Value and $000000FF) shl 24) or Cardinal((Value and $0000FF00) shl 8) - or Cardinal((Value and $00FF0000) shr 8) or Cardinal((Value and $FF000000) shr 24) - else - Result := Value; -end; - -function UInt16HostToNetwork(Value: Word): Word; -begin - if not FByteOrderIsBigEndian then - Result := ((Value and $00FF) shl 8) or ((Value and $FF00) shr 8) - else - Result := Value; -end; - -function UInt64NetworkToHost(Value: TUInt64): TUInt64; -begin - if CurrentByteOrderIsBigEndian then - Result := Value - else - Result := ReverseUInt64(Value); -end; - -function UInt32NetworkToHost(Value: Cardinal): Cardinal; -begin - if not FByteOrderIsBigEndian then - Result := Cardinal((Value and $000000FF) shl 24) or Cardinal((Value and $0000FF00) shl 8) - or Cardinal((Value and $00FF0000) shr 8) or Cardinal((Value and $FF000000) shr 24) - else - Result := Value; -end; - -function UInt16NetworkToHost(Value: Word): Word; -begin - if not FByteOrderIsBigEndian then - Result := ((Value and $00FF) shl 8) or ((Value and $FF00) shr 8) - else - Result := Value; -end; - -function ReverseBitsInInt8(V: Byte): Byte; -begin - // 0 1 2 3 4 5 6 7 - V := ((V and $AA) shr 1) or ((V and $55) shl 1); - // 01 23 45 67 - V := ((V and $CC) shr 2) or ((V and $33) shl 2); - // 0123 4567 - V := (V shr 4) or (V shl 4); - Result := V; -end; - -function ReverseBitsInInt16(V: Word): Word; -begin - Result := (ReverseBitsInInt8(V and $00FF) shl 8) - or ReverseBitsInInt8((V and $FF00) shr 8); -end; - -function ReverseBitsInInt32(V: Cardinal): Cardinal; -begin - Result := (ReverseBitsInInt16(V and $0000FFFF) shl 16) - or ReverseBitsInInt16((V and $FFFF0000) shr 16); -end; - -function ReverseBitsInInt64(V: Int64): Int64; -begin - Result := (Int64(ReverseBitsInInt32(V and $00000000FFFFFFFF)) shl 32) - or ReverseBitsInInt32((V and $FFFFFFFF00000000) shr 32); -end; - -procedure ReverseMemory(Mem: Pointer; MemByteLen: Integer); -var - I, L: Integer; - P: PByteArray; - T: Byte; -begin - if (Mem = nil) or (MemByteLen < 2) then - Exit; - - L := MemByteLen div 2; - P := PByteArray(Mem); - for I := 0 to L - 1 do - begin - // I ͵ MemLen - I - 1 - T := P^[I]; - P^[I] := P^[MemByteLen - I - 1]; - P^[MemByteLen - I - 1] := T; - end; -end; - -procedure ReverseMemoryWithBits(Mem: Pointer; MemByteLen: Integer); -var - I: Integer; - P: PByteArray; -begin - if (Mem = nil) or (MemByteLen <= 0) then - Exit; - - ReverseMemory(Mem, MemByteLen); - P := PByteArray(Mem); - - for I := 0 to MemByteLen - 1 do - P^[I] := ReverseBitsInInt8(P^[I]); -end; - -procedure MemoryNetworkToHost(Mem: Pointer; MemByteLen: Integer); -begin - if not FByteOrderIsBigEndian then - ReverseMemory(Mem, MemByteLen); -end; - -procedure MemoryHostToNetwork(Mem: Pointer; MemByteLen: Integer); -begin - if not FByteOrderIsBigEndian then - ReverseMemory(Mem, MemByteLen); -end; - -// N ֽڳȵڴλ -procedure MemoryBitOperation(AMem, BMem, RMem: Pointer; N: Integer; Op: TCnBitOperation); -var - A, B, R: PCnLongWord32Array; - BA, BB, BR: PByteArray; -begin - if N <= 0 then - Exit; - - if (AMem = nil) or ((BMem = nil) and (Op <> boNot)) or (RMem = nil) then - Exit; - - A := PCnLongWord32Array(AMem); - B := PCnLongWord32Array(BMem); - R := PCnLongWord32Array(RMem); - - while (N and (not 3)) <> 0 do - begin - case Op of - boAnd: - R^[0] := A^[0] and B^[0]; - boOr: - R^[0] := A^[0] or B^[0]; - boXor: - R^[0] := A^[0] xor B^[0]; - boNot: // ʱ B - R^[0] := not A^[0]; - end; - - A := PCnLongWord32Array(TCnNativeInt(A) + SizeOf(Cardinal)); - B := PCnLongWord32Array(TCnNativeInt(B) + SizeOf(Cardinal)); - R := PCnLongWord32Array(TCnNativeInt(R) + SizeOf(Cardinal)); - - Dec(N, SizeOf(Cardinal)); - end; - - if N > 0 then - begin - BA := PByteArray(A); - BB := PByteArray(B); - BR := PByteArray(R); - - while N <> 0 do - begin - case Op of - boAnd: - BR^[0] := BA^[0] and BB^[0]; - boOr: - BR^[0] := BA^[0] or BB^[0]; - boXor: - BR^[0] := BA^[0] xor BB^[0]; - boNot: - BR^[0] := not BA^[0]; - end; - - BA := PByteArray(TCnNativeInt(BA) + SizeOf(Byte)); - BB := PByteArray(TCnNativeInt(BB) + SizeOf(Byte)); - BR := PByteArray(TCnNativeInt(BR) + SizeOf(Byte)); - Dec(N); - end; - end; -end; - -procedure MemoryAnd(AMem, BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); -begin - MemoryBitOperation(AMem, BMem, ResMem, MemByteLen, boAnd); -end; - -procedure MemoryOr(AMem, BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); -begin - MemoryBitOperation(AMem, BMem, ResMem, MemByteLen, boOr); -end; - -procedure MemoryXor(AMem, BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); -begin - MemoryBitOperation(AMem, BMem, ResMem, MemByteLen, boXor); -end; - -procedure MemoryNot(Mem: Pointer; MemByteLen: Integer; ResMem: Pointer); -begin - MemoryBitOperation(Mem, nil, ResMem, MemByteLen, boNot); -end; - -procedure MemoryShiftLeft(AMem, BMem: Pointer; MemByteLen: Integer; BitCount: Integer); -var - I, L, N, LB, RB: Integer; - PF, PT: PByteArray; -begin - if (AMem = nil) or (MemByteLen <= 0) or (BitCount = 0) then - Exit; - - if BitCount < 0 then - begin - MemoryShiftRight(AMem, BMem, MemByteLen, -BitCount); - Exit; - end; - - if BMem = nil then - BMem := AMem; - - if (MemByteLen * 8) <= BitCount then // ̫಻ȫ 0 - begin - FillChar(BMem^, MemByteLen, 0); - Exit; - end; - - N := BitCount div 8; // λֽ - RB := BitCount mod 8; // ȥֽںʣµλ - LB := 8 - RB; // ʣµλһֽʣµλ - - PF := PByteArray(AMem); - PT := PByteArray(BMem); - - if RB = 0 then // 飬ð죬Ҫλֽ MemLen - NW - begin - Move(PF^[N], PT^[0], MemByteLen - N); - FillChar(PT^[MemByteLen - N], N, 0); - end - else - begin - // PF^[N] PT^[0] MemLen - N ֽڣֽڼн - L := MemByteLen - N; - PF := PByteArray(TCnNativeInt(PF) + N); - - for I := 1 to L do // ӵλƶȴ͵ - begin - PT^[0] := Byte(PF^[0] shl RB); - if I < L then // һֽ PF^[1] ᳬ - PT^[0] := (PF^[1] shr LB) or PT^[0]; - - PF := PByteArray(TCnNativeInt(PF) + 1); - PT := PByteArray(TCnNativeInt(PT) + 1); - end; - - // ʣµҪ 0 - if N > 0 then - FillChar(PT^[0], N, 0); - end; -end; - -procedure MemoryShiftRight(AMem, BMem: Pointer; MemByteLen: Integer; BitCount: Integer); -var - I, L, N, LB, RB: Integer; - PF, PT: PByteArray; -begin - if (AMem = nil) or (MemByteLen <= 0) or (BitCount = 0) then - Exit; - - if BitCount < 0 then - begin - MemoryShiftLeft(AMem, BMem, MemByteLen, -BitCount); - Exit; - end; - - if BMem = nil then - BMem := AMem; - - if (MemByteLen * 8) <= BitCount then // ̫಻ȫ 0 - begin - FillChar(BMem^, MemByteLen, 0); - Exit; - end; - - N := BitCount div 8; // λֽ - RB := BitCount mod 8; // ȥֽںʣµλ - LB := 8 - RB; // ʣµλһֽʣµλ - - if RB = 0 then // 飬ð죬Ҫλֽ MemLen - N - begin - PF := PByteArray(AMem); - PT := PByteArray(BMem); - - Move(PF^[0], PT^[N], MemByteLen - N); - FillChar(PT^[0], N, 0); - end - else - begin - // PF^[0] PT^[N] MemLen - N ֽڣôӸߴʼֽڼн - L := MemByteLen - N; - - PF := PByteArray(TCnNativeInt(AMem) + L - 1); - PT := PByteArray(TCnNativeInt(BMem) + MemByteLen - 1); - - for I := L downto 1 do // Ӹλλƶȴ - begin - PT^[0] := Byte(PF^[0] shr RB); - if I > 1 then // һֽ PF^[-1] ᳬ - begin - PF := PByteArray(TCnNativeInt(PF) - 1); - PT^[0] := (PF^[0] shl LB) or PT^[0]; - end - else - PF := PByteArray(TCnNativeInt(PF) - 1); - - PT := PByteArray(TCnNativeInt(PT) - 1); - end; - - // ʣµǰҪ 0 - if N > 0 then - FillChar(BMem^, N, 0); - end; -end; - -function MemoryIsBitSet(Mem: Pointer; N: Integer): Boolean; -var - P: PByte; - A, B: Integer; - V: Byte; -begin - if (Mem = nil) or (N < 0) then - raise ERangeError.Create(SRangeError); - - A := N div 8; - B := N mod 8; - P := PByte(TCnNativeInt(Mem) + A); - - V := Byte(1 shl B); - Result := (P^ and V) <> 0; -end; - -procedure MemorySetBit(Mem: Pointer; N: Integer); -var - P: PByte; - A, B: Integer; - V: Byte; -begin - if (Mem = nil) or (N < 0) then - raise ERangeError.Create(SRangeError); - - A := N div 8; - B := N mod 8; - P := PByte(TCnNativeInt(Mem) + A); - - V := Byte(1 shl B); - P^ := P^ or V; -end; - -procedure MemoryClearBit(Mem: Pointer; N: Integer); -var - P: PByte; - A, B: Integer; - V: Byte; -begin - if (Mem = nil) or (N < 0) then - raise ERangeError.Create(SRangeError); - - A := N div 8; - B := N mod 8; - P := PByte(TCnNativeInt(Mem) + A); - - V := not Byte(1 shl B); - P^ := P^ and V; -end; - -function MemoryToBinStr(Mem: Pointer; MemByteLen: Integer; Sep: Boolean): string; -var - J, L: Integer; - P: PByteArray; - B: PChar; - - procedure FillAByteToBuf(V: Byte; Buf: PChar); - const - M = $80; - var - I: Integer; - begin - for I := 0 to 7 do - begin - if (V and M) <> 0 then - Buf[I] := '1' - else - Buf[I] := '0'; - V := V shl 1; - end; - end; - -begin - Result := ''; - if (Mem = nil) or (MemByteLen <= 0) then - Exit; - - L := MemByteLen * 8; - if Sep then - L := L + MemByteLen - 1; // мÿոָ - - SetLength(Result, L); - B := PChar(@Result[1]); - P := PByteArray(Mem); - - for J := 0 to MemByteLen - 1 do - begin - FillAByteToBuf(P^[J], B); - if Sep then - begin - B[8] := ' '; - Inc(B, 9); - end - else - Inc(B, 8); - end; -end; - -procedure MemorySwap(AMem, BMem: Pointer; MemByteLen: Integer); -var - A, B: PCnLongWord32Array; - BA, BB: PByteArray; - TC: Cardinal; - TB: Byte; -begin - if (AMem = nil) or (BMem = nil) or (MemByteLen <= 0) then - Exit; - - A := PCnLongWord32Array(AMem); - B := PCnLongWord32Array(BMem); - - if A = B then - Exit; - - while (MemByteLen and (not 3)) <> 0 do - begin - TC := A^[0]; - A^[0] := B^[0]; - B^[0] := TC; - - A := PCnLongWord32Array(TCnNativeInt(A) + SizeOf(Cardinal)); - B := PCnLongWord32Array(TCnNativeInt(B) + SizeOf(Cardinal)); - - Dec(MemByteLen, SizeOf(Cardinal)); - end; - - if MemByteLen > 0 then - begin - BA := PByteArray(A); - BB := PByteArray(B); - - while MemByteLen <> 0 do - begin - TB := BA^[0]; - BA^[0] := BB^[0]; - BB^[0] :=TB; - - BA := PByteArray(TCnNativeInt(BA) + SizeOf(Byte)); - BB := PByteArray(TCnNativeInt(BB) + SizeOf(Byte)); - - Dec(MemByteLen); - end; - end; -end; - -function MemoryCompare(AMem, BMem: Pointer; MemByteLen: Integer): Integer; -var - A, B: PCnLongWord32Array; - BA, BB: PByteArray; -begin - Result := 0; - if ((AMem = nil) and (BMem = nil)) or (AMem = BMem) then // ͬһ - Exit; - - if MemByteLen <= 0 then - Exit; - - if AMem = nil then - begin - Result := -1; - Exit; - end; - if BMem = nil then - begin - Result := 1; - Exit; - end; - - A := PCnLongWord32Array(AMem); - B := PCnLongWord32Array(BMem); - - while (MemByteLen and (not 3)) <> 0 do - begin - if A^[0] > B^[0] then - begin - Result := 1; - Exit; - end - else if A^[0] < B^[0] then - begin - Result := -1; - Exit; - end; - - A := PCnLongWord32Array(TCnNativeInt(A) + SizeOf(Cardinal)); - B := PCnLongWord32Array(TCnNativeInt(B) + SizeOf(Cardinal)); - - Dec(MemByteLen, SizeOf(Cardinal)); - end; - - if MemByteLen > 0 then - begin - BA := PByteArray(A); - BB := PByteArray(B); - - while MemByteLen <> 0 do - begin - if BA^[0] > BB^[0] then - begin - Result := 1; - Exit; - end - else if BA^[0] < BB^[0] then - begin - Result := -1; - Exit; - end; - - BA := PByteArray(TCnNativeInt(BA) + SizeOf(Byte)); - BB := PByteArray(TCnNativeInt(BB) + SizeOf(Byte)); - - Dec(MemByteLen); - end; - end; -end; - -function UInt8ToBinStr(V: Byte): string; -const - M = $80; -var - I: Integer; -begin - SetLength(Result, 8 * SizeOf(V)); - for I := 1 to 8 * SizeOf(V) do - begin - if (V and M) <> 0 then - Result[I] := '1' - else - Result[I] := '0'; - V := V shl 1; - end; -end; - -function UInt16ToBinStr(V: Word): string; -const - M = $8000; -var - I: Integer; -begin - SetLength(Result, 8 * SizeOf(V)); - for I := 1 to 8 * SizeOf(V) do - begin - if (V and M) <> 0 then - Result[I] := '1' - else - Result[I] := '0'; - V := V shl 1; - end; -end; - -function UInt32ToBinStr(V: Cardinal): string; -const - M = $80000000; -var - I: Integer; -begin - SetLength(Result, 8 * SizeOf(V)); - for I := 1 to 8 * SizeOf(V) do - begin - if (V and M) <> 0 then - Result[I] := '1' - else - Result[I] := '0'; - V := V shl 1; - end; -end; - -function UInt32ToStr(V: Cardinal): string; -begin - Result := Format('%u', [V]); -end; - -function UInt64ToBinStr(V: TUInt64): string; -const - M = $8000000000000000; -var - I: Integer; -begin - SetLength(Result, 8 * SizeOf(V)); - - for I := 1 to 8 * SizeOf(V) do - begin - if (V and M) <> 0 then - Result[I] := '1' - else - Result[I] := '0'; - V := V shl 1; - end; -end; - -const - HiDigits: array[0..15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); -const - LoDigits: array[0..15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); - -const - AnsiHiDigits: array[0..15] of AnsiChar = ('0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); -const - AnsiLoDigits: array[0..15] of AnsiChar = ('0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); - -function HexToInt(Hex: PChar; CharLen: Integer): Integer; -var - I, Res: Integer; - C: Char; -begin - Res := 0; - for I := 0 to CharLen - 1 do - begin - C := Hex[I]; - if (C >= '0') and (C <= '9') then - Res := Res * 16 + Ord(C) - Ord('0') - else if (C >= 'A') and (C <= 'F') then - Res := Res * 16 + Ord(C) - Ord('A') + 10 - else if (C >= 'a') and (C <= 'f') then - Res := Res * 16 + Ord(C) - Ord('a') + 10 - else - raise ECnNativeException.CreateFmt(SCnErrorNotAHexPChar, [C]); - end; - Result := Res; -end; - -function HexToInt(const Hex: string): Integer; -begin - Result := HexToInt(PChar(Hex), Length(Hex)); -end; - -{$WARNINGS OFF} - -function IsHexString(const Hex: string): Boolean; -var - I, L: Integer; -begin - Result := False; - L := Length(Hex); - if (L <= 0) or ((L and 1) <> 0) then // ջżȶ - Exit; - - for I := 1 to L do - begin - // ע˴ Unicode Ȼ Warningǽ Hex[I] WideChar ֱӽض AnsiChar - // ٽжϣᵼ¡޻ޡ $66$66$66$66 ַУ - // ֱͨ WideChar ֵ ax ˫ֽڵģӼжϣ - if not (Hex[I] in ['0'..'9', 'A'..'F', 'a'..'f']) then - Exit; - end; - Result := True; -end; - -{$WARNINGS ON} - -function DataToHex(InData: Pointer; ByteLength: Integer; UseUpperCase: Boolean = True): string; -var - I: Integer; - B: Byte; -begin - Result := ''; - if ByteLength <= 0 then - Exit; - - SetLength(Result, ByteLength * 2); - if UseUpperCase then - begin - for I := 0 to ByteLength - 1 do - begin - B := PByte(TCnNativeInt(InData) + I * SizeOf(Byte))^; - Result[I * 2 + 1] := HiDigits[(B shr 4) and $0F]; - Result[I * 2 + 2] := HiDigits[B and $0F]; - end; - end - else - begin - for I := 0 to ByteLength - 1 do - begin - B := PByte(TCnNativeInt(InData) + I * SizeOf(Byte))^; - Result[I * 2 + 1] := LoDigits[(B shr 4) and $0F]; - Result[I * 2 + 2] := LoDigits[B and $0F]; - end; - end; -end; - -function HexToData(const Hex: string; OutData: Pointer): Integer; -var - I, L: Integer; - H: PChar; -begin - L := Length(Hex); - if (L mod 2) <> 0 then - raise ECnNativeException.CreateFmt(SCnErrorLengthNotHex, [L]); - - if OutData = nil then - begin - Result := L div 2; - Exit; - end; - - Result := 0; - H := PChar(Hex); - for I := 1 to L div 2 do - begin - PByte(TCnNativeInt(OutData) + I - 1)^ := Byte(HexToInt(@H[(I - 1) * 2], 2)); - Inc(Result); - end; -end; - -function StringToHex(const Data: string; UseUpperCase: Boolean): string; -var - I, L: Integer; - B: Byte; - Buffer: PChar; -begin - Result := ''; - L := Length(Data); - if L = 0 then - Exit; - - SetLength(Result, L * 2); - Buffer := @Data[1]; - - if UseUpperCase then - begin - for I := 0 to L - 1 do - begin - B := PByte(TCnNativeInt(Buffer) + I * SizeOf(Char))^; - Result[I * 2 + 1] := HiDigits[(B shr 4) and $0F]; - Result[I * 2 + 2] := HiDigits[B and $0F]; - end; - end - else - begin - for I := 0 to L - 1 do - begin - B := PByte(TCnNativeInt(Buffer) + I * SizeOf(Char))^; - Result[I * 2 + 1] := LoDigits[(B shr 4) and $0F]; - Result[I * 2 + 2] := LoDigits[B and $0F]; - end; - end; -end; - -function HexToString(const Hex: string): string; -var - I, L: Integer; - H: PChar; -begin - L := Length(Hex); - if (L mod 2) <> 0 then - raise ECnNativeException.CreateFmt(SCnErrorLengthNotHex, [L]); - - SetLength(Result, L div 2); - H := PChar(Hex); - for I := 1 to L div 2 do - Result[I] := Chr(HexToInt(@H[(I - 1) * 2], 2)); -end; - -function HexToAnsiStr(const Hex: AnsiString): AnsiString; -var - I, L: Integer; - S: string; -begin - L := Length(Hex); - if (L mod 2) <> 0 then - raise ECnNativeException.CreateFmt(SCnErrorLengthNotHexAnsi, [L]); - - SetLength(Result, L div 2); - for I := 1 to L div 2 do - begin - S := string(Copy(Hex, I * 2 - 1, 2)); - Result[I] := AnsiChar(Chr(HexToInt(S))); - end; -end; - -function AnsiStrToHex(const Data: AnsiString; UseUpperCase: Boolean): AnsiString; -var - I, L: Integer; - B: Byte; - Buffer: PAnsiChar; -begin - Result := ''; - L := Length(Data); - if L = 0 then - Exit; - - SetLength(Result, L * 2); - Buffer := @Data[1]; - - if UseUpperCase then - begin - for I := 0 to L - 1 do - begin - B := PByte(TCnNativeInt(Buffer) + I)^; - Result[I * 2 + 1] := AnsiHiDigits[(B shr 4) and $0F]; - Result[I * 2 + 2] := AnsiHiDigits[B and $0F]; - end; - end - else - begin - for I := 0 to L - 1 do - begin - B := PByte(TCnNativeInt(Buffer) + I)^; - Result[I * 2 + 1] := AnsiLoDigits[(B shr 4) and $0F]; - Result[I * 2 + 2] := AnsiLoDigits[B and $0F]; - end; - end; -end; - -function BytesToHex(Data: TBytes; UseUpperCase: Boolean): string; -var - I, L: Integer; - B: Byte; - Buffer: PAnsiChar; -begin - Result := ''; - L := Length(Data); - if L = 0 then - Exit; - - SetLength(Result, L * 2); - Buffer := @Data[0]; - - if UseUpperCase then - begin - for I := 0 to L - 1 do - begin - B := PByte(TCnNativeInt(Buffer) + I)^; - Result[I * 2 + 1] := HiDigits[(B shr 4) and $0F]; - Result[I * 2 + 2] := HiDigits[B and $0F]; - end; - end - else - begin - for I := 0 to L - 1 do - begin - B := PByte(TCnNativeInt(Buffer) + I)^; - Result[I * 2 + 1] := LoDigits[(B shr 4) and $0F]; - Result[I * 2 + 2] := LoDigits[B and $0F]; - end; - end; -end; - -function HexToBytes(const Hex: string): TBytes; -var - I, L: Integer; - H: PChar; -begin - L := Length(Hex); - if (L mod 2) <> 0 then - raise ECnNativeException.CreateFmt(SCnErrorLengthNotHex, [L]); - - SetLength(Result, L div 2); - H := PChar(Hex); - - for I := 1 to L div 2 do - Result[I - 1] := Byte(HexToInt(@H[(I - 1) * 2], 2)); -end; - -function StreamToHex(Stream: TStream; UseUpperCase: Boolean): string; -var - B: Byte; - I: Integer; -begin - Result := ''; - if Stream.Size > 0 then - begin - Stream.Position := 0; - SetLength(Result, Stream.Size * 2); - I := 1; - if UseUpperCase then - begin - while Stream.Read(B, 1) = 1 do - begin - Result[I] := HiDigits[(B shr 4) and $0F]; - Inc(I); - Result[I] := HiDigits[B and $0F]; - Inc(I); - end; - end - else - begin - while Stream.Read(B, 1) = 1 do - begin - Result[I] := LoDigits[(B shr 4) and $0F]; - Inc(I); - Result[I] := LoDigits[B and $0F]; - Inc(I); - end; - end; - end; -end; - -function HexToStream(const Hex: string; Stream: TStream): Integer; -var - I, L: Integer; - H: PChar; - B: Byte; -begin - Result := 0; - L := Length(Hex); - if (L mod 2) <> 0 then - raise ECnNativeException.CreateFmt(SCnErrorLengthNotHex, [L]); - - H := PChar(Hex); - for I := 1 to L div 2 do - begin - B := Byte(HexToInt(@H[(I - 1) * 2], 2)); - Inc(Result, Stream.Write(B, 1)); - end; -end; - -procedure ReverseBytes(Data: TBytes); -var - I, L, M: Integer; - T: Byte; -begin - if (Data = nil) or (Length(Data) <= 1) then - Exit; - L := Length(Data); - M := L div 2; - for I := 0 to M - 1 do - begin - // I L - I - 1 - T := Data[I]; - Data[I] := Data[L - I - 1]; - Data[L - I - 1] := T; - end; -end; - -function CloneBytes(Data: TBytes): TBytes; -begin - if Length(Data) = 0 then - Result := nil - else - begin - SetLength(Result, Length(Data)); - Move(Data[0], Result[0], Length(Data)); - end; -end; - -function StreamToBytes(Stream: TStream): TBytes; -begin - Result := nil; - if (Stream <> nil) and (Stream.Size > 0) then - begin - SetLength(Result, Stream.Size); - Stream.Position := 0; - Stream.Read(Result[0], Stream.Size); - end; -end; - -function BytesToStream(Data: TBytes; OutStream: TStream): Integer; -begin - Result := 0; - if (Data <> nil) and (Length(Data) > 0) and (OutStream <> nil) then - begin - OutStream.Size := 0; - Result := OutStream.Write(Data[0], Length(Data)); - end; -end; - -function AnsiToBytes(const Str: AnsiString): TBytes; -begin - SetLength(Result, Length(Str)); - if Length(Str) > 0 then - Move(Str[1], Result[0], Length(Str)); -end; - -function BytesToAnsi(Data: TBytes): AnsiString; -begin - SetLength(Result, Length(Data)); - if Length(Data) > 0 then - Move(Data[0], Result[1], Length(Data)); -end; - -function BytesToString(Data: TBytes): string; -var - I: Integer; -begin - SetLength(Result, Length(Data)); - for I := 1 to Length(Data) do - Result[I] := Chr(Data[I - 1]); -end; - -function MemoryToString(Mem: Pointer; MemByteLen: Integer): string; -var - P: PByteArray; - I: Integer; -begin - if (Mem = nil) or (MemByteLen <= 0) then - begin - Result := ''; - Exit; - end; - - P := PByteArray(Mem); - SetLength(Result, MemByteLen); - for I := 1 to MemByteLen do - Result[I] := Chr(P^[I - 1]); -end; - -function BitsToString(Bits: TBits): string; -var - I: Integer; -begin - if (Bits = nil) or (Bits.Size = 0) then - Result := '' - else - begin - SetLength(Result, Bits.Size); - for I := 0 to Bits.Size - 1 do - begin - if Bits.Bits[I] then - Result[I + 1] := '1' - else - Result[I + 1] := '0'; - end; - end; -end; - -function ConcatBytes(A, B: TBytes): TBytes; -begin - // XE7 ҲֱӣΪ A B Ϊʱ᷵һֽ - if (A = nil) or (Length(A) = 0) then - begin - SetLength(Result, Length(B)); - if Length(B) > 0 then - Move(B[0], Result[0], Length(B)); - end - else if (B = nil) or (Length(B) = 0) then - begin - SetLength(Result, Length(A)); - if Length(A) > 0 then - Move(A[0], Result[0], Length(A)); - end - else - begin - SetLength(Result, Length(A) + Length(B)); - Move(A[0], Result[0], Length(A)); - Move(B[0], Result[Length(A)], Length(B)); - end; -end; - -function NewBytesFromMemory(Data: Pointer; DataByteLen: Integer): TBytes; -begin - if (Data = nil) or (DataByteLen <= 0) then - Result := nil - else - begin - SetLength(Result, DataByteLen); - Move(Data^, Result[0], DataByteLen); - end; -end; - -function CompareBytes(A, B: TBytes): Boolean; -var - L: Integer; -begin - Result := False; - - L := Length(A); - if Length(B) <> L then // Ȳ˳ - Exit; - - if L = 0 then // - Result := True // 綼 0 - else - Result := CompareMem(@A[0], @B[0], L); -end; - -function CompareBytes(A, B: TBytes; MaxLength: Integer): Boolean; -var - LA, LB: Integer; -begin - Result := False; - - LA := Length(A); - LB := Length(B); - - if LA > MaxLength then - LA := MaxLength; - if LB > MaxLength then - LB := MaxLength; - - if LA <> LB then - Exit; - - if LA = 0 then - Result := True - else - Result := CompareMem(@A[0], @B[0], LA); -end; - -function MoveMost(const Source; var Dest; ByteLen, MostLen: Integer): Integer; -begin - if (MostLen <= 0) or (ByteLen <= 0) then - begin - Result := 0; - Exit; - end; - - if ByteLen > MostLen then - ByteLen := MostLen - else if ByteLen < MostLen then - begin - FillChar(Dest, MostLen, 0); - - // TODO: ҪΪ FillChar(Dest + ByteLen, MostLen - ByteLen, 0); ֻ䲻IJ - end; - - Move(Source, Dest, ByteLen); - Result := ByteLen; -end; - -// =============================== =================================== - -function SarInt8(var V: Byte; ShiftCount: Integer): Byte; -begin - Result := V shr ShiftCount; - if (V and $80) <> 0 then - Result := Result or $80; -end; - -function SarInt16(var V: Word; ShiftCount: Integer): Word; -begin - Result := V shr ShiftCount; - if (V and $8000) <> 0 then - Result := Result or $8000; -end; - -function SarInt32(var V: Cardinal; ShiftCount: Integer): Cardinal; -begin - Result := V shr ShiftCount; - if (V and $80000000) <> 0 then - Result := Result or $80000000; -end; - -function SarInt64(var V: TUInt64; ShiftCount: Integer): TUInt64; -begin - Result := V shr ShiftCount; - if (V and $8000000000000000) <> 0 then - Result := Result or $8000000000000000; -end; - -procedure ConstTimeConditionalSwap8(CanSwap: Boolean; var A, B: Byte); -var - T, V: Byte; -begin - T := ConstTimeExpandBoolean8(CanSwap); - V := (A xor B) and T; - A := A xor V; - B := B xor V; -end; - -procedure ConstTimeConditionalSwap16(CanSwap: Boolean; var A, B: Word); -var - T, V: Word; -begin - T := ConstTimeExpandBoolean16(CanSwap); - V := (A xor B) and T; - A := A xor V; - B := B xor V; -end; - -procedure ConstTimeConditionalSwap32(CanSwap: Boolean; var A, B: Cardinal); -var - T, V: Cardinal; -begin - T := ConstTimeExpandBoolean32(CanSwap); - V := (A xor B) and T; - A := A xor V; - B := B xor V; -end; - -procedure ConstTimeConditionalSwap64(CanSwap: Boolean; var A, B: TUInt64); -var - T, V: TUInt64; -begin - T := ConstTimeExpandBoolean64(CanSwap); - V := (A xor B) and T; - A := A xor V; - B := B xor V; -end; - -function ConstTimeEqual8(A, B: Byte): Boolean; -var - R: Byte; -begin - R := not (A xor B); // - R := R and (R shr 4); // һһ - R := R and (R shr 2); // һλ 0 - R := R and (R shr 1); // 0 - Result := Boolean(R); // ֻȫ 1 1 -end; - -function ConstTimeEqual16(A, B: Word): Boolean; -begin - Result := ConstTimeEqual8(Byte(A shr 8), Byte(B shr 8)) - and ConstTimeEqual8(Byte(A and $FF), Byte(B and $FF)); -end; - -function ConstTimeEqual32(A, B: Cardinal): Boolean; -begin - Result := ConstTimeEqual16(Word(A shr 16), Word(B shr 16)) - and ConstTimeEqual16(Word(A and $FFFF), Word(B and $FFFF)); -end; - -function ConstTimeEqual64(A, B: TUInt64): Boolean; -begin - Result := ConstTimeEqual32(Cardinal(A shr 32), Cardinal(B shr 32)) - and ConstTimeEqual32(Cardinal(A and $FFFFFFFF), Cardinal(B and $FFFFFFFF)); -end; - -function ConstTimeBytesEqual(A, B: TBytes): Boolean; -var - I: Integer; -begin - Result := False; - if Length(A) <> Length(B) then - Exit; - - Result := True; - for I := 0 to Length(A) - 1 do // ÿֽڶȽϣͬ˳ - Result := Result and (ConstTimeEqual8(A[I], B[I])); -end; - -function ConstTimeExpandBoolean8(V: Boolean): Byte; -begin - Result := Byte(V); - Result := not Result; // V True 0˲ R Ǵ $FFR ͷ 0 - Result := Result and (Result shr 4); // һһ - Result := Result and (Result shr 2); // һλ 0 - Result := Result and (Result shr 1); // 00000000 00000001 - Result := Result or (Result shl 1); // True õ 00000000False õ 00000001λ - Result := Result or (Result shl 2); - Result := Result or (Result shl 4); // ȫ 0 ȫ 1 - Result := not Result; // ȫ 1 ȫ 0 -end; - -function ConstTimeExpandBoolean16(V: Boolean): Word; -var - R: Byte; -begin - R := ConstTimeExpandBoolean8(V); - Result := R; - Result := (Result shl 8) or R; // ֽȫ 1 ȫ 0 ˫ֽ -end; - -function ConstTimeExpandBoolean32(V: Boolean): Cardinal; -var - R: Word; -begin - R := ConstTimeExpandBoolean16(V); - Result := R; - Result := (Result shl 16) or R; // ˫ֽȫ 1 ȫ 0 ֽ -end; - -function ConstTimeExpandBoolean64(V: Boolean): TUInt64; -var - R: Cardinal; -begin - R := ConstTimeExpandBoolean32(V); - Result := R; - Result := (Result shl 32) or R; // ֽȫ 1 ȫ 0 ɰֽ -end; - -function ConstTimeConditionalSelect8(Condition: Boolean; A, B: Byte): Byte; -begin - ConstTimeConditionalSwap8(Condition, A, B); - Result := B; -end; - -function ConstTimeConditionalSelect16(Condition: Boolean; A, B: Word): Word; -begin - ConstTimeConditionalSwap16(Condition, A, B); - Result := B; -end; - -function ConstTimeConditionalSelect32(Condition: Boolean; A, B: Cardinal): Cardinal; -begin - ConstTimeConditionalSwap32(Condition, A, B); - Result := B; -end; - -function ConstTimeConditionalSelect64(Condition: Boolean; A, B: TUInt64): TUInt64; -begin - ConstTimeConditionalSwap64(Condition, A, B); - Result := B; -end; - -{$IFDEF MSWINDOWS} - -{$IFDEF CPUX64} - -// 64 λ IDIV IDIV ָʵ֣ A RCX B EDX/RDX DivRes ַ R8 ModRes ַ R9 -procedure Int64DivInt32Mod(A: Int64; B: Integer; var DivRes, ModRes: Integer); assembler; -asm - PUSH RCX // RCX A - MOV RCX, RDX // B RCX - POP RAX // A RAX - XOR RDX, RDX // 64 λ - IDIV RCX - MOV [R8], EAX // ̷ R8 ָ DivRes - MOV [R9], EDX // R9 ָ ModRes -end; - -procedure UInt64DivUInt32Mod(A: TUInt64; B: Cardinal; var DivRes, ModRes: Cardinal); assembler; -asm - PUSH RCX // RCX A - MOV RCX, RDX // B RCX - POP RAX // A RAX - XOR RDX, RDX // 64 λ - DIV RCX - MOV [R8], EAX // ̷ R8 ָ DivRes - MOV [R9], EDX // R9 ָ ModRes -end; - -// 64 λ IDIV IDIV ָʵ֣ALo RCXAHi RDXB R8DivRes ĵַ R9 -procedure Int128DivInt64Mod(ALo, AHi: Int64; B: Int64; var DivRes, ModRes: Int64); assembler; -asm - MOV RAX, RCX // ALo RAXAHi Ѿ RDX - MOV RCX, R8 // B RCX - IDIV RCX - MOV [R9], RAX // ̷ R9 ָ DivRes - MOV RAX, [RBP + $30] // ModRes ַ RAX - MOV [RAX], RDX // RAX ָ ModRes -end; - -procedure UInt128DivUInt64Mod(ALo, AHi: UInt64; B: UInt64; var DivRes, ModRes: UInt64); assembler; -asm - MOV RAX, RCX // ALo RAXAHi Ѿ RDX - MOV RCX, R8 // B RCX - DIV RCX - MOV [R9], RAX // ̷ R9 ָ DivRes - MOV RAX, [RBP + $30] // ModRes ַ RAX - MOV [RAX], RDX // RAX ָ ModRes -end; - -{$ELSE} - -// 32 λ IDIV IDIV ָʵ֣ A ڶջϣB EAXDivRes ַ EDXModRes ַ ECX -procedure Int64DivInt32Mod(A: Int64; B: Integer; var DivRes, ModRes: Integer); assembler; -asm - PUSH ECX // ECX ModRes ַȱ - MOV ECX, B // B EAX УƵ ECX - PUSH EDX // DivRes ĵַ EDX УҲ - MOV EAX, [EBP + $8] // A Lo - MOV EDX, [EBP + $C] // A Hi - IDIV ECX - POP ECX // ECXõ DivRes ַ - MOV [ECX], EAX - POP ECX // ECXõ ModRes ַ - MOV [ECX], EDX -end; - -procedure UInt64DivUInt32Mod(A: TUInt64; B: Cardinal; var DivRes, ModRes: Cardinal); assembler; -asm - PUSH ECX // ECX ModRes ַȱ - MOV ECX, B // B EAX УƵ ECX - PUSH EDX // DivRes ĵַ EDX УҲ - MOV EAX, [EBP + $8] // A Lo - MOV EDX, [EBP + $C] // A Hi - DIV ECX - POP ECX // ECXõ DivRes ַ - MOV [ECX], EAX - POP ECX // ECXõ ModRes ַ - MOV [ECX], EDX -end; - -// 32 λµʵ -procedure Int128DivInt64Mod(ALo, AHi: Int64; B: Int64; var DivRes, ModRes: Int64); -var - C: Integer; -begin - if B = 0 then - raise EDivByZero.Create(SDivByZero); - - if (AHi = 0) or (AHi = $FFFFFFFFFFFFFFFF) then // 64 λΪ 0 ֵֵ - begin - DivRes := ALo div B; - ModRes := ALo mod B; - end - else - begin - if B < 0 then // Ǹ - begin - Int128DivInt64Mod(ALo, AHi, -B, DivRes, ModRes); - DivRes := -DivRes; - Exit; - end; - - if AHi < 0 then // Ǹ - begin - // AHi, ALo 󷴼 1Եõֵ - AHi := not AHi; - ALo := not ALo; -{$IFDEF SUPPORT_UINT64} - UInt64Add(UInt64(ALo), UInt64(ALo), 1, C); -{$ELSE} - UInt64Add(ALo, ALo, 1, C); -{$ENDIF} - if C > 0 then - AHi := AHi + C; - - // ת - Int128DivInt64Mod(ALo, AHi, B, DivRes, ModRes); - - // ٵ - if ModRes = 0 then - DivRes := -DivRes - else - begin - DivRes := -DivRes - 1; - ModRes := B - ModRes; - end; - Exit; - end; - - // ȫ󣬰޷ -{$IFDEF SUPPORT_UINT64} - UInt128DivUInt64Mod(TUInt64(ALo), TUInt64(AHi), TUInt64(B), TUInt64(DivRes), TUInt64(ModRes)); -{$ELSE} - UInt128DivUInt64Mod(ALo, AHi, B, DivRes, ModRes); -{$ENDIF} - end; -end; - -procedure UInt128DivUInt64Mod(ALo, AHi: TUInt64; B: TUInt64; var DivRes, ModRes: TUInt64); -var - I, Cnt: Integer; - Q, R: TUInt64; -begin - if B = 0 then - raise EDivByZero.Create(SDivByZero); - - if AHi = 0 then - begin - DivRes := UInt64Div(ALo, B); - ModRes := UInt64Mod(ALo, B); - end - else - begin - // иλеλզ죿жǷ AHi >= BʾҪ 64 λ - if UInt64Compare(AHi, B) >= 0 then - raise EIntOverflow.Create(SIntOverflow); - - Q := 0; - R := 0; - Cnt := GetUInt64LowBits(AHi) + 64; - for I := Cnt downto 0 do - begin - R := R shl 1; - if IsUInt128BitSet(ALo, AHi, I) then // ĵ I λǷ 0 - R := R or 1 - else - R := R and TUInt64(not 1); - - if UInt64Compare(R, B) >= 0 then - begin - R := R - B; - Q := Q or (TUInt64(1) shl I); - end; - end; - DivRes := Q; - ModRes := R; - end; -end; - -{$ENDIF} - -{$ENDIF} - -{$IFDEF SUPPORT_UINT64} - -// ֻҪ֧ 64 λ޷ 32/64 λ Intel ARM Delphi FPCʲôϵͳ - -function UInt64Mod(A, B: TUInt64): TUInt64; -begin - Result := A mod B; -end; - -function UInt64Div(A, B: TUInt64): TUInt64; -begin - Result := A div B; -end; - -{$ELSE} -{ - ֧ UInt64 ĵͰ汾 Delphi Int64 A mod/div B - - õջ˳ A ĸλA ĵλB ĸλB ĵλ push ϲ뺯 - ESP ǷصַESP+4 B ĵλESP + 8 B ĸλESP + C A ĵλESP + 10 A ĸλ - push esp ESP 4Ȼ mov ebp esp֮ EBP ѰַȫҪ 4 - - System.@_llumod ҪڸսʱEAX <- A ĵλEDX <- A ĸλSystem Դע EAX/EDX дˣ - [ESP + 8]Ҳ EBP + C<- B ĸλ[ESP + 4] Ҳ EBP + 8<- B ĵλ - - CALL ǰľƴ롣UInt64 Div Ҳ -} -function UInt64Mod(A, B: TUInt64): TUInt64; -asm - // PUSH ESP ESP 4Ҫ - MOV EAX, [EBP + $10] // A Lo - MOV EDX, [EBP + $14] // A Hi - PUSH DWORD PTR[EBP + $C] // B Hi - PUSH DWORD PTR[EBP + $8] // B Lo - CALL System.@_llumod; -end; - -function UInt64Div(A, B: TUInt64): TUInt64; -asm - // PUSH ESP ESP 4Ҫ - MOV EAX, [EBP + $10] // A Lo - MOV EDX, [EBP + $14] // A Hi - PUSH DWORD PTR[EBP + $C] // B Hi - PUSH DWORD PTR[EBP + $8] // B Lo - CALL System.@_lludiv; -end; - -{$ENDIF} - -{$IFDEF SUPPORT_UINT64} - -// ֻҪ֧ 64 λ޷ 32/64 λ Intel ARM Delphi FPCʲôϵͳ - -function UInt64Mul(A, B: Cardinal): TUInt64; -begin - Result := TUInt64(A) * B; -end; - -{$ELSE} // ֻеͰ汾 Delphi Win32 x86 - -{ - ޷ 32 λˣֱʹ Int64 ģ 64 λ޷ - - üĴԼ A -> EAXB -> EDXʹöջ - System.@_llmul ҪڸսʱEAX <- A ĵλEDX <- A ĸλ 0 - [ESP + 8]Ҳ EBP + C<- B ĸλ 0[ESP + 4] Ҳ EBP + 8<- B ĵλ -} -function UInt64Mul(A, B: Cardinal): TUInt64; -asm - PUSH 0 // PUSH B λ 0 - PUSH EDX // PUSH B λ - // EAX A λѾ - XOR EDX, EDX // EDX A λ 0 - CALL System.@_llmul; // EAX 32 λEDX 32 λ -end; - -{$ENDIF} - -// ޷ 64 λӣ ResLo ResHi -procedure UInt64AddUInt64(A, B: TUInt64; var ResLo, ResHi: TUInt64); -var - X, Y, Z, T, R0L, R0H, R1L, R1H: Cardinal; - R0, R1, R01, R12: TUInt64; -begin - // ˼룺2^32 ϵ M (xM+y) + (zM+t) = (x+z) M + (y+t) - // y+t R0 ռ 01x+z R1 ռ 12 R0, R1 ٲӳ R01, R12 - if IsUInt64AddOverflow(A, B) then - begin - X := Int64Rec(A).Hi; - Y := Int64Rec(A).Lo; - Z := Int64Rec(B).Hi; - T := Int64Rec(B).Lo; - - R0 := TUInt64(Y) + TUInt64(T); - R1 := TUInt64(X) + TUInt64(Z); - - R0L := Int64Rec(R0).Lo; - R0H := Int64Rec(R0).Hi; - R1L := Int64Rec(R1).Lo; - R1H := Int64Rec(R1).Hi; - - R01 := TUInt64(R0H) + TUInt64(R1L); - R12 := TUInt64(R1H) + TUInt64(Int64Rec(R01).Hi); - - Int64Rec(ResLo).Lo := R0L; - Int64Rec(ResLo).Hi := Int64Rec(R01).Lo; - Int64Rec(ResHi).Lo := Int64Rec(R12).Lo; - Int64Rec(ResHi).Hi := Int64Rec(R12).Hi; - end - else - begin - ResLo := A + B; - ResHi := 0; - end; -end; - -{$IFDEF WIN64} // ע Linux 64 ²֧ ASMֻ WIN64 - -// 64 λ޷ 64 λˣ ResLo ResHi Уֱûʵ֣һ -procedure UInt64MulUInt64(A, B: UInt64; var ResLo, ResHi: UInt64); assembler; -asm - PUSH RAX - MOV RAX, RCX - MUL RDX // ޷ţзŵ IMUL - MOV [R8], RAX - MOV [R9], RDX - POP RAX -end; - -{$ELSE} - -// ޷ 64 λˣ ResLo ResHi -procedure UInt64MulUInt64(A, B: TUInt64; var ResLo, ResHi: TUInt64); -var - X, Y, Z, T: Cardinal; - YT, XT, ZY, ZX: TUInt64; - P, R1Lo, R1Hi, R2Lo, R2Hi: TUInt64; -begin - // ˼룺2^32 ϵ M (xM+y)*(zM+t) = xzM^2 + (xt+yz)M + yt - // ϵ UInt64xz ռ 234xt+yz ռ 123yt ռ 01Ȼۼ - X := Int64Rec(A).Hi; - Y := Int64Rec(A).Lo; - Z := Int64Rec(B).Hi; - T := Int64Rec(B).Lo; - - YT := UInt64Mul(Y, T); - XT := UInt64Mul(X, T); - ZY := UInt64Mul(Y, Z); - ZX := UInt64Mul(X, Z); - - Int64Rec(ResLo).Lo := Int64Rec(YT).Lo; - - P := Int64Rec(YT).Hi; - UInt64AddUInt64(P, XT, R1Lo, R1Hi); - UInt64AddUInt64(ZY, R1Lo, R2Lo, R2Hi); - - Int64Rec(ResLo).Hi := Int64Rec(R2Lo).Lo; - - P := TUInt64(Int64Rec(R2Lo).Hi) + TUInt64(Int64Rec(ZX).Lo); - - Int64Rec(ResHi).Lo := Int64Rec(P).Lo; - Int64Rec(ResHi).Hi := Int64Rec(R1Hi).Lo + Int64Rec(R2Hi).Lo + Int64Rec(ZX).Hi + Int64Rec(P).Hi; -end; - -{$ENDIF} - -{$HINTS OFF} - -function _ValUInt64(const S: string; var Code: Integer): TUInt64; -const - FirstIndex = 1; -var - I: Integer; - Dig: Integer; - Sign: Boolean; - Empty: Boolean; -begin - I := FirstIndex; - Dig := 0; - Result := 0; - - if S = '' then - begin - Code := 1; - Exit; - end; - - while S[I] = Char(' ') do - Inc(I); - Sign := False; - - if S[I] = Char('-') then - begin - Sign := True; - Inc(I); - end - else if S[I] = Char('+') then - Inc(I); - Empty := True; - - if (S[I] = Char('$')) or (UpCase(S[I]) = Char('X')) - or ((S[I] = Char('0')) and (I < Length(S)) and (UpCase(S[I+1]) = Char('X'))) then - begin - if S[I] = Char('0') then - Inc(I); - Inc(I); - while True do - begin - case Char(S[I]) of - Char('0').. Char('9'): Dig := Ord(S[I]) - Ord('0'); - Char('A').. Char('F'): Dig := Ord(S[I]) - (Ord('A') - 10); - Char('a').. Char('f'): Dig := Ord(S[I]) - (Ord('a') - 10); - else - Break; - end; - - if Result > (CN_MAX_TUINT64 shr 4) then - Break; - if Sign and (Dig <> 0) then - Break; - - Result := Result shl 4 + TUInt64(Dig); - Inc(I); - Empty := False; - end; - end - else - begin - while True do - begin - case Char(S[I]) of - Char('0').. Char('9'): Dig := Ord(S[I]) - Ord('0'); - else - Break; - end; - - if Result > UInt64Div(CN_MAX_TUINT64, 10) then - Break; - if Sign and (Dig <> 0) then - Break; - - Result := Result * 10 + TUInt64(Dig); - Inc(I); - Empty := False; - end; - end; - - if (S[I] <> Char(#0)) or Empty then - Code := I + 1 - FirstIndex - else - Code := 0; -end; - -{$HINTS ON} - -function UInt64ToHex(N: TUInt64): string; -const - Digits: array[0..15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); - - function HC(B: Byte): string; - begin - Result := string(Digits[(B shr 4) and $0F] + Digits[B and $0F]); - end; - -begin - Result := - HC(Byte((N and $FF00000000000000) shr 56)) - + HC(Byte((N and $00FF000000000000) shr 48)) - + HC(Byte((N and $0000FF0000000000) shr 40)) - + HC(Byte((N and $000000FF00000000) shr 32)) - + HC(Byte((N and $00000000FF000000) shr 24)) - + HC(Byte((N and $0000000000FF0000) shr 16)) - + HC(Byte((N and $000000000000FF00) shr 8)) - + HC(Byte((N and $00000000000000FF))); -end; - -function UInt64ToStr(N: TUInt64): string; -begin - Result := Format('%u', [N]); -end; - -function StrToUInt64(const S: string): TUInt64; -{$IFNDEF DELPHIXE6_UP} -var - E: Integer; -{$ENDIF} -begin -{$IFDEF DELPHIXE6_UP} - Result := SysUtils.StrToUInt64(S); // StrToUInt64 only exists under XE6 or above -{$ELSE} - Result := _ValUInt64(S, E); - if E <> 0 then raise EConvertError.CreateResFmt(@SInvalidInteger, [S]); -{$ENDIF} -end; - -function UInt64Compare(A, B: TUInt64): Integer; -{$IFNDEF SUPPORT_UINT64} -var - HiA, HiB, LoA, LoB: Cardinal; -{$ENDIF} -begin -{$IFDEF SUPPORT_UINT64} - if A > B then - Result := 1 - else if A < B then - Result := -1 - else - Result := 0; -{$ELSE} - HiA := (A and $FFFFFFFF00000000) shr 32; - HiB := (B and $FFFFFFFF00000000) shr 32; - if HiA > HiB then - Result := 1 - else if HiA < HiB then - Result := -1 - else - begin - LoA := Cardinal(A and $00000000FFFFFFFF); - LoB := Cardinal(B and $00000000FFFFFFFF); - if LoA > LoB then - Result := 1 - else if LoA < LoB then - Result := -1 - else - Result := 0; - end; -{$ENDIF} -end; - -function UInt64Sqrt(N: TUInt64): TUInt64; -var - Rem, Root: TUInt64; - I: Integer; -begin - Result := 0; - if N = 0 then - Exit; - - if UInt64Compare(N, 4) < 0 then - begin - Result := 1; - Exit; - end; - - Rem := 0; - Root := 0; - - for I := 0 to 31 do - begin - Root := Root shl 1; - Inc(Root); - - Rem := Rem shl 2; - Rem := Rem or (N shr 62); - N := N shl 2; - - if UInt64Compare(Root, Rem) <= 0 then - begin - Rem := Rem - Root; - Inc(Root); - end - else - Dec(Root); - end; - Result := Root shr 1; -end; - -function UInt32IsNegative(N: Cardinal): Boolean; -begin - Result := (N and (1 shl 31)) <> 0; -end; - -function UInt64IsNegative(N: TUInt64): Boolean; -begin -{$IFDEF SUPPORT_UINT64} - Result := (N and (UInt64(1) shl 63)) <> 0; -{$ELSE} - Result := N < 0; -{$ENDIF} -end; - -// UInt64 ijһλ 1λ Index 0 ʼ -procedure UInt64SetBit(var B: TUInt64; Index: Integer); -begin - B := B or (TUInt64(1) shl Index); -end; - -// UInt64 ijһλ 0λ Index 0 ʼ -procedure UInt64ClearBit(var B: TUInt64; Index: Integer); -begin - B := B and not (TUInt64(1) shl Index); -end; - -// UInt64 ĵڼλǷ 10 ʼ -function GetUInt64BitSet(B: TUInt64; Index: Integer): Boolean; -begin - B := B and (TUInt64(1) shl Index); - Result := B <> 0; -end; - -// UInt64 1 ߶λǵڼλλ 0û 1 -1 -function GetUInt64HighBits(B: TUInt64): Integer; -begin - if B = 0 then - begin - Result := -1; - Exit; - end; - - Result := 1; - if B shr 32 = 0 then - begin - Inc(Result, 32); - B := B shl 32; - end; - if B shr 48 = 0 then - begin - Inc(Result, 16); - B := B shl 16; - end; - if B shr 56 = 0 then - begin - Inc(Result, 8); - B := B shl 8; - end; - if B shr 60 = 0 then - begin - Inc(Result, 4); - B := B shl 4; - end; - if B shr 62 = 0 then - begin - Inc(Result, 2); - B := B shl 2; - end; - Result := Result - Integer(B shr 63); // õǰ 0 - Result := 63 - Result; -end; - -// Cardinal 1 ߶λǵڼλλ 0û 1 -1 -function GetUInt32HighBits(B: Cardinal): Integer; -begin - if B = 0 then - begin - Result := -1; - Exit; - end; - - Result := 1; - if B shr 16 = 0 then - begin - Inc(Result, 16); - B := B shl 16; - end; - if B shr 24 = 0 then - begin - Inc(Result, 8); - B := B shl 8; - end; - if B shr 28 = 0 then - begin - Inc(Result, 4); - B := B shl 4; - end; - if B shr 30 = 0 then - begin - Inc(Result, 2); - B := B shl 2; - end; - Result := Result - Integer(B shr 31); // õǰ 0 - Result := 31 - Result; -end; - -function GetUInt16HighBits(B: Word): Integer; -begin - if B = 0 then - begin - Result := -1; - Exit; - end; - - Result := 1; - if B shr 8 = 0 then - begin - Inc(Result, 8); - B := B shl 8; - end; - if B shr 12 = 0 then - begin - Inc(Result, 4); - B := B shl 4; - end; - if B shr 14 = 0 then - begin - Inc(Result, 2); - B := B shl 2; - end; - Result := Result - Integer(B shr 15); // õǰ 0 - Result := 15 - Result; -end; - -function GetUInt8HighBits(B: Byte): Integer; -begin - if B = 0 then - begin - Result := -1; - Exit; - end; - - Result := 1; - if B shr 4 = 0 then - begin - Inc(Result, 4); - B := B shl 4; - end; - if B shr 6 = 0 then - begin - Inc(Result, 2); - B := B shl 2; - end; - Result := Result - Integer(B shr 7); // õǰ 0 - Result := 7 - Result; -end; - -// Int64 1 Ͷλǵڼλλ 0û 1 -1 -function GetUInt64LowBits(B: TUInt64): Integer; -var - Y: TUInt64; - N: Integer; -begin - Result := -1; - if B = 0 then - Exit; - - N := 63; - Y := B shl 32; - if Y <> 0 then - begin - Dec(N, 32); - B := Y; - end; - Y := B shl 16; - if Y <> 0 then - begin - Dec(N, 16); - B := Y; - end; - Y := B shl 8; - if Y <> 0 then - begin - Dec(N, 8); - B := Y; - end; - Y := B shl 4; - if Y <> 0 then - begin - Dec(N, 4); - B := Y; - end; - Y := B shl 2; - if Y <> 0 then - begin - Dec(N, 2); - B := Y; - end; - B := B shl 1; - Result := N - Integer(B shr 63); -end; - -// Cardinal 1 Ͷλǵڼλλ 0û 1 -1 -function GetUInt32LowBits(B: Cardinal): Integer; -var - Y, N: Integer; -begin - Result := -1; - if B = 0 then - Exit; - - N := 31; - Y := B shl 16; - if Y <> 0 then - begin - Dec(N, 16); - B := Y; - end; - Y := B shl 8; - if Y <> 0 then - begin - Dec(N, 8); - B := Y; - end; - Y := B shl 4; - if Y <> 0 then - begin - Dec(N, 4); - B := Y; - end; - Y := B shl 2; - if Y <> 0 then - begin - Dec(N, 2); - B := Y; - end; - B := B shl 1; - Result := N - Integer(B shr 31); -end; - -// Word 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 -function GetUInt16LowBits(B: Word): Integer; -var - Y, N: Integer; -begin - Result := -1; - if B = 0 then - Exit; - - N := 15; - Y := B shl 8; - if Y <> 0 then - begin - Dec(N, 8); - B := Y; - end; - Y := B shl 4; - if Y <> 0 then - begin - Dec(N, 4); - B := Y; - end; - Y := B shl 2; - if Y <> 0 then - begin - Dec(N, 2); - B := Y; - end; - B := B shl 1; - Result := N - Integer(B shr 15); -end; - -// Byte 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 -function GetUInt8LowBits(B: Byte): Integer; -var - N: Integer; -begin - Result := -1; - if B = 0 then - Exit; - - N := 7; - if B shr 4 = 0 then - begin - Dec(N, 4); - B := B shl 4; - end; - if B shr 6 = 0 then - begin - Dec(N, 2); - B := B shl 2; - end; - B := B shl 1; - Result := N - Integer(B shr 7); -end; - -// װ Int64 Modֵʱȡģģ -function Int64Mod(M, N: Int64): Int64; -begin - if M > 0 then - Result := M mod N - else - Result := N - ((-M) mod N); -end; - -// жһ 32 λ޷Ƿ 2 -function IsUInt32PowerOf2(N: Cardinal): Boolean; -begin - Result := (N and (N - 1)) = 0; -end; - -// жһ 64 λ޷Ƿ 2 -function IsUInt64PowerOf2(N: TUInt64): Boolean; -begin - Result := (N and (N - 1)) = 0; -end; - -// õһָ 32 λ޷ȵ 2 ݣ򷵻 0 -function GetUInt32PowerOf2GreaterEqual(N: Cardinal): Cardinal; -begin - Result := N - 1; - Result := Result or (Result shr 1); - Result := Result or (Result shr 2); - Result := Result or (Result shr 4); - Result := Result or (Result shr 8); - Result := Result or (Result shr 16); - Inc(Result); -end; - -// õһָ 64 λ޷ 2 ݣ򷵻 0 -function GetUInt64PowerOf2GreaterEqual(N: TUInt64): TUInt64; -begin - Result := N - 1; - Result := Result or (Result shr 1); - Result := Result or (Result shr 2); - Result := Result or (Result shr 4); - Result := Result or (Result shr 8); - Result := Result or (Result shr 16); - Result := Result or (Result shr 32); - Inc(Result); -end; - -// ж 32 λзǷ 32 λз -function IsInt32AddOverflow(A, B: Integer): Boolean; -var - C: Integer; -begin - C := A + B; - Result := ((A > 0) and (B > 0) and (C < 0)) or // ͬҽ˵ - ((A < 0) and (B < 0) and (C > 0)); -end; - -// ж 32 λ޷Ƿ 32 λ޷ -function IsUInt32AddOverflow(A, B: Cardinal): Boolean; -begin - Result := (A + B) < A; // ޷ӣֻҪСһ˵ -end; - -// ж 64 λзǷ 64 λз -function IsInt64AddOverflow(A, B: Int64): Boolean; -var - C: Int64; -begin - C := A + B; - Result := ((A > 0) and (B > 0) and (C < 0)) or // ͬҽ˵ - ((A < 0) and (B < 0) and (C > 0)); -end; - -// ж 64 λ޷Ƿ 64 λ޷ -function IsUInt64AddOverflow(A, B: TUInt64): Boolean; -begin - Result := UInt64Compare(A + B, A) < 0; // ޷ӣֻҪСһ˵ -end; - -function IsUInt64SubOverflowInt32(A: TUInt64; B: TUInt64): Boolean; -var - GT: Boolean; - R: TUInt64; -begin - GT := UInt64Compare(A, B) >= 0; // GT ʾ A >= B - if GT then - begin - R := A - B; - // ж 64 λ޷ŷΧ R Ƿ񳬹 MaxInt32 - Result := UInt64Compare(R, TUInt64(CN_MAX_INT32)) > 0; - end - else - begin - R := B - A; - // ж 64 λзŷΧ -R ǷС MinInt32Ҳж 64 λ޷ R Ƿ񳬹 MinInt32 ޷ʽ - Result := UInt64Compare(R, CN_MIN_INT32_IN_INT64) > 0; - end; -end; - -// 64 λ޷ӣA + B => R 1 λ -procedure UInt64Add(var R: TUInt64; A, B: TUInt64; out Carry: Integer); -begin - R := A + B; - if UInt64Compare(R, A) < 0 then // ޷ӣֻҪСһ˵ - Carry := 1 - else - Carry := 0; -end; - -// 64 λ޷A - B => Rнλ 1 λ -procedure UInt64Sub(var R: TUInt64; A, B: TUInt64; out Carry: Integer); -begin - R := A - B; - if UInt64Compare(R, A) > 0 then // ޷ֻҪڱ˵λ - Carry := 1 - else - Carry := 0; -end; - -// ж 32 λзǷ 32 λз -function IsInt32MulOverflow(A, B: Integer): Boolean; -var - T: Integer; -begin - T := A * B; - Result := (B <> 0) and ((T div B) <> A); -end; - -// ж 32 λ޷Ƿ 32 λ޷ -function IsUInt32MulOverflow(A, B: Cardinal): Boolean; -var - T: TUInt64; -begin - T := TUInt64(A) * TUInt64(B); - Result := (T = Cardinal(T)); -end; - -// ж 32 λ޷Ƿ 64 λзδҲ False ʱR ֱӷؽ -function IsUInt32MulOverflowInt64(A, B: Cardinal; out R: TUInt64): Boolean; -var - T: Int64; -begin - T := Int64(A) * Int64(B); - Result := T < 0; // Int64 ֵ˵ - if not Result then - R := TUInt64(T); -end; - -// ж 64 λзǷ 64 λз -function IsInt64MulOverflow(A, B: Int64): Boolean; -var - T: Int64; -begin - T := A * B; - Result := (B <> 0) and ((T div B) <> A); -end; - -// ָת֧ͣ 32/64 λ -function PointerToInteger(P: Pointer): Integer; -begin -{$IFDEF CPU64BITS} - // ôд Pointer ĵ 32 λ Integer - Result := Integer(P); -{$ELSE} - Result := Integer(P); -{$ENDIF} -end; - -// תָ֧ͣ 32/64 λ -function IntegerToPointer(I: Integer): Pointer; -begin -{$IFDEF CPU64BITS} - // ôд Pointer ĵ 32 λ Integer - Result := Pointer(I); -{$ELSE} - Result := Pointer(I); -{$ENDIF} -end; - -// Int64 Χĺ࣬Ҫ N 0 -function Int64NonNegativeAddMod(A, B, N: Int64): Int64; -begin - if IsInt64AddOverflow(A, B) then // Int64 - begin - if A > 0 then - begin - // A B 0 UInt64 ȡģδ UInt64 ޣע N δ Int64 ȡģС Int64 ޣɸֵ - Result := UInt64NonNegativeAddMod(A, B, N); - end - else - begin - // A B С 0ȡ UInt64 ȡģĺδ UInt64 ޣģٱһ -{$IFDEF SUPPORT_UINT64} - Result := UInt64(N) - UInt64NonNegativeAddMod(-A, -B, N); -{$ELSE} - Result := N - UInt64NonNegativeAddMod(-A, -B, N); -{$ENDIF} - end; - end - else // ֱӼ - Result := Int64NonNegativeMod(A + B, N); -end; - -// UInt64 Χĺ࣬Ҫ N 0 -function UInt64NonNegativeAddMod(A, B, N: TUInt64): TUInt64; -var - C, D: TUInt64; -begin - if IsUInt64AddOverflow(A, B) then // - begin - C := UInt64Mod(A, N); // ͸ģ - D := UInt64Mod(B, N); - if IsUInt64AddOverflow(C, D) then - begin - // ˵ģ󣬸ģûá - // һڵ 2^63N 2^63 + 1 - // = + 2^64 - // mod N = mod N + (2^64 - 1) mod N) + 1 - // N 2^63 + 1 2^64 - 2ǰӲֱӺһģ - Result := UInt64Mod(UInt64Mod(A + B, N) + UInt64Mod(CN_MAX_TUINT64, N) + 1, N); - end - else - Result := UInt64Mod(C + D, N); - end - else - begin - Result := UInt64Mod(A + B, N); - end; -end; - -function Int64NonNegativeMulMod(A, B, N: Int64): Int64; -var - Neg: Boolean; -begin - if N <= 0 then - raise EDivByZero.Create(SDivByZero); - - // ΧСֱ - if not IsInt64MulOverflow(A, B) then - begin - Result := A * B mod N; - if Result < 0 then - Result := Result + N; - Exit; - end; - - // ŵ - Result := 0; - if (A = 0) or (B = 0) then - Exit; - - Neg := False; - if (A < 0) and (B > 0) then - begin - A := -A; - Neg := True; - end - else if (A > 0) and (B < 0) then - begin - B := -B; - Neg := True; - end - else if (A < 0) and (B < 0) then - begin - A := -A; - B := -B; - end; - - // λѭ - while B <> 0 do - begin - if (B and 1) <> 0 then - Result := ((Result mod N) + (A mod N)) mod N; - - A := A shl 1; - if A >= N then - A := A mod N; - - B := B shr 1; - end; - - if Neg then - Result := N - Result; -end; - -function UInt64NonNegativeMulMod(A, B, N: TUInt64): TUInt64; -begin - Result := 0; - if (UInt64Compare(A, CN_MAX_UINT32) <= 0) and (UInt64Compare(B, CN_MAX_UINT32) <= 0) then - begin - Result := UInt64Mod(A * B, N); // 㹻СĻֱӳ˺ģ - end - else - begin - while B <> 0 do - begin - if (B and 1) <> 0 then - Result := UInt64NonNegativeAddMod(Result, A, N); - - A := UInt64NonNegativeAddMod(A, A, N); - // ôͳ㷨 A := A shl 1 N mod NΪ - - B := B shr 1; - end; - end; -end; - -// װķǸຯҲΪʱӸ豣֤ P 0 -function Int64NonNegativeMod(N: Int64; P: Int64): Int64; -begin - if P <= 0 then - raise EDivByZero.Create(SDivByZero); - - Result := N mod P; - if Result < 0 then - Inc(Result, P); -end; - -// Int64 ķǸָ -function Int64NonNegativPower(N: Int64; Exp: Integer): Int64; -var - T: Int64; -begin - if Exp < 0 then - raise ERangeError.Create(SRangeError) - else if Exp = 0 then - begin - if N <> 0 then - Result := 1 - else - raise EDivByZero.Create(SDivByZero); - end - else if Exp = 1 then - Result := N - else - begin - Result := 1; - T := N; - - while Exp > 0 do - begin - if (Exp and 1) <> 0 then - Result := Result * T; - - Exp := Exp shr 1; - T := T * T; - end; - end; -end; - -function Int64NonNegativeRoot(N: Int64; Exp: Integer): Int64; -var - I: Integer; - X: Int64; - X0, X1: Extended; -begin - if (Exp < 0) or (N < 0) then - raise ERangeError.Create(SRangeError) - else if Exp = 0 then - raise EDivByZero.Create(SDivByZero) - else if (N = 0) or (N = 1) then - Result := N - else if Exp = 2 then - Result := UInt64Sqrt(N) - else - begin - // ţٵ - I := GetUInt64HighBits(N) + 1; // õԼ Log2 N ֵ - I := (I div Exp) + 1; - X := 1 shl I; // õһϴ X0 ֵΪʼֵ - - X0 := X; - X1 := X0 - (Power(X0, Exp) - N) / (Exp * Power(X0, Exp - 1)); - - while True do - begin - if (Trunc(X0) = Trunc(X1)) and (Abs(X0 - X1) < 0.001) then - begin - Result := Trunc(X1); // Trunc ֻ֧ Int64˻ - Exit; - end; - - X0 := X1; - X1 := X0 - (Power(X0, Exp) - N) / (Exp * Power(X0, Exp - 1)); - end; - end; -end; - -function UInt64NonNegativPower(N: TUInt64; Exp: Integer): TUInt64; -var - T, RL, RH: TUInt64; -begin - if Exp < 0 then - raise ERangeError.Create(SRangeError) - else if Exp = 0 then - begin - if N <> 0 then - Result := 1 - else - raise EDivByZero.Create(SDivByZero); - end - else if Exp = 1 then - Result := N - else - begin - Result := 1; - T := N; - - while Exp > 0 do - begin - if (Exp and 1) <> 0 then - begin - UInt64MulUInt64(Result, T, RL, RH); - Result := RL; - end; - - Exp := Exp shr 1; - UInt64MulUInt64(T, T, RL, RH); - T := RL; - end; - end; -end; - -function UInt64NonNegativeRoot(N: TUInt64; Exp: Integer): TUInt64; -var - I: Integer; - X: TUInt64; - XN, X0, X1: Extended; -begin - if Exp < 0 then - raise ERangeError.Create(SRangeError) - else if Exp = 0 then - raise EDivByZero.Create(SDivByZero) - else if (N = 0) or (N = 1) then - Result := N - else if Exp = 2 then - Result := UInt64Sqrt(N) - else - begin - // ţٵ - I := GetUInt64HighBits(N) + 1; // õԼ Log2 N ֵ - I := (I div Exp) + 1; - X := 1 shl I; // õһϴ X0 ֵΪʼֵ - - X0 := UInt64ToExtended(X); - XN := UInt64ToExtended(N); - X1 := X0 - (Power(X0, Exp) - XN) / (Exp * Power(X0, Exp - 1)); - - while True do - begin - if (ExtendedToUInt64(X0) = ExtendedToUInt64(X1)) and (Abs(X0 - X1) < 0.001) then - begin - Result := ExtendedToUInt64(X1); - Exit; - end; - - X0 := X1; - X1 := X0 - (Power(X0, Exp) - XN) / (Exp * Power(X0, Exp - 1)); - end; - end; -end; - -function IsUInt128BitSet(Lo, Hi: TUInt64; N: Integer): Boolean; -begin - if N < 64 then - Result := (Lo and (TUInt64(1) shl N)) <> 0 - else - begin - Dec(N, 64); - Result := (Hi and (TUInt64(1) shl N)) <> 0; - end; -end; - -procedure SetUInt128Bit(var Lo, Hi: TUInt64; N: Integer); -begin - if N < 64 then - Lo := Lo or (TUInt64(1) shl N) - else - begin - Dec(N, 64); - Hi := Hi or (TUInt64(1) shl N); - end; -end; - -procedure ClearUInt128Bit(var Lo, Hi: TUInt64; N: Integer); -begin - if N < 64 then - Lo := Lo and not (TUInt64(1) shl N) - else - begin - Dec(N, 64); - Hi := Hi and not (TUInt64(1) shl N); - end; -end; - -function UnsignedAddWithLimitRadix(A, B, C: Cardinal; var R: Cardinal; - L, H: Cardinal): Cardinal; -begin - R := A + B + C; - if R > H then // нλ - begin - A := H - L + 1; // õ - B := R - L; // õ L ֵ - - Result := B div A; // Ƶĵڼͽ - R := L + (B mod A); // ȥƺ - end - else - Result := 0; -end; - -procedure InternalQuickSort(Mem: Pointer; L, R: Integer; ElementByteSize: Integer; - CompareProc: TCnMemSortCompareProc); -var - I, J, P: Integer; -begin - repeat - I := L; - J := R; - P := (L + R) shr 1; - repeat - while CompareProc(Pointer(TCnNativeInt(Mem) + I * ElementByteSize), - Pointer(TCnNativeInt(Mem) + P * ElementByteSize), ElementByteSize) < 0 do - Inc(I); - while CompareProc(Pointer(TCnNativeInt(Mem) + J * ElementByteSize), - Pointer(TCnNativeInt(Mem) + P * ElementByteSize), ElementByteSize) > 0 do - Dec(J); - - if I <= J then - begin - MemorySwap(Pointer(TCnNativeInt(Mem) + I * ElementByteSize), - Pointer(TCnNativeInt(Mem) + J * ElementByteSize), ElementByteSize); - - if P = I then - P := J - else if P = J then - P := I; - Inc(I); - Dec(J); - end; - until I > J; - - if L < J then - InternalQuickSort(Mem, L, J, ElementByteSize, CompareProc); - L := I; - until I >= R; -end; - -function DefaultCompareProc(P1, P2: Pointer; ElementByteSize: Integer): Integer; -begin - Result := MemoryCompare(P1, P2, ElementByteSize); -end; - -procedure MemoryQuickSort(Mem: Pointer; ElementByteSize: Integer; - ElementCount: Integer; CompareProc: TCnMemSortCompareProc); -begin - if (Mem <> nil) and (ElementCount > 0) and (ElementCount > 0) then - begin - if Assigned(CompareProc) then - InternalQuickSort(Mem, 0, ElementCount - 1, ElementByteSize, CompareProc) - else - InternalQuickSort(Mem, 0, ElementCount - 1, ElementByteSize, DefaultCompareProc); - end; -end; - -{$IFDEF COMPILER5} - -function BoolToStr(Value: Boolean; UseBoolStrs: Boolean): string; -begin - if UseBoolStrs then - begin - if Value then - Result := 'True' - else - Result := 'False'; - end - else - begin - if Value then - Result := '-1' - else - Result := '0'; - end; -end; - -{$ENDIF} - -// =========================== ѭλ ==================================== - -function RotateLeft16(A: Word; N: Integer): Word; -begin - Result := (A shl N) or (A shr (16 - N)); -end; - -function RotateRight16(A: Word; N: Integer): Word; -begin - Result := (A shr N) or (A shl (16 - N)); -end; - -function RotateLeft32(A: Cardinal; N: Integer): Cardinal; -begin - Result := (A shl N) or (A shr (32 - N)); -end; - -function RotateRight32(A: Cardinal; N: Integer): Cardinal; -begin - Result := (A shr N) or (A shl (32 - N)); -end; - -function RotateLeft64(A: TUInt64; N: Integer): TUInt64; -begin - Result := (A shl N) or (A shr (64 - N)); -end; -function RotateRight64(A: TUInt64; N: Integer): TUInt64; -begin - Result := (A shr N) or (A shl (64 - N)); -end; - -initialization - FByteOrderIsBigEndian := CurrentByteOrderIsBigEndian; - -end. +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnNative; +{* |
+================================================================================
+* ƣCnPack 
+* Ԫƣ32 λ 64 λƽ̨һЩͳһԼһʵֵԪ
+* ԪߣCnPack  (master@cnpack.org)
+*     עԪһ 32 λ 64 λƽ̨һЩͳһʵ֡
+*           Delphi XE 2 ֧ 32  64 ų NativeInt  NativeUInt 
+*           ǰ 32 λ 64 ̬仯Ӱ쵽 PointerReferenceȶ
+*           ǵԣ̶ȵ 32 λ Cardinal/Integer Ⱥ Pointer Щ
+*           ͨˣʹ 32 λҲֹ˱Ԫ˼ͣ
+*           ͬʱڵͰ汾͸߰汾 Delphi ʹá
+*
+*           ԪҲڲ֧ UInt64 ı Delphi 5/6/7  Int64 ģ UInt64
+*           ĸ㣬ӼȻ֧֣˳Ҫģ div  mod
+*           ַ Integer(APtr)  64 λ MacOS ׳ֽضϣҪ NativeInt
+*
+*           ʵ˴Сءֽת̶ʱȷĴײ㺯빤ࡣ
+*
+* ƽ̨PWin2000 + Delphi 5.0
+* ݲԣPWin9X/2000/XP + Delphi 5/6/7 XE 2
+*   õԪеַϱػʽ
+* ޸ļ¼2023.08.14 V2.4
+*               ϼʱ̶ĺ
+*           2022.11.11 V2.3
+*               ϼ޷ֽ˳
+*           2022.07.23 V2.2
+*               Ӽڴλ㺯תַΪ CnNative
+*           2022.06.08 V2.1
+*               ĸʱ̶ĽԼڴ浹ź
+*           2022.03.14 V2.0
+*               Ӽʮת
+*           2022.02.17 V1.9
+*                FPC ı֧
+*           2022.02.09 V1.8
+*               ڵĴСжϺ
+*           2021.09.05 V1.7
+*                Int64/UInt64 㺯
+*           2020.10.28 V1.6
+*                UInt64 صж㺯
+*           2020.09.06 V1.5
+*                UInt64 ƽĺ
+*           2020.07.01 V1.5
+*               ж 32 λ 64 λ޷Ƿĺ
+*           2020.06.20 V1.4
+*                32 λ 64 λȡ͵ 1 λλõĺ
+*           2020.01.01 V1.3
+*                32 λ޷͵ mul 㣬ڲ֧ UInt64 ϵͳ Int64 Ա
+*           2018.06.05 V1.2
+*                64 λ͵ div/mod 㣬ڲ֧ UInt64 ϵͳ Int64  
+*           2016.09.27 V1.1
+*                64 λ͵һЩ
+*           2011.07.06 V1.0
+*               Ԫʵֹ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + Classes, SysUtils, SysConst, Math {$IFDEF COMPILER5}, Windows {$ENDIF}; + // D5 Ҫ Windows е PByte +type + ECnNativeException = class(Exception); + {* Native 쳣} + +{$IFDEF COMPILER5} + PByte = Windows.PByte; + {* D5 PByte Windows У汾 System У + ͳһһ¹ʹ PByte ʱ uses Windowsڿƽ̨ͬ} + PWord = Windows.PWord; + {* D5 PWord Windows } + PShortInt = Windows.PShortInt; + {* D5 PShortInt Windows } + PSmallInt = Windows.PSmallInt; + {* D5 PSmallInt Windows } + PInteger = Windows.PInteger; + {* D5 PInteger Windows } + PSingle = Windows.PSingle; + {* D5 PSingle Windows } + PDouble = Windows.PDouble; + {* D5 PDouble Windows } + + PCardinal = ^Cardinal; + {* D5 System Ԫδ Cardinal ָͣ} + PBoolean = ^Boolean; + {* D5 System Ԫδ Boolean ָͣ} +{$ENDIF} + +{$IFDEF BCB5OR6} + PInt64 = ^Int64; + {* C++Builder 5/6 sysmac.h û PInt64 Ķ壨е PUINT64 Сдͬ㣩} +{$ENDIF} + +{$IFDEF SUPPORT_32_AND_64} + TCnNativeInt = NativeInt; + {* ͳһ 32 λ 64 λͨõз} + TCnNativeUInt = NativeUInt; + {* ͳһ 32 λ 64 λͨõ޷} + TCnNativePointer = NativeInt; + {* ͳһ 32 λ 64 λͨõָ} + TCnNativeIntPtr = PNativeInt; + {* ͳһ 32 λ 64 λͨõָзָ} + TCnNativeUIntPtr = PNativeUInt; + {* ͳһ 32 λ 64 λͨõָ޷ָ} +{$ELSE} + TCnNativeInt = Integer; + {* ͳһ 32 λ 64 λͨõз} + TCnNativeUInt = Cardinal; + {* ͳһ 32 λ 64 λͨõ޷} + TCnNativePointer = Integer; + {* ͳһ 32 λ 64 λͨõָ} + TCnNativeIntPtr = PInteger; + {* ͳһ 32 λ 64 λͨõָзָ} + TCnNativeUIntPtr = PCardinal; + {* ͳһ 32 λ 64 λͨõָ޷ָ} +{$ENDIF} + PCnNativeInt = ^TCnNativeInt; + {* ָͳһ 32 λ 64 λͨõз͵ָ} + PCnNativeUInt = ^TCnNativeUInt; + {* ָͳһ 32 λ 64 λͨõ޷͵ָ} +{$IFDEF FPC} + TCnHashCode = PtrInt; + {* ͳһ Delphi FPC µ HashCode } +{$ELSE} + TCnHashCode = Integer; + {* ͳһ Delphi FPC µ HashCode } +{$ENDIF} + + // еַӼͣ FPC Delphi ¶ԷŵҪ +{$IFDEF FPC} + TCnIntAddress = NativeUInt; + {* ͳһ Delphi FPC µĹеַӼ} +{$ELSE} + {$IFDEF SUPPORT_32_AND_64} + TCnIntAddress = NativeInt; + {* ͳһ Delphi FPC µĹеַӼ} + {$ELSE} + TCnIntAddress = Integer; + {* ͳһ Delphi FPC µĹеַӼ} + {$ENDIF} +{$ENDIF} + +{$IFDEF CPU64BITS} + TCnUInt64 = NativeUInt; + {* ͳһ 64 λ޷} + TCnInt64 = NativeInt; + {* ͳһ 64 λз} +{$ELSE} + {$IFDEF SUPPORT_UINT64} + TCnUInt64 = UInt64; + {* ͳһ 64 λ޷} + {$ELSE} + TCnUInt64 = packed record + {* ڲ֧ UInt64 32 λ£ 64 λ޷ṹ} + case Boolean of + True: (Value: Int64); + False: (Lo32, Hi32: Cardinal); + end; + {$ENDIF} + TCnInt64 = Int64; + {* ͳһ 64 λ޷} +{$ENDIF} + +// TUInt64 cnvcl в֧ UInt64 div mod +{$IFDEF SUPPORT_UINT64} + TUInt64 = UInt64; + {* ͳһ 64 λ޷} + {$IFNDEF SUPPORT_PUINT64} + PUInt64 = ^UInt64; + {* ͳһָ 64 λ޷ָ} + {$ENDIF} +{$ELSE} + TUInt64 = Int64; + {* ͳһ 64 λ޷ͣ cnvcl в֧ UInt64 } + PUInt64 = ^TUInt64; + {* ͳһָ 64 λ޷ָͣ cnvcl в֧ UInt64 } +{$ENDIF} + +{$IFNDEF SUPPORT_INT64ARRAY} + Int64Array = array[0..$0FFFFFFE] of Int64; + {* ϵͳûж Int64Array 64 λз} + PInt64Array = ^Int64Array; + {* ϵͳûж PInt64Array 64 λзָ} +{$ENDIF} + + TUInt64Array = array of TUInt64; + {* ͳһ 64 λ޷̬飬ע̬ƺ׺;̬гͻ} + ExtendedArray = array[0..65537] of Extended; + {* չȸ} + PExtendedArray = ^ExtendedArray; + {* չȸָ} + + PCnWord16Array = ^TCnWord16Array; + {* 16 λ޷ָ} + TCnWord16Array = array [0..0] of Word; + {* 16 λ޷} + +{$IFDEF POSIX64} + TCnLongWord32 = Cardinal; + {* ͳһ 32 λ޷ LongWordΪ Linux64/MacOS64 POSIX64 LongWord Ȼ 64 λ޷} +{$ELSE} + TCnLongWord32 = LongWord; + {* ͳһ 32 λ޷ LongWord} +{$ENDIF} + PCnLongWord32 = ^TCnLongWord32; + {* ͳһָ 32 λ޷ LongWord ָ} + + TCnLongWord32Array = array [0..MaxInt div SizeOf(Integer) - 1] of TCnLongWord32; + {* ͳһ 32 λ޷ LongWord } + + PCnLongWord32Array = ^TCnLongWord32Array; + {* ͳһ 32 λ޷ LongWord ָ} + +{$IFNDEF TBYTES_DEFINED} + TBytes = array of Byte; + {* ޷ֽڶ̬飬δʱ} +{$ENDIF} + + TShortInts = array of ShortInt; + {* зֽڶ̬} + + TSmallInts = array of SmallInt; + {* з˫ֽڶ̬} + + TWords = array of Word; + {* ޷˫ֽڶ̬} + + TIntegers = array of Integer; + {* зֽڶ̬} + + TCardinals = array of Cardinal; + {* ޷ֽڶ̬} + + TBooleans = array of Boolean; + {* ̬} + + PCnByte = ^Byte; + {* ָ 8 λ޷ָ} + PCnWord = ^Word; + {* ָ 16 λ޷ָ} + + TCnBitOperation = (boAnd, boOr, boXor, boNot); + {* λ} + + // ʹõľ̬з޷ + PCnInt8Array = ^TCnInt8Array; + {* ̬ 8 λзָ} + TCnInt8Array = array[0..(MaxInt div SizeOf(ShortInt) - 1)] of ShortInt; + {* ̬ 8 λз} + + PCnUInt8Array = ^TCnUInt8Array; + {* ̬ 8 λ޷ָ} + TCnUInt8Array = array[0..(MaxInt div SizeOf(Byte) - 1)] of Byte; + {* ̬ 8 λ޷} + + PCnInt16Array = ^TCnInt16Array; + {* ̬ 16 λзָ} + TCnInt16Array = array[0..(MaxInt div SizeOf(SmallInt) - 1)] of SmallInt; + {* ̬ 16 λз} + + PCnUInt16Array = ^TCnUInt16Array; + {* ̬ 16 λ޷ָ} + TCnUInt16Array = array[0..(MaxInt div SizeOf(Word) - 1)] of Word; + {* ̬ 16 λ޷} + + PCnInt32Array = ^TCnInt32Array; + {* ̬ 32 λзָ} + TCnInt32Array = array[0..(MaxInt div SizeOf(Integer) - 1)] of Integer; + {* ̬ 32 λз} + + PCnUInt32Array = ^TCnUInt32Array; + {* ̬ 32 λ޷ָ} + TCnUInt32Array = array[0..(MaxInt div SizeOf(Cardinal) - 1)] of Cardinal; + {* ̬ 32 λ޷} + + PCnInt64Array = ^TCnInt64Array; + {* ̬ 64 λзָ} + TCnInt64Array = array[0..(MaxInt div SizeOf(Int64) - 1)] of Int64; + {* ̬ 64 λз} + + PCnUInt64Array = ^TCnUInt64Array; + {* ̬ 64 λ޷ָ} + TCnUInt64Array = array[0..(MaxInt div SizeOf(TUInt64) - 1)] of TUInt64; + {* ̬ 64 λ޷} + +type + TCnMemSortCompareProc = function (P1, P2: Pointer; ElementByteSize: Integer): Integer; + {* ڴ̶ߴȽϺԭ} + +const + CN_MAX_SQRT_INT64: Cardinal = 3037000499; + {* 64 λзΧƽ} + CN_MAX_INT8: ShortInt = $7F; + {* 8 λз} + CN_MIN_INT8: ShortInt = -128; + {* С 8 λз} + CN_MAX_INT16: SmallInt = $7FFF; + {* 16 λз} + CN_MIN_INT16: SmallInt = -32768; + {* С 16 λз} + CN_MAX_INT32: Integer = $7FFFFFFF; + {* 32 λз} +{$WARNINGS OFF} + CN_MIN_INT32: Integer = $80000000; + {* С 32 λз -2147483648} + // 뾯棬д -2147483648 +{$WARNINGS ON} + CN_MIN_INT32_IN_INT64: Int64 = $0000000080000000; + {* 64 λзΧС 32 λз -2147483648} + CN_MAX_INT64: Int64 = $7FFFFFFFFFFFFFFF; + {* 64 λз} + CN_MIN_INT64: Int64 = $8000000000000000; + {* С 64 λз} + CN_MAX_UINT8: Byte = $FF; + {* 8 λ޷} + CN_MAX_UINT16: Word = $FFFF; + {* 16 λ޷} + CN_MAX_UINT32: Cardinal = $FFFFFFFF; + {* 32 λ޷} + CN_MAX_TUINT64: TUInt64 = $FFFFFFFFFFFFFFFF; + {* 64 λ޷} + CN_MAX_SIGNED_INT64_IN_TUINT64: TUInt64 = $7FFFFFFFFFFFFFFF; + {* 64 λ޷Χ 64 λз} + +{* + D567 Ȳ֧ UInt64 ıȻ Int64 UInt64 мӼ洢 + ˳޷ֱɣװ System е _lludiv _llumod + ʵ Int64 ʾ UInt64 ݵ div mod ܡ +} +function UInt64Mod(A: TUInt64; B: TUInt64): TUInt64; +{* 64 λ޷ࡣ + + + A: TUInt64 - + B: TUInt64 - + + ֵTUInt64 - +} + +function UInt64Div(A: TUInt64; B: TUInt64): TUInt64; +{* 64 λ޷ + + + A: TUInt64 - + B: TUInt64 - + + ֵTUInt64 - +} + +function UInt64Mul(A: Cardinal; B: Cardinal): TUInt64; +{* 32 λ޷ˡڲ֧ UInt64 ƽ̨ϣ UInt64 ʽ Int64  + ֱʹ Int64 п + + + A: Cardinal - һ + B: Cardinal - + + ֵTUInt64 - +} + +procedure UInt64AddUInt64(A: TUInt64; B: TUInt64; var ResLo: TUInt64; var ResHi: TUInt64); +{* 64 λ޷ӣ ResLo ResHi С + עڲʵְ㷨ΪӣʵResHi Ȼ 1ֱж 1 + + + A: TUInt64 - һ + B: TUInt64 - + var ResLo: TUInt64 - ͵λ + var ResHi: TUInt64 - ͸λ + + ֵޣ +} + +procedure UInt64MulUInt64(A: TUInt64; B: TUInt64; var ResLo: TUInt64; var ResHi: TUInt64); +{* 64 λ޷ˣ ResLo ResHi СWin 64 λûʵ֣Լһϡ + + + A: TUInt64 - һ + B: TUInt64 - + var ResLo: TUInt64 - λ + var ResHi: TUInt64 - λ + + ֵޣ +} + +function UInt64ToHex(N: TUInt64; RemoveZeroPrefix: Boolean = False): string; +{* 64 λ޷תΪʮַ + + + N: TUInt64 - תֵ + RemoveZeroPrefix: Boolean - Ƿȥתλ 0Ĭϲȥ + + ֵstring - ʮַ +} + +function UInt64ToStr(N: TUInt64): string; +{* 64 λ޷תΪʮַ + + + N: TUInt64 - תֵ + + ֵstring - ʮַ +} + +function StrToUInt64(const S: string): TUInt64; +{* ַתΪ 64 λ޷ + + + const S: string - תַ + + ֵTUInt64 - ת +} + +function UInt64Compare(A: TUInt64; B: TUInt64): Integer; +{* Ƚ 64 λ޷ֱֵݱȽϵĽǴڡڻС 10-1 + + + A: TUInt64 - Ƚϵһ + B: TUInt64 - Ƚϵ + + ֵInteger - رȽϽ +} + +function UInt64Sqrt(N: TUInt64): TUInt64; +{* 64 λ޷ƽ֡ + + + N: TUInt64 - ƽ + + ֵTUInt64 - ƽ +} + +function UInt32IsNegative(N: Cardinal): Boolean; +{* ж 32 λ޷ 32 λзʱǷС 0 + + + N: Cardinal - жϵֵ + + ֵBoolean - ǷС 0 +} + +function UInt64IsNegative(N: TUInt64): Boolean; +{* ж 64 λ޷ 64 λзʱǷС 0 + + + N: TUInt64 - жϵֵ + + ֵBoolean - ǷС 0 +} + +procedure UInt64SetBit(var B: TUInt64; Index: Integer); +{* 64 λijһλ 1λ Index 0 ʼ 63 + + + var B: TUInt64 - λֵ + Index: Integer - 1 λ + + ֵޣ +} + +procedure UInt64ClearBit(var B: TUInt64; Index: Integer); +{* 64 λijһλ 0λ Index 0 ʼ 63 + + + var B: TUInt64 - λֵ + Index: Integer - 0 λ + + ֵޣ +} + +function GetUInt64BitSet(B: TUInt64; Index: Integer): Boolean; +{* 64 λijһλǷ 1λ Index 0 ʼ 63 + + + B: TUInt64 - жϵֵ + Index: Integer - жϵλ + + ֵBoolean - ظλǷ 1 +} + +function GetUInt64HighBits(B: TUInt64): Integer; +{* 64 λ 1 ߶λǵڼλλ 0û 1 -1 + + + B: TUInt64 - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt32HighBits(B: Cardinal): Integer; +{* 32 λ 1 ߶λǵڼλλ 0û 1 -1 + + + B: Cardinal - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt16HighBits(B: Word): Integer; +{* 16 λ 1 ߶λǵڼλλ 0û 1 -1 + + + B: Word - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt8HighBits(B: Byte): Integer; +{* 8 λ 1 ߶λǵڼλλ 0û 1 -1 + + + B: Byte - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt64BitLength(B: TUInt64): Integer; +{* 64 λȥλ 0 ʣµλȣû 1 0 + + + B: TUInt64 - жϵֵ + + ֵInteger - Чλ +} + +function GetUInt32BitLength(B: Cardinal): Integer; +{* 32 λȥλ 0 ʣµλȣû 1 0 + + + B: Cardinal - жϵֵ + + ֵInteger - Чλ +} + +function GetUInt16BitLength(B: Word): Integer; +{* 16 λȥλ 0 ʣµλȣû 1 0 + + + B: Word - жϵֵ + + ֵInteger - Чλ +} + +function GetUInt8BitLength(B: Byte): Integer; +{* 8 λȥλ 0 ʣµλȣû 1 0 + + + B: Byte - жϵֵ + + ֵInteger - Чλ +} + +function GetUInt64LowBits(B: TUInt64): Integer; +{* 64 λ 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 + + + B: TUInt64 - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt32LowBits(B: Cardinal): Integer; +{* 32 λ 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 + + + B: Cardinal - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt16LowBits(B: Word): Integer; +{* 16 λ 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 + + + B: Word - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt8LowBits(B: Byte): Integer; +{* 8 λ 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 + + + B: Byte - жϵֵ + + ֵInteger - 1 λ +} + +function Int64Mod(M: Int64; N: Int64): Int64; +{* װ Int64 ModM ֵʱȡģģ N Ҫס + + + M: Int64 - + N: Int64 - + + ֵInt64 - +} + +function Int64CenterMod(A: Int64; N: Int64): Int64; +{* A mod N Ļ (-(N - 1)/2 ½磨, (N - 1)/ 2 ½磨 0] + Ҫ N ע⣬Ļǽ A mod N ֵƣdzһֱӼ N + һľȷǣ N/2 ִģֱӼ N N ż + ڱ߽磺һ仰ԳżϿ + N 7 [-3, 3] 3 Ķ 7ע 3 + N 6 [-2, 3] 3 Ķ 6ע 3 Ҳ + N Ϊʱ(N - 1)żԶ 0 һ N 0 N - 1ӳ䵽 [-(N - 1)/2, (N - 1)/2] + N ΪżʱN/2 ż߽ -N/2 + 1ұ߽ N/20 N - 1ӳ䵽 [-N/2 + 1, N/2] + + + A: Int64 - Ļֵ + N: Int64 - ģ + + ֵInt64 - Ļ +} + +function IsUInt32PowerOf2(N: Cardinal): Boolean; +{* жһ 32 λ޷Ƿ 2 ݡ + + + N: Cardinal - жϵֵ + + ֵBoolean - Ƿ 2 +} + +function IsUInt64PowerOf2(N: TUInt64): Boolean; +{* жһ 64 λ޷Ƿ 2 ݡ + + + N: TUInt64 - жϵֵ + + ֵBoolean - Ƿ 2 +} + +function GetUInt32PowerOf2GreaterEqual(N: Cardinal): Cardinal; +{* õһָ 32 λ޷ȵ 2 ݣ򷵻 0 + + + N: Cardinal - ֵ + + ֵCardinal - ط 2 ݻ 0 +} + +function GetUInt64PowerOf2GreaterEqual(N: TUInt64): TUInt64; +{* õһָ 64 λ޷ȵ 2 ݣ򷵻 0 + + + N: TUInt64 - ֵ + + ֵTUInt64 - ط 2 ݻ 0 +} + +function IsInt32AddOverflow(A: Integer; B: Integer): Boolean; +{* ж 32 λзǷ 32 λзޡ + + + A: Integer - һ + B: Integer - + + ֵBoolean - Ƿ +} + +function IsUInt32AddOverflow(A: Cardinal; B: Cardinal): Boolean; +{* ж 32 λ޷Ƿ 32 λ޷ޡ + + + A: Cardinal - һ + B: Cardinal - + + ֵBoolean - Ƿ +} + +function IsInt64AddOverflow(A: Int64; B: Int64): Boolean; +{* ж 64 λзǷ 64 λзޡ + + + A: Int64 - һ + B: Int64 - + + ֵBoolean - Ƿ +} + +function IsUInt64AddOverflow(A: TUInt64; B: TUInt64): Boolean; +{* ж 64 λ޷Ƿ 64 λ޷ޡ + + + A: TUInt64 - һ + B: TUInt64 - + + ֵBoolean - Ƿ +} + +function IsUInt64SubOverflowInt32(A: TUInt64; B: TUInt64): Boolean; +{* жһ 64 λ޷ȥһ 64 λ޷ĽǷ񳬳 32 λзΧ + 64 λе JMP תжϡ + + + A: TUInt64 - + B: TUInt64 - + + ֵBoolean - Ƿ񳬳 32 λзΧ +} + +procedure UInt64Add(var R: TUInt64; A: TUInt64; B: TUInt64; out Carry: Integer); +{* 64 λ޷ӣA + B => R 1 ýλλ㡣 + + + var R: TUInt64 - + A: TUInt64 - һ + B: TUInt64 - + out Carry: Integer - λ + + ֵޣ +} + +procedure UInt64Sub(var R: TUInt64; A: TUInt64; B: TUInt64; out Carry: Integer); +{* 64 λ޷A - B => Rнλ 1 ýλλ㡣 + + + var R: TUInt64 - + A: TUInt64 - + B: TUInt64 - + out Carry: Integer - λ + + ֵޣ +} + +function IsInt32MulOverflow(A: Integer; B: Integer): Boolean; +{* ж 32 λзǷ 32 λзޡ + + + A: Integer - һ + B: Integer - + + ֵBoolean - Ƿ +} + +function IsUInt32MulOverflow(A: Cardinal; B: Cardinal): Boolean; +{* ж 32 λ޷Ƿ 32 λ޷ + + + A: Cardinal - һ + B: Cardinal - + + ֵBoolean - Ƿ +} + +function IsUInt32MulOverflowInt64(A: Cardinal; B: Cardinal; out R: TUInt64): Boolean; +{* ж 32 λ޷Ƿ 64 λзޣδҲ False ʱR ֱӷؽ + Ҳ TrueҪµ UInt64Mul ʵʩˡ + + + A: Cardinal - һ + B: Cardinal - + out R: TUInt64 - δʱػ + + ֵBoolean - Ƿ +} + +function IsInt64MulOverflow(A: Int64; B: Int64): Boolean; +{* ж 64 λзǷ 64 λзޡ + + + A: Int64 - һ + B: Int64 - + + ֵBoolean - Ƿ +} + +function PointerToInteger(P: Pointer): Integer; +{* ָת֧ͣ 32/64 λע 64 λ¿ܻᶪ 32 λݡ + + + P: Pointer - תָ + + ֵInteger - ת +} + +function IntegerToPointer(I: Integer): Pointer; +{* תָ֧ͣ 32/64 λ + + + I: Integer - ת + + ֵPointer - תָ +} + +function Int64NonNegativeAddMod(A: Int64; B: Int64; N: Int64): Int64; +{* 64 λзΧĺ࣬Ҫ N 0 + + + A: Int64 - һ + B: Int64 - һ + N: Int64 - ģ + + ֵInt64 - Ľ +} + +function UInt64NonNegativeAddMod(A: TUInt64; B: TUInt64; N: TUInt64): TUInt64; +{* 64 λ޷Χĺ࣬Ҫ N 0 + + + A: TUInt64 - һ + B: TUInt64 - + N: TUInt64 - ģ + + ֵTUInt64 - Ľ +} + +function Int64NonNegativeMulMod(A: Int64; B: Int64; N: Int64): Int64; +{* 64 λзΧڵֱ࣬Ӽ㣬Ҫ N 0 + + + A: Int64 - һ + B: Int64 - + N: Int64 - ģ + + ֵInt64 - Ľ +} + +function UInt64NonNegativeMulMod(A: TUInt64; B: TUInt64; N: TUInt64): TUInt64; +{* 64 λ޷Χڵֱ࣬Ӽ㣬 + + + A: TUInt64 - һ + B: TUInt64 - + N: TUInt64 - ģ + + ֵTUInt64 - Ľ +} + +function Int64NonNegativeMod(N: Int64; P: Int64): Int64; +{* װ 64 λзķǸຯҲΪʱӸ豣֤ P 0 + + + N: Int64 - + P: Int64 - + + ֵInt64 - طǸĽ +} + +function Int64NonNegativPower(N: Int64; Exp: Integer): Int64; +{* 64 λзķǸָݣ + + + N: Int64 - + Exp: Integer - ָҪ 0 + + ֵInt64 - ݵĽ +} + +function Int64NonNegativeRoot(N: Int64; Exp: Integer): Int64; +{* 64 λзķǸη֣ + + + N: Int64 - + Exp: Integer - + + ֵInt64 - ؿֽ +} + +function UInt64NonNegativPower(N: TUInt64; Exp: Integer): TUInt64; +{* 64 λ޷ķǸָݣ + + + N: TUInt64 - + Exp: Integer - ָҪ 0 + + ֵTUInt64 - ݵĽ +} + +function UInt64NonNegativeRoot(N: TUInt64; Exp: Integer): TUInt64; +{* 64 λ޷ķǸη֣ + + + N: TUInt64 - + Exp: Integer - + + ֵTUInt64 - ؿֽ +} + +function CurrentByteOrderIsBigEndian: Boolean; +{* صǰڻǷǴˣҲǷеĸֽڴ洢ڽϵ͵ʼַ + ϴҵĶϰߣ粿ָ ARM MIPS + + + ޣ + + ֵBoolean - صǰڻǷǴ +} + +function CurrentByteOrderIsLittleEndian: Boolean; +{* صǰڻǷСˣҲǷеĸֽڴ洢ڽϸߵʼַ x86 벿Ĭ ARM + + + ޣ + + ֵBoolean - صǰڻǷС +} + +function Int64ToBigEndian(Value: Int64): Int64; +{* ȷ 64 λзֵΪˣС˻лת + + + Value: Int64 - ת 64 λз + + ֵInt64 - شֵ +} + +function Int32ToBigEndian(Value: Integer): Integer; +{* ȷ 32 λзֵΪˣС˻лת + + + Value: Integer - ת 32 λз + + ֵInteger - شֵ +} + +function Int16ToBigEndian(Value: SmallInt): SmallInt; +{* ȷ 16 λзֵΪˣС˻лת + + + Value: SmallInt - ת 16 λз + + ֵSmallInt - شֵ +} + +function Int64ToLittleEndian(Value: Int64): Int64; +{* ȷ 64 λзֵΪСˣڴ˻лת + + + Value: Int64 - ת 64 λз + + ֵInt64 - شֵ +} + +function Int32ToLittleEndian(Value: Integer): Integer; +{* ȷ 32 λзֵΪСˣڴ˻лת + + + Value: Integer - ת 32 λз + + ֵInteger - Сֵ +} + +function Int16ToLittleEndian(Value: SmallInt): SmallInt; +{* ȷ 16 λзֵΪСˣڴ˻лת + + + Value: SmallInt - ת 16 λз + + ֵSmallInt - Сֵ +} + +function UInt64ToBigEndian(Value: TUInt64): TUInt64; +{* ȷ 64 λ޷ֵΪˣС˻лת + + + Value: TUInt64 - ת 64 λ޷ + + ֵTUInt64 - شֵ +} + +function UInt32ToBigEndian(Value: Cardinal): Cardinal; +{* ȷ 32 λ޷ֵΪˣС˻лת + + + Value: Cardinal - ת 32 λ޷ + + ֵCardinal - شֵ +} + +function UInt16ToBigEndian(Value: Word): Word; +{* ȷ 16 λ޷ֵΪˣС˻лת + + + Value: Word - ת 16 λ޷ + + ֵWord - شֵ +} + +function UInt64ToLittleEndian(Value: TUInt64): TUInt64; +{* ȷ 64 λ޷ֵΪСˣڴ˻лת + + + Value: TUInt64 - ת 64 λ޷ + + ֵTUInt64 - شֵ +} + +function UInt32ToLittleEndian(Value: Cardinal): Cardinal; +{* ȷ 32 λ޷ֵΪСˣڴ˻лת + + + Value: Cardinal - ת 32 λ޷ + + ֵCardinal - Сֵ +} + +function UInt16ToLittleEndian(Value: Word): Word; +{* ȷ 16 λ޷ֵΪСˣڴ˻лת + + + Value: Word - ת 16 λ޷ + + ֵWord - Сֵ +} + +function Int64HostToNetwork(Value: Int64): Int64; +{* 64 λзֵֽ˳תΪֽ˳С˻лת + + + Value: Int64 - ת 64 λз + + ֵInt64 - ֽ˳ֵ +} + +function Int32HostToNetwork(Value: Integer): Integer; +{* 32 λзֵֽ˳תΪֽ˳С˻лת + + + Value: Integer - ת 32 λз + + ֵInteger - ֽ˳ֵ +} + +function Int16HostToNetwork(Value: SmallInt): SmallInt; +{* 16 λзֵֽ˳תΪֽ˳С˻лת + + + Value: SmallInt - ת 16 λз + + ֵSmallInt - ֽ˳ֵ +} + +function Int64NetworkToHost(Value: Int64): Int64; +{* 64 λзֵֽ˳תΪֽ˳С˻лת + + + Value: Int64 - ת 64 λз + + ֵInt64 - ֽ˳ֵ +} + +function Int32NetworkToHost(Value: Integer): Integer; +{* 32 λзֵֽ˳תΪֽ˳С˻лת + + + Value: Integer - ת 32 λз + + ֵInteger - ֽ˳ֵ +} + +function Int16NetworkToHost(Value: SmallInt): SmallInt; +{* 16 λзֵֽ˳תΪֽ˳С˻лת + + + Value: SmallInt - ת 16 λз + + ֵSmallInt - ֽ˳ֵ +} + +function UInt64HostToNetwork(Value: TUInt64): TUInt64; +{* 64 λ޷ֵֽ˳תΪֽ˳С˻лת + + + Value: TUInt64 - ת 64 λ޷ + + ֵTUInt64 - ֽ˳ֵ +} + +function UInt32HostToNetwork(Value: Cardinal): Cardinal; +{* 32 λ޷ֵֽ˳תΪֽ˳С˻лת + + + Value: Cardinal - ת 32 λ޷ + + ֵCardinal - ֽ˳ֵ +} + +function UInt16HostToNetwork(Value: Word): Word; +{* 16 λ޷ֵֽ˳תΪֽ˳С˻лת + + + Value: Word - ת 16 λ޷ + + ֵWord - ֽ˳ֵ +} + +function UInt64NetworkToHost(Value: TUInt64): TUInt64; +{* 64 λ޷ֵֽ˳תΪֽ˳С˻лת + + + Value: TUInt64 - ת 64 λ޷ + + ֵTUInt64 - ֽ˳ֵ +} + +function UInt32NetworkToHost(Value: Cardinal): Cardinal; +{* 32 λ޷ֵֽ˳תΪֽ˳С˻лת + + + Value: Cardinal - ת 32 λ޷ + + ֵCardinal - ֽ˳ֵ +} + +function UInt16NetworkToHost(Value: Word): Word; +{* 16 λ޷ֵֽ˳תΪֽ˳С˻лת + + + Value: Word - ת 16 λ޷ + + ֵWord - ֽ˳ֵ +} + +procedure MemoryNetworkToHost(Mem: Pointer; MemByteLen: Integer); +{* һƬڴֽ˳תΪֽ˳С˻лת + ÷ӦóϽ٣¶ġֽתѾ㹻 + + + Mem: Pointer - תݿַ + MemByteLen: Integer - תݿֽڳ + + ֵޣ +} + +procedure MemoryHostToNetwork(Mem: Pointer; MemByteLen: Integer); +{* һƬڴֽ˳תΪֽ˳С˻лת + ÷ӦóϽ٣¶ġֽתѾ㹻 + + + Mem: Pointer - תݿַ + MemByteLen: Integer - תݿֽڳ + + ֵޣ +} + +procedure ReverseMemory(Mem: Pointer; MemByteLen: Integer); +{* ֽ˳һڴ飬ֽڲ䡣 + + + Mem: Pointer - õݿַ + MemByteLen: Integer - õݿֽڳ + + ֵޣ +} + +function ReverseBitsInInt8(V: Byte): Byte; +{* һֽڲλݡ + + + V: Byte - õһֽ + + ֵByte - صֵ +} + +function ReverseBitsInInt16(V: Word): Word; +{* öֽڼڲλݡ + + + V: Word - õĶֽ + + ֵWord - صֵ +} + +function ReverseBitsInInt32(V: Cardinal): Cardinal; +{* ֽڼڲλݡ + + + V: Cardinal - õֽ + + ֵCardinal - صֵ +} + +function ReverseBitsInInt64(V: Int64): Int64; +{* ðֽڼڲλݡ + + + V: Int64 - õİֽ + + ֵInt64 - صֵ +} + +procedure ReverseMemoryWithBits(Mem: Pointer; MemByteLen: Integer); +{* ֽ˳һڴ飬ÿֽҲ + + + Mem: Pointer - õݿַ + MemByteLen: Integer - õݿֽڳ + + ֵޣ +} + +procedure MemoryAnd(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +{* 鳤ͬڴ AMem BMem λ룬 ResMem У߿ͬ + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + ResMem: Pointer - ݿַ + + ֵޣ +} + +procedure MemoryOr(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +{* 鳤ͬڴ AMem BMem λ򣬽 ResMem У߿ͬ + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + ResMem: Pointer - ݿַ + + ֵޣ +} + +procedure MemoryXor(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +{* 鳤ͬڴ AMem BMem λ򣬽 ResMem У߿ͬ + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + ResMem: Pointer - ݿַ + + ֵޣ +} + +procedure MemoryNot(Mem: Pointer; MemByteLen: Integer; ResMem: Pointer); +{* һڴ AMem ȡ ResMem У߿ͬ + + + Mem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + ResMem: Pointer - ݿַ + + ֵޣ +} + +procedure MemoryShiftLeft(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; BitCount: Integer); +{* AMem ڴ BitCount λ BMemڴַλƣλ 0߿ȡ + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + BitCount: Integer - Ƶλ + + ֵޣ +} + +procedure MemoryShiftRight(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; BitCount: Integer); +{* AMem ڴ BitCount λ BMemڴַλƣλ 0߿ȡ + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + BitCount: Integer - Ƶλ + + ֵޣ +} + +function MemoryIsBitSet(Mem: Pointer; N: Integer): Boolean; +{* ڴij Bit λǷ 1ڴַλ 0ֽڻұΪ 0 + + + Mem: Pointer - ݿַ + N: Integer - λ + + ֵBoolean - Ƿ 1 +} + +procedure MemorySetBit(Mem: Pointer; N: Integer); +{* ڴij Bit λ 1ڴַλ 0ֽڻұΪ 0 + + + Mem: Pointer - ݿַ + N: Integer - λ + + ֵޣ +} + +procedure MemoryClearBit(Mem: Pointer; N: Integer); +{* ڴij Bit λ 0ڴַλ 0ֽڻұΪ 0 + + + Mem: Pointer - ݿַ + N: Integer - λ + + ֵޣ +} + +function MemoryGetHighBits(Mem: Pointer; MemByteLen: Integer): Integer; +{* ڴ 1 ߶λǵڼλߡָ͵ַû 1 -1 + ڴӵַ͵߱Ϊ 8 * MemByteLen - 1 0 ôλĩֽڵλ 0 λ + + + Mem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + + ֵInteger - 1 λ +} + +function MemoryGetLowBits(Mem: Pointer; MemByteLen: Integer): Integer; +{* ڴ 1 Ͷλǵڼλָ͡ߵַû 1 -1 + ڴӵַ͵߱Ϊ 8 * MemByteLen - 1 0 ôλĩֽڵλ 0 λ + + + Mem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + + ֵInteger - 1 λ +} + +function MemoryToBinStr(Mem: Pointer; MemByteLen: Integer; Sep: Boolean = False): string; +{* һڴݴӵ͵ֽ˳ΪַSep ʾֽ֮Ƿոָ + + + Mem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + Sep: Boolean - ֽ֮Ƿÿոָ + + ֵstring - ضַ +} + +procedure MemorySwap(AMem: Pointer; BMem: Pointer; MemByteLen: Integer); +{* ͬȵڴݣͬڴʲô + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + + ֵޣ +} + +function MemoryCompare(AMem: Pointer; BMem: Pointer; MemByteLen: Integer): Integer; +{* ޷ķʽȽڴ棬 10-1ͬڴֱӷ 0 + + + AMem: Pointer - Ƚϵݿַһ + BMem: Pointer - Ƚϵݿַ + MemByteLen: Integer - Ƚϵݿֽڳ + + ֵInteger - رȽϵĽ +} + +procedure MemoryQuickSort(Mem: Pointer; ElementByteSize: Integer; + ElementCount: Integer; CompareProc: TCnMemSortCompareProc = nil); +{* Թ̶СԪص + + + Mem: Pointer - ݿַ + ElementByteSize: Integer - Ԫֽڳ + ElementCount: Integer - ݿԪصĸ + CompareProc: TCnMemSortCompareProc - ԪرȽϵĻص + + ֵޣ +} + +function UInt8ToBinStr(V: Byte): string; +{* һ 8 λ޷תΪַ + + + V: Byte - ת 8 λ޷ + + ֵstring - ضַ +} + +function UInt16ToBinStr(V: Word): string; +{* һ 16 λ޷תΪַ + + + V: Word - ת 16 λ޷ + + ֵstring - ضַ +} + +function UInt32ToBinStr(V: Cardinal): string; +{* һ 32 λ޷תΪַ + + + V: Cardinal - ת 32 λ޷ + + ֵstring - ضַ +} + +function UInt32ToStr(V: Cardinal): string; +{* һ 32 λ޷תΪʮַ + + + V: Cardinal - ת 32 λ޷ + + ֵstring - ʮַ +} + +function UInt64ToBinStr(V: TUInt64): string; +{* һ 64 λ޷תΪַ + + + V: TUInt64 - ת 64 λ޷ + + ֵstring - ضַ +} + +function StrToUInt(const S: string): Cardinal; +{* ַתΪ 32 λ޷ + + + const S: string - תַ + + ֵCardinal - ת +} + +function HexToInt(const Hex: string): Integer; overload; +{* һʮַתΪͣʺϽ϶ 2 ַַ + + + const Hex: string - תʮַ + + ֵInteger - +} + +function HexToInt(Hex: PChar; CharLen: Integer): Integer; overload; +{* һʮַָָתΪͣʺϽ϶ 2 ַַ + + + Hex: PChar - תʮַַ + CharLen: Integer - ַ + + ֵInteger - +} + +function IsHexString(const Hex: string): Boolean; +{* жһַǷϷʮִַСд + + + const Hex: string - жϵʮַ + + ֵBoolean - ǷǺϷʮַ +} + +function DataToHex(InData: Pointer; ByteLength: Integer; UseUpperCase: Boolean = True): string; +{* ڴתΪʮַڴλݳַ󷽣൱ֽ˳ + UseUpperCase ݵĴСд + + + InData: Pointer - תݿַ + ByteLength: Integer - תݿֽڳ + UseUpperCase: Boolean - ʮַڲǷд + + ֵstring - ʮַ +} + +function HexToData(const Hex: string; OutData: Pointer = nil): Integer; +{* ʮַתΪڴ飬ַ󷽵ݳڴλ൱ֽ˳ + ʮַΪתʧʱ׳쳣תɹֽ + ע OutData Ӧָ㹻תݵֽڳΪ Length(Hex) div 2 + nilֻֽڳȣʽת + + + const Hex: string - תʮַ + OutData: Pointer - ֽڳӦΪ Length(Hex) div 2 + + ֵInteger - תֽڳ +} + +function StringToHex(const Data: string; UseUpperCase: Boolean = True): string; +{* ַתΪʮַUseUpperCase ݵĴСд + + + const Data: string - תַ + UseUpperCase: Boolean - ʮַڲǷд + + ֵstring - תʮַ +} + +function HexToString(const Hex: string): string; +{* ʮַתΪַʮַΪתʧʱ׳쳣 + + + const Hex: string - תʮַ + + ֵstring - תַ +} + +function HexToAnsiStr(const Hex: AnsiString): AnsiString; +{* ʮַתΪַʮַΪתʧʱ׳쳣 + + + const Hex: AnsiString - תʮַ + + ֵAnsiString - תַ +} + +function AnsiStrToHex(const Data: AnsiString; UseUpperCase: Boolean = True): AnsiString; +{* AnsiString תΪʮַUseUpperCase ݵĴСд + + + const Data: AnsiString - תַ + UseUpperCase: Boolean - ʮַڲǷд + + ֵAnsiString - ʮַ +} + +function BytesToHex(const Data: TBytes; UseUpperCase: Boolean = True): string; +{* ֽתΪʮַ±λݳַ󷽣൱ֽ˳ + UseUpperCase ݵĴСд + + + const Data: TBytes - תֽ + UseUpperCase: Boolean - ʮַڲǷд + + ֵstring - ʮַ +} + +function HexToBytes(const Hex: string): TBytes; +{* ʮַתΪֽ飬ַߵݳ±λ൱ֽ˳ + ַΪתʧʱ׳쳣 + + + const Hex: string - תʮַ + + ֵTBytes - ½ֽ +} + +function StreamToHex(Stream: TStream; UseUpperCase: Boolean = True): string; +{* еȫݴͷתΪʮַ + + + Stream: TStream - + UseUpperCase: Boolean - ʮַڲǷд + + ֵstring - ʮַ +} + +function HexToStream(const Hex: string; Stream: TStream): Integer; +{* ʮַתдУдֽ + + + const Hex: string - תʮַ + Stream: TStream - д + + ֵInteger - дֽ +} + +function WriteBytesToStream(const Data: TBytes; Stream: TStream): Integer; +{* ֽдУдֽ + + + const Data: TBytes - дֽ + Stream: TStream - д + + ֵInteger - дֽ +} + +procedure ReverseBytes(Data: TBytes); +{* ֽ˳һֽݡ + + + Data: TBytes - õֽ + + ֵޣ +} + +function CloneBytes(const Data: TBytes): TBytes; +{* һµֽ + + + const Data: TBytes - Ƶֽ + + ֵTBytes - ½ֽ +} + +function StreamToBytes(Stream: TStream): TBytes; +{* ͷȫֽ飬½ֽ顣 + + + Stream: TStream - + + ֵTBytes - ½ֽ +} + +function BytesToStream(const Data: TBytes; OutStream: TStream): Integer; +{* ֽдԭʼдֽ + + + const Data: TBytes - дֽ + OutStream: TStream - д + + ֵInteger - дֽ +} + +function AnsiToBytes(const Str: AnsiString): TBytes; +{* AnsiString ֱתΪֽ飬롣 + + + const Str: AnsiString - תַ + + ֵTBytes - תֽ +} + +function BytesToAnsi(const Data: TBytes): AnsiString; +{* ֱֽתΪ AnsiString롣 + + + const Data: TBytes - תֽ + + ֵAnsiString - תַ +} + +function BytesToString(const Data: TBytes): string; +{* ֽתΪ stringڲ Byte ֵΪ Char롣 + + + const Data: TBytes - תֽ + + ֵstring - תַ +} + +function MemoryToString(Mem: Pointer; MemByteLen: Integer): string; +{* ڴתΪ stringڲֽڸֵ롣 + + + Mem: Pointer - תݿַ + MemByteLen: Integer - תݿֽڳ + + ֵstring - תַ +} + +function BitsToString(Bits: TBits): string; +{* λתΪ 0 1 ַ + + + Bits: TBits - תλ + + ֵstring - תַ +} + +function ConcatBytes(const A: TBytes; const B: TBytes): TBytes; overload; +{* A B ֽ˳ƴ÷һֽ飬A B ֲ䡣 + + + const A: TBytes - ƴӵֽһ + const B: TBytes - ƴӵֽ + + ֵTBytes - ƴӵֽ +} + +function ConcatBytes(const A: TBytes; const B: TBytes; const C: TBytes): TBytes; overload; +{* A B C ֽ˳ƴ÷һֽ飬A B C ֲ䡣 + + + const A: TBytes - ƴӵֽһ + const B: TBytes - ƴӵֽ + const C: TBytes - ƴӵֽ + + ֵTBytes - ƴӵֽ +} + +function ConcatBytes(const A: TBytes; const B: TBytes; const C: TBytes; const D: TBytes): TBytes; overload; +{* A B C D ĸֽ˳ƴ÷һֽ飬A B C D ֲ䡣 + + + const A: TBytes - ƴӵֽһ + const B: TBytes - ƴӵֽ + const C: TBytes - ƴӵֽ + const D: TBytes - ƴӵֽ + + ֵTBytes - ƴӵֽ +} + +function NewZeroBytes(ByteLen: Integer): TBytes; +{* ByteLen ֽڳȵֽ顣 + + + ByteLen: Integer - ֽֽڳ + + ֵTBytes - ȫֽ +} + +function ConcatBytesMemory(const A: TBytes; Data: Pointer; DataByteLen: Integer): TBytes; +{* һֽһƬڴƴ÷һ飬ԭֽڴ䡣 + + + const A: TBytes - ƴӵֽ + Data: Pointer - ƴӵݿַ + DataByteLen: Integer - ƴӵݿֽڳ + + ֵTBytes - ƴӵֽ +} + +function NewBytesFromMemory(Data: Pointer; DataByteLen: Integer): TBytes; +{* ½һֽ飬һƬڴݹ + + + Data: Pointer - ݿַ + DataByteLen: Integer - ݿֽڳ + + ֵTBytes - ½ֽ +} + +procedure PutBytesToMemory(const Data: TBytes; Mem: Pointer; MaxByteSize: Integer = 0); +{* һֽдָڴд + + + const Data: TBytes - ֽ + Mem: Pointer - дݿַ + MaxByteSize: Integer - дֽ0 ʾ + + ֵޣ +} + +function CompareBytes(const A: TBytes; const B: TBytes): Boolean; overload; +{* ȽֽǷͬ + + + const A: TBytes - Ƚϵֽһ + const B: TBytes - Ƚϵֽ + + ֵBoolean - رȽϽǷͬ +} + +function CompareBytes(const A: TBytes; const B: TBytes; MaxLength: Integer): Boolean; overload; +{* Ƚֽǰ MaxLength ֽڵǷͬ + + + const A: TBytes - Ƚϵֽһ + const B: TBytes - Ƚϵֽ + MaxLength: Integer - Ƚϵֽ + + ֵBoolean - رȽϽǷͬ +} + +function CompareBytesWithDiffIndex(const A, B: TBytes; out DiffIndex: Integer): Boolean; +{* ȽֽǷͬ + ݲͬʱDiffIndex صһȵֽ -1 + + + const A: TBytes - Ƚϵֽһ + const B: TBytes - Ƚϵֽ + out DiffIndex: Integer - صһȵֽ + + ֵBoolean - رȽϽǷͬ +} + +function MoveMost(const Source; var Dest; ByteLen: Integer; MostLen: Integer): Integer; +{* Source ƶ ByteLen Ҳ MostLen ֽڵ Dest Уʵƶֽ + ByteLen С MostLen Dest 0Ҫ Dest MostLen + + + const Source - ƶԴλáַ + var Dest - ƶĿλáַҪ MostLen ֽ + ByteLen: Integer - ƶֽ + MostLen: Integer - ƶֽ + + ֵInteger - ʵƶֽ +} + +// =============================== =================================== + +function SarInt8(V: ShortInt; ShiftCount: Integer): ShortInt; +{* һ 8 λзƣҲ÷λλơ + + + V: ShortInt - Ƶ 8 λз + ShiftCount: Integer - Ƶλ + + ֵShortInt - λֵ +} + +function SarInt16(V: SmallInt; ShiftCount: Integer): SmallInt; +{* һ 16 λзƣҲ÷λλơ + + + V: SmallInt - Ƶ 16 λз + ShiftCount: Integer - Ƶλ + + ֵSmallInt - λֵ +} + +function SarInt32(V: Integer; ShiftCount: Integer): Integer; +{* һ 32 λзƣҲ÷λλơ + + + V: Integer - Ƶ 32 λз + ShiftCount: Integer - Ƶλ + + ֵInteger - λֵ +} + +function SarInt64(V: Int64; ShiftCount: Integer): Int64; +{* һ 64 λзƣҲ÷λλơ + + + V: Int64 - Ƶ 64 λз + ShiftCount: Integer - Ƶλ + + ֵInt64 - λֵ +} + +// ================ ִʱ̶ if жϵIJ߼ =============== + +procedure ConstTimeConditionalSwap8(CanSwap: Boolean; var A: Byte; var B: Byte); +{* 8 λͱִʱ̶CanSwap Ϊ True ʱʵʩ A B + + + CanSwap: Boolean - Ƿ񽻻 + var A: Byte - 8 λͱһ + var B: Byte - 8 λͱ + + ֵޣ +} + +procedure ConstTimeConditionalSwap16(CanSwap: Boolean; var A: Word; var B: Word); +{* 16 λͱִʱ̶CanSwap Ϊ True ʱʵʩ A B + + + CanSwap: Boolean - Ƿ񽻻 + var A: Word - 16 λͱһ + var B: Word - 16 λͱ + + ֵޣ +} + +procedure ConstTimeConditionalSwap32(CanSwap: Boolean; var A: Cardinal; var B: Cardinal); +{* 32 λͱִʱ̶CanSwap Ϊ True ʱʵʩ A B + + + CanSwap: Boolean - Ƿ񽻻 + var A: Cardinal - 32 λͱһ + var B: Cardinal - 32 λͱ + + ֵޣ +} + +procedure ConstTimeConditionalSwap64(CanSwap: Boolean; var A: TUInt64; var B: TUInt64); +{* 64 λͱִʱ̶CanSwap Ϊ True ʱʵʩ A B + + + CanSwap: Boolean - Ƿ񽻻 + var A: TUInt64 - 64 λͱһ + var B: TUInt64 - 64 λͱ + + ֵޣ +} + +function ConstTimeEqual8(A: Byte; B: Byte): Boolean; +{* ֽڵִʱ̶ıȽϣ CPU ָתԤ⵼µִʱ죬ͬʱ True + + + A: Byte - Ƚϵ 8 λͱһ + B: Byte - Ƚϵ 8 λͱ + + ֵBoolean - Ƿ +} + +function ConstTimeEqual16(A: Word; B: Word): Boolean; +{* ˫ֽڵִʱ̶ıȽϣ CPU ָתԤ⵼µִʱ죬ͬʱ True + + + A: Word - Ƚϵ 16 λͱһ + B: Word - Ƚϵ 16 λͱ + + ֵBoolean - Ƿ +} + +function ConstTimeEqual32(A: Cardinal; B: Cardinal): Boolean; +{* ֽڵִʱ̶ıȽϣ CPU ָתԤ⵼µִʱ죬ͬʱ True + + + A: Cardinal - Ƚϵ 32 λͱһ + B: Cardinal - Ƚϵ 32 λͱ + + ֵBoolean - Ƿ +} + +function ConstTimeEqual64(A: TUInt64; B: TUInt64): Boolean; +{* ֽڵִʱ̶ıȽϣ CPU ָתԤ⵼µִʱ죬ͬʱ True + + + A: TUInt64 - Ƚϵ 64 λͱһ + B: TUInt64 - Ƚϵ 64 λͱ + + ֵBoolean - Ƿ +} + +function ConstTimeCompareMem(P1, P2: Pointer; ByteLength: Integer): Boolean; +{* ͬȵڴִʱ̶ıȽϣͬʱ True + + + P1: Pointer - Ƚϵĵһڴַ + P2: Pointer - Ƚϵĵڶڴַ + ByteLength: Integer - Ƚϵֽڳ + + ֵBoolean - Ƿ +} + +function ConstTimeCompareBytes(const A, B: TBytes): Boolean; +{* ִгͬʱֽĺ㶨ʱıȽϣ糤Ȳֱͬӷ Falseݾͬ򷵻 True + + + const A: TBytes - Ƚϵֽһ + const B: TBytes - Ƚϵֽ + + ֵBoolean - Ƿͬ +} + +function ConstTimeExpandBoolean8(V: Boolean): Byte; +{* V ֵ 8 λȫ 1 ȫ 0 + + + V: Boolean - Ƿ񷵻ȫ 1 + + ֵByte - $FF 0 +} + +function ConstTimeExpandBoolean16(V: Boolean): Word; +{* V ֵ 16 λȫ 1 ȫ 0 + + + V: Boolean - Ƿ񷵻ȫ 1 + + ֵWord - $FFFF 0 +} + +function ConstTimeExpandBoolean32(V: Boolean): Cardinal; +{* V ֵ 32 λȫ 1 ȫ 0 + + + V: Boolean - Ƿ񷵻ȫ 1 + + ֵCardinal - $FFFFFFFF 0 +} + +function ConstTimeExpandBoolean64(V: Boolean): TUInt64; +{* V ֵ 64 λȫ 1 ȫ 0 + + + V: Boolean - Ƿ񷵻ȫ 1 + + ֵTUInt64 - $FFFFFFFFFFFFFFFF 0 +} + +function ConstTimeConditionalSelect8(Condition: Boolean; A: Byte; B: Byte): Byte; +{* ֽڱִʱ̶жѡCondtion Ϊ True ʱ A򷵻 B + + + Condition: Boolean - Ƿѡ A ҲDzһ + A: Byte - ѡ 8 λһ + B: Byte - ѡ 8 λ + + ֵByte - ѡ 8 λ +} + +function ConstTimeConditionalSelect16(Condition: Boolean; A: Word; B: Word): Word; +{* ˫ֽڱִʱ̶жѡCondtion Ϊ True ʱ A򷵻 B + + + Condition: Boolean - Ƿѡ A ҲDzһ + A: Word - ѡ 16 λһ + B: Word - ѡ 16 λ + + ֵWord - ѡ 16 λ +} + +function ConstTimeConditionalSelect32(Condition: Boolean; A: Cardinal; B: Cardinal): Cardinal; +{* ֽڱִʱ̶жѡCondtion Ϊ True ʱ A򷵻 B + + + Condition: Boolean - Ƿѡ A ҲDzһ + A: Cardinal - ѡ 32 λһ + B: Cardinal - ѡ 32 λ + + ֵCardinal - ѡ 32 λ +} + +function ConstTimeConditionalSelect64(Condition: Boolean; A: TUInt64; B: TUInt64): TUInt64; +{* ֽڱִʱ̶жѡCondtion Ϊ True ʱ A򷵻 B + + + Condition: Boolean - Ƿѡ A ҲDzһ + A: TUInt64 - ѡ 64 λһ + B: TUInt64 - ѡ 64 λ + + ֵTUInt64 - ѡ 64 λ +} + +// ================ ִʱ̶ if жϵIJ߼ =============== + +{$IFDEF MSWINDOWS} + +// ĸΪ Intel ֻ֧࣬ 32 λ 64 λ Intel CPUӦCPUX86 CPUX64 + +procedure Int64DivInt32Mod(A: Int64; B: Integer; + var DivRes: Integer; var ModRes: Integer); +{* 64 λз 32 λз̷ DivRes ModRes + б֤ 32 λΧڣ쳣 + + + A: Int64 - + B: Integer - + var DivRes: Integer - + var ModRes: Integer - + + ֵޣ +} + +procedure UInt64DivUInt32Mod(A: TUInt64; B: Cardinal; + var DivRes: Cardinal; var ModRes: Cardinal); +{* 64 λ޷ 32 λ޷̷ DivRes ModRes + б֤ 32 λΧڣ쳣 + + + A: TUInt64 - + B: Cardinal - + var DivRes: Cardinal - + var ModRes: Cardinal - + + ֵޣ +} + +procedure Int128DivInt64Mod(ALo: Int64; AHi: Int64; B: Int64; + var DivRes: Int64; var ModRes: Int64); +{* 128 λз 64 λз̷ DivRes ModRes + б֤ 64 λΧڣ쳣 + + + ALo: Int64 - 64 λ + AHi: Int64 - 64 λ + B: Int64 - + var DivRes: Int64 - + var ModRes: Int64 - + + ֵޣ +} + +procedure UInt128DivUInt64Mod(ALo: TUInt64; AHi: TUInt64; B: TUInt64; + var DivRes: TUInt64; var ModRes: TUInt64); +{* 128 λ޷ 64 λ޷̷ DivRes ModRes + б֤ 64 λΧڣ쳣 + + + ALo: TUInt64 - 64 λ + AHi: TUInt64 - 64 λ + B: TUInt64 - + var DivRes: TUInt64 - + var ModRes: TUInt64 - + + ֵޣ +} + +{$ENDIF} + +function IsUInt128BitSet(Lo: TUInt64; Hi: TUInt64; N: Integer): Boolean; +{* Int64 ƴɵ 128 λ֣ص N λǷΪ 1N 0 127 + + + Lo: TUInt64 - жϵĵ 64 λ + Hi: TUInt64 - жϵĸ 64 λ + N: Integer - жϵλ + + ֵBoolean - ǷΪ 1 +} + +procedure SetUInt128Bit(var Lo: TUInt64; var Hi: TUInt64; N: Integer); +{* Int64 ƴɵ 128 λ֣õ N λΪ 1N 0 127 + + + var Lo: TUInt64 - õĵ 64 λ + var Hi: TUInt64 - õĸ 64 λ + N: Integer - õλ + + ֵޣ +} + +procedure ClearUInt128Bit(var Lo: TUInt64; var Hi: TUInt64; N: Integer); +{* Int64 ƴɵ 128 λ֣ N λN 0 127 + + + var Lo: TUInt64 - õĵ 64 λ + var Hi: TUInt64 - õĸ 64 λ + N: Integer - õλ + + ֵޣ +} + +function UnsignedAddWithLimitRadix(A: Cardinal; B: Cardinal; C: Cardinal; + var R: Cardinal; L: Cardinal; H: Cardinal): Cardinal; +{* Ƶ޷żӷA + B + C R Уؽλֵ + ȷ L H ıڣûȷ H LΡ + úַӳ䣬 C һǽλ + + + A: Cardinal - һ + B: Cardinal - + C: Cardinal - һǽλ + var R: Cardinal - + L: Cardinal - ͵ + H: Cardinal - ͵ + + ֵCardinal - Ƿнλ +} + +// =========================== ѭλ ==================================== + +// ע N Ӧ (0, A λ) ڣ N Ϊ 0 A λʱֵӦΪ A +// N ʱࣨΪͲȲͬ 32 λ AN Ϊ 33 ʱֵ N Ϊ 1 ʱķֵ + +function RotateLeft16(A: Word; N: Integer): Word; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 16 λѭ N λ + + + A: Word - ѭƵ 16 λ + N: Integer - ѭƵλ + + ֵWord - λֵ +} + +function RotateRight16(A: Word; N: Integer): Word; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 16 λѭ N λ + + + A: Word - ѭƵ 16 λ + N: Integer - ѭƵλ + + ֵWord - λֵ +} + +function RotateLeft32(A: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 32 λѭ N λ + + + A: Cardinal - ѭƵ 32 λ + N: Integer - ѭƵλ + + ֵCardinal - λֵ +} + +function RotateRight32(A: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 32 λѭ N λ + + + A: Cardinal - ѭƵ 32 λ + N: Integer - ѭƵλ + + ֵCardinal - λֵ +} + +function RotateLeft64(A: TUInt64; N: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 64 λѭ N λ + + + A: TUInt64 - ѭƵ 64 λ + N: Integer - ѭƵλ + + ֵTUInt64 - λֵ +} + +function RotateRight64(A: TUInt64; N: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 64 λѭ N λ + + + A: TUInt64 - ѭƵ 64 λ + N: Integer - ѭƵλ + + ֵTUInt64 - λֵ +} + +{$IFDEF COMPILER5} + +function BoolToStr(Value: Boolean; UseBoolStrs: Boolean = False): string; +{* תΪַDelphi 5 ûи BoolToStr ϡ + + + Value: Boolean - תIJֵ + UseBoolStrs: Boolean - Ƿ񷵻Ӣĵ + + ֵstring - UseBoolStrs Ϊ False ʱ -1 0򷵻 True False +} + +{$ENDIF} + +implementation + +resourcestring + SCnErrorNotAHexPChar = 'Error: NOT a Hex Char: #%d'; + SCnErrorLengthNotHex = 'Error Length %d: NOT a Hex String'; + SCnErrorLengthNotHexAnsi = 'Error Length %d: NOT a Hex AnsiString'; + +var + FByteOrderIsBigEndian: Boolean = False; + +function CurrentByteOrderIsBigEndian: Boolean; +type + TByteOrder = packed record + case Boolean of + False: (C: array[0..1] of Byte); + True: (W: Word); + end; +var + T: TByteOrder; +begin + T.W := $00CC; + Result := T.C[1] = $CC; +end; + +function CurrentByteOrderIsLittleEndian: Boolean; +begin + Result := not CurrentByteOrderIsBigEndian; +end; + +function ReverseInt64(Value: Int64): Int64; +var + Lo, Hi: Cardinal; + Rec: Int64Rec; +begin + Lo := Int64Rec(Value).Lo; + Hi := Int64Rec(Value).Hi; + Lo := ((Lo and $000000FF) shl 24) or ((Lo and $0000FF00) shl 8) + or ((Lo and $00FF0000) shr 8) or ((Lo and $FF000000) shr 24); + Hi := ((Hi and $000000FF) shl 24) or ((Hi and $0000FF00) shl 8) + or ((Hi and $00FF0000) shr 8) or ((Hi and $FF000000) shr 24); + Rec.Lo := Hi; + Rec.Hi := Lo; + Result := Int64(Rec); +end; + +function ReverseUInt64(Value: TUInt64): TUInt64; +var + Lo, Hi: Cardinal; + Rec: Int64Rec; +begin + Lo := Int64Rec(Value).Lo; + Hi := Int64Rec(Value).Hi; + Lo := ((Lo and $000000FF) shl 24) or ((Lo and $0000FF00) shl 8) + or ((Lo and $00FF0000) shr 8) or ((Lo and $FF000000) shr 24); + Hi := ((Hi and $000000FF) shl 24) or ((Hi and $0000FF00) shl 8) + or ((Hi and $00FF0000) shr 8) or ((Hi and $FF000000) shr 24); + Rec.Lo := Hi; + Rec.Hi := Lo; + Result := TUInt64(Rec); +end; + +function Int64ToBigEndian(Value: Int64): Int64; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := ReverseInt64(Value); +end; + +function Int32ToBigEndian(Value: Integer): Integer; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := Integer((Value and $000000FF) shl 24) or Integer((Value and $0000FF00) shl 8) + or Integer((Value and $00FF0000) shr 8) or Integer((Value and $FF000000) shr 24); +end; + +function Int16ToBigEndian(Value: SmallInt): SmallInt; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := SmallInt((Value and $00FF) shl 8) or SmallInt((Value and $FF00) shr 8); +end; + +function Int64ToLittleEndian(Value: Int64): Int64; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := ReverseInt64(Value); +end; + +function Int32ToLittleEndian(Value: Integer): Integer; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := Integer((Value and $000000FF) shl 24) or Integer((Value and $0000FF00) shl 8) + or Integer((Value and $00FF0000) shr 8) or Integer((Value and $FF000000) shr 24); +end; + +function Int16ToLittleEndian(Value: SmallInt): SmallInt; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := SmallInt((Value and $00FF) shl 8) or SmallInt((Value and $FF00) shr 8); +end; + +function UInt64ToBigEndian(Value: TUInt64): TUInt64; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := ReverseUInt64(Value); +end; + +function UInt32ToBigEndian(Value: Cardinal): Cardinal; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := Cardinal((Value and $000000FF) shl 24) or Cardinal((Value and $0000FF00) shl 8) + or Cardinal((Value and $00FF0000) shr 8) or Cardinal((Value and $FF000000) shr 24); +end; + +function UInt16ToBigEndian(Value: Word): Word; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := Word((Value and $00FF) shl 8) or Word((Value and $FF00) shr 8); +end; + +function UInt64ToLittleEndian(Value: TUInt64): TUInt64; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := ReverseUInt64(Value); +end; + +function UInt32ToLittleEndian(Value: Cardinal): Cardinal; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := Cardinal((Value and $000000FF) shl 24) or Cardinal((Value and $0000FF00) shl 8) + or Cardinal((Value and $00FF0000) shr 8) or Cardinal((Value and $FF000000) shr 24); +end; + +function UInt16ToLittleEndian(Value: Word): Word; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := Word((Value and $00FF) shl 8) or Word((Value and $FF00) shr 8); +end; + +function Int64HostToNetwork(Value: Int64): Int64; +begin + if not FByteOrderIsBigEndian then + Result := ReverseInt64(Value) + else + Result := Value; +end; + +function Int32HostToNetwork(Value: Integer): Integer; +begin + if not FByteOrderIsBigEndian then + Result := Integer((Value and $000000FF) shl 24) or Integer((Value and $0000FF00) shl 8) + or Integer((Value and $00FF0000) shr 8) or Integer((Value and $FF000000) shr 24) + else + Result := Value; +end; + +function Int16HostToNetwork(Value: SmallInt): SmallInt; +begin + if not FByteOrderIsBigEndian then + Result := SmallInt((Value and $00FF) shl 8) or SmallInt((Value and $FF00) shr 8) + else + Result := Value; +end; + +function Int64NetworkToHost(Value: Int64): Int64; +begin + if not FByteOrderIsBigEndian then + REsult := ReverseInt64(Value) + else + Result := Value; +end; + +function Int32NetworkToHost(Value: Integer): Integer; +begin + if not FByteOrderIsBigEndian then + Result := Integer((Value and $000000FF) shl 24) or Integer((Value and $0000FF00) shl 8) + or Integer((Value and $00FF0000) shr 8) or Integer((Value and $FF000000) shr 24) + else + Result := Value; +end; + +function Int16NetworkToHost(Value: SmallInt): SmallInt; +begin + if not FByteOrderIsBigEndian then + Result := SmallInt((Value and $00FF) shl 8) or SmallInt((Value and $FF00) shr 8) + else + Result := Value; +end; + +function UInt64HostToNetwork(Value: TUInt64): TUInt64; +begin + if CurrentByteOrderIsBigEndian then + Result := Value + else + Result := ReverseUInt64(Value); +end; + +function UInt32HostToNetwork(Value: Cardinal): Cardinal; +begin + if not FByteOrderIsBigEndian then + Result := Cardinal((Value and $000000FF) shl 24) or Cardinal((Value and $0000FF00) shl 8) + or Cardinal((Value and $00FF0000) shr 8) or Cardinal((Value and $FF000000) shr 24) + else + Result := Value; +end; + +function UInt16HostToNetwork(Value: Word): Word; +begin + if not FByteOrderIsBigEndian then + Result := ((Value and $00FF) shl 8) or ((Value and $FF00) shr 8) + else + Result := Value; +end; + +function UInt64NetworkToHost(Value: TUInt64): TUInt64; +begin + if CurrentByteOrderIsBigEndian then + Result := Value + else + Result := ReverseUInt64(Value); +end; + +function UInt32NetworkToHost(Value: Cardinal): Cardinal; +begin + if not FByteOrderIsBigEndian then + Result := Cardinal((Value and $000000FF) shl 24) or Cardinal((Value and $0000FF00) shl 8) + or Cardinal((Value and $00FF0000) shr 8) or Cardinal((Value and $FF000000) shr 24) + else + Result := Value; +end; + +function UInt16NetworkToHost(Value: Word): Word; +begin + if not FByteOrderIsBigEndian then + Result := ((Value and $00FF) shl 8) or ((Value and $FF00) shr 8) + else + Result := Value; +end; + +function ReverseBitsInInt8(V: Byte): Byte; +begin + // 0 1 2 3 4 5 6 7 + V := ((V and $AA) shr 1) or ((V and $55) shl 1); + // 01 23 45 67 + V := ((V and $CC) shr 2) or ((V and $33) shl 2); + // 0123 4567 + V := (V shr 4) or (V shl 4); + Result := V; +end; + +function ReverseBitsInInt16(V: Word): Word; +begin + Result := (ReverseBitsInInt8(V and $00FF) shl 8) + or ReverseBitsInInt8((V and $FF00) shr 8); +end; + +function ReverseBitsInInt32(V: Cardinal): Cardinal; +begin + Result := (ReverseBitsInInt16(V and $0000FFFF) shl 16) + or ReverseBitsInInt16((V and $FFFF0000) shr 16); +end; + +function ReverseBitsInInt64(V: Int64): Int64; +begin + Result := (Int64(ReverseBitsInInt32(V and $00000000FFFFFFFF)) shl 32) + or ReverseBitsInInt32((V and $FFFFFFFF00000000) shr 32); +end; + +procedure ReverseMemory(Mem: Pointer; MemByteLen: Integer); +var + I, L: Integer; + P: PByteArray; + T: Byte; +begin + if (Mem = nil) or (MemByteLen < 2) then + Exit; + + L := MemByteLen div 2; + P := PByteArray(Mem); + for I := 0 to L - 1 do + begin + // I ͵ MemLen - I - 1 + T := P^[I]; + P^[I] := P^[MemByteLen - I - 1]; + P^[MemByteLen - I - 1] := T; + end; +end; + +procedure ReverseMemoryWithBits(Mem: Pointer; MemByteLen: Integer); +var + I: Integer; + P: PByteArray; +begin + if (Mem = nil) or (MemByteLen <= 0) then + Exit; + + ReverseMemory(Mem, MemByteLen); + P := PByteArray(Mem); + + for I := 0 to MemByteLen - 1 do + P^[I] := ReverseBitsInInt8(P^[I]); +end; + +procedure MemoryNetworkToHost(Mem: Pointer; MemByteLen: Integer); +begin + if not FByteOrderIsBigEndian then + ReverseMemory(Mem, MemByteLen); +end; + +procedure MemoryHostToNetwork(Mem: Pointer; MemByteLen: Integer); +begin + if not FByteOrderIsBigEndian then + ReverseMemory(Mem, MemByteLen); +end; + +// N ֽڳȵڴλ +procedure MemoryBitOperation(AMem, BMem, RMem: Pointer; N: Integer; Op: TCnBitOperation); +var + A, B, R: PCnLongWord32Array; + BA, BB, BR: PByteArray; +begin + if N <= 0 then + Exit; + + if (AMem = nil) or ((BMem = nil) and (Op <> boNot)) or (RMem = nil) then + Exit; + + A := PCnLongWord32Array(AMem); + B := PCnLongWord32Array(BMem); + R := PCnLongWord32Array(RMem); + + while (N and (not 3)) <> 0 do + begin + case Op of + boAnd: + R^[0] := A^[0] and B^[0]; + boOr: + R^[0] := A^[0] or B^[0]; + boXor: + R^[0] := A^[0] xor B^[0]; + boNot: // ʱ B + R^[0] := not A^[0]; + end; + + A := PCnLongWord32Array(TCnIntAddress(A) + SizeOf(Cardinal)); + B := PCnLongWord32Array(TCnIntAddress(B) + SizeOf(Cardinal)); + R := PCnLongWord32Array(TCnIntAddress(R) + SizeOf(Cardinal)); + + Dec(N, SizeOf(Cardinal)); + end; + + if N > 0 then + begin + BA := PByteArray(A); + BB := PByteArray(B); + BR := PByteArray(R); + + while N <> 0 do + begin + case Op of + boAnd: + BR^[0] := BA^[0] and BB^[0]; + boOr: + BR^[0] := BA^[0] or BB^[0]; + boXor: + BR^[0] := BA^[0] xor BB^[0]; + boNot: + BR^[0] := not BA^[0]; + end; + + BA := PByteArray(TCnIntAddress(BA) + SizeOf(Byte)); + BB := PByteArray(TCnIntAddress(BB) + SizeOf(Byte)); + BR := PByteArray(TCnIntAddress(BR) + SizeOf(Byte)); + Dec(N); + end; + end; +end; + +procedure MemoryAnd(AMem, BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +begin + MemoryBitOperation(AMem, BMem, ResMem, MemByteLen, boAnd); +end; + +procedure MemoryOr(AMem, BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +begin + MemoryBitOperation(AMem, BMem, ResMem, MemByteLen, boOr); +end; + +procedure MemoryXor(AMem, BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +begin + MemoryBitOperation(AMem, BMem, ResMem, MemByteLen, boXor); +end; + +procedure MemoryNot(Mem: Pointer; MemByteLen: Integer; ResMem: Pointer); +begin + MemoryBitOperation(Mem, nil, ResMem, MemByteLen, boNot); +end; + +procedure MemoryShiftLeft(AMem, BMem: Pointer; MemByteLen: Integer; BitCount: Integer); +var + I, L, N, LB, RB: Integer; + PF, PT: PByteArray; +begin + if (AMem = nil) or (MemByteLen <= 0) or (BitCount = 0) then + Exit; + + if BitCount < 0 then + begin + MemoryShiftRight(AMem, BMem, MemByteLen, -BitCount); + Exit; + end; + + if BMem = nil then + BMem := AMem; + + if (MemByteLen * 8) <= BitCount then // ̫಻ȫ 0 + begin + FillChar(BMem^, MemByteLen, 0); + Exit; + end; + + N := BitCount div 8; // λֽ + RB := BitCount mod 8; // ȥֽںʣµλ + LB := 8 - RB; // ʣµλһֽʣµλ + + PF := PByteArray(AMem); + PT := PByteArray(BMem); + + if RB = 0 then // 飬ð죬Ҫλֽ MemLen - NW + begin + Move(PF^[N], PT^[0], MemByteLen - N); + FillChar(PT^[MemByteLen - N], N, 0); + end + else + begin + // PF^[N] PT^[0] MemLen - N ֽڣֽڼн + L := MemByteLen - N; + PF := PByteArray(TCnIntAddress(PF) + N); + + for I := 1 to L do // ӵλƶȴ͵ + begin + PT^[0] := Byte(PF^[0] shl RB); + if I < L then // һֽ PF^[1] ᳬ + PT^[0] := (PF^[1] shr LB) or PT^[0]; + + PF := PByteArray(TCnIntAddress(PF) + 1); + PT := PByteArray(TCnIntAddress(PT) + 1); + end; + + // ʣµҪ 0 + if N > 0 then + FillChar(PT^[0], N, 0); + end; +end; + +procedure MemoryShiftRight(AMem, BMem: Pointer; MemByteLen: Integer; BitCount: Integer); +var + I, L, N, LB, RB: Integer; + PF, PT: PByteArray; +begin + if (AMem = nil) or (MemByteLen <= 0) or (BitCount = 0) then + Exit; + + if BitCount < 0 then + begin + MemoryShiftLeft(AMem, BMem, MemByteLen, -BitCount); + Exit; + end; + + if BMem = nil then + BMem := AMem; + + if (MemByteLen * 8) <= BitCount then // ̫಻ȫ 0 + begin + FillChar(BMem^, MemByteLen, 0); + Exit; + end; + + N := BitCount div 8; // λֽ + RB := BitCount mod 8; // ȥֽںʣµλ + LB := 8 - RB; // ʣµλһֽʣµλ + + if RB = 0 then // 飬ð죬Ҫλֽ MemLen - N + begin + PF := PByteArray(AMem); + PT := PByteArray(BMem); + + Move(PF^[0], PT^[N], MemByteLen - N); + FillChar(PT^[0], N, 0); + end + else + begin + // PF^[0] PT^[N] MemLen - N ֽڣôӸߴʼֽڼн + L := MemByteLen - N; + + PF := PByteArray(TCnIntAddress(AMem) + L - 1); + PT := PByteArray(TCnIntAddress(BMem) + MemByteLen - 1); + + for I := L downto 1 do // Ӹλλƶȴ + begin + PT^[0] := Byte(PF^[0] shr RB); + if I > 1 then // һֽ PF^[-1] ᳬ + begin + PF := PByteArray(TCnIntAddress(PF) - 1); + PT^[0] := Byte((PF^[0] shl LB) or PT^[0]); + end + else + PF := PByteArray(TCnIntAddress(PF) - 1); + + PT := PByteArray(TCnIntAddress(PT) - 1); + end; + + // ʣµǰҪ 0 + if N > 0 then + FillChar(BMem^, N, 0); + end; +end; + +function MemoryIsBitSet(Mem: Pointer; N: Integer): Boolean; +var + P: PByte; + A, B: Integer; + V: Byte; +begin + if (Mem = nil) or (N < 0) then + raise ERangeError.Create(SRangeError); + + A := N div 8; + B := N mod 8; + P := PByte(TCnIntAddress(Mem) + A); + + V := Byte(1 shl B); + Result := (P^ and V) <> 0; +end; + +procedure MemorySetBit(Mem: Pointer; N: Integer); +var + P: PByte; + A, B: Integer; + V: Byte; +begin + if (Mem = nil) or (N < 0) then + raise ERangeError.Create(SRangeError); + + A := N div 8; + B := N mod 8; + P := PByte(TCnIntAddress(Mem) + A); + + V := Byte(1 shl B); + P^ := P^ or V; +end; + +procedure MemoryClearBit(Mem: Pointer; N: Integer); +var + P: PByte; + A, B: Integer; + V: Byte; +begin + if (Mem = nil) or (N < 0) then + raise ERangeError.Create(SRangeError); + + A := N div 8; + B := N mod 8; + P := PByte(TCnIntAddress(Mem) + A); + + V := not Byte(1 shl B); + P^ := P^ and V; +end; + +function MemoryGetHighBits(Mem: Pointer; MemByteLen: Integer): Integer; +var + I, R, ZO: Integer; + P: PByteArray; +begin + Result := -1; + if (Mem = nil) or (MemByteLen <= 0) then + Exit; + + P := PByteArray(Mem); + ZO := 0; + for I := 0 to MemByteLen - 1 do // ӵ͵ַߵַ + begin + R := GetUInt8HighBits(P^[I]); + if R = -1 then // ֽȫ 0 + begin + ZO := ZO + 8; + end + else // ֽ 1ֹ + begin + ZO := ZO + 8 - R + 1; + Break; + end; + end; + + if ZO = MemByteLen * 8 then // ȫ㣬û 1 + Result := -1 + else + Result := MemByteLen * 8 - ZO; // 1λȥ 0 ĸ +end; + +function MemoryGetLowBits(Mem: Pointer; MemByteLen: Integer): Integer; +var + I, R, ZC: Integer; + P: PByteArray; +begin + Result := -1; + if (Mem = nil) or (MemByteLen <= 0) then + Exit; + + P := PByteArray(Mem); + ZC := 0; + for I := MemByteLen - 1 downto 0 do // Ӹߵַ͵ַ + begin + R := GetUInt8LowBits(P^[I]); + if R = -1 then // ֽȫ 0 + begin + ZC := ZC + 8; + end + else // ֽ 1ֹ + begin + ZC := ZC + R; + Break; + end; + end; + + if ZC = MemByteLen * 8 then // ȫ㣬û 1 + Result := -1 + else + Result := MemByteLen * 8 - ZC; // 1λȥ 0 ĸ +end; + +function MemoryToBinStr(Mem: Pointer; MemByteLen: Integer; Sep: Boolean): string; +var + J, L: Integer; + P: PByteArray; + B: PChar; + + procedure FillAByteToBuf(V: Byte; Buf: PChar); + const + M = $80; + var + I: Integer; + begin + for I := 0 to 7 do + begin + if (V and M) <> 0 then + Buf[I] := '1' + else + Buf[I] := '0'; + V := V shl 1; + end; + end; + +begin + Result := ''; + if (Mem = nil) or (MemByteLen <= 0) then + Exit; + + L := MemByteLen * 8; + if Sep then + L := L + MemByteLen - 1; // мÿոָ + + SetLength(Result, L); + B := PChar(@Result[1]); + P := PByteArray(Mem); + + for J := 0 to MemByteLen - 1 do + begin + FillAByteToBuf(P^[J], B); + if Sep then + begin + B[8] := ' '; + Inc(B, 9); + end + else + Inc(B, 8); + end; +end; + +procedure MemorySwap(AMem, BMem: Pointer; MemByteLen: Integer); +var + A, B: PCnLongWord32Array; + BA, BB: PByteArray; + TC: Cardinal; + TB: Byte; +begin + if (AMem = nil) or (BMem = nil) or (MemByteLen <= 0) then + Exit; + + A := PCnLongWord32Array(AMem); + B := PCnLongWord32Array(BMem); + + if A = B then + Exit; + + while (MemByteLen and (not 3)) <> 0 do + begin + TC := A^[0]; + A^[0] := B^[0]; + B^[0] := TC; + + A := PCnLongWord32Array(TCnIntAddress(A) + SizeOf(Cardinal)); + B := PCnLongWord32Array(TCnIntAddress(B) + SizeOf(Cardinal)); + + Dec(MemByteLen, SizeOf(Cardinal)); + end; + + if MemByteLen > 0 then + begin + BA := PByteArray(A); + BB := PByteArray(B); + + while MemByteLen <> 0 do + begin + TB := BA^[0]; + BA^[0] := BB^[0]; + BB^[0] :=TB; + + BA := PByteArray(TCnIntAddress(BA) + SizeOf(Byte)); + BB := PByteArray(TCnIntAddress(BB) + SizeOf(Byte)); + + Dec(MemByteLen); + end; + end; +end; + +function MemoryCompare(AMem, BMem: Pointer; MemByteLen: Integer): Integer; +var + A, B: PCnLongWord32Array; + BA, BB: PByteArray; +begin + Result := 0; + if ((AMem = nil) and (BMem = nil)) or (AMem = BMem) then // ͬһ + Exit; + + if MemByteLen <= 0 then + Exit; + + if AMem = nil then + begin + Result := -1; + Exit; + end; + if BMem = nil then + begin + Result := 1; + Exit; + end; + + A := PCnLongWord32Array(AMem); + B := PCnLongWord32Array(BMem); + + while (MemByteLen and (not 3)) <> 0 do + begin + if A^[0] > B^[0] then + begin + Result := 1; + Exit; + end + else if A^[0] < B^[0] then + begin + Result := -1; + Exit; + end; + + A := PCnLongWord32Array(TCnIntAddress(A) + SizeOf(Cardinal)); + B := PCnLongWord32Array(TCnIntAddress(B) + SizeOf(Cardinal)); + + Dec(MemByteLen, SizeOf(Cardinal)); + end; + + if MemByteLen > 0 then + begin + BA := PByteArray(A); + BB := PByteArray(B); + + while MemByteLen <> 0 do + begin + if BA^[0] > BB^[0] then + begin + Result := 1; + Exit; + end + else if BA^[0] < BB^[0] then + begin + Result := -1; + Exit; + end; + + BA := PByteArray(TCnIntAddress(BA) + SizeOf(Byte)); + BB := PByteArray(TCnIntAddress(BB) + SizeOf(Byte)); + + Dec(MemByteLen); + end; + end; +end; + +function UInt8ToBinStr(V: Byte): string; +const + M = $80; +var + I: Integer; +begin + SetLength(Result, 8 * SizeOf(V)); + for I := 1 to 8 * SizeOf(V) do + begin + if (V and M) <> 0 then + Result[I] := '1' + else + Result[I] := '0'; + V := V shl 1; + end; +end; + +function UInt16ToBinStr(V: Word): string; +const + M = $8000; +var + I: Integer; +begin + SetLength(Result, 8 * SizeOf(V)); + for I := 1 to 8 * SizeOf(V) do + begin + if (V and M) <> 0 then + Result[I] := '1' + else + Result[I] := '0'; + V := V shl 1; + end; +end; + +function UInt32ToBinStr(V: Cardinal): string; +const + M = $80000000; +var + I: Integer; +begin + SetLength(Result, 8 * SizeOf(V)); + for I := 1 to 8 * SizeOf(V) do + begin + if (V and M) <> 0 then + Result[I] := '1' + else + Result[I] := '0'; + V := V shl 1; + end; +end; + +function UInt32ToStr(V: Cardinal): string; +begin + Result := Format('%u', [V]); +end; + +function UInt64ToBinStr(V: TUInt64): string; +const + M = $8000000000000000; +var + I: Integer; +begin + SetLength(Result, 8 * SizeOf(V)); + + for I := 1 to 8 * SizeOf(V) do + begin + if (V and M) <> 0 then + Result[I] := '1' + else + Result[I] := '0'; + V := V shl 1; + end; +end; + +const + HiDigits: array[0..15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); +const + LoDigits: array[0..15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); + +const + AnsiHiDigits: array[0..15] of AnsiChar = ('0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); +const + AnsiLoDigits: array[0..15] of AnsiChar = ('0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); + +function HexToInt(Hex: PChar; CharLen: Integer): Integer; +var + I, Res: Integer; + C: Char; +begin + Res := 0; + for I := 0 to CharLen - 1 do + begin + C := Hex[I]; + if (C >= '0') and (C <= '9') then + Res := Res * 16 + Ord(C) - Ord('0') + else if (C >= 'A') and (C <= 'F') then + Res := Res * 16 + Ord(C) - Ord('A') + 10 + else if (C >= 'a') and (C <= 'f') then + Res := Res * 16 + Ord(C) - Ord('a') + 10 + else + raise ECnNativeException.CreateFmt(SCnErrorNotAHexPChar, [Ord(C)]); + end; + Result := Res; +end; + +function HexToInt(const Hex: string): Integer; +begin + Result := HexToInt(PChar(Hex), Length(Hex)); +end; + +{$WARNINGS OFF} + +function IsHexString(const Hex: string): Boolean; +var + I, L: Integer; +begin + Result := False; + L := Length(Hex); + if (L <= 0) or ((L and 1) <> 0) then // ջżȶ + Exit; + + for I := 1 to L do + begin + // ע˴ Unicode Ȼ Warningǽ Hex[I] WideChar ֱӽض AnsiChar + // ٽжϣᵼ¡޻ޡ $66$66$66$66 ַУ + // ֱͨ WideChar ֵ ax ˫ֽڵģӼжϣ + if not (Hex[I] in ['0'..'9', 'A'..'F', 'a'..'f']) then + Exit; + end; + Result := True; +end; + +{$WARNINGS ON} + +function DataToHex(InData: Pointer; ByteLength: Integer; UseUpperCase: Boolean = True): string; +var + I: Integer; + B: Byte; +begin + Result := ''; + if ByteLength <= 0 then + Exit; + + SetLength(Result, ByteLength * 2); + if UseUpperCase then + begin + for I := 0 to ByteLength - 1 do + begin + B := PByte(TCnIntAddress(InData) + I * SizeOf(Byte))^; + Result[I * 2 + 1] := HiDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := HiDigits[B and $0F]; + end; + end + else + begin + for I := 0 to ByteLength - 1 do + begin + B := PByte(TCnIntAddress(InData) + I * SizeOf(Byte))^; + Result[I * 2 + 1] := LoDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := LoDigits[B and $0F]; + end; + end; +end; + +function HexToData(const Hex: string; OutData: Pointer): Integer; +var + I, L: Integer; + H: PChar; +begin + L := Length(Hex); + if (L mod 2) <> 0 then + raise ECnNativeException.CreateFmt(SCnErrorLengthNotHex, [L]); + + if OutData = nil then + begin + Result := L div 2; + Exit; + end; + + Result := 0; + H := PChar(Hex); + for I := 1 to L div 2 do + begin + PByte(TCnIntAddress(OutData) + I - 1)^ := Byte(HexToInt(@H[(I - 1) * 2], 2)); + Inc(Result); + end; +end; + +function StringToHex(const Data: string; UseUpperCase: Boolean): string; +var + I, L: Integer; + B: Byte; + Buffer: PChar; +begin + Result := ''; + L := Length(Data); + if L = 0 then + Exit; + + SetLength(Result, L * 2); + Buffer := @Data[1]; + + if UseUpperCase then + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnIntAddress(Buffer) + I * SizeOf(Char))^; + Result[I * 2 + 1] := HiDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := HiDigits[B and $0F]; + end; + end + else + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnIntAddress(Buffer) + I * SizeOf(Char))^; + Result[I * 2 + 1] := LoDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := LoDigits[B and $0F]; + end; + end; +end; + +function HexToString(const Hex: string): string; +var + I, L: Integer; + H: PChar; +begin + L := Length(Hex); + if (L mod 2) <> 0 then + raise ECnNativeException.CreateFmt(SCnErrorLengthNotHex, [L]); + + SetLength(Result, L div 2); + H := PChar(Hex); + for I := 1 to L div 2 do + Result[I] := Chr(HexToInt(@H[(I - 1) * 2], 2)); +end; + +function HexToAnsiStr(const Hex: AnsiString): AnsiString; +var + I, L: Integer; + S: string; +begin + L := Length(Hex); + if (L mod 2) <> 0 then + raise ECnNativeException.CreateFmt(SCnErrorLengthNotHexAnsi, [L]); + + SetLength(Result, L div 2); + for I := 1 to L div 2 do + begin + S := string(Copy(Hex, I * 2 - 1, 2)); + Result[I] := AnsiChar(Chr(HexToInt(S))); + end; +end; + +function AnsiStrToHex(const Data: AnsiString; UseUpperCase: Boolean): AnsiString; +var + I, L: Integer; + B: Byte; + Buffer: PAnsiChar; +begin + Result := ''; + L := Length(Data); + if L = 0 then + Exit; + + SetLength(Result, L * 2); + Buffer := @Data[1]; + + if UseUpperCase then + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnIntAddress(Buffer) + I)^; + Result[I * 2 + 1] := AnsiHiDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := AnsiHiDigits[B and $0F]; + end; + end + else + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnIntAddress(Buffer) + I)^; + Result[I * 2 + 1] := AnsiLoDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := AnsiLoDigits[B and $0F]; + end; + end; +end; + +function BytesToHex(const Data: TBytes; UseUpperCase: Boolean): string; +var + I, L: Integer; + B: Byte; + Buffer: PAnsiChar; +begin + Result := ''; + L := Length(Data); + if L = 0 then + Exit; + + SetLength(Result, L * 2); + Buffer := @Data[0]; + + if UseUpperCase then + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnIntAddress(Buffer) + I)^; + Result[I * 2 + 1] := HiDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := HiDigits[B and $0F]; + end; + end + else + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnIntAddress(Buffer) + I)^; + Result[I * 2 + 1] := LoDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := LoDigits[B and $0F]; + end; + end; +end; + +function HexToBytes(const Hex: string): TBytes; +var + I, L: Integer; + H: PChar; +begin + L := Length(Hex); + if (L mod 2) <> 0 then + raise ECnNativeException.CreateFmt(SCnErrorLengthNotHex, [L]); + + SetLength(Result, L div 2); + H := PChar(Hex); + + for I := 1 to L div 2 do + Result[I - 1] := Byte(HexToInt(@H[(I - 1) * 2], 2)); +end; + +function StreamToHex(Stream: TStream; UseUpperCase: Boolean): string; +var + B: Byte; + I: Integer; +begin + Result := ''; + if Stream.Size > 0 then + begin + Stream.Position := 0; + SetLength(Result, Stream.Size * 2); + I := 1; + if UseUpperCase then + begin + while Stream.Read(B, 1) = 1 do + begin + Result[I] := HiDigits[(B shr 4) and $0F]; + Inc(I); + Result[I] := HiDigits[B and $0F]; + Inc(I); + end; + end + else + begin + while Stream.Read(B, 1) = 1 do + begin + Result[I] := LoDigits[(B shr 4) and $0F]; + Inc(I); + Result[I] := LoDigits[B and $0F]; + Inc(I); + end; + end; + end; +end; + +function HexToStream(const Hex: string; Stream: TStream): Integer; +var + I, L: Integer; + H: PChar; + B: Byte; +begin + Result := 0; + L := Length(Hex); + if (L mod 2) <> 0 then + raise ECnNativeException.CreateFmt(SCnErrorLengthNotHex, [L]); + + H := PChar(Hex); + for I := 1 to L div 2 do + begin + B := Byte(HexToInt(@H[(I - 1) * 2], 2)); + Inc(Result, Stream.Write(B, 1)); + end; +end; + +function WriteBytesToStream(const Data: TBytes; Stream: TStream): Integer; +begin + if Length(Data) > 0 then + Result := Stream.Write(Data[0], Length(Data)) + else + Result := 0; +end; + +procedure ReverseBytes(Data: TBytes); +var + I, L, M: Integer; + T: Byte; +begin + if (Data = nil) or (Length(Data) <= 1) then + Exit; + L := Length(Data); + M := L div 2; + for I := 0 to M - 1 do + begin + // I L - I - 1 + T := Data[I]; + Data[I] := Data[L - I - 1]; + Data[L - I - 1] := T; + end; +end; + +function CloneBytes(const Data: TBytes): TBytes; +begin + if Length(Data) = 0 then + Result := nil + else + begin + SetLength(Result, Length(Data)); + Move(Data[0], Result[0], Length(Data)); + end; +end; + +function StreamToBytes(Stream: TStream): TBytes; +begin + Result := nil; + if (Stream <> nil) and (Stream.Size > 0) then + begin + SetLength(Result, Stream.Size); + Stream.Position := 0; + Stream.Read(Result[0], Stream.Size); + end; +end; + +function BytesToStream(const Data: TBytes; OutStream: TStream): Integer; +begin + Result := 0; + if (Data <> nil) and (Length(Data) > 0) and (OutStream <> nil) then + begin + OutStream.Size := 0; + Result := OutStream.Write(Data[0], Length(Data)); + end; +end; + +function AnsiToBytes(const Str: AnsiString): TBytes; +begin + SetLength(Result, Length(Str)); + if Length(Str) > 0 then + Move(Str[1], Result[0], Length(Str)); +end; + +function BytesToAnsi(const Data: TBytes): AnsiString; +begin + SetLength(Result, Length(Data)); + if Length(Data) > 0 then + Move(Data[0], Result[1], Length(Data)); +end; + +function BytesToString(const Data: TBytes): string; +var + I: Integer; +begin + SetLength(Result, Length(Data)); + for I := 1 to Length(Data) do + Result[I] := Chr(Data[I - 1]); +end; + +function MemoryToString(Mem: Pointer; MemByteLen: Integer): string; +var + P: PByteArray; + I: Integer; +begin + if (Mem = nil) or (MemByteLen <= 0) then + begin + Result := ''; + Exit; + end; + + P := PByteArray(Mem); + SetLength(Result, MemByteLen); + for I := 1 to MemByteLen do + Result[I] := Chr(P^[I - 1]); +end; + +function BitsToString(Bits: TBits): string; +var + I: Integer; +begin + if (Bits = nil) or (Bits.Size = 0) then + Result := '' + else + begin + SetLength(Result, Bits.Size); + for I := 0 to Bits.Size - 1 do + begin + if Bits.Bits[I] then + Result[I + 1] := '1' + else + Result[I + 1] := '0'; + end; + end; +end; + +function ConcatBytes(const A, B: TBytes): TBytes; +begin + // XE7 ҲֱӣΪ A B Ϊʱ᷵һֽ + if (A = nil) or (Length(A) = 0) then + begin + SetLength(Result, Length(B)); + if Length(B) > 0 then + Move(B[0], Result[0], Length(B)); + end + else if (B = nil) or (Length(B) = 0) then + begin + SetLength(Result, Length(A)); + if Length(A) > 0 then + Move(A[0], Result[0], Length(A)); + end + else + begin + SetLength(Result, Length(A) + Length(B)); + Move(A[0], Result[0], Length(A)); + Move(B[0], Result[Length(A)], Length(B)); + end; +end; + +function ConcatBytes(const A: TBytes; const B: TBytes; const C: TBytes): TBytes; +var + L1, L2, L3: Integer; +begin + Result := nil; + L1 := Length(A); + L2 := Length(B); + L3 := Length(C); + + if (L1 = 0) and (L2 = 0) and (L3 = 0) then + Exit; + + SetLength(Result, L1 + L2 + L3); + if L1 > 0 then + Move(A[0], Result[0], L1); + if L2 > 0 then + Move(B[0], Result[L1], L2); + if L3 > 0 then + Move(C[0], Result[L1 + L2], L3); +end; + +function ConcatBytes(const A: TBytes; const B: TBytes; const C: TBytes; const D: TBytes): TBytes; +var + L1, L2, L3, L4: Integer; +begin + Result := nil; + L1 := Length(A); + L2 := Length(B); + L3 := Length(C); + L4 := Length(D); + + if (L1 = 0) and (L2 = 0) and (L3 = 0) and (L4 = 0) then + Exit; + + SetLength(Result, L1 + L2 + L3 + L4); + if L1 > 0 then + Move(A[0], Result[0], L1); + if L2 > 0 then + Move(B[0], Result[L1], L2); + if L3 > 0 then + Move(C[0], Result[L1 + L2], L3); + if L4 > 0 then + Move(D[0], Result[L1 + L2 + L3], L4); +end; + +function NewZeroBytes(ByteLen: Integer): TBytes; +begin + if ByteLen > 0 then + begin + SetLength(Result, ByteLen); + FillChar(Result[0], ByteLen, 0); + end + else + Result := nil; +end; + +function ConcatBytesMemory(const A: TBytes; Data: Pointer; DataByteLen: Integer): TBytes; +var + L: Integer; +begin + L := Length(A) + DataByteLen; + if L > 0 then + begin + SetLength(Result, L); + if Length(A) > 0 then + Move(A[0], Result[0], Length(A)); + if (Data <> nil) and (DataByteLen > 0) then + Move(Data^, Result[Length(A)], DataByteLen); + end + else + Result := nil; +end; + +function NewBytesFromMemory(Data: Pointer; DataByteLen: Integer): TBytes; +begin + if (Data = nil) or (DataByteLen <= 0) then + Result := nil + else + begin + SetLength(Result, DataByteLen); + Move(Data^, Result[0], DataByteLen); + end; +end; + +procedure PutBytesToMemory(const Data: TBytes; Mem: Pointer; MaxByteSize: Integer); +var + L: Integer; +begin + L := Length(Data); + if (L > 0) and (Mem <> nil) then + begin + if (MaxByteSize > 0) and (L > MaxByteSize) then + L := MaxByteSize; + + Move(Data[0], Mem^, L); + end; +end; + +function CompareBytes(const A, B: TBytes): Boolean; +var + L: Integer; +begin + Result := False; + + L := Length(A); + if Length(B) <> L then // Ȳ˳ + Exit; + + if L = 0 then // + Result := True // 綼 0 + else + Result := CompareMem(@A[0], @B[0], L); +end; + +function CompareBytes(const A, B: TBytes; MaxLength: Integer): Boolean; +var + LA, LB: Integer; +begin + Result := False; + + LA := Length(A); + LB := Length(B); + + if LA > MaxLength then + LA := MaxLength; + if LB > MaxLength then + LB := MaxLength; + + if LA <> LB then + Exit; + + if LA = 0 then + Result := True + else + Result := CompareMem(@A[0], @B[0], LA); +end; + +function CompareBytesWithDiffIndex(const A, B: TBytes; out DiffIndex: Integer): Boolean; +var + I: Integer; + L1, L2: Integer; +begin + L1 := Length(A); + L2 := Length(B); + DiffIndex := -1; + Result := True; + + if L1 <> L2 then + begin + Result := False; + Exit; + end; + + if (L1 = 0) and (L2 = 0) then + Exit; + + for I := 0 to L1 - 1 do + begin + if A[I] <> B[I] then + begin + Result := False; + DiffIndex := I; + Exit; + end; + end; +end; + +function MoveMost(const Source; var Dest; ByteLen, MostLen: Integer): Integer; +begin + if (MostLen <= 0) or (ByteLen <= 0) then + begin + Result := 0; + Exit; + end; + + if ByteLen > MostLen then + ByteLen := MostLen + else if ByteLen < MostLen then + begin + FillChar(Dest, MostLen, 0); + + // TODO: ҪΪ FillChar(Dest + ByteLen, MostLen - ByteLen, 0); ֻ䲻IJ + end; + + Move(Source, Dest, ByteLen); + Result := ByteLen; +end; + +// =============================== =================================== + +function SarInt8(V: ShortInt; ShiftCount: Integer): ShortInt; +begin + Result := V shr ShiftCount; + if (V and $80) <> 0 then + Result := Result or ($FF shl (8 - ShiftCount)); +end; + +function SarInt16(V: SmallInt; ShiftCount: Integer): SmallInt; +begin + Result := V shr ShiftCount; + if (V and $8000) <> 0 then + Result := Result or ($FFFF shl (16 - ShiftCount)); +end; + +function SarInt32(V: Integer; ShiftCount: Integer): Integer; +begin + Result := V shr ShiftCount; + if (V and $80000000) <> 0 then + Result := Result or Integer($FFFFFFFF shl (32 - ShiftCount)); +end; + +function SarInt64(V: Int64; ShiftCount: Integer): Int64; +begin + Result := V shr ShiftCount; + if (V and $8000000000000000) <> 0 then + Result := Result or ($FFFFFFFFFFFFFFFF shl (64 - ShiftCount)); +end; + +procedure ConstTimeConditionalSwap8(CanSwap: Boolean; var A, B: Byte); +var + T, V: Byte; +begin + T := ConstTimeExpandBoolean8(CanSwap); + V := (A xor B) and T; + A := A xor V; + B := B xor V; +end; + +procedure ConstTimeConditionalSwap16(CanSwap: Boolean; var A, B: Word); +var + T, V: Word; +begin + T := ConstTimeExpandBoolean16(CanSwap); + V := (A xor B) and T; + A := A xor V; + B := B xor V; +end; + +procedure ConstTimeConditionalSwap32(CanSwap: Boolean; var A, B: Cardinal); +var + T, V: Cardinal; +begin + T := ConstTimeExpandBoolean32(CanSwap); + V := (A xor B) and T; + A := A xor V; + B := B xor V; +end; + +procedure ConstTimeConditionalSwap64(CanSwap: Boolean; var A, B: TUInt64); +var + T, V: TUInt64; +begin + T := ConstTimeExpandBoolean64(CanSwap); + V := (A xor B) and T; + A := A xor V; + B := B xor V; +end; + +function ConstTimeEqual8(A, B: Byte): Boolean; +var + R: Byte; +begin + R := not (A xor B); // + R := R and (R shr 4); // һһ + R := R and (R shr 2); // һλ 0 + R := R and (R shr 1); // 0 + Result := Boolean(R); // ֻȫ 1 1 +end; + +function ConstTimeEqual16(A, B: Word): Boolean; +begin + Result := ConstTimeEqual8(Byte(A shr 8), Byte(B shr 8)) + and ConstTimeEqual8(Byte(A and $FF), Byte(B and $FF)); +end; + +function ConstTimeEqual32(A, B: Cardinal): Boolean; +begin + Result := ConstTimeEqual16(Word(A shr 16), Word(B shr 16)) + and ConstTimeEqual16(Word(A and $FFFF), Word(B and $FFFF)); +end; + +function ConstTimeEqual64(A, B: TUInt64): Boolean; +begin + Result := ConstTimeEqual32(Cardinal(A shr 32), Cardinal(B shr 32)) + and ConstTimeEqual32(Cardinal(A and $FFFFFFFF), Cardinal(B and $FFFFFFFF)); +end; + +function ConstTimeCompareMem(P1, P2: Pointer; ByteLength: Integer): Boolean; +var + B1, B2: PByte; + I: Integer; + Diff: Byte; +begin + Diff := 0; + B1 := PByte(P1); + B2 := PByte(P2); + + for I := 0 to ByteLength - 1 do + begin + Diff := Diff or (B1^ xor B2^); + Inc(B1); + Inc(B2); + end; + + Result := Diff = 0; +end; + +function ConstTimeCompareBytes(const A, B: TBytes): Boolean; +begin + if Length(A) <> Length(B) then + Result := False + else + Result := ConstTimeCompareMem(@A[0], @B[0], Length(A)); +end; + +function ConstTimeExpandBoolean8(V: Boolean): Byte; +begin + Result := Byte(V); + Result := not Result; // V True 0˲ R Ǵ $FFR ͷ 0 + Result := Result and (Result shr 4); // һһ + Result := Result and (Result shr 2); // һλ 0 + Result := Result and (Result shr 1); // 00000000 00000001 + Result := Result or (Result shl 1); // True õ 00000000False õ 00000001λ + Result := Result or (Result shl 2); + Result := Result or (Result shl 4); // ȫ 0 ȫ 1 + Result := not Result; // ȫ 1 ȫ 0 +end; + +function ConstTimeExpandBoolean16(V: Boolean): Word; +var + R: Byte; +begin + R := ConstTimeExpandBoolean8(V); + Result := R; + Result := (Result shl 8) or R; // ֽȫ 1 ȫ 0 ˫ֽ +end; + +function ConstTimeExpandBoolean32(V: Boolean): Cardinal; +var + R: Word; +begin + R := ConstTimeExpandBoolean16(V); + Result := R; + Result := (Result shl 16) or R; // ˫ֽȫ 1 ȫ 0 ֽ +end; + +function ConstTimeExpandBoolean64(V: Boolean): TUInt64; +var + R: Cardinal; +begin + R := ConstTimeExpandBoolean32(V); + Result := R; + Result := (Result shl 32) or R; // ֽȫ 1 ȫ 0 ɰֽ +end; + +function ConstTimeConditionalSelect8(Condition: Boolean; A, B: Byte): Byte; +begin + ConstTimeConditionalSwap8(Condition, A, B); + Result := B; +end; + +function ConstTimeConditionalSelect16(Condition: Boolean; A, B: Word): Word; +begin + ConstTimeConditionalSwap16(Condition, A, B); + Result := B; +end; + +function ConstTimeConditionalSelect32(Condition: Boolean; A, B: Cardinal): Cardinal; +begin + ConstTimeConditionalSwap32(Condition, A, B); + Result := B; +end; + +function ConstTimeConditionalSelect64(Condition: Boolean; A, B: TUInt64): TUInt64; +begin + ConstTimeConditionalSwap64(Condition, A, B); + Result := B; +end; + +{$IFDEF MSWINDOWS} + +{$IFDEF CPUX64} + +// 64 λ IDIV IDIV ָʵ֣ A RCX B EDX/RDX DivRes ַ R8 ModRes ַ R9 +procedure Int64DivInt32Mod(A: Int64; B: Integer; var DivRes, ModRes: Integer); assembler; +asm + PUSH RCX // RCX A + MOV RCX, RDX // B RCX + POP RAX // A RAX + XOR RDX, RDX // 64 λ + IDIV RCX + MOV [R8], EAX // ̷ R8 ָ DivRes + MOV [R9], EDX // R9 ָ ModRes +end; + +procedure UInt64DivUInt32Mod(A: TUInt64; B: Cardinal; var DivRes, ModRes: Cardinal); assembler; +asm + PUSH RCX // RCX A + MOV RCX, RDX // B RCX + POP RAX // A RAX + XOR RDX, RDX // 64 λ + DIV RCX + MOV [R8], EAX // ̷ R8 ָ DivRes + MOV [R9], EDX // R9 ָ ModRes +end; + +// 64 λ IDIV IDIV ָʵ֣ALo RCXAHi RDXB R8DivRes ĵַ R9 +procedure Int128DivInt64Mod(ALo, AHi: Int64; B: Int64; var DivRes, ModRes: Int64); assembler; +asm + MOV RAX, RCX // ALo RAXAHi Ѿ RDX + MOV RCX, R8 // B RCX + IDIV RCX + MOV [R9], RAX // ̷ R9 ָ DivRes + MOV RAX, [RBP + $30] // ModRes ַ RAX + MOV [RAX], RDX // RAX ָ ModRes +end; + +procedure UInt128DivUInt64Mod(ALo, AHi: UInt64; B: UInt64; var DivRes, ModRes: UInt64); assembler; +asm + MOV RAX, RCX // ALo RAXAHi Ѿ RDX + MOV RCX, R8 // B RCX + DIV RCX + MOV [R9], RAX // ̷ R9 ָ DivRes + MOV RAX, [RBP + $30] // ModRes ַ RAX + MOV [RAX], RDX // RAX ָ ModRes +end; + +{$ELSE} + +// 32 λ IDIV IDIV ָʵ֣ A ڶջϣB EAXDivRes ַ EDXModRes ַ ECX +procedure Int64DivInt32Mod(A: Int64; B: Integer; var DivRes, ModRes: Integer); assembler; +asm + PUSH ECX // ECX ModRes ַȱ + MOV ECX, B // B EAX УƵ ECX + PUSH EDX // DivRes ĵַ EDX УҲ + MOV EAX, [EBP + $8] // A Lo + MOV EDX, [EBP + $C] // A Hi + IDIV ECX + POP ECX // ECXõ DivRes ַ + MOV [ECX], EAX + POP ECX // ECXõ ModRes ַ + MOV [ECX], EDX +end; + +procedure UInt64DivUInt32Mod(A: TUInt64; B: Cardinal; var DivRes, ModRes: Cardinal); assembler; +asm + PUSH ECX // ECX ModRes ַȱ + MOV ECX, B // B EAX УƵ ECX + PUSH EDX // DivRes ĵַ EDX УҲ + MOV EAX, [EBP + $8] // A Lo + MOV EDX, [EBP + $C] // A Hi + DIV ECX + POP ECX // ECXõ DivRes ַ + MOV [ECX], EAX + POP ECX // ECXõ ModRes ַ + MOV [ECX], EDX +end; + +// 32 λµʵ +procedure Int128DivInt64Mod(ALo, AHi: Int64; B: Int64; var DivRes, ModRes: Int64); +var + C: Integer; +begin + if B = 0 then + raise EDivByZero.Create(SDivByZero); + + if (AHi = 0) or (AHi = $FFFFFFFFFFFFFFFF) then // 64 λΪ 0 ֵֵ + begin + DivRes := ALo div B; + ModRes := ALo mod B; + end + else + begin + if B < 0 then // Ǹ + begin + Int128DivInt64Mod(ALo, AHi, -B, DivRes, ModRes); + DivRes := -DivRes; + Exit; + end; + + if AHi < 0 then // Ǹ + begin + // AHi, ALo 󷴼 1Եõֵ + AHi := not AHi; + ALo := not ALo; +{$IFDEF SUPPORT_UINT64} + UInt64Add(UInt64(ALo), UInt64(ALo), 1, C); +{$ELSE} + UInt64Add(ALo, ALo, 1, C); +{$ENDIF} + if C > 0 then + AHi := AHi + C; + + // ת + Int128DivInt64Mod(ALo, AHi, B, DivRes, ModRes); + + // ٵ + if ModRes = 0 then + DivRes := -DivRes + else + begin + DivRes := -DivRes - 1; + ModRes := B - ModRes; + end; + Exit; + end; + + // ȫ󣬰޷ +{$IFDEF SUPPORT_UINT64} + UInt128DivUInt64Mod(TUInt64(ALo), TUInt64(AHi), TUInt64(B), TUInt64(DivRes), TUInt64(ModRes)); +{$ELSE} + UInt128DivUInt64Mod(ALo, AHi, B, DivRes, ModRes); +{$ENDIF} + end; +end; + +procedure UInt128DivUInt64Mod(ALo, AHi: TUInt64; B: TUInt64; var DivRes, ModRes: TUInt64); +var + I, Cnt: Integer; + Q, R: TUInt64; +begin + if B = 0 then + raise EDivByZero.Create(SDivByZero); + + if AHi = 0 then + begin + DivRes := UInt64Div(ALo, B); + ModRes := UInt64Mod(ALo, B); + end + else + begin + // иλеλզ죿жǷ AHi >= BʾҪ 64 λ + if UInt64Compare(AHi, B) >= 0 then + raise EIntOverflow.Create(SIntOverflow); + + Q := 0; + R := 0; + Cnt := GetUInt64LowBits(AHi) + 64; + for I := Cnt downto 0 do + begin + R := R shl 1; + if IsUInt128BitSet(ALo, AHi, I) then // ĵ I λǷ 0 + R := R or 1 + else + R := R and TUInt64(not 1); + + if UInt64Compare(R, B) >= 0 then + begin + R := R - B; + Q := Q or (TUInt64(1) shl I); + end; + end; + DivRes := Q; + ModRes := R; + end; +end; + +{$ENDIF} + +{$ENDIF} + +{$IFDEF SUPPORT_UINT64} + +// ֻҪ֧ 64 λ޷ 32/64 λ Intel ARM Delphi FPCʲôϵͳ + +function UInt64Mod(A, B: TUInt64): TUInt64; +begin + Result := A mod B; +end; + +function UInt64Div(A, B: TUInt64): TUInt64; +begin + Result := A div B; +end; + +{$ELSE} +{ + ֧ UInt64 ĵͰ汾 Delphi Int64 A mod/div B + + õջ˳ A ĸλA ĵλB ĸλB ĵλ push ϲ뺯 + ESP ǷصַESP+4 B ĵλESP + 8 B ĸλESP + C A ĵλESP + 10 A ĸλ + push esp ESP 4Ȼ mov ebp esp֮ EBP ѰַȫҪ 4 + + System.@_llumod ҪڸսʱEAX <- A ĵλEDX <- A ĸλSystem Դע EAX/EDX дˣ + [ESP + 8]Ҳ EBP + C<- B ĸλ[ESP + 4] Ҳ EBP + 8<- B ĵλ + + CALL ǰľƴ롣UInt64 Div Ҳ +} +function UInt64Mod(A, B: TUInt64): TUInt64; +asm + // PUSH ESP ESP 4Ҫ + MOV EAX, [EBP + $10] // A Lo + MOV EDX, [EBP + $14] // A Hi + PUSH DWORD PTR[EBP + $C] // B Hi + PUSH DWORD PTR[EBP + $8] // B Lo + CALL System.@_llumod; +end; + +function UInt64Div(A, B: TUInt64): TUInt64; +asm + // PUSH ESP ESP 4Ҫ + MOV EAX, [EBP + $10] // A Lo + MOV EDX, [EBP + $14] // A Hi + PUSH DWORD PTR[EBP + $C] // B Hi + PUSH DWORD PTR[EBP + $8] // B Lo + CALL System.@_lludiv; +end; + +{$ENDIF} + +{$IFDEF SUPPORT_UINT64} + +// ֻҪ֧ 64 λ޷ 32/64 λ Intel ARM Delphi FPCʲôϵͳ + +function UInt64Mul(A, B: Cardinal): TUInt64; +begin + Result := TUInt64(A) * B; +end; + +{$ELSE} // ֻеͰ汾 Delphi Win32 x86 + +{ + ޷ 32 λˣֱʹ Int64 ģ 64 λ޷ + + üĴԼ A -> EAXB -> EDXʹöջ + System.@_llmul ҪڸսʱEAX <- A ĵλEDX <- A ĸλ 0 + [ESP + 8]Ҳ EBP + C<- B ĸλ 0[ESP + 4] Ҳ EBP + 8<- B ĵλ +} +function UInt64Mul(A, B: Cardinal): TUInt64; +asm + PUSH 0 // PUSH B λ 0 + PUSH EDX // PUSH B λ + // EAX A λѾ + XOR EDX, EDX // EDX A λ 0 + CALL System.@_llmul; // EAX 32 λEDX 32 λ +end; + +{$ENDIF} + +// ޷ 64 λӣ ResLo ResHi +procedure UInt64AddUInt64(A, B: TUInt64; var ResLo, ResHi: TUInt64); +var + X, Y, Z, T, R0L, R0H, R1L, R1H: Cardinal; + R0, R1, R01, R12: TUInt64; +begin + // ˼룺2^32 ϵ M (xM+y) + (zM+t) = (x+z) M + (y+t) + // y+t R0 ռ 01x+z R1 ռ 12 R0, R1 ٲӳ R01, R12 + if IsUInt64AddOverflow(A, B) then + begin + X := Int64Rec(A).Hi; + Y := Int64Rec(A).Lo; + Z := Int64Rec(B).Hi; + T := Int64Rec(B).Lo; + + R0 := TUInt64(Y) + TUInt64(T); + R1 := TUInt64(X) + TUInt64(Z); + + R0L := Int64Rec(R0).Lo; + R0H := Int64Rec(R0).Hi; + R1L := Int64Rec(R1).Lo; + R1H := Int64Rec(R1).Hi; + + R01 := TUInt64(R0H) + TUInt64(R1L); + R12 := TUInt64(R1H) + TUInt64(Int64Rec(R01).Hi); + + Int64Rec(ResLo).Lo := R0L; + Int64Rec(ResLo).Hi := Int64Rec(R01).Lo; + Int64Rec(ResHi).Lo := Int64Rec(R12).Lo; + Int64Rec(ResHi).Hi := Int64Rec(R12).Hi; + end + else + begin + ResLo := A + B; + ResHi := 0; + end; +end; + +{$IFDEF WIN64} // ע Linux 64 ²֧ ASMֻ WIN64 + +// 64 λ޷ 64 λˣ ResLo ResHi Уֱûʵ֣һ +procedure UInt64MulUInt64(A, B: UInt64; var ResLo, ResHi: UInt64); assembler; +asm + PUSH RAX + MOV RAX, RCX + MUL RDX // ޷ţзŵ IMUL + MOV [R8], RAX + MOV [R9], RDX + POP RAX +end; + +{$ELSE} + +// ޷ 64 λˣ ResLo ResHi +procedure UInt64MulUInt64(A, B: TUInt64; var ResLo, ResHi: TUInt64); +var + X, Y, Z, T: Cardinal; + YT, XT, ZY, ZX: TUInt64; + P, R1Lo, R1Hi, R2Lo, R2Hi: TUInt64; +begin + // ˼룺2^32 ϵ M (xM+y)*(zM+t) = xzM^2 + (xt+yz)M + yt + // ϵ UInt64xz ռ 234xt+yz ռ 123yt ռ 01Ȼۼ + X := Int64Rec(A).Hi; + Y := Int64Rec(A).Lo; + Z := Int64Rec(B).Hi; + T := Int64Rec(B).Lo; + + YT := UInt64Mul(Y, T); + XT := UInt64Mul(X, T); + ZY := UInt64Mul(Y, Z); + ZX := UInt64Mul(X, Z); + + Int64Rec(ResLo).Lo := Int64Rec(YT).Lo; + + P := Int64Rec(YT).Hi; + UInt64AddUInt64(P, XT, R1Lo, R1Hi); + UInt64AddUInt64(ZY, R1Lo, R2Lo, R2Hi); + + Int64Rec(ResLo).Hi := Int64Rec(R2Lo).Lo; + + P := TUInt64(Int64Rec(R2Lo).Hi) + TUInt64(Int64Rec(ZX).Lo); + + Int64Rec(ResHi).Lo := Int64Rec(P).Lo; + Int64Rec(ResHi).Hi := Int64Rec(R1Hi).Lo + Int64Rec(R2Hi).Lo + Int64Rec(ZX).Hi + Int64Rec(P).Hi; +end; + +{$ENDIF} + +{$HINTS OFF} + +function _ValUInt64(const S: string; var Code: Integer): TUInt64; +const + FirstIndex = 1; +var + I: Integer; + Dig: Integer; + Sign: Boolean; + Empty: Boolean; +begin + I := FirstIndex; + Dig := 0; + Result := 0; + + if S = '' then + begin + Code := 1; + Exit; + end; + + while S[I] = Char(' ') do + Inc(I); + Sign := False; + + if S[I] = Char('-') then + begin + Sign := True; + Code := 1; // ָ֧ + Inc(I); + end + else if S[I] = Char('+') then + Inc(I); + Empty := True; + + if (S[I] = Char('$')) or (UpCase(S[I]) = Char('X')) + or ((S[I] = Char('0')) and (I < Length(S)) and (UpCase(S[I + 1]) = Char('X'))) then + begin + if S[I] = Char('0') then + Inc(I); + Inc(I); + while True do + begin + if I > Length(S) then + Break; + case Char(S[I]) of + Char('0').. Char('9'): Dig := Ord(S[I]) - Ord('0'); + Char('A').. Char('F'): Dig := Ord(S[I]) - (Ord('A') - 10); + Char('a').. Char('f'): Dig := Ord(S[I]) - (Ord('a') - 10); + else + Break; + end; + + if Result > (CN_MAX_TUINT64 shr 4) then + Break; + if Sign and (Dig <> 0) then + Break; + + Result := Result shl 4 + TUInt64(Dig); + Inc(I); + Empty := False; + end; + end + else + begin + while True do + begin + if I > Length(S) then + Break; + case Char(S[I]) of + Char('0').. Char('9'): Dig := Ord(S[I]) - Ord('0'); + else + Break; + end; + + if Result > UInt64Div(CN_MAX_TUINT64, 10) then + Break; + if Sign and (Dig <> 0) then + Break; + + Result := Result * 10 + TUInt64(Dig); + Inc(I); + Empty := False; + end; + end; + + if ((I <= Length(S)) and (S[I] <> Char(#0))) or Empty then + Code := I + 1 - FirstIndex + else + Code := 0; +end; + +function _ValUInt32(const S: string; var Code: Integer): Cardinal; +const + FirstIndex = 1; +var + I: Integer; + Dig: Integer; + Sign: Boolean; + Empty: Boolean; +begin + I := FirstIndex; + Dig := 0; + Result := 0; + + if S = '' then + begin + Code := 1; + Exit; + end; + + while S[I] = Char(' ') do + Inc(I); + Sign := False; + + if S[I] = Char('-') then + begin + Sign := True; + Code := 1; // ָ֧ + Inc(I); + end + else if S[I] = Char('+') then + Inc(I); + Empty := True; + + if (S[I] = Char('$')) or (UpCase(S[I]) = Char('X')) + or ((S[I] = Char('0')) and (I < Length(S)) and (UpCase(S[I + 1]) = Char('X'))) then + begin + if S[I] = Char('0') then + Inc(I); + Inc(I); + while True do + begin + if I > Length(S) then + Break; + case Char(S[I]) of + Char('0').. Char('9'): Dig := Ord(S[I]) - Ord('0'); + Char('A').. Char('F'): Dig := Ord(S[I]) - (Ord('A') - 10); + Char('a').. Char('f'): Dig := Ord(S[I]) - (Ord('a') - 10); + else + Break; + end; + + if Result > (CN_MAX_UINT32 shr 4) then + Break; + if Sign and (Dig <> 0) then + Break; + + Result := Result shl 4 + Cardinal(Dig); + Inc(I); + Empty := False; + end; + end + else + begin + while True do + begin + if I > Length(S) then + Break; + case Char(S[I]) of + Char('0').. Char('9'): Dig := Ord(S[I]) - Ord('0'); + else + Break; + end; + + if Result > (CN_MAX_UINT32 div 10) then + Break; + if Sign and (Dig <> 0) then + Break; + + Result := Result * 10 + Cardinal(Dig); + Inc(I); + Empty := False; + end; + end; + + if ((I <= Length(S)) and (S[I] <> Char(#0))) or Empty then + Code := I + 1 - FirstIndex + else + Code := 0; +end; + +{$HINTS ON} + +function UInt64ToHex(N: TUInt64; RemoveZeroPrefix: Boolean): string; +const + Digits: array[0..15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); + + function HC(B: Byte): string; + begin + Result := string(Digits[(B shr 4) and $0F] + Digits[B and $0F]); + end; + +begin + Result := + HC(Byte((N and $FF00000000000000) shr 56)) + + HC(Byte((N and $00FF000000000000) shr 48)) + + HC(Byte((N and $0000FF0000000000) shr 40)) + + HC(Byte((N and $000000FF00000000) shr 32)) + + HC(Byte((N and $00000000FF000000) shr 24)) + + HC(Byte((N and $0000000000FF0000) shr 16)) + + HC(Byte((N and $000000000000FF00) shr 8)) + + HC(Byte((N and $00000000000000FF))); + + if RemoveZeroPrefix then + begin + while (Length(Result) > 1) and (Result[1] = '0') do + Delete(Result, 1, 1); + end; +end; + +function UInt64ToStr(N: TUInt64): string; +begin + Result := Format('%u', [N]); +end; + +function StrToUInt64(const S: string): TUInt64; +{$IFNDEF DELPHIXE6_UP} +var + E: Integer; +{$ENDIF} +begin +{$IFDEF DELPHIXE6_UP} + Result := SysUtils.StrToUInt64(S); // StrToUInt64 only exists under XE6 or above +{$ELSE} + Result := _ValUInt64(S, E); + if E <> 0 then raise EConvertError.CreateResFmt(@SInvalidInteger, [S]); +{$ENDIF} +end; + +function StrToUInt(const S: string): Cardinal; +{$IFNDEF DELPHI102_TOKYO_UP} +var + E: Integer; +{$ENDIF} +begin +{$IFDEF DELPHI102_TOKYO_UP} + Result := SysUtils.StrToUInt(S); // StrToUInt only exists under D102T or above +{$ELSE} + Result := _ValUInt32(S, E); + if E <> 0 then raise EConvertError.CreateResFmt(@SInvalidInteger, [S]); +{$ENDIF} +end; + +function UInt64Compare(A, B: TUInt64): Integer; +{$IFNDEF SUPPORT_UINT64} +var + HiA, HiB, LoA, LoB: Cardinal; +{$ENDIF} +begin +{$IFDEF SUPPORT_UINT64} + if A > B then + Result := 1 + else if A < B then + Result := -1 + else + Result := 0; +{$ELSE} + HiA := (A and $FFFFFFFF00000000) shr 32; + HiB := (B and $FFFFFFFF00000000) shr 32; + if HiA > HiB then + Result := 1 + else if HiA < HiB then + Result := -1 + else + begin + LoA := Cardinal(A and $00000000FFFFFFFF); + LoB := Cardinal(B and $00000000FFFFFFFF); + if LoA > LoB then + Result := 1 + else if LoA < LoB then + Result := -1 + else + Result := 0; + end; +{$ENDIF} +end; + +function UInt64Sqrt(N: TUInt64): TUInt64; +var + Rem, Root: TUInt64; + I: Integer; +begin + Result := 0; + if N = 0 then + Exit; + + if UInt64Compare(N, 4) < 0 then + begin + Result := 1; + Exit; + end; + + Rem := 0; + Root := 0; + + for I := 0 to 31 do + begin + Root := Root shl 1; + Inc(Root); + + Rem := Rem shl 2; + Rem := Rem or (N shr 62); + N := N shl 2; + + if UInt64Compare(Root, Rem) <= 0 then + begin + Rem := Rem - Root; + Inc(Root); + end + else + Dec(Root); + end; + Result := Root shr 1; +end; + +function UInt32IsNegative(N: Cardinal): Boolean; +begin + Result := (N and (1 shl 31)) <> 0; +end; + +function UInt64IsNegative(N: TUInt64): Boolean; +begin +{$IFDEF SUPPORT_UINT64} + Result := (N and (UInt64(1) shl 63)) <> 0; +{$ELSE} + Result := N < 0; +{$ENDIF} +end; + +// UInt64 ijһλ 1λ Index 0 ʼ +procedure UInt64SetBit(var B: TUInt64; Index: Integer); +begin + B := B or (TUInt64(1) shl Index); +end; + +// UInt64 ijһλ 0λ Index 0 ʼ +procedure UInt64ClearBit(var B: TUInt64; Index: Integer); +begin + B := B and not (TUInt64(1) shl Index); +end; + +// UInt64 ĵڼλǷ 10 ʼ +function GetUInt64BitSet(B: TUInt64; Index: Integer): Boolean; +begin + B := B and (TUInt64(1) shl Index); + Result := B <> 0; +end; + +// UInt64 1 ߶λǵڼλλ 0û 1 -1 +function GetUInt64HighBits(B: TUInt64): Integer; +var + I: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + for I := 63 downto 0 do + begin + if (B and (TUInt64(1) shl I)) <> 0 then // TUInt64 ǿתó 8 ߶λΪ 35 Ĵ + begin + Result := I; + Break; + end; + end; +end; + +// Cardinal 1 ߶λǵڼλλ 0û 1 -1 +function GetUInt32HighBits(B: Cardinal): Integer; +var + I: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + for I := 31 downto 0 do + begin + if (B and (1 shl I)) <> 0 then + begin + Result := I; + Break; + end; + end; +end; + +// Word 1 ߶λǵڼλλ 0û 1 -1 +function GetUInt16HighBits(B: Word): Integer; +var + I: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + for I := 15 downto 0 do + begin + if (B and (1 shl I)) <> 0 then + begin + Result := I; + Break; + end; + end; +end; + +// Byte 1 ߶λǵڼλλ 0û 1 -1 +function GetUInt8HighBits(B: Byte): Integer; +var + I: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + for I := 7 downto 0 do + begin + if (B and (1 shl I)) <> 0 then + begin + Result := I; + Break; + end; + end; +end; + +// 64 λȥλ 0 ʣµλȣû 1 0 +function GetUInt64BitLength(B: TUInt64): Integer; +begin + Result := 1 + GetUInt64HighBits(B); +end; + +// 32 λȥλ 0 ʣµλȣû 1 0 +function GetUInt32BitLength(B: Cardinal): Integer; +begin + Result := 1 + GetUInt32HighBits(B); +end; + +// 16 λȥλ 0 ʣµλȣû 1 0 +function GetUInt16BitLength(B: Word): Integer; +begin + Result := 1 + GetUInt16HighBits(B); +end; + +// 8 λȥλ 0 ʣµλȣû 1 0 +function GetUInt8BitLength(B: Byte): Integer; +begin + Result := 1 + GetUInt8HighBits(B); +end; + +// UInt64 1 Ͷλǵڼλλ 0û 1 -1 +function GetUInt64LowBits(B: TUInt64): Integer; +var + I: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + for I := 0 to 63 do + begin + if (B and (1 shl I)) <> 0 then + begin + Result := I; + Break; + end; + end; +end; + +// Cardinal 1 Ͷλǵڼλλ 0û 1 -1 +function GetUInt32LowBits(B: Cardinal): Integer; +var + I: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + for I := 0 to 31 do + begin + if (B and (1 shl I)) <> 0 then + begin + Result := I; + Break; + end; + end; +end; + +// Word 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 +function GetUInt16LowBits(B: Word): Integer; +var + I: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + for I := 0 to 15 do + begin + if (B and (1 shl I)) <> 0 then + begin + Result := I; + Break; + end; + end; +end; + +// Byte 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 +function GetUInt8LowBits(B: Byte): Integer; +var + I: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + for I := 0 to 7 do + begin + if (B and (1 shl I)) <> 0 then + begin + Result := I; + Break; + end; + end; +end; + +// װ Int64 Modֵʱȡģģ +function Int64Mod(M, N: Int64): Int64; +begin + if M > 0 then + Result := M mod N + else + Result := N - ((-M) mod N); +end; + +function Int64CenterMod(A: Int64; N: Int64): Int64; +begin + Result := Int64NonNegativeMod(A, N); + if Result > N div 2 then // ߰벿ֱӼ N + Result := Result - N; +end; + +// жһ 32 λ޷Ƿ 2 +function IsUInt32PowerOf2(N: Cardinal): Boolean; +begin + Result := (N and (N - 1)) = 0; +end; + +// жһ 64 λ޷Ƿ 2 +function IsUInt64PowerOf2(N: TUInt64): Boolean; +begin + Result := (N and (N - 1)) = 0; +end; + +// õһָ 32 λ޷ȵ 2 ݣ򷵻 0 +function GetUInt32PowerOf2GreaterEqual(N: Cardinal): Cardinal; +begin + Result := N - 1; + Result := Result or (Result shr 1); + Result := Result or (Result shr 2); + Result := Result or (Result shr 4); + Result := Result or (Result shr 8); + Result := Result or (Result shr 16); + Inc(Result); +end; + +// õһָ 64 λ޷ 2 ݣ򷵻 0 +function GetUInt64PowerOf2GreaterEqual(N: TUInt64): TUInt64; +begin + Result := N - 1; + Result := Result or (Result shr 1); + Result := Result or (Result shr 2); + Result := Result or (Result shr 4); + Result := Result or (Result shr 8); + Result := Result or (Result shr 16); + Result := Result or (Result shr 32); + Inc(Result); +end; + +// ж 32 λзǷ 32 λз +function IsInt32AddOverflow(A, B: Integer): Boolean; +var + C: Integer; +begin + C := A + B; + Result := ((A > 0) and (B > 0) and (C < 0)) or // ͬҽ˵ + ((A < 0) and (B < 0) and (C > 0)); +end; + +// ж 32 λ޷Ƿ 32 λ޷ +function IsUInt32AddOverflow(A, B: Cardinal): Boolean; +begin + Result := (A + B) < A; // ޷ӣֻҪСһ˵ +end; + +// ж 64 λзǷ 64 λз +function IsInt64AddOverflow(A, B: Int64): Boolean; +var + C: Int64; +begin + C := A + B; + Result := ((A > 0) and (B > 0) and (C < 0)) or // ͬҽ˵ + ((A < 0) and (B < 0) and (C > 0)); +end; + +// ж 64 λ޷Ƿ 64 λ޷ +function IsUInt64AddOverflow(A, B: TUInt64): Boolean; +begin + Result := UInt64Compare(A + B, A) < 0; // ޷ӣֻҪСһ˵ +end; + +function IsUInt64SubOverflowInt32(A: TUInt64; B: TUInt64): Boolean; +var + GT: Boolean; + R: TUInt64; +begin + GT := UInt64Compare(A, B) >= 0; // GT ʾ A >= B + if GT then + begin + R := A - B; + // ж 64 λ޷ŷΧ R Ƿ񳬹 MaxInt32 + Result := UInt64Compare(R, TUInt64(CN_MAX_INT32)) > 0; + end + else + begin + R := B - A; + // ж 64 λзŷΧ -R ǷС MinInt32Ҳж 64 λ޷ R Ƿ񳬹 MinInt32 ޷ʽ + Result := UInt64Compare(R, CN_MIN_INT32_IN_INT64) > 0; + end; +end; + +// 64 λ޷ӣA + B => R 1 λ +procedure UInt64Add(var R: TUInt64; A, B: TUInt64; out Carry: Integer); +begin + R := A + B; + if UInt64Compare(R, A) < 0 then // ޷ӣֻҪСһ˵ + Carry := 1 + else + Carry := 0; +end; + +// 64 λ޷A - B => Rнλ 1 λ +procedure UInt64Sub(var R: TUInt64; A, B: TUInt64; out Carry: Integer); +begin + R := A - B; + if UInt64Compare(R, A) > 0 then // ޷ֻҪڱ˵λ + Carry := 1 + else + Carry := 0; +end; + +// ж 32 λзǷ 32 λз +function IsInt32MulOverflow(A, B: Integer): Boolean; +var + T: Integer; +begin + T := A * B; + Result := (B <> 0) and ((T div B) <> A); +end; + +// ж 32 λ޷Ƿ 32 λ޷ +function IsUInt32MulOverflow(A, B: Cardinal): Boolean; +var + T: TUInt64; +begin + T := TUInt64(A) * TUInt64(B); + Result := (T = Cardinal(T)); +end; + +// ж 32 λ޷Ƿ 64 λзδҲ False ʱR ֱӷؽ +function IsUInt32MulOverflowInt64(A, B: Cardinal; out R: TUInt64): Boolean; +var + T: Int64; +begin + T := Int64(A) * Int64(B); + Result := T < 0; // Int64 ֵ˵ + if not Result then + R := TUInt64(T); +end; + +// ж 64 λзǷ 64 λз +function IsInt64MulOverflow(A, B: Int64): Boolean; +var + T: Int64; +begin + T := A * B; + Result := (B <> 0) and ((T div B) <> A); +end; + +// ָת֧ͣ 32/64 λ +function PointerToInteger(P: Pointer): Integer; +begin +{$IFDEF CPU64BITS} + // ôд Pointer ĵ 32 λ Integer + Result := Integer(P); +{$ELSE} + Result := Integer(P); +{$ENDIF} +end; + +// תָ֧ͣ 32/64 λ +function IntegerToPointer(I: Integer): Pointer; +begin +{$IFDEF CPU64BITS} + // ôд Pointer ĵ 32 λ Integer + Result := Pointer(I); +{$ELSE} + Result := Pointer(I); +{$ENDIF} +end; + +// Int64 Χĺ࣬Ҫ N 0 +function Int64NonNegativeAddMod(A, B, N: Int64): Int64; +begin + if IsInt64AddOverflow(A, B) then // Int64 + begin + if A > 0 then + begin + // A B 0 UInt64 ȡģδ UInt64 ޣע N δ Int64 ȡģС Int64 ޣɸֵ + Result := UInt64NonNegativeAddMod(A, B, N); + end + else + begin + // A B С 0ȡ UInt64 ȡģĺδ UInt64 ޣģٱһ +{$IFDEF SUPPORT_UINT64} + Result := UInt64(N) - UInt64NonNegativeAddMod(-A, -B, N); +{$ELSE} + Result := N - UInt64NonNegativeAddMod(-A, -B, N); +{$ENDIF} + end; + end + else // ֱӼ + Result := Int64NonNegativeMod(A + B, N); +end; + +// UInt64 Χĺ࣬Ҫ N 0 +function UInt64NonNegativeAddMod(A, B, N: TUInt64): TUInt64; +var + C, D: TUInt64; +begin + if IsUInt64AddOverflow(A, B) then // + begin + C := UInt64Mod(A, N); // ͸ģ + D := UInt64Mod(B, N); + if IsUInt64AddOverflow(C, D) then + begin + // ˵ģ󣬸ģûá + // һڵ 2^63N 2^63 + 1 + // = + 2^64 + // mod N = mod N + (2^64 - 1) mod N) + 1 + // N 2^63 + 1 2^64 - 2ǰӲֱӺһģ + Result := UInt64Mod(UInt64Mod(A + B, N) + UInt64Mod(CN_MAX_TUINT64, N) + 1, N); + end + else + Result := UInt64Mod(C + D, N); + end + else + begin + Result := UInt64Mod(A + B, N); + end; +end; + +function Int64NonNegativeMulMod(A, B, N: Int64): Int64; +var + Neg: Boolean; +begin + if N <= 0 then + raise EDivByZero.Create(SDivByZero); + + // ΧСֱ + if not IsInt64MulOverflow(A, B) then + begin + Result := A * B mod N; + if Result < 0 then + Result := Result + N; + Exit; + end; + + // ŵ + Result := 0; + if (A = 0) or (B = 0) then + Exit; + + Neg := False; + if (A < 0) and (B > 0) then + begin + A := -A; + Neg := True; + end + else if (A > 0) and (B < 0) then + begin + B := -B; + Neg := True; + end + else if (A < 0) and (B < 0) then + begin + A := -A; + B := -B; + end; + + // λѭ + while B <> 0 do + begin + if (B and 1) <> 0 then + Result := ((Result mod N) + (A mod N)) mod N; + + A := A shl 1; + if A >= N then + A := A mod N; + + B := B shr 1; + end; + + if Neg then + Result := N - Result; +end; + +function UInt64NonNegativeMulMod(A, B, N: TUInt64): TUInt64; +begin + Result := 0; + if (UInt64Compare(A, CN_MAX_UINT32) <= 0) and (UInt64Compare(B, CN_MAX_UINT32) <= 0) then + begin + Result := UInt64Mod(A * B, N); // 㹻СĻֱӳ˺ģ + end + else + begin + while B <> 0 do + begin + if (B and 1) <> 0 then + Result := UInt64NonNegativeAddMod(Result, A, N); + + A := UInt64NonNegativeAddMod(A, A, N); + // ôͳ㷨 A := A shl 1 N mod NΪ + + B := B shr 1; + end; + end; +end; + +// װķǸຯҲΪʱӸ豣֤ P 0 +function Int64NonNegativeMod(N: Int64; P: Int64): Int64; +begin + if P <= 0 then + raise EDivByZero.Create(SDivByZero); + + Result := N mod P; + if Result < 0 then + Inc(Result, P); +end; + +// Int64 ķǸָ +function Int64NonNegativPower(N: Int64; Exp: Integer): Int64; +var + T: Int64; +begin + if Exp < 0 then + raise ERangeError.Create(SRangeError) + else if Exp = 0 then + begin + if N <> 0 then + Result := 1 + else + raise EDivByZero.Create(SDivByZero); + end + else if Exp = 1 then + Result := N + else + begin + Result := 1; + T := N; + + while Exp > 0 do + begin + if (Exp and 1) <> 0 then + Result := Result * T; + + Exp := Exp shr 1; + T := T * T; + end; + end; +end; + +function Int64NonNegativeRoot(N: Int64; Exp: Integer): Int64; +var + I: Integer; + X: Int64; + X0, X1: Extended; +begin + if (Exp < 0) or (N < 0) then + raise ERangeError.Create(SRangeError) + else if Exp = 0 then + raise EDivByZero.Create(SDivByZero) + else if (N = 0) or (N = 1) then + Result := N + else if Exp = 2 then + Result := UInt64Sqrt(N) + else + begin + // ţٵ + I := GetUInt64HighBits(N) + 1; // õԼ Log2 N ֵ + I := (I div Exp) + 1; + X := 1 shl I; // õһϴ X0 ֵΪʼֵ + + X0 := X; + X1 := X0 - (Power(X0, Exp) - N) / (Exp * Power(X0, Exp - 1)); + + while True do + begin + if (Trunc(X0) = Trunc(X1)) and (Abs(X0 - X1) < 0.001) then + begin + Result := Trunc(X1); // Trunc ֻ֧ Int64˻ + Exit; + end; + + X0 := X1; + X1 := X0 - (Power(X0, Exp) - N) / (Exp * Power(X0, Exp - 1)); + end; + end; +end; + +function UInt64NonNegativPower(N: TUInt64; Exp: Integer): TUInt64; +var + T, RL, RH: TUInt64; +begin + if Exp < 0 then + raise ERangeError.Create(SRangeError) + else if Exp = 0 then + begin + if N <> 0 then + Result := 1 + else + raise EDivByZero.Create(SDivByZero); + end + else if Exp = 1 then + Result := N + else + begin + Result := 1; + T := N; + + while Exp > 0 do + begin + if (Exp and 1) <> 0 then + begin + UInt64MulUInt64(Result, T, RL, RH); + Result := RL; + end; + + Exp := Exp shr 1; + UInt64MulUInt64(T, T, RL, RH); + T := RL; + end; + end; +end; + +function UInt64NonNegativeRoot(N: TUInt64; Exp: Integer): TUInt64; +var + Bits: Integer; + L, H, M, B, P: TUInt64; + Cmp: Integer; + Overflow: Boolean; + E: Integer; +begin + if Exp < 0 then + raise ERangeError.Create(SRangeError) + else if Exp = 0 then + raise EDivByZero.Create(SDivByZero) + else if (N = 0) or (N = 1) then + Result := N + else if Exp = 1 then + Result := N + else if Exp = 2 then + Result := UInt64Sqrt(N) + else + begin + // ֲ ֵ䣻 + // + ǰж Ƚ M^Exp N + // շ floor(N^(1/Exp)) + + Bits := GetUInt64HighBits(N) + 1; // õԼ Log2 N ֵ + H := TUInt64(1) shl ((Bits + Exp - 1) div Exp); + if H = 0 then + H := N + else if H > N then + H := N; + L := 1; + Cmp := -1; + + while L <= H do + begin + M := L + ((H - L) shr 1); + B := M; + P := 1; + E := Exp; + Overflow := False; + while E > 0 do + begin + if (E and 1) <> 0 then + begin + if (B <> 0) and (P > N div B) then + begin + Overflow := True; + Break; + end; + P := P * B; + end; + E := E shr 1; + if E > 0 then + begin + if (B <> 0) and (B > N div B) then + begin + Overflow := True; + Break; + end; + B := B * B; + end; + end; + + if Overflow then + Cmp := 1 + else if P > N then + Cmp := 1 + else if P < N then + Cmp := -1 + else + Cmp := 0; + + if Cmp = 0 then + begin + Result := M; + Exit; + end + else if Cmp < 0 then + L := M + 1 + else + begin + if M = 0 then + Break; + H := M - 1; + end; + end; + + if Cmp > 0 then + Result := H + else + Result := L - 1; + end; +end; + +function IsUInt128BitSet(Lo, Hi: TUInt64; N: Integer): Boolean; +begin + if N < 64 then + Result := (Lo and (TUInt64(1) shl N)) <> 0 + else + begin + Dec(N, 64); + Result := (Hi and (TUInt64(1) shl N)) <> 0; + end; +end; + +procedure SetUInt128Bit(var Lo, Hi: TUInt64; N: Integer); +begin + if N < 64 then + Lo := Lo or (TUInt64(1) shl N) + else + begin + Dec(N, 64); + Hi := Hi or (TUInt64(1) shl N); + end; +end; + +procedure ClearUInt128Bit(var Lo, Hi: TUInt64; N: Integer); +begin + if N < 64 then + Lo := Lo and not (TUInt64(1) shl N) + else + begin + Dec(N, 64); + Hi := Hi and not (TUInt64(1) shl N); + end; +end; + +function UnsignedAddWithLimitRadix(A, B, C: Cardinal; var R: Cardinal; + L, H: Cardinal): Cardinal; +begin + R := A + B + C; + if R > H then // нλ + begin + A := H - L + 1; // õ + B := R - L; // õ L ֵ + + Result := B div A; // Ƶĵڼͽ + R := L + (B mod A); // ȥƺ + end + else + Result := 0; +end; + +procedure InternalQuickSort(Mem: Pointer; L, R: Integer; ElementByteSize: Integer; + CompareProc: TCnMemSortCompareProc); +var + I, J, P: Integer; +begin + repeat + I := L; + J := R; + P := (L + R) shr 1; + repeat + while CompareProc(Pointer(TCnIntAddress(Mem) + I * ElementByteSize), + Pointer(TCnIntAddress(Mem) + P * ElementByteSize), ElementByteSize) < 0 do + Inc(I); + while CompareProc(Pointer(TCnIntAddress(Mem) + J * ElementByteSize), + Pointer(TCnIntAddress(Mem) + P * ElementByteSize), ElementByteSize) > 0 do + Dec(J); + + if I <= J then + begin + MemorySwap(Pointer(TCnIntAddress(Mem) + I * ElementByteSize), + Pointer(TCnIntAddress(Mem) + J * ElementByteSize), ElementByteSize); + + if P = I then + P := J + else if P = J then + P := I; + Inc(I); + Dec(J); + end; + until I > J; + + if L < J then + InternalQuickSort(Mem, L, J, ElementByteSize, CompareProc); + L := I; + until I >= R; +end; + +function DefaultCompareProc(P1, P2: Pointer; ElementByteSize: Integer): Integer; +begin + Result := MemoryCompare(P1, P2, ElementByteSize); +end; + +procedure MemoryQuickSort(Mem: Pointer; ElementByteSize: Integer; + ElementCount: Integer; CompareProc: TCnMemSortCompareProc); +begin + if (Mem <> nil) and (ElementCount > 0) and (ElementCount > 0) then + begin + if Assigned(CompareProc) then + InternalQuickSort(Mem, 0, ElementCount - 1, ElementByteSize, CompareProc) + else + InternalQuickSort(Mem, 0, ElementCount - 1, ElementByteSize, DefaultCompareProc); + end; +end; + +{$IFDEF COMPILER5} + +function BoolToStr(Value: Boolean; UseBoolStrs: Boolean): string; +begin + if UseBoolStrs then + begin + if Value then + Result := 'True' + else + Result := 'False'; + end + else + begin + if Value then + Result := '-1' + else + Result := '0'; + end; +end; + +{$ENDIF} + +// =========================== ѭλ ==================================== + +function RotateLeft16(A: Word; N: Integer): Word; +begin + Result := (A shl N) or (A shr (16 - N)); +end; + +function RotateRight16(A: Word; N: Integer): Word; +begin + Result := (A shr N) or (A shl (16 - N)); +end; + +function RotateLeft32(A: Cardinal; N: Integer): Cardinal; +begin + Result := (A shl N) or (A shr (32 - N)); +end; + +function RotateRight32(A: Cardinal; N: Integer): Cardinal; +begin + Result := (A shr N) or (A shl (32 - N)); +end; + +function RotateLeft64(A: TUInt64; N: Integer): TUInt64; +begin + Result := (A shl N) or (A shr (64 - N)); +end; +function RotateRight64(A: TUInt64; N: Integer): TUInt64; +begin + Result := (A shr N) or (A shl (64 - N)); +end; + +initialization + FByteOrderIsBigEndian := CurrentByteOrderIsBigEndian; + +end. diff --git a/CnPack/Crypto/CnPemUtils.pas b/CnPack/Crypto/CnPemUtils.pas index f4d5719..45d5d3c 100644 --- a/CnPack/Crypto/CnPemUtils.pas +++ b/CnPack/Crypto/CnPemUtils.pas @@ -1,1219 +1,1332 @@ -{******************************************************************************} -{ CnPack For Delphi/C++Builder } -{ йԼĿԴ } -{ (C)Copyright 2001-2025 CnPack } -{ ------------------------------------ } -{ } -{ ǿԴ CnPack ķЭ } -{ ĺ·һ } -{ } -{ һĿϣãûκεû } -{ ʺضĿĶĵϸ CnPack Э顣 } -{ } -{ ӦѾͿһյһ CnPack Эĸ } -{ ûУɷǵվ } -{ } -{ վַhttps://www.cnpack.org } -{ ʼmaster@cnpack.org } -{ } -{******************************************************************************} - -unit CnPemUtils; -{* |
-================================================================================
-* ƣ
-* ԪƣPEM ʽ뵥Ԫ
-* ԪߣCnPack 
-*     עԪʵ PEM ʽĶȡ뱣棬ӽܻơ
-*           Ҳʵ PKCS1/PKCS5/PKCS7/ISO10126 ȶ봦ơ
-*           ע֧ PKCS12 淶֤鼰Կװʽ
-* ƽ̨WinXP + Delphi 5.0
-* ݲԣδ
-*   õԪ豾ػ
-* ޸ļ¼2024.05.27 V1.6
-*                ISO10126 Ĵ
-*           2023.12.14 V1.5
-*                SaveMemoryToPemStream δ
-*           2022.03.09 V1.4
-*                PKCS5 Ĵ
-*           2021.05.14 V1.3
-*               ĸ PKCS7 Ĵ
-*           2020.03.27 V1.2
-*               ģ Openssl ʵ PEM ļд룬ֲֻּ֧㷨
-*               Ŀǰд des/3des/aes128/192/256 PKCS7 룬 Openssl 1.0.2g
-*           2020.03.23 V1.1
-*               ģ Openssl ʵ PEM ļܶȡֲֻּ֧㷨
-*               Ŀǰȡ des/3des/aes128/192/256 PKCS7 룬 Openssl 1.0.2g
-*           2020.03.18 V1.0
-*               Ԫ CnRSA ж
-================================================================================
-|
} - -interface - -{$I CnPack.inc} - -uses - SysUtils, Classes, CnNative, CnRandom, CnKDF, CnBase64, CnAES, CnDES; - -const - CN_PKCS1_BLOCK_TYPE_PRIVATE_00 = 00; - {* PKCS1 ʱĿֵֶһĬӦ RSA ˽Կܳ} - - CN_PKCS1_BLOCK_TYPE_PRIVATE_FF = 01; - {* PKCS1 ʱĿֵֶĬӦ RSA ˽Կǩ} - - CN_PKCS1_BLOCK_TYPE_PUBLIC_RANDOM = 02; - {* PKCS1 ʱĿֵֶĬӦ RSA ĹԿܳ} - -type - TCnKeyHashMethod = (ckhMd5, ckhSha256); - {* PEM ʽֵ֧Ӵ} - - TCnKeyEncryptMethod = (ckeNone, ckeDES, cke3DES, ckeAES128, ckeAES192, ckeAES256); - {* PEM ʽֵ֧ļ} - -// ======================= PEM ļдּ֧ӽ ======================== - -function LoadPemFileToMemory(const FileName: string; const ExpectHead: string; - const ExpectTail: string; MemoryStream: TMemoryStream; const Password: string = ''; - KeyHashMethod: TCnKeyHashMethod = ckhMd5): Boolean; -{* PEM ʽļָ֤ͷβʵݲܽ Base64 롣 - - - const FileName: string - ļ - const ExpectHead: string - ͷ - const ExpectTail: string - β - MemoryStream: TMemoryStream - ڴ - const Password: string - ļܣڴṩ - KeyHashMethod: TCnKeyHashMethod - ļʹõӴ - - ֵBoolean - ضǷɹ -} - -function LoadPemStreamToMemory(Stream: TStream; const ExpectHead: string; - const ExpectTail: string; MemoryStream: TMemoryStream; const Password: string = ''; - KeyHashMethod: TCnKeyHashMethod = ckhMd5): Boolean; -{* PEM ʽļָ֤ͷβʵݲܽ Base64 롣 - - - Stream: TStream - - const ExpectHead: string - ͷ - const ExpectTail: string - β - MemoryStream: TMemoryStream - ڴ - const Password: string - ܣڴṩ - KeyHashMethod: TCnKeyHashMethod - ʹõӴ - - ֵBoolean - ضǷɹ -} - -function SaveMemoryToPemFile(const FileName: string; const Head: string; const Tail: string; - MemoryStream: TMemoryStream; KeyEncryptMethod: TCnKeyEncryptMethod = ckeNone; - KeyHashMethod: TCnKeyHashMethod = ckhMd5; const Password: string = ''; Append: Boolean = False): Boolean; -{* Stream ݽ Base64 ܷвļͷβдļAppend Ϊ True ʱʾ׷ӡ - - - const FileName: string - дļ - const Head: string - дͷ - const Tail: string - дβ - MemoryStream: TMemoryStream - д - KeyEncryptMethod: TCnKeyEncryptMethod - üͣĬϲ - KeyHashMethod: TCnKeyHashMethod - Ӵ - const Password: string - 룬򴫿 - Append: Boolean - Ƿ׷ӵķʽд - - ֵBoolean - Ƿдɹ -} - -function SaveMemoryToPemStream(Stream: TStream; const Head: string; const Tail: string; - MemoryStream: TMemoryStream; KeyEncryptMethod: TCnKeyEncryptMethod = ckeNone; - KeyHashMethod: TCnKeyHashMethod = ckhMd5; const Password: string = ''; Append: Boolean = False): Boolean; -{* Stream ݽ Base64 ܷвͷβдAppend Ϊ True ʱʾ׷ӡ - - - Stream: TStream - д - const Head: string - дͷ - const Tail: string - дβ - MemoryStream: TMemoryStream - д - KeyEncryptMethod: TCnKeyEncryptMethod - üͣĬϲ - KeyHashMethod: TCnKeyHashMethod - ӴͣĬϲӴ - const Password: string - 룬򴫿 - Append: Boolean - Ƿ׷ӵķʽд - - ֵBoolean - Ƿдɹ -} - -// ===================== PKCS1 / PKCS7 Padding 봦 ==================== - -function AddPKCS1Padding(PaddingType: Integer; BlockSize: Integer; Data: Pointer; - DataByteLen: Integer; OutStream: TStream): Boolean; -{* ݿ鲹д Stream Уسɹڲô롣 - PaddingType ȡ 012BlockLen ֽ 128 ȡʽ - EB = 00 || BT || PS || 00 || D - 00 ǰ涨ֽڣBT 1 ֽڵ PaddingType0 1 2 ֱ 00 FF - PS Ķֽݣ 00 ǹ涨Ľβֽڡ - - - PaddingType: Integer - ͣȡ 0 1 2 - BlockSize: Integer - ֽڳ - Data: Pointer - ݿĵַ - DataByteLen: Integer - ݿֽڳ - OutStream: TStream - - - ֵBoolean - ضǷӳɹ -} - -function RemovePKCS1Padding(InData: Pointer; InDataByteLen: Integer; OutBuf: Pointer; - out OutByteLen: Integer): Boolean; -{* ȥݿ PKCS1 PaddingسɹOutBuf ָĿóб֤ - ɹOutLen ԭݳȡ - - - InData: Pointer - ȥݿĵַ - InDataByteLen: Integer - ȥݿֽڳ - OutBuf: Pointer - ȥݵ䳤ȱ㹻 - out OutByteLen: Integer - ȥݳ - - ֵBoolean - ضǷȥɹ -} - -function GetPKCS7PaddingByteLength(OrignalByteLen: Integer; BlockSize: Integer): Integer; -{* ԭʼ鳤ȼ PKCS7 ijȡ - - - OrignalByteLen: Integer - ԭʼֽڳ - BlockSize: Integer - PKCS7 ֽڳ - - ֵInteger - PKCS7 ֽڳ -} - -procedure AddPKCS7Padding(Stream: TMemoryStream; BlockSize: Integer); -{* ĩβ PKCS7 涨䡰ݡ - - - Stream: TMemoryStream - ڴݣݽ׷дβ - BlockSize: Integer - PKCS7 ֽڳ - - ֵޣ -} - -procedure RemovePKCS7Padding(Stream: TMemoryStream); -{* ȥ PKCS7 涨ĩβ䡰ݡ - - - Stream: TMemoryStream - ȥڴ - - ֵޣ} - -function StrAddPKCS7Padding(const Str: AnsiString; BlockSize: Integer): AnsiString; -{* ַĩβ PKCS7 涨䡰ݡ - - - const Str: AnsiString - ַ - BlockSize: Integer - PKCS7 ֽڳ - - ֵAnsiString - ضַ -} - -function StrRemovePKCS7Padding(const Str: AnsiString): AnsiString; -{* ȥ PKCS7 涨ַĩβ䡰ݡ - - - const Str: AnsiString - ȥַ - - ֵAnsiString - ȥַ -} - -procedure BytesAddPKCS7Padding(var Data: TBytes; BlockSize: Integer); -{* ֽĩβ PKCS7 涨䡰ݡ - - - var Data: TBytes - ֽ飬ݽ׷β - BlockSize: Integer - PKCS7 ֽڳ - - ֵޣ -} - -procedure BytesRemovePKCS7Padding(var Data: TBytes); -{* ȥ PKCS7 涨ֽĩβ䡰ݡ - - - var Data: TBytes - ȥֽ - - ֵޣ -} - -procedure AddPKCS5Padding(Stream: TMemoryStream); -{* ĩβ PKCS5 涨䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ - - - Stream: TMemoryStream - ڴݽ׷β - - ֵޣ -} - -procedure RemovePKCS5Padding(Stream: TMemoryStream); -{* ȥ PKCS7 涨ĩβ䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ - - - Stream: TMemoryStream - ȥڴ - - ֵޣ -} - -function StrAddPKCS5Padding(const Str: AnsiString): AnsiString; -{* ַĩβ PKCS5 涨䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ - - - const Str: AnsiString - ַ - - ֵAnsiString - ضַ -} - -function StrRemovePKCS5Padding(const Str: AnsiString): AnsiString; -{* ȥ PKCS5 涨ַĩβ䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ - - - const Str: AnsiString - ȥַ - - ֵAnsiString - ȥַ -} - -procedure BytesAddPKCS5Padding(var Data: TBytes); -{* ֽĩβ PKCS5 涨䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ - - - var Data: TBytes - ֽ飬ݽ׷β - - ֵޣ -} - -procedure BytesRemovePKCS5Padding(var Data: TBytes); -{* ȥ PKCS7 涨ֽĩβ䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ - - - var Data: TBytes - ȥֽ - - ֵޣ -} - -function GetISO10126PaddingByteLength(OrignalByteLen: Integer; BlockSize: Integer): Integer; -{* ԭʼ鳤ȼ ISO10126Padding ijȡ - - - OrignalByteLen: Integer - ԭʼֽڳ - BlockSize: Integer - ISO10126 ֽڳ - - ֵInteger - PKCS7 ֽڳ -} - -procedure AddISO10126Padding(Stream: TMemoryStream; BlockSize: Integer); -{* ĩβ ISO10126Padding 涨䡰ͼݡ - - - Stream: TMemoryStream - ڴݽ׷β - BlockSize: Integer - ISO10126 ֽڳ - - ֵޣ -} - -procedure RemoveISO10126Padding(Stream: TMemoryStream); -{* ȥ ISO10126Padding 涨ĩβ䡰ͼݡ - - - Stream: TMemoryStream - ȥڴ - - ֵޣ -} - -function StrAddISO10126Padding(const Str: AnsiString; BlockSize: Integer): AnsiString; -{* ַĩβ ISO10126Padding 涨䡰ͼݡ - - - const Str: AnsiString - ַ - BlockSize: Integer - ISO10126 ֽڴС - - ֵAnsiString - ضַ -} - -function StrRemoveISO10126Padding(const Str: AnsiString): AnsiString; -{* ȥ ISO10126Padding 涨ַĩβ䡰ͼݡ - - - const Str: AnsiString - ȥַ - - ֵAnsiString - ȥַ -} - -procedure BytesAddISO10126Padding(var Data: TBytes; BlockSize: Integer); -{* ֽĩβ ISO10126Padding 涨䡰ͼݡ - - - var Data: TBytes - ֽ飬ݽ׷β - BlockSize: Integer - ISO10126 ֽڳ - - ֵޣ -} - -procedure BytesRemoveISO10126Padding(var Data: TBytes); -{* ȥ ISO10126Padding 涨ֽĩβ䡰ͼݡ - - - var Data: TBytes - ȥֽ - - ֵޣ -} - -implementation - -const - PKCS1_PADDING_SIZE = 11; // һǰ 00һֽڡ 8 ֽ䣬һ 00 β - PKCS5_BLOCK_SIZE = 8; - - ENC_HEAD_PROCTYPE = 'Proc-Type:'; - ENC_HEAD_PROCTYPE_NUM = '4'; - ENC_HEAD_ENCRYPTED = 'ENCRYPTED'; - ENC_HEAD_DEK = 'DEK-Info:'; - - ENC_TYPE_AES128 = 'AES-128'; - ENC_TYPE_AES192 = 'AES-192'; - ENC_TYPE_AES256 = 'AES-256'; - ENC_TYPE_DES = 'DES'; - ENC_TYPE_3DES = 'DES-EDE3'; - - ENC_BLOCK_CBC = 'CBC'; - - ENC_TYPE_STRS: array[TCnKeyEncryptMethod] of string = - ('', ENC_TYPE_DES, ENC_TYPE_3DES, ENC_TYPE_AES128, ENC_TYPE_AES192, ENC_TYPE_AES256); - - ENC_TYPE_BLOCK_SIZE: array[TCnKeyEncryptMethod] of Byte = - (0, 8, 8, 16, 16, 16); - -function Min(A, B: Integer): Integer; -begin - if A < B then - Result := A - else - Result := B; -end; - -function AddPKCS1Padding(PaddingType, BlockSize: Integer; Data: Pointer; - DataByteLen: Integer; OutStream: TStream): Boolean; -var - I: Integer; - B, F: Byte; -begin - Result := False; - if (Data = nil) or (DataByteLen <= 0) then - Exit; - - // - if DataByteLen > BlockSize - PKCS1_PADDING_SIZE then - Exit; - - B := 0; - OutStream.Write(B, 1); // дǰֽ 00 - B := PaddingType; - F := BlockSize - DataByteLen - 3; // 3 ʾһǰ 00һֽڡһ 00 β - - OutStream.Write(B, 1); - case PaddingType of - CN_PKCS1_BLOCK_TYPE_PRIVATE_00: - begin - B := 0; - for I := 1 to F do - OutStream.Write(B, 1); - end; - CN_PKCS1_BLOCK_TYPE_PRIVATE_FF: - begin - B := $FF; - for I := 1 to F do - OutStream.Write(B, 1); - end; - CN_PKCS1_BLOCK_TYPE_PUBLIC_RANDOM: - begin - Randomize; - for I := 1 to F do - begin - B := Trunc(Random(255)); - if B = 0 then - Inc(B); - OutStream.Write(B, 1); - end; - end; - else - Exit; - end; - - B := 0; - OutStream.Write(B, 1); - OutStream.Write(Data^, DataByteLen); - Result := True; -end; - -function RemovePKCS1Padding(InData: Pointer; InDataByteLen: Integer; OutBuf: Pointer; - out OutByteLen: Integer): Boolean; -var - P: PAnsiChar; - I, J, Start: Integer; -begin - Result := False; - OutByteLen := 0; - I := 0; - - P := PAnsiChar(InData); - while P[I] = #0 do // ַһ #0Ѿȥ - Inc(I); - - if I >= InDataByteLen then - Exit; - - Start := 0; - case Ord(P[I]) of - CN_PKCS1_BLOCK_TYPE_PRIVATE_00: - begin - // P[I + 1] ʼѰҷ 00 - J := I + 1; - while J < InDataByteLen do - begin - if P[J] <> #0 then - begin - Start := J; - Break; - end; - Inc(J); - end; - end; - CN_PKCS1_BLOCK_TYPE_PRIVATE_FF, - CN_PKCS1_BLOCK_TYPE_PUBLIC_RANDOM: - begin - // P[I + 1] ʼѰҵһ 00 ı - J := I + 1; - while J < InDataByteLen do - begin - if P[J] = #0 then - begin - Start := J; - Break; - end; - Inc(J); - end; - - if Start <> 0 then - Inc(Start); - end; - end; - - if Start > 0 then - begin - Move(P[Start], OutBuf^, InDataByteLen - Start); - OutByteLen := InDataByteLen - Start; - Result := True; - end; -end; - -function GetPKCS7PaddingByteLength(OrignalByteLen: Integer; BlockSize: Integer): Integer; -var - R: Byte; -begin - R := OrignalByteLen mod BlockSize; - R := BlockSize - R; - if R = 0 then - R := R + BlockSize; - Result := OrignalByteLen + R; -end; - -procedure AddPKCS7Padding(Stream: TMemoryStream; BlockSize: Integer); -var - R: Byte; - Buf: array[0..255] of Byte; -begin - R := Stream.Size mod BlockSize; - R := BlockSize - R; - if R = 0 then - R := R + BlockSize; - - FillChar(Buf[0], R, R); - Stream.Position := Stream.Size; - Stream.Write(Buf[0], R); -end; - -procedure RemovePKCS7Padding(Stream: TMemoryStream); -var - L: Byte; - Len: Cardinal; - Mem: Pointer; -begin - // ȥ Stream ĩβ 9 9 Padding - if Stream.Size > 1 then - begin - Stream.Position := Stream.Size - 1; - Stream.Read(L, 1); - - if Stream.Size - L < 0 then // ߴ粻ף - Exit; - - Len := Stream.Size - L; - Mem := GetMemory(Len); - if Mem <> nil then - begin - Move(Stream.Memory^, Mem^, Len); - Stream.Clear; - Stream.Write(Mem^, Len); - FreeMemory(Mem); - end; - end; -end; - -function StrAddPKCS7Padding(const Str: AnsiString; BlockSize: Integer): AnsiString; -var - I, L: Integer; - R: Byte; -begin - L := Length(Str); - R := L mod BlockSize; - R := BlockSize - R; - if R = 0 then - R := R + BlockSize; - - SetLength(Result, L + R); - if L > 0 then - Move(Str[1], Result[1], L); - - for I := 1 to R do - Result[L + I] := AnsiChar(R); -end; - -function StrRemovePKCS7Padding(const Str: AnsiString): AnsiString; -var - L: Integer; - V: Byte; -begin - Result := Str; - if Result = '' then - Exit; - - L := Length(Result); - V := Ord(Result[L]); // ĩǼʾ˼ - - if V <= L then - Delete(Result, L - V + 1, V); -end; - -procedure AddPKCS5Padding(Stream: TMemoryStream); -begin - AddPKCS7Padding(Stream, PKCS5_BLOCK_SIZE); -end; - -procedure RemovePKCS5Padding(Stream: TMemoryStream); -begin - RemovePKCS7Padding(Stream); -end; - -function StrAddPKCS5Padding(const Str: AnsiString): AnsiString; -begin - Result := StrAddPKCS7Padding(Str, PKCS5_BLOCK_SIZE); -end; - -function StrRemovePKCS5Padding(const Str: AnsiString): AnsiString; -begin - Result := StrRemovePKCS7Padding(Str); -end; - -procedure BytesAddPKCS7Padding(var Data: TBytes; BlockSize: Integer); -var - R: Byte; - L, I: Integer; -begin - L := Length(Data); - R := L mod BlockSize; - R := BlockSize - R; - if R = 0 then - R := R + BlockSize; - - SetLength(Data, L + R); - for I := 0 to R - 1 do - Data[L + I] := R; -end; - -procedure BytesRemovePKCS7Padding(var Data: TBytes); -var - L: Integer; - V: Byte; -begin - L := Length(Data); - if L = 0 then - Exit; - - V := Ord(Data[L - 1]); // ĩǼʾ˼ֽ - - if V <= L then - SetLength(Data, L - V); -end; - -procedure BytesAddPKCS5Padding(var Data: TBytes); -begin - BytesAddPKCS7Padding(Data, PKCS5_BLOCK_SIZE); -end; - -procedure BytesRemovePKCS5Padding(var Data: TBytes); -begin - BytesRemovePKCS7Padding(Data); -end; - -function GetISO10126PaddingByteLength(OrignalByteLen: Integer; BlockSize: Integer): Integer; -begin - Result := GetPKCS7PaddingByteLength(OrignalByteLen, BlockSize); // Ϊֱͬӵ -end; - -procedure AddISO10126Padding(Stream: TMemoryStream; BlockSize: Integer); -var - R: Byte; - Buf: array[0..255] of Byte; -begin - R := Stream.Size mod BlockSize; - R := BlockSize - R; - if R = 0 then - R := R + BlockSize; - - FillChar(Buf[0], R, 0); - Buf[R - 1] := R; - Stream.Position := Stream.Size; - Stream.Write(Buf[0], R); -end; - -procedure RemoveISO10126Padding(Stream: TMemoryStream); -begin - RemovePKCS7Padding(Stream); // Ϊֱͬӵ -end; - -function StrAddISO10126Padding(const Str: AnsiString; BlockSize: Integer): AnsiString; -var - I, L: Integer; - R: Byte; -begin - L := Length(Str); - R := L mod BlockSize; - R := BlockSize - R; - if R = 0 then - R := R + BlockSize; - - SetLength(Result, L + R); - if L > 0 then - Move(Str[1], Result[1], L); - - if R > 1 then - begin - for I := 1 to R - 1 do - Result[L + I] := #0; - end; - Result[L + R] := AnsiChar(R); -end; - -function StrRemoveISO10126Padding(const Str: AnsiString): AnsiString; -begin - Result := StrRemovePKCS7Padding(Str); // Ϊֱͬӵ -end; - -procedure BytesAddISO10126Padding(var Data: TBytes; BlockSize: Integer); -var - R: Byte; - L, I: Integer; -begin - L := Length(Data); - R := L mod BlockSize; - R := BlockSize - R; - if R = 0 then - R := R + BlockSize; - - SetLength(Data, L + R); - if R > 1 then - begin - for I := 0 to R - 2 do - Data[L + I] := 0; - end; - Data[L - 1 + R] := R; -end; - -procedure BytesRemoveISO10126Padding(var Data: TBytes); -begin - BytesRemovePKCS7Padding(Data); // Ϊֱͬӵ -end; - -function EncryptPemStream(KeyHash: TCnKeyHashMethod; KeyEncrypt: TCnKeyEncryptMethod; - Stream: TStream; const Password: string; out EncryptedHead: string): Boolean; -const - CRLF = #13#10; -var - ES: TMemoryStream; - Keys: array[0..31] of Byte; //  Key Ҳֻ 32 ֽ - IvStr: AnsiString; - HexIv: string; - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; - AesIv: TCnAESBuffer; - DesKey: TCnDESKey; - Des3Key: TCn3DESKey; - DesIv: TCnDESIv; -begin - Result := False; - - // - if (KeyEncrypt = ckeNone) or (Password = '') then - Exit; - - // Iv - SetLength(IvStr, ENC_TYPE_BLOCK_SIZE[KeyEncrypt]); - CnRandomFillBytes(@(IvStr[1]), ENC_TYPE_BLOCK_SIZE[KeyEncrypt]); - HexIv := DataToHex(@(IvStr[1]), ENC_TYPE_BLOCK_SIZE[KeyEncrypt], True); // Ҫд - - EncryptedHead := ENC_HEAD_PROCTYPE + ' ' + ENC_HEAD_PROCTYPE_NUM + ',' + ENC_HEAD_ENCRYPTED + CRLF; - EncryptedHead := EncryptedHead + ENC_HEAD_DEK + ' ' + ENC_TYPE_STRS[KeyEncrypt] - + '-' + ENC_BLOCK_CBC + ',' + HexIv + CRLF; - - ES := TMemoryStream.Create; - Stream.Position := 0; - - try - if KeyHash = ckhMd5 then - begin - if not CnGetDeriveKey(AnsiString(Password), IvStr, @Keys[0], SizeOf(Keys)) then - Exit; - end - else if KeyHash = ckhSha256 then - begin - if not CnGetDeriveKey(AnsiString(Password), IvStr, @Keys[0], SizeOf(Keys), ckdSha256) then - Exit; - end - else - Exit; - - case KeyEncrypt of - ckeDES: - begin - Move(Keys[0], DesKey[0], SizeOf(TCnDESKey)); - Move(IvStr[1], DesIv[0], SizeOf(TCnDESIv)); - - DESEncryptStreamCBC(Stream, Stream.Size, DesKey, DesIv, ES); - Result := True; - end; - cke3DES: - begin - Move(Keys[0], Des3Key[0], SizeOf(TCn3DESKey)); - Move(IvStr[1], DesIv[0], SizeOf(TCn3DESIv)); - - TripleDESEncryptStreamCBC(Stream, Stream.Size, Des3Key, DesIv, ES); - Result := True; - end; - ckeAES128: - begin - Move(Keys[0], AESKey128[0], SizeOf(TCnAESKey128)); - Move(IvStr[1], AesIv[0], SizeOf(TCnAESBuffer)); - - EncryptAES128StreamCBC(Stream, Stream.Size, AESKey128, AesIv, ES); - Result := True; - end; - ckeAES192: - begin - Move(Keys[0], AESKey192[0], SizeOf(TCnAESKey192)); - Move(IvStr[1], AesIv[0], SizeOf(TCnAESBuffer)); - - EncryptAES192StreamCBC(Stream, Stream.Size, AESKey192, AesIv, ES); - Result := True; - end; - ckeAES256: - begin - Move(Keys[0], AESKey256[0], SizeOf(TCnAESKey256)); - Move(IvStr[1], AesIv[0], SizeOf(TCnAESBuffer)); - - EncryptAES256StreamCBC(Stream, Stream.Size, AESKey256, AesIv, ES); - Result := True; - end; - end; - finally - if ES.Size > 0 then - begin - // ES д Stream - Stream.Size := 0; - Stream.Position := 0; - ES.SaveToStream(Stream); - Stream.Position := 0; - end; - ES.Free; - end; -end; - -// ü㷨㡢ʼ⿪ Base64 Sд Stream -function DecryptPemString(const S, M1, M2, HexIv, Password: string; Stream: TMemoryStream; - KeyHash: TCnKeyHashMethod): Boolean; -var - DS: TMemoryStream; - Keys: array[0..31] of Byte; //  Key Ҳֻ 32 ֽ - AESKey128: TCnAESKey128; - AESKey192: TCnAESKey192; - AESKey256: TCnAESKey256; - IvStr: AnsiString; - AesIv: TCnAESBuffer; - DesKey: TCnDESKey; - Des3Key: TCn3DESKey; - DesIv: TCnDESIv; -begin - Result := False; - DS := nil; - - if (M1 = '') or (M2 = '') or (HexIv = '') or (Password = '') then - Exit; - - try - DS := TMemoryStream.Create; - if ECN_BASE64_OK <> Base64Decode(AnsiString(S), DS, False) then - Exit; - - DS.Position := 0; - SetLength(IvStr, HexToData(HexIv)); - if Length(IvStr) > 0 then - HexToData(HexIv, @IvStr[1]); - - // Salt Լ Hash 㷨ӽܵ Key - FillChar(Keys[0], SizeOf(Keys), 0); - if KeyHash = ckhMd5 then - begin - if not CnGetDeriveKey(AnsiString(Password), IvStr, @Keys[0], SizeOf(Keys)) then - Exit; - end - else if KeyHash = ckhSha256 then - begin - if not CnGetDeriveKey(AnsiString(Password), IvStr, @Keys[0], SizeOf(Keys), ckdSha256) then - Exit; - end - else - Exit; - - // DS ģҪ⵽ Stream - if (M1 = ENC_TYPE_AES256) and (M2 = ENC_BLOCK_CBC) then - begin - // ⿪ AES-256-CBC ܵ - Move(Keys[0], AESKey256[0], SizeOf(TCnAESKey256)); - Move(IvStr[1], AesIv[0], Min(SizeOf(TCnAESBuffer), Length(IvStr))); - - DecryptAES256StreamCBC(DS, DS.Size, AESKey256, AesIv, Stream); - RemovePKCS7Padding(Stream); - Result := True; - end - else if (M1 = ENC_TYPE_AES192) and (M2 = ENC_BLOCK_CBC) then - begin - // ⿪ AES-192-CBC ܵ - Move(Keys[0], AESKey192[0], SizeOf(TCnAESKey192)); - Move(IvStr[1], AesIv[0], Min(SizeOf(TCnAESBuffer), Length(IvStr))); - - DecryptAES192StreamCBC(DS, DS.Size, AESKey192, AesIv, Stream); - RemovePKCS7Padding(Stream); - Result := True; - end - else if (M1 = ENC_TYPE_AES128) and (M2 = ENC_BLOCK_CBC) then - begin - // ⿪ AES-128-CBC ܵģ D5 òƿ Bug ³ AV - Move(Keys[0], AESKey128[0], SizeOf(TCnAESKey128)); - Move(IvStr[1], AesIv[0], Min(SizeOf(TCnAESBuffer), Length(IvStr))); - - DecryptAES128StreamCBC(DS, DS.Size, AESKey128, AesIv, Stream); - RemovePKCS7Padding(Stream); - Result := True; - end - else if (M1 = ENC_TYPE_DES) and (M2 = ENC_BLOCK_CBC) then - begin - // ⿪ DES-CBC ܵ - Move(Keys[0], DesKey[0], SizeOf(TCnDESKey)); - Move(IvStr[1], DesIv[0], Min(SizeOf(TCnDESIv), Length(IvStr))); - - DESDecryptStreamCBC(DS, DS.Size, DesKey, DesIv, Stream); - RemovePKCS7Padding(Stream); - Result := True; - end - else if (M1 = ENC_TYPE_3DES) and (M2 = ENC_BLOCK_CBC) then - begin - // ⿪ 3DES-CBC ܵ - Move(Keys[0], Des3Key[0], SizeOf(TCn3DESKey)); - Move(IvStr[1], DesIv[0], Min(SizeOf(TCn3DESIv), Length(IvStr))); - - TripleDESDecryptStreamCBC(DS, DS.Size, Des3Key, DesIv, Stream); - RemovePKCS7Padding(Stream); - Result := True; - end; - finally - DS.Free; - end; -end; - -function LoadPemStreamToMemory(Stream: TStream; const ExpectHead, ExpectTail: string; - MemoryStream: TMemoryStream; const Password: string; KeyHashMethod: TCnKeyHashMethod): Boolean; -var - I, J, HeadIndex, TailIndex: Integer; - S, L1, L2, M1, M2, M3: string; - Sl: TStringList; -begin - Result := False; - - if (Stream <> nil) and (Stream.Size > 0) and (ExpectHead <> '') and (ExpectTail <> '') then - begin - Sl := TStringList.Create; - try - Sl.LoadFromStream(Stream); - if Sl.Count > 2 then - begin - HeadIndex := -1; - for I := 0 to Sl.Count - 1 do - begin - if Trim(Sl[I]) = ExpectHead then - begin - HeadIndex := I; - Break; - end; - end; - - if HeadIndex < 0 then - Exit; - - if HeadIndex > 0 then - for I := 0 to HeadIndex - 1 do - Sl.Delete(0); - - // ҵͷˣβ - - TailIndex := -1; - for I := 0 to Sl.Count - 1 do - begin - if Trim(Sl[I]) = ExpectTail then - begin - TailIndex := I; - Break; - end; - end; - - if TailIndex > 0 then // ҵβͣɾβͺĶ - begin - if TailIndex < Sl.Count - 1 then - for I := Sl.Count - 1 downto TailIndex + 1 do - Sl.Delete(Sl.Count - 1); - end - else - Exit; - - if Sl.Count < 2 then // ûݣ˳ - Exit; - - // ͷβ֤ͨǰжǷ - L1 := Sl[1]; - if Pos(ENC_HEAD_PROCTYPE, L1) = 1 then // Ǽܵ - begin - Delete(L1, 1, Length(ENC_HEAD_PROCTYPE)); - I := Pos(',', L1); - if I <= 1 then - Exit; - - if Trim(Copy(L1, 1, I - 1)) <> ENC_HEAD_PROCTYPE_NUM then - Exit; - - if Trim(Copy(L1, I + 1, MaxInt)) <> ENC_HEAD_ENCRYPTED then - Exit; - - // ProcType: 4,ENCRYPTED жͨ - - L2 := Sl[2]; - if Pos(ENC_HEAD_DEK, L2) <> 1 then - Exit; - - Delete(L2, 1, Length(ENC_HEAD_DEK)); - I := Pos(',', L2); - if I <= 1 then - Exit; - - M1 := Trim(Copy(L2, 1, I - 1)); // õ AES256-CBC - M3 := UpperCase(Trim(Copy(L2, I + 1, MaxInt))); // õʱʹõijʼ - I := Pos('-', M1); - if I <= 1 then - Exit; - J := Pos('-', Copy(M1, I + 1, MaxInt)); - if J > 0 then - I := I + J; // AES-256-CBC - - M2 := UpperCase(Trim(Copy(M1, I + 1, MaxInt))); // õģʽ ECB CBC - M1 := UpperCase(Trim(Copy(M1, 1, I - 1))); // õ㷨 DES AES - - // ͷβȫɾ - Sl.Delete(Sl.Count - 1); - Sl.Delete(0); - Sl.Delete(0); - Sl.Delete(0); - - S := ''; - for I := 0 to Sl.Count - 1 do - S := S + Sl[I]; - - S := Trim(S); - - Result := DecryptPemString(S, M1, M2, M3, Password, MemoryStream, KeyHashMethod); - end - else // δܵģƴճ Base64 - begin - Sl.Delete(Sl.Count - 1); - Sl.Delete(0); - S := ''; - for I := 0 to Sl.Count - 1 do - S := S + Sl[I]; - - S := Trim(S); - - // To De Base64 S - MemoryStream.Clear; -{$IFDEF UNICODE} - Result := (ECN_BASE64_OK = Base64Decode(AnsiString(S), MemoryStream, False)); -{$ELSE} - Result := (ECN_BASE64_OK = Base64Decode(S, MemoryStream, False)); -{$ENDIF} - end; - end; - finally - Sl.Free; - end; - end; -end; - -function LoadPemFileToMemory(const FileName, ExpectHead, ExpectTail: string; - MemoryStream: TMemoryStream; const Password: string; KeyHashMethod: TCnKeyHashMethod): Boolean; -var - Stream: TStream; -begin - Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); - try - Result := LoadPemStreamToMemory(Stream, ExpectHead, ExpectTail, MemoryStream, Password, KeyHashMethod); - finally - Stream.Free; - end; -end; - -procedure SplitStringToList(const S: string; List: TStrings); -const - LINE_WIDTH = 64; -var - C, R: string; -begin - if List = nil then - Exit; - - List.Clear; - if S <> '' then - begin - R := S; - while R <> '' do - begin - C := Copy(R, 1, LINE_WIDTH); - Delete(R, 1, LINE_WIDTH); - List.Add(C); - end; - end; -end; - -function SaveMemoryToPemFile(const FileName, Head, Tail: string; - MemoryStream: TMemoryStream; KeyEncryptMethod: TCnKeyEncryptMethod; - KeyHashMethod: TCnKeyHashMethod; const Password: string; Append: Boolean): Boolean; -var - S, EH: string; - List, Sl: TStringList; -begin - Result := False; - if (MemoryStream <> nil) and (MemoryStream.Size <> 0) then - begin - MemoryStream.Position := 0; - - if (KeyEncryptMethod <> ckeNone) and (Password <> '') then - begin - // MemoryStream - AddPKCS7Padding(MemoryStream, ENC_TYPE_BLOCK_SIZE[KeyEncryptMethod]); - - // ټ - if not EncryptPemStream(KeyHashMethod, KeyEncryptMethod, MemoryStream, Password, EH) then - Exit; - end; - - if ECN_BASE64_OK = Base64Encode(MemoryStream, S) then - begin - List := TStringList.Create; - try - SplitStringToList(S, List); - - List.Insert(0, Head); // ͨͷ - if EH <> '' then // ͷ - List.Insert(1, EH); - List.Add(Tail); // ͨβ - - if Append and FileExists(FileName) then - begin - Sl := TStringList.Create; - try - Sl.LoadFromFile(FileName); - Sl.AddStrings(List); - Sl.SaveToFile(FileName); - finally - Sl.Free; - end; - end - else - List.SaveToFile(FileName); - - Result := True; - finally - List.Free; - end; - end; - end; -end; - -function SaveMemoryToPemStream(Stream: TStream; const Head, Tail: string; - MemoryStream: TMemoryStream; KeyEncryptMethod: TCnKeyEncryptMethod; - KeyHashMethod: TCnKeyHashMethod; const Password: string; Append: Boolean): Boolean; -var - S, EH: string; - List: TStringList; -begin - Result := False; - if (MemoryStream <> nil) and (MemoryStream.Size <> 0) then - begin - MemoryStream.Position := 0; - - if (KeyEncryptMethod <> ckeNone) and (Password <> '') then - begin - // MemoryStream - AddPKCS7Padding(MemoryStream, ENC_TYPE_BLOCK_SIZE[KeyEncryptMethod]); - - // ټ - if not EncryptPemStream(KeyHashMethod, KeyEncryptMethod, MemoryStream, Password, EH) then - Exit; - end; - - if ECN_BASE64_OK = Base64Encode(MemoryStream, S) then - begin - List := TStringList.Create; - try - SplitStringToList(S, List); - - List.Insert(0, Head); // ͨͷ - if EH <> '' then // ͷ - List.Insert(1, EH); - List.Add(Tail); // ͨβ - - if not Append then - Stream.Size := 0; - - List.SaveToStream(Stream); - - Result := True; - finally - List.Free; - end; - end; - end; -end; - -end. +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnPemUtils; +{* |
+================================================================================
+* ƣ
+* ԪƣPEM ʽ뵥Ԫ
+* ԪߣCnPack 
+*     עԪʵ PEM ʽĶȡ뱣棬ӽܻơ
+*           Ҳʵ PKCS1/PKCS5/PKCS7/ISO10126 ȶ봦ơ
+*           ע֧ PKCS12 淶֤鼰Կװʽ
+* ƽ̨WinXP + Delphi 5.0
+* ݲԣδ
+*   õԪ豾ػ
+* ޸ļ¼2026.04.05 V1.8
+*               ǿְȫ
+*           2026.03.24 V1.7
+*               ض汾ı TStringList д Stream  BOM ޷ƣʵ
+*           2024.05.27 V1.6
+*                ISO10126 Ĵ
+*           2023.12.14 V1.5
+*                SaveMemoryToPemStream δ
+*           2022.03.09 V1.4
+*                PKCS5 Ĵ
+*           2021.05.14 V1.3
+*               ĸ PKCS7 Ĵ
+*           2020.03.27 V1.2
+*               ģ Openssl ʵ PEM ļд룬ֲֻּ֧㷨
+*               Ŀǰд des/3des/aes128/192/256 PKCS7 룬 Openssl 1.0.2g
+*           2020.03.23 V1.1
+*               ģ Openssl ʵ PEM ļܶȡֲֻּ֧㷨
+*               Ŀǰȡ des/3des/aes128/192/256 PKCS7 룬 Openssl 1.0.2g
+*           2020.03.18 V1.0
+*               Ԫ CnRSA ж
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes, CnNative, CnRandom, CnKDF, CnBase64, CnAES, CnDES, CnSM4; + +const + CN_PKCS1_BLOCK_TYPE_PRIVATE_00 = 00; + {* PKCS1 ʱĿֵֶһĬӦ RSA ˽Կܻǩϣ RFC2313 Ƽʹ} + + CN_PKCS1_BLOCK_TYPE_PRIVATE_FF = 01; + {* PKCS1 ʱĿֵֶĬӦ RSA ˽ԿܻǩϣRFC2313 Ƽʹ} + + CN_PKCS1_BLOCK_TYPE_PUBLIC_RANDOM = 02; + {* PKCS1 ʱĿֵֶĬӦ RSA ĹԿܳ} + + CN_PKCS1_PADDING_SIZE = 11; + {* PKCS1 ĴСֵһǰ 00һֽڡ 8 ֽ䣬һ 00 β} + + CN_PKCS5_BLOCK_SIZE = 8; + {* PKCS5 ĬϿС} + + CN_PKCS7_BLOCK_SIZE = 16; + {* PKCS7 СAES} + +type + TCnKeyHashMethod = (ckhMd5, ckhSha256); + {* PEM ʽֵ֧Ӵ} + + TCnKeyEncryptMethod = (ckeNone, ckeDES, cke3DES, ckeAES128, ckeAES192, ckeAES256, + ckeSM4); + {* PEM ʽֵ֧ļ} + +// ======================= PEM ļдּ֧ӽ ======================== + +function LoadPemFileToMemory(const FileName: string; const ExpectHead: string; + const ExpectTail: string; MemoryStream: TMemoryStream; const Password: string = ''; + KeyHashMethod: TCnKeyHashMethod = ckhMd5): Boolean; +{* PEM ʽļָ֤ͷβʵݲܽ Base64 롣 + + + const FileName: string - ļ + const ExpectHead: string - ͷ + const ExpectTail: string - β + MemoryStream: TMemoryStream - ڴ + const Password: string - ļܣڴṩ + KeyHashMethod: TCnKeyHashMethod - ļʹõӴ + + ֵBoolean - ضǷɹ +} + +function LoadPemStreamToMemory(Stream: TStream; const ExpectHead: string; + const ExpectTail: string; MemoryStream: TMemoryStream; const Password: string = ''; + KeyHashMethod: TCnKeyHashMethod = ckhMd5): Boolean; +{* PEM ʽָ֤ͷβʵݲܽ Base64 롣 + + + Stream: TStream - + const ExpectHead: string - ͷ + const ExpectTail: string - β + MemoryStream: TMemoryStream - ڴ + const Password: string - ܣڴṩ + KeyHashMethod: TCnKeyHashMethod - ʹõӴ + + ֵBoolean - ضǷɹ +} + +function SaveMemoryToPemFile(const FileName: string; const Head: string; const Tail: string; + MemoryStream: TMemoryStream; KeyEncryptMethod: TCnKeyEncryptMethod = ckeNone; + KeyHashMethod: TCnKeyHashMethod = ckhMd5; const Password: string = ''; Append: Boolean = False): Boolean; +{* ݽ Base64 ܷвͷβдļAppend Ϊ True ʱʾ׷ӡ + + + const FileName: string - дĿļ + const Head: string - дͷ + const Tail: string - дβ + MemoryStream: TMemoryStream - д + KeyEncryptMethod: TCnKeyEncryptMethod - üͣĬϲ + KeyHashMethod: TCnKeyHashMethod - Ӵ + const Password: string - 룬򴫿 + Append: Boolean - Ƿ׷ӵķʽд + + ֵBoolean - Ƿдɹ +} + +function SaveMemoryToPemStream(Stream: TStream; const Head: string; const Tail: string; + MemoryStream: TMemoryStream; KeyEncryptMethod: TCnKeyEncryptMethod = ckeNone; + KeyHashMethod: TCnKeyHashMethod = ckhMd5; const Password: string = ''; Append: Boolean = False): Boolean; +{* ݽ Base64 ܷвͷβдAppend Ϊ True ʱʾ׷ӡ + + + Stream: TStream - дĿ + const Head: string - дͷ + const Tail: string - дβ + MemoryStream: TMemoryStream - д + KeyEncryptMethod: TCnKeyEncryptMethod - üͣĬϲ + KeyHashMethod: TCnKeyHashMethod - ӴͣĬϲӴ + const Password: string - 룬򴫿 + Append: Boolean - Ƿ׷ӵķʽд + + ֵBoolean - Ƿдɹ +} + +// ===================== PKCS1 / PKCS7 Padding 봦 ==================== + +function AddPKCS1Padding(PaddingType: Integer; BlockSize: Integer; Data: Pointer; + DataByteLen: Integer; OutStream: TStream): Boolean; +{* ݿ鲹д Stream Уسɹڲô롣 + PaddingType ȡ 012BlockLen ֽ 128 ȡʽ + EB = 00 || BT || PS || 00 || D + 00 ǰ涨ֽڣBT 1 ֽڵ PaddingType0 1 2 ֱ 00 FF + PS Ķֽݣ 00 ǹ涨Ľβֽڡ + + + PaddingType: Integer - ͣȡ 0 1 2 + BlockSize: Integer - ֽڳ + Data: Pointer - ݿĵַ + DataByteLen: Integer - ݿֽڳ + OutStream: TStream - + + ֵBoolean - ضǷӳɹ +} + +function RemovePKCS1Padding(InData: Pointer; InDataByteLen: Integer; OutBuf: Pointer; + out OutByteLen: Integer): Boolean; +{* ȥݿ PKCS1 PaddingسɹOutBuf ָĿóб֤ + ɹOutLen ԭݳȡ + + + InData: Pointer - ȥݿĵַ + InDataByteLen: Integer - ȥݿֽڳ + OutBuf: Pointer - ȥݵ䳤ȱ㹻 + out OutByteLen: Integer - ȥݳ + + ֵBoolean - ضǷȥɹ +} + +function GetPKCS7PaddingByteLength(OrignalByteLen: Integer; BlockSize: Integer): Integer; +{* ԭʼ鳤ȼ PKCS7 ijȡ + + + OrignalByteLen: Integer - ԭʼֽڳ + BlockSize: Integer - PKCS7 ֽڳ + + ֵInteger - PKCS7 ֽڳ +} + +procedure AddPKCS7Padding(Stream: TMemoryStream; BlockSize: Integer); +{* ĩβ PKCS7 涨䡰ݡ + + + Stream: TMemoryStream - ڴݣݽ׷дβ + BlockSize: Integer - PKCS7 ֽڳ + + ֵޣ +} + +procedure RemovePKCS7Padding(Stream: TMemoryStream); +{* ȥ PKCS7 涨ĩβ䡰ݡ + + + Stream: TMemoryStream - ȥڴ + + ֵޣ} + +function StrAddPKCS7Padding(const Str: AnsiString; BlockSize: Integer): AnsiString; +{* ַĩβ PKCS7 涨䡰ݡ + + + const Str: AnsiString - ַ + BlockSize: Integer - PKCS7 ֽڳ + + ֵAnsiString - ضַ +} + +function StrRemovePKCS7Padding(const Str: AnsiString): AnsiString; +{* ȥ PKCS7 涨ַĩβ䡰ݡ + + + const Str: AnsiString - ȥַ + + ֵAnsiString - ȥַ +} + +procedure BytesAddPKCS7Padding(var Data: TBytes; BlockSize: Integer); +{* ֽĩβ PKCS7 涨䡰ݡ + + + var Data: TBytes - ֽ飬ݽ׷β + BlockSize: Integer - PKCS7 ֽڳ + + ֵޣ +} + +procedure BytesRemovePKCS7Padding(var Data: TBytes); +{* ȥ PKCS7 涨ֽĩβ䡰ݡ + + + var Data: TBytes - ȥֽ + + ֵޣ +} + +procedure AddPKCS5Padding(Stream: TMemoryStream); +{* ĩβ PKCS5 涨䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + Stream: TMemoryStream - ڴݽ׷β + + ֵޣ +} + +procedure RemovePKCS5Padding(Stream: TMemoryStream); +{* ȥ PKCS7 涨ĩβ䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + Stream: TMemoryStream - ȥڴ + + ֵޣ +} + +function StrAddPKCS5Padding(const Str: AnsiString): AnsiString; +{* ַĩβ PKCS5 涨䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + const Str: AnsiString - ַ + + ֵAnsiString - ضַ +} + +function StrRemovePKCS5Padding(const Str: AnsiString): AnsiString; +{* ȥ PKCS5 涨ַĩβ䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + const Str: AnsiString - ȥַ + + ֵAnsiString - ȥַ +} + +procedure BytesAddPKCS5Padding(var Data: TBytes); +{* ֽĩβ PKCS5 涨䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + var Data: TBytes - ֽ飬ݽ׷β + + ֵޣ +} + +procedure BytesRemovePKCS5Padding(var Data: TBytes); +{* ȥ PKCS7 涨ֽĩβ䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + var Data: TBytes - ȥֽ + + ֵޣ +} + +function GetISO10126PaddingByteLength(OrignalByteLen: Integer; BlockSize: Integer): Integer; +{* ԭʼ鳤ȼ ISO10126Padding ijȡ + + + OrignalByteLen: Integer - ԭʼֽڳ + BlockSize: Integer - ISO10126 ֽڳ + + ֵInteger - PKCS7 ֽڳ +} + +procedure AddISO10126Padding(Stream: TMemoryStream; BlockSize: Integer); +{* ĩβ ISO10126Padding 涨䡰ͼݡ + + + Stream: TMemoryStream - ڴݽ׷β + BlockSize: Integer - ISO10126 ֽڳ + + ֵޣ +} + +procedure RemoveISO10126Padding(Stream: TMemoryStream); +{* ȥ ISO10126Padding 涨ĩβ䡰ͼݡ + + + Stream: TMemoryStream - ȥڴ + + ֵޣ +} + +function StrAddISO10126Padding(const Str: AnsiString; BlockSize: Integer): AnsiString; +{* ַĩβ ISO10126Padding 涨䡰ͼݡ + + + const Str: AnsiString - ַ + BlockSize: Integer - ISO10126 ֽڴС + + ֵAnsiString - ضַ +} + +function StrRemoveISO10126Padding(const Str: AnsiString): AnsiString; +{* ȥ ISO10126Padding 涨ַĩβ䡰ͼݡ + + + const Str: AnsiString - ȥַ + + ֵAnsiString - ȥַ +} + +procedure BytesAddISO10126Padding(var Data: TBytes; BlockSize: Integer); +{* ֽĩβ ISO10126Padding 涨䡰ͼݡ + + + var Data: TBytes - ֽ飬ݽ׷β + BlockSize: Integer - ISO10126 ֽڳ + + ֵޣ +} + +procedure BytesRemoveISO10126Padding(var Data: TBytes); +{* ȥ ISO10126Padding 涨ֽĩβ䡰ͼݡ + + + var Data: TBytes - ȥֽ + + ֵޣ +} + +implementation + +uses + CnStrings; + +const + ENC_HEAD_PROCTYPE = 'Proc-Type:'; + ENC_HEAD_PROCTYPE_NUM = '4'; + ENC_HEAD_ENCRYPTED = 'ENCRYPTED'; + ENC_HEAD_DEK = 'DEK-Info:'; + + ENC_TYPE_AES128 = 'AES-128'; + ENC_TYPE_AES192 = 'AES-192'; + ENC_TYPE_AES256 = 'AES-256'; + ENC_TYPE_DES = 'DES'; + ENC_TYPE_3DES = 'DES-EDE3'; + ENC_TYPE_SM4 = 'SM4'; + + ENC_BLOCK_CBC = 'CBC'; + + ENC_TYPE_STRS: array[TCnKeyEncryptMethod] of string = + ('', ENC_TYPE_DES, ENC_TYPE_3DES, ENC_TYPE_AES128, ENC_TYPE_AES192, + ENC_TYPE_AES256, ENC_TYPE_SM4); + + ENC_TYPE_BLOCK_SIZE: array[TCnKeyEncryptMethod] of Byte = + (0, 8, 8, 16, 16, 16, 16); + +function Min(A, B: Integer): Integer; +begin + if A < B then + Result := A + else + Result := B; +end; + +function AddPKCS1Padding(PaddingType, BlockSize: Integer; Data: Pointer; + DataByteLen: Integer; OutStream: TStream): Boolean; +var + I: Integer; + B, F: Byte; + RandBuf: TBytes; +begin + Result := False; + if (Data = nil) or (DataByteLen <= 0) then + Exit; + + // + if DataByteLen > BlockSize - CN_PKCS1_PADDING_SIZE then + Exit; + + B := 0; + OutStream.Write(B, 1); // дǰֽ 00 + B := PaddingType; + F := BlockSize - DataByteLen - 3; // 3 ʾһǰ 00һֽڡһ 00 β + + OutStream.Write(B, 1); + case PaddingType of + CN_PKCS1_BLOCK_TYPE_PRIVATE_00: + begin + B := 0; + for I := 1 to F do + OutStream.Write(B, 1); + end; + CN_PKCS1_BLOCK_TYPE_PRIVATE_FF: + begin + B := $FF; + for I := 1 to F do + OutStream.Write(B, 1); + end; + CN_PKCS1_BLOCK_TYPE_PUBLIC_RANDOM: + begin + // ʹѧȫCSPRNGȫ Random/Randomize + // ޸ԭʹ LCG α+ʱӣԤ⣬ Bleichenbacher + if F > 0 then + begin + SetLength(RandBuf, F); + CnRandomBytes(F); // CnRandomBytes ɰȫֽ + for I := 0 to F - 1 do + begin + if RandBuf[I] = 0 then + RandBuf[I] := 1; // ȷ㣬 PKCS1 淶 + end; + OutStream.Write(RandBuf[0], F); + end; + end; + else + Exit; + end; + + B := 0; + OutStream.Write(B, 1); + OutStream.Write(Data^, DataByteLen); + Result := True; +end; + +function RemovePKCS1Padding(InData: Pointer; InDataByteLen: Integer; OutBuf: Pointer; + out OutByteLen: Integer): Boolean; +var + P: PAnsiChar; + I, J, Start: Integer; + ValidPadding: Integer; // ʹDzֵ֧ + LeadingZeros: Integer; + PaddingType: Byte; + SeparatorFound: Integer; +begin + // ʱʵ֣ Padding ǷЧִͬIJ + Result := False; + OutByteLen := 0; + P := PAnsiChar(InData); + + // ǰʱ䣩 + LeadingZeros := 0; + for I := 0 to InDataByteLen - 1 do + begin + // ʹλ֧ + ValidPadding := Ord(P[I] = #0) and Ord(I = LeadingZeros); + LeadingZeros := LeadingZeros + ValidPadding; + end; + + // ǷЧҪһֽڣ + if LeadingZeros >= InDataByteLen then + Exit; + + // ȡ Padding + PaddingType := Ord(P[LeadingZeros]); + + // ʱҷָ00 ֽڣ + Start := 0; + SeparatorFound := 0; + + for J := LeadingZeros + 1 to InDataByteLen - 1 do + begin + case PaddingType of + CN_PKCS1_BLOCK_TYPE_PRIVATE_00: + begin + // ҵһֽ + if (P[J] <> #0) and (SeparatorFound = 0) then + begin + Start := J; + SeparatorFound := 1; + end; + end; + CN_PKCS1_BLOCK_TYPE_PRIVATE_FF, + CN_PKCS1_BLOCK_TYPE_PUBLIC_RANDOM: + begin + // ҵһֽ + if (P[J] = #0) and (SeparatorFound = 0) then + begin + Start := J + 1; + SeparatorFound := 1; + end; + end; + end; + end; + + // ֤ Padding ͺͷָ + ValidPadding := Ord( + ((PaddingType = CN_PKCS1_BLOCK_TYPE_PRIVATE_00) or + (PaddingType = CN_PKCS1_BLOCK_TYPE_PRIVATE_FF) or + (PaddingType = CN_PKCS1_BLOCK_TYPE_PUBLIC_RANDOM)) and + (SeparatorFound = 1) and + (Start > 0) and + (Start < InDataByteLen) + ); + + // ʱ临 + if ValidPadding = 1 then + begin + Move(P[Start], OutBuf^, InDataByteLen - Start); + OutByteLen := InDataByteLen - Start; + Result := True; + end; + + // ע⣺ʹʧܣҲҪǰأֳʱ +end; + +function GetPKCS7PaddingByteLength(OrignalByteLen: Integer; BlockSize: Integer): Integer; +var + R: Byte; +begin + R := OrignalByteLen mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + Result := OrignalByteLen + R; +end; + +procedure AddPKCS7Padding(Stream: TMemoryStream; BlockSize: Integer); +var + R: Byte; + Buf: array[0..255] of Byte; +begin + R := Stream.Size mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + FillChar(Buf[0], R, R); + Stream.Position := Stream.Size; + Stream.Write(Buf[0], R); +end; + +procedure RemovePKCS7Padding(Stream: TMemoryStream); +var + L, I: Byte; + Len: Cardinal; + Mem, PBuf: Pointer; + Valid: Boolean; +begin + // ȥ Stream ĩβ 9 9 Padding + if Stream.Size > 1 then + begin + Stream.Position := Stream.Size - 1; + Stream.Read(L, 1); + + // ߴ粻ף + if (L < 1) or (L > CN_PKCS7_BLOCK_SIZE) or (Stream.Size < L) then + Exit; + + // ֽ֤ڶ Lֹ Padding Oracle + PBuf := Stream.Memory; + Valid := True; + for I := 1 to L do + if PByte(TCnNativeUInt(PBuf) + Stream.Size - I)^ <> L then + begin + Valid := False; + Break; + end; + + if not Valid then + Exit; + + Len := Stream.Size - L; + Mem := GetMemory(Len); + if Mem <> nil then + begin + Move(Stream.Memory^, Mem^, Len); + Stream.Clear; + Stream.Write(Mem^, Len); + FreeMemory(Mem); + end; + end; +end; + +function StrAddPKCS7Padding(const Str: AnsiString; BlockSize: Integer): AnsiString; +var + I, L: Integer; + R: Byte; +begin + L := Length(Str); + R := L mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + SetLength(Result, L + R); + if L > 0 then + Move(Str[1], Result[1], L); + + for I := 1 to R do + Result[L + I] := AnsiChar(R); +end; + +function StrRemovePKCS7Padding(const Str: AnsiString): AnsiString; +var + L: Integer; + I, V: Byte; + Valid: Boolean; +begin + Result := Str; + if Result = '' then + Exit; + + L := Length(Result); + V := Ord(Result[L]); // ĩǼʾ˼ + + // ֵ֤ϷԣPKCS7 ֵΧ 1~16С + if (V < 1) or (V > CN_PKCS7_BLOCK_SIZE) or (V > L) then + Exit; + + // ֽ֤ڶ Vֹ Padding Oracle + // ޸ԭֻһֽڣδ֤мֽǷһ + Valid := True; + for I := 1 to V do + begin + if Ord(Result[L - I + 1]) <> V then + begin + Valid := False; + Break; + end; + end; + + if Valid then + Delete(Result, L - V + 1, V); +end; + +procedure AddPKCS5Padding(Stream: TMemoryStream); +begin + AddPKCS7Padding(Stream, CN_PKCS5_BLOCK_SIZE); +end; + +procedure RemovePKCS5Padding(Stream: TMemoryStream); +begin + RemovePKCS7Padding(Stream); +end; + +function StrAddPKCS5Padding(const Str: AnsiString): AnsiString; +begin + Result := StrAddPKCS7Padding(Str, CN_PKCS5_BLOCK_SIZE); +end; + +function StrRemovePKCS5Padding(const Str: AnsiString): AnsiString; +begin + Result := StrRemovePKCS7Padding(Str); +end; + +procedure BytesAddPKCS7Padding(var Data: TBytes; BlockSize: Integer); +var + R: Byte; + L, I: Integer; +begin + L := Length(Data); + R := L mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + SetLength(Data, L + R); + for I := 0 to R - 1 do + Data[L + I] := R; +end; + +procedure BytesRemovePKCS7Padding(var Data: TBytes); +var + L, I, V: Integer; + Valid: Boolean; +begin + L := Length(Data); + if L = 0 then + Exit; + + V := Ord(Data[L - 1]); // ĩǼʾ˼ֽ + + // ֵ֤ϷԣPKCS7 ֵΧ 1~16С + if (V < 1) or (V > CN_PKCS7_BLOCK_SIZE) or (V > L) then + Exit; + + // ֽ֤ڶ Vֹ Padding Oracle + Valid := True; + for I := 1 to V do + if Data[L - I] <> V then + begin + Valid := False; + Break; + end; + + if Valid then + SetLength(Data, L - V); +end; + +procedure BytesAddPKCS5Padding(var Data: TBytes); +begin + BytesAddPKCS7Padding(Data, CN_PKCS5_BLOCK_SIZE); +end; + +procedure BytesRemovePKCS5Padding(var Data: TBytes); +begin + BytesRemovePKCS7Padding(Data); +end; + +function GetISO10126PaddingByteLength(OrignalByteLen: Integer; BlockSize: Integer): Integer; +begin + Result := GetPKCS7PaddingByteLength(OrignalByteLen, BlockSize); // Ϊֱͬӵ +end; + +procedure AddISO10126Padding(Stream: TMemoryStream; BlockSize: Integer); +var + R: Byte; + RandBuf: TBytes; +begin + R := Stream.Size mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + // ʹѧȫ䣬 ISO/IEC 9797-1 ׼ + // ޸ԭʹ FillChar ȫ 0 ʹܽȷ + SetLength(RandBuf, R); + RandBuf := CnRandomBytes(R); // ɰȫֽ + RandBuf[R - 1] := R; // һֽڼ¼䳤 + Stream.Position := Stream.Size; + Stream.Write(RandBuf[0], R); +end; + +procedure RemoveISO10126Padding(Stream: TMemoryStream); +begin + RemovePKCS7Padding(Stream); // Ϊֱͬӵ +end; + +function StrAddISO10126Padding(const Str: AnsiString; BlockSize: Integer): AnsiString; +var + I, L: Integer; + R: Byte; +begin + L := Length(Str); + R := L mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + SetLength(Result, L + R); + if L > 0 then + Move(Str[1], Result[1], L); + + if R > 1 then + begin + for I := 1 to R - 1 do + Result[L + I] := #0; + end; + Result[L + R] := AnsiChar(R); +end; + +function StrRemoveISO10126Padding(const Str: AnsiString): AnsiString; +begin + Result := StrRemovePKCS7Padding(Str); // Ϊֱͬӵ +end; + +procedure BytesAddISO10126Padding(var Data: TBytes; BlockSize: Integer); +var + R: Byte; + L, I: Integer; +begin + L := Length(Data); + R := L mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + SetLength(Data, L + R); + if R > 1 then + begin + for I := 0 to R - 2 do + Data[L + I] := 0; + end; + Data[L - 1 + R] := R; +end; + +procedure BytesRemoveISO10126Padding(var Data: TBytes); +begin + BytesRemovePKCS7Padding(Data); // Ϊֱͬӵ +end; + +function EncryptPemStream(KeyHash: TCnKeyHashMethod; KeyEncrypt: TCnKeyEncryptMethod; + Stream: TStream; const Password: string; out EncryptedHead: string): Boolean; +const + CRLF = #13#10; +var + ES: TMemoryStream; + Keys: array[0..31] of Byte; //  Key Ҳֻ 32 ֽ + IvStr: AnsiString; + HexIv: string; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AesIv: TCnAESBuffer; + DesKey: TCnDESKey; + Des3Key: TCn3DESKey; + DesIv: TCnDESIv; + Sm4Key: TCnSM4Key; + Sm4Iv: TCnSM4Iv; +begin + Result := False; + + // + if (KeyEncrypt = ckeNone) or (Password = '') then + Exit; + + // Iv + SetLength(IvStr, ENC_TYPE_BLOCK_SIZE[KeyEncrypt]); + CnRandomFillBytes(@(IvStr[1]), ENC_TYPE_BLOCK_SIZE[KeyEncrypt]); + HexIv := DataToHex(@(IvStr[1]), ENC_TYPE_BLOCK_SIZE[KeyEncrypt], True); // Ҫд + + EncryptedHead := ENC_HEAD_PROCTYPE + ' ' + ENC_HEAD_PROCTYPE_NUM + ',' + ENC_HEAD_ENCRYPTED + CRLF; + EncryptedHead := EncryptedHead + ENC_HEAD_DEK + ' ' + ENC_TYPE_STRS[KeyEncrypt] + + '-' + ENC_BLOCK_CBC + ',' + HexIv + CRLF; + + ES := TMemoryStream.Create; + Stream.Position := 0; + + try + if KeyHash = ckhMd5 then + begin + if not CnGetDeriveKey(AnsiString(Password), IvStr, @Keys[0], SizeOf(Keys)) then + Exit; + end + else if KeyHash = ckhSha256 then + begin + if not CnGetDeriveKey(AnsiString(Password), IvStr, @Keys[0], SizeOf(Keys), ckdSha256) then + Exit; + end + else + Exit; + + case KeyEncrypt of + ckeDES: + begin + Move(Keys[0], DesKey[0], SizeOf(TCnDESKey)); + Move(IvStr[1], DesIv[0], SizeOf(TCnDESIv)); + + DESEncryptStreamCBC(Stream, Stream.Size, DesKey, DesIv, ES); + Result := True; + end; + cke3DES: + begin + Move(Keys[0], Des3Key[0], SizeOf(TCn3DESKey)); + Move(IvStr[1], DesIv[0], SizeOf(TCn3DESIv)); + + TripleDESEncryptStreamCBC(Stream, Stream.Size, Des3Key, DesIv, ES); + Result := True; + end; + ckeAES128: + begin + Move(Keys[0], AESKey128[0], SizeOf(TCnAESKey128)); + Move(IvStr[1], AesIv[0], SizeOf(TCnAESBuffer)); + + EncryptAES128StreamCBC(Stream, Stream.Size, AESKey128, AesIv, ES); + Result := True; + end; + ckeAES192: + begin + Move(Keys[0], AESKey192[0], SizeOf(TCnAESKey192)); + Move(IvStr[1], AesIv[0], SizeOf(TCnAESBuffer)); + + EncryptAES192StreamCBC(Stream, Stream.Size, AESKey192, AesIv, ES); + Result := True; + end; + ckeAES256: + begin + Move(Keys[0], AESKey256[0], SizeOf(TCnAESKey256)); + Move(IvStr[1], AesIv[0], SizeOf(TCnAESBuffer)); + + EncryptAES256StreamCBC(Stream, Stream.Size, AESKey256, AesIv, ES); + Result := True; + end; + ckeSM4: + begin + Move(Keys[0], Sm4Key[0], SizeOf(TCnSM4Key)); + Move(IvStr[1], Sm4Iv[0], SizeOf(TCnSM4Iv)); + + SM4EncryptStreamCBC(Stream, Stream.Size, Sm4Key, Sm4Iv, ES); + Result := True; + end; + end; + finally + if ES.Size > 0 then + begin + // ES д Stream + Stream.Size := 0; + Stream.Position := 0; + ES.SaveToStream(Stream); + Stream.Position := 0; + end; + ES.Free; + end; +end; + +// ü㷨㡢ʼ⿪ Base64 Sд Stream +function DecryptPemString(const S, M1, M2, HexIv, Password: string; Stream: TMemoryStream; + KeyHash: TCnKeyHashMethod): Boolean; +var + DS: TMemoryStream; + Keys: array[0..31] of Byte; //  Key Ҳֻ 32 ֽ + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + IvStr: AnsiString; + AesIv: TCnAESBuffer; + DesKey: TCnDESKey; + Des3Key: TCn3DESKey; + DesIv: TCnDESIv; + Sm4Key: TCnSM4Key; + Sm4Iv: TCnSM4Iv; +begin + Result := False; + DS := nil; + + if (M1 = '') or (M2 = '') or (HexIv = '') or (Password = '') then + Exit; + + try + DS := TMemoryStream.Create; + if ECN_BASE64_OK <> Base64Decode(S, DS, False) then + Exit; + + DS.Position := 0; + SetLength(IvStr, HexToData(HexIv)); + if Length(IvStr) > 0 then + HexToData(HexIv, @IvStr[1]); + + // Salt Լ Hash 㷨ӽܵ Key + FillChar(Keys[0], SizeOf(Keys), 0); + if KeyHash = ckhMd5 then + begin + if not CnGetDeriveKey(AnsiString(Password), IvStr, @Keys[0], SizeOf(Keys)) then + Exit; + end + else if KeyHash = ckhSha256 then + begin + if not CnGetDeriveKey(AnsiString(Password), IvStr, @Keys[0], SizeOf(Keys), ckdSha256) then + Exit; + end + else + Exit; + + // DS ģҪ⵽ Stream + if (M1 = ENC_TYPE_AES256) and (M2 = ENC_BLOCK_CBC) then + begin + // ⿪ AES-256-CBC ܵ + Move(Keys[0], AESKey256[0], SizeOf(TCnAESKey256)); + Move(IvStr[1], AesIv[0], Min(SizeOf(TCnAESBuffer), Length(IvStr))); + + DecryptAES256StreamCBC(DS, DS.Size, AESKey256, AesIv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end + else if (M1 = ENC_TYPE_AES192) and (M2 = ENC_BLOCK_CBC) then + begin + // ⿪ AES-192-CBC ܵ + Move(Keys[0], AESKey192[0], SizeOf(TCnAESKey192)); + Move(IvStr[1], AesIv[0], Min(SizeOf(TCnAESBuffer), Length(IvStr))); + + DecryptAES192StreamCBC(DS, DS.Size, AESKey192, AesIv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end + else if (M1 = ENC_TYPE_AES128) and (M2 = ENC_BLOCK_CBC) then + begin + // ⿪ AES-128-CBC ܵģ D5 òƿ Bug ³ AV + Move(Keys[0], AESKey128[0], SizeOf(TCnAESKey128)); + Move(IvStr[1], AesIv[0], Min(SizeOf(TCnAESBuffer), Length(IvStr))); + + DecryptAES128StreamCBC(DS, DS.Size, AESKey128, AesIv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end + else if (M1 = ENC_TYPE_DES) and (M2 = ENC_BLOCK_CBC) then + begin + // ⿪ DES-CBC ܵ + Move(Keys[0], DesKey[0], SizeOf(TCnDESKey)); + Move(IvStr[1], DesIv[0], Min(SizeOf(TCnDESIv), Length(IvStr))); + + DESDecryptStreamCBC(DS, DS.Size, DesKey, DesIv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end + else if (M1 = ENC_TYPE_3DES) and (M2 = ENC_BLOCK_CBC) then + begin + // ⿪ 3DES-CBC ܵ + Move(Keys[0], Des3Key[0], SizeOf(TCn3DESKey)); + Move(IvStr[1], DesIv[0], Min(SizeOf(TCn3DESIv), Length(IvStr))); + + TripleDESDecryptStreamCBC(DS, DS.Size, Des3Key, DesIv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end + else if (M1 = ENC_TYPE_SM4) and (M2 = ENC_BLOCK_CBC) then + begin + // ⿪ SM4-CBC ܵ + Move(Keys[0], Sm4Key[0], SizeOf(TCnSM4Key)); + Move(IvStr[1], Sm4Iv[0], Min(SizeOf(TCnSM4Iv), Length(IvStr))); + + SM4DecryptStreamCBC(DS, DS.Size, Sm4Key, Sm4Iv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end + finally + DS.Free; + end; +end; + +function LoadPemStreamToMemory(Stream: TStream; const ExpectHead, ExpectTail: string; + MemoryStream: TMemoryStream; const Password: string; KeyHashMethod: TCnKeyHashMethod): Boolean; +var + I, J, HeadIndex, TailIndex: Integer; + S, L1, L2, M1, M2, M3: string; + Sl: TStringList; +begin + Result := False; + + if (Stream <> nil) and (Stream.Size > 0) and (ExpectHead <> '') and (ExpectTail <> '') then + begin + Sl := TStringList.Create; + try + Sl.LoadFromStream(Stream); + if Sl.Count > 2 then + begin + HeadIndex := -1; + for I := 0 to Sl.Count - 1 do + begin + if Trim(Sl[I]) = ExpectHead then + begin + HeadIndex := I; + Break; + end; + end; + + if HeadIndex < 0 then + Exit; + + if HeadIndex > 0 then + for I := 0 to HeadIndex - 1 do + Sl.Delete(0); + + // ҵͷˣβ + + TailIndex := -1; + for I := 0 to Sl.Count - 1 do + begin + if Trim(Sl[I]) = ExpectTail then + begin + TailIndex := I; + Break; + end; + end; + + if TailIndex > 0 then // ҵβͣɾβͺĶ + begin + if TailIndex < Sl.Count - 1 then + for I := Sl.Count - 1 downto TailIndex + 1 do + Sl.Delete(Sl.Count - 1); + end + else + Exit; + + if Sl.Count < 2 then // ûݣ˳ + Exit; + + // ͷβ֤ͨǰжǷ + L1 := Sl[1]; + if Pos(ENC_HEAD_PROCTYPE, L1) = 1 then // Ǽܵ + begin + Delete(L1, 1, Length(ENC_HEAD_PROCTYPE)); + I := Pos(',', L1); + if I <= 1 then + Exit; + + if Trim(Copy(L1, 1, I - 1)) <> ENC_HEAD_PROCTYPE_NUM then + Exit; + + if Trim(Copy(L1, I + 1, MaxInt)) <> ENC_HEAD_ENCRYPTED then + Exit; + + // ProcType: 4,ENCRYPTED жͨ + + L2 := Sl[2]; + if Pos(ENC_HEAD_DEK, L2) <> 1 then + Exit; + + Delete(L2, 1, Length(ENC_HEAD_DEK)); + I := Pos(',', L2); + if I <= 1 then + Exit; + + M1 := Trim(Copy(L2, 1, I - 1)); // õ AES256-CBC + M3 := UpperCase(Trim(Copy(L2, I + 1, MaxInt))); // õʱʹõijʼ + I := Pos('-', M1); + if I <= 1 then + Exit; + J := Pos('-', Copy(M1, I + 1, MaxInt)); + if J > 0 then + I := I + J; // AES-256-CBC + + M2 := UpperCase(Trim(Copy(M1, I + 1, MaxInt))); // õģʽ ECB CBC + M1 := UpperCase(Trim(Copy(M1, 1, I - 1))); // õ㷨 DES AES + + // ͷβȫɾ + Sl.Delete(Sl.Count - 1); + Sl.Delete(0); + Sl.Delete(0); + Sl.Delete(0); + + S := ''; + for I := 0 to Sl.Count - 1 do + S := S + Sl[I]; + + S := Trim(S); + if not Base64IsStrictText(S) then + Exit; + + Result := DecryptPemString(S, M1, M2, M3, Password, MemoryStream, KeyHashMethod); + end + else // δܵģƴճ Base64 + begin + Sl.Delete(Sl.Count - 1); + Sl.Delete(0); + S := ''; + for I := 0 to Sl.Count - 1 do + S := S + Sl[I]; + + S := Trim(S); + + // To De Base64 S + MemoryStream.Clear; + if not Base64IsStrictText(S) then + Exit; + + Result := (ECN_BASE64_OK = Base64Decode(S, MemoryStream, False)); + end; + end; + finally + Sl.Free; + end; + end; +end; + +function LoadPemFileToMemory(const FileName, ExpectHead, ExpectTail: string; + MemoryStream: TMemoryStream; const Password: string; KeyHashMethod: TCnKeyHashMethod): Boolean; +var + Stream: TStream; +begin + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + Result := LoadPemStreamToMemory(Stream, ExpectHead, ExpectTail, MemoryStream, Password, KeyHashMethod); + finally + Stream.Free; + end; +end; + +procedure SplitStringToList(const S: string; List: TCnAnsiStrings); +const + LINE_WIDTH = 64; +var + C, R: AnsiString; +begin + if List = nil then + Exit; + + List.Clear; + if S <> '' then + begin + R := AnsiString(S); + while R <> '' do + begin + C := Copy(R, 1, LINE_WIDTH); + Delete(R, 1, LINE_WIDTH); + List.Add(C); + end; + end; +end; + +function SaveMemoryToPemFile(const FileName, Head, Tail: string; + MemoryStream: TMemoryStream; KeyEncryptMethod: TCnKeyEncryptMethod; + KeyHashMethod: TCnKeyHashMethod; const Password: string; Append: Boolean): Boolean; +var + S, EH: string; + List, Sl: TCnAnsiStringList; +begin + Result := False; + if (MemoryStream <> nil) and (MemoryStream.Size <> 0) then + begin + MemoryStream.Position := 0; + + if (KeyEncryptMethod <> ckeNone) and (Password <> '') then + begin + // MemoryStream + AddPKCS7Padding(MemoryStream, ENC_TYPE_BLOCK_SIZE[KeyEncryptMethod]); + + // ټ + if not EncryptPemStream(KeyHashMethod, KeyEncryptMethod, MemoryStream, Password, EH) then + Exit; + end; + + if ECN_BASE64_OK = Base64Encode(MemoryStream, S) then + begin + List := TCnAnsiStringList.Create; + try + SplitStringToList(S, List); + + List.Insert(0, AnsiString(Head)); // ͨͷ + if EH <> '' then // ͷ + List.Insert(1, AnsiString(EH)); + List.Add(AnsiString(Tail)); // ͨβ + + if Append and FileExists(FileName) then + begin + Sl := TCnAnsiStringList.Create; + try + Sl.LoadFromFile(AnsiString(FileName)); + Sl.AddStrings(List); + Sl.SaveToFile(AnsiString(FileName)); + finally + Sl.Free; + end; + end + else + List.SaveToFile(AnsiString(FileName)); + + Result := True; + finally + List.Free; + end; + end; + end; +end; + +function SaveMemoryToPemStream(Stream: TStream; const Head, Tail: string; + MemoryStream: TMemoryStream; KeyEncryptMethod: TCnKeyEncryptMethod; + KeyHashMethod: TCnKeyHashMethod; const Password: string; Append: Boolean): Boolean; +var + S, EH: string; + List: TCnAnsiStringList; +begin + Result := False; + if (MemoryStream <> nil) and (MemoryStream.Size <> 0) then + begin + MemoryStream.Position := 0; + + if (KeyEncryptMethod <> ckeNone) and (Password <> '') then + begin + // MemoryStream + AddPKCS7Padding(MemoryStream, ENC_TYPE_BLOCK_SIZE[KeyEncryptMethod]); + + // ټ + if not EncryptPemStream(KeyHashMethod, KeyEncryptMethod, MemoryStream, Password, EH) then + Exit; + end; + + if ECN_BASE64_OK = Base64Encode(MemoryStream, S) then + begin + List := TCnAnsiStringList.Create; + try + SplitStringToList(S, List); + + List.Insert(0, AnsiString(Head)); // ͨͷ + if EH <> '' then // ͷ + List.Insert(1, AnsiString(EH)); + List.Add(AnsiString(Tail)); // ͨβ + + if not Append then + Stream.Size := 0; + + List.SaveToStream(Stream); + + Result := True; + finally + List.Free; + end; + end; + end; +end; + +end. diff --git a/CnPack/Crypto/CnRandom.pas b/CnPack/Crypto/CnRandom.pas index de6a2c3..495da09 100644 --- a/CnPack/Crypto/CnRandom.pas +++ b/CnPack/Crypto/CnRandom.pas @@ -1,415 +1,574 @@ -{******************************************************************************} -{ CnPack For Delphi/C++Builder } -{ йԼĿԴ } -{ (C)Copyright 2001-2025 CnPack } -{ ------------------------------------ } -{ } -{ ǿԴ CnPack ķЭ } -{ ĺ·һ } -{ } -{ һĿϣãûκεû } -{ ʺضĿĶĵϸ CnPack Э顣 } -{ } -{ ӦѾͿһյһ CnPack Эĸ } -{ ûУɷǵվ } -{ } -{ վַhttps://www.cnpack.org } -{ ʼmaster@cnpack.org } -{ } -{******************************************************************************} - -unit CnRandom; -{* |
-================================================================================
-* ƣ
-* Ԫƣ䵥Ԫ
-* ԪߣCnPack  (master@cnpack.org)
-*     עԪװ Windows ƽ̨ MacOS/Linux ƽ̨µİȫ
-*           ṩȫ书ܡ
-* ƽ̨Win7 + Delphi 5.0
-* ݲԣWin32/Win64/MacOS/Linux + Unicode/NonUnicode
-*   õԪ豾ػ
-* ޸ļ¼2023.01.15 V1.3
-*                Windows ȫ urandom ֧ Linux
-*           2023.01.08 V1.2
-*                Win64  API 
-*           2022.08.22 V1.1
-*               ʹòϵͳṩ
-*           2020.03.27 V1.0
-*               Ԫ CnPrime ж
-================================================================================
-|
} - -interface - -{$I CnPack.inc} - -uses - SysUtils {$IFDEF MSWINDOWS}, Windows {$ENDIF}, Classes, CnNative; - -type - ECnRandomAPIError = class(Exception); - -function RandomUInt64: TUInt64; -{* UInt64 Χڵڲ֧ UInt64 ƽ̨ Int64 档 - - - ޣ - - ֵTUInt64 - UInt64 Χڵ -} - -function RandomUInt64LessThan(HighValue: TUInt64): TUInt64; -{* شڵ 0 Сָ UInt64 ֵ - - - HighValue: TUInt64 - ָ UInt64 - - ֵTUInt64 - شڵ 0 Сָ HighValue -} - -function RandomInt64: Int64; -{* شڵ 0 С Int64 ޵ - - - ޣ - - ֵInt64 - شڵ 0 С Int64 ޵ -} - -function RandomInt64LessThan(HighValue: Int64): Int64; -{* شڵ 0 Сָ Int64 ֵб֤ HighValue 0 - - - HighValue: Int64 - ָ Int64 - - ֵInt64 - شڵ 0 Сָ HighValue -} - -function RandomUInt32: Cardinal; -{* UInt32 Χڵ - - - ޣ - - ֵCardinal - UInt32 Χڵ -} - -function RandomUInt32LessThan(HighValue: Cardinal): Cardinal; -{* شڵ 0 Сָ UInt32 ֵ - - - HighValue: Cardinal - ָ UInt32 - - ֵCardinal - شڵ 0 Сָ HighValue -} - -function RandomInt32: Integer; -{* شڵ 0 С Int32 ޵ - - - ޣ - - ֵInteger - شڵ 0 С Int32 ޵ -} - -function RandomInt32LessThan(HighValue: Integer): Integer; -{* شڵ 0 Сָ Int32 б֤ HighValue 0 - - - HighValue: Integer - ָ Int32 - - ֵInteger - شڵ 0 Сָ HighValue -} - -function CnKnuthShuffle(ArrayBase: Pointer; ElementByteSize: Integer; - ElementCount: Integer): Boolean; -{* ߵϴ㷨 ArrayBase ָԪسߴΪ ElementSize ElementCount Ԫؾϴơ - - - ArrayBase: Pointer - ϴƵڴַ - ElementByteSize: Integer - ϴƵÿڴԪҲÿһƵֽڴС - ElementCount: Integer - ڴԪҲƵ - - ֵBoolean - ϴǷɹ -} - -function CnRandomFillBytes(Buf: PAnsiChar; BufByteLen: Integer): Boolean; -{* ʹ Windows API /dev/random 豸ʵ䣬ڲγʼ沢ͷš - - - Buf: PAnsiChar - ڴַ - BufByteLen: Integer - ڴֽڳ - - ֵBoolean - Ƿɹ -} - -function CnRandomFillBytes2(Buf: PAnsiChar; BufByteLen: Integer): Boolean; -{* ʹ Windows API /dev/urandom 豸ʵ䣬 - Windows ʹԤȳʼõ١ - - - Buf: PAnsiChar - ڴַ - BufByteLen: Integer - ڴֽڳ - - ֵBoolean - Ƿɹ -} - -implementation - -{$IFDEF MSWINDOWS} - -const - ADVAPI32 = 'advapi32.dll'; - - CRYPT_VERIFYCONTEXT = $F0000000; - CRYPT_NEWKEYSET = $8; - CRYPT_DELETEKEYSET = $10; - - PROV_RSA_FULL = 1; - NTE_BAD_KEYSET = $80090016; - -function CryptAcquireContext(phProv: PHandle; pszContainer: PAnsiChar; - pszProvider: PAnsiChar; dwProvType: LongWord; dwFlags: LongWord): BOOL; - stdcall; external ADVAPI32 name 'CryptAcquireContextA'; - -function CryptReleaseContext(hProv: THandle; dwFlags: LongWord): BOOL; - stdcall; external ADVAPI32 name 'CryptReleaseContext'; - -function CryptGenRandom(hProv: THandle; dwLen: LongWord; pbBuffer: PAnsiChar): BOOL; - stdcall; external ADVAPI32 name 'CryptGenRandom'; - -var - FHProv: THandle = 0; - -{$ELSE} - -const - DEV_FILE = '/dev/urandom'; - -{$ENDIF} - -function CnRandomFillBytes(Buf: PAnsiChar; BufByteLen: Integer): Boolean; -var -{$IFDEF MSWINDOWS} - HProv: THandle; - Res: DWORD; - B: Boolean; -{$ELSE} - F: TFileStream; -{$ENDIF} -begin - Result := False; -{$IFDEF MSWINDOWS} - // ʹ Windows API ʵ - HProv := 0; - B := CryptAcquireContext(@HProv, nil, nil, PROV_RSA_FULL, 0); - if not B then - B := CryptAcquireContext(@HProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); - - if not B then - begin - Res := GetLastError; - if Res = NTE_BAD_KEYSET then // KeyContainer ڣ½ķʽ - begin - if not CryptAcquireContext(@HProv, nil, nil, PROV_RSA_FULL, CRYPT_NEWKEYSET) then - raise ECnRandomAPIError.CreateFmt('Error CryptAcquireContext NewKeySet $%8.8x', [GetLastError]); - end - else - raise ECnRandomAPIError.CreateFmt('Error CryptAcquireContext $%8.8x', [Res]); - end; - - if HProv <> 0 then - begin - try - Result := CryptGenRandom(HProv, BufByteLen, Buf); - if not Result then - raise ECnRandomAPIError.CreateFmt('Error CryptGenRandom $%8.8x', [GetLastError]); - finally - CryptReleaseContext(HProv, 0); - end; - end; -{$ELSE} - // MacOS/Linux µʵ֣öȡ /dev/urandom ݵķʽ - F := nil; - try - F := TFileStream.Create(DEV_FILE, fmOpenRead); - Result := F.Read(Buf^, BufByteLen) = BufByteLen; - finally - F.Free; - end; -{$ENDIF} -end; - -function CnRandomFillBytes2(Buf: PAnsiChar; BufByteLen: Integer): Boolean; -{$IFNDEF MSWINDOWS} -var - F: TFileStream; -{$ENDIF} -begin -{$IFDEF MSWINDOWS} - Result := CryptGenRandom(FHProv, BufByteLen, Buf); -{$ELSE} - // MacOS/Linux µʵ֣öȡ /dev/urandom ݵķʽ - F := nil; - try - F := TFileStream.Create(DEV_FILE, fmOpenRead); - Result := F.Read(Buf^, BufByteLen) = BufByteLen; - finally - F.Free; - end; -{$ENDIF} -end; - -function RandomUInt64: TUInt64; -var - HL: array[0..1] of Cardinal; -begin - // ϵͳ - if not CnRandomFillBytes2(@HL[0], SizeOf(TUInt64)) then - begin - // ֱ Random * High(TUInt64) ܻᾫȲ Lo ȫ FF˷ֿ - Randomize; - HL[0] := Trunc(Random * High(Cardinal) - 1) + 1; - HL[1] := Trunc(Random * High(Cardinal) - 1) + 1; - end; - - Result := (TUInt64(HL[0]) shl 32) + HL[1]; -end; - -function RandomUInt64LessThan(HighValue: TUInt64): TUInt64; -begin - Result := UInt64Mod(RandomUInt64, HighValue); -end; - -function RandomInt64LessThan(HighValue: Int64): Int64; -var - HL: array[0..1] of Cardinal; -begin - // ϵͳ - if not CnRandomFillBytes2(@HL[0], SizeOf(Int64)) then - begin - // ֱ Random * High(Int64) ܻᾫȲ Lo ȫ FF˷ֿ - Randomize; - HL[0] := Trunc(Random * High(Integer) - 1) + 1; // Int64 λ 1⸺ - HL[1] := Trunc(Random * High(Cardinal) - 1) + 1; - end - else - HL[0] := HL[0] mod (Cardinal(High(Integer)) + 1); // Int64 λ 1⸺ - - Result := (Int64(HL[0]) shl 32) + HL[1]; - Result := Result mod HighValue; // δ HighValue Сڵ 0 -end; - -function RandomInt64: Int64; -begin - Result := RandomInt64LessThan(High(Int64)); -end; - -function RandomUInt32: Cardinal; -var - D: Cardinal; -begin - // ϵͳ - if not CnRandomFillBytes2(@D, SizeOf(Cardinal)) then - begin - Randomize; - D := Trunc(Random * High(Cardinal) - 1) + 1; - end; - - Result := D; -end; - -function RandomUInt32LessThan(HighValue: Cardinal): Cardinal; -begin - Result := RandomUInt32 mod HighValue; -end; - -function RandomInt32: Integer; -begin - Result := RandomInt32LessThan(High(Integer)); -end; - -function RandomInt32LessThan(HighValue: Integer): Integer; -var - D: Cardinal; -begin - // ϵͳ - if not CnRandomFillBytes2(@D, SizeOf(Cardinal)) then - begin - Randomize; - D := Trunc(Random * High(Integer) - 1) + 1; - end - else - D := D mod (Cardinal(High(Integer)) + 1); - - Result := Integer(Int64(D) mod Int64(HighValue)); // δ HighValue Сڵ 0 -end; - -function CnKnuthShuffle(ArrayBase: Pointer; ElementByteSize: Integer; - ElementCount: Integer): Boolean; -var - I, R: Integer; - B1, B2: Pointer; -begin - Result := False; - if (ArrayBase = nil) or (ElementByteSize <= 0) or (ElementCount < 0) then // Ȳ - Exit; - - Result := True; - if ElementCount <= 1 then // ûԪػֻһԪʱϴ - Exit; - - for I := ElementCount - 1 downto 0 do - begin - R := RandomInt32LessThan(I + 1); // 0 I ڵҪ 1 - B1 := Pointer(TCnNativeUInt(ArrayBase) + TCnNativeUInt(I * ElementByteSize)); - B2 := Pointer(TCnNativeUInt(ArrayBase) + TCnNativeUInt(R * ElementByteSize)); - MemorySwap(B1, B2, ElementByteSize); - end; - Result := True; -end; - -{$IFDEF MSWINDOWS} - -procedure StartRandom; -var - Res: DWORD; - B: Boolean; -begin - FHProv := 0; - B := CryptAcquireContext(@FHProv, nil, nil, PROV_RSA_FULL, 0); - if not B then - B := CryptAcquireContext(@FHProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); - - if not B then - begin - Res := GetLastError; - if Res = NTE_BAD_KEYSET then // KeyContainer ڣ½ķʽ - begin - if not CryptAcquireContext(@FHProv, nil, nil, PROV_RSA_FULL, CRYPT_NEWKEYSET) then - raise ECnRandomAPIError.CreateFmt('Error CryptAcquireContext NewKeySet $%8.8x', [GetLastError]); - end - else - raise ECnRandomAPIError.CreateFmt('Error CryptAcquireContext $%8.8x', [Res]); - end; -end; - -procedure StopRandom; -begin - if FHProv <> 0 then - begin - CryptReleaseContext(FHProv, 0); - FHProv := 0; - end; -end; - -initialization - StartRandom; - -finalization - StopRandom; - -{$ENDIF} - -end. +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnRandom; +{* |
+================================================================================
+* ƣ
+* Ԫƣ䵥Ԫ
+* ԪߣCnPack  (master@cnpack.org)
+*     עԪװ Windows ƽ̨ MacOS/Linux ƽ̨µİȫ
+*           ṩȫ书ܡ
+* ƽ̨Win7 + Delphi 5.0
+* ݲԣWin32/Win64/MacOS/Linux + Unicode/NonUnicode
+*   õԪ豾ػ
+* ޸ļ¼2026.03.23 V1.5
+*               һײѭ⣬
+*               Windows ִȽLinux Mac ҲͬŻֽ
+*           2026.01.29 V1.4
+*               ܵģƫ²ֺ
+*           2023.01.15 V1.3
+*                Windows ȫ urandom ֧ Linux
+*           2023.01.08 V1.2
+*                Win64  API 
+*           2022.08.22 V1.1
+*               ʹòϵͳṩ
+*           2020.03.27 V1.0
+*               Ԫ CnPrime ж
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + SysUtils {$IFDEF MSWINDOWS}, Windows {$ENDIF}, Classes, CnNative; + +type + ECnRandomAPIError = class(Exception); + {* 쳣} + +function RandomUInt64: TUInt64; +{* UInt64 Χڵڲ֧ UInt64 ƽ̨ Int64 档 + + + ޣ + + ֵTUInt64 - UInt64 Χڵ +} + +function RandomUInt64LessThan(HighValue: TUInt64): TUInt64; +{* شڵ 0 Сָ UInt64 ֵ + + + HighValue: TUInt64 - ָ UInt64 + + ֵTUInt64 - شڵ 0 Сָ HighValue +} + +function RandomInt64: Int64; +{* شڵ 0 С Int64 ޵ + + + ޣ + + ֵInt64 - شڵ 0 С Int64 ޵ +} + +function RandomInt64LessThan(HighValue: Int64): Int64; +{* شڵ 0 Сָ Int64 ֵб֤ HighValue 0 + + + HighValue: Int64 - ָ Int64 + + ֵInt64 - شڵ 0 Сָ HighValue +} + +function RandomUInt32: Cardinal; +{* UInt32 Χڵ + + + ޣ + + ֵCardinal - UInt32 Χڵ +} + +function RandomUInt32LessThan(HighValue: Cardinal): Cardinal; +{* شڵ 0 Сָ UInt32 ֵ + + + HighValue: Cardinal - ָ UInt32 + + ֵCardinal - شڵ 0 Сָ HighValue +} + +function RandomInt32: Integer; +{* شڵ 0 С Int32 ޵ + + + ޣ + + ֵInteger - شڵ 0 С Int32 ޵ +} + +function RandomInt32LessThan(HighValue: Integer): Integer; +{* شڵ 0 Сָ Int32 б֤ HighValue 0 + + + HighValue: Integer - ָ Int32 + + ֵInteger - شڵ 0 Сָ HighValue +} + +function CnKnuthShuffle(ArrayBase: Pointer; ElementByteSize: Integer; + ElementCount: Integer): Boolean; +{* ߵϴ㷨 ArrayBase ָԪسߴΪ ElementSize ElementCount Ԫؾϴơ + + + ArrayBase: Pointer - ϴƵڴַ + ElementByteSize: Integer - ϴƵÿڴԪҲÿһƵֽڴС + ElementCount: Integer - ڴԪҲƵ + + ֵBoolean - ϴǷɹ +} + +function CnRandomFillBytes(Buf: PAnsiChar; BufByteLen: Integer): Boolean; +{* ʹ Windows API /dev/random 豸ʵ䣬ڲγʼ沢ͷš + + + Buf: PAnsiChar - ڴַ + BufByteLen: Integer - ڴֽڳ + + ֵBoolean - Ƿɹ +} + +function CnRandomFillBytes2(Buf: PAnsiChar; BufByteLen: Integer): Boolean; +{* ʹ Windows API /dev/urandom 豸ʵ䣬 + Windows ʹԤȳʼõ١ + + + Buf: PAnsiChar - ڴַ + BufByteLen: Integer - ڴֽڳ + + ֵBoolean - Ƿɹ +} + +function CnRandomBytes(ByteLen: Integer): TBytes; +{* ʹ Windows API /dev/random 豸䲢ָȵֽ顣 + + + ByteLen: Integer - ɵֽֽڳ + + ֵTBytes - ֽ +} + +function CnRandomFloat: Extended; +{* ʹѧȫ [0, 1) ΧڵĸΪģ Delphi Random + ڲ 4 ֽ޷ $1000000002^32õȷϸС 1.0 + + + + + ֵExtended - 0 <= Result < 1 +} + +implementation + +resourcestring + SCnErrorNoSecureRandom = 'NO Secure Random Generator!'; + +{$IFDEF MSWINDOWS} + +const + ADVAPI32 = 'advapi32.dll'; + + CRYPT_VERIFYCONTEXT = $F0000000; + CRYPT_NEWKEYSET = $8; + CRYPT_DELETEKEYSET = $10; + + PROV_RSA_FULL = 1; + NTE_BAD_KEYSET = $80090016; + + BCRYPT_USE_SYSTEM_PREFERRED_RNG = $00000002; + bcryptdll = 'bcrypt.dll'; + +function CryptAcquireContext(phProv: PHandle; pszContainer: PAnsiChar; + pszProvider: PAnsiChar; dwProvType: LongWord; dwFlags: LongWord): BOOL; + stdcall; external ADVAPI32 name 'CryptAcquireContextA'; + +function CryptReleaseContext(hProv: THandle; dwFlags: LongWord): BOOL; + stdcall; external ADVAPI32 name 'CryptReleaseContext'; + +function CryptGenRandom(hProv: THandle; dwLen: LongWord; pbBuffer: PAnsiChar): BOOL; + stdcall; external ADVAPI32 name 'CryptGenRandom'; + +var + FHProv: THandle = 0; + FBCryptHandle: THandle = 0; + FBCryptGenRandom: function(hAlgorithm: THandle; pbBuffer: Pointer; cbBuffer: ULONG; dwFlags: ULONG): LongInt; stdcall = nil; + FBCryptInitAttempted: Boolean = False; + +{$ELSE} + +const + DEV_FILE = '/dev/urandom'; + +{$IFDEF LINUX} +const + libc = 'libc.so.6'; +function getrandom(buf: Pointer; buflen: NativeUInt; flags: Cardinal): Integer; cdecl; external libc name 'getrandom'; +{$ENDIF} + +{$IFDEF MACOS} +function CCRandomGenerateBytes(bytes: Pointer; count: NativeUInt): Integer; cdecl; external '/usr/lib/system/libcommonCrypto.dylib' name 'CCRandomGenerateBytes'; +{$ENDIF} + +{$ENDIF} + +function CnRandomFillBytes(Buf: PAnsiChar; BufByteLen: Integer): Boolean; +var +{$IFDEF MSWINDOWS} + HProv: THandle; + Res: DWORD; + B: Boolean; +{$ELSE} + F: TFileStream; +{$IFDEF LINUX} + R: Integer; +{$ENDIF} +{$ENDIF} +begin + Result := False; +{$IFDEF MSWINDOWS} + // ʹ Windows API ʵ + if not FBCryptInitAttempted then + begin + FBCryptHandle := LoadLibrary(bcryptdll); + if FBCryptHandle <> 0 then + @FBCryptGenRandom := GetProcAddress(FBCryptHandle, 'BCryptGenRandom'); + FBCryptInitAttempted := True; + end; + + if Assigned(FBCryptGenRandom) then + begin + Result := FBCryptGenRandom(0, Buf, BufByteLen, BCRYPT_USE_SYSTEM_PREFERRED_RNG) = 0; + if Result then + Exit; + end; + + // + HProv := 0; + B := CryptAcquireContext(@HProv, nil, nil, PROV_RSA_FULL, 0); + if not B then + B := CryptAcquireContext(@HProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + + if not B then + begin + Res := GetLastError; + if Res = NTE_BAD_KEYSET then // KeyContainer ڣ½ķʽ + begin + if not CryptAcquireContext(@HProv, nil, nil, PROV_RSA_FULL, CRYPT_NEWKEYSET) then + raise ECnRandomAPIError.CreateFmt('Error CryptAcquireContext NewKeySet $%8.8x', [GetLastError]); + end + else + raise ECnRandomAPIError.CreateFmt('Error CryptAcquireContext $%8.8x', [Res]); + end; + + if HProv <> 0 then + begin + try + Result := CryptGenRandom(HProv, BufByteLen, Buf); + if not Result then + raise ECnRandomAPIError.CreateFmt('Error CryptGenRandom $%8.8x', [GetLastError]); + finally + CryptReleaseContext(HProv, 0); + end; + end; +{$ELSE} +{$IFDEF MACOS} + Result := CCRandomGenerateBytes(Buf, BufByteLen) = 0; + if Result then + Exit; +{$ENDIF} +{$IFDEF LINUX} + try + R := getrandom(Buf, BufByteLen, 0); + Result := (R = BufByteLen); + if Result then + Exit; + except + // ignore missing symbol or error + end; +{$ENDIF} + + // MacOS/Linux ½ʵ֣öȡ /dev/urandom ݵķʽ + F := nil; + try + F := TFileStream.Create(DEV_FILE, fmOpenRead); + Result := F.Read(Buf^, BufByteLen) = BufByteLen; + finally + F.Free; + end; +{$ENDIF} +end; + +function CnRandomFillBytes2(Buf: PAnsiChar; BufByteLen: Integer): Boolean; +{$IFNDEF MSWINDOWS} +var + F: TFileStream; +{$IFDEF LINUX} + R: Integer; +{$ENDIF} +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + if not FBCryptInitAttempted then + begin + FBCryptHandle := LoadLibrary(bcryptdll); + if FBCryptHandle <> 0 then + @FBCryptGenRandom := GetProcAddress(FBCryptHandle, 'BCryptGenRandom'); + FBCryptInitAttempted := True; + end; + + if Assigned(FBCryptGenRandom) then + begin + Result := FBCryptGenRandom(0, Buf, BufByteLen, BCRYPT_USE_SYSTEM_PREFERRED_RNG) = 0; + if Result then + Exit; + end; + + Result := CryptGenRandom(FHProv, BufByteLen, Buf); +{$ELSE} +{$IFDEF MACOS} + Result := CCRandomGenerateBytes(Buf, BufByteLen) = 0; + if Result then + Exit; +{$ENDIF} +{$IFDEF LINUX} + try + R := getrandom(Buf, BufByteLen, 0); + Result := (R = BufByteLen); + if Result then + Exit; + except + // ignore missing symbol or error + end; +{$ENDIF} + + // MacOS/Linux ½ʵ֣öȡ /dev/urandom ݵķʽ + F := nil; + try + F := TFileStream.Create(DEV_FILE, fmOpenRead); + Result := F.Read(Buf^, BufByteLen) = BufByteLen; + finally + F.Free; + end; +{$ENDIF} +end; + +function CnRandomBytes(ByteLen: Integer): TBytes; +begin + if ByteLen > 0 then + begin + SetLength(Result, ByteLen); + CnRandomFillBytes2(PAnsiChar(@Result[0]), ByteLen); + end; +end; + +function CnRandomFloat: Extended; +var + D: Cardinal; +begin + if not CnRandomFillBytes2(PAnsiChar(@D), SizeOf(Cardinal)) then + raise ECnRandomAPIError.Create(SCnErrorNoSecureRandom); + + // 2^32$100000000 $FFFFFFFFȷϸС 1.0 + // D = $FFFFFFFF ʱResult = $FFFFFFFF / $100000000 0.99999999976716... + Result := D; + Result := Result / $100000000; +end; + +function RandomUInt64: TUInt64; +var + HL: array[0..1] of Cardinal; +begin + // ϵͳòȫ + if not CnRandomFillBytes2(PAnsiChar(@HL[0]), SizeOf(TUInt64)) then + raise ECnRandomAPIError.Create(SCnErrorNoSecureRandom); + + Result := (TUInt64(HL[0]) shl 32) + HL[1]; +end; + +function RandomUInt64LessThan(HighValue: TUInt64): TUInt64; +var + Threshold, R: TUInt64; + RetryCount: Integer; +begin + if HighValue = 0 then + begin + Result := 0; + Exit; + end; + + // Discard numbers less than remainder of 2^64 / HighValue to avoid modulo bias + Threshold := (UInt64Mod(High(TUInt64), HighValue) + 1); + if Threshold = HighValue then + Threshold := 0; + + RetryCount := 0; + repeat + R := RandomUInt64; + Inc(RetryCount); + if RetryCount > 100 then + raise ECnRandomAPIError.Create(SCnErrorNoSecureRandom); // 'RNG stuck in rejection loop. Hardware/OS RNG failure.' + until R >= Threshold; + + Result := UInt64Mod(R, HighValue); +end; + +function RandomInt64LessThan(HighValue: Int64): Int64; +begin + if HighValue <= 0 then + Result := 0 + else + Result := Int64(RandomUInt64LessThan(TUInt64(HighValue))); +end; + +function RandomInt64: Int64; +begin + Result := RandomInt64LessThan(High(Int64)); +end; + +function RandomUInt32: Cardinal; +var + D: Cardinal; +begin + // ϵͳòȫ + if not CnRandomFillBytes2(PAnsiChar(@D), SizeOf(Cardinal)) then + raise ECnRandomAPIError.Create(SCnErrorNoSecureRandom); + + Result := D; +end; + +function RandomUInt32LessThan(HighValue: Cardinal): Cardinal; +var + Threshold, R: Cardinal; + RetryCount: Integer; +begin + if HighValue = 0 then + begin + Result := 0; + Exit; + end; + + // Discard numbers less than remainder of 2^32 / HighValue to avoid modulo bias + Threshold := (High(Cardinal) mod HighValue + 1); + if Threshold = HighValue then + Threshold := 0; + + RetryCount := 0; + repeat + R := RandomUInt32; + Inc(RetryCount); + if RetryCount > 100 then + raise ECnRandomAPIError.Create(SCnErrorNoSecureRandom); + until R >= Threshold; + + Result := R mod HighValue; +end; + +function RandomInt32: Integer; +begin + Result := RandomInt32LessThan(High(Integer)); +end; + +function RandomInt32LessThan(HighValue: Integer): Integer; +begin + if HighValue <= 0 then + Result := 0 + else + Result := Integer(RandomUInt32LessThan(Cardinal(HighValue))); +end; + +function CnKnuthShuffle(ArrayBase: Pointer; ElementByteSize: Integer; + ElementCount: Integer): Boolean; +var + I, R: Integer; + B1, B2: Pointer; +begin + Result := False; + if (ArrayBase = nil) or (ElementByteSize <= 0) or (ElementCount < 0) then // Ȳ + Exit; + + Result := True; + if ElementCount <= 1 then // ûԪػֻһԪʱϴ + Exit; + + for I := ElementCount - 1 downto 0 do + begin + R := RandomInt32LessThan(I + 1); // 0 I ڵҪ 1 + B1 := Pointer(TCnNativeUInt(ArrayBase) + TCnNativeUInt(I * ElementByteSize)); + B2 := Pointer(TCnNativeUInt(ArrayBase) + TCnNativeUInt(R * ElementByteSize)); + MemorySwap(B1, B2, ElementByteSize); + end; + Result := True; +end; + +{$IFDEF MSWINDOWS} + +procedure StartRandom; +var + Res: DWORD; + B: Boolean; +begin + FHProv := 0; + B := CryptAcquireContext(@FHProv, nil, nil, PROV_RSA_FULL, 0); + if not B then + B := CryptAcquireContext(@FHProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + + if not B then + begin + Res := GetLastError; + if Res = NTE_BAD_KEYSET then // KeyContainer ڣ½ķʽ + begin + if not CryptAcquireContext(@FHProv, nil, nil, PROV_RSA_FULL, CRYPT_NEWKEYSET) then + raise ECnRandomAPIError.CreateFmt('Error CryptAcquireContext NewKeySet $%8.8x', [GetLastError]); + end + else + raise ECnRandomAPIError.CreateFmt('Error CryptAcquireContext $%8.8x', [Res]); + end; +end; + +procedure StopRandom; +begin + if FHProv <> 0 then + begin + CryptReleaseContext(FHProv, 0); + FHProv := 0; + end; + + if FBCryptHandle <> 0 then + begin + FreeLibrary(FBCryptHandle); + FBCryptHandle := 0; + @FBCryptGenRandom := nil; + end; +end; + +initialization + StartRandom; + +finalization + StopRandom; + +{$ENDIF} + +end. diff --git a/CnPack/Crypto/CnSHA1.pas b/CnPack/Crypto/CnSHA1.pas index 4daf51e..d93d428 100644 --- a/CnPack/Crypto/CnSHA1.pas +++ b/CnPack/Crypto/CnSHA1.pas @@ -1,737 +1,757 @@ -{******************************************************************************} -{ CnPack For Delphi/C++Builder } -{ йԼĿԴ } -{ (C)Copyright 2001-2025 CnPack } -{ ------------------------------------ } -{ } -{ ǿԴ CnPack ķЭ } -{ ĺ·һ } -{ } -{ һĿϣãûκεû } -{ ʺضĿĶĵϸ CnPack Э顣 } -{ } -{ ӦѾͿһյһ CnPack Эĸ } -{ ûУɷǵվ } -{ } -{ վַhttps://www.cnpack.org } -{ ʼmaster@cnpack.org } -{ } -{******************************************************************************} - -unit CnSHA1; -{* |
-================================================================================
-* ƣ
-* ԪƣSHA1 Ӵ㷨ʵֵԪ
-* ԪߣCnPack  (master@cnpack.org)
-*           /ֲ䲿ֹܡ
-*     עԪʵ SHA1 Ӵ㷨Ӧ HMAC 㷨
-* ƽ̨PWin2000Pro + Delphi 5.0
-* ݲԣPWin9X/2000/XP + Delphi 5/6
-*   õԪеַϱػʽ
-* ޸ļ¼2022.04.26 V1.5
-*               ޸ LongWord  Integer ַת֧ MacOS64
-*           2019.12.12 V1.4
-*               ֧ TBytes
-*           2019.04.15 V1.3
-*               ֧ Win32/Win64/MacOS32
-*           2015.08.14 V1.2
-*               л Pascal ֿ֧ƽ̨
-*           2014.10.22 V1.1
-*                HMAC 
-*           2010.07.14 V1.0
-*               Ԫ
-================================================================================
-|
} - -interface - -{$I CnPack.inc} - -uses - SysUtils, Classes {$IFDEF MSWINDOWS}, Windows {$ENDIF}, CnNative, CnConsts; - -type - PCnSHA1Digest = ^TCnSHA1Digest; - TCnSHA1Digest = array[0..19] of Byte; - {* SHA1 Ӵս20 ֽ} - - TCnSHA1Context = record - {* SHA1 Ľṹ} - Hash: array[0..4] of Cardinal; - Hi, Lo: Cardinal; - Buffer: array[0..63] of Byte; - Index: Integer; - Ipad: array[0..63] of Byte; {!< HMAC: inner padding } - Opad: array[0..63] of Byte; {!< HMAC: outer padding } - end; - - TCnSHA1CalcProgressFunc = procedure (ATotal, AProgress: Int64; - var Cancel: Boolean) of object; - {* SHA1 ӴսȻص¼} - -function SHA1(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA1Digest; -{* ݿ SHA1 㡣 - - - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵTCnSHA1Digest - ص SHA1 Ӵֵ -} - -function SHA1Buffer(const Buffer; Count: Cardinal): TCnSHA1Digest; -{* ݿ SHA1 㡣 - - - const Buffer - ݿַ - Count: Cardinal - ݿֽڳ - - ֵTCnSHA1Digest - ص SHA1 Ӵֵ -} - -function SHA1Bytes(Data: TBytes): TCnSHA1Digest; -{* ֽ SHA1 㡣 - - - Data: TBytes - ֽ - - ֵTCnSHA1Digest - ص SHA1 Ӵֵ -} - -function SHA1String(const Str: string): TCnSHA1Digest; -{* String ݽ SHA1 㡣ע D2009 ϰ汾 string Ϊ UnicodeString - лὫǿת AnsiString м㡣 - - - const Str: string - ַ - - ֵTCnSHA1Digest - ص SHA1 Ӵֵ -} - -function SHA1StringA(const Str: AnsiString): TCnSHA1Digest; -{* AnsiString ַ SHA1 㣬ֱӼڲݣޱ봦 - - - const Str: AnsiString - ַ - - ֵTCnSHA1Digest - ص SHA1 Ӵֵ -} - -function SHA1StringW(const Str: WideString): TCnSHA1Digest; -{* WideString ַת SHA1 㡣 - ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ - ƽֱ̨תΪ AnsiString ͣٽм㡣 - - - const Str: WideString - Ŀַ - - ֵTCnSHA1Digest - ص SHA1 Ӵֵ -} - -{$IFDEF UNICODE} - -function SHA1UnicodeString(const Str: string): TCnSHA1Digest; -{* UnicodeString ݽֱӵ SHA1 㣬ֱӼڲ UTF16 ݣת - - - const Str: string - Ŀַ - - ֵTCnSHA1Digest - ص SHA1 Ӵֵ -} - -{$ELSE} - -function SHA1UnicodeString(const Str: WideString): TCnSHA1Digest; -{* UnicodeString ݽֱӵ SHA1 㣬ֱӼڲ UTF16 ݣת - - - const Str: WideString - Ŀַ - - ֵTCnSHA1Digest - ص SHA1 Ӵֵ -} - -{$ENDIF} - -function SHA1File(const FileName: string; - CallBack: TCnSHA1CalcProgressFunc = nil): TCnSHA1Digest; -{* ָļݽ SHA1 㡣 - - - const FileName: string - ļ - CallBack: TCnSHA1CalcProgressFunc - ȻصĬΪ - - ֵTCnSHA1Digest - ص SHA1 Ӵֵ -} - -function SHA1Stream(Stream: TStream; - CallBack: TCnSHA1CalcProgressFunc = nil): TCnSHA1Digest; -{* ָݽ SHA1 㡣 - - - Stream: TStream - - CallBack: TCnSHA1CalcProgressFunc - ȻصĬΪ - - ֵTCnSHA1Digest - ص SHA1 Ӵֵ -} - -// ⲿݽɢ SHA1 㣬SHA1Update ɶα - -procedure SHA1Init(var Context: TCnSHA1Context); -{* ʼһ SHA1 ģ׼ SHA1 - - - var Context: TCnSHA1Context - ʼ SHA1 - - ֵޣ -} - -procedure SHA1Update(var Context: TCnSHA1Context; Input: PAnsiChar; ByteLength: Integer); -{* ԳʼĶһݽ SHA1 㡣 - ɶε㲻ͬݿ飬轫ͬݿƴڴС - - - var Context: TCnSHA1Context - SHA1 - Input: PAnsiChar - ݿַ - ByteLength: Integer - ݿֽڳ - - ֵޣ -} - -procedure SHA1Final(var Context: TCnSHA1Context; var Digest: TCnSHA1Digest); -{* ּ㣬 SHA1 Digest С - - - var Context: TCnSHA1Context - SHA1 - var Digest: TCnSHA1Digest - ص SHA1 Ӵֵ - - ֵޣ -} - -function SHA1Print(const Digest: TCnSHA1Digest): string; -{* ʮƸʽ SHA1 Ӵֵ - - - const Digest: TCnSHA1Digest - ָ SHA1 Ӵֵ - - ֵstring - ʮַ -} - -function SHA1Match(const D1: TCnSHA1Digest; const D2: TCnSHA1Digest): Boolean; -{* Ƚ SHA1 ӴֵǷȡ - - - const D1: TCnSHA1Digest - Ƚϵ SHA1 Ӵֵһ - const D2: TCnSHA1Digest - Ƚϵ SHA1 Ӵֵ - - ֵBoolean - Ƿ -} - -function SHA1DigestToStr(const Digest: TCnSHA1Digest): string; -{* SHA1 Ӵֱֵת stringÿֽڶӦһַ - - - const Digest: TCnSHA1Digest - ת SHA1 Ӵֵ - - ֵstring - صַ -} - -procedure SHA1Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA1Digest); -{* SHA1 HMACHash-based Message Authentication Code㣬 - ͨݵļϼԿĸҲмΡ - - - Key: PAnsiChar - SHA1 Կݿַ - KeyByteLength: Integer - SHA1 Կݿֽڳ - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - var Output: TCnSHA1Digest - ص SHA1 Ӵֵ - - ֵޣ -} - -implementation - -const - MAX_FILE_SIZE = 512 * 1024 * 1024; - // If file size <= this size (bytes), using Mapping, else stream - - HMAC_SHA1_BLOCK_SIZE_BYTE = 64; - HMAC_SHA1_OUTPUT_LENGTH_BYTE = 20; - -function LRot32(X: Cardinal; C: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := X shl (C and 31) + X shr (32 - C and 31); -end; - -function F1(x, y, z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := z xor (x and (y xor z)); -end; - -function F2(x, y, z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := x xor y xor z; -end; - -function F3(x, y, z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := (x and y) or (z and (x or y)); -end; - -function RB(A: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := (A shr 24) or ((A shr 8) and $FF00) or ((A shl 8) and $FF0000) or (A shl 24); -end; - -procedure SHA1Compress(var Data: TCnSHA1Context); -var - A, B, C, D, E, T: Cardinal; - W: array[0..79] of Cardinal; - I: Integer; -begin - Move(Data.Buffer, W, Sizeof(Data.Buffer)); - for I := 0 to 15 do - W[I] := RB(W[I]); - for I := 16 to 79 do - W[I] := LRot32(W[I - 3] xor W[I - 8] xor W[I - 14] xor W[I - 16], 1); - A := Data.Hash[0]; - B := Data.Hash[1]; - C := Data.Hash[2]; - D := Data.Hash[3]; - E := Data.Hash[4]; - for I := 0 to 19 do - begin - T := LRot32(A, 5) + F1(B, C, D) + E + W[I] + $5A827999; - E := D; - D := C; - C := LRot32(B, 30); - B := A; - A := T; - end; - for I := 20 to 39 do - begin - T := LRot32(A, 5) + F2(B, C, D) + E + W[I] + $6ED9EBA1; - E := D; - D := C; - C := LRot32(B, 30); - B := A; - A := T; - end; - for I := 40 to 59 do - begin - T := LRot32(A, 5) + F3(B, C, D) + E + W[I] + $8F1BBCDC; - E := D; - D := C; - C := LRot32(B, 30); - B := A; - A := T; - end; - for I := 60 to 79 do - begin - T := LRot32(A, 5) + F2(B, C, D) + E + W[I] + $CA62C1D6; - E := D; - D := C; - C := LRot32(B, 30); - B := A; - A := T; - end; - Data.Hash[0] := Data.Hash[0] + A; - Data.Hash[1] := Data.Hash[1] + B; - Data.Hash[2] := Data.Hash[2] + C; - Data.Hash[3] := Data.Hash[3] + D; - Data.Hash[4] := Data.Hash[4] + E; - FillChar(W, Sizeof(W), 0); - FillChar(Data.Buffer, Sizeof(Data.Buffer), 0); -end; - -procedure SHA1Init(var Context: TCnSHA1Context); -begin - Context.Hi := 0; - Context.Lo := 0; - Context.Index := 0; - FillChar(Context.Buffer, Sizeof(Context.Buffer), 0); - Context.Hash[0] := $67452301; - Context.Hash[1] := $EFCDAB89; - Context.Hash[2] := $98BADCFE; - Context.Hash[3] := $10325476; - Context.Hash[4] := $C3D2E1F0; -end; - -procedure SHA1UpdateLen(var Context: TCnSHA1Context; Len: Integer); -var - I: Cardinal; - K: Integer; -begin - for K := 0 to 7 do - begin - I := Context.Lo; - Inc(Context.Lo, Len); - if Context.Lo < I then - Inc(Context.Hi); - end; -end; - -procedure SHA1Update(var Context: TCnSHA1Context; Input: PAnsiChar; ByteLength: Integer); -begin - SHA1UpdateLen(Context, ByteLength); - while ByteLength > 0 do - begin - Context.Buffer[Context.Index] := PByte(Input)^; - Inc(PByte(Input)); - Inc(Context.Index); - Dec(ByteLength); - if Context.Index = 64 then - begin - Context.Index := 0; - SHA1Compress(Context); - end; - end; -end; - -procedure SHA1UpdateW(var Context: TCnSHA1Context; Input: PWideChar; CharLength: Cardinal); -var -{$IFDEF MSWINDOWS} - pContent: PAnsiChar; - iLen: Cardinal; -{$ELSE} - S: string; // UnicodeString - A: AnsiString; -{$ENDIF} -begin -{$IFDEF MSWINDOWS} - GetMem(pContent, CharLength * SizeOf(WideChar)); - try - iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 - PAnsiChar(pContent), CharLength * SizeOf(WideChar), nil, nil); - SHA1Update(Context, pContent, iLen); - finally - FreeMem(pContent); - end; -{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ - S := StrNew(Input); - A := AnsiString(S); - SHA1Update(Context, @A[1], Length(A)); -{$ENDIF} -end; - -procedure SHA1Final(var Context: TCnSHA1Context; var Digest: TCnSHA1Digest); -type - PDWord = ^Cardinal; -begin - Context.Buffer[Context.Index] := $80; - if Context.Index >= 56 then - SHA1Compress(Context); - PDWord(@Context.Buffer[56])^ := RB(Context.Hi); - PDWord(@Context.Buffer[60])^ := RB(Context.Lo); - SHA1Compress(Context); - Context.Hash[0] := RB(Context.Hash[0]); - Context.Hash[1] := RB(Context.Hash[1]); - Context.Hash[2] := RB(Context.Hash[2]); - Context.Hash[3] := RB(Context.Hash[3]); - Context.Hash[4] := RB(Context.Hash[4]); - Move(Context.Hash, Digest, Sizeof(Digest)); -end; - -// ݿ SHA1 -function SHA1(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA1Digest; -var - Context: TCnSHA1Context; -begin - SHA1Init(Context); - SHA1Update(Context, Input, ByteLength); - SHA1Final(Context, Result); -end; - -// ݿ SHA1 -function SHA1Buffer(const Buffer; Count: Cardinal): TCnSHA1Digest; -var - Context: TCnSHA1Context; -begin - SHA1Init(Context); - SHA1Update(Context, PAnsiChar(Buffer), Count); - SHA1Final(Context, Result); -end; - -function SHA1Bytes(Data: TBytes): TCnSHA1Digest; -var - Context: TCnSHA1Context; -begin - SHA1Init(Context); - SHA1Update(Context, PAnsiChar(@Data[0]), Length(Data)); - SHA1Final(Context, Result); -end; - -// String ݽ SHA1 -function SHA1String(const Str: string): TCnSHA1Digest; -var - AStr: AnsiString; -begin - AStr := AnsiString(Str); - Result := SHA1StringA(AStr); -end; - -// AnsiString ݽ SHA1 -function SHA1StringA(const Str: AnsiString): TCnSHA1Digest; -var - Context: TCnSHA1Context; -begin - SHA1Init(Context); - SHA1Update(Context, PAnsiChar(Str), Length(Str)); - SHA1Final(Context, Result); -end; - -// WideString ݽ SHA1 -function SHA1StringW(const Str: WideString): TCnSHA1Digest; -var - Context: TCnSHA1Context; -begin - SHA1Init(Context); - SHA1UpdateW(Context, PWideChar(Str), Length(Str)); - SHA1Final(Context, Result); -end; - -{$IFDEF UNICODE} -function SHA1UnicodeString(const Str: string): TCnSHA1Digest; -{$ELSE} -function SHA1UnicodeString(const Str: WideString): TCnSHA1Digest; -{$ENDIF} -var - Context: TCnSHA1Context; -begin - SHA1Init(Context); - SHA1Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); - SHA1Final(Context, Result); -end; - -function InternalSHA1Stream(Stream: TStream; const BufSize: Cardinal; var D: - TCnSHA1Digest; CallBack: TCnSHA1CalcProgressFunc = nil): Boolean; -var - Context: TCnSHA1Context; - Buf: PAnsiChar; - BufLen: Cardinal; - Size: Int64; - ReadBytes: Cardinal; - TotalBytes: Int64; - SavePos: Int64; - CancelCalc: Boolean; -begin - Result := False; - Size := Stream.Size; - SavePos := Stream.Position; - TotalBytes := 0; - if Size = 0 then Exit; - if Size < BufSize then BufLen := Size - else BufLen := BufSize; - - CancelCalc := False; - SHA1Init(Context); - GetMem(Buf, BufLen); - try - Stream.Position := 0; - repeat - ReadBytes := Stream.Read(Buf^, BufLen); - if ReadBytes <> 0 then - begin - Inc(TotalBytes, ReadBytes); - SHA1Update(Context, Buf, ReadBytes); - if Assigned(CallBack) then - begin - CallBack(Size, TotalBytes, CancelCalc); - if CancelCalc then Exit; - end; - end; - until (ReadBytes = 0) or (TotalBytes = Size); - SHA1Final(Context, D); - Result := True; - finally - FreeMem(Buf, BufLen); - Stream.Position := SavePos; - end; -end; - -// ָ SHA1 -function SHA1Stream(Stream: TStream; - CallBack: TCnSHA1CalcProgressFunc = nil): TCnSHA1Digest; -begin - InternalSHA1Stream(Stream, 4096 * 1024, Result, CallBack); -end; - -// ָļݽ SHA1 -function SHA1File(const FileName: string; - CallBack: TCnSHA1CalcProgressFunc): TCnSHA1Digest; -var -{$IFDEF MSWINDOWS} - FileHandle: THandle; - MapHandle: THandle; - ViewPointer: Pointer; - Context: TCnSHA1Context; -{$ENDIF} - Stream: TStream; - FileIsZeroSize: Boolean; - - function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; -{$IFDEF MSWINDOWS} - var - H: THandle; - Info: BY_HANDLE_FILE_INFORMATION; - Rec : Int64Rec; -{$ENDIF} - begin -{$IFDEF MSWINDOWS} - Result := False; - IsEmpty := False; - H := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); - if H = INVALID_HANDLE_VALUE then Exit; - try - if not GetFileInformationByHandle(H, Info) then Exit; - finally - CloseHandle(H); - end; - Rec.Lo := Info.nFileSizeLow; - Rec.Hi := Info.nFileSizeHigh; - Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); - IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); -{$ELSE} - Result := True; // Windows ƽ̨ Trueʾ Mapping -{$ENDIF} - end; - -begin - FileIsZeroSize := False; - if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then - begin - // 2G ļ Map ʧܣ Windows ƽ̨ʽѭ - Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); - try - InternalSHA1Stream(Stream, 4096 * 1024, Result, CallBack); - finally - Stream.Free; - end; - end - else - begin -{$IFDEF MSWINDOWS} - SHA1Init(Context); - FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or - FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or - FILE_FLAG_SEQUENTIAL_SCAN, 0); - if FileHandle <> INVALID_HANDLE_VALUE then - begin - try - MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); - if MapHandle <> 0 then - begin - try - ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); - if ViewPointer <> nil then - begin - try - SHA1Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); - finally - UnmapViewOfFile(ViewPointer); - end; - end - else - begin - raise Exception.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); - end; - finally - CloseHandle(MapHandle); - end; - end - else - begin - if not FileIsZeroSize then - raise Exception.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); - end; - finally - CloseHandle(FileHandle); - end; - end; - SHA1Final(Context, Result); -{$ENDIF} - end; -end; - -// ʮƸʽ SHA1 Ӵֵ -function SHA1Print(const Digest: TCnSHA1Digest): string; -begin - Result := DataToHex(@Digest[0], SizeOf(TCnSHA1Digest)); -end; - -// Ƚ SHA1 ӴֵǷ -function SHA1Match(const D1, D2: TCnSHA1Digest): Boolean; -var - I: Integer; -begin - I := 0; - Result := True; - while Result and (I < 20) do - begin - Result := D1[I] = D2[I]; - Inc(I); - end; -end; - -// SHA1 Ӵֵת string -function SHA1DigestToStr(const Digest: TCnSHA1Digest): string; -begin - Result := MemoryToString(@Digest[0], SizeOf(TCnSHA1Digest)); -end; - -procedure SHA1HmacInit(var Ctx: TCnSHA1Context; Key: PAnsiChar; KeyLength: Integer); -var - I: Integer; - Sum: TCnSHA1Digest; -begin - if KeyLength > HMAC_SHA1_BLOCK_SIZE_BYTE then - begin - Sum := SHA1Buffer(Key, KeyLength); - KeyLength := HMAC_SHA1_OUTPUT_LENGTH_BYTE; - Key := @(Sum[0]); - end; - - FillChar(Ctx.Ipad, HMAC_SHA1_BLOCK_SIZE_BYTE, $36); - FillChar(Ctx.Opad, HMAC_SHA1_BLOCK_SIZE_BYTE, $5C); - - for I := 0 to KeyLength - 1 do - begin - Ctx.Ipad[I] := Byte(Ctx.Ipad[I] xor Byte(Key[I])); - Ctx.Opad[I] := Byte(Ctx.Opad[I] xor Byte(Key[I])); - end; - - SHA1Init(Ctx); - SHA1Update(Ctx, @(Ctx.Ipad[0]), HMAC_SHA1_BLOCK_SIZE_BYTE); -end; - -procedure SHA1HmacUpdate(var Ctx: TCnSHA1Context; Input: PAnsiChar; Length: Cardinal); -begin - SHA1Update(Ctx, Input, Length); -end; - -procedure SHA1HmacFinal(var Ctx: TCnSHA1Context; var Output: TCnSHA1Digest); -var - Len: Integer; - TmpBuf: TCnSHA1Digest; -begin - Len := HMAC_SHA1_OUTPUT_LENGTH_BYTE; - SHA1Final(Ctx, TmpBuf); - SHA1Init(Ctx); - SHA1Update(Ctx, @(Ctx.Opad[0]), HMAC_SHA1_BLOCK_SIZE_BYTE); - SHA1Update(Ctx, @(TmpBuf[0]), Len); - SHA1Final(Ctx, Output); -end; - -procedure SHA1Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA1Digest); -var - Ctx: TCnSHA1Context; -begin - SHA1HmacInit(Ctx, Key, KeyByteLength); - SHA1HmacUpdate(Ctx, Input, ByteLength); - SHA1HmacFinal(Ctx, Output); -end; - -end. +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnSHA1; +{* |
+================================================================================
+* ƣ
+* ԪƣSHA1 Ӵ㷨ʵֵԪ
+* ԪߣCnPack  (master@cnpack.org)
+*           /ֲ䲿ֹܡ
+*     עԪʵ SHA1 Ӵ㷨Ӧ HMAC 㷨
+* ƽ̨PWin2000Pro + Delphi 5.0
+* ݲԣPWin9X/2000/XP + Delphi 5/6
+*   õԪеַϱػʽ
+* ޸ļ¼2022.04.26 V1.5
+*               ޸ LongWord  Integer ַת֧ MacOS64
+*           2019.12.12 V1.4
+*               ֧ TBytes
+*           2019.04.15 V1.3
+*               ֧ Win32/Win64/MacOS32
+*           2015.08.14 V1.2
+*               л Pascal ֿ֧ƽ̨
+*           2014.10.22 V1.1
+*                HMAC 
+*           2010.07.14 V1.0
+*               Ԫ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes {$IFDEF MSWINDOWS}, Windows {$ENDIF}, CnNative, CnConsts; + +type + PCnSHA1Digest = ^TCnSHA1Digest; + {* SHA1 Ӵսָ} + TCnSHA1Digest = array[0..19] of Byte; + {* SHA1 Ӵս20 ֽ} + + TCnSHA1Context = packed record + {* SHA1 Ľṹ} + Hash: array[0..4] of Cardinal; + Hi, Lo: Cardinal; + Buffer: array[0..63] of Byte; + Index: Integer; + Ipad: array[0..63] of Byte; {!< HMAC: inner padding } + Opad: array[0..63] of Byte; {!< HMAC: outer padding } + end; + + TCnSHA1CalcProgressFunc = procedure (ATotal, AProgress: Int64; + var Cancel: Boolean) of object; + {* SHA1 ӴսȻص¼} + +function SHA1(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA1Digest; +{* ݿ SHA1 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1Buffer(const Buffer; Count: Cardinal): TCnSHA1Digest; +{* ݿ SHA1 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1Bytes(const Data: TBytes): TCnSHA1Digest; +{* ֽ SHA1 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1String(const Str: string): TCnSHA1Digest; +{* String ݽ SHA1 㡣ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1StringA(const Str: AnsiString): TCnSHA1Digest; +{* AnsiString ַ SHA1 㣬ֱӼڲݣޱ봦 + + + const Str: AnsiString - ַ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1StringW(const Str: WideString): TCnSHA1Digest; +{* WideString ַת SHA1 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +{$IFDEF UNICODE} + +function SHA1UnicodeString(const Str: string): TCnSHA1Digest; +{* UnicodeString ݽֱӵ SHA1 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +{$ELSE} + +function SHA1UnicodeString(const Str: WideString): TCnSHA1Digest; +{* UnicodeString ݽֱӵ SHA1 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +{$ENDIF} + +function SHA1File(const FileName: string; + CallBack: TCnSHA1CalcProgressFunc = nil): TCnSHA1Digest; +{* ָļݽ SHA1 㡣 + + + const FileName: string - ļ + CallBack: TCnSHA1CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1Stream(Stream: TStream; + CallBack: TCnSHA1CalcProgressFunc = nil): TCnSHA1Digest; +{* ָݽ SHA1 㡣 + + + Stream: TStream - + CallBack: TCnSHA1CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +// ⲿݽɢ SHA1 㣬SHA1Update ɶα + +procedure SHA1Init(var Context: TCnSHA1Context); +{* ʼһ SHA1 ģ׼ SHA1 + + + var Context: TCnSHA1Context - ʼ SHA1 + + ֵޣ +} + +procedure SHA1Update(var Context: TCnSHA1Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA1 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA1Context - SHA1 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA1Final(var Context: TCnSHA1Context; var Digest: TCnSHA1Digest); +{* ּ㣬 SHA1 Digest С + + + var Context: TCnSHA1Context - SHA1 + var Digest: TCnSHA1Digest - ص SHA1 Ӵֵ + + ֵޣ +} + +function SHA1Print(const Digest: TCnSHA1Digest): string; +{* ʮƸʽ SHA1 Ӵֵ + + + const Digest: TCnSHA1Digest - ָ SHA1 Ӵֵ + + ֵstring - ʮַ +} + +function SHA1Match(const D1: TCnSHA1Digest; const D2: TCnSHA1Digest): Boolean; +{* Ƚ SHA1 ӴֵǷȡ + + + const D1: TCnSHA1Digest - Ƚϵ SHA1 Ӵֵһ + const D2: TCnSHA1Digest - Ƚϵ SHA1 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA1DigestToStr(const Digest: TCnSHA1Digest): string; +{* SHA1 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA1Digest - ת SHA1 Ӵֵ + + ֵstring - صַ +} + +procedure SHA1Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA1Digest); +{* SHA1 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA1 Կݿַ + KeyByteLength: Integer - SHA1 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA1Digest - ص SHA1 Ӵֵ + + ֵޣ +} + +function SHA1HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA1Digest; +{* ֽл SHA1 HMAC 㡣 + + + const Key: TBytes - SHA1 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +implementation + +const + MAX_FILE_SIZE = 512 * 1024 * 1024; + // If file size <= this size (bytes), using Mapping, else stream + + HMAC_SHA1_BLOCK_SIZE_BYTE = 64; + HMAC_SHA1_OUTPUT_LENGTH_BYTE = 20; + +function LRot32(X: Cardinal; C: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X shl (C and 31) + X shr (32 - C and 31); +end; + +function F1(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := Z xor (X and (Y xor Z)); +end; + +function F2(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor Y xor Z; +end; + +function F3(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Y) or (Z and (X or Y)); +end; + +function RB(A: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (A shr 24) or ((A shr 8) and $FF00) or ((A shl 8) and $FF0000) or (A shl 24); +end; + +procedure SHA1Compress(var Data: TCnSHA1Context); +var + A, B, C, D, E, T: Cardinal; + W: array[0..79] of Cardinal; + I: Integer; +begin + Move(Data.Buffer, W, Sizeof(Data.Buffer)); + for I := 0 to 15 do + W[I] := RB(W[I]); + for I := 16 to 79 do + W[I] := LRot32(W[I - 3] xor W[I - 8] xor W[I - 14] xor W[I - 16], 1); + A := Data.Hash[0]; + B := Data.Hash[1]; + C := Data.Hash[2]; + D := Data.Hash[3]; + E := Data.Hash[4]; + for I := 0 to 19 do + begin + T := LRot32(A, 5) + F1(B, C, D) + E + W[I] + $5A827999; + E := D; + D := C; + C := LRot32(B, 30); + B := A; + A := T; + end; + for I := 20 to 39 do + begin + T := LRot32(A, 5) + F2(B, C, D) + E + W[I] + $6ED9EBA1; + E := D; + D := C; + C := LRot32(B, 30); + B := A; + A := T; + end; + for I := 40 to 59 do + begin + T := LRot32(A, 5) + F3(B, C, D) + E + W[I] + $8F1BBCDC; + E := D; + D := C; + C := LRot32(B, 30); + B := A; + A := T; + end; + for I := 60 to 79 do + begin + T := LRot32(A, 5) + F2(B, C, D) + E + W[I] + $CA62C1D6; + E := D; + D := C; + C := LRot32(B, 30); + B := A; + A := T; + end; + Data.Hash[0] := Data.Hash[0] + A; + Data.Hash[1] := Data.Hash[1] + B; + Data.Hash[2] := Data.Hash[2] + C; + Data.Hash[3] := Data.Hash[3] + D; + Data.Hash[4] := Data.Hash[4] + E; + FillChar(W, Sizeof(W), 0); + FillChar(Data.Buffer, Sizeof(Data.Buffer), 0); +end; + +procedure SHA1Init(var Context: TCnSHA1Context); +begin + Context.Hi := 0; + Context.Lo := 0; + Context.Index := 0; + FillChar(Context.Buffer, Sizeof(Context.Buffer), 0); + Context.Hash[0] := $67452301; + Context.Hash[1] := $EFCDAB89; + Context.Hash[2] := $98BADCFE; + Context.Hash[3] := $10325476; + Context.Hash[4] := $C3D2E1F0; +end; + +procedure SHA1UpdateLen(var Context: TCnSHA1Context; Len: Integer); +var + I: Cardinal; + K: Integer; +begin + for K := 0 to 7 do + begin + I := Context.Lo; + Inc(Context.Lo, Len); + if Context.Lo < I then + Inc(Context.Hi); + end; +end; + +procedure SHA1Update(var Context: TCnSHA1Context; Input: PAnsiChar; ByteLength: Cardinal); +var + B: Integer; +begin + SHA1UpdateLen(Context, ByteLength); + while ByteLength > 0 do + begin + if Cardinal(64 - Context.Index) > ByteLength then + B := ByteLength + else + B := 64 - Context.Index; + + Move(Input^, Context.Buffer[Context.Index], B); + Inc(PByte(Input), B); + Inc(Context.Index, B); + Dec(ByteLength, B); + + if Context.Index = 64 then + begin + Context.Index := 0; + SHA1Compress(Context); + end; + end; +end; + +procedure SHA1UpdateW(var Context: TCnSHA1Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + pContent: PAnsiChar; + iLen: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(pContent, CharLength * SizeOf(WideChar)); + try + iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(pContent), CharLength * SizeOf(WideChar), nil, nil); + SHA1Update(Context, pContent, iLen); + finally + FreeMem(pContent); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + SHA1Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +procedure SHA1Final(var Context: TCnSHA1Context; var Digest: TCnSHA1Digest); +type + PDWord = ^Cardinal; +begin + Context.Buffer[Context.Index] := $80; + if Context.Index >= 56 then + SHA1Compress(Context); + PDWord(@Context.Buffer[56])^ := RB(Context.Hi); + PDWord(@Context.Buffer[60])^ := RB(Context.Lo); + SHA1Compress(Context); + Context.Hash[0] := RB(Context.Hash[0]); + Context.Hash[1] := RB(Context.Hash[1]); + Context.Hash[2] := RB(Context.Hash[2]); + Context.Hash[3] := RB(Context.Hash[3]); + Context.Hash[4] := RB(Context.Hash[4]); + Move(Context.Hash, Digest, Sizeof(Digest)); +end; + +// ݿ SHA1 +function SHA1(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1Update(Context, Input, ByteLength); + SHA1Final(Context, Result); +end; + +// ݿ SHA1 +function SHA1Buffer(const Buffer; Count: Cardinal): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1Update(Context, PAnsiChar(@Buffer), Count); + SHA1Final(Context, Result); +end; + +function SHA1Bytes(const Data: TBytes): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA1Final(Context, Result); +end; + +// String ݽ SHA1 +function SHA1String(const Str: string): TCnSHA1Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA1StringA(AStr); +end; + +// AnsiString ݽ SHA1 +function SHA1StringA(const Str: AnsiString): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1Update(Context, PAnsiChar(Str), Length(Str)); + SHA1Final(Context, Result); +end; + +// WideString ݽ SHA1 +function SHA1StringW(const Str: WideString): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1UpdateW(Context, PWideChar(Str), Length(Str)); + SHA1Final(Context, Result); +end; + +{$IFDEF UNICODE} +function SHA1UnicodeString(const Str: string): TCnSHA1Digest; +{$ELSE} +function SHA1UnicodeString(const Str: WideString): TCnSHA1Digest; +{$ENDIF} +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA1Final(Context, Result); +end; + +function InternalSHA1Stream(Stream: TStream; const BufSize: Cardinal; var D: + TCnSHA1Digest; CallBack: TCnSHA1CalcProgressFunc): Boolean; +var + Context: TCnSHA1Context; + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; +begin + Result := False; + Size := Stream.Size; + SavePos := Stream.Position; + TotalBytes := 0; + if Size = 0 then Exit; + if Size < BufSize then BufLen := Size + else BufLen := BufSize; + + CancelCalc := False; + SHA1Init(Context); + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + SHA1Update(Context, Buf, ReadBytes); + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + SHA1Final(Context, D); + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +// ָ SHA1 +function SHA1Stream(Stream: TStream; + CallBack: TCnSHA1CalcProgressFunc): TCnSHA1Digest; +begin + InternalSHA1Stream(Stream, 4096 * 1024, Result, CallBack); +end; + +// ָļݽ SHA1 +function SHA1File(const FileName: string; + CallBack: TCnSHA1CalcProgressFunc): TCnSHA1Digest; +var +{$IFDEF MSWINDOWS} + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; + Context: TCnSHA1Context; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; + + function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; +{$IFDEF MSWINDOWS} + var + H: THandle; + Info: BY_HANDLE_FILE_INFORMATION; + Rec : Int64Rec; +{$ENDIF} + begin +{$IFDEF MSWINDOWS} + Result := False; + IsEmpty := False; + H := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); + if H = INVALID_HANDLE_VALUE then Exit; + try + if not GetFileInformationByHandle(H, Info) then Exit; + finally + CloseHandle(H); + end; + Rec.Lo := Info.nFileSizeLow; + Rec.Hi := Info.nFileSizeHigh; + Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); + IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); +{$ELSE} + Result := True; // Windows ƽ̨ Trueʾ Mapping +{$ENDIF} + end; + +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣ Windows ƽ̨ʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalSHA1Stream(Stream, 4096 * 1024, Result, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + SHA1Init(Context); + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + SHA1Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise ECnNativeException.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise ECnNativeException.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + SHA1Final(Context, Result); +{$ENDIF} + end; +end; + +// ʮƸʽ SHA1 Ӵֵ +function SHA1Print(const Digest: TCnSHA1Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA1Digest)); +end; + +// Ƚ SHA1 ӴֵǷ +function SHA1Match(const D1, D2: TCnSHA1Digest): Boolean; +begin + Result := ConstTimeCompareMem(@D1[0], @D2[0], SizeOf(TCnSHA1Digest)); +end; + +// SHA1 Ӵֵת string +function SHA1DigestToStr(const Digest: TCnSHA1Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA1Digest)); +end; + +procedure SHA1HmacInit(var Context: TCnSHA1Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA1Digest; +begin + if KeyLength > HMAC_SHA1_BLOCK_SIZE_BYTE then + begin + Sum := SHA1Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA1_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA1_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA1_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA1Init(Context); + SHA1Update(Context, @(Context.Ipad[0]), HMAC_SHA1_BLOCK_SIZE_BYTE); +end; + +procedure SHA1HmacUpdate(var Context: TCnSHA1Context; Input: PAnsiChar; Length: Cardinal); +begin + SHA1Update(Context, Input, Length); +end; + +procedure SHA1HmacFinal(var Context: TCnSHA1Context; var Output: TCnSHA1Digest); +var + Len: Integer; + TmpBuf: TCnSHA1Digest; +begin + Len := HMAC_SHA1_OUTPUT_LENGTH_BYTE; + SHA1Final(Context, TmpBuf); + SHA1Init(Context); + SHA1Update(Context, @(Context.Opad[0]), HMAC_SHA1_BLOCK_SIZE_BYTE); + SHA1Update(Context, @(TmpBuf[0]), Len); + SHA1Final(Context, Output); +end; + +procedure SHA1Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA1Digest); +var + Context: TCnSHA1Context; +begin + SHA1HmacInit(Context, Key, KeyByteLength); + SHA1HmacUpdate(Context, Input, ByteLength); + SHA1HmacFinal(Context, Output); +end; + +function SHA1HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA1HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA1HmacFinal(Context, Result); +end; + +end. diff --git a/CnPack/Crypto/CnSHA2.pas b/CnPack/Crypto/CnSHA2.pas index dfcc2aa..3a32bc7 100644 --- a/CnPack/Crypto/CnSHA2.pas +++ b/CnPack/Crypto/CnSHA2.pas @@ -1,2337 +1,3294 @@ -{******************************************************************************} -{ CnPack For Delphi/C++Builder } -{ йԼĿԴ } -{ (C)Copyright 2001-2025 CnPack } -{ ------------------------------------ } -{ } -{ ǿԴ CnPack ķЭ } -{ ĺ·һ } -{ } -{ һĿϣãûκεû } -{ ʺضĿĶĵϸ CnPack Э顣 } -{ } -{ ӦѾͿһյһ CnPack Эĸ } -{ ûУɷǵվ } -{ } -{ վַhttps://www.cnpack.org } -{ ʼmaster@cnpack.org } -{ } -{******************************************************************************} - -unit CnSHA2; -{* |
-================================================================================
-* ƣ
-* ԪƣSHA2 Ӵ㷨ʵֵԪ
-* ԪߣCnPack  (master@cnpack.org)
-*           / C  Pascal ֲ䲿ֹܡ
-*     עԪʵ SHA2 ϵӴ㷨Ӧ HMAC 㷨 SHA224/256/384/512
-*           עDelphi 5/6/7 Ԫз Int64 ޷ UInt64  SHA512/384
-*           ԭǻڲ޷ļӼλԼƵȶͬΨһ
-*           ͬDZȽϣԪûƵıȽϡ
-* ƽ̨PWinXP + Delphi 5.0
-* ݲԣPWinXP/7 + Delphi 5/6
-*   õԪеַϱػʽ
-* ޸ļ¼2022.04.26 V1.4
-*               ޸ LongWord  Integer ַת֧ MacOS64
-*           2019.04.15 V1.3
-*               ֧ Win32/Win64/MacOS32
-*           2017.10.31 V1.2
-*                SHA512/384 HMAC 
-*           2016.09.30 V1.1
-*               ʵ SHA512/384D567з Int64 ޷ UInt64
-*           2016.09.27 V1.0
-*               Ԫ
-================================================================================
-|
} - -interface - -{$I CnPack.inc} - -uses - SysUtils, Classes {$IFDEF MSWINDOWS}, Windows {$ENDIF}, CnNative, CnConsts; - -type - PCnSHAGeneralDigest = ^TCnSHAGeneralDigest; - TCnSHAGeneralDigest = array[0..63] of Byte; - - PCnSHA224Digest = ^TCnSHA224Digest; - TCnSHA224Digest = array[0..27] of Byte; - {* SHA224 Ӵս28 ֽ} - - PCnSHA256Digest = ^TCnSHA256Digest; - TCnSHA256Digest = array[0..31] of Byte; - {* SHA256 Ӵս32 ֽ} - - PCnSHA384Digest = ^TCnSHA384Digest; - TCnSHA384Digest = array[0..47] of Byte; - {* SHA384 Ӵս48 ֽ} - - PCnSHA512Digest = ^TCnSHA512Digest; - TCnSHA512Digest = array[0..63] of Byte; - {* SHA512 Ӵս64 ֽ} - - TCnSHA256Context = packed record - {* SHA256 Ľṹ} - DataLen: Cardinal; - Data: array[0..63] of Byte; - BitLen: Int64; - State: array[0..7] of Cardinal; - Ipad: array[0..63] of Byte; {!< HMAC: inner padding } - Opad: array[0..63] of Byte; {!< HMAC: outer padding } - end; - - TCnSHA224Context = TCnSHA256Context; - {* SHA224 Ľṹ} - - TCnSHA512Context = packed record - {* SHA512 Ľṹ} - DataLen: Cardinal; - Data: array[0..127] of Byte; - TotalLen: Int64; - State: array[0..7] of Int64; - Ipad: array[0..127] of Byte; {!< HMAC: inner padding } - Opad: array[0..127] of Byte; {!< HMAC: outer padding } - end; - - TCnSHA384Context = TCnSHA512Context; - {* SHA512 Ľṹ} - - TCnSHACalcProgressFunc = procedure(ATotal, AProgress: Int64; var Cancel: - Boolean) of object; - {* SHA2 ϵӴսȻص¼} - -function SHA224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA224Digest; -{* ݿ SHA224 㡣 - - - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵTCnSHA224Digest - ص SHA224 Ӵֵ -} - -function SHA256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA256Digest; -{* ݿ SHA256 㡣 - - - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵTCnSHA256Digest - ص SHA256 Ӵֵ -} - -function SHA384(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA384Digest; -{* ݿ SHA384 㡣 - - - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵTCnSHA384Digest - ص SHA384Ӵֵ -} - -function SHA512(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA512Digest; -{* ݿ SHA512 㡣 - - - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵTCnSHA512Digest - ص SHA512 Ӵֵ -} - -function SHA224Buffer(const Buffer; Count: Cardinal): TCnSHA224Digest; -{* ݿ SHA224 㡣 - - - const Buffer - ݿַ - Count: Cardinal - ݿֽڳ - - ֵTCnSHA224Digest - ص SHA224 Ӵֵ -} - -function SHA256Buffer(const Buffer; Count: Cardinal): TCnSHA256Digest; -{* ݿ SHA256 㡣 - - - const Buffer - ݿַ - Count: Cardinal - - - ֵTCnSHA256Digest - ص SHA256 Ӵֵ -} - -function SHA384Buffer(const Buffer; Count: Cardinal): TCnSHA384Digest; -{* ݿ SHA384 㡣 - - - const Buffer - ݿַ - Count: Cardinal - - - ֵTCnSHA384Digest - ص SHA384Ӵֵ -} - -function SHA512Buffer(const Buffer; Count: Cardinal): TCnSHA512Digest; -{* ݿ SHA512 㡣 - - - const Buffer - ݿַ - Count: Cardinal - - - ֵTCnSHA512Digest - ص SHA512 Ӵֵ -} - -function SHA224Bytes(Data: TBytes): TCnSHA224Digest; -{* ֽ SHA224 㡣 - - - Data: TBytes - ֽ - - ֵTCnSHA224Digest - ص SHA224 Ӵֵ -} - -function SHA256Bytes(Data: TBytes): TCnSHA256Digest; -{* ֽ SHA256 㡣 - - - Data: TBytes - ֽ - - ֵTCnSHA256Digest - ص SHA256 Ӵֵ -} - -function SHA384Bytes(Data: TBytes): TCnSHA384Digest; -{* ֽ SHA384 㡣 - - Data: TBytes - ֽ - - ֵTCnSHA384Digest - ص SHA384Ӵֵ -} - -function SHA512Bytes(Data: TBytes): TCnSHA512Digest; -{* ֽ SHA512 㡣 - - - Data: TBytes - ֽ - - ֵTCnSHA512Digest - ص SHA512 Ӵֵ -} - -function SHA224String(const Str: string): TCnSHA224Digest; -{* String ݽ SHA224 㣬ע D2009 ϰ汾 string Ϊ UnicodeString - лὫǿת AnsiString м㡣 - - - const Str: string - ַ - - ֵTCnSHA224Digest - ص SHA224 Ӵֵ -} - -function SHA256String(const Str: string): TCnSHA256Digest; -{* String ݽ SHA256 㣬ע D2009 ϰ汾 string Ϊ UnicodeString - лὫǿת AnsiString м㡣 - - - const Str: string - ַ - - ֵTCnSHA256Digest - ص SHA256 Ӵֵ -} - -function SHA384String(const Str: string): TCnSHA384Digest; -{* String ݽ SHA384 㣬ע D2009ϰ汾string Ϊ UnicodeString - лὫǿת AnsiString м㡣 - - - const Str: string - ַ - - ֵTCnSHA384Digest - ص SHA384Ӵֵ -} - -function SHA512String(const Str: string): TCnSHA512Digest; -{* String ݽ SHA512 㣬ע D2009 ϰ汾 string Ϊ UnicodeString - лὫǿת AnsiString м㡣 - - - const Str: string - ַ - - ֵTCnSHA512Digest - ص SHA512 Ӵֵ -} - - -function SHA224StringA(const Str: AnsiString): TCnSHA224Digest; -{* AnsiString ݽ SHA224 㡣 - - - const Str: AnsiString - - - ֵTCnSHA224Digest - ص SHA224 Ӵֵ -} - -function SHA224StringW(const Str: WideString): TCnSHA224Digest; -{* WideString ݽ SHA224 㡣 - ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ - ƽֱ̨תΪ AnsiString ͣٽм㡣 - - - const Str: WideString - Ŀַ - - ֵTCnSHA224Digest - ص SHA224 Ӵֵ -} - -function SHA256StringA(const Str: AnsiString): TCnSHA256Digest; -{* AnsiString ݽ SHA256 㡣 - - - const Str: AnsiString - - - ֵTCnSHA256Digest - ص SHA256 Ӵֵ -} - -function SHA256StringW(const Str: WideString): TCnSHA256Digest; -{* WideString ݽ SHA256 㡣 - ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ - ƽֱ̨תΪ AnsiString ͣٽм㡣 - - - const Str: WideString - Ŀַ - - ֵTCnSHA256Digest - ص SHA256 Ӵֵ -} - -function SHA384StringA(const Str: AnsiString): TCnSHA384Digest; -{* AnsiString ݽ SHA384 㡣 - - - const Str: AnsiString - - - ֵTCnSHA384Digest - ص SHA384Ӵֵ -} - -function SHA384StringW(const Str: WideString): TCnSHA384Digest; -{* WideString ݽ SHA384 㡣 - ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ - ƽֱ̨תΪ AnsiString ͣٽм㡣 - - - const Str: WideString - Ŀַ - - ֵTCnSHA384Digest - ص SHA384Ӵֵ -} - -function SHA512StringA(const Str: AnsiString): TCnSHA512Digest; -{* AnsiString ݽ SHA512 㡣 - - - const Str: AnsiString - - - ֵTCnSHA512Digest - ص SHA512 Ӵֵ -} - -function SHA512StringW(const Str: WideString): TCnSHA512Digest; -{* WideString ݽ SHA512 㡣 - ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ - ƽֱ̨תΪ AnsiString ͣٽм㡣 - - - const Str: WideString - Ŀַ - - ֵTCnSHA512Digest - ص SHA512 Ӵֵ -} - -{$IFDEF UNICODE} - -function SHA224UnicodeString(const Str: string): TCnSHA224Digest; -{* UnicodeString ݽֱӵ SHA224 㣬ֱӼڲ UTF16 ݣת - - - const Str: string - Ŀַ - - ֵTCnSHA224Digest - ص SHA224 Ӵֵ -} - -function SHA256UnicodeString(const Str: string): TCnSHA256Digest; -{* UnicodeString ݽֱӵ SHA256 㣬ֱӼڲ UTF16 ݣת - - - const Str: string - Ŀַ - - ֵTCnSHA256Digest - ص SHA256 Ӵֵ -} - -function SHA384UnicodeString(const Str: string): TCnSHA384Digest; -{* UnicodeString ݽֱӵ SHA384 㣬ֱӼڲ UTF16 ݣת - - - const Str: string - Ŀַ - - ֵTCnSHA384Digest - ص SHA384Ӵֵ -} - -function SHA512UnicodeString(const Str: string): TCnSHA512Digest; -{* UnicodeString ݽֱӵ SHA512 㣬ֱӼڲ UTF16 ݣת - - - const Str: string - Ŀַ - - ֵTCnSHA512Digest - ص SHA512 Ӵֵ -} - -{$ELSE} - -function SHA224UnicodeString(const Str: WideString): TCnSHA224Digest; -{* UnicodeString ݽֱӵ SHA224 㣬ֱӼڲ UTF16 ݣת - - - const Str: WideString - Ŀַ - - ֵTCnSHA224Digest - ص SHA224 Ӵֵ -} - -function SHA256UnicodeString(const Str: WideString): TCnSHA256Digest; -{* UnicodeString ݽֱӵ SHA256 㣬ֱӼڲ UTF16 ݣת - - - const Str: WideString - Ŀַ - - ֵTCnSHA256Digest - ص SHA256 Ӵֵ -} - -function SHA384UnicodeString(const Str: WideString): TCnSHA384Digest; -{* UnicodeString ݽֱӵ SHA384 㣬ֱӼڲ UTF16 ݣת - - - const Str: WideString - Ŀַ - - ֵTCnSHA384Digest - ص SHA384Ӵֵ -} - -function SHA512UnicodeString(const Str: WideString): TCnSHA512Digest; -{* UnicodeString ݽֱӵ SHA512 㣬ֱӼڲ UTF16 ݣת - - - const Str: WideString - Ŀַ - - ֵTCnSHA512Digest - ص SHA512 Ӵֵ -} - -{$ENDIF} - -function SHA224File(const FileName: string; CallBack: TCnSHACalcProgressFunc = - nil): TCnSHA224Digest; -{* ָļݽ SHA256 㡣 - - - const FileName: string - ļ - CallBack: TCnSHACalcProgressFunc - ȻصĬΪ - - ֵTCnSHA224Digest - ص SHA224 Ӵֵ -} - -function SHA224Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): - TCnSHA224Digest; -{* ָݽ SHA224 㡣 - - - Stream: TStream - - CallBack: TCnSHACalcProgressFunc - ȻصĬΪ - - ֵTCnSHA224Digest - ص SHA224 Ӵֵ -} - -function SHA256File(const FileName: string; CallBack: TCnSHACalcProgressFunc = - nil): TCnSHA256Digest; -{* ָļݽ SHA256 㡣 - - - const FileName: string - ļ - CallBack: TCnSHACalcProgressFunc - ȻصĬΪ - - ֵTCnSHA256Digest - ص SHA256 Ӵֵ -} - -function SHA256Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): - TCnSHA256Digest; -{* ָݽ SHA256 㡣 - - - Stream: TStream - - CallBack: TCnSHACalcProgressFunc - ȻصĬΪ - - ֵTCnSHA256Digest - ص SHA256 Ӵֵ -} - -function SHA384File(const FileName: string; CallBack: TCnSHACalcProgressFunc = - nil): TCnSHA384Digest; -{* ָļݽ SHA384 㡣 - - - const FileName: string - ļ - CallBack: TCnSHACalcProgressFunc - ȻصĬΪ - - ֵTCnSHA384Digest - ص SHA384Ӵֵ -} - -function SHA384Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): - TCnSHA384Digest; -{* ָݽ SHA384 㡣 - - - Stream: TStream - - CallBack: TCnSHACalcProgressFunc - ȻصĬΪ - - ֵTCnSHA384Digest - ص SHA384Ӵֵ -} - -function SHA512File(const FileName: string; CallBack: TCnSHACalcProgressFunc = - nil): TCnSHA512Digest; -{* ָļݽ SHA512 㡣 - - - const FileName: string - ļ - CallBack: TCnSHACalcProgressFunc - ȻصĬΪ - - ֵTCnSHA512Digest - ص SHA512 Ӵֵ -} - -function SHA512Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): - TCnSHA512Digest; -{* ָݽ SHA512 㡣 - - - Stream: TStream - - CallBack: TCnSHACalcProgressFunc - ȻصĬΪ - - ֵTCnSHA512Digest - ص SHA512 Ӵֵ -} - -// ⲿݽɢ SHA224 㣬SHA224Update ɶα - -procedure SHA224Init(var Context: TCnSHA224Context); -{* ʼһ SHA224 ģ׼ SHA224 - - - var Context: TCnSHA224Context - ʼ SHA224 - - ֵޣ -} - -procedure SHA224Update(var Context: TCnSHA224Context; Input: PAnsiChar; ByteLength: Cardinal); -{* ԳʼĶһݽ SHA224 㡣 - ɶε㲻ͬݿ飬轫ͬݿƴڴС - - - var Context: TCnSHA224Context - SHA224 - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵޣ -} - -procedure SHA224Final(var Context: TCnSHA224Context; var Digest: TCnSHA224Digest); -{* ּ㣬 SHA224 Digest С - - - var Context: TCnSHA224Context - SHA224 - var Digest: TCnSHA224Digest - ص SHA224 Ӵֵ - - ֵޣ -} - -// ⲿݽɢ SHA256 㣬SHA256Update ɶα - -procedure SHA256Init(var Context: TCnSHA256Context); -{* ʼһ SHA256 ģ׼ SHA256 - - - var Context: TCnSHA256Context - ʼ SHA256 - - ֵޣ -} - -procedure SHA256Update(var Context: TCnSHA256Context; Input: PAnsiChar; ByteLength: Cardinal); -{* ԳʼĶһݽ SHA256 㡣 - ɶε㲻ͬݿ飬轫ͬݿƴڴС - - - var Context: TCnSHA256Context - SHA256 - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵޣ -} - -procedure SHA256Final(var Context: TCnSHA256Context; var Digest: TCnSHA256Digest); -{* ּ㣬 SHA256 Digest С - - - var Context: TCnSHA256Context - SHA256 - var Digest: TCnSHA256Digest - ص SHA256 Ӵֵ - - ֵޣ -} - -// ⲿݽɢ SHA384 㣬SHA384Update ɶα - -procedure SHA384Init(var Context: TCnSHA384Context); -{* ʼһ SHA384 ģ׼ SHA384 - - - var Context: TCnSHA384Context - ʼ SHA384 - - ֵޣ -} - -procedure SHA384Update(var Context: TCnSHA384Context; Input: PAnsiChar; ByteLength: Cardinal); -{* ԳʼĶһݽ SHA384 㡣 - ɶε㲻ͬݿ飬轫ͬݿƴڴС - - - var Context: TCnSHA384Context - SHA384 - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵޣ -} - -procedure SHA384Final(var Context: TCnSHA384Context; var Digest: TCnSHA384Digest); -{* ּ㣬 SHA384 Digest С - - - var Context: TCnSHA384Context - SHA384 - var Digest: TCnSHA384Digest - ص SHA384 Ӵֵ - - ֵޣ -} - -// ⲿݽɢ SHA512 㣬SHA512Update ɶα - -procedure SHA512Init(var Context: TCnSHA512Context); -{* ʼһ SHA512 ģ׼ SHA512 - - - var Context: TCnSHA512Context - ʼ SHA512 - - ֵޣ -} - -procedure SHA512Update(var Context: TCnSHA512Context; Input: PAnsiChar; ByteLength: Cardinal); -{* ԳʼĶһݽ SHA512 㡣 - ɶε㲻ͬݿ飬轫ͬݿƴڴС - - - var Context: TCnSHA512Context - SHA512 - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵޣ -} - -procedure SHA512Final(var Context: TCnSHA512Context; var Digest: TCnSHA512Digest); -{* ּ㣬 SHA512 Digest - - - var Context: TCnSHA512Context - SHA512 - var Digest: TCnSHA512Digest - ص SHA512 Ӵֵ - - ֵޣ -} - -function SHA224Print(const Digest: TCnSHA224Digest): string; -{* ʮƸʽ SHA224 Ӵֵ - - - const Digest: TCnSHA224Digest - ָ SHA224 Ӵֵ - - ֵstring - ʮַ -} - -function SHA256Print(const Digest: TCnSHA256Digest): string; -{* ʮƸʽ SHA256 Ӵֵ - - - const Digest: TCnSHA256Digest - ָ SHA256 Ӵֵ - - ֵstring - ʮַ -} - -function SHA384Print(const Digest: TCnSHA384Digest): string; -{* ʮƸʽ SHA384 Ӵֵ - - - const Digest: TCnSHA384Digest - ָ SHA384 Ӵֵ - - ֵstring - ʮַ -} - -function SHA512Print(const Digest: TCnSHA512Digest): string; -{* ʮƸʽ SHA512 Ӵֵ - - - const Digest: TCnSHA512Digest - ָ SHA512 Ӵֵ - - ֵstring - ʮַ -} - -function SHA224Match(const D1: TCnSHA224Digest; const D2: TCnSHA224Digest): Boolean; -{* Ƚ SHA224 ӴֵǷȡ - - - const D1: TCnSHA224Digest - Ƚϵ SHA224 Ӵֵһ - const D2: TCnSHA224Digest - Ƚϵ SHA224 Ӵֵ - - ֵBoolean - Ƿ -} - -function SHA256Match(const D1: TCnSHA256Digest; const D2: TCnSHA256Digest): Boolean; -{* Ƚ SHA256 ӴֵǷȡ - - - const D1: TCnSHA256Digest - Ƚϵ SHA256 Ӵֵһ - const D2: TCnSHA256Digest - Ƚϵ SHA256 Ӵֵ - - ֵBoolean - Ƿ -} - -function SHA384Match(const D1: TCnSHA384Digest; const D2: TCnSHA384Digest): Boolean; -{* Ƚ SHA384 ӴֵǷȡ - - - const D1: TCnSHA384Digest - Ƚϵ SHA384 Ӵֵһ - const D2: TCnSHA384Digest - Ƚϵ SHA384 Ӵֵ - - ֵBoolean - Ƿ -} - -function SHA512Match(const D1: TCnSHA512Digest; const D2: TCnSHA512Digest): Boolean; -{* Ƚ SHA512 ӴֵǷȡ - - - const D1: TCnSHA512Digest - Ƚϵ SHA512 Ӵֵһ - const D2: TCnSHA512Digest - Ƚϵ SHA512 Ӵֵ - - ֵBoolean - Ƿ -} - -function SHA224DigestToStr(const Digest: TCnSHA224Digest): string; -{* SHA224 Ӵֱֵת stringÿֽڶӦһַ - - - const Digest: TCnSHA224Digest - ת SHA224 Ӵֵ - - ֵstring - صַ -} - -function SHA256DigestToStr(const Digest: TCnSHA256Digest): string; -{* SHA256 Ӵֱֵת stringÿֽڶӦһַ - - - const Digest: TCnSHA256Digest - ת SHA256 Ӵֵ - - ֵstring - صַ -} - -function SHA384DigestToStr(const Digest: TCnSHA384Digest): string; -{* SHA384 Ӵֱֵת stringÿֽڶӦһַ - - - const Digest: TCnSHA384Digest - ת SHA384 Ӵֵ - - ֵstring - صַ -} - -function SHA512DigestToStr(const Digest: TCnSHA512Digest): string; -{* SHA512 Ӵֱֵת stringÿֽڶӦһַ - - - const Digest: TCnSHA512Digest - ת SHA512 Ӵֵ - - ֵstring - صַ -} - -procedure SHA224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA224Digest); -{* SHA224 HMACHash-based Message Authentication Code㣬 - ͨݵļϼԿĸҲмΡ - - - Key: PAnsiChar - SHA224 Կݿַ - KeyByteLength: Integer - SHA224 Կݿֽڳ - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - var Output: TCnSHA224Digest - ص SHA224 Ӵֵ - - ֵޣ -} - -procedure SHA256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA256Digest); -{* SHA256 HMACHash-based Message Authentication Code㣬 - ͨݵļϼԿĸҲмΡ - - - Key: PAnsiChar - SHA256 Կݿַ - KeyByteLength: Integer - SHA256 Կݿֽڳ - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - var Output: TCnSHA256Digest - ص SHA256 Ӵֵ - - ֵޣ -} - -procedure SHA384Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA384Digest); -{* SHA384 HMACHash-based Message Authentication Code㣬 - ͨݵļϼԿĸҲмΡ - - - Key: PAnsiChar - SHA384 Կݿַ - KeyByteLength: Integer - SHA384 Կݿֽڳ - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - var Output: TCnSHA384Digest - ص SHA384 Ӵֵ - - ֵޣ -} - -procedure SHA512Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA512Digest); -{* SHA512 HMACHash-based Message Authentication Code㣬 - ͨݵļϼԿĸҲмΡ - - - Key: PAnsiChar - SHA512 Կݿַ - KeyByteLength: Integer - SHA512 Կݿֽڳ - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - var Output: TCnSHA512Digest - ص SHA512 Ӵֵ - - ֵޣ -} - -implementation - -const - HMAC_SHA2_224_256_BLOCK_SIZE_BYTE = 64; - HMAC_SHA2_384_512_BLOCK_SIZE_BYTE = 128; - - HMAC_SHA2_224_OUTPUT_LENGTH_BYTE = 28; - HMAC_SHA2_256_OUTPUT_LENGTH_BYTE = 32; - HMAC_SHA2_384_OUTPUT_LENGTH_BYTE = 48; - HMAC_SHA2_512_OUTPUT_LENGTH_BYTE = 64; - -type - TSHA2Type = (stSHA2_224, stSHA2_256, stSHA2_384, stSHA2_512); - -const - MAX_FILE_SIZE = 512 * 1024 * 1024; - // If file size <= this size (bytes), using Mapping, else stream - - KEYS256: array[0..63] of Cardinal = ($428A2F98, $71374491, $B5C0FBCF, $E9B5DBA5, - $3956C25B, $59F111F1, $923F82A4, $AB1C5ED5, $D807AA98, $12835B01, $243185BE, - $550C7DC3, $72BE5D74, $80DEB1FE, $9BDC06A7, $C19BF174, $E49B69C1, $EFBE4786, - $0FC19DC6, $240CA1CC, $2DE92C6F, $4A7484AA, $5CB0A9DC, $76F988DA, $983E5152, - $A831C66D, $B00327C8, $BF597FC7, $C6E00BF3, $D5A79147, $06CA6351, $14292967, - $27B70A85, $2E1B2138, $4D2C6DFC, $53380D13, $650A7354, $766A0ABB, $81C2C92E, - $92722C85, $A2BFE8A1, $A81A664B, $C24B8B70, $C76C51A3, $D192E819, $D6990624, - $F40E3585, $106AA070, $19A4C116, $1E376C08, $2748774C, $34B0BCB5, $391C0CB3, - $4ED8AA4A, $5B9CCA4F, $682E6FF3, $748F82EE, $78A5636F, $84C87814, $8CC70208, - $90BEFFFA, $A4506CEB, $BEF9A3F7, $C67178F2); - - KEYS512: array[0..79] of TUInt64 = ($428A2F98D728AE22, $7137449123EF65CD, - $B5C0FBCFEC4D3B2F, $E9B5DBA58189DBBC, $3956C25BF348B538, $59F111F1B605D019, - $923F82A4AF194F9B, $AB1C5ED5DA6D8118, $D807AA98A3030242, $12835B0145706FBE, - $243185BE4EE4B28C, $550C7DC3D5FFB4E2, $72BE5D74F27B896F, $80DEB1FE3B1696B1, - $9BDC06A725C71235, $C19BF174CF692694, $E49B69C19EF14AD2, $EFBE4786384F25E3, - $0FC19DC68B8CD5B5, $240CA1CC77AC9C65, $2DE92C6F592B0275, $4A7484AA6EA6E483, - $5CB0A9DCBD41FBD4, $76F988DA831153B5, $983E5152EE66DFAB, $A831C66D2DB43210, - $B00327C898FB213F, $BF597FC7BEEF0EE4, $C6E00BF33DA88FC2, $D5A79147930AA725, - $06CA6351E003826F, $142929670A0E6E70, $27B70A8546D22FFC, $2E1B21385C26C926, - $4D2C6DFC5AC42AED, $53380D139D95B3DF, $650A73548BAF63DE, $766A0ABB3C77B2A8, - $81C2C92E47EDAEE6, $92722C851482353B, $A2BFE8A14CF10364, $A81A664BBC423001, - $C24B8B70D0F89791, $C76C51A30654BE30, $D192E819D6EF5218, $D69906245565A910, - $F40E35855771202A, $106AA07032BBD1B8, $19A4C116B8D2D0C8, $1E376C085141AB53, - $2748774CDF8EEB99, $34B0BCB5E19B48A8, $391C0CB3C5C95A63, $4ED8AA4AE3418ACB, - $5B9CCA4F7763E373, $682E6FF3D6B2B8A3, $748F82EE5DEFB2FC, $78A5636F43172F60, - $84C87814A1F0AB72, $8CC702081A6439EC, $90BEFFFA23631E28, $A4506CEBDE82BDE9, - $BEF9A3F7B2C67915, $C67178F2E372532B, $CA273ECEEA26619C, $D186B8C721C0C207, - $EADA7DD6CDE0EB1E, $F57D4F7FEE6ED178, $06F067AA72176FBA, $0A637DC5A2C898A6, - $113F9804BEF90DAE, $1B710B35131C471B, $28DB77F523047D84, $32CAAB7B40C72493, - $3C9EBE0A15C9BEBC, $431D67C49C100D4C, $4CC5D4BECB3E42B6, $597F299CFC657E2A, - $5FCB6FAB3AD6FAEC, $6C44198C4A475817); - -function ROTRight256(A, B: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := (A shr B) or (A shl (32 - B)); -end; - -function ROTRight512(X: TUInt64; Y: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := (X shr Y) or (X shl (64 - Y)); -end; - -function SHR512(X: TUInt64; Y: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := (X and $FFFFFFFFFFFFFFFF) shr Y; -end; - -function CH256(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := (X and Y) xor ((not X) and Z); -end; - -function CH512(X, Y, Z: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := (((Y xor Z) and X) xor Z); -end; - -function MAJ256(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := (X and Y) xor (X and Z) xor (Y and Z); -end; - -function MAJ512(X, Y, Z: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := ((X or Y) and Z) or (X and Y); -end; - -function EP0256(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := ROTRight256(X, 2) xor ROTRight256(X, 13) xor ROTRight256(X, 22); -end; - -function EP1256(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := ROTRight256(X, 6) xor ROTRight256(X, 11) xor ROTRight256(X, 25); -end; - -function SIG0256(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := ROTRight256(X, 7) xor ROTRight256(X, 18) xor (X shr 3); -end; - -function SIG1256(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := ROTRight256(X, 17) xor ROTRight256(X, 19) xor (X shr 10); -end; - -function SIG0512(X: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := ROTRight512(X, 28) xor ROTRight512(X, 34) xor ROTRight512(X, 39); -end; - -function SIG1512(X: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := ROTRight512(X, 14) xor ROTRight512(X, 18) xor ROTRight512(X, 41); -end; - -function Gamma0512(X: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := ROTRight512(X, 1) xor ROTRight512(X, 8) xor SHR512(X, 7); -end; - -function Gamma1512(X: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := ROTRight512(X, 19) xor ROTRight512(X, 61) xor SHR512(X, 6); -end; - -procedure SHA256Transform(var Context: TCnSHA256Context; Data: PAnsiChar); -var - A, B, C, D, E, F, G, H, T1, T2: Cardinal; - M: array[0..63] of Cardinal; - I, J: Integer; -begin - I := 0; - J := 0; - while I < 16 do - begin - M[I] := (Cardinal(Data[J]) shl 24) or (Cardinal(Data[J + 1]) shl 16) or (Cardinal(Data - [J + 2]) shl 8) or Cardinal(Data[J + 3]); - Inc(I); - Inc(J, 4); - end; - - while I < 64 do - begin - M[I] := SIG1256(M[I - 2]) + M[I - 7] + SIG0256(M[I - 15]) + M[I - 16]; - Inc(I); - end; - - A := Context.State[0]; - B := Context.State[1]; - C := Context.State[2]; - D := Context.State[3]; - E := Context.State[4]; - F := Context.State[5]; - G := Context.State[6]; - H := Context.State[7]; - - I := 0; - while I < 64 do - begin - T1 := H + EP1256(E) + CH256(E, F, G) + KEYS256[I] + M[I]; - T2 := EP0256(A) + MAJ256(A, B, C); - H := G; - G := F; - F := E; - E := D + T1; - D := C; - C := B; - B := A; - A := T1 + T2; - Inc(I); - end; - - Context.State[0] := Context.State[0] + A; - Context.State[1] := Context.State[1] + B; - Context.State[2] := Context.State[2] + C; - Context.State[3] := Context.State[3] + D; - Context.State[4] := Context.State[4] + E; - Context.State[5] := Context.State[5] + F; - Context.State[6] := Context.State[6] + G; - Context.State[7] := Context.State[7] + H; -end; - -{$WARNINGS OFF} - -procedure SHA512Transform(var Context: TCnSHA512Context; Data: PAnsiChar; BlockCount: Integer); -var - A, B, C, D, E, F, G, H, T1, T2: TUInt64; - M: array[0..79] of TUInt64; - I, J, K: Integer; - OrigData: PAnsiChar; -begin - OrigData := Data; - for K := 0 to BlockCount - 1 do - begin - Data := PAnsiChar(TCnNativeInt(OrigData) + (K shl 7)); - - I := 0; - J := 0; - while I < 16 do - begin - M[I] := (TUInt64(Data[J]) shl 56) or (TUInt64(Data[J + 1]) shl 48) or - (TUInt64(Data[J + 2]) shl 40) or (TUInt64(Data[J + 3]) shl 32) or - (TUInt64(Data[J + 4]) shl 24) or (TUInt64(Data[J + 5]) shl 16) or - (TUInt64(Data[J + 6]) shl 8) or TUInt64(Data[J + 7]); - Inc(I); - Inc(J, 8); - end; - - while I < 80 do - begin - M[I] := Gamma1512(M[I - 2]) + M[I - 7] + Gamma0512(M[I - 15]) + M[I - 16]; - Inc(I); - end; - - A := Context.State[0]; - B := Context.State[1]; - C := Context.State[2]; - D := Context.State[3]; - E := Context.State[4]; - F := Context.State[5]; - G := Context.State[6]; - H := Context.State[7]; - - I := 0; - while I < 80 do - begin - T1 := H + SIG1512(E) + CH512(E, F, G) + KEYS512[I] + M[I]; - T2 := SIG0512(A) + MAJ512(A, B, C); - H := G; - G := F; - F := E; - E := D + T1; - D := C; - C := B; - B := A; - A := T1 + T2; - Inc(I); - end; - - // з޷ WarningӰ - Context.State[0] := Context.State[0] + A; - Context.State[1] := Context.State[1] + B; - Context.State[2] := Context.State[2] + C; - Context.State[3] := Context.State[3] + D; - Context.State[4] := Context.State[4] + E; - Context.State[5] := Context.State[5] + F; - Context.State[6] := Context.State[6] + G; - Context.State[7] := Context.State[7] + H; - end; -end; - -{$WARNINGS ON} - -procedure SHA224Init(var Context: TCnSHA224Context); -begin - Context.DataLen := 0; - Context.BitLen := 0; - Context.State[0] := $C1059ED8; - Context.State[1] := $367CD507; - Context.State[2] := $3070DD17; - Context.State[3] := $F70E5939; - Context.State[4] := $FFC00B31; - Context.State[5] := $68581511; - Context.State[6] := $64F98FA7; - Context.State[7] := $BEFA4FA4; - FillChar(Context.Data, SizeOf(Context.Data), 0); -end; - -procedure SHA224Update(var Context: TCnSHA224Context; Input: PAnsiChar; ByteLength: Cardinal); -begin - SHA256Update(Context, Input, ByteLength); -end; - -procedure SHA256UpdateW(var Context: TCnSHA256Context; Input: PWideChar; CharLength: Cardinal); forward; - -procedure SHA224UpdateW(var Context: TCnSHA224Context; Input: PWideChar; CharLength: Cardinal); -begin - SHA256UpdateW(Context, Input, CharLength); -end; - -procedure SHA224Final(var Context: TCnSHA224Context; var Digest: TCnSHA224Digest); -var - Dig: TCnSHA256Digest; -begin - SHA256Final(Context, Dig); - Move(Dig[0], Digest[0], SizeOf(TCnSHA224Digest)); -end; - -procedure SHA256Init(var Context: TCnSHA256Context); -begin - Context.DataLen := 0; - Context.BitLen := 0; - Context.State[0] := $6A09E667; - Context.State[1] := $BB67AE85; - Context.State[2] := $3C6EF372; - Context.State[3] := $A54FF53A; - Context.State[4] := $510E527F; - Context.State[5] := $9B05688C; - Context.State[6] := $1F83D9AB; - Context.State[7] := $5BE0CD19; - FillChar(Context.Data, SizeOf(Context.Data), 0); -end; - -procedure SHA256Update(var Context: TCnSHA256Context; Input: PAnsiChar; ByteLength: Cardinal); -var - I: Integer; -begin - for I := 0 to ByteLength - 1 do - begin - Context.Data[Context.DataLen] := Byte(Input[I]); - Inc(Context.DataLen); - if Context.DataLen = 64 then - begin - SHA256Transform(Context, @Context.Data[0]); - Context.BitLen := Context.BitLen + 512; - Context.DataLen := 0; - end; - end; -end; - -procedure SHA256UpdateW(var Context: TCnSHA256Context; Input: PWideChar; CharLength: Cardinal); -var -{$IFDEF MSWINDOWS} - Content: PAnsiChar; - iLen: Cardinal; -{$ELSE} - S: string; // UnicodeString - A: AnsiString; -{$ENDIF} -begin -{$IFDEF MSWINDOWS} - GetMem(Content, CharLength * SizeOf(WideChar)); - try - iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 - PAnsiChar(Content), CharLength * SizeOf(WideChar), nil, nil); - SHA256Update(Context, Content, iLen); - finally - FreeMem(Content); - end; -{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ - S := StrNew(Input); - A := AnsiString(S); - SHA256Update(Context, @A[1], Length(A)); -{$ENDIF} -end; - -procedure SHA256Final(var Context: TCnSHA256Context; var Digest: TCnSHA256Digest); -var - I: Integer; -begin - I := Context.DataLen; - Context.Data[I] := $80; - Inc(I); - - if Context.Datalen < 56 then - begin - while I < 56 do - begin - Context.Data[I] := 0; - Inc(I); - end; - end - else - begin - while I < 64 do - begin - Context.Data[I] := 0; - Inc(I); - end; - - SHA256Transform(Context, @(Context.Data[0])); - FillChar(Context.Data, 56, 0); - end; - - Context.BitLen := Context.BitLen + Context.DataLen * 8; - Context.Data[63] := Context.Bitlen; - Context.Data[62] := Context.Bitlen shr 8; - Context.Data[61] := Context.Bitlen shr 16; - Context.Data[60] := Context.Bitlen shr 24; - Context.Data[59] := Context.Bitlen shr 32; - Context.Data[58] := Context.Bitlen shr 40; - Context.Data[57] := Context.Bitlen shr 48; - Context.Data[56] := Context.Bitlen shr 56; - SHA256Transform(Context, @(Context.Data[0])); - - for I := 0 to 3 do - begin - Digest[I] := (Context.State[0] shr (24 - I * 8)) and $000000FF; - Digest[I + 4] := (Context.State[1] shr (24 - I * 8)) and $000000FF; - Digest[I + 8] := (Context.State[2] shr (24 - I * 8)) and $000000FF; - Digest[I + 12] := (Context.State[3] shr (24 - I * 8)) and $000000FF; - Digest[I + 16] := (Context.State[4] shr (24 - I * 8)) and $000000FF; - Digest[I + 20] := (Context.State[5] shr (24 - I * 8)) and $000000FF; - Digest[I + 24] := (Context.State[6] shr (24 - I * 8)) and $000000FF; - Digest[I + 28] := (Context.State[7] shr (24 - I * 8)) and $000000FF; - end; -end; - -{$WARNINGS OFF} - -procedure SHA384Init(var Context: TCnSHA384Context); -begin - Context.DataLen := 0; - Context.TotalLen := 0; - Context.State[0] := $CBBB9D5DC1059ED8; - Context.State[1] := $629A292A367CD507; - Context.State[2] := $9159015A3070DD17; - Context.State[3] := $152FECD8F70E5939; - Context.State[4] := $67332667FFC00B31; - Context.State[5] := $8EB44A8768581511; - Context.State[6] := $DB0C2E0D64F98FA7; - Context.State[7] := $47B5481DBEFA4FA4; - FillChar(Context.Data, SizeOf(Context.Data), 0); -end; - -{$WARNINGS ON} - -procedure SHA384Update(var Context: TCnSHA384Context; Input: PAnsiChar; ByteLength: Cardinal); -begin - SHA512Update(Context, Input, ByteLength); -end; - -procedure SHA512UpdateW(var Context: TCnSHA512Context; Input: PWideChar; CharLength: Cardinal); forward; - -procedure SHA384UpdateW(var Context: TCnSHA384Context; Input: PWideChar; CharLength: Cardinal); -begin - SHA512UpdateW(Context, Input, CharLength); -end; - -procedure SHA384Final(var Context: TCnSHA384Context; var Digest: TCnSHA384Digest); -var - Dig: TCnSHA512Digest; -begin - SHA512Final(Context, Dig); - Move(Dig[0], Digest[0], SizeOf(TCnSHA384Digest)); -end; - -{$WARNINGS OFF} - -procedure SHA512Init(var Context: TCnSHA512Context); -begin - Context.DataLen := 0; - Context.TotalLen := 0; - Context.State[0] := $6A09E667F3BCC908; - Context.State[1] := $BB67AE8584CAA73B; - Context.State[2] := $3C6EF372FE94F82B; - Context.State[3] := $A54FF53A5F1D36F1; - Context.State[4] := $510E527FADE682D1; - Context.State[5] := $9B05688C2B3E6C1F; - Context.State[6] := $1F83D9ABFB41BD6B; - Context.State[7] := $5BE0CD19137E2179; - FillChar(Context.Data, SizeOf(Context.Data), 0); -end; - -{$WARNINGS ON} - -procedure SHA512Update(var Context: TCnSHA512Context; Input: PAnsiChar; ByteLength: Cardinal); -var - TempLength, RemainLength, NewLength, BlockCount: Cardinal; -begin - TempLength := 128 - Context.DataLen; - if ByteLength < TempLength then - RemainLength := ByteLength - else - RemainLength := TempLength; - - Move(Input^, Context.Data[Context.DataLen], RemainLength); - if Context.DataLen + ByteLength < 128 then - begin - Inc(Context.DataLen, ByteLength); - Exit; - end; - - NewLength := Cardinal(ByteLength) - RemainLength; - BlockCount := NewLength div 128; - Input := PAnsiChar(TCnNativeUInt(Input) + RemainLength); - - SHA512Transform(Context, @Context.Data[0], 1); - SHA512Transform(Context, Input, BlockCount); - - RemainLength := NewLength mod 128; - Input := PAnsiChar(TCnNativeUInt(Input) + (BlockCount shl 7)); - Move(Input^, Context.Data[Context.DataLen], RemainLength); - - Context.DataLen := RemainLength; - Inc(Context.TotalLen, (BlockCount + 1) shl 7); -end; - -procedure SHA512UpdateW(var Context: TCnSHA512Context; Input: PWideChar; CharLength: Cardinal); -var -{$IFDEF MSWINDOWS} - Content: PAnsiChar; - iLen: Cardinal; -{$ELSE} - S: string; // UnicodeString - A: AnsiString; -{$ENDIF} -begin -{$IFDEF MSWINDOWS} - GetMem(Content, CharLength * SizeOf(WideChar)); - try - iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 - PAnsiChar(Content), CharLength * SizeOf(WideChar), nil, nil); - SHA512Update(Context, Content, iLen); - finally - FreeMem(Content); - end; -{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ - S := StrNew(Input); - A := AnsiString(S); - SHA512Update(Context, @A[1], Length(A)); -{$ENDIF} -end; - -procedure SHA512Final(var Context: TCnSHA512Context; var Digest: TCnSHA512Digest); -var - I: Integer; - BlockCount, BitLength, PmLength: Cardinal; -begin - if (Context.DataLen mod 128) > 111 then - BlockCount := 2 - else - BlockCount := 1; - - BitLength := (Context.TotalLen + Context.DataLen) shl 3; - PmLength := BlockCount shl 7; - FillChar(Context.Data[Context.DataLen], PmLength - Context.DataLen, 0); - Context.Data[Context.DataLen] := $80; - - Context.Data[PmLength - 1] := Byte(BitLength); - Context.Data[PmLength - 2] := Byte(BitLength shr 8); - Context.Data[PmLength - 3] := Byte(BitLength shr 16); - Context.Data[PmLength - 4] := Byte(BitLength shr 24); - - SHA512Transform(Context, @(Context.Data[0]), BlockCount); - - for I := 0 to 7 do - begin - Digest[I] := (Context.State[0] shr (56 - I * 8)) and $000000FF; - Digest[I + 8] := (Context.State[1] shr (56 - I * 8)) and $000000FF; - Digest[I + 16] := (Context.State[2] shr (56 - I * 8)) and $000000FF; - Digest[I + 24] := (Context.State[3] shr (56 - I * 8)) and $000000FF; - Digest[I + 32] := (Context.State[4] shr (56 - I * 8)) and $000000FF; - Digest[I + 40] := (Context.State[5] shr (56 - I * 8)) and $000000FF; - Digest[I + 48] := (Context.State[6] shr (56 - I * 8)) and $000000FF; - Digest[I + 56] := (Context.State[7] shr (56 - I * 8)) and $000000FF; - end; -end; - -// ݿ SHA224 -function SHA224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA224Digest; -var - Context: TCnSHA224Context; -begin - SHA224Init(Context); - SHA224Update(Context, Input, ByteLength); - SHA224Final(Context, Result); -end; - -// ݿ SHA256 -function SHA256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA256Digest; -var - Context: TCnSHA256Context; -begin - SHA256Init(Context); - SHA256Update(Context, Input, ByteLength); - SHA256Final(Context, Result); -end; - -// ݿ SHA384 -function SHA384(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA384Digest; -var - Context: TCnSHA384Context; -begin - SHA384Init(Context); - SHA384Update(Context, Input, ByteLength); - SHA384Final(Context, Result); -end; - -// ݿ SHA512 -function SHA512(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA512Digest; -var - Context: TCnSHA512Context; -begin - SHA512Init(Context); - SHA512Update(Context, Input, ByteLength); - SHA512Final(Context, Result); -end; - -// ݿ SHA224 -function SHA224Buffer(const Buffer; Count: Cardinal): TCnSHA224Digest; -var - Context: TCnSHA224Context; -begin - SHA224Init(Context); - SHA224Update(Context, PAnsiChar(Buffer), Count); - SHA224Final(Context, Result); -end; - -// ݿ SHA256 -function SHA256Buffer(const Buffer; Count: Cardinal): TCnSHA256Digest; -var - Context: TCnSHA256Context; -begin - SHA256Init(Context); - SHA256Update(Context, PAnsiChar(Buffer), Count); - SHA256Final(Context, Result); -end; - -// ݿ SHA384 -function SHA384Buffer(const Buffer; Count: Cardinal): TCnSHA384Digest; -var - Context: TCnSHA384Context; -begin - SHA384Init(Context); - SHA384Update(Context, PAnsiChar(Buffer), Count); - SHA384Final(Context, Result); -end; - -// ݿ SHA512 -function SHA512Buffer(const Buffer; Count: Cardinal): TCnSHA512Digest; -var - Context: TCnSHA512Context; -begin - SHA512Init(Context); - SHA512Update(Context, PAnsiChar(Buffer), Count); - SHA512Final(Context, Result); -end; - -// ֽ SHA224 -function SHA224Bytes(Data: TBytes): TCnSHA224Digest; -var - Context: TCnSHA224Context; -begin - SHA224Init(Context); - SHA224Update(Context, PAnsiChar(@Data[0]), Length(Data)); - SHA224Final(Context, Result); -end; - -// ֽ SHA256 -function SHA256Bytes(Data: TBytes): TCnSHA256Digest; -var - Context: TCnSHA256Context; -begin - SHA256Init(Context); - SHA256Update(Context, PAnsiChar(@Data[0]), Length(Data)); - SHA256Final(Context, Result); -end; - -// ֽ SHA384 -function SHA384Bytes(Data: TBytes): TCnSHA384Digest; -var - Context: TCnSHA384Context; -begin - SHA384Init(Context); - SHA384Update(Context, PAnsiChar(@Data[0]), Length(Data)); - SHA384Final(Context, Result); -end; - -// ֽ SHA512 -function SHA512Bytes(Data: TBytes): TCnSHA512Digest; -var - Context: TCnSHA512Context; -begin - SHA512Init(Context); - SHA512Update(Context, PAnsiChar(@Data[0]), Length(Data)); - SHA512Final(Context, Result); -end; - -// String ݽ SHA224 -function SHA224String(const Str: string): TCnSHA224Digest; -var - AStr: AnsiString; -begin - AStr := AnsiString(Str); - Result := SHA224StringA(AStr); -end; - -// String ݽ SHA256 -function SHA256String(const Str: string): TCnSHA256Digest; -var - AStr: AnsiString; -begin - AStr := AnsiString(Str); - Result := SHA256StringA(AStr); -end; - -// String ݽ SHA384 -function SHA384String(const Str: string): TCnSHA384Digest; -var - AStr: AnsiString; -begin - AStr := AnsiString(Str); - Result := SHA384StringA(AStr); -end; - -// String ݽ SHA512 -function SHA512String(const Str: string): TCnSHA512Digest; -var - AStr: AnsiString; -begin - AStr := AnsiString(Str); - Result := SHA512StringA(AStr); -end; - -// UnicodeString ݽֱӵ SHA224 㣬ת -{$IFDEF UNICODE} -function SHA224UnicodeString(const Str: string): TCnSHA224Digest; -{$ELSE} -function SHA224UnicodeString(const Str: WideString): TCnSHA224Digest; -{$ENDIF} -var - Context: TCnSHA224Context; -begin - SHA224Init(Context); - SHA224Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); - SHA224Final(Context, Result); -end; - -// UnicodeString ݽֱӵ SHA256 㣬ת -{$IFDEF UNICODE} -function SHA256UnicodeString(const Str: string): TCnSHA256Digest; -{$ELSE} -function SHA256UnicodeString(const Str: WideString): TCnSHA256Digest; -{$ENDIF} -var - Context: TCnSHA256Context; -begin - SHA256Init(Context); - SHA256Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); - SHA256Final(Context, Result); -end; - -// UnicodeString ݽֱӵ SHA384 㣬ת -{$IFDEF UNICODE} -function SHA384UnicodeString(const Str: string): TCnSHA384Digest; -{$ELSE} -function SHA384UnicodeString(const Str: WideString): TCnSHA384Digest; -{$ENDIF} -var - Context: TCnSHA384Context; -begin - SHA384Init(Context); - SHA384Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); - SHA384Final(Context, Result); -end; - -// UnicodeString ݽֱӵ SHA512 㣬ת -{$IFDEF UNICODE} -function SHA512UnicodeString(const Str: string): TCnSHA512Digest; -{$ELSE} -function SHA512UnicodeString(const Str: WideString): TCnSHA512Digest; -{$ENDIF} -var - Context: TCnSHA512Context; -begin - SHA512Init(Context); - SHA512Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); - SHA512Final(Context, Result); -end; - -// AnsiString ݽ SHA224 -function SHA224StringA(const Str: AnsiString): TCnSHA224Digest; -var - Context: TCnSHA224Context; -begin - SHA224Init(Context); - SHA224Update(Context, PAnsiChar(Str), Length(Str)); - SHA224Final(Context, Result); -end; - -// WideString ݽ SHA224 -function SHA224StringW(const Str: WideString): TCnSHA224Digest; -var - Context: TCnSHA224Context; -begin - SHA224Init(Context); - SHA224UpdateW(Context, PWideChar(Str), Length(Str)); - SHA224Final(Context, Result); -end; - -// AnsiString ݽ SHA256 -function SHA256StringA(const Str: AnsiString): TCnSHA256Digest; -var - Context: TCnSHA256Context; -begin - SHA256Init(Context); - SHA256Update(Context, PAnsiChar(Str), Length(Str)); - SHA256Final(Context, Result); -end; - -// WideString ݽ SHA256 -function SHA256StringW(const Str: WideString): TCnSHA256Digest; -var - Context: TCnSHA256Context; -begin - SHA256Init(Context); - SHA256UpdateW(Context, PWideChar(Str), Length(Str)); - SHA256Final(Context, Result); -end; - -// AnsiString ݽ SHA384 -function SHA384StringA(const Str: AnsiString): TCnSHA384Digest; -var - Context: TCnSHA384Context; -begin - SHA384Init(Context); - SHA384Update(Context, PAnsiChar(Str), Length(Str)); - SHA384Final(Context, Result); -end; - -// WideString ݽ SHA384 -function SHA384StringW(const Str: WideString): TCnSHA384Digest; -var - Context: TCnSHA384Context; -begin - SHA384Init(Context); - SHA384UpdateW(Context, PWideChar(Str), Length(Str)); - SHA384Final(Context, Result); -end; - -// AnsiString ݽ SHA512 -function SHA512StringA(const Str: AnsiString): TCnSHA512Digest; -var - Context: TCnSHA512Context; -begin - SHA512Init(Context); - SHA512Update(Context, PAnsiChar(Str), Length(Str)); - SHA512Final(Context, Result); -end; - -// WideString ݽ SHA512 -function SHA512StringW(const Str: WideString): TCnSHA512Digest; -var - Context: TCnSHA512Context; -begin - SHA512Init(Context); - SHA512UpdateW(Context, PWideChar(Str), Length(Str)); - SHA512Final(Context, Result); -end; - -function InternalSHAStream(Stream: TStream; const BufSize: Cardinal; var D: - TCnSHAGeneralDigest; SHA2Type: TSHA2Type; CallBack: TCnSHACalcProgressFunc = nil): Boolean; -var - Buf: PAnsiChar; - BufLen: Cardinal; - Size: Int64; - ReadBytes: Cardinal; - TotalBytes: Int64; - SavePos: Int64; - CancelCalc: Boolean; - - Context224: TCnSHA224Context; - Context256: TCnSHA256Context; - Context384: TCnSHA384Context; - Context512: TCnSHA512Context; - Dig224: TCnSHA224Digest; - Dig256: TCnSHA256Digest; - Dig384: TCnSHA384Digest; - Dig512: TCnSHA512Digest; - - procedure _SHAInit; - begin - case SHA2Type of - stSHA2_224: - SHA224Init(Context224); - stSHA2_256: - SHA256Init(Context256); - stSHA2_384: - SHA384Init(Context384); - stSHA2_512: - SHA512Init(Context512); - end; - end; - - procedure _SHAUpdate; - begin - case SHA2Type of - stSHA2_224: - SHA224Update(Context224, Buf, ReadBytes); - stSHA2_256: - SHA256Update(Context256, Buf, ReadBytes); - stSHA2_384: - SHA384Update(Context384, Buf, ReadBytes); - stSHA2_512: - SHA512Update(Context512, Buf, ReadBytes); - end; - end; - - procedure _SHAFinal; - begin - case SHA2Type of - stSHA2_224: - SHA224Final(Context224, Dig224); - stSHA2_256: - SHA256Final(Context256, Dig256); - stSHA2_384: - SHA384Final(Context384, Dig384); - stSHA2_512: - SHA512Final(Context512, Dig512); - end; - end; - - procedure _CopyResult; - begin - case SHA2Type of - stSHA2_224: - Move(Dig224[0], D[0], SizeOf(TCnSHA224Digest)); - stSHA2_256: - Move(Dig256[0], D[0], SizeOf(TCnSHA256Digest)); - stSHA2_384: - Move(Dig384[0], D[0], SizeOf(TCnSHA384Digest)); - stSHA2_512: - Move(Dig512[0], D[0], SizeOf(TCnSHA512Digest)); - end; - end; - -begin - Result := False; - Size := Stream.Size; - SavePos := Stream.Position; - TotalBytes := 0; - if Size = 0 then - Exit; - if Size < BufSize then - BufLen := Size - else - BufLen := BufSize; - - CancelCalc := False; - _SHAInit; - - GetMem(Buf, BufLen); - try - Stream.Position := 0; - repeat - ReadBytes := Stream.Read(Buf^, BufLen); - if ReadBytes <> 0 then - begin - Inc(TotalBytes, ReadBytes); - _SHAUpdate; - - if Assigned(CallBack) then - begin - CallBack(Size, TotalBytes, CancelCalc); - if CancelCalc then - Exit; - end; - end; - until (ReadBytes = 0) or (TotalBytes = Size); - _SHAFinal; - _CopyResult; - Result := True; - finally - FreeMem(Buf, BufLen); - Stream.Position := SavePos; - end; -end; - -// ָ SHA224 -function SHA224Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): - TCnSHA224Digest; -var - Dig: TCnSHAGeneralDigest; -begin - InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_224, CallBack); - Move(Dig[0], Result[0], SizeOf(TCnSHA224Digest)); -end; - -// ָ SHA256 -function SHA256Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): - TCnSHA256Digest; -var - Dig: TCnSHAGeneralDigest; -begin - InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_256, CallBack); - Move(Dig[0], Result[0], SizeOf(TCnSHA256Digest)); -end; - -// ָ SHA384 -function SHA384Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): - TCnSHA384Digest; -var - Dig: TCnSHAGeneralDigest; -begin - InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_384, CallBack); - Move(Dig[0], Result[0], SizeOf(TCnSHA384Digest)); -end; - -// ָ SHA512 -function SHA512Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): - TCnSHA512Digest; -var - Dig: TCnSHAGeneralDigest; -begin - InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_512, CallBack); - Move(Dig[0], Result[0], SizeOf(TCnSHA512Digest)); -end; - -function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; -{$IFDEF MSWINDOWS} -var - H: THandle; - Info: BY_HANDLE_FILE_INFORMATION; - Rec: Int64Rec; -{$ENDIF} - begin -{$IFDEF MSWINDOWS} - Result := False; - IsEmpty := False; - H := CreateFile(PChar(AFileName), GENERIC_READ, FILE_SHARE_READ, nil, - OPEN_EXISTING, 0, 0); - if H = INVALID_HANDLE_VALUE then - Exit; - try - if not GetFileInformationByHandle(H, Info) then - Exit; - finally - CloseHandle(H); - end; - Rec.Lo := Info.nFileSizeLow; - Rec.Hi := Info.nFileSizeHigh; - Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); - IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); -{$ELSE} - Result := True; // Windows ƽ̨ Trueʾ Mapping -{$ENDIF} -end; - -function InternalSHAFile(const FileName: string; SHA2Type: TSHA2Type; - CallBack: TCnSHACalcProgressFunc): TCnSHAGeneralDigest; -var - Context224: TCnSHA224Context; - Context256: TCnSHA256Context; - Context384: TCnSHA384Context; - Context512: TCnSHA512Context; - Dig224: TCnSHA224Digest; - Dig256: TCnSHA256Digest; - Dig384: TCnSHA384Digest; - Dig512: TCnSHA512Digest; - -{$IFDEF MSWINDOWS} - FileHandle: THandle; - MapHandle: THandle; - ViewPointer: Pointer; -{$ENDIF} - Stream: TStream; - FileIsZeroSize: Boolean; - - procedure _SHAInit; - begin - case SHA2Type of - stSHA2_224: - SHA224Init(Context224); - stSHA2_256: - SHA256Init(Context256); - stSHA2_384: - SHA384Init(Context384); - stSHA2_512: - SHA512Init(Context512); - end; - end; - -{$IFDEF MSWINDOWS} - procedure _SHAUpdate; - begin - case SHA2Type of - stSHA2_224: - SHA224Update(Context224, ViewPointer, GetFileSize(FileHandle, nil)); - stSHA2_256: - SHA256Update(Context256, ViewPointer, GetFileSize(FileHandle, nil)); - stSHA2_384: - SHA384Update(Context384, ViewPointer, GetFileSize(FileHandle, nil)); - stSHA2_512: - SHA512Update(Context512, ViewPointer, GetFileSize(FileHandle, nil)); - end; - end; -{$ENDIF} - - procedure _SHAFinal; - begin - case SHA2Type of - stSHA2_224: - SHA224Final(Context224, Dig224); - stSHA2_256: - SHA256Final(Context256, Dig256); - stSHA2_384: - SHA384Final(Context384, Dig384); - stSHA2_512: - SHA512Final(Context512, Dig512); - end; - end; - - procedure _CopyResult(var D: TCnSHAGeneralDigest); - begin - case SHA2Type of - stSHA2_224: - Move(Dig224[0], D[0], SizeOf(TCnSHA224Digest)); - stSHA2_256: - Move(Dig256[0], D[0], SizeOf(TCnSHA256Digest)); - stSHA2_384: - Move(Dig384[0], D[0], SizeOf(TCnSHA384Digest)); - stSHA2_512: - Move(Dig512[0], D[0], SizeOf(TCnSHA512Digest)); - end; - end; - -begin - FileIsZeroSize := False; - if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then - begin - // 2G ļ Map ʧܣ Windows ƽ̨ʽѭ - Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); - try - InternalSHAStream(Stream, 4096 * 1024, Result, SHA2Type, CallBack); - finally - Stream.Free; - end; - end - else - begin -{$IFDEF MSWINDOWS} - _SHAInit; - FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or - FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or - FILE_FLAG_SEQUENTIAL_SCAN, 0); - if FileHandle <> INVALID_HANDLE_VALUE then - begin - try - MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); - if MapHandle <> 0 then - begin - try - ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); - if ViewPointer <> nil then - begin - try - _SHAUpdate; - finally - UnmapViewOfFile(ViewPointer); - end; - end - else - begin - raise Exception.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); - end; - finally - CloseHandle(MapHandle); - end; - end - else - begin - if not FileIsZeroSize then - raise Exception.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); - end; - finally - CloseHandle(FileHandle); - end; - end; - _SHAFinal; - _CopyResult(Result); -{$ENDIF} - end; -end; - -// ָļݽ SHA224 -function SHA224File(const FileName: string; CallBack: TCnSHACalcProgressFunc): - TCnSHA224Digest; -var - Dig: TCnSHAGeneralDigest; -begin - Dig := InternalSHAFile(FileName, stSHA2_224, CallBack); - Move(Dig[0], Result[0], SizeOf(TCnSHA224Digest)); -end; - -// ָļݽ SHA256 -function SHA256File(const FileName: string; CallBack: TCnSHACalcProgressFunc): - TCnSHA256Digest; -var - Dig: TCnSHAGeneralDigest; -begin - Dig := InternalSHAFile(FileName, stSHA2_256, CallBack); - Move(Dig[0], Result[0], SizeOf(TCnSHA256Digest)); -end; - -// ָļݽ SHA384 -function SHA384File(const FileName: string; CallBack: TCnSHACalcProgressFunc): - TCnSHA384Digest; -var - Dig: TCnSHAGeneralDigest; -begin - Dig := InternalSHAFile(FileName, stSHA2_384, CallBack); - Move(Dig[0], Result[0], SizeOf(TCnSHA384Digest)); -end; - -// ָļݽ SHA512 -function SHA512File(const FileName: string; CallBack: TCnSHACalcProgressFunc): - TCnSHA512Digest; -var - Dig: TCnSHAGeneralDigest; -begin - Dig := InternalSHAFile(FileName, stSHA2_512, CallBack); - Move(Dig[0], Result[0], SizeOf(TCnSHA512Digest)); -end; - -// ʮƸʽ SHA224 Ӵֵ -function SHA224Print(const Digest: TCnSHA224Digest): string; -begin - Result := DataToHex(@Digest[0], SizeOf(TCnSHA224Digest)); -end; - -// ʮƸʽ SHA256 Ӵֵ -function SHA256Print(const Digest: TCnSHA256Digest): string; -begin - Result := DataToHex(@Digest[0], SizeOf(TCnSHA256Digest)); -end; - -// ʮƸʽ SHA384 Ӵֵ -function SHA384Print(const Digest: TCnSHA384Digest): string; -begin - Result := DataToHex(@Digest[0], SizeOf(TCnSHA384Digest)); -end; - -// ʮƸʽ SHA512 Ӵֵ -function SHA512Print(const Digest: TCnSHA512Digest): string; -begin - Result := DataToHex(@Digest[0], SizeOf(TCnSHA512Digest)); -end; - -// Ƚ SHA224 ӴֵǷ -function SHA224Match(const D1, D2: TCnSHA224Digest): Boolean; -var - I: Integer; -begin - I := 0; - Result := True; - while Result and (I < 28) do - begin - Result := D1[I] = D2[I]; - Inc(I); - end; -end; - -// Ƚ SHA256 ӴֵǷ -function SHA256Match(const D1, D2: TCnSHA256Digest): Boolean; -var - I: Integer; -begin - I := 0; - Result := True; - while Result and (I < 32) do - begin - Result := D1[I] = D2[I]; - Inc(I); - end; -end; - -// Ƚ SHA384 ӴֵǷ -function SHA384Match(const D1, D2: TCnSHA384Digest): Boolean; -var - I: Integer; -begin - I := 0; - Result := True; - while Result and (I < 48) do - begin - Result := D1[I] = D2[I]; - Inc(I); - end; -end; - -// Ƚ SHA512 ӴֵǷ -function SHA512Match(const D1, D2: TCnSHA512Digest): Boolean; -var - I: Integer; -begin - I := 0; - Result := True; - while Result and (I < 64) do - begin - Result := D1[I] = D2[I]; - Inc(I); - end; -end; - -// SHA224 Ӵֵת string -function SHA224DigestToStr(const Digest: TCnSHA224Digest): string; -begin - Result := MemoryToString(@Digest[0], SizeOf(TCnSHA224Digest)); -end; - -// SHA256 Ӵֵת string -function SHA256DigestToStr(const Digest: TCnSHA256Digest): string; -begin - Result := MemoryToString(@Digest[0], SizeOf(TCnSHA256Digest)); -end; - -// SHA384 Ӵֵת string -function SHA384DigestToStr(const Digest: TCnSHA384Digest): string; -begin - Result := MemoryToString(@Digest[0], SizeOf(TCnSHA384Digest)); -end; - -// SHA512 Ӵֵת string -function SHA512DigestToStr(const Digest: TCnSHA512Digest): string; -begin - Result := MemoryToString(@Digest[0], SizeOf(TCnSHA512Digest)); -end; - -procedure SHA224HmacInit(var Context: TCnSHA224Context; Key: PAnsiChar; KeyLength: Integer); -var - I: Integer; - Sum: TCnSHA224Digest; -begin - if KeyLength > HMAC_SHA2_224_256_BLOCK_SIZE_BYTE then - begin - Sum := SHA224Buffer(Key, KeyLength); - KeyLength := HMAC_SHA2_224_OUTPUT_LENGTH_BYTE; - Key := @(Sum[0]); - end; - - FillChar(Context.Ipad, HMAC_SHA2_224_256_BLOCK_SIZE_BYTE, $36); - FillChar(Context.Opad, HMAC_SHA2_224_256_BLOCK_SIZE_BYTE, $5C); - - for I := 0 to KeyLength - 1 do - begin - Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); - Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); - end; - - SHA224Init(Context); - SHA224Update(Context, @(Context.Ipad[0]), HMAC_SHA2_224_256_BLOCK_SIZE_BYTE); -end; - -procedure SHA224HmacUpdate(var Context: TCnSHA224Context; Input: PAnsiChar; Length: - Cardinal); -begin - SHA224Update(Context, Input, Length); -end; - -procedure SHA224HmacFinal(var Context: TCnSHA224Context; var Output: TCnSHA224Digest); -var - Len: Integer; - TmpBuf: TCnSHA224Digest; -begin - Len := HMAC_SHA2_224_OUTPUT_LENGTH_BYTE; - SHA224Final(Context, TmpBuf); - SHA224Init(Context); - SHA224Update(Context, @(Context.Opad[0]), HMAC_SHA2_224_256_BLOCK_SIZE_BYTE); - SHA224Update(Context, @(TmpBuf[0]), Len); - SHA224Final(Context, Output); -end; - -procedure SHA256HmacInit(var Context: TCnSHA256Context; Key: PAnsiChar; KeyLength: Integer); -var - I: Integer; - Sum: TCnSHA256Digest; -begin - if KeyLength > HMAC_SHA2_224_256_BLOCK_SIZE_BYTE then - begin - Sum := SHA256Buffer(Key, KeyLength); - KeyLength := HMAC_SHA2_256_OUTPUT_LENGTH_BYTE; - Key := @(Sum[0]); - end; - - FillChar(Context.Ipad, HMAC_SHA2_224_256_BLOCK_SIZE_BYTE, $36); - FillChar(Context.Opad, HMAC_SHA2_224_256_BLOCK_SIZE_BYTE, $5C); - - for I := 0 to KeyLength - 1 do - begin - Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); - Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); - end; - - SHA256Init(Context); - SHA256Update(Context, @(Context.Ipad[0]), HMAC_SHA2_224_256_BLOCK_SIZE_BYTE); -end; - -procedure SHA256HmacUpdate(var Context: TCnSHA256Context; Input: PAnsiChar; Length: - Cardinal); -begin - SHA256Update(Context, Input, Length); -end; - -procedure SHA256HmacFinal(var Context: TCnSHA256Context; var Output: TCnSHA256Digest); -var - Len: Integer; - TmpBuf: TCnSHA256Digest; -begin - Len := HMAC_SHA2_256_OUTPUT_LENGTH_BYTE; - SHA256Final(Context, TmpBuf); - SHA256Init(Context); - SHA256Update(Context, @(Context.Opad[0]), HMAC_SHA2_224_256_BLOCK_SIZE_BYTE); - SHA256Update(Context, @(TmpBuf[0]), Len); - SHA256Final(Context, Output); -end; - -procedure SHA224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA224Digest); -var - Context: TCnSHA224Context; -begin - SHA224HmacInit(Context, Key, KeyByteLength); - SHA224HmacUpdate(Context, Input, ByteLength); - SHA224HmacFinal(Context, Output); -end; - -procedure SHA256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA256Digest); -var - Context: TCnSHA256Context; -begin - SHA256HmacInit(Context, Key, KeyByteLength); - SHA256HmacUpdate(Context, Input, ByteLength); - SHA256HmacFinal(Context, Output); -end; - -procedure SHA384HmacInit(var Context: TCnSHA384Context; Key: PAnsiChar; KeyLength: Integer); -var - I: Integer; - Sum: TCnSHA384Digest; -begin - if KeyLength > HMAC_SHA2_384_512_BLOCK_SIZE_BYTE then - begin - Sum := SHA384Buffer(Key, KeyLength); - KeyLength := HMAC_SHA2_384_OUTPUT_LENGTH_BYTE; - Key := @(Sum[0]); - end; - - FillChar(Context.Ipad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $36); - FillChar(Context.Opad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $5C); - - for I := 0 to KeyLength - 1 do - begin - Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); - Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); - end; - - SHA384Init(Context); - SHA384Update(Context, @(Context.Ipad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); -end; - -procedure SHA384HmacUpdate(var Context: TCnSHA384Context; Input: PAnsiChar; - Length: Cardinal); -begin - SHA384Update(Context, Input, Length); -end; - -procedure SHA384HmacFinal(var Context: TCnSHA384Context; var Output: TCnSHA384Digest); -var - Len: Integer; - TmpBuf: TCnSHA384Digest; -begin - Len := HMAC_SHA2_384_OUTPUT_LENGTH_BYTE; - SHA384Final(Context, TmpBuf); - SHA384Init(Context); - SHA384Update(Context, @(Context.Opad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); - SHA384Update(Context, @(TmpBuf[0]), Len); - SHA384Final(Context, Output); -end; - -procedure SHA384Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA384Digest); -var - Context: TCnSHA384Context; -begin - SHA384HmacInit(Context, Key, KeyByteLength); - SHA384HmacUpdate(Context, Input, ByteLength); - SHA384HmacFinal(Context, Output); -end; - -procedure SHA512HmacInit(var Context: TCnSHA512Context; Key: PAnsiChar; KeyLength: Integer); -var - I: Integer; - Sum: TCnSHA512Digest; -begin - if KeyLength > HMAC_SHA2_384_512_BLOCK_SIZE_BYTE then - begin - Sum := SHA512Buffer(Key, KeyLength); - KeyLength := HMAC_SHA2_512_OUTPUT_LENGTH_BYTE; - Key := @(Sum[0]); - end; - - FillChar(Context.Ipad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $36); - FillChar(Context.Opad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $5C); - - for I := 0 to KeyLength - 1 do - begin - Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); - Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); - end; - - SHA512Init(Context); - SHA512Update(Context, @(Context.Ipad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); -end; - -procedure SHA512HmacUpdate(var Context: TCnSHA512Context; Input: PAnsiChar; - Length: Cardinal); -begin - SHA512Update(Context, Input, Length); -end; - -procedure SHA512HmacFinal(var Context: TCnSHA512Context; var Output: TCnSHA512Digest); -var - Len: Integer; - TmpBuf: TCnSHA512Digest; -begin - Len := HMAC_SHA2_512_OUTPUT_LENGTH_BYTE; - SHA512Final(Context, TmpBuf); - SHA512Init(Context); - SHA512Update(Context, @(Context.Opad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); - SHA512Update(Context, @(TmpBuf[0]), Len); - SHA512Final(Context, Output); -end; - -procedure SHA512Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA512Digest); -var - Context: TCnSHA512Context; -begin - SHA512HmacInit(Context, Key, KeyByteLength); - SHA512HmacUpdate(Context, Input, ByteLength); - SHA512HmacFinal(Context, Output); -end; - -end. +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnSHA2; +{* |
+================================================================================
+* ƣ
+* ԪƣSHA2 Ӵ㷨ʵֵԪ
+* ԪߣCnPack  (master@cnpack.org)
+*           / C  Pascal ֲ䲿ֹܡ
+*     עԪʵ SHA2 ϵӴ㷨Ӧ HMAC 㷨
+*            SHA224/256/384/512/512-224/512-256
+* ƽ̨PWinXP + Delphi 5.0
+* ݲԣPWinXP/7 + Delphi 5/6
+*   õԪеַϱػʽ
+* ޸ļ¼2025.11.20 V1.5
+*               ʵ SHA512-224  SHA512-256 㷨
+*           2022.04.26 V1.4
+*               ޸ LongWord  Integer ַת֧ MacOS64
+*           2019.04.15 V1.3
+*               ֧ Win32/Win64/MacOS32
+*           2017.10.31 V1.2
+*                SHA512/384 HMAC 
+*           2016.09.30 V1.1
+*               ʵ SHA512/384D567з Int64 ޷ UInt64
+*           2016.09.27 V1.0
+*               Ԫ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes {$IFDEF MSWINDOWS}, Windows {$ENDIF}, CnNative, CnConsts; + +type + PCnSHA2GeneralDigest = ^TCnSHA2GeneralDigest; + {* SHA2 ϵͨõӴսָ} + TCnSHA2GeneralDigest = array[0..63] of Byte; + {* SHA2 ϵͨõӴս 64 ֽΪ׼} + + PCnSHA224Digest = ^TCnSHA224Digest; + {* SHA224 Ӵսָ} + TCnSHA224Digest = array[0..27] of Byte; + {* SHA224 Ӵս28 ֽ} + + PCnSHA256Digest = ^TCnSHA256Digest; + {* SHA256 Ӵսָ} + TCnSHA256Digest = array[0..31] of Byte; + {* SHA256 Ӵս32 ֽ} + + PCnSHA384Digest = ^TCnSHA384Digest; + {* SHA384 Ӵսָ} + TCnSHA384Digest = array[0..47] of Byte; + {* SHA384 Ӵս48 ֽ} + + PCnSHA512Digest = ^TCnSHA512Digest; + {* SHA512 Ӵսָ} + TCnSHA512Digest = array[0..63] of Byte; + {* SHA512 Ӵս64 ֽ} + + PCnSHA512_224Digest = ^TCnSHA512_224Digest; + {* SHA512_224 Ӵսָ} + TCnSHA512_224Digest = array[0..27] of Byte; + {* SHA512_224 Ӵս28 ֽ} + + PCnSHA512_256Digest = ^TCnSHA512_256Digest; + {* SHA512_256 Ӵսָ} + TCnSHA512_256Digest = array[0..31] of Byte; + {* SHA512_256 Ӵս32 ֽ} + + TCnSHA256Context = packed record + {* SHA256 Ľṹ} + DataLen: Cardinal; + Data: array[0..63] of Byte; + BitLen: Int64; + State: array[0..7] of Cardinal; + Ipad: array[0..63] of Byte; {!< HMAC: inner padding } + Opad: array[0..63] of Byte; {!< HMAC: outer padding } + end; + + TCnSHA224Context = TCnSHA256Context; + {* SHA224 Ľṹ} + + TCnSHA512Context = packed record + {* SHA512 Ľṹ} + DataLen: Cardinal; + Data: array[0..255] of Byte; // Final ʱ + TotalLen: Int64; + State: array[0..7] of Int64; + Ipad: array[0..127] of Byte; {!< HMAC: inner padding } + Opad: array[0..127] of Byte; {!< HMAC: outer padding } + end; + + TCnSHA384Context = TCnSHA512Context; + {* SHA512 Ľṹ} + + TCnSHA512_224Context = TCnSHA512Context; + {* SHA512_224 Ľṹ} + + TCnSHA512_256Context = TCnSHA512Context; + {* SHA512_256 Ľṹ} + + TCnSHACalcProgressFunc = procedure(ATotal, AProgress: Int64; var Cancel: + Boolean) of object; + {* SHA2 ϵӴսȻص¼} + +function SHA224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA224Digest; +{* ݿ SHA224 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA256Digest; +{* ݿ SHA256 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA384Digest; +{* ݿ SHA384 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA512Digest; +{* ݿ SHA512 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA512_224Digest; +{* ݿ SHA512_224 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA512_256Digest; +{* ݿ SHA512_256 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +function SHA224Buffer(const Buffer; Count: Cardinal): TCnSHA224Digest; +{* ݿ SHA224 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256Buffer(const Buffer; Count: Cardinal): TCnSHA256Digest; +{* ݿ SHA256 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384Buffer(const Buffer; Count: Cardinal): TCnSHA384Digest; +{* ݿ SHA384 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512Buffer(const Buffer; Count: Cardinal): TCnSHA512Digest; +{* ݿ SHA512 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224Buffer(const Buffer; Count: Cardinal): TCnSHA512_224Digest; +{* ݿ SHA512_224 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256Buffer(const Buffer; Count: Cardinal): TCnSHA512_256Digest; +{* ݿ SHA512_256 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +function SHA224Bytes(const Data: TBytes): TCnSHA224Digest; +{* ֽ SHA224 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256Bytes(const Data: TBytes): TCnSHA256Digest; +{* ֽ SHA256 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384Bytes(const Data: TBytes): TCnSHA384Digest; +{* ֽ SHA384 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512Bytes(const Data: TBytes): TCnSHA512Digest; +{* ֽ SHA512 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224Bytes(const Data: TBytes): TCnSHA512_224Digest; +{* ֽ SHA512_224 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256Bytes(const Data: TBytes): TCnSHA512_256Digest; +{* ֽ SHA512_256 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +function SHA224String(const Str: string): TCnSHA224Digest; +{* String ݽ SHA224 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256String(const Str: string): TCnSHA256Digest; +{* String ݽ SHA256 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384String(const Str: string): TCnSHA384Digest; +{* String ݽ SHA384 㣬ע D2009ϰ汾string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512String(const Str: string): TCnSHA512Digest; +{* String ݽ SHA512 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224String(const Str: string): TCnSHA512_224Digest; +{* String ݽ SHA512_224 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256String(const Str: string): TCnSHA512_256Digest; +{* String ݽ SHA512_256 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +function SHA224StringA(const Str: AnsiString): TCnSHA224Digest; +{* AnsiString ݽ SHA224 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA224StringW(const Str: WideString): TCnSHA224Digest; +{* WideString ݽ SHA224 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256StringA(const Str: AnsiString): TCnSHA256Digest; +{* AnsiString ݽ SHA256 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA256StringW(const Str: WideString): TCnSHA256Digest; +{* WideString ݽ SHA256 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384StringA(const Str: AnsiString): TCnSHA384Digest; +{* AnsiString ݽ SHA384 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA384StringW(const Str: WideString): TCnSHA384Digest; +{* WideString ݽ SHA384 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512StringA(const Str: AnsiString): TCnSHA512Digest; +{* AnsiString ݽ SHA512 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512StringW(const Str: WideString): TCnSHA512Digest; +{* WideString ݽ SHA512 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224StringA(const Str: AnsiString): TCnSHA512_224Digest; +{* AnsiString ݽ SHA512_224 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_224StringW(const Str: WideString): TCnSHA512_224Digest; +{* WideString ݽ SHA512_224 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256StringA(const Str: AnsiString): TCnSHA512_256Digest; +{* AnsiString ݽ SHA512_256 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +function SHA512_256StringW(const Str: WideString): TCnSHA512_256Digest; +{* WideString ݽ SHA512_256 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +{$IFDEF UNICODE} + +function SHA224UnicodeString(const Str: string): TCnSHA224Digest; +{* UnicodeString ݽֱӵ SHA224 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256UnicodeString(const Str: string): TCnSHA256Digest; +{* UnicodeString ݽֱӵ SHA256 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384UnicodeString(const Str: string): TCnSHA384Digest; +{* UnicodeString ݽֱӵ SHA384 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512UnicodeString(const Str: string): TCnSHA512Digest; +{* UnicodeString ݽֱӵ SHA512 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224UnicodeString(const Str: string): TCnSHA512_224Digest; +{* UnicodeString ݽֱӵ SHA512_224 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256UnicodeString(const Str: string): TCnSHA512_256Digest; +{* UnicodeString ݽֱӵ SHA512_256 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +{$ELSE} + +function SHA224UnicodeString(const Str: WideString): TCnSHA224Digest; +{* UnicodeString ݽֱӵ SHA224 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256UnicodeString(const Str: WideString): TCnSHA256Digest; +{* UnicodeString ݽֱӵ SHA256 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384UnicodeString(const Str: WideString): TCnSHA384Digest; +{* UnicodeString ݽֱӵ SHA384 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512UnicodeString(const Str: WideString): TCnSHA512Digest; +{* UnicodeString ݽֱӵ SHA512 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224UnicodeString(const Str: WideString): TCnSHA512_224Digest; +{* UnicodeString ݽֱӵ SHA512_224 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256UnicodeString(const Str: WideString): TCnSHA512_256Digest; +{* UnicodeString ݽֱӵ SHA512_256 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +{$ENDIF} + +function SHA224File(const FileName: string; CallBack: TCnSHACalcProgressFunc = + nil): TCnSHA224Digest; +{* ָļݽ SHA224 㡣 + + + const FileName: string - ļ + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA224Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA224Digest; +{* ָݽ SHA224 㡣 + + + Stream: TStream - + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256File(const FileName: string; CallBack: TCnSHACalcProgressFunc = + nil): TCnSHA256Digest; +{* ָļݽ SHA256 㡣 + + + const FileName: string - ļ + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA256Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA256Digest; +{* ָݽ SHA256 㡣 + + + Stream: TStream - + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384File(const FileName: string; CallBack: TCnSHACalcProgressFunc = + nil): TCnSHA384Digest; +{* ָļݽ SHA384 㡣 + + + const FileName: string - ļ + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA384Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA384Digest; +{* ָݽ SHA384 㡣 + + + Stream: TStream - + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512File(const FileName: string; CallBack: TCnSHACalcProgressFunc = + nil): TCnSHA512Digest; +{* ָļݽ SHA512 㡣 + + + const FileName: string - ļ + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA512Digest; +{* ָݽ SHA512 㡣 + + + Stream: TStream - + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224File(const FileName: string; CallBack: TCnSHACalcProgressFunc = + nil): TCnSHA512_224Digest; +{* ָļݽ SHA512_224 㡣 + + + const FileName: string - ļ + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_224Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA512_224Digest; +{* ָݽ SHA512_224 㡣 + + + Stream: TStream - + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256File(const FileName: string; CallBack: TCnSHACalcProgressFunc = + nil): TCnSHA512_256Digest; +{* ָļݽ SHA512_256 㡣 + + + const FileName: string - ļ + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +function SHA512_256Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA512_256Digest; +{* ָݽ SHA512_256 㡣 + + + Stream: TStream - + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +// ⲿݽɢ SHA224 㣬SHA224Update ɶα + +procedure SHA224Init(var Context: TCnSHA224Context); +{* ʼһ SHA224 ģ׼ SHA224 + + + var Context: TCnSHA224Context - ʼ SHA224 + + ֵޣ +} + +procedure SHA224Update(var Context: TCnSHA224Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA224 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA224Context - SHA224 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA224Final(var Context: TCnSHA224Context; var Digest: TCnSHA224Digest); +{* ּ㣬 SHA224 Digest С + + + var Context: TCnSHA224Context - SHA224 + var Digest: TCnSHA224Digest - ص SHA224 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA256 㣬SHA256Update ɶα + +procedure SHA256Init(var Context: TCnSHA256Context); +{* ʼһ SHA256 ģ׼ SHA256 + + + var Context: TCnSHA256Context - ʼ SHA256 + + ֵޣ +} + +procedure SHA256Update(var Context: TCnSHA256Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA256 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA256Context - SHA256 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA256Final(var Context: TCnSHA256Context; var Digest: TCnSHA256Digest); +{* ּ㣬 SHA256 Digest С + + + var Context: TCnSHA256Context - SHA256 + var Digest: TCnSHA256Digest - ص SHA256 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA384 㣬SHA384Update ɶα + +procedure SHA384Init(var Context: TCnSHA384Context); +{* ʼһ SHA384 ģ׼ SHA384 + + + var Context: TCnSHA384Context - ʼ SHA384 + + ֵޣ +} + +procedure SHA384Update(var Context: TCnSHA384Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA384 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA384Context - SHA384 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA384Final(var Context: TCnSHA384Context; var Digest: TCnSHA384Digest); +{* ּ㣬 SHA384 Digest С + + + var Context: TCnSHA384Context - SHA384 + var Digest: TCnSHA384Digest - ص SHA384 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA512 㣬SHA512Update ɶα + +procedure SHA512Init(var Context: TCnSHA512Context); +{* ʼһ SHA512 ģ׼ SHA512 + + + var Context: TCnSHA512Context - ʼ SHA512 + + ֵޣ +} + +procedure SHA512Update(var Context: TCnSHA512Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA512 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA512Context - SHA512 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA512Final(var Context: TCnSHA512Context; var Digest: TCnSHA512Digest); +{* ּ㣬 SHA512 Digest С + + + var Context: TCnSHA512Context - SHA512 + var Digest: TCnSHA512Digest - ص SHA512 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA512_224 㣬SHA512_224Update ɶα + +procedure SHA512_224Init(var Context: TCnSHA512_224Context); +{* ʼһ SHA512_224 ģ׼ SHA512_224 + + + var Context: TCnSHA512_224Context - ʼ SHA512_224 + + ֵޣ +} + +procedure SHA512_224Update(var Context: TCnSHA512_224Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA512_224 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA512_224Context - SHA512_224 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA512_224Final(var Context: TCnSHA512_224Context; var Digest: TCnSHA512_224Digest); +{* ּ㣬 SHA512_224 Digest С + + + var Context: TCnSHA512_224Context - SHA512_224 + var Digest: TCnSHA512_224Digest - ص SHA512_224 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA512_256 㣬SHA512_256Update ɶα + +procedure SHA512_256Init(var Context: TCnSHA512_256Context); +{* ʼһ SHA512_256 ģ׼ SHA512_256 + + + var Context: TCnSHA512_256Context - ʼ SHA512_256 + + ֵޣ +} + +procedure SHA512_256Update(var Context: TCnSHA512_256Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA512_256 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA512_256Context - SHA512_256 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA512_256Final(var Context: TCnSHA512_256Context; var Digest: TCnSHA512_256Digest); +{* ּ㣬 SHA512_256 Digest С + + + var Context: TCnSHA512_256Context - SHA512_256 + var Digest: TCnSHA512_256Digest - ص SHA512_256 Ӵֵ + + ֵޣ +} + +function SHA224Print(const Digest: TCnSHA224Digest): string; +{* ʮƸʽ SHA224 Ӵֵ + + + const Digest: TCnSHA224Digest - ָ SHA224 Ӵֵ + + ֵstring - ʮַ +} + +function SHA256Print(const Digest: TCnSHA256Digest): string; +{* ʮƸʽ SHA256 Ӵֵ + + + const Digest: TCnSHA256Digest - ָ SHA256 Ӵֵ + + ֵstring - ʮַ +} + +function SHA384Print(const Digest: TCnSHA384Digest): string; +{* ʮƸʽ SHA384 Ӵֵ + + + const Digest: TCnSHA384Digest - ָ SHA384 Ӵֵ + + ֵstring - ʮַ +} + +function SHA512Print(const Digest: TCnSHA512Digest): string; +{* ʮƸʽ SHA512 Ӵֵ + + + const Digest: TCnSHA512Digest - ָ SHA512 Ӵֵ + + ֵstring - ʮַ +} + +function SHA512_224Print(const Digest: TCnSHA512_224Digest): string; +{* ʮƸʽ SHA512_224 Ӵֵ + + + const Digest: TCnSHA512_224Digest - ָ SHA512_224 Ӵֵ + + ֵstring - ʮַ +} + +function SHA512_256Print(const Digest: TCnSHA512_256Digest): string; +{* ʮƸʽ SHA512_256 Ӵֵ + + + const Digest: TCnSHA512_256Digest - ָ SHA512_256 Ӵֵ + + ֵstring - ʮַ +} + +function SHA224Match(const D1: TCnSHA224Digest; const D2: TCnSHA224Digest): Boolean; +{* Ƚ SHA224 ӴֵǷȡ + + + const D1: TCnSHA224Digest - Ƚϵ SHA224 Ӵֵһ + const D2: TCnSHA224Digest - Ƚϵ SHA224 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA256Match(const D1: TCnSHA256Digest; const D2: TCnSHA256Digest): Boolean; +{* Ƚ SHA256 ӴֵǷȡ + + + const D1: TCnSHA256Digest - Ƚϵ SHA256 Ӵֵһ + const D2: TCnSHA256Digest - Ƚϵ SHA256 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA384Match(const D1: TCnSHA384Digest; const D2: TCnSHA384Digest): Boolean; +{* Ƚ SHA384 ӴֵǷȡ + + + const D1: TCnSHA384Digest - Ƚϵ SHA384 Ӵֵһ + const D2: TCnSHA384Digest - Ƚϵ SHA384 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA512Match(const D1: TCnSHA512Digest; const D2: TCnSHA512Digest): Boolean; +{* Ƚ SHA512 ӴֵǷȡ + + + const D1: TCnSHA512Digest - Ƚϵ SHA512 Ӵֵһ + const D2: TCnSHA512Digest - Ƚϵ SHA512 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA512_224Match(const D1: TCnSHA512_224Digest; const D2: TCnSHA512_224Digest): Boolean; +{* Ƚ SHA512_224 ӴֵǷȡ + + + const D1: TCnSHA512_224Digest - Ƚϵ SHA512_224 Ӵֵһ + const D2: TCnSHA512_224Digest - Ƚϵ SHA512_224 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA512_256Match(const D1: TCnSHA512_256Digest; const D2: TCnSHA512_256Digest): Boolean; +{* Ƚ SHA512_256 ӴֵǷȡ + + + const D1: TCnSHA512_256Digest - Ƚϵ SHA512_256 Ӵֵһ + const D2: TCnSHA512_256Digest - Ƚϵ SHA512_256 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA224DigestToStr(const Digest: TCnSHA224Digest): string; +{* SHA224 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA224Digest - ת SHA224 Ӵֵ + + ֵstring - صַ +} + +function SHA256DigestToStr(const Digest: TCnSHA256Digest): string; +{* SHA256 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA256Digest - ת SHA256 Ӵֵ + + ֵstring - صַ +} + +function SHA384DigestToStr(const Digest: TCnSHA384Digest): string; +{* SHA384 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA384Digest - ת SHA384 Ӵֵ + + ֵstring - صַ +} + +function SHA512DigestToStr(const Digest: TCnSHA512Digest): string; +{* SHA512 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA512Digest - ת SHA512 Ӵֵ + + ֵstring - صַ +} + +function SHA512_224DigestToStr(const Digest: TCnSHA512_224Digest): string; +{* SHA512_224 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA512_224Digest - ת SHA512_224 Ӵֵ + + ֵstring - صַ +} + +function SHA512_256DigestToStr(const Digest: TCnSHA512_256Digest): string; +{* SHA512_256 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA512_256Digest - ת SHA512_256 Ӵֵ + + ֵstring - صַ +} + +procedure SHA224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA224Digest); +{* SHA224 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA224 Կݿַ + KeyByteLength: Integer - SHA224 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA224Digest - ص SHA224 Ӵֵ + + ֵޣ +} + +procedure SHA256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA256Digest); +{* SHA256 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA256 Կݿַ + KeyByteLength: Integer - SHA256 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA256Digest - ص SHA256 Ӵֵ + + ֵޣ +} + +procedure SHA384Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA384Digest); +{* SHA384 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA384 Կݿַ + KeyByteLength: Integer - SHA384 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA384Digest - ص SHA384 Ӵֵ + + ֵޣ +} + +procedure SHA512Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA512Digest); +{* SHA512 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA512 Կݿַ + KeyByteLength: Integer - SHA512 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA512Digest - ص SHA512 Ӵֵ + + ֵޣ +} + +procedure SHA512_224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA512_224Digest); +{* SHA512_224 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA512_224 Կݿַ + KeyByteLength: Integer - SHA512_224 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA512_224Digest - ص SHA512_224 Ӵֵ + + ֵޣ +} + +procedure SHA512_256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA512_256Digest); +{* SHA512_256 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA512_256 Կݿַ + KeyByteLength: Integer - SHA512_256 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA512_256Digest - ص SHA512_256 Ӵֵ + + ֵޣ +} + +function SHA224HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA224Digest; +{* ֽл SHA224 HMAC 㡣 + + + const Key: TBytes - SHA224 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA256Digest; +{* ֽл SHA256 HMAC 㡣 + + + const Key: TBytes - SHA256 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA384Digest; +{* ֽл SHA384 HMAC 㡣 + + + const Key: TBytes - SHA384 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA384Digest - ص SHA384 Ӵֵ +} + +function SHA512HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA512Digest; +{* ֽл SHA512 HMAC 㡣 + + + const Key: TBytes - SHA512 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA512_224Digest; +{* ֽл SHA512_224 HMAC 㡣 + + + const Key: TBytes - SHA512_224 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA512_256Digest; +{* ֽл SHA512_256 HMAC 㡣 + + + const Key: TBytes - SHA512_256 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +implementation + +const + HMAC_SHA2_224_256_BLOCK_SIZE_BYTE = 64; + HMAC_SHA2_384_512_BLOCK_SIZE_BYTE = 128; + + HMAC_SHA2_224_OUTPUT_LENGTH_BYTE = 28; + HMAC_SHA2_256_OUTPUT_LENGTH_BYTE = 32; + HMAC_SHA2_384_OUTPUT_LENGTH_BYTE = 48; + HMAC_SHA2_512_OUTPUT_LENGTH_BYTE = 64; + + HMAC_SHA2_512_224_OUTPUT_LENGTH_BYTE = 28; + HMAC_SHA2_512_256_OUTPUT_LENGTH_BYTE = 32; + +type + TSHA2Type = (stSHA2_224, stSHA2_256, stSHA2_384, stSHA2_512, stSHA2_512_224, stSHA2_512_256); + +const + MAX_FILE_SIZE = 512 * 1024 * 1024; + // If file size <= this size (bytes), using Mapping, else stream + + KEYS256: array[0..63] of Cardinal = ($428A2F98, $71374491, $B5C0FBCF, $E9B5DBA5, + $3956C25B, $59F111F1, $923F82A4, $AB1C5ED5, $D807AA98, $12835B01, $243185BE, + $550C7DC3, $72BE5D74, $80DEB1FE, $9BDC06A7, $C19BF174, $E49B69C1, $EFBE4786, + $0FC19DC6, $240CA1CC, $2DE92C6F, $4A7484AA, $5CB0A9DC, $76F988DA, $983E5152, + $A831C66D, $B00327C8, $BF597FC7, $C6E00BF3, $D5A79147, $06CA6351, $14292967, + $27B70A85, $2E1B2138, $4D2C6DFC, $53380D13, $650A7354, $766A0ABB, $81C2C92E, + $92722C85, $A2BFE8A1, $A81A664B, $C24B8B70, $C76C51A3, $D192E819, $D6990624, + $F40E3585, $106AA070, $19A4C116, $1E376C08, $2748774C, $34B0BCB5, $391C0CB3, + $4ED8AA4A, $5B9CCA4F, $682E6FF3, $748F82EE, $78A5636F, $84C87814, $8CC70208, + $90BEFFFA, $A4506CEB, $BEF9A3F7, $C67178F2); + + KEYS512: array[0..79] of TUInt64 = ($428A2F98D728AE22, $7137449123EF65CD, + $B5C0FBCFEC4D3B2F, $E9B5DBA58189DBBC, $3956C25BF348B538, $59F111F1B605D019, + $923F82A4AF194F9B, $AB1C5ED5DA6D8118, $D807AA98A3030242, $12835B0145706FBE, + $243185BE4EE4B28C, $550C7DC3D5FFB4E2, $72BE5D74F27B896F, $80DEB1FE3B1696B1, + $9BDC06A725C71235, $C19BF174CF692694, $E49B69C19EF14AD2, $EFBE4786384F25E3, + $0FC19DC68B8CD5B5, $240CA1CC77AC9C65, $2DE92C6F592B0275, $4A7484AA6EA6E483, + $5CB0A9DCBD41FBD4, $76F988DA831153B5, $983E5152EE66DFAB, $A831C66D2DB43210, + $B00327C898FB213F, $BF597FC7BEEF0EE4, $C6E00BF33DA88FC2, $D5A79147930AA725, + $06CA6351E003826F, $142929670A0E6E70, $27B70A8546D22FFC, $2E1B21385C26C926, + $4D2C6DFC5AC42AED, $53380D139D95B3DF, $650A73548BAF63DE, $766A0ABB3C77B2A8, + $81C2C92E47EDAEE6, $92722C851482353B, $A2BFE8A14CF10364, $A81A664BBC423001, + $C24B8B70D0F89791, $C76C51A30654BE30, $D192E819D6EF5218, $D69906245565A910, + $F40E35855771202A, $106AA07032BBD1B8, $19A4C116B8D2D0C8, $1E376C085141AB53, + $2748774CDF8EEB99, $34B0BCB5E19B48A8, $391C0CB3C5C95A63, $4ED8AA4AE3418ACB, + $5B9CCA4F7763E373, $682E6FF3D6B2B8A3, $748F82EE5DEFB2FC, $78A5636F43172F60, + $84C87814A1F0AB72, $8CC702081A6439EC, $90BEFFFA23631E28, $A4506CEBDE82BDE9, + $BEF9A3F7B2C67915, $C67178F2E372532B, $CA273ECEEA26619C, $D186B8C721C0C207, + $EADA7DD6CDE0EB1E, $F57D4F7FEE6ED178, $06F067AA72176FBA, $0A637DC5A2C898A6, + $113F9804BEF90DAE, $1B710B35131C471B, $28DB77F523047D84, $32CAAB7B40C72493, + $3C9EBE0A15C9BEBC, $431D67C49C100D4C, $4CC5D4BECB3E42B6, $597F299CFC657E2A, + $5FCB6FAB3AD6FAEC, $6C44198C4A475817); + +function ROTRight256(A, B: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (A shr B) or (A shl (32 - B)); +end; + +function ROTRight512(X: TUInt64; Y: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X shr Y) or (X shl (64 - Y)); +end; + +function SHR512(X: TUInt64; Y: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and $FFFFFFFFFFFFFFFF) shr Y; +end; + +function CH256(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Y) xor ((not X) and Z); +end; + +function CH512(X, Y, Z: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (((Y xor Z) and X) xor Z); +end; + +function MAJ256(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Y) xor (X and Z) xor (Y and Z); +end; + +function MAJ512(X, Y, Z: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ((X or Y) and Z) or (X and Y); +end; + +function EP0256(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight256(X, 2) xor ROTRight256(X, 13) xor ROTRight256(X, 22); +end; + +function EP1256(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight256(X, 6) xor ROTRight256(X, 11) xor ROTRight256(X, 25); +end; + +function SIG0256(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight256(X, 7) xor ROTRight256(X, 18) xor (X shr 3); +end; + +function SIG1256(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight256(X, 17) xor ROTRight256(X, 19) xor (X shr 10); +end; + +function SIG0512(X: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight512(X, 28) xor ROTRight512(X, 34) xor ROTRight512(X, 39); +end; + +function SIG1512(X: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight512(X, 14) xor ROTRight512(X, 18) xor ROTRight512(X, 41); +end; + +function Gamma0512(X: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight512(X, 1) xor ROTRight512(X, 8) xor SHR512(X, 7); +end; + +function Gamma1512(X: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight512(X, 19) xor ROTRight512(X, 61) xor SHR512(X, 6); +end; + +procedure SHA256Transform(var Context: TCnSHA256Context; Data: PAnsiChar); +var + A, B, C, D, E, F, G, H, T1, T2: Cardinal; + M: array[0..63] of Cardinal; + I, J: Integer; +begin + I := 0; + J := 0; + while I < 16 do + begin + M[I] := (Cardinal(Data[J]) shl 24) or (Cardinal(Data[J + 1]) shl 16) or (Cardinal(Data + [J + 2]) shl 8) or Cardinal(Data[J + 3]); + Inc(I); + Inc(J, 4); + end; + + while I < 64 do + begin + M[I] := SIG1256(M[I - 2]) + M[I - 7] + SIG0256(M[I - 15]) + M[I - 16]; + Inc(I); + end; + + A := Context.State[0]; + B := Context.State[1]; + C := Context.State[2]; + D := Context.State[3]; + E := Context.State[4]; + F := Context.State[5]; + G := Context.State[6]; + H := Context.State[7]; + + I := 0; + while I < 64 do + begin + T1 := H + EP1256(E) + CH256(E, F, G) + KEYS256[I] + M[I]; + T2 := EP0256(A) + MAJ256(A, B, C); + H := G; + G := F; + F := E; + E := D + T1; + D := C; + C := B; + B := A; + A := T1 + T2; + Inc(I); + end; + + Context.State[0] := Context.State[0] + A; + Context.State[1] := Context.State[1] + B; + Context.State[2] := Context.State[2] + C; + Context.State[3] := Context.State[3] + D; + Context.State[4] := Context.State[4] + E; + Context.State[5] := Context.State[5] + F; + Context.State[6] := Context.State[6] + G; + Context.State[7] := Context.State[7] + H; +end; + +{$WARNINGS OFF} + +procedure SHA512Transform(var Context: TCnSHA512Context; Data: PAnsiChar; BlockCount: Integer); +var + A, B, C, D, E, F, G, H, T1, T2: TUInt64; + M: array[0..79] of TUInt64; + I, J, K: Integer; + OrigData: PAnsiChar; +begin + OrigData := Data; + for K := 0 to BlockCount - 1 do + begin + Data := PAnsiChar(TCnNativeInt(OrigData) + (K shl 7)); + + I := 0; + J := 0; + while I < 16 do + begin + // ע Delphi 5 6 7 ´˴ Int64 ƣ Range Check شʱ + // ΪȻһÿرصܵõȷ + M[I] := (TUInt64(Data[J]) shl 56) or (TUInt64(Data[J + 1]) shl 48) or + (TUInt64(Data[J + 2]) shl 40) or (TUInt64(Data[J + 3]) shl 32) or + (TUInt64(Data[J + 4]) shl 24) or (TUInt64(Data[J + 5]) shl 16) or + (TUInt64(Data[J + 6]) shl 8) or TUInt64(Data[J + 7]); + Inc(I); + Inc(J, 8); + end; + + while I < 80 do + begin + M[I] := Gamma1512(M[I - 2]) + M[I - 7] + Gamma0512(M[I - 15]) + M[I - 16]; + Inc(I); + end; + + A := Context.State[0]; + B := Context.State[1]; + C := Context.State[2]; + D := Context.State[3]; + E := Context.State[4]; + F := Context.State[5]; + G := Context.State[6]; + H := Context.State[7]; + + I := 0; + while I < 80 do + begin + T1 := H + SIG1512(E) + CH512(E, F, G) + KEYS512[I] + M[I]; + T2 := SIG0512(A) + MAJ512(A, B, C); + H := G; + G := F; + F := E; + E := D + T1; + D := C; + C := B; + B := A; + A := T1 + T2; + Inc(I); + end; + + // з޷ WarningӰ + Context.State[0] := Context.State[0] + A; + Context.State[1] := Context.State[1] + B; + Context.State[2] := Context.State[2] + C; + Context.State[3] := Context.State[3] + D; + Context.State[4] := Context.State[4] + E; + Context.State[5] := Context.State[5] + F; + Context.State[6] := Context.State[6] + G; + Context.State[7] := Context.State[7] + H; + end; +end; + +{$WARNINGS ON} + +procedure SHA224Init(var Context: TCnSHA224Context); +begin + Context.DataLen := 0; + Context.BitLen := 0; + Context.State[0] := $C1059ED8; + Context.State[1] := $367CD507; + Context.State[2] := $3070DD17; + Context.State[3] := $F70E5939; + Context.State[4] := $FFC00B31; + Context.State[5] := $68581511; + Context.State[6] := $64F98FA7; + Context.State[7] := $BEFA4FA4; + FillChar(Context.Data, SizeOf(Context.Data), 0); +end; + +procedure SHA224Update(var Context: TCnSHA224Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA256Update(Context, Input, ByteLength); +end; + +procedure SHA256UpdateW(var Context: TCnSHA256Context; Input: PWideChar; CharLength: Cardinal); forward; + +procedure SHA224UpdateW(var Context: TCnSHA224Context; Input: PWideChar; CharLength: Cardinal); +begin + SHA256UpdateW(Context, Input, CharLength); +end; + +procedure SHA224Final(var Context: TCnSHA224Context; var Digest: TCnSHA224Digest); +var + Dig: TCnSHA256Digest; +begin + SHA256Final(Context, Dig); + Move(Dig[0], Digest[0], SizeOf(TCnSHA224Digest)); +end; + +procedure SHA256Init(var Context: TCnSHA256Context); +begin + Context.DataLen := 0; + Context.BitLen := 0; + Context.State[0] := $6A09E667; + Context.State[1] := $BB67AE85; + Context.State[2] := $3C6EF372; + Context.State[3] := $A54FF53A; + Context.State[4] := $510E527F; + Context.State[5] := $9B05688C; + Context.State[6] := $1F83D9AB; + Context.State[7] := $5BE0CD19; + FillChar(Context.Data, SizeOf(Context.Data), 0); +end; + +procedure SHA256Update(var Context: TCnSHA256Context; Input: PAnsiChar; ByteLength: Cardinal); +var + B: Cardinal; +begin + while ByteLength > 0 do + begin + if 64 - Context.DataLen > ByteLength then + B := ByteLength + else + B := 64 - Context.DataLen; + + Move(Input^, Context.Data[Context.DataLen], B); + Inc(Context.DataLen, B); + Dec(ByteLength, B); + Inc(Input, B); + + if Context.DataLen = 64 then + begin + SHA256Transform(Context, @Context.Data[0]); + Context.BitLen := Context.BitLen + 512; + Context.DataLen := 0; + end; + end; +end; + +procedure SHA256UpdateW(var Context: TCnSHA256Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + Content: PAnsiChar; + iLen: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(Content, CharLength * SizeOf(WideChar)); + try + iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(Content), CharLength * SizeOf(WideChar), nil, nil); + SHA256Update(Context, Content, iLen); + finally + FreeMem(Content); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + SHA256Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +procedure SHA256Final(var Context: TCnSHA256Context; var Digest: TCnSHA256Digest); +var + I: Integer; +begin + I := Context.DataLen; + Context.Data[I] := $80; + Inc(I); + + if Context.Datalen < 56 then + begin + while I < 56 do + begin + Context.Data[I] := 0; + Inc(I); + end; + end + else + begin + while I < 64 do + begin + Context.Data[I] := 0; + Inc(I); + end; + + SHA256Transform(Context, @(Context.Data[0])); + FillChar(Context.Data, 56, 0); + end; + + Context.BitLen := Context.BitLen + Context.DataLen * 8; + Context.Data[63] := Byte(Context.Bitlen); + Context.Data[62] := Byte(Context.Bitlen shr 8); + Context.Data[61] := Byte(Context.Bitlen shr 16); + Context.Data[60] := Byte(Context.Bitlen shr 24); + Context.Data[59] := Byte(Context.Bitlen shr 32); + Context.Data[58] := Byte(Context.Bitlen shr 40); + Context.Data[57] := Byte(Context.Bitlen shr 48); + Context.Data[56] := Byte(Context.Bitlen shr 56); + SHA256Transform(Context, @(Context.Data[0])); + + for I := 0 to 3 do + begin + Digest[I] := (Context.State[0] shr (24 - I * 8)) and $000000FF; + Digest[I + 4] := (Context.State[1] shr (24 - I * 8)) and $000000FF; + Digest[I + 8] := (Context.State[2] shr (24 - I * 8)) and $000000FF; + Digest[I + 12] := (Context.State[3] shr (24 - I * 8)) and $000000FF; + Digest[I + 16] := (Context.State[4] shr (24 - I * 8)) and $000000FF; + Digest[I + 20] := (Context.State[5] shr (24 - I * 8)) and $000000FF; + Digest[I + 24] := (Context.State[6] shr (24 - I * 8)) and $000000FF; + Digest[I + 28] := (Context.State[7] shr (24 - I * 8)) and $000000FF; + end; +end; + +{$WARNINGS OFF} + +procedure SHA384Init(var Context: TCnSHA384Context); +begin + Context.DataLen := 0; + Context.TotalLen := 0; + Context.State[0] := $CBBB9D5DC1059ED8; + Context.State[1] := $629A292A367CD507; + Context.State[2] := $9159015A3070DD17; + Context.State[3] := $152FECD8F70E5939; + Context.State[4] := $67332667FFC00B31; + Context.State[5] := $8EB44A8768581511; + Context.State[6] := $DB0C2E0D64F98FA7; + Context.State[7] := $47B5481DBEFA4FA4; + FillChar(Context.Data, SizeOf(Context.Data), 0); +end; + +{$WARNINGS ON} + +procedure SHA384Update(var Context: TCnSHA384Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA512Update(Context, Input, ByteLength); +end; + +procedure SHA512UpdateW(var Context: TCnSHA512Context; Input: PWideChar; CharLength: Cardinal); forward; + +procedure SHA384UpdateW(var Context: TCnSHA384Context; Input: PWideChar; CharLength: Cardinal); +begin + SHA512UpdateW(Context, Input, CharLength); +end; + +procedure SHA384Final(var Context: TCnSHA384Context; var Digest: TCnSHA384Digest); +var + Dig: TCnSHA512Digest; +begin + SHA512Final(Context, Dig); + Move(Dig[0], Digest[0], SizeOf(TCnSHA384Digest)); +end; + +{$WARNINGS OFF} + +procedure SHA512Init(var Context: TCnSHA512Context); +begin + Context.DataLen := 0; + Context.TotalLen := 0; + Context.State[0] := $6A09E667F3BCC908; + Context.State[1] := $BB67AE8584CAA73B; + Context.State[2] := $3C6EF372FE94F82B; + Context.State[3] := $A54FF53A5F1D36F1; + Context.State[4] := $510E527FADE682D1; + Context.State[5] := $9B05688C2B3E6C1F; + Context.State[6] := $1F83D9ABFB41BD6B; + Context.State[7] := $5BE0CD19137E2179; + FillChar(Context.Data, SizeOf(Context.Data), 0); +end; + +{$WARNINGS ON} + +procedure SHA512Update(var Context: TCnSHA512Context; Input: PAnsiChar; ByteLength: Cardinal); +var + TempLength, RemainLength, NewLength, BlockCount: Cardinal; +begin + TempLength := 128 - Context.DataLen; + if ByteLength < TempLength then + RemainLength := ByteLength + else + RemainLength := TempLength; + + Move(Input^, Context.Data[Context.DataLen], RemainLength); + if Context.DataLen + ByteLength < 128 then + begin + Inc(Context.DataLen, ByteLength); + Exit; + end; + + NewLength := Cardinal(ByteLength) - RemainLength; + BlockCount := NewLength div 128; + Input := PAnsiChar(TCnNativeUInt(Input) + RemainLength); + + SHA512Transform(Context, @Context.Data[0], 1); + SHA512Transform(Context, Input, BlockCount); + + RemainLength := NewLength mod 128; + Input := PAnsiChar(TCnNativeUInt(Input) + (BlockCount shl 7)); + Move(Input^, Context.Data[Context.DataLen], RemainLength); + + Context.DataLen := RemainLength; + Inc(Context.TotalLen, (BlockCount + 1) shl 7); +end; + +procedure SHA512UpdateW(var Context: TCnSHA512Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + Content: PAnsiChar; + iLen: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(Content, CharLength * SizeOf(WideChar)); + try + iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(Content), CharLength * SizeOf(WideChar), nil, nil); + SHA512Update(Context, Content, iLen); + finally + FreeMem(Content); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + SHA512Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +procedure SHA512Final(var Context: TCnSHA512Context; var Digest: TCnSHA512Digest); +var + I: Integer; + BlockCount, PmLength: Cardinal; + BitLength: TUInt64; +begin + if (Context.DataLen mod 128) > 111 then + BlockCount := 2 + else + BlockCount := 1; + + BitLength := (Context.TotalLen + Context.DataLen) shl 3; + PmLength := BlockCount shl 7; + FillChar(Context.Data[Context.DataLen], PmLength - Context.DataLen, 0); + Context.Data[Context.DataLen] := $80; + + Context.Data[PmLength - 1] := Byte(BitLength); + Context.Data[PmLength - 2] := Byte(BitLength shr 8); + Context.Data[PmLength - 3] := Byte(BitLength shr 16); + Context.Data[PmLength - 4] := Byte(BitLength shr 24); + Context.Data[PmLength - 5] := Byte(BitLength shr 32); + Context.Data[PmLength - 6] := Byte(BitLength shr 40); + Context.Data[PmLength - 7] := Byte(BitLength shr 48); + Context.Data[PmLength - 8] := Byte(BitLength shr 56); + + // ٴΰ淶е 128 λȸֵΪ FillChar 0 + SHA512Transform(Context, @(Context.Data[0]), BlockCount); + + for I := 0 to 7 do + begin + Digest[I] := (Context.State[0] shr (56 - I * 8)) and $000000FF; + Digest[I + 8] := (Context.State[1] shr (56 - I * 8)) and $000000FF; + Digest[I + 16] := (Context.State[2] shr (56 - I * 8)) and $000000FF; + Digest[I + 24] := (Context.State[3] shr (56 - I * 8)) and $000000FF; + Digest[I + 32] := (Context.State[4] shr (56 - I * 8)) and $000000FF; + Digest[I + 40] := (Context.State[5] shr (56 - I * 8)) and $000000FF; + Digest[I + 48] := (Context.State[6] shr (56 - I * 8)) and $000000FF; + Digest[I + 56] := (Context.State[7] shr (56 - I * 8)) and $000000FF; + end; +end; + +procedure SHA512_224Init(var Context: TCnSHA512_224Context); +begin + Context.DataLen := 0; + Context.TotalLen := 0; + Context.State[0] := Int64($8C3D37C819544DA2); + Context.State[1] := Int64($73E1996689DCD4D6); + Context.State[2] := Int64($1DFAB7AE32FF9C82); + Context.State[3] := Int64($679DD514582F9FCF); + Context.State[4] := Int64($0F6D2B697BD44DA8); + Context.State[5] := Int64($77E36F7304C48942); + Context.State[6] := Int64($3F9D85A86A1D36C8); + Context.State[7] := Int64($1112E6AD91D692A1); + FillChar(Context.Data, SizeOf(Context.Data), 0); +end; + +procedure SHA512_224Update(var Context: TCnSHA512_224Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA512Update(Context, Input, ByteLength); +end; + +procedure SHA512_224UpdateW(var Context: TCnSHA512_224Context; Input: PWideChar; CharLength: Cardinal); +begin + SHA512UpdateW(Context, Input, CharLength); +end; + +procedure SHA512_224Final(var Context: TCnSHA512_224Context; var Digest: TCnSHA512_224Digest); +var + Dig: TCnSHA512Digest; +begin + SHA512Final(Context, Dig); + Move(Dig[0], Digest[0], SizeOf(TCnSHA512_224Digest)); +end; + +procedure SHA512_256Init(var Context: TCnSHA512_256Context); +begin + Context.DataLen := 0; + Context.TotalLen := 0; + Context.State[0] := Int64($22312194FC2BF72C); + Context.State[1] := Int64($9F555FA3C84C64C2); + Context.State[2] := Int64($2393B86B6F53B151); + Context.State[3] := Int64($963877195940EABD); + Context.State[4] := Int64($96283EE2A88EFFE3); + Context.State[5] := Int64($BE5E1E2553863992); + Context.State[6] := Int64($2B0199FC2C85B8AA); + Context.State[7] := Int64($0EB72DDC81C52CA2); + FillChar(Context.Data, SizeOf(Context.Data), 0); +end; + +procedure SHA512_256Update(var Context: TCnSHA512_256Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA512Update(Context, Input, ByteLength); +end; + +procedure SHA512_256UpdateW(var Context: TCnSHA512_256Context; Input: PWideChar; CharLength: Cardinal); +begin + SHA512UpdateW(Context, Input, CharLength); +end; + +procedure SHA512_256Final(var Context: TCnSHA512_256Context; var Digest: TCnSHA512_256Digest); +var + Dig: TCnSHA512Digest; +begin + SHA512Final(Context, Dig); + Move(Dig[0], Digest[0], SizeOf(TCnSHA512_256Digest)); +end; + +// ݿ SHA224 +function SHA224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224Update(Context, Input, ByteLength); + SHA224Final(Context, Result); +end; + +// ݿ SHA256 +function SHA256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256Update(Context, Input, ByteLength); + SHA256Final(Context, Result); +end; + +// ݿ SHA384 +function SHA384(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384Update(Context, Input, ByteLength); + SHA384Final(Context, Result); +end; + +// ݿ SHA512 +function SHA512(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512Update(Context, Input, ByteLength); + SHA512Final(Context, Result); +end; + +// ݿ SHA512_224 +function SHA512_224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA512_224Digest; +var + Context: TCnSHA512_224Context; +begin + SHA512_224Init(Context); + SHA512_224Update(Context, Input, ByteLength); + SHA512_224Final(Context, Result); +end; + +// ݿ SHA512_256 +function SHA512_256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA512_256Digest; +var + Context: TCnSHA512_256Context; +begin + SHA512_256Init(Context); + SHA512_256Update(Context, Input, ByteLength); + SHA512_256Final(Context, Result); +end; + +// ݿ SHA224 +function SHA224Buffer(const Buffer; Count: Cardinal): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224Update(Context, PAnsiChar(@Buffer), Count); + SHA224Final(Context, Result); +end; + +// ݿ SHA256 +function SHA256Buffer(const Buffer; Count: Cardinal): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256Update(Context, PAnsiChar(@Buffer), Count); + SHA256Final(Context, Result); +end; + +// ݿ SHA384 +function SHA384Buffer(const Buffer; Count: Cardinal): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384Update(Context, PAnsiChar(@Buffer), Count); + SHA384Final(Context, Result); +end; + +// ݿ SHA512 +function SHA512Buffer(const Buffer; Count: Cardinal): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512Update(Context, PAnsiChar(@Buffer), Count); + SHA512Final(Context, Result); +end; + +// ݿ SHA512_224 +function SHA512_224Buffer(const Buffer; Count: Cardinal): TCnSHA512_224Digest; +var + Context: TCnSHA512_224Context; +begin + SHA512_224Init(Context); + SHA512_224Update(Context, PAnsiChar(@Buffer), Count); + SHA512_224Final(Context, Result); +end; + +// ݿ SHA512_256 +function SHA512_256Buffer(const Buffer; Count: Cardinal): TCnSHA512_256Digest; +var + Context: TCnSHA512_256Context; +begin + SHA512_256Init(Context); + SHA512_256Update(Context, PAnsiChar(@Buffer), Count); + SHA512_256Final(Context, Result); +end; + +// ֽ SHA224 +function SHA224Bytes(const Data: TBytes): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA224Final(Context, Result); +end; + +// ֽ SHA256 +function SHA256Bytes(const Data: TBytes): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA256Final(Context, Result); +end; + +// ֽ SHA384 +function SHA384Bytes(const Data: TBytes): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA384Final(Context, Result); +end; + +// ֽ SHA512 +function SHA512Bytes(const Data: TBytes): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA512Final(Context, Result); +end; + +// ֽ SHA512_224 +function SHA512_224Bytes(const Data: TBytes): TCnSHA512_224Digest; +var + Context: TCnSHA512_224Context; +begin + SHA512_224Init(Context); + SHA512_224Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA512_224Final(Context, Result); +end; + +// ֽ SHA512_256 +function SHA512_256Bytes(const Data: TBytes): TCnSHA512_256Digest; +var + Context: TCnSHA512_256Context; +begin + SHA512_256Init(Context); + SHA512_256Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA512_256Final(Context, Result); +end; + +// String ݽ SHA224 +function SHA224String(const Str: string): TCnSHA224Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA224StringA(AStr); +end; + +// String ݽ SHA256 +function SHA256String(const Str: string): TCnSHA256Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA256StringA(AStr); +end; + +// String ݽ SHA384 +function SHA384String(const Str: string): TCnSHA384Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA384StringA(AStr); +end; + +// String ݽ SHA512 +function SHA512String(const Str: string): TCnSHA512Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA512StringA(AStr); +end; + +// String ݽ SHA512_224 +function SHA512_224String(const Str: string): TCnSHA512_224Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA512_224StringA(AStr); +end; + +// String ݽ SHA512_256 +function SHA512_256String(const Str: string): TCnSHA512_256Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA512_256StringA(AStr); +end; + +// UnicodeString ݽֱӵ SHA224 㣬ת +{$IFDEF UNICODE} +function SHA224UnicodeString(const Str: string): TCnSHA224Digest; +{$ELSE} +function SHA224UnicodeString(const Str: WideString): TCnSHA224Digest; +{$ENDIF} +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA224Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SHA256 㣬ת +{$IFDEF UNICODE} +function SHA256UnicodeString(const Str: string): TCnSHA256Digest; +{$ELSE} +function SHA256UnicodeString(const Str: WideString): TCnSHA256Digest; +{$ENDIF} +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA256Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SHA384 㣬ת +{$IFDEF UNICODE} +function SHA384UnicodeString(const Str: string): TCnSHA384Digest; +{$ELSE} +function SHA384UnicodeString(const Str: WideString): TCnSHA384Digest; +{$ENDIF} +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA384Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SHA512 㣬ת +{$IFDEF UNICODE} +function SHA512UnicodeString(const Str: string): TCnSHA512Digest; +{$ELSE} +function SHA512UnicodeString(const Str: WideString): TCnSHA512Digest; +{$ENDIF} +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA512Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SHA512_224 㣬ת +{$IFDEF UNICODE} +function SHA512_224UnicodeString(const Str: string): TCnSHA512_224Digest; +{$ELSE} +function SHA512_224UnicodeString(const Str: WideString): TCnSHA512_224Digest; +{$ENDIF} +var + Context: TCnSHA512_224Context; +begin + SHA512_224Init(Context); + SHA512_224Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA512_224Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SHA512_256 㣬ת +{$IFDEF UNICODE} +function SHA512_256UnicodeString(const Str: string): TCnSHA512_256Digest; +{$ELSE} +function SHA512_256UnicodeString(const Str: WideString): TCnSHA512_256Digest; +{$ENDIF} +var + Context: TCnSHA512_256Context; +begin + SHA512_256Init(Context); + SHA512_256Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA512_256Final(Context, Result); +end; + +// AnsiString ݽ SHA224 +function SHA224StringA(const Str: AnsiString): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224Update(Context, PAnsiChar(Str), Length(Str)); + SHA224Final(Context, Result); +end; + +// WideString ݽ SHA224 +function SHA224StringW(const Str: WideString): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224UpdateW(Context, PWideChar(Str), Length(Str)); + SHA224Final(Context, Result); +end; + +// AnsiString ݽ SHA256 +function SHA256StringA(const Str: AnsiString): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256Update(Context, PAnsiChar(Str), Length(Str)); + SHA256Final(Context, Result); +end; + +// WideString ݽ SHA256 +function SHA256StringW(const Str: WideString): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256UpdateW(Context, PWideChar(Str), Length(Str)); + SHA256Final(Context, Result); +end; + +// AnsiString ݽ SHA384 +function SHA384StringA(const Str: AnsiString): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384Update(Context, PAnsiChar(Str), Length(Str)); + SHA384Final(Context, Result); +end; + +// WideString ݽ SHA384 +function SHA384StringW(const Str: WideString): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384UpdateW(Context, PWideChar(Str), Length(Str)); + SHA384Final(Context, Result); +end; + +// AnsiString ݽ SHA512 +function SHA512StringA(const Str: AnsiString): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512Update(Context, PAnsiChar(Str), Length(Str)); + SHA512Final(Context, Result); +end; + +// WideString ݽ SHA512 +function SHA512StringW(const Str: WideString): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512UpdateW(Context, PWideChar(Str), Length(Str)); + SHA512Final(Context, Result); +end; + +// AnsiString ݽ SHA512_224 +function SHA512_224StringA(const Str: AnsiString): TCnSHA512_224Digest; +var + Context: TCnSHA512_224Context; +begin + SHA512_224Init(Context); + SHA512_224Update(Context, PAnsiChar(Str), Length(Str)); + SHA512_224Final(Context, Result); +end; + +// WideString ݽ SHA512_224 +function SHA512_224StringW(const Str: WideString): TCnSHA512_224Digest; +var + Context: TCnSHA512_224Context; +begin + SHA512_224Init(Context); + SHA512_224UpdateW(Context, PWideChar(Str), Length(Str)); + SHA512_224Final(Context, Result); +end; + +// AnsiString ݽ SHA512_256 +function SHA512_256StringA(const Str: AnsiString): TCnSHA512_256Digest; +var + Context: TCnSHA512_256Context; +begin + SHA512_256Init(Context); + SHA512_256Update(Context, PAnsiChar(Str), Length(Str)); + SHA512_256Final(Context, Result); +end; + +// WideString ݽ SHA512_256 +function SHA512_256StringW(const Str: WideString): TCnSHA512_256Digest; +var + Context: TCnSHA512_256Context; +begin + SHA512_256Init(Context); + SHA512_256UpdateW(Context, PWideChar(Str), Length(Str)); + SHA512_256Final(Context, Result); +end; + +function InternalSHAStream(Stream: TStream; const BufSize: Cardinal; var D: + TCnSHA2GeneralDigest; SHA2Type: TSHA2Type; CallBack: TCnSHACalcProgressFunc): Boolean; +var + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; + + Context224: TCnSHA224Context; + Context256: TCnSHA256Context; + Context384: TCnSHA384Context; + Context512: TCnSHA512Context; + Context512_224: TCnSHA512_224Context; + Context512_256: TCnSHA512_256Context; + Dig224: TCnSHA224Digest; + Dig256: TCnSHA256Digest; + Dig384: TCnSHA384Digest; + Dig512: TCnSHA512Digest; + Dig512_224: TCnSHA512_224Digest; + Dig512_256: TCnSHA512_256Digest; + + procedure _SHAInit; + begin + case SHA2Type of + stSHA2_224: + SHA224Init(Context224); + stSHA2_256: + SHA256Init(Context256); + stSHA2_384: + SHA384Init(Context384); + stSHA2_512: + SHA512Init(Context512); + stSHA2_512_224: + SHA512_224Init(Context512_224); + stSHA2_512_256: + SHA512_256Init(Context512_256); + end; + end; + + procedure _SHAUpdate; + begin + case SHA2Type of + stSHA2_224: + SHA224Update(Context224, Buf, ReadBytes); + stSHA2_256: + SHA256Update(Context256, Buf, ReadBytes); + stSHA2_384: + SHA384Update(Context384, Buf, ReadBytes); + stSHA2_512: + SHA512Update(Context512, Buf, ReadBytes); + stSHA2_512_224: + SHA512_224Update(Context512_224, Buf, ReadBytes); + stSHA2_512_256: + SHA512_256Update(Context512_256, Buf, ReadBytes); + end; + end; + + procedure _SHAFinal; + begin + case SHA2Type of + stSHA2_224: + SHA224Final(Context224, Dig224); + stSHA2_256: + SHA256Final(Context256, Dig256); + stSHA2_384: + SHA384Final(Context384, Dig384); + stSHA2_512: + SHA512Final(Context512, Dig512); + stSHA2_512_224: + SHA512_224Final(Context512_224, Dig512_224); + stSHA2_512_256: + SHA512_256Final(Context512_256, Dig512_256); + end; + end; + + procedure _CopyResult; + begin + case SHA2Type of + stSHA2_224: + Move(Dig224[0], D[0], SizeOf(TCnSHA224Digest)); + stSHA2_256: + Move(Dig256[0], D[0], SizeOf(TCnSHA256Digest)); + stSHA2_384: + Move(Dig384[0], D[0], SizeOf(TCnSHA384Digest)); + stSHA2_512: + Move(Dig512[0], D[0], SizeOf(TCnSHA512Digest)); + stSHA2_512_224: + Move(Dig512_224[0], D[0], SizeOf(TCnSHA512_224Digest)); + stSHA2_512_256: + Move(Dig512_256[0], D[0], SizeOf(TCnSHA512_256Digest)); + end; + end; + +begin + Result := False; + Size := Stream.Size; + SavePos := Stream.Position; + TotalBytes := 0; + if Size = 0 then + Exit; + if Size < BufSize then + BufLen := Size + else + BufLen := BufSize; + + CancelCalc := False; + _SHAInit; + + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + _SHAUpdate; + + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then + Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + _SHAFinal; + _CopyResult; + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +// ָ SHA224 +function SHA224Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc): + TCnSHA224Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_224, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA224Digest)); +end; + +// ָ SHA256 +function SHA256Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc): + TCnSHA256Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_256, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA256Digest)); +end; + +// ָ SHA384 +function SHA384Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc): + TCnSHA384Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_384, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA384Digest)); +end; + +// ָ SHA512 +function SHA512Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc): + TCnSHA512Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_512, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA512Digest)); +end; + +// ָ SHA512_224 +function SHA512_224Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc): + TCnSHA512_224Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_512_224, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA512_224Digest)); +end; + +// ָ SHA512_256 +function SHA512_256Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc): + TCnSHA512_256Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_512_256, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA512_256Digest)); +end; + +function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; +{$IFDEF MSWINDOWS} +var + H: THandle; + Info: BY_HANDLE_FILE_INFORMATION; + Rec: Int64Rec; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + Result := False; + IsEmpty := False; + H := CreateFile(PChar(AFileName), GENERIC_READ, FILE_SHARE_READ, nil, + OPEN_EXISTING, 0, 0); + if H = INVALID_HANDLE_VALUE then + Exit; + try + if not GetFileInformationByHandle(H, Info) then + Exit; + finally + CloseHandle(H); + end; + Rec.Lo := Info.nFileSizeLow; + Rec.Hi := Info.nFileSizeHigh; + Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); + IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); +{$ELSE} + Result := True; // Windows ƽ̨ Trueʾ Mapping +{$ENDIF} +end; + +function InternalSHAFile(const FileName: string; SHA2Type: TSHA2Type; + CallBack: TCnSHACalcProgressFunc): TCnSHA2GeneralDigest; +var + Context224: TCnSHA224Context; + Context256: TCnSHA256Context; + Context384: TCnSHA384Context; + Context512: TCnSHA512Context; + Context512_224: TCnSHA512_224Context; + Context512_256: TCnSHA512_256Context; + Dig224: TCnSHA224Digest; + Dig256: TCnSHA256Digest; + Dig384: TCnSHA384Digest; + Dig512: TCnSHA512Digest; + Dig512_224: TCnSHA512_224Digest; + Dig512_256: TCnSHA512_256Digest; + +{$IFDEF MSWINDOWS} + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; + + procedure _SHAInit; + begin + case SHA2Type of + stSHA2_224: + SHA224Init(Context224); + stSHA2_256: + SHA256Init(Context256); + stSHA2_384: + SHA384Init(Context384); + stSHA2_512: + SHA512Init(Context512); + stSHA2_512_224: + SHA512_224Init(Context512_224); + stSHA2_512_256: + SHA512_256Init(Context512_256); + end; + end; + +{$IFDEF MSWINDOWS} + procedure _SHAUpdate; + begin + case SHA2Type of + stSHA2_224: + SHA224Update(Context224, ViewPointer, GetFileSize(FileHandle, nil)); + stSHA2_256: + SHA256Update(Context256, ViewPointer, GetFileSize(FileHandle, nil)); + stSHA2_384: + SHA384Update(Context384, ViewPointer, GetFileSize(FileHandle, nil)); + stSHA2_512: + SHA512Update(Context512, ViewPointer, GetFileSize(FileHandle, nil)); + stSHA2_512_224: + SHA512_224Update(Context512_224, ViewPointer, GetFileSize(FileHandle, nil)); + stSHA2_512_256: + SHA512_256Update(Context512_256, ViewPointer, GetFileSize(FileHandle, nil)); + end; + end; +{$ENDIF} + + procedure _SHAFinal; + begin + case SHA2Type of + stSHA2_224: + SHA224Final(Context224, Dig224); + stSHA2_256: + SHA256Final(Context256, Dig256); + stSHA2_384: + SHA384Final(Context384, Dig384); + stSHA2_512: + SHA512Final(Context512, Dig512); + stSHA2_512_224: + SHA512_224Final(Context512_224, Dig512_224); + stSHA2_512_256: + SHA512_256Final(Context512_256, Dig512_256); + end; + end; + + procedure _CopyResult(var D: TCnSHA2GeneralDigest); + begin + case SHA2Type of + stSHA2_224: + Move(Dig224[0], D[0], SizeOf(TCnSHA224Digest)); + stSHA2_256: + Move(Dig256[0], D[0], SizeOf(TCnSHA256Digest)); + stSHA2_384: + Move(Dig384[0], D[0], SizeOf(TCnSHA384Digest)); + stSHA2_512: + Move(Dig512[0], D[0], SizeOf(TCnSHA512Digest)); + stSHA2_512_224: + Move(Dig512_224[0], D[0], SizeOf(TCnSHA512_224Digest)); + stSHA2_512_256: + Move(Dig512_256[0], D[0], SizeOf(TCnSHA512_256Digest)); + end; + end; + +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣ Windows ƽ̨ʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalSHAStream(Stream, 4096 * 1024, Result, SHA2Type, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + _SHAInit; + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + _SHAUpdate; + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise ECnNativeException.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise ECnNativeException.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + _SHAFinal; + _CopyResult(Result); +{$ENDIF} + end; +end; + +// ָļݽ SHA224 +function SHA224File(const FileName: string; CallBack: TCnSHACalcProgressFunc): + TCnSHA224Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + Dig := InternalSHAFile(FileName, stSHA2_224, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA224Digest)); +end; + +// ָļݽ SHA256 +function SHA256File(const FileName: string; CallBack: TCnSHACalcProgressFunc): + TCnSHA256Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + Dig := InternalSHAFile(FileName, stSHA2_256, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA256Digest)); +end; + +// ָļݽ SHA384 +function SHA384File(const FileName: string; CallBack: TCnSHACalcProgressFunc): + TCnSHA384Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + Dig := InternalSHAFile(FileName, stSHA2_384, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA384Digest)); +end; + +// ָļݽ SHA512 +function SHA512File(const FileName: string; CallBack: TCnSHACalcProgressFunc): + TCnSHA512Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + Dig := InternalSHAFile(FileName, stSHA2_512, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA512Digest)); +end; + +// ָļݽ SHA512_224 +function SHA512_224File(const FileName: string; CallBack: TCnSHACalcProgressFunc): + TCnSHA512_224Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + Dig := InternalSHAFile(FileName, stSHA2_512_224, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA512_224Digest)); +end; + +// ָļݽ SHA512_256 +function SHA512_256File(const FileName: string; CallBack: TCnSHACalcProgressFunc): + TCnSHA512_256Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + Dig := InternalSHAFile(FileName, stSHA2_512_256, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA512_256Digest)); +end; + +// ʮƸʽ SHA224 Ӵֵ +function SHA224Print(const Digest: TCnSHA224Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA224Digest)); +end; + +// ʮƸʽ SHA256 Ӵֵ +function SHA256Print(const Digest: TCnSHA256Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA256Digest)); +end; + +// ʮƸʽ SHA384 Ӵֵ +function SHA384Print(const Digest: TCnSHA384Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA384Digest)); +end; + +// ʮƸʽ SHA512 Ӵֵ +function SHA512Print(const Digest: TCnSHA512Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA512Digest)); +end; + +// ʮƸʽ SHA512_224 Ӵֵ +function SHA512_224Print(const Digest: TCnSHA512_224Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA512_224Digest)); +end; + +// ʮƸʽ SHA512_256 Ӵֵ +function SHA512_256Print(const Digest: TCnSHA512_256Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA512_256Digest)); +end; + +// Ƚ SHA224 ӴֵǷ +function SHA224Match(const D1, D2: TCnSHA224Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 28) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// Ƚ SHA256 ӴֵǷ +function SHA256Match(const D1, D2: TCnSHA256Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 32) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// Ƚ SHA384 ӴֵǷ +function SHA384Match(const D1, D2: TCnSHA384Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 48) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// Ƚ SHA512 ӴֵǷ +function SHA512Match(const D1, D2: TCnSHA512Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 64) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// Ƚ SHA512_224 ӴֵǷ +function SHA512_224Match(const D1, D2: TCnSHA512_224Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 28) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// Ƚ SHA512_256 ӴֵǷ +function SHA512_256Match(const D1, D2: TCnSHA512_256Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 32) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// SHA224 Ӵֵת string +function SHA224DigestToStr(const Digest: TCnSHA224Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA224Digest)); +end; + +// SHA256 Ӵֵת string +function SHA256DigestToStr(const Digest: TCnSHA256Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA256Digest)); +end; + +// SHA384 Ӵֵת string +function SHA384DigestToStr(const Digest: TCnSHA384Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA384Digest)); +end; + +// SHA512 Ӵֵת string +function SHA512DigestToStr(const Digest: TCnSHA512Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA512Digest)); +end; + +// SHA512_224 Ӵֵת string +function SHA512_224DigestToStr(const Digest: TCnSHA512_224Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA512_224Digest)); +end; + +// SHA512_256 Ӵֵת string +function SHA512_256DigestToStr(const Digest: TCnSHA512_256Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA512_256Digest)); +end; + +procedure SHA224HmacInit(var Context: TCnSHA224Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA224Digest; +begin + if KeyLength > HMAC_SHA2_224_256_BLOCK_SIZE_BYTE then + begin + Sum := SHA224Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA2_224_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA2_224_256_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA2_224_256_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA224Init(Context); + SHA224Update(Context, @(Context.Ipad[0]), HMAC_SHA2_224_256_BLOCK_SIZE_BYTE); +end; + +procedure SHA224HmacUpdate(var Context: TCnSHA224Context; Input: PAnsiChar; Length: + Cardinal); +begin + SHA224Update(Context, Input, Length); +end; + +procedure SHA224HmacFinal(var Context: TCnSHA224Context; var Output: TCnSHA224Digest); +var + Len: Integer; + TmpBuf: TCnSHA224Digest; +begin + Len := HMAC_SHA2_224_OUTPUT_LENGTH_BYTE; + SHA224Final(Context, TmpBuf); + SHA224Init(Context); + SHA224Update(Context, @(Context.Opad[0]), HMAC_SHA2_224_256_BLOCK_SIZE_BYTE); + SHA224Update(Context, @(TmpBuf[0]), Len); + SHA224Final(Context, Output); +end; + +procedure SHA256HmacInit(var Context: TCnSHA256Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA256Digest; +begin + if KeyLength > HMAC_SHA2_224_256_BLOCK_SIZE_BYTE then + begin + Sum := SHA256Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA2_256_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA2_224_256_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA2_224_256_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA256Init(Context); + SHA256Update(Context, @(Context.Ipad[0]), HMAC_SHA2_224_256_BLOCK_SIZE_BYTE); +end; + +procedure SHA256HmacUpdate(var Context: TCnSHA256Context; Input: PAnsiChar; Length: + Cardinal); +begin + SHA256Update(Context, Input, Length); +end; + +procedure SHA256HmacFinal(var Context: TCnSHA256Context; var Output: TCnSHA256Digest); +var + Len: Integer; + TmpBuf: TCnSHA256Digest; +begin + Len := HMAC_SHA2_256_OUTPUT_LENGTH_BYTE; + SHA256Final(Context, TmpBuf); + SHA256Init(Context); + SHA256Update(Context, @(Context.Opad[0]), HMAC_SHA2_224_256_BLOCK_SIZE_BYTE); + SHA256Update(Context, @(TmpBuf[0]), Len); + SHA256Final(Context, Output); +end; + +procedure SHA224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA224Digest); +var + Context: TCnSHA224Context; +begin + SHA224HmacInit(Context, Key, KeyByteLength); + SHA224HmacUpdate(Context, Input, ByteLength); + SHA224HmacFinal(Context, Output); +end; + +function SHA224HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA224HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA224HmacFinal(Context, Result); +end; + +procedure SHA256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA256Digest); +var + Context: TCnSHA256Context; +begin + SHA256HmacInit(Context, Key, KeyByteLength); + SHA256HmacUpdate(Context, Input, ByteLength); + SHA256HmacFinal(Context, Output); +end; + +function SHA256HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA256HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA256HmacFinal(Context, Result); +end; + +procedure SHA384HmacInit(var Context: TCnSHA384Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA384Digest; +begin + if KeyLength > HMAC_SHA2_384_512_BLOCK_SIZE_BYTE then + begin + Sum := SHA384Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA2_384_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA384Init(Context); + SHA384Update(Context, @(Context.Ipad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); +end; + +procedure SHA384HmacUpdate(var Context: TCnSHA384Context; Input: PAnsiChar; + Length: Cardinal); +begin + SHA384Update(Context, Input, Length); +end; + +procedure SHA384HmacFinal(var Context: TCnSHA384Context; var Output: TCnSHA384Digest); +var + Len: Integer; + TmpBuf: TCnSHA384Digest; +begin + Len := HMAC_SHA2_384_OUTPUT_LENGTH_BYTE; + SHA384Final(Context, TmpBuf); + SHA384Init(Context); + SHA384Update(Context, @(Context.Opad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); + SHA384Update(Context, @(TmpBuf[0]), Len); + SHA384Final(Context, Output); +end; + +procedure SHA384Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA384Digest); +var + Context: TCnSHA384Context; +begin + SHA384HmacInit(Context, Key, KeyByteLength); + SHA384HmacUpdate(Context, Input, ByteLength); + SHA384HmacFinal(Context, Output); +end; + +function SHA384HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA384HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA384HmacFinal(Context, Result); +end; + +procedure SHA512HmacInit(var Context: TCnSHA512Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA512Digest; +begin + if KeyLength > HMAC_SHA2_384_512_BLOCK_SIZE_BYTE then + begin + Sum := SHA512Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA2_512_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA512Init(Context); + SHA512Update(Context, @(Context.Ipad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); +end; + +procedure SHA512HmacUpdate(var Context: TCnSHA512Context; Input: PAnsiChar; + Length: Cardinal); +begin + SHA512Update(Context, Input, Length); +end; + +procedure SHA512HmacFinal(var Context: TCnSHA512Context; var Output: TCnSHA512Digest); +var + Len: Integer; + TmpBuf: TCnSHA512Digest; +begin + Len := HMAC_SHA2_512_OUTPUT_LENGTH_BYTE; + SHA512Final(Context, TmpBuf); + SHA512Init(Context); + SHA512Update(Context, @(Context.Opad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); + SHA512Update(Context, @(TmpBuf[0]), Len); + SHA512Final(Context, Output); +end; + +procedure SHA512Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA512Digest); +var + Context: TCnSHA512Context; +begin + SHA512HmacInit(Context, Key, KeyByteLength); + SHA512HmacUpdate(Context, Input, ByteLength); + SHA512HmacFinal(Context, Output); +end; + +function SHA512HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA512HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA512HmacFinal(Context, Result); +end; + +procedure SHA512_224HmacInit(var Context: TCnSHA512_224Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA512_224Digest; +begin + if KeyLength > HMAC_SHA2_384_512_BLOCK_SIZE_BYTE then + begin + Sum := SHA512_224Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA2_512_224_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA512_224Init(Context); + SHA512_224Update(Context, @(Context.Ipad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); +end; + +procedure SHA512_224HmacUpdate(var Context: TCnSHA512_224Context; Input: PAnsiChar; + Length: Cardinal); +begin + SHA512_224Update(Context, Input, Length); +end; + +procedure SHA512_224HmacFinal(var Context: TCnSHA512_224Context; var Output: TCnSHA512_224Digest); +var + Len: Integer; + TmpBuf: TCnSHA512_224Digest; +begin + Len := HMAC_SHA2_512_224_OUTPUT_LENGTH_BYTE; + SHA512_224Final(Context, TmpBuf); + SHA512_224Init(Context); + SHA512_224Update(Context, @(Context.Opad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); + SHA512_224Update(Context, @(TmpBuf[0]), Len); + SHA512_224Final(Context, Output); +end; + +procedure SHA512_224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA512_224Digest); +var + Context: TCnSHA512_224Context; +begin + SHA512_224HmacInit(Context, Key, KeyByteLength); + SHA512_224HmacUpdate(Context, Input, ByteLength); + SHA512_224HmacFinal(Context, Output); +end; + +function SHA512_224HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA512_224Digest; +var + Context: TCnSHA512_224Context; +begin + SHA512_224HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA512_224HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA512_224HmacFinal(Context, Result); +end; + +procedure SHA512_256HmacInit(var Context: TCnSHA512_256Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA512_256Digest; +begin + if KeyLength > HMAC_SHA2_384_512_BLOCK_SIZE_BYTE then + begin + Sum := SHA512_256Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA2_512_256_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA512_256Init(Context); + SHA512_256Update(Context, @(Context.Ipad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); +end; + +procedure SHA512_256HmacUpdate(var Context: TCnSHA512_256Context; Input: PAnsiChar; + Length: Cardinal); +begin + SHA512_256Update(Context, Input, Length); +end; + +procedure SHA512_256HmacFinal(var Context: TCnSHA512_256Context; var Output: TCnSHA512_256Digest); +var + Len: Integer; + TmpBuf: TCnSHA512_256Digest; +begin + Len := HMAC_SHA2_512_256_OUTPUT_LENGTH_BYTE; + SHA512_256Final(Context, TmpBuf); + SHA512_256Init(Context); + SHA512_256Update(Context, @(Context.Opad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); + SHA512_256Update(Context, @(TmpBuf[0]), Len); + SHA512_256Final(Context, Output); +end; + +procedure SHA512_256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA512_256Digest); +var + Context: TCnSHA512_256Context; +begin + SHA512_256HmacInit(Context, Key, KeyByteLength); + SHA512_256HmacUpdate(Context, Input, ByteLength); + SHA512_256HmacFinal(Context, Output); +end; + +function SHA512_256HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA512_256Digest; +var + Context: TCnSHA512_256Context; +begin + SHA512_256HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA512_256HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA512_256HmacFinal(Context, Result); +end; + +end. diff --git a/CnPack/Crypto/CnSHA3.pas b/CnPack/Crypto/CnSHA3.pas index 3e0ade0..1f8500d 100644 --- a/CnPack/Crypto/CnSHA3.pas +++ b/CnPack/Crypto/CnSHA3.pas @@ -1,2700 +1,2917 @@ -{******************************************************************************} -{ CnPack For Delphi/C++Builder } -{ йԼĿԴ } -{ (C)Copyright 2001-2025 CnPack } -{ ------------------------------------ } -{ } -{ ǿԴ CnPack ķЭ } -{ ĺ·һ } -{ } -{ һĿϣãûκεû } -{ ʺضĿĶĵϸ CnPack Э顣 } -{ } -{ ӦѾͿһյһ CnPack Эĸ } -{ ûУɷǵվ } -{ } -{ վַhttps://www.cnpack.org } -{ ʼmaster@cnpack.org } -{ } -{******************************************************************************} - -unit CnSHA3; -{* |
-================================================================================
-* ƣ
-* ԪƣSHA3 Ӵ㷨ʵֵԪ
-* ԪߣCnPack  (master@cnpack.org)
-*           / Keccak C  Pascal ֲ䲿ֹܡ
-*     עԪʵ SHA3 ϵӴ㷨Ӧ HMAC 㷨 SHA3-224/256/384/512
-*           ɱ䳤ժҪ SHAKE128/SHAKE256ȡ
-*           SHA3 淶 NIST.FIPS.202
-*           SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions
-*           жⶨ Bit  Byte ת
-*           ֮ Bit ܹ 8 ʱÿ 8  Bit λþһֽڣֽڼ˳򱣳ֲ䡣
-*
-* ƽ̨PWinXP + Delphi 5.0
-* ݲԣPWinXP/7 + Delphi 5/6
-*   õԪеַϱػʽ
-* ޸ļ¼2023.08.02 V1.4
-*                SHAKE128/SHAKE256 Ŀɱ䳤ժҪļ
-*           2022.04.26 V1.3
-*               ޸ LongWord  Integer ַת֧ MacOS64
-*           2019.12.12 V1.2
-*               ֧ TBytes
-*           2019.04.15 V1.1
-*               ֧ Win32/Win64/MacOS
-*           2017.11.10 V1.0
-*               Ԫ
-================================================================================
-|
} - -interface - -{$I CnPack.inc} - -uses - SysUtils, Classes {$IFDEF MSWINDOWS}, Windows {$ENDIF}, CnNative, CnConsts; - -const - CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH = 32; - {* SHAKE128 ĬӴսֽڳ} - - CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH = 64; - {* SHAKE256 ĬӴսֽڳ} - -type - PCnSHA3GeneralDigest = ^TCnSHA3GeneralDigest; - TCnSHA3GeneralDigest = array[0..63] of Byte; - {* SHA3 ϵͨõӴս 64 ֽΪ׼} - - PCnSHA3_224Digest = ^TCnSHA3_224Digest; - TCnSHA3_224Digest = array[0..27] of Byte; - {* SHA3_224 Ӵս28 ֽ} - - PCnSHA3_256Digest = ^TCnSHA3_256Digest; - TCnSHA3_256Digest = array[0..31] of Byte; - {* SHA3_256 Ӵս32 ֽ} - - PCnSHA3_384Digest = ^TCnSHA3_384Digest; - TCnSHA3_384Digest = array[0..47] of Byte; - {* SHA3_384 Ӵս48 ֽ} - - PCnSHA3_512Digest = ^TCnSHA3_512Digest; - TCnSHA3_512Digest = array[0..63] of Byte; - {* SHA3_512 Ӵս64 ֽ} - - TCnSHA3Context = packed record - {* SHA3 ϵͨõĽṹ} - State: array[0..24] of Int64; - Index: Cardinal; - DigestLen: Cardinal; - Round: Cardinal; - BlockLen: Cardinal; - Block: array[0..255] of Byte; - Ipad: array[0..143] of Byte; {!< HMAC: inner padding } - Opad: array[0..143] of Byte; {!< HMAC: outer padding } - end; - - TCnSHA3CalcProgressFunc = procedure(ATotal, AProgress: Int64; var Cancel: - Boolean) of object; - {* SHA3 ϵͨõļȻص¼} - -function SHA3_224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_224Digest; -{* ݿ SHA3_224 㡣 - - - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ -} - -function SHA3_256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_256Digest; -{* ݿ SHA3_256 㡣 - - - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ -} - -function SHA3_384(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_384Digest; -{* ݿ SHA3_384 㡣 - - - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ -} - -function SHA3_512(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_512Digest; -{* ݿ SHA3_512 㡣 - - - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ -} - -function SHA3_224Buffer(const Buffer; Count: Cardinal): TCnSHA3_224Digest; -{* ݿ SHA3_224 㡣 - - - const Buffer - ݿַ - Count: Cardinal - ݿֽڳ - - ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ -} - -function SHA3_256Buffer(const Buffer; Count: Cardinal): TCnSHA3_256Digest; -{* ݿ SHA3_256 㡣 - - - const Buffer - ݿַ - Count: Cardinal - ݿֽڳ - - ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ -} - -function SHA3_384Buffer(const Buffer; Count: Cardinal): TCnSHA3_384Digest; -{* ݿ SHA3_384 㡣 - - - const Buffer - ݿַ - Count: Cardinal - ݿֽڳ - - ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ -} - -function SHA3_512Buffer(const Buffer; Count: Cardinal): TCnSHA3_512Digest; -{* ݿ SHA3_512 㡣 - - - const Buffer - ݿַ - Count: Cardinal - ݿֽڳ - - ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ -} - -function SHAKE128Buffer(const Buffer; Count: Cardinal; - DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; -{* ݿӴճȿɱ SHAKE128 㣬سΪ DigestByteLength ֽΪӴս - - - const Buffer - ݿַ - Count: Cardinal - ݿֽڳ - DigestByteLength: Cardinal - Ӵսֽڳ - - ֵTBytes - SHAKE128 Ӵֵ -} - -function SHAKE256Buffer(const Buffer; Count: Cardinal; - DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; -{* ݿӴճȿɱ SHAKE128 㣬سΪ DigestByteLength ֽΪӴս - - - const Buffer - ݿַ - Count: Cardinal - ݿֽڳ - DigestByteLength: Cardinal - Ӵսֽڳ - - ֵTBytes - SHAKE256 Ӵֵ -} - -function SHA3_224Bytes(Data: TBytes): TCnSHA3_224Digest; -{* ֽ SHA3_224 㡣 - - - Data: TBytes - ֽ - - ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ -} - -function SHA3_256Bytes(Data: TBytes): TCnSHA3_256Digest; -{* ֽ SHA3_256 㡣 - - - Data: TBytes - ֽ - - ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ -} - -function SHA3_384Bytes(Data: TBytes): TCnSHA3_384Digest; -{* ֽ SHA3_384 㡣 - - - Data: TBytes - ֽ - - ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ -} - -function SHA3_512Bytes(Data: TBytes): TCnSHA3_512Digest; -{* ֽ SHA3_512 㡣 - - - Data: TBytes - ֽ - - ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ -} - -function SHAKE128Bytes(Data: TBytes; DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; -{* ֽӴճȿɱ SHAKE128 㣬سΪ DigestByteLength ֽΪӴս - - - Data: TBytes - ֽ - DigestByteLength: Cardinal - Ӵսֽڳ - - ֵTBytes - SHAKE128 Ӵֵ -} - -function SHAKE256Bytes(Data: TBytes; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; -{* ֽӴճȿɱ SHAKE256 㣬سΪ DigestByteLength ֽΪӴս - - - Data: TBytes - ֽ - DigestByteLength: Cardinal - Ӵսֽڳ - - ֵTBytes - SHAKE256 Ӵֵ -} - -function SHA3_224String(const Str: string): TCnSHA3_224Digest; -{* String ݽ SHA3_224 㣬ע D2009 ϰ汾 string Ϊ UnicodeString - лὫǿת AnsiString м㡣 - - - const Str: string - ַ - - ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ -} - -function SHA3_256String(const Str: string): TCnSHA3_256Digest; -{* String ݽ SHA3_256 㣬ע D2009 ϰ汾 string Ϊ UnicodeString - лὫǿת AnsiString м㡣 - - - const Str: string - ַ - - ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ -} - -function SHA3_384String(const Str: string): TCnSHA3_384Digest; -{* String ݽ SHA3_384 㣬ע D2009 ϰ汾 string Ϊ UnicodeString - лὫǿת AnsiString м㡣 - - - const Str: string - ַ - - ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ -} - -function SHA3_512String(const Str: string): TCnSHA3_512Digest; -{* String ݽ SHA3_512 㣬ע D2009 ϰ汾 string Ϊ UnicodeString - лὫǿת AnsiString м㡣 - - - const Str: string - ַ - - ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ -} - -function SHAKE128String(const Str: string; DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; -{* String ݽӴճȿɱ SHAKE128 㣬سΪ DigestByteLength ֽΪӴս - ע D2009 ϰ汾 string Ϊ UnicodeStringлὫǿת AnsiString м㡣 - - - const Str: string - ַ - DigestByteLength: Cardinal - Ӵսֽڳ - - ֵTBytes - SHAKE128 Ӵֵ -} - -function SHAKE256String(const Str: string; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; -{* String ݽӴճȿɱ SHAKE256 㣬سΪ DigestByteLength ֽΪӴս - ע D2009 ϰ汾 string Ϊ UnicodeStringлὫǿת AnsiString м㡣 - - - const Str: string - ַ - DigestByteLength: Cardinal - Ӵսֽڳ - - ֵTBytes - SHAKE256 Ӵֵ -} - -function SHA3_224StringA(const Str: AnsiString): TCnSHA3_224Digest; -{* AnsiString ݽ SHA3_224 㡣 - - - const Str: AnsiString - ַ - - ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ -} - -function SHA3_224StringW(const Str: WideString): TCnSHA3_224Digest; -{* WideString ݽ SHA3_224 㡣 - ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ - ƽֱ̨תΪ AnsiString ͣٽм㡣 - - - const Str: WideString - Ŀַ - - ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ -} - -function SHA3_256StringA(const Str: AnsiString): TCnSHA3_256Digest; -{* AnsiString ݽ SHA3_256 㡣 - - - const Str: AnsiString - ַ - - ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ -} - -function SHA3_256StringW(const Str: WideString): TCnSHA3_256Digest; -{* WideStringݽ SHA3_256 㡣 - ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ - ƽֱ̨תΪ AnsiString ͣٽм㡣 - - - const Str: WideString - Ŀַ - - ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ -} - -function SHA3_384StringA(const Str: AnsiString): TCnSHA3_384Digest; -{* AnsiString ݽ SHA3_384 㡣 - - - const Str: AnsiString - ַ - - ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ -} - -function SHA3_384StringW(const Str: WideString): TCnSHA3_384Digest; -{* WideString ݽ SHA3_384 㡣 - ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ - ƽֱ̨תΪ AnsiString ͣٽм㡣 - - - const Str: WideString - Ŀַ - - ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ -} - -function SHA3_512StringA(const Str: AnsiString): TCnSHA3_512Digest; -{* AnsiString ݽ SHA3_512 㡣 - - - const Str: AnsiString - ַ - - ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ -} - -function SHA3_512StringW(const Str: WideString): TCnSHA3_512Digest; -{* WideString ݽ SHA512 㡣 - ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ - ƽֱ̨תΪ AnsiString ͣٽм㡣 - - - const Str: WideString - Ŀַ - - ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ -} - -function SHAKE128StringA(const Str: AnsiString; - DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; -{* AnsiString ݽӴճȿɱֱ SHAKE128 㣬 - سΪ DigestByteLength ֽΪӴս - - - const Str: AnsiString - ַ - DigestByteLength: Cardinal - Ӵսֽڳ - - ֵTBytes - SHAKE128 Ӵֵ -} - -function SHAKE128StringW(const Str: WideString; - DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; -{* WideString ݽӴճȿɱֱ SHAKE128 㣬 - سΪ DigestByteLength ֽΪӴս - ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ - ƽֱ̨תΪ AnsiString ͣٽм㡣 - - - const Str: WideString - Ŀַ - DigestByteLength: Cardinal - Ӵսֽڳ - - ֵTBytes - SHAKE128 Ӵֵ -} - -function SHAKE256StringA(const Str: AnsiString; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; -{* AnsiString ݽӴճȿɱֱ SHAKE128 㣬 - سΪ DigestByteLength ֽΪӴս - - - const Str: AnsiString - ַ - DigestByteLength: Cardinal - Ӵսֽڳ - - ֵTBytes - SHAKE256 Ӵֵ -} - -function SHAKE256StringW(const Str: WideString; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; -{* WideString ݽӴճȿɱֱ SHAKE256 㣬 - سΪ DigestByteLength ֽΪӴս - ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ - ƽֱ̨תΪ AnsiString ͣٽм㡣 - - - const Str: WideString - Ŀַ - DigestByteLength: Cardinal - Ӵսֽڳ - - ֵTBytes - SHAKE256 Ӵֵ -} - -{$IFDEF UNICODE} - -function SHA3_224UnicodeString(const Str: string): TCnSHA3_224Digest; -{* UnicodeString ݽֱӵ SHA3_224 㣬ֱӼڲ UTF16 ݣת - - - const Str: string - Ŀַ - - ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ -} - -function SHA3_256UnicodeString(const Str: string): TCnSHA3_256Digest; -{* UnicodeString ݽֱӵ SHA3_256 㣬ֱӼڲ UTF16 ݣת - - - const Str: string - Ŀַ - - ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ -} - -function SHA3_384UnicodeString(const Str: string): TCnSHA3_384Digest; -{* UnicodeString ݽֱӵ SHA3_384 㣬ֱӼڲ UTF16 ݣת - - - const Str: string - Ŀַ - - ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ -} - -function SHA3_512UnicodeString(const Str: string): TCnSHA3_512Digest; -{* UnicodeString ݽֱӵ SHA3_512 㣬ֱӼڲ UTF16 ݣת - - - const Str: string - Ŀַ - - ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ -} - -function SHAKE128UnicodeString(const Str: string; - DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; -{* UnicodeString ݽӴճȿɱֱ SHAKE128 㣬ֱӼڲ UTF16 ݣת - سΪ DigestByteLength ֽΪӴս - - - const Str: string - Ŀַ - DigestByteLength: Cardinal - Ӵսֽڳ - - ֵTBytes - SHAKE128 Ӵֵ -} - -function SHAKE256UnicodeString(const Str: string; - DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; -{* UnicodeString ݽӴճȿɱֱ SHAKE256 㣬ֱӼڲ UTF16 ݣת - سΪ DigestByteLength ֽΪӴս - - - const Str: string - Ŀַ - DigestByteLength: Cardinal - Ӵսֽڳ - - ֵTBytes - SHAKE256 Ӵֵ -} - -{$ELSE} - -function SHA3_224UnicodeString(const Str: WideString): TCnSHA3_224Digest; -{* UnicodeString ݽֱӵ SHA3_224 㣬ֱӼڲ UTF16 ݣת - - - const Str: WideString - Ŀַ - - ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ -} - -function SHA3_256UnicodeString(const Str: WideString): TCnSHA3_256Digest; -{* UnicodeString ݽֱӵ SHA3_256 㣬ֱӼڲ UTF16 ݣת - - - const Str: WideString - Ŀַ - - ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ -} - -function SHA3_384UnicodeString(const Str: WideString): TCnSHA3_384Digest; -{* UnicodeString ݽֱӵ SHA3_384 㣬ֱӼڲ UTF16 ݣת - - - const Str: WideString - Ŀַ - - ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ -} - -function SHA3_512UnicodeString(const Str: WideString): TCnSHA3_512Digest; -{* UnicodeString ݽֱӵ SHA3_512 㣬ֱӼڲ UTF16 ݣת - - - const Str: WideString - Ŀַ - - ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ -} - -function SHAKE128UnicodeString(const Str: WideString; - DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; -{* UnicodeString ݽӴճȿɱֱ SHAKE128 㣬ֱӼڲ UTF16 ݣת - سΪ DigestByteLength ֽΪӴս - - - const Str: WideString - Ŀַ - DigestByteLength: Cardinal - Ӵսֽڳ - - ֵTBytes - SHAKE128 Ӵֵ -} - -function SHAKE256UnicodeString(const Str: WideString; - DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; -{* UnicodeString ݽӴճȿɱֱ SHAKE256 㣬ֱӼڲ UTF16 ݣת - سΪ DigestByteLength ֽΪӴս - - - const Str: WideString - Ŀַ - DigestByteLength: Cardinal - Ӵսֽڳ - - ֵTBytes - SHAKE256 Ӵֵ -} - -{$ENDIF} - -function SHA3_224File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc = - nil): TCnSHA3_224Digest; -{* ָļݽ SHA3_224 㡣 - - - const FileName: string - ļ - CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ - - ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ -} - -function SHA3_224Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc = nil): - TCnSHA3_224Digest; -{* ָݽ SHA3_224 㡣 - - - Stream: TStream - - CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ - - ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ -} - -function SHA3_256File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc = - nil): TCnSHA3_256Digest; -{* ָļݽ SHA3_256 㡣 - - - const FileName: string - ļ - CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ - - ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ -} - -function SHA3_256Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc = nil): - TCnSHA3_256Digest; -{* ָݽ SHA3_256 㡣 - - - Stream: TStream - - CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ - - ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ -} - -function SHA3_384File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc = - nil): TCnSHA3_384Digest; -{* ָļݽ SHA3_384 㡣 - - - const FileName: string - ļ - CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ - - ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ -} - -function SHA3_384Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc = nil): - TCnSHA3_384Digest; -{* ָݽ SHA3_384 㡣 - - - Stream: TStream - - CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ - - ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ -} - -function SHA3_512File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc = - nil): TCnSHA3_512Digest; -{* ָļݽ SHA3_512 㡣 - - - const FileName: string - ļ - CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ - - ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ -} - -function SHA3_512Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc = nil): - TCnSHA3_512Digest; -{* ָݽ SHA3_512 㡣 - - - Stream: TStream - - CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ - - ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ -} - -function SHAKE128File(const FileName: string; - DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH; - CallBack: TCnSHA3CalcProgressFunc = nil): TBytes; -{* ָļݽӴճȿɱ SHAKE128 㣬 - سΪ DigestByteLength ֽΪӴս - - - const FileName: string - ļ - DigestByteLength: Cardinal - Ӵսֽڳ - CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ - - ֵTBytes - SHAKE128Ӵֵ -} - -function SHAKE128Stream(Stream: TStream; - DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH; - CallBack: TCnSHA3CalcProgressFunc = nil): TBytes; -{* ָӴճȿɱ SHAKE128 㣬 - سΪ DigestByteLength ֽΪӴս - - - Stream: TStream - - DigestByteLength: Cardinal - Ӵսֽڳ - CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ - - ֵTBytes - SHAKE128 Ӵֵ -} - -function SHAKE256File(const FileName: string; - DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH; - CallBack: TCnSHA3CalcProgressFunc = nil): TBytes; -{* ָļݽӴճȿɱ SHAKE256 㣬 - سΪ DigestByteLength ֽΪӴս - - - const FileName: string - ļ - DigestByteLength: Cardinal - Ӵսֽڳ - CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ - - ֵTBytes - SHAKE256 Ӵֵ -} - -function SHAKE256Stream(Stream: TStream; - DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH; - CallBack: TCnSHA3CalcProgressFunc = nil): TBytes; -{* ָӴճȿɱ SHAKE256 㣬 - سΪ DigestByteLength ֽΪӴս - - - Stream: TStream - - DigestByteLength: Cardinal - Ӵսֽڳ - CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ - - ֵTBytes - SHAKE256 Ӵֵ -} - -// ⲿݽɢ SHA3_224 㣬SHA3_224Update ɶα - -procedure SHA3_224Init(var Context: TCnSHA3Context); -{* ʼһ SHA3_224 ģ׼ SHA3_224 - - - var Context: TCnSHA3Context - ʼͨ SHA3 - - ֵޣ -} - -procedure SHA3_224Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); -{* ԳʼĶһݽ SHA3_224 㡣 - ɶε㲻ͬݿ飬轫ͬݿƴڴС - - - var Context: TCnSHA3Context - ͨ SHA3 - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵޣ -} - -procedure SHA3_224Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_224Digest); -{* ּ㣬 SHA3_224 Digest С - - - var Context: TCnSHA3Context - ͨ SHA3 - var Digest: TCnSHA3_224Digest - ص SHA3_224 Ӵֵ - - ֵޣ -} - -// ⲿݽɢ SHA3_256 㣬SHA3_256Update ɶα - -procedure SHA3_256Init(var Context: TCnSHA3Context); -{* ʼһ SHA3_256 ģ׼ SHA3_256 - - - var Context: TCnSHA3Context - ʼͨ SHA3 - - ֵޣ -} - -procedure SHA3_256Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); -{* ԳʼĶһݽ SHA3_256 㡣 - ɶε㲻ͬݿ飬轫ͬݿƴڴС - - - var Context: TCnSHA3Context - ͨ SHA3 - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵޣ -} - -procedure SHA3_256Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_256Digest); -{* ּ㣬 SHA3_256 Digest С - - - var Context: TCnSHA3Context - ͨ SHA3 - var Digest: TCnSHA3_256Digest - ص SHA3_256 Ӵֵ - - ֵޣ -} - -// ⲿݽɢ SHA3_384 㣬SHA3_384Update ɶα - -procedure SHA3_384Init(var Context: TCnSHA3Context); -{* ʼһ SHA3_384 ģ׼ SHA3_384 - - - var Context: TCnSHA3Context - ʼͨ SHA3 - - ֵޣ -} - -procedure SHA3_384Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); -{* ԳʼĶһݽ SHA3_384 㡣 - ɶε㲻ͬݿ飬轫ͬݿƴڴС - - - var Context: TCnSHA3Context - ͨ SHA3 - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵޣ -} - -procedure SHA3_384Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_384Digest); -{* ּ㣬 SHA3_384 Digest С - - - var Context: TCnSHA3Context - ͨ SHA3 - var Digest: TCnSHA3_384Digest - ص SHA3_384 Ӵֵ - - ֵޣ -} - -// ⲿݽɢ SHA3_512 㣬SHA3_512Update ɶα - -procedure SHA3_512Init(var Context: TCnSHA3Context); -{* ʼһ SHA3_512 ģ׼ SHA3_512 - - - var Context: TCnSHA3Context - ʼͨ SHA3 - - ֵޣ -} - -procedure SHA3_512Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); -{* ԳʼĶһݽ SHA3_512 㡣 - ɶε㲻ͬݿ飬轫ͬݿƴڴС - - - var Context: TCnSHA3Context - ͨ SHA3 - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵޣ -} - -procedure SHA3_512Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_512Digest); -{* ּ㣬 SHA3_512 Digest С - - - var Context: TCnSHA3Context - ͨ SHA3 - var Digest: TCnSHA3_512Digest - ص SHA3_512 Ӵֵ - - ֵޣ -} - -// ⲿݽɢ SHAKE128 㣬SHAKE128Update ɶα - -procedure SHAKE128Init(var Context: TCnSHA3Context; DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH); -{* ʼһ SHAKE128 ģ׼ SHAKE128 - DigestByteLength ΪӴյֽڳȡ - - - var Context: TCnSHA3Context - ʼͨ SHA3 - DigestByteLength: Cardinal - Ӵսֽڳ - - ֵޣ -} - -procedure SHAKE128Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); -{* ԳʼĶһݽ SHAKE128 㡣 - ɶε㲻ͬݿ飬轫ͬݿƴڴС - - - var Context: TCnSHA3Context - ͨ SHA3 - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵޣ -} - -procedure SHAKE128Final(var Context: TCnSHA3Context; out Digest: TBytes); -{* ּ㣬 SHAKE128 Digest С - - - var Context: TCnSHA3Context - ͨ SHA3 - out Digest: TBytes - ص SHAKE128 Ӵֵ - - ֵޣ -} - -// ⲿݽɢ SHAKE128 㣬SHAKE128Update ɶα - -procedure SHAKE256Init(var Context: TCnSHA3Context; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH); -{* ʼһ SHAKE256 ģ׼ SHAKE256 - DigestByteLength ΪӴյֽڳȡ - - - var Context: TCnSHA3Context - ʼͨ SHA3 - DigestByteLength: Cardinal - Ӵսֽڳ - - ֵޣ -} - -procedure SHAKE256Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); -{* ԳʼĶһݽ SHAKE256 㡣 - ɶε㲻ͬݿ飬轫ͬݿƴڴС - - - var Context: TCnSHA3Context - ͨ SHA3 - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵޣ -} - -procedure SHAKE256Final(var Context: TCnSHA3Context; out Digest: TBytes); -{* ּ㣬 SHAKE256 Digest С - - - var Context: TCnSHA3Context - ͨ SHA3 - out Digest: TBytes - ص SHAKE256 Ӵֵ - - ֵޣ -} - -function SHA3_224Print(const Digest: TCnSHA3_224Digest): string; -{* ʮƸʽ SHA3_224 Ӵֵ - - - const Digest: TCnSHA3_224Digest - ָ SHA3_224 Ӵֵ - - ֵstring - ʮַ -} - -function SHA3_256Print(const Digest: TCnSHA3_256Digest): string; -{* ʮƸʽ SHA3_256 Ӵֵ - - - const Digest: TCnSHA3_256Digest - ָ SHA3_256 Ӵֵ - - ֵstring - ʮַ -} - -function SHA3_384Print(const Digest: TCnSHA3_384Digest): string; -{* ʮƸʽ SHA3_384 Ӵֵ - - const Digest: TCnSHA3_384Digest - ָ SHA3_384 Ӵֵ - - ֵstring - ʮַ -} - -function SHA3_512Print(const Digest: TCnSHA3_512Digest): string; -{* ʮƸʽ SHA3_512 Ӵֵ - - - const Digest: TCnSHA3_512Digest - ָ SHA3_512 Ӵֵ - - ֵstring - ʮַ -} - -function SHAKE128Print(const Digest: TBytes): string; -{* ʮƸʽ SHAKE128 Ӵֵ - - - const Digest: TBytes - ָ SHAKE128 Ӵֵ - - ֵstring - ʮַ -} - -function SHAKE256Print(const Digest: TBytes): string; -{* ʮƸʽ SHAKE256 Ӵֵ - - - const Digest: TBytes - ָ SHAKE128 Ӵֵ - - ֵstring - ʮַ -} - -function SHA3_224Match(const D1: TCnSHA3_224Digest; const D2: TCnSHA3_224Digest): Boolean; -{* Ƚ SHA3_224 ӴֵǷȡ - - - const D1: TCnSHA3_224Digest - Ƚϵ SHA3_224 Ӵֵһ - const D2: TCnSHA3_224Digest - Ƚϵ SHA3_224 Ӵֵ - - ֵBoolean - Ƿ -} - -function SHA3_256Match(const D1: TCnSHA3_256Digest; const D2: TCnSHA3_256Digest): Boolean; -{* Ƚ SHA3_256 ӴֵǷȡ - - - const D1: TCnSHA3_256Digest - Ƚϵ SHA3_256 Ӵֵһ - const D2: TCnSHA3_256Digest - Ƚϵ SHA3_256 Ӵֵ - - ֵBoolean - Ƿ -} - -function SHA3_384Match(const D1: TCnSHA3_384Digest; const D2: TCnSHA3_384Digest): Boolean; -{* Ƚ SHA3_384 ӴֵǷȡ - - - const D1: TCnSHA3_384Digest - Ƚϵ SHA3_384 Ӵֵһ - const D2: TCnSHA3_384Digest - Ƚϵ SHA3_384 Ӵֵ - - ֵBoolean - Ƿ -} - -function SHA3_512Match(const D1: TCnSHA3_512Digest; const D2: TCnSHA3_512Digest): Boolean; -{* Ƚ SHA3_512 ӴֵǷȡ - - - const D1: TCnSHA3_512Digest - Ƚϵ SHA3_512 Ӵֵһ - const D2: TCnSHA3_512Digest - Ƚϵ SHA3_512 Ӵֵ - - ֵBoolean - Ƿ -} - -function SHAKE128Match(const D1: TBytes; const D2: TBytes): Boolean; -{* Ƚ SHAKE128 ӴֵǷȡ - - - const D1: TBytes - Ƚϵ SHAKE128 Ӵֵһ - const D2: TBytes - Ƚϵ SHAKE128 Ӵֵ - - ֵBoolean - Ƿ -} - -function SHAKE256Match(const D1: TBytes; const D2: TBytes): Boolean; -{* Ƚ SHAKE256 ӴֵǷȡ - - - const D1: TBytes - Ƚϵ SHAKE256 Ӵֵһ - const D2: TBytes - Ƚϵ SHAKE256 Ӵֵ - - ֵBoolean - Ƿ -} - -function SHA3_224DigestToStr(const Digest: TCnSHA3_224Digest): string; -{* SHA3_224 Ӵֱֵת stringÿֽڶӦһַ - - - const Digest: TCnSHA3_224Digest - ת SHA3_224 Ӵֵ - - ֵstring - صַ -} - -function SHA3_256DigestToStr(const Digest: TCnSHA3_256Digest): string; -{* SHA3_256 Ӵֱֵת stringÿֽڶӦһַ - |
-   Digest: TSHA3_256Digest   - Ҫ
- |
- - - const Digest: TCnSHA3_256Digest - ת SHA3_256 Ӵֵ - - ֵstring - صַ -} - -function SHA3_384DigestToStr(const Digest: TCnSHA3_384Digest): string; -{* SHA3_384 Ӵֱֵת stringÿֽڶӦһַ - - - const Digest: TCnSHA3_384Digest - ת SHA3_384 Ӵֵ - - ֵstring - صַ -} - -function SHA3_512DigestToStr(const Digest: TCnSHA3_512Digest): string; -{* SHA3_512 Ӵֱֵת stringÿֽڶӦһַ - - - const Digest: TCnSHA3_512Digest - ת SHA3_512 Ӵֵ - - ֵstring - صַ -} - -function SHAKE128DigestToStr(const Digest: TBytes): string; -{* SHAKE128 Ӵֱֵת stringÿֽڶӦһַ - - - const Digest: TBytes - ת SHAKE128 Ӵֵ - - ֵstring - صַ -} - -function SHAKE256DigestToStr(const Digest: TBytes): string; -{* SHAKE256 Ӵֱֵת stringÿֽڶӦһַ - - - const Digest: TBytes - ת SHAKE256 Ӵֵ - - ֵstring - صַ -} - -procedure SHA3_224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA3_224Digest); -{* SHA3_224 HMACHash-based Message Authentication Code㣬 - ͨݵļϼԿĸҲмΡ - - - Key: PAnsiChar - SHA3_224 Կݿַ - KeyByteLength: Integer - SHA3_224 Կݿֽڳ - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - var Output: TCnSHA3_224Digest - ص SHA3_224 Ӵֵ - - ֵޣ -} - -procedure SHA3_256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA3_256Digest); -{* SHA3_256 HMACHash-based Message Authentication Code㣬 - ͨݵļϼԿĸҲмΡ - - - Key: PAnsiChar - SHA3_256 Կݿַ - KeyByteLength: Integer - SHA3_256 Կݿֽڳ - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - var Output: TCnSHA3_256Digest - ص SHA3_256 Ӵֵ - - ֵޣ -} - -procedure SHA3_384Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA3_384Digest); -{* SHA3_384 HMACHash-based Message Authentication Code㣬 - ͨݵļϼԿĸҲмΡ - - - Key: PAnsiChar - SHA3_384 Կݿַ - KeyByteLength: Integer - SHA3_384 Կݿֽڳ - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - var Output: TCnSHA3_384Digest - ص SHA3_384 Ӵֵ - - ֵޣ -} - -procedure SHA3_512Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA3_512Digest); -{* SHA3_512 HMACHash-based Message Authentication Code㣬 - ͨݵļϼԿĸҲмΡ - - - Key: PAnsiChar - SHA3_512 Կݿַ - KeyByteLength: Integer - SHA3_512 Կݿֽڳ - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - var Output: TCnSHA3_512Digest - ص SHA3_512 Ӵֵ - - ֵޣ -} - -implementation - -type - TSHA3Type = (stSHA3_224, stSHA3_256, stSHA3_384, stSHA3_512, stSHAKE128, stSHAKE256); - -const - MAX_FILE_SIZE = 512 * 1024 * 1024; - STREAM_BUF_SIZE = 4096 * 1024; - // If file size <= this size (bytes), using Mapping, else stream - - SHA3_ROUNDS = 24; - SHA3_STATE_LEN = 25; - - SHA3_224_OUTPUT_LENGTH_BYTE = 28; - SHA3_256_OUTPUT_LENGTH_BYTE = 32; - SHA3_384_OUTPUT_LENGTH_BYTE = 48; - SHA3_512_OUTPUT_LENGTH_BYTE = 64; - - SHA3_224_BLOCK_SIZE_BYTE = 144; - SHA3_256_BLOCK_SIZE_BYTE = 136; - SHA3_384_BLOCK_SIZE_BYTE = 104; - SHA3_512_BLOCK_SIZE_BYTE = 72; - - SHAKE128_BLOCK_SIZE_BYTE = 168; - SHAKE256_BLOCK_SIZE_BYTE = 136; - - HMAC_SHA3_224_BLOCK_SIZE_BYTE = SHA3_224_BLOCK_SIZE_BYTE; - HMAC_SHA3_256_BLOCK_SIZE_BYTE = SHA3_256_BLOCK_SIZE_BYTE; - HMAC_SHA3_384_BLOCK_SIZE_BYTE = SHA3_384_BLOCK_SIZE_BYTE; - HMAC_SHA3_512_BLOCK_SIZE_BYTE = SHA3_512_BLOCK_SIZE_BYTE; - - HMAC_SHA3_224_OUTPUT_LENGTH_BYTE = SHA3_224_OUTPUT_LENGTH_BYTE; - HMAC_SHA3_256_OUTPUT_LENGTH_BYTE = SHA3_256_OUTPUT_LENGTH_BYTE; - HMAC_SHA3_384_OUTPUT_LENGTH_BYTE = SHA3_384_OUTPUT_LENGTH_BYTE; - HMAC_SHA3_512_OUTPUT_LENGTH_BYTE = SHA3_512_OUTPUT_LENGTH_BYTE; - - KECCAKF_ROUND_CONSTS: array[0..23] of TUInt64 = ( - $0000000000000001, $0000000000008082, $800000000000808A, - $8000000080008000, $000000000000808B, $0000000080000001, - $8000000080008081, $8000000000008009, $000000000000008A, - $0000000000000088, $0000000080008009, $000000008000000A, - $000000008000808B, $800000000000008B, $8000000000008089, - $8000000000008003, $8000000000008002, $8000000000000080, - $000000000000800A, $800000008000000A, $8000000080008081, - $8000000000008080, $0000000080000001, $8000000080008008 - ); - - KECCAKF_ROT_CONSTS: array[0..23] of Integer = ( - 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, - 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 - ); - - KECCAKF_PILN: array[0..23] of Integer = ( - 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, - 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 - ); - -function ROTL64(Q: TUInt64; N: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := (Q shl N) xor (Q shr (64 - N)); -end; - -// һ SHA3 㣬 Block ݣ State -procedure SHA3_Transform(var Context: TCnSHA3Context); -type - PUInt64Array = ^TUInt64Array; - TUInt64Array = array[0..4095] of TUInt64; -var - I, J, R, L: Integer; - P: PUInt64Array; - T: TUInt64; - BC: array[0..4] of TUInt64; -begin - P := PUInt64Array(@(Context.Block[0])); - I := 0; - L := Integer(Context.BlockLen div 8); - while I < L do - begin - Context.State[I] := Context.State[I] xor P^[I]; - Inc(I); - end; - - for R := 0 to Context.Round - 1 do - begin - // Theta - for I := 0 to 4 do - begin - BC[I] := Context.State[I] xor Context.State[I + 5] xor Context.State[I + 10] - xor Context.State[I + 15] xor Context.State[I + 20]; - end; - for I := 0 to 4 do - begin - T := BC[(I + 4) mod 5] xor ROTL64(BC[(I + 1) mod 5], 1); - for J := 0 to 4 do - Context.State[5 * J + I] := Context.State[5 * J + I] xor T; - end; - - // Rho Pi - T := Context.State[1]; - for I := 0 to 23 do - begin - J := KECCAKF_PILN[I]; - BC[0] := Context.State[J]; - Context.State[J] := ROTL64(T, KECCAKF_ROT_CONSTS[I]); - T := BC[0]; - end; - - // Chi - for J := 0 to 4 do - begin - for I := 0 to 4 do - BC[I] := Context.State[5 * J + I]; - - for I := 0 to 4 do - Context.State[5 * J + I] := Context.State[5 * J + I] xor - ((not BC[(I + 1) mod 5]) and BC[(I + 2) mod 5]); - end; - - // Iota - Context.State[0] := Context.State[0] xor KECCAKF_ROUND_CONSTS[R]; - end; -end; - -procedure SHA3Init(var Context: TCnSHA3Context; SHA3Type: TSHA3Type; - DigestByteLength: Cardinal = 0); -begin - FillChar(Context.State, SizeOf(Context.State), 0); - FillChar(Context.Block, SizeOf(Context.Block), 0); - Context.Index := 0; - Context.Round := SHA3_ROUNDS; - - case SHA3Type of - stSHA3_224: - begin - Context.BlockLen := SHA3_224_BLOCK_SIZE_BYTE; - Context.DigestLen := SHA3_224_OUTPUT_LENGTH_BYTE; - end; - stSHA3_256: - begin - Context.BlockLen := SHA3_256_BLOCK_SIZE_BYTE; - Context.DigestLen := SHA3_256_OUTPUT_LENGTH_BYTE; - end; - stSHA3_384: - begin - Context.BlockLen := SHA3_384_BLOCK_SIZE_BYTE; - Context.DigestLen := SHA3_384_OUTPUT_LENGTH_BYTE; - end; - stSHA3_512: - begin - Context.BlockLen := SHA3_512_BLOCK_SIZE_BYTE; - Context.DigestLen := SHA3_512_OUTPUT_LENGTH_BYTE; - end; - stSHAKE128: - begin - Context.BlockLen := SHAKE128_BLOCK_SIZE_BYTE; - Context.DigestLen := DigestByteLength; - end; - stSHAKE256: - begin - Context.BlockLen := SHAKE256_BLOCK_SIZE_BYTE; - Context.DigestLen := DigestByteLength; - end; - end; -end; - -procedure SHA3Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); -var - R, Idx: Cardinal; -begin - Idx := Context.Index; // Index Block еijʼλָ - repeat - if ByteLength < Context.BlockLen - Idx then - R := ByteLength //  - else - R := Context.BlockLen - Idx; // ܻʣ - - FillChar(Context.Block[Idx], SizeOf(Context.Block) - Idx, 0); // ȷβΪ 0 - Move(Input^, Context.Block[Idx], R); // Block ǰ벿ֲ - - if (Idx + R) < Context.BlockLen then // ûֲ - begin // ֻ Index λָ - Idx := Idx + R; - Break; - end; - - SHA3_Transform(Context); - Dec(ByteLength, R); - Idx := 0; - Inc(Input, R); - until False; - Context.Index := Idx; -end; - -procedure SHA3UpdateW(var Context: TCnSHA3Context; Input: PWideChar; CharLength: Cardinal); -var -{$IFDEF MSWINDOWS} - Content: PAnsiChar; - Len: Cardinal; -{$ELSE} - S: string; // UnicodeString - A: AnsiString; -{$ENDIF} -begin -{$IFDEF MSWINDOWS} - GetMem(Content, CharLength * SizeOf(WideChar)); - try - Len := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 - PAnsiChar(Content), CharLength * SizeOf(WideChar), nil, nil); - SHA3Update(Context, Content, Len); - finally - FreeMem(Content); - end; -{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ - S := StrNew(Input); - A := AnsiString(S); - SHA3Update(Context, @A[1], Length(A)); -{$ENDIF} -end; - -// SHA3_224/256/384/512 ר -procedure SHA3Final(var Context: TCnSHA3Context; var Digest: TCnSHA3GeneralDigest); overload; -begin - Context.Block[Context.Index] := 6; - Context.Block[Context.BlockLen - 1] := Context.Block[Context.BlockLen - 1] or $80; - SHA3_Transform(Context); - Move(Context.State[0], Digest[0], Context.DigestLen); -end; - -// SHAKE128 SHAKE256 ר -procedure SHA3Final(var Context: TCnSHA3Context; out Digest: TBytes); overload; -var - Idx, DL: Cardinal; -begin - Context.Block[Context.Index] := $1F; - Context.Block[Context.BlockLen - 1] := Context.Block[Context.BlockLen - 1] or $80; - SHA3_Transform(Context); - - SetLength(Digest, Context.DigestLen); - if Context.DigestLen <= Context.BlockLen then - Move(Context.State[0], Digest[0], Context.DigestLen) - else - begin - DL := Context.DigestLen; - Idx := 0; - - while DL >= Context.BlockLen do - begin - Move(Context.State[0], Digest[Idx], Context.BlockLen); - Inc(Idx, Context.BlockLen); - Dec(DL, Context.BlockLen); - - if DL > 0 then - begin - FillChar(Context.Block[0], SizeOf(Context.Block), 0); - SHA3_Transform(Context); - end; - end; - - if DL > 0 then - Move(Context.State[0], Digest[Idx], DL); - end; -end; - -procedure SHA3_224Init(var Context: TCnSHA3Context); -begin - SHA3Init(Context, stSHA3_224); -end; - -procedure SHA3_224Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); -begin - SHA3Update(Context, Input, ByteLength); -end; - -procedure SHA3_224Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_224Digest); -var - Res: TCnSHA3GeneralDigest; -begin - SHA3Final(Context, Res); - Move(Res[0], Digest[0], SHA3_224_OUTPUT_LENGTH_BYTE); -end; - -procedure SHA3_256Init(var Context: TCnSHA3Context); -begin - SHA3Init(Context, stSHA3_256); -end; - -procedure SHA3_256Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); -begin - SHA3Update(Context, Input, ByteLength); -end; - -procedure SHA3_256Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_256Digest); -var - Res: TCnSHA3GeneralDigest; -begin - SHA3Final(Context, Res); - Move(Res[0], Digest[0], SHA3_256_OUTPUT_LENGTH_BYTE); -end; - -procedure SHA3_384Init(var Context: TCnSHA3Context); -begin - SHA3Init(Context, stSHA3_384); -end; - -procedure SHA3_384Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); -begin - SHA3Update(Context, Input, ByteLength); -end; - -procedure SHA3_384Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_384Digest); -var - Res: TCnSHA3GeneralDigest; -begin - SHA3Final(Context, Res); - Move(Res[0], Digest[0], SHA3_384_OUTPUT_LENGTH_BYTE); -end; - -procedure SHA3_512Init(var Context: TCnSHA3Context); -begin - SHA3Init(Context, stSHA3_512); -end; - -procedure SHA3_512Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); -begin - SHA3Update(Context, Input, ByteLength); -end; - -procedure SHA3_512Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_512Digest); -var - Res: TCnSHA3GeneralDigest; -begin - SHA3Final(Context, Res); - Move(Res[0], Digest[0], SHA3_512_OUTPUT_LENGTH_BYTE); -end; - -procedure SHAKE128Init(var Context: TCnSHA3Context; DigestByteLength: Cardinal); -begin - SHA3Init(Context, stSHAKE128, DigestByteLength); -end; - -procedure SHAKE128Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); -begin - SHA3Update(Context, Input, ByteLength); -end; - -procedure SHAKE128Final(var Context: TCnSHA3Context; out Digest: TBytes); -begin - SHA3Final(Context, Digest); -end; - -procedure SHAKE256Init(var Context: TCnSHA3Context; DigestByteLength: Cardinal); -begin - SHA3Init(Context, stSHAKE256, DigestByteLength); -end; - -procedure SHAKE256Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); -begin - SHA3Update(Context, Input, ByteLength); -end; - -procedure SHAKE256Final(var Context: TCnSHA3Context; out Digest: TBytes); -begin - SHA3Final(Context, Digest); -end; - -// ݿ SHA3_224λ -function SHA3_224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_224Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_224); - SHA3Update(Context, Input, ByteLength); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); -end; - -// ݿ SHA3_256λ -function SHA3_256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_256Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_256); - SHA3Update(Context, Input, ByteLength); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); -end; - -// ݿ SHA3_384λ -function SHA3_384(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_384Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_384); - SHA3Update(Context, Input, ByteLength); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); -end; - -// ݿ SHA3_512λ -function SHA3_512(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_512Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_512); - SHA3Update(Context, Input, ByteLength); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); -end; - -// ݿ SHA3_224 -function SHA3_224Buffer(const Buffer; Count: Cardinal): TCnSHA3_224Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_224); - SHA3Update(Context, PAnsiChar(Buffer), Count); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); -end; - -// ݿ SHA3_256 -function SHA3_256Buffer(const Buffer; Count: Cardinal): TCnSHA3_256Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_256); - SHA3Update(Context, PAnsiChar(Buffer), Count); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); -end; - -// ݿ SHA3_384 -function SHA3_384Buffer(const Buffer; Count: Cardinal): TCnSHA3_384Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_384); - SHA3Update(Context, PAnsiChar(Buffer), Count); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); -end; - -// ݿ SHA3_512 -function SHA3_512Buffer(const Buffer; Count: Cardinal): TCnSHA3_512Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_512); - SHA3Update(Context, PAnsiChar(Buffer), Count); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); -end; - -// ݿ SHAKE128 -function SHAKE128Buffer(const Buffer; Count: Cardinal; DigestByteLength: Cardinal): TBytes; -var - Context: TCnSHA3Context; -begin - SHAKE128Init(Context, DigestByteLength); - SHAKE128Update(Context, PAnsiChar(Buffer), Count); - SHAKE128Final(Context, Result); -end; - -// ݿ SHAKE256 -function SHAKE256Buffer(const Buffer; Count: Cardinal; DigestByteLength: Cardinal): TBytes; -var - Context: TCnSHA3Context; -begin - SHAKE256Init(Context, DigestByteLength); - SHAKE256Update(Context, PAnsiChar(Buffer), Count); - SHAKE256Final(Context, Result); -end; - -// ֽ SHA3_224 -function SHA3_224Bytes(Data: TBytes): TCnSHA3_224Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_224); - SHA3Update(Context, PAnsiChar(@Data[0]), Length(Data)); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); -end; - -// ֽ SHA3_256 -function SHA3_256Bytes(Data: TBytes): TCnSHA3_256Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_256); - SHA3Update(Context, PAnsiChar(@Data[0]), Length(Data)); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); -end; - -// ֽ SHA3_384 -function SHA3_384Bytes(Data: TBytes): TCnSHA3_384Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_384); - SHA3Update(Context, PAnsiChar(@Data[0]), Length(Data)); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); -end; - -// ֽ SHA3_512 -function SHA3_512Bytes(Data: TBytes): TCnSHA3_512Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_512); - SHA3Update(Context, PAnsiChar(@Data[0]), Length(Data)); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); -end; - -// ֽ SHAKE128 -function SHAKE128Bytes(Data: TBytes; DigestByteLength: Cardinal): TBytes; -var - Context: TCnSHA3Context; -begin - SHAKE128Init(Context, DigestByteLength); - SHAKE128Update(Context, PAnsiChar(@Data[0]), Length(Data)); - SHAKE128Final(Context, Result); -end; - -// ֽ SHAKE256 -function SHAKE256Bytes(Data: TBytes; DigestByteLength: Cardinal): TBytes; -var - Context: TCnSHA3Context; -begin - SHAKE256Init(Context, DigestByteLength); - SHAKE256Update(Context, PAnsiChar(@Data[0]), Length(Data)); - SHAKE256Final(Context, Result); -end; - -// String ݽ SHA3_224 -function SHA3_224String(const Str: string): TCnSHA3_224Digest; -var - AStr: AnsiString; -begin - AStr := AnsiString(Str); - Result := SHA3_224StringA(AStr); -end; - -// String ݽ SHA3_256 -function SHA3_256String(const Str: string): TCnSHA3_256Digest; -var - AStr: AnsiString; -begin - AStr := AnsiString(Str); - Result := SHA3_256StringA(AStr); -end; - -// String ݽ SHA3_384 -function SHA3_384String(const Str: string): TCnSHA3_384Digest; -var - AStr: AnsiString; -begin - AStr := AnsiString(Str); - Result := SHA3_384StringA(AStr); -end; - -// String ݽ SHA3_512 -function SHA3_512String(const Str: string): TCnSHA3_512Digest; -var - AStr: AnsiString; -begin - AStr := AnsiString(Str); - Result := SHA3_512StringA(AStr); -end; - -// String ݽ SHAKE128 -function SHAKE128String(const Str: string; DigestByteLength: Cardinal): TBytes; -var - AStr: AnsiString; -begin - AStr := AnsiString(Str); - Result := SHAKE128StringA(AStr, DigestByteLength); -end; - -// String ݽ SHAKE256 -function SHAKE256String(const Str: string; DigestByteLength: Cardinal): TBytes; -var - AStr: AnsiString; -begin - AStr := AnsiString(Str); - Result := SHAKE256StringA(AStr, DigestByteLength); -end; - -// UnicodeString ݽֱӵ SHA3_224 㣬ת -{$IFDEF UNICODE} -function SHA3_224UnicodeString(const Str: string): TCnSHA3_224Digest; -{$ELSE} -function SHA3_224UnicodeString(const Str: WideString): TCnSHA3_224Digest; -{$ENDIF} -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_224); - SHA3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); -end; - -// UnicodeString ݽֱӵ SHA3_256 㣬ת -{$IFDEF UNICODE} -function SHA3_256UnicodeString(const Str: string): TCnSHA3_256Digest; -{$ELSE} -function SHA3_256UnicodeString(const Str: WideString): TCnSHA3_256Digest; -{$ENDIF} -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_256); - SHA3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); -end; - -// UnicodeString ݽֱӵ SHA3_384 㣬ת -{$IFDEF UNICODE} -function SHA3_384UnicodeString(const Str: string): TCnSHA3_384Digest; -{$ELSE} -function SHA3_384UnicodeString(const Str: WideString): TCnSHA3_384Digest; -{$ENDIF} -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_384); - SHA3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); -end; - -// UnicodeString ݽֱӵ SHA3_512 㣬ת -{$IFDEF UNICODE} -function SHA3_512UnicodeString(const Str: string): TCnSHA3_512Digest; -{$ELSE} -function SHA3_512UnicodeString(const Str: WideString): TCnSHA3_512Digest; -{$ENDIF} -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_512); - SHA3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); -end; - -// UnicodeString ݽֱӵ SHAKE128 㣬ת -{$IFDEF UNICODE} -function SHAKE128UnicodeString(const Str: string; DigestByteLength: Cardinal): TBytes; -{$ELSE} -function SHAKE128UnicodeString(const Str: WideString; DigestByteLength: Cardinal): TBytes; -{$ENDIF} -var - Context: TCnSHA3Context; -begin - SHAKE128Init(Context, DigestByteLength); - SHAKE128Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); - SHAKE128Final(Context, Result); -end; - -// UnicodeString ݽֱӵ SHAKE256 㣬ת -{$IFDEF UNICODE} -function SHAKE256UnicodeString(const Str: string; DigestByteLength: Cardinal): TBytes; -{$ELSE} -function SHAKE256UnicodeString(const Str: WideString; DigestByteLength: Cardinal): TBytes; -{$ENDIF} -var - Context: TCnSHA3Context; -begin - SHAKE256Init(Context, DigestByteLength); - SHAKE256Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); - SHAKE256Final(Context, Result); -end; - -// AnsiString ݽSHA224 -function SHA3_224StringA(const Str: AnsiString): TCnSHA3_224Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_224); - SHA3Update(Context, PAnsiChar(Str), Length(Str)); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); -end; - -// WideString ݽ SHA3_224 -function SHA3_224StringW(const Str: WideString): TCnSHA3_224Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_224); - SHA3UpdateW(Context, PWideChar(Str), Length(Str)); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); -end; - -// AnsiString ݽ SHA3_256 -function SHA3_256StringA(const Str: AnsiString): TCnSHA3_256Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_256); - SHA3Update(Context, PAnsiChar(Str), Length(Str)); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); -end; - -// WideString ݽ SHA3_256 -function SHA3_256StringW(const Str: WideString): TCnSHA3_256Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_256); - SHA3UpdateW(Context, PWideChar(Str), Length(Str)); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); -end; - -// AnsiString ݽ SHA3_384 -function SHA3_384StringA(const Str: AnsiString): TCnSHA3_384Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_384); - SHA3Update(Context, PAnsiChar(Str), Length(Str)); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); -end; - -// WideString ݽ SHA3_384 -function SHA3_384StringW(const Str: WideString): TCnSHA3_384Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_384); - SHA3UpdateW(Context, PWideChar(Str), Length(Str)); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); -end; - -// AnsiString ݽ SHA3_512 -function SHA3_512StringA(const Str: AnsiString): TCnSHA3_512Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_512); - SHA3Update(Context, PAnsiChar(Str), Length(Str)); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); -end; - -// WideString ݽ SHA3_512 -function SHA3_512StringW(const Str: WideString): TCnSHA3_512Digest; -var - Context: TCnSHA3Context; - Res: TCnSHA3GeneralDigest; -begin - SHA3Init(Context, stSHA3_512); - SHA3UpdateW(Context, PWideChar(Str), Length(Str)); - SHA3Final(Context, Res); - Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); -end; - -// AnsiString ݽ SHAKE128 -function SHAKE128StringA(const Str: AnsiString; DigestByteLength: Cardinal): TBytes; -var - Context: TCnSHA3Context; -begin - SHAKE128Init(Context, DigestByteLength); - SHAKE128Update(Context, PAnsiChar(Str), Length(Str)); - SHAKE128Final(Context, Result); -end; - -// WideString ݽ SHAKE128 -function SHAKE128StringW(const Str: WideString; DigestByteLength: Cardinal): TBytes; -var - Context: TCnSHA3Context; -begin - SHAKE128Init(Context, DigestByteLength); - SHA3UpdateW(Context, PWideChar(Str), Length(Str)); // SHAKE128UpdateW = SHA3UpdateW - SHAKE128Final(Context, Result); -end; - -// AnsiString ݽ SHAKE256 -function SHAKE256StringA(const Str: AnsiString; DigestByteLength: Cardinal): TBytes; -var - Context: TCnSHA3Context; -begin - SHAKE256Init(Context, DigestByteLength); - SHAKE256Update(Context, PAnsiChar(Str), Length(Str)); - SHAKE256Final(Context, Result); -end; - -// WideString ݽ SHAKE256 -function SHAKE256StringW(const Str: WideString; DigestByteLength: Cardinal): TBytes; -var - Context: TCnSHA3Context; -begin - SHAKE256Init(Context, DigestByteLength); - SHA3UpdateW(Context, PWideChar(Str), Length(Str)); // SHAKE256UpdateW = SHA3UpdateW - SHAKE256Final(Context, Result); -end; - -// SHA3Type ֻ stSHA3_224, stSHA3_256, stSHA3_384, stSHA3_512 -function InternalSHA3Stream(Stream: TStream; const BufSize: Cardinal; var D: - TCnSHA3GeneralDigest; SHA3Type: TSHA3Type; CallBack: TCnSHA3CalcProgressFunc): Boolean; overload; -var - Buf: PAnsiChar; - BufLen: Cardinal; - Size: Int64; - ReadBytes: Cardinal; - TotalBytes: Int64; - SavePos: Int64; - CancelCalc: Boolean; - Context: TCnSHA3Context; -begin - Result := False; - Size := Stream.Size; - SavePos := Stream.Position; - TotalBytes := 0; - if Size = 0 then - Exit; - if Size < BufSize then - BufLen := Size - else - BufLen := BufSize; - - CancelCalc := False; - SHA3Init(Context, SHA3Type); - - GetMem(Buf, BufLen); - try - Stream.Position := 0; - repeat - ReadBytes := Stream.Read(Buf^, BufLen); - if ReadBytes <> 0 then - begin - Inc(TotalBytes, ReadBytes); - SHA3Update(Context, Buf, ReadBytes); - - if Assigned(CallBack) then - begin - CallBack(Size, TotalBytes, CancelCalc); - if CancelCalc then - Exit; - end; - end; - until (ReadBytes = 0) or (TotalBytes = Size); - SHA3Final(Context, D); - Result := True; - finally - FreeMem(Buf, BufLen); - Stream.Position := SavePos; - end; -end; - -// SHA3Type ֻ stSHAKE128 stSHAKE256 -function InternalSHA3Stream(Stream: TStream; const BufSize: Cardinal; - SHA3Type: TSHA3Type; DigestByteLength: Cardinal; out D: TBytes; - CallBack: TCnSHA3CalcProgressFunc): Boolean; overload; -var - Buf: PAnsiChar; - BufLen: Cardinal; - Size: Int64; - ReadBytes: Cardinal; - TotalBytes: Int64; - SavePos: Int64; - CancelCalc: Boolean; - Context: TCnSHA3Context; -begin - Result := False; - Size := Stream.Size; - SavePos := Stream.Position; - TotalBytes := 0; - if Size = 0 then - Exit; - if Size < BufSize then - BufLen := Size - else - BufLen := BufSize; - - CancelCalc := False; - SHA3Init(Context, SHA3Type, DigestByteLength); - - GetMem(Buf, BufLen); - try - Stream.Position := 0; - repeat - ReadBytes := Stream.Read(Buf^, BufLen); - if ReadBytes <> 0 then - begin - Inc(TotalBytes, ReadBytes); - SHA3Update(Context, Buf, ReadBytes); - - if Assigned(CallBack) then - begin - CallBack(Size, TotalBytes, CancelCalc); - if CancelCalc then - Exit; - end; - end; - until (ReadBytes = 0) or (TotalBytes = Size); - SHA3Final(Context, D); - Result := True; - finally - FreeMem(Buf, BufLen); - Stream.Position := SavePos; - end; -end; - -// ָ SHA3_224 -function SHA3_224Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc): - TCnSHA3_224Digest; -var - Dig: TCnSHA3GeneralDigest; -begin - InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Dig, stSHA3_224, CallBack); - Move(Dig[0], Result[0], SizeOf(TCnSHA3_224Digest)); -end; - -// ָ SHA3_256 -function SHA3_256Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc): - TCnSHA3_256Digest; -var - Dig: TCnSHA3GeneralDigest; -begin - InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Dig, stSHA3_256, CallBack); - Move(Dig[0], Result[0], SizeOf(TCnSHA3_256Digest)); -end; - -// ָ SHA3_384 -function SHA3_384Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc): - TCnSHA3_384Digest; -var - Dig: TCnSHA3GeneralDigest; -begin - InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Dig, stSHA3_384, CallBack); - Move(Dig[0], Result[0], SizeOf(TCnSHA3_384Digest)); -end; - -// ָ SHA3_512 -function SHA3_512Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc): - TCnSHA3_512Digest; -var - Dig: TCnSHA3GeneralDigest; -begin - InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Dig, stSHA3_512, CallBack); - Move(Dig[0], Result[0], SizeOf(TCnSHA3_512Digest)); -end; - -// ָӴճȿɱ SHAKE128 -function SHAKE128Stream(Stream: TStream; DigestByteLength: Cardinal; - CallBack: TCnSHA3CalcProgressFunc): TBytes; -begin - InternalSHA3Stream(Stream, STREAM_BUF_SIZE, stSHAKE128, DigestByteLength, Result, CallBack); -end; - -// ָӴճȿɱ SHAKE256 -function SHAKE256Stream(Stream: TStream; DigestByteLength: Cardinal; - CallBack: TCnSHA3CalcProgressFunc): TBytes; -begin - InternalSHA3Stream(Stream, STREAM_BUF_SIZE, stSHAKE256, DigestByteLength, Result, CallBack); -end; - -function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; -{$IFDEF MSWINDOWS} -var - H: THandle; - Info: BY_HANDLE_FILE_INFORMATION; - Rec: Int64Rec; -{$ENDIF} - begin -{$IFDEF MSWINDOWS} - Result := False; - IsEmpty := False; - H := CreateFile(PChar(AFileName), GENERIC_READ, FILE_SHARE_READ, nil, - OPEN_EXISTING, 0, 0); - if H = INVALID_HANDLE_VALUE then - Exit; - try - if not GetFileInformationByHandle(H, Info) then - Exit; - finally - CloseHandle(H); - end; - Rec.Lo := Info.nFileSizeLow; - Rec.Hi := Info.nFileSizeHigh; - Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); - IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); -{$ELSE} - Result := True; // Windows ƽ̨ Trueʾ Mapping -{$ENDIF} -end; - -function InternalSHA3File(const FileName: string; SHA3Type: TSHA3Type; - CallBack: TCnSHA3CalcProgressFunc): TCnSHA3GeneralDigest; overload; -var -{$IFDEF MSWINDOWS} - Context: TCnSHA3Context; - FileHandle: THandle; - MapHandle: THandle; - ViewPointer: Pointer; -{$ENDIF} - Stream: TStream; - FileIsZeroSize: Boolean; -begin - FileIsZeroSize := False; - if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then - begin - // 2G ļ Map ʧܣʽѭ - Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); - try - InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Result, SHA3Type, CallBack); - finally - Stream.Free; - end; - end - else - begin -{$IFDEF MSWINDOWS} - SHA3Init(Context, SHA3Type); - FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or - FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or - FILE_FLAG_SEQUENTIAL_SCAN, 0); - if FileHandle <> INVALID_HANDLE_VALUE then - begin - try - MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); - if MapHandle <> 0 then - begin - try - ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); - if ViewPointer <> nil then - begin - try - SHA3Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); - finally - UnmapViewOfFile(ViewPointer); - end; - end - else - begin - raise Exception.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); - end; - finally - CloseHandle(MapHandle); - end; - end - else - begin - if not FileIsZeroSize then - raise Exception.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); - end; - finally - CloseHandle(FileHandle); - end; - end; - SHA3Final(Context, Result); -{$ENDIF} - end; -end; - -function InternalSHA3File(const FileName: string; SHA3Type: TSHA3Type; - DigestByteLength: Cardinal; CallBack: TCnSHA3CalcProgressFunc): TBytes; overload; -var -{$IFDEF MSWINDOWS} - Context: TCnSHA3Context; - FileHandle: THandle; - MapHandle: THandle; - ViewPointer: Pointer; -{$ENDIF} - Stream: TStream; - FileIsZeroSize: Boolean; -begin - FileIsZeroSize := False; - if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then - begin - // 2G ļ Map ʧܣʽѭ - Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); - try - InternalSHA3Stream(Stream, STREAM_BUF_SIZE, SHA3Type, DigestByteLength, Result, CallBack); - finally - Stream.Free; - end; - end - else - begin -{$IFDEF MSWINDOWS} - SHA3Init(Context, SHA3Type, DigestByteLength); - FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or - FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or - FILE_FLAG_SEQUENTIAL_SCAN, 0); - if FileHandle <> INVALID_HANDLE_VALUE then - begin - try - MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); - if MapHandle <> 0 then - begin - try - ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); - if ViewPointer <> nil then - begin - try - SHA3Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); - finally - UnmapViewOfFile(ViewPointer); - end; - end - else - begin - raise Exception.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); - end; - finally - CloseHandle(MapHandle); - end; - end - else - begin - if not FileIsZeroSize then - raise Exception.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); - end; - finally - CloseHandle(FileHandle); - end; - end; - SHA3Final(Context, Result); -{$ENDIF} - end; -end; - -// ָļݽ SHA3_224 -function SHA3_224File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc): - TCnSHA3_224Digest; -var - Dig: TCnSHA3GeneralDigest; -begin - Dig := InternalSHA3File(FileName, stSHA3_224, CallBack); - Move(Dig[0], Result[0], SizeOf(TCnSHA3_224Digest)); -end; - -// ָļݽ SHA3_256 -function SHA3_256File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc): - TCnSHA3_256Digest; -var - Dig: TCnSHA3GeneralDigest; -begin - Dig := InternalSHA3File(FileName, stSHA3_256, CallBack); - Move(Dig[0], Result[0], SizeOf(TCnSHA3_256Digest)); -end; - -// ָļݽ SHA3_384 -function SHA3_384File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc): - TCnSHA3_384Digest; -var - Dig: TCnSHA3GeneralDigest; -begin - Dig := InternalSHA3File(FileName, stSHA3_384, CallBack); - Move(Dig[0], Result[0], SizeOf(TCnSHA3_384Digest)); -end; - -// ָļݽ SHA3_512 -function SHA3_512File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc): - TCnSHA3_512Digest; -var - Dig: TCnSHA3GeneralDigest; -begin - Dig := InternalSHA3File(FileName, stSHA3_512, CallBack); - Move(Dig[0], Result[0], SizeOf(TCnSHA3_512Digest)); -end; - -// ָļݽӴճȿɱ SHAKE128 -function SHAKE128File(const FileName: string; DigestByteLength: Cardinal; - CallBack: TCnSHA3CalcProgressFunc): TBytes; -begin - Result := InternalSHA3File(FileName, stSHAKE128, DigestByteLength, CallBack); -end; - -// ָļݽӴճȿɱ SHAKE256 -function SHAKE256File(const FileName: string; DigestByteLength: Cardinal; - CallBack: TCnSHA3CalcProgressFunc): TBytes; -begin - Result := InternalSHA3File(FileName, stSHAKE256, DigestByteLength, CallBack); -end; - -// ʮƸʽ SHA3_224 Ӵֵ -function SHA3_224Print(const Digest: TCnSHA3_224Digest): string; -begin - Result := DataToHex(@Digest[0], SizeOf(TCnSHA3_224Digest)); -end; - -// ʮƸʽ SHA3_256 Ӵֵ -function SHA3_256Print(const Digest: TCnSHA3_256Digest): string; -begin - Result := DataToHex(@Digest[0], SizeOf(TCnSHA3_256Digest)); -end; - -// ʮƸʽ SHA3_384 Ӵֵ -function SHA3_384Print(const Digest: TCnSHA3_384Digest): string; -begin - Result := DataToHex(@Digest[0], SizeOf(TCnSHA3_384Digest)); -end; - -// ʮƸʽ SHA3_512 Ӵֵ -function SHA3_512Print(const Digest: TCnSHA3_512Digest): string; -begin - Result := DataToHex(@Digest[0], SizeOf(TCnSHA3_512Digest)); -end; - -// ʮƸʽ SHAKE128 Ӵֵ -function SHAKE128Print(const Digest: TBytes): string; -begin - Result := BytesToHex(Digest); -end; - -// ʮƸʽ SHAKE256 Ӵֵ -function SHAKE256Print(const Digest: TBytes): string; -begin - Result := BytesToHex(Digest); -end; - -// Ƚ SHA3_224 ӴֵǷ -function SHA3_224Match(const D1, D2: TCnSHA3_224Digest): Boolean; -begin - Result := CompareMem(@D1[0], @D2[0], SizeOf(TCnSHA3_224Digest)); -end; - -// Ƚ SHA3_256 ӴֵǷ -function SHA3_256Match(const D1, D2: TCnSHA3_256Digest): Boolean; -begin - Result := CompareMem(@D1[0], @D2[0], SizeOf(TCnSHA3_256Digest)); -end; - -// Ƚ SHA3_384 ӴֵǷ -function SHA3_384Match(const D1, D2: TCnSHA3_384Digest): Boolean; -begin - Result := CompareMem(@D1[0], @D2[0], SizeOf(TCnSHA3_384Digest)); -end; - -// Ƚ SHA3_512 ӴֵǷ -function SHA3_512Match(const D1, D2: TCnSHA3_512Digest): Boolean; -begin - Result := CompareMem(@D1[0], @D2[0], SizeOf(TCnSHA3_512Digest));; -end; - -// Ƚ SHAKE128 ӴֵǷ -function SHAKE128Match(const D1, D2: TBytes): Boolean; -begin - Result := CompareBytes(D1, D2); -end; - -// Ƚ SHAKE256 ӴֵǷ -function SHAKE256Match(const D1, D2: TBytes): Boolean; -begin - Result := CompareBytes(D1, D2); -end; - -// SHA3_224 Ӵֵת string -function SHA3_224DigestToStr(const Digest: TCnSHA3_224Digest): string; -begin - Result := MemoryToString(@Digest[0], SizeOf(TCnSHA3_224Digest)); -end; - -// SHA3_256 Ӵֵת string -function SHA3_256DigestToStr(const Digest: TCnSHA3_256Digest): string; -begin - Result := MemoryToString(@Digest[0], SizeOf(TCnSHA3_256Digest));; -end; - -// SHA3_384 Ӵֵת string -function SHA3_384DigestToStr(const Digest: TCnSHA3_384Digest): string; -begin - Result := MemoryToString(@Digest[0], SizeOf(TCnSHA3_384Digest)); -end; - -// SHA3_512 Ӵֵת string -function SHA3_512DigestToStr(const Digest: TCnSHA3_512Digest): string; -begin - Result := MemoryToString(@Digest[0], SizeOf(TCnSHA3_512Digest)); -end; - -// SHAKE128 Ӵֵת string -function SHAKE128DigestToStr(const Digest: TBytes): string; -begin - Result := BytesToString(Digest); -end; - -// SHAKE256 Ӵֵת string -function SHAKE256DigestToStr(const Digest: TBytes): string; -begin - Result := BytesToString(Digest); -end; - -procedure SHA3_224HmacInit(var Context: TCnSHA3Context; Key: PAnsiChar; KeyLength: Integer); -var - I: Integer; - Sum: TCnSHA3_224Digest; -begin - if KeyLength > HMAC_SHA3_224_BLOCK_SIZE_BYTE then - begin - Sum := SHA3_224Buffer(Key, KeyLength); - KeyLength := HMAC_SHA3_224_OUTPUT_LENGTH_BYTE; - Key := @(Sum[0]); - end; - - FillChar(Context.Ipad, HMAC_SHA3_224_BLOCK_SIZE_BYTE, $36); - FillChar(Context.Opad, HMAC_SHA3_224_BLOCK_SIZE_BYTE, $5C); - - for I := 0 to KeyLength - 1 do - begin - Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); - Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); - end; - - SHA3Init(Context, stSHA3_224); - SHA3Update(Context, @(Context.Ipad[0]), HMAC_SHA3_224_BLOCK_SIZE_BYTE); -end; - -procedure SHA3_256HmacInit(var Context: TCnSHA3Context; Key: PAnsiChar; KeyLength: Integer); -var - I: Integer; - Sum: TCnSHA3_256Digest; -begin - if KeyLength > HMAC_SHA3_256_BLOCK_SIZE_BYTE then - begin - Sum := SHA3_256Buffer(Key, KeyLength); - KeyLength := HMAC_SHA3_256_OUTPUT_LENGTH_BYTE; - Key := @(Sum[0]); - end; - - FillChar(Context.Ipad, HMAC_SHA3_256_BLOCK_SIZE_BYTE, $36); - FillChar(Context.Opad, HMAC_SHA3_256_BLOCK_SIZE_BYTE, $5C); - - for I := 0 to KeyLength - 1 do - begin - Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); - Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); - end; - - SHA3Init(Context, stSHA3_256); - SHA3Update(Context, @(Context.Ipad[0]), HMAC_SHA3_256_BLOCK_SIZE_BYTE); -end; - -procedure SHA3_384HmacInit(var Context: TCnSHA3Context; Key: PAnsiChar; KeyLength: Integer); -var - I: Integer; - Sum: TCnSHA3_384Digest; -begin - if KeyLength > HMAC_SHA3_384_BLOCK_SIZE_BYTE then - begin - Sum := SHA3_384Buffer(Key, KeyLength); - KeyLength := HMAC_SHA3_384_OUTPUT_LENGTH_BYTE; - Key := @(Sum[0]); - end; - - FillChar(Context.Ipad, HMAC_SHA3_384_BLOCK_SIZE_BYTE, $36); - FillChar(Context.Opad, HMAC_SHA3_384_BLOCK_SIZE_BYTE, $5C); - - for I := 0 to KeyLength - 1 do - begin - Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); - Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); - end; - - SHA3Init(Context, stSHA3_384); - SHA3Update(Context, @(Context.Ipad[0]), HMAC_SHA3_384_BLOCK_SIZE_BYTE); -end; - -procedure SHA3_512HmacInit(var Context: TCnSHA3Context; Key: PAnsiChar; KeyLength: Integer); -var - I: Integer; - Sum: TCnSHA3_512Digest; -begin - if KeyLength > HMAC_SHA3_512_BLOCK_SIZE_BYTE then - begin - Sum := SHA3_512Buffer(Key, KeyLength); - KeyLength := HMAC_SHA3_512_OUTPUT_LENGTH_BYTE; - Key := @(Sum[0]); - end; - - FillChar(Context.Ipad, HMAC_SHA3_512_BLOCK_SIZE_BYTE, $36); - FillChar(Context.Opad, HMAC_SHA3_512_BLOCK_SIZE_BYTE, $5C); - - for I := 0 to KeyLength - 1 do - begin - Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); - Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); - end; - - SHA3Init(Context, stSHA3_512); - SHA3Update(Context, @(Context.Ipad[0]), HMAC_SHA3_512_BLOCK_SIZE_BYTE); -end; - -procedure SHA3_224HmacUpdate(var Context: TCnSHA3Context; Input: PAnsiChar; - ByteLength: Cardinal); -begin - SHA3Update(Context, Input, ByteLength); -end; - -procedure SHA3_256HmacUpdate(var Context: TCnSHA3Context; Input: PAnsiChar; - ByteLength: Cardinal); -begin - SHA3Update(Context, Input, ByteLength); -end; - -procedure SHA3_384HmacUpdate(var Context: TCnSHA3Context; Input: PAnsiChar; - ByteLength: Cardinal); -begin - SHA3Update(Context, Input, ByteLength); -end; - -procedure SHA3_512HmacUpdate(var Context: TCnSHA3Context; Input: PAnsiChar; - ByteLength: Cardinal); -begin - SHA3Update(Context, Input, ByteLength); -end; - -procedure SHA3_224HmacFinal(var Context: TCnSHA3Context; var Output: TCnSHA3GeneralDigest); -var - Len: Integer; - TmpBuf: TCnSHA3GeneralDigest; -begin - Len := HMAC_SHA3_224_OUTPUT_LENGTH_BYTE; - SHA3Final(Context, TmpBuf); - SHA3Init(Context, stSHA3_224); - SHA3Update(Context, @(Context.Opad[0]), HMAC_SHA3_224_BLOCK_SIZE_BYTE); - SHA3Update(Context, @(TmpBuf[0]), Len); - SHA3Final(Context, Output); -end; - -procedure SHA3_256HmacFinal(var Context: TCnSHA3Context; var Output: TCnSHA3GeneralDigest); -var - Len: Integer; - TmpBuf: TCnSHA3GeneralDigest; -begin - Len := HMAC_SHA3_256_OUTPUT_LENGTH_BYTE; - SHA3Final(Context, TmpBuf); - SHA3Init(Context, stSHA3_256); - SHA3Update(Context, @(Context.Opad[0]), HMAC_SHA3_256_BLOCK_SIZE_BYTE); - SHA3Update(Context, @(TmpBuf[0]), Len); - SHA3Final(Context, Output); -end; - -procedure SHA3_384HmacFinal(var Context: TCnSHA3Context; var Output: TCnSHA3GeneralDigest); -var - Len: Integer; - TmpBuf: TCnSHA3GeneralDigest; -begin - Len := HMAC_SHA3_384_OUTPUT_LENGTH_BYTE; - SHA3Final(Context, TmpBuf); - SHA3Init(Context, stSHA3_384); - SHA3Update(Context, @(Context.Opad[0]), HMAC_SHA3_384_BLOCK_SIZE_BYTE); - SHA3Update(Context, @(TmpBuf[0]), Len); - SHA3Final(Context, Output); -end; - -procedure SHA3_512HmacFinal(var Context: TCnSHA3Context; var Output: TCnSHA3GeneralDigest); -var - Len: Integer; - TmpBuf: TCnSHA3GeneralDigest; -begin - Len := HMAC_SHA3_512_OUTPUT_LENGTH_BYTE; - SHA3Final(Context, TmpBuf); - SHA3Init(Context, stSHA3_512); - SHA3Update(Context, @(Context.Opad[0]), HMAC_SHA3_512_BLOCK_SIZE_BYTE); - SHA3Update(Context, @(TmpBuf[0]), Len); - SHA3Final(Context, Output); -end; - -procedure SHA3_224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA3_224Digest); -var - Context: TCnSHA3Context; - Dig: TCnSHA3GeneralDigest; -begin - SHA3_224HmacInit(Context, Key, KeyByteLength); - SHA3_224HmacUpdate(Context, Input, ByteLength); - SHA3_224HmacFinal(Context, Dig); - Move(Dig[0], Output[0], Context.DigestLen); -end; - -procedure SHA3_256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA3_256Digest); -var - Context: TCnSHA3Context; - Dig: TCnSHA3GeneralDigest; -begin - SHA3_256HmacInit(Context, Key, KeyByteLength); - SHA3_256HmacUpdate(Context, Input, ByteLength); - SHA3_256HmacFinal(Context, Dig); - Move(Dig[0], Output[0], Context.DigestLen); -end; - -procedure SHA3_384Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA3_384Digest); -var - Context: TCnSHA3Context; - Dig: TCnSHA3GeneralDigest; -begin - SHA3_384HmacInit(Context, Key, KeyByteLength); - SHA3_384HmacUpdate(Context, Input, ByteLength); - SHA3_384HmacFinal(Context, Dig); - Move(Dig[0], Output[0], Context.DigestLen); -end; - -procedure SHA3_512Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSHA3_512Digest); -var - Context: TCnSHA3Context; - Dig: TCnSHA3GeneralDigest; -begin - SHA3_512HmacInit(Context, Key, KeyByteLength); - SHA3_512HmacUpdate(Context, Input, ByteLength); - SHA3_512HmacFinal(Context, Dig); - Move(Dig[0], Output[0], Context.DigestLen); -end; - -end. +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnSHA3; +{* |
+================================================================================
+* ƣ
+* ԪƣSHA3 Ӵ㷨ʵֵԪ
+* ԪߣCnPack  (master@cnpack.org)
+*           / Keccak C  Pascal ֲ䲿ֹܡ
+*     עԪʵ SHA3 ϵӴ㷨Ӧ HMAC 㷨 SHA3-224/256/384/512
+*           ɱ䳤ժҪ SHAKE128/SHAKE256ȡ
+*
+*           SHA3 淶 NIST.FIPS.202
+*           SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions
+*           жⶨ Bit  Byte ת
+*           ֮ Bit ܹ 8 ʱÿ 8  Bit λþһֽڣֽڼ˳򱣳ֲ䡣
+*
+* ƽ̨PWinXP + Delphi 5.0
+* ݲԣPWinXP/7 + Delphi 5/6
+*   õԪеַϱػʽ
+* ޸ļ¼2025.11.06 V1.5
+*                SHAKE128/SHAKE256  Absorb/Squeeze ƣժҪ
+*           2023.08.02 V1.4
+*                SHAKE128/SHAKE256 Ŀɱ䳤ժҪļ
+*           2022.04.26 V1.3
+*               ޸ LongWord  Integer ַת֧ MacOS64
+*           2019.12.12 V1.2
+*               ֧ TBytes
+*           2019.04.15 V1.1
+*               ֧ Win32/Win64/MacOS
+*           2017.11.10 V1.0
+*               Ԫ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes {$IFDEF MSWINDOWS}, Windows {$ENDIF}, CnNative, CnConsts; + +const + CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH = 32; + {* SHAKE128 ĬӴսֽڳ} + + CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH = 64; + {* SHAKE256 ĬӴսֽڳ} + +type + PCnSHA3GeneralDigest = ^TCnSHA3GeneralDigest; + {* SHA3 ϵͨõӴսָ} + TCnSHA3GeneralDigest = array[0..63] of Byte; + {* SHA3 ϵͨõӴս 64 ֽΪ׼} + + PCnSHA3_224Digest = ^TCnSHA3_224Digest; + {* SHA3_224 Ӵսָ} + TCnSHA3_224Digest = array[0..27] of Byte; + {* SHA3_224 Ӵս28 ֽ} + + PCnSHA3_256Digest = ^TCnSHA3_256Digest; + {* SHA3_256 Ӵսָ} + TCnSHA3_256Digest = array[0..31] of Byte; + {* SHA3_256 Ӵս32 ֽ} + + PCnSHA3_384Digest = ^TCnSHA3_384Digest; + {* SHA3_384 Ӵսָ} + TCnSHA3_384Digest = array[0..47] of Byte; + {* SHA3_384 Ӵս48 ֽ} + + PCnSHA3_512Digest = ^TCnSHA3_512Digest; + {* SHA3_512 Ӵսָ} + TCnSHA3_512Digest = array[0..63] of Byte; + {* SHA3_512 Ӵս64 ֽ} + + TCnSHA3Context = packed record + {* SHA3 ϵͨõĽṹ} + State: array[0..24] of Int64; + Index: Cardinal; + DigestLen: Cardinal; + Round: Cardinal; + BlockLen: Cardinal; + Squeezed: Cardinal; + SqueezeCount: Cardinal; + Block: array[0..255] of Byte; + Ipad: array[0..143] of Byte; {!< HMAC: inner padding } + Opad: array[0..143] of Byte; {!< HMAC: outer padding } + end; + + TCnSHA3CalcProgressFunc = procedure(ATotal, AProgress: Int64; var Cancel: + Boolean) of object; + {* SHA3 ϵͨõļȻص¼} + +function SHA3_224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_224Digest; +{* ݿ SHA3_224 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_256Digest; +{* ݿ SHA3_256 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_384Digest; +{* ݿ SHA3_384 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_512Digest; +{* ݿ SHA3_512 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHA3_224Buffer(const Buffer; Count: Cardinal): TCnSHA3_224Digest; +{* ݿ SHA3_224 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256Buffer(const Buffer; Count: Cardinal): TCnSHA3_256Digest; +{* ݿ SHA3_256 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384Buffer(const Buffer; Count: Cardinal): TCnSHA3_384Digest; +{* ݿ SHA3_384 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512Buffer(const Buffer; Count: Cardinal): TCnSHA3_512Digest; +{* ݿ SHA3_512 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128Buffer(const Buffer; Count: Cardinal; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* ݿӴճȿɱ SHAKE128 㣬سΪ DigestByteLength ֽΪӴս + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256Buffer(const Buffer; Count: Cardinal; + DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* ݿӴճȿɱ SHAKE128 㣬سΪ DigestByteLength ֽΪӴս + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +function SHA3_224Bytes(const Data: TBytes): TCnSHA3_224Digest; +{* ֽ SHA3_224 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256Bytes(const Data: TBytes): TCnSHA3_256Digest; +{* ֽ SHA3_256 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384Bytes(const Data: TBytes): TCnSHA3_384Digest; +{* ֽ SHA3_384 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512Bytes(const Data: TBytes): TCnSHA3_512Digest; +{* ֽ SHA3_512 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128Bytes(const Data: TBytes; DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* ֽӴճȿɱ SHAKE128 㣬سΪ DigestByteLength ֽΪӴս + + + const Data: TBytes - ֽ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256Bytes(const Data: TBytes; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* ֽӴճȿɱ SHAKE256 㣬سΪ DigestByteLength ֽΪӴս + + + const Data: TBytes - ֽ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +function SHA3_224String(const Str: string): TCnSHA3_224Digest; +{* String ݽ SHA3_224 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256String(const Str: string): TCnSHA3_256Digest; +{* String ݽ SHA3_256 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384String(const Str: string): TCnSHA3_384Digest; +{* String ݽ SHA3_384 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512String(const Str: string): TCnSHA3_512Digest; +{* String ݽ SHA3_512 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128String(const Str: string; DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* String ݽӴճȿɱ SHAKE128 㣬سΪ DigestByteLength ֽΪӴս + ע D2009 ϰ汾 string Ϊ UnicodeStringлὫǿת AnsiString м㡣 + + + const Str: string - ַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256String(const Str: string; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* String ݽӴճȿɱ SHAKE256 㣬سΪ DigestByteLength ֽΪӴս + ע D2009 ϰ汾 string Ϊ UnicodeStringлὫǿת AnsiString м㡣 + + + const Str: string - ַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +function SHA3_224StringA(const Str: AnsiString): TCnSHA3_224Digest; +{* AnsiString ݽ SHA3_224 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_224StringW(const Str: WideString): TCnSHA3_224Digest; +{* WideString ݽ SHA3_224 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256StringA(const Str: AnsiString): TCnSHA3_256Digest; +{* AnsiString ݽ SHA3_256 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_256StringW(const Str: WideString): TCnSHA3_256Digest; +{* WideStringݽ SHA3_256 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384StringA(const Str: AnsiString): TCnSHA3_384Digest; +{* AnsiString ݽ SHA3_384 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_384StringW(const Str: WideString): TCnSHA3_384Digest; +{* WideString ݽ SHA3_384 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512StringA(const Str: AnsiString): TCnSHA3_512Digest; +{* AnsiString ݽ SHA3_512 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHA3_512StringW(const Str: WideString): TCnSHA3_512Digest; +{* WideString ݽ SHA512 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128StringA(const Str: AnsiString; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* AnsiString ݽӴճȿɱֱ SHAKE128 㣬 + سΪ DigestByteLength ֽΪӴս + + + const Str: AnsiString - ַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE128StringW(const Str: WideString; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* WideString ݽӴճȿɱֱ SHAKE128 㣬 + سΪ DigestByteLength ֽΪӴս + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256StringA(const Str: AnsiString; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* AnsiString ݽӴճȿɱֱ SHAKE128 㣬 + سΪ DigestByteLength ֽΪӴս + + + const Str: AnsiString - ַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +function SHAKE256StringW(const Str: WideString; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* WideString ݽӴճȿɱֱ SHAKE256 㣬 + سΪ DigestByteLength ֽΪӴս + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +{$IFDEF UNICODE} + +function SHA3_224UnicodeString(const Str: string): TCnSHA3_224Digest; +{* UnicodeString ݽֱӵ SHA3_224 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256UnicodeString(const Str: string): TCnSHA3_256Digest; +{* UnicodeString ݽֱӵ SHA3_256 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384UnicodeString(const Str: string): TCnSHA3_384Digest; +{* UnicodeString ݽֱӵ SHA3_384 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512UnicodeString(const Str: string): TCnSHA3_512Digest; +{* UnicodeString ݽֱӵ SHA3_512 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128UnicodeString(const Str: string; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* UnicodeString ݽӴճȿɱֱ SHAKE128 㣬ֱӼڲ UTF16 ݣת + سΪ DigestByteLength ֽΪӴս + + + const Str: string - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256UnicodeString(const Str: string; + DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* UnicodeString ݽӴճȿɱֱ SHAKE256 㣬ֱӼڲ UTF16 ݣת + سΪ DigestByteLength ֽΪӴս + + + const Str: string - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +{$ELSE} + +function SHA3_224UnicodeString(const Str: WideString): TCnSHA3_224Digest; +{* UnicodeString ݽֱӵ SHA3_224 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256UnicodeString(const Str: WideString): TCnSHA3_256Digest; +{* UnicodeString ݽֱӵ SHA3_256 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384UnicodeString(const Str: WideString): TCnSHA3_384Digest; +{* UnicodeString ݽֱӵ SHA3_384 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512UnicodeString(const Str: WideString): TCnSHA3_512Digest; +{* UnicodeString ݽֱӵ SHA3_512 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128UnicodeString(const Str: WideString; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* UnicodeString ݽӴճȿɱֱ SHAKE128 㣬ֱӼڲ UTF16 ݣת + سΪ DigestByteLength ֽΪӴս + + + const Str: WideString - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256UnicodeString(const Str: WideString; + DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* UnicodeString ݽӴճȿɱֱ SHAKE256 㣬ֱӼڲ UTF16 ݣת + سΪ DigestByteLength ֽΪӴս + + + const Str: WideString - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +{$ENDIF} + +function SHA3_224File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc = + nil): TCnSHA3_224Digest; +{* ָļݽ SHA3_224 㡣 + + + const FileName: string - ļ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_224Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc = nil): + TCnSHA3_224Digest; +{* ָݽ SHA3_224 㡣 + + + Stream: TStream - + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc = + nil): TCnSHA3_256Digest; +{* ָļݽ SHA3_256 㡣 + + + const FileName: string - ļ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_256Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc = nil): + TCnSHA3_256Digest; +{* ָݽ SHA3_256 㡣 + + + Stream: TStream - + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc = + nil): TCnSHA3_384Digest; +{* ָļݽ SHA3_384 㡣 + + + const FileName: string - ļ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_384Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc = nil): + TCnSHA3_384Digest; +{* ָݽ SHA3_384 㡣 + + + Stream: TStream - + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc = + nil): TCnSHA3_512Digest; +{* ָļݽ SHA3_512 㡣 + + + const FileName: string - ļ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHA3_512Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc = nil): + TCnSHA3_512Digest; +{* ָݽ SHA3_512 㡣 + + + Stream: TStream - + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128File(const FileName: string; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH; + CallBack: TCnSHA3CalcProgressFunc = nil): TBytes; +{* ָļݽӴճȿɱ SHAKE128 㣬 + سΪ DigestByteLength ֽΪӴս + + + const FileName: string - ļ + DigestByteLength: Cardinal - Ӵսֽڳ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTBytes - SHAKE128Ӵֵ +} + +function SHAKE128Stream(Stream: TStream; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH; + CallBack: TCnSHA3CalcProgressFunc = nil): TBytes; +{* ָӴճȿɱ SHAKE128 㣬 + سΪ DigestByteLength ֽΪӴս + + + Stream: TStream - + DigestByteLength: Cardinal - Ӵսֽڳ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256File(const FileName: string; + DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH; + CallBack: TCnSHA3CalcProgressFunc = nil): TBytes; +{* ָļݽӴճȿɱ SHAKE256 㣬 + سΪ DigestByteLength ֽΪӴս + + + const FileName: string - ļ + DigestByteLength: Cardinal - Ӵսֽڳ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTBytes - SHAKE256 Ӵֵ +} + +function SHAKE256Stream(Stream: TStream; + DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH; + CallBack: TCnSHA3CalcProgressFunc = nil): TBytes; +{* ָӴճȿɱ SHAKE256 㣬 + سΪ DigestByteLength ֽΪӴս + + + Stream: TStream - + DigestByteLength: Cardinal - Ӵսֽڳ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTBytes - SHAKE256 Ӵֵ +} + +// ⲿݽɢ SHA3_224 㣬SHA3_224Update ɶα + +procedure SHA3_224Init(var Context: TCnSHA3Context); +{* ʼһ SHA3_224 ģ׼ SHA3_224 + + + var Context: TCnSHA3Context - ʼͨ SHA3 + + ֵޣ +} + +procedure SHA3_224Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA3_224 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA3_224Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_224Digest); +{* ּ㣬 SHA3_224 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + var Digest: TCnSHA3_224Digest - ص SHA3_224 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA3_256 㣬SHA3_256Update ɶα + +procedure SHA3_256Init(var Context: TCnSHA3Context); +{* ʼһ SHA3_256 ģ׼ SHA3_256 + + + var Context: TCnSHA3Context - ʼͨ SHA3 + + ֵޣ +} + +procedure SHA3_256Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA3_256 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA3_256Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_256Digest); +{* ּ㣬 SHA3_256 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + var Digest: TCnSHA3_256Digest - ص SHA3_256 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA3_384 㣬SHA3_384Update ɶα + +procedure SHA3_384Init(var Context: TCnSHA3Context); +{* ʼһ SHA3_384 ģ׼ SHA3_384 + + + var Context: TCnSHA3Context - ʼͨ SHA3 + + ֵޣ +} + +procedure SHA3_384Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA3_384 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA3_384Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_384Digest); +{* ּ㣬 SHA3_384 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + var Digest: TCnSHA3_384Digest - ص SHA3_384 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA3_512 㣬SHA3_512Update ɶα + +procedure SHA3_512Init(var Context: TCnSHA3Context); +{* ʼһ SHA3_512 ģ׼ SHA3_512 + + + var Context: TCnSHA3Context - ʼͨ SHA3 + + ֵޣ +} + +procedure SHA3_512Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA3_512 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA3_512Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_512Digest); +{* ּ㣬 SHA3_512 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + var Digest: TCnSHA3_512Digest - ص SHA3_512 Ӵֵ + + ֵޣ +} + +// ¼ⲿݽɢ SHAKE128 㣬SHAKE128Update ɶα + +procedure SHAKE128Init(var Context: TCnSHA3Context; DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH); +{* ʼһ SHAKE128 ģ׼ SHAKE128 + DigestByteLength ΪӴյֽڳȡ + + + var Context: TCnSHA3Context - ʼͨ SHA3 + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵޣ +} + +procedure SHAKE128Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHAKE128 㣬ͬ SHAKE128Absorb + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHAKE128Absorb(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHAKE128 㣬ͬ SHAKE128Update + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHAKE128Final(var Context: TCnSHA3Context; out Digest: TBytes); +{* ּ㣬 SHAKE128 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + out Digest: TBytes - ص SHAKE128 Ӵֵ + + ֵޣ +} + +function SHAKE128Squeeze(var Context: TCnSHA3Context; DigestByteLength: Integer): TBytes; +{* ּ㣬 SHAKE128 DigestByteLength ֽڳݣ + ɼ Squeeze Absorb ˡ + + + var Context: TCnSHA3Context - ͨ SHA3 + DigestByteLength: Integer - Ҫص SHAKE128 Ӵֽڳ + + ֵTBytes - ص SHAKE128 Ӵֵ +} + +// ¼ⲿݽɢ SHAKE128 㣬SHAKE128Update ɶα + +procedure SHAKE256Init(var Context: TCnSHA3Context; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH); +{* ʼһ SHAKE256 ģ׼ SHAKE256 + DigestByteLength ΪӴյֽڳȡ + + + var Context: TCnSHA3Context - ʼͨ SHA3 + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵޣ +} + +procedure SHAKE256Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHAKE256 㣬ͬ SHAKE256Absorb + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHAKE256Absorb(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHAKE256 㣬ͬ SHAKE256Update + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHAKE256Final(var Context: TCnSHA3Context; out Digest: TBytes); +{* ּ㣬 SHAKE256 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + out Digest: TBytes - ص SHAKE256 Ӵֵ + + ֵޣ +} + +function SHAKE256Squeeze(var Context: TCnSHA3Context; DigestByteLength: Integer): TBytes; +{* ּ㣬 SHAKE256 DigestByteLength ֽڳݣ + ɼ Squeeze Absorb ˡ + + + var Context: TCnSHA3Context - ͨ SHA3 + DigestByteLength: Integer - Ҫص SHAKE256 Ӵֽڳ + + ֵTBytes - ص SHAKE256 Ӵֵ +} + +function SHA3_224Print(const Digest: TCnSHA3_224Digest): string; +{* ʮƸʽ SHA3_224 Ӵֵ + + + const Digest: TCnSHA3_224Digest - ָ SHA3_224 Ӵֵ + + ֵstring - ʮַ +} + +function SHA3_256Print(const Digest: TCnSHA3_256Digest): string; +{* ʮƸʽ SHA3_256 Ӵֵ + + + const Digest: TCnSHA3_256Digest - ָ SHA3_256 Ӵֵ + + ֵstring - ʮַ +} + +function SHA3_384Print(const Digest: TCnSHA3_384Digest): string; +{* ʮƸʽ SHA3_384 Ӵֵ + + const Digest: TCnSHA3_384Digest - ָ SHA3_384 Ӵֵ + + ֵstring - ʮַ +} + +function SHA3_512Print(const Digest: TCnSHA3_512Digest): string; +{* ʮƸʽ SHA3_512 Ӵֵ + + + const Digest: TCnSHA3_512Digest - ָ SHA3_512 Ӵֵ + + ֵstring - ʮַ +} + +function SHAKE128Print(const Digest: TBytes): string; +{* ʮƸʽ SHAKE128 Ӵֵ + + + const Digest: TBytes - ָ SHAKE128 Ӵֵ + + ֵstring - ʮַ +} + +function SHAKE256Print(const Digest: TBytes): string; +{* ʮƸʽ SHAKE256 Ӵֵ + + + const Digest: TBytes - ָ SHAKE128 Ӵֵ + + ֵstring - ʮַ +} + +function SHA3_224Match(const D1: TCnSHA3_224Digest; const D2: TCnSHA3_224Digest): Boolean; +{* Ƚ SHA3_224 ӴֵǷȡ + + + const D1: TCnSHA3_224Digest - Ƚϵ SHA3_224 Ӵֵһ + const D2: TCnSHA3_224Digest - Ƚϵ SHA3_224 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA3_256Match(const D1: TCnSHA3_256Digest; const D2: TCnSHA3_256Digest): Boolean; +{* Ƚ SHA3_256 ӴֵǷȡ + + + const D1: TCnSHA3_256Digest - Ƚϵ SHA3_256 Ӵֵһ + const D2: TCnSHA3_256Digest - Ƚϵ SHA3_256 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA3_384Match(const D1: TCnSHA3_384Digest; const D2: TCnSHA3_384Digest): Boolean; +{* Ƚ SHA3_384 ӴֵǷȡ + + + const D1: TCnSHA3_384Digest - Ƚϵ SHA3_384 Ӵֵһ + const D2: TCnSHA3_384Digest - Ƚϵ SHA3_384 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA3_512Match(const D1: TCnSHA3_512Digest; const D2: TCnSHA3_512Digest): Boolean; +{* Ƚ SHA3_512 ӴֵǷȡ + + + const D1: TCnSHA3_512Digest - Ƚϵ SHA3_512 Ӵֵһ + const D2: TCnSHA3_512Digest - Ƚϵ SHA3_512 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHAKE128Match(const D1: TBytes; const D2: TBytes): Boolean; +{* Ƚ SHAKE128 ӴֵǷȡ + + + const D1: TBytes - Ƚϵ SHAKE128 Ӵֵһ + const D2: TBytes - Ƚϵ SHAKE128 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHAKE256Match(const D1: TBytes; const D2: TBytes): Boolean; +{* Ƚ SHAKE256 ӴֵǷȡ + + + const D1: TBytes - Ƚϵ SHAKE256 Ӵֵһ + const D2: TBytes - Ƚϵ SHAKE256 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA3_224DigestToStr(const Digest: TCnSHA3_224Digest): string; +{* SHA3_224 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA3_224Digest - ת SHA3_224 Ӵֵ + + ֵstring - صַ +} + +function SHA3_256DigestToStr(const Digest: TCnSHA3_256Digest): string; +{* SHA3_256 Ӵֱֵת stringÿֽڶӦһַ + |
+   Digest: TSHA3_256Digest   - Ҫ
+ |
+ + + const Digest: TCnSHA3_256Digest - ת SHA3_256 Ӵֵ + + ֵstring - صַ +} + +function SHA3_384DigestToStr(const Digest: TCnSHA3_384Digest): string; +{* SHA3_384 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA3_384Digest - ת SHA3_384 Ӵֵ + + ֵstring - صַ +} + +function SHA3_512DigestToStr(const Digest: TCnSHA3_512Digest): string; +{* SHA3_512 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA3_512Digest - ת SHA3_512 Ӵֵ + + ֵstring - صַ +} + +function SHAKE128DigestToStr(const Digest: TBytes): string; +{* SHAKE128 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TBytes - ת SHAKE128 Ӵֵ + + ֵstring - صַ +} + +function SHAKE256DigestToStr(const Digest: TBytes): string; +{* SHAKE256 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TBytes - ת SHAKE256 Ӵֵ + + ֵstring - صַ +} + +procedure SHA3_224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_224Digest); +{* SHA3_224 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA3_224 Կݿַ + KeyByteLength: Integer - SHA3_224 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA3_224Digest - ص SHA3_224 Ӵֵ + + ֵޣ +} + +procedure SHA3_256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_256Digest); +{* SHA3_256 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA3_256 Կݿַ + KeyByteLength: Integer - SHA3_256 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA3_256Digest - ص SHA3_256 Ӵֵ + + ֵޣ +} + +procedure SHA3_384Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_384Digest); +{* SHA3_384 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA3_384 Կݿַ + KeyByteLength: Integer - SHA3_384 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA3_384Digest - ص SHA3_384 Ӵֵ + + ֵޣ +} + +procedure SHA3_512Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_512Digest); +{* SHA3_512 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA3_512 Կݿַ + KeyByteLength: Integer - SHA3_512 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA3_512Digest - ص SHA3_512 Ӵֵ + + ֵޣ +} + +function SHA3_224HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA3_224Digest; +{* ֽл SHA3_224 HMAC 㡣 + + + const Key: TBytes - SHA3_224 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA3_256Digest; +{* ֽл SHA3_256 HMAC 㡣 + + + const Key: TBytes - SHA3_256 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA3_384Digest; +{* ֽл SHA3_384 HMAC 㡣 + + + const Key: TBytes - SHA3_384 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA3_512Digest; +{* ֽл SHA3_512 HMAC 㡣 + + + const Key: TBytes - SHA3_512 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +implementation + +type + TSHA3Type = (stSHA3_224, stSHA3_256, stSHA3_384, stSHA3_512, stSHAKE128, stSHAKE256); + +const + MAX_FILE_SIZE = 512 * 1024 * 1024; + STREAM_BUF_SIZE = 4096 * 1024; + // If file size <= this size (bytes), using Mapping, else stream + + SHA3_ROUNDS = 24; + SHA3_STATE_LEN = 25; + + SHA3_224_OUTPUT_LENGTH_BYTE = 28; + SHA3_256_OUTPUT_LENGTH_BYTE = 32; + SHA3_384_OUTPUT_LENGTH_BYTE = 48; + SHA3_512_OUTPUT_LENGTH_BYTE = 64; + + SHA3_224_BLOCK_SIZE_BYTE = 144; + SHA3_256_BLOCK_SIZE_BYTE = 136; + SHA3_384_BLOCK_SIZE_BYTE = 104; + SHA3_512_BLOCK_SIZE_BYTE = 72; + + SHAKE128_BLOCK_SIZE_BYTE = 168; + SHAKE256_BLOCK_SIZE_BYTE = 136; + + HMAC_SHA3_224_BLOCK_SIZE_BYTE = SHA3_224_BLOCK_SIZE_BYTE; + HMAC_SHA3_256_BLOCK_SIZE_BYTE = SHA3_256_BLOCK_SIZE_BYTE; + HMAC_SHA3_384_BLOCK_SIZE_BYTE = SHA3_384_BLOCK_SIZE_BYTE; + HMAC_SHA3_512_BLOCK_SIZE_BYTE = SHA3_512_BLOCK_SIZE_BYTE; + + HMAC_SHA3_224_OUTPUT_LENGTH_BYTE = SHA3_224_OUTPUT_LENGTH_BYTE; + HMAC_SHA3_256_OUTPUT_LENGTH_BYTE = SHA3_256_OUTPUT_LENGTH_BYTE; + HMAC_SHA3_384_OUTPUT_LENGTH_BYTE = SHA3_384_OUTPUT_LENGTH_BYTE; + HMAC_SHA3_512_OUTPUT_LENGTH_BYTE = SHA3_512_OUTPUT_LENGTH_BYTE; + + KECCAKF_ROUND_CONSTS: array[0..23] of TUInt64 = ( + $0000000000000001, $0000000000008082, $800000000000808A, + $8000000080008000, $000000000000808B, $0000000080000001, + $8000000080008081, $8000000000008009, $000000000000008A, + $0000000000000088, $0000000080008009, $000000008000000A, + $000000008000808B, $800000000000008B, $8000000000008089, + $8000000000008003, $8000000000008002, $8000000000000080, + $000000000000800A, $800000008000000A, $8000000080008081, + $8000000000008080, $0000000080000001, $8000000080008008 + ); + + KECCAKF_ROT_CONSTS: array[0..23] of Integer = ( + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 + ); + + KECCAKF_PILN: array[0..23] of Integer = ( + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 + ); + +function ROTL64(Q: TUInt64; N: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (Q shl N) xor (Q shr (64 - N)); +end; + +// һ SHA3 㣬 Block ݣ State +procedure SHA3_Transform(var Context: TCnSHA3Context); +type + PUInt64Array = ^TUInt64Array; + TUInt64Array = array[0..4095] of TUInt64; +var + I, J, R, L: Integer; + P: PUInt64Array; + T: TUInt64; + BC: array[0..4] of TUInt64; +begin + P := PUInt64Array(@(Context.Block[0])); + I := 0; + L := Integer(Context.BlockLen div 8); + while I < L do + begin + Context.State[I] := Context.State[I] xor P^[I]; + Inc(I); + end; + + for R := 0 to Context.Round - 1 do + begin + // Theta + for I := 0 to 4 do + begin + BC[I] := Context.State[I] xor Context.State[I + 5] xor Context.State[I + 10] + xor Context.State[I + 15] xor Context.State[I + 20]; + end; + for I := 0 to 4 do + begin + T := BC[(I + 4) mod 5] xor ROTL64(BC[(I + 1) mod 5], 1); + for J := 0 to 4 do + Context.State[5 * J + I] := Context.State[5 * J + I] xor T; + end; + + // Rho Pi + T := Context.State[1]; + for I := 0 to 23 do + begin + J := KECCAKF_PILN[I]; + BC[0] := Context.State[J]; + Context.State[J] := ROTL64(T, KECCAKF_ROT_CONSTS[I]); + T := BC[0]; + end; + + // Chi + for J := 0 to 4 do + begin + for I := 0 to 4 do + BC[I] := Context.State[5 * J + I]; + + for I := 0 to 4 do + Context.State[5 * J + I] := Context.State[5 * J + I] xor + ((not BC[(I + 1) mod 5]) and BC[(I + 2) mod 5]); + end; + + // Iota + Context.State[0] := Context.State[0] xor KECCAKF_ROUND_CONSTS[R]; + end; +end; + +procedure SHA3Init(var Context: TCnSHA3Context; SHA3Type: TSHA3Type; + DigestByteLength: Cardinal = 0); +begin + FillChar(Context.State, SizeOf(Context.State), 0); + FillChar(Context.Block, SizeOf(Context.Block), 0); + Context.Index := 0; + Context.Squeezed := 0; + Context.SqueezeCount := 0; + Context.Round := SHA3_ROUNDS; + + case SHA3Type of + stSHA3_224: + begin + Context.BlockLen := SHA3_224_BLOCK_SIZE_BYTE; + Context.DigestLen := SHA3_224_OUTPUT_LENGTH_BYTE; + end; + stSHA3_256: + begin + Context.BlockLen := SHA3_256_BLOCK_SIZE_BYTE; + Context.DigestLen := SHA3_256_OUTPUT_LENGTH_BYTE; + end; + stSHA3_384: + begin + Context.BlockLen := SHA3_384_BLOCK_SIZE_BYTE; + Context.DigestLen := SHA3_384_OUTPUT_LENGTH_BYTE; + end; + stSHA3_512: + begin + Context.BlockLen := SHA3_512_BLOCK_SIZE_BYTE; + Context.DigestLen := SHA3_512_OUTPUT_LENGTH_BYTE; + end; + stSHAKE128: + begin + Context.BlockLen := SHAKE128_BLOCK_SIZE_BYTE; + Context.DigestLen := DigestByteLength; + end; + stSHAKE256: + begin + Context.BlockLen := SHAKE256_BLOCK_SIZE_BYTE; + Context.DigestLen := DigestByteLength; + end; + end; +end; + +procedure SHA3Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +var + R, Idx: Cardinal; +begin + Idx := Context.Index; // Index Block еijʼλָ + repeat + if ByteLength < Context.BlockLen - Idx then + R := ByteLength //  + else + R := Context.BlockLen - Idx; // ܻʣ + + FillChar(Context.Block[Idx], SizeOf(Context.Block) - Idx, 0); // ȷβΪ 0 + Move(Input^, Context.Block[Idx], R); // Block ǰ벿ֲ + + if (Idx + R) < Context.BlockLen then // ûֲ + begin // ֻ Index λָ + Idx := Idx + R; + Break; + end; + + SHA3_Transform(Context); + Dec(ByteLength, R); + Idx := 0; + Inc(Input, R); + until False; + Context.Index := Idx; +end; + +procedure SHA3UpdateW(var Context: TCnSHA3Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + Content: PAnsiChar; + Len: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(Content, CharLength * SizeOf(WideChar)); + try + Len := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(Content), CharLength * SizeOf(WideChar), nil, nil); + SHA3Update(Context, Content, Len); + finally + FreeMem(Content); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + SHA3Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +// SHA3_224/256/384/512 ר +procedure SHA3Final(var Context: TCnSHA3Context; var Digest: TCnSHA3GeneralDigest); overload; +begin + Context.Block[Context.Index] := 6; + Context.Block[Context.BlockLen - 1] := Context.Block[Context.BlockLen - 1] or $80; + SHA3_Transform(Context); + Move(Context.State[0], Digest[0], Context.DigestLen); +end; + +// SHAKE128 SHAKE256 ר +procedure SHA3Final(var Context: TCnSHA3Context; out Digest: TBytes); overload; +var + Idx, DL: Cardinal; +begin + Context.Block[Context.Index] := $1F; + Context.Block[Context.BlockLen - 1] := Context.Block[Context.BlockLen - 1] or $80; + SHA3_Transform(Context); + + SetLength(Digest, Context.DigestLen); + if Context.DigestLen <= Context.BlockLen then + Move(Context.State[0], Digest[0], Context.DigestLen) + else + begin + DL := Context.DigestLen; + Idx := 0; + + while DL >= Context.BlockLen do + begin + Move(Context.State[0], Digest[Idx], Context.BlockLen); + Inc(Idx, Context.BlockLen); + Dec(DL, Context.BlockLen); + + if DL > 0 then + begin + FillChar(Context.Block[0], SizeOf(Context.Block), 0); + SHA3_Transform(Context); + end; + end; + + if DL > 0 then + Move(Context.State[0], Digest[Idx], DL); + end; +end; + +function SHAKE3Squeeze(var Context: TCnSHA3Context; DigestByteLength: Integer): TBytes; +var + Idx, DL: Cardinal; + BlockLen: Cardinal; + BytesToCopy: Cardinal; +begin + if DigestByteLength <= 0 then + begin + Result := nil; + Exit; + end; + + BlockLen := Context.BlockLen; + + // ǵһν룬 Absorb ׶ + if Context.Squeezed = 0 then + begin + Context.Block[Context.Index] := $1F; + Context.Block[Context.BlockLen - 1] := Context.Block[Context.BlockLen - 1] or $80; + SHA3_Transform(Context); + Context.Squeezed := 1; // Ѿս׶ + Context.SqueezeCount := 0; // üѹ + end; + + // ʼ + SetLength(Result, DigestByteLength); + DL := DigestByteLength; + Idx := 0; + + // ӵǰ״̬ȡ + while DL > 0 do + begin + // 㵱ǰʣȡֽ + BytesToCopy := BlockLen - Context.SqueezeCount; + if BytesToCopy > DL then + BytesToCopy := DL; + + // ״̬ȡ + Move(PByteArray(@Context.State[0])[Context.SqueezeCount], Result[Idx], BytesToCopy); + + // ¼ָ + Inc(Context.SqueezeCount, BytesToCopy); + Inc(Idx, BytesToCopy); + Dec(DL, BytesToCopy); + + // ǰ꣬Ҫ任״̬ȡһ + if (DL > 0) and (Context.SqueezeCount >= BlockLen) then + begin + FillChar(Context.Block[0], SizeOf(Context.Block), 0); + SHA3_Transform(Context); + Context.SqueezeCount := 0; // Ϊµ״̬Ŀʼ + end; + end; +end; + +procedure SHA3_224Init(var Context: TCnSHA3Context); +begin + SHA3Init(Context, stSHA3_224); +end; + +procedure SHA3_224Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_224Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_224Digest); +var + Res: TCnSHA3GeneralDigest; +begin + SHA3Final(Context, Res); + Move(Res[0], Digest[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +procedure SHA3_256Init(var Context: TCnSHA3Context); +begin + SHA3Init(Context, stSHA3_256); +end; + +procedure SHA3_256Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_256Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_256Digest); +var + Res: TCnSHA3GeneralDigest; +begin + SHA3Final(Context, Res); + Move(Res[0], Digest[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +procedure SHA3_384Init(var Context: TCnSHA3Context); +begin + SHA3Init(Context, stSHA3_384); +end; + +procedure SHA3_384Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_384Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_384Digest); +var + Res: TCnSHA3GeneralDigest; +begin + SHA3Final(Context, Res); + Move(Res[0], Digest[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +procedure SHA3_512Init(var Context: TCnSHA3Context); +begin + SHA3Init(Context, stSHA3_512); +end; + +procedure SHA3_512Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_512Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_512Digest); +var + Res: TCnSHA3GeneralDigest; +begin + SHA3Final(Context, Res); + Move(Res[0], Digest[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +procedure SHAKE128Init(var Context: TCnSHA3Context; DigestByteLength: Cardinal); +begin + SHA3Init(Context, stSHAKE128, DigestByteLength); +end; + +procedure SHAKE128Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHAKE128Absorb(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHAKE128Final(var Context: TCnSHA3Context; out Digest: TBytes); +begin + SHA3Final(Context, Digest); +end; + +function SHAKE128Squeeze(var Context: TCnSHA3Context; DigestByteLength: Integer): TBytes; +begin + Result := SHAKE3Squeeze(Context, DigestByteLength); +end; + +procedure SHAKE256Init(var Context: TCnSHA3Context; DigestByteLength: Cardinal); +begin + SHA3Init(Context, stSHAKE256, DigestByteLength); +end; + +procedure SHAKE256Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHAKE256Absorb(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHAKE256Final(var Context: TCnSHA3Context; out Digest: TBytes); +begin + SHA3Final(Context, Digest); +end; + +function SHAKE256Squeeze(var Context: TCnSHA3Context; DigestByteLength: Integer): TBytes; +begin + Result := SHAKE3Squeeze(Context, DigestByteLength); +end; + +// ݿ SHA3_224λ +function SHA3_224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, Input, ByteLength); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_256λ +function SHA3_256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, Input, ByteLength); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_384λ +function SHA3_384(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, Input, ByteLength); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_512λ +function SHA3_512(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, Input, ByteLength); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_224 +function SHA3_224Buffer(const Buffer; Count: Cardinal): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, PAnsiChar(@Buffer), Count); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_256 +function SHA3_256Buffer(const Buffer; Count: Cardinal): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, PAnsiChar(@Buffer), Count); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_384 +function SHA3_384Buffer(const Buffer; Count: Cardinal): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, PAnsiChar(@Buffer), Count); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_512 +function SHA3_512Buffer(const Buffer; Count: Cardinal): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, PAnsiChar(@Buffer), Count); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHAKE128 +function SHAKE128Buffer(const Buffer; Count: Cardinal; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE128Init(Context, DigestByteLength); + SHAKE128Update(Context, PAnsiChar(@Buffer), Count); + SHAKE128Final(Context, Result); +end; + +// ݿ SHAKE256 +function SHAKE256Buffer(const Buffer; Count: Cardinal; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE256Init(Context, DigestByteLength); + SHAKE256Update(Context, PAnsiChar(@Buffer), Count); + SHAKE256Final(Context, Result); +end; + +// ֽ SHA3_224 +function SHA3_224Bytes(const Data: TBytes): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// ֽ SHA3_256 +function SHA3_256Bytes(const Data: TBytes): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// ֽ SHA3_384 +function SHA3_384Bytes(const Data: TBytes): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// ֽ SHA3_512 +function SHA3_512Bytes(const Data: TBytes): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// ֽ SHAKE128 +function SHAKE128Bytes(const Data: TBytes; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE128Init(Context, DigestByteLength); + SHAKE128Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHAKE128Final(Context, Result); +end; + +// ֽ SHAKE256 +function SHAKE256Bytes(const Data: TBytes; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE256Init(Context, DigestByteLength); + SHAKE256Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHAKE256Final(Context, Result); +end; + +// String ݽ SHA3_224 +function SHA3_224String(const Str: string): TCnSHA3_224Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA3_224StringA(AStr); +end; + +// String ݽ SHA3_256 +function SHA3_256String(const Str: string): TCnSHA3_256Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA3_256StringA(AStr); +end; + +// String ݽ SHA3_384 +function SHA3_384String(const Str: string): TCnSHA3_384Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA3_384StringA(AStr); +end; + +// String ݽ SHA3_512 +function SHA3_512String(const Str: string): TCnSHA3_512Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA3_512StringA(AStr); +end; + +// String ݽ SHAKE128 +function SHAKE128String(const Str: string; DigestByteLength: Cardinal): TBytes; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHAKE128StringA(AStr, DigestByteLength); +end; + +// String ݽ SHAKE256 +function SHAKE256String(const Str: string; DigestByteLength: Cardinal): TBytes; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHAKE256StringA(AStr, DigestByteLength); +end; + +// UnicodeString ݽֱӵ SHA3_224 㣬ת +{$IFDEF UNICODE} +function SHA3_224UnicodeString(const Str: string): TCnSHA3_224Digest; +{$ELSE} +function SHA3_224UnicodeString(const Str: WideString): TCnSHA3_224Digest; +{$ENDIF} +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// UnicodeString ݽֱӵ SHA3_256 㣬ת +{$IFDEF UNICODE} +function SHA3_256UnicodeString(const Str: string): TCnSHA3_256Digest; +{$ELSE} +function SHA3_256UnicodeString(const Str: WideString): TCnSHA3_256Digest; +{$ENDIF} +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// UnicodeString ݽֱӵ SHA3_384 㣬ת +{$IFDEF UNICODE} +function SHA3_384UnicodeString(const Str: string): TCnSHA3_384Digest; +{$ELSE} +function SHA3_384UnicodeString(const Str: WideString): TCnSHA3_384Digest; +{$ENDIF} +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// UnicodeString ݽֱӵ SHA3_512 㣬ת +{$IFDEF UNICODE} +function SHA3_512UnicodeString(const Str: string): TCnSHA3_512Digest; +{$ELSE} +function SHA3_512UnicodeString(const Str: WideString): TCnSHA3_512Digest; +{$ENDIF} +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// UnicodeString ݽֱӵ SHAKE128 㣬ת +{$IFDEF UNICODE} +function SHAKE128UnicodeString(const Str: string; DigestByteLength: Cardinal): TBytes; +{$ELSE} +function SHAKE128UnicodeString(const Str: WideString; DigestByteLength: Cardinal): TBytes; +{$ENDIF} +var + Context: TCnSHA3Context; +begin + SHAKE128Init(Context, DigestByteLength); + SHAKE128Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHAKE128Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SHAKE256 㣬ת +{$IFDEF UNICODE} +function SHAKE256UnicodeString(const Str: string; DigestByteLength: Cardinal): TBytes; +{$ELSE} +function SHAKE256UnicodeString(const Str: WideString; DigestByteLength: Cardinal): TBytes; +{$ENDIF} +var + Context: TCnSHA3Context; +begin + SHAKE256Init(Context, DigestByteLength); + SHAKE256Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHAKE256Final(Context, Result); +end; + +// AnsiString ݽSHA224 +function SHA3_224StringA(const Str: AnsiString): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, PAnsiChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// WideString ݽ SHA3_224 +function SHA3_224StringW(const Str: WideString): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// AnsiString ݽ SHA3_256 +function SHA3_256StringA(const Str: AnsiString): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, PAnsiChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// WideString ݽ SHA3_256 +function SHA3_256StringW(const Str: WideString): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// AnsiString ݽ SHA3_384 +function SHA3_384StringA(const Str: AnsiString): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, PAnsiChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// WideString ݽ SHA3_384 +function SHA3_384StringW(const Str: WideString): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// AnsiString ݽ SHA3_512 +function SHA3_512StringA(const Str: AnsiString): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, PAnsiChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// WideString ݽ SHA3_512 +function SHA3_512StringW(const Str: WideString): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// AnsiString ݽ SHAKE128 +function SHAKE128StringA(const Str: AnsiString; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE128Init(Context, DigestByteLength); + SHAKE128Update(Context, PAnsiChar(Str), Length(Str)); + SHAKE128Final(Context, Result); +end; + +// WideString ݽ SHAKE128 +function SHAKE128StringW(const Str: WideString; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE128Init(Context, DigestByteLength); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); // SHAKE128UpdateW = SHA3UpdateW + SHAKE128Final(Context, Result); +end; + +// AnsiString ݽ SHAKE256 +function SHAKE256StringA(const Str: AnsiString; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE256Init(Context, DigestByteLength); + SHAKE256Update(Context, PAnsiChar(Str), Length(Str)); + SHAKE256Final(Context, Result); +end; + +// WideString ݽ SHAKE256 +function SHAKE256StringW(const Str: WideString; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE256Init(Context, DigestByteLength); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); // SHAKE256UpdateW = SHA3UpdateW + SHAKE256Final(Context, Result); +end; + +// SHA3Type ֻ stSHA3_224, stSHA3_256, stSHA3_384, stSHA3_512 +function InternalSHA3Stream(Stream: TStream; const BufSize: Cardinal; var D: + TCnSHA3GeneralDigest; SHA3Type: TSHA3Type; CallBack: TCnSHA3CalcProgressFunc): Boolean; overload; +var + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; + Context: TCnSHA3Context; +begin + Result := False; + Size := Stream.Size; + SavePos := Stream.Position; + TotalBytes := 0; + if Size = 0 then + Exit; + if Size < BufSize then + BufLen := Size + else + BufLen := BufSize; + + CancelCalc := False; + SHA3Init(Context, SHA3Type); + + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + SHA3Update(Context, Buf, ReadBytes); + + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then + Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + SHA3Final(Context, D); + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +// SHA3Type ֻ stSHAKE128 stSHAKE256 +function InternalSHA3Stream(Stream: TStream; const BufSize: Cardinal; + SHA3Type: TSHA3Type; DigestByteLength: Cardinal; out D: TBytes; + CallBack: TCnSHA3CalcProgressFunc): Boolean; overload; +var + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; + Context: TCnSHA3Context; +begin + Result := False; + Size := Stream.Size; + SavePos := Stream.Position; + TotalBytes := 0; + if Size = 0 then + Exit; + if Size < BufSize then + BufLen := Size + else + BufLen := BufSize; + + CancelCalc := False; + SHA3Init(Context, SHA3Type, DigestByteLength); + + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + SHA3Update(Context, Buf, ReadBytes); + + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then + Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + SHA3Final(Context, D); + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +// ָ SHA3_224 +function SHA3_224Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_224Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Dig, stSHA3_224, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_224Digest)); +end; + +// ָ SHA3_256 +function SHA3_256Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_256Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Dig, stSHA3_256, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_256Digest)); +end; + +// ָ SHA3_384 +function SHA3_384Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_384Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Dig, stSHA3_384, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_384Digest)); +end; + +// ָ SHA3_512 +function SHA3_512Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_512Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Dig, stSHA3_512, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_512Digest)); +end; + +// ָӴճȿɱ SHAKE128 +function SHAKE128Stream(Stream: TStream; DigestByteLength: Cardinal; + CallBack: TCnSHA3CalcProgressFunc): TBytes; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, stSHAKE128, DigestByteLength, Result, CallBack); +end; + +// ָӴճȿɱ SHAKE256 +function SHAKE256Stream(Stream: TStream; DigestByteLength: Cardinal; + CallBack: TCnSHA3CalcProgressFunc): TBytes; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, stSHAKE256, DigestByteLength, Result, CallBack); +end; + +function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; +{$IFDEF MSWINDOWS} +var + H: THandle; + Info: BY_HANDLE_FILE_INFORMATION; + Rec: Int64Rec; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + Result := False; + IsEmpty := False; + H := CreateFile(PChar(AFileName), GENERIC_READ, FILE_SHARE_READ, nil, + OPEN_EXISTING, 0, 0); + if H = INVALID_HANDLE_VALUE then + Exit; + try + if not GetFileInformationByHandle(H, Info) then + Exit; + finally + CloseHandle(H); + end; + Rec.Lo := Info.nFileSizeLow; + Rec.Hi := Info.nFileSizeHigh; + Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); + IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); +{$ELSE} + Result := True; // Windows ƽ̨ Trueʾ Mapping +{$ENDIF} +end; + +function InternalSHA3File(const FileName: string; SHA3Type: TSHA3Type; + CallBack: TCnSHA3CalcProgressFunc): TCnSHA3GeneralDigest; overload; +var +{$IFDEF MSWINDOWS} + Context: TCnSHA3Context; + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Result, SHA3Type, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + SHA3Init(Context, SHA3Type); + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + SHA3Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise ECnNativeException.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise ECnNativeException.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + SHA3Final(Context, Result); +{$ENDIF} + end; +end; + +function InternalSHA3File(const FileName: string; SHA3Type: TSHA3Type; + DigestByteLength: Cardinal; CallBack: TCnSHA3CalcProgressFunc): TBytes; overload; +var +{$IFDEF MSWINDOWS} + Context: TCnSHA3Context; + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, SHA3Type, DigestByteLength, Result, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + SHA3Init(Context, SHA3Type, DigestByteLength); + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + SHA3Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise ECnNativeException.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise ECnNativeException.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + SHA3Final(Context, Result); +{$ENDIF} + end; +end; + +// ָļݽ SHA3_224 +function SHA3_224File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_224Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + Dig := InternalSHA3File(FileName, stSHA3_224, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_224Digest)); +end; + +// ָļݽ SHA3_256 +function SHA3_256File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_256Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + Dig := InternalSHA3File(FileName, stSHA3_256, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_256Digest)); +end; + +// ָļݽ SHA3_384 +function SHA3_384File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_384Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + Dig := InternalSHA3File(FileName, stSHA3_384, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_384Digest)); +end; + +// ָļݽ SHA3_512 +function SHA3_512File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_512Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + Dig := InternalSHA3File(FileName, stSHA3_512, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_512Digest)); +end; + +// ָļݽӴճȿɱ SHAKE128 +function SHAKE128File(const FileName: string; DigestByteLength: Cardinal; + CallBack: TCnSHA3CalcProgressFunc): TBytes; +begin + Result := InternalSHA3File(FileName, stSHAKE128, DigestByteLength, CallBack); +end; + +// ָļݽӴճȿɱ SHAKE256 +function SHAKE256File(const FileName: string; DigestByteLength: Cardinal; + CallBack: TCnSHA3CalcProgressFunc): TBytes; +begin + Result := InternalSHA3File(FileName, stSHAKE256, DigestByteLength, CallBack); +end; + +// ʮƸʽ SHA3_224 Ӵֵ +function SHA3_224Print(const Digest: TCnSHA3_224Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA3_224Digest)); +end; + +// ʮƸʽ SHA3_256 Ӵֵ +function SHA3_256Print(const Digest: TCnSHA3_256Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA3_256Digest)); +end; + +// ʮƸʽ SHA3_384 Ӵֵ +function SHA3_384Print(const Digest: TCnSHA3_384Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA3_384Digest)); +end; + +// ʮƸʽ SHA3_512 Ӵֵ +function SHA3_512Print(const Digest: TCnSHA3_512Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA3_512Digest)); +end; + +// ʮƸʽ SHAKE128 Ӵֵ +function SHAKE128Print(const Digest: TBytes): string; +begin + Result := BytesToHex(Digest); +end; + +// ʮƸʽ SHAKE256 Ӵֵ +function SHAKE256Print(const Digest: TBytes): string; +begin + Result := BytesToHex(Digest); +end; + +// Ƚ SHA3_224 ӴֵǷ +function SHA3_224Match(const D1, D2: TCnSHA3_224Digest): Boolean; +begin + Result := ConstTimeCompareMem(@D1[0], @D2[0], SizeOf(TCnSHA3_224Digest)); +end; + +// Ƚ SHA3_256 ӴֵǷ +function SHA3_256Match(const D1, D2: TCnSHA3_256Digest): Boolean; +begin + Result := ConstTimeCompareMem(@D1[0], @D2[0], SizeOf(TCnSHA3_256Digest)); +end; + +// Ƚ SHA3_384 ӴֵǷ +function SHA3_384Match(const D1, D2: TCnSHA3_384Digest): Boolean; +begin + Result := ConstTimeCompareMem(@D1[0], @D2[0], SizeOf(TCnSHA3_384Digest)); +end; + +// Ƚ SHA3_512 ӴֵǷ +function SHA3_512Match(const D1, D2: TCnSHA3_512Digest): Boolean; +begin + Result := ConstTimeCompareMem(@D1[0], @D2[0], SizeOf(TCnSHA3_512Digest)); +end; + +// Ƚ SHAKE128 ӴֵǷ +function SHAKE128Match(const D1, D2: TBytes): Boolean; +begin + Result := ConstTimeCompareBytes(D1, D2); +end; + +// Ƚ SHAKE256 ӴֵǷ +function SHAKE256Match(const D1, D2: TBytes): Boolean; +begin + Result := ConstTimeCompareBytes(D1, D2); +end; + +// SHA3_224 Ӵֵת string +function SHA3_224DigestToStr(const Digest: TCnSHA3_224Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA3_224Digest)); +end; + +// SHA3_256 Ӵֵת string +function SHA3_256DigestToStr(const Digest: TCnSHA3_256Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA3_256Digest));; +end; + +// SHA3_384 Ӵֵת string +function SHA3_384DigestToStr(const Digest: TCnSHA3_384Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA3_384Digest)); +end; + +// SHA3_512 Ӵֵת string +function SHA3_512DigestToStr(const Digest: TCnSHA3_512Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA3_512Digest)); +end; + +// SHAKE128 Ӵֵת string +function SHAKE128DigestToStr(const Digest: TBytes): string; +begin + Result := BytesToString(Digest); +end; + +// SHAKE256 Ӵֵת string +function SHAKE256DigestToStr(const Digest: TBytes): string; +begin + Result := BytesToString(Digest); +end; + +procedure SHA3_224HmacInit(var Context: TCnSHA3Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA3_224Digest; +begin + if KeyLength > HMAC_SHA3_224_BLOCK_SIZE_BYTE then + begin + Sum := SHA3_224Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA3_224_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA3_224_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA3_224_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, @(Context.Ipad[0]), HMAC_SHA3_224_BLOCK_SIZE_BYTE); +end; + +procedure SHA3_256HmacInit(var Context: TCnSHA3Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA3_256Digest; +begin + if KeyLength > HMAC_SHA3_256_BLOCK_SIZE_BYTE then + begin + Sum := SHA3_256Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA3_256_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA3_256_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA3_256_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, @(Context.Ipad[0]), HMAC_SHA3_256_BLOCK_SIZE_BYTE); +end; + +procedure SHA3_384HmacInit(var Context: TCnSHA3Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA3_384Digest; +begin + if KeyLength > HMAC_SHA3_384_BLOCK_SIZE_BYTE then + begin + Sum := SHA3_384Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA3_384_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA3_384_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA3_384_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, @(Context.Ipad[0]), HMAC_SHA3_384_BLOCK_SIZE_BYTE); +end; + +procedure SHA3_512HmacInit(var Context: TCnSHA3Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA3_512Digest; +begin + if KeyLength > HMAC_SHA3_512_BLOCK_SIZE_BYTE then + begin + Sum := SHA3_512Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA3_512_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA3_512_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA3_512_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, @(Context.Ipad[0]), HMAC_SHA3_512_BLOCK_SIZE_BYTE); +end; + +procedure SHA3_224HmacUpdate(var Context: TCnSHA3Context; Input: PAnsiChar; + ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_256HmacUpdate(var Context: TCnSHA3Context; Input: PAnsiChar; + ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_384HmacUpdate(var Context: TCnSHA3Context; Input: PAnsiChar; + ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_512HmacUpdate(var Context: TCnSHA3Context; Input: PAnsiChar; + ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_224HmacFinal(var Context: TCnSHA3Context; var Output: TCnSHA3GeneralDigest); +var + Len: Integer; + TmpBuf: TCnSHA3GeneralDigest; +begin + Len := HMAC_SHA3_224_OUTPUT_LENGTH_BYTE; + SHA3Final(Context, TmpBuf); + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, @(Context.Opad[0]), HMAC_SHA3_224_BLOCK_SIZE_BYTE); + SHA3Update(Context, @(TmpBuf[0]), Len); + SHA3Final(Context, Output); +end; + +procedure SHA3_256HmacFinal(var Context: TCnSHA3Context; var Output: TCnSHA3GeneralDigest); +var + Len: Integer; + TmpBuf: TCnSHA3GeneralDigest; +begin + Len := HMAC_SHA3_256_OUTPUT_LENGTH_BYTE; + SHA3Final(Context, TmpBuf); + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, @(Context.Opad[0]), HMAC_SHA3_256_BLOCK_SIZE_BYTE); + SHA3Update(Context, @(TmpBuf[0]), Len); + SHA3Final(Context, Output); +end; + +procedure SHA3_384HmacFinal(var Context: TCnSHA3Context; var Output: TCnSHA3GeneralDigest); +var + Len: Integer; + TmpBuf: TCnSHA3GeneralDigest; +begin + Len := HMAC_SHA3_384_OUTPUT_LENGTH_BYTE; + SHA3Final(Context, TmpBuf); + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, @(Context.Opad[0]), HMAC_SHA3_384_BLOCK_SIZE_BYTE); + SHA3Update(Context, @(TmpBuf[0]), Len); + SHA3Final(Context, Output); +end; + +procedure SHA3_512HmacFinal(var Context: TCnSHA3Context; var Output: TCnSHA3GeneralDigest); +var + Len: Integer; + TmpBuf: TCnSHA3GeneralDigest; +begin + Len := HMAC_SHA3_512_OUTPUT_LENGTH_BYTE; + SHA3Final(Context, TmpBuf); + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, @(Context.Opad[0]), HMAC_SHA3_512_BLOCK_SIZE_BYTE); + SHA3Update(Context, @(TmpBuf[0]), Len); + SHA3Final(Context, Output); +end; + +procedure SHA3_224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_224Digest); +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_224HmacInit(Context, Key, KeyByteLength); + SHA3_224HmacUpdate(Context, Input, ByteLength); + SHA3_224HmacFinal(Context, Dig); + Move(Dig[0], Output[0], Context.DigestLen); +end; + +procedure SHA3_256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_256Digest); +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_256HmacInit(Context, Key, KeyByteLength); + SHA3_256HmacUpdate(Context, Input, ByteLength); + SHA3_256HmacFinal(Context, Dig); + Move(Dig[0], Output[0], Context.DigestLen); +end; + +procedure SHA3_384Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_384Digest); +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_384HmacInit(Context, Key, KeyByteLength); + SHA3_384HmacUpdate(Context, Input, ByteLength); + SHA3_384HmacFinal(Context, Dig); + Move(Dig[0], Output[0], Context.DigestLen); +end; + +procedure SHA3_512Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_512Digest); +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_512HmacInit(Context, Key, KeyByteLength); + SHA3_512HmacUpdate(Context, Input, ByteLength); + SHA3_512HmacFinal(Context, Dig); + Move(Dig[0], Output[0], Context.DigestLen); +end; + +function SHA3_224HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_224HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA3_224HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3_224HmacFinal(Context, Dig); + Move(Dig[0], Result[0], Context.DigestLen); +end; + +function SHA3_256HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_256HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA3_256HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3_256HmacFinal(Context, Dig); + Move(Dig[0], Result[0], Context.DigestLen); +end; + +function SHA3_384HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_384HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA3_384HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3_384HmacFinal(Context, Dig); + Move(Dig[0], Result[0], Context.DigestLen); +end; + +function SHA3_512HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_512HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA3_512HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3_512HmacFinal(Context, Dig); + Move(Dig[0], Result[0], Context.DigestLen); +end; + +end. diff --git a/CnPack/Crypto/CnSM3.pas b/CnPack/Crypto/CnSM3.pas index 53106c6..c8623de 100644 --- a/CnPack/Crypto/CnSM3.pas +++ b/CnPack/Crypto/CnSM3.pas @@ -1,829 +1,842 @@ -{******************************************************************************} -{ CnPack For Delphi/C++Builder } -{ йԼĿԴ } -{ (C)Copyright 2001-2025 CnPack } -{ ------------------------------------ } -{ } -{ ǿԴ CnPack ķЭ } -{ ĺ·һ } -{ } -{ һĿϣãûκεû } -{ ʺضĿĶĵϸ CnPack Э顣 } -{ } -{ ӦѾͿһյһ CnPack Эĸ } -{ ûУɷǵվ } -{ } -{ վַhttps://www.cnpack.org } -{ ʼmaster@cnpack.org } -{ } -{******************************************************************************} - -unit CnSM3; -{* |
-================================================================================
-* ƣ
-* Ԫƣ SM3 Ӵ㷨ʵֵԪ
-* ԪߣCnPack 飨master@cnpack.org)
-*           οֲ goldboar  C 
-*     עԪʵ˹ SM3 Ӵ㷨Ӧ HMAC 㷨
-*           ο㷨ĵSM3 Cryptographic Hash Algorith
-*           http://www.oscca.gov.cn/UpFile/20101222141857786.pdf
-*
-* ƽ̨Windows 7 + Delphi 5.0
-* ݲԣPWin9X/2000/XP/7 + Delphi 5/6
-*   õԪеַϱػʽ
-* ޸ļ¼2019.12.12 V1.2
-*               ֧ TBytes
-*           2019.04.15 V1.1
-*               ֧ Win32/Win64/MacOS
-*           2014.09.23 V1.0
-*               ֲԪ
-================================================================================
-|
} - -interface - -{$I CnPack.inc} - -uses - Classes, SysUtils, CnNative, CnConsts {$IFDEF MSWINDOWS}, Windows {$ENDIF}; - -type - PCnSM3Digest = ^TCnSM3Digest; - TCnSM3Digest = array[0..31] of Byte; - {* SM3 Ӵս32 ֽ} - - TCnSM3Context = packed record - {* SM3 Ľṹ} - Total: array[0..1] of Cardinal; {!< number of bytes processed } - State: array[0..7] of Cardinal; {!< intermediate digest state } - Buffer: array[0..63] of Byte; {!< data block being processed } - Ipad: array[0..63] of Byte; {!< HMAC: inner padding } - Opad: array[0..63] of Byte; {!< HMAC: outer padding } - end; - PCnSM3Context = ^TCnSM3Context; - - TCnSM3CalcProgressFunc = procedure (ATotal, AProgress: Int64; - var Cancel: Boolean) of object; - {* SM3 ӴսȻص¼} - -function SM3(Input: PAnsiChar; ByteLength: Cardinal): TCnSM3Digest; -{* ݿ SM3 㡣 - - - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵTCnSM3Digest - ص SM3 Ӵֵ - - } - -function SM3Buffer(const Buffer; Count: Cardinal): TCnSM3Digest; -{* ݿ SM3 㡣 - - - const Buffer - ݿַ - Count: Cardinal - ݿֽڳ - - ֵTCnSM3Digest - ص SM3 Ӵֵ -} - -function SM3Bytes(Data: TBytes): TCnSM3Digest; -{* ֽ SM3 㡣 - - - Data: TBytes - ֽ - - ֵTCnSM3Digest - ص SM3 Ӵֵ -} - -function SM3String(const Str: string): TCnSM3Digest; -{* String ݽ SM3 㣬ע D2009 ϰ汾 string Ϊ UnicodeString - лὫǿת AnsiString м㡣 - - - const Str: string - ַ - - ֵTCnSM3Digest - ص SM3 Ӵֵ -} - -function SM3StringA(const Str: AnsiString): TCnSM3Digest; -{* AnsiString ݽ SM3 㡣 - - - const Str: AnsiString - ַ - - ֵTCnSM3Digest - ص SM3 Ӵֵ -} - -function SM3StringW(const Str: WideString): TCnSM3Digest; -{* WideString ַת SM3 㡣 - ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ - ƽֱ̨תΪ AnsiString ͣٽм㡣 - - - const Str: WideString - Ŀַ - - ֵTCnSM3Digest - ص SM3 Ӵֵ -} - -{$IFDEF UNICODE} - -function SM3UnicodeString(const Str: string): TCnSM3Digest; -{* UnicodeString ݽֱӵ SM3 㣬ֱӼڲ UTF16 ݣת - - - const Str: string - Ŀַ - - ֵTCnSM3Digest - ص SM3 Ӵֵ -} - -{$ELSE} - -function SM3UnicodeString(const Str: WideString): TCnSM3Digest; -{* UnicodeString ݽֱӵ SM3 㣬ֱӼڲ UTF16 ݣת - - - const Str: WideString - Ŀַ - - ֵTCnSM3Digest - ص SM3 Ӵֵ -} - -{$ENDIF} - -function SM3File(const FileName: string; CallBack: TCnSM3CalcProgressFunc = nil): TCnSM3Digest; -{* ָļݽ SM3 㡣 - - - const FileName: string - ļ - CallBack: TCnSM3CalcProgressFunc - ȻصĬΪ - - ֵTCnSM3Digest - ص SM3 Ӵֵ -} - -function SM3Stream(Stream: TStream; CallBack: TCnSM3CalcProgressFunc = nil): TCnSM3Digest; -{* ָݽ SM3 㡣 - - - Stream: TStream - - CallBack: TCnSM3CalcProgressFunc - ȻصĬΪ - - ֵTCnSM3Digest - ص SM3 Ӵֵ -} - -// ⲿݽɢ SM3 㣬SM3Update ɶα - -procedure SM3Init(var Context: TCnSM3Context); -{* ʼһ SM3 ģ׼ SM3 - - - var Context: TCnSM3Context - ʼ SM3 - - ֵޣ -} - -procedure SM3Update(var Context: TCnSM3Context; Input: PAnsiChar; ByteLength: Cardinal); -{* ԳʼĶһݽ SM3 㡣 - ɶε㲻ͬݿ飬轫ͬݿƴڴС - - - var Context: TCnSM3Context - SM3 - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - - ֵޣ -} - -procedure SM3Final(var Context: TCnSM3Context; var Digest: TCnSM3Digest); -{* ּ㣬 SM3 Digest - - - var Context: TCnSM3Context - SM3 - var Digest: TCnSM3Digest - ص SM3 Ӵֵ - - ֵޣ -} - -function SM3Print(const Digest: TCnSM3Digest): string; -{* ʮƸʽ SM3 Ӵֵ - - - const Digest: TCnSM3Digest - ָ SM3 Ӵֵ - - ֵstring - ʮַ -} - -function SM3Match(const D1: TCnSM3Digest; const D2: TCnSM3Digest): Boolean; -{* Ƚ SM3 ӴֵǷȡ - - - const D1: TCnSM3Digest - Ƚϵ SM3 Ӵֵһ - const D2: TCnSM3Digest - Ƚϵ SM3 Ӵֵ - - ֵBoolean - Ƿ -} - -function SM3DigestToStr(const Digest: TCnSM3Digest): string; -{* SM3 Ӵֱֵת stringÿֽڶӦһַ - - - const Digest: TCnSM3Digest - ת SM3 Ӵֵ - - ֵstring - صַ -} - -procedure SM3Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSM3Digest); -{* SM3 HMACHash-based Message Authentication Code㣬 - ͨݵļϼԿĸҲмΡ - - - Key: PAnsiChar - SM3 Կݿַ - KeyByteLength: Integer - SM3 Կݿֽڳ - Input: PAnsiChar - ݿַ - ByteLength: Cardinal - ݿֽڳ - var Output: TCnSM3Digest - ص SM3 Ӵֵ - - ֵޣ -} - -implementation - -const - SM3Padding: array[0..63] of Byte = - ( - $80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ); - - SM3_T: array[0..63] of Cardinal = ( - $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, - $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, - $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, - $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, - $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, - $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, - $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, - $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A - ); - - MAX_FILE_SIZE = 512 * 1024 * 1024; - // If file size <= this size (bytes), using Mapping, else stream - - HMAC_SM3_BLOCK_SIZE_BYTE = 64; - HMAC_SM3_OUTPUT_LENGTH_BYTE = 32; - -type - TSM3ProcessData = array[0..63] of Byte; - -procedure GetULongBe(var N: Cardinal; B: PAnsiChar; I: Integer); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -var - D: Cardinal; -begin - D := (Cardinal(B[I]) shl 24) or (Cardinal(B[I + 1]) shl 16) or - (Cardinal(B[I + 2]) shl 8) or (Cardinal(B[I + 3])); - N := D; -end; - -procedure PutULongBe(N: Cardinal; B: PAnsiChar; I: Integer); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - B[I] := AnsiChar(N shr 24); - B[I + 1] := AnsiChar(N shr 16); - B[I + 2] := AnsiChar(N shr 8); - B[I + 3] := AnsiChar(N); -end; - -function FF0(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := X xor Y xor Z; -end; - -function FF1(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := (X and Y) or (Y and Z) or (X and Z); -end; - -function GG0(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := X xor Y xor Z; -end; - -function GG1(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := (X and Y) or ((not X) and Z); -end; - -function SM3Shl(X: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := (X and $FFFFFFFF) shl N; -end; - -// ѭơע N Ϊ 0 32 ʱֵΪ XN Ϊ 33 ʱֵ N Ϊ 1 ʱķֵ -function ROTL(X: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := SM3Shl(X, N) or (X shr (32 - N)); -end; - -function P0(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := X xor ROTL(X, 9) xor ROTL(X, 17); -end; - -function P1(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} -begin - Result := X xor ROTL(X, 15) xor ROTL(X, 23); -end; - -procedure SM3Init(var Context: TCnSM3Context); -begin - Context.Total[0] := 0; - Context.Total[1] := 0; - - Context.State[0] := $7380166F; - Context.State[1] := $4914B2B9; - Context.State[2] := $172442D7; - Context.State[3] := $DA8A0600; - Context.State[4] := $A96F30BC; - Context.State[5] := $163138AA; - Context.State[6] := $E38DEE4D; - Context.State[7] := $B0FB0E4E; - - FillChar(Context.Buffer, SizeOf(Context.Buffer), 0); -end; - -// һδ 64 ֽҲ 512 λݿ -procedure SM3Process(var Context: TCnSM3Context; Data: PAnsiChar); -var - SS1, SS2, TT1, TT2: Cardinal; - W: array[0..67] of Cardinal; - W1: array[0..63] of Cardinal; - A, B, C, D, E, F, G, H: Cardinal; - Temp1, Temp2: Cardinal; - J: Integer; -begin - GetULongBe(W[ 0], Data, 0); - GetULongBe(W[ 1], Data, 4); - GetULongBe(W[ 2], Data, 8); - GetULongBe(W[ 3], Data, 12); - GetULongBe(W[ 4], Data, 16); - GetULongBe(W[ 5], Data, 20); - GetULongBe(W[ 6], Data, 24); - GetULongBe(W[ 7], Data, 28); - GetULongBe(W[ 8], Data, 32); - GetULongBe(W[ 9], Data, 36); - GetULongBe(W[10], Data, 40); - GetULongBe(W[11], Data, 44); - GetULongBe(W[12], Data, 48); - GetULongBe(W[13], Data, 52); - GetULongBe(W[14], Data, 56); - GetULongBe(W[15], Data, 60); - - for J := 16 to 67 do - begin - Temp1 := W[J - 16] xor W[J - 9]; - Temp2 := ROTL(W[J - 3], 15); - W[J] := P1(Temp1 xor Temp2) xor (ROTL(W[J - 13], 7) xor W[J - 6]); - end; - - for J := 0 to 63 do - W1[J] := W[J] xor W[J + 4]; - - // ѾW/W1ֵ - - A := Context.State[0]; - B := Context.State[1]; - C := Context.State[2]; - D := Context.State[3]; - E := Context.State[4]; - F := Context.State[5]; - G := Context.State[6]; - H := Context.State[7]; - - for J := 0 to 15 do - begin - SS1 := ROTL((ROTL(A, 12) + E + ROTL(SM3_T[J], J)), 7); - SS2 := SS1 xor ROTL(A, 12); - TT1 := FF0(A, B, C) + D + SS2 + W1[J]; - TT2 := GG0(E, F, G) + H + SS1 + W[J]; - D := C; - C := ROTL(B, 9); - B := A; - A := TT1; - H := G; - G := ROTL(F, 19); - F := E; - E := P0(TT2); - end; - - for J := 16 to 63 do - begin - SS1 := ROTL((ROTL(A, 12) + E + ROTL(SM3_T[J], J)), 7); - SS2 := SS1 xor ROTL(A, 12); - TT1 := FF1(A, B, C) + D + SS2 + W1[J]; - TT2 := GG1(E, F, G) + H + SS1 + W[J]; - D := C; - C := ROTL(B,9); - B := A; - A := TT1; - H := G; - G := ROTL(F,19); - F := E; - E := P0(TT2); - end; - - Context.State[0] := Context.State[0] xor A; - Context.State[1] := Context.State[1] xor B; - Context.State[2] := Context.State[2] xor C; - Context.State[3] := Context.State[3] xor D; - Context.State[4] := Context.State[4] xor E; - Context.State[5] := Context.State[5] xor F; - Context.State[6] := Context.State[6] xor G; - Context.State[7] := Context.State[7] xor H; - - // -end; - -procedure SM3UpdateW(var Context: TCnSM3Context; Input: PWideChar; CharLength: Cardinal); -var -{$IFDEF MSWINDOWS} - pContent: PAnsiChar; - iLen: Cardinal; -{$ELSE} - S: string; // UnicodeString - A: AnsiString; -{$ENDIF} -begin -{$IFDEF MSWINDOWS} - GetMem(pContent, CharLength * SizeOf(WideChar)); - try - iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 - PAnsiChar(pContent), CharLength * SizeOf(WideChar), nil, nil); - SM3Update(Context, pContent, iLen); - finally - FreeMem(pContent); - end; -{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ - S := StrNew(Input); - A := AnsiString(S); - SM3Update(Context, @A[1], Length(A)); -{$ENDIF} -end; - -procedure SM3Update(var Context: TCnSM3Context; Input: PAnsiChar; ByteLength: Cardinal); -var - Fill, Left: Cardinal; -begin - if (Input = nil) or (ByteLength <= 0) then - Exit; - - Left := Context.Total[0] and $3F; - Fill := 64 - Left; - - Context.Total[0] := Context.Total[0] + ByteLength; - Context.Total[0] := Context.Total[0] and $FFFFFFFF; - - if Context.Total[0] < ByteLength then - Context.Total[1] := Context.Total[1] + 1; - - if (Left <> 0) and (ByteLength >= Fill) then - begin - Move(Input^, Context.Buffer[Left], Fill); - SM3Process(Context, @(Context.Buffer[0])); - Input := Input + Fill; - ByteLength := ByteLength - Fill; - Left := 0; - end; - - while ByteLength >= 64 do - begin - SM3Process(Context, Input); - Input := Input + 64; - ByteLength := ByteLength - 64; - end; - - if ByteLength > 0 then - Move(Input^, Context.Buffer[Left], ByteLength); -end; - -procedure SM3Final(var Context: TCnSM3Context; var Digest: TCnSM3Digest); -var - Last, Padn: Cardinal; - High, Low: Cardinal; - MsgLen: array[0..7] of Byte; -begin - High := (Context.Total[0] shr 29) or (Context.Total[1] shl 3); - Low := Context.Total[0] shl 3; - - PutULongBe(High, @(MsgLen[0]), 0); - PutULongBe(Low, @(MsgLen[0]), 4); - - Last := Context.Total[0] and $3F; - if Last < 56 then - Padn := 56 - Last - else - Padn := 120 - Last; - - SM3Update(Context, @(SM3Padding[0]), Padn); - SM3Update(Context, @(MsgLen[0]), 8); - - PutULongBe(Context.State[0], @Digest, 0); - PutULongBe(Context.State[1], @Digest, 4); - PutULongBe(Context.State[2], @Digest, 8); - PutULongBe(Context.State[3], @Digest, 12); - PutULongBe(Context.State[4], @Digest, 16); - PutULongBe(Context.State[5], @Digest, 20); - PutULongBe(Context.State[6], @Digest, 24); - PutULongBe(Context.State[7], @Digest, 28); -end; - -function SM3(Input: PAnsiChar; ByteLength: Cardinal): TCnSM3Digest; -var - Ctx: TCnSM3Context; -begin - SM3Init(Ctx); - SM3Update(Ctx, Input, ByteLength); - SM3Final(Ctx, Result); -end; - -procedure SM3HmacStarts(var Ctx: TCnSM3Context; Key: PAnsiChar; KeyLength: Integer); -var - I: Integer; - Sum: TCnSM3Digest; -begin - if KeyLength > HMAC_SM3_BLOCK_SIZE_BYTE then - begin - Sum := SM3(Key, KeyLength); - KeyLength := HMAC_SM3_OUTPUT_LENGTH_BYTE; - Key := @(Sum[0]); - end; - - FillChar(Ctx.Ipad, HMAC_SM3_BLOCK_SIZE_BYTE, $36); - FillChar(Ctx.Opad, HMAC_SM3_BLOCK_SIZE_BYTE, $5C); - - for I := 0 to KeyLength - 1 do - begin - Ctx.Ipad[I] := Byte(Ctx.Ipad[I] xor Byte(Key[I])); - Ctx.Opad[I] := Byte(Ctx.Opad[I] xor Byte(Key[I])); - end; - - SM3Init(Ctx); - SM3Update(Ctx, @(Ctx.Ipad[0]), HMAC_SM3_BLOCK_SIZE_BYTE); -end; - -procedure SM3HmacUpdate(var Ctx: TCnSM3Context; Input: PAnsiChar; Length: Cardinal); -begin - SM3Update(Ctx, Input, Length); -end; - -procedure SM3HmacFinish(var Ctx: TCnSM3Context; var Output: TCnSM3Digest); -var - Len: Integer; - TmpBuf: TCnSM3Digest; -begin - Len := HMAC_SM3_OUTPUT_LENGTH_BYTE; - SM3Final(Ctx, TmpBuf); - SM3Init(Ctx); - SM3Update(Ctx, @(Ctx.Opad[0]), HMAC_SM3_BLOCK_SIZE_BYTE); - SM3Update(Ctx, @(TmpBuf[0]), Len); - SM3Final(Ctx, Output); -end; - -procedure SM3Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; - ByteLength: Cardinal; var Output: TCnSM3Digest); -var - Ctx: TCnSM3Context; -begin - SM3HmacStarts(Ctx, Key, KeyByteLength); - SM3HmacUpdate(Ctx, Input, ByteLength); - SM3HmacFinish(Ctx, Output); -end; - -function SM3Buffer(const Buffer; Count: Cardinal): TCnSM3Digest; -var - Context: TCnSM3Context; -begin - SM3Init(Context); - SM3Update(Context, PAnsiChar(Buffer), Count); - SM3Final(Context, Result); -end; - -function SM3Bytes(Data: TBytes): TCnSM3Digest; -var - Context: TCnSM3Context; -begin - SM3Init(Context); - SM3Update(Context, PAnsiChar(@Data[0]), Length(Data)); - SM3Final(Context, Result); -end; - -// String ݽ SM3 ת -function SM3String(const Str: string): TCnSM3Digest; -var - AStr: AnsiString; -begin - AStr := AnsiString(Str); - Result := SM3StringA(AStr); -end; - -// AnsiString ݽ SM3 ת -function SM3StringA(const Str: AnsiString): TCnSM3Digest; -var - Context: TCnSM3Context; -begin - SM3Init(Context); - SM3Update(Context, PAnsiChar(Str), Length(Str)); - SM3Final(Context, Result); -end; - -// WideString ݽ SM3 ת -function SM3StringW(const Str: WideString): TCnSM3Digest; -var - Context: TCnSM3Context; -begin - SM3Init(Context); - SM3UpdateW(Context, PWideChar(Str), Length(Str)); - SM3Final(Context, Result); -end; - -// UnicodeString ݽֱӵ SM3 㣬ת -{$IFDEF UNICODE} -function SM3UnicodeString(const Str: string): TCnSM3Digest; -{$ELSE} -function SM3UnicodeString(const Str: WideString): TCnSM3Digest; -{$ENDIF} -var - Context: TCnSM3Context; -begin - SM3Init(Context); - SM3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); - SM3Final(Context, Result); -end; - -function InternalSM3Stream(Stream: TStream; const BufSize: Cardinal; var D: - TCnSM3Digest; CallBack: TCnSM3CalcProgressFunc = nil): Boolean; -var - Context: TCnSM3Context; - Buf: PAnsiChar; - BufLen: Cardinal; - Size: Int64; - ReadBytes: Cardinal; - TotalBytes: Int64; - SavePos: Int64; - CancelCalc: Boolean; -begin - Result := False; - Size := Stream.Size; - SavePos := Stream.Position; - TotalBytes := 0; - if Size = 0 then Exit; - if Size < BufSize then BufLen := Size - else BufLen := BufSize; - - CancelCalc := False; - SM3Init(Context); - GetMem(Buf, BufLen); - try - Stream.Position := 0; - repeat - ReadBytes := Stream.Read(Buf^, BufLen); - if ReadBytes <> 0 then - begin - Inc(TotalBytes, ReadBytes); - SM3Update(Context, Buf, ReadBytes); - if Assigned(CallBack) then - begin - CallBack(Size, TotalBytes, CancelCalc); - if CancelCalc then Exit; - end; - end; - until (ReadBytes = 0) or (TotalBytes = Size); - SM3Final(Context, D); - Result := True; - finally - FreeMem(Buf, BufLen); - Stream.Position := SavePos; - end; -end; - -// ָļݽSM3ת -function SM3File(const FileName: string; - CallBack: TCnSM3CalcProgressFunc): TCnSM3Digest; -var -{$IFDEF MSWINDOWS} - FileHandle: THandle; - MapHandle: THandle; - ViewPointer: Pointer; - Context: TCnSM3Context; -{$ENDIF} - Stream: TStream; - FileIsZeroSize: Boolean; - - function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; -{$IFDEF MSWINDOWS} - var - H: THandle; - Info: BY_HANDLE_FILE_INFORMATION; - Rec : Int64Rec; -{$ENDIF} - begin -{$IFDEF MSWINDOWS} - Result := False; - IsEmpty := False; - H := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); - if H = INVALID_HANDLE_VALUE then Exit; - try - if not GetFileInformationByHandle(H, Info) then Exit; - finally - CloseHandle(H); - end; - Rec.Lo := Info.nFileSizeLow; - Rec.Hi := Info.nFileSizeHigh; - Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); - IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); -{$ELSE} - Result := True; // Windows ƽ̨ Trueʾ Mapping -{$ENDIF} - end; - -begin - FileIsZeroSize := False; - if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then - begin - // 2G ļ Map ʧܣ Windows ƽ̨ʽѭ - Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); - try - InternalSM3Stream(Stream, 4096 * 1024, Result, CallBack); - finally - Stream.Free; - end; - end - else - begin -{$IFDEF MSWINDOWS} - SM3Init(Context); - FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or - FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or - FILE_FLAG_SEQUENTIAL_SCAN, 0); - if FileHandle <> INVALID_HANDLE_VALUE then - begin - try - MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); - if MapHandle <> 0 then - begin - try - ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); - if ViewPointer <> nil then - begin - try - SM3Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); - finally - UnmapViewOfFile(ViewPointer); - end; - end - else - begin - raise Exception.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); - end; - finally - CloseHandle(MapHandle); - end; - end - else - begin - if not FileIsZeroSize then - raise Exception.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); - end; - finally - CloseHandle(FileHandle); - end; - end; - SM3Final(Context, Result); -{$ENDIF} - end; -end; - -// ָ SM3 -function SM3Stream(Stream: TStream; - CallBack: TCnSM3CalcProgressFunc = nil): TCnSM3Digest; -begin - InternalSM3Stream(Stream, 4096 * 1024, Result, CallBack); -end; - -function SM3Print(const Digest: TCnSM3Digest): string; -begin - Result := DataToHex(@Digest[0], SizeOf(TCnSM3Digest)); -end; - -function SM3Match(const D1, D2: TCnSM3Digest): Boolean; -begin - Result := CompareMem(@D1[0], @D2[0], SizeOf(TCnSM3Digest)); -end; - -function SM3DigestToStr(const Digest: TCnSM3Digest): string; -begin - Result := MemoryToString(@Digest[0], SizeOf(TCnSM3Digest)); -end; - -end. +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnSM3; +{* |
+================================================================================
+* ƣ
+* Ԫƣ SM3 Ӵ㷨ʵֵԪ
+* ԪߣCnPack 飨master@cnpack.org)
+*           ο㷨ĵSM3 Cryptographic Hash Algorith
+*           http://www.oscca.gov.cn/UpFile/20101222141857786.pdf
+*           ο˲ goldboar  C 
+*     עԪʵ˹ SM3 Ӵ㷨Ӧ HMAC 㷨
+*           ʵֹ̲ο㷨ĵSM3 Cryptographic Hash Algorith
+* ƽ̨Windows 7 + Delphi 5.0
+* ݲԣPWin9X/2000/XP/7 + Delphi 5/6
+*   õԪеַϱػʽ
+* ޸ļ¼2019.12.12 V1.2
+*               ֧ TBytes
+*           2019.04.15 V1.1
+*               ֧ Win32/Win64/MacOS
+*           2014.09.23 V1.0
+*               ֲԪ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + Classes, SysUtils, CnNative, CnConsts {$IFDEF MSWINDOWS}, Windows {$ENDIF}; + +type + PCnSM3Digest = ^TCnSM3Digest; + {* SM3 Ӵսָ} + TCnSM3Digest = array[0..31] of Byte; + {* SM3 Ӵս32 ֽ} + + TCnSM3Context = packed record + {* SM3 Ľṹ} + Total: array[0..1] of Cardinal; {!< number of bytes processed } + State: array[0..7] of Cardinal; {!< intermediate digest state } + Buffer: array[0..63] of Byte; {!< data block being processed } + Ipad: array[0..63] of Byte; {!< HMAC: inner padding } + Opad: array[0..63] of Byte; {!< HMAC: outer padding } + end; + PCnSM3Context = ^TCnSM3Context; + + TCnSM3CalcProgressFunc = procedure (ATotal, AProgress: Int64; + var Cancel: Boolean) of object; + {* SM3 ӴսȻص¼} + +function SM3(Input: PAnsiChar; ByteLength: Cardinal): TCnSM3Digest; +{* ݿ SM3 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3Buffer(const Buffer; Count: Cardinal): TCnSM3Digest; +{* ݿ SM3 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3Bytes(const Data: TBytes): TCnSM3Digest; +{* ֽ SM3 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3String(const Str: string): TCnSM3Digest; +{* String ݽ SM3 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3StringA(const Str: AnsiString): TCnSM3Digest; +{* AnsiString ݽ SM3 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3StringW(const Str: WideString): TCnSM3Digest; +{* WideString ַת SM3 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +{$IFDEF UNICODE} + +function SM3UnicodeString(const Str: string): TCnSM3Digest; +{* UnicodeString ݽֱӵ SM3 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +{$ELSE} + +function SM3UnicodeString(const Str: WideString): TCnSM3Digest; +{* UnicodeString ݽֱӵ SM3 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +{$ENDIF} + +function SM3File(const FileName: string; CallBack: TCnSM3CalcProgressFunc = nil): TCnSM3Digest; +{* ָļݽ SM3 㡣 + + + const FileName: string - ļ + CallBack: TCnSM3CalcProgressFunc - ȻصĬΪ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3Stream(Stream: TStream; CallBack: TCnSM3CalcProgressFunc = nil): TCnSM3Digest; +{* ָݽ SM3 㡣 + + + Stream: TStream - + CallBack: TCnSM3CalcProgressFunc - ȻصĬΪ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +// ⲿݽɢ SM3 㣬SM3Update ɶα + +procedure SM3Init(var Context: TCnSM3Context); +{* ʼһ SM3 ģ׼ SM3 + + + var Context: TCnSM3Context - ʼ SM3 + + ֵޣ +} + +procedure SM3Update(var Context: TCnSM3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SM3 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSM3Context - SM3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SM3Final(var Context: TCnSM3Context; var Digest: TCnSM3Digest); +{* ּ㣬 SM3 Digest + + + var Context: TCnSM3Context - SM3 + var Digest: TCnSM3Digest - ص SM3 Ӵֵ + + ֵޣ +} + +function SM3Print(const Digest: TCnSM3Digest): string; +{* ʮƸʽ SM3 Ӵֵ + + + const Digest: TCnSM3Digest - ָ SM3 Ӵֵ + + ֵstring - ʮַ +} + +function SM3Match(const D1: TCnSM3Digest; const D2: TCnSM3Digest): Boolean; +{* Ƚ SM3 ӴֵǷȡ + + + const D1: TCnSM3Digest - Ƚϵ SM3 Ӵֵһ + const D2: TCnSM3Digest - Ƚϵ SM3 Ӵֵ + + ֵBoolean - Ƿ +} + +function SM3DigestToStr(const Digest: TCnSM3Digest): string; +{* SM3 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSM3Digest - ת SM3 Ӵֵ + + ֵstring - صַ +} + +procedure SM3Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSM3Digest); +{* SM3 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SM3 Կݿַ + KeyByteLength: Integer - SM3 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSM3Digest - ص SM3 Ӵֵ + + ֵޣ +} + +function SM3HmacBytes(const Key: TBytes; const Data: TBytes): TCnSM3Digest; +{* ֽл MD5 HMAC 㡣 + + + const Key: TBytes - SM3 Կֽ + const Data: TBytes - ֽ + + ֵTCnMD5Digest - ص SM3 Ӵֵ +} + +implementation + +const + SM3Padding: array[0..63] of Byte = + ( + $80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ); + + SM3_T: array[0..63] of Cardinal = ( + $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, + $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A + ); + + MAX_FILE_SIZE = 512 * 1024 * 1024; + // If file size <= this size (bytes), using Mapping, else stream + + HMAC_SM3_BLOCK_SIZE_BYTE = 64; + HMAC_SM3_OUTPUT_LENGTH_BYTE = 32; + +type + TSM3ProcessData = array[0..63] of Byte; + +procedure GetULongBe(var N: Cardinal; B: PAnsiChar; I: Integer); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +var + D: Cardinal; +begin + D := (Cardinal(B[I]) shl 24) or (Cardinal(B[I + 1]) shl 16) or + (Cardinal(B[I + 2]) shl 8) or (Cardinal(B[I + 3])); + N := D; +end; + +procedure PutULongBe(N: Cardinal; B: PAnsiChar; I: Integer); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + B[I] := AnsiChar(N shr 24); + B[I + 1] := AnsiChar(N shr 16); + B[I + 2] := AnsiChar(N shr 8); + B[I + 3] := AnsiChar(N); +end; + +function FF0(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor Y xor Z; +end; + +function FF1(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Y) or (Y and Z) or (X and Z); +end; + +function GG0(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor Y xor Z; +end; + +function GG1(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Y) or ((not X) and Z); +end; + +function SM3Shl(X: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and $FFFFFFFF) shl N; +end; + +// ѭơע N Ϊ 0 32 ʱֵΪ XN Ϊ 33 ʱֵ N Ϊ 1 ʱķֵ +function ROTL(X: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := SM3Shl(X, N) or (X shr (32 - N)); +end; + +function P0(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor ROTL(X, 9) xor ROTL(X, 17); +end; + +function P1(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor ROTL(X, 15) xor ROTL(X, 23); +end; + +procedure SM3Init(var Context: TCnSM3Context); +begin + Context.Total[0] := 0; + Context.Total[1] := 0; + + Context.State[0] := $7380166F; + Context.State[1] := $4914B2B9; + Context.State[2] := $172442D7; + Context.State[3] := $DA8A0600; + Context.State[4] := $A96F30BC; + Context.State[5] := $163138AA; + Context.State[6] := $E38DEE4D; + Context.State[7] := $B0FB0E4E; + + FillChar(Context.Buffer, SizeOf(Context.Buffer), 0); +end; + +// һδ 64 ֽҲ 512 λݿ +procedure SM3Process(var Context: TCnSM3Context; Data: PAnsiChar); +var + SS1, SS2, TT1, TT2: Cardinal; + W: array[0..67] of Cardinal; + W1: array[0..63] of Cardinal; + A, B, C, D, E, F, G, H: Cardinal; + Temp1, Temp2: Cardinal; + J: Integer; +begin + GetULongBe(W[ 0], Data, 0); + GetULongBe(W[ 1], Data, 4); + GetULongBe(W[ 2], Data, 8); + GetULongBe(W[ 3], Data, 12); + GetULongBe(W[ 4], Data, 16); + GetULongBe(W[ 5], Data, 20); + GetULongBe(W[ 6], Data, 24); + GetULongBe(W[ 7], Data, 28); + GetULongBe(W[ 8], Data, 32); + GetULongBe(W[ 9], Data, 36); + GetULongBe(W[10], Data, 40); + GetULongBe(W[11], Data, 44); + GetULongBe(W[12], Data, 48); + GetULongBe(W[13], Data, 52); + GetULongBe(W[14], Data, 56); + GetULongBe(W[15], Data, 60); + + for J := 16 to 67 do + begin + Temp1 := W[J - 16] xor W[J - 9]; + Temp2 := ROTL(W[J - 3], 15); + W[J] := P1(Temp1 xor Temp2) xor (ROTL(W[J - 13], 7) xor W[J - 6]); + end; + + for J := 0 to 63 do + W1[J] := W[J] xor W[J + 4]; + + // ѾW/W1ֵ + + A := Context.State[0]; + B := Context.State[1]; + C := Context.State[2]; + D := Context.State[3]; + E := Context.State[4]; + F := Context.State[5]; + G := Context.State[6]; + H := Context.State[7]; + + for J := 0 to 15 do + begin + SS1 := ROTL((ROTL(A, 12) + E + ROTL(SM3_T[J], J)), 7); + SS2 := SS1 xor ROTL(A, 12); + TT1 := FF0(A, B, C) + D + SS2 + W1[J]; + TT2 := GG0(E, F, G) + H + SS1 + W[J]; + D := C; + C := ROTL(B, 9); + B := A; + A := TT1; + H := G; + G := ROTL(F, 19); + F := E; + E := P0(TT2); + end; + + for J := 16 to 63 do + begin + SS1 := ROTL((ROTL(A, 12) + E + ROTL(SM3_T[J], J)), 7); + SS2 := SS1 xor ROTL(A, 12); + TT1 := FF1(A, B, C) + D + SS2 + W1[J]; + TT2 := GG1(E, F, G) + H + SS1 + W[J]; + D := C; + C := ROTL(B,9); + B := A; + A := TT1; + H := G; + G := ROTL(F,19); + F := E; + E := P0(TT2); + end; + + Context.State[0] := Context.State[0] xor A; + Context.State[1] := Context.State[1] xor B; + Context.State[2] := Context.State[2] xor C; + Context.State[3] := Context.State[3] xor D; + Context.State[4] := Context.State[4] xor E; + Context.State[5] := Context.State[5] xor F; + Context.State[6] := Context.State[6] xor G; + Context.State[7] := Context.State[7] xor H; + + // +end; + +procedure SM3UpdateW(var Context: TCnSM3Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + pContent: PAnsiChar; + iLen: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(pContent, CharLength * SizeOf(WideChar)); + try + iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(pContent), CharLength * SizeOf(WideChar), nil, nil); + SM3Update(Context, pContent, iLen); + finally + FreeMem(pContent); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + SM3Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +procedure SM3Update(var Context: TCnSM3Context; Input: PAnsiChar; ByteLength: Cardinal); +var + Fill, Left: Cardinal; +begin + if (Input = nil) or (ByteLength <= 0) then + Exit; + + Left := Context.Total[0] and $3F; + Fill := 64 - Left; + + Context.Total[0] := Context.Total[0] + ByteLength; + Context.Total[0] := Context.Total[0] and $FFFFFFFF; + + if Context.Total[0] < ByteLength then + Context.Total[1] := Context.Total[1] + 1; + + if (Left <> 0) and (ByteLength >= Fill) then + begin + Move(Input^, Context.Buffer[Left], Fill); + SM3Process(Context, @(Context.Buffer[0])); + Input := Input + Fill; + ByteLength := ByteLength - Fill; + Left := 0; + end; + + while ByteLength >= 64 do + begin + SM3Process(Context, Input); + Input := Input + 64; + ByteLength := ByteLength - 64; + end; + + if ByteLength > 0 then + Move(Input^, Context.Buffer[Left], ByteLength); +end; + +procedure SM3Final(var Context: TCnSM3Context; var Digest: TCnSM3Digest); +var + Last, Padn: Cardinal; + High, Low: Cardinal; + MsgLen: array[0..7] of Byte; +begin + High := (Context.Total[0] shr 29) or (Context.Total[1] shl 3); + Low := Context.Total[0] shl 3; + + PutULongBe(High, @(MsgLen[0]), 0); + PutULongBe(Low, @(MsgLen[0]), 4); + + Last := Context.Total[0] and $3F; + if Last < 56 then + Padn := 56 - Last + else + Padn := 120 - Last; + + SM3Update(Context, @(SM3Padding[0]), Padn); + SM3Update(Context, @(MsgLen[0]), 8); + + PutULongBe(Context.State[0], @Digest, 0); + PutULongBe(Context.State[1], @Digest, 4); + PutULongBe(Context.State[2], @Digest, 8); + PutULongBe(Context.State[3], @Digest, 12); + PutULongBe(Context.State[4], @Digest, 16); + PutULongBe(Context.State[5], @Digest, 20); + PutULongBe(Context.State[6], @Digest, 24); + PutULongBe(Context.State[7], @Digest, 28); +end; + +function SM3(Input: PAnsiChar; ByteLength: Cardinal): TCnSM3Digest; +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3Update(Context, Input, ByteLength); + SM3Final(Context, Result); +end; + +procedure SM3HmacInit(var Context: TCnSM3Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSM3Digest; +begin + if KeyLength > HMAC_SM3_BLOCK_SIZE_BYTE then + begin + Sum := SM3Buffer(Key^, KeyLength); + KeyLength := HMAC_SM3_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SM3_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SM3_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SM3Init(Context); + SM3Update(Context, @(Context.Ipad[0]), HMAC_SM3_BLOCK_SIZE_BYTE); +end; + +procedure SM3HmacUpdate(var Context: TCnSM3Context; Input: PAnsiChar; Length: Cardinal); +begin + SM3Update(Context, Input, Length); +end; + +procedure SM3HmacFinal(var Context: TCnSM3Context; var Output: TCnSM3Digest); +var + Len: Integer; + TmpBuf: TCnSM3Digest; +begin + Len := HMAC_SM3_OUTPUT_LENGTH_BYTE; + SM3Final(Context, TmpBuf); + SM3Init(Context); + SM3Update(Context, @(Context.Opad[0]), HMAC_SM3_BLOCK_SIZE_BYTE); + SM3Update(Context, @(TmpBuf[0]), Len); + SM3Final(Context, Output); +end; + +procedure SM3Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSM3Digest); +var + Context: TCnSM3Context; +begin + SM3HmacInit(Context, Key, KeyByteLength); + SM3HmacUpdate(Context, Input, ByteLength); + SM3HmacFinal(Context, Output); +end; + +function SM3HmacBytes(const Key: TBytes; const Data: TBytes): TCnSM3Digest; +var + Context: TCnSM3Context; +begin + SM3HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SM3HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SM3HmacFinal(Context, Result); +end; + +function SM3Buffer(const Buffer; Count: Cardinal): TCnSM3Digest; +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3Update(Context, PAnsiChar(@Buffer), Count); + SM3Final(Context, Result); +end; + +function SM3Bytes(const Data: TBytes): TCnSM3Digest; +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SM3Final(Context, Result); +end; + +function SM3String(const Str: string): TCnSM3Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SM3StringA(AStr); +end; + +function SM3StringA(const Str: AnsiString): TCnSM3Digest; +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3Update(Context, PAnsiChar(Str), Length(Str)); + SM3Final(Context, Result); +end; + +function SM3StringW(const Str: WideString): TCnSM3Digest; +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3UpdateW(Context, PWideChar(Str), Length(Str)); + SM3Final(Context, Result); +end; + +{$IFDEF UNICODE} +function SM3UnicodeString(const Str: string): TCnSM3Digest; +{$ELSE} +function SM3UnicodeString(const Str: WideString): TCnSM3Digest; +{$ENDIF} +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SM3Final(Context, Result); +end; + +function InternalSM3Stream(Stream: TStream; const BufSize: Cardinal; var D: + TCnSM3Digest; CallBack: TCnSM3CalcProgressFunc): Boolean; +var + Context: TCnSM3Context; + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; +begin + Result := False; + Size := Stream.Size; + SavePos := Stream.Position; + TotalBytes := 0; + if Size = 0 then Exit; + if Size < BufSize then BufLen := Size + else BufLen := BufSize; + + CancelCalc := False; + SM3Init(Context); + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + SM3Update(Context, Buf, ReadBytes); + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + SM3Final(Context, D); + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +function SM3File(const FileName: string; + CallBack: TCnSM3CalcProgressFunc): TCnSM3Digest; +var +{$IFDEF MSWINDOWS} + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; + Context: TCnSM3Context; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; + + function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; +{$IFDEF MSWINDOWS} + var + H: THandle; + Info: BY_HANDLE_FILE_INFORMATION; + Rec : Int64Rec; +{$ENDIF} + begin +{$IFDEF MSWINDOWS} + Result := False; + IsEmpty := False; + H := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); + if H = INVALID_HANDLE_VALUE then Exit; + try + if not GetFileInformationByHandle(H, Info) then Exit; + finally + CloseHandle(H); + end; + Rec.Lo := Info.nFileSizeLow; + Rec.Hi := Info.nFileSizeHigh; + Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); + IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); +{$ELSE} + Result := True; // Windows ƽ̨ Trueʾ Mapping +{$ENDIF} + end; + +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣ Windows ƽ̨ʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalSM3Stream(Stream, 4096 * 1024, Result, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + SM3Init(Context); + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + SM3Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise ECnNativeException.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise ECnNativeException.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + SM3Final(Context, Result); +{$ENDIF} + end; +end; + +function SM3Stream(Stream: TStream; + CallBack: TCnSM3CalcProgressFunc): TCnSM3Digest; +begin + InternalSM3Stream(Stream, 4096 * 1024, Result, CallBack); +end; + +function SM3Print(const Digest: TCnSM3Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSM3Digest)); +end; + +function SM3Match(const D1, D2: TCnSM3Digest): Boolean; +begin + Result := ConstTimeCompareMem(@D1[0], @D2[0], SizeOf(TCnSM3Digest)); +end; + +function SM3DigestToStr(const Digest: TCnSM3Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSM3Digest)); +end; + +end. diff --git a/CnPack/Crypto/CnSM4.pas b/CnPack/Crypto/CnSM4.pas new file mode 100644 index 0000000..8936be7 --- /dev/null +++ b/CnPack/Crypto/CnSM4.pas @@ -0,0 +1,2202 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnSM4; +{* |
+================================================================================
+* ƣ
+* Ԫƣ SM4 ԳƼӽ㷨ʵֵԪ
+* ԪߣCnPack 飨master@cnpack.org)
+*           οֲ goldboar  C 
+*     עԪʵ˹ SM4 ԳƼӽ㷨ֿС 16 ֽڣʵ
+*           Ķ뷽ʽĩβ 0Ԫڲ֧ PKCS ȿ뷽ʽҪⲿ
+*           CnPemUtils.pas Ԫе PKCS ϵкԼӽݽж⴦
+*           Ԫʵֲο㷨ĵSM4 Encryption alogrithm
+*
+*           ߰汾 Delphi 뾡ʹ AnsiString 汾ĺʮƳ⣩
+*           ⲻַӰӽܽ
+*
+*           ECB/CBC ǿģʽҪ롣CFB/OFB/CTR ĵģʽ뵽顣
+*           ⣬Ԫе CTR  8 ֽ Nonce  8 ֽڼΪڲ 16 ֽڳʼģʽ
+*           Щ 16 ֽ Iv ĺ 4  8 ֽIJͬʹʱע⡣
+*
+* ƽ̨Windows 7 + Delphi 5.0
+* ݲԣPWin9X/2000/XP/7 + Delphi 5/6 + MaxOS 64
+*   õԪеַϱػʽ
+* ޸ļ¼2025.01.22 V1.9
+*                CFB/OFB ģʽĩβʱӽܿܳ
+*           2024.12.01 V1.8
+*               ȥֲҪ const βע
+*           2022.07.21 V1.7
+*                CTR ģʽ֧
+*           2022.06.21 V1.6
+*               뼸ֽ鵽ʮַ֮ļӽܺ
+*           2022.04.26 V1.5
+*               ޸ LongWord  Integer ַת֧ MacOS64
+*           2022.04.19 V1.4
+*               ʹóʼʱڲݣ޸Ĵ
+*           2021.12.12 V1.3
+*                CFB/OFB ģʽ֧
+*           2020.03.24 V1.2
+*               Ӳַװ
+*           2019.04.15 V1.1
+*               ֧ Win32/Win64/MacOS
+*           2014.09.25 V1.0
+*               ֲԪ
+================================================================================
+|
} + +interface + +{$I CnPack.inc} + +uses + Classes, SysUtils, CnNative; + +const + CN_SM4_KEYSIZE = 16; + {* SM4 Կ 16 ֽ} + + CN_SM4_BLOCKSIZE = 16; + {* SM4 ķֿ鳤 16 ֽ} + + CN_SM4_NONCESIZE = 8; + {* SM4 CTR ģʽµ׼ʼ 8 ֽ} + +type + ECnSM4Exception = class(Exception); + {* SM4 쳣} + + TCnSM4Key = array[0..CN_SM4_KEYSIZE - 1] of Byte; + {* SM4 ļ Key16 ֽ} + + TCnSM4Buffer = array[0..CN_SM4_BLOCKSIZE - 1] of Byte; + {* SM4 ļܿ飬16 ֽ} + + TCnSM4Iv = array[0..CN_SM4_BLOCKSIZE - 1] of Byte; + {* SM4 CBC/CFB/OFB ȵijʼ16 ֽ} + + TCnSM4Nonce = array[0..CN_SM4_NONCESIZE - 1] of Byte; + {* SM4 CTR ģʽµijʼ 8 ֽڣһ 8 ֽڼƴһΪ 16 ֽ Iv} + + TCnSM4Context = packed record + {* SM4 Ľṹ} + Mode: Integer; {!< encrypt/decrypt } + Sk: array[0..CN_SM4_KEYSIZE * 2 - 1] of Cardinal; {!< SM4 subkeys } + end; + +function SM4GetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +{* ֽڳȼȡǿ + + + InputByteLength: Integer - ֽڳ + + ֵInteger - SM4 ij +} + +procedure SM4Encrypt(Key: PAnsiChar; Input: PAnsiChar; Output: PAnsiChar; ByteLen: Integer); +{* ԭʼ SM4 ݿ飬ʹ ECB ģʽ Input ڵݼܷ Output У + б֤ Key ָ 16 ֽڣInput Output ָݳȲҶΪ ByteLen ֽ + ByteLen 뱻 16 + + + Key: PAnsiChar - 16 ֽ SM4 Կ + Input: PAnsiChar - ܵݿַ + Output: PAnsiChar - ݿַ + ByteLen: Integer - ӽݿֽڳ + + ֵޣ +} + +procedure SM4Decrypt(Key: PAnsiChar; Input: PAnsiChar; Output: PAnsiChar; ByteLen: Integer); +{* ԭʼ SM4 ݿ飬ECB ģʽ Input ڵݽܸ鵽 Output + б֤ Key ָ 16 ֽڣInput Output ָݳȲҶΪ ByteLen ֽ + ByteLen 뱻 16 + + + Key: PAnsiChar - 16 ֽ SM4 Կ + Input: PAnsiChar - ܵݿַ + Output: PAnsiChar - ݿַ + ByteLen: Integer - ӽݿֽڳ + + ֵޣ +} + +// ============== ַʮַ֮ļӽ =================== + +procedure SM4EncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ ECB ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + const Input: AnsiString - ַܵ䳤粻 16 ıʱᱻ #0 ȴﵽ 16 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 16) + 1) * 16 + + ֵޣ +} + +procedure SM4DecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ ECB ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + const Input: AnsiString - ַܵ䳤粻 16 ıʱᱻ #0 ȴﵽ 16 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 16) + 1) * 16 + + ֵޣ +} + +procedure SM4EncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ CBC ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + Iv: PAnsiChar - 16 ֽڳʼעЧݱڻ 16 ֽ + const Input: AnsiString - ַܵ䳤粻 16 ıʱᱻ #0 ȴﵽ 16 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 16) + 1) * 16 + + ֵޣ +} + +procedure SM4DecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ CBC ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + Iv: PAnsiChar - 16 ֽڳʼעЧݱڻ 16 ֽ + const Input: AnsiString - ַܵ䳤粻 16 ıʱᱻ #0 ȴﵽ 16 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 16) + 1) * 16 + + ֵޣ +} + +procedure SM4EncryptCfbStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ CFB ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + Iv: PAnsiChar - 16 ֽڳʼעЧݱڻ 16 ֽ + const Input: AnsiString - ַܵ + Output: PAnsiChar - 䳤ȱڻ Length(Input) + + ֵޣ +} + +procedure SM4DecryptCfbStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ CFB ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + Iv: PAnsiChar - 16 ֽڳʼעЧݱڻ 16 ֽ + const Input: AnsiString - ַܵ + Output: PAnsiChar - 䳤ȱڻ Length(Input) + + ֵޣ +} + +procedure SM4EncryptOfbStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ OFB ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + Iv: PAnsiChar - 16 ֽڳʼעЧݱڻ 16 ֽ + const Input: AnsiString - ַܵ + Output: PAnsiChar - 䳤ȱڻ Length(Input) + + ֵޣ +} + +procedure SM4DecryptOfbStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ OFB ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + Iv: PAnsiChar - 16 ֽڳʼעЧݱڻ 16 ֽ + const Input: AnsiString - ַܵ + Output: PAnsiChar - 䳤ȱڻ Length(Input) + + ֵޣ +} + +procedure SM4EncryptCtrStr(Key: AnsiString; Nonce: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ CTR ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + Nonce: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ + const Input: AnsiString - ַܵ + Output: PAnsiChar - 䳤ȱڻ Length(Input) + + ֵޣ +} + +procedure SM4DecryptCtrStr(Key: AnsiString; Nonce: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ CTR ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + Nonce: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ + const Input: AnsiString - ַܵ + Output: PAnsiChar - 䳤ȱڻ Length(Input) + + ֵޣ +} + +// ================= ֽֽ֮ļӽ ==================== + +function SM4EncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ ECB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؼֽܺ +} + +function SM4DecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ ECB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؽֽܺ +} + +function SM4EncryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ CBC ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؼֽܺ +} + +function SM4DecryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ CBC ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؽֽܺ +} + +function SM4EncryptCfbBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ CFB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؼֽܺ +} + +function SM4DecryptCfbBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ CFB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؽֽܺ +} + +function SM4EncryptOfbBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ OFB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؼֽܺ +} + +function SM4DecryptOfbBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ OFB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؽֽܺ +} + +function SM4EncryptCtrBytes(Key: TBytes; Nonce: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ CTR ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Nonce: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؼֽܺ +} + +function SM4DecryptCtrBytes(Key: TBytes; Nonce: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ CTR ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Nonce: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؽֽܺ +} + +// ============== ֽʮַ֮ļӽ ================= + +function SM4EncryptEcbBytesToHex(Key: TBytes; Input: TBytes): AnsiString; +{* KeySM4 ܷתʮƵģʹ ECB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵAnsiString - ؼܺʮַ +} + +function SM4DecryptEcbBytesFromHex(Key: TBytes; const Input: AnsiString): TBytes; +{* ʮƵ KeySM4 ܷģʹ ECB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + const Input: AnsiString - ܵʮַ + + ֵTBytes - ؽֽܺ +} + +function SM4EncryptCbcBytesToHex(Key: TBytes; Iv: TBytes; Input: TBytes): AnsiString; +{* Key IvSM4 ܷתʮƵģʹ CBC ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵAnsiString - ؼܺʮַ +} + +function SM4DecryptCbcBytesFromHex(Key: TBytes; Iv: TBytes; const Input: AnsiString): TBytes; +{* ʮƵ Key IvSM4 ܷģʹ CBC ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + const Input: AnsiString - ܵʮַ + + ֵTBytes - ؽֽܺ +} + +function SM4EncryptCfbBytesToHex(Key: TBytes; Iv: TBytes; Input: TBytes): AnsiString; +{* Key IvSM4 ܷתʮƵģʹ CFB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵAnsiString - ؼܺʮַ +} + +function SM4DecryptCfbBytesFromHex(Key: TBytes; Iv: TBytes; const Input: AnsiString): TBytes; +{* ʮƵ Key IvSM4 ܷģʹ CFB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + const Input: AnsiString - ܵʮַ + + ֵTBytes - ؽֽܺ +} + +function SM4EncryptOfbBytesToHex(Key: TBytes; Iv: TBytes; Input: TBytes): AnsiString; +{* Key IvSM4 ܷתʮƵģʹ OFB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵAnsiString - ؼܺʮַ +} + +function SM4DecryptOfbBytesFromHex(Key: TBytes; Iv: TBytes; const Input: AnsiString): TBytes; +{* ʮƵ Key IvSM4 ܷģʹ OFB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + const Input: AnsiString - ܵʮַ + + ֵTBytes - ؽֽܺ +} + +function SM4EncryptCtrBytesToHex(Key: TBytes; Nonce: TBytes; Input: TBytes): AnsiString; +{* Key NonceSM4 ܷתʮƵģʹ CTR ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Nonce: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵAnsiString - ؼܺʮַ +} + +function SM4DecryptCtrBytesFromHex(Key: TBytes; Nonce: TBytes; const Input: AnsiString): TBytes; +{* ʮƵ Key NonceSM4 ܷģʹ CTR ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Nonce: TBytes - 8 ֽڳʼ̫ضϣ 0 + const Input: AnsiString - ܵʮַ + + ֵTBytes - ؽֽܺ +} + +// ======================= ֮ļӽ ========================== + +procedure SM4EncryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; Dest: TStream); overload; +{* SM4 ܣʹ ECB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + Dest: TStream - + + ֵޣ +} + +procedure SM4DecryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; Dest: TStream); overload; +{* SM4 ܣʹ ECB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + Dest: TStream - + + ֵޣ +} + +procedure SM4EncryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +{* SM4 ܣʹ CBC ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + const InitVector: TCnSM4Iv - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure SM4DecryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +{* SM4 ܣʹ CBC ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + const InitVector: TCnSM4Iv - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure SM4EncryptStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +{* SM4 ܣʹ CFB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + const InitVector: TCnSM4Iv - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure SM4DecryptStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +{* SM4 ܣʹ CFB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + const InitVector: TCnSM4Iv - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure SM4EncryptStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +{* SM4 ܣʹ OFB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + const InitVector: TCnSM4Iv - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure SM4DecryptStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +{* SM4 ܣʹ OFB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + const InitVector: TCnSM4Iv - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure SM4EncryptStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitNonce: TCnSM4Nonce; Dest: TStream); +{* SM4 ܣʹ CTR ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + const InitNonce: TCnSM4Nonce - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure SM4DecryptStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitNonce: TCnSM4Nonce; Dest: TStream); +{* SM4 ܣʹ CTR ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + const InitNonce: TCnSM4Nonce - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Ϊײܺųⲿʹ + +procedure SM4SetKeyEnc(var Ctx: TCnSM4Context; Key: PAnsiChar); +{* 16 ֽ Key SM4 IJΪģʽ + + + var Ctx: TCnSM4Context - õ SM4 + Key: PAnsiChar - 16 ֽ SM4 Կ + + ֵޣ +} + +procedure SM4SetKeyDec(var Ctx: TCnSM4Context; Key: PAnsiChar); +{* 16 ֽ Key SM4 IJΪģʽ + + + var Ctx: TCnSM4Context - õ SM4 + Key: PAnsiChar - 16 ֽ SM4 Կ + + ֵޣ +} + +procedure SM4OneRound(SK: PCardinal; Input: PAnsiChar; Output: PAnsiChar); +{* ӽһ飬ݴ Input Output 16 ֽڣ߿ͬһ + SK TSM4Context Skܻǽ + + + SK: PCardinal - SM4 SubKey + Input: PAnsiChar - ݿַ 16 ֽ + Output: PAnsiChar - ϵݿַ 16 ֽ + + ֵޣ +} + +implementation + +resourcestring + SCnErrorSM4InvalidInBufSize = 'Invalid Buffer Size for Decryption'; + SCnErrorSM4ReadError = 'Stream Read Error'; + SCnErrorSM4WriteError = 'Stream Write Error'; + +const + SM4_ENCRYPT = 1; + SM4_DECRYPT = 0; + + SBoxTable: array[0..CN_SM4_KEYSIZE - 1] of array[0..CN_SM4_KEYSIZE - 1] of Byte = ( + ($D6, $90, $E9, $FE, $CC, $E1, $3D, $B7, $16, $B6, $14, $C2, $28, $FB, $2C, $05), + ($2B, $67, $9A, $76, $2A, $BE, $04, $C3, $AA, $44, $13, $26, $49, $86, $06, $99), + ($9C, $42, $50, $F4, $91, $EF, $98, $7A, $33, $54, $0B, $43, $ED, $CF, $AC, $62), + ($E4, $B3, $1C, $A9, $C9, $08, $E8, $95, $80, $DF, $94, $FA, $75, $8F, $3F, $A6), + ($47, $07, $A7, $FC, $F3, $73, $17, $BA, $83, $59, $3C, $19, $E6, $85, $4F, $A8), + ($68, $6B, $81, $B2, $71, $64, $DA, $8B, $F8, $EB, $0F, $4B, $70, $56, $9D, $35), + ($1E, $24, $0E, $5E, $63, $58, $D1, $A2, $25, $22, $7C, $3B, $01, $21, $78, $87), + ($D4, $00, $46, $57, $9F, $D3, $27, $52, $4C, $36, $02, $E7, $A0, $C4, $C8, $9E), + ($EA, $BF, $8A, $D2, $40, $C7, $38, $B5, $A3, $F7, $F2, $CE, $F9, $61, $15, $A1), + ($E0, $AE, $5D, $A4, $9B, $34, $1A, $55, $AD, $93, $32, $30, $F5, $8C, $B1, $E3), + ($1D, $F6, $E2, $2E, $82, $66, $CA, $60, $C0, $29, $23, $AB, $0D, $53, $4E, $6F), + ($D5, $DB, $37, $45, $DE, $FD, $8E, $2F, $03, $FF, $6A, $72, $6D, $6C, $5B, $51), + ($8D, $1B, $AF, $92, $BB, $DD, $BC, $7F, $11, $D9, $5C, $41, $1F, $10, $5A, $D8), + ($0A, $C1, $31, $88, $A5, $CD, $7B, $BD, $2D, $74, $D0, $12, $B8, $E5, $B4, $B0), + ($89, $69, $97, $4A, $0C, $96, $77, $7E, $65, $B9, $F1, $09, $C5, $6E, $C6, $84), + ($18, $F0, $7D, $EC, $3A, $DC, $4D, $20, $79, $EE, $5F, $3E, $D7, $CB, $39, $48) + ); + + FK: array[0..3] of Cardinal = ($A3B1BAC6, $56AA3350, $677D9197, $B27022DC); + + CK: array[0..CN_SM4_KEYSIZE * 2 - 1] of Cardinal = ( + $00070E15, $1C232A31, $383F464D, $545B6269, + $70777E85, $8C939AA1, $A8AFB6BD, $C4CBD2D9, + $E0E7EEF5, $FC030A11, $181F262D, $343B4249, + $50575E65, $6C737A81, $888F969D, $A4ABB2B9, + $C0C7CED5, $DCE3EAF1, $F8FF060D, $141B2229, + $30373E45, $4C535A61, $686F767D, $848B9299, + $A0A7AEB5, $BCC3CAD1, $D8DFE6ED, $F4FB0209, + $10171E25, $2C333A41, $484F565D, $646B7279 ); + +function Min(A, B: Integer): Integer; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + if A < B then + Result := A + else + Result := B; +end; + +procedure GetULongBe(var N: Cardinal; B: PAnsiChar; I: Integer); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +var + D: Cardinal; +begin + D := (Cardinal(B[I]) shl 24) or (Cardinal(B[I + 1]) shl 16) or + (Cardinal(B[I + 2]) shl 8) or (Cardinal(B[I + 3])); + N := D; +end; + +procedure PutULongBe(N: Cardinal; B: PAnsiChar; I: Integer); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + B[I] := AnsiChar(N shr 24); + B[I + 1] := AnsiChar(N shr 16); + B[I + 2] := AnsiChar(N shr 8); + B[I + 3] := AnsiChar(N); +end; + +function SM4Shl(X: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and $FFFFFFFF) shl N; +end; + +// ѭơע N Ϊ 0 32 ʱֵΪ XN Ϊ 33 ʱֵ N Ϊ 1 ʱķֵ +function ROTL(X: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := SM4Shl(X, N) or (X shr (32 - N)); +end; + +procedure Swap(var A: Cardinal; var B: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +var + T: Cardinal; +begin + T := A; + A := B; + B := T; +end; + +function SM4SBox(Inch: Byte): Byte; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +var + PTable: Pointer; +begin + PTable := @(SboxTable[0][0]); + Result := PByte(TCnIntAddress(PTable) + Inch)^; +end; + +function SM4Lt(Ka: Cardinal): Cardinal; +var + BB: Cardinal; + A: array[0..3] of Byte; + B: array[0..3] of Byte; +begin + BB := 0; + PutULongBe(Ka, @(A[0]), 0); + B[0] := SM4SBox(A[0]); + B[1] := SM4SBox(A[1]); + B[2] := SM4SBox(A[2]); + B[3] := SM4SBox(A[3]); + GetULongBe(BB, @(B[0]), 0); + + Result := BB xor (ROTL(BB, 2)) xor (ROTL(BB, 10)) xor (ROTL(BB, 18)) + xor (ROTL(BB, 24)); +end; + +function SM4F(X0: Cardinal; X1: Cardinal; X2: Cardinal; X3: Cardinal; RK: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X0 xor SM4Lt(X1 xor X2 xor X3 xor RK); +end; + +function SM4CalciRK(Ka: Cardinal): Cardinal; +var + BB: Cardinal; + A: array[0..3] of Byte; + B: array[0..3] of Byte; +begin + PutULongBe(Ka, @(A[0]), 0); + B[0] := SM4SBox(A[0]); + B[1] := SM4SBox(A[1]); + B[2] := SM4SBox(A[2]); + B[3] := SM4SBox(A[3]); + GetULongBe(BB, @(B[0]), 0); + Result := BB xor ROTL(BB, 13) xor ROTL(BB, 23); +end; + +// SK Points to 32 DWord Array; Key Points to 16 Byte Array +procedure SM4SetKey(SK: PCardinal; Key: PAnsiChar); +var + MK: array[0..3] of Cardinal; + K: array[0..35] of Cardinal; + I: Integer; +begin + GetULongBe(MK[0], Key, 0); + GetULongBe(MK[1], Key, 4); + GetULongBe(MK[2], Key, 8); + GetULongBe(MK[3], Key, 12); + + K[0] := MK[0] xor FK[0]; + K[1] := MK[1] xor FK[1]; + K[2] := MK[2] xor FK[2]; + K[3] := MK[3] xor FK[3]; + + for I := 0 to 31 do + begin + K[I + 4] := K[I] xor SM4CalciRK(K[I + 1] xor K[I + 2] xor K[I + 3] xor CK[I]); + (PCardinal(TCnIntAddress(SK) + I * SizeOf(Cardinal)))^ := K[I + 4]; + end; +end; + +// SK Points to 32 DWord Array; Input/Output Points to 16 Byte Array +// Input Output ͬһ +procedure SM4OneRound(SK: PCardinal; Input: PAnsiChar; Output: PAnsiChar); +var + I: Integer; + UlBuf: array[0..35] of Cardinal; +begin + FillChar(UlBuf[0], SizeOf(UlBuf), 0); + + GetULongBe(UlBuf[0], Input, 0); + GetULongBe(UlBuf[1], Input, 4); + GetULongBe(UlBuf[2], Input, 8); + GetULongBe(UlBuf[3], Input, 12); + + for I := 0 to 31 do + begin + UlBuf[I + 4] := SM4F(UlBuf[I], UlBuf[I + 1], UlBuf[I + 2], UlBuf[I + 3], + (PCardinal(TCnNativeInt(SK) + I * SizeOf(Cardinal)))^); + end; + + PutULongBe(UlBuf[35], Output, 0); + PutULongBe(UlBuf[34], Output, 4); + PutULongBe(UlBuf[33], Output, 8); + PutULongBe(UlBuf[32], Output, 12); +end; + +procedure SM4SetKeyEnc(var Ctx: TCnSM4Context; Key: PAnsiChar); +begin + Ctx.Mode := SM4_ENCRYPT; + SM4SetKey(@(Ctx.Sk[0]), Key); +end; + +procedure SM4SetKeyDec(var Ctx: TCnSM4Context; Key: PAnsiChar); +var + I: Integer; +begin + Ctx.Mode := SM4_DECRYPT; + SM4SetKey(@(Ctx.Sk[0]), Key); + + for I := 0 to CN_SM4_KEYSIZE - 1 do + Swap(Ctx.Sk[I], Ctx.Sk[31 - I]); +end; + +procedure SM4CryptEcb(var Ctx: TCnSM4Context; Mode: Integer; Length: Integer; + Input: PAnsiChar; Output: PAnsiChar); +var + EndBuf: TCnSM4Buffer; +begin + while Length > 0 do + begin + if Length >= CN_SM4_BLOCKSIZE then + begin + SM4OneRound(@(Ctx.Sk[0]), Input, Output); + end + else + begin + // β 16 0 + FillChar(EndBuf[0], CN_SM4_BLOCKSIZE, 0); + Move(Input^, EndBuf[0], Length); + SM4OneRound(@(Ctx.Sk[0]), @(EndBuf[0]), Output); + end; + Inc(Input, CN_SM4_BLOCKSIZE); + Inc(Output, CN_SM4_BLOCKSIZE); + Dec(Length, CN_SM4_BLOCKSIZE); + end; +end; + +procedure SM4CryptEcbStr(Mode: Integer; Key: AnsiString; + const Input: AnsiString; Output: PAnsiChar); +var + Ctx: TCnSM4Context; +begin + if Length(Key) < CN_SM4_KEYSIZE then + while Length(Key) < CN_SM4_KEYSIZE do Key := Key + Chr(0) // 16 bytes at least padding 0. + else if Length(Key) > CN_SM4_KEYSIZE then + Key := Copy(Key, 1, CN_SM4_KEYSIZE); // Only keep 16 + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[1])); + SM4CryptEcb(Ctx, SM4_ENCRYPT, Length(Input), @(Input[1]), @(Output[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyDec(Ctx, @(Key[1])); + SM4CryptEcb(Ctx, SM4_DECRYPT, Length(Input), @(Input[1]), @(Output[0])); + end; +end; + +procedure SM4CryptCbc(var Ctx: TCnSM4Context; Mode: Integer; ByteLen: Integer; + Iv: PAnsiChar; Input: PAnsiChar; Output: PAnsiChar); +var + I: Integer; + EndBuf: TCnSM4Buffer; + LocalIv: TCnSM4Iv; +begin + Move(Iv^, LocalIv[0], CN_SM4_BLOCKSIZE); + if Mode = SM4_ENCRYPT then + begin + while ByteLen > 0 do + begin + if ByteLen >= CN_SM4_BLOCKSIZE then + begin + for I := 0 to CN_SM4_BLOCKSIZE - 1 do + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Input) + I))^ + xor LocalIv[I]; + + SM4OneRound(@(Ctx.Sk[0]), Output, Output); + Move(Output[0], LocalIv[0], CN_SM4_BLOCKSIZE); + end + else + begin + // β 16 0 + FillChar(EndBuf[0], SizeOf(EndBuf), 0); + Move(Input^, EndBuf[0], ByteLen); + + for I := 0 to CN_SM4_BLOCKSIZE - 1 do + (PByte(TCnIntAddress(Output) + I))^ := EndBuf[I] + xor LocalIv[I]; + + SM4OneRound(@(Ctx.Sk[0]), Output, Output); + Move(Output[0], LocalIv[0], CN_SM4_BLOCKSIZE); + end; + + Inc(Input, CN_SM4_BLOCKSIZE); + Inc(Output, CN_SM4_BLOCKSIZE); + Dec(ByteLen, CN_SM4_BLOCKSIZE); + end; + end + else if Mode = SM4_DECRYPT then + begin + while ByteLen > 0 do + begin + if ByteLen >= CN_SM4_BLOCKSIZE then + begin + SM4OneRound(@(Ctx.Sk[0]), Input, Output); + + for I := 0 to CN_SM4_BLOCKSIZE - 1 do + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Output) + I))^ + xor LocalIv[I]; + + Move(Input^, LocalIv[0], CN_SM4_BLOCKSIZE); + end + else + begin + // β 16 0 + FillChar(EndBuf[0], SizeOf(EndBuf), 0); + Move(Input^, EndBuf[0], ByteLen); + SM4OneRound(@(Ctx.Sk[0]), @(EndBuf[0]), Output); + + for I := 0 to CN_SM4_BLOCKSIZE - 1 do + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Output) + I))^ + xor LocalIv[I]; + + Move(EndBuf[0], LocalIv[0], CN_SM4_BLOCKSIZE); + end; + + Inc(Input, CN_SM4_BLOCKSIZE); + Inc(Output, CN_SM4_BLOCKSIZE); + Dec(ByteLen, CN_SM4_BLOCKSIZE); + end; + end; +end; + +procedure SM4CryptCfb(var Ctx: TCnSM4Context; Mode: Integer; ByteLen: Integer; + Iv: PAnsiChar; Input: PAnsiChar; Output: PAnsiChar); +var + I: Integer; + LocalIv, Tail: TCnSM4Iv; +begin + Move(Iv^, LocalIv[0], CN_SM4_BLOCKSIZE); + if Mode = SM4_ENCRYPT then + begin + while ByteLen > 0 do + begin + if ByteLen >= CN_SM4_BLOCKSIZE then + begin + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], Output); // ȼ Iv + + for I := 0 to CN_SM4_BLOCKSIZE - 1 do + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Input) + I))^ + xor (PByte(TCnIntAddress(Output) + I))^; // ܽΪ + + Move(Output[0], LocalIv[0], CN_SM4_BLOCKSIZE); // ȡ Iv Աһ + end + else + begin + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], @Tail[0]); + + for I := 0 to ByteLen - 1 do // ֻʣ೤ȣ账 16 ֽ + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Input) + I))^ xor Tail[I]; + end; + + Inc(Input, CN_SM4_BLOCKSIZE); + Inc(Output, CN_SM4_BLOCKSIZE); + Dec(ByteLen, CN_SM4_BLOCKSIZE); + end; + end + else if Mode = SM4_DECRYPT then + begin + while ByteLen > 0 do + begin + if ByteLen >= CN_SM4_BLOCKSIZE then + begin + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], Output); // ȼ Iv + + for I := 0 to CN_SM4_BLOCKSIZE - 1 do + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Output) + I))^ + xor (PByte(TCnIntAddress(Input) + I))^; // ܽõ + + Move(Input[0], LocalIv[0], CN_SM4_BLOCKSIZE); // ȡ Iv ȥһּ + end + else + begin + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], @Tail[0]); + + for I := 0 to ByteLen - 1 do + (PByte(TCnIntAddress(Output) + I))^ := Tail[I] xor (PByte(TCnIntAddress(Input) + I))^; + end; + + Inc(Input, CN_SM4_BLOCKSIZE); + Inc(Output, CN_SM4_BLOCKSIZE); + Dec(ByteLen, CN_SM4_BLOCKSIZE); + end; + end; +end; + +procedure SM4CryptOfb(var Ctx: TCnSM4Context; Mode: Integer; ByteLen: Integer; + Iv: PAnsiChar; Input: PAnsiChar; Output: PAnsiChar); +var + I: Integer; + LocalIv, Tail: TCnSM4Iv; +begin + Move(Iv^, LocalIv[0], CN_SM4_BLOCKSIZE); + if Mode = SM4_ENCRYPT then + begin + while ByteLen > 0 do + begin + if ByteLen >= CN_SM4_BLOCKSIZE then + begin + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], Output); // ȼ Iv + Move(Output[0], LocalIv[0], CN_SM4_BLOCKSIZE); // ܽһ + + for I := 0 to CN_SM4_BLOCKSIZE - 1 do // ܽ + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Input) + I))^ + xor (PByte(TCnIntAddress(Output) + I))^; + end + else + begin + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], @Tail[0]); // ȼ Iv + + for I := 0 to ByteLen - 1 do // 16 ֽ + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Input) + I))^ xor Tail[I]; + end; + + Inc(Input, CN_SM4_BLOCKSIZE); + Inc(Output, CN_SM4_BLOCKSIZE); + Dec(ByteLen, CN_SM4_BLOCKSIZE); + end; + end + else if Mode = SM4_DECRYPT then + begin + while ByteLen > 0 do + begin + if ByteLen >= CN_SM4_BLOCKSIZE then + begin + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], Output); // ȼ Iv + Move(Output[0], LocalIv[0], CN_SM4_BLOCKSIZE); // ܽһ + + for I := 0 to CN_SM4_BLOCKSIZE - 1 do // õ + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Output) + I))^ + xor (PByte(TCnIntAddress(Input) + I))^; + end + else + begin + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], @Tail[0]); // ȼ Iv + + for I := 0 to ByteLen - 1 do + (PByte(TCnIntAddress(Output) + I))^ := Tail[I] xor (PByte(TCnIntAddress(Input) + I))^; + end; + + Inc(Input, CN_SM4_BLOCKSIZE); + Inc(Output, CN_SM4_BLOCKSIZE); + Dec(ByteLen, CN_SM4_BLOCKSIZE); + end; + end; +end; + +// CTR ģʽݿ顣Output ȿԺ Input һȡ +procedure SM4CryptCtr(var Ctx: TCnSM4Context; Mode: Integer; ByteLen: Integer; + Nonce: PAnsiChar; Input: PAnsiChar; Output: PAnsiChar); +var + I: Integer; + LocalIv: TCnSM4Iv; + Cnt, T: Int64; +begin + Cnt := 1; + + // ּӽ + while ByteLen > 0 do + begin + if ByteLen >= CN_SM4_BLOCKSIZE then + begin + Move(Nonce^, LocalIv[0], SizeOf(TCnSM4Nonce)); + T := Int64HostToNetwork(Cnt); + Move(T, LocalIv[SizeOf(TCnSM4Nonce)], SizeOf(Int64)); + + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], @LocalIv[0]); // ȼ Iv + + for I := 0 to CN_SM4_BLOCKSIZE - 1 do // ܽ + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Input) + I))^ + xor LocalIv[I]; + end + else + begin + Move(Nonce^, LocalIv[0], SizeOf(TCnSM4Nonce)); + T := Int64HostToNetwork(Cnt); + Move(T, LocalIv[SizeOf(TCnSM4Nonce)], SizeOf(Int64)); + + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], @LocalIv[0]); // ȼ Iv + + for I := 0 to ByteLen - 1 do // 16 ֽ + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Input) + I))^ + xor LocalIv[I]; + end; + + Inc(Input, CN_SM4_BLOCKSIZE); + Inc(Output, CN_SM4_BLOCKSIZE); + Dec(ByteLen, CN_SM4_BLOCKSIZE); + Inc(Cnt); + end; +end; + +procedure SM4CryptCbcStr(Mode: Integer; Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + Ctx: TCnSM4Context; +begin + if Length(Key) < CN_SM4_KEYSIZE then + while Length(Key) < CN_SM4_KEYSIZE do Key := Key + Chr(0) // 16 bytes at least padding 0. + else if Length(Key) > CN_SM4_KEYSIZE then + Key := Copy(Key, 1, CN_SM4_KEYSIZE); // Only keep 16 + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[1])); + SM4CryptCbc(Ctx, SM4_ENCRYPT, Length(Input), @(Iv[0]), @(Input[1]), @(Output[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyDec(Ctx, @(Key[1])); + SM4CryptCbc(Ctx, SM4_DECRYPT, Length(Input), @(Iv[0]), @(Input[1]), @(Output[0])); + end; +end; + +procedure SM4CryptCfbStr(Mode: Integer; Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + Ctx: TCnSM4Context; +begin + if Length(Key) < CN_SM4_KEYSIZE then + while Length(Key) < CN_SM4_KEYSIZE do Key := Key + Chr(0) // 16 bytes at least padding 0. + else if Length(Key) > CN_SM4_KEYSIZE then + Key := Copy(Key, 1, CN_SM4_KEYSIZE); // Only keep 16 + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[1])); + SM4CryptCfb(Ctx, SM4_ENCRYPT, Length(Input), @(Iv[0]), @(Input[1]), @(Output[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[1])); // ע CFB ĽҲõǼܣ + SM4CryptCfb(Ctx, SM4_DECRYPT, Length(Input), @(Iv[0]), @(Input[1]), @(Output[0])); + end; +end; + +procedure SM4CryptOfbStr(Mode: Integer; Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + Ctx: TCnSM4Context; +begin + if Length(Key) < CN_SM4_KEYSIZE then + while Length(Key) < CN_SM4_KEYSIZE do Key := Key + Chr(0) // 16 bytes at least padding 0. + else if Length(Key) > CN_SM4_KEYSIZE then + Key := Copy(Key, 1, CN_SM4_KEYSIZE); // Only keep 16 + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[1])); + SM4CryptOfb(Ctx, SM4_ENCRYPT, Length(Input), @(Iv[0]), @(Input[1]), @(Output[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[1])); // ע OFB ĽҲõǼܣ + SM4CryptOfb(Ctx, SM4_DECRYPT, Length(Input), @(Iv[0]), @(Input[1]), @(Output[0])); + end; +end; + +procedure SM4CryptCtrStr(Mode: Integer; Key: AnsiString; Nonce: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + Ctx: TCnSM4Context; +begin + if Length(Key) < CN_SM4_KEYSIZE then + while Length(Key) < CN_SM4_KEYSIZE do Key := Key + Chr(0) // 16 bytes at least padding 0. + else if Length(Key) > CN_SM4_KEYSIZE then + Key := Copy(Key, 1, CN_SM4_KEYSIZE); // Only keep 16 + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[1])); + SM4CryptCtr(Ctx, SM4_ENCRYPT, Length(Input), @(Nonce[0]), @(Input[1]), @(Output[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[1])); // ע CTR ĽҲõǼܣ + SM4CryptCtr(Ctx, SM4_DECRYPT, Length(Input), @(Nonce[0]), @(Input[1]), @(Output[0])); + end; +end; + +procedure SM4EncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptEcbStr(SM4_ENCRYPT, Key, Input, Output); +end; + +procedure SM4DecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptEcbStr(SM4_DECRYPT, Key, Input, Output); +end; + +procedure SM4EncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptCbcStr(SM4_ENCRYPT, Key, Iv, Input, Output); +end; + +procedure SM4DecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptCbcStr(SM4_DECRYPT, Key, Iv, Input, Output); +end; + +procedure SM4EncryptCfbStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptCfbStr(SM4_ENCRYPT, Key, Iv, Input, Output); +end; + +procedure SM4DecryptCfbStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptCfbStr(SM4_DECRYPT, Key, Iv, Input, Output); +end; + +procedure SM4EncryptOfbStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptOfbStr(SM4_ENCRYPT, Key, Iv, Input, Output); +end; + +procedure SM4DecryptOfbStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptOfbStr(SM4_DECRYPT, Key, Iv, Input, Output); +end; + +procedure SM4EncryptCtrStr(Key: AnsiString; Nonce: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptCtrStr(SM4_ENCRYPT, Key, Nonce, Input, Output); +end; + +procedure SM4DecryptCtrStr(Key: AnsiString; Nonce: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptCtrStr(SM4_DECRYPT, Key, Nonce, Input, Output); +end; + +function SM4CryptEcbBytes(Mode: Integer; Key: TBytes; + const Input: TBytes): TBytes; +var + Ctx: TCnSM4Context; + I, Len: Integer; +begin + Len := Length(Input); + if Len <= 0 then + begin + Result := nil; + Exit; + end; + SetLength(Result, (((Len - 1) div 16) + 1) * 16); + + Len := Length(Key); + if Len < CN_SM4_KEYSIZE then // Key С 16 ֽڲ 0 + begin + SetLength(Key, CN_SM4_KEYSIZE); + for I := Len to CN_SM4_KEYSIZE - 1 do + Key[I] := 0; + end; + // ȴ 16 ֽʱ SM4SetKeyEnc ԶԺIJ + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[0])); + SM4CryptEcb(Ctx, SM4_ENCRYPT, Length(Input), @(Input[0]), @(Result[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyDec(Ctx, @(Key[0])); + SM4CryptEcb(Ctx, SM4_DECRYPT, Length(Input), @(Input[0]), @(Result[0])); + end; +end; + +function SM4CryptCbcBytes(Mode: Integer; Key, Iv: TBytes; + const Input: TBytes): TBytes; +var + Ctx: TCnSM4Context; + LocalIv: TCnSM4Iv; + I, Len: Integer; +begin + Len := Length(Input); + if Len <= 0 then + begin + Result := nil; + Exit; + end; + SetLength(Result, (((Len - 1) div 16) + 1) * 16); + + Len := Length(Key); + if Len < CN_SM4_KEYSIZE then // Key С 16 ֽڲ 0 + begin + SetLength(Key, CN_SM4_KEYSIZE); + for I := Len to CN_SM4_KEYSIZE - 1 do + Key[I] := 0; + end; + // ȴ 16 ֽʱ SM4SetKeyEnc ԶԺIJ + + MoveMost(Iv[0], LocalIv[0], Length(Iv), SizeOf(TCnSM4Iv)); + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[0])); + SM4CryptCbc(Ctx, SM4_ENCRYPT, Length(Input), @(LocalIv[0]), @(Input[0]), @(Result[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyDec(Ctx, @(Key[0])); + SM4CryptCbc(Ctx, SM4_DECRYPT, Length(Input), @(LocalIv[0]), @(Input[0]), @(Result[0])); + end; +end; + +function SM4CryptCfbBytes(Mode: Integer; Key, Iv: TBytes; + const Input: TBytes): TBytes; +var + Ctx: TCnSM4Context; + LocalIv: TCnSM4Iv; + I, Len: Integer; +begin + Len := Length(Input); + if Len <= 0 then + begin + Result := nil; + Exit; + end; + SetLength(Result, Len); // ע CFB ģʽ貹 + + Len := Length(Key); + if Len < CN_SM4_KEYSIZE then // Key С 16 ֽڲ 0 + begin + SetLength(Key, CN_SM4_KEYSIZE); + for I := Len to CN_SM4_KEYSIZE - 1 do + Key[I] := 0; + end; + // ȴ 16 ֽʱ SM4SetKeyEnc ԶԺIJ + + MoveMost(Iv[0], LocalIv[0], Length(Iv), SizeOf(TCnSM4Iv)); + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[0])); + SM4CryptCfb(Ctx, SM4_ENCRYPT, Length(Input), @(LocalIv[0]), @(Input[0]), @(Result[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[0])); // ע CFB ĽҲõǼܣ + SM4CryptCfb(Ctx, SM4_DECRYPT, Length(Input), @(LocalIv[0]), @(Input[0]), @(Result[0])); + end; +end; + +function SM4CryptOfbBytes(Mode: Integer; Key, Iv: TBytes; + const Input: TBytes): TBytes; +var + Ctx: TCnSM4Context; + LocalIv: TCnSM4Iv; + I, Len: Integer; +begin + Len := Length(Input); + if Len <= 0 then + begin + Result := nil; + Exit; + end; + SetLength(Result, Len); // ע OFB ģʽ貹 + + Len := Length(Key); + if Len < CN_SM4_KEYSIZE then // Key С 16 ֽڲ 0 + begin + SetLength(Key, CN_SM4_KEYSIZE); + for I := Len to CN_SM4_KEYSIZE - 1 do + Key[I] := 0; + end; + // ȴ 16 ֽʱ SM4SetKeyEnc ԶԺIJ + + MoveMost(Iv[0], LocalIv[0], Length(Iv), SizeOf(TCnSM4Iv)); + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[0])); + SM4CryptOfb(Ctx, SM4_ENCRYPT, Length(Input), @(LocalIv[0]), @(Input[0]), @(Result[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[0])); // ע OFB ĽҲõǼܣ + SM4CryptOfb(Ctx, SM4_DECRYPT, Length(Input), @(LocalIv[0]), @(Input[0]), @(Result[0])); + end; +end; + +function SM4CryptCtrBytes(Mode: Integer; Key, Nonce: TBytes; + const Input: TBytes): TBytes; +var + Ctx: TCnSM4Context; + LocalNonce: TCnSM4Nonce; + I, Len: Integer; +begin + Len := Length(Input); + if Len <= 0 then + begin + Result := nil; + Exit; + end; + SetLength(Result, Len); + + Len := Length(Key); + if Len < CN_SM4_KEYSIZE then // Key С 16 ֽڲ 0 + begin + SetLength(Key, CN_SM4_KEYSIZE); + for I := Len to CN_SM4_KEYSIZE - 1 do + Key[I] := 0; + end; + // ȴ 16 ֽʱ SM4SetKeyEnc ԶԺIJ + + MoveMost(Nonce[0], LocalNonce[0], Length(Nonce), SizeOf(TCnSM4Nonce)); + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[0])); + SM4CryptCtr(Ctx, SM4_ENCRYPT, Length(Input), @(LocalNonce[0]), @(Input[0]), @(Result[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[0])); // ע CTR ĽҲõǼܣ + SM4CryptCtr(Ctx, SM4_DECRYPT, Length(Input), @(LocalNonce[0]), @(Input[0]), @(Result[0])); + end; +end; + +function SM4EncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptEcbBytes(SM4_ENCRYPT, Key, Input); +end; + +function SM4DecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptEcbBytes(SM4_DECRYPT, Key, Input); +end; + +function SM4EncryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptCbcBytes(SM4_ENCRYPT, Key, Iv, Input); +end; + +function SM4DecryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptCbcBytes(SM4_DECRYPT, Key, Iv, Input); +end; + +function SM4EncryptCfbBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptCfbBytes(SM4_ENCRYPT, Key, Iv, Input); +end; + +function SM4DecryptCfbBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptCfbBytes(SM4_DECRYPT, Key, Iv, Input); +end; + +function SM4EncryptOfbBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptOfbBytes(SM4_ENCRYPT, Key, Iv, Input); +end; + +function SM4DecryptOfbBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptOfbBytes(SM4_DECRYPT, Key, Iv, Input); +end; + +function SM4EncryptCtrBytes(Key, Nonce: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptCtrBytes(SM4_ENCRYPT, Key, Nonce, Input); +end; + +function SM4DecryptCtrBytes(Key, Nonce: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptCtrBytes(SM4_DECRYPT, Key, Nonce, Input); +end; + +function SM4EncryptEcbBytesToHex(Key: TBytes; Input: TBytes): AnsiString; +begin + Result := AnsiString(BytesToHex(SM4EncryptEcbBytes(Key, Input))); +end; + +function SM4DecryptEcbBytesFromHex(Key: TBytes; const Input: AnsiString): TBytes; +begin + Result := SM4DecryptEcbBytes(Key, HexToBytes(string(Input))); +end; + +function SM4EncryptCbcBytesToHex(Key, Iv: TBytes; Input: TBytes): AnsiString; +begin + Result := AnsiString(BytesToHex(SM4EncryptCbcBytes(Key, Iv, Input))); +end; + +function SM4DecryptCbcBytesFromHex(Key, Iv: TBytes; const Input: AnsiString): TBytes; +begin + Result := SM4DecryptCbcBytes(Key, Iv, HexToBytes(string(Input))); +end; + +function SM4EncryptCfbBytesToHex(Key, Iv: TBytes; Input: TBytes): AnsiString; +begin + Result := AnsiString(BytesToHex(SM4EncryptCfbBytes(Key, Iv, Input))); +end; + +function SM4DecryptCfbBytesFromHex(Key, Iv: TBytes; const Input: AnsiString): TBytes; +begin + Result := SM4DecryptCfbBytes(Key, Iv, HexToBytes(string(Input))); +end; + +function SM4EncryptOfbBytesToHex(Key, Iv: TBytes; Input: TBytes): AnsiString; +begin + Result := AnsiString(BytesToHex(SM4EncryptOfbBytes(Key, Iv, Input))); +end; + +function SM4DecryptOfbBytesFromHex(Key, Iv: TBytes; const Input: AnsiString): TBytes; +begin + Result := SM4DecryptOfbBytes(Key, Iv, HexToBytes(string(Input))); +end; + +function SM4EncryptCtrBytesToHex(Key, Nonce: TBytes; Input: TBytes): AnsiString; +begin + Result := AnsiString(BytesToHex(SM4EncryptCtrBytes(Key, Nonce, Input))); +end; + +function SM4DecryptCtrBytesFromHex(Key, Nonce: TBytes; const Input: AnsiString): TBytes; +begin + Result := SM4DecryptCtrBytes(Key, Nonce, HexToBytes(string(Input))); +end; + +procedure SM4EncryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Done: Cardinal; + Ctx: TCnSM4Context; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + SM4SetKeyEnc(Ctx, @(Key[0])); + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4ReadError); + + SM4OneRound(@(Ctx.Sk[0]), @(TempIn[0]), @(TempOut[0])); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorSM4WriteError); + + Dec(Count, SizeOf(TCnSM4Buffer)); + end; + + if Count > 0 then // β 0 + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorSM4ReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + + SM4OneRound(@(Ctx.Sk[0]), @(TempIn[0]), @(TempOut[0])); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorSM4WriteError); + end; +end; + +procedure SM4DecryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Done: Cardinal; + Ctx: TCnSM4Context; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + if (Count mod SizeOf(TCnSM4Buffer)) > 0 then + raise ECnSM4Exception.Create(SCnErrorSM4InvalidInBufSize); + + SM4SetKeyDec(Ctx, @(Key[0])); + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4ReadError); + + SM4OneRound(@(Ctx.Sk[0]), @(TempIn[0]), @(TempOut[0])); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorSM4WriteError); + + Dec(Count, SizeOf(TCnSM4Buffer)); + end; +end; + +procedure SM4EncryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Vector: TCnSM4Iv; + Done: Cardinal; + Ctx: TCnSM4Context; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + SM4SetKeyEnc(Ctx, @(Key[0])); + + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4ReadError); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + + SM4OneRound(@(Ctx.Sk[0]), @(TempIn[0]), @(TempOut[0])); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorSM4WriteError); + + Move(TempOut[0], Vector[0], SizeOf(TCnSM4Iv)); + Dec(Count, SizeOf(TCnSM4Buffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorSM4ReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + + SM4OneRound(@(Ctx.Sk[0]), @(TempIn[0]), @(TempOut[0])); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorSM4WriteError); + end; +end; + +procedure SM4DecryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Vector1, Vector2: TCnSM4Iv; + Done: Cardinal; + Ctx: TCnSM4Context; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + if (Count mod SizeOf(TCnSM4Buffer)) > 0 then + raise ECnSM4Exception.Create(SCnErrorSM4InvalidInBufSize); + + Vector1 := InitVector; + SM4SetKeyDec(Ctx, @(Key[0])); + + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorSM4ReadError); + + Move(TempIn[0], Vector2[0], SizeOf(TCnSM4Iv)); + SM4OneRound(@(Ctx.Sk[0]), @(TempIn[0]), @(TempOut[0])); + + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@Vector1[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@Vector1[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorSM4WriteError); + + Vector1 := Vector2; + Dec(Count, SizeOf(TCnSM4Buffer)); + end; +end; + +procedure SM4EncryptStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Vector: TCnSM4Iv; + Done: Cardinal; + Ctx: TCnSM4Context; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + SM4SetKeyEnc(Ctx, @(Key[0])); + + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4ReadError); + + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); // Key ȼ Iv + + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); // ĽдĽ + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorSM4WriteError); + + Move(TempOut[0], Vector[0], SizeOf(TCnSM4Iv)); // Ľȡ Iv һּ + Dec(Count, SizeOf(TCnSM4Buffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorSM4ReadError); + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); + + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorSM4WriteError); + end; +end; + +procedure SM4DecryptStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Vector: TCnSM4Iv; + Done: Cardinal; + Ctx: TCnSM4Context; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + SM4SetKeyEnc(Ctx, @(Key[0])); // עǼܣǽܣ + + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); // Ķ TempIn + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorSM4ReadError); + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); // Iv ȼ TempOut + + // ܺ TempOut TempIn õ TempOut + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); // TempOut дȥ + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorSM4WriteError); + Move(TempIn[0], Vector[0], SizeOf(TCnSM4Iv)); // TempIn ȡ Iv Ϊһμ + Dec(Count, SizeOf(TCnSM4Buffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorSM4ReadError); + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); + + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorSM4WriteError); + end; +end; + +procedure SM4EncryptStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Vector: TCnSM4Iv; + Done: Cardinal; + Ctx: TCnSM4Context; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + SM4SetKeyEnc(Ctx, @(Key[0])); + + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4ReadError); + + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); // Key ȼ Iv + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4WriteError); + + Move(TempOut[0], Vector[0], SizeOf(TCnSM4Iv)); // ܽȡ Iv һּܣעⲻ + Dec(Count, SizeOf(TCnSM4Buffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorSM4ReadError); + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorSM4WriteError); + end; +end; + +procedure SM4DecryptStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Vector: TCnSM4Iv; + Done: Cardinal; + Ctx: TCnSM4Context; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + SM4SetKeyEnc(Ctx, @(Key[0])); // עǼܣǽܣ + + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); // Ķ TempIn + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorSM4ReadError); + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); // Iv ȼ TempOut + + // ܺ TempOut TempIn õ TempIn + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); // TempIn дȥ + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorSM4WriteError); + Move(TempOut[0], Vector[0], SizeOf(TCnSM4Iv)); // ܽ TempOut ȡ Iv Ϊһμ + Dec(Count, SizeOf(TCnSM4Buffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorSM4ReadError); + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorSM4WriteError); + end; +end; + +procedure SM4EncryptStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitNonce: TCnSM4Nonce; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Vector: TCnSM4Iv; + Done: Cardinal; + Ctx: TCnSM4Context; + Cnt, T: Int64; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Cnt := 1; + SM4SetKeyEnc(Ctx, @(Key[0])); + + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4ReadError); + + // Nonce ͼƴ Iv + T := Int64HostToNetwork(Cnt); + Move(InitNonce[0], Vector[0], SizeOf(TCnSM4Nonce)); + Move(T, Vector[SizeOf(TCnSM4Nonce)], SizeOf(Int64)); + + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); // Key ȼ Iv + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4WriteError); + + Inc(Cnt); + Dec(Count, SizeOf(TCnSM4Buffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorSM4ReadError); + + // Nonce ͼƴ Iv + T := Int64HostToNetwork(Cnt); + Move(InitNonce[0], Vector[0], SizeOf(TCnSM4Nonce)); + Move(T, Vector[SizeOf(TCnSM4Nonce)], SizeOf(Int64)); + + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorSM4WriteError); + end; +end; + +procedure SM4DecryptStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitNonce: TCnSM4Nonce; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Vector: TCnSM4Iv; + Done: Cardinal; + Ctx: TCnSM4Context; + Cnt, T: Int64; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Cnt := 1; + SM4SetKeyEnc(Ctx, @(Key[0])); // עǼܣǽܣ + + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4ReadError); + + // Nonce ͼƴ Iv + T := Int64HostToNetwork(Cnt); + Move(InitNonce[0], Vector[0], SizeOf(TCnSM4Nonce)); + Move(T, Vector[SizeOf(TCnSM4Nonce)], SizeOf(Int64)); + + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); // Key ȼ Iv + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4WriteError); + + Inc(Cnt); + Dec(Count, SizeOf(TCnSM4Buffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorSM4ReadError); + + // Nonce ͼƴ Iv + T := Int64HostToNetwork(Cnt); + Move(InitNonce[0], Vector[0], SizeOf(TCnSM4Nonce)); + Move(T, Vector[SizeOf(TCnSM4Nonce)], SizeOf(Int64)); + + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorSM4WriteError); + end; +end; + +function SM4GetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +begin + Result := (((InputByteLength - 1) div CN_SM4_BLOCKSIZE) + 1) * CN_SM4_BLOCKSIZE; +end; + +procedure SM4Encrypt(Key: PAnsiChar; Input: PAnsiChar; Output: PAnsiChar; ByteLen: Integer); +var + Ctx: TCnSM4Context; +begin + SM4SetKeyEnc(Ctx, Key); + SM4CryptEcb(Ctx, SM4_ENCRYPT, ByteLen, Input, Output); +end; + +procedure SM4Decrypt(Key: PAnsiChar; Input: PAnsiChar; Output: PAnsiChar; ByteLen: Integer); +var + Ctx: TCnSM4Context; +begin + SM4SetKeyDec(Ctx, Key); + SM4CryptEcb(Ctx, SM4_DECRYPT, ByteLen, Input, Output); +end; + +end. From e2c4770e7967f84921534d35c1d2207903506609 Mon Sep 17 00:00:00 2001 From: freitasjca Date: Mon, 8 Jun 2026 12:40:19 +0100 Subject: [PATCH 10/15] chore: conservative .gitattributes + CnPack maintenance doc --- .gitattributes | 41 +++++ MAINTAINING-CNPACK-SUBSET.md | 100 ++++++++++++ Net/Demos/Delphi/HttpClient/HttpClient.dproj | 38 ++--- Net/Demos/Delphi/HttpServer/HttpServer.dproj | 69 ++++---- Net/Linux.epoll.pas | 158 +++++++++---------- Net/Net.Posix.inc | 86 +++++----- boss.json | 20 +-- 7 files changed, 322 insertions(+), 190 deletions(-) create mode 100644 .gitattributes create mode 100644 MAINTAINING-CNPACK-SUBSET.md diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..b24acd2 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,41 @@ +# Conservative policy for an upstream-synced fork: do NOT globally normalise +# (that would drift the fork from winddriver on every sync). Only force endings +# where a wrong one breaks the file, and keep vendored/byte-exact files intact. + +# Scripts & CI — a wrong ending breaks these +*.sh text eol=lf +*.bat text eol=crlf +*.cmd text eol=crlf +*.ps1 text eol=crlf +*.yml text eol=lf +*.yaml text eol=lf + +# Vendored CnPack (GBK-encoded) + patches — never normalise; stay identical to source +CnPack/** -text +*.patch -text +*.diff -text + +# Certs / keys — exact bytes +*.crt binary +*.cer binary +*.der binary +*.pem binary +*.key binary +*.pfx binary +*.p12 binary + +# Binaries / build artifacts +*.png binary +*.jpg binary +*.gif binary +*.ico binary +*.res binary +*.dcr binary +*.dcu binary +*.dcp binary +*.exe binary +*.dll binary +*.so binary +*.dylib binary +# NOTE: *.pas/.dpr/.inc/.dproj are intentionally NOT listed — left to core.autocrlf +# so the fork stays byte-close to upstream after each sync. diff --git a/MAINTAINING-CNPACK-SUBSET.md b/MAINTAINING-CNPACK-SUBSET.md new file mode 100644 index 0000000..55b0e9c --- /dev/null +++ b/MAINTAINING-CNPACK-SUBSET.md @@ -0,0 +1,100 @@ +# Maintaining the bundled CnPack subset (boss-installability) + +**Read this before touching `CnPack/`, releasing a new tag, or running the fork-sync.** + +## Why this fork exists + +`freitasjca/Delphi-Cross-Socket` is a fork of +[`winddriver/Delphi-Cross-Socket`](https://github.com/winddriver/Delphi-Cross-Socket) +whose **only reason to exist is to be installable with [Boss](https://github.com/HashLoad/boss)** +(the Delphi package manager). Two upstreams block that: + +- **`winddriver/Delphi-Cross-Socket`** ships no `boss.json`. +- **CnPack / [`cnpack/cnvcl`](https://github.com/cnpack/cnvcl)** — a *dependency* of + Delphi-Cross-Socket's SSL/crypto layer — also has no `boss.json` and is a huge repo. + +So this fork adds (a) a `boss.json`, (b) the **minimal CnPack subset** that +Delphi-Cross-Socket actually needs, vendored under `CnPack/`, and (c) the mTLS additions +(`Net/Net.CrossSslSocket.{Base,OpenSSL}.pas`). A consumer (e.g. +[`horse-provider-crosssocket`](https://github.com/freitasjca/horse-provider-crosssocket)) +can then `boss install` this fork and compile **without ever touching cnvcl**. + +> The `boss.json` `description` currently says *"adds Boss package manifest only. Zero source +> changes"* — that is **stale**: the fork also vendors the CnPack subset and the mTLS patches. +> Update it when convenient. + +## The invariant — what must always hold + +The vendored subset **must be a complete, self-contained transitive closure** so the package +compiles standalone: + +1. **`CnPack/Common/CnPack.inc` must be present.** Every Cn unit begins with `{$I CnPack.inc}`; + without it nothing compiles. +2. **Every unit named in any `uses` clause of a bundled unit must also be bundled.** If you add + a Crypto unit that pulls in a new `Cn*` dependency, that dependency has to be copied in too. +3. The split mirrors cnvcl's own layout: foundation units in `CnPack/Common/`, crypto in + `CnPack/Crypto/`. + +### Current inventory (18 files — keep this list and the fork-sync in step) + +``` +CnPack/Common/ CnPack.inc CnConsts.pas CnFloat.pas CnStrings.pas CnWideStrings.pas +CnPack/Crypto/ CnAES.pas CnBase64.pas CnDES.pas CnKDF.pas CnMD5.pas CnNative.pas + CnPemUtils.pas CnRandom.pas CnSHA1.pas CnSHA2.pas CnSHA3.pas + CnSM3.pas CnSM4.pas +``` + +> History: earlier releases kept everything under `CnPack/Crypto/` (14 units). cnvcl later +> moved the foundation units to `Source/Common/` and added `CnStrings`, `CnWideStrings`, +> `CnSM4`; the v1.0.3 re-sync follows that — hence the `Common/` directory. + +## Re-syncing the subset when cnvcl updates + +1. Update your local cnvcl: `cd cnvcl && git pull --ff-only origin master`. +2. Copy the units above from cnvcl into the fork: + - `cnvcl/Source/Common/{CnPack.inc,CnConsts,CnFloat,CnStrings,CnWideStrings}` → `CnPack/Common/` + - `cnvcl/Source/Crypto/{the 13 crypto units}.pas` → `CnPack/Crypto/` + - (verify the cnvcl source-side paths — cnvcl occasionally relocates units between + `Source/Common` and `Source/Crypto`.) +3. **Re-validate the closure** — the only authoritative check (the CnPack sources are + **GBK/ANSI-encoded**, which defeats `grep`-based scans): `boss install` this fork into a + throwaway project, or build `horse-provider-crosssocket` against it, and confirm a clean + compile with **no missing `Cn*` unit**. If the compiler reports a missing unit, copy it in + and repeat. +4. Commit the subset change on its own (`git add -A CnPack/` so renames register), separate + from version bumps and `.gitattributes` changes. + +## ⚠️ Keep the fork-sync automation in step — or it reverts the subset + +The fork-sync (`crosssocket-fork-sync-action/` → deployed to the fork's `master` as a daily +GitHub Action) **resets `master` to upstream's tip and re-layers the CnPack subset from a +hardcoded list**. If that list doesn't match the inventory above, the next nightly run +**silently restores the wrong subset and breaks the boss build.** Two files must be updated +together with any subset change: + +- `.github/workflows/sync-upstream.yml` — the `Clone CnPack (cnvcl) and copy required files` + step (the actual `cp` list + the `mkdir CnPack/Common CnPack/Crypto`). +- `.sync/README.md` — the human-readable manifest table (fork path ← cnvcl source path). + +Optionally pin `CNVCL_REF` in `sync-upstream.yml` to a validated cnvcl tag/sha instead of +`master`, so a surprise upstream cnvcl change can't break a nightly sync. + +## Consumer-side note + +Because the foundation units live in `CnPack/Common/`, any consuming project's search path must +include **both** `CnPack/Common` **and** `CnPack/Crypto` (see the "Required search paths" list +in `horse-provider-crosssocket`'s README). Adding only `Crypto/` will fail to resolve +`CnConsts`/`CnFloat`/`CnStrings`/`CnWideStrings`. + +## Don't track build/IDE artifacts + +`.dcu`, `.res`, `.dproj.local`, `.dsv`, `__history/` must stay out of the repo (they bloat it +and create false "modified" churn). They are covered by `.gitignore`; if any are already +tracked, `git rm --cached` them. + +## Endgame + +The mTLS additions are pending an upstream PR. Once upstream merges them **and** a boss-friendly +distribution of Delphi-Cross-Socket + CnPack exists, this fork (and this whole subset-maintenance +burden) can be retired. Until then, every cnvcl bump is a re-sync chore — keep this doc, the +inventory, and the fork-sync manifest aligned. diff --git a/Net/Demos/Delphi/HttpClient/HttpClient.dproj b/Net/Demos/Delphi/HttpClient/HttpClient.dproj index e13e632..2c2470e 100644 --- a/Net/Demos/Delphi/HttpClient/HttpClient.dproj +++ b/Net/Demos/Delphi/HttpClient/HttpClient.dproj @@ -4,7 +4,7 @@ HttpClient.dpr True Release - 693379 + 168067 Console None 20.3 @@ -23,11 +23,6 @@ Base true - - true - Base - true - true Base @@ -49,8 +44,8 @@ true true - - true + + true Cfg_1 true true @@ -90,12 +85,6 @@ true true - - true - Cfg_2 - true - true - true Cfg_2 @@ -133,9 +122,10 @@ System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) $(BDS)\bin\delphi_PROJECTICON.ico $(BDS)\bin\delphi_PROJECTICNS.icns - bin\$(Platform)\ - ..\..\..\..\Net;..\..\..\..\Utils;..\..\..\..\DelphiToFPC;$(DCC_UnitSearchPath) - .\$(Platform)\$(Config) + ..\..\..\..\..\..\bin\$(Platform)\$(Config) + ..\..\..\..\Net;..\..\..\..\Utils;..\..\..\..\DelphiToFPC;C:\lang\Repo\Delphi-Cross-Socket;$(DCC_UnitSearchPath) + ..\..\..\..\..\..\temp\$(Platform)\$(Config) + ..\..\..\..\..\..\temp\$(Platform)\$(Config) package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= @@ -171,9 +161,6 @@ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png activity-1.1.0.dex.jar;annotation-1.2.0.dex.jar;appcompat-1.2.0.dex.jar;appcompat-resources-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;biometric-1.1.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.1.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.1.0.dex.jar;core-runtime-2.1.0.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.2.5.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.2.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.2.0.dex.jar;lifecycle-runtime-2.2.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.2.0.dex.jar;lifecycle-viewmodel-savedstate-2.2.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;savedstate-1.0.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;vectordrawable-1.1.0.dex.jar;vectordrawable-animated-1.1.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar - - $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png - Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) Debug @@ -195,8 +182,10 @@ Debug - - Debug + + /usr/bin/gnome-terminal -- "%debuggee%" + (None) + none Debug @@ -226,9 +215,6 @@ Debug - - Debug - Debug @@ -286,8 +272,6 @@ False True - True - True True True True diff --git a/Net/Demos/Delphi/HttpServer/HttpServer.dproj b/Net/Demos/Delphi/HttpServer/HttpServer.dproj index 1bdc2de..247c26a 100644 --- a/Net/Demos/Delphi/HttpServer/HttpServer.dproj +++ b/Net/Demos/Delphi/HttpServer/HttpServer.dproj @@ -4,11 +4,12 @@ HttpServer.dpr True Release - 693379 + 168067 Console None - 19.5 + 20.2 Win64 + HttpServer true @@ -23,11 +24,6 @@ Base true - - true - Base - true - true Base @@ -43,6 +39,24 @@ Base true + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + true Cfg_1 @@ -60,12 +74,6 @@ true true - - true - Cfg_2 - true - true - true Cfg_2 @@ -97,8 +105,10 @@ System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) $(BDS)\bin\delphi_PROJECTICON.ico $(BDS)\bin\delphi_PROJECTICNS.icns - bin\$(Platform)\ - ..\..\..\..\Net;..\..\..\..\Utils;..\..\..\..\DelphiToFPC;$(DCC_UnitSearchPath) + ..\..\..\..\..\..\bin\$(Platform)\$(Config) + ..\..\..\..\Net;..\..\..\..\Utils;..\..\..\..\DelphiToFPC;C:\lang\Repo\Delphi-Cross-Socket;..\..\..\..\CnPack\Common;..\..\..\..\CnPack\Crypto;$(DCC_UnitSearchPath) + ..\..\..\..\..\..\temp\$(Platform)\$(Config) + ..\..\..\..\..\..\temp\$(Platform)\$(Config) package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey= @@ -134,9 +144,6 @@ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png activity-1.1.0.dex.jar;annotation-1.2.0.dex.jar;appcompat-1.2.0.dex.jar;appcompat-resources-1.2.0.dex.jar;asynclayoutinflater-1.0.0.dex.jar;billing-4.0.0.dex.jar;biometric-1.1.0.dex.jar;browser-1.0.0.dex.jar;cloud-messaging.dex.jar;collection-1.1.0.dex.jar;coordinatorlayout-1.0.0.dex.jar;core-1.5.0-rc02.dex.jar;core-common-2.1.0.dex.jar;core-runtime-2.1.0.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;firebase-annotations-16.0.0.dex.jar;firebase-common-20.0.0.dex.jar;firebase-components-17.0.0.dex.jar;firebase-datatransport-18.0.0.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.0.0.dex.jar;firebase-installations-interop-17.0.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-22.0.0.dex.jar;fmx.dex.jar;fragment-1.2.5.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;legacy-support-core-ui-1.0.0.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.2.0.dex.jar;lifecycle-livedata-2.0.0.dex.jar;lifecycle-livedata-core-2.2.0.dex.jar;lifecycle-runtime-2.2.0.dex.jar;lifecycle-service-2.0.0.dex.jar;lifecycle-viewmodel-2.2.0.dex.jar;lifecycle-viewmodel-savedstate-2.2.0.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;play-services-ads-20.1.0.dex.jar;play-services-ads-base-20.1.0.dex.jar;play-services-ads-identifier-17.0.0.dex.jar;play-services-ads-lite-20.1.0.dex.jar;play-services-base-17.5.0.dex.jar;play-services-basement-17.6.0.dex.jar;play-services-cloud-messaging-16.0.0.dex.jar;play-services-drive-17.0.0.dex.jar;play-services-games-21.0.0.dex.jar;play-services-location-18.0.0.dex.jar;play-services-maps-17.0.1.dex.jar;play-services-measurement-base-18.0.0.dex.jar;play-services-measurement-sdk-api-18.0.0.dex.jar;play-services-places-placereport-17.0.0.dex.jar;play-services-stats-17.0.0.dex.jar;play-services-tasks-17.2.0.dex.jar;print-1.0.0.dex.jar;room-common-2.1.0.dex.jar;room-runtime-2.1.0.dex.jar;savedstate-1.0.0.dex.jar;slidingpanelayout-1.0.0.dex.jar;sqlite-2.0.1.dex.jar;sqlite-framework-2.0.1.dex.jar;swiperefreshlayout-1.0.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.0.0.dex.jar;transport-runtime-3.0.0.dex.jar;user-messaging-platform-1.0.0.dex.jar;vectordrawable-1.1.0.dex.jar;vectordrawable-animated-1.1.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.1.0.dex.jar - - $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png - Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) Debug @@ -155,6 +162,15 @@ false 0 + + Debug + + + Debug + + + Debug + 1033 CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= @@ -171,9 +187,6 @@ Debug - - Debug - Debug @@ -211,21 +224,15 @@ HttpServer.dpr - Embarcadero C++Builder Office 2000 Servers Package - Embarcadero C++Builder Office XP Servers Package - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components - File C:\Users\Public\Documents\Embarcadero\Studio\22.0\Bpl\CEF4Delphi_FMX.bpl not found - File C:\Users\Public\Documents\Embarcadero\Studio\22.0\Bpl\AutoUpgraderProXE10.bpl not found - File C:\Users\Public\Documents\Embarcadero\Studio\22.0\Bpl\KastriFMX280.bpl not found - File C:\Users\Public\Documents\Embarcadero\Studio\22.0\Bpl\CEF4Delphi.bpl not found + Embarcadero C++Builder Office 2000 Servers Package + Embarcadero C++Builder Office XP Servers Package + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components False True - True - True True True True diff --git a/Net/Linux.epoll.pas b/Net/Linux.epoll.pas index 3dca1e7..b876503 100644 --- a/Net/Linux.epoll.pas +++ b/Net/Linux.epoll.pas @@ -1,79 +1,79 @@ -{******************************************************************************} -{ } -{ Delphi cross platform socket library } -{ } -{ Copyright (c) 2017 WiNDDRiVER(soulawing@gmail.com) } -{ } -{ Homepage: https://github.com/winddriver/Delphi-Cross-Socket } -{ } -{******************************************************************************} -unit Linux.epoll; - -{$I zLib.inc} - -interface - -uses - {$IFDEF DELPHI} - Posix.Base, - Posix.StdDef, - Posix.SysTypes, - Posix.Signal - {$ELSE} - BaseUnix, - Unix - {$ENDIF} - ; - -const - EPOLLIN = $01; { The associated file is available for read(2) operations. } - EPOLLPRI = $02; { There is urgent data available for read(2) operations. } - EPOLLOUT = $04; { The associated file is available for write(2) operations. } - EPOLLERR = $08; { Error condition happened on the associated file descriptor. } - EPOLLHUP = $10; { Hang up happened on the associated file descriptor. } - EPOLLONESHOT = $40000000; { Sets the One-Shot behaviour for the associated file descriptor. } - EPOLLET = $80000000; { Sets the Edge Triggered behaviour for the associated file descriptor. } - - { Valid opcodes ( "op" parameter ) to issue to epoll_ctl } - EPOLL_CTL_ADD = 1; - EPOLL_CTL_DEL = 2; - EPOLL_CTL_MOD = 3; - -type - EPoll_Data = record - case integer of - 0: (ptr: pointer); - 1: (fd: Integer); - 2: (u32: Cardinal); - 3: (u64: UInt64); - end; - TEPoll_Data = Epoll_Data; - PEPoll_Data = ^Epoll_Data; - - EPoll_Event = {$IFDEF CPUX64}packed {$ENDIF}record - Events: Cardinal; - Data : TEpoll_Data; - end; - - TEPoll_Event = Epoll_Event; - PEpoll_Event = ^Epoll_Event; - -{$IF DEFINED(FPC)} -{$LINKLIB c} -{$ENDIF} - -{ open an epoll file descriptor } -function epoll_create(size: Integer): Integer; cdecl; - external {$IFDEF DELPHI}libc name 'epoll_create'{$ENDIF}; - -{ control interface for an epoll descriptor } -function epoll_ctl(epfd, op, fd: Integer; event: pepoll_event): Integer; cdecl; - external {$IFDEF DELPHI}libc name 'epoll_ctl'{$ENDIF}; - -{ wait for an I/O event on an epoll file descriptor } -function epoll_wait(epfd: Integer; events: pepoll_event; maxevents, timeout: Integer): Integer; cdecl; - external {$IFDEF DELPHI}libc name 'epoll_wait'{$ENDIF}; - -implementation - -end. +{******************************************************************************} +{ } +{ Delphi cross platform socket library } +{ } +{ Copyright (c) 2017 WiNDDRiVER(soulawing@gmail.com) } +{ } +{ Homepage: https://github.com/winddriver/Delphi-Cross-Socket } +{ } +{******************************************************************************} +unit Linux.epoll; + +{$I zLib.inc} + +interface + +uses + {$IFDEF DELPHI} + Posix.Base, + Posix.StdDef, + Posix.SysTypes, + Posix.Signal + {$ELSE} + BaseUnix, + Unix + {$ENDIF} + ; + +const + EPOLLIN = $01; { The associated file is available for read(2) operations. } + EPOLLPRI = $02; { There is urgent data available for read(2) operations. } + EPOLLOUT = $04; { The associated file is available for write(2) operations. } + EPOLLERR = $08; { Error condition happened on the associated file descriptor. } + EPOLLHUP = $10; { Hang up happened on the associated file descriptor. } + EPOLLONESHOT = $40000000; { Sets the One-Shot behaviour for the associated file descriptor. } + EPOLLET = $80000000; { Sets the Edge Triggered behaviour for the associated file descriptor. } + + { Valid opcodes ( "op" parameter ) to issue to epoll_ctl } + EPOLL_CTL_ADD = 1; + EPOLL_CTL_DEL = 2; + EPOLL_CTL_MOD = 3; + +type + EPoll_Data = record + case integer of + 0: (ptr: pointer); + 1: (fd: Integer); + 2: (u32: Cardinal); + 3: (u64: UInt64); + end; + TEPoll_Data = Epoll_Data; + PEPoll_Data = ^Epoll_Data; + + EPoll_Event = {$IFDEF CPUX64}packed {$ENDIF}record + Events: Cardinal; + Data : TEpoll_Data; + end; + + TEPoll_Event = Epoll_Event; + PEpoll_Event = ^Epoll_Event; + +{$IF DEFINED(FPC)} +{$LINKLIB c} +{$ENDIF} + +{ open an epoll file descriptor } +function epoll_create(size: Integer): Integer; cdecl; + external {$IFDEF DELPHI}libc name 'epoll_create'{$ENDIF}; + +{ control interface for an epoll descriptor } +function epoll_ctl(epfd, op, fd: Integer; event: pepoll_event): Integer; cdecl; + external {$IFDEF DELPHI}libc name 'epoll_ctl'{$ENDIF}; + +{ wait for an I/O event on an epoll file descriptor } +function epoll_wait(epfd: Integer; events: pepoll_event; maxevents, timeout: Integer): Integer; cdecl; + external {$IFDEF DELPHI}libc name 'epoll_wait'{$ENDIF}; + +implementation + +end. diff --git a/Net/Net.Posix.inc b/Net/Net.Posix.inc index e422935..44d6910 100644 --- a/Net/Net.Posix.inc +++ b/Net/Net.Posix.inc @@ -1,43 +1,43 @@ -function PosixSend(ASocket: THandle; ABuf: Pointer; - ALen: Integer): Integer; -var - LBuf: PByte; - LSent, LError: Integer; - LFlags: Integer; -begin - Result := 0; - - // һѾرյ׽ַʱϵͳֱ׳EPIPE쳣³˳ - // LINUX¿sendʱMSG_NOSIGNALܱķ - // OSXпͨ׽ֵSO_NOSIGPIPEﵽͬĿ - //{$IF defined(LINUX) or defined(ANDROID) or defined(FREEBSD)} - {$IFNDEF MACOS} - LFlags := MSG_NOSIGNAL; - {$ELSE} - LFlags := 0; - {$ENDIF} - - LBuf := ABuf; - while (Result < ALen) do - begin - LSent := TSocketAPI.Send(ASocket, LBuf^, ALen - Result, LFlags); - - if (LSent < 0) then - begin - LError := GetLastError; - - // ϵͳźж, send - if (LError = EINTR) then - Continue - // ͻѱ - else if (LError = EAGAIN) or (LError = EWOULDBLOCK) then - Break - // ͳ - else - Exit(-1); - end; - - Inc(Result, LSent); - Inc(LBuf, LSent); - end; -end; +function PosixSend(ASocket: THandle; ABuf: Pointer; + ALen: Integer): Integer; +var + LBuf: PByte; + LSent, LError: Integer; + LFlags: Integer; +begin + Result := 0; + + // һѾرյ׽ַʱϵͳֱ׳EPIPE쳣³˳ + // LINUX¿sendʱMSG_NOSIGNALܱķ + // OSXпͨ׽ֵSO_NOSIGPIPEﵽͬĿ + //{$IF defined(LINUX) or defined(ANDROID) or defined(FREEBSD)} + {$IFNDEF MACOS} + LFlags := MSG_NOSIGNAL; + {$ELSE} + LFlags := 0; + {$ENDIF} + + LBuf := ABuf; + while (Result < ALen) do + begin + LSent := TSocketAPI.Send(ASocket, LBuf^, ALen - Result, LFlags); + + if (LSent < 0) then + begin + LError := GetLastError; + + // ϵͳźж, send + if (LError = EINTR) then + Continue + // ͻѱ + else if (LError = EAGAIN) or (LError = EWOULDBLOCK) then + Break + // ͳ + else + Exit(-1); + end; + + Inc(Result, LSent); + Inc(LBuf, LSent); + end; +end; diff --git a/boss.json b/boss.json index 2586ea6..0144286 100644 --- a/boss.json +++ b/boss.json @@ -1,11 +1,11 @@ -{ - "name": "delphi-cross-socket", - "description": "Delphi cross-platform async socket library (IOCP/epoll/kqueue) with HTTP server and OpenSSL 3.x support. Fork of winddriver/Delphi-Cross-Socket — adds Boss package manifest only. Zero source changes.", - "version": "1.0.3", - "homepage": "https://github.com/freitasjca/Delphi-Cross-Socket", - "license": "MIT", - "mainsrc": "Net/", - "browsingpath": "Net/;Utils/;CnPack/Common/;CnPack/Crypto/", - "projects": [], - "dependencies": {} +{ + "name": "delphi-cross-socket", + "description": "Delphi cross-platform async socket library (IOCP/epoll/kqueue) with HTTP server and OpenSSL 3.x support. Fork of winddriver/Delphi-Cross-Socket — adds Boss package manifest only. Zero source changes.", + "version": "1.0.3", + "homepage": "https://github.com/freitasjca/Delphi-Cross-Socket", + "license": "MIT", + "mainsrc": "Net/", + "browsingpath": "Net/;Utils/;CnPack/Common/;CnPack/Crypto/", + "projects": [], + "dependencies": {} } \ No newline at end of file From 8ca332040e79b0721a5382b534041b1bf20bd001 Mon Sep 17 00:00:00 2001 From: freitasjca Date: Mon, 29 Jun 2026 16:03:02 +0100 Subject: [PATCH 11/15] chore: renormalize line endings per .gitattributes --- CnPack/Common/CnPack.inc | 7246 +++++++++---------- Net/Net.CrossHttpParams.pas | 7018 +++++++++--------- Net/Net.CrossHttpServer.pas | 11758 +++++++++++++++---------------- Net/Net.CrossHttpUtils.pas | 4226 +++++------ Net/Net.CrossSocket.Epoll.pas | 2154 +++--- Net/Net.CrossSocket.Iocp.pas | 1782 ++--- Net/Net.CrossSocket.Kqueue.pas | 2224 +++--- 7 files changed, 18204 insertions(+), 18204 deletions(-) diff --git a/CnPack/Common/CnPack.inc b/CnPack/Common/CnPack.inc index cad0164..3ffcc8d 100644 --- a/CnPack/Common/CnPack.inc +++ b/CnPack/Common/CnPack.inc @@ -1,3623 +1,3623 @@ -{******************************************************************************} -{ CnPack For Delphi/C++Builder } -{ йԼĿԴ } -{ (C)Copyright 2001-2025 CnPack } -{ ------------------------------------ } -{ } -{ ǿԴ CnPack ķЭ } -{ ĺ·һ } -{ } -{ һĿϣãûκεû } -{ ʺضĿĶĵϸ CnPack Э顣 } -{ } -{ ӦѾͿһյһ CnPack Эĸ } -{ ûУɷǵվ } -{ } -{ վַhttps://www.cnpack.org } -{ ʼmaster@cnpack.org } -{ } -{******************************************************************************} - -{******************************************************************************} -{ } -{ עõԪΪָͱ汾Ϣļ } -{ õԪݲֲο JCL GExperts } -{ } -{******************************************************************************} - -//============================================================================== -// ѡ -//============================================================================== - -{$IFDEF FPC} - // Free Pascal Compiler 3.x Up Definitions - {$DEFINE SUPPORT_PASCAL} // Pascal - {$DEFINE SUPPORT_UINT64} // UInt64 - {$DEFINE SUPPORT_32_AND_64} // ֧ 32 64 λ NativeInt - {$DEFINE SUPPORT_ENCODING} // Unicode ַ֧ Encoding ת - {$DEFINE SUPPORT_INLINE} // ֧ inline - - {$DEFINE OBJECT_HAS_TOSTRING} // TObject.ToString - {$DEFINE TBYTES_DEFINED} - - // CPU FPC ӳ䵽 Delphi - {$IFDEF CPU386} // Intel 32 CPU - {$DEFINE CPU32BITS} - {$DEFINE CPUX86} - {$asmMode intel} - {$ENDIF} - {$IFDEF CPUi386} - {$DEFINE CPU32BITS} - {$DEFINE CPUX86} - {$asmMode intel} - {$ENDIF} - - {$IFDEF CPUAMD64} // Intel 64 CPU - {$DEFINE CPU64BITS} - {$DEFINE CPUX64} - {$asmMode intel} - {$ENDIF} - {$IFDEF CPUX86_64} - {$DEFINE CPU64BITS} - {$DEFINE CPUX64} - {$asmMode intel} - {$ENDIF} - {$IFDEF CPUIA64} - {$DEFINE CPU64BITS} - {$DEFINE CPUX64} - {$asmMode intel} - {$ENDIF} - - {$IFDEF CPUARM} // ARM 32 bit processor - {$DEFINE CPU32BITS} - {$DEFINE CPUARM} - {$DEFINE CPUARM32} - {$ENDIF} - - {$IFDEF CPUAARCH64} // ARM 64 bit processor - {$DEFINE CPU64BITS} - {$DEFINE CPUARM} - {$DEFINE CPUARM64} - {$ENDIF} - - {$mode Delphi} // Delphi Compatibility, not DelphiUnicodeעԴظ - - // ر Range Check Overflow Check - {$R- No Range checking} - {$OVERFLOWCHECKS OFF} - -{$ELSE FPC} // Below is for Delphi Compiler - -//{$DEFINE PERSONAL_EDITION} -{$DEFINE ENTERPRISE_EDITION} - -{$IFNDEF PERSONAL_EDITION} - {$DEFINE SUPPORT_DB} - {$DEFINE SUPPORT_ADO} -{$ENDIF} - -//============================================================================== -// 汾Ϣ -//============================================================================== - -{$IFDEF VER360} - {$DEFINE COMPILER29} - {$IFDEF LINUX} - {$DEFINE UCL10} - {$ELSE} - {$DEFINE VCL71} - {$ENDIF} - {$DEFINE DELPHI29} - {$DEFINE DELPHI120_ATHENS} - {$DEFINE BCB28} - {$DEFINE BCB120_ATHENS} - {$DEFINE BDS23} -{$ENDIF} - -{$IFDEF VER350} - {$DEFINE COMPILER28} - {$IFDEF LINUX} - {$DEFINE UCL10} - {$ELSE} - {$DEFINE VCL71} - {$ENDIF} - {$DEFINE DELPHI28} - {$DEFINE DELPHI110_ALEXANDRIA} - {$DEFINE BCB28} - {$DEFINE BCB110_ALEXANDRIA} - {$DEFINE BDS22} -{$ENDIF} - -{$IFDEF VER340} - {$DEFINE COMPILER27} - {$IFDEF LINUX} - {$DEFINE UCL10} - {$ELSE} - {$DEFINE VCL71} - {$ENDIF} - {$DEFINE DELPHI27} - {$DEFINE DELPHI104_SYDNEY} - {$DEFINE BCB27} - {$DEFINE BCB104_SYDNEY} - {$DEFINE BDS21} -{$ENDIF} - -{$IFDEF VER330} - {$DEFINE COMPILER26} - {$IFDEF LINUX} - {$DEFINE UCL10} - {$ELSE} - {$DEFINE VCL71} - {$ENDIF} - {$DEFINE DELPHI26} - {$DEFINE DELPHI103_RIO} - {$DEFINE BCB26} - {$DEFINE BCB103_RIO} - {$DEFINE BDS20} -{$ENDIF} - -{$IFDEF VER320} - {$DEFINE COMPILER25} - {$IFDEF LINUX} - {$DEFINE UCL10} - {$ELSE} - {$DEFINE VCL71} - {$ENDIF} - {$DEFINE DELPHI25} - {$DEFINE DELPHI102_TOKYO} - {$DEFINE BCB25} - {$DEFINE BCB102_TOKYO} - {$DEFINE BDS19} -{$ENDIF} - -{$IFDEF VER310} - {$DEFINE COMPILER24} - {$IFDEF LINUX} - {$DEFINE UCL10} - {$ELSE} - {$DEFINE VCL71} - {$ENDIF} - {$DEFINE DELPHI24} - {$DEFINE DELPHI101_BERLIN} - {$DEFINE BCB24} - {$DEFINE BCB101_BERLIN} - {$DEFINE BDS18} -{$ENDIF} - -{$IFDEF VER300} - {$DEFINE COMPILER23} - {$IFDEF LINUX} - {$DEFINE UCL10} - {$ELSE} - {$DEFINE VCL71} - {$ENDIF} - {$DEFINE DELPHI23} - {$DEFINE DELPHI10_SEATTLE} - {$DEFINE BCB23} - {$DEFINE BCB10_SEATTLE} - {$DEFINE BDS17} -{$ENDIF} - -{$IFDEF VER290} - {$DEFINE COMPILER22} - {$IFDEF LINUX} - {$DEFINE UCL10} - {$ELSE} - {$DEFINE VCL71} - {$ENDIF} - {$DEFINE DELPHI22} - {$DEFINE DELPHIXE8} - {$DEFINE BCB22} - {$DEFINE BCBXE8} - {$DEFINE BDS16} -{$ENDIF} - -{$IFDEF VER280} - {$DEFINE COMPILER21} - {$IFDEF LINUX} - {$DEFINE UCL10} - {$ELSE} - {$DEFINE VCL71} - {$ENDIF} - {$DEFINE DELPHI21} - {$DEFINE DELPHIXE7} - {$DEFINE BCB21} - {$DEFINE BCBXE7} - {$DEFINE BDS15} -{$ENDIF} - -{$IFDEF VER270} - {$DEFINE COMPILER20} - {$IFDEF LINUX} - {$DEFINE UCL10} - {$ELSE} - {$DEFINE VCL71} - {$ENDIF} - {$DEFINE DELPHI20} - {$DEFINE DELPHIXE6} - {$DEFINE BCB20} - {$DEFINE BCBXE6} - {$DEFINE BDS14} -{$ENDIF} - -{$IFDEF VER260} - {$DEFINE COMPILER19} - {$IFDEF LINUX} - {$DEFINE UCL10} - {$ELSE} - {$DEFINE VCL71} - {$ENDIF} - {$DEFINE DELPHI19} - {$DEFINE DELPHIXE5} - {$DEFINE BCB19} - {$DEFINE BCBXE5} - {$DEFINE BDS12} -{$ENDIF} - -{$IFDEF VER250} - {$DEFINE COMPILER18} - {$IFDEF LINUX} - {$DEFINE UCL10} - {$ELSE} - {$DEFINE VCL71} - {$ENDIF} - {$DEFINE DELPHI18} - {$DEFINE DELPHIXE4} - {$DEFINE BCB18} - {$DEFINE BCBXE4} - {$DEFINE BDS11} -{$ENDIF} - -{$IFDEF VER240} - {$DEFINE COMPILER17} - {$IFDEF LINUX} - {$DEFINE UCL10} - {$ELSE} - {$DEFINE VCL71} - {$ENDIF} - {$DEFINE DELPHI17} - {$DEFINE DELPHIXE3} - {$DEFINE DELPHI2013} - {$DEFINE BCB17} - {$DEFINE BCBXE3} - {$DEFINE BCB2013} - {$DEFINE BDS10} - {$DEFINE BDS2013} -{$ENDIF} - -{$IFDEF VER230} - {$DEFINE COMPILER16} - {$IFDEF LINUX} - {$DEFINE UCL10} - {$ELSE} - {$DEFINE VCL71} - {$ENDIF} - {$DEFINE DELPHI16} - {$DEFINE DELPHIXE2} - {$DEFINE DELPHI2012} - {$DEFINE BCB16} - {$DEFINE BCBXE2} - {$DEFINE BCB2012} - {$DEFINE BDS9} - {$DEFINE BDS2012} -{$ENDIF} - -{$IFDEF VER220} - {$DEFINE COMPILER15} - {$IFDEF LINUX} - {$DEFINE UCL10} - {$ELSE} - {$DEFINE VCL71} - {$ENDIF} - {$DEFINE DELPHI15} - {$DEFINE DELPHIXE} - {$DEFINE DELPHI2011} - {$DEFINE BCB15} - {$DEFINE BCBXE} - {$DEFINE BCB2011} - {$DEFINE BDS8} - {$DEFINE BDS2011} -{$ENDIF} - -{$IFDEF VER210} - {$DEFINE COMPILER14} - {$DEFINE VCL71} - {$DEFINE DELPHI14} - {$DEFINE DELPHI2010} - {$DEFINE BCB14} - {$DEFINE BCB2010} - {$DEFINE BDS7} - {$DEFINE BDS2010} -{$ENDIF} - -{$IFDEF VER200} - {$DEFINE COMPILER12} - {$DEFINE VCL71} - {$DEFINE DELPHI12} - {$DEFINE DELPHI2009} - {$DEFINE BCB12} - {$DEFINE BCB2009} - {$DEFINE BDS6} - {$DEFINE BDS2009} -{$ENDIF} - -{$IFDEF VER185} - {$DEFINE COMPILER11} - {$DEFINE VCL71} - {$DEFINE DELPHI11} - {$DEFINE DELPHI2007} - {$DEFINE BCB11} - {$DEFINE BCB2007} - {$DEFINE BDS5} - {$DEFINE BDS2007} - {$UNDEF VER180} -{$ENDIF} - -{$IFDEF VER180} - {$DEFINE COMPILER10} - {$DEFINE VCL71} - {$DEFINE DELPHI10} - {$DEFINE DELPHI2006} - {$DEFINE BCB10} - {$DEFINE BCB2006} - {$DEFINE BDS4} - {$DEFINE BDS2006} -{$ENDIF} - -{$IFDEF VER170} - {$DEFINE COMPILER9} - {$DEFINE VCL71} - {$DEFINE DELPHI9} - {$DEFINE DELPHI2005} - {$DEFINE BDS3} - {$DEFINE BDS2005} -{$ENDIF} - -{$IFDEF VER160} - {$DEFINE COMPILER8} - {$DEFINE VCL71} - {$DEFINE DELPHI8} - {$DEFINE BDS2} -{$ENDIF} - -{$IFDEF VER150} - {$DEFINE COMPILER7} - {$IFDEF LINUX} - {$DEFINE CLX10} - {$ELSE} - {$DEFINE VCL70} - {$DEFINE CLX10} - {$IFDEF BCB} - {$DEFINE BCB7} - {$ELSE} - {$DEFINE DELPHI7} - {$ENDIF} - {$ENDIF} -{$ENDIF} - -{$IFDEF VER140} - {$DEFINE COMPILER6} - {$IFDEF LINUX} - {$DEFINE CLX10} - {$IFDEF CONDITIONALEXPRESSIONS} - {$IFDEF CompilerVersion} - {$IF System.RTLVersion = 14.1} - {$DEFINE KYLIX2} - {$IFEND} - {$IF System.RTLVersion = 14.5} - {$DEFINE KYLIX3} - {$IFEND} - {$ELSE} - {$DEFINE KYLIX1} - {$ENDIF} - {$ENDIF} - {$ELSE} - {$DEFINE VCL60} - {$DEFINE CLX10} - {$IFDEF BCB} - {$DEFINE BCB6} - {$ELSE} - {$DEFINE DELPHI6} - {$ENDIF} - {$ENDIF} -{$ENDIF} - -{$IFDEF VER130} - {$DEFINE COMPILER5} - {$DEFINE VCL50} - {$IFDEF BCB} - {$DEFINE BCB5} - {$ELSE} - {$DEFINE DELPHI5} - {$ENDIF} -{$ENDIF} - -{$IFDEF VER125} - {$DEFINE COMPILER4} - {$DEFINE VCL40} - {$DEFINE BCB4} -{$ENDIF} - -{$IFDEF VER120} - {$DEFINE COMPILER4} - {$DEFINE VCL40} - {$DEFINE DELPHI4} -{$ENDIF} - -{$IFDEF VER110} - {$DEFINE COMPILER35} - {$DEFINE VCL30} - {$DEFINE BCB3} -{$ENDIF} - -{$IFDEF VER100} - {$DEFINE COMPILER3} - {$DEFINE VCL30} - {$DEFINE DELPHI3} -{$ENDIF} - -{$IFDEF VER93} - {$DEFINE COMPILER2} - {$DEFINE VCL20} - {$DEFINE BCB1} -{$ENDIF} - -{$IFDEF VER90} - {$DEFINE COMPILER2} - {$DEFINE VCL20} - {$DEFINE DELPHI2} -{$ENDIF} - -{$IFDEF VER80} - {$DEFINE COMPILER1} - {$DEFINE VCL10} - {$DEFINE DELPHI1} -{$ENDIF} - -// DELPHIX_UP from DELPHIX mappings - -{$IFDEF DELPHI29} - {$DEFINE DELPHI} - {$DEFINE DELPHI29_UP} - {$DEFINE DELPHI28_UP} - {$DEFINE DELPHI27_UP} - {$DEFINE DELPHI26_UP} - {$DEFINE DELPHI25_UP} - {$DEFINE DELPHI24_UP} - {$DEFINE DELPHI23_UP} - {$DEFINE DELPHI22_UP} - {$DEFINE DELPHI21_UP} - {$DEFINE DELPHI20_UP} - {$DEFINE DELPHI19_UP} - {$DEFINE DELPHI18_UP} - {$DEFINE DELPHI17_UP} - {$DEFINE DELPHI16_UP} - {$DEFINE DELPHI15_UP} - {$DEFINE DELPHI14_UP} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI120_ATHENS} - {$DEFINE DELPHI120_ATHENS_UP} - {$DEFINE DELPHI110_ALEXANDRIA_UP} - {$DEFINE DELPHI104_SYDNEY_UP} - {$DEFINE DELPHI103_RIO_UP} - {$DEFINE DELPHI102_TOKYO_UP} - {$DEFINE DELPHI101_BERLIN_UP} - {$DEFINE DELPHI10_SEATTLE_UP} - {$DEFINE DELPHIXE8_UP} - {$DEFINE DELPHIXE7_UP} - {$DEFINE DELPHIXE6_UP} - {$DEFINE DELPHIXE5_UP} - {$DEFINE DELPHIXE4_UP} - {$DEFINE DELPHIXE3_UP} - {$DEFINE DELPHIXE2_UP} - {$DEFINE DELPHIXE_UP} - - // NO DELPHI2014 defined, so need define below here. - {$DEFINE DELPHI2013_UP} - {$DEFINE DELPHI2012_UP} - {$DEFINE DELPHI2011_UP} - {$DEFINE DELPHI2010_UP} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI28} - {$DEFINE DELPHI} - {$DEFINE DELPHI28_UP} - {$DEFINE DELPHI27_UP} - {$DEFINE DELPHI26_UP} - {$DEFINE DELPHI25_UP} - {$DEFINE DELPHI24_UP} - {$DEFINE DELPHI23_UP} - {$DEFINE DELPHI22_UP} - {$DEFINE DELPHI21_UP} - {$DEFINE DELPHI20_UP} - {$DEFINE DELPHI19_UP} - {$DEFINE DELPHI18_UP} - {$DEFINE DELPHI17_UP} - {$DEFINE DELPHI16_UP} - {$DEFINE DELPHI15_UP} - {$DEFINE DELPHI14_UP} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI110_ALEXANDRIA} - {$DEFINE DELPHI110_ALEXANDRIA_UP} - {$DEFINE DELPHI104_SYDNEY_UP} - {$DEFINE DELPHI103_RIO_UP} - {$DEFINE DELPHI102_TOKYO_UP} - {$DEFINE DELPHI101_BERLIN_UP} - {$DEFINE DELPHI10_SEATTLE_UP} - {$DEFINE DELPHIXE8_UP} - {$DEFINE DELPHIXE7_UP} - {$DEFINE DELPHIXE6_UP} - {$DEFINE DELPHIXE5_UP} - {$DEFINE DELPHIXE4_UP} - {$DEFINE DELPHIXE3_UP} - {$DEFINE DELPHIXE2_UP} - {$DEFINE DELPHIXE_UP} - - // NO DELPHI2014 defined, so need define below here. - {$DEFINE DELPHI2013_UP} - {$DEFINE DELPHI2012_UP} - {$DEFINE DELPHI2011_UP} - {$DEFINE DELPHI2010_UP} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI27} - {$DEFINE DELPHI} - {$DEFINE DELPHI27_UP} - {$DEFINE DELPHI26_UP} - {$DEFINE DELPHI25_UP} - {$DEFINE DELPHI24_UP} - {$DEFINE DELPHI23_UP} - {$DEFINE DELPHI22_UP} - {$DEFINE DELPHI21_UP} - {$DEFINE DELPHI20_UP} - {$DEFINE DELPHI19_UP} - {$DEFINE DELPHI18_UP} - {$DEFINE DELPHI17_UP} - {$DEFINE DELPHI16_UP} - {$DEFINE DELPHI15_UP} - {$DEFINE DELPHI14_UP} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI104_SYDNEY} - {$DEFINE DELPHI104_SYDNEY_UP} - {$DEFINE DELPHI103_RIO_UP} - {$DEFINE DELPHI102_TOKYO_UP} - {$DEFINE DELPHI101_BERLIN_UP} - {$DEFINE DELPHI10_SEATTLE_UP} - {$DEFINE DELPHIXE8_UP} - {$DEFINE DELPHIXE7_UP} - {$DEFINE DELPHIXE6_UP} - {$DEFINE DELPHIXE5_UP} - {$DEFINE DELPHIXE4_UP} - {$DEFINE DELPHIXE3_UP} - {$DEFINE DELPHIXE2_UP} - {$DEFINE DELPHIXE_UP} - - // NO DELPHI2014 defined, so need define below here. - {$DEFINE DELPHI2013_UP} - {$DEFINE DELPHI2012_UP} - {$DEFINE DELPHI2011_UP} - {$DEFINE DELPHI2010_UP} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI26} - {$DEFINE DELPHI} - {$DEFINE DELPHI26_UP} - {$DEFINE DELPHI25_UP} - {$DEFINE DELPHI24_UP} - {$DEFINE DELPHI23_UP} - {$DEFINE DELPHI22_UP} - {$DEFINE DELPHI21_UP} - {$DEFINE DELPHI20_UP} - {$DEFINE DELPHI19_UP} - {$DEFINE DELPHI18_UP} - {$DEFINE DELPHI17_UP} - {$DEFINE DELPHI16_UP} - {$DEFINE DELPHI15_UP} - {$DEFINE DELPHI14_UP} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI103_RIO} - {$DEFINE DELPHI103_RIO_UP} - {$DEFINE DELPHI102_TOKYO_UP} - {$DEFINE DELPHI101_BERLIN_UP} - {$DEFINE DELPHI10_SEATTLE_UP} - {$DEFINE DELPHIXE8_UP} - {$DEFINE DELPHIXE7_UP} - {$DEFINE DELPHIXE6_UP} - {$DEFINE DELPHIXE5_UP} - {$DEFINE DELPHIXE4_UP} - {$DEFINE DELPHIXE3_UP} - {$DEFINE DELPHIXE2_UP} - {$DEFINE DELPHIXE_UP} - - // NO DELPHI2014 defined, so need define below here. - {$DEFINE DELPHI2013_UP} - {$DEFINE DELPHI2012_UP} - {$DEFINE DELPHI2011_UP} - {$DEFINE DELPHI2010_UP} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI25} - {$DEFINE DELPHI} - {$DEFINE DELPHI25_UP} - {$DEFINE DELPHI24_UP} - {$DEFINE DELPHI23_UP} - {$DEFINE DELPHI22_UP} - {$DEFINE DELPHI21_UP} - {$DEFINE DELPHI20_UP} - {$DEFINE DELPHI19_UP} - {$DEFINE DELPHI18_UP} - {$DEFINE DELPHI17_UP} - {$DEFINE DELPHI16_UP} - {$DEFINE DELPHI15_UP} - {$DEFINE DELPHI14_UP} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI102_TOKYO} - {$DEFINE DELPHI102_TOKYO_UP} - {$DEFINE DELPHI101_BERLIN_UP} - {$DEFINE DELPHI10_SEATTLE_UP} - {$DEFINE DELPHIXE8_UP} - {$DEFINE DELPHIXE7_UP} - {$DEFINE DELPHIXE6_UP} - {$DEFINE DELPHIXE5_UP} - {$DEFINE DELPHIXE4_UP} - {$DEFINE DELPHIXE3_UP} - {$DEFINE DELPHIXE2_UP} - {$DEFINE DELPHIXE_UP} - - // NO DELPHI2014 defined, so need define below here. - {$DEFINE DELPHI2013_UP} - {$DEFINE DELPHI2012_UP} - {$DEFINE DELPHI2011_UP} - {$DEFINE DELPHI2010_UP} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI24} - {$DEFINE DELPHI} - {$DEFINE DELPHI24_UP} - {$DEFINE DELPHI23_UP} - {$DEFINE DELPHI22_UP} - {$DEFINE DELPHI21_UP} - {$DEFINE DELPHI20_UP} - {$DEFINE DELPHI19_UP} - {$DEFINE DELPHI18_UP} - {$DEFINE DELPHI17_UP} - {$DEFINE DELPHI16_UP} - {$DEFINE DELPHI15_UP} - {$DEFINE DELPHI14_UP} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI101_BERLIN} - {$DEFINE DELPHI101_BERLIN_UP} - {$DEFINE DELPHI10_SEATTLE_UP} - {$DEFINE DELPHIXE8_UP} - {$DEFINE DELPHIXE7_UP} - {$DEFINE DELPHIXE6_UP} - {$DEFINE DELPHIXE5_UP} - {$DEFINE DELPHIXE4_UP} - {$DEFINE DELPHIXE3_UP} - {$DEFINE DELPHIXE2_UP} - {$DEFINE DELPHIXE_UP} - - // NO DELPHI2014 defined, so need define below here. - {$DEFINE DELPHI2013_UP} - {$DEFINE DELPHI2012_UP} - {$DEFINE DELPHI2011_UP} - {$DEFINE DELPHI2010_UP} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI23} - {$DEFINE DELPHI} - {$DEFINE DELPHI23_UP} - {$DEFINE DELPHI22_UP} - {$DEFINE DELPHI21_UP} - {$DEFINE DELPHI20_UP} - {$DEFINE DELPHI19_UP} - {$DEFINE DELPHI18_UP} - {$DEFINE DELPHI17_UP} - {$DEFINE DELPHI16_UP} - {$DEFINE DELPHI15_UP} - {$DEFINE DELPHI14_UP} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI10_SEATTLE} - {$DEFINE DELPHI10_SEATTLE_UP} - {$DEFINE DELPHIXE8_UP} - {$DEFINE DELPHIXE7_UP} - {$DEFINE DELPHIXE6_UP} - {$DEFINE DELPHIXE5_UP} - {$DEFINE DELPHIXE4_UP} - {$DEFINE DELPHIXE3_UP} - {$DEFINE DELPHIXE2_UP} - {$DEFINE DELPHIXE_UP} - - // NO DELPHI2014 defined, so need define below here. - {$DEFINE DELPHI2013_UP} - {$DEFINE DELPHI2012_UP} - {$DEFINE DELPHI2011_UP} - {$DEFINE DELPHI2010_UP} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI22} - {$DEFINE DELPHI} - {$DEFINE DELPHI22_UP} - {$DEFINE DELPHI21_UP} - {$DEFINE DELPHI20_UP} - {$DEFINE DELPHI19_UP} - {$DEFINE DELPHI18_UP} - {$DEFINE DELPHI17_UP} - {$DEFINE DELPHI16_UP} - {$DEFINE DELPHI15_UP} - {$DEFINE DELPHI14_UP} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHIXE8} - {$DEFINE DELPHIXE8_UP} - {$DEFINE DELPHIXE7_UP} - {$DEFINE DELPHIXE6_UP} - {$DEFINE DELPHIXE5_UP} - {$DEFINE DELPHIXE4_UP} - {$DEFINE DELPHIXE3_UP} - {$DEFINE DELPHIXE2_UP} - {$DEFINE DELPHIXE_UP} - - // NO DELPHI2014 defined, so need define below here. - {$DEFINE DELPHI2013_UP} - {$DEFINE DELPHI2012_UP} - {$DEFINE DELPHI2011_UP} - {$DEFINE DELPHI2010_UP} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI21} - {$DEFINE DELPHI} - {$DEFINE DELPHI21_UP} - {$DEFINE DELPHI20_UP} - {$DEFINE DELPHI19_UP} - {$DEFINE DELPHI18_UP} - {$DEFINE DELPHI17_UP} - {$DEFINE DELPHI16_UP} - {$DEFINE DELPHI15_UP} - {$DEFINE DELPHI14_UP} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHIXE7} - {$DEFINE DELPHIXE7_UP} - {$DEFINE DELPHIXE6_UP} - {$DEFINE DELPHIXE5_UP} - {$DEFINE DELPHIXE4_UP} - {$DEFINE DELPHIXE3_UP} - {$DEFINE DELPHIXE2_UP} - {$DEFINE DELPHIXE_UP} - - // NO DELPHI2014 defined, so need define below here. - {$DEFINE DELPHI2013_UP} - {$DEFINE DELPHI2012_UP} - {$DEFINE DELPHI2011_UP} - {$DEFINE DELPHI2010_UP} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI20} - {$DEFINE DELPHI} - {$DEFINE DELPHI20_UP} - {$DEFINE DELPHI19_UP} - {$DEFINE DELPHI18_UP} - {$DEFINE DELPHI17_UP} - {$DEFINE DELPHI16_UP} - {$DEFINE DELPHI15_UP} - {$DEFINE DELPHI14_UP} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHIXE6} - {$DEFINE DELPHIXE6_UP} - {$DEFINE DELPHIXE5_UP} - {$DEFINE DELPHIXE4_UP} - {$DEFINE DELPHIXE3_UP} - {$DEFINE DELPHIXE2_UP} - {$DEFINE DELPHIXE_UP} - - // NO DELPHI2014 defined, so need define below here. - {$DEFINE DELPHI2013_UP} - {$DEFINE DELPHI2012_UP} - {$DEFINE DELPHI2011_UP} - {$DEFINE DELPHI2010_UP} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI19} - {$DEFINE DELPHI} - {$DEFINE DELPHI19_UP} - {$DEFINE DELPHI18_UP} - {$DEFINE DELPHI17_UP} - {$DEFINE DELPHI16_UP} - {$DEFINE DELPHI15_UP} - {$DEFINE DELPHI14_UP} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHIXE5} - {$DEFINE DELPHIXE5_UP} - {$DEFINE DELPHIXE4_UP} - {$DEFINE DELPHIXE3_UP} - {$DEFINE DELPHIXE2_UP} - {$DEFINE DELPHIXE_UP} - - // NO DELPHI2014 defined, so need define below here. - {$DEFINE DELPHI2013_UP} - {$DEFINE DELPHI2012_UP} - {$DEFINE DELPHI2011_UP} - {$DEFINE DELPHI2010_UP} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI18} - {$DEFINE DELPHI} - {$DEFINE DELPHI18_UP} - {$DEFINE DELPHI17_UP} - {$DEFINE DELPHI16_UP} - {$DEFINE DELPHI15_UP} - {$DEFINE DELPHI14_UP} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHIXE4} - {$DEFINE DELPHIXE4_UP} - {$DEFINE DELPHIXE3_UP} - {$DEFINE DELPHIXE2_UP} - {$DEFINE DELPHIXE_UP} - - // NO DELPHI2014 defined, so need define below here. - {$DEFINE DELPHI2013_UP} - {$DEFINE DELPHI2012_UP} - {$DEFINE DELPHI2011_UP} - {$DEFINE DELPHI2010_UP} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI17} - {$DEFINE DELPHI} - {$DEFINE DELPHI17_UP} - {$DEFINE DELPHI16_UP} - {$DEFINE DELPHI15_UP} - {$DEFINE DELPHI14_UP} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHIXE3} - {$DEFINE DELPHIXE3_UP} - {$DEFINE DELPHIXE2_UP} - {$DEFINE DELPHIXE_UP} -{$ENDIF} - -{$IFDEF DELPHI2013} - {$DEFINE DELPHI2013_UP} - {$DEFINE DELPHI2012_UP} - {$DEFINE DELPHI2011_UP} - {$DEFINE DELPHI2010_UP} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI16} - {$DEFINE DELPHI} - {$DEFINE DELPHI16_UP} - {$DEFINE DELPHI15_UP} - {$DEFINE DELPHI14_UP} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHIXE2} - {$DEFINE DELPHIXE2_UP} - {$DEFINE DELPHIXE_UP} -{$ENDIF} - -{$IFDEF DELPHI2012} - {$DEFINE DELPHI2012_UP} - {$DEFINE DELPHI2011_UP} - {$DEFINE DELPHI2010_UP} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI15} - {$DEFINE DELPHI} - {$DEFINE DELPHI15_UP} - {$DEFINE DELPHI14_UP} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHIXE} - {$DEFINE DELPHIXE_UP} -{$ENDIF} - -{$IFDEF DELPHI2011} - {$DEFINE DELPHI2011_UP} - {$DEFINE DELPHI2010_UP} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI14} - {$DEFINE DELPHI} - {$DEFINE DELPHI14_UP} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI2010} - {$DEFINE DELPHI2010_UP} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI12} - {$DEFINE DELPHI} - {$DEFINE DELPHI12_UP} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI2009} - {$DEFINE DELPHI2009_UP} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI11} - {$DEFINE DELPHI} - {$DEFINE DELPHI11_UP} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI2007} - {$DEFINE DELPHI2007_UP} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI10} - {$DEFINE DELPHI} - {$DEFINE DELPHI10_UP} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI2006} - {$DEFINE DELPHI2006_UP} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI9} - {$DEFINE DELPHI} - {$DEFINE DELPHI9_UP} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI2005} - {$DEFINE DELPHI2005_UP} -{$ENDIF} - -{$IFDEF DELPHI8} - {$DEFINE DELPHI} - {$DEFINE DELPHI8_UP} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI7} - {$DEFINE DELPHI} - {$DEFINE DELPHI7_UP} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI6} - {$DEFINE DELPHI} - {$DEFINE DELPHI6_UP} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI5} - {$DEFINE DELPHI} - {$DEFINE DELPHI5_UP} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI4} - {$DEFINE DELPHI} - {$DEFINE DELPHI4_UP} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI3} - {$DEFINE DELPHI} - {$DEFINE DELPHI3_UP} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI2} - {$DEFINE DELPHI} - {$DEFINE DELPHI2_UP} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -{$IFDEF DELPHI1} - {$DEFINE DELPHI} - {$DEFINE DELPHI1_UP} -{$ENDIF} - -// BCBX_UP from BCBX mappings - -{$IFDEF BCB29} - {$DEFINE BCB} - {$DEFINE BCB29_UP} - {$DEFINE BCB28_UP} - {$DEFINE BCB27_UP} - {$DEFINE BCB26_UP} - {$DEFINE BCB25_UP} - {$DEFINE BCB24_UP} - {$DEFINE BCB23_UP} - {$DEFINE BCB22_UP} - {$DEFINE BCB21_UP} - {$DEFINE BCB20_UP} - {$DEFINE BCB19_UP} - {$DEFINE BCB18_UP} - {$DEFINE BCB17_UP} - {$DEFINE BCB16_UP} - {$DEFINE BCB15_UP} - {$DEFINE BCB14_UP} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCB120_ATHENS} - {$DEFINE BCB120_ATHENS_UP} - {$DEFINE BCB110_ALEXANDRIA_UP} - {$DEFINE BCB104_SYDNEY_UP} - {$DEFINE BCB103_RIO_UP} - {$DEFINE BCB102_TOKYO_UP} - {$DEFINE BCB101_BERLIN_UP} - {$DEFINE BCB10_SEATTLE_UP} - {$DEFINE BCBXE8_UP} - {$DEFINE BCBXE7_UP} - {$DEFINE BCBXE6_UP} - {$DEFINE BCBXE5_UP} - {$DEFINE BCBXE4_UP} - {$DEFINE BCBXE3_UP} - {$DEFINE BCBXE2_UP} - {$DEFINE BCBXE_UP} - - // NO BCB2014 defined, so need define below here. - {$DEFINE BCB2013_UP} - {$DEFINE BCB2012_UP} - {$DEFINE BCB2011_UP} - {$DEFINE BCB2010_UP} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB28} - {$DEFINE BCB} - {$DEFINE BCB28_UP} - {$DEFINE BCB27_UP} - {$DEFINE BCB26_UP} - {$DEFINE BCB25_UP} - {$DEFINE BCB24_UP} - {$DEFINE BCB23_UP} - {$DEFINE BCB22_UP} - {$DEFINE BCB21_UP} - {$DEFINE BCB20_UP} - {$DEFINE BCB19_UP} - {$DEFINE BCB18_UP} - {$DEFINE BCB17_UP} - {$DEFINE BCB16_UP} - {$DEFINE BCB15_UP} - {$DEFINE BCB14_UP} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCB110_ALEXANDRIA} - {$DEFINE BCB110_ALEXANDRIA_UP} - {$DEFINE BCB104_SYDNEY_UP} - {$DEFINE BCB103_RIO_UP} - {$DEFINE BCB102_TOKYO_UP} - {$DEFINE BCB101_BERLIN_UP} - {$DEFINE BCB10_SEATTLE_UP} - {$DEFINE BCBXE8_UP} - {$DEFINE BCBXE7_UP} - {$DEFINE BCBXE6_UP} - {$DEFINE BCBXE5_UP} - {$DEFINE BCBXE4_UP} - {$DEFINE BCBXE3_UP} - {$DEFINE BCBXE2_UP} - {$DEFINE BCBXE_UP} - - // NO BCB2014 defined, so need define below here. - {$DEFINE BCB2013_UP} - {$DEFINE BCB2012_UP} - {$DEFINE BCB2011_UP} - {$DEFINE BCB2010_UP} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB27} - {$DEFINE BCB} - {$DEFINE BCB27_UP} - {$DEFINE BCB26_UP} - {$DEFINE BCB25_UP} - {$DEFINE BCB24_UP} - {$DEFINE BCB23_UP} - {$DEFINE BCB22_UP} - {$DEFINE BCB21_UP} - {$DEFINE BCB20_UP} - {$DEFINE BCB19_UP} - {$DEFINE BCB18_UP} - {$DEFINE BCB17_UP} - {$DEFINE BCB16_UP} - {$DEFINE BCB15_UP} - {$DEFINE BCB14_UP} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCB104_SYDNEY} - {$DEFINE BCB104_SYDNEY_UP} - {$DEFINE BCB103_RIO_UP} - {$DEFINE BCB102_TOKYO_UP} - {$DEFINE BCB101_BERLIN_UP} - {$DEFINE BCB10_SEATTLE_UP} - {$DEFINE BCBXE8_UP} - {$DEFINE BCBXE7_UP} - {$DEFINE BCBXE6_UP} - {$DEFINE BCBXE5_UP} - {$DEFINE BCBXE4_UP} - {$DEFINE BCBXE3_UP} - {$DEFINE BCBXE2_UP} - {$DEFINE BCBXE_UP} - - // NO BCB2014 defined, so need define below here. - {$DEFINE BCB2013_UP} - {$DEFINE BCB2012_UP} - {$DEFINE BCB2011_UP} - {$DEFINE BCB2010_UP} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB26} - {$DEFINE BCB} - {$DEFINE BCB26_UP} - {$DEFINE BCB25_UP} - {$DEFINE BCB24_UP} - {$DEFINE BCB23_UP} - {$DEFINE BCB22_UP} - {$DEFINE BCB21_UP} - {$DEFINE BCB20_UP} - {$DEFINE BCB19_UP} - {$DEFINE BCB18_UP} - {$DEFINE BCB17_UP} - {$DEFINE BCB16_UP} - {$DEFINE BCB15_UP} - {$DEFINE BCB14_UP} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCB103_RIO} - {$DEFINE BCB103_RIO_UP} - {$DEFINE BCB102_TOKYO_UP} - {$DEFINE BCB101_BERLIN_UP} - {$DEFINE BCB10_SEATTLE_UP} - {$DEFINE BCBXE8_UP} - {$DEFINE BCBXE7_UP} - {$DEFINE BCBXE6_UP} - {$DEFINE BCBXE5_UP} - {$DEFINE BCBXE4_UP} - {$DEFINE BCBXE3_UP} - {$DEFINE BCBXE2_UP} - {$DEFINE BCBXE_UP} - - // NO BCB2014 defined, so need define below here. - {$DEFINE BCB2013_UP} - {$DEFINE BCB2012_UP} - {$DEFINE BCB2011_UP} - {$DEFINE BCB2010_UP} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB25} - {$DEFINE BCB} - {$DEFINE BCB25_UP} - {$DEFINE BCB24_UP} - {$DEFINE BCB23_UP} - {$DEFINE BCB22_UP} - {$DEFINE BCB21_UP} - {$DEFINE BCB20_UP} - {$DEFINE BCB19_UP} - {$DEFINE BCB18_UP} - {$DEFINE BCB17_UP} - {$DEFINE BCB16_UP} - {$DEFINE BCB15_UP} - {$DEFINE BCB14_UP} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCB102_TOKYO} - {$DEFINE BCB102_TOKYO_UP} - {$DEFINE BCB101_BERLIN_UP} - {$DEFINE BCB10_SEATTLE_UP} - {$DEFINE BCBXE8_UP} - {$DEFINE BCBXE7_UP} - {$DEFINE BCBXE6_UP} - {$DEFINE BCBXE5_UP} - {$DEFINE BCBXE4_UP} - {$DEFINE BCBXE3_UP} - {$DEFINE BCBXE2_UP} - {$DEFINE BCBXE_UP} - - // NO BCB2014 defined, so need define below here. - {$DEFINE BCB2013_UP} - {$DEFINE BCB2012_UP} - {$DEFINE BCB2011_UP} - {$DEFINE BCB2010_UP} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - - -{$IFDEF BCB24} - {$DEFINE BCB} - {$DEFINE BCB24_UP} - {$DEFINE BCB23_UP} - {$DEFINE BCB22_UP} - {$DEFINE BCB21_UP} - {$DEFINE BCB20_UP} - {$DEFINE BCB19_UP} - {$DEFINE BCB18_UP} - {$DEFINE BCB17_UP} - {$DEFINE BCB16_UP} - {$DEFINE BCB15_UP} - {$DEFINE BCB14_UP} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCB101_BERLIN} - {$DEFINE BCB101_BERLIN_UP} - {$DEFINE BCB10_SEATTLE_UP} - {$DEFINE BCBXE8_UP} - {$DEFINE BCBXE7_UP} - {$DEFINE BCBXE6_UP} - {$DEFINE BCBXE5_UP} - {$DEFINE BCBXE4_UP} - {$DEFINE BCBXE3_UP} - {$DEFINE BCBXE2_UP} - {$DEFINE BCBXE_UP} - - // NO BCB2014 defined, so need define below here. - {$DEFINE BCB2013_UP} - {$DEFINE BCB2012_UP} - {$DEFINE BCB2011_UP} - {$DEFINE BCB2010_UP} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB23} - {$DEFINE BCB} - {$DEFINE BCB23_UP} - {$DEFINE BCB22_UP} - {$DEFINE BCB21_UP} - {$DEFINE BCB20_UP} - {$DEFINE BCB19_UP} - {$DEFINE BCB18_UP} - {$DEFINE BCB17_UP} - {$DEFINE BCB16_UP} - {$DEFINE BCB15_UP} - {$DEFINE BCB14_UP} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCB10_SEATTLE} - {$DEFINE BCB10_SEATTLE_UP} - {$DEFINE BCBXE8_UP} - {$DEFINE BCBXE7_UP} - {$DEFINE BCBXE6_UP} - {$DEFINE BCBXE5_UP} - {$DEFINE BCBXE4_UP} - {$DEFINE BCBXE3_UP} - {$DEFINE BCBXE2_UP} - {$DEFINE BCBXE_UP} - - // NO BCB2014 defined, so need define below here. - {$DEFINE BCB2013_UP} - {$DEFINE BCB2012_UP} - {$DEFINE BCB2011_UP} - {$DEFINE BCB2010_UP} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB22} - {$DEFINE BCB} - {$DEFINE BCB22_UP} - {$DEFINE BCB21_UP} - {$DEFINE BCB20_UP} - {$DEFINE BCB19_UP} - {$DEFINE BCB18_UP} - {$DEFINE BCB17_UP} - {$DEFINE BCB16_UP} - {$DEFINE BCB15_UP} - {$DEFINE BCB14_UP} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCBXE8} - {$DEFINE BCBXE8_UP} - {$DEFINE BCBXE7_UP} - {$DEFINE BCBXE6_UP} - {$DEFINE BCBXE5_UP} - {$DEFINE BCBXE4_UP} - {$DEFINE BCBXE3_UP} - {$DEFINE BCBXE2_UP} - {$DEFINE BCBXE_UP} - - // NO BCB2014 defined, so need define below here. - {$DEFINE BCB2013_UP} - {$DEFINE BCB2012_UP} - {$DEFINE BCB2011_UP} - {$DEFINE BCB2010_UP} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB21} - {$DEFINE BCB} - {$DEFINE BCB21_UP} - {$DEFINE BCB20_UP} - {$DEFINE BCB19_UP} - {$DEFINE BCB18_UP} - {$DEFINE BCB17_UP} - {$DEFINE BCB16_UP} - {$DEFINE BCB15_UP} - {$DEFINE BCB14_UP} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCBXE7} - {$DEFINE BCBXE7_UP} - {$DEFINE BCBXE6_UP} - {$DEFINE BCBXE5_UP} - {$DEFINE BCBXE4_UP} - {$DEFINE BCBXE3_UP} - {$DEFINE BCBXE2_UP} - {$DEFINE BCBXE_UP} - - // NO BCB2014 defined, so need define below here. - {$DEFINE BCB2013_UP} - {$DEFINE BCB2012_UP} - {$DEFINE BCB2011_UP} - {$DEFINE BCB2010_UP} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB20} - {$DEFINE BCB} - {$DEFINE BCB20_UP} - {$DEFINE BCB19_UP} - {$DEFINE BCB18_UP} - {$DEFINE BCB17_UP} - {$DEFINE BCB16_UP} - {$DEFINE BCB15_UP} - {$DEFINE BCB14_UP} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCBXE6} - {$DEFINE BCBXE6_UP} - {$DEFINE BCBXE5_UP} - {$DEFINE BCBXE4_UP} - {$DEFINE BCBXE3_UP} - {$DEFINE BCBXE2_UP} - {$DEFINE BCBXE_UP} - - // NO BCB2014 defined, so need define below here. - {$DEFINE BCB2013_UP} - {$DEFINE BCB2012_UP} - {$DEFINE BCB2011_UP} - {$DEFINE BCB2010_UP} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB19} - {$DEFINE BCB} - {$DEFINE BCB19_UP} - {$DEFINE BCB18_UP} - {$DEFINE BCB17_UP} - {$DEFINE BCB16_UP} - {$DEFINE BCB15_UP} - {$DEFINE BCB14_UP} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCBXE5} - {$DEFINE BCBXE5_UP} - {$DEFINE BCBXE4_UP} - {$DEFINE BCBXE3_UP} - {$DEFINE BCBXE2_UP} - {$DEFINE BCBXE_UP} - - // NO BCB2014 defined, so need define below here. - {$DEFINE BCB2013_UP} - {$DEFINE BCB2012_UP} - {$DEFINE BCB2011_UP} - {$DEFINE BCB2010_UP} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB18} - {$DEFINE BCB} - {$DEFINE BCB18_UP} - {$DEFINE BCB17_UP} - {$DEFINE BCB16_UP} - {$DEFINE BCB15_UP} - {$DEFINE BCB14_UP} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCBXE4} - {$DEFINE BCBXE4_UP} - {$DEFINE BCBXE3_UP} - {$DEFINE BCBXE2_UP} - {$DEFINE BCBXE_UP} - - // NO BCB2014 defined, so need define below here. - {$DEFINE BCB2013_UP} - {$DEFINE BCB2012_UP} - {$DEFINE BCB2011_UP} - {$DEFINE BCB2010_UP} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB17} - {$DEFINE BCB} - {$DEFINE BCB17_UP} - {$DEFINE BCB16_UP} - {$DEFINE BCB15_UP} - {$DEFINE BCB14_UP} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCBXE3} - {$DEFINE BCBXE3_UP} - {$DEFINE BCBXE2_UP} - {$DEFINE BCBXE_UP} -{$ENDIF} - -{$IFDEF BCB2013} - {$DEFINE BCB2013_UP} - {$DEFINE BCB2012_UP} - {$DEFINE BCB2011_UP} - {$DEFINE BCB2010_UP} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB16} - {$DEFINE BCB} - {$DEFINE BCB16_UP} - {$DEFINE BCB15_UP} - {$DEFINE BCB14_UP} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCBXE2} - {$DEFINE BCBXE2_UP} - {$DEFINE BCBXE_UP} -{$ENDIF} - -{$IFDEF BCB2012} - {$DEFINE BCB2012_UP} - {$DEFINE BCB2011_UP} - {$DEFINE BCB2010_UP} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB15} - {$DEFINE BCB} - {$DEFINE BCB15_UP} - {$DEFINE BCB14_UP} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCBXE} - {$DEFINE BCBXE_UP} -{$ENDIF} - -{$IFDEF BCB2011} - {$DEFINE BCB2011_UP} - {$DEFINE BCB2010_UP} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB14} - {$DEFINE BCB} - {$DEFINE BCB14_UP} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCB2010} - {$DEFINE BCB2010_UP} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB12} - {$DEFINE BCB} - {$DEFINE BCB12_UP} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCB2009} - {$DEFINE BCB2009_UP} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB11} - {$DEFINE BCB} - {$DEFINE BCB11_UP} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCB2007} - {$DEFINE BCB2007_UP} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB10} - {$DEFINE BCB} - {$DEFINE BCB10_UP} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCB2006} - {$DEFINE BCB2006_UP} -{$ENDIF} - -{$IFDEF BCB7} - {$DEFINE BCB} - {$DEFINE BCB7_UP} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCB6} - {$DEFINE BCB} - {$DEFINE BCB6_UP} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCB5} - {$DEFINE BCB} - {$DEFINE BCB5_UP} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCB4} - {$DEFINE BCB} - {$DEFINE BCB4_UP} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCB3} - {$DEFINE BCB} - {$DEFINE BCB3_UP} - {$DEFINE BCB1_UP} -{$ENDIF} - -{$IFDEF BCB1} - {$DEFINE BCB} - {$DEFINE BCB1_UP} -{$ENDIF} - -// KYLIXX_UP from KYLIXX mappings - -{$IFDEF KYLIX3} - {$DEFINE KYLIX} - {$DEFINE KYLIX3_UP} - {$DEFINE KYLIX2_UP} - {$DEFINE KYLIX1_UP} -{$ENDIF} - -{$IFDEF KYLIX2} - {$DEFINE KYLIX} - {$DEFINE KYLIX2_UP} - {$DEFINE KYLIX1_UP} -{$ENDIF} - -{$IFDEF KYLIX1} - {$DEFINE KYLIX} - {$DEFINE KYLIX1_UP} -{$ENDIF} - -// BDSXX_UP from BDSXX mappings - -{$IFDEF BDS23} // 12.0 ATHENS - {$DEFINE BDS} - {$DEFINE BDS23_UP} - {$DEFINE BDS22_UP} - {$DEFINE BDS21_UP} - {$DEFINE BDS20_UP} - {$DEFINE BDS19_UP} - {$DEFINE BDS18_UP} - {$DEFINE BDS17_UP} - {$DEFINE BDS16_UP} - {$DEFINE BDS15_UP} - {$DEFINE BDS14_UP} - {$DEFINE BDS12_UP} - {$DEFINE BDS11_UP} - {$DEFINE BDS10_UP} - {$DEFINE BDS9_UP} - {$DEFINE BDS8_UP} - {$DEFINE BDS7_UP} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} - - // NO BDS2014 defined, so need define below here. - {$DEFINE BDS2013_UP} - {$DEFINE BDS2012_UP} - {$DEFINE BDS2011_UP} - {$DEFINE BDS2010_UP} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS22} // 11.0 ALEXANDRIA - {$DEFINE BDS} - {$DEFINE BDS22_UP} - {$DEFINE BDS21_UP} - {$DEFINE BDS20_UP} - {$DEFINE BDS19_UP} - {$DEFINE BDS18_UP} - {$DEFINE BDS17_UP} - {$DEFINE BDS16_UP} - {$DEFINE BDS15_UP} - {$DEFINE BDS14_UP} - {$DEFINE BDS12_UP} - {$DEFINE BDS11_UP} - {$DEFINE BDS10_UP} - {$DEFINE BDS9_UP} - {$DEFINE BDS8_UP} - {$DEFINE BDS7_UP} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} - - // NO BDS2014 defined, so need define below here. - {$DEFINE BDS2013_UP} - {$DEFINE BDS2012_UP} - {$DEFINE BDS2011_UP} - {$DEFINE BDS2010_UP} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS21} // 10.4 SYDNEY - {$DEFINE BDS} - {$DEFINE BDS21_UP} - {$DEFINE BDS20_UP} - {$DEFINE BDS19_UP} - {$DEFINE BDS18_UP} - {$DEFINE BDS17_UP} - {$DEFINE BDS16_UP} - {$DEFINE BDS15_UP} - {$DEFINE BDS14_UP} - {$DEFINE BDS12_UP} - {$DEFINE BDS11_UP} - {$DEFINE BDS10_UP} - {$DEFINE BDS9_UP} - {$DEFINE BDS8_UP} - {$DEFINE BDS7_UP} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} - - // NO BDS2014 defined, so need define below here. - {$DEFINE BDS2013_UP} - {$DEFINE BDS2012_UP} - {$DEFINE BDS2011_UP} - {$DEFINE BDS2010_UP} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS20} // 10.3 RIO - {$DEFINE BDS} - {$DEFINE BDS20_UP} - {$DEFINE BDS19_UP} - {$DEFINE BDS18_UP} - {$DEFINE BDS17_UP} - {$DEFINE BDS16_UP} - {$DEFINE BDS15_UP} - {$DEFINE BDS14_UP} - {$DEFINE BDS12_UP} - {$DEFINE BDS11_UP} - {$DEFINE BDS10_UP} - {$DEFINE BDS9_UP} - {$DEFINE BDS8_UP} - {$DEFINE BDS7_UP} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} - - // NO BDS2014 defined, so need define below here. - {$DEFINE BDS2013_UP} - {$DEFINE BDS2012_UP} - {$DEFINE BDS2011_UP} - {$DEFINE BDS2010_UP} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS19} // 10.2 Tokyo - {$DEFINE BDS} - {$DEFINE BDS19_UP} - {$DEFINE BDS18_UP} - {$DEFINE BDS17_UP} - {$DEFINE BDS16_UP} - {$DEFINE BDS15_UP} - {$DEFINE BDS14_UP} - {$DEFINE BDS12_UP} - {$DEFINE BDS11_UP} - {$DEFINE BDS10_UP} - {$DEFINE BDS9_UP} - {$DEFINE BDS8_UP} - {$DEFINE BDS7_UP} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} - - // NO BDS2014 defined, so need define below here. - {$DEFINE BDS2013_UP} - {$DEFINE BDS2012_UP} - {$DEFINE BDS2011_UP} - {$DEFINE BDS2010_UP} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS18} // 10.1 Berlin - {$DEFINE BDS} - {$DEFINE BDS18_UP} - {$DEFINE BDS17_UP} - {$DEFINE BDS16_UP} - {$DEFINE BDS15_UP} - {$DEFINE BDS14_UP} - {$DEFINE BDS12_UP} - {$DEFINE BDS11_UP} - {$DEFINE BDS10_UP} - {$DEFINE BDS9_UP} - {$DEFINE BDS8_UP} - {$DEFINE BDS7_UP} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} - - // NO BDS2014 defined, so need define below here. - {$DEFINE BDS2013_UP} - {$DEFINE BDS2012_UP} - {$DEFINE BDS2011_UP} - {$DEFINE BDS2010_UP} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS17} // 10 Seattle - {$DEFINE BDS} - {$DEFINE BDS17_UP} - {$DEFINE BDS16_UP} - {$DEFINE BDS15_UP} - {$DEFINE BDS14_UP} - {$DEFINE BDS12_UP} - {$DEFINE BDS11_UP} - {$DEFINE BDS10_UP} - {$DEFINE BDS9_UP} - {$DEFINE BDS8_UP} - {$DEFINE BDS7_UP} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} - - // NO BDS2014 defined, so need define below here. - {$DEFINE BDS2013_UP} - {$DEFINE BDS2012_UP} - {$DEFINE BDS2011_UP} - {$DEFINE BDS2010_UP} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS16} - {$DEFINE BDS} - {$DEFINE BDS16_UP} - {$DEFINE BDS15_UP} - {$DEFINE BDS14_UP} - {$DEFINE BDS12_UP} - {$DEFINE BDS11_UP} - {$DEFINE BDS10_UP} - {$DEFINE BDS9_UP} - {$DEFINE BDS8_UP} - {$DEFINE BDS7_UP} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} - - // NO BDS2014 defined, so need define below here. - {$DEFINE BDS2013_UP} - {$DEFINE BDS2012_UP} - {$DEFINE BDS2011_UP} - {$DEFINE BDS2010_UP} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS15} - {$DEFINE BDS} - {$DEFINE BDS15_UP} - {$DEFINE BDS14_UP} - {$DEFINE BDS12_UP} - {$DEFINE BDS11_UP} - {$DEFINE BDS10_UP} - {$DEFINE BDS9_UP} - {$DEFINE BDS8_UP} - {$DEFINE BDS7_UP} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} - - // NO BDS2014 defined, so need define below here. - {$DEFINE BDS2013_UP} - {$DEFINE BDS2012_UP} - {$DEFINE BDS2011_UP} - {$DEFINE BDS2010_UP} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS14} - {$DEFINE BDS} - {$DEFINE BDS14_UP} - {$DEFINE BDS12_UP} - {$DEFINE BDS11_UP} - {$DEFINE BDS10_UP} - {$DEFINE BDS9_UP} - {$DEFINE BDS8_UP} - {$DEFINE BDS7_UP} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} - - // NO BDS2014 defined, so need define below here. - {$DEFINE BDS2013_UP} - {$DEFINE BDS2012_UP} - {$DEFINE BDS2011_UP} - {$DEFINE BDS2010_UP} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS12} - {$DEFINE BDS} - {$DEFINE BDS12_UP} - {$DEFINE BDS11_UP} - {$DEFINE BDS10_UP} - {$DEFINE BDS9_UP} - {$DEFINE BDS8_UP} - {$DEFINE BDS7_UP} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} - - // NO BDS2014 defined, so need define below here. - {$DEFINE BDS2013_UP} - {$DEFINE BDS2012_UP} - {$DEFINE BDS2011_UP} - {$DEFINE BDS2010_UP} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS11} - {$DEFINE BDS} - {$DEFINE BDS11_UP} - {$DEFINE BDS10_UP} - {$DEFINE BDS9_UP} - {$DEFINE BDS8_UP} - {$DEFINE BDS7_UP} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} - - // NO BDS2014 defined, so need define below here. - {$DEFINE BDS2013_UP} - {$DEFINE BDS2012_UP} - {$DEFINE BDS2011_UP} - {$DEFINE BDS2010_UP} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS10} - {$DEFINE BDS} - {$DEFINE BDS10_UP} - {$DEFINE BDS9_UP} - {$DEFINE BDS8_UP} - {$DEFINE BDS7_UP} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} -{$ENDIF} - -{$IFDEF BDS2013} - {$DEFINE BDS2013_UP} - {$DEFINE BDS2012_UP} - {$DEFINE BDS2011_UP} - {$DEFINE BDS2010_UP} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS9} - {$DEFINE BDS} - {$DEFINE BDS9_UP} - {$DEFINE BDS8_UP} - {$DEFINE BDS7_UP} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} -{$ENDIF} - -{$IFDEF BDS2012} - {$DEFINE BDS2012_UP} - {$DEFINE BDS2011_UP} - {$DEFINE BDS2010_UP} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS8} - {$DEFINE BDS} - {$DEFINE BDS8_UP} - {$DEFINE BDS7_UP} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} -{$ENDIF} - -{$IFDEF BDS2011} - {$DEFINE BDS2011_UP} - {$DEFINE BDS2010_UP} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS7} - {$DEFINE BDS} - {$DEFINE BDS7_UP} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} -{$ENDIF} - -{$IFDEF BDS2010} - {$DEFINE BDS2010_UP} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS6} - {$DEFINE BDS} - {$DEFINE BDS6_UP} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} -{$ENDIF} - -{$IFDEF BDS2009} - {$DEFINE BDS2009_UP} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS5} - {$DEFINE BDS} - {$DEFINE BDS5_UP} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} -{$ENDIF} - -{$IFDEF BDS2007} - {$DEFINE BDS2007_UP} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS4} - {$DEFINE BDS} - {$DEFINE BDS4_UP} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} -{$ENDIF} - -{$IFDEF BDS2006} - {$DEFINE BDS2006_UP} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS3} - {$DEFINE BDS} - {$DEFINE BDS3_UP} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} -{$ENDIF} - -{$IFDEF BDS2005} - {$DEFINE BDS2005_UP} -{$ENDIF} - -{$IFDEF BDS2} - {$DEFINE BDS} - {$DEFINE BDS2_UP} - {$DEFINE BDS1_UP} -{$ENDIF} - -{$IFDEF BDS1} - {$DEFINE BDS} - {$DEFINE BDS1_UP} -{$ENDIF} - -// COMPILERX_UP from COMPILERX mappings - -{$IFDEF COMPILER29} // 12.0 ATHENS - {$DEFINE COMPILER29_UP} - {$DEFINE COMPILER28_UP} - {$DEFINE COMPILER27_UP} - {$DEFINE COMPILER26_UP} - {$DEFINE COMPILER25_UP} - {$DEFINE COMPILER24_UP} - {$DEFINE COMPILER23_UP} - {$DEFINE COMPILER22_UP} - {$DEFINE COMPILER21_UP} - {$DEFINE COMPILER20_UP} - {$DEFINE COMPILER19_UP} - {$DEFINE COMPILER18_UP} - {$DEFINE COMPILER17_UP} - {$DEFINE COMPILER16_UP} - {$DEFINE COMPILER15_UP} - {$DEFINE COMPILER14_UP} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER28} // 11.0 ALEXANDRIA - {$DEFINE COMPILER28_UP} - {$DEFINE COMPILER27_UP} - {$DEFINE COMPILER26_UP} - {$DEFINE COMPILER25_UP} - {$DEFINE COMPILER24_UP} - {$DEFINE COMPILER23_UP} - {$DEFINE COMPILER22_UP} - {$DEFINE COMPILER21_UP} - {$DEFINE COMPILER20_UP} - {$DEFINE COMPILER19_UP} - {$DEFINE COMPILER18_UP} - {$DEFINE COMPILER17_UP} - {$DEFINE COMPILER16_UP} - {$DEFINE COMPILER15_UP} - {$DEFINE COMPILER14_UP} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER27} // 10.4 SYDNEY - {$DEFINE COMPILER27_UP} - {$DEFINE COMPILER26_UP} - {$DEFINE COMPILER25_UP} - {$DEFINE COMPILER24_UP} - {$DEFINE COMPILER23_UP} - {$DEFINE COMPILER22_UP} - {$DEFINE COMPILER21_UP} - {$DEFINE COMPILER20_UP} - {$DEFINE COMPILER19_UP} - {$DEFINE COMPILER18_UP} - {$DEFINE COMPILER17_UP} - {$DEFINE COMPILER16_UP} - {$DEFINE COMPILER15_UP} - {$DEFINE COMPILER14_UP} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER26} // 10.3 RIO - {$DEFINE COMPILER26_UP} - {$DEFINE COMPILER25_UP} - {$DEFINE COMPILER24_UP} - {$DEFINE COMPILER23_UP} - {$DEFINE COMPILER22_UP} - {$DEFINE COMPILER21_UP} - {$DEFINE COMPILER20_UP} - {$DEFINE COMPILER19_UP} - {$DEFINE COMPILER18_UP} - {$DEFINE COMPILER17_UP} - {$DEFINE COMPILER16_UP} - {$DEFINE COMPILER15_UP} - {$DEFINE COMPILER14_UP} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER25} // 10.2 Tokyo - {$DEFINE COMPILER25_UP} - {$DEFINE COMPILER24_UP} - {$DEFINE COMPILER23_UP} - {$DEFINE COMPILER22_UP} - {$DEFINE COMPILER21_UP} - {$DEFINE COMPILER20_UP} - {$DEFINE COMPILER19_UP} - {$DEFINE COMPILER18_UP} - {$DEFINE COMPILER17_UP} - {$DEFINE COMPILER16_UP} - {$DEFINE COMPILER15_UP} - {$DEFINE COMPILER14_UP} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER24} // 10.1 Berlin - {$DEFINE COMPILER24_UP} - {$DEFINE COMPILER23_UP} - {$DEFINE COMPILER22_UP} - {$DEFINE COMPILER21_UP} - {$DEFINE COMPILER20_UP} - {$DEFINE COMPILER19_UP} - {$DEFINE COMPILER18_UP} - {$DEFINE COMPILER17_UP} - {$DEFINE COMPILER16_UP} - {$DEFINE COMPILER15_UP} - {$DEFINE COMPILER14_UP} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER23} // 10 Seattle - {$DEFINE COMPILER23_UP} - {$DEFINE COMPILER22_UP} - {$DEFINE COMPILER21_UP} - {$DEFINE COMPILER20_UP} - {$DEFINE COMPILER19_UP} - {$DEFINE COMPILER18_UP} - {$DEFINE COMPILER17_UP} - {$DEFINE COMPILER16_UP} - {$DEFINE COMPILER15_UP} - {$DEFINE COMPILER14_UP} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER22} - {$DEFINE COMPILER22_UP} - {$DEFINE COMPILER21_UP} - {$DEFINE COMPILER20_UP} - {$DEFINE COMPILER19_UP} - {$DEFINE COMPILER18_UP} - {$DEFINE COMPILER17_UP} - {$DEFINE COMPILER16_UP} - {$DEFINE COMPILER15_UP} - {$DEFINE COMPILER14_UP} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER21} - {$DEFINE COMPILER21_UP} - {$DEFINE COMPILER20_UP} - {$DEFINE COMPILER19_UP} - {$DEFINE COMPILER18_UP} - {$DEFINE COMPILER17_UP} - {$DEFINE COMPILER16_UP} - {$DEFINE COMPILER15_UP} - {$DEFINE COMPILER14_UP} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER20} - {$DEFINE COMPILER20_UP} - {$DEFINE COMPILER19_UP} - {$DEFINE COMPILER18_UP} - {$DEFINE COMPILER17_UP} - {$DEFINE COMPILER16_UP} - {$DEFINE COMPILER15_UP} - {$DEFINE COMPILER14_UP} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER19} - {$DEFINE COMPILER19_UP} - {$DEFINE COMPILER18_UP} - {$DEFINE COMPILER17_UP} - {$DEFINE COMPILER16_UP} - {$DEFINE COMPILER15_UP} - {$DEFINE COMPILER14_UP} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER18} - {$DEFINE COMPILER18_UP} - {$DEFINE COMPILER17_UP} - {$DEFINE COMPILER16_UP} - {$DEFINE COMPILER15_UP} - {$DEFINE COMPILER14_UP} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER17} - {$DEFINE COMPILER17_UP} - {$DEFINE COMPILER16_UP} - {$DEFINE COMPILER15_UP} - {$DEFINE COMPILER14_UP} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER16} - {$DEFINE COMPILER16_UP} - {$DEFINE COMPILER15_UP} - {$DEFINE COMPILER14_UP} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER15} - {$DEFINE COMPILER15_UP} - {$DEFINE COMPILER14_UP} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER14} - {$DEFINE COMPILER14_UP} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER12} - {$DEFINE COMPILER12_UP} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER11} - {$DEFINE COMPILER11_UP} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER10} - {$DEFINE COMPILER10_UP} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER9} - {$DEFINE COMPILER9_UP} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER8} - {$DEFINE COMPILER8_UP} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER7} - {$DEFINE COMPILER7_UP} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER6} - {$DEFINE COMPILER6_UP} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER5} - {$DEFINE COMPILER5_UP} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER4} - {$DEFINE COMPILER4_UP} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER35} - {$DEFINE COMPILER35_UP} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER3} - {$DEFINE COMPILER3_UP} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER2} - {$DEFINE COMPILER2_UP} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -{$IFDEF COMPILER1} - {$DEFINE COMPILER1_UP} -{$ENDIF} - -// VCLXX_UP from VCLXX mappings - -{$IFDEF UCL10} - {$DEFINE UCL10_UP} -{$ENDIF} - -{$IFDEF VCL71} - {$DEFINE VCL71_UP} - {$DEFINE VCL70_UP} - {$DEFINE VCL60_UP} - {$DEFINE VCL50_UP} - {$DEFINE VCL40_UP} - {$DEFINE VCL30_UP} - {$DEFINE VCL20_UP} - {$DEFINE VCL10_UP} -{$ENDIF} - -{$IFDEF VCL70} - {$DEFINE VCL70_UP} - {$DEFINE VCL60_UP} - {$DEFINE VCL50_UP} - {$DEFINE VCL40_UP} - {$DEFINE VCL30_UP} - {$DEFINE VCL20_UP} - {$DEFINE VCL10_UP} -{$ENDIF} - -{$IFDEF VCL60} - {$DEFINE VCL60_UP} - {$DEFINE VCL50_UP} - {$DEFINE VCL40_UP} - {$DEFINE VCL30_UP} - {$DEFINE VCL20_UP} - {$DEFINE VCL10_UP} -{$ENDIF} - -{$IFDEF VCL50} - {$DEFINE VCL50_UP} - {$DEFINE VCL40_UP} - {$DEFINE VCL30_UP} - {$DEFINE VCL20_UP} - {$DEFINE VCL10_UP} -{$ENDIF} - -{$IFDEF VCL40} - {$DEFINE VCL40_UP} - {$DEFINE VCL30_UP} - {$DEFINE VCL20_UP} - {$DEFINE VCL10_UP} -{$ENDIF} - -{$IFDEF VCL30} - {$DEFINE VCL30_UP} - {$DEFINE VCL20_UP} - {$DEFINE VCL10_UP} -{$ENDIF} - -{$IFDEF VCL20} - {$DEFINE VCL20_UP} - {$DEFINE VCL10_UP} -{$ENDIF} - -{$IFDEF VCL10} - {$DEFINE VCL10_UP} -{$ENDIF} - -// CLXXX_UP from CLXXX mappings - -{$IFDEF CLX10} - {$DEFINE CLX10_UP} -{$ENDIF} - -//============================================================================== -// ƽ̨ض -//============================================================================== - -{$IFDEF COMPILER1} - {$DEFINE WIN16} - {$DEFINE MSWINDOWS} -{$ENDIF} - -{$IFDEF BDS} - {$DEFINE DOTNET} -{$ENDIF} - -{$IFDEF WIN32} - {$DEFINE MSWINDOWS} -{$ENDIF} - -{$IFDEF LINUX} - {$DEFINE UNIX} - {$DEFINE COMPLIB_CLX} -{$ENDIF} - -{$IFNDEF COMPLIB_CLX} - {$DEFINE COMPLIB_VCL} -{$ENDIF} - -//============================================================================== -// ӳ汾ϢѺõָ -//============================================================================== - -{$IFDEF DELPHI} - {$DEFINE SUPPORT_PASCAL} -{$ENDIF} - -{$IFDEF BCB} - {$DEFINE SUPPORT_PASCAL} - {$DEFINE SUPPORT_CPLUSPLUS} -{$ENDIF} - -{$IFDEF DELPHI120_ATHENS_UP} - {$DEFINE LIST_INDEX_NATIVEINT} // Athens 12 TList use NativeInt for Index and Count instead of Integer - {$DEFINE IDE_HAS_TABMENU_COPY_PATH} // Athens 12 editor tab menu has item to copy path or filename - {$DEFINE IDE_HAS_DBCLICK_HIGHLIGHT} // Athens 12 editor double click selection highlight - {$DEFINE OTA_CODEEDITOR_SERVICE} // 11.3 ToolsAPI.Editor ӿڣʱ޷ 11.0/1/2 ֻ֣ܼӵ 12 -{$ENDIF} - -{$IFDEF DELPHI110_ALEXANDRIA_UP} - {$DEFINE NO_OLDCREATEORDER} // Alexandria 11 removed OldCreateOrder - {$DEFINE IDE_SUPPORT_HDPI} // Alexandria 11 supports HDPI using TVirtualImageList, etc. - {$DEFINE IDE_HAS_AUTO_READONLY} // Alexandria 11 supports auto open VCL source readonly - {$DEFINE IDE_HAS_MEMORY_VISUALIZAER} // Alexandria 11 has Memory Visualizer for Debug - {$DEFINE TSTRINGS_SETTEXTSTR_CANNULL} // Alexandria 11 TStrings.SetTextStr Ignore #0 Terminated Char - {$DEFINE MEMORYSTREAM_CAPACITY_NATIVEINT} // Alexandria 11 TMemoryStream Capacity is NativeInt instead of Longint -{$ENDIF} - -{$IFDEF DELPHI104_SYDNEY_UP} - {$DEFINE IDE_SUPPORT_LSP} // Sydney 10.4 ֧ LSP Է - {$DEFINE IDE_HAS_ERRORINSIGHT} // Sydney 10.4.2 ֱ֧༭ ErrorInsight - {$DEFINE IDE_EDITOR_CUSTOM_COLUMN} // Sydney 10.4 ϱ༭ Gutter ֧Զ壬ûӿڲݣԼ - {$DEFINE IDE_SWITCH_BUG} // Sydney 10.4.2 ڴļʱĪл̨ Bug -{$ENDIF} - -{$IFDEF DELPHI103_RIO_UP} - {$DEFINE SUPPORT_MACOS64} // Rio 10.3.2 ֧ 64 λ MacOS -{$ENDIF} - -{$IFDEF DELPHI102_TOKYO_UP} - {$DEFINE SUPPORT_LINUX64} // Tokyo 10.2 ֧ Linux 64 λ Server - {$DEFINE IDE_SUPPORT_THEMING} // Tokyo 10.2.2 ֧ IDE л -{$ENDIF} - -{$IFDEF DELPHI101_BERLIN_UP} - {$DEFINE IDE_NEW_EMBEDDED_DESIGNER} // 101B Re-opens "Embedded Designer" Option and Gives a New Container. -{$ENDIF} - -{$IFDEF DELPHI10_SEATTLE_UP} - {$DEFINE IDE_HAS_OWN_STRUCTUAL_HIGHLIGHT} // 10S has own Structual Highlight - {$DEFINE IDE_HAS_HIDE_NONVISUAL} // 10S has "Hide Nonvisual" Feature. -{$ENDIF} - -{$IFDEF DELPHIXE8_UP} - {$DEFINE INIFILE_READWRITE_INTEGER} // XE8 IniFile ReadInteger WriteInteger ʼ LongInt Ϊ Integer - {$DEFINE IDE_INTEGRATE_CASTALIA} // XE8/10S and above integrate Castalia. -{$ENDIF} - -{$IFDEF COMPILER21_UP} // COMPILER21 = XE7 - {$DEFINE NOT_SUPPORT_BDE} // BDE -{$ENDIF} - -{$IFDEF DELPHIXE7_UP} - {$DEFINE SUPPORT_TBYTES_OPERATION} // XE7 TBytes ʼ֧ӡȲ - {$DEFINE FMX_CONTROL_HAS_SIZE} // XE7 FMX Control Size -{$ENDIF} - -{$IFDEF DELPHIXE6_UP} - {$DEFINE SUPPORT_JSON} // XE6 System.JSON ⣬ DBX/REST -{$ENDIF} - -{$IFDEF DELPHIXE5_UP} - {$DEFINE SUPPORT_MOBILE} // XE5 ʼ֧ƶ - {$DEFINE IDE_HAS_INSIGHT} // XE5 has IDE Insight Bar -{$ENDIF} - -{$IFDEF DELPHIXE4_UP} - {$IFNDEF DISABLE_FMX} - {$DEFINE SUPPORT_FMX_FRAME} // XE4 FMX Supports FMX Frame - {$ENDIF} -{$ELSE} - {$DEFINE MEMO_CARETPOS_BUG} // Memo CaretPos Get Negative Error Value for Large File under XE3 or below -{$ENDIF} - -{$IFDEF DELPHIXE3_UP} - {$DEFINE SUPPORT_ATOMIC} // XE3 has Atomic Routines - {$DEFINE TCONTROL_HAS_STYLEELEMENTS} // XE3 TControl has StyleElements Property - {$DEFINE IDE_NP_FMX_DESIGN_BUG} // XE3 FMX Designer Cut/Copy/Paste cause AV Bug for -np switch -{$ENDIF} - -{$IFDEF DELPHIXE2_UP} - {$DEFINE SUPPORT_WIN64} // XE2 Supports Win64 - {$DEFINE SUPPORT_MACOS32} // XE2 Supports MacOS 32 - {$DEFINE SUPPORT_UNITNAME_DOT} - {$DEFINE SUPPORT_ENHANCED_INDEXEDPROPERTY} // XE2 New RTTI Supports IndexedProperty - {$DEFINE SUPPORT_ZLIB_WINDOWBITS} // XE2 ZLib Supports WindowBits - {$DEFINE SUPPORT_GDIPLUS} // XE2 Supports GDI+ - {$DEFINE SUPPORT_INT64ARRAY} // XE2 Defined Int64Array - {$DEFINE SUPPORT_ALPHACOLOR} // XE2 System.UITypes Has TAlphaColors -{$ENDIF} - -{$IFDEF DELPHIXE_UP} - {$DEFINE TSTRINGS_HAS_WRITEBOM} // XE TStrings has WriteBOM property. - {$DEFINE IDE_HAS_DEBUGGERVISUALIZER} // XE ToolsAPI has Debugger Visualizer Interfaces. - {$DEFINE IDE_HAS_STRINGS_VISUALIZAER} // XE has TStrings Visualizer for Debug -{$ENDIF} - -{$IFDEF BDS2012_UP} // 2012 = XE2 - {$DEFINE SUPPORT_32_AND_64} // XE2 Support Win32 and Win64 - {$IFNDEF DISABLE_FMX} - {$DEFINE SUPPORT_FMX} - {$ENDIF} - {$DEFINE SUPPORT_CROSS_PLATFORM} // XE2 ֿ֧ƽ̨ - {$DEFINE VERSIONINFO_PER_CONFIGURATION} // Every Configuruation can have a Version Info. - {$DEFINE OTA_ENVOPTIONS_PLATFORM_BUG} - // A Bug Can't get Correct Env Option Values for Current Platform. - {$DEFINE LIST_NEW_POINTER} -{$ENDIF} - -{$IFDEF BDS2010_UP} - {$DEFINE SUPPORT_INTERFACE_AS_OBJECT} - {$DEFINE SUPPORT_ENHANCED_RTTI} // New enhanced RTTI. - {$DEFINE SUPPORT_EXTERNAL_DELAYED} // External functions can be declared as 'delayed'. - {$DEFINE SUPPORT_CLASS_CONSTRUCTOR} // 2010 and above Supports class constructor and destructor - {$DEFINE SUPPORT_CLASS_DESTRUCTOR} - {$DEFINE IMAGELIST_BEGINENDUPDATE} // 2010 ʼImageList й BeginUpdate EndUpdate - {$DEFINE OTA_DEBUG_HAS_EVENTS} // 2010 µ DebuggerService ProcessDebugEvents - {$DEFINE IDE_HAS_NEW_COMPONENT_PALETTE} // IDE has a new style Component Palette. - {$DEFINE IDE_HAS_EDITOR_SEARCHPANEL} // Editor has a Search Panel - {$DEFINE IDE_HAS_DATETIME_HINT} // TDate/TTime/TDateTime shows Normally in Debug Hint -{$ENDIF} - -{$IFDEF BDS2010} - // 2010 EditView CursorPos EditPosition.InsertText ƫ - {$DEFINE EDITVIEW_SETCURSORPOS_BUG} -{$ENDIF} - -{$IFDEF BDS2009_UP} - {$DEFINE UNICODE_STRING} - {$DEFINE SUPPORT_ATTRIBUTE} // ֧ Attribute - {$DEFINE SUPPORT_GENERIC} // ַ֧ - {$DEFINE SUPPORT_ANSISTRING_CODEPAGE} // AnsiString ָ֧ҳ - {$DEFINE SUPPORT_ENCODING} // Unicode with TEncoding - {$DEFINE SUPPORT_PUINT64} // Has Pointer of UInt64 - {$DEFINE OBJECT_HAS_TOSTRING} // TObject.ToString Function - {$DEFINE OBJECT_HAS_EQUAL} // TObject.Equal Function - {$DEFINE OBJECT_HAS_GETHASHCODE} // TObject.GetHashCode Function - {$DEFINE TGRAPHIC_SUPPORT_PARTIALTRANSPARENCY} // TGraphic ֧ Alpha ͨ͸ - {$DEFINE SUPPORT_OTA_PROJECT_CONFIGURATION} - - {$DEFINE IDE_MAINFORM_EAT_MOUSEWHEEL} - // MainForm of 2009 or Above will eat Message in MouseWheelHandler - {$DEFINE IDE_CODEINSIGHT_AUTOINVOKE} - // IDE Code Insight has Auto Invoke Option - {$DEFINE EDITVIEW_CONVERTPOS_BUG} - // 2009 or Above IEditView.ConvertPos Incorrect when Meeting Unicode Chars. - - {$IFNDEF DELPHIXE2_UP} // 2009/2010/XE has a Project Version Number Bug. - {$DEFINE PROJECT_VERSION_NUMBER_BUG} - {$ENDIF} - {$DEFINE OTA_DPKOPTION_SETVALUE_CORRUPT_BUG} - // A OpenTools API Bug IOTAProjectOptions.SetOptionValue under 2009 or above: - // Set an Option Value to DPK Project Options maybe cause DPK Source Corrupt. -{$ELSE} - {$DEFINE ZLIB_STREAM_NOSIZE} // 2007 µ Zlib Ľѹ֧ Size -{$ENDIF} - -{$IFDEF BDS2009} - // 2009 CreateParams пܵѭ - {$DEFINE CREATE_PARAMS_BUG} - // 2009 EditView CursorPos EditPosition.InsertText ƫ - {$DEFINE EDITVIEW_SETCURSORPOS_BUG} -{$ENDIF} - -{$IFDEF BDS2007_UP} - {$DEFINE IDE_CONF_MANAGER} - {$DEFINE TBYTES_DEFINED} // 2007 Defined TBytes = array of Byte; - {$DEFINE PROJECT_FILENAME_DPROJ} // Project File is .dproj -{$ENDIF} - -{$IFDEF BDS2007} - // RAD Studio 2007 ¿ AutoComplete ᵼĺ˸ - {$DEFINE COMBOBOX_CHS_BUG} -{$ENDIF} - -{$IFDEF BDS2006_UP} - {$DEFINE SUPPORT_CLASS_VAR} // 2006 and above Supports class var - {$DEFINE TCONTROL_HAS_MARGINS} // 2006 and above TControl has Margins - {$DEFINE TCONTROL_HAS_EXPLICIT_BOUNDS} // 2006 and above TControl has Explicit Bounds - {$DEFINE TCONTROL_HAS_MOUSEENTERLEAVE} // 2006 and above TControl has Mouse Enter/Leave Events - {$DEFINE OTA_CODE_TEMPLATE_API} // 2006 and above Provides CodeTemplateAPI. - {$DEFINE OTA_DEBUG_HAS_ERBUSY} // 2006 µ Evaluate зֵ erBusy - {$DEFINE IDE_HAS_GUIDE_LINE} // 2006 and above has Designer Guide Line - {$DEFINE IDE_SYNC_EDIT_BLOCK} // 2006 and above Editor Supports Sync Block Edit - {$DEFINE EDITOR_TAB_ONLYFROM_WINCONTROL} - // From BDS 2006 IDEGraident Editor Tab is Only From WinControl, not TabSet/TabControl -{$ENDIF} - -{$IFDEF BDS2005_UP} - {$DEFINE OTA_PALETTE_API} // 2005 and above Provides PaletteAPI. - {$DEFINE IDE_EDITOR_ELIDE} // 2005 ϱ༭֧۵ - {$DEFINE IDE_FILE_HISTORY} // 2005 ϰ汾洢ļʷ汾 -{$ENDIF} - -{$IFDEF BDS2006} - {$DEFINE PROJECT_FILENAME_BDSPROJ} // Project File is .bdsproj -{$ENDIF} - -{$IFDEF BDS2005} - {$DEFINE PROJECT_FILENAME_BDSPROJ} // Project File is .bdsproj -{$ENDIF} - -{$IFDEF BDS} // 2005 - {$DEFINE SUPPORT_PASCAL} - {$DEFINE SUPPORT_CSHARP} - {$DEFINE SUPPORT_INLINE} - {$DEFINE SUPPORT_UINT64} - {$DEFINE IDE_WIDECONTROL} // 2005 ϵı༭ڲǿַ UTF-8Ƿ Unicode - {$DEFINE IDE_EDITOR_SUPPORT_FOLDING} // 2005 ϵı༭֧۵ - {$DEFINE OTA_NEW_BREAKPOINT_NOBUG} // 2005 ϵ NewBreakpoint ܹ - {$DEFINE IDE_ACTION_UPDATE_DELAY} // IDE's Action Menu Update will Delay in 2005 or Up. - {$DEFINE SUPPORT_WIDECHAR_IDENTIFIER} - - {$IFNDEF COMPILER12_UP} - // 2005~2007 Compiler is Ansi but Editor String is UTF-8 - {$DEFINE IDE_STRING_ANSI_UTF8} - {$ENDIF} -{$ENDIF} - -{$IFDEF DELPHI7_UP} - {$DEFINE SUPPORT_FORMAT_SETTINGS} // Delphi 7 ʼ֧ FormatSettings - {$DEFINE IDE_MENUBAR_VERTICAL_POSITION_BUG} - // Delphi 7 ϵ MenuBar ֱϵĵλü׳Ͻ - {$DEFINE IDE_MENUBAR_VERTICAL_NOSCROLL_BUG} - // Delphi 7 ϵ MenuBar ֱʱ -{$ENDIF} - -{$IFDEF COMPILER6_UP} - {$DEFINE SUPPORT_DEPRECATED} -{$ENDIF} - -{$IFDEF COMPILER6_UP} - {$DEFINE SUPPORT_ENUMVALUES} - {$DEFINE SUPPORT_VARIANTS} - {$DEFINE SUPPORT_IFDIRECTIVE} -{$ENDIF} - -{$IFDEF DELPHI5_UP} - {$IFNDEF BDS2005_UP} - {$DEFINE PROJECT_FILENAME_DPR} // Delphi 5/6/7 Project File is .dpr - {$ENDIF} -{$ENDIF} - -{$IFDEF COMPILER5} - {$DEFINE TSTREAM_LONGINT} // D6 ϵ TStream Int64 -{$ENDIF} - -{$IFDEF BCB5} - {$DEFINE BCB5OR6} // һ BCB5OR6 Է BCB5 BCB6 ʹ -{$ENDIF} - -{$IFDEF BCB6} - {$DEFINE BCB5OR6} -{$ENDIF} - -{$IFDEF BCB5OR6} - {$DEFINE NO_ZLIB} -{$ENDIF} - -{$IFDEF DELPHI5} - {$DEFINE DELPHI5OR6} // һ DELPHI5OR6 Է DELPHI5 DELPHI6 ʹ -{$ENDIF} - -{$IFDEF DELPHI6} - {$DEFINE DELPHI5OR6} -{$ENDIF} - -{$IFDEF COMPILER4_UP} - {$DEFINE SUPPORT_INT64} - {$DEFINE SUPPORT_DYNAMICARRAYS} - {$DEFINE SUPPORT_DEFAULTPARAMS} - {$DEFINE SUPPORT_REINTRODUCE} - {$DEFINE SUPPORT_OVERLOAD} -{$ENDIF} - -{$IFDEF COMPILER35_UP} - {$DEFINE SUPPORT_EXTSYM} - {$DEFINE SUPPORT_NODEFINE} -{$ENDIF} - -{$IFDEF COMPILER3_UP} - {$DEFINE SUPPORT_WIDESTRING} - {$DEFINE SUPPORT_INTERFACE} -{$ENDIF} - -{$IFDEF WIN64} - {$DEFINE EXTENDED_SIZE_8} // Win64 Extended ͳ 8 ֽ -{$ENDIF} - -{$IFDEF CPUARM} - {$DEFINE EXTENDED_SIZE_8} // ARM ƽ̨ Extended ͳ 8 ֽ -{$ENDIF} - -{$IFDEF WIN32} - {$DEFINE EXTENDED_SIZE_10} // Win32 Extended ͳ 10 ֽ -{$ENDIF} - -{$IFDEF MACOS64} - {$DEFINE EXTENDED_SIZE_16} // MacOS64 Extended ͳ 16 ֽ -{$ENDIF} - -{$IFDEF LINUX64} - {$DEFINE EXTENDED_SIZE_16} // Linux64 Extended ͳ 16 ֽ -{$ENDIF} - -//============================================================================== -// PascalScript ĵ -//============================================================================== - -{.$DEFINE ALLDEBUG} // òƲҪȽ - -//============================================================================== -// ֶ -//============================================================================== - -{$DEFINE GB2312} -{.$DEFINE BIG5} -{.$DEFINE ENGLISH} - -//============================================================================== -// ıָ -//============================================================================== - -{$A+ Force alignment on word/dword boundaries} -{$S+ stack checking} - -{$B- Short evaluation of boolean values} -{$H+ Long string support} -{$V- No var string checking} -{$X+ Extended syntax} -{$P+ Open string parameters} -{$J+ Writeable typed constants} -{$R- No Range checking} -{$OVERFLOWCHECKS OFF} - -{$IFDEF COMPILER6_UP} - {$WARN SYMBOL_PLATFORM OFF} - {$WARN UNIT_PLATFORM OFF} - {$WARN SYMBOL_DEPRECATED OFF} - {$WARN UNIT_DEPRECATED OFF} -{$ENDIF} - -{$IFDEF COMPILER7_UP} - {$WARN UNSAFE_CAST OFF} - {$WARN UNSAFE_CODE OFF} - {$WARN UNSAFE_TYPE OFF} -{$ENDIF} - -{$IFDEF BCB} - {$OBJEXPORTALL ON} -{$ENDIF} - -{$DEFINE CN_USE_MSXML} - -{$ENDIF FPC} - +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2025 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +{******************************************************************************} +{ } +{ עõԪΪָͱ汾Ϣļ } +{ õԪݲֲο JCL GExperts } +{ } +{******************************************************************************} + +//============================================================================== +// ѡ +//============================================================================== + +{$IFDEF FPC} + // Free Pascal Compiler 3.x Up Definitions + {$DEFINE SUPPORT_PASCAL} // Pascal + {$DEFINE SUPPORT_UINT64} // UInt64 + {$DEFINE SUPPORT_32_AND_64} // ֧ 32 64 λ NativeInt + {$DEFINE SUPPORT_ENCODING} // Unicode ַ֧ Encoding ת + {$DEFINE SUPPORT_INLINE} // ֧ inline + + {$DEFINE OBJECT_HAS_TOSTRING} // TObject.ToString + {$DEFINE TBYTES_DEFINED} + + // CPU FPC ӳ䵽 Delphi + {$IFDEF CPU386} // Intel 32 CPU + {$DEFINE CPU32BITS} + {$DEFINE CPUX86} + {$asmMode intel} + {$ENDIF} + {$IFDEF CPUi386} + {$DEFINE CPU32BITS} + {$DEFINE CPUX86} + {$asmMode intel} + {$ENDIF} + + {$IFDEF CPUAMD64} // Intel 64 CPU + {$DEFINE CPU64BITS} + {$DEFINE CPUX64} + {$asmMode intel} + {$ENDIF} + {$IFDEF CPUX86_64} + {$DEFINE CPU64BITS} + {$DEFINE CPUX64} + {$asmMode intel} + {$ENDIF} + {$IFDEF CPUIA64} + {$DEFINE CPU64BITS} + {$DEFINE CPUX64} + {$asmMode intel} + {$ENDIF} + + {$IFDEF CPUARM} // ARM 32 bit processor + {$DEFINE CPU32BITS} + {$DEFINE CPUARM} + {$DEFINE CPUARM32} + {$ENDIF} + + {$IFDEF CPUAARCH64} // ARM 64 bit processor + {$DEFINE CPU64BITS} + {$DEFINE CPUARM} + {$DEFINE CPUARM64} + {$ENDIF} + + {$mode Delphi} // Delphi Compatibility, not DelphiUnicodeעԴظ + + // ر Range Check Overflow Check + {$R- No Range checking} + {$OVERFLOWCHECKS OFF} + +{$ELSE FPC} // Below is for Delphi Compiler + +//{$DEFINE PERSONAL_EDITION} +{$DEFINE ENTERPRISE_EDITION} + +{$IFNDEF PERSONAL_EDITION} + {$DEFINE SUPPORT_DB} + {$DEFINE SUPPORT_ADO} +{$ENDIF} + +//============================================================================== +// 汾Ϣ +//============================================================================== + +{$IFDEF VER360} + {$DEFINE COMPILER29} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI29} + {$DEFINE DELPHI120_ATHENS} + {$DEFINE BCB28} + {$DEFINE BCB120_ATHENS} + {$DEFINE BDS23} +{$ENDIF} + +{$IFDEF VER350} + {$DEFINE COMPILER28} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI28} + {$DEFINE DELPHI110_ALEXANDRIA} + {$DEFINE BCB28} + {$DEFINE BCB110_ALEXANDRIA} + {$DEFINE BDS22} +{$ENDIF} + +{$IFDEF VER340} + {$DEFINE COMPILER27} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI27} + {$DEFINE DELPHI104_SYDNEY} + {$DEFINE BCB27} + {$DEFINE BCB104_SYDNEY} + {$DEFINE BDS21} +{$ENDIF} + +{$IFDEF VER330} + {$DEFINE COMPILER26} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI26} + {$DEFINE DELPHI103_RIO} + {$DEFINE BCB26} + {$DEFINE BCB103_RIO} + {$DEFINE BDS20} +{$ENDIF} + +{$IFDEF VER320} + {$DEFINE COMPILER25} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI25} + {$DEFINE DELPHI102_TOKYO} + {$DEFINE BCB25} + {$DEFINE BCB102_TOKYO} + {$DEFINE BDS19} +{$ENDIF} + +{$IFDEF VER310} + {$DEFINE COMPILER24} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI24} + {$DEFINE DELPHI101_BERLIN} + {$DEFINE BCB24} + {$DEFINE BCB101_BERLIN} + {$DEFINE BDS18} +{$ENDIF} + +{$IFDEF VER300} + {$DEFINE COMPILER23} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI23} + {$DEFINE DELPHI10_SEATTLE} + {$DEFINE BCB23} + {$DEFINE BCB10_SEATTLE} + {$DEFINE BDS17} +{$ENDIF} + +{$IFDEF VER290} + {$DEFINE COMPILER22} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI22} + {$DEFINE DELPHIXE8} + {$DEFINE BCB22} + {$DEFINE BCBXE8} + {$DEFINE BDS16} +{$ENDIF} + +{$IFDEF VER280} + {$DEFINE COMPILER21} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI21} + {$DEFINE DELPHIXE7} + {$DEFINE BCB21} + {$DEFINE BCBXE7} + {$DEFINE BDS15} +{$ENDIF} + +{$IFDEF VER270} + {$DEFINE COMPILER20} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI20} + {$DEFINE DELPHIXE6} + {$DEFINE BCB20} + {$DEFINE BCBXE6} + {$DEFINE BDS14} +{$ENDIF} + +{$IFDEF VER260} + {$DEFINE COMPILER19} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI19} + {$DEFINE DELPHIXE5} + {$DEFINE BCB19} + {$DEFINE BCBXE5} + {$DEFINE BDS12} +{$ENDIF} + +{$IFDEF VER250} + {$DEFINE COMPILER18} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI18} + {$DEFINE DELPHIXE4} + {$DEFINE BCB18} + {$DEFINE BCBXE4} + {$DEFINE BDS11} +{$ENDIF} + +{$IFDEF VER240} + {$DEFINE COMPILER17} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI17} + {$DEFINE DELPHIXE3} + {$DEFINE DELPHI2013} + {$DEFINE BCB17} + {$DEFINE BCBXE3} + {$DEFINE BCB2013} + {$DEFINE BDS10} + {$DEFINE BDS2013} +{$ENDIF} + +{$IFDEF VER230} + {$DEFINE COMPILER16} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI16} + {$DEFINE DELPHIXE2} + {$DEFINE DELPHI2012} + {$DEFINE BCB16} + {$DEFINE BCBXE2} + {$DEFINE BCB2012} + {$DEFINE BDS9} + {$DEFINE BDS2012} +{$ENDIF} + +{$IFDEF VER220} + {$DEFINE COMPILER15} + {$IFDEF LINUX} + {$DEFINE UCL10} + {$ELSE} + {$DEFINE VCL71} + {$ENDIF} + {$DEFINE DELPHI15} + {$DEFINE DELPHIXE} + {$DEFINE DELPHI2011} + {$DEFINE BCB15} + {$DEFINE BCBXE} + {$DEFINE BCB2011} + {$DEFINE BDS8} + {$DEFINE BDS2011} +{$ENDIF} + +{$IFDEF VER210} + {$DEFINE COMPILER14} + {$DEFINE VCL71} + {$DEFINE DELPHI14} + {$DEFINE DELPHI2010} + {$DEFINE BCB14} + {$DEFINE BCB2010} + {$DEFINE BDS7} + {$DEFINE BDS2010} +{$ENDIF} + +{$IFDEF VER200} + {$DEFINE COMPILER12} + {$DEFINE VCL71} + {$DEFINE DELPHI12} + {$DEFINE DELPHI2009} + {$DEFINE BCB12} + {$DEFINE BCB2009} + {$DEFINE BDS6} + {$DEFINE BDS2009} +{$ENDIF} + +{$IFDEF VER185} + {$DEFINE COMPILER11} + {$DEFINE VCL71} + {$DEFINE DELPHI11} + {$DEFINE DELPHI2007} + {$DEFINE BCB11} + {$DEFINE BCB2007} + {$DEFINE BDS5} + {$DEFINE BDS2007} + {$UNDEF VER180} +{$ENDIF} + +{$IFDEF VER180} + {$DEFINE COMPILER10} + {$DEFINE VCL71} + {$DEFINE DELPHI10} + {$DEFINE DELPHI2006} + {$DEFINE BCB10} + {$DEFINE BCB2006} + {$DEFINE BDS4} + {$DEFINE BDS2006} +{$ENDIF} + +{$IFDEF VER170} + {$DEFINE COMPILER9} + {$DEFINE VCL71} + {$DEFINE DELPHI9} + {$DEFINE DELPHI2005} + {$DEFINE BDS3} + {$DEFINE BDS2005} +{$ENDIF} + +{$IFDEF VER160} + {$DEFINE COMPILER8} + {$DEFINE VCL71} + {$DEFINE DELPHI8} + {$DEFINE BDS2} +{$ENDIF} + +{$IFDEF VER150} + {$DEFINE COMPILER7} + {$IFDEF LINUX} + {$DEFINE CLX10} + {$ELSE} + {$DEFINE VCL70} + {$DEFINE CLX10} + {$IFDEF BCB} + {$DEFINE BCB7} + {$ELSE} + {$DEFINE DELPHI7} + {$ENDIF} + {$ENDIF} +{$ENDIF} + +{$IFDEF VER140} + {$DEFINE COMPILER6} + {$IFDEF LINUX} + {$DEFINE CLX10} + {$IFDEF CONDITIONALEXPRESSIONS} + {$IFDEF CompilerVersion} + {$IF System.RTLVersion = 14.1} + {$DEFINE KYLIX2} + {$IFEND} + {$IF System.RTLVersion = 14.5} + {$DEFINE KYLIX3} + {$IFEND} + {$ELSE} + {$DEFINE KYLIX1} + {$ENDIF} + {$ENDIF} + {$ELSE} + {$DEFINE VCL60} + {$DEFINE CLX10} + {$IFDEF BCB} + {$DEFINE BCB6} + {$ELSE} + {$DEFINE DELPHI6} + {$ENDIF} + {$ENDIF} +{$ENDIF} + +{$IFDEF VER130} + {$DEFINE COMPILER5} + {$DEFINE VCL50} + {$IFDEF BCB} + {$DEFINE BCB5} + {$ELSE} + {$DEFINE DELPHI5} + {$ENDIF} +{$ENDIF} + +{$IFDEF VER125} + {$DEFINE COMPILER4} + {$DEFINE VCL40} + {$DEFINE BCB4} +{$ENDIF} + +{$IFDEF VER120} + {$DEFINE COMPILER4} + {$DEFINE VCL40} + {$DEFINE DELPHI4} +{$ENDIF} + +{$IFDEF VER110} + {$DEFINE COMPILER35} + {$DEFINE VCL30} + {$DEFINE BCB3} +{$ENDIF} + +{$IFDEF VER100} + {$DEFINE COMPILER3} + {$DEFINE VCL30} + {$DEFINE DELPHI3} +{$ENDIF} + +{$IFDEF VER93} + {$DEFINE COMPILER2} + {$DEFINE VCL20} + {$DEFINE BCB1} +{$ENDIF} + +{$IFDEF VER90} + {$DEFINE COMPILER2} + {$DEFINE VCL20} + {$DEFINE DELPHI2} +{$ENDIF} + +{$IFDEF VER80} + {$DEFINE COMPILER1} + {$DEFINE VCL10} + {$DEFINE DELPHI1} +{$ENDIF} + +// DELPHIX_UP from DELPHIX mappings + +{$IFDEF DELPHI29} + {$DEFINE DELPHI} + {$DEFINE DELPHI29_UP} + {$DEFINE DELPHI28_UP} + {$DEFINE DELPHI27_UP} + {$DEFINE DELPHI26_UP} + {$DEFINE DELPHI25_UP} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI120_ATHENS} + {$DEFINE DELPHI120_ATHENS_UP} + {$DEFINE DELPHI110_ALEXANDRIA_UP} + {$DEFINE DELPHI104_SYDNEY_UP} + {$DEFINE DELPHI103_RIO_UP} + {$DEFINE DELPHI102_TOKYO_UP} + {$DEFINE DELPHI101_BERLIN_UP} + {$DEFINE DELPHI10_SEATTLE_UP} + {$DEFINE DELPHIXE8_UP} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI28} + {$DEFINE DELPHI} + {$DEFINE DELPHI28_UP} + {$DEFINE DELPHI27_UP} + {$DEFINE DELPHI26_UP} + {$DEFINE DELPHI25_UP} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI110_ALEXANDRIA} + {$DEFINE DELPHI110_ALEXANDRIA_UP} + {$DEFINE DELPHI104_SYDNEY_UP} + {$DEFINE DELPHI103_RIO_UP} + {$DEFINE DELPHI102_TOKYO_UP} + {$DEFINE DELPHI101_BERLIN_UP} + {$DEFINE DELPHI10_SEATTLE_UP} + {$DEFINE DELPHIXE8_UP} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI27} + {$DEFINE DELPHI} + {$DEFINE DELPHI27_UP} + {$DEFINE DELPHI26_UP} + {$DEFINE DELPHI25_UP} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI104_SYDNEY} + {$DEFINE DELPHI104_SYDNEY_UP} + {$DEFINE DELPHI103_RIO_UP} + {$DEFINE DELPHI102_TOKYO_UP} + {$DEFINE DELPHI101_BERLIN_UP} + {$DEFINE DELPHI10_SEATTLE_UP} + {$DEFINE DELPHIXE8_UP} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI26} + {$DEFINE DELPHI} + {$DEFINE DELPHI26_UP} + {$DEFINE DELPHI25_UP} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI103_RIO} + {$DEFINE DELPHI103_RIO_UP} + {$DEFINE DELPHI102_TOKYO_UP} + {$DEFINE DELPHI101_BERLIN_UP} + {$DEFINE DELPHI10_SEATTLE_UP} + {$DEFINE DELPHIXE8_UP} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI25} + {$DEFINE DELPHI} + {$DEFINE DELPHI25_UP} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI102_TOKYO} + {$DEFINE DELPHI102_TOKYO_UP} + {$DEFINE DELPHI101_BERLIN_UP} + {$DEFINE DELPHI10_SEATTLE_UP} + {$DEFINE DELPHIXE8_UP} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI24} + {$DEFINE DELPHI} + {$DEFINE DELPHI24_UP} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI101_BERLIN} + {$DEFINE DELPHI101_BERLIN_UP} + {$DEFINE DELPHI10_SEATTLE_UP} + {$DEFINE DELPHIXE8_UP} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI23} + {$DEFINE DELPHI} + {$DEFINE DELPHI23_UP} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI10_SEATTLE} + {$DEFINE DELPHI10_SEATTLE_UP} + {$DEFINE DELPHIXE8_UP} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI22} + {$DEFINE DELPHI} + {$DEFINE DELPHI22_UP} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHIXE8} + {$DEFINE DELPHIXE8_UP} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI21} + {$DEFINE DELPHI} + {$DEFINE DELPHI21_UP} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHIXE7} + {$DEFINE DELPHIXE7_UP} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI20} + {$DEFINE DELPHI} + {$DEFINE DELPHI20_UP} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHIXE6} + {$DEFINE DELPHIXE6_UP} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI19} + {$DEFINE DELPHI} + {$DEFINE DELPHI19_UP} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHIXE5} + {$DEFINE DELPHIXE5_UP} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI18} + {$DEFINE DELPHI} + {$DEFINE DELPHI18_UP} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHIXE4} + {$DEFINE DELPHIXE4_UP} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} + + // NO DELPHI2014 defined, so need define below here. + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI17} + {$DEFINE DELPHI} + {$DEFINE DELPHI17_UP} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHIXE3} + {$DEFINE DELPHIXE3_UP} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} +{$ENDIF} + +{$IFDEF DELPHI2013} + {$DEFINE DELPHI2013_UP} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI16} + {$DEFINE DELPHI} + {$DEFINE DELPHI16_UP} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHIXE2} + {$DEFINE DELPHIXE2_UP} + {$DEFINE DELPHIXE_UP} +{$ENDIF} + +{$IFDEF DELPHI2012} + {$DEFINE DELPHI2012_UP} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI15} + {$DEFINE DELPHI} + {$DEFINE DELPHI15_UP} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHIXE} + {$DEFINE DELPHIXE_UP} +{$ENDIF} + +{$IFDEF DELPHI2011} + {$DEFINE DELPHI2011_UP} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI14} + {$DEFINE DELPHI} + {$DEFINE DELPHI14_UP} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI2010} + {$DEFINE DELPHI2010_UP} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI12} + {$DEFINE DELPHI} + {$DEFINE DELPHI12_UP} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI2009} + {$DEFINE DELPHI2009_UP} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI11} + {$DEFINE DELPHI} + {$DEFINE DELPHI11_UP} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI2007} + {$DEFINE DELPHI2007_UP} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI10} + {$DEFINE DELPHI} + {$DEFINE DELPHI10_UP} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI2006} + {$DEFINE DELPHI2006_UP} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI9} + {$DEFINE DELPHI} + {$DEFINE DELPHI9_UP} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI2005} + {$DEFINE DELPHI2005_UP} +{$ENDIF} + +{$IFDEF DELPHI8} + {$DEFINE DELPHI} + {$DEFINE DELPHI8_UP} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI7} + {$DEFINE DELPHI} + {$DEFINE DELPHI7_UP} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI6} + {$DEFINE DELPHI} + {$DEFINE DELPHI6_UP} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI5} + {$DEFINE DELPHI} + {$DEFINE DELPHI5_UP} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI4} + {$DEFINE DELPHI} + {$DEFINE DELPHI4_UP} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI3} + {$DEFINE DELPHI} + {$DEFINE DELPHI3_UP} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI2} + {$DEFINE DELPHI} + {$DEFINE DELPHI2_UP} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +{$IFDEF DELPHI1} + {$DEFINE DELPHI} + {$DEFINE DELPHI1_UP} +{$ENDIF} + +// BCBX_UP from BCBX mappings + +{$IFDEF BCB29} + {$DEFINE BCB} + {$DEFINE BCB29_UP} + {$DEFINE BCB28_UP} + {$DEFINE BCB27_UP} + {$DEFINE BCB26_UP} + {$DEFINE BCB25_UP} + {$DEFINE BCB24_UP} + {$DEFINE BCB23_UP} + {$DEFINE BCB22_UP} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB120_ATHENS} + {$DEFINE BCB120_ATHENS_UP} + {$DEFINE BCB110_ALEXANDRIA_UP} + {$DEFINE BCB104_SYDNEY_UP} + {$DEFINE BCB103_RIO_UP} + {$DEFINE BCB102_TOKYO_UP} + {$DEFINE BCB101_BERLIN_UP} + {$DEFINE BCB10_SEATTLE_UP} + {$DEFINE BCBXE8_UP} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB28} + {$DEFINE BCB} + {$DEFINE BCB28_UP} + {$DEFINE BCB27_UP} + {$DEFINE BCB26_UP} + {$DEFINE BCB25_UP} + {$DEFINE BCB24_UP} + {$DEFINE BCB23_UP} + {$DEFINE BCB22_UP} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB110_ALEXANDRIA} + {$DEFINE BCB110_ALEXANDRIA_UP} + {$DEFINE BCB104_SYDNEY_UP} + {$DEFINE BCB103_RIO_UP} + {$DEFINE BCB102_TOKYO_UP} + {$DEFINE BCB101_BERLIN_UP} + {$DEFINE BCB10_SEATTLE_UP} + {$DEFINE BCBXE8_UP} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB27} + {$DEFINE BCB} + {$DEFINE BCB27_UP} + {$DEFINE BCB26_UP} + {$DEFINE BCB25_UP} + {$DEFINE BCB24_UP} + {$DEFINE BCB23_UP} + {$DEFINE BCB22_UP} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB104_SYDNEY} + {$DEFINE BCB104_SYDNEY_UP} + {$DEFINE BCB103_RIO_UP} + {$DEFINE BCB102_TOKYO_UP} + {$DEFINE BCB101_BERLIN_UP} + {$DEFINE BCB10_SEATTLE_UP} + {$DEFINE BCBXE8_UP} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB26} + {$DEFINE BCB} + {$DEFINE BCB26_UP} + {$DEFINE BCB25_UP} + {$DEFINE BCB24_UP} + {$DEFINE BCB23_UP} + {$DEFINE BCB22_UP} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB103_RIO} + {$DEFINE BCB103_RIO_UP} + {$DEFINE BCB102_TOKYO_UP} + {$DEFINE BCB101_BERLIN_UP} + {$DEFINE BCB10_SEATTLE_UP} + {$DEFINE BCBXE8_UP} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB25} + {$DEFINE BCB} + {$DEFINE BCB25_UP} + {$DEFINE BCB24_UP} + {$DEFINE BCB23_UP} + {$DEFINE BCB22_UP} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB102_TOKYO} + {$DEFINE BCB102_TOKYO_UP} + {$DEFINE BCB101_BERLIN_UP} + {$DEFINE BCB10_SEATTLE_UP} + {$DEFINE BCBXE8_UP} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + + +{$IFDEF BCB24} + {$DEFINE BCB} + {$DEFINE BCB24_UP} + {$DEFINE BCB23_UP} + {$DEFINE BCB22_UP} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB101_BERLIN} + {$DEFINE BCB101_BERLIN_UP} + {$DEFINE BCB10_SEATTLE_UP} + {$DEFINE BCBXE8_UP} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB23} + {$DEFINE BCB} + {$DEFINE BCB23_UP} + {$DEFINE BCB22_UP} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB10_SEATTLE} + {$DEFINE BCB10_SEATTLE_UP} + {$DEFINE BCBXE8_UP} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB22} + {$DEFINE BCB} + {$DEFINE BCB22_UP} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCBXE8} + {$DEFINE BCBXE8_UP} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB21} + {$DEFINE BCB} + {$DEFINE BCB21_UP} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCBXE7} + {$DEFINE BCBXE7_UP} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB20} + {$DEFINE BCB} + {$DEFINE BCB20_UP} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCBXE6} + {$DEFINE BCBXE6_UP} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB19} + {$DEFINE BCB} + {$DEFINE BCB19_UP} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCBXE5} + {$DEFINE BCBXE5_UP} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB18} + {$DEFINE BCB} + {$DEFINE BCB18_UP} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCBXE4} + {$DEFINE BCBXE4_UP} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} + + // NO BCB2014 defined, so need define below here. + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB17} + {$DEFINE BCB} + {$DEFINE BCB17_UP} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCBXE3} + {$DEFINE BCBXE3_UP} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} +{$ENDIF} + +{$IFDEF BCB2013} + {$DEFINE BCB2013_UP} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB16} + {$DEFINE BCB} + {$DEFINE BCB16_UP} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCBXE2} + {$DEFINE BCBXE2_UP} + {$DEFINE BCBXE_UP} +{$ENDIF} + +{$IFDEF BCB2012} + {$DEFINE BCB2012_UP} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB15} + {$DEFINE BCB} + {$DEFINE BCB15_UP} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCBXE} + {$DEFINE BCBXE_UP} +{$ENDIF} + +{$IFDEF BCB2011} + {$DEFINE BCB2011_UP} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB14} + {$DEFINE BCB} + {$DEFINE BCB14_UP} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB2010} + {$DEFINE BCB2010_UP} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB12} + {$DEFINE BCB} + {$DEFINE BCB12_UP} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB2009} + {$DEFINE BCB2009_UP} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB11} + {$DEFINE BCB} + {$DEFINE BCB11_UP} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB2007} + {$DEFINE BCB2007_UP} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB10} + {$DEFINE BCB} + {$DEFINE BCB10_UP} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB2006} + {$DEFINE BCB2006_UP} +{$ENDIF} + +{$IFDEF BCB7} + {$DEFINE BCB} + {$DEFINE BCB7_UP} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB6} + {$DEFINE BCB} + {$DEFINE BCB6_UP} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB5} + {$DEFINE BCB} + {$DEFINE BCB5_UP} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB4} + {$DEFINE BCB} + {$DEFINE BCB4_UP} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB3} + {$DEFINE BCB} + {$DEFINE BCB3_UP} + {$DEFINE BCB1_UP} +{$ENDIF} + +{$IFDEF BCB1} + {$DEFINE BCB} + {$DEFINE BCB1_UP} +{$ENDIF} + +// KYLIXX_UP from KYLIXX mappings + +{$IFDEF KYLIX3} + {$DEFINE KYLIX} + {$DEFINE KYLIX3_UP} + {$DEFINE KYLIX2_UP} + {$DEFINE KYLIX1_UP} +{$ENDIF} + +{$IFDEF KYLIX2} + {$DEFINE KYLIX} + {$DEFINE KYLIX2_UP} + {$DEFINE KYLIX1_UP} +{$ENDIF} + +{$IFDEF KYLIX1} + {$DEFINE KYLIX} + {$DEFINE KYLIX1_UP} +{$ENDIF} + +// BDSXX_UP from BDSXX mappings + +{$IFDEF BDS23} // 12.0 ATHENS + {$DEFINE BDS} + {$DEFINE BDS23_UP} + {$DEFINE BDS22_UP} + {$DEFINE BDS21_UP} + {$DEFINE BDS20_UP} + {$DEFINE BDS19_UP} + {$DEFINE BDS18_UP} + {$DEFINE BDS17_UP} + {$DEFINE BDS16_UP} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS22} // 11.0 ALEXANDRIA + {$DEFINE BDS} + {$DEFINE BDS22_UP} + {$DEFINE BDS21_UP} + {$DEFINE BDS20_UP} + {$DEFINE BDS19_UP} + {$DEFINE BDS18_UP} + {$DEFINE BDS17_UP} + {$DEFINE BDS16_UP} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS21} // 10.4 SYDNEY + {$DEFINE BDS} + {$DEFINE BDS21_UP} + {$DEFINE BDS20_UP} + {$DEFINE BDS19_UP} + {$DEFINE BDS18_UP} + {$DEFINE BDS17_UP} + {$DEFINE BDS16_UP} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS20} // 10.3 RIO + {$DEFINE BDS} + {$DEFINE BDS20_UP} + {$DEFINE BDS19_UP} + {$DEFINE BDS18_UP} + {$DEFINE BDS17_UP} + {$DEFINE BDS16_UP} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS19} // 10.2 Tokyo + {$DEFINE BDS} + {$DEFINE BDS19_UP} + {$DEFINE BDS18_UP} + {$DEFINE BDS17_UP} + {$DEFINE BDS16_UP} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS18} // 10.1 Berlin + {$DEFINE BDS} + {$DEFINE BDS18_UP} + {$DEFINE BDS17_UP} + {$DEFINE BDS16_UP} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS17} // 10 Seattle + {$DEFINE BDS} + {$DEFINE BDS17_UP} + {$DEFINE BDS16_UP} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS16} + {$DEFINE BDS} + {$DEFINE BDS16_UP} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS15} + {$DEFINE BDS} + {$DEFINE BDS15_UP} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS14} + {$DEFINE BDS} + {$DEFINE BDS14_UP} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS12} + {$DEFINE BDS} + {$DEFINE BDS12_UP} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS11} + {$DEFINE BDS} + {$DEFINE BDS11_UP} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} + + // NO BDS2014 defined, so need define below here. + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS10} + {$DEFINE BDS} + {$DEFINE BDS10_UP} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS2013} + {$DEFINE BDS2013_UP} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS9} + {$DEFINE BDS} + {$DEFINE BDS9_UP} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS2012} + {$DEFINE BDS2012_UP} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS8} + {$DEFINE BDS} + {$DEFINE BDS8_UP} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS2011} + {$DEFINE BDS2011_UP} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS7} + {$DEFINE BDS} + {$DEFINE BDS7_UP} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS2010} + {$DEFINE BDS2010_UP} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS6} + {$DEFINE BDS} + {$DEFINE BDS6_UP} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS2009} + {$DEFINE BDS2009_UP} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS5} + {$DEFINE BDS} + {$DEFINE BDS5_UP} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS2007} + {$DEFINE BDS2007_UP} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS4} + {$DEFINE BDS} + {$DEFINE BDS4_UP} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS2006} + {$DEFINE BDS2006_UP} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS3} + {$DEFINE BDS} + {$DEFINE BDS3_UP} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS2005} + {$DEFINE BDS2005_UP} +{$ENDIF} + +{$IFDEF BDS2} + {$DEFINE BDS} + {$DEFINE BDS2_UP} + {$DEFINE BDS1_UP} +{$ENDIF} + +{$IFDEF BDS1} + {$DEFINE BDS} + {$DEFINE BDS1_UP} +{$ENDIF} + +// COMPILERX_UP from COMPILERX mappings + +{$IFDEF COMPILER29} // 12.0 ATHENS + {$DEFINE COMPILER29_UP} + {$DEFINE COMPILER28_UP} + {$DEFINE COMPILER27_UP} + {$DEFINE COMPILER26_UP} + {$DEFINE COMPILER25_UP} + {$DEFINE COMPILER24_UP} + {$DEFINE COMPILER23_UP} + {$DEFINE COMPILER22_UP} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER28} // 11.0 ALEXANDRIA + {$DEFINE COMPILER28_UP} + {$DEFINE COMPILER27_UP} + {$DEFINE COMPILER26_UP} + {$DEFINE COMPILER25_UP} + {$DEFINE COMPILER24_UP} + {$DEFINE COMPILER23_UP} + {$DEFINE COMPILER22_UP} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER27} // 10.4 SYDNEY + {$DEFINE COMPILER27_UP} + {$DEFINE COMPILER26_UP} + {$DEFINE COMPILER25_UP} + {$DEFINE COMPILER24_UP} + {$DEFINE COMPILER23_UP} + {$DEFINE COMPILER22_UP} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER26} // 10.3 RIO + {$DEFINE COMPILER26_UP} + {$DEFINE COMPILER25_UP} + {$DEFINE COMPILER24_UP} + {$DEFINE COMPILER23_UP} + {$DEFINE COMPILER22_UP} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER25} // 10.2 Tokyo + {$DEFINE COMPILER25_UP} + {$DEFINE COMPILER24_UP} + {$DEFINE COMPILER23_UP} + {$DEFINE COMPILER22_UP} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER24} // 10.1 Berlin + {$DEFINE COMPILER24_UP} + {$DEFINE COMPILER23_UP} + {$DEFINE COMPILER22_UP} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER23} // 10 Seattle + {$DEFINE COMPILER23_UP} + {$DEFINE COMPILER22_UP} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER22} + {$DEFINE COMPILER22_UP} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER21} + {$DEFINE COMPILER21_UP} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER20} + {$DEFINE COMPILER20_UP} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER19} + {$DEFINE COMPILER19_UP} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER18} + {$DEFINE COMPILER18_UP} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER17} + {$DEFINE COMPILER17_UP} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER16} + {$DEFINE COMPILER16_UP} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER15} + {$DEFINE COMPILER15_UP} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER14} + {$DEFINE COMPILER14_UP} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER12} + {$DEFINE COMPILER12_UP} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER11} + {$DEFINE COMPILER11_UP} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER10} + {$DEFINE COMPILER10_UP} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER9} + {$DEFINE COMPILER9_UP} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER8} + {$DEFINE COMPILER8_UP} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER7} + {$DEFINE COMPILER7_UP} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER6} + {$DEFINE COMPILER6_UP} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER5} + {$DEFINE COMPILER5_UP} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER4} + {$DEFINE COMPILER4_UP} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER35} + {$DEFINE COMPILER35_UP} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER3} + {$DEFINE COMPILER3_UP} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER2} + {$DEFINE COMPILER2_UP} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +{$IFDEF COMPILER1} + {$DEFINE COMPILER1_UP} +{$ENDIF} + +// VCLXX_UP from VCLXX mappings + +{$IFDEF UCL10} + {$DEFINE UCL10_UP} +{$ENDIF} + +{$IFDEF VCL71} + {$DEFINE VCL71_UP} + {$DEFINE VCL70_UP} + {$DEFINE VCL60_UP} + {$DEFINE VCL50_UP} + {$DEFINE VCL40_UP} + {$DEFINE VCL30_UP} + {$DEFINE VCL20_UP} + {$DEFINE VCL10_UP} +{$ENDIF} + +{$IFDEF VCL70} + {$DEFINE VCL70_UP} + {$DEFINE VCL60_UP} + {$DEFINE VCL50_UP} + {$DEFINE VCL40_UP} + {$DEFINE VCL30_UP} + {$DEFINE VCL20_UP} + {$DEFINE VCL10_UP} +{$ENDIF} + +{$IFDEF VCL60} + {$DEFINE VCL60_UP} + {$DEFINE VCL50_UP} + {$DEFINE VCL40_UP} + {$DEFINE VCL30_UP} + {$DEFINE VCL20_UP} + {$DEFINE VCL10_UP} +{$ENDIF} + +{$IFDEF VCL50} + {$DEFINE VCL50_UP} + {$DEFINE VCL40_UP} + {$DEFINE VCL30_UP} + {$DEFINE VCL20_UP} + {$DEFINE VCL10_UP} +{$ENDIF} + +{$IFDEF VCL40} + {$DEFINE VCL40_UP} + {$DEFINE VCL30_UP} + {$DEFINE VCL20_UP} + {$DEFINE VCL10_UP} +{$ENDIF} + +{$IFDEF VCL30} + {$DEFINE VCL30_UP} + {$DEFINE VCL20_UP} + {$DEFINE VCL10_UP} +{$ENDIF} + +{$IFDEF VCL20} + {$DEFINE VCL20_UP} + {$DEFINE VCL10_UP} +{$ENDIF} + +{$IFDEF VCL10} + {$DEFINE VCL10_UP} +{$ENDIF} + +// CLXXX_UP from CLXXX mappings + +{$IFDEF CLX10} + {$DEFINE CLX10_UP} +{$ENDIF} + +//============================================================================== +// ƽ̨ض +//============================================================================== + +{$IFDEF COMPILER1} + {$DEFINE WIN16} + {$DEFINE MSWINDOWS} +{$ENDIF} + +{$IFDEF BDS} + {$DEFINE DOTNET} +{$ENDIF} + +{$IFDEF WIN32} + {$DEFINE MSWINDOWS} +{$ENDIF} + +{$IFDEF LINUX} + {$DEFINE UNIX} + {$DEFINE COMPLIB_CLX} +{$ENDIF} + +{$IFNDEF COMPLIB_CLX} + {$DEFINE COMPLIB_VCL} +{$ENDIF} + +//============================================================================== +// ӳ汾ϢѺõָ +//============================================================================== + +{$IFDEF DELPHI} + {$DEFINE SUPPORT_PASCAL} +{$ENDIF} + +{$IFDEF BCB} + {$DEFINE SUPPORT_PASCAL} + {$DEFINE SUPPORT_CPLUSPLUS} +{$ENDIF} + +{$IFDEF DELPHI120_ATHENS_UP} + {$DEFINE LIST_INDEX_NATIVEINT} // Athens 12 TList use NativeInt for Index and Count instead of Integer + {$DEFINE IDE_HAS_TABMENU_COPY_PATH} // Athens 12 editor tab menu has item to copy path or filename + {$DEFINE IDE_HAS_DBCLICK_HIGHLIGHT} // Athens 12 editor double click selection highlight + {$DEFINE OTA_CODEEDITOR_SERVICE} // 11.3 ToolsAPI.Editor ӿڣʱ޷ 11.0/1/2 ֻ֣ܼӵ 12 +{$ENDIF} + +{$IFDEF DELPHI110_ALEXANDRIA_UP} + {$DEFINE NO_OLDCREATEORDER} // Alexandria 11 removed OldCreateOrder + {$DEFINE IDE_SUPPORT_HDPI} // Alexandria 11 supports HDPI using TVirtualImageList, etc. + {$DEFINE IDE_HAS_AUTO_READONLY} // Alexandria 11 supports auto open VCL source readonly + {$DEFINE IDE_HAS_MEMORY_VISUALIZAER} // Alexandria 11 has Memory Visualizer for Debug + {$DEFINE TSTRINGS_SETTEXTSTR_CANNULL} // Alexandria 11 TStrings.SetTextStr Ignore #0 Terminated Char + {$DEFINE MEMORYSTREAM_CAPACITY_NATIVEINT} // Alexandria 11 TMemoryStream Capacity is NativeInt instead of Longint +{$ENDIF} + +{$IFDEF DELPHI104_SYDNEY_UP} + {$DEFINE IDE_SUPPORT_LSP} // Sydney 10.4 ֧ LSP Է + {$DEFINE IDE_HAS_ERRORINSIGHT} // Sydney 10.4.2 ֱ֧༭ ErrorInsight + {$DEFINE IDE_EDITOR_CUSTOM_COLUMN} // Sydney 10.4 ϱ༭ Gutter ֧Զ壬ûӿڲݣԼ + {$DEFINE IDE_SWITCH_BUG} // Sydney 10.4.2 ڴļʱĪл̨ Bug +{$ENDIF} + +{$IFDEF DELPHI103_RIO_UP} + {$DEFINE SUPPORT_MACOS64} // Rio 10.3.2 ֧ 64 λ MacOS +{$ENDIF} + +{$IFDEF DELPHI102_TOKYO_UP} + {$DEFINE SUPPORT_LINUX64} // Tokyo 10.2 ֧ Linux 64 λ Server + {$DEFINE IDE_SUPPORT_THEMING} // Tokyo 10.2.2 ֧ IDE л +{$ENDIF} + +{$IFDEF DELPHI101_BERLIN_UP} + {$DEFINE IDE_NEW_EMBEDDED_DESIGNER} // 101B Re-opens "Embedded Designer" Option and Gives a New Container. +{$ENDIF} + +{$IFDEF DELPHI10_SEATTLE_UP} + {$DEFINE IDE_HAS_OWN_STRUCTUAL_HIGHLIGHT} // 10S has own Structual Highlight + {$DEFINE IDE_HAS_HIDE_NONVISUAL} // 10S has "Hide Nonvisual" Feature. +{$ENDIF} + +{$IFDEF DELPHIXE8_UP} + {$DEFINE INIFILE_READWRITE_INTEGER} // XE8 IniFile ReadInteger WriteInteger ʼ LongInt Ϊ Integer + {$DEFINE IDE_INTEGRATE_CASTALIA} // XE8/10S and above integrate Castalia. +{$ENDIF} + +{$IFDEF COMPILER21_UP} // COMPILER21 = XE7 + {$DEFINE NOT_SUPPORT_BDE} // BDE +{$ENDIF} + +{$IFDEF DELPHIXE7_UP} + {$DEFINE SUPPORT_TBYTES_OPERATION} // XE7 TBytes ʼ֧ӡȲ + {$DEFINE FMX_CONTROL_HAS_SIZE} // XE7 FMX Control Size +{$ENDIF} + +{$IFDEF DELPHIXE6_UP} + {$DEFINE SUPPORT_JSON} // XE6 System.JSON ⣬ DBX/REST +{$ENDIF} + +{$IFDEF DELPHIXE5_UP} + {$DEFINE SUPPORT_MOBILE} // XE5 ʼ֧ƶ + {$DEFINE IDE_HAS_INSIGHT} // XE5 has IDE Insight Bar +{$ENDIF} + +{$IFDEF DELPHIXE4_UP} + {$IFNDEF DISABLE_FMX} + {$DEFINE SUPPORT_FMX_FRAME} // XE4 FMX Supports FMX Frame + {$ENDIF} +{$ELSE} + {$DEFINE MEMO_CARETPOS_BUG} // Memo CaretPos Get Negative Error Value for Large File under XE3 or below +{$ENDIF} + +{$IFDEF DELPHIXE3_UP} + {$DEFINE SUPPORT_ATOMIC} // XE3 has Atomic Routines + {$DEFINE TCONTROL_HAS_STYLEELEMENTS} // XE3 TControl has StyleElements Property + {$DEFINE IDE_NP_FMX_DESIGN_BUG} // XE3 FMX Designer Cut/Copy/Paste cause AV Bug for -np switch +{$ENDIF} + +{$IFDEF DELPHIXE2_UP} + {$DEFINE SUPPORT_WIN64} // XE2 Supports Win64 + {$DEFINE SUPPORT_MACOS32} // XE2 Supports MacOS 32 + {$DEFINE SUPPORT_UNITNAME_DOT} + {$DEFINE SUPPORT_ENHANCED_INDEXEDPROPERTY} // XE2 New RTTI Supports IndexedProperty + {$DEFINE SUPPORT_ZLIB_WINDOWBITS} // XE2 ZLib Supports WindowBits + {$DEFINE SUPPORT_GDIPLUS} // XE2 Supports GDI+ + {$DEFINE SUPPORT_INT64ARRAY} // XE2 Defined Int64Array + {$DEFINE SUPPORT_ALPHACOLOR} // XE2 System.UITypes Has TAlphaColors +{$ENDIF} + +{$IFDEF DELPHIXE_UP} + {$DEFINE TSTRINGS_HAS_WRITEBOM} // XE TStrings has WriteBOM property. + {$DEFINE IDE_HAS_DEBUGGERVISUALIZER} // XE ToolsAPI has Debugger Visualizer Interfaces. + {$DEFINE IDE_HAS_STRINGS_VISUALIZAER} // XE has TStrings Visualizer for Debug +{$ENDIF} + +{$IFDEF BDS2012_UP} // 2012 = XE2 + {$DEFINE SUPPORT_32_AND_64} // XE2 Support Win32 and Win64 + {$IFNDEF DISABLE_FMX} + {$DEFINE SUPPORT_FMX} + {$ENDIF} + {$DEFINE SUPPORT_CROSS_PLATFORM} // XE2 ֿ֧ƽ̨ + {$DEFINE VERSIONINFO_PER_CONFIGURATION} // Every Configuruation can have a Version Info. + {$DEFINE OTA_ENVOPTIONS_PLATFORM_BUG} + // A Bug Can't get Correct Env Option Values for Current Platform. + {$DEFINE LIST_NEW_POINTER} +{$ENDIF} + +{$IFDEF BDS2010_UP} + {$DEFINE SUPPORT_INTERFACE_AS_OBJECT} + {$DEFINE SUPPORT_ENHANCED_RTTI} // New enhanced RTTI. + {$DEFINE SUPPORT_EXTERNAL_DELAYED} // External functions can be declared as 'delayed'. + {$DEFINE SUPPORT_CLASS_CONSTRUCTOR} // 2010 and above Supports class constructor and destructor + {$DEFINE SUPPORT_CLASS_DESTRUCTOR} + {$DEFINE IMAGELIST_BEGINENDUPDATE} // 2010 ʼImageList й BeginUpdate EndUpdate + {$DEFINE OTA_DEBUG_HAS_EVENTS} // 2010 µ DebuggerService ProcessDebugEvents + {$DEFINE IDE_HAS_NEW_COMPONENT_PALETTE} // IDE has a new style Component Palette. + {$DEFINE IDE_HAS_EDITOR_SEARCHPANEL} // Editor has a Search Panel + {$DEFINE IDE_HAS_DATETIME_HINT} // TDate/TTime/TDateTime shows Normally in Debug Hint +{$ENDIF} + +{$IFDEF BDS2010} + // 2010 EditView CursorPos EditPosition.InsertText ƫ + {$DEFINE EDITVIEW_SETCURSORPOS_BUG} +{$ENDIF} + +{$IFDEF BDS2009_UP} + {$DEFINE UNICODE_STRING} + {$DEFINE SUPPORT_ATTRIBUTE} // ֧ Attribute + {$DEFINE SUPPORT_GENERIC} // ַ֧ + {$DEFINE SUPPORT_ANSISTRING_CODEPAGE} // AnsiString ָ֧ҳ + {$DEFINE SUPPORT_ENCODING} // Unicode with TEncoding + {$DEFINE SUPPORT_PUINT64} // Has Pointer of UInt64 + {$DEFINE OBJECT_HAS_TOSTRING} // TObject.ToString Function + {$DEFINE OBJECT_HAS_EQUAL} // TObject.Equal Function + {$DEFINE OBJECT_HAS_GETHASHCODE} // TObject.GetHashCode Function + {$DEFINE TGRAPHIC_SUPPORT_PARTIALTRANSPARENCY} // TGraphic ֧ Alpha ͨ͸ + {$DEFINE SUPPORT_OTA_PROJECT_CONFIGURATION} + + {$DEFINE IDE_MAINFORM_EAT_MOUSEWHEEL} + // MainForm of 2009 or Above will eat Message in MouseWheelHandler + {$DEFINE IDE_CODEINSIGHT_AUTOINVOKE} + // IDE Code Insight has Auto Invoke Option + {$DEFINE EDITVIEW_CONVERTPOS_BUG} + // 2009 or Above IEditView.ConvertPos Incorrect when Meeting Unicode Chars. + + {$IFNDEF DELPHIXE2_UP} // 2009/2010/XE has a Project Version Number Bug. + {$DEFINE PROJECT_VERSION_NUMBER_BUG} + {$ENDIF} + {$DEFINE OTA_DPKOPTION_SETVALUE_CORRUPT_BUG} + // A OpenTools API Bug IOTAProjectOptions.SetOptionValue under 2009 or above: + // Set an Option Value to DPK Project Options maybe cause DPK Source Corrupt. +{$ELSE} + {$DEFINE ZLIB_STREAM_NOSIZE} // 2007 µ Zlib Ľѹ֧ Size +{$ENDIF} + +{$IFDEF BDS2009} + // 2009 CreateParams пܵѭ + {$DEFINE CREATE_PARAMS_BUG} + // 2009 EditView CursorPos EditPosition.InsertText ƫ + {$DEFINE EDITVIEW_SETCURSORPOS_BUG} +{$ENDIF} + +{$IFDEF BDS2007_UP} + {$DEFINE IDE_CONF_MANAGER} + {$DEFINE TBYTES_DEFINED} // 2007 Defined TBytes = array of Byte; + {$DEFINE PROJECT_FILENAME_DPROJ} // Project File is .dproj +{$ENDIF} + +{$IFDEF BDS2007} + // RAD Studio 2007 ¿ AutoComplete ᵼĺ˸ + {$DEFINE COMBOBOX_CHS_BUG} +{$ENDIF} + +{$IFDEF BDS2006_UP} + {$DEFINE SUPPORT_CLASS_VAR} // 2006 and above Supports class var + {$DEFINE TCONTROL_HAS_MARGINS} // 2006 and above TControl has Margins + {$DEFINE TCONTROL_HAS_EXPLICIT_BOUNDS} // 2006 and above TControl has Explicit Bounds + {$DEFINE TCONTROL_HAS_MOUSEENTERLEAVE} // 2006 and above TControl has Mouse Enter/Leave Events + {$DEFINE OTA_CODE_TEMPLATE_API} // 2006 and above Provides CodeTemplateAPI. + {$DEFINE OTA_DEBUG_HAS_ERBUSY} // 2006 µ Evaluate зֵ erBusy + {$DEFINE IDE_HAS_GUIDE_LINE} // 2006 and above has Designer Guide Line + {$DEFINE IDE_SYNC_EDIT_BLOCK} // 2006 and above Editor Supports Sync Block Edit + {$DEFINE EDITOR_TAB_ONLYFROM_WINCONTROL} + // From BDS 2006 IDEGraident Editor Tab is Only From WinControl, not TabSet/TabControl +{$ENDIF} + +{$IFDEF BDS2005_UP} + {$DEFINE OTA_PALETTE_API} // 2005 and above Provides PaletteAPI. + {$DEFINE IDE_EDITOR_ELIDE} // 2005 ϱ༭֧۵ + {$DEFINE IDE_FILE_HISTORY} // 2005 ϰ汾洢ļʷ汾 +{$ENDIF} + +{$IFDEF BDS2006} + {$DEFINE PROJECT_FILENAME_BDSPROJ} // Project File is .bdsproj +{$ENDIF} + +{$IFDEF BDS2005} + {$DEFINE PROJECT_FILENAME_BDSPROJ} // Project File is .bdsproj +{$ENDIF} + +{$IFDEF BDS} // 2005 + {$DEFINE SUPPORT_PASCAL} + {$DEFINE SUPPORT_CSHARP} + {$DEFINE SUPPORT_INLINE} + {$DEFINE SUPPORT_UINT64} + {$DEFINE IDE_WIDECONTROL} // 2005 ϵı༭ڲǿַ UTF-8Ƿ Unicode + {$DEFINE IDE_EDITOR_SUPPORT_FOLDING} // 2005 ϵı༭֧۵ + {$DEFINE OTA_NEW_BREAKPOINT_NOBUG} // 2005 ϵ NewBreakpoint ܹ + {$DEFINE IDE_ACTION_UPDATE_DELAY} // IDE's Action Menu Update will Delay in 2005 or Up. + {$DEFINE SUPPORT_WIDECHAR_IDENTIFIER} + + {$IFNDEF COMPILER12_UP} + // 2005~2007 Compiler is Ansi but Editor String is UTF-8 + {$DEFINE IDE_STRING_ANSI_UTF8} + {$ENDIF} +{$ENDIF} + +{$IFDEF DELPHI7_UP} + {$DEFINE SUPPORT_FORMAT_SETTINGS} // Delphi 7 ʼ֧ FormatSettings + {$DEFINE IDE_MENUBAR_VERTICAL_POSITION_BUG} + // Delphi 7 ϵ MenuBar ֱϵĵλü׳Ͻ + {$DEFINE IDE_MENUBAR_VERTICAL_NOSCROLL_BUG} + // Delphi 7 ϵ MenuBar ֱʱ +{$ENDIF} + +{$IFDEF COMPILER6_UP} + {$DEFINE SUPPORT_DEPRECATED} +{$ENDIF} + +{$IFDEF COMPILER6_UP} + {$DEFINE SUPPORT_ENUMVALUES} + {$DEFINE SUPPORT_VARIANTS} + {$DEFINE SUPPORT_IFDIRECTIVE} +{$ENDIF} + +{$IFDEF DELPHI5_UP} + {$IFNDEF BDS2005_UP} + {$DEFINE PROJECT_FILENAME_DPR} // Delphi 5/6/7 Project File is .dpr + {$ENDIF} +{$ENDIF} + +{$IFDEF COMPILER5} + {$DEFINE TSTREAM_LONGINT} // D6 ϵ TStream Int64 +{$ENDIF} + +{$IFDEF BCB5} + {$DEFINE BCB5OR6} // һ BCB5OR6 Է BCB5 BCB6 ʹ +{$ENDIF} + +{$IFDEF BCB6} + {$DEFINE BCB5OR6} +{$ENDIF} + +{$IFDEF BCB5OR6} + {$DEFINE NO_ZLIB} +{$ENDIF} + +{$IFDEF DELPHI5} + {$DEFINE DELPHI5OR6} // һ DELPHI5OR6 Է DELPHI5 DELPHI6 ʹ +{$ENDIF} + +{$IFDEF DELPHI6} + {$DEFINE DELPHI5OR6} +{$ENDIF} + +{$IFDEF COMPILER4_UP} + {$DEFINE SUPPORT_INT64} + {$DEFINE SUPPORT_DYNAMICARRAYS} + {$DEFINE SUPPORT_DEFAULTPARAMS} + {$DEFINE SUPPORT_REINTRODUCE} + {$DEFINE SUPPORT_OVERLOAD} +{$ENDIF} + +{$IFDEF COMPILER35_UP} + {$DEFINE SUPPORT_EXTSYM} + {$DEFINE SUPPORT_NODEFINE} +{$ENDIF} + +{$IFDEF COMPILER3_UP} + {$DEFINE SUPPORT_WIDESTRING} + {$DEFINE SUPPORT_INTERFACE} +{$ENDIF} + +{$IFDEF WIN64} + {$DEFINE EXTENDED_SIZE_8} // Win64 Extended ͳ 8 ֽ +{$ENDIF} + +{$IFDEF CPUARM} + {$DEFINE EXTENDED_SIZE_8} // ARM ƽ̨ Extended ͳ 8 ֽ +{$ENDIF} + +{$IFDEF WIN32} + {$DEFINE EXTENDED_SIZE_10} // Win32 Extended ͳ 10 ֽ +{$ENDIF} + +{$IFDEF MACOS64} + {$DEFINE EXTENDED_SIZE_16} // MacOS64 Extended ͳ 16 ֽ +{$ENDIF} + +{$IFDEF LINUX64} + {$DEFINE EXTENDED_SIZE_16} // Linux64 Extended ͳ 16 ֽ +{$ENDIF} + +//============================================================================== +// PascalScript ĵ +//============================================================================== + +{.$DEFINE ALLDEBUG} // òƲҪȽ + +//============================================================================== +// ֶ +//============================================================================== + +{$DEFINE GB2312} +{.$DEFINE BIG5} +{.$DEFINE ENGLISH} + +//============================================================================== +// ıָ +//============================================================================== + +{$A+ Force alignment on word/dword boundaries} +{$S+ stack checking} + +{$B- Short evaluation of boolean values} +{$H+ Long string support} +{$V- No var string checking} +{$X+ Extended syntax} +{$P+ Open string parameters} +{$J+ Writeable typed constants} +{$R- No Range checking} +{$OVERFLOWCHECKS OFF} + +{$IFDEF COMPILER6_UP} + {$WARN SYMBOL_PLATFORM OFF} + {$WARN UNIT_PLATFORM OFF} + {$WARN SYMBOL_DEPRECATED OFF} + {$WARN UNIT_DEPRECATED OFF} +{$ENDIF} + +{$IFDEF COMPILER7_UP} + {$WARN UNSAFE_CAST OFF} + {$WARN UNSAFE_CODE OFF} + {$WARN UNSAFE_TYPE OFF} +{$ENDIF} + +{$IFDEF BCB} + {$OBJEXPORTALL ON} +{$ENDIF} + +{$DEFINE CN_USE_MSXML} + +{$ENDIF FPC} + diff --git a/Net/Net.CrossHttpParams.pas b/Net/Net.CrossHttpParams.pas index b181dd8..36f651e 100644 --- a/Net/Net.CrossHttpParams.pas +++ b/Net/Net.CrossHttpParams.pas @@ -1,3509 +1,3509 @@ -{******************************************************************************} -{ } -{ Delphi cross platform socket library } -{ } -{ Copyright (c) 2017 WiNDDRiVER(soulawing@gmail.com) } -{ } -{ Homepage: https://github.com/winddriver/Delphi-Cross-Socket } -{ } -{******************************************************************************} -unit Net.CrossHttpParams; - -{$I zLib.inc} - -interface - -uses - SysUtils, - Classes, - Generics.Collections, - Generics.Defaults, - DateUtils, - Math, - - {$IFDEF DELPHI} - System.Diagnostics, - {$ELSE} - DTF.Types, - DTF.Diagnostics, - DTF.Generics, - {$ENDIF} - - Net.CrossHttpUtils, - - Utils.AnonymousThread, - Utils.RegEx, - Utils.IOUtils, - Utils.DateTime, - Utils.StrUtils, - Utils.SyncObjs, - Utils.ArrayUtils, - Utils.Utils; - -type - TNameValue = record - Name, Value: string; - constructor Create(const AName, AValue: string); - end; - - INameValueComparer = IComparer; - TNameValueComparison = {$IFDEF DELPHI}TComparison{$ELSE}TComparisonAnonymousFunc{$ENDIF}; - TNameValueComparer = {$IFDEF DELPHI}TDelegatedComparer{$ELSE}TDelegatedComparerAnonymousFunc{$ENDIF}; - - /// - /// 参数基础类 - /// - TBaseParams = class - private type - TEnumerator = class - private - FIndex: Integer; - FParams: TBaseParams; - public - constructor Create(const AParams: TBaseParams); - function GetCurrent: TNameValue; inline; - function MoveNext: Boolean; inline; - property Current: TNameValue read GetCurrent; - end; - private - FParams: TList; - - function GetParamIndex(const AName: string): Integer; - function GetParam(const AName: string): string; - procedure SetParam(const AName, AValue: string); - function GetCount: Integer; - function GetItem(AIndex: Integer): TNameValue; - procedure SetItem(AIndex: Integer; const AValue: TNameValue); - public - constructor Create; overload; virtual; - constructor Create(const AEncodedParams: string); overload; virtual; - destructor Destroy; override; - - /// - /// 枚举器 - /// - function GetEnumerator: TEnumerator; inline; - - /// - /// 从源对象设置数据 - /// - procedure Assign(const ASource: TBaseParams); - - /// - /// 添加参数 - /// - procedure Add(const AParamValue: TNameValue); overload; - - /// - /// 添加参数 - /// - /// - /// 参数名 - /// - /// - /// 参数值 - /// - /// - /// 是否允许重名参数 - /// - procedure Add(const AName, AValue: string; ADupAllowed: Boolean = False); overload; - - /// - /// 添加已编码参数 - /// - /// - /// 已编码参数字符串 - /// - procedure Add(const AEncodedParams: string); overload; - - /// - /// 根据名称删除指定参数 - /// - /// - /// 参数名称 - /// - procedure Remove(const AName: string); overload; - - /// - /// 根据序号删除指定参数 - /// - /// - /// 参数序号 - /// - procedure Remove(AIndex: Integer); overload; - - /// - /// 清除所有参数 - /// - procedure Clear; - - /// - /// 对参数排序 - /// - /// - /// 自定义比较函数,为nil时按参数名排序 - /// - procedure Sort(const AComparison: TNameValueComparison = nil); - - /// - /// 从已编码的字符串中解码 - /// - /// - /// 已编码字符串 - /// - /// - /// 是否清除现有数据 - /// - /// - /// 解码是否成功 - /// - function Decode(const AEncodedParams: string; AClear: Boolean = True): Boolean; virtual; abstract; - - /// - /// 编码为字符串 - /// - /// - /// 编码后的字符串 - /// - function Encode: string; virtual; abstract; - - /// - /// 获取参数值 - /// - /// - /// 参数名称 - /// - /// - /// 返回的参数值 - /// - /// - /// 如果找到参数返回True,否则返回False - /// - function GetParamValue(const AName: string; out AValue: string): Boolean; - - /// - /// 获取指定名称的所有参数值 - /// - /// - /// 参数名称 - /// - /// - /// 返回的参数值数组 - /// - /// - /// 如果找到参数返回True,否则返回False - /// - function GetHeaderValues(const AName: string; out AValues: TArray): Boolean; - - /// - /// 是否存在参数 - /// - /// - /// 参数名称 - /// - /// - /// 如果存在参数返回True,否则返回False - /// - function ExistsParam(const AName: string): Boolean; - - /// - /// 按名称访问参数 - /// - /// - /// 参数名称 - /// - /// - /// 参数值,如果不存在返回空字符串 - /// - property Params[const AName: string]: string read GetParam write SetParam; default; - - /// - /// 按序号访问参数 - /// - /// - /// 参数序号 - /// - /// - /// 参数名值对 - /// - property Items[AIndex: Integer]: TNameValue read GetItem write SetItem; - - /// - /// 参数个数 - /// - property Count: Integer read GetCount; - end; - - /// - /// Url参数类 - /// - THttpUrlParams = class(TBaseParams) - private - FEncodeName: Boolean; - FEncodeValue: Boolean; - public - constructor Create; override; - - /// - /// 从已编码的字符串中解码 - /// - /// - /// 已编码字符串 - /// - /// - /// 是否清除现有数据 - /// - function Decode(const AEncodedParams: string; AClear: Boolean = True): Boolean; override; - - /// - /// 编码为字符串 - /// - function Encode: string; override; - - /// - /// 是否对名称做编码 - /// - property EncodeName: Boolean read FEncodeName write FEncodeName; - - /// - /// 是否对名称做编码 - /// - property EncodeValue: Boolean read FEncodeValue write FEncodeValue; - end; - - /// - /// HTTP头类 - /// - THttpHeader = class(TBaseParams) - public - /// - /// 从已编码的字符串中解码 - /// - /// - /// 已编码字符串 - /// - /// - /// 是否清除现有数据 - /// - function Decode(const AEncodedParams: string; AClear: Boolean = True): Boolean; override; - - /// - /// 编码为字符串 - /// - function Encode: string; override; - end; - - {$REGION 'Documentation'} - /// - /// x-www-form-urlencoded 格式参数 - /// - {$ENDREGION} - TFormUrlEncoded = class(THttpUrlParams); - - /// - /// 带分隔符的参数 - /// - TDelimitParams = class(TBaseParams) - private - FDelimiter: Char; - FUrlEncode: Boolean; - public - constructor Create(const ADelimiter: Char; const AUrlEncode: Boolean = False); reintroduce; overload; virtual; - constructor Create(const AEncodedParams: string; const ADelimiter: Char; const AUrlEncode: Boolean = False); reintroduce; overload; virtual; - - /// - /// 从已编码的字符串中解码 - /// - /// - /// 已编码字符串 - /// - /// - /// 是否清除现有数据 - /// - function Decode(const AEncodedParams: string; AClear: Boolean = True): Boolean; override; - - /// - /// 编码为字符串 - /// - function Encode: string; override; - - /// - /// 分隔字符 - /// - property Delimiter: Char read FDelimiter write FDelimiter; - - /// - /// 是否进行URL编解码 - /// - property UrlEncode: Boolean read FUrlEncode write FUrlEncode; - end; - - {$REGION 'Documentation'} - /// - /// 客户端请求头中的Cookies - /// - /// - /// - /// 格式如下 - /// - /// - /// Cookie: name1=value1; name2=value2; ... - /// - /// - {$ENDREGION} - TRequestCookies = class(TBaseParams) - public - /// - /// 从已编码的字符串中解码 - /// - /// - /// 已编码字符串 - /// - /// - /// 是否清除现有数据 - /// - function Decode(const AEncodedParams: string; AClear: Boolean = True): Boolean; override; - - /// - /// 编码为字符串 - /// - function Encode: string; override; - end; - - {$REGION 'Documentation'} - /// - /// 响应头中的Cookie - /// - /// - /// - /// 格式如下 - /// - /// - /// Set-Cookie: name=value; [expires=date;] [path=path;] - /// [domain=domain;] [secure;] [HttpOnly;]
- ///
- ///
- {$ENDREGION} - TResponseCookie = record - /// - /// Cookie名称 - /// - Name: string; - - /// - /// Cookie数据 - /// - Value: string; - - /// - /// Cookie有效期秒数, 如果设置为0则浏览器关闭后该Cookie即失效 - /// - MaxAge: Integer; - - /// - /// 域名作用域 - /// - /// - /// 定义Cookie的生效作用域, 只有当域名和路径同时满足的时候, 浏览器才会将Cookie发送给Server. - /// 如果没有设置Domain和Path的话, 他们会被默认为当前请求页面对应值 - /// - Domain: string; - - /// - /// 路径作用域 - /// - /// - /// 定义Cookie的生效作用域, 只有当域名和路径同时满足的时候, 浏览器才会将Cookie发送给Server. - /// 如果没有设置Domain和Path的话, 他们会被默认为当前请求页面对应值 - /// - Path: string; - - /// - /// 是否启用 HttpOnly - /// - /// - /// HttpOnly字段告诉浏览器, 只有在HTTP协议下使用, 对浏览器的脚本不可见, 所以跨站脚本攻击时也不会被窃取 - /// - HttpOnly: Boolean; - - /// - /// 是否启用Secure - /// - /// - /// Secure字段告诉浏览器在https通道时, 对Cookie进行安全加密, 这样即时有黑客监听也无法获取cookie内容 - /// - Secure: Boolean; - - constructor Create(const AName, AValue: string; AMaxAge: Integer; - const APath: string = ''; const ADomain: string = ''; - AHttpOnly: Boolean = False; ASecure: Boolean = False); overload; - - constructor Create(const ACookieData: string; const ADomain: string = ''); overload; - - function Encode: string; - end; - - /// - /// Cookie类 - /// - TResponseCookies = class(TList) - private - function GetCookieIndex(const AName: string): Integer; - function GetCookie(const AName: string): TResponseCookie; - procedure SetCookie(const AName: string; const Value: TResponseCookie); - public - procedure AddOrSet(const AName, AValue: string; AMaxAge: Integer; - const APath: string = ''; const ADomain: string = ''; - AHttpOnly: Boolean = False; ASecure: Boolean = False); - procedure Remove(const AName: string); - - property Cookies[const AName: string]: TResponseCookie read GetCookie write SetCookie; - end; - - TFormField = class - private - FName: string; - FValue: TStream; - FFileName: string; - FFilePath: string; - FContentType: string; - FContentTransferEncoding: string; - FValueOwned, FIsTempFile: Boolean; - public - constructor Create; overload; - destructor Destroy; override; - - /// - /// 从源对象设置数据 - /// - procedure Assign(const ASource: TFormField); - - /// - /// 将数据转为字节 - /// - function AsBytes: TBytes; - - /// - /// 将数据转为字符串 - /// - /// - /// 字符串编码 - /// - function AsString(AEncoding: TEncoding = nil): string; - - /// - /// 释放流数据 - /// - procedure FreeValue; - - /// - /// 名称 - /// - property Name: string read FName; - - /// - /// 原始流数据 - /// - property Value: TStream read FValue; - - /// - /// 文件名(只有文件才有该属性) - /// - property FileName: string read FFileName; - - /// - /// 文件保存路径(只有文件才有该属性) - /// - property FilePath: string read FFilePath; - - /// - /// 内容类型(只有文件才有该属性) - /// - property ContentType: string read FContentType; - property ContentTransferEncoding: string read FContentTransferEncoding; - end; - - /// - /// FormData解码结果 - /// - TFormDataDecodeResult = (frContinue, frComplete, frFailed); - - /// - /// MultiPartFormData类 - /// - THttpMultiPartFormData = class - private type - TEnumerator = class - private - FList: TList; - FIndex: Integer; - public - constructor Create(const AList: TList); - function GetCurrent: TFormField; inline; - function MoveNext: Boolean; inline; - property Current: TFormField read GetCurrent; - end; - public type - TDecodeState = (dsBoundary, dsDetect, dsPartHeader, dsPartData); - - /// - /// 头部结束标记检测状态机, 严格匹配 #13#10#13#10 序列 - /// - TLineEndState = (lesCR1, lesLF1, lesCR2, lesLF2); - - /// - /// dsDetect 状态: Boundary 标记之后判断是 Header 数据还是结束标记 - /// - TPostBoundaryState = (pbsDetect, pbsHeader1, pbsEnd1, pbsEnd2, pbsEnd3); - private const - MAX_PART_HEADER: Integer = 64 * 1024; - private - FBoundary, FStoragePath: string; - FFirstBoundaryBytes, FBoundaryBytes, FLookbehind: TBytes; - FBoundaryIndex, FPartDataBegin: Integer; - FPostBoundaryState: TPostBoundaryState; - FPrevBoundaryIndex: Integer; - FDecodeState: TDecodeState; - FLineEndState: TLineEndState; - FPartFields: TObjectList; - FCurrentPartHeader: TBytes; - FCurrentPartHeaderLen: Integer; - FCurrentPartField: TFormField; - FAutoDeleteFiles: Boolean; - FMaxPartDataSize: Integer; - FCurrentPartDataSize: Int64; - - function GetItemIndex(const AName: string): Integer; - function GetItem(AIndex: Integer): TFormField; - function GetCount: Integer; - function GetDataSize: Integer; - function GetField(const AName: string): TFormField; - procedure SetBoundary(const AValue: string); - public - constructor Create; virtual; - destructor Destroy; override; - - {$REGION 'Documentation'} - /// - /// 枚举器 - /// - {$ENDREGION} - function GetEnumerator: TEnumerator; inline; - - {$REGION 'Documentation'} - /// - /// 从源对象设置数据 - /// - {$ENDREGION} - procedure Assign(const ASource: THttpMultiPartFormData); - - {$REGION 'Documentation'} - /// - /// 初始化Boundary(Decode之前调用) - /// - {$ENDREGION} - procedure InitWithBoundary(const ABoundary: string); - - {$REGION 'Documentation'} - /// - /// 从内存中解码(必须先调用InitWithBoundary) - /// - /// - /// 待解码数据 - /// - /// - /// 数据长度 - /// - /// - /// 已知限制: 仅支持 multipart/form-data; 不支持 RFC 2046 preamble/epilogue 文本; - /// 不支持 multipart/mixed 嵌套; Content-Transfer-Encoding 仅存储不解码. - /// - {$ENDREGION} - function Decode(const ABuf: Pointer; ALen: Integer): TFormDataDecodeResult; overload; - - {$REGION 'Documentation'} - /// - /// 从内存中解码并返回实际消费的字节数(必须先调用InitWithBoundary) - /// - /// - /// 待解码数据 - /// - /// - /// 数据长度 - /// - /// - /// 出参: 实际消费的字节数. frComplete 时可能小于 ALen, 调用方需要用剩余字节继续后续解析. - /// - {$ENDREGION} - function Decode(const ABuf: Pointer; ALen: Integer; out AConsumed: Integer): TFormDataDecodeResult; overload; - - {$REGION 'Documentation'} - /// - /// 从数据流解码(必须先调用InitWithBoundary) - /// - /// - /// 待解码数据流 - /// - {$ENDREGION} - function Decode(const AStream: TStream): TFormDataDecodeResult; overload; - - {$REGION 'Documentation'} - /// - /// 清除所有Items - /// - {$ENDREGION} - procedure Clear; - - {$REGION 'Documentation'} - /// - /// 添加字段 - /// - /// - /// 字段对象 - /// - {$ENDREGION} - function AddField(const AField: TFormField): TFormField; overload; - - {$REGION 'Documentation'} - /// - /// 添加字段 - /// - /// - /// 字段名 - /// - /// - /// 字段值 - /// - {$ENDREGION} - function AddField(const AFieldName: string; const AValue: TBytes): TFormField; overload; - - {$REGION 'Documentation'} - /// - /// 添加字段 - /// - /// - /// 字段名 - /// - /// - /// 字段值 - /// - {$ENDREGION} - function AddField(const AFieldName, AValue: string): TFormField; overload; - - {$REGION 'Documentation'} - /// - /// 添加文件字段 - /// - /// - /// 字段名 - /// - /// - /// 文件名 - /// - /// - /// 文件流 - /// - /// - /// 是否自动释放 - /// - {$ENDREGION} - function AddFile(const AFieldName, AFileName: string; - const AStream: TStream; const AOwned: Boolean = False): TFormField; overload; - - {$REGION 'Documentation'} - /// - /// 添加文件字段 - /// - /// - /// 字段名 - /// - /// - /// 文件名 - /// - {$ENDREGION} - function AddFile(const AFieldName, AFileName: string): TFormField; overload; - - {$REGION 'Documentation'} - /// - /// 根据名称删除指定字段 - /// - /// - /// 字段名 - /// - {$ENDREGION} - procedure Remove(const AFieldName: string); overload; - - {$REGION 'Documentation'} - /// - /// 根据序号删除指定字段 - /// - /// - /// 字段序号 - /// - {$ENDREGION} - procedure Remove(AIndex: Integer); overload; - - {$REGION 'Documentation'} - /// - /// 查找参数 - /// - {$ENDREGION} - function FindField(const AFieldName: string; out AField: TFormField): Boolean; - - function AsBytes(const AFieldName: string; out AValue: TBytes): Boolean; overload; - function AsBytes(const AFieldName: string): TBytes; overload; - - function AsStream(const AFieldName: string; out AValue: TStream): Boolean; overload; - function AsStream(const AFieldName: string): TStream; overload; - - function AsString(const AFieldName: string; const AEncoding: TEncoding; out AValue: string): Boolean; overload; - function AsString(const AFieldName: string; out AValue: string): Boolean; overload; - function AsString(const AFieldName: string; const AEncoding: TEncoding = nil): string; overload; - - {$REGION 'Documentation'} - /// - /// Boundary特征字符串 - /// - {$ENDREGION} - property Boundary: string read FBoundary write SetBoundary; - - {$REGION 'Documentation'} - /// - /// 上传文件保存的路径 - /// - {$ENDREGION} - property StoragePath: string read FStoragePath write FStoragePath; - - {$REGION 'Documentation'} - /// - /// 按序号访问参数 - /// - {$ENDREGION} - property Items[AIndex: Integer]: TFormField read GetItem; - - {$REGION 'Documentation'} - /// - /// 按名称访问参数 - /// - {$ENDREGION} - property Fields[const AName: string]: TFormField read GetField; - - {$REGION 'Documentation'} - /// - /// Items个数(只读) - /// - {$ENDREGION} - property Count: Integer read GetCount; - - {$REGION 'Documentation'} - /// - /// 所有Items数据的总尺寸(字节数) - /// - {$ENDREGION} - property DataSize: Integer read GetDataSize; - - {$REGION 'Documentation'} - /// - /// 对象释放时自动删除上传的文件 - /// - {$ENDREGION} - property AutoDeleteFiles: Boolean read FAutoDeleteFiles write FAutoDeleteFiles; - - {$REGION 'Documentation'} - /// - /// 单个 Part Body 最大字节数, 0 表示不限制. 超过限制时 Decode 返回 frFailed. - /// - {$ENDREGION} - property MaxPartDataSize: Integer read FMaxPartDataSize write FMaxPartDataSize; - end; - - {$REGION 'Documentation'} - /// - /// MultiPartFormData流 - /// - /// - /// 动态从 MultiPartFormData 对象中读取数据, 而不是打包到内存中, 所以支持从磁盘加载超大文件 - /// - {$ENDREGION} - THttpMultiPartFormStream = class(TStream) - private type - TFormFieldEx = record - Header: TBytes; - Field: TFormField; - Offset: Int64; - - function HeaderSize: Integer; - function DataSize: Int64; - function TotalSize: Int64; - end; - - TFormFieldExArray = TArray; - private - FMultiPartFormData: THttpMultiPartFormData; - FOwned: Boolean; - FFormFieldExArray: TFormFieldExArray; - FMultiPartEnd: TBytes; - FSize, FPosition, FEndPos: Int64; - - procedure _Init; - function _GetFiledIndexByOffset(const AOffset: Int64): Integer; - public - constructor Create(const AMultiPartFormData: THttpMultiPartFormData; - const AOwned: Boolean = False); reintroduce; - destructor Destroy; override; - - function Read(var ABuffer; ACount: Longint): Longint; override; - function Seek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64; override; - - property MultiPartFormData: THttpMultiPartFormData read FMultiPartFormData; - end; - - TSessionsBase = class; - ISessions = interface; - - /// - /// Session成员接口 - /// - ISession = interface - ['{A3D525A1-C534-4CE6-969B-53C5B8CB77C3}'] - function GetOwner: ISessions; - - function GetSessionID: string; - function GetCreateTime: TDateTime; - function GetLastAccessTime: TDateTime; - function GetExpiryTime: Integer; - function GetValue(const AName: string): string; - procedure SetSessionID(const ASessionID: string); - procedure SetCreateTime(const ACreateTime: TDateTime); - procedure SetLastAccessTime(const ALastAccessTime: TDateTime); - procedure SetExpiryTime(const Value: Integer); - procedure SetValue(const AName, AValue: string); - - /// - /// 更新最后访问时间 - /// - procedure Touch; - - /// - /// 是否已过期 - /// - function Expired: Boolean; - - /// - /// 父容器 - /// - property Owner: ISessions read GetOwner; - - /// - /// Session ID - /// - property SessionID: string read GetSessionID write SetSessionID; - - /// - /// 创建时间 - /// - property CreateTime: TDateTime read GetCreateTime write SetCreateTime; - - /// - /// 最后访问时间 - /// - property LastAccessTime: TDateTime read GetLastAccessTime write SetLastAccessTime; - - /// - /// Session过期时间(秒) - /// - /// - /// - /// - /// 值大于0时, 当Session超过设定值秒数没有使用就会被释放; - /// - /// - /// 值等于0时, 使用父容器的超时设置 - /// - /// - /// 值小于0时, Session生成后一直有效 - /// - /// - /// - property ExpiryTime: Integer read GetExpiryTime write SetExpiryTime; - - /// - /// Session是一个KEY-VALUE结构的数据, 该属性用于访问其中的成员值 - /// - property Values[const AName: string]: string read GetValue write SetValue; default; - end; - - TSessionBase = class abstract(TInterfacedObject, ISession) - private - FOwner: TSessionsBase; - protected - function GetOwner: ISessions; - function GetSessionID: string; virtual; abstract; - function GetCreateTime: TDateTime; virtual; abstract; - function GetLastAccessTime: TDateTime; virtual; abstract; - function GetExpiryTime: Integer; virtual; abstract; - function GetValue(const AName: string): string; virtual; abstract; - procedure SetSessionID(const ASessionID: string); virtual; abstract; - procedure SetCreateTime(const ACreateTime: TDateTime); virtual; abstract; - procedure SetLastAccessTime(const ALastAccessTime: TDateTime); virtual; abstract; - procedure SetExpiryTime(const Value: Integer); virtual; abstract; - procedure SetValue(const AName, AValue: string); virtual; abstract; - public - constructor Create(const AOwner: TSessionsBase; const ASessionID: string); virtual; - - procedure Touch; virtual; - function Expired: Boolean; virtual; - - property Owner: ISessions read GetOwner; - - property SessionID: string read GetSessionID write SetSessionID; - property CreateTime: TDateTime read GetCreateTime write SetCreateTime; - property LastAccessTime: TDateTime read GetLastAccessTime write SetLastAccessTime; - property ExpiryTime: Integer read GetExpiryTime write SetExpiryTime; - property Values[const AName: string]: string read GetValue write SetValue; default; - end; - - TSession = class(TSessionBase) - protected - FSessionID: string; - FCreateTime: TDateTime; - FLastAccessTime: TDateTime; - FExpire: Integer; - FValues: TDictionary; - - function GetSessionID: string; override; - function GetCreateTime: TDateTime; override; - function GetLastAccessTime: TDateTime; override; - function GetExpiryTime: Integer; override; - function GetValue(const AName: string): string; override; - procedure SetSessionID(const ASessionID: string); override; - procedure SetCreateTime(const ACreateTime: TDateTime); override; - procedure SetLastAccessTime(const ALastAccessTime: TDateTime); override; - procedure SetExpiryTime(const AValue: Integer); override; - procedure SetValue(const AName, AValue: string); override; - public - constructor Create(const AOwner: TSessionsBase; const ASessionID: string); override; - destructor Destroy; override; - - property SessionID: string read GetSessionID write SetSessionID; - property CreateTime: TDateTime read GetCreateTime write SetCreateTime; - property LastAccessTime: TDateTime read GetLastAccessTime write SetLastAccessTime; - property Values[const AName: string]: string read GetValue write SetValue; default; - end; - - TSessionClass = class of TSessionBase; - - /// - /// Session管理接口 - /// - ISessions = interface - ['{5187CA76-4CC4-4986-B67B-BC3E76D6CD74}'] - function GetEnumerator: TEnumerator; - - function GetSessionClass: TSessionClass; - function GetCount: Integer; - function GetItem(const AIndex: Integer): ISession; - function GetSession(const ASessionID: string): ISession; - function GetExpiryTime: Integer; - procedure SetSessionClass(const Value: TSessionClass); - procedure SetExpiryTime(const Value: Integer); - - /// - /// 开始写(用于线程同步) - /// - procedure BeginWrite; - - /// - /// 结束写(用于线程同步) - /// - procedure EndWrite; - - /// - /// 开始读(用于线程同步) - /// - procedure BeginRead; - - /// - /// 结束读(用于线程同步) - /// - procedure EndRead; - - /// - /// 生成新Session ID - /// - function NewSessionID: string; - - /// - /// 检查是否存在指定ID的Session - /// - /// - /// Session ID - /// - /// - /// 如果存在指定的Session, 则将实例保存到该参数中 - /// - function ExistsSession(const ASessionID: string; var ASession: ISession): Boolean; overload; - - /// - /// 检查是否存在指定ID的Session - /// - /// - /// Session ID - /// - function ExistsSession(const ASessionID: string): Boolean; overload; - - /// - /// 新增Session - /// - /// - /// Session ID - /// - /// - /// Session实例 - /// - function AddSession(const ASessionID: string): ISession; overload; - - /// - /// 新增Session - /// - /// - /// Session实例 - /// - function AddSession: ISession; overload; - - /// - /// 新增Session - /// - /// - /// Session ID - /// - /// - /// Session实例 - /// - procedure AddSession(const ASessionID: string; ASession: ISession); overload; - - /// - /// 删除Session - /// - /// - /// Session对象 - /// - procedure RemoveSession(const ASession: ISession); overload; - - /// - /// 删除Session - /// - /// - /// Session ID - /// - procedure RemoveSession(const ASessionID: string); overload; - - /// - /// 批量删除Session - /// - /// - /// Session对象数据 - /// - procedure RemoveSessions(const ASessions: TArray); - - /// - /// 清除所有Session - /// - procedure Clear; - - /// - /// Session类 - /// - property SessionClass: TSessionClass read GetSessionClass write SetSessionClass; - - /// - /// Session个数 - /// - property Count: Integer read GetCount; - - /// - /// 获取指定序号的Session, 如果不存在则返回nil - /// - property Items[const AIndex: Integer]: ISession read GetItem; - - /// - /// 获取指定ID的Session, 如果不存在则会新建一个 - /// - /// - /// Session ID - /// - property Sessions[const ASessionID: string]: ISession read GetSession; default; - - /// - /// Session过期时间(秒) - /// - /// - /// - /// - /// 值大于0时, 当Session超过设定值秒数没有使用就会被释放; - /// - /// - /// 值小于等于0时, Session生成后一直有效 - /// - /// - /// - property ExpiryTime: Integer read GetExpiryTime write SetExpiryTime; - end; - - TSessionsBase = class abstract(TInterfacedObject, ISessions) - protected - function GetSessionClass: TSessionClass; virtual; abstract; - function GetCount: Integer; virtual; abstract; - function GetItem(const AIndex: Integer): ISession; virtual; abstract; - function GetSession(const ASessionID: string): ISession; virtual; abstract; - function GetExpiryTime: Integer; virtual; abstract; - procedure SetSessionClass(const Value: TSessionClass); virtual; abstract; - procedure SetExpiryTime(const Value: Integer); virtual; abstract; - public - function GetEnumerator: TEnumerator; virtual; abstract; - - procedure BeginWrite; virtual; abstract; - procedure EndWrite; virtual; abstract; - - procedure BeginRead; virtual; abstract; - procedure EndRead; virtual; abstract; - - function NewSessionID: string; virtual; abstract; - function ExistsSession(const ASessionID: string; var ASession: ISession): Boolean; overload; virtual; abstract; - function ExistsSession(const ASessionID: string): Boolean; overload; virtual; - function AddSession(const ASessionID: string): ISession; overload; virtual; - function AddSession: ISession; overload; - procedure AddSession(const ASessionID: string; ASession: ISession); overload; virtual; abstract; - - procedure RemoveSessions(const ASessions: TArray); virtual; abstract; - procedure RemoveSession(const ASession: ISession); overload; virtual; - procedure RemoveSession(const ASessionID: string); overload; virtual; - - procedure Clear; virtual; abstract; - - property SessionClass: TSessionClass read GetSessionClass write SetSessionClass; - property Count: Integer read GetCount; - property Items[const AIndex: Integer]: ISession read GetItem; - property Sessions[const ASessionID: string]: ISession read GetSession; default; - property ExpiryTime: Integer read GetExpiryTime write SetExpiryTime; - end; - - TSessions = class(TSessionsBase) - private - FNewGUIDFunc: TFunc; - FLocker: IReadWriteLock; - FSessionClass: TSessionClass; - FExpire: Integer; - FShutdown, FExpiredProcRunning: Boolean; - - procedure _ClearExpiredSessions; - protected - FSessions: TDictionary; - - function GetSessionClass: TSessionClass; override; - function GetCount: Integer; override; - function GetItem(const AIndex: Integer): ISession; override; - function GetSession(const ASessionID: string): ISession; override; - function GetExpiryTime: Integer; override; - procedure SetSessionClass(const Value: TSessionClass); override; - procedure SetExpiryTime(const Value: Integer); override; - - procedure BeforeClearExpiredSessions; virtual; - function OnCheckExpiredSession(const ASession: ISession): Boolean; virtual; - procedure AfterClearExpiredSessions; virtual; - procedure CreateExpiredProcThread; - public - constructor Create(ANewGUIDFunc: TFunc); overload; virtual; - constructor Create; overload; virtual; - destructor Destroy; override; - - function GetEnumerator: TEnumerator; override; - - procedure BeginWrite; override; - procedure EndWrite; override; - - procedure BeginRead; override; - procedure EndRead; override; - - function NewSessionID: string; override; - function ExistsSession(const ASessionID: string; var ASession: ISession): Boolean; override; - procedure AddSession(const ASessionID: string; ASession: ISession); override; - - procedure RemoveSessions(const ASessions: TArray); override; - - procedure Clear; override; - - property NewGUIDFunc: TFunc read FNewGUIDFunc write FNewGUIDFunc; - end; - -implementation - -function _IsHttpToken(const AValue: string): Boolean; -var - I: Integer; -begin - if (AValue = '') then Exit(False); - - for I := 1 to Length(AValue) do - begin - case AValue[I] of - 'A'..'Z', 'a'..'z', '0'..'9', - '!', '#', '$', '%', '&', '''', '*', '+', '-', '.', '^', '_', '`', '|', '~': ; - else - Exit(False); - end; - end; - - Result := True; -end; - -function _IsCookieOctets(const AValue: string): Boolean; -var - I, LCode: Integer; -begin - for I := 1 to Length(AValue) do - begin - LCode := Ord(AValue[I]); - case LCode of - $21, // '!' - $23..$2B, // '#' to '+' - $2D..$3A, // '-' to ':' - $3C..$5B, // '<' to '[' - $5D..$7E: ; // ']' to '~' - else - Exit(False); - end; - end; - - Result := True; -end; - -function _IsCookieAvValue(const AValue: string): Boolean; -var - I, LCode: Integer; -begin - for I := 1 to Length(AValue) do - begin - LCode := Ord(AValue[I]); - if (LCode < $20) or (LCode >= $7F) or (AValue[I] = ';') then - Exit(False); - end; - - Result := True; -end; - -function _TryNormalizeCookieValue(const AValue: string; out ANormalizedValue: string): Boolean; -begin - ANormalizedValue := AValue; - if (Length(ANormalizedValue) >= 2) then - if (ANormalizedValue[1] = '"') - and (ANormalizedValue[High(ANormalizedValue)] = '"') then - ANormalizedValue := Copy(ANormalizedValue, 2, Length(ANormalizedValue) - 2); - - Result := _IsCookieOctets(ANormalizedValue); -end; - -function _NormalizeCookieDomain(const AValue: string): string; -begin - if not _IsCookieAvValue(AValue) then Exit(''); - - Result := AValue.Trim.ToLower; - if (Result <> '') then - if (Result[1] = '.') then - Delete(Result, 1, 1); -end; - -function _TryParseCookieMaxAge(const AValue: string; out AMaxAge: Integer): Boolean; -var - I: Integer; -begin - AMaxAge := 0; - Result := False; - if (AValue = '') then Exit; - - if (AValue[1] = '-') then - begin - if (Length(AValue) = 1) then Exit; - for I := 2 to Length(AValue) do - if not CharInSet(AValue[I], ['0'..'9']) then Exit; - end else - begin - for I := 1 to Length(AValue) do - if not CharInSet(AValue[I], ['0'..'9']) then Exit; - end; - - Result := TryStrToInt(AValue, AMaxAge); -end; - -{ TNameValue } - -constructor TNameValue.Create(const AName, - AValue: string); -begin - Name := AName; - Value := AValue; -end; - -{ TBaseParams.TEnumerator } - -constructor TBaseParams.TEnumerator.Create(const AParams: TBaseParams); -begin - FParams := AParams; - FIndex := -1; -end; - -function TBaseParams.TEnumerator.GetCurrent: TNameValue; -begin - Result := FParams.Items[FIndex]; -end; - -function TBaseParams.TEnumerator.MoveNext: Boolean; -begin - Inc(FIndex); - Result := (FIndex < FParams.Count); -end; - -{ TBaseParams } - -constructor TBaseParams.Create; -begin - FParams := TList.Create(TComparer.Construct( - function(const Left, Right: TNameValue): Integer - begin - Result := CompareText(Left.Name, Right.Name, TLocaleOptions.loUserLocale); - end)); -end; - -constructor TBaseParams.Create(const AEncodedParams: string); -begin - Create; - Decode(AEncodedParams, True); -end; - -destructor TBaseParams.Destroy; -begin - FreeAndNil(FParams); - inherited; -end; - -procedure TBaseParams.Add(const AName, AValue: string; ADupAllowed: Boolean); -begin - if ADupAllowed then - FParams.Add(TNameValue.Create(AName, AValue)) - else - SetParam(AName, AValue); -end; - -procedure TBaseParams.Add(const AEncodedParams: string); -begin - Decode(AEncodedParams, False); -end; - -procedure TBaseParams.Assign(const ASource: TBaseParams); -var - LParamItem: TNameValue; -begin - Clear; - - if (ASource = nil) or (ASource.Count <= 0) then Exit; - - for LParamItem in ASource do - Add(LParamItem); -end; - -procedure TBaseParams.Add(const AParamValue: TNameValue); -begin - FParams.Add(AParamValue); -end; - -procedure TBaseParams.Clear; -begin - FParams.Clear; -end; - -function TBaseParams.GetParamIndex(const AName: string): Integer; -var - I: Integer; -begin - for I := 0 to FParams.Count - 1 do - if TStrUtils.SameText(FParams[I].Name, AName) then Exit(I); - Result := -1; -end; - -function TBaseParams.GetParamValue(const AName: string; - out AValue: string): Boolean; -var - I: Integer; -begin - I := GetParamIndex(AName); - if (I >= 0) then - begin - AValue := FParams[I].Value; - Exit(True); - end; - - AValue := ''; - Result := False; -end; - -function TBaseParams.GetHeaderValues(const AName: string; - out AValues: TArray): Boolean; -var - I, LCount: Integer; -begin - SetLength(AValues, FParams.Count); - LCount := 0; - Result := False; - for I := 0 to FParams.Count - 1 do - begin - if not TStrUtils.SameText(FParams[I].Name, AName) then Continue; - AValues[LCount] := FParams[I].Value; - Inc(LCount); - Result := True; - end; - SetLength(AValues, LCount); -end; - -procedure TBaseParams.Remove(const AName: string); -var - I: Integer; -begin - I := GetParamIndex(AName); - if (I >= 0) then - FParams.Delete(I); -end; - -procedure TBaseParams.Remove(AIndex: Integer); -begin - FParams.Delete(AIndex); -end; - -function TBaseParams.GetCount: Integer; -begin - Result := FParams.Count; -end; - -function TBaseParams.GetEnumerator: TEnumerator; -begin - Result := TEnumerator.Create(Self); -end; - -function TBaseParams.GetItem(AIndex: Integer): TNameValue; -begin - Result := FParams.Items[AIndex]; -end; - -function TBaseParams.ExistsParam(const AName: string): Boolean; -begin - Result := (GetParamIndex(AName) >= 0); -end; - -function TBaseParams.GetParam(const AName: string): string; -var - I: Integer; -begin - I := GetParamIndex(AName); - if (I >= 0) then - Exit(FParams[I].Value); - Result := ''; -end; - -procedure TBaseParams.SetItem(AIndex: Integer; const AValue: TNameValue); -begin - FParams[AIndex] := AValue; -end; - -procedure TBaseParams.SetParam(const AName, AValue: string); -var - I: Integer; - LItem: TNameValue; -begin - I := GetParamIndex(AName); - if (I >= 0) then - begin - LItem := FParams[I]; - LItem.Value := AValue; - FParams[I] := LItem; - end else - FParams.Add(TNameValue.Create(AName, AValue)); -end; - -procedure TBaseParams.Sort(const AComparison: TNameValueComparison); -var - LComparer: INameValueComparer; -begin - if Assigned(AComparison) then - LComparer := TNameValueComparer.Create(AComparison) - else - LComparer := TNameValueComparer.Create( - function(const Left, Right: TNameValue): Integer - begin - Result := CompareStr(Left.Name, Right.Name, TLocaleOptions.loInvariantLocale); - end); - - FParams.Sort(LComparer); -end; - -{ THttpUrlParams } - -constructor THttpUrlParams.Create; -begin - inherited Create; - - // RFC 3986 / WHATWG application/x-www-form-urlencoded: - // key 与 value 内含的 reserved/非 unreserved 字符都必须 percent-encode, - // 否则 key 中的 '&'/'='/'#' 等会被服务端误解析 (参数注入风险). - // 与 Go url.Values.Encode / Python urlencode / Java URLEncoder 等主流库默认行为一致. - FEncodeName := True; - FEncodeValue := True; -end; - -function THttpUrlParams.Decode(const AEncodedParams: string; AClear: Boolean): Boolean; -var - p, pEnd, q: PChar; - LName, LValue: string; - LSize, LDecodedCount: Integer; -begin - if AClear then - FParams.Clear; - - LDecodedCount := 0; - p := PChar(AEncodedParams); - pEnd := p + Length(AEncodedParams); - while (p < pEnd) do - begin - // WHATWG application/x-www-form-urlencoded parser: 按 '&' 拆分并忽略空片段. - while (p < pEnd) and (p^ = '&') do - Inc(p); - if (p >= pEnd) then Break; - - q := p; - LSize := 0; - while (p < pEnd) and (p^ <> '=') and (p^ <> '&') do - begin - Inc(LSize); - Inc(p); - end; - SetString(LName, q, LSize); - LName := TCrossHttpUtils.UrlDecode(LName); - - if (p < pEnd) and (p^ = '=') then - begin - Inc(p); - - q := p; - LSize := 0; - while (p < pEnd) and (p^ <> '&') do - begin - Inc(LSize); - Inc(p); - end; - SetString(LValue, q, LSize); - LValue := TCrossHttpUtils.UrlDecode(LValue); - end else - begin - LValue := ''; - end; - - Add(LName, LValue, True); - Inc(LDecodedCount); - end; - - Result := (LDecodedCount > 0); -end; - -function THttpUrlParams.Encode: string; -var - I: Integer; - LName, LValue: string; -begin - Result := ''; - for I := 0 to FParams.Count - 1 do - begin - if (I > 0) then - Result := Result + '&'; - - if FEncodeName then - LName := TCrossHttpUtils.UrlEncode(FParams[I].Name) - else - LName := FParams[I].Name; - Result := Result + LName; - - if FEncodeValue then - LValue := TCrossHttpUtils.UrlEncode(FParams[I].Value) - else - LValue := FParams[I].Value; - if (LValue <> '') then - Result := Result + '=' + LValue; - end; -end; - -{ THttpHeader } - -function THttpHeader.Decode(const AEncodedParams: string; AClear: Boolean): Boolean; -const - CR = #13; - LF = #10; -var - P, PEnd, LLineStart, LColonPos, LValueStart, LValueEnd: PChar; - LCh: Char; - LName, LValue: string; - LLineValid, LInName: Boolean; - LDecodedCount: Integer; -begin - if AClear then - FParams.Clear; - - LDecodedCount := 0; - P := PChar(AEncodedParams); - PEnd := P + Length(AEncodedParams); - - // 单趟状态机解析 (RFC 7230 §3): 每行字符仅访问 1 次, 同时完成 - // 1) CRLF 边界检测: bare-CR / bare-LF 立即拒绝 (Exit(False)), - // 防御 \r\r\n\n 等走私序列及上下游切分不一致 - // 2) ':' 定位 (切 name / value) - // 3) value 前后 OWS 跳过 + 尾随 OWS 自动 trim - // 4) name 每字节 token 校验 + value 每字节 CTL 校验 - // 非法行整行跳过 (仅限 name/value 校验失败, 不含 bare-CR/LF), - // 与 THttpHeader.Encode 过滤策略对称, 作为深度防御. - while (P < PEnd) do - begin - LLineStart := P; - LColonPos := nil; - LValueStart := nil; - LValueEnd := nil; - LLineValid := True; - LInName := True; - - // 内层: 逐字节扫描本行, 直到 CRLF 或 PEnd - while (P < PEnd) do - begin - LCh := P^; - - if (LCh = CR) then - begin - if (P + 1 < PEnd) and ((P + 1)^ = LF) then - Break; // 完整 CRLF: 退出内层, P 仍指向 CR - // bare-CR: 立即拒绝, 防御 \r\r\n\n 等走私序列 - if AClear then FParams.Clear; - Exit(False); - end; - - if (LCh = LF) then - begin - // bare-LF: 立即拒绝 - if AClear then FParams.Clear; - Exit(False); - end; - - if LInName then - begin - if (LCh = ':') then - begin - LColonPos := P; - LInName := False; - end else - if not TCrossHttpUtils.IsTokenChar(LCh) then - // name 段非 token 字符 (含 OWS / CTL / 非 ASCII 等) → 非法 - LLineValid := False; - end else - begin - // value 段: 前导 OWS 跳过, 记录首/末非 OWS 位置, 同时校验 CTL - if (LCh <> ' ') and (LCh <> #9) then - begin - if (LValueStart = nil) then - LValueStart := P; - LValueEnd := P + 1; // exclusive: 最后非 OWS 字符之后位置 - if not TCrossHttpUtils.IsHeaderValueChar(LCh) then - LLineValid := False; - end; - end; - - Inc(P); - end; - - // 退出内层: P 指向 CR (CRLF 完整) 或 P >= PEnd (末尾无 CRLF). - // 末尾无 CRLF 的残行也按相同规则尝试入库, 兼容 multipart part header - // 等调用方剥掉块终止符 \r\n\r\n 后再喂入的字符串. 主路径 HTTP - // request/response header 末尾必带空行 \r\n, 始终走 CRLF 完整分支, - // 严格性不变. - if (P < PEnd) then - Inc(P, 2); // 跳过 CRLF; PEnd 路径 P 已等于 PEnd, 外层 while 自然退出 - - if not LLineValid then Continue; - - // 空行: header 块结束标记, 跳过. - // CRLF 完整路径: LLineStart 指向被消费 CRLF 的位置 (即 P - 2) - // PEnd 路径 : LLineStart 等于 P (本行 0 字节) - if (LLineStart = P) or (LLineStart = P - 2) then Continue; - - // 必须出现过 ':' - if (LColonPos = nil) then Continue; - - // name 不能为空 - if (LColonPos = LLineStart) then Continue; - - SetString(LName, LLineStart, LColonPos - LLineStart); - - if (LValueStart = nil) then - LValue := '' - else - SetString(LValue, LValueStart, LValueEnd - LValueStart); - - Add(LName, LValue, True); - Inc(LDecodedCount); - end; - - Result := (LDecodedCount > 0); -end; - -function THttpHeader.Encode: string; -var - I: Integer; - LName, LValue: string; -begin - // 防御 HTTP 响应拆分 (Response Splitting): - // Header name 必须是 RFC 7230 token, value 不允许 CR/LF/CTL. - // 非法 entry 直接跳过 (业务方应在写入前自行 sanitize), 避免拼到 wire 上注入伪造响应. - Result := ''; - for I := 0 to FParams.Count - 1 do - begin - LName := FParams[I].Name; - LValue := FParams[I].Value; - - if not TCrossHttpUtils.IsValidHeaderName(LName) then Continue; - if not TCrossHttpUtils.IsValidHeaderValue(LValue) then Continue; - - Result := Result + LName + ': ' + LValue + #13#10; - end; - Result := Result + #13#10; -end; - -{ TDelimitParams } - -constructor TDelimitParams.Create(const ADelimiter: Char; const AUrlEncode: Boolean); -begin - FDelimiter := ADelimiter; - FUrlEncode := AUrlEncode; - - inherited Create; -end; - -constructor TDelimitParams.Create(const AEncodedParams: string; - const ADelimiter: Char; const AUrlEncode: Boolean); -begin - FDelimiter := ADelimiter; - FUrlEncode := AUrlEncode; - - inherited Create(AEncodedParams); -end; - -function TDelimitParams.Decode(const AEncodedParams: string; AClear: Boolean): Boolean; -var - p, pEnd, q: PChar; - LName, LValue: string; - LSize, LDecodedCount: Integer; -begin - if AClear then - FParams.Clear; - - LDecodedCount := 0; - p := PChar(AEncodedParams); - pEnd := p + Length(AEncodedParams); - while (p < pEnd) do - begin - q := p; - LSize := 0; - while (p < pEnd) and (p^ <> '=') do - begin - Inc(LSize); - Inc(p); - end; - SetString(LName, q, LSize); - // 跳过多余的'=' - while (p < pEnd) and (p^ = '=') do - Inc(p); - - q := p; - LSize := 0; - while (p < pEnd) and (p^ <> FDelimiter) do - begin - Inc(LSize); - Inc(p); - end; - SetString(LValue, q, LSize); - if FUrlEncode then - LValue := TCrossHttpUtils.UrlDecode(LValue); - // 跳过多余的';' - while (p < pEnd) and ((p^ = FDelimiter) or (p^ = ' ')) do - Inc(p); - - Add(LName, LValue); - Inc(LDecodedCount); - end; - - Result := (LDecodedCount > 0); -end; - -function TDelimitParams.Encode: string; -var - I: Integer; - LValue: string; -begin - Result := ''; - for I := 0 to FParams.Count - 1 do - begin - if (I > 0) then - Result := Result + FDelimiter + ' '; - LValue := FParams[I].Value; - if FUrlEncode then - LValue := TCrossHttpUtils.UrlEncode(LValue); - Result := Result + FParams[I].Name + '=' + LValue; - end; -end; - -{ TRequestCookies } - -function TRequestCookies.Decode(const AEncodedParams: string; AClear: Boolean): Boolean; -var - LParsedParams: TList; - LItem: TNameValue; - LPos, LLen, LPairEnd, LEqualsPos, LDecodedCount: Integer; - LPair: string; - LName, LValue: string; - LNormalizedValue: string; -begin - LDecodedCount := 0; - Result := False; - // 先解析到临时列表,确保整行 Cookie 全部合法后再提交,避免失败时留下半解析数据。 - LParsedParams := TList.Create; - try - LLen := Length(AEncodedParams); - LPos := 1; - while (LPos <= LLen) do - begin - // 跳过空白字符(空格和制表符) - while (LPos <= LLen) and CharInSet(AEncodedParams[LPos], [' ', #9]) do - Inc(LPos); - if (LPos > LLen) then Break; - - LPairEnd := LPos; - // 查找分号分隔符, 确定当前 cookie-pair 的结束位置 - while (LPairEnd <= LLen) and (AEncodedParams[LPairEnd] <> ';') do - Inc(LPairEnd); - - // 提取当前 cookie-pair 字符串 - LPair := Copy(AEncodedParams, LPos, LPairEnd - LPos); - // 查找等号位置, 用于分割 name 和 value - LEqualsPos := Pos('=', LPair); - // 如果没有等号或等号在第一个位置(name 为空), 则认为格式非法 - if (LEqualsPos <= 1) then - begin - if AClear then FParams.Clear; - Exit; - end; - - // 提取 name 部分(等号之前的内容) - LName := Copy(LPair, 1, LEqualsPos - 1); - // 提取 value 部分(等号之后的所有内容) - LValue := Copy(LPair, LEqualsPos + 1, MaxInt); - // 校验 name 是否为合法的 HTTP token, 以及 value 是否为合法的 cookie 值 - if not _IsHttpToken(LName) - or not _TryNormalizeCookieValue(LValue, LNormalizedValue) then - begin - if AClear then FParams.Clear; - Exit; - end; - - LParsedParams.Add(TNameValue.Create(LName, LNormalizedValue)); - LPos := LPairEnd + 1; - Inc(LDecodedCount); - end; - - // 所有 cookie-pair 均校验通过后,才按 AClear 语义提交到 FParams。 - if AClear then - FParams.Clear; - for LItem in LParsedParams do - Add(LItem.Name, LItem.Value); - Result := (LDecodedCount > 0); - finally - FreeAndNil(LParsedParams); - end; -end; - -function TRequestCookies.Encode: string; -var - I: Integer; - LName, LValue: string; -begin - Result := ''; - for I := 0 to FParams.Count - 1 do - begin - if (I > 0) then - Result := Result + '; '; - LName := FParams[I].Name; - LValue := FParams[I].Value; - if not _IsHttpToken(LName) then - raise Exception.CreateFmt('Invalid cookie name: %s', [LName]); - if not _IsCookieOctets(LValue) then - raise Exception.CreateFmt('Invalid cookie value: %s', [LName]); - Result := Result + LName + '=' + LValue; - end; -end; - -{ TResponseCookie } - -constructor TResponseCookie.Create(const AName, AValue: string; - AMaxAge: Integer; const APath, ADomain: string; AHttpOnly, ASecure: Boolean); -begin - Self.Name := AName; - Self.Value := AValue; - Self.MaxAge := AMaxAge; - Self.Path := APath; - Self.Domain := _NormalizeCookieDomain(ADomain); - Self.HttpOnly := AHttpOnly; - Self.Secure := ASecure; -end; - -constructor TResponseCookie.Create(const ACookieData, ADomain: string); - - procedure SetExpires(const AValue: string); - var - LMaxAge: Integer; - begin - if (Self.MaxAge = 0) then - begin - LMaxAge := TCrossHttpUtils.RFC1123_StrToDate(AValue).SecondsDiffer(Now); - if (LMaxAge > 0) then - Self.MaxAge := LMaxAge; - end; - end; - - procedure SetMaxAge(const AValue: string); - var - LMaxAge: Integer; - begin - if _TryParseCookieMaxAge(AValue, LMaxAge) then - Self.MaxAge := LMaxAge; - end; - - procedure SetPath(const AValue: string); - begin - if (AValue <> '') and (AValue[1] = '/') and _IsCookieAvValue(AValue) then - Self.Path := AValue; - end; - - procedure SetDomain(const AValue: string); - var - LDomain: string; - begin - LDomain := _NormalizeCookieDomain(AValue); - if (LDomain <> '') then - Self.Domain := LDomain; - end; - -var - LValues: TArray; - I: Integer; - LPos: Integer; - LName: string; - LValue: string; -begin - Self.Name := ''; - Self.Value := ''; - Self.MaxAge := 0; - Self.Path := '/'; - Self.Domain := _NormalizeCookieDomain(ADomain); - Self.HttpOnly := False; - Self.Secure := False; - - LValues := ACookieData.Split([Char(';')], Char('"')); - if Length(LValues) = 0 then Exit; - - LPos := LValues[0].IndexOf(Char('=')); - if (LPos <= 0) then Exit; - - Self.Name := LValues[0].Substring(0, LPos).Trim; - if not _IsHttpToken(Self.Name) - or not _TryNormalizeCookieValue(LValues[0].Substring(LPos + 1).Trim, Self.Value) then - begin - Self.Name := ''; - Self.Value := ''; - Exit; - end; - - for I := 1 to High(LValues) do - begin - LPos := LValues[I].IndexOf(Char('=')); - if LPos > 0 then - begin - LName := LValues[I].Substring(0, LPos).Trim; - LValue := LValues[I].Substring(LPos + 1).Trim; - if (LValue.Length > 1) and (LValue.Chars[0] = '"') and (LValue[High(LValue)] = '"') then - LValue := LValue.Substring(1, LValue.Length - 2); - end - else - begin - LName := LValues[I].Trim; - LValue := ''; - end; - - if TStrUtils.SameText(LName, 'Max-Age') then - SetMaxAge(LValue) - else if TStrUtils.SameText(LName, 'Expires') then - SetExpires(LValue) - else if TStrUtils.SameText(LName, 'Path') then - SetPath(LValue) - else if TStrUtils.SameText(LName, 'Domain') then - SetDomain(LValue) - else if TStrUtils.SameText(LName, 'HttpOnly') then - Self.HttpOnly := True - else if TStrUtils.SameText(LName, 'Secure') then - Self.Secure := True; - end; -end; - -function TResponseCookie.Encode: string; -begin - if not _IsHttpToken(Self.Name) then - raise Exception.CreateFmt('Invalid cookie name: %s', [Self.Name]); - if not _IsCookieOctets(Self.Value) then - raise Exception.CreateFmt('Invalid cookie value: %s', [Self.Value]); - if not _IsCookieAvValue(Self.Path) then - raise Exception.CreateFmt('Invalid cookie path: %s', [Self.Name]); - if (Self.Path <> '') and (Self.Path[1] <> '/') then - raise Exception.CreateFmt('Invalid cookie path: %s', [Self.Name]); - if not _IsCookieAvValue(Self.Domain) then - raise Exception.CreateFmt('Invalid cookie domain: %s', [Self.Name]); - - Result := Self.Name + '=' + Self.Value; - - if (Self.MaxAge > 0) then - Result := Result + '; Max-Age=' + Self.MaxAge.ToString; - if (Self.Path <> '') then - Result := Result + '; Path=' + Self.Path; - if (Self.Domain <> '') then - Result := Result + '; Domain=' + Self.Domain; - if Self.HttpOnly then - Result := Result + '; HttpOnly'; - if Self.Secure then - Result := Result + '; Secure'; -end; - -{ TFormField } - -constructor TFormField.Create; -begin - FValueOwned := True; -end; - -destructor TFormField.Destroy; -begin - FreeValue; - - inherited; -end; - -procedure TFormField.FreeValue; -begin - if FValueOwned and Assigned(FValue) then - FreeAndNil(FValue); -end; - -function TFormField.AsBytes: TBytes; -var - LBufSize: Integer; -begin - if (FValue = nil) or (FValue.Size <= 0) then Exit(nil); - - if (FValue is TBytesStream) then - begin - Result := TBytesStream(FValue).Bytes; - SetLength(Result, FValue.Size); - end else - begin - FValue.Position := 0; - LBufSize := FValue.Size; - SetLength(Result, LBufSize); - FValue.ReadBuffer(Result, LBufSize); - end; -end; - -procedure TFormField.Assign(const ASource: TFormField); -begin - FreeValue; - - if (ASource = nil) then Exit; - - FName := ASource.FName; - FValueOwned := ASource.FValueOwned; - FIsTempFile := ASource.FIsTempFile; - FFileName := ASource.FFileName; - FFilePath := ASource.FFilePath; - FContentType := ASource.FContentType; - FContentTransferEncoding := ASource.FContentTransferEncoding; - - if ASource.FValueOwned then - begin - if (FFilePath <> '') then - FValue := TFileUtils.OpenRead(FFilePath, fmShareDenyNone) - else - begin - FValue := TBytesStream.Create; - FValue.CopyFrom(ASource.FValue, 0); - end; - end else - begin - FValue := ASource.FValue; - end; -end; - -function TFormField.AsString(AEncoding: TEncoding): string; -begin - Result := TUtils.GetString(FValue, AEncoding); -end; - -{ THttpMultiPartFormData.TEnumerator } - -constructor THttpMultiPartFormData.TEnumerator.Create( - const AList: TList); -begin - inherited Create; - FList := AList; - FIndex := -1; -end; - -function THttpMultiPartFormData.TEnumerator.GetCurrent: TFormField; -begin - Result := FList[FIndex]; -end; - -function THttpMultiPartFormData.TEnumerator.MoveNext: Boolean; -begin - Inc(FIndex); - Result := (FIndex < FList.Count); -end; - -{ THttpMultiPartFormData } - -constructor THttpMultiPartFormData.Create; -begin - FDecodeState := dsBoundary; - SetLength(FCurrentPartHeader, MAX_PART_HEADER); - FCurrentPartHeaderLen := 0; - FPartFields := TObjectList.Create(True); - FAutoDeleteFiles := True; - FMaxPartDataSize := 0; - FCurrentPartDataSize := 0; -end; - -function THttpMultiPartFormData.Decode( - const AStream: TStream): TFormDataDecodeResult; -const - BUF_SIZE = 1024 * 32; -var - LBuffer: array [0..BUF_SIZE - 1] of Byte; - N: Integer; -begin - while True do - begin - N := AStream.Read(LBuffer[0], BUF_SIZE); - Result := Decode(@LBuffer[0], N); - - if (Result in [frComplete, frFailed]) - or (N < BUF_SIZE) then Exit; - end; -end; - -destructor THttpMultiPartFormData.Destroy; -begin - Clear; - FCurrentPartHeader := nil; - FCurrentPartField := nil; - FreeAndNil(FPartFields); - inherited; -end; - -function THttpMultiPartFormData.AddField(const AField: TFormField): TFormField; -begin - FPartFields.Add(AField); - Result := AField; -end; - -function THttpMultiPartFormData.AddField(const AFieldName: string; - const AValue: TBytes): TFormField; -begin - Result := TFormField.Create; - Result.FName := AFieldName; - Result.FValueOwned := True; - Result.FValue := TBytesStream.Create(AValue); - Result.FContentType := TMediaType.APPLICATION_OCTET_STREAM; - - FPartFields.Add(Result); -end; - -function THttpMultiPartFormData.AddField(const AFieldName, AValue: string): TFormField; -begin - Result := TFormField.Create; - Result.FName := AFieldName; - Result.FValueOwned := True; - Result.FValue := TBytesStream.Create(TEncoding.UTF8.GetBytes(AValue)); - - FPartFields.Add(Result); -end; - -function THttpMultiPartFormData.AddFile(const AFieldName, AFileName: string; - const AStream: TStream; const AOwned: Boolean): TFormField; -begin - Result := TFormField.Create; - Result.FName := AFieldName; - Result.FFileName := AFileName; - Result.FValueOwned := AOwned; - Result.FValue := AStream; - Result.FContentType := TCrossHttpUtils.GetFileMIMEType(AFileName); - - FPartFields.Add(Result); -end; - -function THttpMultiPartFormData.AddFile(const AFieldName, AFileName: string): TFormField; -begin - Result := AddFile(AFieldName, - ExtractFileName(AFileName), - TFileUtils.OpenRead(AFileName, fmShareDenyNone), - True); - Result.FFilePath := AFileName; -end; - -procedure THttpMultiPartFormData.Assign(const ASource: THttpMultiPartFormData); -var - LSrcField, LNewField: TFormField; -begin - Clear; - - Boundary := ASource.Boundary; - - for LSrcField in ASource do - begin - LNewField := TFormField.Create; - LNewField.Assign(LSrcField); - - AddField(LNewField); - end; -end; - -function THttpMultiPartFormData.AsBytes(const AFieldName: string; - out AValue: TBytes): Boolean; -var - LField: TFormField; -begin - Result := FindField(AFieldName, LField); - if Result then - AValue := LField.AsBytes - else - AValue := nil; -end; - -function THttpMultiPartFormData.AsBytes(const AFieldName: string): TBytes; -begin - AsBytes(AFieldName, Result); -end; - -function THttpMultiPartFormData.AsStream(const AFieldName: string; - out AValue: TStream): Boolean; -var - LField: TFormField; -begin - Result := FindField(AFieldName, LField); - if Result then - begin - AValue := LField.Value; - if (AValue.Size > 0) then - AValue.Position := 0; - end else - AValue := nil; -end; - -function THttpMultiPartFormData.AsStream(const AFieldName: string): TStream; -begin - AsStream(AFieldName, Result); -end; - -function THttpMultiPartFormData.AsString(const AFieldName: string; - const AEncoding: TEncoding; out AValue: string): Boolean; -var - LField: TFormField; -begin - Result := FindField(AFieldName, LField); - if Result then - AValue := LField.AsString(AEncoding) - else - AValue := ''; -end; - -function THttpMultiPartFormData.AsString(const AFieldName: string; - out AValue: string): Boolean; -begin - Result := AsString(AFieldName, nil, AValue); -end; - -function THttpMultiPartFormData.AsString(const AFieldName: string; - const AEncoding: TEncoding): string; -begin - AsString(AFieldName, AEncoding, Result); -end; - -procedure THttpMultiPartFormData.Clear; -var - LField: TFormField; -begin - for LField in FPartFields do - begin - if FAutoDeleteFiles and (LField.FilePath <> '') - and FileExists(LField.FilePath) then - begin - LField.FreeValue; - - if LField.FIsTempFile then - DeleteFile(LField.FilePath); - end; - end; - - FPartFields.Clear; -end; - -function THttpMultiPartFormData.FindField(const AFieldName: string; - out AField: TFormField): Boolean; -var - I: Integer; -begin - I := GetItemIndex(AFieldName); - if (I >= 0) then - begin - AField := FPartFields[I]; - Exit(True); - end; - - AField := nil; - Result := False; -end; - -function THttpMultiPartFormData.GetItem(AIndex: Integer): TFormField; -begin - Result := FPartFields.Items[AIndex]; -end; - -function THttpMultiPartFormData.GetItemIndex(const AName: string): Integer; -var - I: Integer; -begin - for I := 0 to FPartFields.Count - 1 do - if TStrUtils.SameText(FPartFields[I].Name, AName) then Exit(I); - Result := -1; -end; - -function THttpMultiPartFormData.GetCount: Integer; -begin - Result := FPartFields.Count; -end; - -function THttpMultiPartFormData.GetDataSize: Integer; -var - LPartField: TFormField; -begin - Result := 0; - for LPartField in FPartFields do - Inc(Result, LPartField.FValue.Size); -end; - -function THttpMultiPartFormData.GetEnumerator: TEnumerator; -begin - Result := TEnumerator.Create(FPartFields); -end; - -function THttpMultiPartFormData.GetField(const AName: string): TFormField; -var - I: Integer; -begin - I := GetItemIndex(AName); - if (I >= 0) then - Exit(FPartFields[I]); - Result := nil; -end; - -procedure THttpMultiPartFormData.InitWithBoundary(const ABoundary: string); -begin - // Decode 返回 frFailed 后, 调用方应调用 InitWithBoundary 重用实例; - // Clear 会根据 AutoDeleteFiles 清理半解析的临时文件. - Clear; - - SetBoundary(ABoundary); - - FDecodeState := dsBoundary; - FBoundaryIndex := 0; - FPrevBoundaryIndex := 0; - FCurrentPartDataSize := 0; - FCurrentPartHeaderLen := 0; - FCurrentPartField := nil; - SetLength(FLookbehind, Length(FBoundaryBytes) + 8); -end; - -procedure THttpMultiPartFormData.Remove(AIndex: Integer); -begin - FPartFields.Delete(AIndex); -end; - -procedure THttpMultiPartFormData.Remove(const AFieldName: string); -var - I: Integer; -begin - I := GetItemIndex(AFieldName); - if (I >= 0) then - FPartFields.Delete(I); -end; - -procedure THttpMultiPartFormData.SetBoundary(const AValue: string); -begin - if (FBoundary <> AValue) then - begin - FBoundary := AValue; - FBoundary := FBoundary.Trim(['"']); - - // 第一块数据是紧跟着 HTTP HEADER 的, 前面没有多余的 #13#10 - FFirstBoundaryBytes := TEncoding.ASCII.GetBytes('--' + FBoundary); - - // 第二块及以后的数据 Boundary 前面都会有 #13#10 - FBoundaryBytes := TArrayUtils.Concat([13, 10], FFirstBoundaryBytes); - end; -end; - -function THttpMultiPartFormData.Decode(const ABuf: Pointer; ALen: Integer; out AConsumed: Integer): TFormDataDecodeResult; - function __NewFileID: string; - begin - Result := TUtils.GetGUID.ToLower; - end; - - function __InitFormFieldByHeader(AFormField: TFormField; const AHeader: string): Boolean; - var - LFieldHeader: THttpHeader; - LContentDisposition: string; - LMatch: TMatch; - begin - Result := False; - - LFieldHeader := THttpHeader.Create; - try - LFieldHeader.Decode(AHeader); - LContentDisposition := LFieldHeader['Content-Disposition']; - if (LContentDisposition = '') then Exit; - - AFormField.FContentType := LFieldHeader['Content-Type']; - - LMatch := TRegEx.Match(LContentDisposition, '\bname="(.*?)"(?=;|$)', [TRegExOption.roIgnoreCase]); - if LMatch.Success then - AFormField.FName := LMatch.Groups[1].Value; - - // 使用 Content-Type 来判断是否需要按文件保存更为准确 - // 前端通过流的方式提交, 可能不会传递 filename 属性, - // 这种情况收到的 AHeader 是这样的: - // Content-Disposition: form-data; name="test_content" - // Content-Type: application/octet-stream - // 这种数据也可以当成文件来储存, 随机给它分配一个文件名即可 - // 而普通的文本数据是不会有 Content-Type 的: - // Content-Disposition: form-data; name="test_text" - if (AFormField.FContentType <> '') then - begin - LMatch := TRegEx.Match(LContentDisposition, '\bfilename="(.*?)"(?=;|$)', [TRegExOption.roIgnoreCase]); - // 带 filename 属性的头: - // Content-Disposition: form-data; name="content"; filename="test.json" - // Content-Type: application/json - if LMatch.Success then - begin - AFormField.FFileName := TPathUtils.GetFileName(LMatch.Groups[1].Value); - AFormField.FFilePath := TPathUtils.Combine(FStoragePath, - __NewFileID + TPathUtils.GetExtension(AFormField.FFileName)); - end else - begin - AFormField.FFileName := __NewFileID + '.bin'; - AFormField.FFilePath := TPathUtils.Combine(FStoragePath, - AFormField.FFileName); - end; - - AFormField.FIsTempFile := True; - AFormField.FValue := TFileUtils.OpenCreate(AFormField.FFilePath); - end else - AFormField.FValue := TBytesStream.Create(nil); - - AFormField.FValueOwned := True; - // 注意: Content-Transfer-Encoding (base64/quoted-printable) 仅存储不解码, - // dsPartData 阶段总是按原始字节写入, 如需支持非二进制传输编码需在此增加解码层. - AFormField.FContentTransferEncoding := LFieldHeader['Content-Transfer-Encoding']; - finally - FreeAndNil(LFieldHeader); - end; - - Result := True; - end; -var - C: Byte; - I, LSize: Integer; - P: PByte; - LPartHeader: string; -begin - AConsumed := 0; - if (FBoundaryBytes = nil) then Exit(frFailed); - - (* - *************************************** - ***** multipart/form-data数据格式 ***** - *************************************** - - # 请求头, 这个是必须的, 需要指定Content-Type为multipart/form-data, 指定唯一边界值 - Content-Type: multipart/form-data; boundary=${Boundary} - - # 请求体 - --${Boundary} - Content-Disposition: form-data; name="name of file" - Content-Type: application/octet-stream - - bytes of file - --${Boundary} - Content-Disposition: form-data; name="name of pdf"; filename="pdf-file.pdf" - Content-Type: application/octet-stream - - bytes of pdf file - --${Boundary} - Content-Disposition: form-data; name="key" - Content-Type: text/plain;charset=UTF-8 - - text encoded in UTF-8 - --${Boundary}-- - *) - - P := ABuf; - I := 0; - while (I < ALen) do - begin - C := P[I]; - case FDecodeState of - // 检测Boundary, 以确定第一块数据 - dsBoundary: - begin - // 第一块数据是紧跟着 HTTP HEADER 的, 前面没有多余的 #13#10 - // 所以这里检测时要跳过 2 个字节 - if (C = FFirstBoundaryBytes[FBoundaryIndex]) then - Inc(FBoundaryIndex) - else - FBoundaryIndex := 0; - // --Boundary - if (FBoundaryIndex >= Length(FFirstBoundaryBytes)) then - begin - FDecodeState := dsDetect; - FLineEndState := lesCR1; - FBoundaryIndex := 0; - FPostBoundaryState := pbsDetect; - end; - end; - - // 已通过Boundary检测, 继续检测以确定后面有数据还是已到结束 - dsDetect: - begin - // 严格匹配 #13#10 (Header) 或 --#13#10 (End), 拒绝其他任何字节 - case FPostBoundaryState of - pbsDetect: - if (C = 45) then // '-' - FPostBoundaryState := pbsEnd1 - else if (C = 13) then // '\r' - FPostBoundaryState := pbsHeader1 - else if (C = 32) or (C = 9) then // RFC 2046 LWSP - { stay in pbsDetect } - else - begin - AConsumed := I + 1; - Exit(frFailed); - end; - pbsEnd1: - if (C = 45) then // '-' - FPostBoundaryState := pbsEnd2 - else - begin - AConsumed := I + 1; - Exit(frFailed); - end; - pbsEnd2: - if (C = 13) then // '\r' - FPostBoundaryState := pbsEnd3 - else - begin - AConsumed := I + 1; - Exit(frFailed); - end; - pbsEnd3: - if (C = 10) then // '\n' → --Boundary--#13#10 - begin - FDecodeState := dsBoundary; - FLineEndState := lesCR1; - FBoundaryIndex := 0; - FPostBoundaryState := pbsDetect; - AConsumed := I + 1; - Exit(frComplete); - end else - begin - AConsumed := I + 1; - Exit(frFailed); - end; - pbsHeader1: - if (C = 10) then // '\n' → --Boundary#13#10 - begin - FCurrentPartHeaderLen := 0; - FDecodeState := dsPartHeader; - FLineEndState := lesCR1; - FBoundaryIndex := 0; - FPostBoundaryState := pbsDetect; - end else - begin - AConsumed := I + 1; - Exit(frFailed); - end; - end; - end; - - dsPartHeader: - begin - FCurrentPartHeader[FCurrentPartHeaderLen] := C; - Inc(FCurrentPartHeaderLen); - - // 状态机严格匹配 #13#10#13#10 序列 - case FLineEndState of - lesCR1: if (C = 13) then FLineEndState := lesLF1; - lesLF1: - if (C = 10) then FLineEndState := lesCR2 - else if (C <> 13) then FLineEndState := lesCR1; - lesCR2: - if (C = 13) then FLineEndState := lesLF2 - else FLineEndState := lesCR1; - lesLF2: - if (C = 10) then - begin - FLineEndState := lesCR1; - // 块头部结束 #13#10#13#10 - // 块头部通常采用UTF8编码 - LPartHeader := TUtils.GetString(@FCurrentPartHeader[0], FCurrentPartHeaderLen - 4{#13#10#13#10}); - FCurrentPartHeaderLen := 0; - FCurrentPartField := TFormField.Create; - if not __InitFormFieldByHeader(FCurrentPartField, LPartHeader) then - begin - FreeAndNil(FCurrentPartField); - AConsumed := I + 1; - Exit(frFailed); - end; - FPartFields.Add(FCurrentPartField); - - FDecodeState := dsPartData; - FPartDataBegin := -1; - FBoundaryIndex := 0; - FPrevBoundaryIndex := 0; - FCurrentPartDataSize := 0; - end else - if (C = 13) then FLineEndState := lesLF1 - else FLineEndState := lesCR1; - end; - - // 块头部过大, 视为非法数据 - if (FCurrentPartHeaderLen > MAX_PART_HEADER) then - begin - AConsumed := I + 1; - Exit(frFailed); - end; - end; - - dsPartData: - begin - // 如果这是一个新的数据块, 需要保存数据块起始位置 - if (FPartDataBegin < 0) then - FPartDataBegin := I; - - // 检测Boundary - if (C = FBoundaryBytes[FBoundaryIndex]) then - begin - Inc(FBoundaryIndex); - - if (FPrevBoundaryIndex > 0) then - begin - FLookbehind[FPrevBoundaryIndex] := C; - Inc(FPrevBoundaryIndex); - end; - end else - begin - // 上一个内存块结尾有部分有点像Boundary的数据, - // 进一步判断之后确定不是Boundary, 需要把这部分数据写入Field中 - if (FPrevBoundaryIndex > 0) then - begin - FCurrentPartField.FValue.Write(FLookbehind[0], FPrevBoundaryIndex); - Inc(FCurrentPartDataSize, FPrevBoundaryIndex); - // 检查单 Part Body 大小是否超限 (与块结尾检查对称) - if (FMaxPartDataSize > 0) and (FCurrentPartDataSize > FMaxPartDataSize) then - begin - AConsumed := I + 1; - Exit(frFailed); - end; - FPrevBoundaryIndex := 0; - FPartDataBegin := I; - end; - - if (FBoundaryIndex > 0) then - begin - // 之前检测到有一部分数据跟Boundary有点像, 但是到这个字节可以确定之前 - // 这部分数据并不是Boundary, 需要把这部分数据写入Field中 - FCurrentPartField.FValue.Write(P[FPartDataBegin], I - FPartDataBegin); - Inc(FCurrentPartDataSize, I - FPartDataBegin); - FPartDataBegin := I; - - FBoundaryIndex := 0; - - // 再次检测Boundary - if (C = FBoundaryBytes[FBoundaryIndex]) then - Inc(FBoundaryIndex); - end; - end; - - // 如果已到内存块结束或者已经解析出一个完整的数据块 - if (I >= ALen - 1) or (FBoundaryIndex >= Length(FBoundaryBytes)) then - begin - // 将内存块数据存入Field中 - if (FPartDataBegin >= 0) then - begin - LSize := I - FPartDataBegin - FBoundaryIndex + 1; - if (LSize > 0) then - begin - FCurrentPartField.FValue.Write(P[FPartDataBegin], LSize); - Inc(FCurrentPartDataSize, LSize); - end; - end; - - // 检查单 Part Body 大小是否超限 (必须在状态切换前检查) - if (FMaxPartDataSize > 0) and (FCurrentPartDataSize > FMaxPartDataSize) then - begin - AConsumed := I + 1; - Exit(frFailed); - end; - - // 已解析出一个完整的数据块 - if (FBoundaryIndex >= Length(FBoundaryBytes)) then - begin - FCurrentPartField.FValue.Position := 0; - FDecodeState := dsDetect; - FBoundaryIndex := 0; - FPrevBoundaryIndex := 0; - FCurrentPartDataSize := 0; - end else - // 已解析到本内存块结尾, 但是发现了部分有点像Boundary的数据 - // 将其保存起来 - if (FPrevBoundaryIndex = 0) and (FBoundaryIndex > 0) then - begin - FPrevBoundaryIndex := FBoundaryIndex; - Move(P[I - FBoundaryIndex + 1], FLookbehind[0], FBoundaryIndex); - end; - - // 数据块起始位置需要在之后决定 - FPartDataBegin := -1; - end; - end; - end; - - Inc(I); - end; - - AConsumed := ALen; - Result := frContinue; -end; - -function THttpMultiPartFormData.Decode(const ABuf: Pointer; ALen: Integer): TFormDataDecodeResult; -var - LDummy: Integer; -begin - // 兼容旧调用方: 丢弃 consumed; 仅在调用方明确知道 multipart 数据帧严格对齐时使用. - Result := Decode(ABuf, ALen, LDummy); -end; - -{ THttpMultiPartFormStream.TFormFieldEx } - -function THttpMultiPartFormStream.TFormFieldEx.DataSize: Int64; -begin - if (Field <> nil) and (Field.Value <> nil) then - Result := Field.Value.Size - else - Result := 0; -end; - -function THttpMultiPartFormStream.TFormFieldEx.HeaderSize: Integer; -begin - Result := Length(Header); -end; - -function THttpMultiPartFormStream.TFormFieldEx.TotalSize: Int64; -begin - Result := HeaderSize + DataSize; -end; - -{ THttpMultiPartFormStream } - -constructor THttpMultiPartFormStream.Create( - const AMultiPartFormData: THttpMultiPartFormData; const AOwned: Boolean); -begin - FMultiPartFormData := AMultiPartFormData; - FOwned := AOwned; - - _Init; -end; - -destructor THttpMultiPartFormStream.Destroy; -begin - if FOwned and (FMultiPartFormData <> nil) then - FreeAndNil(FMultiPartFormData); - - inherited; -end; - -function THttpMultiPartFormStream.Read(var ABuffer; ACount: Longint): Longint; -var - LReadCount, LPos, LHeaderPos, LDataPos, LCount, LHeaderCount, LDataCount, LEndPos, LEndCount: Int64; - LFieldIndex: Integer; - LFieldEx: TFormFieldEx; - P: PByte; -begin - Result := 0; - if (FPosition < 0) or (FPosition >= FSize) or (ACount <= 0) then Exit; - - // 计算实际还能读取多少字节数据 - if (ACount + FPosition <= FSize) then - LReadCount := ACount - else - LReadCount := FSize - FPosition; - - Result := LReadCount; - - P := @ABuffer; - - {$region '从 Field 中读取数据'} - while (LReadCount > 0) do - begin - LFieldIndex := _GetFiledIndexByOffset(FPosition); - if (LFieldIndex < 0) then Break; - - LFieldEx := FFormFieldExArray[LFieldIndex]; - - // 计算要读取的数据位于这个 Field 的偏移 - LPos := FPosition - LFieldEx.Offset; - - // 计算需要从这个 Field 中读取多少字节 - LCount := Min(LFieldEx.TotalSize - LPos, LReadCount); - - // 计算分别需要从 Header 和 Data 中读取多少字节 - if (LPos < LFieldEx.HeaderSize) then - begin - LHeaderPos := LPos; - LDataPos := 0; - - LHeaderCount := Min(LFieldEx.HeaderSize - LHeaderPos, LCount); - LDataCount := LCount - LHeaderCount; - end else - begin - LHeaderPos := -1; - LDataPos := LPos - LFieldEx.HeaderSize; - - LHeaderCount := 0; - LDataCount := LCount - LHeaderCount; - end; - - // 读取 Header - if (LHeaderCount > 0) then - begin - Move(LFieldEx.Header[LHeaderPos], P^, LHeaderCount); - Inc(P, LHeaderCount); - Dec(LReadCount, LHeaderCount); - - Seek(LHeaderCount, soCurrent); - end; - - // 读取 Data - if (LDataCount > 0) then - begin - LFieldEx.Field.Value.Position := LDataPos; - LFieldEx.Field.Value.Read(P^, LDataCount); - Inc(P, LDataCount); - Dec(LReadCount, LDataCount); - - Seek(LDataCount, soCurrent); - end; - end; - {$endregion} - - // 从尾巴读取数据 - if (LReadCount > 0) then - begin - LEndPos := FPosition - FEndPos; - LEndCount := Min(Length(FMultiPartEnd) - LEndPos, LReadCount); - - if (LEndCount > 0) then - begin - Move(FMultiPartEnd[LEndPos], P^, LEndCount); -// Inc(P, LEndCount); -// Dec(LReadCount, LEndCount); - - Seek(LEndCount, soCurrent); - end; - end; -end; - -function THttpMultiPartFormStream.Seek(const AOffset: Int64; - AOrigin: TSeekOrigin): Int64; -begin - case AOrigin of - soBeginning: FPosition := AOffset; - soCurrent: Inc(FPosition, AOffset); - soEnd: FPosition := FSize + AOffset; - end; - - if (FPosition < 0) then - FPosition := -1; - - if (FPosition > FSize) then - FPosition := FSize; - - Result := FPosition; -end; - -function THttpMultiPartFormStream._GetFiledIndexByOffset( - const AOffset: Int64): Integer; -var - LOffset: Int64; - I: Integer; -begin - Result := -1; - if (AOffset < 0) or (AOffset >= FSize) then Exit; - - LOffset := 0; - - for I := 0 to High(FFormFieldExArray) do - begin - Inc(LOffset, FFormFieldExArray[I].TotalSize); - if (AOffset < LOffset) then Exit(I); - end; -end; - -procedure THttpMultiPartFormStream._Init; -var - I: Integer; - LFormFieldEx: TFormFieldEx; - LContentType, LPartHeaderStr: string; - LPartHeaderBytes, LBoundary: TBytes; - LOffset: Int64; -begin - { - --boundary_value - Content-Disposition: form-data; name="text_field" - - This is a simple text field. - - --boundary_value - Content-Disposition: form-data; name="binary_data" - Content-Type: application/octet-stream - - [Binary data goes here] - - --boundary_value - Content-Disposition: form-data; name="file_field"; filename="example.txt" - Content-Type: text/plain - - Contents of the example.txt file. - - --boundary_value - Content-Disposition: form-data; name="image"; filename="image.jpg" - Content-Type: image/jpeg - - [Binary image data] - - --boundary_value-- - } - // 检查 boundary, 如果没有则生成 - if (FMultiPartFormData.Boundary = '') then - begin - Randomize; - FMultiPartFormData.Boundary := '--DCSFormBoundary' - + IntToHex(Random(MaxInt), 8) - + IntToHex(Random(MaxInt), 8); - end; - - // 结尾数据 - FMultiPartEnd := TArrayUtils.Concat(FMultiPartFormData.FBoundaryBytes, [45, 45, 13, 10]); - - LOffset := 0; - FSize := 0; - FPosition := 0; - - {$region '生成Field的头'} - SetLength(FFormFieldExArray, FMultiPartFormData.Count); - - for I := 0 to FMultiPartFormData.Count - 1 do - begin - LFormFieldEx.Offset := LOffset; - LFormFieldEx.Field := FMultiPartFormData.Items[I]; - - if (I = 0) then - LBoundary := FMultiPartFormData.FFirstBoundaryBytes - else - LBoundary := FMultiPartFormData.FBoundaryBytes; - - // 'Content-Disposition: form-data; name="%s"; filename="%s"'#13#10 + - // 'Content-Type: %s'#13#10#13#10 - - LContentType := LFormFieldEx.Field.ContentType; - - LPartHeaderStr := Format( - 'Content-Disposition: form-data; name="%s"', [ - LFormFieldEx.Field.Name - ]); - if (LFormFieldEx.Field.FileName <> '') then - begin - LPartHeaderStr := LPartHeaderStr - + Format('; filename="%s"', [LFormFieldEx.Field.FileName]); - - if (LContentType = '') then - LContentType := TCrossHttpUtils.GetFileMIMEType(LFormFieldEx.Field.FileName); - end; - LPartHeaderStr := LPartHeaderStr + #13#10; - - if (LContentType <> '') then - begin - LPartHeaderStr := LPartHeaderStr - + Format('Content-Type: %s', [LContentType]) - + #13#10; - end; - LPartHeaderStr := LPartHeaderStr + #13#10; - - LPartHeaderBytes := TEncoding.UTF8.GetBytes(LPartHeaderStr); - - LFormFieldEx.Header := TArrayUtils.Concat([ - LBoundary, [13, 10], LPartHeaderBytes]); - - Inc(FSize, LFormFieldEx.HeaderSize); - Inc(FSize, LFormFieldEx.DataSize); - Inc(LOffset, LFormFieldEx.TotalSize); - - FFormFieldExArray[I] := LFormFieldEx; - end; - {$endregion} - - FEndPos := LOffset; - Inc(FSize, Length(FMultiPartEnd)); -end; - -{ TResponseCookies } - -procedure TResponseCookies.AddOrSet(const AName, AValue: string; - AMaxAge: Integer; const APath, ADomain: string; AHttpOnly, ASecure: Boolean); -begin - SetCookie(AName, TResponseCookie.Create(AName, AValue, AMaxAge, APath, ADomain, AHttpOnly, ASecure)); -end; - -function TResponseCookies.GetCookieIndex(const AName: string): Integer; -var - I: Integer; -begin - for I := 0 to Count - 1 do - if TStrUtils.SameText(Items[I].Name, AName) then Exit(I); - Result := -1; -end; - -procedure TResponseCookies.Remove(const AName: string); -var - I: Integer; -begin - I := GetCookieIndex(AName); - if (I >= 0) then - inherited Delete(I); -end; - -function TResponseCookies.GetCookie(const AName: string): TResponseCookie; -var - I: Integer; -begin - I := GetCookieIndex(AName); - if (I >= 0) then - Result := Items[I] - else - begin - Result := TResponseCookie.Create(AName, '', 0); - Add(Result); - end; -end; - -procedure TResponseCookies.SetCookie(const AName: string; - const Value: TResponseCookie); -var - I: Integer; -begin - I := GetCookieIndex(AName); - if (I >= 0) then - Items[I] := Value - else - Add(Value); -end; - -{ TSessionBase } - -constructor TSessionBase.Create(const AOwner: TSessionsBase; const ASessionID: string); -var - LNow: TDateTime; -begin - LNow := Now; - - FOwner := AOwner; - - SetSessionID(ASessionID); - SetCreateTime(LNow); - SetLastAccessTime(LNow); -end; - -function TSessionBase.Expired: Boolean; -begin - Result := (ExpiryTime > 0) and (Now.SecondsDiffer(LastAccessTime) >= ExpiryTime); -end; - -function TSessionBase.GetOwner: ISessions; -begin - Result := FOwner; -end; - -procedure TSessionBase.Touch; -begin - LastAccessTime := Now; -end; - -{ TSession } - -constructor TSession.Create(const AOwner: TSessionsBase; const ASessionID: string); -begin - FValues := TDictionary.Create; - - inherited Create(AOwner, ASessionID); -end; - -destructor TSession.Destroy; -begin - FreeAndNil(FValues); - inherited; -end; - -function TSession.GetCreateTime: TDateTime; -begin - Result := FCreateTime; -end; - -function TSession.GetExpiryTime: Integer; -begin - Result := FExpire; -end; - -function TSession.GetLastAccessTime: TDateTime; -begin - Result := FLastAccessTime; -end; - -function TSession.GetSessionID: string; -begin - Result := FSessionID; -end; - -function TSession.GetValue(const AName: string): string; -begin - if not FValues.TryGetValue(AName, Result) then - Result := ''; - FLastAccessTime := Now; -end; - -procedure TSession.SetCreateTime(const ACreateTime: TDateTime); -begin - FCreateTime := ACreateTime; -end; - -procedure TSession.SetExpiryTime(const AValue: Integer); -begin - FExpire := AValue; -end; - -procedure TSession.SetLastAccessTime(const ALastAccessTime: TDateTime); -begin - FLastAccessTime := ALastAccessTime; -end; - -procedure TSession.SetSessionID(const ASessionID: string); -begin - FSessionID := ASessionID; -end; - -procedure TSession.SetValue(const AName, AValue: string); -begin - if (AValue <> '') then - FValues.AddOrSetValue(AName, AValue) - else - FValues.Remove(AName); - FLastAccessTime := Now; -end; - -{ TSessionsBase } - -function TSessionsBase.AddSession(const ASessionID: string): ISession; -begin - Result := GetSessionClass.Create(Self, ASessionID); - Result.ExpiryTime := ExpiryTime; - AddSession(ASessionID, Result); -end; - -function TSessionsBase.AddSession: ISession; -begin - Result := AddSession(NewSessionID); -end; - -function TSessionsBase.ExistsSession(const ASessionID: string): Boolean; -var - LStuff: ISession; -begin - Result := ExistsSession(ASessionID, LStuff); -end; - -procedure TSessionsBase.RemoveSession(const ASessionID: string); -var - LSession: ISession; -begin - if ExistsSession(ASessionID, LSession) then - RemoveSession(LSession); -end; - -procedure TSessionsBase.RemoveSession(const ASession: ISession); -begin - RemoveSessions([ASession]); -end; - -{ TSessions } - -constructor TSessions.Create(ANewGUIDFunc: TFunc); -begin - FNewGUIDFunc := ANewGUIDFunc; - FSessions := TDictionary.Create; - FLocker := TReadWriteLock.Create; - FSessionClass := TSession; - CreateExpiredProcThread; -end; - -procedure TSessions.Clear; -begin - FSessions.Clear; -end; - -constructor TSessions.Create; -begin - Create(nil); -end; - -destructor TSessions.Destroy; -var - LTimeout: TStopwatch; -begin - FShutdown := True; - LTimeout := TStopwatch.StartNew; - while FExpiredProcRunning and (LTimeout.ElapsedMilliseconds < 5000) do Sleep(10); - - BeginWrite; - FSessions.Clear; - EndWrite; - FreeAndNil(FSessions); - - inherited; -end; - -procedure TSessions.AddSession(const ASessionID: string; ASession: ISession); -begin - if (ASession.ExpiryTime = 0) then - ASession.ExpiryTime := ExpiryTime; - FSessions.AddOrSetValue(ASessionID, ASession); -end; - -procedure TSessions.AfterClearExpiredSessions; -begin - -end; - -procedure TSessions.BeforeClearExpiredSessions; -begin - -end; - -procedure TSessions.BeginRead; -begin - FLocker.BeginRead; -end; - -procedure TSessions.BeginWrite; -begin - FLocker.BeginWrite; -end; - -procedure TSessions.EndRead; -begin - FLocker.EndRead; -end; - -procedure TSessions.EndWrite; -begin - FLocker.EndWrite; -end; - -function TSessions.ExistsSession(const ASessionID: string; - var ASession: ISession): Boolean; -begin - Result := FSessions.TryGetValue(ASessionID, ASession); - if Result then - ASession.Touch; -end; - -procedure TSessions.CreateExpiredProcThread; -begin - TAnonymousThread.Create( - procedure - var - LWatch: TStopwatch; - begin - FExpiredProcRunning := True; - try - LWatch := TStopwatch.StartNew; - while not FShutdown do - begin - // 每 1 分钟清理一次超时 Session - if (FExpire > 0) and (LWatch.Elapsed.TotalMinutes >= 1) then - begin - _ClearExpiredSessions; - LWatch.Reset; - LWatch.Start; - end; - Sleep(10); - end; - finally - FExpiredProcRunning := False; - end; - end).Start; -end; - -function TSessions.NewSessionID: string; -begin - if Assigned(FNewGUIDFunc) then - Result := FNewGUIDFunc() - else - Result := TUtils.GetGUID.ToLower; -end; - -function TSessions.OnCheckExpiredSession(const ASession: ISession): Boolean; -begin - Result := ASession.Expired; -end; - -function TSessions.GetCount: Integer; -begin - Result := FSessions.Count; -end; - -function TSessions.GetEnumerator: TEnumerator; -begin - Result := TDictionary.TValueEnumerator.Create(FSessions); -end; - -function TSessions.GetExpiryTime: Integer; -begin - Result := FExpire; -end; - -function TSessions.GetItem(const AIndex: Integer): ISession; -var - LIndex: Integer; - LPair: TPair; -begin - LIndex := 0; - for LPair in FSessions do - begin - if (LIndex = AIndex) then Exit(LPair.Value); - Inc(LIndex); - end; - Result := nil; -end; - -function TSessions.GetSession(const ASessionID: string): ISession; -var - LSessionID: string; -begin - LSessionID := ASessionID; - BeginWrite; - try - if (LSessionID = '') then - LSessionID := NewSessionID; - if not FSessions.TryGetValue(LSessionID, Result) then - begin - Result := FSessionClass.Create(Self, LSessionID); - Result.ExpiryTime := ExpiryTime; - AddSession(LSessionID, Result); - end; - finally - EndWrite; - end; - - Result.LastAccessTime := Now; -end; - -function TSessions.GetSessionClass: TSessionClass; -begin - Result := FSessionClass; -end; - -procedure TSessions.RemoveSessions(const ASessions: TArray); -var - LSession: ISession; -begin - for LSession in ASessions do - FSessions.Remove(LSession.SessionID); -end; - -procedure TSessions.SetExpiryTime(const Value: Integer); -begin - FExpire := Value; -end; - -procedure TSessions.SetSessionClass(const Value: TSessionClass); -begin - FSessionClass := Value; -end; - -procedure TSessions._ClearExpiredSessions; -var - LPair: TPair; - LDelSessions: TArray; -begin - BeginWrite; - try - BeforeClearExpiredSessions; - - LDelSessions := nil; - for LPair in FSessions do - begin - if FShutdown then Break; - - if OnCheckExpiredSession(LPair.Value) then - LDelSessions := LDelSessions + [LPair.Value]; - end; - RemoveSessions(LDelSessions); - - AfterClearExpiredSessions; - finally - EndWrite; - end; -end; - -end. +{******************************************************************************} +{ } +{ Delphi cross platform socket library } +{ } +{ Copyright (c) 2017 WiNDDRiVER(soulawing@gmail.com) } +{ } +{ Homepage: https://github.com/winddriver/Delphi-Cross-Socket } +{ } +{******************************************************************************} +unit Net.CrossHttpParams; + +{$I zLib.inc} + +interface + +uses + SysUtils, + Classes, + Generics.Collections, + Generics.Defaults, + DateUtils, + Math, + + {$IFDEF DELPHI} + System.Diagnostics, + {$ELSE} + DTF.Types, + DTF.Diagnostics, + DTF.Generics, + {$ENDIF} + + Net.CrossHttpUtils, + + Utils.AnonymousThread, + Utils.RegEx, + Utils.IOUtils, + Utils.DateTime, + Utils.StrUtils, + Utils.SyncObjs, + Utils.ArrayUtils, + Utils.Utils; + +type + TNameValue = record + Name, Value: string; + constructor Create(const AName, AValue: string); + end; + + INameValueComparer = IComparer; + TNameValueComparison = {$IFDEF DELPHI}TComparison{$ELSE}TComparisonAnonymousFunc{$ENDIF}; + TNameValueComparer = {$IFDEF DELPHI}TDelegatedComparer{$ELSE}TDelegatedComparerAnonymousFunc{$ENDIF}; + + /// + /// 参数基础类 + /// + TBaseParams = class + private type + TEnumerator = class + private + FIndex: Integer; + FParams: TBaseParams; + public + constructor Create(const AParams: TBaseParams); + function GetCurrent: TNameValue; inline; + function MoveNext: Boolean; inline; + property Current: TNameValue read GetCurrent; + end; + private + FParams: TList; + + function GetParamIndex(const AName: string): Integer; + function GetParam(const AName: string): string; + procedure SetParam(const AName, AValue: string); + function GetCount: Integer; + function GetItem(AIndex: Integer): TNameValue; + procedure SetItem(AIndex: Integer; const AValue: TNameValue); + public + constructor Create; overload; virtual; + constructor Create(const AEncodedParams: string); overload; virtual; + destructor Destroy; override; + + /// + /// 枚举器 + /// + function GetEnumerator: TEnumerator; inline; + + /// + /// 从源对象设置数据 + /// + procedure Assign(const ASource: TBaseParams); + + /// + /// 添加参数 + /// + procedure Add(const AParamValue: TNameValue); overload; + + /// + /// 添加参数 + /// + /// + /// 参数名 + /// + /// + /// 参数值 + /// + /// + /// 是否允许重名参数 + /// + procedure Add(const AName, AValue: string; ADupAllowed: Boolean = False); overload; + + /// + /// 添加已编码参数 + /// + /// + /// 已编码参数字符串 + /// + procedure Add(const AEncodedParams: string); overload; + + /// + /// 根据名称删除指定参数 + /// + /// + /// 参数名称 + /// + procedure Remove(const AName: string); overload; + + /// + /// 根据序号删除指定参数 + /// + /// + /// 参数序号 + /// + procedure Remove(AIndex: Integer); overload; + + /// + /// 清除所有参数 + /// + procedure Clear; + + /// + /// 对参数排序 + /// + /// + /// 自定义比较函数,为nil时按参数名排序 + /// + procedure Sort(const AComparison: TNameValueComparison = nil); + + /// + /// 从已编码的字符串中解码 + /// + /// + /// 已编码字符串 + /// + /// + /// 是否清除现有数据 + /// + /// + /// 解码是否成功 + /// + function Decode(const AEncodedParams: string; AClear: Boolean = True): Boolean; virtual; abstract; + + /// + /// 编码为字符串 + /// + /// + /// 编码后的字符串 + /// + function Encode: string; virtual; abstract; + + /// + /// 获取参数值 + /// + /// + /// 参数名称 + /// + /// + /// 返回的参数值 + /// + /// + /// 如果找到参数返回True,否则返回False + /// + function GetParamValue(const AName: string; out AValue: string): Boolean; + + /// + /// 获取指定名称的所有参数值 + /// + /// + /// 参数名称 + /// + /// + /// 返回的参数值数组 + /// + /// + /// 如果找到参数返回True,否则返回False + /// + function GetHeaderValues(const AName: string; out AValues: TArray): Boolean; + + /// + /// 是否存在参数 + /// + /// + /// 参数名称 + /// + /// + /// 如果存在参数返回True,否则返回False + /// + function ExistsParam(const AName: string): Boolean; + + /// + /// 按名称访问参数 + /// + /// + /// 参数名称 + /// + /// + /// 参数值,如果不存在返回空字符串 + /// + property Params[const AName: string]: string read GetParam write SetParam; default; + + /// + /// 按序号访问参数 + /// + /// + /// 参数序号 + /// + /// + /// 参数名值对 + /// + property Items[AIndex: Integer]: TNameValue read GetItem write SetItem; + + /// + /// 参数个数 + /// + property Count: Integer read GetCount; + end; + + /// + /// Url参数类 + /// + THttpUrlParams = class(TBaseParams) + private + FEncodeName: Boolean; + FEncodeValue: Boolean; + public + constructor Create; override; + + /// + /// 从已编码的字符串中解码 + /// + /// + /// 已编码字符串 + /// + /// + /// 是否清除现有数据 + /// + function Decode(const AEncodedParams: string; AClear: Boolean = True): Boolean; override; + + /// + /// 编码为字符串 + /// + function Encode: string; override; + + /// + /// 是否对名称做编码 + /// + property EncodeName: Boolean read FEncodeName write FEncodeName; + + /// + /// 是否对名称做编码 + /// + property EncodeValue: Boolean read FEncodeValue write FEncodeValue; + end; + + /// + /// HTTP头类 + /// + THttpHeader = class(TBaseParams) + public + /// + /// 从已编码的字符串中解码 + /// + /// + /// 已编码字符串 + /// + /// + /// 是否清除现有数据 + /// + function Decode(const AEncodedParams: string; AClear: Boolean = True): Boolean; override; + + /// + /// 编码为字符串 + /// + function Encode: string; override; + end; + + {$REGION 'Documentation'} + /// + /// x-www-form-urlencoded 格式参数 + /// + {$ENDREGION} + TFormUrlEncoded = class(THttpUrlParams); + + /// + /// 带分隔符的参数 + /// + TDelimitParams = class(TBaseParams) + private + FDelimiter: Char; + FUrlEncode: Boolean; + public + constructor Create(const ADelimiter: Char; const AUrlEncode: Boolean = False); reintroduce; overload; virtual; + constructor Create(const AEncodedParams: string; const ADelimiter: Char; const AUrlEncode: Boolean = False); reintroduce; overload; virtual; + + /// + /// 从已编码的字符串中解码 + /// + /// + /// 已编码字符串 + /// + /// + /// 是否清除现有数据 + /// + function Decode(const AEncodedParams: string; AClear: Boolean = True): Boolean; override; + + /// + /// 编码为字符串 + /// + function Encode: string; override; + + /// + /// 分隔字符 + /// + property Delimiter: Char read FDelimiter write FDelimiter; + + /// + /// 是否进行URL编解码 + /// + property UrlEncode: Boolean read FUrlEncode write FUrlEncode; + end; + + {$REGION 'Documentation'} + /// + /// 客户端请求头中的Cookies + /// + /// + /// + /// 格式如下 + /// + /// + /// Cookie: name1=value1; name2=value2; ... + /// + /// + {$ENDREGION} + TRequestCookies = class(TBaseParams) + public + /// + /// 从已编码的字符串中解码 + /// + /// + /// 已编码字符串 + /// + /// + /// 是否清除现有数据 + /// + function Decode(const AEncodedParams: string; AClear: Boolean = True): Boolean; override; + + /// + /// 编码为字符串 + /// + function Encode: string; override; + end; + + {$REGION 'Documentation'} + /// + /// 响应头中的Cookie + /// + /// + /// + /// 格式如下 + /// + /// + /// Set-Cookie: name=value; [expires=date;] [path=path;] + /// [domain=domain;] [secure;] [HttpOnly;]
+ ///
+ ///
+ {$ENDREGION} + TResponseCookie = record + /// + /// Cookie名称 + /// + Name: string; + + /// + /// Cookie数据 + /// + Value: string; + + /// + /// Cookie有效期秒数, 如果设置为0则浏览器关闭后该Cookie即失效 + /// + MaxAge: Integer; + + /// + /// 域名作用域 + /// + /// + /// 定义Cookie的生效作用域, 只有当域名和路径同时满足的时候, 浏览器才会将Cookie发送给Server. + /// 如果没有设置Domain和Path的话, 他们会被默认为当前请求页面对应值 + /// + Domain: string; + + /// + /// 路径作用域 + /// + /// + /// 定义Cookie的生效作用域, 只有当域名和路径同时满足的时候, 浏览器才会将Cookie发送给Server. + /// 如果没有设置Domain和Path的话, 他们会被默认为当前请求页面对应值 + /// + Path: string; + + /// + /// 是否启用 HttpOnly + /// + /// + /// HttpOnly字段告诉浏览器, 只有在HTTP协议下使用, 对浏览器的脚本不可见, 所以跨站脚本攻击时也不会被窃取 + /// + HttpOnly: Boolean; + + /// + /// 是否启用Secure + /// + /// + /// Secure字段告诉浏览器在https通道时, 对Cookie进行安全加密, 这样即时有黑客监听也无法获取cookie内容 + /// + Secure: Boolean; + + constructor Create(const AName, AValue: string; AMaxAge: Integer; + const APath: string = ''; const ADomain: string = ''; + AHttpOnly: Boolean = False; ASecure: Boolean = False); overload; + + constructor Create(const ACookieData: string; const ADomain: string = ''); overload; + + function Encode: string; + end; + + /// + /// Cookie类 + /// + TResponseCookies = class(TList) + private + function GetCookieIndex(const AName: string): Integer; + function GetCookie(const AName: string): TResponseCookie; + procedure SetCookie(const AName: string; const Value: TResponseCookie); + public + procedure AddOrSet(const AName, AValue: string; AMaxAge: Integer; + const APath: string = ''; const ADomain: string = ''; + AHttpOnly: Boolean = False; ASecure: Boolean = False); + procedure Remove(const AName: string); + + property Cookies[const AName: string]: TResponseCookie read GetCookie write SetCookie; + end; + + TFormField = class + private + FName: string; + FValue: TStream; + FFileName: string; + FFilePath: string; + FContentType: string; + FContentTransferEncoding: string; + FValueOwned, FIsTempFile: Boolean; + public + constructor Create; overload; + destructor Destroy; override; + + /// + /// 从源对象设置数据 + /// + procedure Assign(const ASource: TFormField); + + /// + /// 将数据转为字节 + /// + function AsBytes: TBytes; + + /// + /// 将数据转为字符串 + /// + /// + /// 字符串编码 + /// + function AsString(AEncoding: TEncoding = nil): string; + + /// + /// 释放流数据 + /// + procedure FreeValue; + + /// + /// 名称 + /// + property Name: string read FName; + + /// + /// 原始流数据 + /// + property Value: TStream read FValue; + + /// + /// 文件名(只有文件才有该属性) + /// + property FileName: string read FFileName; + + /// + /// 文件保存路径(只有文件才有该属性) + /// + property FilePath: string read FFilePath; + + /// + /// 内容类型(只有文件才有该属性) + /// + property ContentType: string read FContentType; + property ContentTransferEncoding: string read FContentTransferEncoding; + end; + + /// + /// FormData解码结果 + /// + TFormDataDecodeResult = (frContinue, frComplete, frFailed); + + /// + /// MultiPartFormData类 + /// + THttpMultiPartFormData = class + private type + TEnumerator = class + private + FList: TList; + FIndex: Integer; + public + constructor Create(const AList: TList); + function GetCurrent: TFormField; inline; + function MoveNext: Boolean; inline; + property Current: TFormField read GetCurrent; + end; + public type + TDecodeState = (dsBoundary, dsDetect, dsPartHeader, dsPartData); + + /// + /// 头部结束标记检测状态机, 严格匹配 #13#10#13#10 序列 + /// + TLineEndState = (lesCR1, lesLF1, lesCR2, lesLF2); + + /// + /// dsDetect 状态: Boundary 标记之后判断是 Header 数据还是结束标记 + /// + TPostBoundaryState = (pbsDetect, pbsHeader1, pbsEnd1, pbsEnd2, pbsEnd3); + private const + MAX_PART_HEADER: Integer = 64 * 1024; + private + FBoundary, FStoragePath: string; + FFirstBoundaryBytes, FBoundaryBytes, FLookbehind: TBytes; + FBoundaryIndex, FPartDataBegin: Integer; + FPostBoundaryState: TPostBoundaryState; + FPrevBoundaryIndex: Integer; + FDecodeState: TDecodeState; + FLineEndState: TLineEndState; + FPartFields: TObjectList; + FCurrentPartHeader: TBytes; + FCurrentPartHeaderLen: Integer; + FCurrentPartField: TFormField; + FAutoDeleteFiles: Boolean; + FMaxPartDataSize: Integer; + FCurrentPartDataSize: Int64; + + function GetItemIndex(const AName: string): Integer; + function GetItem(AIndex: Integer): TFormField; + function GetCount: Integer; + function GetDataSize: Integer; + function GetField(const AName: string): TFormField; + procedure SetBoundary(const AValue: string); + public + constructor Create; virtual; + destructor Destroy; override; + + {$REGION 'Documentation'} + /// + /// 枚举器 + /// + {$ENDREGION} + function GetEnumerator: TEnumerator; inline; + + {$REGION 'Documentation'} + /// + /// 从源对象设置数据 + /// + {$ENDREGION} + procedure Assign(const ASource: THttpMultiPartFormData); + + {$REGION 'Documentation'} + /// + /// 初始化Boundary(Decode之前调用) + /// + {$ENDREGION} + procedure InitWithBoundary(const ABoundary: string); + + {$REGION 'Documentation'} + /// + /// 从内存中解码(必须先调用InitWithBoundary) + /// + /// + /// 待解码数据 + /// + /// + /// 数据长度 + /// + /// + /// 已知限制: 仅支持 multipart/form-data; 不支持 RFC 2046 preamble/epilogue 文本; + /// 不支持 multipart/mixed 嵌套; Content-Transfer-Encoding 仅存储不解码. + /// + {$ENDREGION} + function Decode(const ABuf: Pointer; ALen: Integer): TFormDataDecodeResult; overload; + + {$REGION 'Documentation'} + /// + /// 从内存中解码并返回实际消费的字节数(必须先调用InitWithBoundary) + /// + /// + /// 待解码数据 + /// + /// + /// 数据长度 + /// + /// + /// 出参: 实际消费的字节数. frComplete 时可能小于 ALen, 调用方需要用剩余字节继续后续解析. + /// + {$ENDREGION} + function Decode(const ABuf: Pointer; ALen: Integer; out AConsumed: Integer): TFormDataDecodeResult; overload; + + {$REGION 'Documentation'} + /// + /// 从数据流解码(必须先调用InitWithBoundary) + /// + /// + /// 待解码数据流 + /// + {$ENDREGION} + function Decode(const AStream: TStream): TFormDataDecodeResult; overload; + + {$REGION 'Documentation'} + /// + /// 清除所有Items + /// + {$ENDREGION} + procedure Clear; + + {$REGION 'Documentation'} + /// + /// 添加字段 + /// + /// + /// 字段对象 + /// + {$ENDREGION} + function AddField(const AField: TFormField): TFormField; overload; + + {$REGION 'Documentation'} + /// + /// 添加字段 + /// + /// + /// 字段名 + /// + /// + /// 字段值 + /// + {$ENDREGION} + function AddField(const AFieldName: string; const AValue: TBytes): TFormField; overload; + + {$REGION 'Documentation'} + /// + /// 添加字段 + /// + /// + /// 字段名 + /// + /// + /// 字段值 + /// + {$ENDREGION} + function AddField(const AFieldName, AValue: string): TFormField; overload; + + {$REGION 'Documentation'} + /// + /// 添加文件字段 + /// + /// + /// 字段名 + /// + /// + /// 文件名 + /// + /// + /// 文件流 + /// + /// + /// 是否自动释放 + /// + {$ENDREGION} + function AddFile(const AFieldName, AFileName: string; + const AStream: TStream; const AOwned: Boolean = False): TFormField; overload; + + {$REGION 'Documentation'} + /// + /// 添加文件字段 + /// + /// + /// 字段名 + /// + /// + /// 文件名 + /// + {$ENDREGION} + function AddFile(const AFieldName, AFileName: string): TFormField; overload; + + {$REGION 'Documentation'} + /// + /// 根据名称删除指定字段 + /// + /// + /// 字段名 + /// + {$ENDREGION} + procedure Remove(const AFieldName: string); overload; + + {$REGION 'Documentation'} + /// + /// 根据序号删除指定字段 + /// + /// + /// 字段序号 + /// + {$ENDREGION} + procedure Remove(AIndex: Integer); overload; + + {$REGION 'Documentation'} + /// + /// 查找参数 + /// + {$ENDREGION} + function FindField(const AFieldName: string; out AField: TFormField): Boolean; + + function AsBytes(const AFieldName: string; out AValue: TBytes): Boolean; overload; + function AsBytes(const AFieldName: string): TBytes; overload; + + function AsStream(const AFieldName: string; out AValue: TStream): Boolean; overload; + function AsStream(const AFieldName: string): TStream; overload; + + function AsString(const AFieldName: string; const AEncoding: TEncoding; out AValue: string): Boolean; overload; + function AsString(const AFieldName: string; out AValue: string): Boolean; overload; + function AsString(const AFieldName: string; const AEncoding: TEncoding = nil): string; overload; + + {$REGION 'Documentation'} + /// + /// Boundary特征字符串 + /// + {$ENDREGION} + property Boundary: string read FBoundary write SetBoundary; + + {$REGION 'Documentation'} + /// + /// 上传文件保存的路径 + /// + {$ENDREGION} + property StoragePath: string read FStoragePath write FStoragePath; + + {$REGION 'Documentation'} + /// + /// 按序号访问参数 + /// + {$ENDREGION} + property Items[AIndex: Integer]: TFormField read GetItem; + + {$REGION 'Documentation'} + /// + /// 按名称访问参数 + /// + {$ENDREGION} + property Fields[const AName: string]: TFormField read GetField; + + {$REGION 'Documentation'} + /// + /// Items个数(只读) + /// + {$ENDREGION} + property Count: Integer read GetCount; + + {$REGION 'Documentation'} + /// + /// 所有Items数据的总尺寸(字节数) + /// + {$ENDREGION} + property DataSize: Integer read GetDataSize; + + {$REGION 'Documentation'} + /// + /// 对象释放时自动删除上传的文件 + /// + {$ENDREGION} + property AutoDeleteFiles: Boolean read FAutoDeleteFiles write FAutoDeleteFiles; + + {$REGION 'Documentation'} + /// + /// 单个 Part Body 最大字节数, 0 表示不限制. 超过限制时 Decode 返回 frFailed. + /// + {$ENDREGION} + property MaxPartDataSize: Integer read FMaxPartDataSize write FMaxPartDataSize; + end; + + {$REGION 'Documentation'} + /// + /// MultiPartFormData流 + /// + /// + /// 动态从 MultiPartFormData 对象中读取数据, 而不是打包到内存中, 所以支持从磁盘加载超大文件 + /// + {$ENDREGION} + THttpMultiPartFormStream = class(TStream) + private type + TFormFieldEx = record + Header: TBytes; + Field: TFormField; + Offset: Int64; + + function HeaderSize: Integer; + function DataSize: Int64; + function TotalSize: Int64; + end; + + TFormFieldExArray = TArray; + private + FMultiPartFormData: THttpMultiPartFormData; + FOwned: Boolean; + FFormFieldExArray: TFormFieldExArray; + FMultiPartEnd: TBytes; + FSize, FPosition, FEndPos: Int64; + + procedure _Init; + function _GetFiledIndexByOffset(const AOffset: Int64): Integer; + public + constructor Create(const AMultiPartFormData: THttpMultiPartFormData; + const AOwned: Boolean = False); reintroduce; + destructor Destroy; override; + + function Read(var ABuffer; ACount: Longint): Longint; override; + function Seek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64; override; + + property MultiPartFormData: THttpMultiPartFormData read FMultiPartFormData; + end; + + TSessionsBase = class; + ISessions = interface; + + /// + /// Session成员接口 + /// + ISession = interface + ['{A3D525A1-C534-4CE6-969B-53C5B8CB77C3}'] + function GetOwner: ISessions; + + function GetSessionID: string; + function GetCreateTime: TDateTime; + function GetLastAccessTime: TDateTime; + function GetExpiryTime: Integer; + function GetValue(const AName: string): string; + procedure SetSessionID(const ASessionID: string); + procedure SetCreateTime(const ACreateTime: TDateTime); + procedure SetLastAccessTime(const ALastAccessTime: TDateTime); + procedure SetExpiryTime(const Value: Integer); + procedure SetValue(const AName, AValue: string); + + /// + /// 更新最后访问时间 + /// + procedure Touch; + + /// + /// 是否已过期 + /// + function Expired: Boolean; + + /// + /// 父容器 + /// + property Owner: ISessions read GetOwner; + + /// + /// Session ID + /// + property SessionID: string read GetSessionID write SetSessionID; + + /// + /// 创建时间 + /// + property CreateTime: TDateTime read GetCreateTime write SetCreateTime; + + /// + /// 最后访问时间 + /// + property LastAccessTime: TDateTime read GetLastAccessTime write SetLastAccessTime; + + /// + /// Session过期时间(秒) + /// + /// + /// + /// + /// 值大于0时, 当Session超过设定值秒数没有使用就会被释放; + /// + /// + /// 值等于0时, 使用父容器的超时设置 + /// + /// + /// 值小于0时, Session生成后一直有效 + /// + /// + /// + property ExpiryTime: Integer read GetExpiryTime write SetExpiryTime; + + /// + /// Session是一个KEY-VALUE结构的数据, 该属性用于访问其中的成员值 + /// + property Values[const AName: string]: string read GetValue write SetValue; default; + end; + + TSessionBase = class abstract(TInterfacedObject, ISession) + private + FOwner: TSessionsBase; + protected + function GetOwner: ISessions; + function GetSessionID: string; virtual; abstract; + function GetCreateTime: TDateTime; virtual; abstract; + function GetLastAccessTime: TDateTime; virtual; abstract; + function GetExpiryTime: Integer; virtual; abstract; + function GetValue(const AName: string): string; virtual; abstract; + procedure SetSessionID(const ASessionID: string); virtual; abstract; + procedure SetCreateTime(const ACreateTime: TDateTime); virtual; abstract; + procedure SetLastAccessTime(const ALastAccessTime: TDateTime); virtual; abstract; + procedure SetExpiryTime(const Value: Integer); virtual; abstract; + procedure SetValue(const AName, AValue: string); virtual; abstract; + public + constructor Create(const AOwner: TSessionsBase; const ASessionID: string); virtual; + + procedure Touch; virtual; + function Expired: Boolean; virtual; + + property Owner: ISessions read GetOwner; + + property SessionID: string read GetSessionID write SetSessionID; + property CreateTime: TDateTime read GetCreateTime write SetCreateTime; + property LastAccessTime: TDateTime read GetLastAccessTime write SetLastAccessTime; + property ExpiryTime: Integer read GetExpiryTime write SetExpiryTime; + property Values[const AName: string]: string read GetValue write SetValue; default; + end; + + TSession = class(TSessionBase) + protected + FSessionID: string; + FCreateTime: TDateTime; + FLastAccessTime: TDateTime; + FExpire: Integer; + FValues: TDictionary; + + function GetSessionID: string; override; + function GetCreateTime: TDateTime; override; + function GetLastAccessTime: TDateTime; override; + function GetExpiryTime: Integer; override; + function GetValue(const AName: string): string; override; + procedure SetSessionID(const ASessionID: string); override; + procedure SetCreateTime(const ACreateTime: TDateTime); override; + procedure SetLastAccessTime(const ALastAccessTime: TDateTime); override; + procedure SetExpiryTime(const AValue: Integer); override; + procedure SetValue(const AName, AValue: string); override; + public + constructor Create(const AOwner: TSessionsBase; const ASessionID: string); override; + destructor Destroy; override; + + property SessionID: string read GetSessionID write SetSessionID; + property CreateTime: TDateTime read GetCreateTime write SetCreateTime; + property LastAccessTime: TDateTime read GetLastAccessTime write SetLastAccessTime; + property Values[const AName: string]: string read GetValue write SetValue; default; + end; + + TSessionClass = class of TSessionBase; + + /// + /// Session管理接口 + /// + ISessions = interface + ['{5187CA76-4CC4-4986-B67B-BC3E76D6CD74}'] + function GetEnumerator: TEnumerator; + + function GetSessionClass: TSessionClass; + function GetCount: Integer; + function GetItem(const AIndex: Integer): ISession; + function GetSession(const ASessionID: string): ISession; + function GetExpiryTime: Integer; + procedure SetSessionClass(const Value: TSessionClass); + procedure SetExpiryTime(const Value: Integer); + + /// + /// 开始写(用于线程同步) + /// + procedure BeginWrite; + + /// + /// 结束写(用于线程同步) + /// + procedure EndWrite; + + /// + /// 开始读(用于线程同步) + /// + procedure BeginRead; + + /// + /// 结束读(用于线程同步) + /// + procedure EndRead; + + /// + /// 生成新Session ID + /// + function NewSessionID: string; + + /// + /// 检查是否存在指定ID的Session + /// + /// + /// Session ID + /// + /// + /// 如果存在指定的Session, 则将实例保存到该参数中 + /// + function ExistsSession(const ASessionID: string; var ASession: ISession): Boolean; overload; + + /// + /// 检查是否存在指定ID的Session + /// + /// + /// Session ID + /// + function ExistsSession(const ASessionID: string): Boolean; overload; + + /// + /// 新增Session + /// + /// + /// Session ID + /// + /// + /// Session实例 + /// + function AddSession(const ASessionID: string): ISession; overload; + + /// + /// 新增Session + /// + /// + /// Session实例 + /// + function AddSession: ISession; overload; + + /// + /// 新增Session + /// + /// + /// Session ID + /// + /// + /// Session实例 + /// + procedure AddSession(const ASessionID: string; ASession: ISession); overload; + + /// + /// 删除Session + /// + /// + /// Session对象 + /// + procedure RemoveSession(const ASession: ISession); overload; + + /// + /// 删除Session + /// + /// + /// Session ID + /// + procedure RemoveSession(const ASessionID: string); overload; + + /// + /// 批量删除Session + /// + /// + /// Session对象数据 + /// + procedure RemoveSessions(const ASessions: TArray); + + /// + /// 清除所有Session + /// + procedure Clear; + + /// + /// Session类 + /// + property SessionClass: TSessionClass read GetSessionClass write SetSessionClass; + + /// + /// Session个数 + /// + property Count: Integer read GetCount; + + /// + /// 获取指定序号的Session, 如果不存在则返回nil + /// + property Items[const AIndex: Integer]: ISession read GetItem; + + /// + /// 获取指定ID的Session, 如果不存在则会新建一个 + /// + /// + /// Session ID + /// + property Sessions[const ASessionID: string]: ISession read GetSession; default; + + /// + /// Session过期时间(秒) + /// + /// + /// + /// + /// 值大于0时, 当Session超过设定值秒数没有使用就会被释放; + /// + /// + /// 值小于等于0时, Session生成后一直有效 + /// + /// + /// + property ExpiryTime: Integer read GetExpiryTime write SetExpiryTime; + end; + + TSessionsBase = class abstract(TInterfacedObject, ISessions) + protected + function GetSessionClass: TSessionClass; virtual; abstract; + function GetCount: Integer; virtual; abstract; + function GetItem(const AIndex: Integer): ISession; virtual; abstract; + function GetSession(const ASessionID: string): ISession; virtual; abstract; + function GetExpiryTime: Integer; virtual; abstract; + procedure SetSessionClass(const Value: TSessionClass); virtual; abstract; + procedure SetExpiryTime(const Value: Integer); virtual; abstract; + public + function GetEnumerator: TEnumerator; virtual; abstract; + + procedure BeginWrite; virtual; abstract; + procedure EndWrite; virtual; abstract; + + procedure BeginRead; virtual; abstract; + procedure EndRead; virtual; abstract; + + function NewSessionID: string; virtual; abstract; + function ExistsSession(const ASessionID: string; var ASession: ISession): Boolean; overload; virtual; abstract; + function ExistsSession(const ASessionID: string): Boolean; overload; virtual; + function AddSession(const ASessionID: string): ISession; overload; virtual; + function AddSession: ISession; overload; + procedure AddSession(const ASessionID: string; ASession: ISession); overload; virtual; abstract; + + procedure RemoveSessions(const ASessions: TArray); virtual; abstract; + procedure RemoveSession(const ASession: ISession); overload; virtual; + procedure RemoveSession(const ASessionID: string); overload; virtual; + + procedure Clear; virtual; abstract; + + property SessionClass: TSessionClass read GetSessionClass write SetSessionClass; + property Count: Integer read GetCount; + property Items[const AIndex: Integer]: ISession read GetItem; + property Sessions[const ASessionID: string]: ISession read GetSession; default; + property ExpiryTime: Integer read GetExpiryTime write SetExpiryTime; + end; + + TSessions = class(TSessionsBase) + private + FNewGUIDFunc: TFunc; + FLocker: IReadWriteLock; + FSessionClass: TSessionClass; + FExpire: Integer; + FShutdown, FExpiredProcRunning: Boolean; + + procedure _ClearExpiredSessions; + protected + FSessions: TDictionary; + + function GetSessionClass: TSessionClass; override; + function GetCount: Integer; override; + function GetItem(const AIndex: Integer): ISession; override; + function GetSession(const ASessionID: string): ISession; override; + function GetExpiryTime: Integer; override; + procedure SetSessionClass(const Value: TSessionClass); override; + procedure SetExpiryTime(const Value: Integer); override; + + procedure BeforeClearExpiredSessions; virtual; + function OnCheckExpiredSession(const ASession: ISession): Boolean; virtual; + procedure AfterClearExpiredSessions; virtual; + procedure CreateExpiredProcThread; + public + constructor Create(ANewGUIDFunc: TFunc); overload; virtual; + constructor Create; overload; virtual; + destructor Destroy; override; + + function GetEnumerator: TEnumerator; override; + + procedure BeginWrite; override; + procedure EndWrite; override; + + procedure BeginRead; override; + procedure EndRead; override; + + function NewSessionID: string; override; + function ExistsSession(const ASessionID: string; var ASession: ISession): Boolean; override; + procedure AddSession(const ASessionID: string; ASession: ISession); override; + + procedure RemoveSessions(const ASessions: TArray); override; + + procedure Clear; override; + + property NewGUIDFunc: TFunc read FNewGUIDFunc write FNewGUIDFunc; + end; + +implementation + +function _IsHttpToken(const AValue: string): Boolean; +var + I: Integer; +begin + if (AValue = '') then Exit(False); + + for I := 1 to Length(AValue) do + begin + case AValue[I] of + 'A'..'Z', 'a'..'z', '0'..'9', + '!', '#', '$', '%', '&', '''', '*', '+', '-', '.', '^', '_', '`', '|', '~': ; + else + Exit(False); + end; + end; + + Result := True; +end; + +function _IsCookieOctets(const AValue: string): Boolean; +var + I, LCode: Integer; +begin + for I := 1 to Length(AValue) do + begin + LCode := Ord(AValue[I]); + case LCode of + $21, // '!' + $23..$2B, // '#' to '+' + $2D..$3A, // '-' to ':' + $3C..$5B, // '<' to '[' + $5D..$7E: ; // ']' to '~' + else + Exit(False); + end; + end; + + Result := True; +end; + +function _IsCookieAvValue(const AValue: string): Boolean; +var + I, LCode: Integer; +begin + for I := 1 to Length(AValue) do + begin + LCode := Ord(AValue[I]); + if (LCode < $20) or (LCode >= $7F) or (AValue[I] = ';') then + Exit(False); + end; + + Result := True; +end; + +function _TryNormalizeCookieValue(const AValue: string; out ANormalizedValue: string): Boolean; +begin + ANormalizedValue := AValue; + if (Length(ANormalizedValue) >= 2) then + if (ANormalizedValue[1] = '"') + and (ANormalizedValue[High(ANormalizedValue)] = '"') then + ANormalizedValue := Copy(ANormalizedValue, 2, Length(ANormalizedValue) - 2); + + Result := _IsCookieOctets(ANormalizedValue); +end; + +function _NormalizeCookieDomain(const AValue: string): string; +begin + if not _IsCookieAvValue(AValue) then Exit(''); + + Result := AValue.Trim.ToLower; + if (Result <> '') then + if (Result[1] = '.') then + Delete(Result, 1, 1); +end; + +function _TryParseCookieMaxAge(const AValue: string; out AMaxAge: Integer): Boolean; +var + I: Integer; +begin + AMaxAge := 0; + Result := False; + if (AValue = '') then Exit; + + if (AValue[1] = '-') then + begin + if (Length(AValue) = 1) then Exit; + for I := 2 to Length(AValue) do + if not CharInSet(AValue[I], ['0'..'9']) then Exit; + end else + begin + for I := 1 to Length(AValue) do + if not CharInSet(AValue[I], ['0'..'9']) then Exit; + end; + + Result := TryStrToInt(AValue, AMaxAge); +end; + +{ TNameValue } + +constructor TNameValue.Create(const AName, + AValue: string); +begin + Name := AName; + Value := AValue; +end; + +{ TBaseParams.TEnumerator } + +constructor TBaseParams.TEnumerator.Create(const AParams: TBaseParams); +begin + FParams := AParams; + FIndex := -1; +end; + +function TBaseParams.TEnumerator.GetCurrent: TNameValue; +begin + Result := FParams.Items[FIndex]; +end; + +function TBaseParams.TEnumerator.MoveNext: Boolean; +begin + Inc(FIndex); + Result := (FIndex < FParams.Count); +end; + +{ TBaseParams } + +constructor TBaseParams.Create; +begin + FParams := TList.Create(TComparer.Construct( + function(const Left, Right: TNameValue): Integer + begin + Result := CompareText(Left.Name, Right.Name, TLocaleOptions.loUserLocale); + end)); +end; + +constructor TBaseParams.Create(const AEncodedParams: string); +begin + Create; + Decode(AEncodedParams, True); +end; + +destructor TBaseParams.Destroy; +begin + FreeAndNil(FParams); + inherited; +end; + +procedure TBaseParams.Add(const AName, AValue: string; ADupAllowed: Boolean); +begin + if ADupAllowed then + FParams.Add(TNameValue.Create(AName, AValue)) + else + SetParam(AName, AValue); +end; + +procedure TBaseParams.Add(const AEncodedParams: string); +begin + Decode(AEncodedParams, False); +end; + +procedure TBaseParams.Assign(const ASource: TBaseParams); +var + LParamItem: TNameValue; +begin + Clear; + + if (ASource = nil) or (ASource.Count <= 0) then Exit; + + for LParamItem in ASource do + Add(LParamItem); +end; + +procedure TBaseParams.Add(const AParamValue: TNameValue); +begin + FParams.Add(AParamValue); +end; + +procedure TBaseParams.Clear; +begin + FParams.Clear; +end; + +function TBaseParams.GetParamIndex(const AName: string): Integer; +var + I: Integer; +begin + for I := 0 to FParams.Count - 1 do + if TStrUtils.SameText(FParams[I].Name, AName) then Exit(I); + Result := -1; +end; + +function TBaseParams.GetParamValue(const AName: string; + out AValue: string): Boolean; +var + I: Integer; +begin + I := GetParamIndex(AName); + if (I >= 0) then + begin + AValue := FParams[I].Value; + Exit(True); + end; + + AValue := ''; + Result := False; +end; + +function TBaseParams.GetHeaderValues(const AName: string; + out AValues: TArray): Boolean; +var + I, LCount: Integer; +begin + SetLength(AValues, FParams.Count); + LCount := 0; + Result := False; + for I := 0 to FParams.Count - 1 do + begin + if not TStrUtils.SameText(FParams[I].Name, AName) then Continue; + AValues[LCount] := FParams[I].Value; + Inc(LCount); + Result := True; + end; + SetLength(AValues, LCount); +end; + +procedure TBaseParams.Remove(const AName: string); +var + I: Integer; +begin + I := GetParamIndex(AName); + if (I >= 0) then + FParams.Delete(I); +end; + +procedure TBaseParams.Remove(AIndex: Integer); +begin + FParams.Delete(AIndex); +end; + +function TBaseParams.GetCount: Integer; +begin + Result := FParams.Count; +end; + +function TBaseParams.GetEnumerator: TEnumerator; +begin + Result := TEnumerator.Create(Self); +end; + +function TBaseParams.GetItem(AIndex: Integer): TNameValue; +begin + Result := FParams.Items[AIndex]; +end; + +function TBaseParams.ExistsParam(const AName: string): Boolean; +begin + Result := (GetParamIndex(AName) >= 0); +end; + +function TBaseParams.GetParam(const AName: string): string; +var + I: Integer; +begin + I := GetParamIndex(AName); + if (I >= 0) then + Exit(FParams[I].Value); + Result := ''; +end; + +procedure TBaseParams.SetItem(AIndex: Integer; const AValue: TNameValue); +begin + FParams[AIndex] := AValue; +end; + +procedure TBaseParams.SetParam(const AName, AValue: string); +var + I: Integer; + LItem: TNameValue; +begin + I := GetParamIndex(AName); + if (I >= 0) then + begin + LItem := FParams[I]; + LItem.Value := AValue; + FParams[I] := LItem; + end else + FParams.Add(TNameValue.Create(AName, AValue)); +end; + +procedure TBaseParams.Sort(const AComparison: TNameValueComparison); +var + LComparer: INameValueComparer; +begin + if Assigned(AComparison) then + LComparer := TNameValueComparer.Create(AComparison) + else + LComparer := TNameValueComparer.Create( + function(const Left, Right: TNameValue): Integer + begin + Result := CompareStr(Left.Name, Right.Name, TLocaleOptions.loInvariantLocale); + end); + + FParams.Sort(LComparer); +end; + +{ THttpUrlParams } + +constructor THttpUrlParams.Create; +begin + inherited Create; + + // RFC 3986 / WHATWG application/x-www-form-urlencoded: + // key 与 value 内含的 reserved/非 unreserved 字符都必须 percent-encode, + // 否则 key 中的 '&'/'='/'#' 等会被服务端误解析 (参数注入风险). + // 与 Go url.Values.Encode / Python urlencode / Java URLEncoder 等主流库默认行为一致. + FEncodeName := True; + FEncodeValue := True; +end; + +function THttpUrlParams.Decode(const AEncodedParams: string; AClear: Boolean): Boolean; +var + p, pEnd, q: PChar; + LName, LValue: string; + LSize, LDecodedCount: Integer; +begin + if AClear then + FParams.Clear; + + LDecodedCount := 0; + p := PChar(AEncodedParams); + pEnd := p + Length(AEncodedParams); + while (p < pEnd) do + begin + // WHATWG application/x-www-form-urlencoded parser: 按 '&' 拆分并忽略空片段. + while (p < pEnd) and (p^ = '&') do + Inc(p); + if (p >= pEnd) then Break; + + q := p; + LSize := 0; + while (p < pEnd) and (p^ <> '=') and (p^ <> '&') do + begin + Inc(LSize); + Inc(p); + end; + SetString(LName, q, LSize); + LName := TCrossHttpUtils.UrlDecode(LName); + + if (p < pEnd) and (p^ = '=') then + begin + Inc(p); + + q := p; + LSize := 0; + while (p < pEnd) and (p^ <> '&') do + begin + Inc(LSize); + Inc(p); + end; + SetString(LValue, q, LSize); + LValue := TCrossHttpUtils.UrlDecode(LValue); + end else + begin + LValue := ''; + end; + + Add(LName, LValue, True); + Inc(LDecodedCount); + end; + + Result := (LDecodedCount > 0); +end; + +function THttpUrlParams.Encode: string; +var + I: Integer; + LName, LValue: string; +begin + Result := ''; + for I := 0 to FParams.Count - 1 do + begin + if (I > 0) then + Result := Result + '&'; + + if FEncodeName then + LName := TCrossHttpUtils.UrlEncode(FParams[I].Name) + else + LName := FParams[I].Name; + Result := Result + LName; + + if FEncodeValue then + LValue := TCrossHttpUtils.UrlEncode(FParams[I].Value) + else + LValue := FParams[I].Value; + if (LValue <> '') then + Result := Result + '=' + LValue; + end; +end; + +{ THttpHeader } + +function THttpHeader.Decode(const AEncodedParams: string; AClear: Boolean): Boolean; +const + CR = #13; + LF = #10; +var + P, PEnd, LLineStart, LColonPos, LValueStart, LValueEnd: PChar; + LCh: Char; + LName, LValue: string; + LLineValid, LInName: Boolean; + LDecodedCount: Integer; +begin + if AClear then + FParams.Clear; + + LDecodedCount := 0; + P := PChar(AEncodedParams); + PEnd := P + Length(AEncodedParams); + + // 单趟状态机解析 (RFC 7230 §3): 每行字符仅访问 1 次, 同时完成 + // 1) CRLF 边界检测: bare-CR / bare-LF 立即拒绝 (Exit(False)), + // 防御 \r\r\n\n 等走私序列及上下游切分不一致 + // 2) ':' 定位 (切 name / value) + // 3) value 前后 OWS 跳过 + 尾随 OWS 自动 trim + // 4) name 每字节 token 校验 + value 每字节 CTL 校验 + // 非法行整行跳过 (仅限 name/value 校验失败, 不含 bare-CR/LF), + // 与 THttpHeader.Encode 过滤策略对称, 作为深度防御. + while (P < PEnd) do + begin + LLineStart := P; + LColonPos := nil; + LValueStart := nil; + LValueEnd := nil; + LLineValid := True; + LInName := True; + + // 内层: 逐字节扫描本行, 直到 CRLF 或 PEnd + while (P < PEnd) do + begin + LCh := P^; + + if (LCh = CR) then + begin + if (P + 1 < PEnd) and ((P + 1)^ = LF) then + Break; // 完整 CRLF: 退出内层, P 仍指向 CR + // bare-CR: 立即拒绝, 防御 \r\r\n\n 等走私序列 + if AClear then FParams.Clear; + Exit(False); + end; + + if (LCh = LF) then + begin + // bare-LF: 立即拒绝 + if AClear then FParams.Clear; + Exit(False); + end; + + if LInName then + begin + if (LCh = ':') then + begin + LColonPos := P; + LInName := False; + end else + if not TCrossHttpUtils.IsTokenChar(LCh) then + // name 段非 token 字符 (含 OWS / CTL / 非 ASCII 等) → 非法 + LLineValid := False; + end else + begin + // value 段: 前导 OWS 跳过, 记录首/末非 OWS 位置, 同时校验 CTL + if (LCh <> ' ') and (LCh <> #9) then + begin + if (LValueStart = nil) then + LValueStart := P; + LValueEnd := P + 1; // exclusive: 最后非 OWS 字符之后位置 + if not TCrossHttpUtils.IsHeaderValueChar(LCh) then + LLineValid := False; + end; + end; + + Inc(P); + end; + + // 退出内层: P 指向 CR (CRLF 完整) 或 P >= PEnd (末尾无 CRLF). + // 末尾无 CRLF 的残行也按相同规则尝试入库, 兼容 multipart part header + // 等调用方剥掉块终止符 \r\n\r\n 后再喂入的字符串. 主路径 HTTP + // request/response header 末尾必带空行 \r\n, 始终走 CRLF 完整分支, + // 严格性不变. + if (P < PEnd) then + Inc(P, 2); // 跳过 CRLF; PEnd 路径 P 已等于 PEnd, 外层 while 自然退出 + + if not LLineValid then Continue; + + // 空行: header 块结束标记, 跳过. + // CRLF 完整路径: LLineStart 指向被消费 CRLF 的位置 (即 P - 2) + // PEnd 路径 : LLineStart 等于 P (本行 0 字节) + if (LLineStart = P) or (LLineStart = P - 2) then Continue; + + // 必须出现过 ':' + if (LColonPos = nil) then Continue; + + // name 不能为空 + if (LColonPos = LLineStart) then Continue; + + SetString(LName, LLineStart, LColonPos - LLineStart); + + if (LValueStart = nil) then + LValue := '' + else + SetString(LValue, LValueStart, LValueEnd - LValueStart); + + Add(LName, LValue, True); + Inc(LDecodedCount); + end; + + Result := (LDecodedCount > 0); +end; + +function THttpHeader.Encode: string; +var + I: Integer; + LName, LValue: string; +begin + // 防御 HTTP 响应拆分 (Response Splitting): + // Header name 必须是 RFC 7230 token, value 不允许 CR/LF/CTL. + // 非法 entry 直接跳过 (业务方应在写入前自行 sanitize), 避免拼到 wire 上注入伪造响应. + Result := ''; + for I := 0 to FParams.Count - 1 do + begin + LName := FParams[I].Name; + LValue := FParams[I].Value; + + if not TCrossHttpUtils.IsValidHeaderName(LName) then Continue; + if not TCrossHttpUtils.IsValidHeaderValue(LValue) then Continue; + + Result := Result + LName + ': ' + LValue + #13#10; + end; + Result := Result + #13#10; +end; + +{ TDelimitParams } + +constructor TDelimitParams.Create(const ADelimiter: Char; const AUrlEncode: Boolean); +begin + FDelimiter := ADelimiter; + FUrlEncode := AUrlEncode; + + inherited Create; +end; + +constructor TDelimitParams.Create(const AEncodedParams: string; + const ADelimiter: Char; const AUrlEncode: Boolean); +begin + FDelimiter := ADelimiter; + FUrlEncode := AUrlEncode; + + inherited Create(AEncodedParams); +end; + +function TDelimitParams.Decode(const AEncodedParams: string; AClear: Boolean): Boolean; +var + p, pEnd, q: PChar; + LName, LValue: string; + LSize, LDecodedCount: Integer; +begin + if AClear then + FParams.Clear; + + LDecodedCount := 0; + p := PChar(AEncodedParams); + pEnd := p + Length(AEncodedParams); + while (p < pEnd) do + begin + q := p; + LSize := 0; + while (p < pEnd) and (p^ <> '=') do + begin + Inc(LSize); + Inc(p); + end; + SetString(LName, q, LSize); + // 跳过多余的'=' + while (p < pEnd) and (p^ = '=') do + Inc(p); + + q := p; + LSize := 0; + while (p < pEnd) and (p^ <> FDelimiter) do + begin + Inc(LSize); + Inc(p); + end; + SetString(LValue, q, LSize); + if FUrlEncode then + LValue := TCrossHttpUtils.UrlDecode(LValue); + // 跳过多余的';' + while (p < pEnd) and ((p^ = FDelimiter) or (p^ = ' ')) do + Inc(p); + + Add(LName, LValue); + Inc(LDecodedCount); + end; + + Result := (LDecodedCount > 0); +end; + +function TDelimitParams.Encode: string; +var + I: Integer; + LValue: string; +begin + Result := ''; + for I := 0 to FParams.Count - 1 do + begin + if (I > 0) then + Result := Result + FDelimiter + ' '; + LValue := FParams[I].Value; + if FUrlEncode then + LValue := TCrossHttpUtils.UrlEncode(LValue); + Result := Result + FParams[I].Name + '=' + LValue; + end; +end; + +{ TRequestCookies } + +function TRequestCookies.Decode(const AEncodedParams: string; AClear: Boolean): Boolean; +var + LParsedParams: TList; + LItem: TNameValue; + LPos, LLen, LPairEnd, LEqualsPos, LDecodedCount: Integer; + LPair: string; + LName, LValue: string; + LNormalizedValue: string; +begin + LDecodedCount := 0; + Result := False; + // 先解析到临时列表,确保整行 Cookie 全部合法后再提交,避免失败时留下半解析数据。 + LParsedParams := TList.Create; + try + LLen := Length(AEncodedParams); + LPos := 1; + while (LPos <= LLen) do + begin + // 跳过空白字符(空格和制表符) + while (LPos <= LLen) and CharInSet(AEncodedParams[LPos], [' ', #9]) do + Inc(LPos); + if (LPos > LLen) then Break; + + LPairEnd := LPos; + // 查找分号分隔符, 确定当前 cookie-pair 的结束位置 + while (LPairEnd <= LLen) and (AEncodedParams[LPairEnd] <> ';') do + Inc(LPairEnd); + + // 提取当前 cookie-pair 字符串 + LPair := Copy(AEncodedParams, LPos, LPairEnd - LPos); + // 查找等号位置, 用于分割 name 和 value + LEqualsPos := Pos('=', LPair); + // 如果没有等号或等号在第一个位置(name 为空), 则认为格式非法 + if (LEqualsPos <= 1) then + begin + if AClear then FParams.Clear; + Exit; + end; + + // 提取 name 部分(等号之前的内容) + LName := Copy(LPair, 1, LEqualsPos - 1); + // 提取 value 部分(等号之后的所有内容) + LValue := Copy(LPair, LEqualsPos + 1, MaxInt); + // 校验 name 是否为合法的 HTTP token, 以及 value 是否为合法的 cookie 值 + if not _IsHttpToken(LName) + or not _TryNormalizeCookieValue(LValue, LNormalizedValue) then + begin + if AClear then FParams.Clear; + Exit; + end; + + LParsedParams.Add(TNameValue.Create(LName, LNormalizedValue)); + LPos := LPairEnd + 1; + Inc(LDecodedCount); + end; + + // 所有 cookie-pair 均校验通过后,才按 AClear 语义提交到 FParams。 + if AClear then + FParams.Clear; + for LItem in LParsedParams do + Add(LItem.Name, LItem.Value); + Result := (LDecodedCount > 0); + finally + FreeAndNil(LParsedParams); + end; +end; + +function TRequestCookies.Encode: string; +var + I: Integer; + LName, LValue: string; +begin + Result := ''; + for I := 0 to FParams.Count - 1 do + begin + if (I > 0) then + Result := Result + '; '; + LName := FParams[I].Name; + LValue := FParams[I].Value; + if not _IsHttpToken(LName) then + raise Exception.CreateFmt('Invalid cookie name: %s', [LName]); + if not _IsCookieOctets(LValue) then + raise Exception.CreateFmt('Invalid cookie value: %s', [LName]); + Result := Result + LName + '=' + LValue; + end; +end; + +{ TResponseCookie } + +constructor TResponseCookie.Create(const AName, AValue: string; + AMaxAge: Integer; const APath, ADomain: string; AHttpOnly, ASecure: Boolean); +begin + Self.Name := AName; + Self.Value := AValue; + Self.MaxAge := AMaxAge; + Self.Path := APath; + Self.Domain := _NormalizeCookieDomain(ADomain); + Self.HttpOnly := AHttpOnly; + Self.Secure := ASecure; +end; + +constructor TResponseCookie.Create(const ACookieData, ADomain: string); + + procedure SetExpires(const AValue: string); + var + LMaxAge: Integer; + begin + if (Self.MaxAge = 0) then + begin + LMaxAge := TCrossHttpUtils.RFC1123_StrToDate(AValue).SecondsDiffer(Now); + if (LMaxAge > 0) then + Self.MaxAge := LMaxAge; + end; + end; + + procedure SetMaxAge(const AValue: string); + var + LMaxAge: Integer; + begin + if _TryParseCookieMaxAge(AValue, LMaxAge) then + Self.MaxAge := LMaxAge; + end; + + procedure SetPath(const AValue: string); + begin + if (AValue <> '') and (AValue[1] = '/') and _IsCookieAvValue(AValue) then + Self.Path := AValue; + end; + + procedure SetDomain(const AValue: string); + var + LDomain: string; + begin + LDomain := _NormalizeCookieDomain(AValue); + if (LDomain <> '') then + Self.Domain := LDomain; + end; + +var + LValues: TArray; + I: Integer; + LPos: Integer; + LName: string; + LValue: string; +begin + Self.Name := ''; + Self.Value := ''; + Self.MaxAge := 0; + Self.Path := '/'; + Self.Domain := _NormalizeCookieDomain(ADomain); + Self.HttpOnly := False; + Self.Secure := False; + + LValues := ACookieData.Split([Char(';')], Char('"')); + if Length(LValues) = 0 then Exit; + + LPos := LValues[0].IndexOf(Char('=')); + if (LPos <= 0) then Exit; + + Self.Name := LValues[0].Substring(0, LPos).Trim; + if not _IsHttpToken(Self.Name) + or not _TryNormalizeCookieValue(LValues[0].Substring(LPos + 1).Trim, Self.Value) then + begin + Self.Name := ''; + Self.Value := ''; + Exit; + end; + + for I := 1 to High(LValues) do + begin + LPos := LValues[I].IndexOf(Char('=')); + if LPos > 0 then + begin + LName := LValues[I].Substring(0, LPos).Trim; + LValue := LValues[I].Substring(LPos + 1).Trim; + if (LValue.Length > 1) and (LValue.Chars[0] = '"') and (LValue[High(LValue)] = '"') then + LValue := LValue.Substring(1, LValue.Length - 2); + end + else + begin + LName := LValues[I].Trim; + LValue := ''; + end; + + if TStrUtils.SameText(LName, 'Max-Age') then + SetMaxAge(LValue) + else if TStrUtils.SameText(LName, 'Expires') then + SetExpires(LValue) + else if TStrUtils.SameText(LName, 'Path') then + SetPath(LValue) + else if TStrUtils.SameText(LName, 'Domain') then + SetDomain(LValue) + else if TStrUtils.SameText(LName, 'HttpOnly') then + Self.HttpOnly := True + else if TStrUtils.SameText(LName, 'Secure') then + Self.Secure := True; + end; +end; + +function TResponseCookie.Encode: string; +begin + if not _IsHttpToken(Self.Name) then + raise Exception.CreateFmt('Invalid cookie name: %s', [Self.Name]); + if not _IsCookieOctets(Self.Value) then + raise Exception.CreateFmt('Invalid cookie value: %s', [Self.Value]); + if not _IsCookieAvValue(Self.Path) then + raise Exception.CreateFmt('Invalid cookie path: %s', [Self.Name]); + if (Self.Path <> '') and (Self.Path[1] <> '/') then + raise Exception.CreateFmt('Invalid cookie path: %s', [Self.Name]); + if not _IsCookieAvValue(Self.Domain) then + raise Exception.CreateFmt('Invalid cookie domain: %s', [Self.Name]); + + Result := Self.Name + '=' + Self.Value; + + if (Self.MaxAge > 0) then + Result := Result + '; Max-Age=' + Self.MaxAge.ToString; + if (Self.Path <> '') then + Result := Result + '; Path=' + Self.Path; + if (Self.Domain <> '') then + Result := Result + '; Domain=' + Self.Domain; + if Self.HttpOnly then + Result := Result + '; HttpOnly'; + if Self.Secure then + Result := Result + '; Secure'; +end; + +{ TFormField } + +constructor TFormField.Create; +begin + FValueOwned := True; +end; + +destructor TFormField.Destroy; +begin + FreeValue; + + inherited; +end; + +procedure TFormField.FreeValue; +begin + if FValueOwned and Assigned(FValue) then + FreeAndNil(FValue); +end; + +function TFormField.AsBytes: TBytes; +var + LBufSize: Integer; +begin + if (FValue = nil) or (FValue.Size <= 0) then Exit(nil); + + if (FValue is TBytesStream) then + begin + Result := TBytesStream(FValue).Bytes; + SetLength(Result, FValue.Size); + end else + begin + FValue.Position := 0; + LBufSize := FValue.Size; + SetLength(Result, LBufSize); + FValue.ReadBuffer(Result, LBufSize); + end; +end; + +procedure TFormField.Assign(const ASource: TFormField); +begin + FreeValue; + + if (ASource = nil) then Exit; + + FName := ASource.FName; + FValueOwned := ASource.FValueOwned; + FIsTempFile := ASource.FIsTempFile; + FFileName := ASource.FFileName; + FFilePath := ASource.FFilePath; + FContentType := ASource.FContentType; + FContentTransferEncoding := ASource.FContentTransferEncoding; + + if ASource.FValueOwned then + begin + if (FFilePath <> '') then + FValue := TFileUtils.OpenRead(FFilePath, fmShareDenyNone) + else + begin + FValue := TBytesStream.Create; + FValue.CopyFrom(ASource.FValue, 0); + end; + end else + begin + FValue := ASource.FValue; + end; +end; + +function TFormField.AsString(AEncoding: TEncoding): string; +begin + Result := TUtils.GetString(FValue, AEncoding); +end; + +{ THttpMultiPartFormData.TEnumerator } + +constructor THttpMultiPartFormData.TEnumerator.Create( + const AList: TList); +begin + inherited Create; + FList := AList; + FIndex := -1; +end; + +function THttpMultiPartFormData.TEnumerator.GetCurrent: TFormField; +begin + Result := FList[FIndex]; +end; + +function THttpMultiPartFormData.TEnumerator.MoveNext: Boolean; +begin + Inc(FIndex); + Result := (FIndex < FList.Count); +end; + +{ THttpMultiPartFormData } + +constructor THttpMultiPartFormData.Create; +begin + FDecodeState := dsBoundary; + SetLength(FCurrentPartHeader, MAX_PART_HEADER); + FCurrentPartHeaderLen := 0; + FPartFields := TObjectList.Create(True); + FAutoDeleteFiles := True; + FMaxPartDataSize := 0; + FCurrentPartDataSize := 0; +end; + +function THttpMultiPartFormData.Decode( + const AStream: TStream): TFormDataDecodeResult; +const + BUF_SIZE = 1024 * 32; +var + LBuffer: array [0..BUF_SIZE - 1] of Byte; + N: Integer; +begin + while True do + begin + N := AStream.Read(LBuffer[0], BUF_SIZE); + Result := Decode(@LBuffer[0], N); + + if (Result in [frComplete, frFailed]) + or (N < BUF_SIZE) then Exit; + end; +end; + +destructor THttpMultiPartFormData.Destroy; +begin + Clear; + FCurrentPartHeader := nil; + FCurrentPartField := nil; + FreeAndNil(FPartFields); + inherited; +end; + +function THttpMultiPartFormData.AddField(const AField: TFormField): TFormField; +begin + FPartFields.Add(AField); + Result := AField; +end; + +function THttpMultiPartFormData.AddField(const AFieldName: string; + const AValue: TBytes): TFormField; +begin + Result := TFormField.Create; + Result.FName := AFieldName; + Result.FValueOwned := True; + Result.FValue := TBytesStream.Create(AValue); + Result.FContentType := TMediaType.APPLICATION_OCTET_STREAM; + + FPartFields.Add(Result); +end; + +function THttpMultiPartFormData.AddField(const AFieldName, AValue: string): TFormField; +begin + Result := TFormField.Create; + Result.FName := AFieldName; + Result.FValueOwned := True; + Result.FValue := TBytesStream.Create(TEncoding.UTF8.GetBytes(AValue)); + + FPartFields.Add(Result); +end; + +function THttpMultiPartFormData.AddFile(const AFieldName, AFileName: string; + const AStream: TStream; const AOwned: Boolean): TFormField; +begin + Result := TFormField.Create; + Result.FName := AFieldName; + Result.FFileName := AFileName; + Result.FValueOwned := AOwned; + Result.FValue := AStream; + Result.FContentType := TCrossHttpUtils.GetFileMIMEType(AFileName); + + FPartFields.Add(Result); +end; + +function THttpMultiPartFormData.AddFile(const AFieldName, AFileName: string): TFormField; +begin + Result := AddFile(AFieldName, + ExtractFileName(AFileName), + TFileUtils.OpenRead(AFileName, fmShareDenyNone), + True); + Result.FFilePath := AFileName; +end; + +procedure THttpMultiPartFormData.Assign(const ASource: THttpMultiPartFormData); +var + LSrcField, LNewField: TFormField; +begin + Clear; + + Boundary := ASource.Boundary; + + for LSrcField in ASource do + begin + LNewField := TFormField.Create; + LNewField.Assign(LSrcField); + + AddField(LNewField); + end; +end; + +function THttpMultiPartFormData.AsBytes(const AFieldName: string; + out AValue: TBytes): Boolean; +var + LField: TFormField; +begin + Result := FindField(AFieldName, LField); + if Result then + AValue := LField.AsBytes + else + AValue := nil; +end; + +function THttpMultiPartFormData.AsBytes(const AFieldName: string): TBytes; +begin + AsBytes(AFieldName, Result); +end; + +function THttpMultiPartFormData.AsStream(const AFieldName: string; + out AValue: TStream): Boolean; +var + LField: TFormField; +begin + Result := FindField(AFieldName, LField); + if Result then + begin + AValue := LField.Value; + if (AValue.Size > 0) then + AValue.Position := 0; + end else + AValue := nil; +end; + +function THttpMultiPartFormData.AsStream(const AFieldName: string): TStream; +begin + AsStream(AFieldName, Result); +end; + +function THttpMultiPartFormData.AsString(const AFieldName: string; + const AEncoding: TEncoding; out AValue: string): Boolean; +var + LField: TFormField; +begin + Result := FindField(AFieldName, LField); + if Result then + AValue := LField.AsString(AEncoding) + else + AValue := ''; +end; + +function THttpMultiPartFormData.AsString(const AFieldName: string; + out AValue: string): Boolean; +begin + Result := AsString(AFieldName, nil, AValue); +end; + +function THttpMultiPartFormData.AsString(const AFieldName: string; + const AEncoding: TEncoding): string; +begin + AsString(AFieldName, AEncoding, Result); +end; + +procedure THttpMultiPartFormData.Clear; +var + LField: TFormField; +begin + for LField in FPartFields do + begin + if FAutoDeleteFiles and (LField.FilePath <> '') + and FileExists(LField.FilePath) then + begin + LField.FreeValue; + + if LField.FIsTempFile then + DeleteFile(LField.FilePath); + end; + end; + + FPartFields.Clear; +end; + +function THttpMultiPartFormData.FindField(const AFieldName: string; + out AField: TFormField): Boolean; +var + I: Integer; +begin + I := GetItemIndex(AFieldName); + if (I >= 0) then + begin + AField := FPartFields[I]; + Exit(True); + end; + + AField := nil; + Result := False; +end; + +function THttpMultiPartFormData.GetItem(AIndex: Integer): TFormField; +begin + Result := FPartFields.Items[AIndex]; +end; + +function THttpMultiPartFormData.GetItemIndex(const AName: string): Integer; +var + I: Integer; +begin + for I := 0 to FPartFields.Count - 1 do + if TStrUtils.SameText(FPartFields[I].Name, AName) then Exit(I); + Result := -1; +end; + +function THttpMultiPartFormData.GetCount: Integer; +begin + Result := FPartFields.Count; +end; + +function THttpMultiPartFormData.GetDataSize: Integer; +var + LPartField: TFormField; +begin + Result := 0; + for LPartField in FPartFields do + Inc(Result, LPartField.FValue.Size); +end; + +function THttpMultiPartFormData.GetEnumerator: TEnumerator; +begin + Result := TEnumerator.Create(FPartFields); +end; + +function THttpMultiPartFormData.GetField(const AName: string): TFormField; +var + I: Integer; +begin + I := GetItemIndex(AName); + if (I >= 0) then + Exit(FPartFields[I]); + Result := nil; +end; + +procedure THttpMultiPartFormData.InitWithBoundary(const ABoundary: string); +begin + // Decode 返回 frFailed 后, 调用方应调用 InitWithBoundary 重用实例; + // Clear 会根据 AutoDeleteFiles 清理半解析的临时文件. + Clear; + + SetBoundary(ABoundary); + + FDecodeState := dsBoundary; + FBoundaryIndex := 0; + FPrevBoundaryIndex := 0; + FCurrentPartDataSize := 0; + FCurrentPartHeaderLen := 0; + FCurrentPartField := nil; + SetLength(FLookbehind, Length(FBoundaryBytes) + 8); +end; + +procedure THttpMultiPartFormData.Remove(AIndex: Integer); +begin + FPartFields.Delete(AIndex); +end; + +procedure THttpMultiPartFormData.Remove(const AFieldName: string); +var + I: Integer; +begin + I := GetItemIndex(AFieldName); + if (I >= 0) then + FPartFields.Delete(I); +end; + +procedure THttpMultiPartFormData.SetBoundary(const AValue: string); +begin + if (FBoundary <> AValue) then + begin + FBoundary := AValue; + FBoundary := FBoundary.Trim(['"']); + + // 第一块数据是紧跟着 HTTP HEADER 的, 前面没有多余的 #13#10 + FFirstBoundaryBytes := TEncoding.ASCII.GetBytes('--' + FBoundary); + + // 第二块及以后的数据 Boundary 前面都会有 #13#10 + FBoundaryBytes := TArrayUtils.Concat([13, 10], FFirstBoundaryBytes); + end; +end; + +function THttpMultiPartFormData.Decode(const ABuf: Pointer; ALen: Integer; out AConsumed: Integer): TFormDataDecodeResult; + function __NewFileID: string; + begin + Result := TUtils.GetGUID.ToLower; + end; + + function __InitFormFieldByHeader(AFormField: TFormField; const AHeader: string): Boolean; + var + LFieldHeader: THttpHeader; + LContentDisposition: string; + LMatch: TMatch; + begin + Result := False; + + LFieldHeader := THttpHeader.Create; + try + LFieldHeader.Decode(AHeader); + LContentDisposition := LFieldHeader['Content-Disposition']; + if (LContentDisposition = '') then Exit; + + AFormField.FContentType := LFieldHeader['Content-Type']; + + LMatch := TRegEx.Match(LContentDisposition, '\bname="(.*?)"(?=;|$)', [TRegExOption.roIgnoreCase]); + if LMatch.Success then + AFormField.FName := LMatch.Groups[1].Value; + + // 使用 Content-Type 来判断是否需要按文件保存更为准确 + // 前端通过流的方式提交, 可能不会传递 filename 属性, + // 这种情况收到的 AHeader 是这样的: + // Content-Disposition: form-data; name="test_content" + // Content-Type: application/octet-stream + // 这种数据也可以当成文件来储存, 随机给它分配一个文件名即可 + // 而普通的文本数据是不会有 Content-Type 的: + // Content-Disposition: form-data; name="test_text" + if (AFormField.FContentType <> '') then + begin + LMatch := TRegEx.Match(LContentDisposition, '\bfilename="(.*?)"(?=;|$)', [TRegExOption.roIgnoreCase]); + // 带 filename 属性的头: + // Content-Disposition: form-data; name="content"; filename="test.json" + // Content-Type: application/json + if LMatch.Success then + begin + AFormField.FFileName := TPathUtils.GetFileName(LMatch.Groups[1].Value); + AFormField.FFilePath := TPathUtils.Combine(FStoragePath, + __NewFileID + TPathUtils.GetExtension(AFormField.FFileName)); + end else + begin + AFormField.FFileName := __NewFileID + '.bin'; + AFormField.FFilePath := TPathUtils.Combine(FStoragePath, + AFormField.FFileName); + end; + + AFormField.FIsTempFile := True; + AFormField.FValue := TFileUtils.OpenCreate(AFormField.FFilePath); + end else + AFormField.FValue := TBytesStream.Create(nil); + + AFormField.FValueOwned := True; + // 注意: Content-Transfer-Encoding (base64/quoted-printable) 仅存储不解码, + // dsPartData 阶段总是按原始字节写入, 如需支持非二进制传输编码需在此增加解码层. + AFormField.FContentTransferEncoding := LFieldHeader['Content-Transfer-Encoding']; + finally + FreeAndNil(LFieldHeader); + end; + + Result := True; + end; +var + C: Byte; + I, LSize: Integer; + P: PByte; + LPartHeader: string; +begin + AConsumed := 0; + if (FBoundaryBytes = nil) then Exit(frFailed); + + (* + *************************************** + ***** multipart/form-data数据格式 ***** + *************************************** + + # 请求头, 这个是必须的, 需要指定Content-Type为multipart/form-data, 指定唯一边界值 + Content-Type: multipart/form-data; boundary=${Boundary} + + # 请求体 + --${Boundary} + Content-Disposition: form-data; name="name of file" + Content-Type: application/octet-stream + + bytes of file + --${Boundary} + Content-Disposition: form-data; name="name of pdf"; filename="pdf-file.pdf" + Content-Type: application/octet-stream + + bytes of pdf file + --${Boundary} + Content-Disposition: form-data; name="key" + Content-Type: text/plain;charset=UTF-8 + + text encoded in UTF-8 + --${Boundary}-- + *) + + P := ABuf; + I := 0; + while (I < ALen) do + begin + C := P[I]; + case FDecodeState of + // 检测Boundary, 以确定第一块数据 + dsBoundary: + begin + // 第一块数据是紧跟着 HTTP HEADER 的, 前面没有多余的 #13#10 + // 所以这里检测时要跳过 2 个字节 + if (C = FFirstBoundaryBytes[FBoundaryIndex]) then + Inc(FBoundaryIndex) + else + FBoundaryIndex := 0; + // --Boundary + if (FBoundaryIndex >= Length(FFirstBoundaryBytes)) then + begin + FDecodeState := dsDetect; + FLineEndState := lesCR1; + FBoundaryIndex := 0; + FPostBoundaryState := pbsDetect; + end; + end; + + // 已通过Boundary检测, 继续检测以确定后面有数据还是已到结束 + dsDetect: + begin + // 严格匹配 #13#10 (Header) 或 --#13#10 (End), 拒绝其他任何字节 + case FPostBoundaryState of + pbsDetect: + if (C = 45) then // '-' + FPostBoundaryState := pbsEnd1 + else if (C = 13) then // '\r' + FPostBoundaryState := pbsHeader1 + else if (C = 32) or (C = 9) then // RFC 2046 LWSP + { stay in pbsDetect } + else + begin + AConsumed := I + 1; + Exit(frFailed); + end; + pbsEnd1: + if (C = 45) then // '-' + FPostBoundaryState := pbsEnd2 + else + begin + AConsumed := I + 1; + Exit(frFailed); + end; + pbsEnd2: + if (C = 13) then // '\r' + FPostBoundaryState := pbsEnd3 + else + begin + AConsumed := I + 1; + Exit(frFailed); + end; + pbsEnd3: + if (C = 10) then // '\n' → --Boundary--#13#10 + begin + FDecodeState := dsBoundary; + FLineEndState := lesCR1; + FBoundaryIndex := 0; + FPostBoundaryState := pbsDetect; + AConsumed := I + 1; + Exit(frComplete); + end else + begin + AConsumed := I + 1; + Exit(frFailed); + end; + pbsHeader1: + if (C = 10) then // '\n' → --Boundary#13#10 + begin + FCurrentPartHeaderLen := 0; + FDecodeState := dsPartHeader; + FLineEndState := lesCR1; + FBoundaryIndex := 0; + FPostBoundaryState := pbsDetect; + end else + begin + AConsumed := I + 1; + Exit(frFailed); + end; + end; + end; + + dsPartHeader: + begin + FCurrentPartHeader[FCurrentPartHeaderLen] := C; + Inc(FCurrentPartHeaderLen); + + // 状态机严格匹配 #13#10#13#10 序列 + case FLineEndState of + lesCR1: if (C = 13) then FLineEndState := lesLF1; + lesLF1: + if (C = 10) then FLineEndState := lesCR2 + else if (C <> 13) then FLineEndState := lesCR1; + lesCR2: + if (C = 13) then FLineEndState := lesLF2 + else FLineEndState := lesCR1; + lesLF2: + if (C = 10) then + begin + FLineEndState := lesCR1; + // 块头部结束 #13#10#13#10 + // 块头部通常采用UTF8编码 + LPartHeader := TUtils.GetString(@FCurrentPartHeader[0], FCurrentPartHeaderLen - 4{#13#10#13#10}); + FCurrentPartHeaderLen := 0; + FCurrentPartField := TFormField.Create; + if not __InitFormFieldByHeader(FCurrentPartField, LPartHeader) then + begin + FreeAndNil(FCurrentPartField); + AConsumed := I + 1; + Exit(frFailed); + end; + FPartFields.Add(FCurrentPartField); + + FDecodeState := dsPartData; + FPartDataBegin := -1; + FBoundaryIndex := 0; + FPrevBoundaryIndex := 0; + FCurrentPartDataSize := 0; + end else + if (C = 13) then FLineEndState := lesLF1 + else FLineEndState := lesCR1; + end; + + // 块头部过大, 视为非法数据 + if (FCurrentPartHeaderLen > MAX_PART_HEADER) then + begin + AConsumed := I + 1; + Exit(frFailed); + end; + end; + + dsPartData: + begin + // 如果这是一个新的数据块, 需要保存数据块起始位置 + if (FPartDataBegin < 0) then + FPartDataBegin := I; + + // 检测Boundary + if (C = FBoundaryBytes[FBoundaryIndex]) then + begin + Inc(FBoundaryIndex); + + if (FPrevBoundaryIndex > 0) then + begin + FLookbehind[FPrevBoundaryIndex] := C; + Inc(FPrevBoundaryIndex); + end; + end else + begin + // 上一个内存块结尾有部分有点像Boundary的数据, + // 进一步判断之后确定不是Boundary, 需要把这部分数据写入Field中 + if (FPrevBoundaryIndex > 0) then + begin + FCurrentPartField.FValue.Write(FLookbehind[0], FPrevBoundaryIndex); + Inc(FCurrentPartDataSize, FPrevBoundaryIndex); + // 检查单 Part Body 大小是否超限 (与块结尾检查对称) + if (FMaxPartDataSize > 0) and (FCurrentPartDataSize > FMaxPartDataSize) then + begin + AConsumed := I + 1; + Exit(frFailed); + end; + FPrevBoundaryIndex := 0; + FPartDataBegin := I; + end; + + if (FBoundaryIndex > 0) then + begin + // 之前检测到有一部分数据跟Boundary有点像, 但是到这个字节可以确定之前 + // 这部分数据并不是Boundary, 需要把这部分数据写入Field中 + FCurrentPartField.FValue.Write(P[FPartDataBegin], I - FPartDataBegin); + Inc(FCurrentPartDataSize, I - FPartDataBegin); + FPartDataBegin := I; + + FBoundaryIndex := 0; + + // 再次检测Boundary + if (C = FBoundaryBytes[FBoundaryIndex]) then + Inc(FBoundaryIndex); + end; + end; + + // 如果已到内存块结束或者已经解析出一个完整的数据块 + if (I >= ALen - 1) or (FBoundaryIndex >= Length(FBoundaryBytes)) then + begin + // 将内存块数据存入Field中 + if (FPartDataBegin >= 0) then + begin + LSize := I - FPartDataBegin - FBoundaryIndex + 1; + if (LSize > 0) then + begin + FCurrentPartField.FValue.Write(P[FPartDataBegin], LSize); + Inc(FCurrentPartDataSize, LSize); + end; + end; + + // 检查单 Part Body 大小是否超限 (必须在状态切换前检查) + if (FMaxPartDataSize > 0) and (FCurrentPartDataSize > FMaxPartDataSize) then + begin + AConsumed := I + 1; + Exit(frFailed); + end; + + // 已解析出一个完整的数据块 + if (FBoundaryIndex >= Length(FBoundaryBytes)) then + begin + FCurrentPartField.FValue.Position := 0; + FDecodeState := dsDetect; + FBoundaryIndex := 0; + FPrevBoundaryIndex := 0; + FCurrentPartDataSize := 0; + end else + // 已解析到本内存块结尾, 但是发现了部分有点像Boundary的数据 + // 将其保存起来 + if (FPrevBoundaryIndex = 0) and (FBoundaryIndex > 0) then + begin + FPrevBoundaryIndex := FBoundaryIndex; + Move(P[I - FBoundaryIndex + 1], FLookbehind[0], FBoundaryIndex); + end; + + // 数据块起始位置需要在之后决定 + FPartDataBegin := -1; + end; + end; + end; + + Inc(I); + end; + + AConsumed := ALen; + Result := frContinue; +end; + +function THttpMultiPartFormData.Decode(const ABuf: Pointer; ALen: Integer): TFormDataDecodeResult; +var + LDummy: Integer; +begin + // 兼容旧调用方: 丢弃 consumed; 仅在调用方明确知道 multipart 数据帧严格对齐时使用. + Result := Decode(ABuf, ALen, LDummy); +end; + +{ THttpMultiPartFormStream.TFormFieldEx } + +function THttpMultiPartFormStream.TFormFieldEx.DataSize: Int64; +begin + if (Field <> nil) and (Field.Value <> nil) then + Result := Field.Value.Size + else + Result := 0; +end; + +function THttpMultiPartFormStream.TFormFieldEx.HeaderSize: Integer; +begin + Result := Length(Header); +end; + +function THttpMultiPartFormStream.TFormFieldEx.TotalSize: Int64; +begin + Result := HeaderSize + DataSize; +end; + +{ THttpMultiPartFormStream } + +constructor THttpMultiPartFormStream.Create( + const AMultiPartFormData: THttpMultiPartFormData; const AOwned: Boolean); +begin + FMultiPartFormData := AMultiPartFormData; + FOwned := AOwned; + + _Init; +end; + +destructor THttpMultiPartFormStream.Destroy; +begin + if FOwned and (FMultiPartFormData <> nil) then + FreeAndNil(FMultiPartFormData); + + inherited; +end; + +function THttpMultiPartFormStream.Read(var ABuffer; ACount: Longint): Longint; +var + LReadCount, LPos, LHeaderPos, LDataPos, LCount, LHeaderCount, LDataCount, LEndPos, LEndCount: Int64; + LFieldIndex: Integer; + LFieldEx: TFormFieldEx; + P: PByte; +begin + Result := 0; + if (FPosition < 0) or (FPosition >= FSize) or (ACount <= 0) then Exit; + + // 计算实际还能读取多少字节数据 + if (ACount + FPosition <= FSize) then + LReadCount := ACount + else + LReadCount := FSize - FPosition; + + Result := LReadCount; + + P := @ABuffer; + + {$region '从 Field 中读取数据'} + while (LReadCount > 0) do + begin + LFieldIndex := _GetFiledIndexByOffset(FPosition); + if (LFieldIndex < 0) then Break; + + LFieldEx := FFormFieldExArray[LFieldIndex]; + + // 计算要读取的数据位于这个 Field 的偏移 + LPos := FPosition - LFieldEx.Offset; + + // 计算需要从这个 Field 中读取多少字节 + LCount := Min(LFieldEx.TotalSize - LPos, LReadCount); + + // 计算分别需要从 Header 和 Data 中读取多少字节 + if (LPos < LFieldEx.HeaderSize) then + begin + LHeaderPos := LPos; + LDataPos := 0; + + LHeaderCount := Min(LFieldEx.HeaderSize - LHeaderPos, LCount); + LDataCount := LCount - LHeaderCount; + end else + begin + LHeaderPos := -1; + LDataPos := LPos - LFieldEx.HeaderSize; + + LHeaderCount := 0; + LDataCount := LCount - LHeaderCount; + end; + + // 读取 Header + if (LHeaderCount > 0) then + begin + Move(LFieldEx.Header[LHeaderPos], P^, LHeaderCount); + Inc(P, LHeaderCount); + Dec(LReadCount, LHeaderCount); + + Seek(LHeaderCount, soCurrent); + end; + + // 读取 Data + if (LDataCount > 0) then + begin + LFieldEx.Field.Value.Position := LDataPos; + LFieldEx.Field.Value.Read(P^, LDataCount); + Inc(P, LDataCount); + Dec(LReadCount, LDataCount); + + Seek(LDataCount, soCurrent); + end; + end; + {$endregion} + + // 从尾巴读取数据 + if (LReadCount > 0) then + begin + LEndPos := FPosition - FEndPos; + LEndCount := Min(Length(FMultiPartEnd) - LEndPos, LReadCount); + + if (LEndCount > 0) then + begin + Move(FMultiPartEnd[LEndPos], P^, LEndCount); +// Inc(P, LEndCount); +// Dec(LReadCount, LEndCount); + + Seek(LEndCount, soCurrent); + end; + end; +end; + +function THttpMultiPartFormStream.Seek(const AOffset: Int64; + AOrigin: TSeekOrigin): Int64; +begin + case AOrigin of + soBeginning: FPosition := AOffset; + soCurrent: Inc(FPosition, AOffset); + soEnd: FPosition := FSize + AOffset; + end; + + if (FPosition < 0) then + FPosition := -1; + + if (FPosition > FSize) then + FPosition := FSize; + + Result := FPosition; +end; + +function THttpMultiPartFormStream._GetFiledIndexByOffset( + const AOffset: Int64): Integer; +var + LOffset: Int64; + I: Integer; +begin + Result := -1; + if (AOffset < 0) or (AOffset >= FSize) then Exit; + + LOffset := 0; + + for I := 0 to High(FFormFieldExArray) do + begin + Inc(LOffset, FFormFieldExArray[I].TotalSize); + if (AOffset < LOffset) then Exit(I); + end; +end; + +procedure THttpMultiPartFormStream._Init; +var + I: Integer; + LFormFieldEx: TFormFieldEx; + LContentType, LPartHeaderStr: string; + LPartHeaderBytes, LBoundary: TBytes; + LOffset: Int64; +begin + { + --boundary_value + Content-Disposition: form-data; name="text_field" + + This is a simple text field. + + --boundary_value + Content-Disposition: form-data; name="binary_data" + Content-Type: application/octet-stream + + [Binary data goes here] + + --boundary_value + Content-Disposition: form-data; name="file_field"; filename="example.txt" + Content-Type: text/plain + + Contents of the example.txt file. + + --boundary_value + Content-Disposition: form-data; name="image"; filename="image.jpg" + Content-Type: image/jpeg + + [Binary image data] + + --boundary_value-- + } + // 检查 boundary, 如果没有则生成 + if (FMultiPartFormData.Boundary = '') then + begin + Randomize; + FMultiPartFormData.Boundary := '--DCSFormBoundary' + + IntToHex(Random(MaxInt), 8) + + IntToHex(Random(MaxInt), 8); + end; + + // 结尾数据 + FMultiPartEnd := TArrayUtils.Concat(FMultiPartFormData.FBoundaryBytes, [45, 45, 13, 10]); + + LOffset := 0; + FSize := 0; + FPosition := 0; + + {$region '生成Field的头'} + SetLength(FFormFieldExArray, FMultiPartFormData.Count); + + for I := 0 to FMultiPartFormData.Count - 1 do + begin + LFormFieldEx.Offset := LOffset; + LFormFieldEx.Field := FMultiPartFormData.Items[I]; + + if (I = 0) then + LBoundary := FMultiPartFormData.FFirstBoundaryBytes + else + LBoundary := FMultiPartFormData.FBoundaryBytes; + + // 'Content-Disposition: form-data; name="%s"; filename="%s"'#13#10 + + // 'Content-Type: %s'#13#10#13#10 + + LContentType := LFormFieldEx.Field.ContentType; + + LPartHeaderStr := Format( + 'Content-Disposition: form-data; name="%s"', [ + LFormFieldEx.Field.Name + ]); + if (LFormFieldEx.Field.FileName <> '') then + begin + LPartHeaderStr := LPartHeaderStr + + Format('; filename="%s"', [LFormFieldEx.Field.FileName]); + + if (LContentType = '') then + LContentType := TCrossHttpUtils.GetFileMIMEType(LFormFieldEx.Field.FileName); + end; + LPartHeaderStr := LPartHeaderStr + #13#10; + + if (LContentType <> '') then + begin + LPartHeaderStr := LPartHeaderStr + + Format('Content-Type: %s', [LContentType]) + + #13#10; + end; + LPartHeaderStr := LPartHeaderStr + #13#10; + + LPartHeaderBytes := TEncoding.UTF8.GetBytes(LPartHeaderStr); + + LFormFieldEx.Header := TArrayUtils.Concat([ + LBoundary, [13, 10], LPartHeaderBytes]); + + Inc(FSize, LFormFieldEx.HeaderSize); + Inc(FSize, LFormFieldEx.DataSize); + Inc(LOffset, LFormFieldEx.TotalSize); + + FFormFieldExArray[I] := LFormFieldEx; + end; + {$endregion} + + FEndPos := LOffset; + Inc(FSize, Length(FMultiPartEnd)); +end; + +{ TResponseCookies } + +procedure TResponseCookies.AddOrSet(const AName, AValue: string; + AMaxAge: Integer; const APath, ADomain: string; AHttpOnly, ASecure: Boolean); +begin + SetCookie(AName, TResponseCookie.Create(AName, AValue, AMaxAge, APath, ADomain, AHttpOnly, ASecure)); +end; + +function TResponseCookies.GetCookieIndex(const AName: string): Integer; +var + I: Integer; +begin + for I := 0 to Count - 1 do + if TStrUtils.SameText(Items[I].Name, AName) then Exit(I); + Result := -1; +end; + +procedure TResponseCookies.Remove(const AName: string); +var + I: Integer; +begin + I := GetCookieIndex(AName); + if (I >= 0) then + inherited Delete(I); +end; + +function TResponseCookies.GetCookie(const AName: string): TResponseCookie; +var + I: Integer; +begin + I := GetCookieIndex(AName); + if (I >= 0) then + Result := Items[I] + else + begin + Result := TResponseCookie.Create(AName, '', 0); + Add(Result); + end; +end; + +procedure TResponseCookies.SetCookie(const AName: string; + const Value: TResponseCookie); +var + I: Integer; +begin + I := GetCookieIndex(AName); + if (I >= 0) then + Items[I] := Value + else + Add(Value); +end; + +{ TSessionBase } + +constructor TSessionBase.Create(const AOwner: TSessionsBase; const ASessionID: string); +var + LNow: TDateTime; +begin + LNow := Now; + + FOwner := AOwner; + + SetSessionID(ASessionID); + SetCreateTime(LNow); + SetLastAccessTime(LNow); +end; + +function TSessionBase.Expired: Boolean; +begin + Result := (ExpiryTime > 0) and (Now.SecondsDiffer(LastAccessTime) >= ExpiryTime); +end; + +function TSessionBase.GetOwner: ISessions; +begin + Result := FOwner; +end; + +procedure TSessionBase.Touch; +begin + LastAccessTime := Now; +end; + +{ TSession } + +constructor TSession.Create(const AOwner: TSessionsBase; const ASessionID: string); +begin + FValues := TDictionary.Create; + + inherited Create(AOwner, ASessionID); +end; + +destructor TSession.Destroy; +begin + FreeAndNil(FValues); + inherited; +end; + +function TSession.GetCreateTime: TDateTime; +begin + Result := FCreateTime; +end; + +function TSession.GetExpiryTime: Integer; +begin + Result := FExpire; +end; + +function TSession.GetLastAccessTime: TDateTime; +begin + Result := FLastAccessTime; +end; + +function TSession.GetSessionID: string; +begin + Result := FSessionID; +end; + +function TSession.GetValue(const AName: string): string; +begin + if not FValues.TryGetValue(AName, Result) then + Result := ''; + FLastAccessTime := Now; +end; + +procedure TSession.SetCreateTime(const ACreateTime: TDateTime); +begin + FCreateTime := ACreateTime; +end; + +procedure TSession.SetExpiryTime(const AValue: Integer); +begin + FExpire := AValue; +end; + +procedure TSession.SetLastAccessTime(const ALastAccessTime: TDateTime); +begin + FLastAccessTime := ALastAccessTime; +end; + +procedure TSession.SetSessionID(const ASessionID: string); +begin + FSessionID := ASessionID; +end; + +procedure TSession.SetValue(const AName, AValue: string); +begin + if (AValue <> '') then + FValues.AddOrSetValue(AName, AValue) + else + FValues.Remove(AName); + FLastAccessTime := Now; +end; + +{ TSessionsBase } + +function TSessionsBase.AddSession(const ASessionID: string): ISession; +begin + Result := GetSessionClass.Create(Self, ASessionID); + Result.ExpiryTime := ExpiryTime; + AddSession(ASessionID, Result); +end; + +function TSessionsBase.AddSession: ISession; +begin + Result := AddSession(NewSessionID); +end; + +function TSessionsBase.ExistsSession(const ASessionID: string): Boolean; +var + LStuff: ISession; +begin + Result := ExistsSession(ASessionID, LStuff); +end; + +procedure TSessionsBase.RemoveSession(const ASessionID: string); +var + LSession: ISession; +begin + if ExistsSession(ASessionID, LSession) then + RemoveSession(LSession); +end; + +procedure TSessionsBase.RemoveSession(const ASession: ISession); +begin + RemoveSessions([ASession]); +end; + +{ TSessions } + +constructor TSessions.Create(ANewGUIDFunc: TFunc); +begin + FNewGUIDFunc := ANewGUIDFunc; + FSessions := TDictionary.Create; + FLocker := TReadWriteLock.Create; + FSessionClass := TSession; + CreateExpiredProcThread; +end; + +procedure TSessions.Clear; +begin + FSessions.Clear; +end; + +constructor TSessions.Create; +begin + Create(nil); +end; + +destructor TSessions.Destroy; +var + LTimeout: TStopwatch; +begin + FShutdown := True; + LTimeout := TStopwatch.StartNew; + while FExpiredProcRunning and (LTimeout.ElapsedMilliseconds < 5000) do Sleep(10); + + BeginWrite; + FSessions.Clear; + EndWrite; + FreeAndNil(FSessions); + + inherited; +end; + +procedure TSessions.AddSession(const ASessionID: string; ASession: ISession); +begin + if (ASession.ExpiryTime = 0) then + ASession.ExpiryTime := ExpiryTime; + FSessions.AddOrSetValue(ASessionID, ASession); +end; + +procedure TSessions.AfterClearExpiredSessions; +begin + +end; + +procedure TSessions.BeforeClearExpiredSessions; +begin + +end; + +procedure TSessions.BeginRead; +begin + FLocker.BeginRead; +end; + +procedure TSessions.BeginWrite; +begin + FLocker.BeginWrite; +end; + +procedure TSessions.EndRead; +begin + FLocker.EndRead; +end; + +procedure TSessions.EndWrite; +begin + FLocker.EndWrite; +end; + +function TSessions.ExistsSession(const ASessionID: string; + var ASession: ISession): Boolean; +begin + Result := FSessions.TryGetValue(ASessionID, ASession); + if Result then + ASession.Touch; +end; + +procedure TSessions.CreateExpiredProcThread; +begin + TAnonymousThread.Create( + procedure + var + LWatch: TStopwatch; + begin + FExpiredProcRunning := True; + try + LWatch := TStopwatch.StartNew; + while not FShutdown do + begin + // 每 1 分钟清理一次超时 Session + if (FExpire > 0) and (LWatch.Elapsed.TotalMinutes >= 1) then + begin + _ClearExpiredSessions; + LWatch.Reset; + LWatch.Start; + end; + Sleep(10); + end; + finally + FExpiredProcRunning := False; + end; + end).Start; +end; + +function TSessions.NewSessionID: string; +begin + if Assigned(FNewGUIDFunc) then + Result := FNewGUIDFunc() + else + Result := TUtils.GetGUID.ToLower; +end; + +function TSessions.OnCheckExpiredSession(const ASession: ISession): Boolean; +begin + Result := ASession.Expired; +end; + +function TSessions.GetCount: Integer; +begin + Result := FSessions.Count; +end; + +function TSessions.GetEnumerator: TEnumerator; +begin + Result := TDictionary.TValueEnumerator.Create(FSessions); +end; + +function TSessions.GetExpiryTime: Integer; +begin + Result := FExpire; +end; + +function TSessions.GetItem(const AIndex: Integer): ISession; +var + LIndex: Integer; + LPair: TPair; +begin + LIndex := 0; + for LPair in FSessions do + begin + if (LIndex = AIndex) then Exit(LPair.Value); + Inc(LIndex); + end; + Result := nil; +end; + +function TSessions.GetSession(const ASessionID: string): ISession; +var + LSessionID: string; +begin + LSessionID := ASessionID; + BeginWrite; + try + if (LSessionID = '') then + LSessionID := NewSessionID; + if not FSessions.TryGetValue(LSessionID, Result) then + begin + Result := FSessionClass.Create(Self, LSessionID); + Result.ExpiryTime := ExpiryTime; + AddSession(LSessionID, Result); + end; + finally + EndWrite; + end; + + Result.LastAccessTime := Now; +end; + +function TSessions.GetSessionClass: TSessionClass; +begin + Result := FSessionClass; +end; + +procedure TSessions.RemoveSessions(const ASessions: TArray); +var + LSession: ISession; +begin + for LSession in ASessions do + FSessions.Remove(LSession.SessionID); +end; + +procedure TSessions.SetExpiryTime(const Value: Integer); +begin + FExpire := Value; +end; + +procedure TSessions.SetSessionClass(const Value: TSessionClass); +begin + FSessionClass := Value; +end; + +procedure TSessions._ClearExpiredSessions; +var + LPair: TPair; + LDelSessions: TArray; +begin + BeginWrite; + try + BeforeClearExpiredSessions; + + LDelSessions := nil; + for LPair in FSessions do + begin + if FShutdown then Break; + + if OnCheckExpiredSession(LPair.Value) then + LDelSessions := LDelSessions + [LPair.Value]; + end; + RemoveSessions(LDelSessions); + + AfterClearExpiredSessions; + finally + EndWrite; + end; +end; + +end. diff --git a/Net/Net.CrossHttpServer.pas b/Net/Net.CrossHttpServer.pas index 539abb8..0b3d0bd 100644 --- a/Net/Net.CrossHttpServer.pas +++ b/Net/Net.CrossHttpServer.pas @@ -1,5879 +1,5879 @@ -{******************************************************************************} -{ } -{ Delphi cross platform socket library } -{ } -{ Copyright (c) 2017 WiNDDRiVER(soulawing@gmail.com) } -{ } -{ Homepage: https://github.com/winddriver/Delphi-Cross-Socket } -{ } -{******************************************************************************} -unit Net.CrossHttpServer; - -{$I zLib.inc} - -{ - Linux下需要安装zlib1g-dev开发包 - sudo apt-get install zlib1g-dev -} - -interface - -uses - Classes, - SysUtils, - Math, - Generics.Collections, - //ZLib, - {$IFDEF DELPHI} - ZLib, - {$ELSE} - DTF.StaticZLib, - {$ENDIF} - - Net.SocketAPI, - Net.CrossSocket.Base, - Net.CrossSocket, - Net.CrossServer, - Net.CrossHttpParams, - Net.CrossHttpUtils, - Net.CrossHttpParser, - - Utils.StrUtils, - Utils.IOUtils, - Utils.Hash, - Utils.RegEx, - Utils.SyncObjs, - Utils.ArrayUtils, - Utils.DateTime; - -const - CROSS_HTTP_SERVER_NAME = 'CrossHttpServer/3.0'; - MIN_COMPRESS_SIZE = 512; - WILDCARD_CHAR = '*'; - REGEX_CHARS: array of Char = [':', '*', '?', '(', ')', '[', '{', '|', '+', '.']; - -type - ECrossHttpException = class(Exception) - private - FStatusCode: Integer; - public - constructor Create(const AMessage: string; AStatusCode: Integer = 400); reintroduce; virtual; - constructor CreateFmt(const AMessage: string; const AArgs: array of const; AStatusCode: Integer = 400); reintroduce; virtual; - property StatusCode: Integer read FStatusCode write FStatusCode; - end; - - ICrossHttpServer = interface; - ICrossHttpRequest = interface; - ICrossHttpResponse = interface; - IHttpResponseQueueItem = interface; - - TCrossHttpServer = class; - TCrossHttpRequest = class; - TCrossHttpResponse = class; - THttpResponseQueueItem = class; - - /// - /// HTTP连接接口 - /// - ICrossHttpConnection = interface(ICrossServerConnection) - ['{72E9AC44-958C-4C6F-8769-02EA5EC3E9A8}'] - function GetRequest: ICrossHttpRequest; - function GetResponse: ICrossHttpResponse; - function GetServer: ICrossHttpServer; - function GetPending: Integer; - - /// - /// 请求对象 - /// - property Request: ICrossHttpRequest read GetRequest; - - /// - /// 响应对象 - /// - property Response: ICrossHttpResponse read GetResponse; - - /// - /// Server对象 - /// - property Server: ICrossHttpServer read GetServer; - - /// - /// 当前连接上"已开始解析但尚未完成响应"的请求数量 - /// (含正在处理中的与已入队等待发送的) - /// - property Pending: Integer read GetPending; - end; - - /// - /// 请求体类型 - /// - TBodyType = (btNone, btUrlEncoded, btMultiPart, btBinary); - - /// - /// HTTP请求接口 - /// - ICrossHttpRequest = interface - ['{B26B7E7B-6B24-4D86-AB58-EBC20722CFDD}'] - function GetConnection: ICrossHttpConnection; - function GetRawRequestText: string; - function GetRawPathAndQuery: string; - function GetMethod: string; - function GetPath: string; - function GetPathAndQuery: string; - function GetVersion: string; - function GetHeader: THttpHeader; - function GetCookies: TRequestCookies; - function GetSession: ISession; - function GetParams: THttpUrlParams; - function GetQuery: THttpUrlParams; - function GetQueryText: string; - function GetBody: TObject; - function GetRawBody: TStream; - function GetBodyType: TBodyType; - function GetKeepAlive: Boolean; - function GetAccept: string; - function GetAcceptEncoding: string; - function GetAcceptLanguage: string; - function GetReferer: string; - function GetUserAgent: string; - function GetIfModifiedSince: TDateTime; - function GetIfNoneMatch: string; - function GetRange: string; - function GetIfRange: string; - function GetAuthorization: string; - function GetXForwardedFor: string; - function GetContentLength: Int64; - function GetHostName: string; - function GetHostPort: Word; - function GetContentType: string; - function GetContentEncoding: string; - function GetRequestBoundary: string; - function GetRequestCmdLine: string; - function GetRequestConnection: string; - function GetTransferEncoding: string; - function GetIsChunked: Boolean; - function GetIsMultiPartFormData: Boolean; - function GetIsUrlEncodedFormData: Boolean; - function GetPostDataSize: Int64; - - /// - /// HTTP连接对象 - /// - property Connection: ICrossHttpConnection read GetConnection; - - /// - /// 原始请求数据 - /// - property RawRequestText: string read GetRawRequestText; - - /// - /// 原始请求路径及参数 - /// - property RawPathAndParams: string read GetRawPathAndQuery; - - /// - /// 请求方法 - /// - /// - /// GET - /// - /// - /// POST - /// - /// - /// PUT - /// - /// - /// DELETE - /// - /// - /// HEAD - /// - /// - /// OPTIONS - /// - /// - /// TRACE - /// - /// - /// CONNECT - /// - /// - /// PATCH - /// - /// - /// COPY - /// - /// - /// LINK - /// - /// - /// UNLINK - /// - /// - /// PURGE - /// - /// - /// LOCK - /// - /// - /// UNLOCK - /// - /// - /// PROPFIND - /// - /// - /// - property Method: string read GetMethod; - - /// - /// - /// 请求路径, 不包含参数部分 - /// - /// - /// 比如: /api/callapi1 - /// - /// - property Path: string read GetPath; - - /// - /// - /// 请求路径及参数 - /// - /// - /// 比如: /api/callapi1?aaa=111&bbb=222 - /// - /// - property PathAndQuery: string read GetPathAndQuery; - - /// - /// 请求版本: - /// - /// - /// HTTP/1.0 - /// - /// - /// HTTP/1.1 - /// - /// - /// - property Version: string read GetVersion; - - /// - /// HTTP请求头 - /// - property Header: THttpHeader read GetHeader; - - /// - /// 客户端传递过来的Cookies - /// - property Cookies: TRequestCookies read GetCookies; - - /// - /// Session对象 - /// - /// - /// - /// 只有在Server开启了Session支持的情况, 该属性才有效, 否则该属性为nil - /// - /// - /// 要开启Server的Session支持, 只需要设置Server.SessionIDCookieName不为空即可 - /// - /// - property Session: ISession read GetSession; - - /// - /// - /// 请求路径中定义的参数 - /// - /// - /// 比如定义了一个Get('/echo/:text', cb) 然后有一个请求为 /echo/hello, 那么 Params - /// 中就会有一个名为 'text', 值为 'hello' 的参数 - /// - /// - property Params: THttpUrlParams read GetParams; - - /// - /// 请求路径后形如?key1=value1&key2=value2的参数 - /// - property Query: THttpUrlParams read GetQuery; - - /// - /// - /// 请求路径中定义的参数 - /// - /// - property QueryText: string read GetQueryText; - - /// - /// 解析后的Body数据, 通过检查BodyType可以知道数据类型: - /// - /// - /// btNone(nil) - /// - /// - /// btUrlEncoded(TFormUrlEncoded) - /// - /// - /// btMultiPart(THttpMultiPartFormData) - /// - /// - /// btBinary(TMemoryStream) - /// - /// - /// - property Body: TObject read GetBody; - - /// - /// 原始Body数据流, 仅对btUrlEncoded和btBinary缓存; multipart/form-data返回nil - /// - /// - /// 调用方只读使用, 不负责释放 - /// - property RawBody: TStream read GetRawBody; - - /// - /// Body的类型, - /// - /// - /// btNone(nil) - /// - /// - /// btUrlEncoded(TFormUrlEncoded) - /// - /// - /// btMultiPart(THttpMultiPartFormData) - /// - /// - /// btBinary(TMemoryStream) - /// - /// - /// - property BodyType: TBodyType read GetBodyType; - - /// - /// KeepAliv标志 - /// - property KeepAlive: Boolean read GetKeepAlive; - - /// - /// 客户端能接收的数据种类 - /// - /// - /// image/webp,image/*,*/*;q=0.8 - /// - property Accept: string read GetAccept; - - /// - /// 客户端能接收的编码 - /// - /// - /// gzip, deflate, sdch - /// - property AcceptEncoding: string read GetAcceptEncoding; - - /// - /// 客户端能接收的语言 - /// - /// - /// zh-CN,zh;q=0.8 - /// - property AcceptLanguage: string read GetAcceptLanguage; - - /// - /// 参考地址, 描述该请求由哪个页面发出 - /// - property Referer: string read GetReferer; - - /// - /// 用户代理 - /// - /// - /// Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like - /// Gecko) Chrome/50.0.2661.102 Safari/537.36 - /// - property UserAgent: string read GetUserAgent; - - /// - /// 请求内容在浏览器端的缓存时间 - /// - property IfModifiedSince: TDateTime read GetIfModifiedSince; - - /// - /// 请求内容在浏览器端的标记 - /// - property IfNoneMatch: string read GetIfNoneMatch; - - /// - /// 请求分块传输 - /// - property Range: string read GetRange; - - /// - /// 请求分块传输时传往服务器的标记, 用于服务器比较数据是否已发生变化 - /// - property IfRange: string read GetIfRange; - - /// - /// 简单认证信息 - /// - property Authorization: string read GetAuthorization; - - /// - /// 通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段 - /// - property XForwardedFor: string read GetXForwardedFor; - - /// - /// 请求数据长度 - /// - property ContentLength: Int64 read GetContentLength; - - /// - /// 请求的主机名(域名、IP) - /// - property HostName: string read GetHostName; - - /// - /// 请求的主机端口 - /// - property HostPort: Word read GetHostPort; - - /// - /// 内容类型 - /// - property ContentType: string read GetContentType; - - /// - /// 请求命令行(也就是HTTP请求的第一行) - /// - property RequestCmdLine: string read GetRequestCmdLine; - - /// - /// 请求分界符 - /// - property RequestBoundary: string read GetRequestBoundary; - - /// - /// 传输编码 - /// - property TransferEncoding: string read GetTransferEncoding; - - /// - /// 内容编码 - /// - property ContentEncoding: string read GetContentEncoding; - - /// - /// 连接方式 - /// - property RequestConnection: string read GetRequestConnection; - - /// - /// 请求数据是否使用块编码 - /// - property IsChunked: Boolean read GetIsChunked; - - /// - /// 请求数据是使用 multipart/form-data 方式提交的 - /// - property IsMultiPartFormData: Boolean read GetIsMultiPartFormData; - - /// - /// 请求数据是使用 application/x-www-form-urlencoded 方式提交的 - /// - property IsUrlEncodedFormData: Boolean read GetIsUrlEncodedFormData; - - /// - /// 请求数据大小 - /// - property PostDataSize: Int64 read GetPostDataSize; - end; - - /// - /// 提供块数据的匿名函数 - /// - TCrossHttpChunkDataFunc = reference to function(const AData: PPointer; const ACount: PNativeInt): Boolean; - - /// - /// HTTP响应队列项接口 - /// 用于按请求解析顺序串行化每个连接上的响应发送, 避免 pipelining 响应交错 - /// - IHttpResponseQueueItem = interface - ['{B03F35B7-6984-41A8-9AA0-6B3D48F18F91}'] - function GetRequest: ICrossHttpRequest; - function GetResponse: ICrossHttpResponse; - function GetSource: TCrossHttpChunkDataFunc; - function GetCallback: TCrossConnectionCallback; - function GetReady: Boolean; - function GetSending: Boolean; - function GetCompleted: Boolean; - function GetKeepAlive: Boolean; - function GetStatusCode: Integer; - - procedure SetRequest(const AValue: ICrossHttpRequest); - procedure SetResponse(const AValue: ICrossHttpResponse); - procedure SetSource(const AValue: TCrossHttpChunkDataFunc); - procedure SetCallback(const AValue: TCrossConnectionCallback); - procedure SetReady(const AValue: Boolean); - procedure SetSending(const AValue: Boolean); - procedure SetCompleted(const AValue: Boolean); - procedure SetKeepAlive(const AValue: Boolean); - procedure SetStatusCode(const AValue: Integer); - - property Request: ICrossHttpRequest read GetRequest write SetRequest; - property Response: ICrossHttpResponse read GetResponse write SetResponse; - property Source: TCrossHttpChunkDataFunc read GetSource write SetSource; - property Callback: TCrossConnectionCallback read GetCallback write SetCallback; - property Ready: Boolean read GetReady write SetReady; - property Sending: Boolean read GetSending write SetSending; - property Completed: Boolean read GetCompleted write SetCompleted; - property KeepAlive: Boolean read GetKeepAlive write SetKeepAlive; - property StatusCode: Integer read GetStatusCode write SetStatusCode; - end; - - /// - /// HTTP响应队列项实现类 - /// - THttpResponseQueueItem = class(TInterfacedObject, IHttpResponseQueueItem) - private - FRequest: ICrossHttpRequest; - FResponse: ICrossHttpResponse; - FSource: TCrossHttpChunkDataFunc; - FCallback: TCrossConnectionCallback; - FReady: Boolean; - FSending: Boolean; - FCompleted: Boolean; - FKeepAlive: Boolean; - FStatusCode: Integer; - protected - function GetRequest: ICrossHttpRequest; - function GetResponse: ICrossHttpResponse; - function GetSource: TCrossHttpChunkDataFunc; - function GetCallback: TCrossConnectionCallback; - function GetReady: Boolean; - function GetSending: Boolean; - function GetCompleted: Boolean; - function GetKeepAlive: Boolean; - function GetStatusCode: Integer; - - procedure SetRequest(const AValue: ICrossHttpRequest); - procedure SetResponse(const AValue: ICrossHttpResponse); - procedure SetSource(const AValue: TCrossHttpChunkDataFunc); - procedure SetCallback(const AValue: TCrossConnectionCallback); - procedure SetReady(const AValue: Boolean); - procedure SetSending(const AValue: Boolean); - procedure SetCompleted(const AValue: Boolean); - procedure SetKeepAlive(const AValue: Boolean); - procedure SetStatusCode(const AValue: Integer); - end; - - /// - /// HTTP应答接口 - /// - ICrossHttpResponse = interface - ['{5E15C20F-E221-4B10-90FC-222173A6F3E8}'] - function GetConnection: ICrossHttpConnection; - function GetRequest: ICrossHttpRequest; - function GetStatusCode: Integer; - function GetStatusText: string; - function GetContentType: string; - function GetLocation: string; - function GetHeader: THttpHeader; - function GetCookies: TResponseCookies; - function GetSent: Boolean; - - procedure SetContentType(const Value: string); - procedure SetLocation(const Value: string); - procedure SetStatusCode(Value: Integer); - procedure SetStatusText(const Value: string); - - /// - /// 重置数据 - /// - procedure Reset; - - /// - /// 压缩发送块数据 - /// - /// - /// 产生块数据的匿名函数 - /// // AData: 数据指针 - /// // ACount: 数据大小 - /// // Result: 如果返回True, 则发送数据; 如果返回False, 则忽略AData和ACount并结束发送 - /// function(const AData: PPointer; const ACount: PNativeInt): Boolean - /// begin - /// end - /// - /// - /// 压缩方式 - /// - /// - /// 回调函数 - /// - /// - /// 本方法实现了一边压缩一边发送数据, 所以可以支持无限大的分块数据的压缩发送, 而不用占用太多的内存和CPU
- /// zlib参考手册:
- ///
- procedure SendZCompress(const AChunkSource: TCrossHttpChunkDataFunc; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 压缩发送无类型数据 - /// - /// - /// 无类型数据 - /// - /// - /// 数据大小 - /// - /// - /// 压缩方式 - /// - /// - /// 回调函数 - /// - procedure SendZCompress(const ABody; const ACount: NativeInt; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 压缩发送字节数据 - /// - /// - /// 字节数据 - /// - /// - /// 偏移量 - /// - /// - /// 数据大小 - /// - /// - /// 压缩方式 - /// - /// - /// 回调函数 - /// - procedure SendZCompress(const ABody: TBytes; const AOffset, ACount: NativeInt; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 压缩发送字节数据 - /// - /// - /// 字节数据 - /// - /// - /// 压缩方式 - /// - /// - /// 回调函数 - /// - procedure SendZCompress(const ABody: TBytes; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 压缩发送流数据 - /// - /// - /// 流数据 - /// - /// - /// 偏移量 - /// - /// - /// 数据大小 - /// - /// - /// 压缩方式 - /// - /// - /// 回调函数 - /// - /// - /// 必须保证发送过程中流对象的有效性, 要释放流对象可以放到回调函数中进行 - /// - procedure SendZCompress(const ABody: TStream; const AOffset, ACount: Int64; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 压缩发送流数据 - /// - /// - /// 流数据 - /// - /// - /// 压缩方式 - /// - /// - /// 回调函数 - /// - /// - /// 必须保证发送过程中流对象的有效性, 要释放流对象可以放到回调函数中进行 - /// - procedure SendZCompress(const ABody: TStream; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 压缩发送字符串数据 - /// - /// - /// 字符串数据 - /// - /// - /// 压缩方式 - /// - /// - /// 回调函数 - /// - procedure SendZCompress(const ABody: string; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 不压缩发送块数据 - /// - /// - /// 产生块数据的匿名函数 - /// // AData: 数据指针 - /// // ACount: 数据大小 - /// // Result: 如果返回True, 则发送数据; 如果返回False, 则忽略AData和ACount并结束发送 - /// function(const AData: PPointer; const ACount: PNativeInt): Boolean - /// begin - /// end - /// - /// - /// 回调函数 - /// - /// - /// 使用该方法可以一边生成数据一边发送, 无需等待数据全部准备完成 - /// - procedure SendNoCompress(const AChunkSource: TCrossHttpChunkDataFunc; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 不压缩发送无类型数据 - /// - /// - /// 无类型数据 - /// - /// - /// 数据大小 - /// - /// - /// 回调函数 - /// - procedure SendNoCompress(const ABody; const ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 不压缩发送字节数据 - /// - /// - /// 字节数据 - /// - /// - /// 偏移量 - /// - /// - /// 数据大小 - /// - /// - /// 回调函数 - /// - procedure SendNoCompress(const ABody: TBytes; const AOffset, ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 不压缩发送字节数据 - /// - /// - /// 字节数据 - /// - /// - /// 回调函数 - /// - procedure SendNoCompress(const ABody: TBytes; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 不压缩发送流数据 - /// - /// - /// 流数据 - /// - /// - /// 偏移量 - /// - /// - /// 数据大小 - /// - /// - /// 回调函数 - /// - /// - /// 必须保证发送过程中流对象的有效性, 要释放流对象可以放到回调函数中进行 - /// - procedure SendNoCompress(const ABody: TStream; const AOffset, ACount: Int64; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 不压缩发送流数据 - /// - /// - /// 流数据 - /// - /// - /// 回调函数 - /// - /// - /// 必须保证发送过程中流对象的有效性, 要释放流对象可以放到回调函数中进行 - /// - procedure SendNoCompress(const ABody: TStream; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 不压缩发送字符串数据 - /// - /// - /// 字符串数据 - /// - /// - /// 回调函数 - /// - procedure SendNoCompress(const ABody: string; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 发送无类型数据 - /// - /// - /// 无类型数据 - /// - /// - /// 数据大小 - /// - /// - /// 回调函数 - /// - procedure Send(const ABody; const ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 发送字节数据 - /// - /// - /// 字节数据 - /// - /// - /// 偏移量 - /// - /// - /// 数据大小 - /// - /// - /// 回调函数 - /// - procedure Send(const ABody: TBytes; const AOffset, ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 发送字节数据 - /// - /// - /// 字节数据 - /// - /// - /// 回调函数 - /// - procedure Send(const ABody: TBytes; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 发送流数据 - /// - /// - /// 流数据 - /// - /// - /// 偏移量 - /// - /// - /// 数据大小 - /// - /// - /// 回调函数 - /// - /// - /// 必须保证发送过程中流对象的有效性, 要释放流对象可以放到回调函数中进行 - /// - procedure Send(const ABody: TStream; const AOffset, ACount: Int64; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 发送流数据 - /// - /// - /// 流数据 - /// - /// - /// 回调函数 - /// - /// - /// 必须保证发送过程中流对象的有效性, 要释放流对象可以放到回调函数中进行 - /// - procedure Send(const ABody: TStream; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 发送字符串数据 - /// - /// - /// 字符串数据 - /// - /// - /// 回调函数 - /// - procedure Send(const ABody: string; const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 发送Json字符串数据 - /// - /// - /// Json字符串数据 - /// - /// - /// 回调函数 - /// - procedure Json(const AJson: string; const ACallback: TCrossConnectionCallback = nil); - - /// - /// 发送文件内容 - /// - /// - /// 文件名 - /// - /// - /// 回调函数 - /// - procedure SendFile(const AFileName: string; const ACallback: TCrossConnectionCallback = nil); - - /// - /// 将文件以下载形式发送 - /// - /// - /// 文件名 - /// - /// - /// 回调函数 - /// - procedure Download(const AFileName: string; const ACallback: TCrossConnectionCallback = nil); - - /// - /// 发送状态码 - /// - /// - /// 状态码 - /// - /// - /// 描述信息(body) - /// - /// - /// 回调函数 - /// - /// - /// 描述信息即是body数据, 如果设置为空, 则body也为空 - /// - procedure SendStatus(const AStatusCode: Integer; const ADescription: string; - const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 发送状态码 - /// - /// - /// 状态码 - /// - /// - /// 回调函数 - /// - /// - /// 该方法根据状态码生成默认的body数据 - /// - procedure SendStatus(const AStatusCode: Integer; - const ACallback: TCrossConnectionCallback = nil); overload; - - /// - /// 发送重定向Url命令 - /// - /// - /// 新的Url - /// - /// - /// 回调函数 - /// - procedure Redirect(const AUrl: string; const ACallback: TCrossConnectionCallback = nil); - - /// - /// 设置Content-Disposition, 令客户端将收到的数据作为文件下载处理 - /// - /// - /// 文件名 - /// - procedure Attachment(const AFileName: string); - - /// - /// HTTP连接对象 - /// - property Connection: ICrossHttpConnection read GetConnection; - - /// - /// 请求对象 - /// - property Request: ICrossHttpRequest read GetRequest; - - /// - /// 状态码 - /// - property StatusCode: Integer read GetStatusCode write SetStatusCode; - - /// - /// 状态文本 - /// - property StatusText: string read GetStatusText write SetStatusText; - - /// - /// 内容类型 - /// - property ContentType: string read GetContentType write SetContentType; - - /// - /// 重定向Url - /// - property Location: string read GetLocation write SetLocation; - - /// - /// HTTP响应头 - /// - property Header: THttpHeader read GetHeader; - - /// - /// 设置Cookies - /// - property Cookies: TResponseCookies read GetCookies; - - /// - /// 是否已经发送数据 - /// - property Sent: Boolean read GetSent; - end; - - TCrossHttpRouterProc = reference to procedure(const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse; var AHandled: Boolean); - TCrossHttpRouterMethod = procedure(const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse; var AHandled: Boolean) of object; - - TCrossHttpConnEvent = procedure(const Sender: TObject; const AConnection: ICrossHttpConnection) of object; - TCrossHttpRequestExceptionEvent = procedure(const Sender: TObject; const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse; const AException: Exception) of object; - - TCrossHttpRequestEvent = procedure(const Sender: TObject; - const AConnection: ICrossHttpConnection; - const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse; - var AHandled: Boolean) of object; - - // Begin/End 事件签名带上 ARequest/AResponse, 让事件 handler 能拿到本次事件 - // 对应的请求/响应对象, 不再依赖连接级 FRequest/FResponse 兼容视图 - // (该兼容视图在 pipelining 下语义模糊, 已不再由 _FinishQueueItem 维护) - TCrossHttpRequestBeginEvent = procedure(const Sender: TObject; - const AConnection: ICrossHttpConnection; - const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse) of object; - TCrossHttpRequestEndEvent = procedure(const Sender: TObject; - const AConnection: ICrossHttpConnection; - const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse; - const ASuccess: Boolean) of object; - - /// - /// - /// 跨平台HTTP服务器接口 - /// - /// - /// 路由定义方式: - /// - /// - /// Route(AMehod, APath, ARouter) - /// - /// - /// Get(APath, ARouter) - /// - /// - /// Put(APath, ARouter) - /// - /// - /// Post(APath, ARouter) - /// - /// - /// Delete(APath, ARouter) - /// - /// - /// All(APath, ARouter) - /// - /// - /// 其中AMehod和APath都支持正则表达式, ARouter可以是一个对象方法也可以是匿名函数 - /// - /// - /// - /// - /// 这里偷了下懒, 没将HTTP和HTTPS分开实现两个不同的接口, 需要通过编译开关选择使用HTTP还是HTTP - /// - /// - /// 通过接口引用计数保证连接的有效性,所以可以在路由函数中调用线程池来处理业务逻辑,而不用担心处理过程中连接对象被释放 - /// - /// - /// 每个请求的响应流程大致为: - /// - /// - /// - /// 执行匹配的中间件; - /// - /// - /// 执行匹配的路由 - /// - /// - /// - /// - /// // 在线程池中处理业务逻辑 - /// FCrossHttpServer.Route('GET', '/runtask/:name', - /// procedure(ARequest: ICrossHttpRequest; AResponse: ICrossHttpResponse) - /// begin - /// System.Threading.TTask.Run( - /// procedure - /// begin - /// CallTask(ARequest.Params['name']); - /// end); - /// end); - /// // 正则表达式 - /// FCrossHttpServer.Route('GET', '/query/:count(\d+)', - /// procedure(ARequest: ICrossHttpRequest; AResponse: ICrossHttpResponse) - /// begin - /// System.Threading.TTask.Run( - /// procedure - /// begin - /// CallQuery(ARequest.Params['count'].ToInteger); - /// end); - /// end); - /// - ICrossHttpServer = interface(ICrossServer) - ['{224D16AA-317C-435E-9C2E-92868E578DB3}'] - function GetStoragePath: string; - function GetAutoDeleteFiles: Boolean; - function GetMaxHeaderSize: Int64; - function GetMaxPostDataSize: Int64; - function GetMaxCompressRatio: Integer; - function GetCompressible: Boolean; - function GetMinCompressSize: Int64; - function GetSessions: ISessions; - function GetSessionIDCookieName: string; - function GetOnRequestBegin: TCrossHttpRequestBeginEvent; - function GetOnRequest: TCrossHttpRequestEvent; - function GetOnRequestEnd: TCrossHttpRequestEndEvent; - function GetOnRequestException: TCrossHttpRequestExceptionEvent; - - procedure SetStoragePath(const Value: string); - procedure SetAutoDeleteFiles(const Value: Boolean); - procedure SetMaxHeaderSize(const Value: Int64); - procedure SetMaxPostDataSize(const Value: Int64); - procedure SetMaxCompressRatio(const Value: Integer); - procedure SetCompressible(const Value: Boolean); - procedure SetMinCompressSize(const Value: Int64); - procedure SetSessions(const Value: ISessions); - procedure SetSessionIDCookieName(const Value: string); - procedure SetOnRequestBegin(const Value: TCrossHttpRequestBeginEvent); - procedure SetOnRequest(const Value: TCrossHttpRequestEvent); - procedure SetOnRequestEnd(const Value: TCrossHttpRequestEndEvent); - procedure SetOnRequestException(const Value: TCrossHttpRequestExceptionEvent); - - /// - /// 注册中间件 - /// - /// - /// 请求方式 - /// - /// - /// 请求路径 - /// - /// - /// 中间件处理匿名函数, 执行完处理函数之后, 如果AHandled=False则会继续执行后续匹配的中间件及路由, - /// 否则后续匹配的中间件及路由不会被执行 - /// - /// - /// - /// - /// 中间件严格按照注册时的顺序被调用 - /// - /// - /// 中间件先于路由执行 - /// - /// - /// - function Use(const AMethod, APath: string; - const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - - /// - /// 注册中间件 - /// - /// - /// 请求方式 - /// - /// - /// 请求路径 - /// - /// - /// 中间件处理匿名方法, 执行完处理方法之后, 如果AHandled=False则会继续执行后续匹配的中间件及路由, - /// 否则后续匹配的中间件及路由不会被执行 - /// - /// - /// - /// - /// 中间件严格按照注册时的顺序被调用 - /// - /// - /// 中间件先于路由执行 - /// - /// - /// - function Use(const AMethod, APath: string; - const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - - /// - /// 注册中间件 - /// - /// - /// 请求路径 - /// - /// - /// 中间件处理匿名函数, 执行完处理函数之后, 如果AHandled=False则会继续执行后续匹配的中间件及路由, - /// 否则后续匹配的中间件及路由不会被执行 - /// - /// - /// - /// - /// 中间件严格按照注册时的顺序被调用 - /// - /// - /// 中间件先于路由执行 - /// - /// - /// - function Use(const APath: string; - const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - - /// - /// 注册中间件 - /// - /// - /// 请求路径 - /// - /// - /// 中间件处理匿名方法, 执行完处理方法之后, 如果AHandled=False则会继续执行后续匹配的中间件及路由, - /// 否则后续匹配的中间件及路由不会被执行 - /// - /// - /// - /// - /// 中间件严格按照注册时的顺序被调用 - /// - /// - /// 中间件先于路由执行 - /// - /// - /// - function Use(const APath: string; - const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - - /// - /// 注册中间件 - /// - /// - /// 中间件处理匿名函数, 执行完处理函数之后还会继续执行后续匹配的中间件及路由 - /// - /// - /// - /// - /// 中间件严格按照注册时的顺序被调用 - /// - /// - /// 中间件先于路由执行 - /// - /// - /// - function Use(const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - - /// - /// 注册中间件 - /// - /// - /// 中间件处理方法, 执行完处理方法之后还会继续执行后续匹配的中间件及路由 - /// - /// - /// - /// - /// 中间件严格按照注册时的顺序被调用 - /// - /// - /// 中间件先于路由执行 - /// - /// - /// - function Use(const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - - /// - /// 注册路由(请求处理函数) - /// - /// - /// 请求方式, GET/POST/PUT/DELETE等, 支持正则表达式, * 表示处理全部请求方式 - /// - /// - /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: - /// /path/:param1/:param2(\d+)|/path/:param - /// - /// - /// 路由处理匿名函数 - /// - /// - /// - /// - /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, - /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. - /// - /// - /// 路由中的正则表达式用法与node.js express相同 - /// - /// - /// - function Route(const AMethod, APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - - /// - /// 注册路由(请求处理函数) - /// - /// - /// 请求方式, GET/POST/PUT/DELETE等, 支持正则表达式, * 表示处理全部请求方式 - /// - /// - /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: - /// /path/:param1/:param2(\d+)|/path/:param - /// - /// - /// 路由处理方法 - /// - /// - /// - /// - /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, - /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. - /// - /// - /// 路由中的正则表达式用法与node.js express相同 - /// - /// - /// - function Route(const AMethod, APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - - /// - /// 注册GET路由(请求处理函数) - /// - /// - /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: - /// /path/:param1/:param2(\d+)|/path/:param - /// - /// - /// 路由处理匿名函数 - /// - /// - /// - /// - /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, - /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. - /// - /// - /// 路由中的正则表达式用法与node.js express相同 - /// - /// - /// - function Get(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - - /// - /// 注册GET路由(请求处理函数) - /// - /// - /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: - /// /path/:param1/:param2(\d+)|/path/:param - /// - /// - /// 路由处理方法 - /// - /// - /// - /// - /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, - /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. - /// - /// - /// 路由中的正则表达式用法与node.js express相同 - /// - /// - /// - function Get(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - - /// - /// 注册PUT路由(请求处理函数) - /// - /// - /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: - /// /path/:param1/:param2(\d+)|/path/:param - /// - /// - /// 路由处理匿名函数 - /// - /// - /// - /// - /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, - /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. - /// - /// - /// 路由中的正则表达式用法与node.js express相同 - /// - /// - /// - function Put(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - - /// - /// 注册PUT路由(请求处理函数) - /// - /// - /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: - /// /path/:param1/:param2(\d+)|/path/:param - /// - /// - /// 路由处理方法 - /// - /// - /// - /// - /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, - /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. - /// - /// - /// 路由中的正则表达式用法与node.js express相同 - /// - /// - /// - function Put(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - - /// - /// 注册POST路由(请求处理函数) - /// - /// - /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: - /// /path/:param1/:param2(\d+)|/path/:param - /// - /// - /// 路由处理匿名函数 - /// - /// - /// - /// - /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, - /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. - /// - /// - /// 路由中的正则表达式用法与node.js express相同 - /// - /// - /// - function Post(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - - /// - /// 注册POST路由(请求处理函数) - /// - /// - /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: - /// /path/:param1/:param2(\d+)|/path/:param - /// - /// - /// 路由处理方法 - /// - /// - /// - /// - /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, - /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. - /// - /// - /// 路由中的正则表达式用法与node.js express相同 - /// - /// - /// - function Post(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - - /// - /// 注册DELETE路由(请求处理函数) - /// - /// - /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: - /// /path/:param1/:param2(\d+)|/path/:param - /// - /// - /// 路由处理匿名函数 - /// - /// - /// - /// - /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, - /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. - /// - /// - /// 路由中的正则表达式用法与node.js express相同 - /// - /// - /// - function Delete(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - - /// - /// 注册DELETE路由(请求处理函数) - /// - /// - /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: - /// /path/:param1/:param2(\d+)|/path/:param - /// - /// - /// 路由处理方法 - /// - /// - /// - /// - /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, - /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. - /// - /// - /// 路由中的正则表达式用法与node.js express相同 - /// - /// - /// - function Delete(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - - /// - /// 注册全部请求方式路由(请求处理函数) - /// - /// - /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: - /// /path/:param1/:param2(\d+)|/path/:param - /// - /// - /// 路由处理匿名函数 - /// - /// - /// - /// - /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, - /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. - /// - /// - /// 路由中的正则表达式用法与node.js express相同 - /// - /// - /// - function All(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - - /// - /// 注册全部请求方式路由(请求处理函数) - /// - /// - /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: - /// /path/:param1/:param2(\d+)|/path/:param - /// - /// - /// 路由处理方法 - /// - /// - /// - /// - /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, - /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. - /// - /// - /// 路由中的正则表达式用法与node.js express相同 - /// - /// - /// - function All(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - - /// - /// 注册静态文件路由 - /// - /// - /// 请求路径 - /// - /// - /// 静态文件目录, 该目录及子目录下的文件都将作为静态文件返回 - /// - function &Static(const APath, ALocalStaticDir: string): ICrossHttpServer; - - /// - /// 注册文件列表路由 - /// - /// - /// 请求路径 - /// - /// - /// 本地文件目录 - /// - function Dir(const APath, ALocalDir: string): ICrossHttpServer; - - /// - /// 注册含有默认首页文件的静态文件路由 - /// - /// - /// 请求路径 - /// - /// - /// 含有默认首页文件的本地目录 - /// - /// - /// 默认的首页文件,按顺序选择,先找到哪个就使用哪个 - /// - function Index(const APath, ALocalDir: string; const ADefIndexFiles: TArray): ICrossHttpServer; - - /// - /// 删除指定路由 - /// - function RemoveRouter(const AMethod, APath: string): ICrossHttpServer; - - /// - /// 清除所有路由 - /// - function ClearRouters: ICrossHttpServer; - - /// - /// 删除指定中间件 - /// - function RemoveMiddleware(const AMethod, APath: string): ICrossHttpServer; - - /// - /// 清除所有中间件 - /// - function ClearMiddlewares: ICrossHttpServer; - - /// - /// 上传文件保存路径 - /// - /// - /// 用于保存multipart/form-data上传的文件 - /// - property StoragePath: string read GetStoragePath write SetStoragePath; - - /// - /// 对象释放时自动删除上传的文件 - /// - property AutoDeleteFiles: Boolean read GetAutoDeleteFiles write SetAutoDeleteFiles; - - /// - /// 最大允许HEADER的数据尺寸 - /// - /// - /// > 0, 限制HEADER尺寸 - /// - /// - /// <= 0, 不限制 - /// - /// - /// - property MaxHeaderSize: Int64 read GetMaxHeaderSize write SetMaxHeaderSize; - - /// - /// 最大允许POST的数据尺寸 - /// - /// - /// > 0, 限制上传数据尺寸 - /// - /// - /// <= 0, 不限制 - /// - /// - /// - property MaxPostDataSize: Int64 read GetMaxPostDataSize write SetMaxPostDataSize; - - /// - /// gzip/deflate 解压时的最大压缩比 (DecodedSize / EncodedSize) - /// - /// - /// > 0, 解压输出与输入比超过该值则按 zip bomb 拒绝 (400) - /// - /// - /// = 0, 不做压缩比检查 (仅靠 MaxPostDataSize 拦截) - /// - /// - /// - /// - /// 合法 gzip 通常 1.5-15:1, 极规整数据 (StringOfChar, 大块重复字节) 可达 100-500:1 - /// 经典 zip bomb 1000:1 起 (42.zip ~100000:1), 默认 1000:1 兜底拦截 bomb - /// - property MaxCompressRatio: Integer read GetMaxCompressRatio write SetMaxCompressRatio; - - /// - /// 是否开启压缩 - /// - /// - /// 开启压缩后, 发往客户端的数据将会进行压缩处理 - /// - property Compressible: Boolean read GetCompressible write SetCompressible; - - /// - /// 最小允许压缩的数据尺寸 - /// - /// - /// - /// - /// 如果设置值大于0, 则只有Body数据尺寸大于等于该值才会进行压缩 - /// - /// - /// 如果设置值小于等于0, 则无视Body数据尺寸, 始终进行压缩 - /// - /// - /// 由于数据是分块压缩发送, 所以数据无论多大都不会占用更多的资源, 也就不需要限制最大压缩尺寸了 - /// - /// - /// 目前支持的压缩方式: gzip, deflate - /// - /// - /// - property MinCompressSize: Int64 read GetMinCompressSize write SetMinCompressSize; - - /// - /// Sessions接口对象 - /// - /// - /// 通过它管理所有Session, 如果不设置则Session功能将不会被启用 - /// - property Sessions: ISessions read GetSessions write SetSessions; - - /// - /// - /// SessionID在Cookie中存储的名称 - /// - /// - /// - /// 如果设置为空, 则Session功能将不会被启用 - /// - property SessionIDCookieName: string read GetSessionIDCookieName write SetSessionIDCookieName; - - property OnRequestBegin: TCrossHttpRequestBeginEvent read GetOnRequestBegin write SetOnRequestBegin; - property OnRequest: TCrossHttpRequestEvent read GetOnRequest write SetOnRequest; - property OnRequestEnd: TCrossHttpRequestEndEvent read GetOnRequestEnd write SetOnRequestEnd; - property OnRequestException: TCrossHttpRequestExceptionEvent read GetOnRequestException write SetOnRequestException; - end; - - TCrossHttpConnection = class(TCrossServerConnection, ICrossHttpConnection) - private - FServer: TCrossHttpServer; - FRequestObj: TCrossHttpRequest; - FRequest: ICrossHttpRequest; - FResponseObj: TCrossHttpResponse; - FResponse: ICrossHttpResponse; - FHttpParser: ICrossHttpParser; - FPending: Integer; - - // pipelining 响应队列, 按请求解析顺序串行化响应发送 - FResponseQueue: TList; - FResponseQueueLock: ILock; - FSendingResponse: Boolean; - - {$region 'HttpParser事件'} - // 以下事件都在 FHttpParser.Decode 中被触发 - // 而 FHttpParser.Decode 在 ParseRecvData 中被调用 - // ParseRecvData 在 FServer.LogicReceived 中被调用 - // FServer.LogicReceived 被 TCrossConnectionBase._LockRecv 保护 - // 所以无需担心以下事件的多线程安全问题 - procedure _OnHeaderData(const ADataPtr: Pointer; const ADataSize: Integer); - function _OnGetHeaderValue(const AHeaderName: string; out AHeaderValues: TArray): Boolean; - procedure _OnBodyBegin; - procedure _OnBodyData(const ADataPtr: Pointer; const ADataSize: Integer); - procedure _OnBodyEnd; - procedure _OnParseBegin; - procedure _OnParseSuccess; - procedure _OnParseFailed(const ACode: Integer; const AError: string); - {$endregion} - - // 响应队列内部方法 - procedure _QueueResponseReady(const AItem: IHttpResponseQueueItem; - const ASource: TCrossHttpChunkDataFunc; - const ACallback: TCrossConnectionCallback); - procedure _SendQueueItem(const AItem: IHttpResponseQueueItem); - procedure _FinishQueueItem(const AItem: IHttpResponseQueueItem; const ASuccess: Boolean); - - // 调用前必须已持有 FResponseQueueLock; 若可发送则取出队首 ready item - // 并设置 FSendingResponse / item.Sending, 否则返回 nil - function _TryDequeueReadyLocked: IHttpResponseQueueItem; - - // 调用前必须已持有 FResponseQueueLock; 清空队列, 同时主动断开每个 item - // 内对 request/response/source/callback 的接口引用, 避免与 response.FQueueItem - // 等形成的循环引用导致 item 永不释放 - procedure _ClearResponseQueueLocked; - protected - function GetRequest: ICrossHttpRequest; - function GetResponse: ICrossHttpResponse; - function GetServer: ICrossHttpServer; - function GetPending: Integer; - - procedure ParseRecvData(var ABuf: Pointer; var ALen: Integer); virtual; - - procedure ReleaseRequest; virtual; - procedure ReleaseResponse; virtual; - - // socket 关闭时主动打破 connection 与 request/response 之间的循环引用, - // 并清空响应队列, 避免连接关闭后 connection 因循环引用永不释放导致内存泄漏 - procedure InternalClose; override; - public - constructor Create(const AOwner: TCrossSocketBase; const AClientSocket: TSocket; - const AConnectType: TConnectType; const AHost: string; - const AConnectCb: TCrossConnectionCallback); override; - destructor Destroy; override; - - property Request: ICrossHttpRequest read GetRequest; - property Response: ICrossHttpResponse read GetResponse; - property Server: ICrossHttpServer read GetServer; - property Pending: Integer read GetPending; - end; - - TCrossHttpRequest = class(TInterfacedObject, ICrossHttpRequest) - private - FRawRequestText: string; - FMethod, FPath, FQueryText, FPathAndQuery, FVersion: string; - FRawPath, FRawQueryText, FRawPathAndQuery: string; - FHttpVerNum: Integer; - FKeepAlive: Boolean; - FAccept: string; - FReferer: string; - FAcceptLanguage: string; - FAcceptEncoding: string; - FUserAgent: string; - FIfModifiedSince: TDateTime; - FIfNoneMatch: string; - FRange: string; - FIfRange: string; - FAuthorization: string; - FXForwardedFor: string; - FContentLength: Int64; - FHostName: string; - FHostPort: Word; - - FPostDataSize: Int64; - - FRequestCmdLine: string; - FContentType: string; - FRequestBoundary: string; - FTransferEncoding: string; - FContentEncoding: string; - FRequestCookies: string; - FRequestHost: string; - FRequestConnection: string; - - FConnectionObj: TCrossHttpConnection; - FConnection: ICrossHttpConnection; - FServer: TCrossHttpServer; - FHeader: THttpHeader; - FCookies: TRequestCookies; - FSession: ISession; - FParams: THttpUrlParams; - FQuery: THttpUrlParams; - FBody: TObject; - FRawBody: TMemoryStream; - FBodyType: TBodyType; - FIsChunked: Boolean; - private - function CalcIsChunked: Boolean; inline; - protected - function GetConnection: ICrossHttpConnection; - function GetRawRequestText: string; - function GetRawPathAndQuery: string; - function GetMethod: string; - function GetPath: string; - function GetPathAndQuery: string; - function GetVersion: string; - function GetHeader: THttpHeader; - function GetCookies: TRequestCookies; - function GetSession: ISession; - function GetParams: THttpUrlParams; - function GetQueryText: string; - function GetQuery: THttpUrlParams; - function GetBody: TObject; - function GetRawBody: TStream; - function GetBodyType: TBodyType; - function GetKeepAlive: Boolean; - function GetAccept: string; - function GetAcceptEncoding: string; - function GetAcceptLanguage: string; - function GetReferer: string; - function GetUserAgent: string; - function GetIfModifiedSince: TDateTime; - function GetIfNoneMatch: string; - function GetRange: string; - function GetIfRange: string; - function GetAuthorization: string; - function GetXForwardedFor: string; - function GetContentLength: Int64; - function GetHostName: string; - function GetHostPort: Word; - function GetContentType: string; - function GetContentEncoding: string; - function GetRequestBoundary: string; - function GetRequestCmdLine: string; - function GetRequestConnection: string; - function GetTransferEncoding: string; - function GetIsChunked: Boolean; - function GetIsMultiPartFormData: Boolean; - function GetIsUrlEncodedFormData: Boolean; - function GetPostDataSize: Int64; - - function ParseHeader(const ADataPtr: Pointer; const ADataSize: Integer): Boolean; - public - constructor Create(const AConnection: TCrossHttpConnection); - destructor Destroy; override; - - property Connection: ICrossHttpConnection read GetConnection; - property RawRequestText: string read GetRawRequestText; - property RawPathAndParams: string read GetRawPathAndQuery; - property Method: string read GetMethod; - property Path: string read GetPath; - property PathAndQuery: string read GetPathAndQuery; - property Version: string read GetVersion; - property Header: THttpHeader read GetHeader; - property Cookies: TRequestCookies read GetCookies; - property Session: ISession read GetSession; - property Params: THttpUrlParams read GetParams; - property Query: THttpUrlParams read GetQuery; - property QueryText: string read GetQueryText; - property Body: TObject read GetBody; - property RawBody: TStream read GetRawBody; - property BodyType: TBodyType read GetBodyType; - property KeepAlive: Boolean read GetKeepAlive; - property Accept: string read GetAccept; - property AcceptEncoding: string read GetAcceptEncoding; - property AcceptLanguage: string read GetAcceptLanguage; - property Referer: string read GetReferer; - property UserAgent: string read GetUserAgent; - property IfModifiedSince: TDateTime read GetIfModifiedSince; - property IfNoneMatch: string read GetIfNoneMatch; - property Range: string read GetRange; - property IfRange: string read GetIfRange; - property Authorization: string read GetAuthorization; - property XForwardedFor: string read GetXForwardedFor; - property ContentLength: Int64 read GetContentLength; - property HostName: string read GetHostName; - property HostPort: Word read GetHostPort; - property ContentType: string read GetContentType; - - property RequestCmdLine: string read GetRequestCmdLine; - - property RequestBoundary: string read GetRequestBoundary; - property TransferEncoding: string read GetTransferEncoding; - property ContentEncoding: string read GetContentEncoding; - property RequestConnection: string read GetRequestConnection; - property IsChunked: Boolean read GetIsChunked; - property IsMultiPartFormData: Boolean read GetIsMultiPartFormData; - property IsUrlEncodedFormData: Boolean read GetIsUrlEncodedFormData; - property PostDataSize: Int64 read GetPostDataSize; - end; - - TCrossHttpResponse = class(TInterfacedObject, ICrossHttpResponse) - public const - SND_BUF_SIZE = TCrossConnection.SND_BUF_SIZE; - private - FConnectionObj: TCrossHttpConnection; - FConnection: ICrossHttpConnection; - FRequest: ICrossHttpRequest; - FStatusCode: Integer; - FStatusText: string; - FHeader: THttpHeader; - FCookies: TResponseCookies; - FSendStatus: Integer; - FQueueItem: IHttpResponseQueueItem; - - procedure Reset; - function _CreateHeader(const ABodySize: Int64; AChunked: Boolean): TBytes; - - {$region '内部: 基础发送方法'} - procedure _Send(const ASource: TCrossHttpChunkDataFunc; const ACallback: TCrossConnectionCallback = nil); overload; - procedure _Send(const AHeaderSource, ABodySource: TCrossHttpChunkDataFunc; const ACallback: TCrossConnectionCallback = nil); overload; - {$endregion} - - function _CheckCompress(const ABodySize: Int64; out ACompressType: TCompressType): Boolean; - - // TCustomMemoryStream 优化: 直接获取内存指针, 避免逐块读流 - function _GetMemoryStreamPointer(const AStream: TStream; - const AOffset, ACount: Int64; out P: PByte; out LSize: Int64): Boolean; inline; - - {$region '压缩发送'} - procedure SendZCompress(const AChunkSource: TCrossHttpChunkDataFunc; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; - procedure SendZCompress(const ABody: Pointer; const ACount: NativeInt; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; - procedure SendZCompress(const ABody; const ACount: NativeInt; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; inline; - procedure SendZCompress(const ABody: TBytes; const AOffset, ACount: NativeInt; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; - procedure SendZCompress(const ABody: TBytes; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; inline; - procedure SendZCompress(const ABody: TStream; const AOffset, ACount: Int64; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; - procedure SendZCompress(const ABody: TStream; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; inline; - procedure SendZCompress(const ABody: string; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; - {$endregion} - - {$region '不压缩发送'} - procedure SendNoCompress(const AChunkSource: TCrossHttpChunkDataFunc; const ACallback: TCrossConnectionCallback = nil); overload; - procedure SendNoCompress(const ABody: Pointer; const ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; - procedure SendNoCompress(const ABody; const ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; inline; - procedure SendNoCompress(const ABody: TBytes; const AOffset, ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; - procedure SendNoCompress(const ABody: TBytes; const ACallback: TCrossConnectionCallback = nil); overload; inline; - procedure SendNoCompress(const ABody: TStream; const AOffset, ACount: Int64; const ACallback: TCrossConnectionCallback = nil); overload; - procedure SendNoCompress(const ABody: TStream; const ACallback: TCrossConnectionCallback = nil); overload; inline; - procedure SendNoCompress(const ABody: string; const ACallback: TCrossConnectionCallback = nil); overload; - {$endregion} - - {$region '常规方法'} - procedure Send(const ABody: Pointer; const ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; - procedure Send(const ABody; const ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; inline; - procedure Send(const ABody: TBytes; const AOffset, ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; - procedure Send(const ABody: TBytes; const ACallback: TCrossConnectionCallback = nil); overload; inline; - procedure Send(const ABody: TStream; const AOffset, ACount: Int64; const ACallback: TCrossConnectionCallback = nil); overload; - procedure Send(const ABody: TStream; const ACallback: TCrossConnectionCallback = nil); overload; inline; - procedure Send(const ABody: string; const ACallback: TCrossConnectionCallback = nil); overload; - - procedure Json(const AJson: string; const ACallback: TCrossConnectionCallback = nil); - - procedure SendFile(const AFileName: string; const ACallback: TCrossConnectionCallback = nil); - procedure Download(const AFileName: string; const ACallback: TCrossConnectionCallback = nil); - procedure SendStatus(const AStatusCode: Integer; const ADescription: string; - const ACallback: TCrossConnectionCallback = nil); overload; - procedure SendStatus(const AStatusCode: Integer; - const ACallback: TCrossConnectionCallback = nil); overload; - procedure Redirect(const AUrl: string; const ACallback: TCrossConnectionCallback = nil); - procedure Attachment(const AFileName: string); - {$endregion} - protected - function GetConnection: ICrossHttpConnection; - function GetRequest: ICrossHttpRequest; - function GetStatusCode: Integer; - function GetStatusText: string; - function GetContentType: string; - function GetLocation: string; - function GetHeader: THttpHeader; - function GetCookies: TResponseCookies; - function GetSent: Boolean; - - procedure SetContentType(const Value: string); - procedure SetLocation(const Value: string); - procedure SetStatusCode(Value: Integer); - procedure SetStatusText(const Value: string); - public - constructor Create(const AConnection: TCrossHttpConnection; - const ARequest: ICrossHttpRequest; - const AQueueItem: IHttpResponseQueueItem); - destructor Destroy; override; - end; - - /// - /// 路由参数定义 - /// - TRouteParam = record - Name: string; // 参数名 - Pattern: string; // 正则模式 - end; - - /// - /// 路由类型 - /// - TRouteType = ( - /// - /// 静态路由 - /// - rtStatic, - - /// - /// 正则路由 - /// 例如: /users/:id, /users/:id/echo, /users/:id(\d+) - /// - rtRegex, - - /// - /// 通配符路由 - /// 例如: /files/*, 其中*就是通配符节点, 通配符节点只能出现在路径最后一段 - /// - rtWildcard - ); - - /// - /// 路由接口 - /// - IRouter = interface - ['{5A7E2B1C-8D3F-4E69-A0C5-2F1B8E6D4A93}'] - function GetRouteType: TRouteType; - function GetMethodPattern: string; - function GetRegEx: IRegEx; - - procedure AddRouterProc(const ARouterProc: TCrossHttpRouterProc); overload; - procedure AddRouterProc(const ARouterMethod: TCrossHttpRouterMethod); overload; - - procedure Execute(const ARequest: ICrossHttpRequest; - const AResponse: ICrossHttpResponse; var AHandled: Boolean); - - property RouteType: TRouteType read GetRouteType; - property MethodPattern: string read GetMethodPattern; - property RegEx: IRegEx read GetRegEx; - end; - - /// - /// 路由 - /// - TRouter = class(TInterfacedObject, IRouter) - private - // 路由类型 - FRouteType: TRouteType; - // 方法模式(如 "GET", "GET|POST", "*" 等) - FMethodPattern: string; - FLock: IReadWriteLock; - - // 路由处理函数 - FRouterProcList: TList; - FRouterMethodList: TList; - - function GetRouteType: TRouteType; - function GetMethodPattern: string; - function GetRegEx: IRegEx; - public - constructor Create(const AMethodPattern: string); - destructor Destroy; override; - - procedure AddRouterProc(const ARouterProc: TCrossHttpRouterProc); overload; - procedure AddRouterProc(const ARouterMethod: TCrossHttpRouterMethod); overload; - - procedure Execute(const ARequest: ICrossHttpRequest; - const AResponse: ICrossHttpResponse; var AHandled: Boolean); - end; - - /// - /// 路由段 - /// - TRouteSegment = class - private - FOriginal: string; // 原始段 - FPattern: string; // 完整模式 - FParams: TArray; // 参数定义数组 - FRouteType: TRouteType; // 路由类型 - public - constructor Create(const AOriginal, APattern: string; - const AParams: TArray; ARouteType: TRouteType); - - // 正则匹配 - // 只有正则匹配的路由才需要处理参数 - function RegexMatch(const ASegment: string; const ARequest: ICrossHttpRequest): Boolean; - - property Original: string read FOriginal; - property Pattern: string read FPattern; - property Params: TArray read FParams; - property RouteType: TRouteType read FRouteType; - end; - - /// - /// 路由节点 - /// - TRouteNode = class - private - FRouteType: TRouteType; // 路由类型 - FSegment: TRouteSegment; // 路由段 - - FStaticChildren: TObjectDictionary; // 静态子节点 - FRegexChildren: TObjectList; // 正则子节点 - FWildcardChild: TRouteNode; // 通配符子节点 - - FStaticRouteMethodItems: TDictionary; // 静态方法路由项列表 - FRegexRouteMethodItems: TList; // 正则方法路由项列表 - FWildcardRouteMethodItem: IRouter; // 通配符路由项 - - function GetChildNode(const ASegment: string; const ARouteType: TRouteType; out ARouteNode: TRouteNode): Boolean; - function CreateChildNode(const ASegment: TRouteSegment): TRouteNode; - public - constructor Create(ARouteType: TRouteType; const ASegment: TRouteSegment); - destructor Destroy; override; - - // 注意: 添加和删除是使用的模式字符串(比如 GET POST GET|POST) - procedure AddRouter(const AMethodPattern: string; const ARouter: IRouter); - function GetRouter(const AMethodPattern: string; out ARouter: IRouter): Boolean; - function RemoveRouter(const AMethodPattern: string): Boolean; - - // 注意: 查找使用的是确定的请求方法(比如 GET POST) - function MatchRouter(const AMethod: string; out ARouter: IRouter): Boolean; - function IsEmpty: Boolean; - - property RouteType: TRouteType read FRouteType; - property Segment: TRouteSegment read FSegment; - property StaticChildren: TObjectDictionary read FStaticChildren; - property RegexChildren: TObjectList read FRegexChildren; - property WildcardChild: TRouteNode read FWildcardChild; - end; - - /// - /// 路由树 - /// - TCrossHttpRouterTree = class - private - FRoot: TRouteNode; - FLock: IReadWriteLock; - - function CreateSegment(const ASegment: string; const ARouteType: TRouteType): TRouteSegment; - - // 注意: 添加和删除是使用的模式字符串(比如 GET POST GET|POST, /user/:id) - procedure AddRouterToNode(ANode: TRouteNode; const APathPatternSegments: TArray; - AIndex: Integer; const AMethodPattern: string; const ARouter: IRouter); - function GetRouterFromNode(ANode: TRouteNode; const APathPatternSegments: TArray; - AIndex: Integer; const AMethodPattern: string; out ARouter: IRouter): Boolean; - function RemoveRouterFromNode(ANode: TRouteNode; const APathPatternSegments: TArray; - AIndex: Integer; const AMethodPattern: string): Boolean; - - function GetWildcardValue(const APathSegments: TArray; - AIndex: Integer; const AQueryText: string): string; - // 注意: 查找使用的是确定的请求方法和路径(比如 GET POST, /user/123) - function MatchRouterInNode(ANode: TRouteNode; const APathSegments: TArray; - AIndex: Integer; const AMethod: string; const ARequest: ICrossHttpRequest; - out ARouter: IRouter): Boolean; - public - constructor Create; - destructor Destroy; override; - - // 将请求路径分段 - class function ParsePath(const APath: string): TArray; static; - - // 注意: 添加和删除是使用的模式字符串(比如 GET POST GET|POST, /user/:id) - procedure AddRouter(const AMethodPattern, APathPattern: string; const ARouter: IRouter); overload; - function GetRouter(const AMethodPattern, APathPattern: string; out ARouter: IRouter): Boolean; overload; - function GetRouter(const AMethodPattern, APathPattern: string): IRouter; overload; - - procedure AddRouter(const AMethodPattern, APathPattern: string; const ARouterProc: TCrossHttpRouterProc); overload; - procedure AddRouter(const AMethodPattern, APathPattern: string; const ARouterMethod: TCrossHttpRouterMethod); overload; - - procedure RemoveRouter(const AMethodPattern, APathPattern: string); - - // 注意: 查找与请求匹配的路由 - function MatchRouter(const APathSegments: TArray; const ARequest: ICrossHttpRequest; out ARouter: IRouter): Boolean; overload; - function MatchRouter(const ARequest: ICrossHttpRequest; out ARouter: IRouter): Boolean; overload; - procedure Clear; - end; - - TCrossHttpServer = class(TCrossServer, ICrossHttpServer) - private const - SESSIONID_COOKIE_NAME = 'cross_sessionid'; - private - FStoragePath: string; - FAutoDeleteFiles: Boolean; - FMaxPostDataSize: Int64; - FMaxHeaderSize: Int64; - FMaxCompressRatio: Integer; - FMinCompressSize: Int64; - FSessionIDCookieName: string; - - FRouters: TCrossHttpRouterTree; - FMiddlewares: TCrossHttpRouterTree; - - FSessions: ISessions; - FOnRequestBegin: TCrossHttpRequestBeginEvent; - FOnRequestEnd: TCrossHttpRequestEndEvent; - FOnRequest: TCrossHttpRequestEvent; - FOnRequestException: TCrossHttpRequestExceptionEvent; - FCompressible: Boolean; - protected - function GetStoragePath: string; - function GetAutoDeleteFiles: Boolean; - function GetMaxHeaderSize: Int64; - function GetMaxPostDataSize: Int64; - function GetMaxCompressRatio: Integer; - function GetCompressible: Boolean; - function GetMinCompressSize: Int64; - function GetSessions: ISessions; - function GetSessionIDCookieName: string; - function GetOnRequest: TCrossHttpRequestEvent; - function GetOnRequestEnd: TCrossHttpRequestEndEvent; - function GetOnRequestBegin: TCrossHttpRequestBeginEvent; - function GetOnRequestException: TCrossHttpRequestExceptionEvent; - - procedure SetStoragePath(const Value: string); - procedure SetAutoDeleteFiles(const Value: Boolean); - procedure SetMaxHeaderSize(const Value: Int64); - procedure SetMaxPostDataSize(const Value: Int64); - procedure SetMaxCompressRatio(const Value: Integer); - procedure SetCompressible(const Value: Boolean); - procedure SetMinCompressSize(const Value: Int64); - procedure SetSessions(const Value: ISessions); - procedure SetSessionIDCookieName(const Value: string); - procedure SetOnRequest(const Value: TCrossHttpRequestEvent); - procedure SetOnRequestBegin(const Value: TCrossHttpRequestBeginEvent); - procedure SetOnRequestEnd(const Value: TCrossHttpRequestEndEvent); - procedure SetOnRequestException(const Value: TCrossHttpRequestExceptionEvent); - protected - function CreateConnection(const AOwner: TCrossSocketBase; const AClientSocket: TSocket; - const AConnectType: TConnectType; const AHost: string; - const AConnectCb: TCrossConnectionCallback): ICrossConnection; override; - - procedure LogicReceived(const AConnection: ICrossConnection; const ABuf: Pointer; const ALen: Integer); override; - protected - // 处理请求前 - // 显式传入 ARequest/AResponse, 避免在 pipelining 场景下从 connection 字段读取产生 race - procedure DoOnRequestBegin(const AConnection: ICrossHttpConnection; - const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse); virtual; - - // 处理请求 - procedure DoOnRequest(const AConnection: ICrossHttpConnection; - const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse); virtual; - - // 处理请求后 - procedure DoOnRequestEnd(const AConnection: ICrossHttpConnection; - const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse; - const ASuccess: Boolean); virtual; - public - constructor Create(const AIoThreads: Integer; const ASsl: Boolean); override; - destructor Destroy; override; - - function Use(const AMethod, APath: string; - const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - function Use(const AMethod, APath: string; - const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - function Use(const APath: string; - const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - function Use(const APath: string; - const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - function Use(const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - function Use(const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - - function Route(const AMethod, APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - function Route(const AMethod, APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - - function Get(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - function Get(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - - function Put(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - function Put(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - - function Post(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - function Post(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - - function Delete(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - function Delete(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - - function All(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; - function All(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; - - function &Static(const APath, ALocalStaticDir: string): ICrossHttpServer; - function Dir(const APath, ALocalDir: string): ICrossHttpServer; - function Index(const APath, ALocalDir: string; const ADefIndexFiles: TArray): ICrossHttpServer; - - function RemoveRouter(const AMethod, APath: string): ICrossHttpServer; - function ClearRouters: ICrossHttpServer; - - function RemoveMiddleware(const AMethod, APath: string): ICrossHttpServer; - function ClearMiddlewares: ICrossHttpServer; - - property StoragePath: string read GetStoragePath write SetStoragePath; - property AutoDeleteFiles: Boolean read GetAutoDeleteFiles write SetAutoDeleteFiles; - property MaxHeaderSize: Int64 read GetMaxHeaderSize write SetMaxHeaderSize; - property MaxPostDataSize: Int64 read GetMaxPostDataSize write SetMaxPostDataSize; - property MaxCompressRatio: Integer read GetMaxCompressRatio write SetMaxCompressRatio; - property Compressible: Boolean read GetCompressible write SetCompressible; - property MinCompressSize: Int64 read GetMinCompressSize write SetMinCompressSize; - property Sessions: ISessions read GetSessions write SetSessions; - property SessionIDCookieName: string read GetSessionIDCookieName write SetSessionIDCookieName; - - property OnRequestBegin: TCrossHttpRequestBeginEvent read GetOnRequestBegin write SetOnRequestBegin; - property OnRequest: TCrossHttpRequestEvent read GetOnRequest write SetOnRequest; - property OnRequestEnd: TCrossHttpRequestEndEvent read GetOnRequestEnd write SetOnRequestEnd; - property OnRequestException: TCrossHttpRequestExceptionEvent read GetOnRequestException write SetOnRequestException; - end; - -implementation - -uses - {$IFDEF MSWINDOWS} - Windows, - {$ENDIF} - Utils.Utils, - Net.CrossHttpRouter; - -const - // HTTP/1.1 100 Continue 临时响应,用于 Expect: 100-continue 流程 - CResponse100Continue: AnsiString = 'HTTP/1.1 100 Continue'#13#10#13#10; - - -{ ECrossHttpException } - -constructor ECrossHttpException.Create(const AMessage: string; - AStatusCode: Integer); -begin - inherited Create(AMessage); - FStatusCode := AStatusCode; -end; - -constructor ECrossHttpException.CreateFmt(const AMessage: string; - const AArgs: array of const; AStatusCode: Integer); -begin - inherited CreateFmt(AMessage, AArgs); - FStatusCode := AStatusCode; -end; - -{ THttpResponseQueueItem } - -function THttpResponseQueueItem.GetRequest: ICrossHttpRequest; -begin - Result := FRequest; -end; - -function THttpResponseQueueItem.GetResponse: ICrossHttpResponse; -begin - Result := FResponse; -end; - -function THttpResponseQueueItem.GetSource: TCrossHttpChunkDataFunc; -begin - Result := FSource; -end; - -function THttpResponseQueueItem.GetCallback: TCrossConnectionCallback; -begin - Result := FCallback; -end; - -function THttpResponseQueueItem.GetReady: Boolean; -begin - Result := FReady; -end; - -function THttpResponseQueueItem.GetSending: Boolean; -begin - Result := FSending; -end; - -function THttpResponseQueueItem.GetCompleted: Boolean; -begin - Result := FCompleted; -end; - -function THttpResponseQueueItem.GetKeepAlive: Boolean; -begin - Result := FKeepAlive; -end; - -function THttpResponseQueueItem.GetStatusCode: Integer; -begin - Result := FStatusCode; -end; - -procedure THttpResponseQueueItem.SetRequest(const AValue: ICrossHttpRequest); -begin - FRequest := AValue; -end; - -procedure THttpResponseQueueItem.SetResponse(const AValue: ICrossHttpResponse); -begin - FResponse := AValue; -end; - -procedure THttpResponseQueueItem.SetSource(const AValue: TCrossHttpChunkDataFunc); -begin - FSource := AValue; -end; - -procedure THttpResponseQueueItem.SetCallback(const AValue: TCrossConnectionCallback); -begin - FCallback := AValue; -end; - -procedure THttpResponseQueueItem.SetReady(const AValue: Boolean); -begin - FReady := AValue; -end; - -procedure THttpResponseQueueItem.SetSending(const AValue: Boolean); -begin - FSending := AValue; -end; - -procedure THttpResponseQueueItem.SetCompleted(const AValue: Boolean); -begin - FCompleted := AValue; -end; - -procedure THttpResponseQueueItem.SetKeepAlive(const AValue: Boolean); -begin - FKeepAlive := AValue; -end; - -procedure THttpResponseQueueItem.SetStatusCode(const AValue: Integer); -begin - FStatusCode := AValue; -end; - -{ TCrossHttpConnection } - -constructor TCrossHttpConnection.Create(const AOwner: TCrossSocketBase; - const AClientSocket: TSocket; const AConnectType: TConnectType; - const AHost: string; const AConnectCb: TCrossConnectionCallback); -begin - inherited Create(AOwner, AClientSocket, AConnectType, AHost, AConnectCb); - - FServer := AOwner as TCrossHttpServer; - - FResponseQueue := TList.Create; - FResponseQueueLock := TLock.Create; - - FHttpParser := TCrossHttpParser.Create(pmServer); - FHttpParser.MaxHeaderSize := FServer.MaxHeaderSize; - FHttpParser.MaxBodyDataSize := FServer.MaxPostDataSize; - FHttpParser.MaxCompressRatio := FServer.MaxCompressRatio; - FHttpParser.OnHeaderData := _OnHeaderData; - FHttpParser.OnGetHeaderValue := _OnGetHeaderValue; - FHttpParser.OnBodyBegin := _OnBodyBegin; - FHttpParser.OnBodyData := _OnBodyData; - FHttpParser.OnBodyEnd := _OnBodyEnd; - FHttpParser.OnParseBegin := _OnParseBegin; - FHttpParser.OnParseSuccess := _OnParseSuccess; - FHttpParser.OnParseFailed := _OnParseFailed; -end; - -destructor TCrossHttpConnection.Destroy; -begin - if (FRequest <> nil) then - (FRequest as TCrossHttpRequest).FConnection := nil; - - if (FResponse <> nil) then - (FResponse as TCrossHttpResponse).FConnection := nil; - - ReleaseRequest; - ReleaseResponse; - - // 队列清理由 InternalClose 负责 (包括 _ClearResponseQueueLocked 触发 callbacks), - // 此处仅做 defensive 的 FreeAndNil, 避免重复清理 - FreeAndNil(FResponseQueue); - FResponseQueueLock := nil; - - FHttpParser := nil; - - inherited; -end; - -function TCrossHttpConnection.GetRequest: ICrossHttpRequest; -begin - Result := FRequest; -end; - -function TCrossHttpConnection.GetResponse: ICrossHttpResponse; -begin - Result := FResponse; -end; - -function TCrossHttpConnection.GetServer: ICrossHttpServer; -begin - Result := Owner as ICrossHttpServer; -end; - -function TCrossHttpConnection.GetPending: Integer; -begin - // 读取在多 IO 线程间发生, 与 _OnParseBegin 的 AtomicIncrement / - // _FinishQueueItem 的 AtomicDecrement 保持原子语义 - Result := AtomicCmpExchange(FPending, 0, 0); -end; - -procedure TCrossHttpConnection.ParseRecvData(var ABuf: Pointer; - var ALen: Integer); -begin - if (FHttpParser <> nil) then - FHttpParser.Decode(ABuf, ALen) - else - ALen := 0; -end; - -procedure TCrossHttpConnection.ReleaseRequest; -begin - FRequestObj := nil; - FRequest := nil; -end; - -procedure TCrossHttpConnection.ReleaseResponse; -begin - FResponseObj := nil; - FResponse := nil; -end; - -procedure TCrossHttpConnection.InternalClose; -begin - // 必须在 socket 关闭时主动断开连接级 FRequest/FResponse 与 request.FConnection / - // response.FConnection 之间的循环引用. 否则 connection.FRequest 持有 request, 而 - // request.FConnection 又持有 connection, refcount 永不归零, 不仅 connection 不会 - // 销毁, 队列内 item / request body / response header 等也全部泄漏. - if (FRequest <> nil) then - (FRequest as TCrossHttpRequest).FConnection := nil; - if (FResponse <> nil) then - (FResponse as TCrossHttpResponse).FConnection := nil; - ReleaseRequest; - ReleaseResponse; - - // 清空响应队列中剩余 items: 它们持有的 request/response/source/callback 接口字段 - // 与 response.FQueueItem 形成循环引用. 必须先逐个清空 item 内的接口字段, - // 再 Clear 队列, 否则 items 引用计数减 1 之后仍因循环引用而不会归零, 导致泄漏 - if (FResponseQueueLock <> nil) and (FResponseQueue <> nil) then - begin - FResponseQueueLock.Enter; - try - FSendingResponse := False; - _ClearResponseQueueLocked; - finally - FResponseQueueLock.Leave; - end; - end; - - inherited InternalClose; -end; - -function TCrossHttpConnection._TryDequeueReadyLocked: IHttpResponseQueueItem; -begin - Result := nil; - - if FSendingResponse then Exit; - if (FResponseQueue = nil) or (FResponseQueue.Count = 0) then Exit; - if not FResponseQueue[0].Ready then Exit; - - // 从队列中移除队首, 由调用方的局部接口引用保活后续发送过程 - Result := FResponseQueue[0]; - FResponseQueue.Delete(0); - FSendingResponse := True; - Result.Sending := True; -end; - -// _ClearResponseQueueLocked: -// 调用前必须持有 FResponseQueueLock. -// 按队列注册顺序 (FIFO) 收集所有 callback, 清空队列并逐个清空 item 内部接口引用, -// 锁外按收集顺序触发 callback(False) 通知业务方发送失败. -// 注意: callback 中不应操作连接状态 (如 Disconnect), 因为此时连接正在关闭流程中. -procedure TCrossHttpConnection._ClearResponseQueueLocked; -var - I: Integer; - LItem: IHttpResponseQueueItem; - LCallbacks: TArray; -begin - if (FResponseQueue = nil) then Exit; - - // 收集所有待通知 callback (在本方法尾部、队列清空后触发), - // 避免静默丢弃导致业务方 hang 等通知. - SetLength(LCallbacks, FResponseQueue.Count); - for I := 0 to FResponseQueue.Count - 1 do - begin - LItem := FResponseQueue[I]; - if (LItem <> nil) then - begin - LCallbacks[I] := LItem.Callback; - LItem.Request := nil; - LItem.Response := nil; - LItem.Source := nil; - LItem.Callback := nil; - end; - end; - - FResponseQueue.Clear; - - // 触发所有被丢弃的 callback (通知失败) - for I := 0 to High(LCallbacks) do - if Assigned(LCallbacks[I]) then - LCallbacks[I](Self, False); -end; - -procedure TCrossHttpConnection._QueueResponseReady( - const AItem: IHttpResponseQueueItem; - const ASource: TCrossHttpChunkDataFunc; - const ACallback: TCrossConnectionCallback); -var - LAlreadyReadyOrCompleted: Boolean; - LItemToSend: IHttpResponseQueueItem; -begin - if (AItem = nil) then - begin - if Assigned(ACallback) then - ACallback(Self, False); - Exit; - end; - - LAlreadyReadyOrCompleted := False; - LItemToSend := nil; - - // 单次锁块完成 "标记 ready" 与 "尝试 take 队首" 两件事 - // 减少 happy path 上的锁/解锁次数, 降低高并发竞争开销 - FResponseQueueLock.Enter; - try - if AItem.Ready or AItem.Completed then - begin - // 同一个 item 不允许重复 ready, 不修改原有 Source/Callback - LAlreadyReadyOrCompleted := True; - end else - begin - AItem.Source := ASource; - AItem.Callback := ACallback; - AItem.KeepAlive := AItem.Request.KeepAlive; - AItem.StatusCode := AItem.Response.StatusCode; - AItem.Ready := True; - - // 没有正在发送时, 立即尝试取队首 ready item - LItemToSend := _TryDequeueReadyLocked; - end; - finally - FResponseQueueLock.Leave; - end; - - if LAlreadyReadyOrCompleted then - begin - // 安全降级: 对重复传入的 callback 触发失败, 避免调用方静默挂起 - if Assigned(ACallback) then - ACallback(Self, False); - Exit; - end; - - if (LItemToSend <> nil) then - _SendQueueItem(LItemToSend); -end; - -procedure TCrossHttpConnection._SendQueueItem(const AItem: IHttpResponseQueueItem); -var - LConnection: ICrossHttpConnection; - LSender: TCrossConnectionCallback; -begin - LConnection := Self; - - LSender := - procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) - var - LData: Pointer; - LCount: NativeInt; - LSource: TCrossHttpChunkDataFunc; - begin - if not ASuccess then - begin - _FinishQueueItem(AItem, False); - LConnection := nil; - LSender := nil; - Exit; - end; - - LSource := AItem.Source; - LData := nil; - LCount := 0; - if not Assigned(LSource) - or not LSource(@LData, @LCount) - or (LData = nil) - or (LCount <= 0) then - begin - // StatusCode>=500 表示压缩/发送过程中发生了不可恢复的错误 - _FinishQueueItem(AItem, AItem.StatusCode < 500); - LConnection := nil; - LSender := nil; - Exit; - end; - - AConnection.SendBuf(LData^, LCount, LSender); - end; - - LSender(LConnection, True); -end; - -procedure TCrossHttpConnection._FinishQueueItem( - const AItem: IHttpResponseQueueItem; const ASuccess: Boolean); -var - LRequest: ICrossHttpRequest; - LResponse: ICrossHttpResponse; - LCallback: TCrossConnectionCallback; - LNeedDisconnect, LDoEnd: Boolean; - LItemNext: IHttpResponseQueueItem; -begin - LDoEnd := False; - LNeedDisconnect := False; - LRequest := nil; - LResponse := nil; - LCallback := nil; - LItemNext := nil; - - // 单次锁块完成 "标记 completed + 释放 sending 标志 + 尝试 take 下一个 ready item" - // 三件事, 锁外再触发下一个 item 的发送, 避免两次进出锁的开销 - FResponseQueueLock.Enter; - try - // 先复位 FSendingResponse, 确保无论 AItem 是否已经 Completed 都不会挂起后续响应 - FSendingResponse := False; - if not AItem.Completed then - begin - LRequest := AItem.Request; - LResponse := AItem.Response; - LCallback := AItem.Callback; - LNeedDisconnect := ASuccess and ((not AItem.KeepAlive) or (AItem.StatusCode >= 500)); - - AItem.Completed := True; - LDoEnd := True; - - // 关键: 立即清空 item 对外部对象的接口引用, 打破循环引用导致的内存泄漏: - // response.FQueueItem -> item.FResponse -> response (双向接口循环) - // item.FSource -> 匿名方法 (captured Self=response) -> response (隐式循环) - // 不在此处释放, 这些引用要等到 connection 释放才能解开, 而 connection - // 又被 request.FConnection / response.FConnection 持有, 形成多重循环 - AItem.Request := nil; - AItem.Response := nil; - AItem.Source := nil; - AItem.Callback := nil; - - // 仅在 happy path 下提前 take 下一个 item; 失败/disconnect 路径不取, - // 让 connection 关闭流程清理剩余 queue - if ASuccess and (not LNeedDisconnect) then - LItemNext := _TryDequeueReadyLocked; - end; - finally - FResponseQueueLock.Leave; - end; - - if LDoEnd then - begin - // 不写 FRequest/FResponse 连接级字段, 这两个字段仅由 _OnParseBegin - // 在 _LockRecv 内独占写入. 当前完成 item 的 request/response 通过 - // LRequest/LResponse 显式传给 DoOnRequestEnd, 进而传给 OnRequestEnd 事件, - // 事件 handler 可直接从参数拿到精确对应的请求/响应, 不需要读连接字段 - AtomicDecrement(FPending); - - // 用户 callback 可能抛异常, 必须用 try/finally 保证 DoOnRequestEnd 触发 - try - if Assigned(LCallback) then - LCallback(Self, ASuccess); - finally - FServer.DoOnRequestEnd(Self, LRequest, LResponse, ASuccess); - end; - end; - - if (not ASuccess) or LNeedDisconnect then - Disconnect - else if (LItemNext <> nil) then - _SendQueueItem(LItemNext); -end; - -procedure TCrossHttpConnection._OnBodyBegin; -var - LMultiPart: THttpMultiPartFormData; -begin - {$region '创建Body'} - case FRequestObj.GetBodyType of - btMultiPart: - begin - if (FServer.FStoragePath <> '') and not DirectoryExists(FServer.FStoragePath) then - ForceDirectories(FServer.FStoragePath); - - LMultiPart := THttpMultiPartFormData.Create; - LMultiPart.StoragePath := FServer.FStoragePath; - LMultiPart.AutoDeleteFiles := FServer.FAutoDeleteFiles; - LMultiPart.InitWithBoundary(FRequestObj.RequestBoundary); - if (FRequestObj.FBody = FRequestObj.FRawBody) then - FRequestObj.FBody := nil - else - FreeAndNil(FRequestObj.FBody); - FreeAndNil(FRequestObj.FRawBody); - FRequestObj.FBody := LMultiPart; - end; - - btUrlEncoded, btBinary: - begin - // 二次校验: Parser 层可能未限制时由 Server 层兜底 - if (FServer.FMaxPostDataSize > 0) and (FRequestObj.FContentLength > FServer.FMaxPostDataSize) then - begin - _OnParseFailed(413, 'Request body too large.'); - Exit; // FBody 保持 nil, _OnBodyData/_OnBodyEnd 有 nil guard 安全跳过 - end; - if (FRequestObj.FBody = FRequestObj.FRawBody) then - FRequestObj.FBody := nil - else - FreeAndNil(FRequestObj.FBody); - FreeAndNil(FRequestObj.FRawBody); - FRequestObj.FRawBody := TMemoryStream.Create; - FRequestObj.FBody := FRequestObj.FRawBody; - end; - end; - {$endregion} -end; - -procedure TCrossHttpConnection._OnBodyData(const ADataPtr: Pointer; - const ADataSize: Integer); -begin - if (FRequestObj.FBody = nil) then Exit; - - Inc(FRequestObj.FPostDataSize, ADataSize); - - case FRequestObj.GetBodyType of - btMultiPart: - (FRequestObj.FBody as THttpMultiPartFormData).Decode(ADataPtr, ADataSize); - - btUrlEncoded, btBinary: - if (FRequestObj.FRawBody <> nil) then - FRequestObj.FRawBody.Write(ADataPtr^, ADataSize); - end; -end; - -procedure TCrossHttpConnection._OnBodyEnd; -var - LUrlEncodedStr: string; - LUrlEncodedBody: TFormUrlEncoded; -begin - if (FRequestObj.FBody = nil) then Exit; - - case FRequestObj.GetBodyType of - btUrlEncoded: - begin - if (FRequestObj.FRawBody = nil) then Exit; - - SetString(LUrlEncodedStr, - MarshaledAString(FRequestObj.FRawBody.Memory), - FRequestObj.FRawBody.Size); - LUrlEncodedBody := TFormUrlEncoded.Create; - if LUrlEncodedBody.Decode(LUrlEncodedStr) then - begin - if (FRequestObj.FBody = FRequestObj.FRawBody) then - FRequestObj.FBody := nil - else - FreeAndNil(FRequestObj.FBody); - FRequestObj.FBody := LUrlEncodedBody; - FRequestObj.FRawBody.Position := 0; - end else - begin - FreeAndNil(LUrlEncodedBody); - // 如果按 UrlEncoded 方式解码失败, 则保留原始数据 - // 并将类型改为 btBinary - FRequestObj.FBodyType := btBinary; - FRequestObj.FBody := FRequestObj.FRawBody; - FRequestObj.FRawBody.Position := 0; - end; - end; - - btBinary: - if (FRequestObj.FRawBody <> nil) then - FRequestObj.FRawBody.Position := 0; - end; -end; - -function TCrossHttpConnection._OnGetHeaderValue(const AHeaderName: string; - out AHeaderValues: TArray): Boolean; -begin - Result := FRequest.Header.GetHeaderValues(AHeaderName, AHeaderValues); -end; - -procedure TCrossHttpConnection._OnHeaderData(const ADataPtr: Pointer; - const ADataSize: Integer); -var - LParsed: Boolean; - LExpect: string; -begin - // ParseHeader 内部已用 try/except 将各类解析异常转为 Result := False, - // 这里仍再加一层护栏, 防止以后修改 ParseHeader 时遗漏局部 try/except - // 导致恶意/畸形请求的异常上抛到 LogicReceived 环外. 统一归一为 400 响应. - try - LParsed := (FRequest as TCrossHttpRequest).ParseHeader(ADataPtr, ADataSize); - except - LParsed := False; - end; - - if not LParsed then - begin - _OnParseFailed(400, 'Invalid request header.'); - Abort; - end; - - // RFC 7231 §5.1.1: Expect: 100-continue 支持 - // - // 协议流程: - // 客户端发送 header (含 Expect: 100-continue) → - // 服务器在此处发送 100 Continue (临时响应, 不走响应队列) → - // Parser 继续接收 body (_OnBodyBegin → _OnBodyData → _OnBodyEnd) → - // _OnParseSuccess → DoOnRequest 正常处理路由/中间件 → - // 最终发送正式响应 (200/404/500 等) - // - // 注意: - // 100 Continue 只是一个协议层 "请继续" 信号, 不代表服务器接受该请求. - // 当前实现不在此阶段做认证/校验, 意味着即使后续 DoOnRequest 返回 401, - // 客户端也已发送完整 body. 对于大多数客户端, 不带 Expect 头时的行为 - // 也是如此 (body 总会随 header 一起发送), 所以无实际功能损失. - // SendBuf 是非阻塞操作, 在 _LockRecv 内调用安全. - LExpect := FRequest.Header[HEADER_EXPECT]; - if TStrUtils.SameText(LExpect.Trim, '100-continue') then - Self.SendBuf(@CResponse100Continue[1], Length(CResponse100Continue), nil); -end; - -procedure TCrossHttpConnection._OnParseBegin; -var - LItem: IHttpResponseQueueItem; -begin - // 本函数以及其它 HttpParser 回调均由 FHttpParser.Decode -> ParseRecvData -> - // FServer.LogicReceived -> TCrossSocketBase.TriggerReceived 同步触发, - // 调用链起点已由 TriggerReceived 加上 TCrossConnectionBase._LockRecv, - // 所以这里不需要也不应该重复加锁 - - // 为本次请求创建独立的 queue item, 队列顺序由解析顺序决定 - LItem := THttpResponseQueueItem.Create; - - FRequestObj := TCrossHttpRequest.Create(Self); - FRequest := FRequestObj; - - // 创建响应对象, 显式绑定到 request 和 queue item, 确保异步发送时 - // 不依赖连接级 FRequest/FResponse 字段 - FResponseObj := TCrossHttpResponse.Create(Self, FRequest, LItem); - FResponse := FResponseObj; - - LItem.Request := FRequest; - LItem.Response := FResponse; - - FResponseQueueLock.Enter; - try - FResponseQueue.Add(LItem); - finally - FResponseQueueLock.Leave; - end; - - AtomicIncrement(FPending); -end; - -procedure TCrossHttpConnection._OnParseFailed(const ACode: Integer; - const AError: string); -begin - if (FResponse <> nil) then - FResponse.SendStatus(ACode, AError) - else - Close; -end; - -procedure TCrossHttpConnection._OnParseSuccess; -var - LConnection: ICrossHttpConnection; - LRequest: ICrossHttpRequest; - LResponse: ICrossHttpResponse; -begin - LConnection := Self; - // 这里是 _LockRecv 保护下的同步调用, FRequest/FResponse 此刻仍是 - // _OnParseBegin 刚写入的当前 parse item 的 request/response. - // 显式捕获为局部接口引用的真正意义在于: 一旦后续业务释放锁 - // (如未来调整架构则业务可能在锁外运行) 或 _OnParseBegin 重新写入 - // 连接级字段, 本局部变量仍以接口引用计数保证当前请求/响应对象存活, - // 不会读到错位对象。对象生命周期本质上由接口引用计数保证, 与锁无关 - LRequest := FRequest; - LResponse := FResponse; - FServer.DoOnRequestBegin(LConnection, LRequest, LResponse); - FServer.DoOnRequest(LConnection, LRequest, LResponse); -end; - -function IsRegEx(const APattern: string): Boolean; inline; -begin - Result := (APattern.IndexOfAny(REGEX_CHARS) >= 0); -end; - -function IsWildcard(const APattern: string): Boolean; inline; -begin - Result := (APattern = WILDCARD_CHAR); -end; - -function GetPatternType(const APattern: string): TRouteType; inline; -begin - // 通配符 - if IsWildcard(APattern) then - Result := rtWildcard - // 正则 - else if IsRegEx(APattern) then - Result := rtRegex - // 静态 - else - Result := rtStatic; -end; - -function CreateRouterRegEx(const APattern: string): IRegEx; -var - LPattern: string; -begin - LPattern := APattern; - if (LPattern = '*') then - LPattern := '.*'; - - // 添加正则表达式的开始和结束锚点 - if not LPattern.StartsWith('^') then - LPattern := '^' + LPattern; - if not LPattern.EndsWith('$') then - LPattern := LPattern + '$'; - - Result := TRegEx.Create(LPattern); - Result.Options := [roIgnoreCase]; -end; - -{ TRouter } - -procedure TRouter.AddRouterProc(const ARouterProc: TCrossHttpRouterProc); -begin - FLock.BeginWrite; - try - FRouterProcList.Add(ARouterProc); - finally - FLock.EndWrite; - end; -end; - -procedure TRouter.AddRouterProc(const ARouterMethod: TCrossHttpRouterMethod); -begin - FLock.BeginWrite; - try - FRouterMethodList.Add(ARouterMethod); - finally - FLock.EndWrite; - end; -end; - -constructor TRouter.Create(const AMethodPattern: string); -begin - FMethodPattern := AMethodPattern; - FRouteType := GetPatternType(AMethodPattern); - - FRouterProcList := TList.Create; - FRouterMethodList := TList.Create; - FLock := TReadWriteLock.Create; -end; - -destructor TRouter.Destroy; -begin - FreeAndNil(FRouterProcList); - FreeAndNil(FRouterMethodList); - - inherited; -end; - -function TRouter.GetRouteType: TRouteType; -begin - Result := FRouteType; -end; - -function TRouter.GetMethodPattern: string; -begin - Result := FMethodPattern; -end; - -function TRouter.GetRegEx: IRegEx; -begin - Result := nil; - if (FRouteType = rtRegex) then - Result := CreateRouterRegEx(FMethodPattern); -end; - -procedure TRouter.Execute(const ARequest: ICrossHttpRequest; - const AResponse: ICrossHttpResponse; var AHandled: Boolean); -var - LRouterProcArr: TArray; - LRouterMethodArr: TArray; - LRouterProc: TCrossHttpRouterProc; - LRouterMethod: TCrossHttpRouterMethod; -begin - FLock.BeginRead; - try - LRouterProcArr := FRouterProcList.ToArray; - LRouterMethodArr := FRouterMethodList.ToArray; - finally - FLock.EndRead; - end; - - for LRouterProc in LRouterProcArr do - begin - if Assigned(LRouterProc) then - begin - LRouterProc(ARequest, AResponse, AHandled); - if AHandled or AResponse.Sent then Exit; - end; - end; - - for LRouterMethod in LRouterMethodArr do - begin - if Assigned(LRouterMethod) then - begin - LRouterMethod(ARequest, AResponse, AHandled); - if AHandled or AResponse.Sent then Exit; - end; - end; -end; - -{ TRouteSegment } - -constructor TRouteSegment.Create(const AOriginal, APattern: string; - const AParams: TArray; ARouteType: TRouteType); -begin - inherited Create; - FOriginal := AOriginal; - FPattern := APattern; - FParams := AParams; - FRouteType := ARouteType; -end; - -function TRouteSegment.RegexMatch(const ASegment: string; const ARequest: ICrossHttpRequest): Boolean; -var - I: Integer; - LRegEx: IRegEx; -begin - Result := False; - - case FRouteType of - rtRegex: - begin - LRegEx := CreateRouterRegEx(FPattern); - if LRegEx <> nil then - begin - LRegEx.Subject := ASegment; - Result := LRegEx.Match; - if Result and Assigned(ARequest) then - begin - // 提取所有参数值 - for I := 0 to High(FParams) do - ARequest.Params[FParams[I].Name] := LRegEx.Groups[I + 1]; - end; - end; - end; - end; -end; - -{ TRouteNode } - -constructor TRouteNode.Create(ARouteType: TRouteType; const ASegment: TRouteSegment); -begin - inherited Create; - - FRouteType := ARouteType; - FSegment := ASegment; - FStaticChildren := TObjectDictionary.Create([doOwnsValues]); - FRegexChildren := TObjectList.Create(True); - - FStaticRouteMethodItems := TDictionary.Create; - FRegexRouteMethodItems := TList.Create; -end; - -destructor TRouteNode.Destroy; -begin - FreeAndNil(FSegment); - FreeAndNil(FStaticChildren); - FreeAndNil(FRegexChildren); - FreeAndNil(FWildcardChild); - - FreeAndNil(FStaticRouteMethodItems); - FreeAndNil(FRegexRouteMethodItems); - FWildcardRouteMethodItem := nil; - - inherited; -end; - -function TRouteNode.CreateChildNode(const ASegment: TRouteSegment): TRouteNode; -begin - case ASegment.RouteType of - rtStatic: - begin - Result := TRouteNode.Create(rtStatic, ASegment); - FStaticChildren.Add(ASegment.Original.ToLower, Result); - end; - - rtRegex: - begin - Result := TRouteNode.Create(rtRegex, ASegment); - FRegexChildren.Add(Result); - end; - - rtWildcard: - begin - if FWildcardChild = nil then - FWildcardChild := TRouteNode.Create(rtWildcard, ASegment); - Result := FWildcardChild; - end; - else - Result := nil; - end; -end; - -procedure TRouteNode.AddRouter(const AMethodPattern: string; const ARouter: IRouter); -begin - case ARouter.RouteType of - rtStatic: - FStaticRouteMethodItems.AddOrSetValue(AMethodPattern.ToLower, ARouter); - - rtRegex: - FRegexRouteMethodItems.Add(ARouter); - - rtWildcard: - FWildcardRouteMethodItem := ARouter; - end; -end; - -function TRouteNode.GetChildNode(const ASegment: string; - const ARouteType: TRouteType; out ARouteNode: TRouteNode): Boolean; -var - LChild: TRouteNode; -begin - case ARouteType of - rtStatic: - begin - Result := FStaticChildren.TryGetValue(ASegment.ToLower, ARouteNode) - end; - - rtRegex: - begin - for LChild in FRegexChildren do - begin - if (LChild.Segment.Original = ASegment) then - begin - ARouteNode := LChild; - Exit(True); - end; - end; - - Result := False; - end; - - rtWildcard: - begin - ARouteNode := FWildcardChild; - Result := (ARouteNode <> nil); - end; - else - ARouteNode := nil; - Result := False; - end; -end; - -function TRouteNode.GetRouter(const AMethodPattern: string; - out ARouter: IRouter): Boolean; -var - I: Integer; - LRouter: IRouter; -begin - Result := False; - - // 先尝试从静态方法路由中查找 - if FStaticRouteMethodItems.TryGetValue(AMethodPattern.ToLower, ARouter) then - Exit(True); - - // 从正则方法路由中查找 - for I := 0 to FRegexRouteMethodItems.Count - 1 do - begin - LRouter := FRegexRouteMethodItems[I]; - if SameText(LRouter.MethodPattern, AMethodPattern) then - begin - ARouter := LRouter; - Exit(True); - end; - end; - - // 从通配符方法路由中查找 - if (FWildcardRouteMethodItem <> nil) and IsWildcard(AMethodPattern) then - begin - ARouter := FWildcardRouteMethodItem; - Exit(True); - end; -end; - -function TRouteNode.MatchRouter(const AMethod: string; - out ARouter: IRouter): Boolean; -var - LRouter: IRouter; - LRegEx: IRegEx; -begin - Result := False; - - // 优先从静态方法路由中查找 - if FStaticRouteMethodItems.TryGetValue(AMethod.ToLower, LRouter) then - begin - ARouter := LRouter; - Exit(True); - end; - - // 遍历所有正则方法路由项, 找到第一个匹配的 - for LRouter in FRegexRouteMethodItems do - begin - // 正则表达式方法使用局部匹配器, 避免并发请求共享匹配状态 - LRegEx := LRouter.RegEx; - if (LRegEx <> nil) then - begin - LRegEx.Subject := AMethod; - if LRegEx.Match then - begin - ARouter := LRouter; - Exit(True); - end; - end; - end; - - // 通配符 - if (FWildcardRouteMethodItem <> nil) then - begin - ARouter := FWildcardRouteMethodItem; - Exit(True); - end; -end; - -function TRouteNode.RemoveRouter(const AMethodPattern: string): Boolean; -var - LLowerMethod: string; - I: Integer; - LRouter: IRouter; -begin - Result := False; - - // 先尝试从静态方法路由中删除 - LLowerMethod := AMethodPattern.ToLower; - if FStaticRouteMethodItems.ContainsKey(LLowerMethod) then - begin - FStaticRouteMethodItems.Remove(LLowerMethod); - Exit(True); - end; - - // 从通配符方法路由删除 - if (FWildcardRouteMethodItem <> nil) and IsWildcard(AMethodPattern) then - begin - FWildcardRouteMethodItem := nil; - Exit(True); - end; - - // 遍历正则方法路由项, 删除匹配的路由 - for I := FRegexRouteMethodItems.Count - 1 downto 0 do - begin - LRouter := FRegexRouteMethodItems[I]; - if SameText(LRouter.MethodPattern, AMethodPattern) then - begin - FRegexRouteMethodItems.Delete(I); - Exit(True); - end; - end; -end; - -function TRouteNode.IsEmpty: Boolean; -begin - // 节点为空的条件: 没有子节点且没有路由处理函数 - Result := (FStaticChildren.Count = 0) and - (FRegexChildren.Count = 0) and - (FWildcardChild = nil) and - (FStaticRouteMethodItems.Count = 0) and - (FRegexRouteMethodItems.Count = 0) and - (FWildcardRouteMethodItem = nil); -end; - -{ TCrossHttpRouterTree } - -constructor TCrossHttpRouterTree.Create; -begin - inherited Create; - - FRoot := TRouteNode.Create(rtStatic, TRouteSegment.Create('', '', [], rtStatic)); - FLock := TReadWriteLock.Create; -end; - -destructor TCrossHttpRouterTree.Destroy; -begin - FreeAndNil(FRoot); - - inherited; -end; - -function TCrossHttpRouterTree.CreateSegment(const ASegment: string; - const ARouteType: TRouteType): TRouteSegment; -var - LPattern: string; - LParams: TArray; -begin - LPattern := ASegment; - LParams := []; - - // 正则段需要处理参数 - if (ARouteType = rtRegex) then - begin - LPattern := ASegment; - LParams := []; - // 使用正则表达式匹配所有参数模式 - // 匹配 :param 和 :param(pattern) 格式 - // 可以在参数后面增加正则限定参数 :number(\d+), :word(\w+) - LPattern := TRegEx.Replace(LPattern, ':(\w+)(?:\((.*?)\))?', - function(const AMatch: TMatch): string - var - LParamName, LParamPattern: string; - LParam: TRouteParam; - begin - if not AMatch.Success then Exit(''); - - if (AMatch.Groups.Count > 1) then - LParamName := AMatch.Groups[1].Value - else - LParamName := ''; - if (AMatch.Groups.Count > 2) then - LParamPattern := AMatch.Groups[2].Value - else - LParamPattern := ''; - - if (LParamPattern = '') or (LParamPattern = '*') then - LParamPattern := '.*'; - - Result := '(' + LParamPattern + ')'; - - LParam.Name := LParamName; - LParam.Pattern := LParamPattern; - LParams := LParams + [LParam]; - end); - end; - - Result := TRouteSegment.Create(ASegment, LPattern, LParams, ARouteType); -end; - -class function TCrossHttpRouterTree.ParsePath(const APath: string): TArray; -begin - // 请求的是根路径, 无需拆分 - if (APath = '/') or (APath = '') then - begin - Result := ['']; - Exit; - end; - - // 把请求路径按/拆分成多段 - Result := APath.Split(['/'], TStringSplitOptions.ExcludeEmpty); - if (Result = nil) then - Result := ['']; -end; - -procedure TCrossHttpRouterTree.AddRouter(const AMethodPattern, APathPattern: string; - const ARouter: IRouter); -var - LPathSegments: TArray; -begin - FLock.BeginWrite; - try - LPathSegments := ParsePath(APathPattern); - AddRouterToNode(FRoot, LPathSegments, 0, AMethodPattern, ARouter); - finally - FLock.EndWrite; - end; -end; - -procedure TCrossHttpRouterTree.AddRouter(const AMethodPattern, - APathPattern: string; const ARouterProc: TCrossHttpRouterProc); -var - LRouter: IRouter; -begin - LRouter := GetRouter(AMethodPattern, APathPattern); - LRouter.AddRouterProc(ARouterProc); -end; - -procedure TCrossHttpRouterTree.AddRouter(const AMethodPattern, - APathPattern: string; const ARouterMethod: TCrossHttpRouterMethod); -var - LRouter: IRouter; -begin - LRouter := GetRouter(AMethodPattern, APathPattern); - LRouter.AddRouterProc(ARouterMethod); -end; - -procedure TCrossHttpRouterTree.AddRouterToNode(ANode: TRouteNode; - const APathPatternSegments: TArray; AIndex: Integer; const AMethodPattern: string; - const ARouter: IRouter); -var - LSegmentPattern: string; - LRouteType: TRouteType; - LRouteSegment: TRouteSegment; - LChild: TRouteNode; -begin - if (AIndex > High(APathPatternSegments)) then - begin - // 到达路径末尾, 添加路由 - ANode.AddRouter(AMethodPattern, ARouter); - Exit; - end; - - LSegmentPattern := APathPatternSegments[AIndex]; - LRouteType := GetPatternType(LSegmentPattern); - - if not ANode.GetChildNode(LSegmentPattern, LRouteType, LChild) then - begin - LRouteSegment := CreateSegment(LSegmentPattern, LRouteType); - LChild := ANode.CreateChildNode(LRouteSegment); - end; - - AddRouterToNode(LChild, APathPatternSegments, AIndex + 1, AMethodPattern, ARouter); -end; - -function TCrossHttpRouterTree.GetRouter(const AMethodPattern, - APathPattern: string; out ARouter: IRouter): Boolean; -var - LPathSegments: TArray; -begin - FLock.BeginRead; - try - LPathSegments := ParsePath(APathPattern); - Result := GetRouterFromNode(FRoot, LPathSegments, 0, AMethodPattern, ARouter); - finally - FLock.EndRead; - end; -end; - -function TCrossHttpRouterTree.GetRouter(const AMethodPattern, - APathPattern: string): IRouter; -var - LPathSegments: TArray; -begin - FLock.BeginWrite; - try - LPathSegments := ParsePath(APathPattern); - if not GetRouterFromNode(FRoot, LPathSegments, 0, AMethodPattern, Result) then - begin - Result := TRouter.Create(AMethodPattern); - AddRouterToNode(FRoot, LPathSegments, 0, AMethodPattern, Result); - end; - finally - FLock.EndWrite; - end; -end; - -function TCrossHttpRouterTree.GetRouterFromNode(ANode: TRouteNode; - const APathPatternSegments: TArray; AIndex: Integer; - const AMethodPattern: string; out ARouter: IRouter): Boolean; -var - LSegmentPattern: string; - LRouteType: TRouteType; - LChild: TRouteNode; - LFound: Boolean; -begin - Result := False; - - if (AIndex > High(APathPatternSegments)) then - begin - // 到达路径末尾, 查找该节点的路由 - Result := ANode.GetRouter(AMethodPattern, ARouter); - Exit; - end; - - LSegmentPattern := APathPatternSegments[AIndex]; - LRouteType := GetPatternType(LSegmentPattern); - - case LRouteType of - rtStatic: - // 从静态子节点中查找路由 - if ANode.StaticChildren.TryGetValue(LSegmentPattern.ToLower, LChild) then - begin - LFound := GetRouterFromNode(LChild, APathPatternSegments, AIndex + 1, AMethodPattern, ARouter); - Result := Result or LFound; - end; - - rtRegex: - // 从正则子节点中查找路由 - for LChild in ANode.RegexChildren do - begin - if SameText(LChild.Segment.Original, LSegmentPattern) then - begin - LFound := GetRouterFromNode(LChild, APathPatternSegments, AIndex + 1, AMethodPattern, ARouter); - Result := Result or LFound; - if Result then Break; - end; - end; - - rtWildcard: - // 从通配符子节点查找路由 - if (ANode.WildcardChild <> nil) then - begin - LFound := ANode.WildcardChild.GetRouter(AMethodPattern, ARouter); - Result := Result or LFound; - end; - end; -end; - -function TCrossHttpRouterTree.GetWildcardValue( - const APathSegments: TArray; AIndex: Integer; - const AQueryText: string): string; -begin - Result := string.Join('/', APathSegments, AIndex, Length(APathSegments) - AIndex); - if (AQueryText <> '') then - Result := Result + '?' + AQueryText; -end; - -function TCrossHttpRouterTree.MatchRouterInNode(ANode: TRouteNode; - const APathSegments: TArray; AIndex: Integer; const AMethod: string; - const ARequest: ICrossHttpRequest; out ARouter: IRouter): Boolean; -var - LSegment, LWildcardValue: string; - LChild: TRouteNode; -begin - Result := False; - - if (AIndex > High(APathSegments)) then - begin - // 到达路径末尾, 查找匹配方法的路由 - Result := ANode.MatchRouter(AMethod, ARouter); - - // 尝试从通配符子节点查找路由 - if not Result and (ANode.WildcardChild <> nil) then - begin - Result := ANode.WildcardChild.MatchRouter(AMethod, ARouter); - if Result then - begin - LWildcardValue := GetWildcardValue(APathSegments, AIndex, ARequest.QueryText); - if Assigned(ARequest) then - ARequest.Params[WILDCARD_CHAR] := LWildcardValue; - end; - end; - - Exit; - end; - - LSegment := APathSegments[AIndex]; - - // 1. 首先尝试精确匹配静态节点 - if ANode.StaticChildren.TryGetValue(LSegment.ToLower, LChild) then - begin - Result := MatchRouterInNode(LChild, APathSegments, AIndex + 1, AMethod, - ARequest, ARouter); - if Result then Exit; - end; - - // 2. 尝试正则节点(支持多参数) - for LChild in ANode.RegexChildren do - begin - if LChild.Segment.RegexMatch(LSegment, ARequest) then - begin - // 普通正则节点, 继续递归匹配 - Result := MatchRouterInNode(LChild, APathSegments, AIndex + 1, AMethod, - ARequest, ARouter); - if Result then Exit; - end; - end; - - // 3. 最后尝试通配符子节点(优先级最低) - if (ANode.WildcardChild <> nil) then - begin - Result := ANode.WildcardChild.MatchRouter(AMethod, ARouter); - if Result then - begin - LWildcardValue := GetWildcardValue(APathSegments, AIndex, ARequest.QueryText); - if Assigned(ARequest) then - ARequest.Params[WILDCARD_CHAR] := LWildcardValue; - - Exit; - end; - end; -end; - -function TCrossHttpRouterTree.MatchRouter(const APathSegments: TArray; - const ARequest: ICrossHttpRequest; out ARouter: IRouter): Boolean; -begin - FLock.BeginRead; - try - if FRoot.IsEmpty then - begin - ARouter := nil; - Exit(False); - end; - - Result := MatchRouterInNode(FRoot, APathSegments, 0, ARequest.Method, ARequest, ARouter); - finally - FLock.EndRead; - end; -end; - -function TCrossHttpRouterTree.MatchRouter(const ARequest: ICrossHttpRequest; - out ARouter: IRouter): Boolean; -var - LPathSegments: TArray; -begin - LPathSegments := ParsePath(ARequest.Path); - Result := MatchRouter(LPathSegments, ARequest, ARouter); -end; - -function TCrossHttpRouterTree.RemoveRouterFromNode(ANode: TRouteNode; - const APathPatternSegments: TArray; AIndex: Integer; const AMethodPattern: string): Boolean; -var - LSegmentPattern, LLowerSegment: string; - LRouteType: TRouteType; - LChild: TRouteNode; - LRemoved: Boolean; - I: Integer; -begin - Result := False; - - if (AIndex > High(APathPatternSegments)) then - begin - // 到达路径末尾, 删除该节点的路由 - Result := ANode.RemoveRouter(AMethodPattern); - Exit; - end; - - LSegmentPattern := APathPatternSegments[AIndex]; - LRouteType := GetPatternType(LSegmentPattern); - LLowerSegment := LSegmentPattern.ToLower; - - case LRouteType of - rtStatic: - // 从静态子节点中删除路由 - if ANode.StaticChildren.TryGetValue(LLowerSegment, LChild) then - begin - LRemoved := RemoveRouterFromNode(LChild, APathPatternSegments, AIndex + 1, AMethodPattern); - - // 如果子节点变空, 删除它 - if LRemoved and LChild.IsEmpty then - ANode.StaticChildren.Remove(LLowerSegment); - - Result := Result or LRemoved; - end; - - rtRegex: - // 从正则子节点中删除路由(逆序遍历,避免在迭代中修改集合) - for I := ANode.RegexChildren.Count - 1 downto 0 do - begin - LChild := ANode.RegexChildren[I]; - if SameText(LChild.Segment.Original, LSegmentPattern) then - begin - LRemoved := RemoveRouterFromNode(LChild, APathPatternSegments, AIndex + 1, AMethodPattern); - - // 如果子节点变空, 删除它 - if LRemoved and LChild.IsEmpty then - ANode.RegexChildren.Delete(I); - - Result := Result or LRemoved; - if Result then Break; - end; - end; - - rtWildcard: - // 从通配符子节点删除路由 - if (ANode.WildcardChild <> nil) then - begin - LRemoved := ANode.WildcardChild.RemoveRouter(AMethodPattern); - - // 如果子节点变空, 删除它 - if LRemoved and ANode.WildcardChild.IsEmpty then - FreeAndNil(ANode.FWildcardChild); - - Result := Result or LRemoved; - end; - end; -end; - -procedure TCrossHttpRouterTree.RemoveRouter(const AMethodPattern, APathPattern: string); -var - LPathSegments: TArray; -begin - FLock.BeginWrite; - try - LPathSegments := ParsePath(APathPattern); - RemoveRouterFromNode(FRoot, LPathSegments, 0, AMethodPattern); - finally - FLock.EndWrite; - end; -end; - -procedure TCrossHttpRouterTree.Clear; -begin - FLock.BeginWrite; - try - FreeAndNil(FRoot); - FRoot := TRouteNode.Create(rtStatic, TRouteSegment.Create('', '', [], rtStatic)); - finally - FLock.EndWrite; - end; -end; - -{ TCrossHttpServer } - -function TCrossHttpServer.All(const APath: string; - const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; -begin - Result := Route('*', APath, ARouterProc); -end; - -function TCrossHttpServer.All(const APath: string; - const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; -begin - Result := Route('*', APath, ARouterMethod); -end; - -constructor TCrossHttpServer.Create(const AIoThreads: Integer; const ASsl: Boolean); -begin - inherited Create(AIoThreads, ASsl); - - FRouters := TCrossHttpRouterTree.Create; - FMiddlewares := TCrossHttpRouterTree.Create; - - Port := 80; - Addr := ''; - - FCompressible := True; - FMinCompressSize := MIN_COMPRESS_SIZE; - FMaxCompressRatio := DEFAULT_MAX_COMPRESS_RATIO; - FStoragePath := TCrossHttpUtils.CombinePath(TUtils.AppPath, 'temp', PathDelim) + PathDelim; - FSessionIDCookieName := SESSIONID_COOKIE_NAME; -end; - -function TCrossHttpServer.CreateConnection(const AOwner: TCrossSocketBase; - const AClientSocket: TSocket; const AConnectType: TConnectType; - const AHost: string; const AConnectCb: TCrossConnectionCallback): ICrossConnection; -begin - Result := TCrossHttpConnection.Create( - AOwner, - AClientSocket, - AConnectType, - AHost, - AConnectCb); -end; - -destructor TCrossHttpServer.Destroy; -begin - Stop; - - FreeAndNil(FRouters); - FreeAndNil(FMiddlewares); - - inherited Destroy; -end; - -function TCrossHttpServer.Dir(const APath, ALocalDir: string): ICrossHttpServer; -var - LReqPath: string; -begin - LReqPath := APath; - if not LReqPath.EndsWith('/') then - LReqPath := LReqPath + '/'; - LReqPath := LReqPath + '*'; - Result := Get(LReqPath, TNetCrossRouter.Dir(APath, ALocalDir, '*')); -end; - -function TCrossHttpServer.Delete(const APath: string; - const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; -begin - Result := Route('DELETE', APath, ARouterProc); -end; - -function TCrossHttpServer.Delete(const APath: string; - const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; -begin - Result := Route('DELETE', APath, ARouterMethod); -end; - -procedure TCrossHttpServer.DoOnRequestBegin( - const AConnection: ICrossHttpConnection; - const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse); -begin - if Assigned(FOnRequestBegin) then - FOnRequestBegin(Self, AConnection, ARequest, AResponse); -end; - -procedure TCrossHttpServer.DoOnRequestEnd( - const AConnection: ICrossHttpConnection; - const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse; - const ASuccess: Boolean); -begin - if Assigned(FOnRequestEnd) then - FOnRequestEnd(Self, AConnection, ARequest, AResponse, ASuccess); -end; - -procedure TCrossHttpServer.DoOnRequest(const AConnection: ICrossHttpConnection; - const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse); -var - LRequest: ICrossHttpRequest; - LResponse: ICrossHttpResponse; - LSessionID: string; - LPathSegments: TArray; - LHandled: Boolean; - LRouter: IRouter; -begin - // 显式接收来自 _OnParseSuccess 的 request/response, 不再读取连接字段, - // 避免与 _FinishQueueItem 等异步线程构成 race - LRequest := ARequest; - LResponse := AResponse; - LHandled := False; - - try - {$region 'Session'} - if (FSessions <> nil) and (FSessionIDCookieName <> '') then - begin - LSessionID := LRequest.Cookies[FSessionIDCookieName]; - (LRequest as TCrossHttpRequest).FSession := FSessions.Sessions[LSessionID]; - if (LRequest.Session <> nil) and (LRequest.Session.SessionID <> LSessionID) then - begin - LSessionID := LRequest.Session.SessionID; - LResponse.Cookies.AddOrSet(FSessionIDCookieName, LSessionID, 0); - end; - end; - {$endregion} - - // 提前拆分请求路径, 可以减少一次 ParsePath 调用 - LPathSegments := TCrossHttpRouterTree.ParsePath(LRequest.Path); - - {$region '中间件'} - // 执行匹配的中间件 - if FMiddlewares.MatchRouter(LPathSegments, LRequest, LRouter) then - begin - // 中间件通常用于请求的预处理 - // 所以默认将 LHandled 置为 False, 以保证后续路由能被执行 - // 除非用户在中间件中明确指定了 LHandled := True, 表明该请求无需后续路由响应了 - LHandled := False; - LRouter.Execute(LRequest, LResponse, LHandled); - - // 如果已经发送了数据, 则后续的事件和路由响应都不需要执行了 - if LHandled or LResponse.Sent then Exit; - end; - {$endregion} - - {$region '路由'} - // 执行匹配的路由 - if FRouters.MatchRouter(LPathSegments, LRequest, LRouter) then - begin - // 路由用于响应请求 - // 所以默认将 LHandled 置为 True, 以保证不会有多个匹配的路由被执行 - // 除非用户在路由中明确指定了 LHandled := False, 表明该路由并没有 - // 完成请求响应, 还需要后续路由继续进行响应 - LHandled := True; - LRouter.Execute(LRequest, LResponse, LHandled); - - // 如果已经发送了数据, 则后续的事件和路由响应都不需要执行了 - if LHandled or LResponse.Sent then Exit; - end; - {$endregion} - - {$region '响应请求事件'} - if Assigned(FOnRequest) - and not (LHandled or LResponse.Sent) then - begin - FOnRequest(Self, AConnection, LRequest, LResponse, LHandled); - - // 如果已经发送了数据, 则后续的事件和路由响应都不需要执行了 - if LHandled or LResponse.Sent then Exit; - end; - {$endregion} - - // 如果该请求没有被任何中间件、事件、路由响应, 返回 404 - if not (LHandled or LResponse.Sent) then - LResponse.SendStatus(404); - except - on e: Exception do - begin - if Assigned(FOnRequestException) then - FOnRequestException(Self, LRequest, LResponse, e) - else if LResponse.Sent then - AConnection.Disconnect - else if (e is ECrossHttpException) then - LResponse.SendStatus(ECrossHttpException(e).StatusCode, ECrossHttpException(e).Message) - else - LResponse.SendStatus(500, e.Message); - end; - end; -end; - -function TCrossHttpServer.Get(const APath: string; - const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; -begin - Result := Route('GET', APath, ARouterProc); -end; - -function TCrossHttpServer.Get(const APath: string; - const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; -begin - Result := Route('GET', APath, ARouterMethod); -end; - -function TCrossHttpServer.GetOnRequestEnd: TCrossHttpRequestEndEvent; -begin - Result := FOnRequestEnd; -end; - -function TCrossHttpServer.GetAutoDeleteFiles: Boolean; -begin - Result := FAutoDeleteFiles; -end; - -function TCrossHttpServer.GetOnRequestBegin: TCrossHttpRequestBeginEvent; -begin - Result := FOnRequestBegin; -end; - -function TCrossHttpServer.GetCompressible: Boolean; -begin - Result := FCompressible; -end; - -function TCrossHttpServer.GetMaxHeaderSize: Int64; -begin - Result := FMaxHeaderSize; -end; - -function TCrossHttpServer.GetMaxPostDataSize: Int64; -begin - Result := FMaxPostDataSize; -end; - -function TCrossHttpServer.GetMaxCompressRatio: Integer; -begin - Result := FMaxCompressRatio; -end; - -function TCrossHttpServer.GetMinCompressSize: Int64; -begin - Result := FMinCompressSize; -end; - -function TCrossHttpServer.GetOnRequest: TCrossHttpRequestEvent; -begin - Result := FOnRequest; -end; - -function TCrossHttpServer.GetOnRequestException: TCrossHttpRequestExceptionEvent; -begin - Result := FOnRequestException; -end; - -function TCrossHttpServer.GetSessionIDCookieName: string; -begin - Result := FSessionIDCookieName; -end; - -function TCrossHttpServer.GetSessions: ISessions; -begin - Result := FSessions; -end; - -function TCrossHttpServer.GetStoragePath: string; -begin - Result := FStoragePath; -end; - -procedure TCrossHttpServer.SetOnRequestEnd(const Value: TCrossHttpRequestEndEvent); -begin - FOnRequestEnd := Value; -end; - -procedure TCrossHttpServer.SetAutoDeleteFiles(const Value: Boolean); -begin - FAutoDeleteFiles := Value; -end; - -procedure TCrossHttpServer.SetOnRequestBegin(const Value: TCrossHttpRequestBeginEvent); -begin - FOnRequestBegin := Value; -end; - -procedure TCrossHttpServer.SetCompressible(const Value: Boolean); -begin - FCompressible := Value; -end; - -procedure TCrossHttpServer.SetMaxHeaderSize(const Value: Int64); -begin - FMaxHeaderSize := Value; -end; - -procedure TCrossHttpServer.SetMaxPostDataSize(const Value: Int64); -begin - FMaxPostDataSize := Value; -end; - -procedure TCrossHttpServer.SetMaxCompressRatio(const Value: Integer); -begin - FMaxCompressRatio := Value; -end; - -procedure TCrossHttpServer.SetMinCompressSize(const Value: Int64); -begin - FMinCompressSize := Value; -end; - -procedure TCrossHttpServer.SetOnRequest(const Value: TCrossHttpRequestEvent); -begin - FOnRequest := Value; -end; - -procedure TCrossHttpServer.SetOnRequestException( - const Value: TCrossHttpRequestExceptionEvent); -begin - FOnRequestException := Value; -end; - -procedure TCrossHttpServer.SetSessionIDCookieName(const Value: string); -begin - FSessionIDCookieName := Value; -end; - -procedure TCrossHttpServer.SetSessions(const Value: ISessions); -begin - FSessions := Value; -end; - -procedure TCrossHttpServer.SetStoragePath(const Value: string); -begin - FStoragePath := Value; -end; - -function TCrossHttpServer.Static(const APath, - ALocalStaticDir: string): ICrossHttpServer; -var - LReqPath: string; -begin - LReqPath := APath; - if not LReqPath.EndsWith('/') then - LReqPath := LReqPath + '/'; - LReqPath := LReqPath + '*'; - Result := Get(LReqPath, TNetCrossRouter.Static(ALocalStaticDir, '*')); -end; - -function TCrossHttpServer.Index(const APath, ALocalDir: string; - const ADefIndexFiles: TArray): ICrossHttpServer; -var - LReqPath: string; -begin - LReqPath := APath; - if not LReqPath.EndsWith('/') then - LReqPath := LReqPath + '/'; - LReqPath := LReqPath + '*'; - Result := Get(LReqPath, TNetCrossRouter.Index(ALocalDir, '*', ADefIndexFiles)); -end; - -function TCrossHttpServer.Post(const APath: string; - const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; -begin - Result := Route('POST', APath, ARouterProc); -end; - -function TCrossHttpServer.Post(const APath: string; - const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; -begin - Result := Route('POST', APath, ARouterMethod); -end; - -function TCrossHttpServer.Put(const APath: string; - const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; -begin - Result := Route('PUT', APath, ARouterMethod); -end; - -function TCrossHttpServer.Put(const APath: string; - const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; -begin - Result := Route('PUT', APath, ARouterProc); -end; - -function TCrossHttpServer.Route(const AMethod, APath: string; - const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; -begin - FRouters.AddRouter(AMethod, APath, ARouterProc); - Result := Self; -end; - -function TCrossHttpServer.Route(const AMethod, APath: string; - const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; -begin - FRouters.AddRouter(AMethod, APath, ARouterMethod); - Result := Self; -end; - -function TCrossHttpServer.RemoveMiddleware(const AMethod, - APath: string): ICrossHttpServer; -begin - FMiddlewares.RemoveRouter(AMethod, APath); - Result := Self; -end; - -function TCrossHttpServer.RemoveRouter(const AMethod, APath: string): ICrossHttpServer; -begin - FRouters.RemoveRouter(AMethod, APath); - Result := Self; -end; - -function TCrossHttpServer.ClearMiddlewares: ICrossHttpServer; -begin - FMiddlewares.Clear; - Result := Self; -end; - -function TCrossHttpServer.ClearRouters: ICrossHttpServer; -begin - FRouters.Clear; - Result := Self; -end; - -procedure TCrossHttpServer.LogicReceived(const AConnection: ICrossConnection; - const ABuf: Pointer; const ALen: Integer); -var - LConnObj: TCrossHttpConnection; - LBuf: Pointer; - LLen: Integer; -begin - LConnObj := AConnection as TCrossHttpConnection; - LBuf := ABuf; - LLen := ALen; - - while (LLen > 0) do - LConnObj.ParseRecvData(LBuf, LLen); - - inherited LogicReceived(AConnection, ABuf, ALen); -end; - -function TCrossHttpServer.Use( - const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; -begin - Result := Use('*', '*', AMiddlewareMethod); -end; - -function TCrossHttpServer.Use( - const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; -begin - Result := Use('*', '*', AMiddlewareProc); -end; - -function TCrossHttpServer.Use(const AMethod, APath: string; - const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; -begin - FMiddlewares.AddRouter(AMethod, APath, AMiddlewareMethod); - Result := Self; -end; - -function TCrossHttpServer.Use(const AMethod, APath: string; - const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; -begin - FMiddlewares.AddRouter(AMethod, APath, AMiddlewareProc); - Result := Self; -end; - -function TCrossHttpServer.Use(const APath: string; - const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; -begin - Result := Use('*', APath, AMiddlewareMethod); -end; - -function TCrossHttpServer.Use(const APath: string; - const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; -begin - Result := Use('*', APath, AMiddlewareProc); -end; - -{ TCrossHttpRequest } - -constructor TCrossHttpRequest.Create(const AConnection: TCrossHttpConnection); -begin - FConnectionObj := AConnection; - FConnection := AConnection; - FServer := FConnection.Owner as TCrossHttpServer; - - FHeader := THttpHeader.Create; - FCookies := TRequestCookies.Create; - FParams := THttpUrlParams.Create; - FQuery := THttpUrlParams.Create; -end; - -destructor TCrossHttpRequest.Destroy; -begin - FreeAndNil(FHeader); - FreeAndNil(FCookies); - FreeAndNil(FParams); - FreeAndNil(FQuery); - if (FBody = FRawBody) then - FBody := nil - else - FreeAndNil(FBody); - FreeAndNil(FRawBody); - - inherited; -end; - -function TCrossHttpRequest.GetAccept: string; -begin - Result := FAccept; -end; - -function TCrossHttpRequest.GetAcceptEncoding: string; -begin - Result := FAcceptEncoding; -end; - -function TCrossHttpRequest.GetAcceptLanguage: string; -begin - Result := FAcceptLanguage; -end; - -function TCrossHttpRequest.GetAuthorization: string; -begin - Result := FAuthorization; -end; - -function TCrossHttpRequest.GetBody: TObject; -begin - Result := FBody; -end; - -function TCrossHttpRequest.GetRawBody: TStream; -begin - Result := FRawBody; -end; - -function TCrossHttpRequest.GetBodyType: TBodyType; -begin - Result := FBodyType; -end; - -function TCrossHttpRequest.GetConnection: ICrossHttpConnection; -begin - Result := FConnection; -end; - -function TCrossHttpRequest.GetContentEncoding: string; -begin - Result := FContentEncoding; -end; - -function TCrossHttpRequest.GetContentLength: Int64; -begin - Result := FContentLength; -end; - -function TCrossHttpRequest.GetContentType: string; -begin - Result := FContentType; -end; - -function TCrossHttpRequest.GetCookies: TRequestCookies; -begin - Result := FCookies; -end; - -function TCrossHttpRequest.GetHeader: THttpHeader; -begin - Result := FHeader; -end; - -function TCrossHttpRequest.GetHostName: string; -begin - Result := FHostName; -end; - -function TCrossHttpRequest.GetHostPort: Word; -begin - Result := FHostPort; -end; - -function TCrossHttpRequest.GetIfModifiedSince: TDateTime; -begin - Result := FIfModifiedSince; -end; - -function TCrossHttpRequest.GetIfNoneMatch: string; -begin - Result := FIfNoneMatch; -end; - -function TCrossHttpRequest.GetIfRange: string; -begin - Result := FIfRange; -end; - -function TCrossHttpRequest.GetIsChunked: Boolean; -begin - Result := FIsChunked; -end; - -function TCrossHttpRequest.CalcIsChunked: Boolean; -var - LEncodings: TArray; -begin - // RFC 7230 §3.3.1: Transfer-Encoding 可以是逗号分隔列表, 最终编码为最后一个 - LEncodings := FTransferEncoding.Trim.Split([',']); - if Length(LEncodings) > 0 then - Result := TStrUtils.SameText(LEncodings[Length(LEncodings) - 1].Trim, 'chunked') - else - Result := False; -end; - -function TCrossHttpRequest.GetIsMultiPartFormData: Boolean; -begin - Result := TStrUtils.SameText(FContentType, TMediaType.MULTIPART_FORM_DATA); -end; - -function TCrossHttpRequest.GetIsUrlEncodedFormData: Boolean; -begin - Result := TStrUtils.SameText(FContentType, TMediaType.APPLICATION_FORM_URLENCODED_TYPE); -end; - -function TCrossHttpRequest.GetKeepAlive: Boolean; -begin - Result := FKeepAlive; -end; - -function TCrossHttpRequest.GetMethod: string; -begin - Result := FMethod; -end; - -function TCrossHttpRequest.GetParams: THttpUrlParams; -begin - Result := FParams; -end; - -function TCrossHttpRequest.GetQueryText: string; -begin - Result := FQueryText; -end; - -function TCrossHttpRequest.GetPath: string; -begin - Result := FPath; -end; - -function TCrossHttpRequest.GetPathAndQuery: string; -begin - Result := FPathAndQuery; -end; - -function TCrossHttpRequest.GetPostDataSize: Int64; -begin - Result := FPostDataSize; -end; - -function TCrossHttpRequest.GetQuery: THttpUrlParams; -begin - Result := FQuery; -end; - -function TCrossHttpRequest.GetRange: string; -begin - Result := FRange; -end; - -function TCrossHttpRequest.GetRawPathAndQuery: string; -begin - Result := FRawPathAndQuery; -end; - -function TCrossHttpRequest.GetRawRequestText: string; -begin - Result := FRawRequestText; -end; - -function TCrossHttpRequest.GetReferer: string; -begin - Result := FReferer; -end; - -function TCrossHttpRequest.GetRequestBoundary: string; -begin - Result := FRequestBoundary; -end; - -function TCrossHttpRequest.GetRequestCmdLine: string; -begin - Result := FRequestCmdLine; -end; - -function TCrossHttpRequest.GetRequestConnection: string; -begin - Result := FRequestConnection; -end; - -function TCrossHttpRequest.GetSession: ISession; -begin - Result := FSession; -end; - -function TCrossHttpRequest.GetTransferEncoding: string; -begin - Result := FTransferEncoding; -end; - -function TCrossHttpRequest.GetUserAgent: string; -begin - Result := FUserAgent; -end; - -function TCrossHttpRequest.GetVersion: string; -begin - Result := FVersion; -end; - -function TCrossHttpRequest.GetXForwardedFor: string; -begin - Result := FXForwardedFor; -end; - -function TCrossHttpRequest.ParseHeader(const ADataPtr: Pointer; - const ADataSize: Integer): Boolean; -var - LRequestHeader, LPortStr: string; - LCookieValues, LCLValues: TArray; - LFirstCL: string; - I, J: Integer; - LPortInt: Integer; -begin - Assert(Self <> nil, 'FRequest is nil'); - - // 整体包一层 try/except 保证任何畸形输入都以 Result := False 返回, - // 不会让异常上抛到 _OnHeaderData 环外. 常见调用点如: - // - Substring/IndexOf 上的越界 (请求行过短、缺少空格等) - // - LPortStr.ToInteger 遇到非数字时抛 EConvertError - // - THttpHeader.Decode 内部异常 - // - FCookies.Decode 内部异常 - // 都被这里统一归为 400 Bad Request - try - SetString(FRawRequestText, MarshaledAString(ADataPtr), ADataSize); - - // 拒绝包含 NUL 字节的请求 (可能导致跨编译器字符串行为差异) - if (FRawRequestText.IndexOf(#0) >= 0) then - Exit(False); - - I := FRawRequestText.IndexOf(#13#10); - // 第一行是请求命令行 - // GET /home?param=123 HTTP/1.1 - FRequestCmdLine := FRawRequestText.Substring(0, I); - // 第二行起是请求头 - LRequestHeader := FRawRequestText.Substring(I + 2); - // 解析请求头 - FHeader.Decode(LRequestHeader); - - // 请求行必须包含三段: METHOD SP PATH SP VERSION (RFC 7230 §3.1.1) - // 任何一段为空都不合法, 否则会出现: - // - FMethod=='' 导致路由匹配疑难 - // - FVersion 含错位片段 (如 "GET") 导致 _CreateHeader 输出伪 HTTP 状态行 - // 这里在拆分前先检查两个空格的位置严格递增, 三段均非空 - I := FRequestCmdLine.IndexOf(' '); - if (I <= 0) then Exit(False); - J := FRequestCmdLine.IndexOf(' ', I + 1); - if (J <= I + 1) or (J >= FRequestCmdLine.Length - 1) then Exit(False); - - // 请求方法(GET, POST, PUT, DELETE...) - FMethod := FRequestCmdLine.Substring(0, I).ToUpper; - - // 路径及参数(/home?param=123) - FRawPathAndQuery := FRequestCmdLine.Substring(I + 1, J - I - 1); - - // 请求的HTTP版本(HTTP/1.1) - FVersion := FRequestCmdLine.Substring(J + 1).ToUpper; - - // 解析?key1=value1&key2=value2参数 - J := FRawPathAndQuery.IndexOf('?'); - if (J < 0) then - begin - FRawPath := FRawPathAndQuery; - FRawQueryText := ''; - FQueryText := ''; - end else - begin - FRawPath := FRawPathAndQuery.Substring(0, J); - FRawQueryText := FRawPathAndQuery.Substring(J + 1); - FQueryText := TCrossHttpUtils.UrlDecode(FRawQueryText); - end; - - FPath := TCrossHttpUtils.UrlDecode(FRawPath); - FPathAndQuery := FPath; - if (FQueryText <> '') then - FPathAndQuery := FPathAndQuery + '?' + FQueryText; - - FQuery.Decode(FRawQueryText); - - // HTTP协议版本 - if (FVersion = '') then - FVersion := 'HTTP/1.0'; - if (FVersion = 'HTTP/1.0') then - FHttpVerNum := 10 - else - FHttpVerNum := 11; - FKeepAlive := (FHttpVerNum = 11); - - FContentType := FHeader[HEADER_CONTENT_TYPE]; - FRequestBoundary := ''; - J := FContentType.IndexOf(';'); - if (J >= 0) then - begin - // RFC 2046: 分号前后允许有任意空白, 兼容 "; boundary=" 和 ";boundary=" 两种格式 - FRequestBoundary := FContentType.Substring(J + 1).Trim; - if FRequestBoundary.StartsWith('boundary=', True) then - FRequestBoundary := FRequestBoundary.Substring(9); - - FContentType := FContentType.Substring(0, J).Trim; - end; - - // RFC 7230 §3.3.2: 多个 Content-Length 值不同时必须拒绝请求 - if FHeader.GetHeaderValues(HEADER_CONTENT_LENGTH, LCLValues) and (Length(LCLValues) > 0) then - begin - LFirstCL := LCLValues[0].Trim; - for I := 1 to High(LCLValues) do - if not TStrUtils.SameText(LCLValues[I].Trim, LFirstCL) then - Exit(False); - FContentLength := StrToInt64Def(LFirstCL, -1); - end else - FContentLength := -1; - - // IPv4: 192.168.1.100:8080 - // 192.168.1.100 - // IPv6: [fc00::20:80:5:2]:8080 - // [fc00::20:80:5:2] - FRequestHost := FHeader[HEADER_HOST]; - LPortStr := ''; - - J := FRequestHost.IndexOf(']'); - if (J >= 0) then - begin - FHostName := FRequestHost.Substring(1, J - 1); - J := FRequestHost.IndexOf(':', J); - if (J >= 0) then - LPortStr := FRequestHost.Substring(J + 1); - end else - begin - J := FRequestHost.IndexOf(':'); - if (J >= 0) then - begin - FHostName := FRequestHost.Substring(0, J); - LPortStr := FRequestHost.Substring(J + 1); - end else - FHostName := FRequestHost; - end; - // RFC 7230 §5.4: Host 头中 port 必须是十进制数字. 这里用 TryStrToInt - // 避免 ToInteger 在畸形输入 (如 "abc"、超出 Int32 范围) 时抛 EConvertError; - // 超出 Word (0..65535) 范围亦视为非法 port, 不静默截断高位 - if (LPortStr <> '') then - begin - if not TryStrToInt(LPortStr, LPortInt) - or (LPortInt < 0) or (LPortInt > High(Word)) then - Exit(False); - FHostPort := Word(LPortInt); - end else - FHostPort := GetConnection.Server.Port; - - FRequestConnection := FHeader[HEADER_CONNECTION]; - // HTTP/1.0 默认KeepAlive=False,只有显示指定了Connection: keep-alive才认为KeepAlive=True - // HTTP/1.1 默认KeepAlive=True,只有显示指定了Connection: close才认为KeepAlive=False - if FHttpVerNum = 10 then - FKeepAlive := TStrUtils.SameText(FRequestConnection, 'keep-alive') - else if TStrUtils.SameText(FRequestConnection, 'close') then - FKeepAlive := False; - - FTransferEncoding := FHeader[HEADER_TRANSFER_ENCODING]; - FIsChunked := CalcIsChunked; - FContentEncoding := FHeader[HEADER_CONTENT_ENCODING]; - FAccept := FHeader[HEADER_ACCEPT]; - FReferer := FHeader[HEADER_REFERER]; - FAcceptLanguage := FHeader[HEADER_ACCEPT_LANGUAGE]; - FAcceptEncoding := FHeader[HEADER_ACCEPT_ENCODING]; - FUserAgent := FHeader[HEADER_USER_AGENT]; - FAuthorization := FHeader[HEADER_AUTHORIZATION]; - // 获取并解析 Cookie 头 - // RFC 6265 建议客户端只发送一个 Cookie 头 - // 但部分代理/旧客户端可能拆分成多行,按 RFC 7230 §3.2.2 合并处理 - if FHeader.GetHeaderValues(HEADER_COOKIE, LCookieValues) - and (Length(LCookieValues) > 0) then - begin - // RFC 6265 建议客户端只发送一个 Cookie 头 - // 但部分代理/旧客户端可能拆分成多行,按 RFC 7230 §3.2.2 合并处理 - if (Length(LCookieValues) = 1) then - FRequestCookies := LCookieValues[0] - else - FRequestCookies := string.Join('; ', LCookieValues); - end else - FRequestCookies := ''; - FIfModifiedSince := TCrossHttpUtils.RFC1123_StrToDate(FHeader[HEADER_IF_MODIFIED_SINCE]); - FIfNoneMatch := FHeader[HEADER_IF_NONE_MATCH]; - FRange := FHeader[HEADER_RANGE]; - FIfRange := FHeader[HEADER_IF_RANGE]; - FXForwardedFor:= FHeader[HEADER_X_FORWARDED_FOR]; - - // 解析Cookies - if (FRequestCookies <> '') then - begin - if not FCookies.Decode(FRequestCookies, True) then Exit(False); - end else - FCookies.Clear; - - if IsMultiPartFormData then - FBodyType := btMultiPart - else if IsUrlEncodedFormData then - FBodyType := btUrlEncoded - else - FBodyType := btBinary; - - Result := True; - except - // 任何解析异常都归一为 Result := False, 由 _OnHeaderData 发 400. - // 不记详细错误原因 (不足类型安全且可能被恶意请求刷日志), - // 需要调试时可临时加 Logger 输出. - on Exception do - Result := False; - end; -end; - -{ TCrossHttpResponse } - -constructor TCrossHttpResponse.Create(const AConnection: TCrossHttpConnection; - const ARequest: ICrossHttpRequest; - const AQueueItem: IHttpResponseQueueItem); -begin - FConnectionObj := AConnection; - FConnection := AConnection; - FRequest := ARequest; - FQueueItem := AQueueItem; - FHeader := THttpHeader.Create; - FCookies := TResponseCookies.Create; - FStatusCode := 200; -end; - -destructor TCrossHttpResponse.Destroy; -begin - FreeAndNil(FHeader); - FreeAndNil(FCookies); - FQueueItem := nil; - inherited; -end; - -procedure TCrossHttpResponse.Download(const AFileName: string; - const ACallback: TCrossConnectionCallback); -begin - Attachment(AFileName); - SendFile(AFileName, ACallback); -end; - -function TCrossHttpResponse.GetConnection: ICrossHttpConnection; -begin - Result := FConnection; -end; - -function TCrossHttpResponse.GetContentType: string; -begin - Result := FHeader[HEADER_CONTENT_TYPE]; -end; - -function TCrossHttpResponse.GetCookies: TResponseCookies; -begin - Result := FCookies; -end; - -function TCrossHttpResponse.GetHeader: THttpHeader; -begin - Result := FHeader; -end; - -function TCrossHttpResponse.GetLocation: string; -begin - Result := FHeader[HEADER_LOCATION]; -end; - -function TCrossHttpResponse.GetRequest: ICrossHttpRequest; -begin - Result := FRequest; -end; - -function TCrossHttpResponse.GetSent: Boolean; -begin - Result := (AtomicCmpExchange(FSendStatus, 0, 0) > 0); -end; - -function TCrossHttpResponse.GetStatusCode: Integer; -begin - Result := FStatusCode; -end; - -function TCrossHttpResponse.GetStatusText: string; -begin - Result := FStatusText; -end; - -procedure TCrossHttpResponse.Json(const AJson: string; - const ACallback: TCrossConnectionCallback); -begin - SetContentType(TMediaType.APPLICATION_JSON_UTF8); - Send(AJson, ACallback); -end; - -procedure TCrossHttpResponse.Redirect(const AUrl: string; const ACallback: TCrossConnectionCallback); -begin - SetLocation(AUrl); - SendStatus(302, '', ACallback); -end; - -procedure TCrossHttpResponse.Reset; -begin - FSendStatus := 0; - FStatusCode := 200; - FHeader.Clear; - FCookies.Clear; -end; - -procedure TCrossHttpResponse.Attachment(const AFileName: string); -begin - if (GetContentType = '') then - SetContentType(TCrossHttpUtils.GetFileMIMEType(AFileName)); - FHeader[HEADER_CONTENT_DISPOSITION] := 'attachment; filename="' + - TCrossHttpUtils.UrlEncode(ExtractFileName(AFileName)) + '"'; -end; - -procedure TCrossHttpResponse.Send(const ABody: Pointer; const ACount: NativeInt; - const ACallback: TCrossConnectionCallback); -var - LCompressType: TCompressType; -begin - if _CheckCompress(ACount, LCompressType) then - SendZCompress(ABody, ACount, LCompressType, ACallback) - else - SendNoCompress(ABody, ACount, ACallback); -end; - -procedure TCrossHttpResponse.Send(const ABody; const ACount: NativeInt; - const ACallback: TCrossConnectionCallback); -begin - Send(@ABody, ACount, ACallback); -end; - -procedure TCrossHttpResponse.Send(const ABody: TBytes; - const AOffset, ACount: NativeInt; const ACallback: TCrossConnectionCallback); -var - LBody: TBytes; - LOffset, LCount: NativeInt; -begin - // 增加其引用计数 - LBody := ABody; - - LOffset := AOffset; - LCount := ACount; - TCrossHttpUtils.AdjustOffsetCount(Length(ABody), LOffset, LCount); - - Send(Pointer(PByte(LBody) + LOffset), LCount, - // CALLBACK - procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) - begin - // 减少引用计数 - LBody := nil; - - if Assigned(ACallback) then - ACallback(AConnection, ASuccess); - end); -end; - -procedure TCrossHttpResponse.Send(const ABody: TBytes; - const ACallback: TCrossConnectionCallback); -begin - Send(ABody, 0, Length(ABody), ACallback); -end; - -procedure TCrossHttpResponse.Send(const ABody: TStream; - const AOffset, ACount: Int64; const ACallback: TCrossConnectionCallback); -var - LCompressType: TCompressType; -begin - if (ABody <> nil) and _CheckCompress(ABody.Size, LCompressType) then - SendZCompress(ABody, AOffset, ACount, LCompressType, ACallback) - else - SendNoCompress(ABody, AOffset, ACount, ACallback); -end; - -procedure TCrossHttpResponse.Send(const ABody: TStream; - const ACallback: TCrossConnectionCallback); -begin - Send(ABody, 0, 0, ACallback); -end; - -procedure TCrossHttpResponse.Send(const ABody: string; - const ACallback: TCrossConnectionCallback); -var - LBody: TBytes; -begin - LBody := TEncoding.UTF8.GetBytes(ABody); - if (GetContentType = '') then - SetContentType(TMediaType.TEXT_HTML_UTF8); - - Send(LBody, ACallback); -end; - -procedure TCrossHttpResponse.SendNoCompress( - const AChunkSource: TCrossHttpChunkDataFunc; - const ACallback: TCrossConnectionCallback); -{ -HTTP头\r\n\r\n -块尺寸\r\n -块内容 -\r\n块尺寸\r\n -块内容 -\r\n0\r\n\r\n -} -type - TChunkState = (csHead, csBody, csDone); -const - CHUNK_END: array [0..6] of Byte = (13, 10, 48, 13, 10, 13, 10); // \r\n0\r\n\r\n -var - LHeaderBytes, LChunkHeader: TBytes; - LChunked, LIsFirstChunk: Boolean; - LChunkState: TChunkState; - LChunkData: Pointer; - LChunkSize: NativeInt; -begin - // 先取出第一个数据块 - // 如果有数据才需要使用 chunked 方式发送数据 - if Assigned(AChunkSource) then - begin - LChunked := AChunkSource(@LChunkData, @LChunkSize) - and (LChunkData <> nil) - and (LChunkSize > 0); - end else - LChunked := False; - - LIsFirstChunk := True; - LChunkState := csHead; - - _Send( - // HEADER - function(const AData: PPointer; const ADataSize: PNativeInt): Boolean - begin - LHeaderBytes := _CreateHeader(0, LChunked); - - AData^ := @LHeaderBytes[0]; - ADataSize^ := Length(LHeaderBytes); - - Result := (ADataSize^ > 0); - end, - // BODY - function(const AData: PPointer; const ADataSize: PNativeInt): Boolean - begin - if not LChunked then Exit(False); - - case LChunkState of - csHead: - begin - if LIsFirstChunk then - begin - LIsFirstChunk := False; - LChunkHeader := []; - end else - begin - LChunkData := nil; - LChunkSize := 0; - if not Assigned(AChunkSource) - or not AChunkSource(@LChunkData, @LChunkSize) - or (LChunkData = nil) - or (LChunkSize <= 0) then - begin - LChunkState := csDone; - - AData^ := @CHUNK_END[0]; - ADataSize^ := Length(CHUNK_END); - - Result := (ADataSize^ > 0); - - Exit; - end; - - LChunkHeader := [13, 10]; - end; - - // FPC编译器在Linux下有BUG(FPC 3.3.1) - // 无法将函数返回的字节数组直接与其它字节数组使用加号拼接 - // 实际上使用加号拼接字节数组还有其它各种异常 - // 所以改用我的TArrayUtils.Concat进行拼接 - LChunkHeader := TArrayUtils.Concat([ - LChunkHeader, - TEncoding.ASCII.GetBytes(IntToHex(LChunkSize, 0)), - [13, 10] - ]); - - LChunkState := csBody; - - AData^ := @LChunkHeader[0]; - ADataSize^ := Length(LChunkHeader); - - Result := (ADataSize^ > 0); - end; - - csBody: - begin - LChunkState := csHead; - - AData^ := LChunkData; - ADataSize^ := LChunkSize; - - Result := (ADataSize^ > 0); - end; - - csDone: - begin - Result := False; - end; - else - Result := False; - end; - end, - // CALLBACK - procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) - begin - LHeaderBytes := nil; - LChunkHeader := nil; - - if Assigned(ACallback) then - ACallback(AConnection, ASuccess); - end); -end; - -procedure TCrossHttpResponse.SendFile(const AFileName: string; - const ACallback: TCrossConnectionCallback); -var - LStream: TStream; - LLastModified: TDateTime; - LRequest: TCrossHttpRequest; - LLastModifiedStr, LETag: string; - LRangeStr: string; - LRangeBegin, LRangeEnd, LOffset, LCount, LFileSize: Int64; -begin - if not FileExists(AFileName) then - begin - FHeader.Remove(HEADER_CONTENT_DISPOSITION); - SendStatus(404, ACallback); - Exit; - end; - - if (GetContentType = '') then - SetContentType(TCrossHttpUtils.GetFileMIMEType(AFileName)); - - try - // 根据请求头中的时间戳决定是否需要发送文件数据 - // 当请求头中的时间戳与文件时间一致时, 浏览器会自动从本地加载文件数据 - // 服务端无需发送文件数据 - LRequest := GetRequest as TCrossHttpRequest; - LLastModified := TFileUtils.GetLastWriteTime(AFileName); - - if (LRequest.IfModifiedSince > 0) and (LRequest.IfModifiedSince >= (LLastModified - (1 / SecsPerDay))) then - begin - // 304不要带任何body数据, 否则部分浏览器会报告无效的RESPONSE - SendStatus(304, '', ACallback); - Exit; - end; - - LLastModifiedStr := TCrossHttpUtils.RFC1123_DateToStr(LLastModified); - - LETag := '"' + TUtils.BytesToHex(THashMD5.GetHashBytes( - ExtractFileName(AFileName) + LLastModifiedStr)) + '"'; - if (LRequest.IfNoneMatch = LETag) then - begin - // 304不要带任何body数据, 否则部分浏览器会报告无效的RESPONSE - SendStatus(304, '', ACallback); - Exit; - end; - - LStream := TFileUtils.OpenRead(AFileName, fmShareDenyNone); - except - on e: Exception do - begin - FHeader.Remove(HEADER_CONTENT_DISPOSITION); - SendStatus(404, TStrUtils.Format('%s, %s', [e.ClassName, e.Message]), ACallback); - Exit; - end; - end; - - LFileSize := LStream.Size; - - // 在响应头中加入文件时间戳 - // 浏览器会根据该时间戳决定是否从本地缓存中直接加载数据 - FHeader[HEADER_LAST_MODIFIED] := LLastModifiedStr; - FHeader[HEADER_ETAG] := LETag; - - // 告诉浏览器支持分块传输 - FHeader[HEADER_ACCEPT_RANGES] := 'bytes'; - - // Range 请求处理 (RFC 7233 §3.1) - // 仅当 Range 头存在且 If-Range 校验通过 (无 If-Range 或 If-Range == ETag) 时才走分块逻辑. - // If-Range 不匹配时, RFC 7233 §3.2 要求回退为完整 200 响应. - LRangeStr := LRequest.Range; - if (LRangeStr <> '') - and ((LRequest.IfRange = '') or (LRequest.IfRange = LETag)) then - begin - if not TCrossHttpUtils.ParseSingleByteRange(LRangeStr, LFileSize, LRangeBegin, LRangeEnd) then - begin - // 不可满足的 Range -> 416 Range Not Satisfiable (RFC 7233 §4.4) - // 必须返回 Content-Range: bytes */ 告知客户端实际资源大小. - FreeAndNil(LStream); - FHeader.Remove(HEADER_CONTENT_DISPOSITION); - FHeader[HEADER_CONTENT_RANGE] := TStrUtils.Format('bytes */%d', [LFileSize]); - SendStatus(416, ACallback); - Exit; - end; - - LOffset := LRangeBegin; - LCount := LRangeEnd - LRangeBegin + 1; - - // 返回分块信息 - // Content-Range: bytes -/ - FHeader[HEADER_CONTENT_RANGE] := TStrUtils.Format('bytes %d-%d/%d', - [LRangeBegin, LRangeEnd, LFileSize]); - - // 断点续传需要返回206状态码, 而不是200 - FStatusCode := 206; - end else - begin - LOffset := 0; - LCount := LFileSize; - end; - - // 206 Range 响应禁止压缩:Content-Range 描述的是原始字节偏移, - // 压缩后字节与范围不对应,会导致断点续传客户端数据错乱 (RFC 7233) - SendNoCompress(LStream, LOffset, LCount, - procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) - begin - FreeAndNil(LStream); - - if Assigned(ACallback) then - ACallback(AConnection, ASuccess); - end); -end; - -procedure TCrossHttpResponse.SetContentType(const Value: string); -begin - FHeader[HEADER_CONTENT_TYPE] := Value; -end; - -procedure TCrossHttpResponse.SetLocation(const Value: string); -begin - FHeader[HEADER_LOCATION] := Value; -end; - -procedure TCrossHttpResponse.SetStatusCode(Value: Integer); -begin - FStatusCode := Value; -end; - -procedure TCrossHttpResponse.SetStatusText(const Value: string); -begin - FStatusText := Value; -end; - -function TCrossHttpResponse._CheckCompress(const ABodySize: Int64; - out ACompressType: TCompressType): Boolean; -var - LContType, LRequestAcceptEncoding, LEnc, LQPart: string; - LServer: ICrossHttpServer; - LEncodings: TArray; - I, LQSep: Integer; - LGzipQ, LDeflateQ, LBestQ: Double; -begin - LContType := GetContentType; - LServer := GetConnection.Server; - - if Assigned(LServer) - and LServer.Compressible - and (ABodySize > 0) - and ((LServer.MinCompressSize <= 0) or (ABodySize >= LServer.MinCompressSize)) - and ((Pos('text/', LContType.ToLower) > 0) - or (Pos('application/json', LContType.ToLower) > 0) - or (Pos('javascript', LContType.ToLower) > 0) - or (Pos('xml', LContType.ToLower) > 0) - ) then - begin - LRequestAcceptEncoding := GetRequest.AcceptEncoding; - - // 按 q-value 排序选最优编码 (RFC 7231 §5.3.4). - // q 值越高优先级越高, 缺省 q=1.0; q=0 表示明确拒绝. - LEncodings := LRequestAcceptEncoding.Split([',']); - begin - LGzipQ := 0; - LDeflateQ := 0; - for I := 0 to High(LEncodings) do - begin - LEnc := LEncodings[I].Trim; - LQSep := LEnc.IndexOf(';'); - LBestQ := 1.0; - if LQSep >= 0 then - begin - LQPart := LEnc.Substring(LQSep + 1).Trim.ToLower; - LEnc := LEnc.Substring(0, LQSep).Trim; - if LQPart.StartsWith('q=') then - LBestQ := StrToFloatDef(Copy(LQPart, 3, MaxInt), 0); - if LBestQ <= 0 then - Continue; - end; - if TStrUtils.SameText(LEnc, 'gzip') and (LBestQ > LGzipQ) then - LGzipQ := LBestQ - else if TStrUtils.SameText(LEnc, 'deflate') and (LBestQ > LDeflateQ) then - LDeflateQ := LBestQ; - end; - // 优先 gzip (服务器普遍偏好); 仅当 deflate q 严格更高时选 deflate - if (LGzipQ > 0) and (LGzipQ >= LDeflateQ) then - begin - ACompressType := ctGZip; - Exit(True); - end; - if LDeflateQ > 0 then - begin - ACompressType := ctDeflate; - Exit(True); - end; - end; - end; - - ACompressType := ctNone; - Result := False; -end; - -function TCrossHttpResponse._GetMemoryStreamPointer(const AStream: TStream; - const AOffset, ACount: Int64; out P: PByte; out LSize: Int64): Boolean; -begin - if (AStream is TCustomMemoryStream) then - begin - P := PByte(TCustomMemoryStream(AStream).Memory) + AOffset; - LSize := ACount; - Exit(True); - end; - Result := False; -end; - -function TCrossHttpResponse._CreateHeader(const ABodySize: Int64; - AChunked: Boolean): TBytes; -var - LHeaderStr, LStatusText, LHttpVersion: string; - LCookie: TResponseCookie; -begin - if (GetContentType = '') then - SetContentType(TMediaType.APPLICATION_OCTET_STREAM); - if (FHeader[HEADER_CONNECTION] = '') then - begin - if (FStatusCode >= 400) or (not FRequest.KeepAlive) then - FHeader[HEADER_CONNECTION] := 'close' - else - FHeader[HEADER_CONNECTION] := 'keep-alive'; - end; - - if (FStatusCode = 204) or (FStatusCode = 304) then - begin - FHeader.Remove(HEADER_CONTENT_LENGTH); - FHeader.Remove(HEADER_TRANSFER_ENCODING); - end - else if AChunked then - begin - FHeader[HEADER_TRANSFER_ENCODING] := 'chunked'; - FHeader.Remove(HEADER_CONTENT_LENGTH); - end else - begin - FHeader[HEADER_CONTENT_LENGTH] := ABodySize.ToString; - FHeader.Remove(HEADER_TRANSFER_ENCODING); - end; - - if (FHeader[HEADER_CROSS_HTTP_SERVER] = '') then - FHeader[HEADER_CROSS_HTTP_SERVER] := CROSS_HTTP_SERVER_NAME; - - if (FStatusText <> '') then - begin - if TCrossHttpUtils.IsValidHeaderValue(FStatusText) then - LStatusText := FStatusText - else - begin - _Log('_CreateHeader: FStatusText contains invalid chars, falling back to default'); - LStatusText := TCrossHttpUtils.GetHttpStatusText(FStatusCode); - end; - end else - LStatusText := TCrossHttpUtils.GetHttpStatusText(FStatusCode); - - // Parser 在 psHeader 阶段早失败时, ParseHeader 尚未运行, FRequest.Version 为空. - // 必须回退到 'HTTP/1.1', 否则状态行成 ' 400 Bad Request' (缺版本前缀, 客户端无法识别). - LHttpVersion := FRequest.Version; - if (LHttpVersion = '') then - LHttpVersion := 'HTTP/1.1'; - LHeaderStr := LHttpVersion + ' ' + FStatusCode.ToString + ' ' + - LStatusText + #13#10; - - for LCookie in FCookies do - begin - try - LHeaderStr := LHeaderStr + HEADER_SETCOOKIE + ': ' + LCookie.Encode + #13#10; - except - on E: Exception do - begin - _Log('TCrossHttpResponse._CreateHeader: skip invalid cookie: %s', [E.Message]); - Continue; - end; - end; - end; - - LHeaderStr := LHeaderStr + FHeader.Encode; - - Result := TEncoding.ASCII.GetBytes(LHeaderStr); -end; - -procedure TCrossHttpResponse._Send(const ASource: TCrossHttpChunkDataFunc; - const ACallback: TCrossConnectionCallback); -begin - // 用 AtomicCmpExchange 抢首次发送权限: 如果已有 Send 调用, 直接拒绝. - // 防止两个 Send 之间的 Source/Callback 覆盖导致第一个 callback 永远不触发. - if AtomicCmpExchange(FSendStatus, 1, 0) <> 0 then - begin - if Assigned(ACallback) then - ACallback(FConnection, False); - Exit; - end; - - if (FConnectionObj = nil) or (FQueueItem = nil) then - begin - if Assigned(ACallback) then - ACallback(FConnection, False); - Exit; - end; - - FConnectionObj._QueueResponseReady(FQueueItem, ASource, ACallback); -end; - -procedure TCrossHttpResponse._Send(const AHeaderSource, - ABodySource: TCrossHttpChunkDataFunc; - const ACallback: TCrossConnectionCallback); -var - LHeaderDone: Boolean; -begin - // HEAD 请求不应包含响应体 (RFC 7231 §4.3.2) - if (FRequest.Method = 'HEAD') then - begin - _Send(AHeaderSource, ACallback); - Exit; - end; - - LHeaderDone := False; - - _Send( - function(const AData: PPointer; const ACount: PNativeInt): Boolean - begin - if not LHeaderDone then - begin - LHeaderDone := True; - Result := Assigned(AHeaderSource) and AHeaderSource(AData, ACount); - end else - begin - Result := Assigned(ABodySource) and ABodySource(AData, ACount); - end; - end, - ACallback); -end; - -procedure TCrossHttpResponse.SendNoCompress(const ABody: Pointer; - const ACount: NativeInt; const ACallback: TCrossConnectionCallback); -{ -HTTP头\r\n\r\n -内容 -} -var - P: PByte; - LSize: NativeInt; - LHeaderBytes: TBytes; -begin - P := ABody; - LSize := ACount; - - _Send( - // HEADER - function(const AData: PPointer; const ACount: PNativeInt): Boolean - begin - LHeaderBytes := _CreateHeader(LSize, False); - - AData^ := @LHeaderBytes[0]; - ACount^ := Length(LHeaderBytes); - - Result := (ACount^ > 0); - end, - // BODY - function(const AData: PPointer; const ACount: PNativeInt): Boolean - begin - AData^ := P; - ACount^ := Min(LSize, SND_BUF_SIZE); - Result := (ACount^ > 0); - - if (LSize > SND_BUF_SIZE) then - begin - Inc(P, SND_BUF_SIZE); - Dec(LSize, SND_BUF_SIZE); - end else - begin - LSize := 0; - P := nil; - end; - end, - // CALLBACK - procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) - begin - LHeaderBytes := nil; - - if Assigned(ACallback) then - ACallback(AConnection, ASuccess); - end); -end; - -procedure TCrossHttpResponse.SendNoCompress(const ABody; const ACount: NativeInt; - const ACallback: TCrossConnectionCallback); -begin - SendNoCompress(@ABody, ACount, ACallback); -end; - -procedure TCrossHttpResponse.SendNoCompress(const ABody: TBytes; - const AOffset, ACount: NativeInt; const ACallback: TCrossConnectionCallback); -var - LBody: TBytes; - LOffset, LCount: NativeInt; -begin - // 增加其引用计数 - LBody := ABody; - - LOffset := AOffset; - LCount := ACount; - TCrossHttpUtils.AdjustOffsetCount(Length(ABody), LOffset, LCount); - - SendNoCompress(Pointer(PByte(LBody) + LOffset), LCount, - // CALLBACK - procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) - begin - // 减少引用计数 - LBody := nil; - - if Assigned(ACallback) then - ACallback(AConnection, ASuccess); - end); -end; - -procedure TCrossHttpResponse.SendNoCompress(const ABody: TBytes; - const ACallback: TCrossConnectionCallback); -begin - SendNoCompress(ABody, 0, Length(ABody), ACallback); -end; - -procedure TCrossHttpResponse.SendNoCompress(const ABody: TStream; - const AOffset, ACount: Int64; const ACallback: TCrossConnectionCallback); -var - LOffset, LCount: Int64; - LBody: TStream; - LHeaderBytes, LBuffer: TBytes; - LP: PByte; - LSize: Int64; -begin - if (ABody = nil) then - begin - SendNoCompress(nil, 0, ACallback); - Exit; - end; - - LOffset := AOffset; - LCount := ACount; - TCrossHttpUtils.AdjustOffsetCount(ABody.Size, LOffset, LCount); - - if _GetMemoryStreamPointer(ABody, LOffset, LCount, LP, LSize) then - begin - SendNoCompress(LP^, LSize, ACallback); - Exit; - end; - - LBody := ABody; - LBody.Position := LOffset; - - SetLength(LBuffer, SND_BUF_SIZE); - - _Send( - // HEADER - function(const AData: PPointer; const ACount: PNativeInt): Boolean - begin - LHeaderBytes := _CreateHeader(LCount, False); - - AData^ := @LHeaderBytes[0]; - ACount^ := Length(LHeaderBytes); - - Result := (ACount^ > 0); - end, - // BODY - function(const AData: PPointer; const ACount: PNativeInt): Boolean - begin - if (LCount <= 0) then Exit(False); - - AData^ := @LBuffer[0]; - ACount^ := LBody.Read(LBuffer[0], Min(LCount, SND_BUF_SIZE)); - - Result := (ACount^ > 0); - - if Result then - Dec(LCount, ACount^); - end, - // CALLBACK - procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) - begin - LHeaderBytes := nil; - LBuffer := nil; - - if Assigned(ACallback) then - ACallback(AConnection, ASuccess); - end); -end; - -procedure TCrossHttpResponse.SendNoCompress(const ABody: TStream; - const ACallback: TCrossConnectionCallback); -begin - SendNoCompress(ABody, 0, 0, ACallback); -end; - -procedure TCrossHttpResponse.SendNoCompress(const ABody: string; - const ACallback: TCrossConnectionCallback); -var - LBody: TBytes; -begin - LBody := TEncoding.UTF8.GetBytes(ABody); - if (GetContentType = '') then - SetContentType(TMediaType.TEXT_HTML_UTF8); - - SendNoCompress(LBody, ACallback); -end; - -procedure TCrossHttpResponse.SendStatus(const AStatusCode: Integer; - const ADescription: string; const ACallback: TCrossConnectionCallback); -begin - SetStatusCode(AStatusCode); - Send(ADescription, ACallback); -end; - -procedure TCrossHttpResponse.SendStatus(const AStatusCode: Integer; - const ACallback: TCrossConnectionCallback); -begin - SendStatus(AStatusCode, TCrossHttpUtils.GetHttpStatusText(AStatusCode), ACallback); -end; - -procedure TCrossHttpResponse.SendZCompress( - const AChunkSource: TCrossHttpChunkDataFunc; - const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback); -{ - 本方法实现了一边压缩一边发送数据, 所以可以支持无限大的分块数据的压缩发送, - 而不用占用太多的内存和CPU - - zlib参考手册: http://www.zlib.net/zlib_how.html -} -var - LZStream: TZStreamRec; - LZFlush: Integer; - LZResult: Integer; - LOutSize: Integer; - LBuffer: TBytes; - LZError: Boolean; -begin - if (ACompressType = ctNone) then - begin - SendNoCompress(AChunkSource, ACallback); - Exit; - end; - - // 返回压缩方式 - FHeader[HEADER_CONTENT_ENCODING] := ZLIB_CONTENT_ENCODING[ACompressType]; - - // 明确告知缓存服务器按照 Accept-Encoding 字段的内容, 分别缓存不同的版本 - FHeader[HEADER_VARY] := HEADER_ACCEPT_ENCODING; - - SetLength(LBuffer, SND_BUF_SIZE); - - FillChar(LZStream, SizeOf(TZStreamRec), 0); - LZResult := Z_OK; - LZFlush := Z_NO_FLUSH; - - if (deflateInit2(LZStream, Z_DEFAULT_COMPRESSION, - Z_DEFLATED, ZLIB_WINDOW_BITS[ACompressType], 8, Z_DEFAULT_STRATEGY) <> Z_OK) then - begin - SetStatusCode(500); - if (FQueueItem <> nil) then - FQueueItem.StatusCode := 500; - // 走正常队列流程: _Send → _QueueResponseReady → _SendQueueItem - // → body 为空立即返回 False → _FinishQueueItem (配合 StatusCode>=500 触发 Disconnect) → ACallback 在锁外异步通知 - SendNoCompress(nil, 0, ACallback); - Exit; - end; - - LZError := False; - - SendNoCompress( - // CHUNK - function(const AData: PPointer; const ACount: PNativeInt): Boolean - var - LChunkData: Pointer; - LChunkSize: NativeInt; - begin - repeat - // 当 deflate(LZStream, Z_FINISH) 被调用后 - // 返回 Z_STREAM_END 表示所有数据处理完毕 - if (LZResult = Z_STREAM_END) then - begin - AData^ := nil; - ACount^ := 0; - Exit(False); - end; - - // 输入缓冲区已经处理完毕 - // 需要填入新数据 - if (LZStream.avail_in = 0) then - begin - LChunkData := nil; - LChunkSize := 0; - if not Assigned(AChunkSource) - or not AChunkSource(@LChunkData, @LChunkSize) - or (LChunkData = nil) - or (LChunkSize <= 0) then - LZFlush := Z_FINISH // 如果没有后续数据了, 准备结束压缩 - else - LZFlush := Z_NO_FLUSH; - - // 压缩数据输入缓冲区 - LZStream.avail_in := LChunkSize; - LZStream.next_in := LChunkData; - end; - - // 压缩数据输出缓冲区 - LZStream.avail_out := SND_BUF_SIZE; - LZStream.next_out := @LBuffer[0]; - - // 进行压缩处理 - // 输入缓冲区数据可以大于输出缓冲区 - // 这种情况可以多次调用 deflate 分批压缩, - // 直到 avail_in=0 表示当前输入缓冲区数据已压缩完毕 - LZResult := deflate(LZStream, LZFlush); - - // 压缩出错之后直接结束 - // 这里也可能会返回 Z_STREAM_END(1) - // 返回 Z_STREAM_END(1) 这一次还是有数据的 - // 所以要到下次 CHUNK 函数被调用的时候再结束 - if (LZResult < 0) then - begin - LZError := True; // 标记压缩错误,回调中将向调用方传递 False - // 标记 500 以触发 _FinishQueueItem 中 LNeedDisconnect 断开连接 - if (FQueueItem <> nil) then - FQueueItem.StatusCode := 500; - AData^ := nil; - ACount^ := 0; - Exit(False); - end; - - // 已压缩完成的数据大小 - LOutSize := SND_BUF_SIZE - LZStream.avail_out; - until (LOutSize > 0); - - // 已压缩的数据 - AData^ := @LBuffer[0]; - ACount^ := LOutSize; - - Result := (ACount^ > 0); - end, - // CALLBACK - procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) - begin - LBuffer := nil; - deflateEnd(LZStream); - - if Assigned(ACallback) then - ACallback(AConnection, ASuccess and not LZError); - end); -end; - -procedure TCrossHttpResponse.SendZCompress(const ABody: Pointer; - const ACount: NativeInt; const ACompressType: TCompressType; - const ACallback: TCrossConnectionCallback); -var - P: PByte; - LSize: NativeInt; -begin - P := ABody; - LSize := ACount; - - SendZCompress( - // CHUNK - function(const AData: PPointer; const ACount: PNativeInt): Boolean - begin - AData^ := P; - ACount^ := Min(LSize, SND_BUF_SIZE); - Result := (ACount^ > 0); - - if (LSize > SND_BUF_SIZE) then - begin - Inc(P, SND_BUF_SIZE); - Dec(LSize, SND_BUF_SIZE); - end else - begin - LSize := 0; - P := nil; - end; - end, - ACompressType, - ACallback); -end; - -procedure TCrossHttpResponse.SendZCompress(const ABody; const ACount: NativeInt; - const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback); -begin - SendZCompress(@ABody, ACount, ACompressType, ACallback); -end; - -procedure TCrossHttpResponse.SendZCompress(const ABody: TBytes; - const AOffset, ACount: NativeInt; const ACompressType: TCompressType; - const ACallback: TCrossConnectionCallback); -var - LBody: TBytes; - LOffset, LCount: NativeInt; -begin - // 增加其引用计数 - LBody := ABody; - - LOffset := AOffset; - LCount := ACount; - TCrossHttpUtils.AdjustOffsetCount(Length(ABody), LOffset, LCount); - - SendZCompress(Pointer(PByte(LBody) + LOffset), LCount, ACompressType, - // CALLBACK - procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) - begin - // 减少引用计数 - LBody := nil; - - if Assigned(ACallback) then - ACallback(AConnection, ASuccess); - end); -end; - -procedure TCrossHttpResponse.SendZCompress(const ABody: TBytes; - const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback); -begin - SendZCompress(ABody, 0, Length(ABody), ACompressType, ACallback); -end; - -procedure TCrossHttpResponse.SendZCompress(const ABody: TStream; - const AOffset, ACount: Int64; const ACompressType: TCompressType; - const ACallback: TCrossConnectionCallback); -var - LOffset, LCount: Int64; - LBody: TStream; - LBuffer: TBytes; - LP: PByte; - LSize: Int64; -begin - if (ABody = nil) then - begin - SendNoCompress(nil, 0, ACallback); - Exit; - end; - - LOffset := AOffset; - LCount := ACount; - TCrossHttpUtils.AdjustOffsetCount(ABody.Size, LOffset, LCount); - - if _GetMemoryStreamPointer(ABody, LOffset, LCount, LP, LSize) then - begin - SendZCompress(LP^, LSize, ACompressType, ACallback); - Exit; - end; - - LBody := ABody; - LBody.Position := LOffset; - - SetLength(LBuffer, SND_BUF_SIZE); - - SendZCompress( - // CHUNK - function(const AData: PPointer; const ACount: PNativeInt): Boolean - begin - if (LCount <= 0) then Exit(False); - - ACount^ := LBody.Read(LBuffer[0], Min(LCount, SND_BUF_SIZE)); - AData^ := @LBuffer[0]; - - Result := (ACount^ > 0); - - if Result then - Dec(LCount, ACount^); - end, - ACompressType, - // CALLBACK - procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) - begin - LBuffer := nil; - - if Assigned(ACallback) then - ACallback(AConnection, ASuccess); - end); -end; - -procedure TCrossHttpResponse.SendZCompress(const ABody: TStream; - const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback); -begin - SendZCompress(ABody, 0, 0, ACompressType, ACallback); -end; - -procedure TCrossHttpResponse.SendZCompress(const ABody: string; - const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback); -var - LBody: TBytes; -begin - LBody := TEncoding.UTF8.GetBytes(ABody); - if (GetContentType = '') then - SetContentType(TMediaType.TEXT_HTML_UTF8); - - SendZCompress(LBody, ACompressType, ACallback); -end; - -end. +{******************************************************************************} +{ } +{ Delphi cross platform socket library } +{ } +{ Copyright (c) 2017 WiNDDRiVER(soulawing@gmail.com) } +{ } +{ Homepage: https://github.com/winddriver/Delphi-Cross-Socket } +{ } +{******************************************************************************} +unit Net.CrossHttpServer; + +{$I zLib.inc} + +{ + Linux下需要安装zlib1g-dev开发包 + sudo apt-get install zlib1g-dev +} + +interface + +uses + Classes, + SysUtils, + Math, + Generics.Collections, + //ZLib, + {$IFDEF DELPHI} + ZLib, + {$ELSE} + DTF.StaticZLib, + {$ENDIF} + + Net.SocketAPI, + Net.CrossSocket.Base, + Net.CrossSocket, + Net.CrossServer, + Net.CrossHttpParams, + Net.CrossHttpUtils, + Net.CrossHttpParser, + + Utils.StrUtils, + Utils.IOUtils, + Utils.Hash, + Utils.RegEx, + Utils.SyncObjs, + Utils.ArrayUtils, + Utils.DateTime; + +const + CROSS_HTTP_SERVER_NAME = 'CrossHttpServer/3.0'; + MIN_COMPRESS_SIZE = 512; + WILDCARD_CHAR = '*'; + REGEX_CHARS: array of Char = [':', '*', '?', '(', ')', '[', '{', '|', '+', '.']; + +type + ECrossHttpException = class(Exception) + private + FStatusCode: Integer; + public + constructor Create(const AMessage: string; AStatusCode: Integer = 400); reintroduce; virtual; + constructor CreateFmt(const AMessage: string; const AArgs: array of const; AStatusCode: Integer = 400); reintroduce; virtual; + property StatusCode: Integer read FStatusCode write FStatusCode; + end; + + ICrossHttpServer = interface; + ICrossHttpRequest = interface; + ICrossHttpResponse = interface; + IHttpResponseQueueItem = interface; + + TCrossHttpServer = class; + TCrossHttpRequest = class; + TCrossHttpResponse = class; + THttpResponseQueueItem = class; + + /// + /// HTTP连接接口 + /// + ICrossHttpConnection = interface(ICrossServerConnection) + ['{72E9AC44-958C-4C6F-8769-02EA5EC3E9A8}'] + function GetRequest: ICrossHttpRequest; + function GetResponse: ICrossHttpResponse; + function GetServer: ICrossHttpServer; + function GetPending: Integer; + + /// + /// 请求对象 + /// + property Request: ICrossHttpRequest read GetRequest; + + /// + /// 响应对象 + /// + property Response: ICrossHttpResponse read GetResponse; + + /// + /// Server对象 + /// + property Server: ICrossHttpServer read GetServer; + + /// + /// 当前连接上"已开始解析但尚未完成响应"的请求数量 + /// (含正在处理中的与已入队等待发送的) + /// + property Pending: Integer read GetPending; + end; + + /// + /// 请求体类型 + /// + TBodyType = (btNone, btUrlEncoded, btMultiPart, btBinary); + + /// + /// HTTP请求接口 + /// + ICrossHttpRequest = interface + ['{B26B7E7B-6B24-4D86-AB58-EBC20722CFDD}'] + function GetConnection: ICrossHttpConnection; + function GetRawRequestText: string; + function GetRawPathAndQuery: string; + function GetMethod: string; + function GetPath: string; + function GetPathAndQuery: string; + function GetVersion: string; + function GetHeader: THttpHeader; + function GetCookies: TRequestCookies; + function GetSession: ISession; + function GetParams: THttpUrlParams; + function GetQuery: THttpUrlParams; + function GetQueryText: string; + function GetBody: TObject; + function GetRawBody: TStream; + function GetBodyType: TBodyType; + function GetKeepAlive: Boolean; + function GetAccept: string; + function GetAcceptEncoding: string; + function GetAcceptLanguage: string; + function GetReferer: string; + function GetUserAgent: string; + function GetIfModifiedSince: TDateTime; + function GetIfNoneMatch: string; + function GetRange: string; + function GetIfRange: string; + function GetAuthorization: string; + function GetXForwardedFor: string; + function GetContentLength: Int64; + function GetHostName: string; + function GetHostPort: Word; + function GetContentType: string; + function GetContentEncoding: string; + function GetRequestBoundary: string; + function GetRequestCmdLine: string; + function GetRequestConnection: string; + function GetTransferEncoding: string; + function GetIsChunked: Boolean; + function GetIsMultiPartFormData: Boolean; + function GetIsUrlEncodedFormData: Boolean; + function GetPostDataSize: Int64; + + /// + /// HTTP连接对象 + /// + property Connection: ICrossHttpConnection read GetConnection; + + /// + /// 原始请求数据 + /// + property RawRequestText: string read GetRawRequestText; + + /// + /// 原始请求路径及参数 + /// + property RawPathAndParams: string read GetRawPathAndQuery; + + /// + /// 请求方法 + /// + /// + /// GET + /// + /// + /// POST + /// + /// + /// PUT + /// + /// + /// DELETE + /// + /// + /// HEAD + /// + /// + /// OPTIONS + /// + /// + /// TRACE + /// + /// + /// CONNECT + /// + /// + /// PATCH + /// + /// + /// COPY + /// + /// + /// LINK + /// + /// + /// UNLINK + /// + /// + /// PURGE + /// + /// + /// LOCK + /// + /// + /// UNLOCK + /// + /// + /// PROPFIND + /// + /// + /// + property Method: string read GetMethod; + + /// + /// + /// 请求路径, 不包含参数部分 + /// + /// + /// 比如: /api/callapi1 + /// + /// + property Path: string read GetPath; + + /// + /// + /// 请求路径及参数 + /// + /// + /// 比如: /api/callapi1?aaa=111&bbb=222 + /// + /// + property PathAndQuery: string read GetPathAndQuery; + + /// + /// 请求版本: + /// + /// + /// HTTP/1.0 + /// + /// + /// HTTP/1.1 + /// + /// + /// + property Version: string read GetVersion; + + /// + /// HTTP请求头 + /// + property Header: THttpHeader read GetHeader; + + /// + /// 客户端传递过来的Cookies + /// + property Cookies: TRequestCookies read GetCookies; + + /// + /// Session对象 + /// + /// + /// + /// 只有在Server开启了Session支持的情况, 该属性才有效, 否则该属性为nil + /// + /// + /// 要开启Server的Session支持, 只需要设置Server.SessionIDCookieName不为空即可 + /// + /// + property Session: ISession read GetSession; + + /// + /// + /// 请求路径中定义的参数 + /// + /// + /// 比如定义了一个Get('/echo/:text', cb) 然后有一个请求为 /echo/hello, 那么 Params + /// 中就会有一个名为 'text', 值为 'hello' 的参数 + /// + /// + property Params: THttpUrlParams read GetParams; + + /// + /// 请求路径后形如?key1=value1&key2=value2的参数 + /// + property Query: THttpUrlParams read GetQuery; + + /// + /// + /// 请求路径中定义的参数 + /// + /// + property QueryText: string read GetQueryText; + + /// + /// 解析后的Body数据, 通过检查BodyType可以知道数据类型: + /// + /// + /// btNone(nil) + /// + /// + /// btUrlEncoded(TFormUrlEncoded) + /// + /// + /// btMultiPart(THttpMultiPartFormData) + /// + /// + /// btBinary(TMemoryStream) + /// + /// + /// + property Body: TObject read GetBody; + + /// + /// 原始Body数据流, 仅对btUrlEncoded和btBinary缓存; multipart/form-data返回nil + /// + /// + /// 调用方只读使用, 不负责释放 + /// + property RawBody: TStream read GetRawBody; + + /// + /// Body的类型, + /// + /// + /// btNone(nil) + /// + /// + /// btUrlEncoded(TFormUrlEncoded) + /// + /// + /// btMultiPart(THttpMultiPartFormData) + /// + /// + /// btBinary(TMemoryStream) + /// + /// + /// + property BodyType: TBodyType read GetBodyType; + + /// + /// KeepAliv标志 + /// + property KeepAlive: Boolean read GetKeepAlive; + + /// + /// 客户端能接收的数据种类 + /// + /// + /// image/webp,image/*,*/*;q=0.8 + /// + property Accept: string read GetAccept; + + /// + /// 客户端能接收的编码 + /// + /// + /// gzip, deflate, sdch + /// + property AcceptEncoding: string read GetAcceptEncoding; + + /// + /// 客户端能接收的语言 + /// + /// + /// zh-CN,zh;q=0.8 + /// + property AcceptLanguage: string read GetAcceptLanguage; + + /// + /// 参考地址, 描述该请求由哪个页面发出 + /// + property Referer: string read GetReferer; + + /// + /// 用户代理 + /// + /// + /// Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like + /// Gecko) Chrome/50.0.2661.102 Safari/537.36 + /// + property UserAgent: string read GetUserAgent; + + /// + /// 请求内容在浏览器端的缓存时间 + /// + property IfModifiedSince: TDateTime read GetIfModifiedSince; + + /// + /// 请求内容在浏览器端的标记 + /// + property IfNoneMatch: string read GetIfNoneMatch; + + /// + /// 请求分块传输 + /// + property Range: string read GetRange; + + /// + /// 请求分块传输时传往服务器的标记, 用于服务器比较数据是否已发生变化 + /// + property IfRange: string read GetIfRange; + + /// + /// 简单认证信息 + /// + property Authorization: string read GetAuthorization; + + /// + /// 通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段 + /// + property XForwardedFor: string read GetXForwardedFor; + + /// + /// 请求数据长度 + /// + property ContentLength: Int64 read GetContentLength; + + /// + /// 请求的主机名(域名、IP) + /// + property HostName: string read GetHostName; + + /// + /// 请求的主机端口 + /// + property HostPort: Word read GetHostPort; + + /// + /// 内容类型 + /// + property ContentType: string read GetContentType; + + /// + /// 请求命令行(也就是HTTP请求的第一行) + /// + property RequestCmdLine: string read GetRequestCmdLine; + + /// + /// 请求分界符 + /// + property RequestBoundary: string read GetRequestBoundary; + + /// + /// 传输编码 + /// + property TransferEncoding: string read GetTransferEncoding; + + /// + /// 内容编码 + /// + property ContentEncoding: string read GetContentEncoding; + + /// + /// 连接方式 + /// + property RequestConnection: string read GetRequestConnection; + + /// + /// 请求数据是否使用块编码 + /// + property IsChunked: Boolean read GetIsChunked; + + /// + /// 请求数据是使用 multipart/form-data 方式提交的 + /// + property IsMultiPartFormData: Boolean read GetIsMultiPartFormData; + + /// + /// 请求数据是使用 application/x-www-form-urlencoded 方式提交的 + /// + property IsUrlEncodedFormData: Boolean read GetIsUrlEncodedFormData; + + /// + /// 请求数据大小 + /// + property PostDataSize: Int64 read GetPostDataSize; + end; + + /// + /// 提供块数据的匿名函数 + /// + TCrossHttpChunkDataFunc = reference to function(const AData: PPointer; const ACount: PNativeInt): Boolean; + + /// + /// HTTP响应队列项接口 + /// 用于按请求解析顺序串行化每个连接上的响应发送, 避免 pipelining 响应交错 + /// + IHttpResponseQueueItem = interface + ['{B03F35B7-6984-41A8-9AA0-6B3D48F18F91}'] + function GetRequest: ICrossHttpRequest; + function GetResponse: ICrossHttpResponse; + function GetSource: TCrossHttpChunkDataFunc; + function GetCallback: TCrossConnectionCallback; + function GetReady: Boolean; + function GetSending: Boolean; + function GetCompleted: Boolean; + function GetKeepAlive: Boolean; + function GetStatusCode: Integer; + + procedure SetRequest(const AValue: ICrossHttpRequest); + procedure SetResponse(const AValue: ICrossHttpResponse); + procedure SetSource(const AValue: TCrossHttpChunkDataFunc); + procedure SetCallback(const AValue: TCrossConnectionCallback); + procedure SetReady(const AValue: Boolean); + procedure SetSending(const AValue: Boolean); + procedure SetCompleted(const AValue: Boolean); + procedure SetKeepAlive(const AValue: Boolean); + procedure SetStatusCode(const AValue: Integer); + + property Request: ICrossHttpRequest read GetRequest write SetRequest; + property Response: ICrossHttpResponse read GetResponse write SetResponse; + property Source: TCrossHttpChunkDataFunc read GetSource write SetSource; + property Callback: TCrossConnectionCallback read GetCallback write SetCallback; + property Ready: Boolean read GetReady write SetReady; + property Sending: Boolean read GetSending write SetSending; + property Completed: Boolean read GetCompleted write SetCompleted; + property KeepAlive: Boolean read GetKeepAlive write SetKeepAlive; + property StatusCode: Integer read GetStatusCode write SetStatusCode; + end; + + /// + /// HTTP响应队列项实现类 + /// + THttpResponseQueueItem = class(TInterfacedObject, IHttpResponseQueueItem) + private + FRequest: ICrossHttpRequest; + FResponse: ICrossHttpResponse; + FSource: TCrossHttpChunkDataFunc; + FCallback: TCrossConnectionCallback; + FReady: Boolean; + FSending: Boolean; + FCompleted: Boolean; + FKeepAlive: Boolean; + FStatusCode: Integer; + protected + function GetRequest: ICrossHttpRequest; + function GetResponse: ICrossHttpResponse; + function GetSource: TCrossHttpChunkDataFunc; + function GetCallback: TCrossConnectionCallback; + function GetReady: Boolean; + function GetSending: Boolean; + function GetCompleted: Boolean; + function GetKeepAlive: Boolean; + function GetStatusCode: Integer; + + procedure SetRequest(const AValue: ICrossHttpRequest); + procedure SetResponse(const AValue: ICrossHttpResponse); + procedure SetSource(const AValue: TCrossHttpChunkDataFunc); + procedure SetCallback(const AValue: TCrossConnectionCallback); + procedure SetReady(const AValue: Boolean); + procedure SetSending(const AValue: Boolean); + procedure SetCompleted(const AValue: Boolean); + procedure SetKeepAlive(const AValue: Boolean); + procedure SetStatusCode(const AValue: Integer); + end; + + /// + /// HTTP应答接口 + /// + ICrossHttpResponse = interface + ['{5E15C20F-E221-4B10-90FC-222173A6F3E8}'] + function GetConnection: ICrossHttpConnection; + function GetRequest: ICrossHttpRequest; + function GetStatusCode: Integer; + function GetStatusText: string; + function GetContentType: string; + function GetLocation: string; + function GetHeader: THttpHeader; + function GetCookies: TResponseCookies; + function GetSent: Boolean; + + procedure SetContentType(const Value: string); + procedure SetLocation(const Value: string); + procedure SetStatusCode(Value: Integer); + procedure SetStatusText(const Value: string); + + /// + /// 重置数据 + /// + procedure Reset; + + /// + /// 压缩发送块数据 + /// + /// + /// 产生块数据的匿名函数 + /// // AData: 数据指针 + /// // ACount: 数据大小 + /// // Result: 如果返回True, 则发送数据; 如果返回False, 则忽略AData和ACount并结束发送 + /// function(const AData: PPointer; const ACount: PNativeInt): Boolean + /// begin + /// end + /// + /// + /// 压缩方式 + /// + /// + /// 回调函数 + /// + /// + /// 本方法实现了一边压缩一边发送数据, 所以可以支持无限大的分块数据的压缩发送, 而不用占用太多的内存和CPU
+ /// zlib参考手册:
+ ///
+ procedure SendZCompress(const AChunkSource: TCrossHttpChunkDataFunc; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 压缩发送无类型数据 + /// + /// + /// 无类型数据 + /// + /// + /// 数据大小 + /// + /// + /// 压缩方式 + /// + /// + /// 回调函数 + /// + procedure SendZCompress(const ABody; const ACount: NativeInt; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 压缩发送字节数据 + /// + /// + /// 字节数据 + /// + /// + /// 偏移量 + /// + /// + /// 数据大小 + /// + /// + /// 压缩方式 + /// + /// + /// 回调函数 + /// + procedure SendZCompress(const ABody: TBytes; const AOffset, ACount: NativeInt; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 压缩发送字节数据 + /// + /// + /// 字节数据 + /// + /// + /// 压缩方式 + /// + /// + /// 回调函数 + /// + procedure SendZCompress(const ABody: TBytes; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 压缩发送流数据 + /// + /// + /// 流数据 + /// + /// + /// 偏移量 + /// + /// + /// 数据大小 + /// + /// + /// 压缩方式 + /// + /// + /// 回调函数 + /// + /// + /// 必须保证发送过程中流对象的有效性, 要释放流对象可以放到回调函数中进行 + /// + procedure SendZCompress(const ABody: TStream; const AOffset, ACount: Int64; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 压缩发送流数据 + /// + /// + /// 流数据 + /// + /// + /// 压缩方式 + /// + /// + /// 回调函数 + /// + /// + /// 必须保证发送过程中流对象的有效性, 要释放流对象可以放到回调函数中进行 + /// + procedure SendZCompress(const ABody: TStream; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 压缩发送字符串数据 + /// + /// + /// 字符串数据 + /// + /// + /// 压缩方式 + /// + /// + /// 回调函数 + /// + procedure SendZCompress(const ABody: string; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 不压缩发送块数据 + /// + /// + /// 产生块数据的匿名函数 + /// // AData: 数据指针 + /// // ACount: 数据大小 + /// // Result: 如果返回True, 则发送数据; 如果返回False, 则忽略AData和ACount并结束发送 + /// function(const AData: PPointer; const ACount: PNativeInt): Boolean + /// begin + /// end + /// + /// + /// 回调函数 + /// + /// + /// 使用该方法可以一边生成数据一边发送, 无需等待数据全部准备完成 + /// + procedure SendNoCompress(const AChunkSource: TCrossHttpChunkDataFunc; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 不压缩发送无类型数据 + /// + /// + /// 无类型数据 + /// + /// + /// 数据大小 + /// + /// + /// 回调函数 + /// + procedure SendNoCompress(const ABody; const ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 不压缩发送字节数据 + /// + /// + /// 字节数据 + /// + /// + /// 偏移量 + /// + /// + /// 数据大小 + /// + /// + /// 回调函数 + /// + procedure SendNoCompress(const ABody: TBytes; const AOffset, ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 不压缩发送字节数据 + /// + /// + /// 字节数据 + /// + /// + /// 回调函数 + /// + procedure SendNoCompress(const ABody: TBytes; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 不压缩发送流数据 + /// + /// + /// 流数据 + /// + /// + /// 偏移量 + /// + /// + /// 数据大小 + /// + /// + /// 回调函数 + /// + /// + /// 必须保证发送过程中流对象的有效性, 要释放流对象可以放到回调函数中进行 + /// + procedure SendNoCompress(const ABody: TStream; const AOffset, ACount: Int64; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 不压缩发送流数据 + /// + /// + /// 流数据 + /// + /// + /// 回调函数 + /// + /// + /// 必须保证发送过程中流对象的有效性, 要释放流对象可以放到回调函数中进行 + /// + procedure SendNoCompress(const ABody: TStream; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 不压缩发送字符串数据 + /// + /// + /// 字符串数据 + /// + /// + /// 回调函数 + /// + procedure SendNoCompress(const ABody: string; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 发送无类型数据 + /// + /// + /// 无类型数据 + /// + /// + /// 数据大小 + /// + /// + /// 回调函数 + /// + procedure Send(const ABody; const ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 发送字节数据 + /// + /// + /// 字节数据 + /// + /// + /// 偏移量 + /// + /// + /// 数据大小 + /// + /// + /// 回调函数 + /// + procedure Send(const ABody: TBytes; const AOffset, ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 发送字节数据 + /// + /// + /// 字节数据 + /// + /// + /// 回调函数 + /// + procedure Send(const ABody: TBytes; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 发送流数据 + /// + /// + /// 流数据 + /// + /// + /// 偏移量 + /// + /// + /// 数据大小 + /// + /// + /// 回调函数 + /// + /// + /// 必须保证发送过程中流对象的有效性, 要释放流对象可以放到回调函数中进行 + /// + procedure Send(const ABody: TStream; const AOffset, ACount: Int64; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 发送流数据 + /// + /// + /// 流数据 + /// + /// + /// 回调函数 + /// + /// + /// 必须保证发送过程中流对象的有效性, 要释放流对象可以放到回调函数中进行 + /// + procedure Send(const ABody: TStream; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 发送字符串数据 + /// + /// + /// 字符串数据 + /// + /// + /// 回调函数 + /// + procedure Send(const ABody: string; const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 发送Json字符串数据 + /// + /// + /// Json字符串数据 + /// + /// + /// 回调函数 + /// + procedure Json(const AJson: string; const ACallback: TCrossConnectionCallback = nil); + + /// + /// 发送文件内容 + /// + /// + /// 文件名 + /// + /// + /// 回调函数 + /// + procedure SendFile(const AFileName: string; const ACallback: TCrossConnectionCallback = nil); + + /// + /// 将文件以下载形式发送 + /// + /// + /// 文件名 + /// + /// + /// 回调函数 + /// + procedure Download(const AFileName: string; const ACallback: TCrossConnectionCallback = nil); + + /// + /// 发送状态码 + /// + /// + /// 状态码 + /// + /// + /// 描述信息(body) + /// + /// + /// 回调函数 + /// + /// + /// 描述信息即是body数据, 如果设置为空, 则body也为空 + /// + procedure SendStatus(const AStatusCode: Integer; const ADescription: string; + const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 发送状态码 + /// + /// + /// 状态码 + /// + /// + /// 回调函数 + /// + /// + /// 该方法根据状态码生成默认的body数据 + /// + procedure SendStatus(const AStatusCode: Integer; + const ACallback: TCrossConnectionCallback = nil); overload; + + /// + /// 发送重定向Url命令 + /// + /// + /// 新的Url + /// + /// + /// 回调函数 + /// + procedure Redirect(const AUrl: string; const ACallback: TCrossConnectionCallback = nil); + + /// + /// 设置Content-Disposition, 令客户端将收到的数据作为文件下载处理 + /// + /// + /// 文件名 + /// + procedure Attachment(const AFileName: string); + + /// + /// HTTP连接对象 + /// + property Connection: ICrossHttpConnection read GetConnection; + + /// + /// 请求对象 + /// + property Request: ICrossHttpRequest read GetRequest; + + /// + /// 状态码 + /// + property StatusCode: Integer read GetStatusCode write SetStatusCode; + + /// + /// 状态文本 + /// + property StatusText: string read GetStatusText write SetStatusText; + + /// + /// 内容类型 + /// + property ContentType: string read GetContentType write SetContentType; + + /// + /// 重定向Url + /// + property Location: string read GetLocation write SetLocation; + + /// + /// HTTP响应头 + /// + property Header: THttpHeader read GetHeader; + + /// + /// 设置Cookies + /// + property Cookies: TResponseCookies read GetCookies; + + /// + /// 是否已经发送数据 + /// + property Sent: Boolean read GetSent; + end; + + TCrossHttpRouterProc = reference to procedure(const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse; var AHandled: Boolean); + TCrossHttpRouterMethod = procedure(const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse; var AHandled: Boolean) of object; + + TCrossHttpConnEvent = procedure(const Sender: TObject; const AConnection: ICrossHttpConnection) of object; + TCrossHttpRequestExceptionEvent = procedure(const Sender: TObject; const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse; const AException: Exception) of object; + + TCrossHttpRequestEvent = procedure(const Sender: TObject; + const AConnection: ICrossHttpConnection; + const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse; + var AHandled: Boolean) of object; + + // Begin/End 事件签名带上 ARequest/AResponse, 让事件 handler 能拿到本次事件 + // 对应的请求/响应对象, 不再依赖连接级 FRequest/FResponse 兼容视图 + // (该兼容视图在 pipelining 下语义模糊, 已不再由 _FinishQueueItem 维护) + TCrossHttpRequestBeginEvent = procedure(const Sender: TObject; + const AConnection: ICrossHttpConnection; + const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse) of object; + TCrossHttpRequestEndEvent = procedure(const Sender: TObject; + const AConnection: ICrossHttpConnection; + const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse; + const ASuccess: Boolean) of object; + + /// + /// + /// 跨平台HTTP服务器接口 + /// + /// + /// 路由定义方式: + /// + /// + /// Route(AMehod, APath, ARouter) + /// + /// + /// Get(APath, ARouter) + /// + /// + /// Put(APath, ARouter) + /// + /// + /// Post(APath, ARouter) + /// + /// + /// Delete(APath, ARouter) + /// + /// + /// All(APath, ARouter) + /// + /// + /// 其中AMehod和APath都支持正则表达式, ARouter可以是一个对象方法也可以是匿名函数 + /// + /// + /// + /// + /// 这里偷了下懒, 没将HTTP和HTTPS分开实现两个不同的接口, 需要通过编译开关选择使用HTTP还是HTTP + /// + /// + /// 通过接口引用计数保证连接的有效性,所以可以在路由函数中调用线程池来处理业务逻辑,而不用担心处理过程中连接对象被释放 + /// + /// + /// 每个请求的响应流程大致为: + /// + /// + /// + /// 执行匹配的中间件; + /// + /// + /// 执行匹配的路由 + /// + /// + /// + /// + /// // 在线程池中处理业务逻辑 + /// FCrossHttpServer.Route('GET', '/runtask/:name', + /// procedure(ARequest: ICrossHttpRequest; AResponse: ICrossHttpResponse) + /// begin + /// System.Threading.TTask.Run( + /// procedure + /// begin + /// CallTask(ARequest.Params['name']); + /// end); + /// end); + /// // 正则表达式 + /// FCrossHttpServer.Route('GET', '/query/:count(\d+)', + /// procedure(ARequest: ICrossHttpRequest; AResponse: ICrossHttpResponse) + /// begin + /// System.Threading.TTask.Run( + /// procedure + /// begin + /// CallQuery(ARequest.Params['count'].ToInteger); + /// end); + /// end); + /// + ICrossHttpServer = interface(ICrossServer) + ['{224D16AA-317C-435E-9C2E-92868E578DB3}'] + function GetStoragePath: string; + function GetAutoDeleteFiles: Boolean; + function GetMaxHeaderSize: Int64; + function GetMaxPostDataSize: Int64; + function GetMaxCompressRatio: Integer; + function GetCompressible: Boolean; + function GetMinCompressSize: Int64; + function GetSessions: ISessions; + function GetSessionIDCookieName: string; + function GetOnRequestBegin: TCrossHttpRequestBeginEvent; + function GetOnRequest: TCrossHttpRequestEvent; + function GetOnRequestEnd: TCrossHttpRequestEndEvent; + function GetOnRequestException: TCrossHttpRequestExceptionEvent; + + procedure SetStoragePath(const Value: string); + procedure SetAutoDeleteFiles(const Value: Boolean); + procedure SetMaxHeaderSize(const Value: Int64); + procedure SetMaxPostDataSize(const Value: Int64); + procedure SetMaxCompressRatio(const Value: Integer); + procedure SetCompressible(const Value: Boolean); + procedure SetMinCompressSize(const Value: Int64); + procedure SetSessions(const Value: ISessions); + procedure SetSessionIDCookieName(const Value: string); + procedure SetOnRequestBegin(const Value: TCrossHttpRequestBeginEvent); + procedure SetOnRequest(const Value: TCrossHttpRequestEvent); + procedure SetOnRequestEnd(const Value: TCrossHttpRequestEndEvent); + procedure SetOnRequestException(const Value: TCrossHttpRequestExceptionEvent); + + /// + /// 注册中间件 + /// + /// + /// 请求方式 + /// + /// + /// 请求路径 + /// + /// + /// 中间件处理匿名函数, 执行完处理函数之后, 如果AHandled=False则会继续执行后续匹配的中间件及路由, + /// 否则后续匹配的中间件及路由不会被执行 + /// + /// + /// + /// + /// 中间件严格按照注册时的顺序被调用 + /// + /// + /// 中间件先于路由执行 + /// + /// + /// + function Use(const AMethod, APath: string; + const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + + /// + /// 注册中间件 + /// + /// + /// 请求方式 + /// + /// + /// 请求路径 + /// + /// + /// 中间件处理匿名方法, 执行完处理方法之后, 如果AHandled=False则会继续执行后续匹配的中间件及路由, + /// 否则后续匹配的中间件及路由不会被执行 + /// + /// + /// + /// + /// 中间件严格按照注册时的顺序被调用 + /// + /// + /// 中间件先于路由执行 + /// + /// + /// + function Use(const AMethod, APath: string; + const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + + /// + /// 注册中间件 + /// + /// + /// 请求路径 + /// + /// + /// 中间件处理匿名函数, 执行完处理函数之后, 如果AHandled=False则会继续执行后续匹配的中间件及路由, + /// 否则后续匹配的中间件及路由不会被执行 + /// + /// + /// + /// + /// 中间件严格按照注册时的顺序被调用 + /// + /// + /// 中间件先于路由执行 + /// + /// + /// + function Use(const APath: string; + const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + + /// + /// 注册中间件 + /// + /// + /// 请求路径 + /// + /// + /// 中间件处理匿名方法, 执行完处理方法之后, 如果AHandled=False则会继续执行后续匹配的中间件及路由, + /// 否则后续匹配的中间件及路由不会被执行 + /// + /// + /// + /// + /// 中间件严格按照注册时的顺序被调用 + /// + /// + /// 中间件先于路由执行 + /// + /// + /// + function Use(const APath: string; + const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + + /// + /// 注册中间件 + /// + /// + /// 中间件处理匿名函数, 执行完处理函数之后还会继续执行后续匹配的中间件及路由 + /// + /// + /// + /// + /// 中间件严格按照注册时的顺序被调用 + /// + /// + /// 中间件先于路由执行 + /// + /// + /// + function Use(const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + + /// + /// 注册中间件 + /// + /// + /// 中间件处理方法, 执行完处理方法之后还会继续执行后续匹配的中间件及路由 + /// + /// + /// + /// + /// 中间件严格按照注册时的顺序被调用 + /// + /// + /// 中间件先于路由执行 + /// + /// + /// + function Use(const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + + /// + /// 注册路由(请求处理函数) + /// + /// + /// 请求方式, GET/POST/PUT/DELETE等, 支持正则表达式, * 表示处理全部请求方式 + /// + /// + /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: + /// /path/:param1/:param2(\d+)|/path/:param + /// + /// + /// 路由处理匿名函数 + /// + /// + /// + /// + /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, + /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. + /// + /// + /// 路由中的正则表达式用法与node.js express相同 + /// + /// + /// + function Route(const AMethod, APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + + /// + /// 注册路由(请求处理函数) + /// + /// + /// 请求方式, GET/POST/PUT/DELETE等, 支持正则表达式, * 表示处理全部请求方式 + /// + /// + /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: + /// /path/:param1/:param2(\d+)|/path/:param + /// + /// + /// 路由处理方法 + /// + /// + /// + /// + /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, + /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. + /// + /// + /// 路由中的正则表达式用法与node.js express相同 + /// + /// + /// + function Route(const AMethod, APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + + /// + /// 注册GET路由(请求处理函数) + /// + /// + /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: + /// /path/:param1/:param2(\d+)|/path/:param + /// + /// + /// 路由处理匿名函数 + /// + /// + /// + /// + /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, + /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. + /// + /// + /// 路由中的正则表达式用法与node.js express相同 + /// + /// + /// + function Get(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + + /// + /// 注册GET路由(请求处理函数) + /// + /// + /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: + /// /path/:param1/:param2(\d+)|/path/:param + /// + /// + /// 路由处理方法 + /// + /// + /// + /// + /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, + /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. + /// + /// + /// 路由中的正则表达式用法与node.js express相同 + /// + /// + /// + function Get(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + + /// + /// 注册PUT路由(请求处理函数) + /// + /// + /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: + /// /path/:param1/:param2(\d+)|/path/:param + /// + /// + /// 路由处理匿名函数 + /// + /// + /// + /// + /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, + /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. + /// + /// + /// 路由中的正则表达式用法与node.js express相同 + /// + /// + /// + function Put(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + + /// + /// 注册PUT路由(请求处理函数) + /// + /// + /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: + /// /path/:param1/:param2(\d+)|/path/:param + /// + /// + /// 路由处理方法 + /// + /// + /// + /// + /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, + /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. + /// + /// + /// 路由中的正则表达式用法与node.js express相同 + /// + /// + /// + function Put(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + + /// + /// 注册POST路由(请求处理函数) + /// + /// + /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: + /// /path/:param1/:param2(\d+)|/path/:param + /// + /// + /// 路由处理匿名函数 + /// + /// + /// + /// + /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, + /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. + /// + /// + /// 路由中的正则表达式用法与node.js express相同 + /// + /// + /// + function Post(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + + /// + /// 注册POST路由(请求处理函数) + /// + /// + /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: + /// /path/:param1/:param2(\d+)|/path/:param + /// + /// + /// 路由处理方法 + /// + /// + /// + /// + /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, + /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. + /// + /// + /// 路由中的正则表达式用法与node.js express相同 + /// + /// + /// + function Post(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + + /// + /// 注册DELETE路由(请求处理函数) + /// + /// + /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: + /// /path/:param1/:param2(\d+)|/path/:param + /// + /// + /// 路由处理匿名函数 + /// + /// + /// + /// + /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, + /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. + /// + /// + /// 路由中的正则表达式用法与node.js express相同 + /// + /// + /// + function Delete(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + + /// + /// 注册DELETE路由(请求处理函数) + /// + /// + /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: + /// /path/:param1/:param2(\d+)|/path/:param + /// + /// + /// 路由处理方法 + /// + /// + /// + /// + /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, + /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. + /// + /// + /// 路由中的正则表达式用法与node.js express相同 + /// + /// + /// + function Delete(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + + /// + /// 注册全部请求方式路由(请求处理函数) + /// + /// + /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: + /// /path/:param1/:param2(\d+)|/path/:param + /// + /// + /// 路由处理匿名函数 + /// + /// + /// + /// + /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, + /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. + /// + /// + /// 路由中的正则表达式用法与node.js express相同 + /// + /// + /// + function All(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + + /// + /// 注册全部请求方式路由(请求处理函数) + /// + /// + /// 请求路径, 支持正则表达式, * 表示处理全部请求路径,
例如: + /// /path/:param1/:param2(\d+)|/path/:param + /// + /// + /// 路由处理方法 + /// + /// + /// + /// + /// 路由严格按照注册时的顺序被调用, 所以如果在注册了AMethod=*, + /// APath=*的路由之后,再注册的其它路由将不会被调用. 所以强烈建议把 "* 路由" 放到最后注册. + /// + /// + /// 路由中的正则表达式用法与node.js express相同 + /// + /// + /// + function All(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + + /// + /// 注册静态文件路由 + /// + /// + /// 请求路径 + /// + /// + /// 静态文件目录, 该目录及子目录下的文件都将作为静态文件返回 + /// + function &Static(const APath, ALocalStaticDir: string): ICrossHttpServer; + + /// + /// 注册文件列表路由 + /// + /// + /// 请求路径 + /// + /// + /// 本地文件目录 + /// + function Dir(const APath, ALocalDir: string): ICrossHttpServer; + + /// + /// 注册含有默认首页文件的静态文件路由 + /// + /// + /// 请求路径 + /// + /// + /// 含有默认首页文件的本地目录 + /// + /// + /// 默认的首页文件,按顺序选择,先找到哪个就使用哪个 + /// + function Index(const APath, ALocalDir: string; const ADefIndexFiles: TArray): ICrossHttpServer; + + /// + /// 删除指定路由 + /// + function RemoveRouter(const AMethod, APath: string): ICrossHttpServer; + + /// + /// 清除所有路由 + /// + function ClearRouters: ICrossHttpServer; + + /// + /// 删除指定中间件 + /// + function RemoveMiddleware(const AMethod, APath: string): ICrossHttpServer; + + /// + /// 清除所有中间件 + /// + function ClearMiddlewares: ICrossHttpServer; + + /// + /// 上传文件保存路径 + /// + /// + /// 用于保存multipart/form-data上传的文件 + /// + property StoragePath: string read GetStoragePath write SetStoragePath; + + /// + /// 对象释放时自动删除上传的文件 + /// + property AutoDeleteFiles: Boolean read GetAutoDeleteFiles write SetAutoDeleteFiles; + + /// + /// 最大允许HEADER的数据尺寸 + /// + /// + /// > 0, 限制HEADER尺寸 + /// + /// + /// <= 0, 不限制 + /// + /// + /// + property MaxHeaderSize: Int64 read GetMaxHeaderSize write SetMaxHeaderSize; + + /// + /// 最大允许POST的数据尺寸 + /// + /// + /// > 0, 限制上传数据尺寸 + /// + /// + /// <= 0, 不限制 + /// + /// + /// + property MaxPostDataSize: Int64 read GetMaxPostDataSize write SetMaxPostDataSize; + + /// + /// gzip/deflate 解压时的最大压缩比 (DecodedSize / EncodedSize) + /// + /// + /// > 0, 解压输出与输入比超过该值则按 zip bomb 拒绝 (400) + /// + /// + /// = 0, 不做压缩比检查 (仅靠 MaxPostDataSize 拦截) + /// + /// + /// + /// + /// 合法 gzip 通常 1.5-15:1, 极规整数据 (StringOfChar, 大块重复字节) 可达 100-500:1 + /// 经典 zip bomb 1000:1 起 (42.zip ~100000:1), 默认 1000:1 兜底拦截 bomb + /// + property MaxCompressRatio: Integer read GetMaxCompressRatio write SetMaxCompressRatio; + + /// + /// 是否开启压缩 + /// + /// + /// 开启压缩后, 发往客户端的数据将会进行压缩处理 + /// + property Compressible: Boolean read GetCompressible write SetCompressible; + + /// + /// 最小允许压缩的数据尺寸 + /// + /// + /// + /// + /// 如果设置值大于0, 则只有Body数据尺寸大于等于该值才会进行压缩 + /// + /// + /// 如果设置值小于等于0, 则无视Body数据尺寸, 始终进行压缩 + /// + /// + /// 由于数据是分块压缩发送, 所以数据无论多大都不会占用更多的资源, 也就不需要限制最大压缩尺寸了 + /// + /// + /// 目前支持的压缩方式: gzip, deflate + /// + /// + /// + property MinCompressSize: Int64 read GetMinCompressSize write SetMinCompressSize; + + /// + /// Sessions接口对象 + /// + /// + /// 通过它管理所有Session, 如果不设置则Session功能将不会被启用 + /// + property Sessions: ISessions read GetSessions write SetSessions; + + /// + /// + /// SessionID在Cookie中存储的名称 + /// + /// + /// + /// 如果设置为空, 则Session功能将不会被启用 + /// + property SessionIDCookieName: string read GetSessionIDCookieName write SetSessionIDCookieName; + + property OnRequestBegin: TCrossHttpRequestBeginEvent read GetOnRequestBegin write SetOnRequestBegin; + property OnRequest: TCrossHttpRequestEvent read GetOnRequest write SetOnRequest; + property OnRequestEnd: TCrossHttpRequestEndEvent read GetOnRequestEnd write SetOnRequestEnd; + property OnRequestException: TCrossHttpRequestExceptionEvent read GetOnRequestException write SetOnRequestException; + end; + + TCrossHttpConnection = class(TCrossServerConnection, ICrossHttpConnection) + private + FServer: TCrossHttpServer; + FRequestObj: TCrossHttpRequest; + FRequest: ICrossHttpRequest; + FResponseObj: TCrossHttpResponse; + FResponse: ICrossHttpResponse; + FHttpParser: ICrossHttpParser; + FPending: Integer; + + // pipelining 响应队列, 按请求解析顺序串行化响应发送 + FResponseQueue: TList; + FResponseQueueLock: ILock; + FSendingResponse: Boolean; + + {$region 'HttpParser事件'} + // 以下事件都在 FHttpParser.Decode 中被触发 + // 而 FHttpParser.Decode 在 ParseRecvData 中被调用 + // ParseRecvData 在 FServer.LogicReceived 中被调用 + // FServer.LogicReceived 被 TCrossConnectionBase._LockRecv 保护 + // 所以无需担心以下事件的多线程安全问题 + procedure _OnHeaderData(const ADataPtr: Pointer; const ADataSize: Integer); + function _OnGetHeaderValue(const AHeaderName: string; out AHeaderValues: TArray): Boolean; + procedure _OnBodyBegin; + procedure _OnBodyData(const ADataPtr: Pointer; const ADataSize: Integer); + procedure _OnBodyEnd; + procedure _OnParseBegin; + procedure _OnParseSuccess; + procedure _OnParseFailed(const ACode: Integer; const AError: string); + {$endregion} + + // 响应队列内部方法 + procedure _QueueResponseReady(const AItem: IHttpResponseQueueItem; + const ASource: TCrossHttpChunkDataFunc; + const ACallback: TCrossConnectionCallback); + procedure _SendQueueItem(const AItem: IHttpResponseQueueItem); + procedure _FinishQueueItem(const AItem: IHttpResponseQueueItem; const ASuccess: Boolean); + + // 调用前必须已持有 FResponseQueueLock; 若可发送则取出队首 ready item + // 并设置 FSendingResponse / item.Sending, 否则返回 nil + function _TryDequeueReadyLocked: IHttpResponseQueueItem; + + // 调用前必须已持有 FResponseQueueLock; 清空队列, 同时主动断开每个 item + // 内对 request/response/source/callback 的接口引用, 避免与 response.FQueueItem + // 等形成的循环引用导致 item 永不释放 + procedure _ClearResponseQueueLocked; + protected + function GetRequest: ICrossHttpRequest; + function GetResponse: ICrossHttpResponse; + function GetServer: ICrossHttpServer; + function GetPending: Integer; + + procedure ParseRecvData(var ABuf: Pointer; var ALen: Integer); virtual; + + procedure ReleaseRequest; virtual; + procedure ReleaseResponse; virtual; + + // socket 关闭时主动打破 connection 与 request/response 之间的循环引用, + // 并清空响应队列, 避免连接关闭后 connection 因循环引用永不释放导致内存泄漏 + procedure InternalClose; override; + public + constructor Create(const AOwner: TCrossSocketBase; const AClientSocket: TSocket; + const AConnectType: TConnectType; const AHost: string; + const AConnectCb: TCrossConnectionCallback); override; + destructor Destroy; override; + + property Request: ICrossHttpRequest read GetRequest; + property Response: ICrossHttpResponse read GetResponse; + property Server: ICrossHttpServer read GetServer; + property Pending: Integer read GetPending; + end; + + TCrossHttpRequest = class(TInterfacedObject, ICrossHttpRequest) + private + FRawRequestText: string; + FMethod, FPath, FQueryText, FPathAndQuery, FVersion: string; + FRawPath, FRawQueryText, FRawPathAndQuery: string; + FHttpVerNum: Integer; + FKeepAlive: Boolean; + FAccept: string; + FReferer: string; + FAcceptLanguage: string; + FAcceptEncoding: string; + FUserAgent: string; + FIfModifiedSince: TDateTime; + FIfNoneMatch: string; + FRange: string; + FIfRange: string; + FAuthorization: string; + FXForwardedFor: string; + FContentLength: Int64; + FHostName: string; + FHostPort: Word; + + FPostDataSize: Int64; + + FRequestCmdLine: string; + FContentType: string; + FRequestBoundary: string; + FTransferEncoding: string; + FContentEncoding: string; + FRequestCookies: string; + FRequestHost: string; + FRequestConnection: string; + + FConnectionObj: TCrossHttpConnection; + FConnection: ICrossHttpConnection; + FServer: TCrossHttpServer; + FHeader: THttpHeader; + FCookies: TRequestCookies; + FSession: ISession; + FParams: THttpUrlParams; + FQuery: THttpUrlParams; + FBody: TObject; + FRawBody: TMemoryStream; + FBodyType: TBodyType; + FIsChunked: Boolean; + private + function CalcIsChunked: Boolean; inline; + protected + function GetConnection: ICrossHttpConnection; + function GetRawRequestText: string; + function GetRawPathAndQuery: string; + function GetMethod: string; + function GetPath: string; + function GetPathAndQuery: string; + function GetVersion: string; + function GetHeader: THttpHeader; + function GetCookies: TRequestCookies; + function GetSession: ISession; + function GetParams: THttpUrlParams; + function GetQueryText: string; + function GetQuery: THttpUrlParams; + function GetBody: TObject; + function GetRawBody: TStream; + function GetBodyType: TBodyType; + function GetKeepAlive: Boolean; + function GetAccept: string; + function GetAcceptEncoding: string; + function GetAcceptLanguage: string; + function GetReferer: string; + function GetUserAgent: string; + function GetIfModifiedSince: TDateTime; + function GetIfNoneMatch: string; + function GetRange: string; + function GetIfRange: string; + function GetAuthorization: string; + function GetXForwardedFor: string; + function GetContentLength: Int64; + function GetHostName: string; + function GetHostPort: Word; + function GetContentType: string; + function GetContentEncoding: string; + function GetRequestBoundary: string; + function GetRequestCmdLine: string; + function GetRequestConnection: string; + function GetTransferEncoding: string; + function GetIsChunked: Boolean; + function GetIsMultiPartFormData: Boolean; + function GetIsUrlEncodedFormData: Boolean; + function GetPostDataSize: Int64; + + function ParseHeader(const ADataPtr: Pointer; const ADataSize: Integer): Boolean; + public + constructor Create(const AConnection: TCrossHttpConnection); + destructor Destroy; override; + + property Connection: ICrossHttpConnection read GetConnection; + property RawRequestText: string read GetRawRequestText; + property RawPathAndParams: string read GetRawPathAndQuery; + property Method: string read GetMethod; + property Path: string read GetPath; + property PathAndQuery: string read GetPathAndQuery; + property Version: string read GetVersion; + property Header: THttpHeader read GetHeader; + property Cookies: TRequestCookies read GetCookies; + property Session: ISession read GetSession; + property Params: THttpUrlParams read GetParams; + property Query: THttpUrlParams read GetQuery; + property QueryText: string read GetQueryText; + property Body: TObject read GetBody; + property RawBody: TStream read GetRawBody; + property BodyType: TBodyType read GetBodyType; + property KeepAlive: Boolean read GetKeepAlive; + property Accept: string read GetAccept; + property AcceptEncoding: string read GetAcceptEncoding; + property AcceptLanguage: string read GetAcceptLanguage; + property Referer: string read GetReferer; + property UserAgent: string read GetUserAgent; + property IfModifiedSince: TDateTime read GetIfModifiedSince; + property IfNoneMatch: string read GetIfNoneMatch; + property Range: string read GetRange; + property IfRange: string read GetIfRange; + property Authorization: string read GetAuthorization; + property XForwardedFor: string read GetXForwardedFor; + property ContentLength: Int64 read GetContentLength; + property HostName: string read GetHostName; + property HostPort: Word read GetHostPort; + property ContentType: string read GetContentType; + + property RequestCmdLine: string read GetRequestCmdLine; + + property RequestBoundary: string read GetRequestBoundary; + property TransferEncoding: string read GetTransferEncoding; + property ContentEncoding: string read GetContentEncoding; + property RequestConnection: string read GetRequestConnection; + property IsChunked: Boolean read GetIsChunked; + property IsMultiPartFormData: Boolean read GetIsMultiPartFormData; + property IsUrlEncodedFormData: Boolean read GetIsUrlEncodedFormData; + property PostDataSize: Int64 read GetPostDataSize; + end; + + TCrossHttpResponse = class(TInterfacedObject, ICrossHttpResponse) + public const + SND_BUF_SIZE = TCrossConnection.SND_BUF_SIZE; + private + FConnectionObj: TCrossHttpConnection; + FConnection: ICrossHttpConnection; + FRequest: ICrossHttpRequest; + FStatusCode: Integer; + FStatusText: string; + FHeader: THttpHeader; + FCookies: TResponseCookies; + FSendStatus: Integer; + FQueueItem: IHttpResponseQueueItem; + + procedure Reset; + function _CreateHeader(const ABodySize: Int64; AChunked: Boolean): TBytes; + + {$region '内部: 基础发送方法'} + procedure _Send(const ASource: TCrossHttpChunkDataFunc; const ACallback: TCrossConnectionCallback = nil); overload; + procedure _Send(const AHeaderSource, ABodySource: TCrossHttpChunkDataFunc; const ACallback: TCrossConnectionCallback = nil); overload; + {$endregion} + + function _CheckCompress(const ABodySize: Int64; out ACompressType: TCompressType): Boolean; + + // TCustomMemoryStream 优化: 直接获取内存指针, 避免逐块读流 + function _GetMemoryStreamPointer(const AStream: TStream; + const AOffset, ACount: Int64; out P: PByte; out LSize: Int64): Boolean; inline; + + {$region '压缩发送'} + procedure SendZCompress(const AChunkSource: TCrossHttpChunkDataFunc; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; + procedure SendZCompress(const ABody: Pointer; const ACount: NativeInt; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; + procedure SendZCompress(const ABody; const ACount: NativeInt; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; inline; + procedure SendZCompress(const ABody: TBytes; const AOffset, ACount: NativeInt; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; + procedure SendZCompress(const ABody: TBytes; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; inline; + procedure SendZCompress(const ABody: TStream; const AOffset, ACount: Int64; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; + procedure SendZCompress(const ABody: TStream; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; inline; + procedure SendZCompress(const ABody: string; const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback = nil); overload; + {$endregion} + + {$region '不压缩发送'} + procedure SendNoCompress(const AChunkSource: TCrossHttpChunkDataFunc; const ACallback: TCrossConnectionCallback = nil); overload; + procedure SendNoCompress(const ABody: Pointer; const ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; + procedure SendNoCompress(const ABody; const ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; inline; + procedure SendNoCompress(const ABody: TBytes; const AOffset, ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; + procedure SendNoCompress(const ABody: TBytes; const ACallback: TCrossConnectionCallback = nil); overload; inline; + procedure SendNoCompress(const ABody: TStream; const AOffset, ACount: Int64; const ACallback: TCrossConnectionCallback = nil); overload; + procedure SendNoCompress(const ABody: TStream; const ACallback: TCrossConnectionCallback = nil); overload; inline; + procedure SendNoCompress(const ABody: string; const ACallback: TCrossConnectionCallback = nil); overload; + {$endregion} + + {$region '常规方法'} + procedure Send(const ABody: Pointer; const ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; + procedure Send(const ABody; const ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; inline; + procedure Send(const ABody: TBytes; const AOffset, ACount: NativeInt; const ACallback: TCrossConnectionCallback = nil); overload; + procedure Send(const ABody: TBytes; const ACallback: TCrossConnectionCallback = nil); overload; inline; + procedure Send(const ABody: TStream; const AOffset, ACount: Int64; const ACallback: TCrossConnectionCallback = nil); overload; + procedure Send(const ABody: TStream; const ACallback: TCrossConnectionCallback = nil); overload; inline; + procedure Send(const ABody: string; const ACallback: TCrossConnectionCallback = nil); overload; + + procedure Json(const AJson: string; const ACallback: TCrossConnectionCallback = nil); + + procedure SendFile(const AFileName: string; const ACallback: TCrossConnectionCallback = nil); + procedure Download(const AFileName: string; const ACallback: TCrossConnectionCallback = nil); + procedure SendStatus(const AStatusCode: Integer; const ADescription: string; + const ACallback: TCrossConnectionCallback = nil); overload; + procedure SendStatus(const AStatusCode: Integer; + const ACallback: TCrossConnectionCallback = nil); overload; + procedure Redirect(const AUrl: string; const ACallback: TCrossConnectionCallback = nil); + procedure Attachment(const AFileName: string); + {$endregion} + protected + function GetConnection: ICrossHttpConnection; + function GetRequest: ICrossHttpRequest; + function GetStatusCode: Integer; + function GetStatusText: string; + function GetContentType: string; + function GetLocation: string; + function GetHeader: THttpHeader; + function GetCookies: TResponseCookies; + function GetSent: Boolean; + + procedure SetContentType(const Value: string); + procedure SetLocation(const Value: string); + procedure SetStatusCode(Value: Integer); + procedure SetStatusText(const Value: string); + public + constructor Create(const AConnection: TCrossHttpConnection; + const ARequest: ICrossHttpRequest; + const AQueueItem: IHttpResponseQueueItem); + destructor Destroy; override; + end; + + /// + /// 路由参数定义 + /// + TRouteParam = record + Name: string; // 参数名 + Pattern: string; // 正则模式 + end; + + /// + /// 路由类型 + /// + TRouteType = ( + /// + /// 静态路由 + /// + rtStatic, + + /// + /// 正则路由 + /// 例如: /users/:id, /users/:id/echo, /users/:id(\d+) + /// + rtRegex, + + /// + /// 通配符路由 + /// 例如: /files/*, 其中*就是通配符节点, 通配符节点只能出现在路径最后一段 + /// + rtWildcard + ); + + /// + /// 路由接口 + /// + IRouter = interface + ['{5A7E2B1C-8D3F-4E69-A0C5-2F1B8E6D4A93}'] + function GetRouteType: TRouteType; + function GetMethodPattern: string; + function GetRegEx: IRegEx; + + procedure AddRouterProc(const ARouterProc: TCrossHttpRouterProc); overload; + procedure AddRouterProc(const ARouterMethod: TCrossHttpRouterMethod); overload; + + procedure Execute(const ARequest: ICrossHttpRequest; + const AResponse: ICrossHttpResponse; var AHandled: Boolean); + + property RouteType: TRouteType read GetRouteType; + property MethodPattern: string read GetMethodPattern; + property RegEx: IRegEx read GetRegEx; + end; + + /// + /// 路由 + /// + TRouter = class(TInterfacedObject, IRouter) + private + // 路由类型 + FRouteType: TRouteType; + // 方法模式(如 "GET", "GET|POST", "*" 等) + FMethodPattern: string; + FLock: IReadWriteLock; + + // 路由处理函数 + FRouterProcList: TList; + FRouterMethodList: TList; + + function GetRouteType: TRouteType; + function GetMethodPattern: string; + function GetRegEx: IRegEx; + public + constructor Create(const AMethodPattern: string); + destructor Destroy; override; + + procedure AddRouterProc(const ARouterProc: TCrossHttpRouterProc); overload; + procedure AddRouterProc(const ARouterMethod: TCrossHttpRouterMethod); overload; + + procedure Execute(const ARequest: ICrossHttpRequest; + const AResponse: ICrossHttpResponse; var AHandled: Boolean); + end; + + /// + /// 路由段 + /// + TRouteSegment = class + private + FOriginal: string; // 原始段 + FPattern: string; // 完整模式 + FParams: TArray; // 参数定义数组 + FRouteType: TRouteType; // 路由类型 + public + constructor Create(const AOriginal, APattern: string; + const AParams: TArray; ARouteType: TRouteType); + + // 正则匹配 + // 只有正则匹配的路由才需要处理参数 + function RegexMatch(const ASegment: string; const ARequest: ICrossHttpRequest): Boolean; + + property Original: string read FOriginal; + property Pattern: string read FPattern; + property Params: TArray read FParams; + property RouteType: TRouteType read FRouteType; + end; + + /// + /// 路由节点 + /// + TRouteNode = class + private + FRouteType: TRouteType; // 路由类型 + FSegment: TRouteSegment; // 路由段 + + FStaticChildren: TObjectDictionary; // 静态子节点 + FRegexChildren: TObjectList; // 正则子节点 + FWildcardChild: TRouteNode; // 通配符子节点 + + FStaticRouteMethodItems: TDictionary; // 静态方法路由项列表 + FRegexRouteMethodItems: TList; // 正则方法路由项列表 + FWildcardRouteMethodItem: IRouter; // 通配符路由项 + + function GetChildNode(const ASegment: string; const ARouteType: TRouteType; out ARouteNode: TRouteNode): Boolean; + function CreateChildNode(const ASegment: TRouteSegment): TRouteNode; + public + constructor Create(ARouteType: TRouteType; const ASegment: TRouteSegment); + destructor Destroy; override; + + // 注意: 添加和删除是使用的模式字符串(比如 GET POST GET|POST) + procedure AddRouter(const AMethodPattern: string; const ARouter: IRouter); + function GetRouter(const AMethodPattern: string; out ARouter: IRouter): Boolean; + function RemoveRouter(const AMethodPattern: string): Boolean; + + // 注意: 查找使用的是确定的请求方法(比如 GET POST) + function MatchRouter(const AMethod: string; out ARouter: IRouter): Boolean; + function IsEmpty: Boolean; + + property RouteType: TRouteType read FRouteType; + property Segment: TRouteSegment read FSegment; + property StaticChildren: TObjectDictionary read FStaticChildren; + property RegexChildren: TObjectList read FRegexChildren; + property WildcardChild: TRouteNode read FWildcardChild; + end; + + /// + /// 路由树 + /// + TCrossHttpRouterTree = class + private + FRoot: TRouteNode; + FLock: IReadWriteLock; + + function CreateSegment(const ASegment: string; const ARouteType: TRouteType): TRouteSegment; + + // 注意: 添加和删除是使用的模式字符串(比如 GET POST GET|POST, /user/:id) + procedure AddRouterToNode(ANode: TRouteNode; const APathPatternSegments: TArray; + AIndex: Integer; const AMethodPattern: string; const ARouter: IRouter); + function GetRouterFromNode(ANode: TRouteNode; const APathPatternSegments: TArray; + AIndex: Integer; const AMethodPattern: string; out ARouter: IRouter): Boolean; + function RemoveRouterFromNode(ANode: TRouteNode; const APathPatternSegments: TArray; + AIndex: Integer; const AMethodPattern: string): Boolean; + + function GetWildcardValue(const APathSegments: TArray; + AIndex: Integer; const AQueryText: string): string; + // 注意: 查找使用的是确定的请求方法和路径(比如 GET POST, /user/123) + function MatchRouterInNode(ANode: TRouteNode; const APathSegments: TArray; + AIndex: Integer; const AMethod: string; const ARequest: ICrossHttpRequest; + out ARouter: IRouter): Boolean; + public + constructor Create; + destructor Destroy; override; + + // 将请求路径分段 + class function ParsePath(const APath: string): TArray; static; + + // 注意: 添加和删除是使用的模式字符串(比如 GET POST GET|POST, /user/:id) + procedure AddRouter(const AMethodPattern, APathPattern: string; const ARouter: IRouter); overload; + function GetRouter(const AMethodPattern, APathPattern: string; out ARouter: IRouter): Boolean; overload; + function GetRouter(const AMethodPattern, APathPattern: string): IRouter; overload; + + procedure AddRouter(const AMethodPattern, APathPattern: string; const ARouterProc: TCrossHttpRouterProc); overload; + procedure AddRouter(const AMethodPattern, APathPattern: string; const ARouterMethod: TCrossHttpRouterMethod); overload; + + procedure RemoveRouter(const AMethodPattern, APathPattern: string); + + // 注意: 查找与请求匹配的路由 + function MatchRouter(const APathSegments: TArray; const ARequest: ICrossHttpRequest; out ARouter: IRouter): Boolean; overload; + function MatchRouter(const ARequest: ICrossHttpRequest; out ARouter: IRouter): Boolean; overload; + procedure Clear; + end; + + TCrossHttpServer = class(TCrossServer, ICrossHttpServer) + private const + SESSIONID_COOKIE_NAME = 'cross_sessionid'; + private + FStoragePath: string; + FAutoDeleteFiles: Boolean; + FMaxPostDataSize: Int64; + FMaxHeaderSize: Int64; + FMaxCompressRatio: Integer; + FMinCompressSize: Int64; + FSessionIDCookieName: string; + + FRouters: TCrossHttpRouterTree; + FMiddlewares: TCrossHttpRouterTree; + + FSessions: ISessions; + FOnRequestBegin: TCrossHttpRequestBeginEvent; + FOnRequestEnd: TCrossHttpRequestEndEvent; + FOnRequest: TCrossHttpRequestEvent; + FOnRequestException: TCrossHttpRequestExceptionEvent; + FCompressible: Boolean; + protected + function GetStoragePath: string; + function GetAutoDeleteFiles: Boolean; + function GetMaxHeaderSize: Int64; + function GetMaxPostDataSize: Int64; + function GetMaxCompressRatio: Integer; + function GetCompressible: Boolean; + function GetMinCompressSize: Int64; + function GetSessions: ISessions; + function GetSessionIDCookieName: string; + function GetOnRequest: TCrossHttpRequestEvent; + function GetOnRequestEnd: TCrossHttpRequestEndEvent; + function GetOnRequestBegin: TCrossHttpRequestBeginEvent; + function GetOnRequestException: TCrossHttpRequestExceptionEvent; + + procedure SetStoragePath(const Value: string); + procedure SetAutoDeleteFiles(const Value: Boolean); + procedure SetMaxHeaderSize(const Value: Int64); + procedure SetMaxPostDataSize(const Value: Int64); + procedure SetMaxCompressRatio(const Value: Integer); + procedure SetCompressible(const Value: Boolean); + procedure SetMinCompressSize(const Value: Int64); + procedure SetSessions(const Value: ISessions); + procedure SetSessionIDCookieName(const Value: string); + procedure SetOnRequest(const Value: TCrossHttpRequestEvent); + procedure SetOnRequestBegin(const Value: TCrossHttpRequestBeginEvent); + procedure SetOnRequestEnd(const Value: TCrossHttpRequestEndEvent); + procedure SetOnRequestException(const Value: TCrossHttpRequestExceptionEvent); + protected + function CreateConnection(const AOwner: TCrossSocketBase; const AClientSocket: TSocket; + const AConnectType: TConnectType; const AHost: string; + const AConnectCb: TCrossConnectionCallback): ICrossConnection; override; + + procedure LogicReceived(const AConnection: ICrossConnection; const ABuf: Pointer; const ALen: Integer); override; + protected + // 处理请求前 + // 显式传入 ARequest/AResponse, 避免在 pipelining 场景下从 connection 字段读取产生 race + procedure DoOnRequestBegin(const AConnection: ICrossHttpConnection; + const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse); virtual; + + // 处理请求 + procedure DoOnRequest(const AConnection: ICrossHttpConnection; + const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse); virtual; + + // 处理请求后 + procedure DoOnRequestEnd(const AConnection: ICrossHttpConnection; + const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse; + const ASuccess: Boolean); virtual; + public + constructor Create(const AIoThreads: Integer; const ASsl: Boolean); override; + destructor Destroy; override; + + function Use(const AMethod, APath: string; + const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + function Use(const AMethod, APath: string; + const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + function Use(const APath: string; + const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + function Use(const APath: string; + const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + function Use(const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + function Use(const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + + function Route(const AMethod, APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + function Route(const AMethod, APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + + function Get(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + function Get(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + + function Put(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + function Put(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + + function Post(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + function Post(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + + function Delete(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + function Delete(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + + function All(const APath: string; const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; overload; + function All(const APath: string; const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; overload; + + function &Static(const APath, ALocalStaticDir: string): ICrossHttpServer; + function Dir(const APath, ALocalDir: string): ICrossHttpServer; + function Index(const APath, ALocalDir: string; const ADefIndexFiles: TArray): ICrossHttpServer; + + function RemoveRouter(const AMethod, APath: string): ICrossHttpServer; + function ClearRouters: ICrossHttpServer; + + function RemoveMiddleware(const AMethod, APath: string): ICrossHttpServer; + function ClearMiddlewares: ICrossHttpServer; + + property StoragePath: string read GetStoragePath write SetStoragePath; + property AutoDeleteFiles: Boolean read GetAutoDeleteFiles write SetAutoDeleteFiles; + property MaxHeaderSize: Int64 read GetMaxHeaderSize write SetMaxHeaderSize; + property MaxPostDataSize: Int64 read GetMaxPostDataSize write SetMaxPostDataSize; + property MaxCompressRatio: Integer read GetMaxCompressRatio write SetMaxCompressRatio; + property Compressible: Boolean read GetCompressible write SetCompressible; + property MinCompressSize: Int64 read GetMinCompressSize write SetMinCompressSize; + property Sessions: ISessions read GetSessions write SetSessions; + property SessionIDCookieName: string read GetSessionIDCookieName write SetSessionIDCookieName; + + property OnRequestBegin: TCrossHttpRequestBeginEvent read GetOnRequestBegin write SetOnRequestBegin; + property OnRequest: TCrossHttpRequestEvent read GetOnRequest write SetOnRequest; + property OnRequestEnd: TCrossHttpRequestEndEvent read GetOnRequestEnd write SetOnRequestEnd; + property OnRequestException: TCrossHttpRequestExceptionEvent read GetOnRequestException write SetOnRequestException; + end; + +implementation + +uses + {$IFDEF MSWINDOWS} + Windows, + {$ENDIF} + Utils.Utils, + Net.CrossHttpRouter; + +const + // HTTP/1.1 100 Continue 临时响应,用于 Expect: 100-continue 流程 + CResponse100Continue: AnsiString = 'HTTP/1.1 100 Continue'#13#10#13#10; + + +{ ECrossHttpException } + +constructor ECrossHttpException.Create(const AMessage: string; + AStatusCode: Integer); +begin + inherited Create(AMessage); + FStatusCode := AStatusCode; +end; + +constructor ECrossHttpException.CreateFmt(const AMessage: string; + const AArgs: array of const; AStatusCode: Integer); +begin + inherited CreateFmt(AMessage, AArgs); + FStatusCode := AStatusCode; +end; + +{ THttpResponseQueueItem } + +function THttpResponseQueueItem.GetRequest: ICrossHttpRequest; +begin + Result := FRequest; +end; + +function THttpResponseQueueItem.GetResponse: ICrossHttpResponse; +begin + Result := FResponse; +end; + +function THttpResponseQueueItem.GetSource: TCrossHttpChunkDataFunc; +begin + Result := FSource; +end; + +function THttpResponseQueueItem.GetCallback: TCrossConnectionCallback; +begin + Result := FCallback; +end; + +function THttpResponseQueueItem.GetReady: Boolean; +begin + Result := FReady; +end; + +function THttpResponseQueueItem.GetSending: Boolean; +begin + Result := FSending; +end; + +function THttpResponseQueueItem.GetCompleted: Boolean; +begin + Result := FCompleted; +end; + +function THttpResponseQueueItem.GetKeepAlive: Boolean; +begin + Result := FKeepAlive; +end; + +function THttpResponseQueueItem.GetStatusCode: Integer; +begin + Result := FStatusCode; +end; + +procedure THttpResponseQueueItem.SetRequest(const AValue: ICrossHttpRequest); +begin + FRequest := AValue; +end; + +procedure THttpResponseQueueItem.SetResponse(const AValue: ICrossHttpResponse); +begin + FResponse := AValue; +end; + +procedure THttpResponseQueueItem.SetSource(const AValue: TCrossHttpChunkDataFunc); +begin + FSource := AValue; +end; + +procedure THttpResponseQueueItem.SetCallback(const AValue: TCrossConnectionCallback); +begin + FCallback := AValue; +end; + +procedure THttpResponseQueueItem.SetReady(const AValue: Boolean); +begin + FReady := AValue; +end; + +procedure THttpResponseQueueItem.SetSending(const AValue: Boolean); +begin + FSending := AValue; +end; + +procedure THttpResponseQueueItem.SetCompleted(const AValue: Boolean); +begin + FCompleted := AValue; +end; + +procedure THttpResponseQueueItem.SetKeepAlive(const AValue: Boolean); +begin + FKeepAlive := AValue; +end; + +procedure THttpResponseQueueItem.SetStatusCode(const AValue: Integer); +begin + FStatusCode := AValue; +end; + +{ TCrossHttpConnection } + +constructor TCrossHttpConnection.Create(const AOwner: TCrossSocketBase; + const AClientSocket: TSocket; const AConnectType: TConnectType; + const AHost: string; const AConnectCb: TCrossConnectionCallback); +begin + inherited Create(AOwner, AClientSocket, AConnectType, AHost, AConnectCb); + + FServer := AOwner as TCrossHttpServer; + + FResponseQueue := TList.Create; + FResponseQueueLock := TLock.Create; + + FHttpParser := TCrossHttpParser.Create(pmServer); + FHttpParser.MaxHeaderSize := FServer.MaxHeaderSize; + FHttpParser.MaxBodyDataSize := FServer.MaxPostDataSize; + FHttpParser.MaxCompressRatio := FServer.MaxCompressRatio; + FHttpParser.OnHeaderData := _OnHeaderData; + FHttpParser.OnGetHeaderValue := _OnGetHeaderValue; + FHttpParser.OnBodyBegin := _OnBodyBegin; + FHttpParser.OnBodyData := _OnBodyData; + FHttpParser.OnBodyEnd := _OnBodyEnd; + FHttpParser.OnParseBegin := _OnParseBegin; + FHttpParser.OnParseSuccess := _OnParseSuccess; + FHttpParser.OnParseFailed := _OnParseFailed; +end; + +destructor TCrossHttpConnection.Destroy; +begin + if (FRequest <> nil) then + (FRequest as TCrossHttpRequest).FConnection := nil; + + if (FResponse <> nil) then + (FResponse as TCrossHttpResponse).FConnection := nil; + + ReleaseRequest; + ReleaseResponse; + + // 队列清理由 InternalClose 负责 (包括 _ClearResponseQueueLocked 触发 callbacks), + // 此处仅做 defensive 的 FreeAndNil, 避免重复清理 + FreeAndNil(FResponseQueue); + FResponseQueueLock := nil; + + FHttpParser := nil; + + inherited; +end; + +function TCrossHttpConnection.GetRequest: ICrossHttpRequest; +begin + Result := FRequest; +end; + +function TCrossHttpConnection.GetResponse: ICrossHttpResponse; +begin + Result := FResponse; +end; + +function TCrossHttpConnection.GetServer: ICrossHttpServer; +begin + Result := Owner as ICrossHttpServer; +end; + +function TCrossHttpConnection.GetPending: Integer; +begin + // 读取在多 IO 线程间发生, 与 _OnParseBegin 的 AtomicIncrement / + // _FinishQueueItem 的 AtomicDecrement 保持原子语义 + Result := AtomicCmpExchange(FPending, 0, 0); +end; + +procedure TCrossHttpConnection.ParseRecvData(var ABuf: Pointer; + var ALen: Integer); +begin + if (FHttpParser <> nil) then + FHttpParser.Decode(ABuf, ALen) + else + ALen := 0; +end; + +procedure TCrossHttpConnection.ReleaseRequest; +begin + FRequestObj := nil; + FRequest := nil; +end; + +procedure TCrossHttpConnection.ReleaseResponse; +begin + FResponseObj := nil; + FResponse := nil; +end; + +procedure TCrossHttpConnection.InternalClose; +begin + // 必须在 socket 关闭时主动断开连接级 FRequest/FResponse 与 request.FConnection / + // response.FConnection 之间的循环引用. 否则 connection.FRequest 持有 request, 而 + // request.FConnection 又持有 connection, refcount 永不归零, 不仅 connection 不会 + // 销毁, 队列内 item / request body / response header 等也全部泄漏. + if (FRequest <> nil) then + (FRequest as TCrossHttpRequest).FConnection := nil; + if (FResponse <> nil) then + (FResponse as TCrossHttpResponse).FConnection := nil; + ReleaseRequest; + ReleaseResponse; + + // 清空响应队列中剩余 items: 它们持有的 request/response/source/callback 接口字段 + // 与 response.FQueueItem 形成循环引用. 必须先逐个清空 item 内的接口字段, + // 再 Clear 队列, 否则 items 引用计数减 1 之后仍因循环引用而不会归零, 导致泄漏 + if (FResponseQueueLock <> nil) and (FResponseQueue <> nil) then + begin + FResponseQueueLock.Enter; + try + FSendingResponse := False; + _ClearResponseQueueLocked; + finally + FResponseQueueLock.Leave; + end; + end; + + inherited InternalClose; +end; + +function TCrossHttpConnection._TryDequeueReadyLocked: IHttpResponseQueueItem; +begin + Result := nil; + + if FSendingResponse then Exit; + if (FResponseQueue = nil) or (FResponseQueue.Count = 0) then Exit; + if not FResponseQueue[0].Ready then Exit; + + // 从队列中移除队首, 由调用方的局部接口引用保活后续发送过程 + Result := FResponseQueue[0]; + FResponseQueue.Delete(0); + FSendingResponse := True; + Result.Sending := True; +end; + +// _ClearResponseQueueLocked: +// 调用前必须持有 FResponseQueueLock. +// 按队列注册顺序 (FIFO) 收集所有 callback, 清空队列并逐个清空 item 内部接口引用, +// 锁外按收集顺序触发 callback(False) 通知业务方发送失败. +// 注意: callback 中不应操作连接状态 (如 Disconnect), 因为此时连接正在关闭流程中. +procedure TCrossHttpConnection._ClearResponseQueueLocked; +var + I: Integer; + LItem: IHttpResponseQueueItem; + LCallbacks: TArray; +begin + if (FResponseQueue = nil) then Exit; + + // 收集所有待通知 callback (在本方法尾部、队列清空后触发), + // 避免静默丢弃导致业务方 hang 等通知. + SetLength(LCallbacks, FResponseQueue.Count); + for I := 0 to FResponseQueue.Count - 1 do + begin + LItem := FResponseQueue[I]; + if (LItem <> nil) then + begin + LCallbacks[I] := LItem.Callback; + LItem.Request := nil; + LItem.Response := nil; + LItem.Source := nil; + LItem.Callback := nil; + end; + end; + + FResponseQueue.Clear; + + // 触发所有被丢弃的 callback (通知失败) + for I := 0 to High(LCallbacks) do + if Assigned(LCallbacks[I]) then + LCallbacks[I](Self, False); +end; + +procedure TCrossHttpConnection._QueueResponseReady( + const AItem: IHttpResponseQueueItem; + const ASource: TCrossHttpChunkDataFunc; + const ACallback: TCrossConnectionCallback); +var + LAlreadyReadyOrCompleted: Boolean; + LItemToSend: IHttpResponseQueueItem; +begin + if (AItem = nil) then + begin + if Assigned(ACallback) then + ACallback(Self, False); + Exit; + end; + + LAlreadyReadyOrCompleted := False; + LItemToSend := nil; + + // 单次锁块完成 "标记 ready" 与 "尝试 take 队首" 两件事 + // 减少 happy path 上的锁/解锁次数, 降低高并发竞争开销 + FResponseQueueLock.Enter; + try + if AItem.Ready or AItem.Completed then + begin + // 同一个 item 不允许重复 ready, 不修改原有 Source/Callback + LAlreadyReadyOrCompleted := True; + end else + begin + AItem.Source := ASource; + AItem.Callback := ACallback; + AItem.KeepAlive := AItem.Request.KeepAlive; + AItem.StatusCode := AItem.Response.StatusCode; + AItem.Ready := True; + + // 没有正在发送时, 立即尝试取队首 ready item + LItemToSend := _TryDequeueReadyLocked; + end; + finally + FResponseQueueLock.Leave; + end; + + if LAlreadyReadyOrCompleted then + begin + // 安全降级: 对重复传入的 callback 触发失败, 避免调用方静默挂起 + if Assigned(ACallback) then + ACallback(Self, False); + Exit; + end; + + if (LItemToSend <> nil) then + _SendQueueItem(LItemToSend); +end; + +procedure TCrossHttpConnection._SendQueueItem(const AItem: IHttpResponseQueueItem); +var + LConnection: ICrossHttpConnection; + LSender: TCrossConnectionCallback; +begin + LConnection := Self; + + LSender := + procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) + var + LData: Pointer; + LCount: NativeInt; + LSource: TCrossHttpChunkDataFunc; + begin + if not ASuccess then + begin + _FinishQueueItem(AItem, False); + LConnection := nil; + LSender := nil; + Exit; + end; + + LSource := AItem.Source; + LData := nil; + LCount := 0; + if not Assigned(LSource) + or not LSource(@LData, @LCount) + or (LData = nil) + or (LCount <= 0) then + begin + // StatusCode>=500 表示压缩/发送过程中发生了不可恢复的错误 + _FinishQueueItem(AItem, AItem.StatusCode < 500); + LConnection := nil; + LSender := nil; + Exit; + end; + + AConnection.SendBuf(LData^, LCount, LSender); + end; + + LSender(LConnection, True); +end; + +procedure TCrossHttpConnection._FinishQueueItem( + const AItem: IHttpResponseQueueItem; const ASuccess: Boolean); +var + LRequest: ICrossHttpRequest; + LResponse: ICrossHttpResponse; + LCallback: TCrossConnectionCallback; + LNeedDisconnect, LDoEnd: Boolean; + LItemNext: IHttpResponseQueueItem; +begin + LDoEnd := False; + LNeedDisconnect := False; + LRequest := nil; + LResponse := nil; + LCallback := nil; + LItemNext := nil; + + // 单次锁块完成 "标记 completed + 释放 sending 标志 + 尝试 take 下一个 ready item" + // 三件事, 锁外再触发下一个 item 的发送, 避免两次进出锁的开销 + FResponseQueueLock.Enter; + try + // 先复位 FSendingResponse, 确保无论 AItem 是否已经 Completed 都不会挂起后续响应 + FSendingResponse := False; + if not AItem.Completed then + begin + LRequest := AItem.Request; + LResponse := AItem.Response; + LCallback := AItem.Callback; + LNeedDisconnect := ASuccess and ((not AItem.KeepAlive) or (AItem.StatusCode >= 500)); + + AItem.Completed := True; + LDoEnd := True; + + // 关键: 立即清空 item 对外部对象的接口引用, 打破循环引用导致的内存泄漏: + // response.FQueueItem -> item.FResponse -> response (双向接口循环) + // item.FSource -> 匿名方法 (captured Self=response) -> response (隐式循环) + // 不在此处释放, 这些引用要等到 connection 释放才能解开, 而 connection + // 又被 request.FConnection / response.FConnection 持有, 形成多重循环 + AItem.Request := nil; + AItem.Response := nil; + AItem.Source := nil; + AItem.Callback := nil; + + // 仅在 happy path 下提前 take 下一个 item; 失败/disconnect 路径不取, + // 让 connection 关闭流程清理剩余 queue + if ASuccess and (not LNeedDisconnect) then + LItemNext := _TryDequeueReadyLocked; + end; + finally + FResponseQueueLock.Leave; + end; + + if LDoEnd then + begin + // 不写 FRequest/FResponse 连接级字段, 这两个字段仅由 _OnParseBegin + // 在 _LockRecv 内独占写入. 当前完成 item 的 request/response 通过 + // LRequest/LResponse 显式传给 DoOnRequestEnd, 进而传给 OnRequestEnd 事件, + // 事件 handler 可直接从参数拿到精确对应的请求/响应, 不需要读连接字段 + AtomicDecrement(FPending); + + // 用户 callback 可能抛异常, 必须用 try/finally 保证 DoOnRequestEnd 触发 + try + if Assigned(LCallback) then + LCallback(Self, ASuccess); + finally + FServer.DoOnRequestEnd(Self, LRequest, LResponse, ASuccess); + end; + end; + + if (not ASuccess) or LNeedDisconnect then + Disconnect + else if (LItemNext <> nil) then + _SendQueueItem(LItemNext); +end; + +procedure TCrossHttpConnection._OnBodyBegin; +var + LMultiPart: THttpMultiPartFormData; +begin + {$region '创建Body'} + case FRequestObj.GetBodyType of + btMultiPart: + begin + if (FServer.FStoragePath <> '') and not DirectoryExists(FServer.FStoragePath) then + ForceDirectories(FServer.FStoragePath); + + LMultiPart := THttpMultiPartFormData.Create; + LMultiPart.StoragePath := FServer.FStoragePath; + LMultiPart.AutoDeleteFiles := FServer.FAutoDeleteFiles; + LMultiPart.InitWithBoundary(FRequestObj.RequestBoundary); + if (FRequestObj.FBody = FRequestObj.FRawBody) then + FRequestObj.FBody := nil + else + FreeAndNil(FRequestObj.FBody); + FreeAndNil(FRequestObj.FRawBody); + FRequestObj.FBody := LMultiPart; + end; + + btUrlEncoded, btBinary: + begin + // 二次校验: Parser 层可能未限制时由 Server 层兜底 + if (FServer.FMaxPostDataSize > 0) and (FRequestObj.FContentLength > FServer.FMaxPostDataSize) then + begin + _OnParseFailed(413, 'Request body too large.'); + Exit; // FBody 保持 nil, _OnBodyData/_OnBodyEnd 有 nil guard 安全跳过 + end; + if (FRequestObj.FBody = FRequestObj.FRawBody) then + FRequestObj.FBody := nil + else + FreeAndNil(FRequestObj.FBody); + FreeAndNil(FRequestObj.FRawBody); + FRequestObj.FRawBody := TMemoryStream.Create; + FRequestObj.FBody := FRequestObj.FRawBody; + end; + end; + {$endregion} +end; + +procedure TCrossHttpConnection._OnBodyData(const ADataPtr: Pointer; + const ADataSize: Integer); +begin + if (FRequestObj.FBody = nil) then Exit; + + Inc(FRequestObj.FPostDataSize, ADataSize); + + case FRequestObj.GetBodyType of + btMultiPart: + (FRequestObj.FBody as THttpMultiPartFormData).Decode(ADataPtr, ADataSize); + + btUrlEncoded, btBinary: + if (FRequestObj.FRawBody <> nil) then + FRequestObj.FRawBody.Write(ADataPtr^, ADataSize); + end; +end; + +procedure TCrossHttpConnection._OnBodyEnd; +var + LUrlEncodedStr: string; + LUrlEncodedBody: TFormUrlEncoded; +begin + if (FRequestObj.FBody = nil) then Exit; + + case FRequestObj.GetBodyType of + btUrlEncoded: + begin + if (FRequestObj.FRawBody = nil) then Exit; + + SetString(LUrlEncodedStr, + MarshaledAString(FRequestObj.FRawBody.Memory), + FRequestObj.FRawBody.Size); + LUrlEncodedBody := TFormUrlEncoded.Create; + if LUrlEncodedBody.Decode(LUrlEncodedStr) then + begin + if (FRequestObj.FBody = FRequestObj.FRawBody) then + FRequestObj.FBody := nil + else + FreeAndNil(FRequestObj.FBody); + FRequestObj.FBody := LUrlEncodedBody; + FRequestObj.FRawBody.Position := 0; + end else + begin + FreeAndNil(LUrlEncodedBody); + // 如果按 UrlEncoded 方式解码失败, 则保留原始数据 + // 并将类型改为 btBinary + FRequestObj.FBodyType := btBinary; + FRequestObj.FBody := FRequestObj.FRawBody; + FRequestObj.FRawBody.Position := 0; + end; + end; + + btBinary: + if (FRequestObj.FRawBody <> nil) then + FRequestObj.FRawBody.Position := 0; + end; +end; + +function TCrossHttpConnection._OnGetHeaderValue(const AHeaderName: string; + out AHeaderValues: TArray): Boolean; +begin + Result := FRequest.Header.GetHeaderValues(AHeaderName, AHeaderValues); +end; + +procedure TCrossHttpConnection._OnHeaderData(const ADataPtr: Pointer; + const ADataSize: Integer); +var + LParsed: Boolean; + LExpect: string; +begin + // ParseHeader 内部已用 try/except 将各类解析异常转为 Result := False, + // 这里仍再加一层护栏, 防止以后修改 ParseHeader 时遗漏局部 try/except + // 导致恶意/畸形请求的异常上抛到 LogicReceived 环外. 统一归一为 400 响应. + try + LParsed := (FRequest as TCrossHttpRequest).ParseHeader(ADataPtr, ADataSize); + except + LParsed := False; + end; + + if not LParsed then + begin + _OnParseFailed(400, 'Invalid request header.'); + Abort; + end; + + // RFC 7231 §5.1.1: Expect: 100-continue 支持 + // + // 协议流程: + // 客户端发送 header (含 Expect: 100-continue) → + // 服务器在此处发送 100 Continue (临时响应, 不走响应队列) → + // Parser 继续接收 body (_OnBodyBegin → _OnBodyData → _OnBodyEnd) → + // _OnParseSuccess → DoOnRequest 正常处理路由/中间件 → + // 最终发送正式响应 (200/404/500 等) + // + // 注意: + // 100 Continue 只是一个协议层 "请继续" 信号, 不代表服务器接受该请求. + // 当前实现不在此阶段做认证/校验, 意味着即使后续 DoOnRequest 返回 401, + // 客户端也已发送完整 body. 对于大多数客户端, 不带 Expect 头时的行为 + // 也是如此 (body 总会随 header 一起发送), 所以无实际功能损失. + // SendBuf 是非阻塞操作, 在 _LockRecv 内调用安全. + LExpect := FRequest.Header[HEADER_EXPECT]; + if TStrUtils.SameText(LExpect.Trim, '100-continue') then + Self.SendBuf(@CResponse100Continue[1], Length(CResponse100Continue), nil); +end; + +procedure TCrossHttpConnection._OnParseBegin; +var + LItem: IHttpResponseQueueItem; +begin + // 本函数以及其它 HttpParser 回调均由 FHttpParser.Decode -> ParseRecvData -> + // FServer.LogicReceived -> TCrossSocketBase.TriggerReceived 同步触发, + // 调用链起点已由 TriggerReceived 加上 TCrossConnectionBase._LockRecv, + // 所以这里不需要也不应该重复加锁 + + // 为本次请求创建独立的 queue item, 队列顺序由解析顺序决定 + LItem := THttpResponseQueueItem.Create; + + FRequestObj := TCrossHttpRequest.Create(Self); + FRequest := FRequestObj; + + // 创建响应对象, 显式绑定到 request 和 queue item, 确保异步发送时 + // 不依赖连接级 FRequest/FResponse 字段 + FResponseObj := TCrossHttpResponse.Create(Self, FRequest, LItem); + FResponse := FResponseObj; + + LItem.Request := FRequest; + LItem.Response := FResponse; + + FResponseQueueLock.Enter; + try + FResponseQueue.Add(LItem); + finally + FResponseQueueLock.Leave; + end; + + AtomicIncrement(FPending); +end; + +procedure TCrossHttpConnection._OnParseFailed(const ACode: Integer; + const AError: string); +begin + if (FResponse <> nil) then + FResponse.SendStatus(ACode, AError) + else + Close; +end; + +procedure TCrossHttpConnection._OnParseSuccess; +var + LConnection: ICrossHttpConnection; + LRequest: ICrossHttpRequest; + LResponse: ICrossHttpResponse; +begin + LConnection := Self; + // 这里是 _LockRecv 保护下的同步调用, FRequest/FResponse 此刻仍是 + // _OnParseBegin 刚写入的当前 parse item 的 request/response. + // 显式捕获为局部接口引用的真正意义在于: 一旦后续业务释放锁 + // (如未来调整架构则业务可能在锁外运行) 或 _OnParseBegin 重新写入 + // 连接级字段, 本局部变量仍以接口引用计数保证当前请求/响应对象存活, + // 不会读到错位对象。对象生命周期本质上由接口引用计数保证, 与锁无关 + LRequest := FRequest; + LResponse := FResponse; + FServer.DoOnRequestBegin(LConnection, LRequest, LResponse); + FServer.DoOnRequest(LConnection, LRequest, LResponse); +end; + +function IsRegEx(const APattern: string): Boolean; inline; +begin + Result := (APattern.IndexOfAny(REGEX_CHARS) >= 0); +end; + +function IsWildcard(const APattern: string): Boolean; inline; +begin + Result := (APattern = WILDCARD_CHAR); +end; + +function GetPatternType(const APattern: string): TRouteType; inline; +begin + // 通配符 + if IsWildcard(APattern) then + Result := rtWildcard + // 正则 + else if IsRegEx(APattern) then + Result := rtRegex + // 静态 + else + Result := rtStatic; +end; + +function CreateRouterRegEx(const APattern: string): IRegEx; +var + LPattern: string; +begin + LPattern := APattern; + if (LPattern = '*') then + LPattern := '.*'; + + // 添加正则表达式的开始和结束锚点 + if not LPattern.StartsWith('^') then + LPattern := '^' + LPattern; + if not LPattern.EndsWith('$') then + LPattern := LPattern + '$'; + + Result := TRegEx.Create(LPattern); + Result.Options := [roIgnoreCase]; +end; + +{ TRouter } + +procedure TRouter.AddRouterProc(const ARouterProc: TCrossHttpRouterProc); +begin + FLock.BeginWrite; + try + FRouterProcList.Add(ARouterProc); + finally + FLock.EndWrite; + end; +end; + +procedure TRouter.AddRouterProc(const ARouterMethod: TCrossHttpRouterMethod); +begin + FLock.BeginWrite; + try + FRouterMethodList.Add(ARouterMethod); + finally + FLock.EndWrite; + end; +end; + +constructor TRouter.Create(const AMethodPattern: string); +begin + FMethodPattern := AMethodPattern; + FRouteType := GetPatternType(AMethodPattern); + + FRouterProcList := TList.Create; + FRouterMethodList := TList.Create; + FLock := TReadWriteLock.Create; +end; + +destructor TRouter.Destroy; +begin + FreeAndNil(FRouterProcList); + FreeAndNil(FRouterMethodList); + + inherited; +end; + +function TRouter.GetRouteType: TRouteType; +begin + Result := FRouteType; +end; + +function TRouter.GetMethodPattern: string; +begin + Result := FMethodPattern; +end; + +function TRouter.GetRegEx: IRegEx; +begin + Result := nil; + if (FRouteType = rtRegex) then + Result := CreateRouterRegEx(FMethodPattern); +end; + +procedure TRouter.Execute(const ARequest: ICrossHttpRequest; + const AResponse: ICrossHttpResponse; var AHandled: Boolean); +var + LRouterProcArr: TArray; + LRouterMethodArr: TArray; + LRouterProc: TCrossHttpRouterProc; + LRouterMethod: TCrossHttpRouterMethod; +begin + FLock.BeginRead; + try + LRouterProcArr := FRouterProcList.ToArray; + LRouterMethodArr := FRouterMethodList.ToArray; + finally + FLock.EndRead; + end; + + for LRouterProc in LRouterProcArr do + begin + if Assigned(LRouterProc) then + begin + LRouterProc(ARequest, AResponse, AHandled); + if AHandled or AResponse.Sent then Exit; + end; + end; + + for LRouterMethod in LRouterMethodArr do + begin + if Assigned(LRouterMethod) then + begin + LRouterMethod(ARequest, AResponse, AHandled); + if AHandled or AResponse.Sent then Exit; + end; + end; +end; + +{ TRouteSegment } + +constructor TRouteSegment.Create(const AOriginal, APattern: string; + const AParams: TArray; ARouteType: TRouteType); +begin + inherited Create; + FOriginal := AOriginal; + FPattern := APattern; + FParams := AParams; + FRouteType := ARouteType; +end; + +function TRouteSegment.RegexMatch(const ASegment: string; const ARequest: ICrossHttpRequest): Boolean; +var + I: Integer; + LRegEx: IRegEx; +begin + Result := False; + + case FRouteType of + rtRegex: + begin + LRegEx := CreateRouterRegEx(FPattern); + if LRegEx <> nil then + begin + LRegEx.Subject := ASegment; + Result := LRegEx.Match; + if Result and Assigned(ARequest) then + begin + // 提取所有参数值 + for I := 0 to High(FParams) do + ARequest.Params[FParams[I].Name] := LRegEx.Groups[I + 1]; + end; + end; + end; + end; +end; + +{ TRouteNode } + +constructor TRouteNode.Create(ARouteType: TRouteType; const ASegment: TRouteSegment); +begin + inherited Create; + + FRouteType := ARouteType; + FSegment := ASegment; + FStaticChildren := TObjectDictionary.Create([doOwnsValues]); + FRegexChildren := TObjectList.Create(True); + + FStaticRouteMethodItems := TDictionary.Create; + FRegexRouteMethodItems := TList.Create; +end; + +destructor TRouteNode.Destroy; +begin + FreeAndNil(FSegment); + FreeAndNil(FStaticChildren); + FreeAndNil(FRegexChildren); + FreeAndNil(FWildcardChild); + + FreeAndNil(FStaticRouteMethodItems); + FreeAndNil(FRegexRouteMethodItems); + FWildcardRouteMethodItem := nil; + + inherited; +end; + +function TRouteNode.CreateChildNode(const ASegment: TRouteSegment): TRouteNode; +begin + case ASegment.RouteType of + rtStatic: + begin + Result := TRouteNode.Create(rtStatic, ASegment); + FStaticChildren.Add(ASegment.Original.ToLower, Result); + end; + + rtRegex: + begin + Result := TRouteNode.Create(rtRegex, ASegment); + FRegexChildren.Add(Result); + end; + + rtWildcard: + begin + if FWildcardChild = nil then + FWildcardChild := TRouteNode.Create(rtWildcard, ASegment); + Result := FWildcardChild; + end; + else + Result := nil; + end; +end; + +procedure TRouteNode.AddRouter(const AMethodPattern: string; const ARouter: IRouter); +begin + case ARouter.RouteType of + rtStatic: + FStaticRouteMethodItems.AddOrSetValue(AMethodPattern.ToLower, ARouter); + + rtRegex: + FRegexRouteMethodItems.Add(ARouter); + + rtWildcard: + FWildcardRouteMethodItem := ARouter; + end; +end; + +function TRouteNode.GetChildNode(const ASegment: string; + const ARouteType: TRouteType; out ARouteNode: TRouteNode): Boolean; +var + LChild: TRouteNode; +begin + case ARouteType of + rtStatic: + begin + Result := FStaticChildren.TryGetValue(ASegment.ToLower, ARouteNode) + end; + + rtRegex: + begin + for LChild in FRegexChildren do + begin + if (LChild.Segment.Original = ASegment) then + begin + ARouteNode := LChild; + Exit(True); + end; + end; + + Result := False; + end; + + rtWildcard: + begin + ARouteNode := FWildcardChild; + Result := (ARouteNode <> nil); + end; + else + ARouteNode := nil; + Result := False; + end; +end; + +function TRouteNode.GetRouter(const AMethodPattern: string; + out ARouter: IRouter): Boolean; +var + I: Integer; + LRouter: IRouter; +begin + Result := False; + + // 先尝试从静态方法路由中查找 + if FStaticRouteMethodItems.TryGetValue(AMethodPattern.ToLower, ARouter) then + Exit(True); + + // 从正则方法路由中查找 + for I := 0 to FRegexRouteMethodItems.Count - 1 do + begin + LRouter := FRegexRouteMethodItems[I]; + if SameText(LRouter.MethodPattern, AMethodPattern) then + begin + ARouter := LRouter; + Exit(True); + end; + end; + + // 从通配符方法路由中查找 + if (FWildcardRouteMethodItem <> nil) and IsWildcard(AMethodPattern) then + begin + ARouter := FWildcardRouteMethodItem; + Exit(True); + end; +end; + +function TRouteNode.MatchRouter(const AMethod: string; + out ARouter: IRouter): Boolean; +var + LRouter: IRouter; + LRegEx: IRegEx; +begin + Result := False; + + // 优先从静态方法路由中查找 + if FStaticRouteMethodItems.TryGetValue(AMethod.ToLower, LRouter) then + begin + ARouter := LRouter; + Exit(True); + end; + + // 遍历所有正则方法路由项, 找到第一个匹配的 + for LRouter in FRegexRouteMethodItems do + begin + // 正则表达式方法使用局部匹配器, 避免并发请求共享匹配状态 + LRegEx := LRouter.RegEx; + if (LRegEx <> nil) then + begin + LRegEx.Subject := AMethod; + if LRegEx.Match then + begin + ARouter := LRouter; + Exit(True); + end; + end; + end; + + // 通配符 + if (FWildcardRouteMethodItem <> nil) then + begin + ARouter := FWildcardRouteMethodItem; + Exit(True); + end; +end; + +function TRouteNode.RemoveRouter(const AMethodPattern: string): Boolean; +var + LLowerMethod: string; + I: Integer; + LRouter: IRouter; +begin + Result := False; + + // 先尝试从静态方法路由中删除 + LLowerMethod := AMethodPattern.ToLower; + if FStaticRouteMethodItems.ContainsKey(LLowerMethod) then + begin + FStaticRouteMethodItems.Remove(LLowerMethod); + Exit(True); + end; + + // 从通配符方法路由删除 + if (FWildcardRouteMethodItem <> nil) and IsWildcard(AMethodPattern) then + begin + FWildcardRouteMethodItem := nil; + Exit(True); + end; + + // 遍历正则方法路由项, 删除匹配的路由 + for I := FRegexRouteMethodItems.Count - 1 downto 0 do + begin + LRouter := FRegexRouteMethodItems[I]; + if SameText(LRouter.MethodPattern, AMethodPattern) then + begin + FRegexRouteMethodItems.Delete(I); + Exit(True); + end; + end; +end; + +function TRouteNode.IsEmpty: Boolean; +begin + // 节点为空的条件: 没有子节点且没有路由处理函数 + Result := (FStaticChildren.Count = 0) and + (FRegexChildren.Count = 0) and + (FWildcardChild = nil) and + (FStaticRouteMethodItems.Count = 0) and + (FRegexRouteMethodItems.Count = 0) and + (FWildcardRouteMethodItem = nil); +end; + +{ TCrossHttpRouterTree } + +constructor TCrossHttpRouterTree.Create; +begin + inherited Create; + + FRoot := TRouteNode.Create(rtStatic, TRouteSegment.Create('', '', [], rtStatic)); + FLock := TReadWriteLock.Create; +end; + +destructor TCrossHttpRouterTree.Destroy; +begin + FreeAndNil(FRoot); + + inherited; +end; + +function TCrossHttpRouterTree.CreateSegment(const ASegment: string; + const ARouteType: TRouteType): TRouteSegment; +var + LPattern: string; + LParams: TArray; +begin + LPattern := ASegment; + LParams := []; + + // 正则段需要处理参数 + if (ARouteType = rtRegex) then + begin + LPattern := ASegment; + LParams := []; + // 使用正则表达式匹配所有参数模式 + // 匹配 :param 和 :param(pattern) 格式 + // 可以在参数后面增加正则限定参数 :number(\d+), :word(\w+) + LPattern := TRegEx.Replace(LPattern, ':(\w+)(?:\((.*?)\))?', + function(const AMatch: TMatch): string + var + LParamName, LParamPattern: string; + LParam: TRouteParam; + begin + if not AMatch.Success then Exit(''); + + if (AMatch.Groups.Count > 1) then + LParamName := AMatch.Groups[1].Value + else + LParamName := ''; + if (AMatch.Groups.Count > 2) then + LParamPattern := AMatch.Groups[2].Value + else + LParamPattern := ''; + + if (LParamPattern = '') or (LParamPattern = '*') then + LParamPattern := '.*'; + + Result := '(' + LParamPattern + ')'; + + LParam.Name := LParamName; + LParam.Pattern := LParamPattern; + LParams := LParams + [LParam]; + end); + end; + + Result := TRouteSegment.Create(ASegment, LPattern, LParams, ARouteType); +end; + +class function TCrossHttpRouterTree.ParsePath(const APath: string): TArray; +begin + // 请求的是根路径, 无需拆分 + if (APath = '/') or (APath = '') then + begin + Result := ['']; + Exit; + end; + + // 把请求路径按/拆分成多段 + Result := APath.Split(['/'], TStringSplitOptions.ExcludeEmpty); + if (Result = nil) then + Result := ['']; +end; + +procedure TCrossHttpRouterTree.AddRouter(const AMethodPattern, APathPattern: string; + const ARouter: IRouter); +var + LPathSegments: TArray; +begin + FLock.BeginWrite; + try + LPathSegments := ParsePath(APathPattern); + AddRouterToNode(FRoot, LPathSegments, 0, AMethodPattern, ARouter); + finally + FLock.EndWrite; + end; +end; + +procedure TCrossHttpRouterTree.AddRouter(const AMethodPattern, + APathPattern: string; const ARouterProc: TCrossHttpRouterProc); +var + LRouter: IRouter; +begin + LRouter := GetRouter(AMethodPattern, APathPattern); + LRouter.AddRouterProc(ARouterProc); +end; + +procedure TCrossHttpRouterTree.AddRouter(const AMethodPattern, + APathPattern: string; const ARouterMethod: TCrossHttpRouterMethod); +var + LRouter: IRouter; +begin + LRouter := GetRouter(AMethodPattern, APathPattern); + LRouter.AddRouterProc(ARouterMethod); +end; + +procedure TCrossHttpRouterTree.AddRouterToNode(ANode: TRouteNode; + const APathPatternSegments: TArray; AIndex: Integer; const AMethodPattern: string; + const ARouter: IRouter); +var + LSegmentPattern: string; + LRouteType: TRouteType; + LRouteSegment: TRouteSegment; + LChild: TRouteNode; +begin + if (AIndex > High(APathPatternSegments)) then + begin + // 到达路径末尾, 添加路由 + ANode.AddRouter(AMethodPattern, ARouter); + Exit; + end; + + LSegmentPattern := APathPatternSegments[AIndex]; + LRouteType := GetPatternType(LSegmentPattern); + + if not ANode.GetChildNode(LSegmentPattern, LRouteType, LChild) then + begin + LRouteSegment := CreateSegment(LSegmentPattern, LRouteType); + LChild := ANode.CreateChildNode(LRouteSegment); + end; + + AddRouterToNode(LChild, APathPatternSegments, AIndex + 1, AMethodPattern, ARouter); +end; + +function TCrossHttpRouterTree.GetRouter(const AMethodPattern, + APathPattern: string; out ARouter: IRouter): Boolean; +var + LPathSegments: TArray; +begin + FLock.BeginRead; + try + LPathSegments := ParsePath(APathPattern); + Result := GetRouterFromNode(FRoot, LPathSegments, 0, AMethodPattern, ARouter); + finally + FLock.EndRead; + end; +end; + +function TCrossHttpRouterTree.GetRouter(const AMethodPattern, + APathPattern: string): IRouter; +var + LPathSegments: TArray; +begin + FLock.BeginWrite; + try + LPathSegments := ParsePath(APathPattern); + if not GetRouterFromNode(FRoot, LPathSegments, 0, AMethodPattern, Result) then + begin + Result := TRouter.Create(AMethodPattern); + AddRouterToNode(FRoot, LPathSegments, 0, AMethodPattern, Result); + end; + finally + FLock.EndWrite; + end; +end; + +function TCrossHttpRouterTree.GetRouterFromNode(ANode: TRouteNode; + const APathPatternSegments: TArray; AIndex: Integer; + const AMethodPattern: string; out ARouter: IRouter): Boolean; +var + LSegmentPattern: string; + LRouteType: TRouteType; + LChild: TRouteNode; + LFound: Boolean; +begin + Result := False; + + if (AIndex > High(APathPatternSegments)) then + begin + // 到达路径末尾, 查找该节点的路由 + Result := ANode.GetRouter(AMethodPattern, ARouter); + Exit; + end; + + LSegmentPattern := APathPatternSegments[AIndex]; + LRouteType := GetPatternType(LSegmentPattern); + + case LRouteType of + rtStatic: + // 从静态子节点中查找路由 + if ANode.StaticChildren.TryGetValue(LSegmentPattern.ToLower, LChild) then + begin + LFound := GetRouterFromNode(LChild, APathPatternSegments, AIndex + 1, AMethodPattern, ARouter); + Result := Result or LFound; + end; + + rtRegex: + // 从正则子节点中查找路由 + for LChild in ANode.RegexChildren do + begin + if SameText(LChild.Segment.Original, LSegmentPattern) then + begin + LFound := GetRouterFromNode(LChild, APathPatternSegments, AIndex + 1, AMethodPattern, ARouter); + Result := Result or LFound; + if Result then Break; + end; + end; + + rtWildcard: + // 从通配符子节点查找路由 + if (ANode.WildcardChild <> nil) then + begin + LFound := ANode.WildcardChild.GetRouter(AMethodPattern, ARouter); + Result := Result or LFound; + end; + end; +end; + +function TCrossHttpRouterTree.GetWildcardValue( + const APathSegments: TArray; AIndex: Integer; + const AQueryText: string): string; +begin + Result := string.Join('/', APathSegments, AIndex, Length(APathSegments) - AIndex); + if (AQueryText <> '') then + Result := Result + '?' + AQueryText; +end; + +function TCrossHttpRouterTree.MatchRouterInNode(ANode: TRouteNode; + const APathSegments: TArray; AIndex: Integer; const AMethod: string; + const ARequest: ICrossHttpRequest; out ARouter: IRouter): Boolean; +var + LSegment, LWildcardValue: string; + LChild: TRouteNode; +begin + Result := False; + + if (AIndex > High(APathSegments)) then + begin + // 到达路径末尾, 查找匹配方法的路由 + Result := ANode.MatchRouter(AMethod, ARouter); + + // 尝试从通配符子节点查找路由 + if not Result and (ANode.WildcardChild <> nil) then + begin + Result := ANode.WildcardChild.MatchRouter(AMethod, ARouter); + if Result then + begin + LWildcardValue := GetWildcardValue(APathSegments, AIndex, ARequest.QueryText); + if Assigned(ARequest) then + ARequest.Params[WILDCARD_CHAR] := LWildcardValue; + end; + end; + + Exit; + end; + + LSegment := APathSegments[AIndex]; + + // 1. 首先尝试精确匹配静态节点 + if ANode.StaticChildren.TryGetValue(LSegment.ToLower, LChild) then + begin + Result := MatchRouterInNode(LChild, APathSegments, AIndex + 1, AMethod, + ARequest, ARouter); + if Result then Exit; + end; + + // 2. 尝试正则节点(支持多参数) + for LChild in ANode.RegexChildren do + begin + if LChild.Segment.RegexMatch(LSegment, ARequest) then + begin + // 普通正则节点, 继续递归匹配 + Result := MatchRouterInNode(LChild, APathSegments, AIndex + 1, AMethod, + ARequest, ARouter); + if Result then Exit; + end; + end; + + // 3. 最后尝试通配符子节点(优先级最低) + if (ANode.WildcardChild <> nil) then + begin + Result := ANode.WildcardChild.MatchRouter(AMethod, ARouter); + if Result then + begin + LWildcardValue := GetWildcardValue(APathSegments, AIndex, ARequest.QueryText); + if Assigned(ARequest) then + ARequest.Params[WILDCARD_CHAR] := LWildcardValue; + + Exit; + end; + end; +end; + +function TCrossHttpRouterTree.MatchRouter(const APathSegments: TArray; + const ARequest: ICrossHttpRequest; out ARouter: IRouter): Boolean; +begin + FLock.BeginRead; + try + if FRoot.IsEmpty then + begin + ARouter := nil; + Exit(False); + end; + + Result := MatchRouterInNode(FRoot, APathSegments, 0, ARequest.Method, ARequest, ARouter); + finally + FLock.EndRead; + end; +end; + +function TCrossHttpRouterTree.MatchRouter(const ARequest: ICrossHttpRequest; + out ARouter: IRouter): Boolean; +var + LPathSegments: TArray; +begin + LPathSegments := ParsePath(ARequest.Path); + Result := MatchRouter(LPathSegments, ARequest, ARouter); +end; + +function TCrossHttpRouterTree.RemoveRouterFromNode(ANode: TRouteNode; + const APathPatternSegments: TArray; AIndex: Integer; const AMethodPattern: string): Boolean; +var + LSegmentPattern, LLowerSegment: string; + LRouteType: TRouteType; + LChild: TRouteNode; + LRemoved: Boolean; + I: Integer; +begin + Result := False; + + if (AIndex > High(APathPatternSegments)) then + begin + // 到达路径末尾, 删除该节点的路由 + Result := ANode.RemoveRouter(AMethodPattern); + Exit; + end; + + LSegmentPattern := APathPatternSegments[AIndex]; + LRouteType := GetPatternType(LSegmentPattern); + LLowerSegment := LSegmentPattern.ToLower; + + case LRouteType of + rtStatic: + // 从静态子节点中删除路由 + if ANode.StaticChildren.TryGetValue(LLowerSegment, LChild) then + begin + LRemoved := RemoveRouterFromNode(LChild, APathPatternSegments, AIndex + 1, AMethodPattern); + + // 如果子节点变空, 删除它 + if LRemoved and LChild.IsEmpty then + ANode.StaticChildren.Remove(LLowerSegment); + + Result := Result or LRemoved; + end; + + rtRegex: + // 从正则子节点中删除路由(逆序遍历,避免在迭代中修改集合) + for I := ANode.RegexChildren.Count - 1 downto 0 do + begin + LChild := ANode.RegexChildren[I]; + if SameText(LChild.Segment.Original, LSegmentPattern) then + begin + LRemoved := RemoveRouterFromNode(LChild, APathPatternSegments, AIndex + 1, AMethodPattern); + + // 如果子节点变空, 删除它 + if LRemoved and LChild.IsEmpty then + ANode.RegexChildren.Delete(I); + + Result := Result or LRemoved; + if Result then Break; + end; + end; + + rtWildcard: + // 从通配符子节点删除路由 + if (ANode.WildcardChild <> nil) then + begin + LRemoved := ANode.WildcardChild.RemoveRouter(AMethodPattern); + + // 如果子节点变空, 删除它 + if LRemoved and ANode.WildcardChild.IsEmpty then + FreeAndNil(ANode.FWildcardChild); + + Result := Result or LRemoved; + end; + end; +end; + +procedure TCrossHttpRouterTree.RemoveRouter(const AMethodPattern, APathPattern: string); +var + LPathSegments: TArray; +begin + FLock.BeginWrite; + try + LPathSegments := ParsePath(APathPattern); + RemoveRouterFromNode(FRoot, LPathSegments, 0, AMethodPattern); + finally + FLock.EndWrite; + end; +end; + +procedure TCrossHttpRouterTree.Clear; +begin + FLock.BeginWrite; + try + FreeAndNil(FRoot); + FRoot := TRouteNode.Create(rtStatic, TRouteSegment.Create('', '', [], rtStatic)); + finally + FLock.EndWrite; + end; +end; + +{ TCrossHttpServer } + +function TCrossHttpServer.All(const APath: string; + const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; +begin + Result := Route('*', APath, ARouterProc); +end; + +function TCrossHttpServer.All(const APath: string; + const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; +begin + Result := Route('*', APath, ARouterMethod); +end; + +constructor TCrossHttpServer.Create(const AIoThreads: Integer; const ASsl: Boolean); +begin + inherited Create(AIoThreads, ASsl); + + FRouters := TCrossHttpRouterTree.Create; + FMiddlewares := TCrossHttpRouterTree.Create; + + Port := 80; + Addr := ''; + + FCompressible := True; + FMinCompressSize := MIN_COMPRESS_SIZE; + FMaxCompressRatio := DEFAULT_MAX_COMPRESS_RATIO; + FStoragePath := TCrossHttpUtils.CombinePath(TUtils.AppPath, 'temp', PathDelim) + PathDelim; + FSessionIDCookieName := SESSIONID_COOKIE_NAME; +end; + +function TCrossHttpServer.CreateConnection(const AOwner: TCrossSocketBase; + const AClientSocket: TSocket; const AConnectType: TConnectType; + const AHost: string; const AConnectCb: TCrossConnectionCallback): ICrossConnection; +begin + Result := TCrossHttpConnection.Create( + AOwner, + AClientSocket, + AConnectType, + AHost, + AConnectCb); +end; + +destructor TCrossHttpServer.Destroy; +begin + Stop; + + FreeAndNil(FRouters); + FreeAndNil(FMiddlewares); + + inherited Destroy; +end; + +function TCrossHttpServer.Dir(const APath, ALocalDir: string): ICrossHttpServer; +var + LReqPath: string; +begin + LReqPath := APath; + if not LReqPath.EndsWith('/') then + LReqPath := LReqPath + '/'; + LReqPath := LReqPath + '*'; + Result := Get(LReqPath, TNetCrossRouter.Dir(APath, ALocalDir, '*')); +end; + +function TCrossHttpServer.Delete(const APath: string; + const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; +begin + Result := Route('DELETE', APath, ARouterProc); +end; + +function TCrossHttpServer.Delete(const APath: string; + const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; +begin + Result := Route('DELETE', APath, ARouterMethod); +end; + +procedure TCrossHttpServer.DoOnRequestBegin( + const AConnection: ICrossHttpConnection; + const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse); +begin + if Assigned(FOnRequestBegin) then + FOnRequestBegin(Self, AConnection, ARequest, AResponse); +end; + +procedure TCrossHttpServer.DoOnRequestEnd( + const AConnection: ICrossHttpConnection; + const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse; + const ASuccess: Boolean); +begin + if Assigned(FOnRequestEnd) then + FOnRequestEnd(Self, AConnection, ARequest, AResponse, ASuccess); +end; + +procedure TCrossHttpServer.DoOnRequest(const AConnection: ICrossHttpConnection; + const ARequest: ICrossHttpRequest; const AResponse: ICrossHttpResponse); +var + LRequest: ICrossHttpRequest; + LResponse: ICrossHttpResponse; + LSessionID: string; + LPathSegments: TArray; + LHandled: Boolean; + LRouter: IRouter; +begin + // 显式接收来自 _OnParseSuccess 的 request/response, 不再读取连接字段, + // 避免与 _FinishQueueItem 等异步线程构成 race + LRequest := ARequest; + LResponse := AResponse; + LHandled := False; + + try + {$region 'Session'} + if (FSessions <> nil) and (FSessionIDCookieName <> '') then + begin + LSessionID := LRequest.Cookies[FSessionIDCookieName]; + (LRequest as TCrossHttpRequest).FSession := FSessions.Sessions[LSessionID]; + if (LRequest.Session <> nil) and (LRequest.Session.SessionID <> LSessionID) then + begin + LSessionID := LRequest.Session.SessionID; + LResponse.Cookies.AddOrSet(FSessionIDCookieName, LSessionID, 0); + end; + end; + {$endregion} + + // 提前拆分请求路径, 可以减少一次 ParsePath 调用 + LPathSegments := TCrossHttpRouterTree.ParsePath(LRequest.Path); + + {$region '中间件'} + // 执行匹配的中间件 + if FMiddlewares.MatchRouter(LPathSegments, LRequest, LRouter) then + begin + // 中间件通常用于请求的预处理 + // 所以默认将 LHandled 置为 False, 以保证后续路由能被执行 + // 除非用户在中间件中明确指定了 LHandled := True, 表明该请求无需后续路由响应了 + LHandled := False; + LRouter.Execute(LRequest, LResponse, LHandled); + + // 如果已经发送了数据, 则后续的事件和路由响应都不需要执行了 + if LHandled or LResponse.Sent then Exit; + end; + {$endregion} + + {$region '路由'} + // 执行匹配的路由 + if FRouters.MatchRouter(LPathSegments, LRequest, LRouter) then + begin + // 路由用于响应请求 + // 所以默认将 LHandled 置为 True, 以保证不会有多个匹配的路由被执行 + // 除非用户在路由中明确指定了 LHandled := False, 表明该路由并没有 + // 完成请求响应, 还需要后续路由继续进行响应 + LHandled := True; + LRouter.Execute(LRequest, LResponse, LHandled); + + // 如果已经发送了数据, 则后续的事件和路由响应都不需要执行了 + if LHandled or LResponse.Sent then Exit; + end; + {$endregion} + + {$region '响应请求事件'} + if Assigned(FOnRequest) + and not (LHandled or LResponse.Sent) then + begin + FOnRequest(Self, AConnection, LRequest, LResponse, LHandled); + + // 如果已经发送了数据, 则后续的事件和路由响应都不需要执行了 + if LHandled or LResponse.Sent then Exit; + end; + {$endregion} + + // 如果该请求没有被任何中间件、事件、路由响应, 返回 404 + if not (LHandled or LResponse.Sent) then + LResponse.SendStatus(404); + except + on e: Exception do + begin + if Assigned(FOnRequestException) then + FOnRequestException(Self, LRequest, LResponse, e) + else if LResponse.Sent then + AConnection.Disconnect + else if (e is ECrossHttpException) then + LResponse.SendStatus(ECrossHttpException(e).StatusCode, ECrossHttpException(e).Message) + else + LResponse.SendStatus(500, e.Message); + end; + end; +end; + +function TCrossHttpServer.Get(const APath: string; + const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; +begin + Result := Route('GET', APath, ARouterProc); +end; + +function TCrossHttpServer.Get(const APath: string; + const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; +begin + Result := Route('GET', APath, ARouterMethod); +end; + +function TCrossHttpServer.GetOnRequestEnd: TCrossHttpRequestEndEvent; +begin + Result := FOnRequestEnd; +end; + +function TCrossHttpServer.GetAutoDeleteFiles: Boolean; +begin + Result := FAutoDeleteFiles; +end; + +function TCrossHttpServer.GetOnRequestBegin: TCrossHttpRequestBeginEvent; +begin + Result := FOnRequestBegin; +end; + +function TCrossHttpServer.GetCompressible: Boolean; +begin + Result := FCompressible; +end; + +function TCrossHttpServer.GetMaxHeaderSize: Int64; +begin + Result := FMaxHeaderSize; +end; + +function TCrossHttpServer.GetMaxPostDataSize: Int64; +begin + Result := FMaxPostDataSize; +end; + +function TCrossHttpServer.GetMaxCompressRatio: Integer; +begin + Result := FMaxCompressRatio; +end; + +function TCrossHttpServer.GetMinCompressSize: Int64; +begin + Result := FMinCompressSize; +end; + +function TCrossHttpServer.GetOnRequest: TCrossHttpRequestEvent; +begin + Result := FOnRequest; +end; + +function TCrossHttpServer.GetOnRequestException: TCrossHttpRequestExceptionEvent; +begin + Result := FOnRequestException; +end; + +function TCrossHttpServer.GetSessionIDCookieName: string; +begin + Result := FSessionIDCookieName; +end; + +function TCrossHttpServer.GetSessions: ISessions; +begin + Result := FSessions; +end; + +function TCrossHttpServer.GetStoragePath: string; +begin + Result := FStoragePath; +end; + +procedure TCrossHttpServer.SetOnRequestEnd(const Value: TCrossHttpRequestEndEvent); +begin + FOnRequestEnd := Value; +end; + +procedure TCrossHttpServer.SetAutoDeleteFiles(const Value: Boolean); +begin + FAutoDeleteFiles := Value; +end; + +procedure TCrossHttpServer.SetOnRequestBegin(const Value: TCrossHttpRequestBeginEvent); +begin + FOnRequestBegin := Value; +end; + +procedure TCrossHttpServer.SetCompressible(const Value: Boolean); +begin + FCompressible := Value; +end; + +procedure TCrossHttpServer.SetMaxHeaderSize(const Value: Int64); +begin + FMaxHeaderSize := Value; +end; + +procedure TCrossHttpServer.SetMaxPostDataSize(const Value: Int64); +begin + FMaxPostDataSize := Value; +end; + +procedure TCrossHttpServer.SetMaxCompressRatio(const Value: Integer); +begin + FMaxCompressRatio := Value; +end; + +procedure TCrossHttpServer.SetMinCompressSize(const Value: Int64); +begin + FMinCompressSize := Value; +end; + +procedure TCrossHttpServer.SetOnRequest(const Value: TCrossHttpRequestEvent); +begin + FOnRequest := Value; +end; + +procedure TCrossHttpServer.SetOnRequestException( + const Value: TCrossHttpRequestExceptionEvent); +begin + FOnRequestException := Value; +end; + +procedure TCrossHttpServer.SetSessionIDCookieName(const Value: string); +begin + FSessionIDCookieName := Value; +end; + +procedure TCrossHttpServer.SetSessions(const Value: ISessions); +begin + FSessions := Value; +end; + +procedure TCrossHttpServer.SetStoragePath(const Value: string); +begin + FStoragePath := Value; +end; + +function TCrossHttpServer.Static(const APath, + ALocalStaticDir: string): ICrossHttpServer; +var + LReqPath: string; +begin + LReqPath := APath; + if not LReqPath.EndsWith('/') then + LReqPath := LReqPath + '/'; + LReqPath := LReqPath + '*'; + Result := Get(LReqPath, TNetCrossRouter.Static(ALocalStaticDir, '*')); +end; + +function TCrossHttpServer.Index(const APath, ALocalDir: string; + const ADefIndexFiles: TArray): ICrossHttpServer; +var + LReqPath: string; +begin + LReqPath := APath; + if not LReqPath.EndsWith('/') then + LReqPath := LReqPath + '/'; + LReqPath := LReqPath + '*'; + Result := Get(LReqPath, TNetCrossRouter.Index(ALocalDir, '*', ADefIndexFiles)); +end; + +function TCrossHttpServer.Post(const APath: string; + const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; +begin + Result := Route('POST', APath, ARouterProc); +end; + +function TCrossHttpServer.Post(const APath: string; + const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; +begin + Result := Route('POST', APath, ARouterMethod); +end; + +function TCrossHttpServer.Put(const APath: string; + const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; +begin + Result := Route('PUT', APath, ARouterMethod); +end; + +function TCrossHttpServer.Put(const APath: string; + const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; +begin + Result := Route('PUT', APath, ARouterProc); +end; + +function TCrossHttpServer.Route(const AMethod, APath: string; + const ARouterProc: TCrossHttpRouterProc): ICrossHttpServer; +begin + FRouters.AddRouter(AMethod, APath, ARouterProc); + Result := Self; +end; + +function TCrossHttpServer.Route(const AMethod, APath: string; + const ARouterMethod: TCrossHttpRouterMethod): ICrossHttpServer; +begin + FRouters.AddRouter(AMethod, APath, ARouterMethod); + Result := Self; +end; + +function TCrossHttpServer.RemoveMiddleware(const AMethod, + APath: string): ICrossHttpServer; +begin + FMiddlewares.RemoveRouter(AMethod, APath); + Result := Self; +end; + +function TCrossHttpServer.RemoveRouter(const AMethod, APath: string): ICrossHttpServer; +begin + FRouters.RemoveRouter(AMethod, APath); + Result := Self; +end; + +function TCrossHttpServer.ClearMiddlewares: ICrossHttpServer; +begin + FMiddlewares.Clear; + Result := Self; +end; + +function TCrossHttpServer.ClearRouters: ICrossHttpServer; +begin + FRouters.Clear; + Result := Self; +end; + +procedure TCrossHttpServer.LogicReceived(const AConnection: ICrossConnection; + const ABuf: Pointer; const ALen: Integer); +var + LConnObj: TCrossHttpConnection; + LBuf: Pointer; + LLen: Integer; +begin + LConnObj := AConnection as TCrossHttpConnection; + LBuf := ABuf; + LLen := ALen; + + while (LLen > 0) do + LConnObj.ParseRecvData(LBuf, LLen); + + inherited LogicReceived(AConnection, ABuf, ALen); +end; + +function TCrossHttpServer.Use( + const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; +begin + Result := Use('*', '*', AMiddlewareMethod); +end; + +function TCrossHttpServer.Use( + const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; +begin + Result := Use('*', '*', AMiddlewareProc); +end; + +function TCrossHttpServer.Use(const AMethod, APath: string; + const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; +begin + FMiddlewares.AddRouter(AMethod, APath, AMiddlewareMethod); + Result := Self; +end; + +function TCrossHttpServer.Use(const AMethod, APath: string; + const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; +begin + FMiddlewares.AddRouter(AMethod, APath, AMiddlewareProc); + Result := Self; +end; + +function TCrossHttpServer.Use(const APath: string; + const AMiddlewareMethod: TCrossHttpRouterMethod): ICrossHttpServer; +begin + Result := Use('*', APath, AMiddlewareMethod); +end; + +function TCrossHttpServer.Use(const APath: string; + const AMiddlewareProc: TCrossHttpRouterProc): ICrossHttpServer; +begin + Result := Use('*', APath, AMiddlewareProc); +end; + +{ TCrossHttpRequest } + +constructor TCrossHttpRequest.Create(const AConnection: TCrossHttpConnection); +begin + FConnectionObj := AConnection; + FConnection := AConnection; + FServer := FConnection.Owner as TCrossHttpServer; + + FHeader := THttpHeader.Create; + FCookies := TRequestCookies.Create; + FParams := THttpUrlParams.Create; + FQuery := THttpUrlParams.Create; +end; + +destructor TCrossHttpRequest.Destroy; +begin + FreeAndNil(FHeader); + FreeAndNil(FCookies); + FreeAndNil(FParams); + FreeAndNil(FQuery); + if (FBody = FRawBody) then + FBody := nil + else + FreeAndNil(FBody); + FreeAndNil(FRawBody); + + inherited; +end; + +function TCrossHttpRequest.GetAccept: string; +begin + Result := FAccept; +end; + +function TCrossHttpRequest.GetAcceptEncoding: string; +begin + Result := FAcceptEncoding; +end; + +function TCrossHttpRequest.GetAcceptLanguage: string; +begin + Result := FAcceptLanguage; +end; + +function TCrossHttpRequest.GetAuthorization: string; +begin + Result := FAuthorization; +end; + +function TCrossHttpRequest.GetBody: TObject; +begin + Result := FBody; +end; + +function TCrossHttpRequest.GetRawBody: TStream; +begin + Result := FRawBody; +end; + +function TCrossHttpRequest.GetBodyType: TBodyType; +begin + Result := FBodyType; +end; + +function TCrossHttpRequest.GetConnection: ICrossHttpConnection; +begin + Result := FConnection; +end; + +function TCrossHttpRequest.GetContentEncoding: string; +begin + Result := FContentEncoding; +end; + +function TCrossHttpRequest.GetContentLength: Int64; +begin + Result := FContentLength; +end; + +function TCrossHttpRequest.GetContentType: string; +begin + Result := FContentType; +end; + +function TCrossHttpRequest.GetCookies: TRequestCookies; +begin + Result := FCookies; +end; + +function TCrossHttpRequest.GetHeader: THttpHeader; +begin + Result := FHeader; +end; + +function TCrossHttpRequest.GetHostName: string; +begin + Result := FHostName; +end; + +function TCrossHttpRequest.GetHostPort: Word; +begin + Result := FHostPort; +end; + +function TCrossHttpRequest.GetIfModifiedSince: TDateTime; +begin + Result := FIfModifiedSince; +end; + +function TCrossHttpRequest.GetIfNoneMatch: string; +begin + Result := FIfNoneMatch; +end; + +function TCrossHttpRequest.GetIfRange: string; +begin + Result := FIfRange; +end; + +function TCrossHttpRequest.GetIsChunked: Boolean; +begin + Result := FIsChunked; +end; + +function TCrossHttpRequest.CalcIsChunked: Boolean; +var + LEncodings: TArray; +begin + // RFC 7230 §3.3.1: Transfer-Encoding 可以是逗号分隔列表, 最终编码为最后一个 + LEncodings := FTransferEncoding.Trim.Split([',']); + if Length(LEncodings) > 0 then + Result := TStrUtils.SameText(LEncodings[Length(LEncodings) - 1].Trim, 'chunked') + else + Result := False; +end; + +function TCrossHttpRequest.GetIsMultiPartFormData: Boolean; +begin + Result := TStrUtils.SameText(FContentType, TMediaType.MULTIPART_FORM_DATA); +end; + +function TCrossHttpRequest.GetIsUrlEncodedFormData: Boolean; +begin + Result := TStrUtils.SameText(FContentType, TMediaType.APPLICATION_FORM_URLENCODED_TYPE); +end; + +function TCrossHttpRequest.GetKeepAlive: Boolean; +begin + Result := FKeepAlive; +end; + +function TCrossHttpRequest.GetMethod: string; +begin + Result := FMethod; +end; + +function TCrossHttpRequest.GetParams: THttpUrlParams; +begin + Result := FParams; +end; + +function TCrossHttpRequest.GetQueryText: string; +begin + Result := FQueryText; +end; + +function TCrossHttpRequest.GetPath: string; +begin + Result := FPath; +end; + +function TCrossHttpRequest.GetPathAndQuery: string; +begin + Result := FPathAndQuery; +end; + +function TCrossHttpRequest.GetPostDataSize: Int64; +begin + Result := FPostDataSize; +end; + +function TCrossHttpRequest.GetQuery: THttpUrlParams; +begin + Result := FQuery; +end; + +function TCrossHttpRequest.GetRange: string; +begin + Result := FRange; +end; + +function TCrossHttpRequest.GetRawPathAndQuery: string; +begin + Result := FRawPathAndQuery; +end; + +function TCrossHttpRequest.GetRawRequestText: string; +begin + Result := FRawRequestText; +end; + +function TCrossHttpRequest.GetReferer: string; +begin + Result := FReferer; +end; + +function TCrossHttpRequest.GetRequestBoundary: string; +begin + Result := FRequestBoundary; +end; + +function TCrossHttpRequest.GetRequestCmdLine: string; +begin + Result := FRequestCmdLine; +end; + +function TCrossHttpRequest.GetRequestConnection: string; +begin + Result := FRequestConnection; +end; + +function TCrossHttpRequest.GetSession: ISession; +begin + Result := FSession; +end; + +function TCrossHttpRequest.GetTransferEncoding: string; +begin + Result := FTransferEncoding; +end; + +function TCrossHttpRequest.GetUserAgent: string; +begin + Result := FUserAgent; +end; + +function TCrossHttpRequest.GetVersion: string; +begin + Result := FVersion; +end; + +function TCrossHttpRequest.GetXForwardedFor: string; +begin + Result := FXForwardedFor; +end; + +function TCrossHttpRequest.ParseHeader(const ADataPtr: Pointer; + const ADataSize: Integer): Boolean; +var + LRequestHeader, LPortStr: string; + LCookieValues, LCLValues: TArray; + LFirstCL: string; + I, J: Integer; + LPortInt: Integer; +begin + Assert(Self <> nil, 'FRequest is nil'); + + // 整体包一层 try/except 保证任何畸形输入都以 Result := False 返回, + // 不会让异常上抛到 _OnHeaderData 环外. 常见调用点如: + // - Substring/IndexOf 上的越界 (请求行过短、缺少空格等) + // - LPortStr.ToInteger 遇到非数字时抛 EConvertError + // - THttpHeader.Decode 内部异常 + // - FCookies.Decode 内部异常 + // 都被这里统一归为 400 Bad Request + try + SetString(FRawRequestText, MarshaledAString(ADataPtr), ADataSize); + + // 拒绝包含 NUL 字节的请求 (可能导致跨编译器字符串行为差异) + if (FRawRequestText.IndexOf(#0) >= 0) then + Exit(False); + + I := FRawRequestText.IndexOf(#13#10); + // 第一行是请求命令行 + // GET /home?param=123 HTTP/1.1 + FRequestCmdLine := FRawRequestText.Substring(0, I); + // 第二行起是请求头 + LRequestHeader := FRawRequestText.Substring(I + 2); + // 解析请求头 + FHeader.Decode(LRequestHeader); + + // 请求行必须包含三段: METHOD SP PATH SP VERSION (RFC 7230 §3.1.1) + // 任何一段为空都不合法, 否则会出现: + // - FMethod=='' 导致路由匹配疑难 + // - FVersion 含错位片段 (如 "GET") 导致 _CreateHeader 输出伪 HTTP 状态行 + // 这里在拆分前先检查两个空格的位置严格递增, 三段均非空 + I := FRequestCmdLine.IndexOf(' '); + if (I <= 0) then Exit(False); + J := FRequestCmdLine.IndexOf(' ', I + 1); + if (J <= I + 1) or (J >= FRequestCmdLine.Length - 1) then Exit(False); + + // 请求方法(GET, POST, PUT, DELETE...) + FMethod := FRequestCmdLine.Substring(0, I).ToUpper; + + // 路径及参数(/home?param=123) + FRawPathAndQuery := FRequestCmdLine.Substring(I + 1, J - I - 1); + + // 请求的HTTP版本(HTTP/1.1) + FVersion := FRequestCmdLine.Substring(J + 1).ToUpper; + + // 解析?key1=value1&key2=value2参数 + J := FRawPathAndQuery.IndexOf('?'); + if (J < 0) then + begin + FRawPath := FRawPathAndQuery; + FRawQueryText := ''; + FQueryText := ''; + end else + begin + FRawPath := FRawPathAndQuery.Substring(0, J); + FRawQueryText := FRawPathAndQuery.Substring(J + 1); + FQueryText := TCrossHttpUtils.UrlDecode(FRawQueryText); + end; + + FPath := TCrossHttpUtils.UrlDecode(FRawPath); + FPathAndQuery := FPath; + if (FQueryText <> '') then + FPathAndQuery := FPathAndQuery + '?' + FQueryText; + + FQuery.Decode(FRawQueryText); + + // HTTP协议版本 + if (FVersion = '') then + FVersion := 'HTTP/1.0'; + if (FVersion = 'HTTP/1.0') then + FHttpVerNum := 10 + else + FHttpVerNum := 11; + FKeepAlive := (FHttpVerNum = 11); + + FContentType := FHeader[HEADER_CONTENT_TYPE]; + FRequestBoundary := ''; + J := FContentType.IndexOf(';'); + if (J >= 0) then + begin + // RFC 2046: 分号前后允许有任意空白, 兼容 "; boundary=" 和 ";boundary=" 两种格式 + FRequestBoundary := FContentType.Substring(J + 1).Trim; + if FRequestBoundary.StartsWith('boundary=', True) then + FRequestBoundary := FRequestBoundary.Substring(9); + + FContentType := FContentType.Substring(0, J).Trim; + end; + + // RFC 7230 §3.3.2: 多个 Content-Length 值不同时必须拒绝请求 + if FHeader.GetHeaderValues(HEADER_CONTENT_LENGTH, LCLValues) and (Length(LCLValues) > 0) then + begin + LFirstCL := LCLValues[0].Trim; + for I := 1 to High(LCLValues) do + if not TStrUtils.SameText(LCLValues[I].Trim, LFirstCL) then + Exit(False); + FContentLength := StrToInt64Def(LFirstCL, -1); + end else + FContentLength := -1; + + // IPv4: 192.168.1.100:8080 + // 192.168.1.100 + // IPv6: [fc00::20:80:5:2]:8080 + // [fc00::20:80:5:2] + FRequestHost := FHeader[HEADER_HOST]; + LPortStr := ''; + + J := FRequestHost.IndexOf(']'); + if (J >= 0) then + begin + FHostName := FRequestHost.Substring(1, J - 1); + J := FRequestHost.IndexOf(':', J); + if (J >= 0) then + LPortStr := FRequestHost.Substring(J + 1); + end else + begin + J := FRequestHost.IndexOf(':'); + if (J >= 0) then + begin + FHostName := FRequestHost.Substring(0, J); + LPortStr := FRequestHost.Substring(J + 1); + end else + FHostName := FRequestHost; + end; + // RFC 7230 §5.4: Host 头中 port 必须是十进制数字. 这里用 TryStrToInt + // 避免 ToInteger 在畸形输入 (如 "abc"、超出 Int32 范围) 时抛 EConvertError; + // 超出 Word (0..65535) 范围亦视为非法 port, 不静默截断高位 + if (LPortStr <> '') then + begin + if not TryStrToInt(LPortStr, LPortInt) + or (LPortInt < 0) or (LPortInt > High(Word)) then + Exit(False); + FHostPort := Word(LPortInt); + end else + FHostPort := GetConnection.Server.Port; + + FRequestConnection := FHeader[HEADER_CONNECTION]; + // HTTP/1.0 默认KeepAlive=False,只有显示指定了Connection: keep-alive才认为KeepAlive=True + // HTTP/1.1 默认KeepAlive=True,只有显示指定了Connection: close才认为KeepAlive=False + if FHttpVerNum = 10 then + FKeepAlive := TStrUtils.SameText(FRequestConnection, 'keep-alive') + else if TStrUtils.SameText(FRequestConnection, 'close') then + FKeepAlive := False; + + FTransferEncoding := FHeader[HEADER_TRANSFER_ENCODING]; + FIsChunked := CalcIsChunked; + FContentEncoding := FHeader[HEADER_CONTENT_ENCODING]; + FAccept := FHeader[HEADER_ACCEPT]; + FReferer := FHeader[HEADER_REFERER]; + FAcceptLanguage := FHeader[HEADER_ACCEPT_LANGUAGE]; + FAcceptEncoding := FHeader[HEADER_ACCEPT_ENCODING]; + FUserAgent := FHeader[HEADER_USER_AGENT]; + FAuthorization := FHeader[HEADER_AUTHORIZATION]; + // 获取并解析 Cookie 头 + // RFC 6265 建议客户端只发送一个 Cookie 头 + // 但部分代理/旧客户端可能拆分成多行,按 RFC 7230 §3.2.2 合并处理 + if FHeader.GetHeaderValues(HEADER_COOKIE, LCookieValues) + and (Length(LCookieValues) > 0) then + begin + // RFC 6265 建议客户端只发送一个 Cookie 头 + // 但部分代理/旧客户端可能拆分成多行,按 RFC 7230 §3.2.2 合并处理 + if (Length(LCookieValues) = 1) then + FRequestCookies := LCookieValues[0] + else + FRequestCookies := string.Join('; ', LCookieValues); + end else + FRequestCookies := ''; + FIfModifiedSince := TCrossHttpUtils.RFC1123_StrToDate(FHeader[HEADER_IF_MODIFIED_SINCE]); + FIfNoneMatch := FHeader[HEADER_IF_NONE_MATCH]; + FRange := FHeader[HEADER_RANGE]; + FIfRange := FHeader[HEADER_IF_RANGE]; + FXForwardedFor:= FHeader[HEADER_X_FORWARDED_FOR]; + + // 解析Cookies + if (FRequestCookies <> '') then + begin + if not FCookies.Decode(FRequestCookies, True) then Exit(False); + end else + FCookies.Clear; + + if IsMultiPartFormData then + FBodyType := btMultiPart + else if IsUrlEncodedFormData then + FBodyType := btUrlEncoded + else + FBodyType := btBinary; + + Result := True; + except + // 任何解析异常都归一为 Result := False, 由 _OnHeaderData 发 400. + // 不记详细错误原因 (不足类型安全且可能被恶意请求刷日志), + // 需要调试时可临时加 Logger 输出. + on Exception do + Result := False; + end; +end; + +{ TCrossHttpResponse } + +constructor TCrossHttpResponse.Create(const AConnection: TCrossHttpConnection; + const ARequest: ICrossHttpRequest; + const AQueueItem: IHttpResponseQueueItem); +begin + FConnectionObj := AConnection; + FConnection := AConnection; + FRequest := ARequest; + FQueueItem := AQueueItem; + FHeader := THttpHeader.Create; + FCookies := TResponseCookies.Create; + FStatusCode := 200; +end; + +destructor TCrossHttpResponse.Destroy; +begin + FreeAndNil(FHeader); + FreeAndNil(FCookies); + FQueueItem := nil; + inherited; +end; + +procedure TCrossHttpResponse.Download(const AFileName: string; + const ACallback: TCrossConnectionCallback); +begin + Attachment(AFileName); + SendFile(AFileName, ACallback); +end; + +function TCrossHttpResponse.GetConnection: ICrossHttpConnection; +begin + Result := FConnection; +end; + +function TCrossHttpResponse.GetContentType: string; +begin + Result := FHeader[HEADER_CONTENT_TYPE]; +end; + +function TCrossHttpResponse.GetCookies: TResponseCookies; +begin + Result := FCookies; +end; + +function TCrossHttpResponse.GetHeader: THttpHeader; +begin + Result := FHeader; +end; + +function TCrossHttpResponse.GetLocation: string; +begin + Result := FHeader[HEADER_LOCATION]; +end; + +function TCrossHttpResponse.GetRequest: ICrossHttpRequest; +begin + Result := FRequest; +end; + +function TCrossHttpResponse.GetSent: Boolean; +begin + Result := (AtomicCmpExchange(FSendStatus, 0, 0) > 0); +end; + +function TCrossHttpResponse.GetStatusCode: Integer; +begin + Result := FStatusCode; +end; + +function TCrossHttpResponse.GetStatusText: string; +begin + Result := FStatusText; +end; + +procedure TCrossHttpResponse.Json(const AJson: string; + const ACallback: TCrossConnectionCallback); +begin + SetContentType(TMediaType.APPLICATION_JSON_UTF8); + Send(AJson, ACallback); +end; + +procedure TCrossHttpResponse.Redirect(const AUrl: string; const ACallback: TCrossConnectionCallback); +begin + SetLocation(AUrl); + SendStatus(302, '', ACallback); +end; + +procedure TCrossHttpResponse.Reset; +begin + FSendStatus := 0; + FStatusCode := 200; + FHeader.Clear; + FCookies.Clear; +end; + +procedure TCrossHttpResponse.Attachment(const AFileName: string); +begin + if (GetContentType = '') then + SetContentType(TCrossHttpUtils.GetFileMIMEType(AFileName)); + FHeader[HEADER_CONTENT_DISPOSITION] := 'attachment; filename="' + + TCrossHttpUtils.UrlEncode(ExtractFileName(AFileName)) + '"'; +end; + +procedure TCrossHttpResponse.Send(const ABody: Pointer; const ACount: NativeInt; + const ACallback: TCrossConnectionCallback); +var + LCompressType: TCompressType; +begin + if _CheckCompress(ACount, LCompressType) then + SendZCompress(ABody, ACount, LCompressType, ACallback) + else + SendNoCompress(ABody, ACount, ACallback); +end; + +procedure TCrossHttpResponse.Send(const ABody; const ACount: NativeInt; + const ACallback: TCrossConnectionCallback); +begin + Send(@ABody, ACount, ACallback); +end; + +procedure TCrossHttpResponse.Send(const ABody: TBytes; + const AOffset, ACount: NativeInt; const ACallback: TCrossConnectionCallback); +var + LBody: TBytes; + LOffset, LCount: NativeInt; +begin + // 增加其引用计数 + LBody := ABody; + + LOffset := AOffset; + LCount := ACount; + TCrossHttpUtils.AdjustOffsetCount(Length(ABody), LOffset, LCount); + + Send(Pointer(PByte(LBody) + LOffset), LCount, + // CALLBACK + procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) + begin + // 减少引用计数 + LBody := nil; + + if Assigned(ACallback) then + ACallback(AConnection, ASuccess); + end); +end; + +procedure TCrossHttpResponse.Send(const ABody: TBytes; + const ACallback: TCrossConnectionCallback); +begin + Send(ABody, 0, Length(ABody), ACallback); +end; + +procedure TCrossHttpResponse.Send(const ABody: TStream; + const AOffset, ACount: Int64; const ACallback: TCrossConnectionCallback); +var + LCompressType: TCompressType; +begin + if (ABody <> nil) and _CheckCompress(ABody.Size, LCompressType) then + SendZCompress(ABody, AOffset, ACount, LCompressType, ACallback) + else + SendNoCompress(ABody, AOffset, ACount, ACallback); +end; + +procedure TCrossHttpResponse.Send(const ABody: TStream; + const ACallback: TCrossConnectionCallback); +begin + Send(ABody, 0, 0, ACallback); +end; + +procedure TCrossHttpResponse.Send(const ABody: string; + const ACallback: TCrossConnectionCallback); +var + LBody: TBytes; +begin + LBody := TEncoding.UTF8.GetBytes(ABody); + if (GetContentType = '') then + SetContentType(TMediaType.TEXT_HTML_UTF8); + + Send(LBody, ACallback); +end; + +procedure TCrossHttpResponse.SendNoCompress( + const AChunkSource: TCrossHttpChunkDataFunc; + const ACallback: TCrossConnectionCallback); +{ +HTTP头\r\n\r\n +块尺寸\r\n +块内容 +\r\n块尺寸\r\n +块内容 +\r\n0\r\n\r\n +} +type + TChunkState = (csHead, csBody, csDone); +const + CHUNK_END: array [0..6] of Byte = (13, 10, 48, 13, 10, 13, 10); // \r\n0\r\n\r\n +var + LHeaderBytes, LChunkHeader: TBytes; + LChunked, LIsFirstChunk: Boolean; + LChunkState: TChunkState; + LChunkData: Pointer; + LChunkSize: NativeInt; +begin + // 先取出第一个数据块 + // 如果有数据才需要使用 chunked 方式发送数据 + if Assigned(AChunkSource) then + begin + LChunked := AChunkSource(@LChunkData, @LChunkSize) + and (LChunkData <> nil) + and (LChunkSize > 0); + end else + LChunked := False; + + LIsFirstChunk := True; + LChunkState := csHead; + + _Send( + // HEADER + function(const AData: PPointer; const ADataSize: PNativeInt): Boolean + begin + LHeaderBytes := _CreateHeader(0, LChunked); + + AData^ := @LHeaderBytes[0]; + ADataSize^ := Length(LHeaderBytes); + + Result := (ADataSize^ > 0); + end, + // BODY + function(const AData: PPointer; const ADataSize: PNativeInt): Boolean + begin + if not LChunked then Exit(False); + + case LChunkState of + csHead: + begin + if LIsFirstChunk then + begin + LIsFirstChunk := False; + LChunkHeader := []; + end else + begin + LChunkData := nil; + LChunkSize := 0; + if not Assigned(AChunkSource) + or not AChunkSource(@LChunkData, @LChunkSize) + or (LChunkData = nil) + or (LChunkSize <= 0) then + begin + LChunkState := csDone; + + AData^ := @CHUNK_END[0]; + ADataSize^ := Length(CHUNK_END); + + Result := (ADataSize^ > 0); + + Exit; + end; + + LChunkHeader := [13, 10]; + end; + + // FPC编译器在Linux下有BUG(FPC 3.3.1) + // 无法将函数返回的字节数组直接与其它字节数组使用加号拼接 + // 实际上使用加号拼接字节数组还有其它各种异常 + // 所以改用我的TArrayUtils.Concat进行拼接 + LChunkHeader := TArrayUtils.Concat([ + LChunkHeader, + TEncoding.ASCII.GetBytes(IntToHex(LChunkSize, 0)), + [13, 10] + ]); + + LChunkState := csBody; + + AData^ := @LChunkHeader[0]; + ADataSize^ := Length(LChunkHeader); + + Result := (ADataSize^ > 0); + end; + + csBody: + begin + LChunkState := csHead; + + AData^ := LChunkData; + ADataSize^ := LChunkSize; + + Result := (ADataSize^ > 0); + end; + + csDone: + begin + Result := False; + end; + else + Result := False; + end; + end, + // CALLBACK + procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) + begin + LHeaderBytes := nil; + LChunkHeader := nil; + + if Assigned(ACallback) then + ACallback(AConnection, ASuccess); + end); +end; + +procedure TCrossHttpResponse.SendFile(const AFileName: string; + const ACallback: TCrossConnectionCallback); +var + LStream: TStream; + LLastModified: TDateTime; + LRequest: TCrossHttpRequest; + LLastModifiedStr, LETag: string; + LRangeStr: string; + LRangeBegin, LRangeEnd, LOffset, LCount, LFileSize: Int64; +begin + if not FileExists(AFileName) then + begin + FHeader.Remove(HEADER_CONTENT_DISPOSITION); + SendStatus(404, ACallback); + Exit; + end; + + if (GetContentType = '') then + SetContentType(TCrossHttpUtils.GetFileMIMEType(AFileName)); + + try + // 根据请求头中的时间戳决定是否需要发送文件数据 + // 当请求头中的时间戳与文件时间一致时, 浏览器会自动从本地加载文件数据 + // 服务端无需发送文件数据 + LRequest := GetRequest as TCrossHttpRequest; + LLastModified := TFileUtils.GetLastWriteTime(AFileName); + + if (LRequest.IfModifiedSince > 0) and (LRequest.IfModifiedSince >= (LLastModified - (1 / SecsPerDay))) then + begin + // 304不要带任何body数据, 否则部分浏览器会报告无效的RESPONSE + SendStatus(304, '', ACallback); + Exit; + end; + + LLastModifiedStr := TCrossHttpUtils.RFC1123_DateToStr(LLastModified); + + LETag := '"' + TUtils.BytesToHex(THashMD5.GetHashBytes( + ExtractFileName(AFileName) + LLastModifiedStr)) + '"'; + if (LRequest.IfNoneMatch = LETag) then + begin + // 304不要带任何body数据, 否则部分浏览器会报告无效的RESPONSE + SendStatus(304, '', ACallback); + Exit; + end; + + LStream := TFileUtils.OpenRead(AFileName, fmShareDenyNone); + except + on e: Exception do + begin + FHeader.Remove(HEADER_CONTENT_DISPOSITION); + SendStatus(404, TStrUtils.Format('%s, %s', [e.ClassName, e.Message]), ACallback); + Exit; + end; + end; + + LFileSize := LStream.Size; + + // 在响应头中加入文件时间戳 + // 浏览器会根据该时间戳决定是否从本地缓存中直接加载数据 + FHeader[HEADER_LAST_MODIFIED] := LLastModifiedStr; + FHeader[HEADER_ETAG] := LETag; + + // 告诉浏览器支持分块传输 + FHeader[HEADER_ACCEPT_RANGES] := 'bytes'; + + // Range 请求处理 (RFC 7233 §3.1) + // 仅当 Range 头存在且 If-Range 校验通过 (无 If-Range 或 If-Range == ETag) 时才走分块逻辑. + // If-Range 不匹配时, RFC 7233 §3.2 要求回退为完整 200 响应. + LRangeStr := LRequest.Range; + if (LRangeStr <> '') + and ((LRequest.IfRange = '') or (LRequest.IfRange = LETag)) then + begin + if not TCrossHttpUtils.ParseSingleByteRange(LRangeStr, LFileSize, LRangeBegin, LRangeEnd) then + begin + // 不可满足的 Range -> 416 Range Not Satisfiable (RFC 7233 §4.4) + // 必须返回 Content-Range: bytes */ 告知客户端实际资源大小. + FreeAndNil(LStream); + FHeader.Remove(HEADER_CONTENT_DISPOSITION); + FHeader[HEADER_CONTENT_RANGE] := TStrUtils.Format('bytes */%d', [LFileSize]); + SendStatus(416, ACallback); + Exit; + end; + + LOffset := LRangeBegin; + LCount := LRangeEnd - LRangeBegin + 1; + + // 返回分块信息 + // Content-Range: bytes -/ + FHeader[HEADER_CONTENT_RANGE] := TStrUtils.Format('bytes %d-%d/%d', + [LRangeBegin, LRangeEnd, LFileSize]); + + // 断点续传需要返回206状态码, 而不是200 + FStatusCode := 206; + end else + begin + LOffset := 0; + LCount := LFileSize; + end; + + // 206 Range 响应禁止压缩:Content-Range 描述的是原始字节偏移, + // 压缩后字节与范围不对应,会导致断点续传客户端数据错乱 (RFC 7233) + SendNoCompress(LStream, LOffset, LCount, + procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) + begin + FreeAndNil(LStream); + + if Assigned(ACallback) then + ACallback(AConnection, ASuccess); + end); +end; + +procedure TCrossHttpResponse.SetContentType(const Value: string); +begin + FHeader[HEADER_CONTENT_TYPE] := Value; +end; + +procedure TCrossHttpResponse.SetLocation(const Value: string); +begin + FHeader[HEADER_LOCATION] := Value; +end; + +procedure TCrossHttpResponse.SetStatusCode(Value: Integer); +begin + FStatusCode := Value; +end; + +procedure TCrossHttpResponse.SetStatusText(const Value: string); +begin + FStatusText := Value; +end; + +function TCrossHttpResponse._CheckCompress(const ABodySize: Int64; + out ACompressType: TCompressType): Boolean; +var + LContType, LRequestAcceptEncoding, LEnc, LQPart: string; + LServer: ICrossHttpServer; + LEncodings: TArray; + I, LQSep: Integer; + LGzipQ, LDeflateQ, LBestQ: Double; +begin + LContType := GetContentType; + LServer := GetConnection.Server; + + if Assigned(LServer) + and LServer.Compressible + and (ABodySize > 0) + and ((LServer.MinCompressSize <= 0) or (ABodySize >= LServer.MinCompressSize)) + and ((Pos('text/', LContType.ToLower) > 0) + or (Pos('application/json', LContType.ToLower) > 0) + or (Pos('javascript', LContType.ToLower) > 0) + or (Pos('xml', LContType.ToLower) > 0) + ) then + begin + LRequestAcceptEncoding := GetRequest.AcceptEncoding; + + // 按 q-value 排序选最优编码 (RFC 7231 §5.3.4). + // q 值越高优先级越高, 缺省 q=1.0; q=0 表示明确拒绝. + LEncodings := LRequestAcceptEncoding.Split([',']); + begin + LGzipQ := 0; + LDeflateQ := 0; + for I := 0 to High(LEncodings) do + begin + LEnc := LEncodings[I].Trim; + LQSep := LEnc.IndexOf(';'); + LBestQ := 1.0; + if LQSep >= 0 then + begin + LQPart := LEnc.Substring(LQSep + 1).Trim.ToLower; + LEnc := LEnc.Substring(0, LQSep).Trim; + if LQPart.StartsWith('q=') then + LBestQ := StrToFloatDef(Copy(LQPart, 3, MaxInt), 0); + if LBestQ <= 0 then + Continue; + end; + if TStrUtils.SameText(LEnc, 'gzip') and (LBestQ > LGzipQ) then + LGzipQ := LBestQ + else if TStrUtils.SameText(LEnc, 'deflate') and (LBestQ > LDeflateQ) then + LDeflateQ := LBestQ; + end; + // 优先 gzip (服务器普遍偏好); 仅当 deflate q 严格更高时选 deflate + if (LGzipQ > 0) and (LGzipQ >= LDeflateQ) then + begin + ACompressType := ctGZip; + Exit(True); + end; + if LDeflateQ > 0 then + begin + ACompressType := ctDeflate; + Exit(True); + end; + end; + end; + + ACompressType := ctNone; + Result := False; +end; + +function TCrossHttpResponse._GetMemoryStreamPointer(const AStream: TStream; + const AOffset, ACount: Int64; out P: PByte; out LSize: Int64): Boolean; +begin + if (AStream is TCustomMemoryStream) then + begin + P := PByte(TCustomMemoryStream(AStream).Memory) + AOffset; + LSize := ACount; + Exit(True); + end; + Result := False; +end; + +function TCrossHttpResponse._CreateHeader(const ABodySize: Int64; + AChunked: Boolean): TBytes; +var + LHeaderStr, LStatusText, LHttpVersion: string; + LCookie: TResponseCookie; +begin + if (GetContentType = '') then + SetContentType(TMediaType.APPLICATION_OCTET_STREAM); + if (FHeader[HEADER_CONNECTION] = '') then + begin + if (FStatusCode >= 400) or (not FRequest.KeepAlive) then + FHeader[HEADER_CONNECTION] := 'close' + else + FHeader[HEADER_CONNECTION] := 'keep-alive'; + end; + + if (FStatusCode = 204) or (FStatusCode = 304) then + begin + FHeader.Remove(HEADER_CONTENT_LENGTH); + FHeader.Remove(HEADER_TRANSFER_ENCODING); + end + else if AChunked then + begin + FHeader[HEADER_TRANSFER_ENCODING] := 'chunked'; + FHeader.Remove(HEADER_CONTENT_LENGTH); + end else + begin + FHeader[HEADER_CONTENT_LENGTH] := ABodySize.ToString; + FHeader.Remove(HEADER_TRANSFER_ENCODING); + end; + + if (FHeader[HEADER_CROSS_HTTP_SERVER] = '') then + FHeader[HEADER_CROSS_HTTP_SERVER] := CROSS_HTTP_SERVER_NAME; + + if (FStatusText <> '') then + begin + if TCrossHttpUtils.IsValidHeaderValue(FStatusText) then + LStatusText := FStatusText + else + begin + _Log('_CreateHeader: FStatusText contains invalid chars, falling back to default'); + LStatusText := TCrossHttpUtils.GetHttpStatusText(FStatusCode); + end; + end else + LStatusText := TCrossHttpUtils.GetHttpStatusText(FStatusCode); + + // Parser 在 psHeader 阶段早失败时, ParseHeader 尚未运行, FRequest.Version 为空. + // 必须回退到 'HTTP/1.1', 否则状态行成 ' 400 Bad Request' (缺版本前缀, 客户端无法识别). + LHttpVersion := FRequest.Version; + if (LHttpVersion = '') then + LHttpVersion := 'HTTP/1.1'; + LHeaderStr := LHttpVersion + ' ' + FStatusCode.ToString + ' ' + + LStatusText + #13#10; + + for LCookie in FCookies do + begin + try + LHeaderStr := LHeaderStr + HEADER_SETCOOKIE + ': ' + LCookie.Encode + #13#10; + except + on E: Exception do + begin + _Log('TCrossHttpResponse._CreateHeader: skip invalid cookie: %s', [E.Message]); + Continue; + end; + end; + end; + + LHeaderStr := LHeaderStr + FHeader.Encode; + + Result := TEncoding.ASCII.GetBytes(LHeaderStr); +end; + +procedure TCrossHttpResponse._Send(const ASource: TCrossHttpChunkDataFunc; + const ACallback: TCrossConnectionCallback); +begin + // 用 AtomicCmpExchange 抢首次发送权限: 如果已有 Send 调用, 直接拒绝. + // 防止两个 Send 之间的 Source/Callback 覆盖导致第一个 callback 永远不触发. + if AtomicCmpExchange(FSendStatus, 1, 0) <> 0 then + begin + if Assigned(ACallback) then + ACallback(FConnection, False); + Exit; + end; + + if (FConnectionObj = nil) or (FQueueItem = nil) then + begin + if Assigned(ACallback) then + ACallback(FConnection, False); + Exit; + end; + + FConnectionObj._QueueResponseReady(FQueueItem, ASource, ACallback); +end; + +procedure TCrossHttpResponse._Send(const AHeaderSource, + ABodySource: TCrossHttpChunkDataFunc; + const ACallback: TCrossConnectionCallback); +var + LHeaderDone: Boolean; +begin + // HEAD 请求不应包含响应体 (RFC 7231 §4.3.2) + if (FRequest.Method = 'HEAD') then + begin + _Send(AHeaderSource, ACallback); + Exit; + end; + + LHeaderDone := False; + + _Send( + function(const AData: PPointer; const ACount: PNativeInt): Boolean + begin + if not LHeaderDone then + begin + LHeaderDone := True; + Result := Assigned(AHeaderSource) and AHeaderSource(AData, ACount); + end else + begin + Result := Assigned(ABodySource) and ABodySource(AData, ACount); + end; + end, + ACallback); +end; + +procedure TCrossHttpResponse.SendNoCompress(const ABody: Pointer; + const ACount: NativeInt; const ACallback: TCrossConnectionCallback); +{ +HTTP头\r\n\r\n +内容 +} +var + P: PByte; + LSize: NativeInt; + LHeaderBytes: TBytes; +begin + P := ABody; + LSize := ACount; + + _Send( + // HEADER + function(const AData: PPointer; const ACount: PNativeInt): Boolean + begin + LHeaderBytes := _CreateHeader(LSize, False); + + AData^ := @LHeaderBytes[0]; + ACount^ := Length(LHeaderBytes); + + Result := (ACount^ > 0); + end, + // BODY + function(const AData: PPointer; const ACount: PNativeInt): Boolean + begin + AData^ := P; + ACount^ := Min(LSize, SND_BUF_SIZE); + Result := (ACount^ > 0); + + if (LSize > SND_BUF_SIZE) then + begin + Inc(P, SND_BUF_SIZE); + Dec(LSize, SND_BUF_SIZE); + end else + begin + LSize := 0; + P := nil; + end; + end, + // CALLBACK + procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) + begin + LHeaderBytes := nil; + + if Assigned(ACallback) then + ACallback(AConnection, ASuccess); + end); +end; + +procedure TCrossHttpResponse.SendNoCompress(const ABody; const ACount: NativeInt; + const ACallback: TCrossConnectionCallback); +begin + SendNoCompress(@ABody, ACount, ACallback); +end; + +procedure TCrossHttpResponse.SendNoCompress(const ABody: TBytes; + const AOffset, ACount: NativeInt; const ACallback: TCrossConnectionCallback); +var + LBody: TBytes; + LOffset, LCount: NativeInt; +begin + // 增加其引用计数 + LBody := ABody; + + LOffset := AOffset; + LCount := ACount; + TCrossHttpUtils.AdjustOffsetCount(Length(ABody), LOffset, LCount); + + SendNoCompress(Pointer(PByte(LBody) + LOffset), LCount, + // CALLBACK + procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) + begin + // 减少引用计数 + LBody := nil; + + if Assigned(ACallback) then + ACallback(AConnection, ASuccess); + end); +end; + +procedure TCrossHttpResponse.SendNoCompress(const ABody: TBytes; + const ACallback: TCrossConnectionCallback); +begin + SendNoCompress(ABody, 0, Length(ABody), ACallback); +end; + +procedure TCrossHttpResponse.SendNoCompress(const ABody: TStream; + const AOffset, ACount: Int64; const ACallback: TCrossConnectionCallback); +var + LOffset, LCount: Int64; + LBody: TStream; + LHeaderBytes, LBuffer: TBytes; + LP: PByte; + LSize: Int64; +begin + if (ABody = nil) then + begin + SendNoCompress(nil, 0, ACallback); + Exit; + end; + + LOffset := AOffset; + LCount := ACount; + TCrossHttpUtils.AdjustOffsetCount(ABody.Size, LOffset, LCount); + + if _GetMemoryStreamPointer(ABody, LOffset, LCount, LP, LSize) then + begin + SendNoCompress(LP^, LSize, ACallback); + Exit; + end; + + LBody := ABody; + LBody.Position := LOffset; + + SetLength(LBuffer, SND_BUF_SIZE); + + _Send( + // HEADER + function(const AData: PPointer; const ACount: PNativeInt): Boolean + begin + LHeaderBytes := _CreateHeader(LCount, False); + + AData^ := @LHeaderBytes[0]; + ACount^ := Length(LHeaderBytes); + + Result := (ACount^ > 0); + end, + // BODY + function(const AData: PPointer; const ACount: PNativeInt): Boolean + begin + if (LCount <= 0) then Exit(False); + + AData^ := @LBuffer[0]; + ACount^ := LBody.Read(LBuffer[0], Min(LCount, SND_BUF_SIZE)); + + Result := (ACount^ > 0); + + if Result then + Dec(LCount, ACount^); + end, + // CALLBACK + procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) + begin + LHeaderBytes := nil; + LBuffer := nil; + + if Assigned(ACallback) then + ACallback(AConnection, ASuccess); + end); +end; + +procedure TCrossHttpResponse.SendNoCompress(const ABody: TStream; + const ACallback: TCrossConnectionCallback); +begin + SendNoCompress(ABody, 0, 0, ACallback); +end; + +procedure TCrossHttpResponse.SendNoCompress(const ABody: string; + const ACallback: TCrossConnectionCallback); +var + LBody: TBytes; +begin + LBody := TEncoding.UTF8.GetBytes(ABody); + if (GetContentType = '') then + SetContentType(TMediaType.TEXT_HTML_UTF8); + + SendNoCompress(LBody, ACallback); +end; + +procedure TCrossHttpResponse.SendStatus(const AStatusCode: Integer; + const ADescription: string; const ACallback: TCrossConnectionCallback); +begin + SetStatusCode(AStatusCode); + Send(ADescription, ACallback); +end; + +procedure TCrossHttpResponse.SendStatus(const AStatusCode: Integer; + const ACallback: TCrossConnectionCallback); +begin + SendStatus(AStatusCode, TCrossHttpUtils.GetHttpStatusText(AStatusCode), ACallback); +end; + +procedure TCrossHttpResponse.SendZCompress( + const AChunkSource: TCrossHttpChunkDataFunc; + const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback); +{ + 本方法实现了一边压缩一边发送数据, 所以可以支持无限大的分块数据的压缩发送, + 而不用占用太多的内存和CPU + + zlib参考手册: http://www.zlib.net/zlib_how.html +} +var + LZStream: TZStreamRec; + LZFlush: Integer; + LZResult: Integer; + LOutSize: Integer; + LBuffer: TBytes; + LZError: Boolean; +begin + if (ACompressType = ctNone) then + begin + SendNoCompress(AChunkSource, ACallback); + Exit; + end; + + // 返回压缩方式 + FHeader[HEADER_CONTENT_ENCODING] := ZLIB_CONTENT_ENCODING[ACompressType]; + + // 明确告知缓存服务器按照 Accept-Encoding 字段的内容, 分别缓存不同的版本 + FHeader[HEADER_VARY] := HEADER_ACCEPT_ENCODING; + + SetLength(LBuffer, SND_BUF_SIZE); + + FillChar(LZStream, SizeOf(TZStreamRec), 0); + LZResult := Z_OK; + LZFlush := Z_NO_FLUSH; + + if (deflateInit2(LZStream, Z_DEFAULT_COMPRESSION, + Z_DEFLATED, ZLIB_WINDOW_BITS[ACompressType], 8, Z_DEFAULT_STRATEGY) <> Z_OK) then + begin + SetStatusCode(500); + if (FQueueItem <> nil) then + FQueueItem.StatusCode := 500; + // 走正常队列流程: _Send → _QueueResponseReady → _SendQueueItem + // → body 为空立即返回 False → _FinishQueueItem (配合 StatusCode>=500 触发 Disconnect) → ACallback 在锁外异步通知 + SendNoCompress(nil, 0, ACallback); + Exit; + end; + + LZError := False; + + SendNoCompress( + // CHUNK + function(const AData: PPointer; const ACount: PNativeInt): Boolean + var + LChunkData: Pointer; + LChunkSize: NativeInt; + begin + repeat + // 当 deflate(LZStream, Z_FINISH) 被调用后 + // 返回 Z_STREAM_END 表示所有数据处理完毕 + if (LZResult = Z_STREAM_END) then + begin + AData^ := nil; + ACount^ := 0; + Exit(False); + end; + + // 输入缓冲区已经处理完毕 + // 需要填入新数据 + if (LZStream.avail_in = 0) then + begin + LChunkData := nil; + LChunkSize := 0; + if not Assigned(AChunkSource) + or not AChunkSource(@LChunkData, @LChunkSize) + or (LChunkData = nil) + or (LChunkSize <= 0) then + LZFlush := Z_FINISH // 如果没有后续数据了, 准备结束压缩 + else + LZFlush := Z_NO_FLUSH; + + // 压缩数据输入缓冲区 + LZStream.avail_in := LChunkSize; + LZStream.next_in := LChunkData; + end; + + // 压缩数据输出缓冲区 + LZStream.avail_out := SND_BUF_SIZE; + LZStream.next_out := @LBuffer[0]; + + // 进行压缩处理 + // 输入缓冲区数据可以大于输出缓冲区 + // 这种情况可以多次调用 deflate 分批压缩, + // 直到 avail_in=0 表示当前输入缓冲区数据已压缩完毕 + LZResult := deflate(LZStream, LZFlush); + + // 压缩出错之后直接结束 + // 这里也可能会返回 Z_STREAM_END(1) + // 返回 Z_STREAM_END(1) 这一次还是有数据的 + // 所以要到下次 CHUNK 函数被调用的时候再结束 + if (LZResult < 0) then + begin + LZError := True; // 标记压缩错误,回调中将向调用方传递 False + // 标记 500 以触发 _FinishQueueItem 中 LNeedDisconnect 断开连接 + if (FQueueItem <> nil) then + FQueueItem.StatusCode := 500; + AData^ := nil; + ACount^ := 0; + Exit(False); + end; + + // 已压缩完成的数据大小 + LOutSize := SND_BUF_SIZE - LZStream.avail_out; + until (LOutSize > 0); + + // 已压缩的数据 + AData^ := @LBuffer[0]; + ACount^ := LOutSize; + + Result := (ACount^ > 0); + end, + // CALLBACK + procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) + begin + LBuffer := nil; + deflateEnd(LZStream); + + if Assigned(ACallback) then + ACallback(AConnection, ASuccess and not LZError); + end); +end; + +procedure TCrossHttpResponse.SendZCompress(const ABody: Pointer; + const ACount: NativeInt; const ACompressType: TCompressType; + const ACallback: TCrossConnectionCallback); +var + P: PByte; + LSize: NativeInt; +begin + P := ABody; + LSize := ACount; + + SendZCompress( + // CHUNK + function(const AData: PPointer; const ACount: PNativeInt): Boolean + begin + AData^ := P; + ACount^ := Min(LSize, SND_BUF_SIZE); + Result := (ACount^ > 0); + + if (LSize > SND_BUF_SIZE) then + begin + Inc(P, SND_BUF_SIZE); + Dec(LSize, SND_BUF_SIZE); + end else + begin + LSize := 0; + P := nil; + end; + end, + ACompressType, + ACallback); +end; + +procedure TCrossHttpResponse.SendZCompress(const ABody; const ACount: NativeInt; + const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback); +begin + SendZCompress(@ABody, ACount, ACompressType, ACallback); +end; + +procedure TCrossHttpResponse.SendZCompress(const ABody: TBytes; + const AOffset, ACount: NativeInt; const ACompressType: TCompressType; + const ACallback: TCrossConnectionCallback); +var + LBody: TBytes; + LOffset, LCount: NativeInt; +begin + // 增加其引用计数 + LBody := ABody; + + LOffset := AOffset; + LCount := ACount; + TCrossHttpUtils.AdjustOffsetCount(Length(ABody), LOffset, LCount); + + SendZCompress(Pointer(PByte(LBody) + LOffset), LCount, ACompressType, + // CALLBACK + procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) + begin + // 减少引用计数 + LBody := nil; + + if Assigned(ACallback) then + ACallback(AConnection, ASuccess); + end); +end; + +procedure TCrossHttpResponse.SendZCompress(const ABody: TBytes; + const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback); +begin + SendZCompress(ABody, 0, Length(ABody), ACompressType, ACallback); +end; + +procedure TCrossHttpResponse.SendZCompress(const ABody: TStream; + const AOffset, ACount: Int64; const ACompressType: TCompressType; + const ACallback: TCrossConnectionCallback); +var + LOffset, LCount: Int64; + LBody: TStream; + LBuffer: TBytes; + LP: PByte; + LSize: Int64; +begin + if (ABody = nil) then + begin + SendNoCompress(nil, 0, ACallback); + Exit; + end; + + LOffset := AOffset; + LCount := ACount; + TCrossHttpUtils.AdjustOffsetCount(ABody.Size, LOffset, LCount); + + if _GetMemoryStreamPointer(ABody, LOffset, LCount, LP, LSize) then + begin + SendZCompress(LP^, LSize, ACompressType, ACallback); + Exit; + end; + + LBody := ABody; + LBody.Position := LOffset; + + SetLength(LBuffer, SND_BUF_SIZE); + + SendZCompress( + // CHUNK + function(const AData: PPointer; const ACount: PNativeInt): Boolean + begin + if (LCount <= 0) then Exit(False); + + ACount^ := LBody.Read(LBuffer[0], Min(LCount, SND_BUF_SIZE)); + AData^ := @LBuffer[0]; + + Result := (ACount^ > 0); + + if Result then + Dec(LCount, ACount^); + end, + ACompressType, + // CALLBACK + procedure(const AConnection: ICrossConnection; const ASuccess: Boolean) + begin + LBuffer := nil; + + if Assigned(ACallback) then + ACallback(AConnection, ASuccess); + end); +end; + +procedure TCrossHttpResponse.SendZCompress(const ABody: TStream; + const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback); +begin + SendZCompress(ABody, 0, 0, ACompressType, ACallback); +end; + +procedure TCrossHttpResponse.SendZCompress(const ABody: string; + const ACompressType: TCompressType; const ACallback: TCrossConnectionCallback); +var + LBody: TBytes; +begin + LBody := TEncoding.UTF8.GetBytes(ABody); + if (GetContentType = '') then + SetContentType(TMediaType.TEXT_HTML_UTF8); + + SendZCompress(LBody, ACompressType, ACallback); +end; + +end. diff --git a/Net/Net.CrossHttpUtils.pas b/Net/Net.CrossHttpUtils.pas index 0e76de8..55d11f7 100644 --- a/Net/Net.CrossHttpUtils.pas +++ b/Net/Net.CrossHttpUtils.pas @@ -1,2113 +1,2113 @@ -{******************************************************************************} -{ } -{ Delphi cross platform socket library } -{ } -{ Copyright (c) 2017 WiNDDRiVER(soulawing@gmail.com) } -{ } -{ Homepage: https://github.com/winddriver/Delphi-Cross-Socket } -{ } -{******************************************************************************} -unit Net.CrossHttpUtils; - -{$I zLib.inc} - -interface - -uses - SysUtils, - DateUtils, - - Utils.DateTime, - Utils.StrUtils, - Utils.Utils, - Utils.IOUtils; - -type - THttpStatus = record - Code: Integer; - Text: string; - end; - - TMimeValue = record - Key: string; - Value: string; - end; - - {$REGION 'Documentation'} - /// - /// HTTP版本信息 - /// - {$ENDREGION} - THttpVersion = (hvHttp10, hvHttp11); - - {$REGION 'Documentation'} - /// - /// 压缩类型 - /// - {$ENDREGION} - TCompressType = (ctNone, ctGZip, ctDeflate); - -const - HTTP = 'http'; - HTTPS = 'https'; - HTTP_DEFAULT_PORT = 80; - HTTPS_DEFAULT_PORT = 443; - WS = 'ws'; - WSS = 'wss'; - WEBSOCKET = 'websocket'; - WEBSOCKET_VERSION = '13'; - - HTTP_VER_STR: array [THttpVersion] of string = ('HTTP/1.0', 'HTTP/1.1'); - - {$REGION '常用 HTTP 头'} - HEADER_ACCEPT = 'Accept'; - HEADER_ACCEPT_CHARSET = 'Accept-Charset'; - HEADER_ACCEPT_ENCODING = 'Accept-Encoding'; - HEADER_ACCEPT_LANGUAGE = 'Accept-Language'; - HEADER_ACCEPT_RANGES = 'Accept-Ranges'; - HEADER_AUTHORIZATION = 'Authorization'; - HEADER_CACHE_CONTROL = 'Cache-Control'; - HEADER_CONNECTION = 'Connection'; - HEADER_CONTENT_DISPOSITION = 'Content-Disposition'; - HEADER_CONTENT_ENCODING = 'Content-Encoding'; - HEADER_CONTENT_LANGUAGE = 'Content-Language'; - HEADER_CONTENT_LENGTH = 'Content-Length'; - HEADER_CONTENT_RANGE = 'Content-Range'; - HEADER_CONTENT_TYPE = 'Content-Type'; - HEADER_COOKIE = 'Cookie'; - HEADER_CROSS_HTTP_CLIENT = 'Client'; - HEADER_CROSS_HTTP_SERVER = 'Server'; - HEADER_ETAG = 'ETag'; - HEADER_EXPECT = 'Expect'; - HEADER_HOST = 'Host'; - HEADER_IF_MODIFIED_SINCE = 'If-Modified-Since'; - HEADER_IF_NONE_MATCH = 'If-None-Match'; - HEADER_IF_RANGE = 'If-Range'; - HEADER_LAST_MODIFIED = 'Last-Modified'; - HEADER_LOCATION = 'Location'; - HEADER_PRAGMA = 'Pragma'; - HEADER_PROXY_AUTHENTICATE = 'Proxy-Authenticate'; - HEADER_PROXY_AUTHORIZATION = 'Proxy-Authorization'; - HEADER_RANGE = 'Range'; - HEADER_REFERER = 'Referer'; - HEADER_SEC_WEBSOCKET_ACCEPT = 'Sec-WebSocket-Accept'; - HEADER_SEC_WEBSOCKET_KEY = 'Sec-WebSocket-Key'; - HEADER_SEC_WEBSOCKET_VERSION = 'Sec-WebSocket-Version'; - HEADER_SETCOOKIE = 'Set-Cookie'; - HEADER_TRANSFER_ENCODING = 'Transfer-Encoding'; - HEADER_UPGRADE = 'Upgrade'; - HEADER_USER_AGENT = 'User-Agent'; - HEADER_VARY = 'Vary'; - HEADER_WWW_AUTHENTICATE = 'WWW-Authenticate'; - HEADER_X_METHOD_OVERRIDE = 'x-method-override'; - HEADER_X_FORWARDED_FOR = 'X-Forwarded-For'; - HEADER_X_REAL_IP = 'X-Real-IP'; - HEADER_X_FORWARDED_HOST = 'X-Forwarded-Host'; - HEADER_X_FORWARDED_SERVER = 'X-Forwarded-Server'; - {$ENDREGION} - - ZLIB_BUF_SIZE = 32768; - ZLIB_WINDOW_BITS: array [TCompressType] of Integer = (0, 15 + 16{gzip}, 15{deflate}); - ZLIB_CONTENT_ENCODING: array [TCompressType] of string = ('', 'gzip', 'deflate'); - - {$REGION '常用状态码'} - STATUS_CODES: array [0..56] of THttpStatus = ( - (Code: 100; Text: 'Continue'), - (Code: 101; Text: 'Switching Protocols'), - (Code: 102; Text: 'Processing'), // RFC 2518, obsoleted by RFC 4918 - (Code: 200; Text: 'OK'), - (Code: 201; Text: 'Created'), - (Code: 202; Text: 'Accepted'), - (Code: 203; Text: 'Non-Authoritative Information'), - (Code: 204; Text: 'No Content'), - (Code: 205; Text: 'Reset Content'), - (Code: 206; Text: 'Partial Content'), - (Code: 207; Text: 'Multi-Status'), // RFC 4918 - (Code: 300; Text: 'Multiple Choices'), - (Code: 301; Text: 'Moved Permanently'), - (Code: 302; Text: 'Moved Temporarily'), - (Code: 303; Text: 'See Other'), - (Code: 304; Text: 'Not Modified'), - (Code: 305; Text: 'Use Proxy'), - (Code: 307; Text: 'Temporary Redirect'), - (Code: 308; Text: 'Permanent Redirect'), // RFC 7238 - (Code: 400; Text: 'Bad Request'), - (Code: 401; Text: 'Unauthorized'), - (Code: 402; Text: 'Payment Required'), - (Code: 403; Text: 'Forbidden'), - (Code: 404; Text: 'Not Found'), - (Code: 405; Text: 'Method Not Allowed'), - (Code: 406; Text: 'Not Acceptable'), - (Code: 407; Text: 'Proxy Authentication Required'), - (Code: 408; Text: 'Request Timeout'), - (Code: 409; Text: 'Conflict'), - (Code: 410; Text: 'Gone'), - (Code: 411; Text: 'Length Required'), - (Code: 412; Text: 'Precondition Failed'), - (Code: 413; Text: 'Request Entity Too Large'), - (Code: 414; Text: 'Request URI Too Large'), - (Code: 415; Text: 'Unsupported Media Type'), - (Code: 416; Text: 'Requested Range Not Satisfiable'), - (Code: 417; Text: 'Expectation Failed'), - (Code: 418; Text: 'I''m a teapot'), // RFC 2324 - (Code: 422; Text: 'Unprocessable Entity'), // RFC 4918 - (Code: 423; Text: 'Locked'), // RFC 4918 - (Code: 424; Text: 'Failed Dependency'), // RFC 4918 - (Code: 425; Text: 'Unordered Collection'), // RFC 4918 - (Code: 426; Text: 'Upgrade Required'), // RFC 2817 - (Code: 428; Text: 'Precondition Required'), // RFC 6585 - (Code: 429; Text: 'Too Many Requests'), // RFC 6585 - (Code: 431; Text: 'Request Header Fields Too Large'), // RFC 6585 - (Code: 500; Text: 'Internal Server Error'), - (Code: 501; Text: 'Not Implemented'), - (Code: 502; Text: 'Bad Gateway'), - (Code: 503; Text: 'Service Unavailable'), - (Code: 504; Text: 'Gateway Timeout'), - (Code: 505; Text: 'HTTP Version Not Supported'), - (Code: 506; Text: 'Variant Also Negotiates'), // RFC 2295 - (Code: 507; Text: 'Insufficient Storage'), // RFC 4918 - (Code: 509; Text: 'Bandwidth Limit Exceeded'), - (Code: 510; Text: 'Not Extended'), // RFC 2774 - (Code: 511; Text: 'Network Authentication Required') // RFC 6585 - ); - {$ENDREGION} - - {$REGION 'MIME CONST'} - MIME_TYPES: array[0..988] of TMimeValue = ( - (Key: 'ez'; Value: 'application/andrew-inset'), // do not localize - (Key: 'aw'; Value: 'application/applixware'), // do not localize - (Key: 'atom'; Value: 'application/atom+xml'), // do not localize - (Key: 'atomcat'; Value: 'application/atomcat+xml'), // do not localize - (Key: 'atomsvc'; Value: 'application/atomsvc+xml'), // do not localize - (Key: 'ccxml'; Value: 'application/ccxml+xml'), // do not localize - (Key: 'cdmia'; Value: 'application/cdmi-capability'), // do not localize - (Key: 'cdmic'; Value: 'application/cdmi-container'), // do not localize - (Key: 'cdmid'; Value: 'application/cdmi-domain'), // do not localize - (Key: 'cdmio'; Value: 'application/cdmi-object'), // do not localize - (Key: 'cdmiq'; Value: 'application/cdmi-queue'), // do not localize - (Key: 'cu'; Value: 'application/cu-seeme'), // do not localize - (Key: 'davmount'; Value: 'application/davmount+xml'), // do not localize - (Key: 'dbk'; Value: 'application/docbook+xml'), // do not localize - (Key: 'dssc'; Value: 'application/dssc+der'), // do not localize - (Key: 'xdssc'; Value: 'application/dssc+xml'), // do not localize - (Key: 'ecma'; Value: 'application/ecmascript'), // do not localize - (Key: 'emma'; Value: 'application/emma+xml'), // do not localize - (Key: 'epub'; Value: 'application/epub+zip'), // do not localize - (Key: 'exi'; Value: 'application/exi'), // do not localize - (Key: 'pfr'; Value: 'application/font-tdpfr'), // do not localize - (Key: 'gml'; Value: 'application/gml+xml'), // do not localize - (Key: 'gpx'; Value: 'application/gpx+xml'), // do not localize - (Key: 'gxf'; Value: 'application/gxf'), // do not localize - (Key: 'stk'; Value: 'application/hyperstudio'), // do not localize - (Key: 'ink'; Value: 'application/inkml+xml'), // do not localize - (Key: 'inkml'; Value: 'application/inkml+xml'), // do not localize - (Key: 'ipfix'; Value: 'application/ipfix'), // do not localize - (Key: 'jar'; Value: 'application/java-archive'), // do not localize - (Key: 'ser'; Value: 'application/java-serialized-object'), // do not localize - (Key: 'class'; Value: 'application/java-vm'), // do not localize - (Key: 'js'; Value: 'application/javascript'), // do not localize - (Key: 'json'; Value: 'application/json'), // do not localize - (Key: 'jsonml'; Value: 'application/jsonml+json'), // do not localize - (Key: 'lostxml'; Value: 'application/lost+xml'), // do not localize - (Key: 'hqx'; Value: 'application/mac-binhex40'), // do not localize - (Key: 'cpt'; Value: 'application/mac-compactpro'), // do not localize - (Key: 'mads'; Value: 'application/mads+xml'), // do not localize - (Key: 'mrc'; Value: 'application/marc'), // do not localize - (Key: 'mrcx'; Value: 'application/marcxml+xml'), // do not localize - (Key: 'ma'; Value: 'application/mathematica'), // do not localize - (Key: 'nb'; Value: 'application/mathematica'), // do not localize - (Key: 'mb'; Value: 'application/mathematica'), // do not localize - (Key: 'mathml'; Value: 'application/mathml+xml'), // do not localize - (Key: 'mbox'; Value: 'application/mbox'), // do not localize - (Key: 'mscml'; Value: 'application/mediaservercontrol+xml'), // do not localize - (Key: 'metalink'; Value: 'application/metalink+xml'), // do not localize - (Key: 'meta4'; Value: 'application/metalink4+xml'), // do not localize - (Key: 'mets'; Value: 'application/mets+xml'), // do not localize - (Key: 'mods'; Value: 'application/mods+xml'), // do not localize - (Key: 'm21'; Value: 'application/mp21'), // do not localize - (Key: 'mp21'; Value: 'application/mp21'), // do not localize - (Key: 'mp4s'; Value: 'application/mp4'), // do not localize - (Key: 'doc'; Value: 'application/msword'), // do not localize - (Key: 'dot'; Value: 'application/msword'), // do not localize - (Key: 'mxf'; Value: 'application/mxf'), // do not localize - (Key: 'bin'; Value: 'application/octet-stream'), // do not localize - (Key: 'bpk'; Value: 'application/octet-stream'), // do not localize - (Key: 'class'; Value: 'application/octet-stream'), // do not localize - (Key: 'deploy'; Value: 'application/octet-stream'), // do not localize - (Key: 'dist'; Value: 'application/octet-stream'), // do not localize - (Key: 'distz'; Value: 'application/octet-stream'), // do not localize - (Key: 'dmg'; Value: 'application/octet-stream'), // do not localize - (Key: 'dms'; Value: 'application/octet-stream'), // do not localize - (Key: 'dump'; Value: 'application/octet-stream'), // do not localize - (Key: 'elc'; Value: 'application/octet-stream'), // do not localize - (Key: 'iso'; Value: 'application/octet-stream'), // do not localize - (Key: 'lha'; Value: 'application/octet-stream'), // do not localize - (Key: 'lrf'; Value: 'application/octet-stream'), // do not localize - (Key: 'lzh'; Value: 'application/octet-stream'), // do not localize - (Key: 'mar'; Value: 'application/octet-stream'), // do not localize - (Key: 'pkg'; Value: 'application/octet-stream'), // do not localize - (Key: 'so'; Value: 'application/octet-stream'), // do not localize - (Key: 'oda'; Value: 'application/oda'), // do not localize - (Key: 'opf'; Value: 'application/oebps-package+xml'), // do not localize - (Key: 'ogx'; Value: 'application/ogg'), // do not localize - (Key: 'omdoc'; Value: 'application/omdoc+xml'), // do not localize - (Key: 'onetoc'; Value: 'application/onenote'), // do not localize - (Key: 'onetoc2'; Value: 'application/onenote'), // do not localize - (Key: 'onetmp'; Value: 'application/onenote'), // do not localize - (Key: 'onepkg'; Value: 'application/onenote'), // do not localize - (Key: 'oxps'; Value: 'application/oxps'), // do not localize - (Key: 'xer'; Value: 'application/patch-ops-error+xml'), // do not localize - (Key: 'pdf'; Value: 'application/pdf'), // do not localize - (Key: 'pgp'; Value: 'application/pgp-encrypted'), // do not localize - (Key: 'asc'; Value: 'application/pgp-signature'), // do not localize - (Key: 'sig'; Value: 'application/pgp-signature'), // do not localize - (Key: 'prf'; Value: 'application/pics-rules'), // do not localize - (Key: 'p10'; Value: 'application/pkcs10'), // do not localize - (Key: 'p7m'; Value: 'application/pkcs7-mime'), // do not localize - (Key: 'p7c'; Value: 'application/pkcs7-mime'), // do not localize - (Key: 'p7s'; Value: 'application/pkcs7-signature'), // do not localize - (Key: 'p8'; Value: 'application/pkcs8'), // do not localize - (Key: 'ac'; Value: 'application/pkix-attr-cert'), // do not localize - (Key: 'cer'; Value: 'application/pkix-cert'), // do not localize - (Key: 'crl'; Value: 'application/pkix-crl'), // do not localize - (Key: 'pkipath'; Value: 'application/pkix-pkipath'), // do not localize - (Key: 'pki'; Value: 'application/pkixcmp'), // do not localize - (Key: 'pls'; Value: 'application/pls+xml'), // do not localize - (Key: 'ai'; Value: 'application/postscript'), // do not localize - (Key: 'eps'; Value: 'application/postscript'), // do not localize - (Key: 'ps'; Value: 'application/postscript'), // do not localize - (Key: 'cww'; Value: 'application/prs.cww'), // do not localize - (Key: 'pskcxml'; Value: 'application/pskc+xml'), // do not localize - (Key: 'rdf'; Value: 'application/rdf+xml'), // do not localize - (Key: 'rif'; Value: 'application/reginfo+xml'), // do not localize - (Key: 'rnc'; Value: 'application/relax-ng-compact-syntax'), // do not localize - (Key: 'rl'; Value: 'application/resource-lists+xml'), // do not localize - (Key: 'rld'; Value: 'application/resource-lists-diff+xml'), // do not localize - (Key: 'rs'; Value: 'application/rls-services+xml'), // do not localize - (Key: 'gbr'; Value: 'application/rpki-ghostbusters'), // do not localize - (Key: 'mft'; Value: 'application/rpki-manifest'), // do not localize - (Key: 'roa'; Value: 'application/rpki-roa'), // do not localize - (Key: 'rsd'; Value: 'application/rsd+xml'), // do not localize - (Key: 'rss'; Value: 'application/rss+xml'), // do not localize - (Key: 'rtf'; Value: 'application/rtf'), // do not localize - (Key: 'sbml'; Value: 'application/sbml+xml'), // do not localize - (Key: 'scq'; Value: 'application/scvp-cv-request'), // do not localize - (Key: 'scs'; Value: 'application/scvp-cv-response'), // do not localize - (Key: 'spq'; Value: 'application/scvp-vp-request'), // do not localize - (Key: 'spp'; Value: 'application/scvp-vp-response'), // do not localize - (Key: 'sdp'; Value: 'application/sdp'), // do not localize - (Key: 'setpay'; Value: 'application/set-payment-initiation'), // do not localize - (Key: 'setreg'; Value: 'application/set-registration-initiation'), // do not localize - (Key: 'shf'; Value: 'application/shf+xml'), // do not localize - (Key: 'smi'; Value: 'application/smil+xml'), // do not localize - (Key: 'smil'; Value: 'application/smil+xml'), // do not localize - (Key: 'rq'; Value: 'application/sparql-query'), // do not localize - (Key: 'srx'; Value: 'application/sparql-results+xml'), // do not localize - (Key: 'gram'; Value: 'application/srgs'), // do not localize - (Key: 'grxml'; Value: 'application/srgs+xml'), // do not localize - (Key: 'sru'; Value: 'application/sru+xml'), // do not localize - (Key: 'ssdl'; Value: 'application/ssdl+xml'), // do not localize - (Key: 'ssml'; Value: 'application/ssml+xml'), // do not localize - (Key: 'tei'; Value: 'application/tei+xml'), // do not localize - (Key: 'teicorpus'; Value: 'application/tei+xml'), // do not localize - (Key: 'tfi'; Value: 'application/thraud+xml'), // do not localize - (Key: 'tsd'; Value: 'application/timestamped-data'), // do not localize - (Key: 'plb'; Value: 'application/vnd.3gpp.pic-bw-large'), // do not localize - (Key: 'psb'; Value: 'application/vnd.3gpp.pic-bw-small'), // do not localize - (Key: 'pvb'; Value: 'application/vnd.3gpp.pic-bw-var'), // do not localize - (Key: 'tcap'; Value: 'application/vnd.3gpp2.tcap'), // do not localize - (Key: 'pwn'; Value: 'application/vnd.3m.post-it-notes'), // do not localize - (Key: 'aso'; Value: 'application/vnd.accpac.simply.aso'), // do not localize - (Key: 'imp'; Value: 'application/vnd.accpac.simply.imp'), // do not localize - (Key: 'acu'; Value: 'application/vnd.acucobol'), // do not localize - (Key: 'atc'; Value: 'application/vnd.acucorp'), // do not localize - (Key: 'acutc'; Value: 'application/vnd.acucorp'), // do not localize - (Key: 'air'; Value: 'application/vnd.adobe.air-application-installer-package+zip'), // do not localize - (Key: 'fcdt'; Value: 'application/vnd.adobe.formscentral.fcdt'), // do not localize - (Key: 'fxp'; Value: 'application/vnd.adobe.fxp'), // do not localize - (Key: 'fxpl'; Value: 'application/vnd.adobe.fxp'), // do not localize - (Key: 'xdp'; Value: 'application/vnd.adobe.xdp+xml'), // do not localize - (Key: 'xfdf'; Value: 'application/vnd.adobe.xfdf'), // do not localize - (Key: 'ahead'; Value: 'application/vnd.ahead.space'), // do not localize - (Key: 'azf'; Value: 'application/vnd.airzip.filesecure.azf'), // do not localize - (Key: 'azs'; Value: 'application/vnd.airzip.filesecure.azs'), // do not localize - (Key: 'azw'; Value: 'application/vnd.amazon.ebook'), // do not localize - (Key: 'acc'; Value: 'application/vnd.americandynamics.acc'), // do not localize - (Key: 'ami'; Value: 'application/vnd.amiga.ami'), // do not localize - (Key: 'apk'; Value: 'application/vnd.android.package-archive'), // do not localize - (Key: 'cii'; Value: 'application/vnd.anser-web-certificate-issue-initiation'), // do not localize - (Key: 'fti'; Value: 'application/vnd.anser-web-funds-transfer-initiation'), // do not localize - (Key: 'atx'; Value: 'application/vnd.antix.game-component'), // do not localize - (Key: 'mpkg'; Value: 'application/vnd.apple.installer+xml'), // do not localize - (Key: 'm3u8'; Value: 'application/vnd.apple.mpegurl'), // do not localize - (Key: 'swi'; Value: 'application/vnd.aristanetworks.swi'), // do not localize - (Key: 'iota'; Value: 'application/vnd.astraea-software.iota'), // do not localize - (Key: 'aep'; Value: 'application/vnd.audiograph'), // do not localize - (Key: 'mpm'; Value: 'application/vnd.blueice.multipass'), // do not localize - (Key: 'bmi'; Value: 'application/vnd.bmi'), // do not localize - (Key: 'rep'; Value: 'application/vnd.businessobjects'), // do not localize - (Key: 'cdxml'; Value: 'application/vnd.chemdraw+xml'), // do not localize - (Key: 'mmd'; Value: 'application/vnd.chipnuts.karaoke-mmd'), // do not localize - (Key: 'cdy'; Value: 'application/vnd.cinderella'), // do not localize - (Key: 'cla'; Value: 'application/vnd.claymore'), // do not localize - (Key: 'rp9'; Value: 'application/vnd.cloanto.rp9'), // do not localize - (Key: 'c4g'; Value: 'application/vnd.clonk.c4group'), // do not localize - (Key: 'c4d'; Value: 'application/vnd.clonk.c4group'), // do not localize - (Key: 'c4f'; Value: 'application/vnd.clonk.c4group'), // do not localize - (Key: 'c4p'; Value: 'application/vnd.clonk.c4group'), // do not localize - (Key: 'c4u'; Value: 'application/vnd.clonk.c4group'), // do not localize - (Key: 'c11amc'; Value: 'application/vnd.cluetrust.cartomobile-config'), // do not localize - (Key: 'c11amz'; Value: 'application/vnd.cluetrust.cartomobile-config-pkg'), // do not localize - (Key: 'csp'; Value: 'application/vnd.commonspace'), // do not localize - (Key: 'cdbcmsg'; Value: 'application/vnd.contact.cmsg'), // do not localize - (Key: 'cmc'; Value: 'application/vnd.cosmocaller'), // do not localize - (Key: 'clkx'; Value: 'application/vnd.crick.clicker'), // do not localize - (Key: 'clkk'; Value: 'application/vnd.crick.clicker.keyboard'), // do not localize - (Key: 'clkp'; Value: 'application/vnd.crick.clicker.palette'), // do not localize - (Key: 'clkt'; Value: 'application/vnd.crick.clicker.template'), // do not localize - (Key: 'clkw'; Value: 'application/vnd.crick.clicker.wordbank'), // do not localize - (Key: 'wbs'; Value: 'application/vnd.criticaltools.wbs+xml'), // do not localize - (Key: 'pml'; Value: 'application/vnd.ctc-posml'), // do not localize - (Key: 'ppd'; Value: 'application/vnd.cups-ppd'), // do not localize - (Key: 'car'; Value: 'application/vnd.curl.car'), // do not localize - (Key: 'pcurl'; Value: 'application/vnd.curl.pcurl'), // do not localize - (Key: 'dart'; Value: 'application/vnd.dart'), // do not localize - (Key: 'rdz'; Value: 'application/vnd.data-vision.rdz'), // do not localize - (Key: 'uvf'; Value: 'application/vnd.dece.data'), // do not localize - (Key: 'uvvf'; Value: 'application/vnd.dece.data'), // do not localize - (Key: 'uvd'; Value: 'application/vnd.dece.data'), // do not localize - (Key: 'uvvd'; Value: 'application/vnd.dece.data'), // do not localize - (Key: 'uvt'; Value: 'application/vnd.dece.ttml+xml'), // do not localize - (Key: 'uvvt'; Value: 'application/vnd.dece.ttml+xml'), // do not localize - (Key: 'uvx'; Value: 'application/vnd.dece.unspecified'), // do not localize - (Key: 'uvvx'; Value: 'application/vnd.dece.unspecified'), // do not localize - (Key: 'uvz'; Value: 'application/vnd.dece.zip'), // do not localize - (Key: 'uvvz'; Value: 'application/vnd.dece.zip'), // do not localize - (Key: 'fe_launch'; Value: 'application/vnd.denovo.fcselayout-link'), // do not localize - (Key: 'dna'; Value: 'application/vnd.dna'), // do not localize - (Key: 'mlp'; Value: 'application/vnd.dolby.mlp'), // do not localize - (Key: 'dpg'; Value: 'application/vnd.dpgraph'), // do not localize - (Key: 'dfac'; Value: 'application/vnd.dreamfactory'), // do not localize - (Key: 'kpxx'; Value: 'application/vnd.ds-keypoint'), // do not localize - (Key: 'ait'; Value: 'application/vnd.dvb.ait'), // do not localize - (Key: 'svc'; Value: 'application/vnd.dvb.service'), // do not localize - (Key: 'geo'; Value: 'application/vnd.dynageo'), // do not localize - (Key: 'mag'; Value: 'application/vnd.ecowin.chart'), // do not localize - (Key: 'nml'; Value: 'application/vnd.enliven'), // do not localize - (Key: 'esf'; Value: 'application/vnd.epson.esf'), // do not localize - (Key: 'msf'; Value: 'application/vnd.epson.msf'), // do not localize - (Key: 'qam'; Value: 'application/vnd.epson.quickanime'), // do not localize - (Key: 'slt'; Value: 'application/vnd.epson.salt'), // do not localize - (Key: 'ssf'; Value: 'application/vnd.epson.ssf'), // do not localize - (Key: 'es3'; Value: 'application/vnd.eszigno3+xml'), // do not localize - (Key: 'et3'; Value: 'application/vnd.eszigno3+xml'), // do not localize - (Key: 'ez2'; Value: 'application/vnd.ezpix-album'), // do not localize - (Key: 'ez3'; Value: 'application/vnd.ezpix-package'), // do not localize - (Key: 'fdf'; Value: 'application/vnd.fdf'), // do not localize - (Key: 'mseed'; Value: 'application/vnd.fdsn.mseed'), // do not localize - (Key: 'seed'; Value: 'application/vnd.fdsn.seed'), // do not localize - (Key: 'dataless'; Value: 'application/vnd.fdsn.seed'), // do not localize - (Key: 'gph'; Value: 'application/vnd.flographit'), // do not localize - (Key: 'ftc'; Value: 'application/vnd.fluxtime.clip'), // do not localize - (Key: 'fm'; Value: 'application/vnd.framemaker'), // do not localize - (Key: 'frame'; Value: 'application/vnd.framemaker'), // do not localize - (Key: 'maker'; Value: 'application/vnd.framemaker'), // do not localize - (Key: 'book'; Value: 'application/vnd.framemaker'), // do not localize - (Key: 'fnc'; Value: 'application/vnd.frogans.fnc'), // do not localize - (Key: 'ltf'; Value: 'application/vnd.frogans.ltf'), // do not localize - (Key: 'fsc'; Value: 'application/vnd.fsc.weblaunch'), // do not localize - (Key: 'oas'; Value: 'application/vnd.fujitsu.oasys'), // do not localize - (Key: 'oa2'; Value: 'application/vnd.fujitsu.oasys2'), // do not localize - (Key: 'oa3'; Value: 'application/vnd.fujitsu.oasys3'), // do not localize - (Key: 'fg5'; Value: 'application/vnd.fujitsu.oasysgp'), // do not localize - (Key: 'bh2'; Value: 'application/vnd.fujitsu.oasysprs'), // do not localize - (Key: 'ddd'; Value: 'application/vnd.fujixerox.ddd'), // do not localize - (Key: 'xdw'; Value: 'application/vnd.fujixerox.docuworks'), // do not localize - (Key: 'xbd'; Value: 'application/vnd.fujixerox.docuworks.binder'), // do not localize - (Key: 'fzs'; Value: 'application/vnd.fuzzysheet'), // do not localize - (Key: 'txd'; Value: 'application/vnd.genomatix.tuxedo'), // do not localize - (Key: 'ggb'; Value: 'application/vnd.geogebra.file'), // do not localize - (Key: 'ggt'; Value: 'application/vnd.geogebra.tool'), // do not localize - (Key: 'gex'; Value: 'application/vnd.geometry-explorer'), // do not localize - (Key: 'gre'; Value: 'application/vnd.geometry-explorer'), // do not localize - (Key: 'gxt'; Value: 'application/vnd.geonext'), // do not localize - (Key: 'g2w'; Value: 'application/vnd.geoplan'), // do not localize - (Key: 'g3w'; Value: 'application/vnd.geospace'), // do not localize - (Key: 'gmx'; Value: 'application/vnd.gmx'), // do not localize - (Key: 'kml'; Value: 'application/vnd.google-earth.kml+xml'), // do not localize - (Key: 'kmz'; Value: 'application/vnd.google-earth.kmz'), // do not localize - (Key: 'gqf'; Value: 'application/vnd.grafeq'), // do not localize - (Key: 'gqs'; Value: 'application/vnd.grafeq'), // do not localize - (Key: 'gac'; Value: 'application/vnd.groove-account'), // do not localize - (Key: 'ghf'; Value: 'application/vnd.groove-help'), // do not localize - (Key: 'gim'; Value: 'application/vnd.groove-identity-message'), // do not localize - (Key: 'grv'; Value: 'application/vnd.groove-injector'), // do not localize - (Key: 'gtm'; Value: 'application/vnd.groove-tool-message'), // do not localize - (Key: 'tpl'; Value: 'application/vnd.groove-tool-template'), // do not localize - (Key: 'vcg'; Value: 'application/vnd.groove-vcard'), // do not localize - (Key: 'hal'; Value: 'application/vnd.hal+xml'), // do not localize - (Key: 'zmm'; Value: 'application/vnd.handheld-entertainment+xml'), // do not localize - (Key: 'hbci'; Value: 'application/vnd.hbci'), // do not localize - (Key: 'les'; Value: 'application/vnd.hhe.lesson-player'), // do not localize - (Key: 'hpgl'; Value: 'application/vnd.hp-hpgl'), // do not localize - (Key: 'hpid'; Value: 'application/vnd.hp-hpid'), // do not localize - (Key: 'hps'; Value: 'application/vnd.hp-hps'), // do not localize - (Key: 'jlt'; Value: 'application/vnd.hp-jlyt'), // do not localize - (Key: 'pcl'; Value: 'application/vnd.hp-pcl'), // do not localize - (Key: 'pclxl'; Value: 'application/vnd.hp-pclxl'), // do not localize - (Key: 'sfd-hdstx'; Value: 'application/vnd.hydrostatix.sof-data'), // do not localize - (Key: 'mpy'; Value: 'application/vnd.ibm.minipay'), // do not localize - (Key: 'afp'; Value: 'application/vnd.ibm.modcap'), // do not localize - (Key: 'listafp'; Value: 'application/vnd.ibm.modcap'), // do not localize - (Key: 'list3820'; Value: 'application/vnd.ibm.modcap'), // do not localize - (Key: 'irm'; Value: 'application/vnd.ibm.rights-management'), // do not localize - (Key: 'sc'; Value: 'application/vnd.ibm.secure-container'), // do not localize - (Key: 'icc'; Value: 'application/vnd.iccprofile'), // do not localize - (Key: 'icm'; Value: 'application/vnd.iccprofile'), // do not localize - (Key: 'igl'; Value: 'application/vnd.igloader'), // do not localize - (Key: 'ivp'; Value: 'application/vnd.immervision-ivp'), // do not localize - (Key: 'ivu'; Value: 'application/vnd.immervision-ivu'), // do not localize - (Key: 'igm'; Value: 'application/vnd.insors.igm'), // do not localize - (Key: 'xpw'; Value: 'application/vnd.intercon.formnet'), // do not localize - (Key: 'xpx'; Value: 'application/vnd.intercon.formnet'), // do not localize - (Key: 'i2g'; Value: 'application/vnd.intergeo'), // do not localize - (Key: 'qbo'; Value: 'application/vnd.intu.qbo'), // do not localize - (Key: 'qfx'; Value: 'application/vnd.intu.qfx'), // do not localize - (Key: 'rcprofile'; Value: 'application/vnd.ipunplugged.rcprofile'), // do not localize - (Key: 'irp'; Value: 'application/vnd.irepository.package+xml'), // do not localize - (Key: 'xpr'; Value: 'application/vnd.is-xpr'), // do not localize - (Key: 'fcs'; Value: 'application/vnd.isac.fcs'), // do not localize - (Key: 'jam'; Value: 'application/vnd.jam'), // do not localize - (Key: 'rms'; Value: 'application/vnd.jcp.javame.midlet-rms'), // do not localize - (Key: 'jisp'; Value: 'application/vnd.jisp'), // do not localize - (Key: 'joda'; Value: 'application/vnd.joost.joda-archive'), // do not localize - (Key: 'ktz'; Value: 'application/vnd.kahootz'), // do not localize - (Key: 'ktr'; Value: 'application/vnd.kahootz'), // do not localize - (Key: 'karbon'; Value: 'application/vnd.kde.karbon'), // do not localize - (Key: 'chrt'; Value: 'application/vnd.kde.kchart'), // do not localize - (Key: 'kfo'; Value: 'application/vnd.kde.kformula'), // do not localize - (Key: 'flw'; Value: 'application/vnd.kde.kivio'), // do not localize - (Key: 'kon'; Value: 'application/vnd.kde.kontour'), // do not localize - (Key: 'kpr'; Value: 'application/vnd.kde.kpresenter'), // do not localize - (Key: 'kpt'; Value: 'application/vnd.kde.kpresenter'), // do not localize - (Key: 'ksp'; Value: 'application/vnd.kde.kspread'), // do not localize - (Key: 'kwd'; Value: 'application/vnd.kde.kword'), // do not localize - (Key: 'kwt'; Value: 'application/vnd.kde.kword'), // do not localize - (Key: 'htke'; Value: 'application/vnd.kenameaapp'), // do not localize - (Key: 'kia'; Value: 'application/vnd.kidspiration'), // do not localize - (Key: 'kne'; Value: 'application/vnd.kinar'), // do not localize - (Key: 'knp'; Value: 'application/vnd.kinar'), // do not localize - (Key: 'skp'; Value: 'application/vnd.koan'), // do not localize - (Key: 'skd'; Value: 'application/vnd.koan'), // do not localize - (Key: 'skt'; Value: 'application/vnd.koan'), // do not localize - (Key: 'skm'; Value: 'application/vnd.koan'), // do not localize - (Key: 'sse'; Value: 'application/vnd.kodak-descriptor'), // do not localize - (Key: 'lasxml'; Value: 'application/vnd.las.las+xml'), // do not localize - (Key: 'lbd'; Value: 'application/vnd.llamagraphics.life-balance.desktop'), // do not localize - (Key: 'lbe'; Value: 'application/vnd.llamagraphics.life-balance.exchange+xml'), // do not localize - (Key: '123'; Value: 'application/vnd.lotus-1-2-3'), // do not localize - (Key: 'apr'; Value: 'application/vnd.lotus-approach'), // do not localize - (Key: 'pre'; Value: 'application/vnd.lotus-freelance'), // do not localize - (Key: 'nsf'; Value: 'application/vnd.lotus-notes'), // do not localize - (Key: 'org'; Value: 'application/vnd.lotus-organizer'), // do not localize - (Key: 'scm'; Value: 'application/vnd.lotus-screencam'), // do not localize - (Key: 'lwp'; Value: 'application/vnd.lotus-wordpro'), // do not localize - (Key: 'portpkg'; Value: 'application/vnd.macports.portpkg'), // do not localize - (Key: 'mcd'; Value: 'application/vnd.mcd'), // do not localize - (Key: 'mc1'; Value: 'application/vnd.medcalcdata'), // do not localize - (Key: 'cdkey'; Value: 'application/vnd.mediastation.cdkey'), // do not localize - (Key: 'mwf'; Value: 'application/vnd.mfer'), // do not localize - (Key: 'mfm'; Value: 'application/vnd.mfmp'), // do not localize - (Key: 'flo'; Value: 'application/vnd.micrografx.flo'), // do not localize - (Key: 'igx'; Value: 'application/vnd.micrografx.igx'), // do not localize - (Key: 'mif'; Value: 'application/vnd.mif'), // do not localize - (Key: 'daf'; Value: 'application/vnd.mobius.daf'), // do not localize - (Key: 'dis'; Value: 'application/vnd.mobius.dis'), // do not localize - (Key: 'mbk'; Value: 'application/vnd.mobius.mbk'), // do not localize - (Key: 'mqy'; Value: 'application/vnd.mobius.mqy'), // do not localize - (Key: 'msl'; Value: 'application/vnd.mobius.msl'), // do not localize - (Key: 'plc'; Value: 'application/vnd.mobius.plc'), // do not localize - (Key: 'txf'; Value: 'application/vnd.mobius.txf'), // do not localize - (Key: 'mpn'; Value: 'application/vnd.mophun.application'), // do not localize - (Key: 'mpc'; Value: 'application/vnd.mophun.certificate'), // do not localize - (Key: 'xul'; Value: 'application/vnd.mozilla.xul+xml'), // do not localize - (Key: 'cil'; Value: 'application/vnd.ms-artgalry'), // do not localize - (Key: 'cab'; Value: 'application/vnd.ms-cab-compressed'), // do not localize - (Key: 'xls'; Value: 'application/vnd.ms-excel'), // do not localize - (Key: 'xlm'; Value: 'application/vnd.ms-excel'), // do not localize - (Key: 'xla'; Value: 'application/vnd.ms-excel'), // do not localize - (Key: 'xlc'; Value: 'application/vnd.ms-excel'), // do not localize - (Key: 'xlt'; Value: 'application/vnd.ms-excel'), // do not localize - (Key: 'xlw'; Value: 'application/vnd.ms-excel'), // do not localize - (Key: 'xlam'; Value: 'application/vnd.ms-excel.addin.macroenabled.12'), // do not localize - (Key: 'xlsb'; Value: 'application/vnd.ms-excel.sheet.binary.macroenabled.12'), // do not localize - (Key: 'xlsm'; Value: 'application/vnd.ms-excel.sheet.macroenabled.12'), // do not localize - (Key: 'xltm'; Value: 'application/vnd.ms-excel.template.macroenabled.12'), // do not localize - (Key: 'eot'; Value: 'application/vnd.ms-fontobject'), // do not localize - (Key: 'chm'; Value: 'application/vnd.ms-htmlhelp'), // do not localize - (Key: 'ims'; Value: 'application/vnd.ms-ims'), // do not localize - (Key: 'lrm'; Value: 'application/vnd.ms-lrm'), // do not localize - (Key: 'thmx'; Value: 'application/vnd.ms-officetheme'), // do not localize - (Key: 'cat'; Value: 'application/vnd.ms-pki.seccat'), // do not localize - (Key: 'stl'; Value: 'application/vnd.ms-pki.stl'), // do not localize - (Key: 'ppt'; Value: 'application/vnd.ms-powerpoint'), // do not localize - (Key: 'pps'; Value: 'application/vnd.ms-powerpoint'), // do not localize - (Key: 'pot'; Value: 'application/vnd.ms-powerpoint'), // do not localize - (Key: 'ppam'; Value: 'application/vnd.ms-powerpoint.addin.macroenabled.12'), // do not localize - (Key: 'pptm'; Value: 'application/vnd.ms-powerpoint.presentation.macroenabled.12'), // do not localize - (Key: 'sldm'; Value: 'application/vnd.ms-powerpoint.slide.macroenabled.12'), // do not localize - (Key: 'ppsm'; Value: 'application/vnd.ms-powerpoint.slideshow.macroenabled.12'), // do not localize - (Key: 'potm'; Value: 'application/vnd.ms-powerpoint.template.macroenabled.12'), // do not localize - (Key: 'mpp'; Value: 'application/vnd.ms-project'), // do not localize - (Key: 'mpt'; Value: 'application/vnd.ms-project'), // do not localize - (Key: 'docm'; Value: 'application/vnd.ms-word.document.macroenabled.12'), // do not localize - (Key: 'dotm'; Value: 'application/vnd.ms-word.template.macroenabled.12'), // do not localize - (Key: 'wps'; Value: 'application/vnd.ms-works'), // do not localize - (Key: 'wks'; Value: 'application/vnd.ms-works'), // do not localize - (Key: 'wcm'; Value: 'application/vnd.ms-works'), // do not localize - (Key: 'wdb'; Value: 'application/vnd.ms-works'), // do not localize - (Key: 'wpl'; Value: 'application/vnd.ms-wpl'), // do not localize - (Key: 'xps'; Value: 'application/vnd.ms-xpsdocument'), // do not localize - (Key: 'mseq'; Value: 'application/vnd.mseq'), // do not localize - (Key: 'mus'; Value: 'application/vnd.musician'), // do not localize - (Key: 'msty'; Value: 'application/vnd.muvee.style'), // do not localize - (Key: 'taglet'; Value: 'application/vnd.mynfc'), // do not localize - (Key: 'nlu'; Value: 'application/vnd.neurolanguage.nlu'), // do not localize - (Key: 'ntf'; Value: 'application/vnd.nitf'), // do not localize - (Key: 'nitf'; Value: 'application/vnd.nitf'), // do not localize - (Key: 'nnd'; Value: 'application/vnd.noblenet-directory'), // do not localize - (Key: 'nns'; Value: 'application/vnd.noblenet-sealer'), // do not localize - (Key: 'nnw'; Value: 'application/vnd.noblenet-web'), // do not localize - (Key: 'ngdat'; Value: 'application/vnd.nokia.n-gage.data'), // do not localize - (Key: 'n-gage'; Value: 'application/vnd.nokia.n-gage.symbian.install'), // do not localize - (Key: 'rpst'; Value: 'application/vnd.nokia.radio-preset'), // do not localize - (Key: 'rpss'; Value: 'application/vnd.nokia.radio-presets'), // do not localize - (Key: 'edm'; Value: 'application/vnd.novadigm.edm'), // do not localize - (Key: 'edx'; Value: 'application/vnd.novadigm.edx'), // do not localize - (Key: 'ext'; Value: 'application/vnd.novadigm.ext'), // do not localize - (Key: 'odc'; Value: 'application/vnd.oasis.opendocument.chart'), // do not localize - (Key: 'otc'; Value: 'application/vnd.oasis.opendocument.chart-template'), // do not localize - (Key: 'odb'; Value: 'application/vnd.oasis.opendocument.database'), // do not localize - (Key: 'odf'; Value: 'application/vnd.oasis.opendocument.formula'), // do not localize - (Key: 'odft'; Value: 'application/vnd.oasis.opendocument.formula-template'), // do not localize - (Key: 'odg'; Value: 'application/vnd.oasis.opendocument.graphics'), // do not localize - (Key: 'otg'; Value: 'application/vnd.oasis.opendocument.graphics-template'), // do not localize - (Key: 'odi'; Value: 'application/vnd.oasis.opendocument.image'), // do not localize - (Key: 'oti'; Value: 'application/vnd.oasis.opendocument.image-template'), // do not localize - (Key: 'odp'; Value: 'application/vnd.oasis.opendocument.presentation'), // do not localize - (Key: 'otp'; Value: 'application/vnd.oasis.opendocument.presentation-template'), // do not localize - (Key: 'ods'; Value: 'application/vnd.oasis.opendocument.spreadsheet'), // do not localize - (Key: 'ots'; Value: 'application/vnd.oasis.opendocument.spreadsheet-template'), // do not localize - (Key: 'odt'; Value: 'application/vnd.oasis.opendocument.text'), // do not localize - (Key: 'odm'; Value: 'application/vnd.oasis.opendocument.text-master'), // do not localize - (Key: 'ott'; Value: 'application/vnd.oasis.opendocument.text-template'), // do not localize - (Key: 'oth'; Value: 'application/vnd.oasis.opendocument.text-web'), // do not localize - (Key: 'xo'; Value: 'application/vnd.olpc-sugar'), // do not localize - (Key: 'dd2'; Value: 'application/vnd.oma.dd2+xml'), // do not localize - (Key: 'oxt'; Value: 'application/vnd.openofficeorg.extension'), // do not localize - (Key: 'pptx'; Value: 'application/vnd.openxmlformats-officedocument.presentationml.presentation'), // do not localize - (Key: 'sldx'; Value: 'application/vnd.openxmlformats-officedocument.presentationml.slide'), // do not localize - (Key: 'ppsx'; Value: 'application/vnd.openxmlformats-officedocument.presentationml.slideshow'), // do not localize - (Key: 'potx'; Value: 'application/vnd.openxmlformats-officedocument.presentationml.template'), // do not localize - (Key: 'xlsx'; Value: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'), // do not localize - (Key: 'xltx'; Value: 'application/vnd.openxmlformats-officedocument.spreadsheetml.template'), // do not localize - (Key: 'docx'; Value: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'), // do not localize - (Key: 'dotx'; Value: 'application/vnd.openxmlformats-officedocument.wordprocessingml.template'), // do not localize - (Key: 'mgp'; Value: 'application/vnd.osgeo.mapguide.package'), // do not localize - (Key: 'dp'; Value: 'application/vnd.osgi.dp'), // do not localize - (Key: 'esa'; Value: 'application/vnd.osgi.subsystem'), // do not localize - (Key: 'pdb'; Value: 'application/vnd.palm'), // do not localize - (Key: 'pqa'; Value: 'application/vnd.palm'), // do not localize - (Key: 'oprc'; Value: 'application/vnd.palm'), // do not localize - (Key: 'paw'; Value: 'application/vnd.pawaafile'), // do not localize - (Key: 'str'; Value: 'application/vnd.pg.format'), // do not localize - (Key: 'ei6'; Value: 'application/vnd.pg.osasli'), // do not localize - (Key: 'efif'; Value: 'application/vnd.picsel'), // do not localize - (Key: 'wg'; Value: 'application/vnd.pmi.widget'), // do not localize - (Key: 'plf'; Value: 'application/vnd.pocketlearn'), // do not localize - (Key: 'pbd'; Value: 'application/vnd.powerbuilder6'), // do not localize - (Key: 'box'; Value: 'application/vnd.previewsystems.box'), // do not localize - (Key: 'mgz'; Value: 'application/vnd.proteus.magazine'), // do not localize - (Key: 'qps'; Value: 'application/vnd.publishare-delta-tree'), // do not localize - (Key: 'ptid'; Value: 'application/vnd.pvi.ptid1'), // do not localize - (Key: 'qxd'; Value: 'application/vnd.quark.quarkxpress'), // do not localize - (Key: 'qxt'; Value: 'application/vnd.quark.quarkxpress'), // do not localize - (Key: 'qwd'; Value: 'application/vnd.quark.quarkxpress'), // do not localize - (Key: 'qwt'; Value: 'application/vnd.quark.quarkxpress'), // do not localize - (Key: 'qxl'; Value: 'application/vnd.quark.quarkxpress'), // do not localize - (Key: 'qxb'; Value: 'application/vnd.quark.quarkxpress'), // do not localize - (Key: 'bed'; Value: 'application/vnd.realvnc.bed'), // do not localize - (Key: 'mxl'; Value: 'application/vnd.recordare.musicxml'), // do not localize - (Key: 'musicxml'; Value: 'application/vnd.recordare.musicxml+xml'), // do not localize - (Key: 'cryptonote'; Value: 'application/vnd.rig.cryptonote'), // do not localize - (Key: 'cod'; Value: 'application/vnd.rim.cod'), // do not localize - (Key: 'rm'; Value: 'application/vnd.rn-realmedia'), // do not localize - (Key: 'rmvb'; Value: 'application/vnd.rn-realmedia-vbr'), // do not localize - (Key: 'link66'; Value: 'application/vnd.route66.link66+xml'), // do not localize - (Key: 'st'; Value: 'application/vnd.sailingtracker.track'), // do not localize - (Key: 'see'; Value: 'application/vnd.seemail'), // do not localize - (Key: 'sema'; Value: 'application/vnd.sema'), // do not localize - (Key: 'semd'; Value: 'application/vnd.semd'), // do not localize - (Key: 'semf'; Value: 'application/vnd.semf'), // do not localize - (Key: 'ifm'; Value: 'application/vnd.shana.informed.formdata'), // do not localize - (Key: 'itp'; Value: 'application/vnd.shana.informed.formtemplate'), // do not localize - (Key: 'iif'; Value: 'application/vnd.shana.informed.interchange'), // do not localize - (Key: 'ipk'; Value: 'application/vnd.shana.informed.package'), // do not localize - (Key: 'twd'; Value: 'application/vnd.simtech-mindmapper'), // do not localize - (Key: 'twds'; Value: 'application/vnd.simtech-mindmapper'), // do not localize - (Key: 'mmf'; Value: 'application/vnd.smaf'), // do not localize - (Key: 'teacher'; Value: 'application/vnd.smart.teacher'), // do not localize - (Key: 'sdkm'; Value: 'application/vnd.solent.sdkm+xml'), // do not localize - (Key: 'sdkd'; Value: 'application/vnd.solent.sdkm+xml'), // do not localize - (Key: 'dxp'; Value: 'application/vnd.spotfire.dxp'), // do not localize - (Key: 'sfs'; Value: 'application/vnd.spotfire.sfs'), // do not localize - (Key: 'sdc'; Value: 'application/vnd.stardivision.calc'), // do not localize - (Key: 'sda'; Value: 'application/vnd.stardivision.draw'), // do not localize - (Key: 'sdd'; Value: 'application/vnd.stardivision.impress'), // do not localize - (Key: 'smf'; Value: 'application/vnd.stardivision.math'), // do not localize - (Key: 'sdw'; Value: 'application/vnd.stardivision.writer'), // do not localize - (Key: 'vor'; Value: 'application/vnd.stardivision.writer'), // do not localize - (Key: 'sgl'; Value: 'application/vnd.stardivision.writer-global'), // do not localize - (Key: 'smzip'; Value: 'application/vnd.stepmania.package'), // do not localize - (Key: 'sm'; Value: 'application/vnd.stepmania.stepchart'), // do not localize - (Key: 'sxc'; Value: 'application/vnd.sun.xml.calc'), // do not localize - (Key: 'stc'; Value: 'application/vnd.sun.xml.calc.template'), // do not localize - (Key: 'sxd'; Value: 'application/vnd.sun.xml.draw'), // do not localize - (Key: 'std'; Value: 'application/vnd.sun.xml.draw.template'), // do not localize - (Key: 'sxi'; Value: 'application/vnd.sun.xml.impress'), // do not localize - (Key: 'sti'; Value: 'application/vnd.sun.xml.impress.template'), // do not localize - (Key: 'sxm'; Value: 'application/vnd.sun.xml.math'), // do not localize - (Key: 'sxw'; Value: 'application/vnd.sun.xml.writer'), // do not localize - (Key: 'sxg'; Value: 'application/vnd.sun.xml.writer.global'), // do not localize - (Key: 'stw'; Value: 'application/vnd.sun.xml.writer.template'), // do not localize - (Key: 'sus'; Value: 'application/vnd.sus-calendar'), // do not localize - (Key: 'susp'; Value: 'application/vnd.sus-calendar'), // do not localize - (Key: 'svd'; Value: 'application/vnd.svd'), // do not localize - (Key: 'sis'; Value: 'application/vnd.symbian.install'), // do not localize - (Key: 'sisx'; Value: 'application/vnd.symbian.install'), // do not localize - (Key: 'xsm'; Value: 'application/vnd.syncml+xml'), // do not localize - (Key: 'bdm'; Value: 'application/vnd.syncml.dm+wbxml'), // do not localize - (Key: 'xdm'; Value: 'application/vnd.syncml.dm+xml'), // do not localize - (Key: 'tao'; Value: 'application/vnd.tao.intent-module-archive'), // do not localize - (Key: 'pcap'; Value: 'application/vnd.tcpdump.pcap'), // do not localize - (Key: 'cap'; Value: 'application/vnd.tcpdump.pcap'), // do not localize - (Key: 'dmp'; Value: 'application/vnd.tcpdump.pcap'), // do not localize - (Key: 'tmo'; Value: 'application/vnd.tmobile-livetv'), // do not localize - (Key: 'tpt'; Value: 'application/vnd.trid.tpt'), // do not localize - (Key: 'mxs'; Value: 'application/vnd.triscape.mxs'), // do not localize - (Key: 'tra'; Value: 'application/vnd.trueapp'), // do not localize - (Key: 'ufd'; Value: 'application/vnd.ufdl'), // do not localize - (Key: 'ufdl'; Value: 'application/vnd.ufdl'), // do not localize - (Key: 'utz'; Value: 'application/vnd.uiq.theme'), // do not localize - (Key: 'umj'; Value: 'application/vnd.umajin'), // do not localize - (Key: 'unityweb'; Value: 'application/vnd.unity'), // do not localize - (Key: 'uoml'; Value: 'application/vnd.uoml+xml'), // do not localize - (Key: 'vcx'; Value: 'application/vnd.vcx'), // do not localize - (Key: 'vsd'; Value: 'application/vnd.visio'), // do not localize - (Key: 'vst'; Value: 'application/vnd.visio'), // do not localize - (Key: 'vss'; Value: 'application/vnd.visio'), // do not localize - (Key: 'vsw'; Value: 'application/vnd.visio'), // do not localize - (Key: 'vis'; Value: 'application/vnd.visionary'), // do not localize - (Key: 'vsf'; Value: 'application/vnd.vsf'), // do not localize - (Key: 'wbxml'; Value: 'application/vnd.wap.wbxml'), // do not localize - (Key: 'wmlc'; Value: 'application/vnd.wap.wmlc'), // do not localize - (Key: 'wmlsc'; Value: 'application/vnd.wap.wmlscriptc'), // do not localize - (Key: 'wtb'; Value: 'application/vnd.webturbo'), // do not localize - (Key: 'nbp'; Value: 'application/vnd.wolfram.player'), // do not localize - (Key: 'wpd'; Value: 'application/vnd.wordperfect'), // do not localize - (Key: 'wqd'; Value: 'application/vnd.wqd'), // do not localize - (Key: 'stf'; Value: 'application/vnd.wt.stf'), // do not localize - (Key: 'xar'; Value: 'application/vnd.xara'), // do not localize - (Key: 'xfdl'; Value: 'application/vnd.xfdl'), // do not localize - (Key: 'hvd'; Value: 'application/vnd.yamaha.hv-dic'), // do not localize - (Key: 'hvs'; Value: 'application/vnd.yamaha.hv-script'), // do not localize - (Key: 'hvp'; Value: 'application/vnd.yamaha.hv-voice'), // do not localize - (Key: 'osf'; Value: 'application/vnd.yamaha.openscoreformat'), // do not localize - (Key: 'osfpvg'; Value: 'application/vnd.yamaha.openscoreformat.osfpvg+xml'), // do not localize - (Key: 'saf'; Value: 'application/vnd.yamaha.smaf-audio'), // do not localize - (Key: 'spf'; Value: 'application/vnd.yamaha.smaf-phrase'), // do not localize - (Key: 'cmp'; Value: 'application/vnd.yellowriver-custom-menu'), // do not localize - (Key: 'zir'; Value: 'application/vnd.zul'), // do not localize - (Key: 'zirz'; Value: 'application/vnd.zul'), // do not localize - (Key: 'zaz'; Value: 'application/vnd.zzazz.deck+xml'), // do not localize - (Key: 'vxml'; Value: 'application/voicexml+xml'), // do not localize - (Key: 'wgt'; Value: 'application/widget'), // do not localize - (Key: 'hlp'; Value: 'application/winhlp'), // do not localize - (Key: 'wsdl'; Value: 'application/wsdl+xml'), // do not localize - (Key: 'wspolicy'; Value: 'application/wspolicy+xml'), // do not localize - (Key: '7z'; Value: 'application/x-7z-compressed'), // do not localize - (Key: 'abw'; Value: 'application/x-abiword'), // do not localize - (Key: 'ace'; Value: 'application/x-ace-compressed'), // do not localize - (Key: 'dmg'; Value: 'application/x-apple-diskimage'), // do not localize - (Key: 'aab'; Value: 'application/x-authorware-bin'), // do not localize - (Key: 'x32'; Value: 'application/x-authorware-bin'), // do not localize - (Key: 'u32'; Value: 'application/x-authorware-bin'), // do not localize - (Key: 'vox'; Value: 'application/x-authorware-bin'), // do not localize - (Key: 'aam'; Value: 'application/x-authorware-map'), // do not localize - (Key: 'aas'; Value: 'application/x-authorware-seg'), // do not localize - (Key: 'bcpio'; Value: 'application/x-bcpio'), // do not localize - (Key: 'torrent'; Value: 'application/x-bittorrent'), // do not localize - (Key: 'blb'; Value: 'application/x-blorb'), // do not localize - (Key: 'blorb'; Value: 'application/x-blorb'), // do not localize - (Key: 'bz'; Value: 'application/x-bzip'), // do not localize - (Key: 'bz2'; Value: 'application/x-bzip2'), // do not localize - (Key: 'boz'; Value: 'application/x-bzip2'), // do not localize - (Key: 'cbr'; Value: 'application/x-cbr'), // do not localize - (Key: 'cba'; Value: 'application/x-cbr'), // do not localize - (Key: 'cbt'; Value: 'application/x-cbr'), // do not localize - (Key: 'cbz'; Value: 'application/x-cbr'), // do not localize - (Key: 'cb7'; Value: 'application/x-cbr'), // do not localize - (Key: 'vcd'; Value: 'application/x-cdlink'), // do not localize - (Key: 'cfs'; Value: 'application/x-cfs-compressed'), // do not localize - (Key: 'chat'; Value: 'application/x-chat'), // do not localize - (Key: 'pgn'; Value: 'application/x-chess-pgn'), // do not localize - (Key: 'nsc'; Value: 'application/x-conference'), // do not localize - (Key: 'cpio'; Value: 'application/x-cpio'), // do not localize - (Key: 'csh'; Value: 'application/x-csh'), // do not localize - (Key: 'deb'; Value: 'application/x-debian-package'), // do not localize - (Key: 'udeb'; Value: 'application/x-debian-package'), // do not localize - (Key: 'dgc'; Value: 'application/x-dgc-compressed'), // do not localize - (Key: 'dir'; Value: 'application/x-director'), // do not localize - (Key: 'dcr'; Value: 'application/x-director'), // do not localize - (Key: 'dxr'; Value: 'application/x-director'), // do not localize - (Key: 'cst'; Value: 'application/x-director'), // do not localize - (Key: 'cct'; Value: 'application/x-director'), // do not localize - (Key: 'cxt'; Value: 'application/x-director'), // do not localize - (Key: 'w3d'; Value: 'application/x-director'), // do not localize - (Key: 'fgd'; Value: 'application/x-director'), // do not localize - (Key: 'swa'; Value: 'application/x-director'), // do not localize - (Key: 'wad'; Value: 'application/x-doom'), // do not localize - (Key: 'ncx'; Value: 'application/x-dtbncx+xml'), // do not localize - (Key: 'dtb'; Value: 'application/x-dtbook+xml'), // do not localize - (Key: 'res'; Value: 'application/x-dtbresource+xml'), // do not localize - (Key: 'dvi'; Value: 'application/x-dvi'), // do not localize - (Key: 'evy'; Value: 'application/x-envoy'), // do not localize - (Key: 'eva'; Value: 'application/x-eva'), // do not localize - (Key: 'bdf'; Value: 'application/x-font-bdf'), // do not localize - (Key: 'gsf'; Value: 'application/x-font-ghostscript'), // do not localize - (Key: 'psf'; Value: 'application/x-font-linux-psf'), // do not localize - (Key: 'otf'; Value: 'application/x-font-otf'), // do not localize - (Key: 'pcf'; Value: 'application/x-font-pcf'), // do not localize - (Key: 'snf'; Value: 'application/x-font-snf'), // do not localize - (Key: 'ttf'; Value: 'application/x-font-ttf'), // do not localize - (Key: 'ttc'; Value: 'application/x-font-ttf'), // do not localize - (Key: 'pfa'; Value: 'application/x-font-type1'), // do not localize - (Key: 'pfb'; Value: 'application/x-font-type1'), // do not localize - (Key: 'pfm'; Value: 'application/x-font-type1'), // do not localize - (Key: 'afm'; Value: 'application/x-font-type1'), // do not localize - (Key: 'woff'; Value: 'application/x-font-woff'), // do not localize - (Key: 'arc'; Value: 'application/x-freearc'), // do not localize - (Key: 'spl'; Value: 'application/x-futuresplash'), // do not localize - (Key: 'gca'; Value: 'application/x-gca-compressed'), // do not localize - (Key: 'ulx'; Value: 'application/x-glulx'), // do not localize - (Key: 'gnumeric'; Value: 'application/x-gnumeric'), // do not localize - (Key: 'gramps'; Value: 'application/x-gramps-xml'), // do not localize - (Key: 'gtar'; Value: 'application/x-gtar'), // do not localize - (Key: 'hdf'; Value: 'application/x-hdf'), // do not localize - (Key: 'install'; Value: 'application/x-install-instructions'), // do not localize - (Key: 'iso'; Value: 'application/x-iso9660-image'), // do not localize - (Key: 'jnlp'; Value: 'application/x-java-jnlp-file'), // do not localize - (Key: 'latex'; Value: 'application/x-latex'), // do not localize - (Key: 'lzh'; Value: 'application/x-lzh-compressed'), // do not localize - (Key: 'lha'; Value: 'application/x-lzh-compressed'), // do not localize - (Key: 'mie'; Value: 'application/x-mie'), // do not localize - (Key: 'prc'; Value: 'application/x-mobipocket-ebook'), // do not localize - (Key: 'mobi'; Value: 'application/x-mobipocket-ebook'), // do not localize - (Key: 'application'; Value: 'application/x-ms-application'), // do not localize - (Key: 'lnk'; Value: 'application/x-ms-shortcut'), // do not localize - (Key: 'wmd'; Value: 'application/x-ms-wmd'), // do not localize - (Key: 'wmz'; Value: 'application/x-ms-wmz'), // do not localize - (Key: 'xbap'; Value: 'application/x-ms-xbap'), // do not localize - (Key: 'mdb'; Value: 'application/x-msaccess'), // do not localize - (Key: 'obd'; Value: 'application/x-msbinder'), // do not localize - (Key: 'crd'; Value: 'application/x-mscardfile'), // do not localize - (Key: 'clp'; Value: 'application/x-msclip'), // do not localize - (Key: 'exe'; Value: 'application/x-msdownload'), // do not localize - (Key: 'dll'; Value: 'application/x-msdownload'), // do not localize - (Key: 'com'; Value: 'application/x-msdownload'), // do not localize - (Key: 'bat'; Value: 'application/x-msdownload'), // do not localize - (Key: 'msi'; Value: 'application/x-msdownload'), // do not localize - (Key: 'mvb'; Value: 'application/x-msmediaview'), // do not localize - (Key: 'm13'; Value: 'application/x-msmediaview'), // do not localize - (Key: 'm14'; Value: 'application/x-msmediaview'), // do not localize - (Key: 'wmf'; Value: 'application/x-msmetafile'), // do not localize - (Key: 'wmz'; Value: 'application/x-msmetafile'), // do not localize - (Key: 'emf'; Value: 'application/x-msmetafile'), // do not localize - (Key: 'emz'; Value: 'application/x-msmetafile'), // do not localize - (Key: 'mny'; Value: 'application/x-msmoney'), // do not localize - (Key: 'pub'; Value: 'application/x-mspublisher'), // do not localize - (Key: 'scd'; Value: 'application/x-msschedule'), // do not localize - (Key: 'trm'; Value: 'application/x-msterminal'), // do not localize - (Key: 'wri'; Value: 'application/x-mswrite'), // do not localize - (Key: 'nc'; Value: 'application/x-netcdf'), // do not localize - (Key: 'cdf'; Value: 'application/x-netcdf'), // do not localize - (Key: 'nzb'; Value: 'application/x-nzb'), // do not localize - (Key: 'p12'; Value: 'application/x-pkcs12'), // do not localize - (Key: 'pfx'; Value: 'application/x-pkcs12'), // do not localize - (Key: 'p7b'; Value: 'application/x-pkcs7-certificates'), // do not localize - (Key: 'spc'; Value: 'application/x-pkcs7-certificates'), // do not localize - (Key: 'p7r'; Value: 'application/x-pkcs7-certreqresp'), // do not localize - (Key: 'rar'; Value: 'application/x-rar-compressed'), // do not localize - (Key: 'ris'; Value: 'application/x-research-info-systems'), // do not localize - (Key: 'sh'; Value: 'application/x-sh'), // do not localize - (Key: 'shar'; Value: 'application/x-shar'), // do not localize - (Key: 'swf'; Value: 'application/x-shockwave-flash'), // do not localize - (Key: 'xap'; Value: 'application/x-silverlight-app'), // do not localize - (Key: 'sql'; Value: 'application/x-sql'), // do not localize - (Key: 'sit'; Value: 'application/x-stuffit'), // do not localize - (Key: 'sitx'; Value: 'application/x-stuffitx'), // do not localize - (Key: 'srt'; Value: 'application/x-subrip'), // do not localize - (Key: 'sv4cpio'; Value: 'application/x-sv4cpio'), // do not localize - (Key: 'sv4crc'; Value: 'application/x-sv4crc'), // do not localize - (Key: 't3'; Value: 'application/x-t3vm-image'), // do not localize - (Key: 'gam'; Value: 'application/x-tads'), // do not localize - (Key: 'tar'; Value: 'application/x-tar'), // do not localize - (Key: 'tcl'; Value: 'application/x-tcl'), // do not localize - (Key: 'tex'; Value: 'application/x-tex'), // do not localize - (Key: 'tfm'; Value: 'application/x-tex-tfm'), // do not localize - (Key: 'texinfo'; Value: 'application/x-texinfo'), // do not localize - (Key: 'texi'; Value: 'application/x-texinfo'), // do not localize - (Key: 'obj'; Value: 'application/x-tgif'), // do not localize - (Key: 'ustar'; Value: 'application/x-ustar'), // do not localize - (Key: 'src'; Value: 'application/x-wais-source'), // do not localize - (Key: 'der'; Value: 'application/x-x509-ca-cert'), // do not localize - (Key: 'crt'; Value: 'application/x-x509-ca-cert'), // do not localize - (Key: 'fig'; Value: 'application/x-xfig'), // do not localize - (Key: 'xlf'; Value: 'application/x-xliff+xml'), // do not localize - (Key: 'xpi'; Value: 'application/x-xpinstall'), // do not localize - (Key: 'xz'; Value: 'application/x-xz'), // do not localize - (Key: 'z1'; Value: 'application/x-zmachine'), // do not localize - (Key: 'z2'; Value: 'application/x-zmachine'), // do not localize - (Key: 'z3'; Value: 'application/x-zmachine'), // do not localize - (Key: 'z4'; Value: 'application/x-zmachine'), // do not localize - (Key: 'z5'; Value: 'application/x-zmachine'), // do not localize - (Key: 'z6'; Value: 'application/x-zmachine'), // do not localize - (Key: 'z7'; Value: 'application/x-zmachine'), // do not localize - (Key: 'z8'; Value: 'application/x-zmachine'), // do not localize - (Key: 'xaml'; Value: 'application/xaml+xml'), // do not localize - (Key: 'xdf'; Value: 'application/xcap-diff+xml'), // do not localize - (Key: 'xenc'; Value: 'application/xenc+xml'), // do not localize - (Key: 'xhtml'; Value: 'application/xhtml+xml'), // do not localize - (Key: 'xht'; Value: 'application/xhtml+xml'), // do not localize - (Key: 'xml'; Value: 'application/xml'), // do not localize - (Key: 'xsl'; Value: 'application/xml'), // do not localize - (Key: 'dtd'; Value: 'application/xml-dtd'), // do not localize - (Key: 'xop'; Value: 'application/xop+xml'), // do not localize - (Key: 'xpl'; Value: 'application/xproc+xml'), // do not localize - (Key: 'xslt'; Value: 'application/xslt+xml'), // do not localize - (Key: 'xspf'; Value: 'application/xspf+xml'), // do not localize - (Key: 'mxml'; Value: 'application/xv+xml'), // do not localize - (Key: 'xhvml'; Value: 'application/xv+xml'), // do not localize - (Key: 'xvml'; Value: 'application/xv+xml'), // do not localize - (Key: 'xvm'; Value: 'application/xv+xml'), // do not localize - (Key: 'yang'; Value: 'application/yang'), // do not localize - (Key: 'yin'; Value: 'application/yin+xml'), // do not localize - (Key: 'zip'; Value: 'application/zip'), // do not localize - (Key: 'adp'; Value: 'audio/adpcm'), // do not localize - (Key: 'au'; Value: 'audio/basic'), // do not localize - (Key: 'snd'; Value: 'audio/basic'), // do not localize - (Key: 'mid'; Value: 'audio/midi'), // do not localize - (Key: 'midi'; Value: 'audio/midi'), // do not localize - (Key: 'kar'; Value: 'audio/midi'), // do not localize - (Key: 'rmi'; Value: 'audio/midi'), // do not localize - (Key: 'mp4a'; Value: 'audio/mp4'), // do not localize - (Key: 'mpga'; Value: 'audio/mpeg'), // do not localize - (Key: 'mp2'; Value: 'audio/mpeg'), // do not localize - (Key: 'mp2a'; Value: 'audio/mpeg'), // do not localize - (Key: 'mp3'; Value: 'audio/mpeg'), // do not localize - (Key: 'm2a'; Value: 'audio/mpeg'), // do not localize - (Key: 'm3a'; Value: 'audio/mpeg'), // do not localize - (Key: 'oga'; Value: 'audio/ogg'), // do not localize - (Key: 'ogg'; Value: 'audio/ogg'), // do not localize - (Key: 'spx'; Value: 'audio/ogg'), // do not localize - (Key: 's3m'; Value: 'audio/s3m'), // do not localize - (Key: 'sil'; Value: 'audio/silk'), // do not localize - (Key: 'uva'; Value: 'audio/vnd.dece.audio'), // do not localize - (Key: 'uvva'; Value: 'audio/vnd.dece.audio'), // do not localize - (Key: 'eol'; Value: 'audio/vnd.digital-winds'), // do not localize - (Key: 'dra'; Value: 'audio/vnd.dra'), // do not localize - (Key: 'dts'; Value: 'audio/vnd.dts'), // do not localize - (Key: 'dtshd'; Value: 'audio/vnd.dts.hd'), // do not localize - (Key: 'lvp'; Value: 'audio/vnd.lucent.voice'), // do not localize - (Key: 'pya'; Value: 'audio/vnd.ms-playready.media.pya'), // do not localize - (Key: 'ecelp4800'; Value: 'audio/vnd.nuera.ecelp4800'), // do not localize - (Key: 'ecelp7470'; Value: 'audio/vnd.nuera.ecelp7470'), // do not localize - (Key: 'ecelp9600'; Value: 'audio/vnd.nuera.ecelp9600'), // do not localize - (Key: 'rip'; Value: 'audio/vnd.rip'), // do not localize - (Key: 'weba'; Value: 'audio/webm'), // do not localize - (Key: 'aac'; Value: 'audio/x-aac'), // do not localize - (Key: 'aif'; Value: 'audio/x-aiff'), // do not localize - (Key: 'aiff'; Value: 'audio/x-aiff'), // do not localize - (Key: 'aifc'; Value: 'audio/x-aiff'), // do not localize - (Key: 'caf'; Value: 'audio/x-caf'), // do not localize - (Key: 'flac'; Value: 'audio/x-flac'), // do not localize - (Key: 'mka'; Value: 'audio/x-matroska'), // do not localize - (Key: 'm3u'; Value: 'audio/x-mpegurl'), // do not localize - (Key: 'wax'; Value: 'audio/x-ms-wax'), // do not localize - (Key: 'wma'; Value: 'audio/x-ms-wma'), // do not localize - (Key: 'ram'; Value: 'audio/x-pn-realaudio'), // do not localize - (Key: 'ra'; Value: 'audio/x-pn-realaudio'), // do not localize - (Key: 'rmp'; Value: 'audio/x-pn-realaudio-plugin'), // do not localize - (Key: 'wav'; Value: 'audio/x-wav'), // do not localize - (Key: 'xm'; Value: 'audio/xm'), // do not localize - (Key: 'cdx'; Value: 'chemical/x-cdx'), // do not localize - (Key: 'cif'; Value: 'chemical/x-cif'), // do not localize - (Key: 'cmdf'; Value: 'chemical/x-cmdf'), // do not localize - (Key: 'cml'; Value: 'chemical/x-cml'), // do not localize - (Key: 'csml'; Value: 'chemical/x-csml'), // do not localize - (Key: 'xyz'; Value: 'chemical/x-xyz'), // do not localize - (Key: 'bmp'; Value: 'image/bmp'), // do not localize - (Key: 'cgm'; Value: 'image/cgm'), // do not localize - (Key: 'g3'; Value: 'image/g3fax'), // do not localize - (Key: 'gif'; Value: 'image/gif'), // do not localize - (Key: 'ief'; Value: 'image/ief'), // do not localize - (Key: 'jpeg'; Value: 'image/jpeg'), // do not localize - (Key: 'jpg'; Value: 'image/jpeg'), // do not localize - (Key: 'jpe'; Value: 'image/jpeg'), // do not localize - (Key: 'ktx'; Value: 'image/ktx'), // do not localize - (Key: 'png'; Value: 'image/png'), // do not localize - (Key: 'btif'; Value: 'image/prs.btif'), // do not localize - (Key: 'sgi'; Value: 'image/sgi'), // do not localize - (Key: 'svg'; Value: 'image/svg+xml'), // do not localize - (Key: 'svgz'; Value: 'image/svg+xml'), // do not localize - (Key: 'tiff'; Value: 'image/tiff'), // do not localize - (Key: 'tif'; Value: 'image/tiff'), // do not localize - (Key: 'psd'; Value: 'image/vnd.adobe.photoshop'), // do not localize - (Key: 'uvi'; Value: 'image/vnd.dece.graphic'), // do not localize - (Key: 'uvvi'; Value: 'image/vnd.dece.graphic'), // do not localize - (Key: 'uvg'; Value: 'image/vnd.dece.graphic'), // do not localize - (Key: 'uvvg'; Value: 'image/vnd.dece.graphic'), // do not localize - (Key: 'sub'; Value: 'image/vnd.dvb.subtitle'), // do not localize - (Key: 'djvu'; Value: 'image/vnd.djvu'), // do not localize - (Key: 'djv'; Value: 'image/vnd.djvu'), // do not localize - (Key: 'dwg'; Value: 'image/vnd.dwg'), // do not localize - (Key: 'dxf'; Value: 'image/vnd.dxf'), // do not localize - (Key: 'fbs'; Value: 'image/vnd.fastbidsheet'), // do not localize - (Key: 'fpx'; Value: 'image/vnd.fpx'), // do not localize - (Key: 'fst'; Value: 'image/vnd.fst'), // do not localize - (Key: 'mmr'; Value: 'image/vnd.fujixerox.edmics-mmr'), // do not localize - (Key: 'rlc'; Value: 'image/vnd.fujixerox.edmics-rlc'), // do not localize - (Key: 'mdi'; Value: 'image/vnd.ms-modi'), // do not localize - (Key: 'wdp'; Value: 'image/vnd.ms-photo'), // do not localize - (Key: 'npx'; Value: 'image/vnd.net-fpx'), // do not localize - (Key: 'wbmp'; Value: 'image/vnd.wap.wbmp'), // do not localize - (Key: 'xif'; Value: 'image/vnd.xiff'), // do not localize - (Key: 'webp'; Value: 'image/webp'), // do not localize - (Key: '3ds'; Value: 'image/x-3ds'), // do not localize - (Key: 'ras'; Value: 'image/x-cmu-raster'), // do not localize - (Key: 'cmx'; Value: 'image/x-cmx'), // do not localize - (Key: 'fh'; Value: 'image/x-freehand'), // do not localize - (Key: 'fhc'; Value: 'image/x-freehand'), // do not localize - (Key: 'fh4'; Value: 'image/x-freehand'), // do not localize - (Key: 'fh5'; Value: 'image/x-freehand'), // do not localize - (Key: 'fh7'; Value: 'image/x-freehand'), // do not localize - (Key: 'ico'; Value: 'image/x-icon'), // do not localize - (Key: 'sid'; Value: 'image/x-mrsid-image'), // do not localize - (Key: 'pcx'; Value: 'image/x-pcx'), // do not localize - (Key: 'pic'; Value: 'image/x-pict'), // do not localize - (Key: 'pct'; Value: 'image/x-pict'), // do not localize - (Key: 'pnm'; Value: 'image/x-portable-anymap'), // do not localize - (Key: 'pbm'; Value: 'image/x-portable-bitmap'), // do not localize - (Key: 'pgm'; Value: 'image/x-portable-graymap'), // do not localize - (Key: 'ppm'; Value: 'image/x-portable-pixmap'), // do not localize - (Key: 'rgb'; Value: 'image/x-rgb'), // do not localize - (Key: 'tga'; Value: 'image/x-tga'), // do not localize - (Key: 'xbm'; Value: 'image/x-xbitmap'), // do not localize - (Key: 'xpm'; Value: 'image/x-xpixmap'), // do not localize - (Key: 'xwd'; Value: 'image/x-xwindowdump'), // do not localize - (Key: 'eml'; Value: 'message/rfc822'), // do not localize - (Key: 'mime'; Value: 'message/rfc822'), // do not localize - (Key: 'igs'; Value: 'model/iges'), // do not localize - (Key: 'iges'; Value: 'model/iges'), // do not localize - (Key: 'msh'; Value: 'model/mesh'), // do not localize - (Key: 'mesh'; Value: 'model/mesh'), // do not localize - (Key: 'silo'; Value: 'model/mesh'), // do not localize - (Key: 'dae'; Value: 'model/vnd.collada+xml'), // do not localize - (Key: 'dwf'; Value: 'model/vnd.dwf'), // do not localize - (Key: 'gdl'; Value: 'model/vnd.gdl'), // do not localize - (Key: 'gtw'; Value: 'model/vnd.gtw'), // do not localize - (Key: 'mts'; Value: 'model/vnd.mts'), // do not localize - (Key: 'vtu'; Value: 'model/vnd.vtu'), // do not localize - (Key: 'wrl'; Value: 'model/vrml'), // do not localize - (Key: 'vrml'; Value: 'model/vrml'), // do not localize - (Key: 'x3db'; Value: 'model/x3d+binary'), // do not localize - (Key: 'x3dbz'; Value: 'model/x3d+binary'), // do not localize - (Key: 'x3dv'; Value: 'model/x3d+vrml'), // do not localize - (Key: 'x3dvz'; Value: 'model/x3d+vrml'), // do not localize - (Key: 'x3d'; Value: 'model/x3d+xml'), // do not localize - (Key: 'x3dz'; Value: 'model/x3d+xml'), // do not localize - (Key: 'appcache'; Value: 'text/cache-manifest'), // do not localize - (Key: 'ics'; Value: 'text/calendar'), // do not localize - (Key: 'ifb'; Value: 'text/calendar'), // do not localize - (Key: 'css'; Value: 'text/css'), // do not localize - (Key: 'csv'; Value: 'text/csv'), // do not localize - (Key: 'html'; Value: 'text/html'), // do not localize - (Key: 'htm'; Value: 'text/html'), // do not localize - (Key: 'n3'; Value: 'text/n3'), // do not localize - (Key: 'txt'; Value: 'text/plain'), // do not localize - (Key: 'text'; Value: 'text/plain'), // do not localize - (Key: 'conf'; Value: 'text/plain'), // do not localize - (Key: 'def'; Value: 'text/plain'), // do not localize - (Key: 'list'; Value: 'text/plain'), // do not localize - (Key: 'log'; Value: 'text/plain'), // do not localize - (Key: 'in'; Value: 'text/plain'), // do not localize - (Key: 'dsc'; Value: 'text/prs.lines.tag'), // do not localize - (Key: 'rtx'; Value: 'text/richtext'), // do not localize - (Key: 'sgml'; Value: 'text/sgml'), // do not localize - (Key: 'sgm'; Value: 'text/sgml'), // do not localize - (Key: 'tsv'; Value: 'text/tab-separated-values'), // do not localize - (Key: 't'; Value: 'text/troff'), // do not localize - (Key: 'tr'; Value: 'text/troff'), // do not localize - (Key: 'roff'; Value: 'text/troff'), // do not localize - (Key: 'man'; Value: 'text/troff'), // do not localize - (Key: 'me'; Value: 'text/troff'), // do not localize - (Key: 'ms'; Value: 'text/troff'), // do not localize - (Key: 'ttl'; Value: 'text/turtle'), // do not localize - (Key: 'uri'; Value: 'text/uri-list'), // do not localize - (Key: 'uris'; Value: 'text/uri-list'), // do not localize - (Key: 'urls'; Value: 'text/uri-list'), // do not localize - (Key: 'vcard'; Value: 'text/vcard'), // do not localize - (Key: 'curl'; Value: 'text/vnd.curl'), // do not localize - (Key: 'dcurl'; Value: 'text/vnd.curl.dcurl'), // do not localize - (Key: 'scurl'; Value: 'text/vnd.curl.scurl'), // do not localize - (Key: 'mcurl'; Value: 'text/vnd.curl.mcurl'), // do not localize - (Key: 'sub'; Value: 'text/vnd.dvb.subtitle'), // do not localize - (Key: 'fly'; Value: 'text/vnd.fly'), // do not localize - (Key: 'flx'; Value: 'text/vnd.fmi.flexstor'), // do not localize - (Key: 'gv'; Value: 'text/vnd.graphviz'), // do not localize - (Key: '3dml'; Value: 'text/vnd.in3d.3dml'), // do not localize - (Key: 'spot'; Value: 'text/vnd.in3d.spot'), // do not localize - (Key: 'jad'; Value: 'text/vnd.sun.j2me.app-descriptor'), // do not localize - (Key: 'wml'; Value: 'text/vnd.wap.wml'), // do not localize - (Key: 'wmls'; Value: 'text/vnd.wap.wmlscript'), // do not localize - (Key: 's'; Value: 'text/x-asm'), // do not localize - (Key: 'asm'; Value: 'text/x-asm'), // do not localize - (Key: 'c'; Value: 'text/x-c'), // do not localize - (Key: 'cc'; Value: 'text/x-c'), // do not localize - (Key: 'cxx'; Value: 'text/x-c'), // do not localize - (Key: 'cpp'; Value: 'text/x-c'), // do not localize - (Key: 'h'; Value: 'text/x-c'), // do not localize - (Key: 'hh'; Value: 'text/x-c'), // do not localize - (Key: 'dic'; Value: 'text/x-c'), // do not localize - (Key: 'f'; Value: 'text/x-fortran'), // do not localize - (Key: 'for'; Value: 'text/x-fortran'), // do not localize - (Key: 'f77'; Value: 'text/x-fortran'), // do not localize - (Key: 'f90'; Value: 'text/x-fortran'), // do not localize - (Key: 'java'; Value: 'text/x-java-source'), // do not localize - (Key: 'opml'; Value: 'text/x-opml'), // do not localize - (Key: 'p'; Value: 'text/x-pascal'), // do not localize - (Key: 'pas'; Value: 'text/x-pascal'), // do not localize - (Key: 'nfo'; Value: 'text/x-nfo'), // do not localize - (Key: 'etx'; Value: 'text/x-setext'), // do not localize - (Key: 'sfv'; Value: 'text/x-sfv'), // do not localize - (Key: 'uu'; Value: 'text/x-uuencode'), // do not localize - (Key: 'vcs'; Value: 'text/x-vcalendar'), // do not localize - (Key: 'vcf'; Value: 'text/x-vcard'), // do not localize - (Key: '3gp'; Value: 'video/3gpp'), // do not localize - (Key: '3g2'; Value: 'video/3gpp2'), // do not localize - (Key: 'h261'; Value: 'video/h261'), // do not localize - (Key: 'h263'; Value: 'video/h263'), // do not localize - (Key: 'h264'; Value: 'video/h264'), // do not localize - (Key: 'jpgv'; Value: 'video/jpeg'), // do not localize - (Key: 'jpm'; Value: 'video/jpm'), // do not localize - (Key: 'jpgm'; Value: 'video/jpm'), // do not localize - (Key: 'mj2'; Value: 'video/mj2'), // do not localize - (Key: 'mjp2'; Value: 'video/mj2'), // do not localize - (Key: 'mp4'; Value: 'video/mp4'), // do not localize - (Key: 'mp4v'; Value: 'video/mp4'), // do not localize - (Key: 'mpg4'; Value: 'video/mp4'), // do not localize - (Key: 'mpeg'; Value: 'video/mpeg'), // do not localize - (Key: 'mpg'; Value: 'video/mpeg'), // do not localize - (Key: 'mpe'; Value: 'video/mpeg'), // do not localize - (Key: 'm1v'; Value: 'video/mpeg'), // do not localize - (Key: 'm2v'; Value: 'video/mpeg'), // do not localize - (Key: 'ogv'; Value: 'video/ogg'), // do not localize - (Key: 'qt'; Value: 'video/quicktime'), // do not localize - (Key: 'mov'; Value: 'video/quicktime'), // do not localize - (Key: 'uvh'; Value: 'video/vnd.dece.hd'), // do not localize - (Key: 'uvvh'; Value: 'video/vnd.dece.hd'), // do not localize - (Key: 'uvm'; Value: 'video/vnd.dece.mobile'), // do not localize - (Key: 'uvvm'; Value: 'video/vnd.dece.mobile'), // do not localize - (Key: 'uvp'; Value: 'video/vnd.dece.pd'), // do not localize - (Key: 'uvvp'; Value: 'video/vnd.dece.pd'), // do not localize - (Key: 'uvs'; Value: 'video/vnd.dece.sd'), // do not localize - (Key: 'uvvs'; Value: 'video/vnd.dece.sd'), // do not localize - (Key: 'uvv'; Value: 'video/vnd.dece.video'), // do not localize - (Key: 'uvvv'; Value: 'video/vnd.dece.video'), // do not localize - (Key: 'dvb'; Value: 'video/vnd.dvb.file'), // do not localize - (Key: 'fvt'; Value: 'video/vnd.fvt'), // do not localize - (Key: 'mxu'; Value: 'video/vnd.mpegurl'), // do not localize - (Key: 'm4u'; Value: 'video/vnd.mpegurl'), // do not localize - (Key: 'pyv'; Value: 'video/vnd.ms-playready.media.pyv'), // do not localize - (Key: 'uvu'; Value: 'video/vnd.uvvu.mp4'), // do not localize - (Key: 'uvvu'; Value: 'video/vnd.uvvu.mp4'), // do not localize - (Key: 'viv'; Value: 'video/vnd.vivo'), // do not localize - (Key: 'webm'; Value: 'video/webm'), // do not localize - (Key: 'f4v'; Value: 'video/x-f4v'), // do not localize - (Key: 'fli'; Value: 'video/x-fli'), // do not localize - (Key: 'flv'; Value: 'video/x-flv'), // do not localize - (Key: 'm4v'; Value: 'video/x-m4v'), // do not localize - (Key: 'mkv'; Value: 'video/x-matroska'), // do not localize - (Key: 'mk3d'; Value: 'video/x-matroska'), // do not localize - (Key: 'mks'; Value: 'video/x-matroska'), // do not localize - (Key: 'mng'; Value: 'video/x-mng'), // do not localize - (Key: 'asf'; Value: 'video/x-ms-asf'), // do not localize - (Key: 'asx'; Value: 'video/x-ms-asf'), // do not localize - (Key: 'vob'; Value: 'video/x-ms-vob'), // do not localize - (Key: 'wm'; Value: 'video/x-ms-wm'), // do not localize - (Key: 'wmv'; Value: 'video/x-ms-wmv'), // do not localize - (Key: 'wmx'; Value: 'video/x-ms-wmx'), // do not localize - (Key: 'wvx'; Value: 'video/x-ms-wvx'), // do not localize - (Key: 'avi'; Value: 'video/x-msvideo'), // do not localize - (Key: 'movie'; Value: 'video/x-sgi-movie'), // do not localize - (Key: 'smv'; Value: 'video/x-smv'), // do not localize - (Key: 'ice'; Value: 'x-conference/x-cooltalk'), // do not localize - (Key: 'wasm'; Value: 'application/wasm') // do not localize - ); - {$ENDREGION} - -type - THttpMethod = class - public const - GET = 'GET'; - POST = 'POST'; - PUT = 'PUT'; - DELETE = 'DELETE'; - HEAD = 'HEAD'; - OPTIONS = 'OPTIONS'; - TRACE = 'TRACE'; - CONNECT = 'CONNECT'; - PROPFIND = 'PROPFIND'; - LOCK = 'LOCK'; - UNLOCK = 'UNLOCK'; - COPY = 'COPY'; - MOVE = 'MOVE'; - MKCOL = 'MKCOL'; - end; - - {$REGION 'Documentation'} - /// - /// 常用媒体类型 - /// - {$ENDREGION} - TMediaType = class - public const - DELIM_PARAMS = '; '; - CHARSET_NAME = 'charset'; - CHARSET_UTF8 = 'UTF-8'; - CHARSET_UTF8_DEF = CHARSET_NAME + '=' + CHARSET_UTF8; - - TEXT_PLAIN = 'text/plain'; - TEXT_PLAIN_UTF8 = TEXT_PLAIN + DELIM_PARAMS + CHARSET_UTF8_DEF; - - TEXT_XML = 'text/xml'; - TEXT_XML_UTF8 = TEXT_XML + DELIM_PARAMS + CHARSET_UTF8_DEF; - - TEXT_HTML = 'text/html'; - TEXT_HTML_UTF8 = TEXT_HTML + DELIM_PARAMS + CHARSET_UTF8_DEF; - - APPLICATION_JSON = 'application/json'; - APPLICATION_JSON_UTF8 = APPLICATION_JSON + DELIM_PARAMS + CHARSET_UTF8_DEF; - - APPLICATION_XML = 'application/xml'; - APPLICATION_XML_UTF8 = APPLICATION_XML + DELIM_PARAMS + CHARSET_UTF8_DEF; - - APPLICATION_OCTET_STREAM = 'application/octet-stream'; - APPLICATION_FORM_URLENCODED_TYPE = 'application/x-www-form-urlencoded'; - - MULTIPART_FORM_DATA = 'multipart/form-data'; - MULTIPART_FORM_DATA_BOUNDARY = MULTIPART_FORM_DATA + DELIM_PARAMS + 'boundary='; - - WILDCARD = '*/*'; - end; - - TCrossHttpUtils = class - private const - RFC1123_StrWeekDay: string = 'MonTueWedThuFriSatSun'; - RFC1123_StrMonth : string = 'JanFebMarAprMayJunJulAugSepOctNovDec'; - public - class function GetHttpStatusText(const AStatusCode: Integer): string; static; - class function GetFileMIMEType(const AFileName: string): string; static; - class function RFC1123_DateToStr(const ADate: TDateTime): string; static; inline; - class function RFC1123_StrToDate(const ADateStr: string): TDateTime; static; - - class function ExtractUrl(const AUrl: string; out AProtocol, AHost: string; - out APort: Word; out APath: string): Boolean; static; - class function CreateUrl(const AProtocol, AHost: string; - const APort: Word; const APath: string): string; static; - - class function CombinePath(const APath1, APath2: string; const APathDelim: Char = '/'): string; static; - class function IsSamePath(const APath1, APath2: string): Boolean; static; - - class function GetPathWithoutParams(const APath: string): string; static; - - /// - /// 尝试解析本地路径,确保路径安全性 - /// - /// - /// 本地基础目录 - /// - /// - /// 要解析的相对路径 - /// - /// - /// 解析后的完整路径 - /// - /// - /// 如果路径有效且在基础目录内返回True,否则返回False - /// - /// - /// 此函数会验证路径的安全性,防止路径遍历攻击 - /// - class function TryUrlPathToLocalPath(const ALocalBaseDir, AUrlPath: string; - out AResolvedPath: string): Boolean; static; - - class function HtmlEncode(const AInput: string): string; static; - class function HtmlDecode(const AInput: string): string; static; - - /// - /// URL percent-encoding (RFC 3986 §2.1) - /// - /// - /// 待编码字符串(支持 unicode, 内部统一按 UTF-8 字节流处理) - /// - /// - /// 附加的"无需编码"字符集. 默认仅按 RFC 3986 unreserved 集 - /// (ALPHA / DIGIT / "-" / "." / "_" / "~") 不编码, 其他字符全部 percent-encode. - /// 调用方可据 URI 组件传入合理子集, 如 path 段内可保留 ['/', ':', '@']. - /// - /// - /// 是否将输入按"已含 percent-encoded 序列的 URI 组件"对待 (Normalizer 语义). - /// - False (默认, Encoder 语义): 输入视作原始数据, '%' 字符按字面编码为 '%25'. - /// 适用于参数值/表单字段等"原始字节"场景. 与 RFC 3986 §2.1 Encoder 语义、 - /// 主流库 (Go QueryEscape / Python quote / Java URLEncoder) 默认行为一致. - /// - True (Normalizer 语义): 遇到 '%' + 2 hex 数字时保留 3 字符不再编码, - /// 避免二次编码 (RFC 3986 §2.4 "MUST NOT encode the same string more than once"). - /// 适用于"用户传入的 URL 片段可能已部分编码"场景, 类似 Python requote_uri. - /// - class function UrlEncode(const S: string; const ANoConversion: TSysCharSet = []; - const APreserveEncoded: Boolean = False): string; static; - class function UrlDecode(const S: string): string; static; - - // Delphi 12+ 编译器将NativeInt与Integer(目标32位)和Int64(目标64位)等同 - {$IF DEFINED(DELPHI) AND (CompilerVersion < 36)} - class procedure AdjustOffsetCount(const ABodySize: NativeInt; var AOffset, ACount: NativeInt); overload; static; - {$ENDIF} - class procedure AdjustOffsetCount(const ABodySize: Integer; var AOffset, ACount: Integer); overload; static; - class procedure AdjustOffsetCount(const ABodySize: Int64; var AOffset, ACount: Int64); overload; static; - - /// - /// 严格解析 HTTP Range 请求头中的单一 byte-range (RFC 7233 §2.1, §3.1). - /// - /// - /// 原始 Range 头, 如 "bytes=0-499" / "bytes=500-" / "bytes=-200". - /// - /// - /// 资源完整长度, 必须 > 0. - /// - /// - /// 解析成功时, 输出区间起点 (含, 0-based). - /// - /// - /// 解析成功时, 输出区间终点 (含, 0-based, < AContentLength). - /// - /// - /// True: 区间合法且可满足, AStart/AEnd 已正确设置. - /// False: 缺前缀 / 多 range / 非法数字 / 不可满足 (start > end / start >= size / - /// suffix=0). 调用方应返回 416 + "Content-Range: bytes */size". - /// - /// - /// 不支持 multipart/byteranges (含 ',' 一律拒绝), 与 Nginx/Apache 在小文件上的常见策略一致. - /// - class function ParseSingleByteRange(const ARangeHeader: string; - const AContentLength: Int64; out AStart, AEnd: Int64): Boolean; static; - - /// - /// 校验 HTTP header field-value 是否安全, 不允许出现 CR/LF (RFC 7230 §3.2.4). - /// - /// - /// 主要用于防御响应拆分 (HTTP Response Splitting) 攻击: 若业务把含 CR/LF 的用户输入 - /// 写入响应 header, 可能被攻击者注入伪造响应行或 header. - /// - class function IsValidHeaderValue(const AValue: string): Boolean; static; - - /// - /// 校验 HTTP header field-name 是否符合 RFC 7230 token 字符集. - /// - class function IsValidHeaderName(const AName: string): Boolean; static; - - /// - /// 单字符版本: 判断字符是否属于 RFC 7230 §3.2.6 token 字符集. - /// - /// - /// token = ALPHA / DIGIT / "!" "#" "$" "%" "&" "'" "*" "+" "-" "." "^" "_" "`" "|" "~" - /// 提供给逐字节扫描场景 (如 THttpHeader.Decode 单趟状态机) 复用规则, 避免重复定义. - /// - class function IsTokenChar(ACh: Char): Boolean; static; inline; - - /// - /// 单字符版本: 判断字符是否是合法的 HTTP header field-value 字符. - /// - /// - /// 合法: HTAB(#9) / 可见 ASCII ($20..$7E) / $80+ 高位字符 (历史宽松, 兼容 UTF-8). - /// 非法: NUL/CR/LF 等其他 CTL ($00..$08, $0A..$1F) 与 DEL ($7F). - /// 提供给逐字节扫描场景复用规则, 避免重复定义. - /// - class function IsHeaderValueChar(ACh: Char): Boolean; static; inline; - end; - -implementation - -{ TCrossHttpUtils } - -class function TCrossHttpUtils.GetHttpStatusText(const AStatusCode: Integer): string; -var - LStatusItem: THttpStatus; -begin - for LStatusItem in STATUS_CODES do - if (LStatusItem.Code = AStatusCode) then Exit(LStatusItem.Text); - Result := AStatusCode.ToString; -end; - -class function TCrossHttpUtils.GetPathWithoutParams( - const APath: string): string; -var - LIndex: Integer; -begin - LIndex := APath.IndexOf('?'); - if (LIndex >= 0) then - Result := APath.Substring(0, LIndex) - else - Result := APath; -end; - -class function TCrossHttpUtils.HtmlDecode(const AInput: string): string; -var - LSp, LRp, LCp, LTp: PChar; - LStr: string; - I, LCode: Integer; - LValid: Boolean; -begin - if (AInput = '') then Exit(''); - - SetLength(Result, Length(AInput)); - LSp := PChar(AInput); - LRp := PChar(Result); - while LSp^ <> #0 do - begin - case LSp^ of - '&': - begin - LCp := LSp; - Inc(LSp); - LValid := False; - case LSp^ of - 'a': - if StrLComp(LSp, 'amp;', 4) = 0 then { do not localize } - begin - Inc(LSp, 3); - LRp^ := '&'; - LValid := True; - end - else if StrLComp(LSp, 'apos;', 5) = 0 then { do not localize } - begin - Inc(LSp, 4); - LRp^ := ''''; - LValid := True; - end; - 'l': - if StrLComp(LSp, 'lt;', 3) = 0 then { do not localize } - begin - Inc(LSp, 2); - LRp^ := '<'; - LValid := True; - end; - 'g': - if StrLComp(LSp, 'gt;', 3) = 0 then { do not localize } - begin - Inc(LSp, 2); - LRp^ := '>'; - LValid := True; - end; - 'q': - if StrLComp(LSp, 'quot;', 5) = 0 then { do not localize } - begin - Inc(LSp, 4); - LRp^ := '"'; - LValid := True; - end; - '#': - begin - LTp := LSp; - Inc(LTp); - while (LSp^ <> ';') and (LSp^ <> #0) do - Inc(LSp); - SetString(LStr, LTp, LSp - LTp); - Val(LStr, I, LCode); - if LCode = 0 then - begin - if I >= $10000 then - begin - // DoDecode surrogate pair - LRp^ := Char(((I - $10000) div $400) + $D800); - Inc(LRp); - LRp^ := Char(((I - $10000) and $3FF) + $DC00); - end - else - LRp^ := Chr((I)); - LValid := True; - end - else - LSp := LTp - 1; - end; - end; - if not LValid then - begin - LSp := LCp; - LRp^ := LSp^; - end; - end - else - LRp^ := LSp^; - end; - Inc(LRp); - Inc(LSp); - end; - SetLength(Result, LRp - PChar(Result)); -end; - -class function TCrossHttpUtils.HtmlEncode(const AInput: string): string; -var - LSp, LRp: PChar; -begin - if (AInput = '') then Exit(''); - - SetLength(Result, Length(AInput) * 10); - LSp := PChar(AInput); - LRp := PChar(Result); - // Convert: &, <, >, " - while LSp^ <> #0 do - begin - case LSp^ of - '&': - begin - StrMove(LRp, '&', 5); - Inc(LRp, 5); - end; - '<': - begin - StrMove(LRp, '<', 4); - Inc(LRp, 4); - end; - '>': - begin - StrMove(LRp, '>', 4); - Inc(LRp, 4); - end; - '"': - begin - StrMove(LRp, '"', 6); - Inc(LRp, 6); - end; - else - begin - LRp^ := LSp^; - Inc(LRp); - end; - end; - Inc(LSp); - end; - SetLength(Result, LRp - PChar(Result)); -end; - -class function TCrossHttpUtils.IsSamePath(const APath1, - APath2: string): Boolean; -begin - if (Length(APath1) >= Length(APath2)) then - Result := (Pos(APath2, APath1) = 1) - else - Result := (Pos(APath1, APath2) = 1); -end; - -{$IF DEFINED(DELPHI) AND (CompilerVersion < 36)} -class procedure TCrossHttpUtils.AdjustOffsetCount(const ABodySize: NativeInt; - var AOffset, ACount: NativeInt); -begin - {$region '修正 AOffset'} - // 偏移为正数, 从头部开始计算偏移 - if (AOffset >= 0) then - begin - AOffset := AOffset; - if (AOffset >= ABodySize) then - AOffset := ABodySize - 1; - end else - // 偏移为负数, 从尾部开始计算偏移 - begin - AOffset := ABodySize + AOffset; - if (AOffset < 0) then - AOffset := 0; - end; - {$endregion} - - {$region '修正 ACount'} - // ACount<=0表示需要处理所有数据 - if (ACount <= 0) then - ACount := ABodySize; - - if (ABodySize - AOffset < ACount) then - ACount := ABodySize - AOffset; - {$endregion} -end; -{$ENDIF} - -class procedure TCrossHttpUtils.AdjustOffsetCount(const ABodySize: Integer; - var AOffset, ACount: Integer); -begin - {$region '修正 AOffset'} - // 偏移为正数, 从头部开始计算偏移 - if (AOffset >= 0) then - begin - AOffset := AOffset; - if (AOffset >= ABodySize) then - AOffset := ABodySize - 1; - end else - // 偏移为负数, 从尾部开始计算偏移 - begin - AOffset := ABodySize + AOffset; - if (AOffset < 0) then - AOffset := 0; - end; - {$endregion} - - {$region '修正 ACount'} - // ACount<=0表示需要处理所有数据 - if (ACount <= 0) then - ACount := ABodySize; - - if (ABodySize - AOffset < ACount) then - ACount := ABodySize - AOffset; - {$endregion} -end; - -class procedure TCrossHttpUtils.AdjustOffsetCount(const ABodySize: Int64; - var AOffset, ACount: Int64); -begin - {$region '修正 AOffset'} - // 偏移为正数, 从头部开始计算偏移 - if (AOffset >= 0) then - begin - AOffset := AOffset; - if (AOffset >= ABodySize) then - AOffset := ABodySize - 1; - end else - // 偏移为负数, 从尾部开始计算偏移 - begin - AOffset := ABodySize + AOffset; - if (AOffset < 0) then - AOffset := 0; - end; - {$endregion} - - {$region '修正 ACount'} - // ACount<=0表示需要处理所有数据 - if (ACount <= 0) then - ACount := ABodySize; - - if (ABodySize - AOffset < ACount) then - ACount := ABodySize - AOffset; - {$endregion} -end; - -class function TCrossHttpUtils.CombinePath(const APath1, - APath2: string; const APathDelim: Char): string; -begin - Result := TPathUtils.Combine(APath1, APath2, APathDelim); -end; - -class function TCrossHttpUtils.CreateUrl(const AProtocol, AHost: string; - const APort: Word; const APath: string): string; -var - LPath: string; -begin - if (APath = '') then - LPath := '/' - else if (APath[1] = '/') then - LPath := APath - else - LPath := '/' + APath; - - Result := Format('%s://%s', [AProtocol, AHost]); - - if (SameText(AProtocol, HTTP) and (APort = HTTP_DEFAULT_PORT)) - or (SameText(AProtocol, HTTPS) and (APort = HTTPS_DEFAULT_PORT)) then - Result := Result + LPath - else - Result := Result + Format(':%d%s', [APort, LPath]); -end; - -class function TCrossHttpUtils.ExtractUrl(const AUrl: string; out AProtocol, - AHost: string; out APort: Word; out APath: string): Boolean; -var - LProtocolIndex, LIPv6Index, LPortIndex, LPathIndex, LQueryIndex, LPort: Integer; - LPortStr: string; -begin - // http://www.test.com/abc - // http://www.test.com:8080/abc - // https://www.test.com/abc - // https://www.test.com:8080/abc - // www.test.com:8080/abc - // www.test.com/abc - // www.test.com - // http://[aabb::20:80:5:2]:8080/abc - // [aabb::20:80:5:2] - - Result := False; - - // 找 :// 定位协议类型 - LProtocolIndex := AUrl.IndexOf('://'); - if (LProtocolIndex >= 0) then - begin - // 提取协议类型 - AProtocol := AUrl.Substring(0, LProtocolIndex).Trim; - Inc(LProtocolIndex, 3); - end else - begin - // 默认协议 http - AProtocol := HTTP; - LProtocolIndex := 0; - end; - - // 找 ] 定位IPv6地址 - LIPv6Index := AUrl.IndexOf(']', LProtocolIndex); - - if (LIPv6Index >= 0) then - begin - // 找 : 定位端口 - LPortIndex := AUrl.IndexOf(':', LIPv6Index + 1); - - // 找 / 定位路径 - LPathIndex := AUrl.IndexOf('/', LIPv6Index + 1); - - // 避免在参数部分出现 : 被当成端口定位 - if (LPathIndex >= 0) and (LPortIndex > LPathIndex) then - LPortIndex := -1; - - // 找 ? 定位参数 - LQueryIndex := AUrl.IndexOf('?', LIPv6Index + 1); - end else - begin - // 找 : 定位端口 - LPortIndex := AUrl.IndexOf(':', LProtocolIndex); - - // 找 / 定位路径 - LPathIndex := AUrl.IndexOf('/', LProtocolIndex); - - // 避免在参数部分出现 : 被当成端口定位 - if (LPathIndex >= 0) and (LPortIndex > LPathIndex) then - LPortIndex := -1; - - // 找 ? 定位参数 - LQueryIndex := AUrl.IndexOf('?', LProtocolIndex); - end; - - if (LPathIndex < 0) then - begin - if (LQueryIndex >= 0) then - LPathIndex := LQueryIndex - else - LPathIndex := Length(AUrl); - end; - - if (LPortIndex >= 0) then - begin - // 提取主机地址 - AHost := AUrl.Substring(LProtocolIndex, LPortIndex - LProtocolIndex); - - // 提取主机端口 - LPortStr := AUrl.Substring(LPortIndex + 1, LPathIndex - LPortIndex - 1); - if not TryStrToInt(LPortStr, LPort) then Exit; - - APort := LPort; - end else - begin - // 提取主机地址 - AHost := AUrl.Substring(LProtocolIndex, LPathIndex - LProtocolIndex); - - // 根据协议类型决定默认端口 - if TStrUtils.SameText(AProtocol, HTTPS) - or TStrUtils.SameText(AProtocol, WSS) then - APort := HTTPS_DEFAULT_PORT - else - APort := HTTP_DEFAULT_PORT; - end; - - // 提取路径 - APath := AUrl.Substring(LPathIndex, MaxInt); - if (APath = '') then - APath := '/' - else if (APath[1] <> '/') then - APath := '/' + APath; - - Result := (AHost <> ''); -end; - -class function TCrossHttpUtils.GetFileMIMEType(const AFileName: string): string; -var - LExt: string; - LMimeItem: TMimeValue; -begin - LExt := ExtractFileExt(AFileName).Substring(1); - for LMimeItem in MIME_TYPES do - if TStrUtils.SameText(LMimeItem.Key, LExt) then - Exit(LMimeItem.Value); - Result := TMediaType.APPLICATION_OCTET_STREAM; -end; - -class function TCrossHttpUtils.RFC1123_DateToStr(const ADate: TDateTime): string; -begin - // Fri, 30 Jul 2024 10:10:35 GMT - Result := ADate.ToRFC1123(True); -end; - -class function TCrossHttpUtils.RFC1123_StrToDate(const ADateStr: string) : TDateTime; -var - LYear, LMonth, LDay: Word; - LHour, LMin, LSec: Word; -begin - // Fri, 30 Jul 2024 10:10:35 GMT - if (Length(ADateStr) = 29) then - begin - LDay := StrToIntDef(Copy(ADateStr, 6, 2), 0); - LMonth := (Pos(Copy(ADateStr, 9, 3), RFC1123_StrMonth) + 2) div 3; - LYear := StrToIntDef(Copy(ADateStr, 13, 4), 0); - LHour := StrToIntDef(Copy(ADateStr, 18, 2), 0); - LMin := StrToIntDef(Copy(ADateStr, 21, 2), 0); - LSec := StrToIntDef(Copy(ADateStr, 24, 2), 0); - end else - // Fri, 30 Jul 24 10:10:35 GMT - // Fri, 30-Jul-24 10:10:35 GMT - if (Length(ADateStr) = 27) then - begin - LDay := StrToIntDef(Copy(ADateStr, 6, 2), 0); - LMonth := (Pos(Copy(ADateStr, 9, 3), RFC1123_StrMonth) + 2) div 3; - LYear := 2000 + StrToIntDef(Copy(ADateStr, 13, 2), 0); - LHour := StrToIntDef(Copy(ADateStr, 16, 2), 0); - LMin := StrToIntDef(Copy(ADateStr, 19, 2), 0); - LSec := StrToIntDef(Copy(ADateStr, 22, 2), 0); - end else - Exit(0); - - if not TryEncodeDateTime(LYear, LMonth, LDay, LHour, LMin, LSec, 0, Result) then - Result := 0; -end; - -class function TCrossHttpUtils.TryUrlPathToLocalPath(const ALocalBaseDir, - AUrlPath: string; out AResolvedPath: string): Boolean; -begin - Result := TPathUtils.TryResolveLocalPath( - ALocalBaseDir, - TCrossHttpUtils.GetPathWithoutParams(AUrlPath).Trim, - AResolvedPath); -end; - -class function TCrossHttpUtils.UrlDecode(const S: string): string; -var - LSrcBytes, LDstBytes: TBytes; - LSrcLen, LSrcIdx, LDstIdx: Integer; - H, L: Byte; - C: Byte; -begin - if (S = '') then Exit(''); - - // 先把输入 unicode 字符串 UTF-8 编码为字节流, 与 UrlEncode 对称. - // 这样允许输入混合: ASCII percent-encoded ('%E4%B8%AD') 与 unicode 原字符 ('中') 都能正确处理. - LSrcBytes := TEncoding.UTF8.GetBytes(S); - LSrcLen := Length(LSrcBytes); - SetLength(LDstBytes, LSrcLen); - - LSrcIdx := 0; - LDstIdx := 0; - while (LSrcIdx < LSrcLen) do - begin - C := LSrcBytes[LSrcIdx]; - case C of - // 兼容早期 form-urlencoded: '+' → 空格 - Ord('+'): - begin - LDstBytes[LDstIdx] := Ord(' '); - Inc(LSrcIdx); - end; - - Ord('%'): - begin - if (LSrcIdx + 2 < LSrcLen) - and TUtils.HexCharToByte(Char(LSrcBytes[LSrcIdx + 1]), H) - and TUtils.HexCharToByte(Char(LSrcBytes[LSrcIdx + 2]), L) then - begin - LDstBytes[LDstIdx] := L + (H shl 4); - Inc(LSrcIdx, 3); - end else - begin - // 非法 %xx, 原样保留 '%' 字符 - LDstBytes[LDstIdx] := Ord('%'); - Inc(LSrcIdx); - end; - end; - else - // 包含 ASCII 与 UTF-8 多字节序列的高字节, 都原样透传 - LDstBytes[LDstIdx] := C; - Inc(LSrcIdx); - end; - - Inc(LDstIdx); - end; - SetLength(LDstBytes, LDstIdx); - - Result := TEncoding.UTF8.GetString(LDstBytes); -end; - -class function TCrossHttpUtils.UrlEncode(const S: string; const ANoConversion: TSysCharSet; - const APreserveEncoded: Boolean): string; -const - HEX_CHARS: array[0..15] of Char = ( - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); - - function _IsHexByte(const AByte: Byte): Boolean; inline; - begin - case AByte of - Ord('0')..Ord('9'), - Ord('a')..Ord('f'), - Ord('A')..Ord('F'): - Result := True; - else - Result := False; - end; - end; - -var - LUTF8Bytes: TBytes; - LLen, I: Integer; - C: Byte; - P: PChar; -begin - if (S = '') then Exit(''); - - // 先将 unicode 字符串编码为 utf8 字节数组 - LUTF8Bytes := TEncoding.UTF8.GetBytes(S); - LLen := Length(LUTF8Bytes); - - // 预分配编码字符串, 比一直累加效率高很多 - // 预分配尺寸为 utf8 字节数组长度的 3 倍 - // 之所以预分配 3 倍, 是因为每个 utf8 字节最长可能被编码为 %xy 这样的字符串 - SetLength(Result, LLen * 3); - P := PChar(Result); - - I := 0; - while (I < LLen) do - begin - C := LUTF8Bytes[I]; - case C of - // https://datatracker.ietf.org/doc/html/rfc3986 - // RFC 3986 中明确定义了未保留字(无需编码)包含以下这些 - // 字母数字:大小写英文字母(A-Z, a-z)和数字(0-9)。 - // 特殊字符:连字符(-),下划线(_),点号(.),和波浪号(~)。 - Ord('0')..Ord('9'), - Ord('a')..Ord('z'), - Ord('A')..Ord('Z'), - Ord('-'), Ord('_'), Ord('.'), Ord('~'): - begin - P^ := Char(C); - Inc(P); - end; - else - // RFC 3986 §2.4: 已 percent-encoded 的 %xx 序列不应被二次编码. - // APreserveEncoded=True 时, 遇到 % 后跟 2 个 hex 数字, 原样保留 3 字符. - if APreserveEncoded and (C = Ord('%')) and (I + 2 < LLen) - and _IsHexByte(LUTF8Bytes[I + 1]) - and _IsHexByte(LUTF8Bytes[I + 2]) then - begin - P^ := '%'; - Inc(P); - P^ := Char(LUTF8Bytes[I + 1]); - Inc(P); - P^ := Char(LUTF8Bytes[I + 2]); - Inc(P); - Inc(I, 2); // 跳过两个 hex 字节, 循环底部还会 Inc(I) 一次 - end else - if CharInSet(Char(C), ANoConversion) then - begin - P^ := Char(C); - Inc(P); - end else - begin - P^ := '%'; - Inc(P); - - P^ := HEX_CHARS[C shr 4]; - Inc(P); - - P^ := HEX_CHARS[C and $F]; - Inc(P); - end; - end; - Inc(I); - end; - - // 修正编码字符串的实际长度 - SetLength(Result, P - PChar(Result)); -end; - -class function TCrossHttpUtils.ParseSingleByteRange(const ARangeHeader: string; - const AContentLength: Int64; out AStart, AEnd: Int64): Boolean; -const - PREFIX = 'bytes='; - - function _IsAsciiDigits(const S: string): Boolean; - var - I: Integer; - begin - if (S = '') then Exit(False); - for I := 1 to Length(S) do - case S[I] of - '0'..'9': ; - else - Exit(False); - end; - Result := True; - end; - -var - LSpec, LStartStr, LEndStr: string; - LDashPos: Integer; - LStartVal, LEndVal: Int64; - LHasStart, LHasEnd: Boolean; -begin - AStart := 0; - AEnd := 0; - Result := False; - - // 资源长度必须 > 0 - if (AContentLength <= 0) then Exit; - - // 必须以 'bytes=' 前缀开头 (RFC 7233 §3.1, 大小写不敏感) - if (Length(ARangeHeader) <= Length(PREFIX)) - or not ARangeHeader.StartsWith(PREFIX, True) then Exit; - - LSpec := Copy(ARangeHeader, Length(PREFIX) + 1, MaxInt).Trim; - if (LSpec = '') then Exit; - - // 不支持 multipart/byteranges (含 ',' 一律拒绝) - if (LSpec.IndexOf(',') >= 0) then Exit; - - // 必须存在且仅有一个 '-' - LDashPos := LSpec.IndexOf('-'); - if (LDashPos < 0) then Exit; - if (LSpec.LastIndexOf('-') <> LDashPos) then Exit; - - // 不对子串再 Trim, 避免 'bytes=0 - 100' 内嵌空格被静默吞掉. - // RFC 7230 ABNF 不允许 byte-range-spec 内含 OWS/BWS. - LStartStr := LSpec.Substring(0, LDashPos); - LEndStr := LSpec.Substring(LDashPos + 1); - - LHasStart := (LStartStr <> ''); - LHasEnd := (LEndStr <> ''); - - // 至少要有一个端点; 'bytes=-' 是非法的 - if (not LHasStart) and (not LHasEnd) then Exit; - - // 解析 start (必须为纯 ASCII 十进制数字) - if LHasStart then - begin - if not _IsAsciiDigits(LStartStr) then Exit; - if not TryStrToInt64(LStartStr, LStartVal) then Exit; - if (LStartVal < 0) then Exit; - end else - LStartVal := 0; - - // 解析 end (必须为纯 ASCII 十进制数字) - if LHasEnd then - begin - if not _IsAsciiDigits(LEndStr) then Exit; - if not TryStrToInt64(LEndStr, LEndVal) then Exit; - if (LEndVal < 0) then Exit; - end else - LEndVal := 0; - - if LHasStart and LHasEnd then - begin - // bytes=start-end: 要求 0 <= start <= end < size - if (LStartVal > LEndVal) then Exit; - if (LStartVal >= AContentLength) then Exit; - // end 超出文件大小时按 RFC 7233 §2.1 截断到 size-1 - if (LEndVal >= AContentLength) then - LEndVal := AContentLength - 1; - AStart := LStartVal; - AEnd := LEndVal; - end else - if LHasStart then - begin - // bytes=start-: 从 start 取到末尾 - if (LStartVal >= AContentLength) then Exit; - AStart := LStartVal; - AEnd := AContentLength - 1; - end else - begin - // bytes=-suffix: 取末尾 suffix 字节; suffix 必须 > 0 - if (LEndVal = 0) then Exit; - if (LEndVal >= AContentLength) then - AStart := 0 - else - AStart := AContentLength - LEndVal; - AEnd := AContentLength - 1; - end; - - Result := True; -end; - -class function TCrossHttpUtils.IsTokenChar(ACh: Char): Boolean; -begin - // RFC 7230 §3.2.6 token: ALPHA / DIGIT / "!" "#" "$" "%" "&" "'" "*" "+" - // "-" "." "^" "_" "`" "|" "~" - case ACh of - 'A'..'Z', 'a'..'z', '0'..'9', - '!', '#', '$', '%', '&', '''', '*', '+', '-', '.', '^', '_', '`', '|', '~': - Result := True; - else - Result := False; - end; -end; - -class function TCrossHttpUtils.IsHeaderValueChar(ACh: Char): Boolean; -begin - // RFC 7230 §3.2.4 field-value: - // 合法: HTAB(#9) / 可见 ASCII (#32..#126) / #128+ 高位字符 (历史宽松, 兼容 UTF-8). - // 非法: 其他 CTL (#0..#8, #10..#31) 与 DEL (#127), CR/LF/NUL 是响应拆分主要载体. - case Ord(ACh) of - 9, 32..126, 128..$FFFF: - Result := True; - else - Result := False; - end; -end; - -class function TCrossHttpUtils.IsValidHeaderName(const AName: string): Boolean; -var - I: Integer; -begin - if (AName = '') then Exit(False); - for I := 1 to Length(AName) do - if not IsTokenChar(AName[I]) then Exit(False); - Result := True; -end; - -class function TCrossHttpUtils.IsValidHeaderValue(const AValue: string): Boolean; -var - I: Integer; -begin - for I := 1 to Length(AValue) do - if not IsHeaderValueChar(AValue[I]) then Exit(False); - Result := True; -end; - -end. +{******************************************************************************} +{ } +{ Delphi cross platform socket library } +{ } +{ Copyright (c) 2017 WiNDDRiVER(soulawing@gmail.com) } +{ } +{ Homepage: https://github.com/winddriver/Delphi-Cross-Socket } +{ } +{******************************************************************************} +unit Net.CrossHttpUtils; + +{$I zLib.inc} + +interface + +uses + SysUtils, + DateUtils, + + Utils.DateTime, + Utils.StrUtils, + Utils.Utils, + Utils.IOUtils; + +type + THttpStatus = record + Code: Integer; + Text: string; + end; + + TMimeValue = record + Key: string; + Value: string; + end; + + {$REGION 'Documentation'} + /// + /// HTTP版本信息 + /// + {$ENDREGION} + THttpVersion = (hvHttp10, hvHttp11); + + {$REGION 'Documentation'} + /// + /// 压缩类型 + /// + {$ENDREGION} + TCompressType = (ctNone, ctGZip, ctDeflate); + +const + HTTP = 'http'; + HTTPS = 'https'; + HTTP_DEFAULT_PORT = 80; + HTTPS_DEFAULT_PORT = 443; + WS = 'ws'; + WSS = 'wss'; + WEBSOCKET = 'websocket'; + WEBSOCKET_VERSION = '13'; + + HTTP_VER_STR: array [THttpVersion] of string = ('HTTP/1.0', 'HTTP/1.1'); + + {$REGION '常用 HTTP 头'} + HEADER_ACCEPT = 'Accept'; + HEADER_ACCEPT_CHARSET = 'Accept-Charset'; + HEADER_ACCEPT_ENCODING = 'Accept-Encoding'; + HEADER_ACCEPT_LANGUAGE = 'Accept-Language'; + HEADER_ACCEPT_RANGES = 'Accept-Ranges'; + HEADER_AUTHORIZATION = 'Authorization'; + HEADER_CACHE_CONTROL = 'Cache-Control'; + HEADER_CONNECTION = 'Connection'; + HEADER_CONTENT_DISPOSITION = 'Content-Disposition'; + HEADER_CONTENT_ENCODING = 'Content-Encoding'; + HEADER_CONTENT_LANGUAGE = 'Content-Language'; + HEADER_CONTENT_LENGTH = 'Content-Length'; + HEADER_CONTENT_RANGE = 'Content-Range'; + HEADER_CONTENT_TYPE = 'Content-Type'; + HEADER_COOKIE = 'Cookie'; + HEADER_CROSS_HTTP_CLIENT = 'Client'; + HEADER_CROSS_HTTP_SERVER = 'Server'; + HEADER_ETAG = 'ETag'; + HEADER_EXPECT = 'Expect'; + HEADER_HOST = 'Host'; + HEADER_IF_MODIFIED_SINCE = 'If-Modified-Since'; + HEADER_IF_NONE_MATCH = 'If-None-Match'; + HEADER_IF_RANGE = 'If-Range'; + HEADER_LAST_MODIFIED = 'Last-Modified'; + HEADER_LOCATION = 'Location'; + HEADER_PRAGMA = 'Pragma'; + HEADER_PROXY_AUTHENTICATE = 'Proxy-Authenticate'; + HEADER_PROXY_AUTHORIZATION = 'Proxy-Authorization'; + HEADER_RANGE = 'Range'; + HEADER_REFERER = 'Referer'; + HEADER_SEC_WEBSOCKET_ACCEPT = 'Sec-WebSocket-Accept'; + HEADER_SEC_WEBSOCKET_KEY = 'Sec-WebSocket-Key'; + HEADER_SEC_WEBSOCKET_VERSION = 'Sec-WebSocket-Version'; + HEADER_SETCOOKIE = 'Set-Cookie'; + HEADER_TRANSFER_ENCODING = 'Transfer-Encoding'; + HEADER_UPGRADE = 'Upgrade'; + HEADER_USER_AGENT = 'User-Agent'; + HEADER_VARY = 'Vary'; + HEADER_WWW_AUTHENTICATE = 'WWW-Authenticate'; + HEADER_X_METHOD_OVERRIDE = 'x-method-override'; + HEADER_X_FORWARDED_FOR = 'X-Forwarded-For'; + HEADER_X_REAL_IP = 'X-Real-IP'; + HEADER_X_FORWARDED_HOST = 'X-Forwarded-Host'; + HEADER_X_FORWARDED_SERVER = 'X-Forwarded-Server'; + {$ENDREGION} + + ZLIB_BUF_SIZE = 32768; + ZLIB_WINDOW_BITS: array [TCompressType] of Integer = (0, 15 + 16{gzip}, 15{deflate}); + ZLIB_CONTENT_ENCODING: array [TCompressType] of string = ('', 'gzip', 'deflate'); + + {$REGION '常用状态码'} + STATUS_CODES: array [0..56] of THttpStatus = ( + (Code: 100; Text: 'Continue'), + (Code: 101; Text: 'Switching Protocols'), + (Code: 102; Text: 'Processing'), // RFC 2518, obsoleted by RFC 4918 + (Code: 200; Text: 'OK'), + (Code: 201; Text: 'Created'), + (Code: 202; Text: 'Accepted'), + (Code: 203; Text: 'Non-Authoritative Information'), + (Code: 204; Text: 'No Content'), + (Code: 205; Text: 'Reset Content'), + (Code: 206; Text: 'Partial Content'), + (Code: 207; Text: 'Multi-Status'), // RFC 4918 + (Code: 300; Text: 'Multiple Choices'), + (Code: 301; Text: 'Moved Permanently'), + (Code: 302; Text: 'Moved Temporarily'), + (Code: 303; Text: 'See Other'), + (Code: 304; Text: 'Not Modified'), + (Code: 305; Text: 'Use Proxy'), + (Code: 307; Text: 'Temporary Redirect'), + (Code: 308; Text: 'Permanent Redirect'), // RFC 7238 + (Code: 400; Text: 'Bad Request'), + (Code: 401; Text: 'Unauthorized'), + (Code: 402; Text: 'Payment Required'), + (Code: 403; Text: 'Forbidden'), + (Code: 404; Text: 'Not Found'), + (Code: 405; Text: 'Method Not Allowed'), + (Code: 406; Text: 'Not Acceptable'), + (Code: 407; Text: 'Proxy Authentication Required'), + (Code: 408; Text: 'Request Timeout'), + (Code: 409; Text: 'Conflict'), + (Code: 410; Text: 'Gone'), + (Code: 411; Text: 'Length Required'), + (Code: 412; Text: 'Precondition Failed'), + (Code: 413; Text: 'Request Entity Too Large'), + (Code: 414; Text: 'Request URI Too Large'), + (Code: 415; Text: 'Unsupported Media Type'), + (Code: 416; Text: 'Requested Range Not Satisfiable'), + (Code: 417; Text: 'Expectation Failed'), + (Code: 418; Text: 'I''m a teapot'), // RFC 2324 + (Code: 422; Text: 'Unprocessable Entity'), // RFC 4918 + (Code: 423; Text: 'Locked'), // RFC 4918 + (Code: 424; Text: 'Failed Dependency'), // RFC 4918 + (Code: 425; Text: 'Unordered Collection'), // RFC 4918 + (Code: 426; Text: 'Upgrade Required'), // RFC 2817 + (Code: 428; Text: 'Precondition Required'), // RFC 6585 + (Code: 429; Text: 'Too Many Requests'), // RFC 6585 + (Code: 431; Text: 'Request Header Fields Too Large'), // RFC 6585 + (Code: 500; Text: 'Internal Server Error'), + (Code: 501; Text: 'Not Implemented'), + (Code: 502; Text: 'Bad Gateway'), + (Code: 503; Text: 'Service Unavailable'), + (Code: 504; Text: 'Gateway Timeout'), + (Code: 505; Text: 'HTTP Version Not Supported'), + (Code: 506; Text: 'Variant Also Negotiates'), // RFC 2295 + (Code: 507; Text: 'Insufficient Storage'), // RFC 4918 + (Code: 509; Text: 'Bandwidth Limit Exceeded'), + (Code: 510; Text: 'Not Extended'), // RFC 2774 + (Code: 511; Text: 'Network Authentication Required') // RFC 6585 + ); + {$ENDREGION} + + {$REGION 'MIME CONST'} + MIME_TYPES: array[0..988] of TMimeValue = ( + (Key: 'ez'; Value: 'application/andrew-inset'), // do not localize + (Key: 'aw'; Value: 'application/applixware'), // do not localize + (Key: 'atom'; Value: 'application/atom+xml'), // do not localize + (Key: 'atomcat'; Value: 'application/atomcat+xml'), // do not localize + (Key: 'atomsvc'; Value: 'application/atomsvc+xml'), // do not localize + (Key: 'ccxml'; Value: 'application/ccxml+xml'), // do not localize + (Key: 'cdmia'; Value: 'application/cdmi-capability'), // do not localize + (Key: 'cdmic'; Value: 'application/cdmi-container'), // do not localize + (Key: 'cdmid'; Value: 'application/cdmi-domain'), // do not localize + (Key: 'cdmio'; Value: 'application/cdmi-object'), // do not localize + (Key: 'cdmiq'; Value: 'application/cdmi-queue'), // do not localize + (Key: 'cu'; Value: 'application/cu-seeme'), // do not localize + (Key: 'davmount'; Value: 'application/davmount+xml'), // do not localize + (Key: 'dbk'; Value: 'application/docbook+xml'), // do not localize + (Key: 'dssc'; Value: 'application/dssc+der'), // do not localize + (Key: 'xdssc'; Value: 'application/dssc+xml'), // do not localize + (Key: 'ecma'; Value: 'application/ecmascript'), // do not localize + (Key: 'emma'; Value: 'application/emma+xml'), // do not localize + (Key: 'epub'; Value: 'application/epub+zip'), // do not localize + (Key: 'exi'; Value: 'application/exi'), // do not localize + (Key: 'pfr'; Value: 'application/font-tdpfr'), // do not localize + (Key: 'gml'; Value: 'application/gml+xml'), // do not localize + (Key: 'gpx'; Value: 'application/gpx+xml'), // do not localize + (Key: 'gxf'; Value: 'application/gxf'), // do not localize + (Key: 'stk'; Value: 'application/hyperstudio'), // do not localize + (Key: 'ink'; Value: 'application/inkml+xml'), // do not localize + (Key: 'inkml'; Value: 'application/inkml+xml'), // do not localize + (Key: 'ipfix'; Value: 'application/ipfix'), // do not localize + (Key: 'jar'; Value: 'application/java-archive'), // do not localize + (Key: 'ser'; Value: 'application/java-serialized-object'), // do not localize + (Key: 'class'; Value: 'application/java-vm'), // do not localize + (Key: 'js'; Value: 'application/javascript'), // do not localize + (Key: 'json'; Value: 'application/json'), // do not localize + (Key: 'jsonml'; Value: 'application/jsonml+json'), // do not localize + (Key: 'lostxml'; Value: 'application/lost+xml'), // do not localize + (Key: 'hqx'; Value: 'application/mac-binhex40'), // do not localize + (Key: 'cpt'; Value: 'application/mac-compactpro'), // do not localize + (Key: 'mads'; Value: 'application/mads+xml'), // do not localize + (Key: 'mrc'; Value: 'application/marc'), // do not localize + (Key: 'mrcx'; Value: 'application/marcxml+xml'), // do not localize + (Key: 'ma'; Value: 'application/mathematica'), // do not localize + (Key: 'nb'; Value: 'application/mathematica'), // do not localize + (Key: 'mb'; Value: 'application/mathematica'), // do not localize + (Key: 'mathml'; Value: 'application/mathml+xml'), // do not localize + (Key: 'mbox'; Value: 'application/mbox'), // do not localize + (Key: 'mscml'; Value: 'application/mediaservercontrol+xml'), // do not localize + (Key: 'metalink'; Value: 'application/metalink+xml'), // do not localize + (Key: 'meta4'; Value: 'application/metalink4+xml'), // do not localize + (Key: 'mets'; Value: 'application/mets+xml'), // do not localize + (Key: 'mods'; Value: 'application/mods+xml'), // do not localize + (Key: 'm21'; Value: 'application/mp21'), // do not localize + (Key: 'mp21'; Value: 'application/mp21'), // do not localize + (Key: 'mp4s'; Value: 'application/mp4'), // do not localize + (Key: 'doc'; Value: 'application/msword'), // do not localize + (Key: 'dot'; Value: 'application/msword'), // do not localize + (Key: 'mxf'; Value: 'application/mxf'), // do not localize + (Key: 'bin'; Value: 'application/octet-stream'), // do not localize + (Key: 'bpk'; Value: 'application/octet-stream'), // do not localize + (Key: 'class'; Value: 'application/octet-stream'), // do not localize + (Key: 'deploy'; Value: 'application/octet-stream'), // do not localize + (Key: 'dist'; Value: 'application/octet-stream'), // do not localize + (Key: 'distz'; Value: 'application/octet-stream'), // do not localize + (Key: 'dmg'; Value: 'application/octet-stream'), // do not localize + (Key: 'dms'; Value: 'application/octet-stream'), // do not localize + (Key: 'dump'; Value: 'application/octet-stream'), // do not localize + (Key: 'elc'; Value: 'application/octet-stream'), // do not localize + (Key: 'iso'; Value: 'application/octet-stream'), // do not localize + (Key: 'lha'; Value: 'application/octet-stream'), // do not localize + (Key: 'lrf'; Value: 'application/octet-stream'), // do not localize + (Key: 'lzh'; Value: 'application/octet-stream'), // do not localize + (Key: 'mar'; Value: 'application/octet-stream'), // do not localize + (Key: 'pkg'; Value: 'application/octet-stream'), // do not localize + (Key: 'so'; Value: 'application/octet-stream'), // do not localize + (Key: 'oda'; Value: 'application/oda'), // do not localize + (Key: 'opf'; Value: 'application/oebps-package+xml'), // do not localize + (Key: 'ogx'; Value: 'application/ogg'), // do not localize + (Key: 'omdoc'; Value: 'application/omdoc+xml'), // do not localize + (Key: 'onetoc'; Value: 'application/onenote'), // do not localize + (Key: 'onetoc2'; Value: 'application/onenote'), // do not localize + (Key: 'onetmp'; Value: 'application/onenote'), // do not localize + (Key: 'onepkg'; Value: 'application/onenote'), // do not localize + (Key: 'oxps'; Value: 'application/oxps'), // do not localize + (Key: 'xer'; Value: 'application/patch-ops-error+xml'), // do not localize + (Key: 'pdf'; Value: 'application/pdf'), // do not localize + (Key: 'pgp'; Value: 'application/pgp-encrypted'), // do not localize + (Key: 'asc'; Value: 'application/pgp-signature'), // do not localize + (Key: 'sig'; Value: 'application/pgp-signature'), // do not localize + (Key: 'prf'; Value: 'application/pics-rules'), // do not localize + (Key: 'p10'; Value: 'application/pkcs10'), // do not localize + (Key: 'p7m'; Value: 'application/pkcs7-mime'), // do not localize + (Key: 'p7c'; Value: 'application/pkcs7-mime'), // do not localize + (Key: 'p7s'; Value: 'application/pkcs7-signature'), // do not localize + (Key: 'p8'; Value: 'application/pkcs8'), // do not localize + (Key: 'ac'; Value: 'application/pkix-attr-cert'), // do not localize + (Key: 'cer'; Value: 'application/pkix-cert'), // do not localize + (Key: 'crl'; Value: 'application/pkix-crl'), // do not localize + (Key: 'pkipath'; Value: 'application/pkix-pkipath'), // do not localize + (Key: 'pki'; Value: 'application/pkixcmp'), // do not localize + (Key: 'pls'; Value: 'application/pls+xml'), // do not localize + (Key: 'ai'; Value: 'application/postscript'), // do not localize + (Key: 'eps'; Value: 'application/postscript'), // do not localize + (Key: 'ps'; Value: 'application/postscript'), // do not localize + (Key: 'cww'; Value: 'application/prs.cww'), // do not localize + (Key: 'pskcxml'; Value: 'application/pskc+xml'), // do not localize + (Key: 'rdf'; Value: 'application/rdf+xml'), // do not localize + (Key: 'rif'; Value: 'application/reginfo+xml'), // do not localize + (Key: 'rnc'; Value: 'application/relax-ng-compact-syntax'), // do not localize + (Key: 'rl'; Value: 'application/resource-lists+xml'), // do not localize + (Key: 'rld'; Value: 'application/resource-lists-diff+xml'), // do not localize + (Key: 'rs'; Value: 'application/rls-services+xml'), // do not localize + (Key: 'gbr'; Value: 'application/rpki-ghostbusters'), // do not localize + (Key: 'mft'; Value: 'application/rpki-manifest'), // do not localize + (Key: 'roa'; Value: 'application/rpki-roa'), // do not localize + (Key: 'rsd'; Value: 'application/rsd+xml'), // do not localize + (Key: 'rss'; Value: 'application/rss+xml'), // do not localize + (Key: 'rtf'; Value: 'application/rtf'), // do not localize + (Key: 'sbml'; Value: 'application/sbml+xml'), // do not localize + (Key: 'scq'; Value: 'application/scvp-cv-request'), // do not localize + (Key: 'scs'; Value: 'application/scvp-cv-response'), // do not localize + (Key: 'spq'; Value: 'application/scvp-vp-request'), // do not localize + (Key: 'spp'; Value: 'application/scvp-vp-response'), // do not localize + (Key: 'sdp'; Value: 'application/sdp'), // do not localize + (Key: 'setpay'; Value: 'application/set-payment-initiation'), // do not localize + (Key: 'setreg'; Value: 'application/set-registration-initiation'), // do not localize + (Key: 'shf'; Value: 'application/shf+xml'), // do not localize + (Key: 'smi'; Value: 'application/smil+xml'), // do not localize + (Key: 'smil'; Value: 'application/smil+xml'), // do not localize + (Key: 'rq'; Value: 'application/sparql-query'), // do not localize + (Key: 'srx'; Value: 'application/sparql-results+xml'), // do not localize + (Key: 'gram'; Value: 'application/srgs'), // do not localize + (Key: 'grxml'; Value: 'application/srgs+xml'), // do not localize + (Key: 'sru'; Value: 'application/sru+xml'), // do not localize + (Key: 'ssdl'; Value: 'application/ssdl+xml'), // do not localize + (Key: 'ssml'; Value: 'application/ssml+xml'), // do not localize + (Key: 'tei'; Value: 'application/tei+xml'), // do not localize + (Key: 'teicorpus'; Value: 'application/tei+xml'), // do not localize + (Key: 'tfi'; Value: 'application/thraud+xml'), // do not localize + (Key: 'tsd'; Value: 'application/timestamped-data'), // do not localize + (Key: 'plb'; Value: 'application/vnd.3gpp.pic-bw-large'), // do not localize + (Key: 'psb'; Value: 'application/vnd.3gpp.pic-bw-small'), // do not localize + (Key: 'pvb'; Value: 'application/vnd.3gpp.pic-bw-var'), // do not localize + (Key: 'tcap'; Value: 'application/vnd.3gpp2.tcap'), // do not localize + (Key: 'pwn'; Value: 'application/vnd.3m.post-it-notes'), // do not localize + (Key: 'aso'; Value: 'application/vnd.accpac.simply.aso'), // do not localize + (Key: 'imp'; Value: 'application/vnd.accpac.simply.imp'), // do not localize + (Key: 'acu'; Value: 'application/vnd.acucobol'), // do not localize + (Key: 'atc'; Value: 'application/vnd.acucorp'), // do not localize + (Key: 'acutc'; Value: 'application/vnd.acucorp'), // do not localize + (Key: 'air'; Value: 'application/vnd.adobe.air-application-installer-package+zip'), // do not localize + (Key: 'fcdt'; Value: 'application/vnd.adobe.formscentral.fcdt'), // do not localize + (Key: 'fxp'; Value: 'application/vnd.adobe.fxp'), // do not localize + (Key: 'fxpl'; Value: 'application/vnd.adobe.fxp'), // do not localize + (Key: 'xdp'; Value: 'application/vnd.adobe.xdp+xml'), // do not localize + (Key: 'xfdf'; Value: 'application/vnd.adobe.xfdf'), // do not localize + (Key: 'ahead'; Value: 'application/vnd.ahead.space'), // do not localize + (Key: 'azf'; Value: 'application/vnd.airzip.filesecure.azf'), // do not localize + (Key: 'azs'; Value: 'application/vnd.airzip.filesecure.azs'), // do not localize + (Key: 'azw'; Value: 'application/vnd.amazon.ebook'), // do not localize + (Key: 'acc'; Value: 'application/vnd.americandynamics.acc'), // do not localize + (Key: 'ami'; Value: 'application/vnd.amiga.ami'), // do not localize + (Key: 'apk'; Value: 'application/vnd.android.package-archive'), // do not localize + (Key: 'cii'; Value: 'application/vnd.anser-web-certificate-issue-initiation'), // do not localize + (Key: 'fti'; Value: 'application/vnd.anser-web-funds-transfer-initiation'), // do not localize + (Key: 'atx'; Value: 'application/vnd.antix.game-component'), // do not localize + (Key: 'mpkg'; Value: 'application/vnd.apple.installer+xml'), // do not localize + (Key: 'm3u8'; Value: 'application/vnd.apple.mpegurl'), // do not localize + (Key: 'swi'; Value: 'application/vnd.aristanetworks.swi'), // do not localize + (Key: 'iota'; Value: 'application/vnd.astraea-software.iota'), // do not localize + (Key: 'aep'; Value: 'application/vnd.audiograph'), // do not localize + (Key: 'mpm'; Value: 'application/vnd.blueice.multipass'), // do not localize + (Key: 'bmi'; Value: 'application/vnd.bmi'), // do not localize + (Key: 'rep'; Value: 'application/vnd.businessobjects'), // do not localize + (Key: 'cdxml'; Value: 'application/vnd.chemdraw+xml'), // do not localize + (Key: 'mmd'; Value: 'application/vnd.chipnuts.karaoke-mmd'), // do not localize + (Key: 'cdy'; Value: 'application/vnd.cinderella'), // do not localize + (Key: 'cla'; Value: 'application/vnd.claymore'), // do not localize + (Key: 'rp9'; Value: 'application/vnd.cloanto.rp9'), // do not localize + (Key: 'c4g'; Value: 'application/vnd.clonk.c4group'), // do not localize + (Key: 'c4d'; Value: 'application/vnd.clonk.c4group'), // do not localize + (Key: 'c4f'; Value: 'application/vnd.clonk.c4group'), // do not localize + (Key: 'c4p'; Value: 'application/vnd.clonk.c4group'), // do not localize + (Key: 'c4u'; Value: 'application/vnd.clonk.c4group'), // do not localize + (Key: 'c11amc'; Value: 'application/vnd.cluetrust.cartomobile-config'), // do not localize + (Key: 'c11amz'; Value: 'application/vnd.cluetrust.cartomobile-config-pkg'), // do not localize + (Key: 'csp'; Value: 'application/vnd.commonspace'), // do not localize + (Key: 'cdbcmsg'; Value: 'application/vnd.contact.cmsg'), // do not localize + (Key: 'cmc'; Value: 'application/vnd.cosmocaller'), // do not localize + (Key: 'clkx'; Value: 'application/vnd.crick.clicker'), // do not localize + (Key: 'clkk'; Value: 'application/vnd.crick.clicker.keyboard'), // do not localize + (Key: 'clkp'; Value: 'application/vnd.crick.clicker.palette'), // do not localize + (Key: 'clkt'; Value: 'application/vnd.crick.clicker.template'), // do not localize + (Key: 'clkw'; Value: 'application/vnd.crick.clicker.wordbank'), // do not localize + (Key: 'wbs'; Value: 'application/vnd.criticaltools.wbs+xml'), // do not localize + (Key: 'pml'; Value: 'application/vnd.ctc-posml'), // do not localize + (Key: 'ppd'; Value: 'application/vnd.cups-ppd'), // do not localize + (Key: 'car'; Value: 'application/vnd.curl.car'), // do not localize + (Key: 'pcurl'; Value: 'application/vnd.curl.pcurl'), // do not localize + (Key: 'dart'; Value: 'application/vnd.dart'), // do not localize + (Key: 'rdz'; Value: 'application/vnd.data-vision.rdz'), // do not localize + (Key: 'uvf'; Value: 'application/vnd.dece.data'), // do not localize + (Key: 'uvvf'; Value: 'application/vnd.dece.data'), // do not localize + (Key: 'uvd'; Value: 'application/vnd.dece.data'), // do not localize + (Key: 'uvvd'; Value: 'application/vnd.dece.data'), // do not localize + (Key: 'uvt'; Value: 'application/vnd.dece.ttml+xml'), // do not localize + (Key: 'uvvt'; Value: 'application/vnd.dece.ttml+xml'), // do not localize + (Key: 'uvx'; Value: 'application/vnd.dece.unspecified'), // do not localize + (Key: 'uvvx'; Value: 'application/vnd.dece.unspecified'), // do not localize + (Key: 'uvz'; Value: 'application/vnd.dece.zip'), // do not localize + (Key: 'uvvz'; Value: 'application/vnd.dece.zip'), // do not localize + (Key: 'fe_launch'; Value: 'application/vnd.denovo.fcselayout-link'), // do not localize + (Key: 'dna'; Value: 'application/vnd.dna'), // do not localize + (Key: 'mlp'; Value: 'application/vnd.dolby.mlp'), // do not localize + (Key: 'dpg'; Value: 'application/vnd.dpgraph'), // do not localize + (Key: 'dfac'; Value: 'application/vnd.dreamfactory'), // do not localize + (Key: 'kpxx'; Value: 'application/vnd.ds-keypoint'), // do not localize + (Key: 'ait'; Value: 'application/vnd.dvb.ait'), // do not localize + (Key: 'svc'; Value: 'application/vnd.dvb.service'), // do not localize + (Key: 'geo'; Value: 'application/vnd.dynageo'), // do not localize + (Key: 'mag'; Value: 'application/vnd.ecowin.chart'), // do not localize + (Key: 'nml'; Value: 'application/vnd.enliven'), // do not localize + (Key: 'esf'; Value: 'application/vnd.epson.esf'), // do not localize + (Key: 'msf'; Value: 'application/vnd.epson.msf'), // do not localize + (Key: 'qam'; Value: 'application/vnd.epson.quickanime'), // do not localize + (Key: 'slt'; Value: 'application/vnd.epson.salt'), // do not localize + (Key: 'ssf'; Value: 'application/vnd.epson.ssf'), // do not localize + (Key: 'es3'; Value: 'application/vnd.eszigno3+xml'), // do not localize + (Key: 'et3'; Value: 'application/vnd.eszigno3+xml'), // do not localize + (Key: 'ez2'; Value: 'application/vnd.ezpix-album'), // do not localize + (Key: 'ez3'; Value: 'application/vnd.ezpix-package'), // do not localize + (Key: 'fdf'; Value: 'application/vnd.fdf'), // do not localize + (Key: 'mseed'; Value: 'application/vnd.fdsn.mseed'), // do not localize + (Key: 'seed'; Value: 'application/vnd.fdsn.seed'), // do not localize + (Key: 'dataless'; Value: 'application/vnd.fdsn.seed'), // do not localize + (Key: 'gph'; Value: 'application/vnd.flographit'), // do not localize + (Key: 'ftc'; Value: 'application/vnd.fluxtime.clip'), // do not localize + (Key: 'fm'; Value: 'application/vnd.framemaker'), // do not localize + (Key: 'frame'; Value: 'application/vnd.framemaker'), // do not localize + (Key: 'maker'; Value: 'application/vnd.framemaker'), // do not localize + (Key: 'book'; Value: 'application/vnd.framemaker'), // do not localize + (Key: 'fnc'; Value: 'application/vnd.frogans.fnc'), // do not localize + (Key: 'ltf'; Value: 'application/vnd.frogans.ltf'), // do not localize + (Key: 'fsc'; Value: 'application/vnd.fsc.weblaunch'), // do not localize + (Key: 'oas'; Value: 'application/vnd.fujitsu.oasys'), // do not localize + (Key: 'oa2'; Value: 'application/vnd.fujitsu.oasys2'), // do not localize + (Key: 'oa3'; Value: 'application/vnd.fujitsu.oasys3'), // do not localize + (Key: 'fg5'; Value: 'application/vnd.fujitsu.oasysgp'), // do not localize + (Key: 'bh2'; Value: 'application/vnd.fujitsu.oasysprs'), // do not localize + (Key: 'ddd'; Value: 'application/vnd.fujixerox.ddd'), // do not localize + (Key: 'xdw'; Value: 'application/vnd.fujixerox.docuworks'), // do not localize + (Key: 'xbd'; Value: 'application/vnd.fujixerox.docuworks.binder'), // do not localize + (Key: 'fzs'; Value: 'application/vnd.fuzzysheet'), // do not localize + (Key: 'txd'; Value: 'application/vnd.genomatix.tuxedo'), // do not localize + (Key: 'ggb'; Value: 'application/vnd.geogebra.file'), // do not localize + (Key: 'ggt'; Value: 'application/vnd.geogebra.tool'), // do not localize + (Key: 'gex'; Value: 'application/vnd.geometry-explorer'), // do not localize + (Key: 'gre'; Value: 'application/vnd.geometry-explorer'), // do not localize + (Key: 'gxt'; Value: 'application/vnd.geonext'), // do not localize + (Key: 'g2w'; Value: 'application/vnd.geoplan'), // do not localize + (Key: 'g3w'; Value: 'application/vnd.geospace'), // do not localize + (Key: 'gmx'; Value: 'application/vnd.gmx'), // do not localize + (Key: 'kml'; Value: 'application/vnd.google-earth.kml+xml'), // do not localize + (Key: 'kmz'; Value: 'application/vnd.google-earth.kmz'), // do not localize + (Key: 'gqf'; Value: 'application/vnd.grafeq'), // do not localize + (Key: 'gqs'; Value: 'application/vnd.grafeq'), // do not localize + (Key: 'gac'; Value: 'application/vnd.groove-account'), // do not localize + (Key: 'ghf'; Value: 'application/vnd.groove-help'), // do not localize + (Key: 'gim'; Value: 'application/vnd.groove-identity-message'), // do not localize + (Key: 'grv'; Value: 'application/vnd.groove-injector'), // do not localize + (Key: 'gtm'; Value: 'application/vnd.groove-tool-message'), // do not localize + (Key: 'tpl'; Value: 'application/vnd.groove-tool-template'), // do not localize + (Key: 'vcg'; Value: 'application/vnd.groove-vcard'), // do not localize + (Key: 'hal'; Value: 'application/vnd.hal+xml'), // do not localize + (Key: 'zmm'; Value: 'application/vnd.handheld-entertainment+xml'), // do not localize + (Key: 'hbci'; Value: 'application/vnd.hbci'), // do not localize + (Key: 'les'; Value: 'application/vnd.hhe.lesson-player'), // do not localize + (Key: 'hpgl'; Value: 'application/vnd.hp-hpgl'), // do not localize + (Key: 'hpid'; Value: 'application/vnd.hp-hpid'), // do not localize + (Key: 'hps'; Value: 'application/vnd.hp-hps'), // do not localize + (Key: 'jlt'; Value: 'application/vnd.hp-jlyt'), // do not localize + (Key: 'pcl'; Value: 'application/vnd.hp-pcl'), // do not localize + (Key: 'pclxl'; Value: 'application/vnd.hp-pclxl'), // do not localize + (Key: 'sfd-hdstx'; Value: 'application/vnd.hydrostatix.sof-data'), // do not localize + (Key: 'mpy'; Value: 'application/vnd.ibm.minipay'), // do not localize + (Key: 'afp'; Value: 'application/vnd.ibm.modcap'), // do not localize + (Key: 'listafp'; Value: 'application/vnd.ibm.modcap'), // do not localize + (Key: 'list3820'; Value: 'application/vnd.ibm.modcap'), // do not localize + (Key: 'irm'; Value: 'application/vnd.ibm.rights-management'), // do not localize + (Key: 'sc'; Value: 'application/vnd.ibm.secure-container'), // do not localize + (Key: 'icc'; Value: 'application/vnd.iccprofile'), // do not localize + (Key: 'icm'; Value: 'application/vnd.iccprofile'), // do not localize + (Key: 'igl'; Value: 'application/vnd.igloader'), // do not localize + (Key: 'ivp'; Value: 'application/vnd.immervision-ivp'), // do not localize + (Key: 'ivu'; Value: 'application/vnd.immervision-ivu'), // do not localize + (Key: 'igm'; Value: 'application/vnd.insors.igm'), // do not localize + (Key: 'xpw'; Value: 'application/vnd.intercon.formnet'), // do not localize + (Key: 'xpx'; Value: 'application/vnd.intercon.formnet'), // do not localize + (Key: 'i2g'; Value: 'application/vnd.intergeo'), // do not localize + (Key: 'qbo'; Value: 'application/vnd.intu.qbo'), // do not localize + (Key: 'qfx'; Value: 'application/vnd.intu.qfx'), // do not localize + (Key: 'rcprofile'; Value: 'application/vnd.ipunplugged.rcprofile'), // do not localize + (Key: 'irp'; Value: 'application/vnd.irepository.package+xml'), // do not localize + (Key: 'xpr'; Value: 'application/vnd.is-xpr'), // do not localize + (Key: 'fcs'; Value: 'application/vnd.isac.fcs'), // do not localize + (Key: 'jam'; Value: 'application/vnd.jam'), // do not localize + (Key: 'rms'; Value: 'application/vnd.jcp.javame.midlet-rms'), // do not localize + (Key: 'jisp'; Value: 'application/vnd.jisp'), // do not localize + (Key: 'joda'; Value: 'application/vnd.joost.joda-archive'), // do not localize + (Key: 'ktz'; Value: 'application/vnd.kahootz'), // do not localize + (Key: 'ktr'; Value: 'application/vnd.kahootz'), // do not localize + (Key: 'karbon'; Value: 'application/vnd.kde.karbon'), // do not localize + (Key: 'chrt'; Value: 'application/vnd.kde.kchart'), // do not localize + (Key: 'kfo'; Value: 'application/vnd.kde.kformula'), // do not localize + (Key: 'flw'; Value: 'application/vnd.kde.kivio'), // do not localize + (Key: 'kon'; Value: 'application/vnd.kde.kontour'), // do not localize + (Key: 'kpr'; Value: 'application/vnd.kde.kpresenter'), // do not localize + (Key: 'kpt'; Value: 'application/vnd.kde.kpresenter'), // do not localize + (Key: 'ksp'; Value: 'application/vnd.kde.kspread'), // do not localize + (Key: 'kwd'; Value: 'application/vnd.kde.kword'), // do not localize + (Key: 'kwt'; Value: 'application/vnd.kde.kword'), // do not localize + (Key: 'htke'; Value: 'application/vnd.kenameaapp'), // do not localize + (Key: 'kia'; Value: 'application/vnd.kidspiration'), // do not localize + (Key: 'kne'; Value: 'application/vnd.kinar'), // do not localize + (Key: 'knp'; Value: 'application/vnd.kinar'), // do not localize + (Key: 'skp'; Value: 'application/vnd.koan'), // do not localize + (Key: 'skd'; Value: 'application/vnd.koan'), // do not localize + (Key: 'skt'; Value: 'application/vnd.koan'), // do not localize + (Key: 'skm'; Value: 'application/vnd.koan'), // do not localize + (Key: 'sse'; Value: 'application/vnd.kodak-descriptor'), // do not localize + (Key: 'lasxml'; Value: 'application/vnd.las.las+xml'), // do not localize + (Key: 'lbd'; Value: 'application/vnd.llamagraphics.life-balance.desktop'), // do not localize + (Key: 'lbe'; Value: 'application/vnd.llamagraphics.life-balance.exchange+xml'), // do not localize + (Key: '123'; Value: 'application/vnd.lotus-1-2-3'), // do not localize + (Key: 'apr'; Value: 'application/vnd.lotus-approach'), // do not localize + (Key: 'pre'; Value: 'application/vnd.lotus-freelance'), // do not localize + (Key: 'nsf'; Value: 'application/vnd.lotus-notes'), // do not localize + (Key: 'org'; Value: 'application/vnd.lotus-organizer'), // do not localize + (Key: 'scm'; Value: 'application/vnd.lotus-screencam'), // do not localize + (Key: 'lwp'; Value: 'application/vnd.lotus-wordpro'), // do not localize + (Key: 'portpkg'; Value: 'application/vnd.macports.portpkg'), // do not localize + (Key: 'mcd'; Value: 'application/vnd.mcd'), // do not localize + (Key: 'mc1'; Value: 'application/vnd.medcalcdata'), // do not localize + (Key: 'cdkey'; Value: 'application/vnd.mediastation.cdkey'), // do not localize + (Key: 'mwf'; Value: 'application/vnd.mfer'), // do not localize + (Key: 'mfm'; Value: 'application/vnd.mfmp'), // do not localize + (Key: 'flo'; Value: 'application/vnd.micrografx.flo'), // do not localize + (Key: 'igx'; Value: 'application/vnd.micrografx.igx'), // do not localize + (Key: 'mif'; Value: 'application/vnd.mif'), // do not localize + (Key: 'daf'; Value: 'application/vnd.mobius.daf'), // do not localize + (Key: 'dis'; Value: 'application/vnd.mobius.dis'), // do not localize + (Key: 'mbk'; Value: 'application/vnd.mobius.mbk'), // do not localize + (Key: 'mqy'; Value: 'application/vnd.mobius.mqy'), // do not localize + (Key: 'msl'; Value: 'application/vnd.mobius.msl'), // do not localize + (Key: 'plc'; Value: 'application/vnd.mobius.plc'), // do not localize + (Key: 'txf'; Value: 'application/vnd.mobius.txf'), // do not localize + (Key: 'mpn'; Value: 'application/vnd.mophun.application'), // do not localize + (Key: 'mpc'; Value: 'application/vnd.mophun.certificate'), // do not localize + (Key: 'xul'; Value: 'application/vnd.mozilla.xul+xml'), // do not localize + (Key: 'cil'; Value: 'application/vnd.ms-artgalry'), // do not localize + (Key: 'cab'; Value: 'application/vnd.ms-cab-compressed'), // do not localize + (Key: 'xls'; Value: 'application/vnd.ms-excel'), // do not localize + (Key: 'xlm'; Value: 'application/vnd.ms-excel'), // do not localize + (Key: 'xla'; Value: 'application/vnd.ms-excel'), // do not localize + (Key: 'xlc'; Value: 'application/vnd.ms-excel'), // do not localize + (Key: 'xlt'; Value: 'application/vnd.ms-excel'), // do not localize + (Key: 'xlw'; Value: 'application/vnd.ms-excel'), // do not localize + (Key: 'xlam'; Value: 'application/vnd.ms-excel.addin.macroenabled.12'), // do not localize + (Key: 'xlsb'; Value: 'application/vnd.ms-excel.sheet.binary.macroenabled.12'), // do not localize + (Key: 'xlsm'; Value: 'application/vnd.ms-excel.sheet.macroenabled.12'), // do not localize + (Key: 'xltm'; Value: 'application/vnd.ms-excel.template.macroenabled.12'), // do not localize + (Key: 'eot'; Value: 'application/vnd.ms-fontobject'), // do not localize + (Key: 'chm'; Value: 'application/vnd.ms-htmlhelp'), // do not localize + (Key: 'ims'; Value: 'application/vnd.ms-ims'), // do not localize + (Key: 'lrm'; Value: 'application/vnd.ms-lrm'), // do not localize + (Key: 'thmx'; Value: 'application/vnd.ms-officetheme'), // do not localize + (Key: 'cat'; Value: 'application/vnd.ms-pki.seccat'), // do not localize + (Key: 'stl'; Value: 'application/vnd.ms-pki.stl'), // do not localize + (Key: 'ppt'; Value: 'application/vnd.ms-powerpoint'), // do not localize + (Key: 'pps'; Value: 'application/vnd.ms-powerpoint'), // do not localize + (Key: 'pot'; Value: 'application/vnd.ms-powerpoint'), // do not localize + (Key: 'ppam'; Value: 'application/vnd.ms-powerpoint.addin.macroenabled.12'), // do not localize + (Key: 'pptm'; Value: 'application/vnd.ms-powerpoint.presentation.macroenabled.12'), // do not localize + (Key: 'sldm'; Value: 'application/vnd.ms-powerpoint.slide.macroenabled.12'), // do not localize + (Key: 'ppsm'; Value: 'application/vnd.ms-powerpoint.slideshow.macroenabled.12'), // do not localize + (Key: 'potm'; Value: 'application/vnd.ms-powerpoint.template.macroenabled.12'), // do not localize + (Key: 'mpp'; Value: 'application/vnd.ms-project'), // do not localize + (Key: 'mpt'; Value: 'application/vnd.ms-project'), // do not localize + (Key: 'docm'; Value: 'application/vnd.ms-word.document.macroenabled.12'), // do not localize + (Key: 'dotm'; Value: 'application/vnd.ms-word.template.macroenabled.12'), // do not localize + (Key: 'wps'; Value: 'application/vnd.ms-works'), // do not localize + (Key: 'wks'; Value: 'application/vnd.ms-works'), // do not localize + (Key: 'wcm'; Value: 'application/vnd.ms-works'), // do not localize + (Key: 'wdb'; Value: 'application/vnd.ms-works'), // do not localize + (Key: 'wpl'; Value: 'application/vnd.ms-wpl'), // do not localize + (Key: 'xps'; Value: 'application/vnd.ms-xpsdocument'), // do not localize + (Key: 'mseq'; Value: 'application/vnd.mseq'), // do not localize + (Key: 'mus'; Value: 'application/vnd.musician'), // do not localize + (Key: 'msty'; Value: 'application/vnd.muvee.style'), // do not localize + (Key: 'taglet'; Value: 'application/vnd.mynfc'), // do not localize + (Key: 'nlu'; Value: 'application/vnd.neurolanguage.nlu'), // do not localize + (Key: 'ntf'; Value: 'application/vnd.nitf'), // do not localize + (Key: 'nitf'; Value: 'application/vnd.nitf'), // do not localize + (Key: 'nnd'; Value: 'application/vnd.noblenet-directory'), // do not localize + (Key: 'nns'; Value: 'application/vnd.noblenet-sealer'), // do not localize + (Key: 'nnw'; Value: 'application/vnd.noblenet-web'), // do not localize + (Key: 'ngdat'; Value: 'application/vnd.nokia.n-gage.data'), // do not localize + (Key: 'n-gage'; Value: 'application/vnd.nokia.n-gage.symbian.install'), // do not localize + (Key: 'rpst'; Value: 'application/vnd.nokia.radio-preset'), // do not localize + (Key: 'rpss'; Value: 'application/vnd.nokia.radio-presets'), // do not localize + (Key: 'edm'; Value: 'application/vnd.novadigm.edm'), // do not localize + (Key: 'edx'; Value: 'application/vnd.novadigm.edx'), // do not localize + (Key: 'ext'; Value: 'application/vnd.novadigm.ext'), // do not localize + (Key: 'odc'; Value: 'application/vnd.oasis.opendocument.chart'), // do not localize + (Key: 'otc'; Value: 'application/vnd.oasis.opendocument.chart-template'), // do not localize + (Key: 'odb'; Value: 'application/vnd.oasis.opendocument.database'), // do not localize + (Key: 'odf'; Value: 'application/vnd.oasis.opendocument.formula'), // do not localize + (Key: 'odft'; Value: 'application/vnd.oasis.opendocument.formula-template'), // do not localize + (Key: 'odg'; Value: 'application/vnd.oasis.opendocument.graphics'), // do not localize + (Key: 'otg'; Value: 'application/vnd.oasis.opendocument.graphics-template'), // do not localize + (Key: 'odi'; Value: 'application/vnd.oasis.opendocument.image'), // do not localize + (Key: 'oti'; Value: 'application/vnd.oasis.opendocument.image-template'), // do not localize + (Key: 'odp'; Value: 'application/vnd.oasis.opendocument.presentation'), // do not localize + (Key: 'otp'; Value: 'application/vnd.oasis.opendocument.presentation-template'), // do not localize + (Key: 'ods'; Value: 'application/vnd.oasis.opendocument.spreadsheet'), // do not localize + (Key: 'ots'; Value: 'application/vnd.oasis.opendocument.spreadsheet-template'), // do not localize + (Key: 'odt'; Value: 'application/vnd.oasis.opendocument.text'), // do not localize + (Key: 'odm'; Value: 'application/vnd.oasis.opendocument.text-master'), // do not localize + (Key: 'ott'; Value: 'application/vnd.oasis.opendocument.text-template'), // do not localize + (Key: 'oth'; Value: 'application/vnd.oasis.opendocument.text-web'), // do not localize + (Key: 'xo'; Value: 'application/vnd.olpc-sugar'), // do not localize + (Key: 'dd2'; Value: 'application/vnd.oma.dd2+xml'), // do not localize + (Key: 'oxt'; Value: 'application/vnd.openofficeorg.extension'), // do not localize + (Key: 'pptx'; Value: 'application/vnd.openxmlformats-officedocument.presentationml.presentation'), // do not localize + (Key: 'sldx'; Value: 'application/vnd.openxmlformats-officedocument.presentationml.slide'), // do not localize + (Key: 'ppsx'; Value: 'application/vnd.openxmlformats-officedocument.presentationml.slideshow'), // do not localize + (Key: 'potx'; Value: 'application/vnd.openxmlformats-officedocument.presentationml.template'), // do not localize + (Key: 'xlsx'; Value: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'), // do not localize + (Key: 'xltx'; Value: 'application/vnd.openxmlformats-officedocument.spreadsheetml.template'), // do not localize + (Key: 'docx'; Value: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'), // do not localize + (Key: 'dotx'; Value: 'application/vnd.openxmlformats-officedocument.wordprocessingml.template'), // do not localize + (Key: 'mgp'; Value: 'application/vnd.osgeo.mapguide.package'), // do not localize + (Key: 'dp'; Value: 'application/vnd.osgi.dp'), // do not localize + (Key: 'esa'; Value: 'application/vnd.osgi.subsystem'), // do not localize + (Key: 'pdb'; Value: 'application/vnd.palm'), // do not localize + (Key: 'pqa'; Value: 'application/vnd.palm'), // do not localize + (Key: 'oprc'; Value: 'application/vnd.palm'), // do not localize + (Key: 'paw'; Value: 'application/vnd.pawaafile'), // do not localize + (Key: 'str'; Value: 'application/vnd.pg.format'), // do not localize + (Key: 'ei6'; Value: 'application/vnd.pg.osasli'), // do not localize + (Key: 'efif'; Value: 'application/vnd.picsel'), // do not localize + (Key: 'wg'; Value: 'application/vnd.pmi.widget'), // do not localize + (Key: 'plf'; Value: 'application/vnd.pocketlearn'), // do not localize + (Key: 'pbd'; Value: 'application/vnd.powerbuilder6'), // do not localize + (Key: 'box'; Value: 'application/vnd.previewsystems.box'), // do not localize + (Key: 'mgz'; Value: 'application/vnd.proteus.magazine'), // do not localize + (Key: 'qps'; Value: 'application/vnd.publishare-delta-tree'), // do not localize + (Key: 'ptid'; Value: 'application/vnd.pvi.ptid1'), // do not localize + (Key: 'qxd'; Value: 'application/vnd.quark.quarkxpress'), // do not localize + (Key: 'qxt'; Value: 'application/vnd.quark.quarkxpress'), // do not localize + (Key: 'qwd'; Value: 'application/vnd.quark.quarkxpress'), // do not localize + (Key: 'qwt'; Value: 'application/vnd.quark.quarkxpress'), // do not localize + (Key: 'qxl'; Value: 'application/vnd.quark.quarkxpress'), // do not localize + (Key: 'qxb'; Value: 'application/vnd.quark.quarkxpress'), // do not localize + (Key: 'bed'; Value: 'application/vnd.realvnc.bed'), // do not localize + (Key: 'mxl'; Value: 'application/vnd.recordare.musicxml'), // do not localize + (Key: 'musicxml'; Value: 'application/vnd.recordare.musicxml+xml'), // do not localize + (Key: 'cryptonote'; Value: 'application/vnd.rig.cryptonote'), // do not localize + (Key: 'cod'; Value: 'application/vnd.rim.cod'), // do not localize + (Key: 'rm'; Value: 'application/vnd.rn-realmedia'), // do not localize + (Key: 'rmvb'; Value: 'application/vnd.rn-realmedia-vbr'), // do not localize + (Key: 'link66'; Value: 'application/vnd.route66.link66+xml'), // do not localize + (Key: 'st'; Value: 'application/vnd.sailingtracker.track'), // do not localize + (Key: 'see'; Value: 'application/vnd.seemail'), // do not localize + (Key: 'sema'; Value: 'application/vnd.sema'), // do not localize + (Key: 'semd'; Value: 'application/vnd.semd'), // do not localize + (Key: 'semf'; Value: 'application/vnd.semf'), // do not localize + (Key: 'ifm'; Value: 'application/vnd.shana.informed.formdata'), // do not localize + (Key: 'itp'; Value: 'application/vnd.shana.informed.formtemplate'), // do not localize + (Key: 'iif'; Value: 'application/vnd.shana.informed.interchange'), // do not localize + (Key: 'ipk'; Value: 'application/vnd.shana.informed.package'), // do not localize + (Key: 'twd'; Value: 'application/vnd.simtech-mindmapper'), // do not localize + (Key: 'twds'; Value: 'application/vnd.simtech-mindmapper'), // do not localize + (Key: 'mmf'; Value: 'application/vnd.smaf'), // do not localize + (Key: 'teacher'; Value: 'application/vnd.smart.teacher'), // do not localize + (Key: 'sdkm'; Value: 'application/vnd.solent.sdkm+xml'), // do not localize + (Key: 'sdkd'; Value: 'application/vnd.solent.sdkm+xml'), // do not localize + (Key: 'dxp'; Value: 'application/vnd.spotfire.dxp'), // do not localize + (Key: 'sfs'; Value: 'application/vnd.spotfire.sfs'), // do not localize + (Key: 'sdc'; Value: 'application/vnd.stardivision.calc'), // do not localize + (Key: 'sda'; Value: 'application/vnd.stardivision.draw'), // do not localize + (Key: 'sdd'; Value: 'application/vnd.stardivision.impress'), // do not localize + (Key: 'smf'; Value: 'application/vnd.stardivision.math'), // do not localize + (Key: 'sdw'; Value: 'application/vnd.stardivision.writer'), // do not localize + (Key: 'vor'; Value: 'application/vnd.stardivision.writer'), // do not localize + (Key: 'sgl'; Value: 'application/vnd.stardivision.writer-global'), // do not localize + (Key: 'smzip'; Value: 'application/vnd.stepmania.package'), // do not localize + (Key: 'sm'; Value: 'application/vnd.stepmania.stepchart'), // do not localize + (Key: 'sxc'; Value: 'application/vnd.sun.xml.calc'), // do not localize + (Key: 'stc'; Value: 'application/vnd.sun.xml.calc.template'), // do not localize + (Key: 'sxd'; Value: 'application/vnd.sun.xml.draw'), // do not localize + (Key: 'std'; Value: 'application/vnd.sun.xml.draw.template'), // do not localize + (Key: 'sxi'; Value: 'application/vnd.sun.xml.impress'), // do not localize + (Key: 'sti'; Value: 'application/vnd.sun.xml.impress.template'), // do not localize + (Key: 'sxm'; Value: 'application/vnd.sun.xml.math'), // do not localize + (Key: 'sxw'; Value: 'application/vnd.sun.xml.writer'), // do not localize + (Key: 'sxg'; Value: 'application/vnd.sun.xml.writer.global'), // do not localize + (Key: 'stw'; Value: 'application/vnd.sun.xml.writer.template'), // do not localize + (Key: 'sus'; Value: 'application/vnd.sus-calendar'), // do not localize + (Key: 'susp'; Value: 'application/vnd.sus-calendar'), // do not localize + (Key: 'svd'; Value: 'application/vnd.svd'), // do not localize + (Key: 'sis'; Value: 'application/vnd.symbian.install'), // do not localize + (Key: 'sisx'; Value: 'application/vnd.symbian.install'), // do not localize + (Key: 'xsm'; Value: 'application/vnd.syncml+xml'), // do not localize + (Key: 'bdm'; Value: 'application/vnd.syncml.dm+wbxml'), // do not localize + (Key: 'xdm'; Value: 'application/vnd.syncml.dm+xml'), // do not localize + (Key: 'tao'; Value: 'application/vnd.tao.intent-module-archive'), // do not localize + (Key: 'pcap'; Value: 'application/vnd.tcpdump.pcap'), // do not localize + (Key: 'cap'; Value: 'application/vnd.tcpdump.pcap'), // do not localize + (Key: 'dmp'; Value: 'application/vnd.tcpdump.pcap'), // do not localize + (Key: 'tmo'; Value: 'application/vnd.tmobile-livetv'), // do not localize + (Key: 'tpt'; Value: 'application/vnd.trid.tpt'), // do not localize + (Key: 'mxs'; Value: 'application/vnd.triscape.mxs'), // do not localize + (Key: 'tra'; Value: 'application/vnd.trueapp'), // do not localize + (Key: 'ufd'; Value: 'application/vnd.ufdl'), // do not localize + (Key: 'ufdl'; Value: 'application/vnd.ufdl'), // do not localize + (Key: 'utz'; Value: 'application/vnd.uiq.theme'), // do not localize + (Key: 'umj'; Value: 'application/vnd.umajin'), // do not localize + (Key: 'unityweb'; Value: 'application/vnd.unity'), // do not localize + (Key: 'uoml'; Value: 'application/vnd.uoml+xml'), // do not localize + (Key: 'vcx'; Value: 'application/vnd.vcx'), // do not localize + (Key: 'vsd'; Value: 'application/vnd.visio'), // do not localize + (Key: 'vst'; Value: 'application/vnd.visio'), // do not localize + (Key: 'vss'; Value: 'application/vnd.visio'), // do not localize + (Key: 'vsw'; Value: 'application/vnd.visio'), // do not localize + (Key: 'vis'; Value: 'application/vnd.visionary'), // do not localize + (Key: 'vsf'; Value: 'application/vnd.vsf'), // do not localize + (Key: 'wbxml'; Value: 'application/vnd.wap.wbxml'), // do not localize + (Key: 'wmlc'; Value: 'application/vnd.wap.wmlc'), // do not localize + (Key: 'wmlsc'; Value: 'application/vnd.wap.wmlscriptc'), // do not localize + (Key: 'wtb'; Value: 'application/vnd.webturbo'), // do not localize + (Key: 'nbp'; Value: 'application/vnd.wolfram.player'), // do not localize + (Key: 'wpd'; Value: 'application/vnd.wordperfect'), // do not localize + (Key: 'wqd'; Value: 'application/vnd.wqd'), // do not localize + (Key: 'stf'; Value: 'application/vnd.wt.stf'), // do not localize + (Key: 'xar'; Value: 'application/vnd.xara'), // do not localize + (Key: 'xfdl'; Value: 'application/vnd.xfdl'), // do not localize + (Key: 'hvd'; Value: 'application/vnd.yamaha.hv-dic'), // do not localize + (Key: 'hvs'; Value: 'application/vnd.yamaha.hv-script'), // do not localize + (Key: 'hvp'; Value: 'application/vnd.yamaha.hv-voice'), // do not localize + (Key: 'osf'; Value: 'application/vnd.yamaha.openscoreformat'), // do not localize + (Key: 'osfpvg'; Value: 'application/vnd.yamaha.openscoreformat.osfpvg+xml'), // do not localize + (Key: 'saf'; Value: 'application/vnd.yamaha.smaf-audio'), // do not localize + (Key: 'spf'; Value: 'application/vnd.yamaha.smaf-phrase'), // do not localize + (Key: 'cmp'; Value: 'application/vnd.yellowriver-custom-menu'), // do not localize + (Key: 'zir'; Value: 'application/vnd.zul'), // do not localize + (Key: 'zirz'; Value: 'application/vnd.zul'), // do not localize + (Key: 'zaz'; Value: 'application/vnd.zzazz.deck+xml'), // do not localize + (Key: 'vxml'; Value: 'application/voicexml+xml'), // do not localize + (Key: 'wgt'; Value: 'application/widget'), // do not localize + (Key: 'hlp'; Value: 'application/winhlp'), // do not localize + (Key: 'wsdl'; Value: 'application/wsdl+xml'), // do not localize + (Key: 'wspolicy'; Value: 'application/wspolicy+xml'), // do not localize + (Key: '7z'; Value: 'application/x-7z-compressed'), // do not localize + (Key: 'abw'; Value: 'application/x-abiword'), // do not localize + (Key: 'ace'; Value: 'application/x-ace-compressed'), // do not localize + (Key: 'dmg'; Value: 'application/x-apple-diskimage'), // do not localize + (Key: 'aab'; Value: 'application/x-authorware-bin'), // do not localize + (Key: 'x32'; Value: 'application/x-authorware-bin'), // do not localize + (Key: 'u32'; Value: 'application/x-authorware-bin'), // do not localize + (Key: 'vox'; Value: 'application/x-authorware-bin'), // do not localize + (Key: 'aam'; Value: 'application/x-authorware-map'), // do not localize + (Key: 'aas'; Value: 'application/x-authorware-seg'), // do not localize + (Key: 'bcpio'; Value: 'application/x-bcpio'), // do not localize + (Key: 'torrent'; Value: 'application/x-bittorrent'), // do not localize + (Key: 'blb'; Value: 'application/x-blorb'), // do not localize + (Key: 'blorb'; Value: 'application/x-blorb'), // do not localize + (Key: 'bz'; Value: 'application/x-bzip'), // do not localize + (Key: 'bz2'; Value: 'application/x-bzip2'), // do not localize + (Key: 'boz'; Value: 'application/x-bzip2'), // do not localize + (Key: 'cbr'; Value: 'application/x-cbr'), // do not localize + (Key: 'cba'; Value: 'application/x-cbr'), // do not localize + (Key: 'cbt'; Value: 'application/x-cbr'), // do not localize + (Key: 'cbz'; Value: 'application/x-cbr'), // do not localize + (Key: 'cb7'; Value: 'application/x-cbr'), // do not localize + (Key: 'vcd'; Value: 'application/x-cdlink'), // do not localize + (Key: 'cfs'; Value: 'application/x-cfs-compressed'), // do not localize + (Key: 'chat'; Value: 'application/x-chat'), // do not localize + (Key: 'pgn'; Value: 'application/x-chess-pgn'), // do not localize + (Key: 'nsc'; Value: 'application/x-conference'), // do not localize + (Key: 'cpio'; Value: 'application/x-cpio'), // do not localize + (Key: 'csh'; Value: 'application/x-csh'), // do not localize + (Key: 'deb'; Value: 'application/x-debian-package'), // do not localize + (Key: 'udeb'; Value: 'application/x-debian-package'), // do not localize + (Key: 'dgc'; Value: 'application/x-dgc-compressed'), // do not localize + (Key: 'dir'; Value: 'application/x-director'), // do not localize + (Key: 'dcr'; Value: 'application/x-director'), // do not localize + (Key: 'dxr'; Value: 'application/x-director'), // do not localize + (Key: 'cst'; Value: 'application/x-director'), // do not localize + (Key: 'cct'; Value: 'application/x-director'), // do not localize + (Key: 'cxt'; Value: 'application/x-director'), // do not localize + (Key: 'w3d'; Value: 'application/x-director'), // do not localize + (Key: 'fgd'; Value: 'application/x-director'), // do not localize + (Key: 'swa'; Value: 'application/x-director'), // do not localize + (Key: 'wad'; Value: 'application/x-doom'), // do not localize + (Key: 'ncx'; Value: 'application/x-dtbncx+xml'), // do not localize + (Key: 'dtb'; Value: 'application/x-dtbook+xml'), // do not localize + (Key: 'res'; Value: 'application/x-dtbresource+xml'), // do not localize + (Key: 'dvi'; Value: 'application/x-dvi'), // do not localize + (Key: 'evy'; Value: 'application/x-envoy'), // do not localize + (Key: 'eva'; Value: 'application/x-eva'), // do not localize + (Key: 'bdf'; Value: 'application/x-font-bdf'), // do not localize + (Key: 'gsf'; Value: 'application/x-font-ghostscript'), // do not localize + (Key: 'psf'; Value: 'application/x-font-linux-psf'), // do not localize + (Key: 'otf'; Value: 'application/x-font-otf'), // do not localize + (Key: 'pcf'; Value: 'application/x-font-pcf'), // do not localize + (Key: 'snf'; Value: 'application/x-font-snf'), // do not localize + (Key: 'ttf'; Value: 'application/x-font-ttf'), // do not localize + (Key: 'ttc'; Value: 'application/x-font-ttf'), // do not localize + (Key: 'pfa'; Value: 'application/x-font-type1'), // do not localize + (Key: 'pfb'; Value: 'application/x-font-type1'), // do not localize + (Key: 'pfm'; Value: 'application/x-font-type1'), // do not localize + (Key: 'afm'; Value: 'application/x-font-type1'), // do not localize + (Key: 'woff'; Value: 'application/x-font-woff'), // do not localize + (Key: 'arc'; Value: 'application/x-freearc'), // do not localize + (Key: 'spl'; Value: 'application/x-futuresplash'), // do not localize + (Key: 'gca'; Value: 'application/x-gca-compressed'), // do not localize + (Key: 'ulx'; Value: 'application/x-glulx'), // do not localize + (Key: 'gnumeric'; Value: 'application/x-gnumeric'), // do not localize + (Key: 'gramps'; Value: 'application/x-gramps-xml'), // do not localize + (Key: 'gtar'; Value: 'application/x-gtar'), // do not localize + (Key: 'hdf'; Value: 'application/x-hdf'), // do not localize + (Key: 'install'; Value: 'application/x-install-instructions'), // do not localize + (Key: 'iso'; Value: 'application/x-iso9660-image'), // do not localize + (Key: 'jnlp'; Value: 'application/x-java-jnlp-file'), // do not localize + (Key: 'latex'; Value: 'application/x-latex'), // do not localize + (Key: 'lzh'; Value: 'application/x-lzh-compressed'), // do not localize + (Key: 'lha'; Value: 'application/x-lzh-compressed'), // do not localize + (Key: 'mie'; Value: 'application/x-mie'), // do not localize + (Key: 'prc'; Value: 'application/x-mobipocket-ebook'), // do not localize + (Key: 'mobi'; Value: 'application/x-mobipocket-ebook'), // do not localize + (Key: 'application'; Value: 'application/x-ms-application'), // do not localize + (Key: 'lnk'; Value: 'application/x-ms-shortcut'), // do not localize + (Key: 'wmd'; Value: 'application/x-ms-wmd'), // do not localize + (Key: 'wmz'; Value: 'application/x-ms-wmz'), // do not localize + (Key: 'xbap'; Value: 'application/x-ms-xbap'), // do not localize + (Key: 'mdb'; Value: 'application/x-msaccess'), // do not localize + (Key: 'obd'; Value: 'application/x-msbinder'), // do not localize + (Key: 'crd'; Value: 'application/x-mscardfile'), // do not localize + (Key: 'clp'; Value: 'application/x-msclip'), // do not localize + (Key: 'exe'; Value: 'application/x-msdownload'), // do not localize + (Key: 'dll'; Value: 'application/x-msdownload'), // do not localize + (Key: 'com'; Value: 'application/x-msdownload'), // do not localize + (Key: 'bat'; Value: 'application/x-msdownload'), // do not localize + (Key: 'msi'; Value: 'application/x-msdownload'), // do not localize + (Key: 'mvb'; Value: 'application/x-msmediaview'), // do not localize + (Key: 'm13'; Value: 'application/x-msmediaview'), // do not localize + (Key: 'm14'; Value: 'application/x-msmediaview'), // do not localize + (Key: 'wmf'; Value: 'application/x-msmetafile'), // do not localize + (Key: 'wmz'; Value: 'application/x-msmetafile'), // do not localize + (Key: 'emf'; Value: 'application/x-msmetafile'), // do not localize + (Key: 'emz'; Value: 'application/x-msmetafile'), // do not localize + (Key: 'mny'; Value: 'application/x-msmoney'), // do not localize + (Key: 'pub'; Value: 'application/x-mspublisher'), // do not localize + (Key: 'scd'; Value: 'application/x-msschedule'), // do not localize + (Key: 'trm'; Value: 'application/x-msterminal'), // do not localize + (Key: 'wri'; Value: 'application/x-mswrite'), // do not localize + (Key: 'nc'; Value: 'application/x-netcdf'), // do not localize + (Key: 'cdf'; Value: 'application/x-netcdf'), // do not localize + (Key: 'nzb'; Value: 'application/x-nzb'), // do not localize + (Key: 'p12'; Value: 'application/x-pkcs12'), // do not localize + (Key: 'pfx'; Value: 'application/x-pkcs12'), // do not localize + (Key: 'p7b'; Value: 'application/x-pkcs7-certificates'), // do not localize + (Key: 'spc'; Value: 'application/x-pkcs7-certificates'), // do not localize + (Key: 'p7r'; Value: 'application/x-pkcs7-certreqresp'), // do not localize + (Key: 'rar'; Value: 'application/x-rar-compressed'), // do not localize + (Key: 'ris'; Value: 'application/x-research-info-systems'), // do not localize + (Key: 'sh'; Value: 'application/x-sh'), // do not localize + (Key: 'shar'; Value: 'application/x-shar'), // do not localize + (Key: 'swf'; Value: 'application/x-shockwave-flash'), // do not localize + (Key: 'xap'; Value: 'application/x-silverlight-app'), // do not localize + (Key: 'sql'; Value: 'application/x-sql'), // do not localize + (Key: 'sit'; Value: 'application/x-stuffit'), // do not localize + (Key: 'sitx'; Value: 'application/x-stuffitx'), // do not localize + (Key: 'srt'; Value: 'application/x-subrip'), // do not localize + (Key: 'sv4cpio'; Value: 'application/x-sv4cpio'), // do not localize + (Key: 'sv4crc'; Value: 'application/x-sv4crc'), // do not localize + (Key: 't3'; Value: 'application/x-t3vm-image'), // do not localize + (Key: 'gam'; Value: 'application/x-tads'), // do not localize + (Key: 'tar'; Value: 'application/x-tar'), // do not localize + (Key: 'tcl'; Value: 'application/x-tcl'), // do not localize + (Key: 'tex'; Value: 'application/x-tex'), // do not localize + (Key: 'tfm'; Value: 'application/x-tex-tfm'), // do not localize + (Key: 'texinfo'; Value: 'application/x-texinfo'), // do not localize + (Key: 'texi'; Value: 'application/x-texinfo'), // do not localize + (Key: 'obj'; Value: 'application/x-tgif'), // do not localize + (Key: 'ustar'; Value: 'application/x-ustar'), // do not localize + (Key: 'src'; Value: 'application/x-wais-source'), // do not localize + (Key: 'der'; Value: 'application/x-x509-ca-cert'), // do not localize + (Key: 'crt'; Value: 'application/x-x509-ca-cert'), // do not localize + (Key: 'fig'; Value: 'application/x-xfig'), // do not localize + (Key: 'xlf'; Value: 'application/x-xliff+xml'), // do not localize + (Key: 'xpi'; Value: 'application/x-xpinstall'), // do not localize + (Key: 'xz'; Value: 'application/x-xz'), // do not localize + (Key: 'z1'; Value: 'application/x-zmachine'), // do not localize + (Key: 'z2'; Value: 'application/x-zmachine'), // do not localize + (Key: 'z3'; Value: 'application/x-zmachine'), // do not localize + (Key: 'z4'; Value: 'application/x-zmachine'), // do not localize + (Key: 'z5'; Value: 'application/x-zmachine'), // do not localize + (Key: 'z6'; Value: 'application/x-zmachine'), // do not localize + (Key: 'z7'; Value: 'application/x-zmachine'), // do not localize + (Key: 'z8'; Value: 'application/x-zmachine'), // do not localize + (Key: 'xaml'; Value: 'application/xaml+xml'), // do not localize + (Key: 'xdf'; Value: 'application/xcap-diff+xml'), // do not localize + (Key: 'xenc'; Value: 'application/xenc+xml'), // do not localize + (Key: 'xhtml'; Value: 'application/xhtml+xml'), // do not localize + (Key: 'xht'; Value: 'application/xhtml+xml'), // do not localize + (Key: 'xml'; Value: 'application/xml'), // do not localize + (Key: 'xsl'; Value: 'application/xml'), // do not localize + (Key: 'dtd'; Value: 'application/xml-dtd'), // do not localize + (Key: 'xop'; Value: 'application/xop+xml'), // do not localize + (Key: 'xpl'; Value: 'application/xproc+xml'), // do not localize + (Key: 'xslt'; Value: 'application/xslt+xml'), // do not localize + (Key: 'xspf'; Value: 'application/xspf+xml'), // do not localize + (Key: 'mxml'; Value: 'application/xv+xml'), // do not localize + (Key: 'xhvml'; Value: 'application/xv+xml'), // do not localize + (Key: 'xvml'; Value: 'application/xv+xml'), // do not localize + (Key: 'xvm'; Value: 'application/xv+xml'), // do not localize + (Key: 'yang'; Value: 'application/yang'), // do not localize + (Key: 'yin'; Value: 'application/yin+xml'), // do not localize + (Key: 'zip'; Value: 'application/zip'), // do not localize + (Key: 'adp'; Value: 'audio/adpcm'), // do not localize + (Key: 'au'; Value: 'audio/basic'), // do not localize + (Key: 'snd'; Value: 'audio/basic'), // do not localize + (Key: 'mid'; Value: 'audio/midi'), // do not localize + (Key: 'midi'; Value: 'audio/midi'), // do not localize + (Key: 'kar'; Value: 'audio/midi'), // do not localize + (Key: 'rmi'; Value: 'audio/midi'), // do not localize + (Key: 'mp4a'; Value: 'audio/mp4'), // do not localize + (Key: 'mpga'; Value: 'audio/mpeg'), // do not localize + (Key: 'mp2'; Value: 'audio/mpeg'), // do not localize + (Key: 'mp2a'; Value: 'audio/mpeg'), // do not localize + (Key: 'mp3'; Value: 'audio/mpeg'), // do not localize + (Key: 'm2a'; Value: 'audio/mpeg'), // do not localize + (Key: 'm3a'; Value: 'audio/mpeg'), // do not localize + (Key: 'oga'; Value: 'audio/ogg'), // do not localize + (Key: 'ogg'; Value: 'audio/ogg'), // do not localize + (Key: 'spx'; Value: 'audio/ogg'), // do not localize + (Key: 's3m'; Value: 'audio/s3m'), // do not localize + (Key: 'sil'; Value: 'audio/silk'), // do not localize + (Key: 'uva'; Value: 'audio/vnd.dece.audio'), // do not localize + (Key: 'uvva'; Value: 'audio/vnd.dece.audio'), // do not localize + (Key: 'eol'; Value: 'audio/vnd.digital-winds'), // do not localize + (Key: 'dra'; Value: 'audio/vnd.dra'), // do not localize + (Key: 'dts'; Value: 'audio/vnd.dts'), // do not localize + (Key: 'dtshd'; Value: 'audio/vnd.dts.hd'), // do not localize + (Key: 'lvp'; Value: 'audio/vnd.lucent.voice'), // do not localize + (Key: 'pya'; Value: 'audio/vnd.ms-playready.media.pya'), // do not localize + (Key: 'ecelp4800'; Value: 'audio/vnd.nuera.ecelp4800'), // do not localize + (Key: 'ecelp7470'; Value: 'audio/vnd.nuera.ecelp7470'), // do not localize + (Key: 'ecelp9600'; Value: 'audio/vnd.nuera.ecelp9600'), // do not localize + (Key: 'rip'; Value: 'audio/vnd.rip'), // do not localize + (Key: 'weba'; Value: 'audio/webm'), // do not localize + (Key: 'aac'; Value: 'audio/x-aac'), // do not localize + (Key: 'aif'; Value: 'audio/x-aiff'), // do not localize + (Key: 'aiff'; Value: 'audio/x-aiff'), // do not localize + (Key: 'aifc'; Value: 'audio/x-aiff'), // do not localize + (Key: 'caf'; Value: 'audio/x-caf'), // do not localize + (Key: 'flac'; Value: 'audio/x-flac'), // do not localize + (Key: 'mka'; Value: 'audio/x-matroska'), // do not localize + (Key: 'm3u'; Value: 'audio/x-mpegurl'), // do not localize + (Key: 'wax'; Value: 'audio/x-ms-wax'), // do not localize + (Key: 'wma'; Value: 'audio/x-ms-wma'), // do not localize + (Key: 'ram'; Value: 'audio/x-pn-realaudio'), // do not localize + (Key: 'ra'; Value: 'audio/x-pn-realaudio'), // do not localize + (Key: 'rmp'; Value: 'audio/x-pn-realaudio-plugin'), // do not localize + (Key: 'wav'; Value: 'audio/x-wav'), // do not localize + (Key: 'xm'; Value: 'audio/xm'), // do not localize + (Key: 'cdx'; Value: 'chemical/x-cdx'), // do not localize + (Key: 'cif'; Value: 'chemical/x-cif'), // do not localize + (Key: 'cmdf'; Value: 'chemical/x-cmdf'), // do not localize + (Key: 'cml'; Value: 'chemical/x-cml'), // do not localize + (Key: 'csml'; Value: 'chemical/x-csml'), // do not localize + (Key: 'xyz'; Value: 'chemical/x-xyz'), // do not localize + (Key: 'bmp'; Value: 'image/bmp'), // do not localize + (Key: 'cgm'; Value: 'image/cgm'), // do not localize + (Key: 'g3'; Value: 'image/g3fax'), // do not localize + (Key: 'gif'; Value: 'image/gif'), // do not localize + (Key: 'ief'; Value: 'image/ief'), // do not localize + (Key: 'jpeg'; Value: 'image/jpeg'), // do not localize + (Key: 'jpg'; Value: 'image/jpeg'), // do not localize + (Key: 'jpe'; Value: 'image/jpeg'), // do not localize + (Key: 'ktx'; Value: 'image/ktx'), // do not localize + (Key: 'png'; Value: 'image/png'), // do not localize + (Key: 'btif'; Value: 'image/prs.btif'), // do not localize + (Key: 'sgi'; Value: 'image/sgi'), // do not localize + (Key: 'svg'; Value: 'image/svg+xml'), // do not localize + (Key: 'svgz'; Value: 'image/svg+xml'), // do not localize + (Key: 'tiff'; Value: 'image/tiff'), // do not localize + (Key: 'tif'; Value: 'image/tiff'), // do not localize + (Key: 'psd'; Value: 'image/vnd.adobe.photoshop'), // do not localize + (Key: 'uvi'; Value: 'image/vnd.dece.graphic'), // do not localize + (Key: 'uvvi'; Value: 'image/vnd.dece.graphic'), // do not localize + (Key: 'uvg'; Value: 'image/vnd.dece.graphic'), // do not localize + (Key: 'uvvg'; Value: 'image/vnd.dece.graphic'), // do not localize + (Key: 'sub'; Value: 'image/vnd.dvb.subtitle'), // do not localize + (Key: 'djvu'; Value: 'image/vnd.djvu'), // do not localize + (Key: 'djv'; Value: 'image/vnd.djvu'), // do not localize + (Key: 'dwg'; Value: 'image/vnd.dwg'), // do not localize + (Key: 'dxf'; Value: 'image/vnd.dxf'), // do not localize + (Key: 'fbs'; Value: 'image/vnd.fastbidsheet'), // do not localize + (Key: 'fpx'; Value: 'image/vnd.fpx'), // do not localize + (Key: 'fst'; Value: 'image/vnd.fst'), // do not localize + (Key: 'mmr'; Value: 'image/vnd.fujixerox.edmics-mmr'), // do not localize + (Key: 'rlc'; Value: 'image/vnd.fujixerox.edmics-rlc'), // do not localize + (Key: 'mdi'; Value: 'image/vnd.ms-modi'), // do not localize + (Key: 'wdp'; Value: 'image/vnd.ms-photo'), // do not localize + (Key: 'npx'; Value: 'image/vnd.net-fpx'), // do not localize + (Key: 'wbmp'; Value: 'image/vnd.wap.wbmp'), // do not localize + (Key: 'xif'; Value: 'image/vnd.xiff'), // do not localize + (Key: 'webp'; Value: 'image/webp'), // do not localize + (Key: '3ds'; Value: 'image/x-3ds'), // do not localize + (Key: 'ras'; Value: 'image/x-cmu-raster'), // do not localize + (Key: 'cmx'; Value: 'image/x-cmx'), // do not localize + (Key: 'fh'; Value: 'image/x-freehand'), // do not localize + (Key: 'fhc'; Value: 'image/x-freehand'), // do not localize + (Key: 'fh4'; Value: 'image/x-freehand'), // do not localize + (Key: 'fh5'; Value: 'image/x-freehand'), // do not localize + (Key: 'fh7'; Value: 'image/x-freehand'), // do not localize + (Key: 'ico'; Value: 'image/x-icon'), // do not localize + (Key: 'sid'; Value: 'image/x-mrsid-image'), // do not localize + (Key: 'pcx'; Value: 'image/x-pcx'), // do not localize + (Key: 'pic'; Value: 'image/x-pict'), // do not localize + (Key: 'pct'; Value: 'image/x-pict'), // do not localize + (Key: 'pnm'; Value: 'image/x-portable-anymap'), // do not localize + (Key: 'pbm'; Value: 'image/x-portable-bitmap'), // do not localize + (Key: 'pgm'; Value: 'image/x-portable-graymap'), // do not localize + (Key: 'ppm'; Value: 'image/x-portable-pixmap'), // do not localize + (Key: 'rgb'; Value: 'image/x-rgb'), // do not localize + (Key: 'tga'; Value: 'image/x-tga'), // do not localize + (Key: 'xbm'; Value: 'image/x-xbitmap'), // do not localize + (Key: 'xpm'; Value: 'image/x-xpixmap'), // do not localize + (Key: 'xwd'; Value: 'image/x-xwindowdump'), // do not localize + (Key: 'eml'; Value: 'message/rfc822'), // do not localize + (Key: 'mime'; Value: 'message/rfc822'), // do not localize + (Key: 'igs'; Value: 'model/iges'), // do not localize + (Key: 'iges'; Value: 'model/iges'), // do not localize + (Key: 'msh'; Value: 'model/mesh'), // do not localize + (Key: 'mesh'; Value: 'model/mesh'), // do not localize + (Key: 'silo'; Value: 'model/mesh'), // do not localize + (Key: 'dae'; Value: 'model/vnd.collada+xml'), // do not localize + (Key: 'dwf'; Value: 'model/vnd.dwf'), // do not localize + (Key: 'gdl'; Value: 'model/vnd.gdl'), // do not localize + (Key: 'gtw'; Value: 'model/vnd.gtw'), // do not localize + (Key: 'mts'; Value: 'model/vnd.mts'), // do not localize + (Key: 'vtu'; Value: 'model/vnd.vtu'), // do not localize + (Key: 'wrl'; Value: 'model/vrml'), // do not localize + (Key: 'vrml'; Value: 'model/vrml'), // do not localize + (Key: 'x3db'; Value: 'model/x3d+binary'), // do not localize + (Key: 'x3dbz'; Value: 'model/x3d+binary'), // do not localize + (Key: 'x3dv'; Value: 'model/x3d+vrml'), // do not localize + (Key: 'x3dvz'; Value: 'model/x3d+vrml'), // do not localize + (Key: 'x3d'; Value: 'model/x3d+xml'), // do not localize + (Key: 'x3dz'; Value: 'model/x3d+xml'), // do not localize + (Key: 'appcache'; Value: 'text/cache-manifest'), // do not localize + (Key: 'ics'; Value: 'text/calendar'), // do not localize + (Key: 'ifb'; Value: 'text/calendar'), // do not localize + (Key: 'css'; Value: 'text/css'), // do not localize + (Key: 'csv'; Value: 'text/csv'), // do not localize + (Key: 'html'; Value: 'text/html'), // do not localize + (Key: 'htm'; Value: 'text/html'), // do not localize + (Key: 'n3'; Value: 'text/n3'), // do not localize + (Key: 'txt'; Value: 'text/plain'), // do not localize + (Key: 'text'; Value: 'text/plain'), // do not localize + (Key: 'conf'; Value: 'text/plain'), // do not localize + (Key: 'def'; Value: 'text/plain'), // do not localize + (Key: 'list'; Value: 'text/plain'), // do not localize + (Key: 'log'; Value: 'text/plain'), // do not localize + (Key: 'in'; Value: 'text/plain'), // do not localize + (Key: 'dsc'; Value: 'text/prs.lines.tag'), // do not localize + (Key: 'rtx'; Value: 'text/richtext'), // do not localize + (Key: 'sgml'; Value: 'text/sgml'), // do not localize + (Key: 'sgm'; Value: 'text/sgml'), // do not localize + (Key: 'tsv'; Value: 'text/tab-separated-values'), // do not localize + (Key: 't'; Value: 'text/troff'), // do not localize + (Key: 'tr'; Value: 'text/troff'), // do not localize + (Key: 'roff'; Value: 'text/troff'), // do not localize + (Key: 'man'; Value: 'text/troff'), // do not localize + (Key: 'me'; Value: 'text/troff'), // do not localize + (Key: 'ms'; Value: 'text/troff'), // do not localize + (Key: 'ttl'; Value: 'text/turtle'), // do not localize + (Key: 'uri'; Value: 'text/uri-list'), // do not localize + (Key: 'uris'; Value: 'text/uri-list'), // do not localize + (Key: 'urls'; Value: 'text/uri-list'), // do not localize + (Key: 'vcard'; Value: 'text/vcard'), // do not localize + (Key: 'curl'; Value: 'text/vnd.curl'), // do not localize + (Key: 'dcurl'; Value: 'text/vnd.curl.dcurl'), // do not localize + (Key: 'scurl'; Value: 'text/vnd.curl.scurl'), // do not localize + (Key: 'mcurl'; Value: 'text/vnd.curl.mcurl'), // do not localize + (Key: 'sub'; Value: 'text/vnd.dvb.subtitle'), // do not localize + (Key: 'fly'; Value: 'text/vnd.fly'), // do not localize + (Key: 'flx'; Value: 'text/vnd.fmi.flexstor'), // do not localize + (Key: 'gv'; Value: 'text/vnd.graphviz'), // do not localize + (Key: '3dml'; Value: 'text/vnd.in3d.3dml'), // do not localize + (Key: 'spot'; Value: 'text/vnd.in3d.spot'), // do not localize + (Key: 'jad'; Value: 'text/vnd.sun.j2me.app-descriptor'), // do not localize + (Key: 'wml'; Value: 'text/vnd.wap.wml'), // do not localize + (Key: 'wmls'; Value: 'text/vnd.wap.wmlscript'), // do not localize + (Key: 's'; Value: 'text/x-asm'), // do not localize + (Key: 'asm'; Value: 'text/x-asm'), // do not localize + (Key: 'c'; Value: 'text/x-c'), // do not localize + (Key: 'cc'; Value: 'text/x-c'), // do not localize + (Key: 'cxx'; Value: 'text/x-c'), // do not localize + (Key: 'cpp'; Value: 'text/x-c'), // do not localize + (Key: 'h'; Value: 'text/x-c'), // do not localize + (Key: 'hh'; Value: 'text/x-c'), // do not localize + (Key: 'dic'; Value: 'text/x-c'), // do not localize + (Key: 'f'; Value: 'text/x-fortran'), // do not localize + (Key: 'for'; Value: 'text/x-fortran'), // do not localize + (Key: 'f77'; Value: 'text/x-fortran'), // do not localize + (Key: 'f90'; Value: 'text/x-fortran'), // do not localize + (Key: 'java'; Value: 'text/x-java-source'), // do not localize + (Key: 'opml'; Value: 'text/x-opml'), // do not localize + (Key: 'p'; Value: 'text/x-pascal'), // do not localize + (Key: 'pas'; Value: 'text/x-pascal'), // do not localize + (Key: 'nfo'; Value: 'text/x-nfo'), // do not localize + (Key: 'etx'; Value: 'text/x-setext'), // do not localize + (Key: 'sfv'; Value: 'text/x-sfv'), // do not localize + (Key: 'uu'; Value: 'text/x-uuencode'), // do not localize + (Key: 'vcs'; Value: 'text/x-vcalendar'), // do not localize + (Key: 'vcf'; Value: 'text/x-vcard'), // do not localize + (Key: '3gp'; Value: 'video/3gpp'), // do not localize + (Key: '3g2'; Value: 'video/3gpp2'), // do not localize + (Key: 'h261'; Value: 'video/h261'), // do not localize + (Key: 'h263'; Value: 'video/h263'), // do not localize + (Key: 'h264'; Value: 'video/h264'), // do not localize + (Key: 'jpgv'; Value: 'video/jpeg'), // do not localize + (Key: 'jpm'; Value: 'video/jpm'), // do not localize + (Key: 'jpgm'; Value: 'video/jpm'), // do not localize + (Key: 'mj2'; Value: 'video/mj2'), // do not localize + (Key: 'mjp2'; Value: 'video/mj2'), // do not localize + (Key: 'mp4'; Value: 'video/mp4'), // do not localize + (Key: 'mp4v'; Value: 'video/mp4'), // do not localize + (Key: 'mpg4'; Value: 'video/mp4'), // do not localize + (Key: 'mpeg'; Value: 'video/mpeg'), // do not localize + (Key: 'mpg'; Value: 'video/mpeg'), // do not localize + (Key: 'mpe'; Value: 'video/mpeg'), // do not localize + (Key: 'm1v'; Value: 'video/mpeg'), // do not localize + (Key: 'm2v'; Value: 'video/mpeg'), // do not localize + (Key: 'ogv'; Value: 'video/ogg'), // do not localize + (Key: 'qt'; Value: 'video/quicktime'), // do not localize + (Key: 'mov'; Value: 'video/quicktime'), // do not localize + (Key: 'uvh'; Value: 'video/vnd.dece.hd'), // do not localize + (Key: 'uvvh'; Value: 'video/vnd.dece.hd'), // do not localize + (Key: 'uvm'; Value: 'video/vnd.dece.mobile'), // do not localize + (Key: 'uvvm'; Value: 'video/vnd.dece.mobile'), // do not localize + (Key: 'uvp'; Value: 'video/vnd.dece.pd'), // do not localize + (Key: 'uvvp'; Value: 'video/vnd.dece.pd'), // do not localize + (Key: 'uvs'; Value: 'video/vnd.dece.sd'), // do not localize + (Key: 'uvvs'; Value: 'video/vnd.dece.sd'), // do not localize + (Key: 'uvv'; Value: 'video/vnd.dece.video'), // do not localize + (Key: 'uvvv'; Value: 'video/vnd.dece.video'), // do not localize + (Key: 'dvb'; Value: 'video/vnd.dvb.file'), // do not localize + (Key: 'fvt'; Value: 'video/vnd.fvt'), // do not localize + (Key: 'mxu'; Value: 'video/vnd.mpegurl'), // do not localize + (Key: 'm4u'; Value: 'video/vnd.mpegurl'), // do not localize + (Key: 'pyv'; Value: 'video/vnd.ms-playready.media.pyv'), // do not localize + (Key: 'uvu'; Value: 'video/vnd.uvvu.mp4'), // do not localize + (Key: 'uvvu'; Value: 'video/vnd.uvvu.mp4'), // do not localize + (Key: 'viv'; Value: 'video/vnd.vivo'), // do not localize + (Key: 'webm'; Value: 'video/webm'), // do not localize + (Key: 'f4v'; Value: 'video/x-f4v'), // do not localize + (Key: 'fli'; Value: 'video/x-fli'), // do not localize + (Key: 'flv'; Value: 'video/x-flv'), // do not localize + (Key: 'm4v'; Value: 'video/x-m4v'), // do not localize + (Key: 'mkv'; Value: 'video/x-matroska'), // do not localize + (Key: 'mk3d'; Value: 'video/x-matroska'), // do not localize + (Key: 'mks'; Value: 'video/x-matroska'), // do not localize + (Key: 'mng'; Value: 'video/x-mng'), // do not localize + (Key: 'asf'; Value: 'video/x-ms-asf'), // do not localize + (Key: 'asx'; Value: 'video/x-ms-asf'), // do not localize + (Key: 'vob'; Value: 'video/x-ms-vob'), // do not localize + (Key: 'wm'; Value: 'video/x-ms-wm'), // do not localize + (Key: 'wmv'; Value: 'video/x-ms-wmv'), // do not localize + (Key: 'wmx'; Value: 'video/x-ms-wmx'), // do not localize + (Key: 'wvx'; Value: 'video/x-ms-wvx'), // do not localize + (Key: 'avi'; Value: 'video/x-msvideo'), // do not localize + (Key: 'movie'; Value: 'video/x-sgi-movie'), // do not localize + (Key: 'smv'; Value: 'video/x-smv'), // do not localize + (Key: 'ice'; Value: 'x-conference/x-cooltalk'), // do not localize + (Key: 'wasm'; Value: 'application/wasm') // do not localize + ); + {$ENDREGION} + +type + THttpMethod = class + public const + GET = 'GET'; + POST = 'POST'; + PUT = 'PUT'; + DELETE = 'DELETE'; + HEAD = 'HEAD'; + OPTIONS = 'OPTIONS'; + TRACE = 'TRACE'; + CONNECT = 'CONNECT'; + PROPFIND = 'PROPFIND'; + LOCK = 'LOCK'; + UNLOCK = 'UNLOCK'; + COPY = 'COPY'; + MOVE = 'MOVE'; + MKCOL = 'MKCOL'; + end; + + {$REGION 'Documentation'} + /// + /// 常用媒体类型 + /// + {$ENDREGION} + TMediaType = class + public const + DELIM_PARAMS = '; '; + CHARSET_NAME = 'charset'; + CHARSET_UTF8 = 'UTF-8'; + CHARSET_UTF8_DEF = CHARSET_NAME + '=' + CHARSET_UTF8; + + TEXT_PLAIN = 'text/plain'; + TEXT_PLAIN_UTF8 = TEXT_PLAIN + DELIM_PARAMS + CHARSET_UTF8_DEF; + + TEXT_XML = 'text/xml'; + TEXT_XML_UTF8 = TEXT_XML + DELIM_PARAMS + CHARSET_UTF8_DEF; + + TEXT_HTML = 'text/html'; + TEXT_HTML_UTF8 = TEXT_HTML + DELIM_PARAMS + CHARSET_UTF8_DEF; + + APPLICATION_JSON = 'application/json'; + APPLICATION_JSON_UTF8 = APPLICATION_JSON + DELIM_PARAMS + CHARSET_UTF8_DEF; + + APPLICATION_XML = 'application/xml'; + APPLICATION_XML_UTF8 = APPLICATION_XML + DELIM_PARAMS + CHARSET_UTF8_DEF; + + APPLICATION_OCTET_STREAM = 'application/octet-stream'; + APPLICATION_FORM_URLENCODED_TYPE = 'application/x-www-form-urlencoded'; + + MULTIPART_FORM_DATA = 'multipart/form-data'; + MULTIPART_FORM_DATA_BOUNDARY = MULTIPART_FORM_DATA + DELIM_PARAMS + 'boundary='; + + WILDCARD = '*/*'; + end; + + TCrossHttpUtils = class + private const + RFC1123_StrWeekDay: string = 'MonTueWedThuFriSatSun'; + RFC1123_StrMonth : string = 'JanFebMarAprMayJunJulAugSepOctNovDec'; + public + class function GetHttpStatusText(const AStatusCode: Integer): string; static; + class function GetFileMIMEType(const AFileName: string): string; static; + class function RFC1123_DateToStr(const ADate: TDateTime): string; static; inline; + class function RFC1123_StrToDate(const ADateStr: string): TDateTime; static; + + class function ExtractUrl(const AUrl: string; out AProtocol, AHost: string; + out APort: Word; out APath: string): Boolean; static; + class function CreateUrl(const AProtocol, AHost: string; + const APort: Word; const APath: string): string; static; + + class function CombinePath(const APath1, APath2: string; const APathDelim: Char = '/'): string; static; + class function IsSamePath(const APath1, APath2: string): Boolean; static; + + class function GetPathWithoutParams(const APath: string): string; static; + + /// + /// 尝试解析本地路径,确保路径安全性 + /// + /// + /// 本地基础目录 + /// + /// + /// 要解析的相对路径 + /// + /// + /// 解析后的完整路径 + /// + /// + /// 如果路径有效且在基础目录内返回True,否则返回False + /// + /// + /// 此函数会验证路径的安全性,防止路径遍历攻击 + /// + class function TryUrlPathToLocalPath(const ALocalBaseDir, AUrlPath: string; + out AResolvedPath: string): Boolean; static; + + class function HtmlEncode(const AInput: string): string; static; + class function HtmlDecode(const AInput: string): string; static; + + /// + /// URL percent-encoding (RFC 3986 §2.1) + /// + /// + /// 待编码字符串(支持 unicode, 内部统一按 UTF-8 字节流处理) + /// + /// + /// 附加的"无需编码"字符集. 默认仅按 RFC 3986 unreserved 集 + /// (ALPHA / DIGIT / "-" / "." / "_" / "~") 不编码, 其他字符全部 percent-encode. + /// 调用方可据 URI 组件传入合理子集, 如 path 段内可保留 ['/', ':', '@']. + /// + /// + /// 是否将输入按"已含 percent-encoded 序列的 URI 组件"对待 (Normalizer 语义). + /// - False (默认, Encoder 语义): 输入视作原始数据, '%' 字符按字面编码为 '%25'. + /// 适用于参数值/表单字段等"原始字节"场景. 与 RFC 3986 §2.1 Encoder 语义、 + /// 主流库 (Go QueryEscape / Python quote / Java URLEncoder) 默认行为一致. + /// - True (Normalizer 语义): 遇到 '%' + 2 hex 数字时保留 3 字符不再编码, + /// 避免二次编码 (RFC 3986 §2.4 "MUST NOT encode the same string more than once"). + /// 适用于"用户传入的 URL 片段可能已部分编码"场景, 类似 Python requote_uri. + /// + class function UrlEncode(const S: string; const ANoConversion: TSysCharSet = []; + const APreserveEncoded: Boolean = False): string; static; + class function UrlDecode(const S: string): string; static; + + // Delphi 12+ 编译器将NativeInt与Integer(目标32位)和Int64(目标64位)等同 + {$IF DEFINED(DELPHI) AND (CompilerVersion < 36)} + class procedure AdjustOffsetCount(const ABodySize: NativeInt; var AOffset, ACount: NativeInt); overload; static; + {$ENDIF} + class procedure AdjustOffsetCount(const ABodySize: Integer; var AOffset, ACount: Integer); overload; static; + class procedure AdjustOffsetCount(const ABodySize: Int64; var AOffset, ACount: Int64); overload; static; + + /// + /// 严格解析 HTTP Range 请求头中的单一 byte-range (RFC 7233 §2.1, §3.1). + /// + /// + /// 原始 Range 头, 如 "bytes=0-499" / "bytes=500-" / "bytes=-200". + /// + /// + /// 资源完整长度, 必须 > 0. + /// + /// + /// 解析成功时, 输出区间起点 (含, 0-based). + /// + /// + /// 解析成功时, 输出区间终点 (含, 0-based, < AContentLength). + /// + /// + /// True: 区间合法且可满足, AStart/AEnd 已正确设置. + /// False: 缺前缀 / 多 range / 非法数字 / 不可满足 (start > end / start >= size / + /// suffix=0). 调用方应返回 416 + "Content-Range: bytes */size". + /// + /// + /// 不支持 multipart/byteranges (含 ',' 一律拒绝), 与 Nginx/Apache 在小文件上的常见策略一致. + /// + class function ParseSingleByteRange(const ARangeHeader: string; + const AContentLength: Int64; out AStart, AEnd: Int64): Boolean; static; + + /// + /// 校验 HTTP header field-value 是否安全, 不允许出现 CR/LF (RFC 7230 §3.2.4). + /// + /// + /// 主要用于防御响应拆分 (HTTP Response Splitting) 攻击: 若业务把含 CR/LF 的用户输入 + /// 写入响应 header, 可能被攻击者注入伪造响应行或 header. + /// + class function IsValidHeaderValue(const AValue: string): Boolean; static; + + /// + /// 校验 HTTP header field-name 是否符合 RFC 7230 token 字符集. + /// + class function IsValidHeaderName(const AName: string): Boolean; static; + + /// + /// 单字符版本: 判断字符是否属于 RFC 7230 §3.2.6 token 字符集. + /// + /// + /// token = ALPHA / DIGIT / "!" "#" "$" "%" "&" "'" "*" "+" "-" "." "^" "_" "`" "|" "~" + /// 提供给逐字节扫描场景 (如 THttpHeader.Decode 单趟状态机) 复用规则, 避免重复定义. + /// + class function IsTokenChar(ACh: Char): Boolean; static; inline; + + /// + /// 单字符版本: 判断字符是否是合法的 HTTP header field-value 字符. + /// + /// + /// 合法: HTAB(#9) / 可见 ASCII ($20..$7E) / $80+ 高位字符 (历史宽松, 兼容 UTF-8). + /// 非法: NUL/CR/LF 等其他 CTL ($00..$08, $0A..$1F) 与 DEL ($7F). + /// 提供给逐字节扫描场景复用规则, 避免重复定义. + /// + class function IsHeaderValueChar(ACh: Char): Boolean; static; inline; + end; + +implementation + +{ TCrossHttpUtils } + +class function TCrossHttpUtils.GetHttpStatusText(const AStatusCode: Integer): string; +var + LStatusItem: THttpStatus; +begin + for LStatusItem in STATUS_CODES do + if (LStatusItem.Code = AStatusCode) then Exit(LStatusItem.Text); + Result := AStatusCode.ToString; +end; + +class function TCrossHttpUtils.GetPathWithoutParams( + const APath: string): string; +var + LIndex: Integer; +begin + LIndex := APath.IndexOf('?'); + if (LIndex >= 0) then + Result := APath.Substring(0, LIndex) + else + Result := APath; +end; + +class function TCrossHttpUtils.HtmlDecode(const AInput: string): string; +var + LSp, LRp, LCp, LTp: PChar; + LStr: string; + I, LCode: Integer; + LValid: Boolean; +begin + if (AInput = '') then Exit(''); + + SetLength(Result, Length(AInput)); + LSp := PChar(AInput); + LRp := PChar(Result); + while LSp^ <> #0 do + begin + case LSp^ of + '&': + begin + LCp := LSp; + Inc(LSp); + LValid := False; + case LSp^ of + 'a': + if StrLComp(LSp, 'amp;', 4) = 0 then { do not localize } + begin + Inc(LSp, 3); + LRp^ := '&'; + LValid := True; + end + else if StrLComp(LSp, 'apos;', 5) = 0 then { do not localize } + begin + Inc(LSp, 4); + LRp^ := ''''; + LValid := True; + end; + 'l': + if StrLComp(LSp, 'lt;', 3) = 0 then { do not localize } + begin + Inc(LSp, 2); + LRp^ := '<'; + LValid := True; + end; + 'g': + if StrLComp(LSp, 'gt;', 3) = 0 then { do not localize } + begin + Inc(LSp, 2); + LRp^ := '>'; + LValid := True; + end; + 'q': + if StrLComp(LSp, 'quot;', 5) = 0 then { do not localize } + begin + Inc(LSp, 4); + LRp^ := '"'; + LValid := True; + end; + '#': + begin + LTp := LSp; + Inc(LTp); + while (LSp^ <> ';') and (LSp^ <> #0) do + Inc(LSp); + SetString(LStr, LTp, LSp - LTp); + Val(LStr, I, LCode); + if LCode = 0 then + begin + if I >= $10000 then + begin + // DoDecode surrogate pair + LRp^ := Char(((I - $10000) div $400) + $D800); + Inc(LRp); + LRp^ := Char(((I - $10000) and $3FF) + $DC00); + end + else + LRp^ := Chr((I)); + LValid := True; + end + else + LSp := LTp - 1; + end; + end; + if not LValid then + begin + LSp := LCp; + LRp^ := LSp^; + end; + end + else + LRp^ := LSp^; + end; + Inc(LRp); + Inc(LSp); + end; + SetLength(Result, LRp - PChar(Result)); +end; + +class function TCrossHttpUtils.HtmlEncode(const AInput: string): string; +var + LSp, LRp: PChar; +begin + if (AInput = '') then Exit(''); + + SetLength(Result, Length(AInput) * 10); + LSp := PChar(AInput); + LRp := PChar(Result); + // Convert: &, <, >, " + while LSp^ <> #0 do + begin + case LSp^ of + '&': + begin + StrMove(LRp, '&', 5); + Inc(LRp, 5); + end; + '<': + begin + StrMove(LRp, '<', 4); + Inc(LRp, 4); + end; + '>': + begin + StrMove(LRp, '>', 4); + Inc(LRp, 4); + end; + '"': + begin + StrMove(LRp, '"', 6); + Inc(LRp, 6); + end; + else + begin + LRp^ := LSp^; + Inc(LRp); + end; + end; + Inc(LSp); + end; + SetLength(Result, LRp - PChar(Result)); +end; + +class function TCrossHttpUtils.IsSamePath(const APath1, + APath2: string): Boolean; +begin + if (Length(APath1) >= Length(APath2)) then + Result := (Pos(APath2, APath1) = 1) + else + Result := (Pos(APath1, APath2) = 1); +end; + +{$IF DEFINED(DELPHI) AND (CompilerVersion < 36)} +class procedure TCrossHttpUtils.AdjustOffsetCount(const ABodySize: NativeInt; + var AOffset, ACount: NativeInt); +begin + {$region '修正 AOffset'} + // 偏移为正数, 从头部开始计算偏移 + if (AOffset >= 0) then + begin + AOffset := AOffset; + if (AOffset >= ABodySize) then + AOffset := ABodySize - 1; + end else + // 偏移为负数, 从尾部开始计算偏移 + begin + AOffset := ABodySize + AOffset; + if (AOffset < 0) then + AOffset := 0; + end; + {$endregion} + + {$region '修正 ACount'} + // ACount<=0表示需要处理所有数据 + if (ACount <= 0) then + ACount := ABodySize; + + if (ABodySize - AOffset < ACount) then + ACount := ABodySize - AOffset; + {$endregion} +end; +{$ENDIF} + +class procedure TCrossHttpUtils.AdjustOffsetCount(const ABodySize: Integer; + var AOffset, ACount: Integer); +begin + {$region '修正 AOffset'} + // 偏移为正数, 从头部开始计算偏移 + if (AOffset >= 0) then + begin + AOffset := AOffset; + if (AOffset >= ABodySize) then + AOffset := ABodySize - 1; + end else + // 偏移为负数, 从尾部开始计算偏移 + begin + AOffset := ABodySize + AOffset; + if (AOffset < 0) then + AOffset := 0; + end; + {$endregion} + + {$region '修正 ACount'} + // ACount<=0表示需要处理所有数据 + if (ACount <= 0) then + ACount := ABodySize; + + if (ABodySize - AOffset < ACount) then + ACount := ABodySize - AOffset; + {$endregion} +end; + +class procedure TCrossHttpUtils.AdjustOffsetCount(const ABodySize: Int64; + var AOffset, ACount: Int64); +begin + {$region '修正 AOffset'} + // 偏移为正数, 从头部开始计算偏移 + if (AOffset >= 0) then + begin + AOffset := AOffset; + if (AOffset >= ABodySize) then + AOffset := ABodySize - 1; + end else + // 偏移为负数, 从尾部开始计算偏移 + begin + AOffset := ABodySize + AOffset; + if (AOffset < 0) then + AOffset := 0; + end; + {$endregion} + + {$region '修正 ACount'} + // ACount<=0表示需要处理所有数据 + if (ACount <= 0) then + ACount := ABodySize; + + if (ABodySize - AOffset < ACount) then + ACount := ABodySize - AOffset; + {$endregion} +end; + +class function TCrossHttpUtils.CombinePath(const APath1, + APath2: string; const APathDelim: Char): string; +begin + Result := TPathUtils.Combine(APath1, APath2, APathDelim); +end; + +class function TCrossHttpUtils.CreateUrl(const AProtocol, AHost: string; + const APort: Word; const APath: string): string; +var + LPath: string; +begin + if (APath = '') then + LPath := '/' + else if (APath[1] = '/') then + LPath := APath + else + LPath := '/' + APath; + + Result := Format('%s://%s', [AProtocol, AHost]); + + if (SameText(AProtocol, HTTP) and (APort = HTTP_DEFAULT_PORT)) + or (SameText(AProtocol, HTTPS) and (APort = HTTPS_DEFAULT_PORT)) then + Result := Result + LPath + else + Result := Result + Format(':%d%s', [APort, LPath]); +end; + +class function TCrossHttpUtils.ExtractUrl(const AUrl: string; out AProtocol, + AHost: string; out APort: Word; out APath: string): Boolean; +var + LProtocolIndex, LIPv6Index, LPortIndex, LPathIndex, LQueryIndex, LPort: Integer; + LPortStr: string; +begin + // http://www.test.com/abc + // http://www.test.com:8080/abc + // https://www.test.com/abc + // https://www.test.com:8080/abc + // www.test.com:8080/abc + // www.test.com/abc + // www.test.com + // http://[aabb::20:80:5:2]:8080/abc + // [aabb::20:80:5:2] + + Result := False; + + // 找 :// 定位协议类型 + LProtocolIndex := AUrl.IndexOf('://'); + if (LProtocolIndex >= 0) then + begin + // 提取协议类型 + AProtocol := AUrl.Substring(0, LProtocolIndex).Trim; + Inc(LProtocolIndex, 3); + end else + begin + // 默认协议 http + AProtocol := HTTP; + LProtocolIndex := 0; + end; + + // 找 ] 定位IPv6地址 + LIPv6Index := AUrl.IndexOf(']', LProtocolIndex); + + if (LIPv6Index >= 0) then + begin + // 找 : 定位端口 + LPortIndex := AUrl.IndexOf(':', LIPv6Index + 1); + + // 找 / 定位路径 + LPathIndex := AUrl.IndexOf('/', LIPv6Index + 1); + + // 避免在参数部分出现 : 被当成端口定位 + if (LPathIndex >= 0) and (LPortIndex > LPathIndex) then + LPortIndex := -1; + + // 找 ? 定位参数 + LQueryIndex := AUrl.IndexOf('?', LIPv6Index + 1); + end else + begin + // 找 : 定位端口 + LPortIndex := AUrl.IndexOf(':', LProtocolIndex); + + // 找 / 定位路径 + LPathIndex := AUrl.IndexOf('/', LProtocolIndex); + + // 避免在参数部分出现 : 被当成端口定位 + if (LPathIndex >= 0) and (LPortIndex > LPathIndex) then + LPortIndex := -1; + + // 找 ? 定位参数 + LQueryIndex := AUrl.IndexOf('?', LProtocolIndex); + end; + + if (LPathIndex < 0) then + begin + if (LQueryIndex >= 0) then + LPathIndex := LQueryIndex + else + LPathIndex := Length(AUrl); + end; + + if (LPortIndex >= 0) then + begin + // 提取主机地址 + AHost := AUrl.Substring(LProtocolIndex, LPortIndex - LProtocolIndex); + + // 提取主机端口 + LPortStr := AUrl.Substring(LPortIndex + 1, LPathIndex - LPortIndex - 1); + if not TryStrToInt(LPortStr, LPort) then Exit; + + APort := LPort; + end else + begin + // 提取主机地址 + AHost := AUrl.Substring(LProtocolIndex, LPathIndex - LProtocolIndex); + + // 根据协议类型决定默认端口 + if TStrUtils.SameText(AProtocol, HTTPS) + or TStrUtils.SameText(AProtocol, WSS) then + APort := HTTPS_DEFAULT_PORT + else + APort := HTTP_DEFAULT_PORT; + end; + + // 提取路径 + APath := AUrl.Substring(LPathIndex, MaxInt); + if (APath = '') then + APath := '/' + else if (APath[1] <> '/') then + APath := '/' + APath; + + Result := (AHost <> ''); +end; + +class function TCrossHttpUtils.GetFileMIMEType(const AFileName: string): string; +var + LExt: string; + LMimeItem: TMimeValue; +begin + LExt := ExtractFileExt(AFileName).Substring(1); + for LMimeItem in MIME_TYPES do + if TStrUtils.SameText(LMimeItem.Key, LExt) then + Exit(LMimeItem.Value); + Result := TMediaType.APPLICATION_OCTET_STREAM; +end; + +class function TCrossHttpUtils.RFC1123_DateToStr(const ADate: TDateTime): string; +begin + // Fri, 30 Jul 2024 10:10:35 GMT + Result := ADate.ToRFC1123(True); +end; + +class function TCrossHttpUtils.RFC1123_StrToDate(const ADateStr: string) : TDateTime; +var + LYear, LMonth, LDay: Word; + LHour, LMin, LSec: Word; +begin + // Fri, 30 Jul 2024 10:10:35 GMT + if (Length(ADateStr) = 29) then + begin + LDay := StrToIntDef(Copy(ADateStr, 6, 2), 0); + LMonth := (Pos(Copy(ADateStr, 9, 3), RFC1123_StrMonth) + 2) div 3; + LYear := StrToIntDef(Copy(ADateStr, 13, 4), 0); + LHour := StrToIntDef(Copy(ADateStr, 18, 2), 0); + LMin := StrToIntDef(Copy(ADateStr, 21, 2), 0); + LSec := StrToIntDef(Copy(ADateStr, 24, 2), 0); + end else + // Fri, 30 Jul 24 10:10:35 GMT + // Fri, 30-Jul-24 10:10:35 GMT + if (Length(ADateStr) = 27) then + begin + LDay := StrToIntDef(Copy(ADateStr, 6, 2), 0); + LMonth := (Pos(Copy(ADateStr, 9, 3), RFC1123_StrMonth) + 2) div 3; + LYear := 2000 + StrToIntDef(Copy(ADateStr, 13, 2), 0); + LHour := StrToIntDef(Copy(ADateStr, 16, 2), 0); + LMin := StrToIntDef(Copy(ADateStr, 19, 2), 0); + LSec := StrToIntDef(Copy(ADateStr, 22, 2), 0); + end else + Exit(0); + + if not TryEncodeDateTime(LYear, LMonth, LDay, LHour, LMin, LSec, 0, Result) then + Result := 0; +end; + +class function TCrossHttpUtils.TryUrlPathToLocalPath(const ALocalBaseDir, + AUrlPath: string; out AResolvedPath: string): Boolean; +begin + Result := TPathUtils.TryResolveLocalPath( + ALocalBaseDir, + TCrossHttpUtils.GetPathWithoutParams(AUrlPath).Trim, + AResolvedPath); +end; + +class function TCrossHttpUtils.UrlDecode(const S: string): string; +var + LSrcBytes, LDstBytes: TBytes; + LSrcLen, LSrcIdx, LDstIdx: Integer; + H, L: Byte; + C: Byte; +begin + if (S = '') then Exit(''); + + // 先把输入 unicode 字符串 UTF-8 编码为字节流, 与 UrlEncode 对称. + // 这样允许输入混合: ASCII percent-encoded ('%E4%B8%AD') 与 unicode 原字符 ('中') 都能正确处理. + LSrcBytes := TEncoding.UTF8.GetBytes(S); + LSrcLen := Length(LSrcBytes); + SetLength(LDstBytes, LSrcLen); + + LSrcIdx := 0; + LDstIdx := 0; + while (LSrcIdx < LSrcLen) do + begin + C := LSrcBytes[LSrcIdx]; + case C of + // 兼容早期 form-urlencoded: '+' → 空格 + Ord('+'): + begin + LDstBytes[LDstIdx] := Ord(' '); + Inc(LSrcIdx); + end; + + Ord('%'): + begin + if (LSrcIdx + 2 < LSrcLen) + and TUtils.HexCharToByte(Char(LSrcBytes[LSrcIdx + 1]), H) + and TUtils.HexCharToByte(Char(LSrcBytes[LSrcIdx + 2]), L) then + begin + LDstBytes[LDstIdx] := L + (H shl 4); + Inc(LSrcIdx, 3); + end else + begin + // 非法 %xx, 原样保留 '%' 字符 + LDstBytes[LDstIdx] := Ord('%'); + Inc(LSrcIdx); + end; + end; + else + // 包含 ASCII 与 UTF-8 多字节序列的高字节, 都原样透传 + LDstBytes[LDstIdx] := C; + Inc(LSrcIdx); + end; + + Inc(LDstIdx); + end; + SetLength(LDstBytes, LDstIdx); + + Result := TEncoding.UTF8.GetString(LDstBytes); +end; + +class function TCrossHttpUtils.UrlEncode(const S: string; const ANoConversion: TSysCharSet; + const APreserveEncoded: Boolean): string; +const + HEX_CHARS: array[0..15] of Char = ( + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); + + function _IsHexByte(const AByte: Byte): Boolean; inline; + begin + case AByte of + Ord('0')..Ord('9'), + Ord('a')..Ord('f'), + Ord('A')..Ord('F'): + Result := True; + else + Result := False; + end; + end; + +var + LUTF8Bytes: TBytes; + LLen, I: Integer; + C: Byte; + P: PChar; +begin + if (S = '') then Exit(''); + + // 先将 unicode 字符串编码为 utf8 字节数组 + LUTF8Bytes := TEncoding.UTF8.GetBytes(S); + LLen := Length(LUTF8Bytes); + + // 预分配编码字符串, 比一直累加效率高很多 + // 预分配尺寸为 utf8 字节数组长度的 3 倍 + // 之所以预分配 3 倍, 是因为每个 utf8 字节最长可能被编码为 %xy 这样的字符串 + SetLength(Result, LLen * 3); + P := PChar(Result); + + I := 0; + while (I < LLen) do + begin + C := LUTF8Bytes[I]; + case C of + // https://datatracker.ietf.org/doc/html/rfc3986 + // RFC 3986 中明确定义了未保留字(无需编码)包含以下这些 + // 字母数字:大小写英文字母(A-Z, a-z)和数字(0-9)。 + // 特殊字符:连字符(-),下划线(_),点号(.),和波浪号(~)。 + Ord('0')..Ord('9'), + Ord('a')..Ord('z'), + Ord('A')..Ord('Z'), + Ord('-'), Ord('_'), Ord('.'), Ord('~'): + begin + P^ := Char(C); + Inc(P); + end; + else + // RFC 3986 §2.4: 已 percent-encoded 的 %xx 序列不应被二次编码. + // APreserveEncoded=True 时, 遇到 % 后跟 2 个 hex 数字, 原样保留 3 字符. + if APreserveEncoded and (C = Ord('%')) and (I + 2 < LLen) + and _IsHexByte(LUTF8Bytes[I + 1]) + and _IsHexByte(LUTF8Bytes[I + 2]) then + begin + P^ := '%'; + Inc(P); + P^ := Char(LUTF8Bytes[I + 1]); + Inc(P); + P^ := Char(LUTF8Bytes[I + 2]); + Inc(P); + Inc(I, 2); // 跳过两个 hex 字节, 循环底部还会 Inc(I) 一次 + end else + if CharInSet(Char(C), ANoConversion) then + begin + P^ := Char(C); + Inc(P); + end else + begin + P^ := '%'; + Inc(P); + + P^ := HEX_CHARS[C shr 4]; + Inc(P); + + P^ := HEX_CHARS[C and $F]; + Inc(P); + end; + end; + Inc(I); + end; + + // 修正编码字符串的实际长度 + SetLength(Result, P - PChar(Result)); +end; + +class function TCrossHttpUtils.ParseSingleByteRange(const ARangeHeader: string; + const AContentLength: Int64; out AStart, AEnd: Int64): Boolean; +const + PREFIX = 'bytes='; + + function _IsAsciiDigits(const S: string): Boolean; + var + I: Integer; + begin + if (S = '') then Exit(False); + for I := 1 to Length(S) do + case S[I] of + '0'..'9': ; + else + Exit(False); + end; + Result := True; + end; + +var + LSpec, LStartStr, LEndStr: string; + LDashPos: Integer; + LStartVal, LEndVal: Int64; + LHasStart, LHasEnd: Boolean; +begin + AStart := 0; + AEnd := 0; + Result := False; + + // 资源长度必须 > 0 + if (AContentLength <= 0) then Exit; + + // 必须以 'bytes=' 前缀开头 (RFC 7233 §3.1, 大小写不敏感) + if (Length(ARangeHeader) <= Length(PREFIX)) + or not ARangeHeader.StartsWith(PREFIX, True) then Exit; + + LSpec := Copy(ARangeHeader, Length(PREFIX) + 1, MaxInt).Trim; + if (LSpec = '') then Exit; + + // 不支持 multipart/byteranges (含 ',' 一律拒绝) + if (LSpec.IndexOf(',') >= 0) then Exit; + + // 必须存在且仅有一个 '-' + LDashPos := LSpec.IndexOf('-'); + if (LDashPos < 0) then Exit; + if (LSpec.LastIndexOf('-') <> LDashPos) then Exit; + + // 不对子串再 Trim, 避免 'bytes=0 - 100' 内嵌空格被静默吞掉. + // RFC 7230 ABNF 不允许 byte-range-spec 内含 OWS/BWS. + LStartStr := LSpec.Substring(0, LDashPos); + LEndStr := LSpec.Substring(LDashPos + 1); + + LHasStart := (LStartStr <> ''); + LHasEnd := (LEndStr <> ''); + + // 至少要有一个端点; 'bytes=-' 是非法的 + if (not LHasStart) and (not LHasEnd) then Exit; + + // 解析 start (必须为纯 ASCII 十进制数字) + if LHasStart then + begin + if not _IsAsciiDigits(LStartStr) then Exit; + if not TryStrToInt64(LStartStr, LStartVal) then Exit; + if (LStartVal < 0) then Exit; + end else + LStartVal := 0; + + // 解析 end (必须为纯 ASCII 十进制数字) + if LHasEnd then + begin + if not _IsAsciiDigits(LEndStr) then Exit; + if not TryStrToInt64(LEndStr, LEndVal) then Exit; + if (LEndVal < 0) then Exit; + end else + LEndVal := 0; + + if LHasStart and LHasEnd then + begin + // bytes=start-end: 要求 0 <= start <= end < size + if (LStartVal > LEndVal) then Exit; + if (LStartVal >= AContentLength) then Exit; + // end 超出文件大小时按 RFC 7233 §2.1 截断到 size-1 + if (LEndVal >= AContentLength) then + LEndVal := AContentLength - 1; + AStart := LStartVal; + AEnd := LEndVal; + end else + if LHasStart then + begin + // bytes=start-: 从 start 取到末尾 + if (LStartVal >= AContentLength) then Exit; + AStart := LStartVal; + AEnd := AContentLength - 1; + end else + begin + // bytes=-suffix: 取末尾 suffix 字节; suffix 必须 > 0 + if (LEndVal = 0) then Exit; + if (LEndVal >= AContentLength) then + AStart := 0 + else + AStart := AContentLength - LEndVal; + AEnd := AContentLength - 1; + end; + + Result := True; +end; + +class function TCrossHttpUtils.IsTokenChar(ACh: Char): Boolean; +begin + // RFC 7230 §3.2.6 token: ALPHA / DIGIT / "!" "#" "$" "%" "&" "'" "*" "+" + // "-" "." "^" "_" "`" "|" "~" + case ACh of + 'A'..'Z', 'a'..'z', '0'..'9', + '!', '#', '$', '%', '&', '''', '*', '+', '-', '.', '^', '_', '`', '|', '~': + Result := True; + else + Result := False; + end; +end; + +class function TCrossHttpUtils.IsHeaderValueChar(ACh: Char): Boolean; +begin + // RFC 7230 §3.2.4 field-value: + // 合法: HTAB(#9) / 可见 ASCII (#32..#126) / #128+ 高位字符 (历史宽松, 兼容 UTF-8). + // 非法: 其他 CTL (#0..#8, #10..#31) 与 DEL (#127), CR/LF/NUL 是响应拆分主要载体. + case Ord(ACh) of + 9, 32..126, 128..$FFFF: + Result := True; + else + Result := False; + end; +end; + +class function TCrossHttpUtils.IsValidHeaderName(const AName: string): Boolean; +var + I: Integer; +begin + if (AName = '') then Exit(False); + for I := 1 to Length(AName) do + if not IsTokenChar(AName[I]) then Exit(False); + Result := True; +end; + +class function TCrossHttpUtils.IsValidHeaderValue(const AValue: string): Boolean; +var + I: Integer; +begin + for I := 1 to Length(AValue) do + if not IsHeaderValueChar(AValue[I]) then Exit(False); + Result := True; +end; + +end. diff --git a/Net/Net.CrossSocket.Epoll.pas b/Net/Net.CrossSocket.Epoll.pas index 121a896..cd4bdd3 100644 --- a/Net/Net.CrossSocket.Epoll.pas +++ b/Net/Net.CrossSocket.Epoll.pas @@ -1,1077 +1,1077 @@ -{******************************************************************************} -{ } -{ Delphi cross platform socket library } -{ } -{ Copyright (c) 2017 WiNDDRiVER(soulawing@gmail.com) } -{ } -{ Homepage: https://github.com/winddriver/Delphi-Cross-Socket } -{ } -{******************************************************************************} -unit Net.CrossSocket.Epoll; - -{$I zLib.inc} - -interface - -uses - SysUtils, - Classes, - Generics.Collections, - - {$IFDEF DELPHI} - Posix.Base, - Posix.SysSocket, - Posix.NetinetIn, - Posix.UniStd, - Posix.NetDB, - Posix.Pthread, - Posix.ArpaInet, - Posix.Errno, - Linux.epoll, - {$ELSE} - baseunix, - unix, - linux, - syscall, - sockets, - netdb, - cnetdb, - DTF.RTL, - {$ENDIF DELPHI} - - Net.SocketAPI, - Net.CrossSocket.Base, - - Utils.SyncObjs, - Utils.ArrayUtils; - -type - TIoEvent = (ieRead, ieWrite); - TIoEvents = set of TIoEvent; - - TEpollListen = class(TCrossListenBase) - private - FEpollHandle: Integer; - FOpCode: Integer; - - function _UpdateIoEvent(const AIoEvents: TIoEvents): Boolean; - public - constructor Create(const AOwner: TCrossSocketBase; const AListenSocket: TSocket; - const AFamily, ASockType, AProtocol: Integer); override; - end; - - PSendItem = ^TSendItem; - TSendItem = record - Data: PByte; - Size: Integer; - Callback: TCrossConnectionCallback; - end; - - TSendQueue = class(TList) - protected - procedure Notify(const Value: PSendItem; Action: TCollectionNotification); override; - end; - - TEpollConnection = class(TCrossConnectionBase) - private - FEpollHandle: Integer; - FSendQueue: TSendQueue; - FEpLock: ILock; - FOpCode: Integer; - FInPending, FOutPending: Integer; - - function _UpdateIoEvent(const AIoEvents: TIoEvents): Boolean; - procedure _ClearSendQueue; - - // 为了减少死锁的可能, 不使用父类的 _Lock/_Unlock - // 因为父类的 _Lock/_Unlock 主要用于连接事件和接收数据事件 - // 这里的 _EpLock/_EpUnlock 主要用于发送队列和Epoll事件 - // 在接收完数据之后马上发送数据, 如果使用同一把锁可能会引起死锁 - procedure _EpLock; inline; - procedure _EpUnlock; inline; - protected - procedure InternalClose; override; - public - constructor Create(const AOwner: TCrossSocketBase; const AClientSocket: TSocket; - const AConnectType: TConnectType; const AHost: string; - const AConnectCb: TCrossConnectionCallback); override; - destructor Destroy; override; - end; - - // KQUEUE 与 EPOLL 队列的差异 - // KQUEUE的队列中, 一个Socket句柄可以有多条记录, 每个事件一条, - // 这一点和 EPOLL 不一样, EPOLL中每个Socket句柄只会有一条记录 - // 要监测多个事件时, 只需要将多个事件做位运算加在一起调用 epoll_ctl 即可 - // - // EPOLLONESHOT 是令 epoll 支持线程池的关键 - // 该参数可以令事件触发后就立即被禁用, 避免让同一个Socket的同一个事件 - // 同时被多个工作线程触发, 由于 epoll 中每个 socket 只有一条记录, 所以 - // 一定要注意带上 EPOLLONESHOT 参数的 epoll_ctl, 在 epoll_wait 之后一定要再次 - // 调用 epoll_ctl 增加要监视的事件 - // - // EPOLL 发送数据 - // 最好的做法是将实际发送数据的动作放到 EPOLLOUT 触发时进行, 该 - // 事件触发表明 Socket 发送缓存有空闲空间了。IOCP 可以直接将待发送的数据及 - // 回调同时扔给 WSASend, 发送完成后去调用回调即可; EPOLL 机制不一样, 在 EPOLL - // 中没有类似 WSASend 的函数, 只能自行维护发送数据及回调的队列 - // EPOLL要支持多线程并发发送数据必须创建发送队列, 否则同一个 Socket 的并发发送 - // 极有可能有一部分会被其它发送覆盖掉 - // - // 由于 EPOLL 中每个套接字在队列中只有一条记录, 也就是说改写套接字的监视事件时 - // 后一次修改会修改之前的, 这就很难使用接口的引用计数机制来保持连接有效性了 - // 这里使用连接UID作为 epoll_ctl 的参数, 在事件触发时通过UID查找连接对象, 这样 - // 同样可以保证事件触发时访问到有效的连接对象, 而且不需要引用计数保证 - TEpollCrossSocket = class(TCrossSocketBase) - private const - MAX_EVENT_COUNT = 2048; - SHUTDOWN_FLAG = UInt64(-1); - private class threadvar - FEventList: array [0..MAX_EVENT_COUNT-1] of TEPoll_Event; - private - FEpollHandle: Integer; - FIoThreads: TArray; - FIdleHandle, FStopHandle: Integer; - FIdleLock: ILock; - - // 利用 eventfd 唤醒并退出IO线程 - procedure _OpenStopHandle; - procedure _PostStopCommand; - procedure _CloseStopHandle; - - procedure _OpenIdleHandle; - procedure _CloseIdleHandle; - - procedure _HandleAccept(const AListen: ICrossListen); - procedure _HandleConnect(const AConnection: ICrossConnection); - procedure _HandleRead(const AConnection: ICrossConnection); - procedure _HandleWrite(const AConnection: ICrossConnection); - protected - function CreateConnection(const AOwner: TCrossSocketBase; const AClientSocket: TSocket; - const AConnectType: TConnectType; const AHost: string; - const AConnectCb: TCrossConnectionCallback): ICrossConnection; override; - function CreateListen(const AOwner: TCrossSocketBase; const AListenSocket: TSocket; - const AFamily, ASockType, AProtocol: Integer): ICrossListen; override; - - procedure StartLoop; override; - procedure StopLoop; override; - - procedure Listen(const AHost: string; const APort: Word; - const ACallback: TCrossListenCallback = nil); override; - - procedure Connect(const AHost: string; const APort, ALocalPort: Word; - const ACallback: TCrossConnectionCallback = nil); override; - - procedure Send(const AConnection: ICrossConnection; const ABuf: Pointer; const ALen: Integer; - const ACallback: TCrossConnectionCallback = nil); override; - - function ProcessIoEvent: Boolean; override; - public - constructor Create(const AIoThreads: Integer); override; - destructor Destroy; override; - end; - -implementation - -{ create a file descriptor for event notification } -{$IFDEF DELPHI} -function eventfd(initval: Cardinal; flags: Integer): Integer; cdecl; - external libc name 'eventfd'; -{$ELSE} -function eventfd(initval: Cardinal; flags: Integer): Integer; -begin - Result := do_syscall(syscall_nr_eventfd2, TSysParam(initval), TSysParam(flags)); -end; -{$ENDIF} - -{ TEpollListen } - -constructor TEpollListen.Create(const AOwner: TCrossSocketBase; - const AListenSocket: TSocket; const AFamily, ASockType, AProtocol: Integer); -begin - inherited; - - FOpCode := EPOLL_CTL_ADD; - FEpollHandle := TEpollCrossSocket(Owner).FEpollHandle; -end; - -function TEpollListen._UpdateIoEvent(const AIoEvents: TIoEvents): Boolean; -var - LEvent: TEPoll_Event; -begin - if (AIoEvents = []) or IsClosed then Exit(False); - - LEvent.Events := EPOLLET or EPOLLONESHOT; - LEvent.Data.u64 := Self.UID; - - if (ieRead in AIoEvents) then - LEvent.Events := LEvent.Events or EPOLLIN; - - Result := (epoll_ctl(FEpollHandle, FOpCode, Socket, @LEvent) >= 0); - FOpCode := EPOLL_CTL_MOD; - - if not Result then - _LogLastOsError('listen epoll_ctl, %s', [Self.DebugInfo]); -end; - -{ TSendQueue } - -procedure TSendQueue.Notify(const Value: PSendItem; - Action: TCollectionNotification); -begin - if (Action = TCollectionNotification.cnRemoved) then - begin - if (Value <> nil) then - begin - Value.Callback := nil; - System.Dispose(Value); - end; - end; - - inherited; -end; - -{ TEpollConnection } - -constructor TEpollConnection.Create(const AOwner: TCrossSocketBase; - const AClientSocket: TSocket; const AConnectType: TConnectType; - const AHost: string; const AConnectCb: TCrossConnectionCallback); -begin - inherited Create(AOwner, AClientSocket, AConnectType, AHost, AConnectCb); - - FEpLock := TLock.Create; - FSendQueue := TSendQueue.Create; - - FEpollHandle := TEpollCrossSocket(Owner).FEpollHandle; - FOpCode := EPOLL_CTL_ADD; -end; - -destructor TEpollConnection.Destroy; -begin - _ClearSendQueue; - - FreeAndNil(FSendQueue); - - inherited; -end; - -procedure TEpollConnection.InternalClose; -begin - _ClearSendQueue; - - _EpLock; - try - epoll_ctl(FEpollHandle, EPOLL_CTL_DEL, Socket, nil); - finally - _EpUnlock; - end; - - inherited InternalClose; -end; - -procedure TEpollConnection._ClearSendQueue; -var - LConnection: ICrossConnection; - LSendItem: PSendItem; - LCallbacks: TArray; - LCallback: TCrossConnectionCallback; -begin - LConnection := Self; - LCallbacks := []; - - _EpLock; - try - // 连接释放时, 先收集所有回调, 然后在锁外执行 - // 避免回调中再次发送数据导致死锁 - if (FSendQueue.Count > 0) then - begin - for LSendItem in FSendQueue do - if Assigned(LSendItem.Callback) then - TArrayUtils.Append(LCallbacks, LSendItem.Callback); - - FSendQueue.Clear; - end; - finally - _EpUnlock; - end; - - // 在锁外执行回调, 告知发送失败 - for LCallback in LCallbacks do - LCallback(LConnection, False); -end; - -procedure TEpollConnection._EpLock; -begin - FEpLock.Enter; -end; - -procedure TEpollConnection._EpUnlock; -begin - FEpLock.Leave; -end; - -function TEpollConnection._UpdateIoEvent(const AIoEvents: TIoEvents): Boolean; -var - LEvent: TEPoll_Event; -begin - if (AIoEvents = []) or IsClosed then Exit(False); - - LEvent.Events := 0; - - if (ieRead in AIoEvents) and (AtomicCmpExchange(FInPending, 0, 0) = 0) then - LEvent.Events := LEvent.Events or EPOLLIN; - - if (ieWrite in AIoEvents) and (AtomicCmpExchange(FOutPending, 0, 0) = 0) then - LEvent.Events := LEvent.Events or EPOLLOUT; - - if (LEvent.Events = 0) then Exit(False); - - LEvent.Events := LEvent.Events or EPOLLET or EPOLLONESHOT or EPOLLERR or EPOLLHUP; - LEvent.Data.u64 := Self.UID; - - Result := (epoll_ctl(FEpollHandle, FOpCode, Socket, @LEvent) >= 0); - FOpCode := EPOLL_CTL_MOD; - - if not Result then - begin - _LogLastOsError('connection epoll_ctl, %s, events=0x%.8x', - [Self.DebugInfo, LEvent.Events]); - Close; - end; -end; - -{ TEpollCrossSocket } - -constructor TEpollCrossSocket.Create(const AIoThreads: Integer); -begin - inherited; - - FIdleLock := TLock.Create; -end; - -destructor TEpollCrossSocket.Destroy; -begin - inherited; -end; - -procedure TEpollCrossSocket._CloseIdleHandle; -begin - FileClose(FIdleHandle); -end; - -procedure TEpollCrossSocket._CloseStopHandle; -begin - FileClose(FStopHandle); -end; - -procedure TEpollCrossSocket._HandleAccept(const AListen: ICrossListen); -var - LListen: ICrossListen; - LConnection: ICrossConnection; - LEpConnection: TEpollConnection; - LError: Integer; - LSocket, LListenSocket, LClientSocket: TSocket; - LSuccess: Boolean; -begin - LListen := AListen; - LListenSocket := LListen.Socket; - - while True do - begin - LSocket := TSocketAPI.Accept(LListenSocket, nil, nil); - - // Accept失败 - // EAGAIN 所有就绪的连接都已处理完毕 - // EMFILE 进程的文件句柄已经用完了 - if (LSocket < 0) then - begin - LError := GetLastError; - - if (LError = EAGAIN) or (LError = EWOULDBLOCK) then - begin - end else - // 当句柄用完了的时候, 释放事先占用的临时句柄 - // 然后再次 accept, 然后将 accept 的句柄关掉 - // 这样可以保证在文件句柄耗尽的时候依然能响应连接请求 - // 并立即将新到的连接关闭 - if (LError = EMFILE) then - begin - FIdleLock.Enter; - try - _CloseIdleHandle; - LSocket := TSocketAPI.Accept(LListenSocket, nil, nil); - TSocketAPI.CloseSocket(LSocket); - _OpenIdleHandle; - finally - FIdleLock.Leave; - end; - end else - _LogLastOsError('Accept'); - - Break; - end; - - LClientSocket := LSocket; - TSocketAPI.SetNonBlock(LClientSocket, True); - SetKeepAlive(LClientSocket); - - LConnection := CreateConnection(Self, LClientSocket, ctAccept, ''); - TriggerConnecting(LConnection); - TriggerConnected(LConnection); - - // 连接建立后监视Socket的读事件 - LEpConnection := LConnection as TEpollConnection; - LEpConnection._EpLock; - try - LSuccess := LEpConnection._UpdateIoEvent([ieRead]); - finally - LEpConnection._EpUnlock; - end; - - if not LSuccess then - begin - _Log('_HandleAccept._UpdateIoEvent failed, %s', [LConnection.DebugInfo]); - LConnection.Close; - end; - end; -end; - -procedure TEpollCrossSocket._HandleConnect(const AConnection: ICrossConnection); -var - LConnection: ICrossConnection; - LSockErr: Integer; -begin - LConnection := AConnection; - - // Connect失败 - LSockErr := TSocketAPI.GetError(LConnection.Socket); - if (LSockErr <> 0) then - begin - LConnection.LastNetError := LSockErr; - _LogLastOsError(Self.ClassName + '._HandleConnect.GetError'); - LConnection.Close; - Exit; - end; - - TriggerConnected(LConnection); -end; - -procedure TEpollCrossSocket._HandleRead(const AConnection: ICrossConnection); -var - LConnection: ICrossConnection; - LEpConnection: TEpollConnection; - LRcvd, LError: Integer; -begin - LConnection := AConnection; - LEpConnection := LConnection as TEpollConnection; - - AtomicIncrement(LEpConnection.FInPending); - try - while True do - begin - LRcvd := TSocketAPI.Recv(LConnection.Socket, FRecvBuf[0], RCV_BUF_SIZE); - - // 对方主动断开连接 - if (LRcvd = 0) then - begin - _Log('Recv=0(Close), %s', [LConnection.DebugInfo]); - LConnection.Close; - Break; - end; - - if (LRcvd < 0) then - begin - LError := GetLastError; - - // 被系统信号中断, 可以重新recv - if (LError = EINTR) then - begin - _LogLastOsError('Recv=EINTR, %s', [LConnection.DebugInfo]); - Continue - end else - // 接收缓冲区中数据已经被取完了 - if (LError = EAGAIN) or (LError = EWOULDBLOCK) then - Break - else - // 接收出错 - begin - _LogLastOsError('Recv<0, %s', [LConnection.DebugInfo]); - LConnection.Close; - Break; - end; - end; - - TriggerReceived(LConnection, @FRecvBuf[0], LRcvd); - - // 回调中可能关闭了连接, 需要检查状态 - if LConnection.IsClosed then Break; - - if (LRcvd < RCV_BUF_SIZE) then Break; - end; - finally - AtomicDecrement(LEpConnection.FInPending); - end; -end; - -procedure TEpollCrossSocket._HandleWrite(const AConnection: ICrossConnection); -var - LConnection: ICrossConnection; - LEpConnection: TEpollConnection; - LSendItem: PSendItem; - LSent, LError: Integer; - LSendCbArr: TArray; - LSendCb: TCrossConnectionCallback; -begin - LConnection := AConnection; - LEpConnection := LConnection as TEpollConnection; - LSendCbArr := []; - - AtomicIncrement(LEpConnection.FOutPending); - LEpConnection._EpLock; - try - while True do - begin - // 检查队列中有没有数据 - if (LEpConnection.FSendQueue.Count <= 0) then Break; - - // 获取Socket发送队列中的第一条数据 - LSendItem := LEpConnection.FSendQueue.Items[0]; - - // 发送数据 - LSent := TSocketAPI.Send(LConnection.Socket, LSendItem.Data^, LSendItem.Size, MSG_NOSIGNAL); - - // 对方主动断开连接 - if (LSent = 0) then - begin - _Log('Send=0(Close), %s', [LConnection.DebugInfo]); - LConnection.Close; - Break; - end; - - // 连接断开或发送错误 - if (LSent < 0) then - begin - LError := GetLastError; - - // 被系统信号中断, 可以重新send - if (LError = EINTR) then - begin - _LogLastOsError('Send=EINTR, %s', [LConnection.DebugInfo]); - Continue; - end else - // 发送缓冲区已被填满了, 需要等下次唤醒发送线程再继续发送 - if (LError = EAGAIN) or (LError = EWOULDBLOCK) then - Break - // 发送出错 - else - begin - _LogLastOsError('Send<0, %s', [LConnection.DebugInfo]); - LConnection.Close; - Break; - end; - end; - - // 全部发送完成 - if (LSent >= LSendItem.Size) then - begin - TArrayUtils.Append(LSendCbArr, LSendItem.Callback); - - // 发送成功, 移除已发送成功的数据 - // 必须先从队列移除已发完的数据项, 然后再执行发送成功的回调 - // 因为回调里可能还会发送新的数据, 如果先执行回调再去移除, - // 就会错误的将回调中放到队列里的新数据移除 - if (LEpConnection.FSendQueue.Count > 0) then - LEpConnection.FSendQueue.Delete(0); - end else - begin - // 部分发送成功, 在下一次唤醒发送线程时继续处理剩余部分 - Dec(LSendItem.Size, LSent); - Inc(LSendItem.Data, LSent); - end; - end; - finally - LEpConnection._EpUnlock; - AtomicDecrement(LEpConnection.FOutPending); - end; - - // 调用回调 - for LSendCb in LSendCbArr do - LSendCb(LConnection, True); -end; - -procedure TEpollCrossSocket._OpenIdleHandle; -begin - FIdleHandle := FileOpen('/dev/null', fmOpenRead); -end; - -procedure TEpollCrossSocket._OpenStopHandle; -var - LEvent: TEPoll_Event; -begin - FStopHandle := eventfd(0, 0); - // 这里不使用 EPOLLET - // 这样可以保证通知退出的命令发出后, 所有IO线程都会收到 - LEvent.Events := EPOLLIN; - LEvent.Data.u64 := SHUTDOWN_FLAG; - epoll_ctl(FEpollHandle, EPOLL_CTL_ADD, FStopHandle, @LEvent); -end; - -procedure TEpollCrossSocket._PostStopCommand; -var - LStuff: UInt64; -begin - LStuff := 1; - // 往 FStopHandle 写入任意数据, 唤醒工作线程 - FileWrite(FStopHandle, LStuff, SizeOf(LStuff)); -end; - -procedure TEpollCrossSocket.StartLoop; -var - I: Integer; -begin - if (FIoThreads <> nil) then Exit; - - _OpenIdleHandle; - - // epoll_create(size) - // 这个 size 只要传递大于0的任何值都可以 - // 并不是说队列的大小会受限于该值 - // http://man7.org/linux/man-pages/man2/epoll_create.2.html - FEpollHandle := epoll_create(MAX_EVENT_COUNT); - SetLength(FIoThreads, GetIoThreads); - for I := 0 to Length(FIoThreads) - 1 do - FIoThreads[I] := TIoEventThread.Create(Self); - - _OpenStopHandle; -end; - -procedure TEpollCrossSocket.StopLoop; -var - I: Integer; - LCurrentThreadID: TThreadID; -begin - if (FIoThreads = nil) then Exit; - - CloseAll; - - while (FListensCount > 0) or (FConnectionsCount > 0) do Sleep(1); - - _PostStopCommand; - - LCurrentThreadID := GetCurrentThreadId; - for I := 0 to Length(FIoThreads) - 1 do - begin - if (FIoThreads[I].ThreadID = LCurrentThreadID) then - raise ECrossSocket.Create('不能在IO线程中执行StopLoop!'); - - FIoThreads[I].WaitFor; - FreeAndNil(FIoThreads[I]); - end; - FIoThreads := nil; - - FileClose(FEpollHandle); - _CloseIdleHandle; - _CloseStopHandle; -end; - -procedure TEpollCrossSocket.Connect(const AHost: string; - const APort, ALocalPort: Word; const ACallback: TCrossConnectionCallback); - - procedure _Failed1; - begin - if Assigned(ACallback) then - ACallback(nil, False); - end; - - function _Connect(ASocket: TSocket; AAddr: PRawAddrInfo): Boolean; - procedure _Failed2; - begin - if Assigned(ACallback) then - ACallback(nil, False); - TSocketAPI.CloseSocket(ASocket); - end; - var - LSockAddr: TRawSockAddrIn; - LConnection: ICrossConnection; - LEpConnection: TEpollConnection; - begin - FillChar(LSockAddr, SizeOf(TRawSockAddrIn), 0); - LSockAddr.AddrLen := AAddr.ai_addrlen; - if (AAddr.ai_family = AF_INET6) then - begin - LSockAddr.Addr6.sin6_family := AAddr.ai_family; - LSockAddr.Addr6.sin6_port := htons(ALocalPort); - end else - begin - LSockAddr.Addr.sin_family := AAddr.ai_family; - LSockAddr.Addr.sin_port := htons(ALocalPort); - end; - if (TSocketAPI.Bind(ASocket, @LSockAddr.Addr, LSockAddr.AddrLen) < 0) then - begin - {$IFDEF DEBUG} - _LogLastOsError('TEpollCrossSocket._Connect.Bind'); - {$ENDIF} - _Failed2; - Exit(False); - end; - - if (TSocketAPI.Connect(ASocket, AAddr.ai_addr, AAddr.ai_addrlen) = 0) - or (GetLastError = EINPROGRESS) then - begin - LConnection := CreateConnection(Self, ASocket, ctConnect, AHost, ACallback); - TriggerConnecting(LConnection); - LEpConnection := LConnection as TEpollConnection; - - LEpConnection._EpLock; - try - LEpConnection.ConnectStatus := csConnecting; - if not LEpConnection._UpdateIoEvent([ieWrite]) then - begin - LConnection.Close; - Exit(False); - end; - finally - LEpConnection._EpUnlock; - end; - end else - begin - _LogLastOsError('Connect'); - - _Failed2; - Exit(False); - end; - - Result := True; - end; - -var - LHints: TRawAddrInfo; - P, LAddrInfo: PRawAddrInfo; - LSocket: TSocket; -begin - FillChar(LHints, SizeOf(TRawAddrInfo), 0); - LHints.ai_family := AF_UNSPEC; - LHints.ai_socktype := SOCK_STREAM; - LHints.ai_protocol := IPPROTO_TCP; - LAddrInfo := TSocketAPI.GetAddrInfo(AHost, APort, LHints); - if (LAddrInfo = nil) then - begin - _Failed1; - Exit; - end; - - P := LAddrInfo; - try - while (LAddrInfo <> nil) do - begin - LSocket := TSocketAPI.NewSocket(LAddrInfo.ai_family, LAddrInfo.ai_socktype, - LAddrInfo.ai_protocol); - if (LSocket = INVALID_SOCKET) then - begin - _LogLastOsError('NewSocket'); - - _Failed1; - Exit; - end; - - TSocketAPI.SetNonBlock(LSocket, True); - SetKeepAlive(LSocket); - - if _Connect(LSocket, LAddrInfo) then Exit; - - LAddrInfo := PRawAddrInfo(LAddrInfo.ai_next); - end; - finally - TSocketAPI.FreeAddrInfo(P); - end; - - _Failed1; -end; - -function TEpollCrossSocket.CreateConnection(const AOwner: TCrossSocketBase; - const AClientSocket: TSocket; const AConnectType: TConnectType; - const AHost: string; const AConnectCb: TCrossConnectionCallback): ICrossConnection; -begin - Result := TEpollConnection.Create( - AOwner, - AClientSocket, - AConnectType, - AHost, - AConnectCb); -end; - -function TEpollCrossSocket.CreateListen(const AOwner: TCrossSocketBase; - const AListenSocket: TSocket; const AFamily, ASockType, AProtocol: Integer): ICrossListen; -begin - Result := TEpollListen.Create(AOwner, AListenSocket, AFamily, ASockType, AProtocol); -end; - -procedure TEpollCrossSocket.Listen(const AHost: string; const APort: Word; - const ACallback: TCrossListenCallback); -var - LHints: TRawAddrInfo; - P, LAddrInfo: PRawAddrInfo; - LListenSocket: TSocket; - LListen: ICrossListen; - LEpListen: TEpollListen; - LListenSuccess, LUpdateIoEventSuccess: Boolean; - - procedure _Failed; - begin - if not LListenSuccess and Assigned(ACallback) then - ACallback(LListen, False); - - if (LListen <> nil) then - LListen.Close - else if (LListenSocket <> INVALID_SOCKET) then - TSocketAPI.CloseSocket(LListenSocket); - end; - -begin - LListenSuccess := False; - FillChar(LHints, SizeOf(TRawAddrInfo), 0); - LHints.ai_flags := AI_PASSIVE; - LHints.ai_family := AF_UNSPEC; - LHints.ai_socktype := SOCK_STREAM; - LHints.ai_protocol := IPPROTO_TCP; - LAddrInfo := TSocketAPI.GetAddrInfo(AHost, APort, LHints); - if (LAddrInfo = nil) then - begin - {$IFDEF DEBUG} - _LogLastOsError('TEpollCrossSocket.Listen.GetAddrInfo'); - {$ENDIF} - _Failed; - Exit; - end; - - P := LAddrInfo; - try - while (LAddrInfo <> nil) do - begin - LListen := nil; - LListenSocket := TSocketAPI.NewSocket(LAddrInfo.ai_family, LAddrInfo.ai_socktype, - LAddrInfo.ai_protocol); - if (LListenSocket = INVALID_SOCKET) then - begin - {$IFDEF DEBUG} - _LogLastOsError('TEpollCrossSocket.Listen.NewSocket'); - {$ENDIF} - _Failed; - Exit; - end; - - TSocketAPI.SetNonBlock(LListenSocket, True); - TSocketAPI.SetReUsePort(LListenSocket, True); - - if (LAddrInfo.ai_family = AF_INET6) then - TSocketAPI.SetSockOpt(LListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, 1); - - if (TSocketAPI.Bind(LListenSocket, LAddrInfo.ai_addr, LAddrInfo.ai_addrlen) < 0) - or (TSocketAPI.Listen(LListenSocket) < 0) then - begin - {$IFDEF DEBUG} - _LogLastOsError('TEpollCrossSocket.Listen.Bind'); - {$ENDIF} - _Failed; - Exit; - end; - - LListen := CreateListen(Self, LListenSocket, LAddrInfo.ai_family, - LAddrInfo.ai_socktype, LAddrInfo.ai_protocol); - LEpListen := LListen as TEpollListen; - - // 监听套接字的读事件 - // 读事件到达表明有新连接 - LEpListen._Lock; - try - LUpdateIoEventSuccess := LEpListen._UpdateIoEvent([ieRead]); - finally - LEpListen._Unlock; - end; - - if not LUpdateIoEventSuccess then - begin - _Failed; - Exit; - end; - - // 监听成功 - LListenSuccess := True; - TriggerListened(LListen); - if Assigned(ACallback) then - ACallback(LListen, True); - - // 如果端口传入0,让所有地址统一用首个分配到的端口 - if (APort = 0) and (LAddrInfo.ai_next <> nil) then - Psockaddr_in(LAddrInfo.ai_next.ai_addr).sin_port := htons(LListen.LocalPort); - - LAddrInfo := PRawAddrInfo(LAddrInfo.ai_next); - end; - finally - TSocketAPI.FreeAddrInfo(P); - end; -end; - -procedure TEpollCrossSocket.Send(const AConnection: ICrossConnection; - const ABuf: Pointer; const ALen: Integer; const ACallback: TCrossConnectionCallback); -var - LEpConnection: TEpollConnection; - LSendItem: PSendItem; -begin - // 测试过先发送, 然后将剩余部分放入发送队列的做法 - // 发现会引起内存访问异常, 放到队列里到IO线程中发送则不会有问题 - {$region '放入发送队列'} - System.New(LSendItem); - FillChar(LSendItem^, SizeOf(TSendItem), 0); - LSendItem.Data := ABuf; - LSendItem.Size := ALen; - LSendItem.Callback := ACallback; - - LEpConnection := AConnection as TEpollConnection; - - LEpConnection._Eplock; - try - // 将数据放入队列 - LEpConnection.FSendQueue.Add(LSendItem); - - // 由于epoll队列中每个套接字只有一条记录, 为了避免监视发送数据的时候 - // 无法接收数据, 这里必须同时监视读和写 - LEpConnection._UpdateIoEvent([ieRead, ieWrite]); - finally - LEpConnection._EpUnlock; - end; - {$endregion} -end; - -function TEpollCrossSocket.ProcessIoEvent: Boolean; -var - LRet, I: Integer; - LEvent: TEPoll_Event; - LCrossUID: UInt64; - LCrossTag: Byte; - LListens: TCrossListens; - LConnections: TCrossConnections; - LListen: ICrossListen; - LEpListen: TEpollListen; - LConnection: ICrossConnection; - LEpConnection: TEpollConnection; - LSuccess: Boolean; - LIoEvents: TIoEvents; -begin - // 被系统信号打断或者出错会返回-1, 具体需要根据错误代码判断 - LRet := epoll_wait(FEpollHandle, @FEventList[0], MAX_EVENT_COUNT, -1); - if (LRet < 0) then - begin - _LogLastOsError('epoll_wait'); - LRet := GetLastError; - // EINTR, epoll_wait 调用被系统信号打断, 可以进行重试 - Exit(LRet = EINTR); - end; - - for I := 0 to LRet - 1 do - begin - LEvent := FEventList[I]; - - // 收到退出命令 - if (LEvent.Data.u64 = SHUTDOWN_FLAG) then Exit(False); - - {$region '获取连接或监听对象'} - LCrossUID := LEvent.Data.u64; - LCrossTag := GetTagByUID(LCrossUID); - LListen := nil; - LConnection := nil; - - {$IFDEF DEBUG} -// _Log('epoll events %.8x, uid %.16x, tag %d', [LEvent.Events, LEvent.Data.u64, LCrossTag]); - {$ENDIF} - case LCrossTag of - UID_LISTEN: - begin - LListens := LockListens; - try - if not LListens.TryGetValue(LCrossUID, LListen) - or (LListen = nil) then - Continue; - finally - UnlockListens; - end; - end; - - UID_CONNECTION: - begin - LConnections := LockConnections; - try - if not LConnections.TryGetValue(LCrossUID, LConnection) - or (LConnection = nil) then - Continue; - finally - UnlockConnections; - end; - end; - else - Continue; - end; - {$endregion} - - {$region 'IO事件处理'} - if (LListen <> nil) then - begin - if (LEvent.Events and EPOLLIN <> 0) then - _HandleAccept(LListen); - - // 继续接收新连接 - LEpListen := LListen as TEpollListen; - LEpListen._Lock; - LEpListen._UpdateIoEvent([ieRead]); - LEpListen._Unlock; - end else - if (LConnection <> nil) then - begin - // 连接被断开 - if (LEvent.Events and EPOLLERR <> 0) - or (LEvent.Events and EPOLLHUP <> 0) then - begin - _Log('epoll_wait, %s, EPOLLERR=%d, EPOLLHUP=%d', [ - LConnection.DebugInfo, - LEvent.Events and EPOLLERR, - LEvent.Events and EPOLLHUP - ]); - LConnection.Close; - Continue; - end; - - // epoll的读写事件同一时间可能两个同时触发 - if (LEvent.Events and EPOLLIN <> 0) then - _HandleRead(LConnection); - - if (LEvent.Events and EPOLLOUT <> 0) then - begin - if (LConnection.ConnectStatus = csConnecting) then - _HandleConnect(LConnection) - else - _HandleWrite(LConnection); - end; - - // 把更新连接的IO事件放到这里统一处理 - // 当读写同时触发的情况, 可以节省一次IO事件更新 - if not LConnection.IsClosed then - begin - LEpConnection := LConnection as TEpollConnection; - LEpConnection._EpLock; - try - if (LEpConnection.FSendQueue.Count > 0) then - LIoEvents := [ieRead, ieWrite] - else - LIoEvents := [ieRead]; - LEpConnection._UpdateIoEvent(LIoEvents); - finally - LEpConnection._EpUnlock; - end; - end; - end; - {$endregion} - end; - - Result := True; -end; - -end. +{******************************************************************************} +{ } +{ Delphi cross platform socket library } +{ } +{ Copyright (c) 2017 WiNDDRiVER(soulawing@gmail.com) } +{ } +{ Homepage: https://github.com/winddriver/Delphi-Cross-Socket } +{ } +{******************************************************************************} +unit Net.CrossSocket.Epoll; + +{$I zLib.inc} + +interface + +uses + SysUtils, + Classes, + Generics.Collections, + + {$IFDEF DELPHI} + Posix.Base, + Posix.SysSocket, + Posix.NetinetIn, + Posix.UniStd, + Posix.NetDB, + Posix.Pthread, + Posix.ArpaInet, + Posix.Errno, + Linux.epoll, + {$ELSE} + baseunix, + unix, + linux, + syscall, + sockets, + netdb, + cnetdb, + DTF.RTL, + {$ENDIF DELPHI} + + Net.SocketAPI, + Net.CrossSocket.Base, + + Utils.SyncObjs, + Utils.ArrayUtils; + +type + TIoEvent = (ieRead, ieWrite); + TIoEvents = set of TIoEvent; + + TEpollListen = class(TCrossListenBase) + private + FEpollHandle: Integer; + FOpCode: Integer; + + function _UpdateIoEvent(const AIoEvents: TIoEvents): Boolean; + public + constructor Create(const AOwner: TCrossSocketBase; const AListenSocket: TSocket; + const AFamily, ASockType, AProtocol: Integer); override; + end; + + PSendItem = ^TSendItem; + TSendItem = record + Data: PByte; + Size: Integer; + Callback: TCrossConnectionCallback; + end; + + TSendQueue = class(TList) + protected + procedure Notify(const Value: PSendItem; Action: TCollectionNotification); override; + end; + + TEpollConnection = class(TCrossConnectionBase) + private + FEpollHandle: Integer; + FSendQueue: TSendQueue; + FEpLock: ILock; + FOpCode: Integer; + FInPending, FOutPending: Integer; + + function _UpdateIoEvent(const AIoEvents: TIoEvents): Boolean; + procedure _ClearSendQueue; + + // 为了减少死锁的可能, 不使用父类的 _Lock/_Unlock + // 因为父类的 _Lock/_Unlock 主要用于连接事件和接收数据事件 + // 这里的 _EpLock/_EpUnlock 主要用于发送队列和Epoll事件 + // 在接收完数据之后马上发送数据, 如果使用同一把锁可能会引起死锁 + procedure _EpLock; inline; + procedure _EpUnlock; inline; + protected + procedure InternalClose; override; + public + constructor Create(const AOwner: TCrossSocketBase; const AClientSocket: TSocket; + const AConnectType: TConnectType; const AHost: string; + const AConnectCb: TCrossConnectionCallback); override; + destructor Destroy; override; + end; + + // KQUEUE 与 EPOLL 队列的差异 + // KQUEUE的队列中, 一个Socket句柄可以有多条记录, 每个事件一条, + // 这一点和 EPOLL 不一样, EPOLL中每个Socket句柄只会有一条记录 + // 要监测多个事件时, 只需要将多个事件做位运算加在一起调用 epoll_ctl 即可 + // + // EPOLLONESHOT 是令 epoll 支持线程池的关键 + // 该参数可以令事件触发后就立即被禁用, 避免让同一个Socket的同一个事件 + // 同时被多个工作线程触发, 由于 epoll 中每个 socket 只有一条记录, 所以 + // 一定要注意带上 EPOLLONESHOT 参数的 epoll_ctl, 在 epoll_wait 之后一定要再次 + // 调用 epoll_ctl 增加要监视的事件 + // + // EPOLL 发送数据 + // 最好的做法是将实际发送数据的动作放到 EPOLLOUT 触发时进行, 该 + // 事件触发表明 Socket 发送缓存有空闲空间了。IOCP 可以直接将待发送的数据及 + // 回调同时扔给 WSASend, 发送完成后去调用回调即可; EPOLL 机制不一样, 在 EPOLL + // 中没有类似 WSASend 的函数, 只能自行维护发送数据及回调的队列 + // EPOLL要支持多线程并发发送数据必须创建发送队列, 否则同一个 Socket 的并发发送 + // 极有可能有一部分会被其它发送覆盖掉 + // + // 由于 EPOLL 中每个套接字在队列中只有一条记录, 也就是说改写套接字的监视事件时 + // 后一次修改会修改之前的, 这就很难使用接口的引用计数机制来保持连接有效性了 + // 这里使用连接UID作为 epoll_ctl 的参数, 在事件触发时通过UID查找连接对象, 这样 + // 同样可以保证事件触发时访问到有效的连接对象, 而且不需要引用计数保证 + TEpollCrossSocket = class(TCrossSocketBase) + private const + MAX_EVENT_COUNT = 2048; + SHUTDOWN_FLAG = UInt64(-1); + private class threadvar + FEventList: array [0..MAX_EVENT_COUNT-1] of TEPoll_Event; + private + FEpollHandle: Integer; + FIoThreads: TArray; + FIdleHandle, FStopHandle: Integer; + FIdleLock: ILock; + + // 利用 eventfd 唤醒并退出IO线程 + procedure _OpenStopHandle; + procedure _PostStopCommand; + procedure _CloseStopHandle; + + procedure _OpenIdleHandle; + procedure _CloseIdleHandle; + + procedure _HandleAccept(const AListen: ICrossListen); + procedure _HandleConnect(const AConnection: ICrossConnection); + procedure _HandleRead(const AConnection: ICrossConnection); + procedure _HandleWrite(const AConnection: ICrossConnection); + protected + function CreateConnection(const AOwner: TCrossSocketBase; const AClientSocket: TSocket; + const AConnectType: TConnectType; const AHost: string; + const AConnectCb: TCrossConnectionCallback): ICrossConnection; override; + function CreateListen(const AOwner: TCrossSocketBase; const AListenSocket: TSocket; + const AFamily, ASockType, AProtocol: Integer): ICrossListen; override; + + procedure StartLoop; override; + procedure StopLoop; override; + + procedure Listen(const AHost: string; const APort: Word; + const ACallback: TCrossListenCallback = nil); override; + + procedure Connect(const AHost: string; const APort, ALocalPort: Word; + const ACallback: TCrossConnectionCallback = nil); override; + + procedure Send(const AConnection: ICrossConnection; const ABuf: Pointer; const ALen: Integer; + const ACallback: TCrossConnectionCallback = nil); override; + + function ProcessIoEvent: Boolean; override; + public + constructor Create(const AIoThreads: Integer); override; + destructor Destroy; override; + end; + +implementation + +{ create a file descriptor for event notification } +{$IFDEF DELPHI} +function eventfd(initval: Cardinal; flags: Integer): Integer; cdecl; + external libc name 'eventfd'; +{$ELSE} +function eventfd(initval: Cardinal; flags: Integer): Integer; +begin + Result := do_syscall(syscall_nr_eventfd2, TSysParam(initval), TSysParam(flags)); +end; +{$ENDIF} + +{ TEpollListen } + +constructor TEpollListen.Create(const AOwner: TCrossSocketBase; + const AListenSocket: TSocket; const AFamily, ASockType, AProtocol: Integer); +begin + inherited; + + FOpCode := EPOLL_CTL_ADD; + FEpollHandle := TEpollCrossSocket(Owner).FEpollHandle; +end; + +function TEpollListen._UpdateIoEvent(const AIoEvents: TIoEvents): Boolean; +var + LEvent: TEPoll_Event; +begin + if (AIoEvents = []) or IsClosed then Exit(False); + + LEvent.Events := EPOLLET or EPOLLONESHOT; + LEvent.Data.u64 := Self.UID; + + if (ieRead in AIoEvents) then + LEvent.Events := LEvent.Events or EPOLLIN; + + Result := (epoll_ctl(FEpollHandle, FOpCode, Socket, @LEvent) >= 0); + FOpCode := EPOLL_CTL_MOD; + + if not Result then + _LogLastOsError('listen epoll_ctl, %s', [Self.DebugInfo]); +end; + +{ TSendQueue } + +procedure TSendQueue.Notify(const Value: PSendItem; + Action: TCollectionNotification); +begin + if (Action = TCollectionNotification.cnRemoved) then + begin + if (Value <> nil) then + begin + Value.Callback := nil; + System.Dispose(Value); + end; + end; + + inherited; +end; + +{ TEpollConnection } + +constructor TEpollConnection.Create(const AOwner: TCrossSocketBase; + const AClientSocket: TSocket; const AConnectType: TConnectType; + const AHost: string; const AConnectCb: TCrossConnectionCallback); +begin + inherited Create(AOwner, AClientSocket, AConnectType, AHost, AConnectCb); + + FEpLock := TLock.Create; + FSendQueue := TSendQueue.Create; + + FEpollHandle := TEpollCrossSocket(Owner).FEpollHandle; + FOpCode := EPOLL_CTL_ADD; +end; + +destructor TEpollConnection.Destroy; +begin + _ClearSendQueue; + + FreeAndNil(FSendQueue); + + inherited; +end; + +procedure TEpollConnection.InternalClose; +begin + _ClearSendQueue; + + _EpLock; + try + epoll_ctl(FEpollHandle, EPOLL_CTL_DEL, Socket, nil); + finally + _EpUnlock; + end; + + inherited InternalClose; +end; + +procedure TEpollConnection._ClearSendQueue; +var + LConnection: ICrossConnection; + LSendItem: PSendItem; + LCallbacks: TArray; + LCallback: TCrossConnectionCallback; +begin + LConnection := Self; + LCallbacks := []; + + _EpLock; + try + // 连接释放时, 先收集所有回调, 然后在锁外执行 + // 避免回调中再次发送数据导致死锁 + if (FSendQueue.Count > 0) then + begin + for LSendItem in FSendQueue do + if Assigned(LSendItem.Callback) then + TArrayUtils.Append(LCallbacks, LSendItem.Callback); + + FSendQueue.Clear; + end; + finally + _EpUnlock; + end; + + // 在锁外执行回调, 告知发送失败 + for LCallback in LCallbacks do + LCallback(LConnection, False); +end; + +procedure TEpollConnection._EpLock; +begin + FEpLock.Enter; +end; + +procedure TEpollConnection._EpUnlock; +begin + FEpLock.Leave; +end; + +function TEpollConnection._UpdateIoEvent(const AIoEvents: TIoEvents): Boolean; +var + LEvent: TEPoll_Event; +begin + if (AIoEvents = []) or IsClosed then Exit(False); + + LEvent.Events := 0; + + if (ieRead in AIoEvents) and (AtomicCmpExchange(FInPending, 0, 0) = 0) then + LEvent.Events := LEvent.Events or EPOLLIN; + + if (ieWrite in AIoEvents) and (AtomicCmpExchange(FOutPending, 0, 0) = 0) then + LEvent.Events := LEvent.Events or EPOLLOUT; + + if (LEvent.Events = 0) then Exit(False); + + LEvent.Events := LEvent.Events or EPOLLET or EPOLLONESHOT or EPOLLERR or EPOLLHUP; + LEvent.Data.u64 := Self.UID; + + Result := (epoll_ctl(FEpollHandle, FOpCode, Socket, @LEvent) >= 0); + FOpCode := EPOLL_CTL_MOD; + + if not Result then + begin + _LogLastOsError('connection epoll_ctl, %s, events=0x%.8x', + [Self.DebugInfo, LEvent.Events]); + Close; + end; +end; + +{ TEpollCrossSocket } + +constructor TEpollCrossSocket.Create(const AIoThreads: Integer); +begin + inherited; + + FIdleLock := TLock.Create; +end; + +destructor TEpollCrossSocket.Destroy; +begin + inherited; +end; + +procedure TEpollCrossSocket._CloseIdleHandle; +begin + FileClose(FIdleHandle); +end; + +procedure TEpollCrossSocket._CloseStopHandle; +begin + FileClose(FStopHandle); +end; + +procedure TEpollCrossSocket._HandleAccept(const AListen: ICrossListen); +var + LListen: ICrossListen; + LConnection: ICrossConnection; + LEpConnection: TEpollConnection; + LError: Integer; + LSocket, LListenSocket, LClientSocket: TSocket; + LSuccess: Boolean; +begin + LListen := AListen; + LListenSocket := LListen.Socket; + + while True do + begin + LSocket := TSocketAPI.Accept(LListenSocket, nil, nil); + + // Accept失败 + // EAGAIN 所有就绪的连接都已处理完毕 + // EMFILE 进程的文件句柄已经用完了 + if (LSocket < 0) then + begin + LError := GetLastError; + + if (LError = EAGAIN) or (LError = EWOULDBLOCK) then + begin + end else + // 当句柄用完了的时候, 释放事先占用的临时句柄 + // 然后再次 accept, 然后将 accept 的句柄关掉 + // 这样可以保证在文件句柄耗尽的时候依然能响应连接请求 + // 并立即将新到的连接关闭 + if (LError = EMFILE) then + begin + FIdleLock.Enter; + try + _CloseIdleHandle; + LSocket := TSocketAPI.Accept(LListenSocket, nil, nil); + TSocketAPI.CloseSocket(LSocket); + _OpenIdleHandle; + finally + FIdleLock.Leave; + end; + end else + _LogLastOsError('Accept'); + + Break; + end; + + LClientSocket := LSocket; + TSocketAPI.SetNonBlock(LClientSocket, True); + SetKeepAlive(LClientSocket); + + LConnection := CreateConnection(Self, LClientSocket, ctAccept, ''); + TriggerConnecting(LConnection); + TriggerConnected(LConnection); + + // 连接建立后监视Socket的读事件 + LEpConnection := LConnection as TEpollConnection; + LEpConnection._EpLock; + try + LSuccess := LEpConnection._UpdateIoEvent([ieRead]); + finally + LEpConnection._EpUnlock; + end; + + if not LSuccess then + begin + _Log('_HandleAccept._UpdateIoEvent failed, %s', [LConnection.DebugInfo]); + LConnection.Close; + end; + end; +end; + +procedure TEpollCrossSocket._HandleConnect(const AConnection: ICrossConnection); +var + LConnection: ICrossConnection; + LSockErr: Integer; +begin + LConnection := AConnection; + + // Connect失败 + LSockErr := TSocketAPI.GetError(LConnection.Socket); + if (LSockErr <> 0) then + begin + LConnection.LastNetError := LSockErr; + _LogLastOsError(Self.ClassName + '._HandleConnect.GetError'); + LConnection.Close; + Exit; + end; + + TriggerConnected(LConnection); +end; + +procedure TEpollCrossSocket._HandleRead(const AConnection: ICrossConnection); +var + LConnection: ICrossConnection; + LEpConnection: TEpollConnection; + LRcvd, LError: Integer; +begin + LConnection := AConnection; + LEpConnection := LConnection as TEpollConnection; + + AtomicIncrement(LEpConnection.FInPending); + try + while True do + begin + LRcvd := TSocketAPI.Recv(LConnection.Socket, FRecvBuf[0], RCV_BUF_SIZE); + + // 对方主动断开连接 + if (LRcvd = 0) then + begin + _Log('Recv=0(Close), %s', [LConnection.DebugInfo]); + LConnection.Close; + Break; + end; + + if (LRcvd < 0) then + begin + LError := GetLastError; + + // 被系统信号中断, 可以重新recv + if (LError = EINTR) then + begin + _LogLastOsError('Recv=EINTR, %s', [LConnection.DebugInfo]); + Continue + end else + // 接收缓冲区中数据已经被取完了 + if (LError = EAGAIN) or (LError = EWOULDBLOCK) then + Break + else + // 接收出错 + begin + _LogLastOsError('Recv<0, %s', [LConnection.DebugInfo]); + LConnection.Close; + Break; + end; + end; + + TriggerReceived(LConnection, @FRecvBuf[0], LRcvd); + + // 回调中可能关闭了连接, 需要检查状态 + if LConnection.IsClosed then Break; + + if (LRcvd < RCV_BUF_SIZE) then Break; + end; + finally + AtomicDecrement(LEpConnection.FInPending); + end; +end; + +procedure TEpollCrossSocket._HandleWrite(const AConnection: ICrossConnection); +var + LConnection: ICrossConnection; + LEpConnection: TEpollConnection; + LSendItem: PSendItem; + LSent, LError: Integer; + LSendCbArr: TArray; + LSendCb: TCrossConnectionCallback; +begin + LConnection := AConnection; + LEpConnection := LConnection as TEpollConnection; + LSendCbArr := []; + + AtomicIncrement(LEpConnection.FOutPending); + LEpConnection._EpLock; + try + while True do + begin + // 检查队列中有没有数据 + if (LEpConnection.FSendQueue.Count <= 0) then Break; + + // 获取Socket发送队列中的第一条数据 + LSendItem := LEpConnection.FSendQueue.Items[0]; + + // 发送数据 + LSent := TSocketAPI.Send(LConnection.Socket, LSendItem.Data^, LSendItem.Size, MSG_NOSIGNAL); + + // 对方主动断开连接 + if (LSent = 0) then + begin + _Log('Send=0(Close), %s', [LConnection.DebugInfo]); + LConnection.Close; + Break; + end; + + // 连接断开或发送错误 + if (LSent < 0) then + begin + LError := GetLastError; + + // 被系统信号中断, 可以重新send + if (LError = EINTR) then + begin + _LogLastOsError('Send=EINTR, %s', [LConnection.DebugInfo]); + Continue; + end else + // 发送缓冲区已被填满了, 需要等下次唤醒发送线程再继续发送 + if (LError = EAGAIN) or (LError = EWOULDBLOCK) then + Break + // 发送出错 + else + begin + _LogLastOsError('Send<0, %s', [LConnection.DebugInfo]); + LConnection.Close; + Break; + end; + end; + + // 全部发送完成 + if (LSent >= LSendItem.Size) then + begin + TArrayUtils.Append(LSendCbArr, LSendItem.Callback); + + // 发送成功, 移除已发送成功的数据 + // 必须先从队列移除已发完的数据项, 然后再执行发送成功的回调 + // 因为回调里可能还会发送新的数据, 如果先执行回调再去移除, + // 就会错误的将回调中放到队列里的新数据移除 + if (LEpConnection.FSendQueue.Count > 0) then + LEpConnection.FSendQueue.Delete(0); + end else + begin + // 部分发送成功, 在下一次唤醒发送线程时继续处理剩余部分 + Dec(LSendItem.Size, LSent); + Inc(LSendItem.Data, LSent); + end; + end; + finally + LEpConnection._EpUnlock; + AtomicDecrement(LEpConnection.FOutPending); + end; + + // 调用回调 + for LSendCb in LSendCbArr do + LSendCb(LConnection, True); +end; + +procedure TEpollCrossSocket._OpenIdleHandle; +begin + FIdleHandle := FileOpen('/dev/null', fmOpenRead); +end; + +procedure TEpollCrossSocket._OpenStopHandle; +var + LEvent: TEPoll_Event; +begin + FStopHandle := eventfd(0, 0); + // 这里不使用 EPOLLET + // 这样可以保证通知退出的命令发出后, 所有IO线程都会收到 + LEvent.Events := EPOLLIN; + LEvent.Data.u64 := SHUTDOWN_FLAG; + epoll_ctl(FEpollHandle, EPOLL_CTL_ADD, FStopHandle, @LEvent); +end; + +procedure TEpollCrossSocket._PostStopCommand; +var + LStuff: UInt64; +begin + LStuff := 1; + // 往 FStopHandle 写入任意数据, 唤醒工作线程 + FileWrite(FStopHandle, LStuff, SizeOf(LStuff)); +end; + +procedure TEpollCrossSocket.StartLoop; +var + I: Integer; +begin + if (FIoThreads <> nil) then Exit; + + _OpenIdleHandle; + + // epoll_create(size) + // 这个 size 只要传递大于0的任何值都可以 + // 并不是说队列的大小会受限于该值 + // http://man7.org/linux/man-pages/man2/epoll_create.2.html + FEpollHandle := epoll_create(MAX_EVENT_COUNT); + SetLength(FIoThreads, GetIoThreads); + for I := 0 to Length(FIoThreads) - 1 do + FIoThreads[I] := TIoEventThread.Create(Self); + + _OpenStopHandle; +end; + +procedure TEpollCrossSocket.StopLoop; +var + I: Integer; + LCurrentThreadID: TThreadID; +begin + if (FIoThreads = nil) then Exit; + + CloseAll; + + while (FListensCount > 0) or (FConnectionsCount > 0) do Sleep(1); + + _PostStopCommand; + + LCurrentThreadID := GetCurrentThreadId; + for I := 0 to Length(FIoThreads) - 1 do + begin + if (FIoThreads[I].ThreadID = LCurrentThreadID) then + raise ECrossSocket.Create('不能在IO线程中执行StopLoop!'); + + FIoThreads[I].WaitFor; + FreeAndNil(FIoThreads[I]); + end; + FIoThreads := nil; + + FileClose(FEpollHandle); + _CloseIdleHandle; + _CloseStopHandle; +end; + +procedure TEpollCrossSocket.Connect(const AHost: string; + const APort, ALocalPort: Word; const ACallback: TCrossConnectionCallback); + + procedure _Failed1; + begin + if Assigned(ACallback) then + ACallback(nil, False); + end; + + function _Connect(ASocket: TSocket; AAddr: PRawAddrInfo): Boolean; + procedure _Failed2; + begin + if Assigned(ACallback) then + ACallback(nil, False); + TSocketAPI.CloseSocket(ASocket); + end; + var + LSockAddr: TRawSockAddrIn; + LConnection: ICrossConnection; + LEpConnection: TEpollConnection; + begin + FillChar(LSockAddr, SizeOf(TRawSockAddrIn), 0); + LSockAddr.AddrLen := AAddr.ai_addrlen; + if (AAddr.ai_family = AF_INET6) then + begin + LSockAddr.Addr6.sin6_family := AAddr.ai_family; + LSockAddr.Addr6.sin6_port := htons(ALocalPort); + end else + begin + LSockAddr.Addr.sin_family := AAddr.ai_family; + LSockAddr.Addr.sin_port := htons(ALocalPort); + end; + if (TSocketAPI.Bind(ASocket, @LSockAddr.Addr, LSockAddr.AddrLen) < 0) then + begin + {$IFDEF DEBUG} + _LogLastOsError('TEpollCrossSocket._Connect.Bind'); + {$ENDIF} + _Failed2; + Exit(False); + end; + + if (TSocketAPI.Connect(ASocket, AAddr.ai_addr, AAddr.ai_addrlen) = 0) + or (GetLastError = EINPROGRESS) then + begin + LConnection := CreateConnection(Self, ASocket, ctConnect, AHost, ACallback); + TriggerConnecting(LConnection); + LEpConnection := LConnection as TEpollConnection; + + LEpConnection._EpLock; + try + LEpConnection.ConnectStatus := csConnecting; + if not LEpConnection._UpdateIoEvent([ieWrite]) then + begin + LConnection.Close; + Exit(False); + end; + finally + LEpConnection._EpUnlock; + end; + end else + begin + _LogLastOsError('Connect'); + + _Failed2; + Exit(False); + end; + + Result := True; + end; + +var + LHints: TRawAddrInfo; + P, LAddrInfo: PRawAddrInfo; + LSocket: TSocket; +begin + FillChar(LHints, SizeOf(TRawAddrInfo), 0); + LHints.ai_family := AF_UNSPEC; + LHints.ai_socktype := SOCK_STREAM; + LHints.ai_protocol := IPPROTO_TCP; + LAddrInfo := TSocketAPI.GetAddrInfo(AHost, APort, LHints); + if (LAddrInfo = nil) then + begin + _Failed1; + Exit; + end; + + P := LAddrInfo; + try + while (LAddrInfo <> nil) do + begin + LSocket := TSocketAPI.NewSocket(LAddrInfo.ai_family, LAddrInfo.ai_socktype, + LAddrInfo.ai_protocol); + if (LSocket = INVALID_SOCKET) then + begin + _LogLastOsError('NewSocket'); + + _Failed1; + Exit; + end; + + TSocketAPI.SetNonBlock(LSocket, True); + SetKeepAlive(LSocket); + + if _Connect(LSocket, LAddrInfo) then Exit; + + LAddrInfo := PRawAddrInfo(LAddrInfo.ai_next); + end; + finally + TSocketAPI.FreeAddrInfo(P); + end; + + _Failed1; +end; + +function TEpollCrossSocket.CreateConnection(const AOwner: TCrossSocketBase; + const AClientSocket: TSocket; const AConnectType: TConnectType; + const AHost: string; const AConnectCb: TCrossConnectionCallback): ICrossConnection; +begin + Result := TEpollConnection.Create( + AOwner, + AClientSocket, + AConnectType, + AHost, + AConnectCb); +end; + +function TEpollCrossSocket.CreateListen(const AOwner: TCrossSocketBase; + const AListenSocket: TSocket; const AFamily, ASockType, AProtocol: Integer): ICrossListen; +begin + Result := TEpollListen.Create(AOwner, AListenSocket, AFamily, ASockType, AProtocol); +end; + +procedure TEpollCrossSocket.Listen(const AHost: string; const APort: Word; + const ACallback: TCrossListenCallback); +var + LHints: TRawAddrInfo; + P, LAddrInfo: PRawAddrInfo; + LListenSocket: TSocket; + LListen: ICrossListen; + LEpListen: TEpollListen; + LListenSuccess, LUpdateIoEventSuccess: Boolean; + + procedure _Failed; + begin + if not LListenSuccess and Assigned(ACallback) then + ACallback(LListen, False); + + if (LListen <> nil) then + LListen.Close + else if (LListenSocket <> INVALID_SOCKET) then + TSocketAPI.CloseSocket(LListenSocket); + end; + +begin + LListenSuccess := False; + FillChar(LHints, SizeOf(TRawAddrInfo), 0); + LHints.ai_flags := AI_PASSIVE; + LHints.ai_family := AF_UNSPEC; + LHints.ai_socktype := SOCK_STREAM; + LHints.ai_protocol := IPPROTO_TCP; + LAddrInfo := TSocketAPI.GetAddrInfo(AHost, APort, LHints); + if (LAddrInfo = nil) then + begin + {$IFDEF DEBUG} + _LogLastOsError('TEpollCrossSocket.Listen.GetAddrInfo'); + {$ENDIF} + _Failed; + Exit; + end; + + P := LAddrInfo; + try + while (LAddrInfo <> nil) do + begin + LListen := nil; + LListenSocket := TSocketAPI.NewSocket(LAddrInfo.ai_family, LAddrInfo.ai_socktype, + LAddrInfo.ai_protocol); + if (LListenSocket = INVALID_SOCKET) then + begin + {$IFDEF DEBUG} + _LogLastOsError('TEpollCrossSocket.Listen.NewSocket'); + {$ENDIF} + _Failed; + Exit; + end; + + TSocketAPI.SetNonBlock(LListenSocket, True); + TSocketAPI.SetReUsePort(LListenSocket, True); + + if (LAddrInfo.ai_family = AF_INET6) then + TSocketAPI.SetSockOpt(LListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, 1); + + if (TSocketAPI.Bind(LListenSocket, LAddrInfo.ai_addr, LAddrInfo.ai_addrlen) < 0) + or (TSocketAPI.Listen(LListenSocket) < 0) then + begin + {$IFDEF DEBUG} + _LogLastOsError('TEpollCrossSocket.Listen.Bind'); + {$ENDIF} + _Failed; + Exit; + end; + + LListen := CreateListen(Self, LListenSocket, LAddrInfo.ai_family, + LAddrInfo.ai_socktype, LAddrInfo.ai_protocol); + LEpListen := LListen as TEpollListen; + + // 监听套接字的读事件 + // 读事件到达表明有新连接 + LEpListen._Lock; + try + LUpdateIoEventSuccess := LEpListen._UpdateIoEvent([ieRead]); + finally + LEpListen._Unlock; + end; + + if not LUpdateIoEventSuccess then + begin + _Failed; + Exit; + end; + + // 监听成功 + LListenSuccess := True; + TriggerListened(LListen); + if Assigned(ACallback) then + ACallback(LListen, True); + + // 如果端口传入0,让所有地址统一用首个分配到的端口 + if (APort = 0) and (LAddrInfo.ai_next <> nil) then + Psockaddr_in(LAddrInfo.ai_next.ai_addr).sin_port := htons(LListen.LocalPort); + + LAddrInfo := PRawAddrInfo(LAddrInfo.ai_next); + end; + finally + TSocketAPI.FreeAddrInfo(P); + end; +end; + +procedure TEpollCrossSocket.Send(const AConnection: ICrossConnection; + const ABuf: Pointer; const ALen: Integer; const ACallback: TCrossConnectionCallback); +var + LEpConnection: TEpollConnection; + LSendItem: PSendItem; +begin + // 测试过先发送, 然后将剩余部分放入发送队列的做法 + // 发现会引起内存访问异常, 放到队列里到IO线程中发送则不会有问题 + {$region '放入发送队列'} + System.New(LSendItem); + FillChar(LSendItem^, SizeOf(TSendItem), 0); + LSendItem.Data := ABuf; + LSendItem.Size := ALen; + LSendItem.Callback := ACallback; + + LEpConnection := AConnection as TEpollConnection; + + LEpConnection._Eplock; + try + // 将数据放入队列 + LEpConnection.FSendQueue.Add(LSendItem); + + // 由于epoll队列中每个套接字只有一条记录, 为了避免监视发送数据的时候 + // 无法接收数据, 这里必须同时监视读和写 + LEpConnection._UpdateIoEvent([ieRead, ieWrite]); + finally + LEpConnection._EpUnlock; + end; + {$endregion} +end; + +function TEpollCrossSocket.ProcessIoEvent: Boolean; +var + LRet, I: Integer; + LEvent: TEPoll_Event; + LCrossUID: UInt64; + LCrossTag: Byte; + LListens: TCrossListens; + LConnections: TCrossConnections; + LListen: ICrossListen; + LEpListen: TEpollListen; + LConnection: ICrossConnection; + LEpConnection: TEpollConnection; + LSuccess: Boolean; + LIoEvents: TIoEvents; +begin + // 被系统信号打断或者出错会返回-1, 具体需要根据错误代码判断 + LRet := epoll_wait(FEpollHandle, @FEventList[0], MAX_EVENT_COUNT, -1); + if (LRet < 0) then + begin + _LogLastOsError('epoll_wait'); + LRet := GetLastError; + // EINTR, epoll_wait 调用被系统信号打断, 可以进行重试 + Exit(LRet = EINTR); + end; + + for I := 0 to LRet - 1 do + begin + LEvent := FEventList[I]; + + // 收到退出命令 + if (LEvent.Data.u64 = SHUTDOWN_FLAG) then Exit(False); + + {$region '获取连接或监听对象'} + LCrossUID := LEvent.Data.u64; + LCrossTag := GetTagByUID(LCrossUID); + LListen := nil; + LConnection := nil; + + {$IFDEF DEBUG} +// _Log('epoll events %.8x, uid %.16x, tag %d', [LEvent.Events, LEvent.Data.u64, LCrossTag]); + {$ENDIF} + case LCrossTag of + UID_LISTEN: + begin + LListens := LockListens; + try + if not LListens.TryGetValue(LCrossUID, LListen) + or (LListen = nil) then + Continue; + finally + UnlockListens; + end; + end; + + UID_CONNECTION: + begin + LConnections := LockConnections; + try + if not LConnections.TryGetValue(LCrossUID, LConnection) + or (LConnection = nil) then + Continue; + finally + UnlockConnections; + end; + end; + else + Continue; + end; + {$endregion} + + {$region 'IO事件处理'} + if (LListen <> nil) then + begin + if (LEvent.Events and EPOLLIN <> 0) then + _HandleAccept(LListen); + + // 继续接收新连接 + LEpListen := LListen as TEpollListen; + LEpListen._Lock; + LEpListen._UpdateIoEvent([ieRead]); + LEpListen._Unlock; + end else + if (LConnection <> nil) then + begin + // 连接被断开 + if (LEvent.Events and EPOLLERR <> 0) + or (LEvent.Events and EPOLLHUP <> 0) then + begin + _Log('epoll_wait, %s, EPOLLERR=%d, EPOLLHUP=%d', [ + LConnection.DebugInfo, + LEvent.Events and EPOLLERR, + LEvent.Events and EPOLLHUP + ]); + LConnection.Close; + Continue; + end; + + // epoll的读写事件同一时间可能两个同时触发 + if (LEvent.Events and EPOLLIN <> 0) then + _HandleRead(LConnection); + + if (LEvent.Events and EPOLLOUT <> 0) then + begin + if (LConnection.ConnectStatus = csConnecting) then + _HandleConnect(LConnection) + else + _HandleWrite(LConnection); + end; + + // 把更新连接的IO事件放到这里统一处理 + // 当读写同时触发的情况, 可以节省一次IO事件更新 + if not LConnection.IsClosed then + begin + LEpConnection := LConnection as TEpollConnection; + LEpConnection._EpLock; + try + if (LEpConnection.FSendQueue.Count > 0) then + LIoEvents := [ieRead, ieWrite] + else + LIoEvents := [ieRead]; + LEpConnection._UpdateIoEvent(LIoEvents); + finally + LEpConnection._EpUnlock; + end; + end; + end; + {$endregion} + end; + + Result := True; +end; + +end. diff --git a/Net/Net.CrossSocket.Iocp.pas b/Net/Net.CrossSocket.Iocp.pas index 1e9523c..47a3ba0 100644 --- a/Net/Net.CrossSocket.Iocp.pas +++ b/Net/Net.CrossSocket.Iocp.pas @@ -1,891 +1,891 @@ -{******************************************************************************} -{ } -{ Delphi cross platform socket library } -{ } -{ Copyright (c) 2017 WiNDDRiVER(soulawing@gmail.com) } -{ } -{ Homepage: https://github.com/winddriver/Delphi-Cross-Socket } -{ } -{******************************************************************************} -unit Net.CrossSocket.Iocp; - -{$I zLib.inc} - -interface - -uses - SysUtils, - Classes, - Windows, - - Net.Winsock2, - Net.Wship6, - Net.SocketAPI, - Net.CrossSocket.Base; - -type - TIocpListen = class(TCrossListenBase) - end; - - TIocpConnection = class(TCrossConnectionBase) - end; - - TIocpCrossSocket = class(TCrossSocketBase) - private const - SHUTDOWN_FLAG = ULONG_PTR(-1); - SO_UPDATE_CONNECT_CONTEXT = $7010; - IPV6_V6ONLY = 27; - ERROR_ABANDONED_WAIT_0 = $02DF; - private type - TAddrUnion = record - case Integer of - 0: (IPv4: TSockAddrIn); - 1: (IPv6: TSockAddrIn6); - end; - - TAddrBuffer = record - Addr: TAddrUnion; - Extra: array [0..15] of Byte; - end; - - TAcceptExBuffer = array[0..SizeOf(TAddrBuffer) * 2 - 1] of Byte; - - TPerIoBufUnion = record - case Integer of - 0: (DataBuf: WSABUF); - // 这个Buffer只用于AcceptEx保存终端地址数据,大小为2倍地址结构 - 1: (AcceptExBuffer: TAcceptExBuffer); - end; - - TIocpAction = (ioAccept, ioConnect, ioRead, ioWrite); - - PPerIoData = ^TPerIoData; - TPerIoData = record - Overlapped: TWSAOverlapped; - Buffer: TPerIoBufUnion; - Action: TIocpAction; - Socket: TSocket; - CrossData: ICrossData; - Callback: TCrossConnectionCallback; - end; - private - FIocpHandle: THandle; - FIoThreads: TArray; - FPerIoDataCount: NativeInt; - - function _NewIoData: PPerIoData; inline; - procedure _FreeIoData(const P: PPerIoData); inline; - - procedure _NewAccept(const AListen: ICrossListen); - function _NewReadZero(const AConnection: ICrossConnection): Boolean; - - procedure _HandleAccept(const APerIoData: PPerIoData); - procedure _HandleConnect(const APerIoData: PPerIoData); - procedure _HandleRead(const APerIoData: PPerIoData); - procedure _HandleWrite(const APerIoData: PPerIoData); - protected - function CreateListen(const AOwner: TCrossSocketBase; const AListenSocket: TSocket; - const AFamily, ASockType, AProtocol: Integer): ICrossListen; override; - function CreateConnection(const AOwner: TCrossSocketBase; const AClientSocket: TSocket; - const AConnectType: TConnectType; const AHost: string; - const AConnectCb: TCrossConnectionCallback): ICrossConnection; override; - - procedure StartLoop; override; - procedure StopLoop; override; - - procedure Listen(const AHost: string; const APort: Word; - const ACallback: TCrossListenCallback = nil); override; - - procedure Connect(const AHost: string; const APort, ALocalPort: Word; - const ACallback: TCrossConnectionCallback = nil); override; - - procedure Send(const AConnection: ICrossConnection; const ABuf: Pointer; - const ALen: Integer; const ACallback: TCrossConnectionCallback = nil); override; - - function ProcessIoEvent: Boolean; override; - end; - -implementation - -{ TIocpCrossSocket } - -function TIocpCrossSocket._NewIoData: PPerIoData; -begin - GetMem(Result, SizeOf(TPerIoData)); - FillChar(Result^, SizeOf(TPerIoData), 0); - System.Initialize(Result^); - - AtomicIncrement(FPerIoDataCount); -end; - -procedure TIocpCrossSocket._FreeIoData(const P: PPerIoData); -begin - if (P = nil) then Exit; - - System.Finalize(P^); - FreeMem(P, SizeOf(TPerIoData)); - - AtomicDecrement(FPerIoDataCount); -end; - -procedure TIocpCrossSocket._NewAccept(const AListen: ICrossListen); -var - LClientSocket: TSocket; - LPerIoData: PPerIoData; - LBytes: Cardinal; -begin - LClientSocket := WSASocket(AListen.Family, AListen.SockType, AListen.Protocol, - nil, 0, WSA_FLAG_OVERLAPPED); - if (LClientSocket = INVALID_SOCKET) then - begin - {$IFDEF DEBUG} - _LogLastOsError(Self.ClassName + '._NewAccept.WSASocket, %s', [AListen.DebugInfo]); - {$ENDIF} - Exit; - end; - - TSocketAPI.SetNonBlock(LClientSocket, True); - SetKeepAlive(LClientSocket); - - LPerIoData := _NewIoData; - LPerIoData.Action := ioAccept; - LPerIoData.Socket := LClientSocket; - LPerIoData.CrossData := AListen; - - if (not AcceptEx(AListen.Socket, LClientSocket, @LPerIoData.Buffer.AcceptExBuffer, 0, - SizeOf(TAddrBuffer), SizeOf(TAddrBuffer), LBytes, POverlapped(LPerIoData))) - and (WSAGetLastError <> WSA_IO_PENDING) then - begin - {$IFDEF DEBUG} - _LogLastOsError(Self.ClassName + '._NewAccept.AcceptEx, %s', [AListen.DebugInfo]); - {$ENDIF} - TSocketAPI.CloseSocket(LClientSocket); - _FreeIoData(LPerIoData); - end; -end; - -function TIocpCrossSocket._NewReadZero(const AConnection: ICrossConnection): Boolean; -var - LPerIoData: PPerIoData; - LBytes, LFlags: Cardinal; -begin - LPerIoData := _NewIoData; - LPerIoData.Buffer.DataBuf.buf := nil; - LPerIoData.Buffer.DataBuf.len := 0; - LPerIoData.Action := ioRead; - LPerIoData.Socket := AConnection.Socket; - LPerIoData.CrossData := AConnection; - - LFlags := 0; - LBytes := 0; - if (WSARecv(AConnection.Socket, @LPerIoData.Buffer.DataBuf, 1, LBytes, LFlags, PWSAOverlapped(LPerIoData), nil) < 0) - and (WSAGetLastError <> WSA_IO_PENDING) then - begin - {$IFDEF DEBUG} - _LogLastOsError(Self.ClassName + '._NewReadZero.WSARecv, %s', [AConnection.DebugInfo]); - {$ENDIF} - _FreeIoData(LPerIoData); - Exit(False); - end; - - Result := True; -end; - -procedure TIocpCrossSocket._HandleAccept(const APerIoData: PPerIoData); -var - LListen: ICrossListen; - LConnection: ICrossConnection; - LClientSocket, LListenSocket: TSocket; -begin - if (APerIoData.CrossData = nil) then Exit; - - LListen := APerIoData.CrossData as ICrossListen; - - _NewAccept(LListen); - - LClientSocket := APerIoData.Socket; - LListenSocket := LListen.Socket; - - // 不设置该参数, 会导致 getpeername 调用失败 - if (TSocketAPI.SetSockOpt(LClientSocket, SOL_SOCKET, - SO_UPDATE_ACCEPT_CONTEXT, LListenSocket) < 0) then - begin - {$IFDEF DEBUG} - _LogLastOsError(Self.ClassName + '._HandleAccept.SetSockOpt'); - {$ENDIF} - TSocketAPI.CloseSocket(LClientSocket); - Exit; - end; - - if (CreateIoCompletionPort(LClientSocket, FIocpHandle, ULONG_PTR(LClientSocket), 0) = 0) then - begin - {$IFDEF DEBUG} - _LogLastOsError(Self.ClassName + '._HandleAccept.CreateIoCompletionPort'); - {$ENDIF} - TSocketAPI.CloseSocket(LClientSocket); - Exit; - end; - - LConnection := CreateConnection(Self, LClientSocket, ctAccept, ''); - TriggerConnecting(LConnection); - TriggerConnected(LConnection); - - if not _NewReadZero(LConnection) then - LConnection.Close; -end; - -procedure TIocpCrossSocket._HandleConnect(const APerIoData: PPerIoData); -var - LClientSocket: TSocket; - LConnection: ICrossConnection; - LSockErr: Integer; -begin - LClientSocket := APerIoData.Socket; - LConnection := APerIoData.CrossData as ICrossConnection; - - LSockErr := TSocketAPI.GetError(LClientSocket); - if (LSockErr <> 0) then - begin - if (LConnection <> nil) then - LConnection.LastNetError := LSockErr; - _LogLastOsError(Self.ClassName + '._HandleConnect.GetError'); - LConnection.Close; - Exit; - end; - - // 不设置该参数, 会导致 getpeername 调用失败 - if (TSocketAPI.SetSockOpt(LClientSocket, SOL_SOCKET, - SO_UPDATE_CONNECT_CONTEXT, 1) < 0) then - begin - if (LConnection <> nil) then - LConnection.LastNetError := WSAGetLastError; - _LogLastOsError(Self.ClassName + '._HandleConnect.SetSockOpt'); - LConnection.Close; - Exit; - end; - - TriggerConnected(LConnection); - - if not _NewReadZero(LConnection) then - LConnection.Close; -end; - -procedure TIocpCrossSocket._HandleRead(const APerIoData: PPerIoData); -var - LConnection: ICrossConnection; - LRcvd, LError: Integer; -begin - if (APerIoData.CrossData = nil) then - begin - if Assigned(APerIoData.Callback) then - APerIoData.Callback(nil, False); - Exit; - end; - - LConnection := APerIoData.CrossData as ICrossConnection; - - while True do - begin - LRcvd := TSocketAPI.Recv(LConnection.Socket, FRecvBuf[0], RCV_BUF_SIZE); - - // 对方主动断开连接 - if (LRcvd = 0) then - begin - _Log(Self.ClassName + '.Recv=0(Close), %s', [LConnection.DebugInfo]); - LConnection.Close; - Exit; - end; - - if (LRcvd < 0) then - begin - LError := GetLastError; - - // 被系统信号中断, 可以重新recv - if (LError = WSAEINTR) then - Continue - // 接收缓冲区中数据已经被取完了 - else if (LError = WSAEWOULDBLOCK) or (LError = WSAEINPROGRESS) then - Break - // 接收出错 - else - begin - _LogLastOsError(Self.ClassName + '.Recv<0, %s', [LConnection.DebugInfo]); - LConnection.Close; - Exit; - end; - end; - - {$IFDEF DEBUG} - _Log('[%s]thread%d, _HandleRead.TriggerReceived准备执行, LRcvd=%d', [ - Self.ClassName, TThread.Current.ThreadID, LRcvd - ]); - {$ENDIF} - TriggerReceived(LConnection, @FRecvBuf[0], LRcvd); - {$IFDEF DEBUG} - _Log('[%s]thread%d, _HandleRead.TriggerReceived执行完成, LRcvd=%d', [ - Self.ClassName, TThread.Current.ThreadID, LRcvd - ]); - {$ENDIF} - - // 回调中可能关闭了连接, 需要检查状态 - if LConnection.IsClosed then Exit; - - if (LRcvd < RCV_BUF_SIZE) then Break; - end; - - if not _NewReadZero(LConnection) then - LConnection.Close; -end; - -procedure TIocpCrossSocket._HandleWrite(const APerIoData: PPerIoData); -begin - if Assigned(APerIoData.Callback) then - APerIoData.Callback(APerIoData.CrossData as ICrossConnection, True); -end; - -procedure TIocpCrossSocket.StartLoop; -var - I: Integer; -begin - if (FIoThreads <> nil) then Exit; - - FIocpHandle := CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0); - SetLength(FIoThreads, GetIoThreads); - for I := 0 to Length(FIoThreads) - 1 do - FIoThreads[I] := TIoEventThread.Create(Self); -end; - -procedure TIocpCrossSocket.StopLoop; - - // IO 线程在收到 SHUTDOWN_FLAG 标记之后就会退出 - // 而这时候有可能还有部分操作未完成, 其对应的 PerIoData 结构就无法释放 - // 只需要在这里再次接收完成端口的消息, 就能等到这部分未完成的操作超时或失败 - // 从而释放其对应的 PerIoData 结构 - // - // 超时仍未清零时: 输出错误日志诊断遗留, 仍关闭 IOCP handle (避免 OS 句柄泄漏). - // 因 IO 线程已退出, 此处与 _HandleXxx 路径互斥, 无 PerIoData 重复释放风险. - procedure _FreeMissingPerIoDatas; - const - DEFAULT_DRAIN_TIMEOUT_MS = 3000; - POLL_STEP_MS = 10; - var - LBytes: Cardinal; - LSocket: TSocket; - LPerIoData: PPerIoData; - LConnection: ICrossConnection; - LMaxWait, LRemaining: Integer; - begin - LMaxWait := DEFAULT_DRAIN_TIMEOUT_MS; - LRemaining := LMaxWait; - - while (AtomicCmpExchange(FPerIoDataCount, 0, 0) > 0) and (LRemaining > 0) do - begin - GetQueuedCompletionStatus(FIocpHandle, LBytes, ULONG_PTR(LSocket), POverlapped(LPerIoData), POLL_STEP_MS); - - if (LPerIoData = nil) then - begin - Dec(LRemaining, POLL_STEP_MS); - Continue; - end; - - try - TSocketAPI.CloseSocket(LPerIoData.Socket); - - if Assigned(LPerIoData.Callback) then - begin - if (LPerIoData.CrossData <> nil) - and (LPerIoData.CrossData is TIocpConnection) then - LConnection := LPerIoData.CrossData as ICrossConnection - else - LConnection := nil; - - LPerIoData.Callback(LConnection, False); - end; - - if (LPerIoData.CrossData <> nil) then - LPerIoData.CrossData.Close; - finally - _FreeIoData(LPerIoData); - end; - end; - - // 超时仍未清零: 不静默, 强制 _Log (受 CrossSocketLogEnabled 全局开关控制) - if (AtomicCmpExchange(FPerIoDataCount, 0, 0) > 0) then - _Log('[%s][StopLoop] WARNING: drain 超时 %dms, 仍有 %d 个 PerIoData 未回收, 即将关闭 IOCP handle', - [Self.ClassName, LMaxWait, AtomicCmpExchange(FPerIoDataCount, 0, 0)]); - end; - -var - I: Integer; - LCurrentThreadID: TThreadID; -begin - if (FIoThreads = nil) then Exit; - - {$IFDEF DEBUG} - _Log('[%s][StopLoop] 开始停止, 线程数=%d', [ - Self.ClassName, Length(FIoThreads)]); - {$ENDIF} - CloseAll; - - {$IFDEF DEBUG} - _Log('[%s][StopLoop] 等待连接关闭, ListensCount=%d, ConnectionsCount=%d', [ - Self.ClassName, ListensCount, ConnectionsCount - ]); - {$ENDIF} - while (ListensCount > 0) or (ConnectionsCount > 0) do Sleep(1); - - {$IFDEF DEBUG} - _Log('[%s][StopLoop] 发送 SHUTDOWN_FLAG 唤醒所有线程', [ - Self.ClassName - ]); - {$ENDIF} - for I := 0 to Length(FIoThreads) - 1 do - PostQueuedCompletionStatus(FIocpHandle, 0, 0, POverlapped(SHUTDOWN_FLAG)); - - LCurrentThreadID := GetCurrentThreadId; - for I := 0 to Length(FIoThreads) - 1 do - begin - if (FIoThreads[I].ThreadID = LCurrentThreadID) then - raise ECrossSocket.Create('不能在IO线程中执行StopLoop!'); - - {$IFDEF DEBUG} - _Log('[%s]thread%d[StopLoop] 等待线程 %d 退出', [ - Self.ClassName, FIoThreads[I].ThreadID, I - ]); - {$ENDIF} - FIoThreads[I].WaitFor; - {$IFDEF DEBUG} - _Log('[%s]thread%d[StopLoop] 线程 %d 已退出', [ - Self.ClassName, FIoThreads[I].ThreadID, I]); - {$ENDIF} - FreeAndNil(FIoThreads[I]); - end; - FIoThreads := nil; - - _FreeMissingPerIoDatas; - CloseHandle(FIocpHandle); -end; - -procedure TIocpCrossSocket.Connect(const AHost: string; - const APort, ALocalPort: Word; const ACallback: TCrossConnectionCallback); -var - LHints: TRawAddrInfo; - P, LAddrInfo: PRawAddrInfo; - LSocket: TSocket; - - procedure _Failed1; - begin - if Assigned(ACallback) then - ACallback(nil, False); - end; - - function _Connect(ASocket: TSocket; AAddr: PRawAddrInfo): Boolean; - procedure _Failed2; - begin - if Assigned(ACallback) then - ACallback(nil, False); - TSocketAPI.CloseSocket(ASocket); - end; - var - LSockAddr: TRawSockAddrIn; - LPerIoData: PPerIoData; - LBytes: Cardinal; - LConnection: ICrossConnection; - begin - FillChar(LSockAddr, SizeOf(TRawSockAddrIn), 0); - LSockAddr.AddrLen := AAddr.ai_addrlen; - if (AAddr.ai_family = AF_INET6) then - begin - LSockAddr.Addr6.sin6_family := AAddr.ai_family; - LSockAddr.Addr6.sin6_port := htons(ALocalPort); - end else - begin - LSockAddr.Addr.sin_family := AAddr.ai_family; - LSockAddr.Addr.sin_port := htons(ALocalPort); - end; - if (TSocketAPI.Bind(ASocket, @LSockAddr.Addr, LSockAddr.AddrLen) < 0) then - begin - _LogLastOsError(Self.ClassName + '._Connect.Bind'); - _Failed2; - Exit(False); - end; - - if (CreateIoCompletionPort(ASocket, FIocpHandle, ULONG_PTR(ASocket), 0) = 0) then - begin - _LogLastOsError(Self.ClassName + '._Connect.CreateIoCompletionPort'); - _Failed2; - Exit(False); - end; - - LConnection := CreateConnection(Self, ASocket, ctConnect, AHost, ACallback); - TriggerConnecting(LConnection); - - LPerIoData := _NewIoData; - LPerIoData.Action := ioConnect; - LPerIoData.CrossData := LConnection; - LPerIoData.Socket := ASocket; - LPerIoData.Callback := nil; - if not ConnectEx(ASocket, AAddr.ai_addr, AAddr.ai_addrlen, nil, 0, LBytes, PWSAOverlapped(LPerIoData)) and - (WSAGetLastError <> WSA_IO_PENDING) then - begin - // 先保存 WSAGetLastError 再记录日志, 避免后续 API 调用改写 lastError - if (LConnection <> nil) then - LConnection.LastNetError := WSAGetLastError; - _LogLastOsError(Self.ClassName + '._Connect.ConnectEx'); - _FreeIoData(LPerIoData); - LConnection.Close; - Exit(False); - end; - - Result := True; - end; - -begin - FillChar(LHints, SizeOf(TRawAddrInfo), 0); - LHints.ai_family := AF_UNSPEC; - LHints.ai_socktype := SOCK_STREAM; - LHints.ai_protocol := IPPROTO_TCP; - LAddrInfo := TSocketAPI.GetAddrInfo(AHost, APort, LHints); - if (LAddrInfo = nil) then - begin - _LogLastOsError(Self.ClassName + '.Connect.GetAddrInfo'); - _Failed1; - Exit; - end; - - P := LAddrInfo; - try - while (LAddrInfo <> nil) do - begin - LSocket := WSASocket(LAddrInfo.ai_family, LAddrInfo.ai_socktype, - LAddrInfo.ai_protocol, nil, 0, WSA_FLAG_OVERLAPPED); - if (LSocket = INVALID_SOCKET) then - begin - _LogLastOsError(Self.ClassName + '.Connect.WSASocket'); - _Failed1; - Exit; - end; - - TSocketAPI.SetNonBlock(LSocket, True); - SetKeepAlive(LSocket); - - {$IFDEF DEBUG} - _Log('TIocpCrossSocket.Connect.WSASocket=%d', [LSocket]); - {$ENDIF} - - if _Connect(LSocket, LAddrInfo) then Exit; - - LAddrInfo := PRawAddrInfo(LAddrInfo.ai_next); - end; - finally - TSocketAPI.FreeAddrInfo(P); - end; - - _LogLastOsError(Self.ClassName + '.Connect.Unknown'); - _Failed1; -end; - -function TIocpCrossSocket.CreateConnection(const AOwner: TCrossSocketBase; - const AClientSocket: TSocket; const AConnectType: TConnectType; - const AHost: string; const AConnectCb: TCrossConnectionCallback): ICrossConnection; -begin - Result := TIocpConnection.Create(AOwner, AClientSocket, AConnectType, AHost, AConnectCb); -end; - -function TIocpCrossSocket.CreateListen(const AOwner: TCrossSocketBase; - const AListenSocket: TSocket; const AFamily, ASockType, AProtocol: Integer): ICrossListen; -begin - Result := TIocpListen.Create(AOwner, AListenSocket, AFamily, ASockType, AProtocol); -end; - -procedure TIocpCrossSocket.Listen(const AHost: string; const APort: Word; - const ACallback: TCrossListenCallback); -var - LHints: TRawAddrInfo; - P, LAddrInfo: PRawAddrInfo; - LListenSocket: TSocket; - LListen: ICrossListen; - I: Integer; - LListenSuccess: Boolean; - - procedure _Failed; - begin - if not LListenSuccess and Assigned(ACallback) then - ACallback(LListen, False); - - if (LListen <> nil) then - LListen.Close - else if (LListenSocket <> INVALID_SOCKET) then - TSocketAPI.CloseSocket(LListenSocket); - end; - - procedure _Success; - begin - TriggerListened(LListen); - - if Assigned(ACallback) then - ACallback(LListen, True); - end; -begin - LListenSuccess := False; - FillChar(LHints, SizeOf(TRawAddrInfo), 0); - - LHints.ai_flags := AI_PASSIVE; - LHints.ai_family := AF_UNSPEC; - LHints.ai_socktype := SOCK_STREAM; - LHints.ai_protocol := IPPROTO_TCP; - LAddrInfo := TSocketAPI.GetAddrInfo(AHost, APort, LHints); - if (LAddrInfo = nil) then - begin - {$IFDEF DEBUG} - _LogLastOsError(Self.ClassName + '.Listen.GetAddrInfo'); - {$ENDIF} - _Failed; - Exit; - end; - - P := LAddrInfo; - try - while (LAddrInfo <> nil) do - begin - LListen := nil; - LListenSocket := WSASocket(LAddrInfo.ai_family, LAddrInfo.ai_socktype, - LAddrInfo.ai_protocol, nil, 0, WSA_FLAG_OVERLAPPED); - if (LListenSocket = INVALID_SOCKET) then - begin - {$IFDEF DEBUG} - _LogLastOsError(Self.ClassName + '.Listen.WSASocket'); - {$ENDIF} - _Failed; - Exit; - end; - - TSocketAPI.SetNonBlock(LListenSocket, True); - TSocketAPI.SetReUseAddr(LListenSocket, True); - - if (LAddrInfo.ai_family = AF_INET6) then - TSocketAPI.SetSockOpt(LListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, 1); - - if (TSocketAPI.Bind(LListenSocket, LAddrInfo.ai_addr, LAddrInfo.ai_addrlen) < 0) then - begin - {$IFDEF DEBUG} - _LogLastOsError(Self.ClassName + '.Listen.Bind'); - {$ENDIF} - _Failed; - Exit; - end; - - if (TSocketAPI.Listen(LListenSocket) < 0) then - begin - {$IFDEF DEBUG} - _LogLastOsError(Self.ClassName + '.Listen.Listen'); - {$ENDIF} - _Failed; - Exit; - end; - - LListen := CreateListen(Self, LListenSocket, LAddrInfo.ai_family, - LAddrInfo.ai_socktype, LAddrInfo.ai_protocol); - - if (CreateIoCompletionPort(LListenSocket, FIocpHandle, ULONG_PTR(LListenSocket), 0) = 0) then - begin - {$IFDEF DEBUG} - _LogLastOsError(Self.ClassName + '.Listen.CreateIoCompletionPort'); - {$ENDIF} - _Failed; - Exit; - end; - - // 给每个IO线程投递一个AcceptEx - for I := 1 to GetIoThreads do - _NewAccept(LListen); - - LListenSuccess := True; - _Success; - - // 如果端口传入0,让所有地址统一用首个分配到的端口 - if (APort = 0) and (LAddrInfo.ai_next <> nil) then - LAddrInfo.ai_next.ai_addr.sin_port := htons(LListen.LocalPort); - - LAddrInfo := PRawAddrInfo(LAddrInfo.ai_next); - end; - finally - TSocketAPI.FreeAddrInfo(P); - end; -end; - -procedure TIocpCrossSocket.Send(const AConnection: ICrossConnection; - const ABuf: Pointer; const ALen: Integer; const ACallback: TCrossConnectionCallback); -var - LPerIoData: PPerIoData; - LBytes, LFlags: Cardinal; -begin - LPerIoData := _NewIoData; - LPerIoData.Buffer.DataBuf.buf := ABuf; - LPerIoData.Buffer.DataBuf.len := ALen; - LPerIoData.Action := ioWrite; - LPerIoData.Socket := AConnection.Socket; - LPerIoData.CrossData := AConnection; - LPerIoData.Callback := ACallback; - - LFlags := 0; - LBytes := 0; - // WSASend 不会出现部分发送的情况, 要么全部失败, 要么全部成功 - // 所以不需要像 kqueue 或 epoll 中调用 send 那样调用完之后还得检查实际发送了多少 - // 唯一需要注意的是: WSASend 会将待发送的数据锁定到非页面内存, 非页面内存资源 - // 是非常紧张的, 所以不要无节制的调用 WSASend, 最好通过回调发送完一批数据再继 - // 续发送下一批 - if (WSASend(AConnection.Socket, @LPerIoData.Buffer.DataBuf, 1, LBytes, LFlags, PWSAOverlapped(LPerIoData), nil) < 0) - and (WSAGetLastError <> WSA_IO_PENDING) then - begin - {$IFDEF DEBUG} - _LogLastOsError(Self.ClassName + '.WSASend, %s', [AConnection.DebugInfo]); - {$ENDIF} - - // 出错多半是 WSAENOBUFS, 也就是投递的 WSASend 过多, 来不及发送 - // 导致非页面内存资源全部被锁定, 要避免这种情况必须上层发送逻辑 - // 保证不能无节制的调用Send发送大量数据, 最好发送完一个再继续下 - // 一个, 本函数提供了发送结果的回调函数, 在回调函数报告发送成功 - // 之后就可以继续下一块数据发送了 - _FreeIoData(LPerIoData); - - if Assigned(ACallback) then - ACallback(AConnection, False); - - if Assigned(AConnection) then - AConnection.Close; - end; -end; - -function TIocpCrossSocket.ProcessIoEvent: Boolean; - procedure _ReleasePerIoData(const APerIoData: PPerIoData; const AShutdown: Boolean); - var - LConnection: ICrossConnection; - begin - try - if (APerIoData.CrossData <> nil) then - begin - // AcceptEx虽然成功, 但是Socket句柄耗尽了, 再次投递AcceptEx - if (APerIoData.Action = ioAccept) then - begin - // 照理说能执行到这里, 说明Socket分配失败了 - // 但是为了以防万一, 这里还是判断一下并释放掉无效的Socket句柄 - if (APerIoData.Socket <> 0) then - TSocketAPI.CloseSocket(APerIoData.Socket); - - // 关闭监听后会触发该错误, 这种情况不应该继续投递 - if not AShutdown then - begin - _Log('[%s]thread%d, _NewAccept', [Self.ClassName, TThread.Current.ThreadID]); - _NewAccept(APerIoData.CrossData as ICrossListen); - end; - end else - begin - {$IFDEF DEBUG} - _LogLastOsError( - Format(Self.ClassName + '.ProcessIoEvent.GetQueuedCompletionStatus.CrossDataNotNil(socket=%d, action=%d)', - [APerIoData.Socket, Ord(APerIoData.Action)]) - ); - {$ENDIF} - if Assigned(APerIoData.Callback) then - begin - if (APerIoData.CrossData is TIocpConnection) then - LConnection := APerIoData.CrossData as ICrossConnection - else - LConnection := nil; - - APerIoData.Callback(LConnection, False); - end; - - APerIoData.CrossData.Close; - end; - end else - begin - {$IFDEF DEBUG} - _LogLastOsError( - Format(Self.ClassName + '.ProcessIoEvent.GetQueuedCompletionStatus.CrossDataIsNil(socket=%d, action=%d)', - [APerIoData.Socket, Ord(APerIoData.Action)]) - ); - {$ENDIF} - if Assigned(APerIoData.Callback) then - APerIoData.Callback(nil, False); - - if (APerIoData.Socket <> 0) then - TSocketAPI.CloseSocket(APerIoData.Socket); - end; - finally - _FreeIoData(APerIoData); - end; - end; -var - LBytes: Cardinal; - LSocket: TSocket; - LPerIoData: PPerIoData; - LErrNo: Cardinal; - LIocpClosed: Boolean; -begin - if not GetQueuedCompletionStatus(FIocpHandle, LBytes, ULONG_PTR(LSocket), POverlapped(LPerIoData), INFINITE) then - begin - // ERROR_INVALID_HANDLE, 6, IOCP句柄被关闭 - // ERROR_ABANDONED_WAIT_0, $02DF, IOCP句柄被关闭 - // WSA_OPERATION_ABORTED, 995, 监听端口被关闭, 由于线程退出或应用程序请求,已中止 I/O 操作。 - // WSAENOTSOCK, 10038, 在一个非套接字上尝试了一个操作。 - // WSAESHUTDOWN, 10058, 套接字已关闭 - // ERROR_NETNAME_DELETED, 64, 指定的网络名不再可用 - // ERROR_CONNECTION_REFUSED, 1225, 远程计算机拒绝网络连接。 - LErrNo := GetLastError; - - // 完成端口被关闭时可能会触发 ERROR_INVALID_HANDLE 和 ERROR_ABANDONED_WAIT_0 - // 监听端口被关闭时会触发 WSA_OPERATION_ABORTED - LIocpClosed := (LErrNo = ERROR_INVALID_HANDLE) - or (LErrNo = ERROR_ABANDONED_WAIT_0) - or (LErrNo = WSA_OPERATION_ABORTED); - {$IFDEF DEBUG} - _Log('[%s]thread%d, GetQueuedCompletionStatus:%d, %s', [ - Self.ClassName, TThread.Current.ThreadID, LErrNo, SysErrorMessage(LErrNo) - ]); - {$ENDIF} - - // 出错了, 并且完成数据也都是空的, - // 这种情况即便重试, 应该也会继续出错, 最好立即终止IO线程 - if (LPerIoData = nil) then Exit(False); - - // 出错了, 回收资源 - _ReleasePerIoData(LPerIoData, LIocpClosed); - - // 出错了, 但是完成数据不是空的, 需要重试 - Exit(not LIocpClosed); - end; - - // 主动调用了 StopLoop - if (LBytes = 0) and (ULONG_PTR(LPerIoData) = SHUTDOWN_FLAG) then Exit(False); - - // 由于未知原因未获取到完成数据, 但是返回的错误代码又是正常 - // 这种情况需要进行重试(返回True之后IO线程会再次调用ProcessIoEvent) - if (LPerIoData = nil) then Exit(True); - - try - {$IFDEF DEBUG} - _Log('[%s]thread%d, 准备处理IOCP事件 PerIoData=%p, Action=%d, Bytes=%d', [ - Self.ClassName, TThread.Current.ThreadID, Pointer(LPerIoData), Ord(LPerIoData.Action), LBytes - ]); - {$ENDIF} - case LPerIoData.Action of - ioAccept : _HandleAccept(LPerIoData); - ioConnect : _HandleConnect(LPerIoData); - ioRead : _HandleRead(LPerIoData); - ioWrite : _HandleWrite(LPerIoData); - end; - {$IFDEF DEBUG} - _Log('[%s]thread%d, 处理IOCP事件完成 PerIoData=%p, Action=%d, Bytes=%d', [ - Self.ClassName, TThread.Current.ThreadID, Pointer(LPerIoData), Ord(LPerIoData.Action), LBytes - ]); - {$ENDIF} - finally - _FreeIoData(LPerIoData); - end; - - Result := True; -end; - -end. +{******************************************************************************} +{ } +{ Delphi cross platform socket library } +{ } +{ Copyright (c) 2017 WiNDDRiVER(soulawing@gmail.com) } +{ } +{ Homepage: https://github.com/winddriver/Delphi-Cross-Socket } +{ } +{******************************************************************************} +unit Net.CrossSocket.Iocp; + +{$I zLib.inc} + +interface + +uses + SysUtils, + Classes, + Windows, + + Net.Winsock2, + Net.Wship6, + Net.SocketAPI, + Net.CrossSocket.Base; + +type + TIocpListen = class(TCrossListenBase) + end; + + TIocpConnection = class(TCrossConnectionBase) + end; + + TIocpCrossSocket = class(TCrossSocketBase) + private const + SHUTDOWN_FLAG = ULONG_PTR(-1); + SO_UPDATE_CONNECT_CONTEXT = $7010; + IPV6_V6ONLY = 27; + ERROR_ABANDONED_WAIT_0 = $02DF; + private type + TAddrUnion = record + case Integer of + 0: (IPv4: TSockAddrIn); + 1: (IPv6: TSockAddrIn6); + end; + + TAddrBuffer = record + Addr: TAddrUnion; + Extra: array [0..15] of Byte; + end; + + TAcceptExBuffer = array[0..SizeOf(TAddrBuffer) * 2 - 1] of Byte; + + TPerIoBufUnion = record + case Integer of + 0: (DataBuf: WSABUF); + // 这个Buffer只用于AcceptEx保存终端地址数据,大小为2倍地址结构 + 1: (AcceptExBuffer: TAcceptExBuffer); + end; + + TIocpAction = (ioAccept, ioConnect, ioRead, ioWrite); + + PPerIoData = ^TPerIoData; + TPerIoData = record + Overlapped: TWSAOverlapped; + Buffer: TPerIoBufUnion; + Action: TIocpAction; + Socket: TSocket; + CrossData: ICrossData; + Callback: TCrossConnectionCallback; + end; + private + FIocpHandle: THandle; + FIoThreads: TArray; + FPerIoDataCount: NativeInt; + + function _NewIoData: PPerIoData; inline; + procedure _FreeIoData(const P: PPerIoData); inline; + + procedure _NewAccept(const AListen: ICrossListen); + function _NewReadZero(const AConnection: ICrossConnection): Boolean; + + procedure _HandleAccept(const APerIoData: PPerIoData); + procedure _HandleConnect(const APerIoData: PPerIoData); + procedure _HandleRead(const APerIoData: PPerIoData); + procedure _HandleWrite(const APerIoData: PPerIoData); + protected + function CreateListen(const AOwner: TCrossSocketBase; const AListenSocket: TSocket; + const AFamily, ASockType, AProtocol: Integer): ICrossListen; override; + function CreateConnection(const AOwner: TCrossSocketBase; const AClientSocket: TSocket; + const AConnectType: TConnectType; const AHost: string; + const AConnectCb: TCrossConnectionCallback): ICrossConnection; override; + + procedure StartLoop; override; + procedure StopLoop; override; + + procedure Listen(const AHost: string; const APort: Word; + const ACallback: TCrossListenCallback = nil); override; + + procedure Connect(const AHost: string; const APort, ALocalPort: Word; + const ACallback: TCrossConnectionCallback = nil); override; + + procedure Send(const AConnection: ICrossConnection; const ABuf: Pointer; + const ALen: Integer; const ACallback: TCrossConnectionCallback = nil); override; + + function ProcessIoEvent: Boolean; override; + end; + +implementation + +{ TIocpCrossSocket } + +function TIocpCrossSocket._NewIoData: PPerIoData; +begin + GetMem(Result, SizeOf(TPerIoData)); + FillChar(Result^, SizeOf(TPerIoData), 0); + System.Initialize(Result^); + + AtomicIncrement(FPerIoDataCount); +end; + +procedure TIocpCrossSocket._FreeIoData(const P: PPerIoData); +begin + if (P = nil) then Exit; + + System.Finalize(P^); + FreeMem(P, SizeOf(TPerIoData)); + + AtomicDecrement(FPerIoDataCount); +end; + +procedure TIocpCrossSocket._NewAccept(const AListen: ICrossListen); +var + LClientSocket: TSocket; + LPerIoData: PPerIoData; + LBytes: Cardinal; +begin + LClientSocket := WSASocket(AListen.Family, AListen.SockType, AListen.Protocol, + nil, 0, WSA_FLAG_OVERLAPPED); + if (LClientSocket = INVALID_SOCKET) then + begin + {$IFDEF DEBUG} + _LogLastOsError(Self.ClassName + '._NewAccept.WSASocket, %s', [AListen.DebugInfo]); + {$ENDIF} + Exit; + end; + + TSocketAPI.SetNonBlock(LClientSocket, True); + SetKeepAlive(LClientSocket); + + LPerIoData := _NewIoData; + LPerIoData.Action := ioAccept; + LPerIoData.Socket := LClientSocket; + LPerIoData.CrossData := AListen; + + if (not AcceptEx(AListen.Socket, LClientSocket, @LPerIoData.Buffer.AcceptExBuffer, 0, + SizeOf(TAddrBuffer), SizeOf(TAddrBuffer), LBytes, POverlapped(LPerIoData))) + and (WSAGetLastError <> WSA_IO_PENDING) then + begin + {$IFDEF DEBUG} + _LogLastOsError(Self.ClassName + '._NewAccept.AcceptEx, %s', [AListen.DebugInfo]); + {$ENDIF} + TSocketAPI.CloseSocket(LClientSocket); + _FreeIoData(LPerIoData); + end; +end; + +function TIocpCrossSocket._NewReadZero(const AConnection: ICrossConnection): Boolean; +var + LPerIoData: PPerIoData; + LBytes, LFlags: Cardinal; +begin + LPerIoData := _NewIoData; + LPerIoData.Buffer.DataBuf.buf := nil; + LPerIoData.Buffer.DataBuf.len := 0; + LPerIoData.Action := ioRead; + LPerIoData.Socket := AConnection.Socket; + LPerIoData.CrossData := AConnection; + + LFlags := 0; + LBytes := 0; + if (WSARecv(AConnection.Socket, @LPerIoData.Buffer.DataBuf, 1, LBytes, LFlags, PWSAOverlapped(LPerIoData), nil) < 0) + and (WSAGetLastError <> WSA_IO_PENDING) then + begin + {$IFDEF DEBUG} + _LogLastOsError(Self.ClassName + '._NewReadZero.WSARecv, %s', [AConnection.DebugInfo]); + {$ENDIF} + _FreeIoData(LPerIoData); + Exit(False); + end; + + Result := True; +end; + +procedure TIocpCrossSocket._HandleAccept(const APerIoData: PPerIoData); +var + LListen: ICrossListen; + LConnection: ICrossConnection; + LClientSocket, LListenSocket: TSocket; +begin + if (APerIoData.CrossData = nil) then Exit; + + LListen := APerIoData.CrossData as ICrossListen; + + _NewAccept(LListen); + + LClientSocket := APerIoData.Socket; + LListenSocket := LListen.Socket; + + // 不设置该参数, 会导致 getpeername 调用失败 + if (TSocketAPI.SetSockOpt(LClientSocket, SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, LListenSocket) < 0) then + begin + {$IFDEF DEBUG} + _LogLastOsError(Self.ClassName + '._HandleAccept.SetSockOpt'); + {$ENDIF} + TSocketAPI.CloseSocket(LClientSocket); + Exit; + end; + + if (CreateIoCompletionPort(LClientSocket, FIocpHandle, ULONG_PTR(LClientSocket), 0) = 0) then + begin + {$IFDEF DEBUG} + _LogLastOsError(Self.ClassName + '._HandleAccept.CreateIoCompletionPort'); + {$ENDIF} + TSocketAPI.CloseSocket(LClientSocket); + Exit; + end; + + LConnection := CreateConnection(Self, LClientSocket, ctAccept, ''); + TriggerConnecting(LConnection); + TriggerConnected(LConnection); + + if not _NewReadZero(LConnection) then + LConnection.Close; +end; + +procedure TIocpCrossSocket._HandleConnect(const APerIoData: PPerIoData); +var + LClientSocket: TSocket; + LConnection: ICrossConnection; + LSockErr: Integer; +begin + LClientSocket := APerIoData.Socket; + LConnection := APerIoData.CrossData as ICrossConnection; + + LSockErr := TSocketAPI.GetError(LClientSocket); + if (LSockErr <> 0) then + begin + if (LConnection <> nil) then + LConnection.LastNetError := LSockErr; + _LogLastOsError(Self.ClassName + '._HandleConnect.GetError'); + LConnection.Close; + Exit; + end; + + // 不设置该参数, 会导致 getpeername 调用失败 + if (TSocketAPI.SetSockOpt(LClientSocket, SOL_SOCKET, + SO_UPDATE_CONNECT_CONTEXT, 1) < 0) then + begin + if (LConnection <> nil) then + LConnection.LastNetError := WSAGetLastError; + _LogLastOsError(Self.ClassName + '._HandleConnect.SetSockOpt'); + LConnection.Close; + Exit; + end; + + TriggerConnected(LConnection); + + if not _NewReadZero(LConnection) then + LConnection.Close; +end; + +procedure TIocpCrossSocket._HandleRead(const APerIoData: PPerIoData); +var + LConnection: ICrossConnection; + LRcvd, LError: Integer; +begin + if (APerIoData.CrossData = nil) then + begin + if Assigned(APerIoData.Callback) then + APerIoData.Callback(nil, False); + Exit; + end; + + LConnection := APerIoData.CrossData as ICrossConnection; + + while True do + begin + LRcvd := TSocketAPI.Recv(LConnection.Socket, FRecvBuf[0], RCV_BUF_SIZE); + + // 对方主动断开连接 + if (LRcvd = 0) then + begin + _Log(Self.ClassName + '.Recv=0(Close), %s', [LConnection.DebugInfo]); + LConnection.Close; + Exit; + end; + + if (LRcvd < 0) then + begin + LError := GetLastError; + + // 被系统信号中断, 可以重新recv + if (LError = WSAEINTR) then + Continue + // 接收缓冲区中数据已经被取完了 + else if (LError = WSAEWOULDBLOCK) or (LError = WSAEINPROGRESS) then + Break + // 接收出错 + else + begin + _LogLastOsError(Self.ClassName + '.Recv<0, %s', [LConnection.DebugInfo]); + LConnection.Close; + Exit; + end; + end; + + {$IFDEF DEBUG} + _Log('[%s]thread%d, _HandleRead.TriggerReceived准备执行, LRcvd=%d', [ + Self.ClassName, TThread.Current.ThreadID, LRcvd + ]); + {$ENDIF} + TriggerReceived(LConnection, @FRecvBuf[0], LRcvd); + {$IFDEF DEBUG} + _Log('[%s]thread%d, _HandleRead.TriggerReceived执行完成, LRcvd=%d', [ + Self.ClassName, TThread.Current.ThreadID, LRcvd + ]); + {$ENDIF} + + // 回调中可能关闭了连接, 需要检查状态 + if LConnection.IsClosed then Exit; + + if (LRcvd < RCV_BUF_SIZE) then Break; + end; + + if not _NewReadZero(LConnection) then + LConnection.Close; +end; + +procedure TIocpCrossSocket._HandleWrite(const APerIoData: PPerIoData); +begin + if Assigned(APerIoData.Callback) then + APerIoData.Callback(APerIoData.CrossData as ICrossConnection, True); +end; + +procedure TIocpCrossSocket.StartLoop; +var + I: Integer; +begin + if (FIoThreads <> nil) then Exit; + + FIocpHandle := CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0); + SetLength(FIoThreads, GetIoThreads); + for I := 0 to Length(FIoThreads) - 1 do + FIoThreads[I] := TIoEventThread.Create(Self); +end; + +procedure TIocpCrossSocket.StopLoop; + + // IO 线程在收到 SHUTDOWN_FLAG 标记之后就会退出 + // 而这时候有可能还有部分操作未完成, 其对应的 PerIoData 结构就无法释放 + // 只需要在这里再次接收完成端口的消息, 就能等到这部分未完成的操作超时或失败 + // 从而释放其对应的 PerIoData 结构 + // + // 超时仍未清零时: 输出错误日志诊断遗留, 仍关闭 IOCP handle (避免 OS 句柄泄漏). + // 因 IO 线程已退出, 此处与 _HandleXxx 路径互斥, 无 PerIoData 重复释放风险. + procedure _FreeMissingPerIoDatas; + const + DEFAULT_DRAIN_TIMEOUT_MS = 3000; + POLL_STEP_MS = 10; + var + LBytes: Cardinal; + LSocket: TSocket; + LPerIoData: PPerIoData; + LConnection: ICrossConnection; + LMaxWait, LRemaining: Integer; + begin + LMaxWait := DEFAULT_DRAIN_TIMEOUT_MS; + LRemaining := LMaxWait; + + while (AtomicCmpExchange(FPerIoDataCount, 0, 0) > 0) and (LRemaining > 0) do + begin + GetQueuedCompletionStatus(FIocpHandle, LBytes, ULONG_PTR(LSocket), POverlapped(LPerIoData), POLL_STEP_MS); + + if (LPerIoData = nil) then + begin + Dec(LRemaining, POLL_STEP_MS); + Continue; + end; + + try + TSocketAPI.CloseSocket(LPerIoData.Socket); + + if Assigned(LPerIoData.Callback) then + begin + if (LPerIoData.CrossData <> nil) + and (LPerIoData.CrossData is TIocpConnection) then + LConnection := LPerIoData.CrossData as ICrossConnection + else + LConnection := nil; + + LPerIoData.Callback(LConnection, False); + end; + + if (LPerIoData.CrossData <> nil) then + LPerIoData.CrossData.Close; + finally + _FreeIoData(LPerIoData); + end; + end; + + // 超时仍未清零: 不静默, 强制 _Log (受 CrossSocketLogEnabled 全局开关控制) + if (AtomicCmpExchange(FPerIoDataCount, 0, 0) > 0) then + _Log('[%s][StopLoop] WARNING: drain 超时 %dms, 仍有 %d 个 PerIoData 未回收, 即将关闭 IOCP handle', + [Self.ClassName, LMaxWait, AtomicCmpExchange(FPerIoDataCount, 0, 0)]); + end; + +var + I: Integer; + LCurrentThreadID: TThreadID; +begin + if (FIoThreads = nil) then Exit; + + {$IFDEF DEBUG} + _Log('[%s][StopLoop] 开始停止, 线程数=%d', [ + Self.ClassName, Length(FIoThreads)]); + {$ENDIF} + CloseAll; + + {$IFDEF DEBUG} + _Log('[%s][StopLoop] 等待连接关闭, ListensCount=%d, ConnectionsCount=%d', [ + Self.ClassName, ListensCount, ConnectionsCount + ]); + {$ENDIF} + while (ListensCount > 0) or (ConnectionsCount > 0) do Sleep(1); + + {$IFDEF DEBUG} + _Log('[%s][StopLoop] 发送 SHUTDOWN_FLAG 唤醒所有线程', [ + Self.ClassName + ]); + {$ENDIF} + for I := 0 to Length(FIoThreads) - 1 do + PostQueuedCompletionStatus(FIocpHandle, 0, 0, POverlapped(SHUTDOWN_FLAG)); + + LCurrentThreadID := GetCurrentThreadId; + for I := 0 to Length(FIoThreads) - 1 do + begin + if (FIoThreads[I].ThreadID = LCurrentThreadID) then + raise ECrossSocket.Create('不能在IO线程中执行StopLoop!'); + + {$IFDEF DEBUG} + _Log('[%s]thread%d[StopLoop] 等待线程 %d 退出', [ + Self.ClassName, FIoThreads[I].ThreadID, I + ]); + {$ENDIF} + FIoThreads[I].WaitFor; + {$IFDEF DEBUG} + _Log('[%s]thread%d[StopLoop] 线程 %d 已退出', [ + Self.ClassName, FIoThreads[I].ThreadID, I]); + {$ENDIF} + FreeAndNil(FIoThreads[I]); + end; + FIoThreads := nil; + + _FreeMissingPerIoDatas; + CloseHandle(FIocpHandle); +end; + +procedure TIocpCrossSocket.Connect(const AHost: string; + const APort, ALocalPort: Word; const ACallback: TCrossConnectionCallback); +var + LHints: TRawAddrInfo; + P, LAddrInfo: PRawAddrInfo; + LSocket: TSocket; + + procedure _Failed1; + begin + if Assigned(ACallback) then + ACallback(nil, False); + end; + + function _Connect(ASocket: TSocket; AAddr: PRawAddrInfo): Boolean; + procedure _Failed2; + begin + if Assigned(ACallback) then + ACallback(nil, False); + TSocketAPI.CloseSocket(ASocket); + end; + var + LSockAddr: TRawSockAddrIn; + LPerIoData: PPerIoData; + LBytes: Cardinal; + LConnection: ICrossConnection; + begin + FillChar(LSockAddr, SizeOf(TRawSockAddrIn), 0); + LSockAddr.AddrLen := AAddr.ai_addrlen; + if (AAddr.ai_family = AF_INET6) then + begin + LSockAddr.Addr6.sin6_family := AAddr.ai_family; + LSockAddr.Addr6.sin6_port := htons(ALocalPort); + end else + begin + LSockAddr.Addr.sin_family := AAddr.ai_family; + LSockAddr.Addr.sin_port := htons(ALocalPort); + end; + if (TSocketAPI.Bind(ASocket, @LSockAddr.Addr, LSockAddr.AddrLen) < 0) then + begin + _LogLastOsError(Self.ClassName + '._Connect.Bind'); + _Failed2; + Exit(False); + end; + + if (CreateIoCompletionPort(ASocket, FIocpHandle, ULONG_PTR(ASocket), 0) = 0) then + begin + _LogLastOsError(Self.ClassName + '._Connect.CreateIoCompletionPort'); + _Failed2; + Exit(False); + end; + + LConnection := CreateConnection(Self, ASocket, ctConnect, AHost, ACallback); + TriggerConnecting(LConnection); + + LPerIoData := _NewIoData; + LPerIoData.Action := ioConnect; + LPerIoData.CrossData := LConnection; + LPerIoData.Socket := ASocket; + LPerIoData.Callback := nil; + if not ConnectEx(ASocket, AAddr.ai_addr, AAddr.ai_addrlen, nil, 0, LBytes, PWSAOverlapped(LPerIoData)) and + (WSAGetLastError <> WSA_IO_PENDING) then + begin + // 先保存 WSAGetLastError 再记录日志, 避免后续 API 调用改写 lastError + if (LConnection <> nil) then + LConnection.LastNetError := WSAGetLastError; + _LogLastOsError(Self.ClassName + '._Connect.ConnectEx'); + _FreeIoData(LPerIoData); + LConnection.Close; + Exit(False); + end; + + Result := True; + end; + +begin + FillChar(LHints, SizeOf(TRawAddrInfo), 0); + LHints.ai_family := AF_UNSPEC; + LHints.ai_socktype := SOCK_STREAM; + LHints.ai_protocol := IPPROTO_TCP; + LAddrInfo := TSocketAPI.GetAddrInfo(AHost, APort, LHints); + if (LAddrInfo = nil) then + begin + _LogLastOsError(Self.ClassName + '.Connect.GetAddrInfo'); + _Failed1; + Exit; + end; + + P := LAddrInfo; + try + while (LAddrInfo <> nil) do + begin + LSocket := WSASocket(LAddrInfo.ai_family, LAddrInfo.ai_socktype, + LAddrInfo.ai_protocol, nil, 0, WSA_FLAG_OVERLAPPED); + if (LSocket = INVALID_SOCKET) then + begin + _LogLastOsError(Self.ClassName + '.Connect.WSASocket'); + _Failed1; + Exit; + end; + + TSocketAPI.SetNonBlock(LSocket, True); + SetKeepAlive(LSocket); + + {$IFDEF DEBUG} + _Log('TIocpCrossSocket.Connect.WSASocket=%d', [LSocket]); + {$ENDIF} + + if _Connect(LSocket, LAddrInfo) then Exit; + + LAddrInfo := PRawAddrInfo(LAddrInfo.ai_next); + end; + finally + TSocketAPI.FreeAddrInfo(P); + end; + + _LogLastOsError(Self.ClassName + '.Connect.Unknown'); + _Failed1; +end; + +function TIocpCrossSocket.CreateConnection(const AOwner: TCrossSocketBase; + const AClientSocket: TSocket; const AConnectType: TConnectType; + const AHost: string; const AConnectCb: TCrossConnectionCallback): ICrossConnection; +begin + Result := TIocpConnection.Create(AOwner, AClientSocket, AConnectType, AHost, AConnectCb); +end; + +function TIocpCrossSocket.CreateListen(const AOwner: TCrossSocketBase; + const AListenSocket: TSocket; const AFamily, ASockType, AProtocol: Integer): ICrossListen; +begin + Result := TIocpListen.Create(AOwner, AListenSocket, AFamily, ASockType, AProtocol); +end; + +procedure TIocpCrossSocket.Listen(const AHost: string; const APort: Word; + const ACallback: TCrossListenCallback); +var + LHints: TRawAddrInfo; + P, LAddrInfo: PRawAddrInfo; + LListenSocket: TSocket; + LListen: ICrossListen; + I: Integer; + LListenSuccess: Boolean; + + procedure _Failed; + begin + if not LListenSuccess and Assigned(ACallback) then + ACallback(LListen, False); + + if (LListen <> nil) then + LListen.Close + else if (LListenSocket <> INVALID_SOCKET) then + TSocketAPI.CloseSocket(LListenSocket); + end; + + procedure _Success; + begin + TriggerListened(LListen); + + if Assigned(ACallback) then + ACallback(LListen, True); + end; +begin + LListenSuccess := False; + FillChar(LHints, SizeOf(TRawAddrInfo), 0); + + LHints.ai_flags := AI_PASSIVE; + LHints.ai_family := AF_UNSPEC; + LHints.ai_socktype := SOCK_STREAM; + LHints.ai_protocol := IPPROTO_TCP; + LAddrInfo := TSocketAPI.GetAddrInfo(AHost, APort, LHints); + if (LAddrInfo = nil) then + begin + {$IFDEF DEBUG} + _LogLastOsError(Self.ClassName + '.Listen.GetAddrInfo'); + {$ENDIF} + _Failed; + Exit; + end; + + P := LAddrInfo; + try + while (LAddrInfo <> nil) do + begin + LListen := nil; + LListenSocket := WSASocket(LAddrInfo.ai_family, LAddrInfo.ai_socktype, + LAddrInfo.ai_protocol, nil, 0, WSA_FLAG_OVERLAPPED); + if (LListenSocket = INVALID_SOCKET) then + begin + {$IFDEF DEBUG} + _LogLastOsError(Self.ClassName + '.Listen.WSASocket'); + {$ENDIF} + _Failed; + Exit; + end; + + TSocketAPI.SetNonBlock(LListenSocket, True); + TSocketAPI.SetReUseAddr(LListenSocket, True); + + if (LAddrInfo.ai_family = AF_INET6) then + TSocketAPI.SetSockOpt(LListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, 1); + + if (TSocketAPI.Bind(LListenSocket, LAddrInfo.ai_addr, LAddrInfo.ai_addrlen) < 0) then + begin + {$IFDEF DEBUG} + _LogLastOsError(Self.ClassName + '.Listen.Bind'); + {$ENDIF} + _Failed; + Exit; + end; + + if (TSocketAPI.Listen(LListenSocket) < 0) then + begin + {$IFDEF DEBUG} + _LogLastOsError(Self.ClassName + '.Listen.Listen'); + {$ENDIF} + _Failed; + Exit; + end; + + LListen := CreateListen(Self, LListenSocket, LAddrInfo.ai_family, + LAddrInfo.ai_socktype, LAddrInfo.ai_protocol); + + if (CreateIoCompletionPort(LListenSocket, FIocpHandle, ULONG_PTR(LListenSocket), 0) = 0) then + begin + {$IFDEF DEBUG} + _LogLastOsError(Self.ClassName + '.Listen.CreateIoCompletionPort'); + {$ENDIF} + _Failed; + Exit; + end; + + // 给每个IO线程投递一个AcceptEx + for I := 1 to GetIoThreads do + _NewAccept(LListen); + + LListenSuccess := True; + _Success; + + // 如果端口传入0,让所有地址统一用首个分配到的端口 + if (APort = 0) and (LAddrInfo.ai_next <> nil) then + LAddrInfo.ai_next.ai_addr.sin_port := htons(LListen.LocalPort); + + LAddrInfo := PRawAddrInfo(LAddrInfo.ai_next); + end; + finally + TSocketAPI.FreeAddrInfo(P); + end; +end; + +procedure TIocpCrossSocket.Send(const AConnection: ICrossConnection; + const ABuf: Pointer; const ALen: Integer; const ACallback: TCrossConnectionCallback); +var + LPerIoData: PPerIoData; + LBytes, LFlags: Cardinal; +begin + LPerIoData := _NewIoData; + LPerIoData.Buffer.DataBuf.buf := ABuf; + LPerIoData.Buffer.DataBuf.len := ALen; + LPerIoData.Action := ioWrite; + LPerIoData.Socket := AConnection.Socket; + LPerIoData.CrossData := AConnection; + LPerIoData.Callback := ACallback; + + LFlags := 0; + LBytes := 0; + // WSASend 不会出现部分发送的情况, 要么全部失败, 要么全部成功 + // 所以不需要像 kqueue 或 epoll 中调用 send 那样调用完之后还得检查实际发送了多少 + // 唯一需要注意的是: WSASend 会将待发送的数据锁定到非页面内存, 非页面内存资源 + // 是非常紧张的, 所以不要无节制的调用 WSASend, 最好通过回调发送完一批数据再继 + // 续发送下一批 + if (WSASend(AConnection.Socket, @LPerIoData.Buffer.DataBuf, 1, LBytes, LFlags, PWSAOverlapped(LPerIoData), nil) < 0) + and (WSAGetLastError <> WSA_IO_PENDING) then + begin + {$IFDEF DEBUG} + _LogLastOsError(Self.ClassName + '.WSASend, %s', [AConnection.DebugInfo]); + {$ENDIF} + + // 出错多半是 WSAENOBUFS, 也就是投递的 WSASend 过多, 来不及发送 + // 导致非页面内存资源全部被锁定, 要避免这种情况必须上层发送逻辑 + // 保证不能无节制的调用Send发送大量数据, 最好发送完一个再继续下 + // 一个, 本函数提供了发送结果的回调函数, 在回调函数报告发送成功 + // 之后就可以继续下一块数据发送了 + _FreeIoData(LPerIoData); + + if Assigned(ACallback) then + ACallback(AConnection, False); + + if Assigned(AConnection) then + AConnection.Close; + end; +end; + +function TIocpCrossSocket.ProcessIoEvent: Boolean; + procedure _ReleasePerIoData(const APerIoData: PPerIoData; const AShutdown: Boolean); + var + LConnection: ICrossConnection; + begin + try + if (APerIoData.CrossData <> nil) then + begin + // AcceptEx虽然成功, 但是Socket句柄耗尽了, 再次投递AcceptEx + if (APerIoData.Action = ioAccept) then + begin + // 照理说能执行到这里, 说明Socket分配失败了 + // 但是为了以防万一, 这里还是判断一下并释放掉无效的Socket句柄 + if (APerIoData.Socket <> 0) then + TSocketAPI.CloseSocket(APerIoData.Socket); + + // 关闭监听后会触发该错误, 这种情况不应该继续投递 + if not AShutdown then + begin + _Log('[%s]thread%d, _NewAccept', [Self.ClassName, TThread.Current.ThreadID]); + _NewAccept(APerIoData.CrossData as ICrossListen); + end; + end else + begin + {$IFDEF DEBUG} + _LogLastOsError( + Format(Self.ClassName + '.ProcessIoEvent.GetQueuedCompletionStatus.CrossDataNotNil(socket=%d, action=%d)', + [APerIoData.Socket, Ord(APerIoData.Action)]) + ); + {$ENDIF} + if Assigned(APerIoData.Callback) then + begin + if (APerIoData.CrossData is TIocpConnection) then + LConnection := APerIoData.CrossData as ICrossConnection + else + LConnection := nil; + + APerIoData.Callback(LConnection, False); + end; + + APerIoData.CrossData.Close; + end; + end else + begin + {$IFDEF DEBUG} + _LogLastOsError( + Format(Self.ClassName + '.ProcessIoEvent.GetQueuedCompletionStatus.CrossDataIsNil(socket=%d, action=%d)', + [APerIoData.Socket, Ord(APerIoData.Action)]) + ); + {$ENDIF} + if Assigned(APerIoData.Callback) then + APerIoData.Callback(nil, False); + + if (APerIoData.Socket <> 0) then + TSocketAPI.CloseSocket(APerIoData.Socket); + end; + finally + _FreeIoData(APerIoData); + end; + end; +var + LBytes: Cardinal; + LSocket: TSocket; + LPerIoData: PPerIoData; + LErrNo: Cardinal; + LIocpClosed: Boolean; +begin + if not GetQueuedCompletionStatus(FIocpHandle, LBytes, ULONG_PTR(LSocket), POverlapped(LPerIoData), INFINITE) then + begin + // ERROR_INVALID_HANDLE, 6, IOCP句柄被关闭 + // ERROR_ABANDONED_WAIT_0, $02DF, IOCP句柄被关闭 + // WSA_OPERATION_ABORTED, 995, 监听端口被关闭, 由于线程退出或应用程序请求,已中止 I/O 操作。 + // WSAENOTSOCK, 10038, 在一个非套接字上尝试了一个操作。 + // WSAESHUTDOWN, 10058, 套接字已关闭 + // ERROR_NETNAME_DELETED, 64, 指定的网络名不再可用 + // ERROR_CONNECTION_REFUSED, 1225, 远程计算机拒绝网络连接。 + LErrNo := GetLastError; + + // 完成端口被关闭时可能会触发 ERROR_INVALID_HANDLE 和 ERROR_ABANDONED_WAIT_0 + // 监听端口被关闭时会触发 WSA_OPERATION_ABORTED + LIocpClosed := (LErrNo = ERROR_INVALID_HANDLE) + or (LErrNo = ERROR_ABANDONED_WAIT_0) + or (LErrNo = WSA_OPERATION_ABORTED); + {$IFDEF DEBUG} + _Log('[%s]thread%d, GetQueuedCompletionStatus:%d, %s', [ + Self.ClassName, TThread.Current.ThreadID, LErrNo, SysErrorMessage(LErrNo) + ]); + {$ENDIF} + + // 出错了, 并且完成数据也都是空的, + // 这种情况即便重试, 应该也会继续出错, 最好立即终止IO线程 + if (LPerIoData = nil) then Exit(False); + + // 出错了, 回收资源 + _ReleasePerIoData(LPerIoData, LIocpClosed); + + // 出错了, 但是完成数据不是空的, 需要重试 + Exit(not LIocpClosed); + end; + + // 主动调用了 StopLoop + if (LBytes = 0) and (ULONG_PTR(LPerIoData) = SHUTDOWN_FLAG) then Exit(False); + + // 由于未知原因未获取到完成数据, 但是返回的错误代码又是正常 + // 这种情况需要进行重试(返回True之后IO线程会再次调用ProcessIoEvent) + if (LPerIoData = nil) then Exit(True); + + try + {$IFDEF DEBUG} + _Log('[%s]thread%d, 准备处理IOCP事件 PerIoData=%p, Action=%d, Bytes=%d', [ + Self.ClassName, TThread.Current.ThreadID, Pointer(LPerIoData), Ord(LPerIoData.Action), LBytes + ]); + {$ENDIF} + case LPerIoData.Action of + ioAccept : _HandleAccept(LPerIoData); + ioConnect : _HandleConnect(LPerIoData); + ioRead : _HandleRead(LPerIoData); + ioWrite : _HandleWrite(LPerIoData); + end; + {$IFDEF DEBUG} + _Log('[%s]thread%d, 处理IOCP事件完成 PerIoData=%p, Action=%d, Bytes=%d', [ + Self.ClassName, TThread.Current.ThreadID, Pointer(LPerIoData), Ord(LPerIoData.Action), LBytes + ]); + {$ENDIF} + finally + _FreeIoData(LPerIoData); + end; + + Result := True; +end; + +end. diff --git a/Net/Net.CrossSocket.Kqueue.pas b/Net/Net.CrossSocket.Kqueue.pas index c0f76a7..9c046b5 100644 --- a/Net/Net.CrossSocket.Kqueue.pas +++ b/Net/Net.CrossSocket.Kqueue.pas @@ -1,1112 +1,1112 @@ -{******************************************************************************} -{ } -{ Delphi cross platform socket library } -{ } -{ Copyright (c) 2017 WiNDDRiVER(soulawing@gmail.com) } -{ } -{ Homepage: https://github.com/winddriver/Delphi-Cross-Socket } -{ } -{******************************************************************************} -unit Net.CrossSocket.Kqueue; - -{$I zLib.inc} - -interface - -uses - SysUtils, - Classes, - Generics.Collections, - - {$IFDEF DELPHI} - Posix.SysSocket, - Posix.NetinetIn, - Posix.UniStd, - Posix.NetDB, - Posix.Pthread, - Posix.ArpaInet, - Posix.Errno, - {$ELSE} - baseunix, - unix, - sockets, - netdb, - DTF.RTL, - {$ENDIF} - - BSD.kqueue, - - Net.SocketAPI, - Net.CrossSocket.Base, - - Utils.SyncObjs, - Utils.ArrayUtils; - -{$IFDEF BSD} -const - IPV6_V6ONLY = 27; -{$ENDIF} - -type - {$IFDEF FPC} - TPipeDescriptors = {packed} record - ReadDes: Integer; - WriteDes: Integer; - end; - PPipeDescriptors = ^TPipeDescriptors; - {$ENDIF} - - TIoEvent = (ieRead, ieWrite); - TIoEvents = set of TIoEvent; - - TKqueueListen = class(TCrossListenBase) - private - FKqueueHandle: Integer; - FIoEvents: TIoEvents; - - function _ReadEnabled: Boolean; inline; - function _UpdateIoEvent(const AIoEvents: TIoEvents): Boolean; - public - constructor Create(const AOwner: TCrossSocketBase; const AListenSocket: TSocket; - const AFamily, ASockType, AProtocol: Integer); override; - end; - - PSendItem = ^TSendItem; - TSendItem = packed record - Data: PByte; - Size: Integer; - Callback: TCrossConnectionCallback; - end; - - TSendQueue = class(TList) - protected - procedure Notify(const Value: PSendItem; Action: TCollectionNotification); override; - end; - - TKqueueConnection = class(TCrossConnectionBase) - private - FKqueueHandle: Integer; - FSendQueue: TSendQueue; - FKqLock: ILock; - FInPending, FOutPending: Integer; - - function _UpdateIoEvent(const AIoEvents: TIoEvents): Boolean; - - procedure _ClearSendQueue; - - procedure _KqLock; inline; - procedure _KqUnlock; inline; - protected - procedure InternalClose; override; - public - constructor Create(const AOwner: TCrossSocketBase; const AClientSocket: TSocket; - const AConnectType: TConnectType; const AHost: string; - const AConnectCb: TCrossConnectionCallback); override; - destructor Destroy; override; - end; - - // KQUEUE 与 EPOLL 队列的差异 - // KQUEUE的队列中, 一个Socket句柄可以有多条记录, 每个事件一条, - // 这一点和 EPOLL 不一样, EPOLL中每个Socket句柄只会有一条记录 - // 要监测多个事件时, 只需要将多个事件做位运算加在一起调用 epoll_ctl 即可 - // - // EV_DISPATCH 和 EV_CLEAR 是令 kqueue 支持线程池的关键 - // 该参数组合可以令事件触发后就立即被禁用, 避免让同一个Socket的同一个事件 - // 同时被多个工作线程触发 - // - // EVFILT_READ - // 用于监测接收缓冲区是否可读了 - // 对于监听Socket来说,表示有新的连接到来 - // 对于已连接的Socket来说,表示有数据到达接收缓冲区 - // 为了支持线程池, 必须带上参数 EV_CLEAR or EV_DISPATCH - // 该参数组合表示, 该事件一旦触发立即清除该事件的状态并禁用它 - // 处理完连接或者读取数据之后再投递一次 EVFILT_READ, 带上参数 - // EV_ENABLE or EV_CLEAR or EV_DISPATCH, 让事件继续监测 - // - // EVFILT_WRITE - // 用于监测发送缓冲区是否可写了 - // 对于Connect中的Socket,投递EV_ENABLE,等到事件触发时表示连接已建立 - // 对于已连接的Socket,在Send之后立即投递EVFILT_WRITE,等到事件触发时表示发送完成 - // 对于EVFILT_WRITE都应该带上EV_ONESHOT参数,让该事件只会被触发一次 - // 否则,只要发送缓冲区是空的,该事件就会一直触发,这并没有什么意义 - // 我们只需要用EVFILT_WRITE去监测连接或者发送是否成功 - // - // KQUEUE 发送数据 - // 最好的做法是将实际发送数据的动作放到 EVFILT_WRITE 触发时进行, 该 - // 事件触发表明 Socket 发送缓存有空闲空间了。IOCP可以直接将待发送的数据及 - // 回调同时扔给 WSASend, 发送完成后去调用回调即可; KQUEUE 机制不一样, 在 KQUEUE - // 中没有类似 WSASend 的函数, 只能自行维护发送数据及回调的队列 - // EPOLL要支持多线程并发发送数据必须创建发送队列, 否则同一个 Socket 的并发发送 - // 极有可能有一部分会被其它发送覆盖掉 - // - // 由于 KQUEUE 中每个套接字在队列中的 EV_WRITE 和 EV_READ 是分开的两条记录 - // 所以修改套接字的监听事件时不会互相覆盖, 也就是说每个事件都会对应到一次 - // 触发, 这样就可以方便的使用接口的引用计数机制保持连接的有效性, 也不会出现 - // 内存泄漏 - TKqueueCrossSocket = class(TCrossSocketBase) - private const - MAX_EVENT_COUNT = 2048; - SHUTDOWN_FLAG = Pointer(-1); - private class threadvar - FEventList: array [0..MAX_EVENT_COUNT-1] of TKEvent; - private - FKqueueHandle: Integer; - FIoThreads: TArray; - FIdleHandle: THandle; - FIdleLock: ILock; - FStopHandle: TPipeDescriptors; - - // 利用 pipe 唤醒并退出IO线程 - procedure _OpenStopHandle; inline; - procedure _PostStopCommand; inline; - procedure _CloseStopHandle; inline; - - procedure _OpenIdleHandle; inline; - procedure _CloseIdleHandle; inline; - - // 在向一个已经关闭的套接字发送数据时系统会直接抛出EPIPE异常导致程序非正常退出 - // LINUX下可以在send时带上MSG_NOSIGNAL参数就能避免这种情况的发生 - // OSX中可以通过设置套接字的SO_NOSIGPIPE参数达到同样的目的 - procedure _SetNoSigPipe(ASocket: TSocket); inline; - - procedure _HandleAccept(const AListen: ICrossListen); - procedure _HandleConnect(const AConnection: ICrossConnection); - procedure _HandleRead(const AConnection: ICrossConnection); - procedure _HandleWrite(const AConnection: ICrossConnection); - protected - function CreateConnection(const AOwner: TCrossSocketBase; const AClientSocket: TSocket; - const AConnectType: TConnectType; const AHost: string; - const AConnectCb: TCrossConnectionCallback): ICrossConnection; override; - function CreateListen(const AOwner: TCrossSocketBase; const AListenSocket: TSocket; - const AFamily, ASockType, AProtocol: Integer): ICrossListen; override; - - procedure StartLoop; override; - procedure StopLoop; override; - - procedure Listen(const AHost: string; const APort: Word; - const ACallback: TCrossListenCallback = nil); override; - - procedure Connect(const AHost: string; const APort, ALocalPort: Word; - const ACallback: TCrossConnectionCallback = nil); override; - - procedure Send(const AConnection: ICrossConnection; const ABuf: Pointer; - const ALen: Integer; const ACallback: TCrossConnectionCallback = nil); override; - - function ProcessIoEvent: Boolean; override; - public - constructor Create(const AIoThreads: Integer); override; - destructor Destroy; override; - end; - -implementation - -{$IFDEF FPC} -function pipe(var PipeDes: TPipeDescriptors): Integer; cdecl; external 'c' name 'pipe'; -function __read(Handle: Integer; Buffer: Pointer; Count: size_t): ssize_t; cdecl; external 'c' name 'read'; -function __write(Handle: Integer; Buffer: Pointer; Count: size_t): ssize_t; cdecl; external 'c' name 'write'; -function __close(Handle: Integer): Integer; cdecl; external 'c' name 'close'; -{$ENDIF} - -{ TKqueueListen } - -constructor TKqueueListen.Create(const AOwner: TCrossSocketBase; - const AListenSocket: TSocket; const AFamily, ASockType, AProtocol: Integer); -begin - inherited; - FKqueueHandle := TKqueueCrossSocket(AOwner).FKqueueHandle; -end; - -function TKqueueListen._ReadEnabled: Boolean; -begin - Result := (ieRead in FIoEvents); -end; - -function TKqueueListen._UpdateIoEvent(const AIoEvents: TIoEvents): Boolean; -var - LCrossData: Pointer; - LEvents: array [0..1] of TKEvent; - N: Integer; -begin - FIoEvents := AIoEvents; - - if (FIoEvents = []) or IsClosed then Exit(False); - - LCrossData := Pointer(Self); - N := 0; - - if _ReadEnabled then - begin - EV_SET(@LEvents[N], Socket, EVFILT_READ, - EV_ADD or EV_ONESHOT or EV_CLEAR or EV_DISPATCH, 0, 0, Pointer(LCrossData)); - - Inc(N); - end; - - if (N <= 0) then Exit(False); - - Result := (kevent(FKqueueHandle, @LEvents, N, nil, 0, nil) >= 0); - - {$IFDEF DEBUG} - if not Result then - _LogLastOsError('listen kevent, %s', [Socket, Self.DebugInfo]); - {$ENDIF} -end; - -{ TSendQueue } - -procedure TSendQueue.Notify(const Value: PSendItem; - Action: TCollectionNotification); -begin - inherited; - - if (Action = TCollectionNotification.cnRemoved) then - begin - if (Value <> nil) then - begin - Value.Callback := nil; - System.Dispose(Value); - end; - end; -end; - -{ TKqueueConnection } - -constructor TKqueueConnection.Create(const AOwner: TCrossSocketBase; - const AClientSocket: TSocket; const AConnectType: TConnectType; - const AHost: string; const AConnectCb: TCrossConnectionCallback); -begin - inherited Create(AOwner, AClientSocket, AConnectType, AHost, AConnectCb); - - FKqLock := TLock.Create; - FSendQueue := TSendQueue.Create; - - FKqueueHandle := TKqueueCrossSocket(AOwner).FKqueueHandle; -end; - -destructor TKqueueConnection.Destroy; -begin - _ClearSendQueue; - FreeAndNil(FSendQueue); - - inherited; -end; - -procedure TKqueueConnection.InternalClose; -var - LEvent: TKEvent; -begin - _ClearSendQueue; - - // 从 kqueue 中删除该 socket 的所有事件,防止 fd 重用后触发错误回调 - EV_SET(@LEvent, Socket, EVFILT_READ, EV_DELETE, 0, 0, nil); - kevent(FKqueueHandle, @LEvent, 1, nil, 0, nil); - EV_SET(@LEvent, Socket, EVFILT_WRITE, EV_DELETE, 0, 0, nil); - kevent(FKqueueHandle, @LEvent, 1, nil, 0, nil); - - inherited InternalClose; -end; - -procedure TKqueueConnection._ClearSendQueue; -var - LConnection: ICrossConnection; - LSendItem: PSendItem; - LCallbacks: TArray; - LCallback: TCrossConnectionCallback; -begin - LConnection := Self; - LCallbacks := []; - - _KqLock; - try - // 连接释放时, 先收集所有回调, 然后在锁外执行 - // 避免回调中再次发送数据导致死锁 - if (FSendQueue <> nil) and (FSendQueue.Count > 0) then - begin - for LSendItem in FSendQueue do - if Assigned(LSendItem.Callback) then - TArrayUtils.Append(LCallbacks, LSendItem.Callback); - - FSendQueue.Clear; - end; - finally - _KqUnlock; - end; - - // 在锁外执行回调, 告知发送失败 - for LCallback in LCallbacks do - LCallback(LConnection, False); -end; - -procedure TKqueueConnection._KqLock; -begin - FKqLock.Enter; -end; - -procedure TKqueueConnection._KqUnlock; -begin - FKqLock.Leave; -end; - -function TKqueueConnection._UpdateIoEvent(const AIoEvents: TIoEvents): Boolean; -var - LCrossData: Pointer; - LEvents: array [0..1] of TKEvent; - N: Integer; -begin - if (AIoEvents = []) or IsClosed then Exit(False); - - LCrossData := Pointer(Self); - N := 0; - - // kqueue中同一个套接字的EVFILT_READ和EVFILT_WRITE事件在队列中会有两条记录 - // 并且可能会在不同的线程中同时被触发, 如果其中一个线程关闭了连接, 在没有 - // 引用计数保护的情况下, 就会导致连接对象被释放, 另一个线程再访问连接对象 - // 就会引起异常, 这里为了保证连接对象的有效性, 在添加事件时手动增加连接对象 - // 的引用计数, 到事件触发时再减少引用计数 - // 注意关闭连接一定要使用shutdown而不能直接close, 否则无法触发kqueue事件, - // 导致引用计数无法回收 - - if (ieRead in AIoEvents) and (AtomicCmpExchange(FInPending, 0, 0) = 0) then - begin - Self._AddRef; - - EV_SET(@LEvents[N], Socket, EVFILT_READ, - EV_ADD or EV_ONESHOT or EV_CLEAR or EV_DISPATCH, 0, 0, Pointer(LCrossData)); - - Inc(N); - end; - - if (ieWrite in AIoEvents) and (AtomicCmpExchange(FOutPending, 0, 0) = 0) then - begin - Self._AddRef; - - EV_SET(@LEvents[N], Socket, EVFILT_WRITE, - EV_ADD or EV_ONESHOT or EV_CLEAR or EV_DISPATCH, 0, 0, Pointer(LCrossData)); - - Inc(N); - end; - - if (N <= 0) then Exit(False); - - Result := (kevent(FKqueueHandle, @LEvents, N, nil, 0, nil) >= 0); - - if not Result then - begin - {$IFDEF DEBUG} - _LogLastOsError('connection kevent, %s', [Self.DebugInfo]); - {$ENDIF} - - while (N > 0) do - begin - Self._Release; - Dec(N); - end; - - Self.Close; - end; -end; - -{ TKqueueCrossSocket } - -constructor TKqueueCrossSocket.Create(const AIoThreads: Integer); -begin - inherited; - - FIdleLock := TLock.Create; -end; - -destructor TKqueueCrossSocket.Destroy; -begin - inherited; -end; - -procedure TKqueueCrossSocket._CloseIdleHandle; -begin - FileClose(FIdleHandle); -end; - -procedure TKqueueCrossSocket._CloseStopHandle; -begin - FileClose(FStopHandle.ReadDes); - FileClose(FStopHandle.WriteDes); -end; - -procedure TKqueueCrossSocket._HandleAccept(const AListen: ICrossListen); -var - LListen: ICrossListen; - LKqListen: TKqueueListen; - LConnection: ICrossConnection; - LKqConnection: TKqueueConnection; - LError: Integer; - LSocket, LListenSocket, LClientSocket: TSocket; - LSuccess: Boolean; -begin - LListen := AListen; - LListenSocket := LListen.Socket; - - while True do - begin - LSocket := TSocketAPI.Accept(LListenSocket, nil, nil); - - // Accept失败 - // EAGAIN 所有就绪的连接都已处理完毕 - // EMFILE 进程的文件句柄已经用完了 - if (LSocket < 0) then - begin - LError := GetLastError; - - // 所有就绪的连接都已处理完毕, 正常情况 - if (LError = EAGAIN) or (LError = EWOULDBLOCK) then - begin - // 空处理, 仅用于区分 EMFILE 和其他错误 - end else - // 当句柄用完了的时候, 释放事先占用的临时句柄 - // 然后再次 accept, 然后将 accept 的句柄关掉 - // 这样可以保证在文件句柄耗尽的时候依然能响应连接请求 - // 并立即将新到的连接关闭 - if (LError = EMFILE) then - begin - FIdleLock.Enter; - try - _CloseIdleHandle; - LSocket := TSocketAPI.Accept(LListenSocket, nil, nil); - TSocketAPI.CloseSocket(LSocket); - _OpenIdleHandle; - finally - FIdleLock.Leave; - end; - end else - _LogLastOsError('Accept'); - - Break; - end; - - LClientSocket := LSocket; - TSocketAPI.SetNonBlock(LClientSocket, True); - SetKeepAlive(LClientSocket); - _SetNoSigPipe(LClientSocket); - - LConnection := CreateConnection(Self, LClientSocket, ctAccept, ''); - TriggerConnecting(LConnection); - TriggerConnected(LConnection); - - // 连接建立后监视Socket的读事件 - LKqConnection := LConnection as TKqueueConnection; - LKqConnection._KqLock; - try - LKqConnection._UpdateIoEvent([ieRead]); - finally - LKqConnection._KqUnlock; - end; - end; - - // 继续接收新连接 - LKqListen := LListen as TKqueueListen; - LKqListen._Lock; - LKqListen._UpdateIoEvent([ieRead]); - LKqListen._Unlock; -end; - -procedure TKqueueCrossSocket._HandleConnect(const AConnection: ICrossConnection); -var - LConnection: ICrossConnection; - LKqConnection: TKqueueConnection; - LSockErr: Integer; -begin - LConnection := AConnection; - - // Connect失败 - LSockErr := TSocketAPI.GetError(LConnection.Socket); - if (LSockErr <> 0) then - begin - LConnection.LastNetError := LSockErr; - _LogLastOsError(Self.ClassName + '._HandleConnect.GetError'); - LConnection.Close; - Exit; - end; - - TriggerConnected(LConnection); - - LKqConnection := LConnection as TKqueueConnection; - - LKqConnection._KqLock; - try - LKqConnection._UpdateIoEvent([ieRead]); - finally - LKqConnection._KqUnlock; - end; -end; - -procedure TKqueueCrossSocket._HandleRead(const AConnection: ICrossConnection); -var - LConnection: ICrossConnection; - LKqConnection: TKqueueConnection; - LRcvd, LError: Integer; - LSuccess: Boolean; -begin - LConnection := AConnection; - LKqConnection := LConnection as TKqueueConnection; - - AtomicIncrement(LKqConnection.FInPending); - try - while True do - begin - LRcvd := TSocketAPI.Recv(LConnection.Socket, FRecvBuf[0], RCV_BUF_SIZE); - - // 对方主动断开连接 - if (LRcvd = 0) then - begin - _Log('Recv=0(Close), %s', [LConnection.DebugInfo]); - LConnection.Close; - Exit; - end; - - if (LRcvd < 0) then - begin - LError := GetLastError; - - // 被系统信号中断, 可以重新recv - if (LError = EINTR) then - Continue - // 接收缓冲区中数据已经被取完了 - else if (LError = EAGAIN) or (LError = EWOULDBLOCK) then - Break - else - // 接收出错 - begin - _LogLastOsError('Recv<0, %s', [LConnection.DebugInfo]); - LConnection.Close; - Exit; - end; - end; - - TriggerReceived(LConnection, @FRecvBuf[0], LRcvd); - - // 回调中可能关闭了连接, 需要检查状态 - if LConnection.IsClosed then Exit; - - if (LRcvd < RCV_BUF_SIZE) then Break; - end; - finally - AtomicDecrement(LKqConnection.FInPending); - end; - - LKqConnection._KqLock; - try - LKqConnection._UpdateIoEvent([ieRead]); - finally - LKqConnection._KqUnlock; - end; -end; - -procedure TKqueueCrossSocket._HandleWrite(const AConnection: ICrossConnection); -var - LConnection: ICrossConnection; - LKqConnection: TKqueueConnection; - LSendItem: PSendItem; - LSent, LError: Integer; - LSendCbArr: TArray; - LSendCb: TCrossConnectionCallback; -begin - LConnection := AConnection; - LKqConnection := LConnection as TKqueueConnection; - LSendCbArr := []; - - AtomicIncrement(LKqConnection.FOutPending); - LKqConnection._KqLock; - try - while True do - begin - // 检查队列中有没有数据 - if (LKqConnection.FSendQueue = nil) or (LKqConnection.FSendQueue.Count <= 0) then Break; - - // 获取Socket发送队列中的第一条数据 - LSendItem := LKqConnection.FSendQueue.Items[0]; - - // 发送数据 - {$IFNDEF MACOS} - LSent := TSocketAPI.Send(LConnection.Socket, LSendItem.Data^, LSendItem.Size, MSG_NOSIGNAL); - {$ELSE} - LSent := TSocketAPI.Send(LConnection.Socket, LSendItem.Data^, LSendItem.Size); - {$ENDIF} - - // 对方主动断开连接 - if (LSent = 0) then - begin - _Log('Send=0(close), %s', [LConnection.DebugInfo]); - - LConnection.Close; - Break; - end; - - // 连接断开或发送错误 - if (LSent < 0) then - begin - LError := GetLastError; - - // 被系统信号中断, 可以重新send - if (LError = EINTR) then - Continue - // 发送缓冲区已被填满了, 需要等下次唤醒发送线程再继续发送 - else if (LError = EAGAIN) or (LError = EWOULDBLOCK) then - Break - // 发送出错 - else - begin - _LogLastOsError('Send<0, %s', [LConnection.DebugInfo]); - - LConnection.Close; - Break; - end; - end; - - // 全部发送完成 - if (LSent >= LSendItem.Size) then - begin - TArrayUtils.Append(LSendCbArr, LSendItem.Callback); - - // 发送成功, 移除已发送成功的数据 - // 必须先从队列移除已发完的数据项, 然后再执行发送成功的回调 - // 因为回调里可能还会发送新的数据, 如果先执行回调再去移除, - // 就会错误的将回调中放到队列里的新数据移除 - if (LKqConnection.FSendQueue.Count > 0) then - LKqConnection.FSendQueue.Delete(0); - end else - begin - // 部分发送成功, 在下一次唤醒发送线程时继续处理剩余部分 - Dec(LSendItem.Size, LSent); - Inc(LSendItem.Data, LSent); - end; - end; - finally - LKqConnection._KqUnlock; - AtomicDecrement(LKqConnection.FOutPending); - end; - - // 调用回调 - for LSendCb in LSendCbArr do - LSendCb(LConnection, True); - - LKqConnection._KqLock; - try - if (LKqConnection.FSendQueue <> nil) and (LKqConnection.FSendQueue.Count > 0) then - LKqConnection._UpdateIoEvent([ieWrite]); - finally - LKqConnection._KqUnlock; - end; -end; - -procedure TKqueueCrossSocket._OpenIdleHandle; -begin - FIdleHandle := FileOpen('/dev/null', fmOpenRead); -end; - -procedure TKqueueCrossSocket._OpenStopHandle; -var - LEvent: TKEvent; -begin - pipe(FStopHandle); - - // 这里不使用 EV_ONESHOT - // 这样可以保证通知退出的命令发出后, 所有IO线程都会收到 - EV_SET(@LEvent, FStopHandle.ReadDes, EVFILT_READ, - EV_ADD, 0, 0, SHUTDOWN_FLAG); - kevent(FKqueueHandle, @LEvent, 1, nil, 0, nil); -end; - -procedure TKqueueCrossSocket._PostStopCommand; -var - LStuff: UInt64; -begin - LStuff := 1; - // 往 FStopHandle.WriteDes 写入任意数据, 唤醒工作线程 - __write(FStopHandle.WriteDes, @LStuff, SizeOf(LStuff)); -end; - -procedure TKqueueCrossSocket._SetNoSigPipe(ASocket: TSocket); -begin - {$if defined(MACOS) or defined(FREEBSD)} - TSocketAPI.SetSockOpt(ASocket, SOL_SOCKET, SO_NOSIGPIPE, 1); - {$endif} -end; - -procedure TKqueueCrossSocket.StartLoop; -var - I: Integer; -begin - if (FIoThreads <> nil) then Exit; - - _OpenIdleHandle; - - FKqueueHandle := kqueue(); - SetLength(FIoThreads, GetIoThreads); - for I := 0 to Length(FIoThreads) - 1 do - FIoThreads[i] := TIoEventThread.Create(Self); - - _OpenStopHandle; -end; - -procedure TKqueueCrossSocket.StopLoop; -var - I: Integer; - LCurrentThreadID: TThreadID; -begin - if (FIoThreads = nil) then Exit; - - CloseAll; - - while (ListensCount > 0) or (ConnectionsCount > 0) do Sleep(1); - - _PostStopCommand; - - LCurrentThreadID := GetCurrentThreadId; - for I := 0 to Length(FIoThreads) - 1 do - begin - if (FIoThreads[I].ThreadID = LCurrentThreadID) then - raise ECrossSocket.Create('不能在IO线程中执行StopLoop!'); - - FIoThreads[I].WaitFor; - FreeAndNil(FIoThreads[I]); - end; - FIoThreads := nil; - - FileClose(FKqueueHandle); - _CloseIdleHandle; - _CloseStopHandle; -end; - -procedure TKqueueCrossSocket.Connect(const AHost: string; - const APort, ALocalPort: Word; const ACallback: TCrossConnectionCallback); - - procedure _Failed1; - begin - if Assigned(ACallback) then - ACallback(nil, False); - end; - - function _Connect(const ASocket: TSocket; const AAddr: PRawAddrInfo): Boolean; - procedure _Failed2; - begin - if Assigned(ACallback) then - ACallback(nil, False); - TSocketAPI.CloseSocket(ASocket); - end; - var - LSockAddr: TRawSockAddrIn; - LConnection: ICrossConnection; - LKqConnection: TKqueueConnection; - begin - FillChar(LSockAddr, SizeOf(TRawSockAddrIn), 0); - LSockAddr.AddrLen := AAddr.ai_addrlen; - if (AAddr.ai_family = AF_INET6) then - begin - LSockAddr.Addr6.sin6_family := AAddr.ai_family; - LSockAddr.Addr6.sin6_port := htons(ALocalPort); - end else - begin - LSockAddr.Addr.sin_family := AAddr.ai_family; - LSockAddr.Addr.sin_port := htons(ALocalPort); - end; - if (TSocketAPI.Bind(ASocket, @LSockAddr.Addr, LSockAddr.AddrLen) < 0) then - begin - {$IFDEF DEBUG} - _LogLastOsError('TKqueueCrossSocket._Connect.Bind'); - {$ENDIF} - _Failed2; - Exit(False); - end; - - if (TSocketAPI.Connect(ASocket, AAddr.ai_addr, AAddr.ai_addrlen) = 0) - or (GetLastError = EINPROGRESS) then - begin - LConnection := CreateConnection(Self, ASocket, ctConnect, AHost, ACallback); - TriggerConnecting(LConnection); - LKqConnection := LConnection as TKqueueConnection; - - LKqConnection._KqLock; - try - LKqConnection.ConnectStatus := csConnecting; - if not LKqConnection._UpdateIoEvent([ieWrite]) then - begin - LConnection.Close; - Exit(False); - end; - finally - LKqConnection._KqUnlock; - end; - end else - begin - _Failed2; - Exit(False); - end; - - Result := True; - end; - -var - LHints: TRawAddrInfo; - P, LAddrInfo: PRawAddrInfo; - LSocket: TSocket; -begin - FillChar(LHints, SizeOf(TRawAddrInfo), 0); - LHints.ai_family := AF_UNSPEC; - LHints.ai_socktype := SOCK_STREAM; - LHints.ai_protocol := IPPROTO_TCP; - LAddrInfo := TSocketAPI.GetAddrInfo(AHost, APort, LHints); - if (LAddrInfo = nil) then - begin - _Failed1; - Exit; - end; - - P := LAddrInfo; - try - while (LAddrInfo <> nil) do - begin - LSocket := TSocketAPI.NewSocket(LAddrInfo.ai_family, LAddrInfo.ai_socktype, - LAddrInfo.ai_protocol); - if (LSocket = INVALID_SOCKET) then - begin - _Failed1; - Exit; - end; - - TSocketAPI.SetNonBlock(LSocket, True); - SetKeepAlive(LSocket); - _SetNoSigPipe(LSocket); - - if _Connect(LSocket, LAddrInfo) then Exit; - - LAddrInfo := PRawAddrInfo(LAddrInfo.ai_next); - end; - finally - TSocketAPI.FreeAddrInfo(P); - end; - - _Failed1; -end; - -function TKqueueCrossSocket.CreateConnection(const AOwner: TCrossSocketBase; - const AClientSocket: TSocket; const AConnectType: TConnectType; - const AHost: string; const AConnectCb: TCrossConnectionCallback): ICrossConnection; -begin - Result := TKqueueConnection.Create( - AOwner, - AClientSocket, - AConnectType, - AHost, - AConnectCb); -end; - -function TKqueueCrossSocket.CreateListen(const AOwner: TCrossSocketBase; - const AListenSocket: TSocket; const AFamily, ASockType, AProtocol: Integer): ICrossListen; -begin - Result := TKqueueListen.Create(AOwner, AListenSocket, AFamily, ASockType, AProtocol); -end; - -procedure TKqueueCrossSocket.Listen(const AHost: string; const APort: Word; - const ACallback: TCrossListenCallback); -var - LHints: TRawAddrInfo; - P, LAddrInfo: PRawAddrInfo; - LListenSocket: TSocket; - LListen: ICrossListen; - LKqListen: TKqueueListen; - LListenSuccess, LUpdateIoEventSuccess: Boolean; - - procedure _Failed; - begin - if not LListenSuccess and Assigned(ACallback) then - ACallback(LListen, False); - - if (LListen <> nil) then - LListen.Close - else if (LListenSocket <> INVALID_SOCKET) then - TSocketAPI.CloseSocket(LListenSocket); - end; - -begin - LListenSuccess := False; - FillChar(LHints, SizeOf(TRawAddrInfo), 0); - - LHints.ai_flags := AI_PASSIVE; - LHints.ai_family := AF_UNSPEC; - LHints.ai_socktype := SOCK_STREAM; - LHints.ai_protocol := IPPROTO_TCP; - LAddrInfo := TSocketAPI.GetAddrInfo(AHost, APort, LHints); - if (LAddrInfo = nil) then - begin - {$IFDEF DEBUG} - _LogLastOsError('TKqueueCrossSocket.Listen.GetAddrInfo'); - {$ENDIF} - _Failed; - Exit; - end; - - P := LAddrInfo; - try - while (LAddrInfo <> nil) do - begin - LListen := nil; - LListenSocket := TSocketAPI.NewSocket(LAddrInfo.ai_family, LAddrInfo.ai_socktype, - LAddrInfo.ai_protocol); - if (LListenSocket = INVALID_SOCKET) then - begin - {$IFDEF DEBUG} - _LogLastOsError('TKqueueCrossSocket.Listen.NewSocket'); - {$ENDIF} - _Failed; - Exit; - end; - - TSocketAPI.SetNonBlock(LListenSocket, True); - TSocketAPI.SetReUsePort(LListenSocket, True); - - if (LAddrInfo.ai_family = AF_INET6) then - TSocketAPI.SetSockOpt(LListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, 1); - - if (TSocketAPI.Bind(LListenSocket, LAddrInfo.ai_addr, LAddrInfo.ai_addrlen) < 0) - or (TSocketAPI.Listen(LListenSocket) < 0) then - begin - {$IFDEF DEBUG} - _LogLastOsError('TKqueueCrossSocket.Listen.Bind'); - {$ENDIF} - _Failed; - Exit; - end; - - LListen := CreateListen(Self, LListenSocket, LAddrInfo.ai_family, - LAddrInfo.ai_socktype, LAddrInfo.ai_protocol); - LKqListen := LListen as TKqueueListen; - - // 监听套接字的读事件 - // 读事件到达表明有新连接 - LKqListen._Lock; - try - LUpdateIoEventSuccess := LKqListen._UpdateIoEvent([ieRead]); - finally - LKqListen._Unlock; - end; - - if not LUpdateIoEventSuccess then - begin - _Failed; - - Exit; - end; - - // 监听成功 - LListenSuccess := True; - TriggerListened(LListen); - if Assigned(ACallback) then - ACallback(LListen, True); - - // 如果端口传入0,让所有地址统一用首个分配到的端口 - if (APort = 0) and (LAddrInfo.ai_next <> nil) then - Psockaddr_in(LAddrInfo.ai_next.ai_addr).sin_port := htons(LListen.LocalPort); - - LAddrInfo := PRawAddrInfo(LAddrInfo.ai_next); - end; - finally - TSocketAPI.FreeAddrInfo(P); - end; -end; - -procedure TKqueueCrossSocket.Send(const AConnection: ICrossConnection; - const ABuf: Pointer; const ALen: Integer; const ACallback: TCrossConnectionCallback); -var - LKqConnection: TKqueueConnection; - LSendItem: PSendItem; -begin - // 测试过先发送, 然后将剩余部分放入发送队列的做法 - // 发现会引起内存访问异常, 放到队列里到IO线程中发送则不会有问题 - {$region '放入发送队列'} - System.New(LSendItem); - FillChar(LSendItem^, SizeOf(TSendItem), 0); - LSendItem.Data := ABuf; - LSendItem.Size := ALen; - LSendItem.Callback := ACallback; - - LKqConnection := AConnection as TKqueueConnection; - - LKqConnection._KqLock; - try - // 将数据放入队列 - LKqConnection.FSendQueue.Add(LSendItem); - - // 由于 kqueue 队列中每个套接字的读写事件是分开的两条记录 - // 所以发送只需要添加写事件即可, 不用管读事件, 否则反而会引起引用计数异常 - LKqConnection._UpdateIoEvent([ieWrite]); - finally - LKqConnection._KqUnlock; - end; - {$endregion} -end; - -function TKqueueCrossSocket.ProcessIoEvent: Boolean; -var - LRet, I: Integer; - LEvent: TKEvent; - LCrossData: TCrossData; - LListen: ICrossListen; - LConnection: ICrossConnection; -begin - LRet := kevent(FKqueueHandle, nil, 0, @FEventList[0], MAX_EVENT_COUNT, nil); - if (LRet < 0) then - begin - LRet := GetLastError; - // EINTR, kevent 调用被系统信号打断, 可以进行重试 - Exit(LRet = EINTR); - end; - - for I := 0 to LRet - 1 do - begin - LEvent := FEventList[I]; - - // 收到退出命令 - if (LEvent.uData = SHUTDOWN_FLAG) then Exit(False); - - if (LEvent.uData = nil) then Continue; - - {$region '获取连接或监听对象'} - LCrossData := TCrossData(LEvent.uData); - - if (LCrossData is TKqueueListen) then - LListen := LCrossData as ICrossListen - else - LListen := nil; - - if (LCrossData is TKqueueConnection) then - LConnection := LCrossData as ICrossConnection - else - LConnection := nil; - {$endregion} - - {$region 'IO事件处理'} - if (LListen <> nil) then - begin - if (LEvent.Filter = EVFILT_READ) then - _HandleAccept(LListen); - end else - if (LConnection <> nil) then - begin - LConnection._Release; - - // kqueue的读写事件同一时间只可能触发一个 - if (LEvent.Filter = EVFILT_READ) then - _HandleRead(LConnection) - else if (LEvent.Filter = EVFILT_WRITE) then - begin - if (LConnection.ConnectStatus = csConnecting) then - _HandleConnect(LConnection) - else - _HandleWrite(LConnection); - end; - end; - {$endregion} - end; - - Result := True; -end; - -end. +{******************************************************************************} +{ } +{ Delphi cross platform socket library } +{ } +{ Copyright (c) 2017 WiNDDRiVER(soulawing@gmail.com) } +{ } +{ Homepage: https://github.com/winddriver/Delphi-Cross-Socket } +{ } +{******************************************************************************} +unit Net.CrossSocket.Kqueue; + +{$I zLib.inc} + +interface + +uses + SysUtils, + Classes, + Generics.Collections, + + {$IFDEF DELPHI} + Posix.SysSocket, + Posix.NetinetIn, + Posix.UniStd, + Posix.NetDB, + Posix.Pthread, + Posix.ArpaInet, + Posix.Errno, + {$ELSE} + baseunix, + unix, + sockets, + netdb, + DTF.RTL, + {$ENDIF} + + BSD.kqueue, + + Net.SocketAPI, + Net.CrossSocket.Base, + + Utils.SyncObjs, + Utils.ArrayUtils; + +{$IFDEF BSD} +const + IPV6_V6ONLY = 27; +{$ENDIF} + +type + {$IFDEF FPC} + TPipeDescriptors = {packed} record + ReadDes: Integer; + WriteDes: Integer; + end; + PPipeDescriptors = ^TPipeDescriptors; + {$ENDIF} + + TIoEvent = (ieRead, ieWrite); + TIoEvents = set of TIoEvent; + + TKqueueListen = class(TCrossListenBase) + private + FKqueueHandle: Integer; + FIoEvents: TIoEvents; + + function _ReadEnabled: Boolean; inline; + function _UpdateIoEvent(const AIoEvents: TIoEvents): Boolean; + public + constructor Create(const AOwner: TCrossSocketBase; const AListenSocket: TSocket; + const AFamily, ASockType, AProtocol: Integer); override; + end; + + PSendItem = ^TSendItem; + TSendItem = packed record + Data: PByte; + Size: Integer; + Callback: TCrossConnectionCallback; + end; + + TSendQueue = class(TList) + protected + procedure Notify(const Value: PSendItem; Action: TCollectionNotification); override; + end; + + TKqueueConnection = class(TCrossConnectionBase) + private + FKqueueHandle: Integer; + FSendQueue: TSendQueue; + FKqLock: ILock; + FInPending, FOutPending: Integer; + + function _UpdateIoEvent(const AIoEvents: TIoEvents): Boolean; + + procedure _ClearSendQueue; + + procedure _KqLock; inline; + procedure _KqUnlock; inline; + protected + procedure InternalClose; override; + public + constructor Create(const AOwner: TCrossSocketBase; const AClientSocket: TSocket; + const AConnectType: TConnectType; const AHost: string; + const AConnectCb: TCrossConnectionCallback); override; + destructor Destroy; override; + end; + + // KQUEUE 与 EPOLL 队列的差异 + // KQUEUE的队列中, 一个Socket句柄可以有多条记录, 每个事件一条, + // 这一点和 EPOLL 不一样, EPOLL中每个Socket句柄只会有一条记录 + // 要监测多个事件时, 只需要将多个事件做位运算加在一起调用 epoll_ctl 即可 + // + // EV_DISPATCH 和 EV_CLEAR 是令 kqueue 支持线程池的关键 + // 该参数组合可以令事件触发后就立即被禁用, 避免让同一个Socket的同一个事件 + // 同时被多个工作线程触发 + // + // EVFILT_READ + // 用于监测接收缓冲区是否可读了 + // 对于监听Socket来说,表示有新的连接到来 + // 对于已连接的Socket来说,表示有数据到达接收缓冲区 + // 为了支持线程池, 必须带上参数 EV_CLEAR or EV_DISPATCH + // 该参数组合表示, 该事件一旦触发立即清除该事件的状态并禁用它 + // 处理完连接或者读取数据之后再投递一次 EVFILT_READ, 带上参数 + // EV_ENABLE or EV_CLEAR or EV_DISPATCH, 让事件继续监测 + // + // EVFILT_WRITE + // 用于监测发送缓冲区是否可写了 + // 对于Connect中的Socket,投递EV_ENABLE,等到事件触发时表示连接已建立 + // 对于已连接的Socket,在Send之后立即投递EVFILT_WRITE,等到事件触发时表示发送完成 + // 对于EVFILT_WRITE都应该带上EV_ONESHOT参数,让该事件只会被触发一次 + // 否则,只要发送缓冲区是空的,该事件就会一直触发,这并没有什么意义 + // 我们只需要用EVFILT_WRITE去监测连接或者发送是否成功 + // + // KQUEUE 发送数据 + // 最好的做法是将实际发送数据的动作放到 EVFILT_WRITE 触发时进行, 该 + // 事件触发表明 Socket 发送缓存有空闲空间了。IOCP可以直接将待发送的数据及 + // 回调同时扔给 WSASend, 发送完成后去调用回调即可; KQUEUE 机制不一样, 在 KQUEUE + // 中没有类似 WSASend 的函数, 只能自行维护发送数据及回调的队列 + // EPOLL要支持多线程并发发送数据必须创建发送队列, 否则同一个 Socket 的并发发送 + // 极有可能有一部分会被其它发送覆盖掉 + // + // 由于 KQUEUE 中每个套接字在队列中的 EV_WRITE 和 EV_READ 是分开的两条记录 + // 所以修改套接字的监听事件时不会互相覆盖, 也就是说每个事件都会对应到一次 + // 触发, 这样就可以方便的使用接口的引用计数机制保持连接的有效性, 也不会出现 + // 内存泄漏 + TKqueueCrossSocket = class(TCrossSocketBase) + private const + MAX_EVENT_COUNT = 2048; + SHUTDOWN_FLAG = Pointer(-1); + private class threadvar + FEventList: array [0..MAX_EVENT_COUNT-1] of TKEvent; + private + FKqueueHandle: Integer; + FIoThreads: TArray; + FIdleHandle: THandle; + FIdleLock: ILock; + FStopHandle: TPipeDescriptors; + + // 利用 pipe 唤醒并退出IO线程 + procedure _OpenStopHandle; inline; + procedure _PostStopCommand; inline; + procedure _CloseStopHandle; inline; + + procedure _OpenIdleHandle; inline; + procedure _CloseIdleHandle; inline; + + // 在向一个已经关闭的套接字发送数据时系统会直接抛出EPIPE异常导致程序非正常退出 + // LINUX下可以在send时带上MSG_NOSIGNAL参数就能避免这种情况的发生 + // OSX中可以通过设置套接字的SO_NOSIGPIPE参数达到同样的目的 + procedure _SetNoSigPipe(ASocket: TSocket); inline; + + procedure _HandleAccept(const AListen: ICrossListen); + procedure _HandleConnect(const AConnection: ICrossConnection); + procedure _HandleRead(const AConnection: ICrossConnection); + procedure _HandleWrite(const AConnection: ICrossConnection); + protected + function CreateConnection(const AOwner: TCrossSocketBase; const AClientSocket: TSocket; + const AConnectType: TConnectType; const AHost: string; + const AConnectCb: TCrossConnectionCallback): ICrossConnection; override; + function CreateListen(const AOwner: TCrossSocketBase; const AListenSocket: TSocket; + const AFamily, ASockType, AProtocol: Integer): ICrossListen; override; + + procedure StartLoop; override; + procedure StopLoop; override; + + procedure Listen(const AHost: string; const APort: Word; + const ACallback: TCrossListenCallback = nil); override; + + procedure Connect(const AHost: string; const APort, ALocalPort: Word; + const ACallback: TCrossConnectionCallback = nil); override; + + procedure Send(const AConnection: ICrossConnection; const ABuf: Pointer; + const ALen: Integer; const ACallback: TCrossConnectionCallback = nil); override; + + function ProcessIoEvent: Boolean; override; + public + constructor Create(const AIoThreads: Integer); override; + destructor Destroy; override; + end; + +implementation + +{$IFDEF FPC} +function pipe(var PipeDes: TPipeDescriptors): Integer; cdecl; external 'c' name 'pipe'; +function __read(Handle: Integer; Buffer: Pointer; Count: size_t): ssize_t; cdecl; external 'c' name 'read'; +function __write(Handle: Integer; Buffer: Pointer; Count: size_t): ssize_t; cdecl; external 'c' name 'write'; +function __close(Handle: Integer): Integer; cdecl; external 'c' name 'close'; +{$ENDIF} + +{ TKqueueListen } + +constructor TKqueueListen.Create(const AOwner: TCrossSocketBase; + const AListenSocket: TSocket; const AFamily, ASockType, AProtocol: Integer); +begin + inherited; + FKqueueHandle := TKqueueCrossSocket(AOwner).FKqueueHandle; +end; + +function TKqueueListen._ReadEnabled: Boolean; +begin + Result := (ieRead in FIoEvents); +end; + +function TKqueueListen._UpdateIoEvent(const AIoEvents: TIoEvents): Boolean; +var + LCrossData: Pointer; + LEvents: array [0..1] of TKEvent; + N: Integer; +begin + FIoEvents := AIoEvents; + + if (FIoEvents = []) or IsClosed then Exit(False); + + LCrossData := Pointer(Self); + N := 0; + + if _ReadEnabled then + begin + EV_SET(@LEvents[N], Socket, EVFILT_READ, + EV_ADD or EV_ONESHOT or EV_CLEAR or EV_DISPATCH, 0, 0, Pointer(LCrossData)); + + Inc(N); + end; + + if (N <= 0) then Exit(False); + + Result := (kevent(FKqueueHandle, @LEvents, N, nil, 0, nil) >= 0); + + {$IFDEF DEBUG} + if not Result then + _LogLastOsError('listen kevent, %s', [Socket, Self.DebugInfo]); + {$ENDIF} +end; + +{ TSendQueue } + +procedure TSendQueue.Notify(const Value: PSendItem; + Action: TCollectionNotification); +begin + inherited; + + if (Action = TCollectionNotification.cnRemoved) then + begin + if (Value <> nil) then + begin + Value.Callback := nil; + System.Dispose(Value); + end; + end; +end; + +{ TKqueueConnection } + +constructor TKqueueConnection.Create(const AOwner: TCrossSocketBase; + const AClientSocket: TSocket; const AConnectType: TConnectType; + const AHost: string; const AConnectCb: TCrossConnectionCallback); +begin + inherited Create(AOwner, AClientSocket, AConnectType, AHost, AConnectCb); + + FKqLock := TLock.Create; + FSendQueue := TSendQueue.Create; + + FKqueueHandle := TKqueueCrossSocket(AOwner).FKqueueHandle; +end; + +destructor TKqueueConnection.Destroy; +begin + _ClearSendQueue; + FreeAndNil(FSendQueue); + + inherited; +end; + +procedure TKqueueConnection.InternalClose; +var + LEvent: TKEvent; +begin + _ClearSendQueue; + + // 从 kqueue 中删除该 socket 的所有事件,防止 fd 重用后触发错误回调 + EV_SET(@LEvent, Socket, EVFILT_READ, EV_DELETE, 0, 0, nil); + kevent(FKqueueHandle, @LEvent, 1, nil, 0, nil); + EV_SET(@LEvent, Socket, EVFILT_WRITE, EV_DELETE, 0, 0, nil); + kevent(FKqueueHandle, @LEvent, 1, nil, 0, nil); + + inherited InternalClose; +end; + +procedure TKqueueConnection._ClearSendQueue; +var + LConnection: ICrossConnection; + LSendItem: PSendItem; + LCallbacks: TArray; + LCallback: TCrossConnectionCallback; +begin + LConnection := Self; + LCallbacks := []; + + _KqLock; + try + // 连接释放时, 先收集所有回调, 然后在锁外执行 + // 避免回调中再次发送数据导致死锁 + if (FSendQueue <> nil) and (FSendQueue.Count > 0) then + begin + for LSendItem in FSendQueue do + if Assigned(LSendItem.Callback) then + TArrayUtils.Append(LCallbacks, LSendItem.Callback); + + FSendQueue.Clear; + end; + finally + _KqUnlock; + end; + + // 在锁外执行回调, 告知发送失败 + for LCallback in LCallbacks do + LCallback(LConnection, False); +end; + +procedure TKqueueConnection._KqLock; +begin + FKqLock.Enter; +end; + +procedure TKqueueConnection._KqUnlock; +begin + FKqLock.Leave; +end; + +function TKqueueConnection._UpdateIoEvent(const AIoEvents: TIoEvents): Boolean; +var + LCrossData: Pointer; + LEvents: array [0..1] of TKEvent; + N: Integer; +begin + if (AIoEvents = []) or IsClosed then Exit(False); + + LCrossData := Pointer(Self); + N := 0; + + // kqueue中同一个套接字的EVFILT_READ和EVFILT_WRITE事件在队列中会有两条记录 + // 并且可能会在不同的线程中同时被触发, 如果其中一个线程关闭了连接, 在没有 + // 引用计数保护的情况下, 就会导致连接对象被释放, 另一个线程再访问连接对象 + // 就会引起异常, 这里为了保证连接对象的有效性, 在添加事件时手动增加连接对象 + // 的引用计数, 到事件触发时再减少引用计数 + // 注意关闭连接一定要使用shutdown而不能直接close, 否则无法触发kqueue事件, + // 导致引用计数无法回收 + + if (ieRead in AIoEvents) and (AtomicCmpExchange(FInPending, 0, 0) = 0) then + begin + Self._AddRef; + + EV_SET(@LEvents[N], Socket, EVFILT_READ, + EV_ADD or EV_ONESHOT or EV_CLEAR or EV_DISPATCH, 0, 0, Pointer(LCrossData)); + + Inc(N); + end; + + if (ieWrite in AIoEvents) and (AtomicCmpExchange(FOutPending, 0, 0) = 0) then + begin + Self._AddRef; + + EV_SET(@LEvents[N], Socket, EVFILT_WRITE, + EV_ADD or EV_ONESHOT or EV_CLEAR or EV_DISPATCH, 0, 0, Pointer(LCrossData)); + + Inc(N); + end; + + if (N <= 0) then Exit(False); + + Result := (kevent(FKqueueHandle, @LEvents, N, nil, 0, nil) >= 0); + + if not Result then + begin + {$IFDEF DEBUG} + _LogLastOsError('connection kevent, %s', [Self.DebugInfo]); + {$ENDIF} + + while (N > 0) do + begin + Self._Release; + Dec(N); + end; + + Self.Close; + end; +end; + +{ TKqueueCrossSocket } + +constructor TKqueueCrossSocket.Create(const AIoThreads: Integer); +begin + inherited; + + FIdleLock := TLock.Create; +end; + +destructor TKqueueCrossSocket.Destroy; +begin + inherited; +end; + +procedure TKqueueCrossSocket._CloseIdleHandle; +begin + FileClose(FIdleHandle); +end; + +procedure TKqueueCrossSocket._CloseStopHandle; +begin + FileClose(FStopHandle.ReadDes); + FileClose(FStopHandle.WriteDes); +end; + +procedure TKqueueCrossSocket._HandleAccept(const AListen: ICrossListen); +var + LListen: ICrossListen; + LKqListen: TKqueueListen; + LConnection: ICrossConnection; + LKqConnection: TKqueueConnection; + LError: Integer; + LSocket, LListenSocket, LClientSocket: TSocket; + LSuccess: Boolean; +begin + LListen := AListen; + LListenSocket := LListen.Socket; + + while True do + begin + LSocket := TSocketAPI.Accept(LListenSocket, nil, nil); + + // Accept失败 + // EAGAIN 所有就绪的连接都已处理完毕 + // EMFILE 进程的文件句柄已经用完了 + if (LSocket < 0) then + begin + LError := GetLastError; + + // 所有就绪的连接都已处理完毕, 正常情况 + if (LError = EAGAIN) or (LError = EWOULDBLOCK) then + begin + // 空处理, 仅用于区分 EMFILE 和其他错误 + end else + // 当句柄用完了的时候, 释放事先占用的临时句柄 + // 然后再次 accept, 然后将 accept 的句柄关掉 + // 这样可以保证在文件句柄耗尽的时候依然能响应连接请求 + // 并立即将新到的连接关闭 + if (LError = EMFILE) then + begin + FIdleLock.Enter; + try + _CloseIdleHandle; + LSocket := TSocketAPI.Accept(LListenSocket, nil, nil); + TSocketAPI.CloseSocket(LSocket); + _OpenIdleHandle; + finally + FIdleLock.Leave; + end; + end else + _LogLastOsError('Accept'); + + Break; + end; + + LClientSocket := LSocket; + TSocketAPI.SetNonBlock(LClientSocket, True); + SetKeepAlive(LClientSocket); + _SetNoSigPipe(LClientSocket); + + LConnection := CreateConnection(Self, LClientSocket, ctAccept, ''); + TriggerConnecting(LConnection); + TriggerConnected(LConnection); + + // 连接建立后监视Socket的读事件 + LKqConnection := LConnection as TKqueueConnection; + LKqConnection._KqLock; + try + LKqConnection._UpdateIoEvent([ieRead]); + finally + LKqConnection._KqUnlock; + end; + end; + + // 继续接收新连接 + LKqListen := LListen as TKqueueListen; + LKqListen._Lock; + LKqListen._UpdateIoEvent([ieRead]); + LKqListen._Unlock; +end; + +procedure TKqueueCrossSocket._HandleConnect(const AConnection: ICrossConnection); +var + LConnection: ICrossConnection; + LKqConnection: TKqueueConnection; + LSockErr: Integer; +begin + LConnection := AConnection; + + // Connect失败 + LSockErr := TSocketAPI.GetError(LConnection.Socket); + if (LSockErr <> 0) then + begin + LConnection.LastNetError := LSockErr; + _LogLastOsError(Self.ClassName + '._HandleConnect.GetError'); + LConnection.Close; + Exit; + end; + + TriggerConnected(LConnection); + + LKqConnection := LConnection as TKqueueConnection; + + LKqConnection._KqLock; + try + LKqConnection._UpdateIoEvent([ieRead]); + finally + LKqConnection._KqUnlock; + end; +end; + +procedure TKqueueCrossSocket._HandleRead(const AConnection: ICrossConnection); +var + LConnection: ICrossConnection; + LKqConnection: TKqueueConnection; + LRcvd, LError: Integer; + LSuccess: Boolean; +begin + LConnection := AConnection; + LKqConnection := LConnection as TKqueueConnection; + + AtomicIncrement(LKqConnection.FInPending); + try + while True do + begin + LRcvd := TSocketAPI.Recv(LConnection.Socket, FRecvBuf[0], RCV_BUF_SIZE); + + // 对方主动断开连接 + if (LRcvd = 0) then + begin + _Log('Recv=0(Close), %s', [LConnection.DebugInfo]); + LConnection.Close; + Exit; + end; + + if (LRcvd < 0) then + begin + LError := GetLastError; + + // 被系统信号中断, 可以重新recv + if (LError = EINTR) then + Continue + // 接收缓冲区中数据已经被取完了 + else if (LError = EAGAIN) or (LError = EWOULDBLOCK) then + Break + else + // 接收出错 + begin + _LogLastOsError('Recv<0, %s', [LConnection.DebugInfo]); + LConnection.Close; + Exit; + end; + end; + + TriggerReceived(LConnection, @FRecvBuf[0], LRcvd); + + // 回调中可能关闭了连接, 需要检查状态 + if LConnection.IsClosed then Exit; + + if (LRcvd < RCV_BUF_SIZE) then Break; + end; + finally + AtomicDecrement(LKqConnection.FInPending); + end; + + LKqConnection._KqLock; + try + LKqConnection._UpdateIoEvent([ieRead]); + finally + LKqConnection._KqUnlock; + end; +end; + +procedure TKqueueCrossSocket._HandleWrite(const AConnection: ICrossConnection); +var + LConnection: ICrossConnection; + LKqConnection: TKqueueConnection; + LSendItem: PSendItem; + LSent, LError: Integer; + LSendCbArr: TArray; + LSendCb: TCrossConnectionCallback; +begin + LConnection := AConnection; + LKqConnection := LConnection as TKqueueConnection; + LSendCbArr := []; + + AtomicIncrement(LKqConnection.FOutPending); + LKqConnection._KqLock; + try + while True do + begin + // 检查队列中有没有数据 + if (LKqConnection.FSendQueue = nil) or (LKqConnection.FSendQueue.Count <= 0) then Break; + + // 获取Socket发送队列中的第一条数据 + LSendItem := LKqConnection.FSendQueue.Items[0]; + + // 发送数据 + {$IFNDEF MACOS} + LSent := TSocketAPI.Send(LConnection.Socket, LSendItem.Data^, LSendItem.Size, MSG_NOSIGNAL); + {$ELSE} + LSent := TSocketAPI.Send(LConnection.Socket, LSendItem.Data^, LSendItem.Size); + {$ENDIF} + + // 对方主动断开连接 + if (LSent = 0) then + begin + _Log('Send=0(close), %s', [LConnection.DebugInfo]); + + LConnection.Close; + Break; + end; + + // 连接断开或发送错误 + if (LSent < 0) then + begin + LError := GetLastError; + + // 被系统信号中断, 可以重新send + if (LError = EINTR) then + Continue + // 发送缓冲区已被填满了, 需要等下次唤醒发送线程再继续发送 + else if (LError = EAGAIN) or (LError = EWOULDBLOCK) then + Break + // 发送出错 + else + begin + _LogLastOsError('Send<0, %s', [LConnection.DebugInfo]); + + LConnection.Close; + Break; + end; + end; + + // 全部发送完成 + if (LSent >= LSendItem.Size) then + begin + TArrayUtils.Append(LSendCbArr, LSendItem.Callback); + + // 发送成功, 移除已发送成功的数据 + // 必须先从队列移除已发完的数据项, 然后再执行发送成功的回调 + // 因为回调里可能还会发送新的数据, 如果先执行回调再去移除, + // 就会错误的将回调中放到队列里的新数据移除 + if (LKqConnection.FSendQueue.Count > 0) then + LKqConnection.FSendQueue.Delete(0); + end else + begin + // 部分发送成功, 在下一次唤醒发送线程时继续处理剩余部分 + Dec(LSendItem.Size, LSent); + Inc(LSendItem.Data, LSent); + end; + end; + finally + LKqConnection._KqUnlock; + AtomicDecrement(LKqConnection.FOutPending); + end; + + // 调用回调 + for LSendCb in LSendCbArr do + LSendCb(LConnection, True); + + LKqConnection._KqLock; + try + if (LKqConnection.FSendQueue <> nil) and (LKqConnection.FSendQueue.Count > 0) then + LKqConnection._UpdateIoEvent([ieWrite]); + finally + LKqConnection._KqUnlock; + end; +end; + +procedure TKqueueCrossSocket._OpenIdleHandle; +begin + FIdleHandle := FileOpen('/dev/null', fmOpenRead); +end; + +procedure TKqueueCrossSocket._OpenStopHandle; +var + LEvent: TKEvent; +begin + pipe(FStopHandle); + + // 这里不使用 EV_ONESHOT + // 这样可以保证通知退出的命令发出后, 所有IO线程都会收到 + EV_SET(@LEvent, FStopHandle.ReadDes, EVFILT_READ, + EV_ADD, 0, 0, SHUTDOWN_FLAG); + kevent(FKqueueHandle, @LEvent, 1, nil, 0, nil); +end; + +procedure TKqueueCrossSocket._PostStopCommand; +var + LStuff: UInt64; +begin + LStuff := 1; + // 往 FStopHandle.WriteDes 写入任意数据, 唤醒工作线程 + __write(FStopHandle.WriteDes, @LStuff, SizeOf(LStuff)); +end; + +procedure TKqueueCrossSocket._SetNoSigPipe(ASocket: TSocket); +begin + {$if defined(MACOS) or defined(FREEBSD)} + TSocketAPI.SetSockOpt(ASocket, SOL_SOCKET, SO_NOSIGPIPE, 1); + {$endif} +end; + +procedure TKqueueCrossSocket.StartLoop; +var + I: Integer; +begin + if (FIoThreads <> nil) then Exit; + + _OpenIdleHandle; + + FKqueueHandle := kqueue(); + SetLength(FIoThreads, GetIoThreads); + for I := 0 to Length(FIoThreads) - 1 do + FIoThreads[i] := TIoEventThread.Create(Self); + + _OpenStopHandle; +end; + +procedure TKqueueCrossSocket.StopLoop; +var + I: Integer; + LCurrentThreadID: TThreadID; +begin + if (FIoThreads = nil) then Exit; + + CloseAll; + + while (ListensCount > 0) or (ConnectionsCount > 0) do Sleep(1); + + _PostStopCommand; + + LCurrentThreadID := GetCurrentThreadId; + for I := 0 to Length(FIoThreads) - 1 do + begin + if (FIoThreads[I].ThreadID = LCurrentThreadID) then + raise ECrossSocket.Create('不能在IO线程中执行StopLoop!'); + + FIoThreads[I].WaitFor; + FreeAndNil(FIoThreads[I]); + end; + FIoThreads := nil; + + FileClose(FKqueueHandle); + _CloseIdleHandle; + _CloseStopHandle; +end; + +procedure TKqueueCrossSocket.Connect(const AHost: string; + const APort, ALocalPort: Word; const ACallback: TCrossConnectionCallback); + + procedure _Failed1; + begin + if Assigned(ACallback) then + ACallback(nil, False); + end; + + function _Connect(const ASocket: TSocket; const AAddr: PRawAddrInfo): Boolean; + procedure _Failed2; + begin + if Assigned(ACallback) then + ACallback(nil, False); + TSocketAPI.CloseSocket(ASocket); + end; + var + LSockAddr: TRawSockAddrIn; + LConnection: ICrossConnection; + LKqConnection: TKqueueConnection; + begin + FillChar(LSockAddr, SizeOf(TRawSockAddrIn), 0); + LSockAddr.AddrLen := AAddr.ai_addrlen; + if (AAddr.ai_family = AF_INET6) then + begin + LSockAddr.Addr6.sin6_family := AAddr.ai_family; + LSockAddr.Addr6.sin6_port := htons(ALocalPort); + end else + begin + LSockAddr.Addr.sin_family := AAddr.ai_family; + LSockAddr.Addr.sin_port := htons(ALocalPort); + end; + if (TSocketAPI.Bind(ASocket, @LSockAddr.Addr, LSockAddr.AddrLen) < 0) then + begin + {$IFDEF DEBUG} + _LogLastOsError('TKqueueCrossSocket._Connect.Bind'); + {$ENDIF} + _Failed2; + Exit(False); + end; + + if (TSocketAPI.Connect(ASocket, AAddr.ai_addr, AAddr.ai_addrlen) = 0) + or (GetLastError = EINPROGRESS) then + begin + LConnection := CreateConnection(Self, ASocket, ctConnect, AHost, ACallback); + TriggerConnecting(LConnection); + LKqConnection := LConnection as TKqueueConnection; + + LKqConnection._KqLock; + try + LKqConnection.ConnectStatus := csConnecting; + if not LKqConnection._UpdateIoEvent([ieWrite]) then + begin + LConnection.Close; + Exit(False); + end; + finally + LKqConnection._KqUnlock; + end; + end else + begin + _Failed2; + Exit(False); + end; + + Result := True; + end; + +var + LHints: TRawAddrInfo; + P, LAddrInfo: PRawAddrInfo; + LSocket: TSocket; +begin + FillChar(LHints, SizeOf(TRawAddrInfo), 0); + LHints.ai_family := AF_UNSPEC; + LHints.ai_socktype := SOCK_STREAM; + LHints.ai_protocol := IPPROTO_TCP; + LAddrInfo := TSocketAPI.GetAddrInfo(AHost, APort, LHints); + if (LAddrInfo = nil) then + begin + _Failed1; + Exit; + end; + + P := LAddrInfo; + try + while (LAddrInfo <> nil) do + begin + LSocket := TSocketAPI.NewSocket(LAddrInfo.ai_family, LAddrInfo.ai_socktype, + LAddrInfo.ai_protocol); + if (LSocket = INVALID_SOCKET) then + begin + _Failed1; + Exit; + end; + + TSocketAPI.SetNonBlock(LSocket, True); + SetKeepAlive(LSocket); + _SetNoSigPipe(LSocket); + + if _Connect(LSocket, LAddrInfo) then Exit; + + LAddrInfo := PRawAddrInfo(LAddrInfo.ai_next); + end; + finally + TSocketAPI.FreeAddrInfo(P); + end; + + _Failed1; +end; + +function TKqueueCrossSocket.CreateConnection(const AOwner: TCrossSocketBase; + const AClientSocket: TSocket; const AConnectType: TConnectType; + const AHost: string; const AConnectCb: TCrossConnectionCallback): ICrossConnection; +begin + Result := TKqueueConnection.Create( + AOwner, + AClientSocket, + AConnectType, + AHost, + AConnectCb); +end; + +function TKqueueCrossSocket.CreateListen(const AOwner: TCrossSocketBase; + const AListenSocket: TSocket; const AFamily, ASockType, AProtocol: Integer): ICrossListen; +begin + Result := TKqueueListen.Create(AOwner, AListenSocket, AFamily, ASockType, AProtocol); +end; + +procedure TKqueueCrossSocket.Listen(const AHost: string; const APort: Word; + const ACallback: TCrossListenCallback); +var + LHints: TRawAddrInfo; + P, LAddrInfo: PRawAddrInfo; + LListenSocket: TSocket; + LListen: ICrossListen; + LKqListen: TKqueueListen; + LListenSuccess, LUpdateIoEventSuccess: Boolean; + + procedure _Failed; + begin + if not LListenSuccess and Assigned(ACallback) then + ACallback(LListen, False); + + if (LListen <> nil) then + LListen.Close + else if (LListenSocket <> INVALID_SOCKET) then + TSocketAPI.CloseSocket(LListenSocket); + end; + +begin + LListenSuccess := False; + FillChar(LHints, SizeOf(TRawAddrInfo), 0); + + LHints.ai_flags := AI_PASSIVE; + LHints.ai_family := AF_UNSPEC; + LHints.ai_socktype := SOCK_STREAM; + LHints.ai_protocol := IPPROTO_TCP; + LAddrInfo := TSocketAPI.GetAddrInfo(AHost, APort, LHints); + if (LAddrInfo = nil) then + begin + {$IFDEF DEBUG} + _LogLastOsError('TKqueueCrossSocket.Listen.GetAddrInfo'); + {$ENDIF} + _Failed; + Exit; + end; + + P := LAddrInfo; + try + while (LAddrInfo <> nil) do + begin + LListen := nil; + LListenSocket := TSocketAPI.NewSocket(LAddrInfo.ai_family, LAddrInfo.ai_socktype, + LAddrInfo.ai_protocol); + if (LListenSocket = INVALID_SOCKET) then + begin + {$IFDEF DEBUG} + _LogLastOsError('TKqueueCrossSocket.Listen.NewSocket'); + {$ENDIF} + _Failed; + Exit; + end; + + TSocketAPI.SetNonBlock(LListenSocket, True); + TSocketAPI.SetReUsePort(LListenSocket, True); + + if (LAddrInfo.ai_family = AF_INET6) then + TSocketAPI.SetSockOpt(LListenSocket, IPPROTO_IPV6, IPV6_V6ONLY, 1); + + if (TSocketAPI.Bind(LListenSocket, LAddrInfo.ai_addr, LAddrInfo.ai_addrlen) < 0) + or (TSocketAPI.Listen(LListenSocket) < 0) then + begin + {$IFDEF DEBUG} + _LogLastOsError('TKqueueCrossSocket.Listen.Bind'); + {$ENDIF} + _Failed; + Exit; + end; + + LListen := CreateListen(Self, LListenSocket, LAddrInfo.ai_family, + LAddrInfo.ai_socktype, LAddrInfo.ai_protocol); + LKqListen := LListen as TKqueueListen; + + // 监听套接字的读事件 + // 读事件到达表明有新连接 + LKqListen._Lock; + try + LUpdateIoEventSuccess := LKqListen._UpdateIoEvent([ieRead]); + finally + LKqListen._Unlock; + end; + + if not LUpdateIoEventSuccess then + begin + _Failed; + + Exit; + end; + + // 监听成功 + LListenSuccess := True; + TriggerListened(LListen); + if Assigned(ACallback) then + ACallback(LListen, True); + + // 如果端口传入0,让所有地址统一用首个分配到的端口 + if (APort = 0) and (LAddrInfo.ai_next <> nil) then + Psockaddr_in(LAddrInfo.ai_next.ai_addr).sin_port := htons(LListen.LocalPort); + + LAddrInfo := PRawAddrInfo(LAddrInfo.ai_next); + end; + finally + TSocketAPI.FreeAddrInfo(P); + end; +end; + +procedure TKqueueCrossSocket.Send(const AConnection: ICrossConnection; + const ABuf: Pointer; const ALen: Integer; const ACallback: TCrossConnectionCallback); +var + LKqConnection: TKqueueConnection; + LSendItem: PSendItem; +begin + // 测试过先发送, 然后将剩余部分放入发送队列的做法 + // 发现会引起内存访问异常, 放到队列里到IO线程中发送则不会有问题 + {$region '放入发送队列'} + System.New(LSendItem); + FillChar(LSendItem^, SizeOf(TSendItem), 0); + LSendItem.Data := ABuf; + LSendItem.Size := ALen; + LSendItem.Callback := ACallback; + + LKqConnection := AConnection as TKqueueConnection; + + LKqConnection._KqLock; + try + // 将数据放入队列 + LKqConnection.FSendQueue.Add(LSendItem); + + // 由于 kqueue 队列中每个套接字的读写事件是分开的两条记录 + // 所以发送只需要添加写事件即可, 不用管读事件, 否则反而会引起引用计数异常 + LKqConnection._UpdateIoEvent([ieWrite]); + finally + LKqConnection._KqUnlock; + end; + {$endregion} +end; + +function TKqueueCrossSocket.ProcessIoEvent: Boolean; +var + LRet, I: Integer; + LEvent: TKEvent; + LCrossData: TCrossData; + LListen: ICrossListen; + LConnection: ICrossConnection; +begin + LRet := kevent(FKqueueHandle, nil, 0, @FEventList[0], MAX_EVENT_COUNT, nil); + if (LRet < 0) then + begin + LRet := GetLastError; + // EINTR, kevent 调用被系统信号打断, 可以进行重试 + Exit(LRet = EINTR); + end; + + for I := 0 to LRet - 1 do + begin + LEvent := FEventList[I]; + + // 收到退出命令 + if (LEvent.uData = SHUTDOWN_FLAG) then Exit(False); + + if (LEvent.uData = nil) then Continue; + + {$region '获取连接或监听对象'} + LCrossData := TCrossData(LEvent.uData); + + if (LCrossData is TKqueueListen) then + LListen := LCrossData as ICrossListen + else + LListen := nil; + + if (LCrossData is TKqueueConnection) then + LConnection := LCrossData as ICrossConnection + else + LConnection := nil; + {$endregion} + + {$region 'IO事件处理'} + if (LListen <> nil) then + begin + if (LEvent.Filter = EVFILT_READ) then + _HandleAccept(LListen); + end else + if (LConnection <> nil) then + begin + LConnection._Release; + + // kqueue的读写事件同一时间只可能触发一个 + if (LEvent.Filter = EVFILT_READ) then + _HandleRead(LConnection) + else if (LEvent.Filter = EVFILT_WRITE) then + begin + if (LConnection.ConnectStatus = csConnecting) then + _HandleConnect(LConnection) + else + _HandleWrite(LConnection); + end; + end; + {$endregion} + end; + + Result := True; +end; + +end. From ba0dceecb5f314b482bdd88235ad1123ecbf2129 Mon Sep 17 00:00:00 2001 From: freitasjca Date: Mon, 29 Jun 2026 16:56:33 +0100 Subject: [PATCH 12/15] feat(ssl): add TLSOPT-1/2 (SetPrivateKeyPassword, SetCipherList) --- Net/Net.CrossSslSocket.Base.pas | 13 +++++ Net/Net.CrossSslSocket.OpenSSL.pas | 94 +++++++++++++++++++++++++++++- 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/Net/Net.CrossSslSocket.Base.pas b/Net/Net.CrossSslSocket.Base.pas index 8bb369f..982f428 100644 --- a/Net/Net.CrossSslSocket.Base.pas +++ b/Net/Net.CrossSslSocket.Base.pas @@ -210,6 +210,19 @@ TCrossSslSocketBase = class(TCrossSocket, ICrossSslSocket) populated before verify mode is enabled. } procedure SetVerifyPeer(const AVerify: Boolean); virtual; abstract; + { ── TLSOPT-1: passphrase for an encrypted PEM private key ── + Set the password OpenSSL uses to decrypt an encrypted PEM private key. + Must be called BEFORE SetPrivateKey / SetPrivateKeyFile so the key is + parsed with the passphrase available. Passing '' (the default) leaves the + unencrypted-key code path unchanged — a no-op for plain keys. } + procedure SetPrivateKeyPassword(const APassword: string); virtual; abstract; + + { ── TLSOPT-2: override the negotiated cipher list (TLS 1.2 and below) ── + ACipherList is an OpenSSL cipher-list string (e.g. + 'ECDHE-RSA-AES256-GCM-SHA384:...'). Empty leaves the built-in default + list set in _InitSslCtx. TLS 1.3 cipher suites are not affected. } + procedure SetCipherList(const ACipherList: string); virtual; abstract; + property Ssl: Boolean read GetSsl; property SslMaxPendingWriteBytes: Int64 read GetSslMaxPendingWriteBytes write SetSslMaxPendingWriteBytes; diff --git a/Net/Net.CrossSslSocket.OpenSSL.pas b/Net/Net.CrossSslSocket.OpenSSL.pas index 9ded76a..ac7001c 100644 --- a/Net/Net.CrossSslSocket.OpenSSL.pas +++ b/Net/Net.CrossSslSocket.OpenSSL.pas @@ -39,6 +39,15 @@ When AVerify=False, reverts to SSL_VERIFY_NONE (default). Must be called AFTER SetCACertificate — the trust store must be populated before verify mode is enabled. + + ── TLS-option additions ───────────────────────────────────────────────────── + [TLSOPT-1] SetPrivateKeyPassword(string) override + password-aware SetPrivateKey. + Stores a passphrase; the next SetPrivateKey parses an encrypted PEM + key with PEM_read_bio_PrivateKey + a password callback, then + SSL_CTX_use_PrivateKey. Empty passphrase keeps the unencrypted path. + [TLSOPT-2] SetCipherList(string) override. + Calls SSL_CTX_set_cipher_list to override the TLS 1.2 cipher list; + raises if the string selects no ciphers. TLS 1.3 suites unchanged. } interface @@ -160,6 +169,7 @@ TPendingWrite = record TCrossOpenSslSocket = class(TCrossSslSocketBase) private FSslCtx: PSSL_CTX; + FPKeyPassword: AnsiString; // [TLSOPT-1] passphrase for an encrypted key procedure _InitSslCtx; procedure _FreeSslCtx; @@ -199,6 +209,12 @@ TCrossOpenSslSocket = class(TCrossSslSocketBase) (handshake fails without a valid client cert) AVerify=False → SSL_VERIFY_NONE (default) } procedure SetVerifyPeer(const AVerify: Boolean); override; + { ── TLSOPT-1: store the passphrase used to decrypt an encrypted PEM private + key. Applied by the next SetPrivateKey call. } + procedure SetPrivateKeyPassword(const APassword: string); override; + + { ── TLSOPT-2: override the TLS 1.2 cipher list via SSL_CTX_set_cipher_list. } + procedure SetCipherList(const ACipherList: string); override; end; {$IFDEF CROSS_OPENSSL_SELFTEST} @@ -1141,11 +1157,87 @@ procedure TCrossOpenSslSocket.SetCertificate(const ACertBuf: Pointer; TSSLTools.SetCertificate(FSslCtx, ACertBuf, ACertBufSize); end; +{ ── TLSOPT-1: OpenSSL PEM password callback ────────────────────────────────── + OpenSSL calls this to obtain the passphrase for an encrypted PEM key. AUserData + points to a null-terminated copy of the passphrase (PAnsiChar of an AnsiString). + Copies up to ASize bytes into ABuf and returns the length. No RTL dependency + (manual null-scan) so the unit stays dual-compile (Delphi + FPC). } +function _IcsHorsePemPasswdCb(ABuf: Pointer; ASize, ARWFlag: Integer; + AUserData: Pointer): Integer; cdecl; +var + P: PAnsiChar; + LLen: Integer; +begin + Result := 0; + if (AUserData = nil) or (ASize <= 0) then Exit; + P := PAnsiChar(AUserData); + LLen := 0; + while (P[LLen] <> #0) and (LLen < ASize) do + Inc(LLen); + if LLen > 0 then + Move(P^, ABuf^, LLen); + Result := LLen; +end; + procedure TCrossOpenSslSocket.SetPrivateKey(const APKeyBuf: Pointer; const APKeyBufSize: Integer); +var + LBio: PBIO; + LPKey: PEVP_PKEY; begin - if Ssl then + if not Ssl or (FSslCtx = nil) then Exit; + + // Unencrypted key (no passphrase set) — unchanged upstream behaviour. + if FPKeyPassword = '' then + begin TSSLTools.SetPrivateKey(FSslCtx, APKeyBuf, APKeyBufSize); + Exit; + end; + + // [TLSOPT-1] Encrypted PEM key — parse with the passphrase callback (mirrors + // the SetCACertificate BIO + PEM_read pattern), then install into the context. + LBio := BIO_new_mem_buf(APKeyBuf, APKeyBufSize); + if LBio = nil then + raise ESsl.Create('SetPrivateKey: BIO_new_mem_buf failed'); + try + LPKey := PEM_read_bio_PrivateKey(LBio, nil, @_IcsHorsePemPasswdCb, + PAnsiChar(FPKeyPassword)); + if LPKey = nil then + raise ESsl.Create( + 'SetPrivateKey: PEM_read_bio_PrivateKey failed — wrong passphrase or ' + + 'the buffer is not a valid PEM private key'); + try + if SSL_CTX_use_PrivateKey(FSslCtx, LPKey) <> 1 then + raise ESsl.Create('SetPrivateKey: SSL_CTX_use_PrivateKey failed'); + finally + EVP_PKEY_free(LPKey); + end; + finally + BIO_free(LBio); + end; +end; + +{ ── TLSOPT-1: store the passphrase for the next SetPrivateKey call. ────────── } +procedure TCrossOpenSslSocket.SetPrivateKeyPassword(const APassword: string); +begin + FPKeyPassword := AnsiString(APassword); +end; + +{ ── TLSOPT-2: override the TLS 1.2 cipher list. SSL_CTX_set_cipher_list returns + 1 on success; a string that selects no ciphers returns 0. TLS 1.3 suites are + left at the _InitSslCtx defaults (they use a different naming/API). } +procedure TCrossOpenSslSocket.SetCipherList(const ACipherList: string); +var + LAnsi: AnsiString; +begin + if not Ssl or (FSslCtx = nil) or (ACipherList = '') then Exit; + LAnsi := AnsiString(ACipherList); + // MarshaledAString = PAnsiChar; pass the AnsiString's buffer directly + // (mirrors the literal calls in _InitSslCtx). + if SSL_CTX_set_cipher_list(FSslCtx, PAnsiChar(LAnsi)) <> 1 then + raise ESsl.Create( + 'SetCipherList: SSL_CTX_set_cipher_list rejected "' + ACipherList + + '" (no matching ciphers)'); end; { ── MTLS-1: load a CA certificate (PEM buffer) into the SSL context ────────── From a0f53e0c7d2caaa5ae8227469fb268e9c8fc53c9 Mon Sep 17 00:00:00 2001 From: freitasjca Date: Mon, 29 Jun 2026 17:03:47 +0100 Subject: [PATCH 13/15] feat(ssl): add TLSOPT-1/2 (SetPrivateKeyPassword, SetCipherList) + FPC StaticZLib stack-guard --- DelphiToFPC/DTF.StaticZLib.pas | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/DelphiToFPC/DTF.StaticZLib.pas b/DelphiToFPC/DTF.StaticZLib.pas index 1e3f32c..5ebcc69 100644 --- a/DelphiToFPC/DTF.StaticZLib.pas +++ b/DelphiToFPC/DTF.StaticZLib.pas @@ -1242,5 +1242,22 @@ procedure zlibFreeMem(AppData, Block: Pointer); cdecl; FreeMem(Block); end; +{$ifdef FPC} +{$ifdef MSWINDOWS} +// libz.a from msys2/MinGW is compiled with -fstack-protector, which emits +// references to two symbols in every object file: +// __stack_chk_guard — the canary value loaded onto the stack at function entry +// __stack_chk_fail — called when the canary is corrupted on return +// FPC does not link libssp automatically, and libssp_nonshared.a is absent +// from GCC 15+ installs. These stubs satisfy both linker references. +var + StackChkGuard: PtrUInt; [public, alias: '__stack_chk_guard']; + +procedure StackChkFail; [public, alias: '__stack_chk_fail']; +begin + Halt(127); +end; +{$endif} +{$endif} end. From 15522177701a24fcfcd3e7dde29341a1272d080a Mon Sep 17 00:00:00 2001 From: freitasjca Date: Mon, 29 Jun 2026 17:40:02 +0100 Subject: [PATCH 14/15] =?UTF-8?q?revert:=20remove=20stack-chk=20stubs=20fr?= =?UTF-8?q?om=20DTF.StaticZLib=20=E2=80=94=20keep=20file=20identical=20to?= =?UTF-8?q?=20upstream?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DelphiToFPC/DTF.StaticZLib.pas | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/DelphiToFPC/DTF.StaticZLib.pas b/DelphiToFPC/DTF.StaticZLib.pas index 5ebcc69..5011e16 100644 --- a/DelphiToFPC/DTF.StaticZLib.pas +++ b/DelphiToFPC/DTF.StaticZLib.pas @@ -1242,22 +1242,4 @@ procedure zlibFreeMem(AppData, Block: Pointer); cdecl; FreeMem(Block); end; -{$ifdef FPC} -{$ifdef MSWINDOWS} -// libz.a from msys2/MinGW is compiled with -fstack-protector, which emits -// references to two symbols in every object file: -// __stack_chk_guard — the canary value loaded onto the stack at function entry -// __stack_chk_fail — called when the canary is corrupted on return -// FPC does not link libssp automatically, and libssp_nonshared.a is absent -// from GCC 15+ installs. These stubs satisfy both linker references. -var - StackChkGuard: PtrUInt; [public, alias: '__stack_chk_guard']; - -procedure StackChkFail; [public, alias: '__stack_chk_fail']; -begin - Halt(127); -end; -{$endif} -{$endif} - end. From bde8f50532d750ac37a64e3d4f3904158d8f0aff Mon Sep 17 00:00:00 2001 From: freitasjca Date: Wed, 1 Jul 2026 16:43:48 +0100 Subject: [PATCH 15/15] chore(release): bump version to 1.0.4 --- DelphiToFPC/DTF.StaticZLib.pas | 1 + boss.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/DelphiToFPC/DTF.StaticZLib.pas b/DelphiToFPC/DTF.StaticZLib.pas index 5011e16..1e3f32c 100644 --- a/DelphiToFPC/DTF.StaticZLib.pas +++ b/DelphiToFPC/DTF.StaticZLib.pas @@ -1242,4 +1242,5 @@ procedure zlibFreeMem(AppData, Block: Pointer); cdecl; FreeMem(Block); end; + end. diff --git a/boss.json b/boss.json index 0144286..aac5229 100644 --- a/boss.json +++ b/boss.json @@ -1,7 +1,7 @@ { "name": "delphi-cross-socket", "description": "Delphi cross-platform async socket library (IOCP/epoll/kqueue) with HTTP server and OpenSSL 3.x support. Fork of winddriver/Delphi-Cross-Socket — adds Boss package manifest only. Zero source changes.", - "version": "1.0.3", + "version": "1.0.4", "homepage": "https://github.com/freitasjca/Delphi-Cross-Socket", "license": "MIT", "mainsrc": "Net/",

GjU1lO-!A@MOz*mL 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 WtWPF_AP}eC1XBtgT&1reuKxu#%R$fp diff --git a/CnPack/Crypto/CnNative.dcu b/CnPack/Crypto/CnNative.dcu deleted file mode 100644 index 6b75b118ea19893f0e12fe282c3f47c9989c3dbf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48972 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 diff --git a/CnPack/Crypto/CnPemUtils.dcu b/CnPack/Crypto/CnPemUtils.dcu deleted file mode 100644 index b14a181ea709064b3476fff66071bca6173099f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16968 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 HV0HfoxNO-h diff --git a/CnPack/Crypto/CnRandom.dcu b/CnPack/Crypto/CnRandom.dcu deleted file mode 100644 index c89e954877a4cd1e8e54c20ff7c9e1f2ca04318b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5673 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 diff --git a/CnPack/Crypto/CnSHA1.dcu b/CnPack/Crypto/CnSHA1.dcu deleted file mode 100644 index a3f75043eb9f12c9d50a84dbf880dc9592c6e5f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10859 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 QlTU=35CcrI#ct;Ke<$eb%>V!Z diff --git a/CnPack/Crypto/CnSHA2.dcu b/CnPack/Crypto/CnSHA2.dcu deleted file mode 100644 index b080c2a50656f8ebf30bc3076405071038294457..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30907 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