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