Example #1
0
        public bool Check(string passphrase, BitcoinAddress expectedAddress)
        {
            //Derive passfactor using scrypt with ownerentropy and the user's passphrase and use it to recompute passpoint
            byte[] passfactor = BitcoinEncryptedSecretEC.CalculatePassFactor(passphrase, LotSequence, OwnerEntropy);
            //Derive decryption key for pointb using scrypt with passpoint, addresshash, and ownerentropy
            byte[] passpoint = BitcoinEncryptedSecretEC.CalculatePassPoint(passfactor);
            byte[] derived   = BitcoinEncryptedSecretEC.CalculateDecryptionKey(passpoint, AddressHash, OwnerEntropy);

            //Decrypt encryptedpointb to yield pointb
            var pointbprefix = EncryptedPointB[0];

            pointbprefix = (byte)(pointbprefix ^ (byte)(derived[63] & (byte)0x01));

            //Optional since ArithmeticException will catch it, but it saves some times
            if (pointbprefix != 0x02 && pointbprefix != 0x03)
            {
                return(false);
            }
            var pointb = BitcoinEncryptedSecret.DecryptKey(EncryptedPointB.Skip(1).ToArray(), derived);

            pointb = new byte[] { pointbprefix }.Concat(pointb).ToArray();

            //4.ECMultiply pointb by passfactor. Use the resulting EC point as a public key

#if HAS_SPAN
            if (!NBitcoinContext.Instance.TryCreatePubKey(pointb, out var pk) || pk is null)
            {
                return(false);
            }
            PubKey pubkey = new PubKey(pk.TweakMul(passfactor), true);
#else
            var     curve = ECKey.Secp256k1;
            ECPoint pointbec;
            try
            {
                pointbec = curve.Curve.DecodePoint(pointb);
            }
            catch (ArgumentException)
            {
                return(false);
            }
            catch (ArithmeticException)
            {
                return(false);
            }
            PubKey pubkey = new PubKey(pointbec.Multiply(new BigInteger(1, passfactor)).GetEncoded());
#endif
            //and hash it into address using either compressed or uncompressed public key methodology as specifid in flagbyte.
            pubkey = IsCompressed ? pubkey.Compress() : pubkey.Decompress();

            var actualhash   = BitcoinEncryptedSecretEC.HashAddress(pubkey.GetAddress(ScriptPubKeyType.Legacy, Network));
            var expectedhash = BitcoinEncryptedSecretEC.HashAddress(expectedAddress);

            return(Utils.ArrayEqual(actualhash, expectedhash));
        }
        public bool Check(string passphrase, BitcoinAddress expectedAddress)
        {
            //Derive passfactor using scrypt with ownerentropy and the user's passphrase and use it to recompute passpoint
            byte[] passfactor = BitcoinEncryptedSecretEC.CalculatePassFactor(passphrase, this.LotSequence, this.OwnerEntropy);
            //Derive decryption key for pointb using scrypt with passpoint, addresshash, and ownerentropy
            byte[] passpoint = BitcoinEncryptedSecretEC.CalculatePassPoint(passfactor);
            byte[] derived   = BitcoinEncryptedSecretEC.CalculateDecryptionKey(passpoint, this.AddressHash, this.OwnerEntropy);

            //Decrypt encryptedpointb to yield pointb
            byte pointbprefix = this.EncryptedPointB[0];

            pointbprefix = (byte)(pointbprefix ^ (byte)(derived[63] & (byte)0x01));

            //Optional since ArithmeticException will catch it, but it saves some times
            if (pointbprefix != 0x02 && pointbprefix != 0x03)
            {
                return(false);
            }
            byte[] pointb = BitcoinEncryptedSecret.DecryptKey(this.EncryptedPointB.Skip(1).ToArray(), derived);
            pointb = new byte[] { pointbprefix }.Concat(pointb).ToArray();

            //4.ECMultiply pointb by passfactor. Use the resulting EC point as a public key
            X9ECParameters curve = ECKey.Secp256k1;
            ECPoint        pointbec;

            try
            {
                pointbec = curve.Curve.DecodePoint(pointb);
            }
            catch (ArgumentException)
            {
                return(false);
            }
            catch (ArithmeticException)
            {
                return(false);
            }
            var pubkey = new PubKey(pointbec.Multiply(new BigInteger(1, passfactor)).GetEncoded());

            //and hash it into address using either compressed or uncompressed public key methodology as specifid in flagbyte.
            pubkey = this.IsCompressed ? pubkey.Compress() : pubkey.Decompress();

            byte[] actualhash   = BitcoinEncryptedSecretEC.HashAddress(pubkey.GetAddress(this.Network));
            byte[] expectedhash = BitcoinEncryptedSecretEC.HashAddress(expectedAddress);

            return(Utils.ArrayEqual(actualhash, expectedhash));
        }
        public EncryptedKeyResult GenerateEncryptedSecret(bool isCompressed = true, byte[] seedb = null)
        {
            //Set flagbyte.
            byte flagByte = 0;

            //Turn on bit 0x20 if the Bitcoin address will be formed by hashing the compressed public key
            flagByte |= isCompressed ? (byte)0x20 : (byte)0x00;
            flagByte |= LotSequence != null ? (byte)0x04 : (byte)0x00;

            //Generate 24 random bytes, call this seedb. Take SHA256(SHA256(seedb)) to yield 32 bytes, call this factorb.
            seedb = seedb ?? RandomUtils.GetBytes(24);

            var factorb = Hashes.Hash256(seedb).ToBytes();

            //ECMultiply passpoint by factorb.
            var curve     = ECKey.CreateCurve();
            var passpoint = curve.Curve.DecodePoint(Passpoint);
            var pubPoint  = passpoint.Multiply(new BigInteger(1, factorb));

            //Use the resulting EC point as a public key
            var pubKey = new PubKey(pubPoint.GetEncoded());

            //and hash it into a Bitcoin address using either compressed or uncompressed public key
            //This is the generated Bitcoin address, call it generatedaddress.
            pubKey = isCompressed ? pubKey.Compress() : pubKey.Decompress();

            //call it generatedaddress.
            var generatedaddress = pubKey.GetAddress(Network);

            //Take the first four bytes of SHA256(SHA256(generatedaddress)) and call it addresshash.
            var addresshash = BitcoinEncryptedSecretEC.HashAddress(generatedaddress);

            //Derive a second key from passpoint using scrypt
            //salt is addresshash + ownerentropy
            var derived = BitcoinEncryptedSecretEC.CalculateDecryptionKey(Passpoint, addresshash, OwnerEntropy);

            //Now we will encrypt seedb.
            var encrypted = BitcoinEncryptedSecret.EncryptSeed
                                (seedb,
                                derived);

            //0x01 0x43 + flagbyte + addresshash + ownerentropy + encryptedpart1[0...7] + encryptedpart2 which totals 39 bytes
            var bytes =
                new[] { flagByte }
            .Concat(addresshash)
            .Concat(this.OwnerEntropy)
            .Concat(encrypted.Take(8).ToArray())
            .Concat(encrypted.Skip(16).ToArray())
            .ToArray();

            var encryptedSecret = new BitcoinEncryptedSecretEC(bytes, Network);

            return(new EncryptedKeyResult(encryptedSecret, generatedaddress, seedb, () =>
            {
                //ECMultiply factorb by G, call the result pointb. The result is 33 bytes.
                var pointb = new Key(factorb).PubKey.ToBytes();
                //The first byte is 0x02 or 0x03. XOR it by (derivedhalf2[31] & 0x01), call the resulting byte pointbprefix.
                var pointbprefix = (byte)(pointb[0] ^ (byte)(derived[63] & 0x01));
                var pointbx = BitcoinEncryptedSecret.EncryptKey(pointb.Skip(1).ToArray(), derived);
                var encryptedpointb = new byte[] { pointbprefix }.Concat(pointbx).ToArray();

                var confirmBytes =
                    Network.GetVersionBytes(Base58Type.CONFIRMATION_CODE)
                    .Concat(new[] { flagByte })
                    .Concat(addresshash)
                    .Concat(OwnerEntropy)
                    .Concat(encryptedpointb)
                    .ToArray();

                return new BitcoinConfirmationCode(Encoders.Base58Check.EncodeData(confirmBytes), Network);
            }));
        }
        public bool Check(string passphrase, BitcoinAddress expectedAddress)
        {
            //Derive passfactor using scrypt with ownerentropy and the user's passphrase and use it to recompute passpoint
            byte[] passfactor = BitcoinEncryptedSecretEC.CalculatePassFactor(passphrase, LotSequence, OwnerEntropy);
            //Derive decryption key for pointb using scrypt with passpoint, addresshash, and ownerentropy
            byte[] passpoint = BitcoinEncryptedSecretEC.CalculatePassPoint(passfactor);
            byte[] derived = BitcoinEncryptedSecretEC.CalculateDecryptionKey(passpoint, AddressHash, OwnerEntropy);

            //Decrypt encryptedpointb to yield pointb
            var pointbprefix = EncryptedPointB[0];
            pointbprefix = (byte)(pointbprefix ^ (byte)(derived[63] & (byte)0x01));

            //Optional since ArithmeticException will catch it, but it saves some times
            if(pointbprefix != 0x02 && pointbprefix != 0x03)
                return false;
            var pointb = BitcoinEncryptedSecret.DecryptKey(EncryptedPointB.Skip(1).ToArray(), derived);
            pointb = new byte[] { pointbprefix }.Concat(pointb).ToArray();

            //4.ECMultiply pointb by passfactor. Use the resulting EC point as a public key
            var curve = ECKey.CreateCurve();
            ECPoint pointbec = null;
            try
            {
                pointbec = curve.Curve.DecodePoint(pointb);
            }
            catch(ArithmeticException)
            {
                return false;
            }
            PubKey pubkey = new PubKey(pointbec.Multiply(new BigInteger(1, passfactor)).GetEncoded());

            //and hash it into address using either compressed or uncompressed public key methodology as specifid in flagbyte.
            pubkey = IsCompressed ? pubkey.Compress() : pubkey.Decompress();

            var actualhash = BitcoinEncryptedSecretEC.HashAddress(pubkey.GetAddress(Network));
            var expectedhash = BitcoinEncryptedSecretEC.HashAddress(expectedAddress);

            return Utils.ArrayEqual(actualhash, expectedhash);
        }
        public async Task <string> WithdrawBtc(string withdrawHash, string recipient, decimal amount)
        {
            var coins        = new List <UTXO>();
            var coinsUsed    = new List <UTXO>();
            var estimatedFee = await client.GetFeeRateAsync(3);

            try
            {
                await locker.WaitAsync();

                while (coinsUsed.Sum(c => c.AsCoin().Amount.ToDecimal(MoneyUnit.BTC)) <= amount)
                {
                    var txOperations = await client.GetUTXOsAsync(TrackedSource.Create(pubKey.GetAddress(ScriptPubKeyType.Legacy, Network.Main)));

                    foreach (var op in txOperations.Confirmed.UTXOs)
                    {
                        if (!usedInputs.ContainsKey(op.TransactionHash.ToString() + op.Value.Satoshi.ToString()))
                        {
                            coins.Add(op);
                        }
                    }

                    coins.Sort(delegate(UTXO x, UTXO y)
                    {
                        return(-x.AsCoin().Amount.CompareTo(y.AsCoin().Amount));
                    });

                    foreach (var item in coins)
                    {
                        if (coinsUsed.Sum(c => c.AsCoin().Amount.ToDecimal(MoneyUnit.BTC)) <= amount)
                        {
                            coinsUsed.Add(item);
                            usedInputs.Add(item.TransactionHash.ToString() + item.Value.Satoshi.ToString(), item);
                        }
                        else
                        {
                            break;
                        }
                    }

                    if (coinsUsed.Sum(c => c.AsCoin().Amount.ToDecimal(MoneyUnit.BTC)) < amount)
                    {
                        await Task.Delay(5000);
                    }
                }

                TransactionBuilder   builder     = null;
                BitcoinPubKeyAddress destination = null;
                if (network == NetworkType.Testnet)
                {
                    builder     = Network.TestNet.CreateTransactionBuilder();
                    destination = new BitcoinPubKeyAddress(recipient, Network.TestNet);
                }
                else
                {
                    builder     = Network.Main.CreateTransactionBuilder();
                    destination = new BitcoinPubKeyAddress(recipient, Network.Main);
                }

                NBitcoin.Transaction tx = builder
                                          .AddCoins(coinsUsed.Select(c => c.AsCoin() /* .ScriptPubKey.ToBytes()*/))
                                          .Send(destination, Money.Coins(amount))
                                          .Send(TxNullDataTemplate.Instance.GenerateScriptPubKey(Encoding.UTF8.GetBytes(withdrawHash)), Money.Zero)
                                          .SetChange(pubKey.GetAddress(ScriptPubKeyType.Legacy, Network.Main))
                                          .SendEstimatedFees((await client.GetFeeRateAsync(3)).FeeRate)
                                          .BuildTransaction(sign: false);

                // Specify the path to unmanaged PKCS#11 library provided by the cryptographic device vendor
                string pkcs11LibraryPath = @"/opt/cloudhsm/lib/libcloudhsm_pkcs11_standard.so";

                // Create factories used by Pkcs11Interop library
                Net.Pkcs11Interop.HighLevelAPI.Pkcs11InteropFactories factories = new Net.Pkcs11Interop.HighLevelAPI.Pkcs11InteropFactories();

                // Load unmanaged PKCS#11 library
                using (Net.Pkcs11Interop.HighLevelAPI.IPkcs11Library pkcs11Library = factories.Pkcs11LibraryFactory.LoadPkcs11Library(factories, pkcs11LibraryPath, AppType.MultiThreaded))
                {
                    // Show general information about loaded library
                    Net.Pkcs11Interop.HighLevelAPI.ILibraryInfo libraryInfo = pkcs11Library.GetInfo();

                    Console.WriteLine("Library");
                    Console.WriteLine("  Manufacturer:       " + libraryInfo.ManufacturerId);
                    Console.WriteLine("  Description:        " + libraryInfo.LibraryDescription);
                    Console.WriteLine("  Version:            " + libraryInfo.LibraryVersion);

                    // Get list of all available slots
                    foreach (Net.Pkcs11Interop.HighLevelAPI.ISlot slot in pkcs11Library.GetSlotList(SlotsType.WithOrWithoutTokenPresent))
                    {
                        // Show basic information about slot
                        Net.Pkcs11Interop.HighLevelAPI.ISlotInfo slotInfo = slot.GetSlotInfo();

                        Console.WriteLine();
                        Console.WriteLine("Slot");
                        Console.WriteLine("  Manufacturer:       " + slotInfo.ManufacturerId);
                        Console.WriteLine("  Description:        " + slotInfo.SlotDescription);
                        Console.WriteLine("  Token present:      " + slotInfo.SlotFlags.TokenPresent);

                        if (slotInfo.SlotFlags.TokenPresent)
                        {
                            // Show basic information about token present in the slot
                            Net.Pkcs11Interop.HighLevelAPI.ITokenInfo tokenInfo = slot.GetTokenInfo();

                            Console.WriteLine("Token");
                            Console.WriteLine("  Manufacturer:       " + tokenInfo.ManufacturerId);
                            Console.WriteLine("  Model:              " + tokenInfo.Model);
                            Console.WriteLine("  Serial number:      " + tokenInfo.SerialNumber);
                            Console.WriteLine("  Label:              " + tokenInfo.Label);

                            // Show list of mechanisms (algorithms) supported by the token
                            Console.WriteLine("Supported mechanisms: ");
                            foreach (CKM mechanism in slot.GetMechanismList())
                            {
                                Console.WriteLine("  " + mechanism);
                            }
                        }

                        using (Net.Pkcs11Interop.HighLevelAPI.ISession session = slot.OpenSession(SessionType.ReadWrite))
                        {
                            session.Login(CKU.CKU_USER, pkcsUser);

                            // Specify signing mechanism
                            Net.Pkcs11Interop.HighLevelAPI.IMechanism mechanism = session.Factories.MechanismFactory.Create(CKM.CKM_ECDSA);

                            List <Net.Pkcs11Interop.HighLevelAPI.IObjectAttribute> publicKeyAttributes = new List <Net.Pkcs11Interop.HighLevelAPI.IObjectAttribute>();
                            publicKeyAttributes.Add(new Net.Pkcs11Interop.HighLevelAPI80.ObjectAttribute(CKA.CKA_LABEL, hsmKey));
                            publicKeyAttributes.Add(new Net.Pkcs11Interop.HighLevelAPI80.ObjectAttribute(CKA.CKA_SIGN, true));


                            Net.Pkcs11Interop.HighLevelAPI.IObjectHandle key = session.FindAllObjects(publicKeyAttributes).FirstOrDefault();

                            uint i = 0;
                            foreach (var c in tx.Inputs.AsIndexedInputs())
                            {
                                byte[] sourceData = c.GetSignatureHash(coinsUsed.First(cu => cu.Outpoint.Hash == c.PrevOut.Hash).AsCoin()).ToBytes();
                                Console.WriteLine("sourceData: " + tx.ToHex());

                                byte[] signature = session.Sign(mechanism, key, sourceData);
                                Console.WriteLine("signature: " + BitConverter.ToString(signature));
                                var canSig = ECDSASignatureFactory.FromComponents(signature).MakeCanonical();
                                var sig    = new NBitcoin.TransactionSignature(new NBitcoin.Crypto.ECDSASignature(new NBitcoin.BouncyCastle.Math.BigInteger(canSig.R.ToByteArray()), new NBitcoin.BouncyCastle.Math.BigInteger(canSig.S.ToByteArray())), SigHash.Single);
                                builder = builder.AddKnownSignature(pubKey, sig, c.PrevOut);
                                TransactionSignature sig2 = null;
                                if (builder.TrySignInput(tx, i, SigHash.Single, out sig2))
                                {
                                    Console.WriteLine("Input Signed");
                                    Console.WriteLine(BitConverter.ToString(sig2.ToBytes()));
                                }
                                else
                                {
                                    Console.WriteLine("Input Not Signed");
                                }

                                Console.WriteLine("tx: " + tx);
                                i++;

                                tx = builder.SignTransactionInPlace(tx);
                            }


                            Console.WriteLine("tx: " + tx);
                            TransactionPolicyError[] errors = null;
                            if (builder.Verify(tx, out errors))
                            {
                                var broadcastResult = await client.BroadcastAsync(tx);

                                broadcastResult.ToString();
                                Console.WriteLine("broadcast: " + tx.GetHash().ToString());
                                session.Logout();
                                return(tx.GetHash().ToString());
                            }
                            else
                            {
                                Console.WriteLine("Verify transaction failed");
                            }

                            if (errors != null)
                            {
                                foreach (var e in errors)
                                {
                                    Console.WriteLine(e.ToString());
                                }
                            }

                            session.Logout();
                        }
                    }
                }

                return(null);
            }
            catch (Exception e)
            {
                Log.Error("Failed to send BTC Withdraw" + e.ToString());
                throw e;
            }
            finally
            {
                locker.Release();
            }
        }
		public EncryptedKeyResult GenerateEncryptedSecret(bool isCompressed = true, byte[] seedb = null)
		{
			//Set flagbyte.
			byte flagByte = 0;
			//Turn on bit 0x20 if the Bitcoin address will be formed by hashing the compressed public key
			flagByte |= isCompressed ? (byte)0x20 : (byte)0x00;
			flagByte |= LotSequence != null ? (byte)0x04 : (byte)0x00;

			//Generate 24 random bytes, call this seedb. Take SHA256(SHA256(seedb)) to yield 32 bytes, call this factorb.
			seedb = seedb ?? RandomUtils.GetBytes(24);

			var factorb = Hashes.Hash256(seedb).ToBytes();

			//ECMultiply passpoint by factorb.
			var curve = ECKey.Secp256k1;
			var passpoint = curve.Curve.DecodePoint(Passpoint);
			var pubPoint = passpoint.Multiply(new BigInteger(1, factorb));

			//Use the resulting EC point as a public key
			var pubKey = new PubKey(pubPoint.GetEncoded());

			//and hash it into a Bitcoin address using either compressed or uncompressed public key
			//This is the generated Bitcoin address, call it generatedaddress.
			pubKey = isCompressed ? pubKey.Compress() : pubKey.Decompress();

			//call it generatedaddress.
			var generatedaddress = pubKey.GetAddress(Network);

			//Take the first four bytes of SHA256(SHA256(generatedaddress)) and call it addresshash.
			var addresshash = BitcoinEncryptedSecretEC.HashAddress(generatedaddress);

			//Derive a second key from passpoint using scrypt
			//salt is addresshash + ownerentropy
			var derived = BitcoinEncryptedSecretEC.CalculateDecryptionKey(Passpoint, addresshash, OwnerEntropy);

			//Now we will encrypt seedb.
			var encrypted = BitcoinEncryptedSecret.EncryptSeed
							(seedb,
							derived);

			//0x01 0x43 + flagbyte + addresshash + ownerentropy + encryptedpart1[0...7] + encryptedpart2 which totals 39 bytes
			var bytes =
				new[] { flagByte }
				.Concat(addresshash)
				.Concat(this.OwnerEntropy)
				.Concat(encrypted.Take(8).ToArray())
				.Concat(encrypted.Skip(16).ToArray())
				.ToArray();

			var encryptedSecret = new BitcoinEncryptedSecretEC(bytes, Network);

			return new EncryptedKeyResult(encryptedSecret, generatedaddress, seedb, () =>
			{
				//ECMultiply factorb by G, call the result pointb. The result is 33 bytes.
				var pointb = new Key(factorb).PubKey.ToBytes();
				//The first byte is 0x02 or 0x03. XOR it by (derivedhalf2[31] & 0x01), call the resulting byte pointbprefix.
				var pointbprefix = (byte)(pointb[0] ^ (byte)(derived[63] & 0x01));
				var pointbx = BitcoinEncryptedSecret.EncryptKey(pointb.Skip(1).ToArray(), derived);
				var encryptedpointb = new byte[] { pointbprefix }.Concat(pointbx).ToArray();

				var confirmBytes =
					Network.GetVersionBytes(Base58Type.CONFIRMATION_CODE)
					.Concat(new[] { flagByte })
					.Concat(addresshash)
					.Concat(OwnerEntropy)
					.Concat(encryptedpointb)
					.ToArray();

				return new BitcoinConfirmationCode(Encoders.Base58Check.EncodeData(confirmBytes), Network);
			});
		}