Client-side encryption (CSE) ensures that your data is encrypted before it
reaches Drive servers, giving you control over your data. This
guide walks you through the process of programmatically encrypting and
uploading, as well as downloading and decrypting, CSE files using the
Drive API. It also covers recommended approaches for testing and
validating your implementation.

## Before you begin

Before you manage encrypted files, set up your Google Workspace domain
using the following checklist:

- Configure [client-side encryption (CSE)](https://knowledge.workspace.google.com/admin/security/about-client-side-encryption?visit_id=639098914640434020-216981450&rd=1#zippy=%2Cbasic-setup-steps-for-cse)
  for your domain.

- Set up your [Identity Provider
  (IdP)](https://knowledge.workspace.google.com/admin/security/connect-to-your-identity-provider-for-client-side-encryption).

- Verify that your [Key Access Control List Service
  (KACLS)](https://developers.google.com/workspace/cse/guides/configure-service) supports the
  [`/wrap`](https://developers.google.com/workspace/cse/reference/wrap),
  [`/unwrap`](https://developers.google.com/workspace/cse/reference/unwrap),
  [`/privilegedwrap`](https://developers.google.com/workspace/cse/reference/privileged-wrap),
  [`/privilegedunwrap`](https://developers.google.com/workspace/cse/reference/privileged-unwrap), and
  [`/digest`](https://developers.google.com/workspace/cse/reference/digest) endpoints.

- Create a project in the [Google Cloud
  console](https://console.cloud.google.com/) and enable the [Drive API](https://developers.google.com/workspace/guides/view-turn-off-apis).

### Authentication and authorization

To interact with the Drive API and your KACLS, you must choose an
authentication method. This choice affects how you interact with both services:

- **Individual:** To authenticate as an individual, use the [OAuth](https://developers.google.com/workspace/guides/auth-overview#process_overview) flow to act on behalf of that user. Use the standard [`/wrap`](https://developers.google.com/workspace/cse/reference/wrap) and [`/unwrap`](https://developers.google.com/workspace/cse/reference/unwrap) endpoints, and provide the Google authorization token for that user.
- **Administrator:** To impersonate other users in the domain, use a [service
  account](https://developers.google.com/identity/protocols/oauth2#serviceaccount) with [domain-wide delegation](https://support.google.com/a/answer/162106) (DWD). Use the [`/privilegedwrap`](https://developers.google.com/workspace/cse/reference/privileged-wrap) and [`/privilegedunwrap`](https://developers.google.com/workspace/cse/reference/privileged-unwrap) endpoints, without a Google authorization token.

> [!CAUTION]
> **Caution:** If a service account is used without domain-wide delegation, created files are added to the service account's drive and not to a particular user's drive, making the files inaccessible to users.

For additional details regarding creating credentials, see the [Create access
credentials](https://developers.google.com/workspace/guides/create-credentials) guide.

### Domain IdP Authentication

To authenticate with your IdP, you must configure an OAuth client ID and
download its client secret file. Your application must obtain an authentication
token from your IdP to authenticate requests to your KACLS. This token is
required to allow your application access to the [Data Encryption Key](https://developers.google.com/workspace/cse/guides/overview#encryption_decryption).

### Handle credentials securely

Your application handles sensitive credentials for authenticating to the
Drive API and your IdP. These include:

- Secret material from the IdP, such as a client-secret-file
- Secret material from Google, such as a service-account-private-key-file
- Secret material stored by the app, such as saved-credentials

You must ensure that all of these credentials are stored securely.

### Limits and quotas

Client-side encrypted files are subject to standard Drive limits
and quotas. Be aware of [shared drive
limits](https://support.google.com/a/users/answer/7338880), general [file and
folder
limits](https://knowledge.workspace.google.com/admin/drive/drive-faq-for-admins#folder),
and how to [manage your
quota](https://docs.cloud.google.com/docs/quotas/view-manage#managing_your_quota_console).
Additionally, your import tool must handle rate limits from your Key Access
Control List Service (KACLS) and your Identity Provider (IdP).

## Encrypted file structure

Drive expects the following client-side encrypted file format for
uploads and downloads.

    +---+
    | Magic header      |
    +---+
    | Encrypted Chunk 1 |
    +---+
    | Encrypted Chunk 2 |
    +---+
    | ...               |
    +---+
    | Encrypted Chunk N |
    +---+

### Magic header

A magic header (also known as a file signature or magic number) is a constant
byte sequence placed at the very beginning of a file to uniquely identify its
format. The file must begin with the bytes `0x99 0x5E 0xCC 0x5E`.

### Encrypted chunks

The file must be split into 2MiB chunks. Each chunk is encrypted using the
[Google Tink](https://developers.google.com/tink) library's Authenticated
Encryption with Associated Data (AEAD) primitive with an AES-GCM key type, using
the chunk index and a final chunk flag as the Associated Data. For a code
example that uses the Drive API and conforms to this specification,
see the [open source demo](https://developers.google.com/workspace/cse/guides/handle-cse-files#open-source-demo).

> [!WARNING]
> **Warning:** Drive will be unable to client-side decrypt files that are structured incorrectly. See [validation
> techniques](https://developers.google.com/workspace/cse/guides/handle-cse-files#validate-imported-files) for recommended testing methods.

## Encrypt and upload a file

To upload a CSE file, your application must authenticate, request a CSE token,
encrypt the file content locally, wrap the encryption key, and finally upload
the encrypted content and metadata to Google Drive.

### Obtain a CSE token

Request a CSE token from Google Drive by calling the Drive API
[`Files:generateCseToken`](https://developers.google.com/drive/api/reference/rest/v3/files/generateCseToken)
method. Ensure that you don't include the `fileId` query parameter in the
request. To create the file in a specific folder, include the `parent` query
parameter with the folder ID. If `parent` is omitted, the file is created in the
user's root My Drive folder. The response includes a unique file ID for the
upload and a JWT authorization token, which is required for the key wrapping
step.

### Encrypt data locally

1. Use [Google Tink](https://developers.google.com/tink) to generate a unique Data Encryption Key (DEK) for the file.
2. Encrypt the file content according to the [encrypted file
   structure](https://developers.google.com/workspace/cse/guides/handle-cse-files#encrypted-file-structure).

### Compute Resource Key Hash

To compute the resource key hash:

1. Extract the `resource_name` and `perimeter_id` from the `jwt` authorization token received from `generateCseToken`. If `perimeter_id` is missing, use an empty string.
2. Calculate HMAC-SHA256 using the plaintext DEK as the key and the string `ResourceKeyDigest:my_resource_name:my_perimeter_id` as the data to sign.
3. Base64-encode the resulting hash.

For more details, see [Resource Key
Hash](https://developers.google.com/workspace/cse/reference/resource-key-hash).

### Wrap the encryption key

To protect the DEK, encrypt (wrap) it using your external KACLS.

1. Call the appropriate endpoint:
   - **Individual:** [`/wrap`](https://developers.google.com/workspace/cse/reference/wrap)
   - **Administrator:** [`/privilegedwrap`](https://developers.google.com/workspace/cse/reference/privileged-wrap)
2. Pass the plaintext DEK, your IdP authentication token, the Google authorization token (if required), the `resource_name` from the JWT, and a `reason`.
3. Receive the Wrapped DEK (WDEK) from the KACLS.

### Upload to Drive

Use the Drive API
[`files.create`](https://developers.google.com/drive/api/reference/rest/v3/files/create) endpoint to perform
a standard [file upload](https://developers.google.com/drive/api/guides/manage-uploads#file-content) of the
encrypted file blob. Set the following fields in the file metadata:

- `id`: The unique file ID received from the `generateCseToken` response.
- `mimeType`: `application/vnd.google-gsuite.encrypted; content="application/octet-stream"`.
  - The `content` parameter can be set to the original file's MIME type.
- [`clientEncryptionDetails`](https://developers.google.com/drive/api/reference/rest/v3/files#File.clientEncryptionDetails):
  - `encryptionState`: `"encrypted"`.
  - [`decryptionMetadata`](https://developers.google.com/drive/api/reference/rest/v3/files#File.DecryptionMetadata):
    - `wrappedKey`: The Wrapped DEK (WDEK) received from the KACLS.
    - `kaclsId`: The KACLS ID received from the `generateCseToken` response.
    - `keyFormat`: `"tinkAesGcmKey"`.
    - `aes256GcmChunkSize`: `"default"`.
    - `encryptionResourceKeyHash`: The hash computed in [Compute Resource
      Key Hash](https://developers.google.com/workspace/cse/guides/handle-cse-files#compute-resource-key-hash).

> [!NOTE]
> **Note:** Some fields require base64 encoding. See the Drive API [documentation](https://developers.google.com/drive/api/reference/rest/v3/files#File.DecryptionMetadata) for details

### Open source example

For a practical demonstration of the encrypt and upload process, refer to the
[open source demo](https://developers.google.com/workspace/cse/guides/handle-cse-files#open-source-demo). This provides a working solution and can
serve as a valuable reference.

## Download and decrypt a file

Downloading a CSE file requires retrieving the encrypted content and metadata
from Google Drive, requesting the plaintext DEK from your KACLS, and decrypting
the file locally.

### Retrieve file metadata and encrypted content

Call the Drive API
[`Files:get`](https://developers.google.com/drive/api/reference/rest/v3/files/get) method to retrieve the
file's metadata and content. The `clientEncryptionDetails` contains the
`DecryptionMetadata` which includes the Wrapped DEK (WDEK) and the JWT
containing the KACLS information.

### Unwrap the encryption key

1. Call the appropriate endpoint:
   - **Individual:** [`/unwrap`](https://developers.google.com/workspace/cse/reference/unwrap)
   - **Administrator:** [`/privilegedunwrap`](https://developers.google.com/workspace/cse/reference/privileged-unwrap)
2. Pass the WDEK, your IdP authentication token, the Google authorization token (if required), the `resource_name`, and a `reason`.
3. Receive the plaintext DEK from the KACLS.

### Decrypt data locally

1. Initialize the cipher using the plaintext DEK received from the KACLS.
2. Skip the initial magic bytes and decrypt the remaining content according to the [encrypted file structure](https://developers.google.com/workspace/cse/guides/handle-cse-files#encrypted-file-structure).

### Open source example

For a practical demonstration of the download and decrypt process, refer to the
[open source demo](https://developers.google.com/workspace/cse/guides/handle-cse-files#open-source-demo). This provides a working solution and can
serve as a valuable reference.

## Validate imported files

Because Google doesn't have access to the encryption keys, Google cannot decrypt
and validate your files server-side. Implementation errors during the local
encryption or key wrapping phases will result in errors when client-side
decrypting files. Thorough validation is critical before utilizing your own
implementation.

For uploaded Google Drive CSE content to function correctly, it must be
properly encrypted and contain the correct metadata. You are responsible for
ensuring that the content is valid and can be decrypted.

### Perform roundtrip encryption and decryption tests

To validate your implementation, it's crucial to test the end-to-end flow. This
involves taking a set of test files, encrypting them using your local logic,
uploading them to Drive using the API, and then downloading and
decrypting them. After decryption, compare the resulting content with the
original files to ensure they are identical. This process helps catch any issues
in the encryption, key wrapping, or metadata handling. The [open source
demo](https://developers.google.com/workspace/cse/guides/handle-cse-files#open-source-demo) demonstrates how you can implement such a validation
process within your own application.

### Spot-checking with Google Drive

Verify that the uploaded files include a lock icon in the Drive
web client. Manually download a small number of uploaded files to verify they
function as expected. This check uses Google's CSE implementation to attempt
decryption, helping to isolate issues in your encryption or key wrapping logic.
Include files from both **My Drive** and **Shared drives**.

> [!WARNING]
> **Warning:** Don't delete your original source files until you fully validate that the imported CSE versions are decryptable.

## Open source demo

The open source [Drive CSE
Upload](https://github.com/googleworkspace/drive-cse-upload/) package provides a
complete, working Python library and command-line example that implements the
CSE upload and download flows described in this guide. Reviewing the demo code
is highly recommended before building your own CSE integration.