From a work application; loading:
var
first : TBase64DecodingStream;
ins :TStringStream;
ind,outs : TMemoryStream;
cipher : TDCP_rijndael;
hash: TDCP_sha512;
CipherIV: array of byte; // the initialisation vector (for chaining modes)
HashDigest: array of byte; // the result of hashing the passphrase with the salt
Salt: array[0..7] of byte; // a random salt to help prevent precomputated attacks
ins:=TStringstream.Create(s); // input: a base64 encoded string
first :=TBase64DecodingStream.Create(ins); //first decode
try
ind:=TMemoryStream.create; // stream for based64 decoded data
try
ind.CopyFrom(first,first.Size);
ind.Seek(0,soFromBeginning); // !!!!! ALWAYS MAKE SURE THAT INPUT STREAM
// IS AT CORRECT POINT, MOST COMMON MISTAKE!
outs:=TMemoryStream.Create; // the memorystream containeing the output
try
Hash := TDCP_sha512.create(nil);
try
SetLength(HashDigest,Hash.HashSize div 8);
ind.ReadBuffer(Salt[0],Sizeof(Salt)); // read the salt in from the file
Hash.Init;
Hash.Update(Salt[0],Sizeof(Salt)); // hash the salt
Hash.UpdateStr(Passphrase); // and the passphrase
Hash.Final(HashDigest[0]); // store the hash in HashDigest
Cipher := TDCP_rijndael.Create(nil);
try
SetLength(CipherIV,TDCP_blockcipher(Cipher).BlockSize div 8);
ind.ReadBuffer(CipherIV[0],Length(CipherIV)); // read the initialisation vector from the file
Cipher.Init(HashDigest[0],Min(Cipher.MaxKeySize,Hash.HashSize),CipherIV); // initialise the cipher
TDCP_blockcipher(Cipher).CipherMode := cmCBC;
Cipher.DecryptStream(ind,outs,ind.Size - ind.Position); // decrypt!
Cipher.Burn;
ins.Free;
outs.Seek(0,soFromBeginning);
r:=TMyReader.Create;
try
r.handle:=outs; // open(s);
r.readinteger(mversie);
// mversie:=$160011;
r.setversionobject(self);
laad(r);
finally
r.free;
end;
finally
cipher.free;
end;
finally
hash.free;
end;
finally
outs.free;
end;
finally
ind.free;
end;
finally
first.free;
end;
The writing:
var i,j : integer;
w : TMyWriter;
ins,outs: TMemoryStream;
final : TStringStream;
bstr : TBase64EncodingStream;
cipher : TDCP_rijndael;
hash: TDCP_sha512;
CipherIV: array of byte; // the initialisation vector (for chaining modes)
HashDigest: array of byte; // the result of hashing the passphrase with the salt
Salt: array[0..7] of byte; // a random salt to help prevent precomputated attacks
begin
ins:=TMemoryStream.create;
try
// code here streams datastructure to "ins".
ins.Seek(0,soFromBeginning); // reset INS position.
j:=ins.size;
outs:=TmemoryStream.create;
try
Hash := TDCP_sha512.create(nil);
try
SetLength(HashDigest,Hash.HashSize div 8);
for i := 0 to 7 do
Salt[i] := Random(256); // just fill the salt with random values (crypto secure PRNG would be better but not _really_ necessary)
outs.WriteBuffer(Salt,Sizeof(Salt)); // write out the salt so we can decrypt!
Hash.Init;
Hash.Update(Salt[0],Sizeof(Salt)); // hash the salt
Hash.UpdateStr(Passphrase); // and the passphrase
Hash.Final(HashDigest[0]); // store the output in HashDigest
cipher :=TDCP_rijndael.create(nil);
try
SetLength(CipherIV,TDCP_blockcipher(Cipher).BlockSize div 8);
for i := 0 to (Length(CipherIV) - 1) do
CipherIV[i] := Random(256); // again just random values for the IV
outs.WriteBuffer(CipherIV[0],Length(CipherIV)); // write out the IV so we can decrypt!
Cipher.Init(HashDigest[0],Min(Cipher.MaxKeySize,Hash.HashSize),CipherIV); // initialise the cipher with the hash as key
TDCP_blockcipher(Cipher).CipherMode := cmCBC; // use CBC chaining when encrypting
Cipher.EncryptStream(ins,outs,ins.Size); // encrypt the entire file
Cipher.Burn; // important! get rid of keying information
final:=TStringStream.create('');
outs.Seek(0,soFromBeginning);
bstr :=TBase64EncodingStream.Create(final); // we base64 result, because have to store in XML config file.
try
bstr.WriteBuffer(outs.memory^,outs.Size);
finally
bstr.Free;
end;
final.Seek(0,soFromBeginning);
data :=final.DataString;
final.Free;
finally
cipher.free;
end;
finally
hash.free;
end;
finally
outs.Free;
end;
finally
ins.Free;
end;
end;
The streams can be TFileStreams. These are seekable, so work the same. Only non seekable streams require (possibly) different approach.