Como criptografar e descriptografar dados com uma chave simétrica

Neste tópico, você verá como realizar as seguintes operações de chave simétrica:

  • Usar uma chave do Cloud Key Management Service para criptografar texto ou conteúdo binário (texto simples).
  • Descriptografar texto cifrado que foi criptografado com uma chave do Cloud KMS.

Se você quiser usar uma chave assimétrica para criptografia, consulte Como criptografar e descriptografar dados com uma chave assimétrica.

Antes de começar

  1. Crie um keyring e uma chave, conforme descrito em Como criar keyrings e chaves.

  2. Verifique se o usuário que está chamando os métodos de criptografia e descriptografia tem as permissões cloudkms.cryptoKeyVersions.useToEncrypt e cloudkms.cryptoKeyVersions.useToDecrypt na chave usada para criptografar ou descriptografar.

    Uma maneira de permitir que alguém criptografe ou descriptografe é adicionar o usuário aos papéis roles/cloudkms.cryptoKeyEncrypter, roles/cloudkms.cryptoKeyDecrypter ou roles/cloudkms.cryptoKeyEncrypterDecrypter do Cloud Identity and Access Management dessa chave. Para mais informações, consulte Permissões e papéis.

  3. Opcional: se você for usar a biblioteca de cliente para o Cloud KMS, instale-a no idioma de sua preferência.

  4. Opcional: se você for usar a ferramenta de linha de comando gcloud, instale o SDK do Cloud.

Criptografar

Linha de comando

Para criptografar dados, forneça as informações de chave apropriadas, especifique o nome do arquivo de texto simples que será criptografado e o nome do arquivo com o conteúdo criptografado. Por convenção, esses exemplos anexam .enc ao arquivo criptografado.

O arquivo de texto simples que será criptografado não pode ser maior que 64 KiB (65.536 bytes).

gcloud kms encrypt \
  --location=location  \
  --keyring=keyring-name \
  --key=key-name \
  --plaintext-file=filepath-and-file-to-encrypt \
  --ciphertext-file=encrypted-filepath-and-file.enc

Por exemplo, se text.txt for o nome do arquivo de texto simples a ser criptografado:

gcloud kms encrypt \
  --location global \
  --keyring my_keyring \
  --key my_key \
  --plaintext-file text.txt \
  --ciphertext-file text.enc

O comando encrypt é compatível com uma sinalização --additional-authenticated-data- file opcional, que é usada para especificar um arquivo que contém dados autenticados adicionais. O arquivo de dados autenticados adicionais não pode ser maior que 64 KiB (65.536 bytes).

Se --plaintext-file ou --additional-authenticated-data-file for definido como -, essa informação será lida a partir de stdin. Da mesma maneira, se --ciphertext-file estiver definido como -, o texto criptografado será gravado em stdout. Ao usar a entrada padrão, quaisquer caracteres de espaço em branco fornecidos (por exemplo, novas linhas produzidas por echo ou outros comandos da shell) serão incluídos no texto criptografado.

O comando encrypt é compatível com uma sinalização --version opcional, que é usada para indicar a versão da chave a ser usada na criptografia. Por padrão, é usada a versão principal.

O exemplo de encrypt a seguir mostra como especificar uma chave de versão e dados autenticados adicionais.

gcloud kms encrypt \
  --location=location  \
  --keyring=keyring-name \
  --key=key-name \
  --version=key-version \
  --additional-authenticated-data-file=aad-file-path-and-name \
  --plaintext-file=filepath-and-file-to-encrypt \
  --ciphertext-file=encrypted-filepath-and-file.enc

Protocolo

Ao usar o JSON e a API REST, o conteúdo precisa ser codificado em Base64 antes de ser criptografado pelo Cloud KMS.

Para criptografar dados, faça uma solicitação POST e forneça as informações apropriadas do projeto e da chave. Além disso, especifique o texto codificado em base64 a ser criptografado no campo plaintext do corpo da solicitação. Substitua API_KEY por uma chave de API válida. Para mais informações sobre como gerar uma chave de API, consulte Como acessar a API.

