You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 
 
 
 
 

86 lines
2.2 KiB

  1. import PIL.Image
  2. import sys
  3. def get_bitstream(message):
  4. for c in message:
  5. bin_string = "{:08b}".format(c)
  6. for bit in bin_string:
  7. yield int(bit)
  8. def parse_bitstream(stream):
  9. for bits in by_chunk(stream, 8, fillvalue=0):
  10. binstr = "".join([str(b) for b in bits])
  11. c = int(binstr, 2)
  12. if chr(c) == "\n":
  13. break
  14. yield c
  15. def by_chunk(iterable, size, fillvalue=0):
  16. "Collect data into fixed-length chunks or blocks"
  17. chunk = []
  18. for x in iterable:
  19. chunk.append(x)
  20. if len(chunk) >= size:
  21. yield chunk
  22. chunk = []
  23. def set_bit(old_byte, new_bit):
  24. b = list(bin(old_byte))
  25. b[-1] = str(new_bit)
  26. return int("".join(b), 2)
  27. def main_encrypt():
  28. message = (sys.argv[2] + "\n").encode()
  29. base_name = sys.argv[3]
  30. carrier_name = base_name.replace(".png", ".carrier.png")
  31. base_image = PIL.Image.open(base_name)
  32. width, height = base_image.size
  33. new_image = PIL.Image.new("RGB", (width, height), "white")
  34. bitstream = get_bitstream(message)
  35. for row in range(height):
  36. for col in range(width):
  37. r, g, b, = base_image.getpixel((col, row))
  38. value = None
  39. try:
  40. value = next(bitstream)
  41. except StopIteration:
  42. pass
  43. if value is not None:
  44. r = set_bit(r, value)
  45. new_image.putpixel((col, row), (r, g, b))
  46. new_image.save(carrier_name, "png")
  47. print("carrier written to", carrier_name)
  48. def yield_bits(carrier_image):
  49. width, height = carrier_image.size
  50. for row in range(height):
  51. for col in range(width):
  52. r, g, b, = carrier_image.getpixel((col, row))
  53. last_bit = int(bin(r)[-1])
  54. yield last_bit
  55. def main_decrypt():
  56. carrier_name = sys.argv[2]
  57. carrier_image = PIL.Image.open(carrier_name)
  58. encoded = yield_bits(carrier_image)
  59. decoded = bytes(parse_bitstream(encoded))
  60. print(decoded.decode())
  61. def main():
  62. if sys.argv[1] == "encrypt":
  63. main_encrypt()
  64. elif sys.argv[1] == "decrypt":
  65. main_decrypt()
  66. else:
  67. sys.exit("choose from encrypt, decrypt")