Como criptografar e descriptografar dados com uma chave assimétrica

Neste tópico, apresentamos informações sobre como criar e usar uma chave para criptografia assimétrica usando uma chave RSA. Para usar chaves assimétricas a fim de criar e validar assinaturas, consulte Como criar e validar assinaturas digitais. Para usar chaves simétricas na criptografia e descriptografia, consulte Como criptografar e descriptografar dados.

A criptografia assimétrica usa a parte da chave pública da chave assimétrica, e a descriptografia usa a parte da chave privada. O Cloud KMS oferece funcionalidade para recuperar a chave pública e descriptografar o texto criptografado com ela. O Cloud KMS não permite acesso direto à chave privada.

Antes de começar

Controle de acesso à chave

  • Para um usuário ou serviço que recuperará a chave pública, conceda a permissão cloudkms.cryptoKeyVersions.viewPublicKey na chave assimétrica. A chave pública é necessária para criptografar dados.

  • Para um usuário ou serviço que descriptografará dados criptografados com a chave pública, conceda a permissão cloudkms.cryptoKeyVersions.useToDecrypt na chave assimétrica.

Saiba mais sobre permissões e papéis no Cloud KMS em Permissões e papéis.

Criptografar dados

Se você ainda não tem a chave pública, recupere-a.

Linha de comando

Neste exemplo, consideramos que a chave pública esteja em um arquivo chamado rsa-decrypt-key.pub.

  1. Clique no botão Ativar o Cloud Shell na parte superior da janela do console. Ativar o Cloud Shell Uma sessão do Cloud Shell é aberta em um novo frame na parte inferior do console, e um prompt de linha de comando é exibido. A inicialização da sessão do shell pode levar alguns segundos. Sessão do Cloud Shell

  2. No prompt de linha de comando do Cloud Shell, crie um arquivo de texto simples.

    echo "my secret message" > ~/my-secret-file
    
  3. Use o OpenSSL para criptografar o arquivo. No exemplo, usamos o resumo SHA-256. Atualmente, todos os algoritmos de criptografia assimétrica usam o resumo SHA-256.

    openssl pkeyutl -in ~/my-secret-file \
      -encrypt -pubin \
      -inkey ~/rsa-decrypt-key.pub \
      -pkeyopt rsa_padding_mode:oaep \
      -pkeyopt rsa_oaep_md:sha256 \
      -pkeyopt rsa_mgf1_md:sha256 > ~/my-secret-file.enc
    

Go

import (
	"context"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/pem"
	"fmt"

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

// encryptRSA will encrypt data locally using an 'RSA_DECRYPT_OAEP_2048_SHA256'
// public key retrieved from Cloud KMS.
func encryptRSA(name string, plaintext []byte) ([]byte, error) {
	// name: "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys/KEY_ID/cryptoKeyVersions/1"
	// plaintext := []byte("Sample message")
	ctx := context.Background()
	client, err := cloudkms.NewKeyManagementClient(ctx)
	if err != nil {
		return nil, fmt.Errorf("cloudkms.NewKeyManagementClient: %v", err)
	}

	// Retrieve the public key from KMS.
	response, err := client.GetPublicKey(ctx, &kmspb.GetPublicKeyRequest{Name: name})
	if err != nil {
		return nil, fmt.Errorf("GetPublicKey: %v", err)
	}
	// Parse the key.
	block, _ := pem.Decode([]byte(response.Pem))
	abstractKey, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, fmt.Errorf("x509.ParsePKIXPublicKey: %+v", err)
	}
	rsaKey, ok := abstractKey.(*rsa.PublicKey)
	if !ok {
		return nil, fmt.Errorf("key %q is not RSA", name)
	}
	// Encrypt data using the RSA public key.
	ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, rsaKey, plaintext, nil)
	if err != nil {
		return nil, fmt.Errorf("rsa.EncryptOAEP: %v", err)
	}
	return ciphertext, nil
}

Java

/**
 * Encrypt data locally using an 'RSA_DECRYPT_OAEP_2048_SHA256' public key
 * retrieved from Cloud KMS
 *
 * Example keyName:
 *   "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys/KEY_ID/cryptoKeyVersions/1"
 */
