IdBlockCipherIntercept.pas 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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. procedure InitComponent; override;
  59. public
  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. procedure InitComponent; override;
  70. public
  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. //const
  83. // bitLongTail = $80; //future: for IdBlockCipherBlockSizeMax>256
  84. procedure TIdBlockCipherIntercept.Encrypt(var VData : TIdBytes);
  85. begin
  86. if Assigned(FOnSend) then begin
  87. FOnSend(Self, VData);
  88. end;//ex: EncryptAES(LTempIn, ExpandedKey, LTempOut);
  89. end;
  90. procedure TIdBlockCipherIntercept.Decrypt(var VData : TIdBytes);
  91. Begin
  92. if Assigned(FOnReceive) then begin
  93. FOnReceive(Self, VData);
  94. end;//ex: DecryptAES(LTempIn, ExpandedKey, LTempOut);
  95. end;
  96. procedure TIdBlockCipherIntercept.Send(var VBuffer: TIdBytes);
  97. var
  98. LSrc, LBlock : TIdBytes;
  99. LSize, LCount, LMaxDataSize: Integer;
  100. LCompleteBlocks, LRemaining: Integer;
  101. begin
  102. LSrc := nil; // keep the compiler happy
  103. LSize := Length(VBuffer);
  104. if LSize > 0 then begin
  105. LSrc := VBuffer;
  106. LMaxDataSize := FBlockSize - 1;
  107. SetLength(VBuffer, ((LSize + LMaxDataSize - 1) div LMaxDataSize) * FBlockSize);
  108. SetLength(LBlock, FBlockSize);
  109. LCompleteBlocks := LSize div LMaxDataSize;
  110. LRemaining := LSize mod LMaxDataSize;
  111. //process all complete blocks
  112. for LCount := 0 to LCompleteBlocks-1 do
  113. begin
  114. CopyTIdBytes(LSrc, LCount * LMaxDataSize, LBlock, 0, LMaxDataSize);
  115. LBlock[LMaxDataSize] := LMaxDataSize;
  116. Encrypt(LBlock);
  117. CopyTIdBytes(LBlock, 0, VBuffer, LCount * FBlockSize, FBlockSize);
  118. end;
  119. //process the possible remaining bytes, ie less than a full block
  120. if LRemaining > 0 then
  121. begin
  122. CopyTIdBytes(LSrc, LSize - LRemaining, LBlock, 0, LRemaining);
  123. LBlock[LMaxDataSize] := LRemaining;
  124. Encrypt(LBlock);
  125. CopyTIdBytes(LBlock, 0, VBuffer, Length(VBuffer) - FBlockSize, FBlockSize);
  126. end;
  127. end;
  128. // let the next Intercept in the chain encode its data next
  129. // RLebeau: DO NOT call inherited! It will trigger the OnSend event
  130. // again with the entire altered buffer as input, which can cause user
  131. // code to re-encrypt the already-encrypted data. We do not want that
  132. // here! Just call the next Intercept directly...
  133. //inherited Send(VBuffer);
  134. if Intercept <> nil then begin
  135. Intercept.Send(VBuffer);
  136. end;
  137. end;
  138. procedure TIdBlockCipherIntercept.Receive(var VBuffer: TIdBytes);
  139. var
  140. LBlock : TIdBytes;
  141. LSize, LCount, LPos, LMaxDataSize, LCompleteBlocks: Integer;
  142. LRemaining: Integer;
  143. begin
  144. // let the next Intercept in the chain decode its data first
  145. // RLebeau: DO NOT call inherited! It will trigger the OnReceive event
  146. // with the entire decoded buffer as input, which can cause user
  147. // code to decrypt data prematurely/incorrectly. We do not want that
  148. // here! Just call the next Intercept directly...
  149. //inherited Receive(VBuffer);
  150. if Intercept <> nil then begin
  151. Intercept.Receive(VBuffer);
  152. end;
  153. LPos := 0;
  154. AppendBytes(FIncoming, VBuffer);
  155. LSize := Length(FIncoming);
  156. if LSize >= FBlockSize then
  157. begin
  158. // the length of ABuffer when we have finished is currently unknown, but must be less than
  159. // the length of FIncoming. We will reserve this much, then reallocate at the end
  160. SetLength(VBuffer, LSize);
  161. SetLength(LBlock, FBlockSize);
  162. LMaxDataSize := FBlockSize - 1;
  163. LCompleteBlocks := LSize div FBlockSize;
  164. LRemaining := LSize mod FBlockSize;
  165. for LCount := 0 to LCompleteBlocks-1 do
  166. begin
  167. CopyTIdBytes(FIncoming, LCount * FBlockSize, LBlock, 0, FBlockSize);
  168. Decrypt(LBlock);
  169. if (LBlock[LMaxDataSize] = 0) or (LBlock[LMaxDataSize] >= FBlockSize) then begin
  170. raise EIdBlockCipherInterceptException.CreateFmt(RSBlockIncorrectLength, [LBlock[LMaxDataSize]]);
  171. end;
  172. CopyTIdBytes(LBlock, 0, VBuffer, LPos, LBlock[LMaxDataSize]);
  173. Inc(LPos, LBlock[LMaxDataSize]);
  174. end;
  175. if LRemaining > 0 then begin
  176. CopyTIdBytes(FIncoming, LSize - LRemaining, FIncoming, 0, LRemaining);
  177. end;
  178. SetLength(FIncoming, LRemaining);
  179. end;
  180. SetLength(VBuffer, LPos);
  181. end;
  182. procedure TIdBlockCipherIntercept.CopySettingsFrom(ASrcBlockCipherIntercept: TIdBlockCipherIntercept);
  183. Begin
  184. FBlockSize := ASrcBlockCipherIntercept.FBlockSize;
  185. {$IFDEF USE_OBJECT_ARC}
  186. FDataObject := ASrcBlockCipherIntercept.FDataObject;
  187. FDataValue := ASrcBlockCipherIntercept.FDataValue;
  188. {$ELSE}
  189. FData := ASrcBlockCipherIntercept.FData; // not sure that this is actually safe
  190. {$ENDIF}
  191. FOnConnect := ASrcBlockCipherIntercept.FOnConnect;
  192. FOnDisconnect:= ASrcBlockCipherIntercept.FOnDisconnect;
  193. FOnReceive := ASrcBlockCipherIntercept.FOnReceive;
  194. FOnSend := ASrcBlockCipherIntercept.FOnSend;
  195. end;
  196. procedure TIdBlockCipherIntercept.SetBlockSize(const Value: Integer);
  197. Begin
  198. if (Value > 0) and (Value <= IdBlockCipherBlockSizeMax) then begin
  199. FBlockSize := Value;
  200. end;
  201. end;
  202. procedure TIdBlockCipherIntercept.InitComponent;
  203. begin
  204. inherited InitComponent;
  205. FBlockSize := IdBlockCipherBlockSizeDefault;
  206. SetLength(FIncoming, 0);
  207. end;
  208. { TIdServerBlockCipherIntercept }
  209. procedure TIdServerBlockCipherIntercept.InitComponent;
  210. begin
  211. inherited InitComponent;
  212. FBlockSize := IdBlockCipherBlockSizeDefault;
  213. end;
  214. procedure TIdServerBlockCipherIntercept.Init;
  215. begin
  216. end;
  217. function TIdServerBlockCipherIntercept.Accept(AConnection: TComponent): TIdConnectionIntercept;
  218. begin
  219. Result := TIdBlockCipherIntercept.Create(nil);
  220. TIdBlockCipherIntercept(Result).BlockSize := BlockSize;
  221. end;
  222. end.