ProtectedData
Provides methods for encrypting and decrypting data. This class cannot be inherited.
using Internal.Cryptography;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace System.Security.Cryptography
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public static class ProtectedData
{
private static readonly byte[] s_nonEmpty = new byte[1];
public static byte[] Protect(byte[] userData, [System.Runtime.CompilerServices.Nullable(2)] byte[] optionalEntropy, DataProtectionScope scope)
{
CheckPlatformSupport();
if (userData == null)
throw new ArgumentNullException("userData");
return ProtectOrUnprotect(userData, optionalEntropy, scope, true);
}
public static byte[] Unprotect(byte[] encryptedData, [System.Runtime.CompilerServices.Nullable(2)] byte[] optionalEntropy, DataProtectionScope scope)
{
CheckPlatformSupport();
if (encryptedData == null)
throw new ArgumentNullException("encryptedData");
return ProtectOrUnprotect(encryptedData, optionalEntropy, scope, false);
}
private unsafe static byte[] ProtectOrUnprotect(byte[] inputData, byte[] optionalEntropy, DataProtectionScope scope, bool protect)
{
byte[] array = (inputData.Length == 0) ? s_nonEmpty : inputData;
fixed (byte* value = array) {
fixed (byte* value2 = optionalEntropy) {
global::Interop.Crypt32.DATA_BLOB pDataIn = new global::Interop.Crypt32.DATA_BLOB((IntPtr)(void*)value, (uint)inputData.Length);
global::Interop.Crypt32.DATA_BLOB pOptionalEntropy = default(global::Interop.Crypt32.DATA_BLOB);
if (optionalEntropy != null)
pOptionalEntropy = new global::Interop.Crypt32.DATA_BLOB((IntPtr)(void*)value2, (uint)optionalEntropy.Length);
global::Interop.Crypt32.CryptProtectDataFlags cryptProtectDataFlags = global::Interop.Crypt32.CryptProtectDataFlags.CRYPTPROTECT_UI_FORBIDDEN;
if (scope == DataProtectionScope.LocalMachine)
cryptProtectDataFlags |= global::Interop.Crypt32.CryptProtectDataFlags.CRYPTPROTECT_LOCAL_MACHINE;
global::Interop.Crypt32.DATA_BLOB pDataOut = default(global::Interop.Crypt32.DATA_BLOB);
try {
if (!(protect ? global::Interop.Crypt32.CryptProtectData(ref pDataIn, null, ref pOptionalEntropy, IntPtr.Zero, IntPtr.Zero, cryptProtectDataFlags, out pDataOut) : global::Interop.Crypt32.CryptUnprotectData(ref pDataIn, IntPtr.Zero, ref pOptionalEntropy, IntPtr.Zero, IntPtr.Zero, cryptProtectDataFlags, out pDataOut))) {
int lastWin32Error = Marshal.GetLastWin32Error();
if (protect && ErrorMayBeCausedByUnloadedProfile(lastWin32Error))
throw new CryptographicException(System.SR.Cryptography_DpApi_ProfileMayNotBeLoaded);
throw lastWin32Error.ToCryptographicException();
}
if (pDataOut.pbData == IntPtr.Zero)
throw new OutOfMemoryException();
int cbData = (int)pDataOut.cbData;
byte[] array2 = new byte[cbData];
Marshal.Copy(pDataOut.pbData, array2, 0, cbData);
return array2;
} finally {
if (pDataOut.pbData != IntPtr.Zero) {
int cbData2 = (int)pDataOut.cbData;
byte* ptr = (byte*)(void*)pDataOut.pbData;
for (int i = 0; i < cbData2; i++) {
ptr[i] = 0;
}
Marshal.FreeHGlobal(pDataOut.pbData);
}
}
}
}
}
private static bool ErrorMayBeCausedByUnloadedProfile(int errorCode)
{
if (errorCode != -2147024894)
return errorCode == 2;
return true;
}
private static void CheckPlatformSupport()
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
throw new PlatformNotSupportedException();
}
}
}