Code cleanup
Rename IAuthenticatedEncryptor2 -> IOptimizedAuthenticatedEncryptor Rename ProtectedMemoryBlob -> Secret Add some missing doc comments explaining
This commit is contained in:
parent
71a2712c5a
commit
8ec6dc3712
|
|
@ -12,7 +12,7 @@ namespace Microsoft.AspNet.Security.DataProtection.AuthenticatedEncryption
|
||||||
public static byte[] Encrypt(this IAuthenticatedEncryptor encryptor, ArraySegment<byte> plaintext, ArraySegment<byte> additionalAuthenticatedData, uint preBufferSize, uint postBufferSize)
|
public static byte[] Encrypt(this IAuthenticatedEncryptor encryptor, ArraySegment<byte> plaintext, ArraySegment<byte> additionalAuthenticatedData, uint preBufferSize, uint postBufferSize)
|
||||||
{
|
{
|
||||||
// Can we call the optimized version?
|
// Can we call the optimized version?
|
||||||
IAuthenticatedEncryptor2 optimizedEncryptor = encryptor as IAuthenticatedEncryptor2;
|
IOptimizedAuthenticatedEncryptor optimizedEncryptor = encryptor as IOptimizedAuthenticatedEncryptor;
|
||||||
if (optimizedEncryptor != null)
|
if (optimizedEncryptor != null)
|
||||||
{
|
{
|
||||||
return optimizedEncryptor.Encrypt(plaintext, additionalAuthenticatedData, preBufferSize, postBufferSize);
|
return optimizedEncryptor.Encrypt(plaintext, additionalAuthenticatedData, preBufferSize, postBufferSize);
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Security.DataProtection.AuthenticatedEncryption
|
||||||
{
|
{
|
||||||
// generate a 512-bit secret randomly
|
// generate a 512-bit secret randomly
|
||||||
const int KDK_SIZE_IN_BYTES = 512 / 8;
|
const int KDK_SIZE_IN_BYTES = 512 / 8;
|
||||||
var secret = ProtectedMemoryBlob.Random(KDK_SIZE_IN_BYTES);
|
var secret = Secret.Random(KDK_SIZE_IN_BYTES);
|
||||||
return new CngCbcAuthenticatedEncryptorConfiguration(_options, secret);
|
return new CngCbcAuthenticatedEncryptorConfiguration(_options, secret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ namespace Microsoft.AspNet.Security.DataProtection.AuthenticatedEncryption
|
||||||
|
|
||||||
// and we're good to go!
|
// and we're good to go!
|
||||||
return new CbcAuthenticatedEncryptor(
|
return new CbcAuthenticatedEncryptor(
|
||||||
keyDerivationKey: new ProtectedMemoryBlob(secret),
|
keyDerivationKey: new Secret(secret),
|
||||||
symmetricAlgorithmHandle: encryptionAlgorithmHandle,
|
symmetricAlgorithmHandle: encryptionAlgorithmHandle,
|
||||||
symmetricAlgorithmKeySizeInBytes: encryptionAlgorithmKeySizeInBits / 8,
|
symmetricAlgorithmKeySizeInBytes: encryptionAlgorithmKeySizeInBits / 8,
|
||||||
hmacAlgorithmHandle: hashAlgorithmHandle);
|
hmacAlgorithmHandle: hashAlgorithmHandle);
|
||||||
|
|
|
||||||
|
|
@ -58,8 +58,8 @@ namespace Microsoft.AspNet.Security.DataProtection.AuthenticatedEncryption
|
||||||
byte[] decryptedSecretBytes = Convert.FromBase64String((string)decryptedSecretElement);
|
byte[] decryptedSecretBytes = Convert.FromBase64String((string)decryptedSecretElement);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var protectedMemoryBlob = new ProtectedMemoryBlob(decryptedSecretBytes);
|
var secret = new Secret(decryptedSecretBytes);
|
||||||
return new CngCbcAuthenticatedEncryptorConfiguration(options, protectedMemoryBlob);
|
return new CngCbcAuthenticatedEncryptorConfiguration(options, secret);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Security.DataProtection.AuthenticatedEncryption
|
||||||
{
|
{
|
||||||
// generate a 512-bit secret randomly
|
// generate a 512-bit secret randomly
|
||||||
const int KDK_SIZE_IN_BYTES = 512 / 8;
|
const int KDK_SIZE_IN_BYTES = 512 / 8;
|
||||||
var secret = ProtectedMemoryBlob.Random(KDK_SIZE_IN_BYTES);
|
var secret = Secret.Random(KDK_SIZE_IN_BYTES);
|
||||||
return new CngGcmAuthenticatedEncryptorConfiguration(_options, secret);
|
return new CngGcmAuthenticatedEncryptorConfiguration(_options, secret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ namespace Microsoft.AspNet.Security.DataProtection.AuthenticatedEncryption
|
||||||
|
|
||||||
// and we're good to go!
|
// and we're good to go!
|
||||||
return new GcmAuthenticatedEncryptor(
|
return new GcmAuthenticatedEncryptor(
|
||||||
keyDerivationKey: new ProtectedMemoryBlob(secret),
|
keyDerivationKey: new Secret(secret),
|
||||||
symmetricAlgorithmHandle: encryptionAlgorithmHandle,
|
symmetricAlgorithmHandle: encryptionAlgorithmHandle,
|
||||||
symmetricAlgorithmKeySizeInBytes: encryptionAlgorithmKeySizeInBits / 8);
|
symmetricAlgorithmKeySizeInBytes: encryptionAlgorithmKeySizeInBits / 8);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,8 @@ namespace Microsoft.AspNet.Security.DataProtection.AuthenticatedEncryption
|
||||||
byte[] decryptedSecretBytes = Convert.FromBase64String((string)decryptedSecretElement);
|
byte[] decryptedSecretBytes = Convert.FromBase64String((string)decryptedSecretElement);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var protectedMemoryBlob = new ProtectedMemoryBlob(decryptedSecretBytes);
|
var secret = new Secret(decryptedSecretBytes);
|
||||||
return new CngGcmAuthenticatedEncryptorConfiguration(options, protectedMemoryBlob);
|
return new CngGcmAuthenticatedEncryptorConfiguration(options, secret);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Security.DataProtection.AuthenticatedEncryption
|
|
||||||
{
|
|
||||||
internal interface IAuthenticatedEncryptor2 : IAuthenticatedEncryptor
|
|
||||||
{
|
|
||||||
byte[] Encrypt(ArraySegment<byte> plaintext, ArraySegment<byte> additionalAuthenticatedData, uint preBufferSize, uint postBufferSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Security.DataProtection.AuthenticatedEncryption
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An optimized encryptor that can avoid buffer allocations in common code paths.
|
||||||
|
/// </summary>
|
||||||
|
internal interface IOptimizedAuthenticatedEncryptor : IAuthenticatedEncryptor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Encrypts and tamper-proofs a piece of data.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="plaintext">The plaintext to encrypt. This input may be zero bytes in length.</param>
|
||||||
|
/// <param name="additionalAuthenticatedData">A piece of data which will not be included in
|
||||||
|
/// the returned ciphertext but which will still be covered by the authentication tag.
|
||||||
|
/// This input may be zero bytes in length. The same AAD must be specified in the corresponding
|
||||||
|
/// call to Decrypt.</param>
|
||||||
|
/// <param name="preBufferSize">The number of bytes to include before the ciphertext in the return value.</param>
|
||||||
|
/// <param name="postBufferSize">The number of bytes to include after the ciphertext in the return value.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A buffer containing the ciphertext and authentication tag.
|
||||||
|
/// If a non-zero pre-buffer or post-buffer size is specified, the returned buffer will contain appropriate padding
|
||||||
|
/// on either side of the ciphertext and authentication tag. For instance, if a pre-buffer size of 4 and a post-buffer
|
||||||
|
/// size of 7 are specified, and if the ciphertext and tag are a combined 48 bytes, then the returned buffer will
|
||||||
|
/// be a total 59 bytes in length. The first four bytes will be undefined, the next 48 bytes will contain the
|
||||||
|
/// ciphertext and tag, and the last seven bytes will be undefined. The intent is that the caller can overwrite the
|
||||||
|
/// pre-buffer or post-buffer with a header or footer without needing to allocate an additional buffer object.
|
||||||
|
/// </returns>
|
||||||
|
/// <remarks>All cryptography-related exceptions should be homogenized to CryptographicException.</remarks>
|
||||||
|
byte[] Encrypt(ArraySegment<byte> plaintext, ArraySegment<byte> additionalAuthenticatedData, uint preBufferSize, uint postBufferSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -21,10 +21,10 @@ namespace Microsoft.AspNet.Security.DataProtection.AuthenticatedEncryption
|
||||||
// generate a 512-bit secret randomly
|
// generate a 512-bit secret randomly
|
||||||
const int KDK_SIZE_IN_BYTES = 512 / 8;
|
const int KDK_SIZE_IN_BYTES = 512 / 8;
|
||||||
byte[] kdk = ManagedGenRandomImpl.Instance.GenRandom(KDK_SIZE_IN_BYTES);
|
byte[] kdk = ManagedGenRandomImpl.Instance.GenRandom(KDK_SIZE_IN_BYTES);
|
||||||
ProtectedMemoryBlob secret;
|
Secret secret;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
secret = new ProtectedMemoryBlob(kdk);
|
secret = new Secret(kdk);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ namespace Microsoft.AspNet.Security.DataProtection.AuthenticatedEncryption
|
||||||
|
|
||||||
// We're good to go!
|
// We're good to go!
|
||||||
return new ManagedAuthenticatedEncryptor(
|
return new ManagedAuthenticatedEncryptor(
|
||||||
keyDerivationKey: new ProtectedMemoryBlob(secret),
|
keyDerivationKey: new Secret(secret),
|
||||||
symmetricAlgorithmFactory: encryptorFactory,
|
symmetricAlgorithmFactory: encryptorFactory,
|
||||||
symmetricAlgorithmKeySizeInBytes: keySizeInBytes,
|
symmetricAlgorithmKeySizeInBytes: keySizeInBytes,
|
||||||
validationAlgorithmFactory: validatorFactory);
|
validationAlgorithmFactory: validatorFactory);
|
||||||
|
|
|
||||||
|
|
@ -56,8 +56,8 @@ namespace Microsoft.AspNet.Security.DataProtection.AuthenticatedEncryption
|
||||||
byte[] decryptedSecretBytes = Convert.FromBase64String((string)decryptedSecretElement);
|
byte[] decryptedSecretBytes = Convert.FromBase64String((string)decryptedSecretElement);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var protectedMemoryBlob = new ProtectedMemoryBlob(decryptedSecretBytes);
|
var secret = new Secret(decryptedSecretBytes);
|
||||||
return new ManagedAuthenticatedEncryptorConfiguration(options, protectedMemoryBlob);
|
return new ManagedAuthenticatedEncryptorConfiguration(options, secret);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,20 @@ namespace Microsoft.AspNet.Security.DataProtection
|
||||||
bytePtr[3] = (byte)(value);
|
bytePtr[3] = (byte)(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes an unsigned 32-bit value to a memory address, big-endian.
|
||||||
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void WriteTo(ref byte* ptr, uint value)
|
||||||
|
{
|
||||||
|
byte* pTemp = ptr;
|
||||||
|
pTemp[0] = (byte)(value >> 24);
|
||||||
|
pTemp[1] = (byte)(value >> 16);
|
||||||
|
pTemp[2] = (byte)(value >> 8);
|
||||||
|
pTemp[3] = (byte)(value);
|
||||||
|
ptr = &pTemp[4];
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes a signed 32-bit value to a memory address, big-endian.
|
/// Writes a signed 32-bit value to a memory address, big-endian.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Security.Cryptography;
|
|
||||||
using Microsoft.AspNet.Security.DataProtection.SafeHandles;
|
using Microsoft.AspNet.Security.DataProtection.SafeHandles;
|
||||||
using Microsoft.AspNet.Security.DataProtection.SP800_108;
|
using Microsoft.AspNet.Security.DataProtection.SP800_108;
|
||||||
|
|
||||||
|
|
@ -41,7 +40,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Cng
|
||||||
private readonly uint _symmetricAlgorithmBlockSizeInBytes;
|
private readonly uint _symmetricAlgorithmBlockSizeInBytes;
|
||||||
private readonly uint _symmetricAlgorithmSubkeyLengthInBytes;
|
private readonly uint _symmetricAlgorithmSubkeyLengthInBytes;
|
||||||
|
|
||||||
public CbcAuthenticatedEncryptor(ProtectedMemoryBlob keyDerivationKey, BCryptAlgorithmHandle symmetricAlgorithmHandle, uint symmetricAlgorithmKeySizeInBytes, BCryptAlgorithmHandle hmacAlgorithmHandle, IBCryptGenRandom genRandom = null)
|
public CbcAuthenticatedEncryptor(Secret keyDerivationKey, BCryptAlgorithmHandle symmetricAlgorithmHandle, uint symmetricAlgorithmKeySizeInBytes, BCryptAlgorithmHandle hmacAlgorithmHandle, IBCryptGenRandom genRandom = null)
|
||||||
{
|
{
|
||||||
CryptoUtil.Assert(KEY_MODIFIER_SIZE_IN_BYTES <= symmetricAlgorithmKeySizeInBytes && symmetricAlgorithmKeySizeInBytes <= Constants.MAX_STACKALLOC_BYTES,
|
CryptoUtil.Assert(KEY_MODIFIER_SIZE_IN_BYTES <= symmetricAlgorithmKeySizeInBytes && symmetricAlgorithmKeySizeInBytes <= Constants.MAX_STACKALLOC_BYTES,
|
||||||
"KEY_MODIFIER_SIZE_IN_BYTES <= symmetricAlgorithmKeySizeInBytes && symmetricAlgorithmKeySizeInBytes <= Constants.MAX_STACKALLOC_BYTES");
|
"KEY_MODIFIER_SIZE_IN_BYTES <= symmetricAlgorithmKeySizeInBytes && symmetricAlgorithmKeySizeInBytes <= Constants.MAX_STACKALLOC_BYTES");
|
||||||
|
|
@ -88,16 +87,12 @@ namespace Microsoft.AspNet.Security.DataProtection.Cng
|
||||||
*(ptr++) = 0; // 0x00 = CBC encryption + HMAC authentication
|
*(ptr++) = 0; // 0x00 = CBC encryption + HMAC authentication
|
||||||
|
|
||||||
// Next is information about the symmetric algorithm (key size followed by block size)
|
// Next is information about the symmetric algorithm (key size followed by block size)
|
||||||
BitHelpers.WriteTo(ptr, _symmetricAlgorithmSubkeyLengthInBytes);
|
BitHelpers.WriteTo(ref ptr, _symmetricAlgorithmSubkeyLengthInBytes);
|
||||||
ptr += sizeof(uint);
|
BitHelpers.WriteTo(ref ptr, _symmetricAlgorithmBlockSizeInBytes);
|
||||||
BitHelpers.WriteTo(ptr, _symmetricAlgorithmBlockSizeInBytes);
|
|
||||||
ptr += sizeof(uint);
|
|
||||||
|
|
||||||
// Next is information about the HMAC algorithm (key size followed by digest size)
|
// Next is information about the HMAC algorithm (key size followed by digest size)
|
||||||
BitHelpers.WriteTo(ptr, _hmacAlgorithmSubkeyLengthInBytes);
|
BitHelpers.WriteTo(ref ptr, _hmacAlgorithmSubkeyLengthInBytes);
|
||||||
ptr += sizeof(uint);
|
BitHelpers.WriteTo(ref ptr, _hmacAlgorithmDigestLengthInBytes);
|
||||||
BitHelpers.WriteTo(ptr, _hmacAlgorithmDigestLengthInBytes);
|
|
||||||
ptr += sizeof(uint);
|
|
||||||
|
|
||||||
// See the design document for an explanation of the following code.
|
// See the design document for an explanation of the following code.
|
||||||
byte[] tempKeys = new byte[_symmetricAlgorithmSubkeyLengthInBytes + _hmacAlgorithmSubkeyLengthInBytes];
|
byte[] tempKeys = new byte[_symmetricAlgorithmSubkeyLengthInBytes + _hmacAlgorithmSubkeyLengthInBytes];
|
||||||
|
|
@ -348,7 +343,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Cng
|
||||||
|
|
||||||
using (var symmetricKeyHandle = _symmetricAlgorithmHandle.GenerateSymmetricKey(pbSymmetricEncryptionSubkey, _symmetricAlgorithmSubkeyLengthInBytes))
|
using (var symmetricKeyHandle = _symmetricAlgorithmHandle.GenerateSymmetricKey(pbSymmetricEncryptionSubkey, _symmetricAlgorithmSubkeyLengthInBytes))
|
||||||
{
|
{
|
||||||
// We can't assume PKCS#7 padding (maybe the underlying provided is using CTS),
|
// We can't assume PKCS#7 padding (maybe the underlying provider is really using CTS),
|
||||||
// so we need to query the padded output size before we can allocate the return value array.
|
// so we need to query the padded output size before we can allocate the return value array.
|
||||||
uint cbOutputCiphertext = GetCbcEncryptedOutputSizeWithPadding(symmetricKeyHandle, pbPlaintext, cbPlaintext);
|
uint cbOutputCiphertext = GetCbcEncryptedOutputSizeWithPadding(symmetricKeyHandle, pbPlaintext, cbPlaintext);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,14 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Security.Cryptography;
|
|
||||||
using Microsoft.AspNet.Security.DataProtection.AuthenticatedEncryption;
|
using Microsoft.AspNet.Security.DataProtection.AuthenticatedEncryption;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Security.DataProtection.Cng
|
namespace Microsoft.AspNet.Security.DataProtection.Cng
|
||||||
{
|
{
|
||||||
internal unsafe abstract class CngAuthenticatedEncryptorBase : IAuthenticatedEncryptor, IDisposable
|
/// <summary>
|
||||||
|
/// Base class used for all CNG-related authentication encryption operations.
|
||||||
|
/// </summary>
|
||||||
|
internal unsafe abstract class CngAuthenticatedEncryptorBase : IOptimizedAuthenticatedEncryptor, IDisposable
|
||||||
{
|
{
|
||||||
public byte[] Decrypt(ArraySegment<byte> ciphertext, ArraySegment<byte> additionalAuthenticatedData)
|
public byte[] Decrypt(ArraySegment<byte> ciphertext, ArraySegment<byte> additionalAuthenticatedData)
|
||||||
{
|
{
|
||||||
|
|
@ -30,7 +32,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Cng
|
||||||
pbAdditionalAuthenticatedData: (pbAdditionalAuthenticatedDataArray != null) ? &pbAdditionalAuthenticatedDataArray[additionalAuthenticatedData.Offset] : &dummy,
|
pbAdditionalAuthenticatedData: (pbAdditionalAuthenticatedDataArray != null) ? &pbAdditionalAuthenticatedDataArray[additionalAuthenticatedData.Offset] : &dummy,
|
||||||
cbAdditionalAuthenticatedData: (uint)additionalAuthenticatedData.Count);
|
cbAdditionalAuthenticatedData: (uint)additionalAuthenticatedData.Count);
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (!(ex is CryptographicException))
|
catch (Exception ex) when (ex.RequiresHomogenization())
|
||||||
{
|
{
|
||||||
// Homogenize to CryptographicException.
|
// Homogenize to CryptographicException.
|
||||||
throw Error.CryptCommon_GenericError(ex);
|
throw Error.CryptCommon_GenericError(ex);
|
||||||
|
|
@ -71,7 +73,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Cng
|
||||||
cbPreBuffer: preBufferSize,
|
cbPreBuffer: preBufferSize,
|
||||||
cbPostBuffer: postBufferSize);
|
cbPostBuffer: postBufferSize);
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (!(ex is CryptographicException))
|
catch (Exception ex) when (ex.RequiresHomogenization())
|
||||||
{
|
{
|
||||||
// Homogenize to CryptographicException.
|
// Homogenize to CryptographicException.
|
||||||
throw Error.CryptCommon_GenericError(ex);
|
throw Error.CryptCommon_GenericError(ex);
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Cng
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProtectedMemoryBlob UnprotectWithDpapi(byte[] protectedSecret)
|
public static Secret UnprotectWithDpapi(byte[] protectedSecret)
|
||||||
{
|
{
|
||||||
Debug.Assert(protectedSecret != null);
|
Debug.Assert(protectedSecret != null);
|
||||||
|
|
||||||
|
|
@ -185,7 +185,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Cng
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static ProtectedMemoryBlob UnprotectWithDpapiImpl(byte* pbProtectedData, uint cbProtectedData, byte* pbOptionalEntropy, uint cbOptionalEntropy)
|
internal static Secret UnprotectWithDpapiImpl(byte* pbProtectedData, uint cbProtectedData, byte* pbOptionalEntropy, uint cbOptionalEntropy)
|
||||||
{
|
{
|
||||||
byte dummy; // provides a valid memory address if the secret or entropy has zero length
|
byte dummy; // provides a valid memory address if the secret or entropy has zero length
|
||||||
|
|
||||||
|
|
@ -220,7 +220,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Cng
|
||||||
throw new CryptographicException(errorCode);
|
throw new CryptographicException(errorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ProtectedMemoryBlob(dataOut.pbData, checked((int)dataOut.cbData));
|
return new Secret(dataOut.pbData, checked((int)dataOut.cbData));
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
@ -234,7 +234,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Cng
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProtectedMemoryBlob UnprotectWithDpapiNG(byte[] protectedData)
|
public static Secret UnprotectWithDpapiNG(byte[] protectedData)
|
||||||
{
|
{
|
||||||
Debug.Assert(protectedData != null);
|
Debug.Assert(protectedData != null);
|
||||||
|
|
||||||
|
|
@ -247,7 +247,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Cng
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProtectedMemoryBlob UnprotectWithDpapiNGImpl(byte* pbData, uint cbData)
|
private static Secret UnprotectWithDpapiNGImpl(byte* pbData, uint cbData)
|
||||||
{
|
{
|
||||||
Debug.Assert(pbData != null);
|
Debug.Assert(pbData != null);
|
||||||
|
|
||||||
|
|
@ -280,7 +280,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Cng
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
unencryptedPayloadHandle.DangerousAddRef(ref handleAcquired);
|
unencryptedPayloadHandle.DangerousAddRef(ref handleAcquired);
|
||||||
return new ProtectedMemoryBlob((byte*)unencryptedPayloadHandle.DangerousGetHandle(), checked((int)cbUnencryptedPayload));
|
return new Secret((byte*)unencryptedPayloadHandle.DangerousGetHandle(), checked((int)cbUnencryptedPayload));
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Cng
|
||||||
private readonly BCryptAlgorithmHandle _symmetricAlgorithmHandle;
|
private readonly BCryptAlgorithmHandle _symmetricAlgorithmHandle;
|
||||||
private readonly uint _symmetricAlgorithmSubkeyLengthInBytes;
|
private readonly uint _symmetricAlgorithmSubkeyLengthInBytes;
|
||||||
|
|
||||||
public GcmAuthenticatedEncryptor(ProtectedMemoryBlob keyDerivationKey, BCryptAlgorithmHandle symmetricAlgorithmHandle, uint symmetricAlgorithmKeySizeInBytes, IBCryptGenRandom genRandom = null)
|
public GcmAuthenticatedEncryptor(Secret keyDerivationKey, BCryptAlgorithmHandle symmetricAlgorithmHandle, uint symmetricAlgorithmKeySizeInBytes, IBCryptGenRandom genRandom = null)
|
||||||
{
|
{
|
||||||
CryptoUtil.Assert(KEY_MODIFIER_SIZE_IN_BYTES <= symmetricAlgorithmKeySizeInBytes && symmetricAlgorithmKeySizeInBytes <= Constants.MAX_STACKALLOC_BYTES,
|
CryptoUtil.Assert(KEY_MODIFIER_SIZE_IN_BYTES <= symmetricAlgorithmKeySizeInBytes && symmetricAlgorithmKeySizeInBytes <= Constants.MAX_STACKALLOC_BYTES,
|
||||||
"KEY_MODIFIER_SIZE_IN_BYTES <= symmetricAlgorithmKeySizeInBytes && symmetricAlgorithmKeySizeInBytes <= Constants.MAX_STACKALLOC_BYTES");
|
"KEY_MODIFIER_SIZE_IN_BYTES <= symmetricAlgorithmKeySizeInBytes && symmetricAlgorithmKeySizeInBytes <= Constants.MAX_STACKALLOC_BYTES");
|
||||||
|
|
@ -67,14 +67,10 @@ namespace Microsoft.AspNet.Security.DataProtection.Cng
|
||||||
*(ptr++) = 1; // 0x01 = GCM encryption + authentication
|
*(ptr++) = 1; // 0x01 = GCM encryption + authentication
|
||||||
|
|
||||||
// Next is information about the symmetric algorithm (key size, nonce size, block size, tag size)
|
// Next is information about the symmetric algorithm (key size, nonce size, block size, tag size)
|
||||||
BitHelpers.WriteTo(ptr, _symmetricAlgorithmSubkeyLengthInBytes);
|
BitHelpers.WriteTo(ref ptr, _symmetricAlgorithmSubkeyLengthInBytes);
|
||||||
ptr += sizeof(uint);
|
BitHelpers.WriteTo(ref ptr, NONCE_SIZE_IN_BYTES);
|
||||||
BitHelpers.WriteTo(ptr, NONCE_SIZE_IN_BYTES);
|
BitHelpers.WriteTo(ref ptr, TAG_SIZE_IN_BYTES); // block size = tag size
|
||||||
ptr += sizeof(uint);
|
BitHelpers.WriteTo(ref ptr, TAG_SIZE_IN_BYTES);
|
||||||
BitHelpers.WriteTo(ptr, TAG_SIZE_IN_BYTES); // block size
|
|
||||||
ptr += sizeof(uint);
|
|
||||||
BitHelpers.WriteTo(ptr, TAG_SIZE_IN_BYTES);
|
|
||||||
ptr += sizeof(uint);
|
|
||||||
|
|
||||||
// See the design document for an explanation of the following code.
|
// See the design document for an explanation of the following code.
|
||||||
byte[] tempKeys = new byte[_symmetricAlgorithmSubkeyLengthInBytes];
|
byte[] tempKeys = new byte[_symmetricAlgorithmSubkeyLengthInBytes];
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,8 @@ namespace Microsoft.AspNet.Security.DataProtection
|
||||||
throw new CryptographicException("Assertion failed: " + message);
|
throw new CryptographicException("Assertion failed: " + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allows callers to write "var x = Method() ?? Fail<T>(message);" as a convenience to guard
|
||||||
|
// against a method returning null unexpectedly.
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public static T Fail<T>(string message) where T : class
|
public static T Fail<T>(string message) where T : class
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ namespace Microsoft.AspNet.Security.DataProtection
|
||||||
byte[] protectedDataAsBytes = protector.Protect(unprotectedDataAsBytes);
|
byte[] protectedDataAsBytes = protector.Protect(unprotectedDataAsBytes);
|
||||||
return WebEncoders.Base64UrlEncode(protectedDataAsBytes);
|
return WebEncoders.Base64UrlEncode(protectedDataAsBytes);
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (!(ex is CryptographicException))
|
catch (Exception ex) when (ex.RequiresHomogenization())
|
||||||
{
|
{
|
||||||
// Homogenize exceptions to CryptographicException
|
// Homogenize exceptions to CryptographicException
|
||||||
throw Error.CryptCommon_GenericError(ex);
|
throw Error.CryptCommon_GenericError(ex);
|
||||||
|
|
@ -60,7 +60,7 @@ namespace Microsoft.AspNet.Security.DataProtection
|
||||||
byte[] unprotectedDataAsBytes = protector.Unprotect(protectedDataAsBytes);
|
byte[] unprotectedDataAsBytes = protector.Unprotect(protectedDataAsBytes);
|
||||||
return CryptoUtil.SecureUtf8Encoding.GetString(unprotectedDataAsBytes);
|
return CryptoUtil.SecureUtf8Encoding.GetString(unprotectedDataAsBytes);
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (!(ex is CryptographicException))
|
catch (Exception ex) when (ex.RequiresHomogenization())
|
||||||
{
|
{
|
||||||
// Homogenize exceptions to CryptographicException
|
// Homogenize exceptions to CryptographicException
|
||||||
throw Error.CryptCommon_GenericError(ex);
|
throw Error.CryptCommon_GenericError(ex);
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Dpapi
|
||||||
return _shim.Protect(unprotectedData, _combinedPurposes, _scope)
|
return _shim.Protect(unprotectedData, _combinedPurposes, _scope)
|
||||||
?? CryptoUtil.Fail<byte[]>("Null return value.");
|
?? CryptoUtil.Fail<byte[]>("Null return value.");
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (!(ex is CryptographicException))
|
catch (Exception ex) when (ex.RequiresHomogenization())
|
||||||
{
|
{
|
||||||
// Homogenize to CryptographicException
|
// Homogenize to CryptographicException
|
||||||
throw Error.CryptCommon_GenericError(ex);
|
throw Error.CryptCommon_GenericError(ex);
|
||||||
|
|
@ -57,7 +57,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Dpapi
|
||||||
return _shim.Unprotect(protectedData, _combinedPurposes, _scope)
|
return _shim.Unprotect(protectedData, _combinedPurposes, _scope)
|
||||||
?? CryptoUtil.Fail<byte[]>("Null return value.");
|
?? CryptoUtil.Fail<byte[]>("Null return value.");
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (!(ex is CryptographicException))
|
catch (Exception ex) when (ex.RequiresHomogenization())
|
||||||
{
|
{
|
||||||
// Homogenize to CryptographicException
|
// Homogenize to CryptographicException
|
||||||
throw Error.CryptCommon_GenericError(ex);
|
throw Error.CryptCommon_GenericError(ex);
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Dpapi
|
||||||
public byte[] Unprotect(byte[] encryptedData, byte[] optionalEntropy, DataProtectionScope scope)
|
public byte[] Unprotect(byte[] encryptedData, byte[] optionalEntropy, DataProtectionScope scope)
|
||||||
{
|
{
|
||||||
#if ASPNETCORE50
|
#if ASPNETCORE50
|
||||||
ProtectedMemoryBlob blob;
|
Secret blob;
|
||||||
fixed (byte* pbEncryptedData = encryptedData)
|
fixed (byte* pbEncryptedData = encryptedData)
|
||||||
{
|
{
|
||||||
fixed (byte* pbOptionalEntropy = optionalEntropy)
|
fixed (byte* pbOptionalEntropy = optionalEntropy)
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ namespace Microsoft.AspNet.Security.DataProtection
|
||||||
// Currently hardcoded to a 512-bit KDK.
|
// Currently hardcoded to a 512-bit KDK.
|
||||||
private const int NUM_BYTES_IN_KDK = 512 / 8;
|
private const int NUM_BYTES_IN_KDK = 512 / 8;
|
||||||
|
|
||||||
public IAuthenticatedEncryptor DefaultAuthenticatedEncryptor { get; } = new T().CreateAuthenticatedEncryptor(ProtectedMemoryBlob.Random(NUM_BYTES_IN_KDK));
|
public IAuthenticatedEncryptor DefaultAuthenticatedEncryptor { get; } = new T().CreateAuthenticatedEncryptor(Secret.Random(NUM_BYTES_IN_KDK));
|
||||||
|
|
||||||
public Guid DefaultKeyId { get; } = default(Guid);
|
public Guid DefaultKeyId { get; } = default(Guid);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Security.DataProtection
|
||||||
|
{
|
||||||
|
internal static class ExceptionExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether an exception must be homogenized by being wrapped inside a
|
||||||
|
/// CryptographicException before being rethrown.
|
||||||
|
/// </summary>
|
||||||
|
public static bool RequiresHomogenization(this Exception ex)
|
||||||
|
{
|
||||||
|
return !(ex is CryptographicException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Security.DataProtection
|
||||||
public interface ISecret : IDisposable
|
public interface ISecret : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The length (in bytes) of the value.
|
/// The length (in bytes) of the secret value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int Length { get; }
|
int Length { get; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ namespace Microsoft.AspNet.Security.DataProtection.KeyManagement
|
||||||
postBufferSize: 0);
|
postBufferSize: 0);
|
||||||
CryptoUtil.Assert(retVal != null && retVal.Length >= sizeof(uint) + sizeof(Guid), "retVal != null && retVal.Length >= sizeof(uint) + sizeof(Guid)");
|
CryptoUtil.Assert(retVal != null && retVal.Length >= sizeof(uint) + sizeof(Guid), "retVal != null && retVal.Length >= sizeof(uint) + sizeof(Guid)");
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (!(ex is CryptographicException))
|
catch (Exception ex) when (ex.RequiresHomogenization())
|
||||||
{
|
{
|
||||||
// homogenize all errors to CryptographicException
|
// homogenize all errors to CryptographicException
|
||||||
throw Error.Common_EncryptionFailed(ex);
|
throw Error.Common_EncryptionFailed(ex);
|
||||||
|
|
@ -247,7 +247,7 @@ namespace Microsoft.AspNet.Security.DataProtection.KeyManagement
|
||||||
CryptoUtil.Assert(retVal != null, "retVal != null");
|
CryptoUtil.Assert(retVal != null, "retVal != null");
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (!(ex is CryptographicException))
|
catch (Exception ex) when (ex.RequiresHomogenization())
|
||||||
{
|
{
|
||||||
// homogenize all failures to CryptographicException
|
// homogenize all failures to CryptographicException
|
||||||
throw Error.DecryptionFailed(ex);
|
throw Error.DecryptionFailed(ex);
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ namespace Microsoft.AspNet.Security.DataProtection.KeyManagement
|
||||||
var thisKey = ParseKeyElement(element);
|
var thisKey = ParseKeyElement(element);
|
||||||
if (idToKeyMap.ContainsKey(thisKey.KeyId))
|
if (idToKeyMap.ContainsKey(thisKey.KeyId))
|
||||||
{
|
{
|
||||||
CryptoUtil.Fail("TODO: Duplicate key.");
|
throw CryptoUtil.Fail("TODO: Duplicate key.");
|
||||||
}
|
}
|
||||||
idToKeyMap.Add(thisKey.KeyId, thisKey);
|
idToKeyMap.Add(thisKey.KeyId, thisKey);
|
||||||
}
|
}
|
||||||
|
|
@ -140,7 +140,7 @@ namespace Microsoft.AspNet.Security.DataProtection.KeyManagement
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CryptoUtil.Fail("TODO: Unknown element.");
|
throw CryptoUtil.Fail("TODO: Unknown element.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Managed
|
||||||
|
|
||||||
private readonly byte[] _contextHeader;
|
private readonly byte[] _contextHeader;
|
||||||
private readonly IManagedGenRandom _genRandom;
|
private readonly IManagedGenRandom _genRandom;
|
||||||
private readonly ProtectedMemoryBlob _keyDerivationKey;
|
private readonly Secret _keyDerivationKey;
|
||||||
private readonly Func<SymmetricAlgorithm> _symmetricAlgorithmFactory;
|
private readonly Func<SymmetricAlgorithm> _symmetricAlgorithmFactory;
|
||||||
private readonly int _symmetricAlgorithmBlockSizeInBytes;
|
private readonly int _symmetricAlgorithmBlockSizeInBytes;
|
||||||
private readonly int _symmetricAlgorithmSubkeyLengthInBytes;
|
private readonly int _symmetricAlgorithmSubkeyLengthInBytes;
|
||||||
|
|
@ -44,7 +44,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Managed
|
||||||
private readonly int _validationAlgorithmSubkeyLengthInBytes;
|
private readonly int _validationAlgorithmSubkeyLengthInBytes;
|
||||||
private readonly Func<KeyedHashAlgorithm> _validationAlgorithmFactory;
|
private readonly Func<KeyedHashAlgorithm> _validationAlgorithmFactory;
|
||||||
|
|
||||||
public ManagedAuthenticatedEncryptor(ProtectedMemoryBlob keyDerivationKey, Func<SymmetricAlgorithm> symmetricAlgorithmFactory, int symmetricAlgorithmKeySizeInBytes, Func<KeyedHashAlgorithm> validationAlgorithmFactory, IManagedGenRandom genRandom = null)
|
public ManagedAuthenticatedEncryptor(Secret keyDerivationKey, Func<SymmetricAlgorithm> symmetricAlgorithmFactory, int symmetricAlgorithmKeySizeInBytes, Func<KeyedHashAlgorithm> validationAlgorithmFactory, IManagedGenRandom genRandom = null)
|
||||||
{
|
{
|
||||||
CryptoUtil.Assert(KEY_MODIFIER_SIZE_IN_BYTES <= symmetricAlgorithmKeySizeInBytes && symmetricAlgorithmKeySizeInBytes <= Constants.MAX_STACKALLOC_BYTES,
|
CryptoUtil.Assert(KEY_MODIFIER_SIZE_IN_BYTES <= symmetricAlgorithmKeySizeInBytes && symmetricAlgorithmKeySizeInBytes <= Constants.MAX_STACKALLOC_BYTES,
|
||||||
"KEY_MODIFIER_SIZE_IN_BYTES <= symmetricAlgorithmKeySizeInBytes && symmetricAlgorithmKeySizeInBytes <= Constants.MAX_STACKALLOC_BYTES");
|
"KEY_MODIFIER_SIZE_IN_BYTES <= symmetricAlgorithmKeySizeInBytes && symmetricAlgorithmKeySizeInBytes <= Constants.MAX_STACKALLOC_BYTES");
|
||||||
|
|
@ -278,7 +278,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Managed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (!(ex is CryptographicException))
|
catch (Exception ex) when (ex.RequiresHomogenization())
|
||||||
{
|
{
|
||||||
// Homogenize all exceptions to CryptographicException.
|
// Homogenize all exceptions to CryptographicException.
|
||||||
throw Error.CryptCommon_GenericError(ex);
|
throw Error.CryptCommon_GenericError(ex);
|
||||||
|
|
@ -382,7 +382,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Managed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (!(ex is CryptographicException))
|
catch (Exception ex) when (ex.RequiresHomogenization())
|
||||||
{
|
{
|
||||||
// Homogenize all exceptions to CryptographicException.
|
// Homogenize all exceptions to CryptographicException.
|
||||||
throw Error.CryptCommon_GenericError(ex);
|
throw Error.CryptCommon_GenericError(ex);
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ namespace Microsoft.AspNet.Security.DataProtection.SP800_108
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a provider from the given secret.
|
// Creates a provider from the given secret.
|
||||||
public static ISP800_108_CTR_HMACSHA512Provider CreateProvider(ProtectedMemoryBlob kdk)
|
public static ISP800_108_CTR_HMACSHA512Provider CreateProvider(Secret kdk)
|
||||||
{
|
{
|
||||||
uint secretLengthInBytes = checked((uint)kdk.Length);
|
uint secretLengthInBytes = checked((uint)kdk.Length);
|
||||||
if (secretLengthInBytes == 0)
|
if (secretLengthInBytes == 0)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,10 @@ using Microsoft.AspNet.Security.DataProtection.SafeHandles;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Security.DataProtection
|
namespace Microsoft.AspNet.Security.DataProtection
|
||||||
{
|
{
|
||||||
public unsafe sealed class ProtectedMemoryBlob : IDisposable, ISecret
|
/// <summary>
|
||||||
|
/// Represents a secret value stored in memory.
|
||||||
|
/// </summary>
|
||||||
|
public unsafe sealed class Secret : IDisposable, ISecret
|
||||||
{
|
{
|
||||||
// from wincrypt.h
|
// from wincrypt.h
|
||||||
private const uint CRYPTPROTECTMEMORY_BLOCK_SIZE = 16;
|
private const uint CRYPTPROTECTMEMORY_BLOCK_SIZE = 16;
|
||||||
|
|
@ -16,42 +19,57 @@ namespace Microsoft.AspNet.Security.DataProtection
|
||||||
private readonly SecureLocalAllocHandle _localAllocHandle;
|
private readonly SecureLocalAllocHandle _localAllocHandle;
|
||||||
private readonly uint _plaintextLength;
|
private readonly uint _plaintextLength;
|
||||||
|
|
||||||
public ProtectedMemoryBlob(ArraySegment<byte> plaintext)
|
/// <summary>
|
||||||
|
/// Creates a new Secret from the provided input value, where the input value
|
||||||
|
/// is specified as an array segment.
|
||||||
|
/// </summary>
|
||||||
|
public Secret(ArraySegment<byte> value)
|
||||||
{
|
{
|
||||||
plaintext.Validate();
|
value.Validate();
|
||||||
|
|
||||||
_localAllocHandle = Protect(plaintext);
|
_localAllocHandle = Protect(value);
|
||||||
_plaintextLength = (uint)plaintext.Count;
|
_plaintextLength = (uint)value.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProtectedMemoryBlob(byte[] plaintext)
|
/// <summary>
|
||||||
: this(new ArraySegment<byte>(plaintext))
|
/// Creates a new Secret from the provided input value, where the input value
|
||||||
|
/// is specified as an array.
|
||||||
|
/// </summary>
|
||||||
|
public Secret(byte[] value)
|
||||||
|
: this(new ArraySegment<byte>(value))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProtectedMemoryBlob(byte* plaintext, int plaintextLength)
|
/// <summary>
|
||||||
|
/// Creates a new Secret from the provided input value, where the input value
|
||||||
|
/// is specified as a pointer to unmanaged memory.
|
||||||
|
/// </summary>
|
||||||
|
public Secret(byte* secret, int secretLength)
|
||||||
{
|
{
|
||||||
if (plaintext == null)
|
if (secret == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("plaintext");
|
throw new ArgumentNullException("secret");
|
||||||
}
|
}
|
||||||
if (plaintextLength < 0)
|
if (secretLength < 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException("plaintextLength");
|
throw new ArgumentOutOfRangeException("secretLength");
|
||||||
}
|
}
|
||||||
|
|
||||||
_localAllocHandle = Protect(plaintext, (uint)plaintextLength);
|
_localAllocHandle = Protect(secret, (uint)secretLength);
|
||||||
_plaintextLength = (uint)plaintextLength;
|
_plaintextLength = (uint)secretLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProtectedMemoryBlob(ISecret secret)
|
/// <summary>
|
||||||
|
/// Creates a new Secret from another secret object.
|
||||||
|
/// </summary>
|
||||||
|
public Secret(ISecret secret)
|
||||||
{
|
{
|
||||||
if (secret == null)
|
if (secret == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("secret");
|
throw new ArgumentNullException("secret");
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtectedMemoryBlob other = secret as ProtectedMemoryBlob;
|
Secret other = secret as Secret;
|
||||||
if (other != null)
|
if (other != null)
|
||||||
{
|
{
|
||||||
// Fast-track: simple deep copy scenario.
|
// Fast-track: simple deep copy scenario.
|
||||||
|
|
@ -79,6 +97,9 @@ namespace Microsoft.AspNet.Security.DataProtection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The length (in bytes) of the secret value.
|
||||||
|
/// </summary>
|
||||||
public int Length
|
public int Length
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -87,6 +108,9 @@ namespace Microsoft.AspNet.Security.DataProtection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wipes the secret from memory.
|
||||||
|
/// </summary>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_localAllocHandle.Dispose();
|
_localAllocHandle.Dispose();
|
||||||
|
|
@ -134,21 +158,25 @@ namespace Microsoft.AspNet.Security.DataProtection
|
||||||
return encryptedMemoryHandle;
|
return encryptedMemoryHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProtectedMemoryBlob Random(int numBytes)
|
/// <summary>
|
||||||
|
/// Returns a Secret comprised entirely of random bytes retrieved from
|
||||||
|
/// a cryptographically secure RNG.
|
||||||
|
/// </summary>
|
||||||
|
public static Secret Random(int numBytes)
|
||||||
{
|
{
|
||||||
CryptoUtil.Assert(numBytes >= 0, "numBytes >= 0");
|
CryptoUtil.Assert(numBytes >= 0, "numBytes >= 0");
|
||||||
|
|
||||||
if (numBytes == 0)
|
if (numBytes == 0)
|
||||||
{
|
{
|
||||||
byte dummy;
|
byte dummy;
|
||||||
return new ProtectedMemoryBlob(&dummy, 0);
|
return new Secret(&dummy, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Don't use CNG if we're not on Windows.
|
// Don't use CNG if we're not on Windows.
|
||||||
if (!OSVersionUtil.IsBCryptOnWin7OrLaterAvailable())
|
if (!OSVersionUtil.IsBCryptOnWin7OrLaterAvailable())
|
||||||
{
|
{
|
||||||
return new ProtectedMemoryBlob(ManagedGenRandomImpl.Instance.GenRandom(numBytes));
|
return new Secret(ManagedGenRandomImpl.Instance.GenRandom(numBytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] bytes = new byte[numBytes];
|
byte[] bytes = new byte[numBytes];
|
||||||
|
|
@ -157,7 +185,7 @@ namespace Microsoft.AspNet.Security.DataProtection
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
BCryptUtil.GenRandom(pbBytes, (uint)numBytes);
|
BCryptUtil.GenRandom(pbBytes, (uint)numBytes);
|
||||||
return new ProtectedMemoryBlob(pbBytes, numBytes);
|
return new Secret(pbBytes, numBytes);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
@ -196,6 +224,12 @@ namespace Microsoft.AspNet.Security.DataProtection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the secret value to the specified buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The buffer size must exactly match the length of the secret value.
|
||||||
|
/// </remarks>
|
||||||
public void WriteSecretIntoBuffer(ArraySegment<byte> buffer)
|
public void WriteSecretIntoBuffer(ArraySegment<byte> buffer)
|
||||||
{
|
{
|
||||||
// Parameter checking
|
// Parameter checking
|
||||||
|
|
@ -215,6 +249,12 @@ namespace Microsoft.AspNet.Security.DataProtection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the secret value to the specified buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The 'bufferLength' parameter must exactly match the length of the secret value.
|
||||||
|
/// </remarks>
|
||||||
public void WriteSecretIntoBuffer(byte* buffer, int bufferLength)
|
public void WriteSecretIntoBuffer(byte* buffer, int bufferLength)
|
||||||
{
|
{
|
||||||
if (buffer == null)
|
if (buffer == null)
|
||||||
|
|
@ -86,7 +86,7 @@ namespace Microsoft.AspNet.Security.DataProtection
|
||||||
expiration = new DateTimeOffset((long)utcTicksExpiration, TimeSpan.Zero);
|
expiration = new DateTimeOffset((long)utcTicksExpiration, TimeSpan.Zero);
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (!(ex is CryptographicException))
|
catch (Exception ex) when (ex.RequiresHomogenization())
|
||||||
{
|
{
|
||||||
// Homogenize all failures to CryptographicException
|
// Homogenize all failures to CryptographicException
|
||||||
throw Error.CryptCommon_GenericError(ex);
|
throw Error.CryptCommon_GenericError(ex);
|
||||||
|
|
|
||||||
|
|
@ -46,20 +46,19 @@ namespace Microsoft.AspNet.Security.DataProtection.XmlEncryption
|
||||||
public XElement Encrypt([NotNull] XElement plaintextElement)
|
public XElement Encrypt([NotNull] XElement plaintextElement)
|
||||||
{
|
{
|
||||||
// First, convert the XML element to a byte[] so that it can be encrypted.
|
// First, convert the XML element to a byte[] so that it can be encrypted.
|
||||||
ProtectedMemoryBlob secret;
|
Secret secret;
|
||||||
using (var memoryStream = new MemoryStream())
|
using (var memoryStream = new MemoryStream())
|
||||||
{
|
{
|
||||||
plaintextElement.Save(memoryStream);
|
plaintextElement.Save(memoryStream);
|
||||||
|
|
||||||
#if !ASPNETCORE50
|
#if !ASPNETCORE50
|
||||||
// If we're on full desktop CLR, utilize the underlying buffer directly as an optimization.
|
// If we're on full desktop CLR, utilize the underlying buffer directly as an optimization.
|
||||||
byte[] underlyingBuffer = memoryStream.GetBuffer();
|
byte[] underlyingBuffer = memoryStream.GetBuffer();
|
||||||
secret = new ProtectedMemoryBlob(new ArraySegment<byte>(underlyingBuffer, 0, checked((int)memoryStream.Length)));
|
secret = new Secret(new ArraySegment<byte>(underlyingBuffer, 0, checked((int)memoryStream.Length)));
|
||||||
Array.Clear(underlyingBuffer, 0, underlyingBuffer.Length);
|
Array.Clear(underlyingBuffer, 0, underlyingBuffer.Length);
|
||||||
#else
|
#else
|
||||||
// Otherwise, need to make a copy of the buffer.
|
// Otherwise, need to make a copy of the buffer.
|
||||||
byte[] clonedBuffer = memoryStream.ToArray();
|
byte[] clonedBuffer = memoryStream.ToArray();
|
||||||
secret = new ProtectedMemoryBlob(clonedBuffer);
|
secret = new Secret(clonedBuffer);
|
||||||
Array.Clear(clonedBuffer, 0, clonedBuffer.Length);
|
Array.Clear(clonedBuffer, 0, clonedBuffer.Length);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Security.DataProtection.XmlEncryption
|
||||||
public XElement Encrypt([NotNull] XElement plaintextElement)
|
public XElement Encrypt([NotNull] XElement plaintextElement)
|
||||||
{
|
{
|
||||||
// First, convert the XML element to a byte[] so that it can be encrypted.
|
// First, convert the XML element to a byte[] so that it can be encrypted.
|
||||||
ProtectedMemoryBlob secret;
|
Secret secret;
|
||||||
using (var memoryStream = new MemoryStream())
|
using (var memoryStream = new MemoryStream())
|
||||||
{
|
{
|
||||||
plaintextElement.Save(memoryStream);
|
plaintextElement.Save(memoryStream);
|
||||||
|
|
@ -39,12 +39,12 @@ namespace Microsoft.AspNet.Security.DataProtection.XmlEncryption
|
||||||
#if !ASPNETCORE50
|
#if !ASPNETCORE50
|
||||||
// If we're on full desktop CLR, utilize the underlying buffer directly as an optimization.
|
// If we're on full desktop CLR, utilize the underlying buffer directly as an optimization.
|
||||||
byte[] underlyingBuffer = memoryStream.GetBuffer();
|
byte[] underlyingBuffer = memoryStream.GetBuffer();
|
||||||
secret = new ProtectedMemoryBlob(new ArraySegment<byte>(underlyingBuffer, 0, checked((int)memoryStream.Length)));
|
secret = new Secret(new ArraySegment<byte>(underlyingBuffer, 0, checked((int)memoryStream.Length)));
|
||||||
Array.Clear(underlyingBuffer, 0, underlyingBuffer.Length);
|
Array.Clear(underlyingBuffer, 0, underlyingBuffer.Length);
|
||||||
#else
|
#else
|
||||||
// Otherwise, need to make a copy of the buffer.
|
// Otherwise, need to make a copy of the buffer.
|
||||||
byte[] clonedBuffer = memoryStream.ToArray();
|
byte[] clonedBuffer = memoryStream.ToArray();
|
||||||
secret = new ProtectedMemoryBlob(clonedBuffer);
|
secret = new Secret(clonedBuffer);
|
||||||
Array.Clear(clonedBuffer, 0, clonedBuffer.Length);
|
Array.Clear(clonedBuffer, 0, clonedBuffer.Length);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.Cng
|
||||||
public void Encrypt_Decrypt_RoundTrips()
|
public void Encrypt_Decrypt_RoundTrips()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
ProtectedMemoryBlob kdk = new ProtectedMemoryBlob(new byte[512 / 8]);
|
Secret kdk = new Secret(new byte[512 / 8]);
|
||||||
CbcAuthenticatedEncryptor encryptor = new CbcAuthenticatedEncryptor(kdk,
|
CbcAuthenticatedEncryptor encryptor = new CbcAuthenticatedEncryptor(kdk,
|
||||||
symmetricAlgorithmHandle: CachedAlgorithmHandles.AES_CBC,
|
symmetricAlgorithmHandle: CachedAlgorithmHandles.AES_CBC,
|
||||||
symmetricAlgorithmKeySizeInBytes: 256 / 8,
|
symmetricAlgorithmKeySizeInBytes: 256 / 8,
|
||||||
|
|
@ -39,7 +39,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.Cng
|
||||||
public void Encrypt_Decrypt_Tampering_Fails()
|
public void Encrypt_Decrypt_Tampering_Fails()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
ProtectedMemoryBlob kdk = new ProtectedMemoryBlob(new byte[512 / 8]);
|
Secret kdk = new Secret(new byte[512 / 8]);
|
||||||
CbcAuthenticatedEncryptor encryptor = new CbcAuthenticatedEncryptor(kdk,
|
CbcAuthenticatedEncryptor encryptor = new CbcAuthenticatedEncryptor(kdk,
|
||||||
symmetricAlgorithmHandle: CachedAlgorithmHandles.AES_CBC,
|
symmetricAlgorithmHandle: CachedAlgorithmHandles.AES_CBC,
|
||||||
symmetricAlgorithmKeySizeInBytes: 256 / 8,
|
symmetricAlgorithmKeySizeInBytes: 256 / 8,
|
||||||
|
|
@ -86,7 +86,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.Cng
|
||||||
public void Encrypt_KnownKey()
|
public void Encrypt_KnownKey()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
ProtectedMemoryBlob kdk = new ProtectedMemoryBlob(Encoding.UTF8.GetBytes("master key"));
|
Secret kdk = new Secret(Encoding.UTF8.GetBytes("master key"));
|
||||||
CbcAuthenticatedEncryptor encryptor = new CbcAuthenticatedEncryptor(kdk,
|
CbcAuthenticatedEncryptor encryptor = new CbcAuthenticatedEncryptor(kdk,
|
||||||
symmetricAlgorithmHandle: CachedAlgorithmHandles.AES_CBC,
|
symmetricAlgorithmHandle: CachedAlgorithmHandles.AES_CBC,
|
||||||
symmetricAlgorithmKeySizeInBytes: 256 / 8,
|
symmetricAlgorithmKeySizeInBytes: 256 / 8,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.Cng
|
||||||
public void Encrypt_Decrypt_RoundTrips()
|
public void Encrypt_Decrypt_RoundTrips()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
ProtectedMemoryBlob kdk = new ProtectedMemoryBlob(new byte[512 / 8]);
|
Secret kdk = new Secret(new byte[512 / 8]);
|
||||||
GcmAuthenticatedEncryptor encryptor = new GcmAuthenticatedEncryptor(kdk, CachedAlgorithmHandles.AES_GCM, symmetricAlgorithmKeySizeInBytes: 256 / 8);
|
GcmAuthenticatedEncryptor encryptor = new GcmAuthenticatedEncryptor(kdk, CachedAlgorithmHandles.AES_GCM, symmetricAlgorithmKeySizeInBytes: 256 / 8);
|
||||||
ArraySegment<byte> plaintext = new ArraySegment<byte>(Encoding.UTF8.GetBytes("plaintext"));
|
ArraySegment<byte> plaintext = new ArraySegment<byte>(Encoding.UTF8.GetBytes("plaintext"));
|
||||||
ArraySegment<byte> aad = new ArraySegment<byte>(Encoding.UTF8.GetBytes("aad"));
|
ArraySegment<byte> aad = new ArraySegment<byte>(Encoding.UTF8.GetBytes("aad"));
|
||||||
|
|
@ -36,7 +36,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.Cng
|
||||||
public void Encrypt_Decrypt_Tampering_Fails()
|
public void Encrypt_Decrypt_Tampering_Fails()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
ProtectedMemoryBlob kdk = new ProtectedMemoryBlob(new byte[512 / 8]);
|
Secret kdk = new Secret(new byte[512 / 8]);
|
||||||
GcmAuthenticatedEncryptor encryptor = new GcmAuthenticatedEncryptor(kdk, CachedAlgorithmHandles.AES_GCM, symmetricAlgorithmKeySizeInBytes: 256 / 8);
|
GcmAuthenticatedEncryptor encryptor = new GcmAuthenticatedEncryptor(kdk, CachedAlgorithmHandles.AES_GCM, symmetricAlgorithmKeySizeInBytes: 256 / 8);
|
||||||
ArraySegment<byte> plaintext = new ArraySegment<byte>(Encoding.UTF8.GetBytes("plaintext"));
|
ArraySegment<byte> plaintext = new ArraySegment<byte>(Encoding.UTF8.GetBytes("plaintext"));
|
||||||
ArraySegment<byte> aad = new ArraySegment<byte>(Encoding.UTF8.GetBytes("aad"));
|
ArraySegment<byte> aad = new ArraySegment<byte>(Encoding.UTF8.GetBytes("aad"));
|
||||||
|
|
@ -80,7 +80,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.Cng
|
||||||
public void Encrypt_KnownKey()
|
public void Encrypt_KnownKey()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
ProtectedMemoryBlob kdk = new ProtectedMemoryBlob(Encoding.UTF8.GetBytes("master key"));
|
Secret kdk = new Secret(Encoding.UTF8.GetBytes("master key"));
|
||||||
GcmAuthenticatedEncryptor encryptor = new GcmAuthenticatedEncryptor(kdk, CachedAlgorithmHandles.AES_GCM, symmetricAlgorithmKeySizeInBytes: 128 / 8, genRandom: new SequentialGenRandom());
|
GcmAuthenticatedEncryptor encryptor = new GcmAuthenticatedEncryptor(kdk, CachedAlgorithmHandles.AES_GCM, symmetricAlgorithmKeySizeInBytes: 128 / 8, genRandom: new SequentialGenRandom());
|
||||||
ArraySegment<byte> plaintext = new ArraySegment<byte>(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }, 2, 3);
|
ArraySegment<byte> plaintext = new ArraySegment<byte>(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }, 2, 3);
|
||||||
ArraySegment<byte> aad = new ArraySegment<byte>(new byte[] { 7, 6, 5, 4, 3, 2, 1, 0 }, 1, 4);
|
ArraySegment<byte> aad = new ArraySegment<byte>(new byte[] { 7, 6, 5, 4, 3, 2, 1, 0 }, 1, 4);
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.Managed
|
||||||
public void Encrypt_Decrypt_RoundTrips()
|
public void Encrypt_Decrypt_RoundTrips()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
ProtectedMemoryBlob kdk = new ProtectedMemoryBlob(new byte[512 / 8]);
|
Secret kdk = new Secret(new byte[512 / 8]);
|
||||||
ManagedAuthenticatedEncryptor encryptor = new ManagedAuthenticatedEncryptor(kdk,
|
ManagedAuthenticatedEncryptor encryptor = new ManagedAuthenticatedEncryptor(kdk,
|
||||||
symmetricAlgorithmFactory: Aes.Create,
|
symmetricAlgorithmFactory: Aes.Create,
|
||||||
symmetricAlgorithmKeySizeInBytes: 256 / 8,
|
symmetricAlgorithmKeySizeInBytes: 256 / 8,
|
||||||
|
|
@ -36,7 +36,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.Managed
|
||||||
public void Encrypt_Decrypt_Tampering_Fails()
|
public void Encrypt_Decrypt_Tampering_Fails()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
ProtectedMemoryBlob kdk = new ProtectedMemoryBlob(new byte[512 / 8]);
|
Secret kdk = new Secret(new byte[512 / 8]);
|
||||||
ManagedAuthenticatedEncryptor encryptor = new ManagedAuthenticatedEncryptor(kdk,
|
ManagedAuthenticatedEncryptor encryptor = new ManagedAuthenticatedEncryptor(kdk,
|
||||||
symmetricAlgorithmFactory: Aes.Create,
|
symmetricAlgorithmFactory: Aes.Create,
|
||||||
symmetricAlgorithmKeySizeInBytes: 256 / 8,
|
symmetricAlgorithmKeySizeInBytes: 256 / 8,
|
||||||
|
|
@ -82,7 +82,7 @@ namespace Microsoft.AspNet.Security.DataProtection.Test.Managed
|
||||||
public void Encrypt_KnownKey()
|
public void Encrypt_KnownKey()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
ProtectedMemoryBlob kdk = new ProtectedMemoryBlob(Encoding.UTF8.GetBytes("master key"));
|
Secret kdk = new Secret(Encoding.UTF8.GetBytes("master key"));
|
||||||
ManagedAuthenticatedEncryptor encryptor = new ManagedAuthenticatedEncryptor(kdk,
|
ManagedAuthenticatedEncryptor encryptor = new ManagedAuthenticatedEncryptor(kdk,
|
||||||
symmetricAlgorithmFactory: Aes.Create,
|
symmetricAlgorithmFactory: Aes.Create,
|
||||||
symmetricAlgorithmKeySizeInBytes: 256 / 8,
|
symmetricAlgorithmKeySizeInBytes: 256 / 8,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue