Exemple #1
0
        /// <summary>
        /// Adds encryption data to provided blob metadata, overwriting previous entry if any.
        /// Safely creates new metadata object if none is provided.
        /// </summary>
        /// <param name="metadata">Optionally existing metadata.</param>
        /// <param name="encryptionData">Encryption data to add.</param>
        private static Metadata TransformMetadata(Metadata metadata, EncryptionData encryptionData)
        {
            Metadata modifiedMetadata = metadata == default
                ? new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase)
                : new Dictionary <string, string>(metadata, StringComparer.OrdinalIgnoreCase);

            modifiedMetadata[Constants.ClientSideEncryption.EncryptionDataKey] = EncryptionDataSerializer.Serialize(encryptionData);

            return(modifiedMetadata);
        }
Exemple #2
0
        /// <summary>
        /// Applies client-side encryption to the data for upload.
        /// </summary>
        /// <param name="content">
        /// Content to encrypt.
        /// </param>
        /// <param name="metadata">
        /// Metadata to add encryption metadata to.
        /// </param>
        /// <param name="async">
        /// Whether to perform this operation asynchronously.
        /// </param>
        /// <param name="cancellationToken">
        /// Cancellation token.
        /// </param>
        /// <returns>Transformed content stream and metadata.</returns>
        public async Task <(Stream, Metadata)> ClientSideEncryptInternal(
            Stream content,
            Metadata metadata,
            bool async,
            CancellationToken cancellationToken)
        {
            (Stream nonSeekableCiphertext, EncryptionData encryptionData) = await _encryptor.EncryptInternal(
                content,
                async,
                cancellationToken).ConfigureAwait(false);

            metadata ??= new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
            metadata[Constants.ClientSideEncryption.EncryptionDataKey] = EncryptionDataSerializer.Serialize(encryptionData);

            return(nonSeekableCiphertext, metadata);
        }
Exemple #3
0
        private static async Task UpdateClientsideKeyEncryptionKeyInternal(
            BlobClient client,
            ClientSideEncryptionOptions encryptionOptionsOverride,
            BlobRequestConditions conditions,
            bool async,
            CancellationToken cancellationToken)
        {
            // argument validation
            Argument.AssertNotNull(client, nameof(client));
            ClientSideEncryptionOptions operationEncryptionOptions = encryptionOptionsOverride
                                                                     ?? client.ClientSideEncryption
                                                                     ?? throw new ArgumentException($"{nameof(ClientSideEncryptionOptions)} are not configured on this client and none were provided for the operation.");

            Argument.AssertNotNull(operationEncryptionOptions.KeyEncryptionKey, nameof(ClientSideEncryptionOptions.KeyEncryptionKey));
            Argument.AssertNotNull(operationEncryptionOptions.KeyResolver, nameof(ClientSideEncryptionOptions.KeyResolver));
            Argument.AssertNotNull(operationEncryptionOptions.KeyWrapAlgorithm, nameof(ClientSideEncryptionOptions.KeyWrapAlgorithm));

            using (client.ClientConfiguration.Pipeline.BeginLoggingScope(nameof(BlobClient)))
            {
                client.ClientConfiguration.Pipeline.LogMethodEnter(
                    nameof(BlobBaseClient),
                    message:
                    $"{nameof(Uri)}: {client.Uri}\n" +
                    $"{nameof(conditions)}: {conditions}");

                DiagnosticScope scope = client.ClientConfiguration.ClientDiagnostics.CreateScope($"{nameof(BlobClient)}.{nameof(UpdateClientSideKeyEncryptionKey)}");

                try
                {
                    // hold onto etag, metadata, encryptiondata
                    BlobProperties getPropertiesResponse = await client.GetPropertiesInternal(conditions, async, cancellationToken).ConfigureAwait(false);

                    ETag etag = getPropertiesResponse.ETag;
                    IDictionary <string, string> metadata = getPropertiesResponse.Metadata;
                    EncryptionData encryptionData         = BlobClientSideDecryptor.GetAndValidateEncryptionDataOrDefault(metadata)
                                                            ?? throw new InvalidOperationException("Resource has no client-side encryption key to rotate.");

                    // rotate keywrapping
                    byte[] newWrappedKey = await WrapKeyInternal(
                        await UnwrapKeyInternal(
                            encryptionData,
                            operationEncryptionOptions.KeyResolver,
                            async,
                            cancellationToken).ConfigureAwait(false),
                        operationEncryptionOptions.KeyWrapAlgorithm,
                        operationEncryptionOptions.KeyEncryptionKey,
                        async,
                        cancellationToken).ConfigureAwait(false);

                    // set new wrapped key info and reinsert into metadata
                    encryptionData.WrappedContentKey = new KeyEnvelope
                    {
                        EncryptedKey = newWrappedKey,
                        Algorithm    = operationEncryptionOptions.KeyWrapAlgorithm,
                        KeyId        = operationEncryptionOptions.KeyEncryptionKey.KeyId
                    };
                    metadata[Constants.ClientSideEncryption.EncryptionDataKey] = EncryptionDataSerializer.Serialize(encryptionData);

                    // update blob ONLY IF ETAG MATCHES (do not take chances encryption info is now out of sync)
                    BlobRequestConditions modifiedRequestConditions = BlobRequestConditions.CloneOrDefault(conditions) ?? new BlobRequestConditions();
                    modifiedRequestConditions.IfMatch = etag;
                    await client.SetMetadataInternal(metadata, modifiedRequestConditions, async, cancellationToken).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    client.ClientConfiguration.Pipeline.LogException(ex);
                    scope.Failed(ex);
                    throw;
                }
                finally
                {
                    client.ClientConfiguration.Pipeline.LogMethodExit(nameof(BlobBaseClient));
                    scope.Dispose();
                }
            }
        }