AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

RC4 Stromdekorierer

Ein Thema von maximov · begonnen am 20. Feb 2005 · letzter Beitrag vom 23. Apr 2005
Antwort Antwort
Benutzerbild von maximov
maximov

Registriert seit: 2. Okt 2003
Ort: Hamburg
548 Beiträge
 
Delphi 2005 Professional
 
#1

RC4 Stromdekorierer

  Alt 20. Feb 2005, 13:28
RC4 und RCx Stromdekorierer

Die TRC?StreamDecorator klassen machen es möglich, die funktionalitat jedes beliebigen streams, um eine RC4 oder RCx (ein RC4 derivat von Hagen) verschlüsselung (siehe hagEnCode.pas und RCx.pas) zu erweitern. Wobei die erweiterung der funktionalität nicht durch eine starre ableitung realisiert wird, sondern durch das Dekorierer-Entwurfsmuster, dh. der dekorierer verpackt (wrappen) einen beliebigen stream und delegiert alle aufrufe an ihn weiter, oder modifiziert sie (lesen, schreiben etc). Die lese-und schreibaufrufe werden abgefangen und die kodierung durchgeführt. Wobei die schnittstelle nach aussen die gleiche bleibt, damit der dekorierer wie ein ganz normaler stream behandelt werden kann.

Allgemeine informationen zum prinzip des dekorierers: http://de.wikipedia.org/wiki/Dekorierer

In diesen stromverschlüsselungen, ist ein springen im strom nicht möglich, da sonst der aktuelle kontext nicht mehr stimmen würde und somit der output unbrauchbar wäre. Dh. bei expliziten Seek-aufrufen wird die exception ERCSeekNotAllowed geschmissen!

Die RC4 kodierung von Hagen Redmann kann man hier einsehen -> HagEnCode.pas
Und die allgemeine RCx-Kodierung findet man hier.


Die verwendung demonstriert dann auch ganz gut die schönheit dieses konzepts:

Delphi-Quellcode:
uses RCStreamDeco;

...

procedure TForm1.SaveBuClick(Sender: TObject);
var Stream:TRCxStreamDecorator;
begin
  // variante 1 der Erzeugung des RCx-Stream-Dekorierers
  // und des eigentlichen streams.
  // Der RCx-stream verhalt sich nun wie ein fileStream, nur
  // dass er eben verschlüsseln kann, wenn er will (EnCodeMode).
  stream := TRCxStreamDecorator.Create(TFileStream.Create(Filename, fmCreate));
  with Stream do
  try
    // Da wir explizit mit TRCxStreamDecorator zu tun haben,
    // konnen wir das Passwort, welches zum Erstellen der SandBox benutzt wird,
    // nachträglich setzen.
    Password := 'Password';

    // Zufällige Zeichenfolge (salt) schreiben, damit der restliche codierte
    // Text, bei jeder Verschlüsselung andere Resultate ergibt.
    // Nur beim RCx verfugbar.
    WriteSalt;
    // RC4 liefert immer, bei gleichem Text, gleiche Resultate.
      
    // Memo1 kodieren und in Datei speichern!
    Memo1.Lines.SaveToStream(Stream);
  finally
    // Wenn der Parameter des konstruktors 'OwnsStream' auf true ist (default)
    // dann erlauben es die Besitzverhältnisse, dass der Dekorierer den
    // FileStream selbstständig freigibt.
    Stream.Free;
  end;
end;

