Entwickler-Ecke

Sonstiges (Delphi) - Textverschlüsselung


oPPi - So 20.10.02 02:48
Titel: Textverschlüsselung
Hallo,

Ich hab von meinem Dotzenten ne Aufgabe hingeschnissen bekommen die mir einiges Kopfzerbrechen :roll: bereitet.
Ich habe ein RichEdit1, RichEdit2, Button_Codiere, Button_Decodiere.

Jetzt zu meinen Problem:
Ich gebe Text in das RichEdit1 ein, dieser soll dann wenn ich den Button_Codiere betätige verschlüsselt werden nach dem Schlüssel:

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z <- Klartext
Q A Y W S X E D C R F V T G B Z H N U J M I K O L P <- Geheimtext
(Diese Methode nennt sich Monoalphabetische Chiffrierung)

Ich hab das mal getestet mit der Function:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
function Search_And_Replace(RichEdit: TRichEdit; 
  SearchText, ReplaceText: string): Boolean; 
var 
  startpos, Position, endpos: integer; 
begin 
  startpos := 0; 
  with RichEdit do 
  begin 
    endpos := Length(RichEdit.Text); 
    Lines.BeginUpdate; 
    while FindText(SearchText, startpos, endpos, [stMatchCase])<>-1 do 
    begin 
      endpos   := Length(RichEdit.Text) - startpos; 
      Position := FindText(SearchText, startpos, endpos, [stMatchCase]); 
      Inc(startpos, Length(SearchText)); 
      SetFocus; 
      SelStart  := Position; 
      SelLength := Length(SearchText); 
      richedit.clearselection; 
      SelText := ReplaceText; 
    end; 
    Lines.EndUpdate; 
  end; 
end;


Quelltext
1:
2:
3:
4:
5:
6:
procedure TForm1.Button_VerschluesselnClick(Sender: TObject); 
begin
  RichEdit2.Text := RichEdit1.Text; 
  Search_And_Replace(Richedit1, 'OldText', 'NewText');
  MsgBox('Der Text wurde verschlüsselt !!!'); 
end;


Das funktioniert auch soweit wenn ich für OldText u. NewText die entsprechenden Werte (siehe oben) einsetze. Oder gibt es da ne bessere
Lösung?

Der verschlüsselte Text soll mir dann im RichEdit2 ausgegeben werden.
Wenn ich den Button_Decodiere betätige soll mir der verschlüsselte Text wieder als Klartext im RichEdit1 ausgeben werden.

Ich wäre euch für eine schnelle Hilfe sehr verbunden.
Gruß
oPPi


Delete - So 20.10.02 05:36

