Python Forum
need help decrypting a gif file
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
need help decrypting a gif file
#1
hello, i got a job offer which will send me to a fully paid studying program which i will be able to work at the end of, if only i will be able to solve a few of they're riddles, they said there is no need in previous knowledge and i already figured out what i need to do but in order to solve it i need to use python which i never did before

i got a gif file i need to decrypt in order to get a message from but i have no idea how to use code i got 2 other files that came with the gif file, one of them seems to be the encryption but i don't know which command lines to use in python in order to decrypt it

here are the 3 files: https://files.fm/u/6z5xrsx3 and this might be a key ill need to use in order to access the message: Steganos & Graphein (i might be wrong on this one but i saw someone else using something similar to encrypt and decrypt a picture and he used 2 key codes to do so)

Thank you in advance!!


I'm new here so i don't know if I'm doing it right so correct me if I'm wrong:

file codes:

enc.py:

from __future__ import print_function
from random import randint, shuffle
import sys
from struct import unpack, pack as pk
from io import BytesIO as BIO
import lzwlib

up = lambda *args: unpack(*args)[0]


def F(f):
    assert f.read(3) == 'GIF', ''
    assert f.read(3) == '89a', ''
    w, h = unpack('HH', f.read(4))

    assert 32 <= w <= 500, ''
    assert 32 <= h <= 500, ''
    logflags = up('B', f.read(1))

    assert logflags & 0x80, ''
    size_count = logflags & 0x07

    gct_count = 2**(size_count+1)
    assert 4 <= gct_count <= 256, ''

    bgcoloridx = up('B', f.read(1))
    f.seek(1, 1)
    clrs = []
    for i in xrange(gct_count):
        clr = (up('B', f.read(1)), up('B', f.read(1)), up('B', f.read(1)))
        clrs.append(clr)

    assert len(clrs) > bgcoloridx, ''
    return clrs, bgcoloridx, size_count, h, w


class T(object):
    I = 0
    EG = 1
    EA = 2
    EC = 3
    ET = 4


def C(f):
    rb = f.read(1)
    b = up('B', rb)

    while b != 0x3B:
        buf = ''
        buf += rb
        if b == 0x2c:
            nbuf = f.read(2*4)
            eb = f.read(1)
            assert (up('B', eb) & 0x03) == 0, ''
            nbuf += eb

            nbuf += f.read(1)
            nbuf += V(f)
            t = T.I
        elif b == 0x21:
            rb = f.read(1)
            buf += rb
            b = up('B', rb)

            if b == 0xF9:
                nbuf = f.read(1)
                blksize = up('B', nbuf)
                nbuf += f.read(blksize)
                nbuf += f.read(1)
                assert nbuf[-1] == '\x00', ''
                t = T.EG
            elif b in [0xFF, 0x01]:
                nbuf = f.read(1)
                blksize = up('B', nbuf)
                nbuf += f.read(blksize)
                nbuf += V(f)

                t = (b+3) & 0x0F
            elif b == 0xFE:
                nbuf = V(f)

                t = T.EC
            else:
                raise Exception("unsupprted thing @{}".format(f.tell()))

        buf += nbuf

        yield t, buf
        rb = f.read(1)
        b = up('B', rb)

    yield None, '\x3B'

    raise StopIteration


def WB(buf):
    blockcount = len(buf)/0xFF
    blockcount += 1 if len(buf) % 0xFF else 0

    blocks = [
        pk('B', len(subblock))+subblock for subblock in [
            buf[i:0xFF+i] for i in xrange(0, blockcount*0xFF, 0xFF)
        ]
    ]

    return ''.join(blocks) + '\x00'


def k(bf):
    combined_buf = ''
    while True:
        cb = ord(bf.read(1))
        if not cb:
            break

        combined_buf += bf.read(cb)
    return combined_buf


def V(f):
    sbx = ''
    while True:
        rcb = f.read(1)
        sbx += rcb
        if rcb == '\x00':
            break

        cb = up('B', rcb)
        blk = f.read(cb)
        sbx += blk

    return sbx


def Q(delay, w, h, x, y, tidx):

    assert 0 <= tidx <= 255
    assert 0 <= delay < 2**16

    indices = [tidx]*(w*h)
    buf = BIO('')

    buf.write('\x21\xF9\x04\x05')
    buf.write(pk('H', delay))
    buf.write(pk('B', tidx))
    buf.write('\x00')

    buf.write('\x2c')
    buf.write(pk('H', x))
    buf.write(pk('H', y))
    buf.write(pk('H', w))
    buf.write(pk('H', h))
    buf.write('\x00')

    LZWMinimumCodeSize = 8

    cmprs, _ = lzwlib.Lzwg.compress(
        indices, LZWMinimumCodeSize)

    obuf = pk('B', LZWMinimumCodeSize) + WB(cmprs)

    buf.write(obuf)
    buf.seek(0)
    return buf.read()


