-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsfc.py
More file actions
68 lines (53 loc) · 2.02 KB
/
sfc.py
File metadata and controls
68 lines (53 loc) · 2.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
### SECURED FILE CONTAINER ###
import os, struct, zlib
from Crypto.Cipher import AES
from Crypto.Protocol.KDF import PBKDF2
from Crypto.Random import get_random_bytes
MAGIC = b'SFC'
def derive_key(password, salt):
return PBKDF2(password, salt, dkLen=32, count=100000)
def pad(data):
pad_len = 16 - len(data) % 16
return data + bytes([pad_len] * pad_len)
def unpad(data):
return data[:-data[-1]]
def encrypt(data, key):
iv = get_random_bytes(16)
cipher = AES.new(key, AES.MODE_CBC, iv)
return iv + cipher.encrypt(pad(data))
def decrypt(data, key):
iv, ct = data[:16], data[16:]
cipher = AES.new(key, AES.MODE_CBC, iv)
return unpad(cipher.decrypt(ct))
def pack_file(input_file, output_file, password):
salt = get_random_bytes(16)
key = derive_key(password.encode(), salt)
with open(input_file, 'rb') as f:
raw = f.read()
compressed = zlib.compress(raw)
encrypted = encrypt(compressed, key)
fname = os.path.basename(input_file).encode()
with open(output_file, 'wb') as out:
out.write(MAGIC)
out.write(salt)
out.write(struct.pack('<H', len(fname)))
out.write(fname)
out.write(struct.pack('<I', len(encrypted)))
out.write(encrypted)
def unpack_file(container, output_folder, password):
with open(container, 'rb') as f:
assert f.read(4) == MAGIC
salt = f.read(16)
key = derive_key(password.encode(), salt)
fname_len = struct.unpack('<H', f.read(2))[0]
fname = f.read(fname_len).decode()
data_len = struct.unpack('<I', f.read(4))[0]
encrypted = f.read(data_len)
compressed = decrypt(encrypted, key)
raw = zlib.decompress(compressed)
out_path = os.path.join(output_folder, fname)
with open(out_path, 'wb') as out:
out.write(raw)
# Example usage: or filename.sfc
pack_file("filename", "locked.sfc", "password")
# unpack_file("locked.sfc", "./output", "password")