1# Copyright 2021 Google LLC 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS-IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15# [START digital-signature-example] 16 17"""A utility for signing and verifying files using digital signatures. 18 19It loads cleartext keys from disk - this is not recommended! 20""" 21 22import binascii 23 24from absl import app 25from absl import flags 26from absl import logging 27import tink 28from tink import cleartext_keyset_handle 29from tink import signature 30 31 32FLAGS = flags.FLAGS 33 34flags.DEFINE_enum('mode', None, ['sign', 'verify'], 35 'The operation to perform.') 36flags.DEFINE_string('keyset_path', None, 37 'Path to the keyset used for the signature operation.') 38flags.DEFINE_string('data_path', None, 39 'Path to the file with the input data.') 40flags.DEFINE_string('signature_path', None, 41 'Path to the signature file.') 42 43 44def main(argv): 45 del argv # Unused. 46 47 # Initialise Tink 48 signature.register() 49 50 # Read the keyset into a keyset_handle 51 with open(FLAGS.keyset_path, 'rt') as keyset_file: 52 try: 53 text = keyset_file.read() 54 keyset_handle = cleartext_keyset_handle.read(tink.JsonKeysetReader(text)) 55 except tink.TinkError as e: 56 logging.exception('Error reading key: %s', e) 57 return 1 58 59 with open(FLAGS.data_path, 'rb') as data_file: 60 data = data_file.read() 61 62 if FLAGS.mode == 'sign': 63 # Get the primitive 64 try: 65 cipher = keyset_handle.primitive(signature.PublicKeySign) 66 except tink.TinkError as e: 67 logging.exception('Error creating primitive: %s', e) 68 return 1 69 70 # Sign data 71 sig = cipher.sign(data) 72 with open(FLAGS.signature_path, 'wb') as signature_file: 73 signature_file.write(binascii.hexlify(sig)) 74 return 0 75 76 # Get the primitive 77 try: 78 cipher = keyset_handle.primitive(signature.PublicKeyVerify) 79 except tink.TinkError as e: 80 logging.exception('Error creating primitive: %s', e) 81 return 1 82 83 # Verify data 84 with open(FLAGS.signature_path, 'rb') as signature_file: 85 try: 86 expected_signature = binascii.unhexlify(signature_file.read().strip()) 87 except binascii.Error as e: 88 logging.exception('Error reading expected code: %s', e) 89 return 1 90 try: 91 cipher.verify(expected_signature, data) 92 logging.info('Signature verification succeeded.') 93 return 0 94 except binascii.Error as e: 95 logging.exception('Error reading expected signature: %s', e) 96 except tink.TinkError as e: 97 logging.info('Signature verification failed.') 98 return 1 99 100 101if __name__ == '__main__': 102 flags.mark_flags_as_required([ 103 'mode', 'keyset_path', 'data_path', 'signature_path']) 104 app.run(main) 105 106# [END digital-signature-example] 107