Creating one IAuthenticatedEncryptor per IKey

This commit is contained in:
Ajay Bhargav Baaskaran 2017-04-05 21:00:39 -07:00
parent ff3ff939c3
commit c959795a64
21 changed files with 180 additions and 181 deletions

View File

@ -29,8 +29,6 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IEnumerable<IAuthenticatedEncryptorFactory> _encryptorFactories;
/// <summary> /// <summary>
/// The maximum skew that is allowed between servers. /// The maximum skew that is allowed between servers.
/// This is used to allow newly-created keys to be used across servers even though /// This is used to allow newly-created keys to be used across servers even though
@ -46,7 +44,6 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
{ {
_keyPropagationWindow = keyManagementOptions.Value.KeyPropagationWindow; _keyPropagationWindow = keyManagementOptions.Value.KeyPropagationWindow;
_maxServerToServerClockSkew = keyManagementOptions.Value.MaxServerClockSkew; _maxServerToServerClockSkew = keyManagementOptions.Value.MaxServerClockSkew;
_encryptorFactories = keyManagementOptions.Value.AuthenticatedEncryptorFactories;
_logger = loggerFactory.CreateLogger<DefaultKeyResolver>(); _logger = loggerFactory.CreateLogger<DefaultKeyResolver>();
} }
@ -54,16 +51,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
{ {
try try
{ {
IAuthenticatedEncryptor encryptorInstance = null; var encryptorInstance = key.CreateEncryptor();
foreach (var factory in _encryptorFactories)
{
encryptorInstance = factory.CreateEncryptorInstance(key);
if (encryptorInstance != null)
{
break;
}
}
if (encryptorInstance == null) if (encryptorInstance == null)
{ {
CryptoUtil.Fail<IAuthenticatedEncryptor>("CreateEncryptorInstance returned null."); CryptoUtil.Fail<IAuthenticatedEncryptor>("CreateEncryptorInstance returned null.");
@ -73,7 +61,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.KeyIsIneligibleToBeTheDefaultKeyBecauseItsMethodFailed(key.KeyId, nameof(IAuthenticatedEncryptorFactory.CreateEncryptorInstance), ex); _logger.KeyIsIneligibleToBeTheDefaultKeyBecauseItsMethodFailed(key.KeyId, nameof(IKey.CreateEncryptor), ex);
return false; return false;
} }
} }

View File

@ -2,7 +2,9 @@
// 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.Collections.Generic;
using System.Xml.Linq; using System.Xml.Linq;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel; using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
using Microsoft.AspNetCore.DataProtection.KeyManagement.Internal; using Microsoft.AspNetCore.DataProtection.KeyManagement.Internal;
using Microsoft.AspNetCore.DataProtection.XmlEncryption; using Microsoft.AspNetCore.DataProtection.XmlEncryption;
@ -21,8 +23,14 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
DateTimeOffset activationDate, DateTimeOffset activationDate,
DateTimeOffset expirationDate, DateTimeOffset expirationDate,
IInternalXmlKeyManager keyManager, IInternalXmlKeyManager keyManager,
XElement keyElement) XElement keyElement,
: base(keyId, creationDate, activationDate, expirationDate, new Lazy<IAuthenticatedEncryptorDescriptor>(GetLazyDescriptorDelegate(keyManager, keyElement))) IEnumerable<IAuthenticatedEncryptorFactory> encryptorFactories)
: base(keyId,
creationDate,
activationDate,
expirationDate,
new Lazy<IAuthenticatedEncryptorDescriptor>(GetLazyDescriptorDelegate(keyManager, keyElement)),
encryptorFactories)
{ {
} }

View File

@ -49,5 +49,12 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
/// Gets the <see cref="IAuthenticatedEncryptorDescriptor"/> instance associated with this key. /// Gets the <see cref="IAuthenticatedEncryptorDescriptor"/> instance associated with this key.
/// </summary> /// </summary>
IAuthenticatedEncryptorDescriptor Descriptor { get; } IAuthenticatedEncryptorDescriptor Descriptor { get; }
/// <summary>
/// Creates an <see cref="IAuthenticatedEncryptor"/> instance that can be used to encrypt data
/// to and decrypt data from this key.
/// </summary>
/// <returns>An <see cref="IAuthenticatedEncryptor"/>.</returns>
IAuthenticatedEncryptor CreateEncryptor();
} }
} }

View File

@ -15,8 +15,8 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement.Internal
{ {
private readonly CancellationToken _expirationToken; private readonly CancellationToken _expirationToken;
internal CacheableKeyRing(CancellationToken expirationToken, DateTimeOffset expirationTime, IKey defaultKey, IEnumerable<IKey> allKeys, IEnumerable<IAuthenticatedEncryptorFactory> encryptorFactories) internal CacheableKeyRing(CancellationToken expirationToken, DateTimeOffset expirationTime, IKey defaultKey, IEnumerable<IKey> allKeys)
: this(expirationToken, expirationTime, keyRing: new KeyRing(defaultKey, allKeys, encryptorFactories)) : this(expirationToken, expirationTime, keyRing: new KeyRing(defaultKey, allKeys))
{ {
} }

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement.Internal
/// The default key, may be null if no key is a good default candidate. /// The default key, may be null if no key is a good default candidate.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// If this property is non-null, its <see cref="IAuthenticatedEncryptorFactory.CreateEncryptorInstance(IKey)"/> method will succeed /// If this property is non-null, its <see cref="IKey.CreateEncryptor()"/> method will succeed
/// so is appropriate for use with deferred keys. /// so is appropriate for use with deferred keys.
/// </remarks> /// </remarks>
public IKey DefaultKey; public IKey DefaultKey;
@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement.Internal
/// be null if there is no viable fallback key. /// be null if there is no viable fallback key.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// If this property is non-null, its <see cref="IAuthenticatedEncryptorFactory.CreateEncryptorInstance(IKey)"/> method will succeed /// If this property is non-null, its <see cref="IKey.CreateEncryptor()"/> method will succeed
/// so is appropriate for use with deferred keys. /// so is appropriate for use with deferred keys.
/// </remarks> /// </remarks>
public IKey FallbackKey; public IKey FallbackKey;

View File

@ -2,6 +2,7 @@
// 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.Collections.Generic;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption; using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel; using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
@ -13,8 +14,19 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
/// </summary> /// </summary>
internal sealed class Key : KeyBase internal sealed class Key : KeyBase
{ {
public Key(Guid keyId, DateTimeOffset creationDate, DateTimeOffset activationDate, DateTimeOffset expirationDate, IAuthenticatedEncryptorDescriptor descriptor) public Key(
: base(keyId, creationDate, activationDate, expirationDate, new Lazy<IAuthenticatedEncryptorDescriptor>(() => descriptor)) Guid keyId,
DateTimeOffset creationDate,
DateTimeOffset activationDate,
DateTimeOffset expirationDate,
IAuthenticatedEncryptorDescriptor descriptor,
IEnumerable<IAuthenticatedEncryptorFactory> encryptorFactories)
: base(keyId,
creationDate,
activationDate,
expirationDate,
new Lazy<IAuthenticatedEncryptorDescriptor>(() => descriptor),
encryptorFactories)
{ {
} }
} }

View File

@ -2,6 +2,7 @@
// 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.Collections.Generic;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption; using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel; using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
@ -13,14 +14,24 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
internal abstract class KeyBase : IKey internal abstract class KeyBase : IKey
{ {
private readonly Lazy<IAuthenticatedEncryptorDescriptor> _lazyDescriptor; private readonly Lazy<IAuthenticatedEncryptorDescriptor> _lazyDescriptor;
private readonly IEnumerable<IAuthenticatedEncryptorFactory> _encryptorFactories;
public KeyBase(Guid keyId, DateTimeOffset creationDate, DateTimeOffset activationDate, DateTimeOffset expirationDate, Lazy<IAuthenticatedEncryptorDescriptor> lazyDescriptor) private IAuthenticatedEncryptor _encryptor;
public KeyBase(
Guid keyId,
DateTimeOffset creationDate,
DateTimeOffset activationDate,
DateTimeOffset expirationDate,
Lazy<IAuthenticatedEncryptorDescriptor> lazyDescriptor,
IEnumerable<IAuthenticatedEncryptorFactory> encryptorFactories)
{ {
KeyId = keyId; KeyId = keyId;
CreationDate = creationDate; CreationDate = creationDate;
ActivationDate = activationDate; ActivationDate = activationDate;
ExpirationDate = expirationDate; ExpirationDate = expirationDate;
_lazyDescriptor = lazyDescriptor; _lazyDescriptor = lazyDescriptor;
_encryptorFactories = encryptorFactories;
} }
public DateTimeOffset ActivationDate { get; } public DateTimeOffset ActivationDate { get; }
@ -41,6 +52,24 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
} }
} }
public IAuthenticatedEncryptor CreateEncryptor()
{
if (_encryptor == null)
{
foreach (var factory in _encryptorFactories)
{
var encryptor = factory.CreateEncryptorInstance(this);
if (encryptor != null)
{
_encryptor = encryptor;
break;
}
}
}
return _encryptor;
}
internal void SetRevoked() internal void SetRevoked()
{ {
IsRevoked = true; IsRevoked = true;

View File

@ -17,12 +17,12 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
private readonly KeyHolder _defaultKeyHolder; private readonly KeyHolder _defaultKeyHolder;
private readonly Dictionary<Guid, KeyHolder> _keyIdToKeyHolderMap; private readonly Dictionary<Guid, KeyHolder> _keyIdToKeyHolderMap;
public KeyRing(IKey defaultKey, IEnumerable<IKey> allKeys, IEnumerable<IAuthenticatedEncryptorFactory> encryptorFactories) public KeyRing(IKey defaultKey, IEnumerable<IKey> allKeys)
{ {
_keyIdToKeyHolderMap = new Dictionary<Guid, KeyHolder>(); _keyIdToKeyHolderMap = new Dictionary<Guid, KeyHolder>();
foreach (IKey key in allKeys) foreach (IKey key in allKeys)
{ {
_keyIdToKeyHolderMap.Add(key.KeyId, new KeyHolder(key, encryptorFactories)); _keyIdToKeyHolderMap.Add(key.KeyId, new KeyHolder(key));
} }
// It's possible under some circumstances that the default key won't be part of 'allKeys', // It's possible under some circumstances that the default key won't be part of 'allKeys',
@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
// wasn't in the underlying repository. In this case, we just add it now. // wasn't in the underlying repository. In this case, we just add it now.
if (!_keyIdToKeyHolderMap.ContainsKey(defaultKey.KeyId)) if (!_keyIdToKeyHolderMap.ContainsKey(defaultKey.KeyId))
{ {
_keyIdToKeyHolderMap.Add(defaultKey.KeyId, new KeyHolder(defaultKey, encryptorFactories)); _keyIdToKeyHolderMap.Add(defaultKey.KeyId, new KeyHolder(defaultKey));
} }
DefaultKeyId = defaultKey.KeyId; DefaultKeyId = defaultKey.KeyId;
@ -61,12 +61,10 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
{ {
private readonly IKey _key; private readonly IKey _key;
private IAuthenticatedEncryptor _encryptor; private IAuthenticatedEncryptor _encryptor;
private readonly IEnumerable<IAuthenticatedEncryptorFactory> _encryptorFactories;
internal KeyHolder(IKey key, IEnumerable<IAuthenticatedEncryptorFactory> encryptorFactories) internal KeyHolder(IKey key)
{ {
_key = key; _key = key;
_encryptorFactories = encryptorFactories;
} }
internal IAuthenticatedEncryptor GetEncryptorInstance(out bool isRevoked) internal IAuthenticatedEncryptor GetEncryptorInstance(out bool isRevoked)
@ -81,14 +79,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
encryptor = Volatile.Read(ref _encryptor); encryptor = Volatile.Read(ref _encryptor);
if (encryptor == null) if (encryptor == null)
{ {
foreach (var factory in _encryptorFactories) encryptor = _key.CreateEncryptor();
{
encryptor = factory.CreateEncryptorInstance(_key);
if (encryptor != null)
{
break;
}
}
Volatile.Write(ref _encryptor, encryptor); Volatile.Write(ref _encryptor, encryptor);
} }
} }

View File

@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Threading; using System.Threading;
using Microsoft.AspNetCore.Cryptography; using Microsoft.AspNetCore.Cryptography;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using Microsoft.AspNetCore.DataProtection.KeyManagement.Internal; using Microsoft.AspNetCore.DataProtection.KeyManagement.Internal;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -118,7 +117,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
Debug.Assert(defaultKey != null); Debug.Assert(defaultKey != null);
// Invariant: our caller ensures that CreateEncryptorInstance succeeded at least once // Invariant: our caller ensures that CreateEncryptorInstance succeeded at least once
Debug.Assert(CreateEncryptorForKey(defaultKey) != null); Debug.Assert(defaultKey.CreateEncryptor() != null);
_logger.UsingKeyAsDefaultKey(defaultKey.KeyId); _logger.UsingKeyAsDefaultKey(defaultKey.KeyId);
@ -135,8 +134,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
expirationToken: cacheExpirationToken, expirationToken: cacheExpirationToken,
expirationTime: (defaultKey.ExpirationDate <= now) ? nextAutoRefreshTime : Min(defaultKey.ExpirationDate, nextAutoRefreshTime), expirationTime: (defaultKey.ExpirationDate <= now) ? nextAutoRefreshTime : Min(defaultKey.ExpirationDate, nextAutoRefreshTime),
defaultKey: defaultKey, defaultKey: defaultKey,
allKeys: allKeys, allKeys: allKeys);
encryptorFactories: _keyManagementOptions.AuthenticatedEncryptorFactories);
} }
public IKeyRing GetCurrentKeyRing() public IKeyRing GetCurrentKeyRing()
@ -236,20 +234,6 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
} }
} }
private IAuthenticatedEncryptor CreateEncryptorForKey(IKey key)
{
foreach (var factory in _keyManagementOptions.AuthenticatedEncryptorFactories)
{
var encryptor = factory.CreateEncryptorInstance(key);
if (encryptor != null)
{
return encryptor;
}
}
return null;
}
private static TimeSpan GetRefreshPeriodWithJitter(TimeSpan refreshPeriod) private static TimeSpan GetRefreshPeriodWithJitter(TimeSpan refreshPeriod)
{ {
// We'll fudge the refresh period up to -20% so that multiple applications don't try to // We'll fudge the refresh period up to -20% so that multiple applications don't try to

View File

@ -12,6 +12,7 @@ using System.Xml;
using System.Xml.Linq; using System.Xml.Linq;
using Microsoft.AspNetCore.Cryptography; using Microsoft.AspNetCore.Cryptography;
using Microsoft.AspNetCore.Cryptography.Cng; using Microsoft.AspNetCore.Cryptography.Cng;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel; using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
using Microsoft.AspNetCore.DataProtection.Cng; using Microsoft.AspNetCore.DataProtection.Cng;
using Microsoft.AspNetCore.DataProtection.Internal; using Microsoft.AspNetCore.DataProtection.Internal;
@ -50,6 +51,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
private readonly IInternalXmlKeyManager _internalKeyManager; private readonly IInternalXmlKeyManager _internalKeyManager;
private readonly ILoggerFactory _loggerFactory; private readonly ILoggerFactory _loggerFactory;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IEnumerable<IAuthenticatedEncryptorFactory> _encryptorFactories;
private CancellationTokenSource _cacheExpirationTokenSource; private CancellationTokenSource _cacheExpirationTokenSource;
@ -88,6 +90,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
_activator = activator; _activator = activator;
TriggerAndResetCacheExpirationToken(suppressLogging: true); TriggerAndResetCacheExpirationToken(suppressLogging: true);
_internalKeyManager = _internalKeyManager ?? this; _internalKeyManager = _internalKeyManager ?? this;
_encryptorFactories = keyManagementOptions.Value.AuthenticatedEncryptorFactories;
} }
// Internal for testing. // Internal for testing.
@ -240,7 +243,8 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
activationDate: activationDate, activationDate: activationDate,
expirationDate: expirationDate, expirationDate: expirationDate,
keyManager: this, keyManager: this,
keyElement: keyElement); keyElement: keyElement,
encryptorFactories: _encryptorFactories);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -400,7 +404,8 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
creationDate: creationDate, creationDate: creationDate,
activationDate: activationDate, activationDate: activationDate,
expirationDate: expirationDate, expirationDate: expirationDate,
descriptor: newDescriptor); descriptor: newDescriptor,
encryptorFactories: _encryptorFactories);
} }
IAuthenticatedEncryptorDescriptor IInternalXmlKeyManager.DeserializeDescriptorFromKeyElement(XElement keyElement) IAuthenticatedEncryptorDescriptor IInternalXmlKeyManager.DeserializeDescriptorFromKeyElement(XElement keyElement)

