private static byte[] EncryptKey(byte[] keyhalf1, byte[] keyhalf2, byte[] derived) { var derivedhalf1 = derived.Take(32).ToArray(); var derivedhalf2 = derived.Skip(32).Take(32).ToArray(); var encryptedhalf1 = new byte[16]; var encryptedhalf2 = new byte[16]; var aes = BitcoinEncryptedSecret.CreateAES256(); aes.Key = derivedhalf2; var encrypt = aes.CreateEncryptor(); for (int i = 0; i < 16; i++) { derivedhalf1[i] = (byte)(keyhalf1[i] ^ derivedhalf1[i]); } encrypt.TransformBlock(derivedhalf1, 0, 16, encryptedhalf1, 0); for (int i = 0; i < 16; i++) { derivedhalf1[16 + i] = (byte)(keyhalf2[i] ^ derivedhalf1[16 + i]); } encrypt.TransformBlock(derivedhalf1, 16, 16, encryptedhalf2, 0); return(encryptedhalf1.Concat(encryptedhalf2).ToArray()); }
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)); }
private static byte[] EncryptKey(byte[] keyhalf1, byte[] keyhalf2, byte[] derived) { byte[] derivedhalf1 = derived.SafeSubarray(0, 32); byte[] derivedhalf2 = derived.SafeSubarray(32, 32); var encryptedhalf1 = new byte[16]; var encryptedhalf2 = new byte[16]; #if USEBC || WINDOWS_UWP var aes = BitcoinEncryptedSecret.CreateAES256(true, derivedhalf2); #else Aes aes = CreateAES256(); aes.Key = derivedhalf2; ICryptoTransform encrypt = aes.CreateEncryptor(); #endif for (int i = 0; i < 16; i++) { derivedhalf1[i] = (byte)(keyhalf1[i] ^ derivedhalf1[i]); } #if USEBC || WINDOWS_UWP aes.ProcessBytes(derivedhalf1, 0, 16, encryptedhalf1, 0); aes.ProcessBytes(derivedhalf1, 0, 16, encryptedhalf1, 0); #else encrypt.TransformBlock(derivedhalf1, 0, 16, encryptedhalf1, 0); #endif for (int i = 0; i < 16; i++) { derivedhalf1[16 + i] = (byte)(keyhalf2[i] ^ derivedhalf1[16 + i]); } #if USEBC || WINDOWS_UWP aes.ProcessBytes(derivedhalf1, 16, 16, encryptedhalf2, 0); aes.ProcessBytes(derivedhalf1, 16, 16, encryptedhalf2, 0); #else encrypt.TransformBlock(derivedhalf1, 16, 16, encryptedhalf2, 0); #endif return(encryptedhalf1.Concat(encryptedhalf2).ToArray()); }
public override Key GetKey(string password) { var encrypted = PartialEncrypted.ToArray(); //Derive passfactor using scrypt with ownerentropy and the user's passphrase and use it to recompute passpoint byte[] passfactor = CalculatePassFactor(password, LotSequence, OwnerEntropy); var passpoint = CalculatePassPoint(passfactor); var derived = SCrypt.BitcoinComputeDerivedKey2(passpoint, this.AddressHash.Concat(this.OwnerEntropy).ToArray()); //Decrypt encryptedpart1 to yield the remainder of seedb. var seedb = BitcoinEncryptedSecret.DecryptSeed(encrypted, derived); var factorb = Hashes.Hash256(seedb).ToBytes(); var curve = ECKey.CreateCurve(); //Multiply passfactor by factorb mod N to yield the private key associated with generatedaddress. var keyNum = new BigInteger(1, passfactor).Multiply(new BigInteger(1, factorb)).Mod(curve.N); var keyBytes = keyNum.ToByteArrayUnsigned(); if (keyBytes.Length < 32) { keyBytes = new byte[32 - keyBytes.Length].Concat(keyBytes).ToArray(); } var key = new Key(keyBytes, fCompressedIn: IsCompressed); var generatedaddress = key.PubKey.GetAddress(Network); var addresshash = HashAddress(generatedaddress); if (!Utils.ArrayEqual(addresshash, AddressHash)) { throw new SecurityException("Invalid password"); } return(key); }
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); })); }