public static byte[] encryptRSA(String keyName, byte[] plaintext)
    throws IOException, GeneralSecurityException {
  // Create the Cloud KMS client.
  try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) {
    // Get the public key
    com.google.cloud.kms.v1.PublicKey pub = client.getPublicKey(keyName);
    String pemKey = pub.getPem();
    pemKey = pemKey.replaceFirst("-----BEGIN PUBLIC KEY-----", "");
    pemKey = pemKey.replaceFirst("-----END PUBLIC KEY-----", "");
    pemKey = pemKey.replaceAll("\\s", "");
    byte[] derKey = BaseEncoding.base64().decode(pemKey);
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(derKey);
    PublicKey rsaKey = KeyFactory.getInstance("RSA").generatePublic(keySpec);

    // Encrypt plaintext for the 'RSA_DECRYPT_OAEP_2048_SHA256' key.
    // For other key algorithms:
    // https://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html
    Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
    OAEPParameterSpec oaepParams = new OAEPParameterSpec(
        "SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);
    cipher.init(Cipher.ENCRYPT_MODE, rsaKey, oaepParams);

    return cipher.doFinal(plaintext);
  }
}

Python

def encrypt_rsa(plaintext, key_name):
    """
    Encrypt the input plaintext (bytes) locally using an
    'RSA_DECRYPT_OAEP_2048_SHA256' public key retrieved from Cloud KMS

    Example key_name:
      "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\
              /KEY_ID/cryptoKeyVersions/1"

    Requires:
      cryptography.hazmat.primitives.asymmetric.padding
      cryptography.hazmat.primitives.hashes
    """
    # get the public key
    client = kms_v1.KeyManagementServiceClient()
    response = client.get_public_key(key_name)
    key_txt = response.pem.encode('ascii')
    public_key = serialization.load_pem_public_key(key_txt, default_backend())

    # encrypt plaintext
    pad = padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),
                       algorithm=hashes.SHA256(),
                       label=None)
    return public_key.encrypt(plaintext, pad)

Descriptografar dados

Use o Cloud KMS para executar a descriptografia.

Linha de comando

gcloud kms asymmetric-decrypt \
  --location [LOCATION] \
  --keyring [KEYRING_NAME] \
  --key [KEY_NAME] \
  --version [KEY_VERSION] \
  --ciphertext-file ~/my-secret-file.enc \
  --plaintext-file ~/my-secret-file.dec

Exiba o conteúdo do arquivo descriptografado.

cat ~/my-secret-file.dec

Você deve ver o mesmo texto que criou para o arquivo de texto simples.

my secret message

API

Use o método CryptoKeyVersions.asymmetricDecrypt.

  • Defina o valor de ciphertext da solicitação como o texto criptografado criado quando você criptografou o texto simples.

A resposta de CryptoKeyVersions.asymmetricDecrypt contém os dados descriptografados.

Go

import (
	"context"
	"fmt"

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

// decryptRSA will attempt to decrypt a given ciphertext with an
// 'RSA_DECRYPT_OAEP_2048_SHA256' private key stored on Cloud KMS.
func decryptRSA(name string, ciphertext []byte) ([]byte, error) {
	// name := "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys/KEY_ID/cryptoKeyVersions/1"
	// ciphertext, err := encryptRSA(rsaDecryptPath, []byte("Sample message"))
	// if err != nil {
	//   return nil, fmt.Errorf("encryptRSA: %v", err)
	// }
	ctx := context.Background()
	client, err := cloudkms.NewKeyManagementClient(ctx)
	if err != nil {
		return nil, fmt.Errorf("cloudkms.NewKeyManagementClient: %v", err)
	}

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

Java

/**
 * Decrypt a given ciphertext using an 'RSA_DECRYPT_OAEP_2048_SHA256' private key
 * stored on Cloud KMS
 *
 * Example keyName:
 *   "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys/KEY_ID/cryptoKeyVersions/1"
 */
public static byte[] decryptRSA(String keyName, byte[] ciphertext) throws IOException {
  // Create the Cloud KMS client.
  try (KeyManagementServiceClient client = KeyManagementServiceClient.create()) {
    AsymmetricDecryptResponse response = client.asymmetricDecrypt(
        keyName, ByteString.copyFrom(ciphertext));
    return response.getPlaintext().toByteArray();
  }
}

Python

def decrypt_rsa(ciphertext, key_name):
    """
    Decrypt the input ciphertext (bytes) using an
    'RSA_DECRYPT_OAEP_2048_SHA256' private key stored on Cloud KMS

    Example key_name:
      "projects/PROJECT_ID/locations/global/keyRings/RING_ID/cryptoKeys\
              /KEY_ID/cryptoKeyVersions/1"
    """

    client = kms_v1.KeyManagementServiceClient()
    response = client.asymmetric_decrypt(key_name, ciphertext)
    return response.plaintext