def z(n):
    import math
    for i in xrange(1, int(math.sqrt(n) + 1)):
        if n % i == 0:
            yield i


def m(a, mm, hh):
    if a < 0x08:
        if a % 2:
            _0 = 0
            _1 = 1
            _4 = a << 2
            _3 = randint(4, mm-1)
        else:
            _0 = 1
            _1 = a << 1
            _3 = randint(4, mm/2)
            _4 = randint(4, hh/3)
    else:
        ds = list(z(a))
        _0 = 0
        _1 = 0
        shuffle(ds)
        _4 = ds[0]
        assert a % _4 == 0
        _3 = a/_4

    return _0, _1, _3, _4


def h(b6, b1, mw, mh, mci, d=3):
    idx = randint(0, (mci-1)/2)*2 + b1
    x, xx, xxx, xxxx = m(b6, mw, mh)
    f = Q(d, xxx, xxxx, x, xx, idx)
    return f


def M(s):
    l = list(set(s.upper()))
    shuffle(l)
    d = ''.join(l)
    assert len(d) <= 2**6, ''
    return d, [(d.index(c.upper()), int(c.isupper())) for c in s]


def E(f, s, o):
    global_colors, bgcoloridx, size_count, hh, ww = F(f)
    mp, ks = M(s)
    hdr_end = f.tell()
    f.seek(0)
    o.write(f.read(hdr_end))
    fc = 0

    o.write('\x21\xFE')
    o.write(WB('RDBNB'+mp))
    o.flush()

    for t, buf in C(f):
        print('.', end='')
        if t == T.EC:
            continue
        if t == T.EG:
            if ks:
                delay = up('<H', buf[4:6])
                assert delay >= 6
                buf = buf[:4] + pk('<H', delay - 3) + buf[6:]
            obuf = buf

        elif t == T.I:
            fc += 1
            total_raw_blocks_data = ''
            bf = BIO(buf)
            pref = bf.read(10)

            LZWMinimumCodeSize = ord(bf.read(1))
            total_raw_blocks_data = k(bf)

            indices, dcmprsdcodes = lzwlib.Lzwg.decompress(
                total_raw_blocks_data, LZWMinimumCodeSize)
            xxx = unpack('<B H H H H B', pref)

            cmprs, codes = lzwlib.Lzwg.compress(
                indices, LZWMinimumCodeSize)

            obuf = pref + pk('B', LZWMinimumCodeSize) + WB(cmprs)

            if ks:
                mpindx, isup = ks.pop(0)
                obuf += h(mpindx, isup,
                          ww, hh, len(global_colors)-1)
        else:
            obuf = buf

        o.write(obuf)
    o.flush()
    assert not ks, ''

    return 0


if __name__ == '__main__':
    assert len(sys.argv) > 2, 'bad input'
    fpath = sys.argv[1]
    flag = sys.argv[2]
    if len(sys.argv) > 3:
        outpath = sys.argv[3]
    else:
        outpath = fpath + '.out.gif'

    f = open(fpath, 'rb')
    o = open(outpath, 'wb')
    rv = E(f, flag, o)
    sys.exit(rv)
lzwlib.py:

from io import BytesIO as BIO


class Bitstream(object):
    def __init__(self, buf=None, raw=None, bits=None):
        self.bytes = buf or BIO(raw)
        self.bits = bits or []

    def __len__(self):
        curr = self.bytes.tell()
        last = self.bytes.seek(0, 2)
        self.bytes.seek(curr)
        total = len(self.bits) + (last - curr)*8
        return total

    def _write_bits(self, newbits):
        self.bits += newbits

    def write(self, v, count):
        newbits = [1 if v & (1 << i) else 0 for i in range(count)]
        self._write_bits(newbits)

    def _read_bits(self, count):
        bytes_for_bits = count/8 + (1 if (count % 8) else 0)

        raw_bytes = self.bytes.read(bytes_for_bits)
        for b in raw_bytes:
            self.bits += [1 if ord(b) & (1 << i) else 0 for i in range(8)]

    def _makeint(self, bitcount):
        assert bitcount < 13, bitcount
        x = 0
        for i in xrange(bitcount):
            b = self.bits.pop(0)
            x |= (b << i)

        return x

    def readByte(self):
        return chr(self.read(8))

    def read(self, bitcount):
        current_bit_count = len(self.bits)
        if current_bit_count < bitcount:
            self._read_bits(bitcount - current_bit_count)

        return self._makeint(bitcount)


