Projekt

Obecné

Profil

« Předchozí | Další » 

Revize f16fb9e7

Přidáno uživatelem Stanislav Král před asi 4 roky(ů)

Re #8472 - Added CryptographyService class and implemented a method to generate private keys

Added CryptographyException exception that is thrown when incorrect parameters are passed to openssl or when openssl process exits with non-zero return code.
Added 3 unit tests verifying the validity of the private key generation.

Zobrazit rozdíly:

services/cryptography.py
1
import subprocess
2

  
3
# encryption method to be used when generating private keys
4
PRIVATE_KEY_ENCRYPTION_METHOD = "-aes256"
5

  
6
# openssl executable name
7
OPENSSL_EXECUTABLE = "openssl"
8

  
9

  
10
class CryptographyService:
11

  
12
    @staticmethod
13
    def _run_for_output(args=None, stdin=None, executable=OPENSSL_EXECUTABLE):
14
        """
15
        Launches a new process in which the given executable is run. STDIN and process arguments can be set.
16
        If the process ends with a non-zero then <CryptographyException> is raised.
17
        :param args: Arguments to be passed to the program.
18
        :param stdin: Arguments to be passed to the process.
19
        :param executable: Executable to be run (defaults to openssl)
20
        :return: If the process ends with a zero return code then the STDOUT of the process is returned as a byte array.
21
        """
22
        if args is None:
23
            args = []
24
        try:
25
            # prepend the name of the executable
26
            args.insert(0, executable)
27

  
28
            # create a new process
29
            proc = subprocess.Popen(args, stdin=stdin, stdout=subprocess.PIPE,
30
                                    stderr=subprocess.PIPE)
31

  
32
            # get process result
33
            out, err = proc.communicate()
34

  
35
            if proc.returncode != 0:
36
                # if the process did not result in zero result code, then raise an exception
37
                if err is not None:
38
                    raise CryptographyException(err.decode())
39
                else:
40
                    raise CryptographyException(
41
                        f""""{executable} with parameters {args} resulted in non-zero argument""")
42

  
43
            return out
44
        except FileNotFoundError:
45
            raise CryptographyException(f""""{executable}" not found in the current PATH.""")
46

  
47
    def create_private_key(self, passphrase=None):
48
        """
49
        Creates a private key with the option to encrypt it using a passphrase.
50
        :param passphrase: A passphrase to be used when encrypting the key (if none is passed then the key is not
51
        encrypted at all). Empty passphrase ("") also results in a key that is not encrypted.
52
        :return: A text representation of the generated private key.
53
        """
54
        if passphrase is None or len(passphrase) == 0:
55
            return self._run_for_output(["genrsa", "2048"]).decode()
56
        else:
57
            return self._run_for_output(
58
                ["genrsa", PRIVATE_KEY_ENCRYPTION_METHOD, "-passout", f"pass:{passphrase}", "2048"]).decode()
59

  
60

  
61
class CryptographyException(Exception):
62

  
63
    def __init__(self, message):
64
        self.message = message
tests/services/cryptography_test.py
1
import pytest
2
from services.cryptography import CryptographyService, CryptographyException
3
import subprocess
4

  
5

  
6
@pytest.fixture
7
def service():
8
    # provide a CryptographyService fixture
9
    return CryptographyService()
10

  
11

  
12
def test_private_key(service):
13
    private_key = service.create_private_key()
14

  
15
    # verify the private key
16
    subprocess.check_output(["openssl", "rsa", "-in", "-", "-check"], input=bytes(private_key, encoding="utf-8"),
17
                            stderr=subprocess.STDOUT)
18

  
19

  
20
def test_encrypted_private_key(service):
21
    private_key = service.create_private_key(passphrase="foobar")
22

  
23
    # verify the private key providing a correct passphrase
24
    subprocess.check_output(["openssl", "rsa", "-in", "-", "-passin", "pass:foobar", "-check"],
25
                            input=bytes(private_key, encoding="utf-8"), stderr=subprocess.STDOUT)
26

  
27

  
28
def test_encrypted_private_key_incorrect_pass(service):
29
    private_key = service.create_private_key(passphrase="foobar")
30

  
31
    # incorrect passphrase provided
32
    with pytest.raises(subprocess.CalledProcessError) as e:
33
        subprocess.check_output(["openssl", "rsa", "-in", "-", "-passin", "pass:bazbaz", "-check"],
34
                                input=bytes(private_key, encoding="utf-8"), stderr=subprocess.STDOUT)
35
    # no passphrase provided
36
    with pytest.raises(subprocess.CalledProcessError) as e:
37
        subprocess.check_output(["openssl", "rsa", "-in", "-", "-check"],
38
                                input=bytes(private_key, encoding="utf-8"), stderr=subprocess.STDOUT)

Také k dispozici: Unified diff