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 void Store(Guid keyId, XElement element) { // Encrypt the key element to the escrow encryptor. var encryptedXmlInfo = _escrowEncryptor.Encrypt(element); // A real implementation would save the escrowed key to a // write-only file share or some other stable storage, but // in this sample we'll just write it out to the console. Console.WriteLine($"Escrowing key {keyId}"); Console.WriteLine(encryptedXmlInfo.EncryptedElement); // Note: We cannot read the escrowed key material ourselves. // We need to get a member of CONTOSO\Domain Admins to read // it for us in the event we need to recover it. }
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)); }