BacoNG Steganography (Part 2)
Based on the steps outlined in my initial BacoNG post the first thing I needed to figure out was how (in Python) to take a text string, encode it into binary and store it in an array.
So based on the steps outlined in my initial BacoNG post the first thing I needed to figure out was how (in Python) to take a text string, encode it into binary and store it in an array.
Every ASCII character that we see on a computer has an 8 digit binary representation.
For example: a = 01100001 | A = 01000001 | space = 01000001
Our python code should be able to take any string of characters, split it into individual letters and then encode each into their binary counterpart to be stored in an array.
To accomplish this, I created a class called toBinary which takes the string input and encodes it into an array of binary values for us to use later.
def toBinary(a): l,m=, for i in a: l.append(ord(i)) for i in l: m.append(int(bin(i)[2:])) return m
To then encode this data we need to loop through an array of values, subtracting the binary value in the same position (either 0 or 1) from each. To accomplish this we created a class named encode, which takes the string, encodes it into binary and then returns the encoded array.
def encode(string, array): testString = string testArray = toBinary(testString) arrayPosition = 1 len(testString) for j in range(len(testString)): letter = split(str(testArray[j])) loopControl = len(letter) k = 0 while k < loopControl: if letter[k] == '1': array[arrayPosition] = array[arrayPosition] - 1 else: array[arrayPosition] = array[arrayPosition] arrayPosition = arrayPosition + 1 k = k + 1 return(array)
From here we then need to be able to decode the array, ideally with the same string that we encoded it with! To do this we loop through the values of the array (assuming that 255 is the default, more on this later) and creating a new array with binary values based on whether or not the value is 254 or 255.
def decode(array): arrayPosition = 0 output =  sep = '' k = 0 j = 0 len(array) #will have to be dynamic length of array while j < len(array): #print(j) l = 0 for l in range(7): print(j) print(l) if array[k] == 254: output.append('1') else: output.append('0') #print("value of k is:", k) k = k + 1 j = j + 1 #print("value of l is:", l) #print("value of j is:", j) output.append(',') #print(output) j = j + 1 stringBinary = sep.join(output) print(stringBinary) characterBinary = stringBinary.split(',') #print('cB =', characterBinary) j = 0 for j in range(len(characterBinary)): characterASCII = int(characterBinary[j], base=2) print(chr(characterASCII))
And success! (Note that the code producing the output below is slightly different from the above - from the more final version - but still has the same intended output!)
There are, however, some drawbacks to how this code will function.
- It requires the array being fed into it to be consistent with the values to be able to understand whether it was a 0 or 1 that was encoded into it. This therefore means that a PNG that utilises its transparency values is not a valid candidate to encode our data.
- The encoded message length will be restricted to the total pixel count of the image divided by 7, due to the binary values being 7 characters long.
Next, we try to take the transparency values from an image, perform our encoding on the array and re-encode it back to an image!
If you wish to have a look at the code, or even contribute you can check out my Github repository here