private async Task <XElement> DecryptAsync(XElement encryptedElement)
        {
            var kid          = (string)encryptedElement.Element("kid");
            var symmetricKey = Convert.FromBase64String((string)encryptedElement.Element("key"));
            var symmetricIV  = Convert.FromBase64String((string)encryptedElement.Element("iv"));

            var encryptedValue = Convert.FromBase64String((string)encryptedElement.Element("value"));

            var key = await _client.ResolveAsync(kid).ConfigureAwait(false);

            var result = await key.UnwrapKeyAsync(AzureKeyVaultXmlEncryptor.DefaultKeyEncryption, symmetricKey).ConfigureAwait(false);

            byte[] decryptedValue;
            using (var symmetricAlgorithm = AzureKeyVaultXmlEncryptor.DefaultSymmetricAlgorithmFactory())
            {
                using (var decryptor = symmetricAlgorithm.CreateDecryptor(result, symmetricIV))
                {
                    decryptedValue = decryptor.TransformFinalBlock(encryptedValue, 0, encryptedValue.Length);
                }
            }

            using (var memoryStream = new MemoryStream(decryptedValue))
            {
                return(XElement.Load(memoryStream));
            }
        }
Ejemplo n.º 2
0
        private static async Task <byte[]> UnwrapKeyInternal(EncryptionData encryptionData, IKeyEncryptionKeyResolver keyResolver, bool async, CancellationToken cancellationToken)
        {
            IKeyEncryptionKey oldKey = async
                    ? await keyResolver.ResolveAsync(encryptionData.WrappedContentKey.KeyId, cancellationToken).ConfigureAwait(false)
                    : keyResolver.Resolve(encryptionData.WrappedContentKey.KeyId, cancellationToken);

            if (oldKey == default)
            {
                throw Errors.ClientSideEncryption.KeyNotFound(encryptionData.WrappedContentKey.KeyId);
            }

            return(async
                ? await oldKey.UnwrapKeyAsync(
                       encryptionData.WrappedContentKey.Algorithm,
                       encryptionData.WrappedContentKey.EncryptedKey,
                       cancellationToken).ConfigureAwait(false)
                : oldKey.UnwrapKey(
                       encryptionData.WrappedContentKey.Algorithm,
                       encryptionData.WrappedContentKey.EncryptedKey,
                       cancellationToken));
        }
#pragma warning disable CS1587 // XML comment is not placed on a valid language element
        /// <summary>
        /// Returns the content encryption key for blob. First tries to get the key encryption key from KeyResolver,
        /// then falls back to IKey stored on this EncryptionPolicy. Unwraps the content encryption key with the
        /// correct key wrapper.
        /// </summary>
        /// <param name="encryptionData">The encryption data.</param>
        /// <param name="async">Whether to perform asynchronously.</param>
        /// <param name="cancellationToken"></param>
        /// <returns>
        /// Encryption key as a byte array.
        /// </returns>
        /// <exception cref="Exception">
        /// Exceptions thrown based on implementations of <see cref="IKeyEncryptionKey"/> and
        /// <see cref="IKeyEncryptionKeyResolver"/>.
        /// </exception>
        private async Task <Memory <byte> > GetContentEncryptionKeyAsync(
#pragma warning restore CS1587 // XML comment is not placed on a valid language element
            EncryptionData encryptionData,
            bool async,
            CancellationToken cancellationToken)
        {
            IKeyEncryptionKey key = default;

            // If we already have a local key and it is the correct one, use that.
            if (encryptionData.WrappedContentKey.KeyId == _potentialCachedIKeyEncryptionKey?.KeyId)
            {
                key = _potentialCachedIKeyEncryptionKey;
            }
            // Otherwise, use the resolver.
            else if (_keyResolver != null)
            {
                key = async
                    ? await _keyResolver.ResolveAsync(encryptionData.WrappedContentKey.KeyId, cancellationToken).ConfigureAwait(false)
                    : _keyResolver.Resolve(encryptionData.WrappedContentKey.KeyId, cancellationToken);
            }

            // We throw for every other reason that decryption couldn't happen. Throw a reasonable
            // exception here instead of nullref.
            if (key == default)
            {
                throw Errors.ClientSideEncryption.KeyNotFound(encryptionData.WrappedContentKey.KeyId);
            }

            return(async
                ? await key.UnwrapKeyAsync(
                       encryptionData.WrappedContentKey.Algorithm,
                       encryptionData.WrappedContentKey.EncryptedKey,
                       cancellationToken).ConfigureAwait(false)
                : key.UnwrapKey(
                       encryptionData.WrappedContentKey.Algorithm,
                       encryptionData.WrappedContentKey.EncryptedKey,
                       cancellationToken));
        }
        private async Task <EncryptedXmlInfo> EncryptAsync(XElement plaintextElement)
        {
            byte[] value;
            using (var memoryStream = new MemoryStream())
            {
                plaintextElement.Save(memoryStream, SaveOptions.DisableFormatting);
                value = memoryStream.ToArray();
            }

            using (var symmetricAlgorithm = DefaultSymmetricAlgorithmFactory())
            {
                var symmetricBlockSize = symmetricAlgorithm.BlockSize / 8;
                var symmetricKey       = new byte[symmetricBlockSize];
                var symmetricIV        = new byte[symmetricBlockSize];
                _randomNumberGenerator.GetBytes(symmetricKey);
                _randomNumberGenerator.GetBytes(symmetricIV);

                byte[] encryptedValue;
                using (var encryptor = symmetricAlgorithm.CreateEncryptor(symmetricKey, symmetricIV))
                {
                    encryptedValue = encryptor.TransformFinalBlock(value, 0, value.Length);
                }

                var key = await _client.ResolveAsync(_keyId).ConfigureAwait(false);

                var wrappedKey = await key.WrapKeyAsync(DefaultKeyEncryption, symmetricKey).ConfigureAwait(false);

                var element = new XElement("encryptedKey",
                                           new XComment(" This key is encrypted with Azure KeyVault. "),
                                           new XElement("kid", key.KeyId),
                                           new XElement("key", Convert.ToBase64String(wrappedKey)),
                                           new XElement("iv", Convert.ToBase64String(symmetricIV)),
                                           new XElement("value", Convert.ToBase64String(encryptedValue)));

                return(new EncryptedXmlInfo(element, typeof(AzureKeyVaultXmlDecryptor)));
            }
        }