KeyManager

class privex.helpers.crypto.KeyManager.KeyManager(key: Union[str, bytes, cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization, cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization, cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey, cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey, cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey, cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey], password: Union[str, bytes] = None)[source]

Asymmetric key handling class - Generate, save, and load asymmetric keys, with signatures + encryption made easy.

A wrapper around cryptography.hazmat.primitives.asymmetric to make generation, saving, loading, AND usage of asymmetric keys easy.

Basic Usage

Using output_keypair() - you can generate a key pair, and output it at the same time:

>>> priv, pub = KeyManager.output_keypair('id_rsa', 'id_rsa.pub')
>>> pub
b'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDbzCL+Dn8B9jS404mETt8fb6+TJek1afFthSBi2qZ0iL8dbv/Go0ig...'

If you don’t want to output the key pair to a file, you can also just generate one and have the private/public keys purely returned as bytes:

>>> priv, pub = KeyManager.generate_keypair(alg='ed25519')
>>> priv
b'-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwB.....T2YxW/Xkz3PkMHrrYBvI0LbUPky
-----END PRIVATE KEY-----'
>>> pub
b'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICJ9OK6v2UGfCgWxzGdPlCQIps+lffLTWwuMLPdqfco6'

Loading a key for signature/encryption operations

You can load a private or public key directly from the string/bytes returned by generate_keypair() like so:

>>> km = KeyManager(priv)

Alternatively, you can load a key straight from disk using load_keyfile() - which will automatically detect the asymmetric algorithm, encoding/output format, and key type (public/private) and return a KeyManager instance:

>>> km = KeyManager.load_keyfile('id_rsa.pub')

Automatic public key generation

If you load a private key, then the constructor will automatically generate the matching public key for you, so that you can use all signature/encryption methods available for your key algorithm.

If you load a public key, then you will only be able to use methods which are available to public keys, such as verify() and encrypt() - you will NOT be able to use sign() or decrypt()

Manually accessing the public/private key class instances

If you need to access the raw cryptography PublicKey/PrivateKey instances, you can access them via the two attributes public_key and private_key after creating a KeyManager instance:

>>> km.public_key
<cryptography.hazmat.backends.openssl.rsa._RSAPublicKey object at 0x7f953848c438>
>>> km.private_key
<cryptography.hazmat.backends.openssl.rsa._RSAPrivateKey object at 0x7f95381c1ef0>

Signing, verification, and en/decryption

Once you have a KeyManager instance, you can now use the signing, verification, and en/decryption methods using the loaded key.

Most key algorithms support signing and verification, which can be done using sign() and verify() respectively.

Sensible values for things like padding/hash algorithms are set by default, so you can simply call sign() with just a message, and verify() with just the signature + message:

>>> sig = km.sign('hello world')
>>> km.verify(signature=sig, message='hello world')  # Raises InvalidSignature if it was invalid
True

With RSA keys, you can also encrypt() using the public key, and decrypt() using the private key:

>>> msg = km.encrypt('my secret message')
>>> km.decrypt(msg)
b'my secret message'
__init__(key: Union[str, bytes, cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization, cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization, cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey, cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey, cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey, cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey], password: Union[str, bytes] = None)[source]

Create an instance of KeyManager using the public/private key data key

If you want to load the key from a file instead of passing it’s data / key class instance, then you should use load_keyfile() instead to create the class instance.

You do NOT need to initialize this class if you’re simply using the class methods / static methods such as generate_keypair() or load_key() - only to use the normal instance methods which require a loaded public/private key, such as sign()

Parameters
  • key – The public/private key data, as either a string, bytes, or one of the various private key class instances or public key class instances (see public_key_types and private_key_types)

  • password (str|bytes) – If your key data is encrypted, pass the password in this argument to decrypt it.

Methods

Methods

__init__(key[, password])

Create an instance of KeyManager using the public/private key data key

decrypt(message[, pad, hashing])

Decrypt a message using the loaded private_key - returns the decrypted message as bytes.

encrypt(message[, pad, hashing])

Encrypt a message using the loaded public_key - returns the ciphertext as base64 encoded bytes.

export_key(key, **kwargs)

Export/serialize a given public/private key object as bytes.

export_private(**kwargs)

Serialize the cryptography private key instance loaded into KeyManager into storable bytes.

export_public(**kwargs)

Serialize the cryptography public key instance loaded into KeyManager into storable bytes.

generate_keypair([alg])

Generate a key pair, returning private + public key as serialized bytes based on default_formats and the kwarg format if it’s present.

generate_keypair_raw([alg])

Generate a key pair, returning private + public key instances from the cryptography module.

identify_algorithm(key)

Identifies a cryptography public/private key instance, such as RSAPrivateKey and returns the algorithm name that can be used with other KeyManager methods, e.g.

load_key(data[, password])

Load a private/public key from a string or bytes data containing the key in some format, such as PEM or OpenSSH.

load_keyfile(filename[, password])

Returns an instance of KeyManager using a public/private key loaded from disk, instead of from string/bytes key data.

output_keypair(priv, pub, *args, **kwargs)

Similar to generate_keypair() - except this also writes the private key and public key to the file locations and/or byte streams specified in the first two arguments (priv and pub)

sign(message[, pad, hashing])

Generate a signature for a given message using the loaded private_key.

verify(signature, message[, pad, hashing])

Verify a signature against a given message using an asymmetric public key.

Attributes

Attributes

backend

combined_key_types

A Union which just combines private_key_types and public_key_types into one type.

curves

An alias for Cryptography’s map of string curve names (e.g.

default_formats

Default Format formatting options for serialising each key algorithm

default_gen

A map of key algorithms to their generator’s default kwargs

generators

Maps each key algorithm to a tuple containing the algorithm’s generation function, and any extra kwargs needed for generating a private key

private_key_types

The cryptography library doesn’t have a standard parent type for private keys, so we need a Union to hold the various private key types for return types, type/instance comparison etc.

public_key_types

Same as private_key_types but for public key types.

raw_priv_types

This extracts the actual class types from the Union[] for isinstance() checks

raw_pub_types

This extracts the actual class types from the Union[] for isinstance() checks

type_name_map

Maps public/private key types to their associated algorithm name for type/instance identification