Add age implementation to tree
... and fix ALL the warnings
This commit is contained in:
parent
7bc4391185
commit
4642dd4aa1
12 changed files with 4626 additions and 10 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -17,3 +17,6 @@
|
|||
[submodule "upstream/CMSIS_5"]
|
||||
path = upstream/CMSIS_5
|
||||
url = https://github.com/ARM-software/CMSIS_5
|
||||
[submodule "upstream/mbedtls"]
|
||||
path = upstream/mbedtls
|
||||
url = https://github.com/ARMmbed/mbedtls
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
CUBE_CMSIS_DIR ?= ../../upstream/cmsis_device_f4
|
||||
CMSIS_DIR ?= ../../upstream/CMSIS_5
|
||||
MUSL_DIR ?= ../../upstream/musl
|
||||
MBEDTLS_DIR ?= ../../upstream/mbedtls
|
||||
|
||||
########################################################################################################################
|
||||
# Sources
|
||||
|
|
@ -17,6 +18,9 @@ C_SOURCES += src/serial.c
|
|||
C_SOURCES += src/spi.c
|
||||
C_SOURCES += src/gpio_helpers.c
|
||||
C_SOURCES += src/dma_util.c
|
||||
C_SOURCES += src/cage.c
|
||||
C_SOURCES += src/cage_base64.c
|
||||
C_SOURCES += src/bech32.c
|
||||
C_SOURCES += tinyprintf/tinyprintf.c
|
||||
|
||||
MUSL_SOURCES :=
|
||||
|
|
@ -70,11 +74,13 @@ ARCH_FLAGS ?= -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16
|
|||
SYSTEM_FLAGS ?= -nostdlib -ffreestanding -nostartfiles
|
||||
|
||||
#CFLAGS += -I$(abspath musl_include_shims)
|
||||
CFLAGS += -I$(CUBE_CMSIS_DIR)/Include -I$(CMSIS_DIR)/CMSIS/Core/Include
|
||||
CFLAGS += -Itinyprintf
|
||||
COMMON_CFLAGS += -I$(BUILDDIR) -Isrc
|
||||
INCLUDES += -I$(CUBE_CMSIS_DIR)/Include -I$(CMSIS_DIR)/CMSIS/Core/Include
|
||||
INCLUDES += -Itinyprintf -I$(MBEDTLS_DIR)/include
|
||||
COMMON_INCLUDES += -I$(BUILDDIR) -Isrc
|
||||
MBEDTLS_CONFIG_INCLUDE := -I$(realpath include)
|
||||
INCLUDES += $(MBEDTLS_CONFIG_INCLUDE)
|
||||
|
||||
COMMON_CFLAGS += -O0 -std=gnu11 -g -DSTM32F407xx -DSTM32F4 -DDEBUG=$(DEBUG)
|
||||
COMMON_CFLAGS += -O0 -std=gnu11 -g -DSTM32F407xx -DSTM32F4 -DDEBUG=$(DEBUG) -DMBEDTLS_ALLOW_PRIVATE_ACCESS
|
||||
CFLAGS += $(ARCH_FLAGS) $(SYSTEM_FLAGS)
|
||||
#SIM_CFLAGS += -mthumb -mcpu=cortex-m4 -mfloat-abi=soft
|
||||
CFLAGS += -fno-common -ffunction-sections -fdata-sections
|
||||
|
|
@ -92,7 +98,6 @@ CXXFLAGS += -Os -g
|
|||
CXXFLAGS += $(ARCH_FLAGS) $(SYSTEM_FLAGS)
|
||||
CXXFLAGS += -fno-common -ffunction-sections -fdata-sections
|
||||
CXXFLAGS += -Wall -Wextra -Wshadow -Wundef -Wredundant-decls
|
||||
CXXFLAGS += -I.
|
||||
|
||||
LDFLAGS += $(ARCH_FLAGS) $(SYSTEM_FLAGS)
|
||||
|
||||
|
|
@ -127,7 +132,12 @@ $(BUILDDIR)/generated: ; mkdir -p $@
|
|||
$(BUILDDIR)/$(BINARY) $(BUILDDIR)/$(BINARY:.elf=.map) &: $(ALL_OBJS)
|
||||
$(LD) -T$(LDSCRIPT) $(LDFLAGS) -o $@ -Wl,-Map=$(BUILDDIR)/$(BINARY:.elf=.map) $^ $(LIBS)
|
||||
|
||||
build/$(BINARY:.elf=-symbol-sizes.dot): $(ALL_OBJS)
|
||||
$(BUILDDIR)/libmbedcrypto.a:
|
||||
make -C $(MBEDTLS_DIR) clean
|
||||
make -C $(MBEDTLS_DIR) CC=$(CC) LD=$(LD) CFLAGS="$(CFLAGS) $(COMMON_CFLAGS) $(MBEDTLS_CONFIG_INCLUDE)" LDFLAGS="$(LDFLAGS)" lib
|
||||
mv $(MBEDTLS_DIR)/library/libmbedcrypto.a $@
|
||||
|
||||
build/$(BINARY:.elf=-symbol-sizes.dot): $(ALL_OBJS) $(BUILDDIR)/libmbedcrypto.a
|
||||
$(PYTHON3) tools/linkmem.py $(LINKMEM_FLAGS) $(LD) -T$(LDSCRIPT) $(LDFLAGS) $^ $(LIBS) > $@
|
||||
|
||||
%.pdf: %.dot
|
||||
|
|
@ -138,11 +148,11 @@ build/$(BINARY:.elf=-symbol-sizes.dot): $(ALL_OBJS)
|
|||
|
||||
$(BUILDDIR)/src/%.o: src/%.s
|
||||
mkdir -p $(@D)
|
||||
$(CC) $(COMMON_CFLAGS) $(CFLAGS) $(INT_CFLAGS) -o $@ -c $<
|
||||
$(CC) $(COMMON_CFLAGS) $(CFLAGS) $(INT_CFLAGS) $(INCLUDES) $(COMMON_INCLUDES) -o $@ -c $<
|
||||
|
||||
$(BUILDDIR)/src/%.o: src/%.c
|
||||
mkdir -p $(@D)
|
||||
$(CC) $(COMMON_CFLAGS) $(CFLAGS) $(INT_CFLAGS) -o $@ -c $<
|
||||
$(CC) $(COMMON_CFLAGS) $(CFLAGS) $(INT_CFLAGS) $(INCLUDES) $(COMMON_INCLUDES) -o $@ -c $<
|
||||
|
||||
$(BUILDDIR)/src/%.o: src/%.cpp
|
||||
mkdir -p $(@D)
|
||||
|
|
@ -150,13 +160,14 @@ $(BUILDDIR)/src/%.o: src/%.cpp
|
|||
|
||||
$(BUILDDIR)/generated/%.o: $(BUILDDIR)/generated/%.c
|
||||
mkdir -p $(@D)
|
||||
$(CC) $(COMMON_CFLAGS) $(CFLAGS) $(INT_CFLAGS) -o $@ -c $<
|
||||
$(CC) $(COMMON_CFLAGS) $(CFLAGS) $(INT_CFLAGS) $(INCLUDES) $(COMMON_INCLUDES) -o $@ -c $<
|
||||
|
||||
$(BUILDDIR)/%.o: %.c
|
||||
mkdir -p $(@D)
|
||||
$(CC) $(COMMON_CFLAGS) $(CFLAGS) $(EXT_CFLAGS) -o $@ -c $<
|
||||
$(CC) $(COMMON_CFLAGS) $(CFLAGS) $(EXT_CFLAGS) $(INCLUDES) $(COMMON_INCLUDES) -o $@ -c $<
|
||||
|
||||
clean:
|
||||
make -C $(MBEDTLS_DIR) clean
|
||||
rm -rf $(BUILDDIR)/src
|
||||
rm -rf $(BUILDDIR)/generated
|
||||
rm -f $(BUILDDIR)/$(BINARY)
|
||||
|
|
|
|||
189
demo/fw/include/endian.h
Normal file
189
demo/fw/include/endian.h
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2002 Thomas Moestl <tmm@FreeBSD.org>
|
||||
* 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 AUTHOR 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 AUTHOR 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
/*
|
||||
* Portions copyright (c) 2018, ARM Limited and Contributors.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef ENDIAN_H
|
||||
#define ENDIAN_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* General byte order swapping functions.
|
||||
*/
|
||||
#define bswap16(x) __bswap16(x)
|
||||
#define bswap32(x) __bswap32(x)
|
||||
#define bswap64(x) __bswap64(x)
|
||||
|
||||
/*
|
||||
* Host to big endian, host to little endian, big endian to host, and little
|
||||
* endian to host byte order functions as detailed in byteorder(9).
|
||||
*/
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define htobe16(x) bswap16((x))
|
||||
#define htobe32(x) bswap32((x))
|
||||
#define htobe64(x) bswap64((x))
|
||||
#define htole16(x) ((uint16_t)(x))
|
||||
#define htole32(x) ((uint32_t)(x))
|
||||
#define htole64(x) ((uint64_t)(x))
|
||||
|
||||
#define be16toh(x) bswap16((x))
|
||||
#define be32toh(x) bswap32((x))
|
||||
#define be64toh(x) bswap64((x))
|
||||
#define le16toh(x) ((uint16_t)(x))
|
||||
#define le32toh(x) ((uint32_t)(x))
|
||||
#define le64toh(x) ((uint64_t)(x))
|
||||
#else /* __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ */
|
||||
#define htobe16(x) ((uint16_t)(x))
|
||||
#define htobe32(x) ((uint32_t)(x))
|
||||
#define htobe64(x) ((uint64_t)(x))
|
||||
#define htole16(x) bswap16((x))
|
||||
#define htole32(x) bswap32((x))
|
||||
#define htole64(x) bswap64((x))
|
||||
|
||||
#define be16toh(x) ((uint16_t)(x))
|
||||
#define be32toh(x) ((uint32_t)(x))
|
||||
#define be64toh(x) ((uint64_t)(x))
|
||||
#define le16toh(x) bswap16((x))
|
||||
#define le32toh(x) bswap32((x))
|
||||
#define le64toh(x) bswap64((x))
|
||||
#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
|
||||
|
||||
/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */
|
||||
|
||||
static __inline uint16_t
|
||||
be16dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return ((p[0] << 8) | p[1]);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
be32dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return (((unsigned)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
|
||||
}
|
||||
|
||||
static __inline uint64_t
|
||||
be64dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4));
|
||||
}
|
||||
|
||||
static __inline uint16_t
|
||||
le16dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return ((p[1] << 8) | p[0]);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
le32dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return (((unsigned)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
|
||||
}
|
||||
|
||||
static __inline uint64_t
|
||||
le64dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
be16enc(void *pp, uint16_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
p[0] = (u >> 8) & 0xff;
|
||||
p[1] = u & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
be32enc(void *pp, uint32_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
p[0] = (u >> 24) & 0xff;
|
||||
p[1] = (u >> 16) & 0xff;
|
||||
p[2] = (u >> 8) & 0xff;
|
||||
p[3] = u & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
be64enc(void *pp, uint64_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
be32enc(p, (uint32_t)(u >> 32));
|
||||
be32enc(p + 4, (uint32_t)(u & 0xffffffffU));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
le16enc(void *pp, uint16_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
p[0] = u & 0xff;
|
||||
p[1] = (u >> 8) & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
le32enc(void *pp, uint32_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
p[0] = u & 0xff;
|
||||
p[1] = (u >> 8) & 0xff;
|
||||
p[2] = (u >> 16) & 0xff;
|
||||
p[3] = (u >> 24) & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
le64enc(void *pp, uint64_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
le32enc(p, (uint32_t)(u & 0xffffffffU));
|
||||
le32enc(p + 4, (uint32_t)(u >> 32));
|
||||
}
|
||||
|
||||
#endif /* ENDIAN_H */
|
||||
3282
demo/fw/include/mbedtls/mbedtls_config.h
Normal file
3282
demo/fw/include/mbedtls/mbedtls_config.h
Normal file
File diff suppressed because it is too large
Load diff
224
demo/fw/src/bech32.c
Normal file
224
demo/fw/src/bech32.c
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/* Copyright (c) 2017, 2021 Pieter Wuille
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "bech32.h"
|
||||
|
||||
/* Returns negative error code on failure, number of bytes written */
|
||||
static ssize_t convert_bits(uint8_t* out, size_t outlen, int outbits, const uint8_t* in, size_t inlen, int inbits);
|
||||
|
||||
static uint32_t bech32_polymod_step(uint32_t pre) {
|
||||
uint8_t b = pre >> 25;
|
||||
return ((pre & 0x1FFFFFF) << 5) ^
|
||||
(-((b >> 0) & 1) & 0x3b6a57b2UL) ^
|
||||
(-((b >> 1) & 1) & 0x26508e6dUL) ^
|
||||
(-((b >> 2) & 1) & 0x1ea119faUL) ^
|
||||
(-((b >> 3) & 1) & 0x3d4233ddUL) ^
|
||||
(-((b >> 4) & 1) & 0x2a1462b3UL);
|
||||
}
|
||||
|
||||
static const char* charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
||||
|
||||
static const int8_t charset_rev[128] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
|
||||
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
|
||||
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
|
||||
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
|
||||
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len, enum bech32_encoding enc) {
|
||||
uint32_t chk = 1;
|
||||
size_t i = 0;
|
||||
while (hrp[i] != 0) {
|
||||
int ch = hrp[i];
|
||||
if (ch < 33 || ch > 126) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ch >= 'A' && ch <= 'Z') return 0;
|
||||
chk = bech32_polymod_step(chk) ^ (ch >> 5);
|
||||
++i;
|
||||
}
|
||||
if (i + 7 + data_len > 90) return 0;
|
||||
chk = bech32_polymod_step(chk);
|
||||
while (*hrp != 0) {
|
||||
chk = bech32_polymod_step(chk) ^ (*hrp & 0x1f);
|
||||
*(output++) = *(hrp++);
|
||||
}
|
||||
*(output++) = '1';
|
||||
for (i = 0; i < data_len; ++i) {
|
||||
if (*data >> 5) return 0;
|
||||
chk = bech32_polymod_step(chk) ^ (*data);
|
||||
*(output++) = charset[*(data++)];
|
||||
}
|
||||
for (i = 0; i < 6; ++i) {
|
||||
chk = bech32_polymod_step(chk);
|
||||
}
|
||||
chk ^= enc;
|
||||
for (i = 0; i < 6; ++i) {
|
||||
*(output++) = charset[(chk >> ((5 - i) * 5)) & 0x1f];
|
||||
}
|
||||
*output = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum bech32_err bech32_decode(char* hrp, size_t hrplen, uint8_t *decoded, size_t decoded_len, size_t *decoded_len_out, const char *input, enum bech32_encoding *enc_out) {
|
||||
uint32_t chk = 1;
|
||||
size_t i;
|
||||
size_t input_len = strlen(input);
|
||||
size_t found_hrp_len;
|
||||
int have_lower = 0, have_upper = 0;
|
||||
|
||||
if (decoded_len_out) {
|
||||
*decoded_len_out = 0;
|
||||
}
|
||||
|
||||
if (input_len < 8) {
|
||||
return BECH32_ERR_INPUT_TOO_SMALL;
|
||||
}
|
||||
|
||||
size_t data_len = 0;
|
||||
while (data_len < input_len && input[(input_len - 1) - data_len] != '1') {
|
||||
data_len += 1;
|
||||
}
|
||||
|
||||
found_hrp_len = input_len - (1 + data_len);
|
||||
|
||||
if (data_len >= input_len - 1) {
|
||||
return BECH32_ERR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
if (data_len < 6) {
|
||||
return BECH32_ERR_INPUT_TOO_SMALL;
|
||||
}
|
||||
|
||||
if (found_hrp_len + 1 > hrplen) {
|
||||
return BECH32_ERR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
data_len -= 6;
|
||||
for (i = 0; i < found_hrp_len; i++) {
|
||||
int ch = input[i];
|
||||
if (ch < 33 || ch > 126) {
|
||||
return BECH32_ERR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
if (ch >= 'a' && ch <= 'z') {
|
||||
have_lower = 1;
|
||||
} else if (ch >= 'A' && ch <= 'Z') {
|
||||
have_upper = 1;
|
||||
ch = (ch - 'A') + 'a';
|
||||
}
|
||||
|
||||
hrp[i] = ch;
|
||||
chk = bech32_polymod_step(chk) ^ (ch >> 5);
|
||||
}
|
||||
hrp[i] = 0;
|
||||
|
||||
chk = bech32_polymod_step(chk);
|
||||
for (i = 0; i < found_hrp_len; ++i) {
|
||||
chk = bech32_polymod_step(chk) ^ (input[i] & 0x1f);
|
||||
}
|
||||
i += 1;
|
||||
|
||||
if (decoded_len < input_len - 6 - found_hrp_len - 1) {
|
||||
return BECH32_ERR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
size_t prefix_len = found_hrp_len + 1;
|
||||
for (size_t j=0; j < input_len - prefix_len; j++) {
|
||||
char c = input[prefix_len + j];
|
||||
|
||||
if (c & 0x80) {
|
||||
return BECH32_ERR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
if ('a' <= c && c <= 'z') {
|
||||
have_lower = 1;
|
||||
} else if ('A' <= c && c <= 'Z') {
|
||||
have_upper = 1;
|
||||
}
|
||||
|
||||
int v = charset_rev[(size_t)c];
|
||||
chk = bech32_polymod_step(chk) ^ v;
|
||||
|
||||
if (prefix_len + j < input_len - 6) {
|
||||
decoded[j] = v;
|
||||
}
|
||||
}
|
||||
|
||||
if (chk != BECH32_ENCODING_BECH32 && chk != BECH32_ENCODING_BECH32M) {
|
||||
return BECH32_ERR_BROKEN_CHECKSUM;
|
||||
}
|
||||
|
||||
if (enc_out) {
|
||||
*enc_out = chk;
|
||||
}
|
||||
|
||||
ssize_t rc = convert_bits(decoded, decoded_len, 8, decoded, data_len, 5);
|
||||
if (rc < 0) {
|
||||
return -rc;
|
||||
} else {
|
||||
*decoded_len_out = rc;
|
||||
}
|
||||
|
||||
if (have_lower && have_upper) {
|
||||
return BECH32_ERR_MIXED_CASE;
|
||||
} else {
|
||||
return BECH32_ERR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t convert_bits(uint8_t* out, size_t outlen, int outbits, const uint8_t* in, size_t inlen, int inbits) {
|
||||
uint32_t val = 0;
|
||||
int bits = 0;
|
||||
uint32_t mask = (((uint32_t)1) << outbits) - 1;
|
||||
|
||||
size_t wpos = 0;
|
||||
for (size_t rpos=0; rpos<inlen; rpos++) {
|
||||
val = (val << inbits) | in[rpos];
|
||||
bits += inbits;
|
||||
while (bits >= outbits) {
|
||||
bits -= outbits;
|
||||
|
||||
if (wpos >= outlen)
|
||||
return -BECH32_ERR_BUFFER_TOO_SMALL;
|
||||
|
||||
out[wpos] = (val >> bits) & mask;
|
||||
wpos += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (((val << (outbits - bits)) & mask) || bits >= inbits) {
|
||||
return -BECH32_ERR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
return wpos;
|
||||
}
|
||||
|
||||
63
demo/fw/src/bech32.h
Normal file
63
demo/fw/src/bech32.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/* Copyright (c) 2017, 2021 Pieter Wuille
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _SEGWIT_ADDR_H_
|
||||
#define _SEGWIT_ADDR_H_ 1
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
enum bech32_err {
|
||||
BECH32_ERR_SUCCESS = 0,
|
||||
BECH32_ERR_BUFFER_TOO_SMALL,
|
||||
BECH32_ERR_INPUT_TOO_SMALL,
|
||||
BECH32_ERR_INVALID_INPUT,
|
||||
BECH32_ERR_MIXED_CASE,
|
||||
BECH32_ERR_BROKEN_CHECKSUM,
|
||||
};
|
||||
|
||||
/** Supported encodings. */
|
||||
enum bech32_encoding {
|
||||
BECH32_ENCODING_BECH32 = 1,
|
||||
BECH32_ENCODING_BECH32M = 0x2bc830a3,
|
||||
};
|
||||
|
||||
/** Encode a Bech32 or Bech32m string
|
||||
*
|
||||
* Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that
|
||||
* will be updated to contain the null-terminated Bech32 string.
|
||||
* In: hrp : Pointer to the null-terminated human readable part.
|
||||
* data : Pointer to an array of 5-bit values.
|
||||
* data_len: Length of the data array.
|
||||
* enc: Which encoding to use (BECH32_ENCODING_BECH32{,M}).
|
||||
* Returns 1 if successful.
|
||||
*/
|
||||
int bech32_encode(
|
||||
char *output,
|
||||
const char *hrp,
|
||||
const uint8_t *data,
|
||||
size_t data_len,
|
||||
enum bech32_encoding enc
|
||||
);
|
||||
|
||||
enum bech32_err bech32_decode(char* hrp, size_t hrplen, uint8_t *decoded, size_t decoded_len, size_t *decoded_len_out, const char *input, enum bech32_encoding *enc_out);
|
||||
|
||||
#endif
|
||||
665
demo/fw/src/cage.c
Normal file
665
demo/fw/src/cage.c
Normal file
|
|
@ -0,0 +1,665 @@
|
|||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <endian.h>
|
||||
#ifdef CAGE_DEBUG
|
||||
#include <error.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "cage.h"
|
||||
#include "cage_base64.h"
|
||||
#include "logging.h"
|
||||
#include "bech32.h"
|
||||
|
||||
#include "mbedtls/chachapoly.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include "mbedtls/hkdf.h"
|
||||
#include "mbedtls/ecp.h"
|
||||
#include "mbedtls/base64.h"
|
||||
|
||||
|
||||
static enum ca_error parse_stanza(struct ca_keystore *ks, const char *stanza_head, size_t len, unsigned char file_key[16]);
|
||||
static enum ca_error parse_stanza_x25519(struct ca_keystore *ks, size_t nargs, const char **args, size_t body_len, const unsigned char *body, unsigned char file_key[16]);
|
||||
static enum ca_error check_file_key(const unsigned char *buf, size_t buflen, const unsigned char file_key[16]);
|
||||
|
||||
void ca_keystore_init(struct ca_keystore *ks) {
|
||||
mbedtls_ecp_keypair_init(&(ks->x25519_kp));
|
||||
}
|
||||
|
||||
enum ca_error ca_keystore_load_x25519_private_key(struct ca_keystore *ks, const unsigned char buf[32]) {
|
||||
|
||||
/*
|
||||
printf("x25519: private key: ");
|
||||
for (size_t i=0; i<32; i++) {
|
||||
printf("%02x", buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
|
||||
int mbedtls_rc = mbedtls_ecp_read_key(MBEDTLS_ECP_DP_CURVE25519, &(ks->x25519_kp), buf, 32);
|
||||
if (mbedtls_rc) {
|
||||
LOG_PRINTF("Error: mbedtls_ecp_read_key: rc=-0x%x\n", -mbedtls_rc);
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
/* Reconstruct public key from private key */
|
||||
mbedtls_rc = mbedtls_ecp_mul(&(ks->x25519_kp.grp), &(ks->x25519_kp.Q),
|
||||
&(ks->x25519_kp.d), &(ks->x25519_kp.grp.G),
|
||||
NULL, NULL/* FIXME: DEBUG ONLY!!! */);
|
||||
if (mbedtls_rc) {
|
||||
LOG_PRINTF("Error: mbedtls_ecp_read_key: rc=-0x%x\n", -mbedtls_rc);
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
return CA_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t buflen, unsigned char file_key[16]) {
|
||||
enum ca_error err = CA_ERR_CORRUPTED_STATE;
|
||||
|
||||
if (buflen <= 0) {
|
||||
LOG_PRINTF("Error: parse_age_buf: (buflen == %d) <= 0\n", buflen);
|
||||
return CA_ERR_INVALID_HEADER;
|
||||
}
|
||||
if (strnlen(buf, buflen) >= buflen) {
|
||||
LOG_PRINTF("Error: parse_age_buf: Buffer is not null-terminated\n");
|
||||
return CA_ERR_INVALID_HEADER; /* buffer is not null-terminated */
|
||||
}
|
||||
|
||||
const char *current_line = buf;
|
||||
const char *line_end = strchr(buf, '\n');
|
||||
|
||||
if (!line_end) {
|
||||
LOG_PRINTF("Error: parse_age_buf: newline in header not found\n");
|
||||
return CA_ERR_INVALID_HEADER; /* header has to contain at least magic string, one stanza and payload separator line */
|
||||
}
|
||||
|
||||
const char *header_start = "age-encryption.org/v";
|
||||
if (strncmp(current_line, header_start, strlen(header_start))) {
|
||||
LOG_PRINTF("Error: parse_age_buf: header magic string corrupt or missing\n");
|
||||
return CA_ERR_INVALID_HEADER; /* header magic string corrupt or missing */
|
||||
}
|
||||
|
||||
char *endptr = NULL;
|
||||
unsigned long header_version = strtoul(current_line + strlen(header_start), &endptr, 10);
|
||||
|
||||
if (current_line[strlen(header_start)] == '\0' || header_version == ULONG_MAX || *endptr != '\n') {
|
||||
LOG_PRINTF("Error: parse_age_buf: corrupt version number\n");
|
||||
return CA_ERR_INVALID_HEADER; /* corrupt version number */
|
||||
}
|
||||
|
||||
if (header_version > 1) {
|
||||
LOG_PRINTF("Error: parse_age_buf: file version too new\n");
|
||||
return CA_ERR_FILE_FORMAT_TOO_NEW;
|
||||
}
|
||||
|
||||
const char *stanza_head = NULL;
|
||||
size_t stanza_num = 0;
|
||||
for (size_t i=0; i<buflen; i++) {
|
||||
/* we forced buf above to be nul-terminated and we know line_end is \n (!= \0), so line_end+1 must be valid. */
|
||||
current_line = line_end+1;
|
||||
|
||||
line_end = strchr(current_line, '\n');
|
||||
if (!line_end) {
|
||||
LOG_PRINTF("Error: parse_age_buf: header does not end in newline\n");
|
||||
return CA_ERR_INVALID_HEADER; /* the header must always end with '\n' after the --- separator line */
|
||||
}
|
||||
|
||||
if (!strncmp(current_line, "-> ", 3)) { /* stanza start */
|
||||
stanza_num += 1;
|
||||
|
||||
if (stanza_head) {
|
||||
err = parse_stanza(ks, stanza_head, current_line - stanza_head, file_key);
|
||||
if (err != CA_ERR_SUCCESS)
|
||||
return err;
|
||||
|
||||
if (!check_file_key((const unsigned char *)buf, buflen, file_key)) {
|
||||
/*
|
||||
LOG_PRINTF("Found file key in stanza %d\n", stanza_num);
|
||||
*/
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
/*
|
||||
LOG_PRINTF("stanza %d does not match\n", stanza_num);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
stanza_head = current_line;
|
||||
continue;
|
||||
|
||||
} else if (!strncmp(current_line, "---", 3)) { /* Payload separator line */
|
||||
|
||||
if (stanza_head) {
|
||||
err = parse_stanza(ks, stanza_head, current_line - stanza_head, file_key);
|
||||
if (err != CA_ERR_SUCCESS)
|
||||
return err;
|
||||
|
||||
if (!check_file_key((const unsigned char *)buf, buflen, file_key)) {
|
||||
/*
|
||||
LOG_PRINTF("Found file key in stanza %d\n", stanza_num);
|
||||
*/
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
/*
|
||||
LOG_PRINTF("stanza %d does not match\n", stanza_num);
|
||||
*/
|
||||
}
|
||||
} else {
|
||||
LOG_PRINTF("Error: parse_age_buf: header does not contain any stanzas\n");
|
||||
return CA_ERR_INVALID_HEADER; /* the header must contain at least one stanza */
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
} else { /* b64 stanza content */
|
||||
|
||||
if (line_end - current_line > 64) {
|
||||
LOG_PRINTF("Error: parse_age_buf: base64 stanza body wider than 64 chars\n");
|
||||
return CA_ERR_INVALID_HEADER; /* b64 must be wrapped to exactly 64 chars */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* current_line now points to the beginning of the "--- [0-9a-f]+" end-of-header marker, line_end to the end of this
|
||||
* marker line. */
|
||||
|
||||
return CA_ERR_KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
enum ca_error parse_stanza(struct ca_keystore *ks, const char *stanza_head, size_t len, unsigned char file_key[16]) {
|
||||
const char *stanza_x25519 = "X25519";
|
||||
enum ca_error err = CA_ERR_CORRUPTED_STATE;
|
||||
|
||||
/* Remove "-> " */
|
||||
stanza_head += 3;
|
||||
len -= 3;
|
||||
|
||||
char *line_end = strchr(stanza_head, '\n');
|
||||
if (!line_end) {
|
||||
LOG_PRINTF("Error: parse_stanza: end of line not found (bug, should not happen!)\n");
|
||||
return CA_ERR_CORRUPTED_STATE;
|
||||
}
|
||||
|
||||
size_t head_len = line_end - stanza_head;
|
||||
|
||||
const char **stanza_args = calloc(head_len, sizeof(char *));
|
||||
if (!stanza_args) {
|
||||
LOG_PRINTF("Error: parse_stanza: cannot allocate stanza arg memory\n");
|
||||
return CA_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
size_t max_payload_len = (len - head_len) * 8 / 6 + 1;
|
||||
unsigned char *payload = malloc(max_payload_len);
|
||||
if (!payload) {
|
||||
free(stanza_args);
|
||||
LOG_PRINTF("Error: parse_stanza: cannot allocate stanza body memory\n");
|
||||
return CA_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
size_t nargs = 1;
|
||||
stanza_args[0] = stanza_head;
|
||||
for (size_t i=0; i<head_len; i++) {
|
||||
char c = stanza_head[i];
|
||||
if (c == ' ') {
|
||||
stanza_args[nargs] = stanza_head + i + 1;
|
||||
nargs += 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t b64_len = 0;
|
||||
if (head_len + 1 < len) { /* has payload */
|
||||
const char *endp = base64_decode(payload, max_payload_len, &b64_len, line_end + 1, len - head_len - 1);
|
||||
if (!endp || endp != stanza_head + len - 1) {
|
||||
LOG_PRINTF("Error: parse_stanza: cannot parse stanza body base64\n");
|
||||
err = CA_ERR_BROKEN_BASE64;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strncmp(stanza_args[0], stanza_x25519, strlen(stanza_x25519))) {
|
||||
err = parse_stanza_x25519(ks, nargs-1, stanza_args + 1, b64_len, payload, file_key);
|
||||
}
|
||||
|
||||
errout:
|
||||
free(payload);
|
||||
free(stanza_args);
|
||||
return err;
|
||||
}
|
||||
|
||||
enum ca_error parse_stanza_x25519(struct ca_keystore *ks, size_t nargs, const char **args, size_t body_len, const unsigned char *body, unsigned char file_key[16]) {
|
||||
int mbedtls_rc = -1;
|
||||
|
||||
/* body length: 16 bytes ciphertext of 128 bit file key + 16 bytes Poly1305 tag */
|
||||
if (nargs != 1 || body_len != 32) {
|
||||
LOG_PRINTF("Error: parse_stanza_x25519: (nargs == %zu) != 1 || (body_len == %zu) != 32\n", nargs, body_len);
|
||||
return CA_ERR_INVALID_HEADER_ARG;
|
||||
}
|
||||
|
||||
size_t ciphertext_len = 0;
|
||||
unsigned char ecp_ciphertext[32];
|
||||
const char *arg_newline = strchr(args[0], '\n');
|
||||
if (!arg_newline) {
|
||||
LOG_PRINTF("Error: parse_stanza_x25519: First argument does not end in '\\n' (this is a bug!)\n");
|
||||
return CA_ERR_CORRUPTED_STATE;
|
||||
}
|
||||
size_t arglen = arg_newline - args[0];
|
||||
const char *endp = base64_decode(ecp_ciphertext, sizeof(ecp_ciphertext), &ciphertext_len, args[0], arglen);
|
||||
if (!endp || endp != arg_newline) {
|
||||
LOG_PRINTF("Error: parse_stanza_x25519: Cannot decode ciphertext header arg base64 %p %p\n", endp, arg_newline);
|
||||
return CA_ERR_INVALID_HEADER_ARG;
|
||||
}
|
||||
|
||||
if (ciphertext_len != 32) {
|
||||
LOG_PRINTF("Error: parse_stanza_x25519: Ciphertext header arg has wrong length\n");
|
||||
return CA_ERR_INVALID_HEADER_ARG;
|
||||
}
|
||||
|
||||
mbedtls_ecp_point ecp_ciphertext_pt;
|
||||
mbedtls_ecp_point_init(&ecp_ciphertext_pt);
|
||||
mbedtls_ecp_group x25519_grp;
|
||||
mbedtls_ecp_group_init(&x25519_grp);
|
||||
mbedtls_rc = mbedtls_ecp_group_load(&x25519_grp, MBEDTLS_ECP_DP_CURVE25519);
|
||||
if (mbedtls_rc) {
|
||||
LOG_PRINTF("Error: mbedtls_ecp_group_load: rc=-0x%x\n", -mbedtls_rc);
|
||||
return CA_ERR_KEY_WRAPPING_DECRYPTION_FAILURE;
|
||||
}
|
||||
|
||||
mbedtls_rc = mbedtls_ecp_point_read_binary(&x25519_grp, &ecp_ciphertext_pt, ecp_ciphertext, sizeof(ecp_ciphertext));
|
||||
if (mbedtls_rc) {
|
||||
LOG_PRINTF("Error: mbedtls_ecp_point_read_binary: rc=-0x%x\n", -mbedtls_rc);
|
||||
return CA_ERR_KEY_WRAPPING_DECRYPTION_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
printf("x25519: derived_secret: ");
|
||||
for (size_t i=0; i<32; i++) {
|
||||
printf("%02x", ecp_ciphertext[i]);
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
|
||||
mbedtls_ecp_point ecp_dec_res_pt;
|
||||
mbedtls_ecp_point_init(&ecp_dec_res_pt);
|
||||
|
||||
mbedtls_rc = mbedtls_ecp_mul(&x25519_grp, &ecp_dec_res_pt, &(ks->x25519_kp.d), &ecp_ciphertext_pt,
|
||||
NULL, NULL/* FIXME: DEBUG ONLY!!! */);
|
||||
if (mbedtls_rc) {
|
||||
LOG_PRINTF("Error: mbedtls_ecp_mul: rc=-0x%x\n", -mbedtls_rc);
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
|
||||
unsigned char ecp_plaintext_buf[32];
|
||||
size_t ecp_plaintext_len = 0;
|
||||
mbedtls_rc = mbedtls_ecp_point_write_binary(&x25519_grp, &ecp_dec_res_pt,
|
||||
MBEDTLS_ECP_PF_UNCOMPRESSED, &ecp_plaintext_len,
|
||||
ecp_plaintext_buf, sizeof(ecp_plaintext_buf));
|
||||
|
||||
/*
|
||||
printf("x25519: key_material: ");
|
||||
for (size_t i=0; i<32; i++) {
|
||||
printf("%02x", ecp_plaintext_buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
|
||||
if (mbedtls_rc) {
|
||||
LOG_PRINTF("Error: mbedtls_ecp_point_write_binary: rc=-0x%x\n", -mbedtls_rc);
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
if (ecp_plaintext_len != 32) {
|
||||
LOG_PRINTF("Error: parse_stanza_x25519: (ecp_plaintext_len == %d) != 32 (bug, should not happen!)\n", ecp_plaintext_len);
|
||||
return CA_ERR_CORRUPTED_STATE;
|
||||
}
|
||||
|
||||
const mbedtls_md_info_t *sha256_md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
if (!sha256_md) {
|
||||
LOG_PRINTF("Error: mbedtls_md_info_from_type: cannot load SHA256\n");
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
unsigned char salt[64];
|
||||
memcpy(salt, ecp_ciphertext, 32);
|
||||
size_t pbin_olen = 0;
|
||||
mbedtls_rc = mbedtls_ecp_point_write_binary(&x25519_grp, &(ks->x25519_kp.Q),
|
||||
MBEDTLS_ECP_PF_UNCOMPRESSED, &pbin_olen, salt+32, 32);
|
||||
if (mbedtls_rc) {
|
||||
LOG_PRINTF("Error: mbedtls_ecp_point_write_binary: rc=-0x%x\n", -mbedtls_rc);
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
if (pbin_olen != 32) {
|
||||
LOG_PRINTF("Error: mbedtls_ecp_point_write_binary returned invalid output len: %d != 32\n", pbin_olen);
|
||||
return CA_ERR_CORRUPTED_STATE;
|
||||
}
|
||||
|
||||
/*
|
||||
printf("x25519: salt: ");
|
||||
for (size_t i=0; i<64; i++) {
|
||||
printf("%02x", salt[i]);
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
|
||||
const char *info_str = "age-encryption.org/v1/X25519";
|
||||
unsigned char wrap_key[32];
|
||||
mbedtls_rc = mbedtls_hkdf(sha256_md, salt, sizeof(salt),
|
||||
ecp_plaintext_buf, sizeof(ecp_plaintext_buf),
|
||||
(const unsigned char *)info_str, strlen(info_str),
|
||||
wrap_key, sizeof(wrap_key));
|
||||
if (mbedtls_rc) {
|
||||
LOG_PRINTF("Error: mbedtls_hkdf: rc=-0x%x\n", -mbedtls_rc);
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
printf("x25519: key: ");
|
||||
for (size_t i=0; i<32; i++) {
|
||||
printf("%02x", wrap_key[i]);
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
|
||||
mbedtls_chachapoly_context cp_ctx;
|
||||
mbedtls_chachapoly_init(&cp_ctx);
|
||||
mbedtls_rc = mbedtls_chachapoly_setkey(&cp_ctx, wrap_key);
|
||||
if (mbedtls_rc) {
|
||||
LOG_PRINTF("Error: mbedtls_chachapoly_setkey: rc=-0x%x\n", -mbedtls_rc);
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
const unsigned char nonce[12] = { 0 };
|
||||
mbedtls_rc = mbedtls_chachapoly_auth_decrypt(&cp_ctx, 16, nonce, NULL, 0, (const unsigned char*)(body + body_len - 16), body, file_key);
|
||||
if (mbedtls_rc) {
|
||||
LOG_PRINTF("Error: mbedtls_chachapoly_auth_decrypt: rc=-0x%x\n", -mbedtls_rc);
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
|
||||
return CA_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
enum ca_error check_file_key(const unsigned char *buf, size_t buflen, const unsigned char file_key[16]) {
|
||||
int mbedtls_rc;
|
||||
|
||||
const mbedtls_md_info_t *sha256_md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
if (!sha256_md) {
|
||||
LOG_PRINTF("Error: mbedtls_md_info_from_type: cannot load SHA256\n");
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
/* we know buf is null-terminated */
|
||||
const char *found = strstr((const char *)buf, "\n--- ");
|
||||
if (!found) {
|
||||
return CA_ERR_INVALID_HEADER;
|
||||
}
|
||||
found += 4; /* for "\n---" */
|
||||
size_t header_len = found - (const char *)buf;
|
||||
|
||||
unsigned char check_value[32];
|
||||
mbedtls_rc = mbedtls_hkdf(sha256_md, (const unsigned char *)"", 0,
|
||||
file_key, 16,
|
||||
(const unsigned char *)"header", strlen("header"),
|
||||
check_value, sizeof(check_value));
|
||||
if (mbedtls_rc) {
|
||||
LOG_PRINTF("Error: mbedtls_hkdf: rc=-0x%x\n", -mbedtls_rc);
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
unsigned char hmac_calculated[32];
|
||||
mbedtls_rc = mbedtls_md_hmac(sha256_md, check_value, sizeof(check_value),
|
||||
buf, header_len,
|
||||
hmac_calculated);
|
||||
if (mbedtls_rc) {
|
||||
LOG_PRINTF("Error: mbedtls_md_hmac: rc=-0x%x\n", -mbedtls_rc);
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
unsigned char mac[32];
|
||||
size_t mac_osize = 0;
|
||||
const char *endp = base64_decode(mac, sizeof(mac), &mac_osize, (const char *)found + 1 /* for " " */, buflen - ((const unsigned char *)found - buf));
|
||||
if (!endp || *endp != '\n') {
|
||||
LOG_PRINTF("Error: check_file_key: Cannot decode ciphertext header arg base64\n");
|
||||
return CA_ERR_INVALID_HEADER_ARG;
|
||||
}
|
||||
|
||||
if (mac_osize != 32) {
|
||||
LOG_PRINTF("Error: check_file_key: (mac_osize == %d) != 32\n", mac_osize);
|
||||
return CA_ERR_INVALID_HEADER;
|
||||
}
|
||||
|
||||
if (memcmp(mac, hmac_calculated, 32)) {
|
||||
return CA_ERR_MAC_MISMATCH;
|
||||
}
|
||||
|
||||
return CA_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
enum ca_error stream_decrypt(unsigned char *out, size_t outlen, size_t *out_written, const unsigned char *in, size_t inlen, const unsigned char file_key[16]) {
|
||||
|
||||
const char *found = strstr((const char *)in, "\n--- ");
|
||||
if (!found) {
|
||||
return CA_ERR_INVALID_HEADER;
|
||||
}
|
||||
|
||||
const unsigned char *endl = (const unsigned char *)strchr(found+1, '\n');
|
||||
if (!endl) {
|
||||
return CA_ERR_INVALID_HEADER;
|
||||
}
|
||||
|
||||
inlen -= endl - in + 1;
|
||||
in = endl+1;
|
||||
|
||||
if (inlen < 32) {
|
||||
return CA_ERR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
*out_written = 0;
|
||||
|
||||
size_t stream_bytes = inlen - 16 /* nonce */; /* >= 16 */
|
||||
size_t out_blocksize = 0x10000;
|
||||
size_t stream_blocksize = out_blocksize + 16;
|
||||
size_t stream_blocks = (stream_bytes - 1) / stream_blocksize + 1;
|
||||
size_t aead_tagsize = 16;
|
||||
|
||||
if (outlen < stream_bytes - aead_tagsize * stream_blocks) {
|
||||
LOG_PRINTF("Error: stream_decrypt: caller-provided buffer too small for decryption result: %zu < %zu\n", outlen, stream_bytes - aead_tagsize * stream_blocks);
|
||||
return CA_ERR_NOT_ENOUGH_SPACE;
|
||||
}
|
||||
|
||||
/*
|
||||
printf("file key: ");
|
||||
for (size_t i=0; i<16; i++) {
|
||||
printf("%02x", file_key[i]);
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
|
||||
const mbedtls_md_info_t *sha256_md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
if (!sha256_md) {
|
||||
LOG_PRINTF("Error: mbedtls_md_info_from_type: cannot load SHA256\n");
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
printf("salt: ");
|
||||
for (size_t i=0; i<16; i++) {
|
||||
printf("%02x", in[i]);
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
|
||||
unsigned char stream_key[32];
|
||||
int mbedtls_rc = mbedtls_hkdf(sha256_md, in, 16,
|
||||
file_key, 16,
|
||||
(const unsigned char *)"payload", strlen("payload"),
|
||||
stream_key, sizeof(stream_key));
|
||||
if (!sha256_md) {
|
||||
LOG_PRINTF("Error: mbedtls_md_info_from_type: cannot load SHA256\n");
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
printf("stream key: ");
|
||||
for (size_t i=0; i<32; i++) {
|
||||
printf("%02x", stream_key[i]);
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
|
||||
mbedtls_chachapoly_context cp_ctx;
|
||||
mbedtls_chachapoly_init(&cp_ctx);
|
||||
mbedtls_rc = mbedtls_chachapoly_setkey(&cp_ctx, stream_key);
|
||||
if (mbedtls_rc) {
|
||||
LOG_PRINTF("Error: mbedtls_chachapoly_setkey: rc=-0x%x\n", -mbedtls_rc);
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
in += 16;
|
||||
size_t block_num = 0;
|
||||
for (size_t i=0; i<stream_bytes; i+=stream_blocksize) {
|
||||
struct __attribute__((__packed__)) {
|
||||
unsigned char zeros[3];
|
||||
uint64_t counter;
|
||||
unsigned char last_block;
|
||||
} nonce = { {0}, htobe64(block_num), i + stream_blocksize + 16 >= inlen };
|
||||
|
||||
assert (sizeof(nonce) == 12);
|
||||
|
||||
/*
|
||||
printf("block nonce: ");
|
||||
for (size_t i=0; i<12; i++) {
|
||||
printf("%02x", ((uint8_t*)&nonce)[i]);
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
|
||||
size_t block_len = stream_bytes - i > stream_blocksize ? stream_blocksize : stream_bytes - i;
|
||||
const unsigned char *inp = in + i;
|
||||
unsigned char *outp = out + block_num * out_blocksize;
|
||||
size_t data_len = block_len - 16;
|
||||
const unsigned char *tag = inp + data_len;
|
||||
/*
|
||||
LOG_PRINTF("inlen=%zu block_len=%zu inp=%p@%zu outp=%p@%zu data_len=%zu tag=%p\n",
|
||||
inlen, block_len, inp, i, outp, block_num*out_blocksize, data_len, tag);
|
||||
*/
|
||||
mbedtls_rc = mbedtls_chachapoly_auth_decrypt(&cp_ctx,
|
||||
data_len, (unsigned char *)&nonce, NULL, 0, tag, inp, outp);
|
||||
if (mbedtls_rc) {
|
||||
LOG_PRINTF("Error: mbedtls_chachapoly_auth_decrypt: i=%zx rc=-0x%x\n", i, -mbedtls_rc);
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
*out_written += data_len;
|
||||
block_num += 1;
|
||||
}
|
||||
|
||||
return CA_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef CAGE_DEBUG
|
||||
|
||||
static void usage(const char *cmdname) {
|
||||
fprintf(stderr, "%s private_key\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
enum ca_error err;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Error: invalid number of arguments.\n");
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char hrp[64];
|
||||
char private_key[64];
|
||||
size_t bech32_key_len;
|
||||
enum bech32_err b32_err = bech32_decode(hrp, sizeof(hrp), private_key, sizeof(private_key), &bech32_key_len, argv[1], NULL);
|
||||
if (b32_err) {
|
||||
fprintf(stderr, "Error: bech32_decode: rc=%d\n", b32_err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
fprintf(stderr, "bech32 output: ");
|
||||
for (size_t i=0; i<32; i++) {
|
||||
fprintf(stderr, "%02x", private_key[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
*/
|
||||
|
||||
if (bech32_key_len != 32) {
|
||||
fprintf(stderr, "Error: incorrect bech32 key length %d\n", bech32_key_len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ca_keystore ks;
|
||||
ca_keystore_init(&ks);
|
||||
|
||||
err = ca_keystore_load_x25519_private_key(&ks, private_key);
|
||||
if (err) {
|
||||
fprintf(stderr, "Error %d, exiting.\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t bufsize = 16384;
|
||||
char *buf = malloc(bufsize);
|
||||
size_t read_pos = 0;
|
||||
if (!buf) {
|
||||
fprintf(stderr, "Error: main: cannot allocate memory\n");
|
||||
return 2;
|
||||
}
|
||||
ssize_t nread = read(STDIN_FILENO, buf, bufsize - read_pos - 1);
|
||||
while (nread > 0 || (nread == -1 && errno == EAGAIN)) {
|
||||
if (nread > 0) {
|
||||
read_pos += nread;
|
||||
if (read_pos == bufsize) {
|
||||
bufsize += 16384;
|
||||
buf = realloc(buf, bufsize+1);
|
||||
if (!buf) {
|
||||
fprintf(stderr, "Error: main: cannot allocate memory\n");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
nread = read(STDIN_FILENO, buf + read_pos, bufsize - read_pos);
|
||||
}
|
||||
buf[read_pos] = '\0';
|
||||
|
||||
unsigned char file_key[16];
|
||||
err = parse_age_buf(&ks, buf, read_pos+1, file_key);
|
||||
if (err == CA_ERR_KEY_NOT_FOUND) {
|
||||
fprintf(stderr, "Cannot find stanza matching given key\n");
|
||||
return 3;
|
||||
} else if (err) {
|
||||
fprintf(stderr, "Error %d, exiting.\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned char *decrypted = malloc(bufsize);
|
||||
if (!decrypted) {
|
||||
fprintf(stderr, "Error: main: cannot allocate memory\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
size_t decrypted_size = 0;
|
||||
err = stream_decrypt(decrypted, bufsize, &decrypted_size, buf, read_pos, file_key);
|
||||
if (err) {
|
||||
fprintf(stderr, "Error: main: Error decrypting payload: rc=%d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t written = fwrite(decrypted, 1, bufsize, stdout);
|
||||
if (written != bufsize) {
|
||||
fprintf(stderr, "Error: main: Failed to write decrypted payload to stdout\n");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CAGE_DEBUG */
|
||||
|
||||
39
demo/fw/src/cage.h
Normal file
39
demo/fw/src/cage.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef __CAGE_H__
|
||||
#define __CAGE_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "mbedtls/build_info.h"
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/ecp.h"
|
||||
|
||||
|
||||
enum ca_error {
|
||||
CA_ERR_SUCCESS = 0,
|
||||
CA_ERR_INVALID_HEADER = 1,
|
||||
CA_ERR_INVALID_HEADER_ARG = 2,
|
||||
CA_ERR_KEY_WRAPPING_DECRYPTION_FAILURE = 3,
|
||||
CA_ERR_BROKEN_BASE64 = 4,
|
||||
CA_ERR_FILE_FORMAT_TOO_NEW = 5,
|
||||
CA_ERR_CORRUPTED_STATE = 6,
|
||||
CA_ERR_OUT_OF_MEMORY = 7,
|
||||
CA_ERR_MBEDTLS_ERROR = 8,
|
||||
CA_ERR_MAC_MISMATCH = 9,
|
||||
CA_ERR_INVALID_PARAMETER = 10,
|
||||
CA_ERR_NOT_ENOUGH_SPACE = 11,
|
||||
CA_ERR_KEY_NOT_FOUND = 12,
|
||||
};
|
||||
|
||||
struct ca_keystore {
|
||||
struct mbedtls_ecp_keypair x25519_kp;
|
||||
};
|
||||
|
||||
|
||||
enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t buflen, unsigned char file_key[16]);
|
||||
void ca_keystore_init(struct ca_keystore *ks);
|
||||
enum ca_error ca_keystore_load_x25519_private_key(struct ca_keystore *ks, const unsigned char buf[32]);
|
||||
enum ca_error stream_decrypt(unsigned char *out, size_t outlen, size_t *out_written, const unsigned char *in, size_t inlen, const unsigned char file_key[16]);
|
||||
|
||||
#endif /* __CAGE_H__ */
|
||||
105
demo/fw/src/cage_base64.c
Normal file
105
demo/fw/src/cage_base64.c
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cage_base64.h"
|
||||
|
||||
static const char *base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
const char *base64_decode(unsigned char *dst, size_t dlen, size_t *olen, const char *src, size_t slen) {
|
||||
*olen = 0;
|
||||
if (dlen == 0)
|
||||
return NULL;
|
||||
|
||||
uint8_t last = 0;
|
||||
uint8_t rem_bits = 8;
|
||||
|
||||
const char *c;
|
||||
bool is_padding = false;
|
||||
for (c=src; (c - src) < (ssize_t)slen; c++) {
|
||||
if (!*c)
|
||||
return c;
|
||||
|
||||
if (*c == '=') {
|
||||
is_padding = true;
|
||||
continue;
|
||||
|
||||
} else {
|
||||
if (is_padding) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
char *found = strchr(base64_table, (char)*c);
|
||||
if (!found)
|
||||
return c;
|
||||
|
||||
int decoded = found - base64_table;
|
||||
|
||||
if (rem_bits > 6) {
|
||||
rem_bits -= 6;
|
||||
last |= (decoded << rem_bits);
|
||||
|
||||
} else if (rem_bits <= 6) {
|
||||
if (*olen == dlen)
|
||||
return NULL;
|
||||
|
||||
dst[*olen] = last | (decoded >> (6 - rem_bits));
|
||||
last = decoded << (8 - 6 + rem_bits);
|
||||
rem_bits = 8 - (6 - rem_bits);
|
||||
*olen += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef CAGE_DEBUG
|
||||
static void base64_decode_test(void);
|
||||
|
||||
static const char *base64_test_vectors[][2] = {
|
||||
{"", ""},
|
||||
{"f", "Zg=="},
|
||||
{"fo", "Zm8="},
|
||||
{"foo", "Zm9v"},
|
||||
{"foob", "Zm9vYg=="},
|
||||
{"fooba", "Zm9vYmE="},
|
||||
{"foobar", "Zm9vYmFy"},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
void base64_decode_test() {
|
||||
for (size_t i=0; base64_test_vectors[i][0] != NULL; i++) {
|
||||
//printf("base64 testcase %d\n", i);
|
||||
unsigned char outbuf[1024];
|
||||
size_t outlen;
|
||||
memset(outbuf, 0, sizeof(outbuf));
|
||||
|
||||
const char *endp = base64_decode(outbuf, sizeof(outbuf), &outlen, base64_test_vectors[i][1], strlen(base64_test_vectors[i][1]));
|
||||
assert (endp != NULL);
|
||||
assert (*endp == '\0');
|
||||
assert (endp == base64_test_vectors[i][1] + strlen(base64_test_vectors[i][1]));
|
||||
|
||||
/*
|
||||
printf(" Expected: \"%s\"\n", base64_test_vectors[i][0]);
|
||||
printf(" Got: \"%s\"\n", outbuf);
|
||||
printf(" Hex:");
|
||||
for (size_t j=0; j<outlen; j++) {
|
||||
printf(" %02x", outbuf[j]);
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
assert (!strcmp(outbuf, base64_test_vectors[i][0]));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CAGE_BASE64_DEBUG
|
||||
int main(int argc, char **argv) {
|
||||
base64_decode_test();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
19
demo/fw/src/cage_base64.h
Normal file
19
demo/fw/src/cage_base64.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef __CAGE_BASE64_H__
|
||||
#define __CAGE_BASE64_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* This file contains the cage-internal base-64 implementation. The main difference between this implementation and one
|
||||
* you should actually use is that this one I G N O R E S A L L P A D D I I N G ! ! !
|
||||
* This implementation is not inteded for use outside of cage.
|
||||
*/
|
||||
|
||||
const char *base64_decode(unsigned char *dst, size_t dlen, size_t *olen, const char *src, size_t slen);
|
||||
|
||||
#ifdef CAGE_DEBUG
|
||||
void base64_decode_test(void);
|
||||
#endif
|
||||
|
||||
#endif /* __CAGE_BASE64_H__ */
|
||||
15
demo/fw/src/logging.h
Normal file
15
demo/fw/src/logging.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef __LOGGING_H__
|
||||
#define __LOGGING_H__
|
||||
|
||||
#ifdef CAGE_DEBUG
|
||||
#include <stdio.h>
|
||||
|
||||
#define LOG_PRINTF(format, ...) fprintf(stderr, format, ##__VA_ARGS__);
|
||||
|
||||
#else
|
||||
|
||||
#define LOG_PRINTF(dummy, ...) ((void)dummy)
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __LOGGING_H__ */
|
||||
1
upstream/mbedtls
Submodule
1
upstream/mbedtls
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit bd3bfbf5c2a87a19303d1e1c55f01b03084f32d8
|
||||
Loading…
Add table
Add a link
Reference in a new issue