fix(crypto): Bip39.TryParse must not throw on unrecognisable text
Wordlist.AutoDetect lands on NBitcoin's internal "Unknown" language for text resembling no wordlist and throws NotSupportedException instead of failing gracefully — found by fuzzing the restore-mnemonic input. TryParse now treats that (and the same failure mode from the Mnemonic constructor) as "not a valid mnemonic", consistent with every other rejection path.
This commit is contained in:
@@ -58,12 +58,26 @@ public static class Bip39
|
|||||||
// ideographic spaces — the text must not be altered further (§4.1).
|
// ideographic spaces — the text must not be altered further (§4.1).
|
||||||
text = text.Trim();
|
text = text.Trim();
|
||||||
|
|
||||||
IEnumerable<Wordlist> candidates = language is not null
|
Wordlist wordlist;
|
||||||
? [ToWordlist(language.Value)]
|
if (language is not null)
|
||||||
: [Wordlist.AutoDetect(text)];
|
|
||||||
|
|
||||||
foreach (var wordlist in candidates)
|
|
||||||
{
|
{
|
||||||
|
wordlist = ToWordlist(language.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
wordlist = Wordlist.AutoDetect(text);
|
||||||
|
}
|
||||||
|
catch (NotSupportedException)
|
||||||
|
{
|
||||||
|
// AutoDetect lands on NBitcoin's internal "Unknown" language for
|
||||||
|
// text resembling no wordlist and throws instead of returning a
|
||||||
|
// default (found by fuzzing) — not a valid mnemonic, plain and simple.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var parsed = new Mnemonic(text, wordlist);
|
var parsed = new Mnemonic(text, wordlist);
|
||||||
@@ -76,8 +90,11 @@ public static class Bip39
|
|||||||
}
|
}
|
||||||
catch (FormatException)
|
catch (FormatException)
|
||||||
{
|
{
|
||||||
// Words outside the wordlist or invalid count — try the next candidate.
|
// Words outside the wordlist or invalid count.
|
||||||
}
|
}
|
||||||
|
catch (NotSupportedException)
|
||||||
|
{
|
||||||
|
// Defensive: same NBitcoin failure mode surfacing from the constructor.
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -126,4 +126,15 @@ public class Bip39Tests
|
|||||||
Assert.Throws<ArgumentOutOfRangeException>(
|
Assert.Throws<ArgumentOutOfRangeException>(
|
||||||
() => Bip39.Generate(MnemonicLength.Twelve, (MnemonicLanguage)99));
|
() => Bip39.Generate(MnemonicLength.Twelve, (MnemonicLanguage)99));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Testo_che_non_somiglia_a_nessuna_wordlist_viene_rifiutato_senza_eccezioni()
|
||||||
|
{
|
||||||
|
// NBitcoin's Wordlist.AutoDetect throws NotSupportedException("Unknown")
|
||||||
|
// for text resembling no wordlist instead of failing gracefully (found by
|
||||||
|
// fuzzing): TryParse must swallow it and return false — this string reaches
|
||||||
|
// TryParse straight from the user's restore input.
|
||||||
|
Assert.False(Bip39.TryParse("ábÊco ábaco0ábaco ábÊ", out var mnemonic));
|
||||||
|
Assert.Null(mnemonic);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user