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
{
public static class ProtectedData
{
private static readonly byte[] s_nonEmpty = new byte[1];
[NullableContext(1)]
public static byte[] Protect(byte[] userData, [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;
}
[return: Nullable(1)]
public static byte[] Protect(ReadOnlySpan<byte> userData, DataProtectionScope scope, ReadOnlySpan<byte> optionalEntropy = default(ReadOnlySpan<byte>))
{
CheckPlatformSupport();
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 bool TryProtect(ReadOnlySpan<byte> userData, DataProtectionScope scope, Span<byte> destination, out int bytesWritten, ReadOnlySpan<byte> optionalEntropy = default(ReadOnlySpan<byte>))
{
CheckPlatformSupport();
byte[] outputData;
return TryProtectOrUnprotect(userData, optionalEntropy, scope, true, out bytesWritten, out outputData, false, destination);
}
public static int Protect(ReadOnlySpan<byte> userData, DataProtectionScope scope, Span<byte> destination, ReadOnlySpan<byte> optionalEntropy = default(ReadOnlySpan<byte>))
{
CheckPlatformSupport();
if (!TryProtectOrUnprotect(userData, optionalEntropy, scope, true, out int bytesWritten, out byte[] _, false, destination))
throw new ArgumentException(System.SR.Argument_DestinationTooShort, "destination");
return bytesWritten;
}
[NullableContext(1)]
public static byte[] Unprotect(byte[] encryptedData, [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;
}
[return: Nullable(1)]
public static byte[] Unprotect(ReadOnlySpan<byte> encryptedData, DataProtectionScope scope, ReadOnlySpan<byte> optionalEntropy = default(ReadOnlySpan<byte>))
{
CheckPlatformSupport();
int bytesWritten = default(int);
byte[] outputData = default(byte[]);
TryProtectOrUnprotect(encryptedData, optionalEntropy, scope, false, out bytesWritten, out outputData, true, default(Span<byte>));
return outputData;
}
public static bool TryUnprotect(ReadOnlySpan<byte> encryptedData, DataProtectionScope scope, Span<byte> destination, out int bytesWritten, ReadOnlySpan<byte> optionalEntropy = default(ReadOnlySpan<byte>))
{
CheckPlatformSupport();
byte[] outputData;
return TryProtectOrUnprotect(encryptedData, optionalEntropy, scope, false, out bytesWritten, out outputData, false, destination);
}
public static int Unprotect(ReadOnlySpan<byte> encryptedData, DataProtectionScope scope, Span<byte> destination, ReadOnlySpan<byte> optionalEntropy = default(ReadOnlySpan<byte>))
{
CheckPlatformSupport();
if (!TryProtectOrUnprotect(encryptedData, optionalEntropy, scope, false, out int bytesWritten, out byte[] _, false, destination))
throw new ArgumentException(System.SR.Argument_DestinationTooShort, "destination");
return bytesWritten;
}
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* handle = &(inputData.IsEmpty ? ((ReadOnlySpan<byte>)s_nonEmpty) : inputData).GetPinnableReference()) {
fixed (byte* handle2 = &optionalEntropy.GetPinnableReference()) {
global::Interop.Crypt32.DATA_BLOB pDataIn = new global::Interop.Crypt32.DATA_BLOB((IntPtr)handle, (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)handle2, (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 lastPInvokeError = Marshal.GetLastPInvokeError();
if (protect && ErrorMayBeCausedByUnloadedProfile(lastPInvokeError))
throw new CryptographicException(System.SR.Cryptography_DpApi_ProfileMayNotBeLoaded);
throw lastPInvokeError.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();
}
}
}