ソースを参照

add stream processing support for ciphers that implement IBufferedCipher

Ugochukwu Mmaduekwe 7 年 前
コミット
4a69083f66

+ 149 - 0
CryptoLib/src/Crypto/ClpBufferedCipherBase.pas

@@ -22,6 +22,7 @@ unit ClpBufferedCipherBase;
 interface
 interface
 
 
 uses
 uses
+  Classes,
   ClpIBufferedCipher,
   ClpIBufferedCipher,
   ClpICipherParameters,
   ClpICipherParameters,
   ClpIBufferedCipherBase,
   ClpIBufferedCipherBase,
@@ -29,6 +30,14 @@ uses
 
 
 resourcestring
 resourcestring
   SOutputBufferTooSmall = 'Output Buffer too Short';
   SOutputBufferTooSmall = 'Output Buffer too Short';
+  SInvalidBufferSize = '"BufferSize" Must Be Greater Than Zero';
+  SInputOutputStreamSame =
+    'Input and Output Streams Must not Point to the Same Stream Instance';
+  SUnAssignedInputStream = 'Input Stream Is Unassigned';
+  SUnAssignedOutputStream = 'Output Stream Is Unassigned';
+  SPositionOutOfRange = 'Current Position Is Out Of Range';
+  SStreamPositionOutOfRange =
+    'Stream Position (or Stream Length to Process) Is Out Of Range';
 
 
 type
 type
   TBufferedCipherBase = class abstract(TInterfacedObject, IBufferedCipherBase,
   TBufferedCipherBase = class abstract(TInterfacedObject, IBufferedCipherBase,
@@ -43,12 +52,24 @@ type
 
 
     class constructor BufferedCipherBase();
     class constructor BufferedCipherBase();
 
 
+  var
+
+    FBufferSize: Int32;
+
+  const
+    BUFFER_SIZE = Int32(64 * 1024); // 64Kb
+
+    function GetBufferSize: Int32; inline;
+    procedure SetBufferSize(value: Int32); inline;
+
   strict protected
   strict protected
 
 
     class property EmptyBuffer: TCryptoLibByteArray read GetEmptyBuffer;
     class property EmptyBuffer: TCryptoLibByteArray read GetEmptyBuffer;
 
 
   public
   public
 
 
+    constructor Create();
+
     procedure Init(forEncryption: Boolean; const parameters: ICipherParameters);
     procedure Init(forEncryption: Boolean; const parameters: ICipherParameters);
       virtual; abstract;
       virtual; abstract;
 
 
@@ -76,6 +97,13 @@ type
       length: Int32; const output: TCryptoLibByteArray; outOff: Int32): Int32;
       length: Int32; const output: TCryptoLibByteArray; outOff: Int32): Int32;
       overload; virtual;
       overload; virtual;
 
 
+    procedure ProcessStream(const inputStream, outputStream: TStream;
+      length: Int64); overload; virtual;
+
+    procedure ProcessStream(const inputStream: TStream; inPos: Int64;
+      const outputStream: TStream; outPos: Int64; length: Int64);
+      overload; virtual;
+
     function DoFinal(): TCryptoLibByteArray; overload; virtual; abstract;
     function DoFinal(): TCryptoLibByteArray; overload; virtual; abstract;
 
 
     function DoFinal(const input: TCryptoLibByteArray): TCryptoLibByteArray;
     function DoFinal(const input: TCryptoLibByteArray): TCryptoLibByteArray;
@@ -99,6 +127,12 @@ type
     function GetAlgorithmName: String; virtual; abstract;
     function GetAlgorithmName: String; virtual; abstract;
     property AlgorithmName: String read GetAlgorithmName;
     property AlgorithmName: String read GetAlgorithmName;
 
 
+    /// <summary>
+    /// property for determining the buffer size to use for stream based
+    /// encryption/decryption.
+    /// </summary>
+    property BufferSize: Int32 read GetBufferSize write SetBufferSize;
+
   end;
   end;
 
 
 implementation
 implementation
@@ -110,6 +144,29 @@ begin
   System.SetLength(FEmptyBuffer, 0);
   System.SetLength(FEmptyBuffer, 0);
 end;
 end;
 
 
