Pārlūkot izejas kodu

abstract asn1 generators

Ugochukwu Mmaduekwe 2 nedēļas atpakaļ
vecāks
revīzija
4e11e09e45

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

@@ -515,6 +515,8 @@ uses
   ClpAsn1Tags in '..\..\CryptoLib\src\Asn1\ClpAsn1Tags.pas',
   ClpIAsn1Encodings in '..\..\CryptoLib\src\Interfaces\Asn1\ClpIAsn1Encodings.pas',
   ClpAsn1Encodings in '..\..\CryptoLib\src\Asn1\ClpAsn1Encodings.pas',
+  ClpAsn1Generators in '..\..\CryptoLib\src\Asn1\ClpAsn1Generators.pas',
+  ClpIAsn1Generators in '..\..\CryptoLib\src\Interfaces\Asn1\ClpIAsn1Generators.pas',
   ClpFixedSecureRandom in '..\src\Utils\ClpFixedSecureRandom.pas',
   ClpIFixedSecureRandom in '..\src\Utils\ClpIFixedSecureRandom.pas',
   ClpIShortenedDigest in '..\src\Utils\ClpIShortenedDigest.pas',

+ 2 - 0
CryptoLib.Tests/src/Asn1/Asn1SequenceParserTests.pas

@@ -37,6 +37,8 @@ uses
   ClpIAsn1Objects,
   ClpIAsn1Parsers,
   ClpAsn1Parsers,
+  ClpIAsn1Generators,
+  ClpAsn1Generators,
   ClpCryptoLibTypes,
   CryptoLibTestBase;
 

+ 2 - 0
CryptoLib.Tests/src/Asn1/OctetStringTests.pas

@@ -35,6 +35,8 @@ uses
   ClpIAsn1Objects,
   ClpIAsn1Parsers,
   ClpAsn1Parsers,
+  ClpIAsn1Generators,
+  ClpAsn1Generators,
   ClpStreamUtilities,
   ClpCryptoLibTypes,
   CryptoLibTestBase;

+ 479 - 0
CryptoLib/src/Asn1/ClpAsn1Generators.pas

