From 353d7e9f5062e3766a40b1b4c62f7cbfb351205d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikael=20=C3=85gren?= Date: Wed, 23 Apr 2025 14:21:08 +0200 Subject: [PATCH] tkey-libs: Import tag fw-4 of tkey-libs - Use tag fw-4 from https://github.com/tillitis/tkey-libs/ --- .gitignore | 1 + .../application_fpga.bin.sha256 | 2 +- hw/application_fpga/firmware.bin.sha512 | 2 +- hw/application_fpga/tkey-libs/Makefile | 13 +- hw/application_fpga/tkey-libs/README-DIST.txt | 8 +- hw/application_fpga/tkey-libs/README.md | 38 +- hw/application_fpga/tkey-libs/RELEASE.md | 33 +- hw/application_fpga/tkey-libs/REUSE.toml | 16 + hw/application_fpga/tkey-libs/blake2s/LICENSE | 116 ++++++ .../tkey-libs/blake2s/Makefile | 52 +++ .../tkey-libs/blake2s/blake2s.c | 354 ++++++++++++++++++ .../tkey-libs/blake2s/blake2s.h | 45 +++ .../tkey-libs/blake2s/blake2s_test.c | 138 +++++++ .../tkey-libs/include/tkey/assert.h | 5 +- .../tkey-libs/include/tkey/blake2s.h | 22 -- .../tkey-libs/include/tkey/debug.h | 12 +- .../tkey-libs/include/tkey/io.h | 25 +- .../tkey-libs/libcommon/blake2s.c | 14 - hw/application_fpga/tkey-libs/libcommon/io.c | 48 ++- .../tkey-libs/tools/spdx-ensure | 1 + 20 files changed, 864 insertions(+), 81 deletions(-) create mode 100644 hw/application_fpga/tkey-libs/blake2s/LICENSE create mode 100644 hw/application_fpga/tkey-libs/blake2s/Makefile create mode 100644 hw/application_fpga/tkey-libs/blake2s/blake2s.c create mode 100644 hw/application_fpga/tkey-libs/blake2s/blake2s.h create mode 100644 hw/application_fpga/tkey-libs/blake2s/blake2s_test.c delete mode 100644 hw/application_fpga/tkey-libs/include/tkey/blake2s.h delete mode 100644 hw/application_fpga/tkey-libs/libcommon/blake2s.c diff --git a/.gitignore b/.gitignore index 19698e8..6552eaf 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ /testbench_verilator* /check.smt2 /check.vcd +/hw/application_fpga/tkey-libs/libblake2s.a /hw/application_fpga/tkey-libs/libcommon.a /hw/application_fpga/tkey-libs/libcrt0.a /hw/application_fpga/tkey-libs/libmonocypher.a diff --git a/hw/application_fpga/application_fpga.bin.sha256 b/hw/application_fpga/application_fpga.bin.sha256 index ec93b6a..ab89eb4 100644 --- a/hw/application_fpga/application_fpga.bin.sha256 +++ b/hw/application_fpga/application_fpga.bin.sha256 @@ -1 +1 @@ -c770fe25034655241d9e0152b03fcf691c548bc50d30b574a5213abc5b36fe25 application_fpga.bin +3d88184d4d636878d7d891e0360413b47f288eea2227435f0bfa2aad6e956f24 application_fpga.bin diff --git a/hw/application_fpga/firmware.bin.sha512 b/hw/application_fpga/firmware.bin.sha512 index a20a8d6..da6dd76 100644 --- a/hw/application_fpga/firmware.bin.sha512 +++ b/hw/application_fpga/firmware.bin.sha512 @@ -1 +1 @@ -e72557c38bee1e16114f550b16fc04412bfba09274d7b1fe971ab6b2ef4f06421d976276175ea4df3b7d590599eb052b85a812b689d728be5031ae412b2f8d24 firmware.bin +77e6c9e519bce27f7be1a38c10839875ac8c75c71bef540f11569e821638af85a3e724089702a1c17af4c9caa06461ef38a3b8ad5bc5cb01ecf1f3107771708f firmware.bin diff --git a/hw/application_fpga/tkey-libs/Makefile b/hw/application_fpga/tkey-libs/Makefile index a7c08b8..3c1cdf5 100644 --- a/hw/application_fpga/tkey-libs/Makefile +++ b/hw/application_fpga/tkey-libs/Makefile @@ -31,7 +31,7 @@ LDFLAGS=-T app.lds -L libcommon/ -lcommon -L libcrt0/ -lcrt0 .PHONY: all -all: libcrt0.a libcommon.a libmonocypher.a +all: libcrt0.a libcommon.a libmonocypher.a libblake2s.a IMAGE=ghcr.io/tillitis/tkey-builder:4 @@ -48,12 +48,12 @@ libcrt0.a: libcrt0/crt0.o $(AR) -qc $@ libcrt0/crt0.o # Common C functions -LIBOBJS=libcommon/assert.o libcommon/blake2s.o libcommon/led.o libcommon/lib.o \ +LIBOBJS=libcommon/assert.o libcommon/led.o libcommon/lib.o \ libcommon/proto.o libcommon/touch.o libcommon/io.o libcommon.a: $(LIBOBJS) $(AR) -qc $@ $(LIBOBJS) -$(LIBOBJS): include/tkey/assert.h include/tkey/blake2s.h include/tkey/led.h \ +$(LIBOBJS): include/tkey/assert.h include/tkey/led.h \ include/tkey/lib.h include/tkey/proto.h include/tkey/tk1_mem.h \ include/tkey/touch.h include/tkey/debug.h @@ -63,12 +63,19 @@ libmonocypher.a: $(MONOOBJS) $(AR) -qc $@ $(MONOOBJS) $MONOOBJS: monocypher/monocypher-ed25519.h monocypher/monocypher.h +# blake2s +B2OBJS=blake2s/blake2s.o +libblake2s.a: $(B2OBJS) + $(AR) -qc $@ $(B2OBJS) +$B2OBJS: blake2s/blake2s.h + LIBS=libcrt0.a libcommon.a .PHONY: clean clean: rm -f $(LIBS) $(LIBOBJS) libcrt0/crt0.o rm -f libmonocypher.a $(MONOOBJS) + rm -f libblake2s.a $(B2OBJS) # Create compile_commands.json for clangd and LSP .PHONY: clangd diff --git a/hw/application_fpga/tkey-libs/README-DIST.txt b/hw/application_fpga/tkey-libs/README-DIST.txt index e196b01..868e890 100644 --- a/hw/application_fpga/tkey-libs/README-DIST.txt +++ b/hw/application_fpga/tkey-libs/README-DIST.txt @@ -25,5 +25,9 @@ modify it under the terms of the BSD-2-Clause license. See LICENSE for the full BSD-2-Clause license text. -Note that Monocypher is Copyright Loup Vaillant and released under CC0 -1.0 Universal, see monocypher/LICENSE. +Note that: + +- Monocypher is Copyright Loup Vaillant and released under CC0 + 1.0 Universal, see monocypher/LICENSE. +- blake2s is Copyright Markku-Juhani O. Saarinen and released under CC0 + 1.0 Universal, see blake2s/LICENSE. diff --git a/hw/application_fpga/tkey-libs/README.md b/hw/application_fpga/tkey-libs/README.md index a4ead9e..722f4cd 100644 --- a/hw/application_fpga/tkey-libs/README.md +++ b/hw/application_fpga/tkey-libs/README.md @@ -4,13 +4,15 @@ - C runtime: libcrt0. - Common C functions including protocol calls: libcommon. -- Cryptographic functions: libmonocypher. - Based on monocypher version 4.0.2 - https://github.com/LoupVaillant/Monocypher +- Cryptographic functions: libmonocypher. Based on + [Monocypher](https://github.com/LoupVaillant/Monocypher) version + 4.0.2 +- BLAKE2s hash function: libblake2s. Release notes in [RELEASE.md](RELEASE.md). -## Licenses and SPDX tags +## Licenses + Unless otherwise noted, the project sources are copyright Tillitis AB, licensed under the terms and conditions of the "BSD-2-Clause" license. See [LICENSE](LICENSE) for the full license text. @@ -22,6 +24,21 @@ directories. They may be released under other licenses. This is noted with a similar `LICENSE` file in every directory containing imported sources. +Imported sources: + +- [Monocypher](https://github.com/LoupVaillant/Monocypher) (BSD-2) by + Loup Vaillant. + +- blake2s (CC-0), originally based on the reference implementation in + [RFC 7693](https://www.rfc-editor.org/rfc/rfc7693.html) written by + Markku-Juhani O. Saarinen ([original + repository](https://github.com/mjosaarinen/blake2_mjosref). Imported + from [Joachim Strömbergson's + fork](https://github.com/secworks/blake2s/) used as a model for a + hardware implementation. + +### SPDX tags + The project uses single-line references to Unique License Identifiers as defined by the Linux Foundation's [SPDX project](https://spdx.org/) on its own source files, but not necessarily imported files. The line @@ -40,13 +57,18 @@ specification](https://reuse.software/). ### Bellatrix and earlier -Please note that you need to use `uart_write()` and `uart_read()` for -I/O. +Please note that: -If you want debug prints in QEMU you can still use `write(IO_QEMU, -...)`. Avoid using `write()` in other cases. +- For reading, only use the blocking `uart_read()`. + +- Only `IO_UART` and `IO_QEMU` destinations are useful for writing as + in `write(IO_UART, ...)`, `puts(IO_UART, ...)`, and so on. + +- Defining `QEMU_DEBUG` works with all the `debug_*` functions, but + `TKEY_DEBUG` does not. ## Building + In order to build, you must have the `make`, `clang`, `llvm`, and `lld` packages installed. diff --git a/hw/application_fpga/tkey-libs/RELEASE.md b/hw/application_fpga/tkey-libs/RELEASE.md index c119014..347e2dc 100644 --- a/hw/application_fpga/tkey-libs/RELEASE.md +++ b/hw/application_fpga/tkey-libs/RELEASE.md @@ -2,15 +2,38 @@ ## Upcoming release -NOTE WELL! Rewritten I/O functions with new semantics! +- NOTE WELL! Rewritten I/O functions with new signatures and + semantics! +- `blake2s()` with new signature. + +### BLAKE2s hash function + +The `blake2s()` function no longer call the firmware. + +- The `blake2s.h` header file has moved to `blake2s/blake2s.h`. + +- The `blake2s()` hash function has changed signature. It's now defined + as: + + ``` + // All-in-one convenience function. + int blake2s(void *out, size_t outlen, // return buffer for digest + const void *key, size_t keylen, // optional secret key + const void *in, size_t inlen); // data to be hashed + + ``` + +- The component functions `blake2s_init()`, `blake2s_update()`, and + `blake2s_final()` are now available. ### I/O The Castor TKey hardware supports more USB endpoints: - CDC - the same thing as older versions. -- HID security token, for FIDO-like apps. -- CTRL, a HID debug port. +- FIDO security token, for FIDO-like apps. +- CCID, smart card interface. +- DEBUG, a HID debug port. The communication is still over a single UART. To differ between the endpoints we use an internal USB Mode Protocol between programs @@ -18,7 +41,7 @@ running on the PicoRV32 and the CH552 USB Controller. The I/O functions has changed accordingly. Please use: -- `readselect()` with appropriate bitmask (e.g. `IO_CDC|IO_HID`) to +- `readselect()` with appropriate bitmask (e.g. `IO_CDC|IO_FIDO`) to see if there's anything to read in the endpoints you are interested in. Data from endpoints not mentioned in the bitmask will be discarded. @@ -48,7 +71,7 @@ The optionally built debug prints have changed. You now use You define the debug output endpoint when you compile your program by including `debug.h` and defining `QEMU_DEBUG` for the qemu debug port -or `TKEY_DEBUG` for output on the CTRL HID endpoint. If you don't +or `TKEY_DEBUG` for output on the DEBUG HID endpoint. If you don't define either, they won't appear in your code. Similiarly, `assert()` now also follows `QEMU_DEBUG` or `TKEY_DEBUG`, diff --git a/hw/application_fpga/tkey-libs/REUSE.toml b/hw/application_fpga/tkey-libs/REUSE.toml index 2d1e9e3..38daa65 100644 --- a/hw/application_fpga/tkey-libs/REUSE.toml +++ b/hw/application_fpga/tkey-libs/REUSE.toml @@ -21,3 +21,19 @@ path = [ ] SPDX-FileCopyrightText = "2022 Tillitis AB " SPDX-License-Identifier = "BSD-2-Clause" + +[[annotations]] +path = [ + "blake2s/*", +] + +SPDX-FileCopyrightText = "Markku-Juhani O. Saarinen" +SPDX-License-Identifier = "CC0-1.0" + +[[annotations]] +path = [ + "blake2s/Makefile", +] + +SPDX-FileCopyrightText = "2014 Secworks Sweden AB" +SPDX-License-Identifier = "BSD-2-Clause" diff --git a/hw/application_fpga/tkey-libs/blake2s/LICENSE b/hw/application_fpga/tkey-libs/blake2s/LICENSE new file mode 100644 index 0000000..670154e --- /dev/null +++ b/hw/application_fpga/tkey-libs/blake2s/LICENSE @@ -0,0 +1,116 @@ +CC0 1.0 Universal + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator and +subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific +works ("Commons") that the public can reliably and without fear of later +claims of infringement build upon, modify, incorporate in other works, reuse +and redistribute as freely as possible in any form whatsoever and for any +purposes, including without limitation commercial purposes. These owners may +contribute to the Commons to promote the ideal of a free culture and the +further production of creative, cultural and scientific works, or to gain +reputation or greater distribution for their Work in part through the use and +efforts of others. + +For these and/or other purposes and motivations, and without any expectation +of additional consideration or compensation, the person associating CC0 with a +Work (the "Affirmer"), to the extent that he or she is an owner of Copyright +and Related Rights in the Work, voluntarily elects to apply CC0 to the Work +and publicly distribute the Work under its terms, with knowledge of his or her +Copyright and Related Rights in the Work and the meaning and intended legal +effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not limited +to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, communicate, + and translate a Work; + + ii. moral rights retained by the original author(s) and/or performer(s); + + iii. publicity and privacy rights pertaining to a person's image or likeness + depicted in a Work; + + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + + v. rights protecting the extraction, dissemination, use and reuse of data in + a Work; + + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation thereof, + including any amended or successor version of such directive); and + + vii. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, +applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and +unconditionally waives, abandons, and surrenders all of Affirmer's Copyright +and Related Rights and associated claims and causes of action, whether now +known or unknown (including existing as well as future claims and causes of +action), in the Work (i) in all territories worldwide, (ii) for the maximum +duration provided by applicable law or treaty (including future time +extensions), (iii) in any current or future medium and for any number of +copies, and (iv) for any purpose whatsoever, including without limitation +commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes +the Waiver for the benefit of each member of the public at large and to the +detriment of Affirmer's heirs and successors, fully intending that such Waiver +shall not be subject to revocation, rescission, cancellation, termination, or +any other legal or equitable action to disrupt the quiet enjoyment of the Work +by the public as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be +judged legally invalid or ineffective under applicable law, then the Waiver +shall be preserved to the maximum extent permitted taking into account +Affirmer's express Statement of Purpose. In addition, to the extent the Waiver +is so judged Affirmer hereby grants to each affected person a royalty-free, +non transferable, non sublicensable, non exclusive, irrevocable and +unconditional license to exercise Affirmer's Copyright and Related Rights in +the Work (i) in all territories worldwide, (ii) for the maximum duration +provided by applicable law or treaty (including future time extensions), (iii) +in any current or future medium and for any number of copies, and (iv) for any +purpose whatsoever, including without limitation commercial, advertising or +promotional purposes (the "License"). The License shall be deemed effective as +of the date CC0 was applied by Affirmer to the Work. Should any part of the +License for any reason be judged legally invalid or ineffective under +applicable law, such partial invalidity or ineffectiveness shall not +invalidate the remainder of the License, and in such case Affirmer hereby +affirms that he or she will not (i) exercise any of his or her remaining +Copyright and Related Rights in the Work or (ii) assert any associated claims +and causes of action with respect to the Work, in either case contrary to +Affirmer's express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + + b. Affirmer offers the Work as-is and makes no representations or warranties + of any kind concerning the Work, express, implied, statutory or otherwise, + including without limitation warranties of title, merchantability, fitness + for a particular purpose, non infringement, or the absence of latent or + other defects, accuracy, or the present or absence of errors, whether or not + discoverable, all to the greatest extent permissible under applicable law. + + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without limitation + any person's Copyright and Related Rights in the Work. Further, Affirmer + disclaims responsibility for obtaining any necessary consents, permissions + or other rights required for any use of the Work. + + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to this + CC0 or use of the Work. + +For more information, please see + diff --git a/hw/application_fpga/tkey-libs/blake2s/Makefile b/hw/application_fpga/tkey-libs/blake2s/Makefile new file mode 100644 index 0000000..b5bdfd0 --- /dev/null +++ b/hw/application_fpga/tkey-libs/blake2s/Makefile @@ -0,0 +1,52 @@ +#=================================================================== +# +# Makefile +# -------- +# Makefile for building the blake2s model. +# +# +# Author: Joachim Strombergson +# Copyright (c) 2014, Secworks Sweden AB +# All rights reserved. +# +# 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 OWNER 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. +# +#=================================================================== + +SRC = blake2s_test.c blake2s.c +INC = blake2s.h + +CC = clang +CC_FLAGS = -Wall + +blake2s_test: $(SRC) $(INC) + $(CC) $(CC_FLAGS) -o $@ $(SRC) -I $(INC) + + +clean: + rm -f ./blake2s_test + rm -f *.log + rm -f *.txt diff --git a/hw/application_fpga/tkey-libs/blake2s/blake2s.c b/hw/application_fpga/tkey-libs/blake2s/blake2s.c new file mode 100644 index 0000000..6f67dad --- /dev/null +++ b/hw/application_fpga/tkey-libs/blake2s/blake2s.c @@ -0,0 +1,354 @@ +//====================================================================== +// +// blake2s.c +// --------- +// +// A simple BLAKE2s reference implementation. +// +// See LICENSE for license terms. +// See README.md in the repo root for info about source code origin. +//====================================================================== + +#include +#include "blake2s.h" + +#define VERBOSE 0 +#define SHOW_V 0 +#define SHOW_M_WORDS 0 + +#if VERBOSE || SHOW_V || SHOW_M_WORDS +#include +#endif + +// Cyclic right rotation. +#ifndef ROTR32 +#define ROTR32(x, y) (((x) >> (y)) ^ ((x) << (32 - (y)))) +#endif + + +// Little-endian byte access. +#define B2S_GET32(p) \ + (((uint32_t) ((uint8_t *) (p))[0]) ^ \ + (((uint32_t) ((uint8_t *) (p))[1]) << 8) ^ \ + (((uint32_t) ((uint8_t *) (p))[2]) << 16) ^ \ + (((uint32_t) ((uint8_t *) (p))[3]) << 24)) + + +// Initialization Vector. +static const uint32_t blake2s_iv[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +}; + + +#if VERBOSE || SHOW_V +//------------------------------------------------------------------ +//------------------------------------------------------------------ +void print_v(uint32_t *v) { + printf("0x%08x, 0x%08x, 0x%08x, 0x%08x\n", v[0], v[1], v[2], v[3]); + printf("0x%08x, 0x%08x, 0x%08x, 0x%08x\n", v[4], v[5], v[6], v[7]); + printf("0x%08x, 0x%08x, 0x%08x, 0x%08x\n", v[8], v[9], v[10], v[11]); + printf("0x%08x, 0x%08x, 0x%08x, 0x%08x\n", v[12], v[13], v[14], v[15]); + printf("\n"); +} + + +//------------------------------------------------------------------ +// print_ctx() +// Print the contents of the context data structure. +//------------------------------------------------------------------ +void print_ctx(blake2s_ctx *ctx) { + printf("Chained state (h):\n"); + printf("0x%08x, 0x%08x, 0x%08x, 0x%08x, ", + ctx->h[0], ctx->h[1], ctx->h[2], ctx->h[3]); + printf("0x%08x, 0x%08x, 0x%08x, 0x%08x", + ctx->h[4], ctx->h[5], ctx->h[6], ctx->h[7]); + printf("\n"); + + printf("Byte counter (t):\n"); + printf("0x%08x, 0x%08x", ctx->t[0], ctx->t[1]); + printf("\n"); + + printf("\n"); +} + +#endif + +//------------------------------------------------------------------ +// B2S_G macro redefined as a G function. +// Allows us to output intermediate values for debugging. +//------------------------------------------------------------------ +void G(uint32_t *v, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t y) { +#if VERBOSE + printf("G started.\n"); +#endif + +#if SHOW_V + printf("v before processing:\n"); + print_v(&v[0]); +#endif + +#if SHOW_M_WORDS + printf("x: 0x%08x, y: 0x%08x\n", x, y); +#endif + + v[a] = v[a] + v[b] + x; + v[d] = ROTR32(v[d] ^ v[a], 16); + v[c] = v[c] + v[d]; + v[b] = ROTR32(v[b] ^ v[c], 12); + v[a] = v[a] + v[b] + y; + v[d] = ROTR32(v[d] ^ v[a], 8); + v[c] = v[c] + v[d]; + v[b] = ROTR32(v[b] ^ v[c], 7); + +#if SHOW_V + printf("v after processing:\n"); + print_v(&v[0]); +#endif + +#if VERBOSE + printf("G completed.\n\n"); +#endif +} + + +//------------------------------------------------------------------ +// Compression function. "last" flag indicates last block. +//------------------------------------------------------------------ +static void blake2s_compress(blake2s_ctx *ctx, int last) +{ + const uint8_t sigma[10][16] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0} + }; + + int i; + uint32_t v[16], m[16]; + +#if VERBOSE + printf("blake2s_compress started.\n"); +#endif + + // init work variables + for (i = 0; i < 8; i++) { + v[i] = ctx->h[i]; + v[i + 8] = blake2s_iv[i]; + } + + // low 32 bits of offset + // high 32 bits +#if VERBOSE + printf("t[0]: 0x%08x, t[1]: 0x%08x\n", ctx->t[0], ctx->t[1]); +#endif + v[12] ^= ctx->t[0]; + v[13] ^= ctx->t[1]; + + // last block flag set ? + if (last) { + v[14] = ~v[14]; + } + + // get little-endian words + for (i = 0; i < 16; i++) { + m[i] = B2S_GET32(&ctx->b[4 * i]); + } + +#if VERBOSE + printf("v before G processing:\n"); + print_v(&v[0]); +#endif + + // Ten rounds of the G function applied on rows, diagonal. + for (i = 0; i < 10; i++) { +#if VERBOSE + printf("Round %02d:\n", (i + 1)); + printf("Row processing started.\n"); +#endif + + G(&v[0], 0, 4, 8, 12, m[sigma[i][ 0]], m[sigma[i][ 1]]); + G(&v[0], 1, 5, 9, 13, m[sigma[i][ 2]], m[sigma[i][ 3]]); + G(&v[0], 2, 6, 10, 14, m[sigma[i][ 4]], m[sigma[i][ 5]]); + G(&v[0], 3, 7, 11, 15, m[sigma[i][ 6]], m[sigma[i][ 7]]); + +#if VERBOSE + printf("Row processing completed.\n"); + printf("Diagonal processing started.\n"); +#endif + + G(&v[0], 0, 5, 10, 15, m[sigma[i][ 8]], m[sigma[i][ 9]]); + G(&v[0], 1, 6, 11, 12, m[sigma[i][10]], m[sigma[i][11]]); + G(&v[0], 2, 7, 8, 13, m[sigma[i][12]], m[sigma[i][13]]); + G(&v[0], 3, 4, 9, 14, m[sigma[i][14]], m[sigma[i][15]]); + +#if VERBOSE + printf("Diagonal processing completed.\n"); + printf("\n"); +#endif + } + +#if VERBOSE + printf("v after G processing:\n"); + print_v(&v[0]); +#endif + + // Update the hash state. + for (i = 0; i < 8; ++i) { + ctx->h[i] ^= v[i] ^ v[i + 8]; + } + +#if VERBOSE + printf("blake2s_compress completed.\n"); +#endif +} + + +//------------------------------------------------------------------ +// Initialize the hashing context "ctx" with optional key "key". +// 1 <= outlen <= 32 gives the digest size in bytes. +// Secret key (also <= 32 bytes) is optional (keylen = 0). +//------------------------------------------------------------------ +int blake2s_init(blake2s_ctx *ctx, size_t outlen, + const void *key, size_t keylen) // (keylen=0: no key) +{ + size_t i; + +#if VERBOSE + printf("blake2s_init started.\n"); + printf("Context before blake2s_init processing:\n"); + print_ctx(ctx); +#endif + + if (outlen == 0 || outlen > 32 || keylen > 32) + return -1; // illegal parameters + + for (i = 0; i < 8; i++) // state, "param block" + ctx->h[i] = blake2s_iv[i]; + ctx->h[0] ^= 0x01010000 ^ (keylen << 8) ^ outlen; + + ctx->t[0] = 0; // input count low word + ctx->t[1] = 0; // input count high word + ctx->c = 0; // pointer within buffer + ctx->outlen = outlen; + + for (i = keylen; i < 64; i++) // zero input block + ctx->b[i] = 0; + if (keylen > 0) { + blake2s_update(ctx, key, keylen); + ctx->c = 64; // at the end + } + +#if VERBOSE + printf("Context after blake2s_init processing:\n"); + print_ctx(ctx); + printf("blake2s_init completed.\n"); +#endif + + return 0; +} + + +//------------------------------------------------------------------ +// Add "inlen" bytes from "in" into the hash. +//------------------------------------------------------------------ +void blake2s_update(blake2s_ctx *ctx, + const void *in, size_t inlen) // data bytes +{ + size_t i; + +#if VERBOSE + printf("blake2s_update started.\n"); + printf("Context before blake2s_update processing:\n"); + print_ctx(ctx); +#endif + + for (i = 0; i < inlen; i++) { + if (ctx->c == 64) { // buffer full ? + ctx->t[0] += ctx->c; // add counters + if (ctx->t[0] < ctx->c) // carry overflow ? + ctx->t[1]++; // high word + blake2s_compress(ctx, 0); // compress (not last) + ctx->c = 0; // counter to zero + } + ctx->b[ctx->c++] = ((const uint8_t *) in)[i]; + } + +#if VERBOSE + printf("Context after blake2s_update processing:\n"); + print_ctx(ctx); + printf("blake2s_update completed.\n"); +#endif +} + + +//------------------------------------------------------------------ +// Generate the message digest (size given in init). +// Result placed in "out". +//------------------------------------------------------------------ +void blake2s_final(blake2s_ctx *ctx, void *out) +{ + size_t i; + +#if VERBOSE + printf("blake2s_final started.\n"); + printf("Context before blake2s_final processing:\n"); + print_ctx(ctx); +#endif + + ctx->t[0] += ctx->c; // mark last block offset + + // carry overflow + // high word + if (ctx->t[0] < ctx->c) { + ctx->t[1]++; + } + + // fill up with zeros + // final block flag = 1 + while (ctx->c < 64) { + ctx->b[ctx->c++] = 0; + } + blake2s_compress(ctx, 1); + + // little endian convert and store + for (i = 0; i < ctx->outlen; i++) { + ((uint8_t *) out)[i] = + (ctx->h[i >> 2] >> (8 * (i & 3))) & 0xFF; + } + +#if VERBOSE + printf("Context after blake2s_final processing:\n"); + print_ctx(ctx); + printf("blake2s_final completed.\n"); +#endif +} + + +//------------------------------------------------------------------ +// Convenience function for all-in-one computation. +//------------------------------------------------------------------ +int blake2s(void *out, size_t outlen, + const void *key, size_t keylen, + const void *in, size_t inlen) +{ + blake2s_ctx ctx; + + if (blake2s_init(&ctx, outlen, key, keylen)) + return -1; + + blake2s_update(&ctx, in, inlen); + + blake2s_final(&ctx, out); + + return 0; +} + +//====================================================================== +//====================================================================== diff --git a/hw/application_fpga/tkey-libs/blake2s/blake2s.h b/hw/application_fpga/tkey-libs/blake2s/blake2s.h new file mode 100644 index 0000000..888fc20 --- /dev/null +++ b/hw/application_fpga/tkey-libs/blake2s/blake2s.h @@ -0,0 +1,45 @@ +//====================================================================== +// +// blake2s.h +// --------- +// BLAKE2s Hashing Context and API Prototypes +// +// See LICENSE for license terms. +// See README.md in the repo root for info about source code origin. +//====================================================================== + +#ifndef BLAKE2S_H +#define BLAKE2S_H + +#include +#include + +// state context +typedef struct { + uint8_t b[64]; // input buffer + uint32_t h[8]; // chained state + uint32_t t[2]; // total number of bytes + size_t c; // pointer for b[] + size_t outlen; // digest size +} blake2s_ctx; + +// Initialize the hashing context "ctx" with optional key "key". +// 1 <= outlen <= 32 gives the digest size in bytes. +// Secret key (also <= 32 bytes) is optional (keylen = 0). +int blake2s_init(blake2s_ctx *ctx, size_t outlen, + const void *key, size_t keylen); // secret key + +// Add "inlen" bytes from "in" into the hash. +void blake2s_update(blake2s_ctx *ctx, // context + const void *in, size_t inlen); // data to be hashed + +// Generate the message digest (size given in init). +// Result placed in "out". +void blake2s_final(blake2s_ctx *ctx, void *out); + +// All-in-one convenience function. +int blake2s(void *out, size_t outlen, // return buffer for digest + const void *key, size_t keylen, // optional secret key + const void *in, size_t inlen); // data to be hashed + +#endif diff --git a/hw/application_fpga/tkey-libs/blake2s/blake2s_test.c b/hw/application_fpga/tkey-libs/blake2s/blake2s_test.c new file mode 100644 index 0000000..d735a82 --- /dev/null +++ b/hw/application_fpga/tkey-libs/blake2s/blake2s_test.c @@ -0,0 +1,138 @@ +//====================================================================== +// +// blake2s_test.c +// -------------- +// +//====================================================================== + +#include +#include "blake2s.h" + + +//------------------------------------------------------------------ +//------------------------------------------------------------------ +void print_message(uint8_t *m, int mlen) { + printf("The message:\n"); + for (int i = 1 ; i <= mlen ; i++) { + printf("0x%02x ", m[(i - 1)]); + if (i % 8 == 0) { + printf("\n"); + } + } + printf("\n"); +} + + +//------------------------------------------------------------------ +//------------------------------------------------------------------ +void print_digest(uint8_t *md) { + printf("The digest:\n"); + for (int j = 0 ; j < 4 ; j++) { + for (int i = 0 ; i < 8 ; i++) { + printf("0x%02x ", md[i + 8 * j]); + } + printf("\n"); + } + printf("\n"); +} + + +//------------------------------------------------------------------ +// test_zero_length() +// Test with a zero length mwssage. +//------------------------------------------------------------------ +void test_zero_length() { + + uint8_t md[32]; + + printf("Testing zero byte message.\n"); + blake2s(md, 32, NULL, 0, NULL, 0); + print_digest(md); + printf("\n"); +} + + +//------------------------------------------------------------------ +// test_abc_message() +// Test with a zero length mwssage. +//------------------------------------------------------------------ +void test_abc_message() { + + uint8_t md[32]; + uint8_t msg[64] = {'a', 'b', 'c'}; + + printf("Testing with RFC 7693 three byte 'abc' message.\n"); + print_message(msg, 3); + + blake2s(md, 32, NULL, 0, msg, 3); + print_digest(md); + printf("\n"); +} + + +//------------------------------------------------------------------ +// test_one_block_message() +// Test with a 64 byte message, filling one block. +//------------------------------------------------------------------ +void test_one_block_message() { + + uint8_t md[32]; + uint8_t msg[64]; + + for (uint8_t i = 0 ; i < 64 ; i++) { + msg[i] = i; + } + + printf("Testing with 64 byte message.\n"); + print_message(msg, 64); + + blake2s(md, 32, NULL, 0, msg, 64); + print_digest(md); + printf("\n"); +} + + +//------------------------------------------------------------------ +// test_one_block_one_byte_message() +// Test with a 65 byte message, filling one block and a single +// byte in the next block. +//------------------------------------------------------------------ +void test_one_block_one_byte_message() { + + uint8_t md[32]; + uint8_t msg[65]; + + for (uint8_t i = 0 ; i < 65 ; i++) { + msg[i] = i; + } + + printf("Testing with 65 byte message.\n"); + print_message(msg, 65); + + blake2s(md, 32, NULL, 0, msg, 65); + print_digest(md); + printf("\n"); +} + + +//------------------------------------------------------------------ +//------------------------------------------------------------------ +int main(void) { + printf("\n"); + printf("BLAKE2s reference model started. Performing a set of tests..\n"); + printf("Performing a set of tests.\n"); + + test_zero_length(); + test_abc_message(); + test_one_block_message(); + test_one_block_one_byte_message(); + + printf("BLAKE2s reference model completed.\n"); + printf("\n"); + + return 0; +} + +//====================================================================== +/// EOF blake2s_test.c +//====================================================================== diff --git a/hw/application_fpga/tkey-libs/include/tkey/assert.h b/hw/application_fpga/tkey-libs/include/tkey/assert.h index dc3fd94..3039123 100644 --- a/hw/application_fpga/tkey-libs/include/tkey/assert.h +++ b/hw/application_fpga/tkey-libs/include/tkey/assert.h @@ -14,9 +14,8 @@ #elif defined(TKEY_DEBUG) #define assert(expr) \ - ((expr) \ - ? (void)(0) \ - : assert_fail(IO_TKEYCTRL, #expr, __FILE__, __LINE__, __func__)) + ((expr) ? (void)(0) \ + : assert_fail(IO_DEBUG, #expr, __FILE__, __LINE__, __func__)) #else diff --git a/hw/application_fpga/tkey-libs/include/tkey/blake2s.h b/hw/application_fpga/tkey-libs/include/tkey/blake2s.h deleted file mode 100644 index f0e0c59..0000000 --- a/hw/application_fpga/tkey-libs/include/tkey/blake2s.h +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Tillitis AB -// SPDX-License-Identifier: BSD-2-Clause - -#ifndef TKEY_BLAKE2S_H -#define TKEY_BLAKE2S_H - -#include -#include - -// blake2s state context -typedef struct { - uint8_t b[64]; // input buffer - uint32_t h[8]; // chained state - uint32_t t[2]; // total number of bytes - size_t c; // pointer for b[] - size_t outlen; // digest size -} blake2s_ctx; - -int blake2s(void *out, unsigned long outlen, const void *key, - unsigned long keylen, const void *in, unsigned long inlen, - blake2s_ctx *ctx); -#endif diff --git a/hw/application_fpga/tkey-libs/include/tkey/debug.h b/hw/application_fpga/tkey-libs/include/tkey/debug.h index 5c24c6a..11e530c 100644 --- a/hw/application_fpga/tkey-libs/include/tkey/debug.h +++ b/hw/application_fpga/tkey-libs/include/tkey/debug.h @@ -18,12 +18,12 @@ #elif defined(TKEY_DEBUG) -#define debug_putchar(ch) putchar(IO_TKEYCTRL, ch) -#define debug_lf() putchar(IO_TKEYCTRL, '\n') -#define debug_putinthex(ch) putinthex(IO_TKEYCTRL, ch) -#define debug_puts(s) puts(IO_TKEYCTRL, s) -#define debug_puthex(ch) puthex(IO_TKEYCTRL, ch) -#define debug_hexdump(buf, len) hexdump(IO_TKEYCTRL, buf, len) +#define debug_putchar(ch) putchar(IO_DEBUG, ch) +#define debug_lf() putchar(IO_DEBUG, '\n') +#define debug_putinthex(ch) putinthex(IO_DEBUG, ch) +#define debug_puts(s) puts(IO_DEBUG, s) +#define debug_puthex(ch) puthex(IO_DEBUG, ch) +#define debug_hexdump(buf, len) hexdump(IO_DEBUG, buf, len) #else diff --git a/hw/application_fpga/tkey-libs/include/tkey/io.h b/hw/application_fpga/tkey-libs/include/tkey/io.h index 67aa8d0..60c5f60 100644 --- a/hw/application_fpga/tkey-libs/include/tkey/io.h +++ b/hw/application_fpga/tkey-libs/include/tkey/io.h @@ -10,15 +10,22 @@ // I/O endpoints. Keep it as bits possible to use in a bitmask in // readselect(). // -// Note that the the TKEYCTRL, CDC, and HID should be kept the same on -// the CH552 side. +// Note that the values for IO_CH552, IO_CDC, IO_FIDO, IO_CCID and IO_DEBUG +// should be kept the same in the code for the CH552 side. enum ioend { - IO_NONE = 0x00, // No endpoint - IO_UART = 0x01, // Only destination, raw UART access - IO_QEMU = 0x10, // Only destination, QEMU debug port - IO_TKEYCTRL = 0x20, // HID debug port - IO_CDC = 0x40, // CDC "serial port" - IO_HID = 0x80, // HID security token + IO_NONE = 0x00, // No endpoint + IO_UART = 0x01, // Only destination, raw UART access + IO_QEMU = 0x02, // Only destination, QEMU debug port + IO_CH552 = 0x04, // Internal CH552 control port + IO_CDC = 0x08, // CDC "serial" port + IO_FIDO = 0x10, // FIDO security token port + IO_CCID = 0x20, // CCID "smart card" port + IO_DEBUG = 0x40, // Debug port over USB HID +}; + +enum ch552cmd { + SET_ENDPOINTS = 0x01, // Config USB endpoints on the CH552 + CH552_CMD_MAX, }; void write(enum ioend dest, const uint8_t *buf, size_t nbytes); @@ -30,4 +37,6 @@ void puthex(enum ioend dest, const uint8_t ch); void putinthex(enum ioend dest, const uint32_t n); void puts(enum ioend dest, const char *s); void hexdump(enum ioend dest, void *buf, int len); +void config_endpoints(enum ioend endpoints); + #endif diff --git a/hw/application_fpga/tkey-libs/libcommon/blake2s.c b/hw/application_fpga/tkey-libs/libcommon/blake2s.c deleted file mode 100644 index 828c10c..0000000 --- a/hw/application_fpga/tkey-libs/libcommon/blake2s.c +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Tillitis AB -// SPDX-License-Identifier: BSD-2-Clause - -#include -#include -#include - -int blake2s(void *out, unsigned long outlen, const void *key, - unsigned long keylen, const void *in, unsigned long inlen, - blake2s_ctx *ctx) -{ - // Not implemented. - return -1; -} diff --git a/hw/application_fpga/tkey-libs/libcommon/io.c b/hw/application_fpga/tkey-libs/libcommon/io.c index 77ca924..03d67a1 100644 --- a/hw/application_fpga/tkey-libs/libcommon/io.c +++ b/hw/application_fpga/tkey-libs/libcommon/io.c @@ -74,15 +74,20 @@ static void write_with_header(enum ioend dest, const uint8_t *buf, // write blockingly writes nbytes bytes of data from buf to dest which // is either: // +// - IO_UART: Low-level UART access, no USB Mode Header added. +// // - IO_QEMU: QEMU debug port // -// - IO_UART: Low-level UART access, no USB Mode Header added. +// - IO_CH552: Internal communication between the FPGA and the +// CH552, with header. // // - IO_CDC: Through the UART for the CDC endpoint, with header. // -// - IO_HID: Through the UART for the HID endpoint, with header. +// - IO_FIDO: Through the UART for the FIDO endpoint, with header. // -// - IO_TKEYCTRL: Through the UART for the debug HID endpoint, with +// - IO_CCID: Through the UART for the CCID endpoint, with header. +// +// - IO_DEBUG: Through the UART for the DEBUG endpoint (USB HID), with // header. void write(enum ioend dest, const uint8_t *buf, size_t nbytes) { @@ -194,18 +199,20 @@ static int discard(size_t nbytes) // // Use like this: // -// readselect(IO_CDC|IO_HID, &endpoint, &len) +// readselect(IO_CDC|IO_FIDO, &endpoint, &len) // -// to wait for some data from either the CDC or the HID endpoint. +// to wait for some data from either the CDC or the FIDO endpoint. // // NOTE WELL: You need to call readselect() first, before doing any // calls to read(). // // Only endpoints available for read are: // -// - IO_TKEYCTRL +// - IO_CH552 // - IO_CDC -// - IO_HID +// - IO_FIDO +// - IO_CCID +// - IO_DEBUG // // If you need blocking low-level UART reads, use uart_read() instead. // @@ -215,7 +222,7 @@ static int discard(size_t nbytes) // Returns non-zero on error. int readselect(int bitmask, enum ioend *endpoint, uint8_t *len) { - if (bitmask & IO_UART || bitmask & IO_QEMU) { + if ((bitmask & IO_UART) || (bitmask & IO_QEMU)) { // Not possible to use readselect() on these // endpoints. return -1; @@ -348,3 +355,28 @@ void hexdump(enum ioend dest, void *buf, int len) write(dest, rowbuf, rowpos); } } + +// Configure USB endpoints that should be enabled/disabled +// +// Allowed options are: +// - IO_FIDO (can't be used used together with IO_CCID) +// - IO_CCID (can't be used used together with IO_FIDO) +// - IO_DEBUG +// +// The following are always enabled: +// - IO_CDC +// - IO_CH552 +// +// Use like this: +// +// config_endpoints(IO_FIDO|IO_DEBUG) +// +void config_endpoints(enum ioend endpoints) +{ + uint8_t cmdbuf[2] = {0}; + + cmdbuf[0] = SET_ENDPOINTS; + cmdbuf[1] = endpoints; + + write(IO_CH552, cmdbuf, 2); +} diff --git a/hw/application_fpga/tkey-libs/tools/spdx-ensure b/hw/application_fpga/tkey-libs/tools/spdx-ensure index 853868d..28267f4 100755 --- a/hw/application_fpga/tkey-libs/tools/spdx-ensure +++ b/hw/application_fpga/tkey-libs/tools/spdx-ensure @@ -29,6 +29,7 @@ RELEASE.md example-app/Makefile monocypher/LICENSE monocypher/README.md +blake2s/* ) is_missingok() {