update dependencies, replace pycrypto with cryptography
This commit is contained in:
parent
2623444b11
commit
35b4313ad1
7 changed files with 109 additions and 45 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -4,3 +4,4 @@ local_settings.py
|
|||
build
|
||||
*.sqlite3
|
||||
*~
|
||||
venv*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
# initialization vector
|
||||
iv = os.urandom(16) # random.read(16)
|
||||
cipher = Cipher(algorithms.AES(key), modes.CFB(iv), backend=default_backend())
|
||||
encryptor = cipher.encryptor()
|
||||
|
||||
# do the encryption
|
||||
aes = AES.new(key, AES.MODE_CFB, iv)
|
||||
message = iv + aes.encrypt(cleartext_pw.encode())
|
||||
ciphertext = encryptor.update(cleartext_pw.encode()) + encryptor.finalize()
|
||||
|
||||
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):
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
5
pytest.ini
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# pytest.ini
|
||||
[pytest]
|
||||
DJANGO_SETTINGS_MODULE = cbmi.settings
|
||||
python_files = tests.py test_*.py *_tests.py
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue