Dec-22-2018, 06:40 PM
Hi everyone,
I need help with converting an encryption module (p3.py) written for Python2 to Python3.
First, I converted the module to python3 using the online python 2 to 3 converter (http://www.pythonconverter.com/). When I tried to use the converted module, I get errors.
I have attached the converted source below. The encryption module imports base64i, which I have also included:
Error 1:
Error 2:
Error 3:
Error 4:
Error 5:
Error 6:
Please help me check if I have fixed those errors correctly and for those that I don't know how, please suggest a fix.
Thank you very much in anticipation
I need help with converting an encryption module (p3.py) written for Python2 to Python3.
First, I converted the module to python3 using the online python 2 to 3 converter (http://www.pythonconverter.com/). When I tried to use the converted module, I get errors.
I have attached the converted source below. The encryption module imports base64i, which I have also included:
# p3.py from string import join from array import array import base64i import hashlib 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.") #print('Content-Type: text/html; charset=UTF-8\n\n') #http://devnote.stokemaster.com/2009/07/simple-way-to-encrpt-and-decrypt-short.html class CryptError(Exception): pass def _hash(str): return hashlib.sha224(str).digest() _ivlen = 16 _maclen = 8 _state = _hash(repr(time())) try: import os _pid = repr(os.getpid()) except ImportError as AttributeError: _pid = '' def _expand_key(key, clen): blocks = (clen+19)/20 xkey=[] seed=key for i in range(blocks): seed=hashlib.sha224(key+seed).digest() xkey.append(seed) j = join(xkey,'') return array (uint32, j) def encrypt(plain,key): 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). _state = 'X'+_state # 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. nlist = [repr(time()), _pid, _state, repr(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) # cipher size not counting IV stream = array(uint32, plain+'0000'[n&3:]) xkey = _expand_key(k_enc, n+4) for i in range(len(stream)): stream[i] = stream[i] ^ xkey[i] ct = nonce + stream.tostring()[:n] auth = _hmac(ct, k_auth) #return ct + auth[:_maclen] 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 range (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 range(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 hashlib.sha224(ko+hashlib.sha224(ki+msg).digest()).digest() # # benchmark and unit test # def _time_p3(n=1000,len=20): plain="a"*len t=time() for i in range(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() # uncomment to run speed test
#base64i """RFC 3548: Base16, Base32, Base64 Data Encodings""" # Modified 04-Oct-1995 by Jack Jansen to use binascii module # Modified 30-Dec-2003 by Barry Warsaw to add full RFC 3548 support import re import struct import binascii __all__ = [ # Legacy interface exports traditional RFC 1521 Base64 encodings 'encode', 'decode', 'encodestring', 'decodestring', # Generalized interface for other encodings 'b64encode', 'b64decode', 'b32encode', 'b32decode', 'b16encode', 'b16decode', # Standard Base64 encoding 'standard_b64encode', 'standard_b64decode', # Some common Base64 alternatives. As referenced by RFC 3458, see thread # starting at: # # http://zgp.org/pipermail/p2p-hackers/2001-September/000316.html 'urlsafe_b64encode', 'urlsafe_b64decode', ] _translation = [chr(_x) for _x in range(256)] EMPTYSTRING = '' def _translate(s, altchars): translation = _translation[:] for k, v in list(altchars.items()): translation[ord(k)] = v return s.translate(''.join(translation)) # Base64 encoding/decoding uses binascii def b64encode(s, altchars=None): """Encode a string using Base64. s is the string to encode. Optional altchars must be a string of at least length 2 (additional characters are ignored) which specifies an alternative alphabet for the '+' and '/' characters. This allows an application to e.g. generate url or filesystem safe Base64 strings. The encoded string is returned. """ # Strip off the trailing newline encoded = binascii.b2a_base64(s)[:-1] if altchars is not None: return _translate(encoded, {'+': altchars[0], '/': altchars[1]}) return encoded def b64decode(s, altchars=None): """Decode a Base64 encoded string. s is the string to decode. Optional altchars must be a string of at least length 2 (additional characters are ignored) which specifies the alternative alphabet used instead of the '+' and '/' characters. The decoded string is returned. A TypeError is raised if s were incorrectly padded or if there are non-alphabet characters present in the string. """ if altchars is not None: s = _translate(s, {altchars[0]: '+', altchars[1]: '/'}) try: return binascii.a2b_base64(s) except binascii.Error as msg: # Transform this exception for consistency raise TypeError(msg) def standard_b64encode(s): """Encode a string using the standard Base64 alphabet. s is the string to encode. The encoded string is returned. """ return b64encode(s) def standard_b64decode(s): """Decode a string encoded with the standard Base64 alphabet. s is the string to decode. The decoded string is returned. A TypeError is raised if the string is incorrectly padded or if there are non-alphabet characters present in the string. """ return b64decode(s) def urlsafe_b64encode(s): """Encode a string using a url-safe Base64 alphabet. s is the string to encode. The encoded string is returned. The alphabet uses '-' instead of '+' and '_' instead of '/'. """ return b64encode(s, '-_') def urlsafe_b64decode(s): """Decode a string encoded with the standard Base64 alphabet. s is the string to decode. The decoded string is returned. A TypeError is raised if the string is incorrectly padded or if there are non-alphabet characters present in the string. The alphabet uses '-' instead of '+' and '_' instead of '/'. """ return b64decode(s, '-_') # Base32 encoding/decoding must be done in Python _b32alphabet = { 0: 'A', 9: 'J', 18: 'S', 27: '3', 1: 'B', 10: 'K', 19: 'T', 28: '4', 2: 'C', 11: 'L', 20: 'U', 29: '5', 3: 'D', 12: 'M', 21: 'V', 30: '6', 4: 'E', 13: 'N', 22: 'W', 31: '7', 5: 'F', 14: 'O', 23: 'X', 6: 'G', 15: 'P', 24: 'Y', 7: 'H', 16: 'Q', 25: 'Z', 8: 'I', 17: 'R', 26: '2', } _b32tab = [v for v in list(_b32alphabet.values())] _b32rev = dict([(v, int(k)) for k, v in list(_b32alphabet.items())]) def b32encode(s): """Encode a string using Base32. s is the string to encode. The encoded string is returned. """ parts = [] quanta, leftover = divmod(len(s), 5) # Pad the last quantum with zero bits if necessary if leftover: s += ('\0' * (5 - leftover)) quanta += 1 for i in range(quanta): # c1 and c2 are 16 bits wide, c3 is 8 bits wide. The intent of this # code is to process the 40 bits in units of 5 bits. So we take the 1 # leftover bit of c1 and tack it onto c2. Then we take the 2 leftover # bits of c2 and tack them onto c3. The shifts and masks are intended # to give us values of exactly 5 bits in width. c1, c2, c3 = struct.unpack('!HHB', s[i*5:(i+1)*5]) c2 += (c1 & 1) << 16 # 17 bits wide c3 += (c2 & 3) << 8 # 10 bits wide parts.extend([_b32tab[c1 >> 11], # bits 1 - 5 _b32tab[(c1 >> 6) & 0x1f], # bits 6 - 10 _b32tab[(c1 >> 1) & 0x1f], # bits 11 - 15 _b32tab[c2 >> 12], # bits 16 - 20 (1 - 5) _b32tab[(c2 >> 7) & 0x1f], # bits 21 - 25 (6 - 10) _b32tab[(c2 >> 2) & 0x1f], # bits 26 - 30 (11 - 15) _b32tab[c3 >> 5], # bits 31 - 35 (1 - 5) _b32tab[c3 & 0x1f], # bits 36 - 40 (1 - 5) ]) encoded = EMPTYSTRING.join(parts) # Adjust for any leftover partial quanta if leftover == 1: return encoded[:-6] + '======' elif leftover == 2: return encoded[:-4] + '====' elif leftover == 3: return encoded[:-3] + '===' elif leftover == 4: return encoded[:-1] + '=' return encoded def b32decode(s, casefold=False, map01=None): """Decode a Base32 encoded string. s is the string to decode. Optional casefold is a flag specifying whether a lowercase alphabet is acceptable as input. For security purposes, the default is False. RFC 3548 allows for optional mapping of the digit 0 (zero) to the letter O (oh), and for optional mapping of the digit 1 (one) to either the letter I (eye) or letter L (el). The optional argument map01 when not None, specifies which letter the digit 1 should be mapped to (when map01 is not None, the digit 0 is always mapped to the letter O). For security purposes the default is None, so that 0 and 1 are not allowed in the input. The decoded string is returned. A TypeError is raised if s were incorrectly padded or if there are non-alphabet characters present in the string. """ quanta, leftover = divmod(len(s), 8) if leftover: raise TypeError('Incorrect padding') # Handle section 2.4 zero and one mapping. The flag map01 will be either # False, or the character to map the digit 1 (one) to. It should be # either L (el) or I (eye). if map01: s = _translate(s, {'0': 'O', '1': map01}) if casefold: s = s.upper() # Strip off pad characters from the right. We need to count the pad # characters because this will tell us how many null bytes to remove from # the end of the decoded string. padchars = 0 mo = re.search('(?P<pad>[=]*)$', s) if mo: padchars = len(mo.group('pad')) if padchars > 0: s = s[:-padchars] # Now decode the full quanta parts = [] acc = 0 shift = 35 for c in s: val = _b32rev.get(c) if val is None: raise TypeError('Non-base32 digit found') acc += _b32rev[c] << shift shift -= 5 if shift < 0: parts.append(binascii.unhexlify(hex(acc)[2:-1])) acc = 0 shift = 35 # Process the last, partial quanta last = binascii.unhexlify(hex(acc)[2:-1]) if padchars == 1: last = last[:-1] elif padchars == 3: last = last[:-2] elif padchars == 4: last = last[:-3] elif padchars == 6: last = last[:-4] elif padchars != 0: raise TypeError('Incorrect padding') parts.append(last) return EMPTYSTRING.join(parts) # RFC 3548, Base 16 Alphabet specifies uppercase, but hexlify() returns # lowercase. The RFC also recommends against accepting input case # insensitively. def b16encode(s): """Encode a string using Base16. s is the string to encode. The encoded string is returned. """ return binascii.hexlify(s).upper() def b16decode(s, casefold=False): """Decode a Base16 encoded string. s is the string to decode. Optional casefold is a flag specifying whether a lowercase alphabet is acceptable as input. For security purposes, the default is False. The decoded string is returned. A TypeError is raised if s were incorrectly padded or if there are non-alphabet characters present in the string. """ if casefold: s = s.upper() if re.search('[^0-9A-F]', s): raise TypeError('Non-base16 digit found') return binascii.unhexlify(s) # Legacy interface. This code could be cleaned up since I don't believe # binascii has any line length limitations. It just doesn't seem worth it # though. MAXLINESIZE = 76 # Excluding the CRLF MAXBINSIZE = (MAXLINESIZE//4)*3 def encode(input, output): """Encode a file.""" while True: s = input.read(MAXBINSIZE) if not s: break while len(s) < MAXBINSIZE: ns = input.read(MAXBINSIZE-len(s)) if not ns: break s += ns line = binascii.b2a_base64(s) output.write(line) def decode(input, output): """Decode a file.""" while True: line = input.readline() if not line: break s = binascii.a2b_base64(line) output.write(s) def encodestring(s): """Encode a string.""" pieces = [] for i in range(0, len(s), MAXBINSIZE): chunk = s[i : i + MAXBINSIZE] pieces.append(binascii.b2a_base64(chunk)) return "".join(pieces) def decodestring(s): """Decode a string.""" return binascii.a2b_base64(s) # Useable as a script... def test(): """Small test program""" import sys, getopt try: opts, args = getopt.getopt(sys.argv[1:], 'deut') except getopt.error as msg: sys.stdout = sys.stderr print(msg) print("""usage: %s [-d|-e|-u|-t] [file|-] -d, -u: decode -e: encode (default) -t: encode and decode string 'Aladdin:open sesame'"""%sys.argv[0]) sys.exit(2) func = encode for o, a in opts: if o == '-e': func = encode if o == '-d': func = decode if o == '-u': func = decode if o == '-t': test1(); return if args and args[0] != '-': func(open(args[0], 'rb'), sys.stdout) else: func(sys.stdin, sys.stdout) def test1(): s0 = "Aladdin:open sesame" s1 = encodestring(s0) s2 = decodestring(s1) print(s0, repr(s1), s2) if __name__ == '__main__': test()I tried to fix the errors as follows:
Error 1:
Error: from string import join
ImportError: cannot import name 'join'
Affected code is:def _expand_key(key, clen): blocks = (clen+19)/20 xkey=[] seed=key for i in range(blocks): seed=hashlib.sha224(key+seed).digest() xkey.append(seed) j = join(xkey,'') return array (uint32, j)Fixed as:
j = ''.join(xkey)Is that correct?
Error 2:
Error: def _hash(str): return hashlib.sha224(str).digest()
TypeError: Unicode-objects must be encoded before hashing
Fixed as:def _hash(str): return hashlib.sha224(str.encode()).digest()Is that correct?
Error 3:
Error: from string import translate
ImportError: cannot import name 'translate'
from string import translate 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 hashlib.sha224(ko+hashlib.sha224(ki+msg).digest()).digest()How do I fix this?
Error 4:
Error: _state = 'X'+_state
TypeError: Can't convert 'bytes' object to str implicitly
Fixed as:_state = 'X' + str(_state)Is that correct?
Error 5:
Error: nonce = H(','.join(nlist))[:_ivlen]
TypeError: sequence item 2: expected str instance, bytes found
Fixed as:nonce = H(','.join(str(nlist)))[:_ivlen]]Is that correct?
Error 6:
Error: stream = array(uint32, plain+'0000'[n&3:])
TypeError: cannot use a str to initialize an array with typecode 'I'
How do I fix this?Please help me check if I have fixed those errors correctly and for those that I don't know how, please suggest a fix.
Thank you very much in anticipation
