Créer et valider des signatures numériques

Cet article fournit des informations sur la création et la validation de signatures numériques basées sur des clés asymétriques.

Une signature numérique est créée à l'aide de la partie clé privée d'une clé asymétrique. Elle est validée à l'aide de la partie clé publique de cette même clé asymétrique.

Avant de commencer

  • Lorsque vous créez des signatures numériques, vous devez utiliser une clé dotée de l'objectif ASYMMETRIC_SIGN. Lorsque vous créez la clé , utilisez ASYMMETRIC_SIGN.

  • Pour valider une signature, vous devez connaître l'algorithme complet utilisé lors de la création de la clé. Pour les instructions de ligne de commande ci-dessous qui utilisent la commande openssl, vous devez transmettre ces informations à ces commandes.

  • Accordez l'autorisation cloudkms.cryptoKeyVersions.useToSign sur la clé asymétrique à l'utilisateur ou au service qui effectuera la signature. Pour en savoir plus sur les autorisations et les rôles dans Cloud Key Management Service, consultez la page Autorisations et rôles.

  • Si vous souhaitez valider une signature, accordez l'autorisation cloudkms.cryptoKeyVersions.viewPublicKey sur la clé asymétrique à l'utilisateur ou au service qui téléchargera la clé publique à utiliser pour la validation.

  • Si vous souhaitez utiliser la ligne de commande, installez OpenSSL si vous ne l'avez pas déjà. Si vous utilisez Cloud Shell, OpenSSL est déjà installé.

Données et condensé

L'entrée fournie pour les requêtes AsymmetricSign peut être transmise via le champ data ou le champ digest. Ces champs ne peuvent pas être spécifiés simultanément. Certains algorithmes nécessitent le champ de données, comme les algorithmes bruts et la signature avec une clé Cloud External Key Manager.

Algorithmes bruts

Les algorithmes "bruts", identifiés par le préfixe RSA_SIGN_RAW_, sont une variante de la signature PKCS #1 qui omet l'encodage dans un condensé DigestInfo. Dans la variante :

  • Un condensé est calculé sur le message qui sera signé.
  • Le remplissage PKCS #1 est appliqué directement au condensé.
  • Une signature du condensé complété est calculée à l'aide de la clé privée RSA.

Pour utiliser ces algorithmes, procédez comme suit :

  • Les données brutes doivent être fournies (au lieu d'un condensé) dans le champ data.
  • La longueur des données est limitée à 11 octets de la taille de la clé RSA. Par exemple, le format PKCS #1 avec une clé RSA de 2 048 bits peut signer au maximum 245 octets.
  • Attribuez le rôle cloudkms.expertRawPKCS1 à l'utilisateur ou au service approprié. Pour en savoir plus sur les autorisations et les rôles dans Cloud Key Management Service, consultez la page Autorisations et rôles.

En utilisant des algorithmes bruts, vous pouvez également signer un type de résumé pour lequel aucun algorithme prédéfini n'est disponible. Par exemple, vous pouvez utiliser une clé RSA_SIGN_RAW_2048 pour signer une structure DigestInfo PKCS #1 SHA-512 que vous avez déjà calculée en externe. Ce processus crée les mêmes résultats qu'un algorithme RSA_SIGN_PKCS1_2048_SHA512 standard.

Prise en charge d'ECDSA pour d'autres algorithmes de hachage

Nos algorithmes de signature ECDSA ont le format général suivant :

EC_SIGN_ELLIPTIC_CURVE_[DIGEST_ALGORITHM]

DIGEST_ALGORITHM a la valeur SHA256, SHA384 ou SHA512. Étant donné que le hachage est effectué avant la création de la signature, ces algorithmes de signature peuvent également être utilisés avec des résumés autres que SHA, tels que Keccak. Pour utiliser un condensé Keccak, fournissez une valeur de hachage Keccak et utilisez l'algorithme de condensé SHA de même longueur. Par exemple, vous pouvez utiliser un résumé KECCAK256 dans une requête avec l'algorithme EC_SIGN_P256_SHA256.

Créer une signature

gcloud

Pour utiliser Cloud KMS sur la ligne de commande, commencez par installer ou mettre à jour 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

Remplacez key-version par la version de la clé à utiliser pour la signature. Remplacez key par le nom de la clé. Remplacez key-ring par le nom du trousseau de clés où se trouve la clé. Remplacez location par l'emplacement Cloud KMS du trousseau de clés. Remplacez digest-algorithm par l'algorithme à utiliser. Omettez digest-algorithm pour envoyer input-file à Cloud KMS pour signature. Remplacez input-file et signature-file par les chemins d'accès locaux du fichier à signer et du fichier de signature.

Pour en savoir plus sur toutes les options et valeurs possibles, exécutez la commande avec l'option --help.

C#

Pour exécuter ce code, commencez par configurer un environnement de développement C#, puis installez le SDK Cloud KMS pour C#.


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

Pour exécuter ce code, commencez par configurer un environnement de développement Go, puis installez le SDK Cloud KMS pour Go.

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 := crc32.MakeTable(crc32.Castagnoli)
		return crc32.Checksum(data, t)

	}
	digestCRC32C := crc32c(digest.Sum(nil))

	// Build the signing request.
	//
	// Note: Key algorithms will require a varying hash function. For example,
	// EC_SIGN_P384_SHA384 requires SHA-384.
	req := &kmspb.AsymmetricSignRequest{
		Name: name,
		Digest: &kmspb.Digest{
			Digest: &kmspb.Digest_Sha256{
				Sha256: digest.Sum(nil),
			},
		},
		DigestCrc32C: wrapperspb.Int64(int64(digestCRC32C)),
	}

	// Call the API.
	result, err := client.AsymmetricSign(ctx, req)
	if err != nil {
		return fmt.Errorf("failed to sign digest: %w", err)
	}

	// Optional, but recommended: perform integrity verification on result.
	// For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit:
	// https://cloud.google.com/kms/docs/data-integrity-guidelines
	if result.VerifiedDigestCrc32C == false {
		return fmt.Errorf("AsymmetricSign: request corrupted in-transit")
	}
	if result.Name != req.Name {
		return fmt.Errorf("AsymmetricSign: request corrupted in-transit")
	}
	if int64(crc32c(result.Signature)) != result.SignatureCrc32C.Value {
		return fmt.Errorf("AsymmetricSign: response corrupted in-transit")
	}

	fmt.Fprintf(w, "Signed digest: %s", result.Signature)
	return nil
}

Java

Pour exécuter ce code, commencez par configurer un environnement de développement Java et installez le SDK Cloud KMS pour Java.

import com.google.cloud.kms.v1.AsymmetricSignResponse;
import com.google.cloud.kms.v1.CryptoKeyVersionName;
import com.google.cloud.kms.v1.Digest;
import com.google.cloud.kms.v1.KeyManagementServiceClient;
import com.google.protobuf.ByteString;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;

public class SignAsymmetric {

  public void signAsymmetric() throws