diff --git a/sdk/storage/inc/blobs/blob_client.hpp b/sdk/storage/inc/blobs/blob_client.hpp index 8e5b0fec9..7da662577 100644 --- a/sdk/storage/inc/blobs/blob_client.hpp +++ b/sdk/storage/inc/blobs/blob_client.hpp @@ -367,12 +367,18 @@ namespace Azure { namespace Storage { namespace Blobs { protected: UriBuilder m_blobUrl; std::shared_ptr m_pipeline; + Azure::Core::Nullable m_customerProvidedKey; + Azure::Core::Nullable m_encryptionScope; private: explicit BlobClient( UriBuilder blobUri, - std::shared_ptr pipeline) - : m_blobUrl(std::move(blobUri)), m_pipeline(std::move(pipeline)) + std::shared_ptr pipeline, + Azure::Core::Nullable customerProvidedKey, + Azure::Core::Nullable encryptionScope) + : m_blobUrl(std::move(blobUri)), m_pipeline(std::move(pipeline)), + m_customerProvidedKey(std::move(customerProvidedKey)), + m_encryptionScope(std::move(encryptionScope)) { } diff --git a/sdk/storage/inc/blobs/blob_container_client.hpp b/sdk/storage/inc/blobs/blob_container_client.hpp index a84c8f2ae..9e1ee50a6 100644 --- a/sdk/storage/inc/blobs/blob_container_client.hpp +++ b/sdk/storage/inc/blobs/blob_container_client.hpp @@ -231,7 +231,7 @@ namespace Azure { namespace Storage { namespace Blobs { /** * @brief Acquires a lease on the container. - * + * * @param proposedLeaseId * Proposed lease ID, in a GUID string format. * @param duration Specifies the duration of @@ -249,7 +249,7 @@ namespace Azure { namespace Storage { namespace Blobs { /** * @brief Renews the container's previously-acquired lease. - * + * * @param * leaseId ID of the previously-acquired lease. * @param options Optional parameters to @@ -262,7 +262,7 @@ namespace Azure { namespace Storage { namespace Blobs { /** * @brief Releases the container's previously-acquired lease. - * + * * @param * leaseId ID of the previously-acquired lease. * @param options Optional parameters to @@ -275,7 +275,7 @@ namespace Azure { namespace Storage { namespace Blobs { /** * @brief Changes the lease of an active lease. - * + * * @param leaseId ID of the * previously-acquired lease. * @param proposedLeaseId Proposed lease ID, in a GUID string @@ -291,7 +291,7 @@ namespace Azure { namespace Storage { namespace Blobs { /** * @brief Breaks the previously-acquired lease. - * + * * @param options Optional * parameters to execute this function. * @return A BrokenLease describing the broken lease. @@ -302,6 +302,8 @@ namespace Azure { namespace Storage { namespace Blobs { private: UriBuilder m_containerUrl; std::shared_ptr m_pipeline; + Azure::Core::Nullable m_customerProvidedKey; + Azure::Core::Nullable m_encryptionScope; explicit BlobContainerClient( UriBuilder containerUri, diff --git a/sdk/storage/inc/blobs/blob_options.hpp b/sdk/storage/inc/blobs/blob_options.hpp index be7754039..4e3aee6a5 100644 --- a/sdk/storage/inc/blobs/blob_options.hpp +++ b/sdk/storage/inc/blobs/blob_options.hpp @@ -181,6 +181,28 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Context Context; }; + /** + * @brief Wrapper for an encryption key to be used with client provided key server-side + * encryption. + */ + struct EncryptionKey + { + /** + * @brief Base64 encoded string of the AES256 encryption key. + */ + std::string Key; + + /** + * @brief Base64 encoded string of the AES256 encryption key's SHA256 hash. + */ + std::string KeyHash; + + /** + * @brief The algorithm for Azure Blob Storage to encrypt with. + */ + EncryptionAlgorithmType Algorithm; + }; + /** * @brief Container client options used to initalize BlobContainerClient. */ @@ -197,6 +219,16 @@ namespace Azure { namespace Storage { namespace Blobs { * are applied to every retrial. */ std::vector> PerRetryPolicies; + + /** + * @brief Holds the customer provided key used when making requests. + */ + Azure::Core::Nullable CustomerProvidedKey; + + /** + * @brief Holds the encryption scope used when making requests. + */ + Azure::Core::Nullable EncryptionScope; }; /** @@ -219,6 +251,17 @@ namespace Azure { namespace Storage { namespace Blobs { * @brief Name-value pairs to associate with the container as metadata. */ std::map Metadata; + + /** + * @brief The encryption scope to use as the default on the container. + */ + Azure::Core::Nullable DefaultEncryptionScope; + + /** + * @brief If true, prevents any blob upload from specifying a different encryption + * scope. + */ + Azure::Core::Nullable PreventEncryptionScopeOverride; }; /** @@ -430,6 +473,16 @@ namespace Azure { namespace Storage { namespace Blobs { * are applied to every retrial. */ std::vector> PerRetryPolicies; + + /** + * @brief Holds the customer provided key used when making requests. + */ + Azure::Core::Nullable CustomerProvidedKey; + + /** + * @brief Holds the encryption scope used when making requests. + */ + Azure::Core::Nullable EncryptionScope; }; /** diff --git a/sdk/storage/inc/blobs/protocol/blob_rest_client.hpp b/sdk/storage/inc/blobs/protocol/blob_rest_client.hpp index 872ad73eb..d107cebf7 100644 --- a/sdk/storage/inc/blobs/protocol/blob_rest_client.hpp +++ b/sdk/storage/inc/blobs/protocol/blob_rest_client.hpp @@ -243,6 +243,7 @@ namespace Azure { namespace Storage { namespace Blobs { int64_t CommittedBlockCount = 0; Azure::Core::Nullable ServerEncrypted; Azure::Core::Nullable EncryptionKeySha256; + Azure::Core::Nullable EncryptionScope; }; // struct BlobAppendInfo enum class BlobArchiveStatus @@ -306,6 +307,7 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable SequenceNumber; Azure::Core::Nullable ServerEncrypted; Azure::Core::Nullable EncryptionKeySha256; + Azure::Core::Nullable EncryptionScope; }; // struct BlobContentInfo struct BlobCorsRule @@ -502,6 +504,7 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable VersionId; Azure::Core::Nullable ServerEncrypted; Azure::Core::Nullable EncryptionKeySha256; + Azure::Core::Nullable EncryptionScope; }; // struct BlobSnapshotInfo struct BlobStaticWebsite @@ -564,6 +567,7 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable ContentCrc64; Azure::Core::Nullable ServerEncrypted; Azure::Core::Nullable EncryptionKeySha256; + Azure::Core::Nullable EncryptionScope; }; // struct BlockInfo enum class BlockListTypeOption @@ -742,6 +746,41 @@ namespace Azure { namespace Storage { namespace Blobs { "cannot convert " + delete_snapshots_option + " to DeleteSnapshotsOption"); } + enum class EncryptionAlgorithmType + { + Unknown, + Aes256, + }; // enum class EncryptionAlgorithmType + + inline std::string EncryptionAlgorithmTypeToString( + const EncryptionAlgorithmType& encryption_algorithm_type) + { + switch (encryption_algorithm_type) + { + case EncryptionAlgorithmType::Unknown: + return ""; + case EncryptionAlgorithmType::Aes256: + return "AES256"; + default: + return std::string(); + } + } + + inline EncryptionAlgorithmType EncryptionAlgorithmTypeFromString( + const std::string& encryption_algorithm_type) + { + if (encryption_algorithm_type == "") + { + return EncryptionAlgorithmType::Unknown; + } + if (encryption_algorithm_type == "AES256") + { + return EncryptionAlgorithmType::Aes256; + } + throw std::runtime_error( + "cannot convert " + encryption_algorithm_type + " to EncryptionAlgorithmType"); + } + enum class ListBlobContainersIncludeOption { None = 0, @@ -890,6 +929,7 @@ namespace Azure { namespace Storage { namespace Blobs { int64_t SequenceNumber = 0; Azure::Core::Nullable ServerEncrypted; Azure::Core::Nullable EncryptionKeySha256; + Azure::Core::Nullable EncryptionScope; }; // struct PageInfo struct PageRangesInfoInternal @@ -1170,6 +1210,7 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable LeaseStatus; Azure::Core::Nullable ServerEncrypted; Azure::Core::Nullable EncryptionKeySha256; + Azure::Core::Nullable EncryptionScope; }; // struct BlobDownloadResponse struct BlobGeoReplication @@ -1199,6 +1240,7 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable LeaseDuration; Azure::Core::Nullable ServerEncrypted; Azure::Core::Nullable EncryptionKeySha256; + Azure::Core::Nullable EncryptionScope; }; // struct BlobItem struct BlobMetrics @@ -1225,6 +1267,7 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable CommittedBlockCount; // only for append blob Azure::Core::Nullable ServerEncrypted; Azure::Core::Nullable EncryptionKeySha256; + Azure::Core::Nullable EncryptionScope; Azure::Core::Nullable Tier; Azure::Core::Nullable AccessTierInferred; Azure::Core::Nullable ArchiveStatus; @@ -2762,6 +2805,8 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable Timeout; Azure::Core::Nullable AccessType; std::map Metadata; + Azure::Core::Nullable DefaultEncryptionScope; + Azure::Core::Nullable PreventEncryptionScopeOverride; }; // struct CreateOptions static Azure::Core::Response Create( @@ -2798,6 +2843,17 @@ namespace Azure { namespace Storage { namespace Blobs { request.AddHeader( "x-ms-blob-public-access", PublicAccessTypeToString(options.AccessType.GetValue())); } + if (options.DefaultEncryptionScope.HasValue()) + { + request.AddHeader( + "x-ms-default-encryption-scope", options.DefaultEncryptionScope.GetValue()); + } + if (options.PreventEncryptionScopeOverride.HasValue()) + { + request.AddHeader( + "x-ms-deny-encryption-scope-override", + options.PreventEncryptionScopeOverride.GetValue() ? "true" : "false"); + } auto pHttpResponse = pipeline.Send(context, request); Azure::Core::Http::RawResponse& httpResponse = *pHttpResponse; BlobContainerInfo response; @@ -2865,9 +2921,6 @@ namespace Azure { namespace Storage { namespace Blobs { struct GetPropertiesOptions { Azure::Core::Nullable Timeout; - Azure::Core::Nullable EncryptionKey; - Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; Azure::Core::Nullable LeaseId; }; // struct GetPropertiesOptions @@ -2885,18 +2938,6 @@ namespace Azure { namespace Storage { namespace Blobs { { request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue())); } - if (options.EncryptionKey.HasValue()) - { - request.AddHeader("x-ms-encryption-key", options.EncryptionKey.GetValue()); - } - if (options.EncryptionKeySha256.HasValue()) - { - request.AddHeader("x-ms-encryption-key-sha256", options.EncryptionKeySha256.GetValue()); - } - if (options.EncryptionAlgorithm.HasValue()) - { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); - } if (options.LeaseId.HasValue()) { request.AddHeader("x-ms-lease-id", options.LeaseId.GetValue()); @@ -4310,7 +4351,7 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable> Range; Azure::Core::Nullable EncryptionKey; Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionAlgorithm; Azure::Core::Nullable LeaseId; Azure::Core::Nullable IfModifiedSince; Azure::Core::Nullable IfUnmodifiedSince; @@ -4356,7 +4397,9 @@ namespace Azure { namespace Storage { namespace Blobs { } if (options.EncryptionAlgorithm.HasValue()) { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); + request.AddHeader( + "x-ms-encryption-algorithm", + EncryptionAlgorithmTypeToString(options.EncryptionAlgorithm.GetValue())); } if (options.IfModifiedSince.HasValue()) { @@ -4447,7 +4490,7 @@ namespace Azure { namespace Storage { namespace Blobs { response.Metadata.emplace(i->first.substr(10), i->second); } auto response_server_encrypted_iterator - = httpResponse.GetHeaders().find("x-ms-server-encrypted"); + = httpResponse.GetHeaders().find("x-ms-request-server-encrypted"); if (response_server_encrypted_iterator != httpResponse.GetHeaders().end()) { response.ServerEncrypted = response_server_encrypted_iterator->second == "true"; @@ -4458,6 +4501,12 @@ namespace Azure { namespace Storage { namespace Blobs { { response.EncryptionKeySha256 = response_encryption_key_sha256_iterator->second; } + auto response_encryption_scope_iterator + = httpResponse.GetHeaders().find("x-ms-encryption-scope"); + if (response_encryption_scope_iterator != httpResponse.GetHeaders().end()) + { + response.EncryptionScope = response_encryption_scope_iterator->second; + } auto response_lease_status_iterator = httpResponse.GetHeaders().find("x-ms-lease-status"); if (response_lease_status_iterator != httpResponse.GetHeaders().end()) { @@ -4597,6 +4646,9 @@ namespace Azure { namespace Storage { namespace Blobs { struct GetPropertiesOptions { Azure::Core::Nullable Timeout; + Azure::Core::Nullable EncryptionKey; + Azure::Core::Nullable EncryptionKeySha256; + Azure::Core::Nullable EncryptionAlgorithm; Azure::Core::Nullable LeaseId; Azure::Core::Nullable IfModifiedSince; Azure::Core::Nullable IfUnmodifiedSince; @@ -4617,6 +4669,20 @@ namespace Azure { namespace Storage { namespace Blobs { { request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue())); } + if (options.EncryptionKey.HasValue()) + { + request.AddHeader("x-ms-encryption-key", options.EncryptionKey.GetValue()); + } + if (options.EncryptionKeySha256.HasValue()) + { + request.AddHeader("x-ms-encryption-key-sha256", options.EncryptionKeySha256.GetValue()); + } + if (options.EncryptionAlgorithm.HasValue()) + { + request.AddHeader( + "x-ms-encryption-algorithm", + EncryptionAlgorithmTypeToString(options.EncryptionAlgorithm.GetValue())); + } if (options.LeaseId.HasValue()) { request.AddHeader("x-ms-lease-id", options.LeaseId.GetValue()); @@ -4726,7 +4792,7 @@ namespace Azure { namespace Storage { namespace Blobs { response.CommittedBlockCount = std::stoi(response_committed_block_count_iterator->second); } auto response_server_encrypted_iterator - = httpResponse.GetHeaders().find("x-ms-server-encrypted"); + = httpResponse.GetHeaders().find("x-ms-request-server-encrypted"); if (response_server_encrypted_iterator != httpResponse.GetHeaders().end()) { response.ServerEncrypted = response_server_encrypted_iterator->second == "true"; @@ -4737,6 +4803,12 @@ namespace Azure { namespace Storage { namespace Blobs { { response.EncryptionKeySha256 = response_encryption_key_sha256_iterator->second; } + auto response_encryption_scope_iterator + = httpResponse.GetHeaders().find("x-ms-encryption-scope"); + if (response_encryption_scope_iterator != httpResponse.GetHeaders().end()) + { + response.EncryptionScope = response_encryption_scope_iterator->second; + } auto response_tier_iterator = httpResponse.GetHeaders().find("x-ms-access-tier"); if (response_tier_iterator != httpResponse.GetHeaders().end()) { @@ -4794,9 +4866,6 @@ namespace Azure { namespace Storage { namespace Blobs { { Azure::Core::Nullable Timeout; BlobHttpHeaders HttpHeaders; - Azure::Core::Nullable EncryptionKey; - Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; Azure::Core::Nullable LeaseId; Azure::Core::Nullable IfModifiedSince; Azure::Core::Nullable IfUnmodifiedSince; @@ -4844,18 +4913,6 @@ namespace Azure { namespace Storage { namespace Blobs { request.AddHeader( "x-ms-blob-content-disposition", options.HttpHeaders.ContentDisposition); } - if (options.EncryptionKey.HasValue()) - { - request.AddHeader("x-ms-encryption-key", options.EncryptionKey.GetValue()); - } - if (options.EncryptionKeySha256.HasValue()) - { - request.AddHeader("x-ms-encryption-key-sha256", options.EncryptionKeySha256.GetValue()); - } - if (options.EncryptionAlgorithm.HasValue()) - { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); - } if (options.LeaseId.HasValue()) { request.AddHeader("x-ms-lease-id", options.LeaseId.GetValue()); @@ -4903,7 +4960,8 @@ namespace Azure { namespace Storage { namespace Blobs { std::map Metadata; Azure::Core::Nullable EncryptionKey; Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionScope; Azure::Core::Nullable LeaseId; Azure::Core::Nullable IfModifiedSince; Azure::Core::Nullable IfUnmodifiedSince; @@ -4950,7 +5008,13 @@ namespace Azure { namespace Storage { namespace Blobs { } if (options.EncryptionAlgorithm.HasValue()) { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); + request.AddHeader( + "x-ms-encryption-algorithm", + EncryptionAlgorithmTypeToString(options.EncryptionAlgorithm.GetValue())); + } + if (options.EncryptionScope.HasValue()) + { + request.AddHeader("x-ms-encryption-scope", options.EncryptionScope.GetValue()); } if (options.LeaseId.HasValue()) { @@ -5202,7 +5266,8 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable LeaseId; Azure::Core::Nullable EncryptionKey; Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionScope; Azure::Core::Nullable IfModifiedSince; Azure::Core::Nullable IfUnmodifiedSince; Azure::Core::Nullable IfMatch; @@ -5234,7 +5299,13 @@ namespace Azure { namespace Storage { namespace Blobs { } if (options.EncryptionAlgorithm.HasValue()) { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); + request.AddHeader( + "x-ms-encryption-algorithm", + EncryptionAlgorithmTypeToString(options.EncryptionAlgorithm.GetValue())); + } + if (options.EncryptionScope.HasValue()) + { + request.AddHeader("x-ms-encryption-scope", options.EncryptionScope.GetValue()); } std::set metadataKeys; for (const auto& pair : options.Metadata) @@ -5283,7 +5354,7 @@ namespace Azure { namespace Storage { namespace Blobs { response.ETag = httpResponse.GetHeaders().at("etag"); response.LastModified = httpResponse.GetHeaders().at("last-modified"); auto response_server_encrypted_iterator - = httpResponse.GetHeaders().find("x-ms-server-encrypted"); + = httpResponse.GetHeaders().find("x-ms-request-server-encrypted"); if (response_server_encrypted_iterator != httpResponse.GetHeaders().end()) { response.ServerEncrypted = response_server_encrypted_iterator->second == "true"; @@ -5294,6 +5365,12 @@ namespace Azure { namespace Storage { namespace Blobs { { response.EncryptionKeySha256 = response_encryption_key_sha256_iterator->second; } + auto response_encryption_scope_iterator + = httpResponse.GetHeaders().find("x-ms-encryption-scope"); + if (response_encryption_scope_iterator != httpResponse.GetHeaders().end()) + { + response.EncryptionScope = response_encryption_scope_iterator->second; + } response.Snapshot = httpResponse.GetHeaders().at("x-ms-snapshot"); auto response_version_id_iterator = httpResponse.GetHeaders().find("x-ms-version-id"); if (response_version_id_iterator != httpResponse.GetHeaders().end()) @@ -5631,7 +5708,8 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable Tier; Azure::Core::Nullable EncryptionKey; Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionScope; Azure::Core::Nullable IfModifiedSince; Azure::Core::Nullable IfUnmodifiedSince; Azure::Core::Nullable IfMatch; @@ -5664,7 +5742,13 @@ namespace Azure { namespace Storage { namespace Blobs { } if (options.EncryptionAlgorithm.HasValue()) { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); + request.AddHeader( + "x-ms-encryption-algorithm", + EncryptionAlgorithmTypeToString(options.EncryptionAlgorithm.GetValue())); + } + if (options.EncryptionScope.HasValue()) + { + request.AddHeader("x-ms-encryption-scope", options.EncryptionScope.GetValue()); } if (options.ContentMd5.HasValue()) { @@ -5766,7 +5850,7 @@ namespace Azure { namespace Storage { namespace Blobs { response.VersionId = response_version_id_iterator->second; } auto response_server_encrypted_iterator - = httpResponse.GetHeaders().find("x-ms-server-encrypted"); + = httpResponse.GetHeaders().find("x-ms-request-server-encrypted"); if (response_server_encrypted_iterator != httpResponse.GetHeaders().end()) { response.ServerEncrypted = response_server_encrypted_iterator->second == "true"; @@ -5777,6 +5861,12 @@ namespace Azure { namespace Storage { namespace Blobs { { response.EncryptionKeySha256 = response_encryption_key_sha256_iterator->second; } + auto response_encryption_scope_iterator + = httpResponse.GetHeaders().find("x-ms-encryption-scope"); + if (response_encryption_scope_iterator != httpResponse.GetHeaders().end()) + { + response.EncryptionScope = response_encryption_scope_iterator->second; + } return Azure::Core::Response( std::move(response), std::move(pHttpResponse)); } @@ -5790,7 +5880,8 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable LeaseId; Azure::Core::Nullable EncryptionKey; Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionScope; }; // struct StageBlockOptions static Azure::Core::Response StageBlock( @@ -5833,7 +5924,13 @@ namespace Azure { namespace Storage { namespace Blobs { } if (options.EncryptionAlgorithm.HasValue()) { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); + request.AddHeader( + "x-ms-encryption-algorithm", + EncryptionAlgorithmTypeToString(options.EncryptionAlgorithm.GetValue())); + } + if (options.EncryptionScope.HasValue()) + { + request.AddHeader("x-ms-encryption-scope", options.EncryptionScope.GetValue()); } auto pHttpResponse = pipeline.Send(context, request); Azure::Core::Http::RawResponse& httpResponse = *pHttpResponse; @@ -5856,7 +5953,7 @@ namespace Azure { namespace Storage { namespace Blobs { response.ContentCrc64 = response_content_crc64_iterator->second; } auto response_server_encrypted_iterator - = httpResponse.GetHeaders().find("x-ms-server-encrypted"); + = httpResponse.GetHeaders().find("x-ms-request-server-encrypted"); if (response_server_encrypted_iterator != httpResponse.GetHeaders().end()) { response.ServerEncrypted = response_server_encrypted_iterator->second == "true"; @@ -5867,6 +5964,12 @@ namespace Azure { namespace Storage { namespace Blobs { { response.EncryptionKeySha256 = response_encryption_key_sha256_iterator->second; } + auto response_encryption_scope_iterator + = httpResponse.GetHeaders().find("x-ms-encryption-scope"); + if (response_encryption_scope_iterator != httpResponse.GetHeaders().end()) + { + response.EncryptionScope = response_encryption_scope_iterator->second; + } return Azure::Core::Response(std::move(response), std::move(pHttpResponse)); } @@ -5881,7 +5984,8 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable LeaseId; Azure::Core::Nullable EncryptionKey; Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionScope; Azure::Core::Nullable SourceIfModifiedSince; Azure::Core::Nullable SourceIfUnmodifiedSince; Azure::Core::Nullable SourceIfMatch; @@ -5942,7 +6046,13 @@ namespace Azure { namespace Storage { namespace Blobs { } if (options.EncryptionAlgorithm.HasValue()) { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); + request.AddHeader( + "x-ms-encryption-algorithm", + EncryptionAlgorithmTypeToString(options.EncryptionAlgorithm.GetValue())); + } + if (options.EncryptionScope.HasValue()) + { + request.AddHeader("x-ms-encryption-scope", options.EncryptionScope.GetValue()); } if (options.SourceIfModifiedSince.HasValue()) { @@ -5983,7 +6093,7 @@ namespace Azure { namespace Storage { namespace Blobs { response.ContentCrc64 = response_content_crc64_iterator->second; } auto response_server_encrypted_iterator - = httpResponse.GetHeaders().find("x-ms-server-encrypted"); + = httpResponse.GetHeaders().find("x-ms-request-server-encrypted"); if (response_server_encrypted_iterator != httpResponse.GetHeaders().end()) { response.ServerEncrypted = response_server_encrypted_iterator->second == "true"; @@ -5994,6 +6104,12 @@ namespace Azure { namespace Storage { namespace Blobs { { response.EncryptionKeySha256 = response_encryption_key_sha256_iterator->second; } + auto response_encryption_scope_iterator + = httpResponse.GetHeaders().find("x-ms-encryption-scope"); + if (response_encryption_scope_iterator != httpResponse.GetHeaders().end()) + { + response.EncryptionScope = response_encryption_scope_iterator->second; + } return Azure::Core::Response(std::move(response), std::move(pHttpResponse)); } @@ -6006,7 +6122,8 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable LeaseId; Azure::Core::Nullable EncryptionKey; Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionScope; Azure::Core::Nullable IfModifiedSince; Azure::Core::Nullable IfUnmodifiedSince; Azure::Core::Nullable IfMatch; @@ -6092,7 +6209,13 @@ namespace Azure { namespace Storage { namespace Blobs { } if (options.EncryptionAlgorithm.HasValue()) { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); + request.AddHeader( + "x-ms-encryption-algorithm", + EncryptionAlgorithmTypeToString(options.EncryptionAlgorithm.GetValue())); + } + if (options.EncryptionScope.HasValue()) + { + request.AddHeader("x-ms-encryption-scope", options.EncryptionScope.GetValue()); } if (options.Tier.HasValue()) { @@ -6132,7 +6255,7 @@ namespace Azure { namespace Storage { namespace Blobs { response.VersionId = response_version_id_iterator->second; } auto response_server_encrypted_iterator - = httpResponse.GetHeaders().find("x-ms-server-encrypted"); + = httpResponse.GetHeaders().find("x-ms-request-server-encrypted"); if (response_server_encrypted_iterator != httpResponse.GetHeaders().end()) { response.ServerEncrypted = response_server_encrypted_iterator->second == "true"; @@ -6143,6 +6266,12 @@ namespace Azure { namespace Storage { namespace Blobs { { response.EncryptionKeySha256 = response_encryption_key_sha256_iterator->second; } + auto response_encryption_scope_iterator + = httpResponse.GetHeaders().find("x-ms-encryption-scope"); + if (response_encryption_scope_iterator != httpResponse.GetHeaders().end()) + { + response.EncryptionScope = response_encryption_scope_iterator->second; + } return Azure::Core::Response( std::move(response), std::move(pHttpResponse)); } @@ -6363,7 +6492,8 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable Tier; Azure::Core::Nullable EncryptionKey; Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionScope; Azure::Core::Nullable IfModifiedSince; Azure::Core::Nullable IfUnmodifiedSince; Azure::Core::Nullable IfMatch; @@ -6448,7 +6578,13 @@ namespace Azure { namespace Storage { namespace Blobs { } if (options.EncryptionAlgorithm.HasValue()) { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); + request.AddHeader( + "x-ms-encryption-algorithm", + EncryptionAlgorithmTypeToString(options.EncryptionAlgorithm.GetValue())); + } + if (options.EncryptionScope.HasValue()) + { + request.AddHeader("x-ms-encryption-scope", options.EncryptionScope.GetValue()); } if (options.IfModifiedSince.HasValue()) { @@ -6494,7 +6630,7 @@ namespace Azure { namespace Storage { namespace Blobs { response.VersionId = response_version_id_iterator->second; } auto response_server_encrypted_iterator - = httpResponse.GetHeaders().find("x-ms-server-encrypted"); + = httpResponse.GetHeaders().find("x-ms-request-server-encrypted"); if (response_server_encrypted_iterator != httpResponse.GetHeaders().end()) { response.ServerEncrypted = response_server_encrypted_iterator->second == "true"; @@ -6505,6 +6641,12 @@ namespace Azure { namespace Storage { namespace Blobs { { response.EncryptionKeySha256 = response_encryption_key_sha256_iterator->second; } + auto response_encryption_scope_iterator + = httpResponse.GetHeaders().find("x-ms-encryption-scope"); + if (response_encryption_scope_iterator != httpResponse.GetHeaders().end()) + { + response.EncryptionScope = response_encryption_scope_iterator->second; + } return Azure::Core::Response( std::move(response), std::move(pHttpResponse)); } @@ -6521,7 +6663,8 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable IfSequenceNumberEqualTo; Azure::Core::Nullable EncryptionKey; Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionScope; Azure::Core::Nullable IfModifiedSince; Azure::Core::Nullable IfUnmodifiedSince; Azure::Core::Nullable IfMatch; @@ -6590,7 +6733,13 @@ namespace Azure { namespace Storage { namespace Blobs { } if (options.EncryptionAlgorithm.HasValue()) { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); + request.AddHeader( + "x-ms-encryption-algorithm", + EncryptionAlgorithmTypeToString(options.EncryptionAlgorithm.GetValue())); + } + if (options.EncryptionScope.HasValue()) + { + request.AddHeader("x-ms-encryption-scope", options.EncryptionScope.GetValue()); } if (options.IfModifiedSince.HasValue()) { @@ -6633,7 +6782,7 @@ namespace Azure { namespace Storage { namespace Blobs { response.SequenceNumber = std::stoll(httpResponse.GetHeaders().at("x-ms-blob-sequence-number")); auto response_server_encrypted_iterator - = httpResponse.GetHeaders().find("x-ms-server-encrypted"); + = httpResponse.GetHeaders().find("x-ms-request-server-encrypted"); if (response_server_encrypted_iterator != httpResponse.GetHeaders().end()) { response.ServerEncrypted = response_server_encrypted_iterator->second == "true"; @@ -6644,6 +6793,12 @@ namespace Azure { namespace Storage { namespace Blobs { { response.EncryptionKeySha256 = response_encryption_key_sha256_iterator->second; } + auto response_encryption_scope_iterator + = httpResponse.GetHeaders().find("x-ms-encryption-scope"); + if (response_encryption_scope_iterator != httpResponse.GetHeaders().end()) + { + response.EncryptionScope = response_encryption_scope_iterator->second; + } return Azure::Core::Response(std::move(response), std::move(pHttpResponse)); } @@ -6661,7 +6816,8 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable IfSequenceNumberEqualTo; Azure::Core::Nullable EncryptionKey; Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionScope; Azure::Core::Nullable IfModifiedSince; Azure::Core::Nullable IfUnmodifiedSince; Azure::Core::Nullable IfMatch; @@ -6733,7 +6889,13 @@ namespace Azure { namespace Storage { namespace Blobs { } if (options.EncryptionAlgorithm.HasValue()) { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); + request.AddHeader( + "x-ms-encryption-algorithm", + EncryptionAlgorithmTypeToString(options.EncryptionAlgorithm.GetValue())); + } + if (options.EncryptionScope.HasValue()) + { + request.AddHeader("x-ms-encryption-scope", options.EncryptionScope.GetValue()); } if (options.IfModifiedSince.HasValue()) { @@ -6776,7 +6938,7 @@ namespace Azure { namespace Storage { namespace Blobs { response.SequenceNumber = std::stoll(httpResponse.GetHeaders().at("x-ms-blob-sequence-number")); auto response_server_encrypted_iterator - = httpResponse.GetHeaders().find("x-ms-server-encrypted"); + = httpResponse.GetHeaders().find("x-ms-request-server-encrypted"); if (response_server_encrypted_iterator != httpResponse.GetHeaders().end()) { response.ServerEncrypted = response_server_encrypted_iterator->second == "true"; @@ -6787,6 +6949,12 @@ namespace Azure { namespace Storage { namespace Blobs { { response.EncryptionKeySha256 = response_encryption_key_sha256_iterator->second; } + auto response_encryption_scope_iterator + = httpResponse.GetHeaders().find("x-ms-encryption-scope"); + if (response_encryption_scope_iterator != httpResponse.GetHeaders().end()) + { + response.EncryptionScope = response_encryption_scope_iterator->second; + } return Azure::Core::Response(std::move(response), std::move(pHttpResponse)); } @@ -6800,7 +6968,8 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable IfSequenceNumberEqualTo; Azure::Core::Nullable EncryptionKey; Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionScope; Azure::Core::Nullable IfModifiedSince; Azure::Core::Nullable IfUnmodifiedSince; Azure::Core::Nullable IfMatch; @@ -6859,7 +7028,13 @@ namespace Azure { namespace Storage { namespace Blobs { } if (options.EncryptionAlgorithm.HasValue()) { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); + request.AddHeader( + "x-ms-encryption-algorithm", + EncryptionAlgorithmTypeToString(options.EncryptionAlgorithm.GetValue())); + } + if (options.EncryptionScope.HasValue()) + { + request.AddHeader("x-ms-encryption-scope", options.EncryptionScope.GetValue()); } if (options.IfModifiedSince.HasValue()) { @@ -6892,7 +7067,7 @@ namespace Azure { namespace Storage { namespace Blobs { response.SequenceNumber = std::stoll(httpResponse.GetHeaders().at("x-ms-blob-sequence-number")); auto response_server_encrypted_iterator - = httpResponse.GetHeaders().find("x-ms-server-encrypted"); + = httpResponse.GetHeaders().find("x-ms-request-server-encrypted"); if (response_server_encrypted_iterator != httpResponse.GetHeaders().end()) { response.ServerEncrypted = response_server_encrypted_iterator->second == "true"; @@ -6903,6 +7078,12 @@ namespace Azure { namespace Storage { namespace Blobs { { response.EncryptionKeySha256 = response_encryption_key_sha256_iterator->second; } + auto response_encryption_scope_iterator + = httpResponse.GetHeaders().find("x-ms-encryption-scope"); + if (response_encryption_scope_iterator != httpResponse.GetHeaders().end()) + { + response.EncryptionScope = response_encryption_scope_iterator->second; + } return Azure::Core::Response(std::move(response), std::move(pHttpResponse)); } @@ -6916,7 +7097,8 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable IfSequenceNumberEqualTo; Azure::Core::Nullable EncryptionKey; Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionScope; Azure::Core::Nullable IfModifiedSince; Azure::Core::Nullable IfUnmodifiedSince; Azure::Core::Nullable IfMatch; @@ -6971,7 +7153,13 @@ namespace Azure { namespace Storage { namespace Blobs { } if (options.EncryptionAlgorithm.HasValue()) { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); + request.AddHeader( + "x-ms-encryption-algorithm", + EncryptionAlgorithmTypeToString(options.EncryptionAlgorithm.GetValue())); + } + if (options.EncryptionScope.HasValue()) + { + request.AddHeader("x-ms-encryption-scope", options.EncryptionScope.GetValue()); } if (options.IfModifiedSince.HasValue()) { @@ -7342,7 +7530,8 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable LeaseId; Azure::Core::Nullable EncryptionKey; Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionScope; Azure::Core::Nullable IfModifiedSince; Azure::Core::Nullable IfUnmodifiedSince; Azure::Core::Nullable IfMatch; @@ -7417,7 +7606,13 @@ namespace Azure { namespace Storage { namespace Blobs { } if (options.EncryptionAlgorithm.HasValue()) { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); + request.AddHeader( + "x-ms-encryption-algorithm", + EncryptionAlgorithmTypeToString(options.EncryptionAlgorithm.GetValue())); + } + if (options.EncryptionScope.HasValue()) + { + request.AddHeader("x-ms-encryption-scope", options.EncryptionScope.GetValue()); } if (options.IfModifiedSince.HasValue()) { @@ -7463,7 +7658,7 @@ namespace Azure { namespace Storage { namespace Blobs { response.VersionId = response_version_id_iterator->second; } auto response_server_encrypted_iterator - = httpResponse.GetHeaders().find("x-ms-server-encrypted"); + = httpResponse.GetHeaders().find("x-ms-request-server-encrypted"); if (response_server_encrypted_iterator != httpResponse.GetHeaders().end()) { response.ServerEncrypted = response_server_encrypted_iterator->second == "true"; @@ -7474,6 +7669,12 @@ namespace Azure { namespace Storage { namespace Blobs { { response.EncryptionKeySha256 = response_encryption_key_sha256_iterator->second; } + auto response_encryption_scope_iterator + = httpResponse.GetHeaders().find("x-ms-encryption-scope"); + if (response_encryption_scope_iterator != httpResponse.GetHeaders().end()) + { + response.EncryptionScope = response_encryption_scope_iterator->second; + } return Azure::Core::Response( std::move(response), std::move(pHttpResponse)); } @@ -7488,7 +7689,8 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable AppendPosition; Azure::Core::Nullable EncryptionKey; Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionScope; Azure::Core::Nullable IfModifiedSince; Azure::Core::Nullable IfUnmodifiedSince; Azure::Core::Nullable IfMatch; @@ -7544,7 +7746,13 @@ namespace Azure { namespace Storage { namespace Blobs { } if (options.EncryptionAlgorithm.HasValue()) { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); + request.AddHeader( + "x-ms-encryption-algorithm", + EncryptionAlgorithmTypeToString(options.EncryptionAlgorithm.GetValue())); + } + if (options.EncryptionScope.HasValue()) + { + request.AddHeader("x-ms-encryption-scope", options.EncryptionScope.GetValue()); } if (options.IfModifiedSince.HasValue()) { @@ -7588,7 +7796,7 @@ namespace Azure { namespace Storage { namespace Blobs { response.CommittedBlockCount = std::stoll(httpResponse.GetHeaders().at("x-ms-blob-committed-block-count")); auto response_server_encrypted_iterator - = httpResponse.GetHeaders().find("x-ms-server-encrypted"); + = httpResponse.GetHeaders().find("x-ms-request-server-encrypted"); if (response_server_encrypted_iterator != httpResponse.GetHeaders().end()) { response.ServerEncrypted = response_server_encrypted_iterator->second == "true"; @@ -7599,6 +7807,12 @@ namespace Azure { namespace Storage { namespace Blobs { { response.EncryptionKeySha256 = response_encryption_key_sha256_iterator->second; } + auto response_encryption_scope_iterator + = httpResponse.GetHeaders().find("x-ms-encryption-scope"); + if (response_encryption_scope_iterator != httpResponse.GetHeaders().end()) + { + response.EncryptionScope = response_encryption_scope_iterator->second; + } return Azure::Core::Response(std::move(response), std::move(pHttpResponse)); } @@ -7614,7 +7828,8 @@ namespace Azure { namespace Storage { namespace Blobs { Azure::Core::Nullable AppendPosition; Azure::Core::Nullable EncryptionKey; Azure::Core::Nullable EncryptionKeySha256; - Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionAlgorithm; + Azure::Core::Nullable EncryptionScope; Azure::Core::Nullable IfModifiedSince; Azure::Core::Nullable IfUnmodifiedSince; Azure::Core::Nullable IfMatch; @@ -7684,7 +7899,13 @@ namespace Azure { namespace Storage { namespace Blobs { } if (options.EncryptionAlgorithm.HasValue()) { - request.AddHeader("x-ms-encryption-algorithm", options.EncryptionAlgorithm.GetValue()); + request.AddHeader( + "x-ms-encryption-algorithm", + EncryptionAlgorithmTypeToString(options.EncryptionAlgorithm.GetValue())); + } + if (options.EncryptionScope.HasValue()) + { + request.AddHeader("x-ms-encryption-scope", options.EncryptionScope.GetValue()); } if (options.IfModifiedSince.HasValue()) { @@ -7728,7 +7949,7 @@ namespace Azure { namespace Storage { namespace Blobs { response.CommittedBlockCount = std::stoll(httpResponse.GetHeaders().at("x-ms-blob-committed-block-count")); auto response_server_encrypted_iterator - = httpResponse.GetHeaders().find("x-ms-server-encrypted"); + = httpResponse.GetHeaders().find("x-ms-request-server-encrypted"); if (response_server_encrypted_iterator != httpResponse.GetHeaders().end()) { response.ServerEncrypted = response_server_encrypted_iterator->second == "true"; @@ -7739,6 +7960,12 @@ namespace Azure { namespace Storage { namespace Blobs { { response.EncryptionKeySha256 = response_encryption_key_sha256_iterator->second; } + auto response_encryption_scope_iterator + = httpResponse.GetHeaders().find("x-ms-encryption-scope"); + if (response_encryption_scope_iterator != httpResponse.GetHeaders().end()) + { + response.EncryptionScope = response_encryption_scope_iterator->second; + } return Azure::Core::Response(std::move(response), std::move(pHttpResponse)); } diff --git a/sdk/storage/inc/common/crypt.hpp b/sdk/storage/inc/common/crypt.hpp index 23090bf98..c4638e0d4 100644 --- a/sdk/storage/inc/common/crypt.hpp +++ b/sdk/storage/inc/common/crypt.hpp @@ -7,6 +7,7 @@ namespace Azure { namespace Storage { + std::string Sha256(const std::string& text); std::string Hmac_Sha256(const std::string& text, const std::string& key); std::string Base64Encode(const std::string& text); std::string Base64Decode(const std::string& text); diff --git a/sdk/storage/src/blobs/append_blob_client.cpp b/sdk/storage/src/blobs/append_blob_client.cpp index 976a357b7..b2b35da37 100644 --- a/sdk/storage/src/blobs/append_blob_client.cpp +++ b/sdk/storage/src/blobs/append_blob_client.cpp @@ -83,6 +83,13 @@ namespace Azure { namespace Storage { namespace Blobs { protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch; protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch; + if (m_customerProvidedKey.HasValue()) + { + protocolLayerOptions.EncryptionKey = m_customerProvidedKey.GetValue().Key; + protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash; + protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm; + } + protocolLayerOptions.EncryptionScope = m_encryptionScope; return BlobRestClient::AppendBlob::Create( options.Context, *m_pipeline, m_blobUrl.ToString(), protocolLayerOptions); } @@ -101,6 +108,13 @@ namespace Azure { namespace Storage { namespace Blobs { protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch; protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch; + if (m_customerProvidedKey.HasValue()) + { + protocolLayerOptions.EncryptionKey = m_customerProvidedKey.GetValue().Key; + protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash; + protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm; + } + protocolLayerOptions.EncryptionScope = m_encryptionScope; return BlobRestClient::AppendBlob::AppendBlock( options.Context, *m_pipeline, m_blobUrl.ToString(), content, protocolLayerOptions); } @@ -133,6 +147,13 @@ namespace Azure { namespace Storage { namespace Blobs { protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch; protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch; + if (m_customerProvidedKey.HasValue()) + { + protocolLayerOptions.EncryptionKey = m_customerProvidedKey.GetValue().Key; + protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash; + protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm; + } + protocolLayerOptions.EncryptionScope = m_encryptionScope; return BlobRestClient::AppendBlob::AppendBlockFromUri( options.Context, *m_pipeline, m_blobUrl.ToString(), protocolLayerOptions); } diff --git a/sdk/storage/src/blobs/blob_client.cpp b/sdk/storage/src/blobs/blob_client.cpp index de028997c..ad87d62f8 100644 --- a/sdk/storage/src/blobs/blob_client.cpp +++ b/sdk/storage/src/blobs/blob_client.cpp @@ -44,7 +44,7 @@ namespace Azure { namespace Storage { namespace Blobs { const std::string& blobUri, std::shared_ptr credential, const BlobClientOptions& options) - : m_blobUrl(blobUri) + : BlobClient(blobUri, options) { std::vector> policies; policies.emplace_back(std::make_unique( @@ -70,7 +70,7 @@ namespace Azure { namespace Storage { namespace Blobs { const std::string& blobUri, std::shared_ptr credential, const BlobClientOptions& options) - : m_blobUrl(blobUri) + : BlobClient(blobUri, options) { std::vector> policies; policies.emplace_back(std::make_unique( @@ -95,7 +95,8 @@ namespace Azure { namespace Storage { namespace Blobs { } BlobClient::BlobClient(const std::string& blobUri, const BlobClientOptions& options) - : m_blobUrl(blobUri) + : m_blobUrl(blobUri), m_customerProvidedKey(options.CustomerProvidedKey), + m_encryptionScope(options.EncryptionScope) { std::vector> policies; policies.emplace_back(std::make_unique( @@ -170,6 +171,12 @@ namespace Azure { namespace Storage { namespace Blobs { protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch; protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch; + if (m_customerProvidedKey.HasValue()) + { + protocolLayerOptions.EncryptionKey = m_customerProvidedKey.GetValue().Key; + protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash; + protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm; + } auto downloadResponse = BlobRestClient::Blob::Download( options.Context, *m_pipeline, m_blobUrl.ToString(), protocolLayerOptions); @@ -474,6 +481,12 @@ namespace Azure { namespace Storage { namespace Blobs { protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch; protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch; + if (m_customerProvidedKey.HasValue()) + { + protocolLayerOptions.EncryptionKey = m_customerProvidedKey.GetValue().Key; + protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash; + protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm; + } return BlobRestClient::Blob::GetProperties( options.Context, *m_pipeline, m_blobUrl.ToString(), protocolLayerOptions); } @@ -504,6 +517,13 @@ namespace Azure { namespace Storage { namespace Blobs { protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch; protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch; + if (m_customerProvidedKey.HasValue()) + { + protocolLayerOptions.EncryptionKey = m_customerProvidedKey.GetValue().Key; + protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash; + protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm; + } + protocolLayerOptions.EncryptionScope = m_encryptionScope; return BlobRestClient::Blob::SetMetadata( options.Context, *m_pipeline, m_blobUrl.ToString(), protocolLayerOptions); } @@ -563,6 +583,13 @@ namespace Azure { namespace Storage { namespace Blobs { protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch; protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch; + if (m_customerProvidedKey.HasValue()) + { + protocolLayerOptions.EncryptionKey = m_customerProvidedKey.GetValue().Key; + protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash; + protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm; + } + protocolLayerOptions.EncryptionScope = m_encryptionScope; return BlobRestClient::Blob::CreateSnapshot( options.Context, *m_pipeline, m_blobUrl.ToString(), protocolLayerOptions); } diff --git a/sdk/storage/src/blobs/blob_container_client.cpp b/sdk/storage/src/blobs/blob_container_client.cpp index d03e4f0fe..6fa7e30b1 100644 --- a/sdk/storage/src/blobs/blob_container_client.cpp +++ b/sdk/storage/src/blobs/blob_container_client.cpp @@ -93,7 +93,8 @@ namespace Azure { namespace Storage { namespace Blobs { BlobContainerClient::BlobContainerClient( const std::string& containerUri, const BlobContainerClientOptions& options) - : m_containerUrl(containerUri) + : m_containerUrl(containerUri), m_customerProvidedKey(options.CustomerProvidedKey), + m_encryptionScope(options.EncryptionScope) { std::vector> policies; policies.emplace_back(std::make_unique( @@ -118,7 +119,7 @@ namespace Azure { namespace Storage { namespace Blobs { { auto blobUri = m_containerUrl; blobUri.AppendPath(blobName); - return BlobClient(std::move(blobUri), m_pipeline); + return BlobClient(std::move(blobUri), m_pipeline, m_customerProvidedKey, m_encryptionScope); } BlockBlobClient BlobContainerClient::GetBlockBlobClient(const std::string& blobName) const @@ -142,6 +143,8 @@ namespace Azure { namespace Storage { namespace Blobs { BlobRestClient::Container::CreateOptions protocolLayerOptions; protocolLayerOptions.AccessType = options.AccessType; protocolLayerOptions.Metadata = options.Metadata; + protocolLayerOptions.DefaultEncryptionScope = options.DefaultEncryptionScope; + protocolLayerOptions.PreventEncryptionScopeOverride = options.PreventEncryptionScopeOverride; return BlobRestClient::Container::Create( options.Context, *m_pipeline, m_containerUrl.ToString(), protocolLayerOptions); } diff --git a/sdk/storage/src/blobs/block_blob_client.cpp b/sdk/storage/src/blobs/block_blob_client.cpp index 5b1c3d0b1..fa1be1a01 100644 --- a/sdk/storage/src/blobs/block_blob_client.cpp +++ b/sdk/storage/src/blobs/block_blob_client.cpp @@ -90,6 +90,13 @@ namespace Azure { namespace Storage { namespace Blobs { protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch; protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch; + if (m_customerProvidedKey.HasValue()) + { + protocolLayerOptions.EncryptionKey = m_customerProvidedKey.GetValue().Key; + protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash; + protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm; + } + protocolLayerOptions.EncryptionScope = m_encryptionScope; return BlobRestClient::BlockBlob::Upload( options.Context, *m_pipeline, m_blobUrl.ToString(), content, protocolLayerOptions); } @@ -246,6 +253,13 @@ namespace Azure { namespace Storage { namespace Blobs { protocolLayerOptions.ContentMd5 = options.ContentMd5; protocolLayerOptions.ContentCrc64 = options.ContentCrc64; protocolLayerOptions.LeaseId = options.AccessConditions.LeaseId; + if (m_customerProvidedKey.HasValue()) + { + protocolLayerOptions.EncryptionKey = m_customerProvidedKey.GetValue().Key; + protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash; + protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm; + } + protocolLayerOptions.EncryptionScope = m_encryptionScope; return BlobRestClient::BlockBlob::StageBlock( options.Context, *m_pipeline, m_blobUrl.ToString(), content, protocolLayerOptions); } @@ -278,6 +292,13 @@ namespace Azure { namespace Storage { namespace Blobs { protocolLayerOptions.SourceIfUnmodifiedSince = options.SourceConditions.IfUnmodifiedSince; protocolLayerOptions.SourceIfMatch = options.SourceConditions.IfMatch; protocolLayerOptions.SourceIfNoneMatch = options.SourceConditions.IfNoneMatch; + if (m_customerProvidedKey.HasValue()) + { + protocolLayerOptions.EncryptionKey = m_customerProvidedKey.GetValue().Key; + protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash; + protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm; + } + protocolLayerOptions.EncryptionScope = m_encryptionScope; return BlobRestClient::BlockBlob::StageBlockFromUri( options.Context, *m_pipeline, m_blobUrl.ToString(), protocolLayerOptions); } @@ -296,6 +317,13 @@ namespace Azure { namespace Storage { namespace Blobs { protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch; protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch; + if (m_customerProvidedKey.HasValue()) + { + protocolLayerOptions.EncryptionKey = m_customerProvidedKey.GetValue().Key; + protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash; + protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm; + } + protocolLayerOptions.EncryptionScope = m_encryptionScope; return BlobRestClient::BlockBlob::CommitBlockList( options.Context, *m_pipeline, m_blobUrl.ToString(), protocolLayerOptions); } diff --git a/sdk/storage/src/blobs/page_blob_client.cpp b/sdk/storage/src/blobs/page_blob_client.cpp index d9bfdf612..e3a9ea04c 100644 --- a/sdk/storage/src/blobs/page_blob_client.cpp +++ b/sdk/storage/src/blobs/page_blob_client.cpp @@ -85,6 +85,13 @@ namespace Azure { namespace Storage { namespace Blobs { protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch; protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch; + if (m_customerProvidedKey.HasValue()) + { + protocolLayerOptions.EncryptionKey = m_customerProvidedKey.GetValue().Key; + protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash; + protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm; + } + protocolLayerOptions.EncryptionScope = m_encryptionScope; return BlobRestClient::PageBlob::Create( options.Context, *m_pipeline, m_blobUrl.ToString(), protocolLayerOptions); } @@ -103,6 +110,13 @@ namespace Azure { namespace Storage { namespace Blobs { protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch; protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch; + if (m_customerProvidedKey.HasValue()) + { + protocolLayerOptions.EncryptionKey = m_customerProvidedKey.GetValue().Key; + protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash; + protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm; + } + protocolLayerOptions.EncryptionScope = m_encryptionScope; return BlobRestClient::PageBlob::UploadPages( options.Context, *m_pipeline, m_blobUrl.ToString(), content, protocolLayerOptions); } @@ -127,6 +141,13 @@ namespace Azure { namespace Storage { namespace Blobs { protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch; protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch; + if (m_customerProvidedKey.HasValue()) + { + protocolLayerOptions.EncryptionKey = m_customerProvidedKey.GetValue().Key; + protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash; + protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm; + } + protocolLayerOptions.EncryptionScope = m_encryptionScope; return BlobRestClient::PageBlob::UploadPagesFromUri( options.Context, *m_pipeline, m_blobUrl.ToString(), protocolLayerOptions); } @@ -143,6 +164,13 @@ namespace Azure { namespace Storage { namespace Blobs { protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch; protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch; + if (m_customerProvidedKey.HasValue()) + { + protocolLayerOptions.EncryptionKey = m_customerProvidedKey.GetValue().Key; + protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash; + protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm; + } + protocolLayerOptions.EncryptionScope = m_encryptionScope; return BlobRestClient::PageBlob::ClearPages( options.Context, *m_pipeline, m_blobUrl.ToString(), protocolLayerOptions); } @@ -158,6 +186,13 @@ namespace Azure { namespace Storage { namespace Blobs { protocolLayerOptions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; protocolLayerOptions.IfMatch = options.AccessConditions.IfMatch; protocolLayerOptions.IfNoneMatch = options.AccessConditions.IfNoneMatch; + if (m_customerProvidedKey.HasValue()) + { + protocolLayerOptions.EncryptionKey = m_customerProvidedKey.GetValue().Key; + protocolLayerOptions.EncryptionKeySha256 = m_customerProvidedKey.GetValue().KeyHash; + protocolLayerOptions.EncryptionAlgorithm = m_customerProvidedKey.GetValue().Algorithm; + } + protocolLayerOptions.EncryptionScope = m_encryptionScope; return BlobRestClient::PageBlob::Resize( options.Context, *m_pipeline, m_blobUrl.ToString(), protocolLayerOptions); } diff --git a/sdk/storage/src/common/crypt.cpp b/sdk/storage/src/common/crypt.cpp index 7690721cf..a7ee367b1 100644 --- a/sdk/storage/src/common/crypt.cpp +++ b/sdk/storage/src/common/crypt.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #endif #include @@ -20,18 +21,31 @@ namespace Azure { namespace Storage { #ifdef _WIN32 - std::string Hmac_Sha256(const std::string& text, const std::string& key) - { + + namespace { + + enum class AlgorithmType + { + Hmac_Sha256, + Sha256, + }; + struct AlgorithmProviderInstance { BCRYPT_ALG_HANDLE Handle; std::size_t ContextSize; std::size_t HashLength; - AlgorithmProviderInstance() + AlgorithmProviderInstance(AlgorithmType type) { - NTSTATUS status = BCryptOpenAlgorithmProvider( - &Handle, BCRYPT_SHA256_ALGORITHM, nullptr, BCRYPT_ALG_HANDLE_HMAC_FLAG); + const wchar_t* algorithmId = BCRYPT_SHA256_ALGORITHM; + unsigned long algorithmFlags = 0; + if (type == AlgorithmType::Hmac_Sha256) + { + algorithmFlags = BCRYPT_ALG_HANDLE_HMAC_FLAG; + } + NTSTATUS status + = BCryptOpenAlgorithmProvider(&Handle, algorithmId, nullptr, algorithmFlags); if (!BCRYPT_SUCCESS(status)) { throw std::runtime_error("BCryptOpenAlgorithmProvider failed"); @@ -68,7 +82,57 @@ namespace Azure { namespace Storage { ~AlgorithmProviderInstance() { BCryptCloseAlgorithmProvider(Handle, 0); } }; - static AlgorithmProviderInstance AlgorithmProvider; + } // namespace + + std::string Sha256(const std::string& text) + { + static AlgorithmProviderInstance AlgorithmProvider(AlgorithmType::Sha256); + + std::string context; + context.resize(AlgorithmProvider.ContextSize); + + BCRYPT_HASH_HANDLE hashHandle; + NTSTATUS status = BCryptCreateHash( + AlgorithmProvider.Handle, + &hashHandle, + reinterpret_cast(&context[0]), + static_cast(context.size()), + nullptr, + 0, + 0); + if (!BCRYPT_SUCCESS(status)) + { + throw std::runtime_error("BCryptCreateHash failed"); + } + + status = BCryptHashData( + hashHandle, + reinterpret_cast(const_cast(&text[0])), + static_cast(text.length()), + 0); + if (!BCRYPT_SUCCESS(status)) + { + throw std::runtime_error("BCryptHashData failed"); + } + + std::string hash; + hash.resize(AlgorithmProvider.HashLength); + status = BCryptFinishHash( + hashHandle, reinterpret_cast(&hash[0]), static_cast(hash.length()), 0); + if (!BCRYPT_SUCCESS(status)) + { + throw std::runtime_error("BCryptFinishHash failed"); + } + + BCryptDestroyHash(hashHandle); + + return hash; + } + + std::string Hmac_Sha256(const std::string& text, const std::string& key) + { + + static AlgorithmProviderInstance AlgorithmProvider(AlgorithmType::Hmac_Sha256); std::string context; context.resize(AlgorithmProvider.ContextSize); @@ -150,6 +214,16 @@ namespace Azure { namespace Storage { #else + std::string Sha256(const std::string& text) + { + SHA256_CTX context; + SHA256_Init(&context); + SHA256_Update(&context, text.data(), text.length()); + unsigned char hash[SHA256_DIGEST_LENGTH]; + SHA256_Final(hash, &context); + return std::string(std::begin(hash), std::end(hash)); + } + std::string Hmac_Sha256(const std::string& text, const std::string& key) { char hash[EVP_MAX_MD_SIZE]; @@ -198,6 +272,7 @@ namespace Azure { namespace Storage { decoded.resize(decodedLength); return decoded; } + #endif }} // namespace Azure::Storage diff --git a/sdk/storage/test/blobs/append_blob_client_test.cpp b/sdk/storage/test/blobs/append_blob_client_test.cpp index f43d1c35e..ba7d483f8 100644 --- a/sdk/storage/test/blobs/append_blob_client_test.cpp +++ b/sdk/storage/test/blobs/append_blob_client_test.cpp @@ -47,6 +47,8 @@ namespace Azure { namespace Storage { namespace Test { EXPECT_FALSE(blobContentInfo->LastModified.empty()); EXPECT_TRUE(blobContentInfo->VersionId.HasValue()); EXPECT_FALSE(blobContentInfo->VersionId.GetValue().empty()); + EXPECT_FALSE(blobContentInfo->EncryptionScope.HasValue()); + EXPECT_FALSE(blobContentInfo->EncryptionKeySha256.HasValue()); auto properties = *appendBlobClient.GetProperties(); EXPECT_TRUE(properties.CommittedBlockCount.HasValue()); diff --git a/sdk/storage/test/blobs/blob_container_client_test.cpp b/sdk/storage/test/blobs/blob_container_client_test.cpp index d3fdbab13..11fc880ee 100644 --- a/sdk/storage/test/blobs/blob_container_client_test.cpp +++ b/sdk/storage/test/blobs/blob_container_client_test.cpp @@ -3,6 +3,7 @@ #include "blob_container_client_test.hpp" #include "blobs/blob_sas_builder.hpp" +#include "common/crypt.hpp" namespace Azure { namespace Storage { namespace Blobs { @@ -393,4 +394,163 @@ namespace Azure { namespace Storage { namespace Test { m_blobContainerClient->BreakLease(options); } + TEST_F(BlobContainerClientTest, EncryptionScope) + { + { + std::string containerName = LowercaseRandomString(); + std::string blobName = RandomString(); + Blobs::BlobContainerClientOptions options; + options.EncryptionScope = c_TestEncryptionScope; + auto containerClient = Azure::Storage::Blobs::BlobContainerClient::CreateFromConnectionString( + StandardStorageConnectionString(), containerName, options); + Blobs::CreateBlobContainerOptions createOptions; + createOptions.DefaultEncryptionScope = c_TestEncryptionScope; + createOptions.PreventEncryptionScopeOverride = true; + EXPECT_NO_THROW(containerClient.Create(createOptions)); + auto appendBlobClient = containerClient.GetAppendBlobClient(blobName); + auto blobContentInfo = appendBlobClient.Create(); + EXPECT_TRUE(blobContentInfo->EncryptionScope.HasValue()); + EXPECT_EQ(blobContentInfo->EncryptionScope.GetValue(), c_TestEncryptionScope); + auto appendBlobClientWithoutEncryptionScope + = Azure::Storage::Blobs::AppendBlobClient::CreateFromConnectionString( + StandardStorageConnectionString(), containerName, blobName); + blobContentInfo = appendBlobClientWithoutEncryptionScope.Create(); + EXPECT_TRUE(blobContentInfo->EncryptionScope.HasValue()); + EXPECT_EQ(blobContentInfo->EncryptionScope.GetValue(), c_TestEncryptionScope); + containerClient.Delete(); + } + { + std::string blobName = RandomString(); + Blobs::AppendBlobClientOptions options; + options.EncryptionScope = c_TestEncryptionScope; + auto appendBlobClient = Azure::Storage::Blobs::AppendBlobClient::CreateFromConnectionString( + StandardStorageConnectionString(), m_containerName, blobName, options); + auto blobContentInfo = appendBlobClient.Create(); + EXPECT_TRUE(blobContentInfo->EncryptionScope.HasValue()); + EXPECT_EQ(blobContentInfo->EncryptionScope.GetValue(), c_TestEncryptionScope); + auto properties = *appendBlobClient.GetProperties(); + EXPECT_TRUE(properties.EncryptionScope.HasValue()); + EXPECT_EQ(properties.EncryptionScope.GetValue(), c_TestEncryptionScope); + std::vector appendContent(1); + Azure::Core::Http::MemoryBodyStream bodyStream(appendContent.data(), appendContent.size()); + EXPECT_NO_THROW(appendBlobClient.AppendBlock(&bodyStream)); + + bodyStream.Rewind(); + auto appendBlobClientWithoutEncryptionScope + = Azure::Storage::Blobs::AppendBlobClient::CreateFromConnectionString( + StandardStorageConnectionString(), m_containerName, blobName); + EXPECT_THROW(appendBlobClientWithoutEncryptionScope.AppendBlock(&bodyStream), StorageError); + EXPECT_THROW(appendBlobClientWithoutEncryptionScope.CreateSnapshot(), StorageError); + } + } + + TEST_F(BlobContainerClientTest, CustomerProvidedKey) + { + auto getRandomCustomerProvidedKey = []() { + Blobs::EncryptionKey key; + std::string aes256Key; + aes256Key.resize(32); + RandomBuffer(&aes256Key[0], aes256Key.size()); + key.Key = Base64Encode(aes256Key); + key.KeyHash = Base64Encode(Sha256(aes256Key)); + key.Algorithm = Blobs::EncryptionAlgorithmType::Aes256; + return key; + }; + + Blobs::BlobContainerClientOptions options; + options.CustomerProvidedKey = getRandomCustomerProvidedKey(); + auto containerClient = Azure::Storage::Blobs::BlobContainerClient::CreateFromConnectionString( + StandardStorageConnectionString(), m_containerName, options); + + std::vector blobContent(512); + Azure::Core::Http::MemoryBodyStream bodyStream(blobContent.data(), blobContent.size()); + auto copySourceBlob = m_blobContainerClient->GetBlockBlobClient(RandomString()); + copySourceBlob.UploadFromBuffer(blobContent.data(), blobContent.size()); + + { + std::string blockBlobName = RandomString(); + auto blockBlob = containerClient.GetBlockBlobClient(blockBlobName); + bodyStream.Rewind(); + EXPECT_NO_THROW(blockBlob.Upload(&bodyStream)); + std::string blockId1 = Base64Encode("1"); + std::string blockId2 = Base64Encode("2"); + bodyStream.Rewind(); + EXPECT_NO_THROW(blockBlob.StageBlock(blockId1, &bodyStream)); + EXPECT_NO_THROW(blockBlob.StageBlockFromUri(blockId2, copySourceBlob.GetUri() + GetSas())); + EXPECT_NO_THROW(blockBlob.CommitBlockList( + {{Blobs::BlockType::Uncommitted, blockId1}, {Blobs::BlockType::Uncommitted, blockId2}})); + EXPECT_THROW(blockBlob.SetAccessTier(Blobs::AccessTier::Cool), StorageError); + + auto appendBlobClientWithoutEncryptionKey + = Azure::Storage::Blobs::BlockBlobClient::CreateFromConnectionString( + StandardStorageConnectionString(), m_containerName, blockBlobName); + EXPECT_THROW( + appendBlobClientWithoutEncryptionKey.SetAccessTier(Blobs::AccessTier::Cool), + StorageError); + EXPECT_NO_THROW(appendBlobClientWithoutEncryptionKey.GetBlockList()); + } + + { + std::string appendBlobName = RandomString(); + auto appendBlob = containerClient.GetAppendBlobClient(appendBlobName); + auto blobContentInfo = *appendBlob.Create(); + EXPECT_TRUE(blobContentInfo.ServerEncrypted.HasValue()); + EXPECT_TRUE(blobContentInfo.ServerEncrypted.GetValue()); + EXPECT_TRUE(blobContentInfo.EncryptionKeySha256.HasValue()); + EXPECT_EQ( + blobContentInfo.EncryptionKeySha256.GetValue(), + options.CustomerProvidedKey.GetValue().KeyHash); + + bodyStream.Rewind(); + EXPECT_NO_THROW(appendBlob.AppendBlock(&bodyStream)); + EXPECT_NO_THROW(appendBlob.AppendBlockFromUri(copySourceBlob.GetUri() + GetSas())); + EXPECT_NO_THROW(appendBlob.Download()); + EXPECT_NO_THROW(appendBlob.GetProperties()); + EXPECT_NO_THROW(appendBlob.SetMetadata({})); + EXPECT_NO_THROW(appendBlob.CreateSnapshot()); + + auto appendBlobClientWithoutEncryptionKey + = Azure::Storage::Blobs::AppendBlobClient::CreateFromConnectionString( + StandardStorageConnectionString(), m_containerName, appendBlobName); + bodyStream.Rewind(); + EXPECT_THROW(appendBlobClientWithoutEncryptionKey.AppendBlock(&bodyStream), StorageError); + EXPECT_THROW( + appendBlobClientWithoutEncryptionKey.AppendBlockFromUri( + copySourceBlob.GetUri() + GetSas()), + StorageError); + EXPECT_THROW(appendBlobClientWithoutEncryptionKey.Download(), StorageError); + EXPECT_THROW(appendBlobClientWithoutEncryptionKey.GetProperties(), StorageError); + EXPECT_THROW(appendBlobClientWithoutEncryptionKey.SetMetadata({}), StorageError); + EXPECT_THROW(appendBlobClientWithoutEncryptionKey.CreateSnapshot(), StorageError); + EXPECT_NO_THROW( + appendBlobClientWithoutEncryptionKey.SetHttpHeaders(Blobs::BlobHttpHeaders())); + Blobs::DeleteBlobOptions deleteOptions; + deleteOptions.DeleteSnapshots = Blobs::DeleteSnapshotsOption::IncludeSnapshots; + EXPECT_NO_THROW(appendBlobClientWithoutEncryptionKey.Delete(deleteOptions)); + } + + { + std::string pageBlobName = RandomString(); + auto pageBlob = containerClient.GetPageBlobClient(pageBlobName); + auto blobContentInfo = *pageBlob.Create(0); + EXPECT_TRUE(blobContentInfo.ServerEncrypted.HasValue()); + EXPECT_TRUE(blobContentInfo.ServerEncrypted.GetValue()); + EXPECT_TRUE(blobContentInfo.EncryptionKeySha256.HasValue()); + EXPECT_EQ( + blobContentInfo.EncryptionKeySha256.GetValue(), + options.CustomerProvidedKey.GetValue().KeyHash); + bodyStream.Rewind(); + EXPECT_NO_THROW(pageBlob.Resize(blobContent.size())); + EXPECT_NO_THROW(pageBlob.UploadPages(&bodyStream, 0)); + EXPECT_NO_THROW(pageBlob.ClearPages(0, blobContent.size())); + EXPECT_NO_THROW(pageBlob.UploadPagesFromUri( + copySourceBlob.GetUri() + GetSas(), 0, blobContent.size(), 0)); + + auto pageBlobClientWithoutEncryptionKey + = Azure::Storage::Blobs::PageBlobClient::CreateFromConnectionString( + StandardStorageConnectionString(), m_containerName, pageBlobName); + EXPECT_NO_THROW(pageBlobClientWithoutEncryptionKey.GetPageRanges()); + } + } + }}} // namespace Azure::Storage::Test diff --git a/sdk/storage/test/blobs/block_blob_client_test.cpp b/sdk/storage/test/blobs/block_blob_client_test.cpp index 8dac62151..62220f36f 100644 --- a/sdk/storage/test/blobs/block_blob_client_test.cpp +++ b/sdk/storage/test/blobs/block_blob_client_test.cpp @@ -69,6 +69,8 @@ namespace Azure { namespace Storage { namespace Test { EXPECT_FALSE(blobContentInfo->LastModified.empty()); EXPECT_TRUE(blobContentInfo->VersionId.HasValue()); EXPECT_FALSE(blobContentInfo->VersionId.GetValue().empty()); + EXPECT_FALSE(blobContentInfo->EncryptionScope.HasValue()); + EXPECT_FALSE(blobContentInfo->EncryptionKeySha256.HasValue()); blockBlobClient.Delete(); EXPECT_THROW(blockBlobClient.Delete(), StorageError); diff --git a/sdk/storage/test/blobs/page_blob_client_test.cpp b/sdk/storage/test/blobs/page_blob_client_test.cpp index 8a88dc873..17a32d8d5 100644 --- a/sdk/storage/test/blobs/page_blob_client_test.cpp +++ b/sdk/storage/test/blobs/page_blob_client_test.cpp @@ -47,6 +47,8 @@ namespace Azure { namespace Storage { namespace Test { EXPECT_FALSE(blobContentInfo->LastModified.empty()); EXPECT_TRUE(blobContentInfo->VersionId.HasValue()); EXPECT_FALSE(blobContentInfo->VersionId.GetValue().empty()); + EXPECT_FALSE(blobContentInfo->EncryptionScope.HasValue()); + EXPECT_FALSE(blobContentInfo->EncryptionKeySha256.HasValue()); pageBlobClient.Delete(); EXPECT_THROW(pageBlobClient.Delete(), StorageError); diff --git a/sdk/storage/test/test_base.hpp b/sdk/storage/test/test_base.hpp index c732b553d..1a2336ad0 100644 --- a/sdk/storage/test/test_base.hpp +++ b/sdk/storage/test/test_base.hpp @@ -22,6 +22,8 @@ namespace Azure { namespace Storage { namespace Test { const std::string& AadClientId(); const std::string& AadClientSecret(); + constexpr static const char* c_TestEncryptionScope = "EncryptionScopeForTest"; + constexpr inline unsigned long long operator""_KB(unsigned long long x) { return x * 1024; } constexpr inline unsigned long long operator""_MB(unsigned long long x) {