source upload

This commit is contained in:
Razor12911
2022-01-17 22:16:47 +02:00
parent 12936d065b
commit 098e8c48de
1778 changed files with 1206749 additions and 0 deletions

View File

@@ -0,0 +1,157 @@
@echo off
cls
setlocal enableextensions
setlocal enabledelayedexpansion
echo.
echo Compiles for all Delphis in %ProgramFiles(x86)%\Embarcadero
echo TODO : switch to paths read out of registry
echo HKCU\Software\Embarcadero\BDS\*.0 : RootDir
echo.
echo Compiles as well for Lazarus/FPC in C:\lazarus
echo.
echo creates one directory per DelphiVersion+ProjectConfig with the DCUs
echo ..\Compiled\DCU_IDE$(ProductVersion)_$(Platform)_$(Config)
echo.
title CLEAR
echo.
echo ##### CLEAR #####
echo.
echo delete "..\Compiled"
echo.
del "%~dpn0.log"
rd /s /q "%~dp0..\Compiled"
cd /d "%ProgramFiles(x86)%\Embarcadero"
for /r %%X in (rsvars*.bat) do call :run_compiler "%%X"
echo.
title %comspec%
type "%~dpn0.log"
echo.
find /c "FAIL " "%~dpn0.log" >nul
if not errorlevel 1 pause
exit /b
:run_compiler
title COMPILE
echo.
echo ##### %~dp1 #####
echo.
setlocal
call "%~1"
set IDEVER=unknown
for /f "delims=" %%E in ("%BDS%") do set IDEVER=%%~nxE
echo. >> "%~dpn0.log"
echo ### Delphi %IDEVER% ### >> "%~dpn0.log"
echo. >> "%~dpn0.log"
::::: Lazarus-DCUs :::::
title COMPILE Lazarus x86_64 win64 : Source\DEC60Lazarus.lpk
echo ### Lazarus x86_64 win64 # Source\DEC60Lazarus.lpk
C:\lazarus\lazbuild.exe --build-all --cpu=x86_64 --build-mode=Default "%~dp0\DEC60Lazarus.lpk"
if errorlevel 1 (
echo FAIL Source\DEC60Lazarus.lpk : x86_64 win64 >> "%~dpn0.log"
rundll32 user32.dll,MessageBeep
timeout 11
) else (
echo OK Source\DEC60Lazarus.lpk : x86_64 win64 >> "%~dpn0.log"
)
echo.
title COMPILE Lazarus i386 win32 : Source\DEC60Lazarus.lpk
echo ### Lazarus i386 win32 # Source\DEC60Lazarus.lpk
C:\lazarus\lazbuild.exe --build-all --cpu=i386 --build-mode=Default "%~dp0\DEC60Lazarus.lpk"
if errorlevel 1 (
echo FAIL Source\DEC60Lazarus.lpk : i386 win32 >> "%~dpn0.log"
rundll32 user32.dll,MessageBeep
timeout 11
) else (
echo OK Source\DEC60Lazarus.lpk : i386 win32 >> "%~dpn0.log"
)
echo.
::::: Delphi-DCUs :::::
for %%P in (Win32,Win64,Linux64,Android,Android64,iOSDevice64,iOSSimulator,OSX32,OSX64) do (
for %%C in (Debug,Release) do (
call :do_compile "Source\DEC60.dproj" %%P %%C
)
)
::::: TestApps :::::
echo. >> "%~dpn0.log"
for %%P in (Win32) do (
for %%C in (Debug,Console) do (
call :do_compile "Unit Tests\DECDUnitTestSuite.dproj" %%P %%C
)
for %%C in (Debug,GUI,MobileGUI,TestInsight) do (
call :do_compile "Unit Tests\DECDUnitXTestSuite.dproj" %%P %%C
)
)
::::: DemoApps :::::
echo. >> "%~dpn0.log"
call :do_compile "Demos\Cipher_Console\Cipher_Console.dproj"
call :do_compile "Demos\Cipher_FMX\Cipher_FMX.dproj"
call :do_compile "Demos\CryptoWorkbench_VCL\CryptoWorkbench_VCL.dproj"
call :do_compile "Demos\Format_Console\Format_Console.dproj"
call :do_compile "Demos\Hash_Console\Hash_Console.dproj"
call :do_compile "Demos\Hash_FMX\Hash_FMX.dproj"
call :do_compile "Demos\Progress_VCL\Progress_VCL.dproj"
call :do_compile "Demos\Random_Console\Random_Console.dproj"
echo. >> "%~dpn0.log"
title RUN Tests
echo ##### RUN Tests #####
echo.
REM for %%C in (Debug,Console,GUI) do (
REM for %%P in (Win32) do (
REM call :do_execute DECDUnitTestSuite.exe %%P %%C
REM call :do_execute DECDUnitXTestSuite.exe %%P %%C
REM )
REM )
call :do_execute DECDUnitTestSuite.exe Win32 Console
call :do_execute DECDUnitTestSuite.exe Win32 Debug
call :do_execute DECDUnitXTestSuite.exe Win32 Debug
call :do_execute DECDUnitXTestSuite.exe Win32 GUI
endlocal
exit /b
:do_compile
title COMPILE %IDEVER% %2 %3 : %~1
echo ### %IDEVER% %2 %3 # %~1
set params=
if not "%2" == "" set params=/p:Platform=%2 /p:Config=%3
REM msbuild "%~dp0..\%~1" /t:Rebuild %params% :: $(ProductVersion) is missing in msbuild, but is present in InlineCompiler of the IDE
msbuild "%~dp0..\%~1" /t:Rebuild %params% /p:ProductVersion=%IDEVER%
if errorlevel 1 (
echo FAIL %~1 : %2 %3 >> "%~dpn0.log"
rundll32 user32.dll,MessageBeep
timeout 11
) else (
echo OK %~1 : %2 %3 >> "%~dpn0.log"
)
:: remove dir if empty
if not "%2" == "" (
rd /q "%~dp0..\Compiled\BIN_IDE%IDEVER%_%2_%3" >nul
rd /q "%~dp0..\Compiled\DCP_IDE%IDEVER%_%2_%3" >nul
rd /q "%~dp0..\Compiled\DCU_IDE%IDEVER%_%2_%3" >nul
)
echo.
exit /b
:do_execute
title EXECUTE %IDEVER% %2 %3 : %~1
echo ### %IDEVER% %2 %3 # %~1
"%~dp0..\Compiled\BIN_IDE%IDEVER%_%2_%3\%~1"
set "ERR=%ERRORLEVEL% "
echo RUN:%ERR:~0,6% %~1 : %2 %3 >> "%~dpn0.log"
echo EXITCODE:%ERR%
echo.
exit /b

View File

@@ -0,0 +1,56 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
// Simple project group for easier DEC development
program DEC60;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
DECBaseClass in 'DECBaseClass.pas',
DECCipherBase in 'DECCipherBase.pas',
DECCipherFormats in 'DECCipherFormats.pas',
DECCipherModes in 'DECCipherModes.pas',
DECCipherInterface in 'DECCipherInterface.pas',
DECCiphers in 'DECCiphers.pas',
DECCRC in 'DECCRC.pas',
DECData in 'DECData.pas',
DECDataCipher in 'DECDataCipher.pas',
DECDataHash in 'DECDataHash.pas',
DECFormat in 'DECFormat.pas',
DECFormatBase in 'DECFormatBase.pas',
DECHash in 'DECHash.pas',
DECHashBase in 'DECHashBase.pas',
DECHashInterface in 'DECHashInterface.pas',
DECRandom in 'DECRandom.pas',
DECTypes in 'DECTypes.pas',
DECUtil in 'DECUtil.pas',
DECUtilRawByteStringHelper in 'DECUtilRawByteStringHelper.pas',
DECHashAuthentication in 'DECHashAuthentication.pas',
DECHashBitBase in 'DECHashBitBase.pas';
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
except
on E: Exception do
WriteLn(E.ClassName, ': ', E.Message);
end;
end.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,156 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{46A7B5B1-D413-4DB1-A118-2403457B463A}</ProjectGuid>
</PropertyGroup>
<ItemGroup>
<Projects Include="DEC60.dproj">
<Dependencies/>
</Projects>
<Projects Include="..\Unit Tests\DECDUnitTestSuite.dproj">
<Dependencies/>
</Projects>
<Projects Include="..\Unit Tests\DECDUnitXTestSuite.dproj">
<Dependencies/>
</Projects>
<Projects Include="..\Demos\Cipher_Console\Cipher_Console.dproj">
<Dependencies/>
</Projects>
<Projects Include="..\Demos\Cipher_FMX\Cipher_FMX.dproj">
<Dependencies/>
</Projects>
<Projects Include="..\Demos\Format_Console\Format_Console.dproj">
<Dependencies/>
</Projects>
<Projects Include="..\Demos\Hash_Console\Hash_Console.dproj">
<Dependencies/>
</Projects>
<Projects Include="..\Demos\Hash_FMX\Hash_FMX.dproj">
<Dependencies/>
</Projects>
<Projects Include="..\Demos\Random_Console\Random_Console.dproj">
<Dependencies/>
</Projects>
<Projects Include="..\Demos\Progress_VCL\ProgressDemoVCL.dproj">
<Dependencies/>
</Projects>
<Projects Include="..\Demos\HashBenchmark_FMX\HashBenchmark.dproj">
<Dependencies/>
</Projects>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Default.Personality.12</Borland.Personality>
<Borland.ProjectType/>
<BorlandProject>
<Default.Personality/>
</BorlandProject>
</ProjectExtensions>
<Target Name="DEC60">
<MSBuild Projects="DEC60.dproj"/>
</Target>
<Target Name="DEC60:Clean">
<MSBuild Projects="DEC60.dproj" Targets="Clean"/>
</Target>
<Target Name="DEC60:Make">
<MSBuild Projects="DEC60.dproj" Targets="Make"/>
</Target>
<Target Name="DECDUnitTestSuite">
<MSBuild Projects="..\Unit Tests\DECDUnitTestSuite.dproj"/>
</Target>
<Target Name="DECDUnitTestSuite:Clean">
<MSBuild Projects="..\Unit Tests\DECDUnitTestSuite.dproj" Targets="Clean"/>
</Target>
<Target Name="DECDUnitTestSuite:Make">
<MSBuild Projects="..\Unit Tests\DECDUnitTestSuite.dproj" Targets="Make"/>
</Target>
<Target Name="DECDUnitXTestSuite">
<MSBuild Projects="..\Unit Tests\DECDUnitXTestSuite.dproj"/>
</Target>
<Target Name="DECDUnitXTestSuite:Clean">
<MSBuild Projects="..\Unit Tests\DECDUnitXTestSuite.dproj" Targets="Clean"/>
</Target>
<Target Name="DECDUnitXTestSuite:Make">
<MSBuild Projects="..\Unit Tests\DECDUnitXTestSuite.dproj" Targets="Make"/>
</Target>
<Target Name="Cipher_Console">
<MSBuild Projects="..\Demos\Cipher_Console\Cipher_Console.dproj"/>
</Target>
<Target Name="Cipher_Console:Clean">
<MSBuild Projects="..\Demos\Cipher_Console\Cipher_Console.dproj" Targets="Clean"/>
</Target>
<Target Name="Cipher_Console:Make">
<MSBuild Projects="..\Demos\Cipher_Console\Cipher_Console.dproj" Targets="Make"/>
</Target>
<Target Name="Cipher_FMX">
<MSBuild Projects="..\Demos\Cipher_FMX\Cipher_FMX.dproj"/>
</Target>
<Target Name="Cipher_FMX:Clean">
<MSBuild Projects="..\Demos\Cipher_FMX\Cipher_FMX.dproj" Targets="Clean"/>
</Target>
<Target Name="Cipher_FMX:Make">
<MSBuild Projects="..\Demos\Cipher_FMX\Cipher_FMX.dproj" Targets="Make"/>
</Target>
<Target Name="Format_Console">
<MSBuild Projects="..\Demos\Format_Console\Format_Console.dproj"/>
</Target>
<Target Name="Format_Console:Clean">
<MSBuild Projects="..\Demos\Format_Console\Format_Console.dproj" Targets="Clean"/>
</Target>
<Target Name="Format_Console:Make">
<MSBuild Projects="..\Demos\Format_Console\Format_Console.dproj" Targets="Make"/>
</Target>
<Target Name="Hash_Console">
<MSBuild Projects="..\Demos\Hash_Console\Hash_Console.dproj"/>
</Target>
<Target Name="Hash_Console:Clean">
<MSBuild Projects="..\Demos\Hash_Console\Hash_Console.dproj" Targets="Clean"/>
</Target>
<Target Name="Hash_Console:Make">
<MSBuild Projects="..\Demos\Hash_Console\Hash_Console.dproj" Targets="Make"/>
</Target>
<Target Name="Hash_FMX">
<MSBuild Projects="..\Demos\Hash_FMX\Hash_FMX.dproj"/>
</Target>
<Target Name="Hash_FMX:Clean">
<MSBuild Projects="..\Demos\Hash_FMX\Hash_FMX.dproj" Targets="Clean"/>
</Target>
<Target Name="Hash_FMX:Make">
<MSBuild Projects="..\Demos\Hash_FMX\Hash_FMX.dproj" Targets="Make"/>
</Target>
<Target Name="Random_Console">
<MSBuild Projects="..\Demos\Random_Console\Random_Console.dproj"/>
</Target>
<Target Name="Random_Console:Clean">
<MSBuild Projects="..\Demos\Random_Console\Random_Console.dproj" Targets="Clean"/>
</Target>
<Target Name="Random_Console:Make">
<MSBuild Projects="..\Demos\Random_Console\Random_Console.dproj" Targets="Make"/>
</Target>
<Target Name="ProgressDemoVCL">
<MSBuild Projects="..\Demos\Progress_VCL\ProgressDemoVCL.dproj"/>
</Target>
<Target Name="ProgressDemoVCL:Clean">
<MSBuild Projects="..\Demos\Progress_VCL\ProgressDemoVCL.dproj" Targets="Clean"/>
</Target>
<Target Name="ProgressDemoVCL:Make">
<MSBuild Projects="..\Demos\Progress_VCL\ProgressDemoVCL.dproj" Targets="Make"/>
</Target>
<Target Name="HashBenchmark">
<MSBuild Projects="..\Demos\HashBenchmark_FMX\HashBenchmark.dproj"/>
</Target>
<Target Name="HashBenchmark:Clean">
<MSBuild Projects="..\Demos\HashBenchmark_FMX\HashBenchmark.dproj" Targets="Clean"/>
</Target>
<Target Name="HashBenchmark:Make">
<MSBuild Projects="..\Demos\HashBenchmark_FMX\HashBenchmark.dproj" Targets="Make"/>
</Target>
<Target Name="Build">
<CallTarget Targets="DEC60;DECDUnitTestSuite;DECDUnitXTestSuite;Cipher_Console;Cipher_FMX;Format_Console;Hash_Console;Hash_FMX;Random_Console;ProgressDemoVCL;HashBenchmark"/>
</Target>
<Target Name="Clean">
<CallTarget Targets="DEC60:Clean;DECDUnitTestSuite:Clean;DECDUnitXTestSuite:Clean;Cipher_Console:Clean;Cipher_FMX:Clean;Format_Console:Clean;Hash_Console:Clean;Hash_FMX:Clean;Random_Console:Clean;ProgressDemoVCL:Clean;HashBenchmark:Clean"/>
</Target>
<Target Name="Make">
<CallTarget Targets="DEC60:Make;DECDUnitTestSuite:Make;DECDUnitXTestSuite:Make;Cipher_Console:Make;Cipher_FMX:Make;Format_Console:Make;Hash_Console:Make;Hash_FMX:Make;Random_Console:Make;ProgressDemoVCL:Make;HashBenchmark:Make"/>
</Target>
<Import Project="$(BDS)\Bin\CodeGear.Group.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')"/>
</Project>

View File

@@ -0,0 +1,2 @@
<?xml version="1.0"?>
<TgConfig Version="3" SubLevelDisabled="False" />

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<Package Version="4">
<PathDelim Value="\"/>
<Name Value="DEC60Lazarus"/>
<Author Value="geheimniswelten"/>
<AutoUpdate Value="Manually"/>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<SearchPaths>
<UnitOutputDirectory Value="$(PkgDir)\..\Compiled\DCU_Lazarus_$(TargetCPU)_$(TargetOS)_$(BuildMode)\"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<SyntaxMode Value="DelphiUnicode"/>
</SyntaxOptions>
</Parsing>
</CompilerOptions>
<Description Value="Delphi Encryption Compendium (DEC)"/>
<License Value="AFL 2.0"/>
<Version Major="6"/>
<Files Count="21">
<Item1>
<Filename Value="DECBaseClass.pas"/>
<UnitName Value="DECBaseClass"/>
</Item1>
<Item2>
<Filename Value="DECCipherBase.pas"/>
<UnitName Value="DECCipherBase"/>
</Item2>
<Item3>
<Filename Value="DECCipherFormats.pas"/>
<UnitName Value="DECCipherFormats"/>
</Item3>
<Item4>
<Filename Value="DECCipherInterface.pas"/>
<UnitName Value="DECCipherInterface"/>
</Item4>
<Item5>
<Filename Value="DECCipherModes.pas"/>
<UnitName Value="DECCipherModes"/>
</Item5>
<Item6>
<Filename Value="DECCiphers.pas"/>
<UnitName Value="DECCiphers"/>
</Item6>
<Item7>
<Filename Value="DECCRC.pas"/>
<UnitName Value="DECCRC"/>
</Item7>
<Item8>
<Filename Value="DECData.pas"/>
<UnitName Value="DECData"/>
</Item8>
<Item9>
<Filename Value="DECDataCipher.pas"/>
<UnitName Value="DECDataCipher"/>
</Item9>
<Item10>
<Filename Value="DECDataHash.pas"/>
<UnitName Value="DECDataHash"/>
</Item10>
<Item11>
<Filename Value="DECFormat.pas"/>
<UnitName Value="DECFormat"/>
</Item11>
<Item12>
<Filename Value="DECFormatBase.pas"/>
<UnitName Value="DECFormatBase"/>
</Item12>
<Item13>
<Filename Value="DECHash.pas"/>
<UnitName Value="DECHash"/>
</Item13>
<Item14>
<Filename Value="DECHashBase.pas"/>
<UnitName Value="DECHashBase"/>
</Item14>
<Item15>
<Filename Value="DECHashInterface.pas"/>
<UnitName Value="DECHashInterface"/>
</Item15>
<Item16>
<Filename Value="DECRandom.pas"/>
<UnitName Value="DECRandom"/>
</Item16>
<Item17>
<Filename Value="DECTypes.pas"/>
<UnitName Value="DECTypes"/>
</Item17>
<Item18>
<Filename Value="DECUtil.pas"/>
<UnitName Value="DECUtil"/>
</Item18>
<Item19>
<Filename Value="DECUtilRawByteStringHelper.pas"/>
<UnitName Value="DECUtilRawByteStringHelper"/>
</Item19>
<Item20>
<Filename Value="DECHash.asm86.inc"/>
<Type Value="Include"/>
</Item20>
<Item21>
<Filename Value="DECOptions.inc"/>
<Type Value="Include"/>
</Item21>
</Files>
<RequiredPkgs Count="1">
<Item1>
<PackageName Value="FCL"/>
</Item1>
</RequiredPkgs>
<PublishOptions>
<Version Value="2"/>
<OpenInFileMan Value="True"/>
<UseFileFilters Value="True"/>
</PublishOptions>
</Package>
</CONFIG>

View File

@@ -0,0 +1,18 @@
{ This file was automatically created by Lazarus. Do not edit!
This source is only used to compile and install the package.
}
unit DEC60Lazarus;
{$warn 5023 off : no warning about unused units}
interface
uses
DECBaseClass, DECCipherBase, DECCipherFormats, DECCipherInterface,
DECCipherModes, DECCiphers, DECCRC, DECData, DECDataCipher, DECDataHash,
DECFormat, DECFormatBase, DECHash, DECHashBase, DECHashInterface, DECRandom,
DECTypes, DECUtil, DECUtilRawByteStringHelper;
implementation
end.

View File

@@ -0,0 +1,2 @@
<?xml version="1.0"?>
<TgConfig Version="3" SubLevelDisabled="False" />

View File