POST https://cloudkms.googleapis.com/v1/projects/project-id/locations/locationkeyRings/keyring-name/cryptoKeys/key-name:encrypt&key=api-key
{
  "plaintext": "U3VwZXIgc2VjcmV0IHRleHQgdGhhdCBtdXN0IGJlIGVuY3J5cHRlZAo=",
}

Este exemplo usa curl:

curl -s -X POST "https://cloudkms.googleapis.com/v1/projects/project-id/locations/location/keyRings/keyring-name/cryptoKeys/key-name:encrypt" \
  -d "{\"plaintext\":\"base64-encoded-input\"}" \
  -H "Authorization:Bearer api-key"\
  -H "Content-Type:application/json"

C#

        public static void Encrypt(string projectId, string locationId, string keyRingId, string cryptoKeyId,
string plaintextFile, string ciphertextFile)
        {
            KeyManagementServiceClient client = KeyManagementServiceClient.Create();
            CryptoKeyName cryptoKeyName =
                new CryptoKeyName(projectId, locationId, keyRingId, cryptoKeyId);

            byte[] plaintext = File.ReadAllBytes(plaintextFile);
            CryptoKeyPathName pathName = CryptoKeyPathName.Parse(cryptoKeyName.ToString());
            EncryptResponse result = client.Encrypt(pathName, ByteString.CopyFrom(plaintext));

            // Output encrypted data to a file.
            File.WriteAllBytes(ciphertextFile, result.Ciphertext.ToByteArray());
            Console.Write($"Encrypted file created: {ciphertextFile}");
        }

Java


/**
 * Encrypts the given plaintext using the specified crypto key.
 */
public static byte[] encrypt(
    String projectId, String locationId, String keyRingId, String cryptoKeyId, byte[] plaintext)
    throws IOException {

  // Create the KeyManagementServiceClient using try-with-resources to manage client cleanup.
  try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) {

    // The resource name of the cryptoKey
    String resourceName = CryptoKeyName.format(projectId, locationId, keyRingId, cryptoKeyId);

    // Encrypt the plaintext with Cloud KMS.
    EncryptResponse response = client.encrypt(resourceName, ByteString.copyFrom(plaintext));

    // Extract the ciphertext from the response.
    return response.getCiphertext().toByteArray();
  }
}

Node.js

async function encrypt(
  projectId = 'your-project-id', // Your GCP projectId
  keyRingId = 'my-key-ring', // Name of the crypto key's key ring
  cryptoKeyId = 'my-key', // Name of the crypto key, e.g. "my-key"
  plaintextFileName = './path/to/plaintext.txt',
  ciphertextFileName = './path/to/plaintext.txt.encrypted'
) {
  const fs = require('fs');
  const {promisify} = require('util');

  // Import the library and create a client
  const kms = require('@google-cloud/kms');
  const client = new kms.KeyManagementServiceClient();

  // The location of the crypto key's key ring, e.g. "global"
  const locationId = 'global';

  // Reads the file to be encrypted
  const readFile = promisify(fs.readFile);
  const plaintext = await readFile(plaintextFileName);
  const name = client.cryptoKeyPath(
    projectId,
    locationId,
    keyRingId,
    cryptoKeyId
  );

  // Encrypts the file using the specified crypto key
  const [result] = await client.encrypt({name, plaintext});
  const writeFile = promisify(fs.writeFile);
  await writeFile(ciphertextFileName, result.ciphertext);
  console.log(`Encrypted ${plaintextFileName} using ${result.name}.`);
  console.log(`Result saved to ${ciphertextFileName}.`);
}

PHP

use Google\Cloud\Kms\V1\KeyManagementServiceClient;

/** Uncomment and populate these variables in your code */
// $projectId = 'The Google project ID';
// $locationId = 'The location ID of the crypto key. Can be "global", "us-west1", etc.';
// $keyRingId = 'The KMS key ring ID';
// $cryptoKeyId = 'The KMS key ID';
// $plaintextFileName = 'The path to the file containing plaintext to encrypt';
// $ciphertextFileName = 'The path to write the ciphertext';

$kms = new KeyManagementServiceClient();

// The resource name of the CryptoKey.
$cryptoKeyName = $kms->cryptoKeyName($projectId, $locationId, $keyRingId, $cryptoKeyId);

$plaintext = file_get_contents($plaintextFileName);
$response = $kms->encrypt($cryptoKeyName, $plaintext);

// Write the encrypted text to a file.
file_put_contents($ciphertextFileName, $response->getCiphertext());
printf('Saved encrypted text to %s' . PHP_EOL, $ciphertextFileName);

Python

def encrypt_symmetric(project_id, location_id, key_ring_id, crypto_key_id,
                      plaintext):
    """Encrypts input plaintext data using the provided symmetric CryptoKey."""

    from google.cloud import kms_v1

    # Creates an API client for the KMS API.
    client = kms_v1.KeyManagementServiceClient()

    # The resource name of the CryptoKey.
    name = client.crypto_key_path_path(project_id, location_id, key_ring_id,
                                       crypto_key_id)

    # Use the KMS API to encrypt the data.
    response = client.encrypt(name, plaintext)
    return response.ciphertext

Ruby

# project_id      = "Your Google Cloud project ID"
# location_id     = "The location of the key ring"
# key_ring_id     = "The ID of the key ring"
# crypto_key_id   = "The ID of the crypto key"
# plaintext_file  = "File to encrypt"
# ciphertext_file = "File to store encrypted input data"

require "google/cloud/kms/v1"
CloudKMS = Google::Cloud::Kms::V1

# Initialize the client
client = CloudKMS::KeyManagementServiceClient.new

# The crypto key to use
crypto_key = CloudKMS::KeyManagementServiceClient.crypto_key_path(
  project_id, location_id, key_ring_id, crypto_key_id
)

# Read the secret data from the file
plaintext = File.open(plaintext_file, "rb", &:read)

# Use the KMS API to encrypt the data
response = client.encrypt crypto_key, plaintext

# Write the encrypted binary data to the output file
File.open(ciphertext_file, "wb") { |f| f.write response.ciphertext }

puts "Saved encrypted #{plaintext_file} as #{ciphertext_file}"

Descriptografia

Linha de comando

Para descriptografar dados, forneça as informações de chave apropriadas, especifique o nome do arquivo a ser descriptografado e especifique o nome do arquivo com o conteúdo descriptografado.

gcloud kms decrypt \
  --location=location  \
  --keyring=keyring-name \
  --key=key-name \
  --ciphertext-file=filepath-and-file-to-decrypt \
  --plaintext-file=decrypted-filepath-and-file.dec

Por exemplo, se text.enc for o nome do arquivo de texto criptografado a descriptografar:

gcloud kms decrypt \
  --location=global \
  --keyring=my_keyring \
  --key=my_key \
  --ciphertext-file=text.enc \
  --plaintext-file=text.dec

O comando decrypt é compatível com uma sinalização --additional-authenticated-data- file opcional para especificar um arquivo que contenha dados autenticados adicionais. O arquivo de dados autenticados adicionais não pode ultrapassar 64 KiB.

Se --ciphertext-file ou --additional-authenticated-data-file estiver definido como -, esse arquivo será lido de stdin. Da mesma forma, se --plaintext-file estiver definido como -, o texto simples descriptografado será gravado em stdout. Ao usar a entrada padrão, observe que quaisquer caracteres de espaço em branco fornecidos (por exemplo, novas linhas produzidas por echo ou outros comandos de shell) serão incluídos na tentativa de descriptografia.

O exemplo de decrypt a seguir mostra como especificar dados autenticados adicionais.

gcloud kms decrypt \
  --location=location \
  --keyring=keyring-name \
  --key=key-name \
  --additional-authenticated-data-file=aad-file-path-and-name \
  --ciphertext-file=text.enc \
  --plaintext-file=text.dec

