Difference between revisions of "CryptINI"
Minesadorada (talk | contribs) (Download link added) |
Minesadorada (talk | contribs) m (re-Fixed syntax highlight errors) |
||
(25 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
==CryptINI== | ==CryptINI== | ||
− | === | + | === Screenshots === |
+ | <br> | ||
+ | * Screenshot of Test/Demo app | ||
+ | [[File:latest_testcryptini.jpg]] | ||
+ | <br> | ||
+ | * Contents of INI written by CryptINI | ||
+ | [[File:testcryptini1.jpg]] | ||
+ | ===Purpose=== | ||
− | + | TCryptIni is a TiniFile implementation that is resistant to tampering. | |
− | In normal (PlainTextMode = FALSE) mode, any calls to Write values are | + | 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) |
− | 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. |
− | This is invisible in normal use (i.e. read methods return normal results) | + | 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. |
− | 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 also includes a useful 'First Run' functionality. | ||
− | It's intended purpose is to store information that cannot be easily altered | + | 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. |
− | 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. |
− | 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 | It is paired with ReadInteger and VerifyInteger | ||
− | === | + | ===Disclaimer=== |
− | This unit does not claim to pass any security tests nor be used in | + | This unit does not claim to pass any security tests nor be used in any environment where a moderate-level hacker could circumvent it. |
− | any environment where a moderate-level hacker could circumvent it. | ||
− | === | + | ===Encryption=== |
By Default CryptINI uses the DCPCrypt package for string 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 | + | The mode is IDEA cipher with an MD5 hash for the key. The EncryptINI and DecryptINI methods use DCPCrypt RC4 Cipher (With SHA hash) |
− | and DecryptINI methods use DCPCrypt RC4 Cipher (With SHA hash) | + | There is a $DEFINE USE_DCPCRYPT directive at the top of the ucryptini file. |
− | There is a $DEFINE USE_DCPCRYPT directive at the top of | ||
− | If this DEFINE is commented out, then CryptINI will default | + | If this DEFINE is commented out, then CryptINI will default to BASE64 string encryption, which is weaker. Encrypt/DecryptINI methods will be unavailable. |
− | 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. | You can then delete any requirement for dcpcrypt in the project inspector. | ||
− | === | + | ===FPC versions=== |
− | Starting in FPC V3. | + | 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. |
− | are implemented in TCryptINI if the FPC Version >= 3 is detected. | ||
− | === | + | ===Use and Example Code=== |
+ | * '''Tip:''' Add CryptINI as a requirement in Project Inspector | ||
+ | ====Simple use==== | ||
+ | Instead of | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | Uses Inifiles; | ||
+ | TForm1.SomeProcedure; | ||
+ | Var INI:TIniFile; | ||
+ | begin | ||
+ | INI := TIniFile.Create(ChangeFileExt(Application.EXEName, '.cfg')); | ||
+ | end; | ||
+ | </syntaxhighlight> | ||
+ | You do: (note the 'uses ucryptini') | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | Uses ucryptini; | ||
+ | TForm1.SomeProcedure; | ||
+ | Var INI:TCryptIniFile; | ||
+ | begin | ||
+ | INI := TCryptIniFile.Create(ChangeFileExt(Application.EXEName, '.cfg')); | ||
+ | end; | ||
+ | </syntaxhighlight> | ||
+ | * If you do: | ||
+ | <syntaxhighlight lang="pascal"> | ||
+ | INI.PlainTextMode=True; | ||
+ | INI.SectionHashing:=False; | ||
+ | </syntaxhighlight> | ||
+ | .. then TCryptINI will behave *exactly* as TIniFile does, so you can drop it into existing code without changing an existing INI file. | ||
+ | * If you are coding a new app, then leave PlainTextmode as its default value (TRUE) and code as you would for Tinifile. The advantage is that you can then use CryptINI's extra methods, like Verify and WriteIdent etc. | ||
− | * You can hard-code an Ident Section in your INI file | + | ====Using the WriteIdent etc in Form.Create==== |
− | and check if it has been altered | + | * You can hard-code an Ident Section in your INI file and check if it has been altered |
+ | * '''Note''' to use this function you must include Version Info in your project (Project/Project Options/Version Info) | ||
* Typical Form.Create() | * Typical Form.Create() | ||
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
procedure TForm1.FormCreate(Sender: TObject); | procedure TForm1.FormCreate(Sender: TObject); | ||
const | const | ||
Line 54: | Line 78: | ||
// First ever run. INI is absent | // First ever run. INI is absent | ||
− | If INI.IsVirgin then INI.WriteIdent('minesadorada','(c)2016','minesadorada@charcodelvalle.com','Creative Commons',TRUE); | + | If INI.IsVirgin then INI.WriteIdent('minesadorada','(c)2016','minesadorada@charcodelvalle.com','Creative Commons',TRUE); |
if NOT INI.VerifyIdent('5b319674f5cb55f3ed1e404e33c25868') then // I got this from the INI file | if NOT INI.VerifyIdent('5b319674f5cb55f3ed1e404e33c25868') then // I got this from the INI file | ||
Line 82: | Line 106: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | * Has the Ident been tampered with? Put this in Form.Create | + | * Has the Ident been tampered with? Put something like this in Form.Create: |
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
// Use the MD5 value from the INI file (use your own!) | // Use the MD5 value from the INI file (use your own!) | ||
If INI.VerifyIdent('92abf0deecbb25c435bff507a396d92a') then | If INI.VerifyIdent('92abf0deecbb25c435bff507a396d92a') then | ||
Line 91: | Line 115: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
* Test for first run | * Test for first run | ||
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
If INI.IsVirgin then // note that doing the test Deflowers the app by default | If INI.IsVirgin then // note that doing the test Deflowers the app by default | ||
ShowMessage('First time run of this app'); | ShowMessage('First time run of this app'); | ||
Line 98: | Line 122: | ||
* Toggle to normal UnEncrypted INI use | * Toggle to normal UnEncrypted INI use | ||
(by default it is set to FALSE) | (by default it is set to FALSE) | ||
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
INI.PlainTextMode:=TRUE; | INI.PlainTextMode:=TRUE; | ||
INI.WriteString('MySection', 'String', 'MyString'); // just writes normally | INI.WriteString('MySection', 'String', 'MyString'); // just writes normally | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | * When PlainTextMode = FALSE (default) and SectionHashing=TRUE (default),Write<anytype> encrypts the value | + | * When PlainTextMode = FALSE (default) and SectionHashing=TRUE (default),Write<anytype> encrypts the value and prefixes the encrypted value with an MD5Hash. In addition each section has an entry MD5Hash=<32 characters> which is updated on each write. |
− | and prefixes the encrypted value with an MD5Hash | + | <syntaxhighlight lang="pascal">INI.WriteInteger('MySection', 'Integer',1000);</syntaxhighlight> |
− | <syntaxhighlight>INI.WriteInteger('MySection', 'Integer',1000);</syntaxhighlight> | ||
* Note WriteInteger adds a '+' (INTEGER_MARKER) to the written Key | * Note WriteInteger adds a '+' (INTEGER_MARKER) to the written Key | ||
Line 113: | Line 136: | ||
* When PlainTextMode = FALSE (default), use these convenient methods if you like: | * When PlainTextMode = FALSE (default), use these convenient methods if you like: | ||
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
INI.ReadUnencryptedString | INI.ReadUnencryptedString | ||
INI.WriteUnencryptedString | INI.WriteUnencryptedString | ||
Line 121: | Line 144: | ||
* Store 'First Run' status using these methods: | * Store 'First Run' status using these methods: | ||
− | <syntaxhighlight> | + | <syntaxhighlight lang="pascal"> |
INI.IsVirgin | INI.IsVirgin | ||
INI.Deflower | INI.Deflower | ||
INI.ReFlower (useful for testing) | INI.ReFlower (useful for testing) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | * Original IniFiles methods and properties | + | ===Encrypting/Decrypting the whole INI file=== |
− | Just use them as normal. Note: you can mix-and-match Plaintext and Encrypted | + | * You can encrypt and decrypt the entire INI file using methods EncryptINI and DecryptINI. |
− | in the same INI file. Just toggle the property PlainTextMode before Writing/Reading | + | This uses a different cipher and hash method, so is extra-secure. |
+ | * Note: 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 EncryptINI/DecryptINI method calls 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 | ||
===Testing App/Demo=== | ===Testing App/Demo=== | ||
* This can be downloaded from https://sourceforge.net/projects/lazautoupdate/files/otherpackages/testcryptini_compiled.zip | * This can be downloaded from https://sourceforge.net/projects/lazautoupdate/files/otherpackages/testcryptini_compiled.zip | ||
− | * There are compiled versions for Windows 32/64-bit and Linux 32/64-bit in the archive | + | * There are compiled versions for Windows 32/64-bit and Linux 32/64-bit in the archive. (Also untested MacOS 10 'Darwin' 32-bit) |
+ | |||
+ | ===Documentation=== | ||
+ | * As well as this page, ucryptini.pas is heavily commented. The Testing app (source also commented) will help you understand the strengths and limitations of CryptINI, and how to get the best of it in your own applications. | ||
+ | |||
+ | === Licence === | ||
+ | * [https://www.gnu.org/licenses/gpl-faq.en.html ModifiedGPL] | ||
==Download== | ==Download== | ||
* Sourcecode and Testing app Direct link: https://sourceforge.net/projects/lazautoupdate/files/otherpackages/cryptinitest_source.zip | * Sourcecode and Testing app Direct link: https://sourceforge.net/projects/lazautoupdate/files/otherpackages/cryptinitest_source.zip | ||
+ | * CryptIni as a component: via [[Online_Package_Manager]] | ||
+ | |||
+ | ===Package Installation=== | ||
+ | * Download the package: https://sourceforge.net/projects/lazautoupdate/files/otherpackages/cryptini.zip | ||
+ | * Unzip it into a new folder (Suggest <LazarusDir>/components/cryptini) | ||
+ | * In the Lazarus IDE Click Package/Open Package File (lpk), navigate to your new folder and click "cryptini.lpk", then "Open" | ||
+ | * Just click "Compile". It is not a visual component, so cannot be "Installed" | ||
+ | * To use it in your project, just add ucryptini to the Uses clause when required, or better still: add CryptIni (the component) to the projects's requirements. | ||
<br> | <br> | ||
---- | ---- |
Latest revision as of 12:13, 30 August 2019
CryptINI
Screenshots
- Screenshot of Test/Demo app
- Contents of INI written by CryptINI
Purpose
TCryptIni 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 the ucryptini 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.
FPC 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
- Tip: Add CryptINI as a requirement in Project Inspector
Simple use
Instead of
Uses Inifiles;
TForm1.SomeProcedure;
Var INI:TIniFile;
begin
INI := TIniFile.Create(ChangeFileExt(Application.EXEName, '.cfg'));
end;
You do: (note the 'uses ucryptini')
Uses ucryptini;
TForm1.SomeProcedure;
Var INI:TCryptIniFile;
begin
INI := TCryptIniFile.Create(ChangeFileExt(Application.EXEName, '.cfg'));
end;
- If you do:
INI.PlainTextMode=True;
INI.SectionHashing:=False;
.. then TCryptINI will behave *exactly* as TIniFile does, so you can drop it into existing code without changing an existing INI file.
- If you are coding a new app, then leave PlainTextmode as its default value (TRUE) and code as you would for Tinifile. The advantage is that you can then use CryptINI's extra methods, like Verify and WriteIdent etc.
Using the WriteIdent etc in Form.Create
- You can hard-code an Ident Section in your INI file and check if it has been altered
- Note to use this function you must include Version Info in your project (Project/Project Options/Version Info)
- 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);
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 something like 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) and SectionHashing=TRUE (default),Write<anytype> encrypts the value and prefixes the encrypted value with an MD5Hash. In addition each section has an entry MD5Hash=<32 characters> which is updated on each write.
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)
Encrypting/Decrypting the whole INI file
- You can encrypt and decrypt the entire INI file using methods EncryptINI and DecryptINI.
This uses a different cipher and hash method, so is extra-secure.
- Note: 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 EncryptINI/DecryptINI method calls 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
Testing App/Demo
- This can be downloaded from https://sourceforge.net/projects/lazautoupdate/files/otherpackages/testcryptini_compiled.zip
- There are compiled versions for Windows 32/64-bit and Linux 32/64-bit in the archive. (Also untested MacOS 10 'Darwin' 32-bit)
Documentation
- As well as this page, ucryptini.pas is heavily commented. The Testing app (source also commented) will help you understand the strengths and limitations of CryptINI, and how to get the best of it in your own applications.
Licence
Download
- Sourcecode and Testing app Direct link: https://sourceforge.net/projects/lazautoupdate/files/otherpackages/cryptinitest_source.zip
- CryptIni as a component: via Online_Package_Manager
Package Installation
- Download the package: https://sourceforge.net/projects/lazautoupdate/files/otherpackages/cryptini.zip
- Unzip it into a new folder (Suggest <LazarusDir>/components/cryptini)
- In the Lazarus IDE Click Package/Open Package File (lpk), navigate to your new folder and click "cryptini.lpk", then "Open"
- Just click "Compile". It is not a visual component, so cannot be "Installed"
- To use it in your project, just add ucryptini to the Uses clause when required, or better still: add CryptIni (the component) to the projects's requirements.