@@ -80,6 +80,7 @@ class encryptContentPlugin(BasePlugin):
8080 ('session_storage' , config_options .Type (bool , default = True )),
8181 ('password_inventory' , config_options .Type (dict , default = {})),
8282 ('password_file' , config_options .Type (string_types , default = None )),
83+ ('cache_file' , config_options .Type (string_types , default = 'encryptcontent.cache' )),
8384 ('sharelinks' , config_options .Type (bool , default = False )),
8485 ('sharelinks_output' , config_options .Type (string_types , default = 'sharelinks.txt' )),
8586 # default features enabled
@@ -166,8 +167,30 @@ def __encrypt_keys_from_keystore__(self, index):
166167 iterations = self .setup ['kdf_iterations' ]
167168 """ Encrypts key with PBKDF2 and AES-256. """
168169 salt = get_random_bytes (16 )
169- # generate PBKDF2 key from salt and password (password is URI encoded)
170- kdfkey = PBKDF2 (quote (password , safe = '~()*!\' ' ), salt , 32 , count = iterations , hmac_hash_module = SHA256 )
170+
171+ if index [0 ] == KS_OBFUSCATE and password in self .setup ['cache' ]['obfuscate' ]:
172+ fromcache = self .setup ['cache' ]['obfuscate' ][password ].split (';' )
173+ kdfkey = bytes .fromhex (fromcache [0 ])
174+ salt = bytes .fromhex (fromcache [1 ])
175+ elif index [0 ] == KS_PASSWORD and password in self .setup ['cache' ]['password' ]:
176+ fromcache = self .setup ['cache' ]['password' ][password ].split (';' )
177+ kdfkey = bytes .fromhex (fromcache [0 ])
178+ salt = bytes .fromhex (fromcache [1 ])
179+ elif isinstance (index [0 ], str ) and index [0 ] in self .setup ['cache' ]['userpass' ]:
180+ fromcache = self .setup ['cache' ]['userpass' ][index [0 ]].split (';' )
181+ kdfkey = bytes .fromhex (fromcache [0 ])
182+ salt = bytes .fromhex (fromcache [1 ])
183+ else :
184+ # generate PBKDF2 key from salt and password (password is URI encoded)
185+ kdfkey = PBKDF2 (quote (password , safe = '~()*!\' ' ), salt , 32 , count = iterations , hmac_hash_module = SHA256 )
186+ logger .info ('Need to generate KDF key...' )
187+ if index [0 ] == KS_OBFUSCATE :
188+ self .setup ['cache' ]['obfuscate' ][password ] = kdfkey .hex () + ';' + salt .hex ()
189+ elif index [0 ] == KS_PASSWORD :
190+ self .setup ['cache' ]['password' ][password ] = kdfkey .hex () + ';' + salt .hex ()
191+ else :
192+ self .setup ['cache' ]['userpass' ][index [0 ]] = kdfkey .hex () + ';' + salt .hex ()
193+
171194 # initialize AES-256
172195 iv = get_random_bytes (16 )
173196 cipher = AES .new (kdfkey , AES .MODE_CBC , iv )
@@ -494,6 +517,23 @@ def on_config(self, config, **kwargs):
494517 if 'keystore_userpass' not in self .setup : self .setup ['keystore_userpass' ] = {}
495518 if 'keystore_obfuscate' not in self .setup : self .setup ['keystore_obfuscate' ] = {}
496519
520+ # rebuild kdf keys only if not in cache
521+ if 'cache_file' not in self .setup and self .config ['cache_file' ]:
522+ self .setup ['cache_file' ] = self .setup ['config_path' ].joinpath (self .config ['cache_file' ])
523+ if self .setup ['cache_file' ].exists ():
524+ with open (self .setup ['cache_file' ], 'r' ) as stream :
525+ self .setup ['cache' ] = yaml .safe_load (stream )
526+
527+ if 'cache' not in self .setup or self .setup ['cache' ]['kdf_iterations' ] != self .setup ['kdf_iterations' ]:
528+ self .setup ['cache' ] = {}
529+ self .setup ['cache' ]['userpass' ] = {}
530+ self .setup ['cache' ]['password' ] = {}
531+ self .setup ['cache' ]['obfuscate' ] = {}
532+ self .setup ['cache' ]['kdf_iterations' ] = self .setup ['kdf_iterations' ]
533+ self .setup ['keystore_password' ] = {}
534+ self .setup ['keystore_userpass' ] = {}
535+ self .setup ['keystore_obfuscate' ] = {}
536+
497537 if 'sharelinks' not in self .setup and self .config ['sharelinks' ]:
498538 self .setup ['sharelinks_output' ] = self .setup ['config_path' ].joinpath (self .config ['sharelinks_output' ])
499539 self .setup ['sharelinks' ] = {}
@@ -1030,6 +1070,10 @@ def on_post_build(self, config, **kwargs):
10301070 ' (and a maximum of {secret} bits total)!' .format (spied_on = math .ceil (self .setup ['min_enttropy_spied_on' ]), secret = math .ceil (self .setup ['min_enttropy_secret' ]))
10311071 )
10321072
1073+ if 'cache_file' in self .setup :
1074+ with open (self .setup ['cache_file' ], 'w' ) as stream :
1075+ stream .write (yaml .dump (self .setup ['cache' ]))
1076+
10331077 if self .config ['sharelinks' ]:
10341078 sharelinks = []
10351079 for page in self .setup ['sharelinks' ]:
0 commit comments