Compare commits

..

No commits in common. "master" and "hash" have entirely different histories.
master ... hash

15 changed files with 94 additions and 627 deletions

11
.gitignore vendored
View File

@ -1,11 +1,3 @@
# Project specific files
#
# binaries
*.jpg
# Python Files
#
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
@ -45,8 +37,11 @@ coverage.xml
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
#binaries
*.jpg

39
README
View File

@ -1,39 +0,0 @@
***** ***** ***** *****
*** Picseal ***
***** ***** ***** *****
Your Photo is your Crypto Key
-protect from photo modification
-verify photo ownership
-proof of photo originality, proof of photo ownership. (hash time stamp, Certified Secret tech)
-use a photo as authentication (what you have), requires chain-of-custody, requires time stamp verify
-generate a new key pair to share with every photo
[[ Requirements ]]
Python 3
pycrypto==2.6.1
[[ Usage ]]
Create PicSeal images
picseal.py -i <image_file>
***** ***** ***** *****
usage: picseal.py [-h] [-f FILE] [-v] [-vv] [-l] [-pm] [-pi] [-pa] [-w]
optional arguments:
-h, --help show this help message and exit
-f FILE, --file FILE source image file
-v, --verbose will set logging level to INFO
-vv, --vverbose will set logging level to DEBUG
-l, --logging will supercede the -v option and send all logging to a
file, logging.DEBUG
-pm, --printmeta print the metadata markers
-pi, --printimage print the image markers
-pa, --printall print all markers
-w, --write write picseal files

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 ]]

View File

@ -1,26 +0,0 @@
[[[ PicSeal Agile ]]]
[[ BACKLOG ]]
[ current (ver 1.0) ]
[ future ]
* add option "-d" to decrypt file
* add option "-e" to encrypt file
* add option "-ex" to export the key to .PEM file
* add visual stamp to the file so that a picseal photo can be recognized
* use block-chain for "certified secret" technology, insert hash signature into block-chain
[[ COMPLETED ]]
[ current (ver 1.0) ]
* reads a picseal .jpg file, understands pub/pvt keys from file
* writes new .jpg files with crypto keys
* verbose output of image data chunks
* reads .jpg file, parses data tags

View File

