Пример #1
0
        public static void KeyDerivationFunction()
        {
            // KDF or Key Derivation Function is a way to have a stronger key, despite low entropy.
            // A 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 the attack knows that the source of entropy is 5 letters, he needs to run SCrypt to check each possibility, taking 5 seconds.

            // A standard already exists for encrypting your private key with a password using a KDF. This 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.GetSecret("password");

            Console.WriteLine(decryptedBitcoinPrivateKey);

            // Why generate several keys?
            // The main reason is privacy.
            // You can see the balance of all Bitcoin addresses.
            // It is better to use a new address for each transaction.
            // In practice, you can also generate keys for each contact which makes this a simple way to identify your payer without leaking too much privacy.
            // However, all bakcups of your wallet that you have will become outdated when you generate a new key.
            // You cannot delegate the address creation process to an untrusted peer.
        }
Пример #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 void CanRoundTripSeedEncryption()
        {
            //Test easily debuggable
            var seed    = new byte[24];
            var derived = new byte[64];

            byte[] encrypted  = BitcoinEncryptedSecret.EncryptSeed(seed, derived);
            byte[] actualSeed = BitcoinEncryptedSecret.DecryptSeed(encrypted, derived);
            Assert.Equal(seed, actualSeed);

            //The real deal
            for (int i = 0; i < 5; i++)
            {
                seed      = RandomUtils.GetBytes(24);
                derived   = RandomUtils.GetBytes(64);
                encrypted = BitcoinEncryptedSecret.EncryptSeed(seed, derived);

                byte[] encryptedBefore = encrypted.ToArray();
                for (int u = 8; u < 16; u++)
                {
                    encrypted[u] = 0;
                }
                actualSeed = BitcoinEncryptedSecret.DecryptSeed(encrypted, derived);
                //Restore old encrypted
                AssertEx.CollectionEquals(encrypted, encryptedBefore);
                Assert.Equal(seed, actualSeed);
            }
        }
Пример #4
0
        private void Code8()
        {
            var           key = new Key();
            BitcoinSecret wif = key.GetBitcoinSecret(Network.Main);

            Console.WriteLine(wif);
            BitcoinEncryptedSecret encrypted = wif.Encrypt("secret");

            Console.WriteLine(encrypted);
            wif = encrypted.GetSecret("secret");
            Console.WriteLine(wif);
        }
Пример #5
0
        /// <summary>
        /// Decrypt and retrieve the BitcoinSecret stored in the database.
        /// /// </summary>
        /// <param name="password">The password with which to decrypt the key.</param>
        /// <returns>The stored BitcoinSecret if exists or null if does not. Throws SecurityException on invalid password.</returns>
        public BitcoinSecret RetrieveDecryptedPrivateKey(string password)
        {
            var retrKeyDoc = BitCollection.FindOne(z => z.ContainsKey("BPK1"));

            if (retrKeyDoc != null)
            {
                return(BitcoinEncryptedSecret.Create(retrKeyDoc["BPK1"], Network.GetNetwork(retrKeyDoc["BPK1NW"])).GetSecret(password));
            }
            else
            {
                return(null);
            }
        }
Пример #6
0
        void Start()
        {
            var privateKey        = new Key();
            var bitcoinPrivateKey = privateKey.GetWif(Network.Main);

            UnityEngine.Debug.Log(bitcoinPrivateKey);                                   // L1tZPQt7HHj5V49YtYAMSbAmwN9zRjajgXQt9gGtXhNZbcwbZk2r
            BitcoinEncryptedSecret encryptedBitcoinPrivateKey = bitcoinPrivateKey.Encrypt("password");

            UnityEngine.Debug.Log(encryptedBitcoinPrivateKey);                  // 6PYKYQQgx947Be41aHGypBhK6TA5Xhi9TdPBkatV3fHbbKrdDoBoXFCyLK
            var decryptedBitcoinPrivateKey = encryptedBitcoinPrivateKey.GetSecret("password");

            UnityEngine.Debug.Log(decryptedBitcoinPrivateKey);                  // L1tZPQt7HHj5V49YtYAMSbAmwN9zRjajgXQt9gGtXhNZbcwbZk2r
        }
