From 0e03f327b1edbd75435393e7bc6bf89f89370951 Mon Sep 17 00:00:00 2001 From: Rodolphe Breard Date: Sat, 27 Jul 2019 18:29:18 +0200 Subject: [PATCH] Add an admin command that re-encrypts passwords after a key rollover --- pwdb/management/__init__.py | 0 pwdb/management/commands/__init__.py | 0 .../commands/pwdb_rotate_secret_key.py | 26 +++++++++++++++++++ pwdb/models.py | 4 +-- 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 pwdb/management/__init__.py create mode 100644 pwdb/management/commands/__init__.py create mode 100644 pwdb/management/commands/pwdb_rotate_secret_key.py diff --git a/pwdb/management/__init__.py b/pwdb/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pwdb/management/commands/__init__.py b/pwdb/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pwdb/management/commands/pwdb_rotate_secret_key.py b/pwdb/management/commands/pwdb_rotate_secret_key.py new file mode 100644 index 0000000..601b815 --- /dev/null +++ b/pwdb/management/commands/pwdb_rotate_secret_key.py @@ -0,0 +1,26 @@ +from django.core.management.base import BaseCommand, CommandError +from pwdb.models import SharedPassword, IV_LENGTH +import secrets + + +class Command(BaseCommand): + help = "Re-encrypts all the shared passwords after a secret key rollover" + + def add_arguments(self, parser): + parser.add_argument("old_key", type=str) + + def handle(self, *args, **options): + self.stdout.write("Re-encrypting passwords with the new secret key.") + self.old_key = options["old_key"] + try: + for p in SharedPassword.objects.all(): + self.update_password(p) + self.stdout.write("Done.") + except ValueError: + self.stderr.write("Invalid key.") + + def update_password(self, password): + clear_password = password.decrypt_password(key=self.old_key) + password.iv = secrets.token_bytes(IV_LENGTH) + password.set_password(clear_password) + password.save() diff --git a/pwdb/models.py b/pwdb/models.py index 298eebf..7fd5229 100644 --- a/pwdb/models.py +++ b/pwdb/models.py @@ -77,8 +77,8 @@ class SharedPassword(models.Model): encryptor.update(clear_password) + encryptor.finalize() ) - def decrypt_password(self): - key = SharedPassword.get_key(self.uuid) + def decrypt_password(self, key=None): + key = SharedPassword.get_key(self.uuid, key=key) cipher = SharedPassword.get_cipher(key, self.iv) decryptor = cipher.decryptor() clear_password = (