private static byte[] DeriveKey(byte[] key, byte[] salt, int outputSize, int iterationPower, int blocks, int parallelisation)
        {
            var output = new byte[outputSize];

            SCrypt.ComputeKey(key, salt, iterationPower, blocks, parallelisation, null, output);
            return(output);
        }
        /// <summary>
        /// Initialize the intermediate from a passphrase
        /// </summary>
        private void createFromPassphrase(string passphrase, byte[] existingownerentropy, bool entropyContainsLotSequence)
        {
            if (passphrase == null || passphrase == "")
            {
                throw new ArgumentException("Passphrase is required");
            }

            if (existingownerentropy.Length != 8)
            {
                throw new ArgumentException("existingownerentropy must be 8 bytes");
            }

            _ownerentropy            = existingownerentropy;
            this._lotSequencePresent = entropyContainsLotSequence;

            UTF8Encoding utf8 = new UTF8Encoding(false);

            byte[] prefactorA = new byte[32];
            SCrypt.ComputeKey(utf8.GetBytes(passphrase), ownersalt, 16384, 8, 8, 8, prefactorA);

            if (LotSequencePresent)
            {
                derivedBytes = prefactorA;
                byte[] prefactorB = new byte[32 + _ownerentropy.Length];
                Array.Copy(prefactorA, 0, prefactorB, 0, 32);
                Array.Copy(_ownerentropy, 0, prefactorB, 32, _ownerentropy.Length);
                _passfactor = Util.ComputeDoubleSha256(prefactorB);
            }
            else
            {
                _passfactor = prefactorA;
            }

            computeCode();
        }
Exemple #3
0
        /// <summary>
        /// Encryption constructor (non-EC-multiply)
        /// </summary>
        public Bip38KeyPair(KeyPair key, string passphrase)
        {
            if (passphrase == null && passphrase == "")
            {
                throw new ArgumentException("Passphrase is required");
            }

            if (key == null)
            {
                throw new ArgumentException("Passphrase is required");
            }

            this.IsCompressedPoint = key.IsCompressedPoint;
            this._addressType      = key.AddressType;

            UTF8Encoding utf8 = new UTF8Encoding(false);

            byte[] addrhashfull = Global.HashForAddress(utf8.GetBytes(key.AddressBase58));
            byte[] addresshash  = new byte[] { addrhashfull[0], addrhashfull[1], addrhashfull[2], addrhashfull[3] };

            byte[] derivedBytes = new byte[64];
            SCrypt.ComputeKey(utf8.GetBytes(passphrase), addresshash, 16384, 8, 8, 8, derivedBytes);

            var aes = Aes.Create();

            aes.KeySize = 256;
            aes.Mode    = CipherMode.ECB;
            byte[] aeskey = new byte[32];
            Array.Copy(derivedBytes, 32, aeskey, 0, 32);
            aes.Key = aeskey;
            ICryptoTransform encryptor = aes.CreateEncryptor();

            byte[] unencrypted = new byte[32];
            byte[] rv          = new byte[39];
            Array.Copy(key.PrivateKeyBytes, unencrypted, 32);
            for (int x = 0; x < 32; x++)
            {
                unencrypted[x] ^= derivedBytes[x];
            }

            encryptor.TransformBlock(unencrypted, 0, 16, rv, 7);
            encryptor.TransformBlock(unencrypted, 0, 16, rv, 7);
            encryptor.TransformBlock(unencrypted, 16, 16, rv, 23);
            encryptor.TransformBlock(unencrypted, 16, 16, rv, 23);

            // put header
            rv[0] = 0x01;
            rv[1] = 0x42;
            rv[2] = IsCompressedPoint ? (byte)0xe0 : (byte)0xc0;

            byte[] checksum = Global.HashForAddress(utf8.GetBytes(key.AddressBase58));
            rv[3] = checksum[0];
            rv[4] = checksum[1];
            rv[5] = checksum[2];
            rv[6] = checksum[3];

            _encryptedKey = Util.ByteArrayToBase58Check(rv);
            _pubKey       = key.PublicKeyBytes;
            _hash160      = key.Hash160;
        }
        public static byte[] DeriveKeyWithConfig(byte[] key, byte[] salt, int outputSize, byte[] config)
        {
            int iterationPower, blocks, parallelisation;

            ScryptConfigurationUtility.Read(config, out iterationPower, out blocks, out parallelisation);
            var output = new byte[outputSize];

            SCrypt.ComputeKey(key, salt, iterationPower, blocks, parallelisation, null, output);
            return(output);
        }
Exemple #5
0
        public static string TestSCrypt(this Vector vector)
        {
            var derivedBytes = new byte[vector.Len];

            SCrypt.ComputeKey(Encoding.ASCII.GetBytes(vector.Password), Encoding.ASCII.GetBytes(vector.Salt), vector.N, vector.R, vector.P, null, derivedBytes);

            var derived = new string(HexBase16.Encode(derivedBytes));

            return(derived);
        }
Exemple #6
0
        public static string GetHashedString(string secret, string salt)
        {
            var keyBytes   = Encoding.UTF8.GetBytes(secret);
            var saltBytes  = Encoding.UTF8.GetBytes(salt);
            var cost       = 262144;
            var blockSize  = 8;
            var parallel   = 1;
            var maxThreads = (int?)null;
            var output     = new byte[32];

            SCrypt.ComputeKey(keyBytes, saltBytes, cost, blockSize, parallel, maxThreads, output);
            return(Convert.ToBase64String(output));
        }
Exemple #7
0
        /// <summary>
        ///  Generates the password key.
        /// </summary>
        /// <returns>
        ///  The password key.
        /// </returns>
        /// <param name='password'>
        ///  The password.
        /// </param>
        /// <param name='salt'>
        ///  The salt.
        /// </param>
        public byte[] GeneratePasswordKey(string password, byte[] salt)
        {
            var key = new byte[32];

            SCrypt.ComputeKey(
                Encoding.UTF8.GetBytes(password),
                salt,
                32,
                1024,
                1,
                null,
                key);

            return(key);
        }
        /// <summary>
        /// Calculates the master key.
        /// </summary>
        /// <returns>The master key.</returns>
        /// <param name="userName">User name.</param>
        /// <param name="masterPassword">Master password.</param>
        public static byte[] CalcMasterKey(string userName, string masterPassword)
        {
            byte[] result = new byte[64];

            var masterBytes = UTF8Encoding.UTF8.GetBytes(masterPassword);
            var salt        = Combine(UTF8Encoding.UTF8.GetBytes("com.lyndir.masterpassword"), GetBytes(userName.Length), UTF8Encoding.UTF8.GetBytes(userName));

            SCrypt.ComputeKey(
                masterBytes,
                salt,
                32768,
                8,
                2,
                64,
                result
                );

            return(result);
        }
        private void btnConfirm_Click(object sender, EventArgs e)
        {
            lblAddressHeader.Visible = false;
            lblAddressItself.Visible = false;
            lblResult.Visible        = false;


            // check for null entry
            if (txtPassphrase.Text == "")
            {
                MessageBox.Show("Passphrase is required.", "Passphrase required", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            if (txtConfCode.Text == "")
            {
                MessageBox.Show("Confirmation code is required.", "Confirmation code required", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            // Parse confirmation code.
            byte[] confbytes = Util.Base58CheckToByteArray(txtConfCode.Text.Trim());
            if (confbytes == null)
            {
                // is it even close?
                if (txtConfCode.Text.StartsWith("cfrm38"))
                {
                    MessageBox.Show("This is not a valid confirmation code.  It has the right prefix, but " +
                                    "doesn't contain valid confirmation data.  Possible typo or incomplete?",
                                    "Invalid confirmation code", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }

                MessageBox.Show("This is not a valid confirmation code.", "Invalid confirmation code", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            if (confbytes.Length != 51 || confbytes[0] != 0x64 || confbytes[1] != 0x3B || confbytes[2] != 0xF6 ||
                confbytes[3] != 0xA8 || confbytes[4] != 0x9A || confbytes[18] < 0x02 || confbytes[18] > 0x03)
            {
                // Unrecognized Base58 object.  Do we know what this is?  Tell the user.
                object result = StringInterpreter.Interpret(txtConfCode.Text.Trim());
                if (result != null)
                {
                    // did we actually get an encrypted private key?  if so, just try to decrypt it.
                    if (result is PassphraseKeyPair)
                    {
                        PassphraseKeyPair ppkp = result as PassphraseKeyPair;
                        if (ppkp.DecryptWithPassphrase(txtPassphrase.Text))
                        {
                            confirmIsValid(ppkp.GetAddress().AddressBase58);
                            MessageBox.Show("What you provided contains a private key, not just a confirmation. " +
                                            "Confirmation is successful, and with this correct passphrase, " +
                                            "you are also able to spend the funds from the address.", "This is actually a private key",
                                            MessageBoxButtons.OK, MessageBoxIcon.Information);
                            return;
                        }
                        else
                        {
                            MessageBox.Show("This is not a valid confirmation code.  It looks like an " +
                                            "encrypted private key.  Decryption was attempted but the passphrase couldn't decrypt it", "Invalid confirmation code", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                            return;
                        }
                    }

                    string objectKind = result.GetType().Name;
                    if (objectKind == "AddressBase")
                    {
                        objectKind = "an Address";
                    }
                    else
                    {
                        objectKind = "a " + objectKind;
                    }

                    MessageBox.Show("This is not a valid confirmation code.  Instead, it looks like " + objectKind +
                                    ".  Perhaps you entered the wrong thing?  Confirmation codes " +
                                    "start with \"cfrm\".", "Invalid confirmation code", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }

                MessageBox.Show("This is not a valid confirmation code.", "Invalid confirmation code", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            // extract ownersalt and get an intermediate
            byte[] ownersalt = new byte[8];
            Array.Copy(confbytes, 10, ownersalt, 0, 8);

            bool includeHashStep           = (confbytes[5] & 0x04) == 0x04;
            Bip38Intermediate intermediate = new Bip38Intermediate(txtPassphrase.Text, ownersalt, includeHashStep);

            // derive the 64 bytes we need
            // get ECPoint from passpoint
            PublicKey pk = new PublicKey(intermediate.passpoint);

            byte[] addresshashplusownersalt = new byte[12];
            Array.Copy(confbytes, 6, addresshashplusownersalt, 0, 4);
            Array.Copy(intermediate.ownerentropy, 0, addresshashplusownersalt, 4, 8);

            // derive encryption key material
            byte[] derived = new byte[64];
            SCrypt.ComputeKey(intermediate.passpoint, addresshashplusownersalt, 1024, 1, 1, 1, derived);

            byte[] derivedhalf2 = new byte[32];
            Array.Copy(derived, 32, derivedhalf2, 0, 32);

            byte[] unencryptedpubkey = new byte[33];
            // recover the 0x02 or 0x03 prefix
            unencryptedpubkey[0] = (byte)(confbytes[18] ^ (derived[63] & 0x01));

            // decrypt
            var aes = Aes.Create();

            aes.KeySize = 256;
            aes.Mode    = CipherMode.ECB;
            aes.Key     = derivedhalf2;
            ICryptoTransform decryptor = aes.CreateDecryptor();

            decryptor.TransformBlock(confbytes, 19, 16, unencryptedpubkey, 1);
            decryptor.TransformBlock(confbytes, 19, 16, unencryptedpubkey, 1);
            decryptor.TransformBlock(confbytes, 19 + 16, 16, unencryptedpubkey, 17);
            decryptor.TransformBlock(confbytes, 19 + 16, 16, unencryptedpubkey, 17);

            // xor out the padding
            for (int i = 0; i < 32; i++)
            {
                unencryptedpubkey[i + 1] ^= derived[i];
            }

            // reconstitute the ECPoint
            var     ps = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
            ECPoint point;

            try {
                point = ps.Curve.DecodePoint(unencryptedpubkey);

                // multiply passfactor.  Result is going to be compressed.
                ECPoint pubpoint = point.Multiply(new BigInteger(1, intermediate.passfactor));

                // Do we want it uncompressed?  then we will have to uncompress it.
                byte flagbyte = confbytes[5];
                if ((flagbyte & 0x20) == 0x00)
                {
                    pubpoint = ps.Curve.CreatePoint(pubpoint.X.ToBigInteger(), pubpoint.Y.ToBigInteger(), false);
                }

                // Convert to bitcoin address and check address hash.
                PublicKey generatedaddress = new PublicKey(pubpoint);

                // get addresshash
                UTF8Encoding utf8   = new UTF8Encoding(false);
                Sha256Digest sha256 = new Sha256Digest();
                byte[]       generatedaddressbytes = utf8.GetBytes(generatedaddress.AddressBase58);
                sha256.BlockUpdate(generatedaddressbytes, 0, generatedaddressbytes.Length);
                byte[] addresshashfull = new byte[32];
                sha256.DoFinal(addresshashfull, 0);
                sha256.BlockUpdate(addresshashfull, 0, 32);
                sha256.DoFinal(addresshashfull, 0);

                for (int i = 0; i < 4; i++)
                {
                    if (addresshashfull[i] != confbytes[i + 6])
                    {
                        MessageBox.Show("This passphrase is wrong or does not belong to this confirmation code.", "Invalid passphrase", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        return;
                    }
                }

                confirmIsValid(generatedaddress.AddressBase58);
            } catch {
                // Might throw an exception - not every 256-bit integer is a valid X coordinate
                MessageBox.Show("This passphrase is wrong or does not belong to this confirmation code.", "Invalid passphrase", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }
        }
Exemple #10
0
        public Exception DecryptWithPassphrase(string passphrase)
        {
            // check for null entry
            if (passphrase == null || passphrase == "")
            {
                return(new ArgumentException("Passphrase is required"));
            }

            Bip38Intermediate intermediate = new Bip38Intermediate(passphrase, _ownerentropy, LotSequencePresent);

            // derive the 64 bytes we need
            // get ECPoint from passpoint
            PublicKey pk = new PublicKey(intermediate.passpoint);

            byte[] addresshashplusownerentropy = Util.ConcatenateByteArrays(_addressHash, intermediate.ownerentropy);

            // derive encryption key material
            byte[] derived = new byte[64];
            SCrypt.ComputeKey(intermediate.passpoint, addresshashplusownerentropy, 1024, 1, 1, 1, derived);

            byte[] derivedhalf2 = new byte[32];
            Array.Copy(derived, 32, derivedhalf2, 0, 32);

            byte[] unencryptedpubkey = new byte[33];
            // recover the 0x02 or 0x03 prefix
            unencryptedpubkey[0] = (byte)(_encryptedpointb[0] ^ (derived[63] & 0x01));

            // decrypt
            var aes = Aes.Create();

            aes.KeySize = 256;
            aes.Mode    = CipherMode.ECB;
            aes.Key     = derivedhalf2;
            ICryptoTransform decryptor = aes.CreateDecryptor();

            decryptor.TransformBlock(_encryptedpointb, 1, 16, unencryptedpubkey, 1);
            decryptor.TransformBlock(_encryptedpointb, 1, 16, unencryptedpubkey, 1);
            decryptor.TransformBlock(_encryptedpointb, 1 + 16, 16, unencryptedpubkey, 17);
            decryptor.TransformBlock(_encryptedpointb, 1 + 16, 16, unencryptedpubkey, 17);

            // xor out the padding
            for (int i = 0; i < 32; i++)
            {
                unencryptedpubkey[i + 1] ^= derived[i];
            }

            // reconstitute the ECPoint
            var     ps = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
            ECPoint point;

            try {
                point = ps.Curve.DecodePoint(unencryptedpubkey);

                // multiply passfactor.  Result is going to be compressed.
                ECPoint pubpoint = point.Multiply(new BigInteger(1, intermediate.passfactor));

                // Do we want it uncompressed?  then we will have to uncompress it.
                if (IsCompressedPoint == false)
                {
                    pubpoint = ps.Curve.CreatePoint(pubpoint.X.ToBigInteger(), pubpoint.Y.ToBigInteger(), false);
                }

                // Convert to bitcoin address and check address hash.
                PublicKey generatedaddress = new PublicKey(pubpoint);

                // get addresshash
                UTF8Encoding utf8 = new UTF8Encoding(false);
                byte[]       generatedaddressbytes = utf8.GetBytes(generatedaddress.AddressBase58);
                byte[]       addresshashfull       = Global.HashForAddress(generatedaddressbytes);

                for (int i = 0; i < 4; i++)
                {
                    if (addresshashfull[i] != _addressHash[i])
                    {
                        return(new ArgumentException("This passphrase is wrong or does not belong to this confirmation code."));
                    }
                }

                this.PublicKey = generatedaddress;
            } catch {
                return(new ArgumentException("This passphrase is wrong or does not belong to this confirmation code."));
            }
            return(null);
        }
Exemple #11
0
        public override bool DecryptWithPassphrase(string passphrase)
        {
            if (passphrase == null)
            {
                return(false);
            }

            byte[]  hex     = Util.Base58CheckToByteArray(_encryptedKey);
            KeyPair tempkey = null;

            if (hex.Length == 39 && hex[0] == 1 && hex[1] == 0x42)
            {
                UTF8Encoding utf8        = new UTF8Encoding(false);
                byte[]       addresshash = new byte[] { hex[3], hex[4], hex[5], hex[6] };

                byte[] derivedBytes = new byte[64];
                SCrypt.ComputeKey(utf8.GetBytes(passphrase), addresshash, 16384, 8, 8, 8, derivedBytes);

                var aes = Aes.Create();
                aes.KeySize = 256;
                aes.Mode    = CipherMode.ECB;
                byte[] aeskey = new byte[32];
                Array.Copy(derivedBytes, 32, aeskey, 0, 32);
                aes.Key = aeskey;
                ICryptoTransform decryptor = aes.CreateDecryptor();

                byte[] decrypted = new byte[32];
                decryptor.TransformBlock(hex, 7, 16, decrypted, 0);
                decryptor.TransformBlock(hex, 7, 16, decrypted, 0);
                decryptor.TransformBlock(hex, 23, 16, decrypted, 16);
                decryptor.TransformBlock(hex, 23, 16, decrypted, 16);
                for (int x = 0; x < 32; x++)
                {
                    decrypted[x] ^= derivedBytes[x];
                }

                tempkey = new KeyPair(decrypted, compressed: IsCompressedPoint);

                byte[] addrtext = utf8.GetBytes(tempkey.AddressBase58);
                byte[] addrhash = Global.HashForAddress(addrtext);
                if (addrhash[0] != hex[3] || addrhash[1] != hex[4] || addrhash[2] != hex[5] || addrhash[3] != hex[6])
                {
                    return(false);
                }
                _privKey = tempkey.PrivateKeyBytes;
                _pubKey  = tempkey.PublicKeyBytes;
                _hash160 = tempkey.Hash160;
                return(true);
            }
            else if (hex.Length == 39 && hex[0] == 1 && hex[1] == 0x43)
            {
                // produce the intermediate from the passphrase


                // get ownersalt and encryptedpart2 since they are in the record
                byte[] ownersalt = new byte[8];
                Array.Copy(hex, 7, ownersalt, 0, 8);
                bool includeHashStep           = (hex[2] & 4) == 4;
                Bip38Intermediate intermediate = new Bip38Intermediate(passphrase, ownersalt, includeHashStep);
                this.LotNumber      = intermediate.LotNumber;
                this.SequenceNumber = intermediate.SequenceNumber;

                tempkey = decryptUsingIntermediate(intermediate, hex);
                if (verifyAddressHash(tempkey.AddressBase58, hex) == false)
                {
                    return(false);
                }
            }
            _privKey = tempkey.PrivateKeyBytes;
            _pubKey  = tempkey.PublicKeyBytes;
            _hash160 = tempkey.Hash160;
            return(true);
        }
Exemple #12
0
        /// <summary>
        /// Encryption constructor to create a new random key from an intermediate
        /// </summary>
        public Bip38KeyPair(Bip38Intermediate intermediate, bool retainPrivateKeyWhenPossible = false)
        {
            // generate seedb
            byte[]       seedb = new byte[24];
            SecureRandom sr    = new SecureRandom();

            sr.NextBytes(seedb);

            // get factorb as sha256(sha256(seedb))
            Sha256Digest sha256 = new Sha256Digest();

            sha256.BlockUpdate(seedb, 0, 24);
            factorb = new byte[32];
            sha256.DoFinal(factorb, 0);
            sha256.BlockUpdate(factorb, 0, 32);
            sha256.DoFinal(factorb, 0);

            // get ECPoint from passpoint
            PublicKey pk = new PublicKey(intermediate.passpoint);

            ECPoint generatedpoint = pk.GetECPoint().Multiply(new BigInteger(1, factorb));

            byte[]    generatedpointbytes = generatedpoint.GetEncoded();
            PublicKey generatedaddress    = new PublicKey(generatedpointbytes);

            // get addresshash
            UTF8Encoding utf8 = new UTF8Encoding(false);

            byte[] generatedaddressbytes = utf8.GetBytes(generatedaddress.AddressBase58);
            byte[] addresshashfull       = Global.HashForAddress(generatedaddressbytes);

            byte[] addresshashplusownerentropy = new byte[12];
            Array.Copy(addresshashfull, 0, addresshashplusownerentropy, 0, 4);
            Array.Copy(intermediate.ownerentropy, 0, addresshashplusownerentropy, 4, 8);

            // derive encryption key material
            derived = new byte[64];
            SCrypt.ComputeKey(intermediate.passpoint, addresshashplusownerentropy, 1024, 1, 1, 1, derived);

            byte[] derivedhalf2 = new byte[32];
            Array.Copy(derived, 32, derivedhalf2, 0, 32);

            byte[] unencryptedpart1 = new byte[16];
            for (int i = 0; i < 16; i++)
            {
                unencryptedpart1[i] = (byte)(seedb[i] ^ derived[i]);
            }
            byte[] encryptedpart1 = new byte[16];

            // encrypt it
            var aes = Aes.Create();

            aes.KeySize = 256;
            aes.Mode    = CipherMode.ECB;
            aes.Key     = derivedhalf2;
            ICryptoTransform encryptor = aes.CreateEncryptor();

            encryptor.TransformBlock(unencryptedpart1, 0, 16, encryptedpart1, 0);
            encryptor.TransformBlock(unencryptedpart1, 0, 16, encryptedpart1, 0);

            byte[] unencryptedpart2 = new byte[16];
            for (int i = 0; i < 8; i++)
            {
                unencryptedpart2[i] = (byte)(encryptedpart1[i + 8] ^ derived[i + 16]);
            }
            for (int i = 0; i < 8; i++)
            {
                unencryptedpart2[i + 8] = (byte)(seedb[i + 16] ^ derived[i + 24]);
            }

            byte[] encryptedpart2 = new byte[16];
            encryptor.TransformBlock(unencryptedpart2, 0, 16, encryptedpart2, 0);
            encryptor.TransformBlock(unencryptedpart2, 0, 16, encryptedpart2, 0);

            byte[] result = new byte[39];
            result[0] = 0x01;
            result[1] = 0x43;
            result[2] = generatedaddress.IsCompressedPoint ? (byte)0x20 : (byte)0x00;
            if (intermediate.LotSequencePresent)
            {
                result[2] |= 0x04;
            }

            Array.Copy(addresshashfull, 0, result, 3, 4);
            Array.Copy(intermediate.ownerentropy, 0, result, 7, 8);
            Array.Copy(encryptedpart1, 0, result, 15, 8);
            Array.Copy(encryptedpart2, 0, result, 23, 16);

            _encryptedKey = Util.ByteArrayToBase58Check(result);
            _pubKey       = generatedaddress.PublicKeyBytes;
            _hash160      = generatedaddress.Hash160;

            var ps = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");

            if (retainPrivateKeyWhenPossible && intermediate.passfactor != null)
            {
                BigInteger privatekey = new BigInteger(1, intermediate.passfactor).Multiply(new BigInteger(1, factorb)).Mod(ps.N);
                _privKey = new KeyPair(privatekey).PrivateKeyBytes;
            }

            // create the confirmation code
            confirmationCodeInfo = new byte[51];
            // constant provides for prefix "cfrm38"
            confirmationCodeInfo[0] = 0x64;
            confirmationCodeInfo[1] = 0x3B;
            confirmationCodeInfo[2] = 0xF6;
            confirmationCodeInfo[3] = 0xA8;
            confirmationCodeInfo[4] = 0x9A;
            // fields for flagbyte, addresshash, and ownerentropy all copy verbatim
            Array.Copy(result, 2, confirmationCodeInfo, 5, 1 + 4 + 8);
        }
Exemple #13
0
        private KeyPair decryptUsingIntermediate(Bip38Intermediate intermediate, byte[] hex)
        {
            if (intermediate.passfactor == null)
            {
                throw new ArgumentException("This is an encryption-only intermediate code because it was not created from a passphrase.  An intermediate must have been created from passphrase to be used for decryption");
            }

            byte[] encryptedpart2 = new byte[16];
            Array.Copy(hex, 23, encryptedpart2, 0, 16);

            // get the first part of encryptedpart1 (the rest is encrypted within encryptedpart2)
            byte[] encryptedpart1 = new byte[16];
            Array.Copy(hex, 15, encryptedpart1, 0, 8);

            // derive decryption key
            byte[] addresshashplusownerentropy = new byte[12];
            Array.Copy(hex, 3, addresshashplusownerentropy, 0, 4);
            Array.Copy(intermediate.ownerentropy, 0, addresshashplusownerentropy, 4, 8);
            byte[] derived = new byte[64];
            SCrypt.ComputeKey(intermediate.passpoint, addresshashplusownerentropy, 1024, 1, 1, 1, derived);
            byte[] derivedhalf2 = new byte[32];
            Array.Copy(derived, 32, derivedhalf2, 0, 32);

            // decrypt encrypted payload
            var aes = Aes.Create();

            aes.KeySize = 256;
            aes.Mode    = CipherMode.ECB;
            aes.Key     = derivedhalf2;
            ICryptoTransform decryptor = aes.CreateDecryptor();

            byte[] unencryptedpart2 = new byte[16];
            decryptor.TransformBlock(encryptedpart2, 0, 16, unencryptedpart2, 0);
            decryptor.TransformBlock(encryptedpart2, 0, 16, unencryptedpart2, 0);
            for (int i = 0; i < 16; i++)
            {
                unencryptedpart2[i] ^= derived[i + 16];
            }

            // take the decrypted part and recover encrypted part 1
            Array.Copy(unencryptedpart2, 0, encryptedpart1, 8, 8);

            // decrypt part 1
            byte[] unencryptedpart1 = new byte[16];
            decryptor.TransformBlock(encryptedpart1, 0, 16, unencryptedpart1, 0);
            decryptor.TransformBlock(encryptedpart1, 0, 16, unencryptedpart1, 0);
            for (int i = 0; i < 16; i++)
            {
                unencryptedpart1[i] ^= derived[i];
            }

            // recover seedb
            byte[] seedb = new byte[24];
            Array.Copy(unencryptedpart1, 0, seedb, 0, 16);
            Array.Copy(unencryptedpart2, 8, seedb, 16, 8);

            // turn seedb into factorb
            Sha256Digest sha256 = new Sha256Digest();

            sha256.BlockUpdate(seedb, 0, 24);
            byte[] factorb = new byte[32];
            sha256.DoFinal(factorb, 0);
            sha256.BlockUpdate(factorb, 0, 32);
            sha256.DoFinal(factorb, 0);

            // get private key
            var        ps         = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
            BigInteger privatekey = new BigInteger(1, intermediate.passfactor).Multiply(new BigInteger(1, factorb)).Mod(ps.N);

            // use private key
            return(new KeyPair(privatekey, this.IsCompressedPoint, this._addressType));
        }