// Hiermit kann man einen kurzen Text in Bildern verstecken (Steganografie).

// Getestet mit D4 unter XP

// Variante 1:
// Text wird einfach hinten an ein Bild angehängt. Ich benutze hier Klartext,
// welcher aber besser verschlüsselt werden sollte. Wird das Bild bearbeitet,
// geht die Informationt verloren.
uses JPeg; 
 
function JPAnhang(jp: TJpegImage; ziel: string; st: TStrings): boolean; 
var 
  ms: TMemorystream; 
  lg: integer; 
begin 
  result := false; 
  try 
    ms := TMemorystream.create; 
    jp.savetostream(ms); 
    lg := length(st.text); 
    ms.writebuffer(st.text[1], lg); 
    ms.writebuffer(lg, 4); 
    ms.SaveToFile(ziel); 
    ms.free; 
  except 
    exit; 
  end; 
  result := true; 
end; 
 

function JPAuslesen(jp: TJpegImage): string; 
var 
  ms: TMemorystream; 
  lg: integer; 
begin 
  result := ''; 
  ms := TMemorystream.create; 
  try 
    jp.savetostream(ms); 
    ms.Seek(-4, sofromend); 
    ms.readbuffer(lg, 4); 
    setlength(result, lg); 
    ms.Seek(-lg - 4, sofromend); 
    ms.readbuffer(result[1], lg); 
    ms.free; 
  except 
    ms.free; 
  end; 
end;

// Beispielaufruf: 
 
// Text verstecken 
 
procedure TForm1.Button4Click(Sender: TObject); 
var 
  jp: TJpegImage; 
begin 
  jp := TJpegImage.create; 
  jp.loadfromfile('c:\vogel.jpg'); 
  canvas.draw(500, 10, jp); 
  if not JPAnhang(jp, 'c:\versteck.jpg', Memo1.Lines) 
    then showmessage('FEHLER') else begin 
    jp.loadfromfile('c:\versteck.jpg'); 
    canvas.draw(500 + jp.width + 5, 10, jp); // Kontrolle 
  end; 
end; 
 
 
// Text auslesen 
 
procedure TForm1.Button5Click(Sender: TObject); 
var 
  sl: TStringlist; 
  jp: TJPegImage; 
begin 
  sl := TStringlist.create; 
  jp := TJpegImage.create; 
  jp.loadfromfile('c:\versteck.jpg'); 
  sl.text := JPAuslesen(jp); 
  showmessage(sl.text); 
  sl.free; 
  jp.free; 
end;


// -------------------------------------------------------------

// Variante 2:
// Hiermit kann man einen kurzen Text in den Farbinformationen einer Bitmap
// mit 24 Bit Farbtiefe unterbringen ohne dass man einen Unterschied zum
// Original sehen kann und ohne dass man das Original zum entschlüsseln braucht.
// Bei Veränderung des codierten Bildes, wie z.B. Aufhellung, Kontrast-
// steigerung oder Änderung des Pixelformates, gehen die Informationen
// verloren.

function einsetzen(bm: TBitmap; const txt: TStrings): boolean; 
var 
  i, x, y, z, b3, lg: integer; 
  p: PBytearray; 
  mask: byte; 
  s: string; 
begin 
  Result := false; 
  if (txt.Text = '') or 
    (bm.pixelformat <> pf24bit) then exit; 
  lg := length(txt.Text); 
  s := inttohex(lg, 4) + txt.Text; 
  inc(lg, 4); 
  if lg * 8 > bm.height * bm.width then exit; // Text zu lang 
  b3 := bm.width * 3; 
  mask := 1; 
  z := 1; 
  i := 0; 
  try 
    for y := 0 to bm.height - 1 do begin 
      p := bm.scanline[y]; 
      x := 0; 
      while x < b3 do begin 
        if z = succ(lg) then begin 
          Result := true; 
          exit; 
        end; 
        p[x + 1] := p[x + 1] and $FE or ((ord(s[z]) and mask) shr i); 
        inc(i); 
        if i = 8 then begin 
          inc(z); 
          i := 0; 
          mask := 1; 
        end else 
          mask := mask shl 1; 
        inc(x, 3); 
      end; 
    end; 
  except end; 
end; 
 
 
function auslesen(bm: TBitmap): string; 
var 
  i, x, y, z, m, b3: integer; 
  p: PBytearray; 
  c: byte; 
  s: string; 
