Nous recommandons la primitive code d'authentification de message (MAC) avec le type de clé HMAC_SHA256 pour la plupart des cas d'utilisation.
Si vous souhaitez vous assurer que personne ne peut falsifier vos données, nous vous recommandons d'utiliser la primitive MAC (Message Authentication Code). Il utilise une seule clé pour générer et valider des codes d'authentification de message. Le MAC ne chiffre pas les données. Dans la plupart des cas, il est préférable de protéger les données avec le AEAD, qui inclut le chiffrement et le code de contrôle d'accès, plutôt qu'avec le code de contrôle d'accès seul.
Les exemples suivants vous aideront à utiliser la primitive MAC:
C++
// A command-line utility for showcasing using the Tink MAC primitive. #include <cstdlib> #include <fstream> #include <iostream> #include <memory> #include <ostream> #include <sstream> #include <string> #include <utility> #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/mac.h" #include "tink/mac/mac_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 {compute|verify}"); ABSL_FLAG(std::string, data_filename, "", "Data file name"); ABSL_FLAG(std::string, tag_filename, "", "Authentication tag file name"); namespace { using ::crypto::tink::KeysetHandle; using ::crypto::tink::Mac; using ::crypto::tink::MacConfig; using ::crypto::tink::util::Status; using ::crypto::tink::util::StatusOr; constexpr absl::string_view kCompute = "compute"; constexpr absl::string_view kVerify = "verify"; void ValidateParams() { // ... } } // namespace namespace tink_cc_examples { // MAC example CLI implementation. Status MacCli(absl::string_view mode, const std::string keyset_filename, const std::string& data_filename, const std::string& tag_filename) { Status result = MacConfig::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(); // Get the primitive. StatusOr<std::unique_ptr<Mac>> mac_primitive = (*keyset_handle) ->GetPrimitive<crypto::tink::Mac>( crypto::tink::ConfigGlobalRegistry()); if (!mac_primitive.ok()) return mac_primitive.status(); // Read the input. StatusOr<std::string> data_file_content = ReadFile(data_filename); if (!data_file_content.ok()) return data_file_content.status(); std::string output; if (mode == kCompute) { // Compute authentication tag. StatusOr<std::string> compute_result = (*mac_primitive)->ComputeMac(*data_file_content); if (!compute_result.ok()) return compute_result.status(); // Write out the authentication tag to tag file. return WriteToFile(*compute_result, tag_filename); } else { // operation == kVerify. // Read the authentication tag from tag file. StatusOr<std::string> tag_result = ReadFile(tag_filename); if (!tag_result.ok()) { std::cerr << tag_result.status().message() << '\n'; exit(1); } // Verify authentication tag. Status verify_result = (*mac_primitive)->VerifyMac(*tag_result, *data_file_content); if (verify_result.ok()) std::clog << "Verification succeeded!" << '\n'; return verify_result; } } } // 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 data_filename = absl::GetFlag(FLAGS_data_filename); std::string tag_filename = absl::GetFlag(FLAGS_tag_filename); std::clog << "Using keyset from file '" << keyset_filename << "' to " << mode << " authentication tag from file '" << tag_filename << "' for data file '" << data_filename << "'." << '\n'; std::clog << "The tag will be " << ((mode == kCompute) ? "written to" : "read from") << " file '" << tag_filename << "'." << '\n'; CHECK_OK(tink_cc_examples::MacCli(mode, keyset_filename, data_filename, tag_filename)); return 0; }
Go
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/mac" ) func Example() { // A keyset created with "tinkey create-keyset --key-template=HMAC_SHA256_128BITTAG". // Note that this keyset has the secret key information in cleartext. jsonKeyset := `{ "key": [{ "keyData": { "keyMaterialType": "SYMMETRIC", "typeUrl": "type.googleapis.com/google.crypto.tink.HmacKey", "value": "EgQIAxAQGiA0LQjovcydWhVQV3k8W9ZSRkd7Ei4Y/TRWApE8guwV4Q==" }, "keyId": 1892702217, "outputPrefixType": "TINK", "status": "ENABLED" }], "primaryKeyId": 1892702217 }` // 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 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. keysetHandle, err := insecurecleartextkeyset.Read( keyset.NewJSONReader(bytes.NewBufferString(jsonKeyset))) if err != nil { log.Fatal(err) } // Retrieve the MAC primitive we want to use from the keyset handle. primitive, err := mac.New(keysetHandle) if err != nil { log.Fatal(err) } // Use the primitive to create a MAC tag for some data. In this case the primary // key of the keyset will be used (which is also the only key in this example). data := []byte("data") tag, err := primitive.ComputeMAC(data) if err != nil { log.Fatal(err) } // Use the primitive to verify the tag. VerifyMAC finds the correct key in // the keyset. If no key is found or verification fails, it returns an error. err = primitive.VerifyMAC(tag, data) if err != nil { log.Fatal(err) } fmt.Printf("tag is valid") // Output: tag is valid }
Java
package mac; 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.Mac; import com.google.crypto.tink.RegistryConfiguration; import com.google.crypto.tink.TinkJsonProtoKeysetFormat; import com.google.crypto.tink.mac.MacConfig; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; /** * A command-line utility for checking file integrity with a Message Authentication Code (MAC). * * <p>It loads cleartext keys from disk - this is not recommended! * * <p>It requires the following arguments: * * <ul> * <li>mode: either 'compute' or 'verify'. * <li>key-file: Read the key material from this file. * <li>input-file: Read the input from this file. * <li>mac-file: name of the file containing a hexadecimal MAC of the input data. */ public final class MacExample { 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 MacExample compute/verify key-file input-file mac-file"); System.exit(1); } String mode = args[0]; if (!mode.equals("compute") && !mode.equals("verify")) { System.err.println("Incorrect mode. Please select compute or verify."); System.exit(1); } Path keyFile = Paths.get(args[1]); byte[] msg = Files.readAllBytes(Paths.get(args[2])); Path macFile = Paths.get(args[3]); // Register all MAC key types with the Tink runtime. MacConfig.register(); // Read the keyset into a KeysetHandle. KeysetHandle handle = TinkJsonProtoKeysetFormat.parseKeyset( new String(Files.readAllBytes(keyFile), UTF_8), InsecureSecretKeyAccess.get()); // Get the primitive. Mac macPrimitive = handle.getPrimitive(RegistryConfiguration.get(), Mac.class); if (mode.equals("compute")) { byte[] macTag = macPrimitive.computeMac(msg); Files.write(macFile, macTag); } else { byte[] macTag = Files.readAllBytes(macFile); // This will throw a GeneralSecurityException if verification fails. macPrimitive.verifyMac(macTag, msg); } } private MacExample() {} }
Python
import tink from tink import mac from tink import secret_key_access def example(): """Compute and verify MAC tags.""" # Register the MAC key managers. This is needed to create a Mac primitive # later. mac.register() # Created with "tinkey create-keyset --key-template=HMAC_SHA256_128BITTAG". # Note that this keyset has the secret key information in cleartext. keyset = r"""{ "key": [{ "keyData": { "keyMaterialType": "SYMMETRIC", "typeUrl": "type.googleapis.com/google.crypto.tink.HmacKey", "value": "EgQIAxAQGiA0LQjovcydWhVQV3k8W9ZSRkd7Ei4Y/TRWApE8guwV4Q==" }, "keyId": 1892702217, "outputPrefixType": "TINK", "status": "ENABLED" }], "primaryKeyId": 1892702217 }""" # Create a keyset handle from the cleartext keyset in the previous # step. The keyset handle provides abstract access to the underlying keyset to # limit access of 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. keyset_handle = tink.json_proto_keyset_format.parse( keyset, secret_key_access.TOKEN ) # Retrieve the Mac primitive we want to use from the keyset handle. primitive = keyset_handle.primitive(mac.Mac) # Use the primitive to compute the MAC for a message. In this case the primary # key of the keyset will be used (which is also the only key in this example). data = b'data' tag = primitive.compute_mac(data) # Use the primitive to verify the MAC for the message. Verify finds the # correct key in the keyset and verifies the MAC. If no key is found or # verification fails, it raises an error. primitive.verify_mac(tag, data)
Code d'authentification de message (MAC)
La primitive MAC vous permet de vérifier que personne n'a falsifié vos données. Un expéditeur qui partage une clé symétrique avec un destinataire peut calculer une balise d'authentification pour un message donné, ce qui permet au destinataire de vérifier qu'un message provient de l'expéditeur attendu et qu'il n'a pas été modifié.
Le MAC possède les propriétés suivantes:
- Authenticité: connaître la clé est le seul moyen de créer une balise MAC vérifiable.
- Symmetric: le calcul et la validation de la balise nécessitent la même clé.
Le MAC peut être déterministe ou aléatoire, en fonction de l'algorithme. Tink n'implémente pas d'algorithmes MAC non déterministes pour le moment. Vous devez utiliser le code de contrôle d'accès MAC uniquement pour l'authentification des messages, et non à d'autres fins, comme la génération d'octets pseudo-aléatoires (pour cela, consultez la section PRF).
Si vous avez plutôt besoin d'une primitive asymétrique, consultez la section Signature numérique.
Choisir un type de clé
Nous vous recommandons d'utiliser HMAC_SHA256 pour la plupart des cas d'utilisation, mais d'autres options sont également disponibles.
En règle générale, les éléments suivants sont valables:
- HMAC_SHA512 peut être plus ou moins rapide en fonction de la taille de votre message et des spécificités du matériel que vous utilisez.
- HMAC_SHA512 est le mode le plus conservateur qui peut être utilisé pour un nombre pratiquement illimité de messages.
AES256_CMAC est le plus rapide sur les systèmes compatibles avec l'accélération matérielle AES-NI.
Garanties de sécurité minimales
- Niveau d'authentification d'au moins 80 bits
- Protection contre la falsification existentielle en cas d'attaque par texte clair choisi
- Sécurité de 128 bits minimum contre les attaques de récupération de clé, et également dans les scénarios multi-utilisateurs (lorsqu'attaquant ne cible pas une clé spécifique, mais n'importe quelle clé d'un ensemble de clés pouvant comporter jusqu'à 232 clés)