summaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'README.md')
-rw-r--r--README.md133
1 files changed, 114 insertions, 19 deletions
diff --git a/README.md b/README.md
index 6c58bdd..45c230a 100644
--- a/README.md
+++ b/README.md
@@ -69,12 +69,97 @@ for processes that were not spawned by that same *etoolkit* session.
69 # add sgs' custom repository using app-eselect/eselect-repository 69 # add sgs' custom repository using app-eselect/eselect-repository
70 eselect repository add sgs 70 eselect repository add sgs
71 71
72 # ... or using layman (obsolete)
73 layman -a sgs
74
75 emerge dev-python/etoolkit 72 emerge dev-python/etoolkit
76 ``` 73 ```
77 74
75## Encryption & decryption scheme
76
77The etoolkit encryption format is currently at version 2.
78Encrypted values start with *enc-val$2$*.
79
80This new version introduces padding for values that are shorter than 32 bytes.
81The idea behind padding is to generate (32 - value length) random bytes and
82append them to the original value.
83That prevents a potential attacker from knowing the length of the encrypted
84short value (f.i. password, PIN number, username... etc).
85
86Values encrypted in the old format (*enc-val$1$*) can still be decrypted
87seamlessly.
88
89Authenticated encryption with associated data (AEAD) is implemented using
90AES-GCM.
91
92
93### Encryption
94
95Input:
96
97- plain-text value to be encrypted (P)
98
99- plain-text master-password used for key derivation (M)
100
101
102Output:
103
104- an encrypted value digest (base64) (B)
105
106
107Operation:
108
109- generate 32 bytes of random data to be used as a salt (S)
110
111- derive a 32 bytes key (K): K = scrypt(M, S, n=2**14, r=8, p=1)
112
113- use the first 12 bytes of S as nonce (NONCE)
114
115- calculate the padding length (L) as 32 - length of P, if P < 32, 0 otherwise
116
117- set the padding length bytes (N) (2bytes) to "%02d", if L > 0, "-1" otherwise
118
119- generate L bytes of random data to be used for padding (D)
120
121- encrypt and auth. P, auth.only S (E): E = AES_GCM_ENC(K, NONCE, N + P + D, S)
122
123- encrypted value digest (B) = enc-val$2$:BASE64_ENCODE(S)$BASE64_ENCODE(E)
124
125example:
126enc-val$2$uYpZM1VfAGq0CDZL2duITs076CQj+hIFEgx+F4mn80o=$UWP5YeRsh5/2vZ2J1UOS+BJti73Kbp6C1pJmCo8hFSujpe35X/XpzBegJJpo86AiCsNsUS6B6JM=
127
128
129### Decryption
130
131Input:
132
133- encrypted value digest (base64) (B)
134
135- plain-text master-password used for key derivation (M)
136
137
138Output:
139
140- plain-text password (P)
141
142
143Operation:
144
145- remove the prefix (enc-val$2$) from B and split the remaining value by '$'
146
147- base64-decode the salt (S): S = BASE64_DECODE(B1)
148
149- base64-decode the rest of the data (E): E = BASE64_DECODE(B2)
150
151- derive a 32 bytes key (K): K = scrypt(M, S, n=2**14, r=8, p=1)
152
153- use the first 12 bytes of S as nonce (NONCE)
154
155- decrypt the encrypted data (D): D = AES_GCM_DECRYPT(K, NONCE, E, S)
156
157- fetch the first 2 bytes (padding length bytes) (N): N = D[0 : 2]
158
159- calculate the padding length (L): L = INT(N) if N != "-1", 0 otherwise
160
161- fetch the plain-text (P): P = D[2 : -L] if L != 0, D[2 :] otherwise
162
78 163
79## Setup and examples 164## Setup and examples
80 165
@@ -201,6 +286,17 @@ One can also spawn a different process than an interactive shell by using the
201 etoolkit --spawn /bin/othershell <instance-name> 286 etoolkit --spawn /bin/othershell <instance-name>
202 ``` 287 ```
203 288
289It is possible to re-encrypt all encrypted values in a specific instance or in
290all defined instances either by using the same or a new master password.
291
292 ```bash
293 etoolkit --reencrypt all
294 ```
295
296will prompt for the current master password, then for a new master password
297(with confirmation) and finally the new config file (if "all") or instance
298contents will be displayed.
299
204Contact the author for questions and suggestions! :) 300Contact the author for questions and suggestions! :)
205 301
206 302
@@ -223,11 +319,11 @@ or the *instances* structure being loaded from a diferent configuration file
223 319
224 320
225 # using some static methods in order to create encrypted values 321 # using some static methods in order to create encrypted values
226 etoolkit.EtoolkitInstance.encrypt('the very secret passwd', 'secret1') 322 etoolkit.EtoolkitInstance.encrypt('The very secret passwd', 'secret1')
227 # Out: 'enc-val$1$Y/TBb1F3siHTw6qZg9ERzZfA8PLPf2CwGSQLpu9jYWw=$FT5tS9o+ABvsxogIXpJim16Gz5SVtV8=' 323 # Out: 'enc-val$2$NDdp6WMbX7gdEyzGM5nI4jhyer4XL+BoQwAHtL2CXHw=$+Pztn1pfaXKjPpem5PIQrCNxR9pyE6zqgSoGg9qXvmhH6VsNQvUTmiaOvUFl35EbiYE='
228 324
229 etoolkit.EtoolkitInstance.encrypt('the very secret passwd', 'secret2') 325 etoolkit.EtoolkitInstance.encrypt('The very secret passwd', 'secret2')
230 # Out: 'enc-val$1$vIBcoCNiYrsDLtF41uLuSEnppBjhliD0B8jwcBJcj/c=$KwOGe/y1dlxktDaCnJPIVNuaQ4Q7yNo=' 326 # Out: 'enc-val$2$H953GxW+qrYXIp+I97lJBmG1gv89wxcfmTu7PEpZzjE=$Tb3F8/izDbHAMklpIjYk73JAiav+w8ZhrMsO93FlQjGh4MTChjp2Yen5BxSBOWLvCD4='
231 327
232 328
233 # The encrypted values will be used in our configuration structure 329 # The encrypted values will be used in our configuration structure
@@ -237,34 +333,33 @@ or the *instances* structure being loaded from a diferent configuration file
237 }, 333 },
238 "instances": { 334 "instances": {
239 "_default": { 335 "_default": {
240 "ETOOLKIT_PROMPT": "(%i)", 336 "ETOOLKIT_PROMPT": "(%i)",
241 "PYTHONPATH": "/home/user/%i/python", 337 "ETOOLKIT_SENSITIVE": ["DB_CONNECTION", "ETOOLKIT_TEST_PASSWORD"]
242 }, 338 },
243 "dev": { 339 "dev": {
244 "ETOOLKIT_PARENT": "_default", 340 "ETOOLKIT_PARENT": "_default",
245 "PYTHONPATH": "%p:/home/user/%i/.pythonpath", 341 "PYTHONPATH": ":/home/user/.pythonpath",
342 "DB_CONNECTION": "enc-val$2$RAgDei59tUvDAkrBmxROqRaV/NxNFEI2eJIOP7sG/b8=$yse7zawHCzQCU31sZj4oJYLGonz1M7oqHqCilXLHkywa9nMPALypmVzi3QekekYuLeb5XVTmmp84NHoPn1M052otoRHSp+TMPsqBPRabfriIKEK4XQ=="
246 }, 343 },
247 "secret": { 344 "secret": {
248 "ETOOLKIT_PARENT": "_default", 345 "ETOOLKIT_PARENT": "_default",
249 "ETOOLKIT_SENSITIVE": ["PASSWORD"],
250 "GNUPGHOME": "%h/private/.gnupg", 346 "GNUPGHOME": "%h/private/.gnupg",
251 "PASSWORD": "enc-val$1$vIBcoCNiYrsDLtF41uLuSEnppBjhliD0B8jwcBJcj/c=$KwOGe/y1dlxktDaCnJPIVNuaQ4Q7yNo=" 347 "ETOOLKIT_TEST_PASSWORD": "enc-val$2$RCSZqq9pWrRDoCVYVHopyu1LzaJGfv8roVviqrLTBxM=$+YYrZbwTBuG0Pl+WMQrvxLUtq5j8qYuQqzoIwgoGt7AaWZCJz+E7qoDeg3wke70ST8U="
252 } 348 }
253 } 349 }
254 } 350 }
255 351
256 352 secret_instance = etoolkit.EtoolkitInstance('secret', instances)
257 dev_instance = etoolkit.EtoolkitInstance('dev', instances)
258 353
259 # fetch the variables before the processing stage (calling get_environ()) 354 # fetch the variables before the processing stage (calling get_environ())
260 # since raw_env_variables is a dict, it can be modified (f.i. .update()) 355 # since raw_env_variables is a dict, it can be modified (f.i. .update())
261 dev_instance.raw_env_variables 356 secret_instance.raw_env_variables
262 357
263 dev_instance.master_password = 'the very secret passwd' # or perhaps using getpass 358 secret_instance.master_password = 'The very secret passwd' # or perhaps using getpass
264 env_vars = dev_instance.get_env() 359 env_vars = secret_instance.get_environ()
265 print(env_vars['PASSWORD']) # outputs: 'secret2' 360 print(env_vars['ETOOLKIT_TEST_PASSWORD']) # outputs: 'secret1'
266 361
267 inst.dump_env(env_vars) # prints all values, with the exception of 'PASSWORD' 362 secret_instance.env_to_str(env_vars) # prints all values, with the exception of 'ETOOLKIT_TEST_PASSWORD'
268 363
269 # set the env. variables. 364 # set the env. variables.
270 os.environ.update(env_vars) 365 os.environ.update(env_vars)