Encripta y desencripta datos con una clave asimétrica

En este tema se describe cómo crear y usar una clave para la encriptación asimétrica con una clave de RSA. Consulta Crear y validar firmas digitales, si deseas usar claves asimétricas para crear y validar firmas. Además, consulta Encriptación y desencriptación de datos si quieres usar claves asimétricas para estas operaciones.

En la encriptación asimétrica, se usa la porción de clave pública de la clave asimétrica, mientras que en la desencriptación se usa la porción de clave privada. Cloud KMS ofrece la función de recuperar la clave pública, además de desencriptar el cifrado que se encriptó con esta. Cloud KMS no permite el acceso directo a la clave privada.

Antes de comenzar

Control de acceso a la clave

  • Para un usuario o servicio que recuperará la clave pública, otorga el permiso cloudkms.cryptoKeyVersions.viewPublicKey en la clave asimétrica. Se necesita la clave pública para encriptar los datos.

  • Para un usuario o servicio que desencriptará datos que se encriptaron con la clave pública, otorga el permiso cloudkms.cryptoKeyVersions.useToDecrypt en la clave asimétrica.

Para conocer más sobre los permisos y funciones en Cloud KMS, sigue este vínculo.

Encriptar datos

Si no tienes la clave pública, recupérala.

Línea de comandos

En este ejemplo, se supone que la clave pública se encuentra en un archivo llamado rsa-decrypt-key.pub.

  1. Haz clic en el botón Activar Cloud Shell en la parte superior de la ventana de la consola. Activar Cloud Shell Se abrirá una sesión de Cloud Shell en un marco nuevo en la parte inferior de la consola, que mostrará una línea de comandos. La sesión del shell puede tardar unos segundos en inicializarse. Sesión de Cloud Shell

  2. Crea un archivo de texto sin formato en la ventana emergente de la línea de comandos de Cloud Shell.

    echo "my secret message" > ~/my-secret-file
    
  3. Encripta el archivo con OpenSSL. En el ejemplo, se usa el resumen SHA-256. Actualmente todos los algoritmos de encriptación asimétrica usan este resumen.

    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


// encryptRSA will 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"
func encryptRSA(keyName string, plaintext []byte) ([]byte, error) {
	ctx := context.Background()
	client, err := cloudkms.NewKeyManagementClient(ctx)
	if err != nil {
		return nil, err
	}

	// Retrieve the public key from KMS.
	response, err := client.GetPublicKey(ctx, &kmspb.GetPublicKeyRequest{Name: keyName})
	if err != nil {
		return nil, fmt.Errorf("failed to fetch public key: %+v", err)
	}
	// Parse the key.
	block, _ := pem.Decode([]byte(response.Pem))
	abstractKey, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, fmt.Errorf("failed to parse public key: %+v", err)
	}
	rsaKey, ok := abstractKey.(*rsa.PublicKey)
	if !ok {
		return nil, fmt.Errorf("key '%s' is not RSA", keyName)
	}
	// 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("encryption failed: %+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)

Desencripta datos

Desencripta los datos con Cloud KMS.

Línea de comandos

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

Permite mostrar el contenido del archivo desencriptado.

cat ~/my-secret-file.dec

Debes ver el mismo texto que creaste para tu archivo de texto sin formato.

my secret message

API

Usa el método CryptoKeyVersions.asymmetricDecrypt.

  • Configura el valor de ciphertext de la solicitud en función del cifrado que se creó cuando encriptaste el texto sin formato.

La respuesta CryptoKeyVersions.asymmetricDecrypt contiene los datos desencriptados.

Go


// decryptRSA will attempt to decrypt a given ciphertext with 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"
func decryptRSA(keyName string, ciphertext []byte) ([]byte, error) {
	ctx := context.Background()
	client, err := cloudkms.NewKeyManagementClient(ctx)
	if err != nil {
		return nil, err
	}

	// Build the request.
	req := &kmspb.AsymmetricDecryptRequest{
		Name:       keyName,
		Ciphertext: ciphertext,
	}
	// Call the API.
	response, err := client.AsymmetricDecrypt(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("decryption request failed: %+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

¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...