فهرست منبع

stream related updates

Ugochukwu Mmaduekwe 2 هفته پیش
والد
کامیت
b21091f3e2

+ 1 - 0
CryptoLib.Tests/Delphi.Tests/CryptoLib.Tests.dpr

@@ -456,6 +456,7 @@ uses
   ClpSpeckEngine in '..\..\CryptoLib\src\Crypto\Engines\ClpSpeckEngine.pas',
   ClpSpeckLegacyEngine in '..\..\CryptoLib\src\Crypto\Engines\ClpSpeckLegacyEngine.pas',
   ClpStreams in '..\..\CryptoLib\src\IO\ClpStreams.pas',
+  ClpStreamUtilities in '..\..\CryptoLib\src\IO\ClpStreamUtilities.pas',
   ClpStringUtils in '..\..\CryptoLib\src\GeneralUtilities\ClpStringUtils.pas',
   ClpSubjectPublicKeyInfoFactory in '..\..\CryptoLib\src\Factories\ClpSubjectPublicKeyInfoFactory.pas',
   ClpTeleTrusTNamedCurves in '..\..\CryptoLib\src\Asn1\TeleTrust\ClpTeleTrusTNamedCurves.pas',

+ 1 - 1
CryptoLib.Tests/src/Asn1/EqualsAndHashCodeTests.pas

@@ -115,7 +115,7 @@ begin
 
   LBOut := TMemoryStream.Create();
    // LeaveOpen is False so TAsn1OutputStream owns LBOut and will free it.
-  LAOut := TAsn1OutputStream.CreateStream(LBOut);
+  LAOut := TAsn1OutputStream.CreateInstance(LBOut);
   try
     for I := 0 to System.Length(LValues) - 1 do
     begin

+ 8 - 7
CryptoLib/src/Asn1/ClpAsn1Objects.pas

@@ -35,6 +35,7 @@ uses
   ClpAsn1Utilities,
   ClpPlatform,
   ClpStreams,
+  ClpStreamUtilities,
   ClpArrayUtils,
   ClpEncoders,
   ClpConverters,
@@ -4833,7 +4834,7 @@ procedure TAsn1Object.EncodeTo(const AOutput: TStream);
 var
   LAsn1Out: TAsn1OutputStream;
 begin
-  LAsn1Out := TAsn1OutputStream.CreateStream(AOutput, TAsn1Encodable.Ber, True);
+  LAsn1Out := TAsn1OutputStream.CreateInstance(AOutput, TAsn1Encodable.Ber, True);
   try
     GetEncoding(LAsn1Out.Encoding).Encode(LAsn1Out);
   finally
@@ -4845,7 +4846,7 @@ procedure TAsn1Object.EncodeTo(const AOutput: TStream; const AEncoding: String);
 var
   LAsn1Out: TAsn1OutputStream;
 begin
-  LAsn1Out := TAsn1OutputStream.CreateStream(AOutput, AEncoding, True);
+  LAsn1Out := TAsn1OutputStream.CreateInstance(AOutput, AEncoding, True);
   try
     GetEncoding(LAsn1Out.Encoding).Encode(LAsn1Out);
   finally
@@ -4863,7 +4864,7 @@ begin
   LAsn1Encoding := GetEncoding(LEncodingType);
   LLength := LAsn1Encoding.GetLength();
   System.SetLength(Result, APreAlloc + LLength + APostAlloc);
-  LAsn1Out := TAsn1OutputStream.CreateStream(Result, APreAlloc, LLength, AEncoding, False);
+  LAsn1Out := TAsn1OutputStream.CreateInstance(Result, APreAlloc, LLength, AEncoding, False);
   try
     LAsn1Encoding.Encode(LAsn1Out);
     // Assert(LAsn1Out.Length = LAsn1Out.Position);
@@ -7544,7 +7545,7 @@ var
 begin
   LBitStream := TAsn1ConstructedBitStream.Create(ASp, False);
   try
-    LData := TStreamUtils.ReadAll(LBitStream);
+    LData := TStreamUtilities.ReadAll(LBitStream);
     LPadBits := LBitStream.PadBits;
     Result := TBerBitString.Create(LData, LPadBits);
   finally
@@ -7581,7 +7582,7 @@ var
 begin
   LOctetStream := TAsn1ConstructedOctetStream.Create(ASp);
   try
-    Result := TBerOctetString.Create(TStreamUtils.ReadAll(LOctetStream));
+    Result := TBerOctetString.Create(TStreamUtilities.ReadAll(LOctetStream));
   finally
     LOctetStream.Free;
   end;
