Skip to content
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
9 changes: 9 additions & 0 deletions wrapper/rust/wolfssl-wolfcrypt/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,20 @@ Breaking changes:

- Curve25519Key::generate() now takes ownership of the RNG instead of borrowing
it; the key holds the RNG for its lifetime
- Ed25519 and Ed448 no longer implement the signature crate's Keypair trait;
use the new SigningKey types instead

New features:

- Add Curve25519Key::generate_shared_rng() to generate a key from an RNG shared
between keys via Rc (requires the alloc feature)
- Add ed25519::SigningKey and ed448::SigningKey, which always carry a public
key and so implement Keypair::verifying_key() without it being able to fail

Fixes and improvements:

- Fix a panic in Keypair::verifying_key() for Ed25519 and Ed448 keys with no
public key, such as after new() or import_private_only()

## v2.2.0

Expand Down
198 changes: 191 additions & 7 deletions wrapper/rust/wolfssl-wolfcrypt/src/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1504,13 +1504,17 @@ impl Drop for Ed25519 {

/// RustCrypto `signature` crate trait implementations.
///
/// Provides a fixed-size [`Signature`] and a [`VerifyingKey`] type so that
/// [`Ed25519`] can be used wherever the `signature` crate's
/// [`signature::SignerMut`], [`signature::Keypair`], and
/// Provides a fixed-size [`Signature`], a [`VerifyingKey`] and a
/// [`SigningKey`] type so that Ed25519 keys can be used wherever the
/// `signature` crate's [`signature::SignerMut`], [`signature::Keypair`], and
/// [`signature::Verifier`] traits are accepted.
#[cfg(feature = "signature")]
mod signature_impl {
use super::Ed25519;
#[cfg(all(ed25519_sign, ed25519_export))]
use zeroize::Zeroize;
#[cfg(all(ed25519_make_key, ed25519_sign, ed25519_export, random))]
use crate::random::RNG;
use signature::Error;

/// Ed25519 signature in its standard 64-byte encoded form.
Expand Down Expand Up @@ -1587,13 +1591,191 @@ mod signature_impl {
}
}

/// Ed25519 signing (private) key that is guaranteed to carry a public key.
///
/// An [`Ed25519`] on its own may hold no public key: `Ed25519::new()`
/// leaves the key empty and `Ed25519::import_private_only()` loads only
/// the private scalar. [`signature::Keypair::verifying_key()`] cannot
/// fail, so it is implemented for this type rather than for [`Ed25519`].
/// Every constructor here derives or validates the public key and caches
/// it, which makes handing out a [`VerifyingKey`] infallible.
#[cfg(all(ed25519_sign, ed25519_export))]
pub struct SigningKey {
inner: Ed25519,
public: [u8; Ed25519::PUB_KEY_SIZE],
}

#[cfg(all(ed25519_sign, ed25519_export))]
impl signature::Keypair for Ed25519 {
impl SigningKey {
/// Generate a new Ed25519 signing key.
///
/// # Parameters
///
/// * `rng`: Random number generator to use.
///
/// # Returns
///
/// Returns either Ok(signing_key) containing the SigningKey struct
/// instance or Err(e) containing the wolfSSL library error code value.
///
/// # Example
///
/// ```rust
/// #[cfg(all(feature = "signature", ed25519_make_key, ed25519_sign, ed25519_export, random))]
/// {
/// use wolfssl_wolfcrypt::random::RNG;
/// use wolfssl_wolfcrypt::ed25519::SigningKey;
/// let rng = RNG::new().expect("Error creating RNG");
/// let sk = SigningKey::generate(&rng).expect("Error with generate()");
/// }
/// ```
#[cfg(all(ed25519_make_key, random))]
pub fn generate(rng: &RNG) -> Result<Self, i32> {
Self::from_key(Ed25519::generate(rng)?)
}

/// Create a signing key from a private key, deriving its public key.
///
/// # Parameters
///
/// * `private`: Input buffer containing the private key.
///
/// # Returns
///
/// Returns either Ok(signing_key) containing the SigningKey struct
/// instance or Err(e) containing the wolfSSL library error code value.
///
/// # Example
///
/// ```rust
/// #[cfg(all(feature = "signature", ed25519_make_key, ed25519_import, ed25519_export, ed25519_sign, random))]
/// {
/// use wolfssl_wolfcrypt::random::RNG;
/// use wolfssl_wolfcrypt::ed25519::{Ed25519, SigningKey};
/// let rng = RNG::new().expect("Error creating RNG");
/// let ed = Ed25519::generate(&rng).expect("Error with generate()");
/// let mut private = [0u8; Ed25519::KEY_SIZE];
/// ed.export_private_only(&mut private).expect("Error with export_private_only()");
/// let sk = SigningKey::from_private_only(&private).expect("Error with from_private_only()");
/// }
/// ```
#[cfg(all(ed25519_import, ed25519_make_key))]
pub fn from_private_only(private: &[u8; Ed25519::KEY_SIZE]) -> Result<Self, i32> {
let mut key = Ed25519::new()?;
key.import_private_only(private)?;
let mut public = [0u8; Ed25519::PUB_KEY_SIZE];
key.make_public(&mut public)?;
Ok(Self { inner: key, public })
}

/// Create a signing key from a private key and its public key.
///
/// The public key is untrusted and is checked against the private key.
///
/// # Parameters
///
/// * `private`: Input buffer containing the private key.
/// * `public`: Input buffer containing the public key.
///
/// # Returns
///
/// Returns either Ok(signing_key) containing the SigningKey struct
/// instance or Err(e) containing the wolfSSL library error code value.
///
/// # Example
///
/// ```rust
/// #[cfg(all(feature = "signature", ed25519_make_key, ed25519_import, ed25519_export, ed25519_sign, random))]
/// {
/// use wolfssl_wolfcrypt::random::RNG;
/// use wolfssl_wolfcrypt::ed25519::{Ed25519, SigningKey};
/// let rng = RNG::new().expect("Error creating RNG");
/// let ed = Ed25519::generate(&rng).expect("Error with generate()");
/// let mut private = [0u8; Ed25519::KEY_SIZE];
/// let mut public = [0u8; Ed25519::PUB_KEY_SIZE];
/// ed.export_private_only(&mut private).expect("Error with export_private_only()");
/// ed.export_public(&mut public).expect("Error with export_public()");
/// let sk = SigningKey::from_keypair(&private, &public).expect("Error with from_keypair()");
/// }
/// ```
#[cfg(ed25519_import)]
pub fn from_keypair(private: &[u8; Ed25519::KEY_SIZE],
public: &[u8; Ed25519::PUB_KEY_SIZE]) -> Result<Self, i32>
{
let mut key = Ed25519::new()?;
key.import_private_key(private, Some(public))?;
Ok(Self { inner: key, public: *public })
}

/// Create a signing key from an existing [`Ed25519`] key.
///
/// Both key components must be present. Fails with the wolfSSL error
/// code `PUBLIC_KEY_E` when `key` holds no public key, for instance
/// after `Ed25519::new()` or `Ed25519::import_private_only()`, and with
/// `BAD_FUNC_ARG` when it holds no private key, for instance after
/// `Ed25519::import_public()`.
///
/// # Parameters
///
/// * `key`: The Ed25519 key to wrap.
///
/// # Returns
///
/// Returns either Ok(signing_key) containing the SigningKey struct
/// instance or Err(e) containing the wolfSSL library error code value.
///
/// # Example
///
/// ```rust
/// #[cfg(all(feature = "signature", ed25519_make_key, ed25519_export, ed25519_sign, random))]
/// {
/// use wolfssl_wolfcrypt::random::RNG;
/// use wolfssl_wolfcrypt::ed25519::{Ed25519, SigningKey};
/// let rng = RNG::new().expect("Error creating RNG");
/// let ed = Ed25519::generate(&rng).expect("Error with generate()");
/// let sk = SigningKey::from_key(ed).expect("Error with from_key()");
/// }
/// ```
pub fn from_key(key: Ed25519) -> Result<Self, i32> {
Comment thread
holtrop-wolfssl marked this conversation as resolved.
let mut public = [0u8; Ed25519::PUB_KEY_SIZE];
key.export_public(&mut public)?;
/* A key carrying only a public component would build a SigningKey
* that cannot sign, so require the private component too.
* Exporting it is the only way to ask wolfCrypt whether it is
* there; the copy is wiped again right away. */
let mut private = [0u8; Ed25519::KEY_SIZE];
let ret = key.export_private_only(&mut private);
private.zeroize();
ret?;
Ok(Self { inner: key, public })
}

/// Borrow the wrapped [`Ed25519`] key for operations that are not
/// covered by the signature traits.
pub fn as_key(&self) -> &Ed25519 {
&self.inner
}

/// Consume the signing key and return the wrapped [`Ed25519`] key.
pub fn into_key(self) -> Ed25519 {
self.inner
}
}

#[cfg(all(ed25519_sign, ed25519_export))]
impl signature::Keypair for SigningKey {
type VerifyingKey = VerifyingKey;
fn verifying_key(&self) -> Self::VerifyingKey {
let mut pub_key = [0u8; Ed25519::PUB_KEY_SIZE];
self.export_public(&mut pub_key).expect("ed25519 export_public failed");
VerifyingKey(pub_key)
VerifyingKey(self.public)
}
}

#[cfg(all(ed25519_sign, ed25519_export))]
impl signature::SignerMut<Signature> for SigningKey {
fn try_sign(&mut self, msg: &[u8]) -> Result<Signature, Error> {
let mut sig = [0u8; Ed25519::SIG_SIZE];
self.inner.sign_msg(msg, &mut sig).map_err(|_| Error::new())?;
Ok(Signature(sig))
}
}

Expand Down Expand Up @@ -1621,3 +1803,5 @@ mod signature_impl {

#[cfg(feature = "signature")]
pub use signature_impl::{Signature, VerifyingKey};
#[cfg(all(feature = "signature", ed25519_sign, ed25519_export))]
pub use signature_impl::SigningKey;
Loading
Loading