11import base64
22import os
3+ from traceback import print_exc
34import re
45from getpass import getpass
56from .settings import Settings
67from .message import print_err
8+ from .pyaes import AESModeOfOperationCTR
79
810
911EXTRA_STR = 'ENCo0D#DT{xTCh$cKe>'
1012ENCODED_IDF = '=*=EnC0d3dH3aDer==*'
13+ EXTRA_STR_2 = '3NCo0D#DT{xTCh$cKe>'
14+ ENCODED_IDF_2 = '=*=3nC0d3dH3aDer==*'
1115
1216# Vigenere's Cipher: http://stackoverflow.com/a/38223403
1317
14- def encode (key , clear ):
18+ def encode_1 (key , clear ):
1519 if clear .startswith (ENCODED_IDF ): # already encoded, no need to encode
1620 return clear
1721 clear += EXTRA_STR # used to check if decrypt is correct
@@ -24,7 +28,7 @@ def encode(key, clear):
2428 return ENCODED_IDF + base64 .urlsafe_b64encode ("" .join (enc ).encode ()).decode ()
2529
2630
27- def decode (key , enc ):
31+ def decode_1 (key , enc ):
2832 st = ''
2933 if not enc .startswith (ENCODED_IDF ): # not encoded, so not decode
3034 return enc
@@ -44,6 +48,40 @@ def decode(key, enc):
4448 return st [:- 1 * len (EXTRA_STR )]
4549
4650
51+ def encode (key , clear ):
52+ if clear .startswith (ENCODED_IDF ) or clear .startswith (ENCODED_IDF_2 ): # already encoded, no need to encode
53+ return clear
54+ clear += EXTRA_STR_2 # used to check if decrypt is correct
55+ # encrypt string
56+ aes = AESModeOfOperationCTR (key_32 (key ))
57+ clear = bytes (clear , 'utf8' ) # everyone writes in utf8
58+ ciphertext = aes .encrypt (clear )
59+ return ENCODED_IDF_2 + base64 .urlsafe_b64encode (ciphertext ).decode ('iso-8859-1' )
60+
61+
62+ def decode (key , enc ):
63+ st = ''
64+ if not (enc .startswith (ENCODED_IDF_2 ) or enc .startswith (ENCODED_IDF )): # not encoded, so not decode
65+ return enc
66+ if enc .startswith (ENCODED_IDF ): # old version
67+ return decode_1 (key , enc )
68+ # new version
69+ enc = enc [len (ENCODED_IDF_2 ):] # trim out idf
70+ # https://wiki.python.org/moin/Python3UnicodeDecodeError
71+ # seems like the bytes created by pyaes are best decrypted using it
72+ enc = base64 .urlsafe_b64decode (enc ).decode ('iso-8859-1' )
73+ # decode string
74+ aes = AESModeOfOperationCTR (key_32 (key ))
75+ st = aes .decrypt (enc )
76+ st = st .decode ('utf8' ) # because utf8 is what everyone uses
77+ # ^^ decode error might be returned even when password is wrong
78+ # check if correctly decoded
79+ if not st .endswith (EXTRA_STR_2 ):
80+ return None
81+ else :
82+ return st [:- 1 * len (EXTRA_STR_2 )]
83+
84+
4785def get_file_list ():
4886 listFiles = []
4987 sts = Settings ()
@@ -71,11 +109,15 @@ def update_file(funcptr, flist, key):
71109 data = fptr .read ()
72110 fptr .close ()
73111 fptr = open (file , 'w' )
74- newData = funcptr (key , data )
112+ try :
113+ newData = funcptr (key , data )
114+ except Exception :
115+ print_exc ()
116+ newData = None # handled sufficiently well now
75117 if newData is None :
76118 newData = data
77119 failed = True
78- print_err ('Failed decrypting %s' % file )
120+ print_err ('Failed processing %s' % file )
79121 fptr .write (newData )
80122 fptr .close ()
81123 # check if failed
@@ -89,3 +131,11 @@ def get_key():
89131 while key == '' :
90132 key = getpass ('Enter key > ' )
91133 return key
134+
135+
136+ def key_32 (key ):
137+ if len (key ) > 32 :
138+ key = key [:32 ]
139+ else :
140+ key = key + ('0' * (32 - len (key )))
141+ return bytes (key , 'utf8' )
0 commit comments