@@ -7866,7 +7867,7 @@ end;
 
 procedure TBerGenerator.WriteBerBody(AContentStream: TStream);
 begin
-  TStreamUtils.PipeAll(AContentStream, &Out);
+  TStreamUtilities.PipeAll(AContentStream, &Out);
 end;
 
 procedure TBerGenerator.WriteBerEnd();
@@ -7992,7 +7993,7 @@ end;
 
 class procedure TDerGenerator.WriteDerEncoded(const AOutStr: TStream; ATag: Int32; const AInStr: TStream);
 begin
-  WriteDerEncoded(AOutStr, ATag, TStreamUtils.ReadAll(AInStr));
+  WriteDerEncoded(AOutStr, ATag, TStreamUtilities.ReadAll(AInStr));
 end;
 
 class procedure TDerGenerator.WriteLength(const AOutStr: TStream; ALength: Int32);

+ 20 - 19
CryptoLib/src/Asn1/ClpAsn1Streams.pas

@@ -29,7 +29,8 @@ uses
   ClpBits,
   ClpPlatform,
   ClpCryptoLibTypes,
-  ClpStreams;
+  ClpStreams,
+  ClpStreamUtilities;
 
 type
   /// <summary>
@@ -161,20 +162,20 @@ type
     /// <summary>
     /// Create an ASN.1 output stream.
     /// </summary>
-    class function CreateStream(const AOutput: TStream): TAsn1OutputStream; overload; static;
+    class function CreateInstance(const AOutput: TStream): TAsn1OutputStream; overload; static;
     /// <summary>
     /// Create an ASN.1 output stream with encoding.
     /// </summary>
-    class function CreateStream(const AOutput: TStream; const AEncoding: String): TAsn1OutputStream; overload; static;
+    class function CreateInstance(const AOutput: TStream; const AEncoding: String): TAsn1OutputStream; overload; static;
     /// <summary>
     /// Create an ASN.1 output stream from byte array.
     /// </summary>
-    class function CreateStream(const ABuffer: TCryptoLibByteArray; AIndex, ACount: Int32; const AEncoding: String; ALeaveOpen: Boolean): TAsn1OutputStream; overload; static;
+    class function CreateInstance(const ABuffer: TCryptoLibByteArray; AIndex, ACount: Int32; const AEncoding: String; ALeaveOpen: Boolean): TAsn1OutputStream; overload; static;
 
     /// <summary>
     /// Create an ASN.1 output stream with encoding and leaveOpen (factory method).
     /// </summary>
-    class function CreateStream(const AOutput: TStream; const AEncoding: String; ALeaveOpen: Boolean): TAsn1OutputStream; overload; static;
+    class function CreateInstance(const AOutput: TStream; const AEncoding: String; ALeaveOpen: Boolean): TAsn1OutputStream; overload; static;
 
     /// <summary>
     /// Destructor.
@@ -602,7 +603,7 @@ begin
       ('corrupted stream - out of bounds length found: %d >= %d',
       [FRemaining, LLimit]);
 
-  FRemaining := FRemaining - TStreamUtils.ReadFully(FIn, ABuf, 0,
+  FRemaining := FRemaining - TStreamUtilities.ReadFully(FIn, ABuf, 0,
     System.Length(ABuf));
   if FRemaining <> 0 then
     raise EEndOfStreamCryptoLibException.CreateFmt
@@ -628,7 +629,7 @@ begin
       [FRemaining, LLimit]);
 
   System.SetLength(Result, FRemaining);
