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.
 | |
| 
 | |
| 
 | |
| 
 |