/usr/bin/yhsm-generate-keys is in yhsm-tools 1.0.4f-1.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | #! /usr/bin/python
#
"""
Tool to generate YubiKey secret keys using YubiHSM.
After generation with this tool, you can (given that you know the AES
key for the key handle used in the HSM) generate a CSV file of the
unencrypted AEADs formatted for YubiKey personalization using the
YubiKey multi configuration utility (Windows) using the command
yhsm-decrypt-aead.
Example :
1) Configure HSM with key handle 99 having key
2000200020002000200020002000200020002000200020002000200020002000
2) Generate 1000 AEADs for YubiKeys using something like this
(XXXX can be a customer specific public_id prefix allocated by Yubico -
0000-0009 (in modhex) are for tests)
$ yhsm-generate-keys --key-handles 99 --start-public-id djXXXXcccccc \
-O /var/cache/yubikey-ksm/aeads --count 1000
3) Create CSV-file with
$ yhsm-decrypt-aead --aes-key 2000...2000 --format yubikey-csv \
/var/cache/yubikey-ksm/aeads
4) Program YubiKeys using CSV file contents
5) Start a KSM to decrypt OTPs from the YubiKeys
$ yhsm-yubikey-ksm --key-handle 99
"""
#
# Copyright (c) 2011, 2012 Yubico AB
# See the file COPYING for licence statement.
#
import os
import sys
import argparse
sys.path.append('Lib')
import pyhsm
import pyhsm.yubikey
default_device = "/dev/ttyACM0"
default_dir = "/var/cache/yubikey-ksm/aeads"
def parse_args():
"""
Parse the command line arguments
"""
parser = argparse.ArgumentParser(description = "Generate secrets for YubiKeys using YubiHSM",
add_help=True,
formatter_class = argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument('-D', '--device',
dest='device',
default=default_device,
required=False,
help='YubiHSM device',
)
parser.add_argument('-O', '--output-dir', '--aead-dir',
dest='output_dir',
default=default_dir,
required=False,
help='Output directory (AEAD base dir)',
)
parser.add_argument('-c', '--count',
dest='count',
type=int, default=1,
required=False,
help='Number of secrets to generate',
)
parser.add_argument('-v', '--verbose',
dest='verbose',
action='store_true', default=False,
help='Enable verbose operation',
)
parser.add_argument('--public-id-chars',
dest='public_id_chars',
type=int, default=12,
required=False,
help='Number of chars in generated public ids',
)
parser.add_argument('--key-handles',
dest='key_handles',
nargs='+',
required=True,
help='Key handles to encrypt the generated secrets with',
)
parser.add_argument('--start-public-id',
dest='start_id',
required=True,
help='The first public id to generate AEAD for',
)
parser.add_argument('--random-nonce',
dest='random_nonce',
required=False,
action='store_true', default=False,
help='Let the HSM generate nonce',
)
return parser.parse_args()
def args_fixup(args):
if not os.path.isdir(args.output_dir):
sys.stderr.write("Output directory '%s' does not exist.\n" % (args.output_dir))
sys.exit(1)
keyhandles_fixup(args)
try:
n = int(args.start_id)
except ValueError:
hexstr = pyhsm.yubikey.modhex_decode(args.start_id)
n = int(hexstr, 16)
if(n <= 0):
sys.stderr.write("Start ID must be greater than 0, was %d\n" % (n))
sys.exit(1)
args.start_id = n
def keyhandles_fixup(args):
"""
Walk through the supplied key handles and normalize them, while keeping
the input format too (as value in a dictionary). The input format is
used in AEAD filename paths.
"""
new_handles = {}
for val in args.key_handles:
for this in val.split(','):
n = pyhsm.util.key_handle_to_int(this)
new_handles[n] = this
args.key_handles = new_handles
def gen_keys(hsm, args):
"""
The main key generating loop.
"""
if args.verbose:
print "Generating %i keys :\n" % (args.count)
else:
print "Generating %i keys" % (args.count)
for int_id in range(args.start_id, args.start_id + args.count):
public_id = ("%x" % int_id).rjust(args.public_id_chars, '0')
padded_id = pyhsm.yubikey.modhex_encode(public_id)
if args.verbose:
print " %s" % (padded_id)
num_bytes = len(pyhsm.aead_cmd.YHSM_YubiKeySecret('a' * 16, 'b' * 6).pack())
hsm.load_random(num_bytes)
for kh in args.key_handles.keys():
if args.random_nonce:
nonce = ""
else:
nonce = public_id.decode('hex')
aead = hsm.generate_aead(public_id.decode('hex'), kh)
filename = output_filename(args.output_dir, args.key_handles[kh], padded_id)
if args.verbose:
print " %4s, %i bytes (%s) -> %s" % \
(args.key_handles[kh], len(aead.data), shorten_aead(aead), filename)
aead.save(filename)
if args.verbose:
print ""
print "\nDone\n"
def shorten_aead(aead):
""" Produce pretty-printable version of long AEAD. """
head = aead.data[:4].encode('hex')
tail = aead.data[-4:].encode('hex')
return "%s...%s" % (head, tail)
def output_filename(output_dir, key_handle, public_id):
"""
Return an output filename for a generated AEAD. Creates a hashed directory structure
using the last three bytes of the public id to get equal usage.
"""
parts = [output_dir, key_handle] + pyhsm.util.group(public_id, 2)
path = os.path.join(*parts)
if not os.path.isdir(path):
os.makedirs(path)
return os.path.join(path, public_id)
def main():
args = parse_args()
args_fixup(args)
print "output dir : %s" % (args.output_dir)
print "keys to generate : %s" % (args.count)
print "key handles : %s" % (args.key_handles)
print "start public_id : %s (0x%x)" % (args.start_id, args.start_id)
print "YHSM device : %s" % (args.device)
print ""
hsm = pyhsm.YHSM(device = args.device)
gen_keys(hsm, args)
if __name__ == '__main__':
if main():
sys.exit(0)
sys.exit(1)
|