对于大多数使用场景,我们建议使用 HMAC_SHA256 密钥类型。对于所有受支持的 密钥类型,请参阅支持的密钥类型。
如果您想防止他人篡改您的数据,我们建议您 消息身份验证代码 (MAC) 基元。它使用单个密钥来生成 消息身份验证码并验证它们。MAC 不会加密数据。大多数 使用 AEAD 保护数据,包括加密 和 MAC,比单独的 MAC 更可取。
以下示例介绍了如何开始使用 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.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(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)