Expand description
An implementation of a password authenticate key exchange (PAKE) that relies on quantum-resistant cryptographic primitives
⚠️ Warning: This implementation has not been audited. Use at your own risk!
§Overview
pake-kem is a protocol between two parties: an initiator and a responder.
At a high level, the initiator and responder each hold as input to the
protocol an Input
. After exchanging the protocol messages, the initiator
and responder end up with an Output
. If the two participants had matching
Input
s, then they will end up with the same Output
. Otherwise,
their Output
s will not match, and in fact be (computationally) uncorrelated.
§Setup
In order to execute the protocol, the initiator and responder must first agree on a collection of primitives to be kept consistent throughout protocol execution. These include:
- a (classically-secure) two-message PAKE protocol,
- a (quantum-resistant) key encapsulation mechanism, and
- a hashing function.
We will use the following choices in this example:
use pake_kem::CipherSuite;
struct Default;
impl CipherSuite for Default {
type Pake = pake_kem::CPaceRistretto255;
type Kem = ml_kem::MlKem768;
type Hash = sha2::Sha256;
}
See examples/demo.rs for a working example for using pake-kem.
Like any symmetric (balanced) PAKE, the initiator and responder will each begin with their own input, exchange some messages as part of the protocol, and derive a secret as the output of the protocol.
If the initiator and responder used the exact same input to the protocol, then they are guaranteed to end up with the same secret (this would be a “shared secret”).
If the initiator and responder used different inputs, then they will not end up with the same shared secret (with overwhelming probability).
The way an input is created in pake-kem is as follows:
use pake_kem::Input;
let input = Input::new(b"password", b"initiator", b"responder");
§Protocol Execution
The pake-kem protocol occurs over four steps, involving three messages between the initiator and responder.
§Initiator Start
The initiator begins the protocol by invoking the following with
an Input
and source of randomness:
use pake_kem::EncodedSizeUser; // Needed for calling as_bytes()
use pake_kem::Initiator;
use rand_core::OsRng;
let mut initiator_rng = OsRng;
let (initiator, message_one) = Initiator::<Default>::start(&input, &mut initiator_rng)
.expect("Error with Initiator::start()");
let message_one_bytes = message_one.as_bytes();
// Send message_one_bytes over the wire to the responder
The initiator retains the Initiator
object for the third step, and sends
the MessageOne
object over the wire to the responder.
§Responder Start
Next, the responder invokes the following with an Input
, a MessageOne
object received from the initiator in the previous step, and a source of
randomness:
use pake_kem::MessageOne;
use pake_kem::Responder;
let mut responder_rng = OsRng;
let message_one = MessageOne::from_bytes(&message_one_bytes);
let (responder, message_two) =
Responder::<Default>::start(&input, &message_one, &mut responder_rng)
.expect("Error with Responder::start()");
let message_two_bytes = message_two.as_bytes();
// Send message_two_bytes over the wire to the initiator
The responder retains the Responder
object for the fourth step, and sends
the MessageTwo
object over the wire to the initiator.
§Initiator Finish
Next, the initiator invokes the following with the already-initialized object
retained from the first step, a MessageTwo
object received from the responder
in the previous step, and a source of randomness:
use pake_kem::MessageTwo;
let message_two = MessageTwo::from_bytes(&message_two_bytes);
let (initiator_output, message_three) =
initiator.finish(&message_two, &mut initiator_rng)
.expect("Error with Initiator::finish()");
let message_three_bytes = message_three.as_bytes();
// Send message_three_bytes over the wire to the responder
The initiator retains the Output
object as the output of the pake-kem
protocol, and sends the MessageThree
object over the wire to the responder.
§Responder Finish
Finally, the responder invokes the following with the already-initialized object
retained from the second step and a MessageThree
object received from the initiator
in the previous step:
use pake_kem::MessageThree;
let message_three = MessageThree::from_bytes(&message_three_bytes);
let responder_output = responder.finish(&message_three)
.expect("Error with Responder::finish()");
The responder retains the Output
object as the output of the pake-kem
protocol.
Re-exports§
pub use rand_core;
Structs§
- Array
Array
is a newtype for an inner[T; N]
array whereN
is determined by a genericArraySize
parameter, which is a marker trait for a numeric value determined by ZSTs that impl thetypenum::Unsigned
trait.- CPace
Ristretto255 - An implementation of the
CPace
protocol using Ristretto255 and SHA-512. - Default
Cipher Suite - The default
CipherSuite
for pake-kem, based onCPaceRistretto255
,MlKem768
, andSha256
- Initiator
- The main struct for the initiator of the pake-kem protocol
- Input
- The input to the pake-kem protocol
- Message
One - The first message in the pake-kem protocol, created by the initiator
- Message
Three - The third message in the pake-kem protocol, created by the initiator
- Message
Two - The second message in the pake-kem protocol, created by the responder
- Output
- The output of the pake-kem protocol
- Responder
- The main struct for the responder of the pake-kem protocol
Enums§
- Pake
KemError - The library’s error type
Traits§
- Cipher
Suite - Configures the primitives used in pake-kem:
- Encoded
Size User - An object that knows what size it is