Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

no_std support with alloc #183

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 43 additions & 18 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,45 @@ edition = "2021"
# This is slightly mumbo-jumboey, but in short:
# Features with a -resolver suffix simply enables the existence of a specific resolver,
# and -accelerated suffix means that this resolver will be the default used by the Builder.
#
# If default features are disabled and default-resolver is used, required crypto primitives
# must be enabled individually.
[features]
default = ["default-resolver"]
default-resolver = ["aes-gcm", "chacha20poly1305", "blake2", "sha2", "curve25519-dalek"]
default = ["default-resolver", "default-resolver-crypto", "std"]
default-resolver = []
default-resolver-crypto = ["use-aes-gcm", "use-chacha20poly1305", "use-blake2", "use-sha2", "use-curve25519-dalek"]
nightly = ["blake2/simd_opt", "subtle/nightly"]
ring-resolver = ["ring"]
ring-accelerated = ["ring-resolver", "default-resolver"]
libsodium-resolver = ["sodiumoxide", "byteorder"]
libsodium-accelerated = ["libsodium-resolver", "default-resolver"]
ring-resolver = ["ring", "std"]
ring-accelerated = ["ring-resolver", "default-resolver", "std"]
libsodium-resolver = ["sodiumoxide", "byteorder", "std"]
libsodium-accelerated = ["libsodium-resolver", "default-resolver", "std"]
vector-tests = []
hfs = []
pqclean_kyber1024 = ["pqcrypto-kyber", "pqcrypto-traits", "hfs", "default-resolver"]
xchachapoly = ["chacha20poly1305", "default-resolver"]
risky-raw-split = []

# Backwards-compatibility aliases
pqclean_kyber1024 = ["use-pqcrypto-kyber1024"]
xchachapoly = ["use-xchacha20poly1305"]

# Enable std features on dependencies if possible.
std = [
"rand_core/std",
"subtle/std",
"ring/std",
"blake2/std",
"sha2/std",
"byteorder/std",
]

# Crypto primitives for default-resolver.
use-curve25519-dalek = ["curve25519-dalek", "default-resolver"]
use-chacha20poly1305 = ["chacha20poly1305", "default-resolver"]
use-xchacha20poly1305 = ["chacha20poly1305", "default-resolver"]
use-blake2 = ["blake2", "default-resolver"]
use-sha2 = ["sha2", "default-resolver"]
use-aes-gcm = ["aes-gcm", "default-resolver"]
use-pqcrypto-kyber1024 = ["pqcrypto-kyber", "pqcrypto-traits", "hfs", "default-resolver"]

[[bench]]
name = "benches"
harness = false
Expand All @@ -37,24 +62,24 @@ harness = false
travis-ci = { repository = "mcginty/snow", branch = "master" }

[dependencies]
rand_core = { version = "0.6", features = ["std", "getrandom"] }
subtle = "2.4"
rand_core = { version = "0.6", default-features = false, features = ["getrandom"] }
subtle = { version = "2.4", default-features = false }

# default crypto provider
aes-gcm = { version = "0.10", optional = true }
chacha20poly1305 = { version = "0.10", optional = true }
blake2 = { version = "0.10", optional = true }
sha2 = { version = "0.10", optional = true }
curve25519-dalek = { version = "4", optional = true }
aes-gcm = { version = "0.10", optional = true, default-features = false, features = ["aes"] }
chacha20poly1305 = { version = "0.10", optional = true, default-features = false }
blake2 = { version = "0.10", optional = true, default-features = false }
sha2 = { version = "0.10", optional = true, default-features = false }
curve25519-dalek = { version = "4", optional = true, default-features = false }

pqcrypto-kyber = { version = "0.8", optional = true }
pqcrypto-traits = { version = "0.3", optional = true }

# ring crypto provider
ring = { version = "0.17", optional = true, features = ["std"] }
ring = { version = "0.17", optional = true }
# libsodium crypto provider
sodiumoxide = { version = "0.2", optional = true }
byteorder = { version = "1.4", optional = true }
sodiumoxide = { version = "0.2", optional = true, default-features = false }
byteorder = { version = "1.4", optional = true, default-features = false }

[dev-dependencies]
criterion = "0.5"
Expand Down
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,69 @@ crypto implementations when available.
| BLAKE2s | ✔ | |
| BLAKE2b | ✔ | |

## `no_std` support and feature selection

Snow can be used in `no_std` environments if `alloc` is provided.

By default Snow uses the standard library, default cyprot resolver and a selected collection
of crypto primitives. To use Snow in `no_std` environments or make other kinds of customized
setups, use Snow with `default-features = false`. This way you will individually select
the components you wish to use. `default-resolver` is the only built-in resolver that
currently supports `no_std`.

