From 4bd9b0fd4b6e33c1911f0b87bb83d2ad03ea376b Mon Sep 17 00:00:00 2001 From: gbamber Date: Wed, 14 Dec 2016 13:19:41 +0000 Subject: [PATCH] cryptini component initial commit Component V 0.1.2.0 Demo V 0.1.2.0 git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5487 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../cryptini/latest_stable/cryptini.lpk | 88 + .../cryptini/latest_stable/cryptini.pas | 14 + .../latest_stable/demo/cryptinitest.ico | Bin 0 -> 220108 bytes .../latest_stable/demo/cryptinitest.lpi | 283 ++++ .../latest_stable/demo/cryptinitest.lpr | 51 + .../latest_stable/demo/cryptinitest.lps | 500 ++++++ .../latest_stable/demo/cryptinitest.res | Bin 0 -> 221636 bytes .../demo/uinputsectionvaluesform.lfm | 86 + .../demo/uinputsectionvaluesform.pas | 156 ++ .../latest_stable/demo/ukeydialog.lfm | 59 + .../latest_stable/demo/ukeydialog.pas | 51 + .../cryptini/latest_stable/demo/umainform.lfm | 348 ++++ .../cryptini/latest_stable/demo/umainform.pas | 993 +++++++++++ .../cryptini/latest_stable/demo/umemoform.lfm | 62 + .../cryptini/latest_stable/demo/umemoform.pas | 94 ++ .../latest_stable/locale/ucryptini.po | 15 + .../cryptini/latest_stable/ucryptini.pas | 1477 +++++++++++++++++ 17 files changed, 4277 insertions(+) create mode 100644 components/cryptini/latest_stable/cryptini.lpk create mode 100644 components/cryptini/latest_stable/cryptini.pas create mode 100644 components/cryptini/latest_stable/demo/cryptinitest.ico create mode 100644 components/cryptini/latest_stable/demo/cryptinitest.lpi create mode 100644 components/cryptini/latest_stable/demo/cryptinitest.lpr create mode 100644 components/cryptini/latest_stable/demo/cryptinitest.lps create mode 100644 components/cryptini/latest_stable/demo/cryptinitest.res create mode 100644 components/cryptini/latest_stable/demo/uinputsectionvaluesform.lfm create mode 100644 components/cryptini/latest_stable/demo/uinputsectionvaluesform.pas create mode 100644 components/cryptini/latest_stable/demo/ukeydialog.lfm create mode 100644 components/cryptini/latest_stable/demo/ukeydialog.pas create mode 100644 components/cryptini/latest_stable/demo/umainform.lfm create mode 100644 components/cryptini/latest_stable/demo/umainform.pas create mode 100644 components/cryptini/latest_stable/demo/umemoform.lfm create mode 100644 components/cryptini/latest_stable/demo/umemoform.pas create mode 100644 components/cryptini/latest_stable/locale/ucryptini.po create mode 100644 components/cryptini/latest_stable/ucryptini.pas diff --git a/components/cryptini/latest_stable/cryptini.lpk b/components/cryptini/latest_stable/cryptini.lpk new file mode 100644 index 000000000..a31d78dc5 --- /dev/null +++ b/components/cryptini/latest_stable/cryptini.lpk @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/cryptini/latest_stable/cryptini.pas b/components/cryptini/latest_stable/cryptini.pas new file mode 100644 index 000000000..c769bc1fd --- /dev/null +++ b/components/cryptini/latest_stable/cryptini.pas @@ -0,0 +1,14 @@ +{ This file was automatically created by Lazarus. Do not edit! + This source is only used to compile and install the package. + } + +unit cryptini; + +interface + +uses + ucryptini; + +implementation + +end. diff --git a/components/cryptini/latest_stable/demo/cryptinitest.ico b/components/cryptini/latest_stable/demo/cryptinitest.ico new file mode 100644 index 0000000000000000000000000000000000000000..9f02c598bc45b2941d1581eaf5c9d1e892ce5de0 GIT binary patch literal 220108 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�&?mT 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 + + + + + + + + + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + <XPManifest> + <TextName Value="CompanyName.ProductName.AppName"/> + <TextDesc Value="Your application description."/> + </XPManifest> + <Icon Value="0"/> + </General> + <VersionInfo> + <UseVersionInfo Value="True"/> + <AutoIncrementBuild Value="True"/> + <MinorVersionNr Value="1"/> + <RevisionNr Value="2"/> + <StringTable Comments="App is GPL licensed" CompanyName="HELENA" FileDescription="Test app for CryptINI unit" InternalName="cryptinitest" LegalCopyright="(c)2016 minesadorada@charcodelvalle.com" LegalTrademarks="none" OriginalFilename="cryptinitest" ProductName="Lazarus" ProductVersion="1.6.0.0"/> + </VersionInfo> + <BuildModes Count="6"> + <Item1 Name="Win64" Default="True"/> + <Item2 Name="Win32"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="compiled\win32\cryptinitestwin32"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <CodeGeneration> + <TargetCPU Value="i386"/> + <TargetOS Value="win32"/> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + <Other> + <CustomOptions Value="-FcUTF8"/> + </Other> + </CompilerOptions> + </Item2> + <Item3 Name="Linux64"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="compiled\linux64\cryptinitestlinux64"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <CodeGeneration> + <TargetCPU Value="x86_64"/> + <TargetOS Value="linux"/> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + </CompilerOptions> + </Item3> + <Item4 Name="Linux32"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="compiled\linux32\cryptinitestlinux32"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <CodeGeneration> + <TargetCPU Value="i386"/> + <TargetOS Value="linux"/> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + <Other> + <CustomOptions Value="-FcUTF8"/> + </Other> + </CompilerOptions> + </Item4> + <Item5 Name="DebugWin64"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="compiled\debugwin64\dcryptinitestwin64"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <IncludeAssertionCode Value="True"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <Checks> + <IOChecks Value="True"/> + <RangeChecks Value="True"/> + <OverflowChecks Value="True"/> + <StackChecks Value="True"/> + </Checks> + <TargetCPU Value="x86_64"/> + <TargetOS Value="win64"/> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + <UseHeaptrc Value="True"/> + </Debugging> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + </CompilerOptions> + </Item5> + <Item6 Name="Darwin32"> + <MacroValues Count="1"> + <Macro1 Name="LCLWidgetType" Value="carbon"/> + </MacroValues> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="compiled\darwin32\cryptinitestdarwin32"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <CodeGeneration> + <TargetCPU Value="i386"/> + <TargetOS Value="darwin"/> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + <Other> + <CustomOptions Value="-FcUTF8"/> + </Other> + </CompilerOptions> + </Item6> + <SharedMatrixOptions Count="1"> + <Item1 ID="543305826982" Modes="Darwin32" Type="IDEMacro" MacroName="LCLWidgetType" Value="carbon"/> + </SharedMatrixOptions> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <DestinationDirectory Value="D:\Lazarusprojects\MDSUM\CryptINI\trunk\latest_stable"/> + <IncludeFileFilter Value="*.(pas|pp|inc|lpr|lfm|lrs|lpi|lpk|xml|sh|ico|exe)"/> + <SaveClosedEditorFilesInfo Value="True"/> + </PublishOptions> + <RunParams> + <local> + <FormatVersion Value="1"/> + </local> + </RunParams> + <RequiredPackages Count="2"> + <Item1> + <PackageName Value="cryptini"/> + </Item1> + <Item2> + <PackageName Value="LCL"/> + </Item2> + </RequiredPackages> + <Units Count="5"> + <Unit0> + <Filename Value="cryptinitest.lpr"/> + <IsPartOfProject Value="True"/> + </Unit0> + <Unit1> + <Filename Value="umainform.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="mainform"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit1> + <Unit2> + <Filename Value="umemoform.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="ShowINIForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit2> + <Unit3> + <Filename Value="ukeydialog.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="keydialog"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit3> + <Unit4> + <Filename Value="uinputsectionvaluesform.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="InputSectionValuesForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="uInputSectionValuesForm"/> + </Unit4> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="compiled\win64\cryptinitestwin64"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <CodeGeneration> + <TargetCPU Value="x86_64"/> + <TargetOS Value="win64"/> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/components/cryptini/latest_stable/demo/cryptinitest.lpr b/components/cryptini/latest_stable/demo/cryptinitest.lpr new file mode 100644 index 000000000..0f9ae1357 --- /dev/null +++ b/components/cryptini/latest_stable/demo/cryptinitest.lpr @@ -0,0 +1,51 @@ +program cryptinitest; +{ Test App for cryptini unit + + Copyright (C) 2016 Gordon Bamber minesadorada@gmail.com + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License + for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +} + +{$ifdef Linux} + {$ifdef FPC_CROSSCOMPILING} + {$ifdef CPUARM} +//if GUI on RPi, then uncomment +//{$linklib GLESv2} + {$endif} + {$linklib libc_nonshared.a} + {$endif} +{$endif} +{$mode objfpc}{$H+} + +uses {$IFDEF UNIX} {$IFDEF UseCThreads} + cthreads, {$ENDIF} {$ENDIF} + Interfaces, // this includes the LCL widgetset + Forms, + umainform, umemoform, ukeydialog, +uInputSectionValuesForm; + +{$R *.res} +begin + Application.Title:='CryptINI Test'; + RequireDerivedFormResource := True; + Application.Initialize; + Application.CreateForm(Tmainform, mainform); + Application.CreateForm(TShowINIForm, ShowINIForm); + Application.CreateForm(Tkeydialog, keydialog); + Application.CreateForm(TInputSectionValuesForm, InputSectionValuesForm); + Application.Run; +end. + + diff --git a/components/cryptini/latest_stable/demo/cryptinitest.lps b/components/cryptini/latest_stable/demo/cryptinitest.lps new file mode 100644 index 000000000..3d9a8e81c --- /dev/null +++ b/components/cryptini/latest_stable/demo/cryptinitest.lps @@ -0,0 +1,500 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectSession> + <PathDelim Value="\"/> + <Version Value="10"/> + <BuildModes Active="Darwin32"/> + <Units Count="51"> + <Unit0> + <Filename Value="cryptinitest.lpr"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="4"/> + <TopLine Value="6"/> + <CursorPos Y="49"/> + <UsageCount Value="116"/> + <Loaded Value="True"/> + </Unit0> + <Unit1> + <Filename Value="umainform.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="mainform"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <TopLine Value="197"/> + <CursorPos X="41" Y="199"/> + <UsageCount Value="116"/> + <Loaded Value="True"/> + <LoadedDesigner Value="True"/> + </Unit1> + <Unit2> + <Filename Value="umemoform.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="ShowINIForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="3"/> + <TopLine Value="55"/> + <CursorPos X="3" Y="68"/> + <UsageCount Value="108"/> + <Loaded Value="True"/> + <LoadedDesigner Value="True"/> + </Unit2> + <Unit3> + <Filename Value="ukeydialog.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="keydialog"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <EditorIndex Value="2"/> + <CursorPos X="12" Y="29"/> + <UsageCount Value="100"/> + <Loaded Value="True"/> + <LoadedDesigner Value="True"/> + </Unit3> + <Unit4> + <Filename Value="uinputsectionvaluesform.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="InputSectionValuesForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="uInputSectionValuesForm"/> + <EditorIndex Value="-1"/> + <TopLine Value="72"/> + <CursorPos Y="84"/> + <UsageCount Value="78"/> + </Unit4> + <Unit5> + <Filename Value="htmlhelp2viewer.pas"/> + <ComponentName Value="HelpViewerForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="HtmlHelp2Viewer"/> + <EditorIndex Value="-1"/> + <TopLine Value="58"/> + <CursorPos X="44" Y="82"/> + <UsageCount Value="20"/> + </Unit5> + <Unit6> + <Filename Value="cryptini\ucryptini.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="203"/> + <CursorPos X="37" Y="226"/> + <UsageCount Value="33"/> + </Unit6> + <Unit7> + <Filename Value="cryptinilpk\ucryptini.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="727"/> + <CursorPos X="67" Y="754"/> + <UsageCount Value="24"/> + </Unit7> + <Unit8> + <Filename Value="..\MD5Code\ucryptini.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="360"/> + <CursorPos Y="363"/> + <UsageCount Value="101"/> + <Bookmarks Count="2"> + <Item0 Y="975" ID="1"/> + <Item1 Y="1028"/> + </Bookmarks> + </Unit8> + <Unit9> + <Filename Value="D:\fpc\packages\hash\src\md5.pp"/> + <EditorIndex Value="-1"/> + <TopLine Value="130"/> + <UsageCount Value="5"/> + </Unit9> + <Unit10> + <Filename Value="D:\fpc\packages\fcl-base\src\inifiles.pp"/> + <UnitName Value="IniFiles"/> + <EditorIndex Value="-1"/> + <TopLine Value="100"/> + <CursorPos X="5" Y="188"/> + <UsageCount Value="31"/> + </Unit10> + <Unit11> + <Filename Value="..\..\lazautoupdate\svn\trunk\lazautoupdatesource\packagesource\versionsupport.pas"/> + <UnitName Value="VersionSupport"/> + <EditorIndex Value="-1"/> + <TopLine Value="187"/> + <CursorPos X="45" Y="109"/> + <UsageCount Value="5"/> + </Unit11> + <Unit12> + <Filename Value="D:\lazarus\components\lazproj\lazxproj_src\lazxproj_intf.pas"/> + <UnitName Value="LazXProj_Intf"/> + <EditorIndex Value="-1"/> + <CursorPos X="41" Y="18"/> + <UsageCount Value="5"/> + </Unit12> + <Unit13> + <Filename Value="D:\lazarus\lcl\dialogs.pp"/> + <UnitName Value="Dialogs"/> + <EditorIndex Value="-1"/> + <TopLine Value="685"/> + <CursorPos X="25" Y="704"/> + <UsageCount Value="6"/> + </Unit13> + <Unit14> + <Filename Value="D:\fpc\rtl\objpas\sysutils\sysstrh.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="65"/> + <CursorPos X="18" Y="115"/> + <UsageCount Value="6"/> + </Unit14> + <Unit15> + <Filename Value="D:\fpc\rtl\objpas\sysutils\sysstr.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="890"/> + <CursorPos X="3" Y="893"/> + <UsageCount Value="6"/> + </Unit15> + <Unit16> + <Filename Value="D:\lazarus\lcl\include\messagedialogs.inc"/> + <EditorIndex Value="-1"/> + <CursorPos X="3" Y="212"/> + <UsageCount Value="6"/> + </Unit16> + <Unit17> + <Filename Value="..\..\lazautoupdate\svn\trunk\lazautoupdatesource\packagesource\ulazautoupdate.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="461"/> + <CursorPos X="42" Y="469"/> + <UsageCount Value="11"/> + </Unit17> + <Unit18> + <Filename Value="D:\usr\share\fpcsrc\3.0.0\rtl\objpas\sysutils\datih.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="132"/> + <CursorPos X="84" Y="153"/> + <UsageCount Value="6"/> + </Unit18> + <Unit19> + <Filename Value="D:\usr\share\fpcsrc\3.0.0\rtl\objpas\sysutils\sysinth.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="43"/> + <CursorPos X="24" Y="57"/> + <UsageCount Value="6"/> + </Unit19> + <Unit20> + <Filename Value="D:\usr\share\fpcsrc\3.0.0\packages\fcl-base\src\blowfish.pp"/> + <UnitName Value="BlowFish"/> + <EditorIndex Value="-1"/> + <TopLine Value="478"/> + <UsageCount Value="6"/> + </Unit20> + <Unit21> + <Filename Value="D:\lazarus\lcl\controls.pp"/> + <UnitName Value="Controls"/> + <EditorIndex Value="-1"/> + <TopLine Value="28"/> + <CursorPos X="3" Y="47"/> + <UsageCount Value="6"/> + </Unit21> + <Unit22> + <Filename Value="..\..\..\..\snippets\uuser.pas"/> + <UnitName Value="uUser"/> + <EditorIndex Value="-1"/> + <TopLine Value="301"/> + <UsageCount Value="6"/> + </Unit22> + <Unit23> + <Filename Value="D:\usr\share\fpcsrc\3.0.0\packages\fcl-base\src\inifiles.pp"/> + <UnitName Value="IniFiles"/> + <EditorIndex Value="-1"/> + <CursorPos Y="20"/> + <UsageCount Value="20"/> + </Unit23> + <Unit24> + <Filename Value="D:\fpc\rtl\objpas\sysutils\sysinth.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="44"/> + <CursorPos X="3" Y="33"/> + <UsageCount Value="17"/> + </Unit24> + <Unit25> + <Filename Value="D:\fpc\rtl\objpas\classes\classesh.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="654"/> + <CursorPos X="37" Y="676"/> + <UsageCount Value="12"/> + </Unit25> + <Unit26> + <Filename Value="D:\lazarus\lcl\include\customform.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="996"/> + <CursorPos Y="1019"/> + <UsageCount Value="7"/> + </Unit26> + <Unit27> + <Filename Value="D:\lazarus\components\lazutils\lazmethodlist.pas"/> + <UnitName Value="LazMethodList"/> + <EditorIndex Value="-1"/> + <TopLine Value="273"/> + <CursorPos Y="308"/> + <UsageCount Value="11"/> + </Unit27> + <Unit28> + <Filename Value="D:\lazarus\lcl\include\wincontrol.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="6442"/> + <CursorPos Y="6463"/> + <UsageCount Value="7"/> + </Unit28> + <Unit29> + <Filename Value="D:\lazarus\lcl\include\control.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="3235"/> + <CursorPos Y="3259"/> + <UsageCount Value="7"/> + </Unit29> + <Unit30> + <Filename Value="D:\lazarus\lcl\include\customedit.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="527"/> + <CursorPos Y="547"/> + <UsageCount Value="7"/> + </Unit30> + <Unit31> + <Filename Value="D:\lazarus\lcl\interfaces\win32\win32wsstdctrls.pp"/> + <UnitName Value="Win32WSStdCtrls"/> + <EditorIndex Value="-1"/> + <TopLine Value="1187"/> + <CursorPos Y="1210"/> + <UsageCount Value="7"/> + </Unit31> + <Unit32> + <Filename Value="D:\lazarus\lcl\interfaces\win32\win32proc.pp"/> + <EditorIndex Value="-1"/> + <TopLine Value="1044"/> + <CursorPos Y="1069"/> + <UsageCount Value="7"/> + </Unit32> + <Unit33> + <Filename Value="D:\lazarus\components\lazutils\lazutf8.pas"/> + <UnitName Value="LazUTF8"/> + <EditorIndex Value="-1"/> + <TopLine Value="3565"/> + <CursorPos Y="3589"/> + <UsageCount Value="7"/> + </Unit33> + <Unit34> + <Filename Value="..\..\golfml\coursewriter\source\2.x\umainform.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="3333"/> + <CursorPos X="31" Y="3328"/> + <UsageCount Value="8"/> + </Unit34> + <Unit35> + <Filename Value="D:\lazarus\components\LazOpkMan-master\LazOpkMan-master\opkman_installer.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="147"/> + <CursorPos X="42" Y="163"/> + <UsageCount Value="8"/> + </Unit35> + <Unit36> + <Filename Value="D:\usr\lib\lazarus\1.6\lcl\lclversion.pas"/> + <UnitName Value="LCLVersion"/> + <EditorIndex Value="-1"/> + <CursorPos X="12" Y="35"/> + <UsageCount Value="20"/> + </Unit36> + <Unit37> + <Filename Value="D:\home\gordon\lazarus_components\LazOpkMan-master\opkman_common.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="227"/> + <UsageCount Value="8"/> + </Unit37> + <Unit38> + <Filename Value="D:\home\gordon\lazarus_components\LazOpkMan-master\opkman_mainfrm.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="19"/> + <UsageCount Value="8"/> + </Unit38> + <Unit39> + <Filename Value="D:\home\gordon\lazarus_components\LazOpkMan-master\opkman_installer.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="139"/> + <CursorPos X="13" Y="168"/> + <UsageCount Value="12"/> + </Unit39> + <Unit40> + <Filename Value="..\..\lazprojx\lazxproj_src\lazxproj_intf.pas"/> + <UnitName Value="LazXProj_Intf"/> + <EditorIndex Value="-1"/> + <CursorPos X="41" Y="18"/> + <UsageCount Value="9"/> + </Unit40> + <Unit41> + <Filename Value="D:\lazarustrunk\components\onlinepackagemanager\opkman_installer.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="139"/> + <CursorPos X="3" Y="145"/> + <UsageCount Value="10"/> + </Unit41> + <Unit42> + <Filename Value="D:\lazarustrunk\components\onlinepackagemanager\opkman_serializablepackages.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="859"/> + <CursorPos X="37" Y="913"/> + <UsageCount Value="10"/> + </Unit42> + <Unit43> + <Filename Value="D:\lazarustrunk\components\onlinepackagemanager\opkman_optionsfrm.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="165"/> + <UsageCount Value="10"/> + </Unit43> + <Unit44> + <Filename Value="C:\NewPascalDarwin\lazarus\ide\lazarus.pp"/> + <UnitName Value="Lazarus"/> + <EditorIndex Value="-1"/> + <TopLine Value="108"/> + <CursorPos Y="154"/> + <UsageCount Value="10"/> + </Unit44> + <Unit45> + <Filename Value="..\..\..\..\snippets\usefulunits\tcopydir.pas"/> + <UnitName Value="tCopyDir"/> + <EditorIndex Value="-1"/> + <TopLine Value="22"/> + <CursorPos X="5" Y="29"/> + <UsageCount Value="10"/> + </Unit45> + <Unit46> + <Filename Value="..\..\..\..\snippets\usefulunits\uappisrunning.pas"/> + <EditorIndex Value="-1"/> + <CursorPos X="20" Y="8"/> + <UsageCount Value="10"/> + </Unit46> + <Unit47> + <Filename Value="..\..\..\..\snippets\usefulunits\usersupport.pas"/> + <UnitName Value="UserSupport"/> + <EditorIndex Value="-1"/> + <TopLine Value="240"/> + <CursorPos X="48" Y="334"/> + <UsageCount Value="10"/> + </Unit47> + <Unit48> + <Filename Value="..\..\..\..\snippets\usefulunits\utcopydir.pas"/> + <UnitName Value="utCopyDir"/> + <EditorIndex Value="-1"/> + <TopLine Value="44"/> + <CursorPos X="44" Y="60"/> + <UsageCount Value="10"/> + </Unit48> + <Unit49> + <Filename Value="C:\lazarus\examples\htmlhelp_ipro\htmlhelp2unit1.pas"/> + <UnitName Value="HtmlHelp2Unit1"/> + <EditorIndex Value="-1"/> + <TopLine Value="28"/> + <CursorPos X="97" Y="65"/> + <UsageCount Value="10"/> + </Unit49> + <Unit50> + <Filename Value="..\ucryptini.pas"/> + <IsVisibleTab Value="True"/> + <EditorIndex Value="1"/> + <TopLine Value="390"/> + <CursorPos X="19" Y="222"/> + <UsageCount Value="10"/> + <Loaded Value="True"/> + </Unit50> + </Units> + <JumpHistory Count="23" HistoryIndex="22"> + <Position1> + <Filename Value="ukeydialog.pas"/> + <Caret Line="29" Column="12"/> + </Position1> + <Position2> + <Filename Value="umainform.pas"/> + <Caret Line="621" Column="26" TopLine="607"/> + </Position2> + <Position3> + <Filename Value="umainform.pas"/> + <Caret Line="621" Column="26"/> + </Position3> + <Position4> + <Filename Value="umainform.pas"/> + <Caret Line="20" Column="27" TopLine="3"/> + </Position4> + <Position5> + <Filename Value="umainform.pas"/> + <Caret Line="32" Column="21"/> + </Position5> + <Position6> + <Filename Value="umainform.pas"/> + <Caret Line="185" Column="19" TopLine="155"/> + </Position6> + <Position7> + <Filename Value="umainform.pas"/> + <Caret Line="32" Column="24" TopLine="18"/> + </Position7> + <Position8> + <Filename Value="umainform.pas"/> + <Caret Line="234" Column="23" TopLine="222"/> + </Position8> + <Position9> + <Filename Value="umainform.pas"/> + <Caret Line="185" TopLine="167"/> + </Position9> + <Position10> + <Filename Value="umainform.pas"/> + <Caret Line="184" TopLine="166"/> + </Position10> + <Position11> + <Filename Value="umainform.pas"/> + <Caret Line="183" TopLine="165"/> + </Position11> + <Position12> + <Filename Value="umainform.pas"/> + <Caret Line="270" Column="47" TopLine="241"/> + </Position12> + <Position13> + <Filename Value="umainform.pas"/> + <Caret Line="933" Column="43" TopLine="99"/> + </Position13> + <Position14> + <Filename Value="umainform.pas"/> + <Caret Line="191" Column="18" TopLine="179"/> + </Position14> + <Position15> + <Filename Value="umainform.pas"/> + <Caret Line="153" Column="13" TopLine="153"/> + </Position15> + <Position16> + <Filename Value="umainform.pas"/> + <Caret Line="385" Column="9" TopLine="371"/> + </Position16> + <Position17> + <Filename Value="umainform.pas"/> + <Caret Line="11" Column="19"/> + </Position17> + <Position18> + <Filename Value="umainform.pas"/> + <Caret Line="153" Column="13" TopLine="140"/> + </Position18> + <Position19> + <Filename Value="umainform.pas"/> + <Caret Line="395" TopLine="366"/> + </Position19> + <Position20> + <Filename Value="umainform.pas"/> + <Caret Line="154" Column="12" TopLine="125"/> + </Position20> + <Position21> + <Filename Value="umainform.pas"/> + <Caret Line="153" Column="16" TopLine="127"/> + </Position21> + <Position22> + <Filename Value="umainform.pas"/> + <Caret Line="163" TopLine="152"/> + </Position22> + <Position23> + <Filename Value="umainform.pas"/> + <Caret Line="116" Column="24" TopLine="116"/> + </Position23> + </JumpHistory> + </ProjectSession> +</CONFIG> diff --git a/components/cryptini/latest_stable/demo/cryptinitest.res b/components/cryptini/latest_stable/demo/cryptinitest.res new file mode 100644 index 0000000000000000000000000000000000000000..a09d0d3876494c66e442468e65df410c02c1df27 GIT binary patch literal 221636 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 x0N)IN^2 zYuQ3b%Q*n&dQte?gwHomURa`pzN`91_3Ba&?<f;*RIjFe93zdN*0X0V;AcxYH2wpO z16BcB{9v1X93xGp%U(QgNW~)vFF;;L<Nf~?JrIACh}#=~G^RP<r^AC0U**7K48D!F zH%{8-cR$B)wul5j$KVe~JbCSNjMp&d4CPLYEdjoc5adB#?h@zAo%g2_@6VF59rqE& zUkA6{e}|+24?|vH9_JDepZk*Q4d312`xlXbJje^Y<K6sYFTKGOL+&XjzaifJK(4dX z+w8Mrws!ZO6!0+M#r2+!f3El&O<{b`_2;EC{+fRW+9i7L7r_2)>vS~WVZiG&{xRim zG|2acz3myJ$n)(CaV8q_Ag^HkV=lkZVE?}6<*|Fvxewj8Iac^zZ3s(e_sj=qNY8fw z!0R;qeHCsr{GRB~Gvw@7cXIb=yWp_zC8j_z!mtgx(`YysJPde+<R92;Z1)tq>b#S` zH@<>}720-<oi-1;2K$Hl>vuE#z6Tuw-~0USRD3U7@-xA`uCBedxTg>7yG5J(YeVUO z1^6$*IKQjeJ*=m--DBXR<L*AR7oq=(5dOIm{JF1k1pykZgWK-EGoazV%qvghf2r?E zoO4?+wkbl82YIEBb&}f`8@t=reW>JKyhTcH{=roG;h5xEvK9W^h~u)6wT1m#Ytoe6 z@{_6f-4UJZ>oydxAA{HFza3qLzUk%4mNtlYjNh8qn=8tfqaGUo`@2GLy@51CdbKwj z@Ov`nk_SLuq005~xF;MpxR+r}uSylla~)R>Md<IVOq!%&ea*6z*}}Q#zy1vL*Tr9Q z5$<0H;rHQbh_9sgjSrlG{sGd=Od4*mk3u*XwAY=1zSIRpi<rry63z0IS>}m{bWc{o z8R!#m|7;LH(ae}I(r_+lOPzt9Lp!>){miUiu}~6wb(Q@2^6@_Iju3P1;MicqisK%W z?(JGp_Z=bVg1egh^X`AZ|H-(gS}tu8J~73L7Ul0-;{on>AjTsm$MLq!o9g{EXbt9& ze-q$rr9ezf%#KeR*2fxJXYhNsNtr#}Bz)A!yixsC^G3B-(Qa%~=FBj=cWhRgPaA${ zI0uXioQ=7E{MtNu^6aZ$=Uwc@Scl)Izr%gt4;p`H-w)rJ{ri64eW}5ie2Dur(qi7V zndEKB_?>3a)mL6=nl@=7v!_p!b*okphHdm2j*$j9(|04wFH{|a&If@3z*=CBA8fOa zW2DKjr21lg%|Vh?aNgc#aRD5-yC{Ckb8r+N?I&?s@`tZ?a=Y)-oJR=3_i4qTU3tLX zr&Yn649X*UF1>YkzH1-dpBa!Ad;<6Kxr&sYTXN7*<WNO^_Dq1ZoMUy#RWd$>InAB- zYn^v3*)BBxgd(_~w47t-$6Oen!uuM&Bj`qvri+Ad_pwb{&av}-rQ%a~kAU~#0^r{T z-t4UiHO4uC`K8fL#%C+v(efh(b?o0CQm}3No%gu#H|N+=2JKMKR~H?|=Oz$pjB{)$ zi}rGSMlQ=FNXt346u)q`Z|e#1ZAX7*Kw8d8EBE*=ulQB<_HCrqwCQ-JdHa4~YY_Io z)wPo}oscA?#ngM!rfciNHq9EzkiOjoe<cKs@y~=Vt(!{UuGk0e^L-d%{GC>xHj;@W z6B&<iQ1CeW#trQ!ZCiZ8`R@de<L~QVc=`#$Sk{j{ct5`<R|E3+QSGsZ?mxz{e}RUy zz-a~7{i)-I560f$Rq{!r2J+y2RTQ5#ZlHY}Bh6_O(>h9EPsZvVojYP*(jI@TvY)lh zz7oZYuLkMaVi0kU+y~fOwCr!U-0~yAHv0hgUON1VO?J47Wd@6Jhe4#qVlM%{ArS|# Hzu^A>c5TWo literal 0 HcmV?d00001 diff --git a/components/cryptini/latest_stable/demo/uinputsectionvaluesform.lfm b/components/cryptini/latest_stable/demo/uinputsectionvaluesform.lfm new file mode 100644 index 000000000..c7efd9ec2 --- /dev/null +++ b/components/cryptini/latest_stable/demo/uinputsectionvaluesform.lfm @@ -0,0 +1,86 @@ +object InputSectionValuesForm: TInputSectionValuesForm + Left = 1154 + Height = 314 + Top = 456 + Width = 535 + BorderIcons = [biSystemMenu] + BorderStyle = bsSingle + Caption = 'InputSectionValuesForm' + ClientHeight = 314 + ClientWidth = 535 + OnCreate = FormCreate + OnShow = FormShow + Position = poMainFormCenter + LCLVersion = '1.7' + object Grp_NewSectionValues: TGroupBox + Left = 0 + Height = 43 + Top = 0 + Width = 535 + Align = alTop + AutoSize = True + Caption = 'Input new section values' + ChildSizing.HorizontalSpacing = 10 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 4 + ClientHeight = 23 + ClientWidth = 531 + TabOrder = 0 + object Lbl_SectionName: TLabel + Left = 0 + Height = 23 + Top = 0 + Width = 183 + Caption = 'New Section Name:' + ParentColor = False + end + object edt_NewSectionName: TEdit + Left = 193 + Height = 23 + Top = 0 + Width = 159 + AutoSize = False + OnEditingDone = edt_NewSectionNameEditingDone + TabOrder = 0 + Text = 'My New Section' + end + object lbl_Invisible1: TLabel + Left = 362 + Height = 23 + Top = 0 + Width = 80 + ParentColor = False + end + object lbl_Invisible2: TLabel + Left = 452 + Height = 23 + Top = 0 + Width = 79 + ParentColor = False + end + end + object cmd_Close: TBitBtn + Left = 432 + Height = 26 + Top = 272 + Width = 90 + AutoSize = True + Caption = '&Finished' + Kind = bkClose + ModalResult = 11 + TabOrder = 1 + end + object cmd_Cancel: TBitBtn + Left = 344 + Height = 26 + Top = 273 + Width = 82 + AutoSize = True + Cancel = True + DefaultCaption = True + Kind = bkCancel + ModalResult = 2 + TabOrder = 2 + end +end diff --git a/components/cryptini/latest_stable/demo/uinputsectionvaluesform.pas b/components/cryptini/latest_stable/demo/uinputsectionvaluesform.pas new file mode 100644 index 000000000..8a3e51866 --- /dev/null +++ b/components/cryptini/latest_stable/demo/uinputsectionvaluesform.pas @@ -0,0 +1,156 @@ +unit uInputSectionValuesForm; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, + Buttons; + +const + C_NUMBEROFCONTROLS = 8; // Only need to change it here + +type + + { TInputSectionValuesForm } + + TInputSectionValuesForm = class(TForm) + cmd_Cancel: TBitBtn; + cmd_Close: TBitBtn; + edt_NewSectionName: TEdit; + lbl_Invisible2: TLabel; + Lbl_SectionName: TLabel; + Grp_NewSectionValues: TGroupBox; + lbl_Invisible1: TLabel; + procedure edt_NewSectionNameEditingDone(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormShow(Sender: TObject); + private + procedure DisableSectionNameEdit; + procedure InitControls; + procedure ProcessCheckbox(Sender: TObject); + procedure ProcessValueEdit(Sender: TObject); + public + ValueLabelArray: array[0..C_NUMBEROFCONTROLS - 1] of TLabel; + IdentEditArray: array[0..C_NUMBEROFCONTROLS - 1] of TEdit; + ValueEditArray: array[0..C_NUMBEROFCONTROLS - 1] of TEdit; + ValueCheckBoxArray: array[0..C_NUMBEROFCONTROLS - 1] of TCheckBox; + sSectionName: string; + NumberOfControls: integer; + end; + +var + InputSectionValuesForm: TInputSectionValuesForm; + +implementation + +{$R *.lfm} + +{ TInputSectionValuesForm } +procedure TInputSectionValuesForm.InitControls; +var + iCount: integer; +begin + BeginFormUpdate; + NumberOfControls := High(ValueLabelArray) + 1; + for iCount := Low(ValueLabelArray) to High(ValueLabelArray) do + begin + ValueLabelArray[iCount] := TLabel.Create(Grp_NewSectionValues); + ValueLabelArray[iCount].Caption := Format('Key and Value %d', [iCount + 1]); + ValueLabelArray[iCount].Tag := iCount; + ValueLabelArray[iCount].parent := Grp_NewSectionValues; + + IdentEditArray[iCount] := TEdit.Create(Grp_NewSectionValues); + IdentEditArray[iCount].Text := 'Input Key here'; + IdentEditArray[iCount].Tag := iCount; + // IdentEditArray[iCount].OnEditingDone:=@ProcessEdit; + IdentEditArray[iCount].parent := Grp_NewSectionValues; + + ValueEditArray[iCount] := TEdit.Create(Grp_NewSectionValues); + ValueEditArray[iCount].Text := 'Input value here'; + ValueEditArray[iCount].Tag := iCount; + ValueEditArray[iCount].OnEditingDone := @ProcessValueEdit; + ValueEditArray[iCount].parent := Grp_NewSectionValues; + + ValueCheckBoxArray[iCount] := TCheckBox.Create(Grp_NewSectionValues); + ValueCheckBoxArray[iCount].Caption := 'Integer?'; + ValueCheckBoxArray[iCount].Checked := False; + ValueCheckBoxArray[iCount].Tag := iCount; + ValueCheckBoxArray[iCount].TabStop:=FALSE; + ValueCheckBoxArray[iCount].OnClick := @ProcessCheckbox; + ValueCheckBoxArray[iCount].parent := Grp_NewSectionValues; + end; + EndFormUpdate; +end; + +procedure TInputSectionValuesForm.ProcessCheckbox(Sender: TObject); +// Triggered by OnClick event +var + TempCheckBox: TCheckBox; + iTag, iTest: integer; +begin + TempCheckBox := Sender as TCheckBox; + iTag := TempCheckBox.Tag; + // Validate associated Edit text + if ValueCheckBoxArray[iTag].Checked then + if (TryStrToInt(ValueEditArray[iTag].Text, iTest) = False) then + begin + ValueCheckBoxArray[iTag].Checked := False; + ShowMessageFmt('%s is not an Integer! Please edit it first.', + [ValueEditArray[iTag].Text]); + end; +end; + +procedure TInputSectionValuesForm.ProcessValueEdit(Sender: TObject); +// Triggered by OnEditingDone event +var + TempEdit: TEdit; + iTag, iTest: integer; + +begin + TempEdit := Sender as TEdit; + iTag := TempEdit.Tag; + // Auto check/uncheck associated checkbox + if TryStrToInt(TempEdit.Text, iTest) then + ValueCheckBoxArray[iTag].Checked := True + else + ValueCheckBoxArray[iTag].Checked := False; + // cmd_Close.SetFocus; // Enable this if you put a ShowMessage in this proc +end; + +procedure TInputSectionValuesForm.DisableSectionNameEdit; +begin + edt_NewSectionName.Enabled := False; +end; + +procedure TInputSectionValuesForm.FormCreate(Sender: TObject); +begin + Caption := Application.Title + ' - Make New Section'; + Icon := Application.Icon; + InitControls; + sSectionName := edt_NewSectionName.Text; +end; + +procedure TInputSectionValuesForm.edt_NewSectionNameEditingDone(Sender: TObject); +begin + sSectionName := edt_NewSectionName.Text; +end; + +procedure TInputSectionValuesForm.FormShow(Sender: TObject); +var + iCount: integer; +begin + // Reinitialise controls + edt_NewSectionName.Enabled := True; + for iCount := 0 to NumberOfControls - 1 do + begin + ; + IdentEditArray[iCount].Text := Format('Input Key %d here', [iCount + 1]); + ValueEditArray[iCount].Text := Format('Input value %d here', [iCount + 1]); + ValueCheckBoxArray[iCount].Checked := False; + end; + edt_NewSectionName.Text := 'My New Section'; +end; + +end. diff --git a/components/cryptini/latest_stable/demo/ukeydialog.lfm b/components/cryptini/latest_stable/demo/ukeydialog.lfm new file mode 100644 index 000000000..03483d39d --- /dev/null +++ b/components/cryptini/latest_stable/demo/ukeydialog.lfm @@ -0,0 +1,59 @@ +object keydialog: Tkeydialog + Left = 359 + Height = 132 + Top = 268 + Width = 320 + BorderIcons = [biSystemMenu] + BorderStyle = bsDialog + Caption = 'keydialog' + ClientHeight = 132 + ClientWidth = 320 + DefaultMonitor = dmMainForm + OnCreate = FormCreate + OnShow = FormShow + Position = poMainFormCenter + ShowInTaskBar = stNever + LCLVersion = '1.7' + object lbl_info: TLabel + Left = 0 + Height = 15 + Top = 16 + Width = 320 + Alignment = taCenter + AutoSize = False + Caption = 'Choose either a Phrase or a number as your key' + ParentColor = False + end + object edt_key: TEdit + Left = 35 + Height = 23 + Top = 40 + Width = 250 + TabOrder = 0 + Text = 'Type a phrase or number' + end + object BitBtn1: TBitBtn + Left = 123 + Height = 26 + Top = 80 + Width = 82 + AutoSize = True + Cancel = True + DefaultCaption = True + Kind = bkCancel + ModalResult = 2 + TabOrder = 1 + end + object BitBtn2: TBitBtn + Left = 216 + Height = 26 + Top = 80 + Width = 62 + AutoSize = True + Default = True + DefaultCaption = True + Kind = bkOK + ModalResult = 1 + TabOrder = 2 + end +end diff --git a/components/cryptini/latest_stable/demo/ukeydialog.pas b/components/cryptini/latest_stable/demo/ukeydialog.pas new file mode 100644 index 000000000..e319fc494 --- /dev/null +++ b/components/cryptini/latest_stable/demo/ukeydialog.pas @@ -0,0 +1,51 @@ +unit ukeydialog; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, Forms, StdCtrls, + Buttons; + +type + + { Tkeydialog } + + Tkeydialog = class(TForm) + BitBtn1: TBitBtn; + BitBtn2: TBitBtn; + edt_key: TEdit; + lbl_info: TLabel; + procedure FormCreate(Sender: TObject); + procedure FormShow(Sender: TObject); + private + + public + Var sKeyPhrase:String; + end; + +var + keydialog: Tkeydialog; + +implementation + +{$R *.lfm} + +{ Tkeydialog } + +procedure Tkeydialog.FormCreate(Sender: TObject); +begin + Caption := Application.Title + ' Key Chooser'; + Icon := Application.Icon; + sKeyPhrase:='Type a phrase or number'; + edt_key.Text:=sKeyPhrase; +end; + +procedure Tkeydialog.FormShow(Sender: TObject); +begin + edt_key.Text:=sKeyPhrase; +end; + +end. + diff --git a/components/cryptini/latest_stable/demo/umainform.lfm b/components/cryptini/latest_stable/demo/umainform.lfm new file mode 100644 index 000000000..d4f74d5ff --- /dev/null +++ b/components/cryptini/latest_stable/demo/umainform.lfm @@ -0,0 +1,348 @@ +object mainform: Tmainform + Left = 874 + Height = 327 + Top = 158 + Width = 469 + BorderIcons = [biSystemMenu, biMinimize] + BorderStyle = bsSingle + Caption = 'mainform' + ClientHeight = 307 + ClientWidth = 469 + Menu = MainMenu1 + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + Position = poScreenCenter + LCLVersion = '1.7' + object lbl_Section: TLabel + Left = 8 + Height = 15 + Top = 88 + Width = 74 + Caption = 'Section Name' + ParentColor = False + end + object edt_Section: TEdit + Left = 88 + Height = 23 + Top = 88 + Width = 195 + Font.Style = [fsBold] + ParentFont = False + TabOrder = 0 + Text = 'TestSection' + end + object lbl_Ident: TLabel + Left = 16 + Height = 15 + Top = 116 + Width = 51 + Caption = 'Test Ident' + ParentColor = False + end + object edt_Ident: TEdit + Left = 88 + Height = 23 + Top = 116 + Width = 195 + TabOrder = 1 + Text = 'Password' + end + object lbl_Value: TLabel + Left = 16 + Height = 15 + Top = 144 + Width = 55 + Caption = 'Test String' + ParentColor = False + end + object edt_Value: TEdit + Left = 88 + Height = 23 + Top = 144 + Width = 195 + TabOrder = 2 + Text = 'mypassword' + end + object cmd_Close: TBitBtn + Left = 368 + Height = 26 + Top = 263 + Width = 75 + AutoSize = True + DefaultCaption = True + Kind = bkClose + ModalResult = 11 + OnClick = mnu_fileCloseClick + TabOrder = 3 + end + object lbl_Integer: TLabel + Left = 16 + Height = 15 + Top = 172 + Width = 61 + Caption = 'Test Integer' + ParentColor = False + end + object edt_Integer: TEdit + Left = 88 + Height = 23 + Top = 172 + Width = 195 + OnEditingDone = edt_IntegerEditingDone + TabOrder = 4 + Text = '12345' + end + object cmd_ShowINI: TButton + Left = 16 + Height = 25 + Top = 264 + Width = 186 + Caption = 'Show/Edit INI' + OnClick = cmd_ShowINIClick + TabOrder = 5 + end + object rg_Encryption: TRadioGroup + Left = 16 + Height = 58 + Top = 200 + Width = 76 + AutoFill = True + AutoSize = True + Caption = 'Encryption' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 38 + ClientWidth = 72 + ItemIndex = 0 + Items.Strings = ( + 'On' + 'Off' + ) + OnSelectionChanged = rg_EncryptionSelectionChanged + TabOrder = 6 + end + object rg_SectionHashing: TRadioGroup + Left = 96 + Height = 58 + Top = 200 + Width = 105 + AutoFill = True + AutoSize = True + Caption = 'Section Hashing' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 38 + ClientWidth = 101 + ItemIndex = 0 + Items.Strings = ( + 'On' + 'Off' + ) + OnSelectionChanged = rg_SectionHashingSelectionChanged + TabOrder = 7 + end + object GroupBox1: TGroupBox + Left = 304 + Height = 163 + Top = 8 + Width = 139 + AutoSize = True + Caption = 'Section Tests' + ChildSizing.VerticalSpacing = 5 + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 143 + ClientWidth = 135 + TabOrder = 8 + object cmd_WriteSection: TButton + Left = 0 + Height = 25 + Top = 0 + Width = 135 + AutoSize = True + Caption = 'Write Whole Section' + OnClick = cmd_WriteSectionClick + TabOrder = 0 + end + object cmd_ReadSectionValues: TButton + Left = 0 + Height = 25 + Top = 30 + Width = 135 + AutoSize = True + Caption = 'Read Whole Section' + OnClick = cmd_ReadSectionValuesClick + TabOrder = 1 + end + object cmd_VerifySectionValues: TButton + Left = 0 + Height = 25 + Top = 60 + Width = 135 + AutoSize = True + Caption = 'Verify Whole Section' + OnClick = cmd_VerifySectionValuesClick + TabOrder = 2 + end + object cmd_EraseSection: TButton + Left = 0 + Height = 25 + Top = 90 + Width = 135 + AutoSize = True + Caption = 'Erase Whole Section' + OnClick = cmd_EraseSectionClick + TabOrder = 3 + end + object cmb_Sections: TComboBox + Left = 0 + Height = 23 + Top = 120 + Width = 135 + ItemHeight = 15 + OnSelect = cmb_SectionsSelect + Style = csDropDownList + TabOrder = 4 + end + end + object Grp_DefaultValueTests: TGroupBox + Left = 16 + Height = 70 + Top = 8 + Width = 284 + AutoSize = True + Caption = 'Default Value Tests' + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 3 + ClientHeight = 50 + ClientWidth = 280 + TabOrder = 9 + object cmd_Write: TButton + Left = 0 + Height = 25 + Top = 0 + Width = 91 + AutoSize = True + Caption = 'Write Values' + OnClick = cmd_WriteClick + TabOrder = 0 + end + object cmd_Read: TButton + Left = 91 + Height = 25 + Top = 0 + Width = 96 + AutoSize = True + Caption = 'Read Values' + OnClick = cmd_ReadClick + TabOrder = 1 + end + object cmd_Verify: TButton + Left = 187 + Height = 25 + Top = 0 + Width = 93 + AutoSize = True + Caption = 'Verify Values' + OnClick = cmd_VerifyClick + TabOrder = 2 + end + object cmd_ValueExists: TButton + Left = 0 + Height = 25 + Top = 25 + Width = 91 + AutoSize = True + Caption = 'Values Exist' + OnClick = cmd_ValueExistsClick + TabOrder = 3 + end + object cmd_DeleteValue: TButton + Left = 91 + Height = 25 + Top = 25 + Width = 96 + AutoSize = True + Caption = 'Delete Values' + OnClick = cmd_DeleteValueClick + TabOrder = 4 + end + end + object grp_convert: TGroupBox + Left = 304 + Height = 45 + Top = 176 + Width = 133 + AutoSize = True + Caption = 'Upgrade existing INI' + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 25 + ClientWidth = 129 + TabOrder = 10 + object cmd_convertToCryptini: TButton + Left = 0 + Height = 25 + Top = 0 + Width = 129 + AutoSize = True + Caption = 'Convert to CryptINI' + OnClick = cmd_convertToCryptiniClick + TabOrder = 0 + end + end + object MainMenu1: TMainMenu + Left = 432 + object mnu_file: TMenuItem + Caption = '&File' + object mnu_fileClose: TMenuItem + Caption = 'E&xit' + OnClick = mnu_fileCloseClick + end + end + object mnu_options: TMenuItem + Caption = '&Options' + object mnu_optionsEncryptionKey: TMenuItem + Caption = 'Integer En&cryption key...' + OnClick = mnu_optionsEncryptionKeyClick + end + object mnu_optionsEncryptINIFile: TMenuItem + Caption = 'Encrypt INI file' + OnClick = mnu_optionsEncryptINIFileClick + end + object mnu_optionsDecryptINIFile: TMenuItem + Caption = 'Decrypt INI file' + OnClick = mnu_optionsDecryptINIFileClick + end + end + object mnu_help: TMenuItem + Caption = '&Help' + object mnu_helpHelp: TMenuItem + Caption = 'Help' + OnClick = mnu_helpHelpClick + end + object mnu_helpAbout: TMenuItem + Caption = '&About..' + OnClick = mnu_helpAboutClick + end + end + end + object OpenDialog1: TOpenDialog + Title = 'Open existing INI file' + Filter = 'INI file|*.ini|Any File|*.*' + Options = [ofReadOnly, ofNoTestFileCreate, ofEnableSizing, ofViewDetail] + Left = 384 + Top = 8 + end +end diff --git a/components/cryptini/latest_stable/demo/umainform.pas b/components/cryptini/latest_stable/demo/umainform.pas new file mode 100644 index 000000000..03905ac4c --- /dev/null +++ b/components/cryptini/latest_stable/demo/umainform.pas @@ -0,0 +1,993 @@ +unit umainform; + +{$DEFINE USE_DCPCRYPT}// Delete this if you don't have the DCrypt library +// It enables the 'Encrypt INI' and 'Decrypt INI' menu entries +// {$DEFINE USE_THREADSAFE} // Enable this for the thread-safe version + +{ Test App for cryptini unit + + Copyright (C) 2016 Gordon Bamber minesadorada@gmail.com + Encrypt/Decrypt INI code: @Ericktux (http://forum.lazarus.freepascal.org) + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License + for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +} +{$mode objfpc}{$H+} + +interface + +uses + SysUtils, LazFileUtils, FileUtil, Forms, Dialogs, StdCtrls, Controls, Classes, + Buttons, ExtCtrls, Menus, ucryptini, umemoform, ukeydialog, + uInputSectionValuesForm; + +const + {$IFDEF WINDOWS} + C_OS = 'win'; + {$ELSE} + C_OS = 'linux'; + {$ENDIF} + {$IFDEF CPU32} + C_BITNESS = '32'; + {$ELSE} + C_BITNESS = '64'; + {$ENDIF} + C_PFX = C_OS + C_BITNESS; + C_KEYPHRASE = 'Rudolph the Red Nosed Reindeer: had a very shiny nose'; + + C_VERSION = '1.0.0.5'; + +type + + { Tmainform } + + Tmainform = class(TForm) + cmd_convertToCryptini: TButton; + cmd_DeleteValue: TButton; + cmd_EraseSection: TButton; + cmd_Read: TButton; + cmd_ReadSectionValues: TButton; + cmd_ShowINI: TButton; + cmd_Close: TBitBtn; + cmd_ValueExists: TButton; + cmd_Verify: TButton; + cmd_VerifySectionValues: TButton; + cmd_Write: TButton; + cmd_WriteSection: TButton; + cmb_Sections: TComboBox; + edt_Value: TEdit; + edt_Section: TEdit; + edt_Ident: TEdit; + edt_Integer: TEdit; + GroupBox1: TGroupBox; + grp_convert: TGroupBox; + Grp_DefaultValueTests: TGroupBox; + lbl_Value: TLabel; + lbl_Section: TLabel; + lbl_Ident: TLabel; + lbl_Integer: TLabel; + MainMenu1: TMainMenu; + mnu_optionsDecryptINIFile: TMenuItem; + mnu_optionsEncryptINIFile: TMenuItem; + mnu_helpAbout: TMenuItem; + mnu_helpHelp: TMenuItem; + mnu_help: TMenuItem; + mnu_optionsEncryptionKey: TMenuItem; + mnu_fileClose: TMenuItem; + mnu_options: TMenuItem; + mnu_file: TMenuItem; + OpenDialog1: TOpenDialog; + rg_Encryption: TRadioGroup; + rg_SectionHashing: TRadioGroup; + procedure cmb_SectionsSelect(Sender: TObject); + procedure cmd_convertToCryptiniClick(Sender: TObject); + procedure cmd_DeleteValueClick(Sender: TObject); + procedure cmd_ReadClick(Sender: TObject); + procedure cmd_ReadSectionValuesClick(Sender: TObject); + procedure cmd_ShowINIClick(Sender: TObject); + procedure cmd_ValueExistsClick(Sender: TObject); + procedure cmd_VerifyClick(Sender: TObject); + procedure cmd_VerifySectionValuesClick(Sender: TObject); + procedure cmd_WriteClick(Sender: TObject); + procedure cmd_EraseSectionClick(Sender: TObject); + procedure cmd_WriteSectionClick(Sender: TObject); + procedure edt_IntegerEditingDone(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure mnu_fileCloseClick(Sender: TObject); + procedure mnu_helpAboutClick(Sender: TObject); + procedure mnu_helpHelpClick(Sender: TObject); + {$IFDEF USE_DCPCRYPT} + procedure mnu_optionsDecryptINIFileClick(Sender: TObject); + procedure mnu_optionsEncryptINIFileClick(Sender: TObject); + {$ENDIF} + procedure mnu_optionsEncryptionKeyClick(Sender: TObject); + procedure rg_EncryptionSelectionChanged(Sender: TObject); + procedure rg_SectionHashingSelectionChanged(Sender: TObject); + private + IniFilePath: string; + {$IFDEF USE_THREADSAFE} + INI: TLockCryptIniFile; + {$ELSE} + INI: TCryptIniFile; + {$ENDIF} + sStoredMD5Hash: string; + sVersion: string; + public + + end; + +var + mainform: Tmainform; + +implementation + +{$R *.lfm} + +{ Tmainform } + +procedure Tmainform.FormCreate(Sender: TObject); +begin + IniFilePath := ProgramDirectory + 'test' + C_PFX + +{$IFDEF WINDOWS} + '.' + +{$ENDIF} + 'ini'; + +{$IFNDEF USE_DCPCRYPT} + mnu_optionsEncryptINIFile.Enabled := False; + mnu_optionsDecryptINIFile.Enabled := False; +{$ENDIF} + + {DEBUG - delete any old versions of the INI + if FileExists(IniFilePath) then + DeleteFile(IniFilePath); + } + Caption := Application.Title; + Icon := Application.Icon; + {$IFDEF USE_THREADSAFE} + INI := TLockCryptIniFile.Create(IniFilePath); + INI.Lock; + {$ELSE} + INI := TCryptIniFile.Create(IniFilePath); + {$ENDIF} + + // Create encryption key for secure Read/WriteInteger + INI.KeyPhrase := C_KEYPHRASE; + + // Or set INI.Key directly (weaker encryption) + // DEBUG: ShowMessageFmt('Key set to %d',[INI.Key]); + + // method: WriteIdent(Const sAuthor,sCopyright,sLicense,sContact:String;Force: boolean=False); + // No need to do this each time + // Comment this line out once you have the MD5Hash from the ini file + if INI.IsVirgin then // DeFlowers + begin + INI.WriteIdent('Gordon Bamber', '(c)2016', 'LGPL', 'minesadorada@gmail.com', True); + // MD5 for this is: 92abf0deecbb25c435bff507a396d92a + end + else + // someone tampered with the ident? + if not INI.VerifyIdent('92abf0deecbb25c435bff507a396d92a') then + begin + ShowMessage('Program ident has been tampered with.' + LineEnding + + 'Restoring correct version.'); + // Last parameter (Optional) forces a rewrite even if FirstRun = 0 + INI.WriteIdent('Gordon Bamber', '(c)2016', 'LGPL', 'minesadorada@gmail.com', True); + end; + + sVersion := C_VERSION; + sStoredMD5Hash := '32-character MD5Hash string'; + INI.ReadSections(cmb_Sections.Items); + cmb_Sections.ItemIndex := 0; + edt_Section.Text := 'TestSection'; +end; + +procedure Tmainform.FormDestroy(Sender: TObject); +begin + If Assigned(INI) then FreeAndNil(INI); +end; + +procedure Tmainform.FormShow(Sender: TObject); +begin + // Test the IsVirgin function + if INI.IsVirgin then + ShowMessage('First time run of this app'); +end; + +procedure Tmainform.mnu_fileCloseClick(Sender: TObject); +begin + Close; +end; + +procedure Tmainform.mnu_helpAboutClick(Sender: TObject); +// Shows ReadUnencryptedString method +var + s: string; +begin + s := Application.Title + LineEnding; + s += 'Version: ' + INI.ReadUnencryptedString('ProgramInfo', IDENT_APPVERSION, '') + LineEnding + LineEnding; + s += INI.ReadUnencryptedString('ProgramInfo', IDENT_COPYRIGHT, ''); + s += ' by ' + INI.ReadUnencryptedString('ProgramInfo', IDENT_AUTHOR, '') + LineEnding; + s += 'Licence: ' + INI.ReadUnencryptedString('ProgramInfo', IDENT_LICENSE, '') + + LineEnding; + s += 'Made with LCL v ' + INI.ReadUnencryptedString('ProgramInfo', IDENT_LCLVERSION, ''); + s += ' FPC v ' + INI.ReadUnencryptedString('ProgramInfo', IDENT_FPCVERSION, '') + + LineEnding; + s += 'Compiled ' + INI.ReadUnencryptedString('ProgramInfo', IDENT_LASTCOMPILED, ''); + s += ' for ' + INI.ReadUnencryptedString('ProgramInfo', IDENT_TARGET, '') + + LineEnding; + s += 'CryptINI Version: ' + INI.CryptINIVersion + LineEnding; + s += 'Cipher in use: ' + INI.CipherType + '. Hash in use: ' + INI.HashType + '.'; + MessageDlg('About ' + Application.Title, s, + mtInformation, [mbOK], 0); +end; + +procedure Tmainform.mnu_helpHelpClick(Sender: TObject); +begin + with ShowINIForm do + begin + MakeReadOnly; + Caption := 'Help for ' + Application.Title; + Memo_INI.Lines.Clear; + Memo_INI.Lines.Add('This test application is to test the Tcryptini class V ' + + INI.CryptINIVersion); + Memo_INI.Lines.Add(''); + Memo_INI.Lines.Add( + 'The obvious test is to click Write, Read then Verify, which uses automatic values.'); + Memo_INI.Lines.Add( + 'Verification of an entry involves reading the value with its built-in MD5Hash'); + Memo_INI.Lines.Add( + 'and then computing a new MD5Hash from the value, and comparing it with the built-in one.'); + Memo_INI.Lines.Add(''); + Memo_INI.Lines.Add( + 'Additionally, if SectionHashing=TRUE then every time a new entry is added to the section,'); + Memo_INI.Lines.Add( + 'all the entries are combined into a section hash, and it is written/updated as an automatic'); + Memo_INI.Lines.Add( + 'new/updated entry: MD5Hash=<32-character hash> ,which you can use in the VerifySection(MD5Has Value) method'); + Memo_INI.Lines.Add(''); + Memo_INI.Lines.Add( + 'There is a new method WriteSectionValues(Section,Strings) which is absent in TINIFile that you may find useful.'); + Memo_INI.Lines.Add( + 'WriteSectionValues works with PlainText TRUE/FALSE and SectionHashing TRUE/FALSE.'); + Memo_INI.Lines.Add(''); + Memo_INI.Lines.Add( + 'Other new methods are EncryptINI and DecryptINI. This acts on the whole INI file,'); + Memo_INI.Lines.Add( + 'with password, new file extension and auto-deleting the "old" file as optional parameters.'); + Memo_INI.Lines.Add('The defaults are the INI.KeyPhrase, ".enc" and no auto-deletion.'); + Memo_INI.Lines.Add(''); + Memo_INI.Lines.Add( + 'Wnen property PlainText=TRUE then TCryptINI behaves just as TINIFile did'); + Memo_INI.Lines.Add( + 'This property can be changed on-the-fly to enable a mixed Crypted/Plaintext INI file.'); + Memo_INI.Lines.Add(''); + Memo_INI.Lines.Add( + 'Note that Integer keys have an automatic "' + INTEGER_MARKER + + '" added in encrypted mode.'); + Memo_INI.Lines.Add( + 'This is so that the ReadSection method can identify them in Encrypted mode.'); + Memo_INI.Lines.Add( + '(Integers are double-encrypted for extra security, so need to be read differently from all other types)'); + Memo_INI.Lines.Add(''); + Memo_INI.Lines.Add( + 'When testing, use the Show/Edit INI button to see the results. This will help you to understand'); + Memo_INI.Lines.Add( + 'how CryptINI works, and what it can do.'); + Memo_INI.Lines.Add(''); + Memo_INI.Lines.Add('CryptINI was designed to solve 2 issues:'); + Memo_INI.Lines.Add( + '1. Making sure the ProgramInfo section is never altered, assuring you attribution stays secure.'); + Memo_INI.Lines.Add( + 'Once you have the MD5Hash of it, you can easily make an "authenticity checker" app using CryptINI'); + Memo_INI.Lines.Add( + '2. Storing Passwords and Scores in an editable INI file which is tamper-proof to the casual hacker.'); + Memo_INI.Lines.Add( + '(If numbers are written using WriteInteger, they are especially difficult to alter)'); + Memo_INI.Lines.Add(''); + Memo_INI.Lines.Add('In this app and ucryptini.pas is a DEFINE: {$DEFINE USE_DCPCRYPT}'); + Memo_INI.Lines.Add( + 'This assumes you have the DCPCrypt runtime/designtime component installed.'); + Memo_INI.Lines.Add( + 'If you haven''t then either install it or comment out the DEFINE and'); + Memo_INI.Lines.Add( + 'remove it from Project Inspector. It is available via OnlinePackageManager'); + Memo_INI.Lines.Add(''); + Memo_INI.Lines.Add('Open ucryptini in a text editor to look at the commented code'); + Memo_INI.Lines.Add('- Enjoy!'); + ShowModal; + end; +end; + +{$IFDEF USE_DCPCRYPT} +procedure Tmainform.mnu_optionsDecryptINIFileClick(Sender: TObject); +begin + if MessageDlg('Delete encrypted INI file?', mtConfirmation, [mbYes, mbNo], 0, mbYes) = + mrYes then + INI.DecryptINI(True) + else + INI.DecryptINI(False); + // Remember to reset the key phrase! + INI.KeyPhrase := C_KEYPHRASE; + + // Update controls + cmb_Sections.Clear; + INI.ReadSections(cmb_Sections.Items); + cmb_Sections.Refresh; + cmb_Sections.ItemIndex := 0; +end; + +procedure Tmainform.mnu_optionsEncryptINIFileClick(Sender: TObject); +begin + if MessageDlg('Delete unencrypted INI file?', mtConfirmation, + [mbYes, mbNo], 0, mbYes) = mrYes then + INI.EncryptINI(True) + else + INI.EncryptINI(False); + Application.ProcessMessages; + // Update controls + cmb_Sections.Clear; + cmb_Sections.ItemIndex := 0; +end; + +{$ENDIF} + +procedure Tmainform.mnu_optionsEncryptionKeyClick(Sender: TObject); +var + s: string; + l: longint; +begin + keydialog.sKeyPhrase := INI.KeyPhrase; + KeyDialog.ShowModal; + if KeyDialog.ModalResult = mrOk then + begin + s := KeyDialog.edt_key.Text; + if TryStrToInt(s, l) then + INI.Key := l + else + INI.Keyphrase := s; + ShowMessage('Key changed successfully'); + end; +end; + +procedure Tmainform.rg_EncryptionSelectionChanged(Sender: TObject); +begin + if rg_Encryption.ItemIndex = 0 then + INI.PlainTextMode := False + else + INI.PlainTextMode := True; + if INI.PlainTextMode = True then + begin + rg_SectionHashing.ItemIndex := 1; + INI.SectionHashing := False; + end; + cmd_Read.Enabled := False; + cmd_Verify.Enabled := False; +end; + +procedure Tmainform.rg_SectionHashingSelectionChanged(Sender: TObject); +begin + if rg_SectionHashing.ItemIndex = 0 then + INI.SectionHashing := True + else + INI.SectionHashing := False; +end; + +procedure Tmainform.cmd_WriteClick(Sender: TObject); +var + s: string; +begin + // Best results when writing to TestSection + if (edt_Section.Text <> 'TestSection') then + if MessageDlg('Please confirm', 'Are you sure you want to write to ' + + edt_Section.Text + '? (It should be "TestSection")', mtConfirmation, + [mbYes, mbNo], 0, mbNo) = mrNo then + begin + edt_Section.Text := 'TestSection'; + ShowMessage('OK. Writing to default section "TestSection" instead'); + end; + INI.SectionHashing := False; + INI.WriteString(edt_Section.Text, edt_Ident.Text, edt_Value.Text); + INI.WriteInteger(edt_Section.Text, 'Integer', StrToInt(edt_Integer.Text)); + // Write other types as a test + INI.WriteBool(edt_Section.Text, 'Boolean', True); + INI.WriteFloat(edt_Section.Text, 'Float', 3.142); + INI.WriteDateTime(edt_Section.Text, 'Date', StrToDate('15/10/2016', + 'dd mm yyyy', '/')); + INI.WriteInt64(edt_Section.Text, 'Int64', 1000); + INI.SectionHashing := True; + INI.MakeSectionHash(edt_Section.Text, True); + cmd_Read.Enabled := True; + cmd_Verify.Enabled := True; + s := 'Values written:' + LineEnding; + s += 'WriteString: ' + edt_Value.Text + LineEnding; + s += 'WriteFloat: 3.142' + LineEnding; + s += 'WriteDateTime: 15/10/2016' + LineEnding; + s += 'WriteInt64: 1000' + LineEnding; + s += 'WriteInteger: ' + edt_Integer.Text + LineEnding; + INI.ReadSections(cmb_Sections.Items); + cmb_Sections.ItemIndex := Pred(cmb_Sections.Items.Count); + ShowMessage(s); +end; + +procedure Tmainform.cmd_EraseSectionClick(Sender: TObject); +begin + if not INI.SectionExists(edt_Section.Text) then + begin + ShowMessage(edt_Section.Text + ' is absent, so nothing to erase!'); + Exit; + end; + if edt_Section.Text = IDENT_SECTION then + if MessageDlg('Please confirm', 'Are you sure you want to delete ' + + IDENT_SECTION + '?', mtConfirmation, [mbCancel, mbYes], 0, mbCancel) = + mrCancel then + exit; + INI.EraseSection(edt_Section.Text); + ShowMessage('Section ' + edt_Section.Text + ' is no more.'); + INI.ReadSections(cmb_Sections.Items); + cmb_Sections.ItemIndex := 0; +end; + +procedure Tmainform.cmd_WriteSectionClick(Sender: TObject); +var + iCount: integer; + sTempSectionName: string; + MyStringList: TStrings; +begin + with InputSectionValuesForm do + begin + ShowModal; + if ModalResult = mrCancel then + Exit; + sTempSectionName := sSectionName; + if sTempSectionName = IDENT_SECTION then + if MessageDlg('Please confirm', 'Are you sure you want to write to ' + + IDENT_SECTION + '?', mtConfirmation, [mbYes, mbCancel], 0, mbCancel) = + mrCancel then + exit; + edt_Section.Text := sSectionName; + MyStringList := TStringList.Create; + try + MyStringList.Clear; + MyStringList.BeginUpdate; + for iCount := 0 to (NumberOfControls - 1) do + MyStringList.Add(IdentEditArray[iCount].Text + '=' + + ValueEditArray[iCount].Text); + MyStringList.EndUpdate; + INI.WriteSectionValues(sSectionName, MyStringList); + INI.UpdateFile; + ShowMessage('Section ' + sTempSectionName + ' written successfully'); + finally + MyStringList.Free; + end; + end; + INI.ReadSections(cmb_Sections.Items); + cmb_Sections.ItemIndex := Pred(cmb_Sections.Items.Count); +end; + +procedure Tmainform.edt_IntegerEditingDone(Sender: TObject); +var + iTest: longint; +begin + if not TryStrToInt(edt_Integer.Text, iTest) then + begin + ShowMessageFmt('%s is not an Integer. Resetting to %s', + [edt_Integer.Text, '12345']); + edt_Integer.Text := '12345'; + end; +end; + +procedure Tmainform.cmd_ReadClick(Sender: TObject); +var + s: string; +begin + if not INI.SectionExists(edt_Section.Text) then + begin + ShowMessage(edt_Section.Text + ' is absent, so nothing to read!'); + Exit; + end; + // Dont read IDENT_SECTION + if edt_Section.Text = IDENT_SECTION then + begin + cmd_ReadSectionValues.Click; + Exit; + end; + if (edt_Section.Text <> 'TestSection') then + if MessageDlg('Please confirm', 'Are you sure you want to read test values from ' + + edt_Section.Text + '?', mtConfirmation, [mbCancel, mbYes], 0, mbCancel) = + mrCancel then + begin + edt_Section.Text := 'TestSection'; + ShowMessage('OK. Reading default section "TestSection" instead'); + end; + + if INI.PlainTextMode then + INI.MD5Hash := 'n/a'; + s := INI.ReadString(edt_Section.Text, edt_Ident.Text, 'unknown'); + ShowMessageFmt('Value of %s in %s is %s %s(MD5 hash: %s)', + [edt_Ident.Text, edt_Section.Text, s, LineEnding, INI.MD5Hash]); + if INI.ReadBool(edt_Section.Text, 'Boolean', False) = True then + ShowMessageFmt('ReadBool is TRUE%s(MD5 hash: %s)', [LineEnding, INI.MD5Hash]) + else + ShowMessageFmt('ReadBool is FALSE%s(MD5 hash: %s)', [LineEnding, INI.MD5Hash]); + ShowMessageFmt('ReadFloat is %.3f%s(MD5 hash: %s)', + [INI.ReadFloat(edt_Section.Text, 'Float', 0), LineEnding, INI.MD5Hash]); + ShowMessageFmt('ReadDateTime is %s%s(MD5 hash: %s)', + [DateToStr(INI.ReadDateTime(edt_Section.Text, 'Date', NOW)), + LineEnding, INI.MD5Hash]); + ShowMessageFmt('ReadInt64 is %d%s(MD5 hash: %s)', + [INI.ReadInt64(edt_Section.Text, 'Int64', 0), LineEnding, INI.MD5Hash]); + ShowMessageFmt('ReadInteger is %d%s(MD5 hash: %s)', + [INI.ReadInteger(edt_Section.Text, 'Integer', 0), LineEnding, INI.MD5Hash]); +end; + +procedure Tmainform.cmb_SectionsSelect(Sender: TObject); +begin + edt_Section.Text := cmb_Sections.Items[cmb_Sections.ItemIndex]; + +end; + +procedure Tmainform.cmd_convertToCryptiniClick(Sender: TObject); +{ +** This routine is a good demonstation of what TCryptINI can do +** It converts old ini files into encrypted ones. + +** Workflow: +0. Inform user what is about to happen and offer bailout (very important!) +1. Backup old ini file +2. Make a working copy +3. Process the working copy +4. Seek approval of changes +5. If yes, Overwrite the old ini file and clean up +} +const + CR = LineEnding; +var + sINIFilePathToConvert, sSourceINIFilePath, s, TempSectionName, sKeyPhrase: string; + sValueEntry, sKey, sValue: string; + INIFileToConvert: TCryptINIFile; + SectionNameList, ValueList: TStrings; + iCount, jCount, lTemp: integer; + dtTemp: TDateTime; +begin + try // - EXCEPT + s := 'This utility will convert a regular INI file to a CryptINI file' + CR; + s += 'using the Password/Keyphrase of your choice.' + CR + CR; + s += 'Your chosen INI file will first be backed up in the same folder,' + CR; + s += 'and a working copy made. After the conversion you will have a' + CR; + s += 'chance to view the changes and either approve or revert them.' + CR + CR; + s += 'If you approve, the original INI file will be overwritten by' + CR; + s += 'the approved working copy.' + CR; + s += 'If you revert, your original INI file will remain intact.' + CR + CR; + s += 'Would you like to continue?' + CR; + if MessageDlg(s, mtConfirmation, [mbYes, mbNo], 0, mbYes) <> mrYes then + Exit; + if OpenDialog1.Execute then + sINIFilePathToConvert := OpenDialog1.FileName + else + Exit; + // Prevent changing this app's INI file + if sINIFilePathToConvert = INI.Filename then + begin + ShowMessage('You cannot choose the INI file for this application! Try again.'); + Exit; + end; + // Make a backup + if CopyFile(sINIFilePathToConvert, ChangeFileExt(sINIFilePathToConvert, '.bak')) then + ShowMessageFmt('Your existing INI file has been backed up to %s', + [ChangeFileExt(sINIFilePathToConvert, '.bak')]) + else + begin + ShowMessage('Could not write to ' + ExtractFileDir(sINIFilePathToConvert) + + ' - Quitting'); + Exit; + end; + // Make a working copy + sSourceINIFilePath := ChangeFileExt(sINIFilePathToConvert, '.src'); + if not CopyFile(sINIFilePathToConvert, sSourceINIFilePath) then + begin + ShowMessage('Could not write to ' + ExtractFileDir(sINIFilePathToConvert) + + ' - Quitting'); + Exit; + end; + // Use the working copy + INIFileToConvert := TCryptINIFile.Create(sSourceINIFilePath); + // Fetch a pass phrase + sKeyPhrase := InputBox('Pass Phrase', + 'Please type in your pass phrase for this INI file', C_KEYPHRASE); + INIFileToConvert.KeyPhrase := sKeyPhrase; + // Create temprary stringlists + SectionNameList := TStringList.Create; + ValueList := TStringList.Create; + try + // Use as a regular TiniFile + INIFileToConvert.PlainTextmode := True; + INIFileToConvert.SectionHashing := False; + SectionNameList.Clear; + // Fetch all the Section names + INIFileToConvert.ReadSections(SectionNameList); + if SectionNameList.Count > 0 then + // For each Sectionnane... + for iCount := 0 to Pred(SectionNameList.Count) do + begin + TempSectionName := SectionNameList[iCount]; + // Don't process ProgramInfo + if TempSectionName = IDENT_SECTION then + Continue; // Dont convert this + ValueList.Clear; + // Fetch all the Key=Values for this Section + INIFileToConvert.ReadSectionValues(TempSectionName, ValueList); + if ValueList.Count > 0 then + // For each Key-Value pair... + for jCount := 0 to Pred(ValueList.Count) do + begin + sValueEntry := ValueList[jCount]; + sKey := ''; + sValue := ''; + // Split into Key and Value + If NOT INI.SplitKeyValue(sValueEntry, sKey, sValue) then Continue; + // We have the valid key and value else skipped + // Don't process MD5Has key + if sKey = IDENT_MD5HASH then + Continue; + // Is it a number? + if TryStrToInt(sValue, lTemp) then // Integer + begin + INIFileToConvert.PlainTextMode := False; + // Is it a Boolean? + if ((lTemp = 0) or (lTemp = 1)) then // Guess a boolean value? + INIFileToConvert.WriteString(TempSectionName, sKey, sValue) + else + begin + // Process Integer Value + INIFileToConvert.PlainTextMode := True; + // Delete unencrypted key without INTEGER_MARKER + INIFileToConvert.DeleteKey(TempSectionName, sKey); + INIFileToConvert.PlainTextMode := False; + // Rewrite encrypted key with INTEGER_MARKER + INIFileToConvert.WriteInteger(TempSectionName, sKey, lTemp); + end; + INIFileToConvert.PlainTextMode := True; + end + else // String,Date + begin + // Process non-numeric values + INIFileToConvert.PlainTextMode := False; + // Is it a DateTime? + if TryStrToDateTime(sValue, dtTemp) then + INIFileToConvert.WriteDateTime(TempSectionName, sKey, dtTemp) + else + // Process String value + INIFileToConvert.WriteString(TempSectionName, sKey, sValue); + INIFileToConvert.PlainTextMode := True; + end; + // Hash the whole Section (Make MD5Hash entry) + INIFileToConvert.MakeSectionHash(TempSectionName, True); + end; + end; + // Conversion is done. Show the user the Working Copy + with ShowINIForm do + begin + MakeReadOnly; // Put memoform into readonly mode + cmd_Abort.Visible := True; // Show the invisible button + Caption := 'Contents of converted INI file'; + Memo_INI.Lines.Clear; + // Check the file is still there :) + if LazFileUtils.FileExistsUTF8(INIFileToConvert.Filename) then + begin + Memo_INI.Lines.LoadFromFile(INIFileToConvert.Filename); + sINIFilePath := INIFileToConvert.Filename; + cmd_Close.Caption := 'Approve conversion'; + // Display the INI to the user + ShowModal; + // Tidy up + cmd_Close.Caption := '&Close'; + cmd_Abort.Visible := False; // Make the button invisible again. + // What did the user decide? + if ModalResult <> mrAbort then // All good - proceed + begin + INIFileToConvert.UpdateFile; + Sleep(100); + // Overwrite old INI file: + if not CopyFile(sSourceINIFilePath, sINIFilePathToConvert) then + begin + ShowMessage('Could not Update ' + ExtractFileDir(sINIFilePathToConvert) + + ' - Quitting'); + Exit; + end; + +{ + // Encrypt file as well? + if MessageDlg( + 'Conversion Successful. Would you like to Encrypt the whole file as well?', + mtConfirmation, [mbYes, mbNo], 0, mbNo) = mrYes then + begin + // User wants to encrypt. Get a new pass phrase. + sKeyPhrase := InputBox('Pass Phrase', + 'Please type in your pass phrase for this INI file', C_KEYPHRASE); + // Work with the (changed) original + INIFileToConvert.Free; // Finished with the working copy + // Load the original + INIFileToConvert := TCryptINIFile.Create(sINIFilePathToConvert); + INIFileToConvert.KeyPhrase:=sKeyPhrase; + // Delete the old INI file or no? + if MessageDlg('Delete unencrypted INI file?', mtConfirmation, + [mbYes, mbNo], 0, mbYes) = mrYes then + INIFileToConvert.EncryptINI(True, sKeyPhrase, '.enc') + else + INIFileToConvert.EncryptINI(False, sKeyPhrase, '.enc'); + end; + } + // All went well - inform the user. + ShowMessage('All operations were successful.' + LineEnding + + 'Click OK to clean up temporary files'); + end + else + // User chose to Revert. sINIFilePathToConvert file is still intact. + + ShowMessage('Conversion aborted. INI file is unchanged.' + + LineEnding + 'Click OK to clean up temporary files'); + + // Tidy up: + // Delete working copy + if not DeleteFile(sSourceINIFilePath) then + begin + ShowMessage('Could not Delete ' + ExtractFileDir(sSourceINIFilePath) + + ' - Quitting'); + Exit; + end; + // Delete backup file as well? + if MessageDlg('Delete backup file?', mtConfirmation, [mbYes, mbNo], 0, mbYes) = + mrYes then + if not DeleteFile(ChangeFileExt(sINIFilePathToConvert, '.bak')) then + begin + ShowMessage('Could not Delete ' + + ExtractFileDir(ChangeFileExt(sINIFilePathToConvert, '.bak'))); + Exit; + end; + end; + end; + finally + ValueList.Free; + SectionNameList.Free; + FreeAndNil(INIFileToConvert); + end; + except + // It's a long routine. Let's hope we don't get here. + On E: Exception do + ShowMessageFmt('An error has occurred that is not your fault.%sThe error is%s', + [CR, E.Message]); + end; +end; + +procedure Tmainform.cmd_DeleteValueClick(Sender: TObject); +begin + if not INI.SectionExists(edt_Section.Text) then + begin + ShowMessage(edt_Section.Text + ' is absent, so nothing to read!'); + Exit; + end; + if (edt_Section.Text <> 'TestSection') then + if MessageDlg('Please confirm', 'Are you sure you want to delete test values from ' + + edt_Section.Text + '?', mtConfirmation, [mbCancel, mbYes], 0, mbCancel) = + mrCancel then + begin + edt_Section.Text := 'TestSection'; + ShowMessage('OK. Deleting values in default section "TestSection" instead'); + end; + ShowMessage('Deleting values "' + edt_Ident.Text + '" and "Integer"'); + INI.DeleteKey(edt_Section.Text, edt_Ident.Text); + INI.DeleteKey(edt_Section.Text, 'Integer'); + if INI.ValueExists(edt_Section.Text, edt_Ident.Text) then + ShowMessage(edt_Ident.Text + ' not deleted!') + else + ShowMessage(edt_Ident.Text + ' deleted'); + if INI.ValueExists(edt_Section.Text, 'Integer') then + ShowMessage('Integer not deleted!') + else + ShowMessage('Integer deleted'); + +end; + +procedure Tmainform.cmd_ReadSectionValuesClick(Sender: TObject); +var + MyStringList: TStrings; + iCount: integer; + TempPlainTextMode: boolean; +begin + if not INI.SectionExists(edt_Section.Text) then + begin + ShowMessage(edt_Section.Text + ' is absent, so nothing to read!'); + Exit; + end; + TempPlainTextMode := INI.PlainTextMode; + if edt_Section.Text = IDENT_SECTION then + INI.PlainTextMode := True; + MyStringList := TStringList.Create; + try + INI.ReadSectionValues(edt_Section.Text, MyStringList); + if MyStringList.Count > 0 then + for iCount := 0 to Pred(MyStringList.Count) do + ShowMessageFmt('Section name: %s%s(Value %d of %d): %s', + [edt_Section.Text, LineEnding, iCount + 1, MyStringList.Count, + MyStringList[iCount]]) + else + ShowMessage('Nothing in this section!'); + finally + MyStringList.Free; + end; + INI.PlainTextMode := TempPlainTextMode; +end; + +procedure Tmainform.cmd_ShowINIClick(Sender: TObject); +var + s: string; +begin + with ShowINIForm do + begin + MakeWriteable; + Caption := 'Contents of ' + INI.Filename; + Memo_INI.Lines.Clear; + {$WARN UNIT_DEPRECATED OFF} + if LazFileUtils.FileExistsUTF8(INI.Filename) then + begin + Memo_INI.Lines.LoadFromFile(INI.Filename); + sINIFilePath := INI.Filename; + ShowModal; + if bDirty then + begin + s := INI.KeyPhrase; + // Reload (with correct keyphrase) + INI.Free; + {$IFDEF USE_THREADSAFE} + INI := TLockCryptIniFile.Create(IniFilePath); + INI.Lock; + {$ELSE} + INI := TCryptIniFile.Create(IniFilePath); + {$ENDIF} + INI.KeyPhrase := s; + end; + end + else + ShowMessage('No INI file to show!'); + end; +end; + +procedure Tmainform.cmd_ValueExistsClick(Sender: TObject); +begin + if not INI.SectionExists(edt_Section.Text) then + begin + ShowMessage(edt_Section.Text + ' is absent, so nothing to read!'); + Exit; + end; + // Dont read IDENT_SECTION + if edt_Section.Text = IDENT_SECTION then + begin + ShowMessage('Switching Encryption mode off to read ' + IDENT_SECTION + 'section'); + rg_Encryption.ItemIndex := 1; + end; + if (edt_Section.Text <> 'TestSection') then + if MessageDlg('Please confirm', 'Are you sure you want to test values from ' + + edt_Section.Text + '?', mtConfirmation, [mbCancel, mbYes], 0, mbCancel) = + mrCancel then + begin + edt_Section.Text := 'TestSection'; + ShowMessage('OK. Reading default section "TestSection" instead'); + end; + + if INI.ValueExists(edt_Section.Text, edt_Ident.Text) then + ShowMessage('Key "' + edt_Ident.Text + '" exists') + else + ShowMessage('Key "' + edt_Ident.Text + '" is absent'); + if INI.ValueExists(edt_Section.Text, 'Integer') then + ShowMessage('Key "Integer" exists') + else + ShowMessage('Key "Integer" is absent'); +end; + +procedure Tmainform.cmd_VerifyClick(Sender: TObject); +var + TRUEFALSE: boolean; +begin + if not INI.SectionExists(edt_Section.Text) then + begin + ShowMessage(edt_Section.Text + ' is absent, so nothing to verify!'); + Exit; + end; + // Dont verify IDENT_SECTION + if edt_Section.Text = IDENT_SECTION then + begin + cmd_VerifySectionValues.Click; + Exit; + end; + if (edt_Section.Text <> 'TestSection') then + if MessageDlg('Please confirm', 'Are you sure you want to verify test values from ' + + edt_Section.Text + '?', mtConfirmation, [mbCancel, mbYes], 0, mbCancel) = + mrCancel then + begin + edt_Section.Text := 'TestSection'; + ShowMessage('OK. Verifying default section "TestSection" instead'); + end; + if INI.PlainTextMode = False then + begin + TRUEFALSE := True; // Assume success, look for failure + // Test all the value types one-by-one + TRUEFALSE := TRUEFALSE and INI.VerifyBool(edt_Section.Text, 'Boolean', True); + if not INI.VerifyBool(edt_Section.Text, 'Boolean', True) then + ShowMessage('Boolean failed to verify'); + TRUEFALSE := TRUEFALSE and INI.VerifyFloat(edt_Section.Text, 'Float', 3.142); + if not INI.VerifyFloat(edt_Section.Text, 'Float', 3.142) then + ShowMessage('Float failed to verify'); + TRUEFALSE := TRUEFALSE and INI.VerifyDateTime(edt_Section.Text, + 'Date', StrToDate('15/10/2016', 'dd mm yyyy', '/')); + if not INI.VerifyDateTime(edt_Section.Text, 'Date', + StrToDate('15/10/2016', 'dd mm yyyy', '/')) then + ShowMessage('Date failed to verify'); + TRUEFALSE := TRUEFALSE and INI.VerifyInt64(edt_Section.Text, 'Int64', 1000); + if not INI.VerifyInt64(edt_Section.Text, 'Int64', 1000) then + ShowMessage('Int64 failed to verify'); + TRUEFALSE := TRUEFALSE and INI.VerifyString(edt_Section.Text, + edt_Ident.Text, edt_Value.Text); + if not INI.VerifyString(edt_Section.Text, edt_Ident.Text, edt_Value.Text) then + ShowMessage('String failed to verify'); + if TRUEFALSE = True then + ShowMessage('Verify: String,Bool,Float,Date and Int64 types all verified OK') + else + ShowMessage('One or more types failed verification'); + // Test the Read/Write/Verify Integer stuff + if INI.VerifyInteger(edt_Section.Text, 'Integer', StrToInt(edt_Integer.Text)) then + ShowMessage('VerifyInteger: ' + edt_Integer.Text + ' verified OK') + else + ShowMessage('VerifyInteger: ' + edt_Integer.Text + ' failed verification'); + end + else + ShowMessage('Verification of regular values only works when PlainTextMode=FALSE'); + // Use the MD5 value from the INI file + if INI.VerifyIdent('92abf0deecbb25c435bff507a396d92a') then + ShowMessage('Ident ' + IDENT_SECTION + ' verified OK') + else + ShowMessage('Ident ' + IDENT_SECTION + ' failed verification'); +end; + +procedure Tmainform.cmd_VerifySectionValuesClick(Sender: TObject); +var + s: string; +begin + if edt_Section.Text = IDENT_SECTION then + begin + if INI.VerifyIdent('92abf0deecbb25c435bff507a396d92a') then + ShowMessage('Ident ' + IDENT_SECTION + ' verified OK') + else + ShowMessage('Ident ' + IDENT_SECTION + ' failed verification'); + Exit; + end; + if not INI.SectionExists(edt_Section.Text) then + begin + ShowMessage(edt_Section.Text + ' is absent, so nothing to verify!'); + Exit; + end; + + s := InputBox('Verify Section', 'Please enter your 32-character MD5Hash here', + sStoredMD5Hash); + if INI.VerifySectionHash(edt_Section.Text, s) then + begin + ShowMessage('Section is verified'); + sStoredMD5Hash := s; + end + else + ShowMessage('MD5Hash value incorrect. Section failed verification'); +end; + +end. diff --git a/components/cryptini/latest_stable/demo/umemoform.lfm b/components/cryptini/latest_stable/demo/umemoform.lfm new file mode 100644 index 000000000..9917bdc55 --- /dev/null +++ b/components/cryptini/latest_stable/demo/umemoform.lfm @@ -0,0 +1,62 @@ +object ShowINIForm: TShowINIForm + Left = 1253 + Height = 540 + Top = 313 + Width = 768 + BorderStyle = bsToolWindow + Caption = 'INI' + ClientHeight = 540 + ClientWidth = 768 + OnCreate = FormCreate + OnShow = FormShow + Position = poMainFormCenter + LCLVersion = '1.7' + object Memo_INI: TMemo + Left = 0 + Height = 482 + Top = 0 + Width = 768 + Align = alTop + Lines.Strings = ( + 'Memo_INI' + ) + OnChange = Memo_INIChange + ScrollBars = ssAutoBoth + TabOrder = 0 + WordWrap = False + end + object cmd_Close: TBitBtn + Left = 347 + Height = 26 + Top = 500 + Width = 75 + AutoSize = True + Caption = '&Close' + Kind = bkClose + ModalResult = 11 + OnClick = cmd_CloseClick + TabOrder = 1 + end + object cmd_saveChanges: TButton + Left = 600 + Height = 25 + Top = 499 + Width = 154 + AutoSize = True + Caption = 'Save Changes and Close' + Enabled = False + OnClick = cmd_saveChangesClick + TabOrder = 2 + end + object cmd_Abort: TBitBtn + Left = 264 + Height = 26 + Top = 500 + Width = 76 + Caption = '&Revert' + Kind = bkAbort + ModalResult = 3 + TabOrder = 3 + Visible = False + end +end diff --git a/components/cryptini/latest_stable/demo/umemoform.pas b/components/cryptini/latest_stable/demo/umemoform.pas new file mode 100644 index 000000000..4f7a2a5a2 --- /dev/null +++ b/components/cryptini/latest_stable/demo/umemoform.pas @@ -0,0 +1,94 @@ +unit umemoform; + +{$mode objfpc}{$H+} + +interface + +uses + Forms, StdCtrls, SysUtils, + Buttons, Classes, Dialogs,Controls; + +type + + { TShowINIForm } + + TShowINIForm = class(TForm) + cmd_Abort: TBitBtn; + cmd_saveChanges: TButton; + cmd_Close: TBitBtn; + Memo_INI: TMemo; + procedure cmd_CloseClick(Sender: TObject); + procedure cmd_saveChangesClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure Memo_INIChange(Sender: TObject); + private + public + bDirty: boolean; + sINIFilePath: string; + // Help = MakeReadonly, OpenINI = MakeWriteable + procedure MakeReadOnly; + procedure MakeWriteable; + end; + +var + ShowINIForm: TShowINIForm; + +implementation +// Uses umainform; +{$R *.lfm} + +{ TShowINIForm } +procedure TShowINIForm.MakeReadOnly; +begin + Memo_INI.Readonly:=TRUE; +end; + +procedure TShowINIForm.MakeWriteable; +begin + Memo_INI.Readonly:=FALSE; +end; + +procedure TShowINIForm.cmd_saveChangesClick(Sender: TObject); +begin + if bDirty then + try + {$I+} + Memo_INI.Lines.SaveToFile(sINIFilePath); + ShowMessage('Changes saved OK.'); + Close; + except + On E: Exception do + ShowMessageFmt('Oops! Error: %s', [E.Message]); + end; +end; + +procedure TShowINIForm.cmd_CloseClick(Sender: TObject); +begin + if bDirty then + If MessageDlg('Discard changes?',mtConfirmation,[MBYES,MBNO],0,MBNO) = mrNo then + Begin + cmd_saveChanges.Click; + Exit; + end; + Close; +end; + +procedure TShowINIForm.FormCreate(Sender: TObject); +begin + Icon := Application.Icon; +end; + +procedure TShowINIForm.FormShow(Sender: TObject); +begin + bDirty := False; + cmd_saveChanges.Enabled := False; +end; + +procedure TShowINIForm.Memo_INIChange(Sender: TObject); +begin + bDirty := True; + cmd_saveChanges.Enabled := True; +end; + +end. diff --git a/components/cryptini/latest_stable/locale/ucryptini.po b/components/cryptini/latest_stable/locale/ucryptini.po new file mode 100644 index 000000000..e535f25d7 --- /dev/null +++ b/components/cryptini/latest_stable/locale/ucryptini.po @@ -0,0 +1,15 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +#: ucryptini.rsnothingwasen +msgid "Nothing was Entered!" +msgstr "" + +#: ucryptini.rsnotyetinitia +msgid "Not yet initialised" +msgstr "" + +#: ucryptini.rsunknown +msgid "unknown" +msgstr "" + diff --git a/components/cryptini/latest_stable/ucryptini.pas b/components/cryptini/latest_stable/ucryptini.pas new file mode 100644 index 000000000..d9f35c672 --- /dev/null +++ b/components/cryptini/latest_stable/ucryptini.pas @@ -0,0 +1,1477 @@ +unit ucryptini; +{$mode objfpc}{$H+} +{$DEFINE USE_DCPCRYPT} // Delete this if you don't have the DCrypt library + // and CryptINI will use built-in BASE64 instead + // (but turn all project debugging checks off!) + // DCrypt can be downloaded via OnlinePackageManager + // And is vastly preferable to BASE64 +{$IF FPC_VERSION = 3} // inifiles.pp changed in fpc v3.1.? (17 Jan 2016) + {$IF FPC_RELEASE > 0} + {$IF FPC_PATCH > 0} + {$DEFINE FPC311} + {$ENDIF} + {$ENDIF} +{$ENDIF} + +{ 'Paranoid' version of TIniFile + + Copyright (C) 2016 Gordon Bamber minesadorada@gmail.com + Base 64 code by David Barton + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version with the following modification: + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent modules,and + to copy and distribute the resulting executable under terms of your choice, + provided that you also meet, for each linked independent module, the terms + and conditions of the license of that module. An independent module is a + module which is not derived from or based on this library. If you modify + this library, you may extend this exception to your version of the library, + but you are not obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License + for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +PURPOSE +======= +This is a TiniFile implementation that is resistant to tampering. +In normal (PlainTextMode = FALSE) mode, any calls to Write values are +accompanied by an embedded MD5 hash value (and also reversed then Base64/IDEA Encrypted) +This is invisible in normal use (i.e. read methods return normal results) +but there are added methods to internally verify any entries. +It also is able to write a standard ident section containing various +details including authorship and copyright. A single function allows +you to check on app startup whether this section has been altered. +It also includes a useful 'First Run' functionality. +It's intended purpose is to store information that cannot be easily altered +in a text editor (such as HiScores etc) by a weekend scripter. +The WriteInteger method is the most secure as it double-encrypts as well as +embedding an MD5Hash value as a checksum. Very handy to save scores etc. +It is paired with ReadInteger and VerifyInteger + +DISCLAIMER +========== +This unit does not claim to pass any security tests nor be used in +any environment where a moderate-level hacker could circumvent it. + +ENCRYPTION +========== +By Default CryptINI uses the DCPCrypt package for string encryption. +The mode is IDEA cipher with an MD5 hash for the key. The EncryptINI +and DecryptINI methods use DCPCrypt RC4 Cipher (With SHA hash) +There is a $DEFINE USE_DCPCRYPT directive at the top of this file. + +If this DEFINE is commented out, then CryptINI will default +to BASE64 string encryption, which is weaker. Encrypt/DecryptINI methods +will be unavailable. +You can then delete any requirement for dcpcrypt in the project inspector. + +FREEPASCAL VERSIONS +=================== +Starting in FPC V3.1.1 there are additional options in TINIFile which +are implemented in TCryptINI if the FPC Version >= 3.1.1 is detected. + +USE AND EXAMPLE CODE +==================== +** You can hard-code an Ident Section in your INI file +** and check if it has been altered +** Typical Form.Create() +procedure TForm1.FormCreate(Sender: TObject); +const + C_KEYPHRASE = 'I do like to be beside the seaside'; // Move this to the top of the unit +Begin + ...other code + // Initialise the encrypted config file + INI := TCryptIniFile.Create(ChangeFileExt(Application.EXEName, '.cfg')); + + // First ever run. INI is absent + If INI.IsVirgin then INI.WriteIdent('minesadorada','(c)2016','minesadorada@charcodelvalle.com','Creative Commons',TRUE);l + + if NOT INI.VerifyIdent('5b319674f5cb55f3ed1e404e33c25868') then // I got this from the INI file + ShowMessage('This is not a genuine copy of ' + Application.Title + '!') + else INI.Deflower; // If not Deflowered then the default ini is used. + + // After first run, use the encrypted version + If NOT INI.IsVirgin then + begin + INI.DecryptINI(TRUE,C_KEYPHRASE); + // Check the unencrypted version.. + if NOT INI.VerifyIdent('5b319674f5cb55f3ed1e404e33c25868') then // I got this from the INI file + ShowMessage('This is not a genuine copy of ' + Application.Title + '!'); + end; + INI.KeyPhrase:=C_KEYPHRASE; // for subsequent read/writes + ...other code +end; + +procedure Tmainform.FormDestroy(Sender: TObject); +const + C_KEYPHRASE = 'I do like to be beside the seaside'; // Move this to the top of the unit +Begin + ...other code + INI.EncryptINI(TRUE,C_KEYPHRASE); + ...other code +end; + + +** Has the Ident been tampered with? Put this in Form.Create +// Use the MD5 value from the INI file (use your own!) +If INI.VerifyIdent('92abf0deecbb25c435bff507a396d92a') then + ShowMessage('Ident verified OK') // do nothing +else + ShowMessage('Ident failed verification'); // Warning message/exit + +** Test for first run +If INI.IsVirgin then // note that doing the test Deflowers the app by default + ShowMessage('First time run of this app'); + +** Toggle to normal UnEncrypted INI use +(by default it is set to FALSE) +INI.PlainTextMode:=TRUE; +INI.WriteString('MySection', 'String', 'MyString'); // just writes normally + +** When PlainTextMode = FALSE (default),Write<anytype> encrypts the value + and prefixes the encrypted value with an MD5Hash +INI.WriteInteger('MySection', 'Integer',1000); +** Note WriteInteger adds a '+' (INTEGER_MARKER) to the written Key + This is so that CryptINI can deal with Integers specially + Using CryptINI in either mode, this is invisible in use + (i.e. don't add a + to the ident for any methods) + +** When PlainTextMode = FALSE (default), use these convenient methods if you like: +INI.ReadUnencryptedString +INI.WriteUnencryptedString +INI.ReadUnEncryptedInteger +INI.WriteUnencryptedInteger + +** Store 'First Run' status using these methods: +INI.IsVirgin +INI.Deflower +INI.ReFlower (useful for testing) + +** You can encrypt and decrypt the entire INI file usine EncryptINI and DecryptINI + This uses a different cipher and hash method, so is extra-secure + cryptINI methods and properties an only work with an unencrypted INI file + So; Decrypt on startup, and Encrypt before exit. + By default the routines use the KeyPhrase property, but you can override this + in the method call along with whether to delete the "old" file and what + file extension to use for the encrypted file. + +** Original IniFiles methods and properties + Just use them as normal. Note: you can mix-and-match Plaintext and Encrypted + in the same INI file. Just toggle the property PlainTextMode before Writing/Reading +} + +interface + +uses + Forms, SysUtils, LazUTF8, LazFileUtils,StrUtils, INIFiles, md5, LCLVersion, + Classes,fileinfo,SyncObjs + // DEBUGGING for ShowMessage:,Dialogs + // ,Dialogs + {$IFDEF USE_DCPCRYPT},DCPidea, DCPmd5,DCPrc4, DCPsha1{$ENDIF} + ; + + +const + // Fixed Ident section values for Read/Write/Verify Ident methods + // Change the values here if you like. + IDENT_SECTION = 'ProgramInfo'; + IDENT_APPNAME = 'App name'; + IDENT_APPVERSION = 'App version'; + IDENT_EXE = 'App Path'; + IDENT_AUTHOR = 'Author'; + IDENT_COPYRIGHT = 'Copyright'; + IDENT_LICENSE = 'License'; + IDENT_CONTACT = 'Contact'; + IDENT_LCLVERSION = 'LCL Version'; + IDENT_FPCVERSION = 'FPC Version'; + IDENT_TARGET = 'Target System'; + IDENT_LASTCOMPILED = 'Last Compiled'; + IDENT_FIRSTRUN = 'FirstRun'; + IDENT_MD5HASH = 'MD5Hash'; + + // You can change these Consts here if you like + INTEGER_MARKER = '+'; // Appended to Crypted Integer Idents + // so that ReadSectionValues,ValueExists and DeleteKey methods will work + DEFAULT_KEYPHRASE = 'Choose a better keyphrase than this!'; // If none specified + {$IFDEF WINDOWS} + DEFAULT_EXT = '.enc'; + {$ELSE} + DEFAULT_EXT = 'enc'; + {$ENDIF} + + {$IFNDEF USE_DCPCRYPT} + // Base64 array of bytes. CHANGE AT YOUR PERIL! + B64: array[0..63] of byte = (65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 43, 47); + {$ENDIF} + +C_VERSION = '0.1.2'; +{ + VERSION HISTORY + =============== + V 0.0.1: Initial alpha release by (c)2016 minesadorada@charcodelvalle.com (GB) + V 0.0.2: Improved Read/Write/Verify integer values (GB) + V 0.0.3: Section functions added. Integer marker added. (GB) + V 0.0.4: Compatibility test for fpc 3 additions to TIniFiles (GB) + V 0.0.5: Added DCPCrypt units and conditional DEFINES. Added Encrypt/Decrypt INI (GB) + V 0.0.6: ReadBinaryStream and WriteBinaryStream added (GB) + V 0.0.7: ReadSection debugged (GB) + V 0.0.8: Bugfix: FPC Version {DEFINE FPC3} corrected (GB) + V 0.0.9: Added SplitKeyValue procedure. Other fixes and improvements (GB) + V 0.1.0: Added Program Version info to Ident section + V 0.1.2: Added thread-safe TLockCryptINIFile class + for thread-safe operation (GB) + Credit: "Fungus" at http://forum.lazarus.freepascal.org/ + V 0.1.3: ?? +} +type + TCryptIniFile = class(TIniFile) + private + // Md5 Stuff + fMyDigest: TMDDigest; // defined in md5 unit + fMD5String: string; + // For Read/write Integers + fKey: longint; + fKeyPhrase: string; + // Encryption on/off + fPlainText: boolean; + fSectionHashing: boolean; + fVersion: string; + {$IFDEF USE_DCPCRYPT} + DCP_idea1: TDCP_idea; + DCP_md5_1: TDCP_md5; + {$ENDIF} + fHashType:String; + fCipherType:String; + // Functions to convert values + function EncodeString(const sValue: string): string; + function DecodeString(const sValue: string): string; + // Functions to convert Integers only + function EncodeInteger(const iValue: longint): longint; + function DecodeInteger(const iValue: longint): longint; + // Either.. + procedure SetKeyPhrase(AValue: string); // Sets fKey from a string (Preferrred method) + Procedure SetKey(aValue:Integer); // Also sets Keyphrase (weaker) + public + {$IFDEF FPC311} + constructor Create(const AFileName: string; AOptions: TIniFileOptions = []); + override; + {$ELSE} + constructor Create(const AFileName: string; AEscapeLineFeeds : Boolean = False);override; + {$ENDIF} + destructor Destroy; override; + // Overridden TINIFile methods + function ReadInteger(const Section, Ident: string; Default: longint): longint; + override; + procedure WriteInteger(const Section, Ident: string; Value: longint); override; + function ReadString(const Section, Ident, Default: string): string; override; + procedure WriteString(const Section, Ident, Value: string); override; + procedure ReadSection(const Section: string; Strings: TStrings); override; + function ValueExists(const Section, Ident: string): Boolean; override; + procedure DeleteKey(const Section, Ident: String); override; +{$IFDEF FPC311} + procedure ReadSectionValues(const Section: string; Strings: TStrings; + AOptions: TSectionValuesOptions = []); override; +{$ELSE} + procedure ReadSectionValues(const Section: string; Strings: TStrings); override; +{$ENDIF} + function ReadBinaryStream(const Section, Name: string; Value: TStream): Integer; override; + procedure WriteBinaryStream(const Section, Name: string; Value: TStream); override; + + // Added functions + // Compares TestValue's value and MD5Hash with the INI file's version + function VerifyString(const Section, Ident, TestValue: string): boolean; + function VerifyBool(const Section, Ident: string; TestValue: boolean): boolean; + function VerifyInt64(const Section, Ident: string; TestValue: int64): boolean; + function VerifyFloat(const Section, Ident: string; TestValue: double): boolean; + function VerifyDate(const Section, Ident: string; TestValue: TDateTime): boolean; + function VerifyTime(const Section, Ident: string; TestValue: TDateTime): boolean; + function VerifyDateTime(const Section, Ident: string; TestValue: TDateTime): boolean; + // VerifyInteger is more strict + function VerifyInteger(const Section, Ident: string; TestValue: longint): boolean; + + // New functionality. Write a whole section in one go. + procedure WriteSectionValues(const Section: string; Strings: TStrings); + // If SectionHashing = TRUE then MakeSectionHash is called for every write + // Best practioe is to do it only after a bunch of writes + procedure MakeSectionHash(const Section: string; WriteToINI: boolean = True); + function VerifySectionHash(const Section, TestMD5Hash: string): boolean; + // Separates key=value into Skey and sValue + function SplitKeyValue(Const sValueEntry:String;var sKey,sValue:String):Boolean; + // Sets property PlainTextMode to FALSE temporarily to Read/Write normally + // I included these functions for simplicity. They work when PlainTextMode=TRUE or FALSE + function ReadUnencryptedString(const Section, Ident, Default: string): string; + procedure WriteUnencryptedString(const Section, Ident, Value: string); + function ReadUnEncryptedInteger(const Section, Ident: string; + Default: longint): longint; + procedure WriteUnencryptedInteger(const Section, Ident: string; Value: longint); + + // Writes a standard Ident section with MD5 Hash + // This can be done in Form.Create() on program first run + // Or can be done during development, then distribute the prewritten INI file with the exe + procedure WriteIdent(const sAuthor, sCopyright, sLicense, sContact: string; Force: boolean=False); + // Read the MD5Hash from the INI file and pass it as a parameter + // ANY tampering with the [ProgramInfo] ident section info returns a FALSE + // Note not all Key/Values are verified (i.e. Appname etc.) + function VerifyIdent(const sMD5Hash: string): boolean; + + {$IFDEF USE_DCPCRYPT} + // Encrypt and Decrypt the whole file in one go. Very secure via RC4 cipher. + // You can call: + // EncryptINI; (use DEFAULT_KEYPHRASE as the passkey, and delete the old file) + // EncryptINI(FALSE); (don't delete old ini file) + // EncryptINI(TRUE,'bananas'); (delete old file; use "bananas" as the passkey) + // EncryptINI(TRUE,'bananas','.xxx'); (delete old file; use bananas as the passkey, and save as an .xxx file) + // bSuccess:=EncryptINI(optional parameters); (returns FALSE if anything goes wrong) + function EncryptINI(DeleteOld:Boolean = TRUE;sPassword: string = DEFAULT_KEYPHRASE;NewExt:String = DEFAULT_EXT):Boolean; + function DecryptINI(DeleteOld:Boolean = TRUE;sPassword: string = DEFAULT_KEYPHRASE;NewExt:String = DEFAULT_EXT):Boolean; + {$ENDIF} + + // Use to detect or set 'First Run' status + function IsVirgin: boolean; + procedure Deflower; + procedure Reflower; + + // By Default, PlainTextMode = FALSE (Encrypted mode) + property PlainTextMode: boolean read fPlainText write fPlainText; + property MD5Hash: string read fMD5String write fMD5String; + + // Either.. + property KeyPhrase: string read fKeyPhrase write SetKeyPhrase; // also sets Key (preferred property) + // or.. + property Key: longint read fKey write SetKey; // Also sets KeyPhrase (weaker) + + // If SectionHashing=TRUE then a Section hash is written each time any value + // is written. This enables VerifySection. + property SectionHashing: boolean read fSectionHashing write fSectionHashing; + + property HashType:String read fHashType; // Info + property CipherType:String read fCipherType; // Info + property CryptINIVersion: string read fVersion; // Info + property FileName; //inherited +{$IFNDEF FPC311} + // Reflect changes in fpc 3x + property EscapeLineFeeds; + Property CaseSensitive; + Property StripQuotes; +{$ENDIF} +end; + +Type + TLockCryptINIFile = class(TCryptIniFile) + private + FLock: TCriticalSection; + public + destructor Destroy; override; + // Call Lock after creation + procedure Lock; + // Call Unlock before destruction + procedure Unlock; + end; + +resourcestring + rsNotYetInitia = 'Not yet initialised'; + rsNothingWasEn = 'Nothing was Entered!'; + rsUnknown = 'unknown'; + +implementation + +{TLockCryptINIFile} +destructor TLockCryptINIFile.Destroy; +begin + FreeAndNil(FLock); + inherited; +end; + +procedure TLockCryptINIFile.Lock; +begin + if FLock = nil then FLock:= TCriticalSection.Create; + FLock.Acquire; +end; + +procedure TLockCryptINIFile.Unlock; +begin + if FLock <> nil then FLock.Release; +end; + +{TCryptINIFile} +{$IFDEF FPC311} + constructor TCryptIniFile.Create(const AFileName: string; + AOptions: TIniFileOptions = []); + { + TIniFileOption = (ifoStripComments, // Strip comments when reading file + ifoStripInvalid, // Strip invalid lines when reading file. + ifoEscapeLineFeeds, // Escape linefeeds when reading file. + ifoCaseSensitive, // Use Case sensitive section/key names + ifoStripQuotes, // Strip quotes when reading string values. + ifoFormatSettingsActive, // Use format settings when writing date/float etc. + ifoWriteStringBoolean // Write booleans as string + ); + } +begin + // AOptions := AOptions And NOT [ifoWriteStringBoolean]; + inherited Create(AFileName, AOptions); +{$ELSE} +constructor TCryptIniFile.Create(const AFileName: string; AEscapeLineFeeds : Boolean = False); +begin + inherited Create(AFileName,AEscapeLineFeeds); +{$ENDIF} + CacheUpdates := False; + fPlainText := False; + fSectionHashing := True; + fVersion := C_VERSION; + fMD5String := rsNotYetInitia; + fKey := 300554; // Random default key in case user doesn't set one + fKeyPhrase := DEFAULT_KEYPHRASE; +{$IFDEF USE_DCPCRYPT} + DCP_idea1:=TDCP_idea.Create(Nil); + DCP_md5_1:=TDCP_md5.Create(Nil); + If DCP_idea1.SelfTest then + DCP_Idea1.Burn; { Clear all information } + DCP_Idea1.InitStr(fKeyPhrase,TDCP_md5); + fCipherType:=DCP_Idea1.GetAlgorithm; + fHashType:=DCP_md5_1.GetAlgorithm; +{$ELSE} + fHashType:='MD5'; + fCiperType:='BASE64'; +{$ENDIF} +end; + +// ***************************************************************************// + +destructor TCryptIniFile.Destroy; +begin + // Anything to free here? + {$IFDEF USE_DCPCRYPT} + DCP_idea1.Burn; // Clear key info from memory + DCP_idea1.Free; + DCP_md5_1.Burn; // Clear key info from memory + DCP_md5_1.Free; + {$ENDIF} + inherited Destroy; +end; + +// ***************************************************************************// +// Start of internal routines +// ***************************************************************************// +{$IFNDEF USE_DCPCRYPT} // Fallback routines +function B64Encode(pInput: pointer; pOutput: pointer; Size: longint): longint; +var + i, iptr, optr: longint; + Input, Output: PByteArray; +begin + Input := PByteArray(pInput); + Output := PByteArray(pOutput); + iptr := 0; + optr := 0; + for i := 1 to (Size div 3) do + begin + Output^[optr + 0] := B64[Input^[iptr] shr 2]; + Output^[optr + 1] := B64[((Input^[iptr] and 3) shl 4) + (Input^[iptr + 1] shr 4)]; + Output^[optr + 2] := B64[((Input^[iptr + 1] and 15) shl 2) + (Input^[iptr + 2] shr 6)]; + Output^[optr + 3] := B64[Input^[iptr + 2] and 63]; + Inc(optr, 4); + Inc(iptr, 3); + end; + case (Size mod 3) of + 1: + begin + Output^[optr + 0] := B64[Input^[iptr] shr 2]; + Output^[optr + 1] := B64[(Input^[iptr] and 3) shl 4]; + Output^[optr + 2] := byte('='); + Output^[optr + 3] := byte('='); + end; + 2: + begin + Output^[optr + 0] := B64[Input^[iptr] shr 2]; + Output^[optr + 1] := B64[((Input^[iptr] and 3) shl 4) + (Input^[iptr + 1] shr 4)]; + Output^[optr + 2] := B64[(Input^[iptr + 1] and 15) shl 2]; + Output^[optr + 3] := byte('='); + end; + end; + Result := ((Size + 2) div 3) * 4; +end; + +// ***************************************************************************// + +function Base64Encode(const Value: ansistring): ansistring; +begin + SetLength(Result, ((Length(Value) + 2) div 3) * 4); + B64Encode(@Value[1], @Result[1], Length(Value)); +end; + +// ***************************************************************************// + +function B64Decode(pInput: pointer; pOutput: pointer; Size: longint): longint; +var + i, j, iptr, optr: longint; + Temp: array[0..3] of byte; + Input, Output: PByteArray; +begin + Input := PByteArray(pInput); + Output := PByteArray(pOutput); + iptr := 0; + optr := 0; + Result := 0; + for i := 1 to (Size div 4) do + begin + for j := 0 to 3 do + begin + case Input^[iptr] of + 65..90: Temp[j] := Input^[iptr] - Ord('A'); + 97..122: Temp[j] := Input^[iptr] - Ord('a') + 26; + 48..57: Temp[j] := Input^[iptr] - Ord('0') + 52; + 43: Temp[j] := 62; + 47: Temp[j] := 63; + 61: Temp[j] := $FF; + end; + Inc(iptr); + end; + Output^[optr] := (Temp[0] shl 2) or (Temp[1] shr 4); + Result := optr + 1; + if (Temp[2] <> $FF) and (Temp[3] = $FF) then + begin + Output^[optr + 1] := (Temp[1] shl 4) or (Temp[2] shr 2); + Result := optr + 2; + Inc(optr); + end + else if (Temp[2] <> $FF) then + begin + try + Output^[optr + 1] := (Temp[1] shl 4) or (Temp[2] shr 2); + Output^[optr + 2] := (Temp[2] shl 6) or Temp[3]; // Throws error + Result := optr + 3; + Inc(optr, 2); + except + On E: Exception do + Continue; + end; + end; + Inc(optr); + end; +end; + +// ***************************************************************************// + +function Base64Decode(const Value: ansistring): string; +begin + SetLength(Result, (Length(Value) div 4) * 3); + SetLength(Result, B64Decode(@Value[1], @Result[1], Length(Value))); +end; +{$ENDIF} +// ***************************************************************************// + +function CharToBool(AChar: char): boolean; +begin + Result := (Achar = '1'); +end; + +// ***************************************************************************// + +function BoolToChar(ABool: boolean): char; +begin + if ABool then + Result := '1' + else + Result := '0'; +end; + +// ***************************************************************************// +// End of internal routines +// ***************************************************************************// + +Procedure TCryptIniFile.SetKey(aValue:Integer); // Also sets KeyPhrase +begin + fKey:=AValue; + {$IFNDEF USE_DCPCRYPT} + SetKeyPhrase(fKey); // VERY WEAK! + {$ENDIF} +end; + +// ***************************************************************************// + +procedure TCryptIniFile.SetKeyPhrase(AValue: string); +// Hash the phrase to a standard 32 chars +// Then sum the ASCII values to seed the fKey (it never exceeds LongInt) +// Difficult to reverse-engineer even if you have the KeyPhrase +var + aDigest: TMDDigest; // defined in md5 unit + iCount: integer; + lTry: longint; +begin + {$IFDEF USE_DCPCRYPT} + // Use the string directly + fKeyPhrase:=AValue; + if fKeyPhrase = '' then + fKeyPhrase := DEFAULT_KEYPHRASE; // don't allow empty string + DCP_Idea1.Burn; { Clear all stored key information } + DCP_Idea1.InitStr(fKeyPhrase,TDCP_md5); + Exit; // bail out + {$ENDIF} + lTry := 0; + // If it's already a number, just use it. (unless it's zero!) + if ((TryStrToInt(AValue, lTry)) and (lTry <> 0)) then + fKey := lTry + else // It's a string + begin + if AValue = '' then + AValue := rsNothingWasEn; // don't allow empty string + aDigest := MDString(AValue, MD_VERSION_5); + fKeyPhrase := MDPrint(aDigest); // 32 chars + // Mess it up to make a big enough number (96 chars) + fKeyPhrase := fKeyPhrase + ReverseString(fKeyPhrase) + fKeyPhrase; + fKey := 0; + for iCount := 1 to (Length(fKeyPhrase)) do + begin + fKey := fKey + Ord(fKeyPhrase[iCount]); + end; + // Make the number bigger + fKey := fKey * 7; + end; +end; + + +// ***************************************************************************// + +function TCryptIniFile.EncodeString(const sValue: string): string; + // Muddle the String up and encode it in IDEA or Base64 +var + s: string; +begin + s := ReverseString(sValue); + {$IFDEF USE_DCPCRYPT} + DCP_Idea1.Reset;{ Reset any stored chaining information } + Result:=DCP_Idea1.EncryptString(s); + {$ELSE} + Result := Base64Encode(s); + {$ENDIF} +end; + +// ***************************************************************************// + +function TCryptIniFile.DecodeString(const sValue: string): string; + // Decode the IDEA or Base64 then Unmuddle +var + s: string; +begin + {$IFDEF USE_DCPCRYPT} + DCP_Idea1.Reset;{ Reset any stored chaining information } + s:=DCP_Idea1.DecryptString(sValue); + {$ELSE} + s := Base64Decode(sValue); + {$ENDIF} + Result := ReverseString(s); +end; + +// ***************************************************************************// + +function TCryptIniFile.EncodeInteger(const iValue: longint): longint; +begin + //DEBUG: ShowMessageFmt('EncodeInteger value = %d',[iValue]); + // B64Encode(@iValue,@Result,SizeOf(iValue)); deprecated + Result := iValue xor fKey; + // Already IDEA or BASE64 encoded after writing + //DEBUG: ShowMessageFmt('EncodeInteger Result = %d',[Result]); +end; + +// ***************************************************************************// + +function TCryptIniFile.DecodeInteger(const iValue: longint): longint; +begin + // B64Decode(@iValue,@Result,SizeOf(iValue)); deprecated + // Already IDEA or BASE64 decoded before reading + Result := iValue xor fKey; +end; + +// ***************************************************************************// + +procedure TCryptIniFile.Deflower; +// Called by IsVirgin to set FirstRun status to FALSE +var + tempPlainText: boolean; +begin + tempPlainText := fPlainText; + fPlainText := True; + WriteBool(IDENT_SECTION, IDENT_FIRSTRUN, False); + fPlainText := tempPlainText; +end; + +// ***************************************************************************// + +procedure TCryptIniFile.Reflower; +// Set FirstRun status to TRUE +var + tempPlainText: boolean; +begin + tempPlainText := fPlainText; + fPlainText := True; + WriteBool(IDENT_SECTION, IDENT_FIRSTRUN, True); + fPlainText := tempPlainText; +end; + +// ***************************************************************************// + +function TCryptIniFile.IsVirgin: boolean; + // On FirstRun returns TRUE + // Then calls Deflower so subsequent runs will return FALSE +var + tempPlainText: boolean; +begin + tempPlainText := fPlainText; + fPlainText := True; + Result := ReadBool(IDENT_SECTION, IDENT_FIRSTRUN, True); + if Result = True then + Deflower; + fPlainText := tempPlainText; +end; + +// ***************************************************************************// + +function TCryptIniFile.VerifyIdent(const sMD5Hash: string): boolean; + // The sMD5Hash has been previously generated by WriteIdent + // and stored in INI file. Get it from there. +var + s: string; + tempPlainText: boolean; +begin + Result := False; + tempPlainText := fPlainText; // Store old value + fPlainText := True; // Set PlainTextMode ON + // Make a string of all the authorship entries + s := ReadString(IDENT_SECTION, IDENT_AUTHOR, rsUnknown); + s := s + ReadString(IDENT_SECTION, IDENT_COPYRIGHT, rsUnknown); + s := s + ReadString(IDENT_SECTION, IDENT_LICENSE, rsUnknown); + s := s + ReadString(IDENT_SECTION, IDENT_CONTACT, rsUnknown); + // Make up an MD5 hash from the INI values read + fMyDigest := MDString(s, MD_VERSION_5); + fMD5String := MDPrint(fMyDigest); + // Compare it with the value passed in the parameter + if fMD5String = sMD5Hash then + Result := True; + fPlainText := tempPlainText; // Restore old value +end; + +// ***************************************************************************// + +procedure TCryptIniFile.WriteIdent(const sAuthor, sCopyright, sLicense, sContact: string; Force: boolean=False); +// This proc will only write anything if IsVirgin (First Run status) is TRUE +// Or the INI file is empty or altered +var + s: string; + tempPlainText: boolean; + VInfo:TFileVersionInfo; + Version:TProgramVersion; +begin + tempPlainText := fPlainText; // Store old value + fPlainText := True; // Set PlainTextMode ON + if ((ReadBool(IDENT_SECTION, IDENT_FIRSTRUN, True) = True) OR (Force = True)) then + begin // IsVirgin=TRUE so write the section in plaintext + WriteString(IDENT_SECTION, IDENT_AUTHOR, sAuthor); + WriteString(IDENT_SECTION, IDENT_COPYRIGHT, sCopyright); + WriteString(IDENT_SECTION, IDENT_LICENSE, sLicense); + WriteString(IDENT_SECTION, IDENT_CONTACT, sContact); + WriteString(IDENT_SECTION, IDENT_LCLVERSION, lcl_version); + WriteString(IDENT_SECTION, IDENT_FPCVERSION, {$I %FPCVERSION%}); + s:={$I %FPCTARGETCPU%}+' - '+{$I %FPCTARGETOS%}; + WriteString(IDENT_SECTION, IDENT_TARGET, s); + // If you don't need this you can delete 'Forms' from the Uses clause + WriteString(IDENT_SECTION, IDENT_APPNAME,Application.Title); + s:='0.0.0.0'; // Default + VInfo:=TFileVersionInfo.Create(Application); + TRY + VInfo.ReadFileInfo; + If fileinfo.GetProgramVersion(Version) then + s:=ProgramversionToStr(Version); + finally + VInfo.free; + end; + WriteString(IDENT_SECTION,IDENT_APPVERSION,s); + WriteString(IDENT_SECTION, IDENT_EXE, ParamStrUTF8(0)); + WriteBool(IDENT_SECTION,IDENT_FIRSTRUN,TRUE); + s:={$I %DATE%} + ' at ' + {$I %TIME%}; + WriteString(IDENT_SECTION, IDENT_LASTCOMPILED, s); + // Make up the MD5Hash of all the authorship entries + s := sAuthor + sCopyright + sLicense + sContact; + fMyDigest := MDString(s, MD_VERSION_5); + fMD5String := MDPrint(fMyDigest); + WriteString(IDENT_SECTION, IDENT_MD5HASH, fMD5String); + UpdateFile; + end; + fPlainText := tempPlainText; // Restore old value +end; + +// ***************************************************************************// + +procedure TCryptIniFile.WriteUnencryptedString(const Section, Ident, Value: string); +var + tempPlainText: boolean; + // Temporarily sets PlainTextMode = TRUE then restores previous status +begin + tempPlainText := fPlainText; // Store old value + fPlainText := True; // Set PlainTextMode ON + WriteString(Section, Ident, Value); + fPlainText := tempPlainText; // Restore old value +end; + +// ***************************************************************************// + +function TCryptIniFile.ReadUnencryptedString( + const Section, Ident, Default: string): string; + // Temporarily sets PlainTextMode = TRUE then restores previous status +var + tempPlainText: boolean; +begin + tempPlainText := fPlainText; // Store old value + fPlainText := True; // Set PlainTextMode ON + Result := ReadString(Section, Ident, Default); + fPlainText := tempPlainText; // Restore old value +end; + +// ***************************************************************************// + +function TCryptIniFile.ReadUnEncryptedInteger(const Section, Ident: string; + Default: longint): longint; + // Temporarily sets PlainTextMode = TRUE then restores previous status +var + tempPlainText: boolean; +begin + tempPlainText := fPlainText; // Store old value + fPlainText := True; // Set PlainTextMode ON + Result := ReadInteger(Section, Ident, Default); + fPlainText := tempPlainText; // Restore old value +end; + +// ***************************************************************************// + +procedure TCryptIniFile.WriteUnencryptedInteger(const Section, Ident: string; + Value: longint); +// Temporarily sets PlainTextMode = TRUE then restores previous status +var + tempPlainText: boolean; +begin + tempPlainText := fPlainText; // Store old value + fPlainText := True; // Set PlainTextMode ON + WriteInteger(Section, Ident, Value); + fPlainText := tempPlainText; // Restore old value +end; + +(******************************************************************************) +// Subclass of TIniFiles to enable obfuscation of entries +(******************************************************************************) +function TCryptIniFile.ReadInteger(const Section, Ident: string; + Default: longint): longint; + // Unobfuscates the number if PlainTextMode=FALSE +var + s: string; + iTemp: longint; +begin + if fPlainText = True then + begin + // Read result using TiniFile + Result := inherited ReadInteger(Section, Ident, Default); + Exit; + end; + Result := Default; // If all else fails.. + s := ReadString(Section, Ident + INTEGER_MARKER, IntToStr(Default)); + //DEBUG: ShowMessage(s); + if s = IntToStr(Default) then + Exit // nothing there - return Default value + else + begin + if not TryStrToInt(s, iTemp) then + Exit; // Error - return Default value + Result := DecodeInteger(iTemp); // Un-Scramble it + end; +end; + +(******************************************************************************) + +procedure TCryptIniFile.WriteInteger(const Section, Ident: string; Value: longint); +// Obfuscates the number if PlainTextMode=FALSE +begin + if fPlainText = False then + begin + Value := EncodeInteger(Value); // Scramble it + inherited WriteInteger(Section, Ident + INTEGER_MARKER, Value); // Write+ using TiniFile + end + else inherited WriteInteger(Section, Ident, Value); // Write using TiniFile + if SectionHashing = True then + MakeSectionHash(Section, True); + UpdateFile; +end; + +(******************************************************************************) + +function TCryptIniFile.ReadString(const Section, Ident, Default: string): string; + // Behaviour depends on PlainTextMode = FALSE/TRUE +var + s: string; +begin + fMD5String:=''; + // Read value via TIniFile + s := inherited ReadString(Section, Ident, Default); + Result := s; + if fPlainText = True then // Use unencrypted version + Exit; + If (Length(s) < 32) then Exit; + + fMD5String := LeftStr(s, 32); // Grab the MD5 string and store (unencoded) + Result := RightStr(s, Length(s) - 32); // Use the rest + if Result <> EncodeString(Default) then + begin + Result := DecodeString(Result); // Un-Encrypt it + end; +end; + +(******************************************************************************) + +function TCryptIniFile.ValueExists(const Section, Ident: string): Boolean; +// In Encrypted mode Integers have a special marker +Var s:String; +begin + Result:= inherited ValueExists(Section,Ident); //Normal result + if fPlainText = False then + begin + If Ident = '' then // bail out + begin + Result:=FALSE; + exit; + end; + // Test against both Ident and (Ident + INTEGER_MARKER) + s:=Ident; + s := s + INTEGER_MARKER; // Add INTEGER_MARKER + Result:=Result OR inherited ValueExists(Section,s); + end; +end; + +(******************************************************************************) + +procedure TCryptIniFile.DeleteKey(const Section, Ident: String); +// In Encrypted mode Integers have a special marker +Var s:String; +begin + If Ident = '' then exit; // Bail out + inherited DeleteKey(Section,Ident); //Normal behaviour + // Ident might have an INTEGER_MARKER so preceding code didn't delete it + // So delete (Ident + INTEGER_MARKER) if its there + s:=Ident; // Make a copy + // DEBUG: ShowMessage(s); + s := s + INTEGER_MARKER; // Add INTEGER_MARKER + inherited DeleteKey(Section,s); + If SectionHashing then MakeSectionHash(Section,TRUE); + UpdateFile; +end; + +(******************************************************************************) + + procedure TCryptIniFile.WriteString(const Section, Ident, Value: string); +// Writes MD5Digest string + BASE64 or IDEA string +// Behaviour depends on PlainTextMode = FALSE/TRUE +var + s: string; +begin + if fPlainText = True then // Write regular string + begin + // Use regular TiniFile + inherited WriteString(Section, Ident, Value); + UpdateFile; + Exit; + end; + s := EncodeString(Value); // Encode the string (IDEA/BASE64) + fMyDigest := MDString(s, MD_VERSION_5); + fMD5String := MDPrint(fMyDigest); // Get the MD5Hash of the encoded string + s := fMD5String + s; // Prefix it to the encoded string + inherited WriteString(Section, Ident, s); // Write the result using TiniFile + if SectionHashing = True then + MakeSectionHash(Section, True); + UpdateFile; +end; + +(******************************************************************************) + +Function TCryptIniFile.SplitKeyValue(Const sValueEntry:String;var sKey,sValue:String):Boolean; +Var iEqualsPos:Integer; +begin + Result:=FALSE; + If Length(sValueEntry) < 4 then exit; + iEqualsPos := Pos('=', sValueEntry); + if (iEqualsPos >= 2) then + begin + sKey := LeftStr(sValueEntry, iEqualsPos - 1); + sValue := RightStr(sValueEntry, Length(sValueEntry) - iEqualsPos); + Result:=TRUE; + end; +end; + +(******************************************************************************) + +procedure TCryptIniFile.ReadSection(const Section: string; Strings: TStrings); +// If PlainText = FALSE then +// 1. Remove any INTEGER_MARKER +// 2. Remove MD5Hash entry +Var + TempStrings:TStrings; + iCount,iMD5HashEntry: integer; + s: string; +begin + inherited ReadSection(Section, Strings); // Use regular TiniFile + if fPlainText = True then exit;// Return faithful copy + + // Deal with PlainText = FALSE + iMD5HashEntry := -1; // dummy value + TempStrings := TStringList.Create; // Use a copy + TempStrings.BeginUpdate; + try + // Make a Copy + TempStrings.Clear; + TempStrings.AddStrings(Strings); // contains encrypted versions + for iCount := 0 to Pred(TempStrings.Count) do + begin + // Do not retrieve MD5Hash entry + if (Pos(IDENT_MD5HASH, TempStrings[iCount]) = 0) then + begin + s := TempStrings[iCount]; + If RightStr(s,1) = INTEGER_MARKER then + TempStrings[iCount]:=LeftStr(s,Length(s)-1); + end + else + iMD5HashEntry := iCount; + end; + finally + TempStrings.EndUpdate; + // Copy decoded versions back into the calling StringList + if (iMD5HashEntry >= 0) then + TempStrings.Delete(iMD5HashEntry); // Dont return the MD5Hash entry + Strings.Clear; + Strings.AddStrings(TempStrings); + TempStrings.Free; + end; +end; + +procedure TCryptIniFile.WriteSectionValues(const Section: string; Strings: TStrings); +// Writes either normal or Encrypted values depending on property PlainTextMode +// If SectionHashing = TRUE, also writes the MD5Hash entry at the end (for VerifySection method) +var + iCount, iTemp: integer; + s, sKey, sValue: string; + f: double; + TempSectionHashing: boolean; +begin + TempSectionHashing := fSectionHashing; // Preserve property + fSectionHashing := False; // Write section without on-the-fly hashing + for iCount := 0 to Strings.Count - 1 do + begin + s := Strings[iCount]; + // Split key and value + If NOT SplitKeyValue(s,sKey,sValue) then continue; + if TryStrToInt(sValue, iTemp) = True then + begin + WriteInteger(Section, sKey, iTemp); + Continue; + end; + if ((LowerCase(sValue) = 'true') or (LowerCase(sValue) = 'false')) then + begin + if (LowerCase(sValue) = 'true') then + WriteBool(Section, sKey, True) + else + WriteBool(Section, sKey, False); + Continue; + end; + if TryStrToFloat(sValue, f) = True then + begin + WriteFloat(Section, sKey, f); + Continue; + end; + // All other values + WriteString(Section, sKey, sValue); + end; + // Now is the time to write the MD5Hash entry + if TempSectionHashing = True then + begin + fSectionHashing := True; + MakeSectionHash(Section, True); + end; + UpdateFile; + fSectionHashing := TempSectionHashing; // Restore property +end; + +// ***************************************************************************// +{$IFDEF FPC311} + // TSectionValuesOption = (svoIncludeComments,svoIncludeInvalid, svoIncludeQuotes); + procedure TCryptIniFile.ReadSectionValues(const Section: string; + Strings: TStrings; AOptions: TSectionValuesOptions = []); +{$ELSE} + procedure TCryptIniFile.ReadSectionValues(const Section: string; Strings: TStrings); +{$ENDIF} +var + TempStrings: TStrings; + iCount, iMD5HashEntry: integer; + s, sKey, sValue: string; + iTemp: longint; +begin +{$IFDEF FPC311} + inherited ReadSectionValues(Section, Strings, AOptions); +{$ELSE} + inherited ReadSectionValues(Section, Strings); +{$ENDIF} + if fPlainText = True then // Use regular method + begin + // Use regular TiniFile + UpdateFile; + Exit; + end; + iMD5HashEntry := -1; // dummy value + TempStrings := TStringList.Create; // Use a copy + TempStrings.BeginUpdate; + try + // Make a Copy + TempStrings.Clear; + TempStrings.AddStrings(Strings); // contains encrypted versions + // Iterate through the list + for iCount := 0 to Pred(TempStrings.Count) do + begin + // Do not retrieve MD5Hash entry + if (Pos(IDENT_MD5HASH, TempStrings[iCount]) = 0) then + begin + s := TempStrings[iCount]; + // Split key and value + If NOT SplitKeyValue(s,sKey,sValue) then Exit; + // Deal with Integers, which are IDEA or BASE64 encoded then Encrypted + if RightStr(sKey, 1) = INTEGER_MARKER then // It's an Integer value + begin + s := DecodeString(RightStr(sValue, Length(sValue) - 32)); + // Decode (IDEA/BASE64) to a string + if TryStrToInt(s, iTemp) then + begin + iTemp := DecodeInteger(iTemp); // Decrypt the integer + s := IntToStr(iTemp); // String value of decoded integer + end; + sKey := LeftStr(sKey, Length(sKey) - 1); // Trim off the INTEGER_MARKER + end + else + begin + // All but Integers are simply IDEA or BASE64 encoded + s := DecodeString(RightStr(sValue, Length(sValue) - 32)); + end; + // Replace encoded version with decoded version + TempStrings[iCount] := sKey + '=' + s; + end + else + iMD5HashEntry := iCount; + // Grab the sKey and sValue (we only want to decrypt the Value) + end; + finally + TempStrings.EndUpdate; + // Copy decoded versions back into the calling StringList + if (iMD5HashEntry >= 0) then + TempStrings.Delete(iMD5HashEntry); // Dont return the MD5Hash entry + Strings.Clear; + Strings.AddStrings(TempStrings); + TempStrings.Free; + end; +end; + +// ***************************************************************************// + +function TCryptIniFile.ReadBinaryStream(const Section, Name: string; Value: TStream): Integer; +// Force normal TINIFile mode +Var + tempPlainTextMode:Boolean; + tempSectionHashing:Boolean; +begin + tempPlainTextMode:=PlainTextMode; + tempSectionHashing:=SectionHashing; + PlainTextMode:=TRUE; + SectionHashing:=FALSE; + Result:=inherited ReadBinaryStream(Section, Name,Value); + PlainTextMode:=tempPlainTextMode; + SectionHashing:=tempSectionHashing; +end; + +// ***************************************************************************// + +procedure TCryptIniFile.WriteBinaryStream(const Section, Name: string; Value: TStream); +// Force normal TINIFile mode +Var + tempPlainTextMode:Boolean; + tempSectionHashing:Boolean; +begin + tempPlainTextMode:=PlainTextMode; + tempSectionHashing:=SectionHashing; + PlainTextMode:=TRUE; + SectionHashing:=FALSE; + inherited WriteBinaryStream(Section, Name,Value); + PlainTextMode:=tempPlainTextMode; + SectionHashing:=tempSectionHashing; +end; + +// ***************************************************************************// +// ***************************************************************************// + + procedure TCryptIniFile.MakeSectionHash(const Section: string; WriteToINI: boolean); +// VerifySection uses WriteToINI=FALSE +var + TempStrings: TStrings; + iCount: integer; + s: string; + tempPlainText: boolean; +begin + if fSectionHashing = False then Exit; + tempPlainText:=fPlainText; // Store value + TempStrings := TStringList.Create; + TempStrings.BeginUpdate; + try + s := ''; + ReadSectionValues(Section, TempStrings); + for iCount := 0 to Pred(TempStrings.Count) do + // Ignore the MD5Hash entry + if (Pos(IDENT_MD5HASH, TempStrings[iCount]) = 0) then + s := s + TempStrings[iCount]; + //DEBUG: else ShowMessage('Found ' + IDENT_MD5HASH); + fMyDigest := MDString(s, MD_VERSION_5); + fMD5String := MDPrint(fMyDigest); + //DEBUG: ShowMessage(fMD5String); + TempPlainText := fPlainText; // Store old value + fPlainText := True; // Set PlainTextMode ON + // Default WriteToINI = TRUE + if WriteToINI then + WriteString(Section, IDENT_MD5HASH, fMD5String); + fPlainText := tempPlainText; // Restore old value + finally + TempStrings.EndUpdate; + TempStrings.Free; + end; +end; + +function TCryptIniFile.VerifySectionHash(const Section, TestMD5Hash: string): boolean; +begin + Result := False; + if fSectionHashing = False then Exit; + { + if ((fSectionHashing = False) or (fPlainText = True)) then + Exit; + } + fMD5String := ''; + // Rehash, but without writing in order to set fMD5String correctly + MakeSectionHash(Section, False); + //DEBUG: ShowMessage(fMD5String); + //DEBUG: ShowMessage(TestMD5Hash); + if (fMD5String = TestMD5Hash) then + Result := True; +end; + +function TCryptIniFile.VerifyString(const Section, Ident, TestValue: string): boolean; + // Matches both value and Hash +var + sCorrect, sCorrectMD5: string; +begin + Result := False; + if fPlainText = True then + Exit; + // Fetch the MD5 hash of the TestValue string + sCorrect := EncodeString(TestValue); + fMyDigest := MDString(sCorrect, MD_VERSION_5); + sCorrectMD5 := MDPrint(fMyDigest); + + // Read the MD5 hash of the INI string (sets fMD5String) and get the value; + fMD5String := ''; + sCorrect := ReadString(Section, Ident, ''); + // DEBUG + { + ShowMessageFmt('sCorrectMD5=%s, fMD5String=%s, sCorrect=%s, TestValue=%s', + [sCorrectMD5,fMD5String,sCorrect,TestValue]); + } + if ((sCorrectMD5 = fMD5String) and (sCorrect = TestValue)) then + Result := True; +end; + +// ***************************************************************************// + +function TCryptIniFile.VerifyInteger(const Section, Ident: string; + TestValue: longint): boolean; + // Matches both value and Hash +var + iCorrect: longint; + sCorrect, sCorrectMD5: string; +begin + Result := False; + if fPlainText = True then + Exit; + iCorrect:=0; + if TestValue <> 0 then + iCorrect := EncodeInteger(TestValue); // Use fKey to scramble it + // Encode it as a string + sCorrect := EncodeString(IntToStr(iCorrect)); + // Make an MD5 Hash of it (sets fMD5String) + fMyDigest := MDString(sCorrect, MD_VERSION_5); + sCorrectMD5 := MDPrint(fMyDigest); + // Use ReadInteger to get the fMD5String of the INI file entry + // And read the value + iCorrect := ReadInteger(Section, Ident, 9999); // Automatically uses fKey to unscramble + // Value and MD5Hash match? + if ((sCorrectMD5 = fMD5String) and (iCorrect = TestValue)) then + Result := True; +end; + +// ***************************************************************************// + +function TCryptIniFile.VerifyBool(const Section, Ident: string; + TestValue: boolean): boolean; +begin + Result := False; + if fPlainText = True then + Exit; + Result := VerifyString(Section, Ident, BoolToChar(TestValue)); +end; + +// ***************************************************************************// + +function TCryptIniFile.VerifyInt64(const Section, Ident: string; + TestValue: int64): boolean; +begin + Result := False; + if fPlainText = True then + Exit; + Result := VerifyString(Section, Ident, IntToStr(TestValue)); +end; + +// ***************************************************************************// + +function TCryptIniFile.VerifyFloat(const Section, Ident: string; + TestValue: double): boolean; +begin + Result := False; + if fPlainText = True then + Exit; + Result := VerifyString(Section, Ident, FloatToStr(TestValue)); +end; + +// ***************************************************************************// + +function TCryptIniFile.VerifyDate(const Section, Ident: string; + TestValue: TDateTime): boolean; +begin + Result := False; + if fPlainText = True then + Exit; + Result := VerifyString(Section, Ident, DateToStr(TestValue)); +end; + +// ***************************************************************************// + +function TCryptIniFile.VerifyTime(const Section, Ident: string; + TestValue: TDateTime): boolean; +begin + Result := False; + if fPlainText = True then + Exit; + Result := VerifyString(Section, Ident, TimeToStr(TestValue)); +end; + +// ***************************************************************************// + +function TCryptIniFile.VerifyDateTime(const Section, Ident: string; + TestValue: TDateTime): boolean; +begin + Result := False; + if fPlainText = True then + Exit; + Result := VerifyString(Section, Ident, DateTimeToStr(TestValue)); +end; + +// ***************************************************************************// + +{$IFDEF USE_DCPCRYPT} +// TODO? use Stream property (Filename='') +Function TCryptIniFile.EncryptINI(DeleteOld:Boolean = TRUE;sPassword: string = DEFAULT_KEYPHRASE;NewExt:String = DEFAULT_EXT):Boolean; +var + Cipher: TDCP_rc4; + Source,Dest: TFileStream; +begin + CacheUpdates:=FALSE; + UpdateFile; + Result:=FALSE; + If NOT FileExistsUTF8(Filename) then exit; + try + If sPassword = '' then sPassword:=fKeyPhrase; + Source := TFileStream.Create(Filename, fmOpenRead); + // INI.Filename, PATH SOURCE OF FILE + Dest := TFileStream.Create(ChangeFileExt(Filename, NewExt), fmCreate); + // ChangeFileExt(INI.Filename, NewExt), PATH DESTINATION OF FILE + Cipher := TDCP_rc4.Create(Nil); + Cipher.InitStr(sPassword, TDCP_sha1); + // initialize the cipher with a hash of the passphrase + Cipher.EncryptStream(Source, Dest, Source.Size); + // encrypt the contents of the file + Cipher.Burn; + Cipher.Free; + finally + Dest.Free; + Source.Free; + Result:=TRUE; + If DeleteOld then Result:=Result AND DeleteFile(Filename); + end; +end; + +// ***************************************************************************// + +Function TCryptIniFile.DecryptINI(DeleteOld:Boolean = TRUE;sPassword: string = DEFAULT_KEYPHRASE;NewExt:String = DEFAULT_EXT):Boolean; +var + Cipher: TDCP_rc4; + Source,Dest: TFileStream; +begin + Result:=FALSE; + If NOT FileExistsUTF8(ChangeFileExt(Filename, NewExt)) then exit; + try + If sPassword = '' then sPassword:=fKeyPhrase; + Source := TFileStream.Create(ChangeFileExt(Filename, NewExt), fmOpenRead); + // ChangeFileExt(INI.Filename, NewExt), PATH SOURCE OF FILE + Dest := TFileStream.Create(Filename, fmCreate); + // INI.Filename, PATH DESTINATION OF FILE + Cipher := TDCP_rc4.Create(Nil); + Cipher.InitStr(sPassword, TDCP_sha1); + // initialize the cipher with a hash of the passphrase + Cipher.DecryptStream(Source, Dest, Source.Size); + // decrypt the contents of the file + Cipher.Burn; + Cipher.Free; + finally + Dest.Free; + Source.Free; + Result:=TRUE; + If DeleteOld then Result:=Result AND DeleteFile(ChangeFileExt(Filename, NewExt)); + // Re-initialise Decrypted INI from disk + Try + {$IFDEF FPC311} + Create(Filename,Options); + {$else} + Create(Filename,EscapeLineFeeds); + {$endif} + CacheUpdates:=FALSE; + Except + // Eat exception + Result:=FALSE; + end; + end; +end; +{$ENDIF} + +// ***************************************************************************// +// ENDOFFILE +// ***************************************************************************// + +end.