/// <summary>
        /// Encrypts data according to a specified protection type.
        /// </summary>
        /// <param name="type">One of the <see cref="ProtectionType"/> values.</param>
        /// <param name="data">The data to encrypt.</param>
        /// <param name="offset">The zero-based position in the <i>data</i> parameter at which to begin encrypting.</param>
        /// <param name="size">The number of bytes to encrypt.</param>
        /// <param name="entropy">Additional entropy to use during the encryption process. This parameter can be set to null.</param>
        /// <exception cref="ArgumentNullException"><i>data</i> is a null reference (<b>Nothing</b> in Visual Basic).</exception>
        /// <exception cref="ArgumentException">The specified <i>offset</i> or <i>size</i> exceeds the size of buffer.</exception>
        /// <exception cref="CryptographicException">An error occurs during the encryption process. Under some circumstances, Microsoft cryptographic service providers may not allow encryption when used in France. This may occur on down-level platforms such as Windows 98 and Windows NT 4.0, depending on the system's configuration and the version of the CSPs.</exception>
        /// <returns>An array of encrypted bytes.</returns>
        /// <remarks>The number of the returned bytes will be larger than the number of input bytes.</remarks>
        public byte[] ProtectData(ProtectionType type, byte[] data, int offset, int size, byte[] entropy)
        {
            if (m_Disposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }
            if (data == null)
            {
                throw new ArgumentNullException();
            }
            if (offset < 0 || offset + size > data.Length || !Enum.IsDefined(typeof(ProtectionType), type))
            {
                throw new ArgumentException();
            }
            DataBlob input  = new DataBlob();
            DataBlob entr   = new DataBlob();
            DataBlob output = new DataBlob();

            try {
                // initialize input structure
                input.cbData = size;
                input.pbData = Marshal.AllocHGlobal(size);
                Marshal.Copy(data, offset, input.pbData, size);
                // initialize entropy structure
                if (entropy == null)
                {
                    entr.cbData = 0;
                    entr.pbData = IntPtr.Zero;
                }
                else
                {
                    entr.cbData = entropy.Length;
                    entr.pbData = Marshal.AllocHGlobal(entr.cbData);
                    Marshal.Copy(entropy, 0, entr.pbData, entr.cbData);
                }
                // initialize output structure
                output.cbData = 0;
                output.pbData = IntPtr.Zero;
                // call the function and check for errors
                int flags = 0;
                if (type == ProtectionType.LocalMachine)
                {
                    flags = flags | SecurityConstants.CRYPTPROTECT_LOCAL_MACHINE;
                }
                if (!Environment.UserInteractive)
                {
                    flags = flags | SecurityConstants.CRYPTPROTECT_UI_FORBIDDEN;
                }
                if (SspiProvider.CryptProtectData(ref input, "", ref entr, IntPtr.Zero, IntPtr.Zero, flags, ref output) == 0 || output.pbData == IntPtr.Zero)
                {
                    throw new CryptographicException("The data could not be protected.");
                }
                byte[] ret = new byte[output.cbData];
                Marshal.Copy(output.pbData, ret, 0, output.cbData);
                return(ret);
            } finally {
                if (input.pbData != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(input.pbData);
                }
                if (entr.pbData != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(entr.pbData);
                }
                if (output.pbData != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(output.pbData);
                }
            }
        }