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
python/examples/signature/signature.py
"""A utility for signing and verifying files using digital signatures. It loads cleartext keys from disk - this is not recommended! """ from __future__ import absolute_import from __future__ import division from __future__ import print_function import binascii # Special imports from absl import app from absl import flags from absl import logging import tink from tink import cleartext_keyset_handle from tink import signature FLAGS = flags.FLAGS flags.DEFINE_enum('mode', None, ['sign', 'verify'], 'The operation to perform.') flags.DEFINE_string('keyset_path', None, 'Path to the keyset used for the signature operation.') flags.DEFINE_string('data_path', None, 'Path to the file with the input data.') flags.DEFINE_string('signature_path', None, 'Path to the signature file.') def main(argv): del argv # Unused. # Initialise Tink try: signature.register() except tink.TinkError as e: logging.exception('Error initialising Tink: %s', e) return 1 # Read the keyset into a keyset_handle with open(FLAGS.keyset_path, 'rt') as keyset_file: try: text = keyset_file.read() keyset_handle = cleartext_keyset_handle.read(tink.JsonKeysetReader(text)) except tink.TinkError as e: logging.exception('Error reading key: %s', e) return 1 with open(FLAGS.data_path, 'rb') as data_file: data = data_file.read() if FLAGS.mode == 'sign': # Get the primitive try: cipher = keyset_handle.primitive(signature.PublicKeySign) except tink.TinkError as e: logging.exception('Error creating primitive: %s', e) return 1 # Sign data sig = cipher.sign(data) with open(FLAGS.signature_path, 'wb') as signature_file: signature_file.write(binascii.hexlify(sig)) return 0 # Get the primitive try: cipher = keyset_handle.primitive(signature.PublicKeyVerify) except tink.TinkError as e: logging.exception('Error creating primitive: %s', e) return 1 # Verify data with open(FLAGS.signature_path, 'rb') as signature_file: try: expected_signature = binascii.unhexlify(signature_file.read().strip()) except binascii.Error as e: logging.exception('Error reading expected code: %s', e) return 1 try: cipher.verify(expected_signature, data) logging.info('Signature verification succeeded.') return 0 except binascii.Error as e: logging.exception('Error reading expected signature: %s', e) except tink.TinkError as e: logging.info('Signature verification failed.') return 1 if __name__ == '__main__': flags.mark_flags_as_required([ 'mode', 'keyset_path', 'data_path', 'signature_path']) app.run(main)
Java
java_src/examples/signature/SignatureExample.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() {} }