public static XElement?EncryptIfNecessary(this IXmlEncryptor encryptor, XElement element) { // If no encryption is necessary, return null. if (!DoesElementOrDescendentRequireEncryption(element)) { return(null); } // Deep copy the element (since we're going to mutate) and put // it into a document to guarantee it has a parent. var doc = new XDocument(new XElement(element)); // We remove elements from the document as we encrypt them and perform // fix-up later. This keeps us from going into an infinite loop in // the case of a null encryptor (which returns its original input which // is still marked as 'requires encryption'). var placeholderReplacements = new Dictionary <XElement, EncryptedXmlInfo>(); while (true) { var elementWhichRequiresEncryption = doc.Descendants().FirstOrDefault(DoesSingleElementRequireEncryption); if (elementWhichRequiresEncryption == null) { // All encryption is finished. break; } // Encrypt the clone so that the encryptor doesn't inadvertently modify // the original document or other data structures. var clonedElementWhichRequiresEncryption = new XElement(elementWhichRequiresEncryption); var innerDoc = new XDocument(clonedElementWhichRequiresEncryption); var encryptedXmlInfo = encryptor.Encrypt(clonedElementWhichRequiresEncryption); CryptoUtil.Assert(encryptedXmlInfo != null, "IXmlEncryptor.Encrypt returned null."); // Put a placeholder into the original document so that we can continue our // search for elements which need to be encrypted. var newPlaceholder = new XElement("placeholder"); placeholderReplacements[newPlaceholder] = encryptedXmlInfo; elementWhichRequiresEncryption.ReplaceWith(newPlaceholder); } // Finally, perform fixup. Debug.Assert(placeholderReplacements.Count > 0); foreach (var entry in placeholderReplacements) { // <enc:encryptedSecret decryptorType="{type}" xmlns:enc="{ns}"> // <element /> // </enc:encryptedSecret> entry.Key.ReplaceWith( new XElement(XmlConstants.EncryptedSecretElementName, new XAttribute(XmlConstants.DecryptorTypeAttributeName, entry.Value.DecryptorType.AssemblyQualifiedName !), entry.Value.EncryptedElement)); } return(doc.Root); }
public MyKeyEscrowSink(IServiceProvider services) { // Assuming I'm on a machine that's a member of the CONTOSO // domain, I can use the Domain Admins SID to generate an // encrypted payload that only they can read. Sample SID from // https://technet.microsoft.com/library/cc778824(v=ws.10).aspx. _escrowEncryptor = new DpapiNGXmlEncryptor( "SID=S-1-5-21-1004336348-1177238915-682003330-512", DpapiNGProtectionDescriptorFlags.None, services); }
public MyKeyEscrowSink(IServiceProvider services) { // Assuming I'm on a machine that's a member of the CONTOSO // domain, I can use the Domain Admins SID to generate an // encrypted payload that only they can read. Sample SID from // https://technet.microsoft.com/en-us/library/cc778824(v=ws.10).aspx. _escrowEncryptor = new DpapiNGXmlEncryptor( "SID=S-1-5-21-1004336348-1177238915-682003330-512", DpapiNGProtectionDescriptorFlags.None, services); }
public XmlKeyManager( [NotNull] IServiceProvider serviceProvider, [NotNull] IAuthenticatedEncryptorConfigurationFactory authenticatedEncryptorConfigurationFactory, [NotNull] ITypeActivator typeActivator, [NotNull] IXmlRepository xmlRepository, [NotNull] IXmlEncryptor xmlEncryptor) { _serviceProvider = serviceProvider; _authenticatedEncryptorConfigurationFactory = authenticatedEncryptorConfigurationFactory; _typeActivator = typeActivator; _xmlRepository = xmlRepository; _xmlEncryptor = xmlEncryptor; }
public XElement ToXml([NotNull] IXmlEncryptor xmlEncryptor) { // <cbcEncryptor reader="{TYPE}"> // <encryption algorithm="{STRING}" provider="{STRING}" keyLength="{INT}" /> // <secret>...</secret> // </cbcEncryptor> return(new XElement(GcmEncryptorElementName, new XAttribute("reader", typeof(CngGcmAuthenticatedEncryptorConfigurationXmlReader).AssemblyQualifiedName), new XElement(EncryptionElementName, new XAttribute("algorithm", _options.EncryptionAlgorithm), new XAttribute("provider", _options.EncryptionAlgorithmProvider ?? String.Empty), new XAttribute("keyLength", _options.EncryptionAlgorithmKeySize)), EncryptSecret(xmlEncryptor))); }
public XElement ToXml([NotNull] IXmlEncryptor xmlEncryptor) { // <managedEncryptor reader="{TYPE}"> // <encryption type="{TYPE}" keyLength="{INT}" /> // <validation type="{TYPE}" /> // <secret>...</secret> // </managedEncryptor> return(new XElement(ManagedEncryptorElementName, new XAttribute("reader", typeof(ManagedAuthenticatedEncryptorConfigurationXmlReader).AssemblyQualifiedName), new XElement(EncryptionElementName, new XAttribute("type", _options.EncryptionAlgorithmType), new XAttribute("keyLength", _options.EncryptionAlgorithmKeySize)), new XElement(ValidationElementName, new XAttribute("type", _options.ValidationAlgorithmType)), EncryptSecret(xmlEncryptor))); }
private XElement EncryptSecret(IXmlEncryptor encryptor) { // First, create the inner <secret> element. XElement secretElement; byte[] plaintextSecret = new byte[_secret.Length]; try { _secret.WriteSecretIntoBuffer(new ArraySegment <byte>(plaintextSecret)); secretElement = new XElement(SecretElementName, Convert.ToBase64String(plaintextSecret)); } finally { Array.Clear(plaintextSecret, 0, plaintextSecret.Length); } // Then encrypt it and wrap it in another <secret> element. var encryptedSecretElement = encryptor.Encrypt(secretElement); CryptoUtil.Assert(!String.IsNullOrEmpty((string)encryptedSecretElement.Attribute("decryptor")), @"TODO: <secret> encryption was invalid."); return(new XElement(SecretElementName, encryptedSecretElement)); }
internal KeyValuePair <IXmlRepository, IXmlEncryptor> GetFallbackKeyRepositoryEncryptorPair() { IXmlRepository repository = null; IXmlEncryptor encryptor = null; // If we're running in Azure Web Sites, the key repository goes in the %HOME% directory. var azureWebSitesKeysFolder = _keyStorageDirectories.GetKeyStorageDirectoryForAzureWebSites(); if (azureWebSitesKeysFolder != null) { _logger.UsingAzureAsKeyRepository(azureWebSitesKeysFolder.FullName); // Cloud DPAPI isn't yet available, so we don't encrypt keys at rest. // This isn't all that different than what Azure Web Sites does today, and we can always add this later. repository = new FileSystemXmlRepository(azureWebSitesKeysFolder, _loggerFactory); } else { // If the user profile is available, store keys in the user profile directory. var localAppDataKeysFolder = _keyStorageDirectories.GetKeyStorageDirectory(); if (localAppDataKeysFolder != null) { if (OSVersionUtil.IsWindows()) { Debug.Assert(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); // Hint for the platform compatibility analyzer. // If the user profile is available, we can protect using DPAPI. // Probe to see if protecting to local user is available, and use it as the default if so. encryptor = new DpapiXmlEncryptor( protectToLocalMachine: !DpapiSecretSerializerHelper.CanProtectToCurrentUserAccount(), loggerFactory: _loggerFactory); } repository = new FileSystemXmlRepository(localAppDataKeysFolder, _loggerFactory); if (encryptor != null) { _logger.UsingProfileAsKeyRepositoryWithDPAPI(localAppDataKeysFolder.FullName); } else { _logger.UsingProfileAsKeyRepository(localAppDataKeysFolder.FullName); } } else { // Use profile isn't available - can we use the HKLM registry? RegistryKey regKeyStorageKey = null; if (OSVersionUtil.IsWindows()) { Debug.Assert(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); // Hint for the platform compatibility analyzer. regKeyStorageKey = RegistryXmlRepository.DefaultRegistryKey; } if (regKeyStorageKey != null) { Debug.Assert(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); // Hint for the platform compatibility analyzer. regKeyStorageKey = RegistryXmlRepository.DefaultRegistryKey; // If the user profile isn't available, we can protect using DPAPI (to machine). encryptor = new DpapiXmlEncryptor(protectToLocalMachine: true, loggerFactory: _loggerFactory); repository = new RegistryXmlRepository(regKeyStorageKey, _loggerFactory); _logger.UsingRegistryAsKeyRepositoryWithDPAPI(regKeyStorageKey.Name); } else { // Final fallback - use an ephemeral repository since we don't know where else to go. // This can only be used for development scenarios. repository = new EphemeralXmlRepository(_loggerFactory); _logger.UsingEphemeralKeyRepository(); } } } return(new KeyValuePair <IXmlRepository, IXmlEncryptor>(repository, encryptor)); }