begin 
  result := ''; 
  if (bm.pixelformat <> pf24bit) 
    then exit; 
  s := ''; 
  m := maxint; 
  b3 := bm.width * 3; 
  z := 1; 
  i := 0; 
  c := 0; 
  try 
    for y := 0 to bm.height - 1 do begin 
      p := bm.scanline[y]; 
      x := 0; 
      while x < b3 do begin 
        if i = 8 then begin 
          if m = 0 then exit; 
          i := 0; 
          if z < 5 then begin 
            inc(z); 
            s := s + chr(c); 
            if z = 5 then 
              m := strtoint('$' + s); 
          end else begin 
            result := result + chr(c); 
            dec(m); 
          end; 
          c := 0; 
        end; 
        c := c or ((p[x + 1] and 1) shl i); 
        inc(i); 
        inc(x, 3); 
      end; 
    end; 
  except end; 
end; 
 
 
// Beispielaufruf: 
 
 
// Text verstecken 
 
procedure TForm1.Button2Click(Sender: TObject); 
var 
  bm: TBitmap; 
begin 
  bm := TBitmap.create; 
  bm.loadfromfile('c:\frau.bmp'); 
  bm.pixelformat := pf24bit; 
  canvas.draw(500, 10, bm); 
  if not einsetzen(bm, Memo1.Lines) 
    then showmessage('FEHLER') 
  else begin 
    canvas.draw(500 + bm.width + 5, 10, bm); // Kontrolle 
    bm.savetofile('c:\versteck.bmp'); 
  end; 
  bm.free; 
end; 
 
// Text auslesen 
 
procedure TForm1.Button3Click(Sender: TObject); 
var 
  sl: TStringlist; 
  bm: TBitmap; 
begin 
  sl := TStringlist.create; 
  bm := TBitmap.create; 
  bm.loadfromfile('c:\versteck.bmp'); 
  bm.pixelformat := pf24bit; 
  sl.text := auslesen(bm); 
  showmessage(sl.text); 
  sl.free; 
  bm.free; 
end;

// -------------------------------------------------------------

// Variante 2.1:
// Hiermit kann man die dreifache Menge an Text unterbringen als bei der
// vorigen Variante. Allerdings ist statistisch eher nachweisbar, dass Text
// im Bild versteckt ist.

function einsetzenX(bm: TBitmap; const txt: TStrings): boolean; 
var 
  i, k, x, y, z, b3, lg: integer; 
  p: PBytearray; 
  mask: byte; 
  s: string; 
  function weiter: boolean; 
  begin 
    inc(i); 
    if i = 8 then begin 
      inc(z); 
      if z = succ(lg) then begin 
        Result := true; 
        exit; 
      end; 
      i := 0; 
      mask := 1; 
    end else 
      mask := mask shl 1; 
    Result := false; 
  end; 
begin 
  Result := false; 
  if (txt.Text = '') or 
    (bm.pixelformat <> pf24bit) then exit; 
  lg := length(txt.Text); 
  s := inttohex(lg, 4) + txt.Text; 
  inc(lg, 4); 
  b3 := bm.width * 3; 
  mask := 1; 
  z := 1; 
  i := 0; 
  try 
    for y := 0 to bm.height - 1 do begin 
      p := bm.scanline[y]; 
      x := 0; 
      while x < b3 do begin 
        for k := 0 to 2 do begin 
          p[x + k] := p[x + k] and $FE or ((ord(s[z]) and mask) shr i); 
          if weiter then begin 
            Result := true; 
            exit; 
          end; 
        end; 
        inc(x, 3); 
      end; 
    end; 
  except end; 
end; 
 
 
function auslesenX(bm: TBitmap): string; 
var 
  i, k, x, y, z, m, b3: integer; 
  p: PBytearray; 
  c: byte; 
  s: string; 
begin 
  result := ''; 
  if (bm.pixelformat <> pf24bit) 
    then exit; 
  s := ''; 
  m := maxint; 
  b3 := bm.width * 3; 
  z := 1; 
  i := 0; 
  c := 0; 
  try 
    for y := 0 to bm.height - 1 do begin 
      p := bm.scanline[y]; 
      x := 0; 
      while x < b3 do begin 
        for k := 0 to 2 do begin 
          if i = 8 then begin 
            if m = 0 then exit; 
            i := 0; 
            if z < 5 then begin 
              inc(z); 
              s := s + chr(c); 
              if z = 5 then 
                m := strtoint('$' + s); 
            end else begin 
              result := result + chr(c); 
              dec(m); 
            end; 
            c := 0; 
          end; 
          c := c or ((p[x + k] and 1) shl i); 
          inc(i); 
        end; 
        inc(x, 3); 
      end; 
    end; 
  except end; 
