예제 #1
0
        public bool CheckBase58Bip38(string bip38, out string message)
        {
            if (!Base58.IsValid(bip38))
            {
                message = "The given BIP-38 string contains invalid base-58 characters.";
                return(false);
            }
            if (!Base58.IsValidWithChecksum(bip38))
            {
                message = "The given BIP-38 string has an invalid checksum.";
                return(false);
            }

            byte[] data = Base58.DecodeWithChecksum(bip38);
            if (data.Length != ConstantsFO.Bip38ByteLen)
            {
                message = "The given BIP-38 string has an invalid byte length.";
                return(false);
            }
            if (data[0] != 1 || (data[1] != 0x42 && data[1] != 0x43))
            {
                message = "The given BIP-38 string has invalid starting bytes.";
                return(false);
            }

            message = "The given BIP-38 string is valid.";
            return(true);
        }
예제 #2
0
        public string CheckPrivateKey(string key)
        {
            if (!Base58.IsValid(key))
            {
                return("The given key contains invalid base-58 characters.");
            }
            if (!Base58.IsValidWithChecksum(key))
            {
                return("The given key has an invalid checksum.");
            }

            byte[] keyBa = Base58.DecodeWithChecksum(key);
            if (keyBa[0] != ConstantsFO.PrivKeyFirstByte)
            {
                return($"Invalid first key byte (actual={keyBa[0]}, expected={ConstantsFO.PrivKeyFirstByte}).");
            }

            if (keyBa.Length == 33)
            {
                if (!IsPrivateKeyInRange(keyBa.SubArray(1)))
                {
                    return("Invalid key integer value (outside of the range defined by secp256k1 curve).");
                }

                return("The given key is a valid uncompressed private key.");
            }
            else if (keyBa.Length == 34)
            {
                if (keyBa[^ 1] != ConstantsFO.PrivKeyCompLastByte)
예제 #3
0
        public string CheckBase58Address(string address)
        {
            if (!Base58.IsValid(address))
            {
                return("The given address contains invalid base-58 characters.");
            }
            if (!Base58.IsValidWithChecksum(address))
            {
                return("The given address has an invalid checksum.");
            }

            byte[] addrBa = Base58.DecodeWithChecksum(address);

            if (addrBa[0] != ConstantsFO.P2pkhAddrFirstByte && addrBa[0] != ConstantsFO.P2shAddrFirstByte)
            {
                return("The given address starts with an invalid byte.");
            }
            if (addrBa.Length != 21)
            {
                return("The given address byte length is invalid.");
            }

            return($"The given address is a valid base-58 encoded address used for " +
                   $"{(addrBa[0] == ConstantsFO.P2pkhAddrFirstByte ? "P2PKH" : "P2SH")} scripts.");
        }
예제 #4
0
        public void LoadFromJson(string json)
        {
            JObject data = JObject.Parse(json);

            if (data["version"].Value <string>() != Version)
            {
                throw new FormatException(String.Format("Invalid wallet version: {0}", data["version"].Value <ulong>()));
            }

            KeyHashes = data["key_hashes"].Value <ulong>();

            IV   = Base58.DecodeWithChecksum(data["encrypted"]["iv"].Value <string>());
            Salt = Base58.DecodeWithChecksum(data["encrypted"]["salt"].Value <string>());

            if (data["watch_addresses"] != null)
            {
                foreach (JToken key in data["watch_addresses"])
                {
                    WatchAddresses.Add(key["addr"].Value <string>(), key["label"] != null ? key["label"].Value <string>() : null);
                }
            }

            if (data["public_addresses"] != null)
            {
                foreach (JToken key in data["public_addresses"])
                {
                    PublicAddresses.Add(key["addr"].Value <string>(), key["label"] != null ? key["label"].Value <string>() : null);
                }
            }

            EncryptedData = Base58.DecodeWithChecksum(data["encrypted"]["data"].Value <string>());
        }
예제 #5
0
파일: BIP0032.cs 프로젝트: supaFool/Denovo
        /// <summary>
        /// Initializes a new instance of <see cref="BIP0032"/> using the given base-58 encoded
        /// extended public or private key string.
        /// <para/>This will set the <see cref="ExtendedKeyType"/> property that can be used by caller to decide
        /// what derivation path and address type to use for child keys.
        /// </summary>
        /// <exception cref="ArgumentNullException"/>
        /// <exception cref="ArgumentOutOfRangeException">If given private key is outside of curve range.</exception>
        /// <exception cref="FormatException"/>
        /// <param name="extendedKey">Base-58 encoded extended key to use</param>
        public BIP0032(string extendedKey)
        {
            if (string.IsNullOrWhiteSpace(extendedKey))
            {
                throw new ArgumentNullException(nameof(extendedKey), "Extended key can not be null or empty.");
            }


            byte[] decoded = Base58.DecodeWithChecksum(extendedKey);
            if (decoded.Length != ExtendedKeyLength)
            {
                throw new FormatException($"Extended key length should be {ExtendedKeyLength} bytes " +
                                          $"but it is {decoded.Length} bytes.");
            }

            int version = decoded[3] | (decoded[2] << 8) | (decoded[1] << 16) | (decoded[0] << 24);

            ExtendedKeyDepth  = decoded[4];
            ParentFingerPrint = decoded.SubArray(5, 4);
            ChildNumber       = decoded.SubArray(9, 4);
            ChainCode         = decoded.SubArray(13, 32);
            byte[] key = decoded.SubArray(45, 33);

            bool isPublic;

            if (Enum.IsDefined(typeof(XType), version))
            {
                ExtendedKeyType = (XType)version;
                isPublic        = IsPublic(ExtendedKeyType);
            }
            else
            {
                ExtendedKeyType = XType.Unknown;
                isPublic        = key[0] != 0;
            }

            if (!isPublic && key[0] != 0)
            {
                throw new FormatException($"The key has an invalid first byte, " +
                                          $"it should be 0 for private keys but it is 0x{key[0]:x2}.");
            }

            if (isPublic)
            {
                PrvKey = null;
                if (!PublicKey.TryRead(key, out PubKey))
                {
                    throw new ArgumentOutOfRangeException("public key", "Invalid public key format.");
                }
            }
            else
            {
                // The following line will check if the key is valid and throws ArgumentOutOfRangeException if not
                PrvKey = new PrivateKey(key.SubArray(1));
                PubKey = PrvKey.ToPublicKey();
            }
        }
예제 #6
0
        public void DecodeWithChecksum_ExceptionTest(string s, string expErrMsg)
        {
            Exception ex = Assert.Throws <FormatException>(() => Base58.DecodeWithChecksum(s));

            Assert.Contains(expErrMsg, ex.Message);

            Assert.False(Base58.TryDecodeWithChecksum(s, out byte[] result));
            Assert.Null(result);
        }
예제 #7
0
//		public static EcKey FromAsn1(byte[] asn1PrivKey) {
//			return new EcKey(ExtractPrivateKeyFromAsn1(asn1PrivKey));
//		}

        public static ECKey FromWalletImportFormat(string wif)
        {
            byte[] decoded = Base58.DecodeWithChecksum(wif);
            if (decoded[0] != 0x80)
            {
                throw new FormatException("Invalid private key");
            }
            return(new ECKey(ArrayHelpers.SubArray(decoded, 1)));
        }
예제 #8
0
        static string GetHashedAddress(Address address)
        {
            byte[] currentHash = Base58.DecodeWithChecksum(address.ID);
            for (int i = 0; i < 1024; i++)
            {
                currentHash = SHA256.Hash(currentHash);
            }

            return(Base58.Encode(currentHash));
        }
예제 #9
0
        public static bool AddressIsValid(string address)
        {
//			byte[] bytes = Base58.DecodeWithChecksum(address);
            Base58.DecodeWithChecksum(address);
            if (!SupportedAddressPrefix(address[0]))
            {
                throw new FormatException(String.Format("'{0}' is an unsupported address prefix", address[0]));
            }

            return(true);
        }
예제 #10
0
        /// <summary>
        /// Decrypts the given base-58 encoded encrypted key using the given password bytes and first 4 bytes of hash of
        /// (un)compressed P2PKH address as <see cref="Scrypt"/> salt.
        /// </summary>
        /// <exception cref="ArgumentNullException"/>
        /// <exception cref="FormatException"/>
        /// <exception cref="ObjectDisposedException"/>
        /// <param name="encrypted">Base-58 encrypted key (it will be normalized using Unicode Normalization Form C (NFC))</param>
        /// <param name="password">Password to use</param>
        /// <param name="isCompressed">Indicates whether to use compressed or uncompressed public key to build P2PKH address</param>
        /// <returns>The private key</returns>
        public PrivateKey Decrypt(string encrypted, byte[] password, out bool isCompressed)
        {
            if (isDisposed)
            {
                throw new ObjectDisposedException(nameof(BIP0038), "Instance was disposed.");
            }
            if (string.IsNullOrWhiteSpace(encrypted))
            {
                throw new ArgumentNullException(nameof(encrypted), "Invalid (null) encrypted key.");
            }
            if (password == null)
            {
                throw new ArgumentNullException(nameof(password), "Password can not be null.");
            }


            byte[] encryptedBytes = Base58.DecodeWithChecksum(encrypted);
            if (encryptedBytes.Length != EncodedLength)
            {
                throw new FormatException("Invalid encrypted bytes length.");
            }

            if (!((Span <byte>)encryptedBytes).Slice(0, 2).SequenceEqual(prefix))
            {
                throw new FormatException("Invalid prefix.");
            }

            isCompressed = IsCompressed(encryptedBytes[2]);

            Span <byte> salt = ((Span <byte>)encryptedBytes).Slice(3, 4);

            byte[] dk = scrypt.GetBytes(password, salt.ToArray(), 64);
            byte[] decryptedResult = new byte[32];

            aes.Key = dk.SubArray(32, 32); // AES key is derivedhalf2
            using ICryptoTransform decryptor = aes.CreateDecryptor();
            decryptor.TransformBlock(encryptedBytes, 7, 16, decryptedResult, 0);
            decryptor.TransformBlock(encryptedBytes, 23, 16, decryptedResult, 16);

            // XOR method will only work on first item's length (32 byte here) so it doesn't matter of dk.Legth is 64
            PrivateKey result = new PrivateKey(XOR(decryptedResult, dk));

            string      address      = Address.GetP2pkh(result.ToPublicKey(), isCompressed, NetworkType.MainNet);
            Span <byte> computedHash = hash.ComputeHashTwice(Encoding.ASCII.GetBytes(address)).SubArray(0, 4);

            if (!computedHash.SequenceEqual(salt))
            {
                throw new FormatException("Wrong password (derived address hash is not the same).");
            }

            return(result);
        }
예제 #11
0
 private byte[] Decode(EncodingNames fromEnc, string input)
 {
     return(fromEnc switch
     {
         EncodingNames.Base16 => Base16.Decode(input),
         EncodingNames.Base43 => Base43.Decode(input),
         EncodingNames.Base58 => Base58.Decode(input),
         EncodingNames.Base58Check => Base58.DecodeWithChecksum(input),
         EncodingNames.Base64 => Convert.FromBase64String(input),
         EncodingNames.UTF8 => Encoding.UTF8.GetBytes(input),
         EncodingNames.Unicode => Encoding.Unicode.GetBytes(input),
         _ => throw new ArgumentException("undefined encoding.")
     });
예제 #12
0
        public AddressType GetAddressType(string address)
        {
            if (string.IsNullOrWhiteSpace(address))
            {
                return(AddressType.Invalid);
            }

            try
            {
                byte[] decoded = Base58.DecodeWithChecksum(address);
                if (decoded.Length == Hash160.HashByteSize + 1)
                {
                    if (decoded[0] == versionByte_P2pkh_MainNet ||
                        decoded[0] == versionByte_P2pkh_TestNet ||
                        decoded[0] == versionByte_P2pkh_RegTest)
                    {
                        return(AddressType.P2PKH);
                    }
                    else if (decoded[0] == versionByte_P2sh_MainNet ||
                             decoded[0] == versionByte_P2sh_TestNet ||
                             decoded[0] == versionByte_P2sh_RegTest)
                    {
                        return(AddressType.P2SH);
                    }
                }

                return(AddressType.Invalid);
            }
            catch (Exception) { }

            try
            {
                byte[] decoded = Bech32.Decode(address, Bech32.Mode.B32, out byte witVer, out string hrp);

                if (witVer == 0 &&
                    hrp == hrp_MainNet || hrp == hrp_TestNet || hrp == hrp_RegTest)
                {
                    if (decoded.Length == Hash160.HashByteSize)
                    {
                        return(AddressType.P2WPKH);
                    }
                    else if (decoded.Length == witHashFunc.BlockByteSize)
                    {
                        return(AddressType.P2WSH);
                    }
                }
            }
            catch (Exception) { }

            return(AddressType.Invalid);
        }
예제 #13
0
        /// <summary>
        /// Initializes a new instance of <see cref="PrivateKey"/> using the given WIF (Base-58 encoded private key
        /// with a checksum)
        /// </summary>
        /// <exception cref="ArgumentException"/>
        /// <exception cref="ArgumentNullException"/>
        /// <exception cref="ArgumentOutOfRangeException"/>
        /// <exception cref="FormatException"/>
        /// <param name="wif">Wallet import format</param>
        /// <param name="netType">
        /// [Default value = <see cref="NetworkType.MainNet"/>]
        /// Network type to check against (affects WIF's starting characters)
        /// </param>
        public PrivateKey(string wif, NetworkType netType = NetworkType.MainNet)
        {
            if (string.IsNullOrWhiteSpace(wif))
            {
                throw new ArgumentNullException(nameof(wif), "Input WIF can not be null or empty.");
            }


            byte[] ba = Base58.DecodeWithChecksum(wif);
            if (ba[0] != GetWifFirstByte(netType))
            {
                throw new FormatException("Invalid first byte.");
            }

            if (ba.Length == KeyByteSize + 1) // Uncompressed
            {
                SetBytes(ba.SubArray(1));
            }
            else if (ba.Length == KeyByteSize + 2) // Compressed
            {
                if (ba[^ 1] != CompressedByte)
예제 #14
0
 public void DecodeWithChecksumTest(string s, byte[] expected)
 {
     byte[] actual = Base58.DecodeWithChecksum(s);
     Assert.Equal(expected, actual);
 }
예제 #15
0
        public void DecodeBitcoinAddress()
        {
            var actualBytes = Base58.DecodeWithChecksum(addressText);

            Assert.AreEqual(BitConverter.ToString(addressBytes), BitConverter.ToString(actualBytes));
        }
예제 #16
0
 public void DecodeBrokenBitcoinAddress()
 {
     Assert.Throws <FormatException>(() => { Base58.DecodeWithChecksum(brokenAddressText); });
 }
예제 #17
0
        public static Transaction Create(List <Output> inpoints, IReadOnlyDictionary <Address, Money> destinations, IReadOnlyDictionary <Address, ECKey> privateKeys, bool allowDust = false)
        {
            if (!allowDust && destinations.Select(d => d.Value).Sum() <= DustValue)
            {
                throw new DustException();
            }

            var tx = new Transaction {
                Version = CurrentVersion
            };

            int outputIndex = 0;

            foreach (KeyValuePair <Address, Money> destination in destinations)
            {
                Script pkScript = Script.Create(Op.Dup, Op.Hash160, ArrayHelpers.SubArray(Base58.DecodeWithChecksum(destination.Key.ID), 1), Op.EqualVerify, Op.CheckSig);
                tx.Outputs.Add(new Output(pkScript, destination.Value, tx, (uint)outputIndex));
                outputIndex++;
            }

            foreach (Output inpoint in inpoints)
            {
                tx.Inputs.Add(new Input(inpoint, (uint)tx.Inputs.Count));
            }

            foreach (Input input in tx.Inputs)
            {
                ECKey  key = privateKeys[input.Outpoint.Recipient];
                byte[] sig = tx.GenerateInputSignature(key, SigHash.All, input.Outpoint.ScriptPubKey, (int)input.Index);
                input.ScriptSig = Script.Create(sig, key.PubKey);
            }

            tx.LockTime = 0U;

            return(tx);
        }