Crea y valida firmas digitales

En este tema, se proporciona información sobre cómo crear y validar firmas digitales con base en claves asimétricas.

Una firma digital se crea usando la porción de la clave privada de una clave asimétrica. La firma se valida con la porción de la clave pública de la misma clave asimétrica.

Antes de comenzar

  • Cuando crees firmas digitales, debes usar una clave que tenga el propósito de clave de ASYMMETRIC_SIGN. Cuando crees la clave, usa ASYMMETRIC_SIGN.

  • Para validar una firma, necesitas conocer el algoritmo completo que se usó cuando creaste la clave. Para obtener instrucciones sobre la línea de comandos que está a continuación y que usa el comando openssl, debes pasar esta información a esos comandos.

  • Otorga el permiso cloudkms.cryptoKeyVersions.useToSign sobre la clave asimétrica al usuario o servicio que realizará la firma. Puedes obtener información sobre los permisos de Cloud Key Management Service en Permisos y funciones.

  • Si vas a validar una firma, otorga el permiso cloudkms.cryptoKeyVersions.viewPublicKey sobre la clave asimétrica al usuario o servicio que descargará la clave pública para usarla en la validación.

  • Si vas a usar la línea de comandos, asegúrate de tener instalado OpenSSL. Si usas Cloud Shell, OpenSSL ya está instalado.

Datos versus resumen

La entrada proporcionada para las solicitudes de AsymmetricSign se puede pasar a través del campo data o del campo digest. Estos campos no se pueden especificar al mismo tiempo. Hay algunos algoritmos que requieren el campo de datos, como los algoritmos sin procesar y la firma con una clave de Cloud External Key Manager.

Algoritmos sin procesar

Los algoritmos "sin procesar", identificados por el prefijo RSA_SIGN_RAW_, son una variante de la firma PKCS #1 que omite la codificación en un DigestInfo. En la variante:

  • Se calcula un resumen del mensaje que se firmará.
  • El padding PKCS #1 se aplica directamente al resumen.
  • Se calcula una firma del resumen con relleno, utilizando la clave privada RSA.

Para usar estos algoritmos, haz lo siguiente:

  • Los datos sin procesar deben proporcionarse (en lugar de un resumen) como parte del campo data.
  • Los datos tienen un límite de longitud de 11 bytes menos que el tamaño de la clave RSA. Por ejemplo, PKCS #1 con una clave RSA de 2,048 bits puede firmar como máximo 245 bytes.
  • Otorga el rol cloudkms.expertRawPKCS1 al usuario o servicio correspondiente. Puedes obtener información sobre los permisos en Cloud Key Management Service en Permisos y roles.

Con los algoritmos sin procesar, también puedes firmar un tipo de resumen para el que no hay un algoritmo predefinido disponible. Por ejemplo, puedes usar una clave RSA_SIGN_RAW_2048 para firmar una estructura SHA-512 PKCS #1 DigestInfo que ya calculaste de forma externa. Este proceso crea los mismos resultados que un algoritmo RSA_SIGN_PKCS1_2048_SHA512 estándar.

Compatibilidad con ECDSA para otros algoritmos de hash

Nuestros algoritmos de firma ECDSA tienen el siguiente formato general:

EC_SIGN_ELLIPTIC_CURVE_[DIGEST_ALGORITHM]

DIGEST_ALGORITHM tiene el valor SHA256, SHA384 o SHA512. Dado que el hash se realiza antes de que crees la firma, estos algoritmos de firma también se pueden usar con resúmenes distintos de SHA, como Keccak. Para usar un resumen de Keccak, proporciona un valor hash de Keccak y usa el algoritmo de resumen SHA con la misma longitud. Por ejemplo, puedes usar un resumen KECCAK256 en una solicitud con el algoritmo EC_SIGN_P256_SHA256.

Crea una firma

gcloud

Para usar Cloud KMS en la línea de comandos, primero instala o actualiza a la versión más reciente de Google Cloud CLI.

