Merge branch 'hash'

This commit is contained in:
JohnE 2016-10-12 02:13:46 -07:00
commit 7c9fec279b
21 changed files with 351 additions and 190 deletions

17
docs/README Normal file
View File

@ -0,0 +1,17 @@
***** ***** ***** *****
*** Picseal ***
***** ***** ***** *****
Your Photo is your Crypto Key
Generate a new Crypto Key to share with every photo
[[ Requirements ]]
Python 3
pycrypto==2.6.1
[[ Usage ]]

37
docs/README_DSN Normal file
View File

@ -0,0 +1,37 @@
[[ JPG file parse Pseudo Code ]]
1) Verify File
a. read JPG file: find record markers, save file locations
b. verify no parsing issues
c. save file locations for metatdate
d. save file locations for image data
2) Generate Hash
a. hash all image data
3) Digital Signature
a. generate new public keys
b. sign hash data with priv key
4) Write new PicSeal Public file
a. write encrypted original metadata
b. write PicSeal metadata
i. write JSON
b. write image data
5) Write new PicSeal Private file
a. create thumbnail (smaller files)
b. write PicSeal metadata (JSON)
c. write image data
[[ PicSeal Metadata ]]
JSON Format
{
"format_ver": "50",
"pubkey_alg": "rsa",
"pubkey_size": 4096,
"pubkey_pem": "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnvdAyn5JuiRcoL8s+rAV\nMpoEUioB1NTV97EDG4z/R5pm89v86UkH0xeeB6OS2EacsPHmbIY6oY0IXKA+0EX6\nSZdVSya2vv36fy/CByfHgZsDUxpzMnRZLdYbITBwil7keCTOC4EfnYIMUDsvrx6s\nA+BSEbR1rUkIXMe7NJ2Qssj68lXKMOfhrJ9wUgPLVSTIiDytiX4Wd+yAuo9lUqUk\nxt7FwjEEBV5Nj0yKZp2sJZnqp+pL5dsLsYz9xKNQHonMkGuj+3IthenTkfuXm9a6\nx+Qm3B+6AN4qBd7Uz65tffS2e2OQCzSRVoqEaRUrQKvQcSfJv+w0lh4xoZs41CJE\nc8XmmJeaDqt/zYBQWWYJlvZfpq0oh3mKGmHRtNOnKQmMd+FRJj/5fUvG7WedcHt1\noAkUg1qKu/HBgPNTVN9PWaikM1fA1E8T1koCYN0ecP29Zo8SHwcL6g82ou+fGtae\nSrXW0bFKV1JbF+hF3nBzCw+xDPAXXpUGPTwSXYZa6Gvgfckk4qP17vfFaR9f+hiL\nmW8GUmgfupvbapcG189M+UB9nDUSj3557TJpqItdbH5m4FGNv9tcMRYSwIniVVxw\n+F5FuT7nhd8vC+simwyjlB3hteICya1c7tVo5rav/LBBzHYg9ywPJCdZKUvN3qRE\n4Txbp7DC99x/xZhGck2Cpj8CAwEAAQ==",
"image_sig": "6acda44a9e492ddcc0e6ddadbdbd2cc20fdbb06a9264f36268b03aff921332919edb541d9bcdafa2b958276fb553682e5b67d92a127ec8d5d89b29774db86c50",
"metadata_sig": ""
}

View File

