Steganographic Encoder/Decoder

This is the place for ALL of the user submitted challenges. If you create a little challenge/mission/riddle/whatever, post it here.
Forum rules
Do not post missions that you did NOT create without proper citing.

Steganographic Encoder/Decoder

Post by -Ninjex- on Sun Sep 22, 2013 7:10 am
([msg=77464]see Steganographic Encoder/Decoder[/msg])

This is part of the continuous programming challenges!

The challenge:
Level: Harder

Create a hybrid encoder/decoder & steganographic program.
The encoder should be designed for secrecy/security.
Do not use hard coded, static operands in the encoding process
The encoding process should create (as much as possible) a unique graph image based on the information being encoded. In addition, I ask of you to hide some valuable information associated with the decoding process using the graph image.

I tried to keep the restrictions at a minimum to allow everyone to be as versatile as possible and to get the most fun out of it. With this program, the points you earn will be based on my judgment, but the least amount of points that any program can receive is 250 points (assuming it is in coordination with the given rules)

I have a program designed for this already, but I am interested to see others results before I post my code.
Also, before you ask, yes: You may use built in classes, libs, etc to handle the graphs.
Points: 250

Here are just a few examples of what a graph could simulate: http://imgur.com/a/0lsiH
However, these graphs are used for getting access to some information to decode some specific data.

** Raised Points **
Last edited by -Ninjex- on Thu Oct 03, 2013 2:31 pm, edited 5 times in total.
If you're not willing to learn, no one can help you. If you're determined to learn, no one can stop you.⠠⠵
The absence of evidence is not evidence of absence.
I can explain it for you, but I can't understand it for you.
^(-.^)>
User avatar
-Ninjex-
Addict
Addict
 
Posts: 1449
Joined: Sun Sep 02, 2012 8:02 pm
Blog: View Blog (0)


Re: Stenographic Encoder/Decoder

Post by aeroxtk on Sun Sep 22, 2013 7:44 am
([msg=77465]see Re: Stenographic Encoder/Decoder[/msg])

-Ninjex- wrote:stenographic program


You do know that stenography is something quite different from steganography? Some might fall for that and actually investigate stenography instead of steganography in this very case.
Isolation, in my world means opportunity. Reflection of that nature undoubtedly brings round to the fact that comprehension is a requisite of success and thence exculpates the notion associated with the above alluded quips.
User avatar
aeroxtk
New User
New User
 
Posts: 24
Joined: Wed Oct 17, 2012 8:29 am
Location: Bulgaria
Blog: View Blog (0)


Re: Stenographic Encoder/Decoder

Post by -Ninjex- on Sun Sep 22, 2013 7:51 am
([msg=77466]see Re: Stenographic Encoder/Decoder[/msg])

Whoopsie, I'll fix that up, thanks
If you're not willing to learn, no one can help you. If you're determined to learn, no one can stop you.⠠⠵
The absence of evidence is not evidence of absence.
I can explain it for you, but I can't understand it for you.
^(-.^)>
User avatar
-Ninjex-
Addict
Addict
 
Posts: 1449
Joined: Sun Sep 02, 2012 8:02 pm
Blog: View Blog (0)


Re: Stenographic Encoder/Decoder

Post by Goatboy on Sun Sep 22, 2013 7:53 am
([msg=77467]see Re: Stenographic Encoder/Decoder[/msg])

aeroxtk wrote:
-Ninjex- wrote:stenographic program


You do know that stenography is something quite different from steganography? Some might fall for that and actually investigate stenography instead of steganography in this very case.

Kinda funny, but when I googled "stenography" for a good definition, it actually gave me "steganography" first but *not* as a "Did you mean this?" suggestion.
Assume that everything I say is or could be a lie.
1UHQ15HqBRZFykqx7mKHpYroxanLjJcUk
User avatar
Goatboy
Expert
Expert
 
Posts: 2823
Joined: Mon Jul 07, 2008 9:35 pm
Blog: View Blog (0)


Re: Stenographic Encoder/Decoder

Post by -Ninjex- on Sun Sep 22, 2013 7:55 am
([msg=77468]see Re: Stenographic Encoder/Decoder[/msg])

Goatboy wrote:Kinda funny, but when I googled "stenography" for a good definition, it actually gave me "steganography" first but *not* as a "Did you mean this?" suggestion.


