Skip to content

Key Exchange

Usage

N variant

In the N variant key exchange, the client is not authenticated, and the server is authenticated using its public key.

  • The server generates a long-term key pair.
  • The client knows the server's public key.
  • The client generates session keys and sends a packet with an ephemeral public key to the server.
  • The server receives the packet and generates the same session keys on its side.

Server side:

from cydrogen import KxPair

server_kp = KxPair.gen()
print(server_kp.public_key())

=> Printed public key: RvyXqG9WP6nYKQRoIzmnDMvUE5KAnbDNAPXPG8dphi0=

Client side:

from cydrogen import KxPublicKey, client_init_kx_n

server_public_key = KxPublicKey("RvyXqG9WP6nYKQRoIzmnDMvUE5KAnbDNAPXPG8dphi0=")
session_keys, packet = client_init_kx_n(server_public_key)

session_keys contains the session keys that the client would use to communicate with the server. packet contains the ephemeral public key and other necessary information to complete the key exchange. The client can now send the packet to the server.

Server side:

from cydrogen import server_finish_kx_n
session_keys = server_finish_kx_n(server_kp, packet)

session_keys contains the session keys that the server would use to communicate with the client. They are the same as the ones generated by the client (only the order of keys rx/tx is reversed).

KK variant

In the KK variant key exchange, the client and the server authenticate each other using their public keys.

  • The client generates a long-term key pair.
  • The server generates a long-term key pair.
  • The client knows the server's public key, and the server knows the client's public key.
  • The client initiates the key exchange by sending a packet with its ephemeral public key to the server.
  • The server receives the packet, generates session keys, and sends a packet with its ephemeral public key to the client.
  • The client receives the packet and generates the same session keys on its side.

Client side:

from cydrogen import KxPair, KxPublicKey

# client keygen
client_kp = KxPair.gen()
print(client_kp.public_key())
# qkPUJxB+//AFmVb9B40z8lmbh/RK6LyeKLWot57190s=

# client knows server's public key
server_public_key = KxPublicKey("blnFyUVHsJNj9cRGIbhDU04M/Iq7fWL5Aam+IosBQ1s=")

# client initiates key Exchange
s = client_kp.client_init_kx_kk(server_public_key)
# now s.packet1 contains the packet to send to the server

# [client sends s.packet1 to the server]
# [the server will respond with some packet2]

# client calculates session keys
session_keys = s.client_finish_kx_kk(packet2)

Server side:

from cydrogen import KxPair, KxPublicKey

# server keygen
server_kp = KxPair.gen()
print(server_kp.public_key())
# blnFyUVHsJNj9cRGIbhDU04M/Iq7fWL5Aam+IosBQ1s=

# server knows client's public key
client_public_key = KxPublicKey("qkPUJxB+//AFmVb9B40z8lmbh/RK6LyeKLWot57190s=")

# [server receives packet1 from the client]

# the server calculates session keys
session_keys, packet2 = server_kp.server_process_kx_kk(client_public_key, packet1)

# [server sends packet2 to the client]

client_init_kx_n(server_public_key, psk=None)

Initiate a key exchange variant N (anonymous client) from the client side.

Parameters:

  • server_public_key (KxPublicKey) –

    The public key of the server to exchange keys with.

  • psk (Psk | None, default: None ) –

    An optional pre-shared key to use in the key exchange.

Returns:

  • SessionPair

    A tuple containing a SessionPair with the symmetric keys for the session.

  • KX_N_Packet1

    The packet to send to the server.

Raises:

server_finish_kx_n(server_kp, packet1, psk=None)

Finalize a key exchange variant N (anonymous client) from the server side.

Parameters:

  • server_kp (KxPair) –

    The server key pair.

  • packet1 (KX_N_Packet1) –

    The packet received from the client.

  • psk (Psk | None, default: None ) –

    An optional pre-shared key to use in the key exchange.

Returns:

  • SessionPair

    A SessionPair with the symmetric keys for the session.

Raises:

  • KeyExchangeException

    If the operation fails. In particular, this exception is raised if the packet is invalid or if the key exchange fails.

class KxPair

KxPair represents a pair of public/secret keys used in key exchange.

KxPair implements the buffer protocol, allowing it to be used as a byte-like object.

__init__(kp)

Initializes a KxPair instance.

Parameters:

  • kp (str | bytes | Buffer | Self) –

    The key pair data to initialize the KxPair instance with.

Raises:

  • ValueError

    If the provided key pair data is invalid.

__str__()

Returns a string representation of the KxPair (base64 encoded).

Returns:

  • str

    A base64 encoded string representation of the key pair.

client_init_kx_kk(server_public_key)

Initiate a key exchange variant KK from the client side.

Parameters:

  • server_public_key (KxPublicKey) –

    The public key of the server to exchange keys with.

Returns:

  • KxKkClientState

    A state object containing the first packet to send to the server.

Raises:

from_keys(public_key, secret_key) classmethod

Creates a KxPair instance from a public key and a secret key.

