internal static byte[] DecryptDataAsBytes(byte[] encryptedData, string privateKeyPem)
        {
            using (var encryptedDataStream = new MemoryStream(encryptedData))
                using (var encryptedDataWithoutKeyPair = new MemoryStream())
                {
                    var encryptedKeyLengthBytes = new byte[4];
                    var bytesRead = encryptedDataStream.Read(encryptedKeyLengthBytes, 0, 4);
                    if (bytesRead == -1)
                    {
                        throw new Exception("Unexpected end of encrypted data (expected encrypted key size)");
                    }
                    var encryptedKeyLength = BitConverter.ToInt32(encryptedKeyLengthBytes, 0);

                    var encryptedKey = new byte[encryptedKeyLength];
                    bytesRead = encryptedDataStream.Read(encryptedKey, 0, encryptedKeyLength);
                    if (bytesRead != encryptedKeyLength)
                    {
                        throw new Exception("Unexpected end of encrypted data (expected encrypted key)");
                    }

                    encryptedDataStream.CopyTo(encryptedDataWithoutKeyPair);

                    var encryptionKey = AsymmetricCryptoUtil.DecryptDataWithPrivateKey(encryptedKey, privateKeyPem);
                    return(EncryptedData.DecryptDataAsBytes(encryptionKey, encryptedDataWithoutKeyPair.ToArray()));
                }
        }
        public static byte[] DecryptDataAsBytes(string serializedEncryptedData, string password)
        {
            var encryptedData = Convert.FromBase64String(serializedEncryptedData);

            using (var encryptedDataStream = new MemoryStream(encryptedData))
            {
                var hmacNumBytes = new byte[4];
                var bytesRead    = encryptedDataStream.Read(hmacNumBytes, 0, 4);
                if (bytesRead != 4)
                {
                    throw new Exception("Unexpected end of encrypted data (expected HMAC length)");
                }
                var hmacLength = BitConverter.ToInt32(hmacNumBytes, 0);

                var givenMac = new byte[hmacLength];
                bytesRead = encryptedDataStream.Read(givenMac, 0, hmacLength);
                if (bytesRead != hmacLength)
                {
                    throw new Exception("Unexpected end of encrypted data (expected HMAC)");
                }

                // Can't think of a more elegant way to read the remaining bytes of the stream.
                byte[] ciphertext;
                using (var encryptedDataWithoutPassword = new MemoryStream())
                {
                    encryptedDataStream.CopyTo(encryptedDataWithoutPassword);
                    ciphertext = encryptedDataWithoutPassword.ToArray();
                }

                var encryptionKey = PasswordHash.CreateHash(password, 1, "");
                var authKey       = Convert.FromBase64String(PasswordHash.CreateHash(password, 2, ""));

                var hmac          = new HMac(new Sha256Digest());
                var calculatedMac = new byte[hmac.GetMacSize()];
                hmac.Init(new KeyParameter(authKey));
                hmac.BlockUpdate(ciphertext, 0, ciphertext.Length);
                hmac.DoFinal(calculatedMac, 0);

                if (!Arrays.ConstantTimeAreEqual(givenMac, calculatedMac))
                {
                    throw new Exception("Encrypted data macs do not match");
                }

                return(EncryptedData.DecryptDataAsBytes(Convert.FromBase64String(encryptionKey), ciphertext));
            }
        }