class Lzwg(object):

    @classmethod
    def extract_info_from_imagedatadescriptor(cls, buf):
        buf.seek(1+2*4, 1)
        desc_flags = ord(buf.read(1))
        assert desc_flags == 0, 'flags: {:08b}'.format(desc_flags)

        lzw_min_codesize = ord(buf.read(1))
        size = ord(buf.read(1))
        subblocks = []
        while size:
            subblocks.append(buf.read(size))
            size = ord(buf.read(1))

        return lzw_min_codesize, subblocks

    @classmethod
    def _get_initialized_code_table(cls, lzw_min_codesize):
        max_indx = 2**(lzw_min_codesize) - 1 + 2  # 2 for CC and EOI codes
        return [[i] for i in xrange(max_indx + 1)]

    @classmethod
    def decompress(cls, buf, lzw_min_codesize=2):
        can_insert_to_table = True
        index_stream = []
        current_bits_per_code = initial_bits_per_code = lzw_min_codesize+1
        code_table = cls._get_initialized_code_table(lzw_min_codesize)
        bits = Bitstream(raw=buf)
        codes = []
        CLEAR_CODE = len(code_table) - 2
        EOI_CODE = len(code_table) - 1
        assert CLEAR_CODE == bits.read(
            initial_bits_per_code), 'first code is not CC'
        pc = c = bits.read(initial_bits_per_code)
        codes.append(CLEAR_CODE)
        codes.append(c)

        index_stream.extend(code_table[c])
        k = None
        while len(bits):

            c = bits.read(current_bits_per_code)
            codes.append(c)

            if c == CLEAR_CODE:
                code_table = cls._get_initialized_code_table(lzw_min_codesize)
                current_bits_per_code = initial_bits_per_code
                pc = c = bits.read(initial_bits_per_code)
                codes.append(c)
                index_stream.extend(code_table[c])
                can_insert_to_table = True
                continue

            if c == EOI_CODE:
                assert len(bits) == 0 or (len(bits) <= 8 and bits.read(len(bits)
                                                                       ) == 0), '{} left: {}'.format(len(bits), bits.bits)
                break

            if len(code_table) > c:
                index_stream.extend(code_table[c])
                k = code_table[c][:1]
                if can_insert_to_table:
                    code_table.append(code_table[pc] + k)
            else:
                k = code_table[pc][:1]
                index_stream.extend(code_table[pc] + k)
                if can_insert_to_table:
                    code_table.append(code_table[pc] + k)

            if len(code_table) - 1 == (2**current_bits_per_code) - 1:
                if current_bits_per_code < 12:
                    current_bits_per_code += 1
                else:
                    can_insert_to_table = False

            assert current_bits_per_code < 13, 'bad bits per code'

            pc = c

        return index_stream, codes

    @classmethod
    def _compress_indices_using_table(cls, indices, lzw_min_codesize):
        code_table = cls._get_initialized_code_table(lzw_min_codesize)
        CLEAR_CODE = len(code_table) - 2
        EOI_CODE = len(code_table) - 1
        current_bits_per_code = initial_bits_per_code = lzw_min_codesize+1

        yield CLEAR_CODE, current_bits_per_code
        intermediate_index_buffer = [indices[0]]

        for indx in indices[1:]:
            k = indx
            if intermediate_index_buffer + [k] in code_table:
                intermediate_index_buffer.append(k)
            else:
                code_table.append(intermediate_index_buffer+[k])
                new_idx = code_table.index(intermediate_index_buffer)

                yield new_idx, current_bits_per_code
                intermediate_index_buffer = [k]
                k = None

                if len(code_table) == 2**12 - 1-1:
                    yield CLEAR_CODE, current_bits_per_code

                    current_bits_per_code = initial_bits_per_code
                    code_table = cls._get_initialized_code_table(
                        lzw_min_codesize)
                    # code_table.append(intermediate_index_buffer+[k])

            if len(code_table) == 2**current_bits_per_code + 1:
                current_bits_per_code += 1

        yield code_table.index(intermediate_index_buffer), current_bits_per_code
        yield EOI_CODE, current_bits_per_code

    @classmethod
    def compress(cls, indices, lzw_min_codesize=2):
        bits = Bitstream()
        comcodes = []
        cmprsd = ''
        for c, bits_per_code in cls._compress_indices_using_table(indices, lzw_min_codesize):
            comcodes.append(c)
            bits.write(c, bits_per_code)
            while len(bits) >= 8:
                b = bits.readByte()
                cmprsd += b

        if len(bits) > 0:
            assert len(bits) < 8, 'bitstream has more than a byte left!: {}'.format(
                bits.bits)
            bits.write(0, 8-len(bits))
            b = bits.readByte()
            cmprsd += b

        return cmprsd, comcodes
Reply
#2
could someone please say something so I can understand what is wrong :(
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020