new encriptation system of sensible datas

This commit is contained in:
Cayo Puigdefabregas 2024-02-20 17:50:45 +01:00
parent 93f2432edb
commit 0247c5007d
12 changed files with 192 additions and 154 deletions

View File

@ -1,23 +1,19 @@
import csv
import json
import copy
import base64
import jsonschema
import pandas as pd
from pyhanko.sign import signers
from nacl.exceptions import CryptoError
from django import forms
from django.core.cache import cache
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError
from utils import credtools, certs
from utils import certs
from idhub.models import (
DID,
File_datas,
Membership,
Schemas,
Service,
UserRol,
VerificableCredential,
)
@ -51,6 +47,37 @@ class TermsConditionsForm2(forms.Form):
return
class EncryptionKeyForm(forms.Form):
key = forms.CharField(
label=_("Key for encrypt the secrets of all system"),
required=True
)
def clean(self):
data = self.cleaned_data
self._key = data["key"]
if not DID.objects.exists():
return data
did = DID.objects.first()
cache.set("KEY_DIDS", self._key, None)
try:
did.get_key_material()
except CryptoError:
cache.set("KEY_DIDS", None)
txt = _("Key no valid!")
raise ValidationError(txt)
return data
def save(self, commit=True):
if commit:
cache.set("KEY_DIDS", self._key, None)
return
class TermsConditionsForm(forms.Form):
accept_privacy = forms.BooleanField(
widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
@ -133,7 +160,7 @@ class ImportForm(forms.Form):
self.fields['did'].choices = [
(x.did, x.label) for x in dids.filter(eidas1=False)
]
self.fields['schema'].choices = [
self.fields['schema'].choices = [(0, _('Select one'))] + [
(x.id, x.name) for x in Schemas.objects.filter()
]
if dids.filter(eidas1=True).exists():
@ -197,6 +224,9 @@ class ImportForm(forms.Form):
if not data_pd:
self.exception("This file is empty!")
if not self._schema:
return data
for n in range(df.last_valid_index()+1):
row = {}
for k in data_pd.keys():
@ -382,7 +412,6 @@ class ImportCertificateForm(forms.Form):
return data
def new_did(self):
cert = self.pfx_file
keys = {
"cert": base64.b64encode(self.pfx_file).decode('utf-8'),
"passphrase": self._pss

View File

@ -1,9 +1,6 @@
import os
import json
import logging
import pandas as pd
from pathlib import Path
from jsonschema import validate
from smtplib import SMTPException
from django_tables2 import SingleTableView
@ -18,7 +15,6 @@ from django.views.generic.edit import (
UpdateView,
)
from django.shortcuts import get_object_or_404, redirect
from django.core.cache import cache
from django.urls import reverse_lazy
from django.http import HttpResponse
from django.contrib import messages
@ -28,12 +24,13 @@ from idhub_auth.forms import ProfileForm
from idhub.mixins import AdminView, Http403
from idhub.email.views import NotifyActivateUserByEmail
from idhub.admin.forms import (
EncryptionKeyForm,
ImportCertificateForm,
ImportForm,
MembershipForm,
TermsConditionsForm,
SchemaForm,
UserRolForm,
ImportCertificateForm,
UserRolForm
)
from idhub.admin.tables import (
DashboardTable,
@ -79,7 +76,27 @@ class TermsAndConditionsView(AdminView, FormView):
return kwargs
def form_valid(self, form):
user = form.save()
form.save()
return super().form_valid(form)
class EncryptionKeyView(AdminView, FormView):
template_name = "idhub/admin/encryption_key.html"
title = _('Encryption Key')
section = ""
subtitle = _('Encryption Key')
icon = 'bi bi-key'
form_class = EncryptionKeyForm
success_url = reverse_lazy('idhub:admin_dashboard')
def get(self, request, *args, **kwargs):
if self.admin_validated:
return redirect(self.success_url)
return super().get(request, *args, **kwargs)
def form_valid(self, form):
form.save()
return super().form_valid(form)
@ -649,7 +666,7 @@ class CredentialJsonView(Credentials):
VerificableCredential,
pk=pk,
)
response = HttpResponse(self.object.data, content_type="application/json")
response = HttpResponse(self.object.get_data(), content_type="application/json")
response['Content-Disposition'] = 'attachment; filename={}'.format("credential.json")
return response
@ -730,7 +747,7 @@ class DidRegisterView(Credentials, CreateView):
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.set_did(cache.get("KEY_DIDS"))
form.instance.set_did()
form.save()
messages.success(self.request, _('DID created successfully'))
Event.set_EV_ORG_DID_CREATED_BY_ADMIN(form.instance)
@ -752,7 +769,7 @@ class DidEditView(Credentials, UpdateView):
return super().get(request, *args, **kwargs)
def form_valid(self, form):
user = form.save()
form.save()
messages.success(self.request, _('DID updated successfully'))
return super().form_valid(form)

View File

@ -23,6 +23,8 @@ class Command(BaseCommand):
def handle(self, *args, **kwargs):
ADMIN_EMAIL = config('ADMIN_EMAIL', 'admin@example.org')
ADMIN_PASSWORD = config('ADMIN_PASSWORD', '1234')
KEY_DIDS = config('KEY_DIDS', '1234')
cache.set("KEY_DIDS", KEY_DIDS, None)
self.create_admin_users(ADMIN_EMAIL, ADMIN_PASSWORD)
if settings.CREATE_TEST_USERS:
@ -43,21 +45,17 @@ class Command(BaseCommand):
def create_admin_users(self, email, password):
su = User.objects.create_superuser(email=email, password=password)
su.set_encrypted_sensitive_data(password)
su.set_encrypted_sensitive_data()
su.save()
key = su.decrypt_sensitive_data(password)
key_dids = {su.id: key}
cache.set("KEY_DIDS", key_dids, None)
self.create_defaults_dids(su, key)
self.create_defaults_dids(su)
def create_users(self, email, password):
u = User.objects.create(email=email, password=password)
u.set_password(password)
u.set_encrypted_sensitive_data(password)
u.set_encrypted_sensitive_data()
u.save()
key = u.decrypt_sensitive_data(password)
self.create_defaults_dids(u, key)
self.create_defaults_dids(u)
def create_organizations(self, name, url):
@ -72,9 +70,10 @@ class Command(BaseCommand):
org1.my_client_secret = org2.client_secret
org1.save()
org2.save()
def create_defaults_dids(self, u, password):
def create_defaults_dids(self, u):
did = DID(label="Default", user=u, type=DID.Types.WEB)
did.set_did(password)
did.set_did()
did.save()
def create_schemas(self):

View File

@ -12,8 +12,8 @@ class Http403(PermissionDenied):
default_detail = _('Permission denied. User is not authenticated')
default_code = 'forbidden'
def __init__(self, detail=None, code=None):
if detail is not None:
def __init__(self, details=None, code=None):
if details is not None:
self.detail = details or self.default_details
if code is not None:
self.code = code or self.default_code
@ -22,15 +22,30 @@ class Http403(PermissionDenied):
class UserView(LoginRequiredMixin):
login_url = "/login/"
wallet = False
admin_validated = False
path_terms = [
'admin_terms_and_conditions',
'user_terms_and_conditions',
'user_gdpr',
'user_waiting',
'user_waiting',
'encryption_key',
]
def get(self, request, *args, **kwargs):
self.admin_validated = cache.get("KEY_DIDS")
response = super().get(request, *args, **kwargs)
if not self.admin_validated:
actual_path = resolve(self.request.path).url_name
if not self.request.user.is_admin:
if actual_path != 'user_waiting':
return redirect(reverse_lazy("idhub:user_waiting"))
if self.request.user.is_admin:
if actual_path != 'encryption_key':
return redirect(reverse_lazy("idhub:encryption_key"))
url = self.check_gdpr()
return url or response

View File

@ -9,7 +9,6 @@ from django.conf import settings
from django.core.cache import cache
from django.template.loader import get_template
from django.utils.translation import gettext_lazy as _
from nacl import secret
from utils.idhub_ssikit import (
generate_did_controller_key,
@ -34,26 +33,27 @@ class Event(models.Model):
EV_DID_CREATED = 9, "DID created"
EV_DID_DELETED = 10, "DID deleted"
EV_CREDENTIAL_DELETED_BY_USER = 11, "Credential deleted by user"
EV_CREDENTIAL_DELETED = 12, "Credential deleted"
EV_CREDENTIAL_ISSUED_FOR_USER = 13, "Credential issued for user"
EV_CREDENTIAL_ISSUED = 14, "Credential issued"
EV_CREDENTIAL_PRESENTED_BY_USER = 15, "Credential presented by user"
EV_CREDENTIAL_PRESENTED = 16, "Credential presented"
EV_CREDENTIAL_ENABLED = 17, "Credential enabled"
EV_CREDENTIAL_CAN_BE_REQUESTED = 18, "Credential available"
EV_CREDENTIAL_REVOKED_BY_ADMIN = 19, "Credential revoked by admin"
EV_CREDENTIAL_REVOKED = 20, "Credential revoked"
EV_ROLE_CREATED_BY_ADMIN = 21, "Role created by admin"
EV_ROLE_MODIFIED_BY_ADMIN = 22, "Role modified by admin"
EV_ROLE_DELETED_BY_ADMIN = 23, "Role deleted by admin"
EV_SERVICE_CREATED_BY_ADMIN = 24, "Service created by admin"
EV_SERVICE_MODIFIED_BY_ADMIN = 25, "Service modified by admin"
EV_SERVICE_DELETED_BY_ADMIN = 26, "Service deleted by admin"
EV_ORG_DID_CREATED_BY_ADMIN = 27, "Organisational DID created by admin"
EV_ORG_DID_DELETED_BY_ADMIN = 28, "Organisational DID deleted by admin"
EV_USR_DEACTIVATED_BY_ADMIN = 29, "User deactivated"
EV_USR_ACTIVATED_BY_ADMIN = 30, "User activated"
EV_USR_SEND_VP = 31, "User send Verificable Presentation"
EV_CREDENTIAL_DELETED_BY_ADMIN = 12, "Credential deleted by admin"
EV_CREDENTIAL_DELETED = 13, "Credential deleted"
EV_CREDENTIAL_ISSUED_FOR_USER = 14, "Credential issued for user"
EV_CREDENTIAL_ISSUED = 15, "Credential issued"
EV_CREDENTIAL_PRESENTED_BY_USER = 16, "Credential presented by user"
EV_CREDENTIAL_PRESENTED = 17, "Credential presented"
EV_CREDENTIAL_ENABLED = 18, "Credential enabled"
EV_CREDENTIAL_CAN_BE_REQUESTED = 19, "Credential available"
EV_CREDENTIAL_REVOKED_BY_ADMIN = 20, "Credential revoked by admin"
EV_CREDENTIAL_REVOKED = 21, "Credential revoked"
EV_ROLE_CREATED_BY_ADMIN = 22, "Role created by admin"
EV_ROLE_MODIFIED_BY_ADMIN = 23, "Role modified by admin"
EV_ROLE_DELETED_BY_ADMIN = 24, "Role deleted by admin"
EV_SERVICE_CREATED_BY_ADMIN = 25, "Service created by admin"
EV_SERVICE_MODIFIED_BY_ADMIN = 26, "Service modified by admin"
EV_SERVICE_DELETED_BY_ADMIN = 27, "Service deleted by admin"
EV_ORG_DID_CREATED_BY_ADMIN = 28, "Organisational DID created by admin"
EV_ORG_DID_DELETED_BY_ADMIN = 29, "Organisational DID deleted by admin"
EV_USR_DEACTIVATED_BY_ADMIN = 30, "User deactivated"
EV_USR_ACTIVATED_BY_ADMIN = 31, "User activated"
EV_USR_SEND_VP = 32, "User send Verificable Presentation"
created = models.DateTimeField(_("Date"), auto_now=True)
message = models.CharField(_("Description"), max_length=350)
@ -99,9 +99,8 @@ class Event(models.Model):
@classmethod
def set_EV_DATA_UPDATE_REQUESTED_BY_USER(cls, user):
msg = _("The user '{username}' has request the update of the following information: ")
msg += "['field1':'value1', 'field2':'value2'>,...]".format(
username=user.username,
)
msg += "['field1':'value1', 'field2':'value2'>,...]"
msg = msg.format(username=user.username)
cls.objects.create(
type=cls.Types.EV_DATA_UPDATE_REQUESTED_BY_USER,
message=msg,
@ -444,11 +443,11 @@ class DID(models.Model):
# JSON-serialized DID document
didweb_document = models.TextField()
def get_key_material(self, password):
return self.user.decrypt_data(self.key_material, password)
def get_key_material(self):
return self.user.decrypt_data(self.key_material)
def set_key_material(self, value, password):
self.key_material = self.user.encrypt_data(value, password)
def set_key_material(self, value):
self.key_material = self.user.encrypt_data(value)
@property
def is_organization_did(self):
@ -456,9 +455,9 @@ class DID(models.Model):
return True
return False
def set_did(self, password):
def set_did(self):
new_key_material = generate_did_controller_key()
self.set_key_material(new_key_material, password)
self.set_key_material(new_key_material)
if self.type == self.Types.KEY:
self.did = keydid_from_controller_key(new_key_material)
@ -621,17 +620,14 @@ class VerificableCredential(models.Model):
return True
return False
def get_data(self, password):
def get_data(self):
if not self.data:
return ""
if self.eidas1_did:
return self.data
return self.user.decrypt_data(self.data, password)
return self.user.decrypt_data(self.data)
def set_data(self, value, password):
self.data = self.user.encrypt_data(value, password)
def set_data(self, value):
self.data = self.user.encrypt_data(value)
def get_description(self):
return self.schema._description or ''
@ -652,32 +648,24 @@ class VerificableCredential(models.Model):
data = json.loads(self.csv_data).items()
return data
def issue(self, did, password, domain=settings.DOMAIN.strip("/")):
def issue(self, did, domain=settings.DOMAIN.strip("/")):
if self.status == self.Status.ISSUED:
return
self.subject_did = did
self.issued_on = datetime.datetime.now().astimezone(pytz.utc)
issuer_pass = cache.get("KEY_DIDS")
# issuer_pass = self.user.decrypt_data(
# cache.get("KEY_DIDS"),
# settings.SECRET_KEY,
# )
# hash of credential without sign
self.hash = hashlib.sha3_256(self.render(domain).encode()).hexdigest()
data = sign_credential(
self.render(domain),
self.issuer_did.get_key_material(issuer_pass)
self.issuer_did.get_key_material()
)
valid, reason = verify_credential(data)
if not valid:
return
if self.eidas1_did:
self.data = data
else:
self.data = self.user.encrypt_data(data, password)
self.data = self.user.encrypt_data(data)
self.status = self.Status.ISSUED

View File

@ -38,7 +38,7 @@
<strong>{% trans 'Issuance date' %}:</strong>
</div>
<div class="col bg-light text-secondary">
{{ object.issuer_on|default_if_none:"" }}
{{ object.issued_on|default_if_none:"" }}
</div>
</div>
<div class="row mt-3">

View File

@ -25,7 +25,7 @@
<strong>{% trans 'Issuance date' %}:</strong>
</div>
<div class="col bg-light text-secondary">
{{ object.issuer_on|default_if_none:"" }}
{{ object.issued_on|default_if_none:"" }}
</div>
</div>
<div class="row mt-3">

View File

@ -88,6 +88,9 @@ urlpatterns = [
path('user/terms/', views_user.TermsAndConditionsView.as_view(),
name='user_terms_and_conditions'),
path('waiting/', views_user.WaitingView.as_view(),
name='user_waiting'),
# Admin
path('admin/dashboard/', views_admin.DashboardView.as_view(),
name='admin_dashboard'),
@ -173,6 +176,7 @@ urlpatterns = [
name='admin_terms_and_conditions'),
path('admin/import/new', views_admin.ImportAddView.as_view(),
name='admin_import_add'),
path('admin/enc/', views_admin.EncryptionKeyView.as_view(), name='encryption_key'),
path('admin/auth/<uuid:admin2fauth>', views_admin.DobleFactorAuthView.as_view(),
name='admin_2fauth'),
path('admin/auth/2f/', DobleFactorSendView.as_view(), name='confirm_send_2f'),

View File

@ -81,7 +81,6 @@ class RequestCredentialForm(forms.Form):
self.user = kwargs.pop('user', None)
self.lang = kwargs.pop('lang', None)
self._domain = kwargs.pop('domain', None)
self.password = kwargs.pop('password', None)
super().__init__(*args, **kwargs)
self.fields['did'].choices = [
(x.did, x.label) for x in DID.objects.filter(user=self.user)
@ -109,8 +108,7 @@ class RequestCredentialForm(forms.Form):
did = did[0]
cred = cred[0]
try:
if self.password:
cred.issue(did, self.password, domain=self._domain)
cred.issue(did, domain=self._domain)
except Exception:
return

View File

@ -161,10 +161,25 @@ class TermsAndConditionsView(UserView, FormView):
return kwargs
def form_valid(self, form):
user = form.save()
form.save()
return super().form_valid(form)
class WaitingView(UserView, TemplateView):
template_name = "idhub/user/waiting.html"
title = _("Comunication with admin")
subtitle = _('Service temporary close')
section = ""
icon = 'bi bi-file-earmark-medical'
success_url = reverse_lazy('idhub:user_dashboard')
def get(self, request, *args, **kwargs):
if cache.get("KEY_DIDS"):
return redirect(self.success_url)
return super().get(request, *args, **kwargs)
class CredentialView(MyWallet, TemplateView):
template_name = "idhub/user/credential.html"
subtitle = _('Credential')
@ -194,7 +209,8 @@ class CredentialPdfView(MyWallet, TemplateView):
file_name = "certificate.pdf"
def get(self, request, *args, **kwargs):
self.admin_validated = cache.get("KEY_DIDS")
if not self.admin_validated:
return redirect(reverse_lazy('idhub:user_dashboard'))
pk = kwargs['pk']
self.user = self.request.user
self.object = get_object_or_404(
@ -282,10 +298,9 @@ class CredentialPdfView(MyWallet, TemplateView):
def get_pfx_data(self):
did = self.object.eidas1_did
pw = self.admin_validated
if not did or not pw:
if not did:
return None, None
key_material = json.loads(did.get_key_material(pw))
key_material = json.loads(did.get_key_material())
cert = key_material.get("cert")
passphrase = key_material.get("passphrase")
if cert and passphrase:
@ -337,14 +352,7 @@ class CredentialJsonView(MyWallet, TemplateView):
pk=pk,
user=self.request.user
)
pass_enc = self.request.session.get("key_did")
data = ""
if pass_enc:
user_pass = self.request.user.decrypt_data(
pass_enc,
self.request.user.password+self.request.session._session_key
)
data = self.object.get_data(user_pass)
data = self.object.get_data()
response = HttpResponse(data, content_type="application/json")
response['Content-Disposition'] = 'attachment; filename={}'.format("credential.json")
return response
@ -383,15 +391,6 @@ class CredentialsRequestView(MyWallet, FormView):
kwargs['lang'] = self.request.LANGUAGE_CODE
domain = "{}://{}".format(self.request.scheme, self.request.get_host())
kwargs['domain'] = domain
pass_enc = self.request.session.get("key_did")
if pass_enc:
user_pass = self.request.user.decrypt_data(
pass_enc,
self.request.user.password+self.request.session._session_key
)
else:
pass_enc = None
kwargs['password'] = user_pass
return kwargs
def form_valid(self, form):
@ -468,11 +467,7 @@ class DidRegisterView(MyWallet, CreateView):
def form_valid(self, form):
form.instance.user = self.request.user
pw = self.request.user.decrypt_data(
self.request.session.get("key_did"),
self.request.user.password+self.request.session._session_key
)
form.instance.set_did(pw)
form.instance.set_did()
form.save()
messages.success(self.request, _('DID created successfully'))
@ -496,7 +491,7 @@ class DidEditView(MyWallet, UpdateView):
return super().get(request, *args, **kwargs)
def form_valid(self, form):
user = form.save()
form.save()
messages.success(self.request, _('DID updated successfully'))
return super().form_valid(form)

View File

@ -18,7 +18,6 @@ from django.http import HttpResponseRedirect, HttpResponse, Http404
from idhub.models import DID, VerificableCredential
from idhub.email.views import NotifyActivateUserByEmail
from trustchain_idhub import settings
logger = logging.getLogger(__name__)
@ -46,30 +45,20 @@ class LoginView(auth_views.LoginView):
def form_valid(self, form):
user = form.get_user()
password = form.cleaned_data.get("password")
auth_login(self.request, user)
sensitive_data_encryption_key = user.decrypt_sensitive_data(password)
if user.is_anonymous:
return redirect(reverse_lazy("idhub:login"))
if not user.is_anonymous and user.is_admin:
admin_dashboard = reverse_lazy('idhub:admin_dashboard')
self.extra_context['success_url'] = admin_dashboard
# encryption_key = user.encrypt_data(
# sensitive_data_encryption_key,
# settings.SECRET_KEY
# )
# cache.set("KEY_DIDS", encryption_key, None)
cache.set("KEY_DIDS", sensitive_data_encryption_key, None)
if user.is_admin:
if settings.ENABLE_2FACTOR_AUTH:
self.request.session["2fauth"] = str(uuid.uuid4())
return redirect(reverse_lazy('idhub:confirm_send_2f'))
self.request.session["key_did"] = user.encrypt_data(
sensitive_data_encryption_key,
user.password+self.request.session._session_key
)
admin_dashboard = reverse_lazy('idhub:admin_dashboard')
self.extra_context['success_url'] = admin_dashboard
return HttpResponseRedirect(self.extra_context['success_url'])
return redirect(self.extra_context['success_url'])
class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):

View File

@ -1,7 +1,7 @@
import nacl
import base64
from nacl import pwhash
from nacl import pwhash, secret
from django.db import models
from django.core.cache import cache
from django.utils.translation import gettext_lazy as _
@ -95,21 +95,24 @@ class User(AbstractBaseUser):
roles.append(r.name)
return ", ".join(set(roles))
def derive_key_from_password(self, password):
def derive_key_from_password(self, password=None):
if not password:
password = cache.get("KEY_DIDS").encode('utf-8')
kdf = pwhash.argon2i.kdf
ops = pwhash.argon2i.OPSLIMIT_INTERACTIVE
mem = pwhash.argon2i.MEMLIMIT_INTERACTIVE
return kdf(
nacl.secret.SecretBox.KEY_SIZE,
secret.SecretBox.KEY_SIZE,
password,
self.get_salt(),
opslimit=ops,
memlimit=mem
)
def decrypt_sensitive_data(self, password, data=None):
sb_key = self.derive_key_from_password(password.encode('utf-8'))
sb = nacl.secret.SecretBox(sb_key)
def decrypt_sensitive_data(self, data=None):
sb_key = self.derive_key_from_password()
sb = secret.SecretBox(sb_key)
if not data:
data = self.get_encrypted_sensitive_data()
if not isinstance(data, bytes):
@ -117,9 +120,9 @@ class User(AbstractBaseUser):
return sb.decrypt(data).decode('utf-8')
def encrypt_sensitive_data(self, password, data):
sb_key = self.derive_key_from_password(password.encode('utf-8'))
sb = nacl.secret.SecretBox(sb_key)
def encrypt_sensitive_data(self, data):
sb_key = self.derive_key_from_password()
sb = secret.SecretBox(sb_key)
if not isinstance(data, bytes):
data = data.encode('utf-8')
@ -134,32 +137,33 @@ class User(AbstractBaseUser):
def get_encrypted_sensitive_data(self):
return base64.b64decode(self.encrypted_sensitive_data.encode('utf-8'))
def set_encrypted_sensitive_data(self, password):
def set_encrypted_sensitive_data(self):
key = base64.b64encode(nacl.utils.random(64))
self.set_salt()
key_crypted = self.encrypt_sensitive_data(password, key)
key_crypted = self.encrypt_sensitive_data(key)
self.encrypted_sensitive_data = key_crypted
def encrypt_data(self, data, password):
sb = self.get_secret_box(password)
def encrypt_data(self, data):
sb = self.get_secret_box()
value_enc = sb.encrypt(data.encode('utf-8'))
return base64.b64encode(value_enc).decode('utf-8')
def decrypt_data(self, data, password):
sb = self.get_secret_box(password)
def decrypt_data(self, data):
sb = self.get_secret_box()
value = base64.b64decode(data.encode('utf-8'))
return sb.decrypt(value).decode('utf-8')
def get_secret_box(self, password):
pw = base64.b64decode(password.encode('utf-8')*4)
sb_key = self.derive_key_from_password(pw)
return nacl.secret.SecretBox(sb_key)
def get_secret_box(self):
sb_key = self.derive_key_from_password()
return secret.SecretBox(sb_key)
def change_password(self, old_password, new_password):
sensitive_data = self.decrypt_sensitive_data(old_password)
self.encrypted_sensitive_data = self.encrypt_sensitive_data(
new_password,
sensitive_data
)
self.set_password(new_password)
def change_password_key(self, new_password):
data = self.decrypt_sensitive_data()
sb_key = self.derive_key_from_password(new_password)
sb = secret.SecretBox(sb_key)
if not isinstance(data, bytes):
data = data.encode('utf-8')
encrypted_data = base64.b64encode(sb.encrypt(data)).decode('utf-8')
self.encrypted_sensitive_data = encrypted_data