Je souhaite signer numériquement des données

Nous recommandons la primitive Signature numérique avec le type de clé ECDSA_P256 pour la plupart des cas d'utilisation.

La primitive de signature numérique garantit que personne n'a falsifié vos données et prouve qu'elles proviennent de vous. Il est asymétrique, utilisant la clé privée pour signer les données et la clé publique pour les valider.

Les exemples suivants vous aideront à utiliser la primitive de signature numérique:

// A utility for signing and verifying files using digital signatures.
#include <iostream>
#include <memory>
#include <ostream>
#include <string>

#include "absl/flags/flag.h"
#include "absl/flags/parse.h"
#include "absl/log/check.h"
#include "absl/strings/string_view.h"
#include "tink/config/global_registry.h"
#include "util/util.h"
#include "tink/keyset_handle.h"
#include "tink/public_key_sign.h"
#include "tink/public_key_verify.h"
#include "tink/signature/signature_config.h"
#include "tink/util/status.h"

ABSL_FLAG(std::string, keyset_filename, "", "Keyset file in JSON format");
ABSL_FLAG(std::string, mode, "", "Mode of operation (sign|verify)");
ABSL_FLAG(std::string, input_filename, "", "Filename to operate on");
ABSL_FLAG(std::string, signature_filename, "", "Path to the signature file");

namespace {

using ::crypto::tink::KeysetHandle;
using ::crypto::tink::PublicKeySign;
using ::crypto::tink::PublicKeyVerify;
using ::crypto::tink::util::Status;
using ::crypto::tink::util::StatusOr;

constexpr absl::string_view kSign = "sign";
constexpr absl::string_view kVerify = "verify";

void ValidateParams() {
  // ...
}

}  // namespace

namespace tink_cc_examples {

// Digital signature example CLI implementation.
Status DigitalSignatureCli(absl::string_view mode,
                           const std::string& keyset_filename,
                           const std::string& input_filename,
                           const std::string& signature_filename) {
  Status result = crypto::tink::SignatureConfig::Register();
  if (!result.ok()) return result;

  // Read the keyset from file.
  StatusOr<std::unique_ptr<KeysetHandle>> keyset_handle =
      ReadJsonCleartextKeyset(keyset_filename);
  if (!keyset_handle.ok()) return keyset_handle.status();

  // Read the input.
  StatusOr<std::string> input_file_content = ReadFile(input_filename);
  if (!input_file_content.ok()) return input_file_content.status();

  if (mode == kSign) {
    StatusOr<std::unique_ptr<PublicKeySign>> public_key_sign =
        (*keyset_handle)
            ->GetPrimitive<crypto::tink::PublicKeySign>(
                crypto::tink::ConfigGlobalRegistry());
    if (!public_key_sign.ok()) return public_key_sign.status();

    StatusOr<std::string> signature =
        (*public_key_sign)->Sign(*input_file_content);
    if (!signature.ok()) return signature.status();

    return WriteToFile(*signature, signature_filename);
  } else {  // mode == kVerify
    StatusOr<std::unique_ptr<PublicKeyVerify>> public_key_verify =
        (*keyset_handle)
            ->GetPrimitive<crypto::tink::PublicKeyVerify>(
                crypto::tink::ConfigGlobalRegistry());
    if (!public_key_verify.ok()) return public_key_verify.status();

    // Read the signature.
    StatusOr<std::string> signature_file_content = ReadFile(signature_filename);
    if (!signature_file_content.ok()) return signature_file_content.status();

    return (*public_key_verify)
        ->Verify(*signature_file_content, *input_file_content);
  }
}

}  // namespace tink_cc_examples

int main(int argc, char** argv) {
  absl::ParseCommandLine(argc, argv);

  ValidateParams();

  std::string mode = absl::GetFlag(FLAGS_mode);
  std::string keyset_filename = absl::GetFlag(FLAGS_keyset_filename);
  std::string input_filename = absl::GetFlag(FLAGS_input_filename);
  std::string signature_filename = absl::GetFlag(FLAGS_signature_filename);

  std::clog << "Using keyset in " << keyset_filename << " to " << mode;
  if (mode == kSign) {
    std::clog << " file " << input_filename
              << "; the resulting signature is written to "
              << signature_filename << '\n';
  } else {  // mode == kVerify
    std::clog << " the signature in " << signature_filename
              << " over the content of " << input_filename << '\n';
  }

  CHECK_OK(tink_cc_examples::DigitalSignatureCli(
      mode, keyset_filename, input_filename, signature_filename));
  return 0;
}
import (
	"bytes"
	"fmt"
	"log"

	"github.com/tink-crypto/tink-go/v2/insecurecleartextkeyset"
	"github.com/tink-crypto/tink-go/v2/keyset"
	"github.com/tink-crypto/tink-go/v2/signature"
)