@ -0,0 +1,7 @@
{
"format_ver": "50",
"pubkey_alg": "rsa",
"pubkey_size": 4096,
"pubkey_pem": "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnvdAyn5JuiRcoL8s+rAV\nMpoEUioB1NTV97EDG4z/R5pm89v86UkH0xeeB6OS2EacsPHmbIY6oY0IXKA+0EX6\nSZdVSya2vv36fy/CByfHgZsDUxpzMnRZLdYbITBwil7keCTOC4EfnYIMUDsvrx6s\nA+BSEbR1rUkIXMe7NJ2Qssj68lXKMOfhrJ9wUgPLVSTIiDytiX4Wd+yAuo9lUqUk\nxt7FwjEEBV5Nj0yKZp2sJZnqp+pL5dsLsYz9xKNQHonMkGuj+3IthenTkfuXm9a6\nx+Qm3B+6AN4qBd7Uz65tffS2e2OQCzSRVoqEaRUrQKvQcSfJv+w0lh4xoZs41CJE\nc8XmmJeaDqt/zYBQWWYJlvZfpq0oh3mKGmHRtNOnKQmMd+FRJj/5fUvG7WedcHt1\noAkUg1qKu/HBgPNTVN9PWaikM1fA1E8T1koCYN0ecP29Zo8SHwcL6g82ou+fGtae\nSrXW0bFKV1JbF+hF3nBzCw+xDPAXXpUGPTwSXYZa6Gvgfckk4qP17vfFaR9f+hiL\nmW8GUmgfupvbapcG189M+UB9nDUSj3557TJpqItdbH5m4FGNv9tcMRYSwIniVVxw\n+F5FuT7nhd8vC+simwyjlB3hteICya1c7tVo5rav/LBBzHYg9ywPJCdZKUvN3qRE\n4Txbp7DC99x/xZhGck2Cpj8CAwEAAQ==",
"image_sig": "6acda44a9e492ddcc0e6ddadbdbd2cc20fdbb06a9264f36268b03aff921332919edb541d9bcdafa2b958276fb553682e5b67d92a127ec8d5d89b29774db86c50"
}

View File

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 120 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 1.7 MiB

View File

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -1,6 +1,9 @@
# #
# DEPRECATED
# #
# # ditching this for my own custom code
# uses GExiv2, and the C to Python bindings. but pain in the ass to install and config
# very limited read/wriging...cannot create a new application comment block. writing my own
import logging import logging
import json import json
import gi import gi

View File

