mms-client 1.0.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -0,0 +1,44 @@
1
+ """Contains functionality associated with certificates."""
2
+
3
+ from pathlib import Path
4
+ from typing import Union
5
+
6
+ from requests_pkcs12 import Pkcs12Adapter
7
+
8
+
9
+ class Certificate:
10
+ """Describes a certificate composed of a cert file and a key file."""
11
+
12
+ def __init__(self, cert: Union[str, Path, bytes], passphrase: str):
13
+ """Create a new Certificate.
14
+
15
+ Creates a new certificate from the absolute path to the certificate file and a passpharse.
16
+
17
+ Arguments:
18
+ cert: The certificate file. If a string, it should be the absolute path to the certificate file. If
19
+ bytes, it should be the contents of the certificate file.
20
+ passphrase: The passphrase the certificate is encrypted with
21
+ """
22
+ # Get the certificate file contents
23
+ if isinstance(cert, (str, Path)):
24
+ with open(cert, "rb") as file:
25
+ self._cert = file.read()
26
+ else:
27
+ self._cert = cert
28
+
29
+ # Save the passphrase
30
+ self._passphrase = passphrase
31
+
32
+ @property
33
+ def certificate(self) -> bytes:
34
+ """Return the certificate data."""
35
+ return self._cert
36
+
37
+ @property
38
+ def passphrase(self) -> str:
39
+ """Return the full path to the passphrase."""
40
+ return self._passphrase
41
+
42
+ def to_adapter(self) -> Pkcs12Adapter:
43
+ """Convert the certificate to a Pkcs12Adapter."""
44
+ return Pkcs12Adapter(pkcs12_data=self._cert, pkcs12_password=self._passphrase)
@@ -0,0 +1,57 @@
1
+ """Contains objects for cryptographic operations."""
2
+
3
+ from base64 import b64encode
4
+ from hashlib import sha256
5
+
6
+ from cryptography.hazmat.backends import default_backend
7
+ from cryptography.hazmat.primitives import hashes
8
+ from cryptography.hazmat.primitives.asymmetric import padding
9
+ from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey
10
+ from cryptography.hazmat.primitives.serialization.pkcs12 import load_key_and_certificates
11
+
12
+ from mms_client.security.certs import Certificate
13
+
14
+
15
+ class CryptoWrapper:
16
+ """Wraps the cryptographic operations necessary for signing and encrypting MMS payload data."""
17
+
18
+ def __init__(self, cert: Certificate):
19
+ """Create a new CryptoWrapper with the given certificate.
20
+
21
+ Arguments:
22
+ cert (Certificate): The certificate to use for cryptographic operations.
23
+ """
24
+ # First, save our certificate for later use
25
+ self._cert = cert
26
+
27
+ # Next, import the private key from the certificate
28
+ private_key, _, _ = load_key_and_certificates(
29
+ self._cert.certificate, self._cert.passphrase.encode(), default_backend()
30
+ )
31
+
32
+ # Now, we need to assert typing on this private key to make mypy happy
33
+ if isinstance(private_key, RSAPrivateKey):
34
+ self._private_key = private_key
35
+ else:
36
+ raise TypeError(f"Private key of type ({type(private_key).__name__}) was not expected.")
37
+
38
+ # Finally, save our padding and algorithm for later use
39
+ self._padding = padding.PKCS1v15()
40
+ self._algorithm = hashes.SHA256()
41
+
42
+ def sign(self, data: bytes) -> bytes:
43
+ """Create a signature from the given data using the certificate.
44
+
45
+ Arguments:
46
+ data (bytes): The data to be encrypted.
47
+
48
+ Returns: A base64-encoded string containing the signature.
49
+ """
50
+ # First, hash the data using SHA256
51
+ hashed = sha256(data)
52
+
53
+ # Next, sign the hash using the private key
54
+ signature = self._private_key.sign(hashed.digest(), self._padding, self._algorithm)
55
+
56
+ # Finally, return the base64-encoded signature
57
+ return b64encode(signature)
File without changes