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