Skip to content

Instantly share code, notes, and snippets.

@schlamar
Created December 20, 2012 13:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save schlamar/4345304 to your computer and use it in GitHub Desktop.
Save schlamar/4345304 to your computer and use it in GitHub Desktop.
Safe pickle implementations
In [1]: %paste
import hmac
import hashlib
import cPickle
import cStringIO
key = '\xa7\x9ePS\xf5\x84\xce\xc8\xad\xcdfEb\x94\x10K\x9b\x12\xed'
dig_size = hashlib.sha1().digest_size
def safe_loads(data):
fobj = cStringIO.StringIO(data)
unpickler = cPickle.Unpickler(fobj)
unpickler.find_global = None
return unpickler.load()
def safe_dumps(data):
return cPickle.dumps(data, protocol=-1)
def safe_loads_hmac(data):
sig, data = data[:dig_size], data[dig_size:]
expected = hmac.new(key, data, hashlib.sha1).digest()
if expected != sig:
raise cPickle.UnpicklingError('Signature wrong.')
return cPickle.loads(data)
def safe_dumps_hmac(data):
data = cPickle.dumps(data, protocol=-1)
sig = hmac.new(key, data, hashlib.sha1).digest()
return sig + data
## -- End pasted text --
In [2]: data = [1, 2, True, False, 'abcd']
In [3]: %timeit s = safe_dumps(data); safe_loads(s)
100000 loops, best of 3: 3.31 us per loop
In [4]: %timeit s = safe_dumps_hmac(data); safe_loads_hmac(s)
10000 loops, best of 3: 25.1 us per loop
In [5]: %timeit s = cPickle.dumps(data, protocol=-1); cPickle.loads(s)
100000 loops, best of 3: 2.55 us per loop
In [6]: data = dict((i, str(i) * 10) for i in xrange(20000))
In [7]: %timeit s = safe_dumps(data); safe_loads(s)
100 loops, best of 3: 6.86 ms per loop
In [8]: %timeit s = safe_dumps_hmac(data); safe_loads_hmac(s)
100 loops, best of 3: 13 ms per loop
In [9]: %timeit s = cPickle.dumps(data, protocol=-1); cPickle.loads(s)
100 loops, best of 3: 6.8 ms per loop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment