If you want to ensure that nobody can tamper with your data and prove that the data came from you, we recommend the Digital Signature primitive. It is asymmetric, meaning it uses paired keys, one public and one private. The private key signs the data, and the public key verifies it.
We recommend the ECDSA_P256 key type for most use cases. For all supported key types, see Supported Key Types.
The following examples get you started using the Digital Signature primitive.
Python
Java
package signature; import static java.nio.charset.StandardCharsets.UTF_8; import com.google.crypto.tink.CleartextKeysetHandle; import com.google.crypto.tink.JsonKeysetReader; import com.google.crypto.tink.KeysetHandle; import com.google.crypto.tink.PublicKeySign; import com.google.crypto.tink.PublicKeyVerify; import com.google.crypto.tink.signature.SignatureConfig; import com.google.crypto.tink.subtle.Hex; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.security.GeneralSecurityException; import java.util.List; /** * 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); } File keyFile = new File(args[1]); byte[] msg = Files.readAllBytes(Paths.get(args[2])); File signatureFile = new File(args[3]); // Register all signature key types with the Tink runtime. SignatureConfig.register(); // Read the keyset into a KeysetHandle. KeysetHandle handle = null; try (FileInputStream inputStream = new FileInputStream(keyFile)) { handle = CleartextKeysetHandle.read(JsonKeysetReader.withInputStream(inputStream)); } catch (GeneralSecurityException | IOException ex) { System.err.println("Cannot read keyset, got error: " + ex); System.exit(1); } if (mode.equals("sign")) { // Get the primitive. PublicKeySign signer = null; try { signer = handle.getPrimitive(PublicKeySign.class); } catch (GeneralSecurityException ex) { System.err.println("Cannot create primitive, got error: " + ex); System.exit(1); } // Use the primitive to sign data. byte[] signature = signer.sign(msg); try (FileOutputStream stream = new FileOutputStream(signatureFile)) { stream.write(Hex.encode(signature).getBytes(UTF_8)); } System.exit(0); } List<String> lines = Files.readAllLines(signatureFile.toPath()); if (lines.size() != 1) { System.err.printf("The signature file should contain only one line, got %d", lines.size()); System.exit(1); } byte[] signature = Hex.decode(lines.get(0).trim()); // Get the primitive. PublicKeyVerify verifier = null; try { verifier = handle.getPrimitive(PublicKeyVerify.class); } catch (GeneralSecurityException ex) { System.err.println("Cannot create primitive, got error: " + ex); System.exit(1); } // Use the primitive to verify data. try { verifier.verify(signature, msg); } catch (GeneralSecurityException ex) { System.err.println("Signature verification failed."); System.exit(1); } System.exit(0); } private SignatureExample() {} }
C++
// A utility for signing and verifying files using digital signatures. #include <iostream> #include <memory> #include <ostream> #include <string> #include <utility> #include "absl/flags/flag.h" #include "absl/flags/parse.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"; // ... } // 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<PublicKeySign>(); 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<PublicKeyVerify>(); 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 << std::endl; } else { // mode == kVerify std::clog << " the signature in " << signature_filename << " over the content of " << input_filename << std::endl; } Status result = tink_cc_examples::DigitalSignatureCli( mode, keyset_filename, input_filename, signature_filename); if (!result.ok()) { std::cerr << result.message() << std::endl; exit(1); } return 0; }
Go