Hide text in BMP image data
Algorithm creator(s)
n/a
PB author(s)
Wayne Diamond
Description
Demonstration of a simple, common image watermarking technique. The least significant bit (LSB) of each byte in the image data is used to store a hidden message.
Note
The first PowerBASIC steganographic example, this is a simple demonstration of just one of many steganographic techniques that can be applied to images.
Source
https://forum.powerbasic.com/forum/user-to-user-discussions/source-code/24148-steganography-hide-a-message-inside-a-bitmap-image?t=23511
See also
n/a
Source Code
Download source code file steg-bmpdata.bas (Right-click -> "Save as ...")
Data modification sample:
Before: 000A0A170A0A0A0A0A0A0A0A0A0A0A170C080A010F010B6A4D630215060D0B0E080C0C0808171F4E310C13040834010403150911000F040504061E0904
After : 010B0B170A0A0A0A0B0A0B0B0A0A0B160D080A010F010B6A4C620214060D0A0E080C0D0809171F4E310C13040835010403150810010F050404061F0805
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
'#########################################################
#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.
TYPE BITMAP_HEADER
'Based on this BMP specification:
' http://www.wotsit.org/filestore/bmpfrmat.zip
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