**We recommend the [Message Authentication Code (MAC)](https://developers.google.com/tink/protect-data-from-tampering#mac) primitive with the
[HMAC_SHA256](https://developers.google.com/tink/protect-data-from-tampering#choose_a_key_type) key type for most use cases.**

If you want to ensure that nobody can tamper with your data, we recommend the
Message Authentication Code (MAC) primitive. It uses a single key to generate
message authentication codes and verify them. MAC does not encrypt data. In most
cases, protecting data with [AEAD](https://developers.google.com/tink/encrypt-data), which includes encryption
and MAC, is preferable to MAC alone.

> [!CAUTION]
> **Caution:** The MAC primitive operates over an arbitrary byte array. When encoding multi-part messages, you should consider collisions that can arise. For example, the output of `ComputeMac("Foo" + "Bar")`, is the same as `ComputeMac("Fo" +
> "oBar")`. When joining multi-part messages, it's recommended to use a context separator (an additional character or sequence which is not part of the alphabet of the input messages), especially in cases where some of the inputs might be controlled by a user. An example serialization strategy is to use the length of each element as follows: `serialize(data1 , data2 , ..., datan) = 4-byte-data1's
> length || data1 || 4-byte-data2's length || data2 || ... || 4-byte-dataN's length
> || dataN`

The following examples get you started using the MAC primitive:

### C++

```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/absl_check.h"
#include "absl/status/status.h"
#include "absl/status/statusor.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"

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;

constexpr absl::string_view kCompute = "compute";
constexpr absl::string_view kVerify = "verify";

void ValidateParams() {
  // ...
}

}  // namespace

namespace tink_cc_examples {

// MAC example CLI implementation.
absl::Status MacCli(absl::string_view mode, const std::string keyset_filename,
                    const std::string& data_filename,
                    const std::string& tag_filename) {
  absl::Status result = MacConfig::Register();
  if (!result.ok()) return result;

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

  // Get the primitive.
  absl::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.
  absl::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.
    absl::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.
    absl::StatusOr<std::string> tag_result = ReadFile(tag_filename);
    if (!tag_result.ok()) {
      std::cerr << tag_result.status().message() << '\n';
      exit(1);
    }
    // Verify authentication tag.
    absl::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';

  ABSL_CHECK_OK(tink_cc_examples::MacCli(mode, keyset_filename, data_filename,
                                         tag_filename));
  return 0;
}
```

### Go

```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://developers.google.com/tink/key-management-overview.
	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

```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

```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)
```

## Message Authentication Code (MAC)

The MAC primitive lets you to verify that no one has tampered with your data.
A sender sharing a *symmetric key* with a recipient can compute an
*authentication tag* for a given message, which allows the recipient to verify
that a message is from the expected sender and has not been modified.

MAC has the following properties:

- **Authenticity**: Knowing the key is the only way to create a verifiable MAC tag.
- **Symmetric**: Computing and verifying the tag requires the same key.

MAC can be deterministic or randomized, depending on the algorithm. Tink does
not implement non-deterministic MAC algorithms at the moment. You should use MAC
only for message authentication, not for other purposes like generation of
pseudorandom bytes (for that, see [PRF](https://developers.google.com/tink/prf)).

If you need an asymmetric primitive instead, see [Digital
Signature](https://developers.google.com/tink/digital-signature).

### Choose a key type

We recommend using **HMAC_SHA256** for most uses, but there are other options as
well.

In general, the following holds true:

- HMAC_SHA512 may or may not be faster depending on your message size and the specifics of the hardware you use.
- HMAC_SHA512 is the most conservative mode that can be used for practically unlimited number of messages.
- AES256_CMAC is fastest on systems that support the [AES-NI](https://www.intel.com/content/www/us/en/developer/articles/technical/advanced-encryption-standard-instructions-aes-ni.html) hardware
  acceleration.

  > [!NOTE]
  > **Note:** Tink doesn't offer AES128_CMAC because it doesn't offer 128-bit security in multi-user scenarios.

### Minimal security guarantees

- At least 80-bit authentication strength
- Secure against existential forgery under chosen plaintext attack
- At least 128-bit security against key recovery attacks, and also in multi-user scenarios (when an attacker is not targeting a specific key, but any key from a set of up to 2^32^ keys)