Skip to content

Instantly share code, notes, and snippets.

@joakibj
Created August 24, 2013 19:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joakibj/6330040 to your computer and use it in GitHub Desktop.
Save joakibj/6330040 to your computer and use it in GitHub Desktop.
Made this into a gist instead. Contains an implementation of the Least Significant Bit algorithm for steganography. Hides a png image (payload) in the n lowest bits of another png image(carrier), resulting in contaminated image called the package. This program was created for the Ukens Nøtt (nut of the week) newsmail, security group, Visma Consu…
import os, sys, png, argparse
#coding: utf-8
"""
Contains an implementation of the Least Significant Bit algorithm for steganography.
Hides a png image (payload) in the n lowest bits of another png image(carrier), resulting in contaminated image called the package.
"""
class Error(Exception):
"""Base class for exceptions"""
pass
class PayloadLargerThanCarrierError(Error):
"""The payload image is larger than the carrier image in either width or height"""
class Image:
def __init__(self, width, height, pixels=None):
self.width = width
self.height = height
self.pixels = pixels
def encode(args):
carrier = read_png(args.carrier[0])
print 'The carrier image size is %d*%d' % (carrier.width, carrier.height)
payload = read_png(args.payload[0])
print 'The payload image size is %d*%d' % (payload.width, payload.height)
if (carrier.width < payload.width) or (carrier.height < payload.height):
raise PayloadLargerThanCarrierError()
package = encode_payload_into_carrier(payload, carrier, args.encode_bits)
write_png(package, 'package.png')
print 'Encoded payload(%s) into carrier(%s) in the lowest %d bits.' % (args.payload[0], args.carrier[0], args.encode_bits)
print 'Written package.png. Exiting... '
def encode_payload_into_carrier(payload, carrier, encodeBits):
package = carrier
for row in range(len(payload.pixels)):
for colourComponent in range(len(payload.pixels[row])):
package.pixels[row][colourComponent] = encode_colour_component(carrier.pixels[row][colourComponent], payload.pixels[row][colourComponent], encodeBits)
return package
def encode_colour_component(carrierColourComponent, payloadColourComponent, encodeBits):
mask = 0b11111111 << encodeBits
payloadColourComponent = payloadColourComponent >> 8 - encodeBits
carrierColourComponent = carrierColourComponent & mask
return carrierColourComponent + payloadColourComponent
def decode(args):
suspect = read_png(args.suspect[0])
print 'The suspect image is %d*%d' % (suspect.width, suspect.height)
payload = decode_payload_from_suspect(suspect, args.encode_bits)
write_png(payload, 'payload.png')
print 'Decoded payload from suspect(%s).' % (args.suspect[0])
print 'Written payload.png. Exiting... '
def decode_payload_from_suspect(suspect, encodeBits):
payload = suspect
for row in range(len(suspect.pixels)):
for colourComponent in range(len(suspect.pixels[row])):
payload.pixels[row][colourComponent] = decode_colour_component(suspect.pixels[row][colourComponent], encodeBits)
return payload
def decode_colour_component(suspectPixel, encodeBits):
suspectPixel = suspectPixel << 8 - encodeBits
return 0b11111111 & suspectPixel
def write_png(image, fileName):
fileHandle = open(fileName, 'wb')
writer = png.Writer(image.width, image.height, alpha=True)
writer.write(fileHandle, image.pixels)
fileHandle.close()
def read_png(fileName):
fileHandle = open(fileName, 'rb')
pngImage = png.Reader(fileHandle).asRGBA()
pixels = list(pngImage[2])
fileHandle.close()
return Image(pngImage[0], pngImage[1], pixels)
def init_parser():
parent_parser = argparse.ArgumentParser(add_help=False)
parent_parser.add_argument('-eb', '--encode-bits', type=int, default=3)
parser = argparse.ArgumentParser(parents=[parent_parser], description='Encodes and decodes a png inside a png. A practice in image steganography.')
subparsers = parser.add_subparsers(help='subcommand help')
encode_parser = subparsers.add_parser('encode', help='encode help', description='Encode a payload in the lower encode_bits of the carrier png')
encode_parser.add_argument('-c', '--carrier', nargs=1, required=True, help='The PNG file where the payload is hidden')
encode_parser.add_argument('-p', '--payload', nargs=1, required=True, help='The PNG with the secret message')
encode_parser.set_defaults(func=encode)
decode_parser = subparsers.add_parser('decode', help='decode help', description='Decode a carrier png, extracting the payload from the lower encode_bits')
decode_parser.add_argument('-s', '--suspect', nargs=1, required=True, help='The PNG with the suspected secret message')
decode_parser.set_defaults(func=decode)
return parser
def call_subcommand(args):
try:
args.func(args)
except PayloadLargerThanCarrierError:
print 'The payload image does not fit inside the carrier image.'
print 'Exiting...'
def main():
parser = init_parser()
args = parser.parse_args()
call_subcommand(args)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment