def test_export_medium():
    '''
    Can export binary data of medium
    '''

    pm = PictureModifier()
    pm.load_medium(medium_data)
    assert pm.export_medium('BMP') == medium_data
def test_get_data_picture_not_load():
    '''
    If medium is not loaded, raise ValueError.
    '''

    pm = PictureModifier()

    with pytest.raises(ValueError) as ve:
        pm.get_data(1)
    assert str(ve.value) == constants.PICTURE_NOT_LOADED_ERROR_MSG
def test_hide_data_picture_not_load():
    '''
    If medium is not loaded, raise ValueError.
    '''

    secret = os.urandom(100)
    pm = PictureModifier()

    with pytest.raises(ValueError) as ve:
        pm.hide_data(secret)
    assert str(ve.value) == constants.PICTURE_NOT_LOADED_ERROR_MSG
def test_load_medium():
    '''
    Can load picture from binary data.
    '''

    pm = PictureModifier()
    pm.load_medium(medium_data)
    assert pm.img.mode == 'RGB'
    assert pm.img_height == test_data_height
    assert pm.img_width == test_data_width
    assert pm.pixels is not None
def test_init():
    '''
    Can initialize ste_lvl, img and curr_read/write_pixel_index.
    '''

    pm = PictureModifier()
    assert pm.ste_lvl == constants.DEFAULT_STEGANOGRAPHY_LEVEL

    for ste_lvl in range(1, 9):
        pm = PictureModifier(ste_lvl)
        assert pm.ste_lvl == ste_lvl \
            and pm.curr_write_pixel_index == 0 \
            and pm.curr_read_pixel_index == 0 \
            and pm.img is None and pm.pixels is None \
            and pm.img_width == 0 and pm.img_height == 0
Exemplo n.º 6
0
def test_main_decryption_otp(mocker):
    '''
    This package can be called straight from command line.
    Can decrypt data using OTP encryption.
    '''

    my_namespace = namedtuple('Namespace', [
        'mode', 'encryption', 'key_stretch', 'level', 'medium', 'password',
        'secret', 'result', 'format'
    ])

    args = my_namespace(mode='decrypt', encryption='otp', key_stretch=None, \
                level='2', medium='medium.bmp', password='******', \
                secret='secret.txt', result='hidden.bmp', format='BMP')

    dummyEncryptor = OTPCryptor()
    dummyModifier = PictureModifier(int(args.level))

    with mocker.patch('builtins.open', new_callable=mocker.mock_open()) as mo:
        with monkeypatch.context() as m:
            m.setattr(argparse.ArgumentParser, 'parse_args', lambda self: args)
            mocker.patch.object(OTPCryptor, '__init__')
            OTPCryptor.__init__.return_value = None
            mocker.patch.object(PictureModifier, '__init__')
            PictureModifier.__init__.return_value = None
            mocker.patch.object(Steganography, 'get_file')

            steganography_main()
            mo.assert_any_call(args.password, 'rb')
            mo.assert_any_call(args.result, 'wb')
            OTPCryptor.__init__.assert_called_once_with()
            PictureModifier.__init__.assert_called_once_with(int(args.level))
            assert Steganography.get_file.call_count == 1
def test_get_data():
    '''
    Can get data from low-bit of pixel in image.
    '''

    data_list1 = [
        bytes.fromhex('ca'),
        os.urandom(100),
        os.urandom(200),
        os.urandom(400),
    ]

    data_list2 = [
        bytes.fromhex('fe'),
        os.urandom(400),
        os.urandom(200),
        os.urandom(100),
    ]

    data_list3 = [
        bytes.fromhex('babe'),
        os.urandom(100),
        os.urandom(200),
        os.urandom(400),
    ]

    data_list4 = [
        os.urandom(100),
        os.urandom(100),
        os.urandom(100),
        os.urandom(100),
    ]

    for data1, data2, data3, data4 in zip(data_list1, data_list2, data_list3,
                                          data_list4):
        pm = PictureModifier()
        pm.load_medium(medium_data)

        pm.hide_data(data1)
        pm.hide_data(data2)
        pm.hide_data(data3)
        pm.hide_data(data4)
        assert pm.get_data(len(data1)) == data1
        assert pm.get_data(len(data2)) == data2
        assert pm.get_data(len(data3)) == data3
        assert pm.get_data(len(data4)) == data4
def test_init_error_level_value():
    '''
    If steganography level is smaller than 1 or bigger than 0, raise ValueError.
    '''

    ste_lvl_list = [0, -1, 9, 1000]

    for ste_lvl in ste_lvl_list:
        with pytest.raises(ValueError) as ve:
            PictureModifier(ste_lvl)
        assert str(ve.value) == constants.STEGANOGRAPHY_LEVEL_VALUE_ERROR_MSG
def test_init_error_type_value():
    '''
    If steganography level is not a number raise TypeError.
    '''

    ste_lvl_list = ['aaa', [], None]

    for ste_lvl in ste_lvl_list:
        with pytest.raises(TypeError) as te:
            PictureModifier(ste_lvl)
        assert str(te.value) == constants.STEGANOGRAPHY_LEVEL_TYPE_ERROR_MSG
def test_get_data_from_pixel():
    '''
    Can get data from low-bit of individual pixel.
    '''

    data1 = bitarray([True, False, False, False, True])
    data2 = bitarray([False, False, False, True, True, True])
    data3 = bitarray([False, False, True, True, True])

    pm = PictureModifier()
    pm.load_medium(medium_data)

    assert pm.curr_write_pixel_index == 0
    pm.hide_data_into_pixel(data1)
    pm.hide_data_into_pixel(data2)
    pm.hide_data_into_pixel(data3)
    assert pm.curr_write_pixel_index == 3

    assert pm.get_data_from_pixel(pm.pixels[0, 0], 5) == data1
    assert pm.get_data_from_pixel(pm.pixels[1, 0], 6) == data2
    assert pm.get_data_from_pixel(pm.pixels[2, 0], 5) == data3
def test_get_data_value_error():
    '''
    If size is bigger than size of medium, raise TypeError
    '''

    sizes = [
        test_data_width * test_data_height * constants.MAX_COLOR_INDEX *
        test_depth, test_data_width * test_data_height *
        constants.MAX_COLOR_INDEX * test_depth, 0, -1, -10
    ]

    messages = [
        constants.GET_DATA_PARA_VALUE_ERROR_MSG,
        constants.GET_DATA_PARA_VALUE_ERROR_MSG,
        constants.GET_DATA_PARA_VALUE_NEGATIVE_MSG,
        constants.GET_DATA_PARA_VALUE_NEGATIVE_MSG,
    ]

    pm = PictureModifier()
    pm.load_medium(medium_data)

    for size, message in zip(sizes, messages):
        with pytest.raises(ValueError) as ve:
            pm.get_data(size)
        assert str(ve.value) == message
def test_hide_data_type_error():
    '''
    If data is not bytes, raise TypeError.
    '''

    data_list = ['string', [], 1, None]

    pm = PictureModifier()
    pm.load_medium(medium_data)

    for data in data_list:
        with pytest.raises(TypeError) as te:
            pm.hide_data(data)
        assert str(te.value) == constants.INPUT_DATA_ERROR_MSG
def test_hide_data_size_error():
    '''
    If data is too big, raise ValueError
    '''

    data = bytes(b'\0' * int(test_data_width * test_data_height *
                             constants.MAX_COLOR_INDEX * test_depth / 8 + 1))

    pm = PictureModifier()
    pm.load_medium(medium_data)

    with pytest.raises(ValueError) as ve:
        pm.hide_data(data)
    assert str(ve.value) == constants.DATA_SIZE_ERROR_MSG
def test_get_data_type_error():
    '''
    If size is not integer, raise TypeError.
    '''

    sizes = [None, {}, 1]

    pm = PictureModifier()
    pm.load_medium(medium_data)

    for size in zip(sizes):
        with pytest.raises(TypeError) as te:
            pm.get_data(size)
        assert str(te.value) == constants.GET_DATA_PARA_TYPE_ERROR_MSG
def test_hide_data_into_pixel():
    '''
    Can hide data into low-bit of individual pixel
    '''

    data = bitarray([True, False, False, False, True])
    pm = PictureModifier()
    pm.load_medium(medium_data)

    pm.hide_data_into_pixel(data)
    assert pm.curr_write_pixel_index == 1

    pixel = pm.pixels[0, 0]
    assert __get_bit(pixel[0], 0) == True
    assert __get_bit(pixel[0], 1) == False
    assert __get_bit(pixel[1], 0) == False
    assert __get_bit(pixel[1], 1) == False
    assert __get_bit(pixel[2], 0) == True