func Example() {
	// A private keyset created with
	// "tinkey create-keyset --key-template=ECDSA_P256 --out private_keyset.cfg".
	// Note that this keyset has the secret key information in cleartext.
	privateJSONKeyset := `{
		"key": [{
			"keyData": {
					"keyMaterialType":
							"ASYMMETRIC_PRIVATE",
					"typeUrl":
							"type.googleapis.com/google.crypto.tink.EcdsaPrivateKey",
					"value":
							"EkwSBggDEAIYAhogEiSZ9u2nDtvZuDgWgGsVTIZ5/V08N4ycUspTX0RYRrkiIHpEwHxQd1bImkyMvV2bqtUbgMh5uPSTdnUEGrPXdt56GiEA3iUi+CRN71qy0fOCK66xAW/IvFyjOGtxjppRhSFUneo="
			},
			"keyId": 611814836,
			"outputPrefixType": "TINK",
			"status": "ENABLED"
		}],
		"primaryKeyId": 611814836
	}`

	// The corresponding public keyset created with
	// "tinkey create-public-keyset --in private_keyset.cfg"
	publicJSONKeyset := `{
      "key": [{
          "keyData": {
              "keyMaterialType":
                  "ASYMMETRIC_PUBLIC",
              "typeUrl":
                  "type.googleapis.com/google.crypto.tink.EcdsaPublicKey",
              "value":
                  "EgYIAxACGAIaIBIkmfbtpw7b2bg4FoBrFUyGef1dPDeMnFLKU19EWEa5IiB6RMB8UHdWyJpMjL1dm6rVG4DIebj0k3Z1BBqz13beeg=="
          },
          "keyId": 611814836,
          "outputPrefixType": "TINK",
          "status": "ENABLED"
      }],
      "primaryKeyId": 611814836
  }`

	// Create a keyset handle from the cleartext private keyset in the previous
	// step. The keyset handle provides abstract access to the underlying keyset to
	// limit the access of the raw key material. WARNING: In practice,
	// it is unlikely you will want to use a insecurecleartextkeyset, as it implies
	// that your key material is passed in cleartext, which is a security risk.
	// Consider encrypting it with a remote key in Cloud KMS, AWS KMS or HashiCorp Vault.
	// See https://github.com/google/tink/blob/master/docs/GOLANG-HOWTO.md#storing-and-loading-existing-keysets.
	privateKeysetHandle, err := insecurecleartextkeyset.Read(
		keyset.NewJSONReader(bytes.NewBufferString(privateJSONKeyset)))
	if err != nil {
		log.Fatal(err)
	}

	// Retrieve the Signer primitive from privateKeysetHandle.
	signer, err := signature.NewSigner(privateKeysetHandle)
	if err != nil {
		log.Fatal(err)
	}

	// Use the primitive to sign a message. In this case, the primary key of the
	// keyset will be used (which is also the only key in this example).
	data := []byte("data")
	sig, err := signer.Sign(data)
	if err != nil {
		log.Fatal(err)
	}

	// Create a keyset handle from the keyset containing the public key. Because the
	// public keyset does not contain any secrets, we can use [keyset.ReadWithNoSecrets].
	publicKeysetHandle, err := keyset.ReadWithNoSecrets(
		keyset.NewJSONReader(bytes.NewBufferString(publicJSONKeyset)))
	if err != nil {
		log.Fatal(err)
	}

	// Retrieve the Verifier primitive from publicKeysetHandle.
	verifier, err := signature.NewVerifier(publicKeysetHandle)
	if err != nil {
		log.Fatal(err)
	}

	if err = verifier.Verify(sig, data); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("sig is valid")
	// Output: sig is valid
}
package signature;

import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.crypto.tink.InsecureSecretKeyAccess;
import com.google.crypto.tink.KeysetHandle;
import com.google.crypto.tink.PublicKeySign;
import com.google.crypto.tink.PublicKeyVerify;
import com.google.crypto.tink.RegistryConfiguration;
import com.google.crypto.tink.TinkJsonProtoKeysetFormat;
import com.google.crypto.tink.signature.SignatureConfig;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * A command-line utility for digitally signing and verifying a file.
 *
 * <p>It loads cleartext keys from disk - this is not recommended!
 *
 * <p>It requires the following arguments:
 *
 * <ul>
 *   <li>mode: either 'sign' or 'verify'.
 *   <li>key-file: Read the key material from this file.
 *   <li>input-file: Read the input from this file.
 *   <li>signature-file: name of the file containing a hexadecimal signature of the input file.
 */
public final class SignatureExample {
  public static void main(String[] args) throws Exception {
    if (args.length != 4) {
      System.err.printf("Expected 4 parameters, got %d\n", args.length);
      System.err.println(
          "Usage: java SignatureExample sign/verify key-file input-file signature-file");
      System.exit(1);
    }

    String mode = args[0];
    if (!mode.equals("sign") && !mode.equals("verify")) {
      System.err.println("Incorrect mode. Please select sign or verify.");
      System.exit(1);
    }
    Path keyFile = Paths.get(args[1]);
    byte[] msg = Files.readAllBytes(Paths.get(args[2]));
    Path signatureFile = Paths.get(args[3]);

    // Register all signature key types with the Tink runtime.
    SignatureConfig.register();

    // Read the keyset into a KeysetHandle.
    KeysetHandle handle =
        TinkJsonProtoKeysetFormat.parseKeyset(
            new String(Files.readAllBytes(keyFile), UTF_8), InsecureSecretKeyAccess.get());

    if (mode.equals("sign")) {
      // Get the primitive.
      PublicKeySign signer = handle.getPrimitive(RegistryConfiguration.get(), PublicKeySign.class);

      // Use the primitive to sign data.
      byte[] signature = signer.sign(msg);
      Files.write(signatureFile, signature);
    } else {
      byte[] signature = Files.readAllBytes(signatureFile);

      // Get the primitive.
      PublicKeyVerify verifier =
          handle.getPrimitive(RegistryConfiguration.get(), PublicKeyVerify.class);

      verifier.verify(signature, msg);
    }
  }

  private SignatureExample() {}
}

GUIDE

import tink
from tink import secret_key_access
from tink import signature