@@ -0,0 +1,376 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
unit DECBaseClass;
interface
{$INCLUDE DECOptions.inc}
uses
{$IFDEF FPC}
SysUtils, Classes,
{$ELSE}
System.SysUtils, System.Classes,
{$ENDIF}
Generics.Collections;
type
/// <summary>
/// Class type for the base class from which all other DEC classes inherit
/// in order to be able to create lists of classes, pick an entry of such a
/// list and construct an object out of it
/// </summary>
TDECClass = class of TDECObject;
/// <summary>
/// Generic list of DEC classes with the identity as key
/// </summary>
TDECClassList = class(TDictionary<Int64, TDECClass>)
strict private
/// <summary>
/// Checks if a given class type has the same short class name as given
/// </summary>
/// <param name="Name">
/// Short class name, e.g. HEXL
/// </param>
/// <param name="ClassType">
/// Class reference to check against
/// </param>
/// <returns>
/// true if the class reference is for the given short name
/// </returns>
function DoFindNameShort(const Name: string; const ClassType: TDECClass): Boolean;
/// <summary>
/// Checks if a given class type has the same long class name as given
/// </summary>
/// <param name="Name">
/// Long class name, e.g. TFormat_HEXL
/// </param>
/// <param name="ClassType">
/// Class reference to check against
/// </param>
/// <returns>
/// true if the class reference is for the given long name
/// </returns>
function DoFindNameLong(const Name: string; const ClassType: TClass): Boolean;
public
/// <summary>
/// Tries to find a class type by its name
/// </summary>
/// <param name="Name">
/// Name to look for in the list
/// </param>
/// <returns>
/// Returns the class type if found. if it could not be found a
/// EDECClassNotRegisteredException will be thrown
/// </returns>
function ClassByName(const Name: string): TDECClass;
/// <summary>
/// Tries to find a class type by its numeric identity DEC assigned to it.
/// Useful for file headers, so they can easily encode numerically which
/// cipher class was being used.
/// </summary>
/// <param name="Identity">
/// Identity to look for
/// </param>
/// <returns>
/// Returns the class type of the class with the specified identity value
/// or throws an EDECClassNotRegisteredException exception if no class
/// with the given identity has been found
/// </returns>
function ClassByIdentity(Identity: Int64): TDECClass;
/// <summary>
/// Returns a list of all classes registered in this list
/// </summary>
/// <param name="List">
/// List where the registered classes shall be added to. The string is the
/// long class name, the object the class reference. The list is being
/// cleared first and when an uncreated list is given nothing is being done
/// </param>
procedure GetClassList(List: TStrings);
end;
/// <summary>
/// Parent class of all cryptography and hash implementations
/// </summary>
TDECObject = class(TInterfacedObject)
public
/// <summary>
/// Overrideable but otherwise empty constructor (calls his parent
/// constructor or course)
/// </summary>
constructor Create; virtual;
/// <summary>
/// This function creates a unique Signature for each class using the
/// following naming scheme:
///
/// 'Z' repeated n times (to fill space of 256 chars) + DEC ClassName
///
/// The CRC32 of the generated Signature is used as our unique Identity
///
/// Important Note:
/// DEC 5.2 introduced a bug which breaks backward compatibility with
/// DEC 5.1 by using String instead of AnsiString. This leads to different
/// Identities when using Unicode capable Delphi Versions (Delphi 2009+).
///
/// To restore the *wrong* behavior of DEC 5.2 enable the DEC52_IDENTITY option
/// in the configuration file DECOptions.inc.
///
/// With this and all future versions we will keep backward compatibility.
/// </summary>
class function Identity: Int64;
{$IFDEF X86ASM}
/// <summary>
/// Override FreeInstance to fill allocated Object with zeros, that is
/// safer for any access to invalid Pointers of released Objects.
/// </summary>
procedure FreeInstance; override;
{$ENDIF X86ASM}
/// <summary>
/// Registers this class type in the list of DEC classes (ClassList).
/// Trying to register an already registered class will raise an exception.
/// </summary>
/// <param name="ClassList">
/// List to which the own class type shall be added. This allows subclasses
/// to have their own lists
/// </param>
class procedure RegisterClass(ClassList : TDECClassList);
/// <summary>
/// Removes tthis class type from the list of registered DEC classes
/// (ClassList). Trying to unregister a non registered class is a do nothing
/// operation.
/// </summary>
/// <param name="ClassList">
/// List from which the own class type shall be removed. This allows
/// subclasses to have their own lists
/// </param>
class procedure UnregisterClass(ClassList : TDECClassList);
/// <summary>
/// Returns short Classname of any DEC derrived class. This is the part
/// of the class name after the _ so for THash_RipeMD160 it will be RipeMD160.
/// </summary>
/// <param name="ClassName">
/// Complete class name
/// </param>
/// <returns>
/// Short class name
/// </returns>
class function GetShortClassNameFromName(const ClassName: string): string;
/// <summary>
/// Returns short Classname of any DEC derrived class type. This is the part
/// of the class name after the _ so for THash_RipeMD160 it will be RipeMD160.
/// </summary>
/// <returns>
/// Short class name or empty string if ClassType is nil.
/// </returns>
class function GetShortClassName: string;
end;
var
/// <summary>
/// default used for generating class identities
/// </summary>
IdentityBase: Int64 = $25844852;
/// <summary>
/// Size in bytes used for buffering data read from or written to a stream
/// </summary>
StreamBufferSize: Integer = 8192;
{$IFDEF NEXTGEN}
EmptyStr: string = '';
/// <summary>
/// Pointer to an empty string. For non Nextgen platforms declared in SysUtils
/// for backwards compatibility only. Here declared for NextGen only and
/// should get replaced
/// </summary>
NullStr: PString = @EmptyStr;
{$ENDIF}
implementation
uses
DECUtil, DECCRC;
resourcestring
sClassNotRegistered = 'Class %s is not registered';
sWrongIdentity = 'Another class "%s" with the same identity as "%s" has already been registered';
constructor TDECObject.Create;
begin
inherited Create;
end;
class function TDECObject.Identity: Int64;
var
Signature: {$IFDEF DEC52_IDENTITY}string{$ELSE !DEC52_IDENTITY}RawByteString{$ENDIF !DEC52_IDENTITY};
begin
{$IFDEF DEC52_IDENTITY}
Signature := StringOfChar(#$5A, 256 - Length(ClassName)) + UpperCase(ClassName);
{$IF CompilerVersion >= 24.0}
Result := CRC32(IdentityBase, Signature[Low(Signature)],
Length(Signature) * SizeOf(Signature[Low(Signature)]));
{$ELSE}
Result := CRC32(IdentityBase, Signature[Low(Signature)],
Length(Signature) * SizeOf(Signature[1]));
{$IFEND}
{$ELSE !DEC52_IDENTITY}
Signature := RawByteString(StringOfChar(#$5A, 256 - Length(ClassName)) + UpperCase(ClassName));
{$IF CompilerVersion >= 24.0}
Result := CRC32(IdentityBase, Signature[Low(Signature)],
Length(Signature) * SizeOf(Signature[Low(Signature)]));
{$ELSE}
Result := CRC32(IdentityBase, Signature[1],
Length(Signature) * SizeOf(Signature[1]));
{$IFEND}
{$ENDIF !DEC52_IDENTITY}
end;
class procedure TDECObject.RegisterClass(ClassList : TDECClassList);
begin
ClassList.Add(Identity, self);
end;
{$IFDEF X86ASM}
procedure TDECObject.FreeInstance;
// Override FreeInstance to fill allocated Object with zeros, that is
// safer for any access to invalid Pointers of released Objects
asm
PUSH EBX
PUSH EDI
MOV EBX,EAX
CALL TObject.CleanupInstance
MOV EAX,[EBX]
CALL TObject.InstanceSize
MOV ECX,EAX
MOV EDI,EBX
XOR EAX,EAX
REP STOSB
MOV EAX,EBX
CALL System.@FreeMem
POP EDI
POP EBX
end;
{$ENDIF X86ASM}
class procedure TDECObject.UnregisterClass(ClassList : TDECClassList);
begin
ClassList.Remove(Identity);
end;
class function TDECObject.GetShortClassName: string;
begin
Result := GetShortClassNameFromName(self.ClassName);
end;
class function TDECObject.GetShortClassNameFromName(const ClassName: string): string;
var
i: Integer;
begin
Result := ClassName;
i := Pos('_', Result);
if i > 0 then
Delete(Result, 1, i);
end;
{ TDECClassList }
function TDECClassList.DoFindNameShort(const Name: string; const ClassType: TDECClass): Boolean;
begin
Result := CompareText(ClassType.GetShortClassName, Name) = 0;
end;
function TDECClassList.DoFindNameLong(const Name: string; const ClassType: TClass): Boolean;
var
s: string;
begin
s := Name;
Result := CompareText(ClassType.ClassName, Name) = 0;
end;
function TDECClassList.ClassByIdentity(Identity: Int64): TDECClass;
begin
try
Result := Items[Identity];
except
On EListError do
raise EDECClassNotRegisteredException.CreateResFmt(@sClassNotRegistered,
[IntToHEX(Identity, 8)]);
end;
end;
function TDECClassList.ClassByName(const Name: string): TDECClass;
var
FindNameShort : Boolean;
Pair : TPair<Int64, TDECCLass>;
begin
Result := nil;
if Length(Name) > 0 then
begin
FindNameShort := TDECClass.GetShortClassNameFromName(Name) = Name;
for Pair in self do
begin
if FindNameShort then
begin
if DoFindNameShort(Name, Pair.Value) then
begin
result := Pair.Value;
break;
end;
end
else
if DoFindNameLong(Name, Pair.Value) then
begin
result := Pair.Value;
break;
end;
end;
end;
if Result = nil then
raise EDECClassNotRegisteredException.CreateResFmt(@sClassNotRegistered, [Name]);
end;
procedure TDECClassList.GetClassList(List: TStrings);
var
Pair : TPair<Int64, TDECCLass>;
begin
if List <> nil then
try
List.BeginUpdate;
List.Clear;
for Pair in self do
List.AddObject(Pair.Value.ClassName, TObject(Pair.Value));
finally
List.EndUpdate;
end;
end;
initialization
finalization
end.

View File

@@ -0,0 +1,908 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
{
Implementation of threadsafe CRC checksum functions.
The following standard CRCs are supported:
CRC-8, CRC-10, CRC-12 (Mobil Telephone),
CRC-16, CRC-16-CCITT, CRC-16-ZModem,
CRC-24 (PGP's MIME64 Armor CRC),
CRC-32, CRC-32-CCITT and CRC-32-ZModem.
How to use:
var
CRC16: UInt16;
begin
CRC16 := CRCCalc(CRC_16, Data, SizeOf(Data)); // all in one
end;
or
var
CRC: TCRCDef;
CRC32: UInt32;
begin
CRCInit(CRC, CRC_32); // setup CRC data structure
CRCCode(CRC, Data, SizeOf(Data)); // calcs CRC for "Data"
CRCCode(CRC, PChar(string)^, Length(string) * SizeOf(string[1])); // calcs CRC for String
CRC32 := CRCDone(CRC); // returns correct combined CRC for Data and String
// after CRCDone we can start a new calculation
end;
}
unit DECCRC;
interface
{$INCLUDE DECOptions.inc}
type
/// <summary>
/// CRC Definition Structure
/// </summary>
PCRCDef = ^TCRCDef;
/// <summary>
/// Record with meta data about a single CRC algorithm/polynom
/// Do *not* reorder or change this structure
/// <para>
/// SizeOf(TCRCDef) = 1056 = 0420h
/// </para>
/// </summary>
TCRCDef = packed record
/// <summary>
/// Lookup Table, precomputed in CRCSetup
/// </summary>
Table : array[0..255] of UInt32;
/// <summary>
/// Intermediate CRC
/// </summary>
CRC : UInt32;
/// <summary>
/// Is this Polynomial an inverse function?
/// </summary>
Inverse : LongBool;
/// <summary>
/// Shift Value for CRCCode (for more speed)
/// </summary>
Shift : UInt32;
/// <summary>
/// Start Value of CRC cComputation
/// </summary>
InitVector : UInt32;
/// <summary>
/// Final XOR Vector of computed CRC
/// </summary>
FinalVector : UInt32;
/// <summary>
/// Precomputed AND Mask of computed CRC
/// </summary>
Mask : UInt32;
/// <summary>
/// Bitsize of CRC
/// </summary>
Bits : UInt32;
/// <summary>
/// Used Polynomial
/// </summary>
Polynomial : UInt32;
end;
/// <summary>
/// predefined standard CRC Types
/// </summary>
TCRCType = (
CRC_8,
CRC_10,
CRC_12,
CRC_16,
CRC_16CCITT,
CRC_16XModem,
CRC_24,
CRC_32,
CRC_32CCITT,
CRC_32ZModem,
CRC_8ATMHEC,
CRC_8SMBus,
CRC_15CAN,
CRC_16ZMODEM
);
type
/// <summary>
/// Callback method used by some CRC calculation routines to fetch the data
/// to be processed
/// </summary>
/// <param name="Buffer">
/// Buffer containing the data to be processed
/// </param>
/// <param name="Count">
/// Number of bytes of the buffer to be processed
/// </param>
/// <returns>
///
/// </returns>
TReadMethod = function(var Buffer; Count: Int64): Int64 of object;
// initialize CRC Definition with a custom Algorithm
/// <summary>
/// Fills the individual fields of a CRC meta data structure
/// </summary>
/// <param name="CRCDef">
/// Structure whose fields shall be filled
/// </param>
/// <param name="Polynomial">
/// CRC polynome, defining the algorithm
/// </param>
/// <param name="Bits">
/// Size of the CRC value to be computed in bits. Needs to be at least 8
/// </param>
/// <param name="InitVector">
/// Initial value for the vector going into each calculation cycle
/// </param>
/// <param name="FinalVector">
/// Final XOR Vector of computed CRC
/// </param>
/// <param name="Inverse">
/// true if this Polynomial is an inverse function
/// </param>
/// <returns>
/// true on success, false when a number smaller 8 is being passed as Bits parameter
/// </returns>
function CRCSetup(var CRCDef: TCRCDef;
Polynomial, Bits, InitVector, FinalVector: UInt32;
Inverse: LongBool): Boolean;
/// <summary>
/// Retrieves the necessary meta data and precomputed tables for a given CRC
/// algorithm.
/// </summary>
/// <param name="CRCDef">
/// Record in which the to be retrieved meta data will be returned
/// </param>
/// <param name="CRCType">
/// Specifies the exact CRC type which shall be initialized
/// </param>
/// <returns>
/// true on success
/// </returns>
function CRCInit(var CRCDef: TCRCDef; CRCType: TCRCType): Boolean;
/// <summary>
/// Calculate the CRC of the contents of the passed in buffer.
/// </summary>
/// <param name="CRCDef">
/// Structure with the necessary metadata for the CRC algorithm to be used.
/// CRC processing state is being updated during calculation to enable this
/// structure to be fed in another call to CRCCode if a CRC over multiple
/// buffers has to be calculated.
/// </param>
/// <param name="Buffer">
/// Buffer with the data the CRC shall be calculated from
/// </param>
/// <param name="Size">
/// Number of bytes to calculate the CRC from, starting at the beginning of
/// the buffer
/// </param>
/// <returns>
/// Calculated CRC value, including any necessary correction (like CRCDone).
/// CRCDef.CRC holds the actual computed CRC, additional calls of CRCCode
/// compute the total CRC of split buffers
/// </returns>
function CRCCode(var CRCDef: TCRCDef; const Buffer; Size: UInt32): UInt32; overload;
/// <summary>
/// Calculate the CRC of the contents provided by a given callback
/// </summary>
/// <param name="CRCDef">
/// Structure with the necessary metadata for the CRC algorithm to be used.
/// CRC processing state is being updated during calculation to enable this
/// structure to be fed in another call to CRCCode if a CRC over multiple
/// buffers has to be calculated.
/// </param>
/// <param name="ReadMethod">
/// Callback which is being called to get the data the CRC is processed over,
/// e.g. TStream.Read
/// </param>
/// <param name="Size">
/// Number of bytes over which the CRC will be calculated. The callback will
/// be called until that number of bytes have been processed.
/// </param>
/// <returns>
/// Calculated CRC value, including any necessary correction (like CRCDone).
/// CRCDef.CRC holds the actual computed CRC, additional calls of CRCCode
/// compute the total CRC of split buffers
/// </returns>
function CRCCode(var CRCDef: TCRCDef;
ReadMethod: TReadMethod;
Size: UInt32 = $FFFFFFFF): UInt32; overload;
{ TODO :
DUnitTests f<>r die Callback-Methoden Varianten von CRCCode und CRCCalc
schreiben }
//
// CRCInit(CRC, CRC_32); // setup CRC data structure
// CRCCode(CRC, Data, SizeOf(Data)); // calcs CRC for "Data"
// CRCCode(CRC, PChar(string)^, Length(string) * SizeOf(string[1])); // calcs CRC for String
// CRC32 := CRCDone(CRC);
// returns corrected CRC as definied in CRCDef and resets CRCDef.CRC to InitVector
/// <summary>
/// Corrects the CRC via the final vector and resets the internal intermediate
/// CRC value to the init vector so the next CRC calculation can start.
/// </summary>
/// <param name="CRCDef">
/// Structure with the current CRC state
/// </param>
/// <returns>
/// Final CRC value
/// </returns>
function CRCDone(var CRCDef: TCRCDef): UInt32;
/// <summary>
/// Calculates a CRC over some Buffer with Size Bytes length. Processing is
/// being done in one single step
/// </summary>
/// <param name="CRCType">
/// Specifies the CRC algorithm to be used
/// </param>
/// <param name="Buffer">
/// Buffer with the data to calculate the CRC from
/// </param>
/// <param name="Size">
/// Number of bytes over which the CRC will be calculated from the beginning
/// of the buffer
/// </param>
function CRCCalc(CRCType: TCRCType; const Buffer; Size: UInt32): UInt32; overload;
/// <summary>
/// Calculates a CRC. Data is passed via callback, which is called repeatedly
/// if necessary
/// </summary>
/// <param name="CRCType">
/// Specifies the CRC algorithm to be used
/// </param>
/// <param name="ReadMethod">
/// Callback which is being called to get the data the CRC is processed over
/// e.g. TStream.Read
/// </param>
/// <param name="Size">
/// Number of bytes over which the CRC will be calculated. The callback will
/// be called until that number of bytes have been processed.
/// </param>
/// <returns>
/// Calculated CRC value.
/// </returns>
function CRCCalc(CRCType : TCRCType;
ReadMethod : TReadMethod;
Size : UInt32 = $FFFFFFFF): UInt32; overload;
/// <summary>
/// Calculates a CRC according a predefined CRC16-Standard over some Buffer
/// with Size Bytes length. Processing is being done in one single step
/// </summary>
/// <remarks>
/// call CRC := CRC16(0, Data, SizeOf(Data));
/// </remarks>
/// <param name="CRC">
/// Specifies the CRC algorithm to be used
/// </param>
/// <param name="Buffer">
/// Buffer with the data to calculate the CRC from
/// </param>
/// <param name="Size">
/// Number of bytes over which the CRC will be calculated from the beginning
/// of the buffer
/// </param>
/// <returns>
/// Calculated CRC16 value
/// </returns>
function CRC16(CRC: UInt16; const Buffer; Size: UInt32): UInt16;
/// <summary>
/// Calculates a CRC according the CRC32-CCITT standard over some Buffer
/// with Size Bytes length. Processing is being done in one single step
/// </summary>
/// <remarks>
/// call CRC := CRC32(0, Data, SizeOf(Data));
/// </remarks>
/// <param name="CRC">
/// Specifies the CRC algorithm to be used
/// </param>
/// <param name="Buffer">
/// Buffer with the data to calculate the CRC from
/// </param>
/// <param name="Size">
/// Number of bytes over which the CRC will be calculated from the beginning
/// of the buffer
/// </param>
/// <returns>
/// Calculated CRC32 value
/// </returns>
function CRC32(CRC: UInt32; const Buffer; Size: UInt32): UInt32;
implementation
{$IFOPT Q+}{$DEFINE RESTORE_OVERFLOWCHECKS}{$Q-}{$ENDIF}
{$IFOPT R+}{$DEFINE RESTORE_RANGECHECKS}{$R-}{$ENDIF}
type
PCRCTab = ^TCRCTab;
/// <summary>
/// Array type for the meta data definitions of the individual CRC algorithms
/// </summary>
TCRCTab = array[TCRCType] of packed record
Poly, Bits, Init, FInit: UInt32;
Inverse: LongBool;
end;
const
/// <summary>
/// Table containing meta data of various well known CRC algorithms/polynoms
/// </summary>
CRCTab : TCRCTab = (
(Poly: $000000D1; Bits: 08; Init: $00000000; FInit: $00000000; Inverse: True), // CRC_8 GSM/ERR
(Poly: $00000233; Bits: 10; Init: $00000000; FInit: $00000000; Inverse: True), // CRC_10 ATM/OAM Cell
(Poly: $0000080F; Bits: 12; Init: $00000000; FInit: $00000000; Inverse: True), // CRC_12
(Poly: $00008005; Bits: 16; Init: $00000000; FInit: $00000000; Inverse: True), // CRC_16 ARC;IBM;MODBUS RTU
// Init value of 1D0F instead of FFFF because the code doesn't fill with zeros,
// which would otherwise be required for the CCITT variant
(Poly: $00001021; Bits: 16; Init: $00001D0F; FInit: $00000000; Inverse: False), // CRC_16 CCITT ITU
(Poly: $00008408; Bits: 16; Init: $00000000; FInit: $00000000; Inverse: True), // CRC_16 XModem
(Poly: $00864CFB; Bits: 24; Init: $00B704CE; FInit: $00000000; Inverse: False), // CRC_24
(Poly: $9DB11213; Bits: 32; Init: $FFFFFFFF; FInit: $FFFFFFFF; Inverse: True), // CRC_32
(Poly: $04C11DB7; Bits: 32; Init: $FFFFFFFF; FInit: $FFFFFFFF; Inverse: True), // CRC_32CCITT
(Poly: $04C11DB7; Bits: 32; Init: $FFFFFFFF; FInit: $00000000; Inverse: True), // CRC_32ZModem
(Poly: $00000007; Bits: 08; Init: $00000000; FInit: $00000000; Inverse: True), // CRC_8ATMHEC
(Poly: $00000007; Bits: 08; Init: $00000000; FInit: $00000000; Inverse: False), // CRC_8SMBus
(Poly: $00004599; Bits: 15; Init: $00000000; FInit: $00000000; Inverse: True), // CRC_15CAN
(Poly: $00001021; Bits: 16; Init: $00000000; FInit: $00000000; Inverse: False) // CRC_16ZMODEM
);
// some other CRC's, not all yet verfied
// DD $00001021, 16, $0000FFFF, $00000000, 0 // CRC_16 CCITT British Aerospace
// DD $00004003, 16, $00000000, $00000000, -1 // CRC_16 reversed
// DD $00001005, 16, $00000000, $00000000, -1 // CRC_16 X25
// https://fenix.tecnico.ulisboa.pt/downloadFile/3779571246541/BasicCrd.pdf enth<74>lt
// eine beschreibung dieser BasicCard Smartcard incl. C-CRC Quellcode, aber die
// Polynome konnte ich so noch nicht <20>berpr<70>fen
// DD $00000053, 16, $00000000, $00000000, -1 // BasicCard 16Bit CRC (sparse poly for Crypto MCU)
// DD $000000C5, 32, $00000000, $00000000, -1 // BasicCard 32Bit CRC
function CRCSetup(var CRCDef: TCRCDef; Polynomial, Bits, InitVector,
FinalVector: UInt32; Inverse: LongBool): Boolean;
// initialize CRCDef according to the parameters, calculate the lookup table
{$IFDEF X86ASM}
asm
CMP ECX,8
JB @@8
PUSH EBX
PUSH EDI
PUSH ESI
MOV [EAX].TCRCDef.Polynomial,EDX
MOV [EAX].TCRCDef.Bits,ECX
MOV EBX,InitVector
MOV EDI,FinalVector
MOV ESI,Inverse
MOV [EAX].TCRCDef.CRC,EBX
MOV [EAX].TCRCDef.InitVector,EBX
MOV [EAX].TCRCDef.FinalVector,EDI
MOV [EAX].TCRCDef.Inverse,ESI
XOR EDI,EDI
LEA EBX,[ECX - 8]
SUB ECX,32
DEC EDI
NEG ECX
SHR EDI,CL
MOV [EAX].TCRCDef.Shift,EBX
MOV [EAX].TCRCDef.Mask,EDI
TEST ESI,ESI
JZ @@5
XOR EBX,EBX
MOV ECX,[EAX].TCRCDef.Bits
@@1: SHR EDX,1
ADC EBX,EBX
DEC ECX
JNZ @@1
NOP
MOV ECX,255
NOP
@@20: MOV EDX,ECX
SHR EDX,1
JNC @@21
XOR EDX,EBX
@@21: SHR EDX,1
JNC @@22
XOR EDX,EBX
@@22: SHR EDX,1
JNC @@23
XOR EDX,EBX
@@23: SHR EDX,1
JNC @@24
XOR EDX,EBX
@@24: SHR EDX,1
JNC @@25
XOR EDX,EBX
@@25: SHR EDX,1
JNC @@26
XOR EDX,EBX
@@26: SHR EDX,1
JNC @@27
XOR EDX,EBX
@@27: SHR EDX,1
JNC @@28
XOR EDX,EBX
@@28: MOV [EAX + ECX * 4],EDX
DEC ECX
JNL @@20
JMP @@7
@@5: AND EDX,EDI
ROL EDX,CL
MOV EBX,255
// can be coded branchfree
@@60: MOV ESI,EBX
SHL ESI,25
JNC @@61
XOR ESI,EDX
@@61: ADD ESI,ESI
JNC @@62
XOR ESI,EDX
@@62: ADD ESI,ESI
JNC @@63
XOR ESI,EDX
@@63: ADD ESI,ESI
JNC @@64
XOR ESI,EDX
@@64: ADD ESI,ESI
JNC @@65
XOR ESI,EDX
@@65: ADD ESI,ESI
JNC @@66
XOR ESI,EDX
@@66: ADD ESI,ESI
JNC @@67
XOR ESI,EDX
@@67: ADD ESI,ESI
JNC @@68
XOR ESI,EDX
@@68: ROR ESI,CL
MOV [EAX + EBX * 4],ESI
DEC EBX
JNL @@60
@@7: POP ESI
POP EDI
POP EBX
@@8: CMC
SBB EAX,EAX
NEG EAX
end;
{$ELSE !X86ASM}
var
Value, XorValue, OldValue: UInt32;
Index: Integer;
B: Boolean;
One: Byte;
begin
if Bits >= 8 then
begin
CRCDef.Polynomial := Polynomial;
CRCDef.Bits := Bits;
CRCDef.CRC := InitVector;
CRCDef.InitVector := InitVector;
CRCDef.FinalVector := FinalVector;
CRCDef.Inverse := Inverse;
CRCDef.Shift := Bits - 8;
Bits := -(Bits - 32);
CRCDef.Mask := -1 shr Byte(Bits);
if Inverse then
begin
Bits := CRCDef.Bits;
XorValue := 0;
repeat
Inc(XorValue, XorValue + Ord(Polynomial and $1));
Polynomial := Polynomial shr 1;
Dec(Bits);
until Bits = 0;
One := $1;
for Index := 255 downto 0 do
begin
Value := Index;
B := Boolean(Value and One); Value := Value shr 1;
if B then Value := Value xor XorValue;
B := Boolean(Value and One); Value := Value shr 1;
if B then Value := Value xor XorValue;
B := Boolean(Value and One); Value := Value shr 1;
if B then Value := Value xor XorValue;
B := Boolean(Value and One); Value := Value shr 1;
if B then Value := Value xor XorValue;
B := Boolean(Value and One); Value := Value shr 1;
if B then Value := Value xor XorValue;
B := Boolean(Value and One); Value := Value shr 1;
if B then Value := Value xor XorValue;
B := Boolean(Value and One); Value := Value shr 1;
if B then Value := Value xor XorValue;
B := Boolean(Value and One); Value := Value shr 1;
if B then Value := Value xor XorValue;
CRCDef.Table[Index] := Value;
end;
end
else
begin
XorValue := Polynomial and CRCDef.Mask;
XorValue := (XorValue shl Byte(Bits)) or (XorValue shr (32 - Byte(Bits)));
for Index := 255 downto 0 do
begin
B := Boolean(Index and $000000080); Value := Index shl 25;
if B then Value := Value xor XorValue;
OldValue := Value; Inc(Value, Value);
if Value < OldValue then Value := Value xor XorValue;
OldValue := Value; Inc(Value, Value);
if Value < OldValue then Value := Value xor XorValue;
OldValue := Value; Inc(Value, Value);
if Value < OldValue then Value := Value xor XorValue;
OldValue := Value; Inc(Value, Value);
if Value < OldValue then Value := Value xor XorValue;
OldValue := Value; Inc(Value, Value);
if Value < OldValue then Value := Value xor XorValue;
OldValue := Value; Inc(Value, Value);
if Value < OldValue then Value := Value xor XorValue;
OldValue := Value; Inc(Value, Value);
if Value < OldValue then Value := Value xor XorValue;
Value := (Value shr Byte(Bits)) or (Value shl (32 - Byte(Bits)));
CRCDef.Table[Index] := Value;
end;
end;
Result := True;
end
else
Result := False;
end;
{$ENDIF !X86ASM}
function CRCInit(var CRCDef: TCRCDef; CRCType: TCRCType): Boolean;
begin
Result := CRCSetup(CRCDef,
PCRCTab(@CRCTab)[CRCType].Poly,
PCRCTab(@CRCTab)[CRCType].Bits,
PCRCTab(@CRCTab)[CRCType].Init,
PCRCTab(@CRCTab)[CRCType].FInit,
PCRCTab(@CRCTab)[CRCType].Inverse);
end;
function CRCCode(var CRCDef: TCRCDef; const Buffer; Size: UInt32): UInt32;
// do the CRC computation
{$IFDEF X86ASM}
asm
JECXZ @@5
TEST EDX,EDX
JZ @@5
PUSH ESI
PUSH EBX
MOV ESI,EAX
CMP [EAX].TCRCDef.Inverse,0
MOV EAX,[ESI].TCRCDef.CRC
JZ @@2
XOR EBX,EBX
@@1: MOV BL,[EDX]
XOR BL,AL
SHR EAX,8
INC EDX
XOR EAX,[ESI + EBX * 4]
DEC ECX
JNZ @@1
JMP @@4
@@2: PUSH EDI
MOV EBX,EAX
MOV EDI,ECX
MOV ECX,[ESI].TCRCDef.Shift
MOV EBX,EAX
@@3: SHR EBX,CL
SHL EAX,8
XOR BL,[EDX]
INC EDX
MOVZX EBX,BL
XOR EAX,[ESI + EBX * 4]
DEC EDI
MOV EBX,EAX
JNZ @@3
POP EDI
@@4: MOV [ESI].TCRCDef.CRC,EAX
XOR EAX,[ESI].TCRCDef.FinalVector
AND EAX,[ESI].TCRCDef.Mask
POP EBX
POP ESI
RET
@@5: MOV EAX,[EAX].TCRCDef.CRC
end;
{$ELSE !X86ASM}
var
P: PByte;
Value: Byte;
begin
Result := CRCDef.CRC;
P := @Buffer;
if (Size <> 0) and (P <> nil) then
begin
if CRCDef.Inverse then
begin
repeat
Value := P^ xor Byte(Result);
Result := (Result shr 8) xor CRCDef.Table[Value];
Inc(P);
Dec(Size);
until Size = 0;
end
else
begin
Value := Byte(CRCDef.Shift); // move to local variable => cpu register
repeat
Result := (Result shl 8) xor CRCDef.Table[Byte(Result shr Value) xor P^];
Inc(P);
Dec(Size);
until Size = 0;
end;
CRCDef.CRC := Result;
Result := (Result xor CRCDef.FinalVector) and CRCDef.Mask;
end;
end;
{$ENDIF !X86ASM}
function CRCCode(var CRCDef: TCRCDef; ReadMethod: TReadMethod; Size: UInt32 = $FFFFFFFF): UInt32;
var
Buffer: array[0..1023] of Char;
Count: Int64;
begin
repeat
if Size > SizeOf(Buffer) then
Count := SizeOf(Buffer)
else
Count := Size;
Count := ReadMethod(Buffer, Count);
Result := CRCCode(CRCDef, Buffer, Count);
Dec(Size, Count);
until (Size = 0) or (Count = 0);
end;
function CRCDone(var CRCDef: TCRCDef): UInt32;
// finalize CRCDef after a computation
{$IFDEF X86ASM}
asm
MOV EDX,[EAX].TCRCDef.CRC
MOV ECX,[EAX].TCRCDef.InitVector
XOR EDX,[EAX].TCRCDef.FinalVector
MOV [EAX].TCRCDef.CRC,ECX
AND EDX,[EAX].TCRCDef.Mask
MOV EAX,EDX
end;
{$ELSE !X86ASM}
begin
Result := CRCDef.CRC;
CRCDef.CRC := CRCDef.InitVector;
Result := (Result xor CRCDef.FinalVector) and CRCDef.Mask;
end;
{$ENDIF !X86ASM}
function CRCCalc(CRCType: TCRCType; const Buffer; Size: UInt32): UInt32;
// inplace calculation
var
CRC: TCRCDef;
begin
CRCInit(CRC, CRCType);
Result := CRCCode(CRC, Buffer, Size);
end;
function CRCCalc(CRCType: TCRCType; ReadMethod: TReadMethod; Size: UInt32): UInt32;
var
CRC: TCRCDef;
begin
CRCInit(CRC, CRCType);
Result := CRCCode(CRC, ReadMethod, Size);
end;
// predefined CRC16/CRC32CCITT, avoid slower lookuptable computation by use of precomputation
var
FCRC16: PCRCDef = nil;
FCRC32: PCRCDef = nil;
function CRC16Init: Pointer;
begin
// Replace GetMem by GetMemory due to C++ Builder compatibility
// GetMem(FCRC16, SizeOf(TCRCDef));
FCRC16 := GetMemory(SizeOf(TCRCDef));
CRCInit(FCRC16^, CRC_16);
Result := FCRC16;
end;
function CRC16(CRC: UInt16; const Buffer; Size: UInt32): UInt16;
{$IFDEF X86ASM}
asm
JECXZ @@2
PUSH EDI
PUSH ESI
MOV EDI,ECX
{$IFDEF PIC}
MOV ESI,[EBX].FCRC16
{$ELSE !PIC}
MOV ESI,FCRC16
{$ENDIF !PIC}
XOR ECX,ECX
TEST ESI,ESI
JZ @@3
@@1: MOV CL,[EDX]
XOR CL,AL
SHR EAX,8
INC EDX
XOR EAX,[ESI + ECX * 4]
DEC EDI
JNZ @@1
POP ESI
POP EDI
@@2: RET
@@3: PUSH EAX
PUSH EDX
CALL CRC16Init
MOV ESI,EAX
XOR ECX,ECX
POP EDX
POP EAX
JMP @@1
end;
{$ELSE !X86ASM}
var
LCRC16: PCRCDef;
P: PByte;
CRC32: UInt32;
Value: Byte;
begin
if Size <> 0 then
begin
LCRC16 := FCRC16;
if LCRC16 = nil then
LCRC16 := CRC16Init;
CRC32 := CRC;
P := @Buffer;
repeat
Value := P^ xor Byte(CRC32);
CRC32 := (CRC32 shr 8) xor LCRC16.Table[Value];
Inc(P);
Dec(Size);
until Size = 0;
Result := UInt16(CRC32);
end
else
Result := CRC;
end;
{$ENDIF !X86ASM}
function CRC32Init: Pointer;
begin
// Replaced for C++ Builder compatibility
// GetMem(FCRC32, SizeOf(TCRCDef));
FCRC32 := GetMemory(SizeOf(TCRCDef));
CRCInit(FCRC32^, CRC_32CCITT);
Result := FCRC32;
end;
function CRC32(CRC: UInt32; const Buffer; Size: UInt32): UInt32;
{$IFDEF X86ASM}
asm
JECXZ @@2
PUSH EDI
PUSH ESI
NOT EAX // inverse Input CRC
MOV EDI,ECX
{$IFDEF PIC}
MOV ESI,[EBX].FCRC32
{$ELSE !PIC}
MOV ESI,FCRC32
{$ENDIF !PIC}
XOR ECX,ECX
TEST ESI,ESI
JZ @@3
@@1: MOV CL,[EDX]
XOR CL,AL
SHR EAX,8
INC EDX
XOR EAX,[ESI + ECX * 4]
DEC EDI
JNZ @@1
NOT EAX // inverse Output CRC
POP ESI
POP EDI
@@2: RET
@@3: PUSH EAX
PUSH EDX
CALL CRC32Init
MOV ESI,EAX
XOR ECX,ECX
POP EDX
POP EAX
JMP @@1
end;
{$ELSE !X86ASM}
var
LCRC32: PCRCDef;
P: PByte;
CRC32: UInt32;
Value: Byte;
begin
if Size <> 0 then
begin
LCRC32 := FCRC32;
if LCRC32 = nil then
LCRC32 := CRC32Init;
CRC32 := not CRC; // inverse Input CRC
P := @Buffer;
repeat
Value := P^ xor Byte(CRC32);
CRC32 := (CRC32 shr 8) xor LCRC32.Table[Value];
Inc(P);
Dec(Size);
until Size = 0;
Result := not CRC32; // inverse Output CRC
end
else
Result := CRC;
end;
{$ENDIF !X86ASM}
procedure CRCInitThreadSafe;
begin
CRC16Init;
CRC32Init;
end;
{$IFDEF RESTORE_RANGECHECKS}{$R+}{$ENDIF}
{$IFDEF RESTORE_OVERFLOWCHECKS}{$Q+}{$ENDIF}
initialization
CRCInitThreadSafe;
finalization
if FCRC16 <> nil then
FreeMem(FCRC16);
if FCRC32 <> nil then
FreeMem(FCRC32);
end.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,605 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
unit DECCipherInterface;
interface
uses
{$IFDEF FPC}
SysUtils, Classes,
{$ELSE}
System.SysUtils, System.Classes,
{$ENDIF}
DECUtil, DECCipherBase, DECFormatBase;
type
/// <summary>
/// Common interface for all ciphers. Some ciphers may have additional
/// methods/properties though!
/// </summary>
IDECCipher = Interface
/// <summary>
/// Encrypts the contents of a given byte array
/// </summary>
/// <param name="Source">
/// Byte array with data to be encrypted
/// </param>
/// <returns>
/// Byte array with encrypted data
/// </returns>
function EncodeBytes(const Source: TBytes): TBytes;
/// <summary>
/// Decrypts the contents of a given byte array
/// </summary>
/// <param name="Source">
/// Byte array with data to be decrypted
/// </param>
/// <returns>
/// Byte array with decrypted data
/// </returns>
function DecodeBytes(const Source: TBytes): TBytes;
/// <summary>
/// Encrypts the data contained in a given stream
/// </summary>
/// <param name="Source">
/// Source stream containing the data to encrypt
/// </param>
/// <param name="Dest">
/// Destination stream, where the encrypted data shall be put in
/// </param>
/// <param name="DataSize">
/// Number of bytes of Source to be encrypted
/// </param>
/// <param name="OnProgress">
/// optional callback for reporting progress of the operation
/// </param>
procedure EncodeStream(const Source, Dest: TStream; DataSize: Int64;
const OnProgress: TDECProgressEvent = nil);
/// <summary>
/// Decrypts the data contained in a given stream
/// </summary>
/// <param name="Source">
/// Source stream containing the data to decrypt
/// </param>
/// <param name="Dest">
/// Destination stream, where the decrypted data shall be put in
/// </param>
/// <param name="DataSize">
/// Number of bytes of Source to be decrypted
/// </param>
/// <param name="OnProgress">
/// optional callback for reporting progress of the operation
/// </param>
procedure DecodeStream(const Source, Dest: TStream; DataSize: Int64;
const OnProgress: TDECProgressEvent = nil);
/// <summary>
/// Reads the contents of one file, encrypts it and stores it in another file
/// </summary>
/// <param name="SourceFileName">
/// Path and name of the file to encrypt
/// </param>
/// <param name="DestFileName">
/// Path and name of the file the encrypted data shall be stored in
/// </param>
/// <param name="OnProgress">
/// Optional event which can be passed to get information about the
/// progress of the encryption operation
/// </param>
procedure EncodeFile(const SourceFileName, DestFileName: string;
const OnProgress: TDECProgressEvent = nil);
/// <summary>
/// Reads the contents of one file, decrypts it and stores it in another file
/// </summary>
/// <param name="SourceFileName">
/// Path and name of the file to decrypt
/// </param>
/// <param name="DestFileName">
/// Path and name of the file the decrypted data shall be stored in
/// </param>
/// <param name="OnProgress">
/// Optional event which can be passed to get information about the
/// progress of the decryption operation
/// </param>
procedure DecodeFile(const SourceFileName, DestFileName: string;
const OnProgress: TDECProgressEvent = nil);
/// <summary>
/// Encrypts the contents of the passed unicode string
/// </summary>
/// <param name="Source">
/// String to encrypt
/// </param>
/// <param name="Format">
/// Optional parameter. One can pass a class reference of one of the
/// concrete data formatting classes here which will be internally used
/// to convert the data. Encoded will be the encrypted data, not the
/// source data. Formattings can be used to convert data into a format
/// suitable for the transport medium the data shall be transported with.
/// </param>
/// <returns>
/// Encrypted string as a byte array
/// </returns>
function EncodeStringToBytes(const Source: string; Format: TDECFormatClass = nil): TBytes; overload;
/// <summary>
/// Encrypts the contents of the passed RawByteString
/// </summary>
/// <param name="Source">
/// String to encrypt
/// </param>
/// <param name="Format">
/// Optional parameter. One can pass a class reference of one of the
/// concrete data formatting classes here which will be internally used
/// to convert the data. Encoded will be the encrypted data, not the
/// source data. Formattings can be used to convert data into a format
/// suitable for the transport medium the data shall be transported with.
/// </param>
/// <returns>
/// Encrypted string as a byte array
/// </returns>
function EncodeStringToBytes(const Source: RawByteString; Format: TDECFormatClass = nil): TBytes; overload;
/// <summary>
/// Encrypts the contents of the passed unicode string
/// </summary>
/// <param name="Source">
/// String to encrypt
/// </param>
/// <param name="Format">
/// Optional parameter. One can pass a class reference of one of the
/// concrete data formatting classes here which will be internally used
/// to convert the data. Encoded will be the encrypted data, not the
/// source data. Formattings can be used to convert data into a format
/// suitable for the transport medium the data shall be transported with.
/// </param>
/// <returns>
/// Encrypted string
/// </returns>
/// <remarks>
/// The use of this method is only recommended if a formatting is passed
/// which will result in an 7-bit ASCII compatible string as we cannot
/// ensure that Unicode string processing will not alter/interpret some
/// byte combinations in a destructive way, making the encrypted string
/// un-decryptable.
/// </remarks>
function EncodeStringToString(const Source: string; Format: TDECFormatClass = nil): string; overload;
/// <summary>
/// Encrypts the contents of the passed unicode string
/// </summary>
/// <param name="Source">
/// String to encrypt
/// </param>
/// <param name="Format">
/// Optional parameter. One can pass a class reference of one of the
/// concrete data formatting classes here which will be internally used
/// to convert the data. Encoded will be the encrypted data, not the
/// source data. Formattings can be used to convert data into a format
/// suitable for the transport medium the data shall be transported with.
/// </param>
/// <returns>
/// Encrypted string
/// </returns>
/// <remarks>
/// The use of this method is only recommended if a formatting is passed
/// which will result in an 7-bit ASCII compatible string as we cannot
/// ensure that string processing will not alter/interpret some
/// byte combinations in a destructive way, making the encrypted string
/// un-decryptable.
/// </remarks>
function EncodeStringToString(const Source: RawByteString; Format: TDECFormatClass = nil): RawByteString; overload;
/// <summary>
/// Decrypts the contents of the passed encrypted unicode string
/// </summary>
/// <param name="Source">
/// String to decrypt
/// </param>
/// <param name="Format">
/// Optional parameter. One can pass a class reference of one of the
/// concrete data formatting classes here which will be internally used
/// to convert the data. Decoded will be the still encrypted data, not the
/// encrypted data. Formattings can be used to convert data into a format
/// suitable for the transport medium the data shall be transported with.
/// </param>
/// <returns>
/// Decrypted string as a byte array
/// </returns>
function DecodeStringToBytes(const Source: string; Format: TDECFormatClass = nil): TBytes; overload;
/// <summary>
/// Decrypts the contents of the passed encrypted RawByteString
/// </summary>
/// <param name="Source">
/// String to decrypt
/// </param>
/// <param name="Format">
/// Optional parameter. One can pass a class reference of one of the
/// concrete data formatting classes here which will be internally used
/// to convert the data. Decoded will be the still encrypted data, not the
/// encrypted data. Formattings can be used to convert data into a format
/// suitable for the transport medium the data shall be transported with.
/// </param>
/// <returns>
/// Decrypted string as a byte array
/// </returns>
function DecodeStringToBytes(const Source: RawByteString; Format: TDECFormatClass = nil): TBytes; overload;
/// <summary>
/// Decrypts the contents of the passed Unicode string
/// </summary>
/// <param name="Source">
/// String to decrypt
/// </param>
/// <param name="Format">
/// Optional parameter. One can pass a class reference of one of the
/// concrete data formatting classes here which will be internally used
/// to convert the data. Decoded will be the encrypted data, not the
/// decrypted data. Formattings can be used to convert data into a format
/// suitable for the transport medium the data shall be transported with.
/// </param>
/// <returns>
/// Decrypted string
/// </returns>
/// <remarks>
/// The use of this method is only recommended if a formatting is passed
/// which uses an 7-bit ASCII compatible string as input so that it
/// didn't get altered by Unicode string processing in some hafrmful way
/// </remarks>
function DecodeStringToString(const Source: string; Format: TDECFormatClass = nil): string; overload;
/// <summary>
/// Decrypts the contents of the passed RawByteString string
/// </summary>
/// <param name="Source">
/// String to decrypt
/// </param>
/// <param name="Format">
/// Optional parameter. One can pass a class reference of one of the
/// concrete data formatting classes here which will be internally used
/// to convert the data. Decoded will be the encrypted data, not the
/// decrypted data. Formattings can be used to convert data into a format
/// suitable for the transport medium the data shall be transported with.
/// </param>
/// <returns>
/// Decrypted string
/// </returns>
/// <remarks>
/// The use of this method is only recommended if a formatting is passed
/// which uses an 7-bit ASCII compatible string as input so that it
/// didn't get altered by string processing in some hafrmful way
/// </remarks>
function DecodeStringToString(const Source: RawByteString; Format: TDECFormatClass = nil): RawByteString; overload;
{$IFDEF ANSISTRINGSUPPORTED}
/// <summary>
/// Encrypts the contents of the passed Ansistring
/// </summary>
/// <param name="Source">
/// String to encrypt
/// </param>
/// <param name="Format">
/// Optional parameter. One can pass a class reference of one of the
/// concrete data formatting classes here which will be internally used
/// to convert the data. Encoded will be the encrypted data, not the
/// source data. Formattings can be used to convert data into a format
/// suitable for the transport medium the data shall be transported with.
/// </param>
/// <returns>
/// Encrypted string as a byte array
/// </returns>
function EncodeStringToBytes(const Source: AnsiString; Format: TDECFormatClass = nil): TBytes; overload;
/// <summary>
/// Encrypts the contents of the passed Ansistring
/// </summary>
/// <param name="Source">
/// String to encrypt
/// </param>
/// <param name="Format">
/// Optional parameter. One can pass a class reference of one of the
/// concrete data formatting classes here which will be internally used
/// to convert the data. Encoded will be the encrypted data, not the
/// source data. Formattings can be used to convert data into a format
/// suitable for the transport medium the data shall be transported with.
/// </param>
/// <returns>
/// Encrypted string as an AnsiString
/// </returns>
/// <remarks>
/// The use of this method is only recommended if a formatting is passed
/// which will result in an 7-bit ASCII compatible string as we cannot
/// ensure that string processing will not alter/interpret some
/// byte combinations in a destructive way, making the encrypted string
/// un-decryptable.
/// </remarks>
function EncodeStringToString(const Source: AnsiString; Format: TDECFormatClass = nil): AnsiString; overload;
/// <summary>
/// Decrypts the contents of the passed encrypted Ansistring
/// </summary>
/// <param name="Source">
/// String to decrypt
/// </param>
/// <param name="Format">
/// Optional parameter. One can pass a class reference of one of the
/// concrete data formatting classes here which will be internally used
/// to convert the data. Decoded will be the still encrypted data, not the
/// encrypted data. Formattings can be used to convert data into a format
/// suitable for the transport medium the data shall be transported with.
/// </param>
/// <returns>
/// Decrypted string as a byte array
/// </returns>
function DecodeStringToBytes(const Source: AnsiString; Format: TDECFormatClass = nil): TBytes; overload;
/// <summary>
/// Decrypts the contents of the passed AnsiString string
/// </summary>
/// <param name="Source">
/// String to decrypt
/// </param>
/// <param name="Format">
/// Optional parameter. One can pass a class reference of one of the
/// concrete data formatting classes here which will be internally used
/// to convert the data. Decoded will be the encrypted data, not the
/// decrypted data. Formattings can be used to convert data into a format
/// suitable for the transport medium the data shall be transported with.
/// </param>
/// <returns>
/// Decrypted string
/// </returns>
/// <remarks>
/// The use of this method is only recommended if a formatting is passed
/// which uses an 7-bit ASCII compatible string as input so that it
/// didn't get altered by string processing in some hafrmful way
/// </remarks>
function DecodeStringToString(const Source: AnsiString; Format: TDECFormatClass = nil): AnsiString; overload;
{$ENDIF}
{$IFNDEF NEXTGEN}
/// <summary>
/// Encrypts the contents of the passed Widestring
/// </summary>
/// <param name="Source">
/// String to encrypt
/// </param>
/// <param name="Format">
/// Optional parameter. One can pass a class reference of one of the
/// concrete data formatting classes here which will be internally used
/// to convert the data. Encoded will be the encrypted data, not the
/// source data. Formattings can be used to convert data into a format
/// suitable for the transport medium the data shall be transported with.
/// </param>
/// <returns>
/// Encrypted string as a byte array
/// </returns>
function EncodeStringToBytes(const Source: WideString; Format: TDECFormatClass = nil): TBytes; overload;
/// <summary>
/// Encrypts the contents of the passed Widestring
/// </summary>
/// <param name="Source">
/// String to encrypt
/// </param>
/// <param name="Format">
/// Optional parameter. One can pass a class reference of one of the
/// concrete data formatting classes here which will be internally used
/// to convert the data. Encoded will be the encrypted data, not the
/// source data. Formattings can be used to convert data into a format
/// suitable for the transport medium the data shall be transported with.
/// </param>
/// <returns>
/// Encrypted string as an WideString
/// </returns>
/// <remarks>
/// The use of this method is only recommended if a formatting is passed
/// which will result in an 7-bit ASCII compatible string as we cannot
/// ensure that string processing will not alter/interpret some
/// byte combinations in a destructive way, making the encrypted string
/// un-decryptable.
/// </remarks>
function EncodeStringToString(const Source: WideString; Format: TDECFormatClass = nil): WideString; overload;
/// <summary>
/// Decrypts the contents of the passed encrypted Widestring
/// </summary>
/// <param name="Source">
/// String to decrypt
/// </param>
/// <param name="Format">
/// Optional parameter. One can pass a class reference of one of the
/// concrete data formatting classes here which will be internally used
/// to convert the data. Decoded will be the still encrypted data, not the
/// encrypted data. Formattings can be used to convert data into a format
/// suitable for the transport medium the data shall be transported with.
/// </param>
/// <returns>
/// Decrypted string as a byte array
/// </returns>
function DecodeStringToBytes(const Source: WideString; Format: TDECFormatClass = nil): TBytes; overload;
/// <summary>
/// Decrypts the contents of the passed WideString string
/// </summary>
/// <param name="Source">
/// String to decrypt
/// </param>
/// <param name="Format">
/// Optional parameter. One can pass a class reference of one of the
/// concrete data formatting classes here which will be internally used
/// to convert the data. Decoded will be the encrypted data, not the
/// decrypted data. Formattings can be used to convert data into a format
/// suitable for the transport medium the data shall be transported with.
/// </param>
/// <returns>
/// Decrypted string
/// </returns>
/// <remarks>
/// The use of this method is only recommended if a formatting is passed
/// which uses an 7-bit ASCII compatible string as input so that it
/// didn't get altered by string processing in some hafrmful way
/// </remarks>
function DecodeStringToString(const Source: WideString; Format: TDECFormatClass = nil): WideString; overload;
{$ENDIF}
/// <summary>
/// Initializes the cipher with the necessary encryption/decryption key
/// </summary>
/// <param name="Key">
/// Encryption/decryption key. Recommended/required key length is dependant
/// on the concrete algorithm.
/// </param>
/// <param name="Size">
/// Size of the key in bytes
/// </param>
/// <param name="IVector">
/// Initialization vector. This contains the values the first block of
/// data to be processed is linked with. This is being done the same way
/// as the 2nd block of the data to be processed will be linked with the
/// first block and so on and this is dependant on the cypher mode set via
/// Mode property
/// </param>
/// <param name="IVectorSize">
/// Size of the initialization vector in bytes
/// </param>
/// <param name="IFiller">
/// optional parameter defining the value with which the last block will
/// be filled up if the size of the data to be processed cannot be divided
/// by block size without reminder. Means: if the last block is not
/// completely filled with data.
/// </param>
procedure Init(const Key; Size: Integer; const IVector; IVectorSize: Integer; IFiller: Byte = $FF); overload;
/// <summary>
/// Initializes the cipher with the necessary encryption/decryption key
/// </summary>
/// <param name="Key">
/// Encryption/decryption key. Recommended/required key length is dependant
/// on the concrete algorithm.
/// </param>
/// <param name="IVector">
/// Initialization vector. This contains the values the first block of
/// data to be processed is linked with. This is being done the same way
/// as the 2nd block of the data to be processed will be linked with the
/// first block and so on and this is dependant on the cypher mode set via
/// Mode property
/// </param>
/// <param name="IFiller">
/// optional parameter defining the value with which the last block will
/// be filled up if the size of the data to be processed cannot be divided
/// by block size without reminder. Means: if the last block is not
/// completely filled with data.
/// </param>
procedure Init(const Key: TBytes; const IVector: TBytes; IFiller: Byte = $FF); overload;
/// <summary>
/// Initializes the cipher with the necessary encryption/decryption key
/// </summary>
/// <param name="Key">
/// Encryption/decryption key. Recommended/required key length is dependant
/// on the concrete algorithm.
/// </param>
/// <param name="IVector">
/// Initialization vector. This contains the values the first block of
/// data to be processed is linked with. This is being done the same way
/// as the 2nd block of the data to be processed will be linked with the
/// first block and so on and this is dependant on the cypher mode set via
/// Mode property
/// </param>
/// <param name="IFiller">
/// optional parameter defining the value with which the last block will
/// be filled up if the size of the data to be processed cannot be divided
/// by block size without reminder. Means: if the last block is not
/// completely filled with data.
/// </param>
procedure Init(const Key: RawByteString; const IVector: RawByteString = ''; IFiller: Byte = $FF); overload;
{$IFDEF ANSISTRINGSUPPORTED}
/// <summary>
/// Initializes the cipher with the necessary encryption/decryption key.
/// Only for use with the classic desktop compilers.
/// </summary>
/// <param name="Key">
/// Encryption/decryption key. Recommended/required key length is dependant
/// on the concrete algorithm.
/// </param>
/// <param name="IVector">
/// Initialization vector. This contains the values the first block of
/// data to be processed is linked with. This is being done the same way
/// as the 2nd block of the data to be processed will be linked with the
/// first block and so on and this is dependant on the cypher mode set via
/// Mode property
/// </param>
/// <param name="IFiller">
/// optional parameter defining the value with which the last block will
/// be filled up if the size of the data to be processed cannot be divided
/// by block size without reminder. Means: if the last block is not
/// completely filled with data.
/// </param>
procedure Init(const Key: AnsiString; const IVector: AnsiString = ''; IFiller: Byte = $FF); overload;
{$ENDIF}
{$IFNDEF NEXTGEN}
/// <summary>
/// Initializes the cipher with the necessary encryption/decryption key.
/// Only for use with the classic desktop compilers.
/// </summary>
/// <param name="Key">
/// Encryption/decryption key. Recommended/required key length is dependant
/// on the concrete algorithm.
/// </param>
/// <param name="IVector">
/// Initialization vector. This contains the values the first block of
/// data to be processed is linked with. This is being done the same way
/// as the 2nd block of the data to be processed will be linked with the
/// first block and so on and this is dependant on the cypher mode set via
/// Mode property
/// </param>
/// <param name="IFiller">
/// optional parameter defining the value with which the last block will
/// be filled up if the size of the data to be processed cannot be divided
/// by block size without reminder. Means: if the last block is not
/// completely filled with data.
/// </param>
procedure Init(const Key: WideString; const IVector: WideString = ''; IFiller: Byte = $FF); overload;
{$ENDIF}
/// <summary>
/// Returns the currently set cipher block mode, means how blocks are
/// linked to each other in order to avoid certain attacks.
/// </summary>
function GetMode: TCipherMode;
/// <summary>
/// Sets the cipher mode, means how each block is being linked with his
/// predecessor to avoid certain attacks
/// </summary>
procedure SetMode(Value: TCipherMode);
/// <summary>
/// Mode used for padding data to be encrypted/decrypted. See TCipherMode.
/// </summary>
property Mode: TCipherMode
read GetMode
write SetMode;
end;
implementation
end.

View File

@@ -0,0 +1,919 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
unit DECCipherModes;
interface
{$INCLUDE DECOptions.inc}
uses
{$IFDEF FPC}
SysUtils,
{$ELSE}
System.SysUtils,
{$ENDIF}
DECCipherBase;
{$I DECOptions.inc}
type
/// <summary>
/// Most ciphers are block oriented and thus work on blocks of a fixed size.
/// In order to not encrypt each block separately without any link to his
/// predecessor and sucessor, which would make attacks on the encrypted data
/// easier, each block should be linked with his predecessor (or the
/// initialization vector). This class implements the various supported
/// algorithms for linking blocks.
/// </summary>
TDECCipherModes = class(TDECCipher)
strict protected
/// <summary>
/// Raises an EDECCipherException exception and provides the correct values
/// for message lenght and block size
/// </summary>
procedure ReportInvalidMessageLength(Cipher: TDECCipher);
/// <summary>
/// Electronic Code Book
/// Mode cmECBx needs message padding to be a multiple of Cipher.BlockSize
/// and should be used only in 1-byte Streamciphers.
/// This one works on Blocks of Cipher.BufferSize bytes, when using a
/// Blockcipher that's equal to Cipher.BlockSize.
/// </summary>
/// <remarks>
/// This mode should not be used in practice, as it makes the encrypted
/// message vulnerable to certain attacks without knowing the encryption key
/// </remarks>
procedure EncodeECBx(Source, Dest: PByteArray; Size: Integer); virtual;
/// <summary>
/// 8bit Output Feedback mode, needs no padding
/// </summary>
procedure EncodeOFB8(Source, Dest: PByteArray; Size: Integer); virtual;
/// <summary>
/// 8 bit Cipher Feedback mode, needs no padding and works on 8 bit
/// Feedback Shift Registers.
/// </summary>
procedure EncodeCFB8(Source, Dest: PByteArray; Size: Integer); virtual;
/// <summary>
/// 8Bit CFS, double Cipher Feedback mode (CFB), needs no padding and
/// works on 8 bit Feedback Shift Registers.
/// This one is a proprietary mode developed by Hagen Reddmann. This mode
/// works as cmCBCx, cmCFBx, cmCFB8 but with double XOR'ing of the
/// inputstream into Feedback register.
/// </summary>
procedure EncodeCFS8(Source, Dest: PByteArray; Size: Integer); virtual;
/// <summary>
/// Cipher Feedback mode (CFB) on Blocksize of Cipher, needs no padding
/// This one works on Blocks of Cipher.BufferSize bytes, when using a
/// Blockcipher that's equal to Cipher.BlockSize.
/// </summary>
procedure EncodeCFBx(Source, Dest: PByteArray; Size: Integer); virtual;
/// <summary>
/// Output Feedback mode on Blocksize of Cipher, needs no padding and
/// works on 8 bit Feedback Shift Registers.
/// This one works on Blocks of Cipher.BufferSize bytes, when using a
/// Blockcipher that's equal to Cipher.BlockSize.
/// </summary>
procedure EncodeOFBx(Source, Dest: PByteArray; Size: Integer); virtual;
/// <summary>
/// double Cipher Feedback mode (CFB) on Blocksize of Cipher, needs no padding.
/// This one works on Blocks of Cipher.BufferSize bytes, when using a
/// Blockcipher that's equal to Cipher.BlockSize.
/// This one is a proprietary mode developed by Hagen Reddmann. This mode
/// works as cmCBCx, cmCFBx, cmCFB8 but with double XOR'ing of the
/// inputstream into Feedback register.
/// </summary>
procedure EncodeCFSx(Source, Dest: PByteArray; Size: Integer); virtual;
/// <summary>
/// Cipher Block Chaining, with CFB8 padding of truncated final block
/// It needs no external padding, because internally the last
/// truncated block is padded by cmCFS8 or cmCFB8. After padding these Modes
/// cannot be used to process any more data. If needed to process chunks of
/// data then each chunk must be aligned to Cipher.BufferSize bytes.
/// This one works on Blocks of Cipher.BufferSize bytes, when using a
/// Blockcipher that's equal to Cipher.BlockSize.
/// </summary>
procedure EncodeCBCx(Source, Dest: PByteArray; Size: Integer); virtual;
/// <summary>
/// double CBC, with CFS8 padding of truncated final block
/// It needs no external padding, because internally the last
/// truncated block is padded by cmCFS8 or cmCFB8. After padding these Modes
/// cannot be used to process any more data. If needed to process chunks of
/// data then each chunk must be aligned to Cipher.BufferSize bytes.
/// This one works on Blocks of Cipher.BufferSize bytes, when using a
/// Blockcipher that's equal to Cipher.BlockSize.
/// This one is a proprietary mode developed by Hagen Reddmann. This mode
/// works as cmCBCx, cmCFBx, cmCFB8 but with double XOR'ing of the
/// inputstream into Feedback register.
/// </summary>
procedure EncodeCTSx(Source, Dest: PByteArray; Size: Integer); virtual;
{$IFDEF DEC3_CMCTS}
/// <summary>
/// double CBC, with
/// for DEC 3.0 compatibility only
/// This is a proprietary mode developed by Frederik Winkelsdorf. It
/// replaces the CFS8 padding of the truncated final block with a CFSx padding.
/// Useful when converting projects that previously used the old DEC v3.0. It
/// has the same restrictions for external padding and chunk processing as
/// cmCTSx has. It has a less secure padding of the truncated final block.
/// (to enable it see DECOptions.inc)
/// </summary>
procedure EncodeCTS3(Source, Dest: PByteArray; Size: Integer); virtual;
{$ENDIF}
/// <summary>
/// Electronic Code Book
/// Mode cmECBx needs message padding to be a multiple of Cipher.BlockSize
/// and should be used only in 1-byte Streamciphers.
/// This one works on blocks of Cipher.BufferSize bytes, when using a
/// blockcipher that's equal to Cipher.BlockSize.
/// </summary>
procedure DecodeECBx(Source, Dest: PByteArray; Size: Integer); virtual;
/// <summary>
/// 8 bit Output Feedback mode, needs no padding
/// </summary>
procedure DecodeOFB8(Source, Dest: PByteArray; Size: Integer); virtual;
/// <summary>
/// 8 bit Cipher Feedback mode, needs no padding and works on 8 bit
/// Feedback Shift Registers.
/// </summary>
procedure DecodeCFB8(Source, Dest: PByteArray; Size: Integer); virtual;
/// <summary>
/// 8 Bit CFS, double Cipher Feedback mode (CFB), needs no padding and
/// works on 8 bit Feedback Shift Registers.
/// This one is a proprietary mode developed by Hagen Reddmann. This mode
/// works as cmCBCx, cmCFBx, cmCFB8 but with double XOR'ing of the
/// inputstream into Feedback register.
/// </summary>
procedure DecodeCFS8(Source, Dest: PByteArray; Size: Integer); virtual;
/// <summary>
/// Cipher Feedback mode (CFB) on Blocksize of Cipher, needs no padding
/// This one works on blocks of Cipher.BufferSize bytes, when using a
/// blockcipher that's equal to Cipher.BlockSize.
/// </summary>
procedure DecodeCFBx(Source, Dest: PByteArray; Size: Integer); virtual;
/// <summary>
/// Output Feedback mode on Blocksize of Cipher, needs no padding and
/// works on 8 bit Feedback Shift Registers.
/// This one works on blocks of Cipher.BufferSize bytes, when using a
/// blockcipher that's equal to Cipher.BlockSize.
/// </summary>
procedure DecodeOFBx(Source, Dest: PByteArray; Size: Integer); virtual;
/// <summary>
/// double Cipher Feedback mode (CFB) on Blocksize of Cipher, needs no padding.
/// This one works on blocks of Cipher.BufferSize bytes, when using a
/// blockcipher that's equal to Cipher.BlockSize.
/// This one is a proprietary mode developed by Hagen Reddmann. This mode
/// works as cmCBCx, cmCFBx, cmCFB8 but with double XOR'ing of the
/// inputstream into Feedback register.
/// </summary>
procedure DecodeCFSx(Source, Dest: PByteArray; Size: Integer); virtual;
/// <summary>
/// Cipher Block Chaining, with CFB8 padding of truncated final block.
/// It needs no external padding, because internally the last
/// truncated block is padded by cmCFS8 or cmCFB8. After padding these modes
/// cannot be used to process any more data. If needed to process chunks of
/// data then each chunk must be algined to Cipher.BufferSize bytes.
/// This one works on blocks of Cipher.BufferSize bytes, when using a
/// blockcipher that's equal to Cipher.BlockSize.
/// </summary>
procedure DecodeCBCx(Source, Dest: PByteArray; Size: Integer); virtual;
/// <summary>
/// double CBC, with CFS8 padding of truncated final block
/// It needs no external padding, because internally the last
/// truncated block is padded by cmCFS8 or cmCFB8. After padding these Modes
/// cannot be used to process any more data. If needed to process chunks of
/// data then each chunk must be algined to Cipher.BufferSize bytes.
/// This one works on blocks of Cipher.BufferSize bytes, when using a
/// blockcipher that's equal to Cipher.BlockSize.
/// This one is a proprietary mode developed by Hagen Reddmann. This mode
/// works as cmCBCx, cmCFBx, cmCFB8 but with double XOR'ing of the
/// inputstream into feedback register.
/// </summary>
procedure DecodeCTSx(Source, Dest: PByteArray; Size: Integer); virtual;
{$IFDEF DEC3_CMCTS}
/// <summary>
/// double CBC
/// This is a proprietary mode developed by Frederik Winkelsdorf. It
/// replaces the CFS8 padding of the truncated final block with a CFSx padding.
/// Useful when converting projects that previously used the old DEC v3.0. It
/// has the same restrictions for external padding and chunk processing as
/// cmCTSx has. It has a less secure padding of the truncated final block.
/// (to enable it see DECOptions.inc)
/// </summary>
/// <remarks>
/// For DEC 3.0 compatibility only
/// </remarks>
procedure DecodeCTS3(Source, Dest: PByteArray; Size: Integer); virtual;
{$ENDIF}
public
/// <summary>
/// Encrypts a given block of data
/// </summary>
/// <param name="Source">
/// Data to be encrypted
/// </param>
/// <param name="Dest">
/// Data after encryption
/// </param>
/// <param name="DataSize">
/// Size of the data the Source parameter points to in byte
/// </param>
procedure Encode(const Source; var Dest; DataSize: Integer);
/// <summary>
/// Decrypts a given block of data
/// </summary>
/// <param name="Source">
/// Data to be Decrypted
/// </param>
/// <param name="Dest">
/// Data after decryption
/// </param>
/// <param name="DataSize">
/// Size of the data the Source parameter points to in byte
/// </param>
procedure Decode(const Source; var Dest; DataSize: Integer);
end;
implementation
uses
{$IFDEF FPC}
TypInfo,
{$ELSE}
System.TypInfo,
{$ENDIF}
DECUtil;
resourcestring
sInvalidMessageLength = 'Message length for mode %0:s must be a multiple of %1:d bytes';
procedure TDECCipherModes.ReportInvalidMessageLength(Cipher: TDECCipher);
begin
raise EDECCipherException.CreateResFmt(@sInvalidMessageLength,
[System.TypInfo.GetEnumName(TypeInfo(TCipherMode),
Integer(Cipher.Mode)),
Cipher.Context.BlockSize]);
end;
procedure TDECCipherModes.Encode(const Source; var Dest; DataSize: Integer);
begin
CheckState([csInitialized, csEncode, csDone]);
case FMode of
cmECBx: EncodeECBx(@Source, @Dest, DataSize);
cmCBCx: EncodeCBCx(@Source, @Dest, DataSize);
cmCTSx: EncodeCTSx(@Source, @Dest, DataSize);
{$IFDEF DEC3_CMCTS}
cmCTS3: EncodeCTS3(@Source, @Dest, DataSize);
{$ENDIF DEC3_CMCTS}
cmCFB8: EncodeCFB8(@Source, @Dest, DataSize);
cmCFBx: EncodeCFBx(@Source, @Dest, DataSize);
cmOFB8: EncodeOFB8(@Source, @Dest, DataSize);
cmOFBx: EncodeOFBx(@Source, @Dest, DataSize);
cmCFS8: EncodeCFS8(@Source, @Dest, DataSize);
cmCFSx: EncodeCFSx(@Source, @Dest, DataSize);
end;
end;
procedure TDECCipherModes.EncodeECBx(Source, Dest: PByteArray; Size: Integer);
var
I: Integer;
begin
if Context.BlockSize = 1 then
begin
DoEncode(Source, Dest, Size);
FState := csEncode;
end
else
begin
Dec(Size, FBufferSize);
I := 0;
while I <= Size do
begin
DoEncode(@Source[I], @Dest[I], FBufferSize);
Inc(I, FBufferSize);
end;
Dec(Size, I - FBufferSize);
if Size > 0 then
begin
if Size mod Context.BlockSize = 0 then
begin
DoEncode(@Source[I], @Dest[I], Size);
FState := csEncode;
end
else
begin
FState := csPadded;
ReportInvalidMessageLength(Self);
end;
end;
end;
end;
procedure TDECCipherModes.EncodeOFB8(Source, Dest: PByteArray; Size: Integer);
var
I: Integer;
begin
I := 0;
while I < Size do
begin
DoEncode(FFeedback, FBuffer, FBufferSize);
Move(FFeedback[1], FFeedback[0], FBufferSize - 1);
FFeedback[FBufferSize - 1] := FBuffer[0];
Dest[I] := Source[I] xor FBuffer[0];
Inc(I);
end;
FState := csEncode;
end;
procedure TDECCipherModes.EncodeCFB8(Source, Dest: PByteArray; Size: Integer);
// CFB-8
var
I: Integer;
begin
I := 0;
while I < Size do
begin
DoEncode(FFeedback, FBuffer, FBufferSize);
Move(FFeedback[1], FFeedback[0], FBufferSize - 1);
Dest[I] := Source[I] xor FBuffer[0];
FFeedback[FBufferSize - 1] := Dest[I];
Inc(I);
end;
FState := csEncode;
end;
procedure TDECCipherModes.EncodeCFS8(Source, Dest: PByteArray; Size: Integer);
// CFS-8, CTS as CFB
var
I: Integer;
begin
I := 0;
while I < Size do
begin
DoEncode(FFeedback, FBuffer, FBufferSize);
Dest[I] := Source[I] xor FBuffer[0];
Move(FFeedback[1], FFeedback[0], FBufferSize - 1);
FFeedback[FBufferSize - 1] := FFeedback[FBufferSize - 1] xor Dest[I];
Inc(I);
end;
FState := csEncode;
end;
procedure TDECCipherModes.EncodeCFBx(Source, Dest: PByteArray; Size: Integer);
// CFB-BlockSize
var
I: Integer;
F: PByteArray;
begin
FState := csEncode;
if FBufferIndex > 0 then
begin
I := FBufferSize - FBufferIndex;
if I > Size then
I := Size;
XORBuffers(Source[0], FBuffer[FBufferIndex], I, Dest[0]);
Move(Dest[0], FFeedback[FBufferIndex], I);
Inc(FBufferIndex, I);
if FBufferIndex < FBufferSize then
Exit;
Dec(Size, I);
Source := @Source[I];
Dest := @Dest[I];
FBufferIndex := 0
end;
Dec(Size, FBufferSize);
F := FFeedback;
I := 0;
while I < Size do
begin
DoEncode(F, FBuffer, FBufferSize);
XORBuffers(Source[I], FBuffer[0], FBufferSize, Dest[I]);
F := @Dest[I];
Inc(I, FBufferSize);
end;
if F <> FFeedback then
Move(F^, FFeedback^, FBufferSize);
Dec(Size, I - FBufferSize);
if Size > 0 then
begin
DoEncode(FFeedback, FBuffer, FBufferSize);
XORBuffers(Source[I], FBuffer[0], Size, Dest[I]);
Move(Dest[I], FFeedback[0], Size);
FBufferIndex := Size;
end;
end;
procedure TDECCipherModes.EncodeOFBx(Source, Dest: PByteArray; Size: Integer);
// OFB-BlockSize
var
I: Integer;
begin
FState := csEncode;
if FBufferIndex > 0 then
begin
I := FBufferSize - FBufferIndex;
if I > Size then
I := Size;
XORBuffers(Source[0], FFeedback[FBufferIndex], I, Dest[0]);
Inc(FBufferIndex, I);
if FBufferIndex < FBufferSize then
Exit;
Dec(Size, I);
Source := @Source[I];
Dest := @Dest[I];
FBufferIndex := 0
end;
Dec(Size, FBufferSize);
I := 0;
while I < Size do
begin
DoEncode(FFeedback, FFeedback, FBufferSize);
XORBuffers(Source[I], FFeedback[0], FBufferSize, Dest[I]);
Inc(I, FBufferSize);
end;
Dec(Size, I - FBufferSize);
if Size > 0 then
begin
DoEncode(FFeedback, FFeedback, FBufferSize);
XORBuffers(Source[I], FFeedback[0], Size, Dest[I]);
FBufferIndex := Size;
end;
end;
procedure TDECCipherModes.EncodeCFSx(Source, Dest: PByteArray; Size: Integer);
// CFS-BlockSize
var
I: Integer;
begin
FState := csEncode;
if FBufferIndex > 0 then
begin
I := FBufferSize - FBufferIndex;
if I > Size then
I := Size;
XORBuffers(Source[0], FBuffer[FBufferIndex], I, Dest[0]);
XORBuffers(Dest[0], FFeedback[FBufferIndex], I, FFeedback[FBufferIndex]);
Inc(FBufferIndex, I);
if FBufferIndex < FBufferSize then
Exit;
Dec(Size, I);
Source := @Source[I];
Dest := @Dest[I];
FBufferIndex := 0
end;
Dec(Size, FBufferSize);
I := 0;
while I < Size do
begin
DoEncode(FFeedback, FBuffer, FBufferSize);
XORBuffers(Source[I], FBuffer[0], FBufferSize, Dest[I]);
XORBuffers(Dest[I], FFeedback[0], FBufferSize, FFeedback[0]);
Inc(I, FBufferSize);
end;
Dec(Size, I - FBufferSize);
if Size > 0 then
begin
DoEncode(FFeedback, FBuffer, FBufferSize);
XORBuffers(Source[I], FBuffer[0], Size, Dest[I]);
XORBuffers(Dest[I], FFeedback[0], Size, FFeedback[0]);
FBufferIndex := Size;
end;
end;
procedure TDECCipherModes.EncodeCBCx(Source, Dest: PByteArray; Size: Integer);
var
F: PByteArray;
I: Integer;
begin
Dec(Size, FBufferSize);
F := FFeedback;
I := 0;
while I <= Size do
begin
XORBuffers(Source[I], F[0], FBufferSize, Dest[I]);
F := @Dest[I];
DoEncode(F, F, FBufferSize);
Inc(I, FBufferSize);
end;
if F <> FFeedback then
Move(F[0], FFeedback[0], FBufferSize);
Dec(Size, I - FBufferSize);
if Size > 0 then
begin // padding
EncodeCFB8(@Source[I], @Dest[I], Size);
FState := csPadded;
end
else
FState := csEncode;
end;
procedure TDECCipherModes.EncodeCTSx(Source, Dest: PByteArray; Size: Integer);
var
I: Integer;
begin
Dec(Size, FBufferSize);
I := 0;
while I <= Size do
begin
XORBuffers(Source[I], FFeedback[0], FBufferSize, Dest[I]);
DoEncode(@Dest[I], @Dest[I], FBufferSize);
XORBuffers(Dest[I], FFeedback[0], FBufferSize, FFeedback[0]);
Inc(I, FBufferSize);
end;
Dec(Size, I - FBufferSize);
if Size > 0 then
begin // padding
EncodeCFS8(@Source[I], @Dest[I], Size);
FState := csPadded;
end
else
FState := csEncode;
end;
{$IFDEF DEC3_CMCTS}
procedure TDECCipherModes.EncodeCTS3(Source, Dest: PByteArray; Size: Integer);
var
I: Integer;
begin
Dec(Size, FBufferSize);
I := 0;
while I <= Size do
begin
XORBuffers(Source[I], FFeedback[0], FBufferSize, Dest[I]);
DoEncode(@Dest[I], @Dest[I], FBufferSize);
XORBuffers(Dest[I], FFeedback[0], FBufferSize, FFeedback[0]);
Inc(I, FBufferSize);
end;
Dec(Size, I - FBufferSize);
if Size > 0 then
begin // padding
EncodeCFSx(@Source[I], @Dest[I], Size); // use the padding implemented in CFSx
FState := csPadded;
end
else
FState := csEncode;
end;
{$ENDIF DEC3_CMCTS}
procedure TDECCipherModes.Decode(const Source; var Dest; DataSize: Integer);
begin
CheckState([csInitialized, csDecode, csDone]);
case FMode of
cmECBx: DecodeECBx(@Source, @Dest, DataSize);
cmCBCx: DecodeCBCx(@Source, @Dest, DataSize);
cmCTSx: DecodeCTSx(@Source, @Dest, DataSize);
{$IFDEF DEC3_CMCTS}
cmCTS3: DecodeCTS3(@Source, @Dest, DataSize);
{$ENDIF DEC3_CMCTS}
cmCFB8: DecodeCFB8(@Source, @Dest, DataSize);
cmCFBx: DecodeCFBx(@Source, @Dest, DataSize);
cmOFB8: DecodeOFB8(@Source, @Dest, DataSize);
cmOFBx: DecodeOFBx(@Source, @Dest, DataSize);
cmCFS8: DecodeCFS8(@Source, @Dest, DataSize);
cmCFSx: DecodeCFSx(@Source, @Dest, DataSize);
end;
end;
procedure TDECCipherModes.DecodeECBx(Source, Dest: PByteArray; Size: Integer);
var
I: Integer;
begin
if Context.BlockSize = 1 then
begin
DoDecode(Source, Dest, Size);
FState := csDecode;
end
else
begin
Dec(Size, FBufferSize);
I := 0;
while I <= Size do
begin
DoDecode(@Source[I], @Dest[I], FBufferSize);
Inc(I, FBufferSize);
end;
Dec(Size, I - FBufferSize);
if Size > 0 then
begin
if Size mod Context.BlockSize = 0 then
begin
DoDecode(@Source[I], @Dest[I], Size);
FState := csDecode;
end
else
begin
FState := csPadded;
ReportInvalidMessageLength(Self);
end;
end;
end;
end;
procedure TDECCipherModes.DecodeCFB8(Source, Dest: PByteArray; Size: Integer);
// CFB-8
var
I: Integer;
begin
I := 0;
while I < Size do
begin
DoEncode(FFeedback, FBuffer, FBufferSize);
Move(FFeedback[1], FFeedback[0], FBufferSize - 1);
FFeedback[FBufferSize - 1] := Source[I];
Dest[I] := Source[I] xor FBuffer[0];
Inc(I);
end;
FState := csDecode;
end;
procedure TDECCipherModes.DecodeOFB8(Source, Dest: PByteArray; Size: Integer);
// same as EncodeOFB
var
I: Integer;
begin
I := 0;
while I < Size do
begin
DoEncode(FFeedback, FBuffer, FBufferSize);
Move(FFeedback[1], FFeedback[0], FBufferSize - 1);
FFeedback[FBufferSize - 1] := FBuffer[0];
Dest[I] := Source[I] xor FBuffer[0];
Inc(I);
end;
FState := csDecode;
end;
procedure TDECCipherModes.DecodeCFS8(Source, Dest: PByteArray; Size: Integer);
var
I: Integer;
begin
I := 0;
while I < Size do
begin
DoEncode(FFeedback, FBuffer, FBufferSize);
Move(FFeedback[1], FFeedback[0], FBufferSize - 1);
FFeedback[FBufferSize - 1] := FFeedback[FBufferSize - 1] xor Source[I];
Dest[I] := Source[I] xor FBuffer[0];
Inc(I);
end;
FState := csDecode;
end;
procedure TDECCipherModes.DecodeCFBx(Source, Dest: PByteArray; Size: Integer);
// CFB-BlockSize
var
I: Integer;
F: PByteArray;
begin
FState := csDecode;
if FBufferIndex > 0 then
begin // remaining bytes of last decode
I := FBufferSize - FBufferIndex;
if I > Size then
I := Size;
Move(Source[0], FFeedback[FBufferIndex], I);
XORBuffers(Source[0], FBuffer[FBufferIndex], I, Dest[0]);
Inc(FBufferIndex, I);
if FBufferIndex < FBufferSize then
Exit;
Dec(Size, I);
Source := @Source[I];
Dest := @Dest[I];
FBufferIndex := 0
end;
// process chunks of FBufferSize bytes
Dec(Size, FBufferSize);
I := 0;
if Source <> Dest then
begin
F := FFeedback;
while I < Size do
begin
DoEncode(F, FBuffer, FBufferSize);
XORBuffers(Source[I], FBuffer[0], FBufferSize, Dest[I]);
F := @Source[I];
Inc(I, FBufferSize);
end;
if F <> FFeedback then
Move(F^, FFeedback^, FBufferSize);
end
else
while I < Size do
begin
DoEncode(FFeedback, FBuffer, FBufferSize);
Move(Source[I], FFeedback[0], FBufferSize);
XORBuffers(Source[I], FBuffer[0], FBufferSize, Dest[I]);
Inc(I, FBufferSize);
end;
Dec(Size, I - FBufferSize);
if Size > 0 then
begin // remaining bytes
DoEncode(FFeedback, FBuffer, FBufferSize);
Move(Source[I], FFeedback[0], Size);
XORBuffers(Source[I], FBuffer[0], Size, Dest[I]);
FBufferIndex := Size;
end;
end;
procedure TDECCipherModes.DecodeOFBx(Source, Dest: PByteArray; Size: Integer);
// OFB-BlockSize, same as EncodeOFBx
var
I: Integer;
begin
FState := csDecode;
if FBufferIndex > 0 then
begin
I := FBufferSize - FBufferIndex;
if I > Size then
I := Size;
XORBuffers(Source[0], FFeedback[FBufferIndex], I, Dest[0]);
Inc(FBufferIndex, I);
if FBufferIndex < FBufferSize then
Exit;
Dec(Size, I);
Source := @Source[I];
Dest := @Dest[I];
FBufferIndex := 0
end;
Dec(Size, FBufferSize);
I := 0;
while I < Size do
begin
DoEncode(FFeedback, FFeedback, FBufferSize);
XORBuffers(Source[I], FFeedback[0], FBufferSize, Dest[I]);
Inc(I, FBufferSize);
end;
Dec(Size, I - FBufferSize);
if Size > 0 then
begin
DoEncode(FFeedback, FFeedback, FBufferSize);
XORBuffers(Source[I], FFeedback[0], Size, Dest[I]);
FBufferIndex := Size;
end;
end;
procedure TDECCipherModes.DecodeCFSx(Source, Dest: PByteArray; Size: Integer);
// CFS-BlockSize
var
I: Integer;
begin
FState := csDecode;
if FBufferIndex > 0 then
begin // remaining bytes of last decode
I := FBufferSize - FBufferIndex;
if I > Size then
I := Size;
XORBuffers(Source[0], FFeedback[FBufferIndex], I, FFeedback[FBufferIndex]);
XORBuffers(Source[0], FBuffer[FBufferIndex], I, Dest[0]);
Inc(FBufferIndex, I);
if FBufferIndex < FBufferSize then
Exit;
Dec(Size, I);
Source := @Source[I];
Dest := @Dest[I];
FBufferIndex := 0
end;
// process chunks of FBufferSize bytes
Dec(Size, FBufferSize);
I := 0;
while I < Size do
begin
DoEncode(FFeedback, FBuffer, FBufferSize);
XORBuffers(Source[I], FFeedback[0], FBufferSize, FFeedback[0]);
XORBuffers(Source[I], FBuffer[0], FBufferSize, Dest[I]);
Inc(I, FBufferSize);
end;
Dec(Size, I - FBufferSize);
if Size > 0 then
begin // remaining bytes
DoEncode(FFeedback, FBuffer, FBufferSize);
XORBuffers(Source[I], FFeedback[0], Size, FFeedback[0]);
XORBuffers(Source[I], FBuffer[0], Size, Dest[I]);
FBufferIndex := Size;
end;
end;
procedure TDECCipherModes.DecodeCBCx(Source, Dest: PByteArray; Size: Integer);
var
I: Integer;
F, B, T: PByteArray;
begin
Dec(Size, FBufferSize);
F := FFeedback;
I := 0;
if Source = Dest then
begin
B := FBuffer;
while I <= Size do
begin
Move(Source[I], B[0], FBufferSize);
DoDecode(@Source[I], @Source[I], FBufferSize);
XORBuffers(Source[I], F[0], FBufferSize, Source[I]);
T := F;
F := B;
B := T;
Inc(I, FBufferSize);
end;
end
else
begin
while I <= Size do
begin
DoDecode(@Source[I], @Dest[I], FBufferSize);
XORBuffers(F[0], Dest[I], FBufferSize, Dest[I]);
F := @Source[I];
Inc(I, FBufferSize);
end;
end;
if F <> FFeedback then
Move(F[0], FFeedback[0], FBufferSize);
Dec(Size, I - FBufferSize);
if Size > 0 then
begin
DecodeCFB8(@Source[I], @Dest[I], Size);
FState := csPadded;
end
else
FState := csDecode;
end;
procedure TDECCipherModes.DecodeCTSx(Source, Dest: PByteArray; Size: Integer);
var
I: Integer;
F, B, T: PByteArray;
begin
Dec(Size, FBufferSize);
F := FFeedback;
B := FBuffer;
I := 0;
while I <= Size do
begin
XORBuffers(Source[I], F[0], FBufferSize, B[0]);
DoDecode(@Source[I], @Dest[I], FBufferSize);
XORBuffers(Dest[I], F[0], FBufferSize, Dest[I]);
T := B;
B := F;
F := T;
Inc(I, FBufferSize);
end;
if F <> FFeedback then
Move(F[0], FFeedback[0], FBufferSize);
Dec(Size, I - FBufferSize);
if Size > 0 then
begin
DecodeCFS8(@Source[I], @Dest[I], Size);
FState := csPadded;
end
else
FState := csDecode;
end;
{$IFDEF DEC3_CMCTS}
procedure DecodeCTS3(Source, Dest: PByteArray; Size: Integer);
var
I: Integer;
F, B, T: PByteArray;
begin
Dec(Size, FBufferSize);
F := FFeedback;
B := FBuffer;
I := 0;
while I <= Size do
begin
XORBuffers(Source[I], F[0], FBufferSize, B[0]);
DoDecode(@Source[I], @Dest[I], FBufferSize);
XORBuffers(Dest[I], F[0], FBufferSize, Dest[I]);
T := B;
B := F;
F := T;
Inc(I, FBufferSize);
end;
if F <> FFeedback then
Move(F[0], FFeedback[0], FBufferSize);
Dec(Size, I - FBufferSize);
if Size > 0 then
begin
DecodeCFSx(@Source[I], @Dest[I], Size); // use the padding implemented in CFSx
FState := csPadded;
end
else
FState := csDecode;
end;
{$ENDIF DEC3_CMCTS}
end.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,167 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
/// <summary>
/// Data Arrays for the Hash and Cipher functions
/// </summary>
unit DECData;
interface
{$INCLUDE DECOptions.inc}
{$IFOPT Q+}{$DEFINE RESTORE_OVERFLOWCHECKS}{$Q-}{$ENDIF}
{$IFOPT R+}{$DEFINE RESTORE_RANGECHECKS}{$R-}{$ENDIF}
const
Square_TE: array[0..3, 0..255] of UInt32 = (
($26B1B197,$A7CECE69,$B0C3C373,$4A9595DF,$EE5A5AB4,$02ADADAF,$DCE7E73B,$06020204,
$D74D4D9A,$CC444488,$F8FBFB03,$469191D7,$140C0C18,$7C8787FB,$16A1A1B7,$F05050A0,
$A8CBCB63,$A96767CE,$FC5454A8,$92DDDD4F,$CA46468C,$648F8FEB,$D6E1E137,$D24E4E9C,
$E5F0F015,$F2FDFD0F,$F1FCFC0D,$C8EBEB23,$FEF9F907,$B9C4C47D,$2E1A1A34,$B26E6EDC,
$E25E5EBC,$EAF5F51F,$A1CCCC6D,$628D8DEF,$241C1C38,$FA5656AC,$C5434386,$F7FEFE09,
$0907070E,$A36161C2,$FDF8F805,$9F7575EA,$EB5959B2,$F4FFFF0B,$05030306,$66222244,
$6B8A8AE1,$86D1D157,$35131326,$C7EEEE29,$6D8888E5,$00000000,$120E0E1C,$5C343468,
$3F15152A,$758080F5,$499494DD,$D0E3E333,$C2EDED2F,$2AB5B59F,$F55353A6,$65232346,
$DD4B4B96,$C947478E,$3917172E,$1CA7A7BB,$459090D5,$5F35356A,$08ABABA3,$9DD8D845,
$3DB8B885,$94DFDF4B,$D14F4F9E,$F95757AE,$5B9A9AC1,$439292D1,$98DBDB43,$2D1B1B36,
$443C3C78,$ADC8C865,$5E9999C7,$0C040408,$678E8EE9,$D5E0E035,$8CD7D75B,$877D7DFA,
$7A8585FF,$38BBBB83,$C0404080,$742C2C58,$4E3A3A74,$CF45458A,$E6F1F117,$C6424284,
$AF6565CA,$60202040,$C3414182,$28181830,$967272E4,$6F25254A,$409393D3,$907070E0,
$5A36366C,$0F05050A,$E3F2F211,$1D0B0B16,$10A3A3B3,$8B7979F2,$C1ECEC2D,$18080810,
$6927274E,$53313162,$56323264,$2FB6B699,$847C7CF8,$25B0B095,$1E0A0A14,$957373E6,
$ED5B5BB6,$8D7B7BF6,$2CB7B79B,$768181F7,$83D2D251,$170D0D1A,$BE6A6AD4,$6A26264C,
$579E9EC9,$E85858B0,$519C9CCD,$708383F3,$9C7474E8,$20B3B393,$01ACACAD,$50303060,
$8E7A7AF4,$BB6969D2,$997777EE,$110F0F1E,$07AEAEA9,$63212142,$97DEDE49,$85D0D055,
$722E2E5C,$4C9797DB,$30101020,$19A4A4BD,$5D9898C5,$0DA8A8A5,$89D4D45D,$B86868D0,
$772D2D5A,$A66262C4,$7B292952,$B76D6DDA,$3A16162C,$DB494992,$9A7676EC,$BCC7C77B,
$CDE8E825,$B6C1C177,$4F9696D9,$5937376E,$DAE5E53F,$ABCACA61,$E9F4F41D,$CEE9E927,
$A56363C6,$36121224,$B3C2C271,$1FA6A6B9,$3C141428,$31BCBC8D,$80D3D353,$78282850,
$04AFAFAB,$712F2F5E,$DFE6E639,$6C242448,$F65252A4,$BFC6C679,$15A0A0B5,$1B090912,
$32BDBD8F,$618C8CED,$A4CFCF6B,$E75D5DBA,$33111122,$E15F5FBE,$03010102,$BAC5C57F,
$549F9FCB,$473D3D7A,$13A2A2B1,$589B9BC3,$AEC9C967,$4D3B3B76,$37BEBE89,$F35151A2,
$2B191932,$211F1F3E,$413F3F7E,$E45C5CB8,$23B2B291,$C4EFEF2B,$DE4A4A94,$A2CDCD6F,
$34BFBF8B,$3BBABA81,$B16F6FDE,$AC6464C8,$9ED9D947,$E0F3F313,$423E3E7C,$29B4B49D,
$0BAAAAA1,$91DCDC4D,$8AD5D55F,$0A06060C,$B5C0C075,$827E7EFC,$EFF6F619,$AA6666CC,
$B46C6CD8,$798484FD,$937171E2,$48383870,$3EB9B987,$271D1D3A,$817F7FFE,$529D9DCF,
$D8484890,$688B8BE3,$7E2A2A54,$9BDADA41,$1AA5A5BF,$55333366,$738282F1,$4B393972,
$8FD6D659,$887878F0,$7F8686F9,$FBFAFA01,$D9E4E43D,$7D2B2B56,$0EA9A9A7,$221E1E3C,
$6E8989E7,$A06060C0,$BD6B6BD6,$CBEAEA21,$FF5555AA,$D44C4C98,$ECF7F71B,$D3E2E231),
($B1B19726,$CECE69A7,$C3C373B0,$9595DF4A,$5A5AB4EE,$ADADAF02,$E7E73BDC,$02020406,
$4D4D9AD7,$444488CC,$FBFB03F8,$9191D746,$0C0C1814,$8787FB7C,$A1A1B716,$5050A0F0,
$CBCB63A8,$6767CEA9,$5454A8FC,$DDDD4F92,$46468CCA,$8F8FEB64,$E1E137D6,$4E4E9CD2,
$F0F015E5,$FDFD0FF2,$FCFC0DF1,$EBEB23C8,$F9F907FE,$C4C47DB9,$1A1A342E,$6E6EDCB2,
$5E5EBCE2,$F5F51FEA,$CCCC6DA1,$8D8DEF62,$1C1C3824,$5656ACFA,$434386C5,$FEFE09F7,
$07070E09,$6161C2A3,$F8F805FD,$7575EA9F,$5959B2EB,$FFFF0BF4,$03030605,$22224466,
$8A8AE16B,$D1D15786,$13132635,$EEEE29C7,$8888E56D,$00000000,$0E0E1C12,$3434685C,
$15152A3F,$8080F575,$9494DD49,$E3E333D0,$EDED2FC2,$B5B59F2A,$5353A6F5,$23234665,
$4B4B96DD,$47478EC9,$17172E39,$A7A7BB1C,$9090D545,$35356A5F,$ABABA308,$D8D8459D,
$B8B8853D,$DFDF4B94,$4F4F9ED1,$5757AEF9,$9A9AC15B,$9292D143,$DBDB4398,$1B1B362D,
$3C3C7844,$C8C865AD,$9999C75E,$0404080C,$8E8EE967,$E0E035D5,$D7D75B8C,$7D7DFA87,
$8585FF7A,$BBBB8338,$404080C0,$2C2C5874,$3A3A744E,$45458ACF,$F1F117E6,$424284C6,
$6565CAAF,$20204060,$414182C3,$18183028,$7272E496,$25254A6F,$9393D340,$7070E090,
$36366C5A,$05050A0F,$F2F211E3,$0B0B161D,$A3A3B310,$7979F28B,$ECEC2DC1,$08081018,
$27274E69,$31316253,$32326456,$B6B6992F,$7C7CF884,$B0B09525,$0A0A141E,$7373E695,
$5B5BB6ED,$7B7BF68D,$B7B79B2C,$8181F776,$D2D25183,$0D0D1A17,$6A6AD4BE,$26264C6A,
$9E9EC957,$5858B0E8,$9C9CCD51,$8383F370,$7474E89C,$B3B39320,$ACACAD01,$30306050,
$7A7AF48E,$6969D2BB,$7777EE99,$0F0F1E11,$AEAEA907,$21214263,$DEDE4997,$D0D05585,
$2E2E5C72,$9797DB4C,$10102030,$A4A4BD19,$9898C55D,$A8A8A50D,$D4D45D89,$6868D0B8,
$2D2D5A77,$6262C4A6,$2929527B,$6D6DDAB7,$16162C3A,$494992DB,$7676EC9A,$C7C77BBC,
$E8E825CD,$C1C177B6,$9696D94F,$37376E59,$E5E53FDA,$CACA61AB,$F4F41DE9,$E9E927CE,
$6363C6A5,$12122436,$C2C271B3,$A6A6B91F,$1414283C,$BCBC8D31,$D3D35380,$28285078,
$AFAFAB04,$2F2F5E71,$E6E639DF,$2424486C,$5252A4F6,$C6C679BF,$A0A0B515,$0909121B,
$BDBD8F32,$8C8CED61,$CFCF6BA4,$5D5DBAE7,$11112233,$5F5FBEE1,$01010203,$C5C57FBA,
$9F9FCB54,$3D3D7A47,$A2A2B113,$9B9BC358,$C9C967AE,$3B3B764D,$BEBE8937,$5151A2F3,
$1919322B,$1F1F3E21,$3F3F7E41,$5C5CB8E4,$B2B29123,$EFEF2BC4,$4A4A94DE,$CDCD6FA2,
$BFBF8B34,$BABA813B,$6F6FDEB1,$6464C8AC,$D9D9479E,$F3F313E0,$3E3E7C42,$B4B49D29,
$AAAAA10B,$DCDC4D91,$D5D55F8A,$06060C0A,$C0C075B5,$7E7EFC82,$F6F619EF,$6666CCAA,
$6C6CD8B4,$8484FD79,$7171E293,$38387048,$B9B9873E,$1D1D3A27,$7F7FFE81,$9D9DCF52,
$484890D8,$8B8BE368,$2A2A547E,$DADA419B,$A5A5BF1A,$33336655,$8282F173,$3939724B,
$D6D6598F,$7878F088,$8686F97F,$FAFA01FB,$E4E43DD9,$2B2B567D,$A9A9A70E,$1E1E3C22,
$8989E76E,$6060C0A0,$6B6BD6BD,$EAEA21CB,$5555AAFF,$4C4C98D4,$F7F71BEC,$E2E231D3),
($B19726B1,$CE69A7CE,$C373B0C3,$95DF4A95,$5AB4EE5A,$ADAF02AD,$E73BDCE7,$02040602,
$4D9AD74D,$4488CC44,$FB03F8FB,$91D74691,$0C18140C,$87FB7C87,$A1B716A1,$50A0F050,
$CB63A8CB,$67CEA967,$54A8FC54,$DD4F92DD,$468CCA46,$8FEB648F,$E137D6E1,$4E9CD24E,
$F015E5F0,$FD0FF2FD,$FC0DF1FC,$EB23C8EB,$F907FEF9,$C47DB9C4,$1A342E1A,$6EDCB26E,
$5EBCE25E,$F51FEAF5,$CC6DA1CC,$8DEF628D,$1C38241C,$56ACFA56,$4386C543,$FE09F7FE,
$070E0907,$61C2A361,$F805FDF8,$75EA9F75,$59B2EB59,$FF0BF4FF,$03060503,$22446622,
$8AE16B8A,$D15786D1,$13263513,$EE29C7EE,$88E56D88,$00000000,$0E1C120E,$34685C34,
$152A3F15,$80F57580,$94DD4994,$E333D0E3,$ED2FC2ED,$B59F2AB5,$53A6F553,$23466523,
$4B96DD4B,$478EC947,$172E3917,$A7BB1CA7,$90D54590,$356A5F35,$ABA308AB,$D8459DD8,
$B8853DB8,$DF4B94DF,$4F9ED14F,$57AEF957,$9AC15B9A,$92D14392,$DB4398DB,$1B362D1B,
$3C78443C,$C865ADC8,$99C75E99,$04080C04,$8EE9678E,$E035D5E0,$D75B8CD7,$7DFA877D,
$85FF7A85,$BB8338BB,$4080C040,$2C58742C,$3A744E3A,$458ACF45,$F117E6F1,$4284C642,
$65CAAF65,$20406020,$4182C341,$18302818,$72E49672,$254A6F25,$93D34093,$70E09070,
$366C5A36,$050A0F05,$F211E3F2,$0B161D0B,$A3B310A3,$79F28B79,$EC2DC1EC,$08101808,
$274E6927,$31625331,$32645632,$B6992FB6,$7CF8847C,$B09525B0,$0A141E0A,$73E69573,
$5BB6ED5B,$7BF68D7B,$B79B2CB7,$81F77681,$D25183D2,$0D1A170D,$6AD4BE6A,$264C6A26,
$9EC9579E,$58B0E858,$9CCD519C,$83F37083,$74E89C74,$B39320B3,$ACAD01AC,$30605030,
$7AF48E7A,$69D2BB69,$77EE9977,$0F1E110F,$AEA907AE,$21426321,$DE4997DE,$D05585D0,
$2E5C722E,$97DB4C97,$10203010,$A4BD19A4,$98C55D98,$A8A50DA8,$D45D89D4,$68D0B868,
$2D5A772D,$62C4A662,$29527B29,$6DDAB76D,$162C3A16,$4992DB49,$76EC9A76,$C77BBCC7,
$E825CDE8,$C177B6C1,$96D94F96,$376E5937,$E53FDAE5,$CA61ABCA,$F41DE9F4,$E927CEE9,
$63C6A563,$12243612,$C271B3C2,$A6B91FA6,$14283C14,$BC8D31BC,$D35380D3,$28507828,
$AFAB04AF,$2F5E712F,$E639DFE6,$24486C24,$52A4F652,$C679BFC6,$A0B515A0,$09121B09,
$BD8F32BD,$8CED618C,$CF6BA4CF,$5DBAE75D,$11223311,$5FBEE15F,$01020301,$C57FBAC5,
$9FCB549F,$3D7A473D,$A2B113A2,$9BC3589B,$C967AEC9,$3B764D3B,$BE8937BE,$51A2F351,
$19322B19,$1F3E211F,$3F7E413F,$5CB8E45C,$B29123B2,$EF2BC4EF,$4A94DE4A,$CD6FA2CD,
$BF8B34BF,$BA813BBA,$6FDEB16F,$64C8AC64,$D9479ED9,$F313E0F3,$3E7C423E,$B49D29B4,
$AAA10BAA,$DC4D91DC,$D55F8AD5,$060C0A06,$C075B5C0,$7EFC827E,$F619EFF6,$66CCAA66,
$6CD8B46C,$84FD7984,$71E29371,$38704838,$B9873EB9,$1D3A271D,$7FFE817F,$9DCF529D,
$4890D848,$8BE3688B,$2A547E2A,$DA419BDA,$A5BF1AA5,$33665533,$82F17382,$39724B39,
$D6598FD6,$78F08878,$86F97F86,$FA01FBFA,$E43DD9E4,$2B567D2B,$A9A70EA9,$1E3C221E,
$89E76E89,$60C0A060,$6BD6BD6B,$EA21CBEA,$55AAFF55,$4C98D44C,$F71BECF7,$E231D3E2),
($9726B1B1,$69A7CECE,$73B0C3C3,$DF4A9595,$B4EE5A5A,$AF02ADAD,$3BDCE7E7,$04060202,
$9AD74D4D,$88CC4444,$03F8FBFB,$D7469191,$18140C0C,$FB7C8787,$B716A1A1,$A0F05050,
$63A8CBCB,$CEA96767,$A8FC5454,$4F92DDDD,$8CCA4646,$EB648F8F,$37D6E1E1,$9CD24E4E,
$15E5F0F0,$0FF2FDFD,$0DF1FCFC,$23C8EBEB,$07FEF9F9,$7DB9C4C4,$342E1A1A,$DCB26E6E,
$BCE25E5E,$1FEAF5F5,$6DA1CCCC,$EF628D8D,$38241C1C,$ACFA5656,$86C54343,$09F7FEFE,
$0E090707,$C2A36161,$05FDF8F8,$EA9F7575,$B2EB5959,$0BF4FFFF,$06050303,$44662222,
$E16B8A8A,$5786D1D1,$26351313,$29C7EEEE,$E56D8888,$00000000,$1C120E0E,$685C3434,
$2A3F1515,$F5758080,$DD499494,$33D0E3E3,$2FC2EDED,$9F2AB5B5,$A6F55353,$46652323,
$96DD4B4B,$8EC94747,$2E391717,$BB1CA7A7,$D5459090,$6A5F3535,$A308ABAB,$459DD8D8,
$853DB8B8,$4B94DFDF,$9ED14F4F,$AEF95757,$C15B9A9A,$D1439292,$4398DBDB,$362D1B1B,
$78443C3C,$65ADC8C8,$C75E9999,$080C0404,$E9678E8E,$35D5E0E0,$5B8CD7D7,$FA877D7D,
$FF7A8585,$8338BBBB,$80C04040,$58742C2C,$744E3A3A,$8ACF4545,$17E6F1F1,$84C64242,
$CAAF6565,$40602020,$82C34141,$30281818,$E4967272,$4A6F2525,$D3409393,$E0907070,
$6C5A3636,$0A0F0505,$11E3F2F2,$161D0B0B,$B310A3A3,$F28B7979,$2DC1ECEC,$10180808,
$4E692727,$62533131,$64563232,$992FB6B6,$F8847C7C,$9525B0B0,$141E0A0A,$E6957373,
$B6ED5B5B,$F68D7B7B,$9B2CB7B7,$F7768181,$5183D2D2,$1A170D0D,$D4BE6A6A,$4C6A2626,
$C9579E9E,$B0E85858,$CD519C9C,$F3708383,$E89C7474,$9320B3B3,$AD01ACAC,$60503030,
$F48E7A7A,$D2BB6969,$EE997777,$1E110F0F,$A907AEAE,$42632121,$4997DEDE,$5585D0D0,
$5C722E2E,$DB4C9797,$20301010,$BD19A4A4,$C55D9898,$A50DA8A8,$5D89D4D4,$D0B86868,
$5A772D2D,$C4A66262,$527B2929,$DAB76D6D,$2C3A1616,$92DB4949,$EC9A7676,$7BBCC7C7,
$25CDE8E8,$77B6C1C1,$D94F9696,$6E593737,$3FDAE5E5,$61ABCACA,$1DE9F4F4,$27CEE9E9,
$C6A56363,$24361212,$71B3C2C2,$B91FA6A6,$283C1414,$8D31BCBC,$5380D3D3,$50782828,
$AB04AFAF,$5E712F2F,$39DFE6E6,$486C2424,$A4F65252,$79BFC6C6,$B515A0A0,$121B0909,
$8F32BDBD,$ED618C8C,$6BA4CFCF,$BAE75D5D,$22331111,$BEE15F5F,$02030101,$7FBAC5C5,
$CB549F9F,$7A473D3D,$B113A2A2,$C3589B9B,$67AEC9C9,$764D3B3B,$8937BEBE,$A2F35151,
$322B1919,$3E211F1F,$7E413F3F,$B8E45C5C,$9123B2B2,$2BC4EFEF,$94DE4A4A,$6FA2CDCD,
$8B34BFBF,$813BBABA,$DEB16F6F,$C8AC6464,$479ED9D9,$13E0F3F3,$7C423E3E,$9D29B4B4,
$A10BAAAA,$4D91DCDC,$5F8AD5D5,$0C0A0606,$75B5C0C0,$FC827E7E,$19EFF6F6,$CCAA6666,
$D8B46C6C,$FD798484,$E2937171,$70483838,$873EB9B9,$3A271D1D,$FE817F7F,$CF529D9D,
$90D84848,$E3688B8B,$547E2A2A,$419BDADA,$BF1AA5A5,$66553333,$F1738282,$724B3939,
$598FD6D6,$F0887878,$F97F8686,$01FBFAFA,$3DD9E4E4,$567D2B2B,$A70EA9A9,$3C221E1E,
$E76E8989,$C0A06060,$D6BD6B6B,$21CBEAEA,$AAFF5555,$98D44C4C,$1BECF7F7,$31D3E2E2)
);
{$IFDEF RESTORE_RANGECHECKS}{$R+}{$ENDIF}
{$IFDEF RESTORE_OVERFLOWCHECKS}{$Q+}{$ENDIF}
implementation
end.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,637 @@
{ *****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
***************************************************************************** }
/// <summary>
/// Contains the base class for all the formatting classes
/// </summary>
unit DECFormatBase;
interface
{$INCLUDE DECOptions.inc}
uses
{$IFDEF FPC}
SysUtils, Classes,
{$ELSE}
System.SysUtils, System.Classes,
{$ENDIF}
DECBaseClass, DECUtil;
type
/// <summary>
/// Class reference type of the TDECFormat base class. This is used for
/// passing formatting classes as parameters or returning those. This is
/// especially useful for the formatting classes, as they only contain
/// class functions.
/// </summary>
TDECFormatClass = class of TDECFormat;
/// <summary>
/// copy input to output (default format)
/// </summary>
TFormat_Copy = class;
/// <summary>
/// Basis for all formatting classes. Not to be instantiated directly.
/// </summary>
TDECFormat = class(TDECObject)
protected
/// <summary>
/// Internal method for the actual format conversion. This method needs to
/// be overridden in all the child classes. Converts into the format.
/// </summary>
/// <param name="Source">
/// Data to be converted
/// </param>
/// <param name="Dest">
/// Into this parameter the converted data will be written into.
/// </param>
/// <param name="Size">
/// Number of bytes from source which will get converted.
/// </param>
class procedure DoEncode(const Source; var Dest: TBytes;
Size: Integer); virtual;
/// <summary>
/// Internal method for the actual format conversion. This method needs to
/// be overridden in all the child classes. Converts from the format into
/// the format the data had before encoding it.
/// </summary>
/// <param name="Source">
/// Data to be converted
/// </param>
/// <param name="Dest">
/// Into this parameter the converted data will be written into.
/// </param>
/// <param name="Size">
/// Number of bytes from source which will get converted.
/// </param>
class procedure DoDecode(const Source; var Dest: TBytes;
Size: Integer); virtual;
/// <summary>
/// Internal method for checking whether all bytes of the data to be
/// processed are valid for this particular formatting. This method needs
/// to be overridden in all the child classes.
/// </summary>
/// <param name="Data">
/// Data to be checked
/// </param>
/// <param name="Size">
/// Number of bytes from data which will get checked.
/// </param>
class function DoIsValid(const Data; Size: Integer): Boolean; virtual;
public
/// <summary>
/// List of registered DEC classes. Key is the Identity of the class.
/// </summary>
class var ClassList: TDECClassList;
/// <summary>
/// Tries to find a class type by its name in the list of registered
/// formatting classes
/// </summary>
/// <param name="Name">
/// Name to look for in the list
/// </param>
/// <returns>
/// Returns the class type if found. if it could not be found a
/// EDECClassNotRegisteredException will be thrown
/// </returns>
class function ClassByName(const Name: string): TDECFormatClass;
/// <summary>
/// Tries to find a class type by its numeric identity DEC assigned to it.
/// Useful for file headers, so they can easily encode numerically which
/// cipher class was being used.
/// </summary>
/// <param name="Identity">
/// Identity to look for
/// </param>
/// <returns>
/// Returns the class type of the class with the specified identity value
/// or throws an EDECClassNotRegisteredException exception if no class
/// with the given identity has been found
/// </returns>
class function ClassByIdentity(Identity: Int64): TDECFormatClass;
/// <summary>
/// Calls the internal method which actually does the format conversion.
/// </summary>
/// <param name="Data">
/// Source data to be converted into the format of this class as
/// RawByteString. Empty strings are allowed. They will simply lead to
// empty return arrays as well.
/// </param>
/// <returns>
/// Data in the format of this formatting algorithm as RawByteString
/// </returns>
class function Encode(const Data: RawByteString): RawByteString; overload;
/// <summary>
/// Calls the internal method which actually does the format conversion.
/// </summary>
/// <param name="Data">
/// Source data to be converted into the format of this class as untyped
/// parameter. Empty data is allowed. It will simply lead to empty return
// values as well.
/// </param>
/// <param name="Size">
/// Size of the data passed via data in bytes.
/// </param>
/// <returns>
/// Data in the format of this formatting algorithm as RawByteString
/// </returns>
class function Encode(const Data; Size: Integer): RawByteString; overload;
/// <summary>
/// Calls the internal method which actually does the format conversion.
/// </summary>
/// <param name="Data">
/// Source data to be converted into the format of this class as Byte Array.
/// Empty arrays of size 0 are allowed. They will simply lead to empty return
// arrays as well.
/// </param>
/// <returns>
/// Data in the format of this formatting algorithm as byte array.
/// </returns>
class function Encode(const Data: TBytes): TBytes; overload;
/// <summary>
/// Calls the internal method which actually does the format conversion.
/// </summary>
/// <param name="Data">
/// Source data to be converted from the format of this class as byte array
/// into the original byte representation. Empty arrays of size 0 are allowed.
// They will simply lead to empty return arrays as well.
/// </param>
/// <returns>
/// Data in the original byte format it had before getting encoded with
/// this formatting.
/// </returns>
class function Decode(const Data: TBytes): TBytes; overload;
/// <summary>
/// Calls the internal method which actually does the format conversion.
/// </summary>
/// <param name="Data">
/// Source data to be converted from the format of this class as
/// RawByteString into the original representation. Empty strings are allowed.
/// They will simply lead to empty return arrays as well.
/// </param>
/// <returns>
/// Data in the format of this formatting algorithm as RawByteString
/// </returns>
class function Decode(const Data: RawByteString): RawByteString; overload;
/// <summary>
/// Calls the internal method which actually does the format conversion.
/// </summary>
/// <param name="Data">
/// Source data to be converted from the format of this class as untyped
/// parameter into the original representation. Empty data is allowed.
/// It will simply lead to empty return values as well.
/// </param>
/// <param name="Size">
/// Size of the data passed via data in bytes.
/// </param>
/// <returns>
/// Data in the format of this formatting algorithm as RawByteString
/// </returns>
class function Decode(const Data; Size: Integer): RawByteString; overload;
/// <summary>
/// Checks whether the data passed to this method only contains chars
/// valid for this specific formatting.
/// </summary>
/// <param name="Data">
/// Untyped parameter with the data to be checked
/// </param>
/// <param name="Size">
/// Size of the data to be checked in bytes
/// </param>
/// <returns>
/// true, if the input data contains only characters valid for this format
/// </returns>
class function IsValid(const Data; Size: Integer): Boolean; overload;
/// <summary>
/// Checks whether the data passed to this method only contains chars
/// valid for this specific formatting.
/// </summary>
/// <param name="Data">
/// Byte array with the data to be checked
/// </param>
/// <returns>
/// true, if the input data contains only characters valid for this format
/// </returns>
class function IsValid(const Data: TBytes): Boolean; overload;
/// <summary>
/// Checks whether the data passed to this method only contains chars
/// valid for this specific formatting.
/// </summary>
/// <param name="Text">
/// RawByteString with the data to be checked
/// </param>
/// <returns>
/// true, if the input data contains only characters valid for this format
/// </returns>
class function IsValid(const Text: RawByteString): Boolean; overload;
/// <summary>
/// Converts the ordinal number of an ASCII char given as byte into the
/// ordinal number of the corresponding upper case ASCII char. Works only
/// on a-z and works like the System.Pas variant just on bytes instead of chars
/// </summary>
/// <param name="b">
/// Ordinal ASCII char value to be converted to upper case
/// </param>
/// <returns>
/// Uppercase ordinal number if the number passed in as parameter belongs to
/// a char in the a-z range. Otherwise the number passed in will be returned.
/// </returns>
class function UpCaseBinary(b: Byte): Byte;
/// <summary>
/// Looks for the index of a given byte in a byte-array.
/// </summary>
/// <param name="Value">
/// Byte value to be searched in the array
/// </param>
/// <param name="Table">
/// Byte-array where the value is searched in
/// </param>
/// <param name="Len">
/// Maximum index until which the search will be performed. If Len is higher
/// than length(Table) the latter will be used as maximum
/// </param>
/// <returns>
/// Index of the first appearance of the searched value. If it cannot be found
/// the result will be -1. The index is 0 based.
/// </returns>
class function TableFindBinary(Value: Byte; Table: TBytes;
Len: Integer): Integer;
end;
/// <summary>
/// Formatting class which doesn't apply any transformation to the data
/// passed in. It simply copies it from Source to Dest.
/// </summary>
TFormat_Copy = class(TDECFormat)
protected
/// <summary>
/// Copies the data contained in Source into Dest without any conversion
/// </summary>
/// <param name="Source">
/// Variable from which Size bytes will be copied to Dest
/// </param>
/// <param name="Dest">
/// Byte-array where Source will be copied into. It will be dimensioned
/// to a length of Size internally.
/// </param>
/// <param name="Size">
/// Number of bytes to copy from Soruce to Dest
/// </param>
class procedure DoEncode(const Source; var Dest: TBytes;
Size: Integer); override;
/// <summary>
/// Copies the data contained in Source into Dest without any conversion
/// </summary>
/// <param name="Source">
/// Variable from which Size bytes will be copied to Dest
/// </param>
/// <param name="Dest">
/// Byte-array where Source will be copied into. It will be dimensioned
/// to a length of Size internally.
/// </param>
/// <param name="Size">
/// Number of bytes to copy from Soruce to Dest
/// </param>
class procedure DoDecode(const Source; var Dest: TBytes;
Size: Integer); override;
/// <summary>
/// Dummy function to check if Source is valid for this particular format
/// </summary>
/// <param name="Data">
/// Data to be checked for validity. In this dummy case it will only be
/// checked for Size >= 0
/// </param>
/// <param name="Size">
/// Number of bytes the Source to be checked contains
/// </param>
/// <returns>
/// true if Size >= 0
/// </returns>
class function DoIsValid(const Data; Size: Integer): Boolean; override;
public
end;
/// <summary>
/// Returns the passed class type if it is not nil. Otherwise the class type
/// of the TFormat_Copy class is being returned.
/// </summary>
/// <param name="FormatClass">
/// Class type of a formatting class like TFormat_HEX or nil, if no formatting
/// is desired.
/// </param>
/// <returns>
/// Passed class type or TFormat_Copy class type, depending on FormatClass
/// parameter value.
/// </returns>
function ValidFormat(FormatClass: TDECFormatClass = nil): TDECFormatClass;
/// <summary>
/// Searches a registered formatting class by name.
/// </summary>
/// <param name="Name">
/// Unique long (TFormat_HEXL) or short (HEXL) name of the class to be searched.
/// </param>
/// <returns>
/// Class type, which can be used to create an object isntance from. Raises an
/// EDECClassNotRegisteredException exception if the class cannot be found in
/// the list of registered format classes.
/// </returns>
function FormatByName(const Name: string): TDECFormatClass;
/// <summary>
/// Searches a registered formatting class by identity. The identity is some
/// integer value calculated on the basis of the class name, the length of the
/// name and a fixed prefix and by calculating a CRC32 checksum of this.
/// </summary>
/// <param name="Identity">
/// Unique identity of the class to be searched.
/// </param>
/// <returns>
/// Class type, which can be used to create an object isntance from. Raises an
/// EDECClassNotRegisteredException exception if the class cannot be found in
/// the list of registered format classes.
/// </returns>
function FormatByIdentity(Identity: Int64): TDECFormatClass;
implementation
function ValidFormat(FormatClass: TDECFormatClass = nil): TDECFormatClass;
begin
if FormatClass <> nil then
Result := FormatClass
else
Result := TFormat_Copy;
end;
function FormatByName(const Name: string): TDECFormatClass;
begin
Result := TDECFormatClass(TDECFormat.ClassList.ClassByName(Name));
end;
function FormatByIdentity(Identity: Int64): TDECFormatClass;
begin
Result := TDECFormatClass(TDECFormat.ClassList.ClassByIdentity(Identity));
end;
{ TDECFormat }
class procedure TDECFormat.DoEncode(const Source; var Dest: TBytes;
Size: Integer);
begin
// C++ does not support virtual static functions thus the base cannot be
// marked 'abstract'. This is our workaround:
raise EDECAbstractError.Create(GetShortClassName);
end;
class procedure TDECFormat.DoDecode(const Source; var Dest: TBytes;
Size: Integer);
begin
// C++ does not support virtual static functions thus the base cannot be
// marked 'abstract'. This is our workaround:
raise EDECAbstractError.Create(GetShortClassName);
end;
class function TDECFormat.DoIsValid(const Data; Size: Integer): Boolean;
begin
{$IFDEF FPC}
Result := False; // suppress FPC compiler warning
{$ENDIF FPC}
// C++ does not support virtual static functions thus the base cannot be
// marked 'abstract'. This is our workaround:
raise EDECAbstractError.Create(GetShortClassName);
end;
class function TDECFormat.Encode(const Data: RawByteString): RawByteString;
var
b: TBytes;
begin
if Length(Data) > 0 then
begin
{$IF CompilerVersion >= 24.0}
DoEncode(Data[Low(Data)], b, Length(Data) * SizeOf(Data[Low(Data)]));
{$ELSE}
DoEncode(Data[1], b, Length(Data) * SizeOf(Data[1]));
{$IFEND}
Result := BytesToRawString(b);
end
else
SetLength(Result, 0);
end;
class function TDECFormat.Encode(const Data: TBytes): TBytes;
var
b: TBytes;
begin
if Length(Data) > 0 then
begin
DoEncode(Data[0], b, Length(Data));
Result := b;
end
else
SetLength(Result, 0);
end;
class function TDECFormat.ClassByIdentity(Identity: Int64): TDECFormatClass;
begin
Result := TDECFormatClass(ClassList.ClassByIdentity(Identity));
end;
class function TDECFormat.ClassByName(const Name: string): TDECFormatClass;
begin
Result := TDECFormatClass(ClassList.ClassByName(Name));
end;
class function TDECFormat.Decode(const Data: TBytes): TBytes;
var
b: TBytes;
begin
if Length(Data) > 0 then
begin
DoDecode(Data[0], b, Length(Data));
Result := b;
end
else
SetLength(Result, 0);
end;
class function TDECFormat.Decode(const Data: RawByteString): RawByteString;
var
b: TBytes;
begin
if Length(Data) > 0 then
begin
{$IF CompilerVersion >= 24.0}
DoDecode(Data[Low(Data)], b, Length(Data) * SizeOf(Data[Low(Data)]));
{$ELSE}
DoDecode(Data[1], b, Length(Data) * SizeOf(Data[1]));
{$IFEND}
Result := BytesToRawString(b);
end
else
SetLength(Result, 0);
end;
class function TDECFormat.Decode(const Data; Size: Integer): RawByteString;
var
b: TBytes;
begin
if Size > 0 then
begin
DoDecode(Data, b, Size);
Result := BytesToRawString(b);
end
else
SetLength(Result, 0);
end;
class function TDECFormat.Encode(const Data; Size: Integer): RawByteString;
var
b: TBytes;
begin
if Size > 0 then
begin
DoEncode(Data, b, Size);
Result := BytesToRawString(b);
end
else
SetLength(Result, 0);
end;
class function TDECFormat.IsValid(const Data; Size: Integer): Boolean;
begin
Result := DoIsValid(Data, Size);
end;
class function TDECFormat.IsValid(const Data: TBytes): Boolean;
begin
Result := (Length(Data) = 0) or (DoIsValid(Data[0], Length(Data)));
end;
class function TDECFormat.IsValid(const Text: RawByteString): Boolean;
begin
{$IF CompilerVersion >= 24.0}
Result := (Length(Text) = 0) or
(DoIsValid(Text[Low(Text)], Length(Text) * SizeOf(Text[Low(Text)])));
{$ELSE}
Result := (Length(Text) = 0) or
(DoIsValid(Text[1], Length(Text) * SizeOf(Text[1])));
{$IFEND}
end;
class function TDECFormat.UpCaseBinary(b: Byte): Byte;
begin
Result := b;
if Result in [$61 .. $7A] then
Dec(Result, $61 - $41);
end;
class function TDECFormat.TableFindBinary(Value: Byte; Table: TBytes;
Len: Integer): Integer;
var
i: Integer;
begin
Result := -1;
i := 0;
while (i <= Len) and (i < Length(Table)) do
begin
if (Table[i] = Value) then
begin
Result := i;
break;
end;
inc(i);
end;
end;
{ TFormat_Copy }
class procedure TFormat_Copy.DoEncode(const Source; var Dest: TBytes;
Size: Integer);
begin
SetLength(Dest, Size);
if Size <> 0 then
Move(Source, Dest[0], Size);
end;
class procedure TFormat_Copy.DoDecode(const Source; var Dest: TBytes;
Size: Integer);
begin
SetLength(Dest, Size);
if Size <> 0 then
Move(Source, Dest[0], Size);
end;
class function TFormat_Copy.DoIsValid(const Data; Size: Integer): Boolean;
begin
Result := Size >= 0;
end;
{$IFDEF DELPHIORBCB}
procedure ModuleUnload(Instance: NativeInt);
var
i: Integer;
begin
if TDECFormat.ClassList <> nil then
begin
for i := TDECFormat.ClassList.Count - 1 downto 0 do
begin
if NativeInt(FindClassHInstance(TClass(TDECFormat.ClassList[i]))) = Instance
then
TDECFormat.ClassList.Remove(TDECFormat.ClassList[i].Identity);
end;
end;
end;
{$ENDIF DELPHIORBCB}
initialization
// Code for packages and dynamic extension of the class registration list
{$IFDEF DELPHIORBCB}
AddModuleUnloadProc(ModuleUnload);
{$ENDIF DELPHIORBCB}
TDECFormat.ClassList := TDECClassList.Create;
TFormat_Copy.RegisterClass(TDECFormat.ClassList);
finalization
// Ensure no further instances of classes registered in the registration list
// are possible through the list after this unit has been unloaded by unloding
// the package this unit is in
{$IFDEF DELPHIORBCB}
RemoveModuleUnloadProc(ModuleUnload);
{$ENDIF DELPHIORBCB}
TDECFormat.ClassList.Free;
end.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,377 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory of
this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
{**********************************************************************}
{ }
{ "The contents of this file are subject to the Mozilla Public }
{ License Version 1.1 (the "License"); you may not use this }
{ file except in compliance with the License. You may obtain }
{ a copy of the License at http://www.mozilla.org/MPL/ }
{ }
{ Software distributed under the License is distributed on an }
{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express }
{ or implied. See the License for the specific language }
{ governing rights and limitations under the License. }
{ }
{ Copyright Creative IT. }
{ Current maintainer: Eric Grange }
{ }
{**********************************************************************}
// The original source file can be found here:
// https://bitbucket.org/egrange/dwscript/src
add edx, 128
add eax, 128
movq mm1, [edx-120]
movq mm4, [edx-96]
movq mm3, [edx-104]
pxor mm1, [edx-80]
movq mm5, [edx+16]
pxor mm1, [edx]
movq mm2, [edx-112]
pxor mm1, [edx+40]
pxor mm1, [edx-40]
movq mm0, [edx-128]
movq mm6, mm1
pxor mm4, [edx-56]
movq [ecx+8], mm1
psrlq mm6, 63
pxor mm4, [edx+24]
pxor mm4, [edx+64]
pxor mm4, [edx-16]
psllq mm1, 1
pxor mm2, [edx+48]
por mm1, mm6
movq mm6, [edx-88]
pxor mm1, mm4
pxor mm2, [edx-32]
pxor mm2, [edx-72]
pxor mm6, mm1
movq mm7, mm6
psrlq mm7, 28
psllq mm6, 36
por mm6, mm7
pxor mm2, [edx+8]
movq [eax], mm6
movq mm6, [edx+32]
movq mm7, mm4
psrlq mm7, 63
psllq mm4, 1
pxor mm0, mm6
por mm4, mm7
pxor mm4, mm2
pxor mm5, mm4
movq mm7, mm5
pxor mm0, [edx-8]
psllq mm5, 21
psrlq mm7, 43
pxor mm6, mm1
por mm5, mm7
movq [eax-104], mm5
movq mm5, [edx-48]
pxor mm0, mm5
movq mm7, mm6
psrlq mm7, 46
psllq mm6, 18
por mm6, mm7
movq [eax-16], mm6
movq mm6, [edx+56]
pxor mm5, mm1
movq mm7, mm5
pxor mm3, mm6
psllq mm5, 3
psrlq mm7, 61
pxor mm3, [edx+16]
pxor mm3, [edx-24]
por mm5, mm7
pxor mm6, mm4
pxor mm0, [edx-88]
movq mm7, mm6
psrlq mm7, 8
movq [eax-72], mm5
movq mm5, mm2
psllq mm2, 1
psllq mm6, 56
psrlq mm5, 63
por mm6, mm7
por mm2, mm5
pxor mm2, mm0
movq [eax+24], mm6
movq mm5, [edx-120]
movq mm6, mm0
psllq mm0, 1
pxor mm5, mm2
pxor mm3, [edx-64]
psrlq mm6, 63
por mm0, mm6
movq mm6, [edx-64]
movq mm7, mm5
psllq mm5, 1
psrlq mm7, 63
pxor mm6, mm4
por mm5, mm7
pxor mm0, mm3
movq mm7, mm6
movq [eax-48], mm5
movq mm5, [edx]
psllq mm6, 55
psrlq mm7, 9
por mm6, mm7
movq [eax+40], mm6
movq mm6, [edx-40]
pxor mm5, mm2
movq mm7, mm5
psllq mm5, 45
psrlq mm7, 19
pxor mm6, mm2
por mm5, mm7
movq [eax-64], mm5
movq mm5, [edx+40]
movq mm7, mm6
pxor mm5, mm2
psllq mm6, 10
psrlq mm7, 54
por mm6, mm7
movq [eax+8], mm6
movq mm6, [edx-96]
movq mm7, mm3
psrlq mm7, 63
psllq mm3, 1
por mm3, mm7
movq mm7, mm5
psllq mm5, 2
psrlq mm7, 62
por mm5, mm7
movq [eax+64], mm5
movq mm5, [edx+24]
pxor mm6, mm0
movq mm7, mm6
psrlq mm7, 37
psllq mm6, 27
por mm6, mm7
movq [eax-8], mm6
pxor mm5, mm0
movq mm6, [edx-16]
movq mm7, mm5
psllq mm5, 8
pxor mm3, [ecx+8]
psrlq mm7, 56
pxor mm6, mm0
por mm5, mm7
movq [eax-24], mm5
movq mm7, mm6
psllq mm6, 39
movq mm5, [edx-112]
psrlq mm7, 25
por mm6, mm7
movq [eax+48], mm6
movq mm6, [edx-24]
pxor mm5, mm3
movq mm7, mm5
psrlq mm7, 2
psllq mm5, 62
por mm5, mm7
movq [eax+32], mm5
movq mm5, [edx-104]
pxor mm6, mm4
movq mm7, mm6
psrlq mm7, 39
psllq mm6, 25
por mm6, mm7
pxor mm5, mm4
movq [eax-32], mm6
movq mm6, [edx-128]
pxor mm6, mm1
movq mm4, mm6
movq [eax-128], mm6
movq mm4, mm6
movq mm6, [edx-8]
movq mm7, mm5
psrlq mm7, 36
psllq mm5, 28
pxor mm6, mm1
por mm5, mm7
movq mm7, mm6
psrlq mm7, 23
movq mm1, mm5
movq [eax-88], mm5
movq mm5, [edx-56]
pxor mm5, mm0
psllq mm6, 41
por mm6, mm7
movq [eax+56], mm6
movq mm6, [edx+48]
pxor mm6, mm3
movq mm7, mm5
psrlq mm7, 44
psllq mm5, 20
por mm5, mm7
movq [eax-80], mm5
pandn mm1, mm5
movq mm5, [edx-32]
movq mm7, mm6
psrlq mm7, 3
psllq mm6, 61
por mm6, mm7
pxor mm1, mm6
movq [eax-56], mm6
movq mm6, [edx+8]
movq [edx-56], mm1
movq mm1, [eax-112]
pxor mm5, mm3
movq mm7, mm5
psllq mm5, 43
psrlq mm7, 21
pxor mm6, mm3
por mm5, mm7
movq mm1, mm5
movq mm5, [edx-80]
pxor mm5, mm2
movq mm2, [eax-104]
movq mm7, mm6
psrlq mm7, 49
psllq mm6, 15
por mm6, mm7
movq [eax+16], mm6
movq mm6, [edx+64]
movq [eax-96], mm6
movq mm7, mm5
psrlq mm7, 20
psllq mm5, 44
pxor mm6, mm0
por mm5, mm7
movq mm7, mm6
psrlq mm7, 50
psllq mm6, 14
por mm6, mm7
pandn mm2, mm6
movq mm0, mm5
pandn mm0, mm1
pxor mm2, mm1
pandn mm1, [eax-104]
movq [edx-112], mm2
pandn mm4, mm5
pxor mm1, mm5
movq [eax-120], mm5
movq mm2, [eax-40]
movq [edx-120], mm1
movq mm5, [edx-72]
movq mm1, [eax-64]
pxor mm4, mm6
movq [edx-96], mm4
pxor mm5, mm3
movq mm4, [eax-88]
movq mm7, mm5
movq mm3, mm6
pxor mm0, [eax-128]
movq [edx-128], mm0
movq mm6, [eax-72]
psllq mm5, 6
psrlq mm7, 58
movq mm0, [eax-56]
por mm5, mm7
movq mm2, mm5
movq mm5, [eax-80]
movq mm7, mm1
pandn mm7, mm0
pxor mm7, mm6
movq [edx-72], mm7
movq mm7, [eax-72]
pandn mm6, mm1
pxor mm6, mm5
pandn mm0, mm4
pandn mm5, mm7
movq mm7, [eax]
pxor mm5, mm4
movq mm4, [eax-24]
movq [edx-80], mm6
movq mm6, [eax-48]
movq [edx-88], mm5
movq mm5, mm1
movq mm1, [eax-16]
pxor mm0, mm5
movq mm5, mm1
pandn mm3, [eax-128]
pxor mm3, [eax-104]
movq [edx-64], mm0
movq mm0, [eax+8]
movq [edx-104], mm3
movq mm3, [eax-32]
pandn mm6, mm2
pxor mm6, mm5
movq [edx-16], mm6
movq mm6, [eax+56]
pandn mm3, mm4
pxor mm3, mm2
movq [edx-40], mm3
movq mm3, [eax-32]
pandn mm5, [eax-48]
pxor mm5, mm4
movq [edx-24], mm5
pandn mm7, mm0
movq mm5, [eax+16]
pandn mm4, mm1
pxor mm4, mm3
movq [edx-32], mm4
movq mm4, [eax+40]
movq mm1, mm5
movq mm5, [eax+48]
pandn mm5, mm6
pxor mm5, mm4
pandn mm2, mm3
movq mm3, [eax-8]
movq [edx+40], mm5
movq mm5, [eax+24]
pxor mm7, mm3
movq [edx-8], mm7
movq mm7, [eax+64]
pxor mm2, [eax-48]
movq [edx-48], mm2
movq mm2, mm5
pandn mm2, mm3
pxor mm2, mm1
movq [edx+16], mm2
pandn mm3, [eax]
movq mm2, mm5
movq mm5, [eax+48]
pandn mm6, mm7
pxor mm6, mm5
movq [edx+48], mm6
pandn mm1, mm2
movq mm6, [eax+32]
pxor mm1, mm0
pxor mm3, mm2
movq [edx+24], mm3
pandn mm0, [eax+16]
pxor mm0, [eax]
movq mm3, mm4
movq [edx+8], mm1
movq [edx], mm0
movq mm0, mm6
movq mm1, [eax+56]
pandn mm4, mm5
pxor mm4, mm0
pandn mm0, mm3
pxor mm0, mm7
movq [edx+32], mm4
pandn mm7, mm6
pxor mm7, mm1
movq [edx+56], mm7
movq [edx+64], mm0

View File

@@ -0,0 +1,318 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory of
this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
{**********************************************************************}
{ }
{ "The contents of this file are subject to the Mozilla Public }
{ License Version 1.1 (the "License"); you may not use this }
{ file except in compliance with the License. You may obtain }
{ a copy of the License at http://www.mozilla.org/MPL/ }
{ }
{ Software distributed under the License is distributed on an }
{ "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express }
{ or implied. See the License for the specific language }
{ governing rights and limitations under the License. }
{ }
{ Copyright Creative IT. }
{ Current maintainer: Eric Grange }
{ }
{**********************************************************************}
// The original source file can be found here:
// https://bitbucket.org/egrange/dwscript/src
push r12
push r13
push r14
add rdx, 128
add rcx, 128
// Theta
mov rax, [rdx-128]
xor rax, [rdx-88]
xor rax, [rdx-48]
xor rax, [rdx-8]
xor rax, [rdx+32]
mov [r8], rax
mov rax, [rdx-120]
xor rax, [rdx-80]
xor rax, [rdx-40]
xor rax, [rdx]
xor rax, [rdx+40]
mov [r8+8], rax
mov rax, [rdx-112]
xor rax, [rdx-72]
xor rax, [rdx-32]
xor rax, [rdx+8]
xor rax, [rdx+48]
mov [r8+16], rax
mov rax, [rdx-104]
xor rax, [rdx-64]
xor rax, [rdx-24]
xor rax, [rdx+16]
xor rax, [rdx+56]
mov [r8+24], rax
mov rax, [rdx-96]
xor rax, [rdx-56]
xor rax, [rdx-16]
xor rax, [rdx+24]
xor rax, [rdx+64]
mov [r8+32], rax
mov r10, [r8]
rol r10, 1
xor r10, [r8+24]
mov r11, [r8+8]
rol r11, 1
xor r11, [r8+32]
mov r12, [r8+16]
rol r12, 1
xor r12, [r8]
mov r13, [r8+24]
rol r13, 1
xor r13, [r8+8]
mov r14, [r8+32]
rol r14, 1
xor r14, [r8+16]
// Rho Pi
mov rax, [rdx-128]
xor rax, r11
mov [rcx-128], rax
mov rax, [rdx-80]
xor rax, r12
rol rax, 44
mov [rcx-120], rax
mov rax, [rdx-32]
xor rax, r13
rol rax, 43
mov [rcx-112], rax
mov rax, [rdx+16]
xor rax, r14
rol rax, 21
mov [rcx-104], rax
mov rax, [rdx+64]
xor rax, r10
rol rax, 14
mov [rcx-96], rax
mov rax, [rdx-104]
xor rax, r14
rol rax, 28
mov [rcx-88], rax
mov rax, [rdx-56]
xor rax, r10
rol rax, 20
mov [rcx-80], rax
mov rax, [rdx-48]
xor rax, r11
rol rax, 3
mov [rcx-72], rax
mov rax, [rdx]
xor rax, r12
rol rax, 45
mov [rcx-64], rax
mov rax, [rdx+48]
xor rax, r13
rol rax, 61
mov [rcx-56], rax
mov rax, [rdx-120]
xor rax, r12
rol rax, 1
mov [rcx-48], rax
mov rax, [rdx-72]
xor rax, r13
rol rax, 6
mov [rcx-40], rax
mov rax, [rdx-24]
xor rax, r14
rol rax, 25
mov [rcx-32], rax
mov rax, [rdx+24]
xor rax, r10
rol rax, 8
mov [rcx-24], rax
mov rax, [rdx+32]
xor rax, r11
rol rax, 18
mov [rcx-16], rax
mov rax, [rdx-96]
xor rax, r10
rol rax, 27
mov [rcx-8], rax
mov rax, [rdx-88]
xor rax, r11
rol rax, 36
mov [rcx], rax
mov rax, [rdx-40]
xor rax, r12
rol rax, 10
mov [rcx+8], rax
mov rax, [rdx+8]
xor rax, r13
rol rax, 15
mov [rcx+16], rax
mov rax, [rdx+56]
xor rax, r14
rol rax, 56
mov [rcx+24], rax
mov rax, [rdx-112]
xor rax, r13
rol rax, 62
mov [rcx+32], rax
mov rax, [rdx-64]
xor rax, r14
rol rax, 55
mov [rcx+40], rax
mov rax, [rdx-16]
xor rax, r10
rol rax, 39
mov [rcx+48], rax
mov rax, [rdx-8]
xor rax, r11
rol rax, 41
mov [rcx+56], rax
mov rax, [rdx+40]
xor rax, r12
rol rax, 2
mov [rcx+64], rax
// Chi
mov rax, [rcx-120]
not rax
and rax, [rcx-112]
xor rax, [rcx-128]
mov [rdx-128], rax
mov rax, [rcx-112]
not rax
and rax, [rcx-104]
xor rax, [rcx-120]
mov [rdx-120], rax
mov rax, [rcx-104]
not rax
and rax, [rcx-96]
xor rax, [rcx-112]
mov [rdx-112], rax
mov rax, [rcx-96]
not rax
and rax, [rcx-128]
xor rax, [rcx-104]
mov [rdx-104], rax
mov rax, [rcx-128]
not rax
and rax, [rcx-120]
xor rax, [rcx-96]
mov [rdx-96], rax
mov rax, [rcx-80]
not rax
and rax, [rcx-72]
xor rax, [rcx-88]
mov [rdx-88], rax
mov rax, [rcx-72]
not rax
and rax, [rcx-64]
xor rax, [rcx-80]
mov [rdx-80], rax
mov rax, [rcx-64]
not rax
and rax, [rcx-56]
xor rax, [rcx-72]
mov [rdx-72], rax
mov rax, [rcx-56]
not rax
and rax, [rcx-88]
xor rax, [rcx-64]
mov [rdx-64], rax
mov rax, [rcx-88]
not rax
and rax, [rcx-80]
xor rax, [rcx-56]
mov [rdx-56], rax
mov rax, [rcx-40]
not rax
and rax, [rcx-32]
xor rax, [rcx-48]
mov [rdx-48], rax
mov rax, [rcx-32]
not rax
and rax, [rcx-24]
xor rax, [rcx-40]
mov [rdx-40], rax
mov rax, [rcx-24]
not rax
and rax, [rcx-16]
xor rax, [rcx-32]
mov [rdx-32], rax
mov rax, [rcx-16]
not rax
and rax, [rcx-48]
xor rax, [rcx-24]
mov [rdx-24], rax
mov rax, [rcx-48]
not rax
and rax, [rcx-40]
xor rax, [rcx-16]
mov [rdx-16], rax
mov rax, [rcx]
not rax
and rax, [rcx+8]
xor rax, [rcx-8]
mov [rdx-8], rax
mov rax, [rcx+8]
not rax
and rax, [rcx+16]
xor rax, [rcx]
mov [rdx], rax
mov rax, [rcx+16]
not rax
and rax, [rcx+24]
xor rax, [rcx+8]
mov [rdx+8], rax
mov rax, [rcx+24]
not rax
and rax, [rcx-8]
xor rax, [rcx+16]
mov [rdx+16], rax
mov rax, [rcx-8]
not rax
and rax, [rcx]
xor rax, [rcx+24]
mov [rdx+24], rax
mov rax, [rcx+40]
not rax
and rax, [rcx+48]
xor rax, [rcx+32]
mov [rdx+32], rax
mov rax, [rcx+48]
not rax
and rax, [rcx+56]
xor rax, [rcx+40]
mov [rdx+40], rax
mov rax, [rcx+56]
not rax
and rax, [rcx+64]
xor rax, [rcx+48]
mov [rdx+48], rax
mov rax, [rcx+64]
not rax
and rax, [rcx+32]
xor rax, [rcx+56]
mov [rdx+56], rax
mov rax, [rcx+32]
not rax
and rax, [rcx+40]
xor rax, [rcx+64]
mov [rdx+64], rax
pop r14
pop r13
pop r12

View File

@@ -0,0 +1,879 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
/// <summary>
/// Unit containing all the KDF, MGF, HMAC and PBKDF2 algorithms
/// </summary>
unit DECHashAuthentication;
interface
uses
System.SysUtils, DECHashBase;
type
/// <summary>
/// Meta class for all the hashing classes in order to support the
/// registration mechanism
/// </summary>
TDECHashAuthenticationClass = class of TDECHashAuthentication;
/// <summary>
/// Type of the KDF variant
/// </summary>
TKDFType = (ktKDF1, ktKDF2, ktKDF3);
/// <summary>
/// Class containing all the KDF, MGF, HMAC and PBKDF2 algorithms
/// </summary>
TDECHashAuthentication = class(TDECHash)
strict private
/// <summary>
/// Key deviation algorithm to derrive keys from other keys.
/// IEEE P1363 Working Group, ISO 18033-2:2004
/// This is either KDF1 or KDF2 depending on KDFType
/// </summary>
/// <param name="Data">
/// Source data from which the new key shall be derrived.
/// </param>
/// <param name="DataSize">
/// Size in bytes of the source data passed.
/// </param>
/// <param name="Seed">
/// Start value for pseudo random number generator
/// </param>
/// <param name="SeedSize">
/// Size of the seed in byte.
/// </param>
/// <param name="MaskSize">
/// Size of the generated output in byte
/// </param>
/// <param name="KDFType">
/// Type of the algorithm: 1 = KDF1, 2 = KDF2 and 3 = KDF 3
/// </param>
/// <returns>
/// Returns the new derrived key.
/// </returns>
class function KDFInternal(const Data; DataSize: Integer; const Seed;
SeedSize, MaskSize: Integer; KDFType: TKDFType): TBytes; inline;
public
/// <summary>
/// Detects whether the given hash class is one particularily suited
/// for storing hashes of passwords
/// </summary>
/// <returns>
/// true if it's a hash class specifically designed to store password
/// hashes, false for ordinary hash algorithms.
/// </returns>
class function IsPasswordHash: Boolean; override;
// mask generation
/// <summary>
/// Mask generation: generates an output based on the data given which is
/// similar to a hash function but in contrast does not have a fixed output
/// length. Use of a MGF is desirable in cases where a fixed-size hash
/// would be inadequate. Examples include generating padding, producing
/// one time pads or keystreams in symmetric key encryption, and yielding
/// outputs for pseudorandom number generators.
/// Indexed Mask generation function, IEEE P1363 working group
/// equal to KDF1 except without seed. RFC 2437 PKCS #1
/// </summary>
/// <param name="Data">
/// Data from which to generate a mask from
/// </param>
/// <param name="DataSize">
/// Size of the input data in bytes
/// </param>
/// <param name="MaskSize">
/// Size of the returned mask in bytes
/// </param>
/// <returns>
/// Mask such that one cannot determine the data which had been given to
/// generate this mask from.
/// </returns>
class function MGF1(const Data; DataSize, MaskSize: Integer): TBytes; overload;
/// <summary>
/// Mask generation: generates an output based on the data given which is
/// similar to a hash function but incontrast does not have a fixed output
/// length. Use of a MGF is desirable in cases where a fixed-size hash
/// would be inadequate. Examples include generating padding, producing
/// one time pads or keystreams in symmetric key encryption, and yielding
/// outputs for pseudorandom number generators
/// </summary>
/// <param name="Data">
/// Data from which to generate a mask from
/// </param>
/// <param name="MaskSize">
/// Size of the returned mask in bytes
/// </param>
/// <returns>
/// Mask such that one cannot determine the data which had been given to
/// generate this mask from.
/// </returns>
class function MGF1(const Data: TBytes; MaskSize: Integer): TBytes; overload;
/// <summary>
/// Key deviation algorithm to derrive keys from other keys.
/// IEEE P1363 Working Group, ISO 18033-2:2004
/// </summary>
/// <param name="Data">
/// Source data from which the new key shall be derrived.
/// </param>
/// <param name="DataSize">
/// Size in bytes of the source data passed.
/// </param>
/// <param name="Seed">
/// Salt value
/// </param>
/// <param name="SeedSize">
/// Size of the seed/salt in byte.
/// </param>
/// <param name="MaskSize">
/// Size of the generated output in byte
/// </param>
/// <returns>
/// Returns the new derrived key with the length specified in MaskSize.
/// </returns>
/// <remarks>
/// In earlier versions there was an optional format parameter. This has
/// been removed as this is a base class. The method might not have
/// returned a result with the MaskSize specified, as the formatting might
/// have had to alter this. This would have been illogical.
/// </remarks>
class function KDF1(const Data; DataSize: Integer; const Seed;
SeedSize, MaskSize: Integer): TBytes; overload;
/// <summary>
/// Key deviation algorithm to derrive keys from other keys.
/// IEEE P1363 Working Group, ISO 18033-2:2004
/// </summary>
/// <param name="Data">
/// Source data from which the new key shall be derrived.
/// </param>
/// <param name="Seed">
/// Salt value
/// </param>
/// <param name="MaskSize">
/// Size of the generated output in byte
/// </param>
/// <returns>
/// Returns the new derrived key with the length specified in MaskSize.
/// </returns>
class function KDF1(const Data, Seed: TBytes; MaskSize: Integer): TBytes; overload;
/// <summary>
/// Key deviation algorithm to derrive keys from other keys.
/// IEEE P1363 Working Group, ISO 18033-2:2004
/// </summary>
/// <param name="Data">
/// Source data from which the new key shall be derrived.
/// </param>
/// <param name="DataSize">
/// Size in bytes of the source data passed.
/// </param>
/// <param name="Seed">
/// Salt value
/// </param>
/// <param name="SeedSize">
/// Size of the seed/salt in byte.
/// </param>
/// <param name="MaskSize">
/// Size of the generated output in byte
/// </param>
/// <returns>
/// Returns the new derrived key with the length specified in MaskSize.
/// </returns>
/// <remarks>
/// In earlier versions there was an optional format parameter. This has
/// been removed as this is a base class. The method might not have
/// returned a result with the MaskSize specified, as the formatting might
/// have had to alter this. This would have been illogical.
/// </remarks>
class function KDF2(const Data; DataSize: Integer; const Seed;
SeedSize, MaskSize: Integer): TBytes; overload;
/// <summary>
/// Key deviation algorithm to derrive keys from other keys.
/// IEEE P1363 Working Group, ISO 18033-2:2004
/// </summary>
/// <param name="Data">
/// Source data from which the new key shall be derrived.
/// </param>
/// <param name="Seed">
/// Start value for pseudo random number generator
/// </param>
/// <param name="MaskSize">
/// Size of the generated output in byte
/// </param>
/// <returns>
/// Returns the new derrived key with the length specified in MaskSize.
/// </returns>
class function KDF2(const Data, Seed: TBytes; MaskSize: Integer): TBytes; overload;
/// <summary>
/// Key deviation algorithm to derrive keys from other keys.
/// </summary>
/// <param name="Data">
/// Source data from which the new key shall be derrived.
/// </param>
/// <param name="DataSize">
/// Size in bytes of the source data passed.
/// </param>
/// <param name="Seed">
/// Salt value
/// </param>
/// <param name="SeedSize">
/// Size of the seed/salt in byte.
/// </param>
/// <param name="MaskSize">
/// Size of the generated output in byte
/// </param>
/// <returns>
/// Returns the new derrived key with the length specified in MaskSize.
/// </returns>
/// <remarks>
/// In earlier versions there was an optional format parameter. This has
/// been removed as this is a base class. The method might not have
/// returned a result with the MaskSize specified, as the formatting might
/// have had to alter this. This would have been illogical.
/// </remarks>
class function KDF3(const Data; DataSize: Integer; const Seed;
SeedSize, MaskSize: Integer): TBytes; overload;
/// <summary>
/// Key deviation algorithm to derrive keys from other keys.
/// </summary>
/// <param name="Data">
/// Source data from which the new key shall be derrived.
/// </param>
/// <param name="Seed">
/// Salt value
/// </param>
/// <param name="MaskSize">
/// Size of the generated output in byte
/// </param>
/// <returns>
/// Returns the new derrived key with the length specified in MaskSize.
/// </returns>
class function KDF3(const Data, Seed: TBytes; MaskSize: Integer): TBytes; overload;
// DEC's own KDF + MGF
/// <summary>
/// Key deviation algorithm to derrive keys from other keys. The alrorithm
/// implemented by this method does not follow any official standard.
/// </summary>
/// <param name="Data">
/// Source data from which the new key shall be derrived.
/// </param>
/// <param name="DataSize">
/// Size in bytes of the source data passed.
/// </param>
/// <param name="Seed">
/// Salt value
/// </param>
/// <param name="SeedSize">
/// Size of the seed/salt in byte.
/// </param>
/// <param name="MaskSize">
/// Size of the generated output in byte
/// </param>
/// <param name="Index">
/// Optional parameter: can be used to specify a different default value
/// for the index variable used in the algorithm.
/// </param>
/// <returns>
/// Returns the new derrived key with the length specified in MaskSize.
/// </returns>
class function KDFx(const Data; DataSize: Integer; const Seed; SeedSize, MaskSize: Integer; Index: UInt32 = 1): TBytes; overload;
/// <summary>
/// Key deviation algorithm to derrive keys from other keys.
/// </summary>
/// <remarks>
/// This variant of the algorithm does not follow an official standard.
/// It has been created by the original author of DEC.
/// </remarks>
/// <param name="Data">
/// Source data from which the new key shall be derrived.
/// </param>
/// <param name="Seed">
/// Salt value
/// </param>
/// <param name="MaskSize">
/// Size of the generated output in byte
/// </param>
/// <param name="Index">
/// Optional parameter: can be used to specify a different default value
/// for the index variable used in the algorithm.
/// </param>
/// <returns>
/// Returns the new derrived key with the length specified in MaskSize.
/// </returns>
class function KDFx(const Data, Seed: TBytes; MaskSize: Integer; Index: UInt32 = 1): TBytes; overload;
/// <summary>
/// Mask generation: generates an output based on the data given which is
/// similar to a hash function but incontrast does not have a fixed output
/// length. Use of a MGF is desirable in cases where a fixed-size hash
/// would be inadequate. Examples include generating padding, producing
/// one time pads or keystreams in symmetric key encryption, and yielding
/// outputs for pseudorandom number generators.
/// </summary>
/// <remarks>
/// This variant of the algorithm does not follow an official standard.
/// It has been created by the original author of DEC.
/// </remarks>
/// <param name="Data">
/// Data from which to generate a mask from
/// </param>
/// <param name="DataSize">
/// Size of the passed data in bytes
/// </param>
/// <param name="MaskSize">
/// Size of the returned mask in bytes
/// </param>
/// <param name="Index">
/// Looks like this is a salt applied to each byte of output data?
{ TODO : Clarify this parameter }
/// </param>
/// <returns>
/// Mask such that one cannot determine the data which had been given to
/// generate this mask from.
/// </returns>
class function MGFx(const Data; DataSize, MaskSize: Integer; Index: UInt32 = 1): TBytes; overload;
/// <summary>
/// Mask generation: generates an output based on the data given which is
/// similar to a hash function but incontrast does not have a fixed output
/// length. Use of a MGF is desirable in cases where a fixed-size hash
/// would be inadequate. Examples include generating padding, producing
/// one time pads or keystreams in symmetric key encryption, and yielding
/// outputs for pseudorandom number generators.
/// </summary>
/// <remarks>
/// This variant of the algorithm does not follow an official standard.
/// It has been created by the original author of DEC.
/// </remarks>
/// <param name="Data">
/// Data from which to generate a mask from
/// </param>
/// <param name="MaskSize">
/// Size of the returned mask in bytes
/// </param>
/// <param name="Index">
/// Looks like this is a salt applied to each byte of output data?
{ TODO : Clarify this parameter }
/// </param>
/// <returns>
/// Mask such that one cannot determine the data which had been given to
/// generate this mask from.
/// </returns>
class function MGFx(const Data: TBytes; MaskSize: Integer; Index: UInt32 = 1): TBytes; overload;
/// <summary>
/// HMAC according to rfc2202: hash message authentication code allow to
/// verify both the data integrity and the authenticity of a message.
/// </summary>
/// <param name="Key">
/// This is the secret key which shall not be transmitted over the line.
/// The sender uses this key to create the resulting HMAC, transmits the
/// text and the HMAC over the line and the receiver recalculates the HMAC
/// based on his copy of the secret key. If his calculated HMAC equals the
/// transfered HMAC value the message has not been tampered.
/// </param>
/// <param name="Text">
/// Text over which to calculate the HMAC
/// </param>
/// <returns>
/// Calculated HMAC
/// </returns>
class function HMAC(const Key, Text: TBytes): TBytes; overload;
/// <summary>
/// HMAC according to rfc2202: hash message authentication code allow to
/// verify both the data integrity and the authenticity of a message.
/// </summary>
/// <param name="Key">
/// This is the secret key which shall not be transmitted over the line.
/// The sender uses this key to create the resulting HMAC, transmits the
/// text and the HMAC over the line and the receiver recalculates the HMAC
/// based on his copy of the secret key. If his calculated HMAC equals the
/// transfered HMAC value the message has not been tampered.
/// </param>
/// <param name="Text">
/// Text over which to calculate the HMAC
/// </param>
/// <returns>
/// Calculated HMAC
/// </returns>
class function HMAC(const Key, Text: RawByteString): TBytes; overload;
/// <summary>
/// Password based key deviation function 2
/// RFC 2898, PKCS #5.
/// This can be used to create a login sheme by storing the output,
/// number of iterations and the salt. When the user enters a password
/// this calculation is done using the same parameters as stored for his
/// user account and comparing the output.
/// </summary>
/// <param name="Password">
/// Password to create the deviation from
/// </param>
/// <param name="Salt">
/// Salt used to modify the password
/// </param>
/// <param name="Iterations">
/// Number of iterations to perform
/// </param>
/// <param name="KeyLength">
/// Length of the resulting key in byte
/// </param>
class function PBKDF2(const Password, Salt: TBytes; Iterations: Integer; KeyLength: Integer): TBytes; overload;
/// <summary>
/// Password based key deviation function 2
/// RFC 2898, PKCS #5.
/// This can be used to create a login sheme by storing the output,
/// number of iterations and the salt. When the user enters a password
/// this calculation is done using the same parameters as stored for his
/// user account and comparing the output.
/// </summary>
/// <param name="Password">
/// Password to create the deviation from
/// </param>
/// <param name="Salt">
/// Salt used to modify the password
/// </param>
/// <param name="Iterations">
/// Number of iterations to perform
/// </param>
/// <param name="KeyLength">
/// Length of the resulting key in byte
/// </param>
class function PBKDF2(const Password, Salt: RawByteString; Iterations: Integer; KeyLength: Integer): TBytes; overload;
end;
/// <summary>
/// All hash classes with hash algorithms specially developed for password
/// hashing should inherit from this class in order to be able to distinguish
/// those from normal hash algorithms not really meant to be used for password
/// hashing.
/// </summary>
TDECPasswordHash = class(TDECHashAuthentication);
{$IF CompilerVersion < 28.0}
/// <summary>
/// Class helper for implementing array concatenation which is not available
/// in Delphi XE6 or lower.
/// </summary>
/// <remarks>
/// SHall be removed as soon as the minimum supported version is XE7 or higher.
/// </remarks>
TArrHelper = class
class procedure AppendArrays<T>(var A: TArray<T>; const B: TArray<T>);
end;
{$IFEND}
implementation
uses
DECUtil;
class function TDECHashAuthentication.IsPasswordHash: Boolean;
begin
Result := self.InheritsFrom(TDECPasswordHash);
end;
class function TDECHashAuthentication.KDFInternal(const Data; DataSize: Integer; const Seed;
SeedSize, MaskSize: Integer; KDFType: TKDFType): TBytes;
var
I, n,
Rounds, DigestBytes : Integer;
Dest : PByteArray;
Count : UInt32;
HashInstance : TDECHashAuthentication;
begin
SetLength(Result, 0);
DigestBytes := DigestSize;
Assert(MaskSize >= 0);
Assert(DataSize >= 0);
Assert(SeedSize >= 0);
Assert(DigestBytes >= 0);
HashInstance := TDECHashAuthenticationClass(self).Create;
try
Rounds := (MaskSize + DigestBytes - 1) div DigestBytes;
SetLength(Result, Rounds * DigestBytes);
Dest := @Result[0];
if (KDFType = ktKDF2) then
n := 1
else
n := 0;
for I := 0 to Rounds-1 do
begin
Count := SwapUInt32(n);
HashInstance.Init;
if (KDFType = ktKDF3) then
begin
HashInstance.Calc(Count, SizeOf(Count));
HashInstance.Calc(Data, DataSize);
end
else
begin
HashInstance.Calc(Data, DataSize);
HashInstance.Calc(Count, SizeOf(Count));
end;
HashInstance.Calc(Seed, SeedSize);
HashInstance.Done;
Move(HashInstance.Digest[0], Dest[(I) * DigestBytes], DigestBytes);
inc(n);
end;
SetLength(Result, MaskSize);
finally
HashInstance.Free;
end;
end;
class function TDECHashAuthentication.MGF1(const Data; DataSize, MaskSize: Integer): TBytes;
begin
Result := KDF1(Data, DataSize, NullStr, 0, MaskSize);
end;
class function TDECHashAuthentication.MGF1(const Data: TBytes; MaskSize: Integer): TBytes;
begin
Result := KDFInternal(Data[0], Length(Data), NullStr, 0, MaskSize, ktKDF1);
end;
class function TDECHashAuthentication.KDF1(const Data; DataSize: Integer; const Seed;
SeedSize, MaskSize: Integer): TBytes;
begin
Result := KDFInternal(Data, DataSize, Seed, SeedSize, MaskSize, ktKDF1);
end;
class function TDECHashAuthentication.KDF1(const Data, Seed: TBytes;
MaskSize: Integer): TBytes;
begin
if (length(Seed) > 0) then
Result := KDFInternal(Data[0], length(Data), Seed[0], length(Seed), MaskSize, ktKDF1)
else
Result := KDFInternal(Data[0], length(Data), NullStr, 0, MaskSize, ktKDF1);
end;
class function TDECHashAuthentication.KDF2(const Data; DataSize: Integer; const Seed;
SeedSize, MaskSize: Integer): TBytes;
begin
Result := KDFInternal(Data, DataSize, Seed, SeedSize, MaskSize, ktKDF2);
end;
class function TDECHashAuthentication.KDF2(const Data, Seed: TBytes; MaskSize: Integer): TBytes;
begin
if (length(Seed) > 0) then
Result := KDFInternal(Data[0], Length(Data), Seed[0], Length(Seed), MaskSize, ktKDF2)
else
Result := KDFInternal(Data[0], Length(Data), NullStr, 0, MaskSize, ktKDF2);
end;
class function TDECHashAuthentication.KDF3(const Data; DataSize: Integer; const Seed;
SeedSize, MaskSize: Integer): TBytes;
begin
Result := KDFInternal(Data, DataSize, Seed, SeedSize, MaskSize, ktKDF3);
end;
class function TDECHashAuthentication.KDF3(const Data, Seed: TBytes; MaskSize: Integer): TBytes;
begin
if (length(Seed) > 0) then
Result := KDFInternal(Data[0], Length(Data), Seed[0], Length(Seed), MaskSize, ktKDF3)
else
Result := KDFInternal(Data[0], Length(Data), NullStr, 0, MaskSize, ktKDF3);
end;
class function TDECHashAuthentication.KDFx(const Data; DataSize: Integer; const Seed; SeedSize, MaskSize: Integer; Index: UInt32 = 1): TBytes;
// DEC's own KDF, even stronger
var
I, J : Integer;
Count : UInt32;
R : Byte;
HashInstance : TDECHashAuthentication;
begin
Assert(MaskSize >= 0);
Assert(DataSize >= 0);
Assert(SeedSize >= 0);
Assert(DigestSize > 0);
SetLength(Result, MaskSize);
Index := SwapUInt32(Index);
HashInstance := TDECHashAuthenticationClass(self).Create;
try
for I := 0 to MaskSize - 1 do
begin
HashInstance.Init;
Count := SwapUInt32(I);
HashInstance.Calc(Count, SizeOf(Count));
HashInstance.Calc(Result[0], I);
HashInstance.Calc(Index, SizeOf(Index));
Count := SwapUInt32(SeedSize);
HashInstance.Calc(Count, SizeOf(Count));
HashInstance.Calc(Seed, SeedSize);
Count := SwapUInt32(DataSize);
HashInstance.Calc(Count, SizeOf(Count));
HashInstance.Calc(Data, DataSize);
HashInstance.Done;
R := 0;
for J := 0 to DigestSize - 1 do
R := R xor HashInstance.Digest[J];
Result[I] := R;
end;
finally
HashInstance.Free;
end;
end;
class function TDECHashAuthentication.KDFx(const Data, Seed: TBytes; MaskSize: Integer; Index: UInt32 = 1): TBytes;
begin
if (length(Seed) > 0) then
Result := KDFx(Data[0], Length(Data), Seed[0], Length(Seed), MaskSize, Index)
else
Result := KDFx(Data[0], Length(Data), NullStr, Length(Seed), MaskSize, Index)
end;
class function TDECHashAuthentication.MGFx(const Data; DataSize, MaskSize: Integer; Index: UInt32 = 1): TBytes;
begin
Result := KDFx(Data, DataSize, NullStr, 0, MaskSize, Index);
end;
class function TDECHashAuthentication.MGFx(const Data: TBytes; MaskSize: Integer; Index: UInt32 = 1): TBytes;
begin
Result := KDFx(Data[0], Length(Data), NullStr, 0, MaskSize, Index);
end;
class function TDECHashAuthentication.HMAC(const Key, Text: RawByteString): TBytes;
begin
result := HMAC(BytesOf(Key), BytesOf(Text));
end;
class function TDECHashAuthentication.HMAC(const Key, Text: TBytes): TBytes;
const
CONST_UINT_OF_0x36 = $3636363636363636;
CONST_UINT_OF_0x5C = $5C5C5C5C5C5C5C5C;
var
HashInstance: TDECHashAuthentication;
InnerKeyPad, OuterKeyPad: array of Byte;
I, KeyLength, BlockSize, DigestLength: Integer;
begin
HashInstance := TDECHashAuthenticationClass(self).Create;
try
BlockSize := HashInstance.BlockSize; // 64 for sha1, ...
DigestLength := HashInstance.DigestSize;
KeyLength := Length(Key);
SetLength(InnerKeyPad, BlockSize);
SetLength(OuterKeyPad, BlockSize);
I := 0;
if KeyLength > BlockSize then
begin
Result := HashInstance.CalcBytes(Key);
KeyLength := DigestLength;
end
else
Result := Key;
while I <= KeyLength - SizeOf(NativeUInt) do
begin
PNativeUInt(@InnerKeyPad[I])^ := PNativeUInt(@Result[I])^ xor NativeUInt(CONST_UINT_OF_0x36);
PNativeUInt(@OuterKeyPad[I])^ := PNativeUInt(@Result[I])^ xor NativeUInt(CONST_UINT_OF_0x5C);
Inc(I, SizeOf(NativeUInt));
end;
while I < KeyLength do
begin
InnerKeyPad[I] := Result[I] xor $36;
OuterKeyPad[I] := Result[I] xor $5C;
Inc(I);
end;
while I <= BlockSize - SizeOf(NativeUInt) do
begin
PNativeUInt(@InnerKeyPad[I])^ := NativeUInt(CONST_UINT_OF_0x36);
PNativeUInt(@OuterKeyPad[I])^ := NativeUInt(CONST_UINT_OF_0x5C);
Inc(I, SizeOf(NativeUInt));
end;
while I < BlockSize do
begin
InnerKeyPad[I] := $36;
OuterKeyPad[I] := $5C;
Inc(I);
end;
HashInstance.Init;
HashInstance.Calc(InnerKeyPad[0], BlockSize);
if Length(Text) > 0 then
HashInstance.Calc(Text[0], Length(Text));
HashInstance.Done;
Result := HashInstance.DigestAsBytes;
HashInstance.Init;
HashInstance.Calc(OuterKeyPad[0], BlockSize);
HashInstance.Calc(Result[0], DigestLength);
HashInstance.Done;
Result := HashInstance.DigestAsBytes;
finally
HashInstance.Free;
end;
end;
class function TDECHashAuthentication.PBKDF2(const Password, Salt: TBytes; Iterations: Integer; KeyLength: Integer): TBytes;
const
CONST_UINT_OF_0x36 = $3636363636363636;
CONST_UINT_OF_0x5C = $5C5C5C5C5C5C5C5C;
var
Hash: TDECHashAuthentication;
I, J, C: Integer;
BlockCount, HashLengthRounded, SaltLength: Integer;
PassLength, DigestLength, BlockSize: Integer;
InnerKeyPad, OuterKeyPad: TBytes;
SaltEx, T, U, TrimmedKey: TBytes;
begin
Hash := TDECHashAuthenticationClass(self).Create;
try
// Setup needed parameters
DigestLength := Hash.DigestSize;
HashLengthRounded := DigestLength - SizeOf(NativeUInt) + 1;
BlockCount := Trunc((KeyLength + DigestLength - 1) / DigestLength);
BlockSize := Hash.BlockSize;
PassLength := Length(Password);
SaltLength := Length(Salt);
SaltEx := Salt;
SetLength(SaltEx, SaltLength + 4); // reserve 4 bytes for INT_32_BE(i)
SetLength(T, DigestLength);
// Prepare Key for HMAC calculation
// PrepareKeyForHMAC;
I := 0;
if PassLength > BlockSize then
begin
TrimmedKey := Hash.CalcBytes(Password);
PassLength := DigestLength;
end
else
TrimmedKey := Password;
SetLength(InnerKeyPad, BlockSize);
SetLength(OuterKeyPad, BlockSize);
while I < PassLength do
begin
InnerKeyPad[I] := TrimmedKey[I] xor $36;
OuterKeyPad[I] := TrimmedKey[I] xor $5C;
Inc(I);
end;
while I < BlockSize do
begin
InnerKeyPad[I] := $36;
OuterKeyPad[I] := $5C;
Inc(I);
end;
// Calculate DK
for I := 1 to BlockCount do
begin
SaltEx[SaltLength + 0] := Byte(I shr 24); // INT_32_BE(i)
SaltEx[SaltLength + 1] := Byte(I shr 16);
SaltEx[SaltLength + 2] := Byte(I shr 8);
SaltEx[SaltLength + 3] := Byte(I shr 0);
FillChar(T[0], DigestLength, 0); // reset Ti / F
U := SaltEx; // initialize U to U1 = Salt + INT_32_BE(i)
// Calculate F(Password, Salt, c, i) = U1 ^ U2 ^ ... ^ Uc
for C := 1 to Iterations do
begin
Hash.Init;
Hash.Calc(InnerKeyPad[0], BlockSize);
Hash.Calc(U[0], Length(U));
Hash.Done;
U := Hash.DigestAsBytes;
Hash.Init;
Hash.Calc(OuterKeyPad[0], BlockSize);
Hash.Calc(U[0], DigestLength);
Hash.Done;
U := Hash.DigestAsBytes; // Ui
// F = U1 ^ U2 ^ ... ^ Uc
J := 0;
while J < HashLengthRounded do
begin
PNativeUInt(@T[J])^ := PNativeUInt(@T[J])^ xor PNativeUInt(@U[J])^;
Inc(J, SizeOf(NativeUInt));
end;
while J < DigestLength do
begin
T[J] := T[J] xor U[J];
Inc(J);
end;
end;
{$IF CompilerVersion >= 28.0}
Result := Result + T; // DK += F , DK = DK || Ti
{$ELSE}
TArrHelper.AppendArrays<Byte>(Result, T);
{$IFEND}
end;
finally
Hash.Free;
end;
// Trim to the needed key length
SetLength(Result, KeyLength);
end;
class function TDECHashAuthentication.PBKDF2(const Password, Salt: RawByteString; Iterations: Integer; KeyLength: Integer): TBytes;
begin
result := PBKDF2(BytesOf(Password), BytesOf(Salt), Iterations, KeyLength);
end;
{ TArrHelper }
{$IF CompilerVersion < 28.0}
class procedure TArrHelper.AppendArrays<T>(var A: TArray<T>; const B: TArray<T>);
var
i, L: Integer;
begin
L := Length(A);
SetLength(A, L + Length(B));
for i := 0 to High(B) do
A[L + i] := B[i];
end;
{$IFEND}
end.

View File

@@ -0,0 +1,940 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
/// <summary>
/// Base unit for all the hash algorithms. The key deviation algorithms are
/// in the DECHashAUthentication unit and hash algorithms which can process
/// messages with a length specified in bits instead of whole bytes have
/// to inherit from TDECHashBit
/// </summary>
unit DECHashBase;
interface
{$INCLUDE DECOptions.inc}
uses
{$IFDEF FPC}
SysUtils, Classes,
{$ELSE}
System.SysUtils, System.Classes,
{$ENDIF}
DECBaseClass, DECFormatBase, DECUtil, DECTypes, DECHashInterface;
type
/// <summary>
/// Meta class for all the hashing classes in order to support the
/// registration mechanism
/// </summary>
TDECHashClass = class of TDECHash;
/// <summary>
/// Base class for all hash algorithm implementation classes
/// </summary>
{$IFDEF FPC}
TDECHash = class(TDECObject) // does not find methods of the interface as it
// searches for AnsiString instead of RawByteString
// and thus does not find that
{$ELSE}
TDECHash = class(TDECObject, IDECHash)
{$ENDIF}
strict private
/// <summary>
/// Raises an EDECHashException hash algorithm not initialized exception
/// </summary>
procedure RaiseHashNotInitialized;
/// <summary>
/// Returns the current value of the padding byte used to fill up data
/// if necessary
/// </summary>
function GetPaddingByte: Byte;
/// <summary>
/// Changes the value of the padding byte used to fill up data
/// if necessary
/// </summary>
/// <param name="Value">
/// New value for the padding byte
/// </param>
procedure SetPaddingByte(Value: Byte);
strict protected
FCount : array[0..7] of UInt32;
/// <summary>
/// Internal processing buffer
/// </summary>
FBuffer : PByteArray;
/// <summary>
/// Size of the internal processing buffer in byte
/// </summary>
FBufferSize : Integer;
/// <summary>
/// Position the algorithm is currently at in the processing buffer
/// </summary>
FBufferIndex : Integer;
/// <summary>
/// Value used to fill up data
/// </summary>
FPaddingByte : Byte;
/// <summary>
/// Last byte of the message to be hashed if the algorithm is capable of
/// processing bit sized message lengths and FFinalBitLen > 0.
/// </summary>
FFinalByte : UInt8;
/// <summary>
/// Setting this to a number of bits allows to process messages which have
/// a length which is not a exact multiple of bytes.
/// </summary>
FFinalByteLength : UInt8;
/// <summary>
/// This abstract method has to be overridden by each concrete hash algorithm
/// to initialize the necessary data structures.
/// </summary>
procedure DoInit; virtual; abstract;
procedure DoTransform(Buffer: PUInt32Array); virtual; abstract;
/// <summary>
/// This abstract method has to be overridden by each concrete hash algorithm
/// to finalize the calculation of a hash value over the data passed.
/// </summary>
procedure DoDone; virtual; abstract;
/// <summary>
/// Adds the value of 8*Add to the value (which is interpreted as an
/// 8*32 bit unsigned integer array. The carry is taken care of.
/// </summary>
/// <param name="Value">
/// Value which is incremented
/// </param>
/// <param name="Add">
/// Value (which is being multiplied by 8) by which to increment Value
/// </param>
/// <remarks>
/// Raises an EDECHashException overflow error if the last operation has
/// set the carry flag
/// </remarks>
procedure Increment8(var Value; Add: UInt32);
/// <summary>
/// Raises an EDECHashException overflow error
/// </summary>
procedure RaiseHashOverflowError;
/// <summary>
/// Overwrite internally used processing buffers to make it harder to steal
/// any data from memory.
/// </summary>
procedure SecureErase; virtual;
/// <summary>
/// Returns the calculated hash value
/// </summary>
function Digest: PByteArray; virtual; abstract;
public
/// <summary>
/// Initialize internal fields
/// </summary>
constructor Create; override;
/// <summary>
/// Fees internal resources
/// </summary>
destructor Destroy; override;
/// <summary>
/// Generic initialization of internal data structures. Additionally the
/// internal algorithm specific (because of being overridden by each
/// hash algorithm) DoInit method is called. Needs to be called before
/// each hash calculation.
/// </summary>
procedure Init;
/// <summary>
/// Processes one chunk of data to be hashed.
/// </summary>
/// <param name="Data">
/// Data on which the hash value shall be calculated on
/// </param>
/// <param name="DataSize">
/// Size of the data in bytes
/// </param>
procedure Calc(const Data; DataSize: Integer); virtual;
/// <summary>
/// Frees dynamically allocated buffers in a way which safeguards agains
/// data stealing by other methods which afterwards might allocate this memory.
/// Additionaly calls the algorithm spercific DoDone method.
/// </summary>
procedure Done;
/// <summary>
/// Returns the calculated hash value as byte array
/// </summary>
function DigestAsBytes: TBytes; virtual;
/// <summary>
/// Returns the calculated hash value as formatted Unicode string
/// </summary>
/// <param name="Format">
/// Optional parameter. If a formatting class is being passed the formatting
/// will be applied to the returned string. Otherwise no formatting is
/// being used.
/// </param>
/// <returns>
/// Hash value of the last performed hash calculation
/// </returns>
/// <remarks>
/// We recommend to use a formatting which results in 7 bit ASCII chars
/// being returned, otherwise the conversion into the Unicode string might
/// result in strange characters in the returned result.
/// </remarks>
function DigestAsString(Format: TDECFormatClass = nil): string;
/// <summary>
/// Returns the calculated hash value as formatted RawByteString
/// </summary>
/// <param name="Format">
/// Optional parameter. If a formatting class is being passed the formatting
/// will be applied to the returned string. Otherwise no formatting is
/// being used.
/// </param>
/// <returns>
/// Hash value of the last performed hash calculation
/// </returns>
/// <remarks>
/// We recommend to use a formatting which results in 7 bit ASCII chars
/// being returned, otherwise the conversion into the RawByteString might
/// result in strange characters in the returned result.
/// </remarks>
function DigestAsRawByteString(Format: TDECFormatClass = nil): RawByteString;
/// <summary>
/// Gives the length of the calculated hash value in byte. Needs to be
/// overridden in concrete hash implementations.
/// </summary>
class function DigestSize: UInt32; virtual;
/// <summary>
/// Gives the length of the blocks the hash value is being calculated
/// on in byte. Needs to be overridden in concrete hash implementations.
/// </summary>
class function BlockSize: UInt32; virtual;
/// <summary>
/// List of registered DEC classes. Key is the Identity of the class.
/// </summary>
class var ClassList : TDECClassList;
/// <summary>
/// Tries to find a class type by its name
/// </summary>
/// <param name="Name">
/// Name to look for in the list
/// </param>
/// <returns>
/// Returns the class type if found. if it could not be found a
/// EDECClassNotRegisteredException will be thrown
/// </returns>
class function ClassByName(const Name: string): TDECHashClass;
/// <summary>
/// Tries to find a class type by its numeric identity DEC assigned to it.
/// Useful for file headers, so they can easily encode numerically which
/// cipher class was being used.
/// </summary>
/// <param name="Identity">
/// Identity to look for
/// </param>
/// <returns>
/// Returns the class type of the class with the specified identity value
/// or throws an EDECClassNotRegisteredException exception if no class
/// with the given identity has been found
/// </returns>
class function ClassByIdentity(Identity: Int64): TDECHashClass;
/// <summary>
/// Detects whether the given hash class is one particularily suited
/// for storing hashes of passwords
/// </summary>
/// <returns>
/// true if it's a hash class specifically designed to store password
/// hashes, false for ordinary hash algorithms.
/// </returns>
class function IsPasswordHash: Boolean; virtual;
// hash calculation wrappers
/// <summary>
/// Calculates the hash value (digest) for a given buffer
/// </summary>
/// <param name="Buffer">
/// Untyped buffer the hash shall be calculated for
/// </param>
/// <param name="BufferSize">
/// Size of the buffer in byte
/// </param>
/// <returns>
/// Byte array with the calculated hash value
/// </returns>
function CalcBuffer(const Buffer; BufferSize: Integer): TBytes;
/// <summary>
/// Calculates the hash value (digest) for a given buffer
/// </summary>
/// <param name="Data">
/// The TBytes array the hash shall be calculated on
/// </param>
/// <returns>
/// Byte array with the calculated hash value
/// </returns>
function CalcBytes(const Data: TBytes): TBytes;
/// <summary>
/// Calculates the hash value (digest) for a given unicode string
/// </summary>
/// <param name="Value">
/// The string the hash shall be calculated on
/// </param>
/// <param name="Format">
/// Formatting class from DECFormat. The formatting will be applied to the
/// returned digest value. This parameter is optional.
/// </param>
/// <returns>
/// string with the calculated hash value
/// </returns>
function CalcString(const Value: string; Format: TDECFormatClass = nil): string; overload;
/// <summary>
/// Calculates the hash value (digest) for a given rawbytestring
/// </summary>
/// <param name="Value">
/// The string the hash shall be calculated on
/// </param>
/// <param name="Format">
/// Formatting class from DECFormat. The formatting will be applied to the
/// returned digest value. This parameter is optional.
/// </param>
/// <returns>
/// string with the calculated hash value
/// </returns>
function CalcString(const Value: RawByteString; Format: TDECFormatClass): RawByteString; overload;
/// <summary>
/// Calculates the hash value over a given stream of bytes
/// </summary>
/// <param name="Stream">
/// Memory or file stream over which the hash value shall be calculated.
/// The stream must be assigned. The hash value will always be calculated
/// from the current position of the stream.
/// </param>
/// <param name="Size">
/// Number of bytes within the stream over which to calculate the hash value
/// </param>
/// <param name="HashResult">
/// In this byte array the calculated hash value will be returned
/// </param>
/// <param name="OnProgress">
/// Optional callback routine. It can be used to display the progress of
/// the operation.
/// </param>
procedure CalcStream(const Stream: TStream; Size: Int64; var HashResult: TBytes;
const OnProgress:TDECProgressEvent = nil); overload;
/// <summary>
/// Calculates the hash value over a givens stream of bytes
/// </summary>
/// <param name="Stream">
/// Memory or file stream over which the hash value shall be calculated.
/// The stream must be assigned. The hash value will always be calculated
/// from the current position of the stream.
/// </param>
/// <param name="Size">
/// Number of bytes within the stream over which to calculate the hash value
/// </param>
/// <param name="Format">
/// Optional formatting class. The formatting of that will be applied to
/// the returned hash value.
/// </param>
/// <param name="OnProgress">
/// Optional callback routine. It can be used to display the progress of
/// the operation.
/// </param>
/// <returns>
/// Hash value over the bytes in the stream, formatted with the formatting
/// passed as format parameter, if used.
/// </returns>
function CalcStream(const Stream: TStream; Size: Int64; Format: TDECFormatClass = nil;
const OnProgress:TDECProgressEvent = nil): RawByteString; overload;
/// <summary>
/// Calculates the hash value over the contents of a given file
/// </summary>
/// <param name="FileName">
/// Path and name of the file to be processed
/// </param>
/// <param name="HashResult">
/// Here the resulting hash value is being returned as byte array
/// </param>
/// <param name="OnProgress">
/// Optional callback. If being used the hash calculation will call it from
/// time to time to return the current progress of the operation
/// </param>
procedure CalcFile(const FileName: string; var HashResult: TBytes;
const OnProgress:TDECProgressEvent = nil); overload;
/// <summary>
/// Calculates the hash value over the contents of a given file
/// </summary>
/// <param name="FileName">
/// Path and name of the file to be processed
/// </param>
/// <param name="Format">
/// Optional parameter: Formatting class. If being used the formatting is
/// being applied to the returned string with the calculated hash value
/// </param>
/// <param name="OnProgress">
/// Optional callback. If being used the hash calculation will call it from
/// time to time to return the current progress of the operation
/// </param>
/// <returns>
/// Calculated hash value as RawByteString.
/// </returns>
/// <remarks>
/// We recommend to use a formatting which results in 7 bit ASCII chars
/// being returned, otherwise the conversion into the RawByteString might
/// result in strange characters in the returned result.
/// </remarks>
function CalcFile(const FileName: string; Format: TDECFormatClass = nil;
const OnProgress:TDECProgressEvent = nil): RawByteString; overload;
/// <summary>
/// Defines the byte used in the KDF methods to padd the end of the data
/// if the length of the data cannot be divided by required size for the
/// hash algorithm without reminder
/// </summary>
property PaddingByte: Byte read GetPaddingByte write SetPaddingByte;
end;
/// <summary>
/// Returns the passed hash class type if it is not nil. Otherwise the
/// class type class set per SetDefaultHashClass is being returned. If using
/// the DECHash unit THash_SHA256 is registered in the initialization, otherwise
/// nil might be returned!
/// </summary>
/// <param name="HashClass">
/// Class type of a hash class like THash_SHA256. If nil is passed the one set
/// as default is returned.
/// </param>
/// <returns>
/// Passed class type or defined default hash class type, depending on
/// HashClass parameter value.
/// </returns>
function ValidHash(HashClass: TDECHashClass = nil): TDECHashClass;
/// <summary>
/// Defines which cipher class to return by ValidCipher if passing nil to that
/// </summary>
/// <param name="HashClass">
/// Class type of a hash class to return by ValidHash if passing nil to
/// that one. This parameter should not be nil!
/// </param>
procedure SetDefaultHashClass(HashClass: TDECHashClass);
implementation
resourcestring
sHashNotInitialized = 'Hash must be initialized';
sRaiseHashOverflowError = 'Hash Overflow: Too many bits processed';
sHashNoDefault = 'No default hash has been registered';
var
/// <summary>
/// Hash class returned by ValidHash if nil is passed as parameter to it
/// </summary>
FDefaultHashClass: TDECHashClass = nil;
function ValidHash(HashClass: TDECHashClass): TDECHashClass;
begin
if Assigned(HashClass) then
Result := HashClass
else
Result := FDefaultHashClass;
if not Assigned(Result) then
raise EDECHashException.CreateRes(@sHashNoDefault);
end;
procedure SetDefaultHashClass(HashClass: TDECHashClass);
begin
Assert(Assigned(HashClass), 'Do not set a nil default hash class!');
FDefaultHashClass := HashClass;
end;
{ TDECHash }
constructor TDECHash.Create;
begin
inherited;
FBufferSize := 0;
FBuffer := nil;
end;
destructor TDECHash.Destroy;
begin
SecureErase;
FreeMem(FBuffer, FBufferSize);
inherited Destroy;
end;
procedure TDECHash.SecureErase;
begin
ProtectBuffer(Digest^, DigestSize);
if FBuffer = nil then
ProtectBuffer(FBuffer^, FBufferSize);
end;
procedure TDECHash.Init;
begin
FBufferIndex := 0;
if (FBuffer = nil) or (UInt32(FBufferSize) <> BlockSize) then
begin
FBufferSize := BlockSize;
// ReallocMemory instead of ReallocMem due to C++ compatibility as per 10.1 help
// It is necessary to reallocate the buffer as FreeMem in destructor wouldn't
// accept a nil pointer on some platforms.
FBuffer := ReallocMemory(FBuffer, FBufferSize);
end;
FillChar(FBuffer^, FBufferSize, 0);
FillChar(FCount, SizeOf(FCount), 0);
DoInit;
end;
class function TDECHash.IsPasswordHash: Boolean;
begin
// has to be overwritten by the base class for password hash algorithms
result := false;
end;
procedure TDECHash.Done;
begin
DoDone;
end;
function TDECHash.GetPaddingByte: Byte;
begin
Result := FPaddingByte;
end;
procedure TDECHash.Increment8(var Value; Add: UInt32);
// Value := Value + 8 * Add
// Value is array[0..7] of UInt32
{ TODO -oNormanNG -cCodeReview : !!Unbedingt noch einmal pr<70>fen, ob das wirklich so alles stimmt!!
Mein Versuch der Umsetzung von Increment8 in ASM.
Die Implementierung zuvor hat immer Zugriffsverletzungen ausgel<65>st.
Vermutung: die alte Implementierung lag urspr<70>nglich ausserhalb der Klasse und wurde sp<73>ter
in die Klasse verschoben. Dabei ver<65>ndert sich aber die Nutzung der Register, da zus<75>tzlich
der SELF-Parameter in EAX <20>bergeben wird. Beim Schreiben nach auf Value wurde dann in die Instanz (Self)
geschrieben -> peng
}
{$IF defined(X86ASM) or defined(X64ASM)}
{$IFDEF X86ASM}
// type TData = packed array[0..7] of UInt32; 8x32bit
// TypeOf Param "Value" = TData
//
// EAX = Self
// EDX = Pointer to "Value"
// ECX = Value of "ADD"
register; // redundant but informative
asm
LEA EAX,[ECX*8] // EAX := ADD * 8
SHR ECX,29 // 29bit nach rechts schieben, 3bit beiben stehen
ADD [EDX].DWord[00],EAX // add [edx], eax TData(Value)[00] := TData(Value)[00] + EAX
ADC [EDX].DWord[04],ECX // adc [edx+$04], ecx TData(Value)[04] := TData(Value)[04] + ECX + Carry
ADC [EDX].DWord[08],0 // adc [edx+$08], 0 TData(Value)[08] := TData(Value)[08] + 0 + Carry
ADC [EDX].DWord[12],0 // adc [edx+$0c], 0 TData(Value)[12] := TData(Value)[12] + 0 + Carry
ADC [EDX].DWord[16],0 // adc [edx+$10], 0 TData(Value)[16] := TData(Value)[16] + 0 + Carry
ADC [EDX].DWord[20],0 // adc [edx+$14], 0 TData(Value)[20] := TData(Value)[20] + 0 + Carry
ADC [EDX].DWord[24],0 // adc [edx+$18], 0 TData(Value)[24] := TData(Value)[24] + 0 + Carry
ADC [EDX].DWord[28],0 // adc [edx+$1c], 0 TData(Value)[28] := TData(Value)[28] + 0 + Carry
JC RaiseHashOverflowError
end;
{$ENDIF !X86ASM}
{$IFDEF X64ASM}
// type TData = packed array[0..3] of UInt64; 4x64bit
// TypeOf Param "Value" = TData
//
// RCX = Self
// RDX = Pointer to "Value"
// R8D = Value of "ADD"
register; // redundant but informative
asm
SHL R8, 3 // R8 := Add * 8 the caller writes to R8D what automatically clears the high DWORD of R8
ADD QWORD PTR [RDX ], R8 // add [rdx], r8 TData(Value)[00] := TData(Value)[00] + R8
ADD QWORD PTR [RDX + 8], 0 // add [rdx+$08], 0 TData(Value)[08] := TData(Value)[08] + 0 + Carry
ADD QWORD PTR [RDX + 16], 0 // add [rdx+$10], 0 TData(Value)[16] := TData(Value)[16] + 0 + Carry
ADD QWORD PTR [RDX + 24], 0 // add [rdx+$18], 0 TData(Value)[24] := TData(Value)[24] + 0 + Carry
JC RaiseHashOverflowError;
end;
{$ENDIF !X64ASM}
{$ELSE PUREPASCAL}
type
TData = packed array[0..7] of UInt32;
var
HiBits: UInt32;
Add8: UInt32;
Carry: Boolean;
procedure AddC(var Value: UInt32; const Add: UInt32; var Carry: Boolean);
begin
if Carry then
begin
Value := Value + 1;
Carry := (Value = 0); // we might cause another overflow by adding the carry bit
end
else
Carry := False;
Value := Value + Add;
Carry := Carry or (Value < Add); // set Carry Flag on overflow or keep it if already set
end;
begin
HiBits := Add shr 29; // Save most significant 3 bits in case an overflow occurs
Add8 := Add * 8;
Carry := False;
AddC(TData(Value)[0], Add8, Carry);
AddC(TData(Value)[1], HiBits, Carry);
AddC(TData(Value)[2], 0, Carry);
AddC(TData(Value)[3], 0, Carry);
AddC(TData(Value)[4], 0, Carry);
AddC(TData(Value)[5], 0, Carry);
AddC(TData(Value)[6], 0, Carry);
AddC(TData(Value)[7], 0, Carry);
if Carry then
RaiseHashOverflowError;
end;
{$IFEND PUREPASCAL}
procedure TDECHash.RaiseHashOverflowError;
begin
raise EDECHashException.CreateRes(@sRaiseHashOverflowError);
end;
procedure TDECHash.SetPaddingByte(Value: Byte);
begin
FPaddingByte := Value;
end;
procedure TDECHash.RaiseHashNotInitialized;
begin
raise EDECHashException.CreateRes(@sHashNotInitialized);
end;
procedure TDECHash.Calc(const Data; DataSize: Integer);
var
Remain: Integer;
Value: PByte;
begin
if DataSize <= 0 then
Exit;
if not Assigned(FBuffer) then
RaiseHashNotInitialized;
Increment8(FCount, DataSize);
Value := @TByteArray(Data)[0];
if FBufferIndex > 0 then
begin
Remain := FBufferSize - FBufferIndex;
if DataSize < Remain then
begin
Move(Value^, FBuffer[FBufferIndex], DataSize);
Inc(FBufferIndex, DataSize);
Exit;
end;
Move(Value^, FBuffer[FBufferIndex], Remain);
DoTransform(Pointer(FBuffer));
Dec(DataSize, Remain);
Inc(Value, Remain);
end;
while DataSize >= FBufferSize do
begin
DoTransform(Pointer(Value));
Inc(Value, FBufferSize);
Dec(DataSize, FBufferSize);
end;
Move(Value^, FBuffer^, DataSize);
FBufferIndex := DataSize;
end;
function TDECHash.DigestAsBytes: TBytes;
begin
SetLength(Result, DigestSize);
if DigestSize <> 0 then
Move(Digest^, Result[0], DigestSize);
end;
function TDECHash.DigestAsRawByteString(Format: TDECFormatClass): RawByteString;
begin
Result := BytesToRawString(ValidFormat(Format).Encode(DigestAsBytes));
end;
function TDECHash.DigestAsString(Format: TDECFormatClass): string;
begin
Result := StringOf(ValidFormat(Format).Encode(DigestAsBytes));
end;
class function TDECHash.DigestSize: UInt32;
begin
// C++ does not support virtual static functions thus the base cannot be
// marked 'abstract'. This is our workaround:
raise EDECAbstractError.Create(GetShortClassName);
end;
class function TDECHash.BlockSize: UInt32;
begin
// C++ does not support virtual static functions thus the base cannot be
// marked 'abstract'. This is our workaround:
raise EDECAbstractError.Create(GetShortClassName);
end;
function TDECHash.CalcBuffer(const Buffer; BufferSize: Integer): TBytes;
var
DataPtr: PByte;
begin
Init;
if (FFinalByteLength = 0) or (BufferSize = 0) then
Calc(Buffer, BufferSize)
else
if (BufferSize > 0) then
begin
// Remember last byte as this might be required for padding for such
// algorithms which have some automatic padding logic
DataPtr := @Buffer;
Inc(DataPtr, BufferSize - 1);
FFinalByte := DataPtr^;
// Last byte is incomplete so do not process normally
Calc(Buffer, BufferSize-1);
end;
Done;
Result := DigestAsBytes;
end;
function TDECHash.CalcBytes(const Data: TBytes): TBytes;
begin
SetLength(Result, 0);
if Length(Data) > 0 then
Result := CalcBuffer(Data[0], Length(Data))
else
Result := CalcBuffer(Data, Length(Data));
end;
function TDECHash.CalcString(const Value: string; Format: TDECFormatClass): string;
var
Size : Integer;
Data : TBytes;
begin
Result := '';
if Length(Value) > 0 then
begin
{$IF CompilerVersion >= 24.0}
Size := Length(Value) * SizeOf(Value[low(Value)]);
Data := CalcBuffer(Value[low(Value)], Size);
{$ELSE}
Size := Length(Value) * SizeOf(Value[1]);
Data := CalcBuffer(Value[1], Size);
{$IFEND}
Result := StringOf(ValidFormat(Format).Encode(Data));
end
else
begin
SetLength(Data, 0);
result := StringOf(ValidFormat(Format).Encode(CalcBuffer(Data, 0)));
end;
end;
function TDECHash.CalcString(const Value: RawByteString; Format: TDECFormatClass): RawByteString;
var
Buf : TBytes;
begin
Result := '';
if Length(Value) > 0 then
{$IF CompilerVersion >= 24.0}
result := BytesToRawString(
ValidFormat(Format).Encode(
CalcBuffer(Value[low(Value)],
Length(Value) * SizeOf(Value[low(Value)]))))
{$ELSE}
result := BytesToRawString(
ValidFormat(Format).Encode(
CalcBuffer(Value[1],
Length(Value) * SizeOf(Value[1]))))
{$IFEND}
else
begin
SetLength(Buf, 0);
Result := BytesToRawString(ValidFormat(Format).Encode(CalcBuffer(Buf, 0)));
end;
end;
class function TDECHash.ClassByIdentity(Identity: Int64): TDECHashClass;
begin
Result := TDECHashClass(ClassList.ClassByIdentity(Identity));
end;
class function TDECHash.ClassByName(const Name: string): TDECHashClass;
begin
Result := TDECHashClass(ClassList.ClassByName(Name));
end;
procedure TDECHash.CalcStream(const Stream: TStream; Size: Int64;
var HashResult: TBytes; const OnProgress:TDECProgressEvent);
var
Buffer: TBytes;
Bytes: Integer;
Max, Pos: Int64;
begin
Assert(Assigned(Stream), 'Stream to calculate hash on is not assigned');
// Last byte is incomplete so it mustn't be processed
if (FFinalByteLength > 0) then
Dec(Size);
Max := 0;
SetLength(HashResult, 0);
try
Init;
if StreamBufferSize <= 0 then
StreamBufferSize := 8192;
Pos := Stream.Position;
if Size < 0 then
Size := Stream.Size - Pos;
Max := Pos + Size;
if Assigned(OnProgress) then
OnProgress(Max, 0, Started);
Bytes := StreamBufferSize mod FBufferSize;
if Bytes = 0 then
Bytes := StreamBufferSize
else
Bytes := StreamBufferSize + FBufferSize - Bytes;
if Bytes > Size then
SetLength(Buffer, Size)
else
SetLength(Buffer, Bytes);
while Size > 0 do
begin
Bytes := Length(Buffer);
if Bytes > Size then
Bytes := Size;
Stream.ReadBuffer(Buffer[0], Bytes);
Calc(Buffer[0], Bytes);
Dec(Size, Bytes);
Inc(Pos, Bytes);
if Assigned(OnProgress) then
OnProgress(Max, Pos, Processing);
end;
// Last byte is incomplete but algorithm may need its value for padding
if (FFinalByteLength > 0) then
Stream.ReadBuffer(FFinalByte, 1);
Done;
HashResult := DigestAsBytes;
finally
ProtectBytes(Buffer);
if Assigned(OnProgress) then
OnProgress(Max, Max, Finished);
end;
end;
function TDECHash.CalcStream(const Stream: TStream; Size: Int64;
Format: TDECFormatClass; const OnProgress:TDECProgressEvent): RawByteString;
var
Hash: TBytes;
begin
CalcStream(Stream, Size, Hash, OnProgress);
Result := BytesToRawString(ValidFormat(Format).Encode(Hash));
end;
procedure TDECHash.CalcFile(const FileName: string; var HashResult: TBytes;
const OnProgress:TDECProgressEvent);
var
S: TFileStream;
begin
SetLength(HashResult, 0);
S := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
try
CalcStream(S, S.Size, HashResult, OnProgress);
finally
S.Free;
end;
end;
function TDECHash.CalcFile(const FileName: string; Format: TDECFormatClass;
const OnProgress:TDECProgressEvent): RawByteString;
var
Hash: TBytes;
begin
CalcFile(FileName, Hash, OnProgress);
Result := BytesToRawString(ValidFormat(Format).Encode(Hash));
end;
{$IFDEF DELPHIORBCB}
procedure ModuleUnload(Instance: NativeInt);
var // automaticaly deregistration/releasing
i: Integer;
begin
if TDECHash.ClassList <> nil then
begin
for i := TDECHash.ClassList.Count - 1 downto 0 do
begin
if NativeInt(FindClassHInstance(TClass(TDECHash.ClassList[i]))) = Instance then
TDECHash.ClassList.Remove(TDECFormat.ClassList[i].Identity);
end;
end;
end;
{$ENDIF DELPHIORBCB}
initialization
// Code for packages and dynamic extension of the class registration list
{$IFDEF DELPHIORBCB}
AddModuleUnloadProc(ModuleUnload);
{$ENDIF DELPHIORBCB}
TDECHash.ClassList := TDECClassList.Create;
finalization
// Ensure no further instances of classes registered in the registration list
// are possible through the list after this unit has been unloaded by unloding
// the package this unit is in
{$IFDEF DELPHIORBCB}
RemoveModuleUnloadProc(ModuleUnload);
{$ENDIF DELPHIORBCB}
TDECHash.ClassList.Free;
end.

View File

@@ -0,0 +1,89 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
/// <summary>
/// Base unit for all the hash algorithms which can operate on bit sized
/// messsages as well.
/// </summary>
unit DECHashBitBase;
interface
{$INCLUDE DECOptions.inc}
uses
{$IFDEF FPC}
SysUtils, Classes,
{$ELSE}
System.SysUtils, System.Classes,
{$ENDIF}
DECHashAuthentication, DECHashInterface, DECUtil;
type
/// <summary>
/// Base class for all hash algorithms which can operate on bit sized
/// messsages as well.
/// </summary>
TDECHashBit = class(TDECHashAuthentication, IDECHashBitsized)
strict private
/// <summary>
/// Returns the number of bits the final byte of the message consists of
/// </summary>
function GetFinalByteLength: UInt8;
/// <summary>
/// Sets the number of bits the final byte of the message consists of
/// </summary>
procedure SetFinalByteLength(const Value: UInt8);
public
/// <summary>
/// Setting this to a number of bits allows to process messages which have
/// a length which is not a exact multiple of bytes.
/// </summary>
property FinalByteLength : UInt8
read GetFinalByteLength
write SetFinalByteLength;
end;
implementation
resourcestring
/// <summary>
/// Exception message for the exception raised when a to long final byte
/// length is specified.
/// </summary>
rFinalByteLengthTooBig = 'Final byte length too big (%0:d) must be 0..7';
{ TDECHashBit }
function TDECHashBit.GetFinalByteLength: UInt8;
begin
Result := FFinalByteLength;
end;
procedure TDECHashBit.SetFinalByteLength(const Value: UInt8);
begin
// if length of final byte is 8 this value shall be 0 as the normal specification
// of message length is good enough then.
Assert(Value < 8, 'Length of final byte too big, a byte has 8 bit maximum');
if (Value > 7) then
raise EDECHashException.CreateFmt(rFinalByteLengthTooBig, [Value]);
FFinalByteLength := Value;
end;
end.

View File

@@ -0,0 +1,290 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
unit DECHashInterface;
interface
uses
{$IFDEF FPC}
SysUtils, Classes,
{$ELSE}
System.SysUtils, System.Classes,
{$ENDIF}
DECFormat, DECUtil;
type
/// <summary>
/// Generic interface for all hash classes.
/// Unfortunately without all the class methods, as they are not accepted
/// in interface declarations
/// </summary>
IDECHash = Interface
/// <summary>
/// Generic initialization of internal data structures. Additionally the
/// internal algorithm specific (because of being overridden by each
/// hash algorithm) DoInit method. Needs to be called before each hash
/// calculation.
/// </summary>
procedure Init;
/// <summary>
/// Calculates one chunk of data to be hashed.
/// </summary>
/// <param name="Data">
/// Data on which the hash value shall be calculated on
/// </param>
/// <param name="DataSize">
/// Size of the data in bytes
/// </param>
procedure Calc(const Data; DataSize: Integer);
/// <summary>
/// Frees dynamically allocated buffers in a way which safeguards agains
/// data stealing by other methods which afterwards might allocate this memory.
/// Additionaly calls the algorithm spercific DoDone method.
/// </summary>
procedure Done;
/// <summary>
/// Returns the calculated hash value as byte array
/// </summary>
function DigestAsBytes: TBytes;
/// <summary>
/// Returns the calculated hash value as formatted Unicode string
/// </summary>
/// <param name="Format">
/// Optional parameter. If a formatting class is being passed the formatting
/// will be applied to the returned string. Otherwise no formatting is
/// being used.
/// </param>
/// <returns>
/// Hash value of the last performed hash calculation
/// </returns>
/// <remarks>
/// We recommend to use a formatting which results in 7 bit ASCII chars
/// being returned, otherwise the conversion into the Unicode string might
/// result in strange characters in the returned result.
/// </remarks>
function DigestAsString(Format: TDECFormatClass = nil): string;
/// <summary>
/// Returns the calculated hash value as formatted RawByteString
/// </summary>
/// <param name="Format">
/// Optional parameter. If a formatting class is being passed the formatting
/// will be applied to the returned string. Otherwise no formatting is
/// being used.
/// </param>
/// <returns>
/// Hash value of the last performed hash calculation
/// </returns>
/// <remarks>
/// We recommend to use a formatting which results in 7 bit ASCII chars
/// being returned, otherwise the conversion into the RawByteString might
/// result in strange characters in the returned result.
/// </remarks>
function DigestAsRawByteString(Format: TDECFormatClass = nil): RawByteString;
/// <summary>
/// Calculates the hash value (digest) for a given buffer
/// </summary>
/// <param name="Buffer">
/// Untyped buffer the hash shall be calculated for
/// </param>
/// <param name="BufferSize">
/// Size of the buffer in byte
/// </param>
/// <returns>
/// Byte array with the calculated hash value
/// </returns>
function CalcBuffer(const Buffer; BufferSize: Integer): TBytes;
/// <summary>
/// Calculates the hash value (digest) for a given buffer
/// </summary>
/// <param name="Data">
/// The TBytes array the hash shall be calculated on
/// </param>
/// <returns>
/// Byte array with the calculated hash value
/// </returns>
function CalcBytes(const Data: TBytes): TBytes;
/// <summary>
/// Calculates the hash value (digest) for a given unicode string
/// </summary>
/// <param name="Value">
/// The string the hash shall be calculated on
/// </param>
/// <param name="Format">
/// Formatting class from DECFormat. The formatting will be applied to the
/// returned digest value. This parameter is optional.
/// </param>
/// <returns>
/// string with the calculated hash value
/// </returns>
function CalcString(const Value: string;
Format: TDECFormatClass = nil): string; overload;
/// <summary>
/// Calculates the hash value (digest) for a given rawbytestring
/// </summary>
/// <param name="Value">
/// The string the hash shall be calculated on
/// </param>
/// <param name="Format">
/// Formatting class from DECFormat. The formatting will be applied to the
/// returned digest value. This parameter is optional.
/// </param>
/// <returns>
/// string with the calculated hash value
/// </returns>
function CalcString(const Value: RawByteString;
Format: TDECFormatClass): RawByteString; overload;
/// <summary>
/// Calculates the hash value over a givens stream of bytes
/// </summary>
/// <param name="Stream">
/// Memory or file stream over which the hash value shall be calculated.
/// The stream must be assigned. The hash value will always be calculated
/// from the current position of the stream.
/// </param>
/// <param name="Size">
/// Number of bytes within the stream over which to calculate the hash value
/// </param>
/// <param name="HashResult">
/// In this byte array the calculated hash value will be returned
/// </param>
/// <param name="OnProgress">
/// Optional callback routine. It can be used to display the progress of
/// the operation.
/// </param>
procedure CalcStream(const Stream: TStream; Size: Int64; var HashResult: TBytes;
const OnProgress:TDECProgressEvent = nil); overload;
/// <summary>
/// Calculates the hash value over a givens stream of bytes
/// </summary>
/// <param name="Stream">
/// Memory or file stream over which the hash value shall be calculated.
/// The stream must be assigned. The hash value will always be calculated
/// from the current position of the stream.
/// </param>
/// <param name="Size">
/// Number of bytes within the stream over which to calculate the hash value
/// </param>
/// <param name="Format">
/// Optional formatting class. The formatting of that will be applied to
/// the returned hash value.
/// </param>
/// <param name="OnProgress">
/// Optional callback routine. It can be used to display the progress of
/// the operation.
/// </param>
/// <returns>
/// Hash value over the bytes in the stream, formatted with the formatting
/// passed as format parameter, if used.
/// </returns>
function CalcStream(const Stream: TStream; Size: Int64; Format: TDECFormatClass = nil;
const OnProgress:TDECProgressEvent = nil): RawByteString; overload;
/// <summary>
/// Calculates the hash value over the contents of a given file
/// </summary>
/// <param name="FileName">
/// Path and name of the file to be processed
/// </param>
/// <param name="HashResult">
/// Here the resulting hash value is being returned as byte array
/// </param>
/// <param name="OnProgress">
/// Optional callback. If being used the hash calculation will call it from
/// time to time to return the current progress of the operation
/// </param>
procedure CalcFile(const FileName: string; var HashResult: TBytes;
const OnProgress:TDECProgressEvent = nil); overload;
/// <summary>
/// Calculates the hash value over the contents of a given file
/// </summary>
/// <param name="FileName">
/// Path and name of the file to be processed
/// </param>
/// <param name="Format">
/// Optional parameter: Formatting class. If being used the formatting is
/// being applied to the returned string with the calculated hash value
/// </param>
/// <param name="OnProgress">
/// Optional callback. If being used the hash calculation will call it from
/// time to time to return the current progress of the operation
/// </param>
/// <returns>
/// Calculated hash value as RawByteString.
/// </returns>
/// <remarks>
/// We recommend to use a formatting which results in 7 bit ASCII chars
/// being returned, otherwise the conversion into the RawByteString might
/// result in strange characters in the returned result.
/// </remarks>
function CalcFile(const FileName: string; Format: TDECFormatClass = nil;
const OnProgress:TDECProgressEvent = nil): RawByteString; overload;
/// <summary>
/// Returns the current value of the padding byte used to fill up data
/// if necessary
/// </summary>
function GetPaddingByte: Byte;
/// <summary>
/// Changes the value of the padding byte used to fill up data
/// if necessary
/// </summary>
/// <param name="Value">
/// New value for the padding byte
/// </param>
procedure SetPaddingByte(Value: Byte);
/// <summary>
/// Defines the byte used in the KDF methods to padd the end of the data
/// if the length of the data cannot be divided by required size for the
/// hash algorithm without reminder
/// </summary>
property PaddingByte: Byte read GetPaddingByte write SetPaddingByte;
end;
/// <summary>
/// Interface for all hash classes which are able to operate on bit sized
/// message lengths instead of byte sized ones only.
/// </summary>
IDECHashBitsized = Interface(IDECHash)
/// <summary>
/// Returns the number of bits the final byte of the message consists of
/// </summary>
function GetFinalByteLength: UInt8;
/// <summary>
/// Sets the number of bits the final byte of the message consists of
/// </summary>
procedure SetFinalByteLength(const Value: UInt8);
/// <summary>
/// Setting this to a number of bits allows to process messages which have
/// a length which is not a exact multiple of bytes.
/// </summary>
property FinalBitLength : UInt8
read GetFinalByteLength
write SetFinalByteLength;
end;
implementation
end.

View File

@@ -0,0 +1,210 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
//------------------------------------------------------------------------------
// Reset Defines (do not change!)
//------------------------------------------------------------------------------
{$UNDEF NATIVEINT_UNDEFINED}
{$UNDEF PUREPASCAL}
{$UNDEF X86ASM}
{$UNDEF X64ASM}
{$UNDEF NO_ASM}
{$UNDEF OLD_SHA_NAME}
{$UNDEF OLD_WHIRLPOOL_NAMES}
{$UNDEF OLD_REGISTER_FAULTY_CIPHERS}
{$UNDEF AUTO_PRNG}
{$UNDEF DEC52_IDENTITY}
{$UNDEF DEC3_CMCTS}
{$UNDEF RESTORE_RANGECHECKS}
{$UNDEF RESTORE_OVERFLOWCHECKS}
//------------------------------------------------------------------------------
// User Configuration (feel free to edit)
//------------------------------------------------------------------------------
// If on, the old class name THash_SHA for the THash_SHA0 class will be available
// This should only be necessary for cases where the identity value has been
// used to determine the algorithm to be used and thus it's necessary that the
// same result will be produced. It is recommended to switch to the new class
// names where possible
// Currently this does not work together with using x86 ASM! Either ASM or the
// old name works
{.$DEFINE OLD_SHA_NAME} (* default off *)
// if on the old outdated class names THash_Whirlpool and THash_Whirlpool1 are
// being used. Nowadays Whirlpool versions are named like this:
// Whirlpool -> Whirlpool0. Whrilpool1 -> WhirlpoolT and there's a new Whirlpool1
// variant which differs to WhrilpoolT only by the initialization of internal data
// This should only be necessary for cases where the identity value has been
// used to determine the algorithm to be used and thus it's necessary that the
// same result will be produced. It is recommended to switch to the new class
// names where possible
{.$DEFINE OLD_WHIRLPOOL_NAMES} (* default off *)
// when enabling this define, the automatic registration of all those cipher and
// hash classes in initialization sections is not being done.
{.$DEFINE ManualRegisterClasses} (* default off *}
// Automatically use DEC's Pseudo Random Number Generator
{$DEFINE AUTO_PRNG} (* default ON *)
// if the compiler does not support assembler turn usage off and even if restrict
// it to Windows, as those non Windows platforms which actually do support ASM
// in Delphi do not use Intel x86 ASM
{$IFNDEF FPC}
{$IFNDEF ASSEMBLER}
{$DEFINE NO_ASM} (* default ON *)
{$ELSE}
{$IFDEF WINDOWS}
{.$DEFINE NO_ASM} (* default OFF *)
{$ELSE
{$DEFINE NO_ASM} (* default ON *)
{$ENDIF}
{$ENDIF}
{$ELSE}
// Turn ASM off for FPC as we do not know enough about ASM support on FPC
{$DEFINE NO_ASM} (* default ON *)
{$ENDIF}
// Enable the following option to restore the *wrong* Identity behavior of
// DEC version 5.2. See TDECObject.Identity in DECBaseClass.pas for more details
{.$DEFINE DEC52_IDENTITY} (* default OFF *)
// Enable the following option to include the cmCTS3 block cipher mode in
// DECCipher. This mode is less secure due to the padding used on data smaller
// that cipher's block size but it might help when having to deal with
// data which needs to be compatible to the DEC 3.0 cmCTS mode. Not recommended!
{.$DEFINE DEC3_CMCTS} (* default OFF *)
/// <summary>
/// When building a Firemonkey project for non Windows platforms
/// ressource strings are not available. Enabling this enables some
/// alternative translation mechanism for exception messages based
/// on Firemonkey's TLang architecture
/// </summary>
{$IF DECLARED(FireMonkeyVersion)}
{$DEFINE FMXTranslateableExceptions}
{$IFEND} { TODO: convert to $ENDIF when raising minimum supported version to XE4+}
//------------------------------------------------------------------------------
// Do NOT change anything below!
//------------------------------------------------------------------------------
{$DEFINE DELPHIORBCB}
//------------------------------------------------------------------------------
// FPC v2.x support (Experimental)
//------------------------------------------------------------------------------
{$IFDEF FPC}
{$UNDEF DELPHIORBCB}
{$DEFINE PUREPASCAL}
{$DEFINE NATIVEINT_UNDEFINED}
// use compatibility mode
{$MODE DELPHI}
// defines for Mac OS X
{$IFDEF DARWIN}
{$DEFINE MACOS}
{$DEFINE ALIGN_STACK}
{$ENDIF}
{$ENDIF FPC}
//------------------------------------------------------------------------------
// Architecture (x86ASM, x64ASM, PurePascal)
//------------------------------------------------------------------------------
//{$DEFINE NO_ASM}
{$IFDEF NO_ASM}
// User config override (see top of this file)
{$UNDEF X86ASM}
{$UNDEF X64ASM}
{$DEFINE PUREPASCAL}
{$ENDIF}
{$IFNDEF PUREPASCAL}
// ignored by FPC (already in PurePascal mode as defined in FPC block above)
{$IFDEF CPUX86}
{$DEFINE X86ASM}
{$ELSE !CPUX86}
{$IFDEF CPUX64}
{$DEFINE X64ASM}
{$ELSE !CPUX64}
{$DEFINE PUREPASCAL}
{$ENDIF !CPUX64}
{$ENDIF}
{$ENDIF !PUREPASCAL}
{$IF SizeOf(Pointer) = 4}
{$DEFINE CPU32BITS}
{$IFEND}
{$IF SizeOf(Pointer) = 8}
{$DEFINE CPU64BITS}
{$IFEND}
//------------------------------------------------------------------------------
// Delphi and C++ Builder
//------------------------------------------------------------------------------
{$IFDEF DELPHIORBCB}
{$BOOLEVAL OFF} // short-circuit bool eval (Default OFF; Local Scope)
{$IF CompilerVersion >= 20} // Delphi 2009 and newer
{$IF CompilerVersion >= 21} // Delphi 2010 and newer
{$DEFINE DELPHI_2010_UP}
{$IFEND}
{$ELSE}
Sorry, but Delphi 2007 and lower are no longer supported!
{$IFEND}
{$ENDIF}
//------------------------------------------------------------------------------
// Asm Core
//------------------------------------------------------------------------------
{$IFDEF X86ASM}
{$DEFINE THash_MD4_asm}
{$DEFINE THash_MD5_asm}
{$DEFINE THash_RipeMD128_asm}
{$DEFINE THash_RipeMD160_asm}
{$DEFINE THash_RipeMD256_asm}
{$DEFINE THash_RipeMD320_asm}
{$DEFINE THash_SHA_asm}
{$DEFINE THash_SHA256_asm}
{$DEFINE THashBaseHaval_asm}
{$DEFINE THash_Panama_asm}
{$DEFINE THashBaseWhirlpool_asm}
{$DEFINE THash_Sapphire_asm}
// The following asm optimized Hashes were incompatible with newer C++
// Builder versions. Due to the fact that BCB detection is not implemented
// in newer Delphi versions anymore, we leave them out for now:
// {$DEFINE THash_MD2_asm}
// {$DEFINE THash_SHA384_asm}
// {$DEFINE THash_Tiger_asm}
// {$DEFINE THash_Square_asm}
// {$DEFINE THash_Snefru128_asm}
// {$DEFINE THash_Snefru256_asm}
{$ENDIF}

View File

@@ -0,0 +1,431 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
/// <summary>
/// Secure Pseudo Random Number Generator based on Yarrow. If used without
/// doing anything special for initialization a repeatable generator will be
/// initialized always using the same start value.
/// </summary>
unit DECRandom;
interface
{$INCLUDE DECOptions.inc}
uses
{$IFDEF FPC}
SysUtils,
{$ELSE}
System.SysUtils,
{$ENDIF}
DECHashBase, DECHash;
/// <summary>
/// Create a seed for the random number generator from system time and
/// PerformanceCounter.
/// </summary>
/// <remarks>
/// Avoid initializing the seed using this fuction if you can as it is not
/// really secure. Use RandomBuffer instead and provide user generated input
/// as Buffer value but ensure that this is not uniform e.g. not a buffer only
/// containing $00 all over or something like this.
/// </remarks>
/// <returns>
/// Created hash value
/// </returns>
function RandomSystemTime: Int64;
/// <summary>
/// Fills the provided buffer with random values. If the DoRandomBuffer
/// variable is assigned (which is usually the case because DoBuffer is
/// assigned to it in initialization of this unit) the hash based algorithm
/// in DoBuffer will be used, otherwise the weaker one in DoRndBuffer.
/// </summary>
/// <param name="Buffer">
/// Buffer to be filled with random values
/// </param>
/// <param name="Size">
/// Size of the buffer in byte
/// </param>
procedure RandomBuffer(out Buffer; Size: Integer);
/// <summary>
/// Creates a buffer of the specified size filled with random bytes
/// </summary>
/// <param name="Size">
/// Size of the buffer to be created in bytes
/// </param>
/// <returns>
/// Buffer of the specified size in bytes filled with random data
/// </returns>
function RandomBytes(Size: Integer): TBytes;
/// <summary>
/// Creates a RawByteString of the specified length filled with random bytes.
/// </summary>
/// <remarks>
/// This function is deprecated. Better use RandomBytes where ever possible!
/// </remarks>
/// <param name="Size">
/// Length of the string to be created in bytes
/// </param>
/// <returns>
/// String of the specified length in bytes filled with random data
/// </returns>
function RandomRawByteString(Size: Integer): RawByteString; deprecated 'please use RandomBytes now';
/// <summary>
/// Creates a random UInt32 value
/// </summary>
/// <returns>
/// Random value
/// </returns>
function RandomLong: UInt32;
/// <summary>
/// If the default value of the global DoRandomSeed variable is kept, this
/// procedure initializes a repeatable or a non repeatable seed,
/// depending on the parameters specified. Otherwise the alternative DoRandomSeed
/// implementation is called. The FRndSeed variable is initialized with the
/// seed value generated.
/// </summary>
/// <param name="Buffer">
/// If a repeatable seed is to be initialized, the contents of this buffer is
/// a parameter to the seed generation and a buffer containing at least Size
/// bytes needs to be passed.
/// </param>
/// <param name="Size">
/// If Size is > 0 a repeatable seed is initialized. If Size is 0 the
/// internal seed variable FRndSeed is initialized with 0. If Size is
/// less than 0 the internal FRndSeed variable is initialized with
/// a value derrived from current system time/performance counter using
/// RandomSystemTime.
/// </param>
procedure RandomSeed(const Buffer; Size: Integer); overload;
/// <summary>
/// Creates a seed (starting) value for the random number generator. If the
/// default value of the global DoRandomSeed variable is kept, a non repeatable
/// seed based on RandomSystemTime (based on system time and potentially
/// QueryPerformanceCounter) is created and assigned to the internal FRndSeed
/// variable.
/// </summary>
procedure RandomSeed; overload;
var
// secure PRNG initialized by this unit
/// <summary>
/// This variable allows overriding the random number generation procedure
/// used for data buffers. By default it is initialized to point to DoBuffer,
/// which is a DECRandom internal procedure.
/// </summary>
/// <param name="Buffer">
/// Buffer in which the random bytes shall be written. The buffer needs to
/// exist and must be of at least Size bytes length.
/// </param>
/// <param name="Size">
/// Length of the buffer to be filled in Byte.
/// </param>
DoRandomBuffer: procedure(out Buffer; Size: Integer); register = nil;
/// <summary>
/// This variable allows overriding the seed value generation procedure.
/// By default it is initialized with the DECRandom internal procedure DoSeed.
/// </summary>
DoRandomSeed: procedure(const Buffer; Size: Integer); register = nil;
/// <summary>
/// Defines the hash-algorithm used for generatin seed values or hashed buffers
/// </summary>
RandomClass: TDECHashClass = THash_SHA256;
implementation
uses
{$IFDEF DELPHI_2010_UP}
System.Diagnostics
{$ELSE}
{$IFDEF FPC}
{$IFDEF MSWINDOWS}
Windows
{$ELSE}
LclIntf
{$ENDIF}
{$ELSE}
Winapi.Windows
{$ENDIF}
{$ENDIF}
;
{$IFOPT Q+}{$DEFINE RESTORE_OVERFLOWCHECKS}{$Q-}{$ENDIF}
{$IFOPT R+}{$DEFINE RESTORE_RANGECHECKS}{$R-}{$ENDIF}
var
/// <summary>
/// A sequence of values which over time will be random by replacing each
/// value with a derived value generated by applying the hash algorithm.
/// </summary>
FRegister: array[0..127] of Byte;
/// <summary>
/// The hash used to generate derived values stored in FRegister is calculated
/// using this counter as input and this counter additionaly defines the index
/// in FRegister where the value will be stored. The counter can assume higher
/// values than the lngth of FRegister. The index calculation takes this into
/// account.
/// </summary>
FCounter: Cardinal;
/// <summary>
/// Object instance for the hash generation algorithm used. The object is
/// created the first time it is needed and freed in finalization of this unit.
/// </summary>
FHash: TDECHash = nil;
/// <summary>
/// Seed value, stores the last generated random number as start value for
/// the next randum number generation
/// </summary>
FRndSeed: Cardinal = 0;
function RandomSystemTime: Int64;
type
TInt64Rec = packed record
Lo, Hi: UInt32;
end;
var
{$IF defined(MSWINDOWS) and not defined(DELPHI_2010_UP)}
SysTime: TSystemTime;
{$ELSE}
Hour, Minute, Second, Milliseconds: Word;
{$IFEND}
Counter: TInt64Rec;
Time: Cardinal;
begin
{$IF defined(MSWINDOWS) and not defined(DELPHI_2010_UP)}
GetSystemTime(SysTime);
Time := ((Cardinal(SysTime.wHour) * 60 + SysTime.wMinute) * 60 + SysTime.wSecond) * 1000 + SysTime.wMilliseconds;
QueryPerformanceCounter(Int64(Counter));
{$ELSE}
DecodeTime(Now, Hour, Minute, Second, Milliseconds);
Time := ((Cardinal(Hour) * 60 + Minute) * 60 + Second) * 1000 + Milliseconds;
{$IFDEF DELPHI_2010_UP}
Int64(Counter) := TStopWatch.GetTimeStamp; // uses System.Diagnostics
{$ELSE}
{$IFDEF FPC}
Int64(Counter) := LclIntf.GetTickCount * 10000 {TicksPerMillisecond}; // uses LclIntf
{$ENDIF}
{$ENDIF}
{$IFEND}
Result := Time + Counter.Hi;
Inc(Result, Ord(Result < Time)); // add "carry flag"
Inc(Result, Counter.Lo);
end;
/// <summary>
/// Simplistic algorithm for filling a buffer with random numbers. This
/// algorithm is directly dependant on the seed passed, which by internal use
/// will normally be FRndSeed.
/// </summary>
/// <param name="Seed">
/// Seed value as starting value
/// </param>
/// <param name="Buffer">
/// Buffer which shall be filled with random bytes
/// </param>
/// <param name="Size">
/// Size of the buffer in byte
/// </param>
/// <returns>
/// New seed value after calculating the random number for the last byte in
/// the buffer.
/// </returns>
function DoRndBuffer(Seed: Cardinal; out Buffer; Size: Integer): Cardinal;
// comparable to Delphi Random() function
var
P: PByte;
begin
Result := Seed;
P := @Buffer;
if P <> nil then
begin
while Size > 0 do
begin
Result := Result * $08088405 + 1;
P^ := Byte(Result shr 24);
Inc(P);
Dec(Size);
end;
end;
end;
procedure RandomBuffer(out Buffer; Size: Integer);
begin
if Assigned(DoRandomBuffer) then
DoRandomBuffer(Buffer, Size)
else
FRndSeed := DoRndBuffer(FRndSeed, Buffer, Size);
end;
function RandomBytes(Size: Integer): TBytes;
begin
SetLength(Result, Size);
RandomBuffer(Result[0], Size);
end;
function RandomRawByteString(Size: Integer): RawByteString;
begin
SetLength(Result, Size);
{$IF CompilerVersion >= 24.0}
RandomBuffer(Result[Low(Result)], Size);
{$ELSE}
RandomBuffer(Result[1], Size);
{$IFEND}
end;
function RandomLong: UInt32;
begin
RandomBuffer(Result, SizeOf(Result));
end;
procedure RandomSeed(const Buffer; Size: Integer);
begin
if Assigned(DoRandomSeed) then
DoRandomSeed(Buffer, Size)
else
begin
if Size >= 0 then
begin
FRndSeed := 0;
while Size > 0 do
begin
Dec(Size);
FRndSeed := (FRndSeed shl 8 + FRndSeed shr 24) xor TByteArray(Buffer)[Size]
end;
end
else
FRndSeed := RandomSystemTime;
end;
end;
procedure RandomSeed;
begin
RandomSeed('', -1);
end;
/// <summary>
/// Generate one random byte and modify FCounter and FRegister
/// </summary>
function DoGenerateRandomByte: Byte;
begin
if FHash = nil then
FHash := RandomClass.Create;
FHash.Init;
FHash.Calc(FCounter, SizeOf(FCounter));
FHash.Calc(FRegister, SizeOf(FRegister));
FHash.Done;
FRegister[FCounter mod SizeOf(FRegister)] := FRegister[FCounter mod SizeOf(FRegister)] xor FHash.DigestAsBytes[0];
Inc(FCounter);
Result := FHash.DigestAsBytes[1]; // no real predictable dependency to above FHash.Digest[0] !
end;
procedure DoBuffer(out Buffer; Size: Integer);
var
i: Integer;
begin
for i := 0 to Size - 1 do
TByteArray(Buffer)[i] := DoGenerateRandomByte;
end;
/// <summary>
/// Initializes a repeatable or a non repeatable seed, depending on the
/// parameters specified
/// </summary>
/// <param name="Buffer">
/// If a repeatable seed is to be initialized, the contents of this buffer is
/// a parameter to the seed generation and a buffer containing at least Size
/// bytes needs to be passed.
/// </param>
/// <param name="Size">
/// If Size is >= 0 a repeatable seed is initialized, otherwise a non repeatable
/// based on system time
/// </param>
procedure DoSeed(const Buffer; Size: Integer);
var
i: Integer;
t: Cardinal;
begin
if Size >= 0 then
begin
// initalize a repeatable Seed
FillChar(FRegister, SizeOf(FRegister), 0);
FCounter := 0;
for i := 0 to Size - 1 do
FRegister[i mod SizeOf(FRegister)] := FRegister[i mod SizeOf(FRegister)] xor TByteArray(Buffer)[i];
end
else
begin
// ! ATTENTION !
// Initalizes a non-repeatable Seed based on Timers, which is not secure
// and inpredictable. The user should call RandomSeed(Data, SizeOf(Data))
// instead, where Date contains i.e. user generated (Human) input.
t := RandomSystemTime;
for i := Low(FRegister) to High(FRegister) do
begin
FRegister[i] := FRegister[i] xor Byte(t);
t := t shl 1 or t shr 31;
end;
end;
for i := Low(FRegister) to High(FRegister) do
DoGenerateRandomByte;
FCounter := 0;
end;
procedure DoInit;
begin
DoRandomBuffer := DoBuffer;
DoRandomSeed := DoSeed;
DoSeed('', 0);
end;
procedure DoDone;
begin
try
if FHash <> nil then
FHash.Free;
except
end;
FHash := nil;
FillChar(FRegister, SizeOf(FRegister), 0);
FCounter := 0;
end;
{$IFDEF RESTORE_RANGECHECKS}{$R+}{$ENDIF}
{$IFDEF RESTORE_OVERFLOWCHECKS}{$Q+}{$ENDIF}
initialization
{$DEFINE AUTO_PRNG}
DoInit;
{$IFDEF AUTO_PRNG} // see DECOptions.inc
RandomSeed;
{$ENDIF AUTO_PRNG}
finalization
DoDone;
end.

View File

@@ -0,0 +1,52 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
/// <summary>
/// Declarations of various datatypes, some of those have not been
/// declared for certain platforms but are used in DEC and some do change
/// meanings between platforms like PLongWord where LongWord is 32 bit on
/// Windows and Android but 64 bit on iOS for instance
/// </summary>
unit DECTypes;
interface
type
{$IFNDEF FPC}
{$IF CompilerVersion <= 20}
// In D2009 NativeInt was not properly treated by the compiler under certain
// conditions. See: http://qc.embarcadero.com/wc/qcmain.aspx?d=71292
NativeInt = Integer;
{$IFEND}
{$ENDIF}
PUInt32Array = ^TUInt32Array;
TUInt32Array = array[0..1023] of UInt32;
/// <summary>
/// Replacement for PLongWord, as LongWord changes between platforms from
/// 32 to 64 bit
/// </summary>
PUInt32 = ^UINT32;
PUInt64Array = ^TUInt64Array;
TUInt64Array = array[0..1023] of UInt64;
implementation
end.

View File

@@ -0,0 +1,733 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
/// <summary>
/// Utility functions
/// </summary>
unit DECUtil;
interface
{$INCLUDE DECOptions.inc}
uses
{$IFDEF FPC}
SysUtils, Classes;
{$ELSE}
System.SysUtils, System.Classes;
{$ENDIF}
type
// Exception Classes
/// <summary>
/// Base exception class for all DEC specific exceptions,
/// </summary>
EDECException = class(Exception)
public
{$IFDEF FMXTranslateableExceptions}
/// <summary>
/// Creates the exception instance and makes the exception message translateable
/// via Firemonkey's TLang translation mechanism. Normal ressource strings
/// are not translated in the same way on mobile platforms as they are on
/// Win32/Win64.
/// </summary>
/// <param name="Msg">
/// String with a failure message to be output or logged
/// </param>
constructor Create(const Msg: string); reintroduce; overload;
/// <summary>
/// Creates the exception instance and makes the exception message translateable
/// via Firemonkey's TLang translation mechanism. Normal ressource strings
/// are not translated in the same way on mobile platforms as they are on
/// Win32/Win64.
/// </summary>
/// <param name="Msg">
/// String with a failure message to be output or logged
/// </param>
/// <param name="Args">
/// Array with values for the parameters specified in the format string
/// </param>
constructor CreateFmt(const Msg: string;
const Args: array of const); reintroduce; overload;
{$ENDIF}
end;
/// <summary>
/// Exception class used when reporting that a class searched in a list is
/// not contained in that list, e.g. when searching for a non existant
/// formatting class.
/// </summary>
EDECClassNotRegisteredException = class(EDECException);
/// <summary>
/// Exception class for reporting formatting related exceptions
/// </summary>
EDECFormatException = class(EDECException);
/// <summary>
/// Exception class for reporting exceptions related to hash functions
/// </summary>
EDECHashException = class(EDECException);
/// <summary>
/// Exception class for reporting encryption/decryption caused exceptions
/// </summary>
EDECCipherException = class(EDECException);
/// <summary>
/// Exception class for reporting the use of abstract things which cannot
/// be called directly
/// </summary>
EDECAbstractError = class(EDECException)
/// <summary>
/// Create the exception using a meaningfull error message
/// </summary>
constructor Create(ClassName: string); overload;
end;
/// <summary>
/// Reason for calling the progress event
/// </summary>
TDECProgressState = (Started, Processing, Finished {, Error});
/// <summary>
/// Event type used by several hash- and cipher methods to display their
/// progress. It can be implemented as regular method, procedure and as
/// anonymous method, means: in place.
/// </summary>
/// <param name="Size">
/// Number of bytes to process. For files this is usually the file size. For
/// streams this can be less than the stream size if the stream is not being
/// processed from the beginning.
/// </param>
/// <param name="Pos">
/// Position within size in byte. For streams this may be a position
/// relative to the starting position for processing.
/// </param>
TDECProgressEvent = reference to procedure(Size, Pos: Int64; State: TDECProgressState);
// Byte Ordering
/// <summary>
/// Reverses all bits in the passed value, 1111 0000 will be 0000 1111 afterwards
/// </summary>
/// <param name="Source">
/// Value who's bits are to be reversed
/// </param>
/// <returns>
/// Representation of Source but with all bits reversed
/// </returns>
function ReverseBits(Source: UInt32): UInt32; overload;
/// <summary>
/// Reverses all bits in the passed value, 1111 0000 will be 0000 1111 afterwards
/// </summary>
/// <param name="Source">
/// Value who's bits are to be reversed
/// </param>
/// <returns>
/// Representation of Source but with all bits reversed
/// </returns>
function ReverseBits(Source: UInt8): UInt8; overload;
/// <summary>
/// Reverses the order of the bytes contained in the buffer passed in.
/// e.g. 1 2 3 will be 3 2 1 afterwards
/// </summary>
/// <param name="Buffer">
/// Buffer who's contents is to be reversed.
/// </param>
/// <param name="Size">
/// Size of the passed buffer in byte
/// </param>
procedure SwapBytes(var Buffer; Size: Integer);
/// <summary>
/// Reverses the byte order of the passed variable
/// </summary>
/// <param name="Source">
/// value who's byte order shall be reversed
/// </param>
/// <returns>
/// value of the passed vallue with reversed byte order
/// </returns>
function SwapUInt32(Source: UInt32): UInt32;
/// <summary>
/// Reverses the byte order for all entries of a passed array of UInt32 values
/// </summary>
/// <param name="Source">
/// Data with a layout like an array of UInt32 values for which the byte order
/// of all entries shall be reversed
/// </param>
/// <param name="Dest">
/// In this variable the reversed values will be stored. Layout is like an
/// array of UInt32 values
/// </param>
/// <param name="Count">
/// Number of values to be reversed
/// </param>
procedure SwapUInt32Buffer(const Source; var Dest; Count: Integer);
/// <summary>
/// Reverses the byte order of an Int64 value
/// </summary>
/// <param name="Source">
/// Value who's byte order shall be reversed
/// </param>
/// <returns>
/// Representation of the passed value after reversing its byte order
/// </returns>
function SwapInt64(Source: Int64): Int64;
/// <summary>
/// Reverses the byte order for all entries of a passed array of Int64 values
/// </summary>
/// <param name="Source">
/// Data with a layout like an array of Int64 values for which the byte order
/// of all entries shall be reversed
/// </param>
/// <param name="Dest">
/// In this variable the reversed values will be stored. Layout is like an
/// array of Int64 values
/// </param>
/// <param name="Count">
/// Number of values to be reversed
/// </param>
procedure SwapInt64Buffer(const Source; var Dest; Count: Integer);
/// <summary>
/// XORs the contents of two passed buffers and stores the result into a 3rd one
/// </summary>
/// <param name="Left">
/// One source buffer of bytes to be XORed
/// </param>
/// <param name="Right">
/// The other source buffer of bytes to be XORed. Buffer size must be equal
/// or bigger than Left
/// </param>
/// <param name="Size">
/// Buffer size in byte.
/// </param>
/// <param name="Dest">
/// Buffer where the result is to be stored in. Must be of equal or bigger
/// size than Left
/// </param>
procedure XORBuffers(const Left, Right; Size: Integer; var Dest);
// Buffer and Data Protection
/// <summary>
/// Fills a given buffer with zeros in a secure way
/// </summary>
/// <param name="Buffer">
/// Buffer to be zeroed. In case of TBytes to be passed as Buf[0]
/// </param>
/// <param name="Size">
/// Buffer size in byte
/// </param>
procedure ProtectBuffer(var Buffer; Size: NativeUInt);
/// <summary>
/// Fills a given stream with zeros in a secure way
/// </summary>
/// <param name="Stream">
/// Stream to be zeroed.
/// </param>
/// <param name="SizeToProtect">
/// Number of bytes of that stream to be zeroed. Starting point is Stream.Position
/// </param>
procedure ProtectStream(Stream: TStream; SizeToProtect: Int64 = 0);
/// <summary>
/// Fills a given byte array with zeros in a secure way and then empties the
/// buffer.
/// </summary>
/// <param name="Source">
/// Byte array to be zeroed. The length of the passed buffer is 0 afterwards!
/// </param>
procedure ProtectBytes(var Source: TBytes);
/// <summary>
/// Overwrites the string's contents in a secure way and returns an empty string.
/// </summary>
/// <param name="Source">
/// String to be safely overwritten
/// </param>
procedure ProtectString(var Source: string); overload;
/// <summary>
/// Overwrites the string's contents in a secure way and returns an empty string.
/// </summary>
/// <param name="Source">
/// String to be safely overwritten
/// </param>
procedure ProtectString(var Source: RawByteString); overload;
{$IFDEF ANSISTRINGSUPPORTED}
/// <summary>
/// Overwrites the string's contents in a secure way and returns an empty string.
/// </summary>
/// <param name="Source">
/// String to be safely overwritten
/// </param>
procedure ProtectString(var Source: AnsiString); overload;
{$ENDIF}
{$IFNDEF NEXTGEN}
/// <summary>
/// Overwrites the string's contents in a secure way and returns an empty string.
/// </summary>
/// <param name="Source">
/// String to be safely overwritten
/// </param>
procedure ProtectString(var Source: WideString); overload;
{$ENDIF}
// Byte/String conversion
/// <summary>
/// Converts a byte array to a RawByteString
/// </summary>
/// <param name="Source">
/// Byte array to be converted into a string. An empty byte array is allowed
/// and results in an empty string.
/// </param>
/// <returns>
/// RawByteString with the same length as Source and all bytes copied over.
/// No conversion of any sort is being applied to the bytes.
/// </returns>
/// <remarks>
/// Not easily replaced by some RTL function as none for TBytes to RawByteString
/// seems to exist
/// </remarks>
function BytesToRawString(const Source: TBytes): RawByteString;
implementation
{$IFDEF FMXTranslateableExceptions}
uses
FMX.Types,
{$ELSE}
uses
{$ENDIF}
DECUtilRawByteStringHelper, DECTypes;
const
{ TODO :
Pr<EFBFBD>fen warum das eine Konstante ist, die gleich vom Ressourcestring
benutzt wird. Weil es keine Ressorcestrings bei FMX gibt? }
cAbstractError = 'Abstract Error: %s is not implemented';
resourcestring
sAbstractError = cAbstractError;
const
// Bit Lookup Table - see 'Bit Twiddling Hacks' by Sean Eron Anderson
// http://graphics.stanford.edu/~seander/bithacks.html
ReverseBitLookupTable256: array[0..255] of Byte = ($00, $80, $40, $C0,
$20, $A0, $60, $E0, $10, $90, $50, $D0, $30, $B0, $70, $F0, $08, $88,
$48, $C8, $28, $A8, $68, $E8, $18, $98, $58, $D8, $38, $B8, $78, $F8,
$04, $84, $44, $C4, $24, $A4, $64, $E4, $14, $94, $54, $D4, $34, $B4,
$74, $F4, $0C, $8C, $4C, $CC, $2C, $AC, $6C, $EC, $1C, $9C, $5C, $DC,
$3C, $BC, $7C, $FC, $02, $82, $42, $C2, $22, $A2, $62, $E2, $12, $92,
$52, $D2, $32, $B2, $72, $F2, $0A, $8A, $4A, $CA, $2A, $AA, $6A, $EA,
$1A, $9A, $5A, $DA, $3A, $BA, $7A, $FA, $06, $86, $46, $C6, $26, $A6,
$66, $E6, $16, $96, $56, $D6, $36, $B6, $76, $F6, $0E, $8E, $4E, $CE,
$2E, $AE, $6E, $EE, $1E, $9E, $5E, $DE, $3E, $BE, $7E, $FE, $01, $81,
$41, $C1, $21, $A1, $61, $E1, $11, $91, $51, $D1, $31, $B1, $71, $F1,
$09, $89, $49, $C9, $29, $A9, $69, $E9, $19, $99, $59, $D9, $39, $B9,
$79, $F9, $05, $85, $45, $C5, $25, $A5, $65, $E5, $15, $95, $55, $D5,
$35, $B5, $75, $F5, $0D, $8D, $4D, $CD, $2D, $AD, $6D, $ED, $1D, $9D,
$5D, $DD, $3D, $BD, $7D, $FD, $03, $83, $43, $C3, $23, $A3, $63, $E3,
$13, $93, $53, $D3, $33, $B3, $73, $F3, $0B, $8B, $4B, $CB, $2B, $AB,
$6B, $EB, $1B, $9B, $5B, $DB, $3B, $BB, $7B, $FB, $07, $87, $47, $C7,
$27, $A7, $67, $E7, $17, $97, $57, $D7, $37, $B7, $77, $F7, $0F, $8F,
$4F, $CF, $2F, $AF, $6F, $EF, $1F, $9F, $5F, $DF, $3F, $BF, $7F, $FF);
function ReverseBits(Source: UInt32): UInt32;
begin
Result := (ReverseBitLookupTable256[Source and $FF] shl 24) or
(ReverseBitLookupTable256[(Source shr 8) and $FF] shl 16) or
(ReverseBitLookupTable256[(Source shr 16) and $FF] shl 8) or
(ReverseBitLookupTable256[(Source shr 24) and $FF]);
end;
function ReverseBits(Source: UInt8): UInt8;
begin
Result := ReverseBitLookupTable256[Source];
end;
procedure SwapBytes(var Buffer; Size: Integer);
{$IFDEF X86ASM}
asm
CMP EDX,1
JLE @@3
AND EAX,EAX
JZ @@3
PUSH EBX
MOV ECX,EDX
LEA EDX,[EAX + ECX - 1]
SHR ECX,1
@@1: MOV BL,[EAX]
XCHG BL,[EDX]
DEC EDX
MOV [EAX],BL
INC EAX
DEC ECX
JNZ @@1
@@2: POP EBX
@@3:
end;
{$ELSE !X86ASM}
var
T: Byte;
P, Q: PByte;
i: Integer;
begin
P := @Buffer;
Inc(P, Size - 1);
Q := @Buffer;
for i := 0 to Size div 2 - 1 do // using P/Q comparison with 'while' breaks some compilers
begin
T := Q^;
Q^ := P^;
P^ := T;
Dec(P);
Inc(Q);
end;
end;
{$ENDIF !X86ASM}
function SwapUInt32(Source: UInt32): UInt32;
{$IF defined(X86ASM) or defined(X64ASM)}
asm
{$IFDEF X64ASM}
MOV EAX, ECX
{$ENDIF X64ASM}
BSWAP EAX
end;
{$ELSE PUREPASCAL}
begin
Result := Source shl 24 or
Source shr 24 or
Source shl 8 and $00FF0000 or
Source shr 8 and $0000FF00;
end;
{$IFEND PUREPASCAL}
procedure SwapUInt32Buffer(const Source; var Dest; Count: Integer);
{$IFDEF X86ASM}
asm
TEST ECX,ECX
JLE @Exit
PUSH EDI
SUB EAX,4
SUB EDX,4
@@1: MOV EDI,[EAX + ECX * 4]
BSWAP EDI
MOV [EDX + ECX * 4],EDI
DEC ECX
JNZ @@1
POP EDI
@Exit:
end;
{$ELSE !X86ASM}
var
i: Integer;
T: UInt32;
begin
for i := 0 to Count - 1 do
begin
T := TUInt32Array(Source)[i];
TUInt32Array(Dest)[i] := (T shl 24) or (T shr 24) or
((T shl 8) and $00FF0000) or ((T shr 8) and $0000FF00);
end;
end;
{$ENDIF !X86ASM}
function SwapInt64(Source: Int64): Int64;
{$IFDEF X86ASM}
asm
MOV EDX,Source.DWord[0]
MOV EAX,Source.DWord[4]
BSWAP EDX
BSWAP EAX
end;
{$ELSE !X86ASM}
var
L, H: Cardinal;
begin
L := Int64Rec(Source).Lo;
H := Int64Rec(Source).Hi;
L := L shl 24 or L shr 24 or L shl 8 and $00FF0000 or L shr 8 and $0000FF00;
H := H shl 24 or H shr 24 or H shl 8 and $00FF0000 or H shr 8 and $0000FF00;
Int64Rec(Result).Hi := L;
Int64Rec(Result).Lo := H;
end;
{$ENDIF !X86ASM}
procedure SwapInt64Buffer(const Source; var Dest; Count: Integer);
{$IFDEF X86ASM}
asm
TEST ECX,ECX
JLE @Exit
PUSH ESI
PUSH EDI
LEA ESI,[EAX + ECX * 8]
LEA EDI,[EDX + ECX * 8]
NEG ECX
@@1: MOV EAX,[ESI + ECX * 8]
MOV EDX,[ESI + ECX * 8 + 4]
BSWAP EAX
BSWAP EDX
MOV [EDI + ECX * 8 + 4],EAX
MOV [EDI + ECX * 8],EDX
INC ECX
JNZ @@1
POP EDI
POP ESI
@Exit:
end;
{$ELSE !X86ASM}
var
H, L: Cardinal;
i: Integer;
begin
for i := 0 to Count - 1 do
begin
H := TUInt32Array(Source)[i * 2 ];
L := TUInt32Array(Source)[i * 2 + 1];
TUInt32Array(Dest)[i * 2 ] := L shl 24 or L shr 24 or L shl 8 and $00FF0000 or L shr 8 and $0000FF00;
TUInt32Array(Dest)[i * 2 + 1] := H shl 24 or H shr 24 or H shl 8 and $00FF0000 or H shr 8 and $0000FF00;
end;
end;
{$ENDIF !X86ASM}
procedure XORBuffers(const Left, Right; Size: Integer; var Dest);
// Dest^ = Source1^ xor Source2^
// Buffers must have the same size!
{$IFDEF X86ASM}
asm
AND ECX,ECX
JZ @@5
PUSH ESI
PUSH EDI
MOV ESI,EAX
MOV EDI,Dest
@@1: TEST ECX,3
JNZ @@3
@@2: SUB ECX,4
JL @@4
MOV EAX,[ESI + ECX]
XOR EAX,[EDX + ECX]
MOV [EDI + ECX],EAX
JMP @@2
@@3: DEC ECX
MOV AL,[ESI + ECX]
XOR AL,[EDX + ECX]
MOV [EDI + ECX],AL
JMP @@1
@@4: POP EDI
POP ESI
@@5:
end;
{$ELSE !X86ASM}
var
P, Q, D: PByte;
i: Integer;
begin
P := @Left;
Q := @Right;
D := @Dest;
for i := 0 to Size - 1 do
begin
D^ := P^ xor Q^;
Inc(P);
Inc(Q);
Inc(D);
end;
end;
{$ENDIF !X86ASM}
const
WipeCount = 4;
WipeBytes: array[0..WipeCount - 1] of Byte = (
$55, // 0101 0101
$AA, // 1010 1010
$FF, // 1111 1111
$00 // 0000 0000
);
procedure ProtectBuffer(var Buffer; Size: NativeUInt);
var
Count: Integer;
begin
if Size > 0 then
begin
for Count := 0 to WipeCount - 1 do
FillChar(Buffer, Size, WipeBytes[Count]);
end;
end;
procedure ProtectStream(Stream: TStream; SizeToProtect: Int64 = 0);
const
BufferSize = 512;
var
Buffer: string;
Count, Bytes, Size: Integer;
Position: Integer;
begin
Position := Stream.Position;
Size := Stream.Size;
if SizeToProtect <= 0 then
begin
SizeToProtect := Size;
Position := 0;
end else
begin
Dec(Size, Position);
if SizeToProtect > Size then
SizeToProtect := Size;
end;
SetLength(Buffer, BufferSize);
for Count := 0 to WipeCount -1 do
begin
Stream.Position := Position;
Size := SizeToProtect;
{$IF CompilerVersion >= 24.0}
FillChar(Buffer[Low(Buffer)], BufferSize, WipeBytes[Count]);
{$ELSE}
FillChar(Buffer[1], BufferSize, WipeBytes[Count]);
{$IFEND}
while Size > 0 do
begin
Bytes := Size;
if Bytes > BufferSize then
Bytes := BufferSize;
{$IF CompilerVersion >= 24.0}
Stream.Write(Buffer[Low(Buffer)], Bytes);
{$ELSE}
Stream.Write(Buffer[1], Bytes);
{$IFEND}
Dec(Size, Bytes);
end;
end;
end;
procedure ProtectBytes(var Source: TBytes);
begin
if (Source <> nil) and (Length(Source) > 0) then
begin
ProtectBuffer(Source[0], Length(Source));
SetLength(Source, 0);
end;
end;
procedure ProtectString(var Source: string);
begin
if Length(Source) > 0 then
begin
System.UniqueString(Source);
{$IF CompilerVersion >= 24.0}
ProtectBuffer(Pointer(Source)^, Length(Source) * SizeOf(Source[Low(Source)]));
{$ELSE}
ProtectBuffer(Pointer(Source)^, Length(Source) * SizeOf(Source[1]));
{$IFEND}
Source := '';
end;
end;
procedure ProtectString(var Source: RawByteString);
begin
if Length(Source) > 0 then
begin
// UniqueString(Source); cannot be called with a RawByteString as there is
// no overload for it, so we need to call our own one.
DECUtilRawByteStringHelper.UniqueString(Source);
{$IF CompilerVersion >= 24.0}
ProtectBuffer(Pointer(Source)^, Length(Source) * SizeOf(Source[Low(Source)]));
{$ELSE}
ProtectBuffer(Pointer(Source)^, Length(Source) * SizeOf(Source[1]));
{$IFEND}
Source := '';
end;
end;
{$IFNDEF NEXTGEN}
procedure ProtectString(var Source: AnsiString); overload;
begin
if Length(Source) > 0 then
begin
System.UniqueString(Source);
{$IF CompilerVersion >= 24.0}
ProtectBuffer(Pointer(Source)^, Length(Source) * SizeOf(Source[Low(Source)]));
{$ELSE}
ProtectBuffer(Pointer(Source)^, Length(Source) * SizeOf(Source[1]));
{$IFEND}
Source := '';
end;
end;
procedure ProtectString(var Source: WideString); overload;
begin
if Length(Source) > 0 then
begin
System.UniqueString(Source); // for OS <> Win, WideString is not RefCounted on Win
{$IF CompilerVersion >= 24.0}
ProtectBuffer(Pointer(Source)^, Length(Source) * SizeOf(Source[Low(Source)]));
{$ELSE}
ProtectBuffer(Pointer(Source)^, Length(Source) * SizeOf(Source[1]));
{$IFEND}
Source := '';
end;
end;
{$ENDIF}
function BytesToRawString(const Source: TBytes): RawByteString;
begin
SetLength(Result, Length(Source));
if Length(Source) > 0 then
begin
// determine lowest string index for handling of ZeroBasedStrings
{$IF CompilerVersion >= 24.0}
Move(Source[0], Result[Low(result)], Length(Source));
{$ELSE}
Move(Source[0], Result[1], Length(Source));
{$IFEND}
end;
end;
{ EDECException }
{$IFDEF FMXTranslateableExceptions}
constructor EDECException.Create(const Msg: string);
begin
inherited Create(Translate(msg));
end;
constructor EDECException.CreateFmt(const Msg: string;
const Args: array of const);
begin
inherited Create(Format(Translate(Msg), Args));
end;
constructor EDECAbstractError.Create(ClassName: string);
begin
inherited Create(Format(Translate(sAbstractError), [ClassName]));
end;
{$ELSE}
constructor EDECAbstractError.Create(ClassName: string);
begin
inherited CreateResFmt(@sAbstractError, [ClassName]);
end;
{$ENDIF}
end.

View File

@@ -0,0 +1,137 @@
{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory of
this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
unit DECUtilRawByteStringHelper;
interface
{$INCLUDE DECOptions.inc}
/// <summary>
/// System.pas does not contain a RawByteString compatible version of this
/// routine so we created our own, copying and adapting code from system.pas
/// for the NextGen compiler and using a solution from Remy Lebeau for the
/// Win32/Win64 compiler.
/// </summary>
/// <param name="str">
/// String to be processed
/// </param>
procedure UniqueString(var Str: RawByteString);
implementation
uses
{$IFDEF FPC}
SysUtils;
{$ELSE}
System.SysUtils;
{$ENDIF}
type
// Duplicate of the System.pas internal declaration. Needs to be kept in sync.
PStrRec = ^StrRec;
StrRec = packed record
{$IFDEF CPU64BITS}
_Padding: Integer; // Make 16 byte align for payload..
{$ENDIF}
codePage: Word;
elemSize: Word;
refCnt: Integer;
length: Integer;
end;
function _NewAnsiString(CharLength: Integer; CodePage: Word): Pointer;
var
P: PStrRec;
begin
Result := nil;
if CharLength > 0 then
begin
// Alloc an extra null for strings with even length. This has no actual
// cost since the allocator will round up the request to an even size
// anyway. All _WideStr allocations have even length, and need a double
// null terminator.
if CharLength >= MaxInt - SizeOf(StrRec) then
raise EIntOverflow.Create(
'IntOverflow in _NewAnsiString. CharLength: ' + IntToStr(CharLength));
GetMem(P, CharLength + SizeOf(StrRec) + 1 + ((CharLength + 1) and 1));
Result := Pointer(PByte(P) + SizeOf(StrRec));
P.length := CharLength;
P.refcnt := 1;
if CodePage = 0 then
{$IFDEF NEXTGEN}
CodePage := Word(CP_UTF8);
{$ELSE NEXTGEN}
CodePage := Word(DefaultSystemCodePage);
{$ENDIF NEXTGEN}
P.codePage := CodePage;
P.elemSize := 1;
PWideChar(Result)[CharLength div 2] := #0; // length guaranteed >= 2
end;
end;
function _LStrClr(var S): Pointer;
var
P: PStrRec;
begin
if Pointer(S) <> nil then
begin
P := Pointer(PByte(S) - SizeOf(StrRec));
Pointer(S) := nil;
if P.refCnt > 0 then
begin
{$IFDEF FPC}
if InterlockedDecrement(P.refCnt) = 0 then
{$ELSE}
{$IF CompilerVersion >= 24.0}
if AtomicDecrement(P.refCnt) = 0 then
{$ELSE}
Dec(P.refCnt);
if (P.refCnt = 0) then
{$IFEND}
{$ENDIF}
FreeMem(P);
end;
end;
Result := @S;
end;
function InternalUniqueStringA(var Str: RawByteString): Pointer;
var
P: PStrRec;
begin
Result := Pointer(Str);
if Result <> nil then
begin
Result := Pointer(Str);
P := Pointer(PByte(Str) - sizeof(StrRec));
if P.refCnt <> 1 then
begin
Result := _NewAnsiString(P.length, P.codePage);
Move(Pointer(Str)^, Pointer(Result)^, P.length);
_LStrClr(Str);
Pointer(Str) := Result;
end;
end;
end;
procedure UniqueString(var Str: RawByteString);
begin
InternalUniqueStringA(Str);
end;
end.

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<nodeSet version="1.0">
<view uin="y77zdiaku6k_v">
<property name="$defaultDiagram" value="true" />
<property name="$metaclass" value="Package Diagram" />
<property name="$name" value="default" />
</view>
</nodeSet>

View File

@@ -0,0 +1,2 @@
<?xml version="1.0"?>
<TgConfig Version="3" SubLevelDisabled="False" />

View File

@@ -0,0 +1,24 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
<DCC_DcuOutput>.\..\..\Compiled\DCU_IDE$(ProductVersion)_$(Platform)__Demos</DCC_DcuOutput>
<DCC_ExeOutput>.\..\..\Compiled\BIN_IDExx.x_$(Platform)__Demos</DCC_ExeOutput>
<DCC_HppOutput>.\..\..\Compiled\DCP_IDE$(ProductVersion)_$(Platform)_$(Config)</DCC_HppOutput>
<DCC_ObjOutput>.\..\..\Compiled\DCU_IDE$(ProductVersion)_$(Platform)__Demos</DCC_ObjOutput>
<DCC_BpiOutput>.\..\..\Compiled\DCP_IDE$(ProductVersion)_$(Platform)_$(Config)</DCC_BpiOutput>
<DCC_UnitSearchPath>.\..\..\Compiled\DCU_IDE$(ProductVersion)_$(Platform)_$(Config);$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<DCC_BplOutput>.\..\..\Compiled\BIN_IDExx.x_$(Platform)__Demos</DCC_BplOutput>
<DCC_DcpOutput>.\..\..\Compiled\DCP_IDE$(ProductVersion)_$(Platform)_$(Config)</DCC_DcpOutput>
<VerInfo_Locale>1031</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<SanitizedProjectName></SanitizedProjectName>
</PropertyGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>OptionSet</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality/>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
</Project>

View File

@@ -0,0 +1,24 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
<DCC_DcuOutput>.\..\Compiled\DCU_IDE$(ProductVersion)_$(Platform)_$(Config)</DCC_DcuOutput>
<DCC_ExeOutput>.\..\Compiled\BIN_IDE$(ProductVersion)_$(Platform)_$(Config)</DCC_ExeOutput>
<DCC_HppOutput>.\..\Compiled\DCP_IDE$(ProductVersion)_$(Platform)_$(Config)</DCC_HppOutput>
<DCC_ObjOutput>.\..\Compiled\DCU_IDE$(ProductVersion)_$(Platform)_$(Config)</DCC_ObjOutput>
<DCC_BpiOutput>.\..\Compiled\DCP_IDE$(ProductVersion)_$(Platform)_$(Config)</DCC_BpiOutput>
<DCC_UnitSearchPath>.\..\Compiled\DCU_IDE$(ProductVersion)_$(Platform)_$(Config);$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<DCC_BplOutput>.\..\Compiled\BIN_IDE$(ProductVersion)_$(Platform)_$(Config)</DCC_BplOutput>
<DCC_DcpOutput>.\..\Compiled\DCP_IDE$(ProductVersion)_$(Platform)_$(Config)</DCC_DcpOutput>
<VerInfo_Locale>1031</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<SanitizedProjectName>DEC60</SanitizedProjectName>
</PropertyGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>OptionSet</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality/>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
</Project>

View File

@@ -0,0 +1,24 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
<DCC_DcuOutput>.\..\Compiled\DCU_IDE$(ProductVersion)_$(Platform)__Demos</DCC_DcuOutput>
<DCC_ExeOutput>.\..\Compiled\BIN_IDE$(ProductVersion)_$(Platform)_$(Config)</DCC_ExeOutput>
<DCC_HppOutput>.\..\Compiled\DCP_IDE$(ProductVersion)_$(Platform)_$(Config)</DCC_HppOutput>
<DCC_ObjOutput>.\..\Compiled\DCU_IDE$(ProductVersion)_$(Platform)__Demos</DCC_ObjOutput>
<DCC_BpiOutput>.\..\Compiled\DCP_IDE$(ProductVersion)_$(Platform)_$(Config)</DCC_BpiOutput>
<DCC_UnitSearchPath>.\..\Compiled\DCU_IDE$(ProductVersion)_$(Platform)_$(Config);.\..\Compiled\DCU_IDE$(ProductVersion)_$(Platform)_Debug;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
<DCC_BplOutput>.\..\Compiled\BIN_IDE$(ProductVersion)_$(Platform)_$(Config)</DCC_BplOutput>
<DCC_DcpOutput>.\..\Compiled\DCP_IDE$(ProductVersion)_$(Platform)_$(Config)</DCC_DcpOutput>
<VerInfo_Locale>1031</VerInfo_Locale>
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<SanitizedProjectName>DECDUnitTestSuite</SanitizedProjectName>
</PropertyGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>OptionSet</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality/>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
</Project>