internal bool VerifyType(string address, PubkeyScriptType scrType, out byte[] result)
        {
            result = null;
            try
            {
                switch (scrType)
                {
                case PubkeyScriptType.P2PKH:
                    byte[] decoded = b58Encoder.DecodeWithCheckSum(address);
                    if (decoded[0] != versionByte_P2pkh_MainNet &&
                        decoded[0] != versionByte_P2pkh_TestNet &&
                        decoded[0] != versionByte_P2pkh_RegTest &&
                        decoded.Length != hashFunc.HashByteSize)
                    {
                        return(false);
                    }
                    result = decoded.SubArray(1);
                    return(true);

                case PubkeyScriptType.P2SH:
                    decoded = b58Encoder.DecodeWithCheckSum(address);
                    if (decoded[0] != versionByte_P2sh_MainNet &&
                        decoded[0] != versionByte_P2sh_TestNet &&
                        decoded[0] != versionByte_P2sh_RegTest &&
                        decoded.Length != hashFunc.HashByteSize)
                    {
                        return(false);
                    }
                    result = decoded.SubArray(1);
                    return(true);

                case PubkeyScriptType.P2WPKH:
                    decoded = b32Encoder.Decode(address, out byte witVer, out string hrp);
                    if (witVer != 0 ||
                        decoded.Length != hashFunc.HashByteSize)
                    {
                        return(false);
                    }
                    result = decoded;
                    return(true);

                case PubkeyScriptType.P2WSH:
                    decoded = b32Encoder.Decode(address, out witVer, out hrp);
                    if (witVer != 0 ||
                        decoded.Length != witHashFunc.HashByteSize)
                    {
                        return(false);
                    }
                    result = decoded;
                    return(true);

                default:
                    return(false);
                }
            }
            catch (Exception)
            {
                return(false);
            }
        }
Exemple #2
0
        public string CheckPrivateKey(string key)
        {
            if (!b58End.HasValidChars(key))
            {
                return("The given key contains invalid base-58 characters.");
            }
            if (!b58End.HasValidCheckSum(key))
            {
                return("The given key has an invalid checksum.");
            }

            byte[] keyBa = b58End.DecodeWithCheckSum(key);
            if (keyBa[0] != Constants.PrivKeyFirstByte)
            {
                return($"Invalid first key byte (actual={keyBa[0]}, expected={Constants.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] != Constants.PrivKeyCompLastByte)
Exemple #3
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 = b58enc.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      = addressMaker.GetP2pkh(result.ToPublicKey(), isCompressed, NetworkType.MainNet);
            Span <byte> computedHash = hash.ComputeHash(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);
        }
Exemple #4
0
        public AddressType GetAddressType(string address)
        {
            if (string.IsNullOrWhiteSpace(address))
            {
                return(AddressType.Invalid);
            }

            try
            {
                byte[] decoded = b58Encoder.DecodeWithCheckSum(address);
                if (decoded.Length == hashFunc.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 = b32Encoder.Decode(address, out byte witVer, out string hrp);

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

            return(AddressType.Invalid);
        }
Exemple #5
0
        public string CheckBase58Bip38(string bip38)
        {
            if (!b58Enc.HasValidChars(bip38))
            {
                return("The given BIP-38 string contains invalid base-58 characters.");
            }
            if (!b58Enc.IsValid(bip38))
            {
                return("The given BIP-38 string has an invalid checksum.");
            }

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

            return("The given BIP-38 string is valid.");
        }
Exemple #6
0
 public void DecodeWithCheckSumTest(string s, byte[] expected)
 {
     byte[] actual = encoder.DecodeWithCheckSum(s);
     Assert.Equal(expected, actual);
 }