p3lib 1.1.100__py3-none-any.whl → 1.1.101__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
p3lib/file_io.py ADDED
@@ -0,0 +1,154 @@
1
+ import json
2
+ import os
3
+ from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
4
+ from cryptography.hazmat.primitives.hashes import SHA256
5
+ from cryptography.hazmat.backends import default_backend
6
+ from cryptography.fernet import Fernet
7
+ from base64 import urlsafe_b64encode
8
+
9
+ class CryptFile(object):
10
+ """@brief Responsible for encrypting and decrypting data to/from files using a password."""
11
+
12
+ def __init__(self,
13
+ filename: str,
14
+ password: str,
15
+ add_enc_extension: bool = True,
16
+ dict_data: bool = True):
17
+ """@brief Constructor
18
+ @param filename The filename to save the data into.
19
+ @param password The password to used encrypt data to and load encrypted data from file.
20
+ @param add_enc_extension If True then the .enc extension is added to the filename
21
+ supplied.
22
+ @param dict_data If True the data is a python dictionary."""
23
+ self._filename = filename
24
+ self._password = password
25
+ self._add_enc_extension = add_enc_extension
26
+ self._dict_data = dict_data
27
+
28
+ if not self._filename:
29
+ raise Exception("No filename defined to save data to.")
30
+
31
+ if len(self._filename) < 1:
32
+ raise Exception("No filename defined. String length = 0.")
33
+
34
+ if not self._password:
35
+ raise Exception("No password defined to encrypt/decrypt data.")
36
+
37
+ if len(self._password) < 1:
38
+ raise Exception("No password defined. String length = 0.")
39
+
40
+ self._add_extension()
41
+
42
+ def save(self,
43
+ data):
44
+ """@brief Save the data to an encrypted file.
45
+ @param data The data to be encrypted.
46
+ """
47
+ encrypted_data = self._encrypt_data(data)
48
+ with open(self._filename, "wb") as file:
49
+ file.write(encrypted_data)
50
+
51
+ def load(self):
52
+ """@brief Load data from an encrypted file.
53
+ @return The decrypted data.
54
+ """
55
+ with open(self._filename, "rb") as file:
56
+ data_bytes = file.read()
57
+ return self._decrypt_data(data_bytes)
58
+
59
+ def _decrypt_data(self, encrypted_data):
60
+ # Extract the salt (first 16 bytes) from the encrypted data
61
+ salt = encrypted_data[:16]
62
+ encrypted_content = encrypted_data[16:]
63
+ key = self._derive_key_from_password(salt)
64
+ fernet = Fernet(key)
65
+ decrypted_data = fernet.decrypt(encrypted_content)
66
+ if self._dict_data:
67
+ # Convert bytes back to a dict
68
+ data = json.loads(decrypted_data.decode())
69
+
70
+ else:
71
+ data = decrypted_data
72
+
73
+ return data
74
+
75
+ def get_file(self):
76
+ """@return Get the name of the encrypted file."""
77
+ return self._filename
78
+
79
+ def _add_extension(self):
80
+ """@brief Add the enc extension to the filename if required."""
81
+ if self._add_enc_extension and self._filename and not self._filename.endswith('.enc') :
82
+ self._filename = self._filename + ".enc"
83
+
84
+ def _derive_key_from_password(self,
85
+ salt: bytes) -> bytes:
86
+ kdf = PBKDF2HMAC(
87
+ algorithm=SHA256(),
88
+ length=32,
89
+ salt=salt,
90
+ iterations=100_000,
91
+ backend=default_backend(),
92
+ )
93
+ return urlsafe_b64encode(kdf.derive(self._password.encode()))
94
+
95
+ def _encrypt_data(self,
96
+ data):
97
+ # Generate a random salt for key derivation
98
+ salt = os.urandom(16)
99
+ key = self._derive_key_from_password(salt)
100
+ fernet = Fernet(key)
101
+ # If we expect a dict
102
+ if self._dict_data:
103
+ data_bytes = json.dumps(data).encode() # Convert JSON to bytes
104
+
105
+ # else check we have bytes
106
+ elif isinstance(data, bytes):
107
+ data_bytes = data
108
+
109
+ else:
110
+ raise Exception("data to be stored is not a bytes instance.")
111
+
112
+ encrypted_data = fernet.encrypt(data_bytes)
113
+ return salt + encrypted_data # Store the salt with the encrypted data
114
+
115
+ # Example usage
116
+ if __name__ == "__main__":
117
+
118
+ password = input("Enter a password for encryption: ")
119
+
120
+ # JSON data to encrypt
121
+ json_data = {
122
+ "name": "Alice",
123
+ "age": 30,
124
+ "is_admin": True,
125
+ "preferences": {
126
+ "theme": "dark",
127
+ "language": "English"
128
+ }
129
+ }
130
+
131
+ filename = "afile.txt"
132
+
133
+ # Save and load a python dict
134
+ cjf = CryptFile(filename=filename,
135
+ password=password)
136
+ cjf.save(json_data)
137
+ print(f"Saved {cjf.get_file()}")
138
+
139
+ decrypted_data = cjf.load()
140
+ print(f"Decrypted data: {decrypted_data}")
141
+
142
+
143
+ # Save and load data bytes
144
+ data_bytes = "123".encode()
145
+ cjf = CryptFile(filename=filename,
146
+ password=password,
147
+ dict_data=False)
148
+ cjf.save(data_bytes)
149
+ print(f"Saved {cjf.get_file()}")
150
+
151
+ decrypted_data = cjf.load()
152
+ print("Decrypted data:")
153
+ for _byte in decrypted_data:
154
+ print(f"_byte={_byte}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: p3lib
3
- Version: 1.1.100
3
+ Version: 1.1.101
4
4
  Summary: A group of python modules for networking, plotting data, config storage, automating boot scripts, ssh access and user input output.
5
5
  Home-page: https://github.com/pjaos/p3lib
6
6
  Author: Paul Austen
@@ -5,6 +5,7 @@ p3lib/bokeh_gui.py,sha256=55sajP_x9O1lE0uP3w3-T5f2oMzk7jSolLqxlEdLeLg,40245
5
5
  p3lib/boot_manager.py,sha256=l7WlaoIRt4cu2jAdCs3FnDeNO2v2jzqideNZ3qg2r_4,19652
6
6
  p3lib/conduit.py,sha256=jPkjdtyCx2I6SFqcEo8y2g7rgnZ-jNY7oCuYIETzT5Q,6046
7
7
  p3lib/database_if.py,sha256=XKu1w3zftGbj4Rh54wrWJnoCtqHkhCzJUPN2S70XIKg,11915
8
+ p3lib/file_io.py,sha256=A7_GKYPlmjRjq6U1YuWhmB0OhLhNm6cWQfQX8qfgYTk,5041
8
9
  p3lib/helper.py,sha256=xTKPgpziwr4zyaoc0sjZRFr0M91fo7Tok_nSAvtiTZE,12020
9
10
  p3lib/json_networking.py,sha256=6u4s1SmypjTYPnSxHP712OgQ3ZJaxOqIkgHQ1J7Qews,9738
10
11
  p3lib/mqtt_rpc.py,sha256=6LmFA1kR4HSJs9eWbOJORRHNY01L_lHWjvtE2fmY8P8,10511
@@ -15,8 +16,8 @@ p3lib/pconfig.py,sha256=2yZUK5nkqpAm4Y_xcJq5H9Lxmc8dfYei1Pi0Ek2Crh0,35376
15
16
  p3lib/ssh.py,sha256=OyoAQ_h1L2RfkjTAChDrvLFfl4Fe_gBNdX5rvK-wKiw,42125
16
17
  p3lib/table_plot.py,sha256=RPncwVlGUkkx5Fw0dHQedXo0TSPlTi__VrJBDzaMsuI,32116
17
18
  p3lib/uio.py,sha256=Aaxc99XiE3d2f9vLjaN-bZsckoNxay5t0ujdK6PXGrw,23265
18
- p3lib-1.1.100.dist-info/LICENSE,sha256=igqTy5u0kVWM1n-NUZMvAlinY6lVjAXKoag0okkS8V8,1067
19
- p3lib-1.1.100.dist-info/METADATA,sha256=z6-lX_HWH1ILG4DcC_z6OssgJQwXN6lhfDplHVAERog,919
20
- p3lib-1.1.100.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
21
- p3lib-1.1.100.dist-info/top_level.txt,sha256=SDCpXYh-19yCFp4Z8ZK4B-3J4NvTCJElZ42NPgcR6-U,6
22
- p3lib-1.1.100.dist-info/RECORD,,
19
+ p3lib-1.1.101.dist-info/LICENSE,sha256=igqTy5u0kVWM1n-NUZMvAlinY6lVjAXKoag0okkS8V8,1067
20
+ p3lib-1.1.101.dist-info/METADATA,sha256=gdbF0zh48zjUc6LXovhTgsfcFldo1mzLJBClcS9iJL4,919
21
+ p3lib-1.1.101.dist-info/WHEEL,sha256=A3WOREP4zgxI0fKrHUG8DC8013e3dK3n7a6HDbcEIwE,91
22
+ p3lib-1.1.101.dist-info/top_level.txt,sha256=SDCpXYh-19yCFp4Z8ZK4B-3J4NvTCJElZ42NPgcR6-U,6
23
+ p3lib-1.1.101.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (75.7.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5