Tipy a triky v Delphi, díl 46.

Dnešní díl bude poněkud odlehčený a berte jej s trochou nadsázky. Zahrajeme si totiž na agenty a naučíme se způsob, jak ukrýt textové zprávy do obrázku tak, aby si nikdo ničeho nevšiml.

Ukrytí textové zprávy do obrázku

Možná znáte některé programy, které vám umožní schovat do běžného obrázku textová data tak, aby byl takto získaný obrázek k nerozeznání od originálu. K čemu je to dobré? Je to jeden ze zajímavých způsobů, jak bezpečným způsobem přenášet citlivá data například prostřednictvím e-mailu. Jistě namítnete, že mnohem lepší je data šifrovat. Ano, je to jeden z účinných způsobů, ale zašifrovaná data mohou být na první pohled podezřelá a mohou lákat ke zkoušení, jak šifru prolomit. A i když se prolomení nepodaří (tak by tomu tedy alespoň v drtivé většině případů mělo být), přesto samo zjištění jiné osoby, že posíláte nějakou šifrovanou poštu, může být pro vás dostatečně kompromitující. Když ovšem pošlete e-mailem naprosto neškodný obrázek, žádné podezření to nevzbudí a vaše paranoidní duše agenta může být klidná.

Ale teď vážně. Ukážeme si jeden jednoduchý způsob, jak tohoto efektu zakomponování textu do obrázku dosáhnout v Delphi. Na originální obrázek je namaskován zadaný text v jeho binární podobě. Při zpětném procesu (dešifrování) jsou porovnány jednotlivé pixely původního a zašifrovaného obrázku a rozdíly jsou opět zpětně "demaskovány", čímž se získají jednotlivé znaky uloženého textu.

V tom je právě menší nevýhoda tohoto jinak velmi jednoduchého postupu – totiž nutnost mít pro dešifrování také původní originální obrázek. V praxi to pak znamená, že pochopitelně nebudete pokaždé posílat oba obrázky (tedy původní originál a obrázek s ukrytým textem), ale originální obrázek si s člověkem, se kterým chcete touto formou komunikovat, vyměníte pouze jednou. Poté už pouze posíláte obrázky s ukrytými texty. Abychom byli opravdu precizní a učinili zadost všem agentským pravidlům, můžete ještě nenápadnost vašeho počínání zvýšit tím, že budete používat obrázků více (v extrémním případě až na každý den v roce jiný obrázek). Jinak by bylo totiž značně podezřelé, kdybyste posílali stejnému člověku stále dokola tentýž obrázek.

Pojďme však již k samotné implementaci v Delphi. Příklad jsou vlastně pouze dvě procedury – události stisku dvou tlačítek. První tlačítko zakóduje do obrázku zprávu, druhé tlačítko ji dekóduje. Kromě těchto dvou tlačítek ještě umístěte na formulář 3 komponenty TImage. První bude obsahovat originální obrázek, takže jej prostřednictvím Object Inspectoru můžete rovnou do komponenty načíst. Obrázek musí být ve formátu BMP. Zbylé dvě komponenty TImage slouží k zobrazení výsledného obrázku na tzv. delta snímku, ve kterém jsou žlutou barvou zvýrazněny klíčové změněné pixely. Tento obrázek slouží pouze pro přehled a nemá žádnou praktickou funkci. Poslední věcí, kterou je třeba na formulář přidat, je komponenta, jež bude obsahovat textovou zprávu, kterou chceme do obrázku ukrýt. V našem případě bude tuto funkci plnit komponenta TEdit.

Jak pojmenovat zmíněné komponenty, zjistíte snadno ze zdrojového kódu. První procedura slouží k "zakódování", druhá ke zpětnému získání textu z obrázku:

procedure TForm1.Button1Click(Sender: TObject);
var
  x, y, i, j: Integer;
  PixelData: TColor;
  CharMask, CharData: Byte;
begin
  imgTarget.Picture.Assign(imgOrig.Picture);
  imgDelta.Picture.Assign(imgOrig.Picture);
  imgTarget.Picture.Bitmap.PixelFormat := pf32bit;
  imgDelta.Picture.Bitmap.PixelFormat := pf32bit;
  x := 0;
  y := 0;
  with imgTarget.Picture.Bitmap do
    for i := 1 to Length(sourceMessage.Text) do
    begin
      CharMask := $80;
      for j := 1 to 8 do
      begin
        CharData := Byte(sourceMessage.Text[i]) and CharMask;
        if (CharData <> 0) then
        begin
          PixelData := Canvas.Pixels[x, y] xor $1;
          Canvas.Pixels[x, y] := PixelData;
        end;
        x := (x + 1) mod imgTarget.Picture.Bitmap.Width;
        if (x = 0) then
        begin
          Inc(y);
        end;
        CharMask := CharMask shr 1;
      end;
    end;
  for y := 0 to imgOrig.Picture.Bitmap.Height -1 do
    for x := 0 to imgOrig.Picture.Bitmap.Width -1 do
      if (imgOrig.Picture.Bitmap.Canvas.Pixels[x, y] <> imgTarget.Picture.Bitmap.Canvas.Pixels[x, y]) then
        imgDelta.Picture.Bitmap.Canvas.Pixels[x, y] := clYellow;
end;

procedure TForm1.Button2Click(Sender: TObject);
Var
  x, y: integer;
  mask, ch: byte;
begin
  sourceMessage.Clear;
  mask := $80;
  ch := 0;
  for y := 0 to imgOrig.Picture.Bitmap.Height -1 do
  begin
    for x := 0 to imgOrig.Picture.Bitmap.Width -1 do
    begin
      if (imgOrig.Picture.Bitmap.Canvas.Pixels[x, y] <>
      imgTarget.Picture.Bitmap.Canvas.Pixels[x, y]) then ch := ch or mask;
      mask := mask shr 1;
      if mask = 0 Then
      begin
        Edit1.Text := Edit1.Text + char(ch);
        mask := $80;
        ch := 0;
      end;
    end;
  end;
end;

Jak vidíte, výsledný obrázek není uložen na disk. Toho však snadno docílíte přidáním tohoto řádku na konec první procedury:

imgTarget.Picture.SaveToFile(`c:\vyslednyobrazek.bmp`);

Celý příklad berte spíše jako ukázkový. Je koncipován tak, abyste přímo viděli, jak daná věc funguje, a mohli experimentovat. V reálné aplikaci bude pochopitelně nutné přidat dialog pro výběr a následné uložení obrázku a také načítání vkládaného textu ze souboru.

Diskuze (1) Další článek: OpenOffice 1.0 CZ Release Candidate 1

Témata článku: , , , , , , , , , , , , , , , , , , ,