end; 
 
 
// Beispielaufruf: 
 
 
// Text verstecken 
 
procedure TForm1.Button2Click(Sender: TObject); 
var 
  bm: TBitmap; 
begin 
  bm := TBitmap.create; 
  bm.loadfromfile('c:\frau.bmp'); 
  bm.pixelformat := pf24bit; 
  canvas.draw(500, 10, bm); 
  if not einsetzenX(bm, Memo1.Lines) 
    then showmessage('FEHLER') 
  else begin 
    canvas.draw(500 + bm.width + 5, 10, bm); // Kontrolle 
    bm.savetofile('c:\versteck.bmp'); 
  end; 
  bm.free; 
end; 
 
// Text auslesen 
 
procedure TForm1.Button3Click(Sender: TObject); 
var 
  sl: TStringlist; 
  bm: TBitmap; 
begin 
  sl := TStringlist.create; 
  bm := TBitmap.create; 
  bm.loadfromfile('c:\versteck.bmp'); 
  bm.pixelformat := pf24bit; 
  sl.text := auslesenX(bm); 
  showmessage(sl.text); 
  sl.free; 
  bm.free; 
end;


// -------------------------------------------------------------

// Variante 3:
// Hiermit kann man einen kurzen Text in den Pixeln einer Bitmap mit 32 Bit
// Farbtiefe unterbringen ohne dass eine Farbinformation geändert wird. Es
// wird einfach das vierte Bit
(alpha-Bit) eines Pixels belegt. Allerdings
// geht das nur, wenn kein Alpha-Blendung genutzt wird. Bei Bearbeitung des
// Bildes geht die Information verloren.

function einsetzen32(bm: TBitmap; const txt: TStrings): boolean; 
var 
  x, y, z, b4: integer; 
  p: PBytearray; 
begin 
  Result := false; 
  if (txt.Text = '') or 
    (bm.pixelformat <> pf32bit) then exit; 
  b4 := bm.width * 4; 
  z := 1; 
  try 
    for y := 0 to bm.height - 1 do begin 
      p := bm.scanline[y]; 
      x := 0; 
      while x < b4 do begin 
        if txt.text[z] = #0 then begin 
          p[x + 3] := 0; 
          Result := true; 
          exit; 
        end else 
          p[x + 3] := ord(txt.text[z]) xor 1; 
        inc(z); 
        inc(x, 4); 
      end; 
    end; 
  except end; 
end; 
 

function auslesen32(bm: TBitmap): string; 
var 
  x, y, b4: integer; 
  p: PBytearray; 
begin 
  result := ''; 
  if bm.pixelformat <> pf32bit then exit; 
  b4 := bm.width * 4; 
  try 
    for y := 0 to bm.height - 1 do begin 
      p := bm.scanline[y]; 
      x := 0; 
      while x < b4 do begin 
        if p[x + 3] = 0 then exit; 
        result := result + chr(p[x + 3] xor 1); 
        inc(x, 4); 
      end; 
    end; 
  except end; 
end; 
 
 
// Beispielaufruf: 
  
 
// Text verstecken  
 
procedure TForm1.Button2Click(Sender: TObject); 
var 
  bm: TBitmap; 
begin 
  bm := TBitmap.create; 
  bm.loadfromfile('c:\frau.bmp'); 
  bm.pixelformat := pf32bit; 
  canvas.draw(500, 10, bm); 
  if not einsetzen32(bm, Memo1.Lines) 
    then showmessage('FEHLER') 
  else begin 
    canvas.draw(500 + bm.width + 5, 10, bm); // Kontrolle
    bm.savetofile('c:\versteck.bmp'); 
  end; 
  bm.free; 
end; 
 
 
// Text auslesen 
 
procedure TForm1.Button3Click(Sender: TObject); 
var 
  sl: TStringlist; 
  bm: TBitmap; 
begin 
  sl := TStringlist.create; 
  bm := TBitmap.create; 
  bm.loadfromfile('c:\versteck.bmp'); 
  bm.pixelformat := pf32bit; 
  sl.text := auslesen32(bm); 
  showmessage(sl.text); 
  sl.free; 
  bm.free; 
end; 





Zugriffe seit 6.9.2001 auf Delphi-Ecke