-  FRemaining := FRemaining - TStreamUtils.ReadFully(FIn, Result, 0,
+  FRemaining := FRemaining - TStreamUtilities.ReadFully(FIn, Result, 0,
     System.Length(Result));
   if FRemaining <> 0 then
     raise EEndOfStreamCryptoLibException.CreateFmt
@@ -750,17 +751,17 @@ begin
   inherited Destroy;
 end;
 
-class function TAsn1OutputStream.CreateStream(const AOutput: TStream): TAsn1OutputStream;
+class function TAsn1OutputStream.CreateInstance(const AOutput: TStream): TAsn1OutputStream;
 begin
   Result := TAsn1OutputStream.Create(AOutput, False);
 end;
 
-class function TAsn1OutputStream.CreateStream(const AOutput: TStream; const AEncoding: String): TAsn1OutputStream;
+class function TAsn1OutputStream.CreateInstance(const AOutput: TStream; const AEncoding: String): TAsn1OutputStream;
 begin
-  Result := TAsn1OutputStream.CreateStream(AOutput, AEncoding, False);
+  Result := TAsn1OutputStream.CreateInstance(AOutput, AEncoding, False);
 end;
 
-class function TAsn1OutputStream.CreateStream(const AOutput: TStream; const AEncoding: String; ALeaveOpen: Boolean): TAsn1OutputStream;
+class function TAsn1OutputStream.CreateInstance(const AOutput: TStream; const AEncoding: String; ALeaveOpen: Boolean): TAsn1OutputStream;
 begin
   if SameText(AEncoding, TAsn1Encodable.Der) then
     Result := TAsn1DerOutputStream.Create(AOutput, ALeaveOpen)
@@ -770,9 +771,9 @@ begin
     Result := TAsn1OutputStream.Create(AOutput, ALeaveOpen);
 end;
 
-class function TAsn1OutputStream.CreateStream(const ABuffer: TCryptoLibByteArray; AIndex, ACount: Int32; const AEncoding: String; ALeaveOpen: Boolean): TAsn1OutputStream;
+class function TAsn1OutputStream.CreateInstance(const ABuffer: TCryptoLibByteArray; AIndex, ACount: Int32; const AEncoding: String; ALeaveOpen: Boolean): TAsn1OutputStream;
 begin
-  Result := TAsn1OutputStream.CreateStream(TFixedBufferStream.Create(ABuffer, AIndex, ACount, True), AEncoding, ALeaveOpen);
+  Result := TAsn1OutputStream.CreateInstance(TFixedBufferStream.Create(ABuffer, AIndex, ACount, True), AEncoding, ALeaveOpen);
 end;
 
 procedure TAsn1OutputStream.FlushInternal;
@@ -1025,7 +1026,7 @@ begin
     raise EArgumentNilCryptoLibException.Create('buf');
   FBuf := ABuf;
   FOff := 0;
-  FAsn1Out := TAsn1OutputStream.CreateStream(AOutStream, TAsn1Encodable.Ber, True);
+  FAsn1Out := TAsn1OutputStream.CreateInstance(AOutStream, TAsn1Encodable.Ber, True);
 end;
 
 destructor TAsn1BufferedBerOctetStream.Destroy;
@@ -1048,7 +1049,7 @@ function TAsn1BufferedBerOctetStream.Write(const ABuffer: TCryptoLibByteArray;
 var
   LBufLen, LAvailable, LPos, LRemaining: Int32;
 begin
-  TStreamUtils.ValidateBufferArguments(ABuffer, AOffset, ACount);
+  TStreamUtilities.ValidateBufferArguments(ABuffer, AOffset, ACount);
   LBufLen := System.Length(FBuf);
   LAvailable := LBufLen - FOff;
   
@@ -1165,7 +1166,7 @@ function TAsn1ConstructedBitStream.Read(ABuffer: TCryptoLibByteArray;
 var
   LTotalRead, LNumRead: Int32;
 begin
-  TStreamUtils.ValidateBufferArguments(ABuffer, AOffset, ACount);
+  TStreamUtilities.ValidateBufferArguments(ABuffer, AOffset, ACount);
 
   if ACount < 1 then
   begin
@@ -1319,7 +1320,7 @@ function TAsn1ConstructedOctetStream.Read(ABuffer: TCryptoLibByteArray;
 var
   LTotalRead, LNumRead: Int32;
 begin
-  TStreamUtils.ValidateBufferArguments(ABuffer, AOffset, ACount);
+  TStreamUtilities.ValidateBufferArguments(ABuffer, AOffset, ACount);
 
   if ACount < 1 then
   begin
@@ -1854,7 +1855,7 @@ begin
   // Read in chunks of 8 bytes
   while LRemainingBytes >= 8 do
   begin
-    if TStreamUtils.ReadFully(ADefIn, LBuf, 0, 8) <> 8 then
+    if TStreamUtilities.ReadFully(ADefIn, LBuf, 0, 8) <> 8 then
       raise EEndOfStreamCryptoLibException.Create('EOF encountered in middle of BMPString');
 
     LStr[LStringPos    ] := Char((LBuf[0] shl 8) or (LBuf[1] and $FF));
@@ -1868,7 +1869,7 @@ begin
   // Read remaining bytes
   if LRemainingBytes > 0 then
   begin
-    if TStreamUtils.ReadFully(ADefIn, LBuf, 0, LRemainingBytes) <> LRemainingBytes then
+    if TStreamUtilities.ReadFully(ADefIn, LBuf, 0, LRemainingBytes) <> LRemainingBytes then
       raise EEndOfStreamCryptoLibException.Create('EOF encountered in middle of BMPString');
 
     LBufPos := 0;

+ 2 - 1
CryptoLib/src/Crypto/Parameters/ClpEd25519PrivateKeyParameters.pas

@@ -33,6 +33,7 @@ uses
   ClpArrayUtils,
   ClpAsn1Objects,
   ClpStreams,
+  ClpStreamUtilities,
   ClpCryptoLibTypes;
 
 resourcestring
@@ -122,7 +123,7 @@ begin
   Inherited Create(true);
   System.SetLength(FData, KeySize);
   FEd25519Instance := Ed25519Instance;
-  if (KeySize <> TStreamUtils.ReadFully(input, FData)) then
+  if (KeySize <> TStreamUtilities.ReadFully(input, FData)) then
   begin
     raise EEndOfStreamCryptoLibException.CreateResFmt(@SEOFInPrivateKey,
       [FEd25519Instance.AlgorithmName]);

+ 2 - 1
CryptoLib/src/Crypto/Parameters/ClpEd25519PublicKeyParameters.pas

@@ -29,6 +29,7 @@ uses
   ClpArrayUtils,
   ClpAsn1Objects,
   ClpStreams,
+  ClpStreamUtilities,
   ClpCryptoLibTypes;
 
 resourcestring
@@ -81,7 +82,7 @@ constructor TEd25519PublicKeyParameters.Create(input: TStream);
 begin
   Inherited Create(false);
   System.SetLength(FData, KeySize);
-  if (KeySize <> TStreamUtils.ReadFully(input, FData)) then
+  if (KeySize <> TStreamUtilities.ReadFully(input, FData)) then
   begin
     raise EEndOfStreamCryptoLibException.CreateRes(@SEOFInPublicKey);
   end;

+ 2 - 1
CryptoLib/src/Crypto/Parameters/ClpX25519PrivateKeyParameters.pas

@@ -32,6 +32,7 @@ uses
   ClpArrayUtils,
   ClpAsn1Objects,
   ClpStreams,
+  ClpStreamUtilities,
   ClpCryptoLibTypes;
 
 resourcestring
@@ -121,7 +122,7 @@ constructor TX25519PrivateKeyParameters.Create(input: TStream);
 begin
   Inherited Create(true);
   System.SetLength(FData, KeySize);
-  if (KeySize <> TStreamUtils.ReadFully(input, FData)) then
+  if (KeySize <> TStreamUtilities.ReadFully(input, FData)) then
   begin
     raise EEndOfStreamCryptoLibException.CreateRes(@SEOFInPrivateKey);
   end;

+ 2 - 1
CryptoLib/src/Crypto/Parameters/ClpX25519PublicKeyParameters.pas

@@ -29,6 +29,7 @@ uses
   ClpArrayUtils,
   ClpAsn1Objects,
   ClpStreams,
+  ClpStreamUtilities,
   ClpCryptoLibTypes;
 
 resourcestring
@@ -81,7 +82,7 @@ constructor TX25519PublicKeyParameters.Create(input: TStream);
 begin
   Inherited Create(false);
   System.SetLength(FData, KeySize);
-  if (KeySize <> TStreamUtils.ReadFully(input, FData)) then
+  if (KeySize <> TStreamUtilities.ReadFully(input, FData)) then
   begin
     raise EEndOfStreamCryptoLibException.CreateRes(@SEOFInPublicKey);
   end;

+ 2 - 1
CryptoLib/src/Crypto/Parsers/ClpECIESPublicKeyParser.pas

@@ -30,6 +30,7 @@ uses
   ClpIAsymmetricKeyParameter,
   ClpIECIESPublicKeyParser,
   ClpStreams,
+  ClpStreamUtilities,
   ClpCryptoLibTypes;
 
 resourcestring
@@ -96,7 +97,7 @@ begin
   end;
 
   v[0] := Byte(first);
-  TStreamUtils.ReadFully(Stream, v, 1, System.length(v) - 1);
+  TStreamUtilities.ReadFully(Stream, v, 1, System.length(v) - 1);
 
   result := TECPublicKeyParameters.Create(FecParams.Curve.DecodePoint(v),
     FecParams);

+ 236 - 0
CryptoLib/src/IO/ClpStreamUtilities.pas

@@ -0,0 +1,236 @@
+{ *********************************************************************************** }
+{ *                              CryptoLib Library                                  * }
+{ *                Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe                    * }
+{ *                 Github Repository <https://github.com/Xor-el>                   * }
+
+{ *  Distributed under the MIT software license, see the accompanying file LICENSE  * }
+{ *          or visit http://www.opensource.org/licenses/mit-license.php.           * }
+
+{ *                              Acknowledgements:                                  * }
+{ *                                                                                 * }
+{ *      Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring     * }
+{ *                           development of this library                           * }
+
+{ * ******************************************************************************* * }
+
+(* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
+
+unit ClpStreamUtilities;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  Classes,
+  SysUtils,
+  ClpCryptoLibTypes;
+
+type
+  /// <summary>
+  /// Utility class with static methods for stream operations.
+  /// </summary>
+  TStreamUtilities = class sealed(TObject)
+
+  strict private
+  const
+    MaxStackAlloc = Int32(4096);
+
+  public
+    class function DefaultBufferSize: Int32; static; inline;
+
+    class procedure CopyTo(const ASource: TStream; const ADestination: TStream;
+      ABufferSize: Int32); overload; static;
+    class procedure CopyTo(const ASource: TStream;
+      const ADestination: TStream); overload; static;
+
+    class procedure Drain(const AInStr: TStream); static;
+
+    class procedure PipeAll(const AInStr: TStream; const AOutStr: TStream;
+      ABufferSize: Int32); overload; static;
+    class procedure PipeAll(const AInStr: TStream;
+      AOutStr: TStream); overload; static;
+
+    class function PipeAllLimited(const AInStr: TStream; ALimit: Int64;
+      const AOutStr: TStream; ABufferSize: Int32): Int64; overload; static;
+    class function PipeAllLimited(const AInStr: TStream; ALimit: Int64;
+      const AOutStr: TStream): Int64; overload; static;
+
+    class function ReadAll(const AInStr: TStream): TCryptoLibByteArray; static;
+
+    class function ReadAllLimited(const AInStr: TStream;
+      ALimit: Int32): TCryptoLibByteArray; static;
+
+    class function ReadFully(const AInStr: TStream;
+      const ABuf: TCryptoLibByteArray; AOff, ALen: Int32): Int32; overload; static;
+    class function ReadFully(const AInStr: TStream;
+      const ABuf: TCryptoLibByteArray): Int32; overload; static;
+
+    class procedure ValidateBufferArguments(const ABuffer: TCryptoLibByteArray;
+      AOffset, ACount: Int32); static;
+
+    class function WriteBufTo(const ABuf: TMemoryStream;
+      const AOutput: TCryptoLibByteArray; AOffset: Int32): Int32; static;
+
+  end;
+
+implementation
+
+uses
+  ClpStreams;
+
+{ TStreamUtilities }
+
+class function TStreamUtilities.DefaultBufferSize: Int32;
+begin
+  Result := MaxStackAlloc;
+end;
+
+class procedure TStreamUtilities.CopyTo(const ASource: TStream;
+  const ADestination: TStream; ABufferSize: Int32);
+var
+  LBytesRead: Int32;
+  LBuffer: TCryptoLibByteArray;
+begin
+  System.SetLength(LBuffer, ABufferSize);
+  LBytesRead := ASource.Read(LBuffer, 0, ABufferSize);
+  while LBytesRead <> 0 do
+  begin
+    ADestination.Write(LBuffer, 0, LBytesRead);
+    LBytesRead := ASource.Read(LBuffer, 0, ABufferSize);
+  end;
+end;
+
+class procedure TStreamUtilities.CopyTo(const ASource: TStream;
+  const ADestination: TStream);
+begin
+  CopyTo(ASource, ADestination, DefaultBufferSize);
+end;
+
+class procedure TStreamUtilities.Drain(const AInStr: TStream);
+var
+  LBuffer: TCryptoLibByteArray;
+  LBytesRead: Int32;
+begin
+  System.SetLength(LBuffer, DefaultBufferSize);
+  LBytesRead := AInStr.Read(LBuffer, 0, DefaultBufferSize);
+  while LBytesRead > 0 do
+  begin
+    // Discard the data
+    LBytesRead := AInStr.Read(LBuffer, 0, DefaultBufferSize);
+  end;
+end;
+
+class procedure TStreamUtilities.PipeAll(const AInStr: TStream; const AOutStr: TStream;
+  ABufferSize: Int32);
+begin
+  CopyTo(AInStr, AOutStr, ABufferSize);
+end;
+
+class procedure TStreamUtilities.PipeAll(const AInStr: TStream;
+  AOutStr: TStream);
+begin
+  PipeAll(AInStr, AOutStr, DefaultBufferSize);
+end;
+
+class function TStreamUtilities.PipeAllLimited(const AInStr: TStream;
+  ALimit: Int64; const AOutStr: TStream; ABufferSize: Int32): Int64;
+var
+  LLimited: TLimitedInputStream;
+begin
+  LLimited := TLimitedInputStream.Create(AInStr, ALimit);
+  try
+    CopyTo(LLimited, AOutStr, ABufferSize);
+    Result := ALimit - LLimited.CurrentLimit;
+  finally
+    LLimited.Free;
+  end;
+end;
+
+class function TStreamUtilities.PipeAllLimited(const AInStr: TStream;
+  ALimit: Int64; const AOutStr: TStream): Int64;
+begin
+  Result := PipeAllLimited(AInStr, ALimit, AOutStr, DefaultBufferSize);
+end;
+
+class function TStreamUtilities.ReadAll(const AInStr: TStream): TCryptoLibByteArray;
+var
+  LBuf: TMemoryStream;
+begin
+  LBuf := TMemoryStream.Create();
+  try
+    PipeAll(AInStr, LBuf);
+    System.SetLength(Result, LBuf.Size);
+    LBuf.Position := 0;
+    LBuf.Read(Result, 0, LBuf.Size);
+  finally
+    LBuf.Free;
+  end;
+end;
+
+class function TStreamUtilities.ReadAllLimited(const AInStr: TStream;
+  ALimit: Int32): TCryptoLibByteArray;
+var
+  LBuf: TMemoryStream;
+begin
+  LBuf := TMemoryStream.Create();
+  try
+    PipeAllLimited(AInStr, ALimit, LBuf);
+    System.SetLength(Result, LBuf.Size);
+    LBuf.Position := 0;
+    LBuf.Read(Result, 0, LBuf.Size);
+  finally
+    LBuf.Free;
+  end;
+end;
+
+class function TStreamUtilities.ReadFully(const AInStr: TStream;
+  const ABuf: TCryptoLibByteArray; AOff, ALen: Int32): Int32;
+var
+  LTotalRead, LNumRead: Int32;
+begin
+  LTotalRead := 0;
+  while LTotalRead < ALen do
+  begin
+    LNumRead := AInStr.Read(ABuf, AOff + LTotalRead, ALen - LTotalRead);
+    if LNumRead < 1 then
+      break;
+    LTotalRead := LTotalRead + LNumRead;
+  end;
+  Result := LTotalRead;
+end;
+
+class function TStreamUtilities.ReadFully(const AInStr: TStream;
+  const ABuf: TCryptoLibByteArray): Int32;
+begin
+  Result := ReadFully(AInStr, ABuf, 0, System.Length(ABuf));
+end;
+
+class procedure TStreamUtilities.ValidateBufferArguments(const ABuffer
+  : TCryptoLibByteArray; AOffset, ACount: Int32);
+var
+  LAvailable, LRemaining: Int32;
+begin
+  if ABuffer = nil then
+    raise EArgumentNilCryptoLibException.Create('Buffer cannot be nil');
+  LAvailable := System.Length(ABuffer) - AOffset;
+  if ((AOffset or LAvailable) < 0) then
+    raise EArgumentOutOfRangeCryptoLibException.Create('Offset out of range');
+  LRemaining := LAvailable - ACount;
+  if ((ACount or LRemaining) < 0) then
+    raise EArgumentOutOfRangeCryptoLibException.Create('Count out of range');
+end;
+
+class function TStreamUtilities.WriteBufTo(const ABuf: TMemoryStream;
+  const AOutput: TBytes; AOffset: Integer): Integer;
+begin
+  Result := ABuf.Size;
+
+  if (AOffset < 0) or (AOffset + Result > Length(AOutput)) then
+    raise ERangeError.Create('Output buffer too small');
+
+  // Copy directly from stream buffer into the byte array
+  Move(PByte(ABuf.Memory)^, AOutput[AOffset], Result);
+end;
+
+end.

+ 5 - 206
CryptoLib/src/IO/ClpStreams.pas

@@ -24,7 +24,8 @@ interface
 uses
   Classes,
   SysUtils,
-  ClpCryptoLibTypes;
+  ClpCryptoLibTypes,
+  ClpStreamUtilities;
 
 type
   /// <summary>
@@ -244,54 +245,6 @@ type
 
   end;
 
-type
-  /// <summary>
-  /// Utility class with static methods for stream operations.
-  /// </summary>
-  TStreamUtils = class sealed(TObject)
-
-  strict private
-  const
-    MaxStackAlloc = Int32(4096);
-
-  public
-    class function DefaultBufferSize: Int32; static; inline;
-
-    class procedure CopyTo(const ASource: TStream; const ADestination: TStream;
-      ABufferSize: Int32); overload; static;
-    class procedure CopyTo(const ASource: TStream;
-      const ADestination: TStream); overload; static;
-
-    class procedure Drain(const AInStr: TStream); static;
-
-    class procedure PipeAll(const AInStr: TStream; const AOutStr: TStream;
-      ABufferSize: Int32); overload; static;
-    class procedure PipeAll(const AInStr: TStream;
-      AOutStr: TStream); overload; static;
-
-    class function PipeAllLimited(const AInStr: TStream; ALimit: Int64;
-      const AOutStr: TStream; ABufferSize: Int32): Int64; overload; static;
-    class function PipeAllLimited(const AInStr: TStream; ALimit: Int64;
-      const AOutStr: TStream): Int64; overload; static;
-
-    class function ReadAll(const AInStr: TStream): TCryptoLibByteArray; static;
-
-    class function ReadAllLimited(const AInStr: TStream;
-      ALimit: Int32): TCryptoLibByteArray; static;
-
-    class function ReadFully(const AInStr: TStream;
-      const ABuf: TCryptoLibByteArray; AOff, ALen: Int32): Int32; overload; static;
-    class function ReadFully(const AInStr: TStream;
-      const ABuf: TCryptoLibByteArray): Int32; overload; static;
-
-    class procedure ValidateBufferArguments(const ABuffer: TCryptoLibByteArray;
-      AOffset, ACount: Int32); static;
-
-    class function WriteBufTo(const ABuf: TMemoryStream;
-      const AOutput: TCryptoLibByteArray; AOffset: Int32): Int32; static;
-
-  end;
-
 implementation
 
 { TStreamHelper }
@@ -601,7 +554,7 @@ end;
 
 function TBaseInputStream.Read(ABuffer: TCryptoLibByteArray; AOffset, ACount: LongInt): LongInt;
 begin
-  TStreamUtils.ValidateBufferArguments(ABuffer, AOffset, ACount);
+  TStreamUtilities.ValidateBufferArguments(ABuffer, AOffset, ACount);
   Result := Read(ABuffer[AOffset], ACount);
 end;
 
@@ -663,7 +616,7 @@ end;
 
 function TBaseOutputStream.Write(const ABuffer: TCryptoLibByteArray; AOffset, ACount: LongInt): LongInt;
 begin
-  TStreamUtils.ValidateBufferArguments(ABuffer, AOffset, ACount);
+  TStreamUtilities.ValidateBufferArguments(ABuffer, AOffset, ACount);
   Result := Write(ABuffer[AOffset], ACount);
 end;
 
@@ -753,7 +706,7 @@ end;
 
 constructor TBufferedFilterStream.Create(const AStream: TStream);
 begin
-  Create(AStream, TStreamUtils.DefaultBufferSize);
+  Create(AStream, TStreamUtilities.DefaultBufferSize);
 end;
 
 constructor TBufferedFilterStream.Create(const AStream: TStream;
@@ -855,158 +808,4 @@ begin
   FBuffer := AByte and $FF;
 end;
 
-{ TStreamUtils }
-
-class function TStreamUtils.DefaultBufferSize: Int32;
-begin
-  Result := MaxStackAlloc;
-end;
-
-class procedure TStreamUtils.CopyTo(const ASource: TStream;
-  const ADestination: TStream; ABufferSize: Int32);
-var
-  LBytesRead: Int32;
-  LBuffer: TCryptoLibByteArray;
-begin
-  System.SetLength(LBuffer, ABufferSize);
-  LBytesRead := ASource.Read(LBuffer, 0, ABufferSize);
-  while LBytesRead <> 0 do
-  begin
-    ADestination.Write(LBuffer, 0, LBytesRead);
-    LBytesRead := ASource.Read(LBuffer, 0, ABufferSize);
-  end;
-end;
-
-class procedure TStreamUtils.CopyTo(const ASource: TStream;
-  const ADestination: TStream);
-begin
-  CopyTo(ASource, ADestination, DefaultBufferSize);
-end;
-
-class procedure TStreamUtils.Drain(const AInStr: TStream);
-var
-  LBuffer: TCryptoLibByteArray;
-  LBytesRead: Int32;
-begin
-  System.SetLength(LBuffer, DefaultBufferSize);
-  LBytesRead := AInStr.Read(LBuffer, 0, DefaultBufferSize);
-  while LBytesRead > 0 do
-  begin
-    // Discard the data
-    LBytesRead := AInStr.Read(LBuffer, 0, DefaultBufferSize);
-  end;
-end;
-
-class procedure TStreamUtils.PipeAll(const AInStr: TStream; const AOutStr: TStream;
-  ABufferSize: Int32);
-begin
-  CopyTo(AInStr, AOutStr, ABufferSize);
-end;
-
-class procedure TStreamUtils.PipeAll(const AInStr: TStream;
-  AOutStr: TStream);
-begin
-  PipeAll(AInStr, AOutStr, DefaultBufferSize);
-end;
-
-class function TStreamUtils.PipeAllLimited(const AInStr: TStream;
-  ALimit: Int64; const AOutStr: TStream; ABufferSize: Int32): Int64;
-var
-  LLimited: TLimitedInputStream;
-begin
-  LLimited := TLimitedInputStream.Create(AInStr, ALimit);
-  try
-    CopyTo(LLimited, AOutStr, ABufferSize);
-    Result := ALimit - LLimited.CurrentLimit;
-  finally
-    LLimited.Free;
-  end;
-end;
-
-class function TStreamUtils.PipeAllLimited(const AInStr: TStream;
-  ALimit: Int64; const AOutStr: TStream): Int64;
-begin
-  Result := PipeAllLimited(AInStr, ALimit, AOutStr, DefaultBufferSize);
-end;
-
-class function TStreamUtils.ReadAll(const AInStr: TStream): TCryptoLibByteArray;
-var
-  LBuf: TMemoryStream;
-begin
-  LBuf := TMemoryStream.Create();
-  try
-    PipeAll(AInStr, LBuf);
-    System.SetLength(Result, LBuf.Size);
-    LBuf.Position := 0;
-    LBuf.Read(Result, 0, LBuf.Size);
-  finally
-    LBuf.Free;
-  end;
-end;
-
-class function TStreamUtils.ReadAllLimited(const AInStr: TStream;
-  ALimit: Int32): TCryptoLibByteArray;
-var
-  LBuf: TMemoryStream;
-begin
-  LBuf := TMemoryStream.Create();
-  try
-    PipeAllLimited(AInStr, ALimit, LBuf);
-    System.SetLength(Result, LBuf.Size);
-    LBuf.Position := 0;
-    LBuf.Read(Result, 0, LBuf.Size);
-  finally
-    LBuf.Free;
-  end;
-end;
-
-class function TStreamUtils.ReadFully(const AInStr: TStream;
-  const ABuf: TCryptoLibByteArray; AOff, ALen: Int32): Int32;
-var
-  LTotalRead, LNumRead: Int32;
-begin
-  LTotalRead := 0;
-  while LTotalRead < ALen do
-  begin
-    LNumRead := AInStr.Read(ABuf, AOff + LTotalRead, ALen - LTotalRead);
-    if LNumRead < 1 then
-      break;
-    LTotalRead := LTotalRead + LNumRead;
-  end;
-  Result := LTotalRead;
-end;
-
-class function TStreamUtils.ReadFully(const AInStr: TStream;
-  const ABuf: TCryptoLibByteArray): Int32;
-begin
-  Result := ReadFully(AInStr, ABuf, 0, System.Length(ABuf));
-end;
-
-class procedure TStreamUtils.ValidateBufferArguments(const ABuffer
-  : TCryptoLibByteArray; AOffset, ACount: Int32);
-var
-  LAvailable, LRemaining: Int32;
-begin
-  if ABuffer = nil then
-    raise EArgumentNilCryptoLibException.Create('Buffer cannot be nil');
-  LAvailable := System.Length(ABuffer) - AOffset;
-  if ((AOffset or LAvailable) < 0) then
-    raise EArgumentOutOfRangeCryptoLibException.Create('Offset out of range');
-  LRemaining := LAvailable - ACount;
-  if ((ACount or LRemaining) < 0) then
-    raise EArgumentOutOfRangeCryptoLibException.Create('Count out of range');
-end;
-
-class function TStreamUtils.WriteBufTo(const ABuf: TMemoryStream;
-  const AOutput: TBytes; AOffset: Integer): Integer;
-begin
-  Result := ABuf.Size;
-
-  if (AOffset < 0) or (AOffset + Result > Length(AOutput)) then
-    raise ERangeError.Create('Output buffer too small');
-
-  // Copy directly from stream buffer into the byte array
-  Move(PByte(ABuf.Memory)^, AOutput[AOffset], Result);
-end;
-
 end.