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.
 
 
 
 
 
 

83 lines
2.1 KiB

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