The flow of creating digital signatures and verification in Python
Tags: python, certification
Published: 2024-06-03 01:27:46

This flow demonstrates how to create and verify a digital signature using the `cryptography` library in Python. This process ensures the authenticity and integrity of the message, confirming that it was signed by the holder of the private key and has not been altered.
There are main 3 steps.

1. **Generate Key Pair:**
   - **Private Key**: Created using RSA, with a public exponent of 65537 and a key size of 2048 bits.
   - **Public Key**: Derived from the private key.
   - **Storage**: Both keys are saved to files in PEM format.

2. **Sign the Message:**
   - **Message**: The data to be signed.
   - **Hash Function**: SHA-256 is used to hash the message.
   - **Padding**: PSS (Probabilistic Signature Scheme) with MGF1 (Mask Generation Function) and a maximum salt length is used for padding.
   - **Signature**: The message is signed using the private key, and the signature is saved to a file.

3. **Verify the Signature:**
   - **Public Key**: Loaded from the PEM file.
   - **Signature**: Loaded from the file.
   - **Message**: The original message that was signed.
   - **Verification**: The public key, along with the message and the signature, is used to verify the authenticity of the signature. If the signature is valid, it means the message was signed by the corresponding private key.

### Step 1: Install the Required Library

First, ensure you have the `cryptography` library installed. You can install it using pip:

```sh
pip install cryptography
```

### Step 2: Generate a Key Pair

A key pair consists of a private key (used for signing) and a public key (used for verification).

```python
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization

# Generate private key
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
)

# Generate public key from the private key
public_key = private_key.public_key()

# Save the private key to a file
with open("private_key.pem", "wb") as f:
    f.write(private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption()
    ))

# Save the public key to a file
with open("public_key.pem", "wb") as f:
    f.write(public_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo
    ))
```

### Step 3: Sign a Message

To create a digital signature, you'll use the private key to sign a message.

```python
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

# Message to be signed
message = b"Hello, this is a secret message!"

# Sign the message
signature = private_key.sign(
    message,
    padding.PSS(
        mgf=padding.MGF1(hashes.SHA256()),
        salt_length=padding.PSS.MAX_LENGTH
    ),
    hashes.SHA256()
)

# Save the signature to a file
with open("signature.bin", "wb") as f:
    f.write(signature)
```

### Step 4: Verify the Signature

To verify the signature, use the public key to check if it matches the message.

```python
# Load the public key
with open("public_key.pem", "rb") as f:
    public_key = serialization.load_pem_public_key(f.read())

# Load the signature
with open("signature.bin", "rb") as f:
    signature = f.read()

# Message to be verified
message = b"Hello, this is a secret message!"

# Verify the signature
try:
    public_key.verify(
        signature,
        message,
        padding.PSS(
            mgf=padding.MGF1(hashes.SHA256()),
            salt_length=padding.PSS.MAX_LENGTH
        ),
        hashes.SHA256()
    )
    print("The signature is valid.")
except:
    print("The signature is invalid.")
```