View File

@ -43,16 +43,17 @@ namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.Configurat
private static IAuthenticatedEncryptor CreateEncryptorInstanceFromDescriptor(AuthenticatedEncryptorDescriptor descriptor) private static IAuthenticatedEncryptor CreateEncryptorInstanceFromDescriptor(AuthenticatedEncryptorDescriptor descriptor)
{ {
var encryptorFactory = new AuthenticatedEncryptorFactory(NullLoggerFactory.Instance);
var key = new Key( var key = new Key(
Guid.NewGuid(), Guid.NewGuid(),
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now + TimeSpan.FromHours(1), DateTimeOffset.Now + TimeSpan.FromHours(1),
DateTimeOffset.Now + TimeSpan.FromDays(30), DateTimeOffset.Now + TimeSpan.FromDays(30),
descriptor); descriptor,
new[] { encryptorFactory });
var encryptorFactory = new AuthenticatedEncryptorFactory(NullLoggerFactory.Instance);
return encryptorFactory.CreateEncryptorInstance(key); return key.CreateEncryptor();
} }
} }
} }

View File

@ -171,17 +171,19 @@ namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.Configurat
private static IAuthenticatedEncryptor CreateEncryptorInstanceFromDescriptor(AuthenticatedEncryptorDescriptor descriptor) private static IAuthenticatedEncryptor CreateEncryptorInstanceFromDescriptor(AuthenticatedEncryptorDescriptor descriptor)
{ {
var encryptorFactory = new AuthenticatedEncryptorFactory(NullLoggerFactory.Instance);
// Dummy key with the specified descriptor. // Dummy key with the specified descriptor.
var key = new Key( var key = new Key(
Guid.NewGuid(), Guid.NewGuid(),
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now + TimeSpan.FromHours(1), DateTimeOffset.Now + TimeSpan.FromHours(1),
DateTimeOffset.Now + TimeSpan.FromDays(30), DateTimeOffset.Now + TimeSpan.FromDays(30),
descriptor); descriptor,
new[] { encryptorFactory });
var encryptorFactory = new AuthenticatedEncryptorFactory(NullLoggerFactory.Instance);
return encryptorFactory.CreateEncryptorInstance(key); return key.CreateEncryptor();
} }
} }
} }

View File

@ -50,16 +50,17 @@ namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.Configurat
private static IAuthenticatedEncryptor CreateEncryptorInstanceFromDescriptor(CngCbcAuthenticatedEncryptorDescriptor descriptor) private static IAuthenticatedEncryptor CreateEncryptorInstanceFromDescriptor(CngCbcAuthenticatedEncryptorDescriptor descriptor)
{ {
var encryptorFactory = new CngCbcAuthenticatedEncryptorFactory(NullLoggerFactory.Instance);
var key = new Key( var key = new Key(
Guid.NewGuid(), Guid.NewGuid(),
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now + TimeSpan.FromHours(1), DateTimeOffset.Now + TimeSpan.FromHours(1),
DateTimeOffset.Now + TimeSpan.FromDays(30), DateTimeOffset.Now + TimeSpan.FromDays(30),
descriptor); descriptor,
new[] { encryptorFactory });
var encryptorFactory = new CngCbcAuthenticatedEncryptorFactory(NullLoggerFactory.Instance);
return encryptorFactory.CreateEncryptorInstance(key); return key.CreateEncryptor();
} }
} }
} }

View File

@ -47,16 +47,17 @@ namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.Configurat
private static IAuthenticatedEncryptor CreateEncryptorInstanceFromDescriptor(CngGcmAuthenticatedEncryptorDescriptor descriptor) private static IAuthenticatedEncryptor CreateEncryptorInstanceFromDescriptor(CngGcmAuthenticatedEncryptorDescriptor descriptor)
{ {
var encryptorFactory = new CngGcmAuthenticatedEncryptorFactory(NullLoggerFactory.Instance);
var key = new Key( var key = new Key(
keyId: Guid.NewGuid(), keyId: Guid.NewGuid(),
creationDate: DateTimeOffset.Now, creationDate: DateTimeOffset.Now,
activationDate: DateTimeOffset.Now + TimeSpan.FromHours(1), activationDate: DateTimeOffset.Now + TimeSpan.FromHours(1),
expirationDate: DateTimeOffset.Now + TimeSpan.FromDays(30), expirationDate: DateTimeOffset.Now + TimeSpan.FromDays(30),
descriptor: descriptor); descriptor: descriptor,
encryptorFactories: new[] { encryptorFactory });
var encryptorFactory = new CngGcmAuthenticatedEncryptorFactory(NullLoggerFactory.Instance);
return encryptorFactory.CreateEncryptorInstance(key); return key.CreateEncryptor();
} }
} }
} }

View File

