Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

Steganography - hide a message inside a bitmap image

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Steganography - hide a message inside a bitmap image

    discussion - http://www.powerbasic.com/support/pb...ad.php?t=19322

    theory, shmeory...
    introducing steganography to powerbasic ...

    while cryptography is the art of concealing the contents of a message,
    steganography is the art of concealing the actual message itself. almost
    any media data transport can be used, such as audio, video, images, even
    plain text! i've chosen to use bitmaps for this demo because they are of
    a very simple format and very easy to work with compared to advanced
    formats such as gif and jpeg.

    this is steganography at its most basic level, and the idea is very simple...
    for every byte of plaintext, store each bit in 8 different bytes in the target,
    modifying only the least significant bit each time.
    for example, suppose you want to embed the letter "a" (&b01100001) in a bmp.
    first, take one byte from the source data (ie. the bitmap image data). now
    replace its least significant bit with the first bit from the letter a (0).
    then take the second byte from the source data, and replace its least significant
    bit with the second bit from the letter a (1). repeat until all 8 bits have
    been embedded (this will require 8 bytes of source data, so if you have 8000
    bytes of source data you'll be able to embed up to 1000 bytes of plaintext).
    because only the least significant bit is being modified, the changes to the
    data are extremely subtle. for example, if a character in the original source
    data is "aa", it will either stay as "aa" or become "ab", depending on the bit
    being embedded. this subtlety is the reason why the naked eye can't see any
    alterations in the image after a message has been embedded in it.


    demo...
    this simple demo allows you to embed a message of up to 255 characters in a
    bitmap image. the before-and-after images will visually look identical to the
    naked eye, giving no indication that the image has been altered in any way.

    note that to keep things simple, this demo features no cryptography or security
    whatsoever, but it is easy to encrypt a message before embedding it using
    steganographic techniques.

    after running this demo, use a graphics viewer to have a look at the before and
    after images - they should look virtually identical to your naked eye. then have
    a look at the files using a hex editor, and enjoy the subtle changes

    Code:
    '#########################################################
    #compile exe
    'ready-to-compile in pbcc
    'just delete waitkey$ and replace stdout with msgbox to compile in pbdll/pbwin
    'modify the pbmain function so that it points at a valid bmp before compiling.
      
    'based on this bmp specification:
    ' http://www.wotsit.org/filestore/bmpfrmat.zip 
    type bitmap_header
     widentifier as word
     dwfilesize as dword
     dwreserved as dword
     dwdataoffset as dword
     dwheadersize as dword
     dwwidth as dword
     dwheight as dword
     wplanes as word
     wbitsperpixel as word
     dwcompression as dword
     dwdatasize as dword
     dwhresolution as dword
     dwvresolution as dword
     dwcolors as dword
     dwimportantcolors as dword
    end type
     
    '#########################################################
    sub savemessage(sfile as string, splaintext as string)
    on error resume next
    local f as long, char as byte, char2 as byte, x as byte, datapos as long, tmp as long
    local bmp as bitmap_header, sdata as string, stext as string
    if len(splaintext) > 255 then
        stdout "maximum message length in this version is 255 characters"
        exit sub
    end if
    stext = chr$(len(splaintext)) & splaintext  'first byte of stext = len of stext
    f = freefile
    open sfile for binary access read lock shared as #f
     get #f, 1, bmp
     sdata = space$(bmp.dwdatasize)
     get #f, bmp.dwdataoffset, sdata  'fill sdata with the data from dwdataoffset
    close #f
    stdout "this file can hold a maximum of " & trim$(str$(cint(bmp.dwdatasize / 8))) & " plaintext characters"
    datapos = 1
    for f = 1 to len(stext)
        char = asc(mid$(stext, f, 1))
        for x = 0 to 7
         char2 = asc(mid$(sdata, datapos,1))
         tmp = bit(char, x)
         if tmp = 0 then
            bit reset char2, 0
         else
            bit set char2, 0
         end if
         mid$(sdata, datapos,1) = chr$(char2)
         datapos = datapos + 1
        next x
    next f
    f = freefile
    open sfile for binary access write lock shared as #f
     put #f, bmp.dwdataoffset, sdata
    close #f
    end sub
    
    '#########################################################
    sub showmessage (sfile as string)
    on error resume next
    local f as long, i as long, sdata as string, sout as string
    local tmp as long, datapos as long, char as byte, char2 as byte, bmp as bitmap_header
    f = freefile
    open sfile for binary access read lock shared as #f
     get #f, 1, bmp
     sdata = space$(bmp.dwdatasize)
     get #f, bmp.dwdataoffset, sdata  'fill sdata with the data from dwdataoffset
    close #f
    char = 0
    for i = 1 to 8
     char = asc(mid$(sdata, i, 1))
     tmp = bit(char, 0)
     if tmp = 0 then
         bit reset char2, i - 1
     else
         bit set char2, i - 1
     end if
    next i
    stdout "message size = " & str$(char2)
    sout = space$(char2)
    datapos = 9
    for i = 1 to char2
     char2 = 0
     for f = 0 to 7
      char = asc(mid$(sdata, datapos, 1))
      tmp = bit(char, 0)
      if tmp = 0 then
          bit reset char2, f
      else
          bit set char2, f
      end if
      datapos = datapos + 1
     next f
     mid$(sout, i, 1) = chr$(char2)
    next i
    stdout "extracted message = " & sout
    end sub
     
    '#########################################################
    function pbmain() as long
    on error resume next
    'create the bitmap to use for encoding/decoding messages
    kill "d:\temp\steg.bmp"
    filecopy "d:\winnt\coffee bean.bmp", "d:\temp\steg.bmp"
     
    '## encode a message
    savemessage "d:\temp\steg.bmp", "my test message"
     
    '## decode the message
    showmessage "d:\temp\steg.bmp"
    waitkey$
    end function
    stir well and enjoy!


    ------------------
    the powerbasic crypto archives




    [this message has been edited by wayne diamond (edited september 09, 2002).]
    -

  • #2
    Wayne,

    Your method works on some bitmaps, but not all. Lots of bitmaps have dwDataSize set to zero, which is
    valid for uncompressed files. Also when you use a 16 color bitmap, result can be quite colorful...
    (With changing the LSBit, you don't actually change the color value of the pixel, but it's INDEX value
    in the color table used. This colortable can be set to any sequence, so it's possible that entry 1 is black
    and entry 2 is red; would give quite colored results )

    Another way is using the color table to store text. The only thing is that you're
    restricted to he max. number of colors for the text length. This does not change
    any colors..
    Code:
    '==============================================================================
    ' Embed text message in bitmap file.
    ' Length of text depends on number of colors used
    ' Peter Lameijn.
    '==============================================================================
    #Compile Exe
    #Include "win32api.inc"
     
    '------------------------------------------------------------------------------
    Function WriteBmpText(BmpFile As String, sPlainText As String) As Long
      Local BMFH As BITMAPFILEHEADER, hFile As Dword, dStr As String, CtLen As Dword, Cnt As Long
      hFile = FreeFile
      Open BmpFile For Binary As #hFile
        Get$ #hFile, 14, dStr
        Poke$ VarPtr(BMFH), dStr
        Get$ #hFile, 40, dStr
        CtLen = (BMFH.bfOffBits - 14 - 40) \ 4
        Print "Max. number of characters to embed is" + Str$(CtLen)
        If Len(sPlainText) <= CtLen Then
          For Cnt = 1 To Len(sPlainText)
            Get$ #hFile, 3, dStr
            Put$ #hFile, Mid$(sPlainText, Cnt, 1)
          Next
          Function = 1
        End If
      Close #hFile
    End Function
     
    '------------------------------------------------------------------------------
    Function ReadBmpText (BmpFile As String) As String
      Local BMFH As BITMAPFILEHEADER, hFile As Dword, dStr As String, Cnt As Long, Text As String
      hFile = FreeFile
      Open BmpFile For Binary As hFile
      Get$ #hFile, 14, dStr
      Poke$ VarPtr(BMFH), dStr
      Get$ #hFile, 40, dStr
      For Cnt = 1 To ((BMFH.bfOffBits - 54) \ 4)
        Get$ #hFile, 4, dStr
        If Mid$(dStr,4,1) = Chr$(0) Then Exit For
        Text = Text + Mid$(dStr,4,1)
      Next
      Close #hFile
      Function = Text
    End Function
     
    '------------------------------------------------------------------------------
    Function PbMain() As Long
      Local dStr As String
    If Dir$("c:\temp\textbmp.bmp") <> "" Then Kill "c:\temp\textbmp.bmp"
    FileCopy "c:\winnt\winnt256.bmp", "c:\temp\textbmp.bmp"
     
    WriteBmpText "c:\temp\textbmp.bmp", "Embedded test..."
    dStr =  ReadBmpText  ("c:\temp\textbmp.bmp")
    Print "Retrieved text: " ; dStr
    WaitKey$
    End Function
    ------------------
    Peter.
    mailtoeterL@pabx-group.com.nospampeterL@pabx-group.com.nospam</A>
    Regards,
    Peter

    Comment

    Working...
    X