restemplate/indy/Protocols/IdBlockCipherIntercept.pas

273 lines
8.1 KiB
Plaintext
Raw Permalink Normal View History

{
$Project$
$Workfile$
$Revision$
$DateUTC$
$Id$
This file is part of the Indy (Internet Direct) project, and is offered
under the dual-licensing agreement described on the Indy website.
(http://www.indyproject.org/)
Copyright:
(c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
}
{
$Log$
}
{
Rev 1.4 5/12/2003 12:30:58 AM GGrieve
Get compiling again with DotNet Changes
Rev 1.3 10/12/2003 1:49:26 PM BGooijen
Changed comment of last checkin
Rev 1.2 10/12/2003 1:43:24 PM BGooijen
Changed IdCompilerDefines.inc to Core\IdCompilerDefines.inc
Rev 1.0 11/14/2002 02:13:56 PM JPMugaas
}
unit IdBlockCipherIntercept;
{
UnitName: IdBlockCipherIntercept
Author: Andrew P.Rybin [magicode@mail.ru]
Creation: 27.02.2002
Version: 0.9.0b
Purpose: Secure communications
}
interface
{$i IdCompilerDefines.inc}
uses
Classes,
IdGlobal,
IdException,
IdResourceStringsProtocols,
IdIntercept;
const
IdBlockCipherBlockSizeDefault = 16;
IdBlockCipherBlockSizeMax = 256;
// why 256? not any block ciphers that can - or should - be used beyond this
// length. You can extend this if you like. But the longer it is, the
// more network traffic is wasted
//256, as currently the last byte of the block is used to store the block size
type
TIdBlockCipherIntercept = class;
// OnSend and OnRecieve Events will always be called with a blockSize Data
TIdBlockCipherIntercept = class(TIdConnectionIntercept)
protected
FBlockSize: Integer;
FIncoming : TIdBytes;
procedure Decrypt (var VData : TIdBytes); virtual;
procedure Encrypt (var VData : TIdBytes); virtual;
procedure SetBlockSize(const Value: Integer);
procedure InitComponent; override;
public
procedure Receive(var VBuffer: TIdBytes); override; //Decrypt
procedure Send(var VBuffer: TIdBytes); override; //Encrypt
procedure CopySettingsFrom (ASrcBlockCipherIntercept: TIdBlockCipherIntercept); // warning: copies Data too
published
property BlockSize: Integer read FBlockSize write SetBlockSize default IdBlockCipherBlockSizeDefault;
end;
TIdServerBlockCipherIntercept = class(TIdServerIntercept)
protected
FBlockSize: Integer;
procedure InitComponent; override;
public
procedure Init; override;
function Accept(AConnection: TComponent): TIdConnectionIntercept; override;
published
property BlockSize: Integer read FBlockSize write FBlockSize default IdBlockCipherBlockSizeDefault;
end;
EIdBlockCipherInterceptException = EIdException; {block length}
implementation
uses
IdResourceStrings,
SysUtils;
{ TIdBlockCipherIntercept }
//const
// bitLongTail = $80; //future: for IdBlockCipherBlockSizeMax>256
procedure TIdBlockCipherIntercept.Encrypt(var VData : TIdBytes);
begin
if Assigned(FOnSend) then begin
FOnSend(Self, VData);
end;//ex: EncryptAES(LTempIn, ExpandedKey, LTempOut);
end;
procedure TIdBlockCipherIntercept.Decrypt(var VData : TIdBytes);
Begin
if Assigned(FOnReceive) then begin
FOnReceive(Self, VData);
end;//ex: DecryptAES(LTempIn, ExpandedKey, LTempOut);
end;
procedure TIdBlockCipherIntercept.Send(var VBuffer: TIdBytes);
var
LSrc, LBlock : TIdBytes;
LSize, LCount, LMaxDataSize: Integer;
LCompleteBlocks, LRemaining: Integer;
begin
LSrc := nil; // keep the compiler happy
LSize := Length(VBuffer);
if LSize > 0 then begin
LSrc := VBuffer;
LMaxDataSize := FBlockSize - 1;
SetLength(VBuffer, ((LSize + LMaxDataSize - 1) div LMaxDataSize) * FBlockSize);
SetLength(LBlock, FBlockSize);
LCompleteBlocks := LSize div LMaxDataSize;
LRemaining := LSize mod LMaxDataSize;
//process all complete blocks
for LCount := 0 to LCompleteBlocks-1 do
begin
CopyTIdBytes(LSrc, LCount * LMaxDataSize, LBlock, 0, LMaxDataSize);
LBlock[LMaxDataSize] := LMaxDataSize;
Encrypt(LBlock);
CopyTIdBytes(LBlock, 0, VBuffer, LCount * FBlockSize, FBlockSize);
end;
//process the possible remaining bytes, ie less than a full block
if LRemaining > 0 then
begin
CopyTIdBytes(LSrc, LSize - LRemaining, LBlock, 0, LRemaining);
LBlock[LMaxDataSize] := LRemaining;
Encrypt(LBlock);
CopyTIdBytes(LBlock, 0, VBuffer, Length(VBuffer) - FBlockSize, FBlockSize);
end;
end;
// let the next Intercept in the chain encode its data next
// RLebeau: DO NOT call inherited! It will trigger the OnSend event
// again with the entire altered buffer as input, which can cause user
// code to re-encrypt the already-encrypted data. We do not want that
// here! Just call the next Intercept directly...
//inherited Send(VBuffer);
if Intercept <> nil then begin
Intercept.Send(VBuffer);
end;
end;
procedure TIdBlockCipherIntercept.Receive(var VBuffer: TIdBytes);
var
LBlock : TIdBytes;
LSize, LCount, LPos, LMaxDataSize, LCompleteBlocks: Integer;
LRemaining: Integer;
begin
// let the next Intercept in the chain decode its data first
// RLebeau: DO NOT call inherited! It will trigger the OnReceive event
// with the entire decoded buffer as input, which can cause user
// code to decrypt data prematurely/incorrectly. We do not want that
// here! Just call the next Intercept directly...
//inherited Receive(VBuffer);
if Intercept <> nil then begin
Intercept.Receive(VBuffer);
end;
LPos := 0;
AppendBytes(FIncoming, VBuffer);
LSize := Length(FIncoming);
if LSize >= FBlockSize then
begin
// the length of ABuffer when we have finished is currently unknown, but must be less than
// the length of FIncoming. We will reserve this much, then reallocate at the end
SetLength(VBuffer, LSize);
SetLength(LBlock, FBlockSize);
LMaxDataSize := FBlockSize - 1;
LCompleteBlocks := LSize div FBlockSize;
LRemaining := LSize mod FBlockSize;
for LCount := 0 to LCompleteBlocks-1 do
begin
CopyTIdBytes(FIncoming, LCount * FBlockSize, LBlock, 0, FBlockSize);
Decrypt(LBlock);
if (LBlock[LMaxDataSize] = 0) or (LBlock[LMaxDataSize] >= FBlockSize) then begin
raise EIdBlockCipherInterceptException.CreateFmt(RSBlockIncorrectLength, [LBlock[LMaxDataSize]]);
end;
CopyTIdBytes(LBlock, 0, VBuffer, LPos, LBlock[LMaxDataSize]);
Inc(LPos, LBlock[LMaxDataSize]);
end;
if LRemaining > 0 then begin
CopyTIdBytes(FIncoming, LSize - LRemaining, FIncoming, 0, LRemaining);
end;
SetLength(FIncoming, LRemaining);
end;
SetLength(VBuffer, LPos);
end;
procedure TIdBlockCipherIntercept.CopySettingsFrom(ASrcBlockCipherIntercept: TIdBlockCipherIntercept);
Begin
FBlockSize := ASrcBlockCipherIntercept.FBlockSize;
{$IFDEF USE_OBJECT_ARC}
FDataObject := ASrcBlockCipherIntercept.FDataObject;
FDataValue := ASrcBlockCipherIntercept.FDataValue;
{$ELSE}
FData := ASrcBlockCipherIntercept.FData; // not sure that this is actually safe
{$ENDIF}
FOnConnect := ASrcBlockCipherIntercept.FOnConnect;
FOnDisconnect:= ASrcBlockCipherIntercept.FOnDisconnect;
FOnReceive := ASrcBlockCipherIntercept.FOnReceive;
FOnSend := ASrcBlockCipherIntercept.FOnSend;
end;
procedure TIdBlockCipherIntercept.SetBlockSize(const Value: Integer);
Begin
if (Value > 0) and (Value <= IdBlockCipherBlockSizeMax) then begin
FBlockSize := Value;
end;
end;
procedure TIdBlockCipherIntercept.InitComponent;
begin
inherited InitComponent;
FBlockSize := IdBlockCipherBlockSizeDefault;
SetLength(FIncoming, 0);
end;
{ TIdServerBlockCipherIntercept }
procedure TIdServerBlockCipherIntercept.InitComponent;
begin
inherited InitComponent;
FBlockSize := IdBlockCipherBlockSizeDefault;
end;
procedure TIdServerBlockCipherIntercept.Init;
begin
end;
function TIdServerBlockCipherIntercept.Accept(AConnection: TComponent): TIdConnectionIntercept;
begin
Result := TIdBlockCipherIntercept.Create(nil);
TIdBlockCipherIntercept(Result).BlockSize := BlockSize;
end;
end.