mirror of
https://github.com/cesanta/mongoose.git
synced 2024-11-24 02:59:01 +08:00
Merge pull request #2538 from cesanta/tls13
Add built-in TLS 1.3 stack: server side, EC support
This commit is contained in:
commit
04178ad0f7
3
Makefile
3
Makefile
@ -177,7 +177,8 @@ mongoose.c: Makefile $(wildcard src/*.c) $(wildcard src/drivers/*.c)
|
||||
(cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c src/drivers/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@
|
||||
|
||||
mongoose.h: $(HDRS) Makefile
|
||||
(cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/event.h src/net.h src/profile.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/device.h src/net_builtin.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
|
||||
(cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/tls_aes128.h src/tls_uecc.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/device.h src/net_builtin.h src/profile.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@
|
||||
|
||||
|
||||
clean: clean_examples clean_embedded
|
||||
rm -rf $(PROG) *.exe *.o *.dSYM *_test* ut fuzzer *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb slow-unit* _CL_* infer-out data.txt crash-* test/packed_fs.c pack
|
||||
|
@ -49,6 +49,8 @@ ifeq ($(TLS), mbedtls)
|
||||
CFLAGS += -DMG_TLS=MG_TLS_MBED -Wno-conversion -Imbedtls/include
|
||||
CFLAGS += -DMBEDTLS_CONFIG_FILE=\"mbedtls_config.h\" mbedtls/library/*.c
|
||||
$(PROG): mbedtls
|
||||
else
|
||||
CFLAGS += -DMG_TLS=MG_TLS_BUILTIN
|
||||
endif
|
||||
|
||||
# Cleanup. Delete built program and all build artifacts
|
||||
|
@ -123,9 +123,9 @@ static void handle_debug(struct mg_connection *c, struct mg_http_message *hm) {
|
||||
}
|
||||
|
||||
static size_t print_int_arr(void (*out)(char, void *), void *ptr, va_list *ap) {
|
||||
size_t len = 0, num = va_arg(*ap, size_t); // Number of items in the array
|
||||
size_t i, len = 0, num = va_arg(*ap, size_t); // Number of items in the array
|
||||
int *arr = va_arg(*ap, int *); // Array ptr
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
for (i = 0; i < num; i++) {
|
||||
len += mg_xprintf(out, ptr, "%s%d", i == 0 ? "" : ",", arr[i]);
|
||||
}
|
||||
return len;
|
||||
@ -168,21 +168,19 @@ static void handle_events_get(struct mg_connection *c,
|
||||
|
||||
static void handle_settings_set(struct mg_connection *c, struct mg_str body) {
|
||||
struct settings settings;
|
||||
char *s = mg_json_get_str(body, "$.device_name");
|
||||
bool ok = true;
|
||||
memset(&settings, 0, sizeof(settings));
|
||||
mg_json_get_bool(body, "$.log_enabled", &settings.log_enabled);
|
||||
settings.log_level = mg_json_get_long(body, "$.log_level", 0);
|
||||
settings.brightness = mg_json_get_long(body, "$.brightness", 0);
|
||||
char *s = mg_json_get_str(body, "$.device_name");
|
||||
if (s && strlen(s) < MAX_DEVICE_NAME) {
|
||||
free(settings.device_name);
|
||||
settings.device_name = s;
|
||||
} else {
|
||||
free(s);
|
||||
}
|
||||
|
||||
// Save to the device flash
|
||||
s_settings = settings;
|
||||
bool ok = true;
|
||||
s_settings = settings; // Save to the device flash
|
||||
mg_http_reply(c, 200, s_json_header,
|
||||
"{%m:%s,%m:%m}", //
|
||||
MG_ESC("status"), ok ? "true" : "false", //
|
||||
|
@ -652,7 +652,7 @@ static const unsigned char v1[] = {
|
||||
0, 0 // .
|
||||
};
|
||||
static const unsigned char v2[] = {
|
||||
31, 139, 8, 8, 246, 5, 126, 101, 0, 3, 99, 111, // ......~e..co
|
||||
31, 139, 8, 8, 87, 102, 129, 101, 0, 3, 99, 111, // ....Wf.e..co
|
||||
109, 112, 111, 110, 101, 110, 116, 115, 46, 106, 115, 0, // mponents.js.
|
||||
237, 93, 235, 115, 219, 70, 146, 255, 238, 191, 98, 162, // .].s.F....b.
|
||||
242, 45, 169, 181, 0, 225, 77, 64, 182, 148, 114, 156, // .-....M@..r.
|
||||
@ -2668,7 +2668,7 @@ static const struct packed_file {
|
||||
time_t mtime;
|
||||
} packed_files[] = {
|
||||
{"/web_root/bundle.js.gz", v1, sizeof(v1), 1695912421},
|
||||
{"/web_root/components.js.gz", v2, sizeof(v2), 1702757878},
|
||||
{"/web_root/components.js.gz", v2, sizeof(v2), 1702979159},
|
||||
{"/web_root/history.min.js.gz", v3, sizeof(v3), 1695912421},
|
||||
{"/web_root/index.html.gz", v4, sizeof(v4), 1693654553},
|
||||
{"/web_root/main.css.gz", v5, sizeof(v5), 1702757929},
|
||||
|
@ -10,8 +10,13 @@ bool hal_gpio_read(int pin) {
|
||||
return (pin >= 0 && pin <= 29) ? gpio_get_out_level((uint) pin) : false;
|
||||
}
|
||||
|
||||
void hal_gpio_write(int pin, bool val) {
|
||||
if (pin >= 0 && pin <= 29) gpio_put((uint) pin, val);
|
||||
bool hal_gpio_write(int pin, bool val) {
|
||||
if (pin >= 0 && pin <= 29) {
|
||||
gpio_put((uint) pin, val);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int hal_led_pin(void) {
|
||||
@ -56,6 +61,10 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_dta) {
|
||||
if (ev == MG_EV_HTTP_MSG) return mg_http_reply(c, 200, "", "ok\n");
|
||||
}
|
||||
|
||||
uint64_t mg_now(void) {
|
||||
return mg_millis();
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
gpio_init(PICO_DEFAULT_LED_PIN);
|
||||
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
||||
|
@ -13,6 +13,7 @@ SOURCES += mongoose.c net.c packed_fs.c
|
||||
|
||||
# Example specific build options. See README.md
|
||||
CFLAGS += -DHTTP_URL=\"http://0.0.0.0/\" -DHTTPS_URL=\"https://0.0.0.0/\"
|
||||
CFLAGS += -DMG_TLS=MG_TLS_BUILTIN
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
RM = cmd /C del /Q /F /S
|
||||
|
@ -24,8 +24,9 @@ void mg_random(void *buf, size_t len) { // Use on-board RNG
|
||||
}
|
||||
|
||||
#ifdef MQTT_DASHBOARD
|
||||
void hal_gpio_write(int pin, bool status) { // For MQTT dashboard HAL
|
||||
bool hal_gpio_write(int pin, bool status) { // For MQTT dashboard HAL
|
||||
gpio_write((uint16_t) pin, status);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hal_gpio_read(int pin) { // For MQTT dashboard HAL
|
||||
|
5936
mongoose.c
5936
mongoose.c
File diff suppressed because it is too large
Load Diff
1067
mongoose.h
1067
mongoose.h
File diff suppressed because it is too large
Load Diff
10
src/base64.c
10
src/base64.c
@ -69,14 +69,15 @@ size_t mg_base64_encode(const unsigned char *p, size_t n, char *to, size_t dl) {
|
||||
size_t mg_base64_decode(const char *src, size_t n, char *dst, size_t dl) {
|
||||
const char *end = src == NULL ? NULL : src + n; // Cannot add to NULL
|
||||
size_t len = 0;
|
||||
if (dl > 0) dst[0] = '\0';
|
||||
if (dl < n / 4 * 3 + 1) return 0;
|
||||
if (dl < n / 4 * 3 + 1) goto fail;
|
||||
while (src != NULL && src + 3 < end) {
|
||||
int a = mg_base64_decode_single(src[0]),
|
||||
b = mg_base64_decode_single(src[1]),
|
||||
c = mg_base64_decode_single(src[2]),
|
||||
d = mg_base64_decode_single(src[3]);
|
||||
if (a == 64 || a < 0 || b == 64 || b < 0 || c < 0 || d < 0) return 0;
|
||||
if (a == 64 || a < 0 || b == 64 || b < 0 || c < 0 || d < 0) {
|
||||
goto fail;
|
||||
}
|
||||
dst[len++] = (char) ((a << 2) | (b >> 4));
|
||||
if (src[2] != '=') {
|
||||
dst[len++] = (char) ((b << 4) | (c >> 2));
|
||||
@ -86,4 +87,7 @@ size_t mg_base64_decode(const char *src, size_t n, char *dst, size_t dl) {
|
||||
}
|
||||
dst[len] = '\0';
|
||||
return len;
|
||||
fail:
|
||||
if (dl > 0) dst[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ static bool vcb(uint8_t c) {
|
||||
// Get character length (valid utf-8). Used to parse method, URI, headers
|
||||
static size_t clen(const char *s, const char *end) {
|
||||
const unsigned char *u = (unsigned char *) s, c = *u;
|
||||
long n = end - s;
|
||||
long n = (long) (end - s);
|
||||
if (c > ' ' && c < '~') return 1; // Usual ascii printed char
|
||||
if ((c & 0xe0) == 0xc0 && n > 1 && vcb(u[1])) return 2; // 2-byte UTF8
|
||||
if ((c & 0xf0) == 0xe0 && n > 2 && vcb(u[1]) && vcb(u[2])) return 3;
|
||||
@ -983,7 +983,8 @@ static void http_cb(struct mg_connection *c, int ev, void *evd, void *fnd) {
|
||||
struct mg_str *te; // Transfer - encoding header
|
||||
bool is_chunked = false;
|
||||
if (n < 0) {
|
||||
mg_error(c, "HTTP parse");
|
||||
mg_error(c, "HTTP parse, %lu bytes", c->recv.len);
|
||||
mg_hexdump(c->recv.buf, c->recv.len > 16 ? 16 : c->recv.len);
|
||||
return;
|
||||
}
|
||||
if (n == 0) break; // Request is not buffered yet
|
||||
|
@ -28,7 +28,7 @@ enum {
|
||||
MG_OTA_UNAVAILABLE = 0, // No OTA information is present
|
||||
MG_OTA_FIRST_BOOT = 1, // Device booting the first time after the OTA
|
||||
MG_OTA_UNCOMMITTED = 2, // Ditto, but marking us for the rollback
|
||||
MG_OTA_COMMITTED = 3, // The firmware is good
|
||||
MG_OTA_COMMITTED = 3 // The firmware is good
|
||||
};
|
||||
enum { MG_FIRMWARE_CURRENT = 0, MG_FIRMWARE_PREVIOUS = 1 };
|
||||
|
||||
|
160
src/sha256.c
Normal file
160
src/sha256.c
Normal file
@ -0,0 +1,160 @@
|
||||
#include "sha256.h"
|
||||
|
||||
#define ror(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
|
||||
#define ch(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
|
||||
#define maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
#define ep0(x) (ror(x, 2) ^ ror(x, 13) ^ ror(x, 22))
|
||||
#define ep1(x) (ror(x, 6) ^ ror(x, 11) ^ ror(x, 25))
|
||||
#define sig0(x) (ror(x, 7) ^ ror(x, 18) ^ ((x) >> 3))
|
||||
#define sig1(x) (ror(x, 17) ^ ror(x, 19) ^ ((x) >> 10))
|
||||
|
||||
static const uint32_t mg_sha256_k[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
||||
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
||||
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
|
||||
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
|
||||
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
||||
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
|
||||
|
||||
void mg_sha256_init(mg_sha256_ctx *ctx) {
|
||||
ctx->len = 0;
|
||||
ctx->bits = 0;
|
||||
ctx->state[0] = 0x6a09e667;
|
||||
ctx->state[1] = 0xbb67ae85;
|
||||
ctx->state[2] = 0x3c6ef372;
|
||||
ctx->state[3] = 0xa54ff53a;
|
||||
ctx->state[4] = 0x510e527f;
|
||||
ctx->state[5] = 0x9b05688c;
|
||||
ctx->state[6] = 0x1f83d9ab;
|
||||
ctx->state[7] = 0x5be0cd19;
|
||||
}
|
||||
|
||||
static void mg_sha256_chunk(mg_sha256_ctx *ctx) {
|
||||
int i, j;
|
||||
uint32_t a, b, c, d, e, f, g, h;
|
||||
uint32_t m[64];
|
||||
for (i = 0, j = 0; i < 16; ++i, j += 4)
|
||||
m[i] = (uint32_t) ((ctx->buffer[j] << 24) | (ctx->buffer[j + 1] << 16) |
|
||||
(ctx->buffer[j + 2] << 8) | (ctx->buffer[j + 3]));
|
||||
for (; i < 64; ++i)
|
||||
m[i] = sig1(m[i - 2]) + m[i - 7] + sig0(m[i - 15]) + m[i - 16];
|
||||
|
||||
a = ctx->state[0];
|
||||
b = ctx->state[1];
|
||||
c = ctx->state[2];
|
||||
d = ctx->state[3];
|
||||
e = ctx->state[4];
|
||||
f = ctx->state[5];
|
||||
g = ctx->state[6];
|
||||
h = ctx->state[7];
|
||||
|
||||
for (i = 0; i < 64; ++i) {
|
||||
uint32_t t1 = h + ep1(e) + ch(e, f, g) + mg_sha256_k[i] + m[i];
|
||||
uint32_t t2 = ep0(a) + maj(a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
}
|
||||
|
||||
ctx->state[0] += a;
|
||||
ctx->state[1] += b;
|
||||
ctx->state[2] += c;
|
||||
ctx->state[3] += d;
|
||||
ctx->state[4] += e;
|
||||
ctx->state[5] += f;
|
||||
ctx->state[6] += g;
|
||||
ctx->state[7] += h;
|
||||
}
|
||||
|
||||
void mg_sha256_update(mg_sha256_ctx *ctx, const unsigned char *data,
|
||||
size_t len) {
|
||||
size_t i;
|
||||
for (i = 0; i < len; i++) {
|
||||
ctx->buffer[ctx->len] = data[i];
|
||||
if ((++ctx->len) == 64) {
|
||||
mg_sha256_chunk(ctx);
|
||||
ctx->bits += 512;
|
||||
ctx->len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: make final reusable (remove side effects)
|
||||
void mg_sha256_final(unsigned char digest[32], mg_sha256_ctx *ctx) {
|
||||
uint32_t i = ctx->len;
|
||||
if (i < 56) {
|
||||
ctx->buffer[i++] = 0x80;
|
||||
while (i < 56) {
|
||||
ctx->buffer[i++] = 0x00;
|
||||
}
|
||||
} else {
|
||||
ctx->buffer[i++] = 0x80;
|
||||
while (i < 64) {
|
||||
ctx->buffer[i++] = 0x00;
|
||||
}
|
||||
mg_sha256_chunk(ctx);
|
||||
memset(ctx->buffer, 0, 56);
|
||||
}
|
||||
|
||||
ctx->bits += ctx->len * 8;
|
||||
ctx->buffer[63] = (uint8_t) ((ctx->bits) & 0xff);
|
||||
ctx->buffer[62] = (uint8_t) ((ctx->bits >> 8) & 0xff);
|
||||
ctx->buffer[61] = (uint8_t) ((ctx->bits >> 16) & 0xff);
|
||||
ctx->buffer[60] = (uint8_t) ((ctx->bits >> 24) & 0xff);
|
||||
ctx->buffer[59] = (uint8_t) ((ctx->bits >> 32) & 0xff);
|
||||
ctx->buffer[58] = (uint8_t) ((ctx->bits >> 40) & 0xff);
|
||||
ctx->buffer[57] = (uint8_t) ((ctx->bits >> 48) & 0xff);
|
||||
ctx->buffer[56] = (uint8_t) ((ctx->bits >> 56) & 0xff);
|
||||
mg_sha256_chunk(ctx);
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
digest[i] = (ctx->state[0] >> (24 - i * 8)) & 0xff;
|
||||
digest[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0xff;
|
||||
digest[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0xff;
|
||||
digest[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0xff;
|
||||
digest[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0xff;
|
||||
digest[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0xff;
|
||||
digest[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0xff;
|
||||
digest[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data,
|
||||
size_t datasz) {
|
||||
mg_sha256_ctx ctx;
|
||||
uint8_t k[64] = {0};
|
||||
uint8_t o_pad[64], i_pad[64];
|
||||
unsigned int i;
|
||||
memset(i_pad, 0x36, sizeof(i_pad));
|
||||
memset(o_pad, 0x5c, sizeof(o_pad));
|
||||
if (keysz < 64) {
|
||||
memmove(k, key, keysz);
|
||||
} else {
|
||||
mg_sha256_init(&ctx);
|
||||
mg_sha256_update(&ctx, key, keysz);
|
||||
mg_sha256_final(k, &ctx);
|
||||
}
|
||||
for (i = 0; i < sizeof(k); i++) {
|
||||
i_pad[i] ^= k[i];
|
||||
o_pad[i] ^= k[i];
|
||||
}
|
||||
mg_sha256_init(&ctx);
|
||||
mg_sha256_update(&ctx, i_pad, sizeof(i_pad));
|
||||
mg_sha256_update(&ctx, data, datasz);
|
||||
mg_sha256_final(dst, &ctx);
|
||||
mg_sha256_init(&ctx);
|
||||
mg_sha256_update(&ctx, o_pad, sizeof(o_pad));
|
||||
mg_sha256_update(&ctx, dst, 32);
|
||||
mg_sha256_final(dst, &ctx);
|
||||
}
|
||||
|
16
src/sha256.h
Normal file
16
src/sha256.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "arch.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t state[8];
|
||||
uint64_t bits;
|
||||
uint32_t len;
|
||||
unsigned char buffer[64];
|
||||
} mg_sha256_ctx;
|
||||
|
||||
void mg_sha256_init(mg_sha256_ctx *);
|
||||
void mg_sha256_update(mg_sha256_ctx *, const unsigned char *data, size_t len);
|
||||
void mg_sha256_final(unsigned char digest[32], mg_sha256_ctx *);
|
||||
void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data,
|
||||
size_t datasz);
|
1002
src/tls_aes128.c
Normal file
1002
src/tls_aes128.c
Normal file
File diff suppressed because it is too large
Load Diff
263
src/tls_aes128.h
Normal file
263
src/tls_aes128.h
Normal file
@ -0,0 +1,263 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
|
||||
*
|
||||
* This is a simple and straightforward implementation of the AES Rijndael
|
||||
* 128-bit block cipher designed by Vincent Rijmen and Joan Daemen. The focus
|
||||
* of this work was correctness & accuracy. It is written in 'C' without any
|
||||
* particular focus upon optimization or speed. It should be endian (memory
|
||||
* byte order) neutral since the few places that care are handled explicitly.
|
||||
*
|
||||
* This implementation of Rijndael was created by Steven M. Gibson of GRC.com.
|
||||
*
|
||||
* It is intended for general purpose use, but was written in support of GRC's
|
||||
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
|
||||
*
|
||||
* See: http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html
|
||||
*
|
||||
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
|
||||
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef AES_HEADER
|
||||
#define AES_HEADER
|
||||
|
||||
/******************************************************************************/
|
||||
#define AES_DECRYPTION 1 // whether AES decryption is supported
|
||||
/******************************************************************************/
|
||||
|
||||
#define ENCRYPT 1 // specify whether we're encrypting
|
||||
#define DECRYPT 0 // or decrypting
|
||||
|
||||
#include "arch.h"
|
||||
|
||||
typedef unsigned char uchar; // add some convienent shorter types
|
||||
typedef unsigned int uint;
|
||||
|
||||
/******************************************************************************
|
||||
* AES_INIT_KEYGEN_TABLES : MUST be called once before any AES use
|
||||
******************************************************************************/
|
||||
void aes_init_keygen_tables(void);
|
||||
|
||||
/******************************************************************************
|
||||
* AES_CONTEXT : cipher context / holds inter-call data
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
int mode; // 1 for Encryption, 0 for Decryption
|
||||
int rounds; // keysize-based rounds count
|
||||
uint32_t *rk; // pointer to current round key
|
||||
uint32_t buf[68]; // key expansion buffer
|
||||
} aes_context;
|
||||
|
||||
/******************************************************************************
|
||||
* AES_SETKEY : called to expand the key for encryption or decryption
|
||||
******************************************************************************/
|
||||
int aes_setkey(aes_context *ctx, // pointer to context
|
||||
int mode, // 1 or 0 for Encrypt/Decrypt
|
||||
const uchar *key, // AES input key
|
||||
uint keysize); // size in bytes (must be 16, 24, 32 for
|
||||
// 128, 192 or 256-bit keys respectively)
|
||||
// returns 0 for success
|
||||
|
||||
/******************************************************************************
|
||||
* AES_CIPHER : called to encrypt or decrypt ONE 128-bit block of data
|
||||
******************************************************************************/
|
||||
int aes_cipher(aes_context *ctx, // pointer to context
|
||||
const uchar input[16], // 128-bit block to en/decipher
|
||||
uchar output[16]); // 128-bit output result block
|
||||
// returns 0 for success
|
||||
|
||||
#endif /* AES_HEADER */
|
||||
/******************************************************************************
|
||||
*
|
||||
* THIS SOURCE CODE IS HEREBY PLACED INTO THE PUBLIC DOMAIN FOR THE GOOD OF ALL
|
||||
*
|
||||
* This is a simple and straightforward implementation of AES-GCM authenticated
|
||||
* encryption. The focus of this work was correctness & accuracy. It is written
|
||||
* in straight 'C' without any particular focus upon optimization or speed. It
|
||||
* should be endian (memory byte order) neutral since the few places that care
|
||||
* are handled explicitly.
|
||||
*
|
||||
* This implementation of AES-GCM was created by Steven M. Gibson of GRC.com.
|
||||
*
|
||||
* It is intended for general purpose use, but was written in support of GRC's
|
||||
* reference implementation of the SQRL (Secure Quick Reliable Login) client.
|
||||
*
|
||||
* See: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf
|
||||
* http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/ \
|
||||
* gcm/gcm-revised-spec.pdf
|
||||
*
|
||||
* NO COPYRIGHT IS CLAIMED IN THIS WORK, HOWEVER, NEITHER IS ANY WARRANTY MADE
|
||||
* REGARDING ITS FITNESS FOR ANY PARTICULAR PURPOSE. USE IT AT YOUR OWN RISK.
|
||||
*
|
||||
*******************************************************************************/
|
||||
#ifndef GCM_HEADER
|
||||
#define GCM_HEADER
|
||||
|
||||
#include "arch.h"
|
||||
#define GCM_AUTH_FAILURE 0x55555555 // authentication failure
|
||||
|
||||
/******************************************************************************
|
||||
* GCM_CONTEXT : GCM context / holds keytables, instance data, and AES ctx
|
||||
******************************************************************************/
|
||||
typedef struct {
|
||||
int mode; // cipher direction: encrypt/decrypt
|
||||
uint64_t len; // cipher data length processed so far
|
||||
uint64_t add_len; // total add data length
|
||||
uint64_t HL[16]; // precalculated lo-half HTable
|
||||
uint64_t HH[16]; // precalculated hi-half HTable
|
||||
uchar base_ectr[16]; // first counter-mode cipher output for tag
|
||||
uchar y[16]; // the current cipher-input IV|Counter value
|
||||
uchar buf[16]; // buf working value
|
||||
aes_context aes_ctx; // cipher context used
|
||||
} gcm_context;
|
||||
|
||||
/******************************************************************************
|
||||
* GCM_CONTEXT : MUST be called once before ANY use of this library
|
||||
******************************************************************************/
|
||||
int gcm_initialize(void);
|
||||
|
||||
/******************************************************************************
|
||||
* GCM_SETKEY : sets the GCM (and AES) keying material for use
|
||||
******************************************************************************/
|
||||
int gcm_setkey(gcm_context *ctx, // caller-provided context ptr
|
||||
const uchar *key, // pointer to cipher key
|
||||
const uint keysize // size in bytes (must be 16, 24, 32 for
|
||||
// 128, 192 or 256-bit keys respectively)
|
||||
); // returns 0 for success
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* GCM_CRYPT_AND_TAG
|
||||
*
|
||||
* This either encrypts or decrypts the user-provided data and, either
|
||||
* way, generates an authentication tag of the requested length. It must be
|
||||
* called with a GCM context whose key has already been set with GCM_SETKEY.
|
||||
*
|
||||
* The user would typically call this explicitly to ENCRYPT a buffer of data
|
||||
* and optional associated data, and produce its an authentication tag.
|
||||
*
|
||||
* To reverse the process the user would typically call the companion
|
||||
* GCM_AUTH_DECRYPT function to decrypt data and verify a user-provided
|
||||
* authentication tag. The GCM_AUTH_DECRYPT function calls this function
|
||||
* to perform its decryption and tag generation, which it then compares.
|
||||
*
|
||||
******************************************************************************/
|
||||
int gcm_crypt_and_tag(
|
||||
gcm_context *ctx, // gcm context with key already setup
|
||||
int mode, // cipher direction: ENCRYPT (1) or DECRYPT (0)
|
||||
const uchar *iv, // pointer to the 12-byte initialization vector
|
||||
size_t iv_len, // byte length if the IV. should always be 12
|
||||
const uchar *add, // pointer to the non-ciphered additional data
|
||||
size_t add_len, // byte length of the additional AEAD data
|
||||
const uchar *input, // pointer to the cipher data source
|
||||
uchar *output, // pointer to the cipher data destination
|
||||
size_t length, // byte length of the cipher data
|
||||
uchar *tag, // pointer to the tag to be generated
|
||||
size_t tag_len); // byte length of the tag to be generated
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* GCM_AUTH_DECRYPT
|
||||
*
|
||||
* This DECRYPTS a user-provided data buffer with optional associated data.
|
||||
* It then verifies a user-supplied authentication tag against the tag just
|
||||
* re-created during decryption to verify that the data has not been altered.
|
||||
*
|
||||
* This function calls GCM_CRYPT_AND_TAG (above) to perform the decryption
|
||||
* and authentication tag generation.
|
||||
*
|
||||
******************************************************************************/
|
||||
int gcm_auth_decrypt(
|
||||
gcm_context *ctx, // gcm context with key already setup
|
||||
const uchar *iv, // pointer to the 12-byte initialization vector
|
||||
size_t iv_len, // byte length if the IV. should always be 12
|
||||
const uchar *add, // pointer to the non-ciphered additional data
|
||||
size_t add_len, // byte length of the additional AEAD data
|
||||
const uchar *input, // pointer to the cipher data source
|
||||
uchar *output, // pointer to the cipher data destination
|
||||
size_t length, // byte length of the cipher data
|
||||
const uchar *tag, // pointer to the tag to be authenticated
|
||||
size_t tag_len); // byte length of the tag <= 16
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* GCM_START
|
||||
*
|
||||
* Given a user-provided GCM context, this initializes it, sets the encryption
|
||||
* mode, and preprocesses the initialization vector and additional AEAD data.
|
||||
*
|
||||
******************************************************************************/
|
||||
int gcm_start(
|
||||
gcm_context *ctx, // pointer to user-provided GCM context
|
||||
int mode, // ENCRYPT (1) or DECRYPT (0)
|
||||
const uchar *iv, // pointer to initialization vector
|
||||
size_t iv_len, // IV length in bytes (should == 12)
|
||||
const uchar *add, // pointer to additional AEAD data (NULL if none)
|
||||
size_t add_len); // length of additional AEAD data (bytes)
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* GCM_UPDATE
|
||||
*
|
||||
* This is called once or more to process bulk plaintext or ciphertext data.
|
||||
* We give this some number of bytes of input and it returns the same number
|
||||
* of output bytes. If called multiple times (which is fine) all but the final
|
||||
* invocation MUST be called with length mod 16 == 0. (Only the final call can
|
||||
* have a partial block length of < 128 bits.)
|
||||
*
|
||||
******************************************************************************/
|
||||
int gcm_update(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
size_t length, // length, in bytes, of data to process
|
||||
const uchar *input, // pointer to source data
|
||||
uchar *output); // pointer to destination data
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* GCM_FINISH
|
||||
*
|
||||
* This is called once after all calls to GCM_UPDATE to finalize the GCM.
|
||||
* It performs the final GHASH to produce the resulting authentication TAG.
|
||||
*
|
||||
******************************************************************************/
|
||||
int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
|
||||
uchar *tag, // ptr to tag buffer - NULL if tag_len = 0
|
||||
size_t tag_len); // length, in bytes, of the tag-receiving buf
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* GCM_ZERO_CTX
|
||||
*
|
||||
* The GCM context contains both the GCM context and the AES context.
|
||||
* This includes keying and key-related material which is security-
|
||||
* sensitive, so it MUST be zeroed after use. This function does that.
|
||||
*
|
||||
******************************************************************************/
|
||||
void gcm_zero_ctx(gcm_context *ctx);
|
||||
|
||||
#endif /* GCM_HEADER */
|
||||
//
|
||||
// aes-gcm.h
|
||||
// MKo
|
||||
//
|
||||
// Created by Markus Kosmal on 20/11/14.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef mko_aes_gcm_h
|
||||
#define mko_aes_gcm_h
|
||||
|
||||
int aes_gcm_encrypt(unsigned char *output, const unsigned char *input,
|
||||
size_t input_length, const unsigned char *key,
|
||||
const size_t key_len, const unsigned char *iv,
|
||||
const size_t iv_len, unsigned char *aead, size_t aead_len,
|
||||
unsigned char *tag, const size_t tag_len);
|
||||
|
||||
int aes_gcm_decrypt(unsigned char *output, const unsigned char *input,
|
||||
size_t input_length, const unsigned char *key,
|
||||
const size_t key_len, const unsigned char *iv,
|
||||
const size_t iv_len);
|
||||
|
||||
#endif
|
||||
|
1010
src/tls_builtin.c
1010
src/tls_builtin.c
File diff suppressed because it is too large
Load Diff
3173
src/tls_uecc.c
Normal file
3173
src/tls_uecc.c
Normal file
File diff suppressed because it is too large
Load Diff
638
src/tls_uecc.h
Normal file
638
src/tls_uecc.h
Normal file
@ -0,0 +1,638 @@
|
||||
#pragma once
|
||||
#include "arch.h"
|
||||
|
||||
#define uECC_SUPPORTS_secp256r1 1
|
||||
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
|
||||
|
||||
#ifndef _UECC_H_
|
||||
#define _UECC_H_
|
||||
|
||||
/* Platform selection options.
|
||||
If uECC_PLATFORM is not defined, the code will try to guess it based on compiler
|
||||
macros. Possible values for uECC_PLATFORM are defined below: */
|
||||
#define uECC_arch_other 0
|
||||
#define uECC_x86 1
|
||||
#define uECC_x86_64 2
|
||||
#define uECC_arm 3
|
||||
#define uECC_arm_thumb 4
|
||||
#define uECC_arm_thumb2 5
|
||||
#define uECC_arm64 6
|
||||
#define uECC_avr 7
|
||||
|
||||
/* If desired, you can define uECC_WORD_SIZE as appropriate for your platform
|
||||
(1, 4, or 8 bytes). If uECC_WORD_SIZE is not explicitly defined then it will be
|
||||
automatically set based on your platform. */
|
||||
|
||||
/* Optimization level; trade speed for code size.
|
||||
Larger values produce code that is faster but larger.
|
||||
Currently supported values are 0 - 4; 0 is unusably slow for most
|
||||
applications. Optimization level 4 currently only has an effect ARM platforms
|
||||
where more than one curve is enabled. */
|
||||
#ifndef uECC_OPTIMIZATION_LEVEL
|
||||
#define uECC_OPTIMIZATION_LEVEL 2
|
||||
#endif
|
||||
|
||||
/* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a
|
||||
specific function to be used for (scalar) squaring instead of the generic
|
||||
multiplication function. This can make things faster somewhat faster, but
|
||||
increases the code size. */
|
||||
#ifndef uECC_SQUARE_FUNC
|
||||
#define uECC_SQUARE_FUNC 0
|
||||
#endif
|
||||
|
||||
/* uECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will
|
||||
switch to native little-endian format for *all* arrays passed in and out of the
|
||||
public API. This includes public and private keys, shared secrets, signatures
|
||||
and message hashes. Using this switch reduces the amount of call stack memory
|
||||
used by uECC, since less intermediate translations are required. Note that this
|
||||
will *only* work on native little-endian processors and it will treat the
|
||||
uint8_t arrays passed into the public API as word arrays, therefore requiring
|
||||
the provided byte arrays to be word aligned on architectures that do not support
|
||||
unaligned accesses. IMPORTANT: Keys and signatures generated with
|
||||
uECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible with keys and signatures
|
||||
generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use the same
|
||||
endianness. */
|
||||
#ifndef uECC_VLI_NATIVE_LITTLE_ENDIAN
|
||||
#define uECC_VLI_NATIVE_LITTLE_ENDIAN 0
|
||||
#endif
|
||||
|
||||
/* Curve support selection. Set to 0 to remove that curve. */
|
||||
#ifndef uECC_SUPPORTS_secp160r1
|
||||
#define uECC_SUPPORTS_secp160r1 0
|
||||
#endif
|
||||
#ifndef uECC_SUPPORTS_secp192r1
|
||||
#define uECC_SUPPORTS_secp192r1 0
|
||||
#endif
|
||||
#ifndef uECC_SUPPORTS_secp224r1
|
||||
#define uECC_SUPPORTS_secp224r1 0
|
||||
#endif
|
||||
#ifndef uECC_SUPPORTS_secp256r1
|
||||
#define uECC_SUPPORTS_secp256r1 1
|
||||
#endif
|
||||
#ifndef uECC_SUPPORTS_secp256k1
|
||||
#define uECC_SUPPORTS_secp256k1 0
|
||||
#endif
|
||||
|
||||
/* Specifies whether compressed point format is supported.
|
||||
Set to 0 to disable point compression/decompression functions. */
|
||||
#ifndef uECC_SUPPORT_COMPRESSED_POINT
|
||||
#define uECC_SUPPORT_COMPRESSED_POINT 1
|
||||
#endif
|
||||
|
||||
struct uECC_Curve_t;
|
||||
typedef const struct uECC_Curve_t *uECC_Curve;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if uECC_SUPPORTS_secp160r1
|
||||
uECC_Curve uECC_secp160r1(void);
|
||||
#endif
|
||||
#if uECC_SUPPORTS_secp192r1
|
||||
uECC_Curve uECC_secp192r1(void);
|
||||
#endif
|
||||
#if uECC_SUPPORTS_secp224r1
|
||||
uECC_Curve uECC_secp224r1(void);
|
||||
#endif
|
||||
#if uECC_SUPPORTS_secp256r1
|
||||
uECC_Curve uECC_secp256r1(void);
|
||||
#endif
|
||||
#if uECC_SUPPORTS_secp256k1
|
||||
uECC_Curve uECC_secp256k1(void);
|
||||
#endif
|
||||
|
||||
/* uECC_RNG_Function type
|
||||
The RNG function should fill 'size' random bytes into 'dest'. It should return 1
|
||||
if 'dest' was filled with random data, or 0 if the random data could not be
|
||||
generated. The filled-in values should be either truly random, or from a
|
||||
cryptographically-secure PRNG.
|
||||
|
||||
A correctly functioning RNG function must be set (using uECC_set_rng()) before
|
||||
calling uECC_make_key() or uECC_sign().
|
||||
|
||||
Setting a correctly functioning RNG function improves the resistance to
|
||||
side-channel attacks for uECC_shared_secret() and uECC_sign_deterministic().
|
||||
|
||||
A correct RNG function is set by default when building for Windows, Linux, or OS
|
||||
X. If you are building on another POSIX-compliant system that supports
|
||||
/dev/random or /dev/urandom, you can define uECC_POSIX to use the predefined
|
||||
RNG. For embedded platforms there is no predefined RNG function; you must
|
||||
provide your own.
|
||||
*/
|
||||
typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size);
|
||||
|
||||
/* uECC_set_rng() function.
|
||||
Set the function that will be used to generate random bytes. The RNG function
|
||||
should return 1 if the random data was generated, or 0 if the random data could
|
||||
not be generated.
|
||||
|
||||
On platforms where there is no predefined RNG function (eg embedded platforms),
|
||||
this must be called before uECC_make_key() or uECC_sign() are used.
|
||||
|
||||
Inputs:
|
||||
rng_function - The function that will be used to generate random bytes.
|
||||
*/
|
||||
void uECC_set_rng(uECC_RNG_Function rng_function);
|
||||
|
||||
/* uECC_get_rng() function.
|
||||
|
||||
Returns the function that will be used to generate random bytes.
|
||||
*/
|
||||
uECC_RNG_Function uECC_get_rng(void);
|
||||
|
||||
/* uECC_curve_private_key_size() function.
|
||||
|
||||
Returns the size of a private key for the curve in bytes.
|
||||
*/
|
||||
int uECC_curve_private_key_size(uECC_Curve curve);
|
||||
|
||||
/* uECC_curve_public_key_size() function.
|
||||
|
||||
Returns the size of a public key for the curve in bytes.
|
||||
*/
|
||||
int uECC_curve_public_key_size(uECC_Curve curve);
|
||||
|
||||
/* uECC_make_key() function.
|
||||
Create a public/private key pair.
|
||||
|
||||
Outputs:
|
||||
public_key - Will be filled in with the public key. Must be at least 2 *
|
||||
the curve size (in bytes) long. For example, if the curve is secp256r1,
|
||||
public_key must be 64 bytes long. private_key - Will be filled in with the
|
||||
private key. Must be as long as the curve order; this is typically the same as
|
||||
the curve size, except for secp160r1. For example, if the curve is secp256r1,
|
||||
private_key must be 32 bytes long.
|
||||
|
||||
For secp160r1, private_key must be 21 bytes long! Note that
|
||||
the first byte will almost always be 0 (there is about a 1 in 2^80 chance of it
|
||||
being non-zero).
|
||||
|
||||
Returns 1 if the key pair was generated successfully, 0 if an error occurred.
|
||||
*/
|
||||
int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve);
|
||||
|
||||
/* uECC_shared_secret() function.
|
||||
Compute a shared secret given your secret key and someone else's public key. If
|
||||
the public key is not from a trusted source and has not been previously
|
||||
verified, you should verify it first using uECC_valid_public_key(). Note: It is
|
||||
recommended that you hash the result of uECC_shared_secret() before using it for
|
||||
symmetric encryption or HMAC.
|
||||
|
||||
Inputs:
|
||||
public_key - The public key of the remote party.
|
||||
private_key - Your private key.
|
||||
|
||||
Outputs:
|
||||
secret - Will be filled in with the shared secret value. Must be the same
|
||||
size as the curve size; for example, if the curve is secp256r1, secret must be
|
||||
32 bytes long.
|
||||
|
||||
Returns 1 if the shared secret was generated successfully, 0 if an error
|
||||
occurred.
|
||||
*/
|
||||
int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key,
|
||||
uint8_t *secret, uECC_Curve curve);
|
||||
|
||||
#if uECC_SUPPORT_COMPRESSED_POINT
|
||||
/* uECC_compress() function.
|
||||
Compress a public key.
|
||||
|
||||
Inputs:
|
||||
public_key - The public key to compress.
|
||||
|
||||
Outputs:
|
||||
compressed - Will be filled in with the compressed public key. Must be at
|
||||
least (curve size + 1) bytes long; for example, if the curve is secp256r1,
|
||||
compressed must be 33 bytes long.
|
||||
*/
|
||||
void uECC_compress(const uint8_t *public_key, uint8_t *compressed,
|
||||
uECC_Curve curve);
|
||||
|
||||
/* uECC_decompress() function.
|
||||
Decompress a compressed public key.
|
||||
|
||||
Inputs:
|
||||
compressed - The compressed public key.
|
||||
|
||||
Outputs:
|
||||
public_key - Will be filled in with the decompressed public key.
|
||||
*/
|
||||
void uECC_decompress(const uint8_t *compressed, uint8_t *public_key,
|
||||
uECC_Curve curve);
|
||||
#endif /* uECC_SUPPORT_COMPRESSED_POINT */
|
||||
|
||||
/* uECC_valid_public_key() function.
|
||||
Check to see if a public key is valid.
|
||||
|
||||
Note that you are not required to check for a valid public key before using any
|
||||
other uECC functions. However, you may wish to avoid spending CPU time computing
|
||||
a shared secret or verifying a signature using an invalid public key.
|
||||
|
||||
Inputs:
|
||||
public_key - The public key to check.
|
||||
|
||||
Returns 1 if the public key is valid, 0 if it is invalid.
|
||||
*/
|
||||
int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve);
|
||||
|
||||
/* uECC_compute_public_key() function.
|
||||
Compute the corresponding public key for a private key.
|
||||
|
||||
Inputs:
|
||||
private_key - The private key to compute the public key for
|
||||
|
||||
Outputs:
|
||||
public_key - Will be filled in with the corresponding public key
|
||||
|
||||
Returns 1 if the key was computed successfully, 0 if an error occurred.
|
||||
*/
|
||||
int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key,
|
||||
uECC_Curve curve);
|
||||
|
||||
/* uECC_sign() function.
|
||||
Generate an ECDSA signature for a given hash value.
|
||||
|
||||
Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and
|
||||
pass it in to this function along with your private key.
|
||||
|
||||
Inputs:
|
||||
private_key - Your private key.
|
||||
message_hash - The hash of the message to sign.
|
||||
hash_size - The size of message_hash in bytes.
|
||||
|
||||
Outputs:
|
||||
signature - Will be filled in with the signature value. Must be at least 2 *
|
||||
curve size long. For example, if the curve is secp256r1, signature must be 64
|
||||
bytes long.
|
||||
|
||||
Returns 1 if the signature generated successfully, 0 if an error occurred.
|
||||
*/
|
||||
int uECC_sign(const uint8_t *private_key, const uint8_t *message_hash,
|
||||
unsigned hash_size, uint8_t *signature, uECC_Curve curve);
|
||||
|
||||
/* uECC_HashContext structure.
|
||||
This is used to pass in an arbitrary hash function to uECC_sign_deterministic().
|
||||
The structure will be used for multiple hash computations; each time a new hash
|
||||
is computed, init_hash() will be called, followed by one or more calls to
|
||||
update_hash(), and finally a call to finish_hash() to produce the resulting
|
||||
hash.
|
||||
|
||||
The intention is that you will create a structure that includes uECC_HashContext
|
||||
followed by any hash-specific data. For example:
|
||||
|
||||
typedef struct SHA256_HashContext {
|
||||
uECC_HashContext uECC;
|
||||
SHA256_CTX ctx;
|
||||
} SHA256_HashContext;
|
||||
|
||||
void init_SHA256(uECC_HashContext *base) {
|
||||
SHA256_HashContext *context = (SHA256_HashContext *)base;
|
||||
SHA256_Init(&context->ctx);
|
||||
}
|
||||
|
||||
void update_SHA256(uECC_HashContext *base,
|
||||
const uint8_t *message,
|
||||
unsigned message_size) {
|
||||
SHA256_HashContext *context = (SHA256_HashContext *)base;
|
||||
SHA256_Update(&context->ctx, message, message_size);
|
||||
}
|
||||
|
||||
void finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) {
|
||||
SHA256_HashContext *context = (SHA256_HashContext *)base;
|
||||
SHA256_Final(hash_result, &context->ctx);
|
||||
}
|
||||
|
||||
... when signing ...
|
||||
{
|
||||
uint8_t tmp[32 + 32 + 64];
|
||||
SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64,
|
||||
32, tmp}}; uECC_sign_deterministic(key, message_hash, &ctx.uECC, signature);
|
||||
}
|
||||
*/
|
||||
typedef struct uECC_HashContext {
|
||||
void (*init_hash)(const struct uECC_HashContext *context);
|
||||
void (*update_hash)(const struct uECC_HashContext *context,
|
||||
const uint8_t *message, unsigned message_size);
|
||||
void (*finish_hash)(const struct uECC_HashContext *context,
|
||||
uint8_t *hash_result);
|
||||
unsigned
|
||||
block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */
|
||||
unsigned
|
||||
result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */
|
||||
uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size +
|
||||
block_size) bytes. */
|
||||
} uECC_HashContext;
|
||||
|
||||
/* uECC_sign_deterministic() function.
|
||||
Generate an ECDSA signature for a given hash value, using a deterministic
|
||||
algorithm (see RFC 6979). You do not need to set the RNG using uECC_set_rng()
|
||||
before calling this function; however, if the RNG is defined it will improve
|
||||
resistance to side-channel attacks.
|
||||
|
||||
Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and
|
||||
pass it to this function along with your private key and a hash context. Note
|
||||
that the message_hash does not need to be computed with the same hash function
|
||||
used by hash_context.
|
||||
|
||||
Inputs:
|
||||
private_key - Your private key.
|
||||
message_hash - The hash of the message to sign.
|
||||
hash_size - The size of message_hash in bytes.
|
||||
hash_context - A hash context to use.
|
||||
|
||||
Outputs:
|
||||
signature - Will be filled in with the signature value.
|
||||
|
||||
Returns 1 if the signature generated successfully, 0 if an error occurred.
|
||||
*/
|
||||
int uECC_sign_deterministic(const uint8_t *private_key,
|
||||
const uint8_t *message_hash, unsigned hash_size,
|
||||
const uECC_HashContext *hash_context,
|
||||
uint8_t *signature, uECC_Curve curve);
|
||||
|
||||
/* uECC_verify() function.
|
||||
Verify an ECDSA signature.
|
||||
|
||||
Usage: Compute the hash of the signed data using the same hash as the signer and
|
||||
pass it to this function along with the signer's public key and the signature
|
||||
values (r and s).
|
||||
|
||||
Inputs:
|
||||
public_key - The signer's public key.
|
||||
message_hash - The hash of the signed data.
|
||||
hash_size - The size of message_hash in bytes.
|
||||
signature - The signature value.
|
||||
|
||||
Returns 1 if the signature is valid, 0 if it is invalid.
|
||||
*/
|
||||
int uECC_verify(const uint8_t *public_key, const uint8_t *message_hash,
|
||||
unsigned hash_size, const uint8_t *signature, uECC_Curve curve);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* _UECC_H_ */
|
||||
|
||||
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
|
||||
|
||||
#ifndef _UECC_VLI_H_
|
||||
#define _UECC_VLI_H_
|
||||
|
||||
//#include "types.h"
|
||||
//#include "uECC.h"
|
||||
|
||||
/* Functions for raw large-integer manipulation. These are only available
|
||||
if uECC.c is compiled with uECC_ENABLE_VLI_API defined to 1. */
|
||||
#ifndef uECC_ENABLE_VLI_API
|
||||
#define uECC_ENABLE_VLI_API 0
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if uECC_ENABLE_VLI_API
|
||||
|
||||
void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words);
|
||||
|
||||
/* Constant-time comparison to zero - secure way to compare long integers */
|
||||
/* Returns 1 if vli == 0, 0 otherwise. */
|
||||
uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words);
|
||||
|
||||
/* Returns nonzero if bit 'bit' of vli is set. */
|
||||
uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit);
|
||||
|
||||
/* Counts the number of bits required to represent vli. */
|
||||
bitcount_t uECC_vli_numBits(const uECC_word_t *vli,
|
||||
const wordcount_t max_words);
|
||||
|
||||
/* Sets dest = src. */
|
||||
void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Constant-time comparison function - secure way to compare long integers */
|
||||
/* Returns one if left == right, zero otherwise */
|
||||
uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Constant-time comparison function - secure way to compare long integers */
|
||||
/* Returns sign of left - right, in constant time. */
|
||||
cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes vli = vli >> 1. */
|
||||
void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words);
|
||||
|
||||
/* Computes result = left + right, returning carry. Can modify in place. */
|
||||
uECC_word_t uECC_vli_add(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, wordcount_t num_words);
|
||||
|
||||
/* Computes result = left - right, returning borrow. Can modify in place. */
|
||||
uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, wordcount_t num_words);
|
||||
|
||||
/* Computes result = left * right. Result must be 2 * num_words long. */
|
||||
void uECC_vli_mult(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, wordcount_t num_words);
|
||||
|
||||
/* Computes result = left^2. Result must be 2 * num_words long. */
|
||||
void uECC_vli_square(uECC_word_t *result, const uECC_word_t *left,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes result = (left + right) % mod.
|
||||
Assumes that left < mod and right < mod, and that result does not overlap
|
||||
mod. */
|
||||
void uECC_vli_modAdd(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, const uECC_word_t *mod,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes result = (left - right) % mod.
|
||||
Assumes that left < mod and right < mod, and that result does not overlap
|
||||
mod. */
|
||||
void uECC_vli_modSub(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, const uECC_word_t *mod,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes result = product % mod, where product is 2N words long.
|
||||
Currently only designed to work for mod == curve->p or curve_n. */
|
||||
void uECC_vli_mmod(uECC_word_t *result, uECC_word_t *product,
|
||||
const uECC_word_t *mod, wordcount_t num_words);
|
||||
|
||||
/* Calculates result = product (mod curve->p), where product is up to
|
||||
2 * curve->num_words long. */
|
||||
void uECC_vli_mmod_fast(uECC_word_t *result, uECC_word_t *product,
|
||||
uECC_Curve curve);
|
||||
|
||||
/* Computes result = (left * right) % mod.
|
||||
Currently only designed to work for mod == curve->p or curve_n. */
|
||||
void uECC_vli_modMult(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, const uECC_word_t *mod,
|
||||
wordcount_t num_words);
|
||||
|
||||
/* Computes result = (left * right) % curve->p. */
|
||||
void uECC_vli_modMult_fast(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *right, uECC_Curve curve);
|
||||
|
||||
/* Computes result = left^2 % mod.
|
||||
Currently only designed to work for mod == curve->p or curve_n. */
|
||||
void uECC_vli_modSquare(uECC_word_t *result, const uECC_word_t *left,
|
||||
const uECC_word_t *mod, wordcount_t num_words);
|
||||
|
||||
/* Computes result = left^2 % curve->p. */
|
||||
void uECC_vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left,
|
||||
uECC_Curve curve);
|
||||
|
||||
/* Computes result = (1 / input) % mod.*/
|
||||
void uECC_vli_modInv(uECC_word_t *result, const uECC_word_t *input,
|
||||
const uECC_word_t *mod, wordcount_t num_words);
|
||||
|
||||
#if uECC_SUPPORT_COMPRESSED_POINT
|
||||
/* Calculates a = sqrt(a) (mod curve->p) */
|
||||
void uECC_vli_mod_sqrt(uECC_word_t *a, uECC_Curve curve);
|
||||
#endif
|
||||
|
||||
/* Converts an integer in uECC native format to big-endian bytes. */
|
||||
void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes,
|
||||
const uECC_word_t *native);
|
||||
/* Converts big-endian bytes to an integer in uECC native format. */
|
||||
void uECC_vli_bytesToNative(uECC_word_t *native, const uint8_t *bytes,
|
||||
int num_bytes);
|
||||
|
||||
unsigned uECC_curve_num_words(uECC_Curve curve);
|
||||
unsigned uECC_curve_num_bytes(uECC_Curve curve);
|
||||
unsigned uECC_curve_num_bits(uECC_Curve curve);
|
||||
unsigned uECC_curve_num_n_words(uECC_Curve curve);
|
||||
unsigned uECC_curve_num_n_bytes(uECC_Curve curve);
|
||||
unsigned uECC_curve_num_n_bits(uECC_Curve curve);
|
||||
|
||||
const uECC_word_t *uECC_curve_p(uECC_Curve curve);
|
||||
const uECC_word_t *uECC_curve_n(uECC_Curve curve);
|
||||
const uECC_word_t *uECC_curve_G(uECC_Curve curve);
|
||||
const uECC_word_t *uECC_curve_b(uECC_Curve curve);
|
||||
|
||||
int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve);
|
||||
|
||||
/* Multiplies a point by a scalar. Points are represented by the X coordinate
|
||||
followed by the Y coordinate in the same array, both coordinates are
|
||||
curve->num_words long. Note that scalar must be curve->num_n_words long (NOT
|
||||
curve->num_words). */
|
||||
void uECC_point_mult(uECC_word_t *result, const uECC_word_t *point,
|
||||
const uECC_word_t *scalar, uECC_Curve curve);
|
||||
|
||||
/* Generates a random integer in the range 0 < random < top.
|
||||
Both random and top have num_words words. */
|
||||
int uECC_generate_random_int(uECC_word_t *random, const uECC_word_t *top,
|
||||
wordcount_t num_words);
|
||||
|
||||
#endif /* uECC_ENABLE_VLI_API */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* _UECC_VLI_H_ */
|
||||
|
||||
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
|
||||
|
||||
#ifndef _UECC_TYPES_H_
|
||||
#define _UECC_TYPES_H_
|
||||
|
||||
#ifndef uECC_PLATFORM
|
||||
#if defined(__AVR__) && __AVR__
|
||||
#define uECC_PLATFORM uECC_avr
|
||||
#elif defined(__thumb2__) || \
|
||||
defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */
|
||||
#define uECC_PLATFORM uECC_arm_thumb2
|
||||
#elif defined(__thumb__)
|
||||
#define uECC_PLATFORM uECC_arm_thumb
|
||||
#elif defined(__arm__) || defined(_M_ARM)
|
||||
#define uECC_PLATFORM uECC_arm
|
||||
#elif defined(__aarch64__)
|
||||
#define uECC_PLATFORM uECC_arm64
|
||||
#elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || \
|
||||
defined(__I86__)
|
||||
#define uECC_PLATFORM uECC_x86
|
||||
#elif defined(__amd64__) || defined(_M_X64)
|
||||
#define uECC_PLATFORM uECC_x86_64
|
||||
#else
|
||||
#define uECC_PLATFORM uECC_arch_other
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef uECC_ARM_USE_UMAAL
|
||||
#if (uECC_PLATFORM == uECC_arm) && (__ARM_ARCH >= 6)
|
||||
#define uECC_ARM_USE_UMAAL 1
|
||||
#elif (uECC_PLATFORM == uECC_arm_thumb2) && (__ARM_ARCH >= 6) && \
|
||||
(!defined(__ARM_ARCH_7M__) || !__ARM_ARCH_7M__)
|
||||
#define uECC_ARM_USE_UMAAL 1
|
||||
#else
|
||||
#define uECC_ARM_USE_UMAAL 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef uECC_WORD_SIZE
|
||||
#if uECC_PLATFORM == uECC_avr
|
||||
#define uECC_WORD_SIZE 1
|
||||
#elif (uECC_PLATFORM == uECC_x86_64 || uECC_PLATFORM == uECC_arm64)
|
||||
#define uECC_WORD_SIZE 8
|
||||
#else
|
||||
#define uECC_WORD_SIZE 4
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (uECC_WORD_SIZE != 1) && (uECC_WORD_SIZE != 4) && (uECC_WORD_SIZE != 8)
|
||||
#error "Unsupported value for uECC_WORD_SIZE"
|
||||
#endif
|
||||
|
||||
#if ((uECC_PLATFORM == uECC_avr) && (uECC_WORD_SIZE != 1))
|
||||
#pragma message("uECC_WORD_SIZE must be 1 for AVR")
|
||||
#undef uECC_WORD_SIZE
|
||||
#define uECC_WORD_SIZE 1
|
||||
#endif
|
||||
|
||||
#if ((uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \
|
||||
uECC_PLATFORM == uECC_arm_thumb2) && \
|
||||
(uECC_WORD_SIZE != 4))
|
||||
#pragma message("uECC_WORD_SIZE must be 4 for ARM")
|
||||
#undef uECC_WORD_SIZE
|
||||
#define uECC_WORD_SIZE 4
|
||||
#endif
|
||||
|
||||
typedef int8_t wordcount_t;
|
||||
typedef int16_t bitcount_t;
|
||||
typedef int8_t cmpresult_t;
|
||||
|
||||
#if (uECC_WORD_SIZE == 1)
|
||||
|
||||
typedef uint8_t uECC_word_t;
|
||||
typedef uint16_t uECC_dword_t;
|
||||
|
||||
#define HIGH_BIT_SET 0x80
|
||||
#define uECC_WORD_BITS 8
|
||||
#define uECC_WORD_BITS_SHIFT 3
|
||||
#define uECC_WORD_BITS_MASK 0x07
|
||||
|
||||
#elif (uECC_WORD_SIZE == 4)
|
||||
|
||||
typedef uint32_t uECC_word_t;
|
||||
typedef uint64_t uECC_dword_t;
|
||||
|
||||
#define HIGH_BIT_SET 0x80000000
|
||||
#define uECC_WORD_BITS 32
|
||||
#define uECC_WORD_BITS_SHIFT 5
|
||||
#define uECC_WORD_BITS_MASK 0x01F
|
||||
|
||||
#elif (uECC_WORD_SIZE == 8)
|
||||
|
||||
typedef uint64_t uECC_word_t;
|
||||
|
||||
#define HIGH_BIT_SET 0x8000000000000000U
|
||||
#define uECC_WORD_BITS 64
|
||||
#define uECC_WORD_BITS_SHIFT 6
|
||||
#define uECC_WORD_BITS_MASK 0x03F
|
||||
|
||||
#endif /* uECC_WORD_SIZE */
|
||||
|
||||
#endif /* _UECC_TYPES_H_ */
|
Loading…
Reference in New Issue
Block a user