+constructor TBufferedCipherBase.Create;
+begin
+  Inherited Create();
+  FBufferSize := BUFFER_SIZE;
+end;
+
+function TBufferedCipherBase.GetBufferSize: Int32;
+begin
+  result := FBufferSize;
+end;
+
+procedure TBufferedCipherBase.SetBufferSize(value: Int32);
+begin
+  if value > 0 then
+  begin
+    FBufferSize := value;
+  end
+  else
+  begin
+    raise EArgumentCryptoLibException.CreateRes(@SInvalidBufferSize);
+  end;
+end;
+
 function TBufferedCipherBase.DoFinal(const output: TCryptoLibByteArray;
 function TBufferedCipherBase.DoFinal(const output: TCryptoLibByteArray;
   outOff: Int32): Int32;
   outOff: Int32): Int32;
 var
 var
@@ -197,6 +254,98 @@ begin
   result := System.length(outBytes);
   result := System.length(outBytes);
 end;
 end;
 
 
+procedure TBufferedCipherBase.ProcessStream(const inputStream: TStream;
+  inPos: Int64; const outputStream: TStream; outPos, length: Int64);
+var
+  LBufferSize, readed: Int32;
+  total: Int64;
+  data, tempRes: TCryptoLibByteArray;
+begin
+  total := 0;
+  if ((inPos < 0) or (outPos < 0) or (length <= 0)) then
+  begin
+    raise EIndexOutOfRangeCryptoLibException.CreateRes
+      (@SStreamPositionOutOfRange);
+  end;
+
+  if inputStream = Nil then
+  begin
+    raise EStreamCryptoLibException.CreateRes(@SUnAssignedInputStream);
+  end;
+
+  if outputStream = Nil then
+  begin
+    raise EStreamCryptoLibException.CreateRes(@SUnAssignedOutputStream);
+  end;
+
+  if inputStream = outputStream then
+  begin
+    raise EStreamCryptoLibException.CreateRes(@SInputOutputStreamSame);
+  end;
+
+  if ((inputStream.Position + length) > inputStream.Size) then
+  begin
+    raise EIndexOutOfRangeCryptoLibException.CreateRes(@SPositionOutOfRange);
+  end;
+
+  if (inputStream.Position >= inputStream.Size) then
+  begin
+    Exit;
+  end;
+
+  if BufferSize > inputStream.Size then // Sanity Check
+  begin
+    LBufferSize := BUFFER_SIZE;
+  end
+  else
+  begin
+    LBufferSize := BufferSize;
+  end;
+
+  System.SetLength(data, LBufferSize);
+
+  inputStream.Position := inPos;
+  outputStream.Position := outPos;
+
+  while true do
+  begin
+
+    readed := inputStream.Read(data[0], LBufferSize);
+
+    if ((total + Int64(readed)) >= length) then
+    begin
+      tempRes := ProcessBytes(data, 0, Int32(length - total));
+      if (tempRes <> Nil) then
+      begin
+        outputStream.Write(tempRes[0], System.length(tempRes));
+      end;
+      break;
+    end
+    else
+    begin
+      tempRes := ProcessBytes(data, 0, readed);
+      if (tempRes <> Nil) then
+      begin
+        outputStream.Write(tempRes[0], System.length(tempRes));
+      end;
+      total := total + readed;
+    end;
+  end;
+
+  tempRes := DoFinal();
+  if (tempRes <> Nil) then
+  begin
+    outputStream.Write(tempRes[0], System.length(tempRes));
+  end;
+
+end;
+
+procedure TBufferedCipherBase.ProcessStream(const inputStream,
+  outputStream: TStream; length: Int64);
+begin
+  ProcessStream(inputStream, 0, outputStream, 0, length);
+end;
+
 function TBufferedCipherBase.ProcessBytes(const input,
 function TBufferedCipherBase.ProcessBytes(const input,
   output: TCryptoLibByteArray; outOff: Int32): Int32;
   output: TCryptoLibByteArray; outOff: Int32): Int32;
 begin
 begin

+ 17 - 3
CryptoLib/src/Crypto/Prng/ClpDigestRandomGenerator.pas

@@ -55,9 +55,10 @@ type
     procedure DigestUpdate(const inSeed: TCryptoLibByteArray); inline;
     procedure DigestUpdate(const inSeed: TCryptoLibByteArray); inline;
     procedure DigestDoFinal(const result: TCryptoLibByteArray); inline;
     procedure DigestDoFinal(const result: TCryptoLibByteArray); inline;
 
 
