public static void BIP38PassphraseCode() { // BIP is in reality two ideas in one document. // The second part of the BIP lets you delegate Key and Address creation to an untrusted peer. // --- // You generate a PassphraseCode to the key generator. // With this PassphraseCode, they will be able to generate encrypted keys on your behalf. // They don't have to know your password or any private key. // The PassphraseCode can be given to your key generator in WIF format. // In NBitcoin, all types prefixed by "Bitcoin" are Base58 (WIF) data. var passphraseCode = new BitcoinPassphraseCode("my secret", Network.Main, null); EncryptedKeyResult encryptedKeyResult = passphraseCode.GenerateEncryptedSecret(); var generatedAddress = encryptedKeyResult.GeneratedAddress; var encryptedKey = encryptedKeyResult.EncryptedKey; var confirmedCode = encryptedKeyResult.ConfirmationCode; // The ConfirmationCode lets the third party prove that the generated key and address correspond to your password. // Now, as the owner... // Check to make sure the generator didn't cheat. Console.WriteLine(confirmedCode.Check("my secret", generatedAddress)); var bitcoinPrivateKey = encryptedKey.GetSecret("my secret"); Console.WriteLine(bitcoinPrivateKey.GetAddress() == generatedAddress); Console.WriteLine(bitcoinPrivateKey); // BIP 32, or Hierarchical Deterministic Wallets (HD wallets) proposes a solution to prevented outdated backups. }
public static void Execute(BitcoinSecret privateKey) { // PRNG (Pseudo-Random-Number-Generator) // add entropy to the PRNG output that NBitcoin is using RandomUtils.AddEntropy("Hello"); RandomUtils.AddEntropy(new byte[] { 1, 2, 3 }); Key nsaProofKey = new Key(); // KDF (Key Derivation Function) byte[] derived = SCrypt.BitcoinComputeDerivedKey("Hello", new byte[] { 1, 2, 3 }); RandomUtils.AddEntropy(derived); string password = "******"; BitcoinEncryptedSecret encryptedBitcoinPrivateKey = privateKey.Encrypt(password); BitcoinSecret decryptedBitcoinPrivateKey = encryptedBitcoinPrivateKey.GetSecret(password); Console.WriteLine("-------------------Key Derivation Function------------------"); Console.WriteLine("BitcoinPrivateKey : " + privateKey); Console.WriteLine("BitcoinPrivateKey(encrypted) : " + encryptedBitcoinPrivateKey); Console.WriteLine("BitcoinPrivateKey(decrypted) : " + decryptedBitcoinPrivateKey); // BIP38 (Part 2) string mySecret = "Secret Phrase"; BitcoinPassphraseCode passphraseCode = new BitcoinPassphraseCode(mySecret, Network.Main, null); EncryptedKeyResult encryptedKeyResult = passphraseCode.GenerateEncryptedSecret(); var generatedAddress = encryptedKeyResult.GeneratedAddress; var encryptedKey = encryptedKeyResult.EncryptedKey; var confirmationCode = encryptedKeyResult.ConfirmationCode; var bitcoinPrivateKey = encryptedKey.GetSecret(mySecret); Console.WriteLine("---------------------BIP38 (Part 2)---------------------"); Console.WriteLine("check generatedAddress: " + confirmationCode.Check(mySecret, generatedAddress)); // True Console.WriteLine("check generatedAddress: " + (bitcoinPrivateKey.GetAddress() == generatedAddress)); // True Console.WriteLine("bitcoinPrivateKey: " + bitcoinPrivateKey); }
public static string createPassPharaseCOde(string password) { BitcoinPassphraseCode passphraseCode = new BitcoinPassphraseCode(password, MainActivity.net, null); EncryptedKeyResult encryptedKey1 = passphraseCode.GenerateEncryptedSecret(); BitcoinSecret privateKey = encryptedKey1.EncryptedKey.GetSecret(password); return(encryptedKey1.EncryptedKey.ToString()); }
static void GenerateKey(Network network, string passphrase) { var passphraseCode = new BitcoinPassphraseCode(passphrase, network, null); EncryptedKeyResult encryptedKeyResult = passphraseCode.GenerateEncryptedSecret(); Console.WriteLine("Addy: " + encryptedKeyResult.GeneratedAddress); }
public void KeyParseWorksOnBothTypeOfEncryptedKey() { var encryptedkey = new Key().GetEncryptedBitcoinSecret("abc", Network.Main); Key.Parse(encryptedkey.ToString(), "abc", Network.Main); var code = new BitcoinPassphraseCode("abc", Network.Main, null); var encryptedkey2 = code.GenerateEncryptedSecret().EncryptedKey; Key.Parse(encryptedkey2.ToString(), "abc", Network.Main); }
public void EncryptedSecretECmultiplyLotSequence() { var tests = new[] { new { Passphrase = "ΜΟΛΩΝ ΛΑΒΕ", PassphraseCode = "passphrased3z9rQJHSyBkNBwTRPkUGNVEVrUAcfAXDyRU1V28ie6hNFbqDwbFBvsTK7yWVK", Encrypted = "6PgGWtx25kUg8QWvwuJAgorN6k9FbE25rv5dMRwu5SKMnfpfVe5mar2ngH", Address = "1Lurmih3KruL4xDB5FmHof38yawNtP9oGf", Unencrypted = "5KMKKuUmAkiNbA3DazMQiLfDq47qs8MAEThm4yL8R2PhV1ov33D", ConfirmationCode = "cfrm38V8G4qq2ywYEFfWLD5Cc6msj9UwsG2Mj4Z6QdGJAFQpdatZLavkgRd1i4iBMdRngDqDs51", LotSequence = new LotSequence(806938, 1), Compressed = false } , new { Passphrase = "MOLON LABE", PassphraseCode = "passphraseaB8feaLQDENqCgr4gKZpmf4VoaT6qdjJNJiv7fsKvjqavcJxvuR1hy25aTu5sX", Encrypted = "6PgNBNNzDkKdhkT6uJntUXwwzQV8Rr2tZcbkDcuC9DZRsS6AtHts4Ypo1j", Address = "1Jscj8ALrYu2y9TD8NrpvDBugPedmbj4Yh", Unencrypted = "5JLdxTtcTHcfYcmJsNVy1v2PMDx432JPoYcBTVVRHpPaxUrdtf8", ConfirmationCode = "cfrm38V8aXBn7JWA1ESmFMUn6erxeBGZGAxJPY4e36S9QWkzZKtaVqLNMgnifETYw7BPwWC9aPD", LotSequence = new LotSequence(263183, 1), Compressed = false } }; foreach (var test in tests) { //Can generate unencrypted key with password and encrypted key var encryptedKey = new BitcoinEncryptedSecretEC(test.Encrypted, Network.Main); AssertSequenceEquals(test.LotSequence, encryptedKey.LotSequence); Key actualKey = encryptedKey.GetKey(test.Passphrase); Assert.Equal(test.Unencrypted, actualKey.GetBitcoinSecret(Network.Main).ToString()); Assert.Equal(test.Address, actualKey.PubKey.GetAddress(Network.Main).ToString()); Assert.Equal(test.Compressed, actualKey.IsCompressed); //Can generate same BitcoinPassphraseCode with by using same ownerentropy var passCode = new BitcoinPassphraseCode(test.PassphraseCode, Network.Main); AssertSequenceEquals(test.LotSequence, passCode.LotSequence); var actualPassCode = new BitcoinPassphraseCode(test.Passphrase, Network.Main, test.LotSequence, passCode.OwnerEntropy); Assert.Equal(passCode.ToString(), actualPassCode.ToString()); //Can verify confirmation var confirmation = new BitcoinConfirmationCode(test.ConfirmationCode, Network.Main); AssertSequenceEquals(confirmation.LotSequence, test.LotSequence); Assert.True(confirmation.Check(test.Passphrase, new BitcoinPubKeyAddress(test.Address, Network.Main))); //Can generate encrypted key from passcode BitcoinEncryptedSecretEC generatedEncryptedKey = passCode.GenerateEncryptedSecret(test.Compressed).EncryptedKey; AssertEx.CollectionEquals(passCode.OwnerEntropy, generatedEncryptedKey.OwnerEntropy); Assert.Equal(test.Compressed, generatedEncryptedKey.IsCompressed); } }
public void KeyParseWorksOnBothTypeOfEncryptedKey() { BitcoinEncryptedSecretNoEC encryptedkey = new Key().GetEncryptedBitcoinSecret("abc", Network.Main); Key.Parse(encryptedkey.ToString(), "abc", Network.Main); var code = new BitcoinPassphraseCode("abc", Network.Main, null); BitcoinEncryptedSecretEC encryptedkey2 = code.GenerateEncryptedSecret().EncryptedKey; Key.Parse(encryptedkey2.ToString(), "abc", Network.Main); }
private void buttonPassphrase_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(textBoxPassword.Text)) { MessageBox.Show(this, "A password is required.", "knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } using (new HourGlass()) { BitcoinPassphraseCode phrase = new BitcoinPassphraseCode(textBoxPassword.Text, Network.TestNet, null); textBoxPhrase.Text = phrase.ToWif(); } }
public static string createPassPharaseCOde(string password) { BitcoinPassphraseCode passphraseCode = new BitcoinPassphraseCode(password, MainActivity.net, null); EncryptedKeyResult encryptedKey1 = passphraseCode.GenerateEncryptedSecret(); Console.WriteLine(encryptedKey1.GeneratedAddress); Console.WriteLine(encryptedKey1.EncryptedKey); Console.WriteLine(encryptedKey1.ConfirmationCode); Console.WriteLine(encryptedKey1.ConfirmationCode.Check(password, encryptedKey1.GeneratedAddress)); BitcoinSecret privateKey = encryptedKey1.EncryptedKey.GetSecret(password); Console.WriteLine(privateKey.GetAddress() == encryptedKey1.GeneratedAddress); return(encryptedKey1.EncryptedKey.ToString()); }
private void buttonGenerate_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(textBoxPhrase.Text)) { MessageBox.Show(this, "You need to create or enter a [Passphrase] first.", "knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } using (new HourGlass()) { BitcoinPassphraseCode phrase = new BitcoinPassphraseCode(textBoxPhrase.Text, Network.TestNet); EncryptedKeyResult encryptedKey = phrase.GenerateEncryptedSecret(); textBoxEncKey.Text = encryptedKey.EncryptedKey.ToWif(); textBoxAddress.Text = encryptedKey.GeneratedAddress.ToWif(); textBoxConfirmation.Text = encryptedKey.ConfirmationCode.ToWif(); } }
public void EncryptedSecretECmultiplyNoLot() { var tests = new[] { new { Passphrase = "TestingOneTwoThree", PassphraseCode = "passphrasepxFy57B9v8HtUsszJYKReoNDV6VHjUSGt8EVJmux9n1J3Ltf1gRxyDGXqnf9qm", Encrypted = "6PfQu77ygVyJLZjfvMLyhLMQbYnu5uguoJJ4kMCLqWwPEdfpwANVS76gTX", Address = "1PE6TQi6HTVNz5DLwB1LcpMBALubfuN2z2", Unencrypted = "5K4caxezwjGCGfnoPTZ8tMcJBLB7Jvyjv4xxeacadhq8nLisLR2", Compressed = false }, new { Passphrase = "Satoshi", PassphraseCode = "passphraseoRDGAXTWzbp72eVbtUDdn1rwpgPUGjNZEc6CGBo8i5EC1FPW8wcnLdq4ThKzAS", Encrypted = "6PfLGnQs6VZnrNpmVKfjotbnQuaJK4KZoPFrAjx1JMJUa1Ft8gnf5WxfKd", Address = "1CqzrtZC6mXSAhoxtFwVjz8LtwLJjDYU3V", Unencrypted = "5KJ51SgxWaAYR13zd9ReMhJpwrcX47xTJh2D3fGPG9CM8vkv5sH", Compressed = false } }; foreach (var test in tests) { //Can generate unencrypted key with password and encrypted key var encryptedKey = new BitcoinEncryptedSecretEC(test.Encrypted, Network.Main); Assert.Null(encryptedKey.LotSequence); Key actualKey = encryptedKey.GetKey(test.Passphrase); Assert.Equal(test.Unencrypted, actualKey.GetBitcoinSecret(Network.Main).ToString()); Assert.Equal(test.Address, actualKey.PubKey.GetAddress(Network.Main).ToString()); Assert.Equal(test.Compressed, actualKey.IsCompressed); //Can generate same BitcoinPassphraseCode with by using same ownerentropy var passCode = new BitcoinPassphraseCode(test.PassphraseCode, Network.Main); Assert.Null(passCode.LotSequence); var actualPassCode = new BitcoinPassphraseCode(test.Passphrase, Network.Main, null, passCode.OwnerEntropy); Assert.Equal(passCode.ToString(), actualPassCode.ToString()); //Can generate encrypted key from passcode BitcoinEncryptedSecretEC generatedEncryptedKey = passCode.GenerateEncryptedSecret(test.Compressed).EncryptedKey; AssertEx.CollectionEquals(passCode.OwnerEntropy, generatedEncryptedKey.OwnerEntropy); Assert.Equal(test.Compressed, generatedEncryptedKey.IsCompressed); } }
private void Code9() { BitcoinPassphraseCode passphraseCode = new BitcoinPassphraseCode("my secret", Network.Main, null); EncryptedKeyResult encryptedKey1 = passphraseCode.GenerateEncryptedSecret(); Console.WriteLine(encryptedKey1.GeneratedAddress); Console.WriteLine(encryptedKey1.EncryptedKey); Console.WriteLine(encryptedKey1.ConfirmationCode); var confirmationCode = encryptedKey1.ConfirmationCode; var generatedAddress = encryptedKey1.GeneratedAddress; var encryptedKey = encryptedKey1.EncryptedKey; Console.WriteLine(confirmationCode.Check("my secret", generatedAddress)); BitcoinSecret privateKey = encryptedKey.GetSecret("my secret"); Console.WriteLine(privateKey.GetAddress() == generatedAddress); Console.WriteLine(privateKey); }
void Start() { var passphraseCode = new BitcoinPassphraseCode("my secret", Network.Main, null); EncryptedKeyResult encryptedKeyResult = passphraseCode.GenerateEncryptedSecret(); var generatedAddress = encryptedKeyResult.GeneratedAddress; var encryptedKey = encryptedKeyResult.EncryptedKey; var confirmationCode = encryptedKeyResult.ConfirmationCode; UnityEngine.Debug.Log(generatedAddress); // 14KZsAVLwafhttaykXxCZt95HqadPXuz73 UnityEngine.Debug.Log(encryptedKey); // 6PnWtBokjVKMjuSQit1h1Ph6rLMSFz2n4u3bjPJH1JMcp1WHqVSfr5ebNS UnityEngine.Debug.Log(confirmationCode); // cfrm38VUcrdt2zf1dCgf4e8gPNJJxnhJSdxYg6STRAEs7QuAuLJmT5W7uNqj88hzh9bBnU9GFkN UnityEngine.Debug.Log(confirmationCode.Check("my secret", generatedAddress)); // True var bitcoinPrivateKey = encryptedKey.GetSecret("my secret"); UnityEngine.Debug.Log(bitcoinPrivateKey.GetAddress() == generatedAddress); // True UnityEngine.Debug.Log(bitcoinPrivateKey); // KzzHhrkr39a7upeqHzYNNeJuaf1SVDBpxdFDuMvFKbFhcBytDF1R }
public string CreateAccount(string password, string path) { BitcoinPassphraseCode passphrase = new BitcoinPassphraseCode(password, Network.Main, null); var generate = passphrase.GenerateEncryptedSecret(); var BTCprivateKey = generate.EncryptedKey; var BTCaddress = generate.GeneratedAddress; var fileName = BTCaddress + ".key"; // Save to File using (var newfile = File.CreateText(Path.Combine(path, fileName))) { Guid guid = Guid.NewGuid(); string json = "{" + "\"crypto\":{" + "\"cipher\":\"\"," + "\"ciphertext\":\"" + passphrase + "\"," + "\"cipherparams\":{" + "\"iv\":\"" + password + "\"" + "}," + "\"kdf\":\"\"," + "\"mac\":\"\"," + "\"kdfparams\":{" + "\"n\":\"\"," + "\"r\":\"\"," + "\"p\":\"\"," + "\"dklen\":\"\"," + "\"salt\":\"" + BTCprivateKey + "\"" + "}" + "}," + "\"id\":\"" + guid + "\"," + "\"address\":\"" + BTCaddress + "\"," + "\"version\":\"" + "}"; newfile.Write(json); newfile.Flush(); } return(fileName); }
public void EncryptedSecretECmultiplyNoLotSimple() { var compressedValues = new[] { false, true }; foreach (bool compressed in compressedValues) { var code = new BitcoinPassphraseCode("test", Network.Main, null); Assert.Null(code.LotSequence); EncryptedKeyResult result = code.GenerateEncryptedSecret(compressed); Assert.True(result.ConfirmationCode.Check("test", result.GeneratedAddress)); Assert.False(result.ConfirmationCode.Check("toto", result.GeneratedAddress)); Assert.False(result.ConfirmationCode.Check("test", new Key().PubKey.GetAddress(Network.Main))); Key decryptedKey = result.EncryptedKey.GetKey("test"); Assert.Equal(result.GeneratedAddress.ToString(), decryptedKey.PubKey.GetAddress(Network.Main).ToString()); Assert.Throws <SecurityException>(() => result.EncryptedKey.GetKey("wrong")); //Can regenerate same result with same seed EncryptedKeyResult result2 = code.GenerateEncryptedSecret(compressed, seedb: result.Seed); Key decryptedKey2 = result.EncryptedKey.GetKey("test"); AssertEx.CollectionEquals(decryptedKey2.ToBytes(), decryptedKey.ToBytes()); } }
private static void Main(string[] args) { // add entropy before creating key RandomUtils.AddEntropy("hello"); RandomUtils.AddEntropy(new byte[] { 1, 2, 3 }); // key created with added entropy var nsaProofKey = new Key(); // What NBitcoin does when you call AddEntropy(data) is: // additionalEntropy = SHA(SHA(data) ^ additionalEntropy) // Then when you generate a new number: // result = SHA(PRNG() ^ additionalEntropy) // Key Derivation Function is a way to have a stronger key, even if your entropy is low // KDF is a hash function that wastes computing resources on purpose. var derived = SCrypt.BitcoinComputeDerivedKey("hello", new byte[] { 1, 2, 3 }); RandomUtils.AddEntropy(derived); // even if attacker knows that your source of entropy contains 5 letters, // they will need to run Scrypt to check each possibility // standard for encrypting private key with a password using kdf is BIP38 var privateKey = new Key(); var bitcoinPrivateKey = privateKey.GetWif(Network.Main); Console.WriteLine(bitcoinPrivateKey); BitcoinEncryptedSecret encryptedBitcoinPrivateKey = bitcoinPrivateKey.Encrypt("password"); Console.WriteLine(encryptedBitcoinPrivateKey); var decryptedBitcoinPrivateKey = encryptedBitcoinPrivateKey.GetKey("password"); Console.WriteLine(decryptedBitcoinPrivateKey); Key keyFromIncorrectPassword = null; Exception error = null; try { keyFromIncorrectPassword = encryptedBitcoinPrivateKey.GetKey("lahsdlahsdlakhslkdash"); } catch (Exception e) { error = e; } var result = keyFromIncorrectPassword != null ? keyFromIncorrectPassword.ToString() : $"{error?.GetType().Name ?? "Error"}: icorrect password"; Console.WriteLine(result); // BIP 38 // how to delegate Key and Address creation to an untrusted peer // create pass phrase code BitcoinPassphraseCode passphraseCode = new BitcoinPassphraseCode("my secret", Network.Main, null); Console.WriteLine(passphraseCode); // then give passPhraseCode to 3rd party key generator // third party can generate encrypted keys on your behalf // without knowing your password and private key. EncryptedKeyResult encryptedKeyResult = passphraseCode.GenerateEncryptedSecret(); var generatedAddress = encryptedKeyResult.GeneratedAddress; var encryptedKey = encryptedKeyResult.EncryptedKey; // used by 3rd party to confirm generated key and address correspond to password var confirmationCode = encryptedKeyResult.ConfirmationCode; // check var isValid = confirmationCode.Check("my secret", generatedAddress); Console.WriteLine(isValid); var bitcoinPrivateKeyFromPassphraseCode = encryptedKey.GetSecret("my secret"); Console.WriteLine(bitcoinPrivateKeyFromPassphraseCode.GetAddress() == generatedAddress); Console.WriteLine(bitcoinPrivateKey); // BIP 32 // hierarchical deterministic wallets // prevent outdated backups var masterKey = new ExtKey(); Console.WriteLine($"Master Key: {masterKey.ToString(Network.Main)}"); for (uint i = 0; i < 5; i++) { ExtKey nextKey = masterKey.Derive(i); Console.WriteLine($"Key {i} : {nextKey.ToString(Network.Main)}"); } // go back from a Key to ExtKey by supplying the Key and the ChainCode to the ExtKey constructor. var extKey = new ExtKey(); byte[] chainCode = extKey.ChainCode; Key key = extKey.PrivateKey; var newExtKey = new ExtKey(key, chainCode); // the base58 type equivalent of ExtKey is BitcoinExtKey // "neuter" master key so 3rd party can generate public keys without knowing private key ExtPubKey masterPubKey = masterKey.Neuter(); for (uint i = 0; i < 5; i++) { ExtPubKey pubKey = masterPubKey.Derive(i); Console.WriteLine($"PubKey {i} : {pubKey.ToString(Network.Main)}"); } // get corresponding private key with master key masterKey = new ExtKey(); masterPubKey = masterKey.Neuter(); // 3rd party generates pubkey1 ExtPubKey pubKey1 = masterPubKey.Derive(1); // get privatekey of pubKey1 ExtKey key1 = masterKey.Derive(1); Console.WriteLine($"Generated address: {pubKey1.PubKey.GetAddress(Network.Main)}"); Console.WriteLine($"Expected address: {key1.PrivateKey.PubKey.GetAddress(Network.Main)}"); // deterministic keys // derive the 1st child of the 1st child ExtKey parent = new ExtKey(); // method 1: ExtKey child11 = parent.Derive(1).Derive(1); // method 2: child11 = parent.Derive(new KeyPath("1/1")); // why use HD wallets ? // easier control, easier to classify keys for multiple accounts // but child keys can recover parent key (non-hardened) ExtKey ceoExtKey = new ExtKey(); Console.WriteLine($"CEO: {ceoExtKey.ToString(Network.Main)}"); ExtKey accountingKey = ceoExtKey.Derive(0, hardened: false); ExtPubKey ceoPubKey = ceoExtKey.Neuter(); // recover ceo key with accounting private key and ceo public key ExtKey ceoKeyRecovered = accountingKey.GetParentExtKey(ceoPubKey); Console.WriteLine($"CEO recovered: {ceoKeyRecovered.ToString(Network.Main)}"); // create a hardened key var privateCeoExtKey = new ExtKey(); Console.WriteLine($"Private CEO: {privateCeoExtKey.ToString(Network.Main)}"); var assitantExtKey = privateCeoExtKey.Derive(1, hardened: true); ExtPubKey privateCeoPubKey = privateCeoExtKey.Neuter(); ExtKey privateCeoKeyRecovered = null; try { privateCeoKeyRecovered = assitantExtKey.GetParentExtKey(privateCeoPubKey); } catch (Exception e) { Console.WriteLine($"{e.Message}"); } // creating hardened keys via keypath var isNonHardened = new KeyPath("1/2/3").IsHardened; Console.WriteLine(isNonHardened); var isHardened = new KeyPath("1/2/3'").IsHardened; Console.WriteLine(isHardened); // imagine that the Accounting Department generates 1 parent key for each customer, and a child for each of the customer’s payments. // As the CEO, you want to spend the money on one of these addresses. var accountingCeoKey = new ExtKey(); string accounting = "1'"; // hardened with apostrophe int customerId = 5; int paymentId = 50; KeyPath path = new KeyPath($"{accounting}/{customerId}/{paymentId}"); // path: 1/5/50 ExtKey paymentKey = accountingCeoKey.Derive(path); Console.WriteLine(paymentKey); // mnemonic code for HD keys BIP 39 // used for easy to write keys Mnemonic mnemo = new Mnemonic(Wordlist.English, WordCount.Twelve); ExtKey hdRoot = mnemo.DeriveExtKey("my password"); Console.WriteLine(mnemo); // recover hdRoot with mnemonic and password mnemo = new Mnemonic(mnemo.ToString(), Wordlist.English); ExtKey recoverdHdRoot = mnemo.DeriveExtKey("my password"); Console.WriteLine(hdRoot.PrivateKey == recoverdHdRoot.PrivateKey); // dark wallet // Prevent outdated backups // Delegate key / address generation to an untrusted peer // bonus feature: only share one address (StealthAddress) var scanKey = new Key(); var spendKey = new Key(); var stealthAddress = new BitcoinStealthAddress( scanKey: scanKey.PubKey, pubKeys: new[] { spendKey.PubKey }, signatureCount: 1, bitfield: null, network: Network.Main ); // payer will take StealthAddress and generate temp key called Ephem Key, and generate a Stealth Pub Key // then they package the Ephem PubKey in Stealth Metadata obj embedded in OP_RETURN // they will also add the output to the generated bitcoin address (Stealth pub key) //The creation of the EphemKey is an implementation detail // it can be omitted as NBitcoin will generate one automatically: var ephemKey = new Key(); var transaction = new Transaction(); stealthAddress.SendTo(transaction, Money.Coins(1.0m), ephemKey); Console.WriteLine(transaction); // the Scanner knows the StealthAddress // and recovers the Stealth PubKey and Bitcoin Address with the Scan Key // scanner then checks if if one of the tx corresponds to the address // if true, Scanner notifies the Receiver about tx // the receiver can get the private key of the address with their spend key // note: a StealthAddress can have mulitple spend pubkeys 9multi sig) // limit: use of OP_RETURN makes embedding data in tx difficult // OP_RETURN limit is 40 bytes Console.ReadLine(); }
private void buttonOk_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(textBoxKey.Text)) { MessageBox.Show(this, "Enter a key.", "Knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } using (new HourGlass()) { Result = Util.InterpretKey(textBoxKey.Text); } if (Result == null) { MessageBox.Show(this, "Unrecognized or invalid key.", "Knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } else { using (new HourGlass()) { Type type = Result.GetType(); switch (type.ToString()) { case "NBitcoin.BitcoinEncryptedSecretEC": if (string.IsNullOrEmpty(textBoxPassword.Text)) { MessageBox.Show(this, "This is an encrypted BitcoinSecret, please provide the password.", "Knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } else { try { BitcoinEncryptedSecretEC encEC = Result as BitcoinEncryptedSecretEC; Result = encEC.GetKey(textBoxPassword.Text).GetBitcoinSecret(Network.TestNet); DialogResult = System.Windows.Forms.DialogResult.OK; } catch { MessageBox.Show(this, "The pasword you entered is incorrect.", "Knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Error); } } break; case "NBitcoin.BitcoinEncryptedSecretNoEC": if (string.IsNullOrEmpty(textBoxPassword.Text)) { MessageBox.Show(this, "This is an encrypted BitcoinSecret, please provide the password.", "Knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } else { try { BitcoinEncryptedSecretNoEC encEC = Result as BitcoinEncryptedSecretNoEC; Result = encEC.GetKey(textBoxPassword.Text).GetBitcoinSecret(Network.TestNet); DialogResult = System.Windows.Forms.DialogResult.OK; } catch { MessageBox.Show(this, "The pasword you entered is incorrect.", "Knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Error); } } break; case "NBitcoin.BitcoinPassphraseCode": if (string.IsNullOrEmpty(textBoxPassword.Text)) { MessageBox.Show(this, "This is a PassphraseCode, please provide the password.", "Knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } else { try { BitcoinPassphraseCode phrase = Result as BitcoinPassphraseCode; EncryptedKeyResult key = phrase.GenerateEncryptedSecret(); if (key.ConfirmationCode.Check(textBoxPassword.Text, key.GeneratedAddress)) { BitcoinSecret secret = key.EncryptedKey.GetSecret(textBoxPassword.Text); if (secret.GetAddress() == key.GeneratedAddress) { Result = secret; DialogResult = System.Windows.Forms.DialogResult.OK; } else { MessageBox.Show(this, "The Generated Addresses do not match.", "Knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Error); } } else { MessageBox.Show(this, "The Confirmation Code check failed.", "Knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Error); } } catch { MessageBox.Show(this, "The password you entered is incorrect.", "Knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Error); } } break; default: DialogResult = System.Windows.Forms.DialogResult.OK; break; } } } }
private static void KeyGenerationAndEncryption() { // 02.01. Key Generation RandomUtils.AddEntropy("hello"); RandomUtils.AddEntropy(new byte[] { 1, 2, 3 }); var nsaProofKey = new Key(); Console.WriteLine("Key with entropy " + nsaProofKey.GetBitcoinSecret(Network.TestNet)); var derived = SCrypt.BitcoinComputeDerivedKey("hello", new byte[] { 1, 2, 3 }); RandomUtils.AddEntropy(derived); var privateKey = new Key(); var privateKeyBitcoinSecret = privateKey.GetWif(Network.TestNet); Console.WriteLine(privateKeyBitcoinSecret); // L1tZPQt7HHj5V49YtYAMSbAmwN9zRjajgXQt9gGtXhNZbcwbZk2r BitcoinEncryptedSecret bitcoinEncryptedSecret = privateKeyBitcoinSecret.Encrypt("password"); Console.WriteLine(bitcoinEncryptedSecret); // 6PYKYQQgx947Be41aHGypBhK6TA5Xhi9TdPBkatV3fHbbKrdDoBoXFCyLK var decryptedBitcoinPrivateKey = bitcoinEncryptedSecret.GetSecret("password"); Console.WriteLine(decryptedBitcoinPrivateKey); // L1tZPQt7HHj5V49YtYAMSbAmwN9zRjajgXQt9gGtXhNZbcwbZk2r //02.02 BIP38 and HD (Hierarchical Deterministic) Wallet var passphraseCode = new BitcoinPassphraseCode("my secret", Network.TestNet, null); // we give this passphraseCode to 3rd party EncryptedKeyResult encryptedKeyResult = passphraseCode.GenerateEncryptedSecret(); var generatedAddress = encryptedKeyResult.GeneratedAddress; var encryptedKeySecretEc = encryptedKeyResult.EncryptedKey; var confirmationCode = encryptedKeyResult.ConfirmationCode; Console.WriteLine(confirmationCode.Check("my secret", generatedAddress)); // True var privateKeyBitcoinSecret1 = encryptedKeySecretEc.GetSecret("my secret"); Console.WriteLine(privateKeyBitcoinSecret1.GetAddress() == generatedAddress); // True Console.WriteLine(privateKeyBitcoinSecret1); // KzzHhrkr39a7upeqHzYNNeJuaf1SVDBpxdFDuMvFKbFhcBytDF1R ExtKey masterKey = new ExtKey(); Console.WriteLine("Master key : " + masterKey.ToString(Network.TestNet)); for (int i = 0; i < 5; i++) { ExtKey extKey1 = masterKey.Derive((uint)i); Console.WriteLine("Key " + i + " : " + extKey1.ToString(Network.TestNet)); } ExtKey extKey = new ExtKey(); byte[] chainCode = extKey.ChainCode; Key key = extKey.PrivateKey; ExtKey newExtKey = new ExtKey(key, chainCode); ExtPubKey masterPubKey = masterKey.Neuter(); for (int i = 0; i < 5; i++) { ExtPubKey pubkey = masterPubKey.Derive((uint)i); Console.WriteLine("PubKey " + i + " : " + pubkey.ToString(Network.TestNet)); } ExtKey key1 = masterKey.Derive(4); //Check it is legit var generatedAddr = masterPubKey.Derive(4).PubKey.GetAddress(Network.TestNet); var expectedAddr = key1.PrivateKey.PubKey.GetAddress(Network.TestNet); Console.WriteLine("Generated address : " + generatedAddr); Console.WriteLine("Expected address : " + expectedAddr); ExtKey parent = new ExtKey(); ExtKey child11 = parent.Derive(1).Derive(1); ExtKey sameChild11 = parent.Derive(new KeyPath("1/1")); Console.WriteLine("child11 : " + child11.PrivateKey.PubKey.GetAddress(Network.TestNet)); Console.WriteLine("child11.PrivateKey == sameChild11.PrivateKey : " + (child11.PrivateKey == sameChild11.PrivateKey)); ExtKey ceoKey = new ExtKey(); Console.WriteLine("CEO: " + ceoKey.ToString(Network.TestNet)); ExtKey notHardenedAccountingKey = ceoKey.Derive(0, hardened: false); ExtPubKey ceoPubkey = ceoKey.Neuter(); //Recover ceo key with accounting private key and ceo public key ExtKey ceoKeyRecovered = notHardenedAccountingKey.GetParentExtKey(ceoPubkey); Console.WriteLine("CEO recovered: " + ceoKeyRecovered.ToString(Network.TestNet)); ExtKey hardenedAccountingKey = ceoKey.Derive(0, hardened: true); // ExtKey ceoKeyRecovered2 = hardenedAccountingKey.GetParentExtKey(ceoPubkey); => //throws exception Mnemonic mnemo = new Mnemonic(Wordlist.English, WordCount.Twelve); // generate random 12 words list ExtKey hdRoot = mnemo.DeriveExtKey("my password"); mnemo = new Mnemonic("minute put grant neglect anxiety case globe win famous correct turn link", Wordlist.English); hdRoot = mnemo.DeriveExtKey("my password"); Console.WriteLine(mnemo); Console.WriteLine(hdRoot.ToString(Network.TestNet)); var scanKey = new Key(); var spendKey = new Key(); BitcoinStealthAddress stealthAddress = new BitcoinStealthAddress ( scanKey: scanKey.PubKey, pubKeys: new[] { spendKey.PubKey }, signatureCount: 1, bitfield: null, network: Network.TestNet); Transaction transaction = new Transaction(); stealthAddress.SendTo(transaction, Money.Coins(1.0m)); Console.WriteLine(transaction); // personal tests Mycelium mnemo = new Mnemonic("artist tiger always access sport major donkey coil scale carry laptop ticket", Wordlist.English); hdRoot = mnemo.DeriveExtKey();//leave the password null as sample Console.WriteLine(hdRoot.ToString(Network.Main)); var hardened2 = new KeyPath("44'/0'/0'/0/1"); ExtKey paymentKey2 = hdRoot.Derive(hardened2); Console.WriteLine(hardened2 + ": " + paymentKey2.ScriptPubKey.GetDestinationAddress(Network.Main)); Console.WriteLine(hardened2 + ": private " + paymentKey2.ToString(Network.Main)); var hardened1 = new KeyPath("44'/0'/0'/0/0"); ExtKey paymentKey1 = hdRoot.Derive(hardened1); Console.WriteLine(hardened1 + ": " + paymentKey1.ScriptPubKey.GetDestinationAddress(Network.Main)); Console.WriteLine(hardened1 + ": private " + paymentKey1.ToString(Network.Main)); }
public void EncryptedSecretECmultiplyNoLot() { var tests = new[] { new { Passphrase= "TestingOneTwoThree", PassphraseCode= "passphrasepxFy57B9v8HtUsszJYKReoNDV6VHjUSGt8EVJmux9n1J3Ltf1gRxyDGXqnf9qm", Encrypted = "6PfQu77ygVyJLZjfvMLyhLMQbYnu5uguoJJ4kMCLqWwPEdfpwANVS76gTX", Address = "1PE6TQi6HTVNz5DLwB1LcpMBALubfuN2z2", Unencrypted = "5K4caxezwjGCGfnoPTZ8tMcJBLB7Jvyjv4xxeacadhq8nLisLR2", Compressed = false }, new { Passphrase= "Satoshi", PassphraseCode= "passphraseoRDGAXTWzbp72eVbtUDdn1rwpgPUGjNZEc6CGBo8i5EC1FPW8wcnLdq4ThKzAS", Encrypted = "6PfLGnQs6VZnrNpmVKfjotbnQuaJK4KZoPFrAjx1JMJUa1Ft8gnf5WxfKd", Address = "1CqzrtZC6mXSAhoxtFwVjz8LtwLJjDYU3V", Unencrypted = "5KJ51SgxWaAYR13zd9ReMhJpwrcX47xTJh2D3fGPG9CM8vkv5sH", Compressed = false } }; foreach(var test in tests) { //Can generate unencrypted key with password and encrypted key var encryptedKey = new BitcoinEncryptedSecretEC(test.Encrypted, Network.Main); Assert.Null(encryptedKey.LotSequence); var actualKey = encryptedKey.GetKey(test.Passphrase); Assert.Equal(test.Unencrypted, actualKey.GetBitcoinSecret(Network.Main).ToString()); Assert.Equal(test.Address, actualKey.PubKey.GetAddress(Network.Main).ToString()); Assert.Equal(test.Compressed, actualKey.IsCompressed); //Can generate same BitcoinPassphraseCode with by using same ownerentropy var passCode = new BitcoinPassphraseCode(test.PassphraseCode, Network.Main); Assert.Null(passCode.LotSequence); var actualPassCode = new BitcoinPassphraseCode(test.Passphrase, Network.Main, null, passCode.OwnerEntropy); Assert.Equal(passCode.ToString(), actualPassCode.ToString()); //Can generate encrypted key from passcode var generatedEncryptedKey = passCode.GenerateEncryptedSecret(test.Compressed).EncryptedKey; AssertEx.CollectionEquals(passCode.OwnerEntropy, generatedEncryptedKey.OwnerEntropy); Assert.Equal(test.Compressed, generatedEncryptedKey.IsCompressed); } }
public void EncryptedSecretECmultiplyNoLotSimple() { var compressedValues = new[] { false, true }; foreach(var compressed in compressedValues) { var code = new BitcoinPassphraseCode("test", Network.Main, null); Assert.Null(code.LotSequence); var result = code.GenerateEncryptedSecret(compressed); Assert.True(result.ConfirmationCode.Check("test", result.GeneratedAddress)); Assert.False(result.ConfirmationCode.Check("toto", result.GeneratedAddress)); Assert.False(result.ConfirmationCode.Check("test", new Key().PubKey.GetAddress(Network.Main))); var decryptedKey = result.EncryptedKey.GetKey("test"); Assert.Equal(result.GeneratedAddress.ToString(), decryptedKey.PubKey.GetAddress(Network.Main).ToString()); Assert.Throws<SecurityException>(() => result.EncryptedKey.GetKey("wrong")); //Can regenerate same result with same seed var result2 = code.GenerateEncryptedSecret(compressed, seedb: result.Seed); var decryptedKey2 = result.EncryptedKey.GetKey("test"); AssertEx.CollectionEquals(decryptedKey2.ToBytes(), decryptedKey.ToBytes()); } }
public void EncryptedSecretECmultiplyLotSequence() { var tests = new[] { new { Passphrase= "ΜΟΛΩΝ ΛΑΒΕ", PassphraseCode= "passphrased3z9rQJHSyBkNBwTRPkUGNVEVrUAcfAXDyRU1V28ie6hNFbqDwbFBvsTK7yWVK", Encrypted = "6PgGWtx25kUg8QWvwuJAgorN6k9FbE25rv5dMRwu5SKMnfpfVe5mar2ngH", Address = "1Lurmih3KruL4xDB5FmHof38yawNtP9oGf", Unencrypted = "5KMKKuUmAkiNbA3DazMQiLfDq47qs8MAEThm4yL8R2PhV1ov33D", ConfirmationCode = "cfrm38V8G4qq2ywYEFfWLD5Cc6msj9UwsG2Mj4Z6QdGJAFQpdatZLavkgRd1i4iBMdRngDqDs51", LotSequence = new LotSequence(806938,1), Compressed = false } ,new { Passphrase= "MOLON LABE", PassphraseCode= "passphraseaB8feaLQDENqCgr4gKZpmf4VoaT6qdjJNJiv7fsKvjqavcJxvuR1hy25aTu5sX", Encrypted = "6PgNBNNzDkKdhkT6uJntUXwwzQV8Rr2tZcbkDcuC9DZRsS6AtHts4Ypo1j", Address = "1Jscj8ALrYu2y9TD8NrpvDBugPedmbj4Yh", Unencrypted = "5JLdxTtcTHcfYcmJsNVy1v2PMDx432JPoYcBTVVRHpPaxUrdtf8", ConfirmationCode = "cfrm38V8aXBn7JWA1ESmFMUn6erxeBGZGAxJPY4e36S9QWkzZKtaVqLNMgnifETYw7BPwWC9aPD", LotSequence = new LotSequence(263183,1), Compressed = false } }; foreach(var test in tests) { //Can generate unencrypted key with password and encrypted key var encryptedKey = new BitcoinEncryptedSecretEC(test.Encrypted, Network.Main); AssertSequenceEquals(test.LotSequence, encryptedKey.LotSequence); var actualKey = encryptedKey.GetKey(test.Passphrase); Assert.Equal(test.Unencrypted, actualKey.GetBitcoinSecret(Network.Main).ToString()); Assert.Equal(test.Address, actualKey.PubKey.GetAddress(Network.Main).ToString()); Assert.Equal(test.Compressed, actualKey.IsCompressed); //Can generate same BitcoinPassphraseCode with by using same ownerentropy var passCode = new BitcoinPassphraseCode(test.PassphraseCode, Network.Main); AssertSequenceEquals(test.LotSequence, passCode.LotSequence); var actualPassCode = new BitcoinPassphraseCode(test.Passphrase, Network.Main, test.LotSequence, passCode.OwnerEntropy); Assert.Equal(passCode.ToString(), actualPassCode.ToString()); //Can verify confirmation var confirmation = new BitcoinConfirmationCode(test.ConfirmationCode, Network.Main); AssertSequenceEquals(confirmation.LotSequence, test.LotSequence); Assert.True(confirmation.Check(test.Passphrase, new BitcoinAddress(test.Address, Network.Main))); //Can generate encrypted key from passcode var generatedEncryptedKey = passCode.GenerateEncryptedSecret(test.Compressed).EncryptedKey; AssertEx.CollectionEquals(passCode.OwnerEntropy, generatedEncryptedKey.OwnerEntropy); Assert.Equal(test.Compressed, generatedEncryptedKey.IsCompressed); } }
static void Main() { RandomUtils.Random = new UnsecureRandom(); //==================================================================================== //Section. BIP38(Part 2) //We already looked at using BIP38 to encrypt a key. However this BIP is in reality two ideas in one document. //The second part of the BIP shows how you can delegate Key and Address creation to an untrusted peer. It will fix one of our concerns. //The idea is to generate a PassphraseCode to the key generator. With this PassphraseCode, they will be able to generate encrypted keys on your behalf, without knowing your password, nor any private key. //This PassphraseCode can be given to your key generator in WIF format. //Tip: In NBitcoin, all types prefixed by “Bitcoin” are Base58 (WIF) data. //So, as a user that wants to delegate key creation, first you will create the PassphraseCode. //Illustration: //Password + Network => PassphraseCode var passphraseCode = new BitcoinPassphraseCode("my secret", Network.Main, null); //You then give this PassphraseCode to a third party key generator. And then, the third party key generator will generate new encrypted keys for me. //Illustration: //PassphraseCode => EncryptedKey1, EncryptedKey2 EncryptedKeyResult encryptedKeyResult = passphraseCode.GenerateEncryptedSecret(); //This EncryptedKeyResult class has lots of information: //Illustration: //First is the generated Bitcoin address. var generatedAddress = encryptedKeyResult.GeneratedAddress; //Output: //14KZsAVLwafhttaykXxCZt95HqadPXuz73 //Second is the encryptedKey itself as we have seen in the previous, Key Encryption lesson. var encryptedKey = encryptedKeyResult.EncryptedKey; //And last but not least, the ConfirmationCode, so that the third party can prove that the generated key and address correspond to my password. var confirmationCode = encryptedKeyResult.ConfirmationCode; //Output: //cfrm38VUcrdt2zf1dCgf4e8gPNJJxnhJSdxYg6STRAEs7QuAuLJmT5W7uNqj88hzh9bBnU9GFkN Console.WriteLine(generatedAddress); //Output: //14KZsAVLwafhttaykXxCZt95HqadPXuz73 Console.WriteLine(encryptedKey); //Output: //6PnWtBokjVKMjuSQit1h1Ph6rLMSFz2n4u3bjPJH1JMcp1WHqVSfr5ebNS Console.WriteLine(confirmationCode); //Output: //cfrm38VUcrdt2zf1dCgf4e8gPNJJxnhJSdxYg6STRAEs7QuAuLJmT5W7uNqj88hzh9bBnU9GFkN //As the owner, once you receive this information, you need to check that the key generator did not cheat by using ConfirmationCode.Check, then get your private key with your password: Console.WriteLine(confirmationCode.Check("my secret", generatedAddress)); //Output: //True //Get bitcoinPrivateKey by a password. var bitcoinPrivateKey = encryptedKey.GetSecret("my secret"); Console.WriteLine(bitcoinPrivateKey.GetAddress() == generatedAddress); //Output: //True Console.WriteLine(bitcoinPrivateKey); //Output: //KzzHhrkr39a7upeqHzYNNeJuaf1SVDBpxdFDuMvFKbFhcBytDF1R //So, we have just seen how the third party can generate encrypted keys on your behalf, without them knowing your password and private key. //In other words, you've delegated a Key and Address creation to an untrusted peer, the third party. //Illustration: //However, one problem remains: //All backups of your wallet that you have will become outdated when you generate a new key. //BIP 32, or Hierarchical Deterministic Wallets (HD wallets), proposes another solution which is more widely supported. }