Make initial public release

This commit is contained in:
Joachim Strömbergson 2022-09-19 08:51:11 +02:00 committed by Daniel Lublin
commit 715de60f4a
251 changed files with 881225 additions and 0 deletions

View 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")

View 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).

View 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)

View 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())