Skip to content

Commit c8928c2

Browse files
committed
update file encryption tutorial to add encryption with password
1 parent 823f0aa commit c8928c2

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import cryptography
2+
from cryptography.fernet import Fernet
3+
from cryptography.hazmat.primitives.kdf.scrypt import Scrypt
4+
5+
import secrets
6+
import base64
7+
import getpass
8+
9+
10+
def generate_salt(size=16):
11+
"""Generate the salt used for key derivation,
12+
`size` is the length of the salt to generate"""
13+
return secrets.token_bytes(size)
14+
15+
16+
def derive_key(salt, password):
17+
"""Derive the key from the `password` using the passed `salt`"""
18+
kdf = Scrypt(salt=salt, length=32, n=2**14, r=8, p=1)
19+
return kdf.derive(password.encode())
20+
21+
22+
def load_salt():
23+
# load salt from salt.salt file
24+
return open("salt.salt", "rb").read()
25+
26+
27+
def generate_key(password, salt_size=16, load_existing_salt=False, save_salt=True):
28+
"""
29+
Generates a key from a `password` and the salt.
30+
If `load_existing_salt` is True, it'll load the salt from a file
31+
in the current directory called "salt.salt".
32+
If `save_salt` is True, then it will generate a new salt
33+
and save it to "salt.salt"
34+
"""
35+
if load_existing_salt:
36+
# load existing salt
37+
salt = load_salt()
38+
elif save_salt:
39+
# generate new salt and save it
40+
salt = generate_salt(salt_size)
41+
with open("salt.salt", "wb") as salt_file:
42+
salt_file.write(salt)
43+
# generate the key from the salt and the password
44+
derived_key = derive_key(salt, password)
45+
# encode it using Base 64 and return it
46+
return base64.urlsafe_b64encode(derived_key)
47+
48+
49+
def encrypt(filename, key):
50+
"""
51+
Given a filename (str) and key (bytes), it encrypts the file and write it
52+
"""
53+
f = Fernet(key)
54+
with open(filename, "rb") as file:
55+
# read all file data
56+
file_data = file.read()
57+
# encrypt data
58+
encrypted_data = f.encrypt(file_data)
59+
# write the encrypted file
60+
with open(filename, "wb") as file:
61+
file.write(encrypted_data)
62+
63+
64+
def decrypt(filename, key):
65+
"""
66+
Given a filename (str) and key (bytes), it decrypts the file and write it
67+
"""
68+
f = Fernet(key)
69+
with open(filename, "rb") as file:
70+
# read the encrypted data
71+
encrypted_data = file.read()
72+
# decrypt data
73+
try:
74+
decrypted_data = f.decrypt(encrypted_data)
75+
except cryptography.fernet.InvalidToken:
76+
print("Invalid token, most likely the password is incorrect")
77+
return
78+
# write the original file
79+
with open(filename, "wb") as file:
80+
file.write(decrypted_data)
81+
print("File decrypted successfully")
82+
83+
84+
if __name__ == "__main__":
85+
import argparse
86+
parser = argparse.ArgumentParser(description="File Encryptor Script with a Password")
87+
parser.add_argument("file", help="File to encrypt/decrypt")
88+
parser.add_argument("-s", "--salt-size", help="If this is set, a new salt with the passed size is generated",
89+
type=int)
90+
parser.add_argument("-e", "--encrypt", action="store_true",
91+
help="Whether to encrypt the file, only -e or -d can be specified.")
92+
parser.add_argument("-d", "--decrypt", action="store_true",
93+
help="Whether to decrypt the file, only -e or -d can be specified.")
94+
95+
args = parser.parse_args()
96+
file = args.file
97+
98+
if args.encrypt:
99+
password = getpass.getpass("Enter the password for encryption: ")
100+
elif args.decrypt:
101+
password = getpass.getpass("Enter the password you used for encryption: ")
102+
103+
if args.salt_size:
104+
key = generate_key(password, salt_size=args.salt_size, save_salt=True)
105+
else:
106+
key = generate_key(password, load_existing_salt=True)
107+
108+
encrypt_ = args.encrypt
109+
decrypt_ = args.decrypt
110+
111+
if encrypt_ and decrypt_:
112+
raise TypeError("Please specify whether you want to encrypt the file or decrypt it.")
113+
elif encrypt_:
114+
encrypt(file, key)
115+
elif decrypt_:
116+
decrypt(file, key)
117+
else:
118+
raise TypeError("Please specify whether you want to encrypt the file or decrypt it.")
119+
120+
121+
122+
123+
124+

0 commit comments

Comments
 (0)