On Feb 11, 2008 4:11 PM, jam <[EMAIL PROTECTED]> wrote:
> The whole concept is an utter myth.
> I zip my data
> or bzip it
> or bzip2 it
> or steg it into a harmless picture
> or encrupt it
>
> As I said, an utter myth

Agreed :-)

[EMAIL PROTECTED]:~/code/cerulif$ cat cerulif.py
#!/usr/bin/env python

"""
Author: Kristian Erik Hermansen

CeRuLiF is a steganography tool useful for hiding messages in textual data
by exploiting the relationship of CR/LF character pairs.
"""

import sys, zlib
from optparse import OptionParser

parser = OptionParser('usage: %prog [options]', version='%prog 20070107')
parser.add_option('-i', '--input-file', action='store', type='string',
                  dest='ifile',
                  help='input file')
parser.add_option('-m', '--message-file', action='store', type='string',
                  dest='mfile',
                  help='message file containing secret')
parser.add_option('-o', '--output-file', action='store', type='string',
                  dest='ofile',
                  help='output file')
parser.add_option('-z', '--zip-message', action='store_true',
                  dest='zipit', default=False,
                  help='zlib the hidden message')
parser.add_option('-H', '--hide', action='store_true',
                  dest='hide', default=False,
                  help='embed a hidden message')
parser.add_option('-U', '--unhide', action='store_true',
                  dest='unhide', default=False,
                  help='unembed a hidden message')
parser.add_option('-p', '--parachute', action='store_false',
                  dest='parachute', default=True,
                  help='simple checks for non-cerulified input files')
# TODO: aes encryption support
(options, args) = parser.parse_args()

# required options, oxymoron
if options.ifile == None:
    parser.error('You must specify an input file!')
# other bad things
if options.hide == True and options.unhide == True:
    parser.error('You have to choose hide/unhide, but not both man!')
if options.hide == False and options.unhide == False:
    parser.error('You have to choose whether to hide or unhide a message!')
if options.unhide == True and options.mfile == True:
    parser.error('Dont specify a hidden input message when unhiding!')

# heh, yes we assume you only use reasonably sized files ;-P
fin = open(options.ifile)
bmes =''                          # message buf
fout = ''                         # output handle

# configure output
if options.ofile == None:
    fout = sys.stdout
else:
    fout = open(options.ofile, 'w')

if options.hide == True:
    # our secret message
    if options.mfile == None:
        # get from stdin until EOF
        bmes = sys.stdin.read()
    else:
        # read from message file
        bmes = open(options.mfile).read()

    # compression support
    if options.zipit == True:
        bmes = zlib.compress(bmes)

# get CRLF/LFCR lines -- can't merely use readline() here dude
# ~spaghetti (+ dont want to hog mem with read())
def get_cerulif_chunk(f):
    cr = lf = eof = 0
    byte = ''
    buf = ''
    while cr == 0 or lf == 0:
        byte = f.read(1)
        if byte == '\n':
            lf = 1
            if f.read(1) != '\r':
                f.seek(-1,1)
                lf = 0
            else:
                cr = 1
        if byte == '\r':
            cr = 1
            if f.read(1) != '\n':
                f.seek(-1,1)
                cr = 0
            else:
                lf = 1
        if byte == '':
            eof = 1
            break
        buf += byte
    if eof != 1:
        f.seek(-1,1)
        buf += f.read(1)
    return buf

# thx python-list
def bstr(n): # n in range 0-255
  return ''.join([str(n >> x & 1) for x in (7,6,5,4,3,2,1,0)])

# take message chunk, embed bit, return string
def embed_bit_in_chunk(s, b):
    t = s[0:-2]
    if b == 1:
        t += '\r'
        t += '\n'
    elif b == 0:
        t += '\n'
        t += '\r'
    else:
        print 'Bit should be 0 or 1!'
        sys.exit(2)
    return t

# take message chunk, unembed bit, return bit
def unembed_bit_from_chunk(s):
    if  s[-2] == '\r' and s[-1] == '\n':
        return 1
    elif s[-2] == '\n' and s[-1] == '\r':
        return 0
    else:
        print 'We did not find a bit in this chunk!'
        sys.exit(3)

if options.hide == True:
    # magic goes here ... ohhh the hacks!
    for c in bmes:
        c_bstr = bstr(ord(c))
        # iterate over the bits
        for b in c_bstr:
            chunk = get_cerulif_chunk(fin)
            if chunk == '':
                print '**********'
                print 'We ran out of slack space necessary to steganize input!'
                print '**********'
                sys.exit(1)
            else:
                fout.write(embed_bit_in_chunk(chunk, int(b)))
    # exhaust the remaining input file
    while True:
        chunk = get_cerulif_chunk(fin)
        if chunk == '':
            break
        else:
            fout.write(chunk)

if options.unhide == True:
    while True:
        chunk = get_cerulif_chunk(fin)
        if chunk == '':
            break
        else:
            bmes += str(unembed_bit_from_chunk(chunk))
    # compression support
    if options.zipit == True:
        bmes = zlib.decompress(bmes)
    if bmes[0:8] == '11111111':
        if options.parachute == True:
            print '**********'
            print 'Looks like this file might not be CeRuLiFied!'
            print '**********'
            sys.exit(4)
    else:
        t = ''
        for c in bmes:
            t += c
            if len(t) == 8 and t != '11111111':
                fout.write(chr(int(t, 2)))
                t = ''
-- 
Kristian Erik Hermansen
"Know something about everything and everything about something."
-- 
SLUG - Sydney Linux User's Group Mailing List - http://slug.org.au/
Subscription info and FAQs: http://slug.org.au/faq/mailinglists.html

Reply via email to