1

I have a Delphi 10.4 program with a clientdataset, loading XML files users choose with OpenFile dialog. It works just fine and depending on the contents of the XML, the fielddef structure is set automatically.

Now I want to be able to read Decrypted files and with ClientDataSet.SaveToFile, save Encrypted files.

Currently I'm using Lockbox 3.7 to Decrypt the chosen file, creating a temp file, which is then read by loadfromfile. Likewise Savetofile writes data back to a temp file, which is then encrypted and given it's chosen name. It works very well, but leaves the temp file on disk. And even if I delete the temp file in code, it's relatively easy to recover it, if you know how. So the security with Encryption like this, is not so high after all.

I would want to be able to perform the decryption directly in LoadFromFile (and similar encryption at SaveToFile) as a fileEn(or De)Crypt function, as suggested by the subject, without the use of temp files, but haven't been able to find any useful functions.

Do anybody know of such function ? If so, please point me in the right direction. The last couple of days I've been using google to search for something useful, but it has left me more confused and lost, than I feel I was before.

An alternative solution where the temp files created by the LockBox EnCryptFile (and DeCryptFile) are completely destroyed, to a point where no recovery is possible, would do as a temporary solution, so pointers to ways to destroy a file completely, would also be welcome.

Thanks in advance for any help I can get.

lscshj
  • 63
  • 6

2 Answers2

1

Use ClientDataSet.LoadFromStream instead of LoadFromFile. I'm sure LockBox has a function to decrypt into a TStream. Use a TMemoryStream to avoid storing decrypted data to disk.

Likewise, write the client dataset to a stream (SaveToStream), use a TMemoryStream and it will stay in memory. Then encrypt it and save the result to disk.

fpiette
  • 11,983
  • 1
  • 24
  • 46
  • Thanks for the comment. As far as I can see Lockbox do have an EnCryptStream and DeCryptStream, but they are procedures as are DecryptFile. I'll look into trying with a MemoryStream and see where it takes me. Thanks again. – lscshj Dec 10 '20 at 15:56
  • As for the Alternative solution: I've found an example of DeleteAndWipe with suggestions overwriting the temp file a number of times with different values, before deleting it. I'll try that as well. – lscshj Dec 10 '20 at 15:58
  • @lscshj If LockBox has EncryptStream, the save ClientDataSet to TMemoryStream and the save the encrypted strreamto a file using MemoryStream.SaveToFile. In the reverse, load the file using a TMemoryStream with his LoadFromFile, decrypt the stream using Lockbox and load ClientDataSet with that decrypted stream. Forget about DeleteAndWipe because if you program crash (maybe intentionally), decoded data will stay there. – fpiette Dec 10 '20 at 16:18
1

piette: Thanks for your input. I have accepted your answer.

And after messing around for a little while, I've come up with the following solution. Please do not comment on missing error check (try-Except) or housekeeping (try-Final) as it is only a test. In the final code, all checks will be in place and users be notified in case of errors encountered. I will also change it to a function, returning true or false, depending on success or not.

And just a few words to clarify: On the form I have a TCryptographicLibrary and TCodec from Lockbox 3.7. The Codec ChainMode and Cipher has been chosen by the user before selecting a file to load, and the user also provides a password used as key. The file is selected with OpenDialog. Also on the form is a TClientDataSet, a TDataSource, a TDBGrid and a TDBNavigator.

I messed around for a while getting "Missing Data Provider or Data Packet" at the time of ClientDataSet.LoadFromStream and the reason turned out to be a missing Seek on the stream. Hence the line: XMLSt.Seek(0, soBeginning); just before loading the stream.

This code is working, giving me a filled-in DBGrid, with Fields and Defs and Data according to the XML file selected.

Procedure TForm1.LoadFile(FileName : String; PassWord : string);
var XMLSt : TMemoryStream;
    DecSt : TMemoryStream;
begin
  DecSt := TMemoryStream.Create;
  DecSt.LoadFromFile(FileName);

  XMLSt := TMemoryStream.Create;

  Codec1.Password    := PassWord;
  Codec1.DeCryptStream(XMLSt,DecSt);

  XMLSt.Seek(0, soBeginning);
  ClientDataSet1.LoadFromStream(XMLSt);

  XmlSt.Free;
  DecSt.Free;

  ClientDataSet1.Active  := true;
end;

And reversing the operation, using ClientDataSet.SaveToStream, Codec1.EnCryptStream and TMemoryStream.SaveToStream in stead, will save the ClientDataSet contents as an encrypted XML file.

NB! This test is with a form, allowing the user to select a decrypted XML file, edit the contents and (once the corresponding SaveFile is in place), be able to save the contents again as an encrypted XML file. It is relatively easy to remove the visual components and create them at runtime, allowing this to be a general function, transporting EnCrypted data from an XML file to a ClientDataSet and back.

Again, Thanks for your input !

lscshj
  • 63
  • 6