Transférer les fichiers vers ''
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								default_image.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								default_image.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 36 KiB  | 
							
								
								
									
										145
									
								
								libstegano.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								libstegano.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
			
		||||
"""
 | 
			
		||||
A library for the steganography program
 | 
			
		||||
Copyright (C) 2022  Valentin Moguérou
 | 
			
		||||
 | 
			
		||||
This program is free software: you can redistribute it and/or modify
 | 
			
		||||
it under the terms of the GNU General Public License as published by
 | 
			
		||||
the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
(at your option) any later version.
 | 
			
		||||
 | 
			
		||||
This program is distributed in the hope that it will be useful,
 | 
			
		||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
You should have received a copy of the GNU General Public License
 | 
			
		||||
along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from typing import BinaryIO
 | 
			
		||||
from PIL import Image
 | 
			
		||||
 | 
			
		||||
# ================= BINARY OPERATIONS =================
 | 
			
		||||
 | 
			
		||||
def write_lsb_in_bin(byte, bit):
 | 
			
		||||
    "Write the specified bit in the LSB of the specified byte"
 | 
			
		||||
    return byte & 254 | bit if bit==1 else byte & 254
 | 
			
		||||
 | 
			
		||||
def read_lsb_in_bin(byte):
 | 
			
		||||
    return byte & 1
 | 
			
		||||
 | 
			
		||||
def combine_bits_to_byte(bits):
 | 
			
		||||
    """
 | 
			
		||||
    Turns a sequence of bits into an integer.
 | 
			
		||||
    Example: turns [0, 1, 1, 0, 1, 1, 0, 1] into 0b01101101 or 109
 | 
			
		||||
    """
 | 
			
		||||
    return sum(bits[-1-i]<<i for i in range(len(bits)))
 | 
			
		||||
 | 
			
		||||
def split_byte_into_bits(integer):
 | 
			
		||||
    """
 | 
			
		||||
    Turns an integer into an array of bits
 | 
			
		||||
    Example: turns 109 or 0b01101101 into [0, 1, 1, 0, 1, 1, 0, 1]
 | 
			
		||||
    """
 | 
			
		||||
    return [integer>>(7-i)&1 for i in range(8)]
 | 
			
		||||
 | 
			
		||||
def hex_print(byte_list, margin=0, line_width=16):
 | 
			
		||||
    "Prints a byte list in hexadecimal"
 | 
			
		||||
 | 
			
		||||
    for line in range(0, len(byte_list), line_width):
 | 
			
		||||
        print(' '*margin + ' '.join(f'{byte:02X}' for byte in byte_list[line:line+line_width]))
 | 
			
		||||
 | 
			
		||||
# ================= STRING OPERATIONS =================
 | 
			
		||||
 | 
			
		||||
def encode_string(string: str) -> bytearray:
 | 
			
		||||
    "Turns the given string into a byte array"
 | 
			
		||||
    return bytearray(ord(ch) for ch in string+'\0')
 | 
			
		||||
 | 
			
		||||
def decode_string(bytelist: bytearray) -> str:
 | 
			
		||||
    "Turns the given byte array into a string"
 | 
			
		||||
    return ''.join(chr(b) for b in bytelist)
 | 
			
		||||
 | 
			
		||||
# ================= WRITE OPERATIONS =================
 | 
			
		||||
 | 
			
		||||
def write_band(band: bytearray, byte_list: bytearray, starting_pos=0) -> bool:
 | 
			
		||||
    "Writes a byte sequence in the given band"
 | 
			
		||||
 | 
			
		||||
    for index in range(starting_pos, len(band), 8):
 | 
			
		||||
        band[index:index+8] = (write_lsb_in_bin(band[index+i], bit) for i, bit in enumerate(split_byte_into_bits(byte_list[index//8])))
 | 
			
		||||
        if byte_list[index//8] == 0:
 | 
			
		||||
            return True, index+8 # finished writing
 | 
			
		||||
    return False, index+8 # didn't finish writing, return last index
 | 
			
		||||
 | 
			
		||||
def write_image(img: Image.Image, byte_list, verbose=False):
 | 
			
		||||
    data = [bytearray(band.tobytes()) for band in img.split()]
 | 
			
		||||
 | 
			
		||||
    ok, position = write_band(data[0], byte_list)
 | 
			
		||||
    if not ok:
 | 
			
		||||
        ok, position = write_band(data[1], byte_list, position)
 | 
			
		||||
    if not ok:
 | 
			
		||||
        ok, position = write_band(data[2], byte_list, position)
 | 
			
		||||
    if not ok:
 | 
			
		||||
        raise ValueError("The byte sequence is too long.")
 | 
			
		||||
 | 
			
		||||
    if verbose:
 | 
			
		||||
        print(f"{position} bits, {position//8} bytes successfully written.")
 | 
			
		||||
 | 
			
		||||
    return Image.merge(img.mode, [Image.frombytes('L', img.size, bytes(band)) for band in data])
 | 
			
		||||
 | 
			
		||||
def write_file(from_file: BinaryIO, to_file: BinaryIO, byte_list, verbose=False):
 | 
			
		||||
    write_image(Image.open(from_file), byte_list, verbose=verbose).save(to_file)
 | 
			
		||||
 | 
			
		||||
# ================= READ OPERATIONS =================
 | 
			
		||||
 | 
			
		||||
def read_band(band: bytes, byte_list: bytearray) -> bool:
 | 
			
		||||
    "Turns a sequence of pixels into a byte list"
 | 
			
		||||
 | 
			
		||||
    for i in range(0, len(band), 8):
 | 
			
		||||
        bits = [read_lsb_in_bin(b) for b in band[i:i+8]]
 | 
			
		||||
        if all(b==0 for b in bits):
 | 
			
		||||
            return True # finished reading
 | 
			
		||||
        byte_list.append(combine_bits_to_byte(bits))
 | 
			
		||||
    return False # didn't finish reading
 | 
			
		||||
 | 
			
		||||
def read_image(img: Image.Image, verbose=False):
 | 
			
		||||
    "Read the whole image"
 | 
			
		||||
 | 
			
		||||
    data = [band.tobytes() for band in img.split()]
 | 
			
		||||
    byte_list = bytearray()
 | 
			
		||||
 | 
			
		||||
    if read_band(data[0], byte_list):
 | 
			
		||||
        if verbose:
 | 
			
		||||
            print("Successfully finished reading.")
 | 
			
		||||
    elif read_band(data[1], byte_list):
 | 
			
		||||
        if verbose:
 | 
			
		||||
            print("Successfully finished reading.")
 | 
			
		||||
            print("Read the whole red band.")
 | 
			
		||||
    elif read_band(data[1], byte_list):
 | 
			
		||||
        if verbose:
 | 
			
		||||
            print("Successfully finished reading.")
 | 
			
		||||
            print("Read the whole green band.")
 | 
			
		||||
    else:
 | 
			
		||||
        if verbose:
 | 
			
		||||
            print("Read the whole blue band.")
 | 
			
		||||
        raise ValueError("Invalid image, did not find end control sequence.")
 | 
			
		||||
 | 
			
		||||
    return byte_list
 | 
			
		||||
 | 
			
		||||
def read_file(from_file: BinaryIO, verbose=False):
 | 
			
		||||
    return read_image(Image.open(from_file), verbose=verbose)
 | 
			
		||||
 | 
			
		||||
# ================= EXAMPLE PROGRAM =================
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    s = "This is a string"
 | 
			
		||||
    oldimg = Image.open('guitar.jpg')
 | 
			
		||||
    oldimg.load()
 | 
			
		||||
    print(encode_string(s))
 | 
			
		||||
    newimg = write_image(oldimg, encode_string(s))
 | 
			
		||||
    newimg.save('dissimulated.png', 'PNG')
 | 
			
		||||
    print('Written...')
 | 
			
		||||
 | 
			
		||||
    print(f"String: --> {read_image(Image.open('guitar.jpg'))} (guitar.jpg)")
 | 
			
		||||
    print(f"String: --> {decode_string(read_image(Image.open('dissimulated.png')))} (dissimulated.png)")
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    main()
 | 
			
		||||
							
								
								
									
										73
									
								
								steganocli.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								steganocli.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
A command-line interface for the steganography program
 | 
			
		||||
Copyright (C) 2022  Valentin Moguérou
 | 
			
		||||
 | 
			
		||||
This program is free software: you can redistribute it and/or modify
 | 
			
		||||
it under the terms of the GNU General Public License as published by
 | 
			
		||||
the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
(at your option) any later version.
 | 
			
		||||
 | 
			
		||||
This program is distributed in the hope that it will be useful,
 | 
			
		||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
You should have received a copy of the GNU General Public License
 | 
			
		||||
along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from argparse import ArgumentParser as ArgParser
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
 | 
			
		||||
from libstegano import read_file, write_file, decode_string, encode_string, hex_print
 | 
			
		||||
 | 
			
		||||
def read(args):
 | 
			
		||||
    if args.verbose:
 | 
			
		||||
        print("Read mode enabled.")
 | 
			
		||||
    
 | 
			
		||||
    with open(args.from_file, 'rb') as from_file:
 | 
			
		||||
        byte_list = read_file(from_file, verbose=args.verbose)
 | 
			
		||||
 | 
			
		||||
        if args.verbose:
 | 
			
		||||
            print(f"Read {(len(byte_list)+1)*8} bits, {len(byte_list)+1} bytes.")
 | 
			
		||||
            print("======== BEGIN MESSAGE ========")
 | 
			
		||||
            print(decode_string(byte_list))
 | 
			
		||||
            print("========= END MESSAGE =========")
 | 
			
		||||
        else:
 | 
			
		||||
            print(decode_string(byte_list))
 | 
			
		||||
 | 
			
		||||
def write(args):
 | 
			
		||||
    byte_list = encode_string(args.string)
 | 
			
		||||
 | 
			
		||||
    with open(args.from_file, 'rb') as from_file, open(args.to_file, 'wb') as to_file:
 | 
			
		||||
        if args.verbose:
 | 
			
		||||
            print("Write mode enabled.")
 | 
			
		||||
            print("================== BYTE STREAM ==================")
 | 
			
		||||
            hex_print(byte_list, margin=1)
 | 
			
		||||
            print("================== BYTE STREAM ==================")
 | 
			
		||||
 | 
			
		||||
        write_file(from_file, to_file, byte_list, verbose=args.verbose)
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    parser = ArgParser()
 | 
			
		||||
    parser.add_argument('-v', '--verbose', action='store_true')
 | 
			
		||||
 | 
			
		||||
    subparsers = parser.add_subparsers(required=True)
 | 
			
		||||
 | 
			
		||||
    parser_read = subparsers.add_parser('read', help='Retrieve data from an image')
 | 
			
		||||
    parser_read.add_argument('from_file', type=Path)
 | 
			
		||||
    parser_read.set_defaults(func=read)
 | 
			
		||||
 | 
			
		||||
    parser_write = subparsers.add_parser('write', help='Dissimulate data in an image')
 | 
			
		||||
    parser_write.add_argument('string', type=str)
 | 
			
		||||
    parser_write.add_argument('to_file', type=Path)
 | 
			
		||||
    parser_write.add_argument('--from', type=Path, dest='from_file', default=Path('default_image.jpg'))
 | 
			
		||||
    parser_write.set_defaults(func=write)
 | 
			
		||||
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
    args.func(args)
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main()
 | 
			
		||||
		Reference in New Issue
	
	Block a user