Merge pull request #2 from yancyribbens/add-entropy-bounds-check

Add entropy bounds check
This commit is contained in:
Steven Roose 2020-07-18 13:14:05 +02:00 committed by GitHub
commit 6179d293ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 29 additions and 5 deletions

View File

@ -54,8 +54,7 @@ pub enum Error {
BadWordCount(usize), BadWordCount(usize),
/// Mnemonic contains an unknown word. /// Mnemonic contains an unknown word.
UnknownWord(String), UnknownWord(String),
/// Entropy was not a multiple of 32 bits. /// Entropy was not a multiple of 32 bits or between 128-256n bits in length.
/// Parameter is the number of bits in the entropy.
BadEntropyBitCount(usize), BadEntropyBitCount(usize),
/// The mnemonic has an invalid checksum. /// The mnemonic has an invalid checksum.
InvalidChecksum, InvalidChecksum,
@ -72,7 +71,7 @@ impl fmt::Display for Error {
w, bitcoin_hashes::hex::ToHex::to_hex(w.as_bytes()), w, bitcoin_hashes::hex::ToHex::to_hex(w.as_bytes()),
), ),
Error::BadEntropyBitCount(c) => write!(f, Error::BadEntropyBitCount(c) => write!(f,
"entropy was not a multiple of 32 bits: {} bits", c, "entropy was not between 128-256 bits or not a multiple of 32 bits: {} bits", c,
), ),
Error::InvalidChecksum => write!(f, "the mnemonic has an invalid checksum"), Error::InvalidChecksum => write!(f, "the mnemonic has an invalid checksum"),
} }
@ -118,12 +117,16 @@ impl Mnemonic {
} }
/// Create a new [Mnemonic] in the specified language from the given entropy. /// Create a new [Mnemonic] in the specified language from the given entropy.
/// Entropy must be a multiple of 32 bits (4 bytes). /// Entropy must be a multiple of 32 bits (4 bytes) and 128-256 bits in length.
pub fn from_entropy_in(language: Language, entropy: &[u8]) -> Result<Mnemonic, Error> { pub fn from_entropy_in(language: Language, entropy: &[u8]) -> Result<Mnemonic, Error> {
if entropy.len() % 4 != 0 { if entropy.len() % 4 != 0 {
return Err(Error::BadEntropyBitCount(entropy.len() * 8)); return Err(Error::BadEntropyBitCount(entropy.len() * 8));
} }
if (entropy.len() * 8) < 128 || (entropy.len() * 8) > 256 {
return Err(Error::BadEntropyBitCount(entropy.len() * 8));
}
let check = sha256::Hash::hash(&entropy); let check = sha256::Hash::hash(&entropy);
let mut bits = vec![false; entropy.len() * 8 + entropy.len() / 4]; let mut bits = vec![false; entropy.len() * 8 + entropy.len() / 4];
for i in 0..entropy.len() { for i in 0..entropy.len() {
@ -150,7 +153,7 @@ impl Mnemonic {
} }
/// Create a new English [Mnemonic] in from the given entropy. /// Create a new English [Mnemonic] in from the given entropy.
/// Entropy must be a multiple of 32 bits (4 bytes). /// Entropy must be a multiple of 32 bits (4 bytes) and 128-256 bits in length.
pub fn from_entropy(entropy: &[u8]) -> Result<Mnemonic, Error> { pub fn from_entropy(entropy: &[u8]) -> Result<Mnemonic, Error> {
Mnemonic::from_entropy_in(Language::English, entropy) Mnemonic::from_entropy_in(Language::English, entropy)
} }
@ -532,6 +535,27 @@ mod tests {
); );
} }
#[test]
fn test_invalid_entropy() {
//between 128 and 256 bits, but not divisible by 32
assert_eq!(
Mnemonic::from_entropy(&vec![b'x'; 17]),
Err(Error::BadEntropyBitCount(136))
);
//less than 128 bits
assert_eq!(
Mnemonic::from_entropy(&vec![b'x'; 4]),
Err(Error::BadEntropyBitCount(32))
);
//greater than 256 bits
assert_eq!(
Mnemonic::from_entropy(&vec![b'x'; 36]),
Err(Error::BadEntropyBitCount(288))
);
}
#[cfg(feature = "japanese")] #[cfg(feature = "japanese")]
#[test] #[test]
fn test_vectors_japanese() { fn test_vectors_japanese() {