예제 #1
0
        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.
        }
예제 #2
0
        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);
        }
예제 #3
0
        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());
        }
예제 #4
0
        static void GenerateKey(Network network, string passphrase)
        {
            var passphraseCode = new BitcoinPassphraseCode(passphrase, network, null);

            EncryptedKeyResult encryptedKeyResult = passphraseCode.GenerateEncryptedSecret();

            Console.WriteLine("Addy: " + encryptedKeyResult.GeneratedAddress);
        }
예제 #5
0
		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);
		}
예제 #6
0
        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);
            }
        }
예제 #7
0
        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();
            }
        }
예제 #9
0
        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();
            }
        }
예제 #11
0
        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);
            }
        }
예제 #12
0
        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);
        }
예제 #13
0
        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
        }
예제 #14
0
        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);
        }
예제 #15
0
        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());
            }
        }
예제 #16
0
        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();
        }
예제 #17
0
        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;
                    }
                }
            }
        }
예제 #18
0
        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));
        }
예제 #19
0
		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);
			}
		}
예제 #20
0
		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());
			}
		}
예제 #21
0
		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);
			}
		}
예제 #22
0
        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.
        }