This is a proof of concept for a key exchange protocol based on the Classic McEliece (CM) key encapsulation mechanism proposed by Bernstein et al.
This protocol was not designed for general use. In particular, it is not a replacement for TLS and does not provide equivalent security. It ensures neither authenticity nor integrity, and the implemented key exchange does not match the performance of others.
This protocol is designed to act as a layer on top of a bidirectional stream such as TCP or TLS. It is not suited for connectionless communication.
The following parameters are specified by Berstein et al. in section 2.1:
nis the code length.
tis the error-correction capability of the linear code.
mis the logarithm to base 2 of the size of the used field.
fis a monic irreducible polynomial of degree
mthat defines a representation of the finite field 𝔽2m.
His a cryptographic hash function.
The following parameters are specific to this protocol:
Eis the symmetric cipher.
sis the size of the symmetric key used by
bis the size of the initialization vector used by
H'is a hash function with output size greater than or equal to
The protocol does not negotiate these parameters. For this implementation, we
chose the following parameters based on the parameter set
proposed by Bernstein et al.:
- n = 6960
- t = 119
- m = 13
- f(z) = z13 + z4 + z3 + z + 1
- H = H' = SHAKE256
- E = AES-CTR
- s = 256
- b = 128
- The client begins the key exchange by sending a
ClientHellomessage. This message has an optional
snifield. It allows to pass a hostname to the server.
- The server selects a CM public key
Nfor the connection. It sends a
ServerHellomessage and sets the
N. The server can also set the
key_signaturefield to allow the client to authenticate the server using external measures.
- If the client has a local copy of
H'(T), proceed at step 6.
- The client sends a
- The server sends a
PublicKeyResponsemessage and sets the
- The client selects a random initialization vector
b, and performs the CM key encapsulation operation using the public key
Tin order to obtain a random key
sand the ciphertext
- The client sends a
EncryptedKeymessage and sets the
- The server performs the CM key decapsulation operation using the public key
Tand the ciphertext
- The server sends a
- Both parties compute
K' = K ⊕ N.
- Both parties compute
K_1 = H'(00000000 || K')and
K_2 = H'(11111111 || K').
- Both parties set up the tunnel by encrypting the remainder of the connection
with the symmetric cipher
Eusing the initialization vector
vand the key
K_1for data from the server to the client, and
K_2for data from client to the server.
The message format is intentionally kept very simple. Each message begins with a single byte that indicates the type of the message, followed by three bytes that encode the length of the rest of the message as a big-endian 24-bit integer. This header is only four bytes long, but limits the total size of all contained fields to 16 megabytes.
-------------------------------------------------------- | Byte offset | 0 | 1 .. 3 | 4 .. 3+len | -------------------------------------------------------- | Field | tag | length | field 1 | field 2 | ... | --------------------------------------------------------
Message types and their fields:
sni: hostname that the client is trying to connect to (optional)
key_id: uniquely identifies the server's public key
nonce: selected randomly by the server
key_signature: externally produced and verified signature (optional)
public_key: the server's public key
encrypted_key: ciphertext produced by CM key encapsulation
iv: randomly chosen initialization vector
Replay attacks from either side are easily prevented since both the client and the server randomly affect the generated keys. A more detailed analysis can be found below in the section "Prevention of (intentional) key and IV reuse".
Authentication and Man-in-the-middle attacks
Since this protocol does not perform any kind of authentication, it does not protect against man-in-the-middle attacks. An attacker who can intercept the communication between client and server can use their own public key instead of the server's public key, and then perform the key exchange both between client and attacker and attacker and server. This would allow the attacker to observe and manipulate all transmitted data.
However, the server can use the
key_signature field of the
message to provide an externally generated signature of its CM public key. For
example, when using TLS on top of this protocol, the server can determine the
TLS certificate that it will use for the TLS handshake upon receiving the
ClientHello message, and can use its TLS private key to sign the CM public
key. This signature is then transmitted as part of the
After the key exchange is completed, the TLS handshake takes over. Once the
client receives the TLS certificate, it can verify the signature and thus the
authenticity of the CM public key.
Maximum transmission size
This protocol does not support renegotiations of the used keys or initialization vector. For AES in Counter mode, this restriction means that the initialization vector will be reused after a fixed number of blocks have been transmitted. Reusing the initialization vector with the same key could negatively affect the security of the transferred data, it is therefore important to restrict the size of the transmission such that this does not happen.
With the chosen parameters, the initialization vector will be reused after
2^b blocks, each having a size of
b bits. The maximum transmission
size is therefore
b * 2^b bits, which equals 5.07 * 1030 gigabytes.
Note that this restriction applies to each transmission direction independently.
Prevention of (intentional) key and IV reuse
Apart from restricting the transmission size to avoid accidental reuse of pairs of keys and initialization vectors, the protocol also ensures that neither the client nor the server can intentionally cause such pairs to be reused.
The client can choose the initialization vector
v freely, leaving no way for
the server to influence its choice. If the client chooses
v at random, the
chance of choosing a previously used initialization vector is small, in fact,
the probability of coincidentally reusing an initialization vector reaches
1% after not less than 2.6 * 1018 key exchanges (see
This does not prevent clients from intentionally reusing initialization vectors,
but as we will see in the following, this does not present a problem.
We will now consider key reuse. The protocol uses two keys for symmetric
encryption and decryption,
K_2. Both parties derive these from the
K', which is computed as
K' = K ⊕ N. Since the server can only choose
N and cannot influence
K, it cannot affect
K' in a predictable way,
making it impossible for the server to cause keys to be reused. For the client,
there are two possible strategies for causing
K_2 to be reused:
K_2, find a valid
00000000 || K'(or
11111111 || K', respectively) is a preimage of
K_2, respectivly) under
H'. This is infeasible due to
H'having the property of (weak) collision resistance.
K', find a valid ciphertext
Cthat, when decrypted, produces a
K' = K ⊕ N, thus resulting in the same keys
K_2. As specified by Bernstein et al.,
Kis the result of a cryptographic hash function applied to multiple inputs, one of which is the ciphertext
C. Finding a suitable
Cthus requires finding a suitable preimage of
K, which is infeasible due to the preimage resistance of the used hash function. Even if an attacker was able to find such a preimage, the probability that a given preimage of
Krepresents a valid ciphertext
Therefore, it is infeasible both for the server and for the client to reuse
previously used keys. Note that, without
N, it would be trivial for the client
to force the server to reuse a previously used key.