@ -1,60 +0,0 @@
[[[ PicSeal Design Document ]]]
[[ 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 key pair
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 ]]
[ binary data blob format ]
# Pub: [app15:2|size:2|'picseal':7|type:1|sig:512|pubkey:550]
# Pvt: [app15:2|size:2|'picseal':7|type:1|sig:512|pvtkey:2347]
# 1. app15 jpg marker
app15_marker = b'\xff\xef'
# 2. ascii code for "picseal"
picseal_marker = b'\x70\x69\x63\x73\x65\x61\x6C'
# 3. type
pub_marker = b'\x01'
pvt_marker = b'\x02'
# 4. signature is the hash of the image, signed by the private key
# 5. JSON crypto blob data
[ crypto blob format ]
JSON:
{
"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

@ -1,215 +0,0 @@
[[[ Picseal ]]]
"crypto key sharing using your photos"
"exif data providing photo integrity, ownership, and crypto key"
[[ Formats]]
@ http://stackoverflow.com/questions/12749858/rsa-public-key-format
@ http://security.stackexchange.com/questions/57043/most-popular-rsa-key-format
DER: binary encoded format, sometimes Asn.1 BER-encoded
PEM: base64 format of the same DER-encoded file with header&footer lines
XML: xml format
-----BEGIN RSA PUBLIC KEY-----
-----END RSA PUBLIC KEY-----
---- BEGIN SSH2 PUBLIC KEY ----
---- END SSH2 PUBLIC KEY ----
[[ WolfSSL ]]
[ Compile Mac ]
@ https://www.wolfssl.com/wolfSSL/Docs-wolfssl-manual-toc.html
@ https://www.wolfssl.com/wolfSSL/Docs-wolfssl-manual-2-building-wolfssl.html
@ https://wolfssl.github.io/wolfcrypt-py/
$ brew install autoconf automake libtool
$ glibtoolize
$ git clone https://github.com/wolfssl/wolfssl.git
$ cd wolfssl/
$ ./autogen.sh
$ ./configure --help
$ ./configure --enable-sha512
$ make
"In order to prevent conflicts with Apple's own libtool we have prepended a "g"
so, you have instead: glibtool and glibtoolize."
[[ gexiv2 ]]
# gobject wrapper of the libexiv2 library (which is the engine for exiv2)
@ https://wiki.gnome.org/Projects/gexiv2
@ http://wiki.gnome.org/GObjectIntrospection
@ http://wiki.gnome.org/PyGObject/IntrospectionPorting
# API docs
@ http://lazka.github.io/pgi-docs/#GExiv2-0.10
[ XMP ]
# adding new XMP namespaces
@ http://dev.exiv2.org/boards/3/topics/1039
[ install ubuntu ]
$ sudo apt-get install libexiv2-dev libgexiv2-dev gir1.2-gexiv2-0.10
[ install mac ]
# install globally (python2)
$ brew install exiv2 gexiv2 pygobject3
# install for python3
$ brew reinstall pygobject3 --with-python3
[ build ]
$ git clone git://git.gnome.org/gexiv2
$ sudo apt-get install gobject-introspection
$ sudo apt-get install glib libgirepository1.0-dev
$ sudo apt-get install libglib2.0-dev libexiv2-dev python-gobject-dev
$
$ ./autogen.sh
$ ./configure --enable-introspection
[[ EXIF ]]
[ exiv2 ]
# BUILD
http://dev.exiv2.org/projects/exiv2/wiki/How_do_I_build_Exiv2_on_the_XYZ_platform
[ pyexiv2 ]
@ http://tilloy.net/dev/pyexiv2/
[ exiftool]
# perl program
@ http://www.sno.phy.queensu.ca/~phil/exiftool/
$ brew install exiftool
[[ exiftool]]
# perl program
# http://www.sno.phy.queensu.ca/~phil/exiftool/
$ brew install exiftool
[[ Competitors ]]
[ authentication ]
https://getclef.com/
[[ Debug ]]
$ exiv2 -ps image.jpg
[[ Crypto ]]
[ Public Key ]
# encrypt
@ https://pythonhosted.org/pycrypto/Crypto.Cipher.PKCS1_v1_5.PKCS115_Cipher-class.html#encrypt
[ OpenSSL ]
openssl genrsa -out ~/myTestKey.pem -passout pass:"f00bar" -des3 2048
openssl rsa -pubout -in ~/myTestKey.pem -passin pass:"f00bar" -out ~/myTestKey.pub
[ Cryptography.io ]
Fernet (Public Key)
@ https://cryptography.io/en/latest/fernet/
[[ MVP Plan ]]
[ C ]
libexiv --> exif read/write
libwolfss --> crypto generation
[ Functions ]
# load image file
picseal.init(image_file)
# create pub/priv key pair
# add new public key to exif
# store priv key in memory
picseal.add_new_key(CIPHER_TYPE)
# hash the image, encrypt hash with priv-key
# hash the image & specific exif tags, encrypt hash with priv-key
# add signatures to exif
picseal.seal_image(HASH_TYPE)
# write the image with public key, and signature
picseal.write_pub(FILE_HANDLE)
# write the image with private key, and signature
# ADD PIN??
picseal.write_priv(FILE_HANDLE)
[ seal ]
sha-512,public-key
[[ Libraries ]]
libexiv2-14 (= 0.25-2.1), libc6 (>= 2.14), libgcc1 (>= 1:4.1.1), libstdc++6 (>= 5.2)
[[ Crypto ]]
@ http://security.stackexchange.com/
@ http://security.stackexchange.com/questions/135946/when-should-i-generate-new-public-private-keys-using-rsa
[[ Images ]]
[ PIL Pillow ]
# use pillow, a PIL fork
@ https://github.com/python-pillow/Pillow
@ http://pillow.readthedocs.io/en/3.0.x/handbook/tutorial.html#reading-and-writing-images
# no python 3 version :(
ver 1.1.7, for Python 2.7, Nov 15 2009
[[ JPG ]]
@ http://stackoverflow.com/questions/4550296/how-to-identify-contents-of-a-byte-is-a-jpeg?rq=1
@ https://en.wikipedia.org/wiki/Magic_number_%28programming%29
@ http://www.effbot.org/imagingbook/image.htm#tag-Image.Image.tobitmap
[[ Testing ]]
[ crypto test ]
b'-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnvdAyn5JuiRcoL8s+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==\n-----END PUBLIC KEY-----'
privkey==
b'-----BEGIN RSA PRIVATE KEY-----\n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\n-----END RSA PRIVATE KEY-----'
text: attack at dawn
crypt: b'A!\x81\t\xac\x87n4qw\x84\xcb\xf1\xdc\x1b\xc0\xdcjQ\xecB:A\xae\x14\xcc\xa9IpV\xa6\xc3\x10\xa2G\xc6\xae\xbbb} \xcf\x12\xfd\x92h\xb9\xd1\xc7\x80\xd9Q\xc1\xd8\x9b\x0c\x04\x14@C\xaa6\x0e\xdc\x95\xbf\xd0\x99\x0fV;i\x14\xbb\x86\xe1\xa2\xbfV]\xa4\x97t\xc7L\xc9sh\xd5\xbc6\x03\xea\xe7\x07a\x01\x08\x0e\\\x90|\xacT\xc2\xfb\xb8\xf7\xa9\xc7\x0c\x8a\xd9\xdbD\x8c\x98aWS\xdf.h\xb6\xb2H\x13\xdac\xd9\x7fM\x85\x8e\xa3\x00_\xeb\x15;\xd9J6\xc0\x99\xef\xf7\xf1D\xdb\xe8\x05\xdf\x16\xf9\x07\x13Gtv\xd9^\xcfr>\xd8w\xc6\xf0\xb8\xff\x1b\xf9rt%#\xc0\x83!\xb85\xb3X\xfd\x1a~\xd51D\x0c~3\xeb\x9fRc*\xb4\xa0\x84v?vI\xe00\xdd\x16\xc1u\x9e\xad`-P\xf8/N<83o\x8d\xb0Q\x82\xd5Z\x13\x8e\xee\xfa\xc0\x89.%\xeb\xdd\xc8.P\x03\x87\xe4C7e\xe9\xd1\x13\n\x83\xe9\x89\x0f^\xfb\xc8$\x95\x7f\xe3\x80G\xf9\x96_l\x03\x92\x01\x9e\xd1\x13\x9e\x8b\xdc-C\x02/^\xb5Nl\xcc\x7f\xb6\xb8v\x95\x998\x0c\x18?@\xaf\xaa\x1e\xea;gt\x83d(G\xefO\x1a\rq9>\xc4\xa5\x01-\xcd?q\x94\xf9\xa0\xa0\xe6}\x9aJjp\xa0\x05\xaf\xda\xf2\xc9\xd8\xf0\x1b\xbe\x0b\x80\xdc\x9c\xed\xabu\xc6\x0eT\x11\xbd8\x12\x10@\x9c\xf8\x97E\xea;\xcb\xf3\xaf\xf9\xc7\xad@\xf3#G\xc9&yE=\xa3nZ\xc7(9\xf15e\xae\xe4\xbdXmw\x98\xf5B\x885$w\x9b\x82\x89\xfa\xf6\xe9\xc9\xea\x95[22\xf4\xc9\xb9\xf9\xfb\xe2\xb4\xe8\xe7\xb2J\xc59\xac\x9e\xa9e\x13\xb4\x1c\xea\x18\xacy+\xb3\x01@$\xef\x15Ao\xb7Y\xf5]0I(\xd1\xd8E\x01^\xba\xa4W\x96D\xe5i\xf4e\x08c\xd37\x15\x1fb\xe5\xca\x9eAN^\xc0\xc8\x82\xa9\xb5N\xd2~\xc6d\xf7\xcbq\x02\x90\x1a#I\xf4\xf8\xe7i\xba\xcdQ\xeb\x87Agn\x8f'
text: b'attack at dawn'

View File

@ -15,11 +15,13 @@ class Signature:
self.sig_data = None
self.hash_data = None
self.hh = SHA512.new()
self.genKeys()
#
def genSig(self):
def genSig(self, hshh):
signer = PKCS1_v1_5.new(self.key_data)
self.sig_data = signer.sign(self.hh)
self.sig_data = signer.sign(hshh)
return self.sig_data
#
def verifySig(self, hshh, bin_sig):
@ -85,20 +87,14 @@ class Signature:
#
def _test():
#logging.basicConfig(level=logging.DEBUG)
msg = b'Hieee, this is a test =)'
sig = Signature()
sig.hh.update(msg)
sig.hash_data = sig.hh.digest()
sig.genSig()
print("Hash created:\n{}".format(sig.hash_data))
print("Size=={}".format(str(len(sig.hash_data))))
print("Signature created:\n{}".format(sig.sig_data))
print("Size=={}".format(str(len(sig.sig_data))))
isVerified = sig.verifySig(sig.hh, sig.sig_data)
sig = Signature()
sig_data = sig.genSig(msg)
print("Signature created")
print("sig_data=={}".format(sig_data))
isVerified = sig.verifySig(msg, sig_data)
print("isVerified=={}".format(str(isVerified)))

View File

@ -21,16 +21,11 @@ import re
import struct
import logging
from libs.jpg_fp import JpgFingerprint
from libs.jpg_picseal import JpgPicSeal
#
class JpgBin:
BUF_CHUNK_SIZE = 8192
soi_marker = b'\xff\xd8'
eof_marker = b'\xff\xd9'
BUF_CHUNK_SIZE = 2048
def __init__(self):
self.data_buf = None
@ -49,8 +44,7 @@ class JpgBin:
self.prev_mstr = "DUH!"
self.prev_imgData = False
self.jpg_fp = JpgFingerprint()
self.importSig = None
self.jpg_fp = JpgFingerprint()
#
# check for JPG file type marker
@ -147,20 +141,14 @@ class JpgBin:
#
#
def markerAppData(self, marker_hex):
seek = True
self.__addPrevMarkerData(marker_hex, "APP ", False)
if (0xffef == marker_hex):
if (self.__processPicSeal()):
seek = False
if (seek):
(rec_len, prev_buf) = self.__calcSeekBytes()
logging.info("length=={}".format(str(rec_len)))
rec_len = self.__calcSeekBytes()
logging.info("length=={}".format(str(rec_len)))
#
def markerComment(self, marker_hex):
self.__addPrevMarkerData(marker_hex, "COM ", False)
self.__calcSeekBytes()
rec_len = self.__calcSeekBytes()
#
# Image Data
@ -179,7 +167,7 @@ class JpgBin:
#
def markerDQT(self, marker_hex):
self.__addPrevMarkerData(marker_hex, "DQT ")
self.__calcSeekBytes()
rec_len = self.__calcSeekBytes()
#
def markerDRI(self, marker_hex):
@ -189,16 +177,16 @@ class JpgBin:
#
def markerSOF0(self, marker_hex):
self.__addPrevMarkerData(marker_hex, "SOF0")
self.__calcSeekBytes()
rec_len = self.__calcSeekBytes()
#
def markerSOF2(self, marker_hex):
self.__addPrevMarkerData(marker_hex, "SOF2")
self.__calcSeekBytes()
rec_len = self.__calcSeekBytes()
def markerDHT(self, marker_hex):
self.__addPrevMarkerData(marker_hex, "DHT ")
self.__calcSeekBytes()
rec_len = self.__calcSeekBytes()
#
# end of file marker is never added to the marker array list (same as start of image marker)
@ -239,17 +227,15 @@ class JpgBin:
# move the index 2 bytes, then read the 2 bytes to get the length
#
def __calcSeekBytes(self):
prev_buf = None
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):
prev_buf = self.data_buf[self.data_idx:]
rec_diff = rec_len - remain_bytes
self.__seekBytes(rec_diff)
else:
self.data_idx += rec_len
return rec_len, prev_buf
return rec_len
#
def __seekBytes(self, num_bytes):
@ -258,36 +244,6 @@ class JpgBin:
logging.debug("SEEK: seek=={}, cur_loc=={}".format(num_bytes, pos))
return pos
#
def __getBuf(self):
new_buf = None
(rec_len, prev_buf) = self.__calcSeekBytes()
if (prev_buf):
remain_bytes = rec_len - len(prev_buf)
new_buf = prev_buf.join(self.data_buf[:remain_bytes])
pass
else:
new_buf = self.data_buf[(self.data_idx-rec_len):self.data_idx]
return new_buf
#
# [app_rec_header:2|len:2|picseal_header:7]
#
def __processPicSeal(self):
rec_hdr = 4
ps_hdr_size = rec_hdr+len(JpgPicSeal.picseal_marker)
remain_buf = self.data_len-(self.data_idx+ps_hdr_size)
if (remain_buf > ps_hdr_size):
if (JpgPicSeal.isPicSeal(self.data_buf[self.data_idx+rec_hdr:self.data_idx+ps_hdr_size])):
#
# calculate size, check buffer, maybe read more bytes from file
#
buf = self.__getBuf()
self.importSig = JpgPicSeal.deserialize(buf)
return True
return False
#
def printMarkerImg(self):
return self.jpg_fp.printImgMarkers()

View File

@ -1,79 +0,0 @@
#
# I tihnk this is support for the website =)
# instead of reading from a file, read from memory
# goal is to avoid reading/writing to the file system
#
from libs.jpg_bin import JpgBin
from libs.jpg_picseal import JpgPicSeal
class JpgBinWriteMem:
#
def __init__(self, jpg_in):
self.fhr = jpg_in
self.mem = none
#
# input is the Crypto Sig class
#
def writeJpgPicSealPub(self, crypto_sig, fp):
self.__writeJpgHeader()
ps = JpgPicSeal(crypto_sig)
ps.writePub(self.fhw)
self.__writeJpgImg(fp)
#
# input is the Crypto Sig class
#
def writeJpgPicSealPvt(self, crypto_sig, fp):
self.__writeJpgHeader()
ps = JpgPicSeal(crypto_sig)
ps.writePvt(self.fhw)
self.__writeJpgImg(fp)
#
def __writeJpgImg(self, fp):
self.__writeJpgMetadata(fp.markers_meta)
self.__writeJpgImgData(fp.markers_img)
self.__writeJpgFooter()
self.fhw.flush()
self.fhw.close()
#
# array of the marker information
#
def __writeJpgMetadata(self, markers):
for marker in markers:
self.fhr.seek(marker.fpos)
data = self.fhr.read(marker.len)
self.fhw.write(data)
self.fhw.flush()
#
# array of the marker information
#
def __writeJpgImgData(self, markers):
for marker in markers:
# most of the image data is sequential
cpos = self.fhr.tell()
if (marker.fpos != cpos):
self.fhr.seek(marker.fpos)
data = self.fhr.read(marker.len)
self.fhw.write(data)
self.fhw.flush()
#
def __writeJpgHeader(self):
self.fhw.write(bytes(JpgBin.soi_marker))
#
def __writeJpgFooter(self):
self.fhw.write(bytes(JpgBin.eof_marker))

View File

@ -1,13 +1,13 @@
#
#
#
from libs.jpg_bin import JpgBin
from libs.jpg_picseal import JpgPicSeal
class JpgBinWrite:
soi_marker = b'\xff\xd8'
eof_marker = b'\xff\xd9'
picseal_marker = b'\xff\xef'
# picseal_marker = b'\xff\xe0'
#
def __init__(self, jpg_in, jpg_out):
self.fhr = jpg_in
@ -18,7 +18,9 @@ class JpgBinWrite:
#
def writeJpgPicSealPub(self, crypto_sig, fp):
self.__writeJpgHeader()
JpgPicSeal.writePub(self.fhw, crypto_sig)
self.__writeJpgPicSeal(crypto_sig, crypto_sig.getPubKeyDER())
self.__writeJpgImg(fp)
#
@ -26,10 +28,28 @@ class JpgBinWrite:
#
def writeJpgPicSealPvt(self, crypto_sig, fp):
self.__writeJpgHeader()
JpgPicSeal.writePvt(self.fhw, crypto_sig)
self.__writeJpgPicSeal(crypto_sig, crypto_sig.getPvtKeyDER())
self.__writeJpgImg(fp)
#
def __writeJpgPicSeal(self, crypto_sig, keyder):
# must include 2 bytes of length too
size = 2
size += len(crypto_sig.hash_data)
size += len(keyder)
# write picseal marker
self.fhw.write(JpgBinWrite.picseal_marker)
# write the size of picseal record
self.fhw.write(size.to_bytes(2, byteorder='big'))
# write hash of image
self.fhw.write(crypto_sig.hash_data)
# write the public key
self.fhw.write(keyder)
#
def __writeJpgImg(self, fp):
self.__writeJpgMetadata(fp.markers_meta)
@ -64,8 +84,8 @@ class JpgBinWrite:
#
def __writeJpgHeader(self):
self.fhw.write(bytes(JpgBin.soi_marker))
self.fhw.write(bytes(JpgBinWrite.soi_marker))
#
def __writeJpgFooter(self):
self.fhw.write(bytes(JpgBin.eof_marker))
self.fhw.write(bytes(JpgBinWrite.eof_marker))

View File

@ -1,5 +1,5 @@
#
# This Class contains information for the jpg markers, length, and position in the file
# This Class contains information for the jpg markers, length, an position in the file
#
class JpgFingerprint:

View File

@ -4,115 +4,19 @@
# Data: public key, private key, image hash, image signature
# Has: JPG fingerprint
#
# Big-endian
# Pub: [app15:2|size:2|'picseal':7|type:1|sig:512|pubkey:550]
# Pvt: [app15:2|size:2|'picseal':7|type:1|sig:512|pvtkey:2347]
#
import struct
import logging
from Crypto.PublicKey import RSA
from libs.crypto_sig import Signature
class JpgPicSeal:
app15_marker = b'\xff\xef'
# ascii code for "picseal"
picseal_marker = b'\x70\x69\x63\x73\x65\x61\x6C'
pub_marker = b'\x01'
pvt_marker = b'\x02'
def __init__(self):
pass
def __init_(self, sig):
self.sig = None
pass
#
# READ
#
def isPicSeal(buf):
if (buf == JpgPicSeal.picseal_marker):
return True
return False
#
# [size:2|picseal:7|type:1|sig:512|key:550] == 1072
#
def deserialize(buf):
sig = Signature()
retval = False
# read type 0x01 is public key, 0x02 private key
try:
if (buf[9] == ord(JpgPicSeal.pub_marker)):
sig.importPubKey(buf[522:])
print("*** *** ***")
print("*** Public Key Import Sucessful")
print("*** *** ***")
else:
sig.importPvtKey(buf[522:])
print("*** *** ***")
print("*** Private Key Import Sucessful")
print("*** *** ***")
return sig
except Exception as ex:
logging.debug(ex)
return None
def serilize(self, fname):
pass
#
def readPub(self):
pass
def readPvt(self):
pass
#
# WRITE
#
#
def serilize(fname):
pass
#
# input is the Crypto Sig class
#
def writePub(fhw, sig):
JpgPicSeal.__writeData(fhw, sig.sig_data, sig.getPubKeyDER(), JpgPicSeal.pub_marker)
#
# input is the Crypto Sig class
#
def writePvt(fhw, sig):
JpgPicSeal.__writeData(fhw, sig.sig_data, sig.getPvtKeyDER(), JpgPicSeal.pvt_marker)
#
def __writeData(fhw, sig_data, keyder, pubpvt):
# must include 2 bytes for length too, plus 1 for the key type
size = 3
size += len(JpgPicSeal.picseal_marker)
size += len(sig_data)
size += len(keyder)
logging.debug("3+{}+{}+{}=={} | picseal, sig, key".format(str(len(JpgPicSeal.picseal_marker)), str(len(sig_data)), str(len(keyder)), str(size) ))
#
# write header
# write app marker
fhw.write(JpgPicSeal.app15_marker)
# write the size of picseal record
fhw.write(size.to_bytes(2, byteorder='big'))
#
# write picseal data
# write picseal marker
fhw.write(JpgPicSeal.picseal_marker)
fhw.write(pubpvt)
# write signature of image
fhw.write(sig_data)
# write the key data
fhw.write(keyder)
def deserialize(self, fname):
pass

View File

@ -44,11 +44,8 @@ class JpgProc:
self.sig = Signature()
img_hash = self.jpg.genHash(self.sig.hh)
self.sig.hash_data = img_hash
self.sig.genKeys()
self.sig.genSig()
logging.debug("*** Public Key:\n{}\n\n".format(self.sig.getPubKeyDER().hex()))
logging.debug("*** Private Key:\n{}".format(self.sig.getPvtKeyDER().hex()))
logging.info("img_hash-size=={}, img_hash=={}".format(len(img_hash), img_hash))
return img_hash
#
def writePicSealJpg(self, fname=None):

View File

@ -3,21 +3,27 @@
#
import argparse
import logging
from shutil import copyfile
from libs.toolbox import Toolbox
from libs.jpg_proc import JpgProc
printall = False
printmeta = False
printimage = False
printall = False
printmeta = False
printimage = False
write_picseal = False
def main():
parseArgs()
# hash the image binary data only (not metadata)
# create new pub keys, sign hash
# export signature & public key to a new image file
def processImage(image_fn):
jpg_proc = JpgProc()
jpg_proc.process(image_fn)
jpg_proc.hash()
if (write_picseal):
jpg_proc.hash()
print("Writing PicSeal JPG files...")
jpg_proc.writePicSealJpg()
@ -35,12 +41,7 @@ def printImageInfo(jpg_bin):
print( jpg_bin.printMarkerMeta())
def main():
parseArgs()
def parseArgs():
print
print("***** ***** ***** *****")
print(" ** Pic * Seal ** ")
print("***** ***** ***** *****\n")
@ -84,10 +85,10 @@ def parseArgs():
if (args.file):
processImage(args.file)
else:
print('***** ***** ***** *****')
print('ERROR: missing image file')
print(' picseal.py -f <image_file>')
print('***** ***** ***** *****')
print('Create PicSeal images')
print(' picseal.py -i <image_file>')
print('\n***** ***** ***** *****\n')
parser.print_help()

View File

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