Add bcrypt_test_db, secure_connection

This commit is contained in:
2023-09-15 13:27:34 -04:00
parent 1b4ba81ab0
commit 0a64bb27ba
4 changed files with 277 additions and 0 deletions

View File

@ -0,0 +1,111 @@
#!/usr/bin/env python3
"""crypto_server.py
----------------
This module contains utilities for generating and storing server keys and
certificates for the Pylandia Secure Email Initiative. It utilizes the
`cryptography` library to create a private key and a self-signed certificate,
which are then saved to specified paths.
Functions:
- parse_args() -> Namespace: Parses the command line arguments.
- generate_key_pair(storage_path: Path): Generates a key pair and a
certificate and writes them to the specified storage path.
"""
from argparse import ArgumentParser, Namespace
from datetime import datetime, timedelta
from pathlib import Path
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509.oid import NameOID
def parse_args() -> Namespace:
"""Parses the command line arguments for the script.
Returns:
Namespace: A namespace object that holds the command line arguments as
attributes.
"""
parser = ArgumentParser(description="Pylandia Server Key Generator")
parser.add_argument(
"-p",
"--path",
default="server_keys",
help="Path to save private and public keys",
)
return parser.parse_args()
def generate_key_pair(storage_path: Path):
"""Generates a private key and a self-signed certificate and saves them to
the specified storage path.
Args:
storage_path (Path): The directory where the private key and certificate
files should be saved.
Returns:
None
"""
private_key = rsa.generate_private_key(
public_exponent=65537, key_size=4096, backend=default_backend()
)
subject = issuer = x509.Name(
[
x509.NameAttribute(NameOID.COUNTRY_NAME, "PY"),
x509.NameAttribute(
NameOID.STATE_OR_PROVINCE_NAME, "Central Province"
),
x509.NameAttribute(NameOID.LOCALITY_NAME, "Pylandia City"),
x509.NameAttribute(
NameOID.ORGANIZATION_NAME, "Pylandia Secure Email Initiative"
),
x509.NameAttribute(NameOID.COMMON_NAME, "securemail.pylandia"),
]
)
cert = (
x509.CertificateBuilder()
.subject_name(subject)
.issuer_name(issuer)
.public_key(private_key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(datetime.utcnow())
.not_valid_after(datetime.utcnow() + timedelta(days=365))
.add_extension(
x509.SubjectAlternativeName([x509.DNSName("localhost")]),
critical=False,
)
.sign(private_key, hashes.SHA256(), default_backend())
)
if not storage_path.exists():
storage_path.mkdir(parents=True)
publickey_path = storage_path / "cert.pem"
with publickey_path.open("wb") as file:
file.write(cert.public_bytes(serialization.Encoding.PEM))
privatekey_path = storage_path / "key.pem"
with privatekey_path.open("wb") as file:
file.write(
private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
)
)
if __name__ == "__main__":
args = parse_args()
storage = args.path
full_storage_path = Path(storage)
generate_key_pair(full_storage_path)

View File

@ -0,0 +1,39 @@
#!/usr/bin/env python3
"""
A module to establish a non-verifying SSL connection with a server and to
send/receive messages through a secure socket.
Usage:
Run the script to start a communication session with the server at
"127.0.0.1" on port 9001. Input messages in the console to send to
the server and receive replies. Type a message with the content
"quit" to close the connection.
Functions:
main(server_address: str, server_port: int): Initiates a secure socket
communication session with the specified server.
"""
from socket import create_connection, socket
from ssl import SSLContext, PROTOCOL_TLS_CLIENT, CERT_NONE
def main(server_address: str, server_port: int):
context = SSLContext(PROTOCOL_TLS_CLIENT)
context.check_hostname = False
context.verify_mode = CERT_NONE
unsecure_socket: socket = create_connection(
(server_address, server_port)
)
secure_socket = context.wrap_socket(unsecure_socket) #, server_hostname="localhost")
while True:
message = input()
secure_socket.send(message.encode("utf-8"))
reply = secure_socket.recv(len(message))
if reply == b"quit":
break
print(reply.decode("utf-8"))
if __name__ == "__main__":
main("127.0.0.1", 9001)

View File

@ -0,0 +1,54 @@
#!/usr/bin/env python3
"""
This module facilitates creating an asynchronous SSL server that echoes
received messages. The server operates using SSL certificates stored in
the "server_keys" directory.
Usage:
Run the script to initiate the server on "localhost" at port 9001.
It listens for incoming connections and echoes messages unless "quit"
is received, which terminates the connection.
Functions:
handle_client(reader: StreamReader, writer: StreamWriter) -> None:
Handles the communication with a connected client asynchronously.
main(address: str, port: int) -> None:
Sets up and starts the SSL server with the necessary certificates.
"""
import logging
from asyncio import StreamReader, StreamWriter, run, start_server
from pathlib import Path
from ssl import Purpose, create_default_context
async def handle_client(reader: StreamReader, writer: StreamWriter):
while True:
msg_bytes = await reader.read(10)
if msg_bytes == b"quit":
writer.write(b"quit")
await writer.drain()
break
writer.write(msg_bytes)
await writer.drain()
async def main(address: str, port: int):
storage_path: Path = Path("server_keys")
keyfile = storage_path / "key.pem"
certfile = storage_path / "cert.pem"
context = create_default_context(Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile, keyfile)
server = await start_server(handle_client, address, port, ssl=context)
service_socket = server.sockets[0].getsockname()
logging.info("Serving on %s", service_socket)
async with server:
await server.serve_forever()
if __name__ == "__main__":
run(main("localhost", 9001))