Skip to content

Commit

Permalink
Add ed25519 key conversion helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
l1h3r committed Apr 7, 2021
1 parent fd4a19d commit cc4b03f
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 2 deletions.
1 change: 1 addition & 0 deletions libjose/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ serde_json = { version = "1.0", default-features = false }
url = { version = "2.2", default-features = false, features = ["serde"] }
zeroize = { version = "1.2", default-features = false, features = ["zeroize_derive"] }

curve25519-dalek = { version = "3.0", default-features = false }
num-bigint-dig = { version = "0.7", default-features = false }
rand = { version = "0.8", default-features = false, features = ["getrandom"] }
rsa = { version = "0.4", default-features = false, features = ["pem", "std"] }
Expand Down
16 changes: 14 additions & 2 deletions libjose/src/utils/crypto/key_repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ pub type X25519SecretKey = crypto::keys::x25519::SecretKey;
pub type X448PublicKey = crypto::keys::x448::PublicKey;
pub type X448SecretKey = crypto::keys::x448::SecretKey;

const ED25519_PUBLIC_KEY_LEN: usize = crypto::signatures::ed25519::COMPRESSED_PUBLIC_KEY_LENGTH;
const ED25519_SECRET_KEY_LEN: usize = crypto::signatures::ed25519::SECRET_KEY_LENGTH;
pub const ED25519_PUBLIC_KEY_LEN: usize = crypto::signatures::ed25519::COMPRESSED_PUBLIC_KEY_LENGTH;
pub const ED25519_SECRET_KEY_LEN: usize = crypto::signatures::ed25519::SECRET_KEY_LENGTH;

pub const X25519_PUBLIC_KEY_LEN: usize = crypto::keys::x25519::PUBLIC_KEY_LEN;
pub const X25519_SECRET_KEY_LEN: usize = crypto::keys::x25519::SECRET_KEY_LEN;

#[derive(Clone, Copy, Debug)]
pub enum Secret<'a> {
Expand Down Expand Up @@ -216,6 +219,15 @@ impl<'a> From<&'a Jwk> for Secret<'a> {
}
}

impl<'a, T> From<&'a T> for Secret<'a>
where
T: AsRef<[u8]>,
{
fn from(other: &'a T) -> Self {
Self::Arr(other.as_ref())
}
}

// =============================================================================
// =============================================================================

Expand Down
2 changes: 2 additions & 0 deletions libjose/src/utils/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ mod key_params;
mod key_repr;
mod random;
mod rsa_primes;
mod x25519;

pub use self::concat_kdf::*;
pub use self::diffie_hellman::*;
pub use self::key_params::*;
pub use self::key_repr::*;
pub use self::random::*;
pub use self::rsa_primes::*;
pub use self::x25519::*;
81 changes: 81 additions & 0 deletions libjose/src/utils/crypto/x25519.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2020-2021 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use core::convert::TryInto;
use crypto::hashes::sha::Sha512;
use crypto::hashes::Digest;
use crypto::hashes::Output;
use curve25519_dalek::edwards::CompressedEdwardsY;
use zeroize::Zeroize;

use crate::error::Error;
use crate::error::Result;
use crate::utils::ED25519_PUBLIC_KEY_LEN;
use crate::utils::ED25519_SECRET_KEY_LEN;
use crate::utils::X25519_PUBLIC_KEY_LEN;
use crate::utils::X25519_SECRET_KEY_LEN;

pub fn ed25519_to_x25519_public<T>(public: &T) -> Result<[u8; X25519_PUBLIC_KEY_LEN]>
where
T: AsRef<[u8]> + ?Sized,
{
let mut ed25519: [u8; ED25519_PUBLIC_KEY_LEN] = public
.as_ref()
.try_into()
.map_err(|_| Error::KeyError("ed25519_to_x25519_public"))?;

let x25519: [u8; X25519_PUBLIC_KEY_LEN] = CompressedEdwardsY(ed25519)
.decompress()
.map(|edwards| edwards.to_montgomery().0)
.ok_or(Error::KeyError("ed25519_to_x25519_public"))?;

ed25519.zeroize();

Ok(x25519)
}

pub fn ed25519_to_x25519_secret<T>(secret: &T) -> Result<[u8; X25519_SECRET_KEY_LEN]>
where
T: AsRef<[u8]> + ?Sized,
{
let mut ed25519: [u8; ED25519_SECRET_KEY_LEN] = secret
.as_ref()
.try_into()
.map_err(|_| Error::KeyError("ed25519_to_x25519_secret"))?;

let mut x25519: [u8; X25519_SECRET_KEY_LEN] = [0; X25519_SECRET_KEY_LEN];
let hash: Output<Sha512> = Sha512::digest(&ed25519);

x25519.copy_from_slice(&hash[..X25519_SECRET_KEY_LEN]);
x25519[0] &= 248;
x25519[31] &= 127;
x25519[31] |= 64;

ed25519.zeroize();

Ok(x25519)
}

#[cfg(test)]
mod tests {
use super::*;
use crate::utils::Ed25519PublicKey;
use crate::utils::Ed25519SecretKey;
use crate::utils::X25519PublicKey;
use crate::utils::X25519SecretKey;

#[test]
fn test_convert_ed25519() {
let ed25519_sk: Ed25519SecretKey = Ed25519SecretKey::generate().unwrap();
let ed25519_pk: Ed25519PublicKey = ed25519_sk.public_key();

let derived_sk = ed25519_to_x25519_secret(&ed25519_sk.to_le_bytes()).unwrap();
let derived_pk = ed25519_to_x25519_public(ed25519_pk.as_ref()).unwrap();

let x25519_sk: X25519SecretKey = X25519SecretKey::from_bytes(&derived_sk).unwrap();
let x25519_pk: X25519PublicKey = X25519PublicKey::from_bytes(&derived_pk).unwrap();

assert_eq!(derived_sk, x25519_sk.to_bytes());
assert_eq!(derived_pk, x25519_pk.to_bytes());
}
}

0 comments on commit cc4b03f

Please sign in to comment.