Skip to content

Commit 6cfd2ae

Browse files
committed
speed up build time by caching kdf key generation
1 parent bdddcd9 commit 6cfd2ae

File tree

1 file changed

+46
-2
lines changed

1 file changed

+46
-2
lines changed

encryptcontent/plugin.py

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)