def example():
  """Sign and verify using digital signatures."""
  # Register the signature key managers. This is needed to create
  # PublicKeySign and PublicKeyVerify primitives later.
  signature.register()

  # A private keyset created with
  # "tinkey create-keyset --key-template=ECDSA_P256 --out private_keyset.cfg".
  # Note that this keyset has the secret key information in cleartext.
  private_keyset = r"""{
      "key": [{
          "keyData": {
              "keyMaterialType":
                  "ASYMMETRIC_PRIVATE",
              "typeUrl":
                  "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey",
              "value":
                  "EkwSBggDEAIYAhogEiSZ9u2nDtvZuDgWgGsVTIZ5/V08N4ycUspTX0RYRrkiIHpEwHxQd1bImkyMvV2bqtUbgMh5uPSTdnUEGrPXdt56GiEA3iUi+CRN71qy0fOCK66xAW/IvFyjOGtxjppRhSFUneo="
          },
          "keyId": 611814836,
          "outputPrefixType": "TINK",
          "status": "ENABLED"
      }],
      "primaryKeyId": 611814836
  }"""

  # The corresponding public keyset created with
  # "tinkey create-public-keyset --in private_keyset.cfg"
  public_keyset = r"""{
      "key": [{
          "keyData": {
              "keyMaterialType":
                  "ASYMMETRIC_PUBLIC",
              "typeUrl":
                  "type.googleapis.com/google.crypto.tink.EcdsaPublicKey",
              "value":
                  "EgYIAxACGAIaIBIkmfbtpw7b2bg4FoBrFUyGef1dPDeMnFLKU19EWEa5IiB6RMB8UHdWyJpMjL1dm6rVG4DIebj0k3Z1BBqz13beeg=="
          },
          "keyId": 611814836,
          "outputPrefixType": "TINK",
          "status": "ENABLED"
      }],
      "primaryKeyId": 611814836
  }"""

  # Create a keyset handle from the cleartext keyset in the previous
  # step. The keyset handle provides abstract access to the underlying keyset to
  # limit the exposure of accessing the raw key material. WARNING: In practice,
  # it is unlikely you will want to use tink.json_proto_keyset_format.parse, as
  # it implies that your key material is passed in cleartext which is a security
  # risk.
  private_keyset_handle = tink.json_proto_keyset_format.parse(
      private_keyset, secret_key_access.TOKEN
  )

  # Retrieve the PublicKeySign primitive we want to use from the keyset
  # handle.
  sign_primitive = private_keyset_handle.primitive(signature.PublicKeySign)

  # Use the primitive to sign a message. In this case the primary key of the
  # keyset will be used (which is also the only key in this example).
  sig = sign_primitive.sign(b'msg')

  # Create a keyset handle from the keyset containing the public key. Because
  # this keyset does not contain any secrets, we can use
  # `parse_without_secret`.
  public_keyset_handle = tink.json_proto_keyset_format.parse_without_secret(
      public_keyset
  )

  # Retrieve the PublicKeyVerify primitive we want to use from the keyset
  # handle.
  verify_primitive = public_keyset_handle.primitive(signature.PublicKeyVerify)

  # Use the primitive to verify that `sig` is valid signature for the message.
  # Verify finds the correct key in the keyset. If no key is found or
  # verification fails, it raises an error.
  verify_primitive.verify(sig, b'msg')

  # Note that we can also get the public keyset handle from the private keyset
  # handle. The verification works the same as above.
  public_keyset_handle2 = private_keyset_handle.public_keyset_handle()
  verify_primitive2 = public_keyset_handle2.primitive(signature.PublicKeyVerify)
  verify_primitive2.verify(sig, b'msg')

Signature numérique

La primitive de signature numérique vous permet de vérifier que personne n'a falsifié vos données. Elle garantit l'authenticité et l'intégrité des données signées, mais pas leur confidentialité. Elle est asymétrique, ce qui signifie qu'elle utilise une paire de clés (clé publique et clé privée).

La primitive de signature numérique présente les propriétés suivantes:

  • Authenticité: à moins de disposer de la clé privée, il est impossible de créer une signature pour laquelle PublicKeyVerify.Verify(signature, message) renvoie une validation.
  • Asymétrie: la création de la signature repose sur une clé différente de celle utilisée pour la validation. Cela vous permet, pour valider les signatures, de distribuer la clé publique aux tiers qui ne peuvent pas créer de signatures eux-mêmes.

Si vous n'avez pas besoin d'asymétrie, envisagez d'utiliser la primitive MAC plus simple et plus efficace à la place.

La fonctionnalité des signatures numériques est représentée dans Tink sous la forme d'une paire de primitives:

  • PublicKeySign pour signer des données
  • PublicKeyVerify pour valider la signature

Choisir un type de clé

Nous vous recommandons d'utiliser ECDSA_P256 pour la plupart des cas d'utilisation, mais il existe de nombreuses options. En règle générale, les éléments suivants sont valables:

  • ECDSA_P256 est l'option la plus utilisée et constitue une valeur par défaut raisonnable. Notez toutefois que les signatures ECDSA sont malleables.
  • ED25519 crée des signatures déterministes et offre de meilleures performances que ECDSA_P256.
  • RSA_SSA_PKCS1_3072_SHA256_F4 crée des signatures déterministes et offre les meilleures performances de validation (mais la signature est beaucoup plus lente que ECDSA_P256 ou ED25519).

Garanties de sécurité minimales

  • La longueur des données à signer peut être arbitraire.
  • Niveau de sécurité de 128 bits contre les attaques par message choisi adaptatif pour les schémas basés sur les courbes elliptiques
  • Niveau de sécurité de 112 bits contre les attaques par message choisi adaptatif pour les schémas basés sur RSA (permet les clés de 2 048 bits)

Malléabilité

Un schéma de signature est malléable si un pirate informatique peut créer une signature valide différente pour un message déjà signé. Bien que cela ne pose pas de problème dans la plupart des scénarios, dans certains cas, les programmeurs supposent implicitement que les signatures valides sont uniques, ce qui peut entraîner des résultats inattendus.