forked from shaba/openuds
Updated crypto manager to use cryptography instead of pyCrypto
This commit is contained in:
parent
2b4a0113a2
commit
3bc08d6b86
@ -308,8 +308,6 @@ def webPassword(request: HttpRequest) -> str:
|
|||||||
The password is stored at session using a simple scramble algorithm that keeps the password splited at
|
The password is stored at session using a simple scramble algorithm that keeps the password splited at
|
||||||
session (db) and client browser cookies. This method uses this two values to recompose the user password
|
session (db) and client browser cookies. This method uses this two values to recompose the user password
|
||||||
so we can provide it to remote sessions.
|
so we can provide it to remote sessions.
|
||||||
@param request: DJango Request
|
|
||||||
@return: Unscrambled user password
|
|
||||||
"""
|
"""
|
||||||
return cryptoManager().symDecrpyt(request.session.get(PASS_KEY, ''), getUDSCookie(request)) # recover as original unicode string
|
return cryptoManager().symDecrpyt(request.session.get(PASS_KEY, ''), getUDSCookie(request)) # recover as original unicode string
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ class DelayedTaskRunner:
|
|||||||
now = getSqlDatetime()
|
now = getSqlDatetime()
|
||||||
exec_time = now + timedelta(seconds=delay)
|
exec_time = now + timedelta(seconds=delay)
|
||||||
cls = instance.__class__
|
cls = instance.__class__
|
||||||
instanceDump = encoders.encode(pickle.dumps(instance), 'base64', asText=True)
|
instanceDump = encoders.encodeAsStr(pickle.dumps(instance), 'base64')
|
||||||
typeName = str(cls.__module__ + '.' + cls.__name__)
|
typeName = str(cls.__module__ + '.' + cls.__name__)
|
||||||
|
|
||||||
logger.debug('Inserting delayed task %s with %s bytes (%s)', typeName, len(instanceDump), exec_time)
|
logger.debug('Inserting delayed task %s with %s bytes (%s)', typeName, len(instanceDump), exec_time)
|
||||||
|
@ -30,40 +30,41 @@
|
|||||||
"""
|
"""
|
||||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
"""
|
"""
|
||||||
import typing
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import array
|
import array
|
||||||
import uuid
|
import uuid
|
||||||
import struct
|
import struct
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import typing
|
||||||
|
|
||||||
|
from cryptography import x509
|
||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
from cryptography.hazmat.primitives import hashes
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import padding
|
||||||
|
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||||
|
|
||||||
|
|
||||||
|
# Deprecating these. On future versions will only use
|
||||||
|
# cryptography libraries. Keep here for backwards compat with
|
||||||
|
# 1.x 2.x encriptions methods
|
||||||
from Crypto.PublicKey import RSA
|
from Crypto.PublicKey import RSA
|
||||||
from Crypto.Cipher import AES
|
|
||||||
from Crypto.Random import atfork # type: ignore
|
from Crypto.Random import atfork # type: ignore
|
||||||
|
|
||||||
from OpenSSL import crypto
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from uds.core.util import encoders
|
from uds.core.util import encoders
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# To generate an rsa key, first we need the crypt module
|
|
||||||
# next, we do:
|
|
||||||
# from Crypto.PublicKey import RSA
|
|
||||||
# import os
|
|
||||||
# RSA.generate(1024, os.urandom).exportKey()
|
|
||||||
|
|
||||||
|
|
||||||
class CryptoManager:
|
class CryptoManager:
|
||||||
instance = None
|
instance = None
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._rsa = RSA.importKey(settings.RSA_KEY)
|
self._rsa = serialization.load_pem_private_key( settings.RSA_KEY.encode(), password=None, backend=default_backend())
|
||||||
|
self._oldRsa = RSA.importKey(settings.RSA_KEY)
|
||||||
self._namespace = uuid.UUID('627a37a5-e8db-431a-b783-73f7d20b4934')
|
self._namespace = uuid.UUID('627a37a5-e8db-431a-b783-73f7d20b4934')
|
||||||
self._counter = 0
|
self._counter = 0
|
||||||
|
|
||||||
@ -94,30 +95,61 @@ class CryptoManager:
|
|||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
value = value.encode('utf-8')
|
value = value.encode('utf-8')
|
||||||
|
|
||||||
atfork()
|
return encoders.encodeAsStr(
|
||||||
return typing.cast(str, encoders.encode((self._rsa.encrypt(value, b'')[0]), 'base64', asText=True))
|
self._rsa.public_key().encrypt(
|
||||||
|
value,
|
||||||
|
padding.OAEP(
|
||||||
|
mgf=padding.MGF1(algorithm=hashes.SHA256()),
|
||||||
|
algorithm=hashes.SHA256(),
|
||||||
|
label=None
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'base64'
|
||||||
|
)
|
||||||
|
|
||||||
|
# atfork()
|
||||||
|
# return typing.cast(str, encoders.encode((self._rsa.encrypt(value, b'')[0]), 'base64', asText=True))
|
||||||
|
|
||||||
|
|
||||||
def decrypt(self, value: typing.Union[str, bytes]) -> str:
|
def decrypt(self, value: typing.Union[str, bytes]) -> str:
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
value = value.encode('utf-8')
|
value = value.encode('utf-8')
|
||||||
# import inspect
|
|
||||||
|
data: bytes = typing.cast(bytes, encoders.decode(value, 'base64'))
|
||||||
|
decrypted: bytes
|
||||||
|
|
||||||
try:
|
try:
|
||||||
atfork()
|
# First, try new "cryptografy" decrpypting
|
||||||
return str(self._rsa.decrypt(encoders.decode(value, 'base64')).decode('utf-8'))
|
decrypted = self._rsa.decrypt(
|
||||||
except Exception:
|
data,
|
||||||
logger.exception('Decripting: %s', value)
|
padding.OAEP(
|
||||||
# logger.error(inspect.stack())
|
mgf=padding.MGF1(algorithm=hashes.SHA256()),
|
||||||
return 'decript error'
|
algorithm=hashes.SHA256(),
|
||||||
|
label=None
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except Exception: # If fails, try old method
|
||||||
|
try:
|
||||||
|
atfork()
|
||||||
|
decrypted = self._oldRsa.decrypt(encoders.decode(value, 'base64'))
|
||||||
|
except Exception:
|
||||||
|
logger.exception('Decripting: %s', value)
|
||||||
|
# logger.error(inspect.stack())
|
||||||
|
return 'decript error'
|
||||||
|
|
||||||
|
return decrypted.decode()
|
||||||
|
|
||||||
def AESCrypt(self, text: bytes, key: bytes, base64: bool = False) -> bytes:
|
def AESCrypt(self, text: bytes, key: bytes, base64: bool = False) -> bytes:
|
||||||
# First, match key to 16 bytes. If key is over 16, create a new one based on key of 16 bytes length
|
# First, match key to 16 bytes. If key is over 16, create a new one based on key of 16 bytes length
|
||||||
cipher = AES.new(CryptoManager.AESKey(key, 16), AES.MODE_CBC, 'udsinitvectoruds')
|
cipher = Cipher(algorithms.AES(CryptoManager.AESKey(key, 16)), modes.CBC(b'udsinitvectoruds'), backend=default_backend())
|
||||||
rndStr = self.randomString(cipher.block_size).encode('utf8')
|
rndStr = self.randomString(16).encode() # Same as block size of CBC (that is 16 here)
|
||||||
paddedLength = ((len(text) + 4 + 15) // 16) * 16
|
paddedLength = ((len(text) + 4 + 15) // 16) * 16
|
||||||
toEncode = struct.pack('>i', len(text)) + text + rndStr[:paddedLength - len(text) - 4]
|
toEncode = struct.pack('>i', len(text)) + text + rndStr[:paddedLength - len(text) - 4]
|
||||||
encoded = cipher.encrypt(toEncode)
|
encryptor = cipher.encryptor()
|
||||||
|
encoded = encryptor.update(toEncode) + encryptor.finalize()
|
||||||
|
|
||||||
if base64:
|
if base64:
|
||||||
return typing.cast(bytes, encoders.encode(encoded, 'base64', asText=False)) # Return as binary
|
return typing.cast(bytes, encoders.encode(encoded, 'base64')) # Return as binary
|
||||||
|
|
||||||
return encoded
|
return encoded
|
||||||
|
|
||||||
@ -125,8 +157,10 @@ class CryptoManager:
|
|||||||
if base64:
|
if base64:
|
||||||
text = typing.cast(bytes, encoders.decode(text, 'base64'))
|
text = typing.cast(bytes, encoders.decode(text, 'base64'))
|
||||||
|
|
||||||
cipher = AES.new(CryptoManager.AESKey(key, 16), AES.MODE_CBC, 'udsinitvectoruds')
|
cipher = Cipher(algorithms.AES(CryptoManager.AESKey(key, 16)), modes.CBC(b'udsinitvectoruds'), backend=default_backend())
|
||||||
toDecode = cipher.decrypt(text)
|
decryptor = cipher.decryptor()
|
||||||
|
|
||||||
|
toDecode = decryptor.update(text) + decryptor.finalize()
|
||||||
return toDecode[4:4 + struct.unpack('>i', toDecode[:4])[0]]
|
return toDecode[4:4 + struct.unpack('>i', toDecode[:4])[0]]
|
||||||
|
|
||||||
def xor(self, s1: typing.Union[str, bytes], s2: typing.Union[str, bytes]) -> bytes:
|
def xor(self, s1: typing.Union[str, bytes], s2: typing.Union[str, bytes]) -> bytes:
|
||||||
@ -153,12 +187,15 @@ class CryptoManager:
|
|||||||
raise e
|
raise e
|
||||||
return pk
|
return pk
|
||||||
|
|
||||||
def loadCertificate(self, certificate: str):
|
def loadCertificate(self, certificate: typing.Union[str, bytes]):
|
||||||
|
if isinstance(certificate, str):
|
||||||
|
certificate = certificate.encode()
|
||||||
|
|
||||||
|
# If invalid certificate, will raise an exception
|
||||||
try:
|
try:
|
||||||
cert = crypto.load_certificate(crypto.FILETYPE_PEM, certificate)
|
return x509.load_pem_x509_certificate(certificate, default_backend())
|
||||||
except crypto.Error as e:
|
except Exception:
|
||||||
raise Exception(e.message[0][2])
|
raise Exception('Invalid certificate')
|
||||||
return cert
|
|
||||||
|
|
||||||
def certificateString(self, certificate: str) -> str:
|
def certificateString(self, certificate: str) -> str:
|
||||||
return certificate.replace('-----BEGIN CERTIFICATE-----', '').replace('-----END CERTIFICATE-----', '').replace('\n', '')
|
return certificate.replace('-----BEGIN CERTIFICATE-----', '').replace('-----END CERTIFICATE-----', '').replace('\n', '')
|
||||||
|
Loading…
Reference in New Issue
Block a user