mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Merge pull request #1357 from fyfe/feature/refactor-cryptutils
refactor cryptutils
This commit is contained in:
+33
-42
@@ -1,58 +1,49 @@
|
||||
# coding: utf-8
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""Crypto related utilities."""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import base64
|
||||
import random
|
||||
import string
|
||||
|
||||
from django.utils.encoding import force_bytes, force_text
|
||||
from django.conf import settings
|
||||
from django.utils.crypto import get_random_string
|
||||
from django.utils.encoding import smart_bytes, smart_text
|
||||
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
from modoboa.parameters import tools as param_tools
|
||||
from cryptography.fernet import Fernet
|
||||
|
||||
|
||||
def random_key(l=16):
|
||||
"""Generate a random key.
|
||||
|
||||
:param integer l: the key's length
|
||||
:return: a string
|
||||
"""
|
||||
punctuation = """!#$%&'()*+,-./:;<=>?@[]^_`{|}~"""
|
||||
population = string.digits + string.ascii_letters + punctuation
|
||||
while True:
|
||||
key = "".join(random.sample(population * l, l))
|
||||
if len(key) == l:
|
||||
return key
|
||||
def random_key(length=16):
|
||||
"""Generate a new key used to encrypt user passwords in session storage."""
|
||||
chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
|
||||
return get_random_string(length, chars)
|
||||
|
||||
|
||||
def encrypt(clear):
|
||||
key = force_bytes(
|
||||
param_tools.get_global_parameter("secret_key", app="core"))
|
||||
backend = default_backend()
|
||||
cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=backend)
|
||||
encryptor = cipher.encryptor()
|
||||
block_size = algorithms.AES.block_size
|
||||
clear = force_bytes(clear)
|
||||
if len(clear) % block_size:
|
||||
clear += b" " * (block_size - len(clear) % block_size)
|
||||
ct = encryptor.update(clear) + encryptor.finalize()
|
||||
return force_text(base64.b64encode(ct))
|
||||
def _get_fernet():
|
||||
"""Create a Fernet instance."""
|
||||
secret_key = base64.urlsafe_b64encode(smart_bytes(settings.SECRET_KEY[:32]))
|
||||
return Fernet(secret_key)
|
||||
|
||||
|
||||
def decrypt(ct):
|
||||
backend = default_backend()
|
||||
key = param_tools.get_global_parameter("secret_key", app="core")
|
||||
cipher = Cipher(
|
||||
algorithms.AES(force_bytes(key)), modes.ECB(), backend=backend)
|
||||
ct = base64.b64decode(force_bytes(ct))
|
||||
decryptor = cipher.decryptor()
|
||||
clear = decryptor.update(ct) + decryptor.finalize()
|
||||
return force_text(clear.rstrip(b" "))
|
||||
def encrypt(clear_value):
|
||||
"""Encrypt a value using secret_key."""
|
||||
return smart_text(_get_fernet().encrypt(smart_bytes(clear_value)))
|
||||
|
||||
|
||||
def decrypt(encrypted_value):
|
||||
"""Decrypt a value using secret_key."""
|
||||
return smart_text(_get_fernet().decrypt(smart_bytes(encrypted_value)))
|
||||
|
||||
|
||||
def get_password(request):
|
||||
return decrypt(request.session["password"])
|
||||
"""
|
||||
Retrieve and decrypt the users password from session storage.
|
||||
|
||||
This is used by modoboa-webmail to allow the user to send/receive e-mails
|
||||
without having to ask the user for a password on each connection to the
|
||||
postfix/dovecot server.
|
||||
"""
|
||||
try:
|
||||
return decrypt(request.session["password"])
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""Tests for crypto utility functions."""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.test import SimpleTestCase
|
||||
from django.test.utils import override_settings
|
||||
|
||||
from modoboa.lib import cryptutils
|
||||
|
||||
|
||||
@override_settings(SECRET_KEY="!8o(-dbbl3e+*bh7nx-^xysdt)1gso*%@4ze4-9_9o+i&"
|
||||
";t--u_")
|
||||
class CryptUtilsTest(SimpleTestCase):
|
||||
|
||||
"""Tests for modoboa.lib.cryptutils"""
|
||||
|
||||
def test_valid_secret_key_generated(self):
|
||||
"""Generate a 32 byte key"""
|
||||
secret_key = cryptutils.random_key(32)
|
||||
self.assertEqual(len(secret_key), 32)
|
||||
|
||||
def test_encrypt(self):
|
||||
"""Encrypt a string"""
|
||||
value = "test"
|
||||
expected_output = "test"
|
||||
output = cryptutils.encrypt(value)
|
||||
output = cryptutils.decrypt(output)
|
||||
self.assertEqual(output, expected_output)
|
||||
|
||||
def test_decrypt(self):
|
||||
"""Decrypt a string"""
|
||||
value = "gAAAAABaXSWk4Via-aYP7diek9MmfknUiEY8szrgxIytdXrbfc"\
|
||||
"YlbOYiNG01zqkn3a06P1xPXe5XD2SP4UrIvCWzhLs-FO19Cw=="
|
||||
expected_output = "test"
|
||||
output = cryptutils.decrypt(value)
|
||||
self.assertEqual(output, expected_output)
|
||||
Reference in New Issue
Block a user