273 lines
8.1 KiB
Plaintext
273 lines
8.1 KiB
Plaintext
{
|
|
$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.
|