Protocolo

O texto descriptografado retornado do Cloud KMS para o JSON é codificado em Base64.

Para descriptografar dados criptografados, crie uma solicitação POST e forneça as informações apropriadas do projeto e da chave. Além disso, especifique o texto criptografado a ser descriptografado no campo ciphertext da solicitação. Substitua API_KEY por uma chave de API válida. Para mais informações sobre como gerar uma chave de API, consulte Como acessar a API.

POST https://cloudkms.googleapis.com/v1/projects/project-id/locations/location/keyRings/keyring-name/cryptoKeys/key-name:decrypt&key=api-key
{
  "ciphertext": "CiQAhMwwBo61cHas7dDgifrUFs5zNzBJ2uZtVFq4ZPEl6fUVT4kSmQ...",
}

Este exemplo usa curl:

curl -s -X POST "https://cloudkms.googleapis.com/v1/projects/project-id/locations/location/keyRings/keyring-name/cryptoKeys/key-name:decrypt" \
  -d "{\"ciphertext\":\"encrypted-content\"}" \
  -H "Authorization:Bearer api-key"\
  -H "Content-Type:application/json"

C#

        public static void Decrypt(string projectId, string locationId, string keyRingId, string cryptoKeyId,
    string ciphertextFile, string plaintextFile)
        {
            KeyManagementServiceClient client = KeyManagementServiceClient.Create();
            CryptoKeyName cryptoKeyName =
                new CryptoKeyName(projectId, locationId, keyRingId, cryptoKeyId);

            byte[] ciphertext = File.ReadAllBytes(ciphertextFile);
            DecryptResponse result = client.Decrypt(cryptoKeyName, ByteString.CopyFrom(ciphertext));

            // Output decrypted data to a file.
            File.WriteAllBytes(plaintextFile, result.Plaintext.ToByteArray());
            Console.Write($"Decrypted file created: {plaintextFile}");
        }

Go

import (
	"context"
	"fmt"

	cloudkms "cloud.google.com/go/kms/apiv1"
	kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1"
)

// decryptSymmetric will decrypt the input ciphertext bytes using the specified symmetric key.
func decryptSymmetric(name string, ciphertext []byte) ([]byte, error) {
	// name := "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys/KEY_ID"
	// cipherBytes, err := encryptRSA(rsaDecryptPath, []byte("Sample message"))
	// if err != nil {
	//   return nil, fmt.Errorf("encryptRSA: %v", err)
	// }
	// ciphertext := base64.StdEncoding.EncodeToString(cipherBytes)
	ctx := context.Background()
	client, err := cloudkms.NewKeyManagementClient(ctx)
	if err != nil {
		return nil, fmt.Errorf("cloudkms.NewKeyManagementClient: %v", err)
	}

	// Build the request.
	req := &kmspb.DecryptRequest{
		Name:       name,
		Ciphertext: ciphertext,
	}
	// Call the API.
	resp, err := client.Decrypt(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("Decrypt: %v", err)
	}
	return resp.Plaintext, nil
}

Java


/**
 * Decrypts the provided ciphertext with the specified crypto key.
 */
public static byte[] decrypt(
    String projectId, String locationId, String keyRingId, String cryptoKeyId, byte[] ciphertext)
    throws IOException {

  // Create the KeyManagementServiceClient using try-with-resources to manage client cleanup.
  try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) {

    // The resource name of the cryptoKey
    String resourceName = CryptoKeyName.format(projectId, locationId, keyRingId, cryptoKeyId);

    // Decrypt the ciphertext with Cloud KMS.
    DecryptResponse response = client.decrypt(resourceName, ByteString.copyFrom(ciphertext));

    // Extract the plaintext from the response.
    return response.getPlaintext().toByteArray();
  }
}

Node.js

async function decrypt(
  projectId = 'your-project-id', // Your GCP projectId
  keyRingId = 'my-key-ring', // Name of the crypto key's key ring
  cryptoKeyId = 'my-key', // Name of the crypto key, e.g. "my-key"
  ciphertextFileName = './path/to/plaintext.txt.encrypted',
  plaintextFileName = './path/to/plaintext.txt.decrypted'
) {
  const fs = require('fs');
  const {promisify} = require('util');

  // Import the library and create a client
  const kms = require('@google-cloud/kms');
  const client = new kms.KeyManagementServiceClient();

  // The location of the crypto key's key ring, e.g. "global"
  const locationId = 'global';

  // Reads the file to be decrypted
  const readFile = promisify(fs.readFile);
  const ciphertext = await readFile(ciphertextFileName);
  const name = client.cryptoKeyPath(
    projectId,
    locationId,
    keyRingId,
    cryptoKeyId
  );

  // Decrypts the file using the specified crypto key
  const [result] = await client.decrypt({name, ciphertext});

  // Writes the decrypted file to disk
  const writeFile = promisify(fs.writeFile);
  await writeFile(plaintextFileName, result.plaintext);
  console.log(
    `Decrypted ${ciphertextFileName}, result saved to ${plaintextFileName}.`
  );
}

PHP

use Google\Cloud\Kms\V1\KeyManagementServiceClient;
use Google\Cloud\Kms\V1\CryptoKey;

/** Uncomment and populate these variables in your code */
// $projectId = 'The Google project ID';
// $locationId = 'The location ID of the crypto key. Can be "global", "us-west1", etc.';
// $keyRingId = 'The KMS key ring ID';
// $cryptoKeyId = 'The KMS key ID';
// $ciphertextFileName = 'The path to the file containing ciphertext to decrypt';
// $plaintextFileName = 'The path to write the plaintext';

$kms = new KeyManagementServiceClient();

// The resource name of the CryptoKey.
$cryptoKey = new CryptoKey();
$cryptoKeyName = $kms->cryptoKeyName($projectId, $locationId, $keyRingId, $cryptoKeyId);

$ciphertext = file_get_contents($ciphertextFileName);
$response = $kms->decrypt($cryptoKeyName, $ciphertext);

// Write the encrypted text to a file.
file_put_contents($plaintextFileName, $response->getPlaintext());
printf('Saved decrypted text to %s' . PHP_EOL, $plaintextFileName);

Python

def decrypt_symmetric(project_id, location_id, key_ring_id, crypto_key_id,
                      ciphertext):
    """Decrypts input ciphertext using the provided symmetric CryptoKey."""

    from google.cloud import kms_v1

    # Creates an API client for the KMS API.
    client = kms_v1.KeyManagementServiceClient()

    # The resource name of the CryptoKey.
    name = client.crypto_key_path_path(project_id, location_id, key_ring_id,
                                       crypto_key_id)
    # Use the KMS API to decrypt the data.
    response = client.decrypt(name, ciphertext)
    return response.plaintext

Ruby

# project_id    = "Your Google Cloud project ID"
# location_id   = "The location of the key ring"
# key_ring_id   = "The ID of the key ring"
# crypto_key_id = "The ID of the crypto key"
# ciphertext_file = "File to decrypt"
# plaintext_file  = "File to store decrypted data"

require "google/cloud/kms/v1"
CloudKMS = Google::Cloud::Kms::V1

# Initialize the client
client = CloudKMS::KeyManagementServiceClient.new

# The crypto key to use
crypto_key = CloudKMS::KeyManagementServiceClient.crypto_key_path(
  project_id, location_id, key_ring_id, crypto_key_id
)

# Read the encrypted data from the file
ciphertext = File.open(ciphertext_file, "rb", &:read)

# Use the KMS API to decrypt the data
response = client.decrypt crypto_key, ciphertext

# Write the decrypted text to the output file
File.open(plaintext_file, "wb") { |f| f.write response.plaintext }

puts "Saved decrypted #{ciphertext_file} as #{plaintext_file}"

A seguir