procedure TForm1.LoadBuClick(Sender: TObject);
var Stream:TStream;
begin
  // Variante 2 der Erzeugung des RCx-Stream-Dekorierers
  // und des eigentlichen Streams.
  // Hier arbeiten wir allgemein mit einem TStream und wissen später nicht,
  // um was für einen Stream es sich handelt. Deshalb müssen alle nötigen
  // Informationen schon im Konstruktor mitgegeben werden.
  stream := TRCxStreamDecorator.Create(
  TFileStream.Create(fileName, fmOpenRead), // der konkrete stream
    true, // ownsStream (auto-free)
    'Password'                                // Passwort fur die SandBox
    emEncodeWriting   ); // schreibend kodieren
  try
    // hier noch das 'salt' lesen, um es zu entfernen.
    // Wird versucht es an einer falschen Stelle zu lesen, so
    // wird eine 'EInvalidDecryption' geworfen
    (Stream as TRCxStreamDecorator).ReadSalt;
    // wir casten hier nur, weil der Stream allgemein ist.
    // in diesem Fall würde sich eine Lösung wie bei WriteBuClick anbieten.
      
    // Daten aus datei laden ins Memo1 laden und dabei dekodieren!
    Memo1.Lines.LoadFromStream(Stream);
  finally
    // Wenn der Parameter des Konstruktors 'OwnsStream' auf true ist (default)
    // dann erlauben es die Besitzverhaltnisse, dass der Dekorierer den
    // FileStream selbstständig freigibt. Andernfalls musste man sich selbst
    // darum kummmern
    Stream.Free;
  end;
end;
Wobei man statt TRCxStreamDecorator auch TRC4StreamDecorator nehmen kann, wenn man eine normale, unsicherere RC4 Verschlüsselung benutzen will. Keinesfalls aber sollte man TRCStreamDecorator benutzen, denn diese Klasse ist abstrakt!

Genaue Erläuterungen über RCx entnehme man bitte Hagens Anmerkungen.


Der Unit
Delphi-Quellcode:
unit RCStreamDeco;


// written by maximov 19.02.2005

// Die TRC?StreamDecorator Klassen machen es möglich, die Funktionalitat jedes
// beliebigen Streams, um eine RC4 oder RCx (ein RC4 derivat von Hagen)
// Verschlüsselung (siehe hagEnCode.pas und RCx.pas) zu
// erweitern. Wobei die Erweiterung der Funktionalitat nicht durch eine starre
// Ableitung realisiert wird, sondern durch das Dekorierer-Entwurfsmuster,
// dh. der Dekorierer verpackt (wrappen) einen beliebigen Stream und delegiert
// alle Aufrufe an ihn weiter, oder modifiziert sie (lesen, schreiben).
// Die Lese-und Schreibaufrufe werden abgefangen und die Kodierung durchgefuhrt.
// Wobei die Schnittstelle nach außsen die gleiche bleibt, damit der Dekorierer wie
// ein ganz normaler Stream behandelt werden kann.

// Allgemeine informationen zum Prinzip des Dekorierers:
// [url]http://de.wikipedia.org/wiki/Dekorierer[/url]

// In diesen Stromverschlüsselungen, ist ein Springen im Strom nicht moglich,
// da sonst der aktuelle Kontext nicht mehr stimmen würde und somit der Output
// unbrauchbar ware. Dh. bei expliziten Seek aufrufen wird die Exception
// ERCSeekNotAllowed geschmissen!

// Die RC4 Kodierung von Hagen Redmann kann man hier einsehen -> HagEnCode.pas
// [url]http://www.delphipraxis.net/topic30830_rc4verschluesselung.html[/url]

// 20.02.2005 - Veröffentlichung!
// 21.02.2005 - Seek Exception, um im richtigen Kontext zu bleiben.
// 21.02.2005 - Temp-Buffer in Read entfernt.
// 25.02.2005 - Abstrakte Oberklasse geschaffen.
// 25.02.2005 - Hangens RC4 derivat RCx integriert.

interface

uses classes, hagEnCode, RCx, sysUtils;

