// Copyright (c) .NET Foundation. 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.AspNetCore.DataProtection
{
///
/// Helpful extension methods for data protection APIs.
///
public static class DataProtectionAdvancedExtensions
{
///
/// Cryptographically protects a piece of plaintext data, expiring the data after
/// the specified amount of time has elapsed.
///
/// The protector to use.
/// The plaintext data to protect.
/// The amount of time after which the payload should no longer be unprotectable.
/// The protected form of the plaintext data.
public static byte[] Protect(this ITimeLimitedDataProtector protector, byte[] plaintext, TimeSpan lifetime)
{
if (protector == null)
{
throw new ArgumentNullException(nameof(protector));
}
if (plaintext == null)
{
throw new ArgumentNullException(nameof(plaintext));
}
return protector.Protect(plaintext, DateTimeOffset.UtcNow + lifetime);
}
///
/// Cryptographically protects a piece of plaintext data, expiring the data at
/// the chosen time.
///
/// The protector to use.
/// The plaintext data to protect.
/// The time when this payload should expire.
/// The protected form of the plaintext data.
public static string Protect(this ITimeLimitedDataProtector protector, string plaintext, DateTimeOffset expiration)
{
if (protector == null)
{
throw new ArgumentNullException(nameof(protector));
}
if (plaintext == null)
{
throw new ArgumentNullException(nameof(plaintext));
}
var wrappingProtector = new TimeLimitedWrappingProtector(protector) { Expiration = expiration };
return wrappingProtector.Protect(plaintext);
}
///
/// Cryptographically protects a piece of plaintext data, expiring the data after
/// the specified amount of time has elapsed.
///
/// The protector to use.
/// The plaintext data to protect.
/// The amount of time after which the payload should no longer be unprotectable.
/// The protected form of the plaintext data.
public static string Protect(this ITimeLimitedDataProtector protector, string plaintext, TimeSpan lifetime)
{
if (protector == null)
{
throw new ArgumentNullException(nameof(protector));
}
if (plaintext == null)
{
throw new ArgumentNullException(nameof(plaintext));
}
return Protect(protector, plaintext, DateTimeOffset.Now + lifetime);
}
///
/// Converts an into an
/// so that payloads can be protected with a finite lifetime.
///
/// The to convert to a time-limited protector.
/// An .
public static ITimeLimitedDataProtector ToTimeLimitedDataProtector(this IDataProtector protector)
{
if (protector == null)
{
throw new ArgumentNullException(nameof(protector));
}
return (protector as ITimeLimitedDataProtector) ?? new TimeLimitedDataProtector(protector);
}
///
/// Cryptographically unprotects a piece of protected data.
///
/// The protector to use.
/// The protected data to unprotect.
/// An 'out' parameter which upon a successful unprotect
/// operation receives the expiration date of the payload.
/// The plaintext form of the protected data.
///
/// Thrown if is invalid, malformed, or expired.
///
public static string Unprotect(this ITimeLimitedDataProtector protector, string protectedData, out DateTimeOffset expiration)
{
if (protector == null)
{
throw new ArgumentNullException(nameof(protector));
}
if (protectedData == null)
{
throw new ArgumentNullException(nameof(protectedData));
}
var wrappingProtector = new TimeLimitedWrappingProtector(protector);
string retVal = wrappingProtector.Unprotect(protectedData);
expiration = wrappingProtector.Expiration;
return retVal;
}
private sealed class TimeLimitedWrappingProtector : IDataProtector
{
public DateTimeOffset Expiration;
private readonly ITimeLimitedDataProtector _innerProtector;
public TimeLimitedWrappingProtector(ITimeLimitedDataProtector innerProtector)
{
_innerProtector = innerProtector;
}
public IDataProtector CreateProtector(string purpose)
{
if (purpose == null)
{
throw new ArgumentNullException(nameof(purpose));
}
throw new NotImplementedException();
}
public byte[] Protect(byte[] plaintext)
{
if (plaintext == null)
{
throw new ArgumentNullException(nameof(plaintext));
}
return _innerProtector.Protect(plaintext, Expiration);
}
public byte[] Unprotect(byte[] protectedData)
{
if (protectedData == null)
{
throw new ArgumentNullException(nameof(protectedData));
}
return _innerProtector.Unprotect(protectedData, out Expiration);
}
}
}
}