diff --git a/Cargo.lock b/Cargo.lock index 874fb3d9e..b9896b19e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2516,7 +2516,7 @@ dependencies = [ [[package]] name = "grin_wallet" -version = "5.4.0-alpha.1" +version = "5.4.1" dependencies = [ "built", "clap", @@ -2548,7 +2548,7 @@ dependencies = [ [[package]] name = "grin_wallet_api" -version = "5.4.0-alpha.1" +version = "5.4.1" dependencies = [ "base64 0.12.3", "chrono", @@ -2573,7 +2573,7 @@ dependencies = [ [[package]] name = "grin_wallet_config" -version = "5.4.0-alpha.1" +version = "5.4.1" dependencies = [ "dirs 2.0.2", "grin_core", @@ -2588,7 +2588,7 @@ dependencies = [ [[package]] name = "grin_wallet_controller" -version = "5.4.0-alpha.1" +version = "5.4.1" dependencies = [ "chrono", "easy-jsonrpc-mw", @@ -2624,7 +2624,7 @@ dependencies = [ [[package]] name = "grin_wallet_impls" -version = "5.4.0-alpha.1" +version = "5.4.1" dependencies = [ "arti-client", "base64 0.12.3", @@ -2675,7 +2675,7 @@ dependencies = [ [[package]] name = "grin_wallet_libwallet" -version = "5.4.0-alpha.1" +version = "5.4.1" dependencies = [ "age", "base64 0.9.3", @@ -2713,7 +2713,7 @@ dependencies = [ [[package]] name = "grin_wallet_util" -version = "5.4.0-alpha.1" +version = "5.4.1" dependencies = [ "data-encoding", "ed25519-dalek 1.0.1", diff --git a/Cargo.toml b/Cargo.toml index 26811f657..27d93a6c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_wallet" -version = "5.4.0-alpha.1" +version = "5.4.1" authors = ["Grin Developers "] description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format." license = "Apache-2.0" @@ -30,12 +30,12 @@ semver = "0.10" rustyline = "6" lazy_static = "1" -grin_wallet_api = { path = "./api", version = "5.4.0-alpha.1" } -grin_wallet_impls = { path = "./impls", version = "5.4.0-alpha.1" } -grin_wallet_libwallet = { path = "./libwallet", version = "5.4.0-alpha.1" } -grin_wallet_controller = { path = "./controller", version = "5.4.0-alpha.1" } -grin_wallet_config = { path = "./config", version = "5.4.0-alpha.1" } -grin_wallet_util = { path = "./util", version = "5.4.0-alpha.1" } +grin_wallet_api = { path = "./api", version = "5.4.1" } +grin_wallet_impls = { path = "./impls", version = "5.4.1" } +grin_wallet_libwallet = { path = "./libwallet", version = "5.4.1" } +grin_wallet_controller = { path = "./controller", version = "5.4.1" } +grin_wallet_config = { path = "./config", version = "5.4.1" } +grin_wallet_util = { path = "./util", version = "5.4.1" } ##### Grin Imports diff --git a/api/Cargo.toml b/api/Cargo.toml index 0c9ff4083..3afb4386c 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_wallet_api" -version = "5.4.0-alpha.1" +version = "5.4.1" authors = ["Grin Developers "] description = "Grin Wallet API" license = "Apache-2.0" @@ -22,10 +22,10 @@ ring = "0.16" base64 = "0.12" ed25519-dalek = "1.0.0-pre.4" -grin_wallet_libwallet = { path = "../libwallet", version = "5.4.0-alpha.1" } -grin_wallet_config = { path = "../config", version = "5.4.0-alpha.1" } -grin_wallet_impls = { path = "../impls", version = "5.4.0-alpha.1" } -grin_wallet_util = { path = "../util", version = "5.4.0-alpha.1" } +grin_wallet_libwallet = { path = "../libwallet", version = "5.4.1" } +grin_wallet_config = { path = "../config", version = "5.4.1" } +grin_wallet_impls = { path = "../impls", version = "5.4.1" } +grin_wallet_util = { path = "../util", version = "5.4.1" } ##### Grin Imports diff --git a/config/Cargo.toml b/config/Cargo.toml index 20f3ba374..c7146f703 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_wallet_config" -version = "5.4.0-alpha.1" +version = "5.4.1" authors = ["Grin Developers "] description = "Configuration for grin wallet , a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format." license = "Apache-2.0" @@ -16,7 +16,7 @@ serde_derive = "1" toml = "0.5" dirs = "2.0" -grin_wallet_util = { path = "../util", version = "5.4.0-alpha.1" } +grin_wallet_util = { path = "../util", version = "5.4.1" } ##### Grin Imports diff --git a/controller/Cargo.toml b/controller/Cargo.toml index 8fba5ccb5..715e68c38 100644 --- a/controller/Cargo.toml +++ b/controller/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_wallet_controller" -version = "5.4.0-alpha.1" +version = "5.4.1" authors = ["Grin Developers "] description = "Controllers for grin wallet instantiation" license = "Apache-2.0" @@ -30,11 +30,11 @@ lazy_static = "1" thiserror = "1" qr_code = "1.1.0" -grin_wallet_util = { path = "../util", version = "5.4.0-alpha.1" } -grin_wallet_api = { path = "../api", version = "5.4.0-alpha.1" } -grin_wallet_impls = { path = "../impls", version = "5.4.0-alpha.1" } -grin_wallet_libwallet = { path = "../libwallet", version = "5.4.0-alpha.1" } -grin_wallet_config = { path = "../config", version = "5.4.0-alpha.1" } +grin_wallet_util = { path = "../util", version = "5.4.1" } +grin_wallet_api = { path = "../api", version = "5.4.1" } +grin_wallet_impls = { path = "../impls", version = "5.4.1" } +grin_wallet_libwallet = { path = "../libwallet", version = "5.4.1" } +grin_wallet_config = { path = "../config", version = "5.4.1" } ##### Grin Imports diff --git a/impls/Cargo.toml b/impls/Cargo.toml index 469482d2c..163bb43fd 100644 --- a/impls/Cargo.toml +++ b/impls/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_wallet_impls" -version = "5.4.0-alpha.1" +version = "5.4.1" authors = ["Grin Developers "] description = "Concrete types derived from libwallet traits" license = "Apache-2.0" @@ -49,9 +49,9 @@ hyper-util = { version = "0.1.20", features = ["tokio"] } http-body-util = "0.1.3" bytes = "1.11.1" -grin_wallet_util = { path = "../util", version = "5.4.0-alpha.1" } -grin_wallet_config = { path = "../config", version = "5.4.0-alpha.1" } -grin_wallet_libwallet = { path = "../libwallet", version = "5.4.0-alpha.1" } +grin_wallet_util = { path = "../util", version = "5.4.1" } +grin_wallet_config = { path = "../config", version = "5.4.1" } +grin_wallet_libwallet = { path = "../libwallet", version = "5.4.1" } ##### Grin Imports diff --git a/libwallet/Cargo.toml b/libwallet/Cargo.toml index bb9fc9c6a..4d9bd64e4 100644 --- a/libwallet/Cargo.toml +++ b/libwallet/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_wallet_libwallet" -version = "5.4.0-alpha.1" +version = "5.4.1" authors = ["Grin Developers "] description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format." license = "Apache-2.0" @@ -40,8 +40,8 @@ num-bigint = "0.2" chacha20 = "0.8.1" hmac = { version = "0.12.0", features = ["std"]} -grin_wallet_util = { path = "../util", version = "5.4.0-alpha.1" } -grin_wallet_config = { path = "../config", version = "5.4.0-alpha.1" } +grin_wallet_util = { path = "../util", version = "5.4.1" } +grin_wallet_config = { path = "../config", version = "5.4.1" } ##### Grin Imports diff --git a/libwallet/src/slate_versions/ser.rs b/libwallet/src/slate_versions/ser.rs index 58f866a08..8e3510c76 100644 --- a/libwallet/src/slate_versions/ser.rs +++ b/libwallet/src/slate_versions/ser.rs @@ -386,8 +386,8 @@ pub mod dalek_sig_serde { String::deserialize(deserializer) .and_then(|string| from_hex(&string).map_err(|err| Error::custom(err.to_string()))) .and_then(|bytes: Vec| { - let mut b = [0u8; 64]; - b.copy_from_slice(&bytes[0..64]); + let b = <[u8; 64]>::try_from(bytes.as_slice()) + .map_err(|_| Error::custom("invalid signature length"))?; DalekSignature::try_from(b).map_err(|err| Error::custom(err.to_string())) }) } @@ -422,8 +422,8 @@ pub mod option_dalek_sig_serde { Some(string) => from_hex(&string) .map_err(|err| Error::custom(err.to_string())) .and_then(|bytes: Vec| { - let mut b = [0u8; 64]; - b.copy_from_slice(&bytes[0..64]); + let b = <[u8; 64]>::try_from(bytes.as_slice()) + .map_err(|_| Error::custom("invalid signature length"))?; DalekSignature::try_from(b) .map(Some) .map_err(|err| Error::custom(err.to_string())) @@ -461,8 +461,8 @@ pub mod option_dalek_sig_base64 { Some(string) => base64::decode(&string) .map_err(|err| Error::custom(err.to_string())) .and_then(|bytes: Vec| { - let mut b = [0u8; 64]; - b.copy_from_slice(&bytes[0..64]); + let b = <[u8; 64]>::try_from(bytes.as_slice()) + .map_err(|_| Error::custom("invalid signature length"))?; DalekSignature::try_from(b) .map(Some) .map_err(|err| Error::custom(err.to_string())) diff --git a/libwallet/src/slate_versions/v4_bin.rs b/libwallet/src/slate_versions/v4_bin.rs index 68f5190b2..455af3f50 100644 --- a/libwallet/src/slate_versions/v4_bin.rs +++ b/libwallet/src/slate_versions/v4_bin.rs @@ -345,11 +345,16 @@ impl<'a> Writeable for ProofWrapRef<'a> { impl Readable for ProofWrap { fn read(reader: &mut R) -> Result { - let saddr = DalekPublicKey::from_bytes(&reader.read_fixed_bytes(32)?).unwrap(); - let raddr = DalekPublicKey::from_bytes(&reader.read_fixed_bytes(32)?).unwrap(); + let saddr = DalekPublicKey::from_bytes(&reader.read_fixed_bytes(32)?) + .map_err(|_| grin_ser::Error::CorruptedData)?; + let raddr = DalekPublicKey::from_bytes(&reader.read_fixed_bytes(32)?) + .map_err(|_| grin_ser::Error::CorruptedData)?; let rsig = match reader.read_u8()? { 0 => None, - 1 | _ => Some(DalekSignature::try_from(&reader.read_fixed_bytes(64)?[..]).unwrap()), + 1 | _ => Some( + DalekSignature::try_from(&reader.read_fixed_bytes(64)?[..]) + .map_err(|_| grin_ser::Error::CorruptedData)?, + ), }; Ok(ProofWrap(PaymentInfoV4 { saddr, raddr, rsig })) } diff --git a/libwallet/src/slatepack/armor.rs b/libwallet/src/slatepack/armor.rs index eacdf32f6..c8be2999e 100644 --- a/libwallet/src/slatepack/armor.rs +++ b/libwallet/src/slatepack/armor.rs @@ -74,7 +74,10 @@ impl SlatepackArmor { // Get the length of the header let header_len = header_bytes.len() + 1; // Skip the length of the header to read for the payload until the next period - let payload_bytes = armor_bytes[header_len as usize..] + let payload_source = armor_bytes + .get(header_len..) + .ok_or_else(|| Error::InvalidSlatepackData("Bad armor header".to_string()))?; + let payload_bytes = payload_source .iter() .take_while(|byte| **byte != b'.') .cloned() @@ -82,8 +85,14 @@ impl SlatepackArmor { // Get length of the payload to check the footer framing let payload_len = payload_bytes.len(); // Get footer bytes and verify them - let consumed_bytes = header_len + payload_len + 1; - let footer_bytes = armor_bytes[consumed_bytes as usize..] + let consumed_bytes = header_len + .checked_add(payload_len) + .and_then(|v| v.checked_add(1)) + .ok_or_else(|| Error::InvalidSlatepackData("Bad armor footer".to_string()))?; + let footer_source = armor_bytes + .get(consumed_bytes..) + .ok_or_else(|| Error::InvalidSlatepackData("Bad armor footer".to_string()))?; + let footer_bytes = footer_source .iter() .take_while(|byte| **byte != b'.') .cloned() @@ -99,8 +108,10 @@ impl SlatepackArmor { let base_decode = bs58::decode(&clean_payload) .into_vec() .map_err(|_| Error::SlatepackDeser("Bad bytes".into()))?; - let error_code = &base_decode[0..4]; - let slatepack_bytes = &base_decode[4..]; + if base_decode.len() < 4 { + return Err(Error::SlatepackDeser("Payload too short".into())); + } + let (error_code, slatepack_bytes) = base_decode.split_at(4); // Make sure the error check code is valid for the slate data error_check(error_code, slatepack_bytes)?; // Return slate as binary or string diff --git a/libwallet/src/slatepack/types.rs b/libwallet/src/slatepack/types.rs index fe08c933c..fc12f4985 100644 --- a/libwallet/src/slatepack/types.rs +++ b/libwallet/src/slatepack/types.rs @@ -208,10 +208,23 @@ impl Slatepack { reader.read_to_end(&mut decrypted)?; // Parse encrypted metadata from payload, first 4 bytes of decrypted payload // will be encrypted metadata length + if decrypted.len() < 4 { + return Err(Error::SlatepackDeser( + "Encrypted payload missing metadata length".into(), + )); + } let mut len_bytes = [0u8; 4]; len_bytes.copy_from_slice(&decrypted[0..4]); let meta_len = Cursor::new(len_bytes).read_u32::()?; - self.payload = decrypted.split_off(meta_len as usize + 4); + let payload_start = (meta_len as usize) + .checked_add(4) + .ok_or_else(|| Error::SlatepackDeser("Encrypted metadata length overflow".into()))?; + if payload_start > decrypted.len() { + return Err(Error::SlatepackDeser( + "Encrypted metadata length exceeds payload".into(), + )); + } + self.payload = decrypted.split_off(payload_start); let meta = byte_ser::from_bytes::(&decrypted) .map_err(|_| Error::SlatepackSer)? .0; @@ -848,3 +861,53 @@ fn slatepack_encrypted_meta_future() -> Result<(), Error> { Ok(()) } + +#[cfg(test)] +fn slatepack_test_decryption_key() -> (edSecretKey, SlatepackAddress) { + use ed25519_dalek::PublicKey as edDalekPublicKey; + use rand::{thread_rng, Rng}; + + let sec_key_bytes: [u8; 32] = thread_rng().gen(); + let ed_sec_key = edSecretKey::from_bytes(&sec_key_bytes).unwrap(); + let ed_pub_key = edDalekPublicKey::from(&ed_sec_key); + let addr = SlatepackAddress::new(&ed_pub_key); + + (ed_sec_key, addr) +} + +#[cfg(test)] +fn encrypt_plaintext_to_slatepack_recipient( + recipient: &SlatepackAddress, + plaintext: &[u8], +) -> Result, Error> { + let recp_key: age::x25519::Recipient = recipient.to_age_pubkey_str()?.parse()?; + let keys = vec![Box::new(recp_key) as Box]; + let encryptor = age::Encryptor::with_recipients(keys); + let mut encrypted = vec![]; + let mut writer = encryptor.wrap_output(&mut encrypted)?; + writer.write_all(plaintext)?; + writer.finish()?; + Ok(encrypted) +} + +#[test] +fn slatepack_decrypt_rejects_malformed_plaintexts() -> Result<(), Error> { + use crate::grin_core::global; + + global::set_local_chain_type(global::ChainTypes::AutomatedTesting); + let (ed_sec_key, addr) = slatepack_test_decryption_key(); + + for plaintext in vec![vec![], vec![0], vec![0, 0, 0], vec![0xff; 4]] { + let mut slatepack = Slatepack { + mode: 1, + payload: encrypt_plaintext_to_slatepack_recipient(&addr, &plaintext)?, + ..Slatepack::default() + }; + assert!(matches!( + slatepack.try_decrypt_payload(Some(&ed_sec_key)), + Err(Error::SlatepackDeser(_)) + )); + } + + Ok(()) +} diff --git a/util/Cargo.toml b/util/Cargo.toml index d4f7487a4..36802e301 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "grin_wallet_util" -version = "5.4.0-alpha.1" +version = "5.4.1" authors = ["Grin Developers "] description = "Util, for generic utilities and to re-export grin crates" license = "Apache-2.0"