635 lines
19 KiB
ObjectPascal
635 lines
19 KiB
ObjectPascal
(* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is TurboPower Abbrevia
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* TurboPower Software
|
|
*
|
|
* Portions created by the Initial Developer are Copyright (C) 1997-2002
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* ***** END LICENSE BLOCK ***** *)
|
|
|
|
{*********************************************************}
|
|
{* ABBREVIA: AbDfCryS.pas *}
|
|
{*********************************************************}
|
|
{* Deflate encryption streams *}
|
|
{*********************************************************}
|
|
|
|
unit AbDfCryS;
|
|
|
|
{$I AbDefine.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes;
|
|
|
|
type
|
|
TAbZipEncryptHeader = array [0..11] of byte;
|
|
|
|
TAbZipDecryptEngine = class
|
|
private
|
|
FReady : boolean;
|
|
FState : array [0..2] of longint;
|
|
protected
|
|
procedure zdeInitState(const aPassphrase : AnsiString);
|
|
public
|
|
constructor Create;
|
|
|
|
function Decode(aCh : byte) : byte;
|
|
{-decodes a byte}
|
|
procedure DecodeBuffer(var aBuffer; aCount : integer);
|
|
{-decodes a buffer}
|
|
|
|
function VerifyHeader(const aHeader : TAbZipEncryptHeader;
|
|
const aPassphrase : AnsiString;
|
|
aCheckValue : longint) : boolean;
|
|
{-validate an encryption header}
|
|
end;
|
|
|
|
TAbDfDecryptStream = class(TStream)
|
|
private
|
|
FCheckValue : longint;
|
|
FEngine : TAbZipDecryptEngine;
|
|
FOwnsStream : Boolean;
|
|
FPassphrase : AnsiString;
|
|
FReady : boolean;
|
|
FStream : TStream;
|
|
protected
|
|
public
|
|
constructor Create(aStream : TStream;
|
|
aCheckValue : longint;
|
|
const aPassphrase : AnsiString);
|
|
destructor Destroy; override;
|
|
|
|
function IsValid : boolean;
|
|
|
|
function Read(var aBuffer; aCount : longint) : longint; override;
|
|
function Seek(aOffset : longint; aOrigin : word) : longint; override;
|
|
function Write(const aBuffer; aCount : longint) : longint; override;
|
|
|
|
property OwnsStream : Boolean
|
|
read FOwnsStream
|
|
write FOwnsStream;
|
|
end;
|
|
|
|
TAbZipEncryptEngine = class
|
|
private
|
|
FReady : boolean;
|
|
FState : array [0..2] of longint;
|
|
protected
|
|
procedure zeeInitState(const aPassphrase : AnsiString);
|
|
public
|
|
constructor Create;
|
|
|
|
function Encode(aCh : byte) : byte;
|
|
{-encodes a byte}
|
|
procedure EncodeBuffer(var aBuffer; aCount : integer);
|
|
{-encodes a buffer}
|
|
|
|
procedure CreateHeader(var aHeader : TAbZipEncryptHeader;
|
|
const aPassphrase : AnsiString;
|
|
aCheckValue : longint);
|
|
{-generate an encryption header}
|
|
end;
|
|
|
|
TAbDfEncryptStream = class(TStream)
|
|
private
|
|
FBuffer : PAnsiChar;
|
|
FBufSize : integer;
|
|
FEngine : TAbZipEncryptEngine;
|
|
FStream : TStream;
|
|
protected
|
|
public
|
|
constructor Create(aStream : TStream;
|
|
aCheckValue : longint;
|
|
const aPassphrase : AnsiString);
|
|
destructor Destroy; override;
|
|
|
|
function Read(var aBuffer; aCount : longint) : longint; override;
|
|
function Seek(aOffset : longint; aOrigin : word) : longint; override;
|
|
function Write(const aBuffer; aCount : longint) : longint; override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
{Notes: the ZIP spec defines a couple of primitive routines for
|
|
performing encryption. For speed Abbrevia inlines them into
|
|
the respective methods of the encryption/decryption engines
|
|
|
|
char crc32(long,char)
|
|
return updated CRC from current CRC and next char
|
|
|
|
update_keys(char):
|
|
Key(0) <- crc32(key(0),char)
|
|
Key(1) <- Key(1) + (Key(0) & 000000ffH)
|
|
Key(1) <- Key(1) * 134775813 + 1
|
|
Key(2) <- crc32(key(2),key(1) >> 24)
|
|
end update_keys
|
|
|
|
char decrypt_byte()
|
|
local unsigned short temp
|
|
temp <- Key(2) | 2
|
|
decrypt_byte <- (temp * (temp ^ 1)) >> 8
|
|
end decrypt_byte
|
|
}
|
|
|
|
uses
|
|
AbUtils;
|
|
|
|
{---magic numbers from ZIP spec---}
|
|
const
|
|
StateInit1 = 305419896;
|
|
StateInit2 = 591751049;
|
|
StateInit3 = 878082192;
|
|
MagicNumber = 134775813;
|
|
|
|
{===internal encryption class========================================}
|
|
constructor TAbZipDecryptEngine.Create;
|
|
begin
|
|
{create the ancestor}
|
|
inherited Create;
|
|
|
|
{we're not ready for decryption yet since a header hasn't been
|
|
properly verified with VerifyHeader}
|
|
FReady := false;
|
|
end;
|
|
{--------}
|
|
function TAbZipDecryptEngine.Decode(aCh : byte) : byte;
|
|
var
|
|
Temp : longint;
|
|
begin
|
|
{check for programming error}
|
|
Assert(FReady,
|
|
'TAbZipDecryptEngine.Decode: must successfully call VerifyHeader first');
|
|
|
|
{calculate the decoded byte (uses inlined decrypt_byte)}
|
|
Temp := (FState[2] and $FFFF) or 2;
|
|
Result := aCh xor ((Temp * (Temp xor 1)) shr 8);
|
|
|
|
{mix the decoded byte into the state (uses inlined update_keys)}
|
|
FState[0] := AbUpdateCrc32(Result, FState[0]);
|
|
FState[1] := FState[1] + (FState[0] and $FF);
|
|
FState[1] := (FState[1] * MagicNumber) + 1;
|
|
FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]);
|
|
end;
|
|
{--------}
|
|
procedure TAbZipDecryptEngine.DecodeBuffer(var aBuffer; aCount : integer);
|
|
var
|
|
i : integer;
|
|
Temp : longint;
|
|
Buffer : PAnsiChar;
|
|
WorkState : array [0..2] of longint;
|
|
begin
|
|
{check for programming error}
|
|
Assert(FReady,
|
|
'TAbZipDecryptEngine.Decode: must successfully call VerifyHeader first');
|
|
|
|
{move the state to a local variable--for better speed}
|
|
WorkState[0] := FState[0];
|
|
WorkState[1] := FState[1];
|
|
WorkState[2] := FState[2];
|
|
|
|
{reference the buffer as a PChar--easier arithmetic}
|
|
Buffer := @aBuffer;
|
|
|
|
{for each byte in the buffer...}
|
|
for i := 0 to pred(aCount) do begin
|
|
|
|
{calculate the next decoded byte (uses inlined decrypt_byte)}
|
|
Temp := (WorkState[2] and $FFFF) or 2;
|
|
Buffer^ := AnsiChar(
|
|
byte(Buffer^) xor ((Temp * (Temp xor 1)) shr 8));
|
|
|
|
{mix the decoded byte into the state (uses inlined update_keys)}
|
|
WorkState[0] := AbUpdateCrc32(byte(Buffer^), WorkState[0]);
|
|
WorkState[1] := WorkState[1] + (WorkState[0] and $FF);
|
|
WorkState[1] := (WorkState[1] * MagicNumber) + 1;
|
|
WorkState[2] := AbUpdateCrc32(WorkState[1] shr 24, WorkState[2]);
|
|
|
|
{move onto the next byte}
|
|
inc(Buffer);
|
|
end;
|
|
|
|
{save the state}
|
|
FState[0] := WorkState[0];
|
|
FState[1] := WorkState[1];
|
|
FState[2] := WorkState[2];
|
|
end;
|
|
{--------}
|
|
function TAbZipDecryptEngine.VerifyHeader(const aHeader : TAbZipEncryptHeader;
|
|
const aPassphrase : AnsiString;
|
|
aCheckValue : longint) : boolean;
|
|
type
|
|
TLongAsBytes = packed record
|
|
L1, L2, L3, L4 : byte
|
|
end;
|
|
var
|
|
i : integer;
|
|
Temp : longint;
|
|
WorkHeader : TAbZipEncryptHeader;
|
|
begin
|
|
{check for programming errors}
|
|
Assert(aPassphrase <> '',
|
|
'TAbZipDecryptEngine.VerifyHeader: need a passphrase');
|
|
|
|
{initialize the decryption state}
|
|
zdeInitState(aPassphrase);
|
|
|
|
{decrypt the bytes in the header}
|
|
for i := 0 to 11 do begin
|
|
|
|
{calculate the next decoded byte (uses inlined decrypt_byte)}
|
|
Temp := (FState[2] and $FFFF) or 2;
|
|
WorkHeader[i] := aHeader[i] xor ((Temp * (Temp xor 1)) shr 8);
|
|
|
|
{mix the decoded byte into the state (uses inlined update_keys)}
|
|
FState[0] := AbUpdateCrc32(WorkHeader[i], FState[0]);
|
|
FState[1] := FState[1] + (FState[0] and $FF);
|
|
FState[1] := (FState[1] * MagicNumber) + 1;
|
|
FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]);
|
|
end;
|
|
|
|
{the header is valid if the twelfth byte of the decrypted header
|
|
equals the fourth byte of the check value}
|
|
Result := WorkHeader[11] = TLongAsBytes(aCheckValue).L4;
|
|
|
|
{note: zips created with PKZIP prior to version 2.0 also checked
|
|
that the tenth byte of the decrypted header equals the third
|
|
byte of the check value}
|
|
FReady := Result;
|
|
end;
|
|
{--------}
|
|
procedure TAbZipDecryptEngine.zdeInitState(const aPassphrase : AnsiString);
|
|
var
|
|
i : integer;
|
|
begin
|
|
{initialize the decryption state}
|
|
FState[0] := StateInit1;
|
|
FState[1] := StateInit2;
|
|
FState[2] := StateInit3;
|
|
|
|
{mix in the passphrase to the state (uses inlined update_keys)}
|
|
for i := 1 to length(aPassphrase) do begin
|
|
FState[0] := AbUpdateCrc32(byte(aPassphrase[i]), FState[0]);
|
|
FState[1] := FState[1] + (FState[0] and $FF);
|
|
FState[1] := (FState[1] * MagicNumber) + 1;
|
|
FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]);
|
|
end;
|
|
end;
|
|
{====================================================================}
|
|
|
|
|
|
{====================================================================}
|
|
constructor TAbDfDecryptStream.Create(aStream : TStream;
|
|
aCheckValue : longint;
|
|
const aPassphrase : AnsiString);
|
|
begin
|
|
{create the ancestor}
|
|
inherited Create;
|
|
|
|
{save the parameters}
|
|
FStream := aStream;
|
|
FCheckValue := aCheckValue;
|
|
FPassphrase := aPassphrase;
|
|
|
|
{create the decryption engine}
|
|
FEngine := TAbZipDecryptEngine.Create;
|
|
end;
|
|
{--------}
|
|
destructor TAbDfDecryptStream.Destroy; {new !!.02}
|
|
begin
|
|
FEngine.Free;
|
|
if FOwnsStream then
|
|
FStream.Free;
|
|
inherited Destroy;
|
|
end;
|
|
{--------}
|
|
function TAbDfDecryptStream.IsValid : boolean;
|
|
var
|
|
Header : TAbZipEncryptHeader;
|
|
begin
|
|
{read the header from the stream}
|
|
FStream.ReadBuffer(Header, sizeof(Header));
|
|
|
|
{check to see if the decryption engine agrees it's valid}
|
|
Result := FEngine.VerifyHeader(Header, FPassphrase, FCheckValue);
|
|
|
|
{if it isn't valid, reposition the stream, ready for the next try}
|
|
if not Result then begin
|
|
FStream.Seek(-sizeof(Header), soCurrent);
|
|
FReady := false;
|
|
end
|
|
|
|
{otherwise, the stream is ready for decrypting data}
|
|
else
|
|
FReady := true;
|
|
end;
|
|
{--------}
|
|
function TAbDfDecryptStream.Read(var aBuffer; aCount : longint) : longint;
|
|
begin
|
|
{check for programming error}
|
|
Assert(FReady,
|
|
'TAbDfDecryptStream.Read: the stream header has not been verified');
|
|
|
|
{read the data from the underlying stream}
|
|
Result := FStream.Read(aBuffer, aCount);
|
|
|
|
{decrypt the data}
|
|
FEngine.DecodeBuffer(aBuffer, Result);
|
|
end;
|
|
{--------}
|
|
function TAbDfDecryptStream.Seek(aOffset : longint; aOrigin : word) : longint;
|
|
begin
|
|
Result := FStream.Seek(aOffset, aOrigin);
|
|
end;
|
|
{--------}
|
|
function TAbDfDecryptStream.Write(const aBuffer; aCount : longint) : longint;
|
|
begin
|
|
{check for programming error}
|
|
Assert(false,
|
|
'TAbDfDecryptStream.Write: the stream is read-only');
|
|
Result := 0;
|
|
end;
|
|
{====================================================================}
|
|
|
|
|
|
{===TAbZipEncryptEngine==============================================}
|
|
constructor TAbZipEncryptEngine.Create;
|
|
begin
|
|
{create the ancestor}
|
|
inherited Create;
|
|
|
|
{we're not ready for encryption yet since a header hasn't been
|
|
properly generated with CreateHeader}
|
|
FReady := false;
|
|
end;
|
|
{--------}
|
|
procedure TAbZipEncryptEngine.CreateHeader(
|
|
var aHeader : TAbZipEncryptHeader;
|
|
const aPassphrase : AnsiString;
|
|
aCheckValue : longint);
|
|
type
|
|
TLongAsBytes = packed record
|
|
L1, L2, L3, L4 : byte
|
|
end;
|
|
var
|
|
Ch : byte;
|
|
i : integer;
|
|
Temp : longint;
|
|
WorkHeader : TAbZipEncryptHeader;
|
|
begin
|
|
{check for programming errors}
|
|
Assert(aPassphrase <> '',
|
|
'TAbZipEncryptEngine.CreateHeader: need a passphrase');
|
|
|
|
{set the first ten bytes of the header with random values (in fact,
|
|
we use a random value for each byte and mix it in with the state)}
|
|
|
|
{initialize the decryption state}
|
|
zeeInitState(aPassphrase);
|
|
|
|
{for the first ten bytes...}
|
|
for i := 0 to 9 do begin
|
|
|
|
{get a random value}
|
|
Ch := Random( 256 );
|
|
|
|
{calculate the XOR encoding byte (uses inlined decrypt_byte)}
|
|
Temp := (FState[2] and $FFFF) or 2;
|
|
Temp := (Temp * (Temp xor 1)) shr 8;
|
|
|
|
{mix the unencoded byte into the state (uses inlined update_keys)}
|
|
FState[0] := AbUpdateCrc32(Ch, FState[0]);
|
|
FState[1] := FState[1] + (FState[0] and $FF);
|
|
FState[1] := (FState[1] * MagicNumber) + 1;
|
|
FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]);
|
|
|
|
{set the current byte of the header}
|
|
WorkHeader[i] := Ch xor Temp;
|
|
end;
|
|
|
|
{now encrypt the first ten bytes of the header (this merely sets up
|
|
the state so that we can encrypt the last two bytes)}
|
|
|
|
{reinitialize the decryption state}
|
|
zeeInitState(aPassphrase);
|
|
|
|
{for the first ten bytes...}
|
|
for i := 0 to 9 do begin
|
|
|
|
{calculate the XOR encoding byte (uses inlined decrypt_byte)}
|
|
Temp := (FState[2] and $FFFF) or 2;
|
|
Temp := (Temp * (Temp xor 1)) shr 8;
|
|
|
|
{mix the unencoded byte into the state (uses inlined update_keys)}
|
|
FState[0] := AbUpdateCrc32(WorkHeader[i], FState[0]);
|
|
FState[1] := FState[1] + (FState[0] and $FF);
|
|
FState[1] := (FState[1] * MagicNumber) + 1;
|
|
FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]);
|
|
|
|
{set the current byte of the header}
|
|
WorkHeader[i] := WorkHeader[i] xor Temp;
|
|
end;
|
|
|
|
{now initialize byte 10 of the header, and encrypt it}
|
|
Ch := TLongAsBytes(aCheckValue).L3;
|
|
Temp := (FState[2] and $FFFF) or 2;
|
|
Temp := (Temp * (Temp xor 1)) shr 8;
|
|
FState[0] := AbUpdateCrc32(Ch, FState[0]);
|
|
FState[1] := FState[1] + (FState[0] and $FF);
|
|
FState[1] := (FState[1] * MagicNumber) + 1;
|
|
FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]);
|
|
WorkHeader[10] := Ch xor Temp;
|
|
|
|
{now initialize byte 11 of the header, and encrypt it}
|
|
Ch := TLongAsBytes(aCheckValue).L4;
|
|
Temp := (FState[2] and $FFFF) or 2;
|
|
Temp := (Temp * (Temp xor 1)) shr 8;
|
|
FState[0] := AbUpdateCrc32(Ch, FState[0]);
|
|
FState[1] := FState[1] + (FState[0] and $FF);
|
|
FState[1] := (FState[1] * MagicNumber) + 1;
|
|
FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]);
|
|
WorkHeader[11] := Ch xor Temp;
|
|
|
|
{we're now ready to encrypt}
|
|
FReady := true;
|
|
|
|
{return the header}
|
|
aHeader := WorkHeader;
|
|
end;
|
|
{--------}
|
|
function TAbZipEncryptEngine.Encode(aCh : byte) : byte;
|
|
var
|
|
Temp : longint;
|
|
begin
|
|
{check for programming error}
|
|
Assert(FReady,
|
|
'TAbZipEncryptEngine.Encode: must call CreateHeader first');
|
|
|
|
{calculate the encoded byte (uses inlined decrypt_byte)}
|
|
Temp := (FState[2] and $FFFF) or 2;
|
|
Result := aCh xor (Temp * (Temp xor 1)) shr 8;
|
|
|
|
{mix the unencoded byte into the state (uses inlined update_keys)}
|
|
FState[0] := AbUpdateCrc32(aCh, FState[0]);
|
|
FState[1] := FState[1] + (FState[0] and $FF);
|
|
FState[1] := (FState[1] * MagicNumber) + 1;
|
|
FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]);
|
|
end;
|
|
{--------}
|
|
procedure TAbZipEncryptEngine.EncodeBuffer(var aBuffer; aCount : integer);
|
|
var
|
|
Ch : byte;
|
|
i : integer;
|
|
Temp : longint;
|
|
Buffer : PAnsiChar;
|
|
WorkState : array [0..2] of longint;
|
|
begin
|
|
{check for programming error}
|
|
Assert(FReady,
|
|
'TAbZipEncryptEngine.EncodeBuffer: must call CreateHeader first');
|
|
|
|
{move the state to a local variable--for better speed}
|
|
WorkState[0] := FState[0];
|
|
WorkState[1] := FState[1];
|
|
WorkState[2] := FState[2];
|
|
|
|
{reference the buffer as a PChar--easier arithmetic}
|
|
Buffer := @aBuffer;
|
|
|
|
{for each byte in the buffer...}
|
|
for i := 0 to pred(aCount) do begin
|
|
|
|
{calculate the next encoded byte (uses inlined decrypt_byte)}
|
|
Temp := (WorkState[2] and $FFFF) or 2;
|
|
Ch := byte(Buffer^);
|
|
Buffer^ := AnsiChar(Ch xor ((Temp * (Temp xor 1)) shr 8));
|
|
|
|
{mix the decoded byte into the state (uses inlined update_keys)}
|
|
WorkState[0] := AbUpdateCrc32(Ch, WorkState[0]);
|
|
WorkState[1] := WorkState[1] + (WorkState[0] and $FF);
|
|
WorkState[1] := (WorkState[1] * MagicNumber) + 1;
|
|
WorkState[2] := AbUpdateCrc32(WorkState[1] shr 24, WorkState[2]);
|
|
|
|
{move onto the next byte}
|
|
inc(Buffer);
|
|
end;
|
|
|
|
{save the state}
|
|
FState[0] := WorkState[0];
|
|
FState[1] := WorkState[1];
|
|
FState[2] := WorkState[2];
|
|
end;
|
|
{--------}
|
|
procedure TAbZipEncryptEngine.zeeInitState(const aPassphrase : AnsiString);
|
|
var
|
|
i : integer;
|
|
begin
|
|
{initialize the decryption state}
|
|
FState[0] := StateInit1;
|
|
FState[1] := StateInit2;
|
|
FState[2] := StateInit3;
|
|
|
|
{mix in the passphrase to the state (uses inlined update_keys)}
|
|
for i := 1 to length(aPassphrase) do begin
|
|
FState[0] := AbUpdateCrc32(byte(aPassphrase[i]), FState[0]);
|
|
FState[1] := FState[1] + (FState[0] and $FF);
|
|
FState[1] := (FState[1] * MagicNumber) + 1;
|
|
FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]);
|
|
end;
|
|
end;
|
|
{====================================================================}
|
|
|
|
|
|
{===TAbDfEncryptStream===============================================}
|
|
constructor TAbDfEncryptStream.Create(aStream : TStream;
|
|
aCheckValue : longint;
|
|
const aPassphrase : AnsiString);
|
|
var
|
|
Header : TAbZipEncryptHeader;
|
|
begin
|
|
{create the ancestor}
|
|
inherited Create;
|
|
|
|
{save the stream parameter}
|
|
FStream := aStream;
|
|
|
|
{create the encryption engine}
|
|
FEngine := TAbZipEncryptEngine.Create;
|
|
|
|
{generate the encryption header, write it to the stream}
|
|
FEngine.CreateHeader(Header, aPassphrase, aCheckValue);
|
|
aStream.WriteBuffer(Header, sizeof(Header));
|
|
end;
|
|
{--------}
|
|
destructor TAbDfEncryptStream.Destroy;
|
|
begin
|
|
{free the internal buffer if used}
|
|
if (FBuffer <> nil) then
|
|
FreeMem(FBuffer);
|
|
|
|
{free the engine}
|
|
FEngine.Free;
|
|
|
|
{destroy the ancestor}
|
|
inherited Destroy;
|
|
end;
|
|
{--------}
|
|
function TAbDfEncryptStream.Read(var aBuffer; aCount : longint) : longint;
|
|
begin
|
|
{check for programming error}
|
|
Assert(false,
|
|
'TAbDfEncryptStream.Read: the stream is write-only');
|
|
Result := 0;
|
|
end;
|
|
{--------}
|
|
function TAbDfEncryptStream.Seek(aOffset : longint; aOrigin : word) : longint;
|
|
begin
|
|
Result := FStream.Seek(aOffset, aOrigin);
|
|
end;
|
|
{--------}
|
|
function TAbDfEncryptStream.Write(const aBuffer; aCount : longint) : longint;
|
|
begin
|
|
{note: since we cannot alter a const parameter, we should copy the
|
|
data to our own buffer, encrypt it and then write it}
|
|
|
|
{check that our buffer is large enough}
|
|
if (FBufSize < aCount) then begin
|
|
if (FBuffer <> nil) then
|
|
FreeMem(FBuffer);
|
|
GetMem(FBuffer, aCount);
|
|
FBufSize := aCount;
|
|
end;
|
|
|
|
{copy the data to our buffer}
|
|
Move(aBuffer, FBuffer^, aCount);
|
|
|
|
{encrypt the data in our buffer}
|
|
FEngine.EncodeBuffer(FBuffer^, aCount);
|
|
|
|
{write the data in our buffer to the underlying stream}
|
|
Result := FStream.Write(FBuffer^, aCount);
|
|
end;
|
|
{====================================================================}
|
|
|
|
|
|
end.
|
|
|
|
|
|
|