1# Copyright 2019 Google Inc. All Rights Reserved. 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# [START mac-example] 15"""A command-line utility for checking file integrity with a Message Authentication Code (MAC). 16 17It loads cleartext keys from disk - this is not recommended! 18""" 19 20import binascii 21 22from absl import app 23from absl import flags 24from absl import logging 25import tink 26from tink import cleartext_keyset_handle 27from tink import mac 28 29FLAGS = flags.FLAGS 30 31flags.DEFINE_enum('mode', None, ['compute', 'verify'], 32 'The operation to perform.') 33flags.DEFINE_string('keyset_path', None, 34 'Path to the keyset used for the MAC operation.') 35flags.DEFINE_string('data_path', None, 36 'Path to the file with the input data to be checked.') 37flags.DEFINE_string('mac_path', None, 38 'Path to the file containing a hexadecimal MAC of the' 39 ' data.') 40 41 42def main(argv): 43 del argv # Unused. 44 45 # Initialise Tink. 46 mac.register() 47 48 # Read the keyset into a keyset_handle. 49 with open(FLAGS.keyset_path, 'rt') as keyset_file: 50 try: 51 text = keyset_file.read() 52 keyset_handle = cleartext_keyset_handle.read(tink.JsonKeysetReader(text)) 53 except tink.TinkError as e: 54 logging.error('Error reading key: %s', e) 55 return 1 56 57 # Get the primitive. 58 try: 59 primitive = keyset_handle.primitive(mac.Mac) 60 except tink.TinkError as e: 61 logging.error('Error creating primitive: %s', e) 62 return 1 63 64 with open(FLAGS.data_path, 'rb') as data_file: 65 data = data_file.read() 66 67 if FLAGS.mode == 'compute': 68 # Compute the MAC. 69 tag = primitive.compute_mac(data) 70 with open(FLAGS.mac_path, 'wb') as mac_file: 71 mac_file.write(binascii.hexlify(tag)) 72 return 0 73 74 with open(FLAGS.mac_path, 'rb') as mac_file: 75 try: 76 expected_tag = binascii.unhexlify(mac_file.read().strip()) 77 except binascii.Error as e: 78 logging.exception('Error reading expected tag: %s', e) 79 return 1 80 81 try: 82 primitive.verify_mac(expected_tag, data) 83 logging.info('MAC verification succeeded.') 84 return 0 85 except tink.TinkError as e: 86 logging.info('MAC verification failed.') 87 return 1 88 89 90if __name__ == '__main__': 91 flags.mark_flags_as_required([ 92 'mode', 'keyset_path', 'data_path', 'mac_path']) 93 app.run(main) 94# [END mac-example] 95