@ -86,16 +86,16 @@ namespace Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.Configurat
private static IAuthenticatedEncryptor CreateEncryptorInstanceFromDescriptor(ManagedAuthenticatedEncryptorDescriptor descriptor) private static IAuthenticatedEncryptor CreateEncryptorInstanceFromDescriptor(ManagedAuthenticatedEncryptorDescriptor descriptor)
{ {
var encryptorFactory = new ManagedAuthenticatedEncryptorFactory(NullLoggerFactory.Instance);
var key = new Key( var key = new Key(
Guid.NewGuid(), Guid.NewGuid(),
DateTimeOffset.Now, DateTimeOffset.Now,
DateTimeOffset.Now + TimeSpan.FromHours(1), DateTimeOffset.Now + TimeSpan.FromHours(1),
DateTimeOffset.Now + TimeSpan.FromDays(30), DateTimeOffset.Now + TimeSpan.FromDays(30),
descriptor); descriptor,
new[] { encryptorFactory });
var encryptorFactory = new ManagedAuthenticatedEncryptorFactory(NullLoggerFactory.Instance); return key.CreateEncryptor();
return encryptorFactory.CreateEncryptorInstance(key);
} }
} }
} }

View File

@ -4,7 +4,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption; using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
using Microsoft.AspNetCore.DataProtection.KeyManagement.Internal; using Microsoft.AspNetCore.DataProtection.KeyManagement.Internal;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
@ -20,7 +19,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
public void ResolveDefaultKeyPolicy_EmptyKeyRing_ReturnsNullDefaultKey() public void ResolveDefaultKeyPolicy_EmptyKeyRing_ReturnsNullDefaultKey()
{ {
// Arrange // Arrange
var resolver = CreateDefaultKeyResolver(new MyEncryptorFactory()); var resolver = CreateDefaultKeyResolver();
// Act // Act
var resolution = resolver.ResolveDefaultKeyPolicy(DateTimeOffset.Now, new IKey[0]); var resolution = resolver.ResolveDefaultKeyPolicy(DateTimeOffset.Now, new IKey[0]);
@ -34,7 +33,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
public void ResolveDefaultKeyPolicy_ValidExistingKey_ReturnsExistingKey() public void ResolveDefaultKeyPolicy_ValidExistingKey_ReturnsExistingKey()
{ {
// Arrange // Arrange
var resolver = CreateDefaultKeyResolver(new MyEncryptorFactory()); var resolver = CreateDefaultKeyResolver();
var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z"); var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z");
var key2 = CreateKey("2016-03-01 00:00:00Z", "2017-03-01 00:00:00Z"); var key2 = CreateKey("2016-03-01 00:00:00Z", "2017-03-01 00:00:00Z");
@ -50,7 +49,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
public void ResolveDefaultKeyPolicy_ValidExistingKey_AllowsForClockSkew_KeysStraddleSkewLine_ReturnsExistingKey() public void ResolveDefaultKeyPolicy_ValidExistingKey_AllowsForClockSkew_KeysStraddleSkewLine_ReturnsExistingKey()
{ {
// Arrange // Arrange
var resolver = CreateDefaultKeyResolver(new MyEncryptorFactory()); var resolver = CreateDefaultKeyResolver();
var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z"); var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z");
var key2 = CreateKey("2016-03-01 00:00:00Z", "2017-03-01 00:00:00Z"); var key2 = CreateKey("2016-03-01 00:00:00Z", "2017-03-01 00:00:00Z");
@ -66,7 +65,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
public void ResolveDefaultKeyPolicy_ValidExistingKey_AllowsForClockSkew_AllKeysInFuture_ReturnsExistingKey() public void ResolveDefaultKeyPolicy_ValidExistingKey_AllowsForClockSkew_AllKeysInFuture_ReturnsExistingKey()
{ {
// Arrange // Arrange
var resolver = CreateDefaultKeyResolver(new MyEncryptorFactory()); var resolver = CreateDefaultKeyResolver();
var key1 = CreateKey("2016-03-01 00:00:00Z", "2017-03-01 00:00:00Z"); var key1 = CreateKey("2016-03-01 00:00:00Z", "2017-03-01 00:00:00Z");
// Act // Act
@ -81,7 +80,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
public void ResolveDefaultKeyPolicy_ValidExistingKey_NoSuccessor_ReturnsExistingKey_SignalsGenerateNewKey() public void ResolveDefaultKeyPolicy_ValidExistingKey_NoSuccessor_ReturnsExistingKey_SignalsGenerateNewKey()
{ {
// Arrange // Arrange
var resolver = CreateDefaultKeyResolver(new MyEncryptorFactory()); var resolver = CreateDefaultKeyResolver();
var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z"); var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z");
// Act // Act
@ -96,7 +95,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
public void ResolveDefaultKeyPolicy_ValidExistingKey_NoLegitimateSuccessor_ReturnsExistingKey_SignalsGenerateNewKey() public void ResolveDefaultKeyPolicy_ValidExistingKey_NoLegitimateSuccessor_ReturnsExistingKey_SignalsGenerateNewKey()
{ {
// Arrange // Arrange
var resolver = CreateDefaultKeyResolver(new MyEncryptorFactory()); var resolver = CreateDefaultKeyResolver();
var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z"); var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z");
var key2 = CreateKey("2016-03-01 00:00:00Z", "2017-03-01 00:00:00Z", isRevoked: true); var key2 = CreateKey("2016-03-01 00:00:00Z", "2017-03-01 00:00:00Z", isRevoked: true);
var key3 = CreateKey("2016-03-01 00:00:00Z", "2016-03-02 00:00:00Z"); // key expires too soon var key3 = CreateKey("2016-03-01 00:00:00Z", "2016-03-02 00:00:00Z"); // key expires too soon
@ -113,7 +112,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
public void ResolveDefaultKeyPolicy_MostRecentKeyIsInvalid_BecauseOfRevocation_ReturnsNull() public void ResolveDefaultKeyPolicy_MostRecentKeyIsInvalid_BecauseOfRevocation_ReturnsNull()
{ {
// Arrange // Arrange
var resolver = CreateDefaultKeyResolver(new MyEncryptorFactory()); var resolver = CreateDefaultKeyResolver();
var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z"); var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z");
var key2 = CreateKey("2015-03-02 00:00:00Z", "2016-03-01 00:00:00Z", isRevoked: true); var key2 = CreateKey("2015-03-02 00:00:00Z", "2016-03-01 00:00:00Z", isRevoked: true);
@ -130,8 +129,8 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
{ {
// Arrange // Arrange
var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z"); var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z");
var key2 = CreateKey("2015-03-02 00:00:00Z", "2016-03-01 00:00:00Z"); var key2 = CreateKey("2015-03-02 00:00:00Z", "2016-03-01 00:00:00Z", createEncryptorThrows: true);
var resolver = CreateDefaultKeyResolver(new MyEncryptorFactory(throwForKeys: key2)); var resolver = CreateDefaultKeyResolver();
// Act // Act
var resolution = resolver.ResolveDefaultKeyPolicy("2015-04-01 00:00:00Z", key1, key2); var resolution = resolver.ResolveDefaultKeyPolicy("2015-04-01 00:00:00Z", key1, key2);
@ -145,7 +144,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
public void ResolveDefaultKeyPolicy_FutureKeyIsValidAndWithinClockSkew_ReturnsFutureKey() public void ResolveDefaultKeyPolicy_FutureKeyIsValidAndWithinClockSkew_ReturnsFutureKey()
{ {
// Arrange // Arrange
var resolver = CreateDefaultKeyResolver(new MyEncryptorFactory()); var resolver = CreateDefaultKeyResolver();
var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z"); var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z");
// Act // Act
@ -160,7 +159,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
public void ResolveDefaultKeyPolicy_FutureKeyIsValidButNotWithinClockSkew_ReturnsNull() public void ResolveDefaultKeyPolicy_FutureKeyIsValidButNotWithinClockSkew_ReturnsNull()
{ {
// Arrange // Arrange
var resolver = CreateDefaultKeyResolver(new MyEncryptorFactory()); var resolver = CreateDefaultKeyResolver();
var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z"); var key1 = CreateKey("2015-03-01 00:00:00Z", "2016-03-01 00:00:00Z");
// Act // Act
@ -175,7 +174,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
public void ResolveDefaultKeyPolicy_IgnoresExpiredOrRevokedFutureKeys() public void ResolveDefaultKeyPolicy_IgnoresExpiredOrRevokedFutureKeys()
{ {
// Arrange // Arrange
var resolver = CreateDefaultKeyResolver(new MyEncryptorFactory()); var resolver = CreateDefaultKeyResolver();
var key1 = CreateKey("2015-03-01 00:00:00Z", "2014-03-01 00:00:00Z"); // expiration before activation should never occur var key1 = CreateKey("2015-03-01 00:00:00Z", "2014-03-01 00:00:00Z"); // expiration before activation should never occur
var key2 = CreateKey("2015-03-01 00:01:00Z", "2015-04-01 00:00:00Z", isRevoked: true); var key2 = CreateKey("2015-03-01 00:01:00Z", "2015-04-01 00:00:00Z", isRevoked: true);
var key3 = CreateKey("2015-03-01 00:02:00Z", "2015-04-01 00:00:00Z"); var key3 = CreateKey("2015-03-01 00:02:00Z", "2015-04-01 00:00:00Z");
@ -192,7 +191,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
public void ResolveDefaultKeyPolicy_FallbackKey_SelectsLatestBeforePriorPropagationWindow_IgnoresRevokedKeys() public void ResolveDefaultKeyPolicy_FallbackKey_SelectsLatestBeforePriorPropagationWindow_IgnoresRevokedKeys()
{ {
// Arrange // Arrange
var resolver = CreateDefaultKeyResolver(new MyEncryptorFactory()); var resolver = CreateDefaultKeyResolver();
var key1 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-01 00:00:00Z"); var key1 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-01 00:00:00Z");
var key2 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-02 00:00:00Z"); var key2 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-02 00:00:00Z");
var key3 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-03 00:00:00Z", isRevoked: true); var key3 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-03 00:00:00Z", isRevoked: true);
@ -212,9 +211,9 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
// Arrange // Arrange
var key1 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-01 00:00:00Z"); var key1 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-01 00:00:00Z");
var key2 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-02 00:00:00Z"); var key2 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-02 00:00:00Z");
var key3 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-03 00:00:00Z"); var key3 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-03 00:00:00Z", createEncryptorThrows: true);
var key4 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-04 00:00:00Z"); var key4 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-04 00:00:00Z");
var resolver = CreateDefaultKeyResolver(new MyEncryptorFactory(throwForKeys: key3)); var resolver = CreateDefaultKeyResolver();
// Act // Act
var resolution = resolver.ResolveDefaultKeyPolicy("2000-01-05 00:00:00Z", key1, key2, key3, key4); var resolution = resolver.ResolveDefaultKeyPolicy("2000-01-05 00:00:00Z", key1, key2, key3, key4);
@ -228,7 +227,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
public void ResolveDefaultKeyPolicy_FallbackKey_NoNonRevokedKeysBeforePriorPropagationWindow_SelectsEarliestNonRevokedKey() public void ResolveDefaultKeyPolicy_FallbackKey_NoNonRevokedKeysBeforePriorPropagationWindow_SelectsEarliestNonRevokedKey()
{ {
// Arrange // Arrange
var resolver = CreateDefaultKeyResolver(new MyEncryptorFactory()); var resolver = CreateDefaultKeyResolver();
var key1 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-03 00:00:00Z", isRevoked: true); var key1 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-03 00:00:00Z", isRevoked: true);
var key2 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-04 00:00:00Z"); var key2 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-04 00:00:00Z");
var key3 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-05 00:00:00Z"); var key3 = CreateKey("2010-01-01 00:00:00Z", "2010-01-01 00:00:00Z", creationDate: "2000-01-05 00:00:00Z");
@ -241,14 +240,13 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
Assert.True(resolution.ShouldGenerateNewKey); Assert.True(resolution.ShouldGenerateNewKey);
} }
private static IDefaultKeyResolver CreateDefaultKeyResolver(IAuthenticatedEncryptorFactory encryptorFactory) private static IDefaultKeyResolver CreateDefaultKeyResolver()
{ {
var options = Options.Create(new KeyManagementOptions()); var options = Options.Create(new KeyManagementOptions());
options.Value.AuthenticatedEncryptorFactories.Add(encryptorFactory);
return new DefaultKeyResolver(options, NullLoggerFactory.Instance); return new DefaultKeyResolver(options, NullLoggerFactory.Instance);
} }
private static IKey CreateKey(string activationDate, string expirationDate, string creationDate = null, bool isRevoked = false) private static IKey CreateKey(string activationDate, string expirationDate, string creationDate = null, bool isRevoked = false, bool createEncryptorThrows = false)
{ {
var mockKey = new Mock<IKey>(); var mockKey = new Mock<IKey>();
mockKey.Setup(o => o.KeyId).Returns(Guid.NewGuid()); mockKey.Setup(o => o.KeyId).Returns(Guid.NewGuid());
@ -256,31 +254,17 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
mockKey.Setup(o => o.ActivationDate).Returns(DateTimeOffset.ParseExact(activationDate, "u", CultureInfo.InvariantCulture)); mockKey.Setup(o => o.ActivationDate).Returns(DateTimeOffset.ParseExact(activationDate, "u", CultureInfo.InvariantCulture));
mockKey.Setup(o => o.ExpirationDate).Returns(DateTimeOffset.ParseExact(expirationDate, "u", CultureInfo.InvariantCulture)); mockKey.Setup(o => o.ExpirationDate).Returns(DateTimeOffset.ParseExact(expirationDate, "u", CultureInfo.InvariantCulture));
mockKey.Setup(o => o.IsRevoked).Returns(isRevoked); mockKey.Setup(o => o.IsRevoked).Returns(isRevoked);
if (createEncryptorThrows)
{
mockKey.Setup(o => o.CreateEncryptor()).Throws(new Exception("This method fails."));
}
else
{
mockKey.Setup(o => o.CreateEncryptor()).Returns(Mock.Of<IAuthenticatedEncryptor>());
}
return mockKey.Object; return mockKey.Object;
} }
private class MyEncryptorFactory : IAuthenticatedEncryptorFactory
{
private IReadOnlyList<IKey> _throwForKeys;
public MyEncryptorFactory(params IKey[] throwForKeys)
{
_throwForKeys = throwForKeys;
}
public IAuthenticatedEncryptor CreateEncryptorInstance(IKey key)
{
if (_throwForKeys.Contains(key))
{
throw new Exception("This method fails.");
}
else
{
return new Mock<IAuthenticatedEncryptor>().Object;
}
}
}
} }
internal static class DefaultKeyResolverExtensions internal static class DefaultKeyResolverExtensions

View File

@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Moq; using Moq;
using Xunit; using Xunit;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
namespace Microsoft.AspNetCore.DataProtection.KeyManagement namespace Microsoft.AspNetCore.DataProtection.KeyManagement
{ {
@ -30,10 +31,10 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
XmlAssert.Equal(@"<node />", element); XmlAssert.Equal(@"<node />", element);
return mockDescriptor; return mockDescriptor;
}); });
var options = Options.Create(new KeyManagementOptions()); var encryptorFactory = Mock.Of<IAuthenticatedEncryptorFactory>();
// Act // Act
var key = new DeferredKey(keyId, creationDate, activationDate, expirationDate, mockInternalKeyManager.Object, XElement.Parse(@"<node />")); var key = new DeferredKey(keyId, creationDate, activationDate, expirationDate, mockInternalKeyManager.Object, XElement.Parse(@"<node />"), new[] { encryptorFactory });
// Assert // Assert
Assert.Equal(keyId, key.KeyId); Assert.Equal(keyId, key.KeyId);
@ -48,8 +49,8 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
{ {
// Arrange // Arrange
var now = DateTimeOffset.UtcNow; var now = DateTimeOffset.UtcNow;
var options = Options.Create(new KeyManagementOptions()); var encryptorFactory = Mock.Of<IAuthenticatedEncryptorFactory>();
var key = new DeferredKey(Guid.Empty, now, now, now, new Mock<IInternalXmlKeyManager>().Object, XElement.Parse(@"<node />")); var key = new DeferredKey(Guid.Empty, now, now, now, new Mock<IInternalXmlKeyManager>().Object, XElement.Parse(@"<node />"), new[] { encryptorFactory });
// Act & assert // Act & assert
Assert.False(key.IsRevoked); Assert.False(key.IsRevoked);
@ -71,7 +72,8 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
}); });
var now = DateTimeOffset.UtcNow; var now = DateTimeOffset.UtcNow;
var key = new DeferredKey(Guid.Empty, now, now, now, mockKeyManager.Object, XElement.Parse(@"<node />")); var encryptorFactory = Mock.Of<IAuthenticatedEncryptorFactory>();
var key = new DeferredKey(Guid.Empty, now, now, now, mockKeyManager.Object, XElement.Parse(@"<node />"), new[] { encryptorFactory });
// Act & assert // Act & assert
ExceptionAssert.Throws<Exception>(() => key.Descriptor, "How exceptional."); ExceptionAssert.Throws<Exception>(() => key.Descriptor, "How exceptional.");

View File

@ -208,8 +208,8 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
var encryptorFactory = new AuthenticatedEncryptorFactory(NullLoggerFactory.Instance); var encryptorFactory = new AuthenticatedEncryptorFactory(NullLoggerFactory.Instance);
// the keyring has only one key // the keyring has only one key
Key key = new Key(Guid.Empty, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, mockDescriptor.Object); Key key = new Key(Guid.Empty, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, mockDescriptor.Object, new[] { mockEncryptorFactory.Object });
var keyRing = new KeyRing(key, new[] { key }, new[] { mockEncryptorFactory.Object }); var keyRing = new KeyRing(key, new[] { key });
var mockKeyRingProvider = new Mock<IKeyRingProvider>(); var mockKeyRingProvider = new Mock<IKeyRingProvider>();
mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing); mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing);
@ -238,9 +238,9 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
mockEncryptorFactory.Setup(o => o.CreateEncryptorInstance(It.IsAny<IKey>())).Returns(new Mock<IAuthenticatedEncryptor>().Object); mockEncryptorFactory.Setup(o => o.CreateEncryptorInstance(It.IsAny<IKey>())).Returns(new Mock<IAuthenticatedEncryptor>().Object);
// the keyring has only one key // the keyring has only one key
Key key = new Key(keyId, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, mockDescriptor.Object); Key key = new Key(keyId, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, mockDescriptor.Object, new[] { mockEncryptorFactory.Object });
key.SetRevoked(); key.SetRevoked();
var keyRing = new KeyRing(key, new[] { key }, new[] { mockEncryptorFactory.Object }); var keyRing = new KeyRing(key, new[] { key });
var mockKeyRingProvider = new Mock<IKeyRingProvider>(); var mockKeyRingProvider = new Mock<IKeyRingProvider>();
mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing); mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing);
@ -278,9 +278,9 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
var mockEncryptorFactory = new Mock<IAuthenticatedEncryptorFactory>(); var mockEncryptorFactory = new Mock<IAuthenticatedEncryptorFactory>();
mockEncryptorFactory.Setup(o => o.CreateEncryptorInstance(It.IsAny<IKey>())).Returns(mockEncryptor.Object); mockEncryptorFactory.Setup(o => o.CreateEncryptorInstance(It.IsAny<IKey>())).Returns(mockEncryptor.Object);
Key defaultKey = new Key(defaultKeyId, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, mockDescriptor.Object); Key defaultKey = new Key(defaultKeyId, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, mockDescriptor.Object, new[] { mockEncryptorFactory.Object });
defaultKey.SetRevoked(); defaultKey.SetRevoked();
var keyRing = new KeyRing(defaultKey, new[] { defaultKey }, new[] { mockEncryptorFactory.Object }); var keyRing = new KeyRing(defaultKey, new[] { defaultKey });
var mockKeyRingProvider = new Mock<IKeyRingProvider>(); var mockKeyRingProvider = new Mock<IKeyRingProvider>();
mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing); mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing);
@ -326,8 +326,8 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
var mockEncryptorFactory = new Mock<IAuthenticatedEncryptorFactory>(); var mockEncryptorFactory = new Mock<IAuthenticatedEncryptorFactory>();
mockEncryptorFactory.Setup(o => o.CreateEncryptorInstance(It.IsAny<IKey>())).Returns(mockEncryptor.Object); mockEncryptorFactory.Setup(o => o.CreateEncryptorInstance(It.IsAny<IKey>())).Returns(mockEncryptor.Object);
Key defaultKey = new Key(defaultKeyId, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, mockDescriptor.Object); Key defaultKey = new Key(defaultKeyId, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, mockDescriptor.Object, new[] { mockEncryptorFactory.Object });
var keyRing = new KeyRing(defaultKey, new[] { defaultKey }, new[] { mockEncryptorFactory.Object }); var keyRing = new KeyRing(defaultKey, new[] { defaultKey });
var mockKeyRingProvider = new Mock<IKeyRingProvider>(); var mockKeyRingProvider = new Mock<IKeyRingProvider>();
mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing); mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing);
@ -376,9 +376,9 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
var mockEncryptorFactory = new Mock<IAuthenticatedEncryptorFactory>(); var mockEncryptorFactory = new Mock<IAuthenticatedEncryptorFactory>();
mockEncryptorFactory.Setup(o => o.CreateEncryptorInstance(It.IsAny<IKey>())).Returns(mockEncryptor.Object); mockEncryptorFactory.Setup(o => o.CreateEncryptorInstance(It.IsAny<IKey>())).Returns(mockEncryptor.Object);
Key defaultKey = new Key(defaultKeyId, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, new Mock<IAuthenticatedEncryptorDescriptor>().Object); Key defaultKey = new Key(defaultKeyId, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, new Mock<IAuthenticatedEncryptorDescriptor>().Object, new[] { mockEncryptorFactory.Object });
Key embeddedKey = new Key(embeddedKeyId, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, mockDescriptor.Object); Key embeddedKey = new Key(embeddedKeyId, DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, mockDescriptor.Object, new[] { mockEncryptorFactory.Object });
var keyRing = new KeyRing(defaultKey, new[] { defaultKey, embeddedKey }, new[] { mockEncryptorFactory.Object }); var keyRing = new KeyRing(defaultKey, new[] { defaultKey, embeddedKey });
var mockKeyRingProvider = new Mock<IKeyRingProvider>(); var mockKeyRingProvider = new Mock<IKeyRingProvider>();
mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing); mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing);
@ -408,9 +408,9 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
{ {
// Arrange // Arrange
byte[] plaintext = new byte[] { 0x10, 0x20, 0x30, 0x40, 0x50 }; byte[] plaintext = new byte[] { 0x10, 0x20, 0x30, 0x40, 0x50 };
Key key = new Key(Guid.NewGuid(), DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, new AuthenticatedEncryptorConfiguration().CreateNewDescriptor());
var encryptorFactory = new AuthenticatedEncryptorFactory(NullLoggerFactory.Instance); var encryptorFactory = new AuthenticatedEncryptorFactory(NullLoggerFactory.Instance);
var keyRing = new KeyRing(key, new[] { key }, new[] { encryptorFactory }); Key key = new Key(Guid.NewGuid(), DateTimeOffset.Now, DateTimeOffset.Now, DateTimeOffset.Now, new AuthenticatedEncryptorConfiguration().CreateNewDescriptor(), new[] { encryptorFactory });
var keyRing = new KeyRing(key, new[] { key });
var mockKeyRingProvider = new Mock<IKeyRingProvider>(); var mockKeyRingProvider = new Mock<IKeyRingProvider>();
mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing); mockKeyRingProvider.Setup(o => o.GetCurrentKeyRing()).Returns(keyRing);

View File

@ -644,6 +644,7 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
mockKey.Setup(o => o.ExpirationDate).Returns(DateTimeOffset.ParseExact(expirationDate, "u", CultureInfo.InvariantCulture)); mockKey.Setup(o => o.ExpirationDate).Returns(DateTimeOffset.ParseExact(expirationDate, "u", CultureInfo.InvariantCulture));
mockKey.Setup(o => o.IsRevoked).Returns(isRevoked); mockKey.Setup(o => o.IsRevoked).Returns(isRevoked);
mockKey.Setup(o => o.Descriptor).Returns(new Mock<IAuthenticatedEncryptorDescriptor>().Object); mockKey.Setup(o => o.Descriptor).Returns(new Mock<IAuthenticatedEncryptorDescriptor>().Object);
mockKey.Setup(o => o.CreateEncryptor()).Returns(new Mock<IAuthenticatedEncryptor>().Object);
return mockKey.Object; return mockKey.Object;
} }
} }

View File

@ -16,20 +16,19 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
{ {
// Arrange // Arrange
var expectedEncryptorInstance = new Mock<IAuthenticatedEncryptor>().Object; var expectedEncryptorInstance = new Mock<IAuthenticatedEncryptor>().Object;
var encryptorFactory = new MyEncryptorFactory(expectedEncryptorInstance);
var key1 = new MyKey(); var key1 = new MyKey(expectedEncryptorInstance: expectedEncryptorInstance);
var key2 = new MyKey(); var key2 = new MyKey();
// Act // Act
var keyRing = new KeyRing(key1, new[] { key1, key2 }, new[] { encryptorFactory }); var keyRing = new KeyRing(key1, new[] { key1, key2 });
// Assert // Assert
Assert.Equal(0, encryptorFactory.NumTimesCreateEncryptorInstanceCalled); Assert.Equal(0, key1.NumTimesCreateEncryptorInstanceCalled);
Assert.Same(expectedEncryptorInstance, keyRing.DefaultAuthenticatedEncryptor); Assert.Same(expectedEncryptorInstance, keyRing.DefaultAuthenticatedEncryptor);
Assert.Equal(1, encryptorFactory.NumTimesCreateEncryptorInstanceCalled); Assert.Equal(1, key1.NumTimesCreateEncryptorInstanceCalled);
Assert.Same(expectedEncryptorInstance, keyRing.DefaultAuthenticatedEncryptor); Assert.Same(expectedEncryptorInstance, keyRing.DefaultAuthenticatedEncryptor);
Assert.Equal(1, encryptorFactory.NumTimesCreateEncryptorInstanceCalled); // should've been cached Assert.Equal(1, key1.NumTimesCreateEncryptorInstanceCalled); // should've been cached
} }
[Fact] [Fact]
@ -38,10 +37,9 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
// Arrange // Arrange
var key1 = new MyKey(); var key1 = new MyKey();
var key2 = new MyKey(); var key2 = new MyKey();
var encryptorFactory = new MyEncryptorFactory();
// Act // Act
var keyRing = new KeyRing(key2, new[] { key1, key2 }, new[] { encryptorFactory }); var keyRing = new KeyRing(key2, new[] { key1, key2 });
// Assert // Assert
Assert.Equal(key2.KeyId, keyRing.DefaultKeyId); Assert.Equal(key2.KeyId, keyRing.DefaultKeyId);
@ -53,16 +51,15 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
// Arrange // Arrange
var key1 = new MyKey(); var key1 = new MyKey();
var key2 = new MyKey(); var key2 = new MyKey();
var key3 = new MyKey(); var key3 = new MyKey(expectedEncryptorInstance: new Mock<IAuthenticatedEncryptor>().Object);
var encryptorFactory = new MyEncryptorFactory(expectedEncryptorInstance: new Mock<IAuthenticatedEncryptor>().Object);
// Act // Act
var keyRing = new KeyRing(key3, new[] { key1, key2 }, new[] { encryptorFactory }); var keyRing = new KeyRing(key3, new[] { key1, key2 });
// Assert // Assert
bool unused; bool unused;
Assert.Equal(key3.KeyId, keyRing.DefaultKeyId); Assert.Equal(key3.KeyId, keyRing.DefaultKeyId);
Assert.Equal(encryptorFactory.CreateEncryptorInstance(key3), keyRing.GetAuthenticatedEncryptorByKeyId(key3.KeyId, out unused)); Assert.Equal(key3.CreateEncryptor(), keyRing.GetAuthenticatedEncryptorByKeyId(key3.KeyId, out unused));
} }
[Fact] [Fact]
@ -72,44 +69,46 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
var expectedEncryptorInstance1 = new Mock<IAuthenticatedEncryptor>().Object; var expectedEncryptorInstance1 = new Mock<IAuthenticatedEncryptor>().Object;
var expectedEncryptorInstance2 = new Mock<IAuthenticatedEncryptor>().Object; var expectedEncryptorInstance2 = new Mock<IAuthenticatedEncryptor>().Object;
var key1 = new MyKey(isRevoked: true); var key1 = new MyKey(expectedEncryptorInstance: expectedEncryptorInstance1, isRevoked: true);
var key2 = new MyKey(); var key2 = new MyKey(expectedEncryptorInstance: expectedEncryptorInstance2);
var encryptorFactory1 = new MyEncryptorFactory(expectedEncryptorInstance: expectedEncryptorInstance1, associatedKey: key1);
var encryptorFactory2 = new MyEncryptorFactory(expectedEncryptorInstance: expectedEncryptorInstance2, associatedKey: key2);
// Act // Act
var keyRing = new KeyRing(key2, new[] { key1, key2 }, new[] { encryptorFactory1, encryptorFactory2 }); var keyRing = new KeyRing(key2, new[] { key1, key2 });
// Assert // Assert
bool isRevoked; bool isRevoked;
Assert.Equal(0, encryptorFactory1.NumTimesCreateEncryptorInstanceCalled); Assert.Equal(0, key1.NumTimesCreateEncryptorInstanceCalled);
Assert.Same(expectedEncryptorInstance1, keyRing.GetAuthenticatedEncryptorByKeyId(key1.KeyId, out isRevoked)); Assert.Same(expectedEncryptorInstance1, keyRing.GetAuthenticatedEncryptorByKeyId(key1.KeyId, out isRevoked));
Assert.True(isRevoked); Assert.True(isRevoked);
Assert.Equal(1, encryptorFactory1.NumTimesCreateEncryptorInstanceCalled); Assert.Equal(1, key1.NumTimesCreateEncryptorInstanceCalled);
Assert.Same(expectedEncryptorInstance1, keyRing.GetAuthenticatedEncryptorByKeyId(key1.KeyId, out isRevoked)); Assert.Same(expectedEncryptorInstance1, keyRing.GetAuthenticatedEncryptorByKeyId(key1.KeyId, out isRevoked));
Assert.True(isRevoked); Assert.True(isRevoked);
Assert.Equal(1, encryptorFactory1.NumTimesCreateEncryptorInstanceCalled); Assert.Equal(1, key1.NumTimesCreateEncryptorInstanceCalled);
Assert.Equal(0, encryptorFactory2.NumTimesCreateEncryptorInstanceCalled); Assert.Equal(0, key2.NumTimesCreateEncryptorInstanceCalled);
Assert.Same(expectedEncryptorInstance2, keyRing.GetAuthenticatedEncryptorByKeyId(key2.KeyId, out isRevoked)); Assert.Same(expectedEncryptorInstance2, keyRing.GetAuthenticatedEncryptorByKeyId(key2.KeyId, out isRevoked));
Assert.False(isRevoked); Assert.False(isRevoked);
Assert.Equal(1, encryptorFactory2.NumTimesCreateEncryptorInstanceCalled); Assert.Equal(1, key2.NumTimesCreateEncryptorInstanceCalled);
Assert.Same(expectedEncryptorInstance2, keyRing.GetAuthenticatedEncryptorByKeyId(key2.KeyId, out isRevoked)); Assert.Same(expectedEncryptorInstance2, keyRing.GetAuthenticatedEncryptorByKeyId(key2.KeyId, out isRevoked));
Assert.False(isRevoked); Assert.False(isRevoked);
Assert.Equal(1, encryptorFactory2.NumTimesCreateEncryptorInstanceCalled); Assert.Equal(1, key2.NumTimesCreateEncryptorInstanceCalled);
Assert.Same(expectedEncryptorInstance2, keyRing.DefaultAuthenticatedEncryptor); Assert.Same(expectedEncryptorInstance2, keyRing.DefaultAuthenticatedEncryptor);
Assert.Equal(1, encryptorFactory2.NumTimesCreateEncryptorInstanceCalled); Assert.Equal(1, key2.NumTimesCreateEncryptorInstanceCalled);
} }
private sealed class MyKey : IKey private sealed class MyKey : IKey
{ {
public MyKey(bool isRevoked = false) public int NumTimesCreateEncryptorInstanceCalled;
private readonly Func<IAuthenticatedEncryptor> _encryptorFactory;
public MyKey(bool isRevoked = false, IAuthenticatedEncryptor expectedEncryptorInstance = null)
{ {
CreationDate = DateTimeOffset.Now; CreationDate = DateTimeOffset.Now;
ActivationDate = CreationDate + TimeSpan.FromHours(1); ActivationDate = CreationDate + TimeSpan.FromHours(1);
ExpirationDate = CreationDate + TimeSpan.FromDays(30); ExpirationDate = CreationDate + TimeSpan.FromDays(30);
IsRevoked = isRevoked; IsRevoked = isRevoked;
KeyId = Guid.NewGuid(); KeyId = Guid.NewGuid();
_encryptorFactory = () => expectedEncryptorInstance ?? new Mock<IAuthenticatedEncryptor>().Object;
} }
public DateTimeOffset ActivationDate { get; } public DateTimeOffset ActivationDate { get; }
@ -118,30 +117,11 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
public bool IsRevoked { get; } public bool IsRevoked { get; }
public Guid KeyId { get; } public Guid KeyId { get; }
public IAuthenticatedEncryptorDescriptor Descriptor => throw new NotImplementedException(); public IAuthenticatedEncryptorDescriptor Descriptor => throw new NotImplementedException();
}
private sealed class MyEncryptorFactory : IAuthenticatedEncryptorFactory public IAuthenticatedEncryptor CreateEncryptor()
{
public int NumTimesCreateEncryptorInstanceCalled;
private IAuthenticatedEncryptor _expectedEncryptorInstance;
private IKey _associatedKey;
public MyEncryptorFactory(IAuthenticatedEncryptor expectedEncryptorInstance = null, IKey associatedKey = null)
{ {
_expectedEncryptorInstance = expectedEncryptorInstance;
_associatedKey = associatedKey;
}
public IAuthenticatedEncryptor CreateEncryptorInstance(IKey key)
{
if (_associatedKey != null && key != _associatedKey)
{
return null;
}
NumTimesCreateEncryptorInstanceCalled++; NumTimesCreateEncryptorInstanceCalled++;
return _encryptorFactory();
return _expectedEncryptorInstance ?? new Mock<IAuthenticatedEncryptor>().Object;
} }
} }
} }

