From 129e271578a811532b31d245f8f9bc820f08add0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pi=C3=B1a?= Date: Tue, 9 Oct 2018 21:20:07 +0200 Subject: [PATCH 1/3] Gitignore update Added venv folder, which I use for testing --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7e99e36..b664ab4 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -*.pyc \ No newline at end of file +*.pyc +venv/ \ No newline at end of file From 53d1a9e792fde39d51d2880237d340326eced64a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pi=C3=B1a?= Date: Thu, 11 Oct 2018 20:20:57 +0200 Subject: [PATCH 2/3] ENCRYPTION ADDED Various changes made to introduce ".wallet" files (with encryption mode) --- .gitignore | 3 +- simpleCoin/testing_01.wallet | 1 + simpleCoin/testing_02.wallet | 1 + simpleCoin/wallet.py | 88 ++++++++++++++++++++++++++++++++++-- 4 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 simpleCoin/testing_01.wallet create mode 100644 simpleCoin/testing_02.wallet diff --git a/.gitignore b/.gitignore index b664ab4..ed33af8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.pyc -venv/ \ No newline at end of file +venv/ +.vscode/ \ No newline at end of file diff --git a/simpleCoin/testing_01.wallet b/simpleCoin/testing_01.wallet new file mode 100644 index 0000000..2457183 --- /dev/null +++ b/simpleCoin/testing_01.wallet @@ -0,0 +1 @@ +{"public_key": "DR44wPNm7Q0vqrykROoVH0XK5+66JYgfeTP2Y8B+QUNeb01EsfHqEeyH+2dVyrD500CMv+mk5p1kmhQP83pI5A==", "private_key": "a9be813f976686691bad8294242c02ec23933a5bed2dde37125f486aee271e1c"} \ No newline at end of file diff --git a/simpleCoin/testing_02.wallet b/simpleCoin/testing_02.wallet new file mode 100644 index 0000000..4752e06 --- /dev/null +++ b/simpleCoin/testing_02.wallet @@ -0,0 +1 @@ +ENCRYPTED:gAAAAABbv4tsv6YCuPLDNcjAfXA6ruJqkIyVDHVytDQqlP45vYpzwSu6UJNlQZlJJUMNC413lbPPAegJQfBJtOU-k6K4DMxqMOoZF7DQwGAEzHgXvnbsnS0z3Rh44DK_oH75nhZ4eZ6Gu3YfmWq1IhtHq5kjNeOnfzXVCtYHrPm99fchVkOlK8Zx0VxIB0thyFFLwsm4sbK6avR1ASyaPOvbNrkpZXQs2CuCt_fv8eIejfz71nRFO1uiygnvzuN_XHUGk8QIp_w_X6aFGVUqHvzxsjd4_dhaxvDnIbJa0my3ndIN07FyJ3MDcLIGiKEfn0atob8ei8By \ No newline at end of file diff --git a/simpleCoin/wallet.py b/simpleCoin/wallet.py index 8f3aec7..de376d0 100644 --- a/simpleCoin/wallet.py +++ b/simpleCoin/wallet.py @@ -22,6 +22,10 @@ import time import base64 import ecdsa +from cryptography.fernet import Fernet, InvalidToken +from hashlib import md5 +from json import loads, dumps +import os def wallet(): @@ -38,8 +42,32 @@ def wallet(): =========================================\n""") generate_ECDSA_keys() elif response == "2": - addr_from = input("From: introduce your wallet address (public key)\n") - private_key = input("Introduce your private key\n") + files_in_directory = []# All files with .wallet extension in the current directory + for file in os.listdir("./"): + if file.endswith(".wallet"): + files_in_directory.append(file)# Add all wallet files found + + if len(files_in_directory) == 0: + # If there's not any wallet files, the 'manual' process is used + addr_from = input("From: introduce your wallet address (public key)\n") + private_key = input("Introduce your private key\n") + elif len(files_in_directory) == 1: + wallet = get_data_from_file(files_in_directory[0]) + addr_from, private_key = wallet["public_key"], wallet["private_key"] + elif len(files_in_directory) > 1: + print("Various wallets detected:") + for i in files_in_directory: + print(i) + while True: + wallet_file = input("Which one do you want to use?: ") + try: + wallet = get_data_from_file(wallet_file) + break + except InvalidToken: + print("There was an error decrypting the file.\nEither the password is not correct or the file is corrupted.") + except FileNotFoundError: + print("There was an error finding the file.") + addr_from, private_key = wallet["public_key"], wallet["private_key"] addr_to = input("To: introduce destination wallet address\n") amount = input("Amount: number stating how much do you want to send\n") print("=========================================\n\n") @@ -51,6 +79,26 @@ def wallet(): else: # Will always occur when response == 3. check_transactions() +def get_data_from_file(wallet_file): + """Gets from a .wallet file the following wallet object: + + { + "public_key":"publicKey", + "private_key":"privateKey" + }""" + with open(wallet_file, "r") as f: + content = f.read()# Gets the content of the .wallet file + f.close() + if content[0:10] == "ENCRYPTED:":# If the key is encrypted + password = input("The wallet file detected is encrypted. Please, input the password: ") + key = gen_encryption_key(password)# Get the password key + f = Fernet(key)# Create the decryption object with the key + # Decrypt the json content, (after 'ENCRYPTED:') and loads it into a python object + wallet = loads( f.decrypt( content[9:].encode() ).decode() ) + else:# If not, just loads the json object + print("Not-encrypted wallet file detected.") + wallet = loads(content) + return wallet def send_transaction(addr_from, private_key, addr_to, amount): """Sends your transaction to different nodes. Once any of the nodes manage @@ -88,6 +136,14 @@ def check_transactions(): res = requests.get('http://localhost:5000/blocks') print(res.text) +def gen_encryption_key(password): + """A plain text password can't be used for encrpting or decrypting with Fernet. + This function returns a 32 bit url-safe base64 encoded key version of the password. + This key is valid for encrypting and decrypting.""" + h = md5() + h.update(password.encode()) + return base64.urlsafe_b64encode(h.hexdigest().encode()) + # Now it's ready to use. def generate_ECDSA_keys(): """This function takes care of creating your private and public (your address) keys. @@ -104,9 +160,31 @@ def generate_ECDSA_keys(): #we are going to encode the public key to make it shorter public_key = base64.b64encode(bytes.fromhex(public_key)) - filename = input("Write the name of your new address: ") + ".txt" - with open(filename, "w") as f: - f.write("Private key: {0}\nWallet address / Public key: {1}".format(private_key, public_key.decode())) + # The private and public key are assembled into a dictionary. + # Dumping and loading this object with json format will make + # them easier to manage. + content = {"public_key":public_key.decode(), "private_key":private_key} + + filename = input("Write the name of your new address: ") + ".wallet" + password = input(""" +Write a password to encript the new wallet file. +Protecting your file with a password prevents your private key for being +stolen by someone that could have access to the wallet file. +Leave in blank to not use any password. (NOT RECOMMENDED) + +Password: """) + + if password != "": + key = gen_encryption_key(password)# Get the key version of the password + f = Fernet(key)# Create encryption object with the key version of the password + content = f.encrypt(dumps(content).encode())# Use it to encrypt the wallet file + with open(filename, "w") as f: + # The encrypted key is written in the file after a 'ENCRYPTED:' tag. + # This tag is used to make the program know that this key requires a password. + f.write("ENCRYPTED:" + content.decode()) + else: + with open(filename, "w") as f: + f.write(dumps(content)) print("Your new address and private key are now in the file {0}".format(filename)) def sign_ECDSA_msg(private_key): From 14e02d0e3aa73136b78b4b0b376e44f11c333e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pi=C3=B1a?= Date: Thu, 11 Oct 2018 22:22:21 +0200 Subject: [PATCH 3/3] ENCRYPTION Changed a little the encription method and removed testing addresses --- simpleCoin/testing_01.wallet | 1 - simpleCoin/testing_02.wallet | 1 - simpleCoin/wallet.py | 27 +++++++++++++-------------- 3 files changed, 13 insertions(+), 16 deletions(-) delete mode 100644 simpleCoin/testing_01.wallet delete mode 100644 simpleCoin/testing_02.wallet diff --git a/simpleCoin/testing_01.wallet b/simpleCoin/testing_01.wallet deleted file mode 100644 index 2457183..0000000 --- a/simpleCoin/testing_01.wallet +++ /dev/null @@ -1 +0,0 @@ -{"public_key": "DR44wPNm7Q0vqrykROoVH0XK5+66JYgfeTP2Y8B+QUNeb01EsfHqEeyH+2dVyrD500CMv+mk5p1kmhQP83pI5A==", "private_key": "a9be813f976686691bad8294242c02ec23933a5bed2dde37125f486aee271e1c"} \ No newline at end of file diff --git a/simpleCoin/testing_02.wallet b/simpleCoin/testing_02.wallet deleted file mode 100644 index 4752e06..0000000 --- a/simpleCoin/testing_02.wallet +++ /dev/null @@ -1 +0,0 @@ -ENCRYPTED:gAAAAABbv4tsv6YCuPLDNcjAfXA6ruJqkIyVDHVytDQqlP45vYpzwSu6UJNlQZlJJUMNC413lbPPAegJQfBJtOU-k6K4DMxqMOoZF7DQwGAEzHgXvnbsnS0z3Rh44DK_oH75nhZ4eZ6Gu3YfmWq1IhtHq5kjNeOnfzXVCtYHrPm99fchVkOlK8Zx0VxIB0thyFFLwsm4sbK6avR1ASyaPOvbNrkpZXQs2CuCt_fv8eIejfz71nRFO1uiygnvzuN_XHUGk8QIp_w_X6aFGVUqHvzxsjd4_dhaxvDnIbJa0my3ndIN07FyJ3MDcLIGiKEfn0atob8ei8By \ No newline at end of file diff --git a/simpleCoin/wallet.py b/simpleCoin/wallet.py index de376d0..5df7019 100644 --- a/simpleCoin/wallet.py +++ b/simpleCoin/wallet.py @@ -64,9 +64,10 @@ def wallet(): wallet = get_data_from_file(wallet_file) break except InvalidToken: - print("There was an error decrypting the file.\nEither the password is not correct or the file is corrupted.") + print("There was an error decrypting the private key.\nEither the password is not correct or the file is corrupted.") except FileNotFoundError: print("There was an error finding the file.") + addr_from, private_key = wallet["public_key"], wallet["private_key"] addr_to = input("To: introduce destination wallet address\n") amount = input("Amount: number stating how much do you want to send\n") @@ -84,21 +85,20 @@ def get_data_from_file(wallet_file): { "public_key":"publicKey", - "private_key":"privateKey" + "private_key":"privateKey", + "encryption":True or False }""" with open(wallet_file, "r") as f: - content = f.read()# Gets the content of the .wallet file + content = loads(f.read())# Gets the content of the .wallet file f.close() - if content[0:10] == "ENCRYPTED:":# If the key is encrypted - password = input("The wallet file detected is encrypted. Please, input the password: ") + if content["encryption"]:# If the private key is encrypted + password = input("The wallet file detected has been encrypted. Please, input the password: ") key = gen_encryption_key(password)# Get the password key f = Fernet(key)# Create the decryption object with the key - # Decrypt the json content, (after 'ENCRYPTED:') and loads it into a python object - wallet = loads( f.decrypt( content[9:].encode() ).decode() ) + content["private_key"] = f.decrypt( content["private_key"].encode() ).decode() else:# If not, just loads the json object print("Not-encrypted wallet file detected.") - wallet = loads(content) - return wallet + return content def send_transaction(addr_from, private_key, addr_to, amount): """Sends your transaction to different nodes. Once any of the nodes manage @@ -163,7 +163,7 @@ def generate_ECDSA_keys(): # The private and public key are assembled into a dictionary. # Dumping and loading this object with json format will make # them easier to manage. - content = {"public_key":public_key.decode(), "private_key":private_key} + content = {"public_key":public_key.decode(), "private_key":private_key, "encryption":False} filename = input("Write the name of your new address: ") + ".wallet" password = input(""" @@ -177,11 +177,10 @@ def generate_ECDSA_keys(): if password != "": key = gen_encryption_key(password)# Get the key version of the password f = Fernet(key)# Create encryption object with the key version of the password - content = f.encrypt(dumps(content).encode())# Use it to encrypt the wallet file + content["private_key"] = f.encrypt(content["private_key"].encode()).decode()# Use it to encrypt the private key + content["encryption"] = True# Make the program know that this file requires a password. with open(filename, "w") as f: - # The encrypted key is written in the file after a 'ENCRYPTED:' tag. - # This tag is used to make the program know that this key requires a password. - f.write("ENCRYPTED:" + content.decode()) + f.write(dumps(content)) else: with open(filename, "w") as f: f.write(dumps(content))