From fd398b00e0f3e8ead6a7bc0b84645707af6dd1d7 Mon Sep 17 00:00:00 2001 From: Emma Turner Date: Wed, 13 Dec 2023 15:14:08 +0000 Subject: [PATCH 1/2] crypto: fix SeedEd25519 base58 prefix bytes --- CHANGELOG.md | 2 +- crypto/src/hash.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45f8695a1e..d3b8e6d9fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ parameterized by the lifetime of the input byte slice. ### Fixed -- Nothing. +- Fix prefix used in `SeedEd25519` encoding. ### Security diff --git a/crypto/src/hash.rs b/crypto/src/hash.rs index 802174f379..15216cf543 100644 --- a/crypto/src/hash.rs +++ b/crypto/src/hash.rs @@ -36,7 +36,7 @@ mod prefix_bytes { pub const PUBLIC_KEY_SECP256K1: [u8; 4] = [3, 254, 226, 86]; pub const PUBLIC_KEY_P256: [u8; 4] = [3, 178, 139, 127]; pub const PUBLIC_KEY_BLS: [u8; 4] = [6, 149, 135, 204]; - pub const SEED_ED25519: [u8; 4] = [43, 246, 78, 7]; + pub const SEED_ED25519: [u8; 4] = [13, 15, 58, 7]; pub const SECRET_KEY_ED25519: [u8; 4] = [43, 246, 78, 7]; pub const SECRET_KEY_BLS: [u8; 4] = [3, 150, 192, 40]; pub const ED22519_SIGNATURE_HASH: [u8; 5] = [9, 245, 205, 134, 18]; From 169f0ae08f68ff254faf4e8f4eb7ff9fb240d9a5 Mon Sep 17 00:00:00 2001 From: Emma Turner Date: Wed, 13 Dec 2023 15:16:46 +0000 Subject: [PATCH 2/2] crypto: enforce correct hash prefix during base58check decoding Previously, hashes could accidentally be parsed with an incorrect hash type, provided: - the lengths of the encoded were the same - the lengths of the base58 prefixes were the same This would manifest, for example, by the following succeeding: `ContractTz1Hash::from_base58check("tz4FENGt5zkiGaHPm1ya4MgLomgkL1k7Dy7q")` This will now return `Err(FromBase58CheckError::IncorrectBase58Prefix)` instead. --- CHANGELOG.md | 3 ++- crypto/src/base58.rs | 3 +++ crypto/src/hash.rs | 29 ++++++++++++++++++++++++++--- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3b8e6d9fa..7c3a57c329 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added -- Nothing. +- Add `FromBase58CheckError::IncorrectBase58Prefix` variant. ### Changed @@ -25,6 +25,7 @@ parameterized by the lifetime of the input byte slice. ### Fixed - Fix prefix used in `SeedEd25519` encoding. +- Add explicit prefix check during base58check decoding. ### Security diff --git a/crypto/src/base58.rs b/crypto/src/base58.rs index 4cdcb762d5..84d6d76ca9 100644 --- a/crypto/src/base58.rs +++ b/crypto/src/base58.rs @@ -23,6 +23,9 @@ pub enum FromBase58CheckError { DataTooLong, #[error("mismatched data lenght: expected {expected}, actual {actual}")] MismatchedLength { expected: usize, actual: usize }, + /// Prefix does not match expected. + #[error("incorrect base58 prefix for hash type")] + IncorrectBase58Prefix, } /// Possible errors for ToBase58Check diff --git a/crypto/src/hash.rs b/crypto/src/hash.rs index 15216cf543..d738b562f3 100644 --- a/crypto/src/hash.rs +++ b/crypto/src/hash.rs @@ -482,7 +482,11 @@ impl HashType { return Ok(hash.to_vec()); } } + } else if !hash.starts_with(self.base58check_prefix()) { + println!("expected: {:?}, found: {hash:?}", self.base58check_prefix()); + return Err(FromBase58CheckError::IncorrectBase58Prefix); } + let expected_len = self.size() + self.base58check_prefix().len(); if expected_len != hash.len() { return Err(FromBase58CheckError::MismatchedLength { @@ -490,6 +494,7 @@ impl HashType { actual: hash.len(), }); } + // prefix is not present in a binary representation hash.drain(0..self.base58check_prefix().len()); Ok(hash) @@ -1056,9 +1061,10 @@ mod tests { } #[test] - fn test_b58_to_hash_mismatched_lenght() -> Result<(), anyhow::Error> { - let b58 = HashType::ChainId.hash_to_b58check(&[0, 0, 0, 0])?; - let result = HashType::BlockHash.b58check_to_hash(&b58); + fn test_b58_to_hash_mismatched_length() -> Result<(), anyhow::Error> { + let b58 = "BwKZdq9yAc1ucmPPoUeRxRQRUeks64eswrLoSa2eZipYwB3UftmTd1pmg4uyiwU6Ge3guh7CoZdpL4YPm35Ajvu5gQu5mYwEgwA8UmjZNaXV7ecc7qkcoe6xro"; + let result = HashType::BlockHash.b58check_to_hash(b58); + println!("{result:?}"); assert!(matches!( result, Err(FromBase58CheckError::MismatchedLength { @@ -1268,6 +1274,23 @@ mod tests { ); } + #[test] + fn from_base58check_incorrect_prefix() { + let h = ContractTz1Hash::from_base58_check("tz4FENGt5zkiGaHPm1ya4MgLomgkL1k7Dy7q"); + + assert!(matches!( + h, + Err(FromBase58CheckError::IncorrectBase58Prefix) + )); + + let h = ContractTz4Hash::from_base58_check("tz1ei4WtWEMEJekSv8qDnu9PExG6Q8HgRGr3"); + + assert!(matches!( + h, + Err(FromBase58CheckError::IncorrectBase58Prefix) + )); + } + #[test] fn block_payload_hash() { let operation_0 = "oom9d3PpjjaMzgg9mZ1pDrF8kjdyzDb41Bd2XE6Y3kRtFHXLku3";