@@ -0,0 +1,479 @@
+{ *********************************************************************************** }
+{ *                              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 ClpAsn1Generators;
+
+{$I ..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  Classes,
+  ClpCryptoLibTypes,
+  ClpIAsn1Generators,
+  ClpIAsn1Core,
+  ClpAsn1Tags,
+  ClpAsn1Core,
+  ClpAsn1Streams;
+
+type
+  /// <summary>
+  /// Abstract base class for ASN.1 generators.
+  /// </summary>
+  TAsn1Generator = class abstract(TInterfacedObject, IAsn1Generator)
+  strict private
+    FOut: TStream;
+    FClosed: Boolean;
+  strict protected
+    constructor Create(AOutStream: TStream);
+    function GetOut: TStream; inline;
+    function GetIsClosed: Boolean; inline;
+    property &Out: TStream read GetOut;
+    procedure Finish(); virtual; abstract;
+    procedure DoClose();
+  public
+    destructor Destroy(); override;
+    procedure AddObject(const AObj: IAsn1Encodable); overload; virtual; abstract;
+    procedure AddObject(const AObj: IAsn1Object); overload; virtual; abstract;
+    function GetRawOutputStream(): TStream; virtual; abstract;
+    procedure Close(); virtual; abstract;
+    property IsClosed: Boolean read GetIsClosed;
+    class function InheritConstructedFlag(AIntoTag, AFromTag: Int32): Int32; static;
+  end;
+
+  /// <summary>
+  /// Abstract base class for BER generators.
+  /// </summary>
+  TBerGenerator = class abstract(TAsn1Generator, IBerGenerator)
+  strict private
+    FTagged, FIsExplicit: Boolean;
+    FTagNo: Int32;
+  strict protected
+    constructor Create(AOutStream: TStream); overload;
+    constructor Create(AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean); overload;
+
+    procedure WriteHdr(ATag: Int32);
+    procedure WriteBerHeader(ATag: Int32);
+    procedure WriteBerBody(AContentStream: TStream);
+    procedure WriteBerEnd();
+    procedure Finish(); override;
+  public
+    procedure AddObject(const AObj: IAsn1Encodable); override;
+    procedure AddObject(const AObj: IAsn1Object); override;
+    function GetRawOutputStream(): TStream; override;
+    procedure Close(); override;
+  end;
+
+  /// <summary>
+  /// BER sequence generator.
+  /// </summary>
+  TBerSequenceGenerator = class(TBerGenerator, IBerSequenceGenerator)
+  public
+    constructor Create(AOutStream: TStream); overload;
+    constructor Create(AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean); overload;
+  end;
+
+  /// <summary>
+  /// BER octet string generator.
+  /// </summary>
+  TBerOctetStringGenerator = class(TBerGenerator, IBerOctetStringGenerator)
+  public
+    constructor Create(AOutStream: TStream); overload;
+    constructor Create(AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean); overload;
+    function GetOctetOutputStream(): TStream; overload;
+    function GetOctetOutputStream(ABufSize: Int32): TStream; overload;
+    function GetOctetOutputStream(const ABuf: TCryptoLibByteArray): TStream; overload;
+  end;
+
+  /// <summary>
+  /// Abstract base class for DER generators.
+  /// </summary>
+  TDerGenerator = class abstract(TAsn1Generator, IDerGenerator)
+  strict private
+    FTagged, FIsExplicit: Boolean;
+    FTagNo: Int32;
+    class procedure WriteLength(const AOutStr: TStream; ALength: Int32); static;
+  strict protected
+    constructor Create(const AOutStream: TStream); overload;
+    constructor Create(const AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean); overload;
+  public
+    procedure WriteDerEncoded(ATag: Int32; const ABytes: TCryptoLibByteArray); overload;
+    class procedure WriteDerEncoded(const AOutStream: TStream; ATag: Int32; const ABytes: TCryptoLibByteArray); overload; static;
+    class procedure WriteDerEncoded(const AOutStr: TStream; ATag: Int32; const AInStr: TStream); overload; static;
+  end;
+
+  /// <summary>
+  /// DER sequence generator.
+  /// </summary>
+  TDerSequenceGenerator = class(TDerGenerator, IDerSequenceGenerator)
+  strict private
+    FBOut: TMemoryStream;
+  strict protected
+    procedure Finish(); override;
+  public
+    constructor Create(AOutStream: TStream); overload;
+    constructor Create(AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean); overload;
+    destructor Destroy(); override;
+    procedure AddObject(const AObj: IAsn1Encodable); overload; override;
+    procedure AddObject(const AObj: IAsn1Object); overload; override;
+    function GetRawOutputStream(): TStream; override;
+    procedure Close(); override;
+  end;
+
+implementation
+
+uses
+  ClpBitUtilities,
+  ClpStreamUtilities;
+
+{ TAsn1Generator }
+
+constructor TAsn1Generator.Create(AOutStream: TStream);
+begin
+  inherited Create;
+  if AOutStream = nil then
+    raise EArgumentNilCryptoLibException.Create('outStream');
+  FOut := AOutStream;
+  FClosed := False;
+end;
+
+destructor TAsn1Generator.Destroy;
+begin
+  DoClose();
+  inherited Destroy;
+end;
+
+procedure TAsn1Generator.DoClose();
+begin
+  if (FOut <> nil) and (not FClosed) then
+  begin
+    FClosed := True;
+    try
+      Finish();
+    finally
+      FOut := nil;  // Prevent any further access to the stream
+    end;
+  end;
+end;
+
+function TAsn1Generator.GetIsClosed: Boolean;
+begin
+  Result := FClosed;
+end;
+
+function TAsn1Generator.GetOut: TStream;
+begin
+  if FOut = nil then
+    raise EInvalidOperationCryptoLibException.Create('Stream is null');
+  Result := FOut;
+end;
+
+class function TAsn1Generator.InheritConstructedFlag(AIntoTag, AFromTag: Int32): Int32;
+begin
+  if ((AFromTag and TAsn1Tags.Constructed) <> 0) then
+    Result := AIntoTag or TAsn1Tags.Constructed
+  else
+    Result := AIntoTag and (not TAsn1Tags.Constructed);
+end;
+
+{ TBerGenerator }
+
+constructor TBerGenerator.Create(AOutStream: TStream);
+begin
+  inherited Create(AOutStream);
+end;
+
+constructor TBerGenerator.Create(AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean);
+begin
+  inherited Create(AOutStream);
+  FTagged := True;
+  FIsExplicit := AIsExplicit;
+  FTagNo := ATagNo;
+end;
+
+procedure TBerGenerator.AddObject(const AObj: IAsn1Encodable);
+begin
+  AObj.EncodeTo(&Out);
+end;
+
+procedure TBerGenerator.AddObject(const AObj: IAsn1Object);
+begin
+  AObj.EncodeTo(&Out);
+end;
+
+procedure TBerGenerator.Finish();
+begin
+  WriteBerEnd();
+end;
+
+procedure TBerGenerator.Close();
+begin
+  DoClose();
+end;
+
+function TBerGenerator.GetRawOutputStream(): TStream;
+begin
+  Result := &Out;
+end;
+
+procedure TBerGenerator.WriteBerBody(AContentStream: TStream);
+begin
+  TStreamUtilities.PipeAll(AContentStream, &Out);
+end;
+
+procedure TBerGenerator.WriteBerEnd();
+begin
+  &Out.WriteByte($00);
+  &Out.WriteByte($00);
+
+  if (FTagged and FIsExplicit) then // write extra end for tag header
+  begin
+    &Out.WriteByte($00);
+    &Out.WriteByte($00);
+  end;
+end;
+
+procedure TBerGenerator.WriteBerHeader(ATag: Int32);
+begin
+  if not FTagged then
+  begin
+    WriteHdr(ATag);
+  end
+  else if FIsExplicit then
+  begin
+    {
+     * X.690-0207 8.14.2. If implicit tagging [..] was not used [..], the encoding shall be constructed
+     * and the contents octets shall be the complete base encoding.
+     }
+    WriteHdr(FTagNo or TAsn1Tags.ContextSpecific or TAsn1Tags.Constructed);
+    WriteHdr(ATag);
+  end
+  else
+  begin
+    {
+     * X.690-0207 8.14.3. If implicit tagging was used [..], then: a) the encoding shall be constructed
+     * if the base encoding is constructed, and shall be primitive otherwise; and b) the contents octets
+     * shall be [..] the contents octets of the base encoding.
+     }
+    WriteHdr(InheritConstructedFlag(FTagNo or TAsn1Tags.ContextSpecific, ATag));
+  end;
+end;
+
+procedure TBerGenerator.WriteHdr(ATag: Int32);
+begin
+  &Out.WriteByte(Byte(ATag));
+  &Out.WriteByte($80);
+end;
+
+{ TBerSequenceGenerator }
+
+constructor TBerSequenceGenerator.Create(AOutStream: TStream);
+begin
+  inherited Create(AOutStream);
+  WriteBerHeader(TAsn1Tags.Constructed or TAsn1Tags.Sequence);
+end;
+
+constructor TBerSequenceGenerator.Create(AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean);
+begin
+  inherited Create(AOutStream, ATagNo, AIsExplicit);
+  WriteBerHeader(TAsn1Tags.Constructed or TAsn1Tags.Sequence);
+end;
+
+{ TBerOctetStringGenerator }
+
+constructor TBerOctetStringGenerator.Create(AOutStream: TStream);
+begin
+  inherited Create(AOutStream);
+  WriteBerHeader(TAsn1Tags.Constructed or TAsn1Tags.OctetString);
+end;
+
+constructor TBerOctetStringGenerator.Create(AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean);
+begin
+  inherited Create(AOutStream, ATagNo, AIsExplicit);
+  WriteBerHeader(TAsn1Tags.Constructed or TAsn1Tags.OctetString);
+end;
+
+function TBerOctetStringGenerator.GetOctetOutputStream(): TStream;
+var
+  LBuf: TCryptoLibByteArray;
+begin
+  System.SetLength(LBuf, 1000);
+  Result := GetOctetOutputStream(LBuf); // limit for CER encoding.
+end;
+
+function TBerOctetStringGenerator.GetOctetOutputStream(ABufSize: Int32): TStream;
+var
+  LBuf: TCryptoLibByteArray;
+begin
+  if ABufSize < 1 then
+    Result := GetOctetOutputStream()
+  else
+  begin
+    System.SetLength(LBuf, ABufSize);
+    Result := GetOctetOutputStream(LBuf);
+  end;
+end;
+
+function TBerOctetStringGenerator.GetOctetOutputStream(const ABuf: TCryptoLibByteArray): TStream;
+begin
+  Result := TAsn1BufferedBerOctetStream.Create(GetRawOutputStream(), ABuf);
+end;
+
+{ TDerGenerator }
+
+constructor TDerGenerator.Create(const AOutStream: TStream);
+begin
+  inherited Create(AOutStream);
+end;
+
+constructor TDerGenerator.Create(const AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean);
+begin
+  inherited Create(AOutStream);
+  FTagged := True;
+  FIsExplicit := AIsExplicit;
+  FTagNo := ATagNo;
+end;
+
+class procedure TDerGenerator.WriteDerEncoded(const AOutStream: TStream; ATag: Int32; const ABytes: TCryptoLibByteArray);
+begin
+  AOutStream.WriteByte(Byte(ATag));
+  WriteLength(AOutStream, System.Length(ABytes));
+  if System.Length(ABytes) > 0 then
+    AOutStream.Write(ABytes[0], System.Length(ABytes));
+end;
+
+class procedure TDerGenerator.WriteDerEncoded(const AOutStr: TStream; ATag: Int32; const AInStr: TStream);
+begin
+  WriteDerEncoded(AOutStr, ATag, TStreamUtilities.ReadAll(AInStr));
+end;
+
+class procedure TDerGenerator.WriteLength(const AOutStr: TStream; ALength: Int32);
+var
+  LSize, LVal, I: Int32;
+begin
+  if ALength > 127 then
+  begin
+    LSize := 1;
+    LVal := ALength;
+    LVal := TBitUtilities.Asr32(LVal, 8);
+    while LVal <> 0 do
+    begin
+      System.Inc(LSize);
+      LVal := TBitUtilities.Asr32(LVal, 8);
+    end;
+    AOutStr.WriteByte(Byte(LSize or $80));
+    I := (LSize - 1) * 8;
+    while I >= 0 do
+    begin
+      AOutStr.WriteByte(Byte(TBitUtilities.Asr32(ALength, I)));
+      System.Dec(I, 8);
+    end;
+  end
+  else
+  begin
+    AOutStr.WriteByte(Byte(ALength));
+  end;
+end;
+
+procedure TDerGenerator.WriteDerEncoded(ATag: Int32; const ABytes: TCryptoLibByteArray);
+var
+  LBOut: TMemoryStream;
+  LTemp: TCryptoLibByteArray;
+begin
+  if not FTagged then
+  begin
+    WriteDerEncoded(&Out, ATag, ABytes);
+  end
+  else if FIsExplicit then
+  begin
+    {
+     * X.690-0207 8.14.2. If implicit tagging [..] was not used [..], the encoding shall be constructed
+     * and the contents octets shall be the complete base encoding.
+     }
+    LBOut := TMemoryStream.Create();
+    try
+      WriteDerEncoded(LBOut, ATag, ABytes);
+      LBOut.Position := 0;
+      System.SetLength(LTemp, LBOut.Size);
+      LBOut.Read(LTemp[0], LBOut.Size);
+      WriteDerEncoded(&Out, FTagNo or TAsn1Tags.ContextSpecific or TAsn1Tags.Constructed, LTemp);
+    finally
+      LBOut.Free;
+    end;
+  end
+  else
+  begin
+    {
+     * X.690-0207 8.14.3. If implicit tagging was used [..], then: a) the encoding shall be constructed
+     * if the base encoding is constructed, and shall be primitive otherwise; and b) the contents octets
+     * shall be [..] the contents octets of the base encoding.
+     }
+    WriteDerEncoded(&Out, InheritConstructedFlag(FTagNo or TAsn1Tags.ContextSpecific, ATag), ABytes);
+  end;
+end;
+
+{ TDerSequenceGenerator }
+
+constructor TDerSequenceGenerator.Create(AOutStream: TStream);
+begin
+  inherited Create(AOutStream);
+  FBOut := TMemoryStream.Create();
+end;
+
+constructor TDerSequenceGenerator.Create(AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean);
+begin
+  inherited Create(AOutStream, ATagNo, AIsExplicit);
+  FBOut := TMemoryStream.Create();
+end;
+
+destructor TDerSequenceGenerator.Destroy;
+begin
+  FBOut.Free;
+  inherited Destroy;
+end;
+
+procedure TDerSequenceGenerator.AddObject(const AObj: IAsn1Encodable);
+begin
+  AObj.EncodeTo(FBOut, TAsn1Encodable.Der);
+end;
+
+procedure TDerSequenceGenerator.AddObject(const AObj: IAsn1Object);
+begin
+  (AObj as IAsn1Encodable).EncodeTo(FBOut, TAsn1Encodable.Der);
+end;
+
+function TDerSequenceGenerator.GetRawOutputStream(): TStream;
+begin
+  Result := FBOut;
+end;
+
+procedure TDerSequenceGenerator.Finish();
+var
+  LTemp: TCryptoLibByteArray;
+begin
+  FBOut.Position := 0;
+  System.SetLength(LTemp, FBOut.Size);
+  FBOut.Read(LTemp[0], FBOut.Size);
+  WriteDerEncoded(TAsn1Tags.Constructed or TAsn1Tags.Sequence, LTemp);
+end;
+
+procedure TDerSequenceGenerator.Close();
+begin
+  DoClose();
+end;
+
+end.