Parameters:

Returns:

  • Self

    A KxPair instance initialized with the provided keys.

Raises:

  • ValueError

    If the provided keys are invalid.

gen() classmethod

Generates a new KxPair instance with a random key pair.

Returns:

  • Self

    A new KxPair instance with a randomly generated public and secret key.

public_key()

Returns the public key part of the KxPair.

Returns:

  • KxPublicKey

    A KxPublicKey instance representing the public key part of the KxPair.

secret_key()

Returns the secret key part of the KxPair.

Returns:

  • KxSecretKey

    A KxSecretKey instance representing the secret key part of the KxPair.

server_finish_kx_n(packet1, psk=None)

server_process_kx_kk(client_public_key, packet1)

Process a key exchange variant KK from the server side.

Parameters:

  • client_public_key (KxPublicKey) –

    The public key of the client to exchange keys with.

  • packet1 (KX_KK_Packet1) –

    The packet received from the client.

Returns:

  • SessionPair

    A SessionPair with the symmetric keys for the session.

  • KX_KK_Packet2

    An object representing the packet to send back to the client.

Raises:

  • KeyExchangeException

    If the operation fails. In particular, this exception is raised if the packet is invalid or if the key exchange fails.

class KxPublicKey

The KxPublicKey class represents a public key used in key exchange.

KxPublicKey implements the buffer protocol, allowing it to be used as a byte-like object.

__init__(kp)

Initializes a KxPublicKey instance.

Parameters:

  • kp (bytes | str | Buffer | Self) –

    The public key data to initialize the KxPublicKey instance with.

Raises:

  • ValueError

    If the provided key data is invalid.

__str__()

Returns a string representation of the KxPublicKey (base64 encoded).

Returns:

  • str

    A base64 encoded string representation of the public key.

class KxSecretKey

The KxSecretKey class represents a secret key used in key exchange.

KxSecretKey implements the buffer protocol, allowing it to be used as a byte-like object.

__init__(kp)

Initializes a KxSecretKey instance.

Parameters:

  • kp (bytes | str | Buffer | Self) –

    The secret key data to initialize the KxSecretKey instance with.

Raises:

  • ValueError

    If the provided key data is invalid.

__str__()

Returns a string representation of the KxSecretKey (base64 encoded).

Returns:

  • str

    A base64 encoded string representation of the secret key.

class SessionPair

The SessionPair class represents a pair of symmetric keys to be used to secure a session with a peer.

Attributes:

  • rx (SecretBoxKey) –

    The symmetric key used to decrypt messages received from the peer.

  • tx (SecretBoxKey) –

    The symmetric key used to encrypt messages sent to the peer.

__init__(rx, tx)

Initializes a SessionPair instance.

Parameters:

  • rx (SecretBoxKey) –

    The symmetric key used to decrypt messages received from the peer.

  • tx (SecretBoxKey) –

    The symmetric key used to encrypt messages sent to the peer.

class KxKkState

KxKkClientState represents the state of a key exchange variant KK from the client side.

session_pair is initially None and will be set after client_finish_kx_kk is called.

Attributes:

  • packet1 (KX_KK_Packet1 | None) –

    The packet to send to the server as part of the key exchange.

  • session_pair (SessionPair | None) –

    The session pair containing the symmetric keys for the session.

client_finish_kx_kk(packet2)

Finalizes the key exchange variant KK from the client side.

Parameters:

  • packet2 (KX_KK_Packet2) –

    The packet received from the server.

Returns:

  • Self

    The updated state including the session keys.

Raises:

  • KeyExchangeException

    If the operation fails. In particular, this exception is raised if the packet is invalid or if the key exchange fails.

class Psk

Bases: BaseKey

The Psk class represents a pre-shared key (PSK).

Pre-shared keys are used optionally by the key exchange algorithms.

__bool__()

Returns True if the key is not zero, False otherwise.

Returns:

  • bool

    True if the key is not zero, False otherwise.

__str__()

Returns a base64-encoded representation of the key.

Returns:

  • str

    A string representing the key in base64 encoding.

gen() classmethod

Generate a new BaseKey with random bytes.

Returns:

  • Self

    A new instance of BaseKey.

is_zero()

Checks if the key is the zero key.

Returns:

  • bool

    True if the key is zero, False otherwise.

read_from(reader) classmethod

Create a key from a reader.

Parameters:

  • reader (Reader) –

    A reader object that supports the read method.

Returns:

  • Self

    A new instance of BaseKey read from the provided reader.

Raises:

  • TypeError

    If the provided reader does not have a 'read' method.

  • ValueError

    If the read data is not 32 bytes long.

writeto(out)

Write the key to a writer.

Parameters:

  • out (Writer) –

    A writer object that supports the write method.

Returns:

  • int

    The number of bytes written, which should be 32.

Raises:

  • TypeError

    If the provided writer does not have a 'write' method.

zero() classmethod

Generate a new BaseKey initialized to zero.

Returns:

  • Self

    A new instance of BaseKey initialized to zero.