Python: cryptography private key public key generation, serialization, encryption and decryption, signature verification

cryptography is a package designed to expose cryptographic primitives and recipes to Python developers.

Translation: cryptography is a package designed to expose cryptographic primitives and recipes to Python developers.

Table of Contents

    • document
    • Install
    • example
      • 1. Generate private key and obtain public key
      • 2. Private key and public key serialization
      • 3. Deserialization of private key and public key
      • 4. Public key encryption and private key decryption
      • 5. Private key signature public key signature verification
    • source code
      • RSAPrivateKey source code
    • RSAPublicKey source code

Documentation

  • https://github.com/pyca/cryptography
  • https://pypi.org/project/cryptography/
  • https://cryptography.io/en/latest/
  • https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa/

Install

pip install cryptography

Example

1. Generate private key and obtain public key

# -*- coding: utf-8 -*-

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa

# generate private key
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
    backend=default_backend()
)

# Get the public key
public_key = private_key. public_key()

2. Private key and public key serialization

# private key serialization
private_key_pem = private_key. private_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PrivateFormat.PKCS8,
    encryption_algorithm = serialization. NoEncryption()
)

# save the private key to a file
with open('private.key', 'wb') as f:
    f.write(private_key_pem)


# public key serialization
public_key_pem = public_key. public_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PublicFormat.SubjectPublicKeyInfo
)

# save the public key to a file
with open('public.pem', 'wb') as f:
    f.write(public_key_pem)

3. Deserialization of private key and public key

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization

# load private key from file
with open("private.key", "rb") as private_key_file:
    private_key = serialization.load_pem_private_key(
        private_key_file. read(),
        password=None,
        backend=default_backend()
    )

# load public key from file
with open("public.pem", "rb") as public_pem_file:
    public_key = serialization.load_pem_public_key(
        public_pem_file. read(),
        backend=default_backend()
    )

4. Public key encryption and private key decryption

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

# public key decryption
message = 'Hello'

encrypted = public_key.encrypt(
    plaintext=message.encode('utf-8'),
    padding = padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

print(encrypted)
# b'm\xf2\x8d\xa84\xbe\x13\xe1...'

# Decrypt with private key
original_message = private_key. decrypt(
    ciphertext=encrypted,
    padding = padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

print(original_message. decode('utf-8'))
#Hello

5. Private key signature public key verification

# -*- coding: utf-8 -*-

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

# private key signature
message = 'Hello'

signature = private_key. sign(
    data=message.encode('utf-8'),
    padding = padding.PSS(
        mgf=padding.MGF1(hashes.SHA256()),
        salt_length=padding.PSS.MAX_LENGTH
    ),
    algorithm=hashes.SHA256()
)
print(signature)
# b'm\xf2\x8d\xa84\xbe\x13\xe1...'

# Public key verification If the verification fails, an exception is thrown cryptography.exceptions.InvalidSignature
public_key. verify(
    signature=signature,
    data='Hello'.encode('utf-8'),
    padding = padding.PSS(
        mgf=padding.MGF1(hashes.SHA256()),
        salt_length=padding.PSS.MAX_LENGTH
    ),
    algorithm=hashes.SHA256()
)

Source code

RSAPrivateKey source code

cryptography/hazmat/primitives/asymmetric/rsa.py

class RSAPrivateKey(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def decrypt(self, ciphertext: bytes, padding: AsymmetricPadding) -> bytes:
        """
        Decrypts the provided ciphertext.
        """

    @abc.abstractproperty
    def key_size(self) -> int:
        """
        The bit length of the public modulus.
        """

    @abc.abstractmethod
    def public_key(self) -> "RSAPublicKey":
        """
        The RSAPublicKey associated with this private key.
        """

    @abc.abstractmethod
    def sign(
        self,
        data: bytes,
        padding: Asymmetric Padding,
        algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm],
    ) -> bytes:
        """
        Signs the data.
        """

    @abc.abstractmethod
    def private_numbers(self) -> "RSAPrivateNumbers":
        """
        Returns an RSAPrivateNumbers.
        """

    @abc.abstractmethod
    def private_bytes(
        self,
        encoding: _serialization. Encoding,
        format: _serialization. PrivateFormat,
        encryption_algorithm: _serialization.KeySerializationEncryption,
    ) -> bytes:
        """
        Returns the key serialized as bytes.
        """

RSAPublicKey source code

cryptography/hazmat/primitives/asymmetric/rsa.py

class RSAPublicKey(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def encrypt(self, plaintext: bytes, padding: AsymmetricPadding) -> bytes:
        """
        Encrypts the given plaintext.
        """

    @abc.abstractproperty
    def key_size(self) -> int:
        """
        The bit length of the public modulus.
        """

    @abc.abstractmethod
    def public_numbers(self) -> "RSAPublicNumbers":
        """
        Returns an RSAPublicNumbers
        """

    @abc.abstractmethod
    def public_bytes(
        self,
        encoding: _serialization. Encoding,
        format: _serialization. PublicFormat,
    ) -> bytes:
        """
        Returns the key serialized as bytes.
        """

    @abc.abstractmethod
    def verify(
        self,
        signature: bytes,
        data: bytes,
        padding: Asymmetric Padding,
        algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm],
    ) -> None:
        """
        Verifies the signature of the data.
        """

    @abc.abstractmethod
    def recover_data_from_signature(
        self,
        signature: bytes,
        padding: Asymmetric Padding,
        algorithm: typing. Optional[hashes. HashAlgorithm],
    ) -> bytes:
        """
        Recovers the original data from the signature.
        """

reference article

    1. RSA encryption using cryptography