type
  ERCSeekNotAllowed = class(Exception);
  EInvalidDecryption = class(Exception);

  TEncodeMode = (emEncodeWriting, emEncodeReading);

  TRCStreamDecorator = class(TStream)
  private
    FStream:TStream;
    FOwnsStream:boolean;
    FEncodeMode:TEncodeMode;
  protected
    function GetSize: Int64; override;
    procedure SetSize(const NewSize: Int64); overload; override;
    procedure SetSize(NewSize: Longint); overload; override;
    procedure Encode(const source; var dest; Count:integer); virtual; abstract;
    procedure Decode(const source; var dest; Count:integer); virtual; abstract;
    procedure SetPassword(const Value: string); virtual; abstract;
  public
    constructor Create(aStream:TStream; OwnsStream:boolean = true); overload;
    constructor Create(aStream:TStream; OwnsStream:boolean;
      const aPassword:string; theEncodeMode:TEncodeMode = emEncodeWriting); overload;
    destructor Destroy; override;
    function Write(const Buffer; Count: Integer): Integer; override;
    function Read(var Buffer; Count: Integer): Integer; override;
    function Seek(Offset: Integer; Origin: Word): Integer; overload; override;
    function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; overload; override;
    property Password:string write SetPassword;
    property EncodeMode:TEncodeMode read FEncodeMode write FEncodeMode;
  end;


  TRC4StreamDecorator = class(TRCStreamDecorator)
  private
    FRC4:TRC4Context;
    procedure SetSandbox(const Value: TRC4Context);
  protected
    procedure Encode(const source; var dest; Count: Integer); override;
    procedure Decode(const source; var dest; Count: Integer); override;
    procedure SetPassword(const Value: String); override;
  public
    destructor Destroy; override;
    property Sandbox:TRC4Context write SetSandbox;
  end;

  TRCxStreamDecorator = class(TRCStreamDecorator)
  private
    FRCx:TRCxContext;
    procedure SetSandbox(const Value: TRCxContext);
  protected
    procedure Encode(const source; var dest; Count: Integer); override;
    procedure Decode(const source; var dest; Count: Integer); override;
    procedure SetPassword(const Value: String); override;
  public
    destructor Destroy; override;
    procedure WriteSalt(Size: Byte = 16);
    procedure ReadSalt;
    property Sandbox:TRCxContext write SetSandbox;
  end;

implementation

procedure ProtectString(var Value: String);
begin
  FillChar(Pointer(Value)^, Length(Value), 0);
end;

function Checksum(const Value: String): Byte;
var
  I: Integer;
begin
  Result := 0;
  for I := 1 to Length(Value) do
    Inc(Result, Result xor Ord(Value[I]));
end;

{ TRCStreamDecorator }

constructor TRCStreamDecorator.Create(aStream: TStream; OwnsStream:boolean;
  const aPassword:string; theEncodeMode:TEncodeMode = emEncodeWriting);
begin
  Create(aStream, OwnsStream);
  Password := aPassword;
  EncodeMode := theEncodeMode;
end;

constructor TRCStreamDecorator.Create(aStream: TStream;
  OwnsStream: boolean);
begin
  Assert(assigned(aStream),'The decorated stream is not assigned');
  FStream := aStream;
  FOwnsStream := OwnsStream;
  FEncodeMode := emEncodeWriting;
end;

destructor TRCStreamDecorator.Destroy;
begin
  if FOwnsStream then
    FStream.Free;
  FStream := nil;   
  inherited;
end;

function TRCStreamDecorator.Read(var Buffer; Count: Integer): Integer;
begin
  result := FStream.Read(Buffer, count);
  case EncodeMode of
    emEncodeWriting: Decode(Buffer, Buffer, Result); // abstrakter aufruf
    emEncodeReading: Encode(Buffer, Buffer, Result); // abstrakter aufruf
  end;
end;

function TRCStreamDecorator.Write(const Buffer; Count: Integer): Integer;
var
  temp:pointer;
begin
  GetMem(temp, count);
  case EncodeMode of
    emEncodeWriting: Encode(Buffer, temp^, Count); // abstrakter aufruf
    emEncodeReading: Decode(Buffer, temp^, Count); // abstrakter aufruf
  end;
  result := FStream.Write(temp^, count);
  FreeMem(temp, count);
end;

function TRCStreamDecorator.GetSize: Int64;
begin
  result := FStream.Size;
end;

procedure TRCStreamDecorator.SetSize(const NewSize: Int64);
begin
  FStream.Size := NewSize;
end;

procedure TRCStreamDecorator.SetSize(NewSize: Integer);
begin
  FStream.Size := NewSize;
end;

function TRCStreamDecorator.Seek(Offset: Integer; Origin: Word): Integer;
begin
  result := Seek(Int64(Offset), TSeekOrigin(Origin));
end;

function TRCStreamDecorator.Seek(const Offset: Int64;
  Origin: TSeekOrigin): Int64;
begin
  if (Origin = soCurrent) and (Offset = 0) then
    Result := FStream.Seek(Offset, Origin)
  else
    raise ERCSeekNotAllowed.Create('Seeking is not allowed');
end;

{ TRC4StreamDecorator }

destructor TRC4StreamDecorator.Destroy;
begin
  RC4Done(FRC4);
  inherited;
end;

procedure TRC4StreamDecorator.Encode(const source; var dest; Count: Integer);
begin
  RC4Code(FRC4, source, dest, Count);
end;

procedure TRC4StreamDecorator.Decode(const source; var dest; Count: Integer);
begin
  RC4Code(FRC4, source, dest, Count);
end;

procedure TRC4StreamDecorator.SetPassword(const Value: String);
begin
  RC4Init(FRC4,Value);
end;

procedure TRC4StreamDecorator.SetSandbox(const Value: TRC4Context);
begin
  FRC4 := Value;
end;

{ TRCxStreamDecorator }

destructor TRCxStreamDecorator.Destroy;
begin
  RCxDone(FRCx);
  inherited;
end;

procedure TRCxStreamDecorator.Encode(const source; var dest; Count: Integer);
begin
  RCxEncode(FRCx, source, dest, Count);
end;

procedure TRCxStreamDecorator.Decode(const source; var dest; Count: Integer);
begin
  RCxDecode(FRCx, source, dest, Count);
end;

procedure TRCxStreamDecorator.SetPassword(const Value: String);
begin
  RCxInit(FRCx, Value);
end;

procedure TRCxStreamDecorator.SetSandbox(const Value: TRCxContext);
begin
  FRCx := Value;
end;

procedure TRCxStreamDecorator.WriteSalt(Size: Byte = 16);
var
  Salt: String;
  CRC: Byte;
begin
  Salt := RCxRandomString(Size);
  try
    WriteBuffer(Size, SizeOf(Size));
    WriteBuffer(Pointer(Salt)^, Size);
    CRC := Checksum(Salt);
    WriteBuffer(CRC, SizeOf(CRC));
  finally
    ProtectString(Salt);
  end;
end;

procedure TRCxStreamDecorator.ReadSalt;
var
  Salt: String;
  CRC,Size: Byte;
begin
  ReadBuffer(Size, SizeOf(Size));
  SetLength(Salt, Size);
  try
    ReadBuffer(Pointer(Salt)^, Size);
    ReadBuffer(CRC, SizeOf(CRC));
    if CRC <> Checksum(Salt) then
      raise EInvalidDecryption.Create('Invalid decryption');
  finally
    ProtectString(Salt);
  end;
end;

end.

Bitte sagt mir was ihr davon haltet oder ob ihr damit was anfangen könnt.

Und dank an Hagen für die Kodierung und die Optimierungen.

[edit=Chakotay1308]Neue Version des Eintrages eingefügt. Mfg, Chakotay1308[/edit]
[edit=Chakotay1308]Anhang geupdatet. Mfg, Chakotay1308[/edit]
[edit=Chakotay1308]Einige Anpassungen. Mfg, Chakotay1308[/edit]
[edit=Matze]Zig Rechtschreibfehler behoben und Code korrekt formatiert. Mfg, Matze[/edit]
Angehängte Dateien
Dateityp: pas rcstreamdeco_150.pas (8,0 KB, 209x aufgerufen)
mâxîmôv.

{KDT}
  Mit Zitat antworten Zitat
CalganX

Registriert seit: 21. Jul 2002
Ort: Bonn
5.403 Beiträge
 
Turbo Delphi für Win32
 
#2

Re: RC4 Stromdekorierer

  Alt 23. Apr 2005, 00:32
Von maximov kommt noch folgende Erweiterung:

Mit dem RC-Stromdekorierer INIs verschlüsseln

betreff: RC4 Stromdekorierer

Kürzlich erhielt ich dazu folgende frage...

Zitat von Jolomino:
hallo,
habe mir mal deinen post angeschaut, das dekodieren und kodieren funzt auch ganz wunderbar. aber könntest du mir evtl. verraten, wie ich dieses auf einer ini-datei anwende? bekomme es leider nicht hin. oder ist es womöglich überhaupt nicht auf ini´s anwendbar...

