diff --git a/.gitignore b/.gitignore index 5409da96..018829f9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,170 @@ -/Compiled -/Source/BuildAll.log +############################################################################### +# Delphi .gitignore (Curated) +# --------------------------------------------------------------------------- +# IMPORTANT: This file must be renamed to ".gitignore" (without .txt extension)! +# +# This carefully curated .gitignore file is specifically optimized for +# Embarcadero Delphi development environments, supporting both legacy and +# modern versions. +# +# USAGE: +# 1. Copy this file to the root directory of your Git repository +# 2. Rename from "Delphi GitIgnore.txt" to ".gitignore" +# 3. Make project-specific adjustments if needed +# +# This file ignores: +# - Compiler and build output (e.g., .dcu, .exe, .dll) +# - IDE-generated metadata and user-specific files (.dsk, .local) +# - Backup and recovery files +# - Platform-specific output directories +# - Known version control systems and Delphi-specific tools +# +# License: MIT License https://opensource.org/license/mit +# Version: 2.0 (keep in sync with Style Guide headers) -backup -__history -__recovery -**/Android/ -**/Android64/ -**/Win32/ -**/Win64/ +# +# Copyright (c) 2025-2026 Olaf Monien +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this file to use without restriction, subject to inclusion of this notice. +############################################################################### + + +# Resource files are binaries containing manifest, project icon and version info. +# They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. +# DEC: intentionally ignored — VersionInfo/icon come from the .dproj and are regenerated by the IDE. +*.res + +# Type library file (binary). In old Delphi versions it should be stored. +# Since Delphi 2009 it is produced from .ridl file and can safely be ignored. +*.tlb + +# Diagram Portfolio file. Used by the diagram editor up to Delphi 7. +# Uncomment this if you are not using diagrams or use newer Delphi version. +*.ddp + +# Delphi compiler-generated binaries (safe to delete) +*.exe +*.dll +*.bpl +*.bpi +*.dcp +*.so +*.apk +*.drc +*.map +*.dres +*.rsm +*.tds +*.dcu +*.lib +*.a +*.o +*.ocx +# Delphi autogenerated files (duplicated info) +*.cfg +*.hpp +*Resource.rc + +# Delphi local files (user-specific info) *.local *.identcache +*.projdata +*.tvsconfig *.dsk +*.user +*.dsv + +# Delphi history and backups +__history/ +__recovery/ *.~* +*.save +*.cbk + +# Castalia statistics file (since XE7 Castalia is distributed with Delphi) *.stat + +# default Debug and Release directories contain binaries only +Release/ +Debug/ +DCU/ + +# Default Platform output directories +Linux64/ +OSX32/ +OSX64/ +Win32/ +Win64/ +Android/ +Android32/ +Android64/ +iOSDevice32/ +iOSDevice64/ +iOSSimARM64/ +iOSSimulator/ + +# Windows-Artefakte Thumbs.db +desktop.ini +# TMS Web Core +TMSWeb/ -*.dsv +# npm dependencies +node_modules/ + +# other SCM/versioning files +.hg/ +.svn/ + +# Boss dependency manager vendor folder https://github.com/HashLoad/boss +modules/ + +# Misc (macOS and other artifacts) +.DS_Store +~$*.* + +# Custom build directories +_Release-Binaries +Build/bin/ + + +# Gnu Global / VSCode Pascal editing +GPATH +GRTAGS +GTAGS + +# VSCode +.vscode/* +!.vscode/settings.json +!.vscode/extensions.json +!.vscode/tasks.json +!.vscode/launch.json + +# FinalBuilder +*.fbpInf # Project info cache +*.fbl8 # Log files +*.fbpbrk # Breakpoints +*.fb8lck # Lock files + +# Claude Code local settings +.claude/settings.local.json +.claude/worktrees/ + +############################################################################### +# Project-specific (DEC) +############################################################################### + +# Local build / tooling output +/Compiled +/Source/BuildAll.log +backup + +# CodeGraph local index (machine-specific) +.codegraph/ + +# Together / modelling leftovers (IDE modelling removed; see docs §3.7.10 history). +# Already-tracked files stay in the repo until a separate "git rm --cached" cleanup. +*.txaPackage +*.txvpck diff --git a/Demos/Cipher_Blockmodes/CipherBlockModesVCL.dpr b/Demos/Cipher_Blockmodes/CipherBlockModesVCL.dpr new file mode 100644 index 00000000..c39ff208 --- /dev/null +++ b/Demos/Cipher_Blockmodes/CipherBlockModesVCL.dpr @@ -0,0 +1,14 @@ +program CipherBlockModesVCL; + +uses + Vcl.Forms, + MainFormCipherBlockmodesVCL in 'MainFormCipherBlockmodesVCL.pas' {FormMain}; + +{$R *.res} + +begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TFormMain, FormMain); + Application.Run; +end. diff --git a/Demos/Cipher_Blockmodes/CipherBlockModesVCL.dproj b/Demos/Cipher_Blockmodes/CipherBlockModesVCL.dproj new file mode 100644 index 00000000..3ba8157d --- /dev/null +++ b/Demos/Cipher_Blockmodes/CipherBlockModesVCL.dproj @@ -0,0 +1,1164 @@ + + + {E4A48F6F-A360-48CB-81A5-C985D910DACC} + 20.4 + VCL + True + Debug + Win32 + CipherBlockModesVCL + 2097155 + Application + CipherBlockModesVCL.dpr + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + $(BDS)\bin\delphi_PROJECTICON.ico + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + CipherBlockModesVCL + + + FireDACIBDriver;JvNet;vclwinx;DataSnapServer;fmx;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;frControlsLibrary37;IndyProtocols;vclx;Skia.Package.RTL;MakerAI;dbxcds;vcledge;FmxTeeUI;DBXFirebirdDriver;JvAppFrm;FireDACSqliteDriver;DbxClientDriver;JclVcl;soapmidas;TeeUI;Jcl;dbexpress;JvManagedThreads;MakerAiDsg;inet;vcltouch;JvDB;FireDACDBXDriver;fmxdae;JvCustom;CustomIPTransport;FireDACMSSQLDriver;JvSystem;JvControls;FMXfrCoreLibrary37;JvCrypt;JvJans;JvMM;IndySystem;frx37;JvGlobus;VirtualTreesR;JclContainers;JvPageComps;vclFireDAC;MakerAi.RAG.Drivers;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;DOSCommandDR;bindcompdbx;rtl;FireDACMySQLDriver;DBXSqliteDriver;frxe37;DBXSybaseASEDriver;JvRuntimeDesign;JvXPCtrls;vclimg;DataSnapFireDAC;inetdbxpress;FireDAC;JvDocking;JvDlgs;xmlrtl;dsnap;JvCmp;FireDACDb2Driver;DBXOracleDriver;DBXInformixDriver;fmxobj;bindcompvclsmp;DataSnapNativeClient;DatasnapConnectorsFreePascal;frxDB37;emshosting;FireDACCommonDriver;frCoreLibrary37;IndyIPClient;bindcompvclwinx;emsedge;bindcompfmx;JvBands;inetdb;FireDACASADriver;Tee;vclactnband;fmxFireDAC;FireDACInfxDriver;DBXMySQLDriver;VclSmp;DataSnapCommon;JvPascalInterpreter;fmxase;JvPluginSystem;FMXfrx37;DBXOdbcDriver;JvTimeFramework;dbrtl;MakerAi.UI;FireDACOracleDriver;Skia.Package.FMX;CodeSiteExpressPkg;TeeDB;frLocalizationLibrary37;FireDACMSAccDriver;DataSnapIndy10ServerTransport;JclDeveloperTools;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;JvWizards;FMXfrxDB37;FireDACTDataDriver;Skia.Package.VCL;vcldb;JvCore;bindcomp;inetstn;IndyCore;RESTBackendComponents;FireDACADSDriver;RaizeComponentsVclDb;RESTComponents;IndyIPServer;vcl;dsnapxml;adortl;dsnapcon;DataSnapClient;DataSnapProviderClient;frGraphicsLibrary37;JvDotNetCtrls;JvHMI;DBXDb2Driver;emsclientfiredac;FireDACPgDriver;FireDACDSDriver;FMXfrLocalizationLibrary37;JvPrintPreview;tethering;JvStdCtrls;bindcompvcl;CloudService;DBXSybaseASADriver;FMXTee;soaprtl;RaizeComponentsVcl;soapserver;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + $(BDS)\bin\default_app.manifest + + + FireDACIBDriver;vclwinx;DataSnapServer;fmx;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;IndyProtocols;vclx;MakerAI;dbxcds;vcledge;FmxTeeUI;DBXFirebirdDriver;FireDACSqliteDriver;DbxClientDriver;soapmidas;TeeUI;dbexpress;MakerAiDsg;inet;vcltouch;FireDACDBXDriver;fmxdae;CustomIPTransport;FireDACMSSQLDriver;IndySystem;VirtualTreesR;vclFireDAC;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;DOSCommandDR;bindcompdbx;rtl;FireDACMySQLDriver;DBXSqliteDriver;DBXSybaseASEDriver;vclimg;DataSnapFireDAC;inetdbxpress;FireDAC;xmlrtl;dsnap;FireDACDb2Driver;DBXOracleDriver;DBXInformixDriver;fmxobj;bindcompvclsmp;DataSnapNativeClient;DatasnapConnectorsFreePascal;emshosting;FireDACCommonDriver;IndyIPClient;bindcompvclwinx;emsedge;bindcompfmx;inetdb;FireDACASADriver;Tee;vclactnband;fmxFireDAC;FireDACInfxDriver;DBXMySQLDriver;VclSmp;DataSnapCommon;fmxase;DBXOdbcDriver;dbrtl;MakerAi.UI;FireDACOracleDriver;TeeDB;FireDACMSAccDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;FireDACTDataDriver;Skia.Package.VCL;vcldb;bindcomp;inetstn;IndyCore;RESTBackendComponents;FireDACADSDriver;RaizeComponentsVclDb;RESTComponents;IndyIPServer;vcl;dsnapxml;adortl;dsnapcon;DataSnapClient;DataSnapProviderClient;DBXDb2Driver;emsclientfiredac;FireDACPgDriver;FireDACDSDriver;tethering;bindcompvcl;CloudService;DBXSybaseASADriver;FMXTee;soaprtl;RaizeComponentsVcl;soapserver;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + $(BDS)\bin\default_app.manifest + + + FireDACIBDriver;vclwinx;DataSnapServer;fmx;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;IndyProtocols;vclx;dbxcds;vcledge;FmxTeeUI;DBXFirebirdDriver;FireDACSqliteDriver;DbxClientDriver;soapmidas;TeeUI;dbexpress;inet;vcltouch;FireDACDBXDriver;fmxdae;CustomIPTransport;FireDACMSSQLDriver;IndySystem;vclFireDAC;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;bindcompdbx;rtl;FireDACMySQLDriver;DBXSqliteDriver;DBXSybaseASEDriver;vclimg;DataSnapFireDAC;inetdbxpress;FireDAC;xmlrtl;dsnap;FireDACDb2Driver;DBXOracleDriver;DBXInformixDriver;fmxobj;bindcompvclsmp;DataSnapNativeClient;DatasnapConnectorsFreePascal;emshosting;FireDACCommonDriver;IndyIPClient;bindcompvclwinx;emsedge;bindcompfmx;inetdb;FireDACASADriver;Tee;vclactnband;fmxFireDAC;FireDACInfxDriver;DBXMySQLDriver;VclSmp;DataSnapCommon;fmxase;DBXOdbcDriver;dbrtl;FireDACOracleDriver;TeeDB;FireDACMSAccDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;FireDACTDataDriver;Skia.Package.VCL;vcldb;bindcomp;inetstn;IndyCore;RESTBackendComponents;FireDACADSDriver;RaizeComponentsVclDb;RESTComponents;IndyIPServer;vcl;dsnapxml;adortl;dsnapcon;DataSnapClient;DataSnapProviderClient;DBXDb2Driver;emsclientfiredac;FireDACPgDriver;FireDACDSDriver;tethering;bindcompvcl;CloudService;DBXSybaseASADriver;FMXTee;soaprtl;RaizeComponentsVcl;soapserver;$(DCC_UsePackage) + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + $(BDS)\bin\default_app.manifest + + + DEBUG;$(DCC_Define) + true + false + true + true + true + true + true + + + false + PerMonitorV2 + + + PerMonitorV2 + + + PerMonitorV2 + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + PerMonitorV2 + + + PerMonitorV2 + + + PerMonitorV2 + + + + MainSource + + +
FormMain
+ dfm +
+ + Base + + + Cfg_1 + Base + + + Cfg_2 + Base + +
+ + Delphi.Personality.12 + Application + + + + CipherBlockModesVCL.dpr + + + + + + CipherBlockModesVCL.exe + true + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-anydpi-v21 + 1 + + + res\drawable-anydpi-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values-v31 + 1 + + + res\values-v31 + 1 + + + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + + + + res\drawable-anydpi-v26 + 1 + + + res\drawable-anydpi-v26 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-anydpi-v33 + 1 + + + res\drawable-anydpi-v33 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-night-v21 + 1 + + + res\values-night-v21 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable-anydpi-v24 + 1 + + + res\drawable-anydpi-v24 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-night-anydpi-v21 + 1 + + + res\drawable-night-anydpi-v21 + 1 + + + + + res\drawable-anydpi-v31 + 1 + + + res\drawable-anydpi-v31 + 1 + + + + + res\drawable-night-anydpi-v31 + 1 + + + res\drawable-night-anydpi-v31 + 1 + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + Contents\MacOS + 1 + .framework + + + Contents\MacOS + 1 + .framework + + + Contents\MacOS + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + Contents\Resources\StartUp\ + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + ..\ + 1 + + + + + Contents + 1 + + + Contents + 1 + + + Contents + 1 + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).launchscreen + 64 + + + ..\$(PROJECTNAME).launchscreen + 64 + + + + + 1 + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + Assets + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + + + + + + + + + + + + + + True + True + True + + + 12 + + + + +
diff --git a/Demos/Cipher_Blockmodes/CipherBlockModesVCL.res b/Demos/Cipher_Blockmodes/CipherBlockModesVCL.res new file mode 100644 index 00000000..80edd2c3 Binary files /dev/null and b/Demos/Cipher_Blockmodes/CipherBlockModesVCL.res differ diff --git a/Demos/Cipher_Blockmodes/MainFormCipherBlockmodesVCL.dfm b/Demos/Cipher_Blockmodes/MainFormCipherBlockmodesVCL.dfm new file mode 100644 index 00000000..87c21724 --- /dev/null +++ b/Demos/Cipher_Blockmodes/MainFormCipherBlockmodesVCL.dfm @@ -0,0 +1,172 @@ +object FormMain: TFormMain + Left = 0 + Top = 0 + Caption = 'Cipher block modes demo' + ClientHeight = 463 + ClientWidth = 873 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -12 + Font.Name = 'Segoe UI' + Font.Style = [] + TextHeight = 15 + object p_Main: TPanel + Left = 0 + Top = 33 + Width = 873 + Height = 430 + Align = alClient + BevelOuter = bvNone + TabOrder = 0 + ExplicitWidth = 800 + ExplicitHeight = 429 + object Splitter_Main: TSplitter + Left = 329 + Top = 0 + Height = 430 + Beveled = True + end + object p_Left: TPanel + Left = 0 + Top = 0 + Width = 329 + Height = 430 + Align = alLeft + BevelOuter = bvNone + TabOrder = 0 + ExplicitHeight = 429 + object Label1: TLabel + Left = 0 + Top = 408 + Width = 329 + Height = 22 + Align = alBottom + Alignment = taCenter + AutoSize = False + Caption = 'Original image' + end + object i_Original: TImage + Left = 0 + Top = 0 + Width = 329 + Height = 408 + Align = alClient + Proportional = True + Stretch = True + end + end + object p_Right: TPanel + Left = 332 + Top = 0 + Width = 541 + Height = 430 + Align = alClient + BevelOuter = bvNone + TabOrder = 1 + ExplicitWidth = 468 + ExplicitHeight = 429 + object Label2: TLabel + Left = 0 + Top = 408 + Width = 541 + Height = 22 + Align = alBottom + Alignment = taCenter + AutoSize = False + Caption = 'Encrypted image' + ExplicitWidth = 468 + end + object i_Encrypted: TImage + Left = 0 + Top = 0 + Width = 541 + Height = 408 + Align = alClient + Proportional = True + Stretch = True + ExplicitWidth = 468 + end + end + end + object p_Top: TPanel + Left = 0 + Top = 0 + Width = 873 + Height = 33 + Align = alTop + BevelOuter = bvNone + TabOrder = 1 + ExplicitLeft = 8 + ExplicitTop = 8 + ExplicitWidth = 800 + object Label3: TLabel + Left = 320 + Top = 12 + Width = 34 + Height = 15 + Caption = 'Mode:' + end + object Label4: TLabel + Left = 536 + Top = 12 + Width = 56 + Height = 15 + Caption = 'Init vector:' + end + object b_LoadImage: TButton + Left = 0 + Top = 5 + Width = 145 + Height = 25 + Caption = '&Load image' + TabOrder = 0 + OnClick = b_LoadImageClick + end + object b_EncryptImage: TButton + Left = 151 + Top = 5 + Width = 145 + Height = 25 + Caption = '&Encrypt image' + TabOrder = 1 + OnClick = b_EncryptImageClick + end + object cb_Mode: TComboBox + Left = 368 + Top = 6 + Width = 145 + Height = 23 + Style = csDropDownList + DropDownCount = 9 + ItemIndex = 0 + TabOrder = 2 + Text = 'ECB' + Items.Strings = ( + 'ECB' + 'CBC' + 'CTSx' + 'CFB8' + 'CFBx' + 'OFB8' + 'OFBx' + 'CFS8' + 'CFSx') + end + object tf_InitVector: TEdit + Left = 598 + Top = 6 + Width = 179 + Height = 23 + TabOrder = 3 + Text = 'PickANewOne' + end + end + object OpenPictureDialog: TOpenPictureDialog + Filter = 'Bitmaps (*.bmp)|*.bmp' + Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing] + Title = 'Load image' + Left = 112 + Top = 129 + end +end diff --git a/Demos/Cipher_Blockmodes/MainFormCipherBlockmodesVCL.pas b/Demos/Cipher_Blockmodes/MainFormCipherBlockmodesVCL.pas new file mode 100644 index 00000000..9a0aea59 --- /dev/null +++ b/Demos/Cipher_Blockmodes/MainFormCipherBlockmodesVCL.pas @@ -0,0 +1,345 @@ +{***************************************************************************** + 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. +*****************************************************************************} + +/// +/// Demo showing graphically why block modes for block ciphers are essential +/// and why ECB-mode should not be used +/// +unit MainFormCipherBlockmodesVCL; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, + Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, + Vcl.ExtDlgs, DECCipherBase; + +type + /// + /// Structure for one single 24-bit pixel (Windows default is BGR) + /// + TRGBTriple = packed record + rgbtBlue: Byte; + rgbtGreen: Byte; + rgbtRed: Byte; + end; + + PRGBTripleArray = ^TRGBTripleArray; + TRGBTripleArray = array[0..32767] of TRGBTriple; + + TByteArray = TArray; + + TFormMain = class(TForm) + OpenPictureDialog: TOpenPictureDialog; + p_Main: TPanel; + Splitter_Main: TSplitter; + p_Left: TPanel; + Label1: TLabel; + i_Original: TImage; + p_Right: TPanel; + Label2: TLabel; + i_Encrypted: TImage; + p_Top: TPanel; + Label3: TLabel; + Label4: TLabel; + b_LoadImage: TButton; + b_EncryptImage: TButton; + cb_Mode: TComboBox; + tf_InitVector: TEdit; + procedure b_EncryptImageClick(Sender: TObject); + procedure b_LoadImageClick(Sender: TObject); + private + /// + /// Convert the contents of the bitmap into an array we can work with + /// + /// + /// Bitmap to convert + /// + /// + /// In this array the data will be stored. + /// + procedure ScanlineToArray(src: TBitmap; var arr: TByteArray); + /// + /// Creates a bitmap from the data of the passed array + /// + /// + /// Array with pixeldata which shall be transformed into a bitmap + /// + /// + /// Width in pixel the resulting bitmap shall have + /// + /// + /// Height in pixel the resulting bitmap shall have + /// + /// + /// Bitmap into which the pixel data shall be written + /// + procedure ByteArrayToBitmap(const ByteArray: TByteArray; + Width, Height: Integer; + var Bitmap: TBitmap); + /// + /// Calculate the size of the target bitmap so that it is a multiple of + /// the blocksize of the cipher algorithm. If necessary further lines will + /// be added (height extension). + /// + /// + /// Bitmap from which the size for the target bitmap is being determined + /// + /// + /// Block size in bytes. The resulting bitmap must be a multiple of that + /// in size + /// + function CalculateBlockedBitmapSize(SrcBitmap: TBitmap; + BlockSize: Integer): TPoint; + /// + /// Encrypts the data of the passed bitmap + /// + /// + /// Bitmap to encrypt + /// + /// + /// Block concatenation/chaining mode + /// + /// + /// Initialization vector + /// + /// + /// Encrypted bitmap + /// + function DemoEncodeBitmap(SrcBitmap: TBitmap; + Mode: TCipherMode; + IV: RawByteString): TBitmap; + /// + /// Returns the selected block chaining/concatenation mode + /// + function SelectedModeToEnum: TCipherMode; + public + end; + +var + FormMain: TFormMain; + +implementation + +uses + System.Types, + DecCiphers; + +{$R *.dfm} + +procedure TFormMain.b_EncryptImageClick(Sender: TObject); +var + bmp : TBitmap; +begin + bmp := DemoEncodeBitmap(i_Original.Picture.Bitmap, + SelectedModeToEnum, + RawByteString(tf_InitVector.Text)); + + if assigned(bmp) then + begin + i_Encrypted.Picture.Bitmap.Assign(bmp); + bmp.free; + end; +end; + +procedure TFormMain.b_LoadImageClick(Sender: TObject); +begin + if OpenPictureDialog.Execute then + i_Original.Picture.LoadFromFile(OpenPictureDialog.FileName); +end; + +procedure TFormMain.ScanlineToArray(src:TBitmap; var arr:TByteArray); +var + X, Y : Integer; + Line : PRGBTripleArray; + ByteIndex : Integer; + BytesPerPixel : Integer; +begin + Assert(Assigned(src), 'No bitmap passed!'); + + // In this example we assume 24-Bit format + src.PixelFormat := pf24bit; + BytesPerPixel := SizeOf(TRGBTriple); + + // define arrow size: width * height * 3 byte (RGB) + SetLength(arr, src.Width * src.Height * BytesPerPixel); + + ByteIndex := 0; + + for Y := 0 to src.Height - 1 do + begin + // Fetch pointer to the beginning of the scanline + Line := src.ScanLine[Y]; + + for X := 0 to src.Width - 1 do + begin + // Read nout values from the bitmap and write them into the array + arr[ByteIndex] := Line[X].rgbtRed; // R + arr[ByteIndex + 1] := Line[X].rgbtGreen; // G + arr[ByteIndex + 2] := Line[X].rgbtBlue; // B + + Inc(ByteIndex, BytesPerPixel); + end; + end; +end; + +function TFormMain.CalculateBlockedBitmapSize(SrcBitmap: TBitmap; BlockSize: Integer): TPoint; +var + SrcBytes : Int64; // Size of the source bitmap in bytes based on byte per pixel + PixelByteSize : Byte; // Bytes for one pixel according to pixel format (here: RGB) + ScM, // smallest common multiple of PixelByteSize and BlockSize + PxBlockCount : Integer; + ModuloResult : Integer; + LineSizeBytes : Integer; // Number of bytes one bitmap line occupies + Height : Integer; +begin + Assert(Assigned(SrcBitmap), 'No bitmap passed!'); + + // Pixel format pf24Bit = 3 byte per pixel + PixelByteSize := 3; + ScM := BlockSize * PixelByteSize; // Smallest common multiple of block size + // and 1 pixel — i.e., how many bytes we need + // so that all bytes of the pixels can be + // accommodated. + // With a block size of 16 and 3 bytes per pixel, + // you need 3 blocks = 48 bytes so that no pixel’s + // bytes “stick out” and all blocks are completely + // filled with whole pixels. + + // size of the source bitmap in byte + SrcBytes := (SrcBitmap.Width * SrcBitmap.Height) * PixelByteSize; + + // How many complete pixel blocks fit into the bitmap (in bytes) + PxBlockCount := (SrcBytes Div ScM); + + // By how much do you need to increase the number of blocks until you have at + // least the number of bytes required by the bitmap? + ModuloResult := (SrcBytes MOD (ScM * PxBlockCount)); + + // If it doesn't exactly fit? + if (ModuloResult <> 0) then + begin + // Number of bytes one line of the bitmap needs + LineSizeBytes := SrcBitmap.Width * PixelByteSize; + + Height := SrcBitmap.Height; + + // add further lines until we have a multiple of the pixel block size bytes + repeat + inc(Height); + inc(SrcBytes, LineSizeBytes); + until ((SrcBytes mod ScM) = 0); + end + else + Height := SrcBitmap.Height; + + Result.X := SrcBitmap.Width; + Result.Y := Height; +end; + +procedure TFormMain.ByteArrayToBitmap(const ByteArray: TByteArray; + Width, Height: Integer; + var Bitmap: TBitmap); +var + X, Y : Integer; + Line : PRGBTripleArray; + ByteIndex : Integer; + BytesPerPixel : Integer; +begin + Assert(Assigned(ByteArray), 'No initialized source array passed!'); + Assert(Assigned(Bitmap), 'No bitmap passed!'); + + // initialize image dimensions and format + Bitmap.PixelFormat := pf24bit; + Bitmap.Width := Width; + Bitmap.Height := Height; + + BytesPerPixel := SizeOf(TRGBTriple); + ByteIndex := 0; + + // Safety check: Are the bytes in the array sufficient for this image size? + if Length(ByteArray) < (Width * Height * BytesPerPixel) then + raise Exception.Create('Failure: the byte array is too small for the image dimensions given.'); + + for Y := 0 to Height - 1 do + begin + // Get a pointer to the target line of the bitmap + Line := Bitmap.ScanLine[Y]; + + for X := 0 to Width - 1 do + begin + // Read values from the byte array and write those into the scanline + Line[X].rgbtRed := ByteArray[ByteIndex]; // R + Line[X].rgbtGreen := ByteArray[ByteIndex + 1]; // G + Line[X].rgbtBlue := ByteArray[ByteIndex + 2]; // B + + Inc(ByteIndex, BytesPerPixel); + end; + end; +end; + +function TFormMain.SelectedModeToEnum: TCipherMode; +begin + Result := cmECBx; + + case cb_Mode.ItemIndex of + 0 : Result := cmECBx; + 1 : Result := cmCBCx; + 2 : Result := cmCTSx; + 3 : Result := cmCFB8; + 4 : Result := cmCFBx; + 5 : Result := cmOFB8; + 6 : Result := cmOFBx; + 7 : Result := cmCFS8; + 8 : Result := cmCFSx; + end; +end; + +function TFormMain.DemoEncodeBitmap(SrcBitmap:TBitmap; + Mode: TCipherMode; + IV: RawByteString):TBitmap; +var + DstSize : TPoint; + Cipher : TCipher_AES128; + SrcBytes, + DstBytes : TByteArray; + SrcHeight : Integer; +begin + Cipher := TCipher_AES128.Create; + try + Cipher.init(RawByteString('PascalSalamanca!'), IV, 32); + Cipher.Mode := Mode; + + SrcHeight := SrcBitmap.Height; + DstSize := CalculateBlockedBitmapSize(SrcBitmap, Cipher.Context.BlockSize); + + // is the new calculated height bigger than the original one? + if (DstSize.Y > SrcHeight) then + // Enlarge bitmap + SrcBitmap.Height := DstSize.Y; + + ScanlineToArray(SrcBitmap, SrcBytes); + + DstBytes := Cipher.EncodeBytes(SrcBytes); + finally + Cipher.Free; + end; + Result := TBitmap.Create; + ByteArrayToBitmap(DstBytes, DstSize.x, DstSize.y, Result); +end; + +end. diff --git a/Demos/Cipher_Console/Cipher_Console.dproj b/Demos/Cipher_Console/Cipher_Console.dproj index d4473def..bf5d14ad 100644 --- a/Demos/Cipher_Console/Cipher_Console.dproj +++ b/Demos/Cipher_Console/Cipher_Console.dproj @@ -1,7 +1,7 @@  {BC13B21E-5E59-450C-A11D-EA58C8E05628} - 20.2 + 20.4 None Cipher_Console.dpr True @@ -14,6 +14,16 @@ true + + true + Base + true + + + true + Base + true + true Base @@ -53,6 +63,12 @@ CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= Cipher_Console + + activity-1.7.2.dex.jar;annotation-experimental-1.4.1.dex.jar;annotation-jvm-1.8.1.dex.jar;annotations-13.0.dex.jar;appcompat-1.2.0.dex.jar;appcompat-resources-1.2.0.dex.jar;billing-7.1.1.dex.jar;biometric-1.1.0.dex.jar;browser-1.4.0.dex.jar;cloud-messaging.dex.jar;collection-jvm-1.4.2.dex.jar;concurrent-futures-1.1.0.dex.jar;core-1.15.0.dex.jar;core-common-2.2.0.dex.jar;core-ktx-1.15.0.dex.jar;core-runtime-2.2.0.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;error_prone_annotations-2.9.0.dex.jar;exifinterface-1.3.6.dex.jar;firebase-annotations-16.2.0.dex.jar;firebase-common-20.3.1.dex.jar;firebase-components-17.1.0.dex.jar;firebase-datatransport-18.1.7.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-encoders-proto-16.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.1.3.dex.jar;firebase-installations-interop-17.1.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-23.1.2.dex.jar;fmx.dex.jar;fragment-1.2.5.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;kotlin-stdlib-1.8.22.dex.jar;kotlin-stdlib-common-1.8.22.dex.jar;kotlin-stdlib-jdk7-1.8.22.dex.jar;kotlin-stdlib-jdk8-1.8.22.dex.jar;kotlinx-coroutines-android-1.6.4.dex.jar;kotlinx-coroutines-core-jvm-1.6.4.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.6.2.dex.jar;lifecycle-livedata-2.6.2.dex.jar;lifecycle-livedata-core-2.6.2.dex.jar;lifecycle-runtime-2.6.2.dex.jar;lifecycle-service-2.6.2.dex.jar;lifecycle-viewmodel-2.6.2.dex.jar;lifecycle-viewmodel-savedstate-2.6.2.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;okio-jvm-3.4.0.dex.jar;play-services-ads-22.2.0.dex.jar;play-services-ads-base-22.2.0.dex.jar;play-services-ads-identifier-18.0.0.dex.jar;play-services-ads-lite-22.2.0.dex.jar;play-services-appset-16.0.1.dex.jar;play-services-base-18.5.0.dex.jar;play-services-basement-18.4.0.dex.jar;play-services-cloud-messaging-17.0.1.dex.jar;play-services-location-21.0.1.dex.jar;play-services-maps-18.1.0.dex.jar;play-services-measurement-base-20.1.2.dex.jar;play-services-measurement-sdk-api-20.1.2.dex.jar;play-services-stats-17.0.2.dex.jar;play-services-tasks-18.2.0.dex.jar;print-1.0.0.dex.jar;profileinstaller-1.3.0.dex.jar;room-common-2.2.5.dex.jar;room-runtime-2.2.5.dex.jar;savedstate-1.2.1.dex.jar;sqlite-2.1.0.dex.jar;sqlite-framework-2.1.0.dex.jar;startup-runtime-1.1.1.dex.jar;tracing-1.2.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.1.8.dex.jar;transport-runtime-3.1.8.dex.jar;user-messaging-platform-2.0.0.dex.jar;vectordrawable-1.1.0.dex.jar;vectordrawable-animated-1.1.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.7.0.dex.jar + + + activity-1.7.2.dex.jar;annotation-experimental-1.4.1.dex.jar;annotation-jvm-1.8.1.dex.jar;annotations-13.0.dex.jar;appcompat-1.2.0.dex.jar;appcompat-resources-1.2.0.dex.jar;billing-7.1.1.dex.jar;biometric-1.1.0.dex.jar;browser-1.4.0.dex.jar;cloud-messaging.dex.jar;collection-jvm-1.4.2.dex.jar;concurrent-futures-1.1.0.dex.jar;core-1.15.0.dex.jar;core-common-2.2.0.dex.jar;core-ktx-1.15.0.dex.jar;core-runtime-2.2.0.dex.jar;cursoradapter-1.0.0.dex.jar;customview-1.0.0.dex.jar;documentfile-1.0.0.dex.jar;drawerlayout-1.0.0.dex.jar;error_prone_annotations-2.9.0.dex.jar;exifinterface-1.3.6.dex.jar;firebase-annotations-16.2.0.dex.jar;firebase-common-20.3.1.dex.jar;firebase-components-17.1.0.dex.jar;firebase-datatransport-18.1.7.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-encoders-proto-16.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.1.3.dex.jar;firebase-installations-interop-17.1.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-23.1.2.dex.jar;fmx.dex.jar;fragment-1.2.5.dex.jar;google-play-licensing.dex.jar;interpolator-1.0.0.dex.jar;javax.inject-1.dex.jar;kotlin-stdlib-1.8.22.dex.jar;kotlin-stdlib-common-1.8.22.dex.jar;kotlin-stdlib-jdk7-1.8.22.dex.jar;kotlin-stdlib-jdk8-1.8.22.dex.jar;kotlinx-coroutines-android-1.6.4.dex.jar;kotlinx-coroutines-core-jvm-1.6.4.dex.jar;legacy-support-core-utils-1.0.0.dex.jar;lifecycle-common-2.6.2.dex.jar;lifecycle-livedata-2.6.2.dex.jar;lifecycle-livedata-core-2.6.2.dex.jar;lifecycle-runtime-2.6.2.dex.jar;lifecycle-service-2.6.2.dex.jar;lifecycle-viewmodel-2.6.2.dex.jar;lifecycle-viewmodel-savedstate-2.6.2.dex.jar;listenablefuture-1.0.dex.jar;loader-1.0.0.dex.jar;localbroadcastmanager-1.0.0.dex.jar;okio-jvm-3.4.0.dex.jar;play-services-ads-22.2.0.dex.jar;play-services-ads-base-22.2.0.dex.jar;play-services-ads-identifier-18.0.0.dex.jar;play-services-ads-lite-22.2.0.dex.jar;play-services-appset-16.0.1.dex.jar;play-services-base-18.5.0.dex.jar;play-services-basement-18.4.0.dex.jar;play-services-cloud-messaging-17.0.1.dex.jar;play-services-location-21.0.1.dex.jar;play-services-maps-18.1.0.dex.jar;play-services-measurement-base-20.1.2.dex.jar;play-services-measurement-sdk-api-20.1.2.dex.jar;play-services-stats-17.0.2.dex.jar;play-services-tasks-18.2.0.dex.jar;print-1.0.0.dex.jar;profileinstaller-1.3.0.dex.jar;room-common-2.2.5.dex.jar;room-runtime-2.2.5.dex.jar;savedstate-1.2.1.dex.jar;sqlite-2.1.0.dex.jar;sqlite-framework-2.1.0.dex.jar;startup-runtime-1.1.1.dex.jar;tracing-1.2.0.dex.jar;transport-api-3.0.0.dex.jar;transport-backend-cct-3.1.8.dex.jar;transport-runtime-3.1.8.dex.jar;user-messaging-platform-2.0.0.dex.jar;vectordrawable-1.1.0.dex.jar;vectordrawable-animated-1.1.0.dex.jar;versionedparcelable-1.1.1.dex.jar;viewpager-1.0.0.dex.jar;work-runtime-2.7.0.dex.jar + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) Debug @@ -274,6 +290,16 @@ 1 + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + res\drawable-anydpi-v26 @@ -807,6 +833,9 @@ 1 + + 1 + @@ -877,6 +906,10 @@ Assets 1 + + Assets + 1 + @@ -887,6 +920,10 @@ Assets 1 + + Assets + 1 + @@ -1101,11 +1138,11 @@ + False False - False True True diff --git a/Demos/Cipher_Console_KDF/Cipher_Console_KDF.dproj b/Demos/Cipher_Console_KDF/Cipher_Console_KDF.dproj index 480d1d02..1c8efcd4 100644 --- a/Demos/Cipher_Console_KDF/Cipher_Console_KDF.dproj +++ b/Demos/Cipher_Console_KDF/Cipher_Console_KDF.dproj @@ -1,7 +1,7 @@  {EB1F3FC9-ED7C-4B29-9D7E-E9A3F356371B} - 20.2 + 20.4 None True Debug @@ -345,6 +345,16 @@ 1 + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + res\drawable-anydpi-v26 @@ -878,6 +888,9 @@ 1 + + 1 + @@ -948,6 +961,10 @@ Assets 1 + + Assets + 1 + @@ -958,6 +975,10 @@ Assets 1 + + Assets + 1 + @@ -1172,11 +1193,11 @@ + False False - False True True diff --git a/Demos/Cipher_FMX/Cipher_FMX.dproj b/Demos/Cipher_FMX/Cipher_FMX.dproj index 33e76ef8..3234c587 100644 --- a/Demos/Cipher_FMX/Cipher_FMX.dproj +++ b/Demos/Cipher_FMX/Cipher_FMX.dproj @@ -1,7 +1,7 @@  {F90DC8C6-DC04-46FE-8D5C-2260589FBEF1} - 20.2 + 20.4 FMX Cipher_FMX.dpr True @@ -9,7 +9,6 @@ Win32 32787 Application - AndroidSDK25.2.5_64bit.sdk Cipher_FMX @@ -121,7 +120,7 @@ Crypto_426_320.png CryptoIcon_72.png Crypto_960_720.png - package=com.dec.Cipher_FMX;label=DEC cipher demo;versionCode=4;versionName=1.4.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34 + package=com.dec.Cipher_FMX;label=DEC cipher demo;versionCode=4;versionName=1.4.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=36 Debug $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png @@ -136,7 +135,7 @@ billing-6.0.1.dex.jar;biometric-1.1.0.dex.jar;cloud-messaging.dex.jar;exifinterface-1.3.6.dex.jar;firebase-annotations-16.2.0.dex.jar;firebase-common-20.3.1.dex.jar;firebase-components-17.1.0.dex.jar;firebase-datatransport-18.1.7.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-encoders-proto-16.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.1.3.dex.jar;firebase-installations-interop-17.1.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-23.1.2.dex.jar;play-services-ads-22.2.0.dex.jar;play-services-ads-base-22.2.0.dex.jar;play-services-ads-identifier-18.0.0.dex.jar;play-services-ads-lite-22.2.0.dex.jar;sqlite-framework-2.1.0.dex.jar;sqlite-2.1.0.dex.jar - package=com.dec.Cipher_FMX;label=DEC cipher demo;versionCode=4;versionName=1.4.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34 + package=com.dec.Cipher_FMX;label=DEC cipher demo;versionCode=4;versionName=1.4.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=36 Debug true true @@ -247,13 +246,13 @@ 6 true AppStore - package=com.dec.Cipher_FMX;label=DEC cipher demo;versionCode=6;versionName=1.4.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34 + package=com.dec.Cipher_FMX;label=DEC cipher demo;versionCode=6;versionName=1.4.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=36 7 mh AppStore - package=com.dec.Cipher_FMX;label=DEC cipher demo;versionCode=7;versionName=1.5.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34 + package=com.dec.Cipher_FMX;label=DEC cipher demo;versionCode=7;versionName=1.5.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=36 true #FFFFFF #000000 @@ -495,6 +494,16 @@ 1 + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + res\drawable-anydpi-v26 @@ -1028,6 +1037,9 @@ 1 + + 1 + @@ -1098,6 +1110,10 @@ Assets 1 + + Assets + 1 + @@ -1108,6 +1124,10 @@ Assets 1 + + Assets + 1 + @@ -1322,6 +1342,7 @@ + True diff --git a/Demos/Cipher_FMX/MainFormCipherFMX.fmx b/Demos/Cipher_FMX/MainFormCipherFMX.fmx index c25082e5..c026bfce 100644 --- a/Demos/Cipher_FMX/MainFormCipherFMX.fmx +++ b/Demos/Cipher_FMX/MainFormCipherFMX.fmx @@ -2,8 +2,8 @@ object FormMain: TFormMain Left = 0 Top = 0 Caption = 'FMX Cipher Demo' - ClientHeight = 910 - ClientWidth = 402 + ClientHeight = 908 + ClientWidth = 404 FormFactor.Width = 320 FormFactor.Height = 480 FormFactor.Devices = [Desktop] @@ -13,13 +13,13 @@ object FormMain: TFormMain DesignerMasterStyle = 0 object VertScrollBox1: TVertScrollBox Align = Client - Size.Width = 402.00000000000000000 - Size.Height = 910.00000000000000000 + Size.Width = 404.00000000000000000 + Size.Height = 908.00000000000000000 Size.PlatformDefault = False StyleLookup = 'scrollboxstyle' TabOrder = 6 - Viewport.Width = 386.00000000000000000 - Viewport.Height = 910.00000000000000000 + Viewport.Width = 388.00000000000000000 + Viewport.Height = 908.00000000000000000 object LayoutTop: TLayout Size.Width = 400.00000000000000000 Size.Height = 313.00000000000000000 diff --git a/Demos/Format_Console/Format_Console.dproj b/Demos/Format_Console/Format_Console.dproj index f1b6d9da..80f56376 100644 --- a/Demos/Format_Console/Format_Console.dproj +++ b/Demos/Format_Console/Format_Console.dproj @@ -1,7 +1,7 @@  {A36C5DFF-C1BF-493E-93AC-4D6170321A4C} - 20.2 + 20.4 None Format_Console.dpr True @@ -297,6 +297,16 @@ 1 + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + res\drawable-anydpi-v26 @@ -830,6 +840,9 @@ 1 + + 1 + @@ -900,6 +913,10 @@ Assets 1 + + Assets + 1 + @@ -910,6 +927,10 @@ Assets 1 + + Assets + 1 + @@ -1124,11 +1145,11 @@ + False False - False True True diff --git a/Demos/HashBenchmark_FMX/HashBenchmark.dproj b/Demos/HashBenchmark_FMX/HashBenchmark.dproj index 5d4791e7..1cce8fd5 100644 --- a/Demos/HashBenchmark_FMX/HashBenchmark.dproj +++ b/Demos/HashBenchmark_FMX/HashBenchmark.dproj @@ -1,7 +1,7 @@  {B265A13B-3BB8-4D4C-A953-4D5FB8ACB4D6} - 20.2 + 20.4 FMX True Debug @@ -91,7 +91,7 @@ DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;RadiantShapesFmx;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;RadiantShapesFmx_Design;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage) - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34 + package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=36 Debug true Hash36.png @@ -120,7 +120,7 @@ DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;tethering;bindcompfmx;FmxTeeUI;fmx;FireDACIBDriver;RadiantShapesFmx;dbexpress;IndyCore;dsnap;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;RadiantShapesFmx_Design;dsnapxml;dbrtl;IndyProtocols;$(DCC_UsePackage) - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34 + package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=36 Debug true Hash36.png @@ -411,6 +411,16 @@ 1 + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + res\drawable-anydpi-v26 @@ -944,6 +954,9 @@ 1 + + 1 + @@ -1014,6 +1027,10 @@ Assets 1 + + Assets + 1 + @@ -1024,6 +1041,10 @@ Assets 1 + + Assets + 1 + @@ -1238,6 +1259,7 @@ + True diff --git a/Demos/HashBenchmark_FMX/MainFormHashBenchmark.fmx b/Demos/HashBenchmark_FMX/MainFormHashBenchmark.fmx index fb4df20c..59e0fd39 100644 --- a/Demos/HashBenchmark_FMX/MainFormHashBenchmark.fmx +++ b/Demos/HashBenchmark_FMX/MainFormHashBenchmark.fmx @@ -47,13 +47,16 @@ object FormMain: TFormMain Viewport.Height = 344.000000000000000000 object StringColumn1: TStringColumn Header = 'Algorithm' + HeaderSettings.TextSettings.WordWrap = False ReadOnly = True end object StringColumn2: TStringColumn Header = 'Speed MB/s' + HeaderSettings.TextSettings.WordWrap = False end object StringColumn3: TStringColumn Header = 'Time (hh:mm:ss:ms)' + HeaderSettings.TextSettings.WordWrap = False end end object TimerBenchmark: TTimer diff --git a/Demos/HashBenchmark_FMX/MainFormHashBenchmark.pas b/Demos/HashBenchmark_FMX/MainFormHashBenchmark.pas index 1960828e..be9b529b 100644 --- a/Demos/HashBenchmark_FMX/MainFormHashBenchmark.pas +++ b/Demos/HashBenchmark_FMX/MainFormHashBenchmark.pas @@ -217,6 +217,7 @@ procedure TFormMain.RunBenchmark(ClassName: string; RowIndex: Integer); Iterations : UInt32; BufferSize : UInt32; Salt : TBytes; + PwdHashBuf : TBytes; begin Hash := TDECHash.ClassByName(ClassName).Create; @@ -232,6 +233,8 @@ procedure TFormMain.RunBenchmark(ClassName: string; RowIndex: Integer); (TDECPasswordHash(Hash).MaxPasswordLength < BufferSize) then begin BufferSize := TDECPasswordHash(Hash).MaxPasswordLength; + SetLength(PwdHashBuf, BufferSize); + Move(FBenchmarkBuffer[0], PwdHashBuf[0], BufferSize); // Since password hashes take quite long time to calculate limit that time // by limiting the number of iterations calculated but in such a way that @@ -264,7 +267,12 @@ procedure TFormMain.RunBenchmark(ClassName: string; RowIndex: Integer); if Hash.IsPasswordHash then TDECPasswordHash(Hash).Salt := Salt; - HashResult := Hash.CalcBuffer(@FBenchmarkBuffer[0], BufferSize); + if not Hash.IsPasswordHash then + HashResult := Hash.CalcBytes(FBenchmarkBuffer) + else + HashResult := Hash.CalcBytes(PwdHashBuf); +// Former implementation, but this leads to crashes: +// HashResult := Hash.CalcBuffer(@FBenchmarkBuffer[0], BufferSize); end; FStopwatch.Stop; diff --git a/Demos/Hash_Console/Hash_Console.dproj b/Demos/Hash_Console/Hash_Console.dproj index d185b381..f680b2b8 100644 --- a/Demos/Hash_Console/Hash_Console.dproj +++ b/Demos/Hash_Console/Hash_Console.dproj @@ -1,7 +1,7 @@  {3617401D-D6AC-4F43-9D1D-B217C40C973D} - 20.2 + 20.4 None Hash_Console.dpr True @@ -297,6 +297,16 @@ 1 + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + res\drawable-anydpi-v26 @@ -830,6 +840,9 @@ 1 + + 1 + @@ -900,6 +913,10 @@ Assets 1 + + Assets + 1 + @@ -910,6 +927,10 @@ Assets 1 + + Assets + 1 + @@ -1124,11 +1145,11 @@ + False False - False True True diff --git a/Demos/Hash_FMX/Hash_FMX.dproj b/Demos/Hash_FMX/Hash_FMX.dproj index 15c52f78..339c70a3 100644 --- a/Demos/Hash_FMX/Hash_FMX.dproj +++ b/Demos/Hash_FMX/Hash_FMX.dproj @@ -1,7 +1,7 @@  {E6A23F63-4CF8-4715-BB2C-BFCA7EFA2431} - 20.2 + 20.4 FMX Hash_FMX.dpr True @@ -9,7 +9,6 @@ Win32 32787 Application - AndroidSDK25.2.5_64bit.sdk Hash_FMX @@ -120,7 +119,7 @@ Debug Crypto_426_320.png Hash72.png - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=9;versionName=1.5.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34 + package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=9;versionName=1.5.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=36 Hash144.png $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png @@ -135,7 +134,7 @@ billing-6.0.1.dex.jar;biometric-1.1.0.dex.jar;exifinterface-1.3.6.dex.jar;firebase-annotations-16.2.0.dex.jar;firebase-common-20.3.1.dex.jar;firebase-components-17.1.0.dex.jar;firebase-datatransport-18.1.7.dex.jar;firebase-encoders-17.0.0.dex.jar;firebase-encoders-json-18.0.0.dex.jar;firebase-encoders-proto-16.0.0.dex.jar;firebase-iid-interop-17.1.0.dex.jar;firebase-installations-17.1.3.dex.jar;firebase-installations-interop-17.1.0.dex.jar;firebase-measurement-connector-19.0.0.dex.jar;firebase-messaging-23.1.2.dex.jar;play-services-ads-22.2.0.dex.jar;play-services-ads-base-22.2.0.dex.jar;play-services-ads-identifier-18.0.0.dex.jar;play-services-ads-lite-22.2.0.dex.jar;print-1.0.0.dex.jar;sqlite-2.1.0.dex.jar;sqlite-framework-2.1.0.dex.jar - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=9;versionName=1.5.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34 + package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=9;versionName=1.5.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=36 Debug true true @@ -206,7 +205,7 @@ fill_horizontal 8 - package=com.dec.Hash_FMX;label=DEC hash demo;versionCode=8;versionName=1.5.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34 + package=com.dec.Hash_FMX;label=DEC hash demo;versionCode=8;versionName=1.5.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=36 false false false @@ -228,7 +227,7 @@ true fill_horizontal 9 - package=com.dec.Hash_FMX;label=DEC hash demo;versionCode=9;versionName=1.5.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34 + package=com.dec.Hash_FMX;label=DEC hash demo;versionCode=9;versionName=1.5.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=36 false false false @@ -281,7 +280,7 @@ ..\..\..\AndroidAppKeystore\mh_Keystore.keystore 850847C65F90078DCF7DE530A4627BB3E44F08447EB9ECFA9F547732D85CA8FFDB06A389E3001C4DC1B85774FAD1C339BAFD36020437228116714592E5A6228DC953F307D56AFAE2BFAAAF1007411D1B92433E551DCB0925E3F016B44439788F mh - package=com.dec.Hash_FMX;label=DEC hash demo;versionCode=9;versionName=1.5.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34 + package=com.dec.Hash_FMX;label=DEC hash demo;versionCode=9;versionName=1.5.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=36 2 2 true @@ -302,7 +301,7 @@ false false false - package=com.dec.Hash_FMX;label=DEC hash demo;versionCode=9;versionName=1.5.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34 + package=com.dec.Hash_FMX;label=DEC hash demo;versionCode=9;versionName=1.5.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=36 2 2 true @@ -553,6 +552,16 @@ 1 + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + res\drawable-anydpi-v26 @@ -1086,6 +1095,9 @@ 1 + + 1 + @@ -1156,6 +1168,10 @@ Assets 1 + + Assets + 1 + @@ -1166,6 +1182,10 @@ Assets 1 + + Assets + 1 + @@ -1380,6 +1400,7 @@ + True diff --git a/Demos/Hash_FMX/MainFormHashFMX.fmx b/Demos/Hash_FMX/MainFormHashFMX.fmx index 492a3da7..fc97cf49 100644 --- a/Demos/Hash_FMX/MainFormHashFMX.fmx +++ b/Demos/Hash_FMX/MainFormHashFMX.fmx @@ -59,7 +59,6 @@ object FormMain: TFormMain Size.PlatformDefault = False TabOrder = 7 Text = 'Calc' - TextSettings.Trimming = None OnClick = ButtonCalcClick end object EditInput: TEdit @@ -96,7 +95,7 @@ object FormMain: TFormMain StyleLookup = 'labelstyle' TextSettings.WordWrap = False TextSettings.Trimming = None - Text = #169' 2018-2024 by Team DEC V%0:s' + Text = #169' 2018-2025 by Team DEC V%0:s' end end object LayoutTop: TLayout diff --git a/Demos/Hash_FMX/MainFormHashFMX.pas b/Demos/Hash_FMX/MainFormHashFMX.pas index 932689c1..f7ab726c 100644 --- a/Demos/Hash_FMX/MainFormHashFMX.pas +++ b/Demos/Hash_FMX/MainFormHashFMX.pas @@ -136,6 +136,7 @@ procedure TFormMain.ButtonCalcClick(Sender: TObject); SaltFormatting : TDECFormatClass; InputBuffer : TBytes; OutputBuffer : TBytes; + Salt : TBytes; ExtensibleInterf : IDECHashExtensibleOutput; LastByteLengthInterf : IDECHashBitsized; RoundsInterf : IDECHashRounds; @@ -165,76 +166,83 @@ procedure TFormMain.ButtonCalcClick(Sender: TObject); if ComboBoxHashFunction.ItemIndex >= 0 then begin // Find the class type of the selected hash class and create an instance of it - Hash := TDECHash.ClassByName(GetSelectedHashClassName).Create; + Hash := TDECHash.ClassByName(GetSelectedHashClassName).Create; - if Supports(Hash.ClassType, IDECHashExtensibleOutput) then - begin - ExtensibleInterf := (Hash as IDECHashExtensibleOutput); - ExtensibleInterf.HashSize := EditHashLength.Text.ToInteger; - end - else - ExtensibleInterf := nil; - - if Supports(Hash.ClassType, IDECHashBitsized) then - begin - LastByteLengthInterf := (Hash as IDECHashBitsized); - LastByteLengthInterf.FinalBitLength := EditLastByteBits.Text.ToInteger; - end - else - LastByteLengthInterf := nil; - - if Supports(Hash.ClassType, IDECHashRounds) then - begin - RoundsInterf := (Hash as IDECHashRounds); - Rounds := EditRounds.Text.ToInteger; - - // If value is not in range we don't display any error message here - // because we already displayed one in OnChange of the edit, means when - // the edit lost focus. This if here is only to prevent that after closing - // the error message the user clicks the calc button again. In that case we - // simply skip calculation completely. - if (Rounds >= RoundsInterf.GetMinRounds) and - (Rounds <= RoundsInterf.GetMaxRounds) then - RoundsInterf.Rounds := EditRounds.Text.ToInteger + try + if Supports(Hash.ClassType, IDECHashExtensibleOutput) then + begin + ExtensibleInterf := (Hash as IDECHashExtensibleOutput); + ExtensibleInterf.HashSize := EditHashLength.Text.ToInteger; + end else - Exit; - end - else - RoundsInterf := nil; + ExtensibleInterf := nil; - // set the salt property - HashClass := TDECHash.ClassByName(GetSelectedHashClassName); - if IsSaltablePasswordHash(HashClass) then - begin - if EditSalt.Text.IsEmpty then + if Supports(Hash.ClassType, IDECHashBitsized) then begin - ShowErrorMessage('No salt value entered'); - exit; - end; + LastByteLengthInterf := (Hash as IDECHashBitsized); + LastByteLengthInterf.FinalBitLength := EditLastByteBits.Text.ToInteger; + end + else + LastByteLengthInterf := nil; - if (ComboBoxSaltFormatting.ItemIndex >= 0) then - // Find the class type of the selected formatting class - SaltFormatting := TDECFormat.ClassByName( - ComboBoxSaltFormatting.Items[ComboBoxSaltFormatting.ItemIndex]) + if Supports(Hash.ClassType, IDECHashRounds) then + begin + RoundsInterf := (Hash as IDECHashRounds); + Rounds := EditRounds.Text.ToInteger; + + // If value is not in range we don't display any error message here + // because we already displayed one in OnChange of the edit, means when + // the edit lost focus. This if here is only to prevent that after closing + // the error message the user clicks the calc button again. In that case we + // simply skip calculation completely. + if (Rounds >= RoundsInterf.GetMinRounds) and + (Rounds <= RoundsInterf.GetMaxRounds) then + RoundsInterf.Rounds := EditRounds.Text.ToInteger + else + Exit; + end else + RoundsInterf := nil; + + // set the salt property + HashClass := TDECHash.ClassByName(GetSelectedHashClassName); + if IsSaltablePasswordHash(HashClass) then begin - ShowErrorMessage('No salt format selected'); - exit; + if EditSalt.Text.IsEmpty then + begin + ShowErrorMessage('No salt value entered'); + exit; + end; + + if (ComboBoxSaltFormatting.ItemIndex >= 0) then + // Find the class type of the selected formatting class + SaltFormatting := TDECFormat.ClassByName( + ComboBoxSaltFormatting.Items[ComboBoxSaltFormatting.ItemIndex]) + else + begin + ShowErrorMessage('No salt format selected'); + exit; + end; + + InputBuffer := System.SysUtils.BytesOf(EditSalt.Text); + if InputFormatting.IsValid(InputBuffer) then + begin + Salt := SaltFormatting.Decode(InputBuffer); + if (length(Salt) >= TDECPasswordHash(Hash).MinSaltLength) and + (length(Salt) <= TDECPasswordHash(Hash).MaxSaltLength) then + TDECPasswordHash(Hash).Salt := Salt + else + Exit; + end + else + ShowErrorMessage('Salt has wrong format'); end; - InputBuffer := System.SysUtils.BytesOf(EditSalt.Text); - if InputFormatting.IsValid(InputBuffer) then - TDECPasswordHash(Hash).Salt := SaltFormatting.Decode(InputBuffer) - else - ShowErrorMessage('Salt has wrong format'); - end; - - // Set the BCrypt specific cost factor. Might be more generalized when - // further password hashes are added. - if (HashClass = THash_BCrypt) then - THash_BCrypt(Hash).Cost := EditCost.Text.ToInteger; + // Set the BCrypt specific cost factor. Might be more generalized when + // further password hashes are added. + if (HashClass = THash_BCrypt) then + THash_BCrypt(Hash).Cost := EditCost.Text.ToInteger; - try InputBuffer := System.SysUtils.BytesOf(EditInput.Text); if InputFormatting.IsValid(InputBuffer) then @@ -363,7 +371,7 @@ procedure TFormMain.ComboBoxHashFunctionChange(Sender: TObject); function TFormMain.IsSaltablePasswordHash(HashClass: TDECHashClass): Boolean; var - Hash : TDECHash; + Hash : TDECHash; begin Result := false; diff --git a/Demos/Password_Console/Password_Console.dproj b/Demos/Password_Console/Password_Console.dproj index ac9c00e0..7f4f3db3 100644 --- a/Demos/Password_Console/Password_Console.dproj +++ b/Demos/Password_Console/Password_Console.dproj @@ -1,7 +1,7 @@  {FA85DBBE-C5D8-4512-B57E-8AE2CB5D842B} - 20.2 + 20.4 None True Debug @@ -324,6 +324,16 @@ 1 + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + res\drawable-anydpi-v26 @@ -857,6 +867,9 @@ 1 + + 1 + @@ -927,6 +940,10 @@ Assets 1 + + Assets + 1 + @@ -937,6 +954,10 @@ Assets 1 + + Assets + 1 + @@ -1151,11 +1172,11 @@ + False False - False True True diff --git a/Demos/Progress_VCL/ProgressDemoVCL.dproj b/Demos/Progress_VCL/ProgressDemoVCL.dproj index bfce2f37..9dec9e52 100644 --- a/Demos/Progress_VCL/ProgressDemoVCL.dproj +++ b/Demos/Progress_VCL/ProgressDemoVCL.dproj @@ -1,7 +1,7 @@ - + {B6DE5711-AD3F-44B0-8206-FB26B8B82A31} - 20.2 + 20.4 VCL True Debug @@ -300,6 +300,16 @@ 1 + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + res\drawable-anydpi-v26 @@ -833,6 +843,9 @@ 1 + + 1 + @@ -903,6 +916,10 @@ Assets 1 + + Assets + 1 + @@ -913,6 +930,10 @@ Assets 1 + + Assets + 1 + @@ -1127,6 +1148,7 @@ + True diff --git a/Demos/Random_Console/Random_Console.dproj b/Demos/Random_Console/Random_Console.dproj index 036dc8dc..8eeb1e58 100644 --- a/Demos/Random_Console/Random_Console.dproj +++ b/Demos/Random_Console/Random_Console.dproj @@ -1,7 +1,7 @@  {D55FA1A8-C7CC-4C2B-B516-EA90F34161BB} - 20.2 + 20.4 None True Debug @@ -299,6 +299,16 @@ 1 + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + res\drawable-anydpi-v26 @@ -832,6 +842,9 @@ 1 + + 1 + @@ -902,6 +915,10 @@ Assets 1 + + Assets + 1 + @@ -912,6 +929,10 @@ Assets 1 + + Assets + 1 + @@ -1126,11 +1147,11 @@ + False False - False True True diff --git a/Demos/Random_VCL_Comparison/RandomComparison_VCL.dproj b/Demos/Random_VCL_Comparison/RandomComparison_VCL.dproj index d3c9ddfe..a8808677 100644 --- a/Demos/Random_VCL_Comparison/RandomComparison_VCL.dproj +++ b/Demos/Random_VCL_Comparison/RandomComparison_VCL.dproj @@ -1,7 +1,7 @@  {EC36B2CD-4E75-49AF-9798-206F8C5BCDA0} - 20.2 + 20.4 VCL True Debug @@ -288,6 +288,16 @@ 1 + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + res\drawable-anydpi-v26 @@ -821,6 +831,9 @@ 1 + + 1 + @@ -891,6 +904,10 @@ Assets 1 + + Assets + 1 + @@ -901,6 +918,10 @@ Assets 1 + + Assets + 1 + @@ -1115,6 +1136,7 @@ + True diff --git a/Docs/DEC65.pdf b/Docs/DEC65.pdf index 1a54b73b..ba390039 100644 Binary files a/Docs/DEC65.pdf and b/Docs/DEC65.pdf differ diff --git a/Docs/VersionHistory.pdf b/Docs/VersionHistory.pdf index 100dfbdf..43bea7b5 100644 Binary files a/Docs/VersionHistory.pdf and b/Docs/VersionHistory.pdf differ diff --git a/Install/SetIDEPaths.dproj b/Install/SetIDEPaths.dproj index 1b5948b7..73cfed3c 100644 --- a/Install/SetIDEPaths.dproj +++ b/Install/SetIDEPaths.dproj @@ -1,7 +1,7 @@  {6AF2AA8F-E3B9-4962-BDC6-DABD87885D4A} - 20.2 + 20.4 None True Debug @@ -296,6 +296,16 @@ 1 + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + res\drawable-anydpi-v26 @@ -829,6 +839,9 @@ 1 + + 1 + @@ -899,6 +912,10 @@ Assets 1 + + Assets + 1 + @@ -909,6 +926,10 @@ Assets 1 + + Assets + 1 + @@ -1123,11 +1144,11 @@ + False False - False True False diff --git a/NOTICE.txt b/NOTICE.txt index c0041c7c..65c9dd4d 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -2,7 +2,7 @@ DEC - Delphi Encryption Compendium Version 6.5 Copyright (c) 2018 - 2020 Norman Gallery (ng931884 [at] gmx [dot] de) -Copyright (c) 2016 - 2024 Markus Humm (markus [dot] humm [at] googlemail [dot] com) (main contact) +Copyright (c) 2016 - 2025 Markus Humm (markus [dot] humm [at] googlemail [dot] com) (main contact) Copyright (c) 2008 - 2019 Frederik A. Winkelsdorf (winkelsdorf [at] gmail [dot] com) Copyright (c) 1999 - 2008 Hagen Reddmann (HaReddmann [at] T-Online [dot] de) @@ -30,6 +30,8 @@ alexrayne Stevie danielmarschall Christoph Schneider (Schneider Infosystems AG) +mikerabat +icTrainer Parts of the work loosely based on the works of Wolfgang Erhardt, who is unfortunately dead already. diff --git a/Source/DEC60.dpr b/Source/DEC60.dpr index 36f91885..10cdafa5 100644 --- a/Source/DEC60.dpr +++ b/Source/DEC60.dpr @@ -47,7 +47,9 @@ uses DECHashBitBase in 'DECHashBitBase.pas', DECCipherModesGCM in 'DECCipherModesGCM.pas', DECZIPHelper in 'DECZIPHelper.pas', - DECCipherPaddings in 'DECCipherPaddings.pas'; + DECCipherPaddings in 'DECCipherPaddings.pas', + DECCipherModesCCM in 'DECCipherModesCCM.pas', + DECAuthenticatedCipherModesBase in 'DECAuthenticatedCipherModesBase.pas'; begin try diff --git a/Source/DEC60.dproj b/Source/DEC60.dproj index 5afc74b3..eb94381d 100644 --- a/Source/DEC60.dproj +++ b/Source/DEC60.dproj @@ -1,7 +1,7 @@  {34FB3EC0-D6C0-4F92-9FEE-3E0E87C91FC4} - 20.2 + 20.4 None DEC60.dpr True @@ -85,13 +85,13 @@ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34 + package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=36 Debug true $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34 + package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=36 Debug true Base @@ -176,6 +176,9 @@ + + + @@ -233,12 +236,48 @@ + + + DEC60.exe + true + + + + + .\ + true + + + + + .\ + true + + + + + .\ + true + + + + + .\ + true + + + + + .\ + true + + 1 @@ -353,6 +392,16 @@ 1 + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + res\drawable-anydpi-v26 @@ -886,6 +935,9 @@ 1 + + 1 + @@ -956,6 +1008,10 @@ Assets 1 + + Assets + 1 + @@ -966,6 +1022,10 @@ Assets 1 + + Assets + 1 + @@ -1180,11 +1240,11 @@ + True True - False True True diff --git a/Source/DEC60Complete.groupproj b/Source/DEC60Complete.groupproj index 808c1494..3976a759 100644 --- a/Source/DEC60Complete.groupproj +++ b/Source/DEC60Complete.groupproj @@ -48,6 +48,9 @@ + + + Default.Personality.12 @@ -191,14 +194,23 @@ + + + + + + + + + - + - + - + diff --git a/Source/DECAuthenticatedCipherModesBase.pas b/Source/DECAuthenticatedCipherModesBase.pas new file mode 100644 index 00000000..6245f1af --- /dev/null +++ b/Source/DECAuthenticatedCipherModesBase.pas @@ -0,0 +1,230 @@ +{***************************************************************************** + 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 DECAuthenticatedCipherModesBase; + +interface + +{$INCLUDE DECOptions.inc} + +uses + {$IFDEF FPC} + SysUtils, + {$ELSE} + System.SysUtils, + {$ENDIF} + DECTypes; + +type + /// + /// Exception raised when nonce has a wrong length + /// + EDECNonceLengthException = class(EDECException); + /// + /// Exception raised when authentication value has wrong length + /// + EDECAuthLengthException = class(EDECException); + + /// + /// A method of this type needs to be supplied for encrypting or decrypting + /// a block via this GCM algorithm. The method is implemented as a parameter, + /// to avoid the need to bring TGCM in the inheritance chain. TGCM thus can + /// be used for composition instead of inheritance. + /// + /// + /// Data to be encrypted + /// + /// + /// In this memory the encrypted result will be written + /// + /// + /// Size of source in byte + /// + TEncodeDecodeMethod = procedure(Source, Dest: Pointer; Size: Integer) of Object; + + /// + /// Base class for authenticated cipher modes + /// + TAuthenticatedCipherModesBase = class(TObject) + strict protected + /// + /// The data which shall be authenticated in parallel to the encryption + /// + FDataToAuthenticate : TBytes; + /// + /// Length of the authentication tag to generate in byte + /// + FCalcAuthenticationTagLength : UInt32; + /// + /// Generated authentication tag + /// + FCalcAuthenticationTag : TBytes; + + /// + /// Expected authentication tag value, will be compared with actual value + /// when decryption finished. + /// + FExpectedAuthenticationTag : TBytes; + + /// + /// Reference to the encode method of the actual cipher used + /// + FEncryptionMethod : TEncodeDecodeMethod; + + /// + /// Defines the length of the resulting authentication value in bit. + /// + /// + /// Sets the length of Authenticaton_tag in bit, values as per specification + /// of the concrete algorithm implemented in a child class + /// + procedure SetAuthenticationTagLength(const Value: UInt32); virtual; + /// + /// Returns the length of the calculated authehtication value in bit + /// + /// + /// Length of the calculated authentication value in bit + /// + function GetAuthenticationTagBitLength: UInt32; virtual; + public + /// + /// Should be called when starting encryption/decryption in order to + /// initialize internal tables etc. + /// + /// + /// Encryption method of the cypher used + /// + /// + /// Initialization vector + /// + procedure Init(EncryptionMethod : TEncodeDecodeMethod; + InitVector : TBytes); virtual; + + /// + /// Encodes a block of data using the supplied cipher + /// + /// + /// Plain text to encrypt + /// + /// + /// Ciphertext after encryption + /// + /// + /// Number of bytes to encrypt + /// + procedure Encode(Source, + Dest : PUInt8Array; + Size : Integer); virtual; abstract; + /// + /// Decodes a block of data using the supplied cipher + /// + /// + /// Encrypted ciphertext to decrypt + /// + /// + /// Plaintext after decryption + /// + /// + /// Number of bytes to decrypt + /// + procedure Decode(Source, + Dest : PUInt8Array; + Size : Integer); virtual; abstract; + + /// + /// Returns a list of authentication tag lengths explicitely specified by + /// the official specification of the standard. + /// + /// + /// List of bit lengths + /// + function GetStandardAuthenticationTagBitLengths:TStandardBitLengths; virtual; + + /// + /// The data which shall be authenticated in parallel to the encryption + /// + property DataToAuthenticate : TBytes + read FDataToAuthenticate + write FDataToAuthenticate; + /// + /// Sets the length of AuthenticatonTag in bit, values as per official + /// specification are: 128, 120, 112, 104, or 96 bit. For certain + /// applications, they may be 64 or 32 as well, but the use of these two + /// tag lengths constrains the length of the input data and the lifetime + /// of the key. + /// + property AuthenticationTagBitLength : UInt32 + read GetAuthenticationTagBitLength + write SetAuthenticationTagLength; + /// + /// Calculated authentication value + /// + property CalculatedAuthenticationTag : TBytes + read FCalcAuthenticationTag + write FCalcAuthenticationTag; + + /// + /// Expected authentication tag value, will be compared with actual value + /// when decryption finished. + /// + property ExpectedAuthenticationTag : TBytes + read FExpectedAuthenticationTag + write FExpectedAuthenticationTag; + end; + +implementation + +uses + DECUtil; + +{ TAuthenticatedCipherModesBase } + +function TAuthenticatedCipherModesBase.GetAuthenticationTagBitLength: UInt32; +begin + Result := FCalcAuthenticationTagLength shl 3; +end; + +function TAuthenticatedCipherModesBase.GetStandardAuthenticationTagBitLengths: TStandardBitLengths; +begin + SetLength(Result, 0); +end; + +procedure TAuthenticatedCipherModesBase.Init(EncryptionMethod : TEncodeDecodeMethod; + InitVector : TBytes); +var + CalcAuthLength : Integer; +begin + Assert(Assigned(EncryptionMethod), 'No encryption method specified'); + + // Clear calculated authentication value + CalcAuthLength := Length(FCalcAuthenticationTag); + if (CalcAuthLength > 0) then + begin + ProtectBytes(FCalcAuthenticationTag); + SetLength(FCalcAuthenticationTag, CalcAuthLength); + FillChar(FCalcAuthenticationTag[0], CalcAuthLength, #0); + end; + + FEncryptionMethod := EncryptionMethod; +end; + +procedure TAuthenticatedCipherModesBase.SetAuthenticationTagLength(const Value: UInt32); +begin + FCalcAuthenticationTagLength := Value shr 3; + SetLength(FCalcAuthenticationTag, FCalcAuthenticationTagLength); +end; + +end. diff --git a/Source/DECCipherBase.pas b/Source/DECCipherBase.pas index 456f681d..6ee2021d 100644 --- a/Source/DECCipherBase.pas +++ b/Source/DECCipherBase.pas @@ -125,7 +125,7 @@ interface /// csDecode : Decoding was started, and more chunks can be decoded, but not encoded /// /// - /// csPadded : trough En/Decoding the messagechunks are padded, no more chunks can + /// csPadded : through En/Decoding the messagechunks are padded, no more chunks can /// be processed, the cipher is blocked /// /// @@ -182,7 +182,8 @@ interface cmCFS8, // 8Bit CFS, double CFB cmCFSx, // CFS on Blocksize bytes cmECBx, // Electronic Code Book - cmGCM // Galois Counter Mode + cmGCM, // Galois Counter Mode + cmCCM // Counter with CBC-MAC Mode {$IFDEF DEC3_CMCTS} ,cmCTS3 // double CBC, with less secure padding of truncated final block // for DEC 3.0 compatibility only (see DECOptions.inc) @@ -228,7 +229,11 @@ TDECCipher = class(TDECObject) /// This is the size of FData in byte /// FDataSize : Integer; - private + + /// + /// Sets the desired padding mode, means how block ciphers treat + /// incompletely filled last blocks. + /// procedure SetPaddingMode(const Value: TPaddingMode); strict protected /// @@ -404,6 +409,11 @@ TDECCipher = class(TDECObject) /// List of registered DEC classes. Key is the Identity of the class. /// class var ClassList : TDECClassList; + /// + /// When true Randomize has already been called. Needed for lazy + /// initialization within SetAutomaticInitVector + /// + class var RandomizeCalled : Boolean; /// /// Tries to find a class type by its name @@ -604,6 +614,12 @@ TDECCipher = class(TDECObject) PaddingMode: TPaddingMode = pmNone); overload; {$ENDIF} + /// + /// Sets a random value for the init vector. Must be called after Init + /// and is a superflous call for stream ciphers + /// + procedure SetAutomaticInitVector; + /// /// Properly finishes the cryptographic operation. It needs to be called /// at the end of encrypting or decrypting data. It does NOT remove the @@ -942,6 +958,38 @@ destructor TDECCipher.Destroy; inherited Destroy; end; +procedure TDECCipher.SetAutomaticInitVector; +var + IVIdx : Integer; + Buf : TBytes; + Entrophy : Double; +begin + if not (ctStream in Context.CipherType) and (Context.BlockSize > 1) then + begin + if not RandomizeCalled then + begin + Randomize; + RandomizeCalled := true; + end; + + SetLength(Buf, FBufferSize); + + repeat + IVIdx := 0; + + while (IVIdx < FBufferSize) do + begin + Buf[IVIdx] := Random(256); + inc(IVIdx); + end; + + Entrophy := ShannonEntropy(Buf); + until (Entrophy >= 3.5) or ((FBufferSize < 16) and (Entrophy >= 3)); + + Move(Buf[0], FInitializationVector[0], FBufferSize); + end; +end; + procedure TDECCipher.SetMode(Value: TCipherMode); begin if Value <> FMode then @@ -1237,7 +1285,9 @@ function TDECCipher.DecodeBytes(const Source: TBytes; Format: TDECFormatClass): function TDECCipher.CalcMAC(Format: TDECFormatClass): RawByteString; begin - Done; { TODO: This might be considered as unwanted side effect. Maybe we should instead raise an Exception if State is not csDone instead? This would also "teach" the user to don't forget to call "Done". } + Done; { TODO: This might be considered as unwanted side effect. Maybe we should + instead raise an Exception if State is not csDone instead? This would + also "teach" the user to don't forget to call "Done". } if FMode in [cmECBx] then raise EDECException.CreateRes(@sInvalidMACMode) else @@ -1246,7 +1296,11 @@ function TDECCipher.CalcMAC(Format: TDECFormatClass): RawByteString; function TDECCipher.CalcMACBytes(Format: TDECFormatClass): TBytes; begin + {$IFNDEF FPC} Result := System.SysUtils.BytesOf(CalcMAC); + {$ELSE} + Result := BytesOf(CalcMAC); + {$ENDIF} end; {$IFDEF RESTORE_RANGECHECKS}{$R+}{$ENDIF} @@ -1279,7 +1333,8 @@ initialization AddModuleUnloadProc(ModuleUnload); {$ENDIF DELPHIORBCB} - TDECCipher.ClassList := TDECClassList.Create; + TDECCipher.ClassList := TDECClassList.Create; + TDECCipher.RandomizeCalled := false; finalization // Ensure no further instances of classes registered in the registraiotn list diff --git a/Source/DECCipherFormats.pas b/Source/DECCipherFormats.pas index 5a754d70..c4598933 100644 --- a/Source/DECCipherFormats.pas +++ b/Source/DECCipherFormats.pas @@ -45,7 +45,7 @@ TDECFormattedCipher = class(TDECCipherModes, IDECCipher) /// /// The static class assigned to this field via Init method or PaddingMode /// property is being used to add or remove paddings in order to simplyfy - /// ading further padding shemes. + /// adding further padding shemes. /// FPaddingClass : TDECPaddingClass; @@ -328,7 +328,7 @@ TDECFormattedCipher = class(TDECCipherModes, IDECCipher) Format: TDECFormatClass = nil): string; overload; /// - /// Encrypts the contents of the passed unicode string + /// Encrypts the contents of the passed RawByteString /// /// /// String to encrypt. When block chaining mode ECBx @@ -733,7 +733,7 @@ function TDECFormattedCipher.EncodeBytes(const Source: TBytes): TBytes; Encode(Source[0], Result[0], Length(Source)) else if (FMode = cmGCM) then - EncodeGCM(@Source, @Result, 0); + EncodeGCM(nil, nil, 0); end; begin @@ -756,7 +756,7 @@ function TDECFormattedCipher.DecodeBytes(const Source: TBytes): TBytes; end else if (FMode = cmGCM) then - DecodeGCM(@Source, @Result, 0); + DecodeGCM(nil, nil, 0); if not (FPaddingClass = nil) then Result := FPaddingClass.RemovePadding(Result, Context.BlockSize); @@ -784,7 +784,7 @@ procedure TDECFormattedCipher.DoEncodeDecodeStream(const Source, Dest: TStream; StartPos := Pos; doPadding := false; doStartOnlyPadding := (DataSize = 0) and IsEncode and - (FPaddingMode <> pmNone); + (FPaddingMode <> pmNone); if (DataSize > 0) or doStartOnlyPadding then begin @@ -1124,11 +1124,11 @@ procedure TDECFormattedCipher.InitPaddingClass; begin case FPaddingMode of pmNone : FPaddingClass := nil; - pmPKCS7 : FPaddingCLass := TPKCS7Padding; - pmPKCS5 : FPaddingCLass := TPKCS5Padding; - pmANSI_X9_23 : FPaddingCLass := TANSI_X9_23_Padding; - pmISO10126 : FPaddingCLass := TISO10126Padding; - pmISO7816 : FPaddingCLass := TISO7816Padding; + pmPKCS7 : FPaddingClass := TPKCS7Padding; + pmPKCS5 : FPaddingClass := TPKCS5Padding; + pmANSI_X9_23 : FPaddingClass := TANSI_X9_23_Padding; + pmISO10126 : FPaddingClass := TISO10126Padding; + pmISO7816 : FPaddingClass := TISO7816Padding; else raise EDECCipherException.CreateResFmt(@sPaddingModeNotImplemented, [GetEnumName(TypeInfo(TPaddingMode), diff --git a/Source/DECCipherInterface.pas b/Source/DECCipherInterface.pas index 90389bf6..a4e1c6ed 100644 --- a/Source/DECCipherInterface.pas +++ b/Source/DECCipherInterface.pas @@ -26,6 +26,8 @@ interface {$ENDIF} DECTypes, DECCipherBase, DECFormatBase; +{$I DECOptions.inc} + type /// /// Common interface for all ciphers. Some ciphers may have additional @@ -596,6 +598,12 @@ interface PaddingMode: TPaddingMode = pmNone); overload; {$ENDIF} + /// + /// Sets a random value for the init vector. Must be called after Init + /// and is a superflous call for stream ciphers + /// + procedure SetAutomaticInitVector; + /// /// Returns the currently set cipher block mode, means how blocks are /// linked to each other in order to avoid certain attacks. diff --git a/Source/DECCipherModes.pas b/Source/DECCipherModes.pas index aa9ef832..e4673bda 100644 --- a/Source/DECCipherModes.pas +++ b/Source/DECCipherModes.pas @@ -26,7 +26,8 @@ interface {$ELSE} System.SysUtils, {$ENDIF} - DECTypes, DECCipherBase, DECCipherModesGCM, DECCipherInterface; + DECTypes, DECCipherBase, DECCipherModesGCM, DECCipherModesCCM, + DECCipherInterface; type /// @@ -143,6 +144,11 @@ TDECCipherModes = class(TDECCipher, IDECAuthenticatedCipher) /// FGCM : TGCM; /// + /// Implementation of the Counter with CBC-MAC mode. Only created when + /// gmCCM is set as mode. + /// + FCCM : TCCM; + /// /// Raises an EDECCipherException exception and provides the correct value /// for block size in that message /// @@ -239,6 +245,12 @@ TDECCipherModes = class(TDECCipher, IDECAuthenticatedCipher) /// source length is 0. /// procedure EncodeGCM(Source, Dest: PUInt8Array; Size: Integer); virtual; + /// + /// Counter with CBC-MAC Mode: encryption with addtional optional authentication. + /// Implemented in its own unit, but needed here to be callable even if + /// source length is 0. + /// + procedure EncodeCCM(Source, Dest: PUInt8Array; Size: Integer); virtual; {$IFDEF DEC3_CMCTS} /// /// double CBC, with @@ -326,6 +338,10 @@ TDECCipherModes = class(TDECCipher, IDECAuthenticatedCipher) /// Galois Counter Mode, details are implemented in DECCipherModesGCM /// procedure DecodeGCM(Source, Dest: PUInt8Array; Size: Integer); virtual; + /// + /// Counter with CBC-MAC Mode, details are implemented in DECCipherModesCCM + /// + procedure DecodeCCM(Source, Dest: PUInt8Array; Size: Integer); virtual; {$IFDEF DEC3_CMCTS} /// /// double CBC @@ -400,7 +416,7 @@ TDECCipherModes = class(TDECCipher, IDECAuthenticatedCipher) /// in addition to encrypting it. This property contains the data which /// shall be authenticated in parallel to the encryption. Some authenticated /// modes still generate an authentication result even if no additional - /// data is supplied via this property, e.g. cmGCM is one of those. + /// data is supplied via this property, e.g. cmGCM or cmCCM are such ones. /// property DataToAuthenticate : TBytes read GetDataToAuthenticate @@ -410,10 +426,8 @@ TDECCipherModes = class(TDECCipher, IDECAuthenticatedCipher) /// Some block chaining modes have the ability to authenticate the message /// in addition to encrypting it. /// Represents the length of CalculatedAuthenticationResult in bit, values - /// as per specification are: 128, 120, 112, 104, or 96 bit. For certain - /// applications, they may be 64 or 32 as well, but the use of these two - /// tag lengths constrains the length of the input data and the lifetime - /// of the key. + /// as per specification can be retrieved via + /// GetStandardAuthenticationTagBitLengths method /// property AuthenticationResultBitLength : Integer read GetAuthenticationResultBitLength @@ -477,27 +491,33 @@ procedure TDECCipherModes.ReportInvalidMessageLength(Cipher: TDECCipher); procedure TDECCipherModes.SetDataToAuthenticate(const Value: TBytes); begin - if (FMode = cmGCM) then - FGCM.DataToAuthenticate := Value - else - raise EDECCipherException.CreateResFmt(@sInvalidModeForMethod, ['cmGCM']); + case FMode of + cmGCM: FGCM.DataToAuthenticate := Value; + cmCCM: FCCM.DataToAuthenticate := Value; + else + raise EDECCipherException.CreateResFmt(@sInvalidModeForMethod, ['cmGCM or cmCCM']); + end; end; procedure TDECCipherModes.SetExpectedAuthenticationResult(const Value: TBytes); begin - if (FMode = cmGCM) then - FGCM.ExpectedAuthenticationTag := Value - else - raise EDECCipherException.CreateResFmt(@sInvalidModeForMethod, ['cmGCM']); + case FMode of + cmGCM: FGCM.ExpectedAuthenticationTag := Value; + cmCCM: FCCM.ExpectedAuthenticationTag := Value; + else + raise EDECCipherException.CreateResFmt(@sInvalidModeForMethod, ['cmGCM or cmCCM']); + end; end; procedure TDECCipherModes.SetAuthenticationResultBitLength( const Value: Integer); begin - if (FMode = cmGCM) then - FGCM.AuthenticationTagBitLength := Value - else - raise EDECCipherException.CreateResFmt(@sInvalidModeForMethod, ['cmGCM']); + case FMode of + cmGCM: FGCM.AuthenticationTagBitLength := Value; + cmCCM: FCCM.AuthenticationTagBitLength := Value; + else + raise EDECCipherException.CreateResFmt(@sInvalidModeForMethod, ['cmGCM or cmCCM']); + end; end; procedure TDECCipherModes.Encode(const Source; var Dest; DataSize: Integer); @@ -518,6 +538,7 @@ procedure TDECCipherModes.Encode(const Source; var Dest; DataSize: Integer); cmCFS8: EncodeCFS8(@Source, @Dest, DataSize); cmCFSx: EncodeCFSx(@Source, @Dest, DataSize); cmGCM : EncodeGCM(@Source, @Dest, DataSize); + cmCCM : EncodeCCM(@Source, @Dest, DataSize); end; end; @@ -689,24 +710,29 @@ procedure TDECCipherModes.EncodeOFBx(Source, Dest: PUInt8Array; Size: Integer); function TDECCipherModes.GetDataToAuthenticate: TBytes; begin - if (FMode = cmGCM) then - Result := FGCM.DataToAuthenticate - else - raise EDECCipherException.CreateResFmt(@sInvalidModeForMethod, ['cmGCM']); + case FMode of + cmGCM: Result := FGCM.DataToAuthenticate; + cmCCM: Result := FCCM.DataToAuthenticate; + else + raise EDECCipherException.CreateResFmt(@sInvalidModeForMethod, ['cmGCM or cCCM']); + end; end; function TDECCipherModes.GetExpectedAuthenticationResult: TBytes; begin - if (FMode = cmGCM) then - Result := FGCM.ExpectedAuthenticationTag - else - raise EDECCipherException.CreateResFmt(@sInvalidModeForMethod, ['cmGCM']); + case FMode of + cmGCM: Result := FGCM.ExpectedAuthenticationTag; + cmCCM: Result := FCCM.ExpectedAuthenticationTag; + else + raise EDECCipherException.CreateResFmt(@sInvalidModeForMethod, ['cmGCM or cmCCM']); + end; end; function TDECCipherModes.GetStandardAuthenticationTagBitLengths: TStandardBitLengths; begin case FMode of cmGCM: Result := FGCM.GetStandardAuthenticationTagBitLengths; + cmCCM: Result := FCCM.GetStandardAuthenticationTagBitLengths; else begin SetLength(Result, 1); @@ -717,35 +743,49 @@ function TDECCipherModes.GetStandardAuthenticationTagBitLengths: TStandardBitLen function TDECCipherModes.GetAuthenticationResultBitLength: Integer; begin - if (FMode = cmGCM) then - Result := FGCM.AuthenticationTagBitLength - else - raise EDECCipherException.CreateResFmt(@sInvalidModeForMethod, ['cmGCM']); + case FMode of + cmGCM: Result := FGCM.AuthenticationTagBitLength; + cmCCM: Result := FCCM.AuthenticationTagBitLength; + else + raise EDECCipherException.CreateResFmt(@sInvalidModeForMethod, ['cmGCM or cmCCM']); + end; end; function TDECCipherModes.GetCalcAuthenticatonResult: TBytes; begin - if (FMode = cmGCM) then - Result := FGCM.CalculatedAuthenticationTag - else - raise EDECCipherException.CreateResFmt(@sInvalidModeForMethod, ['cmGCM']); + case FMode of + cmGCM: Result := FGCM.CalculatedAuthenticationTag; + cmCCM: Result := FCCM.CalculatedAuthenticationTag; + else + raise EDECCipherException.CreateResFmt(@sInvalidModeForMethod, ['cmGCM or cmCCM']); + end; end; procedure TDECCipherModes.InitMode; begin - if FMode = TCipherMode.cmGCM then + if FMode in [TCipherMode.cmGCM, TCipherMode.cmCCM] then begin - if Context.BlockSize = 16 then - FGCM := TGCM.Create + if (Context.BlockSize = 16) then + begin + case FMode of + cmGCM: FGCM := TGCM.Create; + cmCCM: FCCM := TCCM.Create; + end; + end else - // GCM requires a cipher with 128 bit block size + // GCM and CCM require a cipher with 128 bit block size raise EDECCipherException.CreateResFmt(@sInvalidBlockSize, [128, GetEnumName(TypeInfo(TCipherMode), Integer(FMode))]); end else + begin if Assigned(FGCM) then FreeAndNil(FGCM); + + if Assigned(FCCM) then + FreeAndNil(FCCM); + end; end; procedure TDECCipherModes.EncodeCFSx(Source, Dest: PUInt8Array; Size: Integer); @@ -839,22 +879,19 @@ procedure TDECCipherModes.EncodeCTSx(Source, Dest: PUInt8Array; Size: Integer); end; procedure TDECCipherModes.EncodeGCM(Source, Dest: PUInt8Array; Size: Integer); -var - PlainText, - CipherText : TBytes; begin - if (Size > 0) then - begin - PlainText := TBytes(@Source^); - CipherText := TBytes(@Dest^); - end - else - begin - SetLength(PlainText, 0); - SetLength(CipherText, 0); - end; + if (Size < 0) then + Size := 0; - FGCM.EncodeGCM(PlainText, CipherText, Size); + FGCM.Encode(Source, Dest, Size); +end; + +procedure TDECCipherModes.EncodeCCM(Source, Dest: PUInt8Array; Size: Integer); +begin + if (Size < 0) then + Size := 0; + + FCCM.Encode(Source, Dest, Size); end; {$IFDEF DEC3_CMCTS} @@ -900,6 +937,7 @@ procedure TDECCipherModes.Decode(const Source; var Dest; DataSize: Integer); cmCFS8: DecodeCFS8(@Source, @Dest, DataSize); cmCFSx: DecodeCFSx(@Source, @Dest, DataSize); cmGCM : DecodeGCM(@Source, @Dest, DataSize); + cmCCM : DecodeCCM(@Source, @Dest, DataSize); end; end; @@ -939,22 +977,19 @@ procedure TDECCipherModes.DecodeECBx(Source, Dest: PUInt8Array; Size: Integer); end; procedure TDECCipherModes.DecodeGCM(Source, Dest: PUInt8Array; Size: Integer); -var - PlainText, - CipherText : TBytes; begin - if (Size > 0) then - begin - PlainText := TBytes(@Source^); - CipherText := TBytes(@Dest^); - end - else - begin - SetLength(PlainText, 0); - SetLength(CipherText, 0); - end; + if (Size < 0) then + Size := 0; + + FGCM.Decode(Source, Dest, Size); +end; + +procedure TDECCipherModes.DecodeCCM(Source, Dest: PUInt8Array; Size: Integer); +begin + if (Size < 0) then + Size := 0; - FGCM.DecodeGCM(PlainText, CipherText, Size); + FCCM.Decode(Source, Dest, Size); end; procedure TDECCipherModes.DecodeCFB8(Source, Dest: PUInt8Array; Size: Integer); @@ -1103,6 +1138,7 @@ procedure TDECCipherModes.DecodeOFBx(Source, Dest: PUInt8Array; Size: Integer); destructor TDECCipherModes.Destroy; begin FGCM.Free; + FCCM.Free; inherited; end; @@ -1111,11 +1147,18 @@ procedure TDECCipherModes.Done; begin inherited; - if (FMode = cmGCM) then - begin - if (length(FGCM.ExpectedAuthenticationTag) > 0) and - (not IsEqual(FGCM.ExpectedAuthenticationTag, FGCM.CalculatedAuthenticationTag)) then - raise EDECCipherAuthenticationException.CreateRes(@sInvalidAuthenticationValue); + case FMode of + cmGCM : begin + if (length(FGCM.ExpectedAuthenticationTag) > 0) and + (not IsEqual(FGCM.ExpectedAuthenticationTag, FGCM.CalculatedAuthenticationTag)) then + raise EDECCipherAuthenticationException.CreateRes(@sInvalidAuthenticationValue); + end; + + cmCCM : begin + if (length(FCCM.ExpectedAuthenticationTag) > 0) and + (not IsEqual(FCCM.ExpectedAuthenticationTag, FCCM.CalculatedAuthenticationTag)) then + raise EDECCipherAuthenticationException.CreateRes(@sInvalidAuthenticationValue); + end; end; end; @@ -1123,8 +1166,10 @@ procedure TDECCipherModes.OnAfterInitVectorInitialization(const OriginalInitVect begin inherited; - if (FMode = cmGCM) then - FGCM.Init(self.DoEncode, OriginalInitVector); + case FMode of + cmGCM: FGCM.Init(self.DoEncode, OriginalInitVector); + cmCCM: FCCM.Init(self.DoEncode, OriginalInitVector); + end; end; procedure TDECCipherModes.DecodeCFSx(Source, Dest: PUInt8Array; Size: Integer); diff --git a/Source/DECCipherModesCCM.pas b/Source/DECCipherModesCCM.pas new file mode 100644 index 00000000..3f835f67 --- /dev/null +++ b/Source/DECCipherModesCCM.pas @@ -0,0 +1,399 @@ +{***************************************************************************** + 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. +*****************************************************************************} + +// Based on: aes_ccm.pas from Wolfgang Erhard +unit DECCipherModesCCM; + +interface + +{$INCLUDE DECOptions.inc} + +uses + {$IFDEF FPC} + SysUtils, + {$ELSE} + System.SysUtils, + {$ENDIF} + DECTypes, + DECAuthenticatedCipherModesBase; + +resourcestring + sWrongNonceLength = 'Wrong nonce/IV length. Must be between 7 and 13'; + sWrongNonceLengthDetailed = 'Nonce longer than 15 byte. Act. length: %0:d'; + sWrongCCMAuthLength = 'CCM authentication tag needs to have a length of ' + + '4, 6, 8, 10, 12, 14 or 16 byte'; + +type + /// + /// Counter with CBC-MAC Mode specific methods + /// + TCCM = class(TAuthenticatedCipherModesBase) + strict private + /// + /// Unmodified initialization vector + /// + FOrigInitVector : TBytes; + /// + /// Init vector which is modified during processing + /// + FInitVector : TBlock16Byte; + + /// + /// Encodes or decodes a block of data using the supplied cipher + /// + /// + /// Plain text to encrypt or decrypt, depending on encode parameter + /// + /// + /// Ciphertext or plaintext after encryption or decryption, depending on + /// encode parameter + /// + /// + /// Number of bytes to encrypt or decrypt + /// + /// + /// When true it is encrypting data, else it is descrypting data + /// + procedure EncodeDecode(Source, Dest: PUInt8Array; Size: Integer; Encode: Boolean); + strict protected + /// + /// Defines the length of the resulting authentication value in bit. + /// + /// + /// Sets the length of Authenticaton_tag in bit, values as per specification + /// are: 32, 48, 64, 80, 96, 112, 128 + /// + procedure SetAuthenticationTagLength(const Value: UInt32); override; + public + /// + /// Savely clear any buffers + /// + destructor Destroy; override; + /// + /// Should be called when starting encryption/decryption in order to + /// initialize internal tables etc. + /// + /// + /// Encryption method of the cypher used + /// + /// + /// Initialization vector + /// + procedure Init(EncryptionMethod : TEncodeDecodeMethod; + InitVector : TBytes); override; + + /// + /// Encodes a block of data using the supplied cipher + /// + /// + /// Plain text to encrypt + /// + /// + /// Ciphertext after encryption + /// + /// + /// Number of bytes to encrypt + /// + procedure Encode(Source, + Dest : PUInt8Array; + Size : Integer); override; + /// + /// Decodes a block of data using the supplied cipher + /// + /// + /// Encrypted ciphertext to decrypt + /// + /// + /// Plaintext after decryption + /// + /// + /// Number of bytes to decrypt + /// + procedure Decode(Source, + Dest : PUInt8Array; + Size : Integer); override; + + /// + /// Returns a list of authentication tag lengths explicitely specified by + /// the official specification of the standard. + /// + /// + /// List of bit lengths + /// + function GetStandardAuthenticationTagBitLengths:TStandardBitLengths; override; + end; + +implementation + +uses + DECUtil; + +const + /// + /// Size of one block to be processed in byte + /// + cBlockSize = SizeOf(TBlock16Byte); + +resourcestring + /// + /// Exception raised when a size but no source data pointer was passed + /// + sInvalidSourcePointer = 'No source data pointer passed'; + +procedure TCCM.Decode(Source, Dest: PUInt8Array; Size: Integer); +begin + EncodeDecode(Source, Dest, Size, false); +end; + +destructor TCCM.Destroy; +begin + if (Length(FOrigInitVector) > 0) then + ProtectBytes(FOrigInitVector); + + ProtectBuffer(FInitVector, SizeOf(FInitVector)); + ProtectBytes(FCalcAuthenticationTag); + ProtectBytes(FExpectedAuthenticationTag); + + inherited; +end; + +procedure TCCM.Encode(Source, Dest: PUInt8Array; Size: Integer); +begin + EncodeDecode(Source, Dest, Size, true); +end; + +procedure TCCM.EncodeDecode(Source, Dest: PUInt8Array; + Size: Integer; + Encode: Boolean); +var + ecc : TBlock16Byte; // encrypted counter + FixedTagBuf : TBlock16Byte; // during calculation buffer of authentication tag + // might need to be bigger than then one specified + // by the user + len : Int32; + k, L : UInt16; + b : UInt8; + pb : PByte; + AuthDataLen : Integer; // Length of data to authenticate in bytes + InitVectLen : Integer; // Length of the init vector in bytes + + Buf : TBlock16Byte; + + // Increment CTR[15]..CTR[16-L] + procedure IncCTR(var CTR: TBlock16Byte); + var + j: integer; + begin + for j := 15 downto 16-L do + begin + if (CTR[j] = $FF) then + CTR[j] := 0 + else + begin + inc(CTR[j]); + exit; + end; + end; + end; + +begin + if (Size > 0) and + ((not Assigned(Source)) or (not Assigned(Dest))) then + raise EDECCipherException.Create(sInvalidSourcePointer); + + AuthDataLen := Length(FDataToAuthenticate); + InitVectLen := Length(FOrigInitVector); + + // calculate L value = max(number of bytes needed for sLen, 15-nLen) + len := Size; + L := 0; + while (len > 0) do + begin + inc(L); + len := len shr 8; + end; + + // Length of nonce (= init vector) is InitVectLen + if (InitVectLen + L > 15) then + raise EDECNonceLengthException.CreateFmt(sWrongNonceLengthDetailed, + [InitVectLen + L]); + + // Force Length(FInitVector) + L = 15. Since nLen <= 13, L is at least 2 + L := 15 - InitVectLen; + + // compose B_0 = Flags | Nonce N | l(m) + // octet 0: Flags = 64*HdrPresent | 8*((tLen-2) div 2 | (L-1) + + if (AuthDataLen > 0) then + b := 64 + else + b := 0; + + // Typecast for L-1 possible, since L is at least 2, see comment above + Buf[0] := b or ((FCalcAuthenticationTagLength-2) shl 2) or UInt16(L-1); + // octets 1..15-L is nonce + pb := @FOrigInitvector[0]; + for k := 1 to 15-L do + begin + Buf[k] := pb^; + inc(pb); + end; + + // octets 16-L .. 15: l(m) + len := Size; + for k := 1 to L do + begin + Buf[16-k] := len and $FF; + len := len shr 8; + end; + + FEncryptionMethod(@Buf[0], @Buf[0], Length(Buf)); + + // process header + if (AuthDataLen > 0) then + begin + // octets 0..1: encoding of hLen. Note: since we allow max $FEFF bytes + // only these two octets are used. Generally up to 10 octets are needed. + Buf[0] := Buf[0] xor (AuthDataLen shr 8); + Buf[1] := Buf[1] xor (AuthDataLen and $FF); + // now append the hdr data + len := 2; + pb := @FDataToAuthenticate[0]; + for k:= 1 to AuthDataLen do + begin + if (len = 16) then + begin + FEncryptionMethod(@Buf[0], @Buf[0], Length(Buf)); + len := 0; + end; + Buf[len] := Buf[len] xor pb^; + inc(len); + inc(pb); + end; + + if (len <> 0) then + FEncryptionMethod(@Buf[0], @Buf[0], Length(Buf)); + end; + + // setup the counter for source text processing + pb := @FOrigInitVector[0]; + FInitVector[0] := (L-1) and $FF; + for k := 1 to 15 do + begin + if (k < 16-L) then + begin + FInitVector[k] := pb^; + inc(pb); + end + else + FInitVector[k] := 0; + end; + + // process full source text blocks + while (Size >= 16) do + begin + IncCTR(FInitVector); + FEncryptionMethod(@FInitVector[0], @ecc[0], Length(FInitVector)); + + if Encode then + begin + XORBuffers(Source[0], Buf[0], 16, Buf[0]); + XORBuffers(Source[0], ecc[0], 16, Dest[0]); + end + else + begin + XORBuffers(Source[0], ecc[0], 16, Dest[0]); + XORBuffers(Dest[0], Buf[0], 16, Buf[0]); + end; + + FEncryptionMethod(@Buf[0], @Buf[0], Length(Buf)); + + inc(PByte(Source), cBlockSize); + inc(PByte(Dest), cBlockSize); + dec(Size, cBlockSize); + end; + + if (Size > 0) then + begin + // handle remaining bytes of source text + IncCTR(FInitVector); + + FEncryptionMethod(@FInitVector[0], @ecc[0], Length(ecc)); + + for k := 0 to UInt16(Size - 1) do + begin + if Encode then + begin + b := PByte(Source)^; + PByte(Dest)^ := b xor ecc[k]; + end + else + begin + b := PByte(Source)^ xor ecc[k]; + PByte(Dest)^ := b; + end; + Buf[k] := Buf[k] xor b; + inc(PByte(Source)); + inc(PByte(Dest)); + end; + + FEncryptionMethod(@Buf[0], @Buf[0], Length(Buf)); + end; + + // setup counter for the tag (zero the count) + for k := 15 downto 16-L do + FInitVector[k] := 0; + + FEncryptionMethod(@FInitVector[0], @ecc[0], Length(ecc)); + + // store the TAG/Authentication result value + XORBuffers(Buf[0], ecc[0], 16, FixedTagBuf); + Move(FixedTagBuf[0], FCalcAuthenticationTag[0], length(FCalcAuthenticationTag)); + + ProtectBuffer(Buf, SizeOf(Buf)); +end; + +function TCCM.GetStandardAuthenticationTagBitLengths: TStandardBitLengths; +begin + SetLength(Result, 7); + Result := [32, 48, 64, 80, 96, 112, 128]; +end; + +procedure TCCM.SetAuthenticationTagLength(const Value: UInt32); +begin + if not (Value in [32, 48, 64, 80, 96, 112, 128]) then + raise EDECAuthLengthException.Create(sWrongCCMAuthLength); + + FCalcAuthenticationTagLength := Value shr 3; + + SetLength(FCalcAuthenticationTag, FCalcAuthenticationTagLength); +end; + +procedure TCCM.Init(EncryptionMethod : TEncodeDecodeMethod; + InitVector : TBytes); +begin + Assert(Length(InitVector) > 0, 'No init vector specified'); + + if (Length(InitVector) < 7) or (Length(InitVector) > 13) then + raise EDECNonceLengthException.Create(sWrongNonceLength); + + inherited; + + FOrigInitVector := InitVector; +end; + +end. diff --git a/Source/DECCipherModesGCM.pas b/Source/DECCipherModesGCM.pas index 0e819637..ed2cde55 100644 --- a/Source/DECCipherModesGCM.pas +++ b/Source/DECCipherModesGCM.pas @@ -26,7 +26,8 @@ interface {$ELSE} System.SysUtils, {$ENDIF} - DECTypes; + DECTypes, + DECAuthenticatedCipherModesBase; type /// @@ -47,28 +48,11 @@ interface /// P16ByteArray = ^T16ByteArray; - /// - /// A methopd of this type needs to be supplied for encrypting or decrypting - /// a block via this GCM algorithm. The method is implemented as a parameter, - /// to avoid the need to bring TGCM in the inheritance chain. TGCM thus can - /// be used for composition instead of inheritance. - /// - /// - /// Data to be encrypted - /// - /// - /// In this memory the encrypted result will be written - /// - /// - /// Size of source in byte - /// - TEncodeDecodeMethod = procedure(Source, Dest: Pointer; Size: Integer) of Object; - /// /// Galois Counter Mode specific methods /// - TGCM = class(TObject) - private + TGCM = class(TAuthenticatedCipherModesBase) + strict private /// /// Empty value? /// @@ -91,29 +75,6 @@ TGCM = class(TObject) /// FE_K_Y0 : T128; - /// - /// The data which shall be authenticated in parallel to the encryption - /// - FDataToAuthenticate : TBytes; - /// - /// Length of the authentication tag to generate in byte - /// - FCalcAuthenticationTagLength : UInt32; - /// - /// Generated authentication tag - /// - FCalcAuthenticationTag : TBytes; - /// - /// Expected authentication tag value, will be compared with actual value - /// when decryption finished. - /// - FExpectedAuthenticationTag : TBytes; - - /// - /// Reference to the encode method of the actual cipher used - /// - FEncryptionMethod : TEncodeDecodeMethod; - /// /// XOR implementation for unsigned 128 bit numbers /// @@ -159,7 +120,7 @@ TGCM = class(TObject) /// /// Result of the XOR operation /// - procedure XOR_ArrayWithT128(const x: TBytes; XIndex, Count: UInt64; y: T128; var Result: TBytes); inline; + procedure XOR_ArrayWithT128(x: PUInt8Array; XIndex, Count: UInt64; y: T128; Result: PUInt8Array); inline; /// /// XORs all elements of the precalculated matrix with the value passed @@ -213,24 +174,6 @@ TGCM = class(TObject) /// procedure INCR(var Y : T128); - /// - /// Defines the length of the resulting authentication value in bit. - /// - /// - /// Sets the length of Authenticaton_tag in bit, values as per specification - /// are: 128, 120, 112, 104, or 96 bit. For certain applications, they - /// may be 64 or 32 as well, but the use of these two tag lengths - /// constrains the length of the input data and the lifetime of the key. - /// - procedure SetAuthenticationTagLength(const Value: UInt32); - /// - /// Returns the length of the calculated authehtication value in bit - /// - /// - /// Length of the calculated authentication value in bit - /// - function GetAuthenticationTagBitLength: UInt32; - /// /// Calculates the hash value /// @@ -238,6 +181,9 @@ TGCM = class(TObject) /// Specifys the data for which an authentication value shall be /// calculated. It is allowed to be nil. /// + /// + /// Length of the data to authenticate in byte + /// /// /// Encrypted data used in the calculation /// @@ -247,8 +193,10 @@ TGCM = class(TObject) /// /// Calculated raw hash value which will later get returned as AuthenticatedTag /// - function CalcGaloisHash(AuthenticatedData, Ciphertext : TBytes; CiphertextSize: - Integer): T128; + function CalcGaloisHash(AuthenticatedData : PUInt8Array; + AuthLen : Integer; + Ciphertext : PUInt8Array; + CiphertextSize : Integer): T128; /// /// Encrypts a T128 value using the encryption method specified on init @@ -260,6 +208,17 @@ TGCM = class(TObject) /// Encrypted value /// function EncodeT128(Value: T128): T128; + strict protected + /// + /// Defines the length of the resulting authentication value in bit. + /// + /// + /// Sets the length of Authenticaton_tag in bit, values as per specification + /// are: 128, 120, 112, 104, or 96 bit. For certain applications, they + /// may be 64 or 32 as well, but the use of these two tag lengths + /// constrains the length of the input data and the lifetime of the key. + /// + procedure SetAuthenticationTagLength(const Value: UInt32); override; public /// /// Should be called when starting encryption/decryption in order to @@ -272,7 +231,7 @@ TGCM = class(TObject) /// Initialization vector /// procedure Init(EncryptionMethod : TEncodeDecodeMethod; - InitVector : TBytes); + InitVector : TBytes); override; /// /// Encodes a block of data using the supplied cipher /// @@ -285,9 +244,9 @@ TGCM = class(TObject) /// /// Number of bytes to encrypt /// - procedure EncodeGCM(Source, - Dest : TBytes; - Size : Integer); + procedure Encode(Source, + Dest : PUInt8Array; + Size : Integer); override; /// /// Decodes a block of data using the supplied cipher /// @@ -300,9 +259,9 @@ TGCM = class(TObject) /// /// Number of bytes to decrypt /// - procedure DecodeGCM(Source, - Dest : TBytes; - Size : Integer); + procedure Decode(Source, + Dest : PUInt8Array; + Size : Integer); override; /// /// Returns a list of authentication tag lengths explicitely specified by @@ -311,38 +270,7 @@ TGCM = class(TObject) /// /// List of bit lengths /// - function GetStandardAuthenticationTagBitLengths:TStandardBitLengths; - - /// - /// The data which shall be authenticated in parallel to the encryption - /// - property DataToAuthenticate : TBytes - read FDataToAuthenticate - write FDataToAuthenticate; - /// - /// Sets the length of AuthenticatonTag in bit, values as per official - /// specification are: 128, 120, 112, 104, or 96 bit. For certain - /// applications, they may be 64 or 32 as well, but the use of these two - /// tag lengths constrains the length of the input data and the lifetime - /// of the key. - /// - property AuthenticationTagBitLength : UInt32 - read GetAuthenticationTagBitLength - write SetAuthenticationTagLength; - /// - /// Calculated authentication value - /// - property CalculatedAuthenticationTag : TBytes - read FCalcAuthenticationTag - write FCalcAuthenticationTag; - - /// - /// Expected authentication tag value, will be compared with actual value - /// when decryption finished. - /// - property ExpectedAuthenticationTag : TBytes - read FExpectedAuthenticationTag - write FExpectedAuthenticationTag; + function GetStandardAuthenticationTagBitLengths:TStandardBitLengths; override; end; implementation @@ -359,7 +287,7 @@ function TGCM.XOR_PointerWithT128(const x : Pointer; y : T128): T128; Result[1] := P128(x)^[1] xor y[1]; end; -procedure TGCM.XOR_ArrayWithT128(const x: TBytes; XIndex, Count: UInt64; y: T128; var Result: TBytes); +procedure TGCM.XOR_ArrayWithT128(x: PUInt8Array; XIndex, Count: UInt64; y: T128; Result: PUInt8Array); var i : integer; by : P16ByteArray; @@ -367,7 +295,7 @@ procedure TGCM.XOR_ArrayWithT128(const x: TBytes; XIndex, Count: UInt64; y: T128 by := @y[0]; for i := 0 to Count-1 do begin - Result[XIndex] := x[XIndex] xor by[i]; + Result^[XIndex] := x^[XIndex] xor by[i]; inc(XIndex); end; end; @@ -506,13 +434,7 @@ procedure TGCM.Init(EncryptionMethod : TEncodeDecodeMethod; b : ^Byte; OldH : T128; begin - Assert(Assigned(EncryptionMethod), 'No encryption method specified'); - - // Clear calculated authentication value - if (Length(FCalcAuthenticationTag) > 0) then - FillChar(FCalcAuthenticationTag[0], Length(FCalcAuthenticationTag), #0); - - FEncryptionMethod := EncryptionMethod; + inherited; Nullbytes[0] := 0; Nullbytes[1] := 0; @@ -533,19 +455,19 @@ procedure TGCM.Init(EncryptionMethod : TEncodeDecodeMethod; b^ := 1; end else - FY := CalcGaloisHash(nil, InitVector, length(InitVector)); + FY := CalcGaloisHash(nil, 0, @InitVector[0], length(InitVector)); FEncryptionMethod(@FY[0], @FE_K_Y0[0], 16); end; -function TGCM.CalcGaloisHash(AuthenticatedData, Ciphertext : TBytes; +function TGCM.CalcGaloisHash(AuthenticatedData : PUInt8Array; AuthLen : integer; Ciphertext : PUInt8Array; CiphertextSize: Integer): T128; var AuthCipherLength : T128; x : T128; n : Uint64; - procedure encode(data : TBytes; dataSize: Integer); + procedure encode(data : PUInt8Array; dataSize: Integer); var i, mod_d, div_d, len_d : UInt64; hdata : T128; @@ -559,7 +481,7 @@ function TGCM.CalcGaloisHash(AuthenticatedData, Ciphertext : TBytes; begin for i := 0 to div_d-1 do begin - x := poly_mult_H(XOR_PointerWithT128(@data[n], x )); + x := poly_mult_H(XOR_PointerWithT128(@data^[n], x )); inc(n, 16); end; end; @@ -568,7 +490,7 @@ function TGCM.CalcGaloisHash(AuthenticatedData, Ciphertext : TBytes; if mod_d > 0 then begin hdata := nullbytes; - Move(data[n], hdata[0], mod_d); + Move(data^[n], hdata[0], mod_d); x := poly_mult_H(XOR_T128(hdata, x)); end; end; @@ -576,18 +498,21 @@ function TGCM.CalcGaloisHash(AuthenticatedData, Ciphertext : TBytes; begin x := nullbytes; - encode(AuthenticatedData, length(AuthenticatedData)); - Assert(length(Ciphertext) >= CiphertextSize); + if AuthLen > 0 then + encode(@AuthenticatedData[0], AuthLen); + //Assert(length(Ciphertext) >= CiphertextSize); encode(Ciphertext, CiphertextSize); - SetAuthenticationCipherLength(AuthCipherLength, length(AuthenticatedData) shl 3, CiphertextSize shl 3); + SetAuthenticationCipherLength(AuthCipherLength, AuthLen shl 3, CiphertextSize shl 3); Result := poly_mult_H(XOR_T128(AuthCipherLength, x)); end; -procedure TGCM.DecodeGCM(Source, Dest: TBytes; Size: Integer); +procedure TGCM.Decode(Source, Dest: PUInt8Array; Size: Integer); var i, j, BlockCount : UInt64; a_tag : T128; + pDataToAuth : PUInt8Array; + pSrc : PUInt8Array; begin i := 0; BlockCount := Size div 16; @@ -595,17 +520,25 @@ procedure TGCM.DecodeGCM(Source, Dest: TBytes; Size: Integer); for j := 1 to BlockCount do begin INCR(FY); - P128(@Dest[i])^ := XOR_PointerWithT128(@Source[i], EncodeT128(FY)); + P128(@Dest^[i])^ := XOR_PointerWithT128(@Source^[i], EncodeT128(FY)); inc(i, 16); end; if i < Size then begin INCR(FY); - XOR_ArrayWithT128(Source, i, UInt64(Size)-i, EncodeT128(FY), Dest); + XOR_ArrayWithT128(@Source^[0], i, UInt64(Size)-i, EncodeT128(FY), @Dest^[0]); end; - a_tag := XOR_T128(CalcGaloisHash(DataToAuthenticate, Source, Size), FE_K_Y0); + pDataToAuth := nil; + if Length(DataToAuthenticate) > 0 then + pDataToAuth := @DataToAuthenticate[0]; + pSrc := nil; + if Size > 0 then + pSrc := @source[0]; + + a_tag := XOR_T128(CalcGaloisHash(pDataToAuth, Length(DataToAuthenticate), + pSrc, Size), FE_K_Y0); Setlength(FCalcAuthenticationTag, FCalcAuthenticationTagLength); if (FCalcAuthenticationTagLength > 0) then @@ -622,10 +555,11 @@ procedure TGCM.DecodeGCM(Source, Dest: TBytes; Size: Integer); // SetLength(plaintext, 0); // NIST FAIL => pt='' end; -procedure TGCM.EncodeGCM(Source, Dest: TBytes; Size: Integer); +procedure TGCM.Encode(Source, Dest: PUInt8Array; Size: Integer); var i, j, div_len_plain : UInt64; AuthTag : T128; + pDataToAuth : PUInt8Array; begin i := 0; div_len_plain := Size div 16; @@ -634,7 +568,7 @@ procedure TGCM.EncodeGCM(Source, Dest: TBytes; Size: Integer); begin INCR(FY); - P128(@Dest[i])^ := XOR_PointerWithT128(@Source[i], EncodeT128(FY)); + P128(@Dest^[i])^ := XOR_PointerWithT128(@Source^[i], EncodeT128(FY)); inc(i,16); end; @@ -645,7 +579,10 @@ procedure TGCM.EncodeGCM(Source, Dest: TBytes; Size: Integer); XOR_ArrayWithT128(Source, i, UInt64(Size)-i, EncodeT128(FY), Dest); end; - AuthTag := XOR_T128(CalcGaloisHash(DataToAuthenticate, Dest, Size), FE_K_Y0); + pDataToAuth := nil; + if Length(DataToAuthenticate) > 0 then + pDataToAuth := @DataToAuthenticate[0]; + AuthTag := XOR_T128(CalcGaloisHash(pDataToAuth, Length(DataToAuthenticate), @Dest[0], Size), FE_K_Y0); Setlength(FCalcAuthenticationTag, FCalcAuthenticationTagLength); if (FCalcAuthenticationTagLength > 0) then Move(AuthTag[0], FCalcAuthenticationTag[0], FCalcAuthenticationTagLength); @@ -656,11 +593,6 @@ function TGCM.EncodeT128(Value: T128): T128; FEncryptionMethod(@Value[0], @Result[0], 16); end; -function TGCM.GetAuthenticationTagBitLength: UInt32; -begin - Result := FCalcAuthenticationTagLength shl 3; -end; - function TGCM.GetStandardAuthenticationTagBitLengths: TStandardBitLengths; begin SetLength(Result, 5); diff --git a/Source/DECCiphers.pas b/Source/DECCiphers.pas index d91593ad..2ffb4347 100644 --- a/Source/DECCiphers.pas +++ b/Source/DECCiphers.pas @@ -3004,21 +3004,21 @@ procedure TCipher_Rijndael.DoEncode(Source, Dest: Pointer; Size: Integer); D2 := D1 xor P[3]; PUInt32Array(Dest)[0] := (Rijndael_S[0, A2 and $FF] or - Rijndael_S[0, B2 shr 8 and $FF] shl 8 or - Rijndael_S[0, C2 shr 16 and $FF] shl 16 or - Rijndael_S[0, D2 shr 24 ] shl 24) xor P[4]; + Rijndael_S[0, B2 shr 8 and $FF] shl 8 or + Rijndael_S[0, C2 shr 16 and $FF] shl 16 or + Rijndael_S[0, D2 shr 24 ] shl 24) xor P[4]; PUInt32Array(Dest)[1] := (Rijndael_S[0, B2 and $FF] or - Rijndael_S[0, C2 shr 8 and $FF] shl 8 or - Rijndael_S[0, D2 shr 16 and $FF] shl 16 or - Rijndael_S[0, A2 shr 24 ] shl 24) xor P[5]; + Rijndael_S[0, C2 shr 8 and $FF] shl 8 or + Rijndael_S[0, D2 shr 16 and $FF] shl 16 or + Rijndael_S[0, A2 shr 24 ] shl 24) xor P[5]; PUInt32Array(Dest)[2] := (Rijndael_S[0, C2 and $FF] or - Rijndael_S[0, D2 shr 8 and $FF] shl 8 or - Rijndael_S[0, A2 shr 16 and $FF] shl 16 or - Rijndael_S[0, B2 shr 24 ] shl 24) xor P[6]; + Rijndael_S[0, D2 shr 8 and $FF] shl 8 or + Rijndael_S[0, A2 shr 16 and $FF] shl 16 or + Rijndael_S[0, B2 shr 24 ] shl 24) xor P[6]; PUInt32Array(Dest)[3] := (Rijndael_S[0, D2 and $FF] or - Rijndael_S[0, A2 shr 8 and $FF] shl 8 or - Rijndael_S[0, B2 shr 16 and $FF] shl 16 or - Rijndael_S[0, C2 shr 24 ] shl 24) xor P[7]; + Rijndael_S[0, A2 shr 8 and $FF] shl 8 or + Rijndael_S[0, B2 shr 16 and $FF] shl 16 or + Rijndael_S[0, C2 shr 24 ] shl 24) xor P[7]; end; procedure TCipher_Rijndael.DoDecode(Source, Dest: Pointer; Size: Integer); diff --git a/Source/DECFormat.pas b/Source/DECFormat.pas index e274a5cd..76659777 100644 --- a/Source/DECFormat.pas +++ b/Source/DECFormat.pas @@ -2133,9 +2133,14 @@ class procedure TFormat_UTF8.DoDecode(const Source; var Dest: TBytes; Size: Inte p := Pointer(@Source); if p = nil then SetLength(Dest, 0) - else begin + else + begin SetString(Raw, PChar(@Source), Size div sizeof(Char)); + {$IFNDEF FPC} Dest := System.SysUtils.BytesOf(UTF8Encode(Raw)); + {$ELSE} + Dest := BytesOf(UTF8Encode(Raw)); + {$ENDIF} end; end; diff --git a/Source/DECHash.pas b/Source/DECHash.pas index 6237c4df..f63a9438 100644 --- a/Source/DECHash.pas +++ b/Source/DECHash.pas @@ -1174,7 +1174,7 @@ TBCryptBSDData = record var /// - /// The calculated hash value + /// The calculated hash value. /// Should have been 192 bit = 24 byte, but original author's /// imnplementation had a flaw not returning the last byte, which has /// been kept instead of fixing it. Thus DigestSize returns 23 instead @@ -1262,8 +1262,18 @@ TBCryptBSDData = record function SplitTestVector(const Vector : string; var SplittedData : TBCryptBSDData):Boolean; strict protected + /// + /// Prepares internal data structures etc. + /// procedure DoInit; override; + /// + /// Empty on purpose, as bcrypt needs to know the input length. Thus + /// calculation is done directly in method Calc. + /// procedure DoTransform(Buffer: PUInt32Array); override; + /// + /// Remove any sensitive data from memory + /// procedure DoDone; override; {$Region CryptFormat} @@ -1409,8 +1419,17 @@ TBCryptBSDData = record /// procedure Calc(const Data; DataSize: Integer); override; + /// + /// Returns the calculated hash + /// function Digest: PUInt8Array; override; + /// + /// Returns the length of the calculated hash in byte + /// class function DigestSize: UInt32; override; + /// + /// Size of the blocks to be processed in bytes + /// class function BlockSize: UInt32; override; /// @@ -1548,11 +1567,14 @@ procedure THash_MD2.DoDone; var Remain: Integer; begin - Remain := FBufferSize - FBufferIndex; - FillChar(FBuffer[FBufferIndex], Remain, Remain); - DoTransform(Pointer(FBuffer)); - Move(FDigest[48], FBuffer^, FBufferSize); - DoTransform(Pointer(FBuffer)); + if Assigned(FBuffer) then + begin + Remain := FBufferSize - FBufferIndex; + FillChar(FBuffer[FBufferIndex], Remain, Remain); + DoTransform(Pointer(FBuffer)); + Move(FDigest[48], FBuffer^, FBufferSize); + DoTransform(Pointer(FBuffer)); + end; end; function THash_MD2.Digest: PUInt8Array; @@ -1592,17 +1614,21 @@ procedure THashBaseMD4.DoDone; RaiseHashOverflowError; if FPaddingByte = 0 then FPaddingByte := $80; - FBuffer[FBufferIndex] := FPaddingByte; - Inc(FBufferIndex); - if FBufferIndex > FBufferSize - 8 then + + if Assigned(FBuffer) then begin + FBuffer[FBufferIndex] := FPaddingByte; + Inc(FBufferIndex); + if FBufferIndex > FBufferSize - 8 then + begin + FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); + DoTransform(Pointer(FBuffer)); + FBufferIndex := 0; + end; FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); + Move(FCount, FBuffer[FBufferSize - 8], 8); DoTransform(Pointer(FBuffer)); - FBufferIndex := 0; end; - FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); - Move(FCount, FBuffer[FBufferSize - 8], 8); - DoTransform(Pointer(FBuffer)); end; function THashBaseMD4.Digest: PUInt8Array; @@ -2777,19 +2803,23 @@ procedure THash_SHA0.DoDone; RaiseHashOverflowError; if FPaddingByte = 0 then FPaddingByte := $80; - FBuffer[FBufferIndex] := FPaddingByte; - Inc(FBufferIndex); - if FBufferIndex > FBufferSize - 8 then + + if Assigned(FBuffer) then begin + FBuffer[FBufferIndex] := FPaddingByte; + Inc(FBufferIndex); + if FBufferIndex > FBufferSize - 8 then + begin + FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); + DoTransform(Pointer(FBuffer)); + FBufferIndex := 0; + end; FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); + PUInt32(@FBuffer[FBufferSize - 8])^ := SwapUInt32(FCount[1]); + PUInt32(@FBuffer[FBufferSize - 4])^ := SwapUInt32(FCount[0]); DoTransform(Pointer(FBuffer)); - FBufferIndex := 0; + SwapUInt32Buffer(FDigest, FDigest, SizeOf(FDigest) div 4); end; - FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); - PUInt32(@FBuffer[FBufferSize - 8])^ := SwapUInt32(FCount[1]); - PUInt32(@FBuffer[FBufferSize - 4])^ := SwapUInt32(FCount[0]); - DoTransform(Pointer(FBuffer)); - SwapUInt32Buffer(FDigest, FDigest, SizeOf(FDigest) div 4); end; class function THash_SHA0.DigestSize: UInt32; @@ -2965,21 +2995,26 @@ procedure THash_SHA384.DoDone; begin if FPaddingByte = 0 then FPaddingByte := $80; - FBuffer[FBufferIndex] := FPaddingByte; - Inc(FBufferIndex); - if FBufferIndex > FBufferSize - 16 then + + if Assigned(FBuffer) then begin + FBuffer[FBufferIndex] := FPaddingByte; + Inc(FBufferIndex); + if FBufferIndex > FBufferSize - 16 then + begin + FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); + DoTransform(Pointer(FBuffer)); + FBufferIndex := 0; + end; FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); + SwapUInt32Buffer(FCount, FCount, 4); + PUInt32(@FBuffer[FBufferSize - 16])^ := FCount[3]; + PUInt32(@FBuffer[FBufferSize - 12])^ := FCount[2]; + PUInt32(@FBuffer[FBufferSize - 8])^ := FCount[1]; + PUInt32(@FBuffer[FBufferSize - 4])^ := FCount[0]; DoTransform(Pointer(FBuffer)); - FBufferIndex := 0; end; - FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); - SwapUInt32Buffer(FCount, FCount, 4); - PUInt32(@FBuffer[FBufferSize - 16])^ := FCount[3]; - PUInt32(@FBuffer[FBufferSize - 12])^ := FCount[2]; - PUInt32(@FBuffer[FBufferSize - 8])^ := FCount[1]; - PUInt32(@FBuffer[FBufferSize - 4])^ := FCount[0]; - DoTransform(Pointer(FBuffer)); + SwapInt64Buffer(FDigest, FDigest, SizeOf(FDigest) div 8); end; @@ -3105,7 +3140,7 @@ procedure THashBaseHaval.DoTransform3(Buffer: PUInt32Array); begin T := C and (E xor D) xor G and A xor F and B xor E; T := (T shr 7 or T shl 25) + (H shr 11 or H shl 21) + Buffer[I]; - H := G; G := F; F := E; E := D; D := C; C := B; B := A; A := T; + H := G; G := F; F := E; E := D; D := C; C := B; B := A; A := T; end; for I := 0 to 31 do @@ -3293,19 +3328,23 @@ procedure THashBaseHaval.DoDone; RaiseHashOverflowError; if FPaddingByte = 0 then FPaddingByte := $01; - FBuffer[FBufferIndex] := FPaddingByte; - Inc(FBufferIndex); - if FBufferIndex > FBufferSize - 10 then + + if Assigned(FBuffer) then begin + FBuffer[FBufferIndex] := FPaddingByte; + Inc(FBufferIndex); + if FBufferIndex > FBufferSize - 10 then + begin + FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex - 10, 0); + DoTransform(Pointer(FBuffer)); + FBufferIndex := 0; + end; FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex - 10, 0); + T := (DigestSize shl 9) or (UInt32(FRounds) shl 3) or 1; + Move(T, FBuffer[FBufferSize - 10], SizeOf(T)); + Move(FCount, FBuffer[FBufferSize - 8], 8); DoTransform(Pointer(FBuffer)); - FBufferIndex := 0; end; - FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex - 10, 0); - T := (DigestSize shl 9) or (UInt32(FRounds) shl 3) or 1; - Move(T, FBuffer[FBufferSize - 10], SizeOf(T)); - Move(FCount, FBuffer[FBufferSize - 8], 8); - DoTransform(Pointer(FBuffer)); case DigestSize of 16: begin @@ -4099,18 +4138,22 @@ procedure THashBaseWhirlpool.DoDone; begin if FPaddingByte = 0 then FPaddingByte := $80; - FBuffer[FBufferIndex] := FPaddingByte; - Inc(FBufferIndex); - if FBufferIndex > FBufferSize - 32 then + + if Assigned(FBuffer) then begin + FBuffer[FBufferIndex] := FPaddingByte; + Inc(FBufferIndex); + if FBufferIndex > FBufferSize - 32 then + begin + FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); + DoTransform(Pointer(FBuffer)); + FBufferIndex := 0; + end; FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); + for I := 31 downto 0 do + FBuffer[63 - I] := PByteArray(@FCount)[I]; DoTransform(Pointer(FBuffer)); - FBufferIndex := 0; end; - FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); - for I := 31 downto 0 do - FBuffer[63 - I] := PByteArray(@FCount)[I]; - DoTransform(Pointer(FBuffer)); end; function THashBaseWhirlpool.Digest: PUInt8Array; @@ -4258,18 +4301,22 @@ procedure THash_Square.DoDone; begin if FPaddingByte = 0 then FPaddingByte := $80; - FBuffer[FBufferIndex] := FPaddingByte; - Inc(FBufferIndex); - if FBufferIndex > FBufferSize - 8 then + + if Assigned(FBuffer) then begin + FBuffer[FBufferIndex] := FPaddingByte; + Inc(FBufferIndex); + if FBufferIndex > FBufferSize - 8 then + begin + FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); + DoTransform(Pointer(FBuffer)); + FBufferIndex := 0; + end; FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); + for I := 7 downto 0 do + FBuffer[15 - I] := PByteArray(@FCount[0])[I]; DoTransform(Pointer(FBuffer)); - FBufferIndex := 0; end; - FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); - for I := 7 downto 0 do - FBuffer[15 - I] := PByteArray(@FCount[0])[I]; - DoTransform(Pointer(FBuffer)); end; function THash_Square.Digest: PUInt8Array; @@ -4319,16 +4366,20 @@ function THashBaseSnefru.GetRounds: UInt32; procedure THashBaseSnefru.DoDone; begin - if FBufferIndex > 0 then + if Assigned(FBuffer) then begin + if FBufferIndex > 0 then + begin + FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); + DoTransform(Pointer(FBuffer)); + FBufferIndex := 0; + end; FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); + PUInt32(@FBuffer[FBufferSize - 8])^ := SwapUInt32(FCount[1]); + PUInt32(@FBuffer[FBufferSize - 4])^ := SwapUInt32(FCount[0]); DoTransform(Pointer(FBuffer)); - FBufferIndex := 0; end; - FillChar(FBuffer[FBufferIndex], FBufferSize - FBufferIndex, 0); - PUInt32(@FBuffer[FBufferSize - 8])^ := SwapUInt32(FCount[1]); - PUInt32(@FBuffer[FBufferSize - 4])^ := SwapUInt32(FCount[0]); - DoTransform(Pointer(FBuffer)); + SwapUInt32Buffer(FDigest, FDigest, 8); end; diff --git a/Source/DECHashAuthentication.pas b/Source/DECHashAuthentication.pas index f12f95d7..30d43a2c 100644 --- a/Source/DECHashAuthentication.pas +++ b/Source/DECHashAuthentication.pas @@ -305,7 +305,9 @@ TDECHashAuthentication = class(TDECHash) /// /// /// Optional parameter: can be used to specify a different default value - /// for the index variable used in the algorithm. + /// for the index variable used in the algorithm. The value of index is + /// being hashed for each processed byte to further modify the state of + /// the hash algorithm instance internally used. /// /// /// Exception raised if DataSize and SeedSize are both 0 @@ -334,7 +336,9 @@ TDECHashAuthentication = class(TDECHash) /// /// /// Optional parameter: can be used to specify a different default value - /// for the index variable used in the algorithm. + /// for the index variable used in the algorithm. The value of index is + /// being hashed for each processed byte to further modify the state of + /// the hash algorithm instance internally used. /// /// /// Exception raised if DataSize and SeedSize are both 0 @@ -367,8 +371,10 @@ TDECHashAuthentication = class(TDECHash) /// Size of the returned mask in bytes /// /// - /// Looks like this is a salt applied to each byte of output data? -{ TODO : Clarify this parameter } + /// Optional parameter: can be used to specify a different default value + /// for the index variable used in the algorithm. The value of index is + /// being hashed for each processed byte to further modify the state of + /// the hash algorithm instance internally used. /// /// /// Mask such that one cannot determine the data which had been given to @@ -395,8 +401,10 @@ TDECHashAuthentication = class(TDECHash) /// Size of the returned mask in bytes /// /// - /// Looks like this is a salt applied to each byte of output data? -{ TODO : Clarify this parameter } + /// Optional parameter: can be used to specify a different default value + /// for the index variable used in the algorithm. The value of index is + /// being hashed for each processed byte to further modify the state of + /// the hash algorithm instance internally used. /// /// /// Mask such that one cannot determine the data which had been given to @@ -666,7 +674,7 @@ TDECPasswordHash = class(TDECHashAuthentication, IDECHashPassword) /// /// /// If the algorithm on which this is being used is a Crypt/BSD compatible - /// password hash algorithm the ID is returned otherwise an empty string. + /// password hash algorithm the ID is returned, otherwise an empty string. /// class function GetCryptID:string; virtual; diff --git a/Source/DECHashBase.pas b/Source/DECHashBase.pas index 37f75819..05470268 100644 --- a/Source/DECHashBase.pas +++ b/Source/DECHashBase.pas @@ -186,7 +186,9 @@ TDECHash = class(TDECObject, IDECHash) /// /// 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. + /// Additionaly calls the algorithm spercific DoDone method. Since this is + /// automatically called in all public methods except Calc it should not + /// be called by user code. /// procedure Done; diff --git a/Source/DECOptions.inc b/Source/DECOptions.inc index da05d4bd..eceec526 100644 --- a/Source/DECOptions.inc +++ b/Source/DECOptions.inc @@ -119,7 +119,7 @@ /// {$IF DECLARED(FireMonkeyVersion)} {$DEFINE FMXTranslateableExceptions} -{$IFEND} { TODO: convert to $ENDIF when raising minimum supported version to XE4+} +{$ENDIF} //------------------------------------------------------------------------------ // Do NOT change anything below! //------------------------------------------------------------------------------ diff --git a/Source/DECRandom.pas b/Source/DECRandom.pas index f3074a3d..785121af 100644 --- a/Source/DECRandom.pas +++ b/Source/DECRandom.pas @@ -34,21 +34,6 @@ interface {$ENDIF} DECHashBase, DECHash; -/// -/// Create a seed for the random number generator from system time and -/// PerformanceCounter. -/// -/// -/// 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. -/// -/// -/// Created seed value -/// -function RandomSystemTime: Int64; - /// /// Fills the provided buffer with random values. If the DoRandomBuffer /// variable is assigned (which is usually the case because DoBuffer is @@ -123,6 +108,23 @@ procedure RandomSeed(const Buffer; Size: Integer); overload; /// procedure RandomSeed; overload; +// Random number seed value determination + +/// +/// Create a seed for the random number generator from system time and +/// PerformanceCounter. +/// +/// +/// 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. +/// +/// +/// Created seed value +/// +function RandomSystemTime: Int64; + type /// /// Type for the random buffer generation @@ -178,20 +180,7 @@ procedure RandomSeed; overload; implementation uses - {$IFDEF DELPHI_2010_UP} - System.Diagnostics - {$ELSE} - {$IFDEF FPC} - {$IFDEF MSWINDOWS} - Windows - {$ELSE} - LclIntf - {$ENDIF} - {$ELSE} - Winapi.Windows - {$ENDIF} - {$ENDIF} - ; + System.Diagnostics; {$IFOPT Q+}{$DEFINE RESTORE_OVERFLOWCHECKS}{$Q-}{$ENDIF} {$IFOPT R+}{$DEFINE RESTORE_RANGECHECKS}{$R-}{$ENDIF} @@ -222,40 +211,6 @@ implementation /// 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; /// /// Simplistic algorithm for filling a buffer with random numbers. This @@ -343,6 +298,41 @@ procedure RandomSeed(const Buffer; Size: Integer); end; end; +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; + procedure RandomSeed; begin RandomSeed('', -1); diff --git a/Source/DECTypes.pas b/Source/DECTypes.pas index 9c7ec0b2..9fe62d5c 100644 --- a/Source/DECTypes.pas +++ b/Source/DECTypes.pas @@ -53,6 +53,11 @@ interface PUInt64Array = ^TUInt64Array; TUInt64Array = array[0..1023] of UInt64; + /// + /// AES works on 16 byte blocks, some others too + /// + TBlock16Byte = Array[0..15] of UInt8; + /// /// Declared here because it is used by Blowfish cipher and BCrypt hash /// diff --git a/Source/DECUtil.pas b/Source/DECUtil.pas index a47882c1..6649b694 100644 --- a/Source/DECUtil.pas +++ b/Source/DECUtil.pas @@ -281,10 +281,38 @@ function StringToBytes(const Str: string): TBytes; inline; /// function IsEqual(const a, b : TBytes ):Boolean; +/// +/// Calculates the shannon entropy of the byte array. AI generated. +/// +/// +/// Byte array on which to calculate the entropy +/// +/// +/// Shannon entropy +/// 8.0 = perfect distribution +/// 7.0 = plausibly random +/// <5.0 = very suspicious +/// +function ShannonEntropy(const ABytes: TBytes): Double; + implementation uses - DECUtilRawByteStringHelper, DECTypes; + {$IFDEF DELPHI_2010_UP} + System.Diagnostics, + {$ELSE} + {$IFDEF FPC} + {$IFDEF MSWINDOWS} + Windows, + {$ELSE} + LclIntf, + {$ENDIF} + {$ELSE} + Winapi.Windows, + {$ENDIF} + {$ENDIF} + DECUtilRawByteStringHelper, + DECTypes; const // Bit Lookup Table - see 'Bit Twiddling Hacks' by Sean Eron Anderson @@ -680,4 +708,26 @@ function IsEqual(const a, b : TBytes):Boolean; Result := true; end; +function ShannonEntropy(const ABytes: TBytes): Double; +var + freq: array[0..255] of Double; + b: Byte; + p: Double; + i: Integer; +begin + Result := 0; + for i := 0 to Length(freq)-1 do + freq[i] := 0; + + for b in ABytes do + freq[b] := freq[b] + 1; + + for i := 0 to 255 do + begin + p := freq[i] / Length(ABytes); + if p > 0 then + Result := Result - p * Ln(p) / Ln(2); + end; +end; + end. diff --git a/Source/_DECCipherModesGCM.pas b/Source/_DECCipherModesGCM.pas new file mode 100644 index 00000000..d378e895 --- /dev/null +++ b/Source/_DECCipherModesGCM.pas @@ -0,0 +1,857 @@ +{***************************************************************************** + 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 DECCipherModesGCM; + +interface + +{$INCLUDE DECOptions.inc} + +uses + {$IFDEF FPC} + SysUtils, + {$ELSE} + System.SysUtils, + {$ENDIF} + DECTypes; + +type + /// + /// 128 bit unsigned integer + /// + T128 = array[0..1] of UInt64; + /// + /// pointer to an 128 bit unsigned integer + /// + P128 = ^T128; + + /// + /// Array of 16 bytes + /// + T16ByteArray = array[0..15] of Byte; + /// + /// Pointer to an array of 16 bytes + /// + P16ByteArray = ^T16ByteArray; + + /// + /// A methopd of this type needs to be supplied for encrypting or decrypting + /// a block via this GCM algorithm. The method is implemented as a parameter, + /// to avoid the need to bring TGCM in the inheritance chain. TGCM thus can + /// be used for composition instead of inheritance. + /// + /// + /// Data to be encrypted + /// + /// + /// In this memory the encrypted result will be written + /// + /// + /// Size of source in byte + /// + TEncodeDecodeMethod = procedure(Source, Dest: Pointer; Size: Integer) of Object; + + /// + /// Galois Counter Mode specific methods + /// + TGCM = class(TObject) + private + /// + /// Empty value? + /// + nullbytes : T128; + /// + /// Table with precalculated values + /// + FM : array[0..15,0..255] of T128; + + /// + /// Required for creating the table and encryption at least + /// + FH : T128; + /// + /// Calculated in initialization + /// + FY : T128; + /// + /// Calculated in initialization + /// + FE_K_Y0 : T128; + + /// + /// The data which shall be authenticated in parallel to the encryption + /// + FDataToAuthenticate : TBytes; + /// + /// Length of the authentication tag to generate in byte + /// + FCalcAuthenticationTagLength : UInt32; + /// + /// Generated authentication tag + /// + FCalcAuthenticationTag : TBytes; + /// + /// Expected authentication tag value, will be compared with actual value + /// when decryption finished. + /// + FExpectedAuthenticationTag : TBytes; + + /// + /// Reference to the encode method of the actual cipher used + /// + FEncryptionMethod : TEncodeDecodeMethod; + + /// + /// XOR implementation for unsigned 128 bit numbers + /// + /// + /// First number to xor + /// + /// + /// Second number to xor the first with + /// + /// + /// x xor y + /// + function XOR_T128(const x, y: T128): T128; inline; + /// + /// XOR implementation for a pointer and an unsigned 128 bit number + /// + /// + /// Pointer on a T128 typed number to xor with y + /// + /// + /// Second number to xor the first with + /// + /// + /// x xor y + /// + function XOR_PointerWithT128(const x: Pointer; y: T128 ): T128; inline; + /// + /// XORs the bytes given in a byte array with a T128 number given + /// + /// + /// Bytes which shall be XORed with the T128 number + /// + /// + /// Starting index within x from which onwards to XOR + /// + /// + /// Number of bytes from x beginning at XIndex to XOR + /// + /// + /// Value to XOR the bytes from y with. XOR is done bytewise for each + /// byte of y + /// + /// + /// Result of the XOR operation + /// + procedure XOR_ArrayWithT128(const x: TBytes; XIndex, Count: UInt64; y: T128; var Result: TBytes); overload; //inline; + procedure XOR_ArrayWithT128(const x: PUInt8Array; XIndex, Count: UInt64; y: T128; Result: PUInt8Array); overload; + + /// + /// XORs all elements of the precalculated matrix with the value passed + /// + /// + /// Value who's two parts shall be XORed with the two parts of the + /// matrix each. + /// + /// + /// result of the XOR Operation + /// + function poly_mult_H(const hx: T128) : T128; inline; + + /// + /// Encodes the 64 bit lengths of DataToAuthenticate and of the cipher + /// text into a T128 value, swapping the bytes in the process. + /// + /// + /// Result of the operation + /// + /// + /// Length of the data to authenticate in byte + /// + /// + /// Length of the ciphertext in byte + /// + procedure SetAuthenticationCipherLength(var x : T128; + AuthDataLength, CipherTextLength : UInt64); inline; + + /// + /// Calculates a table with precalculated values which speeds up + /// operations later. The initialized table is the FM field. + /// + /// + /// Start value for the precalculation + /// + procedure GenerateTableM8Bit(const H: T128); //inline; + /// + /// Performs a right shift of 1 of all bytes in an 128 bit variable + /// + /// + /// Variable on which the right shift is being performed + /// + procedure ShiftRight(var rx: T128); //inline; + + /// + /// Incremepts the last 4 bytes of the index 0 part + /// + /// + /// Value to increment, this is the return value as well. + /// + procedure INCR(var Y : T128); + + /// + /// Defines the length of the resulting authentication value in bit. + /// + /// + /// Sets the length of Authenticaton_tag in bit, values as per specification + /// are: 128, 120, 112, 104, or 96 bit. For certain applications, they + /// may be 64 or 32 as well, but the use of these two tag lengths + /// constrains the length of the input data and the lifetime of the key. + /// + procedure SetAuthenticationTagLength(const Value: UInt32); + /// + /// Returns the length of the calculated authehtication value in bit + /// + /// + /// Length of the calculated authentication value in bit + /// + function GetAuthenticationTagBitLength: UInt32; + + /// + /// Calculates the hash value + /// + /// + /// Specifys the data for which an authentication value shall be + /// calculated. It is allowed to be nil. + /// + /// + /// Encrypted data used in the calculation + /// + /// + /// Length of the ciphertext in bytes. Use when reading part of array. + /// + /// + /// Calculated raw hash value which will later get returned as AuthenticatedTag + /// + function CalcGaloisHash(AuthenticatedData, Ciphertext : TBytes; CiphertextSize: + Integer): T128; overload; + + /// + /// Calculates the hash value + /// + /// + /// Specifys the data for which an authentication value shall be + /// calculated. It is allowed to be nil. + /// + /// + /// Encrypted data used in the calculation + /// + /// + /// Length of the ciphertext in bytes. Use when reading part of array. + /// + /// + /// Calculated raw hash value which will later get returned as AuthenticatedTag + /// + function CalcGaloisHash(AuthenticatedData: TBytes; Ciphertext : PUInt8Array; CiphertextSize: + Integer): T128; overload; + + /// + /// Encrypts a T128 value using the encryption method specified on init + /// + /// + /// Value to be encrypted + /// + /// + /// Encrypted value + /// + function EncodeT128(Value: T128): T128; + public + /// + /// Should be called when starting encryption/decryption in order to + /// initialize internal tables etc. + /// + /// + /// Encryption method of the cypher used + /// + /// + /// Initialization vector + /// + procedure Init(EncryptionMethod : TEncodeDecodeMethod; + InitVector : TBytes); +// /// +// /// Encodes a block of data using the supplied cipher +// /// +// /// +// /// Plain text to encrypt +// /// +// /// +// /// Ciphertext after encryption +// /// +// /// +// /// Number of bytes to encrypt +// /// +// procedure EncodeGCM(Source, +// Dest : TBytes; +// Size : Integer); + /// + /// Encodes a block of data using the supplied cipher + /// + /// + /// Plain text to encrypt + /// + /// + /// Ciphertext after encryption + /// + /// + /// Number of bytes to encrypt + /// + procedure EncodeGCM(Source, + Dest : PUInt8Array; + Size : Integer); + /// + /// Decodes a block of data using the supplied cipher + /// + /// + /// Encrypted ciphertext to decrypt + /// + /// + /// Plaintext after decryption + /// + /// + /// Number of bytes to decrypt + /// + procedure DecodeGCM(Source, + Dest : TBytes; + Size : Integer); + + /// + /// Returns a list of authentication tag lengths explicitely specified by + /// the official specification of the standard. + /// + /// + /// List of bit lengths + /// + function GetStandardAuthenticationTagBitLengths:TStandardBitLengths; + + /// + /// The data which shall be authenticated in parallel to the encryption + /// + property DataToAuthenticate : TBytes + read FDataToAuthenticate + write FDataToAuthenticate; + /// + /// Sets the length of AuthenticatonTag in bit, values as per official + /// specification are: 128, 120, 112, 104, or 96 bit. For certain + /// applications, they may be 64 or 32 as well, but the use of these two + /// tag lengths constrains the length of the input data and the lifetime + /// of the key. + /// + property AuthenticationTagBitLength : UInt32 + read GetAuthenticationTagBitLength + write SetAuthenticationTagLength; + /// + /// Calculated authentication value + /// + property CalculatedAuthenticationTag : TBytes + read FCalcAuthenticationTag + write FCalcAuthenticationTag; + + /// + /// Expected authentication tag value, will be compared with actual value + /// when decryption finished. + /// + property ExpectedAuthenticationTag : TBytes + read FExpectedAuthenticationTag + write FExpectedAuthenticationTag; + end; + +implementation + +function TGCM.XOR_T128(const x, y : T128): T128; +begin + Result[0] := x[0] xor y[0]; + Result[1] := x[1] xor y[1]; +end; + +function TGCM.XOR_PointerWithT128(const x : Pointer; y : T128): T128; +begin + Result[0] := P128(x)^[0] xor y[0]; + Result[1] := P128(x)^[1] xor y[1]; +end; + +procedure TGCM.XOR_ArrayWithT128(const x: TBytes; XIndex, Count: UInt64; y: T128; var Result: TBytes); +var + i : integer; + by : P16ByteArray; +begin + by := @y[0]; + for i := 0 to Count-1 do + begin + Result[XIndex] := x[XIndex] xor by[i]; + inc(XIndex); + end; +end; + +procedure TGCM.XOR_ArrayWithT128(const x: PUInt8Array; XIndex, Count: UInt64; y: T128; Result: PUInt8Array); +var + i : integer; + by : P16ByteArray; +begin + by := @y[0]; + for i := 0 to Count-1 do + begin + Result^[XIndex] := x^[XIndex] xor by[i]; + inc(XIndex); + end; +end; + +function TGCM.poly_mult_H(const hx : T128): T128; +var + i : integer; + x : P16ByteArray; +begin + x := @hx[0]; + Result := FM[0, x[0]]; + + for i := 1 to 15 do + begin + Result[0] := Result[0] xor FM[i, x[i]][0]; + Result[1] := Result[1] xor FM[i, x[i]][1]; + end; +end; + +procedure TGCM.SetAuthenticationCipherLength(var x : T128; + AuthDataLength, CipherTextLength : UInt64); +var + i : integer; + hx : P16ByteArray; +begin + hx := @x[0]; + // al: + x := nullbytes; + i := 7; + + repeat + hx[i] := AuthDataLength mod 256; + AuthDataLength := AuthDataLength shr 8; + dec(i); + until AuthDataLength = 0; + + // cl: + i := 15; + + repeat + hx[i] := CipherTextLength mod 256; + CipherTextLength := CipherTextLength shr 8; + dec(i); + until CipherTextLength = 0; +end; + +procedure TGCM.GenerateTableM8Bit(const H : T128); +var + hbit, hbyte, i, j : integer; + HP : T128; + bHP : P16ByteArray; + mask : byte; +begin + HP := H; + bHP := @HP[0]; + for hbyte := 0 to 15 do + begin + mask := 128; + for hbit := 0 to 7 do + begin + FM[hbyte, mask] := HP; + + if (bHP[15] and 1 = 0) then + ShiftRight(HP) + else + begin + ShiftRight(HP); + bHP[0] := bHP[0] xor $e1; + end; + + mask := mask shr 1; + end; + end; + + for hbyte := 0 to 15 do + begin + i := 2; + + while i <= 128 do + begin + for j := 1 to i-1 do + FM[hbyte, i+j] := XOR_T128(FM[hbyte, i], FM[hbyte, j]); + i := i*2; + end; + + FM[hbyte, 0] := nullbytes; + end; +end; + +procedure TGCM.ShiftRight(var rx : T128); +var + x : P16ByteArray; + i : integer; +begin + x := @rx[0]; + + for i := 15 downto 1 do + x[i] := (x[i] shr 1) or ((x[i-1] and 1) shl 7); + + x[0] := x[0] shr 1; +end; + +procedure TGCM.SetAuthenticationTagLength(const Value: UInt32); +begin + FCalcAuthenticationTagLength := Value shr 3; + SetLength(FCalcAuthenticationTag, FCalcAuthenticationTagLength); +end; + +procedure TGCM.INCR(var Y : T128); +var + bY : P16ByteArray; +begin + bY := @Y[0]; + + {$IFOPT Q+}{$DEFINE RESTORE_OVERFLOWCHECKS}{$Q-}{$ENDIF} + {$Q-} + inc(bY[15]); + if bY[15] = 0 then + begin + inc(bY[14]); + + if bY[14] = 0 then + begin + inc(bY[13]); + + if bY[13] = 0 then + inc(bY[12]); + end; + end; + {$IFDEF RESTORE_OVERFLOWCHECKS}{$Q+}{$ENDIF} +end; + +procedure TGCM.Init(EncryptionMethod : TEncodeDecodeMethod; + InitVector : TBytes); +var + b : ^Byte; + OldH : T128; +begin + Assert(Assigned(EncryptionMethod), 'No encryption method specified'); + + // Clear calculated authentication value + if (Length(FCalcAuthenticationTag) > 0) then + FillChar(FCalcAuthenticationTag[0], Length(FCalcAuthenticationTag), #0); + + FEncryptionMethod := EncryptionMethod; + + Nullbytes[0] := 0; + Nullbytes[1] := 0; + + OldH := FH; + EncryptionMethod(@Nullbytes[0], @FH[0], 16); + + // Only generate the table when not already generated + if (OldH[0] <> FH[0]) or (OldH[1] <> FH[1]) then + GenerateTableM8Bit(FH); + + if length(InitVector) = 12 then + begin + FY[1] := 0; + Move(InitVector[0], FY[0], 12); + b := @FY[0]; + inc(b, 15); + b^ := 1; + end + else + FY := CalcGaloisHash(nil, InitVector, length(InitVector)); + + FEncryptionMethod(@FY[0], @FE_K_Y0[0], 16); +end; + +function TGCM.CalcGaloisHash(AuthenticatedData, Ciphertext : TBytes; + CiphertextSize: Integer): T128; +var + AuthCipherLength : T128; + x : T128; + n : Uint64; + + procedure encode(data : TBytes; dataSize: Integer); + var + i, mod_d, div_d, len_d : UInt64; + hdata : T128; + begin + len_d := dataSize; + if (len_d > 0) then + begin + n := 0; + div_d := len_d div 16; + if div_d > 0 then + begin + for i := 0 to div_d-1 do + begin + x := poly_mult_H(XOR_PointerWithT128(@data[n], x )); + inc(n, 16); + end; + end; + + mod_d := len_d mod 16; + if mod_d > 0 then + begin + hdata := nullbytes; + Move(data[n], hdata[0], mod_d); + x := poly_mult_H(XOR_T128(hdata, x)); + end; + end; + end; + +begin + x := nullbytes; + encode(AuthenticatedData, length(AuthenticatedData)); + Assert(length(Ciphertext) >= CiphertextSize); + encode(Ciphertext, CiphertextSize); + SetAuthenticationCipherLength(AuthCipherLength, length(AuthenticatedData) shl 3, CiphertextSize shl 3); + + Result := poly_mult_H(XOR_T128(AuthCipherLength, x)); +end; + +function TGCM.CalcGaloisHash(AuthenticatedData: TBytes; Ciphertext : PUInt8Array; + CiphertextSize: Integer): T128; +var + AuthCipherLength : T128; + x : T128; + n : Uint64; + + procedure encode(data : PUInt8Array; dataSize: Integer); + var + i, mod_d, div_d, len_d : UInt64; + hdata : T128; + begin + len_d := dataSize; + if (len_d > 0) then + begin + n := 0; + div_d := len_d div 16; + if div_d > 0 then + begin + for i := 0 to div_d-1 do + begin + x := poly_mult_H(XOR_PointerWithT128(@data^[n], x )); + inc(n, 16); + end; + end; + + mod_d := len_d mod 16; + if mod_d > 0 then + begin + hdata := nullbytes; + Move(data^[n], hdata[0], mod_d); + x := poly_mult_H(XOR_T128(hdata, x)); + end; + end; + end; + +begin + x := nullbytes; + + if (length(AuthenticatedData) > 0) then + encode(@AuthenticatedData[0], length(AuthenticatedData)); +// Assert(length(Ciphertext) >= CiphertextSize); + encode(Ciphertext, CiphertextSize); + SetAuthenticationCipherLength(AuthCipherLength, length(AuthenticatedData) shl 3, CiphertextSize shl 3); + + Result := poly_mult_H(XOR_T128(AuthCipherLength, x)); +end; + +procedure TGCM.DecodeGCM(Source, Dest: TBytes; Size: Integer); +var + i, j, BlockCount : UInt64; + a_tag : T128; +begin + i := 0; + BlockCount := Size div 16; + + for j := 1 to BlockCount do + begin + INCR(FY); + P128(@Dest[i])^ := XOR_PointerWithT128(@Source[i], EncodeT128(FY)); + inc(i, 16); + end; + + if i < Size then + begin + INCR(FY); + XOR_ArrayWithT128(Source, i, UInt64(Size)-i, EncodeT128(FY), Dest); + end; + + a_tag := XOR_T128(CalcGaloisHash(DataToAuthenticate, Source, Size), FE_K_Y0); + + Setlength(FCalcAuthenticationTag, FCalcAuthenticationTagLength); + if (FCalcAuthenticationTagLength > 0) then + Move(a_tag[0], FCalcAuthenticationTag[0], FCalcAuthenticationTagLength); + + // Check for correct authentication result is in Done of DECCipherModes + // if not IsEqual(FExpectedAuthenticationTag, FCalcAuthenticationTag) then + // raise EDECCipherAuthenticationException.CreateRes(@sInvalidAuthenticationValue); + + // In difference to the NIST recommendation we do not discard plaintext if + // authentication failed to make data recovery possible. But since we throw + // an exception the user will get notified that there's something wrong + // if not IsEqual(authenticaton_tag, ba_tag) then + // SetLength(plaintext, 0); // NIST FAIL => pt='' +end; + +//procedure TGCM.EncodeGCM(Source, Dest: TBytes; Size: Integer); +//var +// i, j, div_len_plain : UInt64; +// AuthTag : T128; +//begin +// i := 0; +// div_len_plain := Size div 16; +// +// for j := 1 to div_len_plain do +// begin +// INCR(FY); +// +// P128(@Dest[i])^ := XOR_PointerWithT128(@Source[i], EncodeT128(FY)); +// +// inc(i,16); +// end; +// +// if i < Size then +// begin +// INCR(FY); +// XOR_ArrayWithT128(Source, i, UInt64(Size)-i, EncodeT128(FY), Dest); +// end; +// +// AuthTag := XOR_T128(CalcGaloisHash(DataToAuthenticate, Dest, Size), FE_K_Y0); +// Setlength(FCalcAuthenticationTag, FCalcAuthenticationTagLength); +// if (FCalcAuthenticationTagLength > 0) then +// Move(AuthTag[0], FCalcAuthenticationTag[0], FCalcAuthenticationTagLength); +//end; + +procedure TGCM.EncodeGCM(Source, Dest: PUInt8Array; Size: Integer); +var + i, j, div_len_plain : UInt64; + AuthTag : T128; +begin + i := 0; + div_len_plain := Size div 16; + + for j := 1 to div_len_plain do + begin + INCR(FY); + + P128(@Dest[i])^ := XOR_PointerWithT128(@Source[i], EncodeT128(FY)); + + inc(i,16); + end; + + if i < Size then + begin + INCR(FY); + XOR_ArrayWithT128(Source, i, UInt64(Size)-i, EncodeT128(FY), Dest); + end; + + AuthTag := XOR_T128(CalcGaloisHash(DataToAuthenticate, Dest, Size), FE_K_Y0); + Setlength(FCalcAuthenticationTag, FCalcAuthenticationTagLength); + if (FCalcAuthenticationTagLength > 0) then + Move(AuthTag[0], FCalcAuthenticationTag[0], FCalcAuthenticationTagLength); +end; + +function TGCM.EncodeT128(Value: T128): T128; +begin + FEncryptionMethod(@Value[0], @Result[0], 16); +end; + +function TGCM.GetAuthenticationTagBitLength: UInt32; +begin + Result := FCalcAuthenticationTagLength shl 3; +end; + +function TGCM.GetStandardAuthenticationTagBitLengths: TStandardBitLengths; +begin + SetLength(Result, 5); + Result := [96, 104, 112, 120, 128]; +end; + +// +//function decrypt( const key, IV : TBytes; out plaintext : TBytes; const authenticated_data, +//ciphertext : TBytes; len_auth_tag : integer; const authenticaton_tag : TBytes ) : boolean; +//var +// i, j, div_len_ciph, len_ciph : Uint64; +// a_tag, E_K_Y0, Y, H : T128; +// bY : array[0..15] of byte absolute Y[0]; +// ba_Tag : TBytes; +// +// function equal( const a, b : TBytes ):boolean; +// begin +// if length(a) <> length(b) then Result := false +// else +// Result := CompareMem( @a[0], @b[0], length(a) ); +// end; +// +//begin +// len_auth_tag := len_auth_tag shr 3; +// +// E_Init( key ); +// H := E_Cipher( nullbytes ); +// Table_M_8Bit(H); +// +// len_ciph := length( ciphertext ); +// SetLength( plaintext, len_ciph ); +// +// if length(IV) = 12 then +// begin +// Y[1] := 0; +// Move( IV[0], Y[0], 12 ); +// bY[15] := 1; +// end +// else +// Y := CalcGaloisHash( H, nil, IV ); +// +// E_K_Y0 := E_Cipher( y ); +// +// i := 0; +// div_len_ciph := len_ciph div 16; +// for j := 1 to div_len_ciph do +// begin +// INCR( Y ); +// P128(@plaintext[i])^ := XOR_128_n( @ciphertext[i], E_cipher( Y ) ); +// inc(i,16); +// end; +// +// if i < len_ciph then +// begin +// INCR( Y ); +// XOR_128_n_l( ciphertext, i, len_ciph-i, E_cipher( Y ), plaintext ); +// end; +// +// a_tag := XOR_128( CalcGaloisHash( H, authenticated_data, ciphertext ), E_K_Y0 ); +// +// Setlength( ba_tag, len_auth_tag ); +// Move( a_tag[0], ba_tag[0], len_auth_tag ); +// +// Result := equal( authenticaton_tag, ba_tag ); +// if not Result then SetLength( plaintext, 0 ); // NIST FAIL => pt='' +//end; +// + +end. diff --git a/Unit Tests/DECDUnitTestSuite.dpr b/Unit Tests/DECDUnitTestSuite.dpr index 44ec045b..224f30ca 100644 --- a/Unit Tests/DECDUnitTestSuite.dpr +++ b/Unit Tests/DECDUnitTestSuite.dpr @@ -16,6 +16,7 @@ program DECDUnitTestSuite; {$ENDIF} uses +// FastMM4, Vcl.Forms, {$IFDEF TESTINSIGHT} TestInsight.Client, @@ -40,7 +41,9 @@ uses TestDECHashSHA3 in 'Tests\TestDECHashSHA3.pas', TestDECCipherModesGCM in 'Tests\TestDECCipherModesGCM.pas', TestDECZIPHelper in 'Tests\TestDECZIPHelper.pas', - TestDECCipherPaddings in 'Tests\TestDECCipherPaddings.pas'; + TestDECCipherPaddings in 'Tests\TestDECCipherPaddings.pas', + TestDECCipherModesCCM in 'Tests\TestDECCipherModesCCM.pas', + AuthenticatedCiphersCommonTestData in 'Tests\AuthenticatedCiphersCommonTestData.pas'; {$R *.RES} diff --git a/Unit Tests/DECDUnitTestSuite.dproj b/Unit Tests/DECDUnitTestSuite.dproj index 48958ad9..640c568f 100644 --- a/Unit Tests/DECDUnitTestSuite.dproj +++ b/Unit Tests/DECDUnitTestSuite.dproj @@ -1,7 +1,7 @@  {4117BDAD-9849-4F6E-8968-BB6B92C8AE7B} - 20.2 + 20.4 DECDUnitTestSuite.dpr True Debug @@ -162,6 +162,9 @@ + + + Base @@ -223,7 +226,19 @@ + + + DECDUnitTestSuite.exe + true + + + + + .\ + true + + 1 @@ -338,6 +353,16 @@ 1 + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + res\drawable-anydpi-v26 @@ -871,6 +896,9 @@ 1 + + 1 + @@ -941,6 +969,10 @@ Assets 1 + + Assets + 1 + @@ -951,6 +983,10 @@ Assets 1 + + Assets + 1 + @@ -1165,6 +1201,7 @@ + True diff --git a/Unit Tests/DECDUnitXTestSuite.dproj b/Unit Tests/DECDUnitXTestSuite.dproj index 6563539a..a0e4579c 100644 --- a/Unit Tests/DECDUnitXTestSuite.dproj +++ b/Unit Tests/DECDUnitXTestSuite.dproj @@ -1,7 +1,7 @@  {FEE36113-01B3-4DE2-B2BC-B4858EAD04A3} - 20.2 + 20.4 DECDUnitXTestSuite.dpr True Debug @@ -105,7 +105,7 @@ $(BDS)\bin\delphi_PROJECTICON.ico - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34 + package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=36 Debug android-support-v4.dex.jar;cloud-messaging.dex.jar;fmx.dex.jar;google-analytics-v2.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar;google-play-services.dex.jar DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;FmxTeeUI;FireDACIBDriver;fmx;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FMXTee;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage) @@ -117,7 +117,7 @@ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png - package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=34 + package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=;minSdkVersion=23;targetSdkVersion=36 Debug true Base @@ -152,6 +152,9 @@ (Ohne) 1033 false + 3 + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + none GUI;$(DCC_Define) @@ -194,6 +197,7 @@ + Base @@ -227,6 +231,10 @@ DECDUnitXTestSuite.dpr + + Microsoft Office 2000 Beispiele für gekapselte Komponenten für Automatisierungsserver + Microsoft Office XP Beispiele für gekapselte Komponenten für Automation Server + @@ -249,7 +257,19 @@ + + + DECDUnitXTestSuite.exe + true + + + + + .\ + true + + @@ -361,6 +381,16 @@ 1 + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + res\drawable-anydpi-v26 @@ -831,6 +861,9 @@ 1 + + 1 + @@ -869,6 +902,10 @@ Assets 1 + + Assets + 1 + @@ -879,6 +916,10 @@ Assets 1 + + Assets + 1 + @@ -1093,11 +1134,11 @@ + True True - False True True diff --git a/Unit Tests/DECDUnitXTestSuite.dproj.local b/Unit Tests/DECDUnitXTestSuite.dproj.local index cd86ea92..72cd09a6 100644 --- a/Unit Tests/DECDUnitXTestSuite.dproj.local +++ b/Unit Tests/DECDUnitXTestSuite.dproj.local @@ -24,6 +24,7 @@ + diff --git a/Unit Tests/HashTestDataGenerator/GenerateData.dproj b/Unit Tests/HashTestDataGenerator/GenerateData.dproj index de549f93..df32b15d 100644 --- a/Unit Tests/HashTestDataGenerator/GenerateData.dproj +++ b/Unit Tests/HashTestDataGenerator/GenerateData.dproj @@ -1,7 +1,7 @@  {84E1D523-B4D7-4EC3-84D9-AD83F9C02E34} - 20.2 + 20.4 None True Debug @@ -290,6 +290,16 @@ 1 + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + res\drawable-anydpi-v26 @@ -823,6 +833,9 @@ 1 + + 1 + @@ -893,6 +906,10 @@ Assets 1 + + Assets + 1 + @@ -903,6 +920,10 @@ Assets 1 + + Assets + 1 + @@ -1117,11 +1138,11 @@ + False False - False True False diff --git a/Unit Tests/Tests/AuthenticatedCiphersCommonTestData.pas b/Unit Tests/Tests/AuthenticatedCiphersCommonTestData.pas new file mode 100644 index 00000000..a76938a9 --- /dev/null +++ b/Unit Tests/Tests/AuthenticatedCiphersCommonTestData.pas @@ -0,0 +1,153 @@ +{***************************************************************************** + 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. +*****************************************************************************} + +/// +/// Common definitions used by all authenticated cipher modes tests, if possible. +/// The file loading for the individual algorithms has to be implemented in the +/// individual test unit for the algorith, because NIST doesn't use a 100% +/// identical file format for CCM and GCM. +/// +unit AuthenticatedCiphersCommonTestData; + +interface + +uses + Generics.Collections; + +type + /// + /// Test data for one single authenticated cipher test, all in HexL + /// + TSingleAuthenticatedTestData = record + /// + /// Encryption/decryption key + /// + CryptKey : RawByteString; + /// + /// Initialization vecotr + /// + InitVector : RawByteString; + /// + /// Plain Text: text to be encrypted, given in HexL + /// + PT : RawByteString; + /// + /// Additional Authenticated Data: the data which shall be authenticated + /// but not encrypted. + /// + AAD : RawByteString; + /// + /// Cipher Text: encrypted text, given in HexL + /// + CT : RawByteString; + /// + /// Calculated authenticated "tag" value + /// + TagResult : RawByteString; + /// + /// Used additional authenticated data for testing authentication failures. + /// Only filled when present in test data file. + /// + ModifiedAAD: RawByteString; + /// + /// Used ciphertext data for testing authentication failures. + /// Only filled when present in test data file. + /// + ModifiedCT: RawByteString; + + /// + /// Sets all fields and array entries to default values + /// + procedure Clear; + end; + + /// + /// Test data for one single GCM test + /// + TAuthenticatedCipherTestSetEntry = record + /// + /// Length of the encryption/decryption key in bit, determines the + /// algorithm used in case of AES (AES128, AES192, AES256) + /// + Keylen : UInt16; + /// + /// Length of the initialization vector in bit + /// + IVlen : UInt16; + /// + /// Length of the ? in bit + /// + PTlen : UInt16; + /// + /// Length of the ? in bit + /// + AADlen : UInt16; + /// + /// Length of the "tag" resulting from the authentication part in bit + /// + Taglen : UInt16; + + /// + /// The test data files provided contains one test for the meta data + /// specified above. This array holds the test data. + /// + TestData : array of TSingleAuthenticatedTestData; + + /// + /// Sets all fields and array entries to default values + /// + procedure Clear; + end; + + /// + /// List of loaded authentication cipher test vectors + /// + TAuthenticatedTestDataList = TList; + +implementation + +{ TSingleAuthenticatedTestData } + +procedure TSingleAuthenticatedTestData.Clear; +begin + CryptKey := ''; + InitVector := ''; + PT := ''; + AAD := ''; + CT := ''; + TagResult := ''; + ModifiedAAD := ''; + ModifiedCT := ''; +end; + +{ TAuthenticatedCipherTestSetEntry } + +procedure TAuthenticatedCipherTestSetEntry.Clear; +var + i : Integer; +begin + Keylen := 0; + IVlen := 0; + PTlen := 0; + AADlen := 0; + Taglen := 0; + + for i := Low(TestData) to High(TestData) do + TestData[i].Clear; +end; + +end. diff --git a/Unit Tests/Tests/TestDECCRC.pas b/Unit Tests/Tests/TestDECCRC.pas index 94c8da07..5a6c9d41 100644 --- a/Unit Tests/Tests/TestDECCRC.pas +++ b/Unit Tests/Tests/TestDECCRC.pas @@ -1027,7 +1027,7 @@ initialization {$IFDEF DUnitX} TDUnitX.RegisterTestFixture(TestCRC); {$ELSE} - RegisterTest(TestCRC.Suite); + RegisterTest('DEC CRC', TestCRC.Suite); {$ENDIF} end. diff --git a/Unit Tests/Tests/TestDECCipher.pas b/Unit Tests/Tests/TestDECCipher.pas index d72456f2..fc1e4ac6 100644 --- a/Unit Tests/Tests/TestDECCipher.pas +++ b/Unit Tests/Tests/TestDECCipher.pas @@ -107,6 +107,14 @@ TCipherBasis = class(TTestCase) procedure DoTestEncodeStream(EncodeProc: TEncodeDecodeStreamProc; InitProc: TInitProc; DoneProc: TDoneProc); procedure DoTestDecodeStream(EncodeProc: TEncodeDecodeStreamProc; InitProc: TInitProc; DoneProc: TDoneProc); + + /// + /// Tests automatic init vector generation + /// + /// + /// Cipher instance to test with + /// + procedure DoTestSetAutomaticIV(ACipher : TDECCipher); end; // Testmethods for class TDECCipher @@ -133,6 +141,7 @@ TestTDECCipher = class(TCipherBasis) procedure TestInitWideStringInitVector; procedure TestInitWideStringNoInitVector; procedure TestMACWrongMode; + procedure TestSetAutomaticIV; end; // Testmethoden for Klasse TCipher_Null @@ -166,6 +175,7 @@ TestTCipher_Blowfish = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_Twofish @@ -192,6 +202,7 @@ TestTCipher_Twofish = class(TCipherBasis) procedure TestInitKeyTooLong; procedure TestInitVectorTooLong; procedure TestInitKey0; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_IDEA @@ -250,6 +261,7 @@ TestTCipher_Mars = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_RC4 @@ -291,6 +303,7 @@ TestTCipher_RC6 = class(TCipherBasis) procedure TestMinRounds; procedure TestMaxRounds; procedure TestRounds; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_AES @@ -310,6 +323,7 @@ TestTCipher_AES = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_AES128 @@ -332,6 +346,7 @@ TestTCipher_AES128 = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_AES192 @@ -354,6 +369,7 @@ TestTCipher_AES192 = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_AES256 @@ -376,6 +392,7 @@ TestTCipher_AES256 = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_Rijndael which is an alias for AES as it's @@ -398,6 +415,7 @@ TestTCipher_Rijndael = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_Square @@ -417,6 +435,7 @@ TestTCipher_Square = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_SCOP @@ -495,6 +514,7 @@ TestTCipher_1DES = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_2DES @@ -514,6 +534,7 @@ TestTCipher_2DES = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_3DES @@ -533,6 +554,7 @@ TestTCipher_3DES = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_2DDES @@ -552,6 +574,7 @@ TestTCipher_2DDES = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_3DDES @@ -571,6 +594,7 @@ TestTCipher_3DDES = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_3TDES @@ -590,6 +614,7 @@ TestTCipher_3TDES = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_3Way @@ -609,6 +634,7 @@ TestTCipher_3Way = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_Cast128 @@ -628,6 +654,7 @@ TestTCipher_Cast128 = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_Gost @@ -647,6 +674,7 @@ TestTCipher_Gost = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_Magma, which is an alias for Ghost @@ -668,6 +696,7 @@ TestTCipher_Magma = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_Misty @@ -687,6 +716,7 @@ TestTCipher_Misty = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_NewDES @@ -706,6 +736,7 @@ TestTCipher_NewDES = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_Q128 @@ -725,6 +756,7 @@ TestTCipher_Q128 = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_RC2 @@ -744,6 +776,7 @@ TestTCipher_RC2 = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_RC5 @@ -766,6 +799,7 @@ TestTCipher_RC5 = class(TCipherBasis) procedure TestMinRounds; procedure TestMaxRounds; procedure TestRounds; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_SAFER @@ -788,6 +822,7 @@ TestTCipher_SAFER = class(TCipherBasis) procedure TestMinRounds; procedure TestMaxRounds; procedure TestRounds; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_Shark @@ -807,6 +842,7 @@ TestTCipher_Shark = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_Shark_DEC52 @@ -828,6 +864,7 @@ TestTCipher_Shark_DEC52 = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_Skipjack @@ -847,6 +884,7 @@ TestTCipher_Skipjack = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_TEA @@ -869,6 +907,7 @@ TestTCipher_TEA = class(TCipherBasis) procedure TestMinRounds; procedure TestMaxRounds; procedure TestRounds; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_XTEA @@ -888,6 +927,7 @@ TestTCipher_XTEA = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; // Testmethods for class TCipher_XTEA_DEC52 @@ -909,9 +949,10 @@ TestTCipher_XTEA_DEC52 = class(TCipherBasis) procedure TestEncode; procedure TestDecode; procedure TestClassByName; + procedure TestSetAutomaticIV; end; - // Testmethods for class TCipher_AES256 + // Testmethods for class TCipher_AES256 with PKCS7 padding {$IFDEF DUnitX} [TestFixture] {$ENDIF} TestTCipher_AES256_CBC_PKCS7 = class(TCipherBasis) strict private @@ -930,10 +971,14 @@ TestTCipher_AES256_CBC_PKCS7 = class(TCipherBasis) procedure TestDecodeStringToString; procedure TestEncodeStream; procedure TestDecodeStream; + procedure TestSetAutomaticIV; end; implementation +uses + DECUtil; + const cZeroBlock8 = #$00#$00#$00#$00#$00#$00#$00#$00; cFFBlock8 = 'FFFFFFFFFFFFFFFF'; @@ -1052,6 +1097,11 @@ procedure TestTCipher_Blowfish.TestIdentity; CheckEquals($54E9A294, FCipher_Blowfish.Identity); end; +procedure TestTCipher_Blowfish.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_Blowfish); +end; + procedure TestTCipher_Blowfish.TestClassByName; var ReturnValue : TDECCipherClass; @@ -1170,6 +1220,11 @@ procedure TestTCipher_Twofish.TestInitVectorTooLong; CheckException(DoTestInitVectorTooLong, EDECCipherException); end; +procedure TestTCipher_Twofish.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_Twofish); +end; + procedure TestTCipher_Twofish.DoTestInitKey0; var Key : TBytes; @@ -1428,6 +1483,11 @@ procedure TestTCipher_Mars.TestIdentity; CheckEquals($46AB51F5, FCipher_Mars.Identity); end; +procedure TestTCipher_Mars.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_Mars); +end; + procedure TestTCipher_Mars.TestClassByName; // ClassByName Tests for die restlichen Ciphers umsetzen! var @@ -1624,6 +1684,11 @@ procedure TestTCipher_RC6.TestRounds; CheckEquals(FCipher_RC6.Context.MaxRounds - 1, FCipher_RC6.Rounds); end; +procedure TestTCipher_RC6.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_RC6); +end; + procedure TestTCipher_Square.Done; begin FCipher_Square.Done; @@ -1704,6 +1769,11 @@ procedure TestTCipher_Square.TestIdentity; CheckEquals($2954C319, FCipher_Square.Identity); end; +procedure TestTCipher_Square.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_Square); +end; + procedure TestTCipher_SCOP.Done; begin FCipher_SCOP.Done; @@ -2162,6 +2232,11 @@ procedure TestTCipher_1DES.TestIdentity; CheckEquals($640A08AC, FCipher_1DES.Identity); end; +procedure TestTCipher_1DES.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_1DES); +end; + procedure TestTCipher_2DES.Done; begin FCipher_2DES.Done; @@ -2251,6 +2326,11 @@ procedure TestTCipher_2DES.TestIdentity; CheckEquals($76BFA742, FCipher_2DES.Identity); end; +procedure TestTCipher_2DES.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_2DES); +end; + procedure TestTCipher_3DES.Done; begin FCipher_3DES.Done; @@ -2331,6 +2411,11 @@ procedure TestTCipher_3DES.TestIdentity; CheckEquals($CE03C027, FCipher_3DES.Identity); end; +procedure TestTCipher_3DES.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_3DES); +end; + procedure TestTCipher_2DDES.Done; begin FCipher_2DDES.Done; @@ -2411,6 +2496,11 @@ procedure TestTCipher_2DDES.TestIdentity; CheckEquals($70C155BD, FCipher_2DDES.Identity); end; +procedure TestTCipher_2DDES.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_2DDES); +end; + procedure TestTCipher_3DDES.Done; begin FCipher_3DDES.Done; @@ -2491,6 +2581,11 @@ procedure TestTCipher_3DDES.TestIdentity; CheckEquals($4DA17C0D, FCipher_3DDES.Identity); end; +procedure TestTCipher_3DDES.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_3DDES); +end; + procedure TestTCipher_3TDES.Done; begin FCipher_3TDES.Done; @@ -2571,6 +2666,11 @@ procedure TestTCipher_3TDES.TestIdentity; CheckEquals($1DB82B92, FCipher_3TDES.Identity); end; +procedure TestTCipher_3TDES.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_3TDES); +end; + procedure TestTCipher_3Way.Done; begin FCipher_3Way.Done; @@ -2651,6 +2751,11 @@ procedure TestTCipher_3Way.TestIdentity; CheckEquals($54DAF114, FCipher_3Way.Identity); end; +procedure TestTCipher_3Way.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_3Way); +end; + procedure TestTCipher_Cast128.Done; begin FCipher_Cast128.Done; @@ -2731,6 +2836,11 @@ procedure TestTCipher_Cast128.TestIdentity; CheckEquals($ED7D0785, FCipher_Cast128.Identity); end; +procedure TestTCipher_Cast128.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_Cast128); +end; + procedure TestTCipher_Gost.Done; begin FCipher_Gost.Done; @@ -2811,6 +2921,11 @@ procedure TestTCipher_Gost.TestIdentity; CheckEquals($A4F73879, FCipher_Gost.Identity); end; +procedure TestTCipher_Gost.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_Gost); +end; + procedure TestTCipher_Magma.Done; begin FCipher_Magma.Done; @@ -2898,6 +3013,11 @@ procedure TestTCipher_Magma.TestIdentity; CheckEquals($5BB9788, FCipher_Magma.Identity); end; +procedure TestTCipher_Magma.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_Magma); +end; + procedure TestTCipher_Misty.Done; begin FCipher_Misty.Done; @@ -2978,6 +3098,11 @@ procedure TestTCipher_Misty.TestIdentity; CheckEquals($534C8585, FCipher_Misty.Identity); end; +procedure TestTCipher_Misty.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_Misty); +end; + procedure TestTCipher_NewDES.Done; begin FCipher_NewDES.Done; @@ -3058,6 +3183,11 @@ procedure TestTCipher_NewDES.TestIdentity; CheckEquals($5EE9D8B9, FCipher_NewDES.Identity); end; +procedure TestTCipher_NewDES.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_NewDES); +end; + procedure TestTCipher_Q128.Done; begin FCipher_Q128.Done; @@ -3138,6 +3268,11 @@ procedure TestTCipher_Q128.TestIdentity; CheckEquals($B70802F5, FCipher_Q128.Identity); end; +procedure TestTCipher_Q128.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_Q128); +end; + procedure TestTCipher_RC2.Done; begin FCipher_RC2.Done; @@ -3218,6 +3353,11 @@ procedure TestTCipher_RC2.TestIdentity; CheckEquals($9AC07A6F, FCipher_RC2.Identity); end; +procedure TestTCipher_RC2.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_RC2); +end; + procedure TestTCipher_RC5.Done; begin FCipher_RC5.Done; @@ -3347,6 +3487,11 @@ procedure TestTCipher_RC5.TestRounds; end; end; +procedure TestTCipher_RC5.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_RC5); +end; + procedure TestTCipher_SAFER.Done; begin FCipher_SAFER.Done; @@ -3524,6 +3669,11 @@ procedure TestTCipher_SAFER.TestRounds; end; end; +procedure TestTCipher_SAFER.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_SAFER); +end; + procedure TestTCipher_Shark.Done; begin FCipher_Shark.Done; @@ -3610,6 +3760,11 @@ procedure TestTCipher_Shark.TestIdentity; CheckEquals($8E616AD3, FCipher_Shark.Identity); end; +procedure TestTCipher_Shark.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_Shark); +end; + procedure TestTCipher_Shark_DEC52.Done; begin FCipher_Shark_DEC52.Done; @@ -3697,6 +3852,11 @@ procedure TestTCipher_Shark_DEC52.TestIdentity; CheckEquals($7901E07F, FCipher_Shark_DEC52.Identity); end; +procedure TestTCipher_Shark_DEC52.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_Shark_DEC52); +end; + procedure TestTCipher_Skipjack.Done; begin FCipher_Skipjack.Done; @@ -3777,6 +3937,11 @@ procedure TestTCipher_Skipjack.TestIdentity; CheckEquals($D2283F49, FCipher_Skipjack.Identity); end; +procedure TestTCipher_Skipjack.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_Skipjack); +end; + procedure TestTCipher_TEA.Done; begin FCipher_TEA.Done; @@ -3906,6 +4071,11 @@ procedure TestTCipher_TEA.TestRounds; end; end; +procedure TestTCipher_TEA.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_TEA); +end; + procedure TestTCipher_XTEA.Done; begin FCipher_XTEA.Done; @@ -4010,6 +4180,11 @@ procedure TestTCipher_XTEA.TestIdentity; CheckEquals($CDBB621D, FCipher_XTEA.Identity); end; +procedure TestTCipher_XTEA.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_XTEA); +end; + procedure TestTCipher_XTEA_DEC52.Done; begin FCipher_XTEA_DEC52.Done; @@ -4102,6 +4277,11 @@ procedure TestTCipher_XTEA_DEC52.TestIdentity; CheckEquals($59A6BE1E, FCipher_XTEA_DEC52.Identity); end; +procedure TestTCipher_XTEA_DEC52.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_XTEA_DEC52); +end; + { TCipherBasis } function TCipherBasis.ConvertHexVectorToBytes(Vector: string): TBytes; @@ -4222,6 +4402,32 @@ procedure TCipherBasis.DoTestEncodeString(EncodeFunc: TEncodeDecodeStringFunc; I end; end; +procedure TCipherBasis.DoTestSetAutomaticIV(ACipher : TDECCipher); +var + IV1, IV2 : TBytes; + Entrophy : Double; +begin + ACipher.SetAutomaticInitVector; + CheckEquals(ACipher.Context.BlockSize, ACipher.InitVectorSize, 'Invalid init-vector size'); + + // check that two successive runs create divverent IVs + SetLength(IV1, ACipher.InitVectorSize); + Move(ACipher.InitVector^, IV1[0], ACipher.InitVectorSize); + + ACipher.SetAutomaticInitVector; + + SetLength(IV2, ACipher.InitVectorSize); + Move(ACipher.InitVector^, IV2[0], ACipher.InitVectorSize); + + CheckNotEquals(true, System.SysUtils.CompareMem(@IV1[0], @IV2[0], Length(IV1))); + + Entrophy := ShannonEntropy(IV1); // > 7.0 would be really good + CheckEquals(true, + (Entrophy >= 3.5) or + ((ACipher.InitVectorSize < 16) and + (Entrophy >= 3.0)), 'Not enough entropy. Is: ' + Entrophy.ToString + ' should: > 3.5'); +end; + procedure TCipherBasis.DoTestEncodeStream(EncodeProc: TEncodeDecodeStreamProc; InitProc: TInitProc; DoneProc: TDoneProc); var @@ -4466,6 +4672,11 @@ procedure TestTDECCipher.TestMACWrongMode; CheckException(DoInitMACWrongModeException, EDECException); end; +procedure TestTDECCipher.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher); +end; + procedure TestTDECCipher.TestValidCipherSetDefaultCipherClass; var result : Boolean; @@ -4609,6 +4820,11 @@ procedure TestTCipher_AES.TestIdentity; CheckEquals($E84F910E, FCipher_AES.Identity); end; +procedure TestTCipher_AES.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_AES); +end; + { TestTCipher_Rijndael } procedure TestTCipher_Rijndael.Done; @@ -4697,6 +4913,11 @@ procedure TestTCipher_Rijndael.TestIdentity; CheckEquals($F8B830A5, FCipher_Rijndael.Identity); end; +procedure TestTCipher_Rijndael.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_Rijndael); +end; + { TestTCipher_AES128 } procedure TestTCipher_AES128.Done; @@ -4828,6 +5049,11 @@ procedure TestTCipher_AES128.TestInitializationTooLargeKey; CheckException(DoTestTooLargeKey, EDECCipherException); end; +procedure TestTCipher_AES128.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_AES); +end; + { TestTCipher_AES192 } procedure TestTCipher_AES192.Done; @@ -4939,6 +5165,11 @@ procedure TestTCipher_AES192.TestInitializationTooLargeKey; CheckException(DoTestTooLargeKey, EDECCipherException); end; +procedure TestTCipher_AES192.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_AES); +end; + { TestTCipher_AES256 } procedure TestTCipher_AES256.Done; @@ -5051,6 +5282,11 @@ procedure TestTCipher_AES256.TestInitializationTooLargeKey; CheckException(DoTestTooLargeKey, EDECCipherException); end; +procedure TestTCipher_AES256.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_AES); +end; + { TestTCipher_AES256_CBC_PKCS7 } procedure TestTCipher_AES256_CBC_PKCS7.SetUp; @@ -5138,6 +5374,11 @@ procedure TestTCipher_AES256_CBC_PKCS7.TestEncodeStringToString; DoTestEncodeString(FCipher_AES.EncodeStringToString, self.Init, self.Done); end; +procedure TestTCipher_AES256_CBC_PKCS7.TestSetAutomaticIV; +begin + DoTestSetAutomaticIV(FCipher_AES); +end; + procedure TestTCipher_AES256_CBC_PKCS7.TestDecodeStringToString; begin DoTestDecodeString(FCipher_AES.DecodeStringToString, self.Init, self.Done); diff --git a/Unit Tests/Tests/TestDECCipherFormats.pas b/Unit Tests/Tests/TestDECCipherFormats.pas index adcd9a7e..978ba984 100644 --- a/Unit Tests/Tests/TestDECCipherFormats.pas +++ b/Unit Tests/Tests/TestDECCipherFormats.pas @@ -709,7 +709,7 @@ procedure TestTDECCipherFormats.TestEncodeWideStringToString; initialization // Register any test cases with the test runner {$IFNDEF DUnitX} - RegisterTest(TestTDECCipherFormats.Suite); + RegisterTest('DEC cipher formats', TestTDECCipherFormats.Suite); {$ELSE} TDUnitX.RegisterTestFixture(TestTDECCipherFormats); {$ENDIF} diff --git a/Unit Tests/Tests/TestDECCipherModes.pas b/Unit Tests/Tests/TestDECCipherModes.pas index 2437c44a..21d5d707 100644 --- a/Unit Tests/Tests/TestDECCipherModes.pas +++ b/Unit Tests/Tests/TestDECCipherModes.pas @@ -352,6 +352,12 @@ TestTDECCipherModes = class(TTestCase) /// /// Method needed because CheckException only allows procedure methods and /// not functions as parameter. + /// Simply sets FCipher.Mode to CCM. + /// + procedure TestFailureSetCCMMode; + /// + /// Method needed because CheckException only allows procedure methods and + /// not functions as parameter. /// Tries to encrypt data using ECB-mode but data is not a multiple of /// the block size (length data > 1 block) /// @@ -420,6 +426,7 @@ TestTDECCipherModes = class(TTestCase) procedure TestFailureSetExpectedAuthenticationTag; procedure TestFailureGetExpectedAuthenticationTag; procedure InitGCMBlocksizeNot128Failure; + procedure InitCCMBlocksizeNot128Failure; procedure InitGCMStreamCipherFailure; procedure TestEncodeECBDataDoesNotMatchBlockSizeFailureSmall; procedure TestEncodeECBDataDoesNotMatchBlockSizeFailure; @@ -777,6 +784,16 @@ procedure TestTDECCipherModes.InitGCMBlocksizeNot128Failure; end; end; +procedure TestTDECCipherModes.InitCCMBlocksizeNot128Failure; +begin + FCipher := TCipher_Blowfish.Create; + try + CheckException(TestFailureSetCCMMode, EDECCipherException); + finally + FCipher.Free; + end; +end; + procedure TestTDECCipherModes.InitGCMStreamCipherFailure; begin FCipher := TCipher_RC4.Create; @@ -814,6 +831,11 @@ procedure TestTDECCipherModes.TestFailureSetGCMMode; FCipher.Mode := TCipherMode.cmGCM; end; +procedure TestTDECCipherModes.TestFailureSetCCMMode; +begin + FCipher.Mode := TCipherMode.cmCCM; +end; + procedure TestTDECCipherModes.TestGetStandardAuthenticationTagBitLengths; var i, n : Integer; @@ -1009,6 +1031,6 @@ initialization {$IFDEF DUnitX} TDUnitX.RegisterTestFixture(TestTDECCipherModes); {$ELSE} - RegisterTest(TestTDECCipherModes.Suite); + RegisterTest('DEC cipher modes', TestTDECCipherModes.Suite); {$ENDIF} end. diff --git a/Unit Tests/Tests/TestDECCipherModesCCM.pas b/Unit Tests/Tests/TestDECCipherModesCCM.pas new file mode 100644 index 00000000..26fb507d --- /dev/null +++ b/Unit Tests/Tests/TestDECCipherModesCCM.pas @@ -0,0 +1,805 @@ +{***************************************************************************** + 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. +*****************************************************************************} + +{$M+} // DUnitX would add it anyway +unit TestDECCipherModesCCM; + +interface + +// Needs to be included before any other statements +{$INCLUDE TestDefines.inc} + +uses + {$IFDEF DUnitX} + DUnitX.TestFramework,DUnitX.DUnitCompatibility, + {$ELSE} + TestFramework, + {$ENDIF} + System.SysUtils, + Generics.Collections, + System.Math, + DECBaseClass, + DECCipherBase, + DECCipherModes, + DECCipherFormats, + DECCiphers, + AuthenticatedCiphersCommonTestData; + +type + // Testmethods for class TDECCipher + {$IFDEF DUnitX} [TestFixture] {$ENDIF} + TestTDECCCM = class(TTestCase) + strict private + FTestDataList : TAuthenticatedTestDataList; + FCipherAES : TCipher_AES; + FTestBitLength : Integer; // AuthenticationBitLength for test for wring lengths + private + function IsEqual(const a, b: TBytes): Boolean; + procedure DoTestEncodeStream_LoadAndTestCAVSData(const aMaxChunkSize: Int64); + procedure DoTestEncodeStream_TestSingleSet(const aSetIndex, aDataIndex: + Integer; const aMaxChunkSize: Int64 = -1); + procedure DoTestInitFailureIVTooLong; + procedure DoTestInitFailureIVTooShort; + procedure DoTestRFC3610(EncodeTest: Boolean); + procedure DoTestAuthenticationBitLengthWrong; + public + procedure SetUp; override; + procedure TearDown; override; + published + procedure TestEncode; + /// + /// Uses testvectors from RFC 3610 but in a generated way + /// as they are specified like this. + /// + procedure TestEncodeRFC3610; + /// + /// Uses testvectors from RFC 3610 but in a generated way + /// as they are specified like this. + /// + procedure TestDecodeRFC3610; + procedure TestDecode; + procedure TestDecodeStream; + procedure TestInitIV; + procedure TestInitFailureIVTooLong; + procedure TestInitFailureIVTooShort; + procedure TestEncodeStream; +// procedure TestEncodeLargeStream; +// procedure TestEncodeStreamChunked; + procedure TestGetDataToAuthenticate; + procedure TestSetDataToAuthenticate; + procedure TestSetAuthenticationBitLengths; + procedure TestSetWrongAuthenticationBitLengths; + procedure TestGetStandardAuthenticationTagBitLengths; + procedure TestGetExpectedAuthenticationResult; + procedure TestSetExpectedAuthenticationResult; + end; + + +implementation + +uses + System.Classes, + DECTypes, + DECFormat, + DECUtil, + DECAuthenticatedCipherModesBase; + +{ TestTDECCCM } + +procedure TestTDECCCM.SetUp; +var + TestDataSet : TAuthenticatedCipherTestSetEntry; +begin + inherited; + + FTestDataList := TAuthenticatedTestDataList.Create; + + FCipherAES := TCipher_AES.Create; + FCipherAES.Mode := TCipherMode.cmCCM; + + TestDataSet.Keylen := 256; + TestDataSet.IVlen := 92; + TestDataSet.PTlen := 23 * 8; + TestDataSet.AADlen := 64; // hdr1 length in initial source + TestDataSet.Taglen := 64; // authentication tag length in bit + SetLength(TestDataSet.TestData, 2); + TestDataSet.TestData[0].CryptKey := 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf'; + TestDataSet.TestData[0].InitVector := '00000003020100a0a1a2a3a4a5'; + TestDataSet.TestData[0].PT := '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e'; + TestDataSet.TestData[0].AAD := '0001020304050607'; // hdr1 in initial source + TestDataSet.TestData[0].CT := '588c979a61c663d2f066d0c2c0f989806d5f6b61dac384'; + TestDataSet.TestData[0].TagResult := '17e8d12cfdf926e0'; + TestDataSet.TestData[0].ModifiedAAD := ''; + TestDataSet.TestData[0].ModifiedCT := ''; + + TestDataSet.TestData[1].CryptKey := 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf'; + TestDataSet.TestData[1].InitVector := '00000006050403a0a1a2a3a4a5'; + TestDataSet.TestData[1].PT := '0c0d0e0f101112131415161718191a1b1c1d1e'; + TestDataSet.TestData[1].AAD := '000102030405060708090a0b'; // hdr1 in initial source + TestDataSet.TestData[1].CT := 'a28c6865939a9a79faaa5c4c2a9d4a91cdac8c'; + TestDataSet.TestData[1].TagResult := '96c861b9c9e61ef1'; + TestDataSet.TestData[1].ModifiedAAD := ''; + TestDataSet.TestData[1].ModifiedCT := ''; + + FTestDataList.Add(TestDataSet); + + TestDataSet.Taglen := 32; // authentication tag length in bit + SetLength(TestDataSet.TestData, 1); + TestDataSet.TestData[0].CryptKey := '404142434445464748494a4b4c4d4e4f'; + TestDataSet.TestData[0].InitVector := '10111213141516'; + TestDataSet.TestData[0].PT := '20212223'; + TestDataSet.TestData[0].AAD := '0001020304050607'; // hdr1 in initial source + TestDataSet.TestData[0].CT := '7162015b'; + TestDataSet.TestData[0].TagResult := '4dac255d'; + TestDataSet.TestData[0].ModifiedAAD := ''; + TestDataSet.TestData[0].ModifiedCT := ''; + + FTestDataList.Add(TestDataSet); +end; + +procedure TestTDECCCM.TearDown; +begin + inherited; + + FCipherAES.Free; +// FTestDataLoader.Free; + FTestDataList.Free; +end; + +procedure TestTDECCCM.TestDecode; +var + TestDataSet : TAuthenticatedCipherTestSetEntry; + TestData : TSingleAuthenticatedTestData; + DecryptData : TBytes; +begin + for TestDataSet in FTestDataList do + begin + try + for TestData in TestDataSet.TestData do + begin + FCipherAES.Init(BytesOf(TFormat_HexL.Decode(TestData.CryptKey)), + BytesOf(TFormat_HexL.Decode(TestData.InitVector)), + $FF); + + FCipherAES.AuthenticationResultBitLength := TestDataSet.Taglen; + FCipherAES.DataToAuthenticate := TFormat_HexL.Decode( + BytesOf(TestData.AAD)); + + FCipherAES.ExpectedAuthenticationResult := + TFormat_HexL.Decode(BytesOf(TestData.TagResult)); + + DecryptData := FCipherAES.DecodeBytes( + TFormat_HexL.Decode( + BytesOf(TestData.CT))); + FCipherAES.Done; + + CheckEquals(string(TestData.PT), + StringOf(TFormat_HexL.Encode(DecryptData)), + 'Plaintext wrong for key ' + + string(TestData.CryptKey) + ' IV ' + + string(TestData.InitVector) + ' PT ' + + string(TestData.PT) + ' AAD ' + + string(TestData.AAD) + ' Exp. PT: ' + + string(TestData.CT) + ' Act. PT: ' + + StringOf(TFormat_HexL.Encode(DecryptData))); + + // Additional Authentication Data prfen + CheckEquals(string(TestData.TagResult), + StringOf(TFormat_HexL.Encode(FCipherAES.CalculatedAuthenticationResult)), + 'Authentication tag wrong for key ' + + string(TestData.CryptKey) + ' IV ' + + string(TestData.InitVector) + ' PT ' + + string(TestData.PT) + ' AAD ' + + string(TestData.AAD) + ' Exp. AuthTag: ' + + string(TestData.TagResult) + ' Act. AuthTag: ' + + StringOf(TFormat_HexL.Encode(FCipherAES.DataToAuthenticate))); + end; + except + on E: Exception do + Status('CryptKey ' + string(TestData.CryptKey) + + ' ' + E.ClassName + ': ' + E.Message); + end; + end; +end; + +procedure TestTDECCCM.TestInitFailureIVTooLong; +begin + CheckException(DoTestInitFailureIVTooLong, + EDECNonceLengthException, + 'Init vector too long not detected'); +end; + +procedure TestTDECCCM.DoTestInitFailureIVTooLong; +var + CipherAES : TCipher_AES; +begin + CipherAES := TCipher_AES.Create; + + try + CipherAES.Mode := cmCCM; + CipherAES.Init(BytesOf(TFormat_HexL.Decode('000102030405060708')), + BytesOf(TFormat_HexL.Decode('0a0b0c0d0e0f0a0b0c0d0e0f0a0b0c0d')), + $FF); + finally + CipherAES.Free; + end; +end; + +procedure TestTDECCCM.TestInitFailureIVTooShort; +begin + CheckException(DoTestInitFailureIVTooShort, + EDECNonceLengthException, + 'Init vector too long not detected'); +end; + +procedure TestTDECCCM.TestInitIV; +var + Key : TBytes; + IV : TBytes; + i : Integer; +begin + Key := [1, 2, 3, 4, 5, 6, 7, 8]; + + for i := 7 to 13 do + begin + SetLength(IV, i); + FillChar(IV[0], length(IV), $FF); + + FCipherAES.Init(Key, IV, $FF, pmNone); + Check(true); + end; +end; + +procedure TestTDECCCM.DoTestInitFailureIVTooShort; +var + CipherAES : TCipher_AES; +begin + CipherAES := TCipher_AES.Create; + + try + CipherAES.Mode := cmCCM; + CipherAES.Init(BytesOf(TFormat_HexL.Decode('000102030405060708')), + BytesOf(TFormat_HexL.Decode('0a0b0c0d0e0f')), + $FF); + finally + CipherAES.Free; + end; +end; + +procedure TestTDECCCM.TestEncode; +var + TestDataSet : TAuthenticatedCipherTestSetEntry; + TestData : TSingleAuthenticatedTestData; + EncryptData : TBytes; + EncrDataStr : string; +begin + for TestDataSet in FTestDataList do + begin + for TestData in TestDataSet.TestData do + begin + FCipherAES.Init(BytesOf(TFormat_HexL.Decode(TestData.CryptKey)), + BytesOf(TFormat_HexL.Decode(TestData.InitVector)), + $FF); + + FCipherAES.AuthenticationResultBitLength := TestDataSet.Taglen; + FCipherAES.DataToAuthenticate := TFormat_HexL.Decode( + BytesOf(TestData.AAD)); + + EncryptData := FCipherAES.EncodeBytes( + TFormat_HexL.Decode( + BytesOf(TestData.PT))); + FCipherAES.Done; + + EncrDataStr := StringOf(TFormat_HexL.Encode(EncryptData)); + CheckEquals(string(TestData.CT), + EncrDataStr, + 'Cipher text wrong for Key ' + + string(TestData.CryptKey) + ' IV ' + + string(TestData.InitVector) + ' PT ' + + string(TestData.PT) + ' AAD ' + + string(TestData.AAD) + ' Exp.: ' + + string(TestData.CT) + ' Act.: ' + + EncrDataStr); + + // Additional Authentication Data prfen + CheckEquals(string(TestData.TagResult), + StringOf(TFormat_HexL.Encode(FCipherAES.CalculatedAuthenticationResult)), + 'Authentication tag wrong for Key ' + + string(TestData.CryptKey) + ' IV ' + + string(TestData.InitVector) + ' PT ' + + string(TestData.PT) + ' AAD ' + + string(TestData.AAD) + ' Exp.: ' + + string(TestData.TagResult) + ' Act.: ' + + StringOf(TFormat_HexL.Encode(FCipherAES.DataToAuthenticate))); + end; + end; +end; + +procedure TestTDECCCM.TestGetExpectedAuthenticationResult; +var + Exp, Act: TBytes; +begin + SetLength(Exp, 4); + Exp := [1, 2, 3, 4]; + FCipherAES.ExpectedAuthenticationResult := Exp; + Act := FCipherAES.ExpectedAuthenticationResult; + + CheckEquals(true, IsEqual(Exp, Act), 'Data length = 4'); + + SetLength(Exp, 0); + FCipherAES.ExpectedAuthenticationResult := Exp; + Act := FCipherAES.ExpectedAuthenticationResult; + + CheckEquals(true, IsEqual(Exp, Act), 'Data length = 0'); +end; + +//procedure TestTDECCCM.DoTestDecodeFailure; +//begin +// FDecryptedData := FCipherAES.DecodeBytes(FCipherText); +// FCipherAES.Done; +//end; + +function TestTDECCCM.IsEqual(const a, b : TBytes):Boolean; +begin + if (length(a) <> length(b)) then + Result := false + else + if (Length(a) > 0) then + Result := CompareMem(@a[0], @b[0], length(a)) + else + Result := true; +end; + +procedure TestTDECCCM.TestDecodeStream; +var + ctbStream: TBytesStream; + ctBytes: TBytes; + TestDataSet : TAuthenticatedCipherTestSetEntry; + TestData : TSingleAuthenticatedTestData; + DecryptData : TBytes; + ptbStream: TBytesStream; +begin + for TestDataSet in FTestDataList do + begin + for TestData in TestDataSet.TestData do + begin + ctBytes := TFormat_HexL.Decode(BytesOf(TestData.CT)); + + try + FCipherAES.Init(BytesOf(TFormat_HexL.Decode(TestData.CryptKey)), + BytesOf(TFormat_HexL.Decode(TestData.InitVector)), + $FF); + + FCipherAES.AuthenticationResultBitLength := TestDataSet.Taglen; + FCipherAES.DataToAuthenticate := TFormat_HexL.Decode( + BytesOf(TestData.AAD)); + + FCipherAES.ExpectedAuthenticationResult := + TFormat_HexL.Decode(BytesOf(TestData.TagResult)); + + ctbStream := TBytesStream.Create(ctBytes); + ptbStream := TBytesStream.Create; + + FCipherAES.DecodeStream(ctbStream, ptbStream, ctbStream.Size); + + FCipherAES.Done; + + DecryptData := ptbStream.Bytes; + SetLength(DecryptData, ptbStream.Size); + + except + on E: Exception do + Status('CryptKey ' + string(TestData.CryptKey) + + ' ' + E.ClassName + ': ' + E.Message); + end; + FreeAndNil(ptbStream); + FreeAndNil(ctbStream); + + CheckEquals(string(TestData.PT), + StringOf(TFormat_HexL.Encode(DecryptData)), + 'Plaintext wrong for key ' + + string(TestData.CryptKey) + ' IV ' + + string(TestData.InitVector) + ' PT ' + + string(TestData.PT) + ' AAD ' + + string(TestData.AAD) + ' Exp.: ' + + string(TestData.CT) + ' Act.: ' + + StringOf(TFormat_HexL.Encode(DecryptData))); + + // Additional Authentication Data prfen + CheckEquals(string(TestData.TagResult), + StringOf(TFormat_HexL.Encode(FCipherAES.CalculatedAuthenticationResult)), + 'Authentication tag wrong for key ' + + string(TestData.CryptKey) + ' IV ' + + string(TestData.InitVector) + ' PT ' + + string(TestData.PT) + ' AAD ' + + string(TestData.AAD) + ' Exp.: ' + + string(TestData.TagResult) + ' Act.: ' + + StringOf(TFormat_HexL.Encode(FCipherAES.DataToAuthenticate))); + end; + end; +end; + +procedure TestTDECCCM.TestEncodeStream; +begin + // -1 to disable chunking + DoTestEncodeStream_LoadAndTestCAVSData(-1); +end; + +procedure TestTDECCCM.DoTestAuthenticationBitLengthWrong; +begin + FCipherAES.AuthenticationResultBitLength := FTestBitLength; +end; + +//procedure TestTDECCCM.TestEncodeStreamChunked; +//begin +// // Use cipher block size as max chunk size +// DoTestEncodeStream_LoadAndTestCAVSData( +// Max(FCipherAES.Context.BlockSize, FCipherAES.Context.BufferSize)); +//end; +// +procedure TestTDECCCM.DoTestEncodeStream_LoadAndTestCAVSData(const + aMaxChunkSize: Int64); +var + TestDataSet : TAuthenticatedCipherTestSetEntry; + curSetIndex: Integer; +begin + for curSetIndex := 0 to FTestDataList.Count - 1 do + begin + TestDataSet := FTestDataList[curSetIndex]; + DoTestEncodeStream_TestSingleSet(curSetIndex, 0, aMaxChunkSize); + end; +end; +// +//procedure TestTDECCCM.TestEncodeLargeStream; +//begin +// // There is only one record in test data set atm, so need to allow +// // incomplete load +// FTestDataLoader.LoadFile('..\..\Unit Tests\Data\gcmEncryptExtIV256_large.rsp', +// FTestDataList, True); +// Status('Encode large stream using chunking'); +// CheckEquals(8192, StreamBufferSize, 'Might need to update data set to have enough data!'); +//{ TODO : Auskommentierten Code entfernen } +//// Assert(StreamBufferSize = 8192, 'Might need to update data set to have enough data!'); +// DoTestEncodeStream_TestSingleSet(0, 0, StreamBufferSize); +// Status('Encode large stream without chunking'); +// DoTestEncodeStream_TestSingleSet(0, 0, -1); +//end; + +procedure TestTDECCCM.DoTestEncodeStream_TestSingleSet(const aSetIndex, + aDataIndex: Integer; const aMaxChunkSize: Int64 = -1); +var + ctbStream: TBytesStream; + curChunkSize: Int64; + dataLeftToEncode: Int64; + ptBytes: TBytes; + TestDataSet : TAuthenticatedCipherTestSetEntry; + TestData : TSingleAuthenticatedTestData; + EncryptData : TBytes; + ptbStream: TBytesStream; +begin + TestDataSet := FTestDataList[aSetIndex]; + + for TestData in TestDataSet.TestData do + begin + ptBytes := TFormat_HexL.Decode(BytesOf(TestData.PT)); + + FCipherAES.Init(BytesOf(TFormat_HexL.Decode(TestData.CryptKey)), + BytesOf(TFormat_HexL.Decode(TestData.InitVector)), + $FF); + + FCipherAES.AuthenticationResultBitLength := TestDataSet.Taglen; + FCipherAES.DataToAuthenticate := TFormat_HexL.Decode( + BytesOf(TestData.AAD)); + + ptbStream := TBytesStream.Create(ptBytes); + ctbStream := TBytesStream.Create; + try + dataLeftToEncode := ptbStream.Size; + curChunkSize := dataLeftToEncode; + repeat + // Apply chunking if needed + if aMaxChunkSize > 0 then + curChunkSize := Min(dataLeftToEncode, aMaxChunkSize); + FCipherAES.EncodeStream(ptbStream, ctbStream, curChunkSize); + Dec(dataLeftToEncode, curChunkSize); + until (dataLeftToEncode = 0); + + FCipherAES.Done; + + EncryptData := ctbStream.Bytes; + SetLength(EncryptData, ctbStream.Size); + except + on E: Exception do + Status('CryptKey ' + string(TestData.CryptKey) + + ' ' + E.ClassName + ': ' + E.Message); + end; + + FreeAndNil(ptbStream); + FreeAndNil(ctbStream); + + CheckEquals(string(TestData.CT), + StringOf(TFormat_HexL.Encode(EncryptData)), + 'Cipher text wrong for Set ' + aSetIndex.ToString + ' and Data ' + aDataIndex.ToString + + ' and Key ' + string(TestData.CryptKey) + ' IV ' + + string(TestData.InitVector) + ' PT ' + + string(TestData.PT) + ' AAD Exp.: ' + + string(TestData.AAD) + ' Act.: ' + + StringOf(TFormat_HexL.Encode(FCipherAES.DataToAuthenticate))); + + // Additional Authentication Data prfen + CheckEquals(string(TestData.TagResult), + StringOf(TFormat_HexL.Encode(FCipherAES.CalculatedAuthenticationResult)), + 'Authentication tag wrong for Set ' + aSetIndex.ToString + ' and Data ' + aDataIndex.ToString + + ' and Key ' + string(TestData.CryptKey) + ' IV ' + + string(TestData.InitVector) + ' PT ' + + string(TestData.PT) + ' AAD Exp.: ' + + string(TestData.AAD) + ' Act.: ' + + StringOf(TFormat_HexL.Encode(FCipherAES.DataToAuthenticate))); + end; +end; + +procedure TestTDECCCM.TestGetStandardAuthenticationTagBitLengths; +var + BitLengths: TStandardBitLengths; +begin + BitLengths := FCipherAES.GetStandardAuthenticationTagBitLengths; + + CheckEquals( 32, BitLengths[0]); + CheckEquals( 48, BitLengths[1]); + CheckEquals( 64, BitLengths[2]); + CheckEquals( 80, BitLengths[3]); + CheckEquals( 96, BitLengths[4]); + CheckEquals(112, BitLengths[5]); + CheckEquals(128, BitLengths[6]); +end; + +procedure TestTDECCCM.TestSetExpectedAuthenticationResult; +var + Exp, Act: TBytes; +begin + SetLength(Exp, 4); + Exp := [1, 2, 3, 4]; + FCipherAES.ExpectedAuthenticationResult := Exp; + Act := FCipherAES.ExpectedAuthenticationResult; + + CheckEquals(true, IsEqual(Exp, Act), 'Data length = 4'); + + SetLength(Exp, 8); + Exp := [1, 2, 3, 4, 5, 6, 7, 8]; + FCipherAES.ExpectedAuthenticationResult := Exp; + Act := FCipherAES.ExpectedAuthenticationResult; + + CheckEquals(true, IsEqual(Exp, Act), 'Data length = 8'); + + SetLength(Exp, 12); + Exp := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + FCipherAES.ExpectedAuthenticationResult := Exp; + Act := FCipherAES.ExpectedAuthenticationResult; + + CheckEquals(true, IsEqual(Exp, Act), 'Data length = 12'); + + SetLength(Exp, 0); + FCipherAES.ExpectedAuthenticationResult := Exp; + Act := FCipherAES.ExpectedAuthenticationResult; + + CheckEquals(true, IsEqual(Exp, Act), 'Data length = 0'); +end; + +procedure TestTDECCCM.TestSetWrongAuthenticationBitLengths; +var + bl : Integer; +begin + bl := 31; + while (bl < 128) do + begin + FTestBitLength := bl; + CheckException(DoTestAuthenticationBitLengthWrong, EDECAuthLengthException); + inc(bl, 16); + end; + + bl := 33; + while (bl <= 129) do + begin + FTestBitLength := bl; + CheckException(DoTestAuthenticationBitLengthWrong, EDECAuthLengthException); + inc(bl, 16); + end; +end; + +procedure TestTDECCCM.TestSetAuthenticationBitLengths; +var + bl : Integer; +begin + bl := 32; + + while (bl <= 128) do + begin + FCipherAES.AuthenticationResultBitLength := bl; + CheckEquals(bl, FCipherAES.AuthenticationResultBitLength); + + inc(bl, 16); + end; +end; + +procedure TestTDECCCM.TestGetDataToAuthenticate; +var + inp, outp : TBytes; +begin + inp := BytesOf(RawByteString('Hello')); + FCipherAES.DataToAuthenticate := inp; + outp := FCipherAES.DataToAuthenticate; + + CheckEquals(true, CompareMem(@inp[0], @outp[0], length(inp)), + 'Data to authenticate not properly set. Expected: ' + + string(BytesToRawString(inp)) + ' Result: ' + + string(BytesToRawString(outp))); +end; + +procedure TestTDECCCM.TestSetDataToAuthenticate; +begin + FCipherAES.DataToAuthenticate := BytesOf(RawByteString('Hello')); + CheckEquals(RawByteString('Hello'), + RawByteString(StringOf(FCipherAES.DataToAuthenticate))); + + FCipherAES.DataToAuthenticate := BytesOf(RawByteString('The quick brown fox jumped over the lazy dog')); + CheckEquals(RawByteString('The quick brown fox jumped over the lazy dog'), + RawByteString(StringOf(FCipherAES.DataToAuthenticate))); +end; + +procedure TestTDECCCM.TestEncodeRFC3610; +begin + DoTestRFC3610(true); +end; + +procedure TestTDECCCM.TestDecodeRFC3610; +begin + DoTestRFC3610(false); +end; + +procedure TestTDECCCM.DoTestRFC3610(EncodeTest: Boolean); +type + ta25 = array[0..24] of UInt8; + ta10 = array[0..09] of UInt8; +const + ctest: array[1..12] of ta25 = ( + ($58,$8C,$97,$9A,$61,$C6,$63,$D2,$F0,$66,$D0,$C2,$C0,$F9,$89,$80,$6D,$5F,$6B,$61,$DA,$C3,$84,$00,$00), + ($72,$C9,$1A,$36,$E1,$35,$F8,$CF,$29,$1C,$A8,$94,$08,$5C,$87,$E3,$CC,$15,$C4,$39,$C9,$E4,$3A,$3B,$00), + ($51,$B1,$E5,$F4,$4A,$19,$7D,$1D,$A4,$6B,$0F,$8E,$2D,$28,$2A,$E8,$71,$E8,$38,$BB,$64,$DA,$85,$96,$57), + ($A2,$8C,$68,$65,$93,$9A,$9A,$79,$FA,$AA,$5C,$4C,$2A,$9D,$4A,$91,$CD,$AC,$8C,$00,$00,$00,$00,$00,$00), + ($DC,$F1,$FB,$7B,$5D,$9E,$23,$FB,$9D,$4E,$13,$12,$53,$65,$8A,$D8,$6E,$BD,$CA,$3E,$00,$00,$00,$00,$00), + ($6F,$C1,$B0,$11,$F0,$06,$56,$8B,$51,$71,$A4,$2D,$95,$3D,$46,$9B,$25,$70,$A4,$BD,$87,$00,$00,$00,$00), + ($01,$35,$D1,$B2,$C9,$5F,$41,$D5,$D1,$D4,$FE,$C1,$85,$D1,$66,$B8,$09,$4E,$99,$9D,$FE,$D9,$6C,$00,$00), + ($7B,$75,$39,$9A,$C0,$83,$1D,$D2,$F0,$BB,$D7,$58,$79,$A2,$FD,$8F,$6C,$AE,$6B,$6C,$D9,$B7,$DB,$24,$00), + ($82,$53,$1A,$60,$CC,$24,$94,$5A,$4B,$82,$79,$18,$1A,$B5,$C8,$4D,$F2,$1C,$E7,$F9,$B7,$3F,$42,$E1,$97), + ($07,$34,$25,$94,$15,$77,$85,$15,$2B,$07,$40,$98,$33,$0A,$BB,$14,$1B,$94,$7B,$00,$00,$00,$00,$00,$00), + ($67,$6B,$B2,$03,$80,$B0,$E3,$01,$E8,$AB,$79,$59,$0A,$39,$6D,$A7,$8B,$83,$49,$34,$00,$00,$00,$00,$00), + ($C0,$FF,$A0,$D6,$F0,$5B,$DB,$67,$F2,$4D,$43,$A4,$33,$8D,$2A,$A4,$BE,$D7,$B2,$0E,$43,$00,$00,$00,$00)); + ttest: array[1..12] of ta10 = ( + ($17,$E8,$D1,$2C,$FD,$F9,$26,$E0,$00,$00), + ($A0,$91,$D5,$6E,$10,$40,$09,$16,$00,$00), + ($4A,$DA,$A7,$6F,$BD,$9F,$B0,$C5,$00,$00), + ($96,$C8,$61,$B9,$C9,$E6,$1E,$F1,$00,$00), + ($51,$E8,$3F,$07,$7D,$9C,$2D,$93,$00,$00), + ($40,$5A,$04,$43,$AC,$91,$CB,$94,$00,$00), + ($04,$8C,$56,$60,$2C,$97,$AC,$BB,$74,$90), + ($C1,$7B,$44,$33,$F4,$34,$96,$3F,$34,$B4), + ($EA,$9C,$07,$E5,$6B,$5E,$B1,$7E,$5F,$4E), + ($56,$6A,$A9,$40,$6B,$4D,$99,$99,$88,$DD), + ($F5,$3A,$A2,$E9,$10,$7A,$8B,$6C,$02,$2C), + ($CD,$1A,$A3,$16,$62,$E7,$AD,$65,$D6,$DB)); +var + buf, DecodeBuf : array[0..63] of UInt8; + pn : Integer; + key, nonce : TBlock16Byte; + i, ih, it, k : Integer; + plen, tlen, hlen : UInt16; + x : UInt32; + b : UInt8; + CipherAES : TCipher_AES; + DataToAuth : TBytes; + TagResult : TBytes; +begin + nonce[00] := 0; // = init vector + nonce[01] := 0; + nonce[02] := 0; + nonce[07] := $A0; + nonce[08] := $A1; + nonce[09] := $A2; + nonce[10] := $A3; + nonce[11] := $A4; + nonce[12] := $A5; + + pn := 0; + + // key setup, all tests use the same one + for i:= 0 to 15 do + key[i] := $C0 + i; + + for it := 0 to 1 do + begin + tlen := 8 + 2*it; // authentication tag length + + for ih := 0 to 1 do + begin + hlen := 8 + 4*ih; // length of the data to authenticate + SetLength(DataToAuth, hlen); + + for k := 31 to 33 do + begin + pLen := k-hlen; // plain text length? + + x := pn * $01010101+$03020100; + inc(pn); + + // some positions of the nonce/init vector are different for each test + nonce[03] := (x shr 24) and $ff; + nonce[04] := (x shr 16) and $ff; + nonce[05] := (x shr 08) and $ff; + nonce[06] := x and $ff; + + b := 0; + for i := 0 to hlen - 1 do + begin + DataToAuth[i] := b; + inc(b); + end; + + for i := 0 to pLen - 1 do + begin + buf[i] := b; + inc(b); + end; + + CipherAES := TCipher_AES256.Create; + try + CipherAES.Mode := TCipherMode.cmCCM; + CipherAES.DataToAuthenticate := DataToAuth; + CipherAES.AuthenticationResultBitLength := tlen * 8; + + CipherAES.Init(Key[0], Length(Key), Nonce[0], 13, 0, pmNone); + + if EncodeTest then + begin + CipherAES.Encode(buf[0], buf[0], plen); + CheckEquals(true, CompareMem(@buf,@ctest[pn],plen), 'Ciphertext wrong'); + end + else + begin + CipherAES.Decode(ctest[pn], DecodeBuf[0], plen); + CheckEquals(true, CompareMem(@buf,@DecodeBuf,plen), 'Plaintext wrong'); + end; + + TagResult := CipherAES.CalculatedAuthenticationResult; + + // Test the generated tag + CheckEquals(true, CompareMem(@TagResult[0], @ttest[pn],tlen), 'Tag wrong'); + finally + CipherAES.Free; + end; + end; + end; + end; +end; + +initialization + // Register all test cases to be run + {$IFDEF DUnitX} + TDUnitX.RegisterTestFixture(TestTDECCCM); + {$ELSE} + RegisterTest('DEC authenticated cipher modes', TestTDECCCM.Suite); + {$ENDIF} +end. diff --git a/Unit Tests/Tests/TestDECCipherModesGCM.pas b/Unit Tests/Tests/TestDECCipherModesGCM.pas index aae0da91..b7f5f6cc 100644 --- a/Unit Tests/Tests/TestDECCipherModesGCM.pas +++ b/Unit Tests/Tests/TestDECCipherModesGCM.pas @@ -29,100 +29,17 @@ interface {$ELSE} TestFramework, {$ENDIF} - System.SysUtils, Generics.Collections, System.Math, + System.SysUtils, + Generics.Collections, + System.Math, DECBaseClass, - DECCipherBase, DECCipherModes, DECCipherFormats, DECCiphers; + DECCipherBase, + DECCipherModes, + DECCipherFormats, + DECCiphers, + AuthenticatedCiphersCommonTestData; type - /// - /// Test data for one single GCM test, all in HexL - /// - TGCMSingleTestData = record - /// - /// Encryption/decryption key - /// - CryptKey : RawByteString; - /// - /// Initialization vecotr - /// - InitVector : RawByteString; - /// - /// Plain Text: text to be encrypted, given in HexL - /// - PT : RawByteString; - /// - /// Additional Authenticated Data: the data which shall be authenticated - /// but not encrypted. - /// - AAD : RawByteString; - /// - /// Cipher Text: encrypted text, given in HexL - /// - CT : RawByteString; - /// - /// Calculated authenticated "tag" value - /// - TagResult : RawByteString; - /// - /// Used additional authenticated data for testing authentication failures. - /// Only filled when present in test data file. - /// - ModifiedAAD: RawByteString; - /// - /// Used ciphertext data for testing authentication failures. - /// Only filled when present in test data file. - /// - ModifiedCT: RawByteString; - - /// - /// Sets all fields and array entries to default values - /// - procedure Clear; - end; - - /// - /// Test data for one single GCM test - /// - TGCMTestSetEntry = record - /// - /// Length of the encryption/decryption key in bit, determines the - /// algorithm used in case of AES (AES128, AES192, AES256) - /// - Keylen : UInt16; - /// - /// Length of the initialization vector in bit - /// - IVlen : UInt16; - /// - /// Length of the ? in bit - /// - PTlen : UInt16; - /// - /// Length of the ? in bit - /// - AADlen : UInt16; - /// - /// Length of the "tag" resulting from the authentication part in bit - /// - Taglen : UInt16; - - /// - /// The test data files provided contain 14 tests for the meta data - /// specified above. This array holds the test data. - /// - TestData : array[0..14] of TGCMSingleTestData; - - /// - /// Sets all fields and array entries to default values - /// - procedure Clear; - end; - - /// - /// List of loaded GCM test vectors - /// - TGCMTestDataList = TList; - /// /// Class for loading a GCM style test data file /// @@ -164,7 +81,7 @@ TGCMTestDataLoader = class(TObject) /// the start of a new block has been detected in the method. /// procedure ReadBlockMetaDataLine(const Line : string; - var Entry : TGCMTestSetEntry; + var Entry : TAuthenticatedCipherTestSetEntry; var Index : Byte); /// @@ -187,8 +104,8 @@ TGCMTestDataLoader = class(TObject) /// line will be ignored. /// procedure ReadDataLine(const Line : string; - var Entry : TGCMTestSetEntry; - TestData : TGCMTestDataList; + var Entry : TAuthenticatedCipherTestSetEntry; + TestData : TAuthenticatedTestDataList; var Index : Byte); public /// @@ -204,7 +121,7 @@ TGCMTestDataLoader = class(TObject) /// /// Use when loading data set with incomplete entries. /// - procedure LoadFile(const FileName: string; TestData : TGCMTestDataList; + procedure LoadFile(const FileName: string; TestData : TAuthenticatedTestDataList; AllowIncompleteEntries: Boolean = False); end; @@ -213,7 +130,7 @@ TGCMTestDataLoader = class(TObject) TestTDECGCM = class(TTestCase) strict private FTestDataLoader : TGCMTestDataLoader; - FTestDataList : TGCMTestDataList; + FTestDataList : TAuthenticatedTestDataList; FCipherAES : TCipher_AES; // Needed for passing data to and from DoTestDecodeFailure @@ -241,6 +158,11 @@ TestTDECGCM = class(TTestCase) procedure TestGetStandardAuthenticationTagBitLengths; procedure TestGetExpectedAuthenticationResult; procedure TestSetExpectedAuthenticationResult; + + /// + /// Test for GitHub issue #86 + /// + procedure TestEncodeConstData_86; end; @@ -251,36 +173,6 @@ implementation DECTypes, DECFormat; -{ TGCMTestSetEntry } - -procedure TGCMTestSetEntry.Clear; -var - i : Integer; -begin - Keylen := 0; - IVlen := 0; - PTlen := 0; - AADlen := 0; - Taglen := 0; - - for i := Low(TestData) to High(TestData) do - TestData[i].Clear; -end; - -{ TGCMSingleTestData } - -procedure TGCMSingleTestData.Clear; -begin - CryptKey := ''; - InitVector := ''; - PT := ''; - AAD := ''; - CT := ''; - TagResult := ''; - ModifiedAAD := ''; - ModifiedCT := ''; -end; - { TGCMTestDataLoader } function TGCMTestDataLoader.ExtractHexString(const Line: string): RawByteString; @@ -313,17 +205,19 @@ function TGCMTestDataLoader.ExtractNumber(const Line: string): UInt16; end; procedure TGCMTestDataLoader.LoadFile(const FileName: string; - TestData : TGCMTestDataList; AllowIncompleteEntries: Boolean = False); + TestData : TAuthenticatedTestDataList; AllowIncompleteEntries: Boolean = False); var Reader : TStreamReader; Line : string; - Entry : TGCMTestSetEntry; + Entry : TAuthenticatedCipherTestSetEntry; Index : Byte; begin System.Assert(FileName <> '', 'No file to load specified'); System.Assert(Assigned(TestData), 'Unassigned test data list given'); + SetLength(Entry.TestData, 15); Entry.Clear; + Index := 0; Reader := TStreamReader.Create(FileName, TEncoding.UTF8); @@ -367,13 +261,14 @@ procedure TGCMTestDataLoader.LoadFile(const FileName: string; end; procedure TGCMTestDataLoader.ReadBlockMetaDataLine(const Line : string; - var Entry : TGCMTestSetEntry; + var Entry : TAuthenticatedCipherTestSetEntry; var Index : Byte); begin // Loading of the block metadata // Does a new block start? if (Pos('[keylen', Line) > 0) then begin + SetLength(Entry.TestData, 15); Entry.Clear; Index := 0; @@ -390,8 +285,8 @@ procedure TGCMTestDataLoader.ReadBlockMetaDataLine(const Line : string; end; procedure TGCMTestDataLoader.ReadDataLine(const Line : string; - var Entry : TGCMTestSetEntry; - TestData : TGCMTestDataList; + var Entry : TAuthenticatedCipherTestSetEntry; + TestData : TAuthenticatedTestDataList; var Index : Byte); begin // Data entries do not contain [ @@ -441,7 +336,7 @@ procedure TestTDECGCM.SetUp; inherited; FTestDataLoader := TGCMTestDataLoader.Create; - FTestDataList := TGCMTestDataList.Create; + FTestDataList := TAuthenticatedTestDataList.Create; FCipherAES := TCipher_AES.Create; FCipherAES.Mode := TCipherMode.cmGCM; @@ -458,7 +353,7 @@ procedure TestTDECGCM.TearDown; procedure TestTDECGCM.TestDecode; var - TestDataSet : TGCMTestSetEntry; + TestDataSet : TAuthenticatedCipherTestSetEntry; i : Integer; DecryptData : TBytes; begin @@ -520,7 +415,7 @@ procedure TestTDECGCM.TestDecode; procedure TestTDECGCM.TestDecodeAuthenticationFailure; var - TestDataSet : TGCMTestSetEntry; + TestDataSet : TAuthenticatedCipherTestSetEntry; i : Integer; begin FTestDataLoader.LoadFile('..\..\Unit Tests\Data\GCM128AuthenticationFailures.rsp', FTestDataList); @@ -564,7 +459,7 @@ procedure TestTDECGCM.TestDecodeAuthenticationFailure; procedure TestTDECGCM.TestEncode; var - TestDataSet : TGCMTestSetEntry; + TestDataSet : TAuthenticatedCipherTestSetEntry; i : Integer; EncryptData : TBytes; EncrDataStr : string; @@ -616,6 +511,89 @@ procedure TestTDECGCM.TestEncode; end; end; +procedure TestTDECGCM.TestEncodeConstData_86; +var + cipher : TCipher_AES128; + tag : TBytes; + refPlainText : Array[0..3] of LongWord; + ciphText : Array[0..3] of LongWord; + key : Array[0..3] of LongWord; + iv : Array[0..2] of LongWord; + refCipherText : Array[0..3] of LongWord; + refTag : Array[0..3] of LongWord; + hea : TBytes; + +type + TUINT32Byte = Array[0..3] of Byte; + PUINT32Byte = ^TUINT32Byte; + +// test key/cipher text and IV from an ARM based platform +const cAESKey : Array[0..3] of Longword = ($C939CC13, $397C1D37, $DE6AE0E1, $CB7C423C ); + cAESIV : Array[0..2] of Longword = ($B3D8CC01, $7CBB89B3, $9E0F67E2); + + cPlainText : Array[0..3] of LongWord = ($c3b3c41f, $113a31b7, $3d9a5cd4, $32103069 ); + cCipherText : Array[0..3] of LongWord = ($93FE7D9E, $9BFD1034, $8A5606E5, $CAFA7354 ); + + cExpectedTag : Array[0..3] of LongWord = ($0032A1DC, $85F1C978, $6925A2E7, $1D8272DD); + cAESHea : Array[0..3] of LongWord = ( $24825602, $bd12a984, $e0092d3e, $448eda5f ); + + function InvUINT32( value : UINT32 ) : UINT32; + var + v1, v2 : PUINT32Byte; + begin + v1 := @value; + v2 := @Result; + + v2^[3] := v1^[0]; + v2^[2] := v1^[1]; + v2^[1] := v1^[2]; + v2^[0] := v1^[3]; + end; + + procedure InitKey; + var + i : Integer; + begin + for i := 0 to High(cAESKey) do + key[i] := InvUINT32(cAESKey[i]); + + for i := 0 to High(cAESIV) do + iv[i] := InvUINT32(cAESIV[i]); + + for i := 0 to High(refPlainText) do + refPlainText[i] := InvUINT32(cPlainText[i]); + + for i := 0 to High(refCipherText) do + refCipherText[i] := InvUINT32(cCipherText[i]); + + for i := 0 to High(cExpectedTag) do + refTag[i] := InvUINT32(cExpectedTag[i]); + + SetLength(hea, sizeof(cAESHea)); + for i := 0 to High(cExpectedTag) do + PLongWord(@hea[i*4])^ := InvUINT32(cAESHea[i]); + end; + +begin + InitKey; + cipher := TCipher_AES128.Create; + try + cipher.Mode := cmGCM; + cipher.Init( key, sizeof(key), iv, sizeof(iv), 0 ); + cipher.AuthenticationResultBitLength := 128; + cipher.DataToAuthenticate := hea; + + cipher.Encode(refPlainText, ciphText, sizeof(refPlainText)); + tag := cipher.CalculatedAuthenticationResult; + finally + cipher.Free; + end; + + Check( CompareMem(@refCipherText[0], @ciphText[0], sizeof(ciphText)), 'Cipher failed'); + Check( CompareMem(@refTag[0], @tag[0], sizeof(refTag)), 'Tag failed'); +end; + + procedure TestTDECGCM.TestGetExpectedAuthenticationResult; var Exp, Act: TBytes; @@ -655,7 +633,7 @@ procedure TestTDECGCM.TestDecodeStream; var ctbStream: TBytesStream; ctBytes: TBytes; - TestDataSet : TGCMTestSetEntry; + TestDataSet : TAuthenticatedCipherTestSetEntry; i : Integer; DecryptData : TBytes; ptbStream: TBytesStream; @@ -745,7 +723,7 @@ procedure TestTDECGCM.DoTestEncodeStream_LoadAndTestCAVSData(const aMaxChunkSize: Int64); var i : Integer; - TestDataSet : TGCMTestSetEntry; + TestDataSet : TAuthenticatedCipherTestSetEntry; curSetIndex: Integer; begin FTestDataLoader.LoadFile('..\..\Unit Tests\Data\gcmEncryptExtIV128.rsp', FTestDataList); @@ -784,7 +762,7 @@ procedure TestTDECGCM.DoTestEncodeStream_TestSingleSet(const aSetIndex, curChunkSize: Int64; dataLeftToEncode: Int64; ptBytes: TBytes; - TestDataSet : TGCMTestSetEntry; + TestDataSet : TAuthenticatedCipherTestSetEntry; EncryptData : TBytes; ptbStream: TBytesStream; begin @@ -810,6 +788,13 @@ procedure TestTDECGCM.DoTestEncodeStream_TestSingleSet(const aSetIndex, // Apply chunking if needed if aMaxChunkSize > 0 then curChunkSize := Min(dataLeftToEncode, aMaxChunkSize); +// Darf vermutlich so nicht sein, es darf vermutlich nur einen EncodeStream Aufruf +// geben. Mglicherwiese ist das Padding wie es jetzt umgesetzt ist nicht ganz richtig, +// da man sonst keinen dynamischen Stream haben kann. Gehrt vermutlich ins Done, +// aber das hat noch keinen Stream, braucht also eine berladene Variante mit +// Outputstream als Parameter... +// Zuerst test mal ohne Schleife testen. EncodeStream darf nicht anhand der Size +// das "globale" Ende des Streams ermitteln, sonst nichts nachschiebbar. FCipherAES.EncodeStream(ptbStream, ctbStream, curChunkSize); Dec(dataLeftToEncode, curChunkSize); until (dataLeftToEncode = 0); @@ -917,7 +902,7 @@ initialization {$IFDEF DUnitX} TDUnitX.RegisterTestFixture(TestTDECGCM); {$ELSE} - RegisterTest(TestTDECGCM.Suite); + RegisterTest('DEC authenticated cipher modes', TestTDECGCM.Suite); {$ENDIF} end. diff --git a/Unit Tests/Tests/TestDECHashKDF.pas b/Unit Tests/Tests/TestDECHashKDF.pas index dd1c6c7a..de6d1fdb 100644 --- a/Unit Tests/Tests/TestDECHashKDF.pas +++ b/Unit Tests/Tests/TestDECHashKDF.pas @@ -279,9 +279,15 @@ procedure TestTHash_KDF.InternalTest(KDFType: TKDFMGFAlgorithm); begin if (TestData.Algorithm = KDFType) then begin + {$IFNDEF FPC} Data := System.SysUtils.BytesOf(TestData.InputData); Seed := System.SysUtils.BytesOf(TestData.SeedData); ExpResult := System.SysUtils.BytesOf(TestData.OutputData); + {$ELSE} + Data := BytesOf(TestData.InputData); + Seed := BytesOf(TestData.SeedData); + ExpResult := BytesOf(TestData.OutputData); + {$ENDIF} case KDFType of ktKDF1 : if (length(Seed) = 0) then @@ -330,9 +336,15 @@ procedure TestTHash_KDF.InternalTestTBytes(KDFType: TKDFMGFAlgorithm); begin if (TestData.Algorithm = KDFType) then begin + {$IFNDEF FPC} Data := System.SysUtils.BytesOf(TestData.InputData); Seed := System.SysUtils.BytesOf(TestData.SeedData); ExpResult := System.SysUtils.BytesOf(TestData.OutputData); + {$ELSE} + Data := BytesOf(TestData.InputData); + Seed := BytesOf(TestData.SeedData); + ExpResult := BytesOf(TestData.OutputData); + {$ENDIF} if (KDFType = ktKDF1) then Result := TestData.HashClass.KDF1(Data, Seed, TestData.MaskSize); diff --git a/Unit Tests/Tests/TestDECHashSHA3.pas b/Unit Tests/Tests/TestDECHashSHA3.pas index a427b9aa..04729b2b 100644 --- a/Unit Tests/Tests/TestDECHashSHA3.pas +++ b/Unit Tests/Tests/TestDECHashSHA3.pas @@ -1,4 +1,4 @@ -{***************************************************************************** +{***************************************************************************** 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 @@ -650,9 +650,16 @@ function TestTHash_SHA3_Base.AddLastByteForKeccakTest(SHA3InputVector : RawBy function TestTHash_SHA3_Base.CalcUnicodeHash(TestData : string; HashInst : TDECHashAuthentication): RawByteString; begin + {$IFNDEF FPC} Result := BytesToRawString(TFormat_HEXL.Encode( System.SysUtils.BytesOf(HashInst.CalcString( string(TFormat_HexL.Decode(RawByteString(TestData))))))); + {$ELSE} + Result := BytesToRawString(TFormat_HEXL.Encode( + BytesOf(HashInst.CalcString( + string(TFormat_HexL.Decode(RawByteString(TestData))))))); + + {$ENDIF} end; { TestTHash_SHA3_224 } @@ -1755,14 +1762,13 @@ procedure TestTHash_SHA3_Base.AddLastByteForCodeTest(var lDataRow : IHashTest SHA3InputVector : RawByteString; LastByteLength : UInt8); var - LastByteLen : UInt8; MsgWithFixup : RawByteString; begin - MsgWithFixup := AddLastByteForKeccakTest(SHA3InputVector, LastByteLen); + MsgWithFixup := AddLastByteForKeccakTest(SHA3InputVector, LastByteLength); //LastByteLen); lDataRow.AddInputVector(MsgWithFixup); - lDataRow.FinalBitLength := LastByteLen; + lDataRow.FinalBitLength := LastByteLength; - THash_SHA3Base(FHash).FinalByteLength := LastByteLen; + THash_SHA3Base(FHash).FinalByteLength := LastByteLength; lDataRow.ExpectedOutputUTFStrTest := CalcUnicodeHash(string(TFormat_HexL.Encode(MsgWithFixup)), FHash); diff --git a/Unit Tests/Tests/TestDECUtil.pas b/Unit Tests/Tests/TestDECUtil.pas index ad0493bb..295682df 100644 --- a/Unit Tests/Tests/TestDECUtil.pas +++ b/Unit Tests/Tests/TestDECUtil.pas @@ -77,8 +77,16 @@ TTestIsEqual = class(TTestCase) procedure IsEqualsZeroLength; end; + TTestMist = class(TTestCase) + published + procedure TestShannonEntropy; + end; + implementation +uses + System.Math; + type TestRecUInt8 = record Input : UInt8; @@ -668,15 +676,36 @@ procedure TTestIsEqual.IsEqualsZeroLength; CheckEquals(true, Result, 'a = b = length 0'); end; +{ TTestMist } + +procedure TTestMist.TestShannonEntropy; +var + Entropy : Double; + Str : RawByteString; +begin + Str := 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ' + + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; + Entropy := ShannonEntropy(BytesOf(Str)); + CheckEquals(true, System.Math.IsZero(Entropy, 0.1), 'No entrophy not detected'); + + Str := 'And this is a simple english text without much sense but with a lot ' + + 'of letters and some words.'; + Entropy := ShannonEntropy(BytesOf(Str)); + CheckEquals(true, System.Math.SameValue(Entropy, 3.969, 0.1), + 'English sentence entrophy wrong'); +end; + initialization // Register any test cases with the test runner {$IFDEF DUnitX} TDUnitX.RegisterTestFixture(TTestBitTwiddling); TDUnitX.RegisterTestFixture(TTestBufferProtection); TDUnitX.RegisterTestFixture(TTestIsEqual); + TDUnitX.RegisterTestFixture(TTestMist); {$ELSE} RegisterTests('DECUtil', [TTestBitTwiddling.Suite, TTestBufferProtection.Suite, - TTestIsEqual.Suite]); + TTestIsEqual.Suite, + TTestMist.Suite]); {$ENDIF} end. diff --git a/readme.md b/readme.md index 3b91ddaa..a1cb892e 100644 --- a/readme.md +++ b/readme.md @@ -6,19 +6,20 @@ It contains algorithms for these categories: * Ciphers: encryption/decryption of data * Hashes: "cryptographic checksums" +* Password hashes: bcrypt * Key derivation algorithms like Kdf1-Kdf3 and pbkdf2 * HMAC message authentication * A cryptographic pseudo random number generator * CRCs: non cryptographic checksums based on CRC algorithms ## Which Delphi versions are compatible? -The current version 6.4.1 is compatible with Delphi XE2 - Delphi 12.3 Athens. +The last release version 6.4.1 is compatible with Delphi XE7 - Delphi 13.1 Florence. When defining the NO_ASM define in DECOptions.inc it is compatible with all platforms supported by Delphi! It might be compatible with FPC, but this has not been focus and is not tested. The development branch contains a more FPC compatible version already. -If you need support for older Delphi versions use version 5.2, which is compatible +If you need support for older Delphi versions use version 5.2. This is compatible with Delphi 7-2007 at least but lacks some hash implementations, HMAC and KDF improvements. While V5.2 can be made compatible with newer Delphi versions with small modifications we strongly recommend to better adapt your code to use the @@ -34,8 +35,8 @@ Details about the changes and additions in V6.4.1 can be found in the VersionHistory.pdf file in the docs subfolder of the development branch. In comparison to 5.2 we added some console, VCL and FMX based demo applications. -The FMX based demos are even available via Google play as "DEC cipher demo" and -"DEC hash demo". +The FMX based demos were even available via Google play as "DEC cipher demo" and +"DEC hash demo". Due to some key issue they are no longer installable at the moment. ## Where can I get further information? For example if I'd like to contribute? In the root folder of DEC V6.4.1 you will find further files with information about @@ -97,6 +98,7 @@ vectors provided by NIST are used for the unit tests. * Snefru128 * Snefru256 * Sapphire +* BCrypt ## Contained cipher algorithms * Null @@ -146,6 +148,7 @@ Modes ending on x have been invented by the original developer of DEC * CFS8 * CFSx * GCM +* CCM ## Contained key derivation algorithms: * KDF1