public async Task <bool> FindMissing(string mnemonic, char missingChar, MnemonicTypes mnType, WordLists wl) { InitReport(); if (!TrySetWordList(wl)) { return(false); } if (!IsMissingCharValid(missingChar)) { return(Fail("Missing character is not accepted.")); } if (!TrySplitMnemonic(mnemonic, missingChar, out words)) { return(false); } Stopwatch watch = Stopwatch.StartNew(); bool success = await Task.Run(() => { return(words.Length switch { 24 => Loop24(), 21 => Loop21(), 18 => Loop18(), 15 => Loop15(), _ => Loop12(), }); });
private bool TrySetEntropy(string mnemonic, MnemonicTypes mnType) { if (string.IsNullOrWhiteSpace(mnemonic)) { return(report.Fail("Mnemonic can not be null or empty.")); } return(report.Fail("Not yet implemented.")); }
public async void Find(string mnemonic, MnemonicTypes mnType, BIP0039.WordLists wl, string extra, InputType extraType, string path, int passLength, byte[] allValues) { report.Init(); if (mnType != MnemonicTypes.BIP39 && mnType != MnemonicTypes.Electrum) { report.Fail("Mnemonic type is not defined."); } if (!MnemonicSevice.TrySetWordList(wl, out string[] allWords, out int maxWordLen))
private bool TrySetSalt(int len, MnemonicTypes mnType, out byte[] result) { if (len < 1) { result = null; report.Fail("Password length must be at least 1."); return(false); } // Each SHA512 block is 128 bytes, last 16 bytes are data length, PBKDF2 adds 4 byte block int, // BIP39 and Electrum both add a string that is 8 bytes // Anything smaller than that is a single block. We reject big passphrases (>=100 byte) to make things simple // and it doesn't matter because recovering such big passphrases is already impossible! if (len >= Sha512Fo.BlockByteSize - 16 - Pbkdf2BlockNumberLength - MnStartStringLen) { result = null; report.Fail($"Password length={len} are not supported. Start a new issue on GitHub if you need this."); return(false); } result = new byte[Sha512Fo.BlockByteSize]; // Pad: result[len + MnStartStringLen + Pbkdf2BlockNumberLength] = 0b1000_0000; // PBKDF2 block number = 1 result[len + MnStartStringLen + 3] = 1; // Salt is used in HMACSHA512 where a block (inner pad) is already compressed so total data length is +128 int totalLen = len + MnStartStringLen + Pbkdf2BlockNumberLength + 128; // See SHA512 to understand why this is correct: result[127] = (byte)(totalLen << 3); result[126] = (byte)(totalLen >> 5); result[125] = (byte)(totalLen >> 13); result[124] = (byte)(totalLen >> 21); result[123] = (byte)(totalLen >> 29); byte[] start = mnType == MnemonicTypes.BIP39 ? Encoding.UTF8.GetBytes("mnemonic") : Encoding.UTF8.GetBytes("electrum"); Debug.Assert(start.Length == MnStartStringLen); Buffer.BlockCopy(start, 0, result, 0, start.Length); return(true); }
public bool TryDecodeMnemonic(string mnemonic, MnemonicTypes mnType, string[] allWords, out byte[] bytes) { bytes = null; if (string.IsNullOrWhiteSpace(mnemonic)) { return(report.Fail("Mnemonic can not be null or empty.")); } else { string[] words = mnemonic.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (!MnemonicSevice.allowedWordLengths.Contains(words.Length)) { return(report.Fail("Invalid mnemonic length.")); } bool invalidWord = false; for (int i = 0; i < words.Length; i++) { if (!allWords.Contains(words[i])) { invalidWord = true; report.Fail($"Given mnemonic contains invalid word at index {i} ({words[i]})."); } } if (invalidWord) { return(false); } string temp = string.Join(' ', words); string normalized = mnType == MnemonicTypes.Electrum ? ElectrumMnemonic.Normalize(temp) : temp; bytes = Encoding.UTF8.GetBytes(normalized); return(true); } }