Ich muß gestehen, ich habe mir da jetzt keinen großen Kopf gemacht, aber als erstes ist mir [StringReplace[/b] durch den Kopf geschwirrt. Mir dem Flag ReplaceAll sollte es eigentlich kein Problem sein.


Wolff68 - So 20.10.02 21:01

Wird nicht hinhauen Luckie.
Wenn er alle A durch Q ersetzt und später alle Q zu H ist das Chaos Perfekt...

Eine Lösung wäre es in zwei Durchläufen. Erst A durch Ord(Q)+128 ersetzen usw... dann alles wieder runtersetzen.

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
const Ursprung   = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
const Schluessel = 'qaywsxedcrfvtgbzhnujmikolpQAYWSXEDCRFVTGBZHNUJMIKOLP';
....
procedure TForm1.Button1Click(Sender: TObject);
var i : byte;
    puffer : string;
begin
  puffer := Memo1.Text;
  For i := 1 to Length(Ursprung) do begin
    puffer := StringReplace(puffer,
                            Ursprung[i],
                            Chr(Ord(Schluessel[i])+128),
                            [rfReplaceAll]);
  end;
  For i := 1 to Length(Ursprung) do begin
    puffer := StringReplace(puffer,
                            Chr(Ord(Schluessel[i])+128),
                            Schluessel[i],
                            [rfReplaceAll]);
  end;
  Memo2.Lines.Clear;
  Memo2.Text := puffer;
end;

Zurück das ganze dann genauso.

Ein Problem gibt es dabei aber, wenn im Text Zeichen sind, die aus dem oberen ASCII-Bereich sind. In diesem Beispiel wird ein ä nach dem zurückübersetzen zu einem h :?


oPPi - So 20.10.02 22:13

Hallo,

@Wolff68:

Die Umlaute wie ä,ü,ö und Sonderzeichen aus der oberen ASCII-Tabelle werden nicht verwendet. Es geht nur um die von mir angegebenen Zeichen.

Ich werd deinen Code mal checken ob er für meine Bedürfnisse reicht -> ich hoffe es zu mindest. So wie ich das überblicken kann, macht es nen ganz Guten :lol:

Werd mich morgen nochmal melden ob's gereicht hat fürn Bienchen :wink:

Gruß

oPPi


Christian S. - So 20.10.02 22:28

Hi!

Geht's nicht auch so? Oder habe ich eine Anforderung an den Code übersehen? (Code kodiert, dekodieren geht dann halt genau andersrum)


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
const Ursprung   = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
const Schluessel = 'qaywsxedcrfvtgbzhnujmikolpQAYWSXEDCRFVTGBZHNUJMIKOLP';

{...}

procedure TForm1.Button1Click(Sender: TObject);
VAR i,position : INTEGER;
begin
  memo2.text:='';
  for i:=1 TO Length(memo1.Text) do
  begin
    position:=Pos(memo1.Text[i],ursprung);
    if position>0 then memo2.text:=memo2.text+schluessel[position]
    else memo2.text:=memo2.Text+memo1.text[i];
  end;
end;


MfG,
Peter


oPPi - So 20.10.02 23:09

Hallo,

@Peter Lustig
dein Code ist super - die Sonderzeichen werden normal dargestellt das ist zwar nebensächlich aber man kann halt auch diese dann verwenden.

Anders herum sieht das ganze dann so aus:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure TForm1.Button2Click(Sender: TObject);
VAR i,position : INTEGER;
begin
  memo1.text:='';
  for i:=1 TO Length(memo2.Text) do
  begin
    position:=Pos(memo2.Text[i],Schluessel);
    if position>0 then memo1.text:=memo1.text+Ursprung[position]
    else memo1.text:=memo1.Text+memo2.text[i];
  end;
  Memo2.Lines.Clear;
end;

Ich hab jetzt einige Foren durchforstet aber bislang nichts passendes gefunden.
Aber hier werden Sie geholfen ... :lol:
Ist vielleicht auch für andere User interessant ...

Gruß

oPPi

PS: @Wolff68 - Deine Bio auf deiner Website find ich interessant, haben fast die gleichen Daten nur das ich "1101" Month jünger bin.


Wolff68 - So 20.10.02 23:41

Und wiedermal muß ich Peter recht geben. Ist sicherer wegen den Umlauten.

Das mit dem einzeln durchgehen der Zeichen ist auch das naheliegende, nur hab ich schon oft bemerkt, daß das recht langsam ist. Pos() und StringReplace() sind da irgendwie schneller durch.
Meine Schleifen laufen nur 2x von a bis Z und fertig.


Delete - Mo 21.10.02 01:47

Wolff68 hat folgendes geschrieben:
Wird nicht hinhauen Luckie.
Wenn er alle A durch Q ersetzt und später alle Q zu H ist das Chaos Perfekt...

Ich sagte, ja das ist mir so spontan durch den Kopf geschossen.


Delete - Mo 21.10.02 08:33

Mir ist spontan der HTML-Parser von other durch den Kopf geschossen. Damit gehst du in einem Durchgang durch den Text durch, hast aber die Möglichkeit, gezielt auf einzelne Zeichen (Chars) zu kontrollieren.

Das heißt, ist aus dem A erst mal ein Q geworden, springt er zum nächsten Zeichen, und das Chaos sollte nicht auftreten.


Delete - Mo 21.10.02 09:49

Hier mal mein Vorschlag - wie gesagt, auf der technischen Basis von others HTML-Parser. Der kommt ohne "pos" und "StringReplace" aus und ist auch bei größeren Texten recht flott.
Luckie wird´s vielleicht wissen, die anderen dürfen mir glauben ... :)

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
function CodeFunc(const szInString: AnsiString): AnsiString;
const
  encodetable : string[26] = 'QAYWSXEDCRFVTGBZHNUJMIKOLP';
var
  pSrc,
  pResult     : pchar;
  lc          : char;
