tkey-libs: Import tag fw-4 of tkey-libs

- Use tag fw-4 from https://github.com/tillitis/tkey-libs/
This commit is contained in:
Mikael Ågren 2025-04-23 14:21:08 +02:00
parent f75620720f
commit 353d7e9f50
No known key found for this signature in database
GPG key ID: E02DA3D397792C46
20 changed files with 864 additions and 81 deletions

1
.gitignore vendored
View file

@ -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

View file

@ -1 +1 @@
c770fe25034655241d9e0152b03fcf691c548bc50d30b574a5213abc5b36fe25 application_fpga.bin
3d88184d4d636878d7d891e0360413b47f288eea2227435f0bfa2aad6e956f24 application_fpga.bin

View file

@ -1 +1 @@
e72557c38bee1e16114f550b16fc04412bfba09274d7b1fe971ab6b2ef4f06421d976276175ea4df3b7d590599eb052b85a812b689d728be5031ae412b2f8d24 firmware.bin
77e6c9e519bce27f7be1a38c10839875ac8c75c71bef540f11569e821638af85a3e724089702a1c17af4c9caa06461ef38a3b8ad5bc5cb01ecf1f3107771708f firmware.bin

View file

@ -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

View file

@ -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.

View file

@ -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.

View file

@ -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`,

View file

@ -21,3 +21,19 @@ path = [
]
SPDX-FileCopyrightText = "2022 Tillitis AB <tillitis.se>"
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"

View file

@ -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
<http://creativecommons.org/publicdomain/zero/1.0/>

View file

@ -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

View file

@ -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 <stdint.h>
#include "blake2s.h"
#define VERBOSE 0
#define SHOW_V 0
#define SHOW_M_WORDS 0
#if VERBOSE || SHOW_V || SHOW_M_WORDS
#include <stdio.h>
#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;
}
//======================================================================
//======================================================================

View file

@ -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 <stdint.h>
#include <stddef.h>
// 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

View file

@ -0,0 +1,138 @@
//======================================================================
//
// blake2s_test.c
// --------------
//
//======================================================================
#include <stdio.h>
#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
//======================================================================

View file

@ -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

View file

@ -1,22 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#ifndef TKEY_BLAKE2S_H
#define TKEY_BLAKE2S_H
#include <stddef.h>
#include <stdint.h>
// 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

View file

@ -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

View file

@ -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

View file

@ -1,14 +0,0 @@
// SPDX-FileCopyrightText: 2023 Tillitis AB <tillitis.se>
// SPDX-License-Identifier: BSD-2-Clause
#include <stdint.h>
#include <tkey/blake2s.h>
#include <tkey/tk1_mem.h>
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;
}

View file

@ -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);
}

View file

@ -29,6 +29,7 @@ RELEASE.md
example-app/Makefile
monocypher/LICENSE
monocypher/README.md
blake2s/*
)
is_missingok() {