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); }); }