Пример #7
0
        static void Test(string[] args)
        {
            var privateKey        = new Key();
            var bitcoinPrivateKey = privateKey.GetWif(Network.Main);

            Console.WriteLine(bitcoinPrivateKey);
            BitcoinEncryptedSecret encryptedBitcoinPrivateKey = bitcoinPrivateKey.Encrypt("password");

            Console.WriteLine(encryptedBitcoinPrivateKey);
            var decryptedBitcoinPrivateKey = encryptedBitcoinPrivateKey.GetSecret("password");

            Console.WriteLine(decryptedBitcoinPrivateKey);
            Console.ReadKey();
        }
Пример #8
0
        static void Main()
        {
            var privateKey        = new Key();
            var bitcoinPrivateKey = privateKey.GetWif(Network.Main);

            Console.WriteLine(bitcoinPrivateKey); // L1tZPQt7HHj5V49YtYAMSbAmwN9zRjajgXQt9gGtXhNZbcwbZk2r
            BitcoinEncryptedSecret encryptedBitcoinPrivateKey = bitcoinPrivateKey.Encrypt("password");

            Console.WriteLine(encryptedBitcoinPrivateKey); // 6PYKYQQgx947Be41aHGypBhK6TA5Xhi9TdPBkatV3fHbbKrdDoBoXFCyLK
            var decryptedBitcoinPrivateKey = encryptedBitcoinPrivateKey.GetSecret("password");

            Console.WriteLine(decryptedBitcoinPrivateKey); // L1tZPQt7HHj5V49YtYAMSbAmwN9zRjajgXQt9gGtXhNZbcwbZk2r

            Console.ReadLine();
        }
Пример #9
0
        public void CanRoundTripKeyEncryption()
        {
            //Test easily debuggable
            var key     = new byte[32];
            var derived = new byte[64];

            byte[] encrypted  = BitcoinEncryptedSecret.EncryptKey(key, derived);
            byte[] actualSeed = BitcoinEncryptedSecret.DecryptKey(encrypted, derived);
            Assert.Equal(key, actualSeed);

            //The real deal
            for (int i = 0; i < 5; i++)
            {
                key        = RandomUtils.GetBytes(32);
                derived    = RandomUtils.GetBytes(64);
                encrypted  = BitcoinEncryptedSecret.EncryptKey(key, derived);
                actualSeed = BitcoinEncryptedSecret.DecryptKey(encrypted, derived);
                Assert.Equal(key, actualSeed);
            }
        }
Пример #10
0
        private static void Main(string[] args)
        {
            // Private keys are often represented in Base58Check called a Bitcoin Secret
            // (also known as Wallet Import Format or simply WIF), like Bitcoin Addresses.
            var privateKey = new Key();

            /*
             * Note:
             *  it is easy to go from BitcoinSecret to private Key, however
             *  it is impossible to go from a Bitcoin Address to Public Key
             *  because the Bitcoin Address contains a hash of the Public Key, not the Public Key itself.
             */

            // pass in enum value: Main/TestNet, for use on respective networks
            BitcoinSecret createdWithGetWif           = privateKey.GetWif(Network.Main); // method has same body of .GetBitcoinSecret, returns same result
            BitcoinSecret createdWithGetBitcoinSecret = privateKey.GetBitcoinSecret(Network.Main);

            var wifIsBitcoinSecret = createdWithGetWif == createdWithGetBitcoinSecret;

            Console.WriteLine(wifIsBitcoinSecret); // true

            PubKey publicKey = privateKey.PubKey;
            BitcoinPubKeyAddress bitcoinPubKey = publicKey.GetAddress(Network.Main);

            Console.WriteLine(publicKey);
            Console.WriteLine(bitcoinPubKey);

            BitcoinEncryptedSecret encryptedBitcoinPrivateKey = createdWithGetWif.Encrypt("ilovecrypto");

            Console.WriteLine(encryptedBitcoinPrivateKey);

            BitcoinSecret secret = encryptedBitcoinPrivateKey.GetSecret("ilovecrypto");

            Console.WriteLine(secret);

            Console.WriteLine(secret == createdWithGetWif);

            // keep the console open to read
            Console.ReadLine();
        }
