update dependencies, replace pycrypto with cryptography

This commit is contained in:
smile 2025-04-11 21:44:34 +02:00
parent 2623444b11
commit 35b4313ad1
7 changed files with 109 additions and 45 deletions

1
.gitignore vendored
View file

@ -4,3 +4,4 @@ local_settings.py
build
*.sqlite3
*~
venv*

View file

@ -4,8 +4,8 @@
import base64
import os
from Crypto import Random
from Crypto.Cipher import AES
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
ENCRYPTED_LDAP_PASSWORD = 'encrypted_ldap_password'
@ -18,17 +18,15 @@ def encrypt_ldap_password(cleartext_pw):
The key is supposed to be stored into the 'session_key' cookie field we can
later use it to decrypt the password and connect to the LDAP server with it.
"""
# 16 bytes of key => AES-128
random = Random.new()
key = os.urandom(16) # random.read(16)
key = os.urandom(16) # 128-bit AES key
iv = os.urandom(16) # 128-bit IV
cipher = Cipher(algorithms.AES(key), modes.CFB(iv), backend=default_backend())
encryptor = cipher.encryptor()
# initialization vector
iv = os.urandom(16) # random.read(16)
ciphertext = encryptor.update(cleartext_pw.encode()) + encryptor.finalize()
# do the encryption
aes = AES.new(key, AES.MODE_CFB, iv)
message = iv + aes.encrypt(cleartext_pw.encode())
message = iv + ciphertext
return base64.b64encode(message).decode(), base64.b64encode(key).decode()
@ -40,16 +38,14 @@ def decrypt_ldap_password(message, key):
decoded_message = base64.b64decode(message)
decoded_key = base64.b64decode(key)
# first 16 bytes of the message are the initialization vector
iv = decoded_message[:16]
# the rest is the encrypted password
ciphertext = decoded_message[16:]
# decrypt it
aes = AES.new(decoded_key, AES.MODE_CFB, iv)
cleartext_pw = aes.decrypt(ciphertext).decode()
return cleartext_pw
cipher = Cipher(algorithms.AES(decoded_key), modes.CFB(iv), backend=default_backend())
decryptor = cipher.decryptor()
cleartext_pw = decryptor.update(ciphertext) + decryptor.finalize()
return cleartext_pw.decode()
def store_ldap_password(request, password):

View file

@ -4,6 +4,8 @@ when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
import base64
import pytest
from django.test import TestCase
from account.password_encryption import encrypt_ldap_password, \
@ -28,3 +30,37 @@ class PasswordEncryptionTest(TestCase):
message, key = self.encrypt_it()
decrypted = decrypt_ldap_password(message, key)
self.assertEqual(self.TEST_LDAP_PASSWD, decrypted)
@pytest.mark.parametrize("password", [
"simplePassword123",
"pässwörd_mit_üöäß",
"",
" " * 10,
"🔐✨🚀",
])
def test_encrypt_decrypt_roundtrip(password):
encrypted, key = encrypt_ldap_password(password)
encrypted_bytes = base64.b64decode(encrypted)
key_bytes = base64.b64decode(key)
assert isinstance(encrypted, str)
assert isinstance(key, str)
assert len(key_bytes) == 16 # 128-bit AES
decrypted = decrypt_ldap_password(encrypted, key)
assert decrypted == password
def test_decryption_with_wrong_key_should_fail():
password = "correctPassword"
encrypted, key = encrypt_ldap_password(password)
wrong_key_bytes = base64.b64decode(key)
wrong_key_bytes = bytearray(wrong_key_bytes)
wrong_key_bytes[0] ^= 0xFF # Flip first bit
wrong_key = base64.b64encode(bytes(wrong_key_bytes)).decode()
with pytest.raises(Exception):
decrypt_ldap_password(encrypted, wrong_key)

View file

@ -204,11 +204,9 @@ INSTALLED_APPS = (
'django.contrib.staticfiles',
'django.contrib.admin',
'django.contrib.admindocs',
# 'jsonrpc', # STUBBED due to django-1.8.4 upgraded
'crispy_forms',
# 'cbmi',
"crispy_forms",
"crispy_bootstrap4",
'account',
# 'cbapi_ldap',
)
# A sample logging configuration. The only tangible logging
@ -242,7 +240,8 @@ LOGGING = {
}
}
CRISPY_TEMPLATE_PACK = 'bootstrap'
CRISPY_TEMPLATE_PACK = "bootstrap4"
CRISPY_FAIL_SILENTLY = False
# c-base specific settings
CBASE_LDAP_URL = 'ldaps://lea.cbrp3.c-base.org:389/'

5
pytest.ini Normal file
View file

@ -0,0 +1,5 @@
# pytest.ini
[pytest]
DJANGO_SETTINGS_MODULE = cbmi.settings
python_files = tests.py test_*.py *_tests.py

View file

@ -1,7 +1,12 @@
crispy-bootstrap4
cryptography
Django<5
django-auth-ldap
django-crispy-forms
django-bootstrap4
gunicorn
pycrypto
# pycrypto
passlib
pytest
pytest-django
requests

View file

@ -1,45 +1,67 @@
#
# This file is autogenerated by pip-compile with python 3.9
# To update, run:
# This file is autogenerated by pip-compile with Python 3.9
# by the following command:
#
# pip-compile requirements.in
# pip-compile
#
asgiref==3.5.2
asgiref==3.8.1
# via django
certifi==2022.5.18.1
certifi==2025.1.31
# via requests
charset-normalizer==2.0.12
cffi==1.17.1
# via cryptography
charset-normalizer==3.4.1
# via requests
django==4.0.5
# cryptography==41.0.7
# via -r requirements.in
django==4.2.20
# via
# -r requirements.in
# django-auth-ldap
django-auth-ldap==4.1.0
# django-crispy-forms
django-auth-ldap==5.1.0
# via -r requirements.in
django-crispy-forms==1.14.0
django-crispy-forms==2.3
# via -r requirements.in
gunicorn==20.1.0
exceptiongroup==1.2.2
# via pytest
gunicorn==23.0.0
# via -r requirements.in
idna==3.3
idna==3.10
# via requests
iniconfig==2.1.0
# via pytest
packaging==24.2
# via
# gunicorn
# pytest
passlib==1.7.4
# via -r requirements.in
pyasn1==0.4.8
pluggy==1.5.0
# via pytest
pyasn1==0.6.1
# via
# pyasn1-modules
# python-ldap
pyasn1-modules==0.2.8
pyasn1-modules==0.4.2
# via python-ldap
pycrypto==2.6.1
pycparser==2.22
# via cffi
pytest==8.3.5
# via
# -r requirements.in
# pytest-django
pytest-django==4.11.1
# via -r requirements.in
python-ldap==3.4.0
python-ldap==3.4.4
# via django-auth-ldap
requests==2.28.0
requests==2.32.3
# via -r requirements.in
sqlparse==0.4.2
sqlparse==0.5.3
# via django
urllib3==1.26.9
tomli==2.2.1
# via pytest
typing-extensions==4.13.2
# via asgiref
urllib3==2.4.0
# via requests
# The following packages are considered to be unsafe in a requirements file:
# setuptools