Die antwort:

Hallo jolomino,

normalerweise wäre dein vorhaben nicht möglich, da TIniFile kein stream ist. Der dekorator braucht aber nunmal ein stream, den er umschliessen kann. Allerdings gibt es die klasse TMemIniFile, welche für das speichern Stringlisten verwendet, die man dann verschlüsseln kann. Also machen wir eine neue klasse. Allerdings müssen dafür einige methoden ersetzt werden. LoadValue zb. ist nicht virtuell und kann daher nicht überschrieben werden, also Kann man einfach die stellen ersetzen wo loadValue aufgerufen wird und dann das neue LoadValue aufrufen. In demfall müssen also Create und Rename ersetzwerden. UpdateFile ist virtuell und kann überschrieben werden, ohne es zu vererben.

WICHTIG: die RCx klasse von hagen wird auch benötigt.

Also hier die klasse:

Delphi-Quellcode:

// RCx inifile unit.
// written by maximov (max hue) 2005.
// Inspiration by Jolomino.
// free for all, without warrenty.
// 12.04.2005 - fixes


unit RCmxIni;

interface

uses
   inifiles;

type
   TRCxIniFile = class(TMemIniFile)
   private
      FFileName:string;
      FPassword:string;
      procedure LoadValues;
   protected
   public
      constructor Create(const FileName, PassWord: string);
      procedure UpdateFile; override;
      procedure Rename(const FileName: string; Reload: Boolean);
      destructor Destroy; override;
   end;

implementation

uses
   classes,
   RCStreamDeco,
   sysUtils;


constructor TRCxIniFile.Create(const FileName, PassWord: string);
begin
   FFileName := FileName;
   FPassWord := PassWord;

   // instance sauber erzeugen, aber durch '' keine values laden
   inherited Create('');

   // neues loadValue eingeführt, mit RCx
   LoadValues;
end;

destructor TRCxIniFile.Destroy;
begin
   FPassword := '';
   inherited;
end;

procedure TRCxIniFile.Rename(const FileName: string; Reload: Boolean);
begin
   FFileName := FileName;
   if Reload then
      LoadValues;
end;

procedure TRCxIniFile.LoadValues;
var
   List: TStringList;
   rcxStream:TRCxStreamDecorator;
begin
   if (FFileName <> '') and FileExists(FFileName) then
   begin
      List := TStringList.Create;
      try
         // Filestream, von RCx-dekorierer gewrappt, erzeugen.
         rcxStream := TRCxStreamDecorator.Create(
            TFileStream.Create(FFileName, fmOpenRead or fmShareDenyNone),
            true,
            FPassword);
         try
            // salz lesen -> zur besseren sicherheit
            rcxStream.ReadSalt;
            // entschlüsselnd laden
            List.LoadFromStream(rcxStream);
            SetStrings(List);
         finally
            rcxStream.Free;
         end;
      finally
         List.Free;
      end;
   end
   else
      Clear;
end;

procedure TRCxIniFile.UpdateFile;
var
   List: TStringList;
   rcxStream:TRCxStreamDecorator;
begin
   List := TStringList.Create;
   try
      // stream erzeugen.
      rcxStream := TRCxStreamDecorator.Create(
            TFileStream.Create(FFileName, fmCreate),
            true,
            FPassword);
      try
         GetStrings(List);
         // salz mit zufälliger länge schreiben -> erhöht die sicherheit
         rcxStream.WriteSalt(16 + random(32));
         List.SaveToStream(rcxStream);
      finally
         rcxStream.Free;
      end;
   finally
      List.Free;
   end;
end;



end.
Musst halt nur updateFile selbst aufrufen! Aber ansonsten hast du somit eine verschlüsselte ini-Datei. Wenn du willst kannst du unit auch gerne in der codeLib veröffentlichen, damit vielleicht auch andere was davon haben.

Viel spass damit und wenn fragen sind, immer her damit.

grüsse maximov.


Edit: Kleine verbesserungen von Hagen eingebaut. Danke!

[edit=Chakotay1308]SID aus Link entfernt. Mfg, Chakotay1308[/edit]
  Mit Zitat antworten Zitat
Antwort Antwort

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:27 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz