2014-11-10 21 views
6

Ho bisogno di un implementazione di Python/C/C++/Java che può pausa hashing progresso e negozio che il progresso in un file in modo tale che il progresso è recuperabili da quel file in una fase successiva.Oggetti hash sha256 persistenti?

Non importa in quale lingua sia scritto da sopra elencato, dovrebbe funzionare correttamente in Python. Si consiglia di fornire che funzioni bene con "hashlib", tuttavia non è necessario. Inoltre, se esiste già una cosa del genere, è sufficiente un collegamento.

Per un'idea, ciò che la vostra implementazione dovrebbe raggiungere.

import hashlib 
import hashpersist #THIS IS NEEDED. 

sha256 = hashlib.sha256("Hello ") 
hashpersist.save_state(sha256, open('test_file', 'w')) 

sha256_recovered = hashpersist.load_state(open('test_file', 'r')) 
sha256_recovered.update("World") 
print sha256_recovered.hexdigest() 

Questo dovrebbe fornire lo stesso risultato dell'ashing semplice di "Hello World" con la funzione standard sha256.

a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e 
+2

possibile duplicato di [Stato hashlib persistente] (http://stackoverflow.com/questions/2130892/persisting-hashlib-state) –

+0

Come hai indubbiamente scoperto che non puoi mettere sottochiave gli oggetti Hash di hashlib; vedere [Stato hashlib persistente] (http://stackoverflow.com/q/2130892/4014959) per una spiegazione e alcune opzioni. Ma puoi accelerare il tuo hashing usando un blocco più grande, ad esempio 64kB. –

+0

@ PM2Ring Nessuna risposta è soddisfacente nella tua domanda suggerita perché ho bisogno di qualcosa (SOME_CLASS) che possa mantenere qualsiasi hash da hashlib. –

risposta

6

è rivelato più facile che ho pensato di riscrivere hashlib essere ripristinabile, almeno, la porzione SHA-256. Ho passato un po 'di tempo a giocare con il codice C che utilizza la libreria crittografica OpenSSL, ma poi ho capito che non ho bisogno di tutto ciò, posso semplicemente usare i ctype.

rehash.py

#! /usr/bin/env python 

''' A resumable implementation of SHA-256 using ctypes with the OpenSSL crypto library 

    Written by PM 2Ring 2014.11.13 
''' 

from ctypes import * 

SHA_LBLOCK = 16 
SHA256_DIGEST_LENGTH = 32 

class SHA256_CTX(Structure): 
    _fields_ = [ 
     ("h", c_long * 8), 
     ("Nl", c_long), 
     ("Nh", c_long), 
     ("data", c_long * SHA_LBLOCK), 
     ("num", c_uint), 
     ("md_len", c_uint) 
    ] 

HashBuffType = c_ubyte * SHA256_DIGEST_LENGTH 

#crypto = cdll.LoadLibrary("libcrypto.so") 
crypto = cdll.LoadLibrary("libeay32.dll" if os.name == "nt" else "libssl.so") 

class sha256(object): 
    digest_size = SHA256_DIGEST_LENGTH 

    def __init__(self, datastr=None): 
     self.ctx = SHA256_CTX() 
     crypto.SHA256_Init(byref(self.ctx)) 
     if datastr: 
      self.update(datastr) 

    def update(self, datastr): 
     crypto.SHA256_Update(byref(self.ctx), datastr, c_int(len(datastr))) 

    #Clone the current context 
    def _copy_ctx(self): 
     ctx = SHA256_CTX() 
     pointer(ctx)[0] = self.ctx 
     return ctx 

    def copy(self): 
     other = sha256() 
     other.ctx = self._copy_ctx() 
     return other 

    def digest(self): 
     #Preserve context in case we get called before hashing is 
     # really finished, since SHA256_Final() clears the SHA256_CTX 
     ctx = self._copy_ctx() 
     hashbuff = HashBuffType() 
     crypto.SHA256_Final(hashbuff, byref(self.ctx)) 
     self.ctx = ctx 
     return str(bytearray(hashbuff)) 

    def hexdigest(self): 
     return self.digest().encode('hex') 

#Tests 
def main(): 
    import cPickle 
    import hashlib 

    data = ("Nobody expects ", "the spammish ", "imposition!") 

    print "rehash\n" 

    shaA = sha256(''.join(data)) 
    print shaA.hexdigest() 
    print repr(shaA.digest()) 
    print "digest size =", shaA.digest_size 
    print 

    shaB = sha256() 
    shaB.update(data[0]) 
    print shaB.hexdigest() 

    #Test pickling 
    sha_pickle = cPickle.dumps(shaB, -1) 
    print "Pickle length:", len(sha_pickle) 
    shaC = cPickle.loads(sha_pickle) 

    shaC.update(data[1]) 
    print shaC.hexdigest() 

    #Test copying. Note that copy can be pickled 
    shaD = shaC.copy() 

    shaC.update(data[2]) 
    print shaC.hexdigest() 


    #Verify against hashlib.sha256() 
    print "\nhashlib\n" 

    shaD = hashlib.sha256(''.join(data)) 
    print shaD.hexdigest() 
    print repr(shaD.digest()) 
    print "digest size =", shaD.digest_size 
    print 

    shaE = hashlib.sha256(data[0]) 
    print shaE.hexdigest() 

    shaE.update(data[1]) 
    print shaE.hexdigest() 

    #Test copying. Note that hashlib copy can NOT be pickled 
    shaF = shaE.copy() 
    shaF.update(data[2]) 
    print shaF.hexdigest() 


if __name__ == '__main__': 
    main() 

resumable_SHA-256.py

#! /usr/bin/env python 

''' Resumable SHA-256 hash for large files using the OpenSSL crypto library 

    The hashing process may be interrupted by Control-C (SIGINT) or SIGTERM. 
    When a signal is received, hashing continues until the end of the 
    current chunk, then the current file position, total file size, and 
    the sha object is saved to a file. The name of this file is formed by 
    appending '.hash' to the name of the file being hashed. 

    Just re-run the program to resume hashing. The '.hash' file will be deleted 
    once hashing is completed. 

    Written by PM 2Ring 2014.11.14 
''' 

import cPickle as pickle 
import os 
import signal 
import sys 

import rehash 

quit = False 

blocksize = 1<<16 # 64kB 
blocksperchunk = 1<<8 

chunksize = blocksize * blocksperchunk 

def handler(signum, frame): 
    global quit 
    print "\nGot signal %d, cleaning up." % signum 
    quit = True 


def do_hash(fname, filesize): 
    hashname = fname + '.hash' 
    if os.path.exists(hashname): 
     with open(hashname, 'rb') as f: 
      pos, fsize, sha = pickle.load(f) 
     if fsize != filesize: 
      print "Error: file size of '%s' doesn't match size recorded in '%s'" % (fname, hashname) 
      print "%d != %d. Aborting" % (fsize, filesize) 
      exit(1) 
    else: 
     pos, fsize, sha = 0, filesize, rehash.sha256() 

    finished = False 
    with open(fname, 'rb') as f: 
     f.seek(pos) 
     while not (quit or finished): 
      for _ in xrange(blocksperchunk): 
       block = f.read(blocksize) 
       if block == '': 
        finished = True 
        break 
       sha.update(block) 

      pos += chunksize 
      sys.stderr.write(" %6.2f%% of %d\r" % (100.0 * pos/fsize, fsize)) 
      if finished or quit: 
       break 

    if quit: 
     with open(hashname, 'wb') as f: 
      pickle.dump((pos, fsize, sha), f, -1) 
    elif os.path.exists(hashname): 
     os.remove(hashname) 

    return (not quit), pos, sha.hexdigest() 


def main(): 
    if len(sys.argv) != 2: 
     print "Resumable SHA-256 hash of a file." 
     print "Usage:\npython %s filename\n" % sys.argv[0] 
     exit(1) 

    fname = sys.argv[1] 
    filesize = os.path.getsize(fname) 

    signal.signal(signal.SIGINT, handler) 
    signal.signal(signal.SIGTERM, handler) 

    finished, pos, hexdigest = do_hash(fname, filesize) 
    if finished: 
     print "%s %s" % (hexdigest, fname) 
    else: 
     print "sha-256 hash of '%s' incomplete" % fname 
     print "%s" % hexdigest 
     print "%d/%d bytes processed." % (pos, filesize) 


if __name__ == '__main__': 
    main() 

demo

import rehash 
import pickle 
sha=rehash.sha256("Hello ") 
s=pickle.dumps(sha.ctx) 
sha=rehash.sha256() 
sha.ctx=pickle.loads(s) 
sha.update("World") 
print sha.hexdigest() 

uscita

a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e 

modificare

Ho appena fatto una modifica minore per consentire rehash per funzionare su Windows, anche, anche se ho testato solo su WinXP. libeay32.dll può trovarsi nella directory corrente o da qualche parte nel percorso di ricerca della libreria di sistema, ad esempio WINDOWS\system32. La mia piuttosto vecchia (e per la maggior parte inutilizzata) installazione di XP non è stata in grado di trovare la .dll, anche se è utilizzata da OpenOffice e Avira. Quindi l'ho appena copiato dalla cartella Avira a system32. E ora funziona perfettamente. :)

+0

Dà, OSError: libcrypto.so: impossibile aprire il file oggetto condiviso ... Puoi scrivere/aggiornare le istruzioni per come farlo funzionare? –

+0

Forse non hai quel file di libreria, ma dovresti farlo se sei su Linux e hai OpenSSL installato. Ma prova a cambiare la libreria in "libssl.so", cioè cambia 'crypto = cdll.LoadLibrary (" libcrypto.so ")' a 'crypto = cdll.LoadLibrary (" libssl.so ")'. Se non stai usando Linux o qualche altra forma di Unix, potresti dover usare una sintassi leggermente diversa. –

+0

Non ho molta familiarità con Windows, ma sembra che il nome della libreria di crittografia OpenSSL su Windows sia 'ssleay32.dll'. E l'equivalente a 'libssl.so' (la libreria principale di OpenSSL) è' libeay32.dll'. –