require "rmagick" require "digest" class ImageUtils @@magickImg = nil @@password = "" @@message = "" @@hash = nil @@width = 0 @@height = 0 @@pixel_arr = [] def initialize(pass, msg, uri) @@password = pass @@message = msg @@salt = 0 @@magickImg = Magick::Image.read(uri).first @@width = @@magickImg.columns @@height = @@magickImg.rows @@pixel_arr = @@magickImg.get_pixels(0, 0, @@width, @@height) if msg.length > 1024 then puts "Maximum length exceeded. Exiting." exit end self.generateHash end def getPixel(x, y) loc = (y*@@width) + x return @@pixel_arr[loc] end def getSalt for x in 0..@@width-1 for y in 0..@@height-1 pix = self.getPixel(x, y) @@salt = @@salt + (pix.red/512) @@salt = @@salt + (pix.green/512) @@salt = @@salt + (pix.blue/512) end end h = Digest::SHA512.hexdigest(@@salt.to_s(16)) return h end def generateHash pass_h = Digest::SHA512.hexdigest(@@password) @@hash = Digest::SHA512.hexdigest(pass_h + @@salt.to_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 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