Skip to content

Commit

Permalink
feat(kyberlib): ✨ new macros, fixes and document updates
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastienrousseau committed May 8, 2024
1 parent 122cf72 commit 1144629
Show file tree
Hide file tree
Showing 8 changed files with 334 additions and 66 deletions.
71 changes: 20 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ KyberLib is a robust Rust library designed for CRYSTALS-Kyber Post-Quantum Crypt

See [Documentation][08] for full API details.

![Divider][01]

## Getting Started 🚀

It takes just a few minutes to get up and running with `kyberlib`.
Expand All @@ -90,8 +88,6 @@ using the following command:
cargo install kyberlib
```

![Divider][01]

## Usage 📖

To use the `kyberlib` library in your project, add the following to your
Expand Down Expand Up @@ -181,6 +177,25 @@ alice.client_confirm(server_response, &alice_keys.secret)?;
assert_eq!(alice.shared_secret, bob.shared_secret);
```

## Macros

The KyberLib crate provides several macros to simplify common cryptographic operations:

- `kyberlib_assert!`: Asserts that a given expression is true. Panics if the assertion fails.
- `kyberlib_min!`: Returns the minimum of the given values.
- `kyberlib_max!`: Returns the maximum of the given values.
- `kyberlib_generate_key_pair!`: Generates a public and private key pair for CCA-secure Kyber key encapsulation mechanism.
- `kyberlib_encrypt_message!`: Generates cipher text and a shared secret for a given public key.
- `kyberlib_decrypt_message!`: Generates a shared secret for a given cipher text and private key.
- `kyberlib_uake_client_init!`: Initiates a Unilaterally Authenticated Key Exchange.
- `kyberlib_uake_server_receive!`: Handles the output of a `kyberlib_uake_client_init()` request.
- `kyberlib_uake_client_confirm!`: Decapsulates and authenticates the shared secret from the output of `kyberlib_uake_server_receive()`.
- `kyberlib_ake_client_init!`: Initiates a Mutually Authenticated Key Exchange.
- `kyberlib_ake_server_receive!`: Handles and authenticates the output of a `kyberlib_ake_client_init()` request.
- `kyberlib_ake_client_confirm!`: Decapsulates and authenticates the shared secret from the output of `kyberlib_ake_server_receive()`.