Yeah seems the terms are interchangeably used quite a bit, hence why I assumed stenography was steganography, but it's fixed now.
If you're not willing to learn, no one can help you. If you're determined to learn, no one can stop you.⠠⠵
The absence of evidence is not evidence of absence.
I can explain it for you, but I can't understand it for you.
^(-.^)>
User avatar
-Ninjex-
Addict
Addict
 
Posts: 1449
Joined: Sun Sep 02, 2012 8:02 pm
Blog: View Blog (0)


Re: Steganographic Encoder/Decoder

Post by aeroxtk on Sun Sep 22, 2013 11:26 am
([msg=77470]see Re: Steganographic Encoder/Decoder[/msg])

Now to stay on topic, I've had an intention of writing something quite similar but far more expanded as a notion and advanced. It was gonna include things such as multiple layers of concealment, kleptography, cryptovirology, LSB steganography, obfuscation through esoteric languages, polymorphism and a lot of other things.

I'm gonna post my partial source regarding this very challenge once I finalize the whole project. But anyway, thanks for hitting me up with the idea of graphical representation.
Isolation, in my world means opportunity. Reflection of that nature undoubtedly brings round to the fact that comprehension is a requisite of success and thence exculpates the notion associated with the above alluded quips.
User avatar
aeroxtk
New User
New User
 
Posts: 24
Joined: Wed Oct 17, 2012 8:29 am
Location: Bulgaria
Blog: View Blog (0)


Re: Steganographic Encoder/Decoder

Post by Amazingred on Thu Oct 03, 2013 2:37 am
([msg=77589]see Re: Steganographic Encoder/Decoder[/msg])

#EDITED AGAIN

Here is a setup script (for windows) to get all the packages you'll need to run this on top of the modules included

Code: Select all
import urllib, subprocess

url='https://bitbucket.org/pypa/setuptools/raw/0.8/ez_setup.py'
easyinstall='easy_install.py'
urllib.urlretrieve(url, easyinstall)
subprocess.check_output('easy_install.py install', shell=True)
subprocess.check_output('easy_install matplotlib', shell=True)
subprocess.check_output('easy_install numpy', shell=True)
subprocess.check_output('easy_install pytz', shell=True)
subprocess.check_output('easy_install six', shell=True)
subprocess.check_output('easy_install dateutil', shell=True)
subprocess.check_output('easy_install mechanize', shell=True)
subprocess.check_output('easy_install BeautifulSoup', shell=True)


Python

install the matplotlib packages and numpy for this one...
Okay I think this is what you meant. This one made my brain hurt. Here is my first attempt.

