From 5bc89da4075510d8a898c450ea5d26ce09c71f62 Mon Sep 17 00:00:00 2001 From: JohnE Date: Mon, 5 Sep 2016 18:27:28 -0700 Subject: [PATCH] NEW: custom j3g binary parsing of jpg files!!! =) --- libs/jpg_bin.py | 189 ++++++++++++++++++++++++++++++++++++++++++++++ libs/jpg_tools.py | 67 +++------------- picseal.py | 13 ++-- 3 files changed, 207 insertions(+), 62 deletions(-) create mode 100644 libs/jpg_bin.py diff --git a/libs/jpg_bin.py b/libs/jpg_bin.py new file mode 100644 index 0000000..534f068 --- /dev/null +++ b/libs/jpg_bin.py @@ -0,0 +1,189 @@ +# +# +# +# +# 0xFF,0xD8 - Start of Image (0xFFD8FF to be used as JPG file marker) +# 0xFF,0xEn - App Exif data +# 0xFF,0xDB - DQT - Define Quantization Table +# 0xFF,0xDD - DRI - Define Restart Interval +# 0xFF,0xFE - Comments +# 0xFF,0xC0 - SOF0 - Start of Frame +# 0xFF,0xC2 - SOF2 - Start of Frame +# 0xFF,0xC4 - DHT - Define Huffman Tables +# 0xFF,0xDA - SOS - Start of Scan +# 0xFF,0xDn - RST - Restart (n=0..7) +# 0xFF,0xD9 - EOI - End of Image +# +# high,low - length +# +# https://en.wikipedia.org/wiki/JPEG +import re +import struct +import logging + +# +class JpgBin: + + BUF_CHUNK_SIZE = 2048 + data_buf = None + data_idx = 0 + data_len = 0 + fh = None + + continue_process = True + + metadata_h = {} + img_bin_h = {} + + + def __init__(self): + pass + + # + def __isJPG(self): + (m1, m2) = struct.unpack('>HB', self.data_buf[0:3]) + if (0xffd8 == m1 and 0xff == m2): + self.data_idx = 2 + return True + return False + + # + def processFile(self, fhandle): + self.fh = fhandle + self.getMoreBytes(True) + if (self.data_buf): + if (not self.__isJPG()): + return False + + while(self.continue_process): + self.findMarker() + self.getMoreBytes() + + return True + return False + + # + def getMoreBytes(self, force_bytes=False): + if (self.data_idx >= (self.data_len-1) or force_bytes): + self.data_buf = self.fh.read(self.BUF_CHUNK_SIZE) + self.data_idx = 0 + self.data_len = len(self.data_buf) + if (0 == self.data_len): + self.continue_process = False + logging.debug("DATA: len=={}".format(self.data_len)) + + # + def calcSeekBytes(self): + self.data_idx += 2 + (rec_len,) = struct.unpack('>H', self.data_buf[self.data_idx:self.data_idx+2]) + remain_bytes = self.data_len - self.data_idx + if (rec_len >= remain_bytes): + rec_diff = rec_len - remain_bytes + self.seekBytes(rec_diff) + else: + self.data_idx += rec_len + + # + def seekBytes(self, num_bytes): + pos = self.fh.seek(num_bytes, 1) + logging.debug("SEEK: seek=={}, cur_loc=={}".format(num_bytes, pos)) + self.getMoreBytes(True) + return pos + + # + def findMarker(self): + (word_b,) = struct.unpack('>H', self.data_buf[self.data_idx:self.data_idx+2]) + hex_str = word_b.to_bytes(2, 'big').hex() + # RST 0xD(n) (n==0..7) + if (0xffd0 == word_b or 0xffd1 == word_b or 0xffd2 == word_b or 0xffd3 == word_b or 0xffd4 == word_b or 0xffd5 == word_b or 0xffd6 == word_b or 0xffd7 == word_b): + logging.info("[ {} : RST ]".format(hex_str)) + self.markerRST() + # Comments section + elif (0xfffe == word_b): + logging.info("[ {} : Comment ]".format(hex_str)) + self.markerComment() + # DQT + elif (0xffdb == word_b): + logging.info("[ {} : DQT ]".format(hex_str)) + self.markerDQT() + # DRI + elif (0xffdd == word_b): + logging.info("[ {} : DRI ]".format(hex_str)) + self.markerDRI() + # SOF0 - Start of Frame 0 + elif (0xffc0 == word_b): + logging.info("[ {} : SOF0 ]".format(hex_str)) + self.markerSOF0() + # SOF2 - Start of Frame 2 + elif (0xffc2 == word_b): + logging.info("[ {} : SOF2 ]".format(hex_str)) + self.markerSOF2() + # DHT + elif (0xffC4 == word_b): + logging.info("[ {} : DHT ]".format(hex_str)) + self.markerDHT() + # SOS + elif (0xffda == word_b): + logging.info("[ {} : SOS ]".format(hex_str)) + self.markerSOS() + # EOI + elif (0xffd9 == word_b): + logging.info("[ {} : EOI ]".format(hex_str)) + self.markerEOI() + # APP 0xE(n) - App Exif Data + # struct.pack(">H", intt).hex() + elif ( re.search(r'ffe.', hex_str ) ): + logging.info("[ {} : App Data ]".format(hex_str)) + self.markerAppData() + else: + self.data_idx += 1 + + # + def markerComment(self): + self.calcSeekBytes() + + # + def markerDQT(self): + self.calcSeekBytes() + + # + def markerDRI(self): + self.data_idx += 4 + + # + def markerSOF0(self): + self.calcSeekBytes() + + # + def markerSOF2(self): + self.calcSeekBytes() + + def markerDHT(self): + self.calcSeekBytes() + + def markerSOS(self): + self.calcSeekBytes() + + def markerRST(self): + self.data_idx += 2 + + def markerEOI(self): + self.data_idx += 2 + # self.continue_process = False + + def markerAppData(self): + self.calcSeekBytes() + + def __repr__(self): + pass + + + def findMarkers222(self): + last_idx = len(self.data_buf) + + while ord(self.data_buf[self.data_idx]) != 0xFF: + self.data_idx = self.data_idx+1 + + for idx in range(last_idx): + pass + diff --git a/libs/jpg_tools.py b/libs/jpg_tools.py index 459f5f2..bfafbd5 100644 --- a/libs/jpg_tools.py +++ b/libs/jpg_tools.py @@ -2,79 +2,35 @@ # # from PIL import Image +from libs.jpg_bin import JpgBin -# -# 0xFF,0xD8 - Start of Image -# 0xFF,0xEn - App Exif data -# 0xFF,0xD8 - DQT - Define Quantization Table -# 0xFF,0xDD - DRI - Define Restart Interval -# 0xFF,0xFE - Comments -# 0xFF,0xC0 - SOF0 - Start of Frame -# 0xFF,0xC2 - SOF2 - Start of Frame -# 0xFF,0xC4 - DHT - Define Huffman Tables -# 0xFF,0xDA - SOS - Start of Scan -# 0xFF,0xDn - RST - Restart (n=0..7) -# 0xFF,0xEn - Application -# 0xFF,0xD9 -# -# -# https://en.wikipedia.org/wiki/JPEG class JpgTools: - BUF_CHUNK_SIZE = 2048 - data_buf = None - data_idx = None fh = None def __init__(self): pass + def getJpgBin(self, fname): + self.processFile(fname) + # def jpgHash(self): - - - def findMarkers(self): - last_idx = len(self.data_buf) - while - - - while ord(self.data_buf[self.data_idx]) != 0xFF: - self.data_idx = self.data_idx+1 - - for idx in range(last_idx): - - - while self.data_buf: - - self.getBytes pass - - def processFile(self, fname): - self.data_buf = self.fh.read(self.BUF_CHUNK_SIZE) - while self.data_buf: - (ret, fin) = self.findMarkers() - - - # def getBytes(self, fname): if (not self.fh): self.fh = open(fname, "rb") self.data_buf = self.fh.read(self.BUF_CHUNK_SIZE) - + # def processFile(self, fname): self.fh = open(fname, "rb") - self.data_buf = self.fh.read(self.BUF_CHUNK_SIZE) - if (self.data_buf): - self.data_idx = 0 - findMarkers() - - - - + self.jpg = JpgBin() + retval = self.jpg.processFile(self.fh) + print("processFile()=={}".format(retval)) # def process_OLD(self, fname): @@ -85,8 +41,7 @@ class JpgTools: im.tostring() # - def getJpgBin_OLD(self, fname): - img_h = Image.open(fname) - img_bin = list(img_h.getdata()) - return img_bin + # def getJpgBin_OLD(self, fname): + # img_h = Image.open(fname) + # img_h.??? diff --git a/picseal.py b/picseal.py index 9ae7c59..1fd98ae 100644 --- a/picseal.py +++ b/picseal.py @@ -22,13 +22,14 @@ def main(): def processImage(image_fn): jpg = JpgTools() img_bin = jpg.getJpgBin(image_fn) - sig = Signature() - sig.genSig(img_bin) - - (pub_fn, priv_fn) = copyImage(image_fn) - writePubImg(pub_fn, sig) - writePrivImg(priv_fn, sig) + # sig = Signature() + # sig.genSig(img_bin) + + # (pub_fn, priv_fn) = copyImage(image_fn) + + # writePubImg(pub_fn, sig) + # writePrivImg(priv_fn, sig) # add a digital signature to the metadata