-    class var
+  class var
 
 
-      FLock: TCriticalSection;
+    FLock: TCriticalSection;
+    FIsBooted: Boolean;
 
 
     class constructor CreateDigestRandomGenerator();
     class constructor CreateDigestRandomGenerator();
     class destructor DestroyDigestRandomGenerator();
     class destructor DestroyDigestRandomGenerator();
@@ -72,6 +73,8 @@ type
     procedure NextBytes(const bytes: TCryptoLibByteArray;
     procedure NextBytes(const bytes: TCryptoLibByteArray;
       start, len: Int32); overload;
       start, len: Int32); overload;
 
 
+    class procedure Boot(); static;
+
   end;
   end;
 
 
 implementation
 implementation
@@ -111,6 +114,16 @@ begin
   end;
   end;
 end;
 end;
 
 
+class procedure TDigestRandomGenerator.Boot;
+begin
+  if not FIsBooted then
+  begin
+    FLock := TCriticalSection.Create;
+
+    FIsBooted := True;
+  end;
+end;
+
 procedure TDigestRandomGenerator.AddSeedMaterial(const inSeed
 procedure TDigestRandomGenerator.AddSeedMaterial(const inSeed
   : TCryptoLibByteArray);
   : TCryptoLibByteArray);
 begin
 begin
@@ -132,11 +145,12 @@ begin
   FseedCounter := 1;
   FseedCounter := 1;
   System.SetLength(Fstate, digest.GetDigestSize);
   System.SetLength(Fstate, digest.GetDigestSize);
   FstateCounter := 1;
   FstateCounter := 1;
+  TDigestRandomGenerator.Boot;
 end;
 end;
 
 
 class constructor TDigestRandomGenerator.CreateDigestRandomGenerator;
 class constructor TDigestRandomGenerator.CreateDigestRandomGenerator;
 begin
 begin
-  FLock := TCriticalSection.Create;
+  TDigestRandomGenerator.Boot;
 end;
 end;
 
 
 procedure TDigestRandomGenerator.CycleSeed;
 procedure TDigestRandomGenerator.CycleSeed;

+ 19 - 4
CryptoLib/src/Interfaces/ClpIBufferedCipher.pas

@@ -22,6 +22,7 @@ unit ClpIBufferedCipher;
 interface
 interface
 
 
 uses
 uses
+  Classes,
   ClpICipherParameters,
   ClpICipherParameters,
   ClpCryptoLibTypes;
   ClpCryptoLibTypes;
 
 
@@ -33,6 +34,14 @@ type
     function GetAlgorithmName: String;
     function GetAlgorithmName: String;
     property AlgorithmName: String read GetAlgorithmName;
     property AlgorithmName: String read GetAlgorithmName;
 
 
+    function GetBufferSize: Int32;
+    procedure SetBufferSize(value: Int32);
+    /// <summary>
+    /// property for determining the buffer size to use for stream based
+    /// encryption/decryption.
+    /// </summary>
+    property BufferSize: Int32 read GetBufferSize write SetBufferSize;
+
     /// <summary>Initialise the cipher.</summary>
     /// <summary>Initialise the cipher.</summary>
     /// <param name="forEncryption">If true the cipher is initialised for encryption,
     /// <param name="forEncryption">If true the cipher is initialised for encryption,
     /// if false for decryption.</param>
     /// if false for decryption.</param>
@@ -45,6 +54,12 @@ type
 
 
     function GetUpdateOutputSize(inputLen: Int32): Int32;
     function GetUpdateOutputSize(inputLen: Int32): Int32;
 
 
+    procedure ProcessStream(const inputStream, outputStream: TStream;
+      Length: Int64); overload;
+
+    procedure ProcessStream(const inputStream: TStream; inOff: Int64;
+      const outputStream: TStream; outOff: Int64; Length: Int64); overload;
+
     function ProcessByte(input: Byte): TCryptoLibByteArray; overload;
     function ProcessByte(input: Byte): TCryptoLibByteArray; overload;
     function ProcessByte(input: Byte; const output: TCryptoLibByteArray;
     function ProcessByte(input: Byte; const output: TCryptoLibByteArray;
       outOff: Int32): Int32; overload;
       outOff: Int32): Int32; overload;
@@ -52,23 +67,23 @@ type
     function ProcessBytes(const input: TCryptoLibByteArray)
     function ProcessBytes(const input: TCryptoLibByteArray)
       : TCryptoLibByteArray; overload;
       : TCryptoLibByteArray; overload;
     function ProcessBytes(const input: TCryptoLibByteArray;
     function ProcessBytes(const input: TCryptoLibByteArray;
-      inOff, length: Int32): TCryptoLibByteArray; overload;
+      inOff, Length: Int32): TCryptoLibByteArray; overload;
     function ProcessBytes(const input, output: TCryptoLibByteArray;
     function ProcessBytes(const input, output: TCryptoLibByteArray;
       outOff: Int32): Int32; overload;
       outOff: Int32): Int32; overload;
     function ProcessBytes(const input: TCryptoLibByteArray;
     function ProcessBytes(const input: TCryptoLibByteArray;
-      inOff, length: Int32; const output: TCryptoLibByteArray; outOff: Int32)
+      inOff, Length: Int32; const output: TCryptoLibByteArray; outOff: Int32)
       : Int32; overload;
       : Int32; overload;
 
 
     function DoFinal(): TCryptoLibByteArray; overload;
     function DoFinal(): TCryptoLibByteArray; overload;
     function DoFinal(const input: TCryptoLibByteArray)
     function DoFinal(const input: TCryptoLibByteArray)
       : TCryptoLibByteArray; overload;
       : TCryptoLibByteArray; overload;
-    function DoFinal(const input: TCryptoLibByteArray; inOff, length: Int32)
+    function DoFinal(const input: TCryptoLibByteArray; inOff, Length: Int32)
       : TCryptoLibByteArray; overload;
       : TCryptoLibByteArray; overload;
     function DoFinal(const output: TCryptoLibByteArray; outOff: Int32)
     function DoFinal(const output: TCryptoLibByteArray; outOff: Int32)
       : Int32; overload;
       : Int32; overload;
     function DoFinal(const input, output: TCryptoLibByteArray; outOff: Int32)
     function DoFinal(const input, output: TCryptoLibByteArray; outOff: Int32)
       : Int32; overload;
       : Int32; overload;
-    function DoFinal(const input: TCryptoLibByteArray; inOff, length: Int32;
+    function DoFinal(const input: TCryptoLibByteArray; inOff, Length: Int32;
       const output: TCryptoLibByteArray; outOff: Int32): Int32; overload;
       const output: TCryptoLibByteArray; outOff: Int32): Int32; overload;
 
 
     /// <summary>
     /// <summary>

+ 1 - 0
CryptoLib/src/Utils/ClpCryptoLibTypes.pas

@@ -51,6 +51,7 @@ type
   EAsn1ParsingCryptoLibException = class(ECryptoLibException);
   EAsn1ParsingCryptoLibException = class(ECryptoLibException);
   EInvalidKeyCryptoLibException = class(ECryptoLibException);
   EInvalidKeyCryptoLibException = class(ECryptoLibException);
   EInvalidCipherTextCryptoLibException = class(ECryptoLibException);
   EInvalidCipherTextCryptoLibException = class(ECryptoLibException);
+  EStreamCryptoLibException = class(ECryptoLibException);
   ESecurityUtilityCryptoLibException = class(ECryptoLibException);
   ESecurityUtilityCryptoLibException = class(ECryptoLibException);
   EAccessCryptoLibException = class(ECryptoLibException);
   EAccessCryptoLibException = class(ECryptoLibException);
   EDataLengthCryptoLibException = class(ECryptoLibException);
   EDataLengthCryptoLibException = class(ECryptoLibException);

+ 40 - 28
CryptoLib/src/Utils/Randoms/ClpOSRandom.pas

@@ -78,6 +78,7 @@ type
 {$ENDIF MSWINDOWS}
 {$ENDIF MSWINDOWS}
 
 
   class var
   class var
+    FIsBooted: Boolean;
 {$IFDEF MSWINDOWS}
 {$IFDEF MSWINDOWS}
     FwinCryptOk: Int32; // Windows Random function available
     FwinCryptOk: Int32; // Windows Random function available
     FhProvider: ULONG; // Windows HCryptProvider Handle
     FhProvider: ULONG; // Windows HCryptProvider Handle
@@ -96,6 +97,7 @@ type
 
 
     class procedure GetBytes(const data: TCryptoLibByteArray); static;
     class procedure GetBytes(const data: TCryptoLibByteArray); static;
     class procedure GetNonZeroBytes(const data: TCryptoLibByteArray); static;
     class procedure GetNonZeroBytes(const data: TCryptoLibByteArray); static;
+    class procedure Boot; static;
 
 
   end;
   end;
 
 
@@ -117,45 +119,54 @@ begin
 
 
 end;
 end;
 
 
-class constructor TOSRandom.CreateOSRandom;
+class procedure TOSRandom.Boot;
 {$IFNDEF MSWINDOWS}
 {$IFNDEF MSWINDOWS}
 var
 var
   RandGen: string;
   RandGen: string;
 {$ENDIF MSWINDOWS}
 {$ENDIF MSWINDOWS}
 begin
 begin
-{$IFDEF MSWINDOWS}
-  FWinCryptHndl := LoadLibrary(PChar('advapi32.dll'));
-  if (FWinCryptHndl < 32) then
-  begin
-    FwinCryptOk := -1;
-    Exit;
-  end;
-  @FWCCryptAcquireContextA := GetProcAddress(FWinCryptHndl,
-    'CryptAcquireContextA');
-  @FWCCryptReleaseContext := GetProcAddress(FWinCryptHndl,
-    'CryptReleaseContext');
-  @FWCCryptGenRandom := GetProcAddress(FWinCryptHndl, 'CryptGenRandom');
-
-  if FWCCryptAcquireContextA(@FhProvider, Nil, Nil, 1 { PROV_RSA_FULL } ,
-    $F0000000 { CRYPT_VERIFYCONTEXT } ) then
-  begin
-    FwinCryptOk := 1;
-  end;
-{$ELSE}
-  RandGen := '/dev/urandom';
-  if not FileExists(RandGen) then
+  if not FIsBooted then
   begin
   begin
-    if not FileExists('/dev/random') then
+{$IFDEF MSWINDOWS}
+    FWinCryptHndl := LoadLibrary(PChar('advapi32.dll'));
+    if (FWinCryptHndl < 32) then
     begin
     begin
-      FunixCryptOk := -1;
+      FwinCryptOk := -1;
       Exit;
       Exit;
     end;
     end;
-    RandGen := '/dev/random';
-  end;
-  FStream := TFileStream.Create(RandGen, fmOpenRead);
-  FunixCryptOk := 1;
+    @FWCCryptAcquireContextA := GetProcAddress(FWinCryptHndl,
+      'CryptAcquireContextA');
+    @FWCCryptReleaseContext := GetProcAddress(FWinCryptHndl,
+      'CryptReleaseContext');
+    @FWCCryptGenRandom := GetProcAddress(FWinCryptHndl, 'CryptGenRandom');
+
+    if FWCCryptAcquireContextA(@FhProvider, Nil, Nil, 1 { PROV_RSA_FULL } ,
+      $F0000000 { CRYPT_VERIFYCONTEXT } ) then
+    begin
+      FwinCryptOk := 1;
+    end;
+{$ELSE}
+    RandGen := '/dev/urandom';
+    if not FileExists(RandGen) then
+    begin
+      if not FileExists('/dev/random') then
+      begin
+        FunixCryptOk := -1;
+        Exit;
+      end;
+      RandGen := '/dev/random';
+    end;
+    FStream := TFileStream.Create(RandGen, fmOpenRead);
+    FunixCryptOk := 1;
 
 
 {$ENDIF MSWINDOWS}
 {$ENDIF MSWINDOWS}
+    FIsBooted := True;
+  end;
+end;
+
+class constructor TOSRandom.CreateOSRandom;
+begin
+  TOSRandom.Boot;
 end;
 end;
 
 
 class destructor TOSRandom.DestroyOSRandom;
 class destructor TOSRandom.DestroyOSRandom;
@@ -174,6 +185,7 @@ class procedure TOSRandom.GetBytes(const data: TCryptoLibByteArray);
 var
 var
   count: Int32;
   count: Int32;
 begin
 begin
+  TOSRandom.Boot;
   count := System.Length(data);
   count := System.Length(data);
 {$IFDEF MSWINDOWS}
 {$IFDEF MSWINDOWS}
   if FwinCryptOk = 1 then
   if FwinCryptOk = 1 then