diff --git a/Cargo.toml b/Cargo.toml index b60c431d747d559dda0297f901b3e6f1eb16bec2..d66e10deddc4fe89d692691393ab47e4b8541147 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ arrayvec = { version = "0.5.1", features = ["array-sizes-33-128", "array-sizes-1 base64 = "0.11.0" bs58 = "0.3.0" byteorder = "1.3.2" +curve25519-dalek = "2.0.0" ring = "0.16.9" scrypt = { version = "0.2", default-features = false } serde = { version = "1.0.*", features = ["derive"], optional = true } diff --git a/src/keys/ed25519.rs b/src/keys/ed25519.rs index d3b4a452bb3afa3282ed156eef75c765c53e18a6..e7d178b23ed8d90a9386c38bec4a7ab7923136d4 100644 --- a/src/keys/ed25519.rs +++ b/src/keys/ed25519.rs @@ -27,6 +27,7 @@ use crate::bases::*; use crate::rand::UnspecifiedRandError; use crate::seeds::Seed32; use base64; +use curve25519_dalek::edwards::CompressedEdwardsY; use ring::signature::{Ed25519KeyPair as RingKeyPair, KeyPair, UnparsedPublicKey, ED25519}; #[cfg(feature = "ser")] use serde::{ @@ -73,6 +74,7 @@ impl Serialize for Signature { } #[cfg(feature = "ser")] +#[cfg_attr(tarpaulin, skip)] impl<'de> Deserialize<'de> for Signature { fn deserialize<D>(deserializer: D) -> Result<Signature, D::Error> where @@ -187,12 +189,19 @@ impl TryFrom<&[u8]> for PublicKey { found: bytes.len(), }) } else { - let mut u8_array = [0; PUBKEY_SIZE_IN_BYTES]; - u8_array[(PUBKEY_SIZE_IN_BYTES - bytes.len())..].copy_from_slice(&bytes); - Ok(PublicKey { - datas: u8_array, - count_leading_zero: 0, - }) + // Ensure that given bytes represents a valid point on the Edwards form of Curve25519. + let compressed_edwards_y = CompressedEdwardsY::from_slice(bytes); + if compressed_edwards_y.decompress().is_some() { + let mut u8_array = [0; PUBKEY_SIZE_IN_BYTES]; + u8_array[(PUBKEY_SIZE_IN_BYTES - bytes.len())..].copy_from_slice(bytes); + + Ok(PublicKey { + datas: u8_array, + count_leading_zero: 0, + }) + } else { + Err(PubkeyFromBytesError::InvalidBytesContent) + } } } } @@ -684,6 +693,42 @@ Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 assert!(keypair.verify(message.as_bytes(), &sig).is_ok()); } + #[test] + fn invalid_pubkey() -> Result<(), ()> { + let invalid_bytes = [ + 206u8, 58, 67, 221, 20, 133, 0, 225, 86, 115, 26, 104, 142, 116, 140, 132, 119, 51, + 175, 45, 82, 225, 14, 195, 7, 107, 43, 212, 8, 37, 234, 23, + ]; + if let Err(PubkeyFromBytesError::InvalidBytesContent) = + PublicKey::try_from(&invalid_bytes[..]) + { + Ok(()) + } else { + panic!("expected PubkeyFromBytesError::InvalidBytesContent"); + } + } + + #[test] + fn test_parse_expanded_base58_private_key() { + let bytes = bs58::decode( + "31uSnvigJtJEUgG4YDqJB99awp4hkYgYqb3Yzu8P1LP5ZPMHtwNoCohVhm6jKcG9HFHbagDWdcoPgYBgHhdg5Efo" + ).into_vec().expect("fail to decode b58"); + let mut seed = [0u8; 32]; + seed.copy_from_slice(&bytes[..32]); + let mut pubkey_bytes = [0u8; 32]; + pubkey_bytes.copy_from_slice(&bytes[32..64]); + + let keypair = KeyPairFromSeed32Generator::generate(Seed32::new(seed)); + assert_eq!( + "8hgzaeFnjkNCsemcaL4rmhB2999B79BydtE8xow4etB7", + &keypair.public_key().to_base58() + ); + assert_eq!( + "8hgzaeFnjkNCsemcaL4rmhB2999B79BydtE8xow4etB7", + &bs58::encode(&pubkey_bytes).into_string(), + ); + } + /*#[test] fn test_tmp() { let message = "InnerHash: A9697A9954EA447BBDC88D1B22AA8B60B2D11986DE806319C1A5AAFEB348C213\nNonce: 10300000043648\n"; diff --git a/src/keys/mod.rs b/src/keys/mod.rs index 5ed87046c7fd4a9dcb432928ef4cdee2ff19de90..0f591565dc2d315b9bf26cc36ed9a7241c539961 100644 --- a/src/keys/mod.rs +++ b/src/keys/mod.rs @@ -251,6 +251,8 @@ pub enum PubkeyFromBytesError { /// Found length found: usize, }, + /// Invalid bytes content + InvalidBytesContent, } impl PubKey {