@ -20,29 +20,34 @@
import re import re
import struct import struct
import logging import logging
from libs.jpg_fp import JpgFingerprint
# #
class JpgBin: class JpgBin:
BUF_CHUNK_SIZE = 2048 BUF_CHUNK_SIZE = 2048
data_buf = None
data_idx = 0
data_len = 0
fh = None
hh = None
markers = { markers = {
'SOS': 0xffd9 'SOS': 0xffd9
} }
continue_process = True
metadata_h = {}
img_bin_h = {}
def __init__(self): def __init__(self):
pass self.data_buf = None
self.data_idx = 0
self.data_len = 0
self.fh = None
self.hh = None
self.continue_process = True
self.metadata_h = {}
self.img_bin_h = {}
self.prev_fpos = 0
self.prev_mhex = 0xdead
self.prev_mstr = "DUH!"
self.jpg_fp = JpgFingerprint()
# #
def __isJPG(self): def __isJPG(self):
@ -61,16 +66,140 @@ class JpgBin:
return False return False
while(self.continue_process): while(self.continue_process):
self.findAllMarker() self.findAllMarkers()
self.getMoreBytes() self.getMoreBytes()
return True return True
return False return False
#
def findAllMarkers(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(word_b)
# Comments section
elif (0xfffe == word_b):
logging.info("[ {} : Comment ]".format(hex_str))
self.markerComment(word_b)
# DQT
elif (0xffdb == word_b):
logging.info("[ {} : DQT ]".format(hex_str))
self.markerDQT(word_b)
# DRI
elif (0xffdd == word_b):
logging.info("[ {} : DRI ]".format(hex_str))
self.markerDRI(word_b)
# SOF0 - Start of Frame 0
elif (0xffc0 == word_b):
logging.info("[ {} : SOF0 ]".format(hex_str))
self.markerSOF0(word_b)
# SOF2 - Start of Frame 2
elif (0xffc2 == word_b):
logging.info("[ {} : SOF2 ]".format(hex_str))
self.markerSOF2(word_b)
# DHT
elif (0xffC4 == word_b):
logging.info("[ {} : DHT ]".format(hex_str))
self.markerDHT(word_b)
# SOS
elif (0xffda == word_b):
logging.info("[ {} : SOS ]".format(hex_str))
self.markerSOS(word_b)
# EOI
elif (0xffd9 == word_b):
logging.info("[ {} : EOI ]".format(hex_str))
self.markerEOI(word_b)
# 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(word_b)
else:
self.data_idx += 1
#
# Image Metadata, Exif
#
#
def markerAppData(self, marker_hex):
fpos = self.fh.tell()
rec_len = self.calcSeekBytes()
self.jpg_fp.addImgMetadata(marker_hex, fpos, rec_len, "APP ")
#
def markerComment(self, marker_hex):
fpos = self.fh.tell()
rec_len = self.calcSeekBytes()
self.jpg_fp.addImgMetadata(marker_hex, fpos, rec_len, "COM ")
#
# Image Data
#
#
def markerSOS(self, marker_hex):
# rec_len = self.calcSeekBytes()
self.__addImgData(marker_hex, "SOS ")
#
def markerRST(self, marker_hex):
self.__addImgData(marker_hex, "RST ")
#
def markerDQT(self, marker_hex):
fpos = self.fh.tell()
rec_len = self.calcSeekBytes()
self.jpg_fp.addImgData(marker_hex, fpos, rec_len, "DQT ")
#
def markerDRI(self, marker_hex):
fpos = self.fh.tell()
self.data_idx += 4
self.jpg_fp.addImgData(marker_hex, fpos, 4, "DRI ")
#
def markerSOF0(self, marker_hex):
fpos = self.fh.tell()
rec_len = self.calcSeekBytes()
self.jpg_fp.addImgData(marker_hex, fpos, rec_len, "SOF0")
#
def markerSOF2(self, marker_hex):
fpos = self.fh.tell()
rec_len = self.calcSeekBytes()
self.jpg_fp.addImgData(marker_hex, fpos, rec_len, "SOF2")
def markerDHT(self, marker_hex):
fpos = self.fh.tell()
rec_len = self.calcSeekBytes()
self.jpg_fp.addImgData(marker_hex, fpos, rec_len, "DHT ")
#
def markerEOI(self, marker_hex):
fpos = self.fh.tell()
self.__addImgData(marker_hex, "EOI ")
self.jpg_fp.addImgData(marker_hex, fpos, 2, "EOI ")
# private helper function
def __addImgData(self, mhex, mstr):
fpos = self.fh.tell()
cur_fpos = (fpos - (self.data_len - self.data_idx))
if (self.prev_fpos > 0):
rec_len = cur_fpos - self.prev_fpos
self.jpg_fp.addImgData(self.prev_mhex, self.prev_fpos, rec_len, self.prev_mstr)
self.prev_mhex = mhex
self.prev_mstr = mstr
self.prev_fpos = cur_fpos
self.data_idx += 2
# #
def genHash(self, file_h, hash_h): def genHash(self, file_h, hash_h):
self.hh = hash_h self.hh = hash_h
self.processFile(file_h) #self.processFile(file_h)
while(self.continue_process): while(self.continue_process):
if (self.findMarker(self.makers['SOS'])): if (self.findMarker(self.makers['SOS'])):
@ -106,6 +235,7 @@ class JpgBin:
self.seekBytes(rec_diff) self.seekBytes(rec_diff)
else: else:
self.data_idx += rec_len self.data_idx += rec_len
return rec_len
# #
def seekBytes(self, num_bytes): def seekBytes(self, num_bytes):
@ -114,107 +244,23 @@ class JpgBin:
self.getMoreBytes(True) self.getMoreBytes(True)
return pos return pos
#
def printMarkerImg(self):
return self.jpg_fp.printImgMarkers()
#
def printMarkerMeta(self):
return self.jpg_fp.printMDMarkers()
# #
def findMarker(self, marker): def findMarker(self, marker):
pass pass
# #
def findAllMarker(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
#
# Image Metadata, Exif
#
#
def markerAppData(self):
self.calcSeekBytes()
#
def markerComment(self):
self.calcSeekBytes()
#
# Image Data
#
#
def markerSOS(self):
self.calcSeekBytes()
def markerRST(self):
self.data_idx += 2
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 markerEOI(self):
self.data_idx += 2
# self.continue_process = False
def __repr__(self): def __repr__(self):
pass return repr(self.jpg_fp)
#
def findMarkers222(self): def findMarkers222(self):
last_idx = len(self.data_buf) last_idx = len(self.data_buf)

69
libs/jpg_fp.py Normal file
View File

@ -0,0 +1,69 @@
#
#
#
class JpgFingerprint:
def __init__(self):
self.markers_a = []
self.markers_img = []
self.markers_meta = []
# self.markers_h = {}
def addImgMetadata(self, mhex, mpos, mlen, mstr):
marker = JpgMarker(mhex, mpos, mlen, mstr)
self.markers_a.append(marker)
self.markers_meta.append(marker)
#
def addImgData(self, mhex, mpos, mlen, mstr):
marker = JpgMarker(mhex, mpos, mlen, mstr)
self.markers_a.append(marker)
self.markers_img.append(marker)
#
def printImgMarkers(self):
# print ("Got here dummies")
# print ("len=={}".format(len(self.markers_img)))
# print ("*** *** *** ***\n{}".format(retstr))
return JpgFingerprint.__printMarker(self.markers_img)
#
def printMDMarkers(self):
return JpgFingerprint.__printMarker(self.markers_meta)
#
def __repr__(self):
return JpgFingerprint.__printMarker(self.markers_a)
#
@staticmethod
def __printMarker(markers):
str = ""
total = 0
for marker in markers:
str += repr(marker) + "\n"
total += marker.marker_size
str += "[TOT ] bytes=={}".format(total)
str += "\n"
return str
#
class JpgMarker:
"""
Marker Data Type
"""
def __init__(self, mhex, fpos, mlen, mstr):
self.marker_hex = mhex
self.marker_hexstr = self.marker_hex.to_bytes(2, 'big').hex()
self.marker_filepos = fpos
self.marker_size = mlen
self.marker_cat = mstr
def __repr__(self):
return "[{}] {} {}(len) {}(fpos)".format(self.marker_cat, self.marker_hexstr, self.marker_size, self.marker_filepos)

View File

@ -1,45 +1,33 @@
# #
# #
# #
from PIL import Image import logging
# from PIL import Image
from libs.jpg_bin import JpgBin from libs.jpg_bin import JpgBin
class JpgTools: class JpgTools:
fh = None
def __init__(self): def __init__(self):
self.fh = None
pass pass
#
# process a jpg file, read only
#
def getJpgBin(self, fname): def getJpgBin(self, fname):
self.processFile(fname) self.fh = open(fname, "rb")
self.jpg = JpgBin()
retval = self.jpg.processFile(self.fh)
logging.info("processFile()=={}".format(retval))
return self.jpg
#
# process a jpg file, create new jpg with crypto keys
# #
def jpgHash(self): def jpgHash(self):
self.fh = open(fname, "rb") self.fh = open(fname, "rb")
self.jpg = JpgBin() self.jpg = JpgBin()
retval = self.jpg.processFile(self.fh) retval = self.jpg.processFile(self.fh)
logging.info("processFile()=={}".format(retval))
print("processFile()=={}".format(retval))
#
def processFile(self, fname):
self.fh = open(fname, "rb")
self.jpg = JpgBin()
retval = self.jpg.processFile(self.fh)
print("processFile()=={}".format(retval))
#
def process_OLD(self, fname):
Image.open(fname)
# image as a sequence object containing pixel values
bin_data = list( im.getdata() )
# returns a string containing pixel data, using the standard "raw" encoder
im.tostring()
#
# def getJpgBin_OLD(self, fname):
# img_h = Image.open(fname)
# img_h.???

View File

@ -7,10 +7,13 @@ import logging
from shutil import copyfile from shutil import copyfile
#from subprocess import Popen, PIPE, check_call #from subprocess import Popen, PIPE, check_call
from libs.crypto_pub import Signature from libs.crypto_pub import Signature
from libs.img_exif import ImgExif
from libs.toolbox import Toolbox from libs.toolbox import Toolbox
from libs.jpg_tools import JpgTools from libs.jpg_tools import JpgTools
fingerprint = False
printmeta = False
printimage = False
def main(): def main():
parseArgs() parseArgs()
@ -21,8 +24,10 @@ def main():
# export signature & public key to a new image file # export signature & public key to a new image file
def processImage(image_fn): def processImage(image_fn):
jpg = JpgTools() jpg = JpgTools()
img_bin = jpg.getJpgBin(image_fn) jpg_bin = jpg.getJpgBin(image_fn)
printImageInfo(jpg_bin)
# sig = Signature() # sig = Signature()
# sig.genSig(img_bin) # sig.genSig(img_bin)
@ -34,17 +39,19 @@ def processImage(image_fn):
# add a digital signature to the metadata # add a digital signature to the metadata
def writePubImg(pub_fn, sig): def writePubImg(pub_fn, sig):
img = ImgExif(pub_fn) pass
img.addKey(sig.getPubKeyPEM()) # img = ImgExif(pub_fn)
img.addSig(sig.sig_data) # img.addKey(sig.getPubKeyPEM())
img.saveFile() # img.addSig(sig.sig_data)
# img.saveFile()
# #
def writePrivImg(priv_fn, sig): def writePrivImg(priv_fn, sig):
img = ImgExif(priv_fn) pass
img.addKey(sig.getPrivKeyPEM()) # img = ImgExif(priv_fn)
# img.addKey(sig.getPrivKeyPEM())
#img.addSig(sig.sig_data) #img.addSig(sig.sig_data)
img.saveFile() # img.saveFile()
# #
def copyImage(image_fn): def copyImage(image_fn):
@ -55,16 +62,30 @@ def copyImage(image_fn):
copyfile(image_fn, newFileName) copyfile(image_fn, newFileName)
return (pubFileName, privFileName) return (pubFileName, privFileName)
#
def printImageInfo(jpg_bin2):
if (fingerprint):
print( str(jpg_bin2) )
if (printimage):
print( jpg_bin2.printMarkerImg())
if (printmeta):
print( jpg_bin2.printMarkerMeta())
def parseArgs(): def parseArgs():
print("***** ***** ***** *****") print("***** ***** ***** *****")
print(" ** Pic * Seal ** ") print(" ** Pic * Seal ** ")
print("***** ***** ***** *****\n") print("***** ***** ***** *****\n")
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('-i', '--image', required=False, help="source image file") parser.add_argument('-f', '--file', required=False, help="source image file")
parser.add_argument('-v', '--verbose', action='store_true', help="will set logging level to INFO") parser.add_argument('-v', '--verbose', action='store_true', help="will set logging level to INFO")
parser.add_argument('-vv', '--vverbose', action='store_true', help="will set logging level to DEBUG") parser.add_argument('-vv', '--vverbose', action='store_true', help="will set logging level to DEBUG")
parser.add_argument('-l', '--logging', action='store_true', help="will supercede the -v option and send all logging to a file, logging.DEBUG") parser.add_argument('-l', '--logging', action='store_true', help="will supercede the -v option and send all logging to a file, logging.DEBUG")
parser.add_argument('-pm', '--printmeta', action='store_true', help="print the metadata markers")
parser.add_argument('-pi', '--printimage', action='store_true', help="print the image markers")
parser.add_argument('-fp', '--fingerprint', action='store_true', help="fingerprint")
args = parser.parse_args() args = parser.parse_args()
if (args.logging): if (args.logging):
@ -77,8 +98,20 @@ def parseArgs():
else: else:
logging.basicConfig(level=logging.CRITICAL) logging.basicConfig(level=logging.CRITICAL)
if (args.image): if (args.fingerprint):
processImage(args.image) global fingerprint
fingerprint = True
if (args.printmeta):
global printmeta
printmeta = True
if (args.printimage):
global printimage
printimage = True
if (args.file):
processImage(args.file)
else: else:
print('Create PicSeal images') print('Create PicSeal images')
print(' picseal.py -i <image_file>') print(' picseal.py -i <image_file>')

View File

@ -1,5 +1,2 @@
Pillow==3.3.1
pycrypto==2.6.1 pycrypto==2.6.1
pygobject==3.20.1
requests==2.11.0
shellescape==3.4.1

View File

@ -1,20 +0,0 @@
#!/usr/bin/python
#
#
from Crypto.PublicKey import RSA
def decrypt():
externKey="/home/borrajax/myTestKey.pub"
publickey = open(externKey, "r")
decryptor = RSA.importKey(publickey, passphrase="f00bar")
retval=None
file = open("/tmp/cryptThingy.txt", "rb")
retval = decryptor.decrypt(file.read())
file.close()
return retval
if __name__ == "__main__":
decryptedThingy=decrypt()
print "Decrypted: %s" % decryptedThingy

View File

@ -1,17 +0,0 @@
#!/usr/bin/python
#
#
from Crypto.PublicKey import RSA
def encrypt(message):
externKey="/home/borrajax/myTestKey.pem"
privatekey = open(externKey, "r")
encryptor = RSA.importKey(privatekey, passphrase="f00bar")
encriptedData=encryptor.encrypt(message, 0)
file = open("/tmp/cryptThingy.txt", "wb")
file.write(encriptedData[0])
file.close()
if __name__ == "__main__":
encryptedThingy=encrypt("Loren ipsum")

View File

View File

@ -1,7 +1,8 @@
# #
# Test Signature Class # Test Signature Class
# #
from ..libs.crypto_pub import Signature # run from root of project
from libs.crypto_pub import Signature
msg = b'Hieee, this is a test =)' msg = b'Hieee, this is a test =)'