View File

@ -5,6 +5,7 @@ using System;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel; using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel;
using Moq; using Moq;
using Xunit; using Xunit;
using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption;
namespace Microsoft.AspNetCore.DataProtection.KeyManagement namespace Microsoft.AspNetCore.DataProtection.KeyManagement
{ {
@ -19,9 +20,10 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
var activationDate = creationDate.AddDays(2); var activationDate = creationDate.AddDays(2);
var expirationDate = creationDate.AddDays(90); var expirationDate = creationDate.AddDays(90);
var descriptor = Mock.Of<IAuthenticatedEncryptorDescriptor>(); var descriptor = Mock.Of<IAuthenticatedEncryptorDescriptor>();
var encryptorFactory = Mock.Of<IAuthenticatedEncryptorFactory>();
// Act // Act
var key = new Key(keyId, creationDate, activationDate, expirationDate, descriptor); var key = new Key(keyId, creationDate, activationDate, expirationDate, descriptor, new[] { encryptorFactory });
// Assert // Assert
Assert.Equal(keyId, key.KeyId); Assert.Equal(keyId, key.KeyId);
@ -36,7 +38,8 @@ namespace Microsoft.AspNetCore.DataProtection.KeyManagement
{ {
// Arrange // Arrange
var now = DateTimeOffset.UtcNow; var now = DateTimeOffset.UtcNow;
var key = new Key(Guid.Empty, now, now, now, new Mock<IAuthenticatedEncryptorDescriptor>().Object); var encryptorFactory = Mock.Of<IAuthenticatedEncryptorFactory>();
var key = new Key(Guid.Empty, now, now, now, new Mock<IAuthenticatedEncryptorDescriptor>().Object, new[] { encryptorFactory });
// Act & assert // Act & assert
Assert.False(key.IsRevoked); Assert.False(key.IsRevoked);