52 lines
2.3 KiB
C#
52 lines
2.3 KiB
C#
|
|
using System.ComponentModel;
|
||
|
|
using System.Runtime.InteropServices;
|
||
|
|
|
||
|
|
namespace MusicBridge.Agent.Network;
|
||
|
|
|
||
|
|
// Windows DPAPI, scoped to the signed-in user. No UI or machine-wide key.
|
||
|
|
internal static class UserProtection
|
||
|
|
{
|
||
|
|
public static byte[] Protect(byte[] bytes) => Transform(bytes, true);
|
||
|
|
public static byte[] Unprotect(byte[] bytes) => Transform(bytes, false);
|
||
|
|
|
||
|
|
private static byte[] Transform(byte[] bytes, bool protect)
|
||
|
|
{
|
||
|
|
var input = new Blob { Size = bytes.Length, Data = Marshal.AllocHGlobal(bytes.Length) };
|
||
|
|
var output = new Blob();
|
||
|
|
try
|
||
|
|
{
|
||
|
|
Marshal.Copy(bytes, 0, input.Data, bytes.Length);
|
||
|
|
var ok = protect
|
||
|
|
? CryptProtectData(ref input, null, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 1, out output)
|
||
|
|
: CryptUnprotectData(ref input, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 1, out output);
|
||
|
|
if (!ok) throw new Win32Exception(Marshal.GetLastWin32Error(), "Не удалось открыть защищённое хранилище Windows.");
|
||
|
|
var result = new byte[output.Size];
|
||
|
|
Marshal.Copy(output.Data, result, 0, output.Size);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
Marshal.Copy(new byte[input.Size], 0, input.Data, input.Size);
|
||
|
|
Marshal.FreeHGlobal(input.Data);
|
||
|
|
if (output.Data != IntPtr.Zero)
|
||
|
|
{
|
||
|
|
Marshal.Copy(new byte[output.Size], 0, output.Data, output.Size);
|
||
|
|
LocalFree(output.Data);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
[StructLayout(LayoutKind.Sequential)]
|
||
|
|
private struct Blob { public int Size; public IntPtr Data; }
|
||
|
|
[DllImport("crypt32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||
|
|
private static extern bool CryptProtectData(ref Blob input, string? description, IntPtr entropy, IntPtr reserved,
|
||
|
|
IntPtr prompt, uint flags, out Blob output);
|
||
|
|
[DllImport("crypt32.dll", SetLastError = true)]
|
||
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||
|
|
private static extern bool CryptUnprotectData(ref Blob input, IntPtr description, IntPtr entropy, IntPtr reserved,
|
||
|
|
IntPtr prompt, uint flags, out Blob output);
|
||
|
|
[DllImport("kernel32.dll")]
|
||
|
|
private static extern IntPtr LocalFree(IntPtr memory);
|
||
|
|
}
|