Skip to content
Snippets Groups Projects
Commit 8516ddde authored by Éloïs's avatar Éloïs
Browse files

[fix] keys:ed25519: pubkey as_ref/to_bytes must be consistent with serde

parent 9cd41756
Branches
No related tags found
No related merge requests found
......@@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] - ReleaseDate
### Fixed
- keys: ed25519 public key methods (as_ref, try_from, to_bytes_vector) must be consistent with bincode serialization/deserialization
## [0.13.0] - 2020-03-04
### Added
......
......@@ -24,7 +24,7 @@ pub trait ToBase58 {
}
/// Create an array of 32 bytes from a Base58 string.
pub fn str_base58_to_32bytes(base58_data: &str) -> Result<([u8; 32], usize), BaseConvertionError> {
pub fn str_base58_to_32bytes(base58_data: &str) -> Result<([u8; 32], u8), BaseConvertionError> {
let mut source = base58_data;
let mut count_leading_1 = 0;
while !source.is_empty() && &source[0..1] == "1" {
......@@ -58,7 +58,7 @@ pub fn str_base58_to_32bytes(base58_data: &str) -> Result<([u8; 32], usize), Bas
}
/// Create a Base58 string from a slice of bytes.
pub fn bytes_to_str_base58(bytes: &[u8], count_leading_1: usize) -> String {
pub fn bytes_to_str_base58(bytes: &[u8], count_leading_1: u8) -> String {
let mut str_base58 = String::new();
let mut remaining_leading_1 = count_leading_1;
while remaining_leading_1 > 0 {
......@@ -72,7 +72,7 @@ pub fn bytes_to_str_base58(bytes: &[u8], count_leading_1: usize) -> String {
let bytes = if count_leading_1 == 0 && !bytes.is_empty() && bytes[0] == 0 {
&bytes[1..]
} else {
&bytes[count_leading_1..]
&bytes[count_leading_1 as usize..]
};
str_base58.push_str(&bs58::encode(bytes).into_string());
......
......@@ -16,9 +16,9 @@
//! Read [DEWIF](https://git.duniter.org/nodes/common/doc/blob/dewif/rfc/0013_Duniter_Encrypted_Wallet_Import_Format.md) file content
use super::{Currency, ExpectedCurrency};
use crate::keys::ed25519::{KeyPairFromSeed32Generator, PublicKey, PUBKEY_SIZE_IN_BYTES};
use crate::keys::ed25519::{KeyPairFromSeed32Generator, PublicKey, PUBKEY_DATAS_SIZE_IN_BYTES};
use crate::keys::{KeyPair, KeyPairEnum};
use crate::seeds::Seed32;
use crate::seeds::{Seed32, SEED_32_SIZE_IN_BYTES};
use arrayvec::ArrayVec;
use byteorder::ByteOrder;
use std::convert::{TryFrom, TryInto};
......@@ -135,11 +135,12 @@ fn read_dewif_v2(bytes: &mut [u8], passphrase: &str) -> Result<KeyPairsIter, Dew
fn bytes_to_checked_keypair(bytes: &[u8]) -> Result<KeyPairEnum, DewifReadError> {
// Wrap bytes into Seed32 and PublicKey
let seed = Seed32::new(
(&bytes[..PUBKEY_SIZE_IN_BYTES])
(&bytes[..SEED_32_SIZE_IN_BYTES])
.try_into()
.expect("dev error"),
);
let expected_pubkey = PublicKey::try_from(&bytes[PUBKEY_SIZE_IN_BYTES..]).expect("dev error");
let expected_pubkey =
PublicKey::try_from(&bytes[PUBKEY_DATAS_SIZE_IN_BYTES..]).expect("dev error");
// Get keypair
let keypair = KeyPairFromSeed32Generator::generate(seed);
......
......@@ -32,7 +32,7 @@ pub fn write_dewif_v1_content(
let currency_code: u32 = currency.into();
unwrap!(bytes.try_extend_from_slice(&currency_code.to_be_bytes()));
unwrap!(bytes.try_extend_from_slice(keypair.seed().as_ref()));
unwrap!(bytes.try_extend_from_slice(keypair.public_key().as_ref()));
unwrap!(bytes.try_extend_from_slice(keypair.public_key().datas.as_ref()));
let cipher = crate::aes256::new_cipher(super::gen_aes_seed(passphrase));
crate::aes256::encrypt::encrypt_n_blocks(
......@@ -56,9 +56,9 @@ pub fn write_dewif_v2_content(
let currency_code: u32 = currency.into();
unwrap!(bytes.try_extend_from_slice(&currency_code.to_be_bytes()));
unwrap!(bytes.try_extend_from_slice(keypair1.seed().as_ref()));
unwrap!(bytes.try_extend_from_slice(keypair1.public_key().as_ref()));
unwrap!(bytes.try_extend_from_slice(keypair1.public_key().datas.as_ref()));
unwrap!(bytes.try_extend_from_slice(keypair2.seed().as_ref()));
unwrap!(bytes.try_extend_from_slice(keypair2.public_key().as_ref()));
unwrap!(bytes.try_extend_from_slice(keypair2.public_key().datas.as_ref()));
let cipher = crate::aes256::new_cipher(super::gen_aes_seed(passphrase));
crate::aes256::encrypt::encrypt_8_blocks(&cipher, &mut bytes[super::UNENCRYPTED_BYTES_LEN..]);
......
......@@ -510,7 +510,7 @@ mod tests {
}
#[test]
fn pubkey() {
fn public_key() {
let ed25519_pubkey_default = ed25519::PublicKey::default();
let pubkey_default = PubKey::Ed25519(ed25519_pubkey_default);
let pubkey = PubKey::Ed25519(unwrap!(ed25519::PublicKey::try_from(
......@@ -524,14 +524,16 @@ mod tests {
);
assert_eq!(pubkey.size_in_bytes(), ed25519::PUBKEY_SIZE_IN_BYTES + 3);
assert_eq!("1111111111111111111111111111111", &format!("{}", pubkey));
assert_eq!("11111111111111111111111111111111", &format!("{}", pubkey));
assert_eq!(KeysAlgo::Ed25519, pubkey.algo());
assert_eq!(KeysAlgo::Schnorr, PubKey::Schnorr().algo());
assert_eq!([0u8; 32].to_vec(), pubkey.to_bytes_vector());
let mut expected_vec = [0u8; 32].to_vec();
expected_vec.push(32);
assert_eq!(expected_vec, pubkey.to_bytes_vector());
assert_eq!("1111111111111111111111111111111", &pubkey.to_base58());
assert_eq!("11111111111111111111111111111111", &pubkey.to_base58());
assert_eq!(
Err(SigError::InvalidSig),
......@@ -723,11 +725,11 @@ mod tests {
assert_eq!(
Err(PubkeyFromBytesError::InvalidBytesLen {
expected: ed25519::PUBKEY_SIZE_IN_BYTES,
found: 33,
found: 34,
}),
PubKey::from_bytes(&[
0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 31
23, 24, 25, 26, 27, 28, 29, 30, 31, 31, 17
]),
);
}
......
......@@ -44,8 +44,9 @@ use std::marker::PhantomData;
use unwrap::unwrap;
use zeroize::Zeroize;
/// Maximal size of a public key in bytes
pub const PUBKEY_SIZE_IN_BYTES: usize = 32;
/// Size of a public key in bytes
pub const PUBKEY_SIZE_IN_BYTES: usize = 33;
pub(crate) const PUBKEY_DATAS_SIZE_IN_BYTES: usize = 32;
/// constf a signature in bytes
pub const SIG_SIZE_IN_BYTES: usize = 64;
......@@ -160,8 +161,8 @@ impl Eq for Signature {}
#[cfg_attr(feature = "ser", derive(Deserialize, Serialize))]
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct PublicKey {
datas: [u8; 32],
count_leading_zero: usize,
pub(crate) datas: [u8; 32],
count_leading_zero: u8,
}
impl Default for PublicKey {
......@@ -175,7 +176,7 @@ impl Default for PublicKey {
impl AsRef<[u8]> for PublicKey {
fn as_ref(&self) -> &[u8] {
&self.datas[..]
unsafe { std::slice::from_raw_parts(self.datas.as_ptr(), PUBKEY_SIZE_IN_BYTES) }
}
}
......@@ -189,15 +190,24 @@ impl TryFrom<&[u8]> for PublicKey {
found: bytes.len(),
})
} else {
let (count_leading_zero, datas_bytes) = if bytes.len() <= PUBKEY_DATAS_SIZE_IN_BYTES {
(0, bytes)
} else {
(
bytes[PUBKEY_DATAS_SIZE_IN_BYTES],
&bytes[..PUBKEY_DATAS_SIZE_IN_BYTES],
)
};
// Ensure that given bytes represents a valid point on the Edwards form of Curve25519.
let compressed_edwards_y = CompressedEdwardsY::from_slice(bytes);
let compressed_edwards_y = CompressedEdwardsY::from_slice(datas_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);
let mut u8_array = [0; PUBKEY_DATAS_SIZE_IN_BYTES];
u8_array[(PUBKEY_DATAS_SIZE_IN_BYTES - datas_bytes.len())..]
.copy_from_slice(datas_bytes);
Ok(PublicKey {
datas: u8_array,
count_leading_zero: 0,
count_leading_zero,
})
} else {
Err(PubkeyFromBytesError::InvalidBytesContent)
......@@ -208,7 +218,7 @@ impl TryFrom<&[u8]> for PublicKey {
impl ToBase58 for PublicKey {
fn to_base58(&self) -> String {
bytes_to_str_base58(self.as_ref(), self.count_leading_zero)
bytes_to_str_base58(self.datas.as_ref(), self.count_leading_zero)
}
}
......@@ -217,7 +227,7 @@ impl Display for PublicKey {
write!(
f,
"{}",
bytes_to_str_base58(self.as_ref(), self.count_leading_zero)
bytes_to_str_base58(self.datas.as_ref(), self.count_leading_zero)
)
}
}
......@@ -246,7 +256,7 @@ impl super::PublicKey for PublicKey {
}
fn verify(&self, message: &[u8], signature: &Self::Signature) -> Result<(), SigError> {
Ok(UnparsedPublicKey::new(&ED25519, self.as_ref())
Ok(UnparsedPublicKey::new(&ED25519, self.datas.as_ref())
.verify(message, &signature.0)
.map_err(|_| SigError::InvalidSig)?)
}
......@@ -459,13 +469,6 @@ mod tests {
assert!(!seed.eq(&other_seed));
// Test seed parsing
/*assert_eq!(
Seed32::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd",).unwrap_err(),
BaseConvertionError::InvalidLength {
found: 31,
expected: 32
}
);*/
assert_eq!(
Seed32::from_base58("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQd<<").unwrap_err(),
BaseConvertionError::InvalidCharacter {
......@@ -476,24 +479,67 @@ mod tests {
}
#[test]
fn test_pubkey_111_from_base58() {
fn test_pubkey_111_from_base58() -> Result<(), bincode::Error> {
let public58 = "11111111111111111111111111111111111111111111";
let _ = unwrap!(super::PublicKey::from_base58(public58));
let public_key = unwrap!(super::PublicKey::from_base58(public58));
assert_eq!(
&[
0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 44
][..],
public_key.as_ref(),
);
assert_eq!(
bincode::serialize(&public_key)?,
public_key.to_bytes_vector(),
);
Ok(())
}
#[test]
fn test_pubkey_with_leading_1() -> Result<(), bincode::Error> {
let public58 = "13fn6X3XWVgshHTgS8beZMo9XiyScx6MB6yPsBB5ZBia";
let public_key = unwrap!(super::PublicKey::from_base58(public58));
assert_eq!(
bincode::serialize(&public_key)?,
public_key.to_bytes_vector(),
);
Ok(())
}
#[test]
fn test_other_pubkey_with_leading_1() -> Result<(), bincode::Error> {
let public58 = "1V27SH9TiVEDs8TWFPydpRKxhvZari7wjGwQnPxMnkr";
let public_key = unwrap!(super::PublicKey::from_base58(public58));
assert_eq!(
bincode::serialize(&public_key)?,
public_key.to_bytes_vector(),
);
Ok(())
}
#[test]
fn base58_public_key() {
fn base58_public_key() -> Result<(), bincode::Error> {
let public58 = "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV";
let public_key = unwrap!(super::PublicKey::from_base58(public58));
// Test base58 encoding/decoding (loop for every bytes)
assert_eq!(public_key.to_base58(), public58);
let public_raw = unwrap!(b58::str_base58_to_32bytes(public58));
assert_eq!(public_raw.0.to_vec(), public_key.to_bytes_vector());
for (key, raw) in public_key.as_ref().iter().zip(public_raw.0.iter()) {
assert_eq!(
public_raw.0.to_vec(),
&public_key.to_bytes_vector()[..PUBKEY_DATAS_SIZE_IN_BYTES]
);
for (key, raw) in public_key.datas.as_ref().iter().zip(public_raw.0.iter()) {
assert_eq!(key, raw);
}
// Test binary encoding/decoding
assert_eq!(
bincode::serialize(&public_key)?,
public_key.to_bytes_vector(),
);
// Test pubkey debug
assert_eq!(
"PublicKey { DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV }".to_owned(),
......@@ -516,6 +562,7 @@ mod tests {
offset: 42
}
);
Ok(())
}
#[test]
......
......@@ -31,7 +31,8 @@ pub(crate) struct X25519PublicKey(MontgomeryPoint);
impl From<&PublicKey> for X25519PublicKey {
fn from(ed25519_public_key: &PublicKey) -> Self {
let compressed_edwards_y = CompressedEdwardsY::from_slice(ed25519_public_key.as_ref());
let compressed_edwards_y =
CompressedEdwardsY::from_slice(ed25519_public_key.datas.as_ref());
let edwards_point = compressed_edwards_y
.decompress()
.expect("dev error: invalid ed25519 public key");
......
......@@ -255,7 +255,7 @@ where
// and derive symmetric_key and nonce from shared secret
let (symmetric_key, nonce) = generate_symmetric_key_and_nonce(
algorithm,
ephemeral_keypair.public_key().as_ref(),
ephemeral_keypair.public_key().datas.as_ref(),
ephemeral_keypair.seed(),
&receiver_public_key,
)?;
......@@ -287,7 +287,7 @@ where
.try_extend_from_slice(tag.as_ref())
.expect("too long tag");
clear_footer
.try_extend_from_slice(ephemeral_keypair.public_key().as_ref())
.try_extend_from_slice(ephemeral_keypair.public_key().datas.as_ref())
.expect("too long ephemeral_public_key");
message.extend(clear_footer.into_iter());
......
......@@ -75,7 +75,7 @@ pub(crate) fn write_anthentication_datas(
) -> impl AsRef<[u8]> + IntoIterator<Item = u8> {
let mut authent_datas = arrayvec::ArrayVec::<[u8; 128]>::new();
authent_datas
.try_extend_from_slice(sender_public_key.as_ref())
.try_extend_from_slice(sender_public_key.datas.as_ref())
.expect("too long sender public key");
authent_datas
.try_extend_from_slice(authent_proof.as_ref())
......
......@@ -24,11 +24,14 @@ use serde::{Deserialize, Serialize};
use std::fmt::{self, Debug, Display, Formatter};
use zeroize::Zeroize;
/// Seed32 size in bytes
pub const SEED_32_SIZE_IN_BYTES: usize = 32;
/// Store a 32 bytes seed used to generate keys.
#[cfg_attr(feature = "ser", derive(Deserialize, Serialize))]
#[derive(Clone, Default, PartialEq, Eq, Hash, Zeroize)]
#[zeroize(drop)]
pub struct Seed32([u8; 32]);
pub struct Seed32([u8; SEED_32_SIZE_IN_BYTES]);
impl AsRef<[u8]> for Seed32 {
fn as_ref(&self) -> &[u8] {
......@@ -57,7 +60,7 @@ impl Display for Seed32 {
impl Seed32 {
#[inline]
/// Create new seed
pub fn new(seed_bytes: [u8; 32]) -> Seed32 {
pub fn new(seed_bytes: [u8; SEED_32_SIZE_IN_BYTES]) -> Seed32 {
Seed32(seed_bytes)
}
#[inline]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment