Example #1
0
        private byte[] ProtectWithDpapi(byte *pbSecret, uint cbSecret, bool fLocalMachine = false)
        {
            byte dummy; // provides a valid memory address if the secret or entropy has zero length

            var dataIn = new DATA_BLOB
            {
                cbData = cbSecret,
                pbData = pbSecret != null ? pbSecret : &dummy
            };
            var dataOut = default(DATA_BLOB);

            RuntimeHelpers.PrepareConstrainedRegions();

            try
            {
                var success = Crypt32.CryptProtectData(
                    &dataIn,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    Crypt32.CRYPTPROTECT_UI_FORBIDDEN | (fLocalMachine ? Crypt32.CRYPTPROTECT_LOCAL_MACHINE : 0),
                    out dataOut);
                if (!success)
                {
                    throw new CryptographicException(Marshal.GetLastWin32Error());
                }

                var dataLength = checked ((int)dataOut.cbData);
                var buffer     = new byte[dataLength];
                Marshal.Copy((IntPtr)dataOut.pbData, buffer, 0, dataLength);
                return(buffer);
            }
            finally
            {
                if (dataOut.pbData != null)
                {
                    Marshal.FreeHGlobal((IntPtr)dataOut.pbData);
                }
            }
        }
Example #2
0
        internal static void SaveProtectedData([NotNull] SecureString secureString, [NotNull] string fileName)
        {
            if (string.IsNullOrWhiteSpace(fileName))
            {
                throw new ArgumentException(@"File name is not valid", nameof(fileName));
            }

            // Generate entropy
            var entropy = new byte[20];

            using (var rng = new RNGCryptoServiceProvider())
            {
                rng.GetBytes(entropy);
            }

            IntPtr entropyPtr = Marshal.AllocHGlobal(entropy.Length);

            Marshal.Copy(entropy, 0, entropyPtr, entropy.Length);

            // Get a BSTR from the SecureString
            // NOTE: A BSTR is a Unicode (UTF-16) string, which could contain multiple NULL characters
            IntPtr unmanagedString = Marshal.SecureStringToBSTR(secureString);

            try
            {
                var dataBlob = new DataBlob
                {
                    cbData = secureString.Length * 2,
                    pbData = unmanagedString
                };
                var entropyBlob = new DataBlob
                {
                    cbData = entropy.Length,
                    pbData = entropyPtr
                };
                var outBlob = new DataBlob();

                // Crypt
                bool success = Crypt32.CryptProtectData(ref dataBlob, null, ref entropyBlob, IntPtr.Zero, IntPtr.Zero, CryptProtectFlags.CRYPTPROTECT_LOCAL_MACHINE, ref outBlob);
                if (!success)
                {
                    int error = Marshal.GetLastWin32Error();
                    logger.Error($"CryptProtectData failed with error code {error}!");
                }

                // Save to file
                try
                {
                    var cryptedData = new byte[outBlob.cbData];
                    Marshal.Copy(outBlob.pbData, cryptedData, 0, cryptedData.Length);

                    SaveProtectedDataInternal(cryptedData, entropy, fileName);
                }
                finally
                {
                    Marshal.FreeHGlobal(outBlob.pbData);
                }
            }
            finally
            {
                Marshal.FreeHGlobal(entropyPtr);
                Marshal.ZeroFreeBSTR(unmanagedString);
            }
        }