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