How it works:
This will take your message input and return an image showing a graph that passes through 5 coordinates. The message itself is also encoded into the image pixels under the ALPHA band (which have all been similarly randomized so the message isn't obvious.) The script will retrieve the correct pixels and decode the message when you give the decode information which you can get by using the coordinates listed on the graph.

Encoding:
simply select the name of an output file in the command line and it will prompt you for the text you want to encode. Then it will apply the cipher and save an image to the name you specified containing the graph.

Decoding:
Each coordinate represents a number (i.e. 97)
To determine the correct decode data you must get the binary representation of that character (i.e. for 97 it is '0b1100001')
then for each value of 1 input that index number (0-8 NOT 1-9 REMEMBER) so for a it would be 238 since the 2nd 3rd and 8th index were values of 1. Do that for all 5 coordinates separated by a comma and the message will decode itself.
(it should look something like this '23,235,245,23458,24578')

My file is saved as stinkdeck.py.
Usage from the commandline is as follows:
stinkdeck.py <MODE>
Modes:
-o Outputfilename for encoding message into graph
-i input filename for decoding message from graph image

(i.e. stinkdeck.py -i amazingredscipher.png)


Python

Code: Select all
#!/usr/bin/env python
import matplotlib.pyplot as plt
import random,sys,getopt
from PIL import Image
"""
Stink-Deck.py V1.0
(STEgENC-DEC)
By: AmazingRed
Created 9/24/2013

This is my multi-purpose encryption/decryption/stego tool.  This will take a
message input from a user and return a graph image.  The data on the graph is
all the information required to decode the message itself. The text of the
message is also hidden inside the graph image pixels and will be successfully
extracted upon the entry of the correct data at the decoder input.

Use from command line: stinkdeck.py MODE
    Modes:
        -i inputfile (for decryption mode)
        -o outputfile (for encryption mode)
"""

helptext="""Usage stinkdeck.py MODE
    Modes:
        -i inputfile (for decryption mode)
        -o outputfile (for encryption mode)
            """

def encodeCharacters(message):
    """
    Takes message and codes it from text to numbers and returns the numbers list
    """
    newmessage=[]
    for i in message:
        curtry=[]
        while len(curtry)!=2:
            curnum=random.randrange(ord(i)/3-5, ord(i)/3+6)
            if curnum<0: curnum=0
            curtry.append(curnum)
        curtry.append(ord(i)-sum(curtry))
        for i in curtry:
            newmessage.append(i)
    numa=(random.randrange(32,53))
    numb=(random.randrange(32,53))
    numc=126-(numa+numb)
    newmessage.append(numa)
    newmessage.append(numb)
    newmessage.append(numc)
    return newmessage

def returnskipslist(graphvalues):
    skips=[[y for y, x in enumerate(list(i)) if x == "1"] for i in [bin(int(i)) for i in graphvalues]]
    skipslist=[]
    placeholder=[]
    for i in skips:
        for x in i:
            placeholder.append(str(x))
        skipslist.append(''.join(placeholder))
        placeholder=[]
    skipslist=[int(i) for i in skipslist]
    return skipslist

def equalize_image(img):
    """
    This function just takes a graph image and gets rid of any odd pixels so that
    the coding or decoding iteration doesn't fail.
    """
    for x in range(img.size[0]):
        for y in range(img.size[1]):
            pix=img.getpixel((x,y))
            if pix[0:3]==(255,255,255):
                img.putpixel((x,y), (255,255,255,255))
    return img

def CIPHER(outputfile):
    """
    Takes text input by user and saves an image containing a line graph
    passing through several coordinates. The coordinates given is the
    information needed to compute the decoding data IF YOU KNOW HOW TO USE IT.

    Great tool for one-way blind hidden messages!!!
    """

    text=raw_input("Please enter the text you would like to encode:")
    encoded_message=encodeCharacters(text)

    randomkey=[chr(random.choice(range(65,123))) for i in range(5)]
    graphvalues=[ord(i) for i in randomkey]
    skips=returnskipslist(graphvalues)

    fig = plt.figure(1,figsize=(5,5))
    axis = fig.add_subplot(111, autoscale_on=False,xlim=(0,len(graphvalues)-1),ylim=(0,max(graphvalues)))
    plt.plot(graphvalues)
    for i in range(0, len(graphvalues)):
        plt.annotate(graphvalues[i], xy=(i, graphvalues[i]-5))
    plt.grid(b=True, color='b', linestyle='-')
    plt.savefig(outputfile)

    img=Image.open(outputfile)
    minmax=(min(encoded_message), max(encoded_message)+1)
    img=equalize_image(img)
    count=0
    target=skips[0]
    xcoord,ycoord=0,0
    while len(encoded_message)>0:
        ycoord+=1
        if ycoord==img.size[1]:
            ycoord=0
            xcoord+=1
            if xcoord==img.size[0]:
                xcoord=0
        pix=img.getpixel((xcoord,ycoord))
        if pix==(255,255,255,255):
            count+=1
            if count==target:
                img.putpixel((xcoord,ycoord),(255,255,255,255-encoded_message[0]))
                encoded_message.pop(0)
                count=0
                skips.append(skips[0])
                skips.pop(0)
                target=skips[0]
    for y in range(img.size[1]):
        for x in range(img.size[0]):
            pixel=img.getpixel((x,y))
            if pixel==(255,255,255,255):
                img.putpixel((x,y), (255,255,255,255-random.randrange(minmax[0], minmax[1])))
    img.save(outputfile)
    img.close()

def DECIPHER(inputfile):
    """
    Takes an encoded graph image and loads it for decryption.  Will show the
    image to the user so they can see the coordinates and ask them for the
    decode values.  User must input the DECODE DATA not the graph data.
    """
    decodeimg=Image.open(inputfile)
    decodeimg.show()
    skiplist=[i for i in input('Please input decode values separated by a ,')]
    img=equalize_image(decodeimg.copy())
    count=0
    target=skiplist[0]
    xcoord,ycoord=0,0
    decoded,placeholder=[],[]
    last=0
    while '~' not in decoded:
        ycoord+=1
        if ycoord==img.size[1]:
            ycoord=0
            xcoord+=1
            if xcoord==img.size[0]:
                xcoord=0
        pix=img.getpixel((xcoord,ycoord))
        if pix==(255,255,255,255):
            count+=1
            if count==target:
                img.putpixel((xcoord,ycoord), (0,0,0,0))
                pix=decodeimg.getpixel((xcoord,ycoord))[3]
                count=0
                skiplist.append(skiplist[0])
                skiplist.pop(0)
                target=skiplist[0]
                if len(placeholder)==2:
                    placeholder.append(255-pix)
                    decoded.append(chr(sum(placeholder)))
                    placeholder=[]
                else:
                    placeholder.append(255-pix)
    decoded.remove('~')
    print ''.join(decoded)
    img.close()
    decodeimg.close()

def main():
    try:
        opts, args=getopt.getopt(sys.argv[1:], "hi:o:")
    except:
        print "Error getting command line args!"
        print helptext
        sys.exit(2)
    for opt, arg in opts:
        if opt=='-h':
            print helptext
            sys.exit()
        elif opt=='-i':
            inputfile=arg
            DECIPHER(inputfile)
        elif opt=='-o':
            outputfile=arg
            CIPHER(outputfile)

if __name__ == '__main__':
    main()
Last edited by Amazingred on Tue Oct 15, 2013 1:43 pm, edited 1 time in total.
There are 10 types of people in the world. Those who understand binary and those who don't.
User avatar
Amazingred
Experienced User
Experienced User
 
Posts: 73
Joined: Wed Jul 25, 2012 7:10 pm
Location: Wayyyyyy out there
Blog: View Blog (0)


Re: Steganographic Encoder/Decoder

Post by -Ninjex- on Mon Oct 07, 2013 1:11 am
([msg=77608]see Re: Steganographic Encoder/Decoder[/msg])

@Amazingred, congratz on being the first to complete this challenge! I really loved your approach on this by the way!

The easy install could have worked, I tested it out, but it was just more efficient for me to go ahead and install the whole package since I am running linux using: sudo apt-get install python-matplotlib

Phenomenal work with the program +310 points have been added. The program meets and goes beyond (maybe not hehe) all the requirements I was looking for.

*****************************************************************
*****************************************************************
I guess I will post my horrific code compared to Amazingred heh
This was just a quick bit of code I made as an example really, but here goes

Using Ruby with MD5 and Gruff libraries
Code: Select all
#!/usr/bin/ruby
require 'rubygems'
require 'gruff'
require 'digest/md5'

# Setting up a list of array's to hold graph information
@a = Array.new
@b = Array.new
@c = Array.new
@d = Array.new
@e = Array.new
@f = Array.new
@one   = Array.new
@two   = Array.new
@three = Array.new
@four  = Array.new
@five  = Array.new
@six   = Array.new
@seven = Array.new
@eight = Array.new
@nine  = Array.new
@zero  = Array.new

def create_image

  # Here we take the graph information and create an image from it:
  g = Gruff::Line.new
  g.title = "FIGURE IT OUT"
  g.data("A", @a)
  g.data("B", @b)
  g.data("C", @c)
  g.data("D", @d)
  g.data("E", @e)
  g.data("F", @f)
  g.data("1", @one)
  g.data("2", @two)
  g.data("3", @three)
  g.data("4", @four)
  g.data("5", @five)
  g.data("6", @six)
  g.data("7", @seven)
  g.data("8", @eight)
  g.data("9", @nine)
  g.data("0", @zero)
  g.marker_count = 16
  g.write('key.png')
end

def get_key(data)
  # Here we take the data to encode, convert it to MD5 and get a sum of the value of all ascii values
  key = 0  # This will be our key's value (The sum of all characters in the MD5 hash)
  cntr = 0 # We need this to authorize correct pushes to our graph array's
  md5 = Digest::MD5.hexdigest(data) # Convert the data to encode to an MD5 hash
  puts "MD5 Sum: #{md5}" # Uncomment if you need to verify the graph data (This should not be ran for stego purposes)
  md5_split = md5.split('') # Split the hash by each character
  md5_split.each do |val|   # For each character
    cntr += 1
    # Here we push each character to the desired array
       if val == 'a' then @a.push(cntr)
    elsif val == 'b' then @b.push(cntr)
    elsif val == 'c' then @c.push(cntr)
    elsif val == 'd' then @d.push(cntr)
    elsif val == 'e' then @e.push(cntr)
    elsif val == 'f' then @f.push(cntr)
    elsif val == '1' then @one.push(cntr)
    elsif val == '2' then @two.push(cntr)
    elsif val == '3' then @three.push(cntr)
    elsif val == '4' then @four.push(cntr)
    elsif val == '5' then @five.push(cntr)
    elsif val == '6' then @six.push(cntr)
    elsif val == '7' then @seven.push(cntr)
    elsif val == '8' then @eight.push(cntr)
    elsif val == '9' then @nine.push(cntr)
    elsif val == '0' then @zero.push(cntr)
    end
    ascii = val.ord # Grab the ascii value of the character
    key += ascii    # add the ascii value to the key
  end
   puts "Key: #{key}" # Uncomment if you need to verify the MD5 key value (This should not be ran for stego purposes)
  return key # Return the key for use
end

def encrypt

  # Here we add or subtract the key value from each character depending on it's state
  encrypted_text = '' # This will hold the final encoded data
  print "Encrypt: "
  data = gets.chomp
  key = get_key(data) # Grab the key for the desired encoded text

  chars = data.split('') # Split our text by each character
  chars.each do |val|
    ascii = val.ord  # Grab the characters ascii value
    if ascii.even?   # If the value is even
      up = (ascii + key) # Add the key value to it
      encrypted_text += "#{up}." # Store it in our variable
    else ascii.odd?  # Otherwise if it's odd
      down = (ascii - key) # Subtract the key value from it
      encrypted_text += "#{down}." # Store it in our variable
    end
  end
puts encrypted_text # Output the encoded data
end

def decrypt
  # Here we do the opposite steps of encrypt

  decrypted_text = ''
  print "Key: "
  key = gets.chomp.to_i
  puts "Decrypt: "
  print "> "
  data = gets.chomp

  split_data = data.split('.') # Seperate the data from the .'s
  split_data.each do |val|
    val = val.to_i
    if val <= 32  # Here we can just check if the value is less than 32 since the value from get_key() will never be higher than this if it's odd
      up = (val + key)
      char = up.chr
      decrypted_text += "#{char}"
    else
      down = (val - key)
      char = down.chr
      decrypted_text += "#{char}"
    end
  end
  puts decrypted_text
end

while true # Create a fancy option menu
  print "Choose an option [-e]ncode [-d]ecode [-q]uit: "
  choice = gets.chomp
  if choice == '-e'
    encrypt
    create_image
  elsif choice == '-d'
    decrypt
  elsif choice == '-q'
    abort('Terminating')
  else
    puts "Invalid choice, try again"
  end
end


For simplicity, I have the code uncommented to display the key. The encrypted text it output to the terminal, and then the key can be used to decrypt the string via the -d option. I want to update this code later and have the encrypted text stored inside the image, which isn't too hard, and then have the decrypt function pull that bit of code from it. This will make it even more secure.
The way this works, is that it simply takes the text given, converts the characters to ASCII format, and determines if it is even or odd, where different arithmetic operations will take place. After everything is converted and encoded, we take the encoded text and get a MD5 sum for it. We then take each character in the MD5 sum and push it into an array, and then push it into a graph image. The decoding key is the sum of the ASCII value of the MD5 characters. You can obtain the key by keeping the part uncommented in the program above, or decipher it from the graph image (recommended for additional steganography)
If you're not willing to learn, no one can help you. If you're determined to learn, no one can stop you.⠠⠵
The absence of evidence is not evidence of absence.
I can explain it for you, but I can't understand it for you.
^(-.^)>
User avatar
-Ninjex-
Addict
Addict
 
Posts: 1449
Joined: Sun Sep 02, 2012 8:02 pm
Blog: View Blog (0)



Return to User Submitted

Who is online

Users browsing this forum: No registered users and 0 guests