To use a custom setup with `default-resolver`, enable your desired selection of cryptographic primitives:

| Primitive | Feature flag |
| :----------- | ---------------------: |
| **DH** |
| 25519 | `use-curve25519-dalek` |
| **Cipher** |
| AESGCM | `use-aes-gcm` |
| ChaChaPoly | `use-chacha20poly1305` |
| XChaChaPoly* | `use-xchacha20poly1305`|
| **Hash** |
| SHA256 | `use-sha2` |
| SHA512 | `use-sha2` |
| BLAKE2s | `use-blake2` |
| BLAKE2b | `use-blake2` |

\* *XChaChaPoly*, an extended nonce variant of *ChaChaPoly*, is not in the official specification of Noise!

### Example configurations

**25519 + AES-GCM + SHA** with standard library features.
```toml
default-features = false
features = [
"use-curve25519-dalek",
"use-aes-gcm",
"use-sha2",
"std",
]
```

**25519 + ChaChaPoly + BLAKE2** without standard library.
```toml
default-features = false
features = [
"use-curve25519-dalek",
"use-chacha20poly1305",
"use-blake2",
]
```

### `getrandom` support

Most crypto implementations supported by `default-resolver` will require
[`getrandom`](getrandom).

If your target platform is not directly supported
you might have to provide a custom implementation in your crate root.
Check out their [documentation](getrandom-custom) for details.

[getrandom]: https://crates.io/crates/getrandom
[getrandom-custom]: https://docs.rs/getrandom/0.2.15/getrandom/macro.register_custom_getrandom.html

## License

Licensed under either of:
Expand Down
9 changes: 6 additions & 3 deletions ci-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ COMMON_FEATURES="xchachapoly vector-tests"
set -x
cargo check --benches
cargo test $TARGET --no-default-features
cargo test $TARGET --features "$COMMON_FEATURES"
# Custom set of crypto without std
cargo test $TARGET --no-default-features --features "default-resolver use-curve25519-dalek use-blake2 use-chacha20poly1305"
# Custom set of crypto with std
cargo test $TARGET --no-default-features --features "default-resolver use-curve25519-dalek use-sha2 use-chacha20poly1305"
cargo test $TARGET --features "ring-resolver $COMMON_FEATURES"
cargo test $TARGET --features "ring-accelerated $COMMON_FEATURES"
if ! rustc -vV | grep 'host: .*windows' &> /dev/null; then
cargo test $TARGET --features "hfs pqclean_kyber1024 $COMMON_FEATURES"
cargo test $TARGET --features "ring-resolver hfs pqclean_kyber1024 $COMMON_FEATURES"
cargo test $TARGET --features "hfs use-pqcrypto-kyber1024 $COMMON_FEATURES"
cargo test $TARGET --features "ring-resolver hfs use-pqcrypto-kyber1024 $COMMON_FEATURES"
fi
cargo test $TARGET --features "libsodium-resolver $COMMON_FEATURES"
cargo test $TARGET --features "libsodium-accelerated $COMMON_FEATURES"
15 changes: 11 additions & 4 deletions src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::fmt::Debug;
use core::fmt::Debug;

#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, vec, vec::Vec};

#[cfg(feature = "hfs")]
use crate::params::HandshakeModifier;
Expand Down Expand Up @@ -45,7 +48,7 @@ impl PartialEq for Keypair {
/// # use snow::Builder;
/// # let my_long_term_key = [0u8; 32];
/// # let their_pub_key = [0u8; 32];
/// # #[cfg(any(feature = "default-resolver", feature = "ring-accelerated"))]
/// # #[cfg(any(feature = "default-resolver-crypto", feature = "ring-accelerated"))]
/// let noise = Builder::new("Noise_XX_25519_ChaChaPoly_BLAKE2s".parse()?)
/// .local_private_key(&my_long_term_key)?
/// .remote_public_key(&their_pub_key)?
Expand All @@ -65,7 +68,7 @@ pub struct Builder<'builder> {
}

impl<'builder> Debug for Builder<'builder> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Builder").field("params", &self.params.name).finish_non_exhaustive()
}
}
Expand Down Expand Up @@ -317,8 +320,12 @@ impl<'builder> Builder<'builder> {
}
}


#[cfg(test)]
#[cfg(any(feature = "default-resolver", feature = "ring-accelerated"))]
#[cfg(all(
feature = "std",
any(feature = "default-resolver-crypto", feature = "ring-accelerated")
))]
mod tests {
use super::*;
type TestResult = Result<(), Box<dyn std::error::Error>>;
Expand Down
3 changes: 3 additions & 0 deletions src/cipherstate.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;

use crate::{
constants::{CIPHERKEYLEN, TAGLEN},
error::{Error, InitStage, StateProblem},
Expand Down
3 changes: 2 additions & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! All error types used by Snow operations.

use std::fmt;
use core::fmt;

/// `snow` provides decently detailed errors, exposed as the [`Error`] enum,
/// to allow developers to react to errors in a more actionable way.
Expand Down Expand Up @@ -181,4 +181,5 @@ impl fmt::Display for Error {
}
}

#[cfg(feature = "std")]
impl std::error::Error for Error {}
4 changes: 3 additions & 1 deletion src/handshakestate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ use crate::{
types::{Dh, Hash, Random},
utils::Toggle,
};
use std::{
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
use core::{
convert::{TryFrom, TryInto},
fmt,
};
Expand Down
24 changes: 22 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//! ```
//! # use snow::Error;
//! #
//! # #[cfg(any(feature = "default-resolver", feature = "ring-accelerated"))]
//! # #[cfg(any(feature = "default-resolver-crypto", feature = "ring-accelerated"))]
//! # fn try_main() -> Result<(), Error> {
//! static PATTERN: &'static str = "Noise_NN_25519_ChaChaPoly_BLAKE2s";
//!
Expand Down Expand Up @@ -43,7 +43,7 @@
//! # Ok(())
//! # }
//! #
//! # #[cfg(not(any(feature = "default-resolver", feature = "ring-accelerated")))]
//! # #[cfg(not(any(feature = "default-resolver-crypto", feature = "ring-accelerated")))]
//! # fn try_main() -> Result<(), ()> { Ok(()) }
//! #
//! # fn main() {
Expand All @@ -54,6 +54,26 @@
//! See `examples/simple.rs` for a more complete TCP client/server example with static keys.

#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(not(feature = "std"))]
extern crate alloc;

// Make sure the user is running a supported configuration.
#[cfg(feature = "default-resolver")]
#[cfg(any(
not(any(feature = "use-curve25519-dalek")),
not(any(
feature = "use-aes-gcm",
feature = "use-chacha20poly1305",
feature = "use-xchacha20poly1305"
)),
not(any(feature = "use-sha2", feature = "use-blake2"))
))]
compile_error!(
"Valid selection of crypto primitived must be enabled when using feature 'default-resolver'.
Enable at least one DH feature, one Cipher feature and one Hash feature. Check README.md for details."
);

macro_rules! copy_slices {
($inslice:expr, $outslice:expr) => {
Expand Down
11 changes: 7 additions & 4 deletions src/params/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
//! All structures related to Noise parameter definitions (cryptographic primitive choices, protocol
//! patterns/names)

#[cfg(not(feature = "std"))]
use alloc::{borrow::ToOwned, string::String};

use crate::error::{Error, PatternProblem};
use std::str::FromStr;
use core::str::FromStr;
mod patterns;

pub use self::patterns::{
Expand Down Expand Up @@ -61,7 +64,7 @@ impl FromStr for DHChoice {
pub enum CipherChoice {
/// The ChaCha20Poly1305 AEAD.
ChaChaPoly,
#[cfg(feature = "xchachapoly")]
#[cfg(feature = "use-xchacha20poly1305")]
/// The XChaCha20Poly1305 AEAD, an extended nonce variant of ChaCha20Poly1305.
/// This variant is hidden behind a feature flag to highlight that it is not in the
/// official specification of the Noise Protocol.
Expand All @@ -77,7 +80,7 @@ impl FromStr for CipherChoice {
use self::CipherChoice::*;
match s {
"ChaChaPoly" => Ok(ChaChaPoly),
#[cfg(feature = "xchachapoly")]
#[cfg(feature = "use-xchacha20poly1305")]
"XChaChaPoly" => Ok(XChaChaPoly),
"AESGCM" => Ok(AESGCM),
_ => Err(PatternProblem::UnsupportedCipherType.into()),
Expand Down Expand Up @@ -257,7 +260,7 @@ impl FromStr for NoiseParams {
#[cfg(test)]
mod tests {
use super::*;
use std::convert::TryFrom;
use core::convert::TryFrom;

#[test]
fn test_simple_handshake() {
Expand Down
5 changes: 4 additions & 1 deletion src/params/patterns.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#![allow(clippy::enum_glob_use)]

#[cfg(not(feature = "std"))]
use alloc::{vec, vec::Vec};

use crate::error::{Error, PatternProblem};
use std::{convert::TryFrom, str::FromStr};
use core::{convert::TryFrom, str::FromStr};

/// A small helper macro that behaves similar to the `vec![]` standard macro,
/// except it allocates a bit extra to avoid resizing.
Expand Down
Loading
Loading