If client-side encryption is enabled, objects are locally encrypted before they are uploaded to Object Storage Service (OSS). Only the holder of the customer master key (CMK) can decrypt the objects. Client-side encryption enhances data security during data transmission and storage.
Usage notes
The sample code in this topic uses the region ID
cn-hangzhoufor the China (Hangzhou) region as an example. A public endpoint is used by default. If you want to access OSS from other Alibaba Cloud products in the same region, use an internal endpoint. For more information about the mappings between OSS regions and endpoints, see Regions and endpoints.When you use client-side encryption, you must ensure the integrity and validity of the CMK.
When you copy or migrate encrypted data, you are responsible for the integrity and validity of object metadata.
Use RSA-based CMKs for client-side encryption
Use RSA-based CMKs to encrypt objects in simple uploads and decrypt objects in simple downloads
The following sample code provides an example on how to use an RSA-based CMK to encrypt objects in simple uploads and decrypt objects in simple downloads:
<?php
// Introduce autoload files to load dependent libraries.
require_once __DIR__ . '/../vendor/autoload.php';
use AlibabaCloud\Oss\V2 as Oss;
// Specify the RSA public key for the data encryption operation.
const RSA_PUBLIC_KEY = <<<BBB
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCokfiAVXXf5ImFzKDw+XO/UByW
6mse2QsIgz3ZwBtMNu59fR5zttSx+8fB7vR4CN3bTztrP9A6bjoN0FFnhlQ3vNJC
5MFO1PByrE/MNd5AAfSVba93I6sx8NSk5MzUCA4NJzAUqYOEWGtGBcom6kEF6MmR
1EKib1Id8hpooY5xaQIDAQAB
-----END PUBLIC KEY-----
BBB;
// Specify the RSA private key for the data decryption operation.
const RSA_PRIVATE_KEY = <<<BBB
-----BEGIN PRIVATE KEY-----
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKiR+IBVdd/kiYXM
oPD5c79QHJbqax7ZCwiDPdnAG0w27n19HnO21LH7x8Hu9HgI3dtPO2s/0DpuOg3Q
UWeGVDe80kLkwU7U8HKsT8w13kAB9JVtr3cjqzHw1KTkzNQIDg0nMBSpg4RYa0YF
yibqQQXoyZHUQqJvUh3yGmihjnFpAgMBAAECgYA49RmCQ14QyKevDfVTdvYlLmx6
kbqgMbYIqk+7w611kxoCTMR9VMmJWgmk/Zic9mIAOEVbd7RkCdqT0E+xKzJJFpI2
ZHjrlwb21uqlcUqH1Gn+wI+jgmrafrnKih0kGucavr/GFi81rXixDrGON9KBE0FJ
cPVdc0XiQAvCBnIIAQJBANXu3htPH0VsSznfqcDE+w8zpoAJdo6S/p30tcjsDQnx
l/jYV4FXpErSrtAbmI013VYkdJcghNSLNUXppfk2e8UCQQDJt5c07BS9i2SDEXiz
byzqCfXVzkdnDj9ry9mba1dcr9B9NCslVelXDGZKvQUBqNYCVxg398aRfWlYDTjU
IoVVAkAbTyjPN6R4SkC4HJMg5oReBmvkwFCAFsemBk0GXwuzD0IlJAjXnAZ+/rIO
ItewfwXIL1Mqz53lO/gK+q6TR585AkB304KUIoWzjyF3JqLP3IQOxzns92u9EV6l
V2P+CkbMPXiZV6sls6I4XppJXX2i3bu7iidN3/dqJ9izQK94fMU9AkBZvgsIPCot
y1/POIbv9LtnviDKrmpkXgVQSU4BmTPvXwTJm8APC7P/horSh3SVf1zgmnsyjm9D
hO92gGc+4ajL
-----END PRIVATE KEY-----
BBB;
// Specify descriptions for command line parameters.
$optsdesc = [
"region" => ['help' => The region in which the bucket is located.', 'required' => True], // (Required) Specify the region in which the bucket is located.
"endpoint" => ['help' => The domain names that other services can use to access OSS', 'required' => False], // (Optional) Specify the endpoint that can be used by other services to access OSS.
"bucket" => ['help' => The name of the bucket, 'required' => True], // (Required) Specify the name of the bucket.
"key" => ['help' => The name of the object, 'required' => True], // (Required) Specify the name of the object.
];
// Generate a long options list to parse the command line parameters.
$longopts = \array_map(function ($key) {
return "$key:"; // Add a colon (:) to the end of each parameter to indicate that a value is required.
}, array_keys($optsdesc));
// Parse the command line parameters.
$options = getopt("", $longopts);
// Check whether the required parameters are configured.
foreach ($optsdesc as $key => $value) {
if ($value['required'] === True && empty($options[$key])) {
$help = $value['help'];
echo "Error: the following arguments are required: --$key, $help"; // Indicate that the required parameters are not configured.
exit(1);
}
}
// Obtain the values of the command line parameters.
$region = $options["region"]; // The region in which the bucket is located.
$bucket = $options["bucket"]; // The name of the bucket.
$key = $options["key"]; // The name of the object.
// Use environment variables to load the AccessKey ID and AccessKey secret.
$credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
// Use the default configurations of the SDK.
$cfg = Oss\Config::loadDefault();
// Specify the credential provider.
$cfg->setCredentialsProvider($credentialsProvider);
// Specify the region.
$cfg->setRegion($region);
// Specify the endpoint if an endpoint is provided.
if (isset($options["endpoint"])) {
$cfg->setEndpoint($options["endpoint"]);
}
// Create an OSSClient instance.
$client = new Oss\Client($cfg);
// Create a CMK encrypter and use the RSA public key for data encryption and the RSA private key for data decryption.
$masterCipher = new Oss\Crypto\MasterRsaCipher(
publicKey: RSA_PUBLIC_KEY, // Specify the RSA public key.
privateKey: RSA_PRIVATE_KEY, // Specify the RSA private key.
matDesc: ['tag' => 'value'] // Encrypt additional tags.
);
// Create a client for client-side encryption.
$eclient = new Oss\EncryptionClient(client: $client, masterCipher: $masterCipher);
// Create a PutObjectRequest object for simple upload.
$putObjRequest = new Oss\Models\PutObjectRequest(bucket: $bucket, key: $key);
// Use the putObject method to upload the local file.
$putObjResult = $eclient->putObject(request: $putObjRequest);
// Display the returned result.
printf(
'put object status code:' . $putObjResult->statusCode . PHP_EOL . // The returned HTTP status code.
'request id:' . $putObjResult->requestId . PHP_EOL // The request ID, which is the unique identifier of the request.
);
Use RSA-based CMKs to encrypt objects in multipart upload
The following sample code provides an example on how to use an RSA-based CMK to encrypt an object in multipart upload:
<?php
// Introduce autoload files to load dependent libraries.
require_once __DIR__ . '/../vendor/autoload.php';
use AlibabaCloud\Oss\V2 as Oss;
// Specify the RSA public key for the data encryption operation.
const RSA_PUBLIC_KEY = <<<BBB
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCokfiAVXXf5ImFzKDw+XO/UByW
6mse2QsIgz3ZwBtMNu59fR5zttSx+8fB7vR4CN3bTztrP9A6bjoN0FFnhlQ3vNJC
5MFO1PByrE/MNd5AAfSVba93I6sx8NSk5MzUCA4NJzAUqYOEWGtGBcom6kEF6MmR
1EKib1Id8hpooY5xaQIDAQAB
-----END PUBLIC KEY-----
BBB;
// Specify the RSA private key for the data decryption operation.
const RSA_PRIVATE_KEY = <<<BBB
-----BEGIN PRIVATE KEY-----
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKiR+IBVdd/kiYXM
oPD5c79QHJbqax7ZCwiDPdnAG0w27n19HnO21LH7x8Hu9HgI3dtPO2s/0DpuOg3Q
UWeGVDe80kLkwU7U8HKsT8w13kAB9JVtr3cjqzHw1KTkzNQIDg0nMBSpg4RYa0YF
yibqQQXoyZHUQqJvUh3yGmihjnFpAgMBAAECgYA49RmCQ14QyKevDfVTdvYlLmx6
kbqgMbYIqk+7w611kxoCTMR9VMmJWgmk/Zic9mIAOEVbd7RkCdqT0E+xKzJJFpI2
ZHjrlwb21uqlcUqH1Gn+wI+jgmrafrnKih0kGucavr/GFi81rXixDrGON9KBE0FJ
cPVdc0XiQAvCBnIIAQJBANXu3htPH0VsSznfqcDE+w8zpoAJdo6S/p30tcjsDQnx
l/jYV4FXpErSrtAbmI013VYkdJcghNSLNUXppfk2e8UCQQDJt5c07BS9i2SDEXiz
byzqCfXVzkdnDj9ry9mba1dcr9B9NCslVelXDGZKvQUBqNYCVxg398aRfWlYDTjU
IoVVAkAbTyjPN6R4SkC4HJMg5oReBmvkwFCAFsemBk0GXwuzD0IlJAjXnAZ+/rIO
ItewfwXIL1Mqz53lO/gK+q6TR585AkB304KUIoWzjyF3JqLP3IQOxzns92u9EV6l
V2P+CkbMPXiZV6sls6I4XppJXX2i3bu7iidN3/dqJ9izQK94fMU9AkBZvgsIPCot
y1/POIbv9LtnviDKrmpkXgVQSU4BmTPvXwTJm8APC7P/horSh3SVf1zgmnsyjm9D
hO92gGc+4ajL
-----END PRIVATE KEY-----
BBB;
// Specify descriptions for command line parameters.
$optsdesc = [
"region" => ['help' => The region in which the bucket is located.', 'required' => True], // (Required) Specify the region in which the bucket is located.
"endpoint" => ['help' => The domain names that other services can use to access OSS', 'required' => False], // (Optional) Specify the endpoint that can be used by other services to access OSS.
"bucket" => ['help' => The name of the bucket, 'required' => True], // (Required) Specify the name of the bucket.
"key" => ['help' => The name of the object, 'required' => True], // (Required) Specify the name of the object.
];
// Generate a long options list to parse the command line parameters.
$longopts = \array_map(function ($key) {
return "$key:"; // Add a colon (:) to the end of each parameter to indicate that a value is required.
}, array_keys($optsdesc));
// Parse the command line parameters.
$options = getopt("", $longopts);
// Check whether the required parameters are configured.
foreach ($optsdesc as $key => $value) {
if ($value['required'] === True && empty($options[$key])) {
$help = $value['help'];
echo "Error: the following arguments are required: --$key, $help"; // Indicate that the required parameters are not configured.
exit(1);
}
}
// Obtain the values of the command line parameters.
$region = $options["region"]; // The region in which the bucket is located.
$bucket = $options["bucket"]; // The name of the bucket.
$key = $options["key"]; // The name of the object.
// Use environment variables to load the AccessKey ID and AccessKey secret.
$credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
// Use the default configurations of the SDK.
$cfg = Oss\Config::loadDefault();
// Specify the credential provider.
$cfg->setCredentialsProvider($credentialsProvider);
// Specify the region.
$cfg->setRegion($region);
// Specify the endpoint if an endpoint is provided.
if (isset($options["endpoint"])) {
$cfg->setEndpoint($options["endpoint"]);
}
// Create an OSSClient instance.
$client = new Oss\Client($cfg);
// Create a CMK encrypter and use the RSA public key for data encryption and the RSA private key for data decryption.
$masterCipher = new Oss\Crypto\MasterRsaCipher(
RSA_PUBLIC_KEY, // Specify the RSA public key.
RSA_PRIVATE_KEY, // Specify the RSA private key.
['tag' => 'value'] // Encrypt additional tags.
);
// Create a client for client-side encryption.
$eclient = new Oss\EncryptionClient($client, $masterCipher);
// Initiate a multipart upload request and specify the part size and the total object size.
$initRequest = new Oss\Models\InitiateMultipartUploadRequest(bucket: $bucket, key: $key);
$initRequest-> cseDataSize=500 * 1024; // Set the total size of the object to 500 KB.
$initRequest-> csePartSize=200 * 1024; // Set the size of each part to 200 KB.
// Use the initiateMultipartUpload method to initiate a multipart upload request.
$initResult = $eclient->initiateMultipartUpload(request: $initRequest);
// Create an UploadPartRequest object for the multipart upload task.
$uploadPartRequest = new Oss\Models\UploadPartRequest(bucket: $bucket, key: $key);
// Specify the name and part size of the temporary local file.
$bigFileName = "upload.tmp"; // Specify the name of the temporary local file.
$partSize=200 * 1024; // Set the size of each part to 200 KB.
// Generate a temporary local file whose size is 500 KB for testing.
generateFile($bigFileName, 500 * 1024);
// Open the temporary local file and read the content.
$file = fopen(filename: $bigFileName, mode: 'r');
// Specify the array used to store the part information.
$parts = array();
// If the temporary local file is successfully opened, read and upload the parts.
if ($file) {
$i = 1; // Specify the part number starting from 1.
while (!feof(stream: $file)) {
// Read the data of a part.
$chunk = fread(stream: $file, length: $partSize);
// Create an UploadPartRequest object for the multipart upload task and specify the part number and upload ID.
$uploadPartRequest = new Oss\Models\UploadPartRequest(
bucket: $bucket,
key: $key,
partNumber: $i,
uploadId: $initResult->uploadId,
contentLength: null,
contentMd5: null,
trafficLimit: null,
requestPayer: null,
body: Oss\Utils::streamFor(resource: $chunk) // Convert the part data to a stream.
);
// Encrypt the context.
$uploadPartRequest->encryptionMultipartContext = $initResult->encryptionMultipartContext;
// Use the uploadPart method to upload a part.
$partResult = $eclient->uploadPart($uploadPartRequest);
// Create an UploadPart object and add it to the part array.
$part = new Oss\Models\UploadPart(
partNumber: $i,
etag: $partResult->etag, // Obtain the ETag of the part.
);
array_push(array: $parts, values: $part);
$i++; // Specify the part number. The part number sequentially increases.
}
fclose(stream: $file); // Close the file.
}
// Use the completeMultipartUpload method to combine the parts into a complete object.
$comResult = $eclient->completeMultipartUpload(
request: new Oss\Models\CompleteMultipartUploadRequest(
bucket: $bucket,
key: $key,
uploadId: $initResult->uploadId,
acl: null,
completeMultipartUpload: new Oss\Models\CompleteMultipartUpload(
parts: $parts
),
)
);
// Delete the temporary local file.
unlink($bigFileName);
// Display the returned result.
printf(
'complete multipart upload status code:' . $comResult->statusCode . PHP_EOL . // The returned HTTP status code.
'complete multipart upload request id:' . $comResult->requestId . PHP_EOL . // The request ID, which is the unique identifier of the request.
complete multipart upload result:' . var_export($comResult, true) // The result of the multipart upload task.
);
// Create a local file of a specific size to test multipart upload.
function generateFile($filename, $size)
{
// If the file already exists and the size of the file meets the requirements, it is returned directly.
if (
file_exists($filename) &&
$size == sprintf('%u', filesize($filename))
) {
return;
}
$part_size=32; // Set the size of each data block that the client can write to OSS at a time to 32 bytes.
$fp = fopen($filename, "w"); // Open the file in write mode.
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; // Specify the character set.
$charactersLength = strlen($characters); // Specify the length of the character set.
// If the file is successfully opened, data is written in a loop until the specified size of data is uploaded.
if ($fp) {
while ($size > 0) {
// Calculate the size of data for the current write operation.
if ($size < $part_size) {
$write_size = $size;
} else {
$write_size = $part_size;
}
$size -= $write_size; // Update the remaining size to be written.
// Randomly select a character and repeatedly generate content.
$a = $characters[rand(0, $charactersLength - 1)];
$content = str_repeat($a, $write_size);
// Write the content to the local file.
$flag = fwrite($fp, $content);
if (!$flag) {
break; // Exit the loop if the write operation fails.
}
}
}
fclose($fp); // Close the local file.
}
Use custom CMKs
Use custom CMKs to encrypt objects in simple uploads and decrypt objects in simple downloads
The SDK provides the default RSA implementation. If the default implementation does not meet your needs, you can implement encryption and decryption based on custom CMKs. The following sample code uses a custom CMK in KMS 3.0 to encrypt an object in simple uploads and decrypt the object in simple downloads:
<?php
// Introduce autoload files to load dependent libraries.
require_once 'vendor/autoload.php';
use AlibabaCloud\Dkms\Gcs\Sdk\Client as KmsClient;
use AlibabaCloud\Oss\V2 as Oss;
// Specify descriptions for command line parameters.
$optsdesc = [
"region" => ['help' => The region in which the bucket is located.', 'required' => True], // (Required) Specify the region in which the bucket is located.
"endpoint" => ['help' => The domain names that other services can use to access OSS.', 'required' => False], // (Optional) Specify the endpoint that can be used by other services to access OSS.
"bucket" => ['help' => The name of the bucket, 'required' => True], // (Required) Specify the name of the bucket.
"key" => ['help' => The name of the object, 'required' => True], // (Required) Specify the name of the object.
];
// Generate a long options list to parse the command line parameters.
$longopts = \array_map(function ($key) {
return "$key:"; // Add a colon (:) to the end of each parameter to indicate that a value is required.
}, array_keys($optsdesc));
// Parse the command line parameters.
$options = getopt("", $longopts);
// Check whether the required parameters are configured.
foreach ($optsdesc as $key => $value) {
if ($value['required'] === True && empty($options[$key])) {
$help = $value['help'];
echo "Error: the following arguments are required: --$key, $help"; // Indicate that the required parameters are not configured.
exit(1);
}
}
// Obtain the values of the command line parameters.
$region = $options["region"]; // The region in which the bucket is located.
$bucket = $options["bucket"]; // The name of the bucket.
$key = $options["key"]; // The name of the object.
// Use environment variables to load the AccessKey ID and AccessKey secret.
$credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
// Specify the KMS encryption and decryption class to call the MasterCipherInterface operation.
class KmsCipher implements Oss\Crypto\MasterCipherInterface
{
private $matDesc;
private ?KmsClient $kmsClient;
private ?string $keyId;
private ?string $algorithm;
public function __construct(
$matDesc = null,
?string $keyId = null,
?KmsClient $kmsClient = null,
?string $algorithm = null
)
{
$this->keyId = $keyId;
$this->matDesc = null;
if (\is_array($matDesc)) {
$val = json_encode($matDesc);
if ($val !== false) {
$this->matDesc = $val;
}
} else if (is_string($matDesc)) {
$this->matDesc = $matDesc;
}
$this->kmsClient = $kmsClient;
$this->algorithm = $algorithm;
}
// Specify the encryption method.
public function encrypt(string $data): string
{
$encryptRequest = new \AlibabaCloud\Dkms\Gcs\Sdk\Models\AdvanceEncryptRequest();
$encryptRequest->algorithm = $this->algorithm;
$encryptRequest->keyId = $this->keyId;
$encryptRequest->plaintext = \AlibabaCloud\Tea\Utils\Utils::toBytes($data);
$runtimeOptions = new \AlibabaCloud\Dkms\Gcs\OpenApi\Util\Models\RuntimeOptions();
$encryptResponse = $this->kmsClient->advanceEncryptWithOptions($encryptRequest, $runtimeOptions);
return base64_decode((string)$encryptResponse->ciphertextBlob);
}
// Specify the decryption method.
public function decrypt(string $data): string
{
$decryptRequest = new \AlibabaCloud\Dkms\Gcs\Sdk\Models\AdvanceDecryptRequest();
$decryptRequest->keyId = $this->keyId;
$decryptRequest->ciphertextBlob = $data;
$decryptRequest->algorithm = $this->algorithm;
$runtimeOptions = new \AlibabaCloud\Dkms\Gcs\OpenApi\Util\Models\RuntimeOptions();
$decryptResponse = $this->kmsClient->advanceDecryptWithOptions($decryptRequest, $runtimeOptions);
return base64_decode((string)$decryptResponse->plaintext);
}
// Obtain the wrapping algorithm.
public function getWrapAlgorithm(): string
{
return "KMS/ALICLOUD";
}
public function getMatDesc(): string
{
return $this->matDesc;
}
}
/**
* Create a dedicated KMS SDK client.
* @return KmsClient
*/
function getDkmsGcsSdkClient()
{
global $clientKeyFile, $password, $endpoint;
// Create configurations for the dedicated KMS SDK client.
$config = new \AlibabaCloud\Dkms\Gcs\OpenApi\Models\Config();
$config->protocol = 'https';
$config->clientKeyFile = $clientKeyFile;
$config->password = $password;
$config->endpoint = $endpoint;
// Verify the certificate.
$config->caFilePath = 'path/to/caCert.pem';
// Create a KMS SDK client.
return new \AlibabaCloud\Dkms\Gcs\Sdk\Client($config);
}
// Specify the path of the file that stores the client key of the KMS instance.
$clientKeyFile = '<your client key file path>';
// Specify the password when you create the client key file.
$password = '<your dkms client passowrd>';
// Specify the endpoint of the KMS instance.
$endpoint = '<your dkms instance service address>';
// Specify the ID of the key that you created in KMS.
$kmsKeyId = '<your cmk id>';
// Specify the encryption and decryption algorithms.
$algorithm = '<your encrypt algorithm>';
// Specify the dedicated KMS SDK client.
$kmsClient = getDkmsGcsSdkClient();
$cfg = Oss\Config::loadDefault();
$cfg->setCredentialsProvider($credentialsProvider);
$cfg->setRegion($region);
if (isset($options["endpoint"])) {
$cfg->setEndpoint($options["endpoint"]);
}
$client = new Oss\Client($cfg);
$materialDesc = ['desc' => 'your kms encrypt key material describe information'];
$masterKmsCipher = new KmsCipher($materialDesc, $kmsKeyId, $kmsClient, $algorithm);
$eClient = new \AlibabaCloud\Oss\V2\EncryptionClient($client, $masterKmsCipher);
$eClient->putObject(new Oss\Models\PutObjectRequest(
bucket: $bucket,
key: $key,
body: Oss\Utils::streamFor('hi kms')
));
$result = $eClient->getObject(new Oss\Models\GetObjectRequest(
bucket: $bucket,
key: $key,
));
$data = $result->body->getContents();
echo "get object data: " . $data;
References
For more information about client-side encryption, see Client-side encryption.
For the complete sample code for simple uploads and downloads based on RSA-based CMKs, visit GitHub.