gcloud kms asymmetric-sign \
    --version key-version \
    --key key \
    --keyring key-ring \
    --location location \
    --digest-algorithm digest-algorithm \
    --input-file input-file \
    --signature-file signature-file

Reemplaza key-version por la versión de la clave que se usará para la firma. Reemplaza key por el nombre de la clave. Reemplaza key-ring por el nombre del llavero de claves en el que se encuentra la clave. Reemplaza location por la ubicación de Cloud KMS del llavero de claves. Reemplaza digest-algorithm por el algoritmo que se usará. Omite digest-algorithm para enviar input-file a Cloud KMS para que lo firme. Reemplaza input-file y signature-file por las rutas locales para el archivo que se firmará y el archivo de firma.

Para obtener información sobre todas las marcas y los valores posibles, ejecuta el comando con la marca --help.

C#

Para ejecutar este código, primero configura un entorno de desarrollo de C# e instala el SDK de C# para Cloud KMS.


using Google.Cloud.Kms.V1;
using Google.Protobuf;
using System.Security.Cryptography;
using System.Text;

public class SignAsymmetricSample
{
    public byte[] SignAsymmetric(
      string projectId = "my-project", string locationId = "us-east1", string keyRingId = "my-key-ring", string keyId = "my-key", string keyVersionId = "123",
      string message = "Sample message")
    {
        // Create the client.
        KeyManagementServiceClient client = KeyManagementServiceClient.Create();

        // Build the key version name.
        CryptoKeyVersionName keyVersionName = new CryptoKeyVersionName(projectId, locationId, keyRingId, keyId, keyVersionId);

        // Convert the message into bytes. Cryptographic plaintexts and
        // ciphertexts are always byte arrays.
        byte[] plaintext = Encoding.UTF8.GetBytes(message);

        // Calculate the digest.
        SHA256 sha256 = SHA256.Create();
        byte[] hash = sha256.ComputeHash(plaintext);

        // Build the digest.
        //
        // Note: Key algorithms will require a varying hash function. For
        // example, EC_SIGN_P384_SHA384 requires SHA-384.
        Digest digest = new Digest
        {
            Sha256 = ByteString.CopyFrom(hash),
        };

        // Call the API.
        AsymmetricSignResponse result = client.AsymmetricSign(keyVersionName, digest);

        // Get the signature.
        byte[] signature = result.Signature.ToByteArray();

        // Return the result.
        return signature;
    }
}

Go

Para ejecutar este código, primero configura un entorno de desarrollo de Go y, luego, instala el SDK de Go para Cloud KMS.

import (
	"context"
	"crypto/sha256"
	"fmt"
	"hash/crc32"
	"io"

	kms "cloud.google.com/go/kms/apiv1"
	"cloud.google.com/go/kms/apiv1/kmspb"
	"google.golang.org/protobuf/types/known/wrapperspb"
)

// signAsymmetric will sign a plaintext message using a saved asymmetric private
// key stored in Cloud KMS.
func signAsymmetric(w io.Writer, name string, message string) error {
	// name := "projects/my-project/locations/us-east1/keyRings/my-key-ring/cryptoKeys/my-key/cryptoKeyVersions/123"
	// message := "my message"

	// Create the client.
	ctx := context.Background()
	client, err := kms.NewKeyManagementClient(ctx)
	if err != nil {
		return fmt.Errorf("failed to create kms client: %w", err)
	}
	defer client.Close()

	// Convert the message into bytes. Cryptographic plaintexts and
	// ciphertexts are always byte arrays.
	plaintext := []byte(message)

	// Calculate the digest of the message.
	digest := sha256.New()
	if _, err := digest.Write(plaintext); err != nil {
		return fmt.Errorf("failed to create digest: %w", err)
	}

	// Optional but recommended: Compute digest's CRC32C.
	crc32c := func(data []byte) uint32 {
		t