From 0121490b0d290b822400d096661f1fb27188dcf3 Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Mon, 9 Oct 2017 00:01:13 -0600 Subject: [PATCH] Disallow old encryption protocol and format logging --- crypt.py | 29 ++++++++++++++++++++++------- sn_fuse.py | 9 --------- standardnotes_fs.py | 18 ++++++++++-------- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/crypt.py b/crypt.py index 7b4226b..9cf8b01 100644 --- a/crypt.py +++ b/crypt.py @@ -4,6 +4,7 @@ from binascii import hexlify, unhexlify from Crypto.Cipher import AES from Crypto.Random import random from copy import deepcopy +import sys class EncryptionHelper: def pure_generatePasswordAndKey(self, password, pw_salt, pw_cost): @@ -15,6 +16,7 @@ class EncryptionHelper: pw = output[0 : split_length] mk = output[split_length : split_length * 2] ak = output[split_length * 2 : split_length * 3] + return dict(pw=pw, mk=mk, ak=ak) def encryptDirtyItems(self, dirty_items, keys): @@ -36,6 +38,7 @@ class EncryptionHelper: enc_item = deepcopy(item) enc_item['content'] = self.pure_encryptString002(content, item_ek, item_ak, uuid) enc_item['enc_item_key'] = self.pure_encryptString002(item_key, keys['mk'], keys['ak'], uuid) + return enc_item def pure_decryptItem(self, item, keys): @@ -46,7 +49,13 @@ class EncryptionHelper: if not content: return item - if content[:3] == '002': + if content[:3] == '001': + print('Old encryption protocol detected. This version is not ' + 'supported by standardnotes-fs. Please resync all of ' + 'your notes by following the instructions here:\n' + 'https://standardnotes.org/help/resync') + sys.exit(1) + elif content[:3] == '002': item_key = self.pure_decryptString002(enc_item_key, keys['mk'], keys['ak'], uuid) item_key_length = len(item_key) item_ek = item_key[:item_key_length//2] @@ -54,10 +63,13 @@ class EncryptionHelper: dec_content = self.pure_decryptString002(content, item_ek, item_ak, uuid) else: - print('Invalid protocol version.') + print('Invalid protocol version. This could indicate tampering or ' + 'that something is wrong with the server. Exiting.') + sys.exit(1) dec_item = deepcopy(item) dec_item['content'] = json.loads(dec_content) + return dec_item def pure_encryptString002(self, string_to_encrypt, encryption_key, auth_key, uuid): @@ -87,19 +99,22 @@ class EncryptionHelper: ciphertext = components[4] if local_uuid != uuid: - print('UUID does not match.') - return + print('UUID does not match. This could indicate tampering or ' + 'that something is wrong with the server. Exiting.') + sys.exit(1) string_to_auth = ':'.join([version, uuid, IV, ciphertext]) local_auth_hash = hmac.new(unhexlify(auth_key), string_to_auth.encode(), 'sha256').digest() local_auth_hash = hexlify(local_auth_hash).decode() if local_auth_hash != auth_hash: - print('Message has been tampered with.') - return + print('Auth hash does not match. This could indicate tampering or ' + 'that something is wrong with the server. Exiting.') + sys.exit(1) cipher = AES.new(unhexlify(encryption_key), AES.MODE_CBC, unhexlify(IV)) result = cipher.decrypt(b64decode(ciphertext)) result = result[:-result[-1]] # remove PKCS#7 padding + result = result.decode() - return result.decode() + return result diff --git a/sn_fuse.py b/sn_fuse.py index b2e2c98..5720807 100644 --- a/sn_fuse.py +++ b/sn_fuse.py @@ -139,12 +139,3 @@ class StandardNotesFUSE(LoggingMixIn, Operations): def utimens(self, path, times=None): return 0 - -if __name__ == '__main__': - if len(argv) != 2: - print('usage: %s ' % argv[0]) - exit(1) - - logging.basicConfig(level=logging.DEBUG) - - fuse = FUSE(StandardNotesFUSE(), argv[1], foreground=True, nothreads=True) diff --git a/standardnotes_fs.py b/standardnotes_fs.py index 9ade603..cfb476c 100644 --- a/standardnotes_fs.py +++ b/standardnotes_fs.py @@ -53,11 +53,13 @@ def main(): # configure logging if args.verbosity == 1: - logging.basicConfig(level=logging.INFO) + log_level = logging.INFO elif args.verbosity == 2: - logging.basicConfig(level=logging.DEBUG) + log_level = logging.DEBUG else: - logging.basicConfig(level=logging.CRITICAL) + log_level = logging.CRITICAL + logging.basicConfig(level=log_level, + format='%(levelname)-8s: %(message)s') if args.verbosity: args.foreground = True config_file = args.config if args.config else CONFIG_FILE @@ -74,7 +76,7 @@ def main(): # make sure mountpoint is specified if not args.mountpoint: - logging.critical('No mountpoint specified.') + print('No mountpoint specified.') sys.exit(1) # load config file settings @@ -85,7 +87,7 @@ def main(): logging.info(log_msg % str(config_file.parent)) except OSError: log_msg = 'Error creating config file directory "%s".' - logging.critical(log_msg % str(config_file.parent)) + print(log_msg % str(config_file.parent)) sys.exit(1) try: @@ -130,7 +132,7 @@ def main(): login_success = True except: log_msg = 'Failed to log into account "%s".' - logging.critical(log_msg % username) + print(log_msg % username) login_success = False # write settings back if good, clear if not @@ -145,11 +147,11 @@ def main(): logging.info(log_msg % str(config_file)) else: log_msg = 'Clearing config file "%s".' - logging.info(log_msg % username) + logging.info(log_msg % config_file) config_file.chmod(0o600) except OSError: log_msg = 'Unable to write config file "%s".' - logging.error(log_msg % str(config_file)) + logging.warning(log_msg % str(config_file)) if login_success: logging.info('Starting FUSE filesystem.')