def test_hide_data():
    '''
    Can hide data into low-bit of pixel in image.
    '''

    data = bytes.fromhex('05')
    pm = PictureModifier()
    pm.load_medium(medium_data)

    pm.hide_data(data)

    pixel1 = pm.pixels[0, 0]
    assert __get_bit(pixel1[0], 0) == False
    assert __get_bit(pixel1[0], 1) == False
    assert __get_bit(pixel1[1], 0) == False
    assert __get_bit(pixel1[1], 1) == False
    assert __get_bit(pixel1[2], 0) == False
    assert __get_bit(pixel1[2], 1) == True

    pixel2 = pm.pixels[1, 0]
    assert __get_bit(pixel2[0], 0) == False
    assert __get_bit(pixel2[0], 1) == True
Exemplo n.º 17
0
def main():
    '''
    Entry point of script when run from command line.
    '''

    parser=argparse.ArgumentParser()
    parser.add_argument('--mode', help='Encryption/Decryption flag. Allowed value: encrypt/decrypt')
    parser.add_argument('--encryption', help='Encryption method. Use \'aes\' for Fernet encryption or use \'otp\' for OTP encryption')
    parser.add_argument('--key_stretch', help='Number of iteration use when deriving Fernet key from password. Must be a number. Required if encryption mode is aes')
    parser.add_argument('--level', help='Number of low-bit in each pixel uses to store secret data. Must be between 1~8')
    parser.add_argument('--medium', help='Path to medium file')
    parser.add_argument('--password', help='Password for Fernet encryption or path to OTP pad')
    parser.add_argument('--secret', help='Path to secret file. Required in encryption mode')
    parser.add_argument('--result', help='Path to result file')
    parser.add_argument('--format', help='Format of picture with steganography. Allowed value: BMP/PNG (case insensitive). Required in encryption mode')
    args=parser.parse_args()

    # Input check.
    if not verify_argument(args):
        print(constants.HELP_MSG)
        return

    try:
        # Fernet encryption use args.password to derive encryption key.
        if args.encryption == constants.MODE_FERNET:
            encryptor = FernetCryptor(int(args.key_stretch))
            password = args.password
        
        # OTP encryption read binary file at args.password and use it as encryption pad.
        else:
            encryptor = OTPCryptor()
            with open(args.password, 'rb') as f:
                password = f.read()

        modifier = PictureModifier(int(args.level))
        steganography = Steganography(modifier, encryptor)
        with open(args.medium, 'rb') as f:
            medium_data = f.read()

        if args.mode == constants.MODE_ENCRYPT:
            with open(args.secret, 'rb') as f:
                secret_data = f.read()
            file_with_secret = steganography.hide_file(password, medium_data, secret_data, args.format)
            with open(args.result, 'wb') as f:
                f.write(file_with_secret) 

        else:
            secret_data = steganography.get_file(password, medium_data)
            with open(args.result, 'wb') as f:
                f.write(secret_data)

    except FileNotFoundError as fe:
        print('Cannot open file, please check if file path is correct')
        print(str(fe))

    except InvalidToken as it:
        print('Decryption password is incorrect.')
        print(str(it))

    except ValueError as ve:
        print('An ValueError occurred. Please check value of all parameters')
        print(str(ve))

    except TypeError as te:
        print('An TypeError occurred. Please check type of all parameters')
        print(str(te))

    except Exception as e:
        print('An unknown error occurred.')
        print(str(e))
Exemplo n.º 18
0
import steganosaurus.hash_utils as hash_utils
from _pytest.monkeypatch import MonkeyPatch
from pytest_mock import mocker
from steganosaurus.fernet_cryptor import FernetCryptor
from steganosaurus.otp_cryptor import OTPCryptor
from steganosaurus.picture_modifier import PictureModifier
from steganosaurus.steganography import Steganography
from steganosaurus.steganography import \
    is_positive_number as is_positive_number
from steganosaurus.steganography import main as steganography_main
from steganosaurus.steganography import verify_argument as steganography_verify

monkeypatch = MonkeyPatch()
fernet_cryptor = FernetCryptor(constants.KEY_STRETCH_ITERATION)
otp_cryptor = OTPCryptor()
picture_modifier = PictureModifier(2)
secret_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                           'secret.txt')
test_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                              'medium.bmp')
with open(secret_path, mode='rb') as file:
    secret_data = file.read()
with open(test_data_path, mode='rb') as file:
    medium_data = file.read()


def test_hide_file_fernet(mocker):
    '''
    Can hide hidden data into medium.
    Hidden data is encrypted using Fernet encrpytion (AES-128).
    '''