Blog | G5 Cyber Security

PKI Authentication with Python

TL;DR

This guide shows you how to use Public Key Infrastructure (PKI) for secure service authentication in Python using the pycrypto library. We’ll cover generating keys, creating certificates, and verifying signatures.

Prerequisites

1. Generating a Key Pair

  1. Import the necessary modules from pycrypto:
    from Crypto.PublicKey import RSA
    from Crypto.Cipher import PKCS1_v1_5
    
  2. Generate an RSA key pair (2048 bits is a good starting point):
    key = RSA.generate(2048)
    private_key = key
    public_key = key.publickey()
    
  3. Save the private and public keys to files (important! Keep your private key secure):
    with open('private.pem', 'wb') as f:
        f.write(private_key.exportKey('PEM'))
    
    with open('public.pem', 'wb') as f:
        f.write(public_key.exportKey('PEM'))
    

2. Creating a Certificate (Simplified)

For production, you’d use a proper Certificate Authority (CA). This example creates a self-signed certificate for testing purposes only.

  1. You will need to create a dummy X.509 certificate using an external tool like OpenSSL or a library such as cryptography. For simplicity, we assume you have a certificate.pem file.
    # Example command for generating a self-signed cert (OpenSSL):
    # openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out certificate.pem -days 365
    
  2. Load the certificate:
    from Crypto.PublicKey import RSA
    from Crypto.Cipher import PKCS1_v1_5
    
    with open('certificate.pem', 'r') as f:
        certificate = f.read()
    

3. Signing Data

  1. Import the signing module:
    from Crypto.Hash import SHA256
    from Crypto.Signature import PKCS1_v1_5
    
  2. Prepare the data to be signed (e.g., a message):
    message = b'This is the data I want to sign.'
    
  3. Create a hash object:
    hash_object = SHA256.new(message)
    
  4. Sign the message using your private key:
    signer = PKCS1_v1_5.new(private_key)
    hash_signed = signer.sign(hash_object)
    

4. Verifying the Signature

  1. Load your public key:
    with open('public.pem', 'rb') as f:
        public_key = RSA.importKey(f.read())
    
  2. Create a verifier object using the public key:
    verifier = PKCS1_v1_5.new(public_key)
    
  3. Verify the signature:
    try:
        verifier.verify(hash_object, hash_signed)
        print('Signature is valid.')
    except ValueError:
        print('Signature is invalid.')
    

5. Complete Example

Here’s a complete example combining the steps:

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from Crypto.Hash import SHA256
from Crypto.Signature import PKCS1_v1_5

# Generate key pair (if not already done)
try:
    key = RSA.generate(2048)
    private_key = key
    public_key = key.publickey()
except ValueError as e:
    print(f"Error generating keys: {e}")
    exit()

# Save keys (if not already done)
with open('private.pem', 'wb') as f:
    f.write(private_key.exportKey('PEM'))

with open('public.pem', 'wb') as f:
    f.write(public_key.exportKey('PEM'))

# Load keys
with open('private.pem', 'rb') as f:
    private_key = RSA.importKey(f.read())

with open('public.pem', 'rb') as f:
    public_key = RSA.importKey(f.read())

# Data to be signed
message = b'This is the data I want to sign.'

# Sign the message
hash_object = SHA256.new(message)
signer = PKCS1_v1_5.new(private_key)
hash_signed = signer.sign(hash_object)

# Verify the signature
verifier = PKCS1_v1_5.new(public_key)
try:
    verifier.verify(hash_object, hash_signed)
    print('Signature is valid.')
except ValueError:
    print('Signature is invalid.')

Important Considerations

Exit mobile version