// 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); } } } }