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 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.pas b/CnPack/Crypto/CnAES.pas new file mode 100644 index 0000000..8f0a8da --- /dev/null +++ b/CnPack/Crypto/CnAES.pas @@ -0,0 +1,7569 @@ +{******************************************************************************} +{ 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 字节 Nonce、8 字节 +* 初始化向量,4 字节网络字节序的计数器,拼成 16 字节的真正的初始化向量 +* 参与 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 模式下的初始化向量结构,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 密钥字符串,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 #0 + KeyBit: TCnKeyBitType - AES 加密类型 + + 返回值:AnsiString - 返回密文十六进制字符串 +} + +function AESDecryptEcbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES ECB 解密十六进制字符串。 + + 参数: + const HexStr: AnsiString - 待解密的十六进制密文字符串 + Key: AnsiString - AES 密钥字符串,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 #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 密钥字符串,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 #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 密钥字符串,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 #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 密钥字符串,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 #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 密钥字符串,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 #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 密钥字符串,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 #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 密钥字符串,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 #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 密钥字符串,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 #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 密钥字符串,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 #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 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 0 + KeyBit: TCnKeyBitType - AES 加密类型 + + 返回值:TBytes - 返回密文字节数组 +} + +function AESDecryptEcbBytes(Value: TBytes; Key: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES ECB 模式解密字节数组。 + + 参数: + Value: TBytes - 待解密的密文字节数组 + Key: TBytes - AES 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 0 + KeyBit: TCnKeyBitType - AES 加密类型 + + 返回值:TBytes - 返回明文字节数组 +} + +function AESEncryptCbcBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CBC 模式加密字节数组。 + + 参数: + Value: TBytes - 待加密的明文字节数组 + Key: TBytes - AES 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 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 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 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 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 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 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 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 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 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 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 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 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 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 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 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 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 0 + KeyBit: TCnKeyBitType - AES 加密类型 + + 返回值:AnsiString - 返回密文十六进制字符串 +} + +function AESDecryptEcbBytesFromHex(const HexStr: AnsiString; Key: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES ECB 解密十六进制字符串并返回字节数组。 + + 参数: + const HexStr: AnsiString - 待解密的十六进制密文字符串 + Key: TBytes - AES 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 0 + KeyBit: TCnKeyBitType - AES 加密类型 + + 返回值:TBytes - 返回明文字节数组 +} + +function AESEncryptCbcBytesToHex(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CBC 模式加密字节数组并将其转换成十六进制。 + + 参数: + Value: TBytes - 待加密的明文字节数组 + Key: TBytes - AES 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 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 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 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 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 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 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 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 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 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 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 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 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 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 密钥字节数组,长度根据加密类型确定为 16、24、32 字节,太长则截断,不足则补 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); // 最后写入的只包括密文长度的部分,无需整个块 + 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); // 最后写入的只包括密文长度的部分,无需整个块 + 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); // 最后写入的只包括密文长度的部分,无需整个块 + 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); // 最后写入的只包括密文长度的部分,无需整个块 + 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); // 最后写入的只包括密文长度的部分,无需整个块 + 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 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; + +//------------------------------------------------------------------------------ +// 编码的参考表 +//------------------------------------------------------------------------------ + + 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', '-', '_', + '='); + +//------------------------------------------------------------------------------ +// 解码的参考表 +//------------------------------------------------------------------------------ + + { 不包含在 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 下不知道怎么的不能用 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.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.pas b/CnPack/Crypto/CnDES.pas new file mode 100644 index 0000000..c255235 --- /dev/null +++ b/CnPack/Crypto/CnDES.pas @@ -0,0 +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 的加密 Key,8 字节} + + TCnDESBuffer = array[0..CN_DES_BLOCKSIZE - 1] of Byte; + {* DES 的加密块,8 字节} + + TCnDESIv = array[0..CN_DES_BLOCKSIZE - 1] of Byte; + {* DES 的 CBC 的初始化向量,8 字节} + + TCn3DESKey = array[0..CN_TRIPLE_DES_KEYSIZE - 1] of Byte; + {* 3DES 的密钥长度,是 DES 的三倍,24 字节} + + TCn3DESBuffer = TCnDESBuffer; + {* 3DES 的加密块,等于 DES 的加密块,8 字节} + + TCn3DESIv = TCnDESIv; + {* 3DES 的 CBC 的初始化向量,等于 DES 的 CBC 的初始化向量,8 字节} + +// ================================= DES ======================================= + +function DESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +{* 根据输入明文字节长度计算 DES 块对齐的输出长度。如果非块整数倍则向上增长至块整数倍。 + + 参数: + InputByteLength: Integer - 输入的明文字节长度 + + 返回值:Integer - 返回 DES 块对齐后的长度 +} + +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; +{* 传入明文与加密 Key,DES 加密返回转换成十六进制的密文,块间使用 ECB 模式,明文末尾可能补 #0。 + + 参数: + const Str: AnsiString - 待加密的明文字符串 + const Key: AnsiString - 8 字节 DES 密钥,太长则截断,不足则补 #0 + + 返回值:AnsiString - 返回加密后的十六进制密文字符串 +} + +function DESDecryptEcbStrFromHex(const HexStr: AnsiString; const Key: AnsiString): AnsiString; +{* 传入十六进制的密文与加密 Key,DES 解密返回明文,块间使用 ECB 模式。 + + 参数: + const HexStr: AnsiString - 待解密的十六进制密文字符串 + const Key: AnsiString - 8 字节 DES 密钥,太长则截断,不足则补 #0 + + 返回值:AnsiString - 返回解密后的明文字符串 +} + +function DESEncryptCbcStrToHex(const Str: AnsiString; const Key: AnsiString; const Iv: AnsiString): AnsiString; +{* 传入明文与加密 Key 与 Iv,DES 加密返回转换成十六进制的密文,块间使用 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 与 Iv,DES 解密返回明文,块间使用 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; +{* 传入明文与加密 Key,3DES 加密返回转换成十六进制的密文,块间使用 ECB 模式,明文末尾可能补 #0。 + + 参数: + const Str: AnsiString - 待加密的明文字符串 + const Key: AnsiString - 24 字节 3DES 密钥,太长则截断,不足则补 #0 + + 返回值:AnsiString - 返回加密后的十六进制密文字符串 +} + +function TripleDESDecryptEcbStrFromHex(const HexStr: AnsiString; const Key: AnsiString): AnsiString; +{* 传入十六进制的密文与加密 Key,3DES 解密返回明文,块间使用 ECB 模式。 + + 参数: + const HexStr: AnsiString - 待解密的十六进制密文字符串 + const Key: AnsiString - 24 字节 3DES 密钥,太长则截断,不足则补 #0 + + 返回值:AnsiString - 返回解密后的明文字符串 +} + +function TripleDESEncryptCbcStrToHex(const Str: AnsiString; const Key: AnsiString; + const Iv: AnsiString): AnsiString; +{* 传入明文与加密 Key 与 Iv,3DES 加密返回转换成十六进制的密文,块间使用 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 与 Iv,3DES 解密返回明文,块间使用 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.pas b/CnPack/Crypto/CnFloat.pas new file mode 100644 index 0000000..a727541 --- /dev/null +++ b/CnPack/Crypto/CnFloat.pas @@ -0,0 +1,1354 @@ +{******************************************************************************} +{ 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 单元中的常量 NaN +* Infinity 为无穷大,定义参看 Math.pas 单元中的常量 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 符号位 S,8 位指数 E,23 位有效数 M,共 4 字节 32 位 + 双精度 Double 1 符号位 S,11 位指数 E,52 位有效数 M,共 8 字节 64 位 + 扩展双精度 Extended 1 符号位 S,15 位指数 E,64 位有效数 M,共 10 字节 80 位 + + IEEE 754-2008 加了 + 四倍精度 Quadruple 1 符号位 S,15 位指数 E,112 位有效数 M,共 16 字节 128 位 + 八倍精度 Octuple 1 符号位 S,19 位指数 E,236 位有效数 M,共 32 字节 256 位 + + 其中,符号位 S,0 表示正,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 是标准的 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 - 返回是否非实数 +} + +// FPC、Windows 64/Linux 64 等平台以及 Delphi 5、6 不支持以下三个函数 +{$IFDEF WIN32} +{$IFDEF COMPILER7_UP} + +{ FloatDecimalToBinExtended, FloatDecimalToOctExtended,FloatDecimalToHexExtended + 均调用了 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.pas b/CnPack/Crypto/CnKDF.pas new file mode 100644 index 0000000..8fc6ab4 --- /dev/null +++ b/CnPack/Crypto/CnKDF.pas @@ -0,0 +1,807 @@ +{******************************************************************************} +{ 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 我们不支持} + + TCnPBKDF2KeyHash = (cpdfSha1Hmac, cpdfSha256Hmac); + {* PBKDF2 规定的两种杂凑方法} + + TCnHKDFHash = (chkMd5, chkSha1, chkSha256, chkSha3_256, chkSm3); + {* HKDF(HMAC-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 密钥派生函数。输入 IKM、Salt 和 Info,产生指定长度的密钥。 + Salt 可为空,空则内部使用固定杂凑结果长度的全 0,Info 可为空。返回生成的密钥。 + + 参数: + 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 密钥派生函数。输入 IKM、Salt 和 Info 的字节数组,产生指定长度的密钥。 + Salt 可为空,空则内部使用固定杂凑结果长度的全 0,Info 可为空。返回生成的密钥。 + + 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.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 的 HMAC(Hash-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.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 而动态变化,影响到的是 Pointer、Reference等东西。 +* 考虑到兼容性,固定长度的 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 位无符号整数值,分别根据比较的结果是大于、等于还是小于来返回 1、0、-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 位整数的某一位置 1,位 Index 从 0 开始到 63。 + + 参数: + var B: TUInt64 - 待置位的值 + Index: Integer - 待置 1 的位序号 + + 返回值:(无) +} + +procedure UInt64ClearBit(var B: TUInt64; Index: Integer); +{* 给 64 位整数的某一位置 0,位 Index 从 0 开始到 63。 + + 参数: + var B: TUInt64 - 待置位的值 + Index: Integer - 待置 0 的位序号 + + 返回值:(无) +} + +function GetUInt64BitSet(B: TUInt64; Index: Integer): Boolean; +{* 返回 64 位整数的某一位是否是 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 Mod,M 碰到负值时取反求模再模减,但 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; +{* 返回内存块某 Bit 位是否置 1,内存地址低位是 0,字节内还是右边为 0。 + + 参数: + Mem: Pointer - 待处理的数据块地址 + N: Integer - 位索引号 + + 返回值:Boolean - 返回是否是 1 +} + +procedure MemorySetBit(Mem: Pointer; N: Integer); +{* 给内存块某 Bit 位置 1,内存地址低位是 0,字节内还是右边为 0。 + + 参数: + Mem: Pointer - 待处理的数据块地址 + N: Integer - 位索引号 + + 返回值:(无) +} + +procedure MemoryClearBit(Mem: Pointer; N: Integer); +{* 给内存块某 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; +{* 以无符号整数的方式比较两块内存,返回 1、0、-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 位整数进行算术右移,也就是保留符号位的右移。 + + 参数: + var V: Byte - 待算术右移的 8 位整数 + ShiftCount: Integer - 算术右移的位数 + + 返回值:Byte - 返回移位后的值 +} + +function SarInt16(var V: Word; ShiftCount: Integer): Word; +{* 将一 16 位整数进行算术右移,也就是保留符号位的右移。 + + 参数: + var V: Word - 待算术右移的 16 位整数 + ShiftCount: Integer - 算术右移的位数 + + 返回值:Word - 返回移位后的值 +} + +function SarInt32(var V: Cardinal; ShiftCount: Integer): Cardinal; +{* 将一 32 位整数进行算术右移,也就是保留符号位的右移。 + + 参数: + var V: Cardinal - 待算术右移的 32 位整数 + ShiftCount: Integer - 算术右移的位数 + + 返回值:Cardinal - 返回移位后的值 +} + +function SarInt64(var V: TUInt64; ShiftCount: Integer): TUInt64; +{* 将一 64 位整数进行算术右移,也就是保留符号位的右移。 + + 参数: + var V: TUInt64 - 待算术右移的 64 位整数 + ShiftCount: Integer - 算术右移的位数 + + 返回值:TUInt64 - 返回移位后的值 +} + +// ================ 以下是执行时间固定的无 if 判断的部分逻辑函数 =============== + +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 也就是参数一 + A: Byte - 待选择的 8 位整数一 + B: Byte - 待选择的 8 位整数二 + + 返回值:Byte - 返回选择的 8 位整数 +} + +function ConstTimeConditionalSelect16(Condition: Boolean; A: Word; B: Word): Word; +{* 针对两个双字节变量执行时间固定的判断选择,Condtion 为 True 时返回 A,否则返回 B。 + + 参数: + Condition: Boolean - 是否选择 A 也就是参数一 + A: Word - 待选择的 16 位整数一 + B: Word - 待选择的 16 位整数二 + + 返回值:Word - 返回选择的 16 位整数 +} + +function ConstTimeConditionalSelect32(Condition: Boolean; A: Cardinal; B: Cardinal): Cardinal; +{* 针对两个四字节变量执行时间固定的判断选择,Condtion 为 True 时返回 A,否则返回 B + + 参数: + Condition: Boolean - 是否选择 A 也就是参数一 + A: Cardinal - 待选择的 32 位整数一 + B: Cardinal - 待选择的 32 位整数二 + + 返回值:Cardinal - 返回选择的 32 位整数 +} + +function ConstTimeConditionalSelect64(Condition: Boolean; A: TUInt64; B: TUInt64): TUInt64; +{* 针对两个八字节变量执行时间固定的判断选择,Condtion 为 True 时返回 A,否则返回 B + + 参数: + Condition: Boolean - 是否选择 A 也就是参数一 + A: TUInt64 - 待选择的 64 位整数一 + B: TUInt64 - 待选择的 64 位整数二 + + 返回值:TUInt64 - 返回选择的 64 位整数 +} + +// ================ 以上是执行时间固定的无 if 判断的部分逻辑函数 =============== + +{$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 位是否为 1,N 从 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 位为 1,N 从 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 位 A,N 为 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 - 待转换的布尔值 + 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); 以只填充不满的部分 + 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 非纯 $FF,R 里头有 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 得到 00000000,False 得到 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 在 RCX,AHi 在 RDX,B 在 R8,DivRes 的地址在 R9, +procedure Int128DivInt64Mod(ALo, AHi: Int64; B: Int64; var DivRes, ModRes: Int64); assembler; +asm + MOV RAX, RCX // ALo 放入 RAX,AHi 已经在 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 放入 RAX,AHi 已经在 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 在 EAX,DivRes 地址在 EDX,ModRes 地址在 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 -> EAX,B -> 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 占 0、1,x+z 是 R1 占 1、2,把 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 + // 各项系数都是 UInt64,xz 占 2、3、4,xt+yz 占 1、2、3,yt 占 0、1,然后累加 + 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 的某一位置 1,位 Index 从 0 开始 +procedure UInt64SetBit(var B: TUInt64; Index: Integer); +begin + B := B or (TUInt64(1) shl Index); +end; + +// 给 UInt64 的某一位置 0,位 Index 从 0 开始 +procedure UInt64ClearBit(var B: TUInt64; Index: Integer); +begin + B := B and not (TUInt64(1) shl Index); +end; + +// 返回 UInt64 的第几位是否是 1,0 开始 +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^63,N 至少是 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.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 取 0、1、2,BlockLen 字节数如 128 等。格式形如 + EB = 00 || BT || PS || 00 || D + 其中 00 是前导规定字节,BT 是 1 字节的 PaddingType,0 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 对齐后的长度。 + + 参数: + 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 对齐后的长度。 + + 参数: + 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))); // 得到加密时使用的初始化向量 + 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.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.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 的 HMAC(Hash-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.pas b/CnPack/Crypto/CnSHA2.pas new file mode 100644 index 0000000..dfcc2aa --- /dev/null +++ b/CnPack/Crypto/CnSHA2.pas @@ -0,0 +1,2337 @@ +{******************************************************************************} +{ 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, +* 原因是基于补码规则,有无符号数的加减移位以及溢出的舍弃机制等都相同,唯一不 +* 同的是比较,而本单元中没有类似的比较。 +* 开发平台: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/384。D567下用有符号 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 的 HMAC(Hash-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 的 HMAC(Hash-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 的 HMAC(Hash-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 的 HMAC(Hash-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.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 的 HMAC(Hash-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 的 HMAC(Hash-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 的 HMAC(Hash-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 的 HMAC(Hash-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 中的初始位置指针 + 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.pas b/CnPack/Crypto/CnSM3.pas new file mode 100644 index 0000000..53106c6 --- /dev/null +++ b/CnPack/Crypto/CnSM3.pas @@ -0,0 +1,829 @@ +{******************************************************************************} +{ 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 的 HMAC(Hash-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 时返回值仍为 X,N 为 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. diff --git a/Net/Net.CrossSslSocket.Base.pas b/Net/Net.CrossSslSocket.Base.pas index 0b1c52f..22187f5 100644 --- a/Net/Net.CrossSslSocket.Base.pas +++ b/Net/Net.CrossSslSocket.Base.pas @@ -105,6 +105,44 @@ interface /// procedure SetPrivateKeyFile(const APKeyFile: string); + // 鈹鈹 mTLS (mutual TLS / client-certificate authentication) 鈹鈹鈹鈹鈹鈹鈹鈹鈹鈹鈹鈹鈹鈹鈹鈹 + // [MTLS-1] Load the CA certificate used to verify client certificates. + // Call before Listen/Start. Required when VerifyPeer = True. + // The concrete implementation (TCrossOpenSslSocket) calls + // SSL_CTX_add_client_CA + X509_STORE_add_cert on its private FContext. + + ///