IdBlockCipherIntercept.pas 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.4 5/12/2003 12:30:58 AM GGrieve
  18. Get compiling again with DotNet Changes
  19. Rev 1.3 10/12/2003 1:49:26 PM BGooijen
  20. Changed comment of last checkin
  21. Rev 1.2 10/12/2003 1:43:24 PM BGooijen
  22. Changed IdCompilerDefines.inc to Core\IdCompilerDefines.inc
  23. Rev 1.0 11/14/2002 02:13:56 PM JPMugaas
  24. }
  25. unit IdBlockCipherIntercept;
  26. {
  27. UnitName: IdBlockCipherIntercept
  28. Author: Andrew P.Rybin [[email protected]]
  29. Creation: 27.02.2002
  30. Version: 0.9.0b
  31. Purpose: Secure communications
  32. }
  33. interface
  34. {$i IdCompilerDefines.inc}
  35. uses
  36. Classes,
  37. IdGlobal,
  38. IdException,
  39. IdResourceStringsProtocols,
  40. IdIntercept;
  41. const
  42. IdBlockCipherBlockSizeDefault = 16;
  43. IdBlockCipherBlockSizeMax = 256;
  44. // why 256? not any block ciphers that can - or should - be used beyond this
  45. // length. You can extend this if you like. But the longer it is, the
  46. // more network traffic is wasted
  47. //256, as currently the last byte of the block is used to store the block size
  48. type
  49. TIdBlockCipherIntercept = class;
  50. // OnSend and OnRecieve Events will always be called with a blockSize Data
  51. TIdBlockCipherIntercept = class(TIdConnectionIntercept)
  52. protected
  53. FBlockSize: Integer;
  54. FIncoming : TIdBytes;
  55. procedure Decrypt (var VData : TIdBytes); virtual;
  56. procedure Encrypt (var VData : TIdBytes); virtual;
  57. procedure SetBlockSize(const Value: Integer);
  58. public
  59. constructor Create(AOwner: TComponent); override;
  60. procedure Receive(var VBuffer: TIdBytes); override; //Decrypt
  61. procedure Send(var VBuffer: TIdBytes); override; //Encrypt
  62. procedure CopySettingsFrom (ASrcBlockCipherIntercept: TIdBlockCipherIntercept); // warning: copies Data too
  63. published
  64. property BlockSize: Integer read FBlockSize write SetBlockSize default IdBlockCipherBlockSizeDefault;
  65. end;
  66. TIdServerBlockCipherIntercept = class(TIdServerIntercept)
  67. protected
  68. FBlockSize: Integer;
  69. public
  70. constructor Create(AOwner: TComponent); override;
  71. procedure Init; override;
  72. function Accept(AConnection: TComponent): TIdConnectionIntercept; override;
  73. published
  74. property BlockSize: Integer read FBlockSize write FBlockSize default IdBlockCipherBlockSizeDefault;
  75. end;
  76. EIdBlockCipherInterceptException = EIdException; {block length}
  77. implementation
  78. uses
  79. IdResourceStrings,
  80. SysUtils;
  81. { TIdBlockCipherIntercept }
  82. constructor TIdBlockCipherIntercept.Create(AOwner: TComponent);
  83. begin
  84. inherited Create(AOwner);
  85. FBlockSize := IdBlockCipherBlockSizeDefault;
  86. SetLength(FIncoming, 0);
  87. end;
  88. //const
  89. // bitLongTail = $80; //future: for IdBlockCipherBlockSizeMax>256
  90. procedure TIdBlockCipherIntercept.Encrypt(var VData : TIdBytes);
  91. begin
  92. if Assigned(FOnSend) then begin
  93. FOnSend(Self, VData);
  94. end;//ex: EncryptAES(LTempIn, ExpandedKey, LTempOut);
  95. end;
  96. procedure TIdBlockCipherIntercept.Decrypt(var VData : TIdBytes);
  97. Begin
  98. if Assigned(FOnReceive) then begin
  99. FOnReceive(Self, VData);
  100. end;//ex: DecryptAES(LTempIn, ExpandedKey, LTempOut);
  101. end;
  102. procedure TIdBlockCipherIntercept.Send(var VBuffer: TIdBytes);
  103. var
  104. LSrc, LBlock : TIdBytes;
  105. LSize, LCount, LMaxDataSize: Integer;
  106. LCompleteBlocks, LRemaining: Integer;
  107. begin
  108. LSrc := nil; // keep the compiler happy
  109. LSize := Length(VBuffer);
  110. if LSize > 0 then begin
  111. LSrc := VBuffer;
  112. LMaxDataSize := FBlockSize - 1;
  113. SetLength(VBuffer, ((LSize + LMaxDataSize - 1) div LMaxDataSize) * FBlockSize);
  114. SetLength(LBlock, FBlockSize);
  115. LCompleteBlocks := LSize div LMaxDataSize;
  116. LRemaining := LSize mod LMaxDataSize;
  117. //process all complete blocks
  118. for LCount := 0 to LCompleteBlocks-1 do
  119. begin
  120. CopyTIdBytes(LSrc, LCount * LMaxDataSize, LBlock, 0, LMaxDataSize);
  121. LBlock[LMaxDataSize] := LMaxDataSize;
  122. Encrypt(LBlock);
  123. CopyTIdBytes(LBlock, 0, VBuffer, LCount * FBlockSize, FBlockSize);
  124. end;
  125. //process the possible remaining bytes, ie less than a full block
  126. if LRemaining > 0 then
  127. begin
  128. CopyTIdBytes(LSrc, LSize - LRemaining, LBlock, 0, LRemaining);
  129. LBlock[LMaxDataSize] := LRemaining;
  130. Encrypt(LBlock);
  131. CopyTIdBytes(LBlock, 0, VBuffer, Length(VBuffer) - FBlockSize, FBlockSize);
  132. end;
  133. end;
  134. // let the next Intercept in the chain encode its data next
  135. // RLebeau: DO NOT call inherited! It will trigger the OnSend event
  136. // again with the entire altered buffer as input, which can cause user
  137. // code to re-encrypt the already-encrypted data. We do not want that
  138. // here! Just call the next Intercept directly...
  139. //inherited Send(VBuffer);
  140. if Intercept <> nil then begin
  141. Intercept.Send(VBuffer);
  142. end;
  143. end;
  144. procedure TIdBlockCipherIntercept.Receive(var VBuffer: TIdBytes);
  145. var
  146. LBlock : TIdBytes;
  147. LSize, LCount, LPos, LMaxDataSize, LCompleteBlocks: Integer;
  148. LRemaining: Integer;
  149. begin
  150. // let the next Intercept in the chain decode its data first
  151. // RLebeau: DO NOT call inherited! It will trigger the OnReceive event
  152. // with the entire decoded buffer as input, which can cause user
  153. // code to decrypt data prematurely/incorrectly. We do not want that
  154. // here! Just call the next Intercept directly...
  155. //inherited Receive(VBuffer);
  156. if Intercept <> nil then begin
  157. Intercept.Receive(VBuffer);
  158. end;
  159. LPos := 0;
  160. AppendBytes(FIncoming, VBuffer);
  161. LSize := Length(FIncoming);
  162. if LSize >= FBlockSize then
  163. begin
  164. // the length of ABuffer when we have finished is currently unknown, but must be less than
  165. // the length of FIncoming. We will reserve this much, then reallocate at the end
  166. SetLength(VBuffer, LSize);
  167. SetLength(LBlock, FBlockSize);
  168. LMaxDataSize := FBlockSize - 1;
  169. LCompleteBlocks := LSize div FBlockSize;
  170. LRemaining := LSize mod FBlockSize;
  171. for LCount := 0 to LCompleteBlocks-1 do
  172. begin
  173. CopyTIdBytes(FIncoming, LCount * FBlockSize, LBlock, 0, FBlockSize);
  174. Decrypt(LBlock);
  175. if (LBlock[LMaxDataSize] = 0) or (LBlock[LMaxDataSize] >= FBlockSize) then begin
  176. raise EIdBlockCipherInterceptException.CreateFmt(RSBlockIncorrectLength, [LBlock[LMaxDataSize]]);
  177. end;
  178. CopyTIdBytes(LBlock, 0, VBuffer, LPos, LBlock[LMaxDataSize]);
  179. Inc(LPos, LBlock[LMaxDataSize]);
  180. end;
  181. if LRemaining > 0 then begin
  182. CopyTIdBytes(FIncoming, LSize - LRemaining, FIncoming, 0, LRemaining);
  183. end;
  184. SetLength(FIncoming, LRemaining);
  185. end;
  186. SetLength(VBuffer, LPos);
  187. end;
  188. procedure TIdBlockCipherIntercept.CopySettingsFrom(ASrcBlockCipherIntercept: TIdBlockCipherIntercept);
  189. Begin
  190. FBlockSize := ASrcBlockCipherIntercept.FBlockSize;
  191. FDataObject := ASrcBlockCipherIntercept.FDataObject;
  192. FDataValue := ASrcBlockCipherIntercept.FDataValue;
  193. FOnConnect := ASrcBlockCipherIntercept.FOnConnect;
  194. FOnDisconnect:= ASrcBlockCipherIntercept.FOnDisconnect;
  195. FOnReceive := ASrcBlockCipherIntercept.FOnReceive;
  196. FOnSend := ASrcBlockCipherIntercept.FOnSend;
  197. end;
  198. procedure TIdBlockCipherIntercept.SetBlockSize(const Value: Integer);
  199. Begin
  200. if (Value > 0) and (Value <= IdBlockCipherBlockSizeMax) then begin
  201. FBlockSize := Value;
  202. end;
  203. end;
  204. { TIdServerBlockCipherIntercept }
  205. constructor TIdServerBlockCipherIntercept.Create(AOwner: TComponent);
  206. begin
  207. inherited Create(AOwner);
  208. FBlockSize := IdBlockCipherBlockSizeDefault;
  209. end;
  210. procedure TIdServerBlockCipherIntercept.Init;
  211. begin
  212. end;
  213. function TIdServerBlockCipherIntercept.Accept(AConnection: TComponent): TIdConnectionIntercept;
  214. begin
  215. Result := TIdBlockCipherIntercept.Create(nil);
  216. TIdBlockCipherIntercept(Result).BlockSize := BlockSize;
  217. end;
  218. end.