commit 8b30fe923c07a9af267801f522118f429778b1c0 Author: Monqui Date: Wed Jul 16 01:48:49 2025 +0000 Initial catchat commit. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d4a9345 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +🐱 diff --git a/arty_new.png b/arty_new.png new file mode 100644 index 0000000..b1e1d86 Binary files /dev/null and b/arty_new.png differ diff --git a/decode_image.rb b/decode_image.rb new file mode 100644 index 0000000..412e113 --- /dev/null +++ b/decode_image.rb @@ -0,0 +1,51 @@ +class DecodeImage + @@password = "" + @@utils + + def initialize(pass, image) + @@password = pass + + # initializing utils... + @@utils = ImageUtils.new(@@password, image) + + @@table = @@utils.generateLookupTable + end + + def decode + s = @@utils.getImage.getSize + + msg_bits = 0 + + @@table.reverse.each do |loc| + pixel = @@utils.getImage.getPixel(loc[:x], loc[:y]) + msg_bits = (msg_bits << 6) | pixel.decodeBits + end + +#this trash needs to move somewhere... +puts "Try to convert the message..." + len = msg_bits & 0xffff + msg_bits = msg_bits >> 16 + + # check the padding bits.... + if (msg_bits & 255) != 0 then +puts "Padding failed scrutiny! " +puts msg_bits.to_s(2) + return false + end + + msg_bits = msg_bits >> 8 + +puts "Padding passed scrutiny..." + msg_chars = [] + + while msg_bits > 0 do + byte = msg_bits & 0xff + msg_chars.push(byte.chr) + msg_bits = msg_bits >> 8 + end + + msg = msg_chars.reverse.join + + return msg + end +end \ No newline at end of file diff --git a/encode_image.rb b/encode_image.rb new file mode 100644 index 0000000..9e6d7d1 --- /dev/null +++ b/encode_image.rb @@ -0,0 +1,88 @@ +class EncodeImage + @@password = "" + @@message = "" + + @@img = nil + + @@utils = nil + + + def initialize(p, m, i) + @@password = p + @@message = m + + @@utils = ImageUtils.new(@@password, @@message, i) + + @@table = @@utils.generateLookupTable + end + + def encode + msg_bits = @@utils.getImage.getBits(@@message) + msg_bits = msg_bits << 8 | 0 + msg_bits = msg_bits << 16 | @@message.length + + s = @@utils.getImage.getSize + + original_img = @@utils.getImage.fuzzImage + + @@table.each do |loc| + pixel = @@utils.getImage.getPixel(loc[:x], loc[:y]) + msg_bits = pixel.encodeBits(msg_bits) + end + +# for x in 0..s[:width]-1 +# for y in 0..s[:height]-1 + +# loc = {"x": x, "y": y} +# if @@table.include? loc then +# pixel = @@utils.getImage.getPixel(x, y) +# msg_bits = pixel.encodeBits(msg_bits) +# end +# end +# end + + @@utils.getImage.saveImage + end + + +# Need to properly sever this at some point... + + def decode +puts "Hacked in decode..." + s = @@utils.getImage.getSize + + msg_bits = 0 + + @@table.reverse.each do |loc| + pixel = @@utils.getImage.getPixel(loc[:x], loc[:y]) + msg_bits = (msg_bits << 6) | pixel.decodeBits + end + +#this trash needs to move somewhere... +puts "Try to convert the message..." + len = msg_bits & 0xffff + msg_bits = msg_bits >> 16 + + # check the padding bits.... + if (msg_bits & 255) != 0 then +puts "Padding failed scrutiny! " +puts msg_bits.to_s(2) + return false + end + + msg_bits = msg_bits >> 8 + +puts "Padding passed scrutiny..." + msg_chars = [] + + while msg_bits > 0 do + byte = msg_bits & 0xff + msg_chars.push(byte.chr) + msg_bits = msg_bits >> 8 + end + + msg = msg_chars.reverse.join + + return msg + end +end \ No newline at end of file diff --git a/image_utils.rb b/image_utils.rb new file mode 100644 index 0000000..8f7ee56 --- /dev/null +++ b/image_utils.rb @@ -0,0 +1,81 @@ +require "./pixel_image.rb" +require "digest" + +class ImageUtils + @@magickImg = nil + @@pixelImg = nil + + @@password = "" + @@message = "" + + @@hash = nil + + def initialize(pass, msg, i) + @@password = pass + @@message = msg + + if msg.length > 400 then + puts "Maximum length exceeded. Exiting." + exit + end + + @@magickImg = i + + @@pixelImg = PixelImage.new(@@magickImg) + + self.generateHash + end + + def getImage + return @@pixelImg + end + + def generateHash + h = Digest::SHA512.hexdigest(@@password) + s = @@pixelImg.getSalt + + merge_to_i = h + s + + @@hash = Digest::SHA512.hexdigest(h+s) + end + + def generateLookupTable + tbl = [] + + hash_bits = @@pixelImg.getBits(@@hash) + msg_bits = @@pixelImg.getBits(@@message) + + # gross, but pad in the 24 bits that will become the msg length + # and padding bits... + msg_bits = msg_bits << 24 + + while msg_bits > 0 do + loc = nil + + loop do + x = (hash_bits.to_i % @@pixelImg.getSize[:width]) + y = (hash_bits.to_i % @@pixelImg.getSize[:height]) + + loc = {"x": x, "y": y} + + break if !tbl.include?(loc) + hash_bits = hash_bits >> 1 + + if hash_bits <= 0 then + puts + puts "wow too much data" + puts "leftover bits: " + msg_bits.to_s(36) + exit + end + end + + hash_bits = hash_bits >> 1 + + tbl.push(loc) + + msg_bits = msg_bits >> 6 + end + + return tbl + end +end \ No newline at end of file diff --git a/images/original/arty.png b/images/original/arty.png new file mode 100644 index 0000000..3622ef1 Binary files /dev/null and b/images/original/arty.png differ diff --git a/pixel.rb b/pixel.rb new file mode 100644 index 0000000..699b89b --- /dev/null +++ b/pixel.rb @@ -0,0 +1,61 @@ +class Pixel + @mp = nil + + @r = 0 + @g = 0 + @b = 0 + + def initialize(mp) + @mp = mp + + @r = @mp.red + @g = @mp.green + @b = @mp.blue + end + + def randomize + @r = ((@r >> 2) << 2) | rand(4) + @g = ((@g >> 2) << 2) | rand(4) + @b = ((@b >> 2) << 2) | rand(4) + end + + def getMagickPixel + @mp.red = @r + @mp.green = @g + @mp.blue = @b + return @mp + end + + def getPixelBits() + bits = 0 + + bits = (bits << 8) | @r + bits = (bits << 8) | @g + bits = (bits << 8) | @b + + return bits + end + + def encodeBits(bits) + @r = ((@r >> 2) << 2) | (bits & 3) + bits = bits >> 2 + + @g = ((@g >> 2) << 2) | (bits & 3) + bits = bits >> 2 + + @b = ((@b >> 2) << 2) | (bits & 3) + bits = bits >> 2 + + return bits + end + + def decodeBits + bits = 0 + + bits = (bits << 2) | (@b & 3) + bits = (bits << 2) | (@g & 3) + bits = (bits << 2) | (@r & 3) + + return bits + end +end \ No newline at end of file diff --git a/pixel_image.rb b/pixel_image.rb new file mode 100644 index 0000000..3e71387 --- /dev/null +++ b/pixel_image.rb @@ -0,0 +1,128 @@ +require "./pixel.rb" + +class PixelImage + @@magickImg = nil + + @@pixels = [] + + def initialize(i) + @@magickImg = i + @@width = @@magickImg.columns + @@height = @@magickImg.rows + + self.buildPixels + end + + def buildPixels + tmp_pixels = @@magickImg.get_pixels(0, 0, @@width, @@height) + + for x in 0..@@width-1 + @@pixels[x] = [] + for y in 0..@@height-1 + @@pixels[x][y] = Pixel.new(tmp_pixels.pop) + end + end + end + + # Only used for generating truly random base images + def randomPixels + for x in 0..@@width-1 + @@pixels[x] = [] + for y in 0..@@height-1 + pixel = 0 + + r = rand(256) + g = rand(256) + b = rand(256) + + pixel = (pixel << 8) | r + pixel = (pixel << 8) | g + pixel = (pixel << 8) | b + @@pixels[x][y] = Pixel.new(pixel) + end + end + end + + def saveImage + puts "and the mult is..." + + puts @@width * @@height + + pixel_array = [] + + for x in @@pixels.reverse.each do + for y in x.reverse.each do + pix = y.getMagickPixel + + pixel_array.append(pix.red) + pixel_array.append(pix.green) + pixel_array.append(pix.blue) + end + end + + new_img = Magick::Image.new(@@width, @@height) + + + new_img.import_pixels(0, 0, @@width, @@height, "RGB", pixel_array) + + new_img.write("arty_new.png") + end + + def getPixels + return @@pixels + end + + def getPixel(x, y) + return @@pixels[x][y] + end + + def setPixelBits(x, y, bits) + @@pixels[x][y] = Pixel.new(bits) + end + + def getSize + return {"width": @@width, "height": @@height} + end + + def fuzzImage + for x in 0..@@width-1 do + for y in 0..@@height-1 do + @@pixels[x][y].randomize + end + end + end + + def getSalt + salt = 0 + + for x in 0..@@width-1 + for y in 0..@@height-1 + pix = @@pixels[x][y].getPixelBits + + salt = salt << 6 | ((pix >> 2) & 0b111111) + pix = pix >> 8 + salt = salt << 6 | ((pix >> 2) & 0b111111) + pix = pix >> 8 + salt = salt << 6 | ((pix >> 2) & 0b111111) + pix = pix >> 8 + + end + end + + h = Digest::SHA512.hexdigest(salt.to_s(16)) + + return h + end + + def getBits(o) + msg_bytes = o.unpack("c*") + + msg_bits = 0 + + for b in msg_bytes + msg_bits = (msg_bits << 8) | b + end + + return msg_bits + end +end \ No newline at end of file diff --git a/runner.rb b/runner.rb new file mode 100644 index 0000000..9111825 --- /dev/null +++ b/runner.rb @@ -0,0 +1,50 @@ +require "rmagick" + +require "./image_utils.rb" +require "./encode_image.rb" + +img = Magick::ImageList.new "./images/original/arty.png" + +#srand(12345) + +pass = "my_password" +message = "This is the message that I would like to save please " + + "and thank you also I love you? AND apostrophe's, and " + + "also some commas somewhere hiding around here, It's " + + "gonna be pushing it a bit here... 1234567 let's huck " + + "some more stuff in here to bump it to 255. Wow. We " + + "are going even further. further than anyone believed " + + "`~!@\#\{$%^&*()-_=+\][}{';:'}]} Wooow. 123456789!1234" + + "56789! so put 15 more??????400!" +#message = "tests" + +puts message.length +puts message +puts + +puts "Initializing EncodeImage..." + +start = Time.new.to_f + +em = EncodeImage.new(pass, message, img) + +puts em.encode +puts "Took " + (Time.new.to_f - start).to_s + " seconds to encode... 🐱" +puts + +start = Time.new.to_f + +result = em.decode + +puts result + +puts "Took " + (Time.new.to_f - start).to_s + " seconds to decode... 🐱" + +if message == result then + puts "WOW THEY MATCH! 🐱🐱🐱🐱🐱🐱🐱🐱" +end + +exit +puts + +puts "Done!" \ No newline at end of file