public byte[] Decrypt(byte[] encrypted, byte[] secret)
        {
            using (var aesAlgorithm = new AesManaged())
            {
                var discoveredSalt         = new byte[8];
                var encryptedWithSaltBytes = encrypted;
                var encryptedBytes         = new byte[encryptedWithSaltBytes.Length - OPENSSL_SALT_PREFIX_BYTES.Length - discoveredSalt.Length];

                Buffer.BlockCopy(encryptedWithSaltBytes, OPENSSL_SALT_PREFIX_BYTES.Length, discoveredSalt, 0, discoveredSalt.Length);
                Buffer.BlockCopy(encryptedWithSaltBytes, OPENSSL_SALT_PREFIX_BYTES.Length + discoveredSalt.Length, encryptedBytes, 0, encryptedBytes.Length);

                using (var deriveBytes = new OpenSslCompatDeriveBytes(secret, discoveredSalt, HASH_ALGORITHM, 1))
                {
                    var    bytes = deriveBytes.GetBytes(48);
                    byte[] key   = new byte[32],
                    iv = new byte[16];
                    Buffer.BlockCopy(bytes, 0, key, 0, key.Length);
                    Buffer.BlockCopy(bytes, key.Length, iv, 0, iv.Length);

                    aesAlgorithm.Mode      = CipherMode.CBC;
                    aesAlgorithm.KeySize   = 256;
                    aesAlgorithm.BlockSize = 128;
                    aesAlgorithm.Padding   = PaddingMode.PKCS7;
                    aesAlgorithm.Key       = key;
                    aesAlgorithm.IV        = iv;

                    using (var decryptor = aesAlgorithm.CreateDecryptor())
                    {
                        var plainTextBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);

                        return(plainTextBytes);
                    }
                }
            }
        }
        public byte[] Encrypt(byte[] data, byte[] secret)
        {
            // AesManaged: native .NET, likely preferred for smaller buffers
            // AesCryptoServiceProvider: FIPS compliance, but probably only Windows available?
            // Aes.Create allows framework to choose most appropriate implementation
            using (var aesAlgorithm = Aes.Create())
            {
                var saltBytes = new byte[8];
                m_RngCrypto.GetNonZeroBytes(saltBytes);

                using (var deriveBytes = new OpenSslCompatDeriveBytes(secret, saltBytes, HASH_ALGORITHM, 1))
                {
                    var    bytes = deriveBytes.GetBytes(48);
                    byte[] key   = new byte[32],
                    iv = new byte[16];
                    Buffer.BlockCopy(bytes, 0, key, 0, key.Length);
                    Buffer.BlockCopy(bytes, key.Length, iv, 0, iv.Length);

                    aesAlgorithm.Mode      = CipherMode.CBC;
                    aesAlgorithm.KeySize   = 256;
                    aesAlgorithm.BlockSize = 128;
                    aesAlgorithm.Padding   = PaddingMode.PKCS7;
                    aesAlgorithm.Key       = key;
                    aesAlgorithm.IV        = iv;

                    using (var encryptor = aesAlgorithm.CreateEncryptor())
                    {
                        var encryptedBytes         = encryptor.TransformFinalBlock(data, 0, data.Length);
                        var encryptedWithSaltBytes = new byte[OPENSSL_SALT_PREFIX_BYTES.Length + saltBytes.Length + encryptedBytes.Length];

                        Buffer.BlockCopy(OPENSSL_SALT_PREFIX_BYTES, 0, encryptedWithSaltBytes, 0, OPENSSL_SALT_PREFIX_BYTES.Length);
                        Buffer.BlockCopy(saltBytes, 0, encryptedWithSaltBytes, OPENSSL_SALT_PREFIX_BYTES.Length, saltBytes.Length);
                        Buffer.BlockCopy(encryptedBytes, 0, encryptedWithSaltBytes, OPENSSL_SALT_PREFIX_BYTES.Length + saltBytes.Length, encryptedBytes.Length);

                        return(encryptedWithSaltBytes);
                    }
                }
            }
        }