Apply code formatting

This commit is contained in:
Louis DeJardin 2014-01-28 17:48:49 -08:00
parent 869a4ec267
commit baf338cc83
25 changed files with 395 additions and 225 deletions

34
DataProtection.sln Normal file
View File

@ -0,0 +1,34 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.21005.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Security.DataProtection.net45", "src\Microsoft.AspNet.Security.DataProtection\Microsoft.AspNet.Security.DataProtection.net45.csproj", "{106E3A4A-BD7A-40DC-90D3-2E0683D1E525}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Security.DataProtection.k10", "src\Microsoft.AspNet.Security.DataProtection\Microsoft.AspNet.Security.DataProtection.k10.csproj", "{E646E4FE-167B-42EB-831B-BBC2AB07C3AC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5FCB2DA3-5395-47F5-BCEE-E0EA319448EA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{106E3A4A-BD7A-40DC-90D3-2E0683D1E525}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{106E3A4A-BD7A-40DC-90D3-2E0683D1E525}.Debug|Any CPU.Build.0 = Debug|Any CPU
{106E3A4A-BD7A-40DC-90D3-2E0683D1E525}.Release|Any CPU.ActiveCfg = Release|Any CPU
{106E3A4A-BD7A-40DC-90D3-2E0683D1E525}.Release|Any CPU.Build.0 = Release|Any CPU
{E646E4FE-167B-42EB-831B-BBC2AB07C3AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E646E4FE-167B-42EB-831B-BBC2AB07C3AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E646E4FE-167B-42EB-831B-BBC2AB07C3AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E646E4FE-167B-42EB-831B-BBC2AB07C3AC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{E646E4FE-167B-42EB-831B-BBC2AB07C3AC} = {5FCB2DA3-5395-47F5-BCEE-E0EA319448EA}
{106E3A4A-BD7A-40DC-90D3-2E0683D1E525} = {5FCB2DA3-5395-47F5-BCEE-E0EA319448EA}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LINES/@EntryValue">False</s:Boolean></wpf:ResourceDictionary>

View File

@ -1,65 +1,75 @@
using System; using System;
using System.Security.Cryptography; using System.Security.Cryptography;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
{
internal unsafe static class Algorithms { internal static unsafe class Algorithms
{
public static readonly BCryptAlgorithmHandle AESAlgorithmHandle = CreateAESAlgorithmHandle(); public static readonly BCryptAlgorithmHandle AESAlgorithmHandle = CreateAESAlgorithmHandle();
public static readonly BCryptAlgorithmHandle HMACSHA256AlgorithmHandle = CreateHMACSHA256AlgorithmHandle(); public static readonly BCryptAlgorithmHandle HMACSHA256AlgorithmHandle = CreateHMACSHA256AlgorithmHandle();
public static readonly BCryptAlgorithmHandle HMACSHA512AlgorithmHandle = CreateHMACSHA512AlgorithmHandle(); public static readonly BCryptAlgorithmHandle HMACSHA512AlgorithmHandle = CreateHMACSHA512AlgorithmHandle();
public static readonly BCryptAlgorithmHandle SP800108AlgorithmHandle = CreateSP800108AlgorithmHandle(); public static readonly BCryptAlgorithmHandle SP800108AlgorithmHandle = CreateSP800108AlgorithmHandle();
private static BCryptAlgorithmHandle CreateAESAlgorithmHandle() { private static BCryptAlgorithmHandle CreateAESAlgorithmHandle()
{
// create the AES instance // create the AES instance
BCryptAlgorithmHandle algHandle; BCryptAlgorithmHandle algHandle;
int status = UnsafeNativeMethods.BCryptOpenAlgorithmProvider(out algHandle, Constants.BCRYPT_AES_ALGORITHM, Constants.MS_PRIMITIVE_PROVIDER, dwFlags: 0); int status = UnsafeNativeMethods.BCryptOpenAlgorithmProvider(out algHandle, Constants.BCRYPT_AES_ALGORITHM, Constants.MS_PRIMITIVE_PROVIDER, dwFlags: 0);
if (status != 0 || algHandle == null || algHandle.IsInvalid) { if (status != 0 || algHandle == null || algHandle.IsInvalid)
{
throw new CryptographicException(status); throw new CryptographicException(status);
} }
// change it to use CBC chaining; it already uses PKCS7 padding by default // change it to use CBC chaining; it already uses PKCS7 padding by default
fixed (char* pCbcMode = Constants.BCRYPT_CHAIN_MODE_CBC) { fixed (char* pCbcMode = Constants.BCRYPT_CHAIN_MODE_CBC)
status = UnsafeNativeMethods.BCryptSetProperty(algHandle, Constants.BCRYPT_CHAINING_MODE, (IntPtr)pCbcMode, (uint)((Constants.BCRYPT_CHAIN_MODE_CBC.Length + 1 /* trailing null */) * sizeof(char)), dwFlags: 0); {
status = UnsafeNativeMethods.BCryptSetProperty(algHandle, Constants.BCRYPT_CHAINING_MODE, (IntPtr) pCbcMode, (uint) ((Constants.BCRYPT_CHAIN_MODE_CBC.Length + 1 /* trailing null */)*sizeof (char)), dwFlags: 0);
} }
if (status != 0) { if (status != 0)
{
throw new CryptographicException(status); throw new CryptographicException(status);
} }
return algHandle; return algHandle;
} }
private static BCryptAlgorithmHandle CreateHMACSHA256AlgorithmHandle() {
private static BCryptAlgorithmHandle CreateHMACSHA256AlgorithmHandle()
{
// create the HMACSHA-256 instance // create the HMACSHA-256 instance
BCryptAlgorithmHandle algHandle; BCryptAlgorithmHandle algHandle;
int status = UnsafeNativeMethods.BCryptOpenAlgorithmProvider(out algHandle, Constants.BCRYPT_SHA256_ALGORITHM, Constants.MS_PRIMITIVE_PROVIDER, dwFlags: BCryptAlgorithmFlags.BCRYPT_ALG_HANDLE_HMAC_FLAG); int status = UnsafeNativeMethods.BCryptOpenAlgorithmProvider(out algHandle, Constants.BCRYPT_SHA256_ALGORITHM, Constants.MS_PRIMITIVE_PROVIDER, dwFlags: BCryptAlgorithmFlags.BCRYPT_ALG_HANDLE_HMAC_FLAG);
if (status != 0 || algHandle == null || algHandle.IsInvalid) { if (status != 0 || algHandle == null || algHandle.IsInvalid)
{
throw new CryptographicException(status); throw new CryptographicException(status);
} }
return algHandle; return algHandle;
} }
private static BCryptAlgorithmHandle CreateHMACSHA512AlgorithmHandle() { private static BCryptAlgorithmHandle CreateHMACSHA512AlgorithmHandle()
{
// create the HMACSHA-512 instance // create the HMACSHA-512 instance
BCryptAlgorithmHandle algHandle; BCryptAlgorithmHandle algHandle;
int status = UnsafeNativeMethods.BCryptOpenAlgorithmProvider(out algHandle, Constants.BCRYPT_SHA512_ALGORITHM, Constants.MS_PRIMITIVE_PROVIDER, dwFlags: BCryptAlgorithmFlags.BCRYPT_ALG_HANDLE_HMAC_FLAG); int status = UnsafeNativeMethods.BCryptOpenAlgorithmProvider(out algHandle, Constants.BCRYPT_SHA512_ALGORITHM, Constants.MS_PRIMITIVE_PROVIDER, dwFlags: BCryptAlgorithmFlags.BCRYPT_ALG_HANDLE_HMAC_FLAG);
if (status != 0 || algHandle == null || algHandle.IsInvalid) { if (status != 0 || algHandle == null || algHandle.IsInvalid)
{
throw new CryptographicException(status); throw new CryptographicException(status);
} }
return algHandle; return algHandle;
} }
private static BCryptAlgorithmHandle CreateSP800108AlgorithmHandle() { private static BCryptAlgorithmHandle CreateSP800108AlgorithmHandle()
{
// create the SP800-108 instance // create the SP800-108 instance
BCryptAlgorithmHandle algHandle; BCryptAlgorithmHandle algHandle;
int status = UnsafeNativeMethods.BCryptOpenAlgorithmProvider(out algHandle, Constants.BCRYPT_SP800108_CTR_HMAC_ALGORITHM, Constants.MS_PRIMITIVE_PROVIDER, dwFlags: 0); int status = UnsafeNativeMethods.BCryptOpenAlgorithmProvider(out algHandle, Constants.BCRYPT_SP800108_CTR_HMAC_ALGORITHM, Constants.MS_PRIMITIVE_PROVIDER, dwFlags: 0);
if (status != 0 || algHandle == null || algHandle.IsInvalid) { if (status != 0 || algHandle == null || algHandle.IsInvalid)
{
throw new CryptographicException(status); throw new CryptographicException(status);
} }
return algHandle; return algHandle;
} }
} }
} }

View File

@ -2,10 +2,12 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
{
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa375524(v=vs.85).aspx // http://msdn.microsoft.com/en-us/library/windows/desktop/aa375524(v=vs.85).aspx
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal struct BCRYPT_KEY_DATA_BLOB_HEADER { internal struct BCRYPT_KEY_DATA_BLOB_HEADER
{
// from bcrypt.h // from bcrypt.h
private const uint BCRYPT_KEY_DATA_BLOB_MAGIC = 0x4d42444b; //Key Data Blob Magic (KDBM) private const uint BCRYPT_KEY_DATA_BLOB_MAGIC = 0x4d42444b; //Key Data Blob Magic (KDBM)
private const uint BCRYPT_KEY_DATA_BLOB_VERSION1 = 0x1; private const uint BCRYPT_KEY_DATA_BLOB_VERSION1 = 0x1;
@ -15,7 +17,8 @@ namespace Microsoft.AspNet.Security.DataProtection {
public uint cbKeyData; public uint cbKeyData;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Initialize(ref BCRYPT_KEY_DATA_BLOB_HEADER pHeader) { public static void Initialize(ref BCRYPT_KEY_DATA_BLOB_HEADER pHeader)
{
pHeader.dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; pHeader.dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC;
pHeader.dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; pHeader.dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1;
} }

View File

@ -1,9 +1,11 @@
using System; using System;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
{
// from bcrypt.h // from bcrypt.h
[Flags] [Flags]
internal enum BCryptAlgorithmFlags { internal enum BCryptAlgorithmFlags
{
BCRYPT_ALG_HANDLE_HMAC_FLAG = 0x00000008, BCRYPT_ALG_HANDLE_HMAC_FLAG = 0x00000008,
BCRYPT_CAPI_AES_FLAG = 0x00000010, BCRYPT_CAPI_AES_FLAG = 0x00000010,
BCRYPT_HASH_REUSABLE_FLAG = 0x00000020, BCRYPT_HASH_REUSABLE_FLAG = 0x00000020,

View File

@ -1,15 +1,19 @@
using System; using System;
using Microsoft.Win32.SafeHandles; using Microsoft.Win32.SafeHandles;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
internal sealed class BCryptAlgorithmHandle : SafeHandleZeroOrMinusOneIsInvalid { {
internal sealed class BCryptAlgorithmHandle : SafeHandleZeroOrMinusOneIsInvalid
{
// Called by P/Invoke when returning SafeHandles // Called by P/Invoke when returning SafeHandles
private BCryptAlgorithmHandle() private BCryptAlgorithmHandle()
: base(ownsHandle: true) { : base(ownsHandle: true)
{
} }
// Do not provide a finalizer - SafeHandle's critical finalizer will call ReleaseHandle for you. // Do not provide a finalizer - SafeHandle's critical finalizer will call ReleaseHandle for you.
protected override bool ReleaseHandle() { protected override bool ReleaseHandle()
{
return (UnsafeNativeMethods.BCryptCloseAlgorithmProvider(handle, dwFlags: 0) == 0); return (UnsafeNativeMethods.BCryptCloseAlgorithmProvider(handle, dwFlags: 0) == 0);
} }
} }

View File

@ -2,10 +2,12 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
{
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa375368(v=vs.85).aspx // http://msdn.microsoft.com/en-us/library/windows/desktop/aa375368(v=vs.85).aspx
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal struct BCryptBuffer { internal struct BCryptBuffer
{
public uint cbBuffer; // Length of buffer, in bytes public uint cbBuffer; // Length of buffer, in bytes
public BCryptKeyDerivationBufferType BufferType; // Buffer type public BCryptKeyDerivationBufferType BufferType; // Buffer type
public IntPtr pvBuffer; // Pointer to buffer public IntPtr pvBuffer; // Pointer to buffer

View File

@ -2,10 +2,12 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
{
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa375370(v=vs.85).aspx // http://msdn.microsoft.com/en-us/library/windows/desktop/aa375370(v=vs.85).aspx
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal unsafe struct BCryptBufferDesc { internal unsafe struct BCryptBufferDesc
{
private const int BCRYPTBUFFER_VERSION = 0; private const int BCRYPTBUFFER_VERSION = 0;
public uint ulVersion; // Version number public uint ulVersion; // Version number
@ -13,7 +15,8 @@ namespace Microsoft.AspNet.Security.DataProtection {
public BCryptBuffer* pBuffers; // Pointer to array of buffers public BCryptBuffer* pBuffers; // Pointer to array of buffers
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Initialize(ref BCryptBufferDesc bufferDesc) { public static void Initialize(ref BCryptBufferDesc bufferDesc)
{
bufferDesc.ulVersion = BCRYPTBUFFER_VERSION; bufferDesc.ulVersion = BCRYPTBUFFER_VERSION;
} }
} }

View File

@ -1,9 +1,11 @@
using System; using System;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
{
// from bcrypt.h // from bcrypt.h
[Flags] [Flags]
internal enum BCryptEncryptFlags { internal enum BCryptEncryptFlags
{
BCRYPT_BLOCK_PADDING = 0x00000001, BCRYPT_BLOCK_PADDING = 0x00000001,
} }
} }

View File

@ -1,9 +1,11 @@
using System; using System;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
{
// from bcrypt.h // from bcrypt.h
[Flags] [Flags]
internal enum BCryptGenRandomFlags { internal enum BCryptGenRandomFlags
{
BCRYPT_RNG_USE_ENTROPY_IN_BUFFER = 0x00000001, BCRYPT_RNG_USE_ENTROPY_IN_BUFFER = 0x00000001,
BCRYPT_USE_SYSTEM_PREFERRED_RNG = 0x00000002, BCRYPT_USE_SYSTEM_PREFERRED_RNG = 0x00000002,
} }

View File

@ -1,15 +1,19 @@
using System; using System;
using Microsoft.Win32.SafeHandles; using Microsoft.Win32.SafeHandles;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
internal sealed class BCryptHashHandle : SafeHandleZeroOrMinusOneIsInvalid { {
internal sealed class BCryptHashHandle : SafeHandleZeroOrMinusOneIsInvalid
{
// Called by P/Invoke when returning SafeHandles // Called by P/Invoke when returning SafeHandles
private BCryptHashHandle() private BCryptHashHandle()
: base(ownsHandle: true) { : base(ownsHandle: true)
{
} }
// Do not provide a finalizer - SafeHandle's critical finalizer will call ReleaseHandle for you. // Do not provide a finalizer - SafeHandle's critical finalizer will call ReleaseHandle for you.
protected override bool ReleaseHandle() { protected override bool ReleaseHandle()
{
return (UnsafeNativeMethods.BCryptDestroyHash(handle) == 0); return (UnsafeNativeMethods.BCryptDestroyHash(handle) == 0);
} }
} }

View File

@ -1,8 +1,10 @@
using System; using System;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
{
// from bcrypt.h // from bcrypt.h
internal enum BCryptKeyDerivationBufferType { internal enum BCryptKeyDerivationBufferType
{
KDF_HASH_ALGORITHM = 0x0, KDF_HASH_ALGORITHM = 0x0,
KDF_SECRET_PREPEND = 0x1, KDF_SECRET_PREPEND = 0x1,
KDF_SECRET_APPEND = 0x2, KDF_SECRET_APPEND = 0x2,

View File

@ -1,15 +1,19 @@
using System; using System;
using Microsoft.Win32.SafeHandles; using Microsoft.Win32.SafeHandles;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
internal sealed class BCryptKeyHandle : SafeHandleZeroOrMinusOneIsInvalid { {
internal sealed class BCryptKeyHandle : SafeHandleZeroOrMinusOneIsInvalid
{
// Called by P/Invoke when returning SafeHandles // Called by P/Invoke when returning SafeHandles
private BCryptKeyHandle() private BCryptKeyHandle()
: base(ownsHandle: true) { : base(ownsHandle: true)
{
} }
// Do not provide a finalizer - SafeHandle's critical finalizer will call ReleaseHandle for you. // Do not provide a finalizer - SafeHandle's critical finalizer will call ReleaseHandle for you.
protected override bool ReleaseHandle() { protected override bool ReleaseHandle()
{
return (UnsafeNativeMethods.BCryptDestroyKey(handle) == 0); return (UnsafeNativeMethods.BCryptDestroyKey(handle) == 0);
} }
} }

View File

@ -3,36 +3,43 @@ using System.Runtime.CompilerServices;
using System.Security.Cryptography; using System.Security.Cryptography;
using Microsoft.AspNet.Security.DataProtection.Util; using Microsoft.AspNet.Security.DataProtection.Util;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
internal unsafe static class BCryptUtil { {
internal static unsafe class BCryptUtil
{
// constant-time buffer comparison // constant-time buffer comparison
[MethodImpl(MethodImplOptions.NoOptimization)] [MethodImpl(MethodImplOptions.NoOptimization)]
public static bool BuffersAreEqualSecure(byte* p1, byte* p2, uint count) { public static bool BuffersAreEqualSecure(byte* p1, byte* p2, uint count)
{
bool retVal = true; bool retVal = true;
while (count-- > 0) { while (count-- > 0)
{
retVal &= (*(p1++) == *(p2++)); retVal &= (*(p1++) == *(p2++));
} }
return retVal; return retVal;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void CheckOverflowUnderflow(int input) { private static void CheckOverflowUnderflow(int input)
var unused = checked((uint)input); {
var unused = checked((uint) input);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void CheckOverflowUnderflow(uint input) { private static void CheckOverflowUnderflow(uint input)
var unused = checked((int)input); {
var unused = checked((int) input);
} }
// helper function to wrap BCryptCreateHash // helper function to wrap BCryptCreateHash
public static BCryptHashHandle CreateHash(BCryptAlgorithmHandle algorithmHandle, byte* key, int keyLengthInBytes) { public static BCryptHashHandle CreateHash(BCryptAlgorithmHandle algorithmHandle, byte* key, int keyLengthInBytes)
{
CheckOverflowUnderflow(keyLengthInBytes); CheckOverflowUnderflow(keyLengthInBytes);
BCryptHashHandle retVal; BCryptHashHandle retVal;
int status = UnsafeNativeMethods.BCryptCreateHash(algorithmHandle, out retVal, IntPtr.Zero, 0, key, (uint)keyLengthInBytes, dwFlags: 0); int status = UnsafeNativeMethods.BCryptCreateHash(algorithmHandle, out retVal, IntPtr.Zero, 0, key, (uint) keyLengthInBytes, dwFlags: 0);
if (status != 0 || retVal == null || retVal.IsInvalid) { if (status != 0 || retVal == null || retVal.IsInvalid)
{
throw new CryptographicException(status); throw new CryptographicException(status);
} }
@ -41,32 +48,36 @@ namespace Microsoft.AspNet.Security.DataProtection {
// helper function to wrap BCryptEncrypt; returns number of bytes written to 'output' // helper function to wrap BCryptEncrypt; returns number of bytes written to 'output'
// assumes the output buffer is large enough to hold the ciphertext + any necessary padding // assumes the output buffer is large enough to hold the ciphertext + any necessary padding
public static int DecryptWithPadding(BCryptKeyHandle keyHandle, byte* input, int inputLength, byte* iv, int ivLength, byte* output, int outputLength) { public static int DecryptWithPadding(BCryptKeyHandle keyHandle, byte* input, int inputLength, byte* iv, int ivLength, byte* output, int outputLength)
{
CheckOverflowUnderflow(inputLength); CheckOverflowUnderflow(inputLength);
CheckOverflowUnderflow(ivLength); CheckOverflowUnderflow(ivLength);
CheckOverflowUnderflow(outputLength); CheckOverflowUnderflow(outputLength);
// BCryptEncrypt destroys the 'iv' parameter, so we need to pass a duplicate instead of the original // BCryptEncrypt destroys the 'iv' parameter, so we need to pass a duplicate instead of the original
if (ivLength > Constants.MAX_STACKALLOC_BYTES) { if (ivLength > Constants.MAX_STACKALLOC_BYTES)
{
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
byte* pDuplicatedIV = stackalloc byte[ivLength]; byte* pDuplicatedIV = stackalloc byte[ivLength];
BufferUtil.BlockCopy(from: (IntPtr)iv, to: (IntPtr)pDuplicatedIV, byteCount: ivLength); BufferUtil.BlockCopy(from: (IntPtr) iv, to: (IntPtr) pDuplicatedIV, byteCount: ivLength);
uint retVal; uint retVal;
int status = UnsafeNativeMethods.BCryptDecrypt(keyHandle, input, (uint)inputLength, IntPtr.Zero, pDuplicatedIV, (uint)ivLength, output, (uint)outputLength, out retVal, BCryptEncryptFlags.BCRYPT_BLOCK_PADDING); int status = UnsafeNativeMethods.BCryptDecrypt(keyHandle, input, (uint) inputLength, IntPtr.Zero, pDuplicatedIV, (uint) ivLength, output, (uint) outputLength, out retVal, BCryptEncryptFlags.BCRYPT_BLOCK_PADDING);
if (status != 0) { if (status != 0)
{
throw new CryptographicException(status); throw new CryptographicException(status);
} }
return checked((int)retVal); return checked((int) retVal);
} }
// helper function to wrap BCryptKeyDerivation using SP800-108-CTR-HMAC-SHA512 // helper function to wrap BCryptKeyDerivation using SP800-108-CTR-HMAC-SHA512
public static void DeriveKeysSP800108(BCryptAlgorithmHandle kdfAlgorithmHandle, BCryptKeyHandle keyHandle, string purpose, BCryptAlgorithmHandle encryptionAlgorithmHandle, out BCryptKeyHandle encryptionKeyHandle, BCryptAlgorithmHandle hashAlgorithmHandle, out BCryptHashHandle hmacHandle, out BCryptKeyHandle kdfKeyHandle) { public static void DeriveKeysSP800108(BCryptAlgorithmHandle kdfAlgorithmHandle, BCryptKeyHandle keyHandle, string purpose, BCryptAlgorithmHandle encryptionAlgorithmHandle, out BCryptKeyHandle encryptionKeyHandle, BCryptAlgorithmHandle hashAlgorithmHandle, out BCryptHashHandle hmacHandle, out BCryptKeyHandle kdfKeyHandle)
const int ENCRYPTION_KEY_SIZE_IN_BYTES = 256 / 8; {
const int HMAC_KEY_SIZE_IN_BYTES = 256 / 8; const int ENCRYPTION_KEY_SIZE_IN_BYTES = 256/8;
const int KDF_SUBKEY_SIZE_IN_BYTES = 512 / 8; const int HMAC_KEY_SIZE_IN_BYTES = 256/8;
const int KDF_SUBKEY_SIZE_IN_BYTES = 512/8;
const int TOTAL_NUM_BYTES_TO_DERIVE = ENCRYPTION_KEY_SIZE_IN_BYTES + HMAC_KEY_SIZE_IN_BYTES + KDF_SUBKEY_SIZE_IN_BYTES; const int TOTAL_NUM_BYTES_TO_DERIVE = ENCRYPTION_KEY_SIZE_IN_BYTES + HMAC_KEY_SIZE_IN_BYTES + KDF_SUBKEY_SIZE_IN_BYTES;
// keep our buffers on the stack while we're generating key material // keep our buffers on the stack while we're generating key material
@ -75,21 +86,25 @@ namespace Microsoft.AspNet.Security.DataProtection {
byte* pNewHmacKey = &pNewEncryptionKey[ENCRYPTION_KEY_SIZE_IN_BYTES]; byte* pNewHmacKey = &pNewEncryptionKey[ENCRYPTION_KEY_SIZE_IN_BYTES];
byte* pNewKdfSubkey = &pNewHmacKey[HMAC_KEY_SIZE_IN_BYTES]; byte* pNewKdfSubkey = &pNewHmacKey[HMAC_KEY_SIZE_IN_BYTES];
try { try
fixed (char* pszPrfAlgorithmName = Constants.BCRYPT_SHA512_ALGORITHM) { {
fixed (char* pszPrfAlgorithmName = Constants.BCRYPT_SHA512_ALGORITHM)
{
// Create a buffer to hold the hash algorithm name, currently hardcoded to HMACSHA512 // Create a buffer to hold the hash algorithm name, currently hardcoded to HMACSHA512
uint numBuffers = 1; uint numBuffers = 1;
BCryptBuffer* pBCryptBuffers = stackalloc BCryptBuffer[2]; BCryptBuffer* pBCryptBuffers = stackalloc BCryptBuffer[2];
pBCryptBuffers[0].BufferType = BCryptKeyDerivationBufferType.KDF_HASH_ALGORITHM; pBCryptBuffers[0].BufferType = BCryptKeyDerivationBufferType.KDF_HASH_ALGORITHM;
pBCryptBuffers[0].pvBuffer = (IntPtr)pszPrfAlgorithmName; pBCryptBuffers[0].pvBuffer = (IntPtr) pszPrfAlgorithmName;
pBCryptBuffers[0].cbBuffer = (uint)((Constants.BCRYPT_SHA512_ALGORITHM.Length + 1) * sizeof(char)); // per http://msdn.microsoft.com/en-us/library/windows/desktop/aa375368(v=vs.85).aspx, need to include terminating null pBCryptBuffers[0].cbBuffer = (uint) ((Constants.BCRYPT_SHA512_ALGORITHM.Length + 1)*sizeof (char)); // per http://msdn.microsoft.com/en-us/library/windows/desktop/aa375368(v=vs.85).aspx, need to include terminating null
fixed (char* pszPurpose = (String.IsNullOrEmpty(purpose) ? (string)null : purpose)) { fixed (char* pszPurpose = (String.IsNullOrEmpty(purpose) ? (string) null : purpose))
{
// Create a buffer to hold the purpose string if it is specified (we'll treat it as UTF-16LE) // Create a buffer to hold the purpose string if it is specified (we'll treat it as UTF-16LE)
if (pszPurpose != null) { if (pszPurpose != null)
{
numBuffers = 2; numBuffers = 2;
pBCryptBuffers[1].BufferType = BCryptKeyDerivationBufferType.KDF_LABEL; pBCryptBuffers[1].BufferType = BCryptKeyDerivationBufferType.KDF_LABEL;
pBCryptBuffers[1].pvBuffer = (IntPtr)pszPurpose; pBCryptBuffers[1].pvBuffer = (IntPtr) pszPurpose;
pBCryptBuffers[1].cbBuffer = checked((uint)(purpose.Length * sizeof(char))); pBCryptBuffers[1].cbBuffer = checked((uint) (purpose.Length*sizeof (char)));
} }
// .. and the header .. // .. and the header ..
@ -100,7 +115,8 @@ namespace Microsoft.AspNet.Security.DataProtection {
uint numBytesDerived; uint numBytesDerived;
int status = UnsafeNativeMethods.BCryptKeyDerivation(keyHandle, &bufferDesc, pBuffer, TOTAL_NUM_BYTES_TO_DERIVE, out numBytesDerived, dwFlags: 0); int status = UnsafeNativeMethods.BCryptKeyDerivation(keyHandle, &bufferDesc, pBuffer, TOTAL_NUM_BYTES_TO_DERIVE, out numBytesDerived, dwFlags: 0);
if (status != 0 || numBytesDerived != TOTAL_NUM_BYTES_TO_DERIVE) { if (status != 0 || numBytesDerived != TOTAL_NUM_BYTES_TO_DERIVE)
{
throw new CryptographicException(status); throw new CryptographicException(status);
} }
} }
@ -111,16 +127,19 @@ namespace Microsoft.AspNet.Security.DataProtection {
hmacHandle = CreateHash(hashAlgorithmHandle, pNewHmacKey, HMAC_KEY_SIZE_IN_BYTES); hmacHandle = CreateHash(hashAlgorithmHandle, pNewHmacKey, HMAC_KEY_SIZE_IN_BYTES);
kdfKeyHandle = ImportKey(kdfAlgorithmHandle, pNewKdfSubkey, KDF_SUBKEY_SIZE_IN_BYTES); kdfKeyHandle = ImportKey(kdfAlgorithmHandle, pNewKdfSubkey, KDF_SUBKEY_SIZE_IN_BYTES);
} }
finally { finally
{
BufferUtil.ZeroMemory(pBuffer, TOTAL_NUM_BYTES_TO_DERIVE); BufferUtil.ZeroMemory(pBuffer, TOTAL_NUM_BYTES_TO_DERIVE);
} }
} }
// helper function to wrap BCryptDuplicateHash // helper function to wrap BCryptDuplicateHash
public static BCryptHashHandle DuplicateHash(BCryptHashHandle hashHandle) { public static BCryptHashHandle DuplicateHash(BCryptHashHandle hashHandle)
{
BCryptHashHandle retVal; BCryptHashHandle retVal;
int status = UnsafeNativeMethods.BCryptDuplicateHash(hashHandle, out retVal, IntPtr.Zero, 0, dwFlags: 0); int status = UnsafeNativeMethods.BCryptDuplicateHash(hashHandle, out retVal, IntPtr.Zero, 0, dwFlags: 0);
if (status != 0 || retVal == null || retVal.IsInvalid) { if (status != 0 || retVal == null || retVal.IsInvalid)
{
throw new CryptographicException(status); throw new CryptographicException(status);
} }
@ -129,93 +148,107 @@ namespace Microsoft.AspNet.Security.DataProtection {
// helper function to wrap BCryptEncrypt; returns number of bytes written to 'output' // helper function to wrap BCryptEncrypt; returns number of bytes written to 'output'
// assumes the output buffer is large enough to hold the ciphertext + any necessary padding // assumes the output buffer is large enough to hold the ciphertext + any necessary padding
public static int EncryptWithPadding(BCryptKeyHandle keyHandle, byte* input, int inputLength, byte* iv, int ivLength, byte* output, int outputLength) { public static int EncryptWithPadding(BCryptKeyHandle keyHandle, byte* input, int inputLength, byte* iv, int ivLength, byte* output, int outputLength)
{
CheckOverflowUnderflow(inputLength); CheckOverflowUnderflow(inputLength);
CheckOverflowUnderflow(ivLength); CheckOverflowUnderflow(ivLength);
CheckOverflowUnderflow(outputLength); CheckOverflowUnderflow(outputLength);
// BCryptEncrypt destroys the 'iv' parameter, so we need to pass a duplicate instead of the original // BCryptEncrypt destroys the 'iv' parameter, so we need to pass a duplicate instead of the original
if (ivLength > Constants.MAX_STACKALLOC_BYTES) { if (ivLength > Constants.MAX_STACKALLOC_BYTES)
{
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
byte* pDuplicatedIV = stackalloc byte[ivLength]; byte* pDuplicatedIV = stackalloc byte[ivLength];
BufferUtil.BlockCopy(from: (IntPtr)iv, to: (IntPtr)pDuplicatedIV, byteCount: ivLength); BufferUtil.BlockCopy(from: (IntPtr) iv, to: (IntPtr) pDuplicatedIV, byteCount: ivLength);
uint retVal; uint retVal;
int status = UnsafeNativeMethods.BCryptEncrypt(keyHandle, input, (uint)inputLength, IntPtr.Zero, pDuplicatedIV, (uint)ivLength, output, (uint)outputLength, out retVal, BCryptEncryptFlags.BCRYPT_BLOCK_PADDING); int status = UnsafeNativeMethods.BCryptEncrypt(keyHandle, input, (uint) inputLength, IntPtr.Zero, pDuplicatedIV, (uint) ivLength, output, (uint) outputLength, out retVal, BCryptEncryptFlags.BCRYPT_BLOCK_PADDING);
if (status != 0) { if (status != 0)
{
throw new CryptographicException(status); throw new CryptographicException(status);
} }
return checked((int)retVal); return checked((int) retVal);
} }
// helper function that's similar to RNGCryptoServiceProvider, but works directly with pointers // helper function that's similar to RNGCryptoServiceProvider, but works directly with pointers
public static void GenRandom(byte* buffer, int bufferBytes) { public static void GenRandom(byte* buffer, int bufferBytes)
{
CheckOverflowUnderflow(bufferBytes); CheckOverflowUnderflow(bufferBytes);
int status = UnsafeNativeMethods.BCryptGenRandom(IntPtr.Zero, buffer, (uint)bufferBytes, BCryptGenRandomFlags.BCRYPT_USE_SYSTEM_PREFERRED_RNG); int status = UnsafeNativeMethods.BCryptGenRandom(IntPtr.Zero, buffer, (uint) bufferBytes, BCryptGenRandomFlags.BCRYPT_USE_SYSTEM_PREFERRED_RNG);
if (status != 0) { if (status != 0)
{
throw new CryptographicException(status); throw new CryptographicException(status);
} }
} }
// helper function that wraps BCryptHashData / BCryptFinishHash // helper function that wraps BCryptHashData / BCryptFinishHash
public static void HashData(BCryptHashHandle hashHandle, byte* input, int inputBytes, byte* output, int outputBytes) { public static void HashData(BCryptHashHandle hashHandle, byte* input, int inputBytes, byte* output, int outputBytes)
{
CheckOverflowUnderflow(inputBytes); CheckOverflowUnderflow(inputBytes);
CheckOverflowUnderflow(outputBytes); CheckOverflowUnderflow(outputBytes);
int status = UnsafeNativeMethods.BCryptHashData(hashHandle, input, (uint)inputBytes, dwFlags: 0); int status = UnsafeNativeMethods.BCryptHashData(hashHandle, input, (uint) inputBytes, dwFlags: 0);
if (status != 0) { if (status != 0)
{
throw new CryptographicException(status); throw new CryptographicException(status);
} }
status = UnsafeNativeMethods.BCryptFinishHash(hashHandle, output, (uint)outputBytes, dwFlags: 0); status = UnsafeNativeMethods.BCryptFinishHash(hashHandle, output, (uint) outputBytes, dwFlags: 0);
if (status != 0) { if (status != 0)
{
throw new CryptographicException(status); throw new CryptographicException(status);
} }
} }
// helper function that wraps BCryptImportKey with a key data blob // helper function that wraps BCryptImportKey with a key data blob
public static BCryptKeyHandle ImportKey(BCryptAlgorithmHandle algHandle, byte* key, int keyBytes) { public static BCryptKeyHandle ImportKey(BCryptAlgorithmHandle algHandle, byte* key, int keyBytes)
{
CheckOverflowUnderflow(keyBytes); CheckOverflowUnderflow(keyBytes);
byte[] heapAllocatedKeyDataBlob = null; byte[] heapAllocatedKeyDataBlob = null;
int numBytesRequiredForKeyDataBlob = checked(keyBytes + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER)); int numBytesRequiredForKeyDataBlob = checked(keyBytes + sizeof (BCRYPT_KEY_DATA_BLOB_HEADER));
if (numBytesRequiredForKeyDataBlob > Constants.MAX_STACKALLOC_BYTES) { if (numBytesRequiredForKeyDataBlob > Constants.MAX_STACKALLOC_BYTES)
{
heapAllocatedKeyDataBlob = new byte[numBytesRequiredForKeyDataBlob]; // allocate on heap if we cannot allocate on stack heapAllocatedKeyDataBlob = new byte[numBytesRequiredForKeyDataBlob]; // allocate on heap if we cannot allocate on stack
} }
int status; int status;
BCryptKeyHandle retVal; BCryptKeyHandle retVal;
fixed (byte* pHeapAllocatedKeyDataBlob = heapAllocatedKeyDataBlob) { fixed (byte* pHeapAllocatedKeyDataBlob = heapAllocatedKeyDataBlob)
{
// The header is first // The header is first
BCRYPT_KEY_DATA_BLOB_HEADER* pKeyDataBlobHeader = (BCRYPT_KEY_DATA_BLOB_HEADER*)pHeapAllocatedKeyDataBlob; BCRYPT_KEY_DATA_BLOB_HEADER* pKeyDataBlobHeader = (BCRYPT_KEY_DATA_BLOB_HEADER*) pHeapAllocatedKeyDataBlob;
if (pKeyDataBlobHeader == null) { if (pKeyDataBlobHeader == null)
{
byte* temp = stackalloc byte[numBytesRequiredForKeyDataBlob]; // won't be released until frame pops byte* temp = stackalloc byte[numBytesRequiredForKeyDataBlob]; // won't be released until frame pops
pKeyDataBlobHeader = (BCRYPT_KEY_DATA_BLOB_HEADER*)temp; pKeyDataBlobHeader = (BCRYPT_KEY_DATA_BLOB_HEADER*) temp;
} }
BCRYPT_KEY_DATA_BLOB_HEADER.Initialize(ref *pKeyDataBlobHeader); BCRYPT_KEY_DATA_BLOB_HEADER.Initialize(ref *pKeyDataBlobHeader);
pKeyDataBlobHeader->cbKeyData = (uint)keyBytes; pKeyDataBlobHeader->cbKeyData = (uint) keyBytes;
// the raw material immediately follows the header // the raw material immediately follows the header
byte* pKeyDataRawMaterial = (byte*)(&pKeyDataBlobHeader[1]); byte* pKeyDataRawMaterial = (byte*) (&pKeyDataBlobHeader[1]);
try { try
BufferUtil.BlockCopy(from: (IntPtr)key, to: (IntPtr)pKeyDataRawMaterial, byteCount: keyBytes); {
status = UnsafeNativeMethods.BCryptImportKey(algHandle, IntPtr.Zero, Constants.BCRYPT_KEY_DATA_BLOB, out retVal, IntPtr.Zero, 0, (byte*)pKeyDataBlobHeader, (uint)numBytesRequiredForKeyDataBlob, dwFlags: 0); BufferUtil.BlockCopy(from: (IntPtr) key, to: (IntPtr) pKeyDataRawMaterial, byteCount: keyBytes);
status = UnsafeNativeMethods.BCryptImportKey(algHandle, IntPtr.Zero, Constants.BCRYPT_KEY_DATA_BLOB, out retVal, IntPtr.Zero, 0, (byte*) pKeyDataBlobHeader, (uint) numBytesRequiredForKeyDataBlob, dwFlags: 0);
} }
finally { finally
{
// zero out the key we just copied // zero out the key we just copied
BufferUtil.ZeroMemory(pKeyDataRawMaterial, keyBytes); BufferUtil.ZeroMemory(pKeyDataRawMaterial, keyBytes);
} }
} }
if (status != 0 || retVal == null || retVal.IsInvalid) { if (status != 0 || retVal == null || retVal.IsInvalid)
{
throw new CryptographicException(status); throw new CryptographicException(status);
} }
return retVal; return retVal;
} }
} }
} }

View File

@ -1,8 +1,10 @@
using System; using System;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
{
// from bcrypt.h // from bcrypt.h
internal static class Constants { internal static class Constants
{
internal const int MAX_STACKALLOC_BYTES = 256; // greatest number of bytes that we'll ever allow to stackalloc in a single frame internal const int MAX_STACKALLOC_BYTES = 256; // greatest number of bytes that we'll ever allow to stackalloc in a single frame
// BCrypt(Import/Export)Key BLOB types // BCrypt(Import/Export)Key BLOB types

View File

@ -4,19 +4,22 @@ using System.Reflection;
using Microsoft.AspNet.Security.DataProtection.Resources; using Microsoft.AspNet.Security.DataProtection.Resources;
using Microsoft.AspNet.Security.DataProtection.Util; using Microsoft.AspNet.Security.DataProtection.Util;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
public unsafe static class DataProtectionProvider { {
public static unsafe class DataProtectionProvider
const int MASTER_KEY_REQUIRED_LENGTH = 512 / 8; {
private const int MASTER_KEY_REQUIRED_LENGTH = 512/8;
private static readonly byte[] MASTER_SUBKEY_GENERATOR = GetMasterSubkeyGenerator(); private static readonly byte[] MASTER_SUBKEY_GENERATOR = GetMasterSubkeyGenerator();
private static byte[] GetMasterSubkeyGenerator() { private static byte[] GetMasterSubkeyGenerator()
TypeInfo typeInfo = typeof(DataProtectionProvider).GetTypeInfo(); {
TypeInfo typeInfo = typeof (DataProtectionProvider).GetTypeInfo();
byte[] retVal = new byte[sizeof(Guid) * 2]; byte[] retVal = new byte[sizeof (Guid)*2];
fixed (byte* pRetVal = retVal) { fixed (byte* pRetVal = retVal)
Guid* guids = (Guid*)pRetVal; {
Guid* guids = (Guid*) pRetVal;
guids[0] = typeInfo.GUID; guids[0] = typeInfo.GUID;
#if NET45 #if NET45
guids[1] = typeInfo.Module.ModuleVersionId; guids[1] = typeInfo.Module.ModuleVersionId;
@ -30,13 +33,16 @@ namespace Microsoft.AspNet.Security.DataProtection {
/// <summary> /// <summary>
/// Creates a new IDataProtectorFactory with a randomly-generated master key. /// Creates a new IDataProtectorFactory with a randomly-generated master key.
/// </summary> /// </summary>
public static IDataProtectionProvider CreateNew() { public static IDataProtectionProvider CreateNew()
{
byte* masterKey = stackalloc byte[MASTER_KEY_REQUIRED_LENGTH]; byte* masterKey = stackalloc byte[MASTER_KEY_REQUIRED_LENGTH];
try { try
{
BCryptUtil.GenRandom(masterKey, MASTER_KEY_REQUIRED_LENGTH); BCryptUtil.GenRandom(masterKey, MASTER_KEY_REQUIRED_LENGTH);
return CreateImpl(masterKey, MASTER_KEY_REQUIRED_LENGTH); return CreateImpl(masterKey, MASTER_KEY_REQUIRED_LENGTH);
} }
finally { finally
{
BufferUtil.ZeroMemory(masterKey, MASTER_KEY_REQUIRED_LENGTH); BufferUtil.ZeroMemory(masterKey, MASTER_KEY_REQUIRED_LENGTH);
} }
} }
@ -44,34 +50,41 @@ namespace Microsoft.AspNet.Security.DataProtection {
/// <summary> /// <summary>
/// Creates a new IDataProtectorFactory with the provided master key. /// Creates a new IDataProtectorFactory with the provided master key.
/// </summary> /// </summary>
public static IDataProtectionProvider CreateFromKey(byte[] masterKey) { public static IDataProtectionProvider CreateFromKey(byte[] masterKey)
if (masterKey == null) { {
if (masterKey == null)
{
throw new ArgumentNullException("masterKey"); throw new ArgumentNullException("masterKey");
} }
if (masterKey.Length < MASTER_KEY_REQUIRED_LENGTH) { if (masterKey.Length < MASTER_KEY_REQUIRED_LENGTH)
{
string errorMessage = String.Format(CultureInfo.CurrentCulture, Res.DataProtectorFactory_MasterKeyTooShort, MASTER_KEY_REQUIRED_LENGTH); string errorMessage = String.Format(CultureInfo.CurrentCulture, Res.DataProtectorFactory_MasterKeyTooShort, MASTER_KEY_REQUIRED_LENGTH);
throw new ArgumentOutOfRangeException("masterKey", errorMessage); throw new ArgumentOutOfRangeException("masterKey", errorMessage);
} }
fixed (byte* pMasterKey = masterKey) { fixed (byte* pMasterKey = masterKey)
{
return CreateImpl(pMasterKey, masterKey.Length); return CreateImpl(pMasterKey, masterKey.Length);
} }
} }
private static DataProtectionProviderImpl CreateImpl(byte* masterKey, int masterKeyLengthInBytes) { private static DataProtectionProviderImpl CreateImpl(byte* masterKey, int masterKeyLengthInBytes)
{
// We don't use the master key directly. We derive a master subkey via HMAC_{master_key}(MASTER_SUBKEY_GENERATOR). // We don't use the master key directly. We derive a master subkey via HMAC_{master_key}(MASTER_SUBKEY_GENERATOR).
byte* masterSubkey = stackalloc byte[MASTER_KEY_REQUIRED_LENGTH]; byte* masterSubkey = stackalloc byte[MASTER_KEY_REQUIRED_LENGTH];
try { try
using (var hashHandle = BCryptUtil.CreateHash(Algorithms.HMACSHA512AlgorithmHandle, masterKey, masterKeyLengthInBytes)) { {
using (var hashHandle = BCryptUtil.CreateHash(Algorithms.HMACSHA512AlgorithmHandle, masterKey, masterKeyLengthInBytes))
{
BCryptUtil.HashData(hashHandle, masterKey, masterKeyLengthInBytes, masterSubkey, MASTER_KEY_REQUIRED_LENGTH); BCryptUtil.HashData(hashHandle, masterKey, masterKeyLengthInBytes, masterSubkey, MASTER_KEY_REQUIRED_LENGTH);
} }
BCryptKeyHandle kdfSubkeyHandle = BCryptUtil.ImportKey(Algorithms.SP800108AlgorithmHandle, masterSubkey, MASTER_KEY_REQUIRED_LENGTH); BCryptKeyHandle kdfSubkeyHandle = BCryptUtil.ImportKey(Algorithms.SP800108AlgorithmHandle, masterSubkey, MASTER_KEY_REQUIRED_LENGTH);
return new DataProtectionProviderImpl(kdfSubkeyHandle); return new DataProtectionProviderImpl(kdfSubkeyHandle);
} }
finally { finally
{
BufferUtil.ZeroMemory(masterSubkey, MASTER_KEY_REQUIRED_LENGTH); BufferUtil.ZeroMemory(masterSubkey, MASTER_KEY_REQUIRED_LENGTH);
} }
} }
} }
} }

View File

@ -1,15 +1,18 @@
using System; using System;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
internal unsafe sealed class DataProtectionProviderImpl : IDataProtectionProvider { {
internal sealed unsafe class DataProtectionProviderImpl : IDataProtectionProvider
{
private readonly BCryptKeyHandle _kdfSubkeyHandle; private readonly BCryptKeyHandle _kdfSubkeyHandle;
public DataProtectionProviderImpl(BCryptKeyHandle kdfSubkeyHandle) { public DataProtectionProviderImpl(BCryptKeyHandle kdfSubkeyHandle)
{
_kdfSubkeyHandle = kdfSubkeyHandle; _kdfSubkeyHandle = kdfSubkeyHandle;
} }
public IDataProtector CreateProtector(string purpose) { public IDataProtector CreateProtector(string purpose)
{
BCryptKeyHandle newAesKeyHandle; BCryptKeyHandle newAesKeyHandle;
BCryptHashHandle newHmacHashHandle; BCryptHashHandle newHmacHashHandle;
BCryptKeyHandle newKdfSubkeyHandle; BCryptKeyHandle newKdfSubkeyHandle;
@ -18,9 +21,9 @@ namespace Microsoft.AspNet.Security.DataProtection {
return new DataProtectorImpl(newAesKeyHandle, newHmacHashHandle, newKdfSubkeyHandle); return new DataProtectorImpl(newAesKeyHandle, newHmacHashHandle, newKdfSubkeyHandle);
} }
public void Dispose() { public void Dispose()
{
_kdfSubkeyHandle.Dispose(); _kdfSubkeyHandle.Dispose();
} }
} }
} }

View File

@ -4,35 +4,40 @@ using System.Security.Cryptography;
using Microsoft.AspNet.Security.DataProtection.Resources; using Microsoft.AspNet.Security.DataProtection.Resources;
using Microsoft.AspNet.Security.DataProtection.Util; using Microsoft.AspNet.Security.DataProtection.Util;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
internal unsafe sealed class DataProtectorImpl : IDataProtector { {
internal sealed unsafe class DataProtectorImpl : IDataProtector
private const int AES_BLOCK_LENGTH_IN_BYTES = 128 / 8; {
private const int MAC_LENGTH_IN_BYTES = 256 / 8; private const int AES_BLOCK_LENGTH_IN_BYTES = 128/8;
private const int MAC_LENGTH_IN_BYTES = 256/8;
private readonly BCryptKeyHandle _aesKeyHandle; private readonly BCryptKeyHandle _aesKeyHandle;
private readonly BCryptHashHandle _hmacHashHandle; private readonly BCryptHashHandle _hmacHashHandle;
private readonly BCryptKeyHandle _kdfSubkeyHandle; private readonly BCryptKeyHandle _kdfSubkeyHandle;
public DataProtectorImpl(BCryptKeyHandle aesKeyHandle, BCryptHashHandle hmacHashHandle, BCryptKeyHandle kdfSubkeyHandle) { public DataProtectorImpl(BCryptKeyHandle aesKeyHandle, BCryptHashHandle hmacHashHandle, BCryptKeyHandle kdfSubkeyHandle)
{
_aesKeyHandle = aesKeyHandle; _aesKeyHandle = aesKeyHandle;
_hmacHashHandle = hmacHashHandle; _hmacHashHandle = hmacHashHandle;
_kdfSubkeyHandle = kdfSubkeyHandle; _kdfSubkeyHandle = kdfSubkeyHandle;
} }
private static int CalculateTotalProtectedDataSize(int unprotectedDataSize) { private static int CalculateTotalProtectedDataSize(int unprotectedDataSize)
{
Debug.Assert(unprotectedDataSize >= 0); Debug.Assert(unprotectedDataSize >= 0);
// Calculates // Calculates
int numFullBlocks = unprotectedDataSize / AES_BLOCK_LENGTH_IN_BYTES; int numFullBlocks = unprotectedDataSize/AES_BLOCK_LENGTH_IN_BYTES;
return checked(AES_BLOCK_LENGTH_IN_BYTES /* IV */ + (numFullBlocks + 1) * AES_BLOCK_LENGTH_IN_BYTES /* ciphertext w/ padding */ + MAC_LENGTH_IN_BYTES /* HMAC */); return checked(AES_BLOCK_LENGTH_IN_BYTES /* IV */+ (numFullBlocks + 1)*AES_BLOCK_LENGTH_IN_BYTES /* ciphertext w/ padding */+ MAC_LENGTH_IN_BYTES /* HMAC */);
} }
private static CryptographicException CreateGenericCryptographicException() { private static CryptographicException CreateGenericCryptographicException()
{
return new CryptographicException(Res.DataProtectorImpl_BadEncryptedData); return new CryptographicException(Res.DataProtectorImpl_BadEncryptedData);
} }
public IDataProtector CreateSubProtector(string purpose) { public IDataProtector CreateSubProtector(string purpose)
{
BCryptKeyHandle newAesKeyHandle; BCryptKeyHandle newAesKeyHandle;
BCryptHashHandle newHmacHashHandle; BCryptHashHandle newHmacHashHandle;
BCryptKeyHandle newKdfSubkeyHandle; BCryptKeyHandle newKdfSubkeyHandle;
@ -41,21 +46,25 @@ namespace Microsoft.AspNet.Security.DataProtection {
return new DataProtectorImpl(newAesKeyHandle, newHmacHashHandle, newKdfSubkeyHandle); return new DataProtectorImpl(newAesKeyHandle, newHmacHashHandle, newKdfSubkeyHandle);
} }
public void Dispose() { public void Dispose()
{
_aesKeyHandle.Dispose(); _aesKeyHandle.Dispose();
_hmacHashHandle.Dispose(); _hmacHashHandle.Dispose();
_kdfSubkeyHandle.Dispose(); _kdfSubkeyHandle.Dispose();
} }
public byte[] Protect(byte[] unprotectedData) { public byte[] Protect(byte[] unprotectedData)
if (unprotectedData == null) { {
if (unprotectedData == null)
{
throw new ArgumentNullException("unprotectedData"); throw new ArgumentNullException("unprotectedData");
} }
// When this method finishes, protectedData will contain { IV || ciphertext || HMAC(IV || ciphertext) } // When this method finishes, protectedData will contain { IV || ciphertext || HMAC(IV || ciphertext) }
byte[] protectedData = new byte[CalculateTotalProtectedDataSize(unprotectedData.Length)]; byte[] protectedData = new byte[CalculateTotalProtectedDataSize(unprotectedData.Length)];
fixed (byte* pProtectedData = protectedData) { fixed (byte* pProtectedData = protectedData)
{
// first, generate a random IV for CBC mode encryption // first, generate a random IV for CBC mode encryption
byte* pIV = pProtectedData; byte* pIV = pProtectedData;
BCryptUtil.GenRandom(pIV, AES_BLOCK_LENGTH_IN_BYTES); BCryptUtil.GenRandom(pIV, AES_BLOCK_LENGTH_IN_BYTES);
@ -63,16 +72,19 @@ namespace Microsoft.AspNet.Security.DataProtection {
// then, encrypt the plaintext contents // then, encrypt the plaintext contents
byte* pCiphertext = &pIV[AES_BLOCK_LENGTH_IN_BYTES]; byte* pCiphertext = &pIV[AES_BLOCK_LENGTH_IN_BYTES];
int expectedCiphertextLength = protectedData.Length - AES_BLOCK_LENGTH_IN_BYTES - MAC_LENGTH_IN_BYTES; int expectedCiphertextLength = protectedData.Length - AES_BLOCK_LENGTH_IN_BYTES - MAC_LENGTH_IN_BYTES;
fixed (byte* pPlaintext = unprotectedData) { fixed (byte* pPlaintext = unprotectedData)
{
int actualCiphertextLength = BCryptUtil.EncryptWithPadding(_aesKeyHandle, pPlaintext, unprotectedData.Length, pIV, AES_BLOCK_LENGTH_IN_BYTES, pCiphertext, expectedCiphertextLength); int actualCiphertextLength = BCryptUtil.EncryptWithPadding(_aesKeyHandle, pPlaintext, unprotectedData.Length, pIV, AES_BLOCK_LENGTH_IN_BYTES, pCiphertext, expectedCiphertextLength);
if (actualCiphertextLength != expectedCiphertextLength) { if (actualCiphertextLength != expectedCiphertextLength)
{
throw new InvalidOperationException("Unexpected error while encrypting data."); throw new InvalidOperationException("Unexpected error while encrypting data.");
} }
} }
// finally, calculate an HMAC over { IV || ciphertext } // finally, calculate an HMAC over { IV || ciphertext }
byte* pMac = &pCiphertext[expectedCiphertextLength]; byte* pMac = &pCiphertext[expectedCiphertextLength];
using (var clonedHashHandle = BCryptUtil.DuplicateHash(_hmacHashHandle)) { using (var clonedHashHandle = BCryptUtil.DuplicateHash(_hmacHashHandle))
{
// Use a cloned hash handle since IDataProtector instances could be singletons, but BCryptHashHandle instances contain // Use a cloned hash handle since IDataProtector instances could be singletons, but BCryptHashHandle instances contain
// state hence aren't thread-safe. Our own perf testing shows that duplicating existing hash handles is very fast. // state hence aren't thread-safe. Our own perf testing shows that duplicating existing hash handles is very fast.
BCryptUtil.HashData(clonedHashHandle, pProtectedData, AES_BLOCK_LENGTH_IN_BYTES + expectedCiphertextLength, pMac, MAC_LENGTH_IN_BYTES); BCryptUtil.HashData(clonedHashHandle, pProtectedData, AES_BLOCK_LENGTH_IN_BYTES + expectedCiphertextLength, pMac, MAC_LENGTH_IN_BYTES);
@ -82,49 +94,60 @@ namespace Microsoft.AspNet.Security.DataProtection {
return protectedData; return protectedData;
} }
public byte[] Unprotect(byte[] protectedData) { public byte[] Unprotect(byte[] protectedData)
if (protectedData == null) { {
if (protectedData == null)
{
throw new ArgumentNullException("protectedData"); throw new ArgumentNullException("protectedData");
} }
byte[] retVal = null; byte[] retVal = null;
try { try
{
retVal = UnprotectImpl(protectedData); retVal = UnprotectImpl(protectedData);
} }
catch { catch
{
// swallow all exceptions; we'll homogenize // swallow all exceptions; we'll homogenize
} }
if (retVal != null) { if (retVal != null)
{
return retVal; return retVal;
} }
else { else
{
throw CreateGenericCryptographicException(); throw CreateGenericCryptographicException();
} }
} }
private byte[] UnprotectImpl(byte[] protectedData) { private byte[] UnprotectImpl(byte[] protectedData)
{
Debug.Assert(protectedData != null); Debug.Assert(protectedData != null);
// is the protected data even long enough to be valid? // is the protected data even long enough to be valid?
if (protectedData.Length < AES_BLOCK_LENGTH_IN_BYTES /* IV */ + AES_BLOCK_LENGTH_IN_BYTES /* min ciphertext size = 1 block */ + MAC_LENGTH_IN_BYTES) { if (protectedData.Length < AES_BLOCK_LENGTH_IN_BYTES /* IV */+ AES_BLOCK_LENGTH_IN_BYTES /* min ciphertext size = 1 block */+ MAC_LENGTH_IN_BYTES)
{
return null; return null;
} }
fixed (byte* pProtectedData = protectedData) { fixed (byte* pProtectedData = protectedData)
{
// calculate pointer offsets // calculate pointer offsets
byte* pIV = pProtectedData; byte* pIV = pProtectedData;
byte* pCiphertext = &pProtectedData[AES_BLOCK_LENGTH_IN_BYTES]; byte* pCiphertext = &pProtectedData[AES_BLOCK_LENGTH_IN_BYTES];
int ciphertextLength = protectedData.Length - AES_BLOCK_LENGTH_IN_BYTES /* IV */ - MAC_LENGTH_IN_BYTES /* MAC */; int ciphertextLength = protectedData.Length - AES_BLOCK_LENGTH_IN_BYTES /* IV */- MAC_LENGTH_IN_BYTES /* MAC */;
byte* pSuppliedMac = &pCiphertext[ciphertextLength]; byte* pSuppliedMac = &pCiphertext[ciphertextLength];
// first, ensure that the MAC is valid // first, ensure that the MAC is valid
byte* pCalculatedMac = stackalloc byte[MAC_LENGTH_IN_BYTES]; byte* pCalculatedMac = stackalloc byte[MAC_LENGTH_IN_BYTES];
using (var clonedHashHandle = BCryptUtil.DuplicateHash(_hmacHashHandle)) { using (var clonedHashHandle = BCryptUtil.DuplicateHash(_hmacHashHandle))
{
// see comments in Protect(byte[]) for why we duplicate the hash // see comments in Protect(byte[]) for why we duplicate the hash
BCryptUtil.HashData(clonedHashHandle, pProtectedData, AES_BLOCK_LENGTH_IN_BYTES + ciphertextLength, pCalculatedMac, MAC_LENGTH_IN_BYTES); BCryptUtil.HashData(clonedHashHandle, pProtectedData, AES_BLOCK_LENGTH_IN_BYTES + ciphertextLength, pCalculatedMac, MAC_LENGTH_IN_BYTES);
} }
if (!BCryptUtil.BuffersAreEqualSecure(pSuppliedMac, pCalculatedMac, MAC_LENGTH_IN_BYTES)) { if (!BCryptUtil.BuffersAreEqualSecure(pSuppliedMac, pCalculatedMac, MAC_LENGTH_IN_BYTES))
{
return null; // MAC check failed return null; // MAC check failed
} }
@ -132,13 +155,16 @@ namespace Microsoft.AspNet.Security.DataProtection {
// we don't know the actual plaintext length, but we know it must be strictly less than the ciphertext length // we don't know the actual plaintext length, but we know it must be strictly less than the ciphertext length
int plaintextBufferLength = ciphertextLength; int plaintextBufferLength = ciphertextLength;
byte[] heapAllocatedPlaintext = null; byte[] heapAllocatedPlaintext = null;
if (ciphertextLength > Constants.MAX_STACKALLOC_BYTES) { if (ciphertextLength > Constants.MAX_STACKALLOC_BYTES)
{
heapAllocatedPlaintext = new byte[plaintextBufferLength]; heapAllocatedPlaintext = new byte[plaintextBufferLength];
} }
fixed (byte* pHeapAllocatedPlaintext = heapAllocatedPlaintext) { fixed (byte* pHeapAllocatedPlaintext = heapAllocatedPlaintext)
{
byte* pPlaintextBuffer = pHeapAllocatedPlaintext; byte* pPlaintextBuffer = pHeapAllocatedPlaintext;
if (pPlaintextBuffer == null) { if (pPlaintextBuffer == null)
{
byte* temp = stackalloc byte[plaintextBufferLength]; // will be released when frame pops byte* temp = stackalloc byte[plaintextBufferLength]; // will be released when frame pops
pPlaintextBuffer = temp; pPlaintextBuffer = temp;
} }
@ -148,13 +174,13 @@ namespace Microsoft.AspNet.Security.DataProtection {
// truncate the return value to accomodate the plaintext size perfectly // truncate the return value to accomodate the plaintext size perfectly
byte[] retVal = new byte[actualPlaintextLength]; byte[] retVal = new byte[actualPlaintextLength];
fixed (byte* pRetVal = retVal) { fixed (byte* pRetVal = retVal)
BufferUtil.BlockCopy(from: (IntPtr)pPlaintextBuffer, to: (IntPtr)pRetVal, byteCount: actualPlaintextLength); {
BufferUtil.BlockCopy(from: (IntPtr) pPlaintextBuffer, to: (IntPtr) pRetVal, byteCount: actualPlaintextLength);
} }
return retVal; return retVal;
} }
} }
} }
} }
} }

View File

@ -1,7 +1,9 @@
using System; using System;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
public interface IDataProtectionProvider : IDisposable { {
public interface IDataProtectionProvider : IDisposable
{
/// <summary> /// <summary>
/// Given a purpose, returns a new IDataProtector that has unique cryptographic keys tied to this purpose. /// Given a purpose, returns a new IDataProtector that has unique cryptographic keys tied to this purpose.
/// </summary> /// </summary>

View File

@ -1,10 +1,12 @@
using System; using System;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
{
/// <summary> /// <summary>
/// Represents an object that can perform cryptographic operations. /// Represents an object that can perform cryptographic operations.
/// </summary> /// </summary>
public interface IDataProtector : IDisposable { public interface IDataProtector : IDisposable
{
/// <summary> /// <summary>
/// Given a subpurpose, returns a new IDataProtector that has unique cryptographic keys tied <em>both</em> the purpose /// Given a subpurpose, returns a new IDataProtector that has unique cryptographic keys tied <em>both</em> the purpose
/// that was used to create this IDataProtector instance <em>and</em> the purpose that is provided as a parameter /// that was used to create this IDataProtector instance <em>and</em> the purpose that is provided as a parameter

View File

@ -6,6 +6,7 @@ using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information // set of attributes. Change these attribute values to modify the information
// associated with an assembly. // associated with an assembly.
[assembly: AssemblyTitle("Microsoft.AspNet.Security.DataProtection")] [assembly: AssemblyTitle("Microsoft.AspNet.Security.DataProtection")]
[assembly: AssemblyDescription("")] [assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
@ -14,17 +15,18 @@ using System.Runtime.InteropServices;
// Setting ComVisible to false makes the types in this assembly not visible // Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from // to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type. // COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM // The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("130d9afa-6535-42bf-ba70-610b677d5acf")]
[assembly: Guid("130d9afa-6535-42bf-ba70-610b677d5acf")]
[assembly: AssemblyCompany("Microsoft Corporation")] [assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en-US")] [assembly: NeutralResourcesLanguage("en-US")]
// for OOB servicing // for OOB servicing
[assembly: AssemblyMetadata("Serviceable", "True")] [assembly: AssemblyMetadata("Serviceable", "True")]

View File

@ -6,12 +6,13 @@ using System.Security;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Microsoft.AspNet.Security.DataProtection { namespace Microsoft.AspNet.Security.DataProtection
{
#if NET45 #if NET45
[SuppressUnmanagedCodeSecurity] [SuppressUnmanagedCodeSecurity]
#endif #endif
internal unsafe static class UnsafeNativeMethods { internal static unsafe class UnsafeNativeMethods
{
private const string BCRYPT_LIB = "bcrypt.dll"; private const string BCRYPT_LIB = "bcrypt.dll";
private const string KERNEL32_LIB = "kernel32.dll"; private const string KERNEL32_LIB = "kernel32.dll";

View File

@ -1,24 +1,30 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Microsoft.AspNet.Security.DataProtection.Util { namespace Microsoft.AspNet.Security.DataProtection.Util
internal unsafe static class BufferUtil { {
internal static unsafe class BufferUtil
{
private static readonly byte[] _emptyArray = new byte[0]; private static readonly byte[] _emptyArray = new byte[0];
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void BlockCopy(IntPtr from, IntPtr to, int byteCount) { public static void BlockCopy(IntPtr from, IntPtr to, int byteCount)
BlockCopy(from, to, checked((uint)byteCount)); // will be checked before invoking the delegate {
BlockCopy(from, to, checked((uint) byteCount)); // will be checked before invoking the delegate
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void BlockCopy(IntPtr from, IntPtr to, uint byteCount) { public static void BlockCopy(IntPtr from, IntPtr to, uint byteCount)
BlockCopySlow((byte*)from, (byte*)to, byteCount); {
BlockCopySlow((byte*) from, (byte*) to, byteCount);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void BlockCopySlow(byte* from, byte* to, uint byteCount) { private static void BlockCopySlow(byte* from, byte* to, uint byteCount)
{
// slow, but works // slow, but works
while (byteCount-- != 0) { while (byteCount-- != 0)
{
*(to++) = *(from++); *(to++) = *(from++);
} }
} }
@ -26,21 +32,26 @@ namespace Microsoft.AspNet.Security.DataProtection.Util {
/// <summary> /// <summary>
/// Creates a new managed byte[] from unmanaged memory. /// Creates a new managed byte[] from unmanaged memory.
/// </summary> /// </summary>
public static byte[] ToManagedByteArray(byte* ptr, int byteCount) { public static byte[] ToManagedByteArray(byte* ptr, int byteCount)
return ToManagedByteArray(ptr, checked((uint)byteCount)); {
return ToManagedByteArray(ptr, checked((uint) byteCount));
} }
/// <summary> /// <summary>
/// Creates a new managed byte[] from unmanaged memory. /// Creates a new managed byte[] from unmanaged memory.
/// </summary> /// </summary>
public static byte[] ToManagedByteArray(byte* ptr, uint byteCount) { public static byte[] ToManagedByteArray(byte* ptr, uint byteCount)
if (byteCount == 0) { {
if (byteCount == 0)
{
return _emptyArray; // degenerate case return _emptyArray; // degenerate case
} }
else { else
{
byte[] bytes = new byte[byteCount]; byte[] bytes = new byte[byteCount];
fixed (byte* pBytes = bytes) { fixed (byte* pBytes = bytes)
BlockCopy(from: (IntPtr)ptr, to: (IntPtr)pBytes, byteCount: byteCount); {
BlockCopy(from: (IntPtr) ptr, to: (IntPtr) pBytes, byteCount: byteCount);
} }
return bytes; return bytes;
} }
@ -50,17 +61,18 @@ namespace Microsoft.AspNet.Security.DataProtection.Util {
/// Clears a memory buffer. /// Clears a memory buffer.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ZeroMemory(byte* buffer, int byteCount) { public static void ZeroMemory(byte* buffer, int byteCount)
ZeroMemory(buffer, checked((uint)byteCount)); {
ZeroMemory(buffer, checked((uint) byteCount));
} }
/// <summary> /// <summary>
/// Clears a memory buffer. /// Clears a memory buffer.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ZeroMemory(byte* buffer, uint byteCount) { public static void ZeroMemory(byte* buffer, uint byteCount)
UnsafeNativeMethods.RtlZeroMemory((IntPtr)buffer, (UIntPtr)byteCount); // don't require 'checked': uint -> UIntPtr always guaranteed to succeed {
UnsafeNativeMethods.RtlZeroMemory((IntPtr) buffer, (UIntPtr) byteCount); // don't require 'checked': uint -> UIntPtr always guaranteed to succeed
} }
} }
} }