begin
  SetLength(Result,0);
  if(length(szInString) = 0) then exit;

  pSrc := pointer(szInString);
  if(pSrc = nil) or (pSrc^ = #0) then exit;

  SetLength(Result,length(szInString));
  pResult := pointer(Result);
  ZeroMemory(pResult,length(szInString));

  while(pSrc^ <> #0) do
    begin
      case pSrc^ of
        'A'..'Z':
          Move(encodetable[(byte(pSrc[0]) - 64)],pResult^,1);
        'a'..'z':
          begin
            lc := CHR(byte(encodetable[byte(pSrc[0]) - 96]) + 32);
            Move(lc,pResult^,1);
          end;
        else
          Move(pSrc[0],pResult^,1);
      end;

      inc(pResult);
      inc(pSrc);
    end;
end;

Zur Erklärung -
Der Buchstabe A hat ja bekanntlich den ASCII-Wert 65. Da auch in der ASCII-Tabelle die Buchstaben des Alfabets aufeinanderfolgen, können wir die passenden Schlüsselwerte in einem String der Reihe nach anordnen:

Quelltext
1:
2:
const
  encodetable : string[26] = 'QAYWSXEDCRFVTGBZHNUJMIKOLP';

Bleiben wir beim Beispiel mit dem Buchstaben A -
Um nun an den passenden Codewert zu kommen, ziehen wir 64 ab

Quelltext
1:
A (65) - 64 = 1                    

Diesen Wert Eins benutzen wir in der Anweisung:

Quelltext
1:
Move(encodetable[(byte(pSrc[0]) - 64)],pResult^,1);                    

um das entsprechende Zeichen in "encodevar", das sich an dieser Position befindet, in das Ergebnis (= den Rückgabewert der Funktion) zu kopieren. Und das erste Zeichen unseres Strings ist ein Q.
Und so fort: B hat den ASCII-Wert 66, minus 64 ergibt 2, das entspricht dem A im String ... 8)

Bei den Kleinbuchstaben ist das Prinzip identisch, nur ist hier der Wert, den wir abziehen müssen, 96. Das kleine A hat ja den ASCII-Wert 97, und wir müssen ja wieder auf unsere erste Position kommen. Richtig? Gut, da wir dann aber einen Großbuchstaben haben, müssen wir dessen ASCII-Wert heranziehen und 32 addieren.
Wieder am Beispiel des A:

Quelltext
1:
2:
a (97) - 96 =   1 (entspr. dem Q im String)
Q (81) + 32 = 113 (entspr. dem ASCII-Wert von q)

wzbw.

Ein Wort noch dazu:

Quelltext
1:
2:
else
  Move(pSrc[0],pResult^,1);

oPPi hat zwar gesagt, es werden nur die Buchstaben des Alfabets genutzt. Man sollte aber dennoch damit rechnen, dass mal ein anderes Zeichen angegeben wird. Also reichen wir alles, was durch unser Raster (A-Z,a-z) fällt, 1:1 an das Funktionsergebnis durch.

Für die Dekodierung können wir übrigens die selbe Funktion verwenden. Lediglich die Stringtabelle (var "encodestring") wäre durch diese hier:

Quelltext
1:
'BOIHGKNQVTWYURXZAJEMSLDFCP';                    

zu ersetzen. Ich empfehle aber, eine zweite Variable (var "decodetable") mit diesem Inhalt anzulegen und im Funktionskopf eine Bool-Variable zu ergänzen, die über Kodierung und Dekodierung entscheidet. Beispielsweise:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
function CodeFunc(const szInString: AnsiString;
  const Encode: boolean): AnsiString;
const
  encodetable : string[26] = 'QAYWSXEDCRFVTGBZHNUJMIKOLP';
  decodetable : string[26] = 'BOIHGKNQVTWYURXZAJEMSLDFCP';
{ ... }
        'A'..'Z':
          if(Encode) then Move(encodetable[(byte(pSrc[0]) - 64)],pResult^,1)
            else Move(decodetable[(byte(pSrc[0]) - 64)],pResult^,1);

        'a'..'z':
          begin
            if(Encode) then lc := CHR(byte(encodetable[byte(pSrc[0]) - 96]) + 32)
              else lc := CHR(byte(decodetable[byte(pSrc[0]) - 96]) + 32);
            Move(lc,pResult^,1);
          end;
{ ... }

Das war´s.