+ 0 - 439
CryptoLib/src/Asn1/ClpAsn1Objects.pas

@@ -1425,109 +1425,6 @@ type
     function GetEncodingImplicit(AEncoding, ATagClass, ATagNo: Int32): IAsn1Encoding; override;
   end;
 
-  /// <summary>
-  /// Abstract base class for ASN.1 generators.
-  /// </summary>
-  TAsn1Generator = class abstract(TInterfacedObject, IAsn1Generator)
-  strict private
-    FOut: TStream;
-    FClosed: Boolean;
-  strict protected
-    constructor Create(AOutStream: TStream);
-    function GetOut: TStream; inline;
-    function GetIsClosed: Boolean; inline;
-    property &Out: TStream read GetOut;
-    procedure Finish(); virtual; abstract;
-    procedure DoClose();
-  public
-    destructor Destroy(); override;
-    procedure AddObject(const AObj: IAsn1Encodable); overload; virtual; abstract;
-    procedure AddObject(const AObj: IAsn1Object); overload; virtual; abstract;
-    function GetRawOutputStream(): TStream; virtual; abstract;
-    procedure Close(); virtual; abstract;
-    property IsClosed: Boolean read GetIsClosed;
-    class function InheritConstructedFlag(AIntoTag, AFromTag: Int32): Int32; static;
-  end;
-
-  /// <summary>
-  /// Abstract base class for BER generators.
-  /// </summary>
-  TBerGenerator = class abstract(TAsn1Generator, IBerGenerator)
-  strict private
-    FTagged, FIsExplicit: Boolean;
-    FTagNo: Int32;
-  strict protected
-    constructor Create(AOutStream: TStream); overload;
-    constructor Create(AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean); overload;
-
-    procedure WriteHdr(ATag: Int32);
-    procedure WriteBerHeader(ATag: Int32);
-    procedure WriteBerBody(AContentStream: TStream);
-    procedure WriteBerEnd();
-    procedure Finish(); override;
-  public
-    procedure AddObject(const AObj: IAsn1Encodable); override;
-    procedure AddObject(const AObj: IAsn1Object); override;
-    function GetRawOutputStream(): TStream; override;
-    procedure Close(); override;
-  end;
-
-  /// <summary>
-  /// BER sequence generator.
-  /// </summary>
-  TBerSequenceGenerator = class(TBerGenerator, IBerSequenceGenerator)
-  public
-    constructor Create(AOutStream: TStream); overload;
-    constructor Create(AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean); overload;
-  end;
-
-  /// <summary>
-  /// BER octet string generator.
-  /// </summary>
-  TBerOctetStringGenerator = class(TBerGenerator, IBerOctetStringGenerator)
-  public
-    constructor Create(AOutStream: TStream); overload;
-    constructor Create(AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean); overload;
-    function GetOctetOutputStream(): TStream; overload;
-    function GetOctetOutputStream(ABufSize: Int32): TStream; overload;
-    function GetOctetOutputStream(const ABuf: TCryptoLibByteArray): TStream; overload;
-  end;
-
-  /// <summary>
-  /// Abstract base class for DER generators.
-  /// </summary>
-  TDerGenerator = class abstract(TAsn1Generator, IDerGenerator)
-  strict private
-    FTagged, FIsExplicit: Boolean;
-    FTagNo: Int32;
-    class procedure WriteLength(const AOutStr: TStream; ALength: Int32); static;
-  strict protected
-    constructor Create(const AOutStream: TStream); overload;
-    constructor Create(const AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean); overload;
-  public
-    procedure WriteDerEncoded(ATag: Int32; const ABytes: TCryptoLibByteArray); overload;
-    class procedure WriteDerEncoded(const AOutStream: TStream; ATag: Int32; const ABytes: TCryptoLibByteArray); overload; static;
-    class procedure WriteDerEncoded(const AOutStr: TStream; ATag: Int32; const AInStr: TStream); overload; static;
-  end;
-
-  /// <summary>
-  /// DER sequence generator.
-  /// </summary>
-  TDerSequenceGenerator = class(TDerGenerator, IDerSequenceGenerator)
-  strict private
-    FBOut: TMemoryStream;
-  strict protected
-    procedure Finish(); override;
-  public
-    constructor Create(AOutStream: TStream); overload;
-    constructor Create(AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean); overload;
-    destructor Destroy(); override;
-    procedure AddObject(const AObj: IAsn1Encodable); overload; override;
-    procedure AddObject(const AObj: IAsn1Object); overload; override;
-    function GetRawOutputStream(): TStream; override;
-    procedure Close(); override;
-  end;
-
   /// <summary>
   /// Parser for DER external objects.
   /// </summary>
