diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..b24acd2 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,41 @@ +# Conservative policy for an upstream-synced fork: do NOT globally normalise +# (that would drift the fork from winddriver on every sync). Only force endings +# where a wrong one breaks the file, and keep vendored/byte-exact files intact. + +# Scripts & CI — a wrong ending breaks these +*.sh text eol=lf +*.bat text eol=crlf +*.cmd text eol=crlf +*.ps1 text eol=crlf +*.yml text eol=lf +*.yaml text eol=lf + +# Vendored CnPack (GBK-encoded) + patches — never normalise; stay identical to source +CnPack/** -text +*.patch -text +*.diff -text + +# Certs / keys — exact bytes +*.crt binary +*.cer binary +*.der binary +*.pem binary +*.key binary +*.pfx binary +*.p12 binary + +# Binaries / build artifacts +*.png binary +*.jpg binary +*.gif binary +*.ico binary +*.res binary +*.dcr binary +*.dcu binary +*.dcp binary +*.exe binary +*.dll binary +*.so binary +*.dylib binary +# NOTE: *.pas/.dpr/.inc/.dproj are intentionally NOT listed — left to core.autocrlf +# so the fork stays byte-close to upstream after each sync. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5c8da91 --- /dev/null +++ b/.gitignore @@ -0,0 +1,83 @@ +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 + +# Claude Code +.claude/settings.local.json +.claude.json +CLAUDE.md + +# Delphi build output +__history/ +__recovery/ +*.dcu +*.exe +*.dll +*.bpl +*.dcp +*.local +*.identcache +*.tvsconfig +*.dsk +*.dproj.local +*.dsv diff --git a/CnPack/Common/CnConsts.pas b/CnPack/Common/CnConsts.pas new file mode 100644 index 0000000..792eb93 --- /dev/null +++ b/CnPack/Common/CnConsts.pas @@ -0,0 +1,252 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnConsts; +{* |
+================================================================================ +* ƣ +* ԪƣԴַ嵥Ԫ +* ԪߣCnPack +* ע +* ƽ̨PWin98SE + Delphi 5.0 +* ݲԣPWin9X/2000/XP + Delphi 5/6 +* õԪеַϱػʽ +* ļ¼2005.12.24 V1.0 +* ԪֲӢַ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +const + ECN_OK = 0; // OK + + ECN_FILE_NOT_FOUND = $10; // ļ + + ECN_CUSTOM_ERROR_BASE = $1000; // 趨Ĵʼֵ + +//============================================================================== +// Strings DO NOT Localize: +//============================================================================== + +resourcestring + + // CnPack Reg Path + SCnPackRegPath = '\Software\CnPack'; + + // Tools Reg Path + SCnPackToolRegPath = 'CnTools'; + +//============================================================================== +// Strings to be Localized: +//============================================================================== + + +var + // Common Information + SCnHint: string = 'Hint'; + SCnInformation: string = 'Information'; + SCnWarning: string = 'Warning'; + SCnError: string = 'Error'; + SCnEnabled: string = 'Enabled'; + SCnDisabled: string = 'Disabled'; + SCnMsgDlgOK: string = '&OK'; + SCnMsgDlgCancel: string = '&Cancel'; + SCnMsgDlgYes: string = '&Yes'; + SCnMsgDlgNo: string = '&No'; + SCnMsgDlgYesToAll: string = 'Yes to &All'; + SCnMsgDlgNoToAll: string = 'No to A&ll'; + SCnVersion: string = 'Version'; + SCnNeedAdmin: string = 'Maybe Need Administrator'; + SCnNotSupport: string = 'Operation Not Supported'; + +const + // CnPack Information + SCnPackAbout = 'CnPack'; + SCnPackVer = 'Ver 0.1.8.0'; + SCnPackStr = SCnPackAbout + ' ' + SCnPackVer; + SCnPackUrl = 'https://www.cnpack.org'; + SCnPackBbsUrl = 'https://bbs.cnpack.org'; + SCnPackNewsUrl = 'news://news.cnpack.org'; + SCnPackSourceUrl = 'https://github.com/cnpack'; + SCnPackEmail = 'master@cnpack.org'; + SCnPackBugEmail = 'bugs@cnpack.org'; + SCnPackSuggestionsEmail = 'suggestions@cnpack.org'; + + SCnPackDonationUrl = 'https://www.cnpack.org/donation.php'; + SCnPackDonationUrlSF = 'http://sourceforge.net/donate/index.php?group_id=110999'; + SCnPackGroup = 'CnPack Team'; + SCnPackCopyright = '(C)Copyright 2001-2026 ' + SCnPackGroup; + + // CnPropEditors + SCopyrightFmtStr = + SCnPackStr + #13#10#13#10 + + 'Component Name: %s' + #13#10 + + 'Author: %s(%s)' + #13#10 + + 'Comment: %s' + #13#10 + + 'HomePage: ' + SCnPackUrl + #13#10 + + 'Email: ' + SCnPackEmail + #13#10#13#10 + + SCnPackCopyright; + +resourcestring + + // Component Palette Name + SCnNonVisualPalette = 'CnPack Tools'; + SCnGraphicPalette = 'CnPack VCL'; + SCnNetPalette = 'CnPack Net'; + SCnDatabasePalette = 'CnPack DB'; + SCnReportPalette = 'CnPack Report'; + + // CnPack Developers Added from Last. +var + SCnPack_Team: string = 'CnPack Team'; + SCnPack_Zjy: string = 'Zhou JingYu'; + SCnPack_Shenloqi: string = 'Chinbo'; + SCnPack_xiaolv: string = 'xiaolv'; + SCnPack_Flier: string = 'Flier Lu'; + SCnPack_LiuXiao: string = 'Liu Xiao'; + SCnPack_PanYing: string = 'Pan Ying'; + SCnPack_Hubdog: string = 'Hubdog'; + SCnPack_Wyb_star: string = 'wyb_star'; + SCnPack_Licwing: string = 'Licwing zue'; + SCnPack_Alan: string = 'Alan'; + SCnPack_GuYueChunQiu: string = 'GuYueChunQiu'; + SCnPack_Aimingoo: string = 'Aimingoo'; + SCnPack_QSoft: string = 'QSoft'; + SCnPack_Hospitality: string = 'ZhangJiongXuan (Hospitality)'; + SCnPack_SQuall: string = 'SQUALL'; + SCnPack_Hhha: string = 'Hhha'; + SCnPack_Beta: string = 'beta'; + SCnPack_Leeon: string = 'Leeon'; + SCnPack_SuperYoyoNc: string = 'SuperYoyoNC'; + SCnPack_JohnsonZhong: string = 'Johnson Zhong'; + SCnPack_DragonPC: string = 'Dragon P.C.'; + SCnPack_Kendling: string = 'Kending'; + SCnPack_ccrun: string = 'ccrun'; + SCnPack_Dingbaosheng: string = 'dingbaosheng'; + SCnPack_LuXiaoban: string = 'Zhou Yibo(Lu Xiaoban)'; + SCnPack_Savetime: string = 'savetime'; + SCnPack_solokey: string = 'solokey'; + SCnPack_Bahamut: string = 'Bahamut'; + SCnPack_Sesame: string = 'Sesame'; + SCnPack_BuDeXian: string = 'BuDeXian'; + SCnPack_XiaoXia: string = 'Summer'; + SCnPack_ZiMin: string = 'ZiMin'; + SCnPack_rarnu: string = 'rarnu'; + SCnPack_dejoy: string = 'dejoy'; + SCnPack_Rain: string = 'Rain'; + SCnPack_cnwinds: string = 'cnwinds'; + + // CnCommon + SUnknowError: string = 'Unknow error'; + SErrorCode: string = 'Error code:'; + +const + SCnPack_TeamEmail = 'master@cnpack.org'; + SCnPack_ZjyEmail = 'zjy@cnpack.org'; + SCnPack_ShenloqiEmail = 'Shenloqi@hotmail.com'; + SCnPack_xiaolvEmail = 'xiaolv888@etang.com'; + SCnPack_FlierEmail = 'flier_lu@sina.com'; + SCnPack_LiuXiaoEmail = 'liuxiao@cnpack.org'; + SCnPack_PanYingEmail = 'panying@sina.com'; + SCnPack_HubdogEmail = 'hubdog@263.net'; + SCnPack_Wyb_starMail = 'wyb_star@sina.com'; + SCnPack_LicwingEmail = 'licwing@chinasystemsn.com'; + SCnPack_AlanEmail = 'BeyondStudio@163.com'; + SCnPack_GuYueChunQiuEmail = 'guyuechunqiu@cnpack.org'; + SCnPack_AimingooEmail = 'aim@263.net'; + SCnPack_QSoftEmail = 'hq.com@263.net'; + SCnPack_HospitalityEmail = 'Hospitality_ZJX@msn.com'; + SCnPack_SQuallEmail = 'squall_sa@163.com'; + SCnPack_HhhaEmail = 'Hhha@eyou.com'; + SCnPack_BetaEmail = 'beta@01cn.net'; + SCnPack_LeeonEmail = 'real-like@163.com'; + SCnPack_SuperYoyoNcEmail = 'superyoyonc@sohu.com'; + SCnPack_JohnsonZhongEmail = 'zhongs@tom.com'; + SCnPack_DragonPCEmail = 'dragonpc@21cn.com'; + SCnPack_KendlingEmail = 'kendling@21cn.com'; + SCnPack_ccRunEmail = 'info@ccrun.com'; + SCnPack_DingbaoshengEmail = 'yzdbs@msn.com'; + SCnPack_LuXiaobanEmail = 'zhouyibo2000@sina.com'; + SCnPack_SavetimeEmail = 'savetime2k@hotmail.com'; + SCnPack_solokeyEmail = 'crh611@163.com'; + SCnPack_BahamutEmail = 'fantasyfinal@126.com'; + SCnPack_SesameEmail = 'sesamehch@163.com'; + SCnPack_BuDeXianEmail = 'appleak46@yahoo.com.cn'; + SCnPack_XiaoXiaEmail = 'summercore@163.com'; + SCnPack_ZiMinEmail = '441414288@qq.com'; + SCnPack_rarnuEmail = 'rarnu@cnpack.org'; + SCnPack_dejoyEmail = 'dejoybbs@163.com'; + SCnPack_RainEmail = SCnPack_TeamEmail; // Emailÿ + SCnPack_cnwindsEmail = SCnPack_TeamEmail; + + // CnMemProf + SCnPackMemMgr = 'CnMemProf'; + SMemLeakDlgReport = 'Found %d memory leaks. [There are %d allocated before replace memory manager.]'; + SMemMgrODSReport = 'Get = %d Free = %d Realloc = %d'; + SMemMgrOverflow = 'Memory Manager''s list capability overflow, Please enlarge it!'; + SMemMgrRunTime = '%d hour(s) %d minute(s) %d second(s)'; + SOldAllocMemCount = 'There are %d allocated before replace memory manager.'; + SAppRunTime = 'Application total run time: '; + SMemSpaceCanUse = 'HeapStatus.TotalAddrSpace: %d KB'; + SUncommittedSpace = 'HeapStatus.TotalUncommitted: %d KB'; + SCommittedSpace = 'HeapStatus.TotalCommitted: %d KB'; + SFreeSpace = 'HeapStatus.TotalFree: %d KB'; + SAllocatedSpace = 'HeapStatus.TotalAllocated: %d KB'; + SAllocatedSpacePercent = 'TotalAllocated div TotalAddrSpace: %d%%'; + SFreeSmallSpace = 'HeapStatus.FreeSmall: %d KB'; + SFreeBigSpace = 'HeapStatus.FreeBig: %d KB'; + SUnusedSpace = 'HeapStatus.Unused: %d KB'; + SOverheadSpace = 'HeapStatus.Overhead: %d KB'; + SObjectCountInMemory = 'Objects count in memory: '; + SNoMemLeak = ' No memory leak.'; + SNoName = '(no name)'; + SNotAnObject = ' Not an object'; + SByte = 'Byte'; + SCommaString = ','; + SPeriodString = '.'; + +resourcestring + SCnErrorMapViewOfFile = 'MapViewOfFile Failed. '; + SCnErrorCreateFileMapping = 'CreateFileMapping Failed. '; + +function CnGetLastError: Integer; + +procedure _CnSetLastError(Err: Integer); + +implementation + +threadvar + CnErrorCode: Integer; + +function CnGetLastError: Integer; +begin + Result := CnErrorCode; +end; + +procedure _CnSetLastError(Err: Integer); +begin + CnErrorCode := Err; +end; + +end. + diff --git a/CnPack/Common/CnFloat.pas b/CnPack/Common/CnFloat.pas new file mode 100644 index 0000000..c1df9ab --- /dev/null +++ b/CnPack/Common/CnFloat.pas @@ -0,0 +1,1528 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnFloat; +{* |
+================================================================================ +* ƣ +* ԪƣתԪ +* ԪߣǬԪ(wqyfavor@163.com) +* עõԪʵ˵ȡ˫ȡչȸĽת +* +* ע Extended ֻ Win32 10 ֽڣMacOS/Linux x64 ¾ 16 ֽڣWin64 ARM ƽ̨ 8 ֽ +* ңMacOS64 µ 16 ֽչȲ IEEE 754-2008 й涨 Quadruple ʽǰ 10 ֽڽضϣ +* ڲṹͬ Win32 µչ 10 ֽڡ +* +* ƽ̨WinXP + Delphi 2009 +* ݲԣDelphi 2007 Extended ֻ֧Сģʽ +* õԪеַϱػʽ +* ļ¼2023.01.13 +* ݴ Win64 Extended 8 ֽ Double 10 ֽչȵ +* ݴ MacOS64/Linux64 µ 16 ֽ Extendedֻضϴǰ 10 ֽڣ +* 2022.02.17 +* FPC ı֧֣ +* 2021.09.05 +* תΪ UInt64֧ UInt64 Int64 棩ĺ +* 2020.11.11 +* UInt64֧ UInt64 Int64 棩תΪĺ +* 2020.06.24 +* ƴյĺ +* 2009.1.12 +* Ԫ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes, SysConst, {$IFDEF MSWINDOWS} Windows, {$ENDIF} CnNative; + +{ + IEEE 754 涨ָʽЧڵλ 0 + + Single 1 λ S8 λָ E23 λЧ M 24 λ 1 4 ֽ 32 λ + ˫ Double 1 λ S11 λָ E52 λЧ M 53 λ 1 8 ֽ 64 λ + չ˫ Extended 1 λ S15 λָ E64 λЧ M 64 λʽ 1 10 ֽ 80 λ + + IEEE 754-2008 + ı Quadruple 1 λ S15 λָ E112 λЧ M 16 ֽ 128 λ + ˱ Octuple 1 λ S19 λָ E236 λЧ M 32 ֽ 256 λ + + Уλ S0 ʾ1 ʾE Ҫȥ 127/1023/16383/16383 ָ + M: 淶/˫ȵĶ M ĸλӸ 1. Чչӣ 1. + ֵЧ 1.xxxx ʽ 2 E ηעⲻ 10 E η + + S λX ָM ЧֵʵֵΪ滯˲ҿС㣩 + + ʽ ֽ 1 ֽ 2 ֽ 3 ֽ 4 ... ֽ nÿֽڵұߵλ 0 + + 4 SXXXXXXX XMMMMMMM MMMMMMMM MMMMMMMM + 01000110 00011100 01000000 00000000 + 4 6 1 C 4 0 0 0 ڴΪСˣȫֵʵֵ 10000 + Ϊ 0 10001100 00111000100000000000000 + S0X140Ҫȥ 127 õʵ 13Mԭʼֵ 1C4000 + λ 1 С㣬õ 100111000100000000000000 ΪʵЧ֣ʵֵ 1.001110001 + ʵֵ1.001110001 13 λõʮ 2710.00Сȫ 0ʮ 10000 ʵʽ + + ˫ 8 SXXXXXXX XXXXMMMM MMMMMMMM MMMMMMMM ... MMMMMMMM + 01000000 11000011 10001000 0000000000000000000000000000000000000000 + 4 0 C 3 8 8 0 0 ڴΪСˣȫֵʵֵ 10000 + Ϊ 0 10000001100 0011100010000000000000000000000000000000000000000000 + S0X1036Ҫȥ 1023 õʵ 13Mԭʼֵ 3 88 00 00 00 00 00 + λ 1 Сõ 10011100010000000000000000000000000000000000000000000 ΪʵЧ֣ʵֵ 1.001110001 + ʵֵ1.001110001 13 λõʮ 2710.00Сȫ 0ʮ 10000 ʵʽ + + չ˫ 10 SXXXXXXX XXXXXXXX 1MMMMMMM MMMMMMMM ... MMMMMMMM // עЧְ 1ʡ 1 + 01000000 00001100 10011100 01000000 ... + 4 0 0 C 9 C 4 0 ڴΪСˣȫֵʵֵ 10000 + Ϊ 0 100000000001100 1001110000100000 ... + S0X16396Ҫȥ 16383 õʵ 13Mԭʼֵ 9C 40 00 ... + λö 1ֻҪСõ 10011100 01000000 ... ΪʵЧ֣ʵֵ 1.001110001 + ʵֵ1.001110001 13 λõʮ 2710.00Сȫ 0ʮ 10000 ʵʽ + + ı 16 SXXXXXXX XXXXXXXX MMMMMMMM MMMMMMMM ... MMMMMMMM + ˱ 32 SXXXXXXX XXXXXXXX XXXXMMMM MMMMMMMM ... MMMMMMMM + + ע⣺Little Endian ϣֽ 1 n Ԫѵ + + 0ȫ 0 + -0ȫ 0 λΪ 1 + ָȫ 1Чȫ 0 0 1 +} + +type + TCnQuadruple = packed record + {* Delphi ıͣýṹָ} + Lo: TUInt64; + Hi0: Cardinal; + case Boolean of + True: (Hi1: Cardinal); + False: (W0, W1: Word); // С˻ϣźָ W1 + end; + PCnQuadruple = ^TCnQuadruple; + {* ָıȽṹָ} + + TCnOctuple = packed record + {* Delphi ް˱ͣ Int64 ָ棬} + F0: Int64; + F1: Int64; + F2: Int64; + F3: Int64; + end; + PCnOctuple = ^TCnOctuple; + {* ָ˱Ƚṹָ} + + ECnFloatSizeError = class(Exception); + {* 쳣} + +const + CN_EXTENDED_SIZE_8 = 8; + {* Win64 µ Extended ͵ijȣֻ 8 ֽ} + + CN_EXTENDED_SIZE_10 = 10; + {* Win32 µ Extended ͵ijȣDZ 10 ֽ} + + CN_EXTENDED_SIZE_16 = 16; + {* MACOS64/Linux64 µ Extended ͵ijȣ 16 ֽ} + + CN_SIGN_SINGLE_MASK = $80000000; + {* ȸķλ} + + CN_SIGN_DOUBLE_MASK = $8000000000000000; + {* ˫ȸķλ} + + CN_SIGN_EXTENDED_MASK = $8000; + {* չȸķλ룬Ѿȥ 8 ֽЧ} + + CN_SIGN_QUADRUPLE_MASK = $80000000; + {* ıȸķλ룬ֻǰֽڣȥ˺} + + CN_EXPONENT_SINGLE_MASK = $7F800000; + {* ȸָ룬Ҫ 23 λ} + + CN_EXPONENT_DOUBLE_MASK = $7FF0000000000000; + {* ˫ȸָ룬Ҫ 52 λ} + + CN_EXPONENT_EXTENDED_MASK = $7FFF; + {* չȸָ룬ȥ 8 ֽЧ} + + CN_EXPONENT_QUADRUPLE_MASK = $7FFF; + {* ıȸָ룬ȥ 14 ֽЧ} + + CN_SIGNIFICAND_SINGLE_MASK = $007FFFFF; + {* ȸЧ룬 23 λ} + + CN_SIGNIFICAND_DOUBLE_MASK = $000FFFFFFFFFFFFF; + {* ˫ȸЧ룬 52 λ} + + CN_SIGNIFICAND_EXTENDED_MASK = $FFFFFFFFFFFFFFFF; + {* չȸЧ룬 64 λʵȫ 8 ֽ} + + CN_SIGNIFICAND_QUADRUPLE_MASK = $FFFF; + {* ıȸЧ룬ֻǰֽڣмϺ} + + CN_SINGLE_SIGNIFICAND_BITLENGTH = 23; + {* ȸЧλ} + + CN_DOUBLE_SIGNIFICAND_BITLENGTH = 52; + {* ˫ȸЧλ} + + CN_EXTENDED_SIGNIFICAND_BITLENGTH = 63; + {* չȸЧλ} + + CN_EXPONENT_OFFSET_SINGLE = 127; + {* ȸָƫֵʵֵָҪϸֵܴ뵥ȸָ} + + CN_EXPONENT_OFFSET_DOUBLE = 1023; + {* ˫ȸָƫֵʵֵָҪϸֵܴ˫ȸָ} + + CN_EXPONENT_OFFSET_EXTENDED = 16383; + {* չȸָƫֵʵֵָҪϸֵܴչȸָ10 16 ֽչȸΪֵ} + + // Max ָȫ 1 Σ + CN_SINGLE_MIN_EXPONENT = -127; + {* ȸСָ} + + CN_SINGLE_MAX_EXPONENT = 127; + {* ȸָ} + + CN_DOUBLE_MIN_EXPONENT = -1023; + {* ˫ȸСָ} + + CN_DOUBLE_MAX_EXPONENT = 1023; + {* ˫ȸָ} + + CN_EXTENDED_MIN_EXPONENT = -16383; + {* չȸСָ} + + CN_EXTENDED_MAX_EXPONENT = 16383; + {* չȸָ} + +procedure ExtractFloatSingle(Value: Single; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: Cardinal); +{* ӵȸнλָλ 1 ȥСЧ֡ + ע⣺ָΪʵָЧΪ 24 λԭʼΪ 0~22 λ 23 λΪȥ 1 + + + Value: Single - ĵȸ + out SignNegative: Boolean - λTrue Ϊ + out Exponent: Integer - ָ + out Mantissa: Cardinal - Ч + + ֵޣ +} + +procedure ExtractFloatDouble(Value: Double; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: TUInt64); +{* ˫ȸнλָλ 1 ȥСЧ֡ + ע⣺ָΪʵָЧΪ 53 λԭʼΪ 0~51 λ 52 λΪȥ 1 + + + Value: Double - ˫ȸ + out SignNegative: Boolean - λTrue Ϊ + out Exponent: Integer - ָ + out Mantissa: TUInt64 - Ч + + ֵޣ +} + +procedure ExtractFloatExtended(Value: Extended; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: TUInt64); overload; +{* չȸнλָȥСЧ֣֧ 8 ֽڡ10 ֽڡ + Լ 16 ֽڽضΪ 10 ֽڵ Extended ʽúʵƽ̨ Extended ߴ硣 + ע⣺ָΪʵָЧΪȫ 64 λλ 63 λΪԴ 1 + + + Value: Extended - չȸ + out SignNegative: Boolean - λTrue Ϊ + out Exponent: Integer - ָ + out Mantissa: TUInt64 - Ч + + ֵޣ +} + +procedure ExtractFloatExtended(ValueAddr: Pointer; ExtendedSize: Integer; + out SignNegative: Boolean; out Exponent: Integer; out Mantissa: TUInt64); overload; +{* ӲȵչȸڵַнλָȥСЧ֣֧ 8 ֽڡ10 ֽڡ + Լ 16 ֽڽضΪ 10 ֽڵ Extended ʽúʵ뱾ƽ̨ Extended ߴء + ע⣺ָΪʵָЧΪȫ 64 λλ 63 λΪԴ 1 + + + ValueAddr: Pointer - չȸڵַ + ExtendedSize: Integer - չȵĴСֻ֧ 81016 ֵ + out SignNegative: Boolean - λTrue Ϊ + out Exponent: Integer - ָ + out Mantissa: TUInt64 - Ч + + ֵޣ +} + +procedure ExtractFloatQuadruple(Value: Extended; out SignNegative: Boolean; + out Exponent: Integer; out MantissaLo: TUInt64; out MantissaHi: TUInt64); +{* ʮֽھȸнλָȥСЧֻ֣ Extended Ϊ 16 ֽ + Ҹʽ IEEE 754-2008 ıȸʱЧĿǰ Delphi ָ֧øʽ + ע⣺ָΪʵָЧ 112 λΪߵ֣ԭʼΪ 0~110 λ 111 λΪȥ 1 + + + Value: Extended - ʮֽھȸ + out SignNegative: Boolean - λTrue Ϊ + out Exponent: Integer - ָ + out MantissaLo: TUInt64 - Чֵ 64 λ + out MantissaHi: TUInt64 - Чָ 64 λ + + ֵޣ +} + +procedure CombineFloatSingle(SignNegative: Boolean; Exponent: Integer; + Mantissa: Cardinal; var Value: Single); +{* ѷλָЧƴɵȸҪЧΪ滯ģҲ 24 λλΪ 1 + + + SignNegative: Boolean - λTrue Ϊ + Exponent: Integer - ָ + Mantissa: Cardinal - Ч֣ 24 λЧ + var Value: Single - ϵĵȸ + + ֵޣ +} + +procedure CombineFloatDouble(SignNegative: Boolean; Exponent: Integer; + Mantissa: TUInt64; var Value: Double); +{* ѷλָЧƴ˫ȸҪЧΪ滯ģҲ 53 λλΪ 1 + + + SignNegative: Boolean - λTrue Ϊ + Exponent: Integer - ָ + Mantissa: TUInt64 - Ч֣ 53 λЧ + var Value: Double - ϵ˫ȸ + + ֵޣ +} + +procedure CombineFloatExtended(SignNegative: Boolean; Exponent: Integer; + Mantissa: TUInt64; var Value: Extended); overload; +{* ѷλָЧƴչȸ֧ 10 ֽڡ + Լ 16 ֽڽضΪ 10 ֽڵ Extended ʽúʵƽ̨ Extended ߴ硣 + ҪЧΪ滯ģҲ 64 λλΪ 1 + + + SignNegative: Boolean - λTrue Ϊ + Exponent: Integer - ָ + Mantissa: TUInt64 - Ч֣64 λȫЧ + var Value: Extended - ϵչȸ + + ֵޣ +} + +procedure CombineFloatExtended(SignNegative: Boolean; Exponent: Integer; + Mantissa: TUInt64; ValueAddr: Pointer; ExtendedSize: Integer); overload; +{* ѷλָЧƴչȸ֧ 10 ֽڡ + Լ 16 ֽڽضΪ 10 ֽڵ Extended ʽúʵ뱾ƽ̨ Extended ߴء + ҪЧΪ滯ģҲ 64 λλΪ 1 + + + SignNegative: Boolean - λTrue Ϊ + Exponent: Integer - ָ + Mantissa: TUInt64 - Ч֣64 λȫЧ + ValueAddr: Pointer - ϵչȸĵַ + ExtendedSize: Integer - չȵĴСֻ֧ 81016 ֵ + + ֵޣ +} + +procedure CombineFloatQuadruple(SignNegative: Boolean; Exponent: Integer; + MantissaLo: TUInt64; MantissaHi: TUInt64; var Value: Extended); +{* ѷλָЧƴչȸֻ Extended Ϊ 16 ֽ + Ҹʽ IEEE 754-2008 ıȸʱЧĿǰ Delphi ָ֧øʽ + ҪЧΪ滯ģҲ 112 λλΪ 1 + + + SignNegative: Boolean - λTrue Ϊ + Exponent: Integer - ָ + MantissaLo: TUInt64 - Чֵ 64 λ64 λȫЧ + MantissaHi: TUInt64 - Чָ 64 λ 48 λЧ + var Value: Extended - ϵʮֽھȸ + + ֵޣ +} + +function UInt64ToSingle(U: TUInt64): Single; +{* Int64 зģ 64 λֵ Singleʵͬ + + + U: TUInt64 - ֵ 64 λֵ + + ֵSingle - صĵȸ +} + +function UInt64ToDouble(U: TUInt64): Double; +{* Int64 зģ 64 λֵ Doubleʵͬ + + + U: TUInt64 - ֵ 64 λֵ + + ֵDouble - ص˫ȸ +} + +function UInt64ToExtended(U: TUInt64): Extended; +{* Int64 зģ 64 λֵ Extendedʵͬ + + + U: TUInt64 - ֵ 64 λֵ + + ֵExtended - صչȸ +} + +function SingleToUInt64(F: Single): TUInt64; +{* Single ֵ Int64 зģ 64 λͣʵͬ + + + F: Single - ֵĵȸ + + ֵTUInt64 - ص 64 λֵ +} + +function DoubleToUInt64(F: Double): TUInt64; +{* Double ֵ Int64 зģ 64 λͣʵͬ + + + F: Double - ֵ˫ȸ + + ֵTUInt64 - ص 64 λֵ +} + +function ExtendedToUInt64(F: Extended): TUInt64; +{* Extended ֵ Int64 зģ 64 λͣʵͬ + + + F: Extended - ֵ˫ȸ + + ֵTUInt64 - ص 64 λֵ +} + +function SingleIsInfinite(AValue: Single): Boolean; +{* ȸǷ + + + AValue: Single - жϵĵȸ + + ֵBoolean - Ƿ +} + +function DoubleIsInfinite(AValue: Double): Boolean; +{* ˫ȸǷ + + + AValue: Double - жϵ˫ȸ + + ֵBoolean - Ƿ +} + +function ExtendedIsInfinite(AValue: Extended): Boolean; +{* չȸǷ + + + AValue: Extended - жϵչȸ + + ֵBoolean - Ƿ +} + +function SingleIsNan(AValue: Single): Boolean; +{* ȸǷʵ + + + AValue: Single - жϵĵȸ + + ֵBoolean - Ƿʵ +} + +function DoubleIsNan(AValue: Double): Boolean; +{* ˫ȸǷʵ + + + AValue: Double - жϵ˫ȸ + + ֵBoolean - Ƿʵ +} + +function ExtendedIsNan(AValue: Extended): Boolean; +{* չȸǷʵ + + + AValue: Extended - жϵչȸ + + ֵBoolean - Ƿʵ +} + +function ExtendedToStr(AValue: Extended): string; +{* չȸתΪַ֧ľȡ + Delphi Ĭ 15 λС 18Ҳ֧ 1234567899876543.21 + + + AValue: Extended - жϵչȸ + + ֵstring - ת +} + +// FPCWindows 64/Linux 64 ƽ̨Լ Delphi 56 ֧ +{$IFDEF WIN32} +{$IFDEF COMPILER7_UP} +{ + ˴ʵ Extended תΪˡʮַĺ + 㷨Ƕȡ Extended ڴеĶݽת Extended ͵˵ + ԲοϡDouble Single Ϊϵͳֵ֧ͨĸͣ Delphi е + Extended ڴ洢ʽвͬ߾β Double Single β + Ĭϵ 1βΪ 1.001 Double Single д洢Ϊ 001ȥ + Сǰ 1 Extended 洢Ϊ 1001 + NaN Ϊ "not a number"Ǹο Math.pas Ԫеij NaN + Infinity Ϊο Math.pas Ԫеij Infinity NegInfinity. + һ DecimalExp AlwaysUseExponent + ʮƸתʱָʽѧ㷨Щ + Ҳָֻʽ 1E-1000ָʱ 0.0000000...0001תָ + ҲӦӦƱʾʱʮƱʾָ֣ƴ + 1.001E101ֵΪ 100100ָʮƱһЩ 1.001D5ʾС + 5 λDecimalExp ָǷʮƱֵָġע⣬ʮ + ʾָ涨ʹ "D" ʾ"E" ΪӦƱʾ⣬ + ʮƱȽ⣬"D" "E" ΪʮַʮƱʱʹ "^" + ַ 3.BD^D(12)A.BD^E(ABCE)粻ϲָʽġ + AlwaysUseExponent ָǷһÿѧ 100.111 λȽ٣ + ԶжϲҪʹÿѧ AlwaysUseExponent ΪʱһΪָ + ʽ 1.00111E2 + const + MaxBinDigits = 120; + MaxHexDigits = 30; + MaxOctDigits = 40; + ָλʱһʹÿѧ +} + +{ FloatDecimalToBinExtended, FloatDecimalToOctExtendedFloatDecimalToHexExtended + FloatDecimalToBinaryExtended ̣FloatDecimalToBinaryExtended } + +function FloatDecimalToBinExtended(fIn: Extended; DecimalExp: Boolean; + AlwaysUseExponent: Boolean): AnsiString; deprecated; // Convert to binary + +function FloatDecimalToOctExtended(fIn: Extended; DecimalExp: Boolean; + AlwaysUseExponent: Boolean): AnsiString; deprecated; // Convert to octal + +function FloatDecimalToHexExtended(fIn: Extended; DecimalExp: Boolean; + AlwaysUseExponent: Boolean): AnsiString; deprecated; // Convert to hexdecimal + +{$ENDIF} +{$ENDIF} + +implementation + +const + UINT64_EXTENDED_EXP_MAX = $4040; // UINT64 Ӧ Extended ָ + +resourcestring + SCnErrorExtendedSizeFmt = 'Extended Size Error %d'; + +type + TExtendedRec10 = packed record + {* 10 ֽڵչȸֻ Win32 Ч} + Mantissa: TUInt64; + ExpSign: Word; + end; + PExtendedRec10 = ^TExtendedRec10; + +{$IFDEF WIN32} +{$IFDEF COMPILER7_UP} + +type + PConvertFloatSystem = ^TConvertFloatSystem; + TConvertFloatSystem = record + Negative: Boolean; + ExpFlag, ExponentI: Integer; + end; + +const + MaxBinDigits = 120; + MaxHexDigits = 30; + MaxOctDigits = 40; + +function FloatDecimalToBinaryExtended(fIn: Extended; DecimalExp, + AlwaysUseExponent: Boolean; var ForHexOct: PConvertFloatSystem): AnsiString; +var + Neg: Boolean; + i, Flag, IntExp: Integer; + Exp: AnsiString; +label UseExponent; +begin +{ +Extended(32.125) in memory: +0 100000000000100 10000000 10000000 00000000 00000000 00000000 00000000 00000000 00000000 + 9 8 7 6 5 4 3 2nd Byte 1stByte 0 +sign exponent digits +0 111111111111111 1000000000000000000000000000000000000000000000000000000000000000 + Inf +1 111111111111111 1000000000000000000000000000000000000000000000000000000000000000 - Inf +1 111111111111111 1100000000000000000000000000000000000000000000000000000000000000 Nan +0 111111111111111 1100000000000000000000000000000000000000000000000000000000000000 -Nan +} + SetLength(Result, 255); + SetLength(Exp, 2 * SizeOf(Extended) + 1); + Neg := False; + asm + push EBX + push ESI + mov EBX, Result // Address of Result + mov EBX, [EBX] + mov EAX, 0 + // Test if fIN equals 0 + lea ESI, fIn[7] // get the first byte of digits + mov AL, [ESI] + test AL, 128 // 10000000B + jz @Zero + mov ECX, 0 + lea ESI, fIn[8] + mov AX, [ESI] // Get first two bytes + test AX, 32768 // 32768D = 1000000000000000B + jz @Positive + mov Neg, 1 + sub AX, 32768 // Sign bit <- 0 + @Positive: + // Test if fIn is NaN or Infinity + cmp AX, 32767 + jnz @NotNAN_INF + mov DL, [ESI - 1] + test DL, 64 // 01000000B + jz @INF + mov Flag, 4 // NaN + jmp @Done + @INF: + mov Flag, 3 // INF + jmp @Done + @NotNAN_INF: + sub AX, 16383 // AX = AX - 011111111111111B + jns @ExpPositive + sub AX, 1 + not AX + mov Flag, 2 // // Exponent sign negative + jmp @JudgeDecimalExp + @ExpPositive: + mov Flag, 1 // Exponent sign positive + @JudgeDecimalExp: + mov IntExp, EAX + cmp DecimalExp, 1 + je @MoveDigits + // Binary string exponent. Convert AX to binary string and store it in Exp + lea EBX, Exp + mov EBX, [EBX] + push ECX + mov [EBX], 69 // 'E' // "D" for decimal exponent + mov ECX, 1 + cmp Flag, 2 + jnz @NoNegativeInExp + mov [EBX + 1], 45 // '-' // Add a "-" to exponent string + mov ECX, 2 + @NoNegativeInExp: + mov ESI, 0 // flag whehter "1" appears + // Move exponent digits to Exp + mov DX, 32768 // 1000000000000000 + @NextExpDigit: + test AX, DX + jz @AppendExp0 + mov [EBX + ECX], 49 // '1' + mov ESI, 1 + jmp @NextExpIncECX + @AppendExp0: + cmp ESI, 0 + jz @NextExpNoIncECX // do not append this "0" + mov [EBX + ECX], 48 // '0' + @NextExpIncECX: + inc ECX + @NextExpNoIncECX: + shr DX, 1 + cmp DX, 0 + jne @NextExpDigit + pop ECX + mov EBX, Result + mov EBX, [EBX] + jmp @MoveDigits + @MoveDigits: + // Move digits to Result + mov ESI, 8 + @NextByte: + dec ESI + mov EAX, EBX + lea EBX, fIn[ESI] + mov DL, [EBX] + mov EBX, EAX + mov AL, 128 // 10000000 + @NextDigit: + test DL, AL + jz @Append0 + mov [EBX + ECX], 49 // '1' + mov i, ECX + jmp @Next + @Append0: + mov [EBX + ECX], 48 // '0' + @Next: + inc ECX + shr AL, 1 + cmp AL, 0 + jne @NextDigit + cmp ESI, 0 // if the last byte + jne @NextByte + jmp @Done + @Zero: + mov Flag, 0 + @Done: + pop ESI + pop EBX + end; + case Flag of + 0: + begin + ForHexOct := nil; + Result := '0'; + Exit; + end; + 1, 2: + begin + // Delete redundant "0" in Result + Delete(Result, i + 2, MaxInt); // i stores the position of the last 1 in Result + if Assigned(ForHexOct) then + begin + // Copy to ForHexOct + with ForHexOct^ do + begin + Negative := Neg; + ExpFlag := Flag; + ExponentI := IntExp; + end; + Exit; + end; + // Add dot and exponent to Result + if (IntExp = 0) then + begin + if (Length(Result) > 1) then + Insert('.', Result, 2); + end + else + begin + { Decide whether use exponent. For example "1000.101" shouldn't be output + as 1.000101E11 when AlwaysUseExponent is False. } + if AlwaysUseExponent then + begin +UseExponent: + if DecimalExp then + if Flag = 1 then + Exp := 'D' + {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(IntExp)) + else + Exp := 'D-' + {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(IntExp)); + if Length(Result) >=2 then + Insert('.', Result, 2); + Result := Result + Exp; + end + else + begin + // IntExp may be negative. + if Flag = 1 then + begin + // Calculate all digits required without exponent + if IntExp <= Length(Result) - 2 then + begin + // Do not use exponent + Insert('.', Result, IntExp + 2); + end + else if IntExp = Length(Result) - 1 then + { 1.001, Exp = 3, output 1001 } + else + begin + if IntExp + 1> MaxBinDigits then + goto UseExponent + else + begin + Inc(IntExp); + i := Length(Result); + // Add zeros at tail + SetLength(Result, IntExp); + for i := i + 1 to IntExp do + Result := '0'; + end; + end; + end + else + begin + if IntExp + Length(Result) > MaxBinDigits then + goto UseExponent + else + begin + // Add leading zeros and place "." + SetLength(Exp, 1 + IntExp); + Exp[1] := '0'; + Exp[2] := '.'; + for i := 3 to IntExp + 1 do + Exp := '0'; //} + Result := Exp + Result; + end; + end; + end; + end; + end; + 3: // INF + begin + ForHexOct := nil; + Result := 'INF'; + end; + 4: // NaN + begin + ForHexOct := nil; + Result := 'NaN'; + Exit; + end; + end; + if Neg then + Result := '-' + Result; +end; + +function FloatDecimalToBinExtended(fIn: Extended; DecimalExp, + AlwaysUseExponent: Boolean): AnsiString; +var + PTmp: PConvertFloatSystem; +begin + PTmp := nil; + Result := FloatDecimalToBinaryExtended(fIn, DecimalExp, AlwaysUseExponent, PTmp); +end; + +function FloatDecimalToHexExtended(fIn: Extended; DecimalExp, + AlwaysUseExponent: Boolean): AnsiString; +const + DecToHex: array[0..15] of AnsiChar = + ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); + BinPow: array[0..3] of Integer = (8, 4, 2, 1); + + function IntToHex(Int: Integer): AnsiString; + var + k ,t: Integer; + Buf: array[1..5] of AnsiChar; + begin + k := 1; + while (Int <> 0) do + begin + Buf[k] := DecToHex[Int mod 16]; + Inc(k); + Int := Int div 16; + end; + Dec(k); + SetLength(Result, k); + t := 1; + while (k > 0) do + begin + Result[t] := Buf[k]; + Inc(t); + Dec(k); + end; + end; + + function ToHex(const S: AnsiString; LeftToDot: Boolean): AnsiString; + var + i, l, t, m, k: Integer; + Buf: array[1..20] of AnsiChar; + begin + { LeftToDot = True, S will be patched with zeroes on its left side. + For example, S = '110', after patching, S = '0110'. + LeftToDot = False, S will be patched with zeroes on its right side. + S = '110', after patching, S = '1100'. } + l := Length(S); + if LeftToDot then + t := (4 - (l mod 4)) mod 4 + else + t := 0; + i := 1; + m := 1; + k := 0; + while i <= l do + begin + k := k + BinPow[t] * (Ord(S[i]) - Ord('0')); + Inc(t); + if (t = 4) or (i = l) then + begin + Buf[m] := DecToHex[k]; + Inc(m); + k := 0; + t := 0; + end; + Inc(i); + end; + Dec(m); + SetLength(Result, m); + + while (m > 0) do + begin + Result[m] := Buf[m]; + Dec(m); + end; + end; + +var + PConvertData: PConvertFloatSystem; + ConvertData: TConvertFloatSystem; + tmpS: AnsiString; + k, t, i, m: Integer; +label UseExponent; +begin + PConvertData := @ConvertData; + Result := FloatDecimalToBinaryExtended(fIn, True, True, PConvertData); + // See FloatDecimalToBinaryExtended, PConvertData is set to nil when result is definite. + if PConvertData = nil then + Exit; + with ConvertData do + begin + { 3.BD^D(12) + A.BD^E(ABCE) + AB.FFFF } + k := Length(Result) - 1; + if AlwaysUseExponent then + begin +UseExponent: + { Algorithm: + X.XXXXXXXX^Y Shift Count Exp + 1.00000001^0 = 1.00000001 = 1.01^0 (16) + 1.00000001^1 = 10.0000001 = 2.02^0 (16) + 1.00000001^2 = 100.000001 = 4.04^0 (16) + 1.00000001^3 = 1000.00001 = 8.08^0 (16) + 1.00000001^4 = 1.00000001^100 = 1.01^1 (16) + 1.00000001^5 = 10.0000001^100 = 2.02^1 (16) + Shift Count = Y mod 4 + Exp = Y div 4 + X.XXXXXXXXX^Y Y < 0 Exp + 1.00000001^-1 = 0.100000001 = 1000.00001^-100 = 8.08^-1 + 1.00000001^-2 = 0.0100000001 = 100.000001^-100 = 4.04^-1 + 1.00000001^-3 = 0.00100000001 = 10.0000001^-100 = 2.02^-1 + 1.00000001^-4 = 0.000100000001 = 1.00000001^-100 = 1.01^-1 + 1.00000001^-5 = 0.0000100000001 = 1000.00001^-100 = 8.08^-2 + Shift Count = 4 - (Abs(Y) mod 4) + Exp = -(Abs(Y) div 4 + 1) } + if ExpFlag = 1 then + begin + t := ExponentI div 4; // Exp + i := ExponentI mod 4; // Shift Count + end + else + begin + t := -((ExponentI - 1) div 4 + 1); // Exp + i := (4 - (ExponentI mod 4)) mod 4; // Shift Count + end; + // Get hex digits + if k < i then + begin + // Add extra zeroes + SetLength(Result, i + 1); + for m := k + 2 to i + 1 do + Result[m] := '0'; + Result := ToHex(Result, True); + end + else if k = i then + Result := ToHex(Result, True) + else + begin + tmpS := Copy(Result, 1, i + 1); + Delete(Result, 1, i + 1); + Result := ToHex(tmpS, True) + '.' + ToHex(Result, False); + end; + if t <> 0 then + begin + // Format exponent + if DecimalExp then + Result := Result + '^D(' + {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(t)) + ')' + else + begin + if ExpFlag = 1 then + Result := Result + '^E(' + IntToHex(t) + ')' + else // t < 0 + Result := Result + '^E(-' + IntToHex(-t) + ')'; + end; + end; + end + else + begin + { Always remember that Result equals "XXXXXXXX" not "X.XXXXXXX". + Judge whether to use exponent: + There are K "X" after '.', K = Length(Result) - 1, no "." in Result originally. + X.XXXXXXX^Y (Binary string, ExponentI = Abs(Y)) + case Y >= 0 (Condition: ExpFlag = 2) + Y <= K: + Y+1 binary digits on left side of '.', K-Y digits on right side + totally requires ((Y+1 - 1) div 4 + 1) + ((K-Y - 1) div 4 + 1) hex digits + Y > K: + Y+1 binary digits on left side, totally ((Y+1 - 1) div 4 + 1) hex digits + case Y<0 (Condition: ExpFlag = 1) 0.XXXX or 0.000XXXX + One digit '0' on left side and K+1+Abs(Y)-1 digits on right side, + totally 1 + ((K+1+Abs(Y)-1-1) div 4 + 1) hex digits. + Compare hdc = hex digit count with MaxHexDigits. If hdc > MaxHexDigits, + goto UseExponent. } + if ExponentI = 0 then + begin + if (Length(Result) > 1) then + Result := '1.' + ToHex(Copy(Result, 2, MaxInt), False); + end + else + begin + if ExpFlag = 1 then + begin + if ExponentI < k then + begin + // No possible that "ExponentI div 4 + (k - ExponentI - 1) div 4 + 2" > MaxHexDigits + tmpS := Copy(Result, 1, ExponentI + 1); + Delete(Result, 1, ExponentI + 1); + Result := ToHex(tmpS, True) + '.' + ToHex(Result, False); + end + else if ExponentI = k then + // 1.01^2 = 101, no ".", no extra "0". + Result := ToHex(Result, True) + else + begin + t := ExponentI div 4 + 1; + if t > MaxHexDigits then + goto UseExponent + else + begin + // Append "0" after Result + Inc(ExponentI); + // Add '0' to Result + SetLength(Result, ExponentI); + for t := k + 2{original Length(Result) + 1} to ExponentI do + Result[t] := '0'; + Result := ToHex(Result, True); + end; + end; + end + else + begin + // ExpFlag = 2, X.XXXXXXX^Y, Y < 0 + t := 2 + (k + ExponentI - 1) div 4; {1 + ((K+1+Abs(Y)-1-1) div 4 + 1)} + if t > MaxHexDigits then + goto UseExponent + else + begin + // Add leading zeroes before Result + SetLength(tmpS, ExponentI - 1); // tmpS stores extra zeroes + for t := 1 to ExponentI - 1 do + tmpS[t] := '0'; + Result := '0.' + ToHex(tmpS + Result, False); + end; + end; + end; + end; + if Negative then + Result := '-' + Result; + end; +end; + +function FloatDecimalToOctExtended(fIn: Extended; DecimalExp, + AlwaysUseExponent: Boolean): AnsiString; +const + DecToOct: array[0..7] of AnsiChar = + ('0', '1', '2', '3', '4', '5', '6', '7'); + BinPow: array[0..2] of Integer = (4, 2, 1); + + function IntToOct(Int: Integer): AnsiString; + var + k ,t: Integer; + Buf: array[1..10] of AnsiChar; + begin + k := 1; + while (Int <> 0) do + begin + Buf[k] := DecToOct[Int mod 8]; + Inc(k); + Int := Int div 8; + end; + Dec(k); + SetLength(Result, k); + t := 1; + while (k > 0) do + begin + Result[t] := Buf[k]; + Inc(t); + Dec(k); + end; + end; + + function ToOct(const S: AnsiString; LeftToDot: Boolean): AnsiString; + var + i, l, t, m, k: Integer; + Buf: array[1..30] of AnsiChar; + begin + { LeftToDot = True, S will be patched with zeroes on its left side. + For example, S = '110', after patching, S = '0110'. + LeftToDot = False, S will be patched with zeroes on its right side. + S = '110', after patching, S = '1100'. } + l := Length(S); + if LeftToDot then + t := (3 - (l mod 3)) mod 3 + else + t := 0; + i := 1; + m := 1; + k := 0; + while i <= l do + begin + k := k + BinPow[t] * (Ord(S[i]) - Ord('0')); + Inc(t); + if (t = 3) or (i = l) then + begin + Buf[m] := DecToOct[k]; + Inc(m); + k := 0; + t := 0; + end; + Inc(i); + end; + Dec(m); + SetLength(Result, m); + + while (m > 0) do + begin + Result[m] := Buf[m]; + Dec(m); + end; + end; + +var + PConvertData: PConvertFloatSystem; + ConvertData: TConvertFloatSystem; + tmpS: AnsiString; + k, t, i, m: Integer; +label UseExponent; +begin + PConvertData := @ConvertData; + Result := FloatDecimalToBinaryExtended(fIn, True, True, PConvertData); + // See FloatDecimalToBinaryExtended, PConvertData is set to nil when result is definite. + if PConvertData = nil then + Exit; + with ConvertData do + begin + { 3.333D12 // 12 is decimal + 2.22E33 // 33 is octal} + k := Length(Result) - 1; + if AlwaysUseExponent then + begin +UseExponent: + if ExpFlag = 1 then + begin + t := ExponentI div 3; // Exp + i := ExponentI mod 3; // Shift Count + end + else + begin + t := -((ExponentI - 1) div 3 + 1); // Exp + i := (3 - (ExponentI mod 3)) mod 3; // Shift Count + end; + // Get hex digits + if k < i then + begin + // Add extra zeroes + SetLength(Result, i + 1); + for m := k + 2 to i + 1 do + Result[m] := '0'; + Result := ToOct(Result, True); + end + else if k = i then + Result := ToOct(Result, True) + else + begin + tmpS := Copy(Result, 1, i + 1); + Delete(Result, 1, i + 1); + Result := ToOct(tmpS, True) + '.' + ToOct(Result, False); + end; + if t <> 0 then + begin + // Format exponent + if DecimalExp then + Result := Result + 'D' + {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(t)) + else + begin + if ExpFlag = 1 then + Result := Result + 'E' + IntToOct(t) + else // t < 0 + Result := Result + 'E-' + IntToOct(-t); + end; + end; + end + else + begin + if ExponentI = 0 then + begin + if (Length(Result) > 1) then + Result := '1.' + ToOct(Copy(Result, 2, MaxInt), False); + end + else + begin + if ExpFlag = 1 then + begin + if ExponentI < k then + begin + tmpS := Copy(Result, 1, ExponentI + 1); + Delete(Result, 1, ExponentI + 1); + Result := ToOct(tmpS, True) + '.' + ToOct(Result, False); + end + else if ExponentI = k then + // 1.01^2 = 101, no ".", no extra "0". + Result := ToOct(Result, True) + else + begin + t := ExponentI div 3 + 1; + if t > MaxHexDigits then + goto UseExponent + else + begin + // Append "0" after Result + Inc(ExponentI); + // Add '0' to Result + SetLength(Result, ExponentI); + for t := k + 2{original Length(Result) + 1} to ExponentI do + Result[t] := '0'; + Result := ToOct(Result, True); + end; + end; + end + else + begin + // ExpFlag = 2, X.XXXXXXX^Y, Y < 0 + t := 2 + (k + ExponentI - 1) div 3; + if t > MaxHexDigits then + goto UseExponent + else + begin + // Add leading zeroes before Result + SetLength(tmpS, ExponentI - 1); // tmpS stores extra zeroes + for t := 1 to ExponentI - 1 do + tmpS[t] := '0'; + Result := '0.' + ToOct(tmpS + Result, False); + end; + end; + end; + end; + if Negative then + Result := '-' + Result; + end; +end; + +{$ENDIF} +{$ENDIF} + +procedure ExtractFloatSingle(Value: Single; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: Cardinal); +begin + SignNegative := (PCardinal(@Value)^ and CN_SIGN_SINGLE_MASK) <> 0; + Exponent := ((PCardinal(@Value)^ and CN_EXPONENT_SINGLE_MASK) shr 23) - CN_EXPONENT_OFFSET_SINGLE; + Mantissa := PCardinal(@Value)^ and CN_SIGNIFICAND_SINGLE_MASK; + Mantissa := Mantissa or (1 shl 23); // λټӸ 1 +end; + +procedure ExtractFloatDouble(Value: Double; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: TUInt64); +begin + SignNegative := (PUInt64(@Value)^ and CN_SIGN_DOUBLE_MASK) <> 0; + Exponent := ((PUInt64(@Value)^ and CN_EXPONENT_DOUBLE_MASK) shr 52) - CN_EXPONENT_OFFSET_DOUBLE; + Mantissa := PUInt64(@Value)^ and CN_SIGNIFICAND_DOUBLE_MASK; + Mantissa := Mantissa or (TUInt64(1) shl 52); // λټӸ 1 +end; + +procedure ExtractFloatExtended(Value: Extended; out SignNegative: Boolean; + out Exponent: Integer; out Mantissa: TUInt64); +begin + if (SizeOf(Extended) = CN_EXTENDED_SIZE_10) or (SizeOf(Extended) = CN_EXTENDED_SIZE_16) then + begin + SignNegative := (PExtendedRec10(@Value)^.ExpSign and CN_SIGN_EXTENDED_MASK) <> 0; + Exponent := (PExtendedRec10(@Value)^.ExpSign and CN_EXPONENT_EXTENDED_MASK) - CN_EXPONENT_OFFSET_EXTENDED; + Mantissa := PExtendedRec10(@Value)^.Mantissa; // 1ü + end + else if SizeOf(Extended) = CN_EXTENDED_SIZE_8 then + ExtractFloatDouble(Value, SignNegative, Exponent, Mantissa) + else + raise ECnFloatSizeError.CreateFmt(SCnErrorExtendedSizeFmt, [SizeOf(Extended)]); +end; + +procedure ExtractFloatExtended(ValueAddr: Pointer; ExtendedSize: Integer; + out SignNegative: Boolean; out Exponent: Integer; out Mantissa: TUInt64); +var + D: Double; +begin + if (ExtendedSize = CN_EXTENDED_SIZE_10) or (ExtendedSize = CN_EXTENDED_SIZE_16) then + begin + SignNegative := (PExtendedRec10(ValueAddr)^.ExpSign and CN_SIGN_EXTENDED_MASK) <> 0; + Exponent := (PExtendedRec10(ValueAddr)^.ExpSign and CN_EXPONENT_EXTENDED_MASK) - CN_EXPONENT_OFFSET_EXTENDED; + Mantissa := PExtendedRec10(ValueAddr)^.Mantissa; // 1ü + end + else if ExtendedSize = CN_EXTENDED_SIZE_8 then + begin + Move(ValueAddr^, D, SizeOf(Double)); + ExtractFloatDouble(D, SignNegative, Exponent, Mantissa); + end + else + raise ECnFloatSizeError.CreateFmt(SCnErrorExtendedSizeFmt, [SizeOf(Extended)]); +end; + +procedure ExtractFloatQuadruple(Value: Extended; out SignNegative: Boolean; + out Exponent: Integer; out MantissaLo, MantissaHi: TUInt64); +begin + if SizeOf(Extended) <> CN_EXTENDED_SIZE_16 then + raise ECnFloatSizeError.CreateFmt(SCnErrorExtendedSizeFmt, [SizeOf(Extended)]); + + SignNegative := (PCnQuadruple(@Value)^.W1 and CN_SIGN_QUADRUPLE_MASK) <> 0; + Exponent := (PCnQuadruple(@Value)^.W1 and CN_EXPONENT_QUADRUPLE_MASK) - CN_EXPONENT_OFFSET_EXTENDED; + + // Extract 16 Bytes to Mantissas + MantissaLo := PCnQuadruple(@Value)^.Lo; + MantissaHi := TUInt64(PCnQuadruple(@Value)^.Hi0) or (TUInt64(PCnQuadruple(@Value)^.W0) shl 32) or (TUInt64(1) shl 48); // λټӸ 1 +end; + +procedure CombineFloatSingle(SignNegative: Boolean; Exponent: Integer; + Mantissa: Cardinal; var Value: Single); +begin + Mantissa := Mantissa and not (1 shl 23); // ȥ 23 λϵ 1еĻ + PCardinal(@Value)^ := Mantissa and CN_SIGNIFICAND_SINGLE_MASK; + Inc(Exponent, CN_EXPONENT_OFFSET_SINGLE); + + PCardinal(@Value)^ := PCardinal(@Value)^ or (LongWord(Exponent) shl 23); + if SignNegative then + PCardinal(@Value)^ := PCardinal(@Value)^ or CN_SIGN_SINGLE_MASK + else + PCardinal(@Value)^ := PCardinal(@Value)^ and not CN_SIGN_SINGLE_MASK; +end; + +procedure CombineFloatDouble(SignNegative: Boolean; Exponent: Integer; + Mantissa: TUInt64; var Value: Double); +begin + Mantissa := Mantissa and not (TUInt64(1) shl 52); // ȥ 52 λϵ 1еĻ + PUInt64(@Value)^ := Mantissa and CN_SIGNIFICAND_DOUBLE_MASK; + Inc(Exponent, CN_EXPONENT_OFFSET_DOUBLE); + + PUInt64(@Value)^ := PUInt64(@Value)^ or (TUInt64(Exponent) shl 52); + if SignNegative then + PUInt64(@Value)^ := PUInt64(@Value)^ or CN_SIGN_DOUBLE_MASK + else + PUInt64(@Value)^ := PUInt64(@Value)^ and not CN_SIGN_DOUBLE_MASK; +end; + +{$HINTS OFF} + +procedure CombineFloatExtended(SignNegative: Boolean; Exponent: Integer; + Mantissa: TUInt64; var Value: Extended); +var + D: Double; +begin + if (SizeOf(Extended) = CN_EXTENDED_SIZE_10) or (SizeOf(Extended) = CN_EXTENDED_SIZE_16) then + begin + PExtendedRec10(@Value)^.Mantissa := Mantissa; + Inc(Exponent, CN_EXPONENT_OFFSET_EXTENDED); + + PExtendedRec10(@Value)^.ExpSign := Exponent and CN_EXPONENT_EXTENDED_MASK; + if SignNegative then + PExtendedRec10(@Value)^.ExpSign := PExtendedRec10(@Value)^.ExpSign or CN_SIGN_EXTENDED_MASK + else + PExtendedRec10(@Value)^.ExpSign := PExtendedRec10(@Value)^.ExpSign and not CN_SIGN_EXTENDED_MASK; + end + else if SizeOf(Extended) = CN_EXTENDED_SIZE_8 then + begin + CombineFloatDouble(SignNegative, Exponent, Mantissa, D); + Value := D; + end + else + raise ECnFloatSizeError.CreateFmt(SCnErrorExtendedSizeFmt, [SizeOf(Extended)]); +end; + +procedure CombineFloatExtended(SignNegative: Boolean; Exponent: Integer; + Mantissa: TUInt64; ValueAddr: Pointer; ExtendedSize: Integer); +var + D: Double; +begin + if (ExtendedSize = CN_EXTENDED_SIZE_10) or (ExtendedSize = CN_EXTENDED_SIZE_16) then + begin + PExtendedRec10(ValueAddr)^.Mantissa := Mantissa; + Inc(Exponent, CN_EXPONENT_OFFSET_EXTENDED); + + PExtendedRec10(ValueAddr)^.ExpSign := Exponent and CN_EXPONENT_EXTENDED_MASK; + if SignNegative then + PExtendedRec10(ValueAddr)^.ExpSign := PExtendedRec10(ValueAddr)^.ExpSign or CN_SIGN_EXTENDED_MASK + else + PExtendedRec10(ValueAddr)^.ExpSign := PExtendedRec10(ValueAddr)^.ExpSign and not CN_SIGN_EXTENDED_MASK; + end + else if ExtendedSize = CN_EXTENDED_SIZE_8 then + begin + CombineFloatDouble(SignNegative, Exponent, Mantissa, D); + Move(D, ValueAddr^, SizeOf(Double)); + end + else + raise ECnFloatSizeError.CreateFmt(SCnErrorExtendedSizeFmt, [SizeOf(Extended)]); +end; + +{$HINTS ON} + +procedure CombineFloatQuadruple(SignNegative: Boolean; Exponent: Integer; + MantissaLo, MantissaHi: TUInt64; var Value: Extended); +begin + if SizeOf(Extended) <> CN_EXTENDED_SIZE_16 then + raise ECnFloatSizeError.CreateFmt(SCnErrorExtendedSizeFmt, [SizeOf(Extended)]); + + MantissaHi := MantissaHi and not (TUInt64(1) shl 48); // ȥ 112 λϵ 1еĻ + PCnQuadruple(@Value)^.Lo := MantissaLo; + PCnQuadruple(@Value)^.Hi0 := Cardinal(MantissaHi and $FFFFFFFF); + PCnQuadruple(@Value)^.Hi1 := (MantissaHi shr 32) and CN_SIGNIFICAND_QUADRUPLE_MASK; + + Inc(Exponent, CN_EXPONENT_OFFSET_EXTENDED); + PCnQuadruple(@Value)^.W1 := Exponent and CN_EXPONENT_QUADRUPLE_MASK; + if SignNegative then + PCnQuadruple(@Value)^.Hi1 := PCnQuadruple(@Value)^.Hi1 or CN_SIGN_QUADRUPLE_MASK + else + PCnQuadruple(@Value)^.Hi1 := PCnQuadruple(@Value)^.Hi1 and not CN_SIGN_QUADRUPLE_MASK; +end; + +// UInt64 Ϊ +function UFloat(U: TUInt64): Extended; +{$IFNDEF SUPPORT_UINT64} +var + L, H: Cardinal; +{$ENDIF} +begin +{$IFDEF SUPPORT_UINT64} + Result := U; +{$ELSE} + if U < 0 then // Int64 С 0 ʱ UInt64 Ǵ Int64 ֵ + begin + H := Int64Rec(U).Hi; + L := Int64Rec(U).Lo; + Result := Int64(H) * Int64(CN_MAX_UINT16 + 1); // + Result := Result * (CN_MAX_UINT16 + 1); + Result := Result + L; + end + else + Result := U; +{$ENDIF} +end; + +function UInt64ToSingle(U: TUInt64): Single; +begin + Result := UFloat(U); +end; + +function UInt64ToDouble(U: TUInt64): Double; +begin + Result := UFloat(U); +end; + +function UInt64ToExtended(U: TUInt64): Extended; +begin + Result := UFloat(U); +end; + +// ͨ Trunc ֻܷ Int64 UInt64 +function UTrunc(F: Extended): TUInt64; +var + T: Integer; + SignNeg: Boolean; + Exponent: Integer; + Mantissa: TUInt64; +begin + // õʵָ 1 ͷЧ֣С 1 + ExtractFloatExtended(F, SignNeg, Exponent, Mantissa); + if SignNeg then + raise ERangeError.Create(SRangeError); // ֧ + + // Mantissa 64 λЧ֣С 63 λָС 0 ˵СҪƣôֵ 0 + if Exponent < 0 then + Result := 0 + else + begin + // С Exponent λСߵ + T := 63 - Exponent; // С 0 63 λ 63 λұߣСƺ T λұ + if T < 0 then + raise ERangeError.Create(SRangeError); // Exponent ̫ + + Result := Mantissa shr T; + end; +end; + +function SingleToUInt64(F: Single): TUInt64; +begin + Result := UTrunc(F); +end; + +function DoubleToUInt64(F: Double): TUInt64; +begin + Result := UTrunc(F); +end; + +function ExtendedToUInt64(F: Extended): TUInt64; +begin + Result := UTrunc(F); +end; + +function SingleIsInfinite(AValue: Single): Boolean; +begin + Result := ((PCardinal(@AValue)^ and $7F800000) = $7F800000) and + ((PCardinal(@AValue)^ and $007FFFFF) = $00000000); +end; + +function DoubleIsInfinite(AValue: Double): Boolean; +begin + Result := ((PUInt64(@AValue)^ and $7FF0000000000000) = $7FF0000000000000) and + ((PUInt64(@AValue)^ and $000FFFFFFFFFFFFF) = $0000000000000000); +end; + +function ExtendedIsInfinite(AValue: Extended): Boolean; +begin + if (SizeOf(Extended) = CN_EXTENDED_SIZE_10) or (SizeOf(Extended) = CN_EXTENDED_SIZE_16) then + Result := ((PExtendedRec10(@AValue)^.ExpSign and $7FFF) = $7FFF) and + ((PExtendedRec10(@AValue)^.Mantissa) = 0) + else if SizeOf(Extended) = CN_EXTENDED_SIZE_8 then + Result := DoubleIsInfinite(AValue) + else + raise ECnFloatSizeError.CreateFmt(SCnErrorExtendedSizeFmt, [SizeOf(Extended)]); +end; + +function SingleIsNan(AValue: Single): Boolean; +begin + Result := ((PCardinal(@AValue)^ and $7F800000) = $7F800000) and + ((PCardinal(@AValue)^ and $007FFFFF) <> $00000000); +end; + +function DoubleIsNan(AValue: Double): Boolean; +begin + Result := ((PUInt64(@AValue)^ and $7FF0000000000000) = $7FF0000000000000) and + ((PUInt64(@AValue)^ and $000FFFFFFFFFFFFF) <> $0000000000000000); +end; + +function ExtendedIsNan(AValue: Extended): Boolean; +begin + if (SizeOf(Extended) = CN_EXTENDED_SIZE_10) or (SizeOf(Extended) = CN_EXTENDED_SIZE_16) then + Result := ((PExtendedRec10(@AValue)^.ExpSign and $7FFF) = $7FFF) and + ((PExtendedRec10(@AValue)^.Mantissa and $7FFFFFFFFFFFFFFF) <> 0) + else if SizeOf(Extended) = CN_EXTENDED_SIZE_8 then + Result := DoubleIsNan(AValue) + else + raise ECnFloatSizeError.CreateFmt(SCnErrorExtendedSizeFmt, [SizeOf(Extended)]); +end; + +function ExtendedToStr(AValue: Extended): string; +var + Buffer: array[0..63] of Char; +begin + SetString(Result, Buffer, FloatToText(Buffer, AValue, {$IFNDEF FPC} fvExtended, {$ENDIF} + ffGeneral, 18, 0)); // ڲ 18 +end; + +end. diff --git a/CnPack/Common/CnPack.inc b/CnPack/Common/CnPack.inc new file mode 100644 index 0000000..3ffcc8d --- /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/Common/CnStrings.pas b/CnPack/Common/CnStrings.pas new file mode 100644 index 0000000..504f43a --- /dev/null +++ b/CnPack/Common/CnStrings.pas @@ -0,0 +1,2927 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnStrings; +{* |
+================================================================================ +* ƣCnPack +* ԪƣCnStrings ʵֵԪ AnsiStringList ԼһӴ㷨 +* ֧ Win32/64 Posix +* ԪߣCnPack (master@cnpack.org) +* ƽ̨PWinXPPro + Delphi 5.01 +* ݲԣPWin9X/2000/XP + Delphi 5/6/7/2005 + C++Build 5/6 +* עAnsiStringList ֲ Delphi 7 StringList +* £2025.08.14 +* һָָȫƥʵֺ +* 2022.10.25 +* StringBuilder ʵ֣֧ Ansi Unicode ģʽ +* 2022.04.25 +* ַ滻֧ƥ +* 2017.01.09 +* ֲ Forrest Smith ַģƥ㷨 +* һƥַڿ⡣ +* 2015.06.01 +* ӿӴ㷨 FastPosition +* 2013.03.04 +* Ԫʵֹ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + Classes, SysUtils, {$IFDEF MSWINDOWS} Windows, {$ENDIF} CnNative; + +const + SCN_BOM_UTF8: array[0..2] of Byte = ($EF, $BB, $BF); + + SCN_BOM_UTF16_LE: array[0..1] of Byte = ($FF, $FE); + + SCN_BOM_UTF16_BE: array[0..1] of Byte = ($FE, $FF); + +type + TCnMatchMode = (mmStart, mmAnywhere, mmFuzzy); + {* ַƥģʽͷƥ䣬мƥ䣬ȫΧģƥ} + + TCnAnsiStrings = class; + + ICnStringsAdapter = interface + ['{E32A5BD7-9A80-4DDE-83D7-2EE050BF476A}'] + procedure ReferenceStrings(S: TCnAnsiStrings); + procedure ReleaseStrings; + end; + + TCnAnsiStringsDefined = set of (sdDelimiter, sdQuoteChar, sdNameValueSeparator); + + TCnAnsiStrings = class(TPersistent) + {* Ansi TStrings Unicode ṩ Ansi TStrings } + private + FDefined: TCnAnsiStringsDefined; + FDelimiter: AnsiChar; + FQuoteChar: AnsiChar; + FNameValueSeparator: AnsiChar; + FUpdateCount: Integer; + FAdapter: ICnStringsAdapter; + FUseSingleLF: Boolean; + function GetCommaText: AnsiString; + function GetDelimitedText: AnsiString; + function GetName(Index: Integer): AnsiString; + function GetValue(const Name: AnsiString): AnsiString; + procedure ReadData(Reader: TReader); + procedure SetCommaText(const Value: AnsiString); + procedure SetDelimitedText(const Value: AnsiString); + procedure SetStringsAdapter(const Value: ICnStringsAdapter); + procedure SetValue(const Name, Value: AnsiString); + procedure WriteData(Writer: TWriter); + function GetDelimiter: AnsiChar; + procedure SetDelimiter(const Value: AnsiChar); + function GetQuoteChar: AnsiChar; + procedure SetQuoteChar(const Value: AnsiChar); + function GetNameValueSeparator: AnsiChar; + procedure SetNameValueSeparator(const Value: AnsiChar); + function GetValueFromIndex(Index: Integer): AnsiString; + procedure SetValueFromIndex(Index: Integer; const Value: AnsiString); + protected + procedure DefineProperties(Filer: TFiler); override; + procedure Error(const Msg: AnsiString; Data: Integer); overload; + procedure Error(Msg: PResStringRec; Data: Integer); overload; + function ExtractName(const S: AnsiString): AnsiString; + function Get(Index: Integer): AnsiString; virtual; abstract; + function GetCapacity: Integer; virtual; + function GetCount: Integer; virtual; abstract; + function GetObject(Index: Integer): TObject; virtual; + function GetTextStr: AnsiString; virtual; + procedure Put(Index: Integer; const S: AnsiString); virtual; + procedure PutObject(Index: Integer; AObject: TObject); virtual; + procedure SetCapacity(NewCapacity: Integer); virtual; + procedure SetTextStr(const Value: AnsiString); virtual; + procedure SetUpdateState(Updating: Boolean); virtual; + property UpdateCount: Integer read FUpdateCount; + function CompareStrings(const S1, S2: AnsiString): Integer; virtual; + public + destructor Destroy; override; + function Add(const S: AnsiString): Integer; virtual; + function AddObject(const S: AnsiString; AObject: TObject): Integer; virtual; + procedure Append(const S: AnsiString); + procedure AddStrings(Strings: TCnAnsiStrings); virtual; + procedure Assign(Source: TPersistent); override; + procedure BeginUpdate; + procedure Clear; virtual; abstract; + procedure Delete(Index: Integer); virtual; abstract; + procedure EndUpdate; + function Equals(Strings: TCnAnsiStrings): Boolean; reintroduce; + procedure Exchange(Index1, Index2: Integer); virtual; + function GetText: PAnsiChar; virtual; + function IndexOf(const S: AnsiString): Integer; virtual; + function IndexOfName(const Name: AnsiString): Integer; virtual; + function IndexOfObject(AObject: TObject): Integer; virtual; + procedure Insert(Index: Integer; const S: AnsiString); virtual; abstract; + procedure InsertObject(Index: Integer; const S: AnsiString; + AObject: TObject); virtual; + procedure LoadFromFile(const FileName: AnsiString); virtual; + procedure LoadFromStream(Stream: TStream); virtual; + procedure Move(CurIndex, NewIndex: Integer); virtual; + procedure SaveToFile(const FileName: AnsiString); virtual; + procedure SaveToStream(Stream: TStream); virtual; + procedure SetText(Text: PAnsiChar); virtual; + property Capacity: Integer read GetCapacity write SetCapacity; + property CommaText: AnsiString read GetCommaText write SetCommaText; + property Count: Integer read GetCount; + property Delimiter: AnsiChar read GetDelimiter write SetDelimiter; + property DelimitedText: AnsiString read GetDelimitedText write SetDelimitedText; + property Names[Index: Integer]: AnsiString read GetName; + property Objects[Index: Integer]: TObject read GetObject write PutObject; + property QuoteChar: AnsiChar read GetQuoteChar write SetQuoteChar; + property Values[const Name: AnsiString]: AnsiString read GetValue write SetValue; + property ValueFromIndex[Index: Integer]: AnsiString read GetValueFromIndex write SetValueFromIndex; + property NameValueSeparator: AnsiChar read GetNameValueSeparator write SetNameValueSeparator; + property Strings[Index: Integer]: AnsiString read Get write Put; default; + property Text: AnsiString read GetTextStr write SetTextStr; + property StringsAdapter: ICnStringsAdapter read FAdapter write SetStringsAdapter; + property UseSingleLF: Boolean read FUseSingleLF write FUseSingleLF; + {* ӵԣ GetTextStr ʱʹõĻǷǵ #10 dz #13#10} + end; + + TCnAnsiStringList = class; + + PCnAnsiStringItem = ^TCnAnsiStringItem; + TCnAnsiStringItem = record + FString: AnsiString; + FObject: TObject; + end; + + PCnAnsiStringItemList = ^TCnAnsiStringItemList; + TCnAnsiStringItemList = array[0..MaxListSize div 2] of TCnAnsiStringItem; + TCnAnsiStringListSortCompare = function(List: TCnAnsiStringList; Index1, Index2: Integer): Integer; + + TCnAnsiStringList = class(TCnAnsiStrings) + {* Ansi TStringList Unicode ṩ Ansi TStringList } + private + FList: PCnAnsiStringItemList; + FCount: Integer; + FCapacity: Integer; + FSorted: Boolean; + FDuplicates: TDuplicates; + FCaseSensitive: Boolean; + FOnChange: TNotifyEvent; + FOnChanging: TNotifyEvent; + procedure ExchangeItems(Index1, Index2: Integer); + procedure Grow; + procedure QuickSort(L, R: Integer; SCompare: TCnAnsiStringListSortCompare); + procedure SetSorted(Value: Boolean); + procedure SetCaseSensitive(const Value: Boolean); + protected + procedure Changed; virtual; + procedure Changing; virtual; + function Get(Index: Integer): AnsiString; override; + function GetCapacity: Integer; override; + function GetCount: Integer; override; + function GetObject(Index: Integer): TObject; override; + procedure Put(Index: Integer; const S: AnsiString); override; + procedure PutObject(Index: Integer; AObject: TObject); override; + procedure SetCapacity(NewCapacity: Integer); override; + procedure SetUpdateState(Updating: Boolean); override; + function CompareStrings(const S1, S2: AnsiString): Integer; override; + procedure InsertItem(Index: Integer; const S: AnsiString; AObject: TObject); virtual; + public + destructor Destroy; override; + function Add(const S: AnsiString): Integer; override; + function AddObject(const S: AnsiString; AObject: TObject): Integer; override; + procedure Clear; override; + procedure Delete(Index: Integer); override; + procedure Exchange(Index1, Index2: Integer); override; + function Find(const S: AnsiString; var Index: Integer): Boolean; virtual; + function IndexOf(const S: AnsiString): Integer; override; + procedure Insert(Index: Integer; const S: AnsiString); override; + procedure InsertObject(Index: Integer; const S: AnsiString; + AObject: TObject); override; + procedure Sort; virtual; + procedure CustomSort(Compare: TCnAnsiStringListSortCompare); virtual; + property Duplicates: TDuplicates read FDuplicates write FDuplicates; + property Sorted: Boolean read FSorted write SetSorted; + property CaseSensitive: Boolean read FCaseSensitive write SetCaseSensitive; + property OnChange: TNotifyEvent read FOnChange write FOnChange; + property OnChanging: TNotifyEvent read FOnChanging write FOnChanging; + end; + + PPCnAnsiHashItem = ^PCnAnsiHashItem; + PCnAnsiHashItem = ^TCnAnsiHashItem; + TCnAnsiHashItem = record + Next: PCnAnsiHashItem; + Key: AnsiString; + Value: Integer; + end; + + TCnAnsiStringHash = class + private + Buckets: array of PCnAnsiHashItem; + protected + function Find(const Key: AnsiString): PPCnAnsiHashItem; + function HashOf(const Key: AnsiString): Cardinal; virtual; + public + constructor Create(Size: Cardinal = 256); + destructor Destroy; override; + procedure Add(const Key: AnsiString; Value: Integer); + procedure Clear; + procedure Remove(const Key: AnsiString); + function Modify(const Key: AnsiString; Value: Integer): Boolean; + function ValueOf(const Key: AnsiString): Integer; + end; + + TCnHashedAnsiStringList = class(TCnAnsiStringList) + {* Ansi THashedStringList Unicode ṩ Ansi THashedStringList } + private + FValueHash: TCnAnsiStringHash; + FNameHash: TCnAnsiStringHash; + FValueHashValid: Boolean; + FNameHashValid: Boolean; + procedure UpdateValueHash; + procedure UpdateNameHash; + protected + procedure Changed; override; + public + destructor Destroy; override; + function IndexOf(const S: AnsiString): Integer; override; + function IndexOfName(const Name: AnsiString): Integer; override; + end; + + TCnStringBuilder = class + {* ʽ StringBuilderʱֻ֧ӣ֧ɾ + Unicode 汾֧ string WideStringUnicode 汾֧ AnsiString string} + private + FModeIsFromOut: Boolean; + FOutMode: Boolean; + FAnsiMode: Boolean; // Unicode 汾Ĭ TrueUnicode 汾Ĭ Falseɴʱָ + FCharLength: Integer; // ַΪλij + FMaxCharCapacity: Integer; +{$IFDEF UNICODE} + FAnsiData: AnsiString; // AnsiMode True ʱʹ + FData: string; // AnsiMode False ʱʹ +{$ELSE} + FData: string; // AnsiMode True ʱʹ + FWideData: WideString; // AnsiMode False ʱʹ +{$ENDIF} + function GetCharCapacity: Integer; + procedure SetCharCapacity(const Value: Integer); + procedure SetCharLength(const Value: Integer); + protected + procedure ExpandCharCapacity; + {* CharLength Ҫչڲ洢Ϊ CharLength * 2 CharLength ̶̫չ Capacity 0.5 } + + function AppendString(const Value: string): TCnStringBuilder; + {* string ӵ FDataǷ Unicode ɵ߸ AnsiMode ơ + + + const Value: string - ӵַ + + ֵTCnStringBuilder - رһӵ + } + public + constructor Create; overload; + {* 캯ڲʵĬ string} + + constructor Create(IsAnsi: Boolean); overload; + {* ָڲ Ansi Wide Ĺ캯 + + + IsAnsi: Boolean - ָڲǷʹ Ansi ģʽ + + ֵޣ + } + + destructor Destroy; override; + {* } + + procedure Clear; + {* } + +{$IFDEF UNICODE} + function AppendAnsi(const Value: AnsiString): TCnStringBuilder; + {* AnsiString ӵ Unicode µ FAnsiDataɵ߸ AnsiMode ơ + + + const Value: AnsiString - ӵĵַֽ + + ֵTCnStringBuilder - رһӵ + } + +{$ELSE} + function AppendWide(const Value: WideString): TCnStringBuilder; + {* WideString ӵ Unicode е FWideDataɵ߸ AnsiMode ơ + + + const Value: WideString - ӵĿַ + + ֵTCnStringBuilder - رһӵ + } +{$ENDIF} + + function Append(const Value: string): TCnStringBuilder; overload; + {* ַͨ Append ڣڲݵǰԼ AnsiMode úʵƴӡ + + + const Value: string - ӵַ + + ֵTCnStringBuilder - رһӵ + } + + function Append(Value: Boolean): TCnStringBuilder; overload; + {* һֵ + + + Value: Boolean - ӵIJֵ + + ֵTCnStringBuilder - رһӵ + } + + function AppendChar(Value: Char): TCnStringBuilder; + {* һַע Char ͵ַ String ǵͬģܺ Append overload + + + Value: Char - ӵַ + + ֵTCnStringBuilder - رһӵ + } + + function AppendAnsiChar(Value: AnsiChar): TCnStringBuilder; + {* һַֽ + + + Value: AnsiChar - ӵĵַֽ + + ֵTCnStringBuilder - رһӵ + } + + function AppendWideChar(Value: WideChar): TCnStringBuilder; + {* һַ + + + Value: WideChar - ӵĿַ + + ֵTCnStringBuilder - رһӵ + } + + + function AppendCurrency(Value: Currency): TCnStringBuilder; + {* һ Currency ֵע Currency ڵͰ汾 Delphi к Double ǵͬģ + ܺ Append overload + + + Value: Currency - ӵ Currency ֵ + + ֵTCnStringBuilder - رһӵ + } + + + function Append(Value: Single): TCnStringBuilder; overload; + {* һȸ + + + Value: Single - ӵĵȸ + + ֵTCnStringBuilder - رһӵ + } + + function Append(Value: Double): TCnStringBuilder; overload; + {* һ˫ȸ + + + Value: Double - ӵ˫ȸ + + ֵTCnStringBuilder - رһӵ + } + + function Append(Value: ShortInt): TCnStringBuilder; overload; + {* һ 8 λз + + + Value: ShortInt - ӵ 8 λз + + ֵTCnStringBuilder - رһӵ + } + + function Append(Value: SmallInt): TCnStringBuilder; overload; + {* һ 16 λз + + + Value: SmallInt - ӵ 16 λз + + ֵTCnStringBuilder - رһӵ + } + + function Append(Value: Integer): TCnStringBuilder; overload; + {* һ 32 λз + + + Value: Integer - ӵ 32 λз + + ֵTCnStringBuilder - رһӵ + } + + function Append(Value: Int64): TCnStringBuilder; overload; + {* һ 64 λз + + + Value: Int64 - ӵ 64 λз + + ֵTCnStringBuilder - رһӵ + } + + function Append(Value: Byte): TCnStringBuilder; overload; + {* һ 8 λ + + + Value: Byte - ӵ 8 λ + + ֵTCnStringBuilder - رһӵ + } + + function Append(Value: Word): TCnStringBuilder; overload; + {* һ 16 λ + + + Value: Word - ӵ 16 λ + + ֵTCnStringBuilder - رһӵ + } + + function Append(Value: Cardinal): TCnStringBuilder; overload; + {* һ 32 λ + + + Value: Cardinal - ӵ 32 λ + + ֵTCnStringBuilder - رһӵ + } + +{$IFDEF SUPPORT_UINT64} + function Append(Value: UInt64): TCnStringBuilder; overload; + {* һ 64 λ + + + Value: UInt64 - ӵ 64 λ + + ֵTCnStringBuilder - رһӵ + } +{$ENDIF} + + function Append(Value: TObject): TCnStringBuilder; overload; + {* һ + + + Value: TObject - ӵĶڲʹ ToStringʹöʮƵַ + + ֵTCnStringBuilder - رһӵ + } + + function Append(Value: PAnsiChar): TCnStringBuilder; overload; + {* һַֽ + + + Value: PAnsiChar - ӵĵַַֽ + + ֵTCnStringBuilder - رһӵ + } + + function Append(Value: Char; RepeatCount: Integer): TCnStringBuilder; overload; + {* һظַͬ + + + Value: Char - ӵַ + RepeatCount: Integer - ַ + + ֵTCnStringBuilder - رһӵ + } + + function Append(const Value: string; StartIndex: Integer; Count: Integer): TCnStringBuilder; overload; + {* һַӴ + + + const Value: string - ӵַ + StartIndex: Integer - ʼλ + Count: Integer - ַ + + ֵTCnStringBuilder - رһӵ + } + + function Append(const AFormat: string; const Args: array of const): TCnStringBuilder; overload; + {* һʽַ + + + const AFormat: string - ʽַ + const Args: array of const - ʽб + + ֵTCnStringBuilder - رһӵ + } + + function AppendLine: TCnStringBuilder; overload; + {* һС + + + ޣ + + ֵTCnStringBuilder - رһӵ + } + + function AppendLine(const Value: string): TCnStringBuilder; overload; + {* һַϻس + + + const Value: string - ӵַ + + ֵTCnStringBuilder - رһӵ + } + + function ToString: string; {$IFDEF OBJECT_HAS_TOSTRING} override; {$ENDIF} + {* ݵ string ʽǷ Unicode ֻҪ AnsiMode Unicode ֧һ¡ + 仰˵ Unicode AnsiMode Ϊ True ʱŷ AnsiString + Unicode AnsiMode Ϊ False ʱŷ UnicodeStringؿա + + + ޣ + + ֵstring - ݵַʽ + } + + function ToAnsiString: AnsiString; + {* ǿзݵ AnsiString ʽ AnsiMode Ρ + Unicode ʹãڷ Unicode ʹãͬ ToString + + + ޣ + + ֵAnsiString - ݵĵַֽʽ + } + + function ToWideString: WideString; + {* ǿзݵ WideString ʽ AnsiMode Ρ + ڷ Unicode ʹã Unicode ʹãͬ ToString + + + ޣ + + ֵWideString - ݵĿַʽ + } + + property CharCapacity: Integer read GetCharCapacity write SetCharCapacity; + {* ַΪλڲ} + property CharLength: Integer read FCharLength write SetCharLength; + {* ַΪλڲѾƴյݳ} + property MaxCharCapacity: Integer read FMaxCharCapacity; + {* ַΪλĿõ} + end; + + TCnReplaceFlags = set of (crfReplaceAll, crfIgnoreCase, crfWholeWord); + {* ַ滻} + +{$IFNDEF COMPILER7_UP} + +function PosEx(const SubStr: string; const S: string; Offset: Cardinal = 1): Integer; +{* D5/6 BCB5/6 StrUtils ԪĴ˺ֲ PosEx ʹο PosEx + + + const SubStr: string - ҵӴ + const S: string - ԭַ + Offset: Cardinal - ҵʼƫ + + ֵInteger - شʼƫһγӴλ +} + +{$ENDIF} + +function FastPosition(const Str: PChar; const Pattern: PChar; FromIndex: Integer = 0): Integer; +{* Ӵ Pattern Str еĵһγֵţ -1 + + + const Str: PChar - ַ + const Pattern: PChar - ƥӴ + FromIndex: Integer - Ӻδʼ + + ֵInteger - ƥĵһγֵţ -1 +} + +function FuzzyMatchStr(const Pattern: string; const Str: string; MatchedIndexes: TList = nil; + CaseSensitive: Boolean = False): Boolean; +{* ģƥӴMatchedIndexes з Str ƥ±š + + + const Pattern: string - ƥӴ + const Str: string - ַ + MatchedIndexes: TList - ַиַƥ± + CaseSensitive: Boolean - ǷִСд + + ֵBoolean - Ƿģƥ +} + +function FuzzyMatchStrWithScore(const Pattern: string; const Str: string; out Score: Integer; + MatchedIndexes: TList = nil; CaseSensitive: Boolean = False): Boolean; +{* ģƥӴScore ƥ̶ȣMatchedIndexes з Str ƥ±ţ + ע Score ıȽֻӴԼСдһʱ塣 + + + const Pattern: string - ƥӴ + const Str: string - ַ + out Score: Integer - ƥ̶ + MatchedIndexes: TList - ַиַƥ± + CaseSensitive: Boolean - ǷִСд + + ֵBoolean - Ƿģƥ +} + +function AnyWhereSepMatchStr(const Pattern: string; const Str: string; SepContainer: TStringList; + MatchedIndexes: TList = nil; CaseSensitive: Boolean = False; SepChar: Char = ' '): Boolean; +{* ָӴƥӴҲǰ Pattern SepChar ֳɶַƥ䣬ȫƥŷƥ䡣 + MatchedIndexes з Str ƥ±ţSepContainer 紫 TStringList Լٴ + + + const Pattern: string - ƥӴ + const Str: string - ַ + SepContainer: TStringList; - 紫 TStringList Լڲ + MatchedIndexes: TList - ַиַƥ± + CaseSensitive: Boolean - ǷִСд + + ֵBoolean - Ƿƥɹ +} + +function CnStringReplace(const S: string; const OldPattern: string; + const NewPattern: string; Flags: TCnReplaceFlags): string; +{* ֧ƥַ滻 Unicode Unicode ¶Ч + + + const S: string - 滻ַ + const OldPattern: string - 滻ַ + const NewPattern: string - 滻ַ + Flags: TCnReplaceFlags - 滻ǣ֧ƥ + + ֵstring - ַ滻 +} + +{$IFDEF UNICODE} + +function CnStringReplaceA(const S: AnsiString; const OldPattern: AnsiString; + const NewPattern: AnsiString; Flags: TCnReplaceFlags): AnsiString; +{* ֧ƥ Ansi ַ滻 Unicode Ч + + + const S: AnsiString - 滻ĵַֽ + const OldPattern: AnsiString - 滻ĵַֽ + const NewPattern: AnsiString - 滻ĵַֽ + Flags: TCnReplaceFlags - 滻ǣ֧ƥ + + ֵAnsiString - صַֽ滻 +} + +{$ELSE} + +function CnStringReplaceW(const S: WideString; const OldPattern: WideString; + const NewPattern: WideString; Flags: TCnReplaceFlags): WideString; +{* ֧ƥ Wide ַ滻ڷ Unicode Ч + + + const S: WideString - 滻Ŀַ + const OldPattern: WideString - 滻Ŀַ + const NewPattern: WideString - 滻Ŀַ + Flags: TCnReplaceFlags - 滻ǣ֧ƥ + + ֵWideString - ؿַ滻 +} + +{$ENDIF} + +function CnPosEx(const SubStr, S: string; CaseSensitive: Boolean; WholeWords: + Boolean; StartCount: Integer = 1): Integer; +{* ǿַҺֲ֧ҵڼ StartCount Ϊ 1} + +procedure CnSplitString(const Sub: string; const Str: string; Strings: TStrings); +{* ַַֺ} + +function NativeStringToUIString(const Str: string): string; +{* Lazarus/FPC Ansi ģʽרãΪ Lazarus/FPC Ansi ģʽºͽйصַ Utf8 ʽ + ڲַͨ Ansi Utf16һηװת} + +function UIStringToNativeString(const Str: string): string; +{* Lazarus/FPC Ansi ģʽרãΪ Lazarus/FPC Ansi ģʽºͽйصַ Utf8 ʽ + ڲַͨ Ansi Utf16һηװת} + +implementation + +uses + CnWideStrings; + +const + SLineBreak = #13#10; + SLineBreakLF = #10; + STRING_BUILDER_DEFAULT_CAPACITY = 16; + +resourcestring + SDuplicateString = 'AnsiString list does not allow duplicates'; + SListIndexError = 'AnsiString List index out of bounds (%d)'; + SSortedListError = 'Operation not allowed on sorted AnsiString list'; + SListCapacityError = 'Error New Capacity or Length Value %d'; + +function NativeStringToUIString(const Str: string): string; +begin +{$IFDEF FPC} + Result := CnAnsiToUtf82(Str); +{$ELSE} + Result := Str; +{$ENDIF} +end; + +function UIStringToNativeString(const Str: string): string; +begin +{$IFDEF FPC} + Result := CnUtf8ToAnsi2(Str); +{$ELSE} + Result := Str; +{$ENDIF} +end; + +{$IFNDEF COMPILER7_UP} + +function PosEx(const SubStr, S: string; Offset: Cardinal = 1): Integer; +var + I,X: Integer; + Len, LenSubStr: Integer; +begin + if Offset = 1 then + Result := Pos(SubStr, S) + else + begin + I := Offset; + LenSubStr := Length(SubStr); + Len := Length(S) - LenSubStr + 1; + while I <= Len do + begin + if S[I] = SubStr[1] then + begin + X := 1; + while (X < LenSubStr) and (S[I + X] = SubStr[X + 1]) do + Inc(X); + if (X = LenSubStr) then + begin + Result := I; + exit; + end; + end; + Inc(I); + end; + Result := 0; + end; +end; + +{$ENDIF} + +// Ӵ Pattern Str еĵһγֵţ -1 +function FastPosition(const Str, Pattern: PChar; FromIndex: Integer): Integer; +var + C: Char; + I, L, X, Y, PLen, SLen: Integer; + BCS: array[0..255] of Integer; +begin + Result := -1; + if (Str = nil) or (Pattern = nil) then + Exit; + + PLen := StrLen(Pattern); + if PLen = 0 then + Exit; + SLen := StrLen(Str); + + // ǵַģʽ + if PLen = 1 then + begin + for I := FromIndex to SLen - 1 do + begin + if Str[I] = Pattern[0] then + begin + Result := I; + Exit; + end; + end; + Exit; + end; + + // Ծ + for I := Low(BCS) to High(BCS) do + BCS[I] := PLen; + + for I := 0 to PLen - 2 do + begin + C := Pattern[I]; + L := Ord(C) and $FF; + if PLen - I - 1 < BCS[L] then + BCS[L] := PLen - I - 1; + end; + + // ٽ + I := FromIndex + PLen - 1; + while I < SLen do + begin + X := I; + Y := PLen - 1; + while True do + begin + if Pattern[Y] <> Str[X] then + begin + Inc(I, BCS[Ord(Str[X]) and $FF]); + Break; + end; + + if Y = 0 then + begin + Result := X; + Exit; + end; + + Dec(X); + Dec(Y); + end; + end; +end; + +{$WARNINGS OFF} + +function LowChar(AChar: Char): Char; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + if AChar in ['A'..'Z'] then + Result := Chr(Ord(AChar) + 32) + else + Result := AChar; +end; + +// ģƥӴ +function FuzzyMatchStr(const Pattern: string; const Str: string; + MatchedIndexes: TList; CaseSensitive: Boolean): Boolean; +var + PIdx, SIdx: Integer; +begin + Result := False; + if (Pattern = '') or (Str = '') then + Exit; + + PIdx := 1; + SIdx := 1; + if MatchedIndexes <> nil then + MatchedIndexes.Clear; + + if CaseSensitive then + begin + while (PIdx <= Length(Pattern)) and (SIdx <= Length(Str)) do + begin + if Pattern[PIdx] = Str[SIdx] then + begin + Inc(PIdx); + if MatchedIndexes <> nil then + MatchedIndexes.Add(Pointer(SIdx)); + end; + Inc(SIdx); + end; + end + else + begin + while (PIdx <= Length(Pattern)) and (SIdx <= Length(Str)) do + begin + if LowChar(Pattern[PIdx]) = LowChar(Str[SIdx]) then + begin + Inc(PIdx); + if MatchedIndexes <> nil then + MatchedIndexes.Add(Pointer(SIdx)); + end; + Inc(SIdx); + end; + end; + Result := PIdx > Length(Pattern); +end; + +// ģƥӴScore ƥ̶ȣע Score ıȽֻӴԼСдһʱ +function FuzzyMatchStrWithScore(const Pattern: string; const Str: string; + out Score: Integer; MatchedIndexes: TList; CaseSensitive: Boolean): Boolean; +const + ADJACENCY_BONUS = 4; // ÿһַĽƥʱӷ + SEPARATOR_BONUS = 10; // ÿһַƥ䷢һָźļӷ + CAMEL_BONUS = 5; // ǰһƥСдǴдʱӷ + LEADING_LETTER_PENALTY = -3; // һƥĸԽĸԽ۷ + MAX_LEADING_LETTER_PENALTY = -9; // һƥĸⶥֻô + UNMATCHED_LETTER_PENALTY = -1; // ƥĿ۷ + START_BONUS = 6; +var + PIdx, SIdx: Integer; + PrevMatch, PrevLow, PrevSep: Boolean; + BestLetterPtr: PChar; + BestLetterScore, NewScore, Penalty: Integer; + PatternLetter, StrLetter: Char; // ֱӴĸַ + ThisMatch, Rematch, Advanced, PatternRepeat: Boolean; +begin + Score := 0; + Result := False; + if (Pattern = '') or (Str = '') then + Exit; + + if MatchedIndexes <> nil then + MatchedIndexes.Clear; + + PrevMatch := False; + PrevLow := False; + PrevSep := True; + + PIdx := 1; + SIdx := 1; + + BestLetterPtr := nil; + BestLetterScore := 0; + + while SIdx <= Length(Str) do // SIdx ĸλã1 ʼ + begin + if PIdx <= Length(Pattern) then + PatternLetter := Pattern[PIdx] + else + PatternLetter := #0; + StrLetter := Str[SIdx]; + + if CaseSensitive then + begin + ThisMatch := (PatternLetter <> #0) and (PatternLetter = StrLetter); + Rematch := (BestLetterPtr <> nil) and (BestLetterPtr^ = StrLetter); + Advanced := ThisMatch and (BestLetterPtr <> nil); + PatternRepeat := (BestLetterPtr <> nil) and (PatternLetter <> #0) and (BestLetterPtr^ = PatternLetter); + end + else + begin + ThisMatch := (PatternLetter <> #0) and (LowChar(PatternLetter) = LowChar(StrLetter)); + Rematch := (BestLetterPtr <> nil) and (LowChar(BestLetterPtr^) = LowChar(StrLetter)); + Advanced := ThisMatch and (BestLetterPtr <> nil); + PatternRepeat := (BestLetterPtr <> nil) and (PatternLetter <> #0) and (LowChar(BestLetterPtr^) = LowChar(PatternLetter)); + end; + + if ThisMatch and (MatchedIndexes <> nil) then + begin + MatchedIndexes.Add(Pointer(SIdx)); + if SIdx <= START_BONUS then // ߿ĸǰͷƥַķ + Inc(Score, (START_BONUS - SIdx + 1) * 2); + end; + + if Advanced or PatternRepeat then + begin + Inc(Score, BestLetterScore); + BestLetterPtr := nil; + BestLetterScore := 0; + end; + + if ThisMatch or Rematch then + begin + NewScore := 0; + if PIdx = 1 then + begin + Penalty := LEADING_LETTER_PENALTY * (SIdx - 1); // ͷƥ䲻۷ + if Penalty < MAX_LEADING_LETTER_PENALTY then + Penalty := MAX_LEADING_LETTER_PENALTY; + + Inc(Score, Penalty); + end; + + if PrevMatch then + Inc(NewScore, ADJACENCY_BONUS); + if PrevSep then + Inc(NewScore, SEPARATOR_BONUS); + if PrevLow and (strLetter in ['A'..'Z']) then + Inc(NewScore, CAMEL_BONUS); + + if ThisMatch then + Inc(PIdx); + + if NewScore >= BestLetterScore then + begin + if BestLetterPtr <> nil then + Inc(Score, UNMATCHED_LETTER_PENALTY); + BestLetterPtr := @(Str[SIdx]); + BestLetterScore := NewScore; + end; + PrevMatch := True; + end + else + begin + Inc(Score, UNMATCHED_LETTER_PENALTY); + PrevMatch := False; + end; + + PrevLow := StrLetter in ['a'..'z']; + PrevSep := strLetter in ['_', ' ', '/', '\', '.']; + + Inc(SIdx); + end; + + if BestLetterPtr <> nil then + Inc(Score, BestLetterScore); + + Result := PIdx > Length(Pattern); +end; + +function MatchedIndexesCompare(Item1, Item2: Pointer): Integer; +var + R1, R2: Integer; +begin + R1 := Integer(Item1); + R2 := Integer(Item2); + Result := R1 - R2; +end; + +function AnyWhereSepMatchStr(const Pattern: string; const Str: string; SepContainer: TStringList; + MatchedIndexes: TList; CaseSensitive: Boolean; SepChar: Char): Boolean; +var + IsNil: Boolean; + D, I, J: Integer; + ToFind: string; + SepChars: TSysCharSet; +begin + Result := False; + + if Pos(SepChar, Pattern) <= 0 then + begin + // ûиַɱ Pos + if CaseSensitive then + D := Pos(Pattern, Str) + else + D := Pos(UpperCase(Pattern), UpperCase(Str)); + + if D > 0 then + begin + Result := True; + if MatchedIndexes <> nil then + begin + MatchedIndexes.Clear; + for I := 0 to Length(Pattern) - 1 do + MatchedIndexes.Add(Pointer(D + I)); + end; + end; + end + else + begin + IsNil := SepContainer = nil; + if IsNil then + SepContainer := TStringList.Create + else + SepContainer.Clear; + + try + SepChars := []; + Include(SepChars, AnsiChar(SepChar)); + if CaseSensitive then + begin + ExtractStrings(SepChars, [], PChar(Pattern), SepContainer); + ToFind := Str; + end + else + begin + ExtractStrings(SepChars, [], PChar(UpperCase(Pattern)), SepContainer); + ToFind := UpperCase(Str); + end; + + if MatchedIndexes <> nil then + MatchedIndexes.Clear; + for I := 0 to SepContainer.Count - 1 do + begin + D := Pos(SepContainer[I], ToFind); + if D <= 0 then + begin + if MatchedIndexes <> nil then + MatchedIndexes.Clear; + Exit; + end + else + begin + if MatchedIndexes <> nil then + begin + for J := 0 to Length(SepContainer[I]) - 1 do + MatchedIndexes.Add(Pointer(D + J)); + end; + end; + end; + + if (MatchedIndexes <> nil) and (MatchedIndexes.Count > 1) then + MatchedIndexes.Sort(MatchedIndexesCompare); + Result := True; + finally + if IsNil then + SepContainer.Free; + end; + end; +end; + +{ TCnAnsiStrings } + +destructor TCnAnsiStrings.Destroy; +begin + StringsAdapter := nil; + inherited Destroy; +end; + +function TCnAnsiStrings.Add(const S: AnsiString): Integer; +begin + Result := GetCount; + Insert(Result, S); +end; + +function TCnAnsiStrings.AddObject(const S: AnsiString; AObject: TObject): Integer; +begin + Result := Add(S); + PutObject(Result, AObject); +end; + +procedure TCnAnsiStrings.Append(const S: AnsiString); +begin + Add(S); +end; + +procedure TCnAnsiStrings.AddStrings(Strings: TCnAnsiStrings); +var + I: Integer; +begin + BeginUpdate; + try + for I := 0 to Strings.Count - 1 do + AddObject(Strings[I], Strings.Objects[I]); + finally + EndUpdate; + end; +end; + +procedure TCnAnsiStrings.Assign(Source: TPersistent); +begin + if Source is TCnAnsiStrings then + begin + BeginUpdate; + try + Clear; + FDefined := TCnAnsiStrings(Source).FDefined; + FNameValueSeparator := TCnAnsiStrings(Source).FNameValueSeparator; + FQuoteChar := TCnAnsiStrings(Source).FQuoteChar; + FDelimiter := TCnAnsiStrings(Source).FDelimiter; + AddStrings(TCnAnsiStrings(Source)); + finally + EndUpdate; + end; + Exit; + end; + inherited Assign(Source); +end; + +procedure TCnAnsiStrings.BeginUpdate; +begin + if FUpdateCount = 0 then SetUpdateState(True); + Inc(FUpdateCount); +end; + +procedure TCnAnsiStrings.DefineProperties(Filer: TFiler); + + function DoWrite: Boolean; + begin + if Filer.Ancestor <> nil then + begin + Result := True; + if Filer.Ancestor is TCnAnsiStrings then + Result := not Equals(TCnAnsiStrings(Filer.Ancestor)) + end + else Result := Count > 0; + end; + +begin + Filer.DefineProperty('Strings', ReadData, WriteData, DoWrite); +end; + +procedure TCnAnsiStrings.EndUpdate; +begin + Dec(FUpdateCount); + if FUpdateCount = 0 then SetUpdateState(False); +end; + +function TCnAnsiStrings.Equals(Strings: TCnAnsiStrings): Boolean; +var + I, Count: Integer; +begin + Result := False; + Count := GetCount; + if Count <> Strings.GetCount then Exit; + for I := 0 to Count - 1 do if Get(I) <> Strings.Get(I) then Exit; + Result := True; +end; + +procedure TCnAnsiStrings.Error(const Msg: AnsiString; Data: Integer); + +{$IFDEF MSWINDOWS} + function ReturnAddr: Pointer; + asm + MOV EAX,[EBP+4] + end; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + raise EStringListError.CreateFmt(string(Msg), [Data]) at ReturnAddr; +{$ELSE} + raise EStringListError.CreateFmt(string(Msg), [Data]); +{$ENDIF} +end; + +procedure TCnAnsiStrings.Error(Msg: PResStringRec; Data: Integer); +begin + Error(AnsiString(LoadResString(Msg)), Data); +end; + +procedure TCnAnsiStrings.Exchange(Index1, Index2: Integer); +var + TempObject: TObject; + TempString: AnsiString; +begin + BeginUpdate; + try + TempString := Strings[Index1]; + TempObject := Objects[Index1]; + Strings[Index1] := Strings[Index2]; + Objects[Index1] := Objects[Index2]; + Strings[Index2] := TempString; + Objects[Index2] := TempObject; + finally + EndUpdate; + end; +end; + +function TCnAnsiStrings.ExtractName(const S: AnsiString): AnsiString; +var + P: Integer; +begin + Result := S; + P := AnsiPos(string(NameValueSeparator), string(S)); + if P <> 0 then + SetLength(Result, P-1) else + SetLength(Result, 0); +end; + +function TCnAnsiStrings.GetCapacity: Integer; +begin // descendents may optionally override/replace this default implementation + Result := Count; +end; + +function TCnAnsiStrings.GetCommaText: AnsiString; +var + LOldDefined: TCnAnsiStringsDefined; + LOldDelimiter: AnsiChar; + LOldQuoteChar: AnsiChar; +begin + LOldDefined := FDefined; + LOldDelimiter := FDelimiter; + LOldQuoteChar := FQuoteChar; + Delimiter := ','; + QuoteChar := '"'; + try + Result := GetDelimitedText; + finally + FDelimiter := LOldDelimiter; + FQuoteChar := LOldQuoteChar; + FDefined := LOldDefined; + end; +end; + +function TCnAnsiStrings.GetDelimitedText: AnsiString; +var + S: AnsiString; + P: PAnsiChar; + I, Count: Integer; +begin + Count := GetCount; + if (Count = 1) and (Get(0) = '') then + Result := QuoteChar + QuoteChar + else + begin + Result := ''; + for I := 0 to Count - 1 do + begin + S := Get(I); + P := PAnsiChar(S); + while not (P^ in [#0..' ', QuoteChar, Delimiter]) do + {$IFDEF MSWINDOWS} + P := CharNextA(P); + {$ELSE} + Inc(P); + {$ENDIF} + if (P^ <> #0) then S := AnsiString(AnsiQuotedStr(string(S), Char(QuoteChar))); + Result := Result + S + Delimiter; + end; + System.Delete(Result, Length(Result), 1); + end; +end; + +function TCnAnsiStrings.GetName(Index: Integer): AnsiString; +begin + Result := ExtractName(Get(Index)); +end; + +function TCnAnsiStrings.GetObject(Index: Integer): TObject; +begin + Result := nil; +end; + +function TCnAnsiStrings.GetText: PAnsiChar; +begin + Result := StrNew(PAnsiChar(GetTextStr)); +end; + +function TCnAnsiStrings.GetTextStr: AnsiString; +var + I, L, Size, Count: Integer; + P: PAnsiChar; + S, LB: AnsiString; +begin + Count := GetCount; + Size := 0; + + if FUseSingleLF then + LB := SLineBreakLF + else + LB := SLineBreak; + + for I := 0 to Count - 1 do Inc(Size, Length(Get(I)) + Length(LB)); + SetString(Result, nil, Size); + P := Pointer(Result); + for I := 0 to Count - 1 do + begin + S := Get(I); + L := Length(S); + if L <> 0 then + begin + System.Move(Pointer(S)^, P^, L); + Inc(P, L); + end; + L := Length(LB); + if L <> 0 then + begin + System.Move(Pointer(LB)^, P^, L); + Inc(P, L); + end; + end; +end; + +function TCnAnsiStrings.GetValue(const Name: AnsiString): AnsiString; +var + I: Integer; +begin + I := IndexOfName(Name); + if I >= 0 then + Result := Copy(Get(I), Length(Name) + 2, MaxInt) else + Result := ''; +end; + +function TCnAnsiStrings.IndexOf(const S: AnsiString): Integer; +begin + for Result := 0 to GetCount - 1 do + if CompareStrings(Get(Result), S) = 0 then Exit; + Result := -1; +end; + +function TCnAnsiStrings.IndexOfName(const Name: AnsiString): Integer; +var + P: Integer; + S: AnsiString; +begin + for Result := 0 to GetCount - 1 do + begin + S := Get(Result); + P := AnsiPos(string(NameValueSeparator), string(S)); + if (P <> 0) and (CompareStrings(Copy(S, 1, P - 1), Name) = 0) then Exit; + end; + Result := -1; +end; + +function TCnAnsiStrings.IndexOfObject(AObject: TObject): Integer; +begin + for Result := 0 to GetCount - 1 do + if GetObject(Result) = AObject then Exit; + Result := -1; +end; + +procedure TCnAnsiStrings.InsertObject(Index: Integer; const S: AnsiString; + AObject: TObject); +begin + Insert(Index, S); + PutObject(Index, AObject); +end; + +procedure TCnAnsiStrings.LoadFromFile(const FileName: AnsiString); +var + Stream: TStream; +begin + Stream := TFileStream.Create(string(FileName), fmOpenRead or fmShareDenyWrite); + try + LoadFromStream(Stream); + finally + Stream.Free; + end; +end; + +procedure TCnAnsiStrings.LoadFromStream(Stream: TStream); +var + Size: Integer; + S: AnsiString; +begin + BeginUpdate; + try + Size := Stream.Size - Stream.Position; + SetString(S, nil, Size); + Stream.Read(Pointer(S)^, Size); + SetTextStr(S); + finally + EndUpdate; + end; +end; + +procedure TCnAnsiStrings.Move(CurIndex, NewIndex: Integer); +var + TempObject: TObject; + TempString: AnsiString; +begin + if CurIndex <> NewIndex then + begin + BeginUpdate; + try + TempString := Get(CurIndex); + TempObject := GetObject(CurIndex); + Delete(CurIndex); + InsertObject(NewIndex, TempString, TempObject); + finally + EndUpdate; + end; + end; +end; + +procedure TCnAnsiStrings.Put(Index: Integer; const S: AnsiString); +var + TempObject: TObject; +begin + TempObject := GetObject(Index); + Delete(Index); + InsertObject(Index, S, TempObject); +end; + +procedure TCnAnsiStrings.PutObject(Index: Integer; AObject: TObject); +begin +end; + +procedure TCnAnsiStrings.ReadData(Reader: TReader); +begin + Reader.ReadListBegin; + BeginUpdate; + try + Clear; + while not Reader.EndOfList do Add(AnsiString(Reader.ReadString)); + finally + EndUpdate; + end; + Reader.ReadListEnd; +end; + +procedure TCnAnsiStrings.SaveToFile(const FileName: AnsiString); +var + Stream: TStream; +begin + Stream := TFileStream.Create(string(FileName), fmCreate); + try + SaveToStream(Stream); + finally + Stream.Free; + end; +end; + +procedure TCnAnsiStrings.SaveToStream(Stream: TStream); +var + S: AnsiString; +begin + S := GetTextStr; + Stream.WriteBuffer(Pointer(S)^, Length(S)); +end; + +procedure TCnAnsiStrings.SetCapacity(NewCapacity: Integer); +begin + // do nothing - descendents may optionally implement this method +end; + +procedure TCnAnsiStrings.SetCommaText(const Value: AnsiString); +begin + Delimiter := ','; + QuoteChar := '"'; + SetDelimitedText(Value); +end; + +procedure TCnAnsiStrings.SetStringsAdapter(const Value: ICnStringsAdapter); +begin + if FAdapter <> nil then FAdapter.ReleaseStrings; + FAdapter := Value; + if FAdapter <> nil then FAdapter.ReferenceStrings(Self); +end; + +procedure TCnAnsiStrings.SetText(Text: PAnsiChar); +begin + SetTextStr(Text); +end; + +procedure TCnAnsiStrings.SetTextStr(const Value: AnsiString); +var + P, Start: PAnsiChar; + S: AnsiString; +begin + BeginUpdate; + try + Clear; + P := Pointer(Value); + if P <> nil then + while P^ <> #0 do + begin + Start := P; + while not (P^ in [#0, #10, #13]) do Inc(P); + SetString(S, Start, P - Start); + Add(S); + if P^ = #13 then Inc(P); + if P^ = #10 then Inc(P); + end; + finally + EndUpdate; + end; +end; + +procedure TCnAnsiStrings.SetUpdateState(Updating: Boolean); +begin +end; + +procedure TCnAnsiStrings.SetValue(const Name, Value: AnsiString); +var + I: Integer; +begin + I := IndexOfName(Name); + if Value <> '' then + begin + if I < 0 then I := Add(''); + Put(I, Name + NameValueSeparator + Value); + end else + begin + if I >= 0 then Delete(I); + end; +end; + +procedure TCnAnsiStrings.WriteData(Writer: TWriter); +var + I: Integer; +begin + Writer.WriteListBegin; + for I := 0 to Count - 1 do Writer.WriteString(string(Get(I))); + Writer.WriteListEnd; +end; + +procedure TCnAnsiStrings.SetDelimitedText(const Value: AnsiString); +var + P, P1: PAnsiChar; + S: AnsiString; +begin + BeginUpdate; + try + Clear; + P := PAnsiChar(Value); + while P^ in [#1..' '] do + {$IFDEF MSWINDOWS} + P := CharNextA(P); + {$ELSE} + Inc(P); + {$ENDIF} + while P^ <> #0 do + begin + if P^ = QuoteChar then + S := AnsiExtractQuotedStr(P, QuoteChar) + else + begin + P1 := P; + while (P^ > ' ') and (P^ <> Delimiter) do + {$IFDEF MSWINDOWS} + P := CharNextA(P); + {$ELSE} + Inc(P); + {$ENDIF} + SetString(S, P1, P - P1); + end; + Add(S); + while P^ in [#1..' '] do + {$IFDEF MSWINDOWS} + P := CharNextA(P); + {$ELSE} + Inc(P); + {$ENDIF} + if P^ = Delimiter then + begin + P1 := P; + {$IFDEF MSWINDOWS} + if CharNextA(P1)^ = #0 then + {$ELSE} + Inc(P1); + if P1^ = #0 then + {$ENDIF} + Add(''); + repeat + {$IFDEF MSWINDOWS} + P := CharNextA(P); + {$ELSE} + Inc(P); + {$ENDIF} + until not (P^ in [#1..' ']); + end; + end; + finally + EndUpdate; + end; +end; + +function TCnAnsiStrings.GetDelimiter: AnsiChar; +begin + if not (sdDelimiter in FDefined) then + Delimiter := ','; + Result := FDelimiter; +end; + +function TCnAnsiStrings.GetQuoteChar: AnsiChar; +begin + if not (sdQuoteChar in FDefined) then + QuoteChar := '"'; + Result := FQuoteChar; +end; + +procedure TCnAnsiStrings.SetDelimiter(const Value: AnsiChar); +begin + if (FDelimiter <> Value) or not (sdDelimiter in FDefined) then + begin + Include(FDefined, sdDelimiter); + FDelimiter := Value; + end +end; + +procedure TCnAnsiStrings.SetQuoteChar(const Value: AnsiChar); +begin + if (FQuoteChar <> Value) or not (sdQuoteChar in FDefined) then + begin + Include(FDefined, sdQuoteChar); + FQuoteChar := Value; + end +end; + +function TCnAnsiStrings.CompareStrings(const S1, S2: AnsiString): Integer; +begin + Result := AnsiCompareText(string(S1), string(S2)); +end; + +function TCnAnsiStrings.GetNameValueSeparator: AnsiChar; +begin + if not (sdNameValueSeparator in FDefined) then + NameValueSeparator := '='; + Result := FNameValueSeparator; +end; + +procedure TCnAnsiStrings.SetNameValueSeparator(const Value: AnsiChar); +begin + if (FNameValueSeparator <> Value) or not (sdNameValueSeparator in FDefined) then + begin + Include(FDefined, sdNameValueSeparator); + FNameValueSeparator := Value; + end +end; + +function TCnAnsiStrings.GetValueFromIndex(Index: Integer): AnsiString; +begin + if Index >= 0 then + Result := Copy(Get(Index), Length(Names[Index]) + 2, MaxInt) else + Result := ''; +end; + +procedure TCnAnsiStrings.SetValueFromIndex(Index: Integer; const Value: AnsiString); +begin + if Value <> '' then + begin + if Index < 0 then Index := Add(''); + Put(Index, Names[Index] + NameValueSeparator + Value); + end + else + if Index >= 0 then Delete(Index); +end; + +{ TCnAnsiStringList } + +destructor TCnAnsiStringList.Destroy; +begin + FOnChange := nil; + FOnChanging := nil; + inherited Destroy; + if FCount <> 0 then Finalize(FList^[0], FCount); + FCount := 0; + SetCapacity(0); +end; + +function TCnAnsiStringList.Add(const S: AnsiString): Integer; +begin + Result := AddObject(S, nil); +end; + +function TCnAnsiStringList.AddObject(const S: AnsiString; AObject: TObject): Integer; +begin + if not Sorted then + Result := FCount + else + if Find(S, Result) then + case Duplicates of + dupIgnore: Exit; + dupError: Error(@SDuplicateString, 0); + end; + InsertItem(Result, S, AObject); +end; + +procedure TCnAnsiStringList.Changed; +begin + if (FUpdateCount = 0) and Assigned(FOnChange) then + FOnChange(Self); +end; + +procedure TCnAnsiStringList.Changing; +begin + if (FUpdateCount = 0) and Assigned(FOnChanging) then + FOnChanging(Self); +end; + +procedure TCnAnsiStringList.Clear; +begin + if FCount <> 0 then + begin + Changing; + Finalize(FList^[0], FCount); + FCount := 0; + SetCapacity(0); + Changed; + end; +end; + +procedure TCnAnsiStringList.Delete(Index: Integer); +begin + if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index); + Changing; + Finalize(FList^[Index]); + Dec(FCount); + if Index < FCount then + System.Move(FList^[Index + 1], FList^[Index], + (FCount - Index) * SizeOf(TCnAnsiStringItem)); + Changed; +end; + +procedure TCnAnsiStringList.Exchange(Index1, Index2: Integer); +begin + if (Index1 < 0) or (Index1 >= FCount) then Error(@SListIndexError, Index1); + if (Index2 < 0) or (Index2 >= FCount) then Error(@SListIndexError, Index2); + Changing; + ExchangeItems(Index1, Index2); + Changed; +end; + +procedure TCnAnsiStringList.ExchangeItems(Index1, Index2: Integer); +var + Temp: TCnNativeInt; + Item1, Item2: PStringItem; +begin + Item1 := @FList^[Index1]; + Item2 := @FList^[Index2]; + Temp := TCnNativeInt(Item1^.FString); + TCnNativeInt(Item1^.FString) := TCnNativeInt(Item2^.FString); + TCnNativeInt(Item2^.FString) := Temp; + Temp := TCnNativeInt(Item1^.FObject); + TCnNativeInt(Item1^.FObject) := TCnNativeInt(Item2^.FObject); + TCnNativeInt(Item2^.FObject) := Temp; +end; + +function TCnAnsiStringList.Find(const S: AnsiString; var Index: Integer): Boolean; +var + L, H, I, C: Integer; +begin + Result := False; + L := 0; + H := FCount - 1; + while L <= H do + begin + I := (L + H) shr 1; + C := CompareStrings(FList^[I].FString, S); + if C < 0 then L := I + 1 else + begin + H := I - 1; + if C = 0 then + begin + Result := True; + if Duplicates <> dupAccept then L := I; + end; + end; + end; + Index := L; +end; + +function TCnAnsiStringList.Get(Index: Integer): AnsiString; +begin + if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index); + Result := FList^[Index].FString; +end; + +function TCnAnsiStringList.GetCapacity: Integer; +begin + Result := FCapacity; +end; + +function TCnAnsiStringList.GetCount: Integer; +begin + Result := FCount; +end; + +function TCnAnsiStringList.GetObject(Index: Integer): TObject; +begin + if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index); + Result := FList^[Index].FObject; +end; + +procedure TCnAnsiStringList.Grow; +var + Delta: Integer; +begin + if FCapacity > 64 then Delta := FCapacity div 4 else + if FCapacity > 8 then Delta := 16 else + Delta := 4; + SetCapacity(FCapacity + Delta); +end; + +function TCnAnsiStringList.IndexOf(const S: AnsiString): Integer; +begin + if not Sorted then Result := inherited IndexOf(S) else + if not Find(S, Result) then Result := -1; +end; + +procedure TCnAnsiStringList.Insert(Index: Integer; const S: AnsiString); +begin + InsertObject(Index, S, nil); +end; + +procedure TCnAnsiStringList.InsertObject(Index: Integer; const S: AnsiString; + AObject: TObject); +begin + if Sorted then Error(@SSortedListError, 0); + if (Index < 0) or (Index > FCount) then Error(@SListIndexError, Index); + InsertItem(Index, S, AObject); +end; + +procedure TCnAnsiStringList.InsertItem(Index: Integer; const S: AnsiString; AObject: TObject); +begin + Changing; + if FCount = FCapacity then Grow; + if Index < FCount then + System.Move(FList^[Index], FList^[Index + 1], + (FCount - Index) * SizeOf(TCnAnsiStringItem)); + with FList^[Index] do + begin + Pointer(FString) := nil; + FObject := AObject; + FString := S; + end; + Inc(FCount); + Changed; +end; + +procedure TCnAnsiStringList.Put(Index: Integer; const S: AnsiString); +begin + if Sorted then Error(@SSortedListError, 0); + if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index); + Changing; + FList^[Index].FString := S; + Changed; +end; + +procedure TCnAnsiStringList.PutObject(Index: Integer; AObject: TObject); +begin + if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index); + Changing; + FList^[Index].FObject := AObject; + Changed; +end; + +procedure TCnAnsiStringList.QuickSort(L, R: Integer; SCompare: TCnAnsiStringListSortCompare); +var + I, J, P: Integer; +begin + repeat + I := L; + J := R; + P := (L + R) shr 1; + repeat + while SCompare(Self, I, P) < 0 do Inc(I); + while SCompare(Self, J, P) > 0 do Dec(J); + if I <= J then + begin + ExchangeItems(I, J); + if P = I then + P := J + else if P = J then + P := I; + Inc(I); + Dec(J); + end; + until I > J; + if L < J then QuickSort(L, J, SCompare); + L := I; + until I >= R; +end; + +procedure TCnAnsiStringList.SetCapacity(NewCapacity: Integer); +begin + ReallocMem(FList, NewCapacity * SizeOf(TCnAnsiStringItem)); + FCapacity := NewCapacity; +end; + +procedure TCnAnsiStringList.SetSorted(Value: Boolean); +begin + if FSorted <> Value then + begin + if Value then Sort; + FSorted := Value; + end; +end; + +procedure TCnAnsiStringList.SetUpdateState(Updating: Boolean); +begin + if Updating then Changing else Changed; +end; + +function StringListCompareStrings(List: TCnAnsiStringList; Index1, Index2: Integer): Integer; +begin + Result := List.CompareStrings(List.FList^[Index1].FString, + List.FList^[Index2].FString); +end; + +procedure TCnAnsiStringList.Sort; +begin + CustomSort(StringListCompareStrings); +end; + +procedure TCnAnsiStringList.CustomSort(Compare: TCnAnsiStringListSortCompare); +begin + if not Sorted and (FCount > 1) then + begin + Changing; + QuickSort(0, FCount - 1, Compare); + Changed; + end; +end; + +function TCnAnsiStringList.CompareStrings(const S1, S2: AnsiString): Integer; +begin + if CaseSensitive then + Result := AnsiCompareStr(string(S1), string(S2)) + else + Result := AnsiCompareText(string(S1), string(S2)); +end; + +procedure TCnAnsiStringList.SetCaseSensitive(const Value: Boolean); +begin + if Value <> FCaseSensitive then + begin + FCaseSensitive := Value; + if Sorted then Sort; + end; +end; + +{ TCnAnsiStringHash } + +procedure TCnAnsiStringHash.Add(const Key: AnsiString; Value: Integer); +var + Hash: Integer; + Bucket: PCnAnsiHashItem; +begin + Hash := HashOf(Key) mod Cardinal(Length(Buckets)); + New(Bucket); + Bucket^.Key := Key; + Bucket^.Value := Value; + Bucket^.Next := Buckets[Hash]; + Buckets[Hash] := Bucket; +end; + +procedure TCnAnsiStringHash.Clear; +var + I: Integer; + P, N: PCnAnsiHashItem; +begin + for I := 0 to Length(Buckets) - 1 do + begin + P := Buckets[I]; + while P <> nil do + begin + N := P^.Next; + Dispose(P); + P := N; + end; + Buckets[I] := nil; + end; +end; + +constructor TCnAnsiStringHash.Create(Size: Cardinal); +begin + inherited Create; + SetLength(Buckets, Size); +end; + +destructor TCnAnsiStringHash.Destroy; +begin + Clear; + inherited Destroy; +end; + +function TCnAnsiStringHash.Find(const Key: AnsiString): PPCnAnsiHashItem; +var + Hash: Integer; +begin + Hash := HashOf(Key) mod Cardinal(Length(Buckets)); + Result := @Buckets[Hash]; + while Result^ <> nil do + begin + if Result^.Key = Key then + Exit + else + Result := @Result^.Next; + end; +end; + +function TCnAnsiStringHash.HashOf(const Key: AnsiString): Cardinal; +var + I: Integer; +begin + Result := 0; + for I := 1 to Length(Key) do + Result := ((Result shl 2) or (Result shr (SizeOf(Result) * 8 - 2))) xor + Ord(Key[I]); +end; + +function TCnAnsiStringHash.Modify(const Key: AnsiString; Value: Integer): Boolean; +var + P: PCnAnsiHashItem; +begin + P := Find(Key)^; + if P <> nil then + begin + Result := True; + P^.Value := Value; + end + else + Result := False; +end; + +procedure TCnAnsiStringHash.Remove(const Key: AnsiString); +var + P: PCnAnsiHashItem; + Prev: PPCnAnsiHashItem; +begin + Prev := Find(Key); + P := Prev^; + if P <> nil then + begin + Prev^ := P^.Next; + Dispose(P); + end; +end; + +function TCnAnsiStringHash.ValueOf(const Key: AnsiString): Integer; +var + P: PCnAnsiHashItem; +begin + P := Find(Key)^; + if P <> nil then + Result := P^.Value + else + Result := -1; +end; + +{ TCnHashedAnsiStringList } + +procedure TCnHashedAnsiStringList.Changed; +begin + inherited Changed; + FValueHashValid := False; + FNameHashValid := False; +end; + +destructor TCnHashedAnsiStringList.Destroy; +begin + FValueHash.Free; + FNameHash.Free; + inherited Destroy; +end; + +function TCnHashedAnsiStringList.IndexOf(const S: AnsiString): Integer; +begin + UpdateValueHash; + if not CaseSensitive then + Result := FValueHash.ValueOf(AnsiString(AnsiUpperCase(string(S)))) + else + Result := FValueHash.ValueOf(S); +end; + +function TCnHashedAnsiStringList.IndexOfName(const Name: AnsiString): Integer; +begin + UpdateNameHash; + if not CaseSensitive then + Result := FNameHash.ValueOf(AnsiString(AnsiUpperCase(string(Name)))) + else + Result := FNameHash.ValueOf(Name); +end; + +procedure TCnHashedAnsiStringList.UpdateNameHash; +var + I: Integer; + P: Integer; + Key: AnsiString; +begin + if FNameHashValid then Exit; + + if FNameHash = nil then + FNameHash := TCnAnsiStringHash.Create + else + FNameHash.Clear; + for I := 0 to Count - 1 do + begin + Key := Get(I); + P := AnsiPos('=', string(Key)); + if P <> 0 then + begin + if not CaseSensitive then + Key := AnsiString(AnsiUpperCase(string(Copy(Key, 1, P - 1)))) + else + Key := Copy(Key, 1, P - 1); + FNameHash.Add(Key, I); + end; + end; + FNameHashValid := True; +end; + +procedure TCnHashedAnsiStringList.UpdateValueHash; +var + I: Integer; +begin + if FValueHashValid then Exit; + + if FValueHash = nil then + FValueHash := TCnAnsiStringHash.Create + else + FValueHash.Clear; + for I := 0 to Count - 1 do + if not CaseSensitive then + FValueHash.Add(AnsiString(AnsiUpperCase(string(Self[I]))), I) + else + FValueHash.Add(Self[I], I); + FValueHashValid := True; +end; + +// жһַǷƥķָ +function IsSepChar(AChar: Char): Boolean; +begin +{$IFDEF UNICODE} + Result := not CharInSet(AChar, ['0'..'9', 'A'..'Z', 'a'..'z', '_']); +{$ELSE} + Result := not (AChar in ['0'..'9', 'A'..'Z', 'a'..'z', '_']); +{$ENDIF} +end; + +function IsSepCharA(AChar: AnsiChar): Boolean; +begin + Result := not (AChar in ['0'..'9', 'A'..'Z', 'a'..'z', '_']); +end; + +function IsSepCharW(AChar: WideChar): Boolean; +begin + Result := (Ord(AChar) < 127) and not (AnsiChar(AChar) in ['0'..'9', 'A'..'Z', 'a'..'z', '_']); +end; + +function CnStringReplace(const S, OldPattern, NewPattern: string; + Flags: TCnReplaceFlags): string; +var + SearchStr, Patt, NewStr: string; + Offset, TailOffset: Integer; + IsWhole: Boolean; +begin + if crfIgnoreCase in Flags then + begin +{$IFDEF UNICODE} + SearchStr := UpperCase(S); + Patt := UpperCase(OldPattern); +{$ELSE} + SearchStr := AnsiUpperCase(S); + Patt := AnsiUpperCase(OldPattern); +{$ENDIF} + end + else + begin + SearchStr := S; + Patt := OldPattern; + end; + + NewStr := S; + Result := ''; + + while SearchStr <> '' do + begin +{$IFDEF UNICODE} + Offset := Pos(Patt, SearchStr); +{$ELSE} + Offset := AnsiPos(Patt, SearchStr); +{$ENDIF} + IsWhole := True; + if Offset = 0 then + begin + Result := Result + NewStr; + Break; + end + else if crfWholeWord in Flags then + begin + // ҵӴҪƥ䣬жϣ + // ͷͷǷָββǷָ + if (Offset > 1) and not IsSepChar(SearchStr[Offset - 1]) then + IsWhole := False + else + begin + TailOffset := Offset + Length(Patt); // ָƥһַ + if (TailOffset <= Length(SearchStr)) and not IsSepChar(SearchStr[TailOffset]) then + IsWhole := False; + end; + + // õǷƥĽ + end; + + if not (crfWholeWord in Flags) or IsWhole then // ͨƥƥ + begin + // 滻һ + Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern; + NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt); + if not (crfReplaceAll in Flags) then + begin + Result := Result + NewStr; + Break; + end; + end + else // ƥҪ£δƥ䣬滻 + begin + Result := Result + Copy(NewStr, 1, Offset - 1) + OldPattern; // ע OldePattern滻 + NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt); + end; + SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt); + end; +end; + +{$IFDEF UNICODE} + +function CnStringReplaceA(const S, OldPattern, NewPattern: AnsiString; + Flags: TCnReplaceFlags): AnsiString; +var + SearchStr, Patt, NewStr: AnsiString; + Offset, TailOffset: Integer; + IsWhole: Boolean; +begin + if crfIgnoreCase in Flags then + begin + SearchStr := AnsiUpperCase(S); + Patt := AnsiUpperCase(OldPattern); + end + else + begin + SearchStr := S; + Patt := OldPattern; + end; + + NewStr := S; + Result := ''; + + while SearchStr <> '' do + begin + Offset := AnsiPos(Patt, SearchStr); + IsWhole := True; + if Offset = 0 then + begin + Result := Result + NewStr; + Break; + end + else if crfWholeWord in Flags then + begin + // ҵӴҪƥ䣬жϣ + // ͷͷǷָββǷָ + if (Offset > 1) and not IsSepCharA(SearchStr[Offset - 1]) then + IsWhole := False + else + begin + TailOffset := Offset + Length(Patt); // ָƥһַ + if (TailOffset <= Length(SearchStr)) and not IsSepCharA(SearchStr[TailOffset]) then + IsWhole := False; + end; + + // õǷƥĽ + end; + + if not (crfWholeWord in Flags) or IsWhole then // ͨƥƥ + begin + // 滻һ + Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern; + NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt); + if not (crfReplaceAll in Flags) then + begin + Result := Result + NewStr; + Break; + end; + end + else // ƥҪ£δƥ䣬滻 + begin + Result := Result + Copy(NewStr, 1, Offset - 1) + OldPattern; // ע OldePattern滻 + NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt); + end; + SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt); + end; +end; + +{$ELSE} + +function CnStringReplaceW(const S, OldPattern, NewPattern: WideString; + Flags: TCnReplaceFlags): WideString; +var + SearchStr, Patt, NewStr: WideString; + Offset, TailOffset: Integer; + IsWhole: Boolean; +begin + if crfIgnoreCase in Flags then + begin + SearchStr := UpperCase(S); + Patt := UpperCase(OldPattern); + end + else + begin + SearchStr := S; + Patt := OldPattern; + end; + + NewStr := S; + Result := ''; + + while SearchStr <> '' do + begin + Offset := Pos(Patt, SearchStr); + IsWhole := True; + if Offset = 0 then + begin + Result := Result + NewStr; + Break; + end + else if crfWholeWord in Flags then + begin + // ҵӴҪƥ䣬жϣ + // ͷͷǷָββǷָ + if (Offset > 1) and not IsSepCharW(SearchStr[Offset - 1]) then + IsWhole := False + else + begin + TailOffset := Offset + Length(Patt); // ָƥһַ + if (TailOffset <= Length(SearchStr)) and not IsSepCharW(SearchStr[TailOffset]) then + IsWhole := False; + end; + + // õǷƥĽ + end; + + if not (crfWholeWord in Flags) or IsWhole then // ͨƥƥ + begin + // 滻һ + Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern; + NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt); + if not (crfReplaceAll in Flags) then + begin + Result := Result + NewStr; + Break; + end; + end + else // ƥҪ£δƥ䣬滻 + begin + Result := Result + Copy(NewStr, 1, Offset - 1) + OldPattern; // ע OldePattern滻 + NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt); + end; + SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt); + end; +end; + +{$ENDIF} + +function CnPosEx(const SubStr, S: string; CaseSensitive: Boolean; WholeWords: + Boolean; StartCount: Integer): Integer; +var + P: PChar; + I, Count, Len, SubLen: Integer; + StrUpper, SubUpper: string; +begin + Result := 0; + if (SubStr = '') or (S = '') or (StartCount < 1) then + Exit; + + Len := Length(S); + SubLen := Length(SubStr); + if SubLen > Len then + Exit; + + if not CaseSensitive then + begin + StrUpper := UpperCase(S); + SubUpper := UpperCase(SubStr); + P := PChar(StrUpper); + end + else + P := PChar(S); + + Count := 0; + for I := 1 to Len - SubLen + 1 do + begin + if (CaseSensitive and (P^ = SubStr[1]) and + (CompareMem(P, PChar(SubStr), SubLen * SizeOf(Char)))) + or + (not CaseSensitive and (P^ = SubUpper[1]) and + (CompareMem(P, PChar(SubUpper), SubLen * SizeOf(Char)))) then + begin + if WholeWords then + begin + // Ƿƥ + if ((I = 1) or IsSepChar((P - 1)^)) and + ((I + SubLen - 1 >= Len) or IsSepChar((P + SubLen)^)) then + begin + Inc(Count); + if Count = StartCount then + begin + Result := I; + Exit; + end; + end; + end + else + begin + Inc(Count); + if Count = StartCount then + begin + Result := I; + Exit; + end; + end; + end; + Inc(P); + end; +end; + +procedure CnSplitString(const Sub: string; const Str: string; Strings: TStrings); +var + S: string; + P, SubLen: Integer; +begin + if Strings = nil then + Exit; // Կָ + + Strings.Clear; // ԭ + + // ָΪյַΪһĿ + if Sub = '' then + begin + Strings.Add(Str); + Exit; + end; + + // ԴַΪյһĿ + if Str = '' then + begin + Strings.Add(''); + Exit; + end; + + SubLen := Length(Sub); + S := Str; // ԴַĸĴ˸ + + while S <> '' do + begin + P := Pos(Sub, S); // ʣַвҷָ + + if P = 0 then + begin + // ûиָʣಿΪһĿ + Strings.Add(S); + Break; + end; + + // ȡӿͷָǰݣΪգ + Strings.Add(Copy(S, 1, P - 1)); + + // ɾѴIJ֣ҵķָ + Delete(S, 1, P + SubLen - 1); + + // ɾַΪգԭַԷָβҪһĿ + if S = '' then + Strings.Add(''); + end; +end; + +{$WARNINGS ON} + +{ TCnStringBuilder } + +constructor TCnStringBuilder.Create; +begin + inherited; + if not FModeIsFromOut then // ⲿδָʱԶģʽ + begin +{$IFDEF UNICODE} + FAnsiMode := False; +{$ELSE} + FAnsiMode := True; +{$ENDIF} + end + else + FAnsiMode := FOutMode; + + if FAnsiMode then + FMaxCharCapacity := MaxInt + else + FMaxCharCapacity := MaxInt div 2; + + CharCapacity := STRING_BUILDER_DEFAULT_CAPACITY; + FCharLength := 0; +end; + +function TCnStringBuilder.Append(const Value: string): TCnStringBuilder; +begin +{$IFDEF UNICODE} + if FAnsiMode then + Result := AppendAnsi(AnsiString(Value)) + else + Result := AppendString(Value); +{$ELSE} + if FAnsiMode then + Result := AppendString(Value) + else + Result := AppendWide(WideString(Value)); +{$ENDIF} +end; + +{$IFDEF UNICODE} + +function TCnStringBuilder.AppendAnsi(const Value: AnsiString): TCnStringBuilder; +var + Delta, OL: Integer; +begin + Delta := Length(Value); + if Delta <> 0 then + begin + OL := CharLength; + CharLength := CharLength + Delta; + if CharLength > CharCapacity then + ExpandCharCapacity; + Move(Pointer(Value)^, (PAnsiChar(Pointer(FAnsiData)) + OL)^, Delta * SizeOf(AnsiChar)); + end; + Result := Self; +end; + +{$ELSE} + +function TCnStringBuilder.AppendWide(const Value: WideString): TCnStringBuilder; +var + Delta, OL: Integer; +begin + Delta := Length(Value); + if Delta <> 0 then + begin + OL := CharLength; + CharLength := CharLength + Delta; + if CharLength > CharCapacity then + ExpandCharCapacity; + Move(Pointer(Value)^, (PWideChar(Pointer(FWideData)) + OL)^, Delta * SizeOf(WideChar)); + end; + Result := Self; +end; + +{$ENDIF} + +constructor TCnStringBuilder.Create(IsAnsi: Boolean); +begin + FModeIsFromOut := True; + FOutMode := IsAnsi; // ⲿָ AnsiMode + Create; +end; + +destructor TCnStringBuilder.Destroy; +begin + inherited; + +end; + +procedure TCnStringBuilder.ExpandCharCapacity; +var + NC: Integer; +begin + NC := (CharCapacity * 3) div 2; + if CharLength > NC then + NC := CharLength * 2; + if NC > FMaxCharCapacity then + NC := FMaxCharCapacity; + if NC < 0 then + NC := CharLength; + + CharCapacity := NC; +end; + +function TCnStringBuilder.GetCharCapacity: Integer; +begin +{$IFDEF UNICODE} + if FAnsiMode then + Result := Length(FAnsiData) + else + Result := Length(FData); +{$ELSE} + if FAnsiMode then + Result := Length(FData) + else + Result := Length(FWideData); +{$ENDIF} +end; + +procedure TCnStringBuilder.SetCharCapacity(const Value: Integer); +begin + if (Value < FCharLength) or (Value > FMaxCharCapacity) then + raise ERangeError.CreateResFmt(@SListCapacityError, [Value]); + +{$IFDEF UNICODE} + if FAnsiMode then + SetLength(FAnsiData, Value) // FAnsiData + else + SetLength(FData, Value); // FData +{$ELSE} + if FAnsiMode then + SetLength(FData, Value) // FData + else + SetLength(FWideData, Value); // FWideData +{$ENDIF} +end; + +procedure TCnStringBuilder.SetCharLength(const Value: Integer); +var + OL: Integer; +begin + if (Value < 0) or (Value > FMaxCharCapacity) then + raise ERangeError.CreateResFmt(@SListCapacityError, [Value]); + + OL := FCharLength; + try + FCharLength := Value; + if FCharLength > CharCapacity then + ExpandCharCapacity; + except + on E: EOutOfMemory do + begin + FCharLength := OL; + raise; + end; + end; +end; + +function TCnStringBuilder.AppendString(const Value: string): TCnStringBuilder; +var + Delta, OL: Integer; +begin + Delta := Length(Value); + if Delta <> 0 then + begin + OL := CharLength; + FCharLength := CharLength + Delta; + if CharLength > CharCapacity then + ExpandCharCapacity; + + Move(Pointer(Value)^, (PChar(Pointer(FData)) + OL)^, Delta * SizeOf(Char)); + end; + Result := Self; +end; + +function TCnStringBuilder.ToString: string; +begin + if FCharLength = CharCapacity then + Result := FData + else + Result := Copy(FData, 1, FCharLength); +end; + +function TCnStringBuilder.ToAnsiString: AnsiString; +begin +{$IFDEF UNICODE} + if FAnsiMode then // Unicode Ansi ģʽ FAnsiDataת + begin + if FCharLength = CharCapacity then + Result := FAnsiData + else + Result := Copy(FAnsiData, 1, FCharLength); + end + else // Unicode Ƿ Ansi ģʽ FData AnsiString ת + begin + if FCharLength = CharCapacity then + Result := AnsiString(FData) + else + Result := AnsiString(Copy(FData, 1, FCharLength)); + end; +{$ELSE} + Result := ToString; // Unicode µ ToString +{$ENDIF} +end; + +function TCnStringBuilder.ToWideString: WideString; +begin +{$IFNDEF UNICODE} + if FAnsiMode then // Unicode Ansi ģʽ FData WideString ת + begin + if FCharLength = CharCapacity then + Result := WideString(FData) + else + Result := WideString(Copy(FData, 1, FCharLength)); + end + else // Unicode Ƿ Ansi ģʽ FWideDataת + begin + if FCharLength = CharCapacity then + Result := FWideData + else + Result := Copy(FWideData, 1, FCharLength); + end; +{$ELSE} + Result := ToString; // Unicode µ ToString +{$ENDIF} +end; + +function TCnStringBuilder.Append(Value: Integer): TCnStringBuilder; +begin + Result := Append(IntToStr(Value)); +end; + +function TCnStringBuilder.Append(Value: SmallInt): TCnStringBuilder; +begin + Result := Append(IntToStr(Value)); +end; + +function TCnStringBuilder.Append(Value: TObject): TCnStringBuilder; +begin +{$IFDEF OBJECT_HAS_TOSTRING} + Result := Append(Value.ToString); +{$ELSE} + Result := Append(IntToHex(TCnNativeInt(Value), 2)); +{$ENDIF} +end; + +function TCnStringBuilder.Append(Value: Int64): TCnStringBuilder; +begin + Result := Append(IntToStr(Value)); +end; + +function TCnStringBuilder.Append(Value: Double): TCnStringBuilder; +begin + Result := Append(FloatToStr(Value)); +end; + +function TCnStringBuilder.Append(Value: Byte): TCnStringBuilder; +begin + Result := Append(IntToStr(Value)); +end; + +function TCnStringBuilder.Append(Value: Boolean): TCnStringBuilder; +begin + if Value then + Result := Append('True') + else + Result := Append('False'); +end; + +function TCnStringBuilder.AppendCurrency(Value: Currency): TCnStringBuilder; +begin + Result := Append(CurrToStr(Value)); +end; + +function TCnStringBuilder.AppendChar(Value: Char): TCnStringBuilder; +var + S: string; +begin + SetLength(S, 1); + Move(Value, S[1], SizeOf(Char)); + Result := Append(S); +end; + +function TCnStringBuilder.Append(Value: ShortInt): TCnStringBuilder; +begin + Result := Append(IntToStr(Value)); +end; + +function TCnStringBuilder.Append(Value: Char; + RepeatCount: Integer): TCnStringBuilder; +begin + Result := Append(StringOfChar(Value, RepeatCount)); +end; + +function TCnStringBuilder.Append(Value: PAnsiChar): TCnStringBuilder; +begin + Result := Append(string(Value)); +end; + +function TCnStringBuilder.Append(const Value: string; StartIndex, + Count: Integer): TCnStringBuilder; +begin + Result := Append(Copy(Value, StartIndex, Count)); +end; + +function TCnStringBuilder.Append(Value: Cardinal): TCnStringBuilder; +begin + Result := Append(UInt32ToStr(Value)); +end; + +{$IFDEF SUPPORT_UINT64} + +function TCnStringBuilder.Append(Value: UInt64): TCnStringBuilder; +begin + Result := Append(UInt64ToStr(Value)); +end; + +{$ENDIF} + +function TCnStringBuilder.Append(Value: Single): TCnStringBuilder; +begin + Result := Append(FloatToStr(Value)); +end; + +function TCnStringBuilder.Append(Value: Word): TCnStringBuilder; +begin + Result := Append(IntToStr(Value)); +end; + +procedure TCnStringBuilder.Clear; +begin + CharLength := 0; + CharCapacity := STRING_BUILDER_DEFAULT_CAPACITY; +end; + +function TCnStringBuilder.AppendLine: TCnStringBuilder; +begin + Result := Append(SLineBreak); +end; + +function TCnStringBuilder.AppendLine(const Value: string): TCnStringBuilder; +begin + Result := Append(Value + SLineBreak); +end; + +function TCnStringBuilder.Append(const AFormat: string; + const Args: array of const): TCnStringBuilder; +begin + Result := Append(Format(AFormat, Args)); +end; + +function TCnStringBuilder.AppendAnsiChar(Value: AnsiChar): TCnStringBuilder; +var + S: AnsiString; +begin + SetLength(S, 1); + Move(Value, S[1], SizeOf(AnsiChar)); +{$IFDEF UNICODE} + Result := AppendAnsi(S); +{$ELSE} + Result := Append(S); // Unicode S תΪ string ܻʺ +{$ENDIF} +end; + +function TCnStringBuilder.AppendWideChar(Value: WideChar): TCnStringBuilder; +var + S: WideString; +begin + SetLength(S, 1); + Move(Value, S[1], SizeOf(WideChar)); +{$IFDEF UNICODE} + Result := Append(S); +{$ELSE} + Result := AppendWide(S); +{$ENDIF} +end; + +end. diff --git a/CnPack/Common/CnWideStrings.pas b/CnPack/Common/CnWideStrings.pas new file mode 100644 index 0000000..ae4115b --- /dev/null +++ b/CnPack/Common/CnWideStrings.pas @@ -0,0 +1,2215 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnWideStrings; +{* |
+================================================================================ +* ƣ +* ԪƣWideStrings Ԫ֧ Win32/64 Posix +* ԪߣCnPack +* עõԪʵ˼ TCnWideStringList 벿 Unicode ַ +* Լչ UTF-8 UTF-16 ı뺯֧ UTF-16 еַֽ UTF8-MB4 +* +* ⣬Ԫڴ Ansi ַ Utf16 ַתʱ漰 +* һַֽռпռʾȱ +* ͬųǰ߲ܵͬʴҪ ByteLength DisplayLength +* ȡַֽ IDE Ϊأ ByteLength ϵк +* ռпռʾȱҪ IDE Ϊйأ IDE 汾йأ +* DisplayLength ϵкͬط벻ͬ Calculator м +* +* 䣺Lazarus IDE бʱʹ LConvEncoding תƺ +* +* ƽ̨WinXP SP3 + Delphi 5.0 +* ݲԣ +* õԪеַϱػʽ +* ļ¼2025.08.06 V1.3 +* Ansi תΪ Utf8 ֧ FPC +* 2024.08.01 V1.3 +* ַָʾȼص㲿Զ +* ֳ Ansi ByteLength DisplayLength ϵк +* жʾȡеȣҪ DisplayLength ϵк +* IDE Ҫô붨ƻ Calculator +* 2022.11.25 V1.2 +* CnGB18030 аƹ Unicode +* 2022.11.10 V1.1 +* UTF-8 ֧ UTF8-MB4 UTF-16 еַֽ +* 2010.01.16 by ZhouJingyu +* ʼύ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +// {$DEFINE UTF16_BE} + +// Delphi Ĭ UTF16-LEҪ UTF16-BE ַҪ UTF16_BE + +uses + {$IFDEF MSWINDOWS} Windows, {$ENDIF} SysUtils, Classes, CnNative + {$IFDEF LAZARUS}, LConvEncoding {$ENDIF}; + +const + CN_INVALID_CODEPOINT = $FFFFFFFF; + {* Ƿֵ} + + CN_ALTERNATIVE_CHAR = '?'; + {* תʱĬ滻ַ} + +type + ECnWideStringException = class(Exception); + {* ַ쳣} + +{$IFDEF UNICODE} + TCnWideString = string; +{$ELSE} + TCnWideString = WideString; +{$ENDIF} + + TCnCodePoint = type Cardinal; + {* ֵַ߽㣬ڱı뷽ʽ} + + TCn2CharRec = packed record + {* ˫ַֽṹ} + P1: AnsiChar; + P2: AnsiChar; + end; + PCn2CharRec = ^TCn2CharRec; + + TCn4CharRec = packed record + {* ַֽṹ} + P1: AnsiChar; + P2: AnsiChar; + P3: AnsiChar; + P4: AnsiChar; + end; + PCn4CharRec = ^TCn4CharRec; + +{ TCnWideStringList } + + TCnWideListFormat = (wlfAnsi, wlfUtf8, wlfUnicode); + {* 뱣ʱֱֵ֧룬AnsiUtf8Utf16} + + TCnWideStringList = class; + TCnWideStringListSortCompare = function(List: TCnWideStringList; Index1, Index2: Integer): Integer; + + PCnWideStringItem = ^TCnWideStringItem; + TCnWideStringItem = record + FString: WideString; + FObject: TObject; + end; + + TCnWideStringList = class(TPersistent) + {* WideString TStringList ʵ֣Load/Save ʱбĴ} + private + FList: TList; + FUseSingleLF: Boolean; + FLoadFormat: TCnWideListFormat; + FWriteBOM: Boolean; + function GetName(Index: Integer): WideString; + function GetValue(const Name: WideString): WideString; + procedure SetValue(const Name, Value: WideString); + procedure QuickSort(L, R: Integer; SCompare: TCnWideStringListSortCompare); + function GetObject(Index: Integer): TObject; + procedure PutObject(Index: Integer; const Value: TObject); + protected + function Get(Index: Integer): WideString; virtual; + function GetCount: Integer; virtual; + function GetTextStr: WideString; virtual; + procedure Put(Index: Integer; const S: WideString); virtual; + procedure SetTextStr(const Value: WideString); virtual; + public + constructor Create; + destructor Destroy; override; + function Add(const S: WideString): Integer; virtual; + procedure AddStrings(Strings: TCnWideStringList); virtual; + function AddObject(const S: WideString; AObject: TObject): Integer; virtual; + procedure Assign(Source: TPersistent); override; + procedure Clear; virtual; + procedure Delete(Index: Integer); virtual; + procedure Exchange(Index1, Index2: Integer); virtual; + function IndexOf(const S: WideString): Integer; virtual; + function IndexOfName(const Name: WideString): Integer; + procedure Insert(Index: Integer; const S: WideString); virtual; + procedure LoadFromFile(const FileName: WideString); virtual; + procedure LoadFromStream(Stream: TStream); virtual; + procedure SaveToFile(const FileName: WideString; AFormat: TCnWideListFormat = wlfUnicode); virtual; + procedure SaveToStream(Stream: TStream; AFormat: TCnWideListFormat = wlfUnicode); virtual; + procedure CustomSort(Compare: TCnWideStringListSortCompare); virtual; + procedure Sort; virtual; + property Count: Integer read GetCount; + property Names[Index: Integer]: WideString read GetName; + property Objects[Index: Integer]: TObject read GetObject write PutObject; + property Values[const Name: WideString]: WideString read GetValue write SetValue; + property Strings[Index: Integer]: WideString read Get write Put; default; + property Text: WideString read GetTextStr write SetTextStr; + + property UseSingleLF: Boolean read FUseSingleLF write FUseSingleLF; + {* GetTextStr ʱʹõĻǷǵ #10 dz #13#10} + property LoadFormat: TCnWideListFormat read FLoadFormat; + {* LoadFromStream ʱʶĸʽ} + property WriteBOM: Boolean read FWriteBOM write FWriteBOM; + {* Ƿд BOM ͷ} + end; + + TCnWideCharDisplayWideLengthCalculator = function(AWChar: WideChar): Boolean; + {* Կַʾȼصͣͬ Delphi IDE ༭Ҫͬʵ} + +function CnUtf8EncodeWideString(const S: TCnWideString): AnsiString; +{* WideString UTF-8 벢ݷŵ AnsiString зأ Ansi תⶪַ + ֽ֧ UTF-16 ַ UTF8-MB4 + + + const S: WideString/UnicodeString - תĿַ + + ֵAnsiString - UTF-8 ַ +} + +function CnUtf8DecodeToWideString(const S: AnsiString): TCnWideString; +{* UTF-8 AnsiString UTF-8 õ WideString Ansi תⶪַ + ֽ֧ UTF-16 ַ UTF8-MB4 + + + const S: AnsiString - ת UTF-8 ַ + + ֵWideString/UnicodeString - صĿַ +} + +function GetUtf16HighByte(Rec: PCn2CharRec): Byte; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* õһ UTF-16 ˫ַֽĸλֵֽ + + + Rec: PCn2CharRec - ȡ˫ַֽṹָ + + ֵByte - ظλֵֽ +} + +function GetUtf16LowByte(Rec: PCn2CharRec): Byte; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* õһ UTF-16 ˫ַֽĵλֵֽ + + + Rec: PCn2CharRec - ȡ˫ַֽṹָ + + ֵByte - صλֵֽ +} + +procedure SetUtf16HighByte(B: Byte; Rec: PCn2CharRec); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* һ UTF-16 ˫ַֽĸλֵֽ + + + B: Byte - õĸλֵֽ + Rec: PCn2CharRec - õ˫ַֽṹָ + + ֵޣ +} + +procedure SetUtf16LowByte(B: Byte; Rec: PCn2CharRec); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* һ UTF-16 ˫ַֽĵλֵֽ + + + B: Byte - õĵλֵֽ + Rec: PCn2CharRec - õ˫ַֽṹָ + + ֵޣ +} + +function GetCharLengthFromUtf8(Utf8Str: PAnsiChar): Integer; +{* һ UTF-8 UTF8-MB4ַַ + + + Utf8Str: PAnsiChar - UTF-8 ַַ + + ֵInteger - ظַַ +} + +function GetCharLengthFromUtf16(Utf16Str: PWideChar): Integer; +{* һ UTF-16ܻ Unicode չƽַַַֽ + + + Utf16Str: PWideChar - UTF-16 ַַ + + ֵInteger - ظַַ +} + +function GetByteWidthFromUtf8(Utf8Str: PAnsiChar): Integer; +{* һ UTF-8 UTF8-MB4ַĵǰַռֽڡ + + + Utf8Str: PAnsiChar - UTF-8 ַַ + + ֵInteger - ظַֽ +} + +function GetByteWidthFromUtf16(Utf16Str: PWideChar): Integer; +{* һ UTF-16ܻ Unicode չƽַַֽĵǰַռֽڡ + + + Utf16Str: PWideChar - UTF-16 ַַ + + ֵInteger - ظַֽ +} + +function GetCodePointFromUtf16Char(Utf16Str: PWideChar): TCnCodePoint; +{* һ UTF-16 ַıֵҲдλãע Utf16Str ָһ˫ַֽҲָһַֽ + + + Utf16Str: PWideChar - UTF-16 ַַ + + ֵTCnCodePoint - ظַıֵ +} + +function GetCodePointFromUtf164Char(PtrTo4Char: Pointer): TCnCodePoint; +{* һֽ UTF-16 ַıֵҲдλã + + + PtrTo4Char: Pointer - ֽ UTF-16 ַַ + + ֵTCnCodePoint - ظַıֵ +} + +function GetUtf16CharFromCodePoint(CP: TCnCodePoint; PtrToChars: Pointer): Integer; +{* һ Unicode ֵĶֽڻֽڱʾ PtrToChars ָλòΪգ + PtrToChars ָĶֽڻֽǷ 1 PtrToChars Ϊ #0#0 + CP $FFFF ʱ뱣֤ PtrToChars ָֽڣֽ֮ڼɡ + 1 2ֱʾǶֽڻֽڡ + + + CP: TCnCodePoint - Unicode ֵ + PtrToChars: Pointer - nilתĽ + + ֵInteger - 1 ַռֽڣ 2 ֽ +} + +// ============================================================================= +// +// º漰ַ UTF-8 תʱļ㣬ȽϹ̶ +// +// ============================================================================= + +function CalcUtf8LengthFromWideString(Text: PWideChar): Integer; +{* ַ UTF-8 ȣ Utf8Encode ȡ Lengthʵת + + + Text: PWideChar - Ŀַַ + + ֵInteger - UTF-8 ֽڳ +} + +function CalcUtf8LengthFromWideChar(AChar: WideChar): Integer; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* һ WideChar ת UTF-8 ַȡ + + + AChar: WideChar - Ŀַ + + ֵInteger - UTF-8 ֽڳ +} + +function CalcUtf8LengthFromWideStringOffset(Text: PWideChar; WideOffset: Integer): Integer; +{* Unicode ַ 1 WideOffset Ӵ UTF-8 ȣWideOffset 1 ʼ WideOffset 0 0 + Copy(1, WideOffset) Ӵת UTF-8 ȡ Lengthʵת + + + Text: PWideChar - Ŀַַ + WideOffset: Integer - ԿַΪλƫ + + ֵInteger - ظÿַ 1 WideOffset Ӵ UTF-8 +} + +function CalcUtf8LengthFromWideStringAnsiOffset(Text: PWideChar; AnsiOffset: Integer): Integer; +{* Unicode ַת Ansi 1 AnsiOffset Ӵ UTF-8 ȣAnsiOffset 1 ʼ AnsiOffset 0 0 + ת Ansi Copy(1, AnsiOffset) Ӵת Unicode ַת UTF-8 ȡ Lengthʵת + + + Text: PWideChar - Ŀַַ + AnsiOffset: Integer - Ansi ַΪλƫ + + ֵInteger - ظÿַת Ansi 1 AnsiOffset Ӵ UTF-8 +} + +function CalcUtf8LengthFromUtf8HeadChar(AChar: AnsiChar): Integer; +{* һ UTF-8 ǰַַȡ + + + AChar: AnsiChar - UTF-8 ַ + + ֵInteger - ַ +} + +function CalcUtf8StringLengthFromWideOffset(Utf8Text: PAnsiChar; WideOffset: Integer): Integer; +{* UTF-8 ַת WideSting ָ Wide ӴȶӦ UTF-8 ַȣWideOffset 1 ʼ + ת WideString Copy(1, WideOffset) ת UTF-8 ȡ Length UTF-8/WideString תԱı⡣ + + + Utf8Text: PAnsiChar - UTF-8 ַַ + WideOffset: Integer - ԿַΪλƫ + + ֵInteger - ظ UTF-8 ַת WideSting ָ 1 WideOffset ӴӦ UTF-8 ַ +} + +// ============================================================================= +// +// º漰ַ Ansi תʱֽռп/ռʾȱȵļ +// +// ============================================================================= + +function WideCharIsWideLength(const AWChar: WideChar): Boolean; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* жһ Unicode ַǷռַȣĬϵļªʵ֣ IDE 汾Ϊء + ºе TCnWideCharDisplayWideLengthCalculator Ĭʵ֡ + + + const AWChar: WideChar - жϵĿַ + + ֵBoolean - Ƿռַ +} + +function CalcAnsiByteLengthFromWideString(Text: PWideChar): Integer; +{* Unicode ַ Ansi ֽڳȣת Ansi Lengthת AnsiԷֹӢƽ̨¶ַ + $FF UTF-16 ַ 2 ֽڣΪ 1 ֽڡ + + + Text: PWideChar - Ŀַַ + + ֵInteger - ת Ansi ַ +} + +function CalcAnsiDisplayLengthFromWideString(Text: PWideChar; + Calculator: TCnWideCharDisplayWideLengthCalculator = nil): Integer; +{* Unicode ַ Ansi ʾȣת Ansi ʾ Lengthת AnsiԷֹӢƽ̨¶ַ + Դ Calculator ʾַȣʱĬжϡ + + + Text: PWideChar - Ŀַַ + Calculator: TCnWideCharDisplayWideLengthCalculator - Կַʾȼصͬ Delphi IDE ༭вͬ + + ֵInteger - ת Ansi ַʾ +} + +function CalcAnsiByteLengthFromWideStringOffset(Text: PWideChar; WideOffset: Integer): Integer; +{* Unicode ַ 1 WideOffset Ӵ Ansi ֽڳȣWideOffset 1 ʼ + Copy(1, WideOffset) Ӵת Ansi ֽȡ Lengthʵת AnsiԷֹӢƽ̨¶ַ + $FF UTF-16 ַ 2 ֽڣΪ 1 ֽڡ + + + Text: PWideChar - Ŀַַ + WideOffset: Integer - ԿַΪλƫ + + ֵInteger - ظÿַ 1 WideOffset Ӵ Ansi ֽڳ +} + +function CalcAnsiDisplayLengthFromWideStringOffset(Text: PWideChar; WideOffset: Integer; + Calculator: TCnWideCharDisplayWideLengthCalculator = nil): Integer; +{* Unicode ַ 1 WideOffset Ӵ Ansi ʾȣWideOffset 1 ʼ + Copy(1, WideOffset) Ӵת Ansi ȡ Lengthʵת AnsiԷֹӢƽ̨¶ַ + Դ Calculator ʾַȣʱĬжϡ + + + Text: PWideChar - Ŀַַ + WideOffset: Integer - ַĿȼصͬ Delphi IDE ༭вͬ + Calculator: TCnWideCharDisplayWideLengthCalculator - Կַʾȼصͬ Delphi IDE ༭вͬ + + ֵInteger - ظÿַ 1 WideOffset Ӵ Ansi ʾ +} + +function CalcWideStringByteLengthFromAnsiOffset(Text: PWideChar; AnsiOffset: Integer; + AllowExceedEnd: Boolean = False): Integer; +{* Unicode ַָ Ansi ӴȶӦ Unicode ӴֽڳȣAnsiOffset 1 ʼ + ת Ansi Copy(1, AnsiOffset) ת Unicode ȡ Length Ansi/Unicode תԷֹӢƽ̨¶ַ + ע Ansi Copy ܻ˫ַֽ + AllowExceedEnd Ϊ False ʱ㵽 #0 ֹ #0Ϊ True ʱԲոʽ㡣 + $FF UTF-16 ַ 2 ֽڣΪ 1 ֽڡ + + + Text: PWideChar - Ŀַַ + AnsiOffset: Integer - ԵַֽΪλƫ + AllowExceedEnd: Boolean - Ƿ #0 ʱֹ + + ֵInteger - ظÿַתΪ Ansi 1 AnsiOffset ӴȶӦ Unicode ַֽڳ +} + +function CalcWideStringDisplayLengthFromAnsiOffset(Text: PWideChar; AnsiOffset: Integer; + AllowExceedEnd: Boolean = False; Calculator: TCnWideCharDisplayWideLengthCalculator = nil): Integer; +{* Unicode ַָ Ansi ӴȶӦ Unicode ӴȣAnsiOffset 1 ʼ + ʾת Ansi Copy(1, AnsiOffset) ת Unicode ȡ Length Ansi/Unicode תԷֹӢƽ̨¶ַ + ע Ansi Copy ܻ˫ַֽ + AllowExceedEnd Ϊ False ʱ㵽 #0 ֹ #0Ϊ True ʱԲոʽ + Դ Calculator ʾַȣʱĬжϡ + + + Text: PWideChar - Ŀַַ + AnsiOffset: Integer - ԵַֽΪλƫ + AllowExceedEnd: Boolean - Ƿ #0 ʱֹ + Calculator: TCnWideCharDisplayWideLengthCalculator - Կַʾȼصͬ Delphi IDE ༭вͬ + + ֵInteger - ظÿַתΪ Ansi 1 AnsiOffset ӴȶӦ Unicode ַʾ +} + +function CalcUtf8LengthFromWideStringAnsiDisplayOffset(Text: PWideChar; AnsiDisplayOffset: Integer; + Calculator: TCnWideCharDisplayWideLengthCalculator = nil): Integer; +{* Unicode ַתʾص Ansi 1 AnsiOffset Ӵ UTF-8 ȣAnsiDisplayOffset 1 ʼ AnsiDisplayOffset 0 0 + תʾص Ansi Copy(1, AnsiDisplayOffset) Ӵת Unicode ַת UTF-8 ȡ Lengthʵת + + + Text: PWideChar - Ŀַַ + AnsiDisplayOffset: Integer - ʾص Ansi ַΪλƫ + Calculator: TCnWideCharDisplayWideLengthCalculator - Կַʾȼصͬ Delphi IDE ༭вͬ + + ֵInteger - ظÿַתʾص Ansi 1 AnsiDisplayOffset Ӵ UTF-8 +} + +function ConvertUtf16ToAlterDisplayAnsi(WideText: PWideChar; AlterChar: AnsiChar = ' '; + Calculator: TCnWideCharDisplayWideLengthCalculator = nil): AnsiString; +{* ֶַתʾõ AnsiеĿַ Calculator ж滻һ AlterChar + ʱĬжϡڴӢϵַʾȼ㣬ַֽ֧ + + + WideText: PWideChar - תĿַַ + AlterChar: AnsiChar - 滻ַ + Calculator: TCnWideCharDisplayWideLengthCalculator - Կַʾȼصͬ Delphi IDE ༭вͬ + + ֵAnsiString - תַ +} + +function ConvertUtf8ToAlterDisplayAnsi(Utf8Text: PAnsiChar; AlterChar: AnsiChar = ' '; + Calculator: TCnWideCharDisplayWideLengthCalculator = nil): AnsiString; +{* ֶ UTF-8 ַתʾõ AnsiеĿַ Calculator ж滻һ AlterChar + ʱĬжϡڴӢϵַʾȼ㣬ַֽ֧ + + + Utf8Text: PAnsiChar - ת UTF-8 ַַ + AlterChar: AnsiChar - 滻ַ + Calculator: TCnWideCharDisplayWideLengthCalculator - Կַʾȼصͬ Delphi IDE ༭вͬ + + ֵAnsiString - תַ +} + +function CnUtf8ToAnsi(const Text: AnsiString): AnsiString; +{* Ansi ת UTF-8 Ansi ַԽ Unicode 汾 Utf8ToAnsi UnicodeString ⡣ + + + const Text: AnsiString - ת UTF-8 ַ + + ֵAnsiString - תַ +} + +function CnUtf8ToAnsi2(const Text: string): string; +{* Ansi ת UTF-8 stringԽ Unicode 汾 Utf8ToAnsi UnicodeString ⡣ + + + const Text: string - ת UTF-8 ַ + + ֵstring - תַ +} + +function CnAnsiToUtf8(const Text: AnsiString): AnsiString; +{* Ansi ת Ansi ַ UTF-8 ַԽ Unicode 汾 AnsiToUtf8 UnicodeString ⡣ + + + const Text: AnsiString - ת Ansi ַ + + ֵAnsiString - ת UTF-8 ַ +} + +function CnAnsiToUtf82(const Text: string): string; +{* Ansi ת Ansi ַ UTF-8 ַԽ Unicode 汾 AnsiToUtf8 UnicodeString ⡣ + + + const Text: string - ת Ansi ַ + + ֵstring - ת UTF-8 ַ +} + +{$IFDEF COMPILER5} + +function WideCompareText(const S1, S2: WideString): Integer; +{* Delphi 5 ûпַȽϺ˴ʵһ + + + const S1: WideString - ȽϵĿַһ + const S2: WideString - ȽϵĿַ + + ֵInteger - رȽϽ + +} + +{$ENDIF} + +// ============================================================================= +// +// ļ +// +// ============================================================================= + +type + TCnFileEncoding = (cfeUnknown, cfeUtf8, cfeUtf8Bom, cfeUtf16LE, cfeUtf16BE, cfeAnsi); + {* ļ͡ + + cfeUnknown - δ֪ + cfeUtf8 - UTF-8 BOM + cfeUtf8Bom - UTF-8 with BOM + cfeUtf16LE - UTF-16 Little Endian + cfeUtf16BE - UTF-16 Big Endian + cfeAnsi - ϵͳҳ루 Unicode + } + +function CnDetectFileEncoding(const Bytes: TBytes): TCnFileEncoding; +{* ֽļ롣ȼBOM UTF-8 ʽ Ansi + ǰ 4 ֽڵ BOM ǣ BOM ʱ UTF-8 ϷԼ顣 + + + const Bytes: TBytes - ļݵֽ + + ֵTCnFileEncoding - ı +} + +function CnIsValidUtf8(const Bytes: TBytes): Boolean; +{* ʽжֽǷΪϷ UTF-8 Сÿֽڼ UTF-8 淶 + - ֽڣ0xxxxxxx + - ˫ֽڣ110xxxxx 10xxxxxx + - ֽڣ1110xxxx 10xxxxxx 10xxxxxx + - ֽڣ11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + + + const Bytes: TBytes - ֽ + + ֵBoolean - True ʾϷ UTF-8 +} + +function CnStripBomBytes(const Bytes: TBytes): TBytes; +{* Ƴֽ鿪ͷ BOM ǰUTF-8 BOM #EF#BB#BF / UTF-16 LE BOM #FF#FE / UTF-16 BE BOM #FE#FF + BOM ʱԭʼ鸱 + + + const Bytes: TBytes - ԭʼֽ + + ֵTBytes - ȥ BOM ֽ +} + +// ============================================================================= +// +// TBytes string ת Delphi 汾ȫ UTF-8 ߣ +// +// ============================================================================= + +function CnUtf8BytesToString(const Bytes: TBytes): string; +{* UTF-8 ֽתΪ string֧ Unicode ͷ Unicode + ע Delphi 2007 °汾ת AnsiString ʱַܶ + + + const Bytes: TBytes - UTF-8 ֽ + + ֵstring - תַ +} + +function CnStringToUtf8Bytes(const S: string): TBytes; +{* string תΪ UTF-8 ֽ飬֧ Unicode ͷ Unicode + + + const S: string - תַ + + ֵTBytes - UTF-8 ֽ +} + +implementation + +const + SLineBreak = #13#10; + SLineBreakLF = #10; + + CN_UTF16_4CHAR_PREFIX1_LOW = $D8; + CN_UTF16_4CHAR_PREFIX1_HIGH = $DC; + CN_UTF16_4CHAR_PREFIX2_LOW = $DC; + CN_UTF16_4CHAR_PREFIX2_HIGH = $E0; + + CN_UTF16_4CHAR_HIGH_MASK = $3; + CN_UTF16_4CHAR_SPLIT_MASK = $3FF; + + CN_UTF16_EXT_BASE = $10000; + +resourcestring + SCnErrorInvalidUtf8CharLength = 'More than UTF8-MB4 NOT Support.'; + SCnErrorInvalidModeLength = 'More than UTF32 NOT Support.'; + +{ TCnWideStringList } + +function WideCompareText(const S1, S2: WideString): Integer; +begin +{$IFDEF MSWINDOWS} + Result := CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, PWideChar(S1), + Length(S1), PWideChar(S2), Length(S2)) - 2; +{$ELSE} + Result := WideCompareStr(S1, S2); +{$ENDIF} +end; + +function TCnWideStringList.Add(const S: WideString): Integer; +begin + Result := Count; + Insert(Count, S); +end; + +function TCnWideStringList.AddObject(const S: WideString; + AObject: TObject): Integer; +begin + Result := Add(S); + PutObject(Result, AObject); +end; + +procedure TCnWideStringList.AddStrings(Strings: TCnWideStringList); +var + I: Integer; +begin + for I := 0 to Strings.Count - 1 do + Add(Strings[I]); +end; + +procedure TCnWideStringList.Assign(Source: TPersistent); +begin + if Source is TCnWideStringList then + begin + Clear; + AddStrings(TCnWideStringList(Source)); + FLoadFormat := TCnWideStringList(Source).LoadFormat; + FUseSingleLF := TCnWideStringList(Source).UseSingleLF; + FWriteBOM := TCnWideStringList(Source).WriteBOM; + Exit; + end; + inherited Assign(Source); +end; + +procedure TCnWideStringList.Clear; +var + I: Integer; + P: PCnWideStringItem; +begin + for I := 0 to Count - 1 do + begin + P := PCnWideStringItem(FList[I]); + Dispose(P); + end; + FList.Clear; +end; + +constructor TCnWideStringList.Create; +begin + inherited; + FList := TList.Create; + FLoadFormat := wlfUnicode; + FWriteBOM := True; +end; + +procedure TCnWideStringList.CustomSort(Compare: TCnWideStringListSortCompare); +begin + if Count > 1 then + QuickSort(0, Count - 1, Compare); +end; + +procedure TCnWideStringList.Delete(Index: Integer); +var + P: PCnWideStringItem; +begin + P := PCnWideStringItem(FList[Index]); + FList.Delete(Index); + Dispose(P); +end; + +destructor TCnWideStringList.Destroy; +begin + Clear; + FList.Free; + inherited; +end; + +procedure TCnWideStringList.Exchange(Index1, Index2: Integer); +begin + FList.Exchange(Index1, Index2); +end; + +function TCnWideStringList.Get(Index: Integer): WideString; +begin + Result := PCnWideStringItem(FList[Index])^.FString; +end; + +function TCnWideStringList.GetCount: Integer; +begin + Result := FList.Count; +end; + +function TCnWideStringList.GetName(Index: Integer): WideString; +var + P: Integer; +begin + Result := Get(Index); + P := Pos('=', Result); + if P <> 0 then + SetLength(Result, P - 1) else + SetLength(Result, 0); +end; + +function TCnWideStringList.GetObject(Index: Integer): TObject; +begin + Result := PCnWideStringItem(FList[Index])^.FObject; +end; + +function TCnWideStringList.GetTextStr: WideString; +var + I, L, Size, C: Integer; + P: PwideChar; + S, LB: WideString; +begin + C := GetCount; + Size := 0; + + if FUseSingleLF then + LB := SLineBreakLF + else + LB := SLineBreak; + + for I := 0 to C - 1 do Inc(Size, Length(Get(I)) + Length(LB)); + SetString(Result, nil, Size); + P := Pointer(Result); + for I := 0 to C - 1 do + begin + S := Get(I); + L := Length(S); + if L <> 0 then + begin + System.Move(Pointer(S)^, P^, L * SizeOf(WideChar)); + Inc(P, L); + end; + L := Length(LB); + if L <> 0 then + begin + System.Move(Pointer(LB)^, P^, L * SizeOf(WideChar)); + Inc(P, L); + end; + end; +end; + +function TCnWideStringList.GetValue(const Name: WideString): WideString; +var + I: Integer; +begin + I := IndexOfName(Name); + if I >= 0 then + Result := Copy(Get(I), Length(Name) + 2, MaxInt) else + Result := ''; +end; + +function TCnWideStringList.IndexOf(const S: WideString): Integer; +begin + for Result := 0 to GetCount - 1 do + begin + if WideCompareText(Get(Result), S) = 0 then + Exit; + end; + Result := -1; +end; + +function TCnWideStringList.IndexOfName(const Name: WideString): Integer; +var + P: Integer; + S: string; +begin + for Result := 0 to GetCount - 1 do + begin + S := Get(Result); + P := Pos('=', S); + if (P <> 0) and (WideCompareText(Copy(S, 1, P - 1), Name) = 0) then + Exit; + end; + Result := -1; +end; + +procedure TCnWideStringList.Insert(Index: Integer; const S: WideString); +var + P: PCnWideStringItem; +begin + New(P); + P^.FString := S; + FList.Insert(Index, P); +end; + +procedure TCnWideStringList.LoadFromFile(const FileName: WideString); +var + Stream: TStream; +begin + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + LoadFromStream(Stream); + finally + Stream.Free; + end; +end; + +procedure TCnWideStringList.LoadFromStream(Stream: TStream); +var + Size, Len: Integer; + S: WideString; + HeaderStr, SA: AnsiString; +begin + Size := Stream.Size - Stream.Position; + if Size >= 3 then + begin + SetLength(HeaderStr, 3); + Stream.Read(Pointer(HeaderStr)^, 3); + if HeaderStr = #$EF#$BB#$BF then // UTF-8 BOM + begin + SetLength(SA, Size - 3); + Stream.Read(Pointer(SA)^, Size - 3); +{$IFDEF MSWINDOWS} + Len := MultiByteToWideChar(CP_UTF8, 0, PAnsiChar(SA), -1, nil, 0); + SetLength(S, Len); + MultiByteToWideChar(CP_UTF8, 0, PAnsiChar(SA), -1, PWideChar(S), Len); +{$ELSE} + {$IFDEF FPC} + S := CnUtf8DecodeToWideString(SA); + {$ELSE} + S := UTF8ToWideString(SA); + {$ENDIF} +{$ENDIF} + SetTextStr(S); + + FLoadFormat := wlfUtf8; + Exit; + end; + Stream.Position := Stream.Position - 3; + end; + + if Size >= 2 then + begin + SetLength(HeaderStr, 2); + Stream.Read(Pointer(HeaderStr)^, 2); + if HeaderStr = #$FF#$FE then // UTF-16 BOM + begin + SetLength(S, (Size - 2) div SizeOf(WideChar)); + Stream.Read(Pointer(S)^, (Size - 2) div SizeOf(WideChar) * SizeOf(WideChar)); + SetTextStr(S); + + FLoadFormat := wlfUnicode; + Exit; + end; + Stream.Position := Stream.Position - 2; + end; + + SetString(SA, nil, Size); + Stream.Read(Pointer(SA)^, Size); + SetTextStr({$IFDEF UNICODE}string{$ENDIF}(SA)); + FLoadFormat := wlfAnsi; +end; + +procedure TCnWideStringList.Put(Index: Integer; const S: WideString); +var + P: PCnWideStringItem; +begin + P := PCnWideStringItem(FList[Index]); + P^.FString := S; +end; + +procedure TCnWideStringList.PutObject(Index: Integer; const Value: TObject); +begin + PCnWideStringItem(FList[Index])^.FObject := Value; +end; + +procedure TCnWideStringList.QuickSort(L, R: Integer; + SCompare: TCnWideStringListSortCompare); +var + I, J, P: Integer; +begin + repeat + I := L; + J := R; + P := (L + R) shr 1; + repeat + while SCompare(Self, I, P) < 0 do Inc(I); + while SCompare(Self, J, P) > 0 do Dec(J); + if I <= J then + begin + Exchange(I, J); + if P = I then + P := J + else if P = J then + P := I; + Inc(I); + Dec(J); + end; + until I > J; + if L < J then QuickSort(L, J, SCompare); + L := I; + until I >= R; +end; + +procedure TCnWideStringList.SaveToFile(const FileName: WideString; AFormat: TCnWideListFormat); +var + Stream: TStream; +begin + Stream := TFileStream.Create(FileName, fmCreate); + try + SaveToStream(Stream, AFormat); + finally + Stream.Free; + end; +end; + +procedure TCnWideStringList.SaveToStream(Stream: TStream; AFormat: TCnWideListFormat); +var + S: WideString; + HeaderStr, SA: AnsiString; + Len: Integer; +begin + S := GetTextStr; + if AFormat = wlfAnsi then + begin + SA := AnsiString(S); + Stream.WriteBuffer(Pointer(SA)^, Length(SA) * SizeOf(AnsiChar)); + end + else if AFormat = wlfUtf8 then + begin + if FWriteBOM then + begin + HeaderStr := #$EF#$BB#$BF; + Stream.WriteBuffer(Pointer(HeaderStr)^, Length(HeaderStr) * SizeOf(AnsiChar)); + end; +{$IFDEF MSWINDOWS} + Len := WideCharToMultiByte(CP_UTF8, 0, PWideChar(S), -1, nil, 0, nil, nil); + SetLength(SA, Len); + WideCharToMultiByte(CP_UTF8, 0, PWideChar(S), -1, PAnsiChar(SA), Len, nil, nil); +{$ELSE} + SA := UTF8Encode(S); +{$ENDIF} + Stream.WriteBuffer(Pointer(SA)^, Length(SA) * SizeOf(AnsiChar) - 1); + end + else if AFormat = wlfUnicode then + begin + if FWriteBOM then + begin + HeaderStr := #$FF#$FE; + Stream.WriteBuffer(Pointer(HeaderStr)^, Length(HeaderStr) * SizeOf(AnsiChar)); + end; + Stream.WriteBuffer(Pointer(S)^, Length(S) * SizeOf(WideChar)); + end; +end; + +procedure TCnWideStringList.SetTextStr(const Value: WideString); +var + P, Start: PWideChar; + S: WideString; +begin + Clear; + P := Pointer(Value); + if P <> nil then + begin + while P^ <> #0 do + begin + Start := P; + while not (Ord(P^) in [0, 10, 13]) do Inc(P); + SetString(S, Start, P - Start); + Add(S); + if P^ = #13 then Inc(P); + if P^ = #10 then Inc(P); + end; + end; +end; + +procedure TCnWideStringList.SetValue(const Name, Value: WideString); +var + I: Integer; +begin + I := IndexOfName(Name); + if Value <> '' then + begin + if I < 0 then I := Add(''); + Put(I, Name + '=' + Value); + end + else + begin + if I >= 0 then Delete(I); + end; +end; + +function StringListCompareStrings(List: TCnWideStringList; Index1, Index2: Integer): Integer; +begin + Result := WideCompareText(PCnWideStringItem(List.FList[Index1])^.FString, + PCnWideStringItem(List.FList[Index2])^.FString); +end; + +procedure TCnWideStringList.Sort; +begin + CustomSort(StringListCompareStrings); +end; + +// D5 û UTF-8/Ansi תҵͰ汾ʹҲ֧ UTF8-MB4дƷ +// ΪSourceChars ˫ֽڿַ +function InternalUnicodeToUtf8(Dest: PAnsiChar; MaxDestBytes: Cardinal; + Source: PWideChar; SourceChars: Cardinal): Cardinal; +var + I, Cnt: Cardinal; + C: Cardinal; +begin + Result := 0; + if Source = nil then + Exit; + + Cnt := 0; + I := 0; + if Dest <> nil then + begin + while (I < SourceChars) and (Cnt < MaxDestBytes) do + begin + if (SourceChars - I >= 2) and (GetByteWidthFromUtf16(@(Source[I])) = 4) then + begin + // ַֽڣҪ + C := GetCodePointFromUtf164Char(PAnsiChar(@(Source[I]))); + Inc(I, 2); // WideChar + end + else + begin + C := Cardinal(Source[I]); + Inc(I); // һ WideChar + end; + + if C <= $7F then + begin + Dest[Cnt] := AnsiChar(C); + Inc(Cnt); + end + else if C > $FFFF then + begin + if Cnt + 4 > MaxDestBytes then + Break; + + Dest[Cnt] := AnsiChar($F0 or (C shr 18)); + Dest[Cnt + 1] := AnsiChar($80 or ((C shr 12) and $3F)); + Dest[Cnt + 2] := AnsiChar($80 or ((C shr 6) and $3F)); + Dest[Cnt + 3] := AnsiChar($80 or (C and $3F)); + Inc(Cnt, 4); + end + else if C > $7FF then + begin + if Cnt + 3 > MaxDestBytes then + Break; + Dest[Cnt] := AnsiChar($E0 or (C shr 12)); + Dest[Cnt + 1] := AnsiChar($80 or ((C shr 6) and $3F)); + Dest[Cnt + 2] := AnsiChar($80 or (C and $3F)); + Inc(Cnt, 3); + end + else // $7F < Source[i] <= $7FF + begin + if Cnt + 2 > MaxDestBytes then + Break; + Dest[Cnt] := AnsiChar($C0 or (C shr 6)); + Dest[Cnt + 1] := AnsiChar($80 or (C and $3F)); + Inc(Cnt, 2); + end; + end; + + if Cnt >= MaxDestBytes then + Cnt := MaxDestBytes - 1; + Dest[Cnt] := #0; + end + else + begin + while I < SourceChars do + begin + if (SourceChars - I >= 2) and (GetByteWidthFromUtf16(@(Source[I])) = 4) then + begin + // ַֽڣҪ + C := GetCodePointFromUtf164Char(PAnsiChar(@(Source[I]))); + Inc(I, 2); // WideChar + end + else + begin + C := Cardinal(Source[I]); + Inc(I); + end; + + if C > $7F then + begin + if C > $7FF then + begin + if C > $FFFF then + Inc(Cnt); + Inc(Cnt); + end; + Inc(Cnt); + end; + Inc(Cnt); + end; + end; + Result := Cnt + 1; +end; + +function InternalUtf8ToUnicode(Dest: PWideChar; MaxDestChars: Cardinal; + Source: PAnsiChar; SourceBytes: Cardinal): Cardinal; +var + K: Integer; + I, Cnt: Cardinal; + C: Byte; + WC: Cardinal; +begin + if Source = nil then + begin + Result := 0; + Exit; + end; + + Result := Cardinal(-1); + Cnt := 0; + I := 0; + if Dest <> nil then + begin + while (I < SourceBytes) and (Cnt < MaxDestChars) do + begin + WC := Cardinal(Source[I]); + Inc(I); + + if (WC and $80) <> 0 then + begin + if I >= SourceBytes then // + Exit; + + if (WC and $F0) = $F0 then // ֽڣδλ 0ٲַƴֵַֽڵ UTF-16 + begin + if SourceBytes - I < 3 then // ֽ˳ + Exit; + + // WC ǵһֽڣȡλδλ 0ֽڸȡλõ + WC := ((WC and $7) shl 18) + ((Cardinal(Source[I]) and $3F) shl 12) + + ((Cardinal(Source[I + 1]) and $3F) shl 6) + (Cardinal(Source[I + 2]) and $3F); + + // UTF-16 ַ Cnt + K := GetUtf16CharFromCodePoint(WC, @(Dest[Cnt])); + if K = 2 then // ַֽȲһ WideCharһ if + Inc(Cnt); + Inc(I, 3); + end + else + begin + WC := WC and $3F; + if (WC and $20) <> 0 then + begin + C := Byte(Source[I]); + Inc(I); + if (C and $C0) <> $80 then // malformed trail byte or out of range char + Exit; + if I >= SourceBytes then // incomplete multibyte char + Exit; + WC := (WC shl 6) or (C and $3F); + end; + C := Byte(Source[I]); + Inc(I); + if (C and $C0) <> $80 then // malformed trail byte + Exit; + + Dest[Cnt] := WideChar((WC shl 6) or (C and $3F)); + end; + end + else + Dest[Cnt] := WideChar(WC); + Inc(Cnt); + end; + if Cnt >= MaxDestChars then Cnt := MaxDestChars - 1; + Dest[Cnt] := #0; + end + else + begin + while (I < SourceBytes) do + begin + C := Byte(Source[I]); + Inc(I); + + if (C and $80) <> 0 then // λΪ 1ٶֽ + begin + if I >= SourceBytes then // incomplete multibyte char + Exit; + + C := C and $3F; // µһֽڵĵλǰλѾ 11 + if (C and $20) <> 0 then // 1110ʾֽ + begin + if (C and $10) <> 0 then // 11110ʾֽ + begin + C := Byte(Source[I]); // ĸеĵڶֽ + Inc(I); + if (C and $C0) <> $80 then // ֽλ 10 + Exit; // malformed trail byte or out of range char + if I >= SourceBytes then + Exit; // incomplete multibyte char + + Inc(Cnt); // ֽڵ UTF8ӦӦ UTF-16 е WideCharһ + end; + + C := Byte(Source[I]); // ĸеĵֽڣеĵڶֽ + Inc(I); + if (C and $C0) <> $80 then // ֽλ 10˳ + Exit; + if I >= SourceBytes then + Exit; // incomplete multibyte char + end; + + C := Byte(Source[I]); // ĸеĵĸֽڣеĵֽڣеĵڶֽ + Inc(I); + if (C and $C0) <> $80 then // ֽλ 10˳ + Exit; // malformed trail byte + end; + + Inc(Cnt); + end; + end; + Result := Cnt + 1; +end; + +// WideString UTF-8 õ AnsiString Ansi תⶪַ +function CnUtf8EncodeWideString(const S: TCnWideString): AnsiString; +var + L: Integer; + Temp: AnsiString; +begin + Result := ''; + if S = '' then + Exit; + SetLength(Temp, Length(S) * 4); // һ˫ַֽ 4 UTF-8 ַ + + L := InternalUnicodeToUtf8(PAnsiChar(Temp), Length(Temp) + 1, PWideChar(S), Length(S)); + if L > 0 then + SetLength(Temp, L - 1) + else + Temp := ''; + Result := Temp; +end; + +// AnsiString UTF-8 õ WideString Ansi תⶪַ +function CnUtf8DecodeToWideString(const S: AnsiString): TCnWideString; +var + L: Integer; +begin + Result := ''; + if S = '' then + Exit; + SetLength(Result, Length(S)); + + L := InternalUtf8ToUnicode(PWideChar(Result), Length(Result) + 1, PAnsiChar(S), Length(S)); + if L > 0 then + SetLength(Result, L - 1) + else + Result := ''; +end; + +function GetUtf16HighByte(Rec: PCn2CharRec): Byte; +begin +{$IFDEF UTF16_BE} + Result := Byte(Rec^.P1); +{$ELSE} + Result := Byte(Rec^.P2); // UTF16-LE ĸߵλû +{$ENDIF} +end; + +function GetUtf16LowByte(Rec: PCn2CharRec): Byte; +begin +{$IFDEF UTF16_BE} + Result := Byte(Rec^.P2); +{$ELSE} + Result := Byte(Rec^.P1); // UTF16-LE ĸߵλû +{$ENDIF} +end; + +procedure SetUtf16HighByte(B: Byte; Rec: PCn2CharRec); +begin +{$IFDEF UTF16_BE} + Rec^.P1 := AnsiChar(B); +{$ELSE} + Rec^.P2 := AnsiChar(B); // UTF16-LE ĸߵλû +{$ENDIF} +end; + +procedure SetUtf16LowByte(B: Byte; Rec: PCn2CharRec); +begin +{$IFDEF UTF16_BE} + Rec^.P2 := AnsiChar(B); +{$ELSE} + Rec^.P1 := AnsiChar(B); // UTF16-LE ĸߵλû +{$ENDIF} +end; + +function GetCharLengthFromUtf8(Utf8Str: PAnsiChar): Integer; +var + L: Integer; +begin + Result := 0; + while Utf8Str^ <> #0 do + begin + L := GetByteWidthFromUtf8(Utf8Str); + Inc(Utf8Str, L); + Inc(Result); + end; +end; + +function GetCharLengthFromUtf16(Utf16Str: PWideChar): Integer; +var + L: Integer; +begin + Result := 0; + while Utf16Str^ <> #0 do + begin + L := GetByteWidthFromUtf16(Utf16Str); + Utf16Str := PWideChar(TCnIntAddress(Utf16Str) + L); + Inc(Result); + end; +end; + +function GetByteWidthFromUtf8(Utf8Str: PAnsiChar): Integer; +var + B: Byte; +begin + B := Byte(Utf8Str^); + if B >= $FC then // 6 11 0Ȳ 1 + Result := 6 + else if B >= $F8 then // 5 11 0 + Result := 5 + else if B >= $F0 then // 4 11 0 + Result := 4 + else if B >= $E0 then // 3 11 0 + Result := 3 + else if B >= $B0 then // 2 11 0 + Result := 2 + else // + Result := 1; +end; + +function GetByteWidthFromUtf16(Utf16Str: PWideChar): Integer; +var + P: PCn2CharRec; + B1, B2: Byte; +begin + Result := 2; + + P := PCn2CharRec(Utf16Str); + B1 := GetUtf16HighByte(P); + + if (B1 >= CN_UTF16_4CHAR_PREFIX1_LOW) and (B1 < CN_UTF16_4CHAR_PREFIX1_HIGH) then + begin + // ַֽƴһ飬ֵ $D800 $DBFF ֮䣬ҲǸ˫ֽڵĸλֽ [$D8, $DC) + Inc(P); + B2 := GetUtf16HighByte(P); + + // ôںַֽӦ $DC00 $DFFF ֮䣬 + if (B2 >= CN_UTF16_4CHAR_PREFIX2_LOW) and (B2 < CN_UTF16_4CHAR_PREFIX2_HIGH) then + Result := 4; + + // ĸֽһֽ Unicode ַǸֵıֵ + end; +end; + +function GetCodePointFromUtf16Char(Utf16Str: PWideChar): TCnCodePoint; +var + R: Word; + C2: PCn2CharRec; +begin + if GetByteWidthFromUtf16(Utf16Str) = 4 then // ַֽ + Result := GetCodePointFromUtf164Char(PAnsiChar(Utf16Str)) + else // ͨ˫ַֽ + begin + C2 := PCn2CharRec(Utf16Str); + R := Byte(C2^.P1) shl 8 + Byte(C2^.P2); // ˫ֵַֽDZֵ + +{$IFDEF UTF16_BE} + Result := TCnCodePoint(R); +{$ELSE} + Result := TCnCodePoint(UInt16ToBigEndian(R)); // UTF16-LE Ҫֵ +{$ENDIF} + end; +end; + +function GetCodePointFromUtf164Char(PtrTo4Char: Pointer): TCnCodePoint; +var + TH, TL: Word; + C2: PCn2CharRec; +begin + C2 := PCn2CharRec(PtrTo4Char); + + // һֽڣȥλ 110110ڶֽţ 2 + 8 = 10 λ + TH := (GetUtf16HighByte(C2) and CN_UTF16_4CHAR_HIGH_MASK) shl 8 + GetUtf16LowByte(C2); + Inc(C2); + + // ֽڣȥλ 110111ĸֽţ 2 + 8 = 10 λ + TL := (GetUtf16HighByte(C2) and CN_UTF16_4CHAR_HIGH_MASK) shl 8 + GetUtf16LowByte(C2); + + // 10 λƴ 10 λ + Result := TH shl 10 + TL + CN_UTF16_EXT_BASE; + // ȥ $10000 ֵǰ 10 λӳ䵽 $D800 $DBFF ֮䣬 10 λӳ䵽 $DC00 $DFFF ֮ +end; + +function GetUtf16CharFromCodePoint(CP: TCnCodePoint; PtrToChars: Pointer): Integer; +var + C2: PCn2CharRec; + L, H: Byte; + LW, HW: Word; +begin + if CP = CN_INVALID_CODEPOINT then + begin + if PtrToChars <> nil then + begin + C2 := PCn2CharRec(PtrToChars); + SetUtf16LowByte(0, C2); + SetUtf16HighByte(0, C2); + end; + Result := 1; + Exit; + end; + + if CP >= CN_UTF16_EXT_BASE then + begin + if PtrToChars <> nil then + begin + CP := CP - CN_UTF16_EXT_BASE; + // 10 λǰֽڣ 10 λźֽ + + LW := CP and CN_UTF16_4CHAR_SPLIT_MASK; // 10 λֽ + HW := (CP shr 10) and CN_UTF16_4CHAR_SPLIT_MASK; // 10 λһֽ + + L := HW and $FF; + H := (HW shr 8) and CN_UTF16_4CHAR_HIGH_MASK; + H := H or CN_UTF16_4CHAR_PREFIX1_LOW; // 1101 1000 + C2 := PCn2CharRec(PtrToChars); + + SetUtf16LowByte(L, C2); + SetUtf16HighByte(H, C2); + + L := LW and $FF; + H := (LW shr 8) and CN_UTF16_4CHAR_HIGH_MASK; + H := H or CN_UTF16_4CHAR_PREFIX1_HIGH; // 1101 1100 + Inc(C2); + + SetUtf16LowByte(L, C2); + SetUtf16HighByte(H, C2); + end; + Result := 2; + end + else + begin + if PtrToChars <> nil then + begin + C2 := PCn2CharRec(PtrToChars); + SetUtf16LowByte(Byte(CP and $00FF), C2); + SetUtf16HighByte(Byte(CP shr 8), C2); + end; + Result := 1; + end; +end; + +// ַ UTF-8 ȣ Utf8Encode ȡ Lengthʵת +function CalcUtf8LengthFromWideString(Text: PWideChar): Integer; +begin + Result := 0; + if Text = nil then + Exit; + + while Text^ <> #0 do + begin + Inc(Result, CalcUtf8LengthFromWideChar(Text^)); + Inc(Text); + end; +end; + +// һ WideChar ת UTF-8 ַ +function CalcUtf8LengthFromWideChar(AChar: WideChar): Integer; +var + V: Cardinal; +begin + V := Ord(AChar); + if V <= $7F then + Result := 1 + else if V <= $7FF then + Result := 2 + else if V <= $FFFF then + Result := 3 + else if V <= $10FFFF then + Result := 4 + else + Result := 0; +end; + +// Unicode ַ 1 WideOffset Ӵ UTF-8 ȣWideOffset 1 ʼ +function CalcUtf8LengthFromWideStringOffset(Text: PWideChar; WideOffset: Integer): Integer; +var + Idx: Integer; +begin + Result := 0; + if (Text <> nil) and (WideOffset > 0) then + begin + Idx := 0; + while (Text^ <> #0) and (Idx < WideOffset) do // Idx 0 ʼWideOffset 1 ʼ < + begin + Inc(Result, CalcUtf8LengthFromWideChar(Text^)); + Inc(Text); + Inc(Idx); + end; + end; +end; + +// Unicode ַת Ansi 1 AnsiOffset Ӵ UTF-8 ȣAnsiOffset 1 ʼ +function CalcUtf8LengthFromWideStringAnsiOffset(Text: PWideChar; AnsiOffset: Integer): Integer; +var + Idx: Integer; +begin + Result := 0; + if (Text <> nil) and (AnsiOffset > 0) then + begin + Idx := 0; + while (Text^ <> #0) and (Idx < AnsiOffset) do // Idx 0 ʼAnsiOffset 1 ʼ < + begin + Inc(Result, CalcUtf8LengthFromWideChar(Text^)); + Inc(Text); + if Ord(Text^) > $FF then // $FF ת Ansi Ȼռֽ + Inc(Idx, 2) + else + Inc(Idx); + end; + end; +end; + +// һ UTF-8 ǰַַ +function CalcUtf8LengthFromUtf8HeadChar(AChar: AnsiChar): Integer; +var + B: Byte; +begin + B := Ord(AChar); + if B and $80 = 0 then // 0xxx xxxx + Result := 1 + else if B and $E0 = $C0 then // 110x xxxx 10xxxxxx + Result := 2 + else if B and $F0 = $E0 then // 1110 xxxx 10xxxxxx 10xxxxxx + Result := 3 + else if B and $F8 = $F0 then // 1111 0xxx 10xxxxxx 10xxxxxx 10xxxxxx + Result := 4 + else + raise ECnWideStringException.Create(SCnErrorInvalidUtf8CharLength); +end; + +// UTF-8 ַת WideSting ָ Wide ӴȶӦ UTF-8 ַȣWideOffset 1 ʼ +// ת WideString Copy(1, WideOffset) ת UTF-8 ȡ Length UTF-8/WideString תԱı +function CalcUtf8StringLengthFromWideOffset(Utf8Text: PAnsiChar; + WideOffset: Integer): Integer; +var + Utf8Len, WideIdx: Integer; +begin + Result := 0; + if (Utf8Text = nil) or (WideOffset <= 0) then + Exit; + + WideIdx := 0; + while (Utf8Text^ <> #0) and (WideIdx < WideOffset) do + begin + Utf8Len := CalcUtf8LengthFromUtf8HeadChar(Utf8Text^); + Inc(Result, Utf8Len); + + case Utf8Len of + 1: + begin + Inc(WideIdx); + Inc(Utf8Text); + end; + 2: + begin + Inc(WideIdx); + Inc(Utf8Text); + if Utf8Text^ = #0 then + Exit; + Inc(Utf8Text); + end; + 3: + begin + Inc(WideIdx); + Inc(Utf8Text); + if Utf8Text^ = #0 then + Exit; + Inc(Utf8Text); + if Utf8Text^ = #0 then + Exit; + Inc(Utf8Text); + end; + 4: // UTF8-MB4 + begin + Inc(WideIdx); + Inc(Utf8Text); + if Utf8Text^ = #0 then + Exit; + Inc(Utf8Text); + if Utf8Text^ = #0 then + Exit; + Inc(Utf8Text); + if Utf8Text^ = #0 then + Exit; + Inc(Utf8Text); + end; + else + Exit; + end; + end; +end; + +// жһ Unicode ַǷռַȣĬϵļªʵ +function WideCharIsWideLength(const AWChar: WideChar): Boolean; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +const + CN_UTF16_ANSI_WIDE_CHAR_SEP = $1100; +var + C: Integer; +begin + C := Ord(AWChar); + Result := C > CN_UTF16_ANSI_WIDE_CHAR_SEP; // Ϊ $1100 Utf16 ַƿȲռֽ +end; + +function CalcAnsiByteLengthFromWideString(Text: PWideChar): Integer; +begin + Result := 0; + if Text = nil then + Exit; + + while Text^ <> #0 do + begin + if Ord(Text^) > $FF then + Inc(Result, SizeOf(WideChar)) + else + Inc(Result, SizeOf(AnsiChar)); + Inc(Text); + end; +end; + +// Unicode ַ Ansi ȣת Ansi Lengthת AnsiԷֹӢƽ̨¶ַ +function CalcAnsiDisplayLengthFromWideString(Text: PWideChar; + Calculator: TCnWideCharDisplayWideLengthCalculator): Integer; +begin + Result := 0; + if Text = nil then + Exit; + + if not Assigned(Calculator) then + Calculator := @WideCharIsWideLength; + + while Text^ <> #0 do + begin + if Calculator(Text^) then + Inc(Result, SizeOf(WideChar)) + else + Inc(Result, SizeOf(AnsiChar)); + Inc(Text); + end; +end; + +function CalcAnsiByteLengthFromWideStringOffset(Text: PWideChar; WideOffset: Integer): Integer; +var + Idx: Integer; +begin + Result := 0; + if (Text = nil) or (WideOffset <= 0) then + Exit; + + Idx := 0; + while (Text^ <> #0) and (Idx < WideOffset) do // Idx 0 ʼWideOffset 1 ʼ < + begin + if Ord(Text^) > $FF then + Inc(Result, SizeOf(WideChar)) + else + Inc(Result, SizeOf(AnsiChar)); + Inc(Text); + Inc(Idx); + end; +end; + +// Unicode ַ 1 WideOffset Ӵ Ansi ȣWideOffset 1 ʼ +function CalcAnsiDisplayLengthFromWideStringOffset(Text: PWideChar; WideOffset: Integer; + Calculator: TCnWideCharDisplayWideLengthCalculator): Integer; +var + Idx: Integer; +begin + Result := 0; + if (Text = nil) or (WideOffset <= 0) then + Exit; + + Idx := 0; + if not Assigned(Calculator) then + Calculator := @WideCharIsWideLength; + + while (Text^ <> #0) and (Idx < WideOffset) do // Idx 0 ʼWideOffset 1 ʼ < + begin + if Calculator(Text^) then + Inc(Result, SizeOf(WideChar)) + else + Inc(Result, SizeOf(AnsiChar)); + Inc(Text); + Inc(Idx); + end; +end; + +function CalcWideStringByteLengthFromAnsiOffset(Text: PWideChar; + AnsiOffset: Integer; AllowExceedEnd: Boolean): Integer; +var + Idx: Integer; +begin + Result := 0; + if (Text <> nil) and (AnsiOffset > 0) then + begin + Idx := 0; + while (Text^ <> #0) and (Idx < AnsiOffset) do + begin + if Ord(Text^) > $FF then + Inc(Idx, SizeOf(WideChar)) + else + Inc(Idx, SizeOf(AnsiChar)); + Inc(Text); + Inc(Result); + end; + + if AllowExceedEnd and (Text^ = #0) and (Idx < AnsiOffset) then + Inc(Result, AnsiOffset - Idx); + end; +end; + +function CalcWideStringDisplayLengthFromAnsiOffset(Text: PWideChar; AnsiOffset: Integer; + AllowExceedEnd: Boolean; Calculator: TCnWideCharDisplayWideLengthCalculator): Integer; +var + Idx: Integer; +begin + Result := 0; + if (Text <> nil) and (AnsiOffset > 0) then + begin + Idx := 0; + if not Assigned(Calculator) then + Calculator := @WideCharIsWideLength; + + while (Text^ <> #0) and (Idx < AnsiOffset) do + begin + if Calculator(Text^) then + Inc(Idx, SizeOf(WideChar)) + else + Inc(Idx, SizeOf(AnsiChar)); + Inc(Text); + Inc(Result); + end; + + if AllowExceedEnd and (Text^ = #0) and (Idx < AnsiOffset) then + Inc(Result, AnsiOffset - Idx); + end; +end; + +// Unicode ַתʾص Ansi 1 AnsiOffset Ӵ UTF-8 ȣAnsiDisplayOffset 1 ʼ +function CalcUtf8LengthFromWideStringAnsiDisplayOffset(Text: PWideChar; + AnsiDisplayOffset: Integer; Calculator: TCnWideCharDisplayWideLengthCalculator): Integer; +var + Idx: Integer; +begin + Result := 0; + if (Text <> nil) and (AnsiDisplayOffset > 0) then + begin + Idx := 0; + if not Assigned(Calculator) then + Calculator := @WideCharIsWideLength; + + while (Text^ <> #0) and (Idx < AnsiDisplayOffset) do // Idx 0 ʼAnsiDisplayOffset 1 ʼ < + begin + Inc(Result, CalcUtf8LengthFromWideChar(Text^)); + Inc(Text); + if Calculator(Text^) then + Inc(Idx, SizeOf(WideChar)) + else + Inc(Idx, SizeOf(AnsiChar)); + end; + end; +end; + +// ֶַת AnsiеĿַ滻 AlterCharڴӢϵַȼ +function ConvertUtf16ToAlterDisplayAnsi(WideText: PWideChar; AlterChar: AnsiChar; + Calculator: TCnWideCharDisplayWideLengthCalculator): AnsiString; +var + Len: Integer; +begin + if WideText = nil then + begin + Result := ''; + Exit; + end; + +{$IFDEF UNICODE} + Len := StrLen(WideText); +{$ELSE} + Len := Length(WideString(WideText)); +{$ENDIF} + + if Len = 0 then + begin + Result := ''; + Exit; + end; + + SetLength(Result, Len * SizeOf(WideChar)); + + if not Assigned(Calculator) then + Calculator := @WideCharIsWideLength; + + Len := 0; + while WideText^ <> #0 do + begin + if Calculator(WideText^) then + begin + Inc(Len); + Result[Len] := AlterChar; + Inc(Len); + Result[Len] := AlterChar; + end + else + begin + Inc(Len); + if Ord(WideText^) <= $FF then // Absolutely 'Single' Char + Result[Len] := AnsiChar(WideText^) + else // Extended 'Single' Char, Replace + Result[Len] := AlterChar; + end; + Inc(WideText); + end; + SetLength(Result, Len); +end; + +// ֶ UTF-8 ַת AnsiеĿַ滻 AlterCharڴӢϵַȼ +function ConvertUtf8ToAlterDisplayAnsi(Utf8Text: PAnsiChar; AlterChar: AnsiChar; + Calculator: TCnWideCharDisplayWideLengthCalculator): AnsiString; +var + I, J, Len, ByteCount: Integer; + C: AnsiChar; + W: Word; + B, B1, B2: Byte; +begin + Result := ''; + if Utf8Text = nil then + Exit; + + Len := StrLen(Utf8Text); + if Len = 0 then + Exit; + + SetLength(Result, Len); // ԭijϳ + I := 0; + J := 1; + + if not Assigned(Calculator) then + Calculator := @WideCharIsWideLength; + + while I < Len do + begin + C := Utf8Text[I]; + B := Ord(C); + W := 0; + + // B ֵóַռλ + if B and $80 = 0 then // 0xxx xxxx + ByteCount := 1 + else if B and $E0 = $C0 then // 110x xxxx 10xxxxxx + ByteCount := 2 + else if B and $F0 = $E0 then // 1110 xxxx 10xxxxxx 10xxxxxx + ByteCount := 3 + else if B and $F8 = $F0 then // 1111 0xxx 10xxxxxx 10xxxxxx 10xxxxxx + ByteCount := 4 + else + raise ECnWideStringException.Create(SCnErrorInvalidModeLength); + + // ټӦĿַֽ + case ByteCount of + 1: + begin + W := B and $7F; + end; + 2: + begin + B1 := Ord(Utf8Text[I + 1]); + W := ((B and $1F) shl 6) or (B1 and $3F); + end; + 3: + begin + B1 := Ord(Utf8Text[I + 1]); + B2 := Ord(Utf8Text[I + 2]); + W := ((B and $0F) shl 12) or ((B1 and $3F) shl 6) or (B2 and $3F); + end; + end; + + if ByteCount = 4 then + begin + // ֽ UTF8תΪ WideCharҲĸַ + // TODO: ʾδأܿƧַ + Result[J] := AlterChar; + Inc(J); + Result[J] := AlterChar; + Inc(J); + Result[J] := AlterChar; + Inc(J); + Result[J] := AlterChar; + Inc(J); + end + else if Calculator(WideChar(W)) then // 3 ֽ UTF8жʵʿ + begin + Result[J] := AlterChar; + Inc(J); + Result[J] := AlterChar; + Inc(J); + end + else + begin + if W <= 255 then + Result[J] := AnsiChar(W) + else + Result[J] := AlterChar; + Inc(J); + end; + + Inc(I, ByteCount); + end; + + SetLength(Result, J - 1); // Inc J һַģû˾ͼһ +end; + +function CnUtf8ToAnsi(const Text: AnsiString): AnsiString; +begin +{$IFDEF FPC} + {$IFDEF LAZARUS} + Result := ConvertEncoding(Text, EncodingUTF8, EncodingAnsi); + {$ELSE} + Result := Utf8ToAnsi(Text); + {$ENDIF} +{$ELSE} +{$IFDEF UNICODE} + Result := AnsiString(UTF8ToUnicodeString(PAnsiChar(Text))); +{$ELSE} + {$IFDEF COMPILER6_UP} + Result := Utf8ToAnsi(Text); + {$ELSE} + Result := AnsiString(CnUtf8DecodeToWideString(Text)); + {$ENDIF} +{$ENDIF} +{$ENDIF} +end; + +function CnUtf8ToAnsi2(const Text: string): string; +begin +{$IFDEF FPC} + {$IFDEF LAZARUS} + Result := ConvertEncoding(Text, EncodingUTF8, EncodingAnsi); + {$ELSE} + Result := Utf8ToAnsi(Text); + {$ENDIF} +{$ELSE} +{$IFDEF UNICODE} + Result := UTF8ToUnicodeString(PAnsiChar(AnsiString(Text))); +{$ELSE} + {$IFDEF COMPILER6_UP} + Result := Utf8ToAnsi(Text); + {$ELSE} + Result := AnsiString(CnUtf8DecodeToWideString(Text)); + {$ENDIF} +{$ENDIF} +{$ENDIF} +end; + +function CnAnsiToUtf8(const Text: AnsiString): AnsiString; +begin +{$IFDEF FPC} + {$IFDEF LAZARUS} + Result := ConvertEncoding(Text, EncodingAnsi, EncodingUTF8); + {$ELSE} + Result := AnsiToUtf8(Text); + {$ENDIF} +{$ELSE} +{$IFDEF UNICODE} + Result := AnsiString(Utf8Encode(Text)); // ֵɸΪ UTF8String ͣ˴תЧ +{$ELSE} + {$IFDEF COMPILER6_UP} + Result := AnsiToUtf8(Text); + {$ELSE} + Result := CnUtf8EncodeWideString(WideString(Text)); + {$ENDIF} +{$ENDIF} +{$ENDIF} +end; + +function CnAnsiToUtf82(const Text: string): string; +begin +{$IFDEF FPC} + {$IFDEF LAZARUS} + Result := ConvertEncoding(Text, EncodingAnsi, EncodingUTF8); + {$ELSE} + Result := AnsiToUtf8(Text); + {$ENDIF} +{$ELSE} +{$IFDEF UNICODE} + Result := string(Utf8Encode(Text)); +{$ELSE} + {$IFDEF COMPILER6_UP} + Result := AnsiToUtf8(Text); + {$ELSE} + Result := CnUtf8EncodeWideString(WideString(Text)); + {$ENDIF} +{$ENDIF} +{$ENDIF} +end; + +// ===================== TCnFileEncoding ʵ ============================== + +function CnDetectFileEncoding(const Bytes: TBytes): TCnFileEncoding; +begin + Result := cfeUnknown; + if Length(Bytes) = 0 then Exit; + + // BOM + if Length(Bytes) >= 3 then + begin + if (Bytes[0] = $EF) and (Bytes[1] = $BB) and (Bytes[2] = $BF) then + begin + Result := cfeUtf8Bom; + Exit; + end; + end; + + if Length(Bytes) >= 2 then + begin + if (Bytes[0] = $FF) and (Bytes[1] = $FE) then + begin + Result := cfeUtf16LE; + Exit; + end; + if (Bytes[0] = $FE) and (Bytes[1] = $FF) then + begin + Result := cfeUtf16BE; + Exit; + end; + end; + + // BOMʽ UTF-8 + if CnIsValidUtf8(Bytes) then + Result := cfeUtf8 + else + Result := cfeAnsi; +end; + +function CnIsValidUtf8(const Bytes: TBytes): Boolean; +var + I, Len, Remain: Integer; + B: Byte; +begin + Result := True; + Len := Length(Bytes); + I := 0; + while I < Len do + begin + B := Bytes[I]; + if B and $80 = 0 then + // ֽ: 0xxxxxxx + Inc(I) + else if B and $E0 = $C0 then + begin + // ˫ֽ: 110xxxxx 10xxxxxx + Inc(I); + Remain := 1; + end + else if B and $F0 = $E0 then + begin + // ֽ: 1110xxxx 10xxxxxx 10xxxxxx + Inc(I); + Remain := 2; + end + else if B and $F8 = $F0 then + begin + // ֽ: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + Inc(I); + Remain := 3; + end + else + begin + // Чǰ + Result := False; + Exit; + end; + + // ֽǷ 10xxxxxx + while (Remain > 0) and (I < Len) do + begin + if Bytes[I] and $C0 <> $80 then + begin + Result := False; + Exit; + end; + Inc(I); + Dec(Remain); + end; + + // ֽڲ + if Remain > 0 then + begin + Result := False; + Exit; + end; + end; +end; + +function CnStripBomBytes(const Bytes: TBytes): TBytes; +var + Offset: Integer; +begin + Offset := 0; + if Length(Bytes) >= 3 then + begin + if (Bytes[0] = $EF) and (Bytes[1] = $BB) and (Bytes[2] = $BF) then + Offset := 3; + end; + if (Offset = 0) and (Length(Bytes) >= 2) then + begin + if ((Bytes[0] = $FF) and (Bytes[1] = $FE)) + or ((Bytes[0] = $FE) and (Bytes[1] = $FF)) then + Offset := 2; + end; + + if Offset > 0 then + begin + SetLength(Result, Length(Bytes) - Offset); + if Length(Result) > 0 then + Move(Bytes[Offset], Result[0], Length(Result)); + end + else + Result := Copy(Bytes); +end; + +// ================= TBytes string ֮תʵ =========================== + +function CnUtf8BytesToString(const Bytes: TBytes): string; +var + Utf8Str: AnsiString; +begin + SetLength(Utf8Str, Length(Bytes)); + if Length(Bytes) > 0 then + Move(Bytes[0], Utf8Str[1], Length(Bytes)); + Result := string(CnUtf8DecodeToWideString(Utf8Str)); +end; + +function CnStringToUtf8Bytes(const S: string): TBytes; +var + Utf8Str: AnsiString; +begin + Utf8Str := CnUtf8EncodeWideString(TCnWideString(S)); + SetLength(Result, Length(Utf8Str)); + if Length(Utf8Str) > 0 then + Move(Utf8Str[1], Result[0], Length(Utf8Str)); +end; + +end. diff --git a/CnPack/Crypto/CnAES.pas b/CnPack/Crypto/CnAES.pas new file mode 100644 index 0000000..098c34e --- /dev/null +++ b/CnPack/Crypto/CnAES.pas @@ -0,0 +1,7763 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} +(******************************************************************************) +(* *) +(* Advanced Encryption Standard (AES) *) +(* *) +(* Copyright (c) 1998-2001 *) +(* EldoS, Alexander Ionov *) +(* *) +(******************************************************************************) + +unit CnAES; +{* |
+================================================================================ +* ƣ +* ԪƣAES ԳƼӽ㷨ʵֵԪ +* ԪߣCnPack (master@cnpack.org) +* EldoS, Alexander Ionov ĵԪֲ书ܣԭаȨϢ +* עԪʵ AES 128/192/256 ԳƼӽ㷨ֿС̶ 16 ֽڣģʽ +* Ķ뷽ʽĩβ 0Ԫڲ֧ PKCS ȿ뷽ʽҪⲿ +* CnPemUtils.pas Ԫе PKCS ϵкԼӽݽж +* +* ߰汾 Delphi 뾡ʹ AnsiString 汾ĺʮƳ⣩ +* ⲻַӰӽܽ +* +* 䣺Java Ĭϵ AES Ӧ˴ AES256 +* +* ⣬C++Builder 5/6 ¶ overload ĺʴжϴӶ +* ҵΣʱԪ˴ overload Delphi ´ڣ +* ٷװ˲ֲͬĺ֧ C++Builder 5/6 ±С +* +* ECB/CBC ǿģʽҪ롣CFB/OFB/CTR ĵģʽ뵽顣 +* +* ⣬CTR ģʽ RFC 3686 淶紫ݵ 4 ֽ Nonce8 ֽ +* ʼ4 ֽֽļƴ 16 ֽڵijʼ +* AES 㣬ӽܾΪĶ +* +* ƽ̨Delphi5 + Win 7 +* ļ¼2024.07.25 V1.3 +* CTR ģʽ֧֣ѭ RFC 3686 淶 +* 2024.05.26 V1.2 +* 䲿֧ C++Builder ĺ +* 2022.06.21 V1.1 +* 뼸ֽ鵽ʮַ֮ļӽܺ +* 2021.12.11 V1.2 +* CFB/OFB ģʽ֧ +* 2019.04.15 V1.1 +* ֧ Win32/Win64/MacOS +* 2015.01.21 V1.0 +* Ԫ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + Classes, SysUtils, CnNative; + +const + CN_AES_BLOCKSIZE = 16; + {* AES ķܿСλ٣Ϊ 16 ֽ} + +type + TCnKeyBitType = (kbt128, kbt192, kbt256); + {* AES λ16 ֽڡ24 ֽں 32 ֽ} + + ECnAESException = class(Exception); + {* AES 쳣} + + TCnAESBuffer = array [0..15] of Byte; + {* AES ӽܿ 16 ֽ} + + TCnAESKey128 = array [0..15] of Byte; + {* AES128 Կṹ16 ֽ} + + TCnAESKey192 = array [0..23] of Byte; + {* AES192 Կṹ24 ֽ} + + TCnAESKey256 = array [0..31] of Byte; + {* AES256 Կṹ32 ֽ} + + TCnAESExpandedKey128 = array [0..43] of Cardinal; + {* AES128 չԿṹ} + + TCnAESExpandedKey192 = array [0..53] of Cardinal; + {* AES192 չԿṹ} + + TCnAESExpandedKey256 = array [0..63] of Cardinal; + {* AES256 չԿṹ} + + PCnAESBuffer = ^TCnAESBuffer; + {* AES ӽָܿ} + + PCnAESKey128 = ^TCnAESKey128; + {* AES128 Կṹָ} + + PCnAESKey192 = ^TCnAESKey192; + {* AES192 Կṹָ} + + PCnAESKey256 = ^TCnAESKey256; + {* AES256 Կṹָ} + + PCnAESExpandedKey128 = ^TCnAESExpandedKey128; + {* AES128 չԿṹָ} + + PCnAESExpandedKey192 = ^TCnAESExpandedKey192; + {* AES192 չԿṹָ} + + PCnAESExpandedKey256 = ^TCnAESExpandedKey256; + {* AES256 չԿṹָ} + + TCnAESCTRNonce = array[0..3] of Byte; + {* CTR ģʽµ Nonce ṹ4 ֽ} + + TCnAESCTRIv = array[0..7] of Byte; + {* CTR ģʽµijʼṹ8 ֽ} + +// Key Expansion Routines for Encryption + +procedure ExpandAESKeyForEncryption128(const Key: TCnAESKey128; + var ExpandedKey: TCnAESExpandedKey128); +{* ڼܳչ AES128 Կ + + + const Key: TCnAESKey128 - չ AES128 Կ + var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForEncryption192(const Key: TCnAESKey192; + var ExpandedKey: TCnAESExpandedKey192); +{* ڼܳչ AES192 Կ + + + const Key: TCnAESKey192 - չ AES192 Կ + var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForEncryption256(const Key: TCnAESKey256; + var ExpandedKey: TCnAESExpandedKey256); +{* ڼܳչ AES256 Կ + + + const Key: TCnAESKey256 - չ AES256 Կ + var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ + + ֵޣ +} + +// Block Encryption Routines ܣInBuf OutBuf ͬһ + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); overload; +{* AES128 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey128 - չ AES128 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); overload; +{* AES192 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey192 - չ AES192 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); overload; +{* AES256 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey256 - չ AES256 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +{* AES128 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey128 - չ AES128 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure EncryptAES192(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +{* AES192 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey192 - չ AES192 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure EncryptAES256(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +{* AES256 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey256 - չ AES256 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +// Stream Encryption Routines (ECB mode) ECB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); overload; +{* AES128 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); overload; +{* AES128 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); overload; +{* AES256 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); overload; +{* AES192 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); overload; +{* AES256 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); overload; +{* AES256 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +{* AES128 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES128StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +{* AES128 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES192StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +{* AES192 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +{* AES192 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES256StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +{* AES256 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +{* AES256 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + Dest: TStream - + + ֵޣ +} + +// Stream Encryption Routines (CBC mode) CBC + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES128StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES192StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES256StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Encryption Routines (CFB mode) CFB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES128StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Encryption Routines (OFB mode) OFB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES128StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES192StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - ?? + + ֵޣ +} +procedure EncryptAES192StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure EncryptAES256StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Encryption Routines (CTR mode) CTR + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES128 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES128 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES192 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES192 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES256 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES256 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure EncryptAES128StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES128 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES128StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES128 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES192 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES192StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES192 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES256 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure EncryptAES256StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES256 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Key Transformation Routines for Decryption + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey128); overload; +{* ڽܳչ AES128 Կ + + + var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey128; + var ExpandedKey: TCnAESExpandedKey128); overload; +{* ڽܳչ AES128 Կ + + + const Key: TCnAESKey128 - չ AES128 Կ + var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey192); overload; +{* ڽܳչ AES192 Կ + + + var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ + + ֵޣ +} +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey192; + var ExpandedKey: TCnAESExpandedKey192); overload; +{* ڽܳչ AES192 Կ + + + const Key: TCnAESKey192 - չ AES192 Կ + var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey256); overload; +{* ڽܳչ AES256 Կ + + + var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ + + ֵޣ +} +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey256; + var ExpandedKey: TCnAESExpandedKey256); overload; +{* ڽܳչ AES256 Կ + + + const Key: TCnAESKey256 - չ AES256 Կ + var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure ExpandAESKeyForDecryption128(var ExpandedKey: TCnAESExpandedKey128); +{* ڽܳչ AES128 Կ + + + var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ + + ֵޣ +} +procedure ExpandAESKeyForDecryption128Expanded(const Key: TCnAESKey128; + var ExpandedKey: TCnAESExpandedKey128); +{* ڽܳչ AES128 Կ + + + const Key: TCnAESKey128 - չ AES128 Կ + var ExpandedKey: TCnAESExpandedKey128 - չ AES128 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForDecryption192(var ExpandedKey: TCnAESExpandedKey192); +{* ڽܳչ AES192 Կ + + + var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ + + ֵޣ +} +procedure ExpandAESKeyForDecryption192Expanded(const Key: TCnAESKey192; + var ExpandedKey: TCnAESExpandedKey192); +{* ڽܳչ AES192 Կ + + + const Key: TCnAESKey192 - չ AES192 Կ + var ExpandedKey: TCnAESExpandedKey192 - չ AES192 չԿ + + ֵޣ +} + +procedure ExpandAESKeyForDecryption256(var ExpandedKey: TCnAESExpandedKey256); +{* ڽܳչ AES256 Կ + + + var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ + + ֵޣ +} +procedure ExpandAESKeyForDecryption256Expanded(const Key: TCnAESKey256; + var ExpandedKey: TCnAESExpandedKey256); +{* ڽܳչ AES256 Կ + + + const Key: TCnAESKey256 - չ AES256 Կ + var ExpandedKey: TCnAESExpandedKey256 - չ AES256 չԿ + + ֵޣ +} + +// Block Decryption Routines + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); overload; +{* AES128 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey128 - չ AES128 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); overload; +{* AES192 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey192 - չ AES192 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); overload; +{* AES256 ܿ飬 Delphi ¿á + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey256 - չ AES256 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +{* AES128 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey128 - չ AES128 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure DecryptAES192(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +{* AES192 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey192 - չ AES192 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} +procedure DecryptAES256(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +{* AES256 ܿ飬InBuf OutBuf ͬһ + + + const InBuf: TCnAESBuffer - ܵݿ + const Key: TCnAESExpandedKey256 - չ AES256 Կ + var OutBuf: TCnAESBuffer - ĵݿ + + ֵޣ +} + +// Stream Decryption Routines (ECB mode) ECB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); overload; +{* AES128 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); overload; +{* AES128 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); overload; +{* AES192 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); overload; +{* AES192 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); overload; +{* AES256 ECB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); overload; +{* AES256 ECB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +{* AES128 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES128StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +{* AES128 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAES192StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +{* AES192 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +{* AES192 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAES256StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +{* AES256 ECB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +{* AES156 ECB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + Dest: TStream - + + ֵޣ +} + +// Stream Decryption Routines (CBC mode) CBC + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 CBC ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 CBC ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES128StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 CBC ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 CBC ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Decryption Routines (CFB mode) CFB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 CFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 CFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES128StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 CFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 CFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Decryption Routines (OFB mode) OFB + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES128 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES128 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES192 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES192 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); overload; +{* AES256 OFB ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); overload; +{* AES256 OFB ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES128 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES128StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES128 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES192 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES192 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +{* AES256 OFB ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +{* AES256 OFB ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const InitVector: TCnAESBuffer - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Stream Decryption Routines (CTR mode) CTR + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES128 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES128 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES192 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES192 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES256 CTR ģʽ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); overload; +{* AES256 CTR ģʽʹչԿ Delphi ¿á + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +{$ENDIF} + +// Delphi C++Builder ¾ +procedure DecryptAES128StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES128 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey128 - 16 ֽ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES128StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES128 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey128 - չ AES128 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES192 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey192 - 24 ֽ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES192StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES192 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey192 - չ AES192 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES256 CTR ģʽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnAESKey256 - 32 ֽ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} +procedure DecryptAES256StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +{* AES256 CTR ģʽʹչԿ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const ExpandedKey: TCnAESExpandedKey256 - չ AES256 Կ + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const InitVector: TCnAESCTRIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// ============== ַʮַ֮ļӽ =================== + +function AESEncryptEcbStrToHex(Value: AnsiString; Key: AnsiString; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES ECB ģʽַתʮơ + + + Value: AnsiString - ַܵ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptEcbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES ECB ʮַ + + + const HexStr: AnsiString - ܵʮַ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ַ +} + +function AESEncryptCbcStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CBC ģʽַתʮơ + + + Value: AnsiString - ַܵ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCbcStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CBC ʮַ + + + const HexStr: AnsiString - ܵʮַ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ַ +} + +function AESEncryptCfbStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CFB ģʽַתʮơ + + + Value: AnsiString - ַܵ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCfbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CFB ʮַ + + + const HexStr: AnsiString - ܵʮַ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ַ +} + +function AESEncryptOfbStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES OFB ģʽַתʮơ + + + Value: AnsiString - ַܵ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptOfbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES OFB ʮַ + + + const HexStr: AnsiString - ܵʮַ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Iv: TCnAESBuffer - 16 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ַ +} + +function AESEncryptCtrStrToHex(Value: AnsiString; Key: AnsiString; + const Nonce: TCnAESCTRNonce; const Iv: TCnAESCTRIv; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CTR ģʽַתʮơ + + + Value: AnsiString - ַܵ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const Iv: TCnAESCTRIv - 8 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCtrStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Nonce: TCnAESCTRNonce; const Iv: TCnAESCTRIv; KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CTR ʮַ + + + const HexStr: AnsiString - ܵʮַ + Key: AnsiString - AES ԿַȸݼȷΪ 162432 ֽڣ̫ضϣ #0 + const Nonce: TCnAESCTRNonce - 4 ֽ Nonce + const Iv: TCnAESCTRIv - 8 ֽڳʼ + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ַ +} + +// ================= ֽֽ֮ļӽ ==================== + +function AESEncryptEcbBytes(Value: TBytes; Key: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES ECB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESDecryptEcbBytes(Value: TBytes; Key: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES ECB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCbcBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CBC ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESDecryptCbcBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CBC ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCfbBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CFB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESDecryptCfbBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CFB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptOfbBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES OFB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESDecryptOfbBytes(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES OFB ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCtrBytes(Value: TBytes; Key: TBytes; Nonce: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CTR ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Nonce: TBytes - 4 ֽ Nonce 飬̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESDecryptCtrBytes(Value: TBytes; Key: TBytes; Nonce: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CTR ģʽֽ顣 + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Nonce: TBytes - 4 ֽ Nonce 飬̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +// ============== ֽʮַ֮ļӽ ================= + +function AESEncryptEcbBytesToHex(Value: TBytes; Key: TBytes; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES ECB ģʽֽ鲢תʮơ + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptEcbBytesFromHex(const HexStr: AnsiString; Key: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES ECB ʮַֽ顣 + + + const HexStr: AnsiString - ܵʮַ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCbcBytesToHex(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CBC ģʽֽ鲢תʮơ + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCbcBytesFromHex(const HexStr: AnsiString; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CBC ʮַֽ顣 + + + const HexStr: AnsiString - ܵʮַ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCfbBytesToHex(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CFB ģʽֽ鲢תʮơ + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCfbBytesFromHex(const HexStr: AnsiString; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CFB ʮַֽ顣 + + + const HexStr: AnsiString - ܵʮַ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptOfbBytesToHex(Value: TBytes; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES OFB ģʽֽ鲢תʮơ + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptOfbBytesFromHex(const HexStr: AnsiString; Key: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES OFB ʮַֽ顣 + + + const HexStr: AnsiString - ܵʮַ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +function AESEncryptCtrBytesToHex(Value: TBytes; Key: TBytes; Nonce: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): AnsiString; +{* AES CTR ģʽֽ鲢תʮơ + + + Value: TBytes - ֽܵ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Nonce: TBytes - 4 ֽ Nonce ֽ飬̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵAnsiString - ʮַ +} + +function AESDecryptCtrBytesFromHex(const HexStr: AnsiString; Key: TBytes; Nonce: TBytes; Iv: TBytes; + KeyBit: TCnKeyBitType = kbt128): TBytes; +{* AES CTR ʮַֽ顣 + + + const HexStr: AnsiString - ܵʮַ + Key: TBytes - AES Կֽ飬ȸݼȷΪ 162432 ֽڣ̫ضϣ 0 + Nonce: TBytes - 4 ֽ Nonce ֽ飬̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼֽ飬̫ضϣ 0 + KeyBit: TCnKeyBitType - AES + + ֵTBytes - ֽ +} + +implementation + +resourcestring + SCnErrorAESInvalidInBufSize = 'Invalid Buffer Size for Decryption'; + SCnErrorAESReadError = 'Stream Read Error'; + SCnErrorAESWriteError = 'Stream Write Error'; + +function Min(A, B: Integer): Integer; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + if A < B then + Result := A + else + Result := B; +end; + +const + Rcon: array [1..30] of Cardinal = ( + $00000001, $00000002, $00000004, $00000008, $00000010, $00000020, + $00000040, $00000080, $0000001B, $00000036, $0000006C, $000000D8, + $000000AB, $0000004D, $0000009A, $0000002F, $0000005E, $000000BC, + $00000063, $000000C6, $00000097, $00000035, $0000006A, $000000D4, + $000000B3, $0000007D, $000000FA, $000000EF, $000000C5, $00000091 + ); + + ForwardTable: array [0..255] of Cardinal = ( + $A56363C6, $847C7CF8, $997777EE, $8D7B7BF6, $0DF2F2FF, $BD6B6BD6, $B16F6FDE, $54C5C591, + $50303060, $03010102, $A96767CE, $7D2B2B56, $19FEFEE7, $62D7D7B5, $E6ABAB4D, $9A7676EC, + $45CACA8F, $9D82821F, $40C9C989, $877D7DFA, $15FAFAEF, $EB5959B2, $C947478E, $0BF0F0FB, + $ECADAD41, $67D4D4B3, $FDA2A25F, $EAAFAF45, $BF9C9C23, $F7A4A453, $967272E4, $5BC0C09B, + $C2B7B775, $1CFDFDE1, $AE93933D, $6A26264C, $5A36366C, $413F3F7E, $02F7F7F5, $4FCCCC83, + $5C343468, $F4A5A551, $34E5E5D1, $08F1F1F9, $937171E2, $73D8D8AB, $53313162, $3F15152A, + $0C040408, $52C7C795, $65232346, $5EC3C39D, $28181830, $A1969637, $0F05050A, $B59A9A2F, + $0907070E, $36121224, $9B80801B, $3DE2E2DF, $26EBEBCD, $6927274E, $CDB2B27F, $9F7575EA, + $1B090912, $9E83831D, $742C2C58, $2E1A1A34, $2D1B1B36, $B26E6EDC, $EE5A5AB4, $FBA0A05B, + $F65252A4, $4D3B3B76, $61D6D6B7, $CEB3B37D, $7B292952, $3EE3E3DD, $712F2F5E, $97848413, + $F55353A6, $68D1D1B9, $00000000, $2CEDEDC1, $60202040, $1FFCFCE3, $C8B1B179, $ED5B5BB6, + $BE6A6AD4, $46CBCB8D, $D9BEBE67, $4B393972, $DE4A4A94, $D44C4C98, $E85858B0, $4ACFCF85, + $6BD0D0BB, $2AEFEFC5, $E5AAAA4F, $16FBFBED, $C5434386, $D74D4D9A, $55333366, $94858511, + $CF45458A, $10F9F9E9, $06020204, $817F7FFE, $F05050A0, $443C3C78, $BA9F9F25, $E3A8A84B, + $F35151A2, $FEA3A35D, $C0404080, $8A8F8F05, $AD92923F, $BC9D9D21, $48383870, $04F5F5F1, + $DFBCBC63, $C1B6B677, $75DADAAF, $63212142, $30101020, $1AFFFFE5, $0EF3F3FD, $6DD2D2BF, + $4CCDCD81, $140C0C18, $35131326, $2FECECC3, $E15F5FBE, $A2979735, $CC444488, $3917172E, + $57C4C493, $F2A7A755, $827E7EFC, $473D3D7A, $AC6464C8, $E75D5DBA, $2B191932, $957373E6, + $A06060C0, $98818119, $D14F4F9E, $7FDCDCA3, $66222244, $7E2A2A54, $AB90903B, $8388880B, + $CA46468C, $29EEEEC7, $D3B8B86B, $3C141428, $79DEDEA7, $E25E5EBC, $1D0B0B16, $76DBDBAD, + $3BE0E0DB, $56323264, $4E3A3A74, $1E0A0A14, $DB494992, $0A06060C, $6C242448, $E45C5CB8, + $5DC2C29F, $6ED3D3BD, $EFACAC43, $A66262C4, $A8919139, $A4959531, $37E4E4D3, $8B7979F2, + $32E7E7D5, $43C8C88B, $5937376E, $B76D6DDA, $8C8D8D01, $64D5D5B1, $D24E4E9C, $E0A9A949, + $B46C6CD8, $FA5656AC, $07F4F4F3, $25EAEACF, $AF6565CA, $8E7A7AF4, $E9AEAE47, $18080810, + $D5BABA6F, $887878F0, $6F25254A, $722E2E5C, $241C1C38, $F1A6A657, $C7B4B473, $51C6C697, + $23E8E8CB, $7CDDDDA1, $9C7474E8, $211F1F3E, $DD4B4B96, $DCBDBD61, $868B8B0D, $858A8A0F, + $907070E0, $423E3E7C, $C4B5B571, $AA6666CC, $D8484890, $05030306, $01F6F6F7, $120E0E1C, + $A36161C2, $5F35356A, $F95757AE, $D0B9B969, $91868617, $58C1C199, $271D1D3A, $B99E9E27, + $38E1E1D9, $13F8F8EB, $B398982B, $33111122, $BB6969D2, $70D9D9A9, $898E8E07, $A7949433, + $B69B9B2D, $221E1E3C, $92878715, $20E9E9C9, $49CECE87, $FF5555AA, $78282850, $7ADFDFA5, + $8F8C8C03, $F8A1A159, $80898909, $170D0D1A, $DABFBF65, $31E6E6D7, $C6424284, $B86868D0, + $C3414182, $B0999929, $772D2D5A, $110F0F1E, $CBB0B07B, $FC5454A8, $D6BBBB6D, $3A16162C + ); + + LastForwardTable: array [0..255] of Cardinal = ( + $00000063, $0000007C, $00000077, $0000007B, $000000F2, $0000006B, $0000006F, $000000C5, + $00000030, $00000001, $00000067, $0000002B, $000000FE, $000000D7, $000000AB, $00000076, + $000000CA, $00000082, $000000C9, $0000007D, $000000FA, $00000059, $00000047, $000000F0, + $000000AD, $000000D4, $000000A2, $000000AF, $0000009C, $000000A4, $00000072, $000000C0, + $000000B7, $000000FD, $00000093, $00000026, $00000036, $0000003F, $000000F7, $000000CC, + $00000034, $000000A5, $000000E5, $000000F1, $00000071, $000000D8, $00000031, $00000015, + $00000004, $000000C7, $00000023, $000000C3, $00000018, $00000096, $00000005, $0000009A, + $00000007, $00000012, $00000080, $000000E2, $000000EB, $00000027, $000000B2, $00000075, + $00000009, $00000083, $0000002C, $0000001A, $0000001B, $0000006E, $0000005A, $000000A0, + $00000052, $0000003B, $000000D6, $000000B3, $00000029, $000000E3, $0000002F, $00000084, + $00000053, $000000D1, $00000000, $000000ED, $00000020, $000000FC, $000000B1, $0000005B, + $0000006A, $000000CB, $000000BE, $00000039, $0000004A, $0000004C, $00000058, $000000CF, + $000000D0, $000000EF, $000000AA, $000000FB, $00000043, $0000004D, $00000033, $00000085, + $00000045, $000000F9, $00000002, $0000007F, $00000050, $0000003C, $0000009F, $000000A8, + $00000051, $000000A3, $00000040, $0000008F, $00000092, $0000009D, $00000038, $000000F5, + $000000BC, $000000B6, $000000DA, $00000021, $00000010, $000000FF, $000000F3, $000000D2, + $000000CD, $0000000C, $00000013, $000000EC, $0000005F, $00000097, $00000044, $00000017, + $000000C4, $000000A7, $0000007E, $0000003D, $00000064, $0000005D, $00000019, $00000073, + $00000060, $00000081, $0000004F, $000000DC, $00000022, $0000002A, $00000090, $00000088, + $00000046, $000000EE, $000000B8, $00000014, $000000DE, $0000005E, $0000000B, $000000DB, + $000000E0, $00000032, $0000003A, $0000000A, $00000049, $00000006, $00000024, $0000005C, + $000000C2, $000000D3, $000000AC, $00000062, $00000091, $00000095, $000000E4, $00000079, + $000000E7, $000000C8, $00000037, $0000006D, $0000008D, $000000D5, $0000004E, $000000A9, + $0000006C, $00000056, $000000F4, $000000EA, $00000065, $0000007A, $000000AE, $00000008, + $000000BA, $00000078, $00000025, $0000002E, $0000001C, $000000A6, $000000B4, $000000C6, + $000000E8, $000000DD, $00000074, $0000001F, $0000004B, $000000BD, $0000008B, $0000008A, + $00000070, $0000003E, $000000B5, $00000066, $00000048, $00000003, $000000F6, $0000000E, + $00000061, $00000035, $00000057, $000000B9, $00000086, $000000C1, $0000001D, $0000009E, + $000000E1, $000000F8, $00000098, $00000011, $00000069, $000000D9, $0000008E, $00000094, + $0000009B, $0000001E, $00000087, $000000E9, $000000CE, $00000055, $00000028, $000000DF, + $0000008C, $000000A1, $00000089, $0000000D, $000000BF, $000000E6, $00000042, $00000068, + $00000041, $00000099, $0000002D, $0000000F, $000000B0, $00000054, $000000BB, $00000016 + ); + + InverseTable: array [0..255] of Cardinal = ( + $50A7F451, $5365417E, $C3A4171A, $965E273A, $CB6BAB3B, $F1459D1F, $AB58FAAC, $9303E34B, + $55FA3020, $F66D76AD, $9176CC88, $254C02F5, $FCD7E54F, $D7CB2AC5, $80443526, $8FA362B5, + $495AB1DE, $671BBA25, $980EEA45, $E1C0FE5D, $02752FC3, $12F04C81, $A397468D, $C6F9D36B, + $E75F8F03, $959C9215, $EB7A6DBF, $DA595295, $2D83BED4, $D3217458, $2969E049, $44C8C98E, + $6A89C275, $78798EF4, $6B3E5899, $DD71B927, $B64FE1BE, $17AD88F0, $66AC20C9, $B43ACE7D, + $184ADF63, $82311AE5, $60335197, $457F5362, $E07764B1, $84AE6BBB, $1CA081FE, $942B08F9, + $58684870, $19FD458F, $876CDE94, $B7F87B52, $23D373AB, $E2024B72, $578F1FE3, $2AAB5566, + $0728EBB2, $03C2B52F, $9A7BC586, $A50837D3, $F2872830, $B2A5BF23, $BA6A0302, $5C8216ED, + $2B1CCF8A, $92B479A7, $F0F207F3, $A1E2694E, $CDF4DA65, $D5BE0506, $1F6234D1, $8AFEA6C4, + $9D532E34, $A055F3A2, $32E18A05, $75EBF6A4, $39EC830B, $AAEF6040, $069F715E, $51106EBD, + $F98A213E, $3D06DD96, $AE053EDD, $46BDE64D, $B58D5491, $055DC471, $6FD40604, $FF155060, + $24FB9819, $97E9BDD6, $CC434089, $779ED967, $BD42E8B0, $888B8907, $385B19E7, $DBEEC879, + $470A7CA1, $E90F427C, $C91E84F8, $00000000, $83868009, $48ED2B32, $AC70111E, $4E725A6C, + $FBFF0EFD, $5638850F, $1ED5AE3D, $27392D36, $64D90F0A, $21A65C68, $D1545B9B, $3A2E3624, + $B1670A0C, $0FE75793, $D296EEB4, $9E919B1B, $4FC5C080, $A220DC61, $694B775A, $161A121C, + $0ABA93E2, $E52AA0C0, $43E0223C, $1D171B12, $0B0D090E, $ADC78BF2, $B9A8B62D, $C8A91E14, + $8519F157, $4C0775AF, $BBDD99EE, $FD607FA3, $9F2601F7, $BCF5725C, $C53B6644, $347EFB5B, + $7629438B, $DCC623CB, $68FCEDB6, $63F1E4B8, $CADC31D7, $10856342, $40229713, $2011C684, + $7D244A85, $F83DBBD2, $1132F9AE, $6DA129C7, $4B2F9E1D, $F330B2DC, $EC52860D, $D0E3C177, + $6C16B32B, $99B970A9, $FA489411, $2264E947, $C48CFCA8, $1A3FF0A0, $D82C7D56, $EF903322, + $C74E4987, $C1D138D9, $FEA2CA8C, $360BD498, $CF81F5A6, $28DE7AA5, $268EB7DA, $A4BFAD3F, + $E49D3A2C, $0D927850, $9BCC5F6A, $62467E54, $C2138DF6, $E8B8D890, $5EF7392E, $F5AFC382, + $BE805D9F, $7C93D069, $A92DD56F, $B31225CF, $3B99ACC8, $A77D1810, $6E639CE8, $7BBB3BDB, + $097826CD, $F418596E, $01B79AEC, $A89A4F83, $656E95E6, $7EE6FFAA, $08CFBC21, $E6E815EF, + $D99BE7BA, $CE366F4A, $D4099FEA, $D67CB029, $AFB2A431, $31233F2A, $3094A5C6, $C066A235, + $37BC4E74, $A6CA82FC, $B0D090E0, $15D8A733, $4A9804F1, $F7DAEC41, $0E50CD7F, $2FF69117, + $8DD64D76, $4DB0EF43, $544DAACC, $DF0496E4, $E3B5D19E, $1B886A4C, $B81F2CC1, $7F516546, + $04EA5E9D, $5D358C01, $737487FA, $2E410BFB, $5A1D67B3, $52D2DB92, $335610E9, $1347D66D, + $8C61D79A, $7A0CA137, $8E14F859, $893C13EB, $EE27A9CE, $35C961B7, $EDE51CE1, $3CB1477A, + $59DFD29C, $3F73F255, $79CE1418, $BF37C773, $EACDF753, $5BAAFD5F, $146F3DDF, $86DB4478, + $81F3AFCA, $3EC468B9, $2C342438, $5F40A3C2, $72C31D16, $0C25E2BC, $8B493C28, $41950DFF, + $7101A839, $DEB30C08, $9CE4B4D8, $90C15664, $6184CB7B, $70B632D5, $745C6C48, $4257B8D0 + ); + + LastInverseTable: array [0..255] of Cardinal = ( + $00000052, $00000009, $0000006A, $000000D5, $00000030, $00000036, $000000A5, $00000038, + $000000BF, $00000040, $000000A3, $0000009E, $00000081, $000000F3, $000000D7, $000000FB, + $0000007C, $000000E3, $00000039, $00000082, $0000009B, $0000002F, $000000FF, $00000087, + $00000034, $0000008E, $00000043, $00000044, $000000C4, $000000DE, $000000E9, $000000CB, + $00000054, $0000007B, $00000094, $00000032, $000000A6, $000000C2, $00000023, $0000003D, + $000000EE, $0000004C, $00000095, $0000000B, $00000042, $000000FA, $000000C3, $0000004E, + $00000008, $0000002E, $000000A1, $00000066, $00000028, $000000D9, $00000024, $000000B2, + $00000076, $0000005B, $000000A2, $00000049, $0000006D, $0000008B, $000000D1, $00000025, + $00000072, $000000F8, $000000F6, $00000064, $00000086, $00000068, $00000098, $00000016, + $000000D4, $000000A4, $0000005C, $000000CC, $0000005D, $00000065, $000000B6, $00000092, + $0000006C, $00000070, $00000048, $00000050, $000000FD, $000000ED, $000000B9, $000000DA, + $0000005E, $00000015, $00000046, $00000057, $000000A7, $0000008D, $0000009D, $00000084, + $00000090, $000000D8, $000000AB, $00000000, $0000008C, $000000BC, $000000D3, $0000000A, + $000000F7, $000000E4, $00000058, $00000005, $000000B8, $000000B3, $00000045, $00000006, + $000000D0, $0000002C, $0000001E, $0000008F, $000000CA, $0000003F, $0000000F, $00000002, + $000000C1, $000000AF, $000000BD, $00000003, $00000001, $00000013, $0000008A, $0000006B, + $0000003A, $00000091, $00000011, $00000041, $0000004F, $00000067, $000000DC, $000000EA, + $00000097, $000000F2, $000000CF, $000000CE, $000000F0, $000000B4, $000000E6, $00000073, + $00000096, $000000AC, $00000074, $00000022, $000000E7, $000000AD, $00000035, $00000085, + $000000E2, $000000F9, $00000037, $000000E8, $0000001C, $00000075, $000000DF, $0000006E, + $00000047, $000000F1, $0000001A, $00000071, $0000001D, $00000029, $000000C5, $00000089, + $0000006F, $000000B7, $00000062, $0000000E, $000000AA, $00000018, $000000BE, $0000001B, + $000000FC, $00000056, $0000003E, $0000004B, $000000C6, $000000D2, $00000079, $00000020, + $0000009A, $000000DB, $000000C0, $000000FE, $00000078, $000000CD, $0000005A, $000000F4, + $0000001F, $000000DD, $000000A8, $00000033, $00000088, $00000007, $000000C7, $00000031, + $000000B1, $00000012, $00000010, $00000059, $00000027, $00000080, $000000EC, $0000005F, + $00000060, $00000051, $0000007F, $000000A9, $00000019, $000000B5, $0000004A, $0000000D, + $0000002D, $000000E5, $0000007A, $0000009F, $00000093, $000000C9, $0000009C, $000000EF, + $000000A0, $000000E0, $0000003B, $0000004D, $000000AE, $0000002A, $000000F5, $000000B0, + $000000C8, $000000EB, $000000BB, $0000003C, $00000083, $00000053, $00000099, $00000061, + $00000017, $0000002B, $00000004, $0000007E, $000000BA, $00000077, $000000D6, $00000026, + $000000E1, $00000069, $00000014, $00000063, $00000055, $00000021, $0000000C, $0000007D + ); + +procedure ExpandAESKeyForEncryption128(const Key: TCnAESKey128; var ExpandedKey: + TCnAESExpandedKey128); +var + I, J: Integer; + T: Cardinal; + W0, W1, W2, W3: Cardinal; +begin + ExpandedKey[0] := PCardinal(@Key[0])^; + ExpandedKey[1] := PCardinal(@Key[4])^; + ExpandedKey[2] := PCardinal(@Key[8])^; + ExpandedKey[3] := PCardinal(@Key[12])^; + I := 0; J := 1; + repeat + T := (ExpandedKey[I + 3] shl 24) or (ExpandedKey[I + 3] shr 8); + W0 := LastForwardTable[Byte(T)]; W1 := LastForwardTable[Byte(T shr 8)]; + W2 := LastForwardTable[Byte(T shr 16)]; W3 := LastForwardTable[Byte(T shr 24)]; + ExpandedKey[I + 4] := ExpandedKey[I] xor + (W0 xor ((W1 shl 8) or (W1 shr 24)) xor + ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8))) xor Rcon[J]; + Inc(J); + ExpandedKey[I + 5] := ExpandedKey[I + 1] xor ExpandedKey[I + 4]; + ExpandedKey[I + 6] := ExpandedKey[I + 2] xor ExpandedKey[I + 5]; + ExpandedKey[I + 7] := ExpandedKey[I + 3] xor ExpandedKey[I + 6]; + Inc(I, 4); + until I >= 40; +end; + +procedure ExpandAESKeyForEncryption192(const Key: TCnAESKey192; var ExpandedKey: + TCnAESExpandedKey192); +var + I, J: Integer; + T: Cardinal; + W0, W1, W2, W3: Cardinal; +begin + ExpandedKey[0] := PCardinal(@Key[0])^; + ExpandedKey[1] := PCardinal(@Key[4])^; + ExpandedKey[2] := PCardinal(@Key[8])^; + ExpandedKey[3] := PCardinal(@Key[12])^; + ExpandedKey[4] := PCardinal(@Key[16])^; + ExpandedKey[5] := PCardinal(@Key[20])^; + I := 0; J := 1; + repeat + T := (ExpandedKey[I + 5] shl 24) or (ExpandedKey[I + 5] shr 8); + W0 := LastForwardTable[Byte(T)]; W1 := LastForwardTable[Byte(T shr 8)]; + W2 := LastForwardTable[Byte(T shr 16)]; W3 := LastForwardTable[Byte(T shr 24)]; + ExpandedKey[I + 6] := ExpandedKey[I] xor + (W0 xor ((W1 shl 8) or (W1 shr 24)) xor + ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8))) xor Rcon[J]; + Inc(J); + ExpandedKey[I + 7] := ExpandedKey[I + 1] xor ExpandedKey[I + 6]; + ExpandedKey[I + 8] := ExpandedKey[I + 2] xor ExpandedKey[I + 7]; + ExpandedKey[I + 9] := ExpandedKey[I + 3] xor ExpandedKey[I + 8]; + ExpandedKey[I + 10] := ExpandedKey[I + 4] xor ExpandedKey[I + 9]; + ExpandedKey[I + 11] := ExpandedKey[I + 5] xor ExpandedKey[I + 10]; + Inc(I, 6); + until I >= 46; +end; + +procedure ExpandAESKeyForEncryption256(const Key: TCnAESKey256; var ExpandedKey: + TCnAESExpandedKey256); +var + I, J: Integer; + T: Cardinal; + W0, W1, W2, W3: Cardinal; +begin + ExpandedKey[0] := PCardinal(@Key[0])^; + ExpandedKey[1] := PCardinal(@Key[4])^; + ExpandedKey[2] := PCardinal(@Key[8])^; + ExpandedKey[3] := PCardinal(@Key[12])^; + ExpandedKey[4] := PCardinal(@Key[16])^; + ExpandedKey[5] := PCardinal(@Key[20])^; + ExpandedKey[6] := PCardinal(@Key[24])^; + ExpandedKey[7] := PCardinal(@Key[28])^; + I := 0; J := 1; + repeat + T := (ExpandedKey[I + 7] shl 24) or (ExpandedKey[I + 7] shr 8); + W0 := LastForwardTable[Byte(T)]; W1 := LastForwardTable[Byte(T shr 8)]; + W2 := LastForwardTable[Byte(T shr 16)]; W3 := LastForwardTable[Byte(T shr 24)]; + ExpandedKey[I + 8] := ExpandedKey[I] xor + (W0 xor ((W1 shl 8) or (W1 shr 24)) xor + ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8))) xor Rcon[J]; + Inc(J); + ExpandedKey[I + 9] := ExpandedKey[I + 1] xor ExpandedKey[I + 8]; + ExpandedKey[I + 10] := ExpandedKey[I + 2] xor ExpandedKey[I + 9]; + ExpandedKey[I + 11] := ExpandedKey[I + 3] xor ExpandedKey[I + 10]; + W0 := LastForwardTable[Byte(ExpandedKey[I + 11])]; + W1 := LastForwardTable[Byte(ExpandedKey[I + 11] shr 8)]; + W2 := LastForwardTable[Byte(ExpandedKey[I + 11] shr 16)]; + W3 := LastForwardTable[Byte(ExpandedKey[I + 11] shr 24)]; + ExpandedKey[I + 12] := ExpandedKey[I + 4] xor + (W0 xor ((W1 shl 8) or (W1 shr 24)) xor + ((W2 shl 16) or (W2 shr 16)) xor ((W3 shl 24) or (W3 shr 8))); + ExpandedKey[I + 13] := ExpandedKey[I + 5] xor ExpandedKey[I + 12]; + ExpandedKey[I + 14] := ExpandedKey[I + 6] xor ExpandedKey[I + 13]; + ExpandedKey[I + 15] := ExpandedKey[I + 7] xor ExpandedKey[I + 14]; + Inc(I, 8); + until I >= 52; +end; + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +begin + EncryptAES128(InBuf, Key, OutBuf); +end; + +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +begin + EncryptAES192(InBuf, Key, OutBuf); +end; + +procedure EncryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +begin + EncryptAES256(InBuf, Key, OutBuf); +end; + +{$ENDIF} + +procedure EncryptAES128(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[0]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[1]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[2]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[3]; + + // performing transformation 9 times + // round 1 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // round 2 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 3 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 4 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 5 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 6 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 7 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 8 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 9 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // last round of transformations + W0 := LastForwardTable[Byte(T1[0])]; W1 := LastForwardTable[Byte(T1[1] shr 8)]; + W2 := LastForwardTable[Byte(T1[2] shr 16)]; W3 := LastForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; + W0 := LastForwardTable[Byte(T1[1])]; W1 := LastForwardTable[Byte(T1[2] shr 8)]; + W2 := LastForwardTable[Byte(T1[3] shr 16)]; W3 := LastForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; + W0 := LastForwardTable[Byte(T1[2])]; W1 := LastForwardTable[Byte(T1[3] shr 8)]; + W2 := LastForwardTable[Byte(T1[0] shr 16)]; W3 := LastForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; + W0 := LastForwardTable[Byte(T1[3])]; W1 := LastForwardTable[Byte(T1[0] shr 8)]; + W2 := LastForwardTable[Byte(T1[1] shr 16)]; W3 := LastForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +procedure EncryptAES192(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[0]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[1]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[2]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[3]; + + // performing transformation 11 times + // round 1 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // round 2 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 3 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 4 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 5 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 6 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 7 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 8 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 9 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // round 10 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; + // round 11 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[44]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[45]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[46]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[47]; + // last round of transformations + W0 := LastForwardTable[Byte(T1[0])]; W1 := LastForwardTable[Byte(T1[1] shr 8)]; + W2 := LastForwardTable[Byte(T1[2] shr 16)]; W3 := LastForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[48]; + W0 := LastForwardTable[Byte(T1[1])]; W1 := LastForwardTable[Byte(T1[2] shr 8)]; + W2 := LastForwardTable[Byte(T1[3] shr 16)]; W3 := LastForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[49]; + W0 := LastForwardTable[Byte(T1[2])]; W1 := LastForwardTable[Byte(T1[3] shr 8)]; + W2 := LastForwardTable[Byte(T1[0] shr 16)]; W3 := LastForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[50]; + W0 := LastForwardTable[Byte(T1[3])]; W1 := LastForwardTable[Byte(T1[0] shr 8)]; + W2 := LastForwardTable[Byte(T1[1] shr 16)]; W3 := LastForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[51]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +procedure EncryptAES256(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[0]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[1]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[2]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[3]; + + // performing transformation 13 times + // round 1 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // round 2 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 3 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 4 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 5 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 6 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 7 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 8 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 9 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // round 10 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; + // round 11 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[44]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[45]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[46]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[47]; + // round 12 + W0 := ForwardTable[Byte(T1[0])]; W1 := ForwardTable[Byte(T1[1] shr 8)]; + W2 := ForwardTable[Byte(T1[2] shr 16)]; W3 := ForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[48]; + W0 := ForwardTable[Byte(T1[1])]; W1 := ForwardTable[Byte(T1[2] shr 8)]; + W2 := ForwardTable[Byte(T1[3] shr 16)]; W3 := ForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[49]; + W0 := ForwardTable[Byte(T1[2])]; W1 := ForwardTable[Byte(T1[3] shr 8)]; + W2 := ForwardTable[Byte(T1[0] shr 16)]; W3 := ForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[50]; + W0 := ForwardTable[Byte(T1[3])]; W1 := ForwardTable[Byte(T1[0] shr 8)]; + W2 := ForwardTable[Byte(T1[1] shr 16)]; W3 := ForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[51]; + // round 13 + W0 := ForwardTable[Byte(T0[0])]; W1 := ForwardTable[Byte(T0[1] shr 8)]; + W2 := ForwardTable[Byte(T0[2] shr 16)]; W3 := ForwardTable[Byte(T0[3] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[52]; + W0 := ForwardTable[Byte(T0[1])]; W1 := ForwardTable[Byte(T0[2] shr 8)]; + W2 := ForwardTable[Byte(T0[3] shr 16)]; W3 := ForwardTable[Byte(T0[0] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[53]; + W0 := ForwardTable[Byte(T0[2])]; W1 := ForwardTable[Byte(T0[3] shr 8)]; + W2 := ForwardTable[Byte(T0[0] shr 16)]; W3 := ForwardTable[Byte(T0[1] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[54]; + W0 := ForwardTable[Byte(T0[3])]; W1 := ForwardTable[Byte(T0[0] shr 8)]; + W2 := ForwardTable[Byte(T0[1] shr 16)]; W3 := ForwardTable[Byte(T0[2] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[55]; + // last round of transformations + W0 := LastForwardTable[Byte(T1[0])]; W1 := LastForwardTable[Byte(T1[1] shr 8)]; + W2 := LastForwardTable[Byte(T1[2] shr 16)]; W3 := LastForwardTable[Byte(T1[3] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[56]; + W0 := LastForwardTable[Byte(T1[1])]; W1 := LastForwardTable[Byte(T1[2] shr 8)]; + W2 := LastForwardTable[Byte(T1[3] shr 16)]; W3 := LastForwardTable[Byte(T1[0] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[57]; + W0 := LastForwardTable[Byte(T1[2])]; W1 := LastForwardTable[Byte(T1[3] shr 8)]; + W2 := LastForwardTable[Byte(T1[0] shr 16)]; W3 := LastForwardTable[Byte(T1[1] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[58]; + W0 := LastForwardTable[Byte(T1[3])]; W1 := LastForwardTable[Byte(T1[0] shr 8)]; + W2 := LastForwardTable[Byte(T1[1] shr 16)]; W3 := LastForwardTable[Byte(T1[2] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[59]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey128); +begin + ExpandAESKeyForDecryption128(ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey128; + var ExpandedKey: TCnAESExpandedKey128); +begin + ExpandAESKeyForDecryption128Expanded(Key, ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey192); +begin + ExpandAESKeyForDecryption192(ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey192; + var ExpandedKey: TCnAESExpandedKey192); +begin + ExpandAESKeyForDecryption192Expanded(Key, ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption(var ExpandedKey: TCnAESExpandedKey256); +begin + ExpandAESKeyForDecryption256(ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption(const Key: TCnAESKey256; + var ExpandedKey: TCnAESExpandedKey256); +begin + ExpandAESKeyForDecryption256Expanded(Key, ExpandedKey); +end; + +{$ENDIF} + +procedure ExpandAESKeyForDecryption128(var ExpandedKey: TCnAESExpandedKey128); +var + I: Integer; + U, F2, F4, F8, F9: Cardinal; +begin + for I := 1 to 9 do + begin + F9 := ExpandedKey[I * 4]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 1]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 1] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 2]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 2] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 3]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 3] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + end; +end; + +procedure ExpandAESKeyForDecryption128Expanded(const Key: TCnAESKey128; var ExpandedKey: + TCnAESExpandedKey128); +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + ExpandAESKeyForDecryption128(ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption192(var ExpandedKey: TCnAESExpandedKey192); +var + I: Integer; + U, F2, F4, F8, F9: Cardinal; +begin + for I := 1 to 11 do + begin + F9 := ExpandedKey[I * 4]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 1]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 1] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 2]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 2] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 3]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 3] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + end; +end; + +procedure ExpandAESKeyForDecryption192Expanded(const Key: TCnAESKey192; var ExpandedKey: + TCnAESExpandedKey192); +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + ExpandAESKeyForDecryption192(ExpandedKey); +end; + +procedure ExpandAESKeyForDecryption256(var ExpandedKey: TCnAESExpandedKey256); +var + I: Integer; + U, F2, F4, F8, F9: Cardinal; +begin + for I := 1 to 13 do + begin + F9 := ExpandedKey[I * 4]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 1]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 1] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 2]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 2] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + F9 := ExpandedKey[I * 4 + 3]; + U := F9 and $80808080; + F2 := ((F9 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F2 and $80808080; + F4 := ((F2 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + U := F4 and $80808080; + F8 := ((F4 and $7F7F7F7F) shl 1) xor ((U - (U shr 7)) and $1B1B1B1B); + F9 := F9 xor F8; + ExpandedKey[I * 4 + 3] := F2 xor F4 xor F8 xor + (((F2 xor F9) shl 24) or ((F2 xor F9) shr 8)) xor + (((F4 xor F9) shl 16) or ((F4 xor F9) shr 16)) xor ((F9 shl 8) or (F9 shr 24)); + end; +end; + +procedure ExpandAESKeyForDecryption256Expanded(const Key: TCnAESKey256; var ExpandedKey: + TCnAESExpandedKey256); +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + ExpandAESKeyForDecryption256(ExpandedKey); +end; + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +begin + DecryptAES128(InBuf, Key, OutBuf); +end; + +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +begin + DecryptAES192(InBuf, Key, OutBuf); +end; + +procedure DecryptAES(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +begin + DecryptAES256(InBuf, Key, OutBuf); +end; + +{$ENDIF} + +procedure DecryptAES128(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey128; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[40]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[41]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[42]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[43]; + + // performing transformations 9 times + // round 1 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // round 2 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 3 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 4 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 5 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 6 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 7 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 8 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 9 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // last round of transformations + W0 := LastInverseTable[Byte(T1[0])]; W1 := LastInverseTable[Byte(T1[3] shr 8)]; + W2 := LastInverseTable[Byte(T1[2] shr 16)]; W3 := LastInverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[0]; + W0 := LastInverseTable[Byte(T1[1])]; W1 := LastInverseTable[Byte(T1[0] shr 8)]; + W2 := LastInverseTable[Byte(T1[3] shr 16)]; W3 := LastInverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[1]; + W0 := LastInverseTable[Byte(T1[2])]; W1 := LastInverseTable[Byte(T1[1] shr 8)]; + W2 := LastInverseTable[Byte(T1[0] shr 16)]; W3 := LastInverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[2]; + W0 := LastInverseTable[Byte(T1[3])]; W1 := LastInverseTable[Byte(T1[2] shr 8)]; + W2 := LastInverseTable[Byte(T1[1] shr 16)]; W3 := LastInverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[3]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +procedure DecryptAES192(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey192; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[48]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[49]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[50]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[51]; + + // performing transformations 11 times + // round 1 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[44]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[45]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[46]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[47]; + // round 2 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; + // round 3 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // round 4 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 5 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 6 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 7 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 8 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 9 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 10 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 11 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // last round of transformations + W0 := LastInverseTable[Byte(T1[0])]; W1 := LastInverseTable[Byte(T1[3] shr 8)]; + W2 := LastInverseTable[Byte(T1[2] shr 16)]; W3 := LastInverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[0]; + W0 := LastInverseTable[Byte(T1[1])]; W1 := LastInverseTable[Byte(T1[0] shr 8)]; + W2 := LastInverseTable[Byte(T1[3] shr 16)]; W3 := LastInverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[1]; + W0 := LastInverseTable[Byte(T1[2])]; W1 := LastInverseTable[Byte(T1[1] shr 8)]; + W2 := LastInverseTable[Byte(T1[0] shr 16)]; W3 := LastInverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[2]; + W0 := LastInverseTable[Byte(T1[3])]; W1 := LastInverseTable[Byte(T1[2] shr 8)]; + W2 := LastInverseTable[Byte(T1[1] shr 16)]; W3 := LastInverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[3]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +procedure DecryptAES256(const InBuf: TCnAESBuffer; const Key: TCnAESExpandedKey256; + var OutBuf: TCnAESBuffer); +var + T0, T1: array [0..3] of Cardinal; + W0, W1, W2, W3: Cardinal; +begin + // initializing + T0[0] := PCardinal(@InBuf[0])^ xor Key[56]; + T0[1] := PCardinal(@InBuf[4])^ xor Key[57]; + T0[2] := PCardinal(@InBuf[8])^ xor Key[58]; + T0[3] := PCardinal(@InBuf[12])^ xor Key[59]; + + // performing transformations 13 times + // round 1 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[52]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[53]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[54]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[55]; + // round 2 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[48]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[49]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[50]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[51]; + // round 3 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[44]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[45]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[46]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[47]; + // round 4 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[40]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[41]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[42]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[43]; + // round 5 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[36]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[37]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[38]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[39]; + // round 6 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[32]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[33]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[34]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[35]; + // round 7 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[28]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[29]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[30]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[31]; + // round 8 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[24]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[25]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[26]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[27]; + // round 9 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[20]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[21]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[22]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[23]; + // round 10 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[16]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[17]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[18]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[19]; + // round 11 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[12]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[13]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[14]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[15]; + // round 12 + W0 := InverseTable[Byte(T1[0])]; W1 := InverseTable[Byte(T1[3] shr 8)]; + W2 := InverseTable[Byte(T1[2] shr 16)]; W3 := InverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[8]; + W0 := InverseTable[Byte(T1[1])]; W1 := InverseTable[Byte(T1[0] shr 8)]; + W2 := InverseTable[Byte(T1[3] shr 16)]; W3 := InverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[9]; + W0 := InverseTable[Byte(T1[2])]; W1 := InverseTable[Byte(T1[1] shr 8)]; + W2 := InverseTable[Byte(T1[0] shr 16)]; W3 := InverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[10]; + W0 := InverseTable[Byte(T1[3])]; W1 := InverseTable[Byte(T1[2] shr 8)]; + W2 := InverseTable[Byte(T1[1] shr 16)]; W3 := InverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[11]; + // round 13 + W0 := InverseTable[Byte(T0[0])]; W1 := InverseTable[Byte(T0[3] shr 8)]; + W2 := InverseTable[Byte(T0[2] shr 16)]; W3 := InverseTable[Byte(T0[1] shr 24)]; + T1[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[4]; + W0 := InverseTable[Byte(T0[1])]; W1 := InverseTable[Byte(T0[0] shr 8)]; + W2 := InverseTable[Byte(T0[3] shr 16)]; W3 := InverseTable[Byte(T0[2] shr 24)]; + T1[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[5]; + W0 := InverseTable[Byte(T0[2])]; W1 := InverseTable[Byte(T0[1] shr 8)]; + W2 := InverseTable[Byte(T0[0] shr 16)]; W3 := InverseTable[Byte(T0[3] shr 24)]; + T1[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[6]; + W0 := InverseTable[Byte(T0[3])]; W1 := InverseTable[Byte(T0[2] shr 8)]; + W2 := InverseTable[Byte(T0[1] shr 16)]; W3 := InverseTable[Byte(T0[0] shr 24)]; + T1[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[7]; + // last round of transformations + W0 := LastInverseTable[Byte(T1[0])]; W1 := LastInverseTable[Byte(T1[3] shr 8)]; + W2 := LastInverseTable[Byte(T1[2] shr 16)]; W3 := LastInverseTable[Byte(T1[1] shr 24)]; + T0[0] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[0]; + W0 := LastInverseTable[Byte(T1[1])]; W1 := LastInverseTable[Byte(T1[0] shr 8)]; + W2 := LastInverseTable[Byte(T1[3] shr 16)]; W3 := LastInverseTable[Byte(T1[2] shr 24)]; + T0[1] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[1]; + W0 := LastInverseTable[Byte(T1[2])]; W1 := LastInverseTable[Byte(T1[1] shr 8)]; + W2 := LastInverseTable[Byte(T1[0] shr 16)]; W3 := LastInverseTable[Byte(T1[3] shr 24)]; + T0[2] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[2]; + W0 := LastInverseTable[Byte(T1[3])]; W1 := LastInverseTable[Byte(T1[2] shr 8)]; + W2 := LastInverseTable[Byte(T1[1] shr 16)]; W3 := LastInverseTable[Byte(T1[0] shr 24)]; + T0[3] := (W0 xor ((W1 shl 8) or (W1 shr 24)) xor ((W2 shl 16) or (W2 shr 16)) + xor ((W3 shl 24) or (W3 shr 8))) xor Key[3]; + + // finalizing + PCardinal(@OutBuf[0])^ := T0[0]; + PCardinal(@OutBuf[4])^ := T0[1]; + PCardinal(@OutBuf[8])^ := T0[2]; + PCardinal(@OutBuf[12])^ := T0[3]; +end; + +// Stream Encryption Routines (ECB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +begin + EncryptAES128StreamECB(Source, Count, Key, Dest); +end; + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +begin + EncryptAES128StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +begin + EncryptAES192StreamECB(Source, Count, Key, Dest); +end; + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +begin + EncryptAES192StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +begin + EncryptAES256StreamECB(Source, Count, Key, Dest); +end; + +procedure EncryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +begin + EncryptAES256StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +{$ENDIF} + +procedure EncryptAES128StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + EncryptAES128StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure EncryptAES192StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + EncryptAES192StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure EncryptAES256StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + EncryptAES256StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure EncryptAES128StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES128(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + EncryptAES128(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES192StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES192(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + EncryptAES192(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES256StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES256(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + EncryptAES256(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +// Stream Decryption Routines (ECB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +begin + DecryptAES128StreamECB(Source, Count, Key, Dest); +end; + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +begin + DecryptAES128StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +begin + DecryptAES192StreamECB(Source, Count, Key, Dest); +end; + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +begin + DecryptAES192StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +begin + DecryptAES256StreamECB(Source, Count, Key, Dest); +end; + +procedure DecryptAESStreamECB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +begin + DecryptAES256StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +{$ENDIF} + +procedure DecryptAES128StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForDecryption128Expanded(Key, ExpandedKey); + DecryptAES128StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure DecryptAES128StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + if (Count mod SizeOf(TCnAESBuffer)) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); + + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + DecryptAES128(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +procedure DecryptAES192StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForDecryption192Expanded(Key, ExpandedKey); + DecryptAES192StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure DecryptAES192StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + if (Count mod SizeOf(TCnAESBuffer)) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); + + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + DecryptAES192(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +procedure DecryptAES256StreamECB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForDecryption256Expanded(Key, ExpandedKey); + DecryptAES256StreamECBExpanded(Source, Count, ExpandedKey, Dest); +end; + +procedure DecryptAES256StreamECBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + if (Count mod SizeOf(TCnAESBuffer)) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); + + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + DecryptAES256(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +// Stream Encryption Routines (CBC mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES128StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES128StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES192StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES192StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES256StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES256StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure EncryptAES128StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + EncryptAES128StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES128StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); // Ҫÿһ鶼 + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; // ԭʼ IV + EncryptAES128(TempIn, ExpandedKey, TempOut); // ټ + + Done := Dest.Write(TempOut, SizeOf(TempOut)); // д + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Vector := TempOut; // ݴԭʼ IV һʹ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + EncryptAES128(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES192StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + EncryptAES192StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES192StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + EncryptAES192(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + EncryptAES192(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES256StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + EncryptAES256StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES256StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + EncryptAES256(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + EncryptAES256(TempIn, ExpandedKey, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +// Stream Decryption Routines (CBC mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES128StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES128StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES192StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES192StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES256StreamCBC(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCBC(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES256StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure DecryptAES128StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForDecryption128Expanded(Key, ExpandedKey); + DecryptAES128StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES128StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector1, Vector2: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + if Count mod SizeOf(TCnAESBuffer) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); + + Vector1 := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + Vector2 := TempIn; + DecryptAES128(TempIn, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@Vector1[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@Vector1[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + + Vector1 := Vector2; + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +procedure DecryptAES192StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForDecryption192Expanded(Key, ExpandedKey); + DecryptAES192StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES192StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector1, Vector2: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + if Count mod SizeOf(TCnAESBuffer) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); + + Vector1 := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + Vector2 := TempIn; + DecryptAES192(TempIn, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@Vector1[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@Vector1[12])^; + Done := Dest.Write(TempOut, SizeOf(TempOut)); + + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + + Vector1 := Vector2; + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +procedure DecryptAES256StreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForDecryption256Expanded(Key, ExpandedKey); + DecryptAES256StreamCBCExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES256StreamCBCExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector1, Vector2: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + if Count mod SizeOf(TCnAESBuffer) > 0 then + raise ECnAESException.Create(SCnErrorAESInvalidInBufSize); // CBC Ϊ AES ֿܲģԱ + + Vector1 := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + Vector2 := TempIn; + DecryptAES256(TempIn, ExpandedKey, TempOut); // Ƚ + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; // ܺݺ Iv õ + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@Vector1[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@Vector1[12])^; + Done := Dest.Write(TempOut, SizeOf(TempOut)); // дȥ + + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + + Vector1 := Vector2; // ȡ Iv Ϊһκͽ + Dec(Count, SizeOf(TCnAESBuffer)); + end; +end; + +// Stream Encryption Routines (CFB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES128StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES128StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES192StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES192StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES256StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES256StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure EncryptAES128StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + EncryptAES128StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES128StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES128(Vector, ExpandedKey, TempOut); // Key ȼ Iv + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); // ĽдĽ + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Vector := TempOut; // Ľȡ Iv һּ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES128(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES192StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + EncryptAES192StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES192StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES256StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + EncryptAES256StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES256StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +// Stream Decryption Routines (CFB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES128StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES128StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES192StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES192StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES256StreamCFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamCFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES256StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure DecryptAES128StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + DecryptAES128StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES128StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + // CFB Ϊ AES ֿܲĶĿɶ + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); // + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES128(Vector, ExpandedKey, TempOut); // Iv ȼܡעǼܣǽܣ + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; // ܺݺõ + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); // дȥ + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + + Vector := TempIn; // ȡ Iv Ϊһμ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then // һ鲻Ϊ + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES128(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; // ܺݺõ + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempOut, Count); // дȥ + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +procedure DecryptAES192StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + DecryptAES192StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES192StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + + Vector := TempIn; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempOut, Count); + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +procedure DecryptAES256StreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + DecryptAES256StreamCFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES256StreamCFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorAESWriteError); + + Vector := TempIn; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempOut, Count); + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +// Stream Encryption Routines (OFB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES128StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES128StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES192StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES192StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + EncryptAES256StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure EncryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + EncryptAES256StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure EncryptAES128StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + EncryptAES128StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES128StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES128(Vector, ExpandedKey, TempOut); // Key ȼ Iv + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + Vector := TempOut; // ܽȡ Iv һּܣעⲻ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES128(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES192StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + EncryptAES192StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES192StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES256StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + EncryptAES256StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure EncryptAES256StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +// Stream Decryption Routines (OFB mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES128StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES128StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES192StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES192StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +begin + DecryptAES256StreamOFB(Source, Count, Key, InitVector, Dest); +end; + +procedure DecryptAESStreamOFB(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +begin + DecryptAES256StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +{$ENDIF} + +procedure DecryptAES128StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + DecryptAES128StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES128StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + // OFB Ϊ AES ֿܲĶĿɶ + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); // + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES128(Vector, ExpandedKey, TempOut); // Iv ȼܡעǼܣǽܣ + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; // ܺݺõ + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); // дȥ + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESWriteError); + + Vector := TempOut; // ȡ Iv Ϊһǰ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then // һ鲻Ϊ + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES128(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; // ܺݺõ + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempIn, Count); // дȥ + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +procedure DecryptAES192StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + DecryptAES192StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES192StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESWriteError); + + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +procedure DecryptAES256StreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const InitVector: TCnAESBuffer; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + DecryptAES256StreamOFBExpanded(Source, Count, ExpandedKey, InitVector, Dest); +end; + +procedure DecryptAES256StreamOFBExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const InitVector: TCnAESBuffer; + Dest: TStream); +var + TempIn, TempOut: TCnAESBuffer; + Vector: TCnAESBuffer; + Done: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Vector := InitVector; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorAESWriteError); + + Vector := TempOut; + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESReadError); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempIn, Count); + if Done < Count then + raise EStreamError(SCnErrorAESWriteError); + end; +end; + +// Stream Encryption Routines (CTR mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES128StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES192StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES256StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure EncryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +{$ENDIF} + +procedure EncryptAES128StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + EncryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure EncryptAES128StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done, Cnt, T: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Cnt := 1; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES128(Vector, ExpandedKey, TempOut); // Key ȼƴ Iv + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Inc(Cnt); // һ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES128(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES192StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + EncryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure EncryptAES192StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done, Cnt, T: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Cnt := 1; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES192(Vector, ExpandedKey, TempOut); // Key ȼƴ Iv + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Inc(Cnt); // һ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES192(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +procedure EncryptAES256StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + EncryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure EncryptAES256StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + TempIn, TempOut, Vector: TCnAESBuffer; + Done, Cnt, T: Cardinal; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + if Count = 0 then + Exit; + + Cnt := 1; + while Count >= SizeOf(TCnAESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES256(Vector, ExpandedKey, TempOut); // Key ȼƴ Iv + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorAESWriteError); + + Inc(Cnt); // һ + Dec(Count, SizeOf(TCnAESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorAESReadError); + + Move(Nonce[0], Vector[0], SizeOf(TCnAESCTRNonce)); + Move(InitVector[0], Vector[SizeOf(TCnAESCTRNonce)], SizeOf(TCnAESCTRIv)); + T := UInt32HostToNetwork(Cnt); + Move(T, Vector[SizeOf(TCnAESCTRNonce) + SizeOf(TCnAESCTRIv)], SizeOf(Cardinal)); + + EncryptAES256(Vector, ExpandedKey, TempOut); + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorAESWriteError); + end; +end; + +// Stream Decryption Routines (CTR mode) + +{$IFNDEF BCB5OR6} + +// C++Builder overload ⣬ Delphi ¿ +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES128StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES192StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES256StreamCTR(Source, Count, Key, Nonce, InitVector, Dest); +end; + +procedure DecryptAESStreamCTR(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + DecryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +{$ENDIF} + +procedure DecryptAES128StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey128; +begin + ExpandAESKeyForEncryption128(Key, ExpandedKey); + DecryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAES128StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey128; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES128StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAES192StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey192; +begin + ExpandAESKeyForEncryption192(Key, ExpandedKey); + DecryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAES192StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey192; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES192StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAES256StreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnAESKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +var + ExpandedKey: TCnAESExpandedKey256; +begin + ExpandAESKeyForEncryption256(Key, ExpandedKey); + DecryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +procedure DecryptAES256StreamCTRExpanded(Source: TStream; Count: Cardinal; + const ExpandedKey: TCnAESExpandedKey256; const Nonce: TCnAESCTRNonce; + const InitVector: TCnAESCTRIv; Dest: TStream); +begin + EncryptAES256StreamCTRExpanded(Source, Count, ExpandedKey, Nonce, InitVector, Dest); +end; + +// AES ECB ַתʮ +function AESEncryptEcbStrToHex(Value: AnsiString; Key: AnsiString; + KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[1])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamECB(SS, 0, AESKey128, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamECB(SS, 0, AESKey192, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamECB(SS, 0, AESKey256, DS); + end; + end; + + Result := AnsiString(DataToHex(DS.Memory, DS.Size)); + finally + SS.Free; + DS.Free; + end; +end; + +// AES ECB ʮַ +function AESDecryptEcbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + Tmp: TBytes; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + Tmp := HexToBytes(string(HexStr)); + SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamECB(SS, SS.Size - SS.Position, AESKey128, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamECB(SS, SS.Size - SS.Position, AESKey192, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamECB(SS, SS.Size - SS.Position, AESKey256, DS); + end; + end; + + SetLength(Result, DS.Size); + Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CBC ַתʮ +function AESEncryptCbcStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[1])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCBC(SS, 0, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCBC(SS, 0, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCBC(SS, 0, AESKey256, Iv, DS); + end; + end; + + Result := AnsiString(DataToHex(DS.Memory, DS.Size)); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CBC ʮַ +function AESDecryptCbcStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + Tmp: TBytes; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + Tmp := HexToBytes(string(HexStr)); + SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCBC(SS, SS.Size - SS.Position, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCBC(SS, SS.Size - SS.Position, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCBC(SS, SS.Size - SS.Position, AESKey256, Iv, DS); + end; + end; + + SetLength(Result, DS.Size); + Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CFB ģʽַתʮ +function AESEncryptCfbStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[1])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCFB(SS, 0, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCFB(SS, 0, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCFB(SS, 0, AESKey256, Iv, DS); + end; + end; + + Result := AnsiString(DataToHex(DS.Memory, DS.Size)); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CFB ʮַ +function AESDecryptCfbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + Tmp: TBytes; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + Tmp := HexToBytes(string(HexStr)); + SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCFB(SS, SS.Size - SS.Position, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCFB(SS, SS.Size - SS.Position, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCFB(SS, SS.Size - SS.Position, AESKey256, Iv, DS); + end; + end; + + SetLength(Result, DS.Size); + Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES OFB ģʽַתʮ +function AESEncryptOfbStrToHex(Value: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[1])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamOFB(SS, 0, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamOFB(SS, 0, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamOFB(SS, 0, AESKey256, Iv, DS); + end; + end; + + Result := AnsiString(DataToHex(DS.Memory, DS.Size)); + finally + SS.Free; + DS.Free; + end; +end; + +// AES OFB ʮַ +function AESDecryptOfbStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Iv: TCnAESBuffer; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + Tmp: TBytes; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + Tmp := HexToBytes(string(HexStr)); + SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamOFB(SS, SS.Size - SS.Position, AESKey128, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamOFB(SS, SS.Size - SS.Position, AESKey192, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamOFB(SS, SS.Size - SS.Position, AESKey256, Iv, DS); + end; + end; + + SetLength(Result, DS.Size); + Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CTR ģʽַתʮ +function AESEncryptCtrStrToHex(Value: AnsiString; Key: AnsiString; + const Nonce: TCnAESCTRNonce; const Iv: TCnAESCTRIv; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[1])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCTR(SS, 0, AESKey128, Nonce, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCTR(SS, 0, AESKey192, Nonce, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCTR(SS, 0, AESKey256, Nonce, Iv, DS); + end; + end; + + Result := AnsiString(DataToHex(DS.Memory, DS.Size)); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CTR ʮַ +function AESDecryptCtrStrFromHex(const HexStr: AnsiString; Key: AnsiString; + const Nonce: TCnAESCTRNonce; const Iv: TCnAESCTRIv; KeyBit: TCnKeyBitType): AnsiString; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + Tmp: TBytes; +begin + Result := ''; + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + Tmp := HexToBytes(string(HexStr)); + SS.Write(PAnsiChar(@Tmp[0])^, Length(Tmp)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCTR(SS, SS.Size - SS.Position, AESKey128, Nonce, Iv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCTR(SS, SS.Size - SS.Position, AESKey192, Nonce, Iv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCTR(SS, SS.Size - SS.Position, AESKey256, Nonce, Iv, DS); + end; + end; + + SetLength(Result, DS.Size); + Move(PAnsiChar(DS.Memory)^, Result[1], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES ECB ģʽֽ +function AESEncryptEcbBytes(Value, Key: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamECB(SS, 0, AESKey128, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamECB(SS, 0, AESKey192, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamECB(SS, 0, AESKey256, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES ECB ģʽֽ +function AESDecryptEcbBytes(Value, Key: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamECB(SS, SS.Size - SS.Position, AESKey128, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamECB(SS, SS.Size - SS.Position, AESKey192, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamECB(SS, SS.Size - SS.Position, AESKey256, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CBC ģʽֽ +function AESEncryptCbcBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCBC(SS, 0, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCBC(SS, 0, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCBC(SS, 0, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CBC ģʽֽ +function AESDecryptCbcBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCBC(SS, SS.Size - SS.Position, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCBC(SS, SS.Size - SS.Position, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCBC(SS, SS.Size - SS.Position, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CFB ģʽֽ +function AESEncryptCfbBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCFB(SS, 0, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCFB(SS, 0, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCFB(SS, 0, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CFB ģʽֽ +function AESDecryptCfbBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCFB(SS, SS.Size - SS.Position, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCFB(SS, SS.Size - SS.Position, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCFB(SS, SS.Size - SS.Position, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES OFB ģʽֽ +function AESEncryptOfbBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamOFB(SS, 0, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamOFB(SS, 0, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamOFB(SS, 0, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES OFB ģʽֽ +function AESDecryptOfbBytes(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESBuffer; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamOFB(SS, SS.Size - SS.Position, AESKey128, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamOFB(SS, SS.Size - SS.Position, AESKey192, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamOFB(SS, SS.Size - SS.Position, AESKey256, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CTR ģʽֽ +function AESEncryptCtrBytes(Value, Key, Nonce, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESCTRIv; + AESNonce: TCnAESCTRNonce; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + + FillChar(AESNonce, SizeOF(AESNonce), 0); + Move(PAnsiChar(Nonce)^, AESNonce, Min(SizeOf(AESNonce), Length(Nonce))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + EncryptAES128StreamCTR(SS, 0, AESKey128, AESNonce, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + EncryptAES192StreamCTR(SS, 0, AESKey192, AESNonce, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + EncryptAES256StreamCTR(SS, 0, AESKey256, AESNonce, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES CTR ģʽֽ +function AESDecryptCtrBytes(Value, Key, Nonce, Iv: TBytes; KeyBit: TCnKeyBitType): TBytes; +var + SS, DS: TMemoryStream; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AESIv: TCnAESCTRIv; + AESNonce: TCnAESCTRNonce; +begin + if Length(Value) <= 0 then + begin + Result := nil; + Exit; + end; + + SS := nil; + DS := nil; + + try + SS := TMemoryStream.Create; + SS.Write(PAnsiChar(@Value[0])^, Length(Value)); + SS.Position := 0; + + FillChar(AESIv, SizeOF(AESIv), 0); + Move(PAnsiChar(Iv)^, AESIv, Min(SizeOf(AESIv), Length(Iv))); + + FillChar(AESNonce, SizeOF(AESNonce), 0); + Move(PAnsiChar(Nonce)^, AESNonce, Min(SizeOf(AESNonce), Length(Nonce))); + DS := TMemoryStream.Create; + + case KeyBit of + kbt128: + begin + FillChar(AESKey128, SizeOf(AESKey128), 0); + Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); + DecryptAES128StreamCTR(SS, SS.Size - SS.Position, AESKey128, AESNonce, AESIv, DS); + end; + kbt192: + begin + FillChar(AESKey192, SizeOf(AESKey192), 0); + Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); + DecryptAES192StreamCTR(SS, SS.Size - SS.Position, AESKey192, AESNonce, AESIv, DS); + end; + kbt256: + begin + FillChar(AESKey256, SizeOf(AESKey256), 0); + Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); + DecryptAES256StreamCTR(SS, SS.Size - SS.Position, AESKey256, AESNonce, AESIv, DS); + end; + end; + + SetLength(Result, DS.Size); + DS.Position := 0; + DS.Read(Result[0], DS.Size); + finally + SS.Free; + DS.Free; + end; +end; + +// AES ECB ģʽֽ鲢תʮ +function AESEncryptEcbBytesToHex(Value, Key: TBytes; KeyBit: TCnKeyBitType): AnsiString; +begin + Result := AnsiString(BytesToHex(AESEncryptEcbBytes(Value, Key, KeyBit))); +end; + +// AES ECB ʮַֽ +function AESDecryptEcbBytesFromHex(const HexStr: AnsiString; Key: TBytes; + KeyBit: TCnKeyBitType): TBytes; +begin + Result := AESDecryptEcbBytes(HexToBytes(string(HexStr)), Key, KeyBit); +end; + +// AES CBC ģʽֽ鲢תʮ +function AESEncryptCbcBytesToHex(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): AnsiString; +begin + Result := AnsiString(BytesToHex(AESEncryptCbcBytes(Value, Key, Iv, KeyBit))); +end; + +// AES CBC ʮַֽ +function AESDecryptCbcBytesFromHex(const HexStr: AnsiString; Key, Iv: TBytes; + KeyBit: TCnKeyBitType): TBytes; +begin + Result := AESDecryptCbcBytes(HexToBytes(string(HexStr)), Key, Iv, KeyBit); +end; + +// AES CFB ģʽֽ鲢תʮ +function AESEncryptCfbBytesToHex(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): AnsiString; +begin + Result := AnsiString(BytesToHex(AESEncryptCfbBytes(Value, Key, Iv, KeyBit))); +end; + +// AES CFB ʮַֽ +function AESDecryptCfbBytesFromHex(const HexStr: AnsiString; Key, Iv: TBytes; + KeyBit: TCnKeyBitType): TBytes; +begin + Result := AESDecryptCfbBytes(HexToBytes(string(HexStr)), Key, Iv, KeyBit); +end; + +// AES OFB ģʽֽ鲢תʮ +function AESEncryptOfbBytesToHex(Value, Key, Iv: TBytes; KeyBit: TCnKeyBitType): AnsiString; +begin + Result := AnsiString(BytesToHex(AESEncryptOfbBytes(Value, Key, Iv, KeyBit))); +end; + +// AES OFB ʮַֽ +function AESDecryptOfbBytesFromHex(const HexStr: AnsiString; Key, Iv: TBytes; + KeyBit: TCnKeyBitType): TBytes; +begin + Result := AESDecryptOfbBytes(HexToBytes(string(HexStr)), Key, Iv, KeyBit); +end; + +// AES CTR ģʽֽ鲢תʮ +function AESEncryptCtrBytesToHex(Value, Key, Nonce, Iv: TBytes; KeyBit: TCnKeyBitType): AnsiString; +begin + Result := AnsiString(BytesToHex(AESEncryptCtrBytes(Value, Key, Nonce, Iv, KeyBit))); +end; + +// AES CTR ʮַֽ +function AESDecryptCtrBytesFromHex(const HexStr: AnsiString; Key, Nonce, Iv: TBytes; + KeyBit: TCnKeyBitType): TBytes; +begin + Result := AESDecryptCtrBytes(HexToBytes(string(HexStr)), Key, Nonce, Iv, KeyBit); +end; + +end. + diff --git a/CnPack/Crypto/CnBase64.pas b/CnPack/Crypto/CnBase64.pas new file mode 100644 index 0000000..1aae0e4 --- /dev/null +++ b/CnPack/Crypto/CnBase64.pas @@ -0,0 +1,1070 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +{ -----------------------------------------------------------------------------} +{ uTBase64 v1.0 - Simple Base64 encoding/decoding class } +{ Base64 described in RFC2045, Page 24, (w) 1996 Freed & Borenstein } +{ Delphi implementation (w) 1999 Dennis D. Spreen (dennis@spreendigital.de) } +{ This unit is freeware. Just drop me a line if this unit is useful for you. } +{ -----------------------------------------------------------------------------} + +unit CnBase64; +{* |
+================================================================================ +* ƣ +* ԪƣBase64/32 㷨ʵֵԪ +* ԪߣղSolin solin@21cn.com; http://www.ilovezhuzhu.net +* wr960204 +* CnPack (master@cnpack.org) +* ݻ Dennis D. Spreen UTBASE64.pas дԭаȨϢ +* עԪʵ˱ Base64 Base64URL ı빦ܣԼ RFC 4648 е +* Base32 빦ܣBase16 д HEXʵ֣ +* +* Base64URL ڱ Base64ѷ + / 滻 - _ URL +* Ѻãɾβ = +* +* ע벿в FixZero ȥĩβ #0Ǽӽܵ +* Base64 ܺڴ˴룬ʱ FixZero ָΪ False +* ĩβɳ #0 ʱضӰܽ +* +* ƽ̨PWin2003Std + Delphi 6.0 +* ݲԣδ +* õԪ豾ػ +* ļ¼2026.05.11 V1.7 +* Base32 ıʵ +* 2023.10.04 V1.6 +* ɾʵ֡Base64Encode Base64Decode ֧ Base64URL ı +* 2019.12.12 V1.5 +* ֧ TBytes +* 2019.04.15 V1.4 +* ֧ Win32/Win64/MacOS +* 2018.06.22 V1.3 +* ԭʼݿܰ #0 ԭʼβ #0 Ƴ +* 2016.05.03 V1.2 +* ַа #0 ʱܻᱻضϵ +* 2006.10.25 V1.1 +* wr960204 Ż汾 +* 2003.10.14 V1.0 +* Ԫ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes, CnNative, CnConsts; + +const + // + ECN_BASE64_OK = ECN_OK; + {* Base64 ϵд룺ֵΪ 0} + + ECN_BASE64_ERROR_BASE = ECN_CUSTOM_ERROR_BASE + $500; + {* Base64 ϵдĻʼֵΪ ECN_CUSTOM_ERROR_BASE $500} + + ECN_BASE64_LENGTH = ECN_BASE64_ERROR_BASE + 1; + {* Base64 ֮ݳȷǷ} + + ECN_BASE32_OK = ECN_OK; + {* Base32 ϵд룺ֵΪ 0} + + ECN_BASE32_LENGTH = ECN_BASE64_LENGTH; + {* Base32 ֮ݳȷǷ} + +function Base64Encode(InputData: TStream; var OutputData: string; + URL: Boolean = False): Integer; overload; +{* Base64 Base64URL 룬ɹ ECN_BASE64_OK + + + InputData: TStream - + var OutputData: string - ַ + URL: Boolean - URL ǡTrue ʹ Base64URL 룬False ʹñ Base64 + + ֵInteger - رǷɹɹ ECN_BASE64_OK +} + +function Base64Encode(const InputData: AnsiString; var OutputData: string; + URL: Boolean = False): Integer; overload; +{* ַ Base64 Base64URL 룬ɹ ECN_BASE64_OK + + + const InputData: AnsiString - ַ + var OutputData: string - ַ + URL: Boolean - URL ǡTrue ʹ Base64URL 룬False ʹñ Base64 + + ֵInteger - رǷɹɹ ECN_BASE64_OK +} + +function Base64Encode(InputData: Pointer; DataByteLen: Integer; var OutputData: string; + URL: Boolean = False): Integer; overload; +{* ݿ Base64 Base64URL 룬ɹ ECN_BASE64_OK + + + InputData: Pointer - ݿַ + DataByteLen: Integer - ݿֽڳ + var OutputData: string - ַ + URL: Boolean - URL ǡTrue ʹ Base64URL 룬False ʹñ Base64 + + ֵInteger - رǷɹɹ ECN_BASE64_OK +} + +function Base64Encode(const InputData: TBytes; var OutputData: string; + URL: Boolean = False): Integer; overload; +{* ֽ Base64 Base64URL 룬ɹ ECN_BASE64_OK + + + const InputData: TBytes - ֽ + var OutputData: string - ַ + URL: Boolean - URL ǡTrue ʹ Base64URL 룬False ʹñ Base64 + + ֵInteger - رǷɹɹ ECN_BASE64_OK +} + +function Base64Decode(const InputData: string; OutputData: TStream; + FixZero: Boolean = True): Integer; overload; +{* ַ Base64 루 Base64URL 룩дɹ ECN_BASE64_OK + + + const InputData: string - ַ + OutputData: TStream - + FixZero: Boolean - Ƿȥβ #0 + + ֵInteger - ؽǷɹɹ ECN_BASE64_OK +} + +function Base64Decode(const InputData: string; var OutputData: AnsiString; + FixZero: Boolean = True): Integer; overload; +{* ַ Base64 루 Base64URL 룩дַɹ ECN_BASE64_OK + + + const InputData: string - ַ + var OutputData: AnsiString - ַ + FixZero: Boolean - Ƿȥβ #0 + + ֵInteger - ؽǷɹɹ ECN_BASE64_OK +} + +function Base64Decode(const InputData: string; OutputData: Pointer; + DataByteLen: Integer; FixZero: Boolean = True): Integer; overload; +{* ַ Base64 루 Base64URL 룩дڴɹ ECN_BASE64_OK + + + const InputData: string - ַ + OutputData: Pointer - ڴַ + DataByteLen: Integer - ڴֽڳȣӦΪ 1 + (Length(InputData) * 3 / 4) + FixZero: Boolean - Ƿȥβ #0 + + ֵInteger - OutputData nilĽֽڳȡؽǷɹɹ ECN_BASE64_OK +} + +function Base64Decode(const InputData: string; out OutputData: TBytes; + FixZero: Boolean = True): Integer; overload; +{* ַ Base64 루 Base64URL 룩дֽ顣ɹ ECN_BASE64_OK + + + const InputData: string - ַ + out OutputData: TBytes - ֽ + FixZero: Boolean - Ƿȥβ #0 + + ֵInteger - ؽǷɹɹ ECN_BASE64_OK +} + +function Base64IsStrictText(const InputData: string; AllowURLSafe: Boolean = False): Boolean; +{* жַǷϸϷ Base64 ַݼ볤ȼ⡣ + + + const InputData: string - жϵַ + AllowURLSafe: Boolean - Ƿʹ URL ȫַ + + ֵBoolean - ǷϸϷ Base64 ַ +} + +function Base32Encode(InputData: TStream; var OutputData: string): Integer; overload; +{* Base32 룬ɹ ECN_BASE32_OK + + + InputData: TStream - + var OutputData: string - ַ + + ֵInteger - رǷɹɹ ECN_BASE32_OK +} + +function Base32Encode(const InputData: AnsiString; var OutputData: string): Integer; overload; +{* ַ Base32 룬ɹ ECN_BASE32_OK + + + const InputData: AnsiString - ַ + var OutputData: string - ַ + + ֵInteger - رǷɹɹ ECN_BASE32_OK +} + +function Base32Encode(InputData: Pointer; DataByteLen: Integer; var OutputData: string): Integer; overload; +{* ݿ Base32 룬ɹ ECN_BASE32_OK + + + InputData: Pointer - ݿַ + DataByteLen: Integer - ݿֽڳ + var OutputData: string - ַ + + ֵInteger - رǷɹɹ ECN_BASE32_OK +} + +function Base32Encode(const InputData: TBytes; var OutputData: string): Integer; overload; +{* ֽ Base32 룬ɹ ECN_BASE32_OK + + + const InputData: TBytes - ֽ + var OutputData: string - ַ + + ֵInteger - رǷɹɹ ECN_BASE32_OK +} + +function Base32Decode(const InputData: string; OutputData: TStream): Integer; overload; +{* ַ Base32 룬дɹ ECN_BASE32_OK + + + const InputData: string - ַ + OutputData: TStream - + + ֵInteger - ؽǷɹɹ ECN_BASE32_OK +} + +function Base32Decode(const InputData: string; var OutputData: AnsiString): Integer; overload; +{* ַ Base32 룬дַɹ ECN_BASE32_OK + + + const InputData: string - ַ + var OutputData: AnsiString - ַ + + ֵInteger - ؽǷɹɹ ECN_BASE32_OK +} + +function Base32Decode(const InputData: string; OutputData: Pointer; + DataByteLen: Integer): Integer; overload; +{* ַ Base32 룬дڴɹ ECN_BASE32_OK + + + const InputData: string - ַ + OutputData: Pointer - ڴַ + DataByteLen: Integer - ڴֽڳȣӦΪ 1 + (Length(InputData) * 5 / 8) + + ֵInteger - OutputData nilĽֽڳȡؽǷɹɹ ECN_BASE32_OK +} + +function Base32Decode(const InputData: string; out OutputData: TBytes): Integer; overload; +{* ַ Base32 룬дֽ顣ɹ ECN_BASE32_OK + + + const InputData: string - ַ + out OutputData: TBytes - ֽ + + ֵInteger - ؽǷɹɹ ECN_BASE32_OK +} + +function Base32IsStrictText(const InputData: string): Boolean; +{* жַǷϸϷ Base32 ַݼ볤ȼ⡣ + + + const InputData: string - жϵַ + + ֵBoolean - ǷϸϷ Base32 ַ +} + +implementation + +var + FilterDecodeInput: Boolean = True; + +//------------------------------------------------------------------------------ +// IJο +//------------------------------------------------------------------------------ + + EnCodeTab64: array[0..64] of AnsiChar = + ( + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/', + '='); + + EnCodeTab64URL: array[0..64] of AnsiChar = + ( + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '-', '_', + '='); + + EnCodeTab32: array[0..32] of AnsiChar = + ( + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', '2', '3', '4', '5', '6', '7', + '=' + ); + +//------------------------------------------------------------------------------ +// IJο +//------------------------------------------------------------------------------ + + { Base64 ֱַӸ㣬Ҳȡ} + DecodeTable64: array[#0..#127] of Byte = + ( + Byte('='), 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, + 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 62, 00, 62, 00, 63, // ĵһ 62 63 + / - 62 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 00, 00, 00, 00, 00, 00, + 00, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 00, 00, 00, 00, 63, // _ 63 + 00, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 00, 00, 00, 00, 00 + ); + +// Ϊ wr960204 ĽĿ Base64 㷨 +function Base64Encode(InputData: Pointer; DataByteLen: Integer; + var OutputData: string; URL: Boolean): Integer; +var + Times, I: Integer; + X1, X2, X3, X4: AnsiChar; + XT: Byte; +begin + if (InputData = nil) or (DataByteLen <= 0) then + begin + Result := ECN_BASE64_LENGTH; + Exit; + end; + + if DataByteLen mod 3 = 0 then + Times := DataByteLen div 3 + else + Times := DataByteLen div 3 + 1; + SetLength(OutputData, Times * 4); // һηڴ,һδַ,һδͷŷڴ + FillChar(OutputData[1], Length(OutputData) * SizeOf(Char), 0); + + if URL then + begin + for I := 0 to Times - 1 do + begin + if DataByteLen >= (3 + I * 3) then + begin + X1 := EnCodeTab64URL[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + XT := XT or (Ord(PAnsiChar(InputData)[1 + I * 3]) shr 4); + X2 := EnCodeTab64URL[XT]; + XT := (Ord(PAnsiChar(InputData)[1 + I * 3]) shl 2) and 60; + XT := XT or (Ord(PAnsiChar(InputData)[2 + I * 3]) shr 6); + X3 := EnCodeTab64URL[XT]; + XT := (Ord(PAnsiChar(InputData)[2 + I * 3]) and 63); + X4 := EnCodeTab64URL[XT]; + end + else if DataByteLen >= (2 + I * 3) then + begin + X1 := EnCodeTab64URL[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + XT := XT or (Ord(PAnsiChar(InputData)[1 + I * 3]) shr 4); + X2 := EnCodeTab64URL[XT]; + XT := (Ord(PAnsiChar(InputData)[1 + I * 3]) shl 2) and 60; + X3 := EnCodeTab64URL[XT ]; + X4 := '='; + end + else + begin + X1 := EnCodeTab64URL[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + X2 := EnCodeTab64URL[XT]; + X3 := '='; + X4 := '='; + end; + OutputData[I shl 2 + 1] := Char(X1); + OutputData[I shl 2 + 2] := Char(X2); + OutputData[I shl 2 + 3] := Char(X3); + OutputData[I shl 2 + 4] := Char(X4); + end; + end + else + begin + for I := 0 to Times - 1 do + begin + if DataByteLen >= (3 + I * 3) then + begin + X1 := EnCodeTab64[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + XT := XT or (Ord(PAnsiChar(InputData)[1 + I * 3]) shr 4); + X2 := EnCodeTab64[XT]; + XT := (Ord(PAnsiChar(InputData)[1 + I * 3]) shl 2) and 60; + XT := XT or (Ord(PAnsiChar(InputData)[2 + I * 3]) shr 6); + X3 := EnCodeTab64[XT]; + XT := (Ord(PAnsiChar(InputData)[2 + I * 3]) and 63); + X4 := EnCodeTab64[XT]; + end + else if DataByteLen >= (2 + I * 3) then + begin + X1 := EnCodeTab64[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + XT := XT or (Ord(PAnsiChar(InputData)[1 + I * 3]) shr 4); + X2 := EnCodeTab64[XT]; + XT := (Ord(PAnsiChar(InputData)[1 + I * 3]) shl 2) and 60; + X3 := EnCodeTab64[XT ]; + X4 := '='; + end + else + begin + X1 := EnCodeTab64[(Ord(PAnsiChar(InputData)[I * 3]) shr 2)]; + XT := (Ord(PAnsiChar(InputData)[I * 3]) shl 4) and 48; + X2 := EnCodeTab64[XT]; + X3 := '='; + X4 := '='; + end; + OutputData[I shl 2 + 1] := Char(X1); + OutputData[I shl 2 + 2] := Char(X2); + OutputData[I shl 2 + 3] := Char(X3); + OutputData[I shl 2 + 4] := Char(X4); + end; + end; + + OutputData := Trim(OutputData); + if URL then + begin + // ɾ OutputData β = ַ + if (Length(OutputData) > 0) and (OutputData[Length(OutputData)] = '=') then + begin + Delete(OutputData, Length(OutputData), 1); + if (Length(OutputData) > 0) and (OutputData[Length(OutputData)] = '=') then + begin + Delete(OutputData, Length(OutputData), 1); + if (Length(OutputData) > 0) and (OutputData[Length(OutputData)] = '=') then + Delete(OutputData, Length(OutputData), 1); + end; + end; + end; + Result := ECN_BASE64_OK; +end; + +function Base64Encode(InputData: TStream; var OutputData: string; URL: Boolean): Integer; +var + Mem: TMemoryStream; +begin + Mem := TMemoryStream.Create; + try + Mem.CopyFrom(InputData, InputData.Size); + Result := Base64Encode(Mem.Memory, Mem.Size, OutputData, URL); + finally + Mem.Free; + end; +end; + +function Base64Encode(const InputData: AnsiString; var OutputData: string; URL: Boolean): Integer; +begin + if InputData <> '' then + Result := Base64Encode(@InputData[1], Length(InputData), OutputData, URL) + else + Result := ECN_BASE64_LENGTH; +end; + +function Base64Encode(const InputData: TBytes; var OutputData: string; URL: Boolean): Integer; +begin + if Length(InputData) > 0 then + Result := Base64Encode(@InputData[0], Length(InputData), OutputData, URL) + else + Result := ECN_BASE64_LENGTH; +end; + +function Base64Decode(const InputData: string; OutputData: TStream; FixZero: Boolean): Integer; +var + Data: TBytes; +begin + Result := Base64Decode(InputData, Data, FixZero); + if (Result = ECN_BASE64_OK) and (Length(Data) > 0) then + begin + OutputData.Size := Length(Data); + OutputData.Position := 0; + OutputData.Write(Data[0], Length(Data)); + end; +end; + +function Base64Decode(const InputData: string; out OutputData: TBytes; + FixZero: Boolean): Integer; +var + SrcLen, DstLen, Times, I: Integer; + X1, X2, X3, X4, XT: Byte; + C, ToDec: Integer; + Data: AnsiString; + + function FilterLine(const Source: AnsiString): AnsiString; + var + P, PP: PAnsiChar; + I, FL: Integer; + begin + FL := Length(Source); + if FL > 0 then + begin + GetMem(P, FL); // һηڴ,һδַ,һδͷŷڴ + PP := P; + FillChar(P^, FL, 0); + for I := 1 to FL do + begin + if Source[I] in ['0'..'9', 'A'..'Z', 'a'..'z', '+', '/', '=', '-', '_'] then + begin + PP^ := Source[I]; + Inc(PP); + end; + end; + SetString(Result, P, PP - P); // ȡЧ + FreeMem(P); + end; + end; + +begin + if InputData = '' then + begin + Result := ECN_BASE64_OK; + Exit; + end; + OutPutData := nil; + + // D5 ²֪ôIJ AnsiString(InputData)ܻڴֿ + if FilterDecodeInput then + begin +{$IFDEF UNICODE} + Data := FilterLine(AnsiString(InputData)); +{$ELSE} + Data := FilterLine(InputData); +{$ENDIF} + end + else + begin +{$IFDEF UNICODE} + Data := AnsiString(InputData); +{$ELSE} + Data := InputData; +{$ENDIF} + end; + + // Base64URL Ľȥβ =ҪݳǷ 4 ı + if (Length(Data) and $03) <> 0 then + Data := Data + StringOfChar(AnsiChar('='), 4 - (Length(Data) and $03)); + + SrcLen := Length(Data); + DstLen := SrcLen * 3 div 4; + ToDec := 0; + + // βһȺζԭʼݲ˸ #0ȺζŲ #0ҪȥҲ̳ + // עⲻͬԭʼݵβ #0 ȥ + if Data[SrcLen] = '=' then + begin + Inc(ToDec); + if (SrcLen > 1) and (Data[SrcLen - 1] = '=') then + Inc(ToDec); + end; + + SetLength(OutputData, DstLen); // һηڴ,һδַ,һδͷŷڴ + Times := SrcLen div 4; + C := 0; + + for I := 0 to Times - 1 do + begin + X1 := DecodeTable64[Data[1 + I shl 2]]; + X2 := DecodeTable64[Data[2 + I shl 2]]; + X3 := DecodeTable64[Data[3 + I shl 2]]; + X4 := DecodeTable64[Data[4 + I shl 2]]; + X1 := Byte(X1 shl 2); + XT := Byte(X2 shr 4); + X1 := Byte(X1 or XT); + X2 := Byte(X2 shl 4); + OutputData[C] := X1; + Inc(C); + if X3 = 64 then + Break; + XT := Byte(X3 shr 2); + X2 := Byte(X2 or XT); + X3 := Byte(X3 shl 6); + OutputData[C] := X2; + Inc(C); + if X4 = 64 then + Break; + X3 := Byte(X3 or X4); + OutputData[C] := X3; + Inc(C); + end; + + // ݲĵȺĿǷɾβ #0 + while (ToDec > 0) and (OutputData[DstLen - 1] = 0) do + begin + Dec(ToDec); + Dec(DstLen); + end; + SetLength(OutputData, DstLen); + + // ٸⲿҪɾβ #0ʵ̫ʵ + if FixZero then + begin + while (DstLen > 0) and (OutputData[DstLen - 1] = 0) do + Dec(DstLen); + SetLength(OutputData, DstLen); + end; + + Result := ECN_BASE64_OK; +end; + +function Base64Decode(const InputData: string; var OutputData: AnsiString; FixZero: Boolean): Integer; +var + Data: TBytes; +begin + Result := Base64Decode(InputData, Data, FixZero); + if (Result = ECN_BASE64_OK) and (Length(Data) > 0) then + begin + SetLength(OutputData, Length(Data)); + Move(Data[0], OutputData[1], Length(Data)); + end; +end; + +function Base64Decode(const InputData: string; OutputData: Pointer; + DataByteLen: Integer; FixZero: Boolean): Integer; +var + Data: TBytes; +begin + Result := Base64Decode(InputData, Data, FixZero); + if (Result = ECN_BASE64_OK) and (Length(Data) > 0) then + begin + if OutputData = nil then + begin + Result := Length(Data); + Exit; + end; + + if DataByteLen < Length(Data) then + begin + Result := ECN_BASE64_LENGTH; + Exit; + end; + + Move(Data[0], OutPutData^, Length(Data)); + end; +end; + +function Base64IsStrictText(const InputData: string; AllowURLSafe: Boolean): Boolean; +var + I, EqPos: Integer; + Ch: Char; +begin + Result := False; + if InputData = '' then + Exit; + + if AllowURLSafe then + begin + for I := 1 to Length(InputData) do + begin + Ch := InputData[I]; + if not (Ch in ['A'..'Z', 'a'..'z', '0'..'9', '-', '_', '=']) then + Exit; + end; + end + else + begin + for I := 1 to Length(InputData) do + begin + Ch := InputData[I]; + if not (Ch in ['A'..'Z', 'a'..'z', '0'..'9', '+', '/', '=']) then + Exit; + end; + end; + + if (Length(InputData) mod 4) <> 0 then + Exit; + + EqPos := Pos('=', InputData); + if EqPos > 0 then + begin + for I := EqPos to Length(InputData) do + if InputData[I] <> '=' then + Exit; + + if (Length(InputData) - EqPos + 1) > 2 then + Exit; + end; + + Result := True; +end; + +function Base32Encode(InputData: Pointer; DataByteLen: Integer; + var OutputData: string): Integer; +var + Times, I, J, Remain, DataPos, OutPos: Integer; + B0, B1, B2, B3, B4: Byte; + Chars: array[0..7] of Byte; +begin + if (InputData = nil) or (DataByteLen <= 0) then + begin + Result := ECN_BASE32_LENGTH; + Exit; + end; + + Times := DataByteLen div 5; + if (DataByteLen mod 5) <> 0 then + Inc(Times); + + SetLength(OutputData, Times * 8); + FillChar(OutputData[1], Length(OutputData) * SizeOf(Char), 0); + + for I := 0 to Times - 1 do + begin + DataPos := I * 5; + Remain := DataByteLen - DataPos; + if Remain > 5 then + Remain := 5; + + B0 := 0; + B1 := 0; + B2 := 0; + B3 := 0; + B4 := 0; + if Remain > 0 then B0 := Byte(PAnsiChar(InputData)[DataPos]); + if Remain > 1 then B1 := Byte(PAnsiChar(InputData)[DataPos + 1]); + if Remain > 2 then B2 := Byte(PAnsiChar(InputData)[DataPos + 2]); + if Remain > 3 then B3 := Byte(PAnsiChar(InputData)[DataPos + 3]); + if Remain > 4 then B4 := Byte(PAnsiChar(InputData)[DataPos + 4]); + + Chars[0] := (B0 shr 3) and $1F; + Chars[1] := ((B0 and $07) shl 2) or (B1 shr 6); + Chars[2] := (B1 shr 1) and $1F; + Chars[3] := ((B1 and $01) shl 4) or (B2 shr 4); + Chars[4] := ((B2 and $0F) shl 1) or (B3 shr 7); + Chars[5] := (B3 shr 2) and $1F; + Chars[6] := ((B3 and $03) shl 3) or (B4 shr 5); + Chars[7] := B4 and $1F; + + OutPos := I * 8 + 1; + for J := 0 to 7 do + OutputData[OutPos + J] := Char(EnCodeTab32[Chars[J]]); + + case Remain of + 1: + begin + OutputData[OutPos + 2] := '='; + OutputData[OutPos + 3] := '='; + OutputData[OutPos + 4] := '='; + OutputData[OutPos + 5] := '='; + OutputData[OutPos + 6] := '='; + OutputData[OutPos + 7] := '='; + end; + 2: + begin + OutputData[OutPos + 4] := '='; + OutputData[OutPos + 5] := '='; + OutputData[OutPos + 6] := '='; + OutputData[OutPos + 7] := '='; + end; + 3: + begin + OutputData[OutPos + 5] := '='; + OutputData[OutPos + 6] := '='; + OutputData[OutPos + 7] := '='; + end; + 4: + OutputData[OutPos + 7] := '='; + end; + end; + + Result := ECN_BASE32_OK; +end; + +function Base32Encode(InputData: TStream; var OutputData: string): Integer; +var + Mem: TMemoryStream; +begin + Mem := TMemoryStream.Create; + try + Mem.CopyFrom(InputData, InputData.Size); + Result := Base32Encode(Mem.Memory, Mem.Size, OutputData); + finally + Mem.Free; + end; +end; + +function Base32Encode(const InputData: AnsiString; var OutputData: string): Integer; +begin + if InputData <> '' then + Result := Base32Encode(@InputData[1], Length(InputData), OutputData) + else + Result := ECN_BASE32_LENGTH; +end; + +function Base32Encode(const InputData: TBytes; var OutputData: string): Integer; +begin + if Length(InputData) > 0 then + Result := Base32Encode(@InputData[0], Length(InputData), OutputData) + else + Result := ECN_BASE32_LENGTH; +end; + +function Base32Decode(const InputData: string; out OutputData: TBytes): Integer; +var + Data: AnsiString; + SrcLen, Times, I, J, C, PadCnt, DstLen, BlockPad: Integer; + V: array[0..7] of Byte; + Ch: AnsiChar; + + function FilterLine(const Source: AnsiString): AnsiString; + var + P, PP: PAnsiChar; + I, FL: Integer; + C: AnsiChar; + begin + Result := ''; + FL := Length(Source); + if FL > 0 then + begin + GetMem(P, FL); + PP := P; + FillChar(P^, FL, 0); + for I := 1 to FL do + begin + C := Source[I]; + if C in ['a'..'z'] then + C := AnsiChar(Ord(C) - 32); + if C in ['A'..'Z', '2'..'7', '='] then + begin + PP^ := C; + Inc(PP); + end; + end; + SetString(Result, P, PP - P); + FreeMem(P); + end; + end; + + function DecodeChar32(C: AnsiChar; out Value: Byte): Boolean; + begin + if C in ['A'..'Z'] then + begin + Value := Ord(C) - Ord('A'); + Result := True; + Exit; + end; + if C in ['2'..'7'] then + begin + Value := Ord(C) - Ord('2') + 26; + Result := True; + Exit; + end; + Result := False; + end; + +begin + OutPutData := nil; + if InputData = '' then + begin + Result := ECN_BASE32_OK; + Exit; + end; + +{$IFDEF UNICODE} + Data := FilterLine(AnsiString(InputData)); +{$ELSE} + Data := FilterLine(InputData); +{$ENDIF} + + SrcLen := Length(Data); + if (SrcLen = 0) or ((SrcLen mod 8) <> 0) then + begin + Result := ECN_BASE32_LENGTH; + Exit; + end; + +{$IFDEF UNICODE} + if not Base32IsStrictText(string(Data)) then +{$ELSE} + if not Base32IsStrictText(Data) then +{$ENDIF} + begin + Result := ECN_BASE32_LENGTH; + Exit; + end; + + PadCnt := 0; + while (PadCnt < SrcLen) and (Data[SrcLen - PadCnt] = '=') do + Inc(PadCnt); + + DstLen := (SrcLen div 8) * 5; + case PadCnt of + 0: ; + 1: Dec(DstLen, 1); + 3: Dec(DstLen, 2); + 4: Dec(DstLen, 3); + 6: Dec(DstLen, 4); + else + begin + Result := ECN_BASE32_LENGTH; + Exit; + end; + end; + + SetLength(OutputData, DstLen); + Times := SrcLen div 8; + C := 0; + + for I := 0 to Times - 1 do + begin + BlockPad := 0; + for J := 0 to 7 do + begin + Ch := Data[I * 8 + J + 1]; + if Ch = '=' then + begin + V[J] := 0; + Inc(BlockPad); + end + else if DecodeChar32(Ch, V[J]) then + begin + // do nothing + end + else + begin + Result := ECN_BASE32_LENGTH; + Exit; + end; + end; + + OutputData[C] := Byte((V[0] shl 3) or (V[1] shr 2)); + Inc(C); + if BlockPad = 6 then + Continue; + + OutputData[C] := Byte((V[1] shl 6) or (V[2] shl 1) or (V[3] shr 4)); + Inc(C); + if BlockPad = 4 then + Continue; + + OutputData[C] := Byte((V[3] shl 4) or (V[4] shr 1)); + Inc(C); + if BlockPad = 3 then + Continue; + + OutputData[C] := Byte((V[4] shl 7) or (V[5] shl 2) or (V[6] shr 3)); + Inc(C); + if BlockPad = 1 then + Continue; + + OutputData[C] := Byte((V[6] shl 5) or V[7]); + Inc(C); + end; + + Result := ECN_BASE32_OK; +end; + +function Base32Decode(const InputData: string; OutputData: TStream): Integer; +var + Data: TBytes; +begin + Result := Base32Decode(InputData, Data); + if (Result = ECN_BASE32_OK) and (Length(Data) > 0) then + begin + OutputData.Size := Length(Data); + OutputData.Position := 0; + OutputData.Write(Data[0], Length(Data)); + end; +end; + +function Base32Decode(const InputData: string; var OutputData: AnsiString): Integer; +var + Data: TBytes; +begin + Result := Base32Decode(InputData, Data); + if (Result = ECN_BASE32_OK) and (Length(Data) > 0) then + begin + SetLength(OutputData, Length(Data)); + Move(Data[0], OutputData[1], Length(Data)); + end; +end; + +function Base32Decode(const InputData: string; OutputData: Pointer; + DataByteLen: Integer): Integer; +var + Data: TBytes; +begin + Result := Base32Decode(InputData, Data); + if (Result = ECN_BASE32_OK) and (Length(Data) > 0) then + begin + if OutputData = nil then + begin + Result := Length(Data); + Exit; + end; + + if DataByteLen < Length(Data) then + begin + Result := ECN_BASE32_LENGTH; + Exit; + end; + + Move(Data[0], OutPutData^, Length(Data)); + end; +end; + +function Base32IsStrictText(const InputData: string): Boolean; +var + I, EqPos, EC: Integer; + Ch: Char; +begin + Result := False; + if InputData = '' then + Exit; + + for I := 1 to Length(InputData) do + begin + Ch := InputData[I]; + if not (Ch in ['A'..'Z', '2'..'7', '=']) then + Exit; + end; + + if (Length(InputData) mod 8) <> 0 then + Exit; + + EqPos := Pos('=', InputData); + if EqPos > 0 then + begin + for I := EqPos to Length(InputData) do + begin + if InputData[I] <> '=' then + Exit; + end; + + EC := Length(InputData) - EqPos + 1; + if (EC = 2) or (EC = 5) or (EC > 6) then + Exit; + end; + + Result := True; +end; + +end. diff --git a/CnPack/Crypto/CnDES.pas b/CnPack/Crypto/CnDES.pas new file mode 100644 index 0000000..7acfcb4 --- /dev/null +++ b/CnPack/Crypto/CnDES.pas @@ -0,0 +1,1973 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnDES; +{* |
+================================================================================ +* ƣ +* ԪƣDES ԳƼӽ㷨ʵֵԪ +* ԪߣCnPack (master@cnpack.org) +* /ֲ䲿ֹܡ +* עԪʵ DES/3DES ԳƼӽ㷨ֿС 8 ֽڣʵ +* ECB/CBC ģʽ֧ģʽ +* +* ƽ̨PWin2000Pro + Delphi 5.0 +* ݲԣPWin9X/2000/XP + Delphi 5/6 +* õԪеַϱػʽ +* ļ¼2024.11.30 V1.7 +* ɾ淶 DESEncryptStrToHex DESDecryptStrToHex +* ɾ淶 TripleDESEncryptStrToHex TripleDESDecryptStrToHex +* ECB 汾 +* Ż PAnsiChar ʽ Iv Ĵ +* 2024.10.12 V1.6 +* 3DES ²Խ⣬Ż Key Iv Ķ봦 +* 2022.08.13 V1.5 +* Կݼܷؿ +* 2021.02.07 V1.4 +* Ӷ TBytes ֧ +* 2020.03.25 V1.3 +* 3DES ֧ +* 2020.03.24 V1.2 +* ECB/CBC ַӽܺɾԭеַܺ +* 2019.04.15 V1.1 +* ֧ Win32/Win64/MacOS +* 2008.05.30 V1.0 +* Ԫ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes, CnNative; + +const + CN_DES_KEYSIZE = 8; + {* DES Կȣ8 ֽ} + + CN_DES_BLOCKSIZE = 8; + {* DES ļܿ鳤ȣ8 ֽ} + + CN_TRIPLE_DES_KEYSIZE = CN_DES_KEYSIZE * 3; + {* 3DES Կȣ DES 24 ֽ} + + CN_TRIPLE_DES_BLOCKSIZE = CN_DES_BLOCKSIZE; + {* 3DES ļܿ鳤ȣ 8 ֽ} + +type + ECnDESException = class(Exception); + {* DES 쳣} + + TCnDESKey = array[0..CN_DES_KEYSIZE - 1] of Byte; + {* DES ļ Key8 ֽ} + + TCnDESBuffer = array[0..CN_DES_BLOCKSIZE - 1] of Byte; + {* DES ļܿ飬8 ֽ} + + TCnDESIv = array[0..CN_DES_BLOCKSIZE - 1] of Byte; + {* DES CBC ijʼ8 ֽ} + + TCn3DESKey = array[0..CN_TRIPLE_DES_KEYSIZE - 1] of Byte; + {* 3DES Կȣ DES 24 ֽ} + + TCn3DESBuffer = TCnDESBuffer; + {* 3DES ļܿ飬 DES ļܿ飬8 ֽ} + + TCn3DESIv = TCnDESIv; + {* 3DES CBC ijʼ DES CBC ijʼ8 ֽ} + +// ================================= DES ======================================= + +function DESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +{* ֽڳȼ DES ȡǿ + + + InputByteLength: Integer - ֽڳ + + ֵInteger - DES ij +} + +procedure DESEncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +{* AnsiString DES ܣʹ ECB ģʽ + + + Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure DESDecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +{* AnsiString DES ܣʹ ECB ģʽ + + + Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure DESEncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; const Input: AnsiString; + Output: PAnsiChar); +{* AnsiString DES ܣʹ CBC ģʽ + + + Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + Iv: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure DESDecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; const Input: AnsiString; + Output: PAnsiChar); +{* AnsiString DES ܣʹ CBC ģʽ + + + Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + Iv: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +function DESEncryptEcbStrToHex(const Str: AnsiString; const Key: AnsiString): AnsiString; +{* KeyDES ܷתʮƵģʹ ECB ģʽĩβܲ #0 + + + const Str: AnsiString - ַܵ + const Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + + ֵAnsiString - ؼܺʮַ +} + +function DESDecryptEcbStrFromHex(const HexStr: AnsiString; const Key: AnsiString): AnsiString; +{* ʮƵ KeyDES ܷģʹ ECB ģʽ + + + const HexStr: AnsiString - ܵʮַ + const Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + + ֵAnsiString - ؽַܺ +} + +function DESEncryptCbcStrToHex(const Str: AnsiString; const Key: AnsiString; const Iv: AnsiString): AnsiString; +{* Key IvDES ܷתʮƵģʹ CBC ģʽĩβܲ #0 + + + const Str: AnsiString - ַܵ + const Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + const Iv: AnsiString - 8 ֽڳʼ + + ֵAnsiString - ؼܺʮַ +} + +function DESDecryptCbcStrFromHex(const HexStr: AnsiString; const Key: AnsiString; + const Iv: AnsiString): AnsiString; +{* ʮƵ Key IvDES ܷģʹ ECB ģʽ + + + const HexStr: AnsiString - ܵʮַ + const Key: AnsiString - 8 ֽ DES Կ̫ضϣ #0 + const Iv: AnsiString - 8 ֽڳʼ + + ֵAnsiString - ؽַܺ +} + +function DESEncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +{* ֽ DES ܣʹ ECB ģʽ + + + Key: TBytes - 8 ֽ DES Կ̫ضϣ 0 + Input: TBytes - ֽܵ飬䳤粻 8 ʱᱻ 0 ȴﵽ 8 ı + + ֵTBytes - ؼֽܺ +} + +function DESDecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +{* ֽ DES ܣʹ ECB ģʽ + + + Key: TBytes - 8 ֽ DES Կ̫ضϣ 0 + Input: TBytes - ֽܵ飬䳤粻 8 ʱᱻ 0 ȴﵽ 8 ı + + ֵTBytes - ؽֽܺ +} + +function DESEncryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ DES ܣʹ CBC ģʽ + + + Key: TBytes - 8 ֽ DES Կ̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؼֽܺ +} + +function DESDecryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ DES ܣʹ CBC ģʽ + + + Key: TBytes - 8 ֽ DES Կ̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؽֽܺ +} + +procedure DESEncryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; Dest: TStream); overload; +{* DES ܣʹ ECB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 8 ֽ DES Կ + Dest: TStream - + + ֵޣ +} + +procedure DESDecryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; Dest: TStream); overload; +{* DES ܣʹ ECB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 8 ֽ DES Կ + Dest: TStream - + + ֵޣ +} + +procedure DESEncryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +{* DES ܣʹ CBC ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 8 ֽ DES Կ + const InitVector: TCnDESIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure DESDecryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +{* DES ܣʹ CBC ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 8 ֽ DES Կ + const InitVector: TCnDESIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// =========================== 3-DES (Triple DES) ============================== + +function TripleDESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +{* ֽڳȼȡǿ + + + InputByteLength: Integer - ֽڳ + + ֵInteger - 3DES ֽڳ +} + +procedure TripleDESEncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +{* AnsiString 3DES ܣʹ ECB ģʽ + + + Key: AnsiString - 24ֽ 3DES Կ̫ضϣ #0 + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure TripleDESDecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +{* AnsiString 3DES ܣʹ ECB ģʽ + + + Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure TripleDESEncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString 3DES ܣʹ CBC ģʽ + + + Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + Iv: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +procedure TripleDESDecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString 3DES ܣʹ CBC ģʽ + + + Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + Iv: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ + const Input: AnsiString - ַܵ䳤粻 8 ʱᱻ #0 ȴﵽ 8 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 8) + 1) * 8 + + ֵޣ +} + +function TripleDESEncryptEcbStrToHex(const Str: AnsiString; const Key: AnsiString): AnsiString; +{* Key3DES ܷתʮƵģʹ ECB ģʽĩβܲ #0 + + + const Str: AnsiString - ַܵ + const Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + + ֵAnsiString - ؼܺʮַ +} + +function TripleDESDecryptEcbStrFromHex(const HexStr: AnsiString; const Key: AnsiString): AnsiString; +{* ʮƵ Key3DES ܷģʹ ECB ģʽ + + + const HexStr: AnsiString - ܵʮַ + const Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + + ֵAnsiString - ؽַܺ +} + +function TripleDESEncryptCbcStrToHex(const Str: AnsiString; const Key: AnsiString; + const Iv: AnsiString): AnsiString; +{* Key Iv3DES ܷתʮƵģʹ CBC ģʽĩβܲ #0 + + + const Str: AnsiString - ַܵ + const Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + const Iv: AnsiString - 8 ֽڳʼ + + ֵAnsiString - ؼܺʮַ +} + +function TripleDESDecryptCbcStrFromHex(const HexStr: AnsiString; + const Key: AnsiString; const Iv: AnsiString): AnsiString; +{* ʮƵ Key Iv3DES ܷģʹ CBC ģʽ + + + const HexStr: AnsiString - ܵʮַ + const Key: AnsiString - 24 ֽ 3DES Կ̫ضϣ #0 + const Iv: AnsiString - 8 ֽڳʼ + + ֵAnsiString - ؽַܺ +} + +function TripleDESEncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +{* ֽ 3DES ܣʹ ECB ģʽ + + + Key: TBytes - 24 ֽ 3DES Կ̫ضϣ 0 + Input: TBytes - ֽܵ飬䳤粻 8 ʱᱻ 0 ȴﵽ 8 ı + + ֵTBytes - ؼֽܺ +} + +function TripleDESDecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +{* ֽ 3DES ܣʹ ECB ģʽ + + + Key: TBytes - 24 ֽ 3DES Կ̫ضϣ 0 + Input: TBytes - ֽܵ飬䳤粻 8 ʱᱻ 0 ȴﵽ 8 ı + + ֵTBytes - ؽֽܺ +} + +function TripleDESEncryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ 3DES ܣʹ CBC ģʽ + + + Key: TBytes - 24 ֽ 3DES Կ̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؼֽܺ +} + +function TripleDESDecryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ 3DES ܣʹ CBC ģʽ + + + Key: TBytes - 24 ֽ 3DES Կ̫ضϣ 0 + Iv: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؽֽܺ +} + +procedure TripleDESEncryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; Dest: TStream); overload; +{* 3DES ܣʹ ECB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 24 ֽ 3DES Կ + Dest: TStream - + + ֵޣ +} + +procedure TripleDESDecryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; Dest: TStream); overload; +{* 3DES ܣʹ ECB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnDESKey - 24 ֽ 3DES Կ + Dest: TStream - + + ֵޣ +} + +procedure TripleDESEncryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +{* 3DES ܣʹ CBC ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCn3DESKey - 24 ֽ 3DES Կ + const InitVector: TCnDESIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure TripleDESDecryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +{* 3DES ܣʹ CBC ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCn3DESKey - 24 ֽ 3DES Կ + const InitVector: TCnDESIv - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +implementation + +resourcestring + SCnErrorDESInvalidInBufSize = 'Invalid Buffer Size for Decryption'; + SCnErrorDESReadError = 'Stream Read Error'; + SCnErrorDESWriteError = 'Stream Write Error'; + +type + TKeyByte = array[0..5] of Byte; + TDesMode = (dmEncry, dmDecry); + TSubKey = array[0..15] of TKeyByte; + +const + BitIP: array[0..63] of Byte = + (57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7, + 56, 48, 40, 32, 24, 16, 8, 0, + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6); + + BitCP: array[0..63] of Byte = + (39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25, + 32, 0, 40, 8, 48, 16, 56, 24); + + BitExp: array[0..47] of Integer = + (31, 0, 1, 2, 3, 4, 3, 4, 5, 6, 7, 8, 7, 8, 9, 10, + 11, 12, 11, 12, 13, 14, 15, 16, 15, 16, 17, 18, 19, 20, 19, 20, + 21, 22, 23, 24, 23, 24, 25, 26, 27, 28, 27, 28, 29, 30, 31, 0); + + BitPM: array[0..31] of Byte = + (15, 6, 19, 20, 28, 11, 27, 16, 0, 14, 22, 25, 4, 17, 30, 9, + 1, 7, 23, 13, 31, 26, 2, 8, 18, 12, 29, 5, 21, 10, 3, 24); + + sBox: array[0..7] of array[0..63] of Byte = + ((14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13), + + (15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9), + + (10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12), + + (7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14), + + (2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3), + + (12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13), + + (4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12), + + (13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11)); + + BitPMC1: array[0..55] of Byte = + (56, 48, 40, 32, 24, 16, 8, + 0, 57, 49, 41, 33, 25, 17, + 9, 1, 58, 50, 42, 34, 26, + 18, 10, 2, 59, 51, 43, 35, + 62, 54, 46, 38, 30, 22, 14, + 6, 61, 53, 45, 37, 29, 21, + 13, 5, 60, 52, 44, 36, 28, + 20, 12, 4, 27, 19, 11, 3); + + BitPMC2: array[0..47] of Byte = + (13, 16, 10, 23, 0, 4, + 2, 27, 14, 5, 20, 9, + 22, 18, 11, 3, 25, 7, + 15, 6, 26, 19, 12, 1, + 40, 51, 30, 36, 46, 54, + 29, 39, 50, 44, 32, 47, + 43, 48, 38, 55, 33, 52, + 45, 41, 49, 35, 28, 31); + +function Min(A, B: Integer): Integer; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + if A < B then + Result := A + else + Result := B; +end; + +procedure InitPermutation(var InData: array of Byte); +var + NewData: array[0..7] of Byte; + I: Integer; +begin + FillChar(NewData, 8, 0); + for I := 0 to 63 do + if (InData[BitIP[I] shr 3] and (1 shl (7 - (BitIP[I] and $07)))) <> 0 then + NewData[I shr 3] := NewData[I shr 3] or (1 shl (7 - (I and $07))); + for I := 0 to 7 do InData[I] := NewData[I]; +end; + +procedure ConversePermutation(var InData: array of Byte); +var + NewData: array[0..7] of Byte; + I: Integer; +begin + FillChar(NewData, 8, 0); + for I := 0 to 63 do + if (InData[BitCP[I] shr 3] and (1 shl (7 - (BitCP[I] and $07)))) <> 0 then + NewData[I shr 3] := NewData[I shr 3] or (1 shl (7 - (I and $07))); + for I := 0 to 7 do InData[I] := NewData[I]; +end; + +procedure Expand(const InData: array of Byte; var OutData: array of Byte); +var + I: Integer; +begin + FillChar(OutData, 6, 0); + for I := 0 to 47 do + if (InData[BitExp[I] shr 3] and (1 shl (7 - (BitExp[I] and $07)))) <> 0 then + OutData[I shr 3] := OutData[I shr 3] or (1 shl (7 - (I and $07))); +end; + +procedure Permutation(var InData: array of Byte); +var + NewData: array[0..3] of Byte; + I: Integer; +begin + FillChar(NewData, 4, 0); + for I := 0 to 31 do + if (InData[BitPM[I] shr 3] and (1 shl (7 - (BitPM[I] and $07)))) <> 0 then + NewData[I shr 3] := NewData[I shr 3] or (1 shl (7 - (I and $07))); + for I := 0 to 3 do InData[I] := NewData[I]; +end; + +function Si(S, InByte: Byte): Byte; +var + c: Byte; +begin + c := (InByte and $20) or ((InByte and $1E) shr 1) or + ((InByte and $01) shl 4); + Result := (sBox[S][c] and $0F); +end; + +procedure PermutationChoose1(const InData: array of Byte; var OutData: array of Byte); +var + I: Integer; +begin + FillChar(OutData, 7, 0); + for I := 0 to 55 do + if (InData[BitPMC1[I] shr 3] and (1 shl (7 - (BitPMC1[I] and $07)))) <> 0 then + OutData[I shr 3] := OutData[I shr 3] or (1 shl (7 - (I and $07))); +end; + +procedure PermutationChoose2(const InData: array of Byte; var OutData: array of Byte); +var + I: Integer; +begin + FillChar(OutData, 6, 0); + for I := 0 to 47 do + if (InData[BitPMC2[I] shr 3] and (1 shl (7 - (BitPMC2[I] and $07)))) <> 0 then + OutData[I shr 3] := OutData[I shr 3] or (1 shl (7 - (I and $07))); +end; + +procedure CycleMove(var InData: array of Byte; BitMove: Byte); +var + I: Integer; +begin + for I := 0 to BitMove - 1 do + begin + InData[0] := Byte((InData[0] shl 1) or (InData[1] shr 7)); + InData[1] := Byte((InData[1] shl 1) or (InData[2] shr 7)); + InData[2] := Byte((InData[2] shl 1) or (InData[3] shr 7)); + InData[3] := Byte((InData[3] shl 1) or ((InData[0] and $10) shr 4)); + InData[0] := Byte((InData[0] and $0F)); + end; +end; + +procedure MakeKey(const InKey: array of Byte; var OutKey: array of TKeyByte); +const + bitDisplace: array[0..15] of Byte = + (1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1); +var + OutData56: array[0..6] of Byte; + Key28l: array[0..3] of Byte; + Key28r: array[0..3] of Byte; + Key56o: array[0..6] of Byte; + I: Integer; +begin + PermutationChoose1(InKey, OutData56); + Key28l[0] := Byte(OutData56[0] shr 4); + Key28l[1] := Byte((OutData56[0] shl 4) or (OutData56[1] shr 4)); + Key28l[2] := Byte((OutData56[1] shl 4) or (OutData56[2] shr 4)); + Key28l[3] := Byte((OutData56[2] shl 4) or (OutData56[3] shr 4)); + Key28r[0] := Byte(OutData56[3] and $0F); + Key28r[1] := Byte(OutData56[4]); + Key28r[2] := Byte(OutData56[5]); + Key28r[3] := Byte(OutData56[6]); + for I := 0 to 15 do + begin + CycleMove(Key28l, bitDisplace[I]); + CycleMove(Key28r, bitDisplace[I]); + Key56o[0] := Byte((Key28l[0] shl 4) or (Key28l[1] shr 4)); + Key56o[1] := Byte((Key28l[1] shl 4) or (Key28l[2] shr 4)); + Key56o[2] := Byte((Key28l[2] shl 4) or (Key28l[3] shr 4)); + Key56o[3] := Byte((Key28l[3] shl 4) or (Key28r[0])); + Key56o[4] := Byte(Key28r[1]); + Key56o[5] := Byte(Key28r[2]); + Key56o[6] := Byte(Key28r[3]); + PermutationChoose2(Key56o, OutKey[I]); + end; +end; + +procedure Encry(const InData, ASubKey: array of Byte; var OutData: array of Byte); +var + OutBuf: array[0..5] of Byte; + Buf: array[0..7] of Byte; + I: Integer; +begin + Expand(InData, OutBuf); + for I := 0 to 5 do OutBuf[I] := OutBuf[I] xor ASubKey[I]; + Buf[0] := OutBuf[0] shr 2; + Buf[1] := ((OutBuf[0] and $03) shl 4) or (OutBuf[1] shr 4); + Buf[2] := ((OutBuf[1] and $0F) shl 2) or (OutBuf[2] shr 6); + Buf[3] := OutBuf[2] and $3F; + Buf[4] := OutBuf[3] shr 2; + Buf[5] := ((OutBuf[3] and $03) shl 4) or (OutBuf[4] shr 4); + Buf[6] := ((OutBuf[4] and $0F) shl 2) or (OutBuf[5] shr 6); + Buf[7] := OutBuf[5] and $3F; + for I := 0 to 7 do Buf[I] := si(I, Buf[I]); + for I := 0 to 3 do OutBuf[I] := (Buf[I * 2] shl 4) or Buf[I * 2 + 1]; + Permutation(OutBuf); + for I := 0 to 3 do OutData[I] := OutBuf[I]; +end; + +// InData OutData Ҫ 8 ֽ +procedure DesData(DesMode: TDesMode; SubKey: TSubKey; const InData: array of Byte; + var OutData: array of Byte); +var + I, J: Integer; + Temp, Buf: array[0..3] of Byte; +begin + for I := 0 to 7 do OutData[I] := InData[I]; + InitPermutation(OutData); + if DesMode = dmEncry then + begin + for I := 0 to 15 do + begin + for J := 0 to 3 do Temp[J] := OutData[J]; + for J := 0 to 3 do OutData[J] := OutData[J + 4]; + Encry(OutData, SubKey[I], Buf); + for J := 0 to 3 do OutData[J + 4] := Temp[J] xor Buf[J]; + end; + for J := 0 to 3 do Temp[J] := OutData[J + 4]; + for J := 0 to 3 do OutData[J + 4] := OutData[J]; + for J := 0 to 3 do OutData[J] := Temp[J]; + end + else if DesMode = dmDecry then + begin + for I := 15 downto 0 do + begin + for J := 0 to 3 do Temp[J] := OutData[J]; + for J := 0 to 3 do OutData[J] := OutData[J + 4]; + Encry(OutData, SubKey[I], Buf); + for J := 0 to 3 do OutData[J + 4] := Temp[J] xor Buf[J]; + end; + for J := 0 to 3 do Temp[J] := OutData[J + 4]; + for J := 0 to 3 do OutData[J + 4] := OutData[J]; + for J := 0 to 3 do OutData[J] := Temp[J]; + end; + ConversePermutation(OutData); +end; + +// Key #0 ճ 8 ֽ +procedure MakeKeyAlign(var Key: AnsiString); +begin + if Length(Key) < CN_DES_KEYSIZE then + while Length(Key) < CN_DES_KEYSIZE do + Key := Key + Chr(0); +end; + +// ַ #0 ճ 8 ıעմ +procedure MakeInputAlign(var Str: AnsiString); +begin + while Length(Str) mod CN_DES_KEYSIZE <> 0 do + Str := Str + Chr(0); +end; + +// ֽ鲹 0 ճ 8 ıע鲻 +procedure MakeInputBytesAlign(var Input: TBytes); +var + I, Len, NL: Integer; +begin + Len := Length(Input); + if Len mod CN_DES_BLOCKSIZE <> 0 then + begin + NL := ((Len div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE; + SetLength(Input, NL); + for I := Len to NL - 1 do + Input[I] := 0; + end; +end; + +function DESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +begin + Result := (((InputByteLength - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE; +end; + +procedure DESEncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + Str: AnsiString; + I: Integer; + SubKey: TSubKey; +begin + MakeKeyAlign(Key); + + Str := Input; + MakeInputAlign(Str); // Str 8 ı + + if Str = '' then // մֱӷؿ + begin + if Output <> nil then + Output[0] := #0; + Exit; + end; + + Move(Key[1], KeyByte[0], SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + for I := 0 to Length(Str) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Str[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + DesData(dmEncry, SubKey, StrByte, OutByte); + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +procedure DESDecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + I: Integer; + SubKey: TSubKey; +begin + MakeKeyAlign(Key); + Move(Key[1], KeyByte[0], SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + DesData(dmDecry, SubKey, StrByte, OutByte); + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; + + // ĩβ 0 ⲿжɾ +end; + +procedure DESEncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + Vector: TCnDESIv; + Str: AnsiString; + I: Integer; + SubKey: TSubKey; +begin + MakeKeyAlign(Key); + + Str := Input; + MakeInputAlign(Str); + + if Str = '' then // մֱӷؿ + begin + if Output <> nil then + Output[0] := #0; + Exit; + end; + + Move(Key[1], KeyByte[0], SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + Move(Iv^, Vector[0], SizeOf(TCnDESIv)); + + for I := 0 to Length(Str) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Str[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + + // CBC ݿֵȸ Iv + PCardinal(@StrByte[0])^ := PCardinal(@StrByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@StrByte[4])^ := PCardinal(@StrByte[4])^ xor PCardinal(@Vector[4])^; + + // ټ + DesData(dmEncry, SubKey, StrByte, OutByte); + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ܽµ Iv + Move(OutByte[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +procedure DESDecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + Vector, TV: TCnDESIv; + I: Integer; + SubKey: TSubKey; +begin + MakeKeyAlign(Key); + Move(Key[1], KeyByte[0], SizeOf(TCnDESKey)); + + MakeKey(KeyByte, SubKey); + Move(Iv^, Vector[0], SizeOf(TCnDESIv)); + + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + Move(StrByte[0], TV[0], SizeOf(TCnDESIv)); // ȴһ + + // Ƚ + DesData(dmDecry, SubKey, StrByte, OutByte); + + // CBC ݿֵܺٸ Iv + PCardinal(@OutByte[0])^ := PCardinal(@OutByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@OutByte[4])^ := PCardinal(@OutByte[4])^ xor PCardinal(@Vector[4])^; + + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ĸµ Iv + Move(TV[0], Vector[0], SizeOf(TCnDESIv)); + end; + + // ĩβ 0 ⲿжɾ +end; + +procedure SetResultLengthUsingInput(const Str: AnsiString; var Res: AnsiString); +var + Len: Integer; +begin + Len := Length(Str); + if Len < CN_DES_BLOCKSIZE then + Len := CN_DES_BLOCKSIZE + else + Len := (((Len - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE; + SetLength(Res, Len); +end; + +function DESEncryptEcbStrToHex(const Str, Key: AnsiString): AnsiString; +var + TempResult: AnsiString; +begin + Result := ''; + if Str = '' then + Exit; + + SetResultLengthUsingInput(Str, TempResult); + DESEncryptEcbStr(Key, Str, @TempResult[1]); + Result := AnsiStrToHex(TempResult); +end; + +function DESDecryptEcbStrFromHex(const HexStr, Key: AnsiString): AnsiString; +var + Str: AnsiString; +begin + Str := HexToAnsiStr(HexStr); + SetResultLengthUsingInput(Str, Result); + DESDecryptEcbStr(Key, Str, @(Result[1])); +end; + +function DESEncryptCbcStrToHex(const Str, Key, Iv: AnsiString): AnsiString; +var + TempResult: AnsiString; +begin + Result := ''; + if Str = '' then + Exit; + + SetResultLengthUsingInput(Str, TempResult); + DESEncryptCbcStr(Key, PAnsiChar(Iv), Str, @TempResult[1]); + Result := AnsiStrToHex(TempResult); +end; + +function DESDecryptCbcStrFromHex(const HexStr, Key, Iv: AnsiString): AnsiString; +var + Str: AnsiString; +begin + Str := HexToAnsiStr(HexStr); + SetResultLengthUsingInput(Str, Result); + DESDecryptCbcStr(Key, PAnsiChar(Iv), Str, @(Result[1])); +end; + +function DESEncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + I: Integer; + SubKey: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + MakeInputBytesAlign(Input); + + FillChar(KeyByte[0], SizeOf(TCnDESKey), 0); + MoveMost(Key[0], KeyByte[0], Length(Key), SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + DesData(dmEncry, SubKey, StrByte, OutByte); + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +function DESDecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + I: Integer; + SubKey: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + FillChar(KeyByte[0], SizeOf(TCnDESKey), 0); + MoveMost(Key[0], KeyByte[0], Length(Key), SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + DesData(dmDecry, SubKey, StrByte, OutByte); + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +function DESEncryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + Vector: TCnDESIv; + I: Integer; + SubKey: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + MakeInputBytesAlign(Input); + + FillChar(KeyByte[0], SizeOf(TCnDESKey), 0); + MoveMost(Key[0], KeyByte[0], Length(Key), SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + FillChar(Vector[0], SizeOf(TCnDESIv), 0); + MoveMost(Iv[0], Vector[0], Length(Iv), SizeOf(TCnDESIv)); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + + // CBC ݿֵȸ Iv + PCardinal(@StrByte[0])^ := PCardinal(@StrByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@StrByte[4])^ := PCardinal(@StrByte[4])^ xor PCardinal(@Vector[4])^; + + // ټ + DesData(dmEncry, SubKey, StrByte, OutByte); + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ܽµ Iv + Move(OutByte[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +function DESDecryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + KeyByte: TCnDESKey; + Vector, TV: TCnDESIv; + I: Integer; + SubKey: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + FillChar(KeyByte[0], SizeOf(TCnDESKey), 0); + MoveMost(Key[0], KeyByte[0], Length(Key), SizeOf(TCnDESKey)); + MakeKey(KeyByte, SubKey); + + FillChar(Vector[0], SizeOf(TCnDESIv), 0); + MoveMost(Iv[0], Vector[0], Length(Iv), SizeOf(TCnDESIv)); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + Move(StrByte[0], TV[0], SizeOf(TCnDESIv)); // ȴһ + + // Ƚ + DesData(dmDecry, SubKey, StrByte, OutByte); + + // CBC ݿֵܺٸ Iv + PCardinal(@OutByte[0])^ := PCardinal(@OutByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@OutByte[4])^ := PCardinal(@OutByte[4])^ xor PCardinal(@Vector[4])^; + + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ĸµ Iv + Move(TV[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +procedure DESEncryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; Dest: TStream); overload; +var + TempIn, TempOut: TCnDESBuffer; + Done: Cardinal; + SubKey: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + MakeKey(Key, SubKey); + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + DesData(dmEncry, SubKey, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Dec(Count, SizeOf(TCnDESBuffer)); + end; + + if Count > 0 then // β 0 + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorDESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + + DesData(dmEncry, SubKey, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + end; +end; + +procedure DESDecryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; Dest: TStream); overload; +var + TempIn, TempOut: TCnDESBuffer; + Done: Cardinal; + SubKey: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + if (Count mod SizeOf(TCnDESBuffer)) > 0 then + raise ECnDESException.Create(SCnErrorDESInvalidInBufSize); + + MakeKey(Key, SubKey); + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + DesData(dmDecry, SubKey, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Dec(Count, SizeOf(TCnDESBuffer)); + end; +end; + +procedure DESEncryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +var + TempIn, TempOut: TCnDESBuffer; + Vector: TCnDESIv; + Done: Cardinal; + SubKey: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + MakeKey(Key, SubKey); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + + DesData(dmEncry, SubKey, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Move(TempOut[0], Vector[0], SizeOf(TCnDESIv)); + Dec(Count, SizeOf(TCnDESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorDESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + + DesData(dmEncry, SubKey, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + end; +end; + +procedure DESDecryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnDESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +var + TempIn, TempOut: TCnDESBuffer; + Vector1, Vector2: TCnDESIv; + Done: Cardinal; + SubKey: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + if (Count mod SizeOf(TCnDESBuffer)) > 0 then + raise ECnDESException.Create(SCnErrorDESInvalidInBufSize); + + Vector1 := InitVector; + MakeKey(Key, SubKey); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorDESReadError); + + Move(TempIn[0], Vector2[0], SizeOf(TCnDESIv)); + DesData(dmDecry, SubKey, TempIn, TempOut); + + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorDESWriteError); + + Vector1 := Vector2; + Dec(Count, SizeOf(TCnDESBuffer)); + end; +end; + +procedure Make3DESKeys(Keys: AnsiString; var K1, K2, K3: TCnDESKey); overload; +var + I: Integer; +begin + if Length(Keys) < CN_TRIPLE_DES_KEYSIZE then + while Length(Keys) < CN_TRIPLE_DES_KEYSIZE do + Keys := Keys + Chr(0); + + for I := 0 to CN_DES_KEYSIZE - 1 do + begin + K1[I] := Ord(Keys[I + 1]); + K2[I] := Ord(Keys[I + 1 + CN_DES_KEYSIZE]); + K3[I] := Ord(Keys[I + 1 + CN_DES_KEYSIZE * 2]); + end; +end; + +procedure Make3DESKeys(Keys: TCn3DESKey; var K1, K2, K3: TCnDESKey); overload; +var + I: Integer; +begin + for I := 0 to CN_DES_KEYSIZE - 1 do + begin + K1[I] := Keys[I]; + K2[I] := Keys[I + CN_DES_KEYSIZE]; + K3[I] := Keys[I + CN_DES_KEYSIZE * 2]; + end; +end; + +procedure Make3DESKeys(Keys: TBytes; var K1, K2, K3: TCnDESKey); overload; +var + I, Len: Integer; +begin + Len := Length(Keys); + if Len < CN_TRIPLE_DES_KEYSIZE then + begin + SetLength(Keys, CN_TRIPLE_DES_KEYSIZE); + for I := Len to CN_TRIPLE_DES_KEYSIZE - 1 do + Keys[I] := 0; + end; + + for I := 0 to CN_DES_KEYSIZE - 1 do + begin + K1[I] := Ord(Keys[I]); + K2[I] := Ord(Keys[I + CN_DES_KEYSIZE]); + K3[I] := Ord(Keys[I + CN_DES_KEYSIZE * 2]); + end; +end; + +function TripleDESGetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +begin + Result := (((InputByteLength - 1) div CN_TRIPLE_DES_BLOCKSIZE) + 1) * CN_TRIPLE_DES_BLOCKSIZE; +end; + +procedure TripleDESEncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + Str: AnsiString; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + Str := Input; + MakeInputAlign(Str); + + if Str = '' then // մֱӷؿ + begin + if Output <> nil then + Output[0] := #0; + Exit; + end; + + for I := 0 to Length(Str) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Str[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + + DesData(dmEncry, SubKey1, StrByte, OutByte); + DesData(dmDecry, SubKey2, OutByte, StrByte); + DesData(dmEncry, SubKey3, StrByte, OutByte); + + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +procedure TripleDESDecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + + DesData(dmDecry, SubKey3, StrByte, OutByte); + DesData(dmEncry, SubKey2, OutByte, StrByte); + DesData(dmDecry, SubKey1, StrByte, OutByte); + + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; + + // ĩβ 0 ⲿжɾ +end; + +procedure TripleDESEncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + Vector: TCnDESIv; + Str: AnsiString; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + Str := Input; + MakeInputAlign(Str); + + if Str = '' then // մֱӷؿ + begin + if Output <> nil then + Output[0] := #0; + Exit; + end; + + Move(Iv^, Vector[0], SizeOf(TCnDESIv)); + + for I := 0 to Length(Str) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Str[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + + // CBC ݿֵȸ Iv + PCardinal(@StrByte[0])^ := PCardinal(@StrByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@StrByte[4])^ := PCardinal(@StrByte[4])^ xor PCardinal(@Vector[4])^; + + // ټ + DesData(dmEncry, SubKey1, StrByte, OutByte); + DesData(dmDecry, SubKey2, OutByte, StrByte); + DesData(dmEncry, SubKey3, StrByte, OutByte); + + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ܽµ Iv + Move(OutByte[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +procedure TripleDESDecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + Vector, TV: TCnDESIv; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + Move(Iv^, Vector[0], SizeOf(TCnDESIv)); + + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE + 1], StrByte[0], SizeOf(TCnDESBuffer)); + Move(StrByte[0], TV[0], SizeOf(TCnDESIv)); // ȴһ + + // Ƚ + DesData(dmDecry, SubKey3, StrByte, OutByte); + DesData(dmEncry, SubKey2, OutByte, StrByte); + DesData(dmDecry, SubKey1, StrByte, OutByte); + + // CBC ݿֵܺٸ Iv + PCardinal(@OutByte[0])^ := PCardinal(@OutByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@OutByte[4])^ := PCardinal(@OutByte[4])^ xor PCardinal(@Vector[4])^; + + Move(OutByte[0], Output[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ĸµ Iv + Move(TV[0], Vector[0], SizeOf(TCnDESIv)); + end; + + // ĩβ 0 ⲿжɾ +end; + +function TripleDESEncryptEcbStrToHex(const Str, Key: AnsiString): AnsiString; +var + TempResult, Temp: AnsiString; + I: Integer; +begin + SetResultLengthUsingInput(Str, TempResult); + TripleDESEncryptEcbStr(Key, Str, @TempResult[1]); + + Result := ''; + for I := 0 to Length(TempResult) - 1 do + begin + Temp := AnsiString(Format('%x', [Ord(TempResult[I + 1])])); + if Length(Temp) = 1 then + Temp := '0' + Temp; + Result := Result + Temp; + end; +end; + +function TripleDESDecryptEcbStrFromHex(const HexStr, Key: AnsiString): AnsiString; +var + Str: AnsiString; +begin + Str := HexToAnsiStr(HexStr); + SetResultLengthUsingInput(Str, Result); + TripleDESDecryptEcbStr(Key, Str, @(Result[1])); +end; + +function TripleDESEncryptCbcStrToHex(const Str, Key, Iv: AnsiString): AnsiString; +var + TempResult, Temp: AnsiString; + I: Integer; +begin + SetResultLengthUsingInput(Str, TempResult); + TripleDESEncryptCbcStr(Key, PAnsiChar(Iv), Str, @TempResult[1]); + + Result := ''; + for I := 0 to Length(TempResult) - 1 do + begin + Temp := AnsiString(Format('%x', [Ord(TempResult[I + 1])])); + if Length(Temp) = 1 then + Temp := '0' + Temp; + Result := Result + Temp; + end; +end; + +function TripleDESDecryptCbcStrFromHex(const HexStr, Key, Iv: AnsiString): AnsiString; +var + Str: AnsiString; +begin + Str := HexToAnsiStr(HexStr); + SetResultLengthUsingInput(Str, Result); + TripleDESDecryptCbcStr(Key, PAnsiChar(Iv), Str, @(Result[1])); +end; + +function TripleDESEncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + MakeInputBytesAlign(Input); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + + DesData(dmEncry, SubKey1, StrByte, OutByte); + DesData(dmDecry, SubKey2, OutByte, StrByte); + DesData(dmEncry, SubKey3, StrByte, OutByte); + + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +function TripleDESDecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + + DesData(dmDecry, SubKey3, StrByte, OutByte); + DesData(dmEncry, SubKey2, OutByte, StrByte); + DesData(dmDecry, SubKey1, StrByte, OutByte); + + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + end; +end; + +function TripleDESEncryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + Vector: TCnDESIv; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + MakeInputBytesAlign(Input); + FillChar(Vector[0], SizeOf(TCnDESIv), 0); + MoveMost(Iv[0], Vector[0], Length(Iv), SizeOf(TCnDESIv)); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + + // CBC ݿֵȸ Iv + PCardinal(@StrByte[0])^ := PCardinal(@StrByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@StrByte[4])^ := PCardinal(@StrByte[4])^ xor PCardinal(@Vector[4])^; + + // ټ + DesData(dmEncry, SubKey1, StrByte, OutByte); + DesData(dmDecry, SubKey2, OutByte, StrByte); + DesData(dmEncry, SubKey3, StrByte, OutByte); + + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ܽµ Iv + Move(OutByte[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +function TripleDESDecryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +var + StrByte, OutByte: TCnDESBuffer; + K1, K2, K3: TCnDESKey; + Vector, TV: TCnDESIv; + I: Integer; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Length(Input) <= 0 then + begin + Result := nil; + Exit; + end; + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + FillChar(Vector[0], SizeOf(TCnDESIv), 0); + MoveMost(Iv[0], Vector[0], Length(Iv), SizeOf(TCnDESIv)); + + SetLength(Result, (((Length(Input) - 1) div CN_DES_BLOCKSIZE) + 1) * CN_DES_BLOCKSIZE); + for I := 0 to Length(Input) div CN_DES_BLOCKSIZE - 1 do + begin + Move(Input[I * CN_DES_BLOCKSIZE], StrByte[0], SizeOf(TCnDESBuffer)); + Move(StrByte[0], TV[0], SizeOf(TCnDESIv)); // ȴһ + + // Ƚ + DesData(dmDecry, SubKey3, StrByte, OutByte); + DesData(dmEncry, SubKey2, OutByte, StrByte); + DesData(dmDecry, SubKey1, StrByte, OutByte); + + // CBC ݿֵܺٸ Iv + PCardinal(@OutByte[0])^ := PCardinal(@OutByte[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@OutByte[4])^ := PCardinal(@OutByte[4])^ xor PCardinal(@Vector[4])^; + + Move(OutByte[0], Result[I * CN_DES_BLOCKSIZE], SizeOf(TCnDESBuffer)); + + // ĸµ Iv + Move(TV[0], Vector[0], SizeOf(TCnDESIv)); + end; +end; + +procedure TripleDESEncryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; Dest: TStream); overload; +var + K1, K2, K3: TCnDESKey; + TempIn, TempOut: TCnDESBuffer; + Done: Cardinal; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + DesData(dmEncry, SubKey1, TempIn, TempOut); + DesData(dmDecry, SubKey2, TempOut, TempIn); + DesData(dmEncry, SubKey3, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Dec(Count, SizeOf(TCnDESBuffer)); + end; + + if Count > 0 then // β 0 + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorDESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + + DesData(dmEncry, SubKey1, TempIn, TempOut); + DesData(dmDecry, SubKey2, TempOut, TempIn); + DesData(dmEncry, SubKey3, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + end; +end; + +procedure TripleDESDecryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; Dest: TStream); overload; +var + K1, K2, K3: TCnDESKey; + TempIn, TempOut: TCnDESBuffer; + Done: Cardinal; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + if (Count mod SizeOf(TCnDESBuffer)) > 0 then + raise ECnDESException.Create(SCnErrorDESInvalidInBufSize); + + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + DesData(dmDecry, SubKey3, TempIn, TempOut); + DesData(dmEncry, SubKey2, TempOut, TempIn); + DesData(dmDecry, SubKey1, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Dec(Count, SizeOf(TCnDESBuffer)); + end; +end; + +procedure TripleDESEncryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +var + K1, K2, K3: TCnDESKey; + TempIn, TempOut: TCnDESBuffer; + Vector: TCnDESIv; + Done: Cardinal; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorDESReadError); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + + DesData(dmEncry, SubKey1, TempIn, TempOut); + DesData(dmDecry, SubKey2, TempOut, TempIn); + DesData(dmEncry, SubKey3, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + + Move(TempOut[0], Vector[0], SizeOf(TCnDESIv)); + Dec(Count, SizeOf(TCnDESBuffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorDESReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + + DesData(dmEncry, SubKey1, TempIn, TempOut); + DesData(dmDecry, SubKey2, TempOut, TempIn); + DesData(dmEncry, SubKey3, TempIn, TempOut); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorDESWriteError); + end; +end; + +procedure TripleDESDecryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCn3DESKey; const InitVector: TCnDESIv; Dest: TStream); overload; +var + K1, K2, K3: TCnDESKey; + TempIn, TempOut: TCnDESBuffer; + Vector1, Vector2: TCnDESIv; + Done: Cardinal; + SubKey1, SubKey2, SubKey3: TSubKey; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + if (Count mod SizeOf(TCnDESBuffer)) > 0 then + raise ECnDESException.Create(SCnErrorDESInvalidInBufSize); + + Vector1 := InitVector; + Make3DESKeys(Key, K1, K2, K3); + MakeKey(K1, SubKey1); + MakeKey(K2, SubKey2); + MakeKey(K3, SubKey3); + + while Count >= SizeOf(TCnDESBuffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorDESReadError); + + Move(TempIn[0], Vector2[0], SizeOf(TCnDESIv)); + + DesData(dmDecry, SubKey3, TempIn, TempOut); + DesData(dmEncry, SubKey2, TempOut, TempIn); + DesData(dmDecry, SubKey1, TempIn, TempOut); + + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorDESWriteError); + + Vector1 := Vector2; + Dec(Count, SizeOf(TCnDESBuffer)); + end; +end; + +end. diff --git a/CnPack/Crypto/CnKDF.pas b/CnPack/Crypto/CnKDF.pas new file mode 100644 index 0000000..b361ec5 --- /dev/null +++ b/CnPack/Crypto/CnKDF.pas @@ -0,0 +1,804 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnKDF; +{* |
+================================================================================ +* ƣ +* ԪƣԿ㷨KDFԪ +* ԪߣCnPack (master@cnpack.org) +* עԪʵ˻ RFC2898 PBKDF1 PBKDF2 Կ㷨 PBKDF1 ֧ MD2 㷨 +* ͬʱҲʵ˻ RFC5869 HKDF HMac Կ㷨 +* SM2/SM9 㷨й涨㷨 +* ƽ̨WinXP + Delphi 5.0 +* ݲԣδ +* õԪ豾ػ +* ļ¼2025.01.09 V1.5 +* HKDF ʵֺ +* 2022.06.21 V1.4 +* ϲһֽ CnSM2SM9KDF AnsiString ڸ߰汾 Delphi ¿ +* 2022.04.26 V1.3 +* LongWord Integer ַת֧ MacOS64 +* 2022.01.02 V1.2 +* CnPBKDF2 һԼ Unicode µļ +* 2021.11.25 V1.1 +* CnSM2KDF Unicode µļ +* 2020.03.30 V1.0 +* Ԫ CnPemUtils ж +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes, CnNative, CnMD5, CnSHA1, CnSHA2, CnSHA3, CnSM3; + +type + TCnKeyDeriveHash = (ckdMd5, ckdSha256, ckdSha1); + {* CnGetDeriveKey ʹõӴշ} + + TCnPBKDF1KeyHash = (cpdfMd2, cpdfMd5, cpdfSha1); + {* PBKDF1 涨Ӵշ MD2 Dz֧} + + TCnPBKDF2KeyHash = (cpdfSha1Hmac, cpdfSha256Hmac); + {* PBKDF2 涨Ӵշ} + + TCnHKDFHash = (chkMd5, chkSha1, chkSha256, chkSha3_256, chkSm3); + {* HKDFHMAC-based Key Derivation Functionֵ֧Ӵ} + + ECnKDFException = class(Exception); + {* KDF 쳣} + +function CnGetDeriveKey(const Password: AnsiString; const Salt: AnsiString; + OutKey: PAnsiChar; KeyLength: Cardinal; KeyHash: TCnKeyDeriveHash = ckdMd5): Boolean; +{* Openssl е BytesToKeyָӴ㷨ɼ Key + Ŀǰ KeyLength ֧ HashҲ MD5 32 ֽڣSHA256 64 ֽڡ + + + const Password: AnsiString - + const Salt: AnsiString - ֵ + OutKey: PAnsiChar - Կݿַ + KeyLength: Cardinal - Կݿֽڳ + KeyHash: TCnKeyDeriveHash - Ӵ㷨 + + ֵBoolean - Ƿɳɹ +} + +function CnPBKDF1(const Password: AnsiString; const Salt: AnsiString; Count: Integer; + DerivedKeyByteLength: Integer; KeyHash: TCnPBKDF1KeyHash = cpdfMd5): AnsiString; +{* Password Based KDF 1 ʵ֣Ĺ̶Ӵյֻ֧ MD5 SHA1뷵ֵΪ AnsiString + DerivedKeyByteLength Կֽȹ̶ + + + const Password: AnsiString - + const Salt: AnsiString - ֵ + Count: Integer - + DerivedKeyByteLength: Integer - ɵԿֽڳ + KeyHash: TCnPBKDF1KeyHash - Ӵ㷨 + + ֵAnsiString - ɵԿ +} + +function CnPBKDF2(const Password: AnsiString; const Salt: AnsiString; Count: Integer; + DerivedKeyByteLength: Integer; KeyHash: TCnPBKDF2KeyHash = cpdfSha1Hmac): AnsiString; +{* Password Based KDF 2 ʵ֣ HMAC-SHA1 HMAC-SHA256뷵ֵΪ AnsiString + DerivedKeyByteLength Կֽȿɱ䣬 + + + const Password: AnsiString - + const Salt: AnsiString - ֵ + Count: Integer - + DerivedKeyByteLength: Integer - ɵԿֽڳ + KeyHash: TCnPBKDF2KeyHash - Ӵ㷨 + + ֵAnsiString - ɵԿ +} + +function CnPBKDF1Bytes(const Password: TBytes; const Salt: TBytes; Count: Integer; + DerivedKeyByteLength: Integer; KeyHash: TCnPBKDF1KeyHash = cpdfMd5): TBytes; +{* Password Based KDF 1 ʵ֣Ĺ̶Ӵյֻ֧ MD5 SHA1뷵ֵΪֽ顣 + DerivedKeyByteLength Կֽȹ̶ + + + const Password: TBytes - + const Salt: TBytes - ֵ + Count: Integer - + DerivedKeyByteLength: Integer - ɵԿֽڳ + KeyHash: TCnPBKDF1KeyHash - Ӵ㷨 + + ֵTBytes - ɵԿ +} + +function CnPBKDF2Bytes(const Password: TBytes; const Salt: TBytes; Count: Integer; + DerivedKeyByteLength: Integer; KeyHash: TCnPBKDF2KeyHash = cpdfSha1Hmac): TBytes; +{* Password Based KDF 2 ʵ֣ HMAC-SHA1 HMAC-SHA256뷵ֵΪֽ顣 + DerivedKeyByteLength Կֽȿɱ䣬 + + + const Password: TBytes - + const Salt: TBytes - ֵ + Count: Integer - + DerivedKeyByteLength: Integer - ɵԿֽڳ + KeyHash: TCnPBKDF2KeyHash - Ӵ㷨 + + ֵTBytes - ɵԿ +} + +// ============ SM2/SM9 й涨ͬһԿַװʵ =============== + +function CnSM2KDF(const Data: AnsiString; DerivedKeyByteLength: Integer): AnsiString; +{* SM2 Բ߹Կ㷨й涨ԿDerivedKeyLength Կֽ + AnsiStringͬʱƺҲû SharedInfo ANSI-X9.63-KDF + + + const Data: AnsiString - Կԭʼݣ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵAnsiString - ɵԿ +} + +function CnSM9KDF(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): AnsiString; +{* SM9 ʶ㷨й涨ԿDerivedKeyLength Կֽ + AnsiStringͬʱƺҲû SharedInfo ANSI-X9.63-KDF + + + Data: Pointer - Կԭʼݿַ + DataByteLen: Integer - Կԭʼݵֽڳ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵAnsiString - ɵԿ +} + +function CnSM2KDFBytes(const Data: TBytes; DerivedKeyByteLength: Integer): TBytes; +{* Ϊֽʽ SM2 Բ߹Կ㷨й涨Կ + DerivedKeyLength Կֽɵֽ顣 + + + const Data: TBytes - Կԭʼݵֽ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +function CnSM9KDFBytes(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): TBytes; +{* Ϊڴʽ SM9 ʶ㷨й涨Կ + DerivedKeyLength Կֽɵֽ顣 + + + Data: Pointer - Կԭʼݿַ + DataByteLen: Integer - Կԭʼݵֽڳ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +function CnSM2SM9KDF(Data: TBytes; DerivedKeyByteLength: Integer): TBytes; overload; +{* Ϊֽʽ SM2 Բ߹Կ㷨 SM9 ʶ㷨й涨Կ + DerivedKeyLength ԿֽɵԿֽ顣 + + + Data: TBytes - Կԭʼݵֽ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +function CnSM2SM9KDF(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): TBytes; overload; +{* Ϊڴʽ SM2 Բ߹Կ㷨 SM9 ʶ㷨й涨Կ + DerivedKeyLength ԿֽԿֽ顣 + + + Data: Pointer - Կԭʼݿַ + DataByteLen: Integer - Կԭʼݵֽڳ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +function CnHKDF(HKDF: TCnHKDFHash; IKM: Pointer; IKMByteLen: Integer; + Salt: Pointer; SaltByteLen: Integer; Info: Pointer; InfoByteLen: Integer; + DerivedKeyByteLength: Integer): TBytes; overload; +{* HMAC KDF Կ IKMSalt InfoָȵԿ + Salt Ϊգڲʹù̶Ӵսȵȫ 0Info ΪաɵԿ + + + HKDF: TCnHKDFHash - Ӵ㷨 + IKM: Pointer - ԿݣInput Keying Materialַ + IKMByteLen: Integer - Կݵֽڳ + Salt: Pointer - Կֵݿַ + SaltByteLen: Integer - Կֵݵֽڳ + Info: Pointer - ԿĿѡϢݿַ + InfoByteLen: Integer - ԿĿѡϢݵֽڳ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +function CnHKDFBytes(HKDF: TCnHKDFHash; IKM: TBytes; Salt: TBytes; Info: TBytes; + DerivedKeyByteLength: Integer): TBytes; overload; +{* HMAC KDF Կ IKMSalt Info ֽ飬ָȵԿ + Salt Ϊգڲʹù̶Ӵսȵȫ 0Info ΪաɵԿ + + HKDF: TCnHKDFHash - Ӵ㷨 + IKM: TBytes - Կ + Salt: TBytes - Կֵ + Info: TBytes - ԿĿѡϢ + DerivedKeyByteLength: Integer - ɵԿֽڳ + + ֵTBytes - ɵԿ +} + +implementation + +resourcestring + SCnErrorKDFKeyTooLong = 'Derived Key Too Long.'; + SCnErrorKDFParam = 'Invalid Parameters.'; + SCnErrorKDFHashNOTSupport = 'Hash Method NOT Support.'; + +function Min(A, B: Integer): Integer; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + if A < B then + Result := A + else + Result := B; +end; + +function CnGetDeriveKey(const Password, Salt: AnsiString; OutKey: PAnsiChar; KeyLength: Cardinal; + KeyHash: TCnKeyDeriveHash): Boolean; +var + Md5Dig, Md5Dig2: TCnMD5Digest; + Sha256Dig, Sha256Dig2: TCnSHA256Digest; + SaltBuf, PS, PSMD5, PSSHA256: AnsiString; +begin + Result := False; + + if (Password = '') or (OutKey = nil) or (KeyLength < 8) then + Exit; + + SetLength(SaltBuf, 8); + FillChar(SaltBuf[1], Length(SaltBuf), 0); + if Salt <> '' then + Move(Salt[1], SaltBuf[1], Min(Length(Salt), 8)); + + if not (KeyHash in [ckdMd5, ckdSha256]) then + raise ECnKDFException.Create(SCnErrorKDFHashNOTSupport); + + PS := AnsiString(Password) + SaltBuf; // 涨ǰ 8 ֽΪ Salt + if KeyHash = ckdMd5 then + begin + SetLength(PSMD5, SizeOf(TCnMD5Digest) + Length(PS)); + Move(PS[1], PSMD5[SizeOf(TCnMD5Digest) + 1], Length(PS)); + Md5Dig := MD5StringA(PS); + // Salt ƴ MD5 16 ByteΪһ + + Move(Md5Dig[0], OutKey^, Min(KeyLength, SizeOf(TCnMD5Digest))); + if KeyLength <= SizeOf(TCnMD5Digest) then + begin + Result := True; + Exit; + end; + + KeyLength := KeyLength - SizeOf(TCnMD5Digest); + OutKey := PAnsiChar(TCnNativeUInt(OutKey) + SizeOf(TCnMD5Digest)); + + Move(Md5Dig[0], PSMD5[1], SizeOf(TCnMD5Digest)); + Md5Dig2 := MD5StringA(PSMD5); + Move(Md5Dig2[0], OutKey^, Min(KeyLength, SizeOf(TCnMD5Digest))); + if KeyLength <= SizeOf(TCnMD5Digest) then + Result := True; + + // KeyLength ̫㲻 + end + else if KeyHash = ckdSha256 then + begin + SetLength(PSSHA256, SizeOf(TCnSHA256Digest) + Length(PS)); + Move(PS[1], PSSHA256[SizeOf(TCnSHA256Digest) + 1], Length(PS)); + Sha256Dig := SHA256StringA(PS); + // Salt ƴ SHA256 32 ByteΪһ + + Move(Sha256Dig[0], OutKey^, Min(KeyLength, SizeOf(TCnSHA256Digest))); + if KeyLength <= SizeOf(TCnSHA256Digest) then + begin + Result := True; + Exit; + end; + + KeyLength := KeyLength - SizeOf(TCnSHA256Digest); + OutKey := PAnsiChar(TCnNativeUInt(OutKey) + SizeOf(TCnSHA256Digest)); + + Move(Sha256Dig[0], PSSHA256[1], SizeOf(TCnSHA256Digest)); + Sha256Dig2 := SHA256StringA(PSSHA256); + Move(Sha256Dig2[0], OutKey^, Min(KeyLength, SizeOf(TCnSHA256Digest))); + if KeyLength <= SizeOf(TCnSHA256Digest) then + Result := True; + + // KeyLength ̫㲻 + end; +end; + +(* + T_1 = Hash (P || S) , + T_2 = Hash (T_1) , + ... + T_c = Hash (T_{c-1}) , + DK = Tc<0..dkLen-1> +*) +function CnPBKDF1(const Password, Salt: AnsiString; Count, DerivedKeyByteLength: Integer; + KeyHash: TCnPBKDF1KeyHash): AnsiString; +var + P, S, Res: TBytes; +begin + P := AnsiToBytes(Password); + S := AnsiToBytes(Salt); + Res := CnPBKDF1Bytes(P, S, Count, DerivedKeyByteLength, KeyHash); + Result := BytesToAnsi(Res); +end; + +{ + DK = T1 + T2 + ... + Tdklen/hlen + Ti = F(Password, Salt, c, i) + + F(Password, Salt, c, i) = U1 ^ U2 ^ ... ^ Uc + + U1 = PRF(Password, Salt + INT_32_BE(i)) + U2 = PRF(Password, U1) + ... + Uc = PRF(Password, Uc-1) +} +function CnPBKDF2(const Password, Salt: AnsiString; Count, DerivedKeyByteLength: Integer; + KeyHash: TCnPBKDF2KeyHash): AnsiString; +var + P, S, Res: TBytes; +begin + P := AnsiToBytes(Password); + S := AnsiToBytes(Salt); + Res := CnPBKDF2Bytes(P, S, Count, DerivedKeyByteLength, KeyHash); + Result := BytesToAnsi(Res); +end; + +function CnPBKDF1Bytes(const Password, Salt: TBytes; Count, DerivedKeyByteLength: Integer; + KeyHash: TCnPBKDF1KeyHash = cpdfMd5): TBytes; +var + I: Integer; + Md5Dig, TM: TCnMD5Digest; + Sha1Dig, TS: TCnSHA1Digest; +begin + Result := nil; + if (Password = nil) or (Count <= 0) or (DerivedKeyByteLength <= 0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + case KeyHash of + cpdfMd5: + begin + if DerivedKeyByteLength > SizeOf(TCnMD5Digest) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + SetLength(Result, DerivedKeyByteLength); + Md5Dig := MD5Bytes(ConcatBytes(Password, Salt)); // Got T1 + if Count > 1 then + begin + for I := 2 to Count do + begin + TM := Md5Dig; + Md5Dig := MD5Buffer(TM[0], SizeOf(TCnMD5Digest)); // Got T_c + end; + end; + + Move(Md5Dig[0], Result[0], DerivedKeyByteLength); + end; + cpdfSha1: + begin + if DerivedKeyByteLength > SizeOf(TCnSHA1Digest) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + SetLength(Result, DerivedKeyByteLength); + Sha1Dig := SHA1Bytes(ConcatBytes(Password, Salt)); // Got T1 + if Count > 1 then + begin + for I := 2 to Count do + begin + TS := Sha1Dig; + Sha1Dig := SHA1Buffer(TS[0], SizeOf(TCnSHA1Digest)); // Got T_c + end; + end; + + Move(Sha1Dig[0], Result[0], DerivedKeyByteLength); + end; + else + raise ECnKDFException.Create(SCnErrorKDFHashNOTSupport); + end; +end; + +function CnPBKDF2Bytes(const Password, Salt: TBytes; Count, DerivedKeyByteLength: Integer; + KeyHash: TCnPBKDF2KeyHash = cpdfSha1Hmac): TBytes; +var + HLen, D, I, J, K: Integer; + Sha1Dig1, Sha1Dig, T1: TCnSHA1Digest; + Sha256Dig1, Sha256Dig, T256: TCnSHA256Digest; + S, S1, S256, Pad: TBytes; + PAddr: Pointer; +begin + Result := nil; + if (Salt = nil) or (Count <= 0) or (DerivedKeyByteLength <=0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + if (Password = nil) or (Length(Password) = 0) then + PAddr := nil + else + PAddr := @Password[0]; + + case KeyHash of + cpdfSha1Hmac: + HLen := 20; + cpdfSha256Hmac: + HLen := 32; + else + raise ECnKDFException.Create(SCnErrorKDFParam); + end; + + D := (DerivedKeyByteLength div HLen) + 1; + SetLength(S1, SizeOf(TCnSHA1Digest)); + SetLength(S256, SizeOf(TCnSHA256Digest)); + + SetLength(Pad, 4); + if KeyHash = cpdfSha1Hmac then + begin + for I := 1 to D do + begin + Pad[0] := I shr 24; + Pad[1] := I shr 16; + Pad[2] := I shr 8; + Pad[3] := I; + S := ConcatBytes(Salt, Pad); + + SHA1Hmac(PAddr, Length(Password), PAnsiChar(@S[0]), Length(S), Sha1Dig1); + T1 := Sha1Dig1; + + for J := 2 to Count do + begin + SHA1Hmac(PAddr, Length(Password), PAnsiChar(@T1[0]), SizeOf(TCnSHA1Digest), Sha1Dig); + T1 := Sha1Dig; + for K := Low(TCnSHA1Digest) to High(TCnSHA1Digest) do + Sha1Dig1[K] := Sha1Dig1[K] xor T1[K]; + end; + + Move(Sha1Dig1[0], S1[0], Length(S1)); + Result := ConcatBytes(Result, S1); + end; + Result := Copy(Result, 0, DerivedKeyByteLength); + end + else if KeyHash = cpdfSha256Hmac then + begin + for I := 1 to D do + begin + Pad[0] := I shr 24; + Pad[1] := I shr 16; + Pad[2] := I shr 8; + Pad[3] := I; + S := ConcatBytes(Salt, Pad); + + SHA256Hmac(PAddr, Length(Password), PAnsiChar(@S[0]), Length(S), Sha256Dig1); + T256 := Sha256Dig1; + + for J := 2 to Count do + begin + SHA256Hmac(PAddr, Length(Password), PAnsiChar(@T256[0]), SizeOf(TCnSHA256Digest), Sha256Dig); + T256 := Sha256Dig; + for K := Low(TCnSHA256Digest) to High(TCnSHA256Digest) do + Sha256Dig1[K] := Sha256Dig1[K] xor T256[K]; + end; + + Move(Sha256Dig1[0], S256[0], SizeOf(TCnSHA256Digest)); + Result := ConcatBytes(Result, S256); + end; + Result := Copy(Result, 0, DerivedKeyByteLength); + end; +end; + +function CnSM2KDF(const Data: AnsiString; DerivedKeyByteLength: Integer): AnsiString; +var + Res: TBytes; +begin + if (Data = '') or (DerivedKeyByteLength <= 0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + Res := CnSM2SM9KDF(@Data[1], Length(Data), DerivedKeyByteLength); + Result := BytesToAnsi(Res); +end; + +function CnSM9KDF(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): AnsiString; +var + Res: TBytes; +begin + Res := CnSM2SM9KDF(Data, DataByteLen, DerivedKeyByteLength); + Result := BytesToAnsi(Res); +end; + +function CnSM2KDFBytes(const Data: TBytes; DerivedKeyByteLength: Integer): TBytes; +begin + Result := CnSM2SM9KDF(Data, DerivedKeyByteLength); +end; + +function CnSM9KDFBytes(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): TBytes; +begin + Result := CnSM2SM9KDF(Data, DataByteLen, DerivedKeyByteLength); +end; + +function CnSM2SM9KDF(Data: TBytes; DerivedKeyByteLength: Integer): TBytes; +begin + if (Data = nil) or (Length(Data) <= 0) or (DerivedKeyByteLength <= 0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + Result := CnSM2SM9KDF(@Data[0], Length(Data), DerivedKeyByteLength); +end; + +function CnSM2SM9KDF(Data: Pointer; DataByteLen: Integer; DerivedKeyByteLength: Integer): TBytes; overload; +var + DArr: TBytes; + CT, SCT: Cardinal; + I, CeilLen: Integer; + IsInt: Boolean; + SM3D: TCnSM3Digest; +begin + Result := nil; + if (Data = nil) or (DataByteLen <= 0) or (DerivedKeyByteLength <= 0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + DArr := nil; + CT := 1; + + try + SetLength(DArr, DataByteLen + SizeOf(Cardinal)); + Move(Data^, DArr[0], DataByteLen); + + IsInt := DerivedKeyByteLength mod SizeOf(TCnSM3Digest) = 0; + CeilLen := (DerivedKeyByteLength + SizeOf(TCnSM3Digest) - 1) div SizeOf(TCnSM3Digest); + + SetLength(Result, DerivedKeyByteLength); + for I := 1 to CeilLen do + begin + SCT := UInt32HostToNetwork(CT); // Ȼĵû˵Ҫһ + Move(SCT, DArr[DataByteLen], SizeOf(Cardinal)); + SM3D := SM3(@DArr[0], Length(DArr)); + + if (I = CeilLen) and not IsInt then + begin + // һ 32 ʱֻƶһ + Move(SM3D[0], Result[(I - 1) * SizeOf(TCnSM3Digest)], (DerivedKeyByteLength mod SizeOf(TCnSM3Digest))); + end + else + Move(SM3D[0], Result[(I - 1) * SizeOf(TCnSM3Digest)], SizeOf(TCnSM3Digest)); + + Inc(CT); + end; + finally + SetLength(DArr, 0); + end; +end; + +function CnHKDF(HKDF: TCnHKDFHash; IKM: Pointer; IKMByteLen: Integer; + Salt: Pointer; SaltByteLen: Integer; Info: Pointer; InfoByteLen: Integer; + DerivedKeyByteLength: Integer): TBytes; +const + MAX_BYTE = 255; +var + PRKMd5, Md5T: TCnMD5Digest; + PRKSha1, Sha1T: TCnSHA1Digest; + PRKSha256, Sha256T: TCnSHA256Digest; + PRKSha3256, Sha3256T: TCnSHA3_256Digest; + PRKSm3, Sm3T: TCnSM3Digest; + T0, T: TBytes; + N, I, Start, HashLen: Integer; +begin + if IKM = nil then + IKMByteLen := 0; + + if Salt = nil then + SaltByteLen := 0; + + if Info = nil then + InfoByteLen := 0; + + if (IKMByteLen < 0) or (SaltByteLen < 0) or (InfoByteLen < 0) then + raise ECnKDFException.Create(SCnErrorKDFParam); + + // Extract HMac(Salt, IKM)ע IKM ݣ HMac Key + case HKDF of + chkMd5: + begin + if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnMD5Digest)) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + HashLen := SizeOf(TCnMD5Digest); + if (Salt = nil) or (SaltByteLen <= 0) then + begin + FillChar(PRKMd5[0], HashLen, 0); + MD5Hmac(@PRKMd5[0], HashLen, IKM, IKMByteLen, PRKMd5); + end + else + MD5Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKMd5); + end; + chkSha1: + begin + if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnSHA1Digest)) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + HashLen := SizeOf(TCnSHA1Digest); + if (Salt = nil) or (SaltByteLen <= 0) then + begin + FillChar(PRKSha1[0], HashLen, 0); + SHA1Hmac(@PRKSha1[0], HashLen, IKM, IKMByteLen, PRKSha1); + end + else + SHA1Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKSha1); + end; + chkSha256: + begin + if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnSHA256Digest)) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + HashLen := SizeOf(TCnSHA256Digest); + if (Salt = nil) or (SaltByteLen <= 0) then + begin + FillChar(PRKSha256[0], HashLen, 0); + SHA256Hmac(@PRKSha256[0], HashLen, IKM, IKMByteLen, PRKSha256); + end + else + SHA256Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKSha256); + end; + chkSha3_256: + begin + if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnSHA3_256Digest)) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + HashLen := SizeOf(TCnSHA3_256Digest); + if (Salt = nil) or (SaltByteLen <= 0) then + begin + FillChar(PRKSha3256[0], HashLen, 0); + SHA3_256Hmac(@PRKSha3256[0], HashLen, IKM, IKMByteLen, PRKSha3256); + end + else + SHA3_256Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKSha3256); + end; + chkSm3: + begin + if (DerivedKeyByteLength <= 0) or (DerivedKeyByteLength > MAX_BYTE * SizeOf(TCnSM3Digest)) then + raise ECnKDFException.Create(SCnErrorKDFKeyTooLong); + + HashLen := SizeOf(TCnSM3Digest); + if (Salt = nil) or (SaltByteLen <= 0) then + begin + FillChar(PRKSm3[0], HashLen, 0); + SM3Hmac(@PRKSm3[0], HashLen, IKM, IKMByteLen, PRKSm3); + end + else + SM3Hmac(Salt, SaltByteLen, IKM, IKMByteLen, PRKSm3); + end; + else + raise ECnKDFException.Create(SCnErrorKDFHashNOTSupport); + end; + + // ʼ Expand + SetLength(T0, InfoByteLen + 1); + if InfoByteLen > 0 then + Move(Info^, T0[0], InfoByteLen); + T0[InfoByteLen] := 1; // ƴװ T0 + + // ʼÿֵļ + SetLength(T, HashLen + InfoByteLen + 1); + + // ýȲ + N := (DerivedKeyByteLength + HashLen - 1) div HashLen; + SetLength(Result, DerivedKeyByteLength); + + // T0 һ T1 + case HKDF of + chkMd5: MD5Hmac(@PRKMd5[0], HashLen, @T0[0], Length(T0), Md5T); + chkSha1: SHA1Hmac(@PRKSha1[0], HashLen, @T0[0], Length(T0), Sha1T); + chkSha256: SHA256Hmac(@PRKSha256[0], HashLen, @T0[0], Length(T0), Sha256T); + chkSha3_256: SHA3_256Hmac(@PRKSha3256[0], HashLen, @T0[0], Length(T0), Sha3256T); + chkSm3: SM3Hmac(@PRKSm3[0], HashLen, @T0[0], Length(T0), Sm3T); + end; + + Start := 0; + for I := 1 to N do + begin + // T1 ƴڽ + if DerivedKeyByteLength > HashLen then + begin + case HKDF of + chkMd5: Move(Md5T[0], Result[Start], HashLen); + chkSha1: Move(Sha1T[0], Result[Start], HashLen); + chkSha256: Move(Sha256T[0], Result[Start], HashLen); + chkSha3_256: Move(Sha3256T[0], Result[Start], HashLen); + chkSm3: Move(Sm3T[0], Result[Start], HashLen); + end; + Inc(Start, HashLen); + Dec(DerivedKeyByteLength, HashLen); + end + else + begin + case HKDF of + chkMd5: Move(Md5T[0], Result[Start], DerivedKeyByteLength); + chkSha1: Move(Sha1T[0], Result[Start], DerivedKeyByteLength); + chkSha256: Move(Sha256T[0], Result[Start], DerivedKeyByteLength); + chkSha3_256: Move(Sha3256T[0], Result[Start], DerivedKeyByteLength); + chkSm3: Move(Sm3T[0], Result[Start], DerivedKeyByteLength); + end; + Break; + end; + + // T1 Info ƴһһ + case HKDF of + chkMd5: Move(Md5T[0], T[0], HashLen); + chkSha1: Move(Sha1T[0], T[0], HashLen); + chkSha256: Move(Sha256T[0], T[0], HashLen); + chkSha3_256: Move(Sha3256T[0], T[0], HashLen); + chkSm3: Move(Sm3T[0], T[0], HashLen); + end; + Move(Info^, T[HashLen], InfoByteLen); + T[HashLen + InfoByteLen] := I + 1; + + // Ӵ T2 T1 + case HKDF of + chkMd5: MD5Hmac(@PRKMd5[0], HashLen, @T[0], Length(T), Md5T); + chkSha1: SHA1Hmac(@PRKSha1[0], HashLen, @T[0], Length(T), Sha1T); + chkSha256: SHA256Hmac(@PRKSha256[0], HashLen, @T[0], Length(T), Sha256T); + chkSha3_256: SHA3_256Hmac(@PRKSha3256[0], HashLen, @T[0], Length(T), Sha3256T); + chkSm3: SM3Hmac(@PRKSm3[0], HashLen, @T[0], Length(T), Sm3T); + end; + end; +end; + +function CnHKDFBytes(HKDF: TCnHKDFHash; IKM: TBytes; Salt: TBytes; Info: TBytes; + DerivedKeyByteLength: Integer): TBytes; +var + IKMP, SaltP, InfoP: Pointer; + IKML, SaltL, InfoL: Integer; +begin + IKMP := nil; + SaltP := nil; + InfoP := nil; + IKML := 0; + SaltL := 0; + InfoL := 0; + + if Length(IKM) > 0 then + begin + IKMP := @IKM[0]; + IKML := Length(IKM); + end; + if Length(Salt) > 0 then + begin + SaltP := @Salt[0]; + SaltL := Length(Salt); + end; + if Length(Info) > 0 then + begin + InfoP := @Info[0]; + InfoL := Length(Info); + end; + + Result := CnHKDF(HKDF, IKMP, IKML, SaltP, SaltL, InfoP, InfoL, DerivedKeyByteLength); +end; + +end. diff --git a/CnPack/Crypto/CnMD5.pas b/CnPack/Crypto/CnMD5.pas new file mode 100644 index 0000000..be31d9d --- /dev/null +++ b/CnPack/Crypto/CnMD5.pas @@ -0,0 +1,908 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +{******************************************************************************} +{ } +{ MD5 Message-Digest for Delphi 4 } +{ } +{ Delphi 4 Unit implementing the } +{ RSA Data Security, Inc. MD5 Message-Digest Algorithm } +{ } +{ Implementation of Ronald L. Rivest's RFC 1321 } +{ } +{ Copyright ?1997-1999 Medienagentur Fichtner & Meyer } +{ Written by Matthias Fichtner } +{ } +{ -----------------------------------------------------------------------------} +{ See RFC 1321 for RSA Data Security's copyright and license notice! } +{ -----------------------------------------------------------------------------} +{ The latest release of md5.pas will always be available from } +{ the distribution site at: http://www.fichtner.net/delphi/md5/ } +{ -----------------------------------------------------------------------------} +{ Please send questions, bug reports and suggestions } +{ regarding this code to: mfichtner@fichtner-meyer.com } +{ -----------------------------------------------------------------------------} +{ This code is provided "as is" without express or } +{ implied warranty of any kind. Use it at your own risk. } +{******************************************************************************} + +unit CnMD5; +{* |
+================================================================================ +* ƣ +* ԪƣMD5 Ӵ㷨ʵֵԪ +* Ԫߣ壨QSoft hq.com@263.net; http://qsoft.51.net +* Ronald L. Rivest MD5.pas дԭʼ +* עԪʵ MD5 Ӵ㷨Ӧ HMAC 㷨 +* ƽ̨PWin2000Pro + Delphi 5.0 +* ݲԣPWin9X/2000/XP + Delphi 5/6 +* õԪеַϱػʽ +* ļ¼2019.12.12 V1.4 +* ֧ TBytes +* 2019.04.15 V1.3 +* ֧ Win32/Win64/MacOS +* 2014.11.14 V1.2 +* л Pascal ֿ֧ƽ̨ +* 2003.09.18 V1.1 +* òҵ˸õԪԭߵİȨ +* 2003.09.18 V1.0 +* Ԫ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + Classes, SysUtils, CnConsts, CnNative {$IFDEF MSWINDOWS}, Windows {$ENDIF}; + +type + PMD5Digest = ^TCnMD5Digest; + {* MD5 Ӵսָ} + TCnMD5Digest = array[0..15] of Byte; + {* MD5 Ӵս16 ֽ} + + TCnMD5Count = array[0..1] of Cardinal; + {* MD5 ڲṹ} + TCnMD5State = array[0..3] of Cardinal; + {* MD5 ڲ״̬ṹ} + TCnMD5Block = array[0..15] of Cardinal; + {* MD5 ڲṹ} + + TCnMD5Buffer = array[0..63] of Byte; + {* MD5 ڲṹ} + + TCnMD5Context = packed record + {* MD5 Ľṹ} + State : TCnMD5State; + Count : TCnMD5Count; + Buffer : TCnMD5Buffer; + Ipad : array[0..63] of Byte; {!< HMAC: inner padding } + Opad : array[0..63] of Byte; {!< HMAC: outer padding } + end; + + TCnMD5CalcProgressFunc = procedure (ATotal, AProgress: Int64; + var Cancel: Boolean) of object; + {* Ȼص¼} + +//---------------------------------------------------------------- +// û API +//---------------------------------------------------------------- + +function MD5(Input: PAnsiChar; ByteLength: Cardinal): TCnMD5Digest; +{* ݿ MD5 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5Buffer(const Buffer; Count: Cardinal): TCnMD5Digest; +{* ݿ MD5 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5Bytes(const Data: TBytes): TCnMD5Digest; +{* ֽ MD5 㡣 + + + const Data: TBytes - ֽ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5String(const Str: string): TCnMD5Digest; +{* String ݽ MD5 㡣ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + + const Str: string - ַ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5StringA(const Str: AnsiString): TCnMD5Digest; +{* AnsiString ݽ MD5 㣬ֱӼڲݣޱ봦 + + + const Str: AnsiString - ַ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5StringW(const Str: WideString): TCnMD5Digest; +{* WideString ַת MD5 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +{$IFDEF UNICODE} + +function MD5UnicodeString(const Str: string): TCnMD5Digest; +{* UnicodeString ݽֱӵ MD5 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +{$ELSE} + +function MD5UnicodeString(const Str: WideString): TCnMD5Digest; +{* UnicodeString ݽֱӵ MD5 㣬ֱӼڲ UTF16 ݣת + + + + const Str: WideString - Ŀַ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +{$ENDIF} + +function MD5File(const FileName: string; + CallBack: TCnMD5CalcProgressFunc = nil): TCnMD5Digest; +{* ָļݽ MD5 㡣 + + + const FileName: string - ļ + CallBack: TCnMD5CalcProgressFunc - ȻصĬΪ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +function MD5Stream(Stream: TStream; + CallBack: TCnMD5CalcProgressFunc = nil): TCnMD5Digest; +{* ָݽ MD5 㡣 + + + Stream: TStream - + CallBack: TCnMD5CalcProgressFunc - ȻصĬΪ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +// ⲿݽɢ MD5 㣬MD5Update ɶα + +procedure MD5Init(var Context: TCnMD5Context); +{* ʼһ MD5 ģ MD5 + + + var Context: TCnMD5Context - ʼ MD5 + + ֵޣ +} + +procedure MD5Update(var Context: TCnMD5Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ MD5 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnMD5Context - MD5 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure MD5Final(var Context: TCnMD5Context; var Digest: TCnMD5Digest); +{* ּ㣬 MD5 Digest С + + + var Context: TCnMD5Context - MD5 + var Digest: TCnMD5Digest - ص MD5 Ӵֵ + + ֵޣ +} + +function MD5Print(const Digest: TCnMD5Digest): string; +{* ʮƸʽ MD5 Ӵֵ + + + const Digest: TCnMD5Digest - ָ MD5 Ӵֵ + + ֵstring - ʮַ +} + +function MD5Match(const D1: TCnMD5Digest; const D2: TCnMD5Digest): Boolean; +{* Ƚ MD5 ӴֵǷȡ + + + const D1: TCnMD5Digest - Ƚϵ MD5 Ӵֵһ + const D2: TCnMD5Digest - Ƚϵ MD5 Ӵֵ + + ֵBoolean - Ƿ +} + +function MD5DigestToStr(const Digest: TCnMD5Digest): string; +{* MD5 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnMD5Digest - ת MD5 Ӵֵ + + ֵstring - صַ +} + +procedure MD5Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnMD5Digest); +{* MD5 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - MD5 Կݿַ + KeyByteLength: Integer - MD5 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnMD5Digest - ص MD5 Ӵֵ + + ֵޣ +} + +function MD5HmacBytes(const Key: TBytes; const Data: TBytes): TCnMD5Digest; +{* ֽл MD5 HMAC 㡣 + + + const Key: TBytes - MD5 Կֽ + const Data: TBytes - ֽ + + ֵTCnMD5Digest - ص MD5 Ӵֵ +} + +implementation + +const + MAX_FILE_SIZE = 512 * 1024 * 1024; + // If file size <= this size (bytes), using Mapping, else stream + + HMAC_MD5_BLOCK_SIZE_BYTE = 64; + HMAC_MD5_OUTPUT_LENGTH_BYTE = 16; + +type + TMD5CBits = array[0..7] of Byte; + +var + PADDING: TCnMD5Buffer = ( + $80, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00 + ); + +function F(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Y) or ((not X) and Z); +end; + +function G(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Z) or (Y and (not Z)); +end; + +function H(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor Y xor Z; +end; + +function I(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := Y xor (X or (not Z)); +end; + +procedure ROT(var X: Cardinal; N: BYTE); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + X := (X shl N) or (X shr (32 - N)); +end; + +procedure FF(var A: Cardinal; B, C, D, X: Cardinal; S: BYTE; AC: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Inc(A, F(B, C, D) + X + AC); + ROT(A, S); + Inc(A, B); +end; + +procedure GG(var A: Cardinal; B, C, D, X: Cardinal; S: BYTE; AC: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Inc(A, G(B, C, D) + X + AC); + ROT(A, S); + Inc(A, B); +end; + +procedure HH(var A: Cardinal; B, C, D, X: Cardinal; S: BYTE; AC: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Inc(A, H(B, C, D) + X + AC); + ROT(A, S); + Inc(A, B); +end; + +procedure II(var A: Cardinal; B, C, D, X: Cardinal; S: BYTE; AC: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Inc(A, I(B, C, D) + X + AC); + ROT(A, S); + Inc(A, B); +end; + +// Encode Count bytes at Source into (Count / 4) DWORDs at Target +procedure Encode(Source, Target: Pointer; Count: Cardinal); +var + S: PByte; + T: PCardinal; + I: Cardinal; +begin + S := Source; + T := Target; + for I := 1 to Count div 4 do + begin + T^ := S^; + Inc(S); + T^ := T^ or (S^ shl 8); + Inc(S); + T^ := T^ or (S^ shl 16); + Inc(S); + T^ := T^ or (S^ shl 24); + Inc(S); + Inc(T); + end; +end; + +// Decode Count DWORDs at Source into (Count * 4) Bytes at Target +procedure Decode(Source, Target: Pointer; Count: Cardinal); +var + S: PCardinal; + T: PByte; + I: Cardinal; +begin + S := Source; + T := Target; + for I := 1 to Count do + begin + T^ := S^ and $ff; + Inc(T); + T^ := (S^ shr 8) and $ff; + Inc(T); + T^ := (S^ shr 16) and $ff; + Inc(T); + T^ := (S^ shr 24) and $ff; + Inc(T); + Inc(S); + end; +end; + +// Transform State according to first 64 bytes at Buffer +procedure Transform(Buffer: Pointer; var State: TCnMD5State); +var + A, B, C, D: Cardinal; + Block: TCnMD5Block; +begin + Encode(Buffer, @Block, 64); + A := State[0]; + B := State[1]; + C := State[2]; + D := State[3]; + FF (A, B, C, D, Block[ 0], 7, $d76aa478); + FF (D, A, B, C, Block[ 1], 12, $e8c7b756); + FF (C, D, A, B, Block[ 2], 17, $242070db); + FF (B, C, D, A, Block[ 3], 22, $c1bdceee); + FF (A, B, C, D, Block[ 4], 7, $f57c0faf); + FF (D, A, B, C, Block[ 5], 12, $4787c62a); + FF (C, D, A, B, Block[ 6], 17, $a8304613); + FF (B, C, D, A, Block[ 7], 22, $fd469501); + FF (A, B, C, D, Block[ 8], 7, $698098d8); + FF (D, A, B, C, Block[ 9], 12, $8b44f7af); + FF (C, D, A, B, Block[10], 17, $ffff5bb1); + FF (B, C, D, A, Block[11], 22, $895cd7be); + FF (A, B, C, D, Block[12], 7, $6b901122); + FF (D, A, B, C, Block[13], 12, $fd987193); + FF (C, D, A, B, Block[14], 17, $a679438e); + FF (B, C, D, A, Block[15], 22, $49b40821); + GG (A, B, C, D, Block[ 1], 5, $f61e2562); + GG (D, A, B, C, Block[ 6], 9, $c040b340); + GG (C, D, A, B, Block[11], 14, $265e5a51); + GG (B, C, D, A, Block[ 0], 20, $e9b6c7aa); + GG (A, B, C, D, Block[ 5], 5, $d62f105d); + GG (D, A, B, C, Block[10], 9, $2441453); + GG (C, D, A, B, Block[15], 14, $d8a1e681); + GG (B, C, D, A, Block[ 4], 20, $e7d3fbc8); + GG (A, B, C, D, Block[ 9], 5, $21e1cde6); + GG (D, A, B, C, Block[14], 9, $c33707d6); + GG (C, D, A, B, Block[ 3], 14, $f4d50d87); + GG (B, C, D, A, Block[ 8], 20, $455a14ed); + GG (A, B, C, D, Block[13], 5, $a9e3e905); + GG (D, A, B, C, Block[ 2], 9, $fcefa3f8); + GG (C, D, A, B, Block[ 7], 14, $676f02d9); + GG (B, C, D, A, Block[12], 20, $8d2a4c8a); + HH (A, B, C, D, Block[ 5], 4, $fffa3942); + HH (D, A, B, C, Block[ 8], 11, $8771f681); + HH (C, D, A, B, Block[11], 16, $6d9d6122); + HH (B, C, D, A, Block[14], 23, $fde5380c); + HH (A, B, C, D, Block[ 1], 4, $a4beea44); + HH (D, A, B, C, Block[ 4], 11, $4bdecfa9); + HH (C, D, A, B, Block[ 7], 16, $f6bb4b60); + HH (B, C, D, A, Block[10], 23, $bebfbc70); + HH (A, B, C, D, Block[13], 4, $289b7ec6); + HH (D, A, B, C, Block[ 0], 11, $eaa127fa); + HH (C, D, A, B, Block[ 3], 16, $d4ef3085); + HH (B, C, D, A, Block[ 6], 23, $4881d05); + HH (A, B, C, D, Block[ 9], 4, $d9d4d039); + HH (D, A, B, C, Block[12], 11, $e6db99e5); + HH (C, D, A, B, Block[15], 16, $1fa27cf8); + HH (B, C, D, A, Block[ 2], 23, $c4ac5665); + II (A, B, C, D, Block[ 0], 6, $f4292244); + II (D, A, B, C, Block[ 7], 10, $432aff97); + II (C, D, A, B, Block[14], 15, $ab9423a7); + II (B, C, D, A, Block[ 5], 21, $fc93a039); + II (A, B, C, D, Block[12], 6, $655b59c3); + II (D, A, B, C, Block[ 3], 10, $8f0ccc92); + II (C, D, A, B, Block[10], 15, $ffeff47d); + II (B, C, D, A, Block[ 1], 21, $85845dd1); + II (A, B, C, D, Block[ 8], 6, $6fa87e4f); + II (D, A, B, C, Block[15], 10, $fe2ce6e0); + II (C, D, A, B, Block[ 6], 15, $a3014314); + II (B, C, D, A, Block[13], 21, $4e0811a1); + II (A, B, C, D, Block[ 4], 6, $f7537e82); + II (D, A, B, C, Block[11], 10, $bd3af235); + II (C, D, A, B, Block[ 2], 15, $2ad7d2bb); + II (B, C, D, A, Block[ 9], 21, $eb86d391); + Inc(State[0], A); + Inc(State[1], B); + Inc(State[2], C); + Inc(State[3], D); +end; + +// Initialize given Context +procedure MD5Init(var Context: TCnMD5Context); +begin + with Context do + begin + State[0] := $67452301; + State[1] := $EFCDAB89; + State[2] := $98BADCFE; + State[3] := $10325476; + Count[0] := 0; + Count[1] := 0; + // ZeroMemory(@Buffer, SizeOf(TMD5Buffer)); + FillChar(Buffer, SizeOf(TCnMD5Buffer), 0); + end; +end; + +// Update given Context to include Length bytes of Input +procedure MD5Update(var Context: TCnMD5Context; Input: PAnsiChar; ByteLength: Cardinal); +var + Index: Cardinal; + PartLen: Cardinal; + I: Cardinal; +begin + with Context do + begin + Index := (Count[0] shr 3) and $3F; + Inc(Count[0], ByteLength shl 3); + if Count[0] < (ByteLength shl 3) then Inc(Count[1]); + Inc(Count[1], ByteLength shr 29); + end; + + PartLen := 64 - Index; + if ByteLength >= PartLen then + begin + Move(Input^, Context.Buffer[Index], PartLen); + Transform(@Context.Buffer, Context.State); + I := PartLen; + while I + 63 < ByteLength do + begin + Transform(@Input[I], Context.State); + Inc(I, 64); + end; + Index := 0; + end + else + I := 0; + + Move(Input[I], Context.Buffer[Index], ByteLength - I); +end; + +procedure MD5UpdateW(var Context: TCnMD5Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + pContent: PAnsiChar; + iLen: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(pContent, CharLength * SizeOf(WideChar)); + try + iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(pContent), CharLength * SizeOf(WideChar), nil, nil); + MD5Update(Context, pContent, iLen); + finally + FreeMem(pContent); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + MD5Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +// Finalize given Context, create Digest +procedure MD5Final(var Context: TCnMD5Context; var Digest: TCnMD5Digest); +var + Bits: TMD5CBits; + Index: Cardinal; + PadLen: Cardinal; +begin + Decode(@Context.Count, @Bits, 2); + Index := (Context.Count[0] shr 3) and $3f; + if Index < 56 then + PadLen := 56 - Index + else + PadLen := 120 - Index; + MD5Update(Context, @PADDING, PadLen); + MD5Update(Context, @Bits, 8); + Decode(@Context.State, @Digest, 4); +end; + +function InternalMD5Stream(Stream: TStream; const BufSize: Cardinal; var D: + TCnMD5Digest; CallBack: TCnMD5CalcProgressFunc): Boolean; +var + Context: TCnMD5Context; + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; +begin + Result := False; + Size := Stream.Size; + if Size = 0 then + Exit; + + SavePos := Stream.Position; + TotalBytes := 0; + + if Size < BufSize then + BufLen := Size + else + BufLen := BufSize; + + CancelCalc := False; + MD5Init(Context); + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + MD5Update(Context, Buf, ReadBytes); + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + MD5Final(Context, D); + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +// ݿ MD5 +function MD5(Input: PAnsiChar; ByteLength: Cardinal): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5Update(Context, Input, ByteLength); + MD5Final(Context, Result); +end; + +// ݿ MD5 +function MD5Buffer(const Buffer; Count: Cardinal): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5Update(Context, PAnsiChar(@Buffer), Count); + MD5Final(Context, Result); +end; + +function MD5Bytes(const Data: TBytes): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5Update(Context, PAnsiChar(@Data[0]), Length(Data)); + MD5Final(Context, Result); +end; + +// String ݽ MD5 +function MD5String(const Str: string): TCnMD5Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := MD5StringA(AStr); +end; + +// AnsiString ݽ MD5 +function MD5StringA(const Str: AnsiString): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5Update(Context, PAnsiChar(Str), Length(Str)); + MD5Final(Context, Result); +end; + +// WideString ݽ MD5 +function MD5StringW(const Str: WideString): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5UpdateW(Context, PWideChar(Str), Length(Str)); + MD5Final(Context, Result); +end; + +// UnicodeString ݽֱӵ MD5 㣬ת +{$IFDEF UNICODE} +function MD5UnicodeString(const Str: string): TCnMD5Digest; +{$ELSE} +function MD5UnicodeString(const Str: WideString): TCnMD5Digest; +{$ENDIF} +var + Context: TCnMD5Context; +begin + MD5Init(Context); + MD5Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + MD5Final(Context, Result); +end; + +// ָļݽ MD5 +function MD5File(const FileName: string; + CallBack: TCnMD5CalcProgressFunc): TCnMD5Digest; +var +{$IFDEF MSWINDOWS} + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; + Context: TCnMD5Context; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; + + function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; +{$IFDEF MSWINDOWS} + var + H: THandle; + Info: BY_HANDLE_FILE_INFORMATION; + Rec : Int64Rec; +{$ENDIF} + begin +{$IFDEF MSWINDOWS} + Result := False; + IsEmpty := False; + H := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); + if H = INVALID_HANDLE_VALUE then Exit; + try + if not GetFileInformationByHandle(H, Info) then Exit; + finally + CloseHandle(H); + end; + Rec.Lo := Info.nFileSizeLow; + Rec.Hi := Info.nFileSizeHigh; + Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); + IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); +{$ELSE} + Result := True; // Windows ƽ̨ Trueʾ Mapping +{$ENDIF} + end; + +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣ Windows ƽ̨ʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalMD5Stream(Stream, 4096 * 1024, Result, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + MD5Init(Context); + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + MD5Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise ECnNativeException.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise ECnNativeException.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + MD5Final(Context, Result); +{$ENDIF} + end; +end; + +// ָ MD5 +function MD5Stream(Stream: TStream; + CallBack: TCnMD5CalcProgressFunc): TCnMD5Digest; +begin + InternalMD5Stream(Stream, 4096 * 1024, Result, CallBack); +end; + +// ʮƸʽ MD5 Ӵֵ +function MD5Print(const Digest: TCnMD5Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnMD5Digest)); +end; + +// Ƚ MD5 ӴֵǷ +function MD5Match(const D1, D2: TCnMD5Digest): Boolean; +begin + Result := ConstTimeCompareMem(@D1[0], @D2[0], SizeOf(TCnMD5Digest)); +end; + +// MD5 Ӵֵת string +function MD5DigestToStr(const Digest: TCnMD5Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnMD5Digest)); +end; + +procedure MD5HmacInit(var Context: TCnMD5Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnMD5Digest; +begin + if KeyLength > HMAC_MD5_BLOCK_SIZE_BYTE then + begin + Sum := MD5Buffer(Key^, KeyLength); + KeyLength := HMAC_MD5_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_MD5_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_MD5_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + MD5Init(Context); + MD5Update(Context, @(Context.Ipad[0]), HMAC_MD5_BLOCK_SIZE_BYTE); +end; + +procedure MD5HmacUpdate(var Context: TCnMD5Context; Input: PAnsiChar; Length: Cardinal); +begin + MD5Update(Context, Input, Length); +end; + +procedure MD5HmacFinal(var Context: TCnMD5Context; var Output: TCnMD5Digest); +var + Len: Integer; + TmpBuf: TCnMD5Digest; +begin + Len := HMAC_MD5_OUTPUT_LENGTH_BYTE; + MD5Final(Context, TmpBuf); + MD5Init(Context); + MD5Update(Context, @(Context.Opad[0]), HMAC_MD5_BLOCK_SIZE_BYTE); + MD5Update(Context, @(TmpBuf[0]), Len); + MD5Final(Context, Output); +end; + +procedure MD5Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnMD5Digest); +var + Context: TCnMD5Context; +begin + MD5HmacInit(Context, Key, KeyByteLength); + MD5HmacUpdate(Context, Input, ByteLength); + MD5HmacFinal(Context, Output); +end; + +function MD5HmacBytes(const Key: TBytes; const Data: TBytes): TCnMD5Digest; +var + Context: TCnMD5Context; +begin + MD5HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + MD5HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + MD5HmacFinal(Context, Result); +end; + +end. diff --git a/CnPack/Crypto/CnNative.pas b/CnPack/Crypto/CnNative.pas new file mode 100644 index 0000000..6895190 --- /dev/null +++ b/CnPack/Crypto/CnNative.pas @@ -0,0 +1,5498 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnNative; +{* |
+================================================================================ +* ƣCnPack +* Ԫƣ32 λ 64 λƽ̨һЩͳһԼһʵֵԪ +* ԪߣCnPack (master@cnpack.org) +* עԪһ 32 λ 64 λƽ̨һЩͳһʵ֡ +* Delphi XE 2 ֧ 32 64 ų NativeInt NativeUInt +* ǰ 32 λ 64 ̬仯Ӱ쵽 PointerReferenceȶ +* ǵԣ̶ȵ 32 λ Cardinal/Integer Ⱥ Pointer Щ +* ͨˣʹ 32 λҲֹ˱Ԫ˼ͣ +* ͬʱڵͰ汾߰汾 Delphi ʹá +* +* ԪҲڲ֧ UInt64 ı Delphi 5/6/7 Int64 ģ UInt64 +* ĸ㣬ӼȻ֧֣˳Ҫģ div mod +* ַ Integer(APtr) 64 λ MacOS ׳ֽضϣҪ NativeInt +* +* ʵ˴Сءֽת̶ʱȷĴײ㺯빤ࡣ +* +* ƽ̨PWin2000 + Delphi 5.0 +* ݲԣPWin9X/2000/XP + Delphi 5/6/7 XE 2 +* õԪеַϱػʽ +* ļ¼2023.08.14 V2.4 +* ϼʱ̶ĺ +* 2022.11.11 V2.3 +* ϼֽ˳ +* 2022.07.23 V2.2 +* Ӽڴλ㺯תַΪ CnNative +* 2022.06.08 V2.1 +* ĸʱ̶ĽԼڴ浹ź +* 2022.03.14 V2.0 +* Ӽʮת +* 2022.02.17 V1.9 +* FPC ı֧ +* 2022.02.09 V1.8 +* ڵĴСжϺ +* 2021.09.05 V1.7 +* Int64/UInt64 㺯 +* 2020.10.28 V1.6 +* UInt64 صж㺯 +* 2020.09.06 V1.5 +* UInt64 ƽĺ +* 2020.07.01 V1.5 +* ж 32 λ 64 λǷĺ +* 2020.06.20 V1.4 +* 32 λ 64 λȡ͵ 1 λλõĺ +* 2020.01.01 V1.3 +* 32 λ͵ mul 㣬ڲ֧ UInt64 ϵͳ Int64 Ա +* 2018.06.05 V1.2 +* 64 λ͵ div/mod 㣬ڲ֧ UInt64 ϵͳ Int64 +* 2016.09.27 V1.1 +* 64 λ͵һЩ +* 2011.07.06 V1.0 +* Ԫʵֹ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + Classes, SysUtils, SysConst, Math {$IFDEF COMPILER5}, Windows {$ENDIF}; + // D5 Ҫ Windows е PByte +type + ECnNativeException = class(Exception); + {* Native 쳣} + +{$IFDEF COMPILER5} + PByte = Windows.PByte; + {* D5 PByte Windows У汾 System У + ͳһһ¹ʹ PByte ʱ uses Windowsڿƽ̨ͬ} + PWord = Windows.PWord; + {* D5 PWord Windows } + PShortInt = Windows.PShortInt; + {* D5 PShortInt Windows } + PSmallInt = Windows.PSmallInt; + {* D5 PSmallInt Windows } + PInteger = Windows.PInteger; + {* D5 PInteger Windows } + PSingle = Windows.PSingle; + {* D5 PSingle Windows } + PDouble = Windows.PDouble; + {* D5 PDouble Windows } + + PCardinal = ^Cardinal; + {* D5 System Ԫδ Cardinal ָͣ} + PBoolean = ^Boolean; + {* D5 System Ԫδ Boolean ָͣ} +{$ENDIF} + +{$IFDEF BCB5OR6} + PInt64 = ^Int64; + {* C++Builder 5/6 sysmac.h û PInt64 Ķ壨е PUINT64 Сдͬ㣩} +{$ENDIF} + +{$IFDEF SUPPORT_32_AND_64} + TCnNativeInt = NativeInt; + {* ͳһ 32 λ 64 λͨõз} + TCnNativeUInt = NativeUInt; + {* ͳһ 32 λ 64 λͨõ} + TCnNativePointer = NativeInt; + {* ͳһ 32 λ 64 λͨõָ} + TCnNativeIntPtr = PNativeInt; + {* ͳһ 32 λ 64 λͨõָзָ} + TCnNativeUIntPtr = PNativeUInt; + {* ͳһ 32 λ 64 λͨõָָ} +{$ELSE} + TCnNativeInt = Integer; + {* ͳһ 32 λ 64 λͨõз} + TCnNativeUInt = Cardinal; + {* ͳһ 32 λ 64 λͨõ} + TCnNativePointer = Integer; + {* ͳһ 32 λ 64 λͨõָ} + TCnNativeIntPtr = PInteger; + {* ͳһ 32 λ 64 λͨõָзָ} + TCnNativeUIntPtr = PCardinal; + {* ͳһ 32 λ 64 λͨõָָ} +{$ENDIF} + PCnNativeInt = ^TCnNativeInt; + {* ָͳһ 32 λ 64 λͨõз͵ָ} + PCnNativeUInt = ^TCnNativeUInt; + {* ָͳһ 32 λ 64 λͨõ͵ָ} +{$IFDEF FPC} + TCnHashCode = PtrInt; + {* ͳһ Delphi FPC µ HashCode } +{$ELSE} + TCnHashCode = Integer; + {* ͳһ Delphi FPC µ HashCode } +{$ENDIF} + + // еַӼͣ FPC Delphi ¶ԷŵҪ +{$IFDEF FPC} + TCnIntAddress = NativeUInt; + {* ͳһ Delphi FPC µĹеַӼ} +{$ELSE} + {$IFDEF SUPPORT_32_AND_64} + TCnIntAddress = NativeInt; + {* ͳһ Delphi FPC µĹеַӼ} + {$ELSE} + TCnIntAddress = Integer; + {* ͳһ Delphi FPC µĹеַӼ} + {$ENDIF} +{$ENDIF} + +{$IFDEF CPU64BITS} + TCnUInt64 = NativeUInt; + {* ͳһ 64 λ} + TCnInt64 = NativeInt; + {* ͳһ 64 λз} +{$ELSE} + {$IFDEF SUPPORT_UINT64} + TCnUInt64 = UInt64; + {* ͳһ 64 λ} + {$ELSE} + TCnUInt64 = packed record + {* ڲ֧ UInt64 32 λ£ 64 λṹ} + case Boolean of + True: (Value: Int64); + False: (Lo32, Hi32: Cardinal); + end; + {$ENDIF} + TCnInt64 = Int64; + {* ͳһ 64 λ} +{$ENDIF} + +// TUInt64 cnvcl в֧ UInt64 div mod +{$IFDEF SUPPORT_UINT64} + TUInt64 = UInt64; + {* ͳһ 64 λ} + {$IFNDEF SUPPORT_PUINT64} + PUInt64 = ^UInt64; + {* ͳһָ 64 λָ} + {$ENDIF} +{$ELSE} + TUInt64 = Int64; + {* ͳһ 64 λͣ cnvcl в֧ UInt64 } + PUInt64 = ^TUInt64; + {* ͳһָ 64 λָͣ cnvcl в֧ UInt64 } +{$ENDIF} + +{$IFNDEF SUPPORT_INT64ARRAY} + Int64Array = array[0..$0FFFFFFE] of Int64; + {* ϵͳûж Int64Array 64 λз} + PInt64Array = ^Int64Array; + {* ϵͳûж PInt64Array 64 λзָ} +{$ENDIF} + + TUInt64Array = array of TUInt64; + {* ͳһ 64 λ̬飬ע̬ƺ;̬гͻ} + ExtendedArray = array[0..65537] of Extended; + {* չȸ} + PExtendedArray = ^ExtendedArray; + {* չȸָ} + + PCnWord16Array = ^TCnWord16Array; + {* 16 λָ} + TCnWord16Array = array [0..0] of Word; + {* 16 λ} + +{$IFDEF POSIX64} + TCnLongWord32 = Cardinal; + {* ͳһ 32 λ LongWordΪ Linux64/MacOS64 POSIX64 LongWord Ȼ 64 λ} +{$ELSE} + TCnLongWord32 = LongWord; + {* ͳһ 32 λ LongWord} +{$ENDIF} + PCnLongWord32 = ^TCnLongWord32; + {* ͳһָ 32 λ LongWord ָ} + + TCnLongWord32Array = array [0..MaxInt div SizeOf(Integer) - 1] of TCnLongWord32; + {* ͳһ 32 λ LongWord } + + PCnLongWord32Array = ^TCnLongWord32Array; + {* ͳһ 32 λ LongWord ָ} + +{$IFNDEF TBYTES_DEFINED} + TBytes = array of Byte; + {* ֽڶ̬飬δʱ} +{$ENDIF} + + TShortInts = array of ShortInt; + {* зֽڶ̬} + + TSmallInts = array of SmallInt; + {* з˫ֽڶ̬} + + TWords = array of Word; + {* ˫ֽڶ̬} + + TIntegers = array of Integer; + {* зֽڶ̬} + + TCardinals = array of Cardinal; + {* ֽڶ̬} + + TBooleans = array of Boolean; + {* ̬} + + PCnByte = ^Byte; + {* ָ 8 λָ} + PCnWord = ^Word; + {* ָ 16 λָ} + + TCnBitOperation = (boAnd, boOr, boXor, boNot); + {* λ} + + // ʹõľ̬з + PCnInt8Array = ^TCnInt8Array; + {* ̬ 8 λзָ} + TCnInt8Array = array[0..(MaxInt div SizeOf(ShortInt) - 1)] of ShortInt; + {* ̬ 8 λз} + + PCnUInt8Array = ^TCnUInt8Array; + {* ̬ 8 λָ} + TCnUInt8Array = array[0..(MaxInt div SizeOf(Byte) - 1)] of Byte; + {* ̬ 8 λ} + + PCnInt16Array = ^TCnInt16Array; + {* ̬ 16 λзָ} + TCnInt16Array = array[0..(MaxInt div SizeOf(SmallInt) - 1)] of SmallInt; + {* ̬ 16 λз} + + PCnUInt16Array = ^TCnUInt16Array; + {* ̬ 16 λָ} + TCnUInt16Array = array[0..(MaxInt div SizeOf(Word) - 1)] of Word; + {* ̬ 16 λ} + + PCnInt32Array = ^TCnInt32Array; + {* ̬ 32 λзָ} + TCnInt32Array = array[0..(MaxInt div SizeOf(Integer) - 1)] of Integer; + {* ̬ 32 λз} + + PCnUInt32Array = ^TCnUInt32Array; + {* ̬ 32 λָ} + TCnUInt32Array = array[0..(MaxInt div SizeOf(Cardinal) - 1)] of Cardinal; + {* ̬ 32 λ} + + PCnInt64Array = ^TCnInt64Array; + {* ̬ 64 λзָ} + TCnInt64Array = array[0..(MaxInt div SizeOf(Int64) - 1)] of Int64; + {* ̬ 64 λз} + + PCnUInt64Array = ^TCnUInt64Array; + {* ̬ 64 λָ} + TCnUInt64Array = array[0..(MaxInt div SizeOf(TUInt64) - 1)] of TUInt64; + {* ̬ 64 λ} + +type + TCnMemSortCompareProc = function (P1, P2: Pointer; ElementByteSize: Integer): Integer; + {* ڴ̶ߴȽϺԭ} + +const + CN_MAX_SQRT_INT64: Cardinal = 3037000499; + {* 64 λзΧƽ} + CN_MAX_INT8: ShortInt = $7F; + {* 8 λз} + CN_MIN_INT8: ShortInt = -128; + {* С 8 λз} + CN_MAX_INT16: SmallInt = $7FFF; + {* 16 λз} + CN_MIN_INT16: SmallInt = -32768; + {* С 16 λз} + CN_MAX_INT32: Integer = $7FFFFFFF; + {* 32 λз} +{$WARNINGS OFF} + CN_MIN_INT32: Integer = $80000000; + {* С 32 λз -2147483648} + // 뾯棬д -2147483648 +{$WARNINGS ON} + CN_MIN_INT32_IN_INT64: Int64 = $0000000080000000; + {* 64 λзΧС 32 λз -2147483648} + CN_MAX_INT64: Int64 = $7FFFFFFFFFFFFFFF; + {* 64 λз} + CN_MIN_INT64: Int64 = $8000000000000000; + {* С 64 λз} + CN_MAX_UINT8: Byte = $FF; + {* 8 λ} + CN_MAX_UINT16: Word = $FFFF; + {* 16 λ} + CN_MAX_UINT32: Cardinal = $FFFFFFFF; + {* 32 λ} + CN_MAX_TUINT64: TUInt64 = $FFFFFFFFFFFFFFFF; + {* 64 λ} + CN_MAX_SIGNED_INT64_IN_TUINT64: TUInt64 = $7FFFFFFFFFFFFFFF; + {* 64 λΧ 64 λз} + +{* + D567 Ȳ֧ UInt64 ıȻ Int64 UInt64 мӼ洢 + ˳ֱɣװ System е _lludiv _llumod + ʵ Int64 ʾ UInt64 ݵ div mod ܡ +} +function UInt64Mod(A: TUInt64; B: TUInt64): TUInt64; +{* 64 λࡣ + + + A: TUInt64 - + B: TUInt64 - + + ֵTUInt64 - +} + +function UInt64Div(A: TUInt64; B: TUInt64): TUInt64; +{* 64 λ + + + A: TUInt64 - + B: TUInt64 - + + ֵTUInt64 - +} + +function UInt64Mul(A: Cardinal; B: Cardinal): TUInt64; +{* 32 λˡڲ֧ UInt64 ƽ̨ϣ UInt64 ʽ Int64 + ֱʹ Int64 п + + + A: Cardinal - һ + B: Cardinal - + + ֵTUInt64 - +} + +procedure UInt64AddUInt64(A: TUInt64; B: TUInt64; var ResLo: TUInt64; var ResHi: TUInt64); +{* 64 λӣ ResLo ResHi С + עڲʵְ㷨ΪӣʵResHi Ȼ 1ֱж 1 + + + A: TUInt64 - һ + B: TUInt64 - + var ResLo: TUInt64 - ͵λ + var ResHi: TUInt64 - λ + + ֵޣ +} + +procedure UInt64MulUInt64(A: TUInt64; B: TUInt64; var ResLo: TUInt64; var ResHi: TUInt64); +{* 64 λˣ ResLo ResHi СWin 64 λûʵ֣Լһϡ + + + A: TUInt64 - һ + B: TUInt64 - + var ResLo: TUInt64 - λ + var ResHi: TUInt64 - λ + + ֵޣ +} + +function UInt64ToHex(N: TUInt64; RemoveZeroPrefix: Boolean = False): string; +{* 64 λתΪʮַ + + + N: TUInt64 - תֵ + RemoveZeroPrefix: Boolean - Ƿȥתλ 0Ĭϲȥ + + ֵstring - ʮַ +} + +function UInt64ToStr(N: TUInt64): string; +{* 64 λתΪʮַ + + + N: TUInt64 - תֵ + + ֵstring - ʮַ +} + +function StrToUInt64(const S: string): TUInt64; +{* ַתΪ 64 λ + + + const S: string - תַ + + ֵTUInt64 - ת +} + +function UInt64Compare(A: TUInt64; B: TUInt64): Integer; +{* Ƚ 64 λֱֵݱȽϵĽǴڡڻС 10-1 + + + A: TUInt64 - Ƚϵһ + B: TUInt64 - Ƚϵ + + ֵInteger - رȽϽ +} + +function UInt64Sqrt(N: TUInt64): TUInt64; +{* 64 λƽ֡ + + + N: TUInt64 - ƽ + + ֵTUInt64 - ƽ +} + +function UInt32IsNegative(N: Cardinal): Boolean; +{* ж 32 λ 32 λзʱǷС 0 + + + N: Cardinal - жϵֵ + + ֵBoolean - ǷС 0 +} + +function UInt64IsNegative(N: TUInt64): Boolean; +{* ж 64 λ 64 λзʱǷС 0 + + + N: TUInt64 - жϵֵ + + ֵBoolean - ǷС 0 +} + +procedure UInt64SetBit(var B: TUInt64; Index: Integer); +{* 64 λijһλ 1λ Index 0 ʼ 63 + + + var B: TUInt64 - λֵ + Index: Integer - 1 λ + + ֵޣ +} + +procedure UInt64ClearBit(var B: TUInt64; Index: Integer); +{* 64 λijһλ 0λ Index 0 ʼ 63 + + + var B: TUInt64 - λֵ + Index: Integer - 0 λ + + ֵޣ +} + +function GetUInt64BitSet(B: TUInt64; Index: Integer): Boolean; +{* 64 λijһλǷ 1λ Index 0 ʼ 63 + + + B: TUInt64 - жϵֵ + Index: Integer - жϵλ + + ֵBoolean - ظλǷ 1 +} + +function GetUInt64HighBits(B: TUInt64): Integer; +{* 64 λ 1 ߶λǵڼλλ 0û 1 -1 + + + B: TUInt64 - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt32HighBits(B: Cardinal): Integer; +{* 32 λ 1 ߶λǵڼλλ 0û 1 -1 + + + B: Cardinal - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt16HighBits(B: Word): Integer; +{* 16 λ 1 ߶λǵڼλλ 0û 1 -1 + + + B: Word - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt8HighBits(B: Byte): Integer; +{* 8 λ 1 ߶λǵڼλλ 0û 1 -1 + + + B: Byte - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt64BitLength(B: TUInt64): Integer; +{* 64 λȥλ 0 ʣµλȣû 1 0 + + + B: TUInt64 - жϵֵ + + ֵInteger - Чλ +} + +function GetUInt32BitLength(B: Cardinal): Integer; +{* 32 λȥλ 0 ʣµλȣû 1 0 + + + B: Cardinal - жϵֵ + + ֵInteger - Чλ +} + +function GetUInt16BitLength(B: Word): Integer; +{* 16 λȥλ 0 ʣµλȣû 1 0 + + + B: Word - жϵֵ + + ֵInteger - Чλ +} + +function GetUInt8BitLength(B: Byte): Integer; +{* 8 λȥλ 0 ʣµλȣû 1 0 + + + B: Byte - жϵֵ + + ֵInteger - Чλ +} + +function GetUInt64LowBits(B: TUInt64): Integer; +{* 64 λ 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 + + + B: TUInt64 - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt32LowBits(B: Cardinal): Integer; +{* 32 λ 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 + + + B: Cardinal - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt16LowBits(B: Word): Integer; +{* 16 λ 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 + + + B: Word - жϵֵ + + ֵInteger - 1 λ +} + +function GetUInt8LowBits(B: Byte): Integer; +{* 8 λ 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 + + + B: Byte - жϵֵ + + ֵInteger - 1 λ +} + +function Int64Mod(M: Int64; N: Int64): Int64; +{* װ Int64 ModM ֵʱȡģģ N Ҫס + + + M: Int64 - + N: Int64 - + + ֵInt64 - +} + +function Int64CenterMod(A: Int64; N: Int64): Int64; +{* A mod N Ļ (-(N - 1)/2 ½磨, (N - 1)/ 2 ½磨 0] + Ҫ N ע⣬Ļǽ A mod N ֵƣdzһֱӼ N + һľȷǣ N/2 ִģֱӼ N N ż + ڱ߽磺һ仰ԳżϿ + N 7 [-3, 3] 3 Ķ 7ע 3 + N 6 [-2, 3] 3 Ķ 6ע 3 Ҳ + N Ϊʱ(N - 1)żԶ 0 һ N 0 N - 1ӳ䵽 [-(N - 1)/2, (N - 1)/2] + N ΪżʱN/2 ż߽ -N/2 + 1ұ߽ N/20 N - 1ӳ䵽 [-N/2 + 1, N/2] + + + A: Int64 - Ļֵ + N: Int64 - ģ + + ֵInt64 - Ļ +} + +function IsUInt32PowerOf2(N: Cardinal): Boolean; +{* жһ 32 λǷ 2 ݡ + + + N: Cardinal - жϵֵ + + ֵBoolean - Ƿ 2 +} + +function IsUInt64PowerOf2(N: TUInt64): Boolean; +{* жһ 64 λǷ 2 ݡ + + + N: TUInt64 - жϵֵ + + ֵBoolean - Ƿ 2 +} + +function GetUInt32PowerOf2GreaterEqual(N: Cardinal): Cardinal; +{* õһָ 32 λȵ 2 ݣ 0 + + + N: Cardinal - ֵ + + ֵCardinal - ط 2 ݻ 0 +} + +function GetUInt64PowerOf2GreaterEqual(N: TUInt64): TUInt64; +{* õһָ 64 λȵ 2 ݣ 0 + + + N: TUInt64 - ֵ + + ֵTUInt64 - ط 2 ݻ 0 +} + +function IsInt32AddOverflow(A: Integer; B: Integer): Boolean; +{* ж 32 λзǷ 32 λзޡ + + + A: Integer - һ + B: Integer - + + ֵBoolean - Ƿ +} + +function IsUInt32AddOverflow(A: Cardinal; B: Cardinal): Boolean; +{* ж 32 λǷ 32 λޡ + + + A: Cardinal - һ + B: Cardinal - + + ֵBoolean - Ƿ +} + +function IsInt64AddOverflow(A: Int64; B: Int64): Boolean; +{* ж 64 λзǷ 64 λзޡ + + + A: Int64 - һ + B: Int64 - + + ֵBoolean - Ƿ +} + +function IsUInt64AddOverflow(A: TUInt64; B: TUInt64): Boolean; +{* ж 64 λǷ 64 λޡ + + + A: TUInt64 - һ + B: TUInt64 - + + ֵBoolean - Ƿ +} + +function IsUInt64SubOverflowInt32(A: TUInt64; B: TUInt64): Boolean; +{* жһ 64 λȥһ 64 λĽǷ 32 λзΧ + 64 λе JMP תжϡ + + + A: TUInt64 - + B: TUInt64 - + + ֵBoolean - Ƿ 32 λзΧ +} + +procedure UInt64Add(var R: TUInt64; A: TUInt64; B: TUInt64; out Carry: Integer); +{* 64 λӣA + B => R 1 ýλλ㡣 + + + var R: TUInt64 - + A: TUInt64 - һ + B: TUInt64 - + out Carry: Integer - λ + + ֵޣ +} + +procedure UInt64Sub(var R: TUInt64; A: TUInt64; B: TUInt64; out Carry: Integer); +{* 64 λA - B => Rнλ 1 ýλλ㡣 + + + var R: TUInt64 - + A: TUInt64 - + B: TUInt64 - + out Carry: Integer - λ + + ֵޣ +} + +function IsInt32MulOverflow(A: Integer; B: Integer): Boolean; +{* ж 32 λзǷ 32 λзޡ + + + A: Integer - һ + B: Integer - + + ֵBoolean - Ƿ +} + +function IsUInt32MulOverflow(A: Cardinal; B: Cardinal): Boolean; +{* ж 32 λǷ 32 λ + + + A: Cardinal - һ + B: Cardinal - + + ֵBoolean - Ƿ +} + +function IsUInt32MulOverflowInt64(A: Cardinal; B: Cardinal; out R: TUInt64): Boolean; +{* ж 32 λǷ 64 λзޣδҲ False ʱR ֱӷؽ + Ҳ TrueҪµ UInt64Mul ʵʩˡ + + + A: Cardinal - һ + B: Cardinal - + out R: TUInt64 - δʱػ + + ֵBoolean - Ƿ +} + +function IsInt64MulOverflow(A: Int64; B: Int64): Boolean; +{* ж 64 λзǷ 64 λзޡ + + + A: Int64 - һ + B: Int64 - + + ֵBoolean - Ƿ +} + +function PointerToInteger(P: Pointer): Integer; +{* ָת֧ͣ 32/64 λע 64 λ¿ܻᶪ 32 λݡ + + + P: Pointer - תָ + + ֵInteger - ת +} + +function IntegerToPointer(I: Integer): Pointer; +{* תָ֧ͣ 32/64 λ + + + I: Integer - ת + + ֵPointer - תָ +} + +function Int64NonNegativeAddMod(A: Int64; B: Int64; N: Int64): Int64; +{* 64 λзΧĺ࣬Ҫ N 0 + + + A: Int64 - һ + B: Int64 - һ + N: Int64 - ģ + + ֵInt64 - Ľ +} + +function UInt64NonNegativeAddMod(A: TUInt64; B: TUInt64; N: TUInt64): TUInt64; +{* 64 λΧĺ࣬Ҫ N 0 + + + A: TUInt64 - һ + B: TUInt64 - + N: TUInt64 - ģ + + ֵTUInt64 - Ľ +} + +function Int64NonNegativeMulMod(A: Int64; B: Int64; N: Int64): Int64; +{* 64 λзΧڵֱ࣬Ӽ㣬Ҫ N 0 + + + A: Int64 - һ + B: Int64 - + N: Int64 - ģ + + ֵInt64 - Ľ +} + +function UInt64NonNegativeMulMod(A: TUInt64; B: TUInt64; N: TUInt64): TUInt64; +{* 64 λΧڵֱ࣬Ӽ㣬 + + + A: TUInt64 - һ + B: TUInt64 - + N: TUInt64 - ģ + + ֵTUInt64 - Ľ +} + +function Int64NonNegativeMod(N: Int64; P: Int64): Int64; +{* װ 64 λзķǸຯҲΪʱӸ豣֤ P 0 + + + N: Int64 - + P: Int64 - + + ֵInt64 - طǸĽ +} + +function Int64NonNegativPower(N: Int64; Exp: Integer): Int64; +{* 64 λзķǸָݣ + + + N: Int64 - + Exp: Integer - ָҪ 0 + + ֵInt64 - ݵĽ +} + +function Int64NonNegativeRoot(N: Int64; Exp: Integer): Int64; +{* 64 λзķǸη֣ + + + N: Int64 - + Exp: Integer - + + ֵInt64 - ؿֽ +} + +function UInt64NonNegativPower(N: TUInt64; Exp: Integer): TUInt64; +{* 64 λķǸָݣ + + + N: TUInt64 - + Exp: Integer - ָҪ 0 + + ֵTUInt64 - ݵĽ +} + +function UInt64NonNegativeRoot(N: TUInt64; Exp: Integer): TUInt64; +{* 64 λķǸη֣ + + + N: TUInt64 - + Exp: Integer - + + ֵTUInt64 - ؿֽ +} + +function CurrentByteOrderIsBigEndian: Boolean; +{* صǰڻǷǴˣҲǷеĸֽڴ洢ڽϵ͵ʼַ + ϴҵĶϰߣ粿ָ ARM MIPS + + + ޣ + + ֵBoolean - صǰڻǷǴ +} + +function CurrentByteOrderIsLittleEndian: Boolean; +{* صǰڻǷСˣҲǷеĸֽڴ洢ڽϸߵʼַ x86 벿Ĭ ARM + + + ޣ + + ֵBoolean - صǰڻǷС +} + +function Int64ToBigEndian(Value: Int64): Int64; +{* ȷ 64 λзֵΪˣС˻лת + + + Value: Int64 - ת 64 λз + + ֵInt64 - شֵ +} + +function Int32ToBigEndian(Value: Integer): Integer; +{* ȷ 32 λзֵΪˣС˻лת + + + Value: Integer - ת 32 λз + + ֵInteger - شֵ +} + +function Int16ToBigEndian(Value: SmallInt): SmallInt; +{* ȷ 16 λзֵΪˣС˻лת + + + Value: SmallInt - ת 16 λз + + ֵSmallInt - شֵ +} + +function Int64ToLittleEndian(Value: Int64): Int64; +{* ȷ 64 λзֵΪСˣڴ˻лת + + + Value: Int64 - ת 64 λз + + ֵInt64 - شֵ +} + +function Int32ToLittleEndian(Value: Integer): Integer; +{* ȷ 32 λзֵΪСˣڴ˻лת + + + Value: Integer - ת 32 λз + + ֵInteger - Сֵ +} + +function Int16ToLittleEndian(Value: SmallInt): SmallInt; +{* ȷ 16 λзֵΪСˣڴ˻лת + + + Value: SmallInt - ת 16 λз + + ֵSmallInt - Сֵ +} + +function UInt64ToBigEndian(Value: TUInt64): TUInt64; +{* ȷ 64 λֵΪˣС˻лת + + + Value: TUInt64 - ת 64 λ + + ֵTUInt64 - شֵ +} + +function UInt32ToBigEndian(Value: Cardinal): Cardinal; +{* ȷ 32 λֵΪˣС˻лת + + + Value: Cardinal - ת 32 λ + + ֵCardinal - شֵ +} + +function UInt16ToBigEndian(Value: Word): Word; +{* ȷ 16 λֵΪˣС˻лת + + + Value: Word - ת 16 λ + + ֵWord - شֵ +} + +function UInt64ToLittleEndian(Value: TUInt64): TUInt64; +{* ȷ 64 λֵΪСˣڴ˻лת + + + Value: TUInt64 - ת 64 λ + + ֵTUInt64 - شֵ +} + +function UInt32ToLittleEndian(Value: Cardinal): Cardinal; +{* ȷ 32 λֵΪСˣڴ˻лת + + + Value: Cardinal - ת 32 λ + + ֵCardinal - Сֵ +} + +function UInt16ToLittleEndian(Value: Word): Word; +{* ȷ 16 λֵΪСˣڴ˻лת + + + Value: Word - ת 16 λ + + ֵWord - Сֵ +} + +function Int64HostToNetwork(Value: Int64): Int64; +{* 64 λзֵֽ˳תΪֽ˳С˻лת + + + Value: Int64 - ת 64 λз + + ֵInt64 - ֽ˳ֵ +} + +function Int32HostToNetwork(Value: Integer): Integer; +{* 32 λзֵֽ˳תΪֽ˳С˻лת + + + Value: Integer - ת 32 λз + + ֵInteger - ֽ˳ֵ +} + +function Int16HostToNetwork(Value: SmallInt): SmallInt; +{* 16 λзֵֽ˳תΪֽ˳С˻лת + + + Value: SmallInt - ת 16 λз + + ֵSmallInt - ֽ˳ֵ +} + +function Int64NetworkToHost(Value: Int64): Int64; +{* 64 λзֵֽ˳תΪֽ˳С˻лת + + + Value: Int64 - ת 64 λз + + ֵInt64 - ֽ˳ֵ +} + +function Int32NetworkToHost(Value: Integer): Integer; +{* 32 λзֵֽ˳תΪֽ˳С˻лת + + + Value: Integer - ת 32 λз + + ֵInteger - ֽ˳ֵ +} + +function Int16NetworkToHost(Value: SmallInt): SmallInt; +{* 16 λзֵֽ˳תΪֽ˳С˻лת + + + Value: SmallInt - ת 16 λз + + ֵSmallInt - ֽ˳ֵ +} + +function UInt64HostToNetwork(Value: TUInt64): TUInt64; +{* 64 λֵֽ˳תΪֽ˳С˻лת + + + Value: TUInt64 - ת 64 λ + + ֵTUInt64 - ֽ˳ֵ +} + +function UInt32HostToNetwork(Value: Cardinal): Cardinal; +{* 32 λֵֽ˳תΪֽ˳С˻лת + + + Value: Cardinal - ת 32 λ + + ֵCardinal - ֽ˳ֵ +} + +function UInt16HostToNetwork(Value: Word): Word; +{* 16 λֵֽ˳תΪֽ˳С˻лת + + + Value: Word - ת 16 λ + + ֵWord - ֽ˳ֵ +} + +function UInt64NetworkToHost(Value: TUInt64): TUInt64; +{* 64 λֵֽ˳תΪֽ˳С˻лת + + + Value: TUInt64 - ת 64 λ + + ֵTUInt64 - ֽ˳ֵ +} + +function UInt32NetworkToHost(Value: Cardinal): Cardinal; +{* 32 λֵֽ˳תΪֽ˳С˻лת + + + Value: Cardinal - ת 32 λ + + ֵCardinal - ֽ˳ֵ +} + +function UInt16NetworkToHost(Value: Word): Word; +{* 16 λֵֽ˳תΪֽ˳С˻лת + + + Value: Word - ת 16 λ + + ֵWord - ֽ˳ֵ +} + +procedure MemoryNetworkToHost(Mem: Pointer; MemByteLen: Integer); +{* һƬڴֽ˳תΪֽ˳С˻лת + ÷ӦóϽ٣¶ġֽתѾ㹻 + + + Mem: Pointer - תݿַ + MemByteLen: Integer - תݿֽڳ + + ֵޣ +} + +procedure MemoryHostToNetwork(Mem: Pointer; MemByteLen: Integer); +{* һƬڴֽ˳תΪֽ˳С˻лת + ÷ӦóϽ٣¶ġֽתѾ㹻 + + + Mem: Pointer - תݿַ + MemByteLen: Integer - תݿֽڳ + + ֵޣ +} + +procedure ReverseMemory(Mem: Pointer; MemByteLen: Integer); +{* ֽ˳һڴ飬ֽڲ䡣 + + + Mem: Pointer - õݿַ + MemByteLen: Integer - õݿֽڳ + + ֵޣ +} + +function ReverseBitsInInt8(V: Byte): Byte; +{* һֽڲλݡ + + + V: Byte - õһֽ + + ֵByte - صֵ +} + +function ReverseBitsInInt16(V: Word): Word; +{* öֽڼڲλݡ + + + V: Word - õĶֽ + + ֵWord - صֵ +} + +function ReverseBitsInInt32(V: Cardinal): Cardinal; +{* ֽڼڲλݡ + + + V: Cardinal - õֽ + + ֵCardinal - صֵ +} + +function ReverseBitsInInt64(V: Int64): Int64; +{* ðֽڼڲλݡ + + + V: Int64 - õİֽ + + ֵInt64 - صֵ +} + +procedure ReverseMemoryWithBits(Mem: Pointer; MemByteLen: Integer); +{* ֽ˳һڴ飬ÿֽҲ + + + Mem: Pointer - õݿַ + MemByteLen: Integer - õݿֽڳ + + ֵޣ +} + +procedure MemoryAnd(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +{* 鳤ͬڴ AMem BMem λ룬 ResMem У߿ͬ + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + ResMem: Pointer - ݿַ + + ֵޣ +} + +procedure MemoryOr(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +{* 鳤ͬڴ AMem BMem λ ResMem У߿ͬ + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + ResMem: Pointer - ݿַ + + ֵޣ +} + +procedure MemoryXor(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +{* 鳤ͬڴ AMem BMem λ ResMem У߿ͬ + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + ResMem: Pointer - ݿַ + + ֵޣ +} + +procedure MemoryNot(Mem: Pointer; MemByteLen: Integer; ResMem: Pointer); +{* һڴ AMem ȡ ResMem У߿ͬ + + + Mem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + ResMem: Pointer - ݿַ + + ֵޣ +} + +procedure MemoryShiftLeft(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; BitCount: Integer); +{* AMem ڴ BitCount λ BMemڴַλƣλ 0߿ȡ + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + BitCount: Integer - Ƶλ + + ֵޣ +} + +procedure MemoryShiftRight(AMem: Pointer; BMem: Pointer; MemByteLen: Integer; BitCount: Integer); +{* AMem ڴ BitCount λ BMemڴַλƣλ 0߿ȡ + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + BitCount: Integer - Ƶλ + + ֵޣ +} + +function MemoryIsBitSet(Mem: Pointer; N: Integer): Boolean; +{* ڴij Bit λǷ 1ڴַλ 0ֽڻұΪ 0 + + + Mem: Pointer - ݿַ + N: Integer - λ + + ֵBoolean - Ƿ 1 +} + +procedure MemorySetBit(Mem: Pointer; N: Integer); +{* ڴij Bit λ 1ڴַλ 0ֽڻұΪ 0 + + + Mem: Pointer - ݿַ + N: Integer - λ + + ֵޣ +} + +procedure MemoryClearBit(Mem: Pointer; N: Integer); +{* ڴij Bit λ 0ڴַλ 0ֽڻұΪ 0 + + + Mem: Pointer - ݿַ + N: Integer - λ + + ֵޣ +} + +function MemoryGetHighBits(Mem: Pointer; MemByteLen: Integer): Integer; +{* ڴ 1 ߶λǵڼλߡָ͵ַû 1 -1 + ڴӵַ͵߱Ϊ 8 * MemByteLen - 1 0 ôλĩֽڵλ 0 λ + + + Mem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + + ֵInteger - 1 λ +} + +function MemoryGetLowBits(Mem: Pointer; MemByteLen: Integer): Integer; +{* ڴ 1 Ͷλǵڼλָ͡ߵַû 1 -1 + ڴӵַ͵߱Ϊ 8 * MemByteLen - 1 0 ôλĩֽڵλ 0 λ + + + Mem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + + ֵInteger - 1 λ +} + +function MemoryToBinStr(Mem: Pointer; MemByteLen: Integer; Sep: Boolean = False): string; +{* һڴݴӵ͵ֽ˳ΪַSep ʾֽ֮Ƿոָ + + + Mem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + Sep: Boolean - ֽ֮Ƿÿոָ + + ֵstring - ضַ +} + +procedure MemorySwap(AMem: Pointer; BMem: Pointer; MemByteLen: Integer); +{* ͬȵڴݣͬڴʲô + + + AMem: Pointer - ݿַһ + BMem: Pointer - ݿַ + MemByteLen: Integer - ݿֽڳ + + ֵޣ +} + +function MemoryCompare(AMem: Pointer; BMem: Pointer; MemByteLen: Integer): Integer; +{* ķʽȽڴ棬 10-1ͬڴֱӷ 0 + + + AMem: Pointer - Ƚϵݿַһ + BMem: Pointer - Ƚϵݿַ + MemByteLen: Integer - Ƚϵݿֽڳ + + ֵInteger - رȽϵĽ +} + +procedure MemoryQuickSort(Mem: Pointer; ElementByteSize: Integer; + ElementCount: Integer; CompareProc: TCnMemSortCompareProc = nil); +{* Թ̶СԪص + + + Mem: Pointer - ݿַ + ElementByteSize: Integer - Ԫֽڳ + ElementCount: Integer - ݿԪصĸ + CompareProc: TCnMemSortCompareProc - ԪرȽϵĻص + + ֵޣ +} + +function UInt8ToBinStr(V: Byte): string; +{* һ 8 λתΪַ + + + V: Byte - ת 8 λ + + ֵstring - ضַ +} + +function UInt16ToBinStr(V: Word): string; +{* һ 16 λתΪַ + + + V: Word - ת 16 λ + + ֵstring - ضַ +} + +function UInt32ToBinStr(V: Cardinal): string; +{* һ 32 λתΪַ + + + V: Cardinal - ת 32 λ + + ֵstring - ضַ +} + +function UInt32ToStr(V: Cardinal): string; +{* һ 32 λתΪʮַ + + + V: Cardinal - ת 32 λ + + ֵstring - ʮַ +} + +function UInt64ToBinStr(V: TUInt64): string; +{* һ 64 λתΪַ + + + V: TUInt64 - ת 64 λ + + ֵstring - ضַ +} + +function StrToUInt(const S: string): Cardinal; +{* ַתΪ 32 λ + + + const S: string - תַ + + ֵCardinal - ת +} + +function HexToInt(const Hex: string): Integer; overload; +{* һʮַתΪͣʺϽ϶ 2 ַַ + + + const Hex: string - תʮַ + + ֵInteger - +} + +function HexToInt(Hex: PChar; CharLen: Integer): Integer; overload; +{* һʮַָָתΪͣʺϽ϶ 2 ַַ + + + Hex: PChar - תʮַַ + CharLen: Integer - ַ + + ֵInteger - +} + +function IsHexString(const Hex: string): Boolean; +{* жһַǷϷʮִַСд + + + const Hex: string - жϵʮַ + + ֵBoolean - ǷǺϷʮַ +} + +function DataToHex(InData: Pointer; ByteLength: Integer; UseUpperCase: Boolean = True): string; +{* ڴתΪʮַڴλݳַ൱ֽ˳ + UseUpperCase ݵĴСд + + + InData: Pointer - תݿַ + ByteLength: Integer - תݿֽڳ + UseUpperCase: Boolean - ʮַڲǷд + + ֵstring - ʮַ +} + +function HexToData(const Hex: string; OutData: Pointer = nil): Integer; +{* ʮַתΪڴ飬ַݳڴλ൱ֽ˳ + ʮַΪתʧʱ׳쳣תɹֽ + ע OutData Ӧָ㹻תݵֽڳΪ Length(Hex) div 2 + nilֻֽڳȣʽת + + + const Hex: string - תʮַ + OutData: Pointer - ֽڳӦΪ Length(Hex) div 2 + + ֵInteger - תֽڳ +} + +function StringToHex(const Data: string; UseUpperCase: Boolean = True): string; +{* ַתΪʮַUseUpperCase ݵĴСд + + + const Data: string - תַ + UseUpperCase: Boolean - ʮַڲǷд + + ֵstring - תʮַ +} + +function HexToString(const Hex: string): string; +{* ʮַתΪַʮַΪתʧʱ׳쳣 + + + const Hex: string - תʮַ + + ֵstring - תַ +} + +function HexToAnsiStr(const Hex: AnsiString): AnsiString; +{* ʮַתΪַʮַΪתʧʱ׳쳣 + + + const Hex: AnsiString - תʮַ + + ֵAnsiString - תַ +} + +function AnsiStrToHex(const Data: AnsiString; UseUpperCase: Boolean = True): AnsiString; +{* AnsiString תΪʮַUseUpperCase ݵĴСд + + + const Data: AnsiString - תַ + UseUpperCase: Boolean - ʮַڲǷд + + ֵAnsiString - ʮַ +} + +function BytesToHex(const Data: TBytes; UseUpperCase: Boolean = True): string; +{* ֽתΪʮַ±λݳַ൱ֽ˳ + UseUpperCase ݵĴСд + + + const Data: TBytes - תֽ + UseUpperCase: Boolean - ʮַڲǷд + + ֵstring - ʮַ +} + +function HexToBytes(const Hex: string): TBytes; +{* ʮַתΪֽ飬ַߵݳ±λ൱ֽ˳ + ַΪתʧʱ׳쳣 + + + const Hex: string - תʮַ + + ֵTBytes - ½ֽ +} + +function StreamToHex(Stream: TStream; UseUpperCase: Boolean = True): string; +{* еȫݴͷתΪʮַ + + + Stream: TStream - + UseUpperCase: Boolean - ʮַڲǷд + + ֵstring - ʮַ +} + +function HexToStream(const Hex: string; Stream: TStream): Integer; +{* ʮַתдУдֽ + + + const Hex: string - תʮַ + Stream: TStream - д + + ֵInteger - дֽ +} + +function WriteBytesToStream(const Data: TBytes; Stream: TStream): Integer; +{* ֽдУдֽ + + + const Data: TBytes - дֽ + Stream: TStream - д + + ֵInteger - дֽ +} + +procedure ReverseBytes(Data: TBytes); +{* ֽ˳һֽݡ + + + Data: TBytes - õֽ + + ֵޣ +} + +function CloneBytes(const Data: TBytes): TBytes; +{* һµֽ + + + const Data: TBytes - Ƶֽ + + ֵTBytes - ½ֽ +} + +function StreamToBytes(Stream: TStream): TBytes; +{* ͷȫֽ飬½ֽ顣 + + + Stream: TStream - + + ֵTBytes - ½ֽ +} + +function BytesToStream(const Data: TBytes; OutStream: TStream): Integer; +{* ֽдԭʼдֽ + + + const Data: TBytes - дֽ + OutStream: TStream - д + + ֵInteger - дֽ +} + +function AnsiToBytes(const Str: AnsiString): TBytes; +{* AnsiString ֱתΪֽ飬롣 + + + const Str: AnsiString - תַ + + ֵTBytes - תֽ +} + +function BytesToAnsi(const Data: TBytes): AnsiString; +{* ֱֽתΪ AnsiString롣 + + + const Data: TBytes - תֽ + + ֵAnsiString - תַ +} + +function BytesToString(const Data: TBytes): string; +{* ֽתΪ stringڲ Byte ֵΪ Char롣 + + + const Data: TBytes - תֽ + + ֵstring - תַ +} + +function MemoryToString(Mem: Pointer; MemByteLen: Integer): string; +{* ڴתΪ stringڲֽڸֵ롣 + + + Mem: Pointer - תݿַ + MemByteLen: Integer - תݿֽڳ + + ֵstring - תַ +} + +function BitsToString(Bits: TBits): string; +{* λתΪ 0 1 ַ + + + Bits: TBits - תλ + + ֵstring - תַ +} + +function ConcatBytes(const A: TBytes; const B: TBytes): TBytes; overload; +{* A B ֽ˳ƴ÷һֽ飬A B ֲ䡣 + + + const A: TBytes - ƴӵֽһ + const B: TBytes - ƴӵֽ + + ֵTBytes - ƴӵֽ +} + +function ConcatBytes(const A: TBytes; const B: TBytes; const C: TBytes): TBytes; overload; +{* A B C ֽ˳ƴ÷һֽ飬A B C ֲ䡣 + + + const A: TBytes - ƴӵֽһ + const B: TBytes - ƴӵֽ + const C: TBytes - ƴӵֽ + + ֵTBytes - ƴӵֽ +} + +function ConcatBytes(const A: TBytes; const B: TBytes; const C: TBytes; const D: TBytes): TBytes; overload; +{* A B C D ĸֽ˳ƴ÷һֽ飬A B C D ֲ䡣 + + + const A: TBytes - ƴӵֽһ + const B: TBytes - ƴӵֽ + const C: TBytes - ƴӵֽ + const D: TBytes - ƴӵֽ + + ֵTBytes - ƴӵֽ +} + +function NewZeroBytes(ByteLen: Integer): TBytes; +{* ByteLen ֽڳȵֽ顣 + + + ByteLen: Integer - ֽֽڳ + + ֵTBytes - ȫֽ +} + +function ConcatBytesMemory(const A: TBytes; Data: Pointer; DataByteLen: Integer): TBytes; +{* һֽһƬڴƴ÷һ飬ԭֽڴ䡣 + + + const A: TBytes - ƴӵֽ + Data: Pointer - ƴӵݿַ + DataByteLen: Integer - ƴӵݿֽڳ + + ֵTBytes - ƴӵֽ +} + +function NewBytesFromMemory(Data: Pointer; DataByteLen: Integer): TBytes; +{* ½һֽ飬һƬڴݹ + + + Data: Pointer - ݿַ + DataByteLen: Integer - ݿֽڳ + + ֵTBytes - ½ֽ +} + +procedure PutBytesToMemory(const Data: TBytes; Mem: Pointer; MaxByteSize: Integer = 0); +{* һֽдָڴд + + + const Data: TBytes - ֽ + Mem: Pointer - дݿַ + MaxByteSize: Integer - дֽ0 ʾ + + ֵޣ +} + +function CompareBytes(const A: TBytes; const B: TBytes): Boolean; overload; +{* ȽֽǷͬ + + + const A: TBytes - Ƚϵֽһ + const B: TBytes - Ƚϵֽ + + ֵBoolean - رȽϽǷͬ +} + +function CompareBytes(const A: TBytes; const B: TBytes; MaxLength: Integer): Boolean; overload; +{* Ƚֽǰ MaxLength ֽڵǷͬ + + + const A: TBytes - Ƚϵֽһ + const B: TBytes - Ƚϵֽ + MaxLength: Integer - Ƚϵֽ + + ֵBoolean - رȽϽǷͬ +} + +function CompareBytesWithDiffIndex(const A, B: TBytes; out DiffIndex: Integer): Boolean; +{* ȽֽǷͬ + ݲͬʱDiffIndex صһȵֽ -1 + + + const A: TBytes - Ƚϵֽһ + const B: TBytes - Ƚϵֽ + out DiffIndex: Integer - صһȵֽ + + ֵBoolean - رȽϽǷͬ +} + +function MoveMost(const Source; var Dest; ByteLen: Integer; MostLen: Integer): Integer; +{* Source ƶ ByteLen Ҳ MostLen ֽڵ Dest Уʵƶֽ + ByteLen С MostLen Dest 0Ҫ Dest MostLen + + + const Source - ƶԴλáַ + var Dest - ƶĿλáַҪ MostLen ֽ + ByteLen: Integer - ƶֽ + MostLen: Integer - ƶֽ + + ֵInteger - ʵƶֽ +} + +// =============================== =================================== + +function SarInt8(V: ShortInt; ShiftCount: Integer): ShortInt; +{* һ 8 λзƣҲ÷λλơ + + + V: ShortInt - Ƶ 8 λз + ShiftCount: Integer - Ƶλ + + ֵShortInt - λֵ +} + +function SarInt16(V: SmallInt; ShiftCount: Integer): SmallInt; +{* һ 16 λзƣҲ÷λλơ + + + V: SmallInt - Ƶ 16 λз + ShiftCount: Integer - Ƶλ + + ֵSmallInt - λֵ +} + +function SarInt32(V: Integer; ShiftCount: Integer): Integer; +{* һ 32 λзƣҲ÷λλơ + + + V: Integer - Ƶ 32 λз + ShiftCount: Integer - Ƶλ + + ֵInteger - λֵ +} + +function SarInt64(V: Int64; ShiftCount: Integer): Int64; +{* һ 64 λзƣҲ÷λλơ + + + V: Int64 - Ƶ 64 λз + ShiftCount: Integer - Ƶλ + + ֵInt64 - λֵ +} + +// ================ ִʱ̶ if жϵIJ =============== + +procedure ConstTimeConditionalSwap8(CanSwap: Boolean; var A: Byte; var B: Byte); +{* 8 λͱִʱ̶CanSwap Ϊ True ʱʵʩ A B + + + CanSwap: Boolean - Ƿ + var A: Byte - 8 λͱһ + var B: Byte - 8 λͱ + + ֵޣ +} + +procedure ConstTimeConditionalSwap16(CanSwap: Boolean; var A: Word; var B: Word); +{* 16 λͱִʱ̶CanSwap Ϊ True ʱʵʩ A B + + + CanSwap: Boolean - Ƿ + var A: Word - 16 λͱһ + var B: Word - 16 λͱ + + ֵޣ +} + +procedure ConstTimeConditionalSwap32(CanSwap: Boolean; var A: Cardinal; var B: Cardinal); +{* 32 λͱִʱ̶CanSwap Ϊ True ʱʵʩ A B + + + CanSwap: Boolean - Ƿ + var A: Cardinal - 32 λͱһ + var B: Cardinal - 32 λͱ + + ֵޣ +} + +procedure ConstTimeConditionalSwap64(CanSwap: Boolean; var A: TUInt64; var B: TUInt64); +{* 64 λͱִʱ̶CanSwap Ϊ True ʱʵʩ A B + + + CanSwap: Boolean - Ƿ + var A: TUInt64 - 64 λͱһ + var B: TUInt64 - 64 λͱ + + ֵޣ +} + +function ConstTimeEqual8(A: Byte; B: Byte): Boolean; +{* ֽڵִʱ̶ıȽϣ CPU ָתԤµִʱ죬ͬʱ True + + + A: Byte - Ƚϵ 8 λͱһ + B: Byte - Ƚϵ 8 λͱ + + ֵBoolean - Ƿ +} + +function ConstTimeEqual16(A: Word; B: Word): Boolean; +{* ˫ֽڵִʱ̶ıȽϣ CPU ָתԤµִʱ죬ͬʱ True + + + A: Word - Ƚϵ 16 λͱһ + B: Word - Ƚϵ 16 λͱ + + ֵBoolean - Ƿ +} + +function ConstTimeEqual32(A: Cardinal; B: Cardinal): Boolean; +{* ֽڵִʱ̶ıȽϣ CPU ָתԤµִʱ죬ͬʱ True + + + A: Cardinal - Ƚϵ 32 λͱһ + B: Cardinal - Ƚϵ 32 λͱ + + ֵBoolean - Ƿ +} + +function ConstTimeEqual64(A: TUInt64; B: TUInt64): Boolean; +{* ֽڵִʱ̶ıȽϣ CPU ָתԤµִʱ죬ͬʱ True + + + A: TUInt64 - Ƚϵ 64 λͱһ + B: TUInt64 - Ƚϵ 64 λͱ + + ֵBoolean - Ƿ +} + +function ConstTimeCompareMem(P1, P2: Pointer; ByteLength: Integer): Boolean; +{* ͬȵڴִʱ̶ıȽϣͬʱ True + + + P1: Pointer - Ƚϵĵһڴַ + P2: Pointer - Ƚϵĵڶڴַ + ByteLength: Integer - Ƚϵֽڳ + + ֵBoolean - Ƿ +} + +function ConstTimeCompareBytes(const A, B: TBytes): Boolean; +{* ִгͬʱֽĺ㶨ʱıȽϣ糤Ȳֱͬӷ Falseݾͬ True + + + const A: TBytes - Ƚϵֽһ + const B: TBytes - Ƚϵֽ + + ֵBoolean - Ƿͬ +} + +function ConstTimeExpandBoolean8(V: Boolean): Byte; +{* V ֵ 8 λȫ 1 ȫ 0 + + + V: Boolean - Ƿȫ 1 + + ֵByte - $FF 0 +} + +function ConstTimeExpandBoolean16(V: Boolean): Word; +{* V ֵ 16 λȫ 1 ȫ 0 + + + V: Boolean - Ƿȫ 1 + + ֵWord - $FFFF 0 +} + +function ConstTimeExpandBoolean32(V: Boolean): Cardinal; +{* V ֵ 32 λȫ 1 ȫ 0 + + + V: Boolean - Ƿȫ 1 + + ֵCardinal - $FFFFFFFF 0 +} + +function ConstTimeExpandBoolean64(V: Boolean): TUInt64; +{* V ֵ 64 λȫ 1 ȫ 0 + + + V: Boolean - Ƿȫ 1 + + ֵTUInt64 - $FFFFFFFFFFFFFFFF 0 +} + +function ConstTimeConditionalSelect8(Condition: Boolean; A: Byte; B: Byte): Byte; +{* ֽڱִʱ̶жѡCondtion Ϊ True ʱ A B + + + Condition: Boolean - Ƿѡ A ҲDzһ + A: Byte - ѡ 8 λһ + B: Byte - ѡ 8 λ + + ֵByte - ѡ 8 λ +} + +function ConstTimeConditionalSelect16(Condition: Boolean; A: Word; B: Word): Word; +{* ˫ֽڱִʱ̶жѡCondtion Ϊ True ʱ A B + + + Condition: Boolean - Ƿѡ A ҲDzһ + A: Word - ѡ 16 λһ + B: Word - ѡ 16 λ + + ֵWord - ѡ 16 λ +} + +function ConstTimeConditionalSelect32(Condition: Boolean; A: Cardinal; B: Cardinal): Cardinal; +{* ֽڱִʱ̶жѡCondtion Ϊ True ʱ A B + + + Condition: Boolean - Ƿѡ A ҲDzһ + A: Cardinal - ѡ 32 λһ + B: Cardinal - ѡ 32 λ + + ֵCardinal - ѡ 32 λ +} + +function ConstTimeConditionalSelect64(Condition: Boolean; A: TUInt64; B: TUInt64): TUInt64; +{* ֽڱִʱ̶жѡCondtion Ϊ True ʱ A B + + + Condition: Boolean - Ƿѡ A ҲDzһ + A: TUInt64 - ѡ 64 λһ + B: TUInt64 - ѡ 64 λ + + ֵTUInt64 - ѡ 64 λ +} + +// ================ ִʱ̶ if жϵIJ =============== + +{$IFDEF MSWINDOWS} + +// ĸΪ Intel ֻ֧࣬ 32 λ 64 λ Intel CPUӦCPUX86 CPUX64 + +procedure Int64DivInt32Mod(A: Int64; B: Integer; + var DivRes: Integer; var ModRes: Integer); +{* 64 λз 32 λз̷ DivRes ModRes + б֤ 32 λΧڣ쳣 + + + A: Int64 - + B: Integer - + var DivRes: Integer - + var ModRes: Integer - + + ֵޣ +} + +procedure UInt64DivUInt32Mod(A: TUInt64; B: Cardinal; + var DivRes: Cardinal; var ModRes: Cardinal); +{* 64 λ 32 λ̷ DivRes ModRes + б֤ 32 λΧڣ쳣 + + + A: TUInt64 - + B: Cardinal - + var DivRes: Cardinal - + var ModRes: Cardinal - + + ֵޣ +} + +procedure Int128DivInt64Mod(ALo: Int64; AHi: Int64; B: Int64; + var DivRes: Int64; var ModRes: Int64); +{* 128 λз 64 λз̷ DivRes ModRes + б֤ 64 λΧڣ쳣 + + + ALo: Int64 - 64 λ + AHi: Int64 - 64 λ + B: Int64 - + var DivRes: Int64 - + var ModRes: Int64 - + + ֵޣ +} + +procedure UInt128DivUInt64Mod(ALo: TUInt64; AHi: TUInt64; B: TUInt64; + var DivRes: TUInt64; var ModRes: TUInt64); +{* 128 λ 64 λ̷ DivRes ModRes + б֤ 64 λΧڣ쳣 + + + ALo: TUInt64 - 64 λ + AHi: TUInt64 - 64 λ + B: TUInt64 - + var DivRes: TUInt64 - + var ModRes: TUInt64 - + + ֵޣ +} + +{$ENDIF} + +function IsUInt128BitSet(Lo: TUInt64; Hi: TUInt64; N: Integer): Boolean; +{* Int64 ƴɵ 128 λ֣ص N λǷΪ 1N 0 127 + + + Lo: TUInt64 - жϵĵ 64 λ + Hi: TUInt64 - жϵĸ 64 λ + N: Integer - жϵλ + + ֵBoolean - ǷΪ 1 +} + +procedure SetUInt128Bit(var Lo: TUInt64; var Hi: TUInt64; N: Integer); +{* Int64 ƴɵ 128 λ֣õ N λΪ 1N 0 127 + + + var Lo: TUInt64 - õĵ 64 λ + var Hi: TUInt64 - õĸ 64 λ + N: Integer - õλ + + ֵޣ +} + +procedure ClearUInt128Bit(var Lo: TUInt64; var Hi: TUInt64; N: Integer); +{* Int64 ƴɵ 128 λ֣ N λN 0 127 + + + var Lo: TUInt64 - õĵ 64 λ + var Hi: TUInt64 - õĸ 64 λ + N: Integer - õλ + + ֵޣ +} + +function UnsignedAddWithLimitRadix(A: Cardinal; B: Cardinal; C: Cardinal; + var R: Cardinal; L: Cardinal; H: Cardinal): Cardinal; +{* ƵżӷA + B + C R Уؽλֵ + ȷ L H ıڣûȷ H LΡ + úַӳ䣬 C һǽλ + + + A: Cardinal - һ + B: Cardinal - + C: Cardinal - һǽλ + var R: Cardinal - + L: Cardinal - ͵ + H: Cardinal - ͵ + + ֵCardinal - Ƿнλ +} + +// =========================== ѭλ ==================================== + +// ע N Ӧ (0, A λ) ڣ N Ϊ 0 A λʱֵӦΪ A +// N ʱࣨΪͲȲͬ 32 λ AN Ϊ 33 ʱֵ N Ϊ 1 ʱķֵ + +function RotateLeft16(A: Word; N: Integer): Word; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 16 λѭ N λ + + + A: Word - ѭƵ 16 λ + N: Integer - ѭƵλ + + ֵWord - λֵ +} + +function RotateRight16(A: Word; N: Integer): Word; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 16 λѭ N λ + + + A: Word - ѭƵ 16 λ + N: Integer - ѭƵλ + + ֵWord - λֵ +} + +function RotateLeft32(A: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 32 λѭ N λ + + + A: Cardinal - ѭƵ 32 λ + N: Integer - ѭƵλ + + ֵCardinal - λֵ +} + +function RotateRight32(A: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 32 λѭ N λ + + + A: Cardinal - ѭƵ 32 λ + N: Integer - ѭƵλ + + ֵCardinal - λֵ +} + +function RotateLeft64(A: TUInt64; N: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 64 λѭ N λ + + + A: TUInt64 - ѭƵ 64 λ + N: Integer - ѭƵλ + + ֵTUInt64 - λֵ +} + +function RotateRight64(A: TUInt64; N: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +{* 64 λѭ N λ + + + A: TUInt64 - ѭƵ 64 λ + N: Integer - ѭƵλ + + ֵTUInt64 - λֵ +} + +{$IFDEF COMPILER5} + +function BoolToStr(Value: Boolean; UseBoolStrs: Boolean = False): string; +{* תΪַDelphi 5 ûи BoolToStr ϡ + + + Value: Boolean - תIJֵ + UseBoolStrs: Boolean - ǷӢĵ + + ֵstring - UseBoolStrs Ϊ False ʱ -1 0 True False +} + +{$ENDIF} + +implementation + +resourcestring + SCnErrorNotAHexPChar = 'Error: NOT a Hex Char: #%d'; + SCnErrorLengthNotHex = 'Error Length %d: NOT a Hex String'; + SCnErrorLengthNotHexAnsi = 'Error Length %d: NOT a Hex AnsiString'; + +var + FByteOrderIsBigEndian: Boolean = False; + +function CurrentByteOrderIsBigEndian: Boolean; +type + TByteOrder = packed record + case Boolean of + False: (C: array[0..1] of Byte); + True: (W: Word); + end; +var + T: TByteOrder; +begin + T.W := $00CC; + Result := T.C[1] = $CC; +end; + +function CurrentByteOrderIsLittleEndian: Boolean; +begin + Result := not CurrentByteOrderIsBigEndian; +end; + +function ReverseInt64(Value: Int64): Int64; +var + Lo, Hi: Cardinal; + Rec: Int64Rec; +begin + Lo := Int64Rec(Value).Lo; + Hi := Int64Rec(Value).Hi; + Lo := ((Lo and $000000FF) shl 24) or ((Lo and $0000FF00) shl 8) + or ((Lo and $00FF0000) shr 8) or ((Lo and $FF000000) shr 24); + Hi := ((Hi and $000000FF) shl 24) or ((Hi and $0000FF00) shl 8) + or ((Hi and $00FF0000) shr 8) or ((Hi and $FF000000) shr 24); + Rec.Lo := Hi; + Rec.Hi := Lo; + Result := Int64(Rec); +end; + +function ReverseUInt64(Value: TUInt64): TUInt64; +var + Lo, Hi: Cardinal; + Rec: Int64Rec; +begin + Lo := Int64Rec(Value).Lo; + Hi := Int64Rec(Value).Hi; + Lo := ((Lo and $000000FF) shl 24) or ((Lo and $0000FF00) shl 8) + or ((Lo and $00FF0000) shr 8) or ((Lo and $FF000000) shr 24); + Hi := ((Hi and $000000FF) shl 24) or ((Hi and $0000FF00) shl 8) + or ((Hi and $00FF0000) shr 8) or ((Hi and $FF000000) shr 24); + Rec.Lo := Hi; + Rec.Hi := Lo; + Result := TUInt64(Rec); +end; + +function Int64ToBigEndian(Value: Int64): Int64; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := ReverseInt64(Value); +end; + +function Int32ToBigEndian(Value: Integer): Integer; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := Integer((Value and $000000FF) shl 24) or Integer((Value and $0000FF00) shl 8) + or Integer((Value and $00FF0000) shr 8) or Integer((Value and $FF000000) shr 24); +end; + +function Int16ToBigEndian(Value: SmallInt): SmallInt; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := SmallInt((Value and $00FF) shl 8) or SmallInt((Value and $FF00) shr 8); +end; + +function Int64ToLittleEndian(Value: Int64): Int64; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := ReverseInt64(Value); +end; + +function Int32ToLittleEndian(Value: Integer): Integer; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := Integer((Value and $000000FF) shl 24) or Integer((Value and $0000FF00) shl 8) + or Integer((Value and $00FF0000) shr 8) or Integer((Value and $FF000000) shr 24); +end; + +function Int16ToLittleEndian(Value: SmallInt): SmallInt; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := SmallInt((Value and $00FF) shl 8) or SmallInt((Value and $FF00) shr 8); +end; + +function UInt64ToBigEndian(Value: TUInt64): TUInt64; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := ReverseUInt64(Value); +end; + +function UInt32ToBigEndian(Value: Cardinal): Cardinal; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := Cardinal((Value and $000000FF) shl 24) or Cardinal((Value and $0000FF00) shl 8) + or Cardinal((Value and $00FF0000) shr 8) or Cardinal((Value and $FF000000) shr 24); +end; + +function UInt16ToBigEndian(Value: Word): Word; +begin + if FByteOrderIsBigEndian then + Result := Value + else + Result := Word((Value and $00FF) shl 8) or Word((Value and $FF00) shr 8); +end; + +function UInt64ToLittleEndian(Value: TUInt64): TUInt64; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := ReverseUInt64(Value); +end; + +function UInt32ToLittleEndian(Value: Cardinal): Cardinal; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := Cardinal((Value and $000000FF) shl 24) or Cardinal((Value and $0000FF00) shl 8) + or Cardinal((Value and $00FF0000) shr 8) or Cardinal((Value and $FF000000) shr 24); +end; + +function UInt16ToLittleEndian(Value: Word): Word; +begin + if not FByteOrderIsBigEndian then + Result := Value + else + Result := Word((Value and $00FF) shl 8) or Word((Value and $FF00) shr 8); +end; + +function Int64HostToNetwork(Value: Int64): Int64; +begin + if not FByteOrderIsBigEndian then + Result := ReverseInt64(Value) + else + Result := Value; +end; + +function Int32HostToNetwork(Value: Integer): Integer; +begin + if not FByteOrderIsBigEndian then + Result := Integer((Value and $000000FF) shl 24) or Integer((Value and $0000FF00) shl 8) + or Integer((Value and $00FF0000) shr 8) or Integer((Value and $FF000000) shr 24) + else + Result := Value; +end; + +function Int16HostToNetwork(Value: SmallInt): SmallInt; +begin + if not FByteOrderIsBigEndian then + Result := SmallInt((Value and $00FF) shl 8) or SmallInt((Value and $FF00) shr 8) + else + Result := Value; +end; + +function Int64NetworkToHost(Value: Int64): Int64; +begin + if not FByteOrderIsBigEndian then + REsult := ReverseInt64(Value) + else + Result := Value; +end; + +function Int32NetworkToHost(Value: Integer): Integer; +begin + if not FByteOrderIsBigEndian then + Result := Integer((Value and $000000FF) shl 24) or Integer((Value and $0000FF00) shl 8) + or Integer((Value and $00FF0000) shr 8) or Integer((Value and $FF000000) shr 24) + else + Result := Value; +end; + +function Int16NetworkToHost(Value: SmallInt): SmallInt; +begin + if not FByteOrderIsBigEndian then + Result := SmallInt((Value and $00FF) shl 8) or SmallInt((Value and $FF00) shr 8) + else + Result := Value; +end; + +function UInt64HostToNetwork(Value: TUInt64): TUInt64; +begin + if CurrentByteOrderIsBigEndian then + Result := Value + else + Result := ReverseUInt64(Value); +end; + +function UInt32HostToNetwork(Value: Cardinal): Cardinal; +begin + if not FByteOrderIsBigEndian then + Result := Cardinal((Value and $000000FF) shl 24) or Cardinal((Value and $0000FF00) shl 8) + or Cardinal((Value and $00FF0000) shr 8) or Cardinal((Value and $FF000000) shr 24) + else + Result := Value; +end; + +function UInt16HostToNetwork(Value: Word): Word; +begin + if not FByteOrderIsBigEndian then + Result := ((Value and $00FF) shl 8) or ((Value and $FF00) shr 8) + else + Result := Value; +end; + +function UInt64NetworkToHost(Value: TUInt64): TUInt64; +begin + if CurrentByteOrderIsBigEndian then + Result := Value + else + Result := ReverseUInt64(Value); +end; + +function UInt32NetworkToHost(Value: Cardinal): Cardinal; +begin + if not FByteOrderIsBigEndian then + Result := Cardinal((Value and $000000FF) shl 24) or Cardinal((Value and $0000FF00) shl 8) + or Cardinal((Value and $00FF0000) shr 8) or Cardinal((Value and $FF000000) shr 24) + else + Result := Value; +end; + +function UInt16NetworkToHost(Value: Word): Word; +begin + if not FByteOrderIsBigEndian then + Result := ((Value and $00FF) shl 8) or ((Value and $FF00) shr 8) + else + Result := Value; +end; + +function ReverseBitsInInt8(V: Byte): Byte; +begin + // 0 1 2 3 4 5 6 7 + V := ((V and $AA) shr 1) or ((V and $55) shl 1); + // 01 23 45 67 + V := ((V and $CC) shr 2) or ((V and $33) shl 2); + // 0123 4567 + V := (V shr 4) or (V shl 4); + Result := V; +end; + +function ReverseBitsInInt16(V: Word): Word; +begin + Result := (ReverseBitsInInt8(V and $00FF) shl 8) + or ReverseBitsInInt8((V and $FF00) shr 8); +end; + +function ReverseBitsInInt32(V: Cardinal): Cardinal; +begin + Result := (ReverseBitsInInt16(V and $0000FFFF) shl 16) + or ReverseBitsInInt16((V and $FFFF0000) shr 16); +end; + +function ReverseBitsInInt64(V: Int64): Int64; +begin + Result := (Int64(ReverseBitsInInt32(V and $00000000FFFFFFFF)) shl 32) + or ReverseBitsInInt32((V and $FFFFFFFF00000000) shr 32); +end; + +procedure ReverseMemory(Mem: Pointer; MemByteLen: Integer); +var + I, L: Integer; + P: PByteArray; + T: Byte; +begin + if (Mem = nil) or (MemByteLen < 2) then + Exit; + + L := MemByteLen div 2; + P := PByteArray(Mem); + for I := 0 to L - 1 do + begin + // I ͵ MemLen - I - 1 + T := P^[I]; + P^[I] := P^[MemByteLen - I - 1]; + P^[MemByteLen - I - 1] := T; + end; +end; + +procedure ReverseMemoryWithBits(Mem: Pointer; MemByteLen: Integer); +var + I: Integer; + P: PByteArray; +begin + if (Mem = nil) or (MemByteLen <= 0) then + Exit; + + ReverseMemory(Mem, MemByteLen); + P := PByteArray(Mem); + + for I := 0 to MemByteLen - 1 do + P^[I] := ReverseBitsInInt8(P^[I]); +end; + +procedure MemoryNetworkToHost(Mem: Pointer; MemByteLen: Integer); +begin + if not FByteOrderIsBigEndian then + ReverseMemory(Mem, MemByteLen); +end; + +procedure MemoryHostToNetwork(Mem: Pointer; MemByteLen: Integer); +begin + if not FByteOrderIsBigEndian then + ReverseMemory(Mem, MemByteLen); +end; + +// N ֽڳȵڴλ +procedure MemoryBitOperation(AMem, BMem, RMem: Pointer; N: Integer; Op: TCnBitOperation); +var + A, B, R: PCnLongWord32Array; + BA, BB, BR: PByteArray; +begin + if N <= 0 then + Exit; + + if (AMem = nil) or ((BMem = nil) and (Op <> boNot)) or (RMem = nil) then + Exit; + + A := PCnLongWord32Array(AMem); + B := PCnLongWord32Array(BMem); + R := PCnLongWord32Array(RMem); + + while (N and (not 3)) <> 0 do + begin + case Op of + boAnd: + R^[0] := A^[0] and B^[0]; + boOr: + R^[0] := A^[0] or B^[0]; + boXor: + R^[0] := A^[0] xor B^[0]; + boNot: // ʱ B + R^[0] := not A^[0]; + end; + + A := PCnLongWord32Array(TCnIntAddress(A) + SizeOf(Cardinal)); + B := PCnLongWord32Array(TCnIntAddress(B) + SizeOf(Cardinal)); + R := PCnLongWord32Array(TCnIntAddress(R) + SizeOf(Cardinal)); + + Dec(N, SizeOf(Cardinal)); + end; + + if N > 0 then + begin + BA := PByteArray(A); + BB := PByteArray(B); + BR := PByteArray(R); + + while N <> 0 do + begin + case Op of + boAnd: + BR^[0] := BA^[0] and BB^[0]; + boOr: + BR^[0] := BA^[0] or BB^[0]; + boXor: + BR^[0] := BA^[0] xor BB^[0]; + boNot: + BR^[0] := not BA^[0]; + end; + + BA := PByteArray(TCnIntAddress(BA) + SizeOf(Byte)); + BB := PByteArray(TCnIntAddress(BB) + SizeOf(Byte)); + BR := PByteArray(TCnIntAddress(BR) + SizeOf(Byte)); + Dec(N); + end; + end; +end; + +procedure MemoryAnd(AMem, BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +begin + MemoryBitOperation(AMem, BMem, ResMem, MemByteLen, boAnd); +end; + +procedure MemoryOr(AMem, BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +begin + MemoryBitOperation(AMem, BMem, ResMem, MemByteLen, boOr); +end; + +procedure MemoryXor(AMem, BMem: Pointer; MemByteLen: Integer; ResMem: Pointer); +begin + MemoryBitOperation(AMem, BMem, ResMem, MemByteLen, boXor); +end; + +procedure MemoryNot(Mem: Pointer; MemByteLen: Integer; ResMem: Pointer); +begin + MemoryBitOperation(Mem, nil, ResMem, MemByteLen, boNot); +end; + +procedure MemoryShiftLeft(AMem, BMem: Pointer; MemByteLen: Integer; BitCount: Integer); +var + I, L, N, LB, RB: Integer; + PF, PT: PByteArray; +begin + if (AMem = nil) or (MemByteLen <= 0) or (BitCount = 0) then + Exit; + + if BitCount < 0 then + begin + MemoryShiftRight(AMem, BMem, MemByteLen, -BitCount); + Exit; + end; + + if BMem = nil then + BMem := AMem; + + if (MemByteLen * 8) <= BitCount then // ̫ȫ 0 + begin + FillChar(BMem^, MemByteLen, 0); + Exit; + end; + + N := BitCount div 8; // λֽ + RB := BitCount mod 8; // ȥֽںʣµλ + LB := 8 - RB; // ʣµλһֽʣµλ + + PF := PByteArray(AMem); + PT := PByteArray(BMem); + + if RB = 0 then // 飬ð죬Ҫλֽ MemLen - NW + begin + Move(PF^[N], PT^[0], MemByteLen - N); + FillChar(PT^[MemByteLen - N], N, 0); + end + else + begin + // PF^[N] PT^[0] MemLen - N ֽڣֽڼн + L := MemByteLen - N; + PF := PByteArray(TCnIntAddress(PF) + N); + + for I := 1 to L do // ӵλƶȴ͵ + begin + PT^[0] := Byte(PF^[0] shl RB); + if I < L then // һֽ PF^[1] ᳬ + PT^[0] := (PF^[1] shr LB) or PT^[0]; + + PF := PByteArray(TCnIntAddress(PF) + 1); + PT := PByteArray(TCnIntAddress(PT) + 1); + end; + + // ʣµҪ 0 + if N > 0 then + FillChar(PT^[0], N, 0); + end; +end; + +procedure MemoryShiftRight(AMem, BMem: Pointer; MemByteLen: Integer; BitCount: Integer); +var + I, L, N, LB, RB: Integer; + PF, PT: PByteArray; +begin + if (AMem = nil) or (MemByteLen <= 0) or (BitCount = 0) then + Exit; + + if BitCount < 0 then + begin + MemoryShiftLeft(AMem, BMem, MemByteLen, -BitCount); + Exit; + end; + + if BMem = nil then + BMem := AMem; + + if (MemByteLen * 8) <= BitCount then // ̫ȫ 0 + begin + FillChar(BMem^, MemByteLen, 0); + Exit; + end; + + N := BitCount div 8; // λֽ + RB := BitCount mod 8; // ȥֽںʣµλ + LB := 8 - RB; // ʣµλһֽʣµλ + + if RB = 0 then // 飬ð죬Ҫλֽ MemLen - N + begin + PF := PByteArray(AMem); + PT := PByteArray(BMem); + + Move(PF^[0], PT^[N], MemByteLen - N); + FillChar(PT^[0], N, 0); + end + else + begin + // PF^[0] PT^[N] MemLen - N ֽڣôӸߴʼֽڼн + L := MemByteLen - N; + + PF := PByteArray(TCnIntAddress(AMem) + L - 1); + PT := PByteArray(TCnIntAddress(BMem) + MemByteLen - 1); + + for I := L downto 1 do // Ӹλλƶȴ + begin + PT^[0] := Byte(PF^[0] shr RB); + if I > 1 then // һֽ PF^[-1] ᳬ + begin + PF := PByteArray(TCnIntAddress(PF) - 1); + PT^[0] := Byte((PF^[0] shl LB) or PT^[0]); + end + else + PF := PByteArray(TCnIntAddress(PF) - 1); + + PT := PByteArray(TCnIntAddress(PT) - 1); + end; + + // ʣµǰҪ 0 + if N > 0 then + FillChar(BMem^, N, 0); + end; +end; + +function MemoryIsBitSet(Mem: Pointer; N: Integer): Boolean; +var + P: PByte; + A, B: Integer; + V: Byte; +begin + if (Mem = nil) or (N < 0) then + raise ERangeError.Create(SRangeError); + + A := N div 8; + B := N mod 8; + P := PByte(TCnIntAddress(Mem) + A); + + V := Byte(1 shl B); + Result := (P^ and V) <> 0; +end; + +procedure MemorySetBit(Mem: Pointer; N: Integer); +var + P: PByte; + A, B: Integer; + V: Byte; +begin + if (Mem = nil) or (N < 0) then + raise ERangeError.Create(SRangeError); + + A := N div 8; + B := N mod 8; + P := PByte(TCnIntAddress(Mem) + A); + + V := Byte(1 shl B); + P^ := P^ or V; +end; + +procedure MemoryClearBit(Mem: Pointer; N: Integer); +var + P: PByte; + A, B: Integer; + V: Byte; +begin + if (Mem = nil) or (N < 0) then + raise ERangeError.Create(SRangeError); + + A := N div 8; + B := N mod 8; + P := PByte(TCnIntAddress(Mem) + A); + + V := not Byte(1 shl B); + P^ := P^ and V; +end; + +function MemoryGetHighBits(Mem: Pointer; MemByteLen: Integer): Integer; +var + I, R, ZO: Integer; + P: PByteArray; +begin + Result := -1; + if (Mem = nil) or (MemByteLen <= 0) then + Exit; + + P := PByteArray(Mem); + ZO := 0; + for I := 0 to MemByteLen - 1 do // ӵ͵ַߵַ + begin + R := GetUInt8HighBits(P^[I]); + if R = -1 then // ֽȫ 0 + begin + ZO := ZO + 8; + end + else // ֽ 1ֹ + begin + ZO := ZO + 8 - R + 1; + Break; + end; + end; + + if ZO = MemByteLen * 8 then // ȫ㣬û 1 + Result := -1 + else + Result := MemByteLen * 8 - ZO; // 1λȥ 0 ĸ +end; + +function MemoryGetLowBits(Mem: Pointer; MemByteLen: Integer): Integer; +var + I, R, ZC: Integer; + P: PByteArray; +begin + Result := -1; + if (Mem = nil) or (MemByteLen <= 0) then + Exit; + + P := PByteArray(Mem); + ZC := 0; + for I := MemByteLen - 1 downto 0 do // Ӹߵַ͵ַ + begin + R := GetUInt8LowBits(P^[I]); + if R = -1 then // ֽȫ 0 + begin + ZC := ZC + 8; + end + else // ֽ 1ֹ + begin + ZC := ZC + R; + Break; + end; + end; + + if ZC = MemByteLen * 8 then // ȫ㣬û 1 + Result := -1 + else + Result := MemByteLen * 8 - ZC; // 1λȥ 0 ĸ +end; + +function MemoryToBinStr(Mem: Pointer; MemByteLen: Integer; Sep: Boolean): string; +var + J, L: Integer; + P: PByteArray; + B: PChar; + + procedure FillAByteToBuf(V: Byte; Buf: PChar); + const + M = $80; + var + I: Integer; + begin + for I := 0 to 7 do + begin + if (V and M) <> 0 then + Buf[I] := '1' + else + Buf[I] := '0'; + V := V shl 1; + end; + end; + +begin + Result := ''; + if (Mem = nil) or (MemByteLen <= 0) then + Exit; + + L := MemByteLen * 8; + if Sep then + L := L + MemByteLen - 1; // мÿոָ + + SetLength(Result, L); + B := PChar(@Result[1]); + P := PByteArray(Mem); + + for J := 0 to MemByteLen - 1 do + begin + FillAByteToBuf(P^[J], B); + if Sep then + begin + B[8] := ' '; + Inc(B, 9); + end + else + Inc(B, 8); + end; +end; + +procedure MemorySwap(AMem, BMem: Pointer; MemByteLen: Integer); +var + A, B: PCnLongWord32Array; + BA, BB: PByteArray; + TC: Cardinal; + TB: Byte; +begin + if (AMem = nil) or (BMem = nil) or (MemByteLen <= 0) then + Exit; + + A := PCnLongWord32Array(AMem); + B := PCnLongWord32Array(BMem); + + if A = B then + Exit; + + while (MemByteLen and (not 3)) <> 0 do + begin + TC := A^[0]; + A^[0] := B^[0]; + B^[0] := TC; + + A := PCnLongWord32Array(TCnIntAddress(A) + SizeOf(Cardinal)); + B := PCnLongWord32Array(TCnIntAddress(B) + SizeOf(Cardinal)); + + Dec(MemByteLen, SizeOf(Cardinal)); + end; + + if MemByteLen > 0 then + begin + BA := PByteArray(A); + BB := PByteArray(B); + + while MemByteLen <> 0 do + begin + TB := BA^[0]; + BA^[0] := BB^[0]; + BB^[0] :=TB; + + BA := PByteArray(TCnIntAddress(BA) + SizeOf(Byte)); + BB := PByteArray(TCnIntAddress(BB) + SizeOf(Byte)); + + Dec(MemByteLen); + end; + end; +end; + +function MemoryCompare(AMem, BMem: Pointer; MemByteLen: Integer): Integer; +var + A, B: PCnLongWord32Array; + BA, BB: PByteArray; +begin + Result := 0; + if ((AMem = nil) and (BMem = nil)) or (AMem = BMem) then // ͬһ + Exit; + + if MemByteLen <= 0 then + Exit; + + if AMem = nil then + begin + Result := -1; + Exit; + end; + if BMem = nil then + begin + Result := 1; + Exit; + end; + + A := PCnLongWord32Array(AMem); + B := PCnLongWord32Array(BMem); + + while (MemByteLen and (not 3)) <> 0 do + begin + if A^[0] > B^[0] then + begin + Result := 1; + Exit; + end + else if A^[0] < B^[0] then + begin + Result := -1; + Exit; + end; + + A := PCnLongWord32Array(TCnIntAddress(A) + SizeOf(Cardinal)); + B := PCnLongWord32Array(TCnIntAddress(B) + SizeOf(Cardinal)); + + Dec(MemByteLen, SizeOf(Cardinal)); + end; + + if MemByteLen > 0 then + begin + BA := PByteArray(A); + BB := PByteArray(B); + + while MemByteLen <> 0 do + begin + if BA^[0] > BB^[0] then + begin + Result := 1; + Exit; + end + else if BA^[0] < BB^[0] then + begin + Result := -1; + Exit; + end; + + BA := PByteArray(TCnIntAddress(BA) + SizeOf(Byte)); + BB := PByteArray(TCnIntAddress(BB) + SizeOf(Byte)); + + Dec(MemByteLen); + end; + end; +end; + +function UInt8ToBinStr(V: Byte): string; +const + M = $80; +var + I: Integer; +begin + SetLength(Result, 8 * SizeOf(V)); + for I := 1 to 8 * SizeOf(V) do + begin + if (V and M) <> 0 then + Result[I] := '1' + else + Result[I] := '0'; + V := V shl 1; + end; +end; + +function UInt16ToBinStr(V: Word): string; +const + M = $8000; +var + I: Integer; +begin + SetLength(Result, 8 * SizeOf(V)); + for I := 1 to 8 * SizeOf(V) do + begin + if (V and M) <> 0 then + Result[I] := '1' + else + Result[I] := '0'; + V := V shl 1; + end; +end; + +function UInt32ToBinStr(V: Cardinal): string; +const + M = $80000000; +var + I: Integer; +begin + SetLength(Result, 8 * SizeOf(V)); + for I := 1 to 8 * SizeOf(V) do + begin + if (V and M) <> 0 then + Result[I] := '1' + else + Result[I] := '0'; + V := V shl 1; + end; +end; + +function UInt32ToStr(V: Cardinal): string; +begin + Result := Format('%u', [V]); +end; + +function UInt64ToBinStr(V: TUInt64): string; +const + M = $8000000000000000; +var + I: Integer; +begin + SetLength(Result, 8 * SizeOf(V)); + + for I := 1 to 8 * SizeOf(V) do + begin + if (V and M) <> 0 then + Result[I] := '1' + else + Result[I] := '0'; + V := V shl 1; + end; +end; + +const + HiDigits: array[0..15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); +const + LoDigits: array[0..15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); + +const + AnsiHiDigits: array[0..15] of AnsiChar = ('0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); +const + AnsiLoDigits: array[0..15] of AnsiChar = ('0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); + +function HexToInt(Hex: PChar; CharLen: Integer): Integer; +var + I, Res: Integer; + C: Char; +begin + Res := 0; + for I := 0 to CharLen - 1 do + begin + C := Hex[I]; + if (C >= '0') and (C <= '9') then + Res := Res * 16 + Ord(C) - Ord('0') + else if (C >= 'A') and (C <= 'F') then + Res := Res * 16 + Ord(C) - Ord('A') + 10 + else if (C >= 'a') and (C <= 'f') then + Res := Res * 16 + Ord(C) - Ord('a') + 10 + else + raise ECnNativeException.CreateFmt(SCnErrorNotAHexPChar, [Ord(C)]); + end; + Result := Res; +end; + +function HexToInt(const Hex: string): Integer; +begin + Result := HexToInt(PChar(Hex), Length(Hex)); +end; + +{$WARNINGS OFF} + +function IsHexString(const Hex: string): Boolean; +var + I, L: Integer; +begin + Result := False; + L := Length(Hex); + if (L <= 0) or ((L and 1) <> 0) then // ջżȶ + Exit; + + for I := 1 to L do + begin + // ע˴ Unicode Ȼ Warningǽ Hex[I] WideChar ֱӽض AnsiChar + // ٽжϣᵼ¡ޡ $66$66$66$66 ַУ + // ֱͨ WideChar ֵ ax ˫ֽڵģӼжϣ + if not (Hex[I] in ['0'..'9', 'A'..'F', 'a'..'f']) then + Exit; + end; + Result := True; +end; + +{$WARNINGS ON} + +function DataToHex(InData: Pointer; ByteLength: Integer; UseUpperCase: Boolean = True): string; +var + I: Integer; + B: Byte; +begin + Result := ''; + if ByteLength <= 0 then + Exit; + + SetLength(Result, ByteLength * 2); + if UseUpperCase then + begin + for I := 0 to ByteLength - 1 do + begin + B := PByte(TCnIntAddress(InData) + I * SizeOf(Byte))^; + Result[I * 2 + 1] := HiDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := HiDigits[B and $0F]; + end; + end + else + begin + for I := 0 to ByteLength - 1 do + begin + B := PByte(TCnIntAddress(InData) + I * SizeOf(Byte))^; + Result[I * 2 + 1] := LoDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := LoDigits[B and $0F]; + end; + end; +end; + +function HexToData(const Hex: string; OutData: Pointer): Integer; +var + I, L: Integer; + H: PChar; +begin + L := Length(Hex); + if (L mod 2) <> 0 then + raise ECnNativeException.CreateFmt(SCnErrorLengthNotHex, [L]); + + if OutData = nil then + begin + Result := L div 2; + Exit; + end; + + Result := 0; + H := PChar(Hex); + for I := 1 to L div 2 do + begin + PByte(TCnIntAddress(OutData) + I - 1)^ := Byte(HexToInt(@H[(I - 1) * 2], 2)); + Inc(Result); + end; +end; + +function StringToHex(const Data: string; UseUpperCase: Boolean): string; +var + I, L: Integer; + B: Byte; + Buffer: PChar; +begin + Result := ''; + L := Length(Data); + if L = 0 then + Exit; + + SetLength(Result, L * 2); + Buffer := @Data[1]; + + if UseUpperCase then + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnIntAddress(Buffer) + I * SizeOf(Char))^; + Result[I * 2 + 1] := HiDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := HiDigits[B and $0F]; + end; + end + else + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnIntAddress(Buffer) + I * SizeOf(Char))^; + Result[I * 2 + 1] := LoDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := LoDigits[B and $0F]; + end; + end; +end; + +function HexToString(const Hex: string): string; +var + I, L: Integer; + H: PChar; +begin + L := Length(Hex); + if (L mod 2) <> 0 then + raise ECnNativeException.CreateFmt(SCnErrorLengthNotHex, [L]); + + SetLength(Result, L div 2); + H := PChar(Hex); + for I := 1 to L div 2 do + Result[I] := Chr(HexToInt(@H[(I - 1) * 2], 2)); +end; + +function HexToAnsiStr(const Hex: AnsiString): AnsiString; +var + I, L: Integer; + S: string; +begin + L := Length(Hex); + if (L mod 2) <> 0 then + raise ECnNativeException.CreateFmt(SCnErrorLengthNotHexAnsi, [L]); + + SetLength(Result, L div 2); + for I := 1 to L div 2 do + begin + S := string(Copy(Hex, I * 2 - 1, 2)); + Result[I] := AnsiChar(Chr(HexToInt(S))); + end; +end; + +function AnsiStrToHex(const Data: AnsiString; UseUpperCase: Boolean): AnsiString; +var + I, L: Integer; + B: Byte; + Buffer: PAnsiChar; +begin + Result := ''; + L := Length(Data); + if L = 0 then + Exit; + + SetLength(Result, L * 2); + Buffer := @Data[1]; + + if UseUpperCase then + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnIntAddress(Buffer) + I)^; + Result[I * 2 + 1] := AnsiHiDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := AnsiHiDigits[B and $0F]; + end; + end + else + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnIntAddress(Buffer) + I)^; + Result[I * 2 + 1] := AnsiLoDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := AnsiLoDigits[B and $0F]; + end; + end; +end; + +function BytesToHex(const Data: TBytes; UseUpperCase: Boolean): string; +var + I, L: Integer; + B: Byte; + Buffer: PAnsiChar; +begin + Result := ''; + L := Length(Data); + if L = 0 then + Exit; + + SetLength(Result, L * 2); + Buffer := @Data[0]; + + if UseUpperCase then + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnIntAddress(Buffer) + I)^; + Result[I * 2 + 1] := HiDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := HiDigits[B and $0F]; + end; + end + else + begin + for I := 0 to L - 1 do + begin + B := PByte(TCnIntAddress(Buffer) + I)^; + Result[I * 2 + 1] := LoDigits[(B shr 4) and $0F]; + Result[I * 2 + 2] := LoDigits[B and $0F]; + end; + end; +end; + +function HexToBytes(const Hex: string): TBytes; +var + I, L: Integer; + H: PChar; +begin + L := Length(Hex); + if (L mod 2) <> 0 then + raise ECnNativeException.CreateFmt(SCnErrorLengthNotHex, [L]); + + SetLength(Result, L div 2); + H := PChar(Hex); + + for I := 1 to L div 2 do + Result[I - 1] := Byte(HexToInt(@H[(I - 1) * 2], 2)); +end; + +function StreamToHex(Stream: TStream; UseUpperCase: Boolean): string; +var + B: Byte; + I: Integer; +begin + Result := ''; + if Stream.Size > 0 then + begin + Stream.Position := 0; + SetLength(Result, Stream.Size * 2); + I := 1; + if UseUpperCase then + begin + while Stream.Read(B, 1) = 1 do + begin + Result[I] := HiDigits[(B shr 4) and $0F]; + Inc(I); + Result[I] := HiDigits[B and $0F]; + Inc(I); + end; + end + else + begin + while Stream.Read(B, 1) = 1 do + begin + Result[I] := LoDigits[(B shr 4) and $0F]; + Inc(I); + Result[I] := LoDigits[B and $0F]; + Inc(I); + end; + end; + end; +end; + +function HexToStream(const Hex: string; Stream: TStream): Integer; +var + I, L: Integer; + H: PChar; + B: Byte; +begin + Result := 0; + L := Length(Hex); + if (L mod 2) <> 0 then + raise ECnNativeException.CreateFmt(SCnErrorLengthNotHex, [L]); + + H := PChar(Hex); + for I := 1 to L div 2 do + begin + B := Byte(HexToInt(@H[(I - 1) * 2], 2)); + Inc(Result, Stream.Write(B, 1)); + end; +end; + +function WriteBytesToStream(const Data: TBytes; Stream: TStream): Integer; +begin + if Length(Data) > 0 then + Result := Stream.Write(Data[0], Length(Data)) + else + Result := 0; +end; + +procedure ReverseBytes(Data: TBytes); +var + I, L, M: Integer; + T: Byte; +begin + if (Data = nil) or (Length(Data) <= 1) then + Exit; + L := Length(Data); + M := L div 2; + for I := 0 to M - 1 do + begin + // I L - I - 1 + T := Data[I]; + Data[I] := Data[L - I - 1]; + Data[L - I - 1] := T; + end; +end; + +function CloneBytes(const Data: TBytes): TBytes; +begin + if Length(Data) = 0 then + Result := nil + else + begin + SetLength(Result, Length(Data)); + Move(Data[0], Result[0], Length(Data)); + end; +end; + +function StreamToBytes(Stream: TStream): TBytes; +begin + Result := nil; + if (Stream <> nil) and (Stream.Size > 0) then + begin + SetLength(Result, Stream.Size); + Stream.Position := 0; + Stream.Read(Result[0], Stream.Size); + end; +end; + +function BytesToStream(const Data: TBytes; OutStream: TStream): Integer; +begin + Result := 0; + if (Data <> nil) and (Length(Data) > 0) and (OutStream <> nil) then + begin + OutStream.Size := 0; + Result := OutStream.Write(Data[0], Length(Data)); + end; +end; + +function AnsiToBytes(const Str: AnsiString): TBytes; +begin + SetLength(Result, Length(Str)); + if Length(Str) > 0 then + Move(Str[1], Result[0], Length(Str)); +end; + +function BytesToAnsi(const Data: TBytes): AnsiString; +begin + SetLength(Result, Length(Data)); + if Length(Data) > 0 then + Move(Data[0], Result[1], Length(Data)); +end; + +function BytesToString(const Data: TBytes): string; +var + I: Integer; +begin + SetLength(Result, Length(Data)); + for I := 1 to Length(Data) do + Result[I] := Chr(Data[I - 1]); +end; + +function MemoryToString(Mem: Pointer; MemByteLen: Integer): string; +var + P: PByteArray; + I: Integer; +begin + if (Mem = nil) or (MemByteLen <= 0) then + begin + Result := ''; + Exit; + end; + + P := PByteArray(Mem); + SetLength(Result, MemByteLen); + for I := 1 to MemByteLen do + Result[I] := Chr(P^[I - 1]); +end; + +function BitsToString(Bits: TBits): string; +var + I: Integer; +begin + if (Bits = nil) or (Bits.Size = 0) then + Result := '' + else + begin + SetLength(Result, Bits.Size); + for I := 0 to Bits.Size - 1 do + begin + if Bits.Bits[I] then + Result[I + 1] := '1' + else + Result[I + 1] := '0'; + end; + end; +end; + +function ConcatBytes(const A, B: TBytes): TBytes; +begin + // XE7 ҲֱӣΪ A B Ϊʱ᷵һֽ + if (A = nil) or (Length(A) = 0) then + begin + SetLength(Result, Length(B)); + if Length(B) > 0 then + Move(B[0], Result[0], Length(B)); + end + else if (B = nil) or (Length(B) = 0) then + begin + SetLength(Result, Length(A)); + if Length(A) > 0 then + Move(A[0], Result[0], Length(A)); + end + else + begin + SetLength(Result, Length(A) + Length(B)); + Move(A[0], Result[0], Length(A)); + Move(B[0], Result[Length(A)], Length(B)); + end; +end; + +function ConcatBytes(const A: TBytes; const B: TBytes; const C: TBytes): TBytes; +var + L1, L2, L3: Integer; +begin + Result := nil; + L1 := Length(A); + L2 := Length(B); + L3 := Length(C); + + if (L1 = 0) and (L2 = 0) and (L3 = 0) then + Exit; + + SetLength(Result, L1 + L2 + L3); + if L1 > 0 then + Move(A[0], Result[0], L1); + if L2 > 0 then + Move(B[0], Result[L1], L2); + if L3 > 0 then + Move(C[0], Result[L1 + L2], L3); +end; + +function ConcatBytes(const A: TBytes; const B: TBytes; const C: TBytes; const D: TBytes): TBytes; +var + L1, L2, L3, L4: Integer; +begin + Result := nil; + L1 := Length(A); + L2 := Length(B); + L3 := Length(C); + L4 := Length(D); + + if (L1 = 0) and (L2 = 0) and (L3 = 0) and (L4 = 0) then + Exit; + + SetLength(Result, L1 + L2 + L3 + L4); + if L1 > 0 then + Move(A[0], Result[0], L1); + if L2 > 0 then + Move(B[0], Result[L1], L2); + if L3 > 0 then + Move(C[0], Result[L1 + L2], L3); + if L4 > 0 then + Move(D[0], Result[L1 + L2 + L3], L4); +end; + +function NewZeroBytes(ByteLen: Integer): TBytes; +begin + if ByteLen > 0 then + begin + SetLength(Result, ByteLen); + FillChar(Result[0], ByteLen, 0); + end + else + Result := nil; +end; + +function ConcatBytesMemory(const A: TBytes; Data: Pointer; DataByteLen: Integer): TBytes; +var + L: Integer; +begin + L := Length(A) + DataByteLen; + if L > 0 then + begin + SetLength(Result, L); + if Length(A) > 0 then + Move(A[0], Result[0], Length(A)); + if (Data <> nil) and (DataByteLen > 0) then + Move(Data^, Result[Length(A)], DataByteLen); + end + else + Result := nil; +end; + +function NewBytesFromMemory(Data: Pointer; DataByteLen: Integer): TBytes; +begin + if (Data = nil) or (DataByteLen <= 0) then + Result := nil + else + begin + SetLength(Result, DataByteLen); + Move(Data^, Result[0], DataByteLen); + end; +end; + +procedure PutBytesToMemory(const Data: TBytes; Mem: Pointer; MaxByteSize: Integer); +var + L: Integer; +begin + L := Length(Data); + if (L > 0) and (Mem <> nil) then + begin + if (MaxByteSize > 0) and (L > MaxByteSize) then + L := MaxByteSize; + + Move(Data[0], Mem^, L); + end; +end; + +function CompareBytes(const A, B: TBytes): Boolean; +var + L: Integer; +begin + Result := False; + + L := Length(A); + if Length(B) <> L then // Ȳ˳ + Exit; + + if L = 0 then // + Result := True // 綼 0 + else + Result := CompareMem(@A[0], @B[0], L); +end; + +function CompareBytes(const A, B: TBytes; MaxLength: Integer): Boolean; +var + LA, LB: Integer; +begin + Result := False; + + LA := Length(A); + LB := Length(B); + + if LA > MaxLength then + LA := MaxLength; + if LB > MaxLength then + LB := MaxLength; + + if LA <> LB then + Exit; + + if LA = 0 then + Result := True + else + Result := CompareMem(@A[0], @B[0], LA); +end; + +function CompareBytesWithDiffIndex(const A, B: TBytes; out DiffIndex: Integer): Boolean; +var + I: Integer; + L1, L2: Integer; +begin + L1 := Length(A); + L2 := Length(B); + DiffIndex := -1; + Result := True; + + if L1 <> L2 then + begin + Result := False; + Exit; + end; + + if (L1 = 0) and (L2 = 0) then + Exit; + + for I := 0 to L1 - 1 do + begin + if A[I] <> B[I] then + begin + Result := False; + DiffIndex := I; + Exit; + end; + end; +end; + +function MoveMost(const Source; var Dest; ByteLen, MostLen: Integer): Integer; +begin + if (MostLen <= 0) or (ByteLen <= 0) then + begin + Result := 0; + Exit; + end; + + if ByteLen > MostLen then + ByteLen := MostLen + else if ByteLen < MostLen then + begin + FillChar(Dest, MostLen, 0); + + // TODO: ҪΪ FillChar(Dest + ByteLen, MostLen - ByteLen, 0); ֻ䲻IJ + end; + + Move(Source, Dest, ByteLen); + Result := ByteLen; +end; + +// =============================== =================================== + +function SarInt8(V: ShortInt; ShiftCount: Integer): ShortInt; +begin + Result := V shr ShiftCount; + if (V and $80) <> 0 then + Result := Result or ($FF shl (8 - ShiftCount)); +end; + +function SarInt16(V: SmallInt; ShiftCount: Integer): SmallInt; +begin + Result := V shr ShiftCount; + if (V and $8000) <> 0 then + Result := Result or ($FFFF shl (16 - ShiftCount)); +end; + +function SarInt32(V: Integer; ShiftCount: Integer): Integer; +begin + Result := V shr ShiftCount; + if (V and $80000000) <> 0 then + Result := Result or Integer($FFFFFFFF shl (32 - ShiftCount)); +end; + +function SarInt64(V: Int64; ShiftCount: Integer): Int64; +begin + Result := V shr ShiftCount; + if (V and $8000000000000000) <> 0 then + Result := Result or ($FFFFFFFFFFFFFFFF shl (64 - ShiftCount)); +end; + +procedure ConstTimeConditionalSwap8(CanSwap: Boolean; var A, B: Byte); +var + T, V: Byte; +begin + T := ConstTimeExpandBoolean8(CanSwap); + V := (A xor B) and T; + A := A xor V; + B := B xor V; +end; + +procedure ConstTimeConditionalSwap16(CanSwap: Boolean; var A, B: Word); +var + T, V: Word; +begin + T := ConstTimeExpandBoolean16(CanSwap); + V := (A xor B) and T; + A := A xor V; + B := B xor V; +end; + +procedure ConstTimeConditionalSwap32(CanSwap: Boolean; var A, B: Cardinal); +var + T, V: Cardinal; +begin + T := ConstTimeExpandBoolean32(CanSwap); + V := (A xor B) and T; + A := A xor V; + B := B xor V; +end; + +procedure ConstTimeConditionalSwap64(CanSwap: Boolean; var A, B: TUInt64); +var + T, V: TUInt64; +begin + T := ConstTimeExpandBoolean64(CanSwap); + V := (A xor B) and T; + A := A xor V; + B := B xor V; +end; + +function ConstTimeEqual8(A, B: Byte): Boolean; +var + R: Byte; +begin + R := not (A xor B); // + R := R and (R shr 4); // һһ + R := R and (R shr 2); // һλ 0 + R := R and (R shr 1); // 0 + Result := Boolean(R); // ֻȫ 1 1 +end; + +function ConstTimeEqual16(A, B: Word): Boolean; +begin + Result := ConstTimeEqual8(Byte(A shr 8), Byte(B shr 8)) + and ConstTimeEqual8(Byte(A and $FF), Byte(B and $FF)); +end; + +function ConstTimeEqual32(A, B: Cardinal): Boolean; +begin + Result := ConstTimeEqual16(Word(A shr 16), Word(B shr 16)) + and ConstTimeEqual16(Word(A and $FFFF), Word(B and $FFFF)); +end; + +function ConstTimeEqual64(A, B: TUInt64): Boolean; +begin + Result := ConstTimeEqual32(Cardinal(A shr 32), Cardinal(B shr 32)) + and ConstTimeEqual32(Cardinal(A and $FFFFFFFF), Cardinal(B and $FFFFFFFF)); +end; + +function ConstTimeCompareMem(P1, P2: Pointer; ByteLength: Integer): Boolean; +var + B1, B2: PByte; + I: Integer; + Diff: Byte; +begin + Diff := 0; + B1 := PByte(P1); + B2 := PByte(P2); + + for I := 0 to ByteLength - 1 do + begin + Diff := Diff or (B1^ xor B2^); + Inc(B1); + Inc(B2); + end; + + Result := Diff = 0; +end; + +function ConstTimeCompareBytes(const A, B: TBytes): Boolean; +begin + if Length(A) <> Length(B) then + Result := False + else + Result := ConstTimeCompareMem(@A[0], @B[0], Length(A)); +end; + +function ConstTimeExpandBoolean8(V: Boolean): Byte; +begin + Result := Byte(V); + Result := not Result; // V True 0˲ R Ǵ $FFR ͷ 0 + Result := Result and (Result shr 4); // һһ + Result := Result and (Result shr 2); // һλ 0 + Result := Result and (Result shr 1); // 00000000 00000001 + Result := Result or (Result shl 1); // True õ 00000000False õ 00000001λ + Result := Result or (Result shl 2); + Result := Result or (Result shl 4); // ȫ 0 ȫ 1 + Result := not Result; // ȫ 1 ȫ 0 +end; + +function ConstTimeExpandBoolean16(V: Boolean): Word; +var + R: Byte; +begin + R := ConstTimeExpandBoolean8(V); + Result := R; + Result := (Result shl 8) or R; // ֽȫ 1 ȫ 0 ˫ֽ +end; + +function ConstTimeExpandBoolean32(V: Boolean): Cardinal; +var + R: Word; +begin + R := ConstTimeExpandBoolean16(V); + Result := R; + Result := (Result shl 16) or R; // ˫ֽȫ 1 ȫ 0 ֽ +end; + +function ConstTimeExpandBoolean64(V: Boolean): TUInt64; +var + R: Cardinal; +begin + R := ConstTimeExpandBoolean32(V); + Result := R; + Result := (Result shl 32) or R; // ֽȫ 1 ȫ 0 ɰֽ +end; + +function ConstTimeConditionalSelect8(Condition: Boolean; A, B: Byte): Byte; +begin + ConstTimeConditionalSwap8(Condition, A, B); + Result := B; +end; + +function ConstTimeConditionalSelect16(Condition: Boolean; A, B: Word): Word; +begin + ConstTimeConditionalSwap16(Condition, A, B); + Result := B; +end; + +function ConstTimeConditionalSelect32(Condition: Boolean; A, B: Cardinal): Cardinal; +begin + ConstTimeConditionalSwap32(Condition, A, B); + Result := B; +end; + +function ConstTimeConditionalSelect64(Condition: Boolean; A, B: TUInt64): TUInt64; +begin + ConstTimeConditionalSwap64(Condition, A, B); + Result := B; +end; + +{$IFDEF MSWINDOWS} + +{$IFDEF CPUX64} + +// 64 λ IDIV IDIV ָʵ֣ A RCX B EDX/RDX DivRes ַ R8 ModRes ַ R9 +procedure Int64DivInt32Mod(A: Int64; B: Integer; var DivRes, ModRes: Integer); assembler; +asm + PUSH RCX // RCX A + MOV RCX, RDX // B RCX + POP RAX // A RAX + XOR RDX, RDX // 64 λ + IDIV RCX + MOV [R8], EAX // ̷ R8 ָ DivRes + MOV [R9], EDX // R9 ָ ModRes +end; + +procedure UInt64DivUInt32Mod(A: TUInt64; B: Cardinal; var DivRes, ModRes: Cardinal); assembler; +asm + PUSH RCX // RCX A + MOV RCX, RDX // B RCX + POP RAX // A RAX + XOR RDX, RDX // 64 λ + DIV RCX + MOV [R8], EAX // ̷ R8 ָ DivRes + MOV [R9], EDX // R9 ָ ModRes +end; + +// 64 λ IDIV IDIV ָʵ֣ALo RCXAHi RDXB R8DivRes ĵַ R9 +procedure Int128DivInt64Mod(ALo, AHi: Int64; B: Int64; var DivRes, ModRes: Int64); assembler; +asm + MOV RAX, RCX // ALo RAXAHi Ѿ RDX + MOV RCX, R8 // B RCX + IDIV RCX + MOV [R9], RAX // ̷ R9 ָ DivRes + MOV RAX, [RBP + $30] // ModRes ַ RAX + MOV [RAX], RDX // RAX ָ ModRes +end; + +procedure UInt128DivUInt64Mod(ALo, AHi: UInt64; B: UInt64; var DivRes, ModRes: UInt64); assembler; +asm + MOV RAX, RCX // ALo RAXAHi Ѿ RDX + MOV RCX, R8 // B RCX + DIV RCX + MOV [R9], RAX // ̷ R9 ָ DivRes + MOV RAX, [RBP + $30] // ModRes ַ RAX + MOV [RAX], RDX // RAX ָ ModRes +end; + +{$ELSE} + +// 32 λ IDIV IDIV ָʵ֣ A ڶջϣB EAXDivRes ַ EDXModRes ַ ECX +procedure Int64DivInt32Mod(A: Int64; B: Integer; var DivRes, ModRes: Integer); assembler; +asm + PUSH ECX // ECX ModRes ַȱ + MOV ECX, B // B EAX УƵ ECX + PUSH EDX // DivRes ĵַ EDX УҲ + MOV EAX, [EBP + $8] // A Lo + MOV EDX, [EBP + $C] // A Hi + IDIV ECX + POP ECX // ECXõ DivRes ַ + MOV [ECX], EAX + POP ECX // ECXõ ModRes ַ + MOV [ECX], EDX +end; + +procedure UInt64DivUInt32Mod(A: TUInt64; B: Cardinal; var DivRes, ModRes: Cardinal); assembler; +asm + PUSH ECX // ECX ModRes ַȱ + MOV ECX, B // B EAX УƵ ECX + PUSH EDX // DivRes ĵַ EDX УҲ + MOV EAX, [EBP + $8] // A Lo + MOV EDX, [EBP + $C] // A Hi + DIV ECX + POP ECX // ECXõ DivRes ַ + MOV [ECX], EAX + POP ECX // ECXõ ModRes ַ + MOV [ECX], EDX +end; + +// 32 λµʵ +procedure Int128DivInt64Mod(ALo, AHi: Int64; B: Int64; var DivRes, ModRes: Int64); +var + C: Integer; +begin + if B = 0 then + raise EDivByZero.Create(SDivByZero); + + if (AHi = 0) or (AHi = $FFFFFFFFFFFFFFFF) then // 64 λΪ 0 ֵֵ + begin + DivRes := ALo div B; + ModRes := ALo mod B; + end + else + begin + if B < 0 then // Ǹ + begin + Int128DivInt64Mod(ALo, AHi, -B, DivRes, ModRes); + DivRes := -DivRes; + Exit; + end; + + if AHi < 0 then // Ǹ + begin + // AHi, ALo 1Եõֵ + AHi := not AHi; + ALo := not ALo; +{$IFDEF SUPPORT_UINT64} + UInt64Add(UInt64(ALo), UInt64(ALo), 1, C); +{$ELSE} + UInt64Add(ALo, ALo, 1, C); +{$ENDIF} + if C > 0 then + AHi := AHi + C; + + // ת + Int128DivInt64Mod(ALo, AHi, B, DivRes, ModRes); + + // ٵ + if ModRes = 0 then + DivRes := -DivRes + else + begin + DivRes := -DivRes - 1; + ModRes := B - ModRes; + end; + Exit; + end; + + // ȫ +{$IFDEF SUPPORT_UINT64} + UInt128DivUInt64Mod(TUInt64(ALo), TUInt64(AHi), TUInt64(B), TUInt64(DivRes), TUInt64(ModRes)); +{$ELSE} + UInt128DivUInt64Mod(ALo, AHi, B, DivRes, ModRes); +{$ENDIF} + end; +end; + +procedure UInt128DivUInt64Mod(ALo, AHi: TUInt64; B: TUInt64; var DivRes, ModRes: TUInt64); +var + I, Cnt: Integer; + Q, R: TUInt64; +begin + if B = 0 then + raise EDivByZero.Create(SDivByZero); + + if AHi = 0 then + begin + DivRes := UInt64Div(ALo, B); + ModRes := UInt64Mod(ALo, B); + end + else + begin + // иλеλզ죿жǷ AHi >= BʾҪ 64 λ + if UInt64Compare(AHi, B) >= 0 then + raise EIntOverflow.Create(SIntOverflow); + + Q := 0; + R := 0; + Cnt := GetUInt64LowBits(AHi) + 64; + for I := Cnt downto 0 do + begin + R := R shl 1; + if IsUInt128BitSet(ALo, AHi, I) then // ĵ I λǷ 0 + R := R or 1 + else + R := R and TUInt64(not 1); + + if UInt64Compare(R, B) >= 0 then + begin + R := R - B; + Q := Q or (TUInt64(1) shl I); + end; + end; + DivRes := Q; + ModRes := R; + end; +end; + +{$ENDIF} + +{$ENDIF} + +{$IFDEF SUPPORT_UINT64} + +// ֻҪ֧ 64 λ 32/64 λ Intel ARM Delphi FPCʲôϵͳ + +function UInt64Mod(A, B: TUInt64): TUInt64; +begin + Result := A mod B; +end; + +function UInt64Div(A, B: TUInt64): TUInt64; +begin + Result := A div B; +end; + +{$ELSE} +{ + ֧ UInt64 ĵͰ汾 Delphi Int64 A mod/div B + + õջ˳ A ĸλA ĵλB ĸλB ĵλ push ϲ뺯 + ESP ǷصַESP+4 B ĵλESP + 8 B ĸλESP + C A ĵλESP + 10 A ĸλ + push esp ESP 4Ȼ mov ebp esp֮ EBP ѰַȫҪ 4 + + System.@_llumod ҪڸսʱEAX <- A ĵλEDX <- A ĸλSystem Դע EAX/EDX дˣ + [ESP + 8]Ҳ EBP + C<- B ĸλ[ESP + 4] Ҳ EBP + 8<- B ĵλ + + CALL ǰľƴ롣UInt64 Div Ҳ +} +function UInt64Mod(A, B: TUInt64): TUInt64; +asm + // PUSH ESP ESP 4Ҫ + MOV EAX, [EBP + $10] // A Lo + MOV EDX, [EBP + $14] // A Hi + PUSH DWORD PTR[EBP + $C] // B Hi + PUSH DWORD PTR[EBP + $8] // B Lo + CALL System.@_llumod; +end; + +function UInt64Div(A, B: TUInt64): TUInt64; +asm + // PUSH ESP ESP 4Ҫ + MOV EAX, [EBP + $10] // A Lo + MOV EDX, [EBP + $14] // A Hi + PUSH DWORD PTR[EBP + $C] // B Hi + PUSH DWORD PTR[EBP + $8] // B Lo + CALL System.@_lludiv; +end; + +{$ENDIF} + +{$IFDEF SUPPORT_UINT64} + +// ֻҪ֧ 64 λ 32/64 λ Intel ARM Delphi FPCʲôϵͳ + +function UInt64Mul(A, B: Cardinal): TUInt64; +begin + Result := TUInt64(A) * B; +end; + +{$ELSE} // ֻеͰ汾 Delphi Win32 x86 + +{ + 32 λˣֱʹ Int64 ģ 64 λ + + üĴԼ A -> EAXB -> EDXʹöջ + System.@_llmul ҪڸսʱEAX <- A ĵλEDX <- A ĸλ 0 + [ESP + 8]Ҳ EBP + C<- B ĸλ 0[ESP + 4] Ҳ EBP + 8<- B ĵλ +} +function UInt64Mul(A, B: Cardinal): TUInt64; +asm + PUSH 0 // PUSH B λ 0 + PUSH EDX // PUSH B λ + // EAX A λѾ + XOR EDX, EDX // EDX A λ 0 + CALL System.@_llmul; // EAX 32 λEDX 32 λ +end; + +{$ENDIF} + +// 64 λӣ ResLo ResHi +procedure UInt64AddUInt64(A, B: TUInt64; var ResLo, ResHi: TUInt64); +var + X, Y, Z, T, R0L, R0H, R1L, R1H: Cardinal; + R0, R1, R01, R12: TUInt64; +begin + // ˼룺2^32 ϵ M (xM+y) + (zM+t) = (x+z) M + (y+t) + // y+t R0 ռ 01x+z R1 ռ 12 R0, R1 ٲӳ R01, R12 + if IsUInt64AddOverflow(A, B) then + begin + X := Int64Rec(A).Hi; + Y := Int64Rec(A).Lo; + Z := Int64Rec(B).Hi; + T := Int64Rec(B).Lo; + + R0 := TUInt64(Y) + TUInt64(T); + R1 := TUInt64(X) + TUInt64(Z); + + R0L := Int64Rec(R0).Lo; + R0H := Int64Rec(R0).Hi; + R1L := Int64Rec(R1).Lo; + R1H := Int64Rec(R1).Hi; + + R01 := TUInt64(R0H) + TUInt64(R1L); + R12 := TUInt64(R1H) + TUInt64(Int64Rec(R01).Hi); + + Int64Rec(ResLo).Lo := R0L; + Int64Rec(ResLo).Hi := Int64Rec(R01).Lo; + Int64Rec(ResHi).Lo := Int64Rec(R12).Lo; + Int64Rec(ResHi).Hi := Int64Rec(R12).Hi; + end + else + begin + ResLo := A + B; + ResHi := 0; + end; +end; + +{$IFDEF WIN64} // ע Linux 64 ²֧ ASMֻ WIN64 + +// 64 λ 64 λˣ ResLo ResHi Уֱûʵ֣һ +procedure UInt64MulUInt64(A, B: UInt64; var ResLo, ResHi: UInt64); assembler; +asm + PUSH RAX + MOV RAX, RCX + MUL RDX // ţзŵ IMUL + MOV [R8], RAX + MOV [R9], RDX + POP RAX +end; + +{$ELSE} + +// 64 λˣ ResLo ResHi +procedure UInt64MulUInt64(A, B: TUInt64; var ResLo, ResHi: TUInt64); +var + X, Y, Z, T: Cardinal; + YT, XT, ZY, ZX: TUInt64; + P, R1Lo, R1Hi, R2Lo, R2Hi: TUInt64; +begin + // ˼룺2^32 ϵ M (xM+y)*(zM+t) = xzM^2 + (xt+yz)M + yt + // ϵ UInt64xz ռ 234xt+yz ռ 123yt ռ 01Ȼۼ + X := Int64Rec(A).Hi; + Y := Int64Rec(A).Lo; + Z := Int64Rec(B).Hi; + T := Int64Rec(B).Lo; + + YT := UInt64Mul(Y, T); + XT := UInt64Mul(X, T); + ZY := UInt64Mul(Y, Z); + ZX := UInt64Mul(X, Z); + + Int64Rec(ResLo).Lo := Int64Rec(YT).Lo; + + P := Int64Rec(YT).Hi; + UInt64AddUInt64(P, XT, R1Lo, R1Hi); + UInt64AddUInt64(ZY, R1Lo, R2Lo, R2Hi); + + Int64Rec(ResLo).Hi := Int64Rec(R2Lo).Lo; + + P := TUInt64(Int64Rec(R2Lo).Hi) + TUInt64(Int64Rec(ZX).Lo); + + Int64Rec(ResHi).Lo := Int64Rec(P).Lo; + Int64Rec(ResHi).Hi := Int64Rec(R1Hi).Lo + Int64Rec(R2Hi).Lo + Int64Rec(ZX).Hi + Int64Rec(P).Hi; +end; + +{$ENDIF} + +{$HINTS OFF} + +function _ValUInt64(const S: string; var Code: Integer): TUInt64; +const + FirstIndex = 1; +var + I: Integer; + Dig: Integer; + Sign: Boolean; + Empty: Boolean; +begin + I := FirstIndex; + Dig := 0; + Result := 0; + + if S = '' then + begin + Code := 1; + Exit; + end; + + while S[I] = Char(' ') do + Inc(I); + Sign := False; + + if S[I] = Char('-') then + begin + Sign := True; + Code := 1; // ָ֧ + Inc(I); + end + else if S[I] = Char('+') then + Inc(I); + Empty := True; + + if (S[I] = Char('$')) or (UpCase(S[I]) = Char('X')) + or ((S[I] = Char('0')) and (I < Length(S)) and (UpCase(S[I + 1]) = Char('X'))) then + begin + if S[I] = Char('0') then + Inc(I); + Inc(I); + while True do + begin + if I > Length(S) then + Break; + case Char(S[I]) of + Char('0').. Char('9'): Dig := Ord(S[I]) - Ord('0'); + Char('A').. Char('F'): Dig := Ord(S[I]) - (Ord('A') - 10); + Char('a').. Char('f'): Dig := Ord(S[I]) - (Ord('a') - 10); + else + Break; + end; + + if Result > (CN_MAX_TUINT64 shr 4) then + Break; + if Sign and (Dig <> 0) then + Break; + + Result := Result shl 4 + TUInt64(Dig); + Inc(I); + Empty := False; + end; + end + else + begin + while True do + begin + if I > Length(S) then + Break; + case Char(S[I]) of + Char('0').. Char('9'): Dig := Ord(S[I]) - Ord('0'); + else + Break; + end; + + if Result > UInt64Div(CN_MAX_TUINT64, 10) then + Break; + if Sign and (Dig <> 0) then + Break; + + Result := Result * 10 + TUInt64(Dig); + Inc(I); + Empty := False; + end; + end; + + if ((I <= Length(S)) and (S[I] <> Char(#0))) or Empty then + Code := I + 1 - FirstIndex + else + Code := 0; +end; + +function _ValUInt32(const S: string; var Code: Integer): Cardinal; +const + FirstIndex = 1; +var + I: Integer; + Dig: Integer; + Sign: Boolean; + Empty: Boolean; +begin + I := FirstIndex; + Dig := 0; + Result := 0; + + if S = '' then + begin + Code := 1; + Exit; + end; + + while S[I] = Char(' ') do + Inc(I); + Sign := False; + + if S[I] = Char('-') then + begin + Sign := True; + Code := 1; // ָ֧ + Inc(I); + end + else if S[I] = Char('+') then + Inc(I); + Empty := True; + + if (S[I] = Char('$')) or (UpCase(S[I]) = Char('X')) + or ((S[I] = Char('0')) and (I < Length(S)) and (UpCase(S[I + 1]) = Char('X'))) then + begin + if S[I] = Char('0') then + Inc(I); + Inc(I); + while True do + begin + if I > Length(S) then + Break; + case Char(S[I]) of + Char('0').. Char('9'): Dig := Ord(S[I]) - Ord('0'); + Char('A').. Char('F'): Dig := Ord(S[I]) - (Ord('A') - 10); + Char('a').. Char('f'): Dig := Ord(S[I]) - (Ord('a') - 10); + else + Break; + end; + + if Result > (CN_MAX_UINT32 shr 4) then + Break; + if Sign and (Dig <> 0) then + Break; + + Result := Result shl 4 + Cardinal(Dig); + Inc(I); + Empty := False; + end; + end + else + begin + while True do + begin + if I > Length(S) then + Break; + case Char(S[I]) of + Char('0').. Char('9'): Dig := Ord(S[I]) - Ord('0'); + else + Break; + end; + + if Result > (CN_MAX_UINT32 div 10) then + Break; + if Sign and (Dig <> 0) then + Break; + + Result := Result * 10 + Cardinal(Dig); + Inc(I); + Empty := False; + end; + end; + + if ((I <= Length(S)) and (S[I] <> Char(#0))) or Empty then + Code := I + 1 - FirstIndex + else + Code := 0; +end; + +{$HINTS ON} + +function UInt64ToHex(N: TUInt64; RemoveZeroPrefix: Boolean): string; +const + Digits: array[0..15] of Char = ('0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); + + function HC(B: Byte): string; + begin + Result := string(Digits[(B shr 4) and $0F] + Digits[B and $0F]); + end; + +begin + Result := + HC(Byte((N and $FF00000000000000) shr 56)) + + HC(Byte((N and $00FF000000000000) shr 48)) + + HC(Byte((N and $0000FF0000000000) shr 40)) + + HC(Byte((N and $000000FF00000000) shr 32)) + + HC(Byte((N and $00000000FF000000) shr 24)) + + HC(Byte((N and $0000000000FF0000) shr 16)) + + HC(Byte((N and $000000000000FF00) shr 8)) + + HC(Byte((N and $00000000000000FF))); + + if RemoveZeroPrefix then + begin + while (Length(Result) > 1) and (Result[1] = '0') do + Delete(Result, 1, 1); + end; +end; + +function UInt64ToStr(N: TUInt64): string; +begin + Result := Format('%u', [N]); +end; + +function StrToUInt64(const S: string): TUInt64; +{$IFNDEF DELPHIXE6_UP} +var + E: Integer; +{$ENDIF} +begin +{$IFDEF DELPHIXE6_UP} + Result := SysUtils.StrToUInt64(S); // StrToUInt64 only exists under XE6 or above +{$ELSE} + Result := _ValUInt64(S, E); + if E <> 0 then raise EConvertError.CreateResFmt(@SInvalidInteger, [S]); +{$ENDIF} +end; + +function StrToUInt(const S: string): Cardinal; +{$IFNDEF DELPHI102_TOKYO_UP} +var + E: Integer; +{$ENDIF} +begin +{$IFDEF DELPHI102_TOKYO_UP} + Result := SysUtils.StrToUInt(S); // StrToUInt only exists under D102T or above +{$ELSE} + Result := _ValUInt32(S, E); + if E <> 0 then raise EConvertError.CreateResFmt(@SInvalidInteger, [S]); +{$ENDIF} +end; + +function UInt64Compare(A, B: TUInt64): Integer; +{$IFNDEF SUPPORT_UINT64} +var + HiA, HiB, LoA, LoB: Cardinal; +{$ENDIF} +begin +{$IFDEF SUPPORT_UINT64} + if A > B then + Result := 1 + else if A < B then + Result := -1 + else + Result := 0; +{$ELSE} + HiA := (A and $FFFFFFFF00000000) shr 32; + HiB := (B and $FFFFFFFF00000000) shr 32; + if HiA > HiB then + Result := 1 + else if HiA < HiB then + Result := -1 + else + begin + LoA := Cardinal(A and $00000000FFFFFFFF); + LoB := Cardinal(B and $00000000FFFFFFFF); + if LoA > LoB then + Result := 1 + else if LoA < LoB then + Result := -1 + else + Result := 0; + end; +{$ENDIF} +end; + +function UInt64Sqrt(N: TUInt64): TUInt64; +var + Rem, Root: TUInt64; + I: Integer; +begin + Result := 0; + if N = 0 then + Exit; + + if UInt64Compare(N, 4) < 0 then + begin + Result := 1; + Exit; + end; + + Rem := 0; + Root := 0; + + for I := 0 to 31 do + begin + Root := Root shl 1; + Inc(Root); + + Rem := Rem shl 2; + Rem := Rem or (N shr 62); + N := N shl 2; + + if UInt64Compare(Root, Rem) <= 0 then + begin + Rem := Rem - Root; + Inc(Root); + end + else + Dec(Root); + end; + Result := Root shr 1; +end; + +function UInt32IsNegative(N: Cardinal): Boolean; +begin + Result := (N and (1 shl 31)) <> 0; +end; + +function UInt64IsNegative(N: TUInt64): Boolean; +begin +{$IFDEF SUPPORT_UINT64} + Result := (N and (UInt64(1) shl 63)) <> 0; +{$ELSE} + Result := N < 0; +{$ENDIF} +end; + +// UInt64 ijһλ 1λ Index 0 ʼ +procedure UInt64SetBit(var B: TUInt64; Index: Integer); +begin + B := B or (TUInt64(1) shl Index); +end; + +// UInt64 ijһλ 0λ Index 0 ʼ +procedure UInt64ClearBit(var B: TUInt64; Index: Integer); +begin + B := B and not (TUInt64(1) shl Index); +end; + +// UInt64 ĵڼλǷ 10 ʼ +function GetUInt64BitSet(B: TUInt64; Index: Integer): Boolean; +begin + B := B and (TUInt64(1) shl Index); + Result := B <> 0; +end; + +// UInt64 1 ߶λǵڼλλ 0û 1 -1 +function GetUInt64HighBits(B: TUInt64): Integer; +var + I: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + for I := 63 downto 0 do + begin + if (B and (TUInt64(1) shl I)) <> 0 then // TUInt64 ǿתó 8 ߶λΪ 35 Ĵ + begin + Result := I; + Break; + end; + end; +end; + +// Cardinal 1 ߶λǵڼλλ 0û 1 -1 +function GetUInt32HighBits(B: Cardinal): Integer; +var + I: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + for I := 31 downto 0 do + begin + if (B and (1 shl I)) <> 0 then + begin + Result := I; + Break; + end; + end; +end; + +// Word 1 ߶λǵڼλλ 0û 1 -1 +function GetUInt16HighBits(B: Word): Integer; +var + I: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + for I := 15 downto 0 do + begin + if (B and (1 shl I)) <> 0 then + begin + Result := I; + Break; + end; + end; +end; + +// Byte 1 ߶λǵڼλλ 0û 1 -1 +function GetUInt8HighBits(B: Byte): Integer; +var + I: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + for I := 7 downto 0 do + begin + if (B and (1 shl I)) <> 0 then + begin + Result := I; + Break; + end; + end; +end; + +// 64 λȥλ 0 ʣµλȣû 1 0 +function GetUInt64BitLength(B: TUInt64): Integer; +begin + Result := 1 + GetUInt64HighBits(B); +end; + +// 32 λȥλ 0 ʣµλȣû 1 0 +function GetUInt32BitLength(B: Cardinal): Integer; +begin + Result := 1 + GetUInt32HighBits(B); +end; + +// 16 λȥλ 0 ʣµλȣû 1 0 +function GetUInt16BitLength(B: Word): Integer; +begin + Result := 1 + GetUInt16HighBits(B); +end; + +// 8 λȥλ 0 ʣµλȣû 1 0 +function GetUInt8BitLength(B: Byte): Integer; +begin + Result := 1 + GetUInt8HighBits(B); +end; + +// UInt64 1 Ͷλǵڼλλ 0û 1 -1 +function GetUInt64LowBits(B: TUInt64): Integer; +var + I: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + for I := 0 to 63 do + begin + if (B and (1 shl I)) <> 0 then + begin + Result := I; + Break; + end; + end; +end; + +// Cardinal 1 Ͷλǵڼλλ 0û 1 -1 +function GetUInt32LowBits(B: Cardinal): Integer; +var + I: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + for I := 0 to 31 do + begin + if (B and (1 shl I)) <> 0 then + begin + Result := I; + Break; + end; + end; +end; + +// Word 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 +function GetUInt16LowBits(B: Word): Integer; +var + I: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + for I := 0 to 15 do + begin + if (B and (1 shl I)) <> 0 then + begin + Result := I; + Break; + end; + end; +end; + +// Byte 1 Ͷλǵڼλλ 0ͬĩβ 0û 1 -1 +function GetUInt8LowBits(B: Byte): Integer; +var + I: Integer; +begin + Result := -1; + if B = 0 then + Exit; + + for I := 0 to 7 do + begin + if (B and (1 shl I)) <> 0 then + begin + Result := I; + Break; + end; + end; +end; + +// װ Int64 Modֵʱȡģģ +function Int64Mod(M, N: Int64): Int64; +begin + if M > 0 then + Result := M mod N + else + Result := N - ((-M) mod N); +end; + +function Int64CenterMod(A: Int64; N: Int64): Int64; +begin + Result := Int64NonNegativeMod(A, N); + if Result > N div 2 then // ߰벿ֱӼ N + Result := Result - N; +end; + +// жһ 32 λǷ 2 +function IsUInt32PowerOf2(N: Cardinal): Boolean; +begin + Result := (N and (N - 1)) = 0; +end; + +// жһ 64 λǷ 2 +function IsUInt64PowerOf2(N: TUInt64): Boolean; +begin + Result := (N and (N - 1)) = 0; +end; + +// õһָ 32 λȵ 2 ݣ 0 +function GetUInt32PowerOf2GreaterEqual(N: Cardinal): Cardinal; +begin + Result := N - 1; + Result := Result or (Result shr 1); + Result := Result or (Result shr 2); + Result := Result or (Result shr 4); + Result := Result or (Result shr 8); + Result := Result or (Result shr 16); + Inc(Result); +end; + +// õһָ 64 λ 2 ݣ 0 +function GetUInt64PowerOf2GreaterEqual(N: TUInt64): TUInt64; +begin + Result := N - 1; + Result := Result or (Result shr 1); + Result := Result or (Result shr 2); + Result := Result or (Result shr 4); + Result := Result or (Result shr 8); + Result := Result or (Result shr 16); + Result := Result or (Result shr 32); + Inc(Result); +end; + +// ж 32 λзǷ 32 λз +function IsInt32AddOverflow(A, B: Integer): Boolean; +var + C: Integer; +begin + C := A + B; + Result := ((A > 0) and (B > 0) and (C < 0)) or // ͬҽ˵ + ((A < 0) and (B < 0) and (C > 0)); +end; + +// ж 32 λǷ 32 λ +function IsUInt32AddOverflow(A, B: Cardinal): Boolean; +begin + Result := (A + B) < A; // ӣֻҪСһ˵ +end; + +// ж 64 λзǷ 64 λз +function IsInt64AddOverflow(A, B: Int64): Boolean; +var + C: Int64; +begin + C := A + B; + Result := ((A > 0) and (B > 0) and (C < 0)) or // ͬҽ˵ + ((A < 0) and (B < 0) and (C > 0)); +end; + +// ж 64 λǷ 64 λ +function IsUInt64AddOverflow(A, B: TUInt64): Boolean; +begin + Result := UInt64Compare(A + B, A) < 0; // ӣֻҪСһ˵ +end; + +function IsUInt64SubOverflowInt32(A: TUInt64; B: TUInt64): Boolean; +var + GT: Boolean; + R: TUInt64; +begin + GT := UInt64Compare(A, B) >= 0; // GT ʾ A >= B + if GT then + begin + R := A - B; + // ж 64 λŷΧ R Ƿ MaxInt32 + Result := UInt64Compare(R, TUInt64(CN_MAX_INT32)) > 0; + end + else + begin + R := B - A; + // ж 64 λзŷΧ -R ǷС MinInt32Ҳж 64 λ R Ƿ MinInt32 ʽ + Result := UInt64Compare(R, CN_MIN_INT32_IN_INT64) > 0; + end; +end; + +// 64 λӣA + B => R 1 λ +procedure UInt64Add(var R: TUInt64; A, B: TUInt64; out Carry: Integer); +begin + R := A + B; + if UInt64Compare(R, A) < 0 then // ӣֻҪСһ˵ + Carry := 1 + else + Carry := 0; +end; + +// 64 λA - B => Rнλ 1 λ +procedure UInt64Sub(var R: TUInt64; A, B: TUInt64; out Carry: Integer); +begin + R := A - B; + if UInt64Compare(R, A) > 0 then // ֻҪڱ˵λ + Carry := 1 + else + Carry := 0; +end; + +// ж 32 λзǷ 32 λз +function IsInt32MulOverflow(A, B: Integer): Boolean; +var + T: Integer; +begin + T := A * B; + Result := (B <> 0) and ((T div B) <> A); +end; + +// ж 32 λǷ 32 λ +function IsUInt32MulOverflow(A, B: Cardinal): Boolean; +var + T: TUInt64; +begin + T := TUInt64(A) * TUInt64(B); + Result := (T = Cardinal(T)); +end; + +// ж 32 λǷ 64 λзδҲ False ʱR ֱӷؽ +function IsUInt32MulOverflowInt64(A, B: Cardinal; out R: TUInt64): Boolean; +var + T: Int64; +begin + T := Int64(A) * Int64(B); + Result := T < 0; // Int64 ֵ˵ + if not Result then + R := TUInt64(T); +end; + +// ж 64 λзǷ 64 λз +function IsInt64MulOverflow(A, B: Int64): Boolean; +var + T: Int64; +begin + T := A * B; + Result := (B <> 0) and ((T div B) <> A); +end; + +// ָת֧ͣ 32/64 λ +function PointerToInteger(P: Pointer): Integer; +begin +{$IFDEF CPU64BITS} + // ôд Pointer ĵ 32 λ Integer + Result := Integer(P); +{$ELSE} + Result := Integer(P); +{$ENDIF} +end; + +// תָ֧ͣ 32/64 λ +function IntegerToPointer(I: Integer): Pointer; +begin +{$IFDEF CPU64BITS} + // ôд Pointer ĵ 32 λ Integer + Result := Pointer(I); +{$ELSE} + Result := Pointer(I); +{$ENDIF} +end; + +// Int64 Χĺ࣬Ҫ N 0 +function Int64NonNegativeAddMod(A, B, N: Int64): Int64; +begin + if IsInt64AddOverflow(A, B) then // Int64 + begin + if A > 0 then + begin + // A B 0 UInt64 ȡģδ UInt64 ޣע N δ Int64 ȡģС Int64 ޣɸֵ + Result := UInt64NonNegativeAddMod(A, B, N); + end + else + begin + // A B С 0ȡ UInt64 ȡģĺδ UInt64 ޣģٱһ +{$IFDEF SUPPORT_UINT64} + Result := UInt64(N) - UInt64NonNegativeAddMod(-A, -B, N); +{$ELSE} + Result := N - UInt64NonNegativeAddMod(-A, -B, N); +{$ENDIF} + end; + end + else // ֱӼ + Result := Int64NonNegativeMod(A + B, N); +end; + +// UInt64 Χĺ࣬Ҫ N 0 +function UInt64NonNegativeAddMod(A, B, N: TUInt64): TUInt64; +var + C, D: TUInt64; +begin + if IsUInt64AddOverflow(A, B) then // + begin + C := UInt64Mod(A, N); // ģ + D := UInt64Mod(B, N); + if IsUInt64AddOverflow(C, D) then + begin + // ˵ģģûá + // һڵ 2^63N 2^63 + 1 + // = + 2^64 + // mod N = mod N + (2^64 - 1) mod N) + 1 + // N 2^63 + 1 2^64 - 2ǰӲֱӺһģ + Result := UInt64Mod(UInt64Mod(A + B, N) + UInt64Mod(CN_MAX_TUINT64, N) + 1, N); + end + else + Result := UInt64Mod(C + D, N); + end + else + begin + Result := UInt64Mod(A + B, N); + end; +end; + +function Int64NonNegativeMulMod(A, B, N: Int64): Int64; +var + Neg: Boolean; +begin + if N <= 0 then + raise EDivByZero.Create(SDivByZero); + + // ΧСֱ + if not IsInt64MulOverflow(A, B) then + begin + Result := A * B mod N; + if Result < 0 then + Result := Result + N; + Exit; + end; + + // ŵ + Result := 0; + if (A = 0) or (B = 0) then + Exit; + + Neg := False; + if (A < 0) and (B > 0) then + begin + A := -A; + Neg := True; + end + else if (A > 0) and (B < 0) then + begin + B := -B; + Neg := True; + end + else if (A < 0) and (B < 0) then + begin + A := -A; + B := -B; + end; + + // λѭ + while B <> 0 do + begin + if (B and 1) <> 0 then + Result := ((Result mod N) + (A mod N)) mod N; + + A := A shl 1; + if A >= N then + A := A mod N; + + B := B shr 1; + end; + + if Neg then + Result := N - Result; +end; + +function UInt64NonNegativeMulMod(A, B, N: TUInt64): TUInt64; +begin + Result := 0; + if (UInt64Compare(A, CN_MAX_UINT32) <= 0) and (UInt64Compare(B, CN_MAX_UINT32) <= 0) then + begin + Result := UInt64Mod(A * B, N); // 㹻СĻֱӳ˺ģ + end + else + begin + while B <> 0 do + begin + if (B and 1) <> 0 then + Result := UInt64NonNegativeAddMod(Result, A, N); + + A := UInt64NonNegativeAddMod(A, A, N); + // ôͳ㷨 A := A shl 1 N mod NΪ + + B := B shr 1; + end; + end; +end; + +// װķǸຯҲΪʱӸ豣֤ P 0 +function Int64NonNegativeMod(N: Int64; P: Int64): Int64; +begin + if P <= 0 then + raise EDivByZero.Create(SDivByZero); + + Result := N mod P; + if Result < 0 then + Inc(Result, P); +end; + +// Int64 ķǸָ +function Int64NonNegativPower(N: Int64; Exp: Integer): Int64; +var + T: Int64; +begin + if Exp < 0 then + raise ERangeError.Create(SRangeError) + else if Exp = 0 then + begin + if N <> 0 then + Result := 1 + else + raise EDivByZero.Create(SDivByZero); + end + else if Exp = 1 then + Result := N + else + begin + Result := 1; + T := N; + + while Exp > 0 do + begin + if (Exp and 1) <> 0 then + Result := Result * T; + + Exp := Exp shr 1; + T := T * T; + end; + end; +end; + +function Int64NonNegativeRoot(N: Int64; Exp: Integer): Int64; +var + I: Integer; + X: Int64; + X0, X1: Extended; +begin + if (Exp < 0) or (N < 0) then + raise ERangeError.Create(SRangeError) + else if Exp = 0 then + raise EDivByZero.Create(SDivByZero) + else if (N = 0) or (N = 1) then + Result := N + else if Exp = 2 then + Result := UInt64Sqrt(N) + else + begin + // ţٵ + I := GetUInt64HighBits(N) + 1; // õԼ Log2 N ֵ + I := (I div Exp) + 1; + X := 1 shl I; // õһϴ X0 ֵΪʼֵ + + X0 := X; + X1 := X0 - (Power(X0, Exp) - N) / (Exp * Power(X0, Exp - 1)); + + while True do + begin + if (Trunc(X0) = Trunc(X1)) and (Abs(X0 - X1) < 0.001) then + begin + Result := Trunc(X1); // Trunc ֻ֧ Int64˻ + Exit; + end; + + X0 := X1; + X1 := X0 - (Power(X0, Exp) - N) / (Exp * Power(X0, Exp - 1)); + end; + end; +end; + +function UInt64NonNegativPower(N: TUInt64; Exp: Integer): TUInt64; +var + T, RL, RH: TUInt64; +begin + if Exp < 0 then + raise ERangeError.Create(SRangeError) + else if Exp = 0 then + begin + if N <> 0 then + Result := 1 + else + raise EDivByZero.Create(SDivByZero); + end + else if Exp = 1 then + Result := N + else + begin + Result := 1; + T := N; + + while Exp > 0 do + begin + if (Exp and 1) <> 0 then + begin + UInt64MulUInt64(Result, T, RL, RH); + Result := RL; + end; + + Exp := Exp shr 1; + UInt64MulUInt64(T, T, RL, RH); + T := RL; + end; + end; +end; + +function UInt64NonNegativeRoot(N: TUInt64; Exp: Integer): TUInt64; +var + Bits: Integer; + L, H, M, B, P: TUInt64; + Cmp: Integer; + Overflow: Boolean; + E: Integer; +begin + if Exp < 0 then + raise ERangeError.Create(SRangeError) + else if Exp = 0 then + raise EDivByZero.Create(SDivByZero) + else if (N = 0) or (N = 1) then + Result := N + else if Exp = 1 then + Result := N + else if Exp = 2 then + Result := UInt64Sqrt(N) + else + begin + // ֲ ֵ䣻 + // + ǰж Ƚ M^Exp N + // շ floor(N^(1/Exp)) + + Bits := GetUInt64HighBits(N) + 1; // õԼ Log2 N ֵ + H := TUInt64(1) shl ((Bits + Exp - 1) div Exp); + if H = 0 then + H := N + else if H > N then + H := N; + L := 1; + Cmp := -1; + + while L <= H do + begin + M := L + ((H - L) shr 1); + B := M; + P := 1; + E := Exp; + Overflow := False; + while E > 0 do + begin + if (E and 1) <> 0 then + begin + if (B <> 0) and (P > N div B) then + begin + Overflow := True; + Break; + end; + P := P * B; + end; + E := E shr 1; + if E > 0 then + begin + if (B <> 0) and (B > N div B) then + begin + Overflow := True; + Break; + end; + B := B * B; + end; + end; + + if Overflow then + Cmp := 1 + else if P > N then + Cmp := 1 + else if P < N then + Cmp := -1 + else + Cmp := 0; + + if Cmp = 0 then + begin + Result := M; + Exit; + end + else if Cmp < 0 then + L := M + 1 + else + begin + if M = 0 then + Break; + H := M - 1; + end; + end; + + if Cmp > 0 then + Result := H + else + Result := L - 1; + end; +end; + +function IsUInt128BitSet(Lo, Hi: TUInt64; N: Integer): Boolean; +begin + if N < 64 then + Result := (Lo and (TUInt64(1) shl N)) <> 0 + else + begin + Dec(N, 64); + Result := (Hi and (TUInt64(1) shl N)) <> 0; + end; +end; + +procedure SetUInt128Bit(var Lo, Hi: TUInt64; N: Integer); +begin + if N < 64 then + Lo := Lo or (TUInt64(1) shl N) + else + begin + Dec(N, 64); + Hi := Hi or (TUInt64(1) shl N); + end; +end; + +procedure ClearUInt128Bit(var Lo, Hi: TUInt64; N: Integer); +begin + if N < 64 then + Lo := Lo and not (TUInt64(1) shl N) + else + begin + Dec(N, 64); + Hi := Hi and not (TUInt64(1) shl N); + end; +end; + +function UnsignedAddWithLimitRadix(A, B, C: Cardinal; var R: Cardinal; + L, H: Cardinal): Cardinal; +begin + R := A + B + C; + if R > H then // нλ + begin + A := H - L + 1; // õ + B := R - L; // õ L ֵ + + Result := B div A; // Ƶĵڼͽ + R := L + (B mod A); // ȥƺ + end + else + Result := 0; +end; + +procedure InternalQuickSort(Mem: Pointer; L, R: Integer; ElementByteSize: Integer; + CompareProc: TCnMemSortCompareProc); +var + I, J, P: Integer; +begin + repeat + I := L; + J := R; + P := (L + R) shr 1; + repeat + while CompareProc(Pointer(TCnIntAddress(Mem) + I * ElementByteSize), + Pointer(TCnIntAddress(Mem) + P * ElementByteSize), ElementByteSize) < 0 do + Inc(I); + while CompareProc(Pointer(TCnIntAddress(Mem) + J * ElementByteSize), + Pointer(TCnIntAddress(Mem) + P * ElementByteSize), ElementByteSize) > 0 do + Dec(J); + + if I <= J then + begin + MemorySwap(Pointer(TCnIntAddress(Mem) + I * ElementByteSize), + Pointer(TCnIntAddress(Mem) + J * ElementByteSize), ElementByteSize); + + if P = I then + P := J + else if P = J then + P := I; + Inc(I); + Dec(J); + end; + until I > J; + + if L < J then + InternalQuickSort(Mem, L, J, ElementByteSize, CompareProc); + L := I; + until I >= R; +end; + +function DefaultCompareProc(P1, P2: Pointer; ElementByteSize: Integer): Integer; +begin + Result := MemoryCompare(P1, P2, ElementByteSize); +end; + +procedure MemoryQuickSort(Mem: Pointer; ElementByteSize: Integer; + ElementCount: Integer; CompareProc: TCnMemSortCompareProc); +begin + if (Mem <> nil) and (ElementCount > 0) and (ElementCount > 0) then + begin + if Assigned(CompareProc) then + InternalQuickSort(Mem, 0, ElementCount - 1, ElementByteSize, CompareProc) + else + InternalQuickSort(Mem, 0, ElementCount - 1, ElementByteSize, DefaultCompareProc); + end; +end; + +{$IFDEF COMPILER5} + +function BoolToStr(Value: Boolean; UseBoolStrs: Boolean): string; +begin + if UseBoolStrs then + begin + if Value then + Result := 'True' + else + Result := 'False'; + end + else + begin + if Value then + Result := '-1' + else + Result := '0'; + end; +end; + +{$ENDIF} + +// =========================== ѭλ ==================================== + +function RotateLeft16(A: Word; N: Integer): Word; +begin + Result := (A shl N) or (A shr (16 - N)); +end; + +function RotateRight16(A: Word; N: Integer): Word; +begin + Result := (A shr N) or (A shl (16 - N)); +end; + +function RotateLeft32(A: Cardinal; N: Integer): Cardinal; +begin + Result := (A shl N) or (A shr (32 - N)); +end; + +function RotateRight32(A: Cardinal; N: Integer): Cardinal; +begin + Result := (A shr N) or (A shl (32 - N)); +end; + +function RotateLeft64(A: TUInt64; N: Integer): TUInt64; +begin + Result := (A shl N) or (A shr (64 - N)); +end; +function RotateRight64(A: TUInt64; N: Integer): TUInt64; +begin + Result := (A shr N) or (A shl (64 - N)); +end; + +initialization + FByteOrderIsBigEndian := CurrentByteOrderIsBigEndian; + +end. diff --git a/CnPack/Crypto/CnPemUtils.pas b/CnPack/Crypto/CnPemUtils.pas new file mode 100644 index 0000000..45d5d3c --- /dev/null +++ b/CnPack/Crypto/CnPemUtils.pas @@ -0,0 +1,1332 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnPemUtils; +{* |
+================================================================================ +* ƣ +* ԪƣPEM ʽ뵥Ԫ +* ԪߣCnPack +* עԪʵ PEM ʽĶȡ뱣棬ӽܻơ +* Ҳʵ PKCS1/PKCS5/PKCS7/ISO10126 ȶ봦ơ +* ע֧ PKCS12 淶֤鼰Կװʽ +* ƽ̨WinXP + Delphi 5.0 +* ݲԣδ +* õԪ豾ػ +* ļ¼2026.04.05 V1.8 +* ǿְȫ +* 2026.03.24 V1.7 +* ض汾ı TStringList д Stream BOM ƣʵ +* 2024.05.27 V1.6 +* ISO10126 Ĵ +* 2023.12.14 V1.5 +* SaveMemoryToPemStream δ +* 2022.03.09 V1.4 +* PKCS5 Ĵ +* 2021.05.14 V1.3 +* ĸ PKCS7 Ĵ +* 2020.03.27 V1.2 +* ģ Openssl ʵ PEM ļд룬ֲֻּ֧㷨 +* Ŀǰд des/3des/aes128/192/256 PKCS7 룬 Openssl 1.0.2g +* 2020.03.23 V1.1 +* ģ Openssl ʵ PEM ļܶȡֲֻּ֧㷨 +* Ŀǰȡ des/3des/aes128/192/256 PKCS7 룬 Openssl 1.0.2g +* 2020.03.18 V1.0 +* Ԫ CnRSA ж +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes, CnNative, CnRandom, CnKDF, CnBase64, CnAES, CnDES, CnSM4; + +const + CN_PKCS1_BLOCK_TYPE_PRIVATE_00 = 00; + {* PKCS1 ʱĿֵֶһĬӦ RSA ˽Կܻǩϣ RFC2313 Ƽʹ} + + CN_PKCS1_BLOCK_TYPE_PRIVATE_FF = 01; + {* PKCS1 ʱĿֵֶĬӦ RSA ˽ԿܻǩϣRFC2313 Ƽʹ} + + CN_PKCS1_BLOCK_TYPE_PUBLIC_RANDOM = 02; + {* PKCS1 ʱĿֵֶĬӦ RSA ĹԿܳ} + + CN_PKCS1_PADDING_SIZE = 11; + {* PKCS1 ĴСֵһǰ 00һֽڡ 8 ֽ䣬һ 00 β} + + CN_PKCS5_BLOCK_SIZE = 8; + {* PKCS5 ĬϿС} + + CN_PKCS7_BLOCK_SIZE = 16; + {* PKCS7 СAES} + +type + TCnKeyHashMethod = (ckhMd5, ckhSha256); + {* PEM ʽֵ֧Ӵ} + + TCnKeyEncryptMethod = (ckeNone, ckeDES, cke3DES, ckeAES128, ckeAES192, ckeAES256, + ckeSM4); + {* PEM ʽֵ֧ļ} + +// ======================= PEM ļдּ֧ӽ ======================== + +function LoadPemFileToMemory(const FileName: string; const ExpectHead: string; + const ExpectTail: string; MemoryStream: TMemoryStream; const Password: string = ''; + KeyHashMethod: TCnKeyHashMethod = ckhMd5): Boolean; +{* PEM ʽļָ֤ͷβʵݲܽ Base64 롣 + + + const FileName: string - ļ + const ExpectHead: string - ͷ + const ExpectTail: string - β + MemoryStream: TMemoryStream - ڴ + const Password: string - ļܣڴṩ + KeyHashMethod: TCnKeyHashMethod - ļʹõӴ + + ֵBoolean - ضǷɹ +} + +function LoadPemStreamToMemory(Stream: TStream; const ExpectHead: string; + const ExpectTail: string; MemoryStream: TMemoryStream; const Password: string = ''; + KeyHashMethod: TCnKeyHashMethod = ckhMd5): Boolean; +{* PEM ʽָ֤ͷβʵݲܽ Base64 롣 + + + Stream: TStream - + const ExpectHead: string - ͷ + const ExpectTail: string - β + MemoryStream: TMemoryStream - ڴ + const Password: string - ܣڴṩ + KeyHashMethod: TCnKeyHashMethod - ʹõӴ + + ֵBoolean - ضǷɹ +} + +function SaveMemoryToPemFile(const FileName: string; const Head: string; const Tail: string; + MemoryStream: TMemoryStream; KeyEncryptMethod: TCnKeyEncryptMethod = ckeNone; + KeyHashMethod: TCnKeyHashMethod = ckhMd5; const Password: string = ''; Append: Boolean = False): Boolean; +{* ݽ Base64 ܷвͷβдļAppend Ϊ True ʱʾӡ + + + const FileName: string - дĿļ + const Head: string - дͷ + const Tail: string - дβ + MemoryStream: TMemoryStream - д + KeyEncryptMethod: TCnKeyEncryptMethod - üͣĬϲ + KeyHashMethod: TCnKeyHashMethod - Ӵ + const Password: string - 룬 + Append: Boolean - Ƿӵķʽд + + ֵBoolean - Ƿдɹ +} + +function SaveMemoryToPemStream(Stream: TStream; const Head: string; const Tail: string; + MemoryStream: TMemoryStream; KeyEncryptMethod: TCnKeyEncryptMethod = ckeNone; + KeyHashMethod: TCnKeyHashMethod = ckhMd5; const Password: string = ''; Append: Boolean = False): Boolean; +{* ݽ Base64 ܷвͷβдAppend Ϊ True ʱʾӡ + + + Stream: TStream - дĿ + const Head: string - дͷ + const Tail: string - дβ + MemoryStream: TMemoryStream - д + KeyEncryptMethod: TCnKeyEncryptMethod - üͣĬϲ + KeyHashMethod: TCnKeyHashMethod - ӴͣĬϲӴ + const Password: string - 룬 + Append: Boolean - Ƿӵķʽд + + ֵBoolean - Ƿдɹ +} + +// ===================== PKCS1 / PKCS7 Padding 봦 ==================== + +function AddPKCS1Padding(PaddingType: Integer; BlockSize: Integer; Data: Pointer; + DataByteLen: Integer; OutStream: TStream): Boolean; +{* ݿ鲹д Stream Уسɹڲô롣 + PaddingType ȡ 012BlockLen ֽ 128 ȡʽ + EB = 00 || BT || PS || 00 || D + 00 ǰ涨ֽڣBT 1 ֽڵ PaddingType0 1 2 ֱ 00 FF + PS Ķֽݣ 00 ǹ涨Ľβֽڡ + + + PaddingType: Integer - ͣȡ 0 1 2 + BlockSize: Integer - ֽڳ + Data: Pointer - ݿĵַ + DataByteLen: Integer - ݿֽڳ + OutStream: TStream - + + ֵBoolean - ضǷӳɹ +} + +function RemovePKCS1Padding(InData: Pointer; InDataByteLen: Integer; OutBuf: Pointer; + out OutByteLen: Integer): Boolean; +{* ȥݿ PKCS1 PaddingسɹOutBuf ָĿóб֤ + ɹOutLen ԭݳȡ + + + InData: Pointer - ȥݿĵַ + InDataByteLen: Integer - ȥݿֽڳ + OutBuf: Pointer - ȥݵ䳤ȱ㹻 + out OutByteLen: Integer - ȥݳ + + ֵBoolean - ضǷȥɹ +} + +function GetPKCS7PaddingByteLength(OrignalByteLen: Integer; BlockSize: Integer): Integer; +{* ԭʼ鳤ȼ PKCS7 ijȡ + + + OrignalByteLen: Integer - ԭʼֽڳ + BlockSize: Integer - PKCS7 ֽڳ + + ֵInteger - PKCS7 ֽڳ +} + +procedure AddPKCS7Padding(Stream: TMemoryStream; BlockSize: Integer); +{* ĩβ PKCS7 涨䡰ݡ + + + Stream: TMemoryStream - ڴݣݽдβ + BlockSize: Integer - PKCS7 ֽڳ + + ֵޣ +} + +procedure RemovePKCS7Padding(Stream: TMemoryStream); +{* ȥ PKCS7 涨ĩβ䡰ݡ + + + Stream: TMemoryStream - ȥڴ + + ֵޣ} + +function StrAddPKCS7Padding(const Str: AnsiString; BlockSize: Integer): AnsiString; +{* ַĩβ PKCS7 涨䡰ݡ + + + const Str: AnsiString - ַ + BlockSize: Integer - PKCS7 ֽڳ + + ֵAnsiString - ضַ +} + +function StrRemovePKCS7Padding(const Str: AnsiString): AnsiString; +{* ȥ PKCS7 涨ַĩβ䡰ݡ + + + const Str: AnsiString - ȥַ + + ֵAnsiString - ȥַ +} + +procedure BytesAddPKCS7Padding(var Data: TBytes; BlockSize: Integer); +{* ֽĩβ PKCS7 涨䡰ݡ + + + var Data: TBytes - ֽ飬ݽβ + BlockSize: Integer - PKCS7 ֽڳ + + ֵޣ +} + +procedure BytesRemovePKCS7Padding(var Data: TBytes); +{* ȥ PKCS7 涨ֽĩβ䡰ݡ + + + var Data: TBytes - ȥֽ + + ֵޣ +} + +procedure AddPKCS5Padding(Stream: TMemoryStream); +{* ĩβ PKCS5 涨䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + Stream: TMemoryStream - ڴݽβ + + ֵޣ +} + +procedure RemovePKCS5Padding(Stream: TMemoryStream); +{* ȥ PKCS7 涨ĩβ䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + Stream: TMemoryStream - ȥڴ + + ֵޣ +} + +function StrAddPKCS5Padding(const Str: AnsiString): AnsiString; +{* ַĩβ PKCS5 涨䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + const Str: AnsiString - ַ + + ֵAnsiString - ضַ +} + +function StrRemovePKCS5Padding(const Str: AnsiString): AnsiString; +{* ȥ PKCS5 涨ַĩβ䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + const Str: AnsiString - ȥַ + + ֵAnsiString - ȥַ +} + +procedure BytesAddPKCS5Padding(var Data: TBytes); +{* ֽĩβ PKCS5 涨䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + var Data: TBytes - ֽ飬ݽβ + + ֵޣ +} + +procedure BytesRemovePKCS5Padding(var Data: TBytes); +{* ȥ PKCS7 涨ֽĩβ䡰ݣѭ PKCS7 淶С̶Ϊ 8 ֽڡ + + + var Data: TBytes - ȥֽ + + ֵޣ +} + +function GetISO10126PaddingByteLength(OrignalByteLen: Integer; BlockSize: Integer): Integer; +{* ԭʼ鳤ȼ ISO10126Padding ijȡ + + + OrignalByteLen: Integer - ԭʼֽڳ + BlockSize: Integer - ISO10126 ֽڳ + + ֵInteger - PKCS7 ֽڳ +} + +procedure AddISO10126Padding(Stream: TMemoryStream; BlockSize: Integer); +{* ĩβ ISO10126Padding 涨䡰ͼݡ + + + Stream: TMemoryStream - ڴݽβ + BlockSize: Integer - ISO10126 ֽڳ + + ֵޣ +} + +procedure RemoveISO10126Padding(Stream: TMemoryStream); +{* ȥ ISO10126Padding 涨ĩβ䡰ͼݡ + + + Stream: TMemoryStream - ȥڴ + + ֵޣ +} + +function StrAddISO10126Padding(const Str: AnsiString; BlockSize: Integer): AnsiString; +{* ַĩβ ISO10126Padding 涨䡰ͼݡ + + + const Str: AnsiString - ַ + BlockSize: Integer - ISO10126 ֽڴС + + ֵAnsiString - ضַ +} + +function StrRemoveISO10126Padding(const Str: AnsiString): AnsiString; +{* ȥ ISO10126Padding 涨ַĩβ䡰ͼݡ + + + const Str: AnsiString - ȥַ + + ֵAnsiString - ȥַ +} + +procedure BytesAddISO10126Padding(var Data: TBytes; BlockSize: Integer); +{* ֽĩβ ISO10126Padding 涨䡰ͼݡ + + + var Data: TBytes - ֽ飬ݽβ + BlockSize: Integer - ISO10126 ֽڳ + + ֵޣ +} + +procedure BytesRemoveISO10126Padding(var Data: TBytes); +{* ȥ ISO10126Padding 涨ֽĩβ䡰ͼݡ + + + var Data: TBytes - ȥֽ + + ֵޣ +} + +implementation + +uses + CnStrings; + +const + ENC_HEAD_PROCTYPE = 'Proc-Type:'; + ENC_HEAD_PROCTYPE_NUM = '4'; + ENC_HEAD_ENCRYPTED = 'ENCRYPTED'; + ENC_HEAD_DEK = 'DEK-Info:'; + + ENC_TYPE_AES128 = 'AES-128'; + ENC_TYPE_AES192 = 'AES-192'; + ENC_TYPE_AES256 = 'AES-256'; + ENC_TYPE_DES = 'DES'; + ENC_TYPE_3DES = 'DES-EDE3'; + ENC_TYPE_SM4 = 'SM4'; + + ENC_BLOCK_CBC = 'CBC'; + + ENC_TYPE_STRS: array[TCnKeyEncryptMethod] of string = + ('', ENC_TYPE_DES, ENC_TYPE_3DES, ENC_TYPE_AES128, ENC_TYPE_AES192, + ENC_TYPE_AES256, ENC_TYPE_SM4); + + ENC_TYPE_BLOCK_SIZE: array[TCnKeyEncryptMethod] of Byte = + (0, 8, 8, 16, 16, 16, 16); + +function Min(A, B: Integer): Integer; +begin + if A < B then + Result := A + else + Result := B; +end; + +function AddPKCS1Padding(PaddingType, BlockSize: Integer; Data: Pointer; + DataByteLen: Integer; OutStream: TStream): Boolean; +var + I: Integer; + B, F: Byte; + RandBuf: TBytes; +begin + Result := False; + if (Data = nil) or (DataByteLen <= 0) then + Exit; + + // + if DataByteLen > BlockSize - CN_PKCS1_PADDING_SIZE then + Exit; + + B := 0; + OutStream.Write(B, 1); // дǰֽ 00 + B := PaddingType; + F := BlockSize - DataByteLen - 3; // 3 ʾһǰ 00һֽڡһ 00 β + + OutStream.Write(B, 1); + case PaddingType of + CN_PKCS1_BLOCK_TYPE_PRIVATE_00: + begin + B := 0; + for I := 1 to F do + OutStream.Write(B, 1); + end; + CN_PKCS1_BLOCK_TYPE_PRIVATE_FF: + begin + B := $FF; + for I := 1 to F do + OutStream.Write(B, 1); + end; + CN_PKCS1_BLOCK_TYPE_PUBLIC_RANDOM: + begin + // ʹѧȫCSPRNGȫ Random/Randomize + // ԭʹ LCG α+ʱӣԤ⣬ Bleichenbacher + if F > 0 then + begin + SetLength(RandBuf, F); + CnRandomBytes(F); // CnRandomBytes ɰȫֽ + for I := 0 to F - 1 do + begin + if RandBuf[I] = 0 then + RandBuf[I] := 1; // ȷ㣬 PKCS1 淶 + end; + OutStream.Write(RandBuf[0], F); + end; + end; + else + Exit; + end; + + B := 0; + OutStream.Write(B, 1); + OutStream.Write(Data^, DataByteLen); + Result := True; +end; + +function RemovePKCS1Padding(InData: Pointer; InDataByteLen: Integer; OutBuf: Pointer; + out OutByteLen: Integer): Boolean; +var + P: PAnsiChar; + I, J, Start: Integer; + ValidPadding: Integer; // ʹDzֵ֧ + LeadingZeros: Integer; + PaddingType: Byte; + SeparatorFound: Integer; +begin + // ʱʵ֣ Padding ǷЧִͬIJ + Result := False; + OutByteLen := 0; + P := PAnsiChar(InData); + + // ǰʱ䣩 + LeadingZeros := 0; + for I := 0 to InDataByteLen - 1 do + begin + // ʹλ֧ + ValidPadding := Ord(P[I] = #0) and Ord(I = LeadingZeros); + LeadingZeros := LeadingZeros + ValidPadding; + end; + + // ǷЧҪһֽڣ + if LeadingZeros >= InDataByteLen then + Exit; + + // ȡ Padding + PaddingType := Ord(P[LeadingZeros]); + + // ʱҷָ00 ֽڣ + Start := 0; + SeparatorFound := 0; + + for J := LeadingZeros + 1 to InDataByteLen - 1 do + begin + case PaddingType of + CN_PKCS1_BLOCK_TYPE_PRIVATE_00: + begin + // ҵһֽ + if (P[J] <> #0) and (SeparatorFound = 0) then + begin + Start := J; + SeparatorFound := 1; + end; + end; + CN_PKCS1_BLOCK_TYPE_PRIVATE_FF, + CN_PKCS1_BLOCK_TYPE_PUBLIC_RANDOM: + begin + // ҵһֽ + if (P[J] = #0) and (SeparatorFound = 0) then + begin + Start := J + 1; + SeparatorFound := 1; + end; + end; + end; + end; + + // ֤ Padding ͺͷָ + ValidPadding := Ord( + ((PaddingType = CN_PKCS1_BLOCK_TYPE_PRIVATE_00) or + (PaddingType = CN_PKCS1_BLOCK_TYPE_PRIVATE_FF) or + (PaddingType = CN_PKCS1_BLOCK_TYPE_PUBLIC_RANDOM)) and + (SeparatorFound = 1) and + (Start > 0) and + (Start < InDataByteLen) + ); + + // ʱ临 + if ValidPadding = 1 then + begin + Move(P[Start], OutBuf^, InDataByteLen - Start); + OutByteLen := InDataByteLen - Start; + Result := True; + end; + + // ע⣺ʹʧܣҲҪǰأֳʱ +end; + +function GetPKCS7PaddingByteLength(OrignalByteLen: Integer; BlockSize: Integer): Integer; +var + R: Byte; +begin + R := OrignalByteLen mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + Result := OrignalByteLen + R; +end; + +procedure AddPKCS7Padding(Stream: TMemoryStream; BlockSize: Integer); +var + R: Byte; + Buf: array[0..255] of Byte; +begin + R := Stream.Size mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + FillChar(Buf[0], R, R); + Stream.Position := Stream.Size; + Stream.Write(Buf[0], R); +end; + +procedure RemovePKCS7Padding(Stream: TMemoryStream); +var + L, I: Byte; + Len: Cardinal; + Mem, PBuf: Pointer; + Valid: Boolean; +begin + // ȥ Stream ĩβ 9 9 Padding + if Stream.Size > 1 then + begin + Stream.Position := Stream.Size - 1; + Stream.Read(L, 1); + + // ߴ粻ף + if (L < 1) or (L > CN_PKCS7_BLOCK_SIZE) or (Stream.Size < L) then + Exit; + + // ֽ֤ڶ Lֹ Padding Oracle + PBuf := Stream.Memory; + Valid := True; + for I := 1 to L do + if PByte(TCnNativeUInt(PBuf) + Stream.Size - I)^ <> L then + begin + Valid := False; + Break; + end; + + if not Valid then + Exit; + + Len := Stream.Size - L; + Mem := GetMemory(Len); + if Mem <> nil then + begin + Move(Stream.Memory^, Mem^, Len); + Stream.Clear; + Stream.Write(Mem^, Len); + FreeMemory(Mem); + end; + end; +end; + +function StrAddPKCS7Padding(const Str: AnsiString; BlockSize: Integer): AnsiString; +var + I, L: Integer; + R: Byte; +begin + L := Length(Str); + R := L mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + SetLength(Result, L + R); + if L > 0 then + Move(Str[1], Result[1], L); + + for I := 1 to R do + Result[L + I] := AnsiChar(R); +end; + +function StrRemovePKCS7Padding(const Str: AnsiString): AnsiString; +var + L: Integer; + I, V: Byte; + Valid: Boolean; +begin + Result := Str; + if Result = '' then + Exit; + + L := Length(Result); + V := Ord(Result[L]); // ĩǼʾ˼ + + // ֵ֤ϷԣPKCS7 ֵΧ 1~16С + if (V < 1) or (V > CN_PKCS7_BLOCK_SIZE) or (V > L) then + Exit; + + // ֽ֤ڶ Vֹ Padding Oracle + // ԭֻһֽڣδ֤мֽǷһ + Valid := True; + for I := 1 to V do + begin + if Ord(Result[L - I + 1]) <> V then + begin + Valid := False; + Break; + end; + end; + + if Valid then + Delete(Result, L - V + 1, V); +end; + +procedure AddPKCS5Padding(Stream: TMemoryStream); +begin + AddPKCS7Padding(Stream, CN_PKCS5_BLOCK_SIZE); +end; + +procedure RemovePKCS5Padding(Stream: TMemoryStream); +begin + RemovePKCS7Padding(Stream); +end; + +function StrAddPKCS5Padding(const Str: AnsiString): AnsiString; +begin + Result := StrAddPKCS7Padding(Str, CN_PKCS5_BLOCK_SIZE); +end; + +function StrRemovePKCS5Padding(const Str: AnsiString): AnsiString; +begin + Result := StrRemovePKCS7Padding(Str); +end; + +procedure BytesAddPKCS7Padding(var Data: TBytes; BlockSize: Integer); +var + R: Byte; + L, I: Integer; +begin + L := Length(Data); + R := L mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + SetLength(Data, L + R); + for I := 0 to R - 1 do + Data[L + I] := R; +end; + +procedure BytesRemovePKCS7Padding(var Data: TBytes); +var + L, I, V: Integer; + Valid: Boolean; +begin + L := Length(Data); + if L = 0 then + Exit; + + V := Ord(Data[L - 1]); // ĩǼʾ˼ֽ + + // ֵ֤ϷԣPKCS7 ֵΧ 1~16С + if (V < 1) or (V > CN_PKCS7_BLOCK_SIZE) or (V > L) then + Exit; + + // ֽ֤ڶ Vֹ Padding Oracle + Valid := True; + for I := 1 to V do + if Data[L - I] <> V then + begin + Valid := False; + Break; + end; + + if Valid then + SetLength(Data, L - V); +end; + +procedure BytesAddPKCS5Padding(var Data: TBytes); +begin + BytesAddPKCS7Padding(Data, CN_PKCS5_BLOCK_SIZE); +end; + +procedure BytesRemovePKCS5Padding(var Data: TBytes); +begin + BytesRemovePKCS7Padding(Data); +end; + +function GetISO10126PaddingByteLength(OrignalByteLen: Integer; BlockSize: Integer): Integer; +begin + Result := GetPKCS7PaddingByteLength(OrignalByteLen, BlockSize); // Ϊֱͬӵ +end; + +procedure AddISO10126Padding(Stream: TMemoryStream; BlockSize: Integer); +var + R: Byte; + RandBuf: TBytes; +begin + R := Stream.Size mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + // ʹѧȫ䣬 ISO/IEC 9797-1 + // ԭʹ FillChar ȫ 0 ʹܽȷ + SetLength(RandBuf, R); + RandBuf := CnRandomBytes(R); // ɰȫֽ + RandBuf[R - 1] := R; // һֽڼ¼䳤 + Stream.Position := Stream.Size; + Stream.Write(RandBuf[0], R); +end; + +procedure RemoveISO10126Padding(Stream: TMemoryStream); +begin + RemovePKCS7Padding(Stream); // Ϊֱͬӵ +end; + +function StrAddISO10126Padding(const Str: AnsiString; BlockSize: Integer): AnsiString; +var + I, L: Integer; + R: Byte; +begin + L := Length(Str); + R := L mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + SetLength(Result, L + R); + if L > 0 then + Move(Str[1], Result[1], L); + + if R > 1 then + begin + for I := 1 to R - 1 do + Result[L + I] := #0; + end; + Result[L + R] := AnsiChar(R); +end; + +function StrRemoveISO10126Padding(const Str: AnsiString): AnsiString; +begin + Result := StrRemovePKCS7Padding(Str); // Ϊֱͬӵ +end; + +procedure BytesAddISO10126Padding(var Data: TBytes; BlockSize: Integer); +var + R: Byte; + L, I: Integer; +begin + L := Length(Data); + R := L mod BlockSize; + R := BlockSize - R; + if R = 0 then + R := R + BlockSize; + + SetLength(Data, L + R); + if R > 1 then + begin + for I := 0 to R - 2 do + Data[L + I] := 0; + end; + Data[L - 1 + R] := R; +end; + +procedure BytesRemoveISO10126Padding(var Data: TBytes); +begin + BytesRemovePKCS7Padding(Data); // Ϊֱͬӵ +end; + +function EncryptPemStream(KeyHash: TCnKeyHashMethod; KeyEncrypt: TCnKeyEncryptMethod; + Stream: TStream; const Password: string; out EncryptedHead: string): Boolean; +const + CRLF = #13#10; +var + ES: TMemoryStream; + Keys: array[0..31] of Byte; // Key Ҳֻ 32 ֽ + IvStr: AnsiString; + HexIv: string; + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + AesIv: TCnAESBuffer; + DesKey: TCnDESKey; + Des3Key: TCn3DESKey; + DesIv: TCnDESIv; + Sm4Key: TCnSM4Key; + Sm4Iv: TCnSM4Iv; +begin + Result := False; + + // + if (KeyEncrypt = ckeNone) or (Password = '') then + Exit; + + // Iv + SetLength(IvStr, ENC_TYPE_BLOCK_SIZE[KeyEncrypt]); + CnRandomFillBytes(@(IvStr[1]), ENC_TYPE_BLOCK_SIZE[KeyEncrypt]); + HexIv := DataToHex(@(IvStr[1]), ENC_TYPE_BLOCK_SIZE[KeyEncrypt], True); // Ҫд + + EncryptedHead := ENC_HEAD_PROCTYPE + ' ' + ENC_HEAD_PROCTYPE_NUM + ',' + ENC_HEAD_ENCRYPTED + CRLF; + EncryptedHead := EncryptedHead + ENC_HEAD_DEK + ' ' + ENC_TYPE_STRS[KeyEncrypt] + + '-' + ENC_BLOCK_CBC + ',' + HexIv + CRLF; + + ES := TMemoryStream.Create; + Stream.Position := 0; + + try + if KeyHash = ckhMd5 then + begin + if not CnGetDeriveKey(AnsiString(Password), IvStr, @Keys[0], SizeOf(Keys)) then + Exit; + end + else if KeyHash = ckhSha256 then + begin + if not CnGetDeriveKey(AnsiString(Password), IvStr, @Keys[0], SizeOf(Keys), ckdSha256) then + Exit; + end + else + Exit; + + case KeyEncrypt of + ckeDES: + begin + Move(Keys[0], DesKey[0], SizeOf(TCnDESKey)); + Move(IvStr[1], DesIv[0], SizeOf(TCnDESIv)); + + DESEncryptStreamCBC(Stream, Stream.Size, DesKey, DesIv, ES); + Result := True; + end; + cke3DES: + begin + Move(Keys[0], Des3Key[0], SizeOf(TCn3DESKey)); + Move(IvStr[1], DesIv[0], SizeOf(TCn3DESIv)); + + TripleDESEncryptStreamCBC(Stream, Stream.Size, Des3Key, DesIv, ES); + Result := True; + end; + ckeAES128: + begin + Move(Keys[0], AESKey128[0], SizeOf(TCnAESKey128)); + Move(IvStr[1], AesIv[0], SizeOf(TCnAESBuffer)); + + EncryptAES128StreamCBC(Stream, Stream.Size, AESKey128, AesIv, ES); + Result := True; + end; + ckeAES192: + begin + Move(Keys[0], AESKey192[0], SizeOf(TCnAESKey192)); + Move(IvStr[1], AesIv[0], SizeOf(TCnAESBuffer)); + + EncryptAES192StreamCBC(Stream, Stream.Size, AESKey192, AesIv, ES); + Result := True; + end; + ckeAES256: + begin + Move(Keys[0], AESKey256[0], SizeOf(TCnAESKey256)); + Move(IvStr[1], AesIv[0], SizeOf(TCnAESBuffer)); + + EncryptAES256StreamCBC(Stream, Stream.Size, AESKey256, AesIv, ES); + Result := True; + end; + ckeSM4: + begin + Move(Keys[0], Sm4Key[0], SizeOf(TCnSM4Key)); + Move(IvStr[1], Sm4Iv[0], SizeOf(TCnSM4Iv)); + + SM4EncryptStreamCBC(Stream, Stream.Size, Sm4Key, Sm4Iv, ES); + Result := True; + end; + end; + finally + if ES.Size > 0 then + begin + // ES д Stream + Stream.Size := 0; + Stream.Position := 0; + ES.SaveToStream(Stream); + Stream.Position := 0; + end; + ES.Free; + end; +end; + +// ü㷨㡢ʼ Base64 Sд Stream +function DecryptPemString(const S, M1, M2, HexIv, Password: string; Stream: TMemoryStream; + KeyHash: TCnKeyHashMethod): Boolean; +var + DS: TMemoryStream; + Keys: array[0..31] of Byte; // Key Ҳֻ 32 ֽ + AESKey128: TCnAESKey128; + AESKey192: TCnAESKey192; + AESKey256: TCnAESKey256; + IvStr: AnsiString; + AesIv: TCnAESBuffer; + DesKey: TCnDESKey; + Des3Key: TCn3DESKey; + DesIv: TCnDESIv; + Sm4Key: TCnSM4Key; + Sm4Iv: TCnSM4Iv; +begin + Result := False; + DS := nil; + + if (M1 = '') or (M2 = '') or (HexIv = '') or (Password = '') then + Exit; + + try + DS := TMemoryStream.Create; + if ECN_BASE64_OK <> Base64Decode(S, DS, False) then + Exit; + + DS.Position := 0; + SetLength(IvStr, HexToData(HexIv)); + if Length(IvStr) > 0 then + HexToData(HexIv, @IvStr[1]); + + // Salt Լ Hash 㷨ӽܵ Key + FillChar(Keys[0], SizeOf(Keys), 0); + if KeyHash = ckhMd5 then + begin + if not CnGetDeriveKey(AnsiString(Password), IvStr, @Keys[0], SizeOf(Keys)) then + Exit; + end + else if KeyHash = ckhSha256 then + begin + if not CnGetDeriveKey(AnsiString(Password), IvStr, @Keys[0], SizeOf(Keys), ckdSha256) then + Exit; + end + else + Exit; + + // DS ģҪ Stream + if (M1 = ENC_TYPE_AES256) and (M2 = ENC_BLOCK_CBC) then + begin + // AES-256-CBC ܵ + Move(Keys[0], AESKey256[0], SizeOf(TCnAESKey256)); + Move(IvStr[1], AesIv[0], Min(SizeOf(TCnAESBuffer), Length(IvStr))); + + DecryptAES256StreamCBC(DS, DS.Size, AESKey256, AesIv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end + else if (M1 = ENC_TYPE_AES192) and (M2 = ENC_BLOCK_CBC) then + begin + // AES-192-CBC ܵ + Move(Keys[0], AESKey192[0], SizeOf(TCnAESKey192)); + Move(IvStr[1], AesIv[0], Min(SizeOf(TCnAESBuffer), Length(IvStr))); + + DecryptAES192StreamCBC(DS, DS.Size, AESKey192, AesIv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end + else if (M1 = ENC_TYPE_AES128) and (M2 = ENC_BLOCK_CBC) then + begin + // AES-128-CBC ܵģ D5 òƿ Bug ³ AV + Move(Keys[0], AESKey128[0], SizeOf(TCnAESKey128)); + Move(IvStr[1], AesIv[0], Min(SizeOf(TCnAESBuffer), Length(IvStr))); + + DecryptAES128StreamCBC(DS, DS.Size, AESKey128, AesIv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end + else if (M1 = ENC_TYPE_DES) and (M2 = ENC_BLOCK_CBC) then + begin + // DES-CBC ܵ + Move(Keys[0], DesKey[0], SizeOf(TCnDESKey)); + Move(IvStr[1], DesIv[0], Min(SizeOf(TCnDESIv), Length(IvStr))); + + DESDecryptStreamCBC(DS, DS.Size, DesKey, DesIv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end + else if (M1 = ENC_TYPE_3DES) and (M2 = ENC_BLOCK_CBC) then + begin + // 3DES-CBC ܵ + Move(Keys[0], Des3Key[0], SizeOf(TCn3DESKey)); + Move(IvStr[1], DesIv[0], Min(SizeOf(TCn3DESIv), Length(IvStr))); + + TripleDESDecryptStreamCBC(DS, DS.Size, Des3Key, DesIv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end + else if (M1 = ENC_TYPE_SM4) and (M2 = ENC_BLOCK_CBC) then + begin + // SM4-CBC ܵ + Move(Keys[0], Sm4Key[0], SizeOf(TCnSM4Key)); + Move(IvStr[1], Sm4Iv[0], Min(SizeOf(TCnSM4Iv), Length(IvStr))); + + SM4DecryptStreamCBC(DS, DS.Size, Sm4Key, Sm4Iv, Stream); + RemovePKCS7Padding(Stream); + Result := True; + end + finally + DS.Free; + end; +end; + +function LoadPemStreamToMemory(Stream: TStream; const ExpectHead, ExpectTail: string; + MemoryStream: TMemoryStream; const Password: string; KeyHashMethod: TCnKeyHashMethod): Boolean; +var + I, J, HeadIndex, TailIndex: Integer; + S, L1, L2, M1, M2, M3: string; + Sl: TStringList; +begin + Result := False; + + if (Stream <> nil) and (Stream.Size > 0) and (ExpectHead <> '') and (ExpectTail <> '') then + begin + Sl := TStringList.Create; + try + Sl.LoadFromStream(Stream); + if Sl.Count > 2 then + begin + HeadIndex := -1; + for I := 0 to Sl.Count - 1 do + begin + if Trim(Sl[I]) = ExpectHead then + begin + HeadIndex := I; + Break; + end; + end; + + if HeadIndex < 0 then + Exit; + + if HeadIndex > 0 then + for I := 0 to HeadIndex - 1 do + Sl.Delete(0); + + // ҵͷˣβ + + TailIndex := -1; + for I := 0 to Sl.Count - 1 do + begin + if Trim(Sl[I]) = ExpectTail then + begin + TailIndex := I; + Break; + end; + end; + + if TailIndex > 0 then // ҵβͣɾβͺĶ + begin + if TailIndex < Sl.Count - 1 then + for I := Sl.Count - 1 downto TailIndex + 1 do + Sl.Delete(Sl.Count - 1); + end + else + Exit; + + if Sl.Count < 2 then // ûݣ˳ + Exit; + + // ͷβ֤ͨǰжǷ + L1 := Sl[1]; + if Pos(ENC_HEAD_PROCTYPE, L1) = 1 then // Ǽܵ + begin + Delete(L1, 1, Length(ENC_HEAD_PROCTYPE)); + I := Pos(',', L1); + if I <= 1 then + Exit; + + if Trim(Copy(L1, 1, I - 1)) <> ENC_HEAD_PROCTYPE_NUM then + Exit; + + if Trim(Copy(L1, I + 1, MaxInt)) <> ENC_HEAD_ENCRYPTED then + Exit; + + // ProcType: 4,ENCRYPTED жͨ + + L2 := Sl[2]; + if Pos(ENC_HEAD_DEK, L2) <> 1 then + Exit; + + Delete(L2, 1, Length(ENC_HEAD_DEK)); + I := Pos(',', L2); + if I <= 1 then + Exit; + + M1 := Trim(Copy(L2, 1, I - 1)); // õ AES256-CBC + M3 := UpperCase(Trim(Copy(L2, I + 1, MaxInt))); // õʱʹõijʼ + I := Pos('-', M1); + if I <= 1 then + Exit; + J := Pos('-', Copy(M1, I + 1, MaxInt)); + if J > 0 then + I := I + J; // AES-256-CBC + + M2 := UpperCase(Trim(Copy(M1, I + 1, MaxInt))); // õģʽ ECB CBC + M1 := UpperCase(Trim(Copy(M1, 1, I - 1))); // õ㷨 DES AES + + // ͷβȫɾ + Sl.Delete(Sl.Count - 1); + Sl.Delete(0); + Sl.Delete(0); + Sl.Delete(0); + + S := ''; + for I := 0 to Sl.Count - 1 do + S := S + Sl[I]; + + S := Trim(S); + if not Base64IsStrictText(S) then + Exit; + + Result := DecryptPemString(S, M1, M2, M3, Password, MemoryStream, KeyHashMethod); + end + else // δܵģƴճ Base64 + begin + Sl.Delete(Sl.Count - 1); + Sl.Delete(0); + S := ''; + for I := 0 to Sl.Count - 1 do + S := S + Sl[I]; + + S := Trim(S); + + // To De Base64 S + MemoryStream.Clear; + if not Base64IsStrictText(S) then + Exit; + + Result := (ECN_BASE64_OK = Base64Decode(S, MemoryStream, False)); + end; + end; + finally + Sl.Free; + end; + end; +end; + +function LoadPemFileToMemory(const FileName, ExpectHead, ExpectTail: string; + MemoryStream: TMemoryStream; const Password: string; KeyHashMethod: TCnKeyHashMethod): Boolean; +var + Stream: TStream; +begin + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + Result := LoadPemStreamToMemory(Stream, ExpectHead, ExpectTail, MemoryStream, Password, KeyHashMethod); + finally + Stream.Free; + end; +end; + +procedure SplitStringToList(const S: string; List: TCnAnsiStrings); +const + LINE_WIDTH = 64; +var + C, R: AnsiString; +begin + if List = nil then + Exit; + + List.Clear; + if S <> '' then + begin + R := AnsiString(S); + while R <> '' do + begin + C := Copy(R, 1, LINE_WIDTH); + Delete(R, 1, LINE_WIDTH); + List.Add(C); + end; + end; +end; + +function SaveMemoryToPemFile(const FileName, Head, Tail: string; + MemoryStream: TMemoryStream; KeyEncryptMethod: TCnKeyEncryptMethod; + KeyHashMethod: TCnKeyHashMethod; const Password: string; Append: Boolean): Boolean; +var + S, EH: string; + List, Sl: TCnAnsiStringList; +begin + Result := False; + if (MemoryStream <> nil) and (MemoryStream.Size <> 0) then + begin + MemoryStream.Position := 0; + + if (KeyEncryptMethod <> ckeNone) and (Password <> '') then + begin + // MemoryStream + AddPKCS7Padding(MemoryStream, ENC_TYPE_BLOCK_SIZE[KeyEncryptMethod]); + + // ټ + if not EncryptPemStream(KeyHashMethod, KeyEncryptMethod, MemoryStream, Password, EH) then + Exit; + end; + + if ECN_BASE64_OK = Base64Encode(MemoryStream, S) then + begin + List := TCnAnsiStringList.Create; + try + SplitStringToList(S, List); + + List.Insert(0, AnsiString(Head)); // ͨͷ + if EH <> '' then // ͷ + List.Insert(1, AnsiString(EH)); + List.Add(AnsiString(Tail)); // ͨβ + + if Append and FileExists(FileName) then + begin + Sl := TCnAnsiStringList.Create; + try + Sl.LoadFromFile(AnsiString(FileName)); + Sl.AddStrings(List); + Sl.SaveToFile(AnsiString(FileName)); + finally + Sl.Free; + end; + end + else + List.SaveToFile(AnsiString(FileName)); + + Result := True; + finally + List.Free; + end; + end; + end; +end; + +function SaveMemoryToPemStream(Stream: TStream; const Head, Tail: string; + MemoryStream: TMemoryStream; KeyEncryptMethod: TCnKeyEncryptMethod; + KeyHashMethod: TCnKeyHashMethod; const Password: string; Append: Boolean): Boolean; +var + S, EH: string; + List: TCnAnsiStringList; +begin + Result := False; + if (MemoryStream <> nil) and (MemoryStream.Size <> 0) then + begin + MemoryStream.Position := 0; + + if (KeyEncryptMethod <> ckeNone) and (Password <> '') then + begin + // MemoryStream + AddPKCS7Padding(MemoryStream, ENC_TYPE_BLOCK_SIZE[KeyEncryptMethod]); + + // ټ + if not EncryptPemStream(KeyHashMethod, KeyEncryptMethod, MemoryStream, Password, EH) then + Exit; + end; + + if ECN_BASE64_OK = Base64Encode(MemoryStream, S) then + begin + List := TCnAnsiStringList.Create; + try + SplitStringToList(S, List); + + List.Insert(0, AnsiString(Head)); // ͨͷ + if EH <> '' then // ͷ + List.Insert(1, AnsiString(EH)); + List.Add(AnsiString(Tail)); // ͨβ + + if not Append then + Stream.Size := 0; + + List.SaveToStream(Stream); + + Result := True; + finally + List.Free; + end; + end; + end; +end; + +end. diff --git a/CnPack/Crypto/CnRandom.pas b/CnPack/Crypto/CnRandom.pas new file mode 100644 index 0000000..495da09 --- /dev/null +++ b/CnPack/Crypto/CnRandom.pas @@ -0,0 +1,574 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnRandom; +{* |
+================================================================================ +* ƣ +* Ԫƣ䵥Ԫ +* ԪߣCnPack (master@cnpack.org) +* עԪװ Windows ƽ̨ MacOS/Linux ƽ̨µİȫ +* ṩȫ书ܡ +* ƽ̨Win7 + Delphi 5.0 +* ݲԣWin32/Win64/MacOS/Linux + Unicode/NonUnicode +* õԪ豾ػ +* ļ¼2026.03.23 V1.5 +* һײѭ⣬ +* Windows ִȽLinux Mac ҲͬŻֽ +* 2026.01.29 V1.4 +* ܵģƫ²ֺ +* 2023.01.15 V1.3 +* Windows ȫ urandom ֧ Linux +* 2023.01.08 V1.2 +* Win64 API +* 2022.08.22 V1.1 +* ʹòϵͳṩ +* 2020.03.27 V1.0 +* Ԫ CnPrime ж +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + SysUtils {$IFDEF MSWINDOWS}, Windows {$ENDIF}, Classes, CnNative; + +type + ECnRandomAPIError = class(Exception); + {* 쳣} + +function RandomUInt64: TUInt64; +{* UInt64 Χڵڲ֧ UInt64 ƽ̨ Int64 档 + + + ޣ + + ֵTUInt64 - UInt64 Χڵ +} + +function RandomUInt64LessThan(HighValue: TUInt64): TUInt64; +{* شڵ 0 Сָ UInt64 ֵ + + + HighValue: TUInt64 - ָ UInt64 + + ֵTUInt64 - شڵ 0 Сָ HighValue +} + +function RandomInt64: Int64; +{* شڵ 0 С Int64 + + + ޣ + + ֵInt64 - شڵ 0 С Int64 +} + +function RandomInt64LessThan(HighValue: Int64): Int64; +{* شڵ 0 Сָ Int64 ֵб֤ HighValue 0 + + + HighValue: Int64 - ָ Int64 + + ֵInt64 - شڵ 0 Сָ HighValue +} + +function RandomUInt32: Cardinal; +{* UInt32 Χڵ + + + ޣ + + ֵCardinal - UInt32 Χڵ +} + +function RandomUInt32LessThan(HighValue: Cardinal): Cardinal; +{* شڵ 0 Сָ UInt32 ֵ + + + HighValue: Cardinal - ָ UInt32 + + ֵCardinal - شڵ 0 Сָ HighValue +} + +function RandomInt32: Integer; +{* شڵ 0 С Int32 + + + ޣ + + ֵInteger - شڵ 0 С Int32 +} + +function RandomInt32LessThan(HighValue: Integer): Integer; +{* شڵ 0 Сָ Int32 б֤ HighValue 0 + + + HighValue: Integer - ָ Int32 + + ֵInteger - شڵ 0 Сָ HighValue +} + +function CnKnuthShuffle(ArrayBase: Pointer; ElementByteSize: Integer; + ElementCount: Integer): Boolean; +{* ߵϴ㷨 ArrayBase ָԪسߴΪ ElementSize ElementCount Ԫؾϴơ + + + ArrayBase: Pointer - ϴƵڴַ + ElementByteSize: Integer - ϴƵÿڴԪҲÿһƵֽڴС + ElementCount: Integer - ڴԪҲƵ + + ֵBoolean - ϴǷɹ +} + +function CnRandomFillBytes(Buf: PAnsiChar; BufByteLen: Integer): Boolean; +{* ʹ Windows API /dev/random 豸ʵ䣬ڲγʼ沢ͷš + + + Buf: PAnsiChar - ڴַ + BufByteLen: Integer - ڴֽڳ + + ֵBoolean - Ƿɹ +} + +function CnRandomFillBytes2(Buf: PAnsiChar; BufByteLen: Integer): Boolean; +{* ʹ Windows API /dev/urandom 豸ʵ䣬 + Windows ʹԤȳʼõ١ + + + Buf: PAnsiChar - ڴַ + BufByteLen: Integer - ڴֽڳ + + ֵBoolean - Ƿɹ +} + +function CnRandomBytes(ByteLen: Integer): TBytes; +{* ʹ Windows API /dev/random 豸䲢ָȵֽ顣 + + + ByteLen: Integer - ɵֽֽڳ + + ֵTBytes - ֽ +} + +function CnRandomFloat: Extended; +{* ʹѧȫ [0, 1) ΧڵĸΪģ Delphi Random + ڲ 4 ֽ $1000000002^32õȷϸС 1.0 + + + + + ֵExtended - 0 <= Result < 1 +} + +implementation + +resourcestring + SCnErrorNoSecureRandom = 'NO Secure Random Generator!'; + +{$IFDEF MSWINDOWS} + +const + ADVAPI32 = 'advapi32.dll'; + + CRYPT_VERIFYCONTEXT = $F0000000; + CRYPT_NEWKEYSET = $8; + CRYPT_DELETEKEYSET = $10; + + PROV_RSA_FULL = 1; + NTE_BAD_KEYSET = $80090016; + + BCRYPT_USE_SYSTEM_PREFERRED_RNG = $00000002; + bcryptdll = 'bcrypt.dll'; + +function CryptAcquireContext(phProv: PHandle; pszContainer: PAnsiChar; + pszProvider: PAnsiChar; dwProvType: LongWord; dwFlags: LongWord): BOOL; + stdcall; external ADVAPI32 name 'CryptAcquireContextA'; + +function CryptReleaseContext(hProv: THandle; dwFlags: LongWord): BOOL; + stdcall; external ADVAPI32 name 'CryptReleaseContext'; + +function CryptGenRandom(hProv: THandle; dwLen: LongWord; pbBuffer: PAnsiChar): BOOL; + stdcall; external ADVAPI32 name 'CryptGenRandom'; + +var + FHProv: THandle = 0; + FBCryptHandle: THandle = 0; + FBCryptGenRandom: function(hAlgorithm: THandle; pbBuffer: Pointer; cbBuffer: ULONG; dwFlags: ULONG): LongInt; stdcall = nil; + FBCryptInitAttempted: Boolean = False; + +{$ELSE} + +const + DEV_FILE = '/dev/urandom'; + +{$IFDEF LINUX} +const + libc = 'libc.so.6'; +function getrandom(buf: Pointer; buflen: NativeUInt; flags: Cardinal): Integer; cdecl; external libc name 'getrandom'; +{$ENDIF} + +{$IFDEF MACOS} +function CCRandomGenerateBytes(bytes: Pointer; count: NativeUInt): Integer; cdecl; external '/usr/lib/system/libcommonCrypto.dylib' name 'CCRandomGenerateBytes'; +{$ENDIF} + +{$ENDIF} + +function CnRandomFillBytes(Buf: PAnsiChar; BufByteLen: Integer): Boolean; +var +{$IFDEF MSWINDOWS} + HProv: THandle; + Res: DWORD; + B: Boolean; +{$ELSE} + F: TFileStream; +{$IFDEF LINUX} + R: Integer; +{$ENDIF} +{$ENDIF} +begin + Result := False; +{$IFDEF MSWINDOWS} + // ʹ Windows API ʵ + if not FBCryptInitAttempted then + begin + FBCryptHandle := LoadLibrary(bcryptdll); + if FBCryptHandle <> 0 then + @FBCryptGenRandom := GetProcAddress(FBCryptHandle, 'BCryptGenRandom'); + FBCryptInitAttempted := True; + end; + + if Assigned(FBCryptGenRandom) then + begin + Result := FBCryptGenRandom(0, Buf, BufByteLen, BCRYPT_USE_SYSTEM_PREFERRED_RNG) = 0; + if Result then + Exit; + end; + + // + HProv := 0; + B := CryptAcquireContext(@HProv, nil, nil, PROV_RSA_FULL, 0); + if not B then + B := CryptAcquireContext(@HProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + + if not B then + begin + Res := GetLastError; + if Res = NTE_BAD_KEYSET then // KeyContainer ڣ½ķʽ + begin + if not CryptAcquireContext(@HProv, nil, nil, PROV_RSA_FULL, CRYPT_NEWKEYSET) then + raise ECnRandomAPIError.CreateFmt('Error CryptAcquireContext NewKeySet $%8.8x', [GetLastError]); + end + else + raise ECnRandomAPIError.CreateFmt('Error CryptAcquireContext $%8.8x', [Res]); + end; + + if HProv <> 0 then + begin + try + Result := CryptGenRandom(HProv, BufByteLen, Buf); + if not Result then + raise ECnRandomAPIError.CreateFmt('Error CryptGenRandom $%8.8x', [GetLastError]); + finally + CryptReleaseContext(HProv, 0); + end; + end; +{$ELSE} +{$IFDEF MACOS} + Result := CCRandomGenerateBytes(Buf, BufByteLen) = 0; + if Result then + Exit; +{$ENDIF} +{$IFDEF LINUX} + try + R := getrandom(Buf, BufByteLen, 0); + Result := (R = BufByteLen); + if Result then + Exit; + except + // ignore missing symbol or error + end; +{$ENDIF} + + // MacOS/Linux ½ʵ֣öȡ /dev/urandom ݵķʽ + F := nil; + try + F := TFileStream.Create(DEV_FILE, fmOpenRead); + Result := F.Read(Buf^, BufByteLen) = BufByteLen; + finally + F.Free; + end; +{$ENDIF} +end; + +function CnRandomFillBytes2(Buf: PAnsiChar; BufByteLen: Integer): Boolean; +{$IFNDEF MSWINDOWS} +var + F: TFileStream; +{$IFDEF LINUX} + R: Integer; +{$ENDIF} +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + if not FBCryptInitAttempted then + begin + FBCryptHandle := LoadLibrary(bcryptdll); + if FBCryptHandle <> 0 then + @FBCryptGenRandom := GetProcAddress(FBCryptHandle, 'BCryptGenRandom'); + FBCryptInitAttempted := True; + end; + + if Assigned(FBCryptGenRandom) then + begin + Result := FBCryptGenRandom(0, Buf, BufByteLen, BCRYPT_USE_SYSTEM_PREFERRED_RNG) = 0; + if Result then + Exit; + end; + + Result := CryptGenRandom(FHProv, BufByteLen, Buf); +{$ELSE} +{$IFDEF MACOS} + Result := CCRandomGenerateBytes(Buf, BufByteLen) = 0; + if Result then + Exit; +{$ENDIF} +{$IFDEF LINUX} + try + R := getrandom(Buf, BufByteLen, 0); + Result := (R = BufByteLen); + if Result then + Exit; + except + // ignore missing symbol or error + end; +{$ENDIF} + + // MacOS/Linux ½ʵ֣öȡ /dev/urandom ݵķʽ + F := nil; + try + F := TFileStream.Create(DEV_FILE, fmOpenRead); + Result := F.Read(Buf^, BufByteLen) = BufByteLen; + finally + F.Free; + end; +{$ENDIF} +end; + +function CnRandomBytes(ByteLen: Integer): TBytes; +begin + if ByteLen > 0 then + begin + SetLength(Result, ByteLen); + CnRandomFillBytes2(PAnsiChar(@Result[0]), ByteLen); + end; +end; + +function CnRandomFloat: Extended; +var + D: Cardinal; +begin + if not CnRandomFillBytes2(PAnsiChar(@D), SizeOf(Cardinal)) then + raise ECnRandomAPIError.Create(SCnErrorNoSecureRandom); + + // 2^32$100000000 $FFFFFFFFȷϸС 1.0 + // D = $FFFFFFFF ʱResult = $FFFFFFFF / $100000000 0.99999999976716... + Result := D; + Result := Result / $100000000; +end; + +function RandomUInt64: TUInt64; +var + HL: array[0..1] of Cardinal; +begin + // ϵͳòȫ + if not CnRandomFillBytes2(PAnsiChar(@HL[0]), SizeOf(TUInt64)) then + raise ECnRandomAPIError.Create(SCnErrorNoSecureRandom); + + Result := (TUInt64(HL[0]) shl 32) + HL[1]; +end; + +function RandomUInt64LessThan(HighValue: TUInt64): TUInt64; +var + Threshold, R: TUInt64; + RetryCount: Integer; +begin + if HighValue = 0 then + begin + Result := 0; + Exit; + end; + + // Discard numbers less than remainder of 2^64 / HighValue to avoid modulo bias + Threshold := (UInt64Mod(High(TUInt64), HighValue) + 1); + if Threshold = HighValue then + Threshold := 0; + + RetryCount := 0; + repeat + R := RandomUInt64; + Inc(RetryCount); + if RetryCount > 100 then + raise ECnRandomAPIError.Create(SCnErrorNoSecureRandom); // 'RNG stuck in rejection loop. Hardware/OS RNG failure.' + until R >= Threshold; + + Result := UInt64Mod(R, HighValue); +end; + +function RandomInt64LessThan(HighValue: Int64): Int64; +begin + if HighValue <= 0 then + Result := 0 + else + Result := Int64(RandomUInt64LessThan(TUInt64(HighValue))); +end; + +function RandomInt64: Int64; +begin + Result := RandomInt64LessThan(High(Int64)); +end; + +function RandomUInt32: Cardinal; +var + D: Cardinal; +begin + // ϵͳòȫ + if not CnRandomFillBytes2(PAnsiChar(@D), SizeOf(Cardinal)) then + raise ECnRandomAPIError.Create(SCnErrorNoSecureRandom); + + Result := D; +end; + +function RandomUInt32LessThan(HighValue: Cardinal): Cardinal; +var + Threshold, R: Cardinal; + RetryCount: Integer; +begin + if HighValue = 0 then + begin + Result := 0; + Exit; + end; + + // Discard numbers less than remainder of 2^32 / HighValue to avoid modulo bias + Threshold := (High(Cardinal) mod HighValue + 1); + if Threshold = HighValue then + Threshold := 0; + + RetryCount := 0; + repeat + R := RandomUInt32; + Inc(RetryCount); + if RetryCount > 100 then + raise ECnRandomAPIError.Create(SCnErrorNoSecureRandom); + until R >= Threshold; + + Result := R mod HighValue; +end; + +function RandomInt32: Integer; +begin + Result := RandomInt32LessThan(High(Integer)); +end; + +function RandomInt32LessThan(HighValue: Integer): Integer; +begin + if HighValue <= 0 then + Result := 0 + else + Result := Integer(RandomUInt32LessThan(Cardinal(HighValue))); +end; + +function CnKnuthShuffle(ArrayBase: Pointer; ElementByteSize: Integer; + ElementCount: Integer): Boolean; +var + I, R: Integer; + B1, B2: Pointer; +begin + Result := False; + if (ArrayBase = nil) or (ElementByteSize <= 0) or (ElementCount < 0) then // Ȳ + Exit; + + Result := True; + if ElementCount <= 1 then // ûԪػֻһԪʱϴ + Exit; + + for I := ElementCount - 1 downto 0 do + begin + R := RandomInt32LessThan(I + 1); // 0 I ڵҪ 1 + B1 := Pointer(TCnNativeUInt(ArrayBase) + TCnNativeUInt(I * ElementByteSize)); + B2 := Pointer(TCnNativeUInt(ArrayBase) + TCnNativeUInt(R * ElementByteSize)); + MemorySwap(B1, B2, ElementByteSize); + end; + Result := True; +end; + +{$IFDEF MSWINDOWS} + +procedure StartRandom; +var + Res: DWORD; + B: Boolean; +begin + FHProv := 0; + B := CryptAcquireContext(@FHProv, nil, nil, PROV_RSA_FULL, 0); + if not B then + B := CryptAcquireContext(@FHProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + + if not B then + begin + Res := GetLastError; + if Res = NTE_BAD_KEYSET then // KeyContainer ڣ½ķʽ + begin + if not CryptAcquireContext(@FHProv, nil, nil, PROV_RSA_FULL, CRYPT_NEWKEYSET) then + raise ECnRandomAPIError.CreateFmt('Error CryptAcquireContext NewKeySet $%8.8x', [GetLastError]); + end + else + raise ECnRandomAPIError.CreateFmt('Error CryptAcquireContext $%8.8x', [Res]); + end; +end; + +procedure StopRandom; +begin + if FHProv <> 0 then + begin + CryptReleaseContext(FHProv, 0); + FHProv := 0; + end; + + if FBCryptHandle <> 0 then + begin + FreeLibrary(FBCryptHandle); + FBCryptHandle := 0; + @FBCryptGenRandom := nil; + end; +end; + +initialization + StartRandom; + +finalization + StopRandom; + +{$ENDIF} + +end. diff --git a/CnPack/Crypto/CnSHA1.pas b/CnPack/Crypto/CnSHA1.pas new file mode 100644 index 0000000..d93d428 --- /dev/null +++ b/CnPack/Crypto/CnSHA1.pas @@ -0,0 +1,757 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnSHA1; +{* |
+================================================================================ +* ƣ +* ԪƣSHA1 Ӵ㷨ʵֵԪ +* ԪߣCnPack (master@cnpack.org) +* /ֲ䲿ֹܡ +* עԪʵ SHA1 Ӵ㷨Ӧ HMAC 㷨 +* ƽ̨PWin2000Pro + Delphi 5.0 +* ݲԣPWin9X/2000/XP + Delphi 5/6 +* õԪеַϱػʽ +* ļ¼2022.04.26 V1.5 +* LongWord Integer ַת֧ MacOS64 +* 2019.12.12 V1.4 +* ֧ TBytes +* 2019.04.15 V1.3 +* ֧ Win32/Win64/MacOS32 +* 2015.08.14 V1.2 +* л Pascal ֿ֧ƽ̨ +* 2014.10.22 V1.1 +* HMAC +* 2010.07.14 V1.0 +* Ԫ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes {$IFDEF MSWINDOWS}, Windows {$ENDIF}, CnNative, CnConsts; + +type + PCnSHA1Digest = ^TCnSHA1Digest; + {* SHA1 Ӵսָ} + TCnSHA1Digest = array[0..19] of Byte; + {* SHA1 Ӵս20 ֽ} + + TCnSHA1Context = packed record + {* SHA1 Ľṹ} + Hash: array[0..4] of Cardinal; + Hi, Lo: Cardinal; + Buffer: array[0..63] of Byte; + Index: Integer; + Ipad: array[0..63] of Byte; {!< HMAC: inner padding } + Opad: array[0..63] of Byte; {!< HMAC: outer padding } + end; + + TCnSHA1CalcProgressFunc = procedure (ATotal, AProgress: Int64; + var Cancel: Boolean) of object; + {* SHA1 ӴսȻص¼} + +function SHA1(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA1Digest; +{* ݿ SHA1 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1Buffer(const Buffer; Count: Cardinal): TCnSHA1Digest; +{* ݿ SHA1 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1Bytes(const Data: TBytes): TCnSHA1Digest; +{* ֽ SHA1 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1String(const Str: string): TCnSHA1Digest; +{* String ݽ SHA1 㡣ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1StringA(const Str: AnsiString): TCnSHA1Digest; +{* AnsiString ַ SHA1 㣬ֱӼڲݣޱ봦 + + + const Str: AnsiString - ַ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1StringW(const Str: WideString): TCnSHA1Digest; +{* WideString ַת SHA1 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +{$IFDEF UNICODE} + +function SHA1UnicodeString(const Str: string): TCnSHA1Digest; +{* UnicodeString ݽֱӵ SHA1 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +{$ELSE} + +function SHA1UnicodeString(const Str: WideString): TCnSHA1Digest; +{* UnicodeString ݽֱӵ SHA1 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +{$ENDIF} + +function SHA1File(const FileName: string; + CallBack: TCnSHA1CalcProgressFunc = nil): TCnSHA1Digest; +{* ָļݽ SHA1 㡣 + + + const FileName: string - ļ + CallBack: TCnSHA1CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +function SHA1Stream(Stream: TStream; + CallBack: TCnSHA1CalcProgressFunc = nil): TCnSHA1Digest; +{* ָݽ SHA1 㡣 + + + Stream: TStream - + CallBack: TCnSHA1CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +// ⲿݽɢ SHA1 㣬SHA1Update ɶα + +procedure SHA1Init(var Context: TCnSHA1Context); +{* ʼһ SHA1 ģ SHA1 + + + var Context: TCnSHA1Context - ʼ SHA1 + + ֵޣ +} + +procedure SHA1Update(var Context: TCnSHA1Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA1 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA1Context - SHA1 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA1Final(var Context: TCnSHA1Context; var Digest: TCnSHA1Digest); +{* ּ㣬 SHA1 Digest С + + + var Context: TCnSHA1Context - SHA1 + var Digest: TCnSHA1Digest - ص SHA1 Ӵֵ + + ֵޣ +} + +function SHA1Print(const Digest: TCnSHA1Digest): string; +{* ʮƸʽ SHA1 Ӵֵ + + + const Digest: TCnSHA1Digest - ָ SHA1 Ӵֵ + + ֵstring - ʮַ +} + +function SHA1Match(const D1: TCnSHA1Digest; const D2: TCnSHA1Digest): Boolean; +{* Ƚ SHA1 ӴֵǷȡ + + + const D1: TCnSHA1Digest - Ƚϵ SHA1 Ӵֵһ + const D2: TCnSHA1Digest - Ƚϵ SHA1 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA1DigestToStr(const Digest: TCnSHA1Digest): string; +{* SHA1 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA1Digest - ת SHA1 Ӵֵ + + ֵstring - صַ +} + +procedure SHA1Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA1Digest); +{* SHA1 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA1 Կݿַ + KeyByteLength: Integer - SHA1 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA1Digest - ص SHA1 Ӵֵ + + ֵޣ +} + +function SHA1HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA1Digest; +{* ֽл SHA1 HMAC 㡣 + + + const Key: TBytes - SHA1 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA1Digest - ص SHA1 Ӵֵ +} + +implementation + +const + MAX_FILE_SIZE = 512 * 1024 * 1024; + // If file size <= this size (bytes), using Mapping, else stream + + HMAC_SHA1_BLOCK_SIZE_BYTE = 64; + HMAC_SHA1_OUTPUT_LENGTH_BYTE = 20; + +function LRot32(X: Cardinal; C: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X shl (C and 31) + X shr (32 - C and 31); +end; + +function F1(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := Z xor (X and (Y xor Z)); +end; + +function F2(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor Y xor Z; +end; + +function F3(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Y) or (Z and (X or Y)); +end; + +function RB(A: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (A shr 24) or ((A shr 8) and $FF00) or ((A shl 8) and $FF0000) or (A shl 24); +end; + +procedure SHA1Compress(var Data: TCnSHA1Context); +var + A, B, C, D, E, T: Cardinal; + W: array[0..79] of Cardinal; + I: Integer; +begin + Move(Data.Buffer, W, Sizeof(Data.Buffer)); + for I := 0 to 15 do + W[I] := RB(W[I]); + for I := 16 to 79 do + W[I] := LRot32(W[I - 3] xor W[I - 8] xor W[I - 14] xor W[I - 16], 1); + A := Data.Hash[0]; + B := Data.Hash[1]; + C := Data.Hash[2]; + D := Data.Hash[3]; + E := Data.Hash[4]; + for I := 0 to 19 do + begin + T := LRot32(A, 5) + F1(B, C, D) + E + W[I] + $5A827999; + E := D; + D := C; + C := LRot32(B, 30); + B := A; + A := T; + end; + for I := 20 to 39 do + begin + T := LRot32(A, 5) + F2(B, C, D) + E + W[I] + $6ED9EBA1; + E := D; + D := C; + C := LRot32(B, 30); + B := A; + A := T; + end; + for I := 40 to 59 do + begin + T := LRot32(A, 5) + F3(B, C, D) + E + W[I] + $8F1BBCDC; + E := D; + D := C; + C := LRot32(B, 30); + B := A; + A := T; + end; + for I := 60 to 79 do + begin + T := LRot32(A, 5) + F2(B, C, D) + E + W[I] + $CA62C1D6; + E := D; + D := C; + C := LRot32(B, 30); + B := A; + A := T; + end; + Data.Hash[0] := Data.Hash[0] + A; + Data.Hash[1] := Data.Hash[1] + B; + Data.Hash[2] := Data.Hash[2] + C; + Data.Hash[3] := Data.Hash[3] + D; + Data.Hash[4] := Data.Hash[4] + E; + FillChar(W, Sizeof(W), 0); + FillChar(Data.Buffer, Sizeof(Data.Buffer), 0); +end; + +procedure SHA1Init(var Context: TCnSHA1Context); +begin + Context.Hi := 0; + Context.Lo := 0; + Context.Index := 0; + FillChar(Context.Buffer, Sizeof(Context.Buffer), 0); + Context.Hash[0] := $67452301; + Context.Hash[1] := $EFCDAB89; + Context.Hash[2] := $98BADCFE; + Context.Hash[3] := $10325476; + Context.Hash[4] := $C3D2E1F0; +end; + +procedure SHA1UpdateLen(var Context: TCnSHA1Context; Len: Integer); +var + I: Cardinal; + K: Integer; +begin + for K := 0 to 7 do + begin + I := Context.Lo; + Inc(Context.Lo, Len); + if Context.Lo < I then + Inc(Context.Hi); + end; +end; + +procedure SHA1Update(var Context: TCnSHA1Context; Input: PAnsiChar; ByteLength: Cardinal); +var + B: Integer; +begin + SHA1UpdateLen(Context, ByteLength); + while ByteLength > 0 do + begin + if Cardinal(64 - Context.Index) > ByteLength then + B := ByteLength + else + B := 64 - Context.Index; + + Move(Input^, Context.Buffer[Context.Index], B); + Inc(PByte(Input), B); + Inc(Context.Index, B); + Dec(ByteLength, B); + + if Context.Index = 64 then + begin + Context.Index := 0; + SHA1Compress(Context); + end; + end; +end; + +procedure SHA1UpdateW(var Context: TCnSHA1Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + pContent: PAnsiChar; + iLen: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(pContent, CharLength * SizeOf(WideChar)); + try + iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(pContent), CharLength * SizeOf(WideChar), nil, nil); + SHA1Update(Context, pContent, iLen); + finally + FreeMem(pContent); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + SHA1Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +procedure SHA1Final(var Context: TCnSHA1Context; var Digest: TCnSHA1Digest); +type + PDWord = ^Cardinal; +begin + Context.Buffer[Context.Index] := $80; + if Context.Index >= 56 then + SHA1Compress(Context); + PDWord(@Context.Buffer[56])^ := RB(Context.Hi); + PDWord(@Context.Buffer[60])^ := RB(Context.Lo); + SHA1Compress(Context); + Context.Hash[0] := RB(Context.Hash[0]); + Context.Hash[1] := RB(Context.Hash[1]); + Context.Hash[2] := RB(Context.Hash[2]); + Context.Hash[3] := RB(Context.Hash[3]); + Context.Hash[4] := RB(Context.Hash[4]); + Move(Context.Hash, Digest, Sizeof(Digest)); +end; + +// ݿ SHA1 +function SHA1(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1Update(Context, Input, ByteLength); + SHA1Final(Context, Result); +end; + +// ݿ SHA1 +function SHA1Buffer(const Buffer; Count: Cardinal): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1Update(Context, PAnsiChar(@Buffer), Count); + SHA1Final(Context, Result); +end; + +function SHA1Bytes(const Data: TBytes): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA1Final(Context, Result); +end; + +// String ݽ SHA1 +function SHA1String(const Str: string): TCnSHA1Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA1StringA(AStr); +end; + +// AnsiString ݽ SHA1 +function SHA1StringA(const Str: AnsiString): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1Update(Context, PAnsiChar(Str), Length(Str)); + SHA1Final(Context, Result); +end; + +// WideString ݽ SHA1 +function SHA1StringW(const Str: WideString): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1UpdateW(Context, PWideChar(Str), Length(Str)); + SHA1Final(Context, Result); +end; + +{$IFDEF UNICODE} +function SHA1UnicodeString(const Str: string): TCnSHA1Digest; +{$ELSE} +function SHA1UnicodeString(const Str: WideString): TCnSHA1Digest; +{$ENDIF} +var + Context: TCnSHA1Context; +begin + SHA1Init(Context); + SHA1Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA1Final(Context, Result); +end; + +function InternalSHA1Stream(Stream: TStream; const BufSize: Cardinal; var D: + TCnSHA1Digest; CallBack: TCnSHA1CalcProgressFunc): Boolean; +var + Context: TCnSHA1Context; + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; +begin + Result := False; + Size := Stream.Size; + SavePos := Stream.Position; + TotalBytes := 0; + if Size = 0 then Exit; + if Size < BufSize then BufLen := Size + else BufLen := BufSize; + + CancelCalc := False; + SHA1Init(Context); + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + SHA1Update(Context, Buf, ReadBytes); + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + SHA1Final(Context, D); + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +// ָ SHA1 +function SHA1Stream(Stream: TStream; + CallBack: TCnSHA1CalcProgressFunc): TCnSHA1Digest; +begin + InternalSHA1Stream(Stream, 4096 * 1024, Result, CallBack); +end; + +// ָļݽ SHA1 +function SHA1File(const FileName: string; + CallBack: TCnSHA1CalcProgressFunc): TCnSHA1Digest; +var +{$IFDEF MSWINDOWS} + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; + Context: TCnSHA1Context; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; + + function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; +{$IFDEF MSWINDOWS} + var + H: THandle; + Info: BY_HANDLE_FILE_INFORMATION; + Rec : Int64Rec; +{$ENDIF} + begin +{$IFDEF MSWINDOWS} + Result := False; + IsEmpty := False; + H := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); + if H = INVALID_HANDLE_VALUE then Exit; + try + if not GetFileInformationByHandle(H, Info) then Exit; + finally + CloseHandle(H); + end; + Rec.Lo := Info.nFileSizeLow; + Rec.Hi := Info.nFileSizeHigh; + Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); + IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); +{$ELSE} + Result := True; // Windows ƽ̨ Trueʾ Mapping +{$ENDIF} + end; + +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣ Windows ƽ̨ʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalSHA1Stream(Stream, 4096 * 1024, Result, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + SHA1Init(Context); + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + SHA1Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise ECnNativeException.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise ECnNativeException.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + SHA1Final(Context, Result); +{$ENDIF} + end; +end; + +// ʮƸʽ SHA1 Ӵֵ +function SHA1Print(const Digest: TCnSHA1Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA1Digest)); +end; + +// Ƚ SHA1 ӴֵǷ +function SHA1Match(const D1, D2: TCnSHA1Digest): Boolean; +begin + Result := ConstTimeCompareMem(@D1[0], @D2[0], SizeOf(TCnSHA1Digest)); +end; + +// SHA1 Ӵֵת string +function SHA1DigestToStr(const Digest: TCnSHA1Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA1Digest)); +end; + +procedure SHA1HmacInit(var Context: TCnSHA1Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA1Digest; +begin + if KeyLength > HMAC_SHA1_BLOCK_SIZE_BYTE then + begin + Sum := SHA1Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA1_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA1_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA1_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA1Init(Context); + SHA1Update(Context, @(Context.Ipad[0]), HMAC_SHA1_BLOCK_SIZE_BYTE); +end; + +procedure SHA1HmacUpdate(var Context: TCnSHA1Context; Input: PAnsiChar; Length: Cardinal); +begin + SHA1Update(Context, Input, Length); +end; + +procedure SHA1HmacFinal(var Context: TCnSHA1Context; var Output: TCnSHA1Digest); +var + Len: Integer; + TmpBuf: TCnSHA1Digest; +begin + Len := HMAC_SHA1_OUTPUT_LENGTH_BYTE; + SHA1Final(Context, TmpBuf); + SHA1Init(Context); + SHA1Update(Context, @(Context.Opad[0]), HMAC_SHA1_BLOCK_SIZE_BYTE); + SHA1Update(Context, @(TmpBuf[0]), Len); + SHA1Final(Context, Output); +end; + +procedure SHA1Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA1Digest); +var + Context: TCnSHA1Context; +begin + SHA1HmacInit(Context, Key, KeyByteLength); + SHA1HmacUpdate(Context, Input, ByteLength); + SHA1HmacFinal(Context, Output); +end; + +function SHA1HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA1Digest; +var + Context: TCnSHA1Context; +begin + SHA1HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA1HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA1HmacFinal(Context, Result); +end; + +end. diff --git a/CnPack/Crypto/CnSHA2.pas b/CnPack/Crypto/CnSHA2.pas new file mode 100644 index 0000000..3a32bc7 --- /dev/null +++ b/CnPack/Crypto/CnSHA2.pas @@ -0,0 +1,3294 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnSHA2; +{* |
+================================================================================ +* ƣ +* ԪƣSHA2 Ӵ㷨ʵֵԪ +* ԪߣCnPack (master@cnpack.org) +* / C Pascal ֲ䲿ֹܡ +* עԪʵ SHA2 ϵӴ㷨Ӧ HMAC 㷨 +* SHA224/256/384/512/512-224/512-256 +* ƽ̨PWinXP + Delphi 5.0 +* ݲԣPWinXP/7 + Delphi 5/6 +* õԪеַϱػʽ +* ļ¼2025.11.20 V1.5 +* ʵ SHA512-224 SHA512-256 㷨 +* 2022.04.26 V1.4 +* LongWord Integer ַת֧ MacOS64 +* 2019.04.15 V1.3 +* ֧ Win32/Win64/MacOS32 +* 2017.10.31 V1.2 +* SHA512/384 HMAC +* 2016.09.30 V1.1 +* ʵ SHA512/384D567з Int64 UInt64 +* 2016.09.27 V1.0 +* Ԫ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes {$IFDEF MSWINDOWS}, Windows {$ENDIF}, CnNative, CnConsts; + +type + PCnSHA2GeneralDigest = ^TCnSHA2GeneralDigest; + {* SHA2 ϵͨõӴսָ} + TCnSHA2GeneralDigest = array[0..63] of Byte; + {* SHA2 ϵͨõӴս 64 ֽΪ} + + PCnSHA224Digest = ^TCnSHA224Digest; + {* SHA224 Ӵսָ} + TCnSHA224Digest = array[0..27] of Byte; + {* SHA224 Ӵս28 ֽ} + + PCnSHA256Digest = ^TCnSHA256Digest; + {* SHA256 Ӵսָ} + TCnSHA256Digest = array[0..31] of Byte; + {* SHA256 Ӵս32 ֽ} + + PCnSHA384Digest = ^TCnSHA384Digest; + {* SHA384 Ӵսָ} + TCnSHA384Digest = array[0..47] of Byte; + {* SHA384 Ӵս48 ֽ} + + PCnSHA512Digest = ^TCnSHA512Digest; + {* SHA512 Ӵսָ} + TCnSHA512Digest = array[0..63] of Byte; + {* SHA512 Ӵս64 ֽ} + + PCnSHA512_224Digest = ^TCnSHA512_224Digest; + {* SHA512_224 Ӵսָ} + TCnSHA512_224Digest = array[0..27] of Byte; + {* SHA512_224 Ӵս28 ֽ} + + PCnSHA512_256Digest = ^TCnSHA512_256Digest; + {* SHA512_256 Ӵսָ} + TCnSHA512_256Digest = array[0..31] of Byte; + {* SHA512_256 Ӵս32 ֽ} + + TCnSHA256Context = packed record + {* SHA256 Ľṹ} + DataLen: Cardinal; + Data: array[0..63] of Byte; + BitLen: Int64; + State: array[0..7] of Cardinal; + Ipad: array[0..63] of Byte; {!< HMAC: inner padding } + Opad: array[0..63] of Byte; {!< HMAC: outer padding } + end; + + TCnSHA224Context = TCnSHA256Context; + {* SHA224 Ľṹ} + + TCnSHA512Context = packed record + {* SHA512 Ľṹ} + DataLen: Cardinal; + Data: array[0..255] of Byte; // Final ʱ + TotalLen: Int64; + State: array[0..7] of Int64; + Ipad: array[0..127] of Byte; {!< HMAC: inner padding } + Opad: array[0..127] of Byte; {!< HMAC: outer padding } + end; + + TCnSHA384Context = TCnSHA512Context; + {* SHA512 Ľṹ} + + TCnSHA512_224Context = TCnSHA512Context; + {* SHA512_224 Ľṹ} + + TCnSHA512_256Context = TCnSHA512Context; + {* SHA512_256 Ľṹ} + + TCnSHACalcProgressFunc = procedure(ATotal, AProgress: Int64; var Cancel: + Boolean) of object; + {* SHA2 ϵӴսȻص¼} + +function SHA224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA224Digest; +{* ݿ SHA224 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA256Digest; +{* ݿ SHA256 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA384Digest; +{* ݿ SHA384 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA512Digest; +{* ݿ SHA512 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA512_224Digest; +{* ݿ SHA512_224 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA512_256Digest; +{* ݿ SHA512_256 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +function SHA224Buffer(const Buffer; Count: Cardinal): TCnSHA224Digest; +{* ݿ SHA224 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256Buffer(const Buffer; Count: Cardinal): TCnSHA256Digest; +{* ݿ SHA256 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384Buffer(const Buffer; Count: Cardinal): TCnSHA384Digest; +{* ݿ SHA384 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512Buffer(const Buffer; Count: Cardinal): TCnSHA512Digest; +{* ݿ SHA512 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224Buffer(const Buffer; Count: Cardinal): TCnSHA512_224Digest; +{* ݿ SHA512_224 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256Buffer(const Buffer; Count: Cardinal): TCnSHA512_256Digest; +{* ݿ SHA512_256 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +function SHA224Bytes(const Data: TBytes): TCnSHA224Digest; +{* ֽ SHA224 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256Bytes(const Data: TBytes): TCnSHA256Digest; +{* ֽ SHA256 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384Bytes(const Data: TBytes): TCnSHA384Digest; +{* ֽ SHA384 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512Bytes(const Data: TBytes): TCnSHA512Digest; +{* ֽ SHA512 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224Bytes(const Data: TBytes): TCnSHA512_224Digest; +{* ֽ SHA512_224 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256Bytes(const Data: TBytes): TCnSHA512_256Digest; +{* ֽ SHA512_256 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +function SHA224String(const Str: string): TCnSHA224Digest; +{* String ݽ SHA224 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256String(const Str: string): TCnSHA256Digest; +{* String ݽ SHA256 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384String(const Str: string): TCnSHA384Digest; +{* String ݽ SHA384 㣬ע D2009ϰ汾string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512String(const Str: string): TCnSHA512Digest; +{* String ݽ SHA512 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224String(const Str: string): TCnSHA512_224Digest; +{* String ݽ SHA512_224 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256String(const Str: string): TCnSHA512_256Digest; +{* String ݽ SHA512_256 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +function SHA224StringA(const Str: AnsiString): TCnSHA224Digest; +{* AnsiString ݽ SHA224 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA224StringW(const Str: WideString): TCnSHA224Digest; +{* WideString ݽ SHA224 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256StringA(const Str: AnsiString): TCnSHA256Digest; +{* AnsiString ݽ SHA256 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA256StringW(const Str: WideString): TCnSHA256Digest; +{* WideString ݽ SHA256 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384StringA(const Str: AnsiString): TCnSHA384Digest; +{* AnsiString ݽ SHA384 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA384StringW(const Str: WideString): TCnSHA384Digest; +{* WideString ݽ SHA384 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512StringA(const Str: AnsiString): TCnSHA512Digest; +{* AnsiString ݽ SHA512 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512StringW(const Str: WideString): TCnSHA512Digest; +{* WideString ݽ SHA512 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224StringA(const Str: AnsiString): TCnSHA512_224Digest; +{* AnsiString ݽ SHA512_224 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_224StringW(const Str: WideString): TCnSHA512_224Digest; +{* WideString ݽ SHA512_224 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256StringA(const Str: AnsiString): TCnSHA512_256Digest; +{* AnsiString ݽ SHA512_256 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +function SHA512_256StringW(const Str: WideString): TCnSHA512_256Digest; +{* WideString ݽ SHA512_256 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +{$IFDEF UNICODE} + +function SHA224UnicodeString(const Str: string): TCnSHA224Digest; +{* UnicodeString ݽֱӵ SHA224 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256UnicodeString(const Str: string): TCnSHA256Digest; +{* UnicodeString ݽֱӵ SHA256 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384UnicodeString(const Str: string): TCnSHA384Digest; +{* UnicodeString ݽֱӵ SHA384 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512UnicodeString(const Str: string): TCnSHA512Digest; +{* UnicodeString ݽֱӵ SHA512 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224UnicodeString(const Str: string): TCnSHA512_224Digest; +{* UnicodeString ݽֱӵ SHA512_224 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256UnicodeString(const Str: string): TCnSHA512_256Digest; +{* UnicodeString ݽֱӵ SHA512_256 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +{$ELSE} + +function SHA224UnicodeString(const Str: WideString): TCnSHA224Digest; +{* UnicodeString ݽֱӵ SHA224 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256UnicodeString(const Str: WideString): TCnSHA256Digest; +{* UnicodeString ݽֱӵ SHA256 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384UnicodeString(const Str: WideString): TCnSHA384Digest; +{* UnicodeString ݽֱӵ SHA384 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512UnicodeString(const Str: WideString): TCnSHA512Digest; +{* UnicodeString ݽֱӵ SHA512 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224UnicodeString(const Str: WideString): TCnSHA512_224Digest; +{* UnicodeString ݽֱӵ SHA512_224 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256UnicodeString(const Str: WideString): TCnSHA512_256Digest; +{* UnicodeString ݽֱӵ SHA512_256 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +{$ENDIF} + +function SHA224File(const FileName: string; CallBack: TCnSHACalcProgressFunc = + nil): TCnSHA224Digest; +{* ָļݽ SHA224 㡣 + + + const FileName: string - ļ + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA224Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA224Digest; +{* ָݽ SHA224 㡣 + + + Stream: TStream - + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256File(const FileName: string; CallBack: TCnSHACalcProgressFunc = + nil): TCnSHA256Digest; +{* ָļݽ SHA256 㡣 + + + const FileName: string - ļ + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA256Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA256Digest; +{* ָݽ SHA256 㡣 + + + Stream: TStream - + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384File(const FileName: string; CallBack: TCnSHACalcProgressFunc = + nil): TCnSHA384Digest; +{* ָļݽ SHA384 㡣 + + + const FileName: string - ļ + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA384Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA384Digest; +{* ָݽ SHA384 㡣 + + + Stream: TStream - + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA384Digest - ص SHA384Ӵֵ +} + +function SHA512File(const FileName: string; CallBack: TCnSHACalcProgressFunc = + nil): TCnSHA512Digest; +{* ָļݽ SHA512 㡣 + + + const FileName: string - ļ + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA512Digest; +{* ָݽ SHA512 㡣 + + + Stream: TStream - + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224File(const FileName: string; CallBack: TCnSHACalcProgressFunc = + nil): TCnSHA512_224Digest; +{* ָļݽ SHA512_224 㡣 + + + const FileName: string - ļ + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_224Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA512_224Digest; +{* ָݽ SHA512_224 㡣 + + + Stream: TStream - + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256File(const FileName: string; CallBack: TCnSHACalcProgressFunc = + nil): TCnSHA512_256Digest; +{* ָļݽ SHA512_256 㡣 + + + const FileName: string - ļ + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +function SHA512_256Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc = nil): + TCnSHA512_256Digest; +{* ָݽ SHA512_256 㡣 + + + Stream: TStream - + CallBack: TCnSHACalcProgressFunc - ȻصĬΪ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +// ⲿݽɢ SHA224 㣬SHA224Update ɶα + +procedure SHA224Init(var Context: TCnSHA224Context); +{* ʼһ SHA224 ģ SHA224 + + + var Context: TCnSHA224Context - ʼ SHA224 + + ֵޣ +} + +procedure SHA224Update(var Context: TCnSHA224Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA224 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA224Context - SHA224 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA224Final(var Context: TCnSHA224Context; var Digest: TCnSHA224Digest); +{* ּ㣬 SHA224 Digest С + + + var Context: TCnSHA224Context - SHA224 + var Digest: TCnSHA224Digest - ص SHA224 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA256 㣬SHA256Update ɶα + +procedure SHA256Init(var Context: TCnSHA256Context); +{* ʼһ SHA256 ģ SHA256 + + + var Context: TCnSHA256Context - ʼ SHA256 + + ֵޣ +} + +procedure SHA256Update(var Context: TCnSHA256Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA256 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA256Context - SHA256 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA256Final(var Context: TCnSHA256Context; var Digest: TCnSHA256Digest); +{* ּ㣬 SHA256 Digest С + + + var Context: TCnSHA256Context - SHA256 + var Digest: TCnSHA256Digest - ص SHA256 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA384 㣬SHA384Update ɶα + +procedure SHA384Init(var Context: TCnSHA384Context); +{* ʼһ SHA384 ģ SHA384 + + + var Context: TCnSHA384Context - ʼ SHA384 + + ֵޣ +} + +procedure SHA384Update(var Context: TCnSHA384Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA384 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA384Context - SHA384 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA384Final(var Context: TCnSHA384Context; var Digest: TCnSHA384Digest); +{* ּ㣬 SHA384 Digest С + + + var Context: TCnSHA384Context - SHA384 + var Digest: TCnSHA384Digest - ص SHA384 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA512 㣬SHA512Update ɶα + +procedure SHA512Init(var Context: TCnSHA512Context); +{* ʼһ SHA512 ģ SHA512 + + + var Context: TCnSHA512Context - ʼ SHA512 + + ֵޣ +} + +procedure SHA512Update(var Context: TCnSHA512Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA512 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA512Context - SHA512 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA512Final(var Context: TCnSHA512Context; var Digest: TCnSHA512Digest); +{* ּ㣬 SHA512 Digest С + + + var Context: TCnSHA512Context - SHA512 + var Digest: TCnSHA512Digest - ص SHA512 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA512_224 㣬SHA512_224Update ɶα + +procedure SHA512_224Init(var Context: TCnSHA512_224Context); +{* ʼһ SHA512_224 ģ SHA512_224 + + + var Context: TCnSHA512_224Context - ʼ SHA512_224 + + ֵޣ +} + +procedure SHA512_224Update(var Context: TCnSHA512_224Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA512_224 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA512_224Context - SHA512_224 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA512_224Final(var Context: TCnSHA512_224Context; var Digest: TCnSHA512_224Digest); +{* ּ㣬 SHA512_224 Digest С + + + var Context: TCnSHA512_224Context - SHA512_224 + var Digest: TCnSHA512_224Digest - ص SHA512_224 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA512_256 㣬SHA512_256Update ɶα + +procedure SHA512_256Init(var Context: TCnSHA512_256Context); +{* ʼһ SHA512_256 ģ SHA512_256 + + + var Context: TCnSHA512_256Context - ʼ SHA512_256 + + ֵޣ +} + +procedure SHA512_256Update(var Context: TCnSHA512_256Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA512_256 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA512_256Context - SHA512_256 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA512_256Final(var Context: TCnSHA512_256Context; var Digest: TCnSHA512_256Digest); +{* ּ㣬 SHA512_256 Digest С + + + var Context: TCnSHA512_256Context - SHA512_256 + var Digest: TCnSHA512_256Digest - ص SHA512_256 Ӵֵ + + ֵޣ +} + +function SHA224Print(const Digest: TCnSHA224Digest): string; +{* ʮƸʽ SHA224 Ӵֵ + + + const Digest: TCnSHA224Digest - ָ SHA224 Ӵֵ + + ֵstring - ʮַ +} + +function SHA256Print(const Digest: TCnSHA256Digest): string; +{* ʮƸʽ SHA256 Ӵֵ + + + const Digest: TCnSHA256Digest - ָ SHA256 Ӵֵ + + ֵstring - ʮַ +} + +function SHA384Print(const Digest: TCnSHA384Digest): string; +{* ʮƸʽ SHA384 Ӵֵ + + + const Digest: TCnSHA384Digest - ָ SHA384 Ӵֵ + + ֵstring - ʮַ +} + +function SHA512Print(const Digest: TCnSHA512Digest): string; +{* ʮƸʽ SHA512 Ӵֵ + + + const Digest: TCnSHA512Digest - ָ SHA512 Ӵֵ + + ֵstring - ʮַ +} + +function SHA512_224Print(const Digest: TCnSHA512_224Digest): string; +{* ʮƸʽ SHA512_224 Ӵֵ + + + const Digest: TCnSHA512_224Digest - ָ SHA512_224 Ӵֵ + + ֵstring - ʮַ +} + +function SHA512_256Print(const Digest: TCnSHA512_256Digest): string; +{* ʮƸʽ SHA512_256 Ӵֵ + + + const Digest: TCnSHA512_256Digest - ָ SHA512_256 Ӵֵ + + ֵstring - ʮַ +} + +function SHA224Match(const D1: TCnSHA224Digest; const D2: TCnSHA224Digest): Boolean; +{* Ƚ SHA224 ӴֵǷȡ + + + const D1: TCnSHA224Digest - Ƚϵ SHA224 Ӵֵһ + const D2: TCnSHA224Digest - Ƚϵ SHA224 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA256Match(const D1: TCnSHA256Digest; const D2: TCnSHA256Digest): Boolean; +{* Ƚ SHA256 ӴֵǷȡ + + + const D1: TCnSHA256Digest - Ƚϵ SHA256 Ӵֵһ + const D2: TCnSHA256Digest - Ƚϵ SHA256 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA384Match(const D1: TCnSHA384Digest; const D2: TCnSHA384Digest): Boolean; +{* Ƚ SHA384 ӴֵǷȡ + + + const D1: TCnSHA384Digest - Ƚϵ SHA384 Ӵֵһ + const D2: TCnSHA384Digest - Ƚϵ SHA384 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA512Match(const D1: TCnSHA512Digest; const D2: TCnSHA512Digest): Boolean; +{* Ƚ SHA512 ӴֵǷȡ + + + const D1: TCnSHA512Digest - Ƚϵ SHA512 Ӵֵһ + const D2: TCnSHA512Digest - Ƚϵ SHA512 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA512_224Match(const D1: TCnSHA512_224Digest; const D2: TCnSHA512_224Digest): Boolean; +{* Ƚ SHA512_224 ӴֵǷȡ + + + const D1: TCnSHA512_224Digest - Ƚϵ SHA512_224 Ӵֵһ + const D2: TCnSHA512_224Digest - Ƚϵ SHA512_224 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA512_256Match(const D1: TCnSHA512_256Digest; const D2: TCnSHA512_256Digest): Boolean; +{* Ƚ SHA512_256 ӴֵǷȡ + + + const D1: TCnSHA512_256Digest - Ƚϵ SHA512_256 Ӵֵһ + const D2: TCnSHA512_256Digest - Ƚϵ SHA512_256 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA224DigestToStr(const Digest: TCnSHA224Digest): string; +{* SHA224 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA224Digest - ת SHA224 Ӵֵ + + ֵstring - صַ +} + +function SHA256DigestToStr(const Digest: TCnSHA256Digest): string; +{* SHA256 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA256Digest - ת SHA256 Ӵֵ + + ֵstring - صַ +} + +function SHA384DigestToStr(const Digest: TCnSHA384Digest): string; +{* SHA384 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA384Digest - ת SHA384 Ӵֵ + + ֵstring - صַ +} + +function SHA512DigestToStr(const Digest: TCnSHA512Digest): string; +{* SHA512 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA512Digest - ת SHA512 Ӵֵ + + ֵstring - صַ +} + +function SHA512_224DigestToStr(const Digest: TCnSHA512_224Digest): string; +{* SHA512_224 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA512_224Digest - ת SHA512_224 Ӵֵ + + ֵstring - صַ +} + +function SHA512_256DigestToStr(const Digest: TCnSHA512_256Digest): string; +{* SHA512_256 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA512_256Digest - ת SHA512_256 Ӵֵ + + ֵstring - صַ +} + +procedure SHA224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA224Digest); +{* SHA224 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA224 Կݿַ + KeyByteLength: Integer - SHA224 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA224Digest - ص SHA224 Ӵֵ + + ֵޣ +} + +procedure SHA256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA256Digest); +{* SHA256 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA256 Կݿַ + KeyByteLength: Integer - SHA256 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA256Digest - ص SHA256 Ӵֵ + + ֵޣ +} + +procedure SHA384Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA384Digest); +{* SHA384 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA384 Կݿַ + KeyByteLength: Integer - SHA384 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA384Digest - ص SHA384 Ӵֵ + + ֵޣ +} + +procedure SHA512Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA512Digest); +{* SHA512 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA512 Կݿַ + KeyByteLength: Integer - SHA512 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA512Digest - ص SHA512 Ӵֵ + + ֵޣ +} + +procedure SHA512_224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA512_224Digest); +{* SHA512_224 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA512_224 Կݿַ + KeyByteLength: Integer - SHA512_224 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA512_224Digest - ص SHA512_224 Ӵֵ + + ֵޣ +} + +procedure SHA512_256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA512_256Digest); +{* SHA512_256 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA512_256 Կݿַ + KeyByteLength: Integer - SHA512_256 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA512_256Digest - ص SHA512_256 Ӵֵ + + ֵޣ +} + +function SHA224HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA224Digest; +{* ֽл SHA224 HMAC 㡣 + + + const Key: TBytes - SHA224 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA224Digest - ص SHA224 Ӵֵ +} + +function SHA256HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA256Digest; +{* ֽл SHA256 HMAC 㡣 + + + const Key: TBytes - SHA256 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA256Digest - ص SHA256 Ӵֵ +} + +function SHA384HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA384Digest; +{* ֽл SHA384 HMAC 㡣 + + + const Key: TBytes - SHA384 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA384Digest - ص SHA384 Ӵֵ +} + +function SHA512HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA512Digest; +{* ֽл SHA512 HMAC 㡣 + + + const Key: TBytes - SHA512 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA512Digest - ص SHA512 Ӵֵ +} + +function SHA512_224HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA512_224Digest; +{* ֽл SHA512_224 HMAC 㡣 + + + const Key: TBytes - SHA512_224 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA512_224Digest - ص SHA512_224 Ӵֵ +} + +function SHA512_256HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA512_256Digest; +{* ֽл SHA512_256 HMAC 㡣 + + + const Key: TBytes - SHA512_256 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA512_256Digest - ص SHA512_256 Ӵֵ +} + +implementation + +const + HMAC_SHA2_224_256_BLOCK_SIZE_BYTE = 64; + HMAC_SHA2_384_512_BLOCK_SIZE_BYTE = 128; + + HMAC_SHA2_224_OUTPUT_LENGTH_BYTE = 28; + HMAC_SHA2_256_OUTPUT_LENGTH_BYTE = 32; + HMAC_SHA2_384_OUTPUT_LENGTH_BYTE = 48; + HMAC_SHA2_512_OUTPUT_LENGTH_BYTE = 64; + + HMAC_SHA2_512_224_OUTPUT_LENGTH_BYTE = 28; + HMAC_SHA2_512_256_OUTPUT_LENGTH_BYTE = 32; + +type + TSHA2Type = (stSHA2_224, stSHA2_256, stSHA2_384, stSHA2_512, stSHA2_512_224, stSHA2_512_256); + +const + MAX_FILE_SIZE = 512 * 1024 * 1024; + // If file size <= this size (bytes), using Mapping, else stream + + KEYS256: array[0..63] of Cardinal = ($428A2F98, $71374491, $B5C0FBCF, $E9B5DBA5, + $3956C25B, $59F111F1, $923F82A4, $AB1C5ED5, $D807AA98, $12835B01, $243185BE, + $550C7DC3, $72BE5D74, $80DEB1FE, $9BDC06A7, $C19BF174, $E49B69C1, $EFBE4786, + $0FC19DC6, $240CA1CC, $2DE92C6F, $4A7484AA, $5CB0A9DC, $76F988DA, $983E5152, + $A831C66D, $B00327C8, $BF597FC7, $C6E00BF3, $D5A79147, $06CA6351, $14292967, + $27B70A85, $2E1B2138, $4D2C6DFC, $53380D13, $650A7354, $766A0ABB, $81C2C92E, + $92722C85, $A2BFE8A1, $A81A664B, $C24B8B70, $C76C51A3, $D192E819, $D6990624, + $F40E3585, $106AA070, $19A4C116, $1E376C08, $2748774C, $34B0BCB5, $391C0CB3, + $4ED8AA4A, $5B9CCA4F, $682E6FF3, $748F82EE, $78A5636F, $84C87814, $8CC70208, + $90BEFFFA, $A4506CEB, $BEF9A3F7, $C67178F2); + + KEYS512: array[0..79] of TUInt64 = ($428A2F98D728AE22, $7137449123EF65CD, + $B5C0FBCFEC4D3B2F, $E9B5DBA58189DBBC, $3956C25BF348B538, $59F111F1B605D019, + $923F82A4AF194F9B, $AB1C5ED5DA6D8118, $D807AA98A3030242, $12835B0145706FBE, + $243185BE4EE4B28C, $550C7DC3D5FFB4E2, $72BE5D74F27B896F, $80DEB1FE3B1696B1, + $9BDC06A725C71235, $C19BF174CF692694, $E49B69C19EF14AD2, $EFBE4786384F25E3, + $0FC19DC68B8CD5B5, $240CA1CC77AC9C65, $2DE92C6F592B0275, $4A7484AA6EA6E483, + $5CB0A9DCBD41FBD4, $76F988DA831153B5, $983E5152EE66DFAB, $A831C66D2DB43210, + $B00327C898FB213F, $BF597FC7BEEF0EE4, $C6E00BF33DA88FC2, $D5A79147930AA725, + $06CA6351E003826F, $142929670A0E6E70, $27B70A8546D22FFC, $2E1B21385C26C926, + $4D2C6DFC5AC42AED, $53380D139D95B3DF, $650A73548BAF63DE, $766A0ABB3C77B2A8, + $81C2C92E47EDAEE6, $92722C851482353B, $A2BFE8A14CF10364, $A81A664BBC423001, + $C24B8B70D0F89791, $C76C51A30654BE30, $D192E819D6EF5218, $D69906245565A910, + $F40E35855771202A, $106AA07032BBD1B8, $19A4C116B8D2D0C8, $1E376C085141AB53, + $2748774CDF8EEB99, $34B0BCB5E19B48A8, $391C0CB3C5C95A63, $4ED8AA4AE3418ACB, + $5B9CCA4F7763E373, $682E6FF3D6B2B8A3, $748F82EE5DEFB2FC, $78A5636F43172F60, + $84C87814A1F0AB72, $8CC702081A6439EC, $90BEFFFA23631E28, $A4506CEBDE82BDE9, + $BEF9A3F7B2C67915, $C67178F2E372532B, $CA273ECEEA26619C, $D186B8C721C0C207, + $EADA7DD6CDE0EB1E, $F57D4F7FEE6ED178, $06F067AA72176FBA, $0A637DC5A2C898A6, + $113F9804BEF90DAE, $1B710B35131C471B, $28DB77F523047D84, $32CAAB7B40C72493, + $3C9EBE0A15C9BEBC, $431D67C49C100D4C, $4CC5D4BECB3E42B6, $597F299CFC657E2A, + $5FCB6FAB3AD6FAEC, $6C44198C4A475817); + +function ROTRight256(A, B: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (A shr B) or (A shl (32 - B)); +end; + +function ROTRight512(X: TUInt64; Y: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X shr Y) or (X shl (64 - Y)); +end; + +function SHR512(X: TUInt64; Y: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and $FFFFFFFFFFFFFFFF) shr Y; +end; + +function CH256(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Y) xor ((not X) and Z); +end; + +function CH512(X, Y, Z: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (((Y xor Z) and X) xor Z); +end; + +function MAJ256(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Y) xor (X and Z) xor (Y and Z); +end; + +function MAJ512(X, Y, Z: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ((X or Y) and Z) or (X and Y); +end; + +function EP0256(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight256(X, 2) xor ROTRight256(X, 13) xor ROTRight256(X, 22); +end; + +function EP1256(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight256(X, 6) xor ROTRight256(X, 11) xor ROTRight256(X, 25); +end; + +function SIG0256(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight256(X, 7) xor ROTRight256(X, 18) xor (X shr 3); +end; + +function SIG1256(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight256(X, 17) xor ROTRight256(X, 19) xor (X shr 10); +end; + +function SIG0512(X: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight512(X, 28) xor ROTRight512(X, 34) xor ROTRight512(X, 39); +end; + +function SIG1512(X: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight512(X, 14) xor ROTRight512(X, 18) xor ROTRight512(X, 41); +end; + +function Gamma0512(X: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight512(X, 1) xor ROTRight512(X, 8) xor SHR512(X, 7); +end; + +function Gamma1512(X: TUInt64): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := ROTRight512(X, 19) xor ROTRight512(X, 61) xor SHR512(X, 6); +end; + +procedure SHA256Transform(var Context: TCnSHA256Context; Data: PAnsiChar); +var + A, B, C, D, E, F, G, H, T1, T2: Cardinal; + M: array[0..63] of Cardinal; + I, J: Integer; +begin + I := 0; + J := 0; + while I < 16 do + begin + M[I] := (Cardinal(Data[J]) shl 24) or (Cardinal(Data[J + 1]) shl 16) or (Cardinal(Data + [J + 2]) shl 8) or Cardinal(Data[J + 3]); + Inc(I); + Inc(J, 4); + end; + + while I < 64 do + begin + M[I] := SIG1256(M[I - 2]) + M[I - 7] + SIG0256(M[I - 15]) + M[I - 16]; + Inc(I); + end; + + A := Context.State[0]; + B := Context.State[1]; + C := Context.State[2]; + D := Context.State[3]; + E := Context.State[4]; + F := Context.State[5]; + G := Context.State[6]; + H := Context.State[7]; + + I := 0; + while I < 64 do + begin + T1 := H + EP1256(E) + CH256(E, F, G) + KEYS256[I] + M[I]; + T2 := EP0256(A) + MAJ256(A, B, C); + H := G; + G := F; + F := E; + E := D + T1; + D := C; + C := B; + B := A; + A := T1 + T2; + Inc(I); + end; + + Context.State[0] := Context.State[0] + A; + Context.State[1] := Context.State[1] + B; + Context.State[2] := Context.State[2] + C; + Context.State[3] := Context.State[3] + D; + Context.State[4] := Context.State[4] + E; + Context.State[5] := Context.State[5] + F; + Context.State[6] := Context.State[6] + G; + Context.State[7] := Context.State[7] + H; +end; + +{$WARNINGS OFF} + +procedure SHA512Transform(var Context: TCnSHA512Context; Data: PAnsiChar; BlockCount: Integer); +var + A, B, C, D, E, F, G, H, T1, T2: TUInt64; + M: array[0..79] of TUInt64; + I, J, K: Integer; + OrigData: PAnsiChar; +begin + OrigData := Data; + for K := 0 to BlockCount - 1 do + begin + Data := PAnsiChar(TCnNativeInt(OrigData) + (K shl 7)); + + I := 0; + J := 0; + while I < 16 do + begin + // ע Delphi 5 6 7 ´˴ Int64 ƣ Range Check شʱ + // ΪȻһÿرصܵõȷ + M[I] := (TUInt64(Data[J]) shl 56) or (TUInt64(Data[J + 1]) shl 48) or + (TUInt64(Data[J + 2]) shl 40) or (TUInt64(Data[J + 3]) shl 32) or + (TUInt64(Data[J + 4]) shl 24) or (TUInt64(Data[J + 5]) shl 16) or + (TUInt64(Data[J + 6]) shl 8) or TUInt64(Data[J + 7]); + Inc(I); + Inc(J, 8); + end; + + while I < 80 do + begin + M[I] := Gamma1512(M[I - 2]) + M[I - 7] + Gamma0512(M[I - 15]) + M[I - 16]; + Inc(I); + end; + + A := Context.State[0]; + B := Context.State[1]; + C := Context.State[2]; + D := Context.State[3]; + E := Context.State[4]; + F := Context.State[5]; + G := Context.State[6]; + H := Context.State[7]; + + I := 0; + while I < 80 do + begin + T1 := H + SIG1512(E) + CH512(E, F, G) + KEYS512[I] + M[I]; + T2 := SIG0512(A) + MAJ512(A, B, C); + H := G; + G := F; + F := E; + E := D + T1; + D := C; + C := B; + B := A; + A := T1 + T2; + Inc(I); + end; + + // з WarningӰ + Context.State[0] := Context.State[0] + A; + Context.State[1] := Context.State[1] + B; + Context.State[2] := Context.State[2] + C; + Context.State[3] := Context.State[3] + D; + Context.State[4] := Context.State[4] + E; + Context.State[5] := Context.State[5] + F; + Context.State[6] := Context.State[6] + G; + Context.State[7] := Context.State[7] + H; + end; +end; + +{$WARNINGS ON} + +procedure SHA224Init(var Context: TCnSHA224Context); +begin + Context.DataLen := 0; + Context.BitLen := 0; + Context.State[0] := $C1059ED8; + Context.State[1] := $367CD507; + Context.State[2] := $3070DD17; + Context.State[3] := $F70E5939; + Context.State[4] := $FFC00B31; + Context.State[5] := $68581511; + Context.State[6] := $64F98FA7; + Context.State[7] := $BEFA4FA4; + FillChar(Context.Data, SizeOf(Context.Data), 0); +end; + +procedure SHA224Update(var Context: TCnSHA224Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA256Update(Context, Input, ByteLength); +end; + +procedure SHA256UpdateW(var Context: TCnSHA256Context; Input: PWideChar; CharLength: Cardinal); forward; + +procedure SHA224UpdateW(var Context: TCnSHA224Context; Input: PWideChar; CharLength: Cardinal); +begin + SHA256UpdateW(Context, Input, CharLength); +end; + +procedure SHA224Final(var Context: TCnSHA224Context; var Digest: TCnSHA224Digest); +var + Dig: TCnSHA256Digest; +begin + SHA256Final(Context, Dig); + Move(Dig[0], Digest[0], SizeOf(TCnSHA224Digest)); +end; + +procedure SHA256Init(var Context: TCnSHA256Context); +begin + Context.DataLen := 0; + Context.BitLen := 0; + Context.State[0] := $6A09E667; + Context.State[1] := $BB67AE85; + Context.State[2] := $3C6EF372; + Context.State[3] := $A54FF53A; + Context.State[4] := $510E527F; + Context.State[5] := $9B05688C; + Context.State[6] := $1F83D9AB; + Context.State[7] := $5BE0CD19; + FillChar(Context.Data, SizeOf(Context.Data), 0); +end; + +procedure SHA256Update(var Context: TCnSHA256Context; Input: PAnsiChar; ByteLength: Cardinal); +var + B: Cardinal; +begin + while ByteLength > 0 do + begin + if 64 - Context.DataLen > ByteLength then + B := ByteLength + else + B := 64 - Context.DataLen; + + Move(Input^, Context.Data[Context.DataLen], B); + Inc(Context.DataLen, B); + Dec(ByteLength, B); + Inc(Input, B); + + if Context.DataLen = 64 then + begin + SHA256Transform(Context, @Context.Data[0]); + Context.BitLen := Context.BitLen + 512; + Context.DataLen := 0; + end; + end; +end; + +procedure SHA256UpdateW(var Context: TCnSHA256Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + Content: PAnsiChar; + iLen: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(Content, CharLength * SizeOf(WideChar)); + try + iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(Content), CharLength * SizeOf(WideChar), nil, nil); + SHA256Update(Context, Content, iLen); + finally + FreeMem(Content); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + SHA256Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +procedure SHA256Final(var Context: TCnSHA256Context; var Digest: TCnSHA256Digest); +var + I: Integer; +begin + I := Context.DataLen; + Context.Data[I] := $80; + Inc(I); + + if Context.Datalen < 56 then + begin + while I < 56 do + begin + Context.Data[I] := 0; + Inc(I); + end; + end + else + begin + while I < 64 do + begin + Context.Data[I] := 0; + Inc(I); + end; + + SHA256Transform(Context, @(Context.Data[0])); + FillChar(Context.Data, 56, 0); + end; + + Context.BitLen := Context.BitLen + Context.DataLen * 8; + Context.Data[63] := Byte(Context.Bitlen); + Context.Data[62] := Byte(Context.Bitlen shr 8); + Context.Data[61] := Byte(Context.Bitlen shr 16); + Context.Data[60] := Byte(Context.Bitlen shr 24); + Context.Data[59] := Byte(Context.Bitlen shr 32); + Context.Data[58] := Byte(Context.Bitlen shr 40); + Context.Data[57] := Byte(Context.Bitlen shr 48); + Context.Data[56] := Byte(Context.Bitlen shr 56); + SHA256Transform(Context, @(Context.Data[0])); + + for I := 0 to 3 do + begin + Digest[I] := (Context.State[0] shr (24 - I * 8)) and $000000FF; + Digest[I + 4] := (Context.State[1] shr (24 - I * 8)) and $000000FF; + Digest[I + 8] := (Context.State[2] shr (24 - I * 8)) and $000000FF; + Digest[I + 12] := (Context.State[3] shr (24 - I * 8)) and $000000FF; + Digest[I + 16] := (Context.State[4] shr (24 - I * 8)) and $000000FF; + Digest[I + 20] := (Context.State[5] shr (24 - I * 8)) and $000000FF; + Digest[I + 24] := (Context.State[6] shr (24 - I * 8)) and $000000FF; + Digest[I + 28] := (Context.State[7] shr (24 - I * 8)) and $000000FF; + end; +end; + +{$WARNINGS OFF} + +procedure SHA384Init(var Context: TCnSHA384Context); +begin + Context.DataLen := 0; + Context.TotalLen := 0; + Context.State[0] := $CBBB9D5DC1059ED8; + Context.State[1] := $629A292A367CD507; + Context.State[2] := $9159015A3070DD17; + Context.State[3] := $152FECD8F70E5939; + Context.State[4] := $67332667FFC00B31; + Context.State[5] := $8EB44A8768581511; + Context.State[6] := $DB0C2E0D64F98FA7; + Context.State[7] := $47B5481DBEFA4FA4; + FillChar(Context.Data, SizeOf(Context.Data), 0); +end; + +{$WARNINGS ON} + +procedure SHA384Update(var Context: TCnSHA384Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA512Update(Context, Input, ByteLength); +end; + +procedure SHA512UpdateW(var Context: TCnSHA512Context; Input: PWideChar; CharLength: Cardinal); forward; + +procedure SHA384UpdateW(var Context: TCnSHA384Context; Input: PWideChar; CharLength: Cardinal); +begin + SHA512UpdateW(Context, Input, CharLength); +end; + +procedure SHA384Final(var Context: TCnSHA384Context; var Digest: TCnSHA384Digest); +var + Dig: TCnSHA512Digest; +begin + SHA512Final(Context, Dig); + Move(Dig[0], Digest[0], SizeOf(TCnSHA384Digest)); +end; + +{$WARNINGS OFF} + +procedure SHA512Init(var Context: TCnSHA512Context); +begin + Context.DataLen := 0; + Context.TotalLen := 0; + Context.State[0] := $6A09E667F3BCC908; + Context.State[1] := $BB67AE8584CAA73B; + Context.State[2] := $3C6EF372FE94F82B; + Context.State[3] := $A54FF53A5F1D36F1; + Context.State[4] := $510E527FADE682D1; + Context.State[5] := $9B05688C2B3E6C1F; + Context.State[6] := $1F83D9ABFB41BD6B; + Context.State[7] := $5BE0CD19137E2179; + FillChar(Context.Data, SizeOf(Context.Data), 0); +end; + +{$WARNINGS ON} + +procedure SHA512Update(var Context: TCnSHA512Context; Input: PAnsiChar; ByteLength: Cardinal); +var + TempLength, RemainLength, NewLength, BlockCount: Cardinal; +begin + TempLength := 128 - Context.DataLen; + if ByteLength < TempLength then + RemainLength := ByteLength + else + RemainLength := TempLength; + + Move(Input^, Context.Data[Context.DataLen], RemainLength); + if Context.DataLen + ByteLength < 128 then + begin + Inc(Context.DataLen, ByteLength); + Exit; + end; + + NewLength := Cardinal(ByteLength) - RemainLength; + BlockCount := NewLength div 128; + Input := PAnsiChar(TCnNativeUInt(Input) + RemainLength); + + SHA512Transform(Context, @Context.Data[0], 1); + SHA512Transform(Context, Input, BlockCount); + + RemainLength := NewLength mod 128; + Input := PAnsiChar(TCnNativeUInt(Input) + (BlockCount shl 7)); + Move(Input^, Context.Data[Context.DataLen], RemainLength); + + Context.DataLen := RemainLength; + Inc(Context.TotalLen, (BlockCount + 1) shl 7); +end; + +procedure SHA512UpdateW(var Context: TCnSHA512Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + Content: PAnsiChar; + iLen: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(Content, CharLength * SizeOf(WideChar)); + try + iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(Content), CharLength * SizeOf(WideChar), nil, nil); + SHA512Update(Context, Content, iLen); + finally + FreeMem(Content); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + SHA512Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +procedure SHA512Final(var Context: TCnSHA512Context; var Digest: TCnSHA512Digest); +var + I: Integer; + BlockCount, PmLength: Cardinal; + BitLength: TUInt64; +begin + if (Context.DataLen mod 128) > 111 then + BlockCount := 2 + else + BlockCount := 1; + + BitLength := (Context.TotalLen + Context.DataLen) shl 3; + PmLength := BlockCount shl 7; + FillChar(Context.Data[Context.DataLen], PmLength - Context.DataLen, 0); + Context.Data[Context.DataLen] := $80; + + Context.Data[PmLength - 1] := Byte(BitLength); + Context.Data[PmLength - 2] := Byte(BitLength shr 8); + Context.Data[PmLength - 3] := Byte(BitLength shr 16); + Context.Data[PmLength - 4] := Byte(BitLength shr 24); + Context.Data[PmLength - 5] := Byte(BitLength shr 32); + Context.Data[PmLength - 6] := Byte(BitLength shr 40); + Context.Data[PmLength - 7] := Byte(BitLength shr 48); + Context.Data[PmLength - 8] := Byte(BitLength shr 56); + + // ٴΰ淶е 128 λȸֵΪ FillChar 0 + SHA512Transform(Context, @(Context.Data[0]), BlockCount); + + for I := 0 to 7 do + begin + Digest[I] := (Context.State[0] shr (56 - I * 8)) and $000000FF; + Digest[I + 8] := (Context.State[1] shr (56 - I * 8)) and $000000FF; + Digest[I + 16] := (Context.State[2] shr (56 - I * 8)) and $000000FF; + Digest[I + 24] := (Context.State[3] shr (56 - I * 8)) and $000000FF; + Digest[I + 32] := (Context.State[4] shr (56 - I * 8)) and $000000FF; + Digest[I + 40] := (Context.State[5] shr (56 - I * 8)) and $000000FF; + Digest[I + 48] := (Context.State[6] shr (56 - I * 8)) and $000000FF; + Digest[I + 56] := (Context.State[7] shr (56 - I * 8)) and $000000FF; + end; +end; + +procedure SHA512_224Init(var Context: TCnSHA512_224Context); +begin + Context.DataLen := 0; + Context.TotalLen := 0; + Context.State[0] := Int64($8C3D37C819544DA2); + Context.State[1] := Int64($73E1996689DCD4D6); + Context.State[2] := Int64($1DFAB7AE32FF9C82); + Context.State[3] := Int64($679DD514582F9FCF); + Context.State[4] := Int64($0F6D2B697BD44DA8); + Context.State[5] := Int64($77E36F7304C48942); + Context.State[6] := Int64($3F9D85A86A1D36C8); + Context.State[7] := Int64($1112E6AD91D692A1); + FillChar(Context.Data, SizeOf(Context.Data), 0); +end; + +procedure SHA512_224Update(var Context: TCnSHA512_224Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA512Update(Context, Input, ByteLength); +end; + +procedure SHA512_224UpdateW(var Context: TCnSHA512_224Context; Input: PWideChar; CharLength: Cardinal); +begin + SHA512UpdateW(Context, Input, CharLength); +end; + +procedure SHA512_224Final(var Context: TCnSHA512_224Context; var Digest: TCnSHA512_224Digest); +var + Dig: TCnSHA512Digest; +begin + SHA512Final(Context, Dig); + Move(Dig[0], Digest[0], SizeOf(TCnSHA512_224Digest)); +end; + +procedure SHA512_256Init(var Context: TCnSHA512_256Context); +begin + Context.DataLen := 0; + Context.TotalLen := 0; + Context.State[0] := Int64($22312194FC2BF72C); + Context.State[1] := Int64($9F555FA3C84C64C2); + Context.State[2] := Int64($2393B86B6F53B151); + Context.State[3] := Int64($963877195940EABD); + Context.State[4] := Int64($96283EE2A88EFFE3); + Context.State[5] := Int64($BE5E1E2553863992); + Context.State[6] := Int64($2B0199FC2C85B8AA); + Context.State[7] := Int64($0EB72DDC81C52CA2); + FillChar(Context.Data, SizeOf(Context.Data), 0); +end; + +procedure SHA512_256Update(var Context: TCnSHA512_256Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA512Update(Context, Input, ByteLength); +end; + +procedure SHA512_256UpdateW(var Context: TCnSHA512_256Context; Input: PWideChar; CharLength: Cardinal); +begin + SHA512UpdateW(Context, Input, CharLength); +end; + +procedure SHA512_256Final(var Context: TCnSHA512_256Context; var Digest: TCnSHA512_256Digest); +var + Dig: TCnSHA512Digest; +begin + SHA512Final(Context, Dig); + Move(Dig[0], Digest[0], SizeOf(TCnSHA512_256Digest)); +end; + +// ݿ SHA224 +function SHA224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224Update(Context, Input, ByteLength); + SHA224Final(Context, Result); +end; + +// ݿ SHA256 +function SHA256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256Update(Context, Input, ByteLength); + SHA256Final(Context, Result); +end; + +// ݿ SHA384 +function SHA384(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384Update(Context, Input, ByteLength); + SHA384Final(Context, Result); +end; + +// ݿ SHA512 +function SHA512(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512Update(Context, Input, ByteLength); + SHA512Final(Context, Result); +end; + +// ݿ SHA512_224 +function SHA512_224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA512_224Digest; +var + Context: TCnSHA512_224Context; +begin + SHA512_224Init(Context); + SHA512_224Update(Context, Input, ByteLength); + SHA512_224Final(Context, Result); +end; + +// ݿ SHA512_256 +function SHA512_256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA512_256Digest; +var + Context: TCnSHA512_256Context; +begin + SHA512_256Init(Context); + SHA512_256Update(Context, Input, ByteLength); + SHA512_256Final(Context, Result); +end; + +// ݿ SHA224 +function SHA224Buffer(const Buffer; Count: Cardinal): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224Update(Context, PAnsiChar(@Buffer), Count); + SHA224Final(Context, Result); +end; + +// ݿ SHA256 +function SHA256Buffer(const Buffer; Count: Cardinal): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256Update(Context, PAnsiChar(@Buffer), Count); + SHA256Final(Context, Result); +end; + +// ݿ SHA384 +function SHA384Buffer(const Buffer; Count: Cardinal): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384Update(Context, PAnsiChar(@Buffer), Count); + SHA384Final(Context, Result); +end; + +// ݿ SHA512 +function SHA512Buffer(const Buffer; Count: Cardinal): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512Update(Context, PAnsiChar(@Buffer), Count); + SHA512Final(Context, Result); +end; + +// ݿ SHA512_224 +function SHA512_224Buffer(const Buffer; Count: Cardinal): TCnSHA512_224Digest; +var + Context: TCnSHA512_224Context; +begin + SHA512_224Init(Context); + SHA512_224Update(Context, PAnsiChar(@Buffer), Count); + SHA512_224Final(Context, Result); +end; + +// ݿ SHA512_256 +function SHA512_256Buffer(const Buffer; Count: Cardinal): TCnSHA512_256Digest; +var + Context: TCnSHA512_256Context; +begin + SHA512_256Init(Context); + SHA512_256Update(Context, PAnsiChar(@Buffer), Count); + SHA512_256Final(Context, Result); +end; + +// ֽ SHA224 +function SHA224Bytes(const Data: TBytes): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA224Final(Context, Result); +end; + +// ֽ SHA256 +function SHA256Bytes(const Data: TBytes): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA256Final(Context, Result); +end; + +// ֽ SHA384 +function SHA384Bytes(const Data: TBytes): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA384Final(Context, Result); +end; + +// ֽ SHA512 +function SHA512Bytes(const Data: TBytes): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA512Final(Context, Result); +end; + +// ֽ SHA512_224 +function SHA512_224Bytes(const Data: TBytes): TCnSHA512_224Digest; +var + Context: TCnSHA512_224Context; +begin + SHA512_224Init(Context); + SHA512_224Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA512_224Final(Context, Result); +end; + +// ֽ SHA512_256 +function SHA512_256Bytes(const Data: TBytes): TCnSHA512_256Digest; +var + Context: TCnSHA512_256Context; +begin + SHA512_256Init(Context); + SHA512_256Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA512_256Final(Context, Result); +end; + +// String ݽ SHA224 +function SHA224String(const Str: string): TCnSHA224Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA224StringA(AStr); +end; + +// String ݽ SHA256 +function SHA256String(const Str: string): TCnSHA256Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA256StringA(AStr); +end; + +// String ݽ SHA384 +function SHA384String(const Str: string): TCnSHA384Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA384StringA(AStr); +end; + +// String ݽ SHA512 +function SHA512String(const Str: string): TCnSHA512Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA512StringA(AStr); +end; + +// String ݽ SHA512_224 +function SHA512_224String(const Str: string): TCnSHA512_224Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA512_224StringA(AStr); +end; + +// String ݽ SHA512_256 +function SHA512_256String(const Str: string): TCnSHA512_256Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA512_256StringA(AStr); +end; + +// UnicodeString ݽֱӵ SHA224 㣬ת +{$IFDEF UNICODE} +function SHA224UnicodeString(const Str: string): TCnSHA224Digest; +{$ELSE} +function SHA224UnicodeString(const Str: WideString): TCnSHA224Digest; +{$ENDIF} +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA224Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SHA256 㣬ת +{$IFDEF UNICODE} +function SHA256UnicodeString(const Str: string): TCnSHA256Digest; +{$ELSE} +function SHA256UnicodeString(const Str: WideString): TCnSHA256Digest; +{$ENDIF} +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA256Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SHA384 㣬ת +{$IFDEF UNICODE} +function SHA384UnicodeString(const Str: string): TCnSHA384Digest; +{$ELSE} +function SHA384UnicodeString(const Str: WideString): TCnSHA384Digest; +{$ENDIF} +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA384Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SHA512 㣬ת +{$IFDEF UNICODE} +function SHA512UnicodeString(const Str: string): TCnSHA512Digest; +{$ELSE} +function SHA512UnicodeString(const Str: WideString): TCnSHA512Digest; +{$ENDIF} +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA512Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SHA512_224 㣬ת +{$IFDEF UNICODE} +function SHA512_224UnicodeString(const Str: string): TCnSHA512_224Digest; +{$ELSE} +function SHA512_224UnicodeString(const Str: WideString): TCnSHA512_224Digest; +{$ENDIF} +var + Context: TCnSHA512_224Context; +begin + SHA512_224Init(Context); + SHA512_224Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA512_224Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SHA512_256 㣬ת +{$IFDEF UNICODE} +function SHA512_256UnicodeString(const Str: string): TCnSHA512_256Digest; +{$ELSE} +function SHA512_256UnicodeString(const Str: WideString): TCnSHA512_256Digest; +{$ENDIF} +var + Context: TCnSHA512_256Context; +begin + SHA512_256Init(Context); + SHA512_256Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA512_256Final(Context, Result); +end; + +// AnsiString ݽ SHA224 +function SHA224StringA(const Str: AnsiString): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224Update(Context, PAnsiChar(Str), Length(Str)); + SHA224Final(Context, Result); +end; + +// WideString ݽ SHA224 +function SHA224StringW(const Str: WideString): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224Init(Context); + SHA224UpdateW(Context, PWideChar(Str), Length(Str)); + SHA224Final(Context, Result); +end; + +// AnsiString ݽ SHA256 +function SHA256StringA(const Str: AnsiString): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256Update(Context, PAnsiChar(Str), Length(Str)); + SHA256Final(Context, Result); +end; + +// WideString ݽ SHA256 +function SHA256StringW(const Str: WideString): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256Init(Context); + SHA256UpdateW(Context, PWideChar(Str), Length(Str)); + SHA256Final(Context, Result); +end; + +// AnsiString ݽ SHA384 +function SHA384StringA(const Str: AnsiString): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384Update(Context, PAnsiChar(Str), Length(Str)); + SHA384Final(Context, Result); +end; + +// WideString ݽ SHA384 +function SHA384StringW(const Str: WideString): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384Init(Context); + SHA384UpdateW(Context, PWideChar(Str), Length(Str)); + SHA384Final(Context, Result); +end; + +// AnsiString ݽ SHA512 +function SHA512StringA(const Str: AnsiString): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512Update(Context, PAnsiChar(Str), Length(Str)); + SHA512Final(Context, Result); +end; + +// WideString ݽ SHA512 +function SHA512StringW(const Str: WideString): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512Init(Context); + SHA512UpdateW(Context, PWideChar(Str), Length(Str)); + SHA512Final(Context, Result); +end; + +// AnsiString ݽ SHA512_224 +function SHA512_224StringA(const Str: AnsiString): TCnSHA512_224Digest; +var + Context: TCnSHA512_224Context; +begin + SHA512_224Init(Context); + SHA512_224Update(Context, PAnsiChar(Str), Length(Str)); + SHA512_224Final(Context, Result); +end; + +// WideString ݽ SHA512_224 +function SHA512_224StringW(const Str: WideString): TCnSHA512_224Digest; +var + Context: TCnSHA512_224Context; +begin + SHA512_224Init(Context); + SHA512_224UpdateW(Context, PWideChar(Str), Length(Str)); + SHA512_224Final(Context, Result); +end; + +// AnsiString ݽ SHA512_256 +function SHA512_256StringA(const Str: AnsiString): TCnSHA512_256Digest; +var + Context: TCnSHA512_256Context; +begin + SHA512_256Init(Context); + SHA512_256Update(Context, PAnsiChar(Str), Length(Str)); + SHA512_256Final(Context, Result); +end; + +// WideString ݽ SHA512_256 +function SHA512_256StringW(const Str: WideString): TCnSHA512_256Digest; +var + Context: TCnSHA512_256Context; +begin + SHA512_256Init(Context); + SHA512_256UpdateW(Context, PWideChar(Str), Length(Str)); + SHA512_256Final(Context, Result); +end; + +function InternalSHAStream(Stream: TStream; const BufSize: Cardinal; var D: + TCnSHA2GeneralDigest; SHA2Type: TSHA2Type; CallBack: TCnSHACalcProgressFunc): Boolean; +var + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; + + Context224: TCnSHA224Context; + Context256: TCnSHA256Context; + Context384: TCnSHA384Context; + Context512: TCnSHA512Context; + Context512_224: TCnSHA512_224Context; + Context512_256: TCnSHA512_256Context; + Dig224: TCnSHA224Digest; + Dig256: TCnSHA256Digest; + Dig384: TCnSHA384Digest; + Dig512: TCnSHA512Digest; + Dig512_224: TCnSHA512_224Digest; + Dig512_256: TCnSHA512_256Digest; + + procedure _SHAInit; + begin + case SHA2Type of + stSHA2_224: + SHA224Init(Context224); + stSHA2_256: + SHA256Init(Context256); + stSHA2_384: + SHA384Init(Context384); + stSHA2_512: + SHA512Init(Context512); + stSHA2_512_224: + SHA512_224Init(Context512_224); + stSHA2_512_256: + SHA512_256Init(Context512_256); + end; + end; + + procedure _SHAUpdate; + begin + case SHA2Type of + stSHA2_224: + SHA224Update(Context224, Buf, ReadBytes); + stSHA2_256: + SHA256Update(Context256, Buf, ReadBytes); + stSHA2_384: + SHA384Update(Context384, Buf, ReadBytes); + stSHA2_512: + SHA512Update(Context512, Buf, ReadBytes); + stSHA2_512_224: + SHA512_224Update(Context512_224, Buf, ReadBytes); + stSHA2_512_256: + SHA512_256Update(Context512_256, Buf, ReadBytes); + end; + end; + + procedure _SHAFinal; + begin + case SHA2Type of + stSHA2_224: + SHA224Final(Context224, Dig224); + stSHA2_256: + SHA256Final(Context256, Dig256); + stSHA2_384: + SHA384Final(Context384, Dig384); + stSHA2_512: + SHA512Final(Context512, Dig512); + stSHA2_512_224: + SHA512_224Final(Context512_224, Dig512_224); + stSHA2_512_256: + SHA512_256Final(Context512_256, Dig512_256); + end; + end; + + procedure _CopyResult; + begin + case SHA2Type of + stSHA2_224: + Move(Dig224[0], D[0], SizeOf(TCnSHA224Digest)); + stSHA2_256: + Move(Dig256[0], D[0], SizeOf(TCnSHA256Digest)); + stSHA2_384: + Move(Dig384[0], D[0], SizeOf(TCnSHA384Digest)); + stSHA2_512: + Move(Dig512[0], D[0], SizeOf(TCnSHA512Digest)); + stSHA2_512_224: + Move(Dig512_224[0], D[0], SizeOf(TCnSHA512_224Digest)); + stSHA2_512_256: + Move(Dig512_256[0], D[0], SizeOf(TCnSHA512_256Digest)); + end; + end; + +begin + Result := False; + Size := Stream.Size; + SavePos := Stream.Position; + TotalBytes := 0; + if Size = 0 then + Exit; + if Size < BufSize then + BufLen := Size + else + BufLen := BufSize; + + CancelCalc := False; + _SHAInit; + + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + _SHAUpdate; + + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then + Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + _SHAFinal; + _CopyResult; + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +// ָ SHA224 +function SHA224Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc): + TCnSHA224Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_224, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA224Digest)); +end; + +// ָ SHA256 +function SHA256Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc): + TCnSHA256Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_256, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA256Digest)); +end; + +// ָ SHA384 +function SHA384Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc): + TCnSHA384Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_384, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA384Digest)); +end; + +// ָ SHA512 +function SHA512Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc): + TCnSHA512Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_512, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA512Digest)); +end; + +// ָ SHA512_224 +function SHA512_224Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc): + TCnSHA512_224Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_512_224, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA512_224Digest)); +end; + +// ָ SHA512_256 +function SHA512_256Stream(Stream: TStream; CallBack: TCnSHACalcProgressFunc): + TCnSHA512_256Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + InternalSHAStream(Stream, 4096 * 1024, Dig, stSHA2_512_256, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA512_256Digest)); +end; + +function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; +{$IFDEF MSWINDOWS} +var + H: THandle; + Info: BY_HANDLE_FILE_INFORMATION; + Rec: Int64Rec; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + Result := False; + IsEmpty := False; + H := CreateFile(PChar(AFileName), GENERIC_READ, FILE_SHARE_READ, nil, + OPEN_EXISTING, 0, 0); + if H = INVALID_HANDLE_VALUE then + Exit; + try + if not GetFileInformationByHandle(H, Info) then + Exit; + finally + CloseHandle(H); + end; + Rec.Lo := Info.nFileSizeLow; + Rec.Hi := Info.nFileSizeHigh; + Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); + IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); +{$ELSE} + Result := True; // Windows ƽ̨ Trueʾ Mapping +{$ENDIF} +end; + +function InternalSHAFile(const FileName: string; SHA2Type: TSHA2Type; + CallBack: TCnSHACalcProgressFunc): TCnSHA2GeneralDigest; +var + Context224: TCnSHA224Context; + Context256: TCnSHA256Context; + Context384: TCnSHA384Context; + Context512: TCnSHA512Context; + Context512_224: TCnSHA512_224Context; + Context512_256: TCnSHA512_256Context; + Dig224: TCnSHA224Digest; + Dig256: TCnSHA256Digest; + Dig384: TCnSHA384Digest; + Dig512: TCnSHA512Digest; + Dig512_224: TCnSHA512_224Digest; + Dig512_256: TCnSHA512_256Digest; + +{$IFDEF MSWINDOWS} + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; + + procedure _SHAInit; + begin + case SHA2Type of + stSHA2_224: + SHA224Init(Context224); + stSHA2_256: + SHA256Init(Context256); + stSHA2_384: + SHA384Init(Context384); + stSHA2_512: + SHA512Init(Context512); + stSHA2_512_224: + SHA512_224Init(Context512_224); + stSHA2_512_256: + SHA512_256Init(Context512_256); + end; + end; + +{$IFDEF MSWINDOWS} + procedure _SHAUpdate; + begin + case SHA2Type of + stSHA2_224: + SHA224Update(Context224, ViewPointer, GetFileSize(FileHandle, nil)); + stSHA2_256: + SHA256Update(Context256, ViewPointer, GetFileSize(FileHandle, nil)); + stSHA2_384: + SHA384Update(Context384, ViewPointer, GetFileSize(FileHandle, nil)); + stSHA2_512: + SHA512Update(Context512, ViewPointer, GetFileSize(FileHandle, nil)); + stSHA2_512_224: + SHA512_224Update(Context512_224, ViewPointer, GetFileSize(FileHandle, nil)); + stSHA2_512_256: + SHA512_256Update(Context512_256, ViewPointer, GetFileSize(FileHandle, nil)); + end; + end; +{$ENDIF} + + procedure _SHAFinal; + begin + case SHA2Type of + stSHA2_224: + SHA224Final(Context224, Dig224); + stSHA2_256: + SHA256Final(Context256, Dig256); + stSHA2_384: + SHA384Final(Context384, Dig384); + stSHA2_512: + SHA512Final(Context512, Dig512); + stSHA2_512_224: + SHA512_224Final(Context512_224, Dig512_224); + stSHA2_512_256: + SHA512_256Final(Context512_256, Dig512_256); + end; + end; + + procedure _CopyResult(var D: TCnSHA2GeneralDigest); + begin + case SHA2Type of + stSHA2_224: + Move(Dig224[0], D[0], SizeOf(TCnSHA224Digest)); + stSHA2_256: + Move(Dig256[0], D[0], SizeOf(TCnSHA256Digest)); + stSHA2_384: + Move(Dig384[0], D[0], SizeOf(TCnSHA384Digest)); + stSHA2_512: + Move(Dig512[0], D[0], SizeOf(TCnSHA512Digest)); + stSHA2_512_224: + Move(Dig512_224[0], D[0], SizeOf(TCnSHA512_224Digest)); + stSHA2_512_256: + Move(Dig512_256[0], D[0], SizeOf(TCnSHA512_256Digest)); + end; + end; + +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣ Windows ƽ̨ʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalSHAStream(Stream, 4096 * 1024, Result, SHA2Type, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + _SHAInit; + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + _SHAUpdate; + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise ECnNativeException.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise ECnNativeException.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + _SHAFinal; + _CopyResult(Result); +{$ENDIF} + end; +end; + +// ָļݽ SHA224 +function SHA224File(const FileName: string; CallBack: TCnSHACalcProgressFunc): + TCnSHA224Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + Dig := InternalSHAFile(FileName, stSHA2_224, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA224Digest)); +end; + +// ָļݽ SHA256 +function SHA256File(const FileName: string; CallBack: TCnSHACalcProgressFunc): + TCnSHA256Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + Dig := InternalSHAFile(FileName, stSHA2_256, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA256Digest)); +end; + +// ָļݽ SHA384 +function SHA384File(const FileName: string; CallBack: TCnSHACalcProgressFunc): + TCnSHA384Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + Dig := InternalSHAFile(FileName, stSHA2_384, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA384Digest)); +end; + +// ָļݽ SHA512 +function SHA512File(const FileName: string; CallBack: TCnSHACalcProgressFunc): + TCnSHA512Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + Dig := InternalSHAFile(FileName, stSHA2_512, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA512Digest)); +end; + +// ָļݽ SHA512_224 +function SHA512_224File(const FileName: string; CallBack: TCnSHACalcProgressFunc): + TCnSHA512_224Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + Dig := InternalSHAFile(FileName, stSHA2_512_224, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA512_224Digest)); +end; + +// ָļݽ SHA512_256 +function SHA512_256File(const FileName: string; CallBack: TCnSHACalcProgressFunc): + TCnSHA512_256Digest; +var + Dig: TCnSHA2GeneralDigest; +begin + Dig := InternalSHAFile(FileName, stSHA2_512_256, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA512_256Digest)); +end; + +// ʮƸʽ SHA224 Ӵֵ +function SHA224Print(const Digest: TCnSHA224Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA224Digest)); +end; + +// ʮƸʽ SHA256 Ӵֵ +function SHA256Print(const Digest: TCnSHA256Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA256Digest)); +end; + +// ʮƸʽ SHA384 Ӵֵ +function SHA384Print(const Digest: TCnSHA384Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA384Digest)); +end; + +// ʮƸʽ SHA512 Ӵֵ +function SHA512Print(const Digest: TCnSHA512Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA512Digest)); +end; + +// ʮƸʽ SHA512_224 Ӵֵ +function SHA512_224Print(const Digest: TCnSHA512_224Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA512_224Digest)); +end; + +// ʮƸʽ SHA512_256 Ӵֵ +function SHA512_256Print(const Digest: TCnSHA512_256Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA512_256Digest)); +end; + +// Ƚ SHA224 ӴֵǷ +function SHA224Match(const D1, D2: TCnSHA224Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 28) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// Ƚ SHA256 ӴֵǷ +function SHA256Match(const D1, D2: TCnSHA256Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 32) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// Ƚ SHA384 ӴֵǷ +function SHA384Match(const D1, D2: TCnSHA384Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 48) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// Ƚ SHA512 ӴֵǷ +function SHA512Match(const D1, D2: TCnSHA512Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 64) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// Ƚ SHA512_224 ӴֵǷ +function SHA512_224Match(const D1, D2: TCnSHA512_224Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 28) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// Ƚ SHA512_256 ӴֵǷ +function SHA512_256Match(const D1, D2: TCnSHA512_256Digest): Boolean; +var + I: Integer; +begin + I := 0; + Result := True; + while Result and (I < 32) do + begin + Result := D1[I] = D2[I]; + Inc(I); + end; +end; + +// SHA224 Ӵֵת string +function SHA224DigestToStr(const Digest: TCnSHA224Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA224Digest)); +end; + +// SHA256 Ӵֵת string +function SHA256DigestToStr(const Digest: TCnSHA256Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA256Digest)); +end; + +// SHA384 Ӵֵת string +function SHA384DigestToStr(const Digest: TCnSHA384Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA384Digest)); +end; + +// SHA512 Ӵֵת string +function SHA512DigestToStr(const Digest: TCnSHA512Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA512Digest)); +end; + +// SHA512_224 Ӵֵת string +function SHA512_224DigestToStr(const Digest: TCnSHA512_224Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA512_224Digest)); +end; + +// SHA512_256 Ӵֵת string +function SHA512_256DigestToStr(const Digest: TCnSHA512_256Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA512_256Digest)); +end; + +procedure SHA224HmacInit(var Context: TCnSHA224Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA224Digest; +begin + if KeyLength > HMAC_SHA2_224_256_BLOCK_SIZE_BYTE then + begin + Sum := SHA224Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA2_224_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA2_224_256_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA2_224_256_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA224Init(Context); + SHA224Update(Context, @(Context.Ipad[0]), HMAC_SHA2_224_256_BLOCK_SIZE_BYTE); +end; + +procedure SHA224HmacUpdate(var Context: TCnSHA224Context; Input: PAnsiChar; Length: + Cardinal); +begin + SHA224Update(Context, Input, Length); +end; + +procedure SHA224HmacFinal(var Context: TCnSHA224Context; var Output: TCnSHA224Digest); +var + Len: Integer; + TmpBuf: TCnSHA224Digest; +begin + Len := HMAC_SHA2_224_OUTPUT_LENGTH_BYTE; + SHA224Final(Context, TmpBuf); + SHA224Init(Context); + SHA224Update(Context, @(Context.Opad[0]), HMAC_SHA2_224_256_BLOCK_SIZE_BYTE); + SHA224Update(Context, @(TmpBuf[0]), Len); + SHA224Final(Context, Output); +end; + +procedure SHA256HmacInit(var Context: TCnSHA256Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA256Digest; +begin + if KeyLength > HMAC_SHA2_224_256_BLOCK_SIZE_BYTE then + begin + Sum := SHA256Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA2_256_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA2_224_256_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA2_224_256_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA256Init(Context); + SHA256Update(Context, @(Context.Ipad[0]), HMAC_SHA2_224_256_BLOCK_SIZE_BYTE); +end; + +procedure SHA256HmacUpdate(var Context: TCnSHA256Context; Input: PAnsiChar; Length: + Cardinal); +begin + SHA256Update(Context, Input, Length); +end; + +procedure SHA256HmacFinal(var Context: TCnSHA256Context; var Output: TCnSHA256Digest); +var + Len: Integer; + TmpBuf: TCnSHA256Digest; +begin + Len := HMAC_SHA2_256_OUTPUT_LENGTH_BYTE; + SHA256Final(Context, TmpBuf); + SHA256Init(Context); + SHA256Update(Context, @(Context.Opad[0]), HMAC_SHA2_224_256_BLOCK_SIZE_BYTE); + SHA256Update(Context, @(TmpBuf[0]), Len); + SHA256Final(Context, Output); +end; + +procedure SHA224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA224Digest); +var + Context: TCnSHA224Context; +begin + SHA224HmacInit(Context, Key, KeyByteLength); + SHA224HmacUpdate(Context, Input, ByteLength); + SHA224HmacFinal(Context, Output); +end; + +function SHA224HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA224Digest; +var + Context: TCnSHA224Context; +begin + SHA224HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA224HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA224HmacFinal(Context, Result); +end; + +procedure SHA256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA256Digest); +var + Context: TCnSHA256Context; +begin + SHA256HmacInit(Context, Key, KeyByteLength); + SHA256HmacUpdate(Context, Input, ByteLength); + SHA256HmacFinal(Context, Output); +end; + +function SHA256HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA256Digest; +var + Context: TCnSHA256Context; +begin + SHA256HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA256HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA256HmacFinal(Context, Result); +end; + +procedure SHA384HmacInit(var Context: TCnSHA384Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA384Digest; +begin + if KeyLength > HMAC_SHA2_384_512_BLOCK_SIZE_BYTE then + begin + Sum := SHA384Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA2_384_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA384Init(Context); + SHA384Update(Context, @(Context.Ipad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); +end; + +procedure SHA384HmacUpdate(var Context: TCnSHA384Context; Input: PAnsiChar; + Length: Cardinal); +begin + SHA384Update(Context, Input, Length); +end; + +procedure SHA384HmacFinal(var Context: TCnSHA384Context; var Output: TCnSHA384Digest); +var + Len: Integer; + TmpBuf: TCnSHA384Digest; +begin + Len := HMAC_SHA2_384_OUTPUT_LENGTH_BYTE; + SHA384Final(Context, TmpBuf); + SHA384Init(Context); + SHA384Update(Context, @(Context.Opad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); + SHA384Update(Context, @(TmpBuf[0]), Len); + SHA384Final(Context, Output); +end; + +procedure SHA384Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA384Digest); +var + Context: TCnSHA384Context; +begin + SHA384HmacInit(Context, Key, KeyByteLength); + SHA384HmacUpdate(Context, Input, ByteLength); + SHA384HmacFinal(Context, Output); +end; + +function SHA384HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA384Digest; +var + Context: TCnSHA384Context; +begin + SHA384HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA384HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA384HmacFinal(Context, Result); +end; + +procedure SHA512HmacInit(var Context: TCnSHA512Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA512Digest; +begin + if KeyLength > HMAC_SHA2_384_512_BLOCK_SIZE_BYTE then + begin + Sum := SHA512Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA2_512_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA512Init(Context); + SHA512Update(Context, @(Context.Ipad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); +end; + +procedure SHA512HmacUpdate(var Context: TCnSHA512Context; Input: PAnsiChar; + Length: Cardinal); +begin + SHA512Update(Context, Input, Length); +end; + +procedure SHA512HmacFinal(var Context: TCnSHA512Context; var Output: TCnSHA512Digest); +var + Len: Integer; + TmpBuf: TCnSHA512Digest; +begin + Len := HMAC_SHA2_512_OUTPUT_LENGTH_BYTE; + SHA512Final(Context, TmpBuf); + SHA512Init(Context); + SHA512Update(Context, @(Context.Opad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); + SHA512Update(Context, @(TmpBuf[0]), Len); + SHA512Final(Context, Output); +end; + +procedure SHA512Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA512Digest); +var + Context: TCnSHA512Context; +begin + SHA512HmacInit(Context, Key, KeyByteLength); + SHA512HmacUpdate(Context, Input, ByteLength); + SHA512HmacFinal(Context, Output); +end; + +function SHA512HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA512Digest; +var + Context: TCnSHA512Context; +begin + SHA512HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA512HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA512HmacFinal(Context, Result); +end; + +procedure SHA512_224HmacInit(var Context: TCnSHA512_224Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA512_224Digest; +begin + if KeyLength > HMAC_SHA2_384_512_BLOCK_SIZE_BYTE then + begin + Sum := SHA512_224Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA2_512_224_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA512_224Init(Context); + SHA512_224Update(Context, @(Context.Ipad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); +end; + +procedure SHA512_224HmacUpdate(var Context: TCnSHA512_224Context; Input: PAnsiChar; + Length: Cardinal); +begin + SHA512_224Update(Context, Input, Length); +end; + +procedure SHA512_224HmacFinal(var Context: TCnSHA512_224Context; var Output: TCnSHA512_224Digest); +var + Len: Integer; + TmpBuf: TCnSHA512_224Digest; +begin + Len := HMAC_SHA2_512_224_OUTPUT_LENGTH_BYTE; + SHA512_224Final(Context, TmpBuf); + SHA512_224Init(Context); + SHA512_224Update(Context, @(Context.Opad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); + SHA512_224Update(Context, @(TmpBuf[0]), Len); + SHA512_224Final(Context, Output); +end; + +procedure SHA512_224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA512_224Digest); +var + Context: TCnSHA512_224Context; +begin + SHA512_224HmacInit(Context, Key, KeyByteLength); + SHA512_224HmacUpdate(Context, Input, ByteLength); + SHA512_224HmacFinal(Context, Output); +end; + +function SHA512_224HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA512_224Digest; +var + Context: TCnSHA512_224Context; +begin + SHA512_224HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA512_224HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA512_224HmacFinal(Context, Result); +end; + +procedure SHA512_256HmacInit(var Context: TCnSHA512_256Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA512_256Digest; +begin + if KeyLength > HMAC_SHA2_384_512_BLOCK_SIZE_BYTE then + begin + Sum := SHA512_256Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA2_512_256_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA2_384_512_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA512_256Init(Context); + SHA512_256Update(Context, @(Context.Ipad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); +end; + +procedure SHA512_256HmacUpdate(var Context: TCnSHA512_256Context; Input: PAnsiChar; + Length: Cardinal); +begin + SHA512_256Update(Context, Input, Length); +end; + +procedure SHA512_256HmacFinal(var Context: TCnSHA512_256Context; var Output: TCnSHA512_256Digest); +var + Len: Integer; + TmpBuf: TCnSHA512_256Digest; +begin + Len := HMAC_SHA2_512_256_OUTPUT_LENGTH_BYTE; + SHA512_256Final(Context, TmpBuf); + SHA512_256Init(Context); + SHA512_256Update(Context, @(Context.Opad[0]), HMAC_SHA2_384_512_BLOCK_SIZE_BYTE); + SHA512_256Update(Context, @(TmpBuf[0]), Len); + SHA512_256Final(Context, Output); +end; + +procedure SHA512_256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA512_256Digest); +var + Context: TCnSHA512_256Context; +begin + SHA512_256HmacInit(Context, Key, KeyByteLength); + SHA512_256HmacUpdate(Context, Input, ByteLength); + SHA512_256HmacFinal(Context, Output); +end; + +function SHA512_256HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA512_256Digest; +var + Context: TCnSHA512_256Context; +begin + SHA512_256HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA512_256HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA512_256HmacFinal(Context, Result); +end; + +end. diff --git a/CnPack/Crypto/CnSHA3.pas b/CnPack/Crypto/CnSHA3.pas new file mode 100644 index 0000000..1f8500d --- /dev/null +++ b/CnPack/Crypto/CnSHA3.pas @@ -0,0 +1,2917 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnSHA3; +{* |
+================================================================================ +* ƣ +* ԪƣSHA3 Ӵ㷨ʵֵԪ +* ԪߣCnPack (master@cnpack.org) +* / Keccak C Pascal ֲ䲿ֹܡ +* עԪʵ SHA3 ϵӴ㷨Ӧ HMAC 㷨 SHA3-224/256/384/512 +* ɱ䳤ժҪ SHAKE128/SHAKE256ȡ +* +* SHA3 淶 NIST.FIPS.202 +* SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions +* жⶨ Bit Byte ת +* ֮ Bit ܹ 8 ʱÿ 8 Bit λþһֽڣֽڼ˳ֲ䡣 +* +* ƽ̨PWinXP + Delphi 5.0 +* ݲԣPWinXP/7 + Delphi 5/6 +* õԪеַϱػʽ +* ļ¼2025.11.06 V1.5 +* SHAKE128/SHAKE256 Absorb/Squeeze ƣժҪ +* 2023.08.02 V1.4 +* SHAKE128/SHAKE256 Ŀɱ䳤ժҪļ +* 2022.04.26 V1.3 +* LongWord Integer ַת֧ MacOS64 +* 2019.12.12 V1.2 +* ֧ TBytes +* 2019.04.15 V1.1 +* ֧ Win32/Win64/MacOS +* 2017.11.10 V1.0 +* Ԫ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + SysUtils, Classes {$IFDEF MSWINDOWS}, Windows {$ENDIF}, CnNative, CnConsts; + +const + CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH = 32; + {* SHAKE128 ĬӴսֽڳ} + + CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH = 64; + {* SHAKE256 ĬӴսֽڳ} + +type + PCnSHA3GeneralDigest = ^TCnSHA3GeneralDigest; + {* SHA3 ϵͨõӴսָ} + TCnSHA3GeneralDigest = array[0..63] of Byte; + {* SHA3 ϵͨõӴս 64 ֽΪ} + + PCnSHA3_224Digest = ^TCnSHA3_224Digest; + {* SHA3_224 Ӵսָ} + TCnSHA3_224Digest = array[0..27] of Byte; + {* SHA3_224 Ӵս28 ֽ} + + PCnSHA3_256Digest = ^TCnSHA3_256Digest; + {* SHA3_256 Ӵսָ} + TCnSHA3_256Digest = array[0..31] of Byte; + {* SHA3_256 Ӵս32 ֽ} + + PCnSHA3_384Digest = ^TCnSHA3_384Digest; + {* SHA3_384 Ӵսָ} + TCnSHA3_384Digest = array[0..47] of Byte; + {* SHA3_384 Ӵս48 ֽ} + + PCnSHA3_512Digest = ^TCnSHA3_512Digest; + {* SHA3_512 Ӵսָ} + TCnSHA3_512Digest = array[0..63] of Byte; + {* SHA3_512 Ӵս64 ֽ} + + TCnSHA3Context = packed record + {* SHA3 ϵͨõĽṹ} + State: array[0..24] of Int64; + Index: Cardinal; + DigestLen: Cardinal; + Round: Cardinal; + BlockLen: Cardinal; + Squeezed: Cardinal; + SqueezeCount: Cardinal; + Block: array[0..255] of Byte; + Ipad: array[0..143] of Byte; {!< HMAC: inner padding } + Opad: array[0..143] of Byte; {!< HMAC: outer padding } + end; + + TCnSHA3CalcProgressFunc = procedure(ATotal, AProgress: Int64; var Cancel: + Boolean) of object; + {* SHA3 ϵͨõļȻص¼} + +function SHA3_224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_224Digest; +{* ݿ SHA3_224 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_256Digest; +{* ݿ SHA3_256 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_384Digest; +{* ݿ SHA3_384 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_512Digest; +{* ݿ SHA3_512 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHA3_224Buffer(const Buffer; Count: Cardinal): TCnSHA3_224Digest; +{* ݿ SHA3_224 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256Buffer(const Buffer; Count: Cardinal): TCnSHA3_256Digest; +{* ݿ SHA3_256 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384Buffer(const Buffer; Count: Cardinal): TCnSHA3_384Digest; +{* ݿ SHA3_384 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512Buffer(const Buffer; Count: Cardinal): TCnSHA3_512Digest; +{* ݿ SHA3_512 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128Buffer(const Buffer; Count: Cardinal; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* ݿӴճȿɱ SHAKE128 㣬سΪ DigestByteLength ֽΪӴս + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256Buffer(const Buffer; Count: Cardinal; + DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* ݿӴճȿɱ SHAKE128 㣬سΪ DigestByteLength ֽΪӴս + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +function SHA3_224Bytes(const Data: TBytes): TCnSHA3_224Digest; +{* ֽ SHA3_224 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256Bytes(const Data: TBytes): TCnSHA3_256Digest; +{* ֽ SHA3_256 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384Bytes(const Data: TBytes): TCnSHA3_384Digest; +{* ֽ SHA3_384 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512Bytes(const Data: TBytes): TCnSHA3_512Digest; +{* ֽ SHA3_512 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128Bytes(const Data: TBytes; DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* ֽӴճȿɱ SHAKE128 㣬سΪ DigestByteLength ֽΪӴս + + + const Data: TBytes - ֽ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256Bytes(const Data: TBytes; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* ֽӴճȿɱ SHAKE256 㣬سΪ DigestByteLength ֽΪӴս + + + const Data: TBytes - ֽ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +function SHA3_224String(const Str: string): TCnSHA3_224Digest; +{* String ݽ SHA3_224 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256String(const Str: string): TCnSHA3_256Digest; +{* String ݽ SHA3_256 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384String(const Str: string): TCnSHA3_384Digest; +{* String ݽ SHA3_384 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512String(const Str: string): TCnSHA3_512Digest; +{* String ݽ SHA3_512 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128String(const Str: string; DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* String ݽӴճȿɱ SHAKE128 㣬سΪ DigestByteLength ֽΪӴս + ע D2009 ϰ汾 string Ϊ UnicodeStringлὫǿת AnsiString м㡣 + + + const Str: string - ַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256String(const Str: string; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* String ݽӴճȿɱ SHAKE256 㣬سΪ DigestByteLength ֽΪӴս + ע D2009 ϰ汾 string Ϊ UnicodeStringлὫǿת AnsiString м㡣 + + + const Str: string - ַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +function SHA3_224StringA(const Str: AnsiString): TCnSHA3_224Digest; +{* AnsiString ݽ SHA3_224 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_224StringW(const Str: WideString): TCnSHA3_224Digest; +{* WideString ݽ SHA3_224 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256StringA(const Str: AnsiString): TCnSHA3_256Digest; +{* AnsiString ݽ SHA3_256 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_256StringW(const Str: WideString): TCnSHA3_256Digest; +{* WideStringݽ SHA3_256 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384StringA(const Str: AnsiString): TCnSHA3_384Digest; +{* AnsiString ݽ SHA3_384 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_384StringW(const Str: WideString): TCnSHA3_384Digest; +{* WideString ݽ SHA3_384 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512StringA(const Str: AnsiString): TCnSHA3_512Digest; +{* AnsiString ݽ SHA3_512 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHA3_512StringW(const Str: WideString): TCnSHA3_512Digest; +{* WideString ݽ SHA512 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128StringA(const Str: AnsiString; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* AnsiString ݽӴճȿɱֱ SHAKE128 㣬 + سΪ DigestByteLength ֽΪӴս + + + const Str: AnsiString - ַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE128StringW(const Str: WideString; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* WideString ݽӴճȿɱֱ SHAKE128 㣬 + سΪ DigestByteLength ֽΪӴս + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256StringA(const Str: AnsiString; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* AnsiString ݽӴճȿɱֱ SHAKE128 㣬 + سΪ DigestByteLength ֽΪӴս + + + const Str: AnsiString - ַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +function SHAKE256StringW(const Str: WideString; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* WideString ݽӴճȿɱֱ SHAKE256 㣬 + سΪ DigestByteLength ֽΪӴս + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +{$IFDEF UNICODE} + +function SHA3_224UnicodeString(const Str: string): TCnSHA3_224Digest; +{* UnicodeString ݽֱӵ SHA3_224 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256UnicodeString(const Str: string): TCnSHA3_256Digest; +{* UnicodeString ݽֱӵ SHA3_256 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384UnicodeString(const Str: string): TCnSHA3_384Digest; +{* UnicodeString ݽֱӵ SHA3_384 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512UnicodeString(const Str: string): TCnSHA3_512Digest; +{* UnicodeString ݽֱӵ SHA3_512 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128UnicodeString(const Str: string; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* UnicodeString ݽӴճȿɱֱ SHAKE128 㣬ֱӼڲ UTF16 ݣת + سΪ DigestByteLength ֽΪӴս + + + const Str: string - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256UnicodeString(const Str: string; + DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* UnicodeString ݽӴճȿɱֱ SHAKE256 㣬ֱӼڲ UTF16 ݣת + سΪ DigestByteLength ֽΪӴս + + + const Str: string - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +{$ELSE} + +function SHA3_224UnicodeString(const Str: WideString): TCnSHA3_224Digest; +{* UnicodeString ݽֱӵ SHA3_224 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256UnicodeString(const Str: WideString): TCnSHA3_256Digest; +{* UnicodeString ݽֱӵ SHA3_256 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384UnicodeString(const Str: WideString): TCnSHA3_384Digest; +{* UnicodeString ݽֱӵ SHA3_384 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512UnicodeString(const Str: WideString): TCnSHA3_512Digest; +{* UnicodeString ݽֱӵ SHA3_512 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128UnicodeString(const Str: WideString; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* UnicodeString ݽӴճȿɱֱ SHAKE128 㣬ֱӼڲ UTF16 ݣת + سΪ DigestByteLength ֽΪӴս + + + const Str: WideString - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256UnicodeString(const Str: WideString; + DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH): TBytes; +{* UnicodeString ݽӴճȿɱֱ SHAKE256 㣬ֱӼڲ UTF16 ݣת + سΪ DigestByteLength ֽΪӴս + + + const Str: WideString - Ŀַ + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵTBytes - SHAKE256 Ӵֵ +} + +{$ENDIF} + +function SHA3_224File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc = + nil): TCnSHA3_224Digest; +{* ָļݽ SHA3_224 㡣 + + + const FileName: string - ļ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_224Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc = nil): + TCnSHA3_224Digest; +{* ָݽ SHA3_224 㡣 + + + Stream: TStream - + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc = + nil): TCnSHA3_256Digest; +{* ָļݽ SHA3_256 㡣 + + + const FileName: string - ļ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_256Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc = nil): + TCnSHA3_256Digest; +{* ָݽ SHA3_256 㡣 + + + Stream: TStream - + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc = + nil): TCnSHA3_384Digest; +{* ָļݽ SHA3_384 㡣 + + + const FileName: string - ļ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_384Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc = nil): + TCnSHA3_384Digest; +{* ָݽ SHA3_384 㡣 + + + Stream: TStream - + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc = + nil): TCnSHA3_512Digest; +{* ָļݽ SHA3_512 㡣 + + + const FileName: string - ļ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHA3_512Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc = nil): + TCnSHA3_512Digest; +{* ָݽ SHA3_512 㡣 + + + Stream: TStream - + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +function SHAKE128File(const FileName: string; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH; + CallBack: TCnSHA3CalcProgressFunc = nil): TBytes; +{* ָļݽӴճȿɱ SHAKE128 㣬 + سΪ DigestByteLength ֽΪӴս + + + const FileName: string - ļ + DigestByteLength: Cardinal - Ӵսֽڳ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTBytes - SHAKE128Ӵֵ +} + +function SHAKE128Stream(Stream: TStream; + DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH; + CallBack: TCnSHA3CalcProgressFunc = nil): TBytes; +{* ָӴճȿɱ SHAKE128 㣬 + سΪ DigestByteLength ֽΪӴս + + + Stream: TStream - + DigestByteLength: Cardinal - Ӵսֽڳ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTBytes - SHAKE128 Ӵֵ +} + +function SHAKE256File(const FileName: string; + DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH; + CallBack: TCnSHA3CalcProgressFunc = nil): TBytes; +{* ָļݽӴճȿɱ SHAKE256 㣬 + سΪ DigestByteLength ֽΪӴս + + + const FileName: string - ļ + DigestByteLength: Cardinal - Ӵսֽڳ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTBytes - SHAKE256 Ӵֵ +} + +function SHAKE256Stream(Stream: TStream; + DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH; + CallBack: TCnSHA3CalcProgressFunc = nil): TBytes; +{* ָӴճȿɱ SHAKE256 㣬 + سΪ DigestByteLength ֽΪӴս + + + Stream: TStream - + DigestByteLength: Cardinal - Ӵսֽڳ + CallBack: TCnSHA3CalcProgressFunc - ȻصĬΪ + + ֵTBytes - SHAKE256 Ӵֵ +} + +// ⲿݽɢ SHA3_224 㣬SHA3_224Update ɶα + +procedure SHA3_224Init(var Context: TCnSHA3Context); +{* ʼһ SHA3_224 ģ SHA3_224 + + + var Context: TCnSHA3Context - ʼͨ SHA3 + + ֵޣ +} + +procedure SHA3_224Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA3_224 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA3_224Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_224Digest); +{* ּ㣬 SHA3_224 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + var Digest: TCnSHA3_224Digest - ص SHA3_224 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA3_256 㣬SHA3_256Update ɶα + +procedure SHA3_256Init(var Context: TCnSHA3Context); +{* ʼһ SHA3_256 ģ SHA3_256 + + + var Context: TCnSHA3Context - ʼͨ SHA3 + + ֵޣ +} + +procedure SHA3_256Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA3_256 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA3_256Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_256Digest); +{* ּ㣬 SHA3_256 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + var Digest: TCnSHA3_256Digest - ص SHA3_256 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA3_384 㣬SHA3_384Update ɶα + +procedure SHA3_384Init(var Context: TCnSHA3Context); +{* ʼһ SHA3_384 ģ SHA3_384 + + + var Context: TCnSHA3Context - ʼͨ SHA3 + + ֵޣ +} + +procedure SHA3_384Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA3_384 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA3_384Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_384Digest); +{* ּ㣬 SHA3_384 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + var Digest: TCnSHA3_384Digest - ص SHA3_384 Ӵֵ + + ֵޣ +} + +// ⲿݽɢ SHA3_512 㣬SHA3_512Update ɶα + +procedure SHA3_512Init(var Context: TCnSHA3Context); +{* ʼһ SHA3_512 ģ SHA3_512 + + + var Context: TCnSHA3Context - ʼͨ SHA3 + + ֵޣ +} + +procedure SHA3_512Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHA3_512 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHA3_512Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_512Digest); +{* ּ㣬 SHA3_512 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + var Digest: TCnSHA3_512Digest - ص SHA3_512 Ӵֵ + + ֵޣ +} + +// ¼ⲿݽɢ SHAKE128 㣬SHAKE128Update ɶα + +procedure SHAKE128Init(var Context: TCnSHA3Context; DigestByteLength: Cardinal = CN_SHAKE128_DEF_DIGEST_BYTE_LENGTH); +{* ʼһ SHAKE128 ģ SHAKE128 + DigestByteLength ΪӴյֽڳȡ + + + var Context: TCnSHA3Context - ʼͨ SHA3 + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵޣ +} + +procedure SHAKE128Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHAKE128 㣬ͬ SHAKE128Absorb + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHAKE128Absorb(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHAKE128 㣬ͬ SHAKE128Update + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHAKE128Final(var Context: TCnSHA3Context; out Digest: TBytes); +{* ּ㣬 SHAKE128 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + out Digest: TBytes - ص SHAKE128 Ӵֵ + + ֵޣ +} + +function SHAKE128Squeeze(var Context: TCnSHA3Context; DigestByteLength: Integer): TBytes; +{* ּ㣬 SHAKE128 DigestByteLength ֽڳݣ + ɼ Squeeze Absorb ˡ + + + var Context: TCnSHA3Context - ͨ SHA3 + DigestByteLength: Integer - Ҫص SHAKE128 Ӵֽڳ + + ֵTBytes - ص SHAKE128 Ӵֵ +} + +// ¼ⲿݽɢ SHAKE128 㣬SHAKE128Update ɶα + +procedure SHAKE256Init(var Context: TCnSHA3Context; DigestByteLength: Cardinal = CN_SHAKE256_DEF_DIGEST_BYTE_LENGTH); +{* ʼһ SHAKE256 ģ SHAKE256 + DigestByteLength ΪӴյֽڳȡ + + + var Context: TCnSHA3Context - ʼͨ SHA3 + DigestByteLength: Cardinal - Ӵսֽڳ + + ֵޣ +} + +procedure SHAKE256Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHAKE256 㣬ͬ SHAKE256Absorb + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHAKE256Absorb(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SHAKE256 㣬ͬ SHAKE256Update + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSHA3Context - ͨ SHA3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SHAKE256Final(var Context: TCnSHA3Context; out Digest: TBytes); +{* ּ㣬 SHAKE256 Digest С + + + var Context: TCnSHA3Context - ͨ SHA3 + out Digest: TBytes - ص SHAKE256 Ӵֵ + + ֵޣ +} + +function SHAKE256Squeeze(var Context: TCnSHA3Context; DigestByteLength: Integer): TBytes; +{* ּ㣬 SHAKE256 DigestByteLength ֽڳݣ + ɼ Squeeze Absorb ˡ + + + var Context: TCnSHA3Context - ͨ SHA3 + DigestByteLength: Integer - Ҫص SHAKE256 Ӵֽڳ + + ֵTBytes - ص SHAKE256 Ӵֵ +} + +function SHA3_224Print(const Digest: TCnSHA3_224Digest): string; +{* ʮƸʽ SHA3_224 Ӵֵ + + + const Digest: TCnSHA3_224Digest - ָ SHA3_224 Ӵֵ + + ֵstring - ʮַ +} + +function SHA3_256Print(const Digest: TCnSHA3_256Digest): string; +{* ʮƸʽ SHA3_256 Ӵֵ + + + const Digest: TCnSHA3_256Digest - ָ SHA3_256 Ӵֵ + + ֵstring - ʮַ +} + +function SHA3_384Print(const Digest: TCnSHA3_384Digest): string; +{* ʮƸʽ SHA3_384 Ӵֵ + + const Digest: TCnSHA3_384Digest - ָ SHA3_384 Ӵֵ + + ֵstring - ʮַ +} + +function SHA3_512Print(const Digest: TCnSHA3_512Digest): string; +{* ʮƸʽ SHA3_512 Ӵֵ + + + const Digest: TCnSHA3_512Digest - ָ SHA3_512 Ӵֵ + + ֵstring - ʮַ +} + +function SHAKE128Print(const Digest: TBytes): string; +{* ʮƸʽ SHAKE128 Ӵֵ + + + const Digest: TBytes - ָ SHAKE128 Ӵֵ + + ֵstring - ʮַ +} + +function SHAKE256Print(const Digest: TBytes): string; +{* ʮƸʽ SHAKE256 Ӵֵ + + + const Digest: TBytes - ָ SHAKE128 Ӵֵ + + ֵstring - ʮַ +} + +function SHA3_224Match(const D1: TCnSHA3_224Digest; const D2: TCnSHA3_224Digest): Boolean; +{* Ƚ SHA3_224 ӴֵǷȡ + + + const D1: TCnSHA3_224Digest - Ƚϵ SHA3_224 Ӵֵһ + const D2: TCnSHA3_224Digest - Ƚϵ SHA3_224 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA3_256Match(const D1: TCnSHA3_256Digest; const D2: TCnSHA3_256Digest): Boolean; +{* Ƚ SHA3_256 ӴֵǷȡ + + + const D1: TCnSHA3_256Digest - Ƚϵ SHA3_256 Ӵֵһ + const D2: TCnSHA3_256Digest - Ƚϵ SHA3_256 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA3_384Match(const D1: TCnSHA3_384Digest; const D2: TCnSHA3_384Digest): Boolean; +{* Ƚ SHA3_384 ӴֵǷȡ + + + const D1: TCnSHA3_384Digest - Ƚϵ SHA3_384 Ӵֵһ + const D2: TCnSHA3_384Digest - Ƚϵ SHA3_384 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA3_512Match(const D1: TCnSHA3_512Digest; const D2: TCnSHA3_512Digest): Boolean; +{* Ƚ SHA3_512 ӴֵǷȡ + + + const D1: TCnSHA3_512Digest - Ƚϵ SHA3_512 Ӵֵһ + const D2: TCnSHA3_512Digest - Ƚϵ SHA3_512 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHAKE128Match(const D1: TBytes; const D2: TBytes): Boolean; +{* Ƚ SHAKE128 ӴֵǷȡ + + + const D1: TBytes - Ƚϵ SHAKE128 Ӵֵһ + const D2: TBytes - Ƚϵ SHAKE128 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHAKE256Match(const D1: TBytes; const D2: TBytes): Boolean; +{* Ƚ SHAKE256 ӴֵǷȡ + + + const D1: TBytes - Ƚϵ SHAKE256 Ӵֵһ + const D2: TBytes - Ƚϵ SHAKE256 Ӵֵ + + ֵBoolean - Ƿ +} + +function SHA3_224DigestToStr(const Digest: TCnSHA3_224Digest): string; +{* SHA3_224 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA3_224Digest - ת SHA3_224 Ӵֵ + + ֵstring - صַ +} + +function SHA3_256DigestToStr(const Digest: TCnSHA3_256Digest): string; +{* SHA3_256 Ӵֱֵת stringÿֽڶӦһַ + |
+ Digest: TSHA3_256Digest - Ҫ + |+ + + const Digest: TCnSHA3_256Digest - ת SHA3_256 Ӵֵ + + ֵstring - صַ +} + +function SHA3_384DigestToStr(const Digest: TCnSHA3_384Digest): string; +{* SHA3_384 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA3_384Digest - ת SHA3_384 Ӵֵ + + ֵstring - صַ +} + +function SHA3_512DigestToStr(const Digest: TCnSHA3_512Digest): string; +{* SHA3_512 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSHA3_512Digest - ת SHA3_512 Ӵֵ + + ֵstring - صַ +} + +function SHAKE128DigestToStr(const Digest: TBytes): string; +{* SHAKE128 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TBytes - ת SHAKE128 Ӵֵ + + ֵstring - صַ +} + +function SHAKE256DigestToStr(const Digest: TBytes): string; +{* SHAKE256 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TBytes - ת SHAKE256 Ӵֵ + + ֵstring - صַ +} + +procedure SHA3_224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_224Digest); +{* SHA3_224 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA3_224 Կݿַ + KeyByteLength: Integer - SHA3_224 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA3_224Digest - ص SHA3_224 Ӵֵ + + ֵޣ +} + +procedure SHA3_256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_256Digest); +{* SHA3_256 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA3_256 Կݿַ + KeyByteLength: Integer - SHA3_256 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA3_256Digest - ص SHA3_256 Ӵֵ + + ֵޣ +} + +procedure SHA3_384Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_384Digest); +{* SHA3_384 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA3_384 Կݿַ + KeyByteLength: Integer - SHA3_384 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA3_384Digest - ص SHA3_384 Ӵֵ + + ֵޣ +} + +procedure SHA3_512Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_512Digest); +{* SHA3_512 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SHA3_512 Կݿַ + KeyByteLength: Integer - SHA3_512 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSHA3_512Digest - ص SHA3_512 Ӵֵ + + ֵޣ +} + +function SHA3_224HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA3_224Digest; +{* ֽл SHA3_224 HMAC 㡣 + + + const Key: TBytes - SHA3_224 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA3_224Digest - ص SHA3_224 Ӵֵ +} + +function SHA3_256HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA3_256Digest; +{* ֽл SHA3_256 HMAC 㡣 + + + const Key: TBytes - SHA3_256 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA3_256Digest - ص SHA3_256 Ӵֵ +} + +function SHA3_384HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA3_384Digest; +{* ֽл SHA3_384 HMAC 㡣 + + + const Key: TBytes - SHA3_384 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA3_384Digest - ص SHA3_384 Ӵֵ +} + +function SHA3_512HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA3_512Digest; +{* ֽл SHA3_512 HMAC 㡣 + + + const Key: TBytes - SHA3_512 Կֽ + const Data: TBytes - ֽ + + ֵTCnSHA3_512Digest - ص SHA3_512 Ӵֵ +} + +implementation + +type + TSHA3Type = (stSHA3_224, stSHA3_256, stSHA3_384, stSHA3_512, stSHAKE128, stSHAKE256); + +const + MAX_FILE_SIZE = 512 * 1024 * 1024; + STREAM_BUF_SIZE = 4096 * 1024; + // If file size <= this size (bytes), using Mapping, else stream + + SHA3_ROUNDS = 24; + SHA3_STATE_LEN = 25; + + SHA3_224_OUTPUT_LENGTH_BYTE = 28; + SHA3_256_OUTPUT_LENGTH_BYTE = 32; + SHA3_384_OUTPUT_LENGTH_BYTE = 48; + SHA3_512_OUTPUT_LENGTH_BYTE = 64; + + SHA3_224_BLOCK_SIZE_BYTE = 144; + SHA3_256_BLOCK_SIZE_BYTE = 136; + SHA3_384_BLOCK_SIZE_BYTE = 104; + SHA3_512_BLOCK_SIZE_BYTE = 72; + + SHAKE128_BLOCK_SIZE_BYTE = 168; + SHAKE256_BLOCK_SIZE_BYTE = 136; + + HMAC_SHA3_224_BLOCK_SIZE_BYTE = SHA3_224_BLOCK_SIZE_BYTE; + HMAC_SHA3_256_BLOCK_SIZE_BYTE = SHA3_256_BLOCK_SIZE_BYTE; + HMAC_SHA3_384_BLOCK_SIZE_BYTE = SHA3_384_BLOCK_SIZE_BYTE; + HMAC_SHA3_512_BLOCK_SIZE_BYTE = SHA3_512_BLOCK_SIZE_BYTE; + + HMAC_SHA3_224_OUTPUT_LENGTH_BYTE = SHA3_224_OUTPUT_LENGTH_BYTE; + HMAC_SHA3_256_OUTPUT_LENGTH_BYTE = SHA3_256_OUTPUT_LENGTH_BYTE; + HMAC_SHA3_384_OUTPUT_LENGTH_BYTE = SHA3_384_OUTPUT_LENGTH_BYTE; + HMAC_SHA3_512_OUTPUT_LENGTH_BYTE = SHA3_512_OUTPUT_LENGTH_BYTE; + + KECCAKF_ROUND_CONSTS: array[0..23] of TUInt64 = ( + $0000000000000001, $0000000000008082, $800000000000808A, + $8000000080008000, $000000000000808B, $0000000080000001, + $8000000080008081, $8000000000008009, $000000000000008A, + $0000000000000088, $0000000080008009, $000000008000000A, + $000000008000808B, $800000000000008B, $8000000000008089, + $8000000000008003, $8000000000008002, $8000000000000080, + $000000000000800A, $800000008000000A, $8000000080008081, + $8000000000008080, $0000000080000001, $8000000080008008 + ); + + KECCAKF_ROT_CONSTS: array[0..23] of Integer = ( + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 + ); + + KECCAKF_PILN: array[0..23] of Integer = ( + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 + ); + +function ROTL64(Q: TUInt64; N: Integer): TUInt64; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (Q shl N) xor (Q shr (64 - N)); +end; + +// һ SHA3 㣬 Block ݣ State +procedure SHA3_Transform(var Context: TCnSHA3Context); +type + PUInt64Array = ^TUInt64Array; + TUInt64Array = array[0..4095] of TUInt64; +var + I, J, R, L: Integer; + P: PUInt64Array; + T: TUInt64; + BC: array[0..4] of TUInt64; +begin + P := PUInt64Array(@(Context.Block[0])); + I := 0; + L := Integer(Context.BlockLen div 8); + while I < L do + begin + Context.State[I] := Context.State[I] xor P^[I]; + Inc(I); + end; + + for R := 0 to Context.Round - 1 do + begin + // Theta + for I := 0 to 4 do + begin + BC[I] := Context.State[I] xor Context.State[I + 5] xor Context.State[I + 10] + xor Context.State[I + 15] xor Context.State[I + 20]; + end; + for I := 0 to 4 do + begin + T := BC[(I + 4) mod 5] xor ROTL64(BC[(I + 1) mod 5], 1); + for J := 0 to 4 do + Context.State[5 * J + I] := Context.State[5 * J + I] xor T; + end; + + // Rho Pi + T := Context.State[1]; + for I := 0 to 23 do + begin + J := KECCAKF_PILN[I]; + BC[0] := Context.State[J]; + Context.State[J] := ROTL64(T, KECCAKF_ROT_CONSTS[I]); + T := BC[0]; + end; + + // Chi + for J := 0 to 4 do + begin + for I := 0 to 4 do + BC[I] := Context.State[5 * J + I]; + + for I := 0 to 4 do + Context.State[5 * J + I] := Context.State[5 * J + I] xor + ((not BC[(I + 1) mod 5]) and BC[(I + 2) mod 5]); + end; + + // Iota + Context.State[0] := Context.State[0] xor KECCAKF_ROUND_CONSTS[R]; + end; +end; + +procedure SHA3Init(var Context: TCnSHA3Context; SHA3Type: TSHA3Type; + DigestByteLength: Cardinal = 0); +begin + FillChar(Context.State, SizeOf(Context.State), 0); + FillChar(Context.Block, SizeOf(Context.Block), 0); + Context.Index := 0; + Context.Squeezed := 0; + Context.SqueezeCount := 0; + Context.Round := SHA3_ROUNDS; + + case SHA3Type of + stSHA3_224: + begin + Context.BlockLen := SHA3_224_BLOCK_SIZE_BYTE; + Context.DigestLen := SHA3_224_OUTPUT_LENGTH_BYTE; + end; + stSHA3_256: + begin + Context.BlockLen := SHA3_256_BLOCK_SIZE_BYTE; + Context.DigestLen := SHA3_256_OUTPUT_LENGTH_BYTE; + end; + stSHA3_384: + begin + Context.BlockLen := SHA3_384_BLOCK_SIZE_BYTE; + Context.DigestLen := SHA3_384_OUTPUT_LENGTH_BYTE; + end; + stSHA3_512: + begin + Context.BlockLen := SHA3_512_BLOCK_SIZE_BYTE; + Context.DigestLen := SHA3_512_OUTPUT_LENGTH_BYTE; + end; + stSHAKE128: + begin + Context.BlockLen := SHAKE128_BLOCK_SIZE_BYTE; + Context.DigestLen := DigestByteLength; + end; + stSHAKE256: + begin + Context.BlockLen := SHAKE256_BLOCK_SIZE_BYTE; + Context.DigestLen := DigestByteLength; + end; + end; +end; + +procedure SHA3Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +var + R, Idx: Cardinal; +begin + Idx := Context.Index; // Index Block еijʼλָ + repeat + if ByteLength < Context.BlockLen - Idx then + R := ByteLength // + else + R := Context.BlockLen - Idx; // ܻʣ + + FillChar(Context.Block[Idx], SizeOf(Context.Block) - Idx, 0); // ȷβΪ 0 + Move(Input^, Context.Block[Idx], R); // Block ǰ벿ֲ + + if (Idx + R) < Context.BlockLen then // ûֲ + begin // ֻ Index λָ + Idx := Idx + R; + Break; + end; + + SHA3_Transform(Context); + Dec(ByteLength, R); + Idx := 0; + Inc(Input, R); + until False; + Context.Index := Idx; +end; + +procedure SHA3UpdateW(var Context: TCnSHA3Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + Content: PAnsiChar; + Len: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(Content, CharLength * SizeOf(WideChar)); + try + Len := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(Content), CharLength * SizeOf(WideChar), nil, nil); + SHA3Update(Context, Content, Len); + finally + FreeMem(Content); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + SHA3Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +// SHA3_224/256/384/512 ר +procedure SHA3Final(var Context: TCnSHA3Context; var Digest: TCnSHA3GeneralDigest); overload; +begin + Context.Block[Context.Index] := 6; + Context.Block[Context.BlockLen - 1] := Context.Block[Context.BlockLen - 1] or $80; + SHA3_Transform(Context); + Move(Context.State[0], Digest[0], Context.DigestLen); +end; + +// SHAKE128 SHAKE256 ר +procedure SHA3Final(var Context: TCnSHA3Context; out Digest: TBytes); overload; +var + Idx, DL: Cardinal; +begin + Context.Block[Context.Index] := $1F; + Context.Block[Context.BlockLen - 1] := Context.Block[Context.BlockLen - 1] or $80; + SHA3_Transform(Context); + + SetLength(Digest, Context.DigestLen); + if Context.DigestLen <= Context.BlockLen then + Move(Context.State[0], Digest[0], Context.DigestLen) + else + begin + DL := Context.DigestLen; + Idx := 0; + + while DL >= Context.BlockLen do + begin + Move(Context.State[0], Digest[Idx], Context.BlockLen); + Inc(Idx, Context.BlockLen); + Dec(DL, Context.BlockLen); + + if DL > 0 then + begin + FillChar(Context.Block[0], SizeOf(Context.Block), 0); + SHA3_Transform(Context); + end; + end; + + if DL > 0 then + Move(Context.State[0], Digest[Idx], DL); + end; +end; + +function SHAKE3Squeeze(var Context: TCnSHA3Context; DigestByteLength: Integer): TBytes; +var + Idx, DL: Cardinal; + BlockLen: Cardinal; + BytesToCopy: Cardinal; +begin + if DigestByteLength <= 0 then + begin + Result := nil; + Exit; + end; + + BlockLen := Context.BlockLen; + + // ǵһν룬 Absorb + if Context.Squeezed = 0 then + begin + Context.Block[Context.Index] := $1F; + Context.Block[Context.BlockLen - 1] := Context.Block[Context.BlockLen - 1] or $80; + SHA3_Transform(Context); + Context.Squeezed := 1; // Ѿս + Context.SqueezeCount := 0; // üѹ + end; + + // ʼ + SetLength(Result, DigestByteLength); + DL := DigestByteLength; + Idx := 0; + + // ӵǰ״̬ȡ + while DL > 0 do + begin + // 㵱ǰʣȡֽ + BytesToCopy := BlockLen - Context.SqueezeCount; + if BytesToCopy > DL then + BytesToCopy := DL; + + // ״̬ȡ + Move(PByteArray(@Context.State[0])[Context.SqueezeCount], Result[Idx], BytesToCopy); + + // ¼ָ + Inc(Context.SqueezeCount, BytesToCopy); + Inc(Idx, BytesToCopy); + Dec(DL, BytesToCopy); + + // ǰ꣬Ҫ任״̬ȡһ + if (DL > 0) and (Context.SqueezeCount >= BlockLen) then + begin + FillChar(Context.Block[0], SizeOf(Context.Block), 0); + SHA3_Transform(Context); + Context.SqueezeCount := 0; // Ϊµ״̬Ŀʼ + end; + end; +end; + +procedure SHA3_224Init(var Context: TCnSHA3Context); +begin + SHA3Init(Context, stSHA3_224); +end; + +procedure SHA3_224Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_224Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_224Digest); +var + Res: TCnSHA3GeneralDigest; +begin + SHA3Final(Context, Res); + Move(Res[0], Digest[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +procedure SHA3_256Init(var Context: TCnSHA3Context); +begin + SHA3Init(Context, stSHA3_256); +end; + +procedure SHA3_256Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_256Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_256Digest); +var + Res: TCnSHA3GeneralDigest; +begin + SHA3Final(Context, Res); + Move(Res[0], Digest[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +procedure SHA3_384Init(var Context: TCnSHA3Context); +begin + SHA3Init(Context, stSHA3_384); +end; + +procedure SHA3_384Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_384Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_384Digest); +var + Res: TCnSHA3GeneralDigest; +begin + SHA3Final(Context, Res); + Move(Res[0], Digest[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +procedure SHA3_512Init(var Context: TCnSHA3Context); +begin + SHA3Init(Context, stSHA3_512); +end; + +procedure SHA3_512Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_512Final(var Context: TCnSHA3Context; var Digest: TCnSHA3_512Digest); +var + Res: TCnSHA3GeneralDigest; +begin + SHA3Final(Context, Res); + Move(Res[0], Digest[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +procedure SHAKE128Init(var Context: TCnSHA3Context; DigestByteLength: Cardinal); +begin + SHA3Init(Context, stSHAKE128, DigestByteLength); +end; + +procedure SHAKE128Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHAKE128Absorb(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHAKE128Final(var Context: TCnSHA3Context; out Digest: TBytes); +begin + SHA3Final(Context, Digest); +end; + +function SHAKE128Squeeze(var Context: TCnSHA3Context; DigestByteLength: Integer): TBytes; +begin + Result := SHAKE3Squeeze(Context, DigestByteLength); +end; + +procedure SHAKE256Init(var Context: TCnSHA3Context; DigestByteLength: Cardinal); +begin + SHA3Init(Context, stSHAKE256, DigestByteLength); +end; + +procedure SHAKE256Update(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHAKE256Absorb(var Context: TCnSHA3Context; Input: PAnsiChar; ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHAKE256Final(var Context: TCnSHA3Context; out Digest: TBytes); +begin + SHA3Final(Context, Digest); +end; + +function SHAKE256Squeeze(var Context: TCnSHA3Context; DigestByteLength: Integer): TBytes; +begin + Result := SHAKE3Squeeze(Context, DigestByteLength); +end; + +// ݿ SHA3_224λ +function SHA3_224(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, Input, ByteLength); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_256λ +function SHA3_256(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, Input, ByteLength); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_384λ +function SHA3_384(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, Input, ByteLength); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_512λ +function SHA3_512(Input: PAnsiChar; ByteLength: Cardinal): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, Input, ByteLength); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_224 +function SHA3_224Buffer(const Buffer; Count: Cardinal): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, PAnsiChar(@Buffer), Count); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_256 +function SHA3_256Buffer(const Buffer; Count: Cardinal): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, PAnsiChar(@Buffer), Count); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_384 +function SHA3_384Buffer(const Buffer; Count: Cardinal): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, PAnsiChar(@Buffer), Count); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHA3_512 +function SHA3_512Buffer(const Buffer; Count: Cardinal): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, PAnsiChar(@Buffer), Count); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// ݿ SHAKE128 +function SHAKE128Buffer(const Buffer; Count: Cardinal; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE128Init(Context, DigestByteLength); + SHAKE128Update(Context, PAnsiChar(@Buffer), Count); + SHAKE128Final(Context, Result); +end; + +// ݿ SHAKE256 +function SHAKE256Buffer(const Buffer; Count: Cardinal; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE256Init(Context, DigestByteLength); + SHAKE256Update(Context, PAnsiChar(@Buffer), Count); + SHAKE256Final(Context, Result); +end; + +// ֽ SHA3_224 +function SHA3_224Bytes(const Data: TBytes): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// ֽ SHA3_256 +function SHA3_256Bytes(const Data: TBytes): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// ֽ SHA3_384 +function SHA3_384Bytes(const Data: TBytes): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// ֽ SHA3_512 +function SHA3_512Bytes(const Data: TBytes): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// ֽ SHAKE128 +function SHAKE128Bytes(const Data: TBytes; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE128Init(Context, DigestByteLength); + SHAKE128Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHAKE128Final(Context, Result); +end; + +// ֽ SHAKE256 +function SHAKE256Bytes(const Data: TBytes; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE256Init(Context, DigestByteLength); + SHAKE256Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SHAKE256Final(Context, Result); +end; + +// String ݽ SHA3_224 +function SHA3_224String(const Str: string): TCnSHA3_224Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA3_224StringA(AStr); +end; + +// String ݽ SHA3_256 +function SHA3_256String(const Str: string): TCnSHA3_256Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA3_256StringA(AStr); +end; + +// String ݽ SHA3_384 +function SHA3_384String(const Str: string): TCnSHA3_384Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA3_384StringA(AStr); +end; + +// String ݽ SHA3_512 +function SHA3_512String(const Str: string): TCnSHA3_512Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHA3_512StringA(AStr); +end; + +// String ݽ SHAKE128 +function SHAKE128String(const Str: string; DigestByteLength: Cardinal): TBytes; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHAKE128StringA(AStr, DigestByteLength); +end; + +// String ݽ SHAKE256 +function SHAKE256String(const Str: string; DigestByteLength: Cardinal): TBytes; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SHAKE256StringA(AStr, DigestByteLength); +end; + +// UnicodeString ݽֱӵ SHA3_224 㣬ת +{$IFDEF UNICODE} +function SHA3_224UnicodeString(const Str: string): TCnSHA3_224Digest; +{$ELSE} +function SHA3_224UnicodeString(const Str: WideString): TCnSHA3_224Digest; +{$ENDIF} +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// UnicodeString ݽֱӵ SHA3_256 㣬ת +{$IFDEF UNICODE} +function SHA3_256UnicodeString(const Str: string): TCnSHA3_256Digest; +{$ELSE} +function SHA3_256UnicodeString(const Str: WideString): TCnSHA3_256Digest; +{$ENDIF} +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// UnicodeString ݽֱӵ SHA3_384 㣬ת +{$IFDEF UNICODE} +function SHA3_384UnicodeString(const Str: string): TCnSHA3_384Digest; +{$ELSE} +function SHA3_384UnicodeString(const Str: WideString): TCnSHA3_384Digest; +{$ENDIF} +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// UnicodeString ݽֱӵ SHA3_512 㣬ת +{$IFDEF UNICODE} +function SHA3_512UnicodeString(const Str: string): TCnSHA3_512Digest; +{$ELSE} +function SHA3_512UnicodeString(const Str: WideString): TCnSHA3_512Digest; +{$ENDIF} +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// UnicodeString ݽֱӵ SHAKE128 㣬ת +{$IFDEF UNICODE} +function SHAKE128UnicodeString(const Str: string; DigestByteLength: Cardinal): TBytes; +{$ELSE} +function SHAKE128UnicodeString(const Str: WideString; DigestByteLength: Cardinal): TBytes; +{$ENDIF} +var + Context: TCnSHA3Context; +begin + SHAKE128Init(Context, DigestByteLength); + SHAKE128Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHAKE128Final(Context, Result); +end; + +// UnicodeString ݽֱӵ SHAKE256 㣬ת +{$IFDEF UNICODE} +function SHAKE256UnicodeString(const Str: string; DigestByteLength: Cardinal): TBytes; +{$ELSE} +function SHAKE256UnicodeString(const Str: WideString; DigestByteLength: Cardinal): TBytes; +{$ENDIF} +var + Context: TCnSHA3Context; +begin + SHAKE256Init(Context, DigestByteLength); + SHAKE256Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SHAKE256Final(Context, Result); +end; + +// AnsiString ݽSHA224 +function SHA3_224StringA(const Str: AnsiString): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, PAnsiChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// WideString ݽ SHA3_224 +function SHA3_224StringW(const Str: WideString): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_224); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_224_OUTPUT_LENGTH_BYTE); +end; + +// AnsiString ݽ SHA3_256 +function SHA3_256StringA(const Str: AnsiString): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, PAnsiChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// WideString ݽ SHA3_256 +function SHA3_256StringW(const Str: WideString): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_256); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_256_OUTPUT_LENGTH_BYTE); +end; + +// AnsiString ݽ SHA3_384 +function SHA3_384StringA(const Str: AnsiString): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, PAnsiChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// WideString ݽ SHA3_384 +function SHA3_384StringW(const Str: WideString): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_384); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_384_OUTPUT_LENGTH_BYTE); +end; + +// AnsiString ݽ SHA3_512 +function SHA3_512StringA(const Str: AnsiString): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, PAnsiChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// WideString ݽ SHA3_512 +function SHA3_512StringW(const Str: WideString): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Res: TCnSHA3GeneralDigest; +begin + SHA3Init(Context, stSHA3_512); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); + SHA3Final(Context, Res); + Move(Res[0], Result[0], SHA3_512_OUTPUT_LENGTH_BYTE); +end; + +// AnsiString ݽ SHAKE128 +function SHAKE128StringA(const Str: AnsiString; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE128Init(Context, DigestByteLength); + SHAKE128Update(Context, PAnsiChar(Str), Length(Str)); + SHAKE128Final(Context, Result); +end; + +// WideString ݽ SHAKE128 +function SHAKE128StringW(const Str: WideString; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE128Init(Context, DigestByteLength); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); // SHAKE128UpdateW = SHA3UpdateW + SHAKE128Final(Context, Result); +end; + +// AnsiString ݽ SHAKE256 +function SHAKE256StringA(const Str: AnsiString; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE256Init(Context, DigestByteLength); + SHAKE256Update(Context, PAnsiChar(Str), Length(Str)); + SHAKE256Final(Context, Result); +end; + +// WideString ݽ SHAKE256 +function SHAKE256StringW(const Str: WideString; DigestByteLength: Cardinal): TBytes; +var + Context: TCnSHA3Context; +begin + SHAKE256Init(Context, DigestByteLength); + SHA3UpdateW(Context, PWideChar(Str), Length(Str)); // SHAKE256UpdateW = SHA3UpdateW + SHAKE256Final(Context, Result); +end; + +// SHA3Type ֻ stSHA3_224, stSHA3_256, stSHA3_384, stSHA3_512 +function InternalSHA3Stream(Stream: TStream; const BufSize: Cardinal; var D: + TCnSHA3GeneralDigest; SHA3Type: TSHA3Type; CallBack: TCnSHA3CalcProgressFunc): Boolean; overload; +var + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; + Context: TCnSHA3Context; +begin + Result := False; + Size := Stream.Size; + SavePos := Stream.Position; + TotalBytes := 0; + if Size = 0 then + Exit; + if Size < BufSize then + BufLen := Size + else + BufLen := BufSize; + + CancelCalc := False; + SHA3Init(Context, SHA3Type); + + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + SHA3Update(Context, Buf, ReadBytes); + + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then + Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + SHA3Final(Context, D); + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +// SHA3Type ֻ stSHAKE128 stSHAKE256 +function InternalSHA3Stream(Stream: TStream; const BufSize: Cardinal; + SHA3Type: TSHA3Type; DigestByteLength: Cardinal; out D: TBytes; + CallBack: TCnSHA3CalcProgressFunc): Boolean; overload; +var + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; + Context: TCnSHA3Context; +begin + Result := False; + Size := Stream.Size; + SavePos := Stream.Position; + TotalBytes := 0; + if Size = 0 then + Exit; + if Size < BufSize then + BufLen := Size + else + BufLen := BufSize; + + CancelCalc := False; + SHA3Init(Context, SHA3Type, DigestByteLength); + + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + SHA3Update(Context, Buf, ReadBytes); + + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then + Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + SHA3Final(Context, D); + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +// ָ SHA3_224 +function SHA3_224Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_224Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Dig, stSHA3_224, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_224Digest)); +end; + +// ָ SHA3_256 +function SHA3_256Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_256Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Dig, stSHA3_256, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_256Digest)); +end; + +// ָ SHA3_384 +function SHA3_384Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_384Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Dig, stSHA3_384, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_384Digest)); +end; + +// ָ SHA3_512 +function SHA3_512Stream(Stream: TStream; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_512Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Dig, stSHA3_512, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_512Digest)); +end; + +// ָӴճȿɱ SHAKE128 +function SHAKE128Stream(Stream: TStream; DigestByteLength: Cardinal; + CallBack: TCnSHA3CalcProgressFunc): TBytes; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, stSHAKE128, DigestByteLength, Result, CallBack); +end; + +// ָӴճȿɱ SHAKE256 +function SHAKE256Stream(Stream: TStream; DigestByteLength: Cardinal; + CallBack: TCnSHA3CalcProgressFunc): TBytes; +begin + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, stSHAKE256, DigestByteLength, Result, CallBack); +end; + +function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; +{$IFDEF MSWINDOWS} +var + H: THandle; + Info: BY_HANDLE_FILE_INFORMATION; + Rec: Int64Rec; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + Result := False; + IsEmpty := False; + H := CreateFile(PChar(AFileName), GENERIC_READ, FILE_SHARE_READ, nil, + OPEN_EXISTING, 0, 0); + if H = INVALID_HANDLE_VALUE then + Exit; + try + if not GetFileInformationByHandle(H, Info) then + Exit; + finally + CloseHandle(H); + end; + Rec.Lo := Info.nFileSizeLow; + Rec.Hi := Info.nFileSizeHigh; + Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); + IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); +{$ELSE} + Result := True; // Windows ƽ̨ Trueʾ Mapping +{$ENDIF} +end; + +function InternalSHA3File(const FileName: string; SHA3Type: TSHA3Type; + CallBack: TCnSHA3CalcProgressFunc): TCnSHA3GeneralDigest; overload; +var +{$IFDEF MSWINDOWS} + Context: TCnSHA3Context; + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, Result, SHA3Type, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + SHA3Init(Context, SHA3Type); + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + SHA3Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise ECnNativeException.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise ECnNativeException.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + SHA3Final(Context, Result); +{$ENDIF} + end; +end; + +function InternalSHA3File(const FileName: string; SHA3Type: TSHA3Type; + DigestByteLength: Cardinal; CallBack: TCnSHA3CalcProgressFunc): TBytes; overload; +var +{$IFDEF MSWINDOWS} + Context: TCnSHA3Context; + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalSHA3Stream(Stream, STREAM_BUF_SIZE, SHA3Type, DigestByteLength, Result, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + SHA3Init(Context, SHA3Type, DigestByteLength); + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + SHA3Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise ECnNativeException.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise ECnNativeException.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + SHA3Final(Context, Result); +{$ENDIF} + end; +end; + +// ָļݽ SHA3_224 +function SHA3_224File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_224Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + Dig := InternalSHA3File(FileName, stSHA3_224, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_224Digest)); +end; + +// ָļݽ SHA3_256 +function SHA3_256File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_256Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + Dig := InternalSHA3File(FileName, stSHA3_256, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_256Digest)); +end; + +// ָļݽ SHA3_384 +function SHA3_384File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_384Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + Dig := InternalSHA3File(FileName, stSHA3_384, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_384Digest)); +end; + +// ָļݽ SHA3_512 +function SHA3_512File(const FileName: string; CallBack: TCnSHA3CalcProgressFunc): + TCnSHA3_512Digest; +var + Dig: TCnSHA3GeneralDigest; +begin + Dig := InternalSHA3File(FileName, stSHA3_512, CallBack); + Move(Dig[0], Result[0], SizeOf(TCnSHA3_512Digest)); +end; + +// ָļݽӴճȿɱ SHAKE128 +function SHAKE128File(const FileName: string; DigestByteLength: Cardinal; + CallBack: TCnSHA3CalcProgressFunc): TBytes; +begin + Result := InternalSHA3File(FileName, stSHAKE128, DigestByteLength, CallBack); +end; + +// ָļݽӴճȿɱ SHAKE256 +function SHAKE256File(const FileName: string; DigestByteLength: Cardinal; + CallBack: TCnSHA3CalcProgressFunc): TBytes; +begin + Result := InternalSHA3File(FileName, stSHAKE256, DigestByteLength, CallBack); +end; + +// ʮƸʽ SHA3_224 Ӵֵ +function SHA3_224Print(const Digest: TCnSHA3_224Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA3_224Digest)); +end; + +// ʮƸʽ SHA3_256 Ӵֵ +function SHA3_256Print(const Digest: TCnSHA3_256Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA3_256Digest)); +end; + +// ʮƸʽ SHA3_384 Ӵֵ +function SHA3_384Print(const Digest: TCnSHA3_384Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA3_384Digest)); +end; + +// ʮƸʽ SHA3_512 Ӵֵ +function SHA3_512Print(const Digest: TCnSHA3_512Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSHA3_512Digest)); +end; + +// ʮƸʽ SHAKE128 Ӵֵ +function SHAKE128Print(const Digest: TBytes): string; +begin + Result := BytesToHex(Digest); +end; + +// ʮƸʽ SHAKE256 Ӵֵ +function SHAKE256Print(const Digest: TBytes): string; +begin + Result := BytesToHex(Digest); +end; + +// Ƚ SHA3_224 ӴֵǷ +function SHA3_224Match(const D1, D2: TCnSHA3_224Digest): Boolean; +begin + Result := ConstTimeCompareMem(@D1[0], @D2[0], SizeOf(TCnSHA3_224Digest)); +end; + +// Ƚ SHA3_256 ӴֵǷ +function SHA3_256Match(const D1, D2: TCnSHA3_256Digest): Boolean; +begin + Result := ConstTimeCompareMem(@D1[0], @D2[0], SizeOf(TCnSHA3_256Digest)); +end; + +// Ƚ SHA3_384 ӴֵǷ +function SHA3_384Match(const D1, D2: TCnSHA3_384Digest): Boolean; +begin + Result := ConstTimeCompareMem(@D1[0], @D2[0], SizeOf(TCnSHA3_384Digest)); +end; + +// Ƚ SHA3_512 ӴֵǷ +function SHA3_512Match(const D1, D2: TCnSHA3_512Digest): Boolean; +begin + Result := ConstTimeCompareMem(@D1[0], @D2[0], SizeOf(TCnSHA3_512Digest)); +end; + +// Ƚ SHAKE128 ӴֵǷ +function SHAKE128Match(const D1, D2: TBytes): Boolean; +begin + Result := ConstTimeCompareBytes(D1, D2); +end; + +// Ƚ SHAKE256 ӴֵǷ +function SHAKE256Match(const D1, D2: TBytes): Boolean; +begin + Result := ConstTimeCompareBytes(D1, D2); +end; + +// SHA3_224 Ӵֵת string +function SHA3_224DigestToStr(const Digest: TCnSHA3_224Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA3_224Digest)); +end; + +// SHA3_256 Ӵֵת string +function SHA3_256DigestToStr(const Digest: TCnSHA3_256Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA3_256Digest));; +end; + +// SHA3_384 Ӵֵת string +function SHA3_384DigestToStr(const Digest: TCnSHA3_384Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA3_384Digest)); +end; + +// SHA3_512 Ӵֵת string +function SHA3_512DigestToStr(const Digest: TCnSHA3_512Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSHA3_512Digest)); +end; + +// SHAKE128 Ӵֵת string +function SHAKE128DigestToStr(const Digest: TBytes): string; +begin + Result := BytesToString(Digest); +end; + +// SHAKE256 Ӵֵת string +function SHAKE256DigestToStr(const Digest: TBytes): string; +begin + Result := BytesToString(Digest); +end; + +procedure SHA3_224HmacInit(var Context: TCnSHA3Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA3_224Digest; +begin + if KeyLength > HMAC_SHA3_224_BLOCK_SIZE_BYTE then + begin + Sum := SHA3_224Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA3_224_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA3_224_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA3_224_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, @(Context.Ipad[0]), HMAC_SHA3_224_BLOCK_SIZE_BYTE); +end; + +procedure SHA3_256HmacInit(var Context: TCnSHA3Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA3_256Digest; +begin + if KeyLength > HMAC_SHA3_256_BLOCK_SIZE_BYTE then + begin + Sum := SHA3_256Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA3_256_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA3_256_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA3_256_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, @(Context.Ipad[0]), HMAC_SHA3_256_BLOCK_SIZE_BYTE); +end; + +procedure SHA3_384HmacInit(var Context: TCnSHA3Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA3_384Digest; +begin + if KeyLength > HMAC_SHA3_384_BLOCK_SIZE_BYTE then + begin + Sum := SHA3_384Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA3_384_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA3_384_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA3_384_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, @(Context.Ipad[0]), HMAC_SHA3_384_BLOCK_SIZE_BYTE); +end; + +procedure SHA3_512HmacInit(var Context: TCnSHA3Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSHA3_512Digest; +begin + if KeyLength > HMAC_SHA3_512_BLOCK_SIZE_BYTE then + begin + Sum := SHA3_512Buffer(Key^, KeyLength); + KeyLength := HMAC_SHA3_512_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SHA3_512_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SHA3_512_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, @(Context.Ipad[0]), HMAC_SHA3_512_BLOCK_SIZE_BYTE); +end; + +procedure SHA3_224HmacUpdate(var Context: TCnSHA3Context; Input: PAnsiChar; + ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_256HmacUpdate(var Context: TCnSHA3Context; Input: PAnsiChar; + ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_384HmacUpdate(var Context: TCnSHA3Context; Input: PAnsiChar; + ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_512HmacUpdate(var Context: TCnSHA3Context; Input: PAnsiChar; + ByteLength: Cardinal); +begin + SHA3Update(Context, Input, ByteLength); +end; + +procedure SHA3_224HmacFinal(var Context: TCnSHA3Context; var Output: TCnSHA3GeneralDigest); +var + Len: Integer; + TmpBuf: TCnSHA3GeneralDigest; +begin + Len := HMAC_SHA3_224_OUTPUT_LENGTH_BYTE; + SHA3Final(Context, TmpBuf); + SHA3Init(Context, stSHA3_224); + SHA3Update(Context, @(Context.Opad[0]), HMAC_SHA3_224_BLOCK_SIZE_BYTE); + SHA3Update(Context, @(TmpBuf[0]), Len); + SHA3Final(Context, Output); +end; + +procedure SHA3_256HmacFinal(var Context: TCnSHA3Context; var Output: TCnSHA3GeneralDigest); +var + Len: Integer; + TmpBuf: TCnSHA3GeneralDigest; +begin + Len := HMAC_SHA3_256_OUTPUT_LENGTH_BYTE; + SHA3Final(Context, TmpBuf); + SHA3Init(Context, stSHA3_256); + SHA3Update(Context, @(Context.Opad[0]), HMAC_SHA3_256_BLOCK_SIZE_BYTE); + SHA3Update(Context, @(TmpBuf[0]), Len); + SHA3Final(Context, Output); +end; + +procedure SHA3_384HmacFinal(var Context: TCnSHA3Context; var Output: TCnSHA3GeneralDigest); +var + Len: Integer; + TmpBuf: TCnSHA3GeneralDigest; +begin + Len := HMAC_SHA3_384_OUTPUT_LENGTH_BYTE; + SHA3Final(Context, TmpBuf); + SHA3Init(Context, stSHA3_384); + SHA3Update(Context, @(Context.Opad[0]), HMAC_SHA3_384_BLOCK_SIZE_BYTE); + SHA3Update(Context, @(TmpBuf[0]), Len); + SHA3Final(Context, Output); +end; + +procedure SHA3_512HmacFinal(var Context: TCnSHA3Context; var Output: TCnSHA3GeneralDigest); +var + Len: Integer; + TmpBuf: TCnSHA3GeneralDigest; +begin + Len := HMAC_SHA3_512_OUTPUT_LENGTH_BYTE; + SHA3Final(Context, TmpBuf); + SHA3Init(Context, stSHA3_512); + SHA3Update(Context, @(Context.Opad[0]), HMAC_SHA3_512_BLOCK_SIZE_BYTE); + SHA3Update(Context, @(TmpBuf[0]), Len); + SHA3Final(Context, Output); +end; + +procedure SHA3_224Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_224Digest); +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_224HmacInit(Context, Key, KeyByteLength); + SHA3_224HmacUpdate(Context, Input, ByteLength); + SHA3_224HmacFinal(Context, Dig); + Move(Dig[0], Output[0], Context.DigestLen); +end; + +procedure SHA3_256Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_256Digest); +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_256HmacInit(Context, Key, KeyByteLength); + SHA3_256HmacUpdate(Context, Input, ByteLength); + SHA3_256HmacFinal(Context, Dig); + Move(Dig[0], Output[0], Context.DigestLen); +end; + +procedure SHA3_384Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_384Digest); +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_384HmacInit(Context, Key, KeyByteLength); + SHA3_384HmacUpdate(Context, Input, ByteLength); + SHA3_384HmacFinal(Context, Dig); + Move(Dig[0], Output[0], Context.DigestLen); +end; + +procedure SHA3_512Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSHA3_512Digest); +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_512HmacInit(Context, Key, KeyByteLength); + SHA3_512HmacUpdate(Context, Input, ByteLength); + SHA3_512HmacFinal(Context, Dig); + Move(Dig[0], Output[0], Context.DigestLen); +end; + +function SHA3_224HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA3_224Digest; +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_224HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA3_224HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3_224HmacFinal(Context, Dig); + Move(Dig[0], Result[0], Context.DigestLen); +end; + +function SHA3_256HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA3_256Digest; +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_256HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA3_256HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3_256HmacFinal(Context, Dig); + Move(Dig[0], Result[0], Context.DigestLen); +end; + +function SHA3_384HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA3_384Digest; +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_384HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA3_384HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3_384HmacFinal(Context, Dig); + Move(Dig[0], Result[0], Context.DigestLen); +end; + +function SHA3_512HmacBytes(const Key: TBytes; const Data: TBytes): TCnSHA3_512Digest; +var + Context: TCnSHA3Context; + Dig: TCnSHA3GeneralDigest; +begin + SHA3_512HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SHA3_512HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SHA3_512HmacFinal(Context, Dig); + Move(Dig[0], Result[0], Context.DigestLen); +end; + +end. diff --git a/CnPack/Crypto/CnSM3.pas b/CnPack/Crypto/CnSM3.pas new file mode 100644 index 0000000..c8623de --- /dev/null +++ b/CnPack/Crypto/CnSM3.pas @@ -0,0 +1,842 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnSM3; +{* |
+================================================================================ +* ƣ +* Ԫƣ SM3 Ӵ㷨ʵֵԪ +* ԪߣCnPack 飨master@cnpack.org) +* ο㷨ĵSM3 Cryptographic Hash Algorith +* http://www.oscca.gov.cn/UpFile/20101222141857786.pdf +* ο˲ goldboar C +* עԪʵ˹ SM3 Ӵ㷨Ӧ HMAC 㷨 +* ʵֹ̲ο㷨ĵSM3 Cryptographic Hash Algorith +* ƽ̨Windows 7 + Delphi 5.0 +* ݲԣPWin9X/2000/XP/7 + Delphi 5/6 +* õԪеַϱػʽ +* ļ¼2019.12.12 V1.2 +* ֧ TBytes +* 2019.04.15 V1.1 +* ֧ Win32/Win64/MacOS +* 2014.09.23 V1.0 +* ֲԪ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + Classes, SysUtils, CnNative, CnConsts {$IFDEF MSWINDOWS}, Windows {$ENDIF}; + +type + PCnSM3Digest = ^TCnSM3Digest; + {* SM3 Ӵսָ} + TCnSM3Digest = array[0..31] of Byte; + {* SM3 Ӵս32 ֽ} + + TCnSM3Context = packed record + {* SM3 Ľṹ} + Total: array[0..1] of Cardinal; {!< number of bytes processed } + State: array[0..7] of Cardinal; {!< intermediate digest state } + Buffer: array[0..63] of Byte; {!< data block being processed } + Ipad: array[0..63] of Byte; {!< HMAC: inner padding } + Opad: array[0..63] of Byte; {!< HMAC: outer padding } + end; + PCnSM3Context = ^TCnSM3Context; + + TCnSM3CalcProgressFunc = procedure (ATotal, AProgress: Int64; + var Cancel: Boolean) of object; + {* SM3 ӴսȻص¼} + +function SM3(Input: PAnsiChar; ByteLength: Cardinal): TCnSM3Digest; +{* ݿ SM3 㡣 + + + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3Buffer(const Buffer; Count: Cardinal): TCnSM3Digest; +{* ݿ SM3 㡣 + + + const Buffer - ݿ + Count: Cardinal - ݿֽڳ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3Bytes(const Data: TBytes): TCnSM3Digest; +{* ֽ SM3 㡣 + + + const Data: TBytes - ֽ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3String(const Str: string): TCnSM3Digest; +{* String ݽ SM3 㣬ע D2009 ϰ汾 string Ϊ UnicodeString + лὫǿת AnsiString м㡣 + + + const Str: string - ַ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3StringA(const Str: AnsiString): TCnSM3Digest; +{* AnsiString ݽ SM3 㡣 + + + const Str: AnsiString - ַ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3StringW(const Str: WideString): TCnSM3Digest; +{* WideString ַת SM3 㡣 + ǰ Windows » WideCharToMultyByte תΪ AnsiString ͣ + ƽֱ̨תΪ AnsiString ͣٽм㡣 + + + const Str: WideString - Ŀַ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +{$IFDEF UNICODE} + +function SM3UnicodeString(const Str: string): TCnSM3Digest; +{* UnicodeString ݽֱӵ SM3 㣬ֱӼڲ UTF16 ݣת + + + const Str: string - Ŀַ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +{$ELSE} + +function SM3UnicodeString(const Str: WideString): TCnSM3Digest; +{* UnicodeString ݽֱӵ SM3 㣬ֱӼڲ UTF16 ݣת + + + const Str: WideString - Ŀַ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +{$ENDIF} + +function SM3File(const FileName: string; CallBack: TCnSM3CalcProgressFunc = nil): TCnSM3Digest; +{* ָļݽ SM3 㡣 + + + const FileName: string - ļ + CallBack: TCnSM3CalcProgressFunc - ȻصĬΪ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +function SM3Stream(Stream: TStream; CallBack: TCnSM3CalcProgressFunc = nil): TCnSM3Digest; +{* ָݽ SM3 㡣 + + + Stream: TStream - + CallBack: TCnSM3CalcProgressFunc - ȻصĬΪ + + ֵTCnSM3Digest - ص SM3 Ӵֵ +} + +// ⲿݽɢ SM3 㣬SM3Update ɶα + +procedure SM3Init(var Context: TCnSM3Context); +{* ʼһ SM3 ģ SM3 + + + var Context: TCnSM3Context - ʼ SM3 + + ֵޣ +} + +procedure SM3Update(var Context: TCnSM3Context; Input: PAnsiChar; ByteLength: Cardinal); +{* ԳʼĶһݽ SM3 㡣 + ɶε㲻ͬݿ飬轫ͬݿƴڴС + + + var Context: TCnSM3Context - SM3 + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + + ֵޣ +} + +procedure SM3Final(var Context: TCnSM3Context; var Digest: TCnSM3Digest); +{* ּ㣬 SM3 Digest + + + var Context: TCnSM3Context - SM3 + var Digest: TCnSM3Digest - ص SM3 Ӵֵ + + ֵޣ +} + +function SM3Print(const Digest: TCnSM3Digest): string; +{* ʮƸʽ SM3 Ӵֵ + + + const Digest: TCnSM3Digest - ָ SM3 Ӵֵ + + ֵstring - ʮַ +} + +function SM3Match(const D1: TCnSM3Digest; const D2: TCnSM3Digest): Boolean; +{* Ƚ SM3 ӴֵǷȡ + + + const D1: TCnSM3Digest - Ƚϵ SM3 Ӵֵһ + const D2: TCnSM3Digest - Ƚϵ SM3 Ӵֵ + + ֵBoolean - Ƿ +} + +function SM3DigestToStr(const Digest: TCnSM3Digest): string; +{* SM3 Ӵֱֵת stringÿֽڶӦһַ + + + const Digest: TCnSM3Digest - ת SM3 Ӵֵ + + ֵstring - صַ +} + +procedure SM3Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSM3Digest); +{* SM3 HMACHash-based Message Authentication Code㣬 + ͨݵļϼԿĸҲмΡ + + + Key: PAnsiChar - SM3 Կݿַ + KeyByteLength: Integer - SM3 Կݿֽڳ + Input: PAnsiChar - ݿַ + ByteLength: Cardinal - ݿֽڳ + var Output: TCnSM3Digest - ص SM3 Ӵֵ + + ֵޣ +} + +function SM3HmacBytes(const Key: TBytes; const Data: TBytes): TCnSM3Digest; +{* ֽл MD5 HMAC 㡣 + + + const Key: TBytes - SM3 Կֽ + const Data: TBytes - ֽ + + ֵTCnMD5Digest - ص SM3 Ӵֵ +} + +implementation + +const + SM3Padding: array[0..63] of Byte = + ( + $80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ); + + SM3_T: array[0..63] of Cardinal = ( + $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, + $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, $79CC4519, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, + $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A, $7A879D8A + ); + + MAX_FILE_SIZE = 512 * 1024 * 1024; + // If file size <= this size (bytes), using Mapping, else stream + + HMAC_SM3_BLOCK_SIZE_BYTE = 64; + HMAC_SM3_OUTPUT_LENGTH_BYTE = 32; + +type + TSM3ProcessData = array[0..63] of Byte; + +procedure GetULongBe(var N: Cardinal; B: PAnsiChar; I: Integer); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +var + D: Cardinal; +begin + D := (Cardinal(B[I]) shl 24) or (Cardinal(B[I + 1]) shl 16) or + (Cardinal(B[I + 2]) shl 8) or (Cardinal(B[I + 3])); + N := D; +end; + +procedure PutULongBe(N: Cardinal; B: PAnsiChar; I: Integer); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + B[I] := AnsiChar(N shr 24); + B[I + 1] := AnsiChar(N shr 16); + B[I + 2] := AnsiChar(N shr 8); + B[I + 3] := AnsiChar(N); +end; + +function FF0(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor Y xor Z; +end; + +function FF1(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Y) or (Y and Z) or (X and Z); +end; + +function GG0(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor Y xor Z; +end; + +function GG1(X, Y, Z: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and Y) or ((not X) and Z); +end; + +function SM3Shl(X: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and $FFFFFFFF) shl N; +end; + +// ѭơע N Ϊ 0 32 ʱֵΪ XN Ϊ 33 ʱֵ N Ϊ 1 ʱķֵ +function ROTL(X: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := SM3Shl(X, N) or (X shr (32 - N)); +end; + +function P0(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor ROTL(X, 9) xor ROTL(X, 17); +end; + +function P1(X: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X xor ROTL(X, 15) xor ROTL(X, 23); +end; + +procedure SM3Init(var Context: TCnSM3Context); +begin + Context.Total[0] := 0; + Context.Total[1] := 0; + + Context.State[0] := $7380166F; + Context.State[1] := $4914B2B9; + Context.State[2] := $172442D7; + Context.State[3] := $DA8A0600; + Context.State[4] := $A96F30BC; + Context.State[5] := $163138AA; + Context.State[6] := $E38DEE4D; + Context.State[7] := $B0FB0E4E; + + FillChar(Context.Buffer, SizeOf(Context.Buffer), 0); +end; + +// һδ 64 ֽҲ 512 λݿ +procedure SM3Process(var Context: TCnSM3Context; Data: PAnsiChar); +var + SS1, SS2, TT1, TT2: Cardinal; + W: array[0..67] of Cardinal; + W1: array[0..63] of Cardinal; + A, B, C, D, E, F, G, H: Cardinal; + Temp1, Temp2: Cardinal; + J: Integer; +begin + GetULongBe(W[ 0], Data, 0); + GetULongBe(W[ 1], Data, 4); + GetULongBe(W[ 2], Data, 8); + GetULongBe(W[ 3], Data, 12); + GetULongBe(W[ 4], Data, 16); + GetULongBe(W[ 5], Data, 20); + GetULongBe(W[ 6], Data, 24); + GetULongBe(W[ 7], Data, 28); + GetULongBe(W[ 8], Data, 32); + GetULongBe(W[ 9], Data, 36); + GetULongBe(W[10], Data, 40); + GetULongBe(W[11], Data, 44); + GetULongBe(W[12], Data, 48); + GetULongBe(W[13], Data, 52); + GetULongBe(W[14], Data, 56); + GetULongBe(W[15], Data, 60); + + for J := 16 to 67 do + begin + Temp1 := W[J - 16] xor W[J - 9]; + Temp2 := ROTL(W[J - 3], 15); + W[J] := P1(Temp1 xor Temp2) xor (ROTL(W[J - 13], 7) xor W[J - 6]); + end; + + for J := 0 to 63 do + W1[J] := W[J] xor W[J + 4]; + + // ѾW/W1ֵ + + A := Context.State[0]; + B := Context.State[1]; + C := Context.State[2]; + D := Context.State[3]; + E := Context.State[4]; + F := Context.State[5]; + G := Context.State[6]; + H := Context.State[7]; + + for J := 0 to 15 do + begin + SS1 := ROTL((ROTL(A, 12) + E + ROTL(SM3_T[J], J)), 7); + SS2 := SS1 xor ROTL(A, 12); + TT1 := FF0(A, B, C) + D + SS2 + W1[J]; + TT2 := GG0(E, F, G) + H + SS1 + W[J]; + D := C; + C := ROTL(B, 9); + B := A; + A := TT1; + H := G; + G := ROTL(F, 19); + F := E; + E := P0(TT2); + end; + + for J := 16 to 63 do + begin + SS1 := ROTL((ROTL(A, 12) + E + ROTL(SM3_T[J], J)), 7); + SS2 := SS1 xor ROTL(A, 12); + TT1 := FF1(A, B, C) + D + SS2 + W1[J]; + TT2 := GG1(E, F, G) + H + SS1 + W[J]; + D := C; + C := ROTL(B,9); + B := A; + A := TT1; + H := G; + G := ROTL(F,19); + F := E; + E := P0(TT2); + end; + + Context.State[0] := Context.State[0] xor A; + Context.State[1] := Context.State[1] xor B; + Context.State[2] := Context.State[2] xor C; + Context.State[3] := Context.State[3] xor D; + Context.State[4] := Context.State[4] xor E; + Context.State[5] := Context.State[5] xor F; + Context.State[6] := Context.State[6] xor G; + Context.State[7] := Context.State[7] xor H; + + // +end; + +procedure SM3UpdateW(var Context: TCnSM3Context; Input: PWideChar; CharLength: Cardinal); +var +{$IFDEF MSWINDOWS} + pContent: PAnsiChar; + iLen: Cardinal; +{$ELSE} + S: string; // UnicodeString + A: AnsiString; +{$ENDIF} +begin +{$IFDEF MSWINDOWS} + GetMem(pContent, CharLength * SizeOf(WideChar)); + try + iLen := WideCharToMultiByte(0, 0, Input, CharLength, // ҳĬ 0 + PAnsiChar(pContent), CharLength * SizeOf(WideChar), nil, nil); + SM3Update(Context, pContent, iLen); + finally + FreeMem(pContent); + end; +{$ELSE} // MacOS ֱӰ UnicodeString ת AnsiString 㣬ַ֧ Windows Unicode ƽ̨ + S := StrNew(Input); + A := AnsiString(S); + SM3Update(Context, @A[1], Length(A)); +{$ENDIF} +end; + +procedure SM3Update(var Context: TCnSM3Context; Input: PAnsiChar; ByteLength: Cardinal); +var + Fill, Left: Cardinal; +begin + if (Input = nil) or (ByteLength <= 0) then + Exit; + + Left := Context.Total[0] and $3F; + Fill := 64 - Left; + + Context.Total[0] := Context.Total[0] + ByteLength; + Context.Total[0] := Context.Total[0] and $FFFFFFFF; + + if Context.Total[0] < ByteLength then + Context.Total[1] := Context.Total[1] + 1; + + if (Left <> 0) and (ByteLength >= Fill) then + begin + Move(Input^, Context.Buffer[Left], Fill); + SM3Process(Context, @(Context.Buffer[0])); + Input := Input + Fill; + ByteLength := ByteLength - Fill; + Left := 0; + end; + + while ByteLength >= 64 do + begin + SM3Process(Context, Input); + Input := Input + 64; + ByteLength := ByteLength - 64; + end; + + if ByteLength > 0 then + Move(Input^, Context.Buffer[Left], ByteLength); +end; + +procedure SM3Final(var Context: TCnSM3Context; var Digest: TCnSM3Digest); +var + Last, Padn: Cardinal; + High, Low: Cardinal; + MsgLen: array[0..7] of Byte; +begin + High := (Context.Total[0] shr 29) or (Context.Total[1] shl 3); + Low := Context.Total[0] shl 3; + + PutULongBe(High, @(MsgLen[0]), 0); + PutULongBe(Low, @(MsgLen[0]), 4); + + Last := Context.Total[0] and $3F; + if Last < 56 then + Padn := 56 - Last + else + Padn := 120 - Last; + + SM3Update(Context, @(SM3Padding[0]), Padn); + SM3Update(Context, @(MsgLen[0]), 8); + + PutULongBe(Context.State[0], @Digest, 0); + PutULongBe(Context.State[1], @Digest, 4); + PutULongBe(Context.State[2], @Digest, 8); + PutULongBe(Context.State[3], @Digest, 12); + PutULongBe(Context.State[4], @Digest, 16); + PutULongBe(Context.State[5], @Digest, 20); + PutULongBe(Context.State[6], @Digest, 24); + PutULongBe(Context.State[7], @Digest, 28); +end; + +function SM3(Input: PAnsiChar; ByteLength: Cardinal): TCnSM3Digest; +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3Update(Context, Input, ByteLength); + SM3Final(Context, Result); +end; + +procedure SM3HmacInit(var Context: TCnSM3Context; Key: PAnsiChar; KeyLength: Integer); +var + I: Integer; + Sum: TCnSM3Digest; +begin + if KeyLength > HMAC_SM3_BLOCK_SIZE_BYTE then + begin + Sum := SM3Buffer(Key^, KeyLength); + KeyLength := HMAC_SM3_OUTPUT_LENGTH_BYTE; + Key := @(Sum[0]); + end; + + FillChar(Context.Ipad, HMAC_SM3_BLOCK_SIZE_BYTE, $36); + FillChar(Context.Opad, HMAC_SM3_BLOCK_SIZE_BYTE, $5C); + + for I := 0 to KeyLength - 1 do + begin + Context.Ipad[I] := Byte(Context.Ipad[I] xor Byte(Key[I])); + Context.Opad[I] := Byte(Context.Opad[I] xor Byte(Key[I])); + end; + + SM3Init(Context); + SM3Update(Context, @(Context.Ipad[0]), HMAC_SM3_BLOCK_SIZE_BYTE); +end; + +procedure SM3HmacUpdate(var Context: TCnSM3Context; Input: PAnsiChar; Length: Cardinal); +begin + SM3Update(Context, Input, Length); +end; + +procedure SM3HmacFinal(var Context: TCnSM3Context; var Output: TCnSM3Digest); +var + Len: Integer; + TmpBuf: TCnSM3Digest; +begin + Len := HMAC_SM3_OUTPUT_LENGTH_BYTE; + SM3Final(Context, TmpBuf); + SM3Init(Context); + SM3Update(Context, @(Context.Opad[0]), HMAC_SM3_BLOCK_SIZE_BYTE); + SM3Update(Context, @(TmpBuf[0]), Len); + SM3Final(Context, Output); +end; + +procedure SM3Hmac(Key: PAnsiChar; KeyByteLength: Integer; Input: PAnsiChar; + ByteLength: Cardinal; var Output: TCnSM3Digest); +var + Context: TCnSM3Context; +begin + SM3HmacInit(Context, Key, KeyByteLength); + SM3HmacUpdate(Context, Input, ByteLength); + SM3HmacFinal(Context, Output); +end; + +function SM3HmacBytes(const Key: TBytes; const Data: TBytes): TCnSM3Digest; +var + Context: TCnSM3Context; +begin + SM3HmacInit(Context, PAnsiChar(@Key[0]), Length(Key)); + SM3HmacUpdate(Context, PAnsiChar(@Data[0]), Length(Data)); + SM3HmacFinal(Context, Result); +end; + +function SM3Buffer(const Buffer; Count: Cardinal): TCnSM3Digest; +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3Update(Context, PAnsiChar(@Buffer), Count); + SM3Final(Context, Result); +end; + +function SM3Bytes(const Data: TBytes): TCnSM3Digest; +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3Update(Context, PAnsiChar(@Data[0]), Length(Data)); + SM3Final(Context, Result); +end; + +function SM3String(const Str: string): TCnSM3Digest; +var + AStr: AnsiString; +begin + AStr := AnsiString(Str); + Result := SM3StringA(AStr); +end; + +function SM3StringA(const Str: AnsiString): TCnSM3Digest; +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3Update(Context, PAnsiChar(Str), Length(Str)); + SM3Final(Context, Result); +end; + +function SM3StringW(const Str: WideString): TCnSM3Digest; +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3UpdateW(Context, PWideChar(Str), Length(Str)); + SM3Final(Context, Result); +end; + +{$IFDEF UNICODE} +function SM3UnicodeString(const Str: string): TCnSM3Digest; +{$ELSE} +function SM3UnicodeString(const Str: WideString): TCnSM3Digest; +{$ENDIF} +var + Context: TCnSM3Context; +begin + SM3Init(Context); + SM3Update(Context, PAnsiChar(@Str[1]), Length(Str) * SizeOf(WideChar)); + SM3Final(Context, Result); +end; + +function InternalSM3Stream(Stream: TStream; const BufSize: Cardinal; var D: + TCnSM3Digest; CallBack: TCnSM3CalcProgressFunc): Boolean; +var + Context: TCnSM3Context; + Buf: PAnsiChar; + BufLen: Cardinal; + Size: Int64; + ReadBytes: Cardinal; + TotalBytes: Int64; + SavePos: Int64; + CancelCalc: Boolean; +begin + Result := False; + Size := Stream.Size; + SavePos := Stream.Position; + TotalBytes := 0; + if Size = 0 then Exit; + if Size < BufSize then BufLen := Size + else BufLen := BufSize; + + CancelCalc := False; + SM3Init(Context); + GetMem(Buf, BufLen); + try + Stream.Position := 0; + repeat + ReadBytes := Stream.Read(Buf^, BufLen); + if ReadBytes <> 0 then + begin + Inc(TotalBytes, ReadBytes); + SM3Update(Context, Buf, ReadBytes); + if Assigned(CallBack) then + begin + CallBack(Size, TotalBytes, CancelCalc); + if CancelCalc then Exit; + end; + end; + until (ReadBytes = 0) or (TotalBytes = Size); + SM3Final(Context, D); + Result := True; + finally + FreeMem(Buf, BufLen); + Stream.Position := SavePos; + end; +end; + +function SM3File(const FileName: string; + CallBack: TCnSM3CalcProgressFunc): TCnSM3Digest; +var +{$IFDEF MSWINDOWS} + FileHandle: THandle; + MapHandle: THandle; + ViewPointer: Pointer; + Context: TCnSM3Context; +{$ENDIF} + Stream: TStream; + FileIsZeroSize: Boolean; + + function FileSizeIsLargeThanMaxOrCanNotMap(const AFileName: string; out IsEmpty: Boolean): Boolean; +{$IFDEF MSWINDOWS} + var + H: THandle; + Info: BY_HANDLE_FILE_INFORMATION; + Rec : Int64Rec; +{$ENDIF} + begin +{$IFDEF MSWINDOWS} + Result := False; + IsEmpty := False; + H := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); + if H = INVALID_HANDLE_VALUE then Exit; + try + if not GetFileInformationByHandle(H, Info) then Exit; + finally + CloseHandle(H); + end; + Rec.Lo := Info.nFileSizeLow; + Rec.Hi := Info.nFileSizeHigh; + Result := (Rec.Hi > 0) or (Rec.Lo > MAX_FILE_SIZE); + IsEmpty := (Rec.Hi = 0) and (Rec.Lo = 0); +{$ELSE} + Result := True; // Windows ƽ̨ Trueʾ Mapping +{$ENDIF} + end; + +begin + FileIsZeroSize := False; + if FileSizeIsLargeThanMaxOrCanNotMap(FileName, FileIsZeroSize) then + begin + // 2G ļ Map ʧܣ Windows ƽ̨ʽѭ + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + InternalSM3Stream(Stream, 4096 * 1024, Result, CallBack); + finally + Stream.Free; + end; + end + else + begin +{$IFDEF MSWINDOWS} + SM3Init(Context); + FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or + FILE_FLAG_SEQUENTIAL_SCAN, 0); + if FileHandle <> INVALID_HANDLE_VALUE then + begin + try + MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); + if MapHandle <> 0 then + begin + try + ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); + if ViewPointer <> nil then + begin + try + SM3Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); + finally + UnmapViewOfFile(ViewPointer); + end; + end + else + begin + raise ECnNativeException.Create(SCnErrorMapViewOfFile + IntToStr(GetLastError)); + end; + finally + CloseHandle(MapHandle); + end; + end + else + begin + if not FileIsZeroSize then + raise ECnNativeException.Create(SCnErrorCreateFileMapping + IntToStr(GetLastError)); + end; + finally + CloseHandle(FileHandle); + end; + end; + SM3Final(Context, Result); +{$ENDIF} + end; +end; + +function SM3Stream(Stream: TStream; + CallBack: TCnSM3CalcProgressFunc): TCnSM3Digest; +begin + InternalSM3Stream(Stream, 4096 * 1024, Result, CallBack); +end; + +function SM3Print(const Digest: TCnSM3Digest): string; +begin + Result := DataToHex(@Digest[0], SizeOf(TCnSM3Digest)); +end; + +function SM3Match(const D1, D2: TCnSM3Digest): Boolean; +begin + Result := ConstTimeCompareMem(@D1[0], @D2[0], SizeOf(TCnSM3Digest)); +end; + +function SM3DigestToStr(const Digest: TCnSM3Digest): string; +begin + Result := MemoryToString(@Digest[0], SizeOf(TCnSM3Digest)); +end; + +end. diff --git a/CnPack/Crypto/CnSM4.pas b/CnPack/Crypto/CnSM4.pas new file mode 100644 index 0000000..8936be7 --- /dev/null +++ b/CnPack/Crypto/CnSM4.pas @@ -0,0 +1,2202 @@ +{******************************************************************************} +{ CnPack For Delphi/C++Builder } +{ йԼĿԴ } +{ (C)Copyright 2001-2026 CnPack } +{ ------------------------------------ } +{ } +{ ǿԴ CnPack ķЭ } +{ ĺ·һ } +{ } +{ һĿϣãûκεû } +{ ʺضĿĶĵϸ CnPack Э顣 } +{ } +{ ӦѾͿһյһ CnPack Эĸ } +{ ûУɷǵվ } +{ } +{ վַhttps://www.cnpack.org } +{ ʼmaster@cnpack.org } +{ } +{******************************************************************************} + +unit CnSM4; +{* |
+================================================================================ +* ƣ +* Ԫƣ SM4 ԳƼӽ㷨ʵֵԪ +* ԪߣCnPack 飨master@cnpack.org) +* οֲ goldboar C +* עԪʵ˹ SM4 ԳƼӽ㷨ֿС 16 ֽڣʵ +* Ķ뷽ʽĩβ 0Ԫڲ֧ PKCS ȿ뷽ʽҪⲿ +* CnPemUtils.pas Ԫе PKCS ϵкԼӽݽж +* Ԫʵֲο㷨ĵSM4 Encryption alogrithm +* +* ߰汾 Delphi 뾡ʹ AnsiString 汾ĺʮƳ⣩ +* ⲻַӰӽܽ +* +* ECB/CBC ǿģʽҪ롣CFB/OFB/CTR ĵģʽ뵽顣 +* ⣬Ԫе CTR 8 ֽ Nonce 8 ֽڼΪڲ 16 ֽڳʼģʽ +* Щ 16 ֽ Iv ĺ 4 8 ֽIJͬʹʱע⡣ +* +* ƽ̨Windows 7 + Delphi 5.0 +* ݲԣPWin9X/2000/XP/7 + Delphi 5/6 + MaxOS 64 +* õԪеַϱػʽ +* ļ¼2025.01.22 V1.9 +* CFB/OFB ģʽĩβʱӽܿܳ +* 2024.12.01 V1.8 +* ȥֲҪ const βע +* 2022.07.21 V1.7 +* CTR ģʽ֧ +* 2022.06.21 V1.6 +* 뼸ֽ鵽ʮַ֮ļӽܺ +* 2022.04.26 V1.5 +* LongWord Integer ַת֧ MacOS64 +* 2022.04.19 V1.4 +* ʹóʼʱڲݣĴ +* 2021.12.12 V1.3 +* CFB/OFB ģʽ֧ +* 2020.03.24 V1.2 +* Ӳַװ +* 2019.04.15 V1.1 +* ֧ Win32/Win64/MacOS +* 2014.09.25 V1.0 +* ֲԪ +================================================================================ +|} + +interface + +{$I CnPack.inc} + +uses + Classes, SysUtils, CnNative; + +const + CN_SM4_KEYSIZE = 16; + {* SM4 Կ 16 ֽ} + + CN_SM4_BLOCKSIZE = 16; + {* SM4 ķֿ鳤 16 ֽ} + + CN_SM4_NONCESIZE = 8; + {* SM4 CTR ģʽµʼ 8 ֽ} + +type + ECnSM4Exception = class(Exception); + {* SM4 쳣} + + TCnSM4Key = array[0..CN_SM4_KEYSIZE - 1] of Byte; + {* SM4 ļ Key16 ֽ} + + TCnSM4Buffer = array[0..CN_SM4_BLOCKSIZE - 1] of Byte; + {* SM4 ļܿ飬16 ֽ} + + TCnSM4Iv = array[0..CN_SM4_BLOCKSIZE - 1] of Byte; + {* SM4 CBC/CFB/OFB ȵijʼ16 ֽ} + + TCnSM4Nonce = array[0..CN_SM4_NONCESIZE - 1] of Byte; + {* SM4 CTR ģʽµijʼ 8 ֽڣһ 8 ֽڼƴһΪ 16 ֽ Iv} + + TCnSM4Context = packed record + {* SM4 Ľṹ} + Mode: Integer; {!< encrypt/decrypt } + Sk: array[0..CN_SM4_KEYSIZE * 2 - 1] of Cardinal; {!< SM4 subkeys } + end; + +function SM4GetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +{* ֽڳȼȡǿ + + + InputByteLength: Integer - ֽڳ + + ֵInteger - SM4 ij +} + +procedure SM4Encrypt(Key: PAnsiChar; Input: PAnsiChar; Output: PAnsiChar; ByteLen: Integer); +{* ԭʼ SM4 ݿ飬ʹ ECB ģʽ Input ڵݼܷ Output У + б֤ Key ָ 16 ֽڣInput Output ָݳȲҶΪ ByteLen ֽ + ByteLen 뱻 16 + + + Key: PAnsiChar - 16 ֽ SM4 Կ + Input: PAnsiChar - ܵݿַ + Output: PAnsiChar - ݿַ + ByteLen: Integer - ӽݿֽڳ + + ֵޣ +} + +procedure SM4Decrypt(Key: PAnsiChar; Input: PAnsiChar; Output: PAnsiChar; ByteLen: Integer); +{* ԭʼ SM4 ݿ飬ECB ģʽ Input ڵݽܸ鵽 Output + б֤ Key ָ 16 ֽڣInput Output ָݳȲҶΪ ByteLen ֽ + ByteLen 뱻 16 + + + Key: PAnsiChar - 16 ֽ SM4 Կ + Input: PAnsiChar - ܵݿַ + Output: PAnsiChar - ݿַ + ByteLen: Integer - ӽݿֽڳ + + ֵޣ +} + +// ============== ַʮַ֮ļӽ =================== + +procedure SM4EncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ ECB ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + const Input: AnsiString - ַܵ䳤粻 16 ıʱᱻ #0 ȴﵽ 16 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 16) + 1) * 16 + + ֵޣ +} + +procedure SM4DecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ ECB ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + const Input: AnsiString - ַܵ䳤粻 16 ıʱᱻ #0 ȴﵽ 16 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 16) + 1) * 16 + + ֵޣ +} + +procedure SM4EncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ CBC ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + Iv: PAnsiChar - 16 ֽڳʼעЧݱڻ 16 ֽ + const Input: AnsiString - ַܵ䳤粻 16 ıʱᱻ #0 ȴﵽ 16 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 16) + 1) * 16 + + ֵޣ +} + +procedure SM4DecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ CBC ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + Iv: PAnsiChar - 16 ֽڳʼעЧݱڻ 16 ֽ + const Input: AnsiString - ַܵ䳤粻 16 ıʱᱻ #0 ȴﵽ 16 ı + Output: PAnsiChar - 䳤ȱڻ (((Length(Input) - 1) div 16) + 1) * 16 + + ֵޣ +} + +procedure SM4EncryptCfbStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ CFB ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + Iv: PAnsiChar - 16 ֽڳʼעЧݱڻ 16 ֽ + const Input: AnsiString - ַܵ + Output: PAnsiChar - 䳤ȱڻ Length(Input) + + ֵޣ +} + +procedure SM4DecryptCfbStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ CFB ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + Iv: PAnsiChar - 16 ֽڳʼעЧݱڻ 16 ֽ + const Input: AnsiString - ַܵ + Output: PAnsiChar - 䳤ȱڻ Length(Input) + + ֵޣ +} + +procedure SM4EncryptOfbStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ OFB ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + Iv: PAnsiChar - 16 ֽڳʼעЧݱڻ 16 ֽ + const Input: AnsiString - ַܵ + Output: PAnsiChar - 䳤ȱڻ Length(Input) + + ֵޣ +} + +procedure SM4DecryptOfbStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ OFB ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + Iv: PAnsiChar - 16 ֽڳʼעЧݱڻ 16 ֽ + const Input: AnsiString - ַܵ + Output: PAnsiChar - 䳤ȱڻ Length(Input) + + ֵޣ +} + +procedure SM4EncryptCtrStr(Key: AnsiString; Nonce: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ CTR ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + Nonce: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ + const Input: AnsiString - ַܵ + Output: PAnsiChar - 䳤ȱڻ Length(Input) + + ֵޣ +} + +procedure SM4DecryptCtrStr(Key: AnsiString; Nonce: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +{* AnsiString SM4 ܣʹ CTR ģʽ + + + Key: AnsiString - 16 ֽ SM4 Կ̫ضϣ #0 + Nonce: PAnsiChar - 8 ֽڳʼעЧݱڻ 8 ֽ + const Input: AnsiString - ַܵ + Output: PAnsiChar - 䳤ȱڻ Length(Input) + + ֵޣ +} + +// ================= ֽֽ֮ļӽ ==================== + +function SM4EncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ ECB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؼֽܺ +} + +function SM4DecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ ECB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؽֽܺ +} + +function SM4EncryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ CBC ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؼֽܺ +} + +function SM4DecryptCbcBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ CBC ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؽֽܺ +} + +function SM4EncryptCfbBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ CFB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؼֽܺ +} + +function SM4DecryptCfbBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ CFB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؽֽܺ +} + +function SM4EncryptOfbBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ OFB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؼֽܺ +} + +function SM4DecryptOfbBytes(Key: TBytes; Iv: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ OFB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؽֽܺ +} + +function SM4EncryptCtrBytes(Key: TBytes; Nonce: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ CTR ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Nonce: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؼֽܺ +} + +function SM4DecryptCtrBytes(Key: TBytes; Nonce: TBytes; Input: TBytes): TBytes; +{* ֽ SM4 ܣʹ CTR ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Nonce: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵTBytes - ؽֽܺ +} + +// ============== ֽʮַ֮ļӽ ================= + +function SM4EncryptEcbBytesToHex(Key: TBytes; Input: TBytes): AnsiString; +{* KeySM4 ܷתʮƵģʹ ECB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵAnsiString - ؼܺʮַ +} + +function SM4DecryptEcbBytesFromHex(Key: TBytes; const Input: AnsiString): TBytes; +{* ʮƵ KeySM4 ܷģʹ ECB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + const Input: AnsiString - ܵʮַ + + ֵTBytes - ؽֽܺ +} + +function SM4EncryptCbcBytesToHex(Key: TBytes; Iv: TBytes; Input: TBytes): AnsiString; +{* Key IvSM4 ܷתʮƵģʹ CBC ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵAnsiString - ؼܺʮַ +} + +function SM4DecryptCbcBytesFromHex(Key: TBytes; Iv: TBytes; const Input: AnsiString): TBytes; +{* ʮƵ Key IvSM4 ܷģʹ CBC ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + const Input: AnsiString - ܵʮַ + + ֵTBytes - ؽֽܺ +} + +function SM4EncryptCfbBytesToHex(Key: TBytes; Iv: TBytes; Input: TBytes): AnsiString; +{* Key IvSM4 ܷתʮƵģʹ CFB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵAnsiString - ؼܺʮַ +} + +function SM4DecryptCfbBytesFromHex(Key: TBytes; Iv: TBytes; const Input: AnsiString): TBytes; +{* ʮƵ Key IvSM4 ܷģʹ CFB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + const Input: AnsiString - ܵʮַ + + ֵTBytes - ؽֽܺ +} + +function SM4EncryptOfbBytesToHex(Key: TBytes; Iv: TBytes; Input: TBytes): AnsiString; +{* Key IvSM4 ܷתʮƵģʹ OFB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵAnsiString - ؼܺʮַ +} + +function SM4DecryptOfbBytesFromHex(Key: TBytes; Iv: TBytes; const Input: AnsiString): TBytes; +{* ʮƵ Key IvSM4 ܷģʹ OFB ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Iv: TBytes - 16 ֽڳʼ̫ضϣ 0 + const Input: AnsiString - ܵʮַ + + ֵTBytes - ؽֽܺ +} + +function SM4EncryptCtrBytesToHex(Key: TBytes; Nonce: TBytes; Input: TBytes): AnsiString; +{* Key NonceSM4 ܷתʮƵģʹ CTR ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Nonce: TBytes - 8 ֽڳʼ̫ضϣ 0 + Input: TBytes - ֽܵ + + ֵAnsiString - ؼܺʮַ +} + +function SM4DecryptCtrBytesFromHex(Key: TBytes; Nonce: TBytes; const Input: AnsiString): TBytes; +{* ʮƵ Key NonceSM4 ܷģʹ CTR ģʽ + + + Key: TBytes - 16 ֽ SM4 Կ̫ضϣ 0 + Nonce: TBytes - 8 ֽڳʼ̫ضϣ 0 + const Input: AnsiString - ܵʮַ + + ֵTBytes - ؽֽܺ +} + +// ======================= ֮ļӽ ========================== + +procedure SM4EncryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; Dest: TStream); overload; +{* SM4 ܣʹ ECB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + Dest: TStream - + + ֵޣ +} + +procedure SM4DecryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; Dest: TStream); overload; +{* SM4 ܣʹ ECB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + Dest: TStream - + + ֵޣ +} + +procedure SM4EncryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +{* SM4 ܣʹ CBC ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + const InitVector: TCnSM4Iv - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure SM4DecryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +{* SM4 ܣʹ CBC ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + const InitVector: TCnSM4Iv - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure SM4EncryptStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +{* SM4 ܣʹ CFB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + const InitVector: TCnSM4Iv - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure SM4DecryptStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +{* SM4 ܣʹ CFB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + const InitVector: TCnSM4Iv - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure SM4EncryptStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +{* SM4 ܣʹ OFB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + const InitVector: TCnSM4Iv - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure SM4DecryptStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +{* SM4 ܣʹ OFB ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + const InitVector: TCnSM4Iv - 16 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure SM4EncryptStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitNonce: TCnSM4Nonce; Dest: TStream); +{* SM4 ܣʹ CTR ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + const InitNonce: TCnSM4Nonce - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +procedure SM4DecryptStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitNonce: TCnSM4Nonce; Dest: TStream); +{* SM4 ܣʹ CTR ģʽ + Count Ϊ 0 ʾͷֻ Stream ǰλ Count ֽ + + + Source: TStream - ܵ + Count: Cardinal - ǰλĴֽܵڳȣΪ 0ʾͷ + const Key: TCnSM4Key - 16 ֽ SM4 Կ + const InitNonce: TCnSM4Nonce - 8 ֽڳʼ + Dest: TStream - + + ֵޣ +} + +// Ϊײܺųⲿʹ + +procedure SM4SetKeyEnc(var Ctx: TCnSM4Context; Key: PAnsiChar); +{* 16 ֽ Key SM4 IJΪģʽ + + + var Ctx: TCnSM4Context - õ SM4 + Key: PAnsiChar - 16 ֽ SM4 Կ + + ֵޣ +} + +procedure SM4SetKeyDec(var Ctx: TCnSM4Context; Key: PAnsiChar); +{* 16 ֽ Key SM4 IJΪģʽ + + + var Ctx: TCnSM4Context - õ SM4 + Key: PAnsiChar - 16 ֽ SM4 Կ + + ֵޣ +} + +procedure SM4OneRound(SK: PCardinal; Input: PAnsiChar; Output: PAnsiChar); +{* ӽһ飬ݴ Input Output 16 ֽڣ߿ͬһ + SK TSM4Context Skܻǽ + + + SK: PCardinal - SM4 SubKey + Input: PAnsiChar - ݿַ 16 ֽ + Output: PAnsiChar - ϵݿַ 16 ֽ + + ֵޣ +} + +implementation + +resourcestring + SCnErrorSM4InvalidInBufSize = 'Invalid Buffer Size for Decryption'; + SCnErrorSM4ReadError = 'Stream Read Error'; + SCnErrorSM4WriteError = 'Stream Write Error'; + +const + SM4_ENCRYPT = 1; + SM4_DECRYPT = 0; + + SBoxTable: array[0..CN_SM4_KEYSIZE - 1] of array[0..CN_SM4_KEYSIZE - 1] of Byte = ( + ($D6, $90, $E9, $FE, $CC, $E1, $3D, $B7, $16, $B6, $14, $C2, $28, $FB, $2C, $05), + ($2B, $67, $9A, $76, $2A, $BE, $04, $C3, $AA, $44, $13, $26, $49, $86, $06, $99), + ($9C, $42, $50, $F4, $91, $EF, $98, $7A, $33, $54, $0B, $43, $ED, $CF, $AC, $62), + ($E4, $B3, $1C, $A9, $C9, $08, $E8, $95, $80, $DF, $94, $FA, $75, $8F, $3F, $A6), + ($47, $07, $A7, $FC, $F3, $73, $17, $BA, $83, $59, $3C, $19, $E6, $85, $4F, $A8), + ($68, $6B, $81, $B2, $71, $64, $DA, $8B, $F8, $EB, $0F, $4B, $70, $56, $9D, $35), + ($1E, $24, $0E, $5E, $63, $58, $D1, $A2, $25, $22, $7C, $3B, $01, $21, $78, $87), + ($D4, $00, $46, $57, $9F, $D3, $27, $52, $4C, $36, $02, $E7, $A0, $C4, $C8, $9E), + ($EA, $BF, $8A, $D2, $40, $C7, $38, $B5, $A3, $F7, $F2, $CE, $F9, $61, $15, $A1), + ($E0, $AE, $5D, $A4, $9B, $34, $1A, $55, $AD, $93, $32, $30, $F5, $8C, $B1, $E3), + ($1D, $F6, $E2, $2E, $82, $66, $CA, $60, $C0, $29, $23, $AB, $0D, $53, $4E, $6F), + ($D5, $DB, $37, $45, $DE, $FD, $8E, $2F, $03, $FF, $6A, $72, $6D, $6C, $5B, $51), + ($8D, $1B, $AF, $92, $BB, $DD, $BC, $7F, $11, $D9, $5C, $41, $1F, $10, $5A, $D8), + ($0A, $C1, $31, $88, $A5, $CD, $7B, $BD, $2D, $74, $D0, $12, $B8, $E5, $B4, $B0), + ($89, $69, $97, $4A, $0C, $96, $77, $7E, $65, $B9, $F1, $09, $C5, $6E, $C6, $84), + ($18, $F0, $7D, $EC, $3A, $DC, $4D, $20, $79, $EE, $5F, $3E, $D7, $CB, $39, $48) + ); + + FK: array[0..3] of Cardinal = ($A3B1BAC6, $56AA3350, $677D9197, $B27022DC); + + CK: array[0..CN_SM4_KEYSIZE * 2 - 1] of Cardinal = ( + $00070E15, $1C232A31, $383F464D, $545B6269, + $70777E85, $8C939AA1, $A8AFB6BD, $C4CBD2D9, + $E0E7EEF5, $FC030A11, $181F262D, $343B4249, + $50575E65, $6C737A81, $888F969D, $A4ABB2B9, + $C0C7CED5, $DCE3EAF1, $F8FF060D, $141B2229, + $30373E45, $4C535A61, $686F767D, $848B9299, + $A0A7AEB5, $BCC3CAD1, $D8DFE6ED, $F4FB0209, + $10171E25, $2C333A41, $484F565D, $646B7279 ); + +function Min(A, B: Integer): Integer; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + if A < B then + Result := A + else + Result := B; +end; + +procedure GetULongBe(var N: Cardinal; B: PAnsiChar; I: Integer); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +var + D: Cardinal; +begin + D := (Cardinal(B[I]) shl 24) or (Cardinal(B[I + 1]) shl 16) or + (Cardinal(B[I + 2]) shl 8) or (Cardinal(B[I + 3])); + N := D; +end; + +procedure PutULongBe(N: Cardinal; B: PAnsiChar; I: Integer); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + B[I] := AnsiChar(N shr 24); + B[I + 1] := AnsiChar(N shr 16); + B[I + 2] := AnsiChar(N shr 8); + B[I + 3] := AnsiChar(N); +end; + +function SM4Shl(X: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := (X and $FFFFFFFF) shl N; +end; + +// ѭơע N Ϊ 0 32 ʱֵΪ XN Ϊ 33 ʱֵ N Ϊ 1 ʱķֵ +function ROTL(X: Cardinal; N: Integer): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := SM4Shl(X, N) or (X shr (32 - N)); +end; + +procedure Swap(var A: Cardinal; var B: Cardinal); {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +var + T: Cardinal; +begin + T := A; + A := B; + B := T; +end; + +function SM4SBox(Inch: Byte): Byte; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +var + PTable: Pointer; +begin + PTable := @(SboxTable[0][0]); + Result := PByte(TCnIntAddress(PTable) + Inch)^; +end; + +function SM4Lt(Ka: Cardinal): Cardinal; +var + BB: Cardinal; + A: array[0..3] of Byte; + B: array[0..3] of Byte; +begin + BB := 0; + PutULongBe(Ka, @(A[0]), 0); + B[0] := SM4SBox(A[0]); + B[1] := SM4SBox(A[1]); + B[2] := SM4SBox(A[2]); + B[3] := SM4SBox(A[3]); + GetULongBe(BB, @(B[0]), 0); + + Result := BB xor (ROTL(BB, 2)) xor (ROTL(BB, 10)) xor (ROTL(BB, 18)) + xor (ROTL(BB, 24)); +end; + +function SM4F(X0: Cardinal; X1: Cardinal; X2: Cardinal; X3: Cardinal; RK: Cardinal): Cardinal; {$IFDEF SUPPORT_INLINE} inline; {$ENDIF} +begin + Result := X0 xor SM4Lt(X1 xor X2 xor X3 xor RK); +end; + +function SM4CalciRK(Ka: Cardinal): Cardinal; +var + BB: Cardinal; + A: array[0..3] of Byte; + B: array[0..3] of Byte; +begin + PutULongBe(Ka, @(A[0]), 0); + B[0] := SM4SBox(A[0]); + B[1] := SM4SBox(A[1]); + B[2] := SM4SBox(A[2]); + B[3] := SM4SBox(A[3]); + GetULongBe(BB, @(B[0]), 0); + Result := BB xor ROTL(BB, 13) xor ROTL(BB, 23); +end; + +// SK Points to 32 DWord Array; Key Points to 16 Byte Array +procedure SM4SetKey(SK: PCardinal; Key: PAnsiChar); +var + MK: array[0..3] of Cardinal; + K: array[0..35] of Cardinal; + I: Integer; +begin + GetULongBe(MK[0], Key, 0); + GetULongBe(MK[1], Key, 4); + GetULongBe(MK[2], Key, 8); + GetULongBe(MK[3], Key, 12); + + K[0] := MK[0] xor FK[0]; + K[1] := MK[1] xor FK[1]; + K[2] := MK[2] xor FK[2]; + K[3] := MK[3] xor FK[3]; + + for I := 0 to 31 do + begin + K[I + 4] := K[I] xor SM4CalciRK(K[I + 1] xor K[I + 2] xor K[I + 3] xor CK[I]); + (PCardinal(TCnIntAddress(SK) + I * SizeOf(Cardinal)))^ := K[I + 4]; + end; +end; + +// SK Points to 32 DWord Array; Input/Output Points to 16 Byte Array +// Input Output ͬһ +procedure SM4OneRound(SK: PCardinal; Input: PAnsiChar; Output: PAnsiChar); +var + I: Integer; + UlBuf: array[0..35] of Cardinal; +begin + FillChar(UlBuf[0], SizeOf(UlBuf), 0); + + GetULongBe(UlBuf[0], Input, 0); + GetULongBe(UlBuf[1], Input, 4); + GetULongBe(UlBuf[2], Input, 8); + GetULongBe(UlBuf[3], Input, 12); + + for I := 0 to 31 do + begin + UlBuf[I + 4] := SM4F(UlBuf[I], UlBuf[I + 1], UlBuf[I + 2], UlBuf[I + 3], + (PCardinal(TCnNativeInt(SK) + I * SizeOf(Cardinal)))^); + end; + + PutULongBe(UlBuf[35], Output, 0); + PutULongBe(UlBuf[34], Output, 4); + PutULongBe(UlBuf[33], Output, 8); + PutULongBe(UlBuf[32], Output, 12); +end; + +procedure SM4SetKeyEnc(var Ctx: TCnSM4Context; Key: PAnsiChar); +begin + Ctx.Mode := SM4_ENCRYPT; + SM4SetKey(@(Ctx.Sk[0]), Key); +end; + +procedure SM4SetKeyDec(var Ctx: TCnSM4Context; Key: PAnsiChar); +var + I: Integer; +begin + Ctx.Mode := SM4_DECRYPT; + SM4SetKey(@(Ctx.Sk[0]), Key); + + for I := 0 to CN_SM4_KEYSIZE - 1 do + Swap(Ctx.Sk[I], Ctx.Sk[31 - I]); +end; + +procedure SM4CryptEcb(var Ctx: TCnSM4Context; Mode: Integer; Length: Integer; + Input: PAnsiChar; Output: PAnsiChar); +var + EndBuf: TCnSM4Buffer; +begin + while Length > 0 do + begin + if Length >= CN_SM4_BLOCKSIZE then + begin + SM4OneRound(@(Ctx.Sk[0]), Input, Output); + end + else + begin + // β 16 0 + FillChar(EndBuf[0], CN_SM4_BLOCKSIZE, 0); + Move(Input^, EndBuf[0], Length); + SM4OneRound(@(Ctx.Sk[0]), @(EndBuf[0]), Output); + end; + Inc(Input, CN_SM4_BLOCKSIZE); + Inc(Output, CN_SM4_BLOCKSIZE); + Dec(Length, CN_SM4_BLOCKSIZE); + end; +end; + +procedure SM4CryptEcbStr(Mode: Integer; Key: AnsiString; + const Input: AnsiString; Output: PAnsiChar); +var + Ctx: TCnSM4Context; +begin + if Length(Key) < CN_SM4_KEYSIZE then + while Length(Key) < CN_SM4_KEYSIZE do Key := Key + Chr(0) // 16 bytes at least padding 0. + else if Length(Key) > CN_SM4_KEYSIZE then + Key := Copy(Key, 1, CN_SM4_KEYSIZE); // Only keep 16 + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[1])); + SM4CryptEcb(Ctx, SM4_ENCRYPT, Length(Input), @(Input[1]), @(Output[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyDec(Ctx, @(Key[1])); + SM4CryptEcb(Ctx, SM4_DECRYPT, Length(Input), @(Input[1]), @(Output[0])); + end; +end; + +procedure SM4CryptCbc(var Ctx: TCnSM4Context; Mode: Integer; ByteLen: Integer; + Iv: PAnsiChar; Input: PAnsiChar; Output: PAnsiChar); +var + I: Integer; + EndBuf: TCnSM4Buffer; + LocalIv: TCnSM4Iv; +begin + Move(Iv^, LocalIv[0], CN_SM4_BLOCKSIZE); + if Mode = SM4_ENCRYPT then + begin + while ByteLen > 0 do + begin + if ByteLen >= CN_SM4_BLOCKSIZE then + begin + for I := 0 to CN_SM4_BLOCKSIZE - 1 do + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Input) + I))^ + xor LocalIv[I]; + + SM4OneRound(@(Ctx.Sk[0]), Output, Output); + Move(Output[0], LocalIv[0], CN_SM4_BLOCKSIZE); + end + else + begin + // β 16 0 + FillChar(EndBuf[0], SizeOf(EndBuf), 0); + Move(Input^, EndBuf[0], ByteLen); + + for I := 0 to CN_SM4_BLOCKSIZE - 1 do + (PByte(TCnIntAddress(Output) + I))^ := EndBuf[I] + xor LocalIv[I]; + + SM4OneRound(@(Ctx.Sk[0]), Output, Output); + Move(Output[0], LocalIv[0], CN_SM4_BLOCKSIZE); + end; + + Inc(Input, CN_SM4_BLOCKSIZE); + Inc(Output, CN_SM4_BLOCKSIZE); + Dec(ByteLen, CN_SM4_BLOCKSIZE); + end; + end + else if Mode = SM4_DECRYPT then + begin + while ByteLen > 0 do + begin + if ByteLen >= CN_SM4_BLOCKSIZE then + begin + SM4OneRound(@(Ctx.Sk[0]), Input, Output); + + for I := 0 to CN_SM4_BLOCKSIZE - 1 do + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Output) + I))^ + xor LocalIv[I]; + + Move(Input^, LocalIv[0], CN_SM4_BLOCKSIZE); + end + else + begin + // β 16 0 + FillChar(EndBuf[0], SizeOf(EndBuf), 0); + Move(Input^, EndBuf[0], ByteLen); + SM4OneRound(@(Ctx.Sk[0]), @(EndBuf[0]), Output); + + for I := 0 to CN_SM4_BLOCKSIZE - 1 do + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Output) + I))^ + xor LocalIv[I]; + + Move(EndBuf[0], LocalIv[0], CN_SM4_BLOCKSIZE); + end; + + Inc(Input, CN_SM4_BLOCKSIZE); + Inc(Output, CN_SM4_BLOCKSIZE); + Dec(ByteLen, CN_SM4_BLOCKSIZE); + end; + end; +end; + +procedure SM4CryptCfb(var Ctx: TCnSM4Context; Mode: Integer; ByteLen: Integer; + Iv: PAnsiChar; Input: PAnsiChar; Output: PAnsiChar); +var + I: Integer; + LocalIv, Tail: TCnSM4Iv; +begin + Move(Iv^, LocalIv[0], CN_SM4_BLOCKSIZE); + if Mode = SM4_ENCRYPT then + begin + while ByteLen > 0 do + begin + if ByteLen >= CN_SM4_BLOCKSIZE then + begin + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], Output); // ȼ Iv + + for I := 0 to CN_SM4_BLOCKSIZE - 1 do + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Input) + I))^ + xor (PByte(TCnIntAddress(Output) + I))^; // ܽΪ + + Move(Output[0], LocalIv[0], CN_SM4_BLOCKSIZE); // ȡ Iv Աһ + end + else + begin + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], @Tail[0]); + + for I := 0 to ByteLen - 1 do // ֻʣȣ账 16 ֽ + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Input) + I))^ xor Tail[I]; + end; + + Inc(Input, CN_SM4_BLOCKSIZE); + Inc(Output, CN_SM4_BLOCKSIZE); + Dec(ByteLen, CN_SM4_BLOCKSIZE); + end; + end + else if Mode = SM4_DECRYPT then + begin + while ByteLen > 0 do + begin + if ByteLen >= CN_SM4_BLOCKSIZE then + begin + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], Output); // ȼ Iv + + for I := 0 to CN_SM4_BLOCKSIZE - 1 do + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Output) + I))^ + xor (PByte(TCnIntAddress(Input) + I))^; // ܽõ + + Move(Input[0], LocalIv[0], CN_SM4_BLOCKSIZE); // ȡ Iv ȥһּ + end + else + begin + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], @Tail[0]); + + for I := 0 to ByteLen - 1 do + (PByte(TCnIntAddress(Output) + I))^ := Tail[I] xor (PByte(TCnIntAddress(Input) + I))^; + end; + + Inc(Input, CN_SM4_BLOCKSIZE); + Inc(Output, CN_SM4_BLOCKSIZE); + Dec(ByteLen, CN_SM4_BLOCKSIZE); + end; + end; +end; + +procedure SM4CryptOfb(var Ctx: TCnSM4Context; Mode: Integer; ByteLen: Integer; + Iv: PAnsiChar; Input: PAnsiChar; Output: PAnsiChar); +var + I: Integer; + LocalIv, Tail: TCnSM4Iv; +begin + Move(Iv^, LocalIv[0], CN_SM4_BLOCKSIZE); + if Mode = SM4_ENCRYPT then + begin + while ByteLen > 0 do + begin + if ByteLen >= CN_SM4_BLOCKSIZE then + begin + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], Output); // ȼ Iv + Move(Output[0], LocalIv[0], CN_SM4_BLOCKSIZE); // ܽһ + + for I := 0 to CN_SM4_BLOCKSIZE - 1 do // ܽ + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Input) + I))^ + xor (PByte(TCnIntAddress(Output) + I))^; + end + else + begin + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], @Tail[0]); // ȼ Iv + + for I := 0 to ByteLen - 1 do // 16 ֽ + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Input) + I))^ xor Tail[I]; + end; + + Inc(Input, CN_SM4_BLOCKSIZE); + Inc(Output, CN_SM4_BLOCKSIZE); + Dec(ByteLen, CN_SM4_BLOCKSIZE); + end; + end + else if Mode = SM4_DECRYPT then + begin + while ByteLen > 0 do + begin + if ByteLen >= CN_SM4_BLOCKSIZE then + begin + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], Output); // ȼ Iv + Move(Output[0], LocalIv[0], CN_SM4_BLOCKSIZE); // ܽһ + + for I := 0 to CN_SM4_BLOCKSIZE - 1 do // õ + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Output) + I))^ + xor (PByte(TCnIntAddress(Input) + I))^; + end + else + begin + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], @Tail[0]); // ȼ Iv + + for I := 0 to ByteLen - 1 do + (PByte(TCnIntAddress(Output) + I))^ := Tail[I] xor (PByte(TCnIntAddress(Input) + I))^; + end; + + Inc(Input, CN_SM4_BLOCKSIZE); + Inc(Output, CN_SM4_BLOCKSIZE); + Dec(ByteLen, CN_SM4_BLOCKSIZE); + end; + end; +end; + +// CTR ģʽݿ顣Output ȿԺ Input һȡ +procedure SM4CryptCtr(var Ctx: TCnSM4Context; Mode: Integer; ByteLen: Integer; + Nonce: PAnsiChar; Input: PAnsiChar; Output: PAnsiChar); +var + I: Integer; + LocalIv: TCnSM4Iv; + Cnt, T: Int64; +begin + Cnt := 1; + + // ּӽ + while ByteLen > 0 do + begin + if ByteLen >= CN_SM4_BLOCKSIZE then + begin + Move(Nonce^, LocalIv[0], SizeOf(TCnSM4Nonce)); + T := Int64HostToNetwork(Cnt); + Move(T, LocalIv[SizeOf(TCnSM4Nonce)], SizeOf(Int64)); + + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], @LocalIv[0]); // ȼ Iv + + for I := 0 to CN_SM4_BLOCKSIZE - 1 do // ܽ + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Input) + I))^ + xor LocalIv[I]; + end + else + begin + Move(Nonce^, LocalIv[0], SizeOf(TCnSM4Nonce)); + T := Int64HostToNetwork(Cnt); + Move(T, LocalIv[SizeOf(TCnSM4Nonce)], SizeOf(Int64)); + + SM4OneRound(@(Ctx.Sk[0]), @LocalIv[0], @LocalIv[0]); // ȼ Iv + + for I := 0 to ByteLen - 1 do // 16 ֽ + (PByte(TCnIntAddress(Output) + I))^ := (PByte(TCnIntAddress(Input) + I))^ + xor LocalIv[I]; + end; + + Inc(Input, CN_SM4_BLOCKSIZE); + Inc(Output, CN_SM4_BLOCKSIZE); + Dec(ByteLen, CN_SM4_BLOCKSIZE); + Inc(Cnt); + end; +end; + +procedure SM4CryptCbcStr(Mode: Integer; Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + Ctx: TCnSM4Context; +begin + if Length(Key) < CN_SM4_KEYSIZE then + while Length(Key) < CN_SM4_KEYSIZE do Key := Key + Chr(0) // 16 bytes at least padding 0. + else if Length(Key) > CN_SM4_KEYSIZE then + Key := Copy(Key, 1, CN_SM4_KEYSIZE); // Only keep 16 + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[1])); + SM4CryptCbc(Ctx, SM4_ENCRYPT, Length(Input), @(Iv[0]), @(Input[1]), @(Output[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyDec(Ctx, @(Key[1])); + SM4CryptCbc(Ctx, SM4_DECRYPT, Length(Input), @(Iv[0]), @(Input[1]), @(Output[0])); + end; +end; + +procedure SM4CryptCfbStr(Mode: Integer; Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + Ctx: TCnSM4Context; +begin + if Length(Key) < CN_SM4_KEYSIZE then + while Length(Key) < CN_SM4_KEYSIZE do Key := Key + Chr(0) // 16 bytes at least padding 0. + else if Length(Key) > CN_SM4_KEYSIZE then + Key := Copy(Key, 1, CN_SM4_KEYSIZE); // Only keep 16 + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[1])); + SM4CryptCfb(Ctx, SM4_ENCRYPT, Length(Input), @(Iv[0]), @(Input[1]), @(Output[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[1])); // ע CFB ĽҲõǼܣ + SM4CryptCfb(Ctx, SM4_DECRYPT, Length(Input), @(Iv[0]), @(Input[1]), @(Output[0])); + end; +end; + +procedure SM4CryptOfbStr(Mode: Integer; Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + Ctx: TCnSM4Context; +begin + if Length(Key) < CN_SM4_KEYSIZE then + while Length(Key) < CN_SM4_KEYSIZE do Key := Key + Chr(0) // 16 bytes at least padding 0. + else if Length(Key) > CN_SM4_KEYSIZE then + Key := Copy(Key, 1, CN_SM4_KEYSIZE); // Only keep 16 + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[1])); + SM4CryptOfb(Ctx, SM4_ENCRYPT, Length(Input), @(Iv[0]), @(Input[1]), @(Output[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[1])); // ע OFB ĽҲõǼܣ + SM4CryptOfb(Ctx, SM4_DECRYPT, Length(Input), @(Iv[0]), @(Input[1]), @(Output[0])); + end; +end; + +procedure SM4CryptCtrStr(Mode: Integer; Key: AnsiString; Nonce: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +var + Ctx: TCnSM4Context; +begin + if Length(Key) < CN_SM4_KEYSIZE then + while Length(Key) < CN_SM4_KEYSIZE do Key := Key + Chr(0) // 16 bytes at least padding 0. + else if Length(Key) > CN_SM4_KEYSIZE then + Key := Copy(Key, 1, CN_SM4_KEYSIZE); // Only keep 16 + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[1])); + SM4CryptCtr(Ctx, SM4_ENCRYPT, Length(Input), @(Nonce[0]), @(Input[1]), @(Output[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[1])); // ע CTR ĽҲõǼܣ + SM4CryptCtr(Ctx, SM4_DECRYPT, Length(Input), @(Nonce[0]), @(Input[1]), @(Output[0])); + end; +end; + +procedure SM4EncryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptEcbStr(SM4_ENCRYPT, Key, Input, Output); +end; + +procedure SM4DecryptEcbStr(Key: AnsiString; const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptEcbStr(SM4_DECRYPT, Key, Input, Output); +end; + +procedure SM4EncryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptCbcStr(SM4_ENCRYPT, Key, Iv, Input, Output); +end; + +procedure SM4DecryptCbcStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptCbcStr(SM4_DECRYPT, Key, Iv, Input, Output); +end; + +procedure SM4EncryptCfbStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptCfbStr(SM4_ENCRYPT, Key, Iv, Input, Output); +end; + +procedure SM4DecryptCfbStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptCfbStr(SM4_DECRYPT, Key, Iv, Input, Output); +end; + +procedure SM4EncryptOfbStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptOfbStr(SM4_ENCRYPT, Key, Iv, Input, Output); +end; + +procedure SM4DecryptOfbStr(Key: AnsiString; Iv: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptOfbStr(SM4_DECRYPT, Key, Iv, Input, Output); +end; + +procedure SM4EncryptCtrStr(Key: AnsiString; Nonce: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptCtrStr(SM4_ENCRYPT, Key, Nonce, Input, Output); +end; + +procedure SM4DecryptCtrStr(Key: AnsiString; Nonce: PAnsiChar; + const Input: AnsiString; Output: PAnsiChar); +begin + SM4CryptCtrStr(SM4_DECRYPT, Key, Nonce, Input, Output); +end; + +function SM4CryptEcbBytes(Mode: Integer; Key: TBytes; + const Input: TBytes): TBytes; +var + Ctx: TCnSM4Context; + I, Len: Integer; +begin + Len := Length(Input); + if Len <= 0 then + begin + Result := nil; + Exit; + end; + SetLength(Result, (((Len - 1) div 16) + 1) * 16); + + Len := Length(Key); + if Len < CN_SM4_KEYSIZE then // Key С 16 ֽڲ 0 + begin + SetLength(Key, CN_SM4_KEYSIZE); + for I := Len to CN_SM4_KEYSIZE - 1 do + Key[I] := 0; + end; + // ȴ 16 ֽʱ SM4SetKeyEnc ԶԺIJ + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[0])); + SM4CryptEcb(Ctx, SM4_ENCRYPT, Length(Input), @(Input[0]), @(Result[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyDec(Ctx, @(Key[0])); + SM4CryptEcb(Ctx, SM4_DECRYPT, Length(Input), @(Input[0]), @(Result[0])); + end; +end; + +function SM4CryptCbcBytes(Mode: Integer; Key, Iv: TBytes; + const Input: TBytes): TBytes; +var + Ctx: TCnSM4Context; + LocalIv: TCnSM4Iv; + I, Len: Integer; +begin + Len := Length(Input); + if Len <= 0 then + begin + Result := nil; + Exit; + end; + SetLength(Result, (((Len - 1) div 16) + 1) * 16); + + Len := Length(Key); + if Len < CN_SM4_KEYSIZE then // Key С 16 ֽڲ 0 + begin + SetLength(Key, CN_SM4_KEYSIZE); + for I := Len to CN_SM4_KEYSIZE - 1 do + Key[I] := 0; + end; + // ȴ 16 ֽʱ SM4SetKeyEnc ԶԺIJ + + MoveMost(Iv[0], LocalIv[0], Length(Iv), SizeOf(TCnSM4Iv)); + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[0])); + SM4CryptCbc(Ctx, SM4_ENCRYPT, Length(Input), @(LocalIv[0]), @(Input[0]), @(Result[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyDec(Ctx, @(Key[0])); + SM4CryptCbc(Ctx, SM4_DECRYPT, Length(Input), @(LocalIv[0]), @(Input[0]), @(Result[0])); + end; +end; + +function SM4CryptCfbBytes(Mode: Integer; Key, Iv: TBytes; + const Input: TBytes): TBytes; +var + Ctx: TCnSM4Context; + LocalIv: TCnSM4Iv; + I, Len: Integer; +begin + Len := Length(Input); + if Len <= 0 then + begin + Result := nil; + Exit; + end; + SetLength(Result, Len); // ע CFB ģʽ貹 + + Len := Length(Key); + if Len < CN_SM4_KEYSIZE then // Key С 16 ֽڲ 0 + begin + SetLength(Key, CN_SM4_KEYSIZE); + for I := Len to CN_SM4_KEYSIZE - 1 do + Key[I] := 0; + end; + // ȴ 16 ֽʱ SM4SetKeyEnc ԶԺIJ + + MoveMost(Iv[0], LocalIv[0], Length(Iv), SizeOf(TCnSM4Iv)); + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[0])); + SM4CryptCfb(Ctx, SM4_ENCRYPT, Length(Input), @(LocalIv[0]), @(Input[0]), @(Result[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[0])); // ע CFB ĽҲõǼܣ + SM4CryptCfb(Ctx, SM4_DECRYPT, Length(Input), @(LocalIv[0]), @(Input[0]), @(Result[0])); + end; +end; + +function SM4CryptOfbBytes(Mode: Integer; Key, Iv: TBytes; + const Input: TBytes): TBytes; +var + Ctx: TCnSM4Context; + LocalIv: TCnSM4Iv; + I, Len: Integer; +begin + Len := Length(Input); + if Len <= 0 then + begin + Result := nil; + Exit; + end; + SetLength(Result, Len); // ע OFB ģʽ貹 + + Len := Length(Key); + if Len < CN_SM4_KEYSIZE then // Key С 16 ֽڲ 0 + begin + SetLength(Key, CN_SM4_KEYSIZE); + for I := Len to CN_SM4_KEYSIZE - 1 do + Key[I] := 0; + end; + // ȴ 16 ֽʱ SM4SetKeyEnc ԶԺIJ + + MoveMost(Iv[0], LocalIv[0], Length(Iv), SizeOf(TCnSM4Iv)); + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[0])); + SM4CryptOfb(Ctx, SM4_ENCRYPT, Length(Input), @(LocalIv[0]), @(Input[0]), @(Result[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[0])); // ע OFB ĽҲõǼܣ + SM4CryptOfb(Ctx, SM4_DECRYPT, Length(Input), @(LocalIv[0]), @(Input[0]), @(Result[0])); + end; +end; + +function SM4CryptCtrBytes(Mode: Integer; Key, Nonce: TBytes; + const Input: TBytes): TBytes; +var + Ctx: TCnSM4Context; + LocalNonce: TCnSM4Nonce; + I, Len: Integer; +begin + Len := Length(Input); + if Len <= 0 then + begin + Result := nil; + Exit; + end; + SetLength(Result, Len); + + Len := Length(Key); + if Len < CN_SM4_KEYSIZE then // Key С 16 ֽڲ 0 + begin + SetLength(Key, CN_SM4_KEYSIZE); + for I := Len to CN_SM4_KEYSIZE - 1 do + Key[I] := 0; + end; + // ȴ 16 ֽʱ SM4SetKeyEnc ԶԺIJ + + MoveMost(Nonce[0], LocalNonce[0], Length(Nonce), SizeOf(TCnSM4Nonce)); + + if Mode = SM4_ENCRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[0])); + SM4CryptCtr(Ctx, SM4_ENCRYPT, Length(Input), @(LocalNonce[0]), @(Input[0]), @(Result[0])); + end + else if Mode = SM4_DECRYPT then + begin + SM4SetKeyEnc(Ctx, @(Key[0])); // ע CTR ĽҲõǼܣ + SM4CryptCtr(Ctx, SM4_DECRYPT, Length(Input), @(LocalNonce[0]), @(Input[0]), @(Result[0])); + end; +end; + +function SM4EncryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptEcbBytes(SM4_ENCRYPT, Key, Input); +end; + +function SM4DecryptEcbBytes(Key: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptEcbBytes(SM4_DECRYPT, Key, Input); +end; + +function SM4EncryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptCbcBytes(SM4_ENCRYPT, Key, Iv, Input); +end; + +function SM4DecryptCbcBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptCbcBytes(SM4_DECRYPT, Key, Iv, Input); +end; + +function SM4EncryptCfbBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptCfbBytes(SM4_ENCRYPT, Key, Iv, Input); +end; + +function SM4DecryptCfbBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptCfbBytes(SM4_DECRYPT, Key, Iv, Input); +end; + +function SM4EncryptOfbBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptOfbBytes(SM4_ENCRYPT, Key, Iv, Input); +end; + +function SM4DecryptOfbBytes(Key, Iv: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptOfbBytes(SM4_DECRYPT, Key, Iv, Input); +end; + +function SM4EncryptCtrBytes(Key, Nonce: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptCtrBytes(SM4_ENCRYPT, Key, Nonce, Input); +end; + +function SM4DecryptCtrBytes(Key, Nonce: TBytes; Input: TBytes): TBytes; +begin + Result := SM4CryptCtrBytes(SM4_DECRYPT, Key, Nonce, Input); +end; + +function SM4EncryptEcbBytesToHex(Key: TBytes; Input: TBytes): AnsiString; +begin + Result := AnsiString(BytesToHex(SM4EncryptEcbBytes(Key, Input))); +end; + +function SM4DecryptEcbBytesFromHex(Key: TBytes; const Input: AnsiString): TBytes; +begin + Result := SM4DecryptEcbBytes(Key, HexToBytes(string(Input))); +end; + +function SM4EncryptCbcBytesToHex(Key, Iv: TBytes; Input: TBytes): AnsiString; +begin + Result := AnsiString(BytesToHex(SM4EncryptCbcBytes(Key, Iv, Input))); +end; + +function SM4DecryptCbcBytesFromHex(Key, Iv: TBytes; const Input: AnsiString): TBytes; +begin + Result := SM4DecryptCbcBytes(Key, Iv, HexToBytes(string(Input))); +end; + +function SM4EncryptCfbBytesToHex(Key, Iv: TBytes; Input: TBytes): AnsiString; +begin + Result := AnsiString(BytesToHex(SM4EncryptCfbBytes(Key, Iv, Input))); +end; + +function SM4DecryptCfbBytesFromHex(Key, Iv: TBytes; const Input: AnsiString): TBytes; +begin + Result := SM4DecryptCfbBytes(Key, Iv, HexToBytes(string(Input))); +end; + +function SM4EncryptOfbBytesToHex(Key, Iv: TBytes; Input: TBytes): AnsiString; +begin + Result := AnsiString(BytesToHex(SM4EncryptOfbBytes(Key, Iv, Input))); +end; + +function SM4DecryptOfbBytesFromHex(Key, Iv: TBytes; const Input: AnsiString): TBytes; +begin + Result := SM4DecryptOfbBytes(Key, Iv, HexToBytes(string(Input))); +end; + +function SM4EncryptCtrBytesToHex(Key, Nonce: TBytes; Input: TBytes): AnsiString; +begin + Result := AnsiString(BytesToHex(SM4EncryptCtrBytes(Key, Nonce, Input))); +end; + +function SM4DecryptCtrBytesFromHex(Key, Nonce: TBytes; const Input: AnsiString): TBytes; +begin + Result := SM4DecryptCtrBytes(Key, Nonce, HexToBytes(string(Input))); +end; + +procedure SM4EncryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Done: Cardinal; + Ctx: TCnSM4Context; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + SM4SetKeyEnc(Ctx, @(Key[0])); + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4ReadError); + + SM4OneRound(@(Ctx.Sk[0]), @(TempIn[0]), @(TempOut[0])); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorSM4WriteError); + + Dec(Count, SizeOf(TCnSM4Buffer)); + end; + + if Count > 0 then // β 0 + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorSM4ReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + + SM4OneRound(@(Ctx.Sk[0]), @(TempIn[0]), @(TempOut[0])); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorSM4WriteError); + end; +end; + +procedure SM4DecryptStreamECB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Done: Cardinal; + Ctx: TCnSM4Context; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + if (Count mod SizeOf(TCnSM4Buffer)) > 0 then + raise ECnSM4Exception.Create(SCnErrorSM4InvalidInBufSize); + + SM4SetKeyDec(Ctx, @(Key[0])); + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4ReadError); + + SM4OneRound(@(Ctx.Sk[0]), @(TempIn[0]), @(TempOut[0])); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorSM4WriteError); + + Dec(Count, SizeOf(TCnSM4Buffer)); + end; +end; + +procedure SM4EncryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Vector: TCnSM4Iv; + Done: Cardinal; + Ctx: TCnSM4Context; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + SM4SetKeyEnc(Ctx, @(Key[0])); + + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4ReadError); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + + SM4OneRound(@(Ctx.Sk[0]), @(TempIn[0]), @(TempOut[0])); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorSM4WriteError); + + Move(TempOut[0], Vector[0], SizeOf(TCnSM4Iv)); + Dec(Count, SizeOf(TCnSM4Buffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorSM4ReadError); + FillChar(TempIn[Count], SizeOf(TempIn) - Count, 0); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@Vector[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@Vector[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@Vector[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@Vector[12])^; + + SM4OneRound(@(Ctx.Sk[0]), @(TempIn[0]), @(TempOut[0])); + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorSM4WriteError); + end; +end; + +procedure SM4DecryptStreamCBC(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Vector1, Vector2: TCnSM4Iv; + Done: Cardinal; + Ctx: TCnSM4Context; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + if (Count mod SizeOf(TCnSM4Buffer)) > 0 then + raise ECnSM4Exception.Create(SCnErrorSM4InvalidInBufSize); + + Vector1 := InitVector; + SM4SetKeyDec(Ctx, @(Key[0])); + + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorSM4ReadError); + + Move(TempIn[0], Vector2[0], SizeOf(TCnSM4Iv)); + SM4OneRound(@(Ctx.Sk[0]), @(TempIn[0]), @(TempOut[0])); + + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@Vector1[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@Vector1[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@Vector1[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@Vector1[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorSM4WriteError); + + Vector1 := Vector2; + Dec(Count, SizeOf(TCnSM4Buffer)); + end; +end; + +procedure SM4EncryptStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Vector: TCnSM4Iv; + Done: Cardinal; + Ctx: TCnSM4Context; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + SM4SetKeyEnc(Ctx, @(Key[0])); + + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4ReadError); + + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); // Key ȼ Iv + + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); // ĽдĽ + if Done < SizeOf(TempOut) then + raise EStreamError.Create(SCnErrorSM4WriteError); + + Move(TempOut[0], Vector[0], SizeOf(TCnSM4Iv)); // Ľȡ Iv һּ + Dec(Count, SizeOf(TCnSM4Buffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorSM4ReadError); + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); + + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorSM4WriteError); + end; +end; + +procedure SM4DecryptStreamCFB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Vector: TCnSM4Iv; + Done: Cardinal; + Ctx: TCnSM4Context; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + SM4SetKeyEnc(Ctx, @(Key[0])); // עǼܣǽܣ + + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); // Ķ TempIn + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorSM4ReadError); + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); // Iv ȼ TempOut + + // ܺ TempOut TempIn õ TempOut + PCardinal(@TempOut[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempOut, SizeOf(TempOut)); // TempOut дȥ + if Done < SizeOf(TempOut) then + raise EStreamError(SCnErrorSM4WriteError); + Move(TempIn[0], Vector[0], SizeOf(TCnSM4Iv)); // TempIn ȡ Iv Ϊһμ + Dec(Count, SizeOf(TCnSM4Buffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorSM4ReadError); + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); + + PCardinal(@TempOut[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempOut[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempOut[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempOut[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempOut, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorSM4WriteError); + end; +end; + +procedure SM4EncryptStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Vector: TCnSM4Iv; + Done: Cardinal; + Ctx: TCnSM4Context; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + SM4SetKeyEnc(Ctx, @(Key[0])); + + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4ReadError); + + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); // Key ȼ Iv + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4WriteError); + + Move(TempOut[0], Vector[0], SizeOf(TCnSM4Iv)); // ܽȡ Iv һּܣעⲻ + Dec(Count, SizeOf(TCnSM4Buffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorSM4ReadError); + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorSM4WriteError); + end; +end; + +procedure SM4DecryptStreamOFB(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitVector: TCnSM4Iv; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Vector: TCnSM4Iv; + Done: Cardinal; + Ctx: TCnSM4Context; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Vector := InitVector; + SM4SetKeyEnc(Ctx, @(Key[0])); // עǼܣǽܣ + + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); // Ķ TempIn + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorSM4ReadError); + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); // Iv ȼ TempOut + + // ܺ TempOut TempIn õ TempIn + PCardinal(@TempIn[0])^ := PCardinal(@TempOut[0])^ xor PCardinal(@TempIn[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempOut[4])^ xor PCardinal(@TempIn[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempOut[8])^ xor PCardinal(@TempIn[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempOut[12])^ xor PCardinal(@TempIn[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); // TempIn дȥ + if Done < SizeOf(TempIn) then + raise EStreamError(SCnErrorSM4WriteError); + Move(TempOut[0], Vector[0], SizeOf(TCnSM4Iv)); // ܽ TempOut ȡ Iv Ϊһμ + Dec(Count, SizeOf(TCnSM4Buffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorSM4ReadError); + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorSM4WriteError); + end; +end; + +procedure SM4EncryptStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitNonce: TCnSM4Nonce; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Vector: TCnSM4Iv; + Done: Cardinal; + Ctx: TCnSM4Context; + Cnt, T: Int64; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Cnt := 1; + SM4SetKeyEnc(Ctx, @(Key[0])); + + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4ReadError); + + // Nonce ͼƴ Iv + T := Int64HostToNetwork(Cnt); + Move(InitNonce[0], Vector[0], SizeOf(TCnSM4Nonce)); + Move(T, Vector[SizeOf(TCnSM4Nonce)], SizeOf(Int64)); + + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); // Key ȼ Iv + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4WriteError); + + Inc(Cnt); + Dec(Count, SizeOf(TCnSM4Buffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorSM4ReadError); + + // Nonce ͼƴ Iv + T := Int64HostToNetwork(Cnt); + Move(InitNonce[0], Vector[0], SizeOf(TCnSM4Nonce)); + Move(T, Vector[SizeOf(TCnSM4Nonce)], SizeOf(Int64)); + + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorSM4WriteError); + end; +end; + +procedure SM4DecryptStreamCTR(Source: TStream; Count: Cardinal; + const Key: TCnSM4Key; const InitNonce: TCnSM4Nonce; Dest: TStream); +var + TempIn, TempOut: TCnSM4Buffer; + Vector: TCnSM4Iv; + Done: Cardinal; + Ctx: TCnSM4Context; + Cnt, T: Int64; +begin + if Count = 0 then + begin + Source.Position := 0; + Count := Source.Size; + end + else + Count := Min(Count, Source.Size - Source.Position); + + if Count = 0 then + Exit; + + Cnt := 1; + SM4SetKeyEnc(Ctx, @(Key[0])); // עǼܣǽܣ + + while Count >= SizeOf(TCnSM4Buffer) do + begin + Done := Source.Read(TempIn, SizeOf(TempIn)); + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4ReadError); + + // Nonce ͼƴ Iv + T := Int64HostToNetwork(Cnt); + Move(InitNonce[0], Vector[0], SizeOf(TCnSM4Nonce)); + Move(T, Vector[SizeOf(TCnSM4Nonce)], SizeOf(Int64)); + + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); // Key ȼ Iv + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; // ܽ + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, SizeOf(TempIn)); // ĽдĽ + if Done < SizeOf(TempIn) then + raise EStreamError.Create(SCnErrorSM4WriteError); + + Inc(Cnt); + Dec(Count, SizeOf(TCnSM4Buffer)); + end; + + if Count > 0 then + begin + Done := Source.Read(TempIn, Count); + if Done < Count then + raise EStreamError.Create(SCnErrorSM4ReadError); + + // Nonce ͼƴ Iv + T := Int64HostToNetwork(Cnt); + Move(InitNonce[0], Vector[0], SizeOf(TCnSM4Nonce)); + Move(T, Vector[SizeOf(TCnSM4Nonce)], SizeOf(Int64)); + + SM4OneRound(@(Ctx.Sk[0]), @(Vector[0]), @(TempOut[0])); + + PCardinal(@TempIn[0])^ := PCardinal(@TempIn[0])^ xor PCardinal(@TempOut[0])^; + PCardinal(@TempIn[4])^ := PCardinal(@TempIn[4])^ xor PCardinal(@TempOut[4])^; + PCardinal(@TempIn[8])^ := PCardinal(@TempIn[8])^ xor PCardinal(@TempOut[8])^; + PCardinal(@TempIn[12])^ := PCardinal(@TempIn[12])^ xor PCardinal(@TempOut[12])^; + + Done := Dest.Write(TempIn, Count); // дֻijȵIJ֣ + if Done < Count then + raise EStreamError.Create(SCnErrorSM4WriteError); + end; +end; + +function SM4GetOutputLengthFromInputLength(InputByteLength: Integer): Integer; +begin + Result := (((InputByteLength - 1) div CN_SM4_BLOCKSIZE) + 1) * CN_SM4_BLOCKSIZE; +end; + +procedure SM4Encrypt(Key: PAnsiChar; Input: PAnsiChar; Output: PAnsiChar; ByteLen: Integer); +var + Ctx: TCnSM4Context; +begin + SM4SetKeyEnc(Ctx, Key); + SM4CryptEcb(Ctx, SM4_ENCRYPT, ByteLen, Input, Output); +end; + +procedure SM4Decrypt(Key: PAnsiChar; Input: PAnsiChar; Output: PAnsiChar; ByteLen: Integer); +var + Ctx: TCnSM4Context; +begin + SM4SetKeyDec(Ctx, Key); + SM4CryptEcb(Ctx, SM4_DECRYPT, ByteLen, Input, Output); +end; + +end. diff --git a/MAINTAINING-CNPACK-SUBSET.md b/MAINTAINING-CNPACK-SUBSET.md new file mode 100644 index 0000000..55b0e9c --- /dev/null +++ b/MAINTAINING-CNPACK-SUBSET.md @@ -0,0 +1,100 @@ +# Maintaining the bundled CnPack subset (boss-installability) + +**Read this before touching `CnPack/`, releasing a new tag, or running the fork-sync.** + +## Why this fork exists + +`freitasjca/Delphi-Cross-Socket` is a fork of +[`winddriver/Delphi-Cross-Socket`](https://github.com/winddriver/Delphi-Cross-Socket) +whose **only reason to exist is to be installable with [Boss](https://github.com/HashLoad/boss)** +(the Delphi package manager). Two upstreams block that: + +- **`winddriver/Delphi-Cross-Socket`** ships no `boss.json`. +- **CnPack / [`cnpack/cnvcl`](https://github.com/cnpack/cnvcl)** — a *dependency* of + Delphi-Cross-Socket's SSL/crypto layer — also has no `boss.json` and is a huge repo. + +So this fork adds (a) a `boss.json`, (b) the **minimal CnPack subset** that +Delphi-Cross-Socket actually needs, vendored under `CnPack/`, and (c) the mTLS additions +(`Net/Net.CrossSslSocket.{Base,OpenSSL}.pas`). A consumer (e.g. +[`horse-provider-crosssocket`](https://github.com/freitasjca/horse-provider-crosssocket)) +can then `boss install` this fork and compile **without ever touching cnvcl**. + +> The `boss.json` `description` currently says *"adds Boss package manifest only. Zero source +> changes"* — that is **stale**: the fork also vendors the CnPack subset and the mTLS patches. +> Update it when convenient. + +## The invariant — what must always hold + +The vendored subset **must be a complete, self-contained transitive closure** so the package +compiles standalone: + +1. **`CnPack/Common/CnPack.inc` must be present.** Every Cn unit begins with `{$I CnPack.inc}`; + without it nothing compiles. +2. **Every unit named in any `uses` clause of a bundled unit must also be bundled.** If you add + a Crypto unit that pulls in a new `Cn*` dependency, that dependency has to be copied in too. +3. The split mirrors cnvcl's own layout: foundation units in `CnPack/Common/`, crypto in + `CnPack/Crypto/`. + +### Current inventory (18 files — keep this list and the fork-sync in step) + +``` +CnPack/Common/ CnPack.inc CnConsts.pas CnFloat.pas CnStrings.pas CnWideStrings.pas +CnPack/Crypto/ CnAES.pas CnBase64.pas CnDES.pas CnKDF.pas CnMD5.pas CnNative.pas + CnPemUtils.pas CnRandom.pas CnSHA1.pas CnSHA2.pas CnSHA3.pas + CnSM3.pas CnSM4.pas +``` + +> History: earlier releases kept everything under `CnPack/Crypto/` (14 units). cnvcl later +> moved the foundation units to `Source/Common/` and added `CnStrings`, `CnWideStrings`, +> `CnSM4`; the v1.0.3 re-sync follows that — hence the `Common/` directory. + +## Re-syncing the subset when cnvcl updates + +1. Update your local cnvcl: `cd cnvcl && git pull --ff-only origin master`. +2. Copy the units above from cnvcl into the fork: + - `cnvcl/Source/Common/{CnPack.inc,CnConsts,CnFloat,CnStrings,CnWideStrings}` → `CnPack/Common/` + - `cnvcl/Source/Crypto/{the 13 crypto units}.pas` → `CnPack/Crypto/` + - (verify the cnvcl source-side paths — cnvcl occasionally relocates units between + `Source/Common` and `Source/Crypto`.) +3. **Re-validate the closure** — the only authoritative check (the CnPack sources are + **GBK/ANSI-encoded**, which defeats `grep`-based scans): `boss install` this fork into a + throwaway project, or build `horse-provider-crosssocket` against it, and confirm a clean + compile with **no missing `Cn*` unit**. If the compiler reports a missing unit, copy it in + and repeat. +4. Commit the subset change on its own (`git add -A CnPack/` so renames register), separate + from version bumps and `.gitattributes` changes. + +## ⚠️ Keep the fork-sync automation in step — or it reverts the subset + +The fork-sync (`crosssocket-fork-sync-action/` → deployed to the fork's `master` as a daily +GitHub Action) **resets `master` to upstream's tip and re-layers the CnPack subset from a +hardcoded list**. If that list doesn't match the inventory above, the next nightly run +**silently restores the wrong subset and breaks the boss build.** Two files must be updated +together with any subset change: + +- `.github/workflows/sync-upstream.yml` — the `Clone CnPack (cnvcl) and copy required files` + step (the actual `cp` list + the `mkdir CnPack/Common CnPack/Crypto`). +- `.sync/README.md` — the human-readable manifest table (fork path ← cnvcl source path). + +Optionally pin `CNVCL_REF` in `sync-upstream.yml` to a validated cnvcl tag/sha instead of +`master`, so a surprise upstream cnvcl change can't break a nightly sync. + +## Consumer-side note + +Because the foundation units live in `CnPack/Common/`, any consuming project's search path must +include **both** `CnPack/Common` **and** `CnPack/Crypto` (see the "Required search paths" list +in `horse-provider-crosssocket`'s README). Adding only `Crypto/` will fail to resolve +`CnConsts`/`CnFloat`/`CnStrings`/`CnWideStrings`. + +## Don't track build/IDE artifacts + +`.dcu`, `.res`, `.dproj.local`, `.dsv`, `__history/` must stay out of the repo (they bloat it +and create false "modified" churn). They are covered by `.gitignore`; if any are already +tracked, `git rm --cached` them. + +## Endgame + +The mTLS additions are pending an upstream PR. Once upstream merges them **and** a boss-friendly +distribution of Delphi-Cross-Socket + CnPack exists, this fork (and this whole subset-maintenance +burden) can be retired. Until then, every cnvcl bump is a re-sync chore — keep this doc, the +inventory, and the fork-sync manifest aligned. diff --git a/Net/Demos/Delphi/HttpClient/HttpClient.dproj b/Net/Demos/Delphi/HttpClient/HttpClient.dproj index e13e632..2c2470e 100644 --- a/Net/Demos/Delphi/HttpClient/HttpClient.dproj +++ b/Net/Demos/Delphi/HttpClient/HttpClient.dproj @@ -4,7 +4,7 @@
// AData: 数据指针
- /// // ACount: 数据大小
- /// // Result: 如果返回True, 则发送数据; 如果返回False, 则忽略AData和ACount并结束发送
- /// function(const AData: PPointer; const ACount: PNativeInt): Boolean
- /// begin
- /// end
- ///
- ///
- /// 压缩方式
- ///
- ///
- /// 回调函数
- ///
- /// // AData: 数据指针
- /// // ACount: 数据大小
- /// // Result: 如果返回True, 则发送数据; 如果返回False, 则忽略AData和ACount并结束发送
- /// function(const AData: PPointer; const ACount: PNativeInt): Boolean
- /// begin
- /// end
- ///
- ///
- /// 回调函数
- ///
- /// // 在线程池中处理业务逻辑
- /// FCrossHttpServer.Route('GET', '/runtask/:name',
- /// procedure(ARequest: ICrossHttpRequest; AResponse: ICrossHttpResponse)
- /// begin
- /// System.Threading.TTask.Run(
- /// procedure
- /// begin
- /// CallTask(ARequest.Params['name']);
- /// end);
- /// end);
- /// // 正则表达式
- /// FCrossHttpServer.Route('GET', '/query/:count(\d+)',
- /// procedure(ARequest: ICrossHttpRequest; AResponse: ICrossHttpResponse)
- /// begin
- /// System.Threading.TTask.Run(
- /// procedure
- /// begin
- /// CallQuery(ARequest.Params['count'].ToInteger);
- /// end);
- /// end);
- /// // AData: 数据指针
+ /// // ACount: 数据大小
+ /// // Result: 如果返回True, 则发送数据; 如果返回False, 则忽略AData和ACount并结束发送
+ /// function(const AData: PPointer; const ACount: PNativeInt): Boolean
+ /// begin
+ /// end
+ ///
+ ///
+ /// 压缩方式
+ ///
+ ///
+ /// 回调函数
+ ///
+ /// // AData: 数据指针
+ /// // ACount: 数据大小
+ /// // Result: 如果返回True, 则发送数据; 如果返回False, 则忽略AData和ACount并结束发送
+ /// function(const AData: PPointer; const ACount: PNativeInt): Boolean
+ /// begin
+ /// end
+ ///
+ ///
+ /// 回调函数
+ ///
+ /// // 在线程池中处理业务逻辑
+ /// FCrossHttpServer.Route('GET', '/runtask/:name',
+ /// procedure(ARequest: ICrossHttpRequest; AResponse: ICrossHttpResponse)
+ /// begin
+ /// System.Threading.TTask.Run(
+ /// procedure
+ /// begin
+ /// CallTask(ARequest.Params['name']);
+ /// end);
+ /// end);
+ /// // 正则表达式
+ /// FCrossHttpServer.Route('GET', '/query/:count(\d+)',
+ /// procedure(ARequest: ICrossHttpRequest; AResponse: ICrossHttpResponse)
+ /// begin
+ /// System.Threading.TTask.Run(
+ /// procedure
+ /// begin
+ /// CallQuery(ARequest.Params['count'].ToInteger);
+ /// end);
+ /// end);
+ ///