Created
January 30, 2018 01:37
-
-
Save EIREXE/736d80cd1299c3b019549899da5faa5b to your computer and use it in GitHub Desktop.
Steganography for the godot engine
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extends Node | |
const STEGANO_MAGIC_NUMBER = [0x45, 0x52, 0x4f, 0x31] #ERO1 | |
const STEGANO_CHUNK_END = [0x45, 0x52, 0x4f, 0x45] #EROE | |
const BITS_PER_BYTE = 2 # How many bits we take from each one, 1 is the least singificant bit | |
const STEGANO_FORMAT_VERSION = 1 | |
func store_string_in_image(image ,data): | |
print(data) | |
var text_binary = data.to_utf8().compress() | |
var text_compressed = text_binary.compress() | |
var payload = PoolByteArray(STEGANO_MAGIC_NUMBER) | |
payload.append(text_binary.size()) | |
payload.append(STEGANO_FORMAT_VERSION) | |
payload.append_array(text_compressed) | |
payload.append_array(PoolByteArray(STEGANO_CHUNK_END)) | |
return store_data_in_image(image, payload) | |
func store_data_in_image(image, data): | |
var image_data = image.get_data() | |
var writing_mask = 0 | |
for mask_i in range(BITS_PER_BYTE): | |
writing_mask = writing_mask | (0x1 << mask_i) | |
var image_position = 0 | |
for byte_i in range(data.size()): | |
var images_bytes_per_byte = 8/BITS_PER_BYTE | |
for insert_i in range(images_bytes_per_byte): | |
var insertion_mask = writing_mask << insert_i * MBITS_PER_BYTE | |
var bits_to_write = data[byte_i] & insertion_mask | |
bits_to_write = bits_to_write >> insert_i*BITS_PER_BYTE | |
var image_data_mask = 0xFF >> BITS_PER_BYTE | |
image_data_mask = image_data_mask << BITS_PER_BYTE | |
image_data[image_position+insert_i] = image_data[image_position+insert_i] & image_data_mask | |
image_data[image_position+insert_i] = image_data[image_position+insert_i] | bits_to_write | |
image_position += images_bytes_per_byte | |
var final_image = Image.new() | |
final_image.create_from_data(image.get_width(), image.get_height(), false, Image.FORMAT_RGB8, image_data) | |
return final_image | |
func get_steganographic_data_from_image(image): | |
extracted_data = PoolByteArray() | |
var image_data = image.get_data() | |
var data_mask = 0 | |
for mask_i in range(BITS_PER_BYTE): | |
data_mask = data_mask | (0x1 << mask_i) | |
var current_byte = 0 | |
var magic_number_position = -1 | |
for byte_i in range(image_data.size()): | |
var data = image_data[byte_i] & data_mask | |
var iterations_per_byte = 8/BITS_PER_BYTE | |
var current_bits = data & data_mask | |
current_byte = current_byte | (current_bits << ((byte_i % iterations_per_byte)*BITS_PER_BYTE)) | |
# 0 index bullcrap... | |
if byte_i % iterations_per_byte == iterations_per_byte-1: | |
extracted_data.append(current_byte) | |
if byte_i < 64: | |
pass | |
current_byte = 0 | |
if extracted_data.size() >= 4: | |
var potential_magic_number = extracted_data.subarray(extracted_data.size()-PoolByteArray(STEGANO_MAGIC_NUMBER).size(), extracted_data.size()-1) | |
if potential_magic_number == PoolByteArray(STEGANO_MAGIC_NUMBER): | |
magic_number_position = extracted_data.size()-1 | |
var potential_chunk_end = extracted_data.subarray(extracted_data.size()-PoolByteArray(STEGANO_CHUNK_END).size(), extracted_data.size()-1) | |
if potential_chunk_end == PoolByteArray(STEGANO_CHUNK_END): | |
break | |
if magic_number_position != -1: | |
var uncompressed_size_position = magic_number_position+1 | |
var uncompressed_size = extracted_data[uncompressed_size_position] | |
var version_number = magic_number_position+2 | |
var compressed_data_position = magic_number_position+3 | |
var compressed_data = extracted_data.subarray(compressed_data_position, extracted_data.size()-5) | |
var uncompressed_data = compressed_data.decompress(uncompressed_size).get_string_from_utf8() | |
return uncompressed_data | |
else: | |
return ERR_FILE_CORRUPT |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment