Python Forum
Paul Rubin p3.py lightweight encrypt/decrypt - is there a python3 version?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Paul Rubin p3.py lightweight encrypt/decrypt - is there a python3 version?
#1
Hi all,

I'm currently using the lightweight encryption/decryption script by Paul Rubin on python2.7 below. I was wondering if there's a python3 version of it or if anyone here could help with the conversion. I had tried converting it with online tools a few times but the converted code didn't work.

from string import join
from array import array
import sha, base64i
from time import time

# This fix https://mail.python.org/pipermail/python-list/2010-January/563791.html
for typecode in 'IL':
     if len(array(typecode, [0]).tostring()) == 4:
          uint32 = typecode
          break
     else:
         raise RuntimeError("Neither 'I' nor 'L' are unsigned 32-bit integers.")

class CryptError(Exception): pass
def _hash(str): return sha.new(str).digest()

_ivlen = 16
_maclen = 8
_state = _hash(`time()`)
try:
    import os
    _pid = `os.getpid()`
except ImportError, AttributeError:
    _pid = ''

def _expand_key(key, clen):
    blocks = (clen+19)/20
    xkey=[]
    seed=key
    for i in xrange(blocks):
        seed=sha.new(key+seed).digest()
        xkey.append(seed)
    j = join(xkey,'')
    return array (uint32, j)

def encrypt(plain, key,static=False):
    global _state
    H = _hash
    # change _state BEFORE using it to compute nonce, in case there's
    # a thread switch between computing the nonce and folding it into
    # the state.  This way if two threads compute a nonce from the
    # same data, they won't both get the same nonce.  (There's still
    # a small danger of a duplicate nonce--see below).
    

    # Attempt to make nlist unique for each call, so we can get a
    # unique nonce.  It might be good to include a process ID or
    # something, but I don't know if that's portable between OS's.
    # Since is based partly on both the key and plaintext, in the
    # worst case (encrypting the same plaintext with the same key in
    # two separate Python instances at the same time), you might get
    # identical ciphertexts for the identical plaintexts, which would
    # be a security failure in some applications.  Be careful.
    if static:
        _mytime="1173791978.6500001"
        _mystate = _hash(`_mytime`)
        _state = 'X'+_mystate
        nlist = [_mytime, _pid, _state, `len(plain)`,plain, key]
        nonce = "?`k@?HZmG??B?"
    else:
        _state = 'X'+_state
        nlist = [`time()`, _pid, _state, `len(plain)`,plain, key]
        nonce = H(join(nlist,','))[:_ivlen]
    _state = H('update2'+_state+nonce)
    k_enc, k_auth = H('enc'+key+nonce), H('auth'+key+nonce)
    n=len(plain)
    stream = array(uint32, plain+'0000'[n&3:])
    xkey = _expand_key(k_enc, n+4)
    for i in xrange(len(stream)):
        stream[i] = stream[i] ^ xkey[i]
    ct = nonce + stream.tostring()[:n]
    auth = _hmac(ct, k_auth)
    return base64i.urlsafe_b64encode(ct + auth[:_maclen])

def decrypt(cipher, key):
    cipher=base64i.urlsafe_b64decode(cipher)
    H = _hash
    n=len(cipher)-_ivlen-_maclen        # length of ciphertext
    if n < 0:
        raise CryptError, "invalid ciphertext"
    nonce,stream,auth = \
      cipher[:_ivlen], cipher[_ivlen:-_maclen]+'0000'[n&3:],cipher[-_maclen:]
    k_enc, k_auth = H('enc'+key+nonce), H('auth'+key+nonce)
    vauth = _hmac (cipher[:-_maclen], k_auth)[:_maclen]
    if auth != vauth:
        raise CryptError, "invalid key or ciphertext"

    stream = array(uint32, stream)
    xkey = _expand_key (k_enc, n+4)
    for i in xrange (len(stream)):
        stream[i] = stream[i] ^ xkey[i]
    plain = stream.tostring()[:n]
    return plain

# RFC 2104 HMAC message authentication code
# This implementation is faster than Python 2.2's hmac.py, and also works in
# old Python versions (at least as old as 1.5.2).
from string import translate
def _hmac_setup():
    global _ipad, _opad, _itrans, _otrans
    _itrans = array('B',[0]*256)
    _otrans = array('B',[0]*256)
    for i in xrange(256):
        _itrans[i] = i ^ 0x36
        _otrans[i] = i ^ 0x5c
    _itrans = _itrans.tostring()
    _otrans = _otrans.tostring()

    _ipad = '\x36'*64
    _opad = '\x5c'*64

def _hmac(msg, key):
    if len(key)>64:
        key=sha.new(key).digest()
    ki = (translate(key,_itrans)+_ipad)[:64] # inner
    ko = (translate(key,_otrans)+_opad)[:64] # outer
    return sha.new(ko+sha.new(ki+msg).digest()).digest()

#
# benchmark and unit test
#

def _time_p3(n=1000,len=20):
    plain="a"*len
    t=time()
    for i in xrange(n):
        encrypt(plain,"abcdefgh")
    dt=time()-t
    print "plain p3:", n,len,dt,"sec =",n*len/dt,"bytes/sec"

def _speed():
    _time_p3(len=5)
    _time_p3()
    _time_p3(len=200)
    _time_p3(len=2000,n=100)

def _test():
    e=encrypt
    d=decrypt

    plain="test plaintext"
    key = "test key"
    c1 = e(plain,key)
    c2 = e(plain,key)
    assert c1!=c2
    assert d(c2,key)==plain
    assert d(c1,key)==plain
    c3 = c2[:20]+chr(1+ord(c2[20]))+c2[21:] # change one ciphertext character

    try:
        print d(c3,key)         # should throw exception
        print "auth verification failure"
    except CryptError:
        pass

    try:
        print d(c2,'wrong key')         # should throw exception
        print "test failure"
    except CryptError:
        pass

_hmac_setup()
##_test()
##_speed()
Thanks for reading and in anticipation for your replies. Smile
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  encrypt data in json file help jacksfrustration 1 185 Mar-28-2024, 05:16 PM
Last Post: deanhystad
  Encrypt and decrypt in python using own fixed key SriRajesh 3 4,781 Feb-20-2022, 01:18 PM
Last Post: dboxall123
  Trying to encrypt and decrypt password into a file rpizw 4 3,264 Aug-12-2020, 05:15 PM
Last Post: bowlofred
  encrypt entire project mattc 2 2,410 Jul-21-2020, 07:05 AM
Last Post: mattc
  The code to decrypt Caeser Cipher. lazerwolf101 2 3,125 May-26-2020, 04:01 PM
Last Post: DT2000
  Gnuradio python3 is not compatible python3 xmlrpc library How Can I Fix İt ? muratoznnnn 3 4,876 Nov-07-2019, 05:47 PM
Last Post: DeaD_EyE
  Zeep lib, encrypt soap body miha1234 0 2,839 Sep-12-2019, 07:52 AM
Last Post: miha1234
  How to decrypt Blowfish-encrypted text encrypted with Perl's Crypt::CBC? swechsler 0 2,157 Aug-15-2019, 05:24 PM
Last Post: swechsler
  Need help understanding a couple of functions (encrypt,decrypt, int_to_bytes) xoani 0 1,986 Jun-09-2019, 03:25 PM
Last Post: xoani
  PyPDF2 encrypt Truman 3 5,418 Jan-19-2019, 12:18 AM
Last Post: snippsat

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020