@@ -5824,342 +5721,6 @@ begin
       TBerSequence.FromVector(AContentsElements));
 end;
 
-{ TAsn1Generator }
-
-constructor TAsn1Generator.Create(AOutStream: TStream);
-begin
-  inherited Create;
-  if AOutStream = nil then
-    raise EArgumentNilCryptoLibException.Create('outStream');
-  FOut := AOutStream;
-  FClosed := False;
-end;
-
-destructor TAsn1Generator.Destroy;
-begin
-  DoClose();
-  inherited Destroy;
-end;
-
-procedure TAsn1Generator.DoClose();
-begin
-  if (FOut <> nil) and (not FClosed) then
-  begin
-    FClosed := True;
-    try
-      Finish();
-    finally
-      FOut := nil;  // Prevent any further access to the stream
-    end;
-  end;
-end;
-
-function TAsn1Generator.GetIsClosed: Boolean;
-begin
-  Result := FClosed;
-end;
-
-function TAsn1Generator.GetOut: TStream;
-begin
-  if FOut = nil then
-    raise EInvalidOperationCryptoLibException.Create('Stream is null');
-  Result := FOut;
-end;
-
-class function TAsn1Generator.InheritConstructedFlag(AIntoTag, AFromTag: Int32): Int32;
-begin
-  if ((AFromTag and TAsn1Tags.Constructed) <> 0) then
-    Result := AIntoTag or TAsn1Tags.Constructed
-  else
-    Result := AIntoTag and (not TAsn1Tags.Constructed);
-end;
-
-{ TBerGenerator }
-
-constructor TBerGenerator.Create(AOutStream: TStream);
-begin
-  inherited Create(AOutStream);
-end;
-
-constructor TBerGenerator.Create(AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean);
-begin
-  inherited Create(AOutStream);
-  FTagged := True;
-  FIsExplicit := AIsExplicit;
-  FTagNo := ATagNo;
-end;
-
-procedure TBerGenerator.AddObject(const AObj: IAsn1Encodable);
-begin
-  AObj.EncodeTo(&Out);
-end;
-
-procedure TBerGenerator.AddObject(const AObj: IAsn1Object);
-begin
-  AObj.EncodeTo(&Out);
-end;
-
-procedure TBerGenerator.Finish();
-begin
-  WriteBerEnd();
-end;
-
-procedure TBerGenerator.Close();
-begin
-  DoClose();
-end;
-
-function TBerGenerator.GetRawOutputStream(): TStream;
-begin
-  Result := &Out;
-end;
-
-procedure TBerGenerator.WriteBerBody(AContentStream: TStream);
-begin
-  TStreamUtilities.PipeAll(AContentStream, &Out);
-end;
-
-procedure TBerGenerator.WriteBerEnd();
-begin
-  &Out.WriteByte($00);
-  &Out.WriteByte($00);
-
-  if (FTagged and FIsExplicit) then // write extra end for tag header
-  begin
-    &Out.WriteByte($00);
-    &Out.WriteByte($00);
-  end;
-end;
-
-procedure TBerGenerator.WriteBerHeader(ATag: Int32);
-begin
-  if not FTagged then
-  begin
-    WriteHdr(ATag);
-  end
-  else if FIsExplicit then
-  begin
-    {
-     * X.690-0207 8.14.2. If implicit tagging [..] was not used [..], the encoding shall be constructed
-     * and the contents octets shall be the complete base encoding.
-     }
-    WriteHdr(FTagNo or TAsn1Tags.ContextSpecific or TAsn1Tags.Constructed);
-    WriteHdr(ATag);
-  end
-  else
-  begin
-    {
-     * X.690-0207 8.14.3. If implicit tagging was used [..], then: a) the encoding shall be constructed
-     * if the base encoding is constructed, and shall be primitive otherwise; and b) the contents octets
-     * shall be [..] the contents octets of the base encoding.
-     }
-    WriteHdr(InheritConstructedFlag(FTagNo or TAsn1Tags.ContextSpecific, ATag));
-  end;
-end;
-
-procedure TBerGenerator.WriteHdr(ATag: Int32);
-begin
-  &Out.WriteByte(Byte(ATag));
-  &Out.WriteByte($80);
-end;
-
-{ TBerSequenceGenerator }
-
-constructor TBerSequenceGenerator.Create(AOutStream: TStream);
-begin
-  inherited Create(AOutStream);
-  WriteBerHeader(TAsn1Tags.Constructed or TAsn1Tags.Sequence);
-end;
-
-constructor TBerSequenceGenerator.Create(AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean);
-begin
-  inherited Create(AOutStream, ATagNo, AIsExplicit);
-  WriteBerHeader(TAsn1Tags.Constructed or TAsn1Tags.Sequence);
-end;
-
-{ TBerOctetStringGenerator }
-
-constructor TBerOctetStringGenerator.Create(AOutStream: TStream);
-begin
-  inherited Create(AOutStream);
-  WriteBerHeader(TAsn1Tags.Constructed or TAsn1Tags.OctetString);
-end;
-
-constructor TBerOctetStringGenerator.Create(AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean);
-begin
-  inherited Create(AOutStream, ATagNo, AIsExplicit);
-  WriteBerHeader(TAsn1Tags.Constructed or TAsn1Tags.OctetString);
-end;
-
-function TBerOctetStringGenerator.GetOctetOutputStream(): TStream;
-var
-  LBuf: TCryptoLibByteArray;
-begin
-  System.SetLength(LBuf, 1000);
-  Result := GetOctetOutputStream(LBuf); // limit for CER encoding.
-end;
-
-function TBerOctetStringGenerator.GetOctetOutputStream(ABufSize: Int32): TStream;
-var
-  LBuf: TCryptoLibByteArray;
-begin
-  if ABufSize < 1 then
-    Result := GetOctetOutputStream()
-  else
-  begin
-    System.SetLength(LBuf, ABufSize);
-    Result := GetOctetOutputStream(LBuf);
-  end;
-end;
-
-function TBerOctetStringGenerator.GetOctetOutputStream(const ABuf: TCryptoLibByteArray): TStream;
-begin
-  Result := TAsn1BufferedBerOctetStream.Create(GetRawOutputStream(), ABuf);
-end;
-
-{ TDerGenerator }
-
-constructor TDerGenerator.Create(const AOutStream: TStream);
-begin
-  inherited Create(AOutStream);
-end;
-
-constructor TDerGenerator.Create(const AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean);
-begin
-  inherited Create(AOutStream);
-  FTagged := True;
-  FIsExplicit := AIsExplicit;
-  FTagNo := ATagNo;
-end;
-
-class procedure TDerGenerator.WriteDerEncoded(const AOutStream: TStream; ATag: Int32; const ABytes: TCryptoLibByteArray);
-begin
-  AOutStream.WriteByte(Byte(ATag));
-  WriteLength(AOutStream, System.Length(ABytes));
-  if System.Length(ABytes) > 0 then
-    AOutStream.Write(ABytes[0], System.Length(ABytes));
-end;
-
-class procedure TDerGenerator.WriteDerEncoded(const AOutStr: TStream; ATag: Int32; const AInStr: TStream);
-begin
-  WriteDerEncoded(AOutStr, ATag, TStreamUtilities.ReadAll(AInStr));
-end;
-
-class procedure TDerGenerator.WriteLength(const AOutStr: TStream; ALength: Int32);
-var
-  LSize, LVal, I: Int32;
-begin
-  if ALength > 127 then
-  begin
-    LSize := 1;
-    LVal := ALength;
-    LVal := TBitUtilities.Asr32(LVal, 8);
-    while LVal <> 0 do
-    begin
-      System.Inc(LSize);
-      LVal := TBitUtilities.Asr32(LVal, 8);
-    end;
-    AOutStr.WriteByte(Byte(LSize or $80));
-    I := (LSize - 1) * 8;
-    while I >= 0 do
-    begin
-      AOutStr.WriteByte(Byte(TBitUtilities.Asr32(ALength, I)));
-      System.Dec(I, 8);
-    end;
-  end
-  else
-  begin
-    AOutStr.WriteByte(Byte(ALength));
-  end;
-end;
-
-procedure TDerGenerator.WriteDerEncoded(ATag: Int32; const ABytes: TCryptoLibByteArray);
-var
-  LBOut: TMemoryStream;
-  LTemp: TCryptoLibByteArray;
-begin
-  if not FTagged then
-  begin
-    WriteDerEncoded(&Out, ATag, ABytes);
-  end
-  else if FIsExplicit then
-  begin
-    {
-     * X.690-0207 8.14.2. If implicit tagging [..] was not used [..], the encoding shall be constructed
-     * and the contents octets shall be the complete base encoding.
-     }
-    LBOut := TMemoryStream.Create();
-    try
-      WriteDerEncoded(LBOut, ATag, ABytes);
-      LBOut.Position := 0;
-      System.SetLength(LTemp, LBOut.Size);
-      LBOut.Read(LTemp[0], LBOut.Size);
-      WriteDerEncoded(&Out, FTagNo or TAsn1Tags.ContextSpecific or TAsn1Tags.Constructed, LTemp);
-    finally
-      LBOut.Free;
-    end;
-  end
-  else
-  begin
-    {
-     * X.690-0207 8.14.3. If implicit tagging was used [..], then: a) the encoding shall be constructed
-     * if the base encoding is constructed, and shall be primitive otherwise; and b) the contents octets
-     * shall be [..] the contents octets of the base encoding.
-     }
-    WriteDerEncoded(&Out, InheritConstructedFlag(FTagNo or TAsn1Tags.ContextSpecific, ATag), ABytes);
-  end;
-end;
-
-{ TDerSequenceGenerator }
-
-constructor TDerSequenceGenerator.Create(AOutStream: TStream);
-begin
-  inherited Create(AOutStream);
-  FBOut := TMemoryStream.Create();
-end;
-
-constructor TDerSequenceGenerator.Create(AOutStream: TStream; ATagNo: Int32; AIsExplicit: Boolean);
-begin
-  inherited Create(AOutStream, ATagNo, AIsExplicit);
-  FBOut := TMemoryStream.Create();
-end;
-
-destructor TDerSequenceGenerator.Destroy;
-begin
-  FBOut.Free;
-  inherited Destroy;
-end;
-
-procedure TDerSequenceGenerator.AddObject(const AObj: IAsn1Encodable);
-begin
-  AObj.EncodeTo(FBOut, TAsn1Encodable.Der);
-end;
-
-procedure TDerSequenceGenerator.AddObject(const AObj: IAsn1Object);
-begin
-  (AObj as IAsn1Encodable).EncodeTo(FBOut, TAsn1Encodable.Der);
-end;
-
-function TDerSequenceGenerator.GetRawOutputStream(): TStream;
-begin
-  Result := FBOut;
-end;
-
-procedure TDerSequenceGenerator.Finish();
-var
-  LTemp: TCryptoLibByteArray;
-begin
-  FBOut.Position := 0;
-  System.SetLength(LTemp, FBOut.Size);
-  FBOut.Read(LTemp[0], FBOut.Size);
-  WriteDerEncoded(TAsn1Tags.Constructed or TAsn1Tags.Sequence, LTemp);
-end;
-
-procedure TDerSequenceGenerator.Close();
-begin
-  DoClose();
-end;
-
 { TDerExternalParser }
 
 constructor TDerExternalParser.Create(const AParser: IAsn1StreamParser);

+ 86 - 0
CryptoLib/src/Interfaces/Asn1/ClpIAsn1Generators.pas

@@ -0,0 +1,86 @@
+{ *********************************************************************************** }
+{ *                              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 ClpIAsn1Generators;
+
+{$I ..\..\Include\CryptoLib.inc}
+
+interface
+
+uses
+  Classes,
+  ClpCryptoLibTypes,
+  ClpIAsn1Core;
+
+type
+  /// <summary>
+  /// Interface for ASN.1 generators.
+  /// </summary>
+  IAsn1Generator = interface(IInterface)
+    ['{B1C2D3E4-F5A6-B7C8-D9E0-F1A2B3C4D5E6}']
+    procedure AddObject(const AObj: IAsn1Encodable);
+    function GetRawOutputStream(): TStream;
+    procedure Close();
+  end;
+
+  /// <summary>
+  /// Interface for BER generators.
+  /// </summary>
+  IBerGenerator = interface(IAsn1Generator)
+    ['{C2D3E4F5-A6B7-C8D9-E0F1-A2B3C4D5E6F7}']
+    procedure WriteHdr(ATag: Int32);
+    procedure WriteBerHeader(ATag: Int32);
+    procedure WriteBerBody(AContentStream: TStream);
+    procedure WriteBerEnd();
+  end;
+
+  /// <summary>
+  /// Interface for BER sequence generators.
+  /// </summary>
+  IBerSequenceGenerator = interface(IBerGenerator)
+    ['{5FF489CE-2A51-4FE5-A961-99AE423537CE}']
+  end;
+
+  /// <summary>
+  /// Interface for BER octet string generators.
+  /// </summary>
+  IBerOctetStringGenerator = interface(IBerGenerator)
+    ['{D3E4F5A6-B7C8-D9E0-F1A2-B3C4D5E6F7A8}']
+    function GetOctetOutputStream(): TStream; overload;
+    function GetOctetOutputStream(ABufSize: Int32): TStream; overload;
+    function GetOctetOutputStream(const ABuf: TCryptoLibByteArray): TStream; overload;
+  end;
+
+  /// <summary>
+  /// Interface for DER generators.
+  /// </summary>
+  IDerGenerator = interface(IAsn1Generator)
+    ['{E4F5A6B7-C8D9-E0F1-A2B3-C4D5E6F7A8B9}']
+    procedure WriteDerEncoded(ATag: Int32; const ABytes: TCryptoLibByteArray);
+  end;
+
+  /// <summary>
+  /// Interface for DER sequence generators.
+  /// </summary>
+  IDerSequenceGenerator = interface(IDerGenerator)
+    ['{F5A6B7C8-D9E0-F1A2-B3C4-D5E6F7A8B9C0}']
+    procedure AddObject(const AObj: IAsn1Object); overload;
+  end;
+
+implementation
+
+end.

+ 0 - 55
CryptoLib/src/Interfaces/Asn1/ClpIAsn1Objects.pas

@@ -835,61 +835,6 @@ type
   end;
 
 
-  /// <summary>
-  /// Interface for ASN.1 generators.
-  /// </summary>
-  IAsn1Generator = interface(IInterface)
-    ['{B1C2D3E4-F5A6-B7C8-D9E0-F1A2B3C4D5E6}']
-    procedure AddObject(const AObj: IAsn1Encodable);
-    function GetRawOutputStream(): TStream;
-    procedure Close();
-  end;
-
-  /// <summary>
-  /// Interface for BER generators.
-  /// </summary>
-  IBerGenerator = interface(IAsn1Generator)
-    ['{C2D3E4F5-A6B7-C8D9-E0F1-A2B3C4D5E6F7}']
-    procedure WriteHdr(ATag: Int32);
-    procedure WriteBerHeader(ATag: Int32);
-    procedure WriteBerBody(AContentStream: TStream);
-    procedure WriteBerEnd();
-  end;
-
-  /// <summary>
-  /// Interface for BER sequence generators.
-  /// </summary>
-  IBerSequenceGenerator = interface(IBerGenerator)
-    ['{5FF489CE-2A51-4FE5-A961-99AE423537CE}']
-  end;
-
-  /// <summary>
-  /// Interface for BER octet string generators.
-  /// </summary>
-  IBerOctetStringGenerator = interface(IBerGenerator)
-    ['{D3E4F5A6-B7C8-D9E0-F1A2-B3C4D5E6F7A8}']
-    function GetOctetOutputStream(): TStream; overload;
-    function GetOctetOutputStream(ABufSize: Int32): TStream; overload;
-    function GetOctetOutputStream(const ABuf: TCryptoLibByteArray): TStream; overload;
-  end;
-
-  /// <summary>
-  /// Interface for DER generators.
-  /// </summary>
-  IDerGenerator = interface(IAsn1Generator)
-    ['{E4F5A6B7-C8D9-E0F1-A2B3-C4D5E6F7A8B9}']
-    procedure WriteDerEncoded(ATag: Int32; const ABytes: TCryptoLibByteArray);
-  end;
-
-  /// <summary>
-  /// Interface for DER sequence generators.
-  /// </summary>
-  IDerSequenceGenerator = interface(IDerGenerator)
-    ['{F5A6B7C8-D9E0-F1A2-B3C4-D5E6F7A8B9C0}']
-    procedure AddObject(const AObj: IAsn1Object); overload;
-  end;
-
-
   /// <summary>
   /// Interface for ASN.1 types.
   /// </summary>