mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2025-05-02 06:06:24 -04:00
Make initial public release
This commit is contained in:
commit
715de60f4a
251 changed files with 881225 additions and 0 deletions
26
hw/application_fpga/tools/makehex/makehex.py
Normal file
26
hw/application_fpga/tools/makehex/makehex.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# This is free and unencumbered software released into the public domain.
|
||||
#
|
||||
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
# distribute this software, either in source code form or as a compiled
|
||||
# binary, for any purpose, commercial or non-commercial, and by any
|
||||
# means.
|
||||
|
||||
from sys import argv
|
||||
|
||||
binfile = argv[1]
|
||||
nwords = int(argv[2])
|
||||
|
||||
with open(binfile, "rb") as f:
|
||||
bindata = f.read()
|
||||
|
||||
assert len(bindata) < 4*nwords
|
||||
assert len(bindata) % 4 == 0
|
||||
|
||||
for i in range(nwords):
|
||||
if i < len(bindata) // 4:
|
||||
w = bindata[4*i : 4*i+4]
|
||||
print("%02x%02x%02x%02x" % (w[3], w[2], w[1], w[0]))
|
||||
else:
|
||||
print("0")
|
8
hw/application_fpga/tools/tpt/README.md
Normal file
8
hw/application_fpga/tools/tpt/README.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Tillitis Key Provisioning Tool
|
||||
|
||||
## Introduction
|
||||
Tillis Key Provisioning Tool (tpt) is a program for generating the 32 byte Unique Device Secret (UDS). The tool will also generate the 8 byte Unique Device Identity. Both the UDS and the UDI are injected into the FPGA bitstream file during build.
|
||||
|
||||
The UDS is generated using HKDF (RFC 5869), and the user is expected to supply a secret as part of the input to the HKDF Extract operation. The Input Keying Material is generated by extracting 256 bytes using the Python secrets module.
|
||||
|
||||
The tool uses [python-hkdf](https://github.com/casebeer/python-hkdf).
|
0
hw/application_fpga/tools/tpt/__init__.py
Normal file
0
hw/application_fpga/tools/tpt/__init__.py
Normal file
95
hw/application_fpga/tools/tpt/hkdf.py
Normal file
95
hw/application_fpga/tools/tpt/hkdf.py
Normal file
|
@ -0,0 +1,95 @@
|
|||
# Copyright (c) 2012 Christopher H. Casebeer. All rights reserved.
|
||||
# SPDX-License-Identifier: BSD-2
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from __future__ import division
|
||||
|
||||
import hmac
|
||||
import hashlib
|
||||
import sys
|
||||
|
||||
if sys.version_info[0] == 3:
|
||||
buffer = lambda x: x
|
||||
|
||||
def hkdf_extract(salt, input_key_material, hash=hashlib.sha512):
|
||||
'''
|
||||
Extract a pseudorandom key suitable for use with hkdf_expand
|
||||
from the input_key_material and a salt using HMAC with the
|
||||
provided hash (default SHA-512).
|
||||
|
||||
salt should be a random, application-specific byte string. If
|
||||
salt is None or the empty string, an all-zeros string of the same
|
||||
length as the hash's block size will be used instead per the RFC.
|
||||
|
||||
See the HKDF draft RFC and paper for usage notes.
|
||||
'''
|
||||
hash_len = hash().digest_size
|
||||
if salt == None or len(salt) == 0:
|
||||
salt = bytearray((0,) * hash_len)
|
||||
return hmac.new(bytes(salt), buffer(input_key_material), hash).digest()
|
||||
|
||||
def hkdf_expand(pseudo_random_key, info=b"", length=32, hash=hashlib.sha512):
|
||||
'''
|
||||
Expand `pseudo_random_key` and `info` into a key of length `bytes` using
|
||||
HKDF's expand function based on HMAC with the provided hash (default
|
||||
SHA-512). See the HKDF draft RFC and paper for usage notes.
|
||||
'''
|
||||
hash_len = hash().digest_size
|
||||
length = int(length)
|
||||
if length > 255 * hash_len:
|
||||
raise Exception("Cannot expand to more than 255 * %d = %d bytes using the specified hash function" %\
|
||||
(hash_len, 255 * hash_len))
|
||||
blocks_needed = length // hash_len + (0 if length % hash_len == 0 else 1) # ceil
|
||||
okm = b""
|
||||
output_block = b""
|
||||
for counter in range(blocks_needed):
|
||||
output_block = hmac.new(pseudo_random_key, buffer(output_block + info + bytearray((counter + 1,))),\
|
||||
hash).digest()
|
||||
okm += output_block
|
||||
return okm[:length]
|
||||
|
||||
class Hkdf(object):
|
||||
'''
|
||||
Wrapper class for HKDF extract and expand functions
|
||||
'''
|
||||
def __init__(self, salt, input_key_material, hash=hashlib.sha256):
|
||||
'''
|
||||
Extract a pseudorandom key from `salt` and `input_key_material` arguments.
|
||||
|
||||
See the HKDF draft RFC for guidance on setting these values. The constructor
|
||||
optionally takes a `hash` arugment defining the hash function use,
|
||||
defaulting to hashlib.sha256.
|
||||
'''
|
||||
self._hash = hash
|
||||
self._prk = hkdf_extract(salt, input_key_material, self._hash)
|
||||
def expand(self, info=b"", length=32):
|
||||
'''
|
||||
Generate output key material based on an `info` value
|
||||
|
||||
Arguments:
|
||||
- info - context to generate the OKM
|
||||
- length - length in bytes of the key to generate
|
||||
|
||||
See the HKDF draft RFC for guidance.
|
||||
'''
|
||||
return hkdf_expand(self._prk, info, length, self._hash)
|
129
hw/application_fpga/tools/tpt/tpt.py
Executable file
129
hw/application_fpga/tools/tpt/tpt.py
Executable file
|
@ -0,0 +1,129 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#=======================================================================
|
||||
#
|
||||
# tpt.py
|
||||
# ------
|
||||
# TillitisKey Provisioning Tool.
|
||||
#
|
||||
# The tool use HKDF (RFC5869) to generate the UDS.
|
||||
#
|
||||
# Copyright (C) 2022 - Tillitis AB
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
#=======================================================================
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
from secrets import token_bytes
|
||||
from binascii import unhexlify
|
||||
from hkdf import Hkdf
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
#-------------------------------------------------------------------
|
||||
def gen_uds(verbose, arg_uss):
|
||||
if verbose:
|
||||
print("\nGenerating UDS")
|
||||
|
||||
if arg_uss == None:
|
||||
uss = str.encode(input("Enter user supplied secret: "))
|
||||
else:
|
||||
uss = str.encode(arg_uss)
|
||||
|
||||
ikm = token_bytes(256)
|
||||
my_hkdf = Hkdf(uss, ikm)
|
||||
uds = my_hkdf.expand(b"TillitisKey UDS", 32)
|
||||
uds_hex = uds.hex()
|
||||
|
||||
if verbose:
|
||||
print("\nGenerated UDS:")
|
||||
print(uds_hex, "\n")
|
||||
|
||||
return uds_hex
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
#-------------------------------------------------------------------
|
||||
def save_uds(verbose, uds):
|
||||
if verbose:
|
||||
print("Writing uds.hex")
|
||||
|
||||
with open ("uds.hex", 'w', encoding = 'utf-8') as uds_file:
|
||||
for i in range(8):
|
||||
uds_file.write(uds[(i*8) : (i*8 + 8)]+"\n")
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
#-------------------------------------------------------------------
|
||||
def gen_udi(verbose, pid, vid, rev, serial):
|
||||
if verbose:
|
||||
print("Generating UDI")
|
||||
|
||||
if vid == None:
|
||||
vid = int(input("Enter Vendor ID (0 - 65535): "))
|
||||
|
||||
if pid == None:
|
||||
pid = int(input("Enter Product ID (0 - 255): "))
|
||||
|
||||
if rev == None:
|
||||
rev = int(input("Enter revision (0 - 15): "))
|
||||
|
||||
if serial == None:
|
||||
serial = int(input("Enter serial number (0 - (2**32 -1)): "))
|
||||
|
||||
assert vid < 65536
|
||||
assert pid < 256
|
||||
assert rev < 16
|
||||
assert serial < 2**32
|
||||
|
||||
udi_hex = ("0%04x%02x%1x%08x" % (vid, pid, rev, serial))
|
||||
|
||||
if verbose:
|
||||
print("\nGenerated UDI:")
|
||||
print(udi_hex, "\n")
|
||||
|
||||
return udi_hex
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
#-------------------------------------------------------------------
|
||||
def save_udi(verbose, udi):
|
||||
if verbose:
|
||||
print("Writing udi.hex")
|
||||
|
||||
with open ("udi.hex", 'w', encoding = 'utf-8') as udi_file:
|
||||
udi_file.write(udi[0 : 8] + "\n")
|
||||
udi_file.write(udi[8 : 16] + "\n")
|
||||
|
||||
def enc_str(b):
|
||||
return bytestring.decode(sys.getfilesystemencoding())
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
#-------------------------------------------------------------------
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-v", "--verbose", help="Verbose operation", action="store_true")
|
||||
parser.add_argument("--uss", help="User supplied secret", type=str)
|
||||
parser.add_argument("--vid", help="Vendor id (0 - 65535)", type=int)
|
||||
parser.add_argument("--pid", help="Product id (0 - 2555", type=int)
|
||||
parser.add_argument("--rev", help="Revision number (0 - 15)", type=int)
|
||||
parser.add_argument("--serial", help="Serial number (0 - (2**31 - 1))", type=int)
|
||||
args = parser.parse_args()
|
||||
|
||||
print(args)
|
||||
|
||||
if args.verbose:
|
||||
print("TillitisKey Provisining Tool (TPT)")
|
||||
|
||||
uds = gen_uds(args.verbose, args.uss)
|
||||
save_uds(args.verbose, uds)
|
||||
|
||||
udi = gen_udi(args.verbose, args.pid, args.vid, args.rev, args.serial)
|
||||
save_udi(args.verbose, udi)
|
||||
|
||||
|
||||
#-------------------------------------------------------------------
|
||||
#-------------------------------------------------------------------
|
||||
if __name__=="__main__":
|
||||
sys.exit(main())
|
Loading…
Add table
Add a link
Reference in a new issue