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");
int bytesWritten = default(int);
byte[] outputData = default(byte[]);
TryProtectOrUnprotect(userData, optionalEntropy, scope, true, out bytesWritten, out outputData, true, default(Span<byte>));
return outputData;
}
public static byte[] Unprotect(byte[] encryptedData, [System.Runtime.CompilerServices.Nullable(2)] byte[] optionalEntropy, DataProtectionScope scope)
{
CheckPlatformSupport();
if (encryptedData == null)
throw new ArgumentNullException("encryptedData");
int bytesWritten = default(int);
byte[] outputData = default(byte[]);
TryProtectOrUnprotect(encryptedData, optionalEntropy, scope, false, out bytesWritten, out outputData, true, default(Span<byte>));
return outputData;
}
private unsafe static bool TryProtectOrUnprotect(ReadOnlySpan<byte> inputData, ReadOnlySpan<byte> optionalEntropy, DataProtectionScope scope, bool protect, out int bytesWritten, out byte[] outputData, bool allocateArray, Span<byte> outputSpan = default(Span<byte>))
{
fixed (byte* value = &(inputData.IsEmpty ? ((ReadOnlySpan<byte>)s_nonEmpty) : inputData).GetPinnableReference()) {
fixed (byte* value2 = &optionalEntropy.GetPinnableReference()) {
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.IsEmpty)
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);
Span<byte> span = default(Span<byte>);
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;
span = new Span<byte>(pDataOut.pbData.ToPointer(), cbData);
if (!allocateArray) {
if (pDataOut.cbData <= outputSpan.Length) {
span.CopyTo(outputSpan);
bytesWritten = cbData;
outputData = null;
return true;
}
bytesWritten = 0;
outputData = null;
return false;
}
outputData = span.ToArray();
bytesWritten = cbData;
return true;
} finally {
if (pDataOut.pbData != IntPtr.Zero) {
span.Clear();
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();
}
}
}