Пример #11
0
        private static byte[] EncryptKey(byte[] keyhalf1, byte[] keyhalf2, byte[] derived)
        {
            var derivedhalf1 = derived.SafeSubarray(0, 32);
            var derivedhalf2 = derived.SafeSubarray(32, 32);

            var encryptedhalf1 = new byte[16];
            var encryptedhalf2 = new byte[16];

#if USEBC || WINDOWS_UWP
            var aes = BitcoinEncryptedSecret.CreateAES256(true, derivedhalf2);
#else
            var aes = CreateAES256();
            aes.Key = derivedhalf2;
            var encrypt = aes.CreateEncryptor();
#endif

            for (int i = 0; i < 16; i++)
            {
                derivedhalf1[i] = (byte)(keyhalf1[i] ^ derivedhalf1[i]);
            }
#if USEBC || WINDOWS_UWP
            aes.ProcessBytes(derivedhalf1, 0, 16, encryptedhalf1, 0);
            aes.ProcessBytes(derivedhalf1, 0, 16, encryptedhalf1, 0);
#else
            encrypt.TransformBlock(derivedhalf1, 0, 16, encryptedhalf1, 0);
#endif
            for (int i = 0; i < 16; i++)
            {
                derivedhalf1[16 + i] = (byte)(keyhalf2[i] ^ derivedhalf1[16 + i]);
            }
#if USEBC || WINDOWS_UWP
            aes.ProcessBytes(derivedhalf1, 16, 16, encryptedhalf2, 0);
            aes.ProcessBytes(derivedhalf1, 16, 16, encryptedhalf2, 0);
#else
            encrypt.TransformBlock(derivedhalf1, 16, 16, encryptedhalf2, 0);
#endif
            return(encryptedhalf1.Concat(encryptedhalf2).ToArray());
        }
Пример #12
0
        private ExtKey GetMasterKey()
        {
            if (String.IsNullOrEmpty(WalletExtendedPublicKey))
            {
                return(ExtKey.Parse(WalletPrivateKey));
            }

            var xpub     = ExtPubKey.Parse(WalletExtendedPublicKey);
            var password = default(SecureString);

            try
            {
                var encrypted = BitcoinEncryptedSecret.Create(WalletPrivateKey);
                password = GetPassword();

                return(new ExtKey(xpub, encrypted.GetKey(new NetworkCredential(String.Empty, password).Password)));
            }
            catch (FormatException)
            {
                return(new ExtKey(xpub, Key.Parse(WalletPrivateKey)));
            }
            catch (SecurityException)
            {
                Console.WriteLine("Invalid password.");
#if DEBUG
                Console.WriteLine("Press Any Key To Exit...");
                Console.Read();
#endif
                Environment.Exit(1);
                return(null);
            }
            finally
            {
                password?.Dispose();
            }
        }
Пример #13
0
        static void Main(string[] args)
        {
            var options = new Options();

            if (args.Length == 0)
            {
                ShowUsage(options);
            }
            if (Parser.Default.ParseArguments(args, options))
            {
                var network = options.Network.Equals("mainnet", StringComparison.InvariantCultureIgnoreCase)
                                        ? Network.Main :
                              options.Network.Equals("testnet", StringComparison.InvariantCultureIgnoreCase)
                              ? Network.TestNet : null;

                if (network == null)
                {
                    ShowUsage(options);
                    return;
                }
                if (options.GenerateKey)
                {
                    var key = new Key().GetBitcoinSecret(network);
                    Console.WriteLine("Private Key : " + key);
                    Console.WriteLine("Bitcoin Address : " + key.GetAddress());
                }

                if (options.GenerateEncryptedKey)
                {
                    Console.WriteLine("Password ? (input hidden from screen)");
                    var password = SecretReadLine();
                    while (true)
                    {
                        Console.WriteLine("Confirm, type the password again");
                        if (password == SecretReadLine())
                        {
                            break;
                        }
                        Console.WriteLine("You typed a different one");
                    }
                    var key = new Key().GetBitcoinSecret(network);
                    Console.WriteLine("Encrypted Key : " + key.Encrypt(password));
                    Console.WriteLine("Bitcoin Address : " + key.GetAddress());
                }

                if (options.DecryptEncryptedKey)
                {
                    Console.WriteLine("Encrypted Key ?");
                    BitcoinEncryptedSecret key = null;
                    while (true)
                    {
                        var encrypted = Console.ReadLine();
                        try
                        {
                            key = BitcoinEncryptedSecret.Create(encrypted);
                            break;
                        }
                        catch (FormatException)
                        {
                            Console.WriteLine("Wrong format");
                        }
                    }
                    Console.WriteLine("Password ? (input hidden from screen)");
                    BitcoinSecret secret = null;
                    while (true)
                    {
                        try
                        {
                            var password = SecretReadLine();
                            secret = key.GetSecret(password);
                            Console.WriteLine("Decrypted successfully");
                            Console.WriteLine("Bitcoin address : " + secret.GetAddress());
                            break;
                        }
                        catch (SecurityException ex)
                        {
                            Console.WriteLine("Wrong password");
                        }
                    }

                    Console.WriteLine("Print the decrypted key on screen ? (o/n)");
                    var r = Console.ReadLine();
                    if (r.Equals("o", StringComparison.InvariantCultureIgnoreCase))
                    {
                        Console.WriteLine(secret);
                    }
                }

                if (!String.IsNullOrEmpty(options.ParseBase58))
                {
                    try
                    {
                        var result = Network.CreateFromBase58Data(options.ParseBase58, network);
                        Console.WriteLine(result.GetType().Name);
                        if (result is BitcoinSecret)
                        {
                            Console.WriteLine("Bitcoin Address " + ((BitcoinSecret)result).GetAddress());
                        }
                    }
                    catch (FormatException)
                    {
                        Console.Write("Invalid base58");
                    }
                }
            }
        }
Пример #14
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();
        }
Пример #15
0
        private void buttonOk_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(textBoxPassword.Text))
            {
                MessageBox.Show(this, "You must enter a password and a Bitcoin Secret or Encrypted Key.", "Knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            if (string.IsNullOrEmpty(textBoxEncrypted.Text) && string.IsNullOrEmpty(textBoxSecret.Text))
            {
                MessageBox.Show(this, "You must enter a Bitcoin Secret or Encrypted Key.", "Knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            if (string.IsNullOrEmpty(textBoxEncrypted.Text))
            {
                using (new HourGlass())
                {
                    _result = Util.Interpret(textBoxSecret.Text);
                }

                if (_result == null || !(_result is BitcoinSecret))
                {
                    MessageBox.Show(this, "Unrecognized or invalid key.", "Knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                using (new HourGlass())
                {
                    try
                    {
                        BitcoinSecret          secret    = _result as BitcoinSecret;
                        BitcoinEncryptedSecret encrypted = secret.Encrypt(textBoxPassword.Text);
                        textBoxEncrypted.Text = encrypted.ToString();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(this, ex.Message, "Knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
            else if (string.IsNullOrEmpty(textBoxSecret.Text))
            {
                using (new HourGlass())
                {
                    _result = Util.Interpret(textBoxEncrypted.Text);
                }

                if (_result == null || !(_result is BitcoinEncryptedSecretNoEC))
                {
                    MessageBox.Show(this, "Unrecognized or invalid key.", "Knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                using (new HourGlass())
                {
                    try
                    {
                        BitcoinEncryptedSecretNoEC encEC = _result as BitcoinEncryptedSecretNoEC;
                        textBoxSecret.Text = encEC.GetKey(textBoxPassword.Text).GetBitcoinSecret(Network.TestNet).ToString();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(this, ex.Message, "Knoledge-keychain", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
        }
Пример #16
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));
        }
Пример #17
0
        public void TestAddressCreation()
        {
            Key privateKey;                                                                               // = new Key();

            privateKey = Key.Parse("L5e7GTVzDEFTS2YwRJcRse5LkgpAetKApCafc6avoKLovPcnFE74", Network.Main); // For getting the same outputs
            PubKey         publicKey         = privateKey.PubKey;
            BitcoinAddress addressLegacy     = publicKey.GetAddress(ScriptPubKeyType.Legacy, Network.Main);
            BitcoinAddress addressSegwit     = publicKey.GetAddress(ScriptPubKeyType.Segwit, Network.Main);
            BitcoinAddress addressSegwitP2SH = publicKey.GetAddress(ScriptPubKeyType.SegwitP2SH, Network.Main);
            KeyId          publicKeyHash     = publicKey.Hash;

            // Wif -> 
            // Priv. key -> Wif (Check README.md - Wif)
            BitcoinSecret wif  = privateKey.GetWif(Network.Main);
            BitcoinSecret wif2 = new BitcoinSecret("L5e7GTVzDEFTS2YwRJcRse5LkgpAetKApCafc6avoKLovPcnFE74", Network.Main);

            Assert.AreEqual(wif, wif2);

            // Private key -> 
            // Wif -> Priv. key
            Key privateKey1 = Key.Parse("L5e7GTVzDEFTS2YwRJcRse5LkgpAetKApCafc6avoKLovPcnFE74", Network.Main);

            Assert.AreEqual(privateKey, privateKey1);

            // Base58 encoded priv key
            var privKeyVersionBytes = Network.Main.GetVersionBytes(Base58Type.SECRET_KEY, true);

            byte[] privKeyWithVersionBytes = Helper.Concat(privKeyVersionBytes, privateKey.ToBytes());
            var    privKeyBase58           = Encoders.Base58Check.EncodeData(privKeyWithVersionBytes);

            // Encrypted priv key (BIP38)
            BitcoinEncryptedSecret encryptedPrivKey = wif.Encrypt("password");

            // Decrypted priv key
            BitcoinEncryptedSecret encryptedPrivKeyFromStr = BitcoinEncryptedSecret.Create("6PYWRpL1zPnz5kVxn74H9WdGJZVQ3ah6Pnq54GNinkfrXdd9fWNVS6dn95", Network.Main);
            BitcoinSecret          decryptedPrivKey        = encryptedPrivKeyFromStr.GetSecret("password");

            Assert.AreEqual(wif, decryptedPrivKey);

            // Public key hash -> 
            // Check README (Hash160(Public Key))
            var hash1 = NBitcoin.Crypto.Hashes.SHA256(publicKey.ToBytes());
            var pkh   = NBitcoin.Crypto.Hashes.RIPEMD160(hash1, hash1.Length); // SHA256(RIPEMD160(PUB_KUY))
            var generatedPubKeyHash = new KeyId(pkh);

            Assert.AreEqual(publicKeyHash, generatedPubKeyHash);

            // Bitcoin Address > 
            var versionBytes = Network.Main.GetVersionBytes(Base58Type.PUBKEY_ADDRESS, true); // 0x00

            byte[] PKHWithVersionBytes = Helper.Concat(versionBytes, pkh);                    // 0x00 + PKH
            var    address1            = Encoders.Base58Check.EncodeData(PKHWithVersionBytes);

            Assert.AreEqual(addressLegacy.ToString(), address1); // 1Co3ZZ3U5ELVmZrV3oXk2qbv58AjuwRrnB

            Console.WriteLine();
            Console.WriteLine($"Pri : {privateKey.ToHex()} (Hex)");         // fb401b5261327d8543382c065af27e28a9775c278b7c3dba8cd0d88f0ad042b1
            Console.WriteLine($"Pri : {privKeyBase58} (Base58)");           // 5KiwSFcZuAM3N5Ruf8cfiNzdCFupxFoFuqPafmK7JHqtsEms7HB
            Console.WriteLine($"Pri : {encryptedPrivKey} (Encrypted)");     // 6PYWRpL1zPnz5kVxn74H9WdGJZVQ3ah6Pnq54GNinkfrXdd9fWNVS6dn95
            Console.WriteLine($"Pri : {wif} (Wif)");                        // L5e7GTVzDEFTS2YwRJcRse5LkgpAetKApCafc6avoKLovPcnFE74
            Console.WriteLine($"Pub : {publicKey}");                        // 03c092d451383dedd6052de6778f9b7c393252ecbd4cd05e842638a84a2c6e2528
            Console.WriteLine($"Pub : {publicKey.Decompress()} (Decomp.)"); // 04c092d451383dedd6052de6778f9b7c393252ecbd4cd05e842638a84a2c6e2528fe41f265a1d8884eb304a33b6f8a6a245fab83f7bf503d7dfc532ffc6593df15
            Console.WriteLine($"PKH : {publicKey.Hash}");                   // 815ea7e8372ae215c40dc3d07a024adc7ddaf858
            Console.WriteLine($"Add : {addressLegacy} (Legacy)");           // 1Co3ZZ3U5ELVmZrV3oXk2qbv58AjuwRrnB
            Console.WriteLine($"Add : {addressSegwitP2SH} (SegwitP2SH)");   // 3JCvRhjrEyw9pvZiE3TxsdSHNPJQh1vHTe
            Console.WriteLine($"Add : {addressSegwit} (Segwit)");           // bc1qs90206ph9t3pt3qdc0g85qj2m37a47zclpwws7
        }
Пример #18
0
        static void Main()
        {
            RandomUtils.Random = new UnsecureRandom();

            //============================================================================================
            //Sectioin. Key generation and encryption



            //============================================================================================
            //Section1. Is it random enough?

            //When you call new Key(), under the hood, you are using a PRNG (Pseudo - Random - Number - Generator) to generate your private key.On windows, it uses the RNGCryptoServiceProvider, a.NET wrapper around the Windows Crypto API.
            //    On Android, I use the SecureRandom class, and in fact, you can use your own implementation with RandomUtils.Random.
            //    On iOS, I have not implemented it and you will need to create your own IRandom implementation.
            //    For a computer, being random is hard.But the biggest issue is that it is impossible to know if a series of numbers is really random.
            //If malware modifies your PRNG so that it can predict the numbers you will generate, you won’t see it until it is too late.
            //It means that a cross platform and naïve implementation of PRNG (like using the computer’s clock combined with CPU speed) is dangerous.But you won’t see it until it is too late.
            //For performance reasons, most PRNG works the same way: a random number which is called a Seed is chosen, then a predictable formula generates the next number each time you ask for it.
            //The amount of randomness of the seed is defined by a measure we call Entropy, but the amount of Entropy also depends on the observer.
            //Let’s say you generate a seed from your clock time.
            //And let’s imagine that your clock has 1ms of resolution. (Reality is more ~15ms.)
            //If your attacker knows that you generated the key last week, then your seed has
            //1000 * 60 * 60 * 24 * 7 = 604800000 possibilities.
            //For such attacker, the entropy is log2(604800000) = 29.17 bits.
            //And enumerating such all possibility with corresponding entropy on my home computer took less than 2 seconds. We call such enumeration “brute forcing”.
            //However, let’s say, you use the clock time + the process ID for generating the seed.
            //Let’s imagine that there are 1024 different process IDs.
            //So now, the attacker needs to enumerate 604800000 * 1024 possibilities, which take around 2000 seconds.
            //Now, let’s add the time on it. When I turned on my computer, assuming the attacker knows I turned it on today, it adds 86400000 possibilities.
            //Now the attacker needs to enumerate 604800000 * 1024 * 86400000 = 5,35088E+19 possibilities.
            //However, keep in mind that if the attacker has infiltrated my computer, he can get this last piece of info, and bring down the number of possibilities, reducing entropy.
            //Entropy is measured by log2(possibilities) and so log2(5,35088E+19) = 65 bits.
            //Is it enough? Probably, only when you assuming your attacker does not know more information about the realm of possibilities used to generate the seed.
            //But since the hash of a public key is 20 bytes(160 bits), it is smaller than the total universe of the addresses.You might do better.
            //Note: Adding entropy is linearly harder. On the other hand, cracking entropy is exponentially harder.
            //An interesting way of generating entropy quickly is by incorporating human intervention, such as moving the mouse.+


            //If you don’t completely trust the platform PRNG (which is not so paranoic), you can add entropy to the PRNG output that NBitcoin is using.

            //What NBitcoin does when you call AddEntropy(data) is
            //additionalEntropy = SHA(SHA(data)^additionalEntropy)
            RandomUtils.AddEntropy("hello");
            RandomUtils.AddEntropy(new byte[] { 1, 2, 3 });
            //When you generate a new number it's like
            //result = SHA(PRNG()^additionalEntropy)
            var nsaProofKey = new Key();

            Console.WriteLine(nsaProofKey.GetWif(Network.Main));



            //=======================================================================================
            //Section2. Key Derivation Function

            //However, what is most important is not the number of possibilities.It is the time that an attacker would need to successfully break your key. That’s where KDF enters the game.
            //KDF, or Key Derivation Function, is a way to have a stronger key, even if your entropy is low.
            //Imagine that you want to generate a seed, and the attacker knows that there are 10,000,000 possibilities.
            //Such a seed would be normally cracked pretty easily.
            //But what if you could make the enumeration slower?
            //A KDF is a hash function that wastes computing resources on purpose.
            //Here is an example:
            var derived = SCrypt.BitcoinComputeDerivedKey("hello", new byte[] { 1, 2, 3 });

            RandomUtils.AddEntropy(derived);



            //Even if your attacker knows that your source of entropy is 5 letters, he will need to run Scrypt to check each possibility, which takes 5 seconds on my computer.
            //The bottom line is: There is nothing paranoid in distrusting a PRNG, and you can mitigate an attack by both adding entropy and also using a KDF.
            //Keep in mind that an attacker can decrease entropy by gathering information about you or your system.
            //If you use the timestamp as entropy source, then an attacker can decrease the entropy by knowing the fact that you generated the key last week, and that you only use your computer between 9am and 6pm.
            //In the previous part I talked briefly about a special KDF called Scrypt. As I said, the goal of a KDF is to make "brute forcing" costly.
            //So it should be no surprise for you that a standard already exists for encrypting your private key with a password using a KDF.This is BIP38.

            var privateKey        = new Key();
            var bitcoinPrivateKey = privateKey.GetWif(Network.Main);

            Console.WriteLine(bitcoinPrivateKey);
            //Output:
            //L1tZPQt7HHj5V49YtYAMSbAmwN9zRjajgXQt9gGtXhNZbcwbZk2r
            BitcoinEncryptedSecret encryptedBitcoinPrivateKey = bitcoinPrivateKey.Encrypt("password");

            Console.WriteLine(encryptedBitcoinPrivateKey);
            //Output:
            //6PYKYQQgx947Be41aHGypBhK6TA5Xhi9TdPBkatV3fHbbKrdDoBoXFCyLK
            var decryptedBitcoinPrivateKey = encryptedBitcoinPrivateKey.GetSecret("password");

            Console.WriteLine(decryptedBitcoinPrivateKey);
            //Output:
            //L1tZPQt7HHj5V49YtYAMSbAmwN9zRjajgXQt9gGtXhNZbcwbZk2r



            //Such encryption is used in two different cases:
            //You do not trust your storage provider(they can get hacked)
            //You are storing the key on the behalf of somebody else (and you do not want to know their key)
            //If you own your storage, then encrypting at the database level might be enough.
            //Be careful if your server takes care of decrypting the key. An attacker might attempt a DDoS attack to your server by forcing it to decrypt lots of keys.
            //Delegate decryption to the ultimate end user when you can.



            //=======================================================================================
            //Section3. Like the good ol’ days

            //First, why generate several keys?
            //The main reason is privacy.Since you can see the balance of all addresses, it is better to use a new address for each transaction.
            //However, in practice, you can also generate keys for each contact which makes this a simple way to identify your payer without leaking too much privacy.
            //You can generate a key, like you did at the beginning:
            var privateKey1 = new Key();


            //However, you have two problems with that:
            //1.All backups of your wallet that you have will become outdated when you generate a new key.
            //2.You cannot delegate the address creation process to an untrusted peer.
            //If you are developing a web wallet and generate keys on behalf of your users, and one user get hacked, they will immediately start suspecting you.
        }
Пример #19
0
 public bool PreRun()
 {
     _Check = BitcoinEncryptedSecret.Create(Address, Network.Main);
     return(true);
 }