See the [macros module documentation](https://docs.rs/kyberlib/latest/kyberlib/macros/index.html) for more details and usage examples.

## Errors

The KyberLibError enum has two variants:
Expand All @@ -189,8 +204,6 @@ The KyberLibError enum has two variants:
- **Decapsulation** - The ciphertext was unable to be authenticated. The shared secret was not decapsulated.
- **RandomBytesGeneration** - Error trying to fill random bytes (i.e external (hardware) RNG modules can fail).

![Divider][01]

## Examples

To get started with `kyberlib`, you can use the examples provided in the
Expand Down Expand Up @@ -229,47 +242,9 @@ Run the following command in your terminal from the project root directory.
cargo run --example uake
```

![Divider][01]

### Platform support

`kyberlib` is supported and tested on the following platforms:

### Tier 1 platforms 🏆

| | Operating System | Target | Description |
| --- | --- | --- | --- |
|| Linux | aarch64-unknown-linux-gnu | 64-bit Linux systems on ARM architecture |
|| Windows | i686-pc-windows-gnu | 32-bit Windows systems using the GNU toolchain |
|| Windows | i686-pc-windows-msvc | 32-bit Windows systems using the Microsoft Visual C toolchain |
|| Linux | i686-unknown-linux-gnu | 32-bit Linux systems (kernel 3.2+, glibc 2.17+) |
|| macOS | x86_64-apple-darwin | 64-bit macOS systems (10.7 Lion or later) |
|| Windows | x86_64-pc-windows-gnu | 64-bit Windows systems using the GNU toolchain |
|| Windows | x86_64-pc-windows-msvc | 64-bit Windows systems using the Microsoft Visual C toolchain |
|| Linux | x86_64-unknown-linux-gnu | 64-bit Linux systems (kernel 2.6.32+, glibc 2.11+) |

### Tier 2 platforms 🥈

| | Operating System | Target | Description |
| --- | --- | --- | --- |
|| Linux | aarch64-apple-darwin | 64-bit macOS on Apple Silicon |
|| Windows | aarch64-pc-windows-msvc | 64-bit Windows on ARM architecture using the Microsoft Visual C toolchain |
|| Linux | aarch64-unknown-linux-musl | 64-bit Linux on ARM architecture with musl libc |
|| Linux | arm-unknown-linux-gnueabi | ARMv6 Linux systems (kernel 3.2, glibc 2.17) |
|| Linux | arm-unknown-linux-gnueabihf | ARMv7 Linux systems, hardfloat (kernel 3.2, glibc 2.17) |
|| Linux | armv7-unknown-linux-gnueabihf | ARMv7 Linux systems, hardfloat (kernel 3.2, glibc 2.17) |
|| Linux | powerpc-unknown-linux-gnu | PowerPC Linux systems (kernel 3.2, glibc 2.17) |
|| Linux | powerpc64-unknown-linux-gnu | PowerPC64 Linux systems (kernel 3.2, glibc 2.17) |
|| Linux | powerpc64le-unknown-linux-gnu | PowerPC64le Linux systems (kernel 3.2, glibc 2.17) |
|| Linux | riscv64gc-unknown-linux-gnu | RISC-V Linux systems (kernel 3.2, glibc 2.17) |
|| Linux | s390x-unknown-linux-gnu | s390x Linux systems (kernel 3.2, glibc 2.17) |
|| Linux | x86_64-unknown-freebsd | 64-bit FreeBSD systems on x86-64 architecture |
|| Linux | x86_64-unknown-linux-musl | 64-bit Linux systems (kernel 2.6.32+, musl libc) |

The [GitHub Actions][10] shows the platforms in which the `kyberlib`
library tests are run.

![Divider][01]
`kyberlib` is supported and tested on MacOS, Linux, and Windows. The [GitHub Actions][10] shows the platforms in which the `kyberlib` library tests are run.

### Documentation

Expand All @@ -281,15 +256,11 @@ library tests are run.
For transparency into our release cycle and in striving to maintain
backward compatibility, `kyberlib` follows [semantic versioning][06].

![Divider][01]

## License 📝

The project is licensed under the terms of Apache License, Version 2.0 and the
MIT license.

![Divider][01]

## Contribution 🤝

We welcome all people who want to contribute. Please see the
Expand All @@ -303,8 +274,6 @@ submitted for inclusion in the work by you, as defined in the
Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.

![Divider][01]

## Acknowledgements 💙

A big thank you to all the awesome contributors of [kyberlib][05] for their
Expand Down
46 changes: 46 additions & 0 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,52 @@ where
Ok(Keypair { public, secret })
}

/// Verify that given secret and public key matches and put them in
/// the KeyPair structure after zeroize them if asked.
/// ### Example
/// ```
/// # use kyberlib::*;
/// # fn main() -> Result<(), KyberLibError> {
/// let mut rng = rand::thread_rng();
/// let keys = keypair(&mut rng)?;
/// let mut public = keys.public;
/// let mut secret = keys.secret;
/// let _ = keypairfrom(&mut public, &mut secret, &mut rng)?;
/// # Ok(())}
/// ```
pub fn keypairfrom<R>(
public: &mut [u8; KYBER_PUBLIC_KEY_BYTES],
secret: &mut [u8; KYBER_SECRET_KEY_BYTES],
rng: &mut R,
) -> Result<Keypair, KyberLibError>
where
R: RngCore + CryptoRng,
{
//Try to encapsulate and decapsule to verify secret key matches public key
let (ciphertext, shared_secret) = encapsulate(public, rng)?;
let expected_shared_secret = decapsulate(&ciphertext, secret)?;
//If it does match, return a KeyPair
if expected_shared_secret == shared_secret {
let public2 = *public;
let secret2 = *secret;
let key = Keypair {
public: public2,
secret: secret2,
};
#[cfg(feature = "zeroize")]
{
public.zeroize();
secret.zeroize();
public2.zeroize();
secret2.zeroize();
}
Ok(key)
} else {
//Else return an error
Err(KyberLibError::InvalidKey)
}
}

/// Encapsulates a public key and returns the ciphertext to send and the shared secret.
///
/// This function encapsulates a public key and returns the ciphertext and the shared secret.
Expand Down
6 changes: 6 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ pub enum KyberLibError {
/// two parties using different security levels while trying to negotiate a key exchange.
InvalidInput,

/// Error when generating keys
InvalidKey,

/// The ciphertext was unable to be authenticated. The shared secret was not decapsulated.
Decapsulation,

Expand All @@ -26,6 +29,9 @@ impl core::fmt::Display for KyberLibError {
KyberLibError::RandomBytesGeneration => {
write!(f, "Random bytes generation function failed")
}
KyberLibError::InvalidKey => {
write!(f, "The secret and public key given does not match.")

Check warning on line 33 in src/error.rs

View check run for this annotation

Codecov / codecov/patch

src/error.rs#L33

Added line #L33 was not covered by tests
}
}
}
}
Expand Down
22 changes: 12 additions & 10 deletions src/kex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,13 @@ pub struct Uake {
/// The resulting shared secret from a key exchange
pub shared_secret: SharedSecret,
/// Sent when initiating a key exchange
send_a: UakeSendInit,
pub send_a: UakeSendInit,

Check warning on line 69 in src/kex.rs

View check run for this annotation

Codecov / codecov/patch

src/kex.rs#L69

Added line #L69 was not covered by tests
/// Response to a key exchange initiation
send_b: UakeSendResponse,
// Ephemeral keys
temp_key: TempKey,
eska: Eska,
pub send_b: UakeSendResponse,

Check warning on line 71 in src/kex.rs

View check run for this annotation

Codecov / codecov/patch

src/kex.rs#L71

Added line #L71 was not covered by tests
/// Ephemeral keys for the key exchange
pub temp_key: TempKey,

Check warning on line 73 in src/kex.rs

View check run for this annotation

Codecov / codecov/patch

src/kex.rs#L73

Added line #L73 was not covered by tests
/// Ephemeral secret key
pub eska: Eska,

Check warning on line 75 in src/kex.rs

View check run for this annotation

Codecov / codecov/patch

src/kex.rs#L75

Added line #L75 was not covered by tests
}

impl Default for Uake {
Expand Down Expand Up @@ -208,12 +209,13 @@ pub struct Ake {
/// The resulting shared secret from a key exchange
pub shared_secret: SharedSecret,
/// Sent when initiating a key exchange
send_a: AkeSendInit,
pub send_a: AkeSendInit,

Check warning on line 212 in src/kex.rs

View check run for this annotation

Codecov / codecov/patch

src/kex.rs#L212

Added line #L212 was not covered by tests
/// Response to a key exchange initiation
send_b: AkeSendResponse,
// Ephemeral keys
temp_key: TempKey,
eska: Eska,
pub send_b: AkeSendResponse,

Check warning on line 214 in src/kex.rs

View check run for this annotation

Codecov / codecov/patch

src/kex.rs#L214

Added line #L214 was not covered by tests
/// Ephemeral keys for the key exchange
pub temp_key: TempKey,

Check warning on line 216 in src/kex.rs

View check run for this annotation

Codecov / codecov/patch

src/kex.rs#L216

Added line #L216 was not covered by tests
/// Ephemeral secret key
pub eska: Eska,

Check warning on line 218 in src/kex.rs

View check run for this annotation

Codecov / codecov/patch

src/kex.rs#L218

Added line #L218 was not covered by tests
}

impl Default for Ake {
Expand Down
19 changes: 19 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,25 @@
//! # Ok(()) }
//! ```
//!
//! ## Macros
//!

Check warning on line 122 in src/lib.rs

View check run for this annotation

Codecov / codecov/patch

src/lib.rs#L122

Added line #L122 was not covered by tests
//! The KyberLib crate provides several macros to simplify common cryptographic operations:
//!
//! - `kyberlib_assert!`: Asserts that a given expression is true. Panics if the assertion fails.
//! - `kyberlib_min!`: Returns the minimum of the given values.
//! - `kyberlib_max!`: Returns the maximum of the given values.
//! - `kyberlib_generate_key_pair!`: Generates a public and private key pair for CCA-secure Kyber key encapsulation mechanism.
//! - `kyberlib_encrypt_message!`: Generates cipher text and a shared secret for a given public key.
//! - `kyberlib_decrypt_message!`: Generates a shared secret for a given cipher text and private key.
//! - `kyberlib_uake_client_init!`: Initiates a Unilaterally Authenticated Key Exchange.
//! - `kyberlib_uake_server_receive!`: Handles the output of a `kyberlib_uake_client_init()` request.
//! - `kyberlib_uake_client_confirm!`: Decapsulates and authenticates the shared secret from the output of `kyberlib_uake_server_receive()`.
//! - `kyberlib_ake_client_init!`: Initiates a Mutually Authenticated Key Exchange.
//! - `kyberlib_ake_server_receive!`: Handles and authenticates the output of a `kyberlib_ake_client_init()` request.
//! - `kyberlib_ake_client_confirm!`: Decapsulates and authenticates the shared secret from the output of `kyberlib_ake_server_receive()`.
//!
//! See the [macros module documentation](https://docs.rs/kyberlib/latest/kyberlib/macros/index.html) for more details and usage examples.
//!
//! ## Errors
//!
//! The [KyberLibError](enum.KyberLibError.html) enum handles errors with two variants:
Expand Down
111 changes: 111 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,121 @@ macro_rules! kyberlib_encrypt_message {
///
/// On failure, `ss` will contain a pseudo-random value.
#[macro_export]
#[doc = "Macro to decrypt a message using the Kyber key encapsulation mechanism."]
macro_rules! kyberlib_decrypt_message {
($ss:expr, $ct:expr, $sk:expr) => {
kyberlib::kem::decrypt_message($ss, $ct, $sk)
};
}

/// Initiates a Unilaterally Authenticated Key Exchange.
///
/// # Arguments
///
/// * `pubkey` - Input public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes).
/// * `rng` - Random number generator implementing RngCore + CryptoRng.
///
/// # Returns
///
/// The bytes to send when initiating a unilateral key exchange (UakeSendInit).
#[macro_export]
#[doc = "Macro to initiate a Unilaterally Authenticated Key Exchange."]
macro_rules! kyberlib_uake_client_init {
($pubkey:expr, $rng:expr) => {
kyberlib::kex::Uake::new().client_init($pubkey, $rng)
};
}

/// Handles the output of a `kyberlib_uake_client_init()` request.
///
/// # Arguments
///
/// * `send_a` - The bytes received from the `kyberlib_uake_client_init()` request.
/// * `secretkey` - The secret key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes).
/// * `rng` - Random number generator implementing RngCore + CryptoRng.
///
/// # Returns
///
/// The bytes to send when responding to a unilateral key exchange (UakeSendResponse).
#[macro_export]
#[doc = "Macro to handle the output of a Unilaterally Authenticated Key Exchange."]
macro_rules! kyberlib_uake_server_receive {
($send_a:expr, $secretkey:expr, $rng:expr) => {
kyberlib::kex::Uake::new().server_receive($send_a, $secretkey, $rng)
};
}

/// Decapsulates and authenticates the shared secret from the output of
/// `kyberlib_uake_server_receive()`.
///
/// # Arguments
///
/// * `send_b` - The bytes received from the `kyberlib_uake_server_receive()` request.
///
/// # Returns
///
/// Nothing (the shared secret is stored in the `Uake` struct).
#[macro_export]
#[doc = "Macro to decapsulate and authenticate the shared secret from a Unilaterally Authenticated Key Exchange."]
macro_rules! kyberlib_uake_client_confirm {
($send_b:expr) => {
kyberlib::kex::Uake::new().client_confirm($send_b)
};
}

/// Initiates a Mutually Authenticated Key Exchange.
///
/// # Arguments
///
/// * `pubkey` - Input public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes).
/// * `rng` - Random number generator implementing RngCore + CryptoRng.
///
/// # Returns
///
/// The bytes to send when initiating a mutual key exchange (AkeSendInit).
#[macro_export]
#[doc = "Macro to initiate a Mutually Authenticated Key Exchange."]
macro_rules! kyberlib_ake_client_init {
($pubkey:expr, $rng:expr) => {
kyberlib::kex::Ake::new().client_init($pubkey, $rng)
};
}

/// Handles and authenticates the output of a `kyberlib_ake_client_init()` request.
///
/// # Arguments
///
/// * `ake_send_a` - The bytes received from the `kyberlib_ake_client_init()` request.
/// * `pubkey` - The public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes).
/// * `secretkey` - The secret key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes).
/// * `rng` - Random number generator implementing RngCore + CryptoRng.
///
/// # Returns
///
/// The bytes to send when responding to a mutual key exchange (AkeSendResponse).
#[macro_export]
#[doc = "Macro to handle the output of a Mutually Authenticated Key Exchange."]
macro_rules! kyberlib_ake_server_receive {
($ake_send_a:expr, $pubkey:expr, $secretkey:expr, $rng:expr) => {
kyberlib::kex::Ake::new().server_receive($ake_send_a, $pubkey, $secretkey, $rng)
};
}

/// Decapsulates and authenticates the shared secret from the output of
/// `kyberlib_ake_server_receive()`.
///
/// # Arguments
///
/// * `send_b` - The bytes received from the `kyberlib_ake_server_receive()` request.
/// * `secretkey` - The secret key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes).
///
/// # Returns
///
/// Nothing (the shared secret is stored in the `Ake` struct).
#[macro_export]
#[doc = "Macro to decapsulate and authenticate the shared secret from a Mutually Authenticated Key Exchange."]
macro_rules! kyberlib_ake_client_confirm {
($send_b:expr, $secretkey:expr) => {
kyberlib::kex::Ake::new().client_confirm($send_b, $secretkey)
};
}
Loading

0 comments on commit 1144629

Please sign in to comment.