still wip
This commit is contained in:
@@ -1,11 +1,9 @@
|
||||
#include "base64.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
static const char b64_enc_table[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
int base64_encode(const uint8_t *in, size_t ilen, char *out)
|
||||
void base64_encode(const uint8_t *in, size_t ilen, char *out)
|
||||
{
|
||||
size_t out_len = 0;
|
||||
for (size_t i = 0; i < ilen; i += 3) {
|
||||
@@ -21,5 +19,4 @@ int base64_encode(const uint8_t *in, size_t ilen, char *out)
|
||||
out[out_len++] = (remain > 1) ? b64_enc_table[(triple >> 6) & 0x3F] : '=';
|
||||
out[out_len++] = (remain > 2) ? b64_enc_table[triple & 0x3F] : '=';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#ifdef B64_HEADER
|
||||
#define B64_HEADER
|
||||
#ifndef BASE64_HEADER_FILE
|
||||
#define BASE64_HEADER_FILE
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int base64_encode(const uint8_t *in, size_t ilen, char *out);
|
||||
void base64_encode(const uint8_t *in, size_t ilen, char *out);
|
||||
|
||||
#endif
|
||||
@@ -42,35 +42,29 @@ static const uint8_t S[256] =
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86,
|
||||
0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e,
|
||||
0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42,
|
||||
0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
||||
};
|
||||
0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
|
||||
|
||||
static const uint8_t Rcon[11] =
|
||||
{
|
||||
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36
|
||||
};
|
||||
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
|
||||
|
||||
#ifdef INLINE_FUNCS
|
||||
static inline uint32_t word4(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3)
|
||||
{
|
||||
static inline uint32_t word4 (uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) {
|
||||
return b0 << 24 | b1 << 16 | b2 << 8 | b3;
|
||||
}
|
||||
|
||||
static inline uint8_t byte(uint32_t w, unsigned x)
|
||||
{
|
||||
static inline uint8_t byte (uint32_t w, unsigned x) {
|
||||
/* nb. bytes are numbered 0 (leftmost, top)
|
||||
* to 3 (rightmost). */
|
||||
x = 3 - x;
|
||||
return (w >> (x * 8)) & 0xff;
|
||||
}
|
||||
|
||||
static uint32_t round_constant(uint32_t i)
|
||||
{
|
||||
static uint32_t round_constant (uint32_t i) {
|
||||
return Rcon[i] << 24;
|
||||
}
|
||||
|
||||
static uint32_t rot_word(uint32_t w)
|
||||
{
|
||||
static uint32_t rot_word (uint32_t w) {
|
||||
/* Takes
|
||||
* word [a0,a1,a2,a3]
|
||||
* returns
|
||||
@@ -86,8 +80,7 @@ static uint32_t rot_word(uint32_t w)
|
||||
#define round_constant(i) ((uint32_t)(Rcon[i]) << 24)
|
||||
#define rot_word(w) rotl32 ((w), 8)
|
||||
|
||||
static uint32_t sub_word(uint32_t w, const uint8_t *sbox)
|
||||
{
|
||||
static uint32_t sub_word (uint32_t w, const uint8_t *sbox) {
|
||||
uint8_t a = byte (w, 0),
|
||||
b = byte (w, 1),
|
||||
c = byte (w, 2),
|
||||
@@ -103,8 +96,7 @@ static uint32_t sub_word(uint32_t w, const uint8_t *sbox)
|
||||
return word4 (a, b, c, d);
|
||||
}
|
||||
|
||||
static void aes_schedule(cf_aes_context *ctx, const uint8_t *key, size_t nkey)
|
||||
{
|
||||
static void aes_schedule (cf_aes_context *ctx, const uint8_t *key, size_t nkey) {
|
||||
size_t i,
|
||||
nb = AES_BLOCKSZ / 4,
|
||||
nk = nkey / 4,
|
||||
@@ -112,20 +104,17 @@ static void aes_schedule(cf_aes_context *ctx, const uint8_t *key, size_t nkey)
|
||||
uint32_t *w = ctx->ks;
|
||||
|
||||
/* First words are just the key. */
|
||||
for (i = 0; i < nk; i++)
|
||||
{
|
||||
for (i = 0; i < nk; i++) {
|
||||
w[i] = read32_be (key + i * 4);
|
||||
}
|
||||
|
||||
uint32_t i_div_nk = 1;
|
||||
uint32_t i_mod_nk = 0;
|
||||
|
||||
for (; i < n; i++, i_mod_nk++)
|
||||
{
|
||||
for (; i < n; i++, i_mod_nk++) {
|
||||
uint32_t temp = w[i - 1];
|
||||
|
||||
if (i_mod_nk == nk)
|
||||
{
|
||||
if (i_mod_nk == nk) {
|
||||
i_div_nk++;
|
||||
i_mod_nk = 0;
|
||||
}
|
||||
@@ -139,12 +128,10 @@ static void aes_schedule(cf_aes_context *ctx, const uint8_t *key, size_t nkey)
|
||||
}
|
||||
}
|
||||
|
||||
void cf_aes_init(cf_aes_context *ctx, const uint8_t *key, size_t nkey)
|
||||
{
|
||||
void cf_aes_init (cf_aes_context *ctx, const uint8_t *key, size_t nkey) {
|
||||
memset (ctx, 0, sizeof *ctx);
|
||||
|
||||
switch (nkey)
|
||||
{
|
||||
switch (nkey) {
|
||||
#if CF_AES_MAXROUNDS >= AES128_ROUNDS
|
||||
case 16:
|
||||
ctx->rounds = AES128_ROUNDS;
|
||||
@@ -171,24 +158,21 @@ void cf_aes_init(cf_aes_context *ctx, const uint8_t *key, size_t nkey)
|
||||
}
|
||||
}
|
||||
|
||||
static void add_round_key(uint32_t state[4], const uint32_t rk[4])
|
||||
{
|
||||
static void add_round_key (uint32_t state[4], const uint32_t rk[4]) {
|
||||
state[0] ^= rk[0];
|
||||
state[1] ^= rk[1];
|
||||
state[2] ^= rk[2];
|
||||
state[3] ^= rk[3];
|
||||
}
|
||||
|
||||
static void sub_block(uint32_t state[4])
|
||||
{
|
||||
static void sub_block (uint32_t state[4]) {
|
||||
state[0] = sub_word (state[0], S);
|
||||
state[1] = sub_word (state[1], S);
|
||||
state[2] = sub_word (state[2], S);
|
||||
state[3] = sub_word (state[3], S);
|
||||
}
|
||||
|
||||
static void shift_rows(uint32_t state[4])
|
||||
{
|
||||
static void shift_rows (uint32_t state[4]) {
|
||||
uint32_t u, v, x, y;
|
||||
|
||||
u = word4 (byte (state[0], 0),
|
||||
@@ -217,21 +201,17 @@ static void shift_rows(uint32_t state[4])
|
||||
state[3] = y;
|
||||
}
|
||||
|
||||
static uint32_t gf_poly_mul2(uint32_t x)
|
||||
{
|
||||
return
|
||||
((x & 0x7f7f7f7f) << 1) ^
|
||||
static uint32_t gf_poly_mul2 (uint32_t x) {
|
||||
return ((x & 0x7f7f7f7f) << 1) ^
|
||||
(((x & 0x80808080) >> 7) * 0x1b);
|
||||
}
|
||||
|
||||
static uint32_t mix_column(uint32_t x)
|
||||
{
|
||||
static uint32_t mix_column (uint32_t x) {
|
||||
uint32_t x2 = gf_poly_mul2 (x);
|
||||
return x2 ^ rotr32 (x ^ x2, 24) ^ rotr32 (x, 16) ^ rotr32 (x, 8);
|
||||
}
|
||||
|
||||
static void mix_columns(uint32_t state[4])
|
||||
{
|
||||
static void mix_columns (uint32_t state[4]) {
|
||||
state[0] = mix_column (state[0]);
|
||||
state[1] = mix_column (state[1]);
|
||||
state[2] = mix_column (state[2]);
|
||||
@@ -240,8 +220,7 @@ static void mix_columns(uint32_t state[4])
|
||||
|
||||
void cf_aes_encrypt (const cf_aes_context *ctx,
|
||||
const uint8_t in[AES_BLOCKSZ],
|
||||
uint8_t out[AES_BLOCKSZ])
|
||||
{
|
||||
uint8_t out[AES_BLOCKSZ]) {
|
||||
assert (ctx->rounds == AES128_ROUNDS ||
|
||||
ctx->rounds == AES192_ROUNDS ||
|
||||
ctx->rounds == AES256_ROUNDS);
|
||||
@@ -250,15 +229,13 @@ void cf_aes_encrypt(const cf_aes_context *ctx,
|
||||
read32_be (in + 0),
|
||||
read32_be (in + 4),
|
||||
read32_be (in + 8),
|
||||
read32_be(in + 12)
|
||||
};
|
||||
read32_be (in + 12)};
|
||||
|
||||
const uint32_t *round_keys = ctx->ks;
|
||||
add_round_key (state, round_keys);
|
||||
round_keys += 4;
|
||||
|
||||
for (uint32_t round = 1; round < ctx->rounds; round++)
|
||||
{
|
||||
for (uint32_t round = 1; round < ctx->rounds; round++) {
|
||||
sub_block (state);
|
||||
shift_rows (state);
|
||||
mix_columns (state);
|
||||
@@ -298,19 +275,16 @@ static const uint8_t S_inv[256] =
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93,
|
||||
0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb,
|
||||
0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6,
|
||||
0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
||||
};
|
||||
0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d};
|
||||
|
||||
static void inv_sub_block(uint32_t state[4])
|
||||
{
|
||||
static void inv_sub_block (uint32_t state[4]) {
|
||||
state[0] = sub_word (state[0], S_inv);
|
||||
state[1] = sub_word (state[1], S_inv);
|
||||
state[2] = sub_word (state[2], S_inv);
|
||||
state[3] = sub_word (state[3], S_inv);
|
||||
}
|
||||
|
||||
static void inv_shift_rows(uint32_t state[4])
|
||||
{
|
||||
static void inv_shift_rows (uint32_t state[4]) {
|
||||
uint32_t u, v, x, y;
|
||||
|
||||
u = word4 (byte (state[0], 0),
|
||||
@@ -339,8 +313,7 @@ static void inv_shift_rows(uint32_t state[4])
|
||||
state[3] = y;
|
||||
}
|
||||
|
||||
static uint32_t inv_mix_column(uint32_t x)
|
||||
{
|
||||
static uint32_t inv_mix_column (uint32_t x) {
|
||||
uint32_t x2 = gf_poly_mul2 (x),
|
||||
x4 = gf_poly_mul2 (x2),
|
||||
x9 = x ^ gf_poly_mul2 (x4),
|
||||
@@ -350,8 +323,7 @@ static uint32_t inv_mix_column(uint32_t x)
|
||||
return x ^ x2 ^ x13 ^ rotr32 (x11, 24) ^ rotr32 (x13, 16) ^ rotr32 (x9, 8);
|
||||
}
|
||||
|
||||
static void inv_mix_columns(uint32_t state[4])
|
||||
{
|
||||
static void inv_mix_columns (uint32_t state[4]) {
|
||||
state[0] = inv_mix_column (state[0]);
|
||||
state[1] = inv_mix_column (state[1]);
|
||||
state[2] = inv_mix_column (state[2]);
|
||||
@@ -360,8 +332,7 @@ static void inv_mix_columns(uint32_t state[4])
|
||||
|
||||
void cf_aes_decrypt (const cf_aes_context *ctx,
|
||||
const uint8_t in[AES_BLOCKSZ],
|
||||
uint8_t out[AES_BLOCKSZ])
|
||||
{
|
||||
uint8_t out[AES_BLOCKSZ]) {
|
||||
assert (ctx->rounds == AES128_ROUNDS ||
|
||||
ctx->rounds == AES192_ROUNDS ||
|
||||
ctx->rounds == AES256_ROUNDS);
|
||||
@@ -370,15 +341,13 @@ void cf_aes_decrypt(const cf_aes_context *ctx,
|
||||
read32_be (in + 0),
|
||||
read32_be (in + 4),
|
||||
read32_be (in + 8),
|
||||
read32_be(in + 12)
|
||||
};
|
||||
read32_be (in + 12)};
|
||||
|
||||
const uint32_t *round_keys = &ctx->ks[ctx->rounds << 2];
|
||||
add_round_key (state, round_keys);
|
||||
round_keys -= 4;
|
||||
|
||||
for (uint32_t round = ctx->rounds - 1; round != 0; round--)
|
||||
{
|
||||
for (uint32_t round = ctx->rounds - 1; round != 0; round--) {
|
||||
inv_shift_rows (state);
|
||||
inv_sub_block (state);
|
||||
add_round_key (state, round_keys);
|
||||
@@ -398,20 +367,49 @@ void cf_aes_decrypt(const cf_aes_context *ctx,
|
||||
#else
|
||||
void cf_aes_decrypt (const cf_aes_context *ctx,
|
||||
const uint8_t in[AES_BLOCKSZ],
|
||||
uint8_t out[AES_BLOCKSZ])
|
||||
{
|
||||
uint8_t out[AES_BLOCKSZ]) {
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
void cf_aes_finish(cf_aes_context *ctx)
|
||||
{
|
||||
void cf_aes_finish (cf_aes_context *ctx) {
|
||||
mem_clean (ctx, sizeof *ctx);
|
||||
}
|
||||
|
||||
const cf_prp cf_aes = {
|
||||
.blocksz = AES_BLOCKSZ,
|
||||
.encrypt = (cf_prp_block)cf_aes_encrypt,
|
||||
.decrypt = (cf_prp_block) cf_aes_decrypt
|
||||
};
|
||||
.decrypt = (cf_prp_block)cf_aes_decrypt};
|
||||
|
||||
int aes_encrypt_ecb (const uint8_t *key, const uint8_t keyLen, const uint8_t *input, size_t ilen,
|
||||
uint8_t *output) {
|
||||
if (ilen % 16 != 0)
|
||||
return -1;
|
||||
|
||||
cf_aes_context ctx;
|
||||
cf_aes_init (&ctx, key, keyLen);
|
||||
|
||||
for (size_t i = 0; i < ilen; i += 16) {
|
||||
cf_aes_encrypt (&ctx, input + i, output + i);
|
||||
}
|
||||
|
||||
cf_aes_finish (&ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aes_decrypt_ecb (const uint8_t *key, const uint8_t keyLen, const uint8_t *input, size_t ilen,
|
||||
uint8_t *output) {
|
||||
if (ilen % 16 != 0)
|
||||
return -1;
|
||||
|
||||
cf_aes_context ctx;
|
||||
cf_aes_init (&ctx, key, keyLen);
|
||||
|
||||
for (size_t i = 0; i < ilen; i += 16) {
|
||||
cf_aes_decrypt (&ctx, input + i, output + i);
|
||||
}
|
||||
|
||||
|
||||
cf_aes_finish (&ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -149,4 +149,10 @@ extern void cf_aes_finish(cf_aes_context *ctx);
|
||||
* more information. */
|
||||
extern const cf_prp cf_aes;
|
||||
|
||||
int aes_decrypt_ecb (const uint8_t *key, const uint8_t keyLen, const uint8_t *input, size_t ilen,
|
||||
uint8_t *output);
|
||||
|
||||
int aes_encrypt_ecb (const uint8_t *key, const uint8_t keyLen, const uint8_t *input, size_t ilen,
|
||||
uint8_t *output);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "bitops.h"
|
||||
#include "handy.h"
|
||||
#include "tassert.h"
|
||||
#include "sha2.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -104,3 +105,13 @@ void cf_hmac(const uint8_t *key, size_t nkey,
|
||||
cf_hmac_finish(&ctx, out);
|
||||
}
|
||||
|
||||
// HMAC-SHA256
|
||||
int hmac_sha256 (const uint8_t *key, size_t keylen,
|
||||
const uint8_t *input, size_t ilen,
|
||||
uint8_t *output) {
|
||||
cf_hmac_ctx ctx;
|
||||
cf_hmac_init (&ctx, &cf_sha256, key, keylen);
|
||||
cf_hmac_update (&ctx, input, ilen);
|
||||
cf_hmac_finish (&ctx, output);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -75,4 +75,8 @@ void cf_hmac(const uint8_t *key, size_t nkey,
|
||||
uint8_t *out,
|
||||
const cf_chash *hash);
|
||||
|
||||
int hmac_sha256 (const uint8_t *key, size_t keylen,
|
||||
const uint8_t *input, size_t ilen,
|
||||
uint8_t *output);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,62 @@
|
||||
#include "config.h"
|
||||
#include "ch32v30x_flash.h"
|
||||
#include "util/hexdump.h"
|
||||
#include "util/log.h"
|
||||
|
||||
PersistentData_t persistent;
|
||||
#define TAG "Config"
|
||||
|
||||
NodeEntry * getNextNode() {
|
||||
uint32_t oldest_timestamp = UINT32_MAX;
|
||||
NodeEntry *selectedNode = &(persistent.contacts[0]);
|
||||
for (int i = 0; i < CONTACT_COUNT; i++) {
|
||||
NodeEntry *curNode = &(persistent.contacts[i]);
|
||||
if (curNode->last_seen_lt == 0) {
|
||||
break;
|
||||
}
|
||||
if (curNode->last_seen_lt < oldest_timestamp) {
|
||||
oldest_timestamp = curNode->last_seen_lt;
|
||||
selectedNode = curNode;
|
||||
}
|
||||
}
|
||||
return selectedNode;
|
||||
}
|
||||
|
||||
NodeEntry * getNode(uint8_t hash) {
|
||||
NodeEntry *selectedNode = NULL;
|
||||
for (int i = 0; i < CONTACT_COUNT; i++) {
|
||||
NodeEntry *curNode = &(persistent.contacts[i]);
|
||||
if (curNode->pubKey[0] == hash) {
|
||||
selectedNode = curNode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return selectedNode;
|
||||
}
|
||||
|
||||
void printNodeDB() {
|
||||
printf("Node database:\n");
|
||||
for (int i = 0; i < CONTACT_COUNT; i++) {
|
||||
const NodeEntry *node = &(persistent.contacts[i]);
|
||||
if (node->last_seen_lt == 0) continue; // skip inactive nodes
|
||||
|
||||
printf("Node %d:\n", i);
|
||||
printf(" Name: %s\n", node->name);
|
||||
hexdump("Pubkey", node->pubKey, sizeof(node->pubKey));
|
||||
hexdump("Secret", node->secret, sizeof(node->secret));
|
||||
printf("\n");
|
||||
|
||||
printf(" GPS: lat=%d, lon=%d\n", node->gps_latitude, node->gps_longitude);
|
||||
printf(" Path: ... (not expanded, add if needed)\n");
|
||||
printf(" Flags: 0x%02X\n", node->flags);
|
||||
printf(" Type: 0x%02X\n", node->type);
|
||||
printf(" Authenticated: %s\n", node->authenticated ? "Yes" : "No");
|
||||
printf(" Last Seen (remote ts): %d\n", node->last_seen_rt);
|
||||
printf(" Last Seen (local ts): %d\n", node->last_seen_lt);
|
||||
printf(" Sync timestamp: %d\n", node->sync_timestamp);
|
||||
printf("--------------------------------------\n");
|
||||
}
|
||||
}
|
||||
|
||||
void loadConfig() {
|
||||
memcpy (&persistent, FLASH_USER_PAGE_ADDR, sizeof (persistent));
|
||||
|
||||
@@ -2,16 +2,43 @@
|
||||
#define CONFIG_HEADER
|
||||
#include "stdint.h"
|
||||
#include "string.h"
|
||||
#include "meshcore/packetstructs.h"
|
||||
|
||||
#define FLASH_USER_PAGE_ADDR ((const void *)(0x08077F00))
|
||||
|
||||
#define AESKeyCount 8
|
||||
#define CONTACT_COUNT 100
|
||||
|
||||
typedef struct {
|
||||
char name[32];
|
||||
unsigned char pubKey[32];
|
||||
unsigned char secret[32];
|
||||
|
||||
int32_t gps_latitude;
|
||||
int32_t gps_longitude;
|
||||
|
||||
Path path;
|
||||
|
||||
uint8_t flags;
|
||||
uint8_t type;
|
||||
|
||||
uint8_t authenticated;
|
||||
|
||||
uint32_t last_seen_rt; //remote timestamp
|
||||
uint32_t last_seen_lt; //local timestamp
|
||||
|
||||
uint32_t sync_timestamp;
|
||||
} NodeEntry;
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic; // e.g. 0xDEADBEEF
|
||||
uint8_t privkey[32]; // Ed25519 private
|
||||
uint8_t pubkey[32]; // Ed25519 public
|
||||
uint8_t config[128]; // user config
|
||||
char nodeName[20];
|
||||
uint8_t extra[40];
|
||||
uint8_t nodeType;
|
||||
uint8_t aesKeys[AESKeyCount][17];
|
||||
uint8_t password[16];
|
||||
char nodeName[32];
|
||||
NodeEntry contacts[CONTACT_COUNT];
|
||||
uint32_t crc32; // integrity check
|
||||
} PersistentData_t;
|
||||
|
||||
@@ -19,4 +46,10 @@ extern PersistentData_t persistent;
|
||||
|
||||
void saveConfig();
|
||||
void loadConfig();
|
||||
|
||||
void printNodeDB();
|
||||
|
||||
NodeEntry * getNextNode();
|
||||
|
||||
NodeEntry * getNode(uint8_t hash);
|
||||
#endif
|
||||
69
User/lib/ed25519/add_scalar.c
Normal file
69
User/lib/ed25519/add_scalar.c
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "ed_25519.h"
|
||||
#include "ge.h"
|
||||
#include "sc.h"
|
||||
#include "sha512.h"
|
||||
|
||||
|
||||
/* see http://crypto.stackexchange.com/a/6215/4697 */
|
||||
void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar) {
|
||||
const unsigned char SC_1[32] = {1}; /* scalar with value 1 */
|
||||
|
||||
unsigned char n[32];
|
||||
ge_p3 nB;
|
||||
ge_p1p1 A_p1p1;
|
||||
ge_p3 A;
|
||||
ge_p3 public_key_unpacked;
|
||||
ge_cached T;
|
||||
|
||||
sha512_context hash;
|
||||
unsigned char hashbuf[64];
|
||||
|
||||
int i;
|
||||
|
||||
/* copy the scalar and clear highest bit */
|
||||
for (i = 0; i < 31; ++i) {
|
||||
n[i] = scalar[i];
|
||||
}
|
||||
n[31] = scalar[31] & 127;
|
||||
|
||||
/* private key: a = n + t */
|
||||
if (private_key) {
|
||||
sc_muladd(private_key, SC_1, n, private_key);
|
||||
|
||||
// https://github.com/orlp/ed25519/issues/3
|
||||
sha512_init(&hash);
|
||||
sha512_update(&hash, private_key + 32, 32);
|
||||
sha512_update(&hash, scalar, 32);
|
||||
sha512_final(&hash, hashbuf);
|
||||
for (i = 0; i < 32; ++i) {
|
||||
private_key[32 + i] = hashbuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* public key: A = nB + T */
|
||||
if (public_key) {
|
||||
/* if we know the private key we don't need a point addition, which is faster */
|
||||
/* using a "timing attack" you could find out wether or not we know the private
|
||||
key, but this information seems rather useless - if this is important pass
|
||||
public_key and private_key seperately in 2 function calls */
|
||||
if (private_key) {
|
||||
ge_scalarmult_base(&A, private_key);
|
||||
} else {
|
||||
/* unpack public key into T */
|
||||
ge_frombytes_negate_vartime(&public_key_unpacked, public_key);
|
||||
fe_neg(public_key_unpacked.X, public_key_unpacked.X); /* undo negate */
|
||||
fe_neg(public_key_unpacked.T, public_key_unpacked.T); /* undo negate */
|
||||
ge_p3_to_cached(&T, &public_key_unpacked);
|
||||
|
||||
/* calculate n*B */
|
||||
ge_scalarmult_base(&nB, n);
|
||||
|
||||
/* A = n*B + T */
|
||||
ge_add(&A_p1p1, &nB, &T);
|
||||
ge_p1p1_to_p3(&A, &A_p1p1);
|
||||
}
|
||||
|
||||
/* pack public key */
|
||||
ge_p3_tobytes(public_key, &A);
|
||||
}
|
||||
}
|
||||
41
User/lib/ed25519/ed_25519.h
Normal file
41
User/lib/ed25519/ed_25519.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef ED25519_H
|
||||
#define ED25519_H
|
||||
|
||||
// Nightcracker's Ed25519 - https://github.com/orlp/ed25519
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(ED25519_BUILD_DLL)
|
||||
#define ED25519_DECLSPEC __declspec(dllexport)
|
||||
#elif defined(ED25519_DLL)
|
||||
#define ED25519_DECLSPEC __declspec(dllimport)
|
||||
#else
|
||||
#define ED25519_DECLSPEC
|
||||
#endif
|
||||
#else
|
||||
#define ED25519_DECLSPEC
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef ED25519_NO_SEED
|
||||
int ED25519_DECLSPEC ed25519_create_seed(unsigned char *seed);
|
||||
#endif
|
||||
|
||||
void ED25519_DECLSPEC ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed);
|
||||
void ED25519_DECLSPEC ed25519_derive_pub(unsigned char *public_key, const unsigned char *private_key);
|
||||
void ED25519_DECLSPEC ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key);
|
||||
int ED25519_DECLSPEC ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key);
|
||||
void ED25519_DECLSPEC ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar);
|
||||
void ED25519_DECLSPEC ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1491
User/lib/ed25519/fe.c
Normal file
1491
User/lib/ed25519/fe.c
Normal file
File diff suppressed because it is too large
Load Diff
41
User/lib/ed25519/fe.h
Normal file
41
User/lib/ed25519/fe.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef FE_H
|
||||
#define FE_H
|
||||
|
||||
#include "fixedint.h"
|
||||
|
||||
|
||||
/*
|
||||
fe means field element.
|
||||
Here the field is \Z/(2^255-19).
|
||||
An element t, entries t[0]...t[9], represents the integer
|
||||
t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
|
||||
Bounds on each t[i] vary depending on context.
|
||||
*/
|
||||
|
||||
|
||||
typedef int32_t fe[10];
|
||||
|
||||
|
||||
void fe_0(fe h);
|
||||
void fe_1(fe h);
|
||||
|
||||
void fe_frombytes(fe h, const unsigned char *s);
|
||||
void fe_tobytes(unsigned char *s, const fe h);
|
||||
|
||||
void fe_copy(fe h, const fe f);
|
||||
int fe_isnegative(const fe f);
|
||||
int fe_isnonzero(const fe f);
|
||||
void fe_cmov(fe f, const fe g, unsigned int b);
|
||||
void fe_cswap(fe f, fe g, unsigned int b);
|
||||
|
||||
void fe_neg(fe h, const fe f);
|
||||
void fe_add(fe h, const fe f, const fe g);
|
||||
void fe_invert(fe out, const fe z);
|
||||
void fe_sq(fe h, const fe f);
|
||||
void fe_sq2(fe h, const fe f);
|
||||
void fe_mul(fe h, const fe f, const fe g);
|
||||
void fe_mul121666(fe h, fe f);
|
||||
void fe_pow22523(fe out, const fe z);
|
||||
void fe_sub(fe h, const fe f, const fe g);
|
||||
|
||||
#endif
|
||||
72
User/lib/ed25519/fixedint.h
Normal file
72
User/lib/ed25519/fixedint.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
Portable header to provide the 32 and 64 bits type.
|
||||
|
||||
Not a compatible replacement for <stdint.h>, do not blindly use it as such.
|
||||
*/
|
||||
|
||||
#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED)
|
||||
#include <stdint.h>
|
||||
#define FIXEDINT_H_INCLUDED
|
||||
|
||||
#if defined(__WATCOMC__) && __WATCOMC__ >= 1250 && !defined(UINT64_C)
|
||||
#include <limits.h>
|
||||
#define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef FIXEDINT_H_INCLUDED
|
||||
#define FIXEDINT_H_INCLUDED
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/* (u)int32_t */
|
||||
#ifndef uint32_t
|
||||
#if (ULONG_MAX == 0xffffffffUL)
|
||||
typedef unsigned long uint32_t;
|
||||
#elif (UINT_MAX == 0xffffffffUL)
|
||||
typedef unsigned int uint32_t;
|
||||
#elif (USHRT_MAX == 0xffffffffUL)
|
||||
typedef unsigned short uint32_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef int32_t
|
||||
#if (LONG_MAX == 0x7fffffffL)
|
||||
typedef signed long int32_t;
|
||||
#elif (INT_MAX == 0x7fffffffL)
|
||||
typedef signed int int32_t;
|
||||
#elif (SHRT_MAX == 0x7fffffffL)
|
||||
typedef signed short int32_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* (u)int64_t */
|
||||
#if (defined(__STDC__) && defined(__STDC_VERSION__) && __STDC__ && __STDC_VERSION__ >= 199901L)
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
#define UINT64_C(v) v ##ULL
|
||||
#define INT64_C(v) v ##LL
|
||||
#elif defined(__GNUC__)
|
||||
__extension__ typedef long long int64_t;
|
||||
__extension__ typedef unsigned long long uint64_t;
|
||||
|
||||
#define UINT64_C(v) v ##ULL
|
||||
#define INT64_C(v) v ##LL
|
||||
#elif defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__APPLE_CC__) || defined(_LONG_LONG) || defined(_CRAYC)
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
#define UINT64_C(v) v ##ULL
|
||||
#define INT64_C(v) v ##LL
|
||||
#elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined(__BORLANDC__) && __BORLANDC__ > 0x460) || defined(__alpha) || defined(__DECC)
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
#define UINT64_C(v) v ##UI64
|
||||
#define INT64_C(v) v ##I64
|
||||
#endif
|
||||
#endif
|
||||
467
User/lib/ed25519/ge.c
Normal file
467
User/lib/ed25519/ge.c
Normal file
@@ -0,0 +1,467 @@
|
||||
#include "ge.h"
|
||||
#include "precomp_data.h"
|
||||
|
||||
|
||||
/*
|
||||
r = p + q
|
||||
*/
|
||||
|
||||
void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
|
||||
fe t0;
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
fe_mul(r->Z, r->X, q->YplusX);
|
||||
fe_mul(r->Y, r->Y, q->YminusX);
|
||||
fe_mul(r->T, q->T2d, p->T);
|
||||
fe_mul(r->X, p->Z, q->Z);
|
||||
fe_add(t0, r->X, r->X);
|
||||
fe_sub(r->X, r->Z, r->Y);
|
||||
fe_add(r->Y, r->Z, r->Y);
|
||||
fe_add(r->Z, t0, r->T);
|
||||
fe_sub(r->T, t0, r->T);
|
||||
}
|
||||
|
||||
|
||||
static void slide(signed char *r, const unsigned char *a) {
|
||||
int i;
|
||||
int b;
|
||||
int k;
|
||||
|
||||
for (i = 0; i < 256; ++i) {
|
||||
r[i] = 1 & (a[i >> 3] >> (i & 7));
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; ++i)
|
||||
if (r[i]) {
|
||||
for (b = 1; b <= 6 && i + b < 256; ++b) {
|
||||
if (r[i + b]) {
|
||||
if (r[i] + (r[i + b] << b) <= 15) {
|
||||
r[i] += r[i + b] << b;
|
||||
r[i + b] = 0;
|
||||
} else if (r[i] - (r[i + b] << b) >= -15) {
|
||||
r[i] -= r[i + b] << b;
|
||||
|
||||
for (k = i + b; k < 256; ++k) {
|
||||
if (!r[k]) {
|
||||
r[k] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
r[k] = 0;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
r = a * A + b * B
|
||||
where a = a[0]+256*a[1]+...+256^31 a[31].
|
||||
and b = b[0]+256*b[1]+...+256^31 b[31].
|
||||
B is the Ed25519 base point (x,4/5) with x positive.
|
||||
*/
|
||||
|
||||
void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b) {
|
||||
signed char aslide[256];
|
||||
signed char bslide[256];
|
||||
ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
|
||||
ge_p1p1 t;
|
||||
ge_p3 u;
|
||||
ge_p3 A2;
|
||||
int i;
|
||||
slide(aslide, a);
|
||||
slide(bslide, b);
|
||||
ge_p3_to_cached(&Ai[0], A);
|
||||
ge_p3_dbl(&t, A);
|
||||
ge_p1p1_to_p3(&A2, &t);
|
||||
ge_add(&t, &A2, &Ai[0]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[1], &u);
|
||||
ge_add(&t, &A2, &Ai[1]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[2], &u);
|
||||
ge_add(&t, &A2, &Ai[2]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[3], &u);
|
||||
ge_add(&t, &A2, &Ai[3]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[4], &u);
|
||||
ge_add(&t, &A2, &Ai[4]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[5], &u);
|
||||
ge_add(&t, &A2, &Ai[5]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[6], &u);
|
||||
ge_add(&t, &A2, &Ai[6]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[7], &u);
|
||||
ge_p2_0(r);
|
||||
|
||||
for (i = 255; i >= 0; --i) {
|
||||
if (aslide[i] || bslide[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (; i >= 0; --i) {
|
||||
ge_p2_dbl(&t, r);
|
||||
|
||||
if (aslide[i] > 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_add(&t, &u, &Ai[aslide[i] / 2]);
|
||||
} else if (aslide[i] < 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
|
||||
}
|
||||
|
||||
if (bslide[i] > 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_madd(&t, &u, &Bi[bslide[i] / 2]);
|
||||
} else if (bslide[i] < 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_msub(&t, &u, &Bi[(-bslide[i]) / 2]);
|
||||
}
|
||||
|
||||
ge_p1p1_to_p2(r, &t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const fe d = {
|
||||
-10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116
|
||||
};
|
||||
|
||||
static const fe sqrtm1 = {
|
||||
-32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482
|
||||
};
|
||||
|
||||
int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s) {
|
||||
fe u;
|
||||
fe v;
|
||||
fe v3;
|
||||
fe vxx;
|
||||
fe check;
|
||||
fe_frombytes(h->Y, s);
|
||||
fe_1(h->Z);
|
||||
fe_sq(u, h->Y);
|
||||
fe_mul(v, u, d);
|
||||
fe_sub(u, u, h->Z); /* u = y^2-1 */
|
||||
fe_add(v, v, h->Z); /* v = dy^2+1 */
|
||||
fe_sq(v3, v);
|
||||
fe_mul(v3, v3, v); /* v3 = v^3 */
|
||||
fe_sq(h->X, v3);
|
||||
fe_mul(h->X, h->X, v);
|
||||
fe_mul(h->X, h->X, u); /* x = uv^7 */
|
||||
fe_pow22523(h->X, h->X); /* x = (uv^7)^((q-5)/8) */
|
||||
fe_mul(h->X, h->X, v3);
|
||||
fe_mul(h->X, h->X, u); /* x = uv^3(uv^7)^((q-5)/8) */
|
||||
fe_sq(vxx, h->X);
|
||||
fe_mul(vxx, vxx, v);
|
||||
fe_sub(check, vxx, u); /* vx^2-u */
|
||||
|
||||
if (fe_isnonzero(check)) {
|
||||
fe_add(check, vxx, u); /* vx^2+u */
|
||||
|
||||
if (fe_isnonzero(check)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fe_mul(h->X, h->X, sqrtm1);
|
||||
}
|
||||
|
||||
if (fe_isnegative(h->X) == (s[31] >> 7)) {
|
||||
fe_neg(h->X, h->X);
|
||||
}
|
||||
|
||||
fe_mul(h->T, h->X, h->Y);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p + q
|
||||
*/
|
||||
|
||||
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
|
||||
fe t0;
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
fe_mul(r->Z, r->X, q->yplusx);
|
||||
fe_mul(r->Y, r->Y, q->yminusx);
|
||||
fe_mul(r->T, q->xy2d, p->T);
|
||||
fe_add(t0, p->Z, p->Z);
|
||||
fe_sub(r->X, r->Z, r->Y);
|
||||
fe_add(r->Y, r->Z, r->Y);
|
||||
fe_add(r->Z, t0, r->T);
|
||||
fe_sub(r->T, t0, r->T);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p - q
|
||||
*/
|
||||
|
||||
void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
|
||||
fe t0;
|
||||
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
fe_mul(r->Z, r->X, q->yminusx);
|
||||
fe_mul(r->Y, r->Y, q->yplusx);
|
||||
fe_mul(r->T, q->xy2d, p->T);
|
||||
fe_add(t0, p->Z, p->Z);
|
||||
fe_sub(r->X, r->Z, r->Y);
|
||||
fe_add(r->Y, r->Z, r->Y);
|
||||
fe_sub(r->Z, t0, r->T);
|
||||
fe_add(r->T, t0, r->T);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p
|
||||
*/
|
||||
|
||||
void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) {
|
||||
fe_mul(r->X, p->X, p->T);
|
||||
fe_mul(r->Y, p->Y, p->Z);
|
||||
fe_mul(r->Z, p->Z, p->T);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
r = p
|
||||
*/
|
||||
|
||||
void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) {
|
||||
fe_mul(r->X, p->X, p->T);
|
||||
fe_mul(r->Y, p->Y, p->Z);
|
||||
fe_mul(r->Z, p->Z, p->T);
|
||||
fe_mul(r->T, p->X, p->Y);
|
||||
}
|
||||
|
||||
|
||||
void ge_p2_0(ge_p2 *h) {
|
||||
fe_0(h->X);
|
||||
fe_1(h->Y);
|
||||
fe_1(h->Z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
r = 2 * p
|
||||
*/
|
||||
|
||||
void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) {
|
||||
fe t0;
|
||||
|
||||
fe_sq(r->X, p->X);
|
||||
fe_sq(r->Z, p->Y);
|
||||
fe_sq2(r->T, p->Z);
|
||||
fe_add(r->Y, p->X, p->Y);
|
||||
fe_sq(t0, r->Y);
|
||||
fe_add(r->Y, r->Z, r->X);
|
||||
fe_sub(r->Z, r->Z, r->X);
|
||||
fe_sub(r->X, t0, r->Y);
|
||||
fe_sub(r->T, r->T, r->Z);
|
||||
}
|
||||
|
||||
|
||||
void ge_p3_0(ge_p3 *h) {
|
||||
fe_0(h->X);
|
||||
fe_1(h->Y);
|
||||
fe_1(h->Z);
|
||||
fe_0(h->T);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = 2 * p
|
||||
*/
|
||||
|
||||
void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) {
|
||||
ge_p2 q;
|
||||
ge_p3_to_p2(&q, p);
|
||||
ge_p2_dbl(r, &q);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
r = p
|
||||
*/
|
||||
|
||||
static const fe d2 = {
|
||||
-21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199
|
||||
};
|
||||
|
||||
void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) {
|
||||
fe_add(r->YplusX, p->Y, p->X);
|
||||
fe_sub(r->YminusX, p->Y, p->X);
|
||||
fe_copy(r->Z, p->Z);
|
||||
fe_mul(r->T2d, p->T, d2);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p
|
||||
*/
|
||||
|
||||
void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) {
|
||||
fe_copy(r->X, p->X);
|
||||
fe_copy(r->Y, p->Y);
|
||||
fe_copy(r->Z, p->Z);
|
||||
}
|
||||
|
||||
|
||||
void ge_p3_tobytes(unsigned char *s, const ge_p3 *h) {
|
||||
fe recip;
|
||||
fe x;
|
||||
fe y;
|
||||
fe_invert(recip, h->Z);
|
||||
fe_mul(x, h->X, recip);
|
||||
fe_mul(y, h->Y, recip);
|
||||
fe_tobytes(s, y);
|
||||
s[31] ^= fe_isnegative(x) << 7;
|
||||
}
|
||||
|
||||
|
||||
static unsigned char equal(signed char b, signed char c) {
|
||||
unsigned char ub = b;
|
||||
unsigned char uc = c;
|
||||
unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
|
||||
uint64_t y = x; /* 0: yes; 1..255: no */
|
||||
y -= 1; /* large: yes; 0..254: no */
|
||||
y >>= 63; /* 1: yes; 0: no */
|
||||
return (unsigned char) y;
|
||||
}
|
||||
|
||||
static unsigned char negative(signed char b) {
|
||||
uint64_t x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
|
||||
x >>= 63; /* 1: yes; 0: no */
|
||||
return (unsigned char) x;
|
||||
}
|
||||
|
||||
static void cmov(ge_precomp *t, const ge_precomp *u, unsigned char b) {
|
||||
fe_cmov(t->yplusx, u->yplusx, b);
|
||||
fe_cmov(t->yminusx, u->yminusx, b);
|
||||
fe_cmov(t->xy2d, u->xy2d, b);
|
||||
}
|
||||
|
||||
|
||||
static void select(ge_precomp *t, int pos, signed char b) {
|
||||
ge_precomp minust;
|
||||
unsigned char bnegative = negative(b);
|
||||
unsigned char babs = b - (((-bnegative) & b) << 1);
|
||||
fe_1(t->yplusx);
|
||||
fe_1(t->yminusx);
|
||||
fe_0(t->xy2d);
|
||||
cmov(t, &base[pos][0], equal(babs, 1));
|
||||
cmov(t, &base[pos][1], equal(babs, 2));
|
||||
cmov(t, &base[pos][2], equal(babs, 3));
|
||||
cmov(t, &base[pos][3], equal(babs, 4));
|
||||
cmov(t, &base[pos][4], equal(babs, 5));
|
||||
cmov(t, &base[pos][5], equal(babs, 6));
|
||||
cmov(t, &base[pos][6], equal(babs, 7));
|
||||
cmov(t, &base[pos][7], equal(babs, 8));
|
||||
fe_copy(minust.yplusx, t->yminusx);
|
||||
fe_copy(minust.yminusx, t->yplusx);
|
||||
fe_neg(minust.xy2d, t->xy2d);
|
||||
cmov(t, &minust, bnegative);
|
||||
}
|
||||
|
||||
/*
|
||||
h = a * B
|
||||
where a = a[0]+256*a[1]+...+256^31 a[31]
|
||||
B is the Ed25519 base point (x,4/5) with x positive.
|
||||
|
||||
Preconditions:
|
||||
a[31] <= 127
|
||||
*/
|
||||
|
||||
void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) {
|
||||
signed char e[64];
|
||||
signed char carry;
|
||||
ge_p1p1 r;
|
||||
ge_p2 s;
|
||||
ge_precomp t;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
e[2 * i + 0] = (a[i] >> 0) & 15;
|
||||
e[2 * i + 1] = (a[i] >> 4) & 15;
|
||||
}
|
||||
|
||||
/* each e[i] is between 0 and 15 */
|
||||
/* e[63] is between 0 and 7 */
|
||||
carry = 0;
|
||||
|
||||
for (i = 0; i < 63; ++i) {
|
||||
e[i] += carry;
|
||||
carry = e[i] + 8;
|
||||
carry >>= 4;
|
||||
e[i] -= carry << 4;
|
||||
}
|
||||
|
||||
e[63] += carry;
|
||||
/* each e[i] is between -8 and 8 */
|
||||
ge_p3_0(h);
|
||||
|
||||
for (i = 1; i < 64; i += 2) {
|
||||
select(&t, i / 2, e[i]);
|
||||
ge_madd(&r, h, &t);
|
||||
ge_p1p1_to_p3(h, &r);
|
||||
}
|
||||
|
||||
ge_p3_dbl(&r, h);
|
||||
ge_p1p1_to_p2(&s, &r);
|
||||
ge_p2_dbl(&r, &s);
|
||||
ge_p1p1_to_p2(&s, &r);
|
||||
ge_p2_dbl(&r, &s);
|
||||
ge_p1p1_to_p2(&s, &r);
|
||||
ge_p2_dbl(&r, &s);
|
||||
ge_p1p1_to_p3(h, &r);
|
||||
|
||||
for (i = 0; i < 64; i += 2) {
|
||||
select(&t, i / 2, e[i]);
|
||||
ge_madd(&r, h, &t);
|
||||
ge_p1p1_to_p3(h, &r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p - q
|
||||
*/
|
||||
|
||||
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
|
||||
fe t0;
|
||||
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
fe_mul(r->Z, r->X, q->YminusX);
|
||||
fe_mul(r->Y, r->Y, q->YplusX);
|
||||
fe_mul(r->T, q->T2d, p->T);
|
||||
fe_mul(r->X, p->Z, q->Z);
|
||||
fe_add(t0, r->X, r->X);
|
||||
fe_sub(r->X, r->Z, r->Y);
|
||||
fe_add(r->Y, r->Z, r->Y);
|
||||
fe_sub(r->Z, t0, r->T);
|
||||
fe_add(r->T, t0, r->T);
|
||||
}
|
||||
|
||||
|
||||
void ge_tobytes(unsigned char *s, const ge_p2 *h) {
|
||||
fe recip;
|
||||
fe x;
|
||||
fe y;
|
||||
fe_invert(recip, h->Z);
|
||||
fe_mul(x, h->X, recip);
|
||||
fe_mul(y, h->Y, recip);
|
||||
fe_tobytes(s, y);
|
||||
s[31] ^= fe_isnegative(x) << 7;
|
||||
}
|
||||
74
User/lib/ed25519/ge.h
Normal file
74
User/lib/ed25519/ge.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#ifndef GE_H
|
||||
#define GE_H
|
||||
|
||||
#include "fe.h"
|
||||
|
||||
|
||||
/*
|
||||
ge means group element.
|
||||
|
||||
Here the group is the set of pairs (x,y) of field elements (see fe.h)
|
||||
satisfying -x^2 + y^2 = 1 + d x^2y^2
|
||||
where d = -121665/121666.
|
||||
|
||||
Representations:
|
||||
ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
|
||||
ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
|
||||
ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
|
||||
ge_precomp (Duif): (y+x,y-x,2dxy)
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
} ge_p2;
|
||||
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
fe T;
|
||||
} ge_p3;
|
||||
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
fe T;
|
||||
} ge_p1p1;
|
||||
|
||||
typedef struct {
|
||||
fe yplusx;
|
||||
fe yminusx;
|
||||
fe xy2d;
|
||||
} ge_precomp;
|
||||
|
||||
typedef struct {
|
||||
fe YplusX;
|
||||
fe YminusX;
|
||||
fe Z;
|
||||
fe T2d;
|
||||
} ge_cached;
|
||||
|
||||
void ge_p3_tobytes(unsigned char *s, const ge_p3 *h);
|
||||
void ge_tobytes(unsigned char *s, const ge_p2 *h);
|
||||
int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s);
|
||||
|
||||
void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
|
||||
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
|
||||
void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b);
|
||||
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
|
||||
void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
|
||||
void ge_scalarmult_base(ge_p3 *h, const unsigned char *a);
|
||||
|
||||
void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p);
|
||||
void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p);
|
||||
void ge_p2_0(ge_p2 *h);
|
||||
void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p);
|
||||
void ge_p3_0(ge_p3 *h);
|
||||
void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p);
|
||||
void ge_p3_to_cached(ge_cached *r, const ge_p3 *p);
|
||||
void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p);
|
||||
|
||||
#endif
|
||||
79
User/lib/ed25519/key_exchange.c
Normal file
79
User/lib/ed25519/key_exchange.c
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "ed_25519.h"
|
||||
#include "fe.h"
|
||||
|
||||
void ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key) {
|
||||
unsigned char e[32];
|
||||
unsigned int i;
|
||||
|
||||
fe x1;
|
||||
fe x2;
|
||||
fe z2;
|
||||
fe x3;
|
||||
fe z3;
|
||||
fe tmp0;
|
||||
fe tmp1;
|
||||
|
||||
int pos;
|
||||
unsigned int swap;
|
||||
unsigned int b;
|
||||
|
||||
/* copy the private key and make sure it's valid */
|
||||
for (i = 0; i < 32; ++i) {
|
||||
e[i] = private_key[i];
|
||||
}
|
||||
|
||||
e[0] &= 248;
|
||||
e[31] &= 63;
|
||||
e[31] |= 64;
|
||||
|
||||
/* unpack the public key and convert edwards to montgomery */
|
||||
/* due to CodesInChaos: montgomeryX = (edwardsY + 1)*inverse(1 - edwardsY) mod p */
|
||||
fe_frombytes(x1, public_key);
|
||||
fe_1(tmp1);
|
||||
fe_add(tmp0, x1, tmp1);
|
||||
fe_sub(tmp1, tmp1, x1);
|
||||
fe_invert(tmp1, tmp1);
|
||||
fe_mul(x1, tmp0, tmp1);
|
||||
|
||||
fe_1(x2);
|
||||
fe_0(z2);
|
||||
fe_copy(x3, x1);
|
||||
fe_1(z3);
|
||||
|
||||
swap = 0;
|
||||
for (pos = 254; pos >= 0; --pos) {
|
||||
b = e[pos / 8] >> (pos & 7);
|
||||
b &= 1;
|
||||
swap ^= b;
|
||||
fe_cswap(x2, x3, swap);
|
||||
fe_cswap(z2, z3, swap);
|
||||
swap = b;
|
||||
|
||||
/* from montgomery.h */
|
||||
fe_sub(tmp0, x3, z3);
|
||||
fe_sub(tmp1, x2, z2);
|
||||
fe_add(x2, x2, z2);
|
||||
fe_add(z2, x3, z3);
|
||||
fe_mul(z3, tmp0, x2);
|
||||
fe_mul(z2, z2, tmp1);
|
||||
fe_sq(tmp0, tmp1);
|
||||
fe_sq(tmp1, x2);
|
||||
fe_add(x3, z3, z2);
|
||||
fe_sub(z2, z3, z2);
|
||||
fe_mul(x2, tmp1, tmp0);
|
||||
fe_sub(tmp1, tmp1, tmp0);
|
||||
fe_sq(z2, z2);
|
||||
fe_mul121666(z3, tmp1);
|
||||
fe_sq(x3, x3);
|
||||
fe_add(tmp0, tmp0, z3);
|
||||
fe_mul(z3, x1, z2);
|
||||
fe_mul(z2, tmp1, tmp0);
|
||||
}
|
||||
|
||||
fe_cswap(x2, x3, swap);
|
||||
fe_cswap(z2, z3, swap);
|
||||
|
||||
fe_invert(z2, z2);
|
||||
fe_mul(x2, x2, z2);
|
||||
fe_tobytes(shared_secret, x2);
|
||||
}
|
||||
23
User/lib/ed25519/keypair.c
Normal file
23
User/lib/ed25519/keypair.c
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "ed_25519.h"
|
||||
#include "sha512.h"
|
||||
#include "ge.h"
|
||||
|
||||
|
||||
void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed) {
|
||||
ge_p3 A;
|
||||
|
||||
sha512(seed, 32, private_key);
|
||||
private_key[0] &= 248;
|
||||
private_key[31] &= 63;
|
||||
private_key[31] |= 64;
|
||||
|
||||
ge_scalarmult_base(&A, private_key);
|
||||
ge_p3_tobytes(public_key, &A);
|
||||
}
|
||||
|
||||
void ed25519_derive_pub(unsigned char *public_key, const unsigned char *private_key) {
|
||||
ge_p3 A;
|
||||
|
||||
ge_scalarmult_base(&A, private_key);
|
||||
ge_p3_tobytes(public_key, &A);
|
||||
}
|
||||
16
User/lib/ed25519/license.txt
Normal file
16
User/lib/ed25519/license.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
Copyright (c) 2015 Orson Peters <orsonpeters@gmail.com>
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty. In no event will the
|
||||
authors be held liable for any damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose, including commercial
|
||||
applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the
|
||||
original software. If you use this software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as
|
||||
being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
1391
User/lib/ed25519/precomp_data.h
Normal file
1391
User/lib/ed25519/precomp_data.h
Normal file
File diff suppressed because it is too large
Load Diff
809
User/lib/ed25519/sc.c
Normal file
809
User/lib/ed25519/sc.c
Normal file
@@ -0,0 +1,809 @@
|
||||
#include "fixedint.h"
|
||||
#include "sc.h"
|
||||
|
||||
static uint64_t load_3(const unsigned char *in) {
|
||||
uint64_t result;
|
||||
|
||||
result = (uint64_t) in[0];
|
||||
result |= ((uint64_t) in[1]) << 8;
|
||||
result |= ((uint64_t) in[2]) << 16;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint64_t load_4(const unsigned char *in) {
|
||||
uint64_t result;
|
||||
|
||||
result = (uint64_t) in[0];
|
||||
result |= ((uint64_t) in[1]) << 8;
|
||||
result |= ((uint64_t) in[2]) << 16;
|
||||
result |= ((uint64_t) in[3]) << 24;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Input:
|
||||
s[0]+256*s[1]+...+256^63*s[63] = s
|
||||
|
||||
Output:
|
||||
s[0]+256*s[1]+...+256^31*s[31] = s mod l
|
||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||
Overwrites s in place.
|
||||
*/
|
||||
|
||||
void sc_reduce(unsigned char *s) {
|
||||
int64_t s0 = 2097151 & load_3(s);
|
||||
int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
|
||||
int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
|
||||
int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
|
||||
int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
|
||||
int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
|
||||
int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
|
||||
int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
|
||||
int64_t s8 = 2097151 & load_3(s + 21);
|
||||
int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
|
||||
int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
|
||||
int64_t s11 = 2097151 & (load_4(s + 28) >> 7);
|
||||
int64_t s12 = 2097151 & (load_4(s + 31) >> 4);
|
||||
int64_t s13 = 2097151 & (load_3(s + 34) >> 1);
|
||||
int64_t s14 = 2097151 & (load_4(s + 36) >> 6);
|
||||
int64_t s15 = 2097151 & (load_3(s + 39) >> 3);
|
||||
int64_t s16 = 2097151 & load_3(s + 42);
|
||||
int64_t s17 = 2097151 & (load_4(s + 44) >> 5);
|
||||
int64_t s18 = 2097151 & (load_3(s + 47) >> 2);
|
||||
int64_t s19 = 2097151 & (load_4(s + 49) >> 7);
|
||||
int64_t s20 = 2097151 & (load_4(s + 52) >> 4);
|
||||
int64_t s21 = 2097151 & (load_3(s + 55) >> 1);
|
||||
int64_t s22 = 2097151 & (load_4(s + 57) >> 6);
|
||||
int64_t s23 = (load_4(s + 60) >> 3);
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
int64_t carry10;
|
||||
int64_t carry11;
|
||||
int64_t carry12;
|
||||
int64_t carry13;
|
||||
int64_t carry14;
|
||||
int64_t carry15;
|
||||
int64_t carry16;
|
||||
|
||||
s11 += s23 * 666643;
|
||||
s12 += s23 * 470296;
|
||||
s13 += s23 * 654183;
|
||||
s14 -= s23 * 997805;
|
||||
s15 += s23 * 136657;
|
||||
s16 -= s23 * 683901;
|
||||
s23 = 0;
|
||||
s10 += s22 * 666643;
|
||||
s11 += s22 * 470296;
|
||||
s12 += s22 * 654183;
|
||||
s13 -= s22 * 997805;
|
||||
s14 += s22 * 136657;
|
||||
s15 -= s22 * 683901;
|
||||
s22 = 0;
|
||||
s9 += s21 * 666643;
|
||||
s10 += s21 * 470296;
|
||||
s11 += s21 * 654183;
|
||||
s12 -= s21 * 997805;
|
||||
s13 += s21 * 136657;
|
||||
s14 -= s21 * 683901;
|
||||
s21 = 0;
|
||||
s8 += s20 * 666643;
|
||||
s9 += s20 * 470296;
|
||||
s10 += s20 * 654183;
|
||||
s11 -= s20 * 997805;
|
||||
s12 += s20 * 136657;
|
||||
s13 -= s20 * 683901;
|
||||
s20 = 0;
|
||||
s7 += s19 * 666643;
|
||||
s8 += s19 * 470296;
|
||||
s9 += s19 * 654183;
|
||||
s10 -= s19 * 997805;
|
||||
s11 += s19 * 136657;
|
||||
s12 -= s19 * 683901;
|
||||
s19 = 0;
|
||||
s6 += s18 * 666643;
|
||||
s7 += s18 * 470296;
|
||||
s8 += s18 * 654183;
|
||||
s9 -= s18 * 997805;
|
||||
s10 += s18 * 136657;
|
||||
s11 -= s18 * 683901;
|
||||
s18 = 0;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1 << 20)) >> 21;
|
||||
s13 += carry12;
|
||||
s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1 << 20)) >> 21;
|
||||
s15 += carry14;
|
||||
s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1 << 20)) >> 21;
|
||||
s17 += carry16;
|
||||
s16 -= carry16 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1 << 20)) >> 21;
|
||||
s14 += carry13;
|
||||
s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1 << 20)) >> 21;
|
||||
s16 += carry15;
|
||||
s15 -= carry15 << 21;
|
||||
s5 += s17 * 666643;
|
||||
s6 += s17 * 470296;
|
||||
s7 += s17 * 654183;
|
||||
s8 -= s17 * 997805;
|
||||
s9 += s17 * 136657;
|
||||
s10 -= s17 * 683901;
|
||||
s17 = 0;
|
||||
s4 += s16 * 666643;
|
||||
s5 += s16 * 470296;
|
||||
s6 += s16 * 654183;
|
||||
s7 -= s16 * 997805;
|
||||
s8 += s16 * 136657;
|
||||
s9 -= s16 * 683901;
|
||||
s16 = 0;
|
||||
s3 += s15 * 666643;
|
||||
s4 += s15 * 470296;
|
||||
s5 += s15 * 654183;
|
||||
s6 -= s15 * 997805;
|
||||
s7 += s15 * 136657;
|
||||
s8 -= s15 * 683901;
|
||||
s15 = 0;
|
||||
s2 += s14 * 666643;
|
||||
s3 += s14 * 470296;
|
||||
s4 += s14 * 654183;
|
||||
s5 -= s14 * 997805;
|
||||
s6 += s14 * 136657;
|
||||
s7 -= s14 * 683901;
|
||||
s14 = 0;
|
||||
s1 += s13 * 666643;
|
||||
s2 += s13 * 470296;
|
||||
s3 += s13 * 654183;
|
||||
s4 -= s13 * 997805;
|
||||
s5 += s13 * 136657;
|
||||
s6 -= s13 * 683901;
|
||||
s13 = 0;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = (s0 + (1 << 20)) >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1 << 20)) >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1 << 20)) >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry1 = (s1 + (1 << 20)) >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1 << 20)) >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1 << 20)) >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry11 = s11 >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
|
||||
s[0] = (unsigned char) (s0 >> 0);
|
||||
s[1] = (unsigned char) (s0 >> 8);
|
||||
s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5));
|
||||
s[3] = (unsigned char) (s1 >> 3);
|
||||
s[4] = (unsigned char) (s1 >> 11);
|
||||
s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2));
|
||||
s[6] = (unsigned char) (s2 >> 6);
|
||||
s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7));
|
||||
s[8] = (unsigned char) (s3 >> 1);
|
||||
s[9] = (unsigned char) (s3 >> 9);
|
||||
s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4));
|
||||
s[11] = (unsigned char) (s4 >> 4);
|
||||
s[12] = (unsigned char) (s4 >> 12);
|
||||
s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1));
|
||||
s[14] = (unsigned char) (s5 >> 7);
|
||||
s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6));
|
||||
s[16] = (unsigned char) (s6 >> 2);
|
||||
s[17] = (unsigned char) (s6 >> 10);
|
||||
s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3));
|
||||
s[19] = (unsigned char) (s7 >> 5);
|
||||
s[20] = (unsigned char) (s7 >> 13);
|
||||
s[21] = (unsigned char) (s8 >> 0);
|
||||
s[22] = (unsigned char) (s8 >> 8);
|
||||
s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5));
|
||||
s[24] = (unsigned char) (s9 >> 3);
|
||||
s[25] = (unsigned char) (s9 >> 11);
|
||||
s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2));
|
||||
s[27] = (unsigned char) (s10 >> 6);
|
||||
s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7));
|
||||
s[29] = (unsigned char) (s11 >> 1);
|
||||
s[30] = (unsigned char) (s11 >> 9);
|
||||
s[31] = (unsigned char) (s11 >> 17);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Input:
|
||||
a[0]+256*a[1]+...+256^31*a[31] = a
|
||||
b[0]+256*b[1]+...+256^31*b[31] = b
|
||||
c[0]+256*c[1]+...+256^31*c[31] = c
|
||||
|
||||
Output:
|
||||
s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
|
||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||
*/
|
||||
|
||||
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) {
|
||||
int64_t a0 = 2097151 & load_3(a);
|
||||
int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
|
||||
int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
|
||||
int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
|
||||
int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
|
||||
int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
|
||||
int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
|
||||
int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
|
||||
int64_t a8 = 2097151 & load_3(a + 21);
|
||||
int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
|
||||
int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
|
||||
int64_t a11 = (load_4(a + 28) >> 7);
|
||||
int64_t b0 = 2097151 & load_3(b);
|
||||
int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
|
||||
int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
|
||||
int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
|
||||
int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
|
||||
int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
|
||||
int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
|
||||
int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
|
||||
int64_t b8 = 2097151 & load_3(b + 21);
|
||||
int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
|
||||
int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
|
||||
int64_t b11 = (load_4(b + 28) >> 7);
|
||||
int64_t c0 = 2097151 & load_3(c);
|
||||
int64_t c1 = 2097151 & (load_4(c + 2) >> 5);
|
||||
int64_t c2 = 2097151 & (load_3(c + 5) >> 2);
|
||||
int64_t c3 = 2097151 & (load_4(c + 7) >> 7);
|
||||
int64_t c4 = 2097151 & (load_4(c + 10) >> 4);
|
||||
int64_t c5 = 2097151 & (load_3(c + 13) >> 1);
|
||||
int64_t c6 = 2097151 & (load_4(c + 15) >> 6);
|
||||
int64_t c7 = 2097151 & (load_3(c + 18) >> 3);
|
||||
int64_t c8 = 2097151 & load_3(c + 21);
|
||||
int64_t c9 = 2097151 & (load_4(c + 23) >> 5);
|
||||
int64_t c10 = 2097151 & (load_3(c + 26) >> 2);
|
||||
int64_t c11 = (load_4(c + 28) >> 7);
|
||||
int64_t s0;
|
||||
int64_t s1;
|
||||
int64_t s2;
|
||||
int64_t s3;
|
||||
int64_t s4;
|
||||
int64_t s5;
|
||||
int64_t s6;
|
||||
int64_t s7;
|
||||
int64_t s8;
|
||||
int64_t s9;
|
||||
int64_t s10;
|
||||
int64_t s11;
|
||||
int64_t s12;
|
||||
int64_t s13;
|
||||
int64_t s14;
|
||||
int64_t s15;
|
||||
int64_t s16;
|
||||
int64_t s17;
|
||||
int64_t s18;
|
||||
int64_t s19;
|
||||
int64_t s20;
|
||||
int64_t s21;
|
||||
int64_t s22;
|
||||
int64_t s23;
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
int64_t carry10;
|
||||
int64_t carry11;
|
||||
int64_t carry12;
|
||||
int64_t carry13;
|
||||
int64_t carry14;
|
||||
int64_t carry15;
|
||||
int64_t carry16;
|
||||
int64_t carry17;
|
||||
int64_t carry18;
|
||||
int64_t carry19;
|
||||
int64_t carry20;
|
||||
int64_t carry21;
|
||||
int64_t carry22;
|
||||
|
||||
s0 = c0 + a0 * b0;
|
||||
s1 = c1 + a0 * b1 + a1 * b0;
|
||||
s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0;
|
||||
s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
|
||||
s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
|
||||
s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
|
||||
s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
|
||||
s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0;
|
||||
s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1 + a8 * b0;
|
||||
s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
|
||||
s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
|
||||
s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
|
||||
s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
|
||||
s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2;
|
||||
s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + a9 * b5 + a10 * b4 + a11 * b3;
|
||||
s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + a10 * b5 + a11 * b4;
|
||||
s16 = a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
|
||||
s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
|
||||
s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
|
||||
s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
|
||||
s20 = a9 * b11 + a10 * b10 + a11 * b9;
|
||||
s21 = a10 * b11 + a11 * b10;
|
||||
s22 = a11 * b11;
|
||||
s23 = 0;
|
||||
carry0 = (s0 + (1 << 20)) >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1 << 20)) >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1 << 20)) >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1 << 20)) >> 21;
|
||||
s13 += carry12;
|
||||
s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1 << 20)) >> 21;
|
||||
s15 += carry14;
|
||||
s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1 << 20)) >> 21;
|
||||
s17 += carry16;
|
||||
s16 -= carry16 << 21;
|
||||
carry18 = (s18 + (1 << 20)) >> 21;
|
||||
s19 += carry18;
|
||||
s18 -= carry18 << 21;
|
||||
carry20 = (s20 + (1 << 20)) >> 21;
|
||||
s21 += carry20;
|
||||
s20 -= carry20 << 21;
|
||||
carry22 = (s22 + (1 << 20)) >> 21;
|
||||
s23 += carry22;
|
||||
s22 -= carry22 << 21;
|
||||
carry1 = (s1 + (1 << 20)) >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1 << 20)) >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1 << 20)) >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1 << 20)) >> 21;
|
||||
s14 += carry13;
|
||||
s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1 << 20)) >> 21;
|
||||
s16 += carry15;
|
||||
s15 -= carry15 << 21;
|
||||
carry17 = (s17 + (1 << 20)) >> 21;
|
||||
s18 += carry17;
|
||||
s17 -= carry17 << 21;
|
||||
carry19 = (s19 + (1 << 20)) >> 21;
|
||||
s20 += carry19;
|
||||
s19 -= carry19 << 21;
|
||||
carry21 = (s21 + (1 << 20)) >> 21;
|
||||
s22 += carry21;
|
||||
s21 -= carry21 << 21;
|
||||
s11 += s23 * 666643;
|
||||
s12 += s23 * 470296;
|
||||
s13 += s23 * 654183;
|
||||
s14 -= s23 * 997805;
|
||||
s15 += s23 * 136657;
|
||||
s16 -= s23 * 683901;
|
||||
s23 = 0;
|
||||
s10 += s22 * 666643;
|
||||
s11 += s22 * 470296;
|
||||
s12 += s22 * 654183;
|
||||
s13 -= s22 * 997805;
|
||||
s14 += s22 * 136657;
|
||||
s15 -= s22 * 683901;
|
||||
s22 = 0;
|
||||
s9 += s21 * 666643;
|
||||
s10 += s21 * 470296;
|
||||
s11 += s21 * 654183;
|
||||
s12 -= s21 * 997805;
|
||||
s13 += s21 * 136657;
|
||||
s14 -= s21 * 683901;
|
||||
s21 = 0;
|
||||
s8 += s20 * 666643;
|
||||
s9 += s20 * 470296;
|
||||
s10 += s20 * 654183;
|
||||
s11 -= s20 * 997805;
|
||||
s12 += s20 * 136657;
|
||||
s13 -= s20 * 683901;
|
||||
s20 = 0;
|
||||
s7 += s19 * 666643;
|
||||
s8 += s19 * 470296;
|
||||
s9 += s19 * 654183;
|
||||
s10 -= s19 * 997805;
|
||||
s11 += s19 * 136657;
|
||||
s12 -= s19 * 683901;
|
||||
s19 = 0;
|
||||
s6 += s18 * 666643;
|
||||
s7 += s18 * 470296;
|
||||
s8 += s18 * 654183;
|
||||
s9 -= s18 * 997805;
|
||||
s10 += s18 * 136657;
|
||||
s11 -= s18 * 683901;
|
||||
s18 = 0;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1 << 20)) >> 21;
|
||||
s13 += carry12;
|
||||
s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1 << 20)) >> 21;
|
||||
s15 += carry14;
|
||||
s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1 << 20)) >> 21;
|
||||
s17 += carry16;
|
||||
s16 -= carry16 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1 << 20)) >> 21;
|
||||
s14 += carry13;
|
||||
s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1 << 20)) >> 21;
|
||||
s16 += carry15;
|
||||
s15 -= carry15 << 21;
|
||||
s5 += s17 * 666643;
|
||||
s6 += s17 * 470296;
|
||||
s7 += s17 * 654183;
|
||||
s8 -= s17 * 997805;
|
||||
s9 += s17 * 136657;
|
||||
s10 -= s17 * 683901;
|
||||
s17 = 0;
|
||||
s4 += s16 * 666643;
|
||||
s5 += s16 * 470296;
|
||||
s6 += s16 * 654183;
|
||||
s7 -= s16 * 997805;
|
||||
s8 += s16 * 136657;
|
||||
s9 -= s16 * 683901;
|
||||
s16 = 0;
|
||||
s3 += s15 * 666643;
|
||||
s4 += s15 * 470296;
|
||||
s5 += s15 * 654183;
|
||||
s6 -= s15 * 997805;
|
||||
s7 += s15 * 136657;
|
||||
s8 -= s15 * 683901;
|
||||
s15 = 0;
|
||||
s2 += s14 * 666643;
|
||||
s3 += s14 * 470296;
|
||||
s4 += s14 * 654183;
|
||||
s5 -= s14 * 997805;
|
||||
s6 += s14 * 136657;
|
||||
s7 -= s14 * 683901;
|
||||
s14 = 0;
|
||||
s1 += s13 * 666643;
|
||||
s2 += s13 * 470296;
|
||||
s3 += s13 * 654183;
|
||||
s4 -= s13 * 997805;
|
||||
s5 += s13 * 136657;
|
||||
s6 -= s13 * 683901;
|
||||
s13 = 0;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = (s0 + (1 << 20)) >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1 << 20)) >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1 << 20)) >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry1 = (s1 + (1 << 20)) >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1 << 20)) >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1 << 20)) >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
carry11 = s11 >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= carry11 << 21;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= carry10 << 21;
|
||||
|
||||
s[0] = (unsigned char) (s0 >> 0);
|
||||
s[1] = (unsigned char) (s0 >> 8);
|
||||
s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5));
|
||||
s[3] = (unsigned char) (s1 >> 3);
|
||||
s[4] = (unsigned char) (s1 >> 11);
|
||||
s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2));
|
||||
s[6] = (unsigned char) (s2 >> 6);
|
||||
s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7));
|
||||
s[8] = (unsigned char) (s3 >> 1);
|
||||
s[9] = (unsigned char) (s3 >> 9);
|
||||
s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4));
|
||||
s[11] = (unsigned char) (s4 >> 4);
|
||||
s[12] = (unsigned char) (s4 >> 12);
|
||||
s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1));
|
||||
s[14] = (unsigned char) (s5 >> 7);
|
||||
s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6));
|
||||
s[16] = (unsigned char) (s6 >> 2);
|
||||
s[17] = (unsigned char) (s6 >> 10);
|
||||
s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3));
|
||||
s[19] = (unsigned char) (s7 >> 5);
|
||||
s[20] = (unsigned char) (s7 >> 13);
|
||||
s[21] = (unsigned char) (s8 >> 0);
|
||||
s[22] = (unsigned char) (s8 >> 8);
|
||||
s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5));
|
||||
s[24] = (unsigned char) (s9 >> 3);
|
||||
s[25] = (unsigned char) (s9 >> 11);
|
||||
s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2));
|
||||
s[27] = (unsigned char) (s10 >> 6);
|
||||
s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7));
|
||||
s[29] = (unsigned char) (s11 >> 1);
|
||||
s[30] = (unsigned char) (s11 >> 9);
|
||||
s[31] = (unsigned char) (s11 >> 17);
|
||||
}
|
||||
12
User/lib/ed25519/sc.h
Normal file
12
User/lib/ed25519/sc.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef SC_H
|
||||
#define SC_H
|
||||
|
||||
/*
|
||||
The set of scalars is \Z/l
|
||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||
*/
|
||||
|
||||
void sc_reduce(unsigned char *s);
|
||||
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c);
|
||||
|
||||
#endif
|
||||
40
User/lib/ed25519/seed.c
Normal file
40
User/lib/ed25519/seed.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "ed_25519.h"
|
||||
|
||||
#ifndef ED25519_NO_SEED
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
int ed25519_create_seed(unsigned char *seed) {
|
||||
#ifdef _WIN32
|
||||
HCRYPTPROV prov;
|
||||
|
||||
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!CryptGenRandom(prov, 32, seed)) {
|
||||
CryptReleaseContext(prov, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
CryptReleaseContext(prov, 0);
|
||||
#else
|
||||
FILE *f = fopen("/dev/urandom", "rb");
|
||||
|
||||
if (f == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
fread(seed, 1, 32, f);
|
||||
fclose(f);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
275
User/lib/ed25519/sha512.c
Normal file
275
User/lib/ed25519/sha512.c
Normal file
@@ -0,0 +1,275 @@
|
||||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
|
||||
*
|
||||
* LibTomCrypt is a library that provides various cryptographic
|
||||
* algorithms in a highly modular and flexible manner.
|
||||
*
|
||||
* The library is free for all purposes without any express
|
||||
* guarantee it works.
|
||||
*
|
||||
* Tom St Denis, tomstdenis@gmail.com, http://libtom.org
|
||||
*/
|
||||
|
||||
#include "fixedint.h"
|
||||
#include "sha512.h"
|
||||
|
||||
/* the K array */
|
||||
static const uint64_t K[80] = {
|
||||
UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
|
||||
UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
|
||||
UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019),
|
||||
UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118),
|
||||
UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe),
|
||||
UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2),
|
||||
UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1),
|
||||
UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694),
|
||||
UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3),
|
||||
UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65),
|
||||
UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483),
|
||||
UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5),
|
||||
UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210),
|
||||
UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4),
|
||||
UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725),
|
||||
UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70),
|
||||
UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926),
|
||||
UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df),
|
||||
UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8),
|
||||
UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b),
|
||||
UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001),
|
||||
UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30),
|
||||
UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910),
|
||||
UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8),
|
||||
UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53),
|
||||
UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8),
|
||||
UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb),
|
||||
UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3),
|
||||
UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60),
|
||||
UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec),
|
||||
UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9),
|
||||
UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b),
|
||||
UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207),
|
||||
UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178),
|
||||
UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6),
|
||||
UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b),
|
||||
UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493),
|
||||
UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c),
|
||||
UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a),
|
||||
UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817)
|
||||
};
|
||||
|
||||
/* Various logical functions */
|
||||
|
||||
#define ROR64c(x, y) \
|
||||
( ((((x)&UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)(y)&UINT64_C(63))) | \
|
||||
((x)<<((uint64_t)(64-((y)&UINT64_C(63)))))) & UINT64_C(0xFFFFFFFFFFFFFFFF))
|
||||
|
||||
#define STORE64H(x, y) \
|
||||
{ (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
|
||||
(y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
|
||||
(y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
|
||||
(y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
|
||||
|
||||
#define LOAD64H(x, y) \
|
||||
{ x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \
|
||||
(((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \
|
||||
(((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \
|
||||
(((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); }
|
||||
|
||||
|
||||
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
|
||||
#define Maj(x,y,z) (((x | y) & z) | (x & y))
|
||||
#define S(x, n) ROR64c(x, n)
|
||||
#define R(x, n) (((x) &UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)n))
|
||||
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
|
||||
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
|
||||
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
|
||||
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) ( ((x)<(y))?(x):(y) )
|
||||
#endif
|
||||
|
||||
/* compress 1024-bits */
|
||||
static int sha512_compress(sha512_context *md, unsigned char *buf)
|
||||
{
|
||||
uint64_t S[8], W[80], t0, t1;
|
||||
int i;
|
||||
|
||||
/* copy state into S */
|
||||
for (i = 0; i < 8; i++) {
|
||||
S[i] = md->state[i];
|
||||
}
|
||||
|
||||
/* copy the state into 1024-bits into W[0..15] */
|
||||
for (i = 0; i < 16; i++) {
|
||||
LOAD64H(W[i], buf + (8*i));
|
||||
}
|
||||
|
||||
/* fill W[16..79] */
|
||||
for (i = 16; i < 80; i++) {
|
||||
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
|
||||
}
|
||||
|
||||
/* Compress */
|
||||
#define RND(a,b,c,d,e,f,g,h,i) \
|
||||
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
|
||||
t1 = Sigma0(a) + Maj(a, b, c);\
|
||||
d += t0; \
|
||||
h = t0 + t1;
|
||||
|
||||
for (i = 0; i < 80; i += 8) {
|
||||
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
|
||||
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
|
||||
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
|
||||
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
|
||||
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
|
||||
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
|
||||
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
|
||||
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
|
||||
}
|
||||
|
||||
#undef RND
|
||||
|
||||
|
||||
|
||||
/* feedback */
|
||||
for (i = 0; i < 8; i++) {
|
||||
md->state[i] = md->state[i] + S[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Initialize the hash state
|
||||
@param md The hash state you wish to initialize
|
||||
@return 0 if successful
|
||||
*/
|
||||
int sha512_init(sha512_context * md) {
|
||||
if (md == NULL) return 1;
|
||||
|
||||
md->curlen = 0;
|
||||
md->length = 0;
|
||||
md->state[0] = UINT64_C(0x6a09e667f3bcc908);
|
||||
md->state[1] = UINT64_C(0xbb67ae8584caa73b);
|
||||
md->state[2] = UINT64_C(0x3c6ef372fe94f82b);
|
||||
md->state[3] = UINT64_C(0xa54ff53a5f1d36f1);
|
||||
md->state[4] = UINT64_C(0x510e527fade682d1);
|
||||
md->state[5] = UINT64_C(0x9b05688c2b3e6c1f);
|
||||
md->state[6] = UINT64_C(0x1f83d9abfb41bd6b);
|
||||
md->state[7] = UINT64_C(0x5be0cd19137e2179);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Process a block of memory though the hash
|
||||
@param md The hash state
|
||||
@param in The data to hash
|
||||
@param inlen The length of the data (octets)
|
||||
@return 0 if successful
|
||||
*/
|
||||
int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen)
|
||||
{
|
||||
size_t n;
|
||||
size_t i;
|
||||
int err;
|
||||
if (md == NULL) return 1;
|
||||
if (in == NULL) return 1;
|
||||
if (md->curlen > sizeof(md->buf)) {
|
||||
return 1;
|
||||
}
|
||||
while (inlen > 0) {
|
||||
if (md->curlen == 0 && inlen >= 128) {
|
||||
if ((err = sha512_compress (md, (unsigned char *)in)) != 0) {
|
||||
return err;
|
||||
}
|
||||
md->length += 128 * 8;
|
||||
in += 128;
|
||||
inlen -= 128;
|
||||
} else {
|
||||
n = MIN(inlen, (128 - md->curlen));
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
md->buf[i + md->curlen] = in[i];
|
||||
}
|
||||
|
||||
|
||||
md->curlen += n;
|
||||
in += n;
|
||||
inlen -= n;
|
||||
if (md->curlen == 128) {
|
||||
if ((err = sha512_compress (md, md->buf)) != 0) {
|
||||
return err;
|
||||
}
|
||||
md->length += 8*128;
|
||||
md->curlen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Terminate the hash to get the digest
|
||||
@param md The hash state
|
||||
@param out [out] The destination of the hash (64 bytes)
|
||||
@return 0 if successful
|
||||
*/
|
||||
int sha512_final(sha512_context * md, unsigned char *out)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (md == NULL) return 1;
|
||||
if (out == NULL) return 1;
|
||||
|
||||
if (md->curlen >= sizeof(md->buf)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* increase the length of the message */
|
||||
md->length += md->curlen * UINT64_C(8);
|
||||
|
||||
/* append the '1' bit */
|
||||
md->buf[md->curlen++] = (unsigned char)0x80;
|
||||
|
||||
/* if the length is currently above 112 bytes we append zeros
|
||||
* then compress. Then we can fall back to padding zeros and length
|
||||
* encoding like normal.
|
||||
*/
|
||||
if (md->curlen > 112) {
|
||||
while (md->curlen < 128) {
|
||||
md->buf[md->curlen++] = (unsigned char)0;
|
||||
}
|
||||
sha512_compress(md, md->buf);
|
||||
md->curlen = 0;
|
||||
}
|
||||
|
||||
/* pad upto 120 bytes of zeroes
|
||||
* note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash
|
||||
* > 2^64 bits of data... :-)
|
||||
*/
|
||||
while (md->curlen < 120) {
|
||||
md->buf[md->curlen++] = (unsigned char)0;
|
||||
}
|
||||
|
||||
/* store length */
|
||||
STORE64H(md->length, md->buf+120);
|
||||
sha512_compress(md, md->buf);
|
||||
|
||||
/* copy output */
|
||||
for (i = 0; i < 8; i++) {
|
||||
STORE64H(md->state[i], out+(8*i));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sha512(const unsigned char *message, size_t message_len, unsigned char *out)
|
||||
{
|
||||
sha512_context ctx;
|
||||
int ret;
|
||||
if ((ret = sha512_init(&ctx))) return ret;
|
||||
if ((ret = sha512_update(&ctx, message, message_len))) return ret;
|
||||
if ((ret = sha512_final(&ctx, out))) return ret;
|
||||
return 0;
|
||||
}
|
||||
21
User/lib/ed25519/sha512.h
Normal file
21
User/lib/ed25519/sha512.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef SHA512_H
|
||||
#define SHA512_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "fixedint.h"
|
||||
|
||||
/* state */
|
||||
typedef struct sha512_context_ {
|
||||
uint64_t length, state[8];
|
||||
size_t curlen;
|
||||
unsigned char buf[128];
|
||||
} sha512_context;
|
||||
|
||||
|
||||
int sha512_init(sha512_context * md);
|
||||
int sha512_final(sha512_context * md, unsigned char *out);
|
||||
int sha512_update(sha512_context * md, const unsigned char *in, size_t inlen);
|
||||
int sha512(const unsigned char *message, size_t message_len, unsigned char *out);
|
||||
|
||||
#endif
|
||||
31
User/lib/ed25519/sign.c
Normal file
31
User/lib/ed25519/sign.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "ed_25519.h"
|
||||
#include "sha512.h"
|
||||
#include "ge.h"
|
||||
#include "sc.h"
|
||||
|
||||
|
||||
void ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key) {
|
||||
sha512_context hash;
|
||||
unsigned char hram[64];
|
||||
unsigned char r[64];
|
||||
ge_p3 R;
|
||||
|
||||
|
||||
sha512_init(&hash);
|
||||
sha512_update(&hash, private_key + 32, 32);
|
||||
sha512_update(&hash, message, message_len);
|
||||
sha512_final(&hash, r);
|
||||
|
||||
sc_reduce(r);
|
||||
ge_scalarmult_base(&R, r);
|
||||
ge_p3_tobytes(signature, &R);
|
||||
|
||||
sha512_init(&hash);
|
||||
sha512_update(&hash, signature, 32);
|
||||
sha512_update(&hash, public_key, 32);
|
||||
sha512_update(&hash, message, message_len);
|
||||
sha512_final(&hash, hram);
|
||||
|
||||
sc_reduce(hram);
|
||||
sc_muladd(signature + 32, hram, private_key, r);
|
||||
}
|
||||
77
User/lib/ed25519/verify.c
Normal file
77
User/lib/ed25519/verify.c
Normal file
@@ -0,0 +1,77 @@
|
||||
#include "ed_25519.h"
|
||||
#include "sha512.h"
|
||||
#include "ge.h"
|
||||
#include "sc.h"
|
||||
|
||||
static int consttime_equal(const unsigned char *x, const unsigned char *y) {
|
||||
unsigned char r = 0;
|
||||
|
||||
r = x[0] ^ y[0];
|
||||
#define F(i) r |= x[i] ^ y[i]
|
||||
F(1);
|
||||
F(2);
|
||||
F(3);
|
||||
F(4);
|
||||
F(5);
|
||||
F(6);
|
||||
F(7);
|
||||
F(8);
|
||||
F(9);
|
||||
F(10);
|
||||
F(11);
|
||||
F(12);
|
||||
F(13);
|
||||
F(14);
|
||||
F(15);
|
||||
F(16);
|
||||
F(17);
|
||||
F(18);
|
||||
F(19);
|
||||
F(20);
|
||||
F(21);
|
||||
F(22);
|
||||
F(23);
|
||||
F(24);
|
||||
F(25);
|
||||
F(26);
|
||||
F(27);
|
||||
F(28);
|
||||
F(29);
|
||||
F(30);
|
||||
F(31);
|
||||
#undef F
|
||||
|
||||
return !r;
|
||||
}
|
||||
|
||||
int ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key) {
|
||||
unsigned char h[64];
|
||||
unsigned char checker[32];
|
||||
sha512_context hash;
|
||||
ge_p3 A;
|
||||
ge_p2 R;
|
||||
|
||||
if (signature[63] & 224) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ge_frombytes_negate_vartime(&A, public_key) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sha512_init(&hash);
|
||||
sha512_update(&hash, signature, 32);
|
||||
sha512_update(&hash, public_key, 32);
|
||||
sha512_update(&hash, message, message_len);
|
||||
sha512_final(&hash, h);
|
||||
|
||||
sc_reduce(h);
|
||||
ge_double_scalarmult_vartime(&R, h, &A, signature + 32);
|
||||
ge_tobytes(checker, &R);
|
||||
|
||||
if (!consttime_equal(checker, signature)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1,536 +0,0 @@
|
||||
// Monocypher version 4.0.2
|
||||
//
|
||||
// This file is dual-licensed. Choose whichever licence you want from
|
||||
// the two licences listed below.
|
||||
//
|
||||
// The first licence is a regular 2-clause BSD licence. The second licence
|
||||
// is the CC-0 from Creative Commons. It is intended to release Monocypher
|
||||
// to the public domain. The BSD licence serves as a fallback option.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2017-2019, Loup Vaillant
|
||||
// All rights reserved.
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Written in 2017-2019 by Loup Vaillant
|
||||
//
|
||||
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||
// and related neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
//
|
||||
// You should have received a copy of the CC0 Public Domain Dedication along
|
||||
// with this software. If not, see
|
||||
// <https://creativecommons.org/publicdomain/zero/1.0/>
|
||||
|
||||
#include "monocypher-ed25519.h"
|
||||
|
||||
#ifdef MONOCYPHER_CPP_NAMESPACE
|
||||
namespace MONOCYPHER_CPP_NAMESPACE {
|
||||
#endif
|
||||
|
||||
/////////////////
|
||||
/// Utilities ///
|
||||
/////////////////
|
||||
#define FOR(i, min, max) for (size_t i = min; i < max; i++)
|
||||
#define COPY(dst, src, size) FOR (_i_, 0, size) (dst)[_i_] = (src)[_i_]
|
||||
#define ZERO(buf, size) FOR (_i_, 0, size) (buf)[_i_] = 0
|
||||
#define WIPE_CTX(ctx) crypto_wipe (ctx, sizeof (*(ctx)))
|
||||
#define WIPE_BUFFER(buffer) crypto_wipe (buffer, sizeof (buffer))
|
||||
#define MIN(a, b) ((a) <= (b) ? (a) : (b))
|
||||
typedef uint8_t u8;
|
||||
typedef uint64_t u64;
|
||||
|
||||
// Returns the smallest positive integer y such that
|
||||
// (x + y) % pow_2 == 0
|
||||
// Basically, it's how many bytes we need to add to "align" x.
|
||||
// Only works when pow_2 is a power of 2.
|
||||
// Note: we use ~x+1 instead of -x to avoid compiler warnings
|
||||
static size_t align (size_t x, size_t pow_2) {
|
||||
return (~x + 1) & (pow_2 - 1);
|
||||
}
|
||||
|
||||
static u64 load64_be (const u8 s[8]) {
|
||||
return ((u64)s[0] << 56) | ((u64)s[1] << 48) | ((u64)s[2] << 40) | ((u64)s[3] << 32) | ((u64)s[4] << 24) | ((u64)s[5] << 16) | ((u64)s[6] << 8) | (u64)s[7];
|
||||
}
|
||||
|
||||
static void store64_be (u8 out[8], u64 in) {
|
||||
out[0] = (in >> 56) & 0xff;
|
||||
out[1] = (in >> 48) & 0xff;
|
||||
out[2] = (in >> 40) & 0xff;
|
||||
out[3] = (in >> 32) & 0xff;
|
||||
out[4] = (in >> 24) & 0xff;
|
||||
out[5] = (in >> 16) & 0xff;
|
||||
out[6] = (in >> 8) & 0xff;
|
||||
out[7] = in & 0xff;
|
||||
}
|
||||
|
||||
static void load64_be_buf (u64 *dst, const u8 *src, size_t size) {
|
||||
FOR (i, 0, size) { dst[i] = load64_be (src + i * 8); }
|
||||
}
|
||||
|
||||
///////////////
|
||||
/// SHA 512 ///
|
||||
///////////////
|
||||
static u64 rot (u64 x, int c) { return (x >> c) | (x << (64 - c)); }
|
||||
|
||||
static u64 ch (u64 x, u64 y, u64 z) { return (x & y) ^ (~x & z); }
|
||||
|
||||
static u64 maj (u64 x, u64 y, u64 z) { return (x & y) ^ (x & z) ^ (y & z); }
|
||||
|
||||
static u64 big_sigma0 (u64 x) { return rot (x, 28) ^ rot (x, 34) ^ rot (x, 39); }
|
||||
|
||||
static u64 big_sigma1 (u64 x) { return rot (x, 14) ^ rot (x, 18) ^ rot (x, 41); }
|
||||
|
||||
static u64 lit_sigma0 (u64 x) { return rot (x, 1) ^ rot (x, 8) ^ (x >> 7); }
|
||||
|
||||
static u64 lit_sigma1 (u64 x) { return rot (x, 19) ^ rot (x, 61) ^ (x >> 6); }
|
||||
|
||||
static const u64 K[80] = {
|
||||
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
|
||||
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
|
||||
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
|
||||
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
|
||||
0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
|
||||
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
|
||||
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
|
||||
0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
|
||||
0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
|
||||
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
|
||||
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
|
||||
0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
|
||||
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
|
||||
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
|
||||
0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
|
||||
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
|
||||
0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
|
||||
0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
|
||||
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
|
||||
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817};
|
||||
|
||||
static void sha512_compress (crypto_sha512_ctx *ctx) {
|
||||
u64 a = ctx->hash[0];
|
||||
u64 b = ctx->hash[1];
|
||||
u64 c = ctx->hash[2];
|
||||
u64 d = ctx->hash[3];
|
||||
u64 e = ctx->hash[4];
|
||||
u64 f = ctx->hash[5];
|
||||
u64 g = ctx->hash[6];
|
||||
u64 h = ctx->hash[7];
|
||||
|
||||
FOR (j, 0, 16) {
|
||||
u64 in = K[j] + ctx->input[j];
|
||||
u64 t1 = big_sigma1 (e) + ch (e, f, g) + h + in;
|
||||
u64 t2 = big_sigma0 (a) + maj (a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
}
|
||||
size_t i16 = 0;
|
||||
FOR (i, 1, 5) {
|
||||
i16 += 16;
|
||||
FOR (j, 0, 16) {
|
||||
ctx->input[j] += lit_sigma1 (ctx->input[(j - 2) & 15]);
|
||||
ctx->input[j] += lit_sigma0 (ctx->input[(j - 15) & 15]);
|
||||
ctx->input[j] += ctx->input[(j - 7) & 15];
|
||||
u64 in = K[i16 + j] + ctx->input[j];
|
||||
u64 t1 = big_sigma1 (e) + ch (e, f, g) + h + in;
|
||||
u64 t2 = big_sigma0 (a) + maj (a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->hash[0] += a;
|
||||
ctx->hash[1] += b;
|
||||
ctx->hash[2] += c;
|
||||
ctx->hash[3] += d;
|
||||
ctx->hash[4] += e;
|
||||
ctx->hash[5] += f;
|
||||
ctx->hash[6] += g;
|
||||
ctx->hash[7] += h;
|
||||
}
|
||||
|
||||
// Write 1 input byte
|
||||
static void sha512_set_input (crypto_sha512_ctx *ctx, u8 input) {
|
||||
size_t word = ctx->input_idx >> 3;
|
||||
size_t byte = ctx->input_idx & 7;
|
||||
ctx->input[word] |= (u64)input << (8 * (7 - byte));
|
||||
}
|
||||
|
||||
// Increment a 128-bit "word".
|
||||
static void sha512_incr (u64 x[2], u64 y) {
|
||||
x[1] += y;
|
||||
if (x[1] < y) {
|
||||
x[0]++;
|
||||
}
|
||||
}
|
||||
|
||||
void crypto_sha512_init (crypto_sha512_ctx *ctx) {
|
||||
ctx->hash[0] = 0x6a09e667f3bcc908;
|
||||
ctx->hash[1] = 0xbb67ae8584caa73b;
|
||||
ctx->hash[2] = 0x3c6ef372fe94f82b;
|
||||
ctx->hash[3] = 0xa54ff53a5f1d36f1;
|
||||
ctx->hash[4] = 0x510e527fade682d1;
|
||||
ctx->hash[5] = 0x9b05688c2b3e6c1f;
|
||||
ctx->hash[6] = 0x1f83d9abfb41bd6b;
|
||||
ctx->hash[7] = 0x5be0cd19137e2179;
|
||||
ctx->input_size[0] = 0;
|
||||
ctx->input_size[1] = 0;
|
||||
ctx->input_idx = 0;
|
||||
ZERO (ctx->input, 16);
|
||||
}
|
||||
|
||||
void crypto_sha512_update (crypto_sha512_ctx *ctx,
|
||||
const u8 *message, size_t message_size) {
|
||||
// Avoid undefined NULL pointer increments with empty messages
|
||||
if (message_size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Align ourselves with word boundaries
|
||||
if ((ctx->input_idx & 7) != 0) {
|
||||
size_t nb_bytes = MIN (align (ctx->input_idx, 8), message_size);
|
||||
FOR (i, 0, nb_bytes) {
|
||||
sha512_set_input (ctx, message[i]);
|
||||
ctx->input_idx++;
|
||||
}
|
||||
message += nb_bytes;
|
||||
message_size -= nb_bytes;
|
||||
}
|
||||
|
||||
// Align ourselves with block boundaries
|
||||
if ((ctx->input_idx & 127) != 0) {
|
||||
size_t nb_words = MIN (align (ctx->input_idx, 128), message_size) >> 3;
|
||||
load64_be_buf (ctx->input + (ctx->input_idx >> 3), message, nb_words);
|
||||
ctx->input_idx += nb_words << 3;
|
||||
message += nb_words << 3;
|
||||
message_size -= nb_words << 3;
|
||||
}
|
||||
|
||||
// Compress block if needed
|
||||
if (ctx->input_idx == 128) {
|
||||
sha512_incr (ctx->input_size, 1024); // size is in bits
|
||||
sha512_compress (ctx);
|
||||
ctx->input_idx = 0;
|
||||
ZERO (ctx->input, 16);
|
||||
}
|
||||
|
||||
// Process the message block by block
|
||||
FOR (i, 0, message_size >> 7) { // number of blocks
|
||||
load64_be_buf (ctx->input, message, 16);
|
||||
sha512_incr (ctx->input_size, 1024); // size is in bits
|
||||
sha512_compress (ctx);
|
||||
ctx->input_idx = 0;
|
||||
ZERO (ctx->input, 16);
|
||||
message += 128;
|
||||
}
|
||||
message_size &= 127;
|
||||
|
||||
if (message_size != 0) {
|
||||
// Remaining words
|
||||
size_t nb_words = message_size >> 3;
|
||||
load64_be_buf (ctx->input, message, nb_words);
|
||||
ctx->input_idx += nb_words << 3;
|
||||
message += nb_words << 3;
|
||||
message_size -= nb_words << 3;
|
||||
|
||||
// Remaining bytes
|
||||
FOR (i, 0, message_size) {
|
||||
sha512_set_input (ctx, message[i]);
|
||||
ctx->input_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void crypto_sha512_final (crypto_sha512_ctx *ctx, u8 hash[64]) {
|
||||
// Add padding bit
|
||||
if (ctx->input_idx == 0) {
|
||||
ZERO (ctx->input, 16);
|
||||
}
|
||||
sha512_set_input (ctx, 128);
|
||||
|
||||
// Update size
|
||||
sha512_incr (ctx->input_size, ctx->input_idx * 8);
|
||||
|
||||
// Compress penultimate block (if any)
|
||||
if (ctx->input_idx > 111) {
|
||||
sha512_compress (ctx);
|
||||
ZERO (ctx->input, 14);
|
||||
}
|
||||
// Compress last block
|
||||
ctx->input[14] = ctx->input_size[0];
|
||||
ctx->input[15] = ctx->input_size[1];
|
||||
sha512_compress (ctx);
|
||||
|
||||
// Copy hash to output (big endian)
|
||||
FOR (i, 0, 8) {
|
||||
store64_be (hash + i * 8, ctx->hash[i]);
|
||||
}
|
||||
|
||||
WIPE_CTX (ctx);
|
||||
}
|
||||
|
||||
void crypto_sha512 (u8 hash[64], const u8 *message, size_t message_size) {
|
||||
crypto_sha512_ctx ctx;
|
||||
crypto_sha512_init (&ctx);
|
||||
crypto_sha512_update (&ctx, message, message_size);
|
||||
crypto_sha512_final (&ctx, hash);
|
||||
}
|
||||
|
||||
////////////////////
|
||||
/// HMAC SHA 512 ///
|
||||
////////////////////
|
||||
void crypto_sha512_hmac_init (crypto_sha512_hmac_ctx *ctx,
|
||||
const u8 *key, size_t key_size) {
|
||||
// hash key if it is too long
|
||||
if (key_size > 128) {
|
||||
crypto_sha512 (ctx->key, key, key_size);
|
||||
key = ctx->key;
|
||||
key_size = 64;
|
||||
}
|
||||
// Compute inner key: padded key XOR 0x36
|
||||
FOR (i, 0, key_size) { ctx->key[i] = key[i] ^ 0x36; }
|
||||
FOR (i, key_size, 128) { ctx->key[i] = 0x36; }
|
||||
// Start computing inner hash
|
||||
crypto_sha512_init (&ctx->ctx);
|
||||
crypto_sha512_update (&ctx->ctx, ctx->key, 128);
|
||||
}
|
||||
|
||||
void crypto_sha512_hmac_update (crypto_sha512_hmac_ctx *ctx,
|
||||
const u8 *message, size_t message_size) {
|
||||
crypto_sha512_update (&ctx->ctx, message, message_size);
|
||||
}
|
||||
|
||||
void crypto_sha512_hmac_final (crypto_sha512_hmac_ctx *ctx, u8 hmac[64]) {
|
||||
// Finish computing inner hash
|
||||
crypto_sha512_final (&ctx->ctx, hmac);
|
||||
// Compute outer key: padded key XOR 0x5c
|
||||
FOR (i, 0, 128) {
|
||||
ctx->key[i] ^= 0x36 ^ 0x5c;
|
||||
}
|
||||
// Compute outer hash
|
||||
crypto_sha512_init (&ctx->ctx);
|
||||
crypto_sha512_update (&ctx->ctx, ctx->key, 128);
|
||||
crypto_sha512_update (&ctx->ctx, hmac, 64);
|
||||
crypto_sha512_final (&ctx->ctx, hmac); // outer hash
|
||||
WIPE_CTX (ctx);
|
||||
}
|
||||
|
||||
void crypto_sha512_hmac (u8 hmac[64], const u8 *key, size_t key_size,
|
||||
const u8 *message, size_t message_size) {
|
||||
crypto_sha512_hmac_ctx ctx;
|
||||
crypto_sha512_hmac_init (&ctx, key, key_size);
|
||||
crypto_sha512_hmac_update (&ctx, message, message_size);
|
||||
crypto_sha512_hmac_final (&ctx, hmac);
|
||||
}
|
||||
|
||||
////////////////////
|
||||
/// HKDF SHA 512 ///
|
||||
////////////////////
|
||||
void crypto_sha512_hkdf_expand (u8 *okm, size_t okm_size,
|
||||
const u8 *prk, size_t prk_size,
|
||||
const u8 *info, size_t info_size) {
|
||||
int not_first = 0;
|
||||
u8 ctr = 1;
|
||||
u8 blk[64];
|
||||
|
||||
while (okm_size > 0) {
|
||||
size_t out_size = MIN (okm_size, sizeof (blk));
|
||||
|
||||
crypto_sha512_hmac_ctx ctx;
|
||||
crypto_sha512_hmac_init (&ctx, prk, prk_size);
|
||||
if (not_first) {
|
||||
// For some reason HKDF uses some kind of CBC mode.
|
||||
// For some reason CTR mode alone wasn't enough.
|
||||
// Like what, they didn't trust HMAC in 2010? Really??
|
||||
crypto_sha512_hmac_update (&ctx, blk, sizeof (blk));
|
||||
}
|
||||
crypto_sha512_hmac_update (&ctx, info, info_size);
|
||||
crypto_sha512_hmac_update (&ctx, &ctr, 1);
|
||||
crypto_sha512_hmac_final (&ctx, blk);
|
||||
|
||||
COPY (okm, blk, out_size);
|
||||
|
||||
not_first = 1;
|
||||
okm += out_size;
|
||||
okm_size -= out_size;
|
||||
ctr++;
|
||||
}
|
||||
}
|
||||
|
||||
void crypto_sha512_hkdf (u8 *okm, size_t okm_size,
|
||||
const u8 *ikm, size_t ikm_size,
|
||||
const u8 *salt, size_t salt_size,
|
||||
const u8 *info, size_t info_size) {
|
||||
// Extract
|
||||
u8 prk[64];
|
||||
crypto_sha512_hmac (prk, salt, salt_size, ikm, ikm_size);
|
||||
|
||||
// Expand
|
||||
crypto_sha512_hkdf_expand (okm, okm_size, prk, sizeof (prk), info, info_size);
|
||||
}
|
||||
|
||||
///////////////
|
||||
/// Ed25519 ///
|
||||
///////////////
|
||||
void crypto_ed25519_key_pair (u8 secret_key[64], u8 public_key[32], u8 seed[32]) {
|
||||
u8 a[64];
|
||||
COPY (a, seed, 32); // a[ 0..31] = seed
|
||||
crypto_wipe (seed, 32);
|
||||
COPY (secret_key, a, 32); // secret key = seed
|
||||
crypto_sha512 (a, a, 32); // a[ 0..31] = scalar
|
||||
crypto_eddsa_trim_scalar (a, a); // a[ 0..31] = trimmed scalar
|
||||
crypto_eddsa_scalarbase (public_key, a); // public key = [trimmed scalar]B
|
||||
COPY (secret_key + 32, public_key, 32); // secret key includes public half
|
||||
WIPE_BUFFER (a);
|
||||
}
|
||||
|
||||
static void hash_reduce (u8 h[32],
|
||||
const u8 *a, size_t a_size,
|
||||
const u8 *b, size_t b_size,
|
||||
const u8 *c, size_t c_size,
|
||||
const u8 *d, size_t d_size) {
|
||||
u8 hash[64];
|
||||
crypto_sha512_ctx ctx;
|
||||
crypto_sha512_init (&ctx);
|
||||
crypto_sha512_update (&ctx, a, a_size);
|
||||
crypto_sha512_update (&ctx, b, b_size);
|
||||
crypto_sha512_update (&ctx, c, c_size);
|
||||
crypto_sha512_update (&ctx, d, d_size);
|
||||
crypto_sha512_final (&ctx, hash);
|
||||
crypto_eddsa_reduce (h, hash);
|
||||
}
|
||||
|
||||
static void ed25519_dom_sign (u8 signature[64], const u8 secret_key[32],
|
||||
const u8 *dom, size_t dom_size,
|
||||
const u8 *message, size_t message_size) {
|
||||
u8 a[64]; // secret scalar and prefix
|
||||
u8 r[32]; // secret deterministic "random" nonce
|
||||
u8 h[32]; // publically verifiable hash of the message (not wiped)
|
||||
u8 R[32]; // first half of the signature (allows overlapping inputs)
|
||||
const u8 *pk = secret_key + 32;
|
||||
|
||||
crypto_sha512 (a, secret_key, 32);
|
||||
crypto_eddsa_trim_scalar (a, a);
|
||||
hash_reduce (r, dom, dom_size, a + 32, 32, message, message_size, 0, 0);
|
||||
crypto_eddsa_scalarbase (R, r);
|
||||
hash_reduce (h, dom, dom_size, R, 32, pk, 32, message, message_size);
|
||||
COPY (signature, R, 32);
|
||||
crypto_eddsa_mul_add (signature + 32, h, a, r);
|
||||
|
||||
WIPE_BUFFER (a);
|
||||
WIPE_BUFFER (r);
|
||||
}
|
||||
// Meshcore-parity Ed25519 signing (non-standard, do NOT use outside Meshcore networks)
|
||||
static void ed25519_meshcore_sign(u8 signature[64],
|
||||
const u8 priv_seed[32], // secret seed (32 bytes)
|
||||
const u8 pub_key[32], // public key (32 bytes)
|
||||
const u8 *message, size_t message_size)
|
||||
{
|
||||
u8 a[64]; // secret scalar and prefix (same buffer as Monocypher)
|
||||
u8 r[32]; // nonce scalar
|
||||
u8 h[32]; // challenge scalar
|
||||
u8 R[32]; // encoded R
|
||||
|
||||
// 1. Derive scalar a (clamped) and prefix (discarded here, Meshcore doesn¡¯t use it)
|
||||
crypto_sha512(a, priv_seed, 32); // hash the seed
|
||||
crypto_eddsa_trim_scalar(a, a); // clamp scalar a
|
||||
|
||||
// 2. Derive nonce r = H(public_key || message) instead of H(prefix || message)
|
||||
hash_reduce(r, 0, 0, pub_key, 32, message, message_size, 0, 0);
|
||||
|
||||
// 3. R = r * basepoint
|
||||
crypto_eddsa_scalarbase(R, r);
|
||||
|
||||
// 4. h = H(R || public_key || message)
|
||||
hash_reduce(h, 0, 0, R, 32, pub_key, 32, message, message_size);
|
||||
|
||||
// 5. signature = R || (h*a + r)
|
||||
COPY(signature, R, 32);
|
||||
crypto_eddsa_mul_add(signature + 32, h, a, r);
|
||||
|
||||
// wipe secrets
|
||||
WIPE_BUFFER(a);
|
||||
WIPE_BUFFER(r);
|
||||
}
|
||||
|
||||
void crypto_ed25519_meshcore_sign(u8 signature[64],
|
||||
const u8 priv_seed[32],
|
||||
const u8 pub_key[32],
|
||||
const u8 *message, size_t message_size)
|
||||
{
|
||||
ed25519_meshcore_sign(signature, priv_seed, pub_key, message, message_size);
|
||||
}
|
||||
|
||||
|
||||
void crypto_ed25519_sign (u8 signature[64], const u8 secret_key[64],
|
||||
const u8 *message, size_t message_size) {
|
||||
ed25519_dom_sign (signature, secret_key, 0, 0, message, message_size);
|
||||
}
|
||||
|
||||
int crypto_ed25519_check (const u8 signature[64], const u8 public_key[32],
|
||||
const u8 *msg, size_t msg_size) {
|
||||
u8 h_ram[32];
|
||||
hash_reduce (h_ram, signature, 32, public_key, 32, msg, msg_size, 0, 0);
|
||||
return crypto_eddsa_check_equation (signature, public_key, h_ram);
|
||||
}
|
||||
|
||||
static const u8 domain[34] = "SigEd25519 no Ed25519 collisions\1";
|
||||
|
||||
void crypto_ed25519_ph_sign (uint8_t signature[64], const uint8_t secret_key[64],
|
||||
const uint8_t message_hash[64]) {
|
||||
ed25519_dom_sign (signature, secret_key, domain, sizeof (domain),
|
||||
message_hash, 64);
|
||||
}
|
||||
|
||||
int crypto_ed25519_ph_check (const uint8_t sig[64], const uint8_t pk[32],
|
||||
const uint8_t msg_hash[64]) {
|
||||
u8 h_ram[32];
|
||||
hash_reduce (h_ram, domain, sizeof (domain), sig, 32, pk, 32, msg_hash, 64);
|
||||
return crypto_eddsa_check_equation (sig, pk, h_ram);
|
||||
}
|
||||
|
||||
|
||||
#ifdef MONOCYPHER_CPP_NAMESPACE
|
||||
}
|
||||
#endif
|
||||
@@ -1,144 +0,0 @@
|
||||
// Monocypher version 4.0.2
|
||||
//
|
||||
// This file is dual-licensed. Choose whichever licence you want from
|
||||
// the two licences listed below.
|
||||
//
|
||||
// The first licence is a regular 2-clause BSD licence. The second licence
|
||||
// is the CC-0 from Creative Commons. It is intended to release Monocypher
|
||||
// to the public domain. The BSD licence serves as a fallback option.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2017-2019, Loup Vaillant
|
||||
// All rights reserved.
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Written in 2017-2019 by Loup Vaillant
|
||||
//
|
||||
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||
// and related neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
//
|
||||
// You should have received a copy of the CC0 Public Domain Dedication along
|
||||
// with this software. If not, see
|
||||
// <https://creativecommons.org/publicdomain/zero/1.0/>
|
||||
|
||||
#ifndef ED25519_H
|
||||
#define ED25519_H
|
||||
|
||||
#include "monocypher.h"
|
||||
|
||||
#ifdef MONOCYPHER_CPP_NAMESPACE
|
||||
namespace MONOCYPHER_CPP_NAMESPACE {
|
||||
#elif defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
////////////////////////
|
||||
/// Type definitions ///
|
||||
////////////////////////
|
||||
|
||||
// Do not rely on the size or content on any of those types,
|
||||
// they may change without notice.
|
||||
typedef struct {
|
||||
uint64_t hash[8];
|
||||
uint64_t input[16];
|
||||
uint64_t input_size[2];
|
||||
size_t input_idx;
|
||||
} crypto_sha512_ctx;
|
||||
|
||||
typedef struct {
|
||||
uint8_t key[128];
|
||||
crypto_sha512_ctx ctx;
|
||||
} crypto_sha512_hmac_ctx;
|
||||
|
||||
void crypto_ed25519_meshcore_sign (uint8_t signature[64],
|
||||
const uint8_t priv_seed[32],
|
||||
const uint8_t pub_key[32],
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// SHA 512
|
||||
// -------
|
||||
void crypto_sha512_init (crypto_sha512_ctx *ctx);
|
||||
void crypto_sha512_update (crypto_sha512_ctx *ctx,
|
||||
const uint8_t *message, size_t message_size);
|
||||
void crypto_sha512_final (crypto_sha512_ctx *ctx, uint8_t hash[64]);
|
||||
void crypto_sha512 (uint8_t hash[64],
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// SHA 512 HMAC
|
||||
// ------------
|
||||
void crypto_sha512_hmac_init (crypto_sha512_hmac_ctx *ctx,
|
||||
const uint8_t *key, size_t key_size);
|
||||
void crypto_sha512_hmac_update (crypto_sha512_hmac_ctx *ctx,
|
||||
const uint8_t *message, size_t message_size);
|
||||
void crypto_sha512_hmac_final (crypto_sha512_hmac_ctx *ctx, uint8_t hmac[64]);
|
||||
void crypto_sha512_hmac (uint8_t hmac[64],
|
||||
const uint8_t *key, size_t key_size,
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// SHA 512 HKDF
|
||||
// ------------
|
||||
void crypto_sha512_hkdf_expand (uint8_t *okm, size_t okm_size,
|
||||
const uint8_t *prk, size_t prk_size,
|
||||
const uint8_t *info, size_t info_size);
|
||||
void crypto_sha512_hkdf (uint8_t *okm, size_t okm_size,
|
||||
const uint8_t *ikm, size_t ikm_size,
|
||||
const uint8_t *salt, size_t salt_size,
|
||||
const uint8_t *info, size_t info_size);
|
||||
|
||||
// Ed25519
|
||||
// -------
|
||||
// Signatures (EdDSA with curve25519 + SHA-512)
|
||||
// --------------------------------------------
|
||||
void crypto_ed25519_key_pair (uint8_t secret_key[64],
|
||||
uint8_t public_key[32],
|
||||
uint8_t seed[32]);
|
||||
void crypto_ed25519_sign (uint8_t signature[64],
|
||||
const uint8_t secret_key[64],
|
||||
const uint8_t *message, size_t message_size);
|
||||
int crypto_ed25519_check (const uint8_t signature[64],
|
||||
const uint8_t public_key[32],
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// Pre-hash variants
|
||||
void crypto_ed25519_ph_sign (uint8_t signature[64],
|
||||
const uint8_t secret_key[64],
|
||||
const uint8_t message_hash[64]);
|
||||
int crypto_ed25519_ph_check (const uint8_t signature[64],
|
||||
const uint8_t public_key[32],
|
||||
const uint8_t message_hash[64]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ED25519_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,321 +0,0 @@
|
||||
// Monocypher version 4.0.2
|
||||
//
|
||||
// This file is dual-licensed. Choose whichever licence you want from
|
||||
// the two licences listed below.
|
||||
//
|
||||
// The first licence is a regular 2-clause BSD licence. The second licence
|
||||
// is the CC-0 from Creative Commons. It is intended to release Monocypher
|
||||
// to the public domain. The BSD licence serves as a fallback option.
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2017-2019, Loup Vaillant
|
||||
// All rights reserved.
|
||||
//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// Written in 2017-2019 by Loup Vaillant
|
||||
//
|
||||
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||
// and related neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
//
|
||||
// You should have received a copy of the CC0 Public Domain Dedication along
|
||||
// with this software. If not, see
|
||||
// <https://creativecommons.org/publicdomain/zero/1.0/>
|
||||
|
||||
#ifndef MONOCYPHER_H
|
||||
#define MONOCYPHER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef MONOCYPHER_CPP_NAMESPACE
|
||||
namespace MONOCYPHER_CPP_NAMESPACE {
|
||||
#elif defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Constant time comparisons
|
||||
// -------------------------
|
||||
|
||||
// Return 0 if a and b are equal, -1 otherwise
|
||||
int crypto_verify16(const uint8_t a[16], const uint8_t b[16]);
|
||||
int crypto_verify32(const uint8_t a[32], const uint8_t b[32]);
|
||||
int crypto_verify64(const uint8_t a[64], const uint8_t b[64]);
|
||||
|
||||
|
||||
// Erase sensitive data
|
||||
// --------------------
|
||||
void crypto_wipe(void *secret, size_t size);
|
||||
|
||||
|
||||
// Authenticated encryption
|
||||
// ------------------------
|
||||
void crypto_aead_lock(uint8_t *cipher_text,
|
||||
uint8_t mac [16],
|
||||
const uint8_t key [32],
|
||||
const uint8_t nonce[24],
|
||||
const uint8_t *ad, size_t ad_size,
|
||||
const uint8_t *plain_text, size_t text_size);
|
||||
int crypto_aead_unlock(uint8_t *plain_text,
|
||||
const uint8_t mac [16],
|
||||
const uint8_t key [32],
|
||||
const uint8_t nonce[24],
|
||||
const uint8_t *ad, size_t ad_size,
|
||||
const uint8_t *cipher_text, size_t text_size);
|
||||
|
||||
// Authenticated stream
|
||||
// --------------------
|
||||
typedef struct {
|
||||
uint64_t counter;
|
||||
uint8_t key[32];
|
||||
uint8_t nonce[8];
|
||||
} crypto_aead_ctx;
|
||||
|
||||
void crypto_aead_init_x(crypto_aead_ctx *ctx,
|
||||
const uint8_t key[32], const uint8_t nonce[24]);
|
||||
void crypto_aead_init_djb(crypto_aead_ctx *ctx,
|
||||
const uint8_t key[32], const uint8_t nonce[8]);
|
||||
void crypto_aead_init_ietf(crypto_aead_ctx *ctx,
|
||||
const uint8_t key[32], const uint8_t nonce[12]);
|
||||
|
||||
void crypto_aead_write(crypto_aead_ctx *ctx,
|
||||
uint8_t *cipher_text,
|
||||
uint8_t mac[16],
|
||||
const uint8_t *ad , size_t ad_size,
|
||||
const uint8_t *plain_text, size_t text_size);
|
||||
int crypto_aead_read(crypto_aead_ctx *ctx,
|
||||
uint8_t *plain_text,
|
||||
const uint8_t mac[16],
|
||||
const uint8_t *ad , size_t ad_size,
|
||||
const uint8_t *cipher_text, size_t text_size);
|
||||
|
||||
|
||||
// General purpose hash (BLAKE2b)
|
||||
// ------------------------------
|
||||
|
||||
// Direct interface
|
||||
void crypto_blake2b(uint8_t *hash, size_t hash_size,
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
void crypto_blake2b_keyed(uint8_t *hash, size_t hash_size,
|
||||
const uint8_t *key, size_t key_size,
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// Incremental interface
|
||||
typedef struct {
|
||||
// Do not rely on the size or contents of this type,
|
||||
// for they may change without notice.
|
||||
uint64_t hash[8];
|
||||
uint64_t input_offset[2];
|
||||
uint64_t input[16];
|
||||
size_t input_idx;
|
||||
size_t hash_size;
|
||||
} crypto_blake2b_ctx;
|
||||
|
||||
void crypto_blake2b_init(crypto_blake2b_ctx *ctx, size_t hash_size);
|
||||
void crypto_blake2b_keyed_init(crypto_blake2b_ctx *ctx, size_t hash_size,
|
||||
const uint8_t *key, size_t key_size);
|
||||
void crypto_blake2b_update(crypto_blake2b_ctx *ctx,
|
||||
const uint8_t *message, size_t message_size);
|
||||
void crypto_blake2b_final(crypto_blake2b_ctx *ctx, uint8_t *hash);
|
||||
|
||||
|
||||
// Password key derivation (Argon2)
|
||||
// --------------------------------
|
||||
#define CRYPTO_ARGON2_D 0
|
||||
#define CRYPTO_ARGON2_I 1
|
||||
#define CRYPTO_ARGON2_ID 2
|
||||
|
||||
typedef struct {
|
||||
uint32_t algorithm; // Argon2d, Argon2i, Argon2id
|
||||
uint32_t nb_blocks; // memory hardness, >= 8 * nb_lanes
|
||||
uint32_t nb_passes; // CPU hardness, >= 1 (>= 3 recommended for Argon2i)
|
||||
uint32_t nb_lanes; // parallelism level (single threaded anyway)
|
||||
} crypto_argon2_config;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *pass;
|
||||
const uint8_t *salt;
|
||||
uint32_t pass_size;
|
||||
uint32_t salt_size; // 16 bytes recommended
|
||||
} crypto_argon2_inputs;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t *key; // may be NULL if no key
|
||||
const uint8_t *ad; // may be NULL if no additional data
|
||||
uint32_t key_size; // 0 if no key (32 bytes recommended otherwise)
|
||||
uint32_t ad_size; // 0 if no additional data
|
||||
} crypto_argon2_extras;
|
||||
|
||||
extern const crypto_argon2_extras crypto_argon2_no_extras;
|
||||
|
||||
void crypto_argon2(uint8_t *hash, uint32_t hash_size, void *work_area,
|
||||
crypto_argon2_config config,
|
||||
crypto_argon2_inputs inputs,
|
||||
crypto_argon2_extras extras);
|
||||
|
||||
|
||||
// Key exchange (X-25519)
|
||||
// ----------------------
|
||||
|
||||
// Shared secrets are not quite random.
|
||||
// Hash them to derive an actual shared key.
|
||||
void crypto_x25519_public_key(uint8_t public_key[32],
|
||||
const uint8_t secret_key[32]);
|
||||
void crypto_x25519(uint8_t raw_shared_secret[32],
|
||||
const uint8_t your_secret_key [32],
|
||||
const uint8_t their_public_key [32]);
|
||||
|
||||
// Conversion to EdDSA
|
||||
void crypto_x25519_to_eddsa(uint8_t eddsa[32], const uint8_t x25519[32]);
|
||||
|
||||
// scalar "division"
|
||||
// Used for OPRF. Be aware that exponential blinding is less secure
|
||||
// than Diffie-Hellman key exchange.
|
||||
void crypto_x25519_inverse(uint8_t blind_salt [32],
|
||||
const uint8_t private_key[32],
|
||||
const uint8_t curve_point[32]);
|
||||
|
||||
// "Dirty" versions of x25519_public_key().
|
||||
// Use with crypto_elligator_rev().
|
||||
// Leaks 3 bits of the private key.
|
||||
void crypto_x25519_dirty_small(uint8_t pk[32], const uint8_t sk[32]);
|
||||
void crypto_x25519_dirty_fast (uint8_t pk[32], const uint8_t sk[32]);
|
||||
|
||||
|
||||
// Signatures
|
||||
// ----------
|
||||
|
||||
// EdDSA with curve25519 + BLAKE2b
|
||||
void crypto_eddsa_key_pair(uint8_t secret_key[64],
|
||||
uint8_t public_key[32],
|
||||
uint8_t seed[32]);
|
||||
void crypto_eddsa_sign(uint8_t signature [64],
|
||||
const uint8_t secret_key[64],
|
||||
const uint8_t *message, size_t message_size);
|
||||
int crypto_eddsa_check(const uint8_t signature [64],
|
||||
const uint8_t public_key[32],
|
||||
const uint8_t *message, size_t message_size);
|
||||
|
||||
// Conversion to X25519
|
||||
void crypto_eddsa_to_x25519(uint8_t x25519[32], const uint8_t eddsa[32]);
|
||||
|
||||
// EdDSA building blocks
|
||||
void crypto_eddsa_trim_scalar(uint8_t out[32], const uint8_t in[32]);
|
||||
void crypto_eddsa_reduce(uint8_t reduced[32], const uint8_t expanded[64]);
|
||||
void crypto_eddsa_mul_add(uint8_t r[32],
|
||||
const uint8_t a[32],
|
||||
const uint8_t b[32],
|
||||
const uint8_t c[32]);
|
||||
void crypto_eddsa_scalarbase(uint8_t point[32], const uint8_t scalar[32]);
|
||||
int crypto_eddsa_check_equation(const uint8_t signature[64],
|
||||
const uint8_t public_key[32],
|
||||
const uint8_t h_ram[32]);
|
||||
|
||||
|
||||
// Chacha20
|
||||
// --------
|
||||
|
||||
// Specialised hash.
|
||||
// Used to hash X25519 shared secrets.
|
||||
void crypto_chacha20_h(uint8_t out[32],
|
||||
const uint8_t key[32],
|
||||
const uint8_t in [16]);
|
||||
|
||||
// Unauthenticated stream cipher.
|
||||
// Don't forget to add authentication.
|
||||
uint64_t crypto_chacha20_djb(uint8_t *cipher_text,
|
||||
const uint8_t *plain_text,
|
||||
size_t text_size,
|
||||
const uint8_t key[32],
|
||||
const uint8_t nonce[8],
|
||||
uint64_t ctr);
|
||||
uint32_t crypto_chacha20_ietf(uint8_t *cipher_text,
|
||||
const uint8_t *plain_text,
|
||||
size_t text_size,
|
||||
const uint8_t key[32],
|
||||
const uint8_t nonce[12],
|
||||
uint32_t ctr);
|
||||
uint64_t crypto_chacha20_x(uint8_t *cipher_text,
|
||||
const uint8_t *plain_text,
|
||||
size_t text_size,
|
||||
const uint8_t key[32],
|
||||
const uint8_t nonce[24],
|
||||
uint64_t ctr);
|
||||
|
||||
|
||||
// Poly 1305
|
||||
// ---------
|
||||
|
||||
// This is a *one time* authenticator.
|
||||
// Disclosing the mac reveals the key.
|
||||
// See crypto_lock() on how to use it properly.
|
||||
|
||||
// Direct interface
|
||||
void crypto_poly1305(uint8_t mac[16],
|
||||
const uint8_t *message, size_t message_size,
|
||||
const uint8_t key[32]);
|
||||
|
||||
// Incremental interface
|
||||
typedef struct {
|
||||
// Do not rely on the size or contents of this type,
|
||||
// for they may change without notice.
|
||||
uint8_t c[16]; // chunk of the message
|
||||
size_t c_idx; // How many bytes are there in the chunk.
|
||||
uint32_t r [4]; // constant multiplier (from the secret key)
|
||||
uint32_t pad[4]; // random number added at the end (from the secret key)
|
||||
uint32_t h [5]; // accumulated hash
|
||||
} crypto_poly1305_ctx;
|
||||
|
||||
void crypto_poly1305_init (crypto_poly1305_ctx *ctx, const uint8_t key[32]);
|
||||
void crypto_poly1305_update(crypto_poly1305_ctx *ctx,
|
||||
const uint8_t *message, size_t message_size);
|
||||
void crypto_poly1305_final (crypto_poly1305_ctx *ctx, uint8_t mac[16]);
|
||||
|
||||
|
||||
// Elligator 2
|
||||
// -----------
|
||||
|
||||
// Elligator mappings proper
|
||||
void crypto_elligator_map(uint8_t curve [32], const uint8_t hidden[32]);
|
||||
int crypto_elligator_rev(uint8_t hidden[32], const uint8_t curve [32],
|
||||
uint8_t tweak);
|
||||
|
||||
// Easy to use key pair generation
|
||||
void crypto_elligator_key_pair(uint8_t hidden[32], uint8_t secret_key[32],
|
||||
uint8_t seed[32]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // MONOCYPHER_H
|
||||
@@ -48,6 +48,43 @@ uint8_t Is_Leap_Year (u16 year) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t month_from_str(const char *m) {
|
||||
static const char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||
for (uint8_t i = 0; i < 12; i++) {
|
||||
if (m[0] == months[i*3] &&
|
||||
m[1] == months[i*3 + 1] &&
|
||||
m[2] == months[i*3 + 2])
|
||||
return i + 1; // 1¨C12
|
||||
}
|
||||
return 0; // should never happen
|
||||
}
|
||||
|
||||
void RTC_Set_From_BuildTime(void) {
|
||||
const char *date = __DATE__;
|
||||
const char *time = __TIME__;
|
||||
|
||||
uint16_t year =
|
||||
(date[7] - '0') * 1000 +
|
||||
(date[8] - '0') * 100 +
|
||||
(date[9] - '0') * 10 +
|
||||
(date[10] - '0');
|
||||
|
||||
uint8_t month = month_from_str(date);
|
||||
uint8_t day =
|
||||
(date[4] == ' ' ? 0 : (date[4] - '0') * 10) +
|
||||
(date[5] - '0');
|
||||
|
||||
uint8_t hour =
|
||||
(time[0] - '0') * 10 + (time[1] - '0');
|
||||
uint8_t min =
|
||||
(time[3] - '0') * 10 + (time[4] - '0');
|
||||
uint8_t sec =
|
||||
(time[6] - '0') * 10 + (time[7] - '0');
|
||||
|
||||
RTC_Set(year, month, day, hour, min, sec);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Set
|
||||
*
|
||||
@@ -244,7 +281,8 @@ uint8_t RTC_Init (void) {
|
||||
RTC_EnterConfigMode();
|
||||
RTC_SetPrescaler (32767);
|
||||
RTC_WaitForLastTask();
|
||||
RTC_Set (2025, 9, 7, 11, 33, 30); /* Setup Time */
|
||||
//RTC_Set (2025, 9, 7, 11, 33, 30); /* Setup Time */
|
||||
RTC_Set_From_BuildTime();
|
||||
RTC_ExitConfigMode();
|
||||
BKP_WriteBackupRegister (BKP_DR1, 0XA1A1);
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ void RTC_NVIC_Config (void);
|
||||
*/
|
||||
uint8_t Is_Leap_Year (u16 year);
|
||||
|
||||
void RTC_Set_From_BuildTime(void);
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Set
|
||||
*
|
||||
|
||||
154
User/main.c
154
User/main.c
@@ -16,6 +16,10 @@
|
||||
*/
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "meshcore/meshframing.h"
|
||||
#include "meshcore/packets/advert.h"
|
||||
#include "meshcore/packets/encrypted.h"
|
||||
#include "meshcore/packets/group.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "meshcore/packetstructs.h"
|
||||
@@ -23,9 +27,9 @@
|
||||
#include "util/log.h"
|
||||
#include "string.h"
|
||||
#include "meshcore/meshcore.h"
|
||||
#include "lib/base64.h"
|
||||
#include "lib/config.h"
|
||||
#include "lib/rtc/rtc.h"
|
||||
#include "lib/ed25519/ed_25519.h"
|
||||
|
||||
#define TAG "MeshCore"
|
||||
|
||||
@@ -33,9 +37,6 @@
|
||||
#define TASK1_TASK_PRIO 5
|
||||
#define TASK1_STK_SIZE 2048
|
||||
|
||||
uint8_t publKey[32] = {0x73, 0x78, 0x46, 0x76, 0x87, 0x3c, 0x9f, 0xeb, 0x00, 0x95, 0x05, 0xba, 0xdd, 0x3a, 0x4b, 0x33, 0xc8, 0xf5, 0x88, 0xa3, 0x8f, 0xaa, 0x30, 0x85, 0x3b, 0x91, 0xe6, 0xde, 0x97, 0x8c, 0xf1, 0xb2};
|
||||
uint8_t privKey[32] = {0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20, 0x8a, 0x27, 0xca, 0x33, 0x85, 0xa5, 0x3b, 0x7d, 0x88, 0xce, 0x92, 0x23, 0xc4, 0x40, 0xc3, 0xac};
|
||||
|
||||
/* Global Variable */
|
||||
TaskHandle_t Task1Task_Handler;
|
||||
TaskHandle_t Task2Task_Handler;
|
||||
@@ -54,17 +55,56 @@ uint8_t bufIn[256];
|
||||
|
||||
void task2_task (void *pvParameters) {
|
||||
RTC_Init();
|
||||
while (1) {
|
||||
// char tempBuf[180];
|
||||
// vTaskDelay (pdMS_TO_TICKS (10000));
|
||||
// snprintf (tempBuf, 180, "BRN RISCV: SySTick is %d", xTaskGetTickCount());
|
||||
// makeSendGroupMessage (tempBuf, 1);
|
||||
vTaskDelay (pdMS_TO_TICKS (10000));
|
||||
memcpy (persistent.privkey, privKey, 32);
|
||||
memcpy (persistent.pubkey, publKey, 32);
|
||||
strcpy (persistent.nodeName, "BRN RiscV");
|
||||
//ed25519_create_keypair (persistent.pubkey, persistent.privkey, "vFt0FRugSOeqnkshImMCVfgHM5vBxz4");
|
||||
ed25519_create_keypair (persistent.pubkey, persistent.privkey, "vFt0FRugSOeqnkshImMCVfgHM5vBxz3");
|
||||
// persistent.nodeType = NODE_TYPE_CHAT_NODE;
|
||||
persistent.nodeType = NODE_TYPE_REPEATER;
|
||||
memset (persistent.password, 0, sizeof (persistent.password));
|
||||
strcpy (persistent.password, "hesielko");
|
||||
strcpy (persistent.nodeName, "BRN RiscVpeater");
|
||||
|
||||
const uint8_t aesKeysDefault[AESKeyCount][17] = {
|
||||
{0x11, 0x8b, 0x33, 0x87, 0xe9, 0xc5,
|
||||
0xcd, 0xea, 0x6a, 0xc9, 0xe5, 0xed,
|
||||
0xba, 0xa1, 0x15, 0xcd, 0x72},
|
||||
|
||||
{0x0a, 0x44, 0x81, 0xda, 0x0e, 0x4e,
|
||||
0x03, 0xc4, 0x9e, 0x84, 0x77, 0x25,
|
||||
0xd8, 0x3a, 0x93, 0xbf, 0x80}
|
||||
};
|
||||
|
||||
memcpy (persistent.aesKeys, aesKeysDefault, sizeof (persistent.aesKeys));
|
||||
|
||||
sendAdvert();
|
||||
vTaskDelay (pdMS_TO_TICKS (20000));
|
||||
|
||||
char x;
|
||||
while (1) {
|
||||
if (USART_GetFlagStatus (USART1, USART_FLAG_RXNE) == SET) {
|
||||
x = USART_ReceiveData (USART1);
|
||||
if (x == 'M') {
|
||||
printf ("Sending message\n");
|
||||
char tempBuf[180];
|
||||
snprintf (tempBuf, 180, "SySTick is %d", xTaskGetTickCount());
|
||||
makeSendGroupMessage (tempBuf, 1);
|
||||
}
|
||||
if (x == 'A') {
|
||||
printf ("Sending advert\n");
|
||||
sendAdvert();
|
||||
}
|
||||
if (x == 'N') {
|
||||
printNodeDB();
|
||||
}
|
||||
if (x == 'D') {
|
||||
PlainTextMessagePayload plainTextMessage;
|
||||
plainTextMessage.timestamp = RTC_GetCounter();
|
||||
plainTextMessage.textType = 0;
|
||||
plainTextMessage.attempt = 0;
|
||||
snprintf(plainTextMessage.message, sizeof(plainTextMessage.message), "Sending message at SySTick is %d", xTaskGetTickCount());
|
||||
printf ("Sending a direct message to the first node\n");
|
||||
sendEncryptedTextMessage(&(persistent.contacts[0]), &plainTextMessage);
|
||||
}
|
||||
}
|
||||
vTaskDelay (pdMS_TO_TICKS (2000));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +116,7 @@ void task1_task (void *pvParameters) {
|
||||
ESP_LOGW (TAG, "LoraInit");
|
||||
LoRaInit();
|
||||
int8_t txPowerInDbm = 20;
|
||||
uint32_t frequencyInHz = 869618000;
|
||||
uint32_t frequencyInHz = 869554000;
|
||||
|
||||
ESP_LOGW (TAG, "Enable TCXO");
|
||||
float tcxoVoltage = 2.2; // ebyte
|
||||
@@ -114,59 +154,9 @@ void task1_task (void *pvParameters) {
|
||||
int8_t rssi, snr;
|
||||
GetPacketStatus (&rssi, &snr);
|
||||
ESP_LOGI (TAG, "rssi=%d[dBm] snr=%d[dB]", rssi, snr);
|
||||
|
||||
FrameStruct frame = decodeFrame (bufIn, rxLen);
|
||||
|
||||
printFrameHeader (frame);
|
||||
|
||||
unsigned char checkSumBuf[10];
|
||||
AdvertisementPayload advert;
|
||||
GroupTextMessage msg;
|
||||
|
||||
switch (frame.header & PAYLOAD_TYPE_MASK) {
|
||||
case PAYLOAD_TYPE_REQ:
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_RESPONSE:
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_TXT_MSG:
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_ACK:
|
||||
memset (checkSumBuf, 0, sizeof (checkSumBuf));
|
||||
base64_encode (frame.payload, 4, checkSumBuf);
|
||||
printf ("Checksum: %s\n", checkSumBuf);
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_ADVERT:
|
||||
advert = decodeAdvertisement (frame);
|
||||
printAdvertisement (advert);
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_GRP_TXT:
|
||||
msg = decodeGroupMessage (frame);
|
||||
printGroupMessage (msg);
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_GRP_DATA:
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_ANON_REQ:
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_PATH:
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_TRACE:
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_MULTIPART:
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_RAW_CUSTOM:
|
||||
break;
|
||||
}
|
||||
FrameStruct frame;
|
||||
frame = decodeFrame (bufIn, rxLen);
|
||||
processFrame (frame);
|
||||
}
|
||||
|
||||
int lost = GetPacketLost();
|
||||
@@ -200,7 +190,33 @@ int main (void) {
|
||||
NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2);
|
||||
SystemCoreClockUpdate();
|
||||
Delay_Init();
|
||||
USART_Printf_Init (115200);
|
||||
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
USART_InitTypeDef USART_InitStructure;
|
||||
|
||||
RCC_APB2PeriphClockCmd (RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
GPIO_Init (GPIOA, &GPIO_InitStructure);
|
||||
|
||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
|
||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||
GPIO_Init (GPIOA, &GPIO_InitStructure);
|
||||
|
||||
USART_InitStructure.USART_BaudRate = 115200;
|
||||
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
|
||||
USART_InitStructure.USART_StopBits = USART_StopBits_1;
|
||||
USART_InitStructure.USART_Parity = USART_Parity_No;
|
||||
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
|
||||
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
|
||||
|
||||
USART_Init (USART1, &USART_InitStructure);
|
||||
USART_Cmd (USART1, ENABLE);
|
||||
|
||||
|
||||
printf ("SystemClk:%d\r\n", SystemCoreClock);
|
||||
printf ("ChipID:%08x\r\n", DBGMCU_GetCHIPID());
|
||||
|
||||
@@ -1,547 +1,74 @@
|
||||
#include "meshcore.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "lib/monocypher/monocypher-ed25519.h"
|
||||
#include "lib/ed25519/ed_25519.h"
|
||||
#include "meshcore/packets/advert.h"
|
||||
#include "meshcore/packets/anonymous.h"
|
||||
#include "meshcore/packets/control.h"
|
||||
#include "meshcore/packets/encrypted.h"
|
||||
#include "meshcore/packets/group.h"
|
||||
#include "task.h"
|
||||
#include "lib/base64.h"
|
||||
#include "lib/cifra/aes.h"
|
||||
#include "lib/cifra/sha2.h"
|
||||
#include "lib/cifra/hmac.h"
|
||||
#include "lib/config.h"
|
||||
|
||||
#define AESKeyCount 8
|
||||
|
||||
const uint8_t aesKeys[AESKeyCount][17] = {
|
||||
{0x11, 0x8b, 0x33, 0x87, 0xe9, 0xc5,
|
||||
0xcd, 0xea, 0x6a, 0xc9, 0xe5, 0xed,
|
||||
0xba, 0xa1, 0x15, 0xcd, 0x72},
|
||||
|
||||
{0x0a, 0x44, 0x81, 0xda, 0x0e, 0x4e,
|
||||
0x03, 0xc4, 0x9e, 0x84, 0x77, 0x25,
|
||||
0xd8, 0x3a, 0x93, 0xbf, 0x80}
|
||||
};
|
||||
#include "meshframing.h"
|
||||
|
||||
#define TAG "MeshCore"
|
||||
|
||||
// requires at least a 256 byte data
|
||||
FrameStruct decodeFrame (unsigned char *data, unsigned char dataLen) {
|
||||
hexdump ("RxDump", data, dataLen);
|
||||
FrameStruct frame;
|
||||
memset (&frame, 0, sizeof (frame));
|
||||
unsigned char index = 0;
|
||||
frame.header = data[index++];
|
||||
if ((frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
|
||||
(frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
memcpy (frame.transportCodes, data + index, 4);
|
||||
index += 4;
|
||||
}
|
||||
frame.pathLen = data[index++];
|
||||
|
||||
memcpy (frame.path, data + index, frame.pathLen);
|
||||
index += frame.pathLen;
|
||||
frame.payloadLen = dataLen - index;
|
||||
memcpy (frame.payload, data + index, frame.payloadLen);
|
||||
|
||||
return frame;
|
||||
void processFrame (FrameStruct frame) {
|
||||
printFrameHeader (frame);
|
||||
if (frame.header & PAYLOAD_VERSION_3) { // more than the version 0
|
||||
ESP_LOGW (TAG, "Frame too new, got version %d instead of 0", (frame.header & PAYLOAD_VERSION_3) >> 6);
|
||||
}
|
||||
|
||||
int aes_encrypt_ecb (const uint8_t *key, const uint8_t *input, size_t ilen,
|
||||
uint8_t *output) {
|
||||
if (ilen % 16 != 0)
|
||||
return -1;
|
||||
|
||||
cf_aes_context ctx;
|
||||
cf_aes_init (&ctx, key, 16);
|
||||
|
||||
for (size_t i = 0; i < ilen; i += 16) {
|
||||
cf_aes_encrypt (&ctx, input + i, output + i);
|
||||
}
|
||||
|
||||
cf_aes_finish (&ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int aes_decrypt_ecb (const uint8_t *key, const uint8_t *input, size_t ilen,
|
||||
uint8_t *output) {
|
||||
if (ilen % 16 != 0)
|
||||
return -1;
|
||||
|
||||
cf_aes_context ctx;
|
||||
cf_aes_init (&ctx, key, 16);
|
||||
|
||||
for (size_t i = 0; i < ilen; i += 16) {
|
||||
cf_aes_decrypt (&ctx, input + i, output + i);
|
||||
}
|
||||
|
||||
|
||||
cf_aes_finish (&ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// HMAC-SHA256
|
||||
int hmac_sha256 (const uint8_t *key, size_t keylen,
|
||||
const uint8_t *input, size_t ilen,
|
||||
uint8_t *output) {
|
||||
cf_hmac_ctx ctx;
|
||||
cf_hmac_init (&ctx, &cf_sha256, key, keylen);
|
||||
cf_hmac_update (&ctx, input, ilen);
|
||||
cf_hmac_finish (&ctx, output);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Verify MAC + Decrypt
|
||||
#define KEY_SIZE 16 // AES-128
|
||||
|
||||
int encrypt_then_mac (const uint8_t *aes_key,
|
||||
const uint8_t *plaintext, size_t plen,
|
||||
uint8_t *output, size_t *olen) {
|
||||
if (plen == 0)
|
||||
return -1;
|
||||
|
||||
// ciphertext will go right after HMAC
|
||||
uint8_t *ciphertext = output + HMAC_SIZE;
|
||||
|
||||
// encrypt plaintext
|
||||
aes_encrypt_ecb (aes_key, plaintext, plen, ciphertext);
|
||||
|
||||
// compute HMAC over ciphertext
|
||||
uint8_t mac[32]; // full SHA-256
|
||||
hmac_sha256 (aes_key, KEY_SIZE, ciphertext, plen, mac);
|
||||
|
||||
// copy only HMAC_SIZE bytes of MAC
|
||||
memcpy (output, mac, HMAC_SIZE);
|
||||
|
||||
// return total length = HMAC + ciphertext
|
||||
*olen = HMAC_SIZE + plen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mac_then_decrypt (const uint8_t *aes_key, const uint8_t *input, size_t ilen,
|
||||
uint8_t *plaintext) {
|
||||
if (ilen <= HMAC_SIZE)
|
||||
return -1;
|
||||
|
||||
const uint8_t *mac = input;
|
||||
const uint8_t *ciphertext = input + HMAC_SIZE;
|
||||
size_t clen = ilen - HMAC_SIZE;
|
||||
|
||||
uint8_t calc_mac[32]; // full SHA-256
|
||||
hmac_sha256 (aes_key, KEY_SIZE, ciphertext, clen, calc_mac);
|
||||
|
||||
if (memcmp (mac, calc_mac, HMAC_SIZE) != 0)
|
||||
return -2;
|
||||
|
||||
return aes_decrypt_ecb (aes_key, ciphertext, clen, plaintext);
|
||||
}
|
||||
|
||||
void hexdump (const char *label, const uint8_t *data, size_t len) {
|
||||
if (label)
|
||||
printf ("%s (len=%zu):\n", label, len);
|
||||
|
||||
for (size_t i = 0; i < len; i += 16) {
|
||||
printf ("%04zx ", i); // offset
|
||||
for (size_t j = 0; j < 16; j++) {
|
||||
if (i + j < len)
|
||||
printf ("%02X ", data[i + j]);
|
||||
else
|
||||
printf (" "); // pad spacing
|
||||
}
|
||||
printf (" ");
|
||||
for (size_t j = 0; j < 16 && i + j < len; j++) {
|
||||
uint8_t c = data[i + j];
|
||||
printf ("%c", isprint (c) ? c : '.');
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// EncryptedPayloadStruct decodeEncryptedPayload(FrameStruct frame) {
|
||||
// EncryptedPayloadStruct enc;
|
||||
// memset(&enc, 0, sizeof(enc));
|
||||
// if ((frame.header & PAYLOAD_TYPE_MASK) != PAYLOAD_TYPE_GRP_TXT) {
|
||||
// return enc;
|
||||
// }
|
||||
// unsigned char index = 0;
|
||||
// enc.destinationHash = frame.payload[index++];
|
||||
// enc.sourceHash = frame.payload[index++];
|
||||
|
||||
|
||||
// index = 0;
|
||||
|
||||
// memcpy(&msg.timestamp, tmp + index, 4);
|
||||
// index += 4;
|
||||
// msg.flags = tmp[index++];
|
||||
|
||||
// memcpy(msg.text, tmp + index, plaintextLen - index);
|
||||
// return end;
|
||||
// }
|
||||
|
||||
GroupTextMessage decodeGroupMessage (FrameStruct frame) {
|
||||
GroupTextMessage msg;
|
||||
memset (&msg, 0, sizeof (msg));
|
||||
if ((frame.header & PAYLOAD_TYPE_MASK) != PAYLOAD_TYPE_GRP_TXT) {
|
||||
ESP_LOGW (TAG, "Not a group text");
|
||||
return msg;
|
||||
}
|
||||
unsigned char index = 0;
|
||||
msg.channelHash = frame.payload[index++];
|
||||
unsigned char tmp[184];
|
||||
|
||||
|
||||
unsigned char decrypted = 0;
|
||||
for (unsigned char i = 0; i < AESKeyCount; i++) {
|
||||
|
||||
if (msg.channelHash != aesKeys[i][0]) {
|
||||
ESP_LOGW (TAG, "Hash %d does not equal %d", aesKeys[i][0], msg.channelHash);
|
||||
continue;
|
||||
}
|
||||
|
||||
ESP_LOGW (TAG, "Hash does equal %d", msg.channelHash);
|
||||
|
||||
if (mac_then_decrypt (aesKeys[i] + 1, frame.payload + index, frame.payloadLen - index, tmp) != 0) {
|
||||
ESP_LOGW (TAG, "HMAC failed on grouphash key %d not matching %d", aesKeys[i][0], msg.channelHash);
|
||||
continue;
|
||||
}
|
||||
hexdump ("RxDumpDec", tmp, frame.payloadLen - index);
|
||||
decrypted = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (!decrypted) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
unsigned char plaintextLen = frame.payloadLen - index;
|
||||
index = 0;
|
||||
|
||||
ESP_LOGI (TAG, "Starting memcpy");
|
||||
vTaskDelay (pdMS_TO_TICKS (10));
|
||||
memcpy (&msg.timestamp, tmp + index, 4);
|
||||
index += 4;
|
||||
msg.flags = tmp[index++];
|
||||
|
||||
memcpy (msg.text, tmp + index, plaintextLen - index);
|
||||
return msg;
|
||||
}
|
||||
|
||||
void printGroupMessage (GroupTextMessage msg) {
|
||||
printf ("Message with channel hash %d, flags %d: %s\n", msg.channelHash,
|
||||
msg.flags, msg.text);
|
||||
}
|
||||
|
||||
AdvertisementPayload decodeAdvertisement (FrameStruct frame) {
|
||||
unsigned char checkSumBuf[10];
|
||||
AdvertisementPayload advert;
|
||||
memset (&advert, 0, sizeof (advert));
|
||||
GroupTextMessage msg;
|
||||
|
||||
if ((frame.header & PAYLOAD_TYPE_MASK) != PAYLOAD_TYPE_ADVERT) {
|
||||
return advert;
|
||||
}
|
||||
unsigned char frameType = frame.header & PAYLOAD_TYPE_MASK;
|
||||
|
||||
unsigned char index = 0;
|
||||
|
||||
memcpy (advert.pubKey, frame.payload + index, 32);
|
||||
index += 32;
|
||||
if (frameType == PAYLOAD_TYPE_ANON_REQ) {
|
||||
decodeAnonReq (frame);
|
||||
|
||||
memcpy (&advert.timestamp, frame.payload + index, 4);
|
||||
index += 4;
|
||||
} else if (frameType == PAYLOAD_TYPE_PATH || frameType == PAYLOAD_TYPE_REQ || frameType == PAYLOAD_TYPE_RESPONSE || frameType == PAYLOAD_TYPE_TXT_MSG) {
|
||||
printf (" Typexd: 0x%02X\n", frameType);
|
||||
EncryptedPayloadStruct enc = decodeEncryptedPayload (frame);
|
||||
printf (" Typexdd: 0x%02X\n", enc.type);
|
||||
if (enc.payloadLen > 0) {
|
||||
parseEncryptedPayload (enc);
|
||||
}
|
||||
} else if (frameType == PAYLOAD_TYPE_ACK) {
|
||||
memset (checkSumBuf, 0, sizeof (checkSumBuf));
|
||||
base64_encode (frame.payload, 4, checkSumBuf);
|
||||
printf ("Checksum: %s\n", checkSumBuf);
|
||||
} else if (frameType == PAYLOAD_TYPE_ACK) {
|
||||
uint32_t checkSum = frame.payload[index++];
|
||||
checkSum |= frame.payload[index++] << 8;
|
||||
checkSum |= frame.payload[index++] << 16;
|
||||
checkSum |= frame.payload[index++] << 24;
|
||||
|
||||
memcpy (advert.signature, frame.payload + index, 64);
|
||||
index += 64;
|
||||
} else if (frameType == PAYLOAD_TYPE_ADVERT) {
|
||||
advert = decodeAdvertisement (frame);
|
||||
printAdvertisement (advert);
|
||||
} else if (frameType == PAYLOAD_TYPE_GRP_TXT || frameType == PAYLOAD_TYPE_GRP_DATA) {
|
||||
msg = decodeGroupMessage (frame);
|
||||
printGroupMessage (msg);
|
||||
} else if (frameType == PAYLOAD_TYPE_TRACE) {
|
||||
|
||||
advert.dataFlags = frame.payload[index++];
|
||||
} else if (frameType == PAYLOAD_TYPE_MULTIPART) {
|
||||
|
||||
if (advert.dataFlags & ADVERTISEMENT_FLAG_HAS_LOCATION) {
|
||||
memcpy (&advert.latitude, frame.payload + index, 4);
|
||||
index += 4;
|
||||
memcpy (&advert.longitude, frame.payload + index, 4);
|
||||
index += 4;
|
||||
} else if (frameType == PAYLOAD_TYPE_CONTROL) {
|
||||
decodeControlFrame (frame);
|
||||
|
||||
} else if (frameType == PAYLOAD_TYPE_RAW_CUSTOM) {
|
||||
// not implemented
|
||||
}
|
||||
|
||||
if (advert.dataFlags & ADVERTISEMENT_FLAG_RFU1) {
|
||||
memcpy (&advert.rfu1, frame.payload + index, 2);
|
||||
index += 2;
|
||||
}
|
||||
if (advert.dataFlags & ADVERTISEMENT_FLAG_RFU2) {
|
||||
memcpy (&advert.rfu2, frame.payload + index, 2);
|
||||
index += 2;
|
||||
}
|
||||
memcpy (advert.nodeName, frame.payload + index, frame.payloadLen - index);
|
||||
advert.nodeName[frame.payloadLen - index] = 0;
|
||||
|
||||
return advert;
|
||||
}
|
||||
|
||||
void printAdvertisement (AdvertisementPayload advert) {
|
||||
unsigned char keyBuf[50];
|
||||
unsigned char sigBuf[90];
|
||||
memset (keyBuf, 0, sizeof (keyBuf));
|
||||
memset (sigBuf, 0, sizeof (sigBuf));
|
||||
base64_encode (advert.pubKey, 32, keyBuf);
|
||||
base64_encode (advert.signature, 64, sigBuf);
|
||||
|
||||
printf ("%s on %ld with type %s on %s location %ld %ld, public key %s and "
|
||||
"signature %s\n",
|
||||
advert.dataFlags & ADVERTISEMENT_FLAG_HAS_NAME ? advert.nodeName
|
||||
: "nameless node",
|
||||
advert.timestamp,
|
||||
(advert.dataFlags & 0x07) == 0x04
|
||||
? "sensor"
|
||||
: ((advert.dataFlags & 0x07) == 0x03
|
||||
? "room server"
|
||||
: ((advert.dataFlags & 0x07) == 0x02 ? "repeater"
|
||||
: "chat node")),
|
||||
advert.dataFlags & 0x80 ? "known" : "unknown", advert.latitude,
|
||||
advert.longitude, keyBuf, sigBuf);
|
||||
}
|
||||
|
||||
void printFrameHeader (FrameStruct frame) {
|
||||
switch (frame.header & ROUTE_TYPE_MASK) {
|
||||
case ROUTE_TYPE_TRANSPORT_FLOOD:
|
||||
printf ("transport flood");
|
||||
break;
|
||||
|
||||
case ROUTE_TYPE_FLOOD:
|
||||
printf ("flood");
|
||||
break;
|
||||
|
||||
case ROUTE_TYPE_DIRECT:
|
||||
printf ("direct");
|
||||
break;
|
||||
|
||||
case ROUTE_TYPE_TRANSPORT_DIRECT:
|
||||
printf ("transport direct");
|
||||
break;
|
||||
}
|
||||
|
||||
printf (", payload type is ");
|
||||
|
||||
switch (frame.header & PAYLOAD_TYPE_MASK) {
|
||||
case PAYLOAD_TYPE_REQ:
|
||||
printf ("request");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_RESPONSE:
|
||||
printf ("response");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_TXT_MSG:
|
||||
printf ("text message");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_ACK:
|
||||
printf ("acknowledgement");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_ADVERT:
|
||||
printf ("advert");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_GRP_TXT:
|
||||
printf ("group text");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_GRP_DATA:
|
||||
printf ("group data");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_ANON_REQ:
|
||||
printf ("anon request");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_PATH:
|
||||
printf ("path");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_TRACE:
|
||||
printf ("trace");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_MULTIPART:
|
||||
printf ("multipart");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_RAW_CUSTOM:
|
||||
printf ("raw");
|
||||
break;
|
||||
}
|
||||
char version[2];
|
||||
version[0] = (frame.header >> 6) + '0';
|
||||
version[1] = 0;
|
||||
|
||||
printf (", payload version is %s ", version);
|
||||
|
||||
if ((frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
|
||||
(frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
printf ("Transport codes: %d %d\n", *((uint16_t *)frame.transportCodes),
|
||||
*((uint16_t *)&(frame.transportCodes[2])));
|
||||
}
|
||||
printf ("Path is %d nodes long", frame.pathLen);
|
||||
|
||||
for (uint8_t pathIndex = 0; pathIndex < frame.pathLen; pathIndex++) {
|
||||
printf ("node %d - %02X, ", pathIndex, frame.path[pathIndex]);
|
||||
}
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
void sendFrame (FrameStruct frame) {
|
||||
uint8_t txBuf[256];
|
||||
size_t offset = 0;
|
||||
|
||||
txBuf[offset++] = frame.header;
|
||||
|
||||
if ((frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
|
||||
(frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
memcpy (txBuf + offset, frame.transportCodes, 4);
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
if (frame.pathLen > 64) {
|
||||
frame.pathLen = 64;
|
||||
}
|
||||
|
||||
txBuf[offset++] = frame.pathLen;
|
||||
|
||||
memcpy (txBuf + offset, frame.path, frame.pathLen);
|
||||
offset += frame.pathLen;
|
||||
|
||||
uint16_t maxPayloadLen = 256 - offset;
|
||||
|
||||
uint16_t payloadLen = frame.payloadLen > maxPayloadLen ? maxPayloadLen : frame.payloadLen;
|
||||
|
||||
memcpy (txBuf + offset, frame.payload, payloadLen);
|
||||
offset += payloadLen;
|
||||
|
||||
hexdump ("TxDump", txBuf, offset);
|
||||
LoRaSend (txBuf, offset, SX126x_TXMODE_SYNC);
|
||||
}
|
||||
|
||||
void sendGroupMessage (GroupTextMessage msg) {
|
||||
|
||||
msg.channelHash = aesKeys[msg.keyIndex][0];
|
||||
|
||||
msg.flags = 0;
|
||||
msg.timestamp = RTC_GetCounter();
|
||||
|
||||
FrameStruct frame;
|
||||
frame.header = ROUTE_TYPE_FLOOD | PAYLOAD_TYPE_GRP_TXT | PAYLOAD_VERSION_0;
|
||||
frame.pathLen = 0;
|
||||
size_t offset = 0;
|
||||
memset (frame.payload, 0, sizeof (frame.payload));
|
||||
frame.payload[offset++] = msg.channelHash;
|
||||
|
||||
uint8_t cipherBuf[176];
|
||||
size_t offset2 = 0;
|
||||
memcpy (cipherBuf, (const void *)&(msg.timestamp), 4);
|
||||
offset2 += 4;
|
||||
cipherBuf[offset2++] = msg.flags;
|
||||
size_t textSize = offset2 + strlen ((const char *)msg.text);
|
||||
if (textSize > 175) {
|
||||
textSize = 175;
|
||||
}
|
||||
memcpy (cipherBuf + offset2, msg.text, textSize);
|
||||
offset2 += textSize;
|
||||
|
||||
offset2 = (((offset2 / 16) + 1) * 16);
|
||||
|
||||
size_t olen = 0;
|
||||
hexdump ("TxDumpDec", cipherBuf, offset2);
|
||||
encrypt_then_mac (&(aesKeys[msg.keyIndex][1]), cipherBuf, offset2, &(frame.payload[offset]), &olen);
|
||||
|
||||
frame.payloadLen = olen + 1;
|
||||
|
||||
sendFrame (frame);
|
||||
return;
|
||||
}
|
||||
|
||||
void makeSendGroupMessage (char *txt, uint8_t keyIndex) {
|
||||
GroupTextMessage msg;
|
||||
strcpy ((char *)msg.text, txt);
|
||||
msg.keyIndex = keyIndex;
|
||||
sendGroupMessage (msg);
|
||||
return;
|
||||
}
|
||||
|
||||
void sendAdvert() {
|
||||
AdvertisementPayload ad;
|
||||
memcpy (ad.pubKey, persistent.pubkey, sizeof (ad.pubKey));
|
||||
ad.dataFlags = ADVERTISEMENT_FLAG_IS_CHAT_NODE | ADVERTISEMENT_FLAG_HAS_NAME;
|
||||
strcpy (ad.nodeName, persistent.nodeName);
|
||||
ad.timestamp = RTC_GetCounter();
|
||||
|
||||
// 1. Build app_data exactly like AdvertDataBuilder::encodeTo
|
||||
uint8_t app_data[40];
|
||||
size_t app_len = 0;
|
||||
|
||||
app_data[app_len++] = ad.dataFlags;
|
||||
|
||||
if (ad.dataFlags & ADVERTISEMENT_FLAG_HAS_LOCATION) {
|
||||
memcpy (app_data + app_len, &ad.latitude, sizeof (ad.latitude));
|
||||
app_len += sizeof (ad.latitude);
|
||||
memcpy (app_data + app_len, &ad.longitude, sizeof (ad.longitude));
|
||||
app_len += sizeof (ad.longitude);
|
||||
}
|
||||
|
||||
if (ad.dataFlags & ADVERTISEMENT_FLAG_RFU1) {
|
||||
memcpy (app_data + app_len, &ad.rfu1, sizeof (ad.rfu1));
|
||||
app_len += sizeof (ad.rfu1);
|
||||
}
|
||||
|
||||
if (ad.dataFlags & ADVERTISEMENT_FLAG_RFU2) {
|
||||
memcpy (app_data + app_len, &ad.rfu2, sizeof (ad.rfu2));
|
||||
app_len += sizeof (ad.rfu2);
|
||||
}
|
||||
|
||||
if (ad.dataFlags & ADVERTISEMENT_FLAG_HAS_NAME) {
|
||||
size_t nodenameLen = strlen (ad.nodeName);
|
||||
memcpy (app_data + app_len, ad.nodeName, nodenameLen);
|
||||
app_len += nodenameLen;
|
||||
}
|
||||
|
||||
// 2. Reserve frame and build payload header
|
||||
FrameStruct frame;
|
||||
frame.header = ROUTE_TYPE_FLOOD | PAYLOAD_TYPE_ADVERT | PAYLOAD_VERSION_0;
|
||||
|
||||
size_t offset = 0;
|
||||
memcpy (frame.payload + offset, ad.pubKey, sizeof (ad.pubKey));
|
||||
offset += sizeof (ad.pubKey);
|
||||
|
||||
memcpy (frame.payload + offset, &ad.timestamp, sizeof (ad.timestamp));
|
||||
offset += sizeof (ad.timestamp);
|
||||
|
||||
// reserve signature space
|
||||
uint8_t *signature_pos = frame.payload + offset;
|
||||
offset += 64;
|
||||
|
||||
// append app_data after signature
|
||||
memcpy (frame.payload + offset, app_data, app_len);
|
||||
offset += app_len;
|
||||
|
||||
// 3. Sign pubKey + timestamp + app_data
|
||||
uint8_t message[76];
|
||||
size_t msg_len = 0;
|
||||
memcpy (message + msg_len, ad.pubKey, sizeof (ad.pubKey));
|
||||
msg_len += sizeof (ad.pubKey);
|
||||
memcpy (message + msg_len, &ad.timestamp, sizeof (ad.timestamp));
|
||||
msg_len += sizeof (ad.timestamp);
|
||||
memcpy (message + msg_len, app_data, app_len);
|
||||
msg_len += app_len;
|
||||
|
||||
crypto_ed25519_meshcore_sign (signature_pos, persistent.privkey, persistent.pubkey, message, msg_len);
|
||||
|
||||
hexdump ("Complete advert", frame.payload, offset);
|
||||
|
||||
hexdump ("Public key", ad.pubKey, 32);
|
||||
|
||||
hexdump ("Signature", signature_pos, 64);
|
||||
|
||||
hexdump ("Timestamp", &ad.timestamp, 4);
|
||||
|
||||
hexdump ("NodeName", ad.nodeName, 20);
|
||||
|
||||
hexdump ("Appdata", app_data, app_len);
|
||||
|
||||
// 5. Set payload length and send
|
||||
frame.payloadLen = offset;
|
||||
frame.pathLen = 0;
|
||||
sendFrame (frame);
|
||||
retransmitFrame (frame);
|
||||
}
|
||||
|
||||
@@ -7,55 +7,10 @@
|
||||
#include "lib/cifra/aes.h"
|
||||
#include "lib/cifra/sha2.h"
|
||||
#include "lib/cifra/hmac.h"
|
||||
#include "lib/base64.h"
|
||||
#include "util/log.h"
|
||||
#include <ctype.h>
|
||||
#include "stdio.h"
|
||||
|
||||
// requires at least a 256 byte data
|
||||
FrameStruct decodeFrame (unsigned char *data, unsigned char dataLen);
|
||||
|
||||
#define KEY_SIZE 16 // 128-bit AES
|
||||
#define HMAC_SIZE 2 // SHA256 output size
|
||||
|
||||
int aes_encrypt_ecb (const uint8_t *key, const uint8_t *input, size_t ilen,
|
||||
uint8_t *output);
|
||||
|
||||
// AES-ECB decrypt (same as Arduino's aes.decryptBlock)
|
||||
int aes_decrypt_ecb (const uint8_t *key, const uint8_t *input, size_t ilen,
|
||||
uint8_t *output);
|
||||
|
||||
// HMAC-SHA256
|
||||
int hmac_sha256 (const uint8_t *key, size_t keylen, const uint8_t *input,
|
||||
size_t ilen, uint8_t *output);
|
||||
|
||||
// Verify MAC + Decrypt
|
||||
int mac_then_decrypt (const uint8_t *aes_key, const uint8_t *input, size_t ilen,
|
||||
uint8_t *plaintext);
|
||||
|
||||
void hexdump (const char *label, const uint8_t *data, size_t len);
|
||||
|
||||
#define AESKeyCount 8
|
||||
|
||||
// EncryptedPayloadStruct decodeEncryptedPayload(FrameStruct frame);
|
||||
|
||||
GroupTextMessage decodeGroupMessage (FrameStruct frame);
|
||||
|
||||
void printGroupMessage (GroupTextMessage msg);
|
||||
|
||||
AdvertisementPayload decodeAdvertisement (FrameStruct frame);
|
||||
|
||||
void printAdvertisement (AdvertisementPayload advert);
|
||||
|
||||
void printFrameHeader (FrameStruct frame);
|
||||
|
||||
#define AESKeyCount 8
|
||||
|
||||
extern const uint8_t aesKeys[AESKeyCount][17];
|
||||
|
||||
void sendFrame (FrameStruct frame);
|
||||
void sendGroupMessage (GroupTextMessage msg);
|
||||
void makeSendGroupMessage (char *txt, uint8_t keyIndex);
|
||||
void sendAdvert();
|
||||
void processFrame (FrameStruct frame);
|
||||
|
||||
#endif
|
||||
214
User/meshcore/meshframing.c
Normal file
214
User/meshcore/meshframing.c
Normal file
@@ -0,0 +1,214 @@
|
||||
#include "meshframing.h"
|
||||
#include "lib/config.h"
|
||||
#include "string.h"
|
||||
#include "stdio.h"
|
||||
#include "sx1262.h"
|
||||
#include "util/hexdump.h"
|
||||
|
||||
FrameStruct decodeFrame (unsigned char *data, unsigned char dataLen) {
|
||||
hexdump ("RxDump", data, dataLen);
|
||||
FrameStruct frame;
|
||||
memset (&frame, 0, sizeof (frame));
|
||||
unsigned char index = 0;
|
||||
frame.header = data[index++];
|
||||
if ((frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
|
||||
(frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
memcpy (frame.transportCodes, data + index, 4);
|
||||
index += 4;
|
||||
}
|
||||
frame.path.pathLen = data[index++];
|
||||
|
||||
memcpy (frame.path.path, data + index, frame.path.pathLen);
|
||||
index += frame.path.pathLen;
|
||||
frame.payloadLen = dataLen - index;
|
||||
memcpy (frame.payload, data + index, frame.payloadLen);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
void printFrameHeader (FrameStruct frame) {
|
||||
switch (frame.header & ROUTE_TYPE_MASK) {
|
||||
case ROUTE_TYPE_TRANSPORT_FLOOD:
|
||||
printf ("transport flood");
|
||||
break;
|
||||
|
||||
case ROUTE_TYPE_FLOOD:
|
||||
printf ("flood");
|
||||
break;
|
||||
|
||||
case ROUTE_TYPE_DIRECT:
|
||||
printf ("direct");
|
||||
break;
|
||||
|
||||
case ROUTE_TYPE_TRANSPORT_DIRECT:
|
||||
printf ("transport direct");
|
||||
break;
|
||||
}
|
||||
|
||||
printf (", payload type is ");
|
||||
|
||||
switch (frame.header & PAYLOAD_TYPE_MASK) {
|
||||
case PAYLOAD_TYPE_REQ:
|
||||
printf ("request");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_RESPONSE:
|
||||
printf ("response");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_TXT_MSG:
|
||||
printf ("text message");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_ACK:
|
||||
printf ("acknowledgement");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_ADVERT:
|
||||
printf ("advert");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_GRP_TXT:
|
||||
printf ("group text");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_GRP_DATA:
|
||||
printf ("group data");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_ANON_REQ:
|
||||
printf ("anon request");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_PATH:
|
||||
printf ("path");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_TRACE:
|
||||
printf ("trace");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_MULTIPART:
|
||||
printf ("multipart");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_CONTROL:
|
||||
printf ("control");
|
||||
break;
|
||||
|
||||
case PAYLOAD_TYPE_RAW_CUSTOM:
|
||||
printf ("raw");
|
||||
break;
|
||||
}
|
||||
char version[2];
|
||||
version[0] = (frame.header >> 6) + '0';
|
||||
version[1] = 0;
|
||||
|
||||
printf (", payload version is %s ", version);
|
||||
|
||||
if ((frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
|
||||
(frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
printf ("Transport codes: %d %d\n", *((uint16_t *)frame.transportCodes),
|
||||
*((uint16_t *)&(frame.transportCodes[2])));
|
||||
}
|
||||
printf ("Path is %d nodes long", frame.path.pathLen);
|
||||
|
||||
for (uint8_t pathIndex = 0; pathIndex < frame.path.pathLen; pathIndex++) {
|
||||
printf ("node %d - %02X, ", pathIndex, frame.path.path[pathIndex]);
|
||||
}
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
void sendFrame (FrameStruct frame) {
|
||||
uint8_t txBuf[256];
|
||||
size_t offset = 0;
|
||||
|
||||
txBuf[offset++] = frame.header;
|
||||
|
||||
if ((frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_DIRECT ||
|
||||
(frame.header & ROUTE_TYPE_MASK) == ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
memcpy (txBuf + offset, frame.transportCodes, 4);
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
if (frame.path.pathLen > 64) {
|
||||
frame.path.pathLen = 64;
|
||||
}
|
||||
|
||||
txBuf[offset++] = frame.path.pathLen;
|
||||
|
||||
memcpy (txBuf + offset, frame.path.path, frame.path.pathLen);
|
||||
offset += frame.path.pathLen;
|
||||
|
||||
uint16_t maxPayloadLen = 256 - offset;
|
||||
|
||||
uint16_t payloadLen = frame.payloadLen > maxPayloadLen ? maxPayloadLen : frame.payloadLen;
|
||||
|
||||
memcpy (txBuf + offset, frame.payload, payloadLen);
|
||||
offset += payloadLen;
|
||||
|
||||
hexdump ("TxDump", txBuf, offset);
|
||||
LoRaSend (txBuf, offset, SX126x_TXMODE_SYNC);
|
||||
}
|
||||
|
||||
void retransmitFrame (FrameStruct frame) {
|
||||
if (frame.header & ROUTE_TYPE_FLOOD || frame.header & ROUTE_TYPE_TRANSPORT_FLOOD) {
|
||||
if (frame.header != DONT_RETRANSMIT_HEADER && frame.path.pathLen + 1 < MAX_FLOOD_TTL) {
|
||||
frame.path.path[frame.path.pathLen++] = persistent.pubkey[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (frame.header & ROUTE_TYPE_DIRECT || frame.header & ROUTE_TYPE_TRANSPORT_DIRECT) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Verify MAC + Decrypt
|
||||
|
||||
int encrypt_then_mac (const uint8_t *aes_key, const uint8_t keySize, const uint8_t *plaintext, size_t plen, uint8_t *output, size_t *olen) {
|
||||
if (plen == 0)
|
||||
return -1;
|
||||
|
||||
size_t padded_len = ((plen + 15) / 16) * 16;
|
||||
|
||||
// prepare padded buffer
|
||||
uint8_t padded[padded_len];
|
||||
memset(padded, 0, padded_len); // zero padding
|
||||
memcpy(padded, plaintext, plen); // copy plaintext
|
||||
|
||||
// ciphertext will go right after HMAC
|
||||
uint8_t *ciphertext = output + HMAC_SIZE;
|
||||
|
||||
// encrypt plaintext
|
||||
aes_encrypt_ecb (aes_key, 16, padded, padded_len, ciphertext);
|
||||
|
||||
// compute HMAC over ciphertext
|
||||
uint8_t mac[32]; // full SHA-256
|
||||
hmac_sha256 (aes_key, keySize, ciphertext, padded_len, mac);
|
||||
|
||||
// copy only HMAC_SIZE bytes of MAC
|
||||
memcpy (output, mac, HMAC_SIZE);
|
||||
|
||||
// return total length = HMAC + ciphertext
|
||||
*olen = HMAC_SIZE + padded_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mac_then_decrypt (const uint8_t *aes_key, const uint8_t keySize, const uint8_t *input, size_t ilen, uint8_t *plaintext) {
|
||||
if (ilen <= HMAC_SIZE)
|
||||
return -1;
|
||||
|
||||
const uint8_t *mac = input;
|
||||
const uint8_t *ciphertext = input + HMAC_SIZE;
|
||||
size_t clen = ilen - HMAC_SIZE;
|
||||
|
||||
if (clen % 16 != 0) return -2; // must be multiple of block size
|
||||
|
||||
uint8_t calc_mac[32]; // full SHA-256
|
||||
hmac_sha256 (aes_key, keySize, ciphertext, clen, calc_mac);
|
||||
|
||||
if (memcmp (mac, calc_mac, HMAC_SIZE) != 0)
|
||||
return -2;
|
||||
|
||||
return aes_decrypt_ecb (aes_key, 16, ciphertext, clen, plaintext);
|
||||
}
|
||||
29
User/meshcore/meshframing.h
Normal file
29
User/meshcore/meshframing.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef MESHCORE_FRAME_HEADER
|
||||
#define MESHCORE_FRAME_HEADER
|
||||
|
||||
#include "stddef.h"
|
||||
#include "stdint.h"
|
||||
#include "lib/cifra/aes.h"
|
||||
#include "lib/cifra/hmac.h"
|
||||
#include "packetstructs.h"
|
||||
|
||||
|
||||
#define KEY_SIZE 16 // 128-bit AES
|
||||
#define HMAC_SIZE 2 // meshcore size
|
||||
#define MAX_FLOOD_TTL 64
|
||||
|
||||
FrameStruct decodeFrame (unsigned char *data, unsigned char dataLen);
|
||||
|
||||
void printFrameHeader (FrameStruct frame) ;
|
||||
|
||||
void sendFrame (FrameStruct frame);
|
||||
|
||||
void retransmitFrame (FrameStruct frame) ;
|
||||
|
||||
// Verify MAC + Decrypt
|
||||
|
||||
int encrypt_then_mac (const uint8_t *aes_key, const uint8_t keySize, const uint8_t *plaintext, size_t plen, uint8_t *output, size_t *olen);
|
||||
|
||||
int mac_then_decrypt (const uint8_t *aes_key, const uint8_t keySize, const uint8_t *input, size_t ilen, uint8_t *plaintext);
|
||||
|
||||
#endif
|
||||
42
User/meshcore/packets/ack.c
Normal file
42
User/meshcore/packets/ack.c
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "ack.h"
|
||||
#include "lib/cifra/sha2.h"
|
||||
#include "lib/config.h"
|
||||
#include "meshcore/meshframing.h"
|
||||
#include <string.h>
|
||||
|
||||
#define TAG "Ack"
|
||||
|
||||
void sendDiscreteAck (uint8_t *data, const uint8_t len, uint8_t *senderPubKey) {
|
||||
FrameStruct frame;
|
||||
memset (&frame, 0, sizeof (frame));
|
||||
|
||||
// 1. Header
|
||||
frame.header =
|
||||
ROUTE_TYPE_FLOOD | // currently flood
|
||||
PAYLOAD_TYPE_ACK |
|
||||
PAYLOAD_VERSION_0;
|
||||
|
||||
// Buffer for the digest
|
||||
uint8_t hash[CF_SHA256_HASHSZ];
|
||||
|
||||
// Context
|
||||
cf_sha256_context ctx;
|
||||
|
||||
// 1. Initialize
|
||||
cf_sha256_init (&ctx);
|
||||
|
||||
// 2. Feed in your data
|
||||
cf_sha256_update (&ctx, data, len);
|
||||
|
||||
cf_sha256_update (&ctx, senderPubKey, sizeof (persistent.pubkey));
|
||||
|
||||
// 3. Compute digest
|
||||
cf_sha256_digest (&ctx, hash);
|
||||
|
||||
memcpy (frame.payload, hash, 4);
|
||||
// 5. Finalize
|
||||
frame.payloadLen = 4;
|
||||
|
||||
|
||||
sendFrame (frame);
|
||||
}
|
||||
8
User/meshcore/packets/ack.h
Normal file
8
User/meshcore/packets/ack.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef ACK_HEADER
|
||||
#define ACK_HEADER
|
||||
|
||||
#include "meshcore/packetstructs.h"
|
||||
|
||||
void sendDiscreteAck (uint8_t *data, const uint8_t len, uint8_t *senderPubKey);
|
||||
|
||||
#endif
|
||||
192
User/meshcore/packets/advert.c
Normal file
192
User/meshcore/packets/advert.c
Normal file
@@ -0,0 +1,192 @@
|
||||
#include "ch32v30x_rtc.h"
|
||||
#include "lib/config.h"
|
||||
#include "lib/ed25519/ed_25519.h"
|
||||
#include "meshcore/meshframing.h"
|
||||
#include "meshcore/packetstructs.h"
|
||||
#include <string.h>
|
||||
#include "advert.h"
|
||||
#include "util/hexdump.h"
|
||||
#include "lib/base64.h"
|
||||
|
||||
#define TAG "Advert"
|
||||
|
||||
void sendAdvert() {
|
||||
AdvertisementPayload ad;
|
||||
memcpy (ad.pubKey, persistent.pubkey, sizeof (ad.pubKey));
|
||||
ad.dataFlags = ADVERTISEMENT_FLAG_HAS_NAME;
|
||||
if (persistent.nodeType == NODE_TYPE_CHAT_NODE) {
|
||||
ad.dataFlags |= ADVERTISEMENT_FLAG_IS_CHAT_NODE;
|
||||
} else if (persistent.nodeType == NODE_TYPE_REPEATER) {
|
||||
ad.dataFlags |= ADVERTISEMENT_FLAG_IS_REAPEATER;
|
||||
} else if (persistent.nodeType == NODE_TYPE_ROOM_SERVER) {
|
||||
ad.dataFlags |= ADVERTISEMENT_FLAG_IS_ROOM_SERVER;
|
||||
} else if (persistent.nodeType == NODE_TYPE_SENSOR) {
|
||||
ad.dataFlags |= ADVERTISEMENT_FLAG_IS_SENSOR;
|
||||
}
|
||||
strcpy (ad.nodeName, persistent.nodeName);
|
||||
ad.timestamp = RTC_GetCounter();
|
||||
|
||||
uint8_t app_data[40];
|
||||
size_t app_len = 0;
|
||||
|
||||
app_data[app_len++] = ad.dataFlags;
|
||||
|
||||
if (ad.dataFlags & ADVERTISEMENT_FLAG_HAS_LOCATION) {
|
||||
memcpy (app_data + app_len, &ad.latitude, sizeof (ad.latitude));
|
||||
app_len += sizeof (ad.latitude);
|
||||
memcpy (app_data + app_len, &ad.longitude, sizeof (ad.longitude));
|
||||
app_len += sizeof (ad.longitude);
|
||||
}
|
||||
|
||||
if (ad.dataFlags & ADVERTISEMENT_FLAG_RFU1) {
|
||||
memcpy (app_data + app_len, &ad.rfu1, sizeof (ad.rfu1));
|
||||
app_len += sizeof (ad.rfu1);
|
||||
}
|
||||
|
||||
if (ad.dataFlags & ADVERTISEMENT_FLAG_RFU2) {
|
||||
memcpy (app_data + app_len, &ad.rfu2, sizeof (ad.rfu2));
|
||||
app_len += sizeof (ad.rfu2);
|
||||
}
|
||||
|
||||
if (ad.dataFlags & ADVERTISEMENT_FLAG_HAS_NAME) {
|
||||
size_t nodenameLen = strlen (ad.nodeName);
|
||||
memcpy (app_data + app_len, ad.nodeName, nodenameLen);
|
||||
app_len += nodenameLen;
|
||||
}
|
||||
|
||||
// 2. Reserve frame and build payload header
|
||||
FrameStruct frame;
|
||||
frame.header = ROUTE_TYPE_FLOOD | PAYLOAD_TYPE_ADVERT | PAYLOAD_VERSION_0;
|
||||
|
||||
size_t offset = 0;
|
||||
memcpy (frame.payload + offset, ad.pubKey, sizeof (ad.pubKey));
|
||||
offset += sizeof (ad.pubKey);
|
||||
|
||||
memcpy (frame.payload + offset, &ad.timestamp, sizeof (ad.timestamp));
|
||||
offset += sizeof (ad.timestamp);
|
||||
|
||||
// reserve signature space
|
||||
uint8_t *signature_pos = frame.payload + offset;
|
||||
offset += 64;
|
||||
|
||||
// append app_data after signature
|
||||
memcpy (frame.payload + offset, app_data, app_len);
|
||||
offset += app_len;
|
||||
|
||||
// 3. Sign pubKey + timestamp + app_data
|
||||
uint8_t message[76];
|
||||
size_t msg_len = 0;
|
||||
memcpy (message + msg_len, ad.pubKey, sizeof (ad.pubKey));
|
||||
msg_len += sizeof (ad.pubKey);
|
||||
memcpy (message + msg_len, &ad.timestamp, sizeof (ad.timestamp));
|
||||
msg_len += sizeof (ad.timestamp);
|
||||
memcpy (message + msg_len, app_data, app_len);
|
||||
msg_len += app_len;
|
||||
|
||||
ed25519_sign (signature_pos, message, msg_len, persistent.pubkey, persistent.privkey);
|
||||
|
||||
hexdump ("Complete advert", frame.payload, offset);
|
||||
|
||||
hexdump ("Public key", ad.pubKey, 32);
|
||||
|
||||
hexdump ("Signature", signature_pos, 64);
|
||||
|
||||
printf ("Timestamp is %d\n", ad.timestamp);
|
||||
|
||||
printf ("NodeName %s\n", ad.nodeName);
|
||||
|
||||
hexdump ("Appdata", app_data, app_len);
|
||||
|
||||
// 5. Set payload length and send
|
||||
frame.payloadLen = offset;
|
||||
frame.path.pathLen = 0;
|
||||
sendFrame (frame);
|
||||
}
|
||||
|
||||
AdvertisementPayload decodeAdvertisement (FrameStruct frame) {
|
||||
AdvertisementPayload advert;
|
||||
memset (&advert, 0, sizeof (advert));
|
||||
|
||||
if ((frame.header & PAYLOAD_TYPE_MASK) != PAYLOAD_TYPE_ADVERT) {
|
||||
return advert;
|
||||
}
|
||||
|
||||
unsigned char index = 0;
|
||||
|
||||
memcpy (advert.pubKey, frame.payload + index, 32);
|
||||
index += 32;
|
||||
|
||||
memcpy (&advert.timestamp, frame.payload + index, 4);
|
||||
index += 4;
|
||||
|
||||
memcpy (advert.signature, frame.payload + index, 64);
|
||||
index += 64;
|
||||
|
||||
advert.dataFlags = frame.payload[index++];
|
||||
|
||||
if (advert.dataFlags & ADVERTISEMENT_FLAG_HAS_LOCATION) {
|
||||
memcpy (&advert.latitude, frame.payload + index, 4);
|
||||
index += 4;
|
||||
memcpy (&advert.longitude, frame.payload + index, 4);
|
||||
index += 4;
|
||||
}
|
||||
|
||||
if (advert.dataFlags & ADVERTISEMENT_FLAG_RFU1) {
|
||||
memcpy (&advert.rfu1, frame.payload + index, 2);
|
||||
index += 2;
|
||||
}
|
||||
if (advert.dataFlags & ADVERTISEMENT_FLAG_RFU2) {
|
||||
memcpy (&advert.rfu2, frame.payload + index, 2);
|
||||
index += 2;
|
||||
}
|
||||
unsigned char nameLen = frame.payloadLen - index;
|
||||
if (nameLen > 32) {
|
||||
nameLen = 32;
|
||||
}
|
||||
memcpy (advert.nodeName, frame.payload + index, nameLen);
|
||||
advert.nodeName[frame.payloadLen - index] = 0;
|
||||
|
||||
|
||||
NodeEntry *node = getNode (advert.pubKey[0]);
|
||||
|
||||
if (node == NULL) {
|
||||
node = getNextNode();
|
||||
memset (node, 0, sizeof (NodeEntry));
|
||||
}
|
||||
|
||||
memcpy (node->name, advert.nodeName, sizeof (node->name));
|
||||
memcpy (node->pubKey, advert.pubKey, sizeof (node->pubKey));
|
||||
ed25519_key_exchange ((unsigned char *)node->secret, advert.pubKey, persistent.privkey);
|
||||
node->gps_latitude = advert.latitude;
|
||||
node->gps_longitude = advert.longitude;
|
||||
// ADD PATH
|
||||
node->type = advert.dataFlags & 0x0F;
|
||||
node->last_seen_lt = RTC_GetCounter();
|
||||
node->last_seen_rt = advert.timestamp;
|
||||
|
||||
|
||||
return advert;
|
||||
}
|
||||
|
||||
void printAdvertisement (AdvertisementPayload advert) {
|
||||
unsigned char keyBuf[50];
|
||||
unsigned char sigBuf[90];
|
||||
memset (keyBuf, 0, sizeof (keyBuf));
|
||||
memset (sigBuf, 0, sizeof (sigBuf));
|
||||
base64_encode (advert.pubKey, 32, keyBuf);
|
||||
base64_encode (advert.signature, 64, sigBuf);
|
||||
|
||||
printf ("%s on %ld with type %s on %s location %ld %ld, public key %s and "
|
||||
"signature %s\n",
|
||||
advert.dataFlags & ADVERTISEMENT_FLAG_HAS_NAME ? advert.nodeName
|
||||
: "nameless node",
|
||||
advert.timestamp,
|
||||
(advert.dataFlags & 0x07) == 0x04
|
||||
? "sensor"
|
||||
: ((advert.dataFlags & 0x07) == 0x03
|
||||
? "room server"
|
||||
: ((advert.dataFlags & 0x07) == 0x02 ? "repeater"
|
||||
: "chat node")),
|
||||
advert.dataFlags & 0x80 ? "known" : "unknown", advert.latitude,
|
||||
advert.longitude, keyBuf, sigBuf);
|
||||
}
|
||||
12
User/meshcore/packets/advert.h
Normal file
12
User/meshcore/packets/advert.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef ADVERT_HEADER
|
||||
#define ADVERT_HEADER
|
||||
|
||||
#include "meshcore/packetstructs.h"
|
||||
|
||||
void sendAdvert();
|
||||
|
||||
AdvertisementPayload decodeAdvertisement (FrameStruct frame);
|
||||
|
||||
void printAdvertisement (AdvertisementPayload advert);
|
||||
|
||||
#endif
|
||||
133
User/meshcore/packets/anonymous.c
Normal file
133
User/meshcore/packets/anonymous.c
Normal file
@@ -0,0 +1,133 @@
|
||||
#include "ch32v30x_rtc.h"
|
||||
#include "lib/config.h"
|
||||
#include "lib/ed25519/ed_25519.h"
|
||||
#include "meshcore/meshframing.h"
|
||||
#include "meshcore/packets/encrypted.h"
|
||||
#include "meshcore/packetstructs.h"
|
||||
#include "anonymous.h"
|
||||
#include "util/hexdump.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define TAG "Anonymous"
|
||||
|
||||
void sendAnonymousRequest (NodeEntry *targetNode, const uint8_t *password, uint32_t sync) {
|
||||
uint8_t passwordLen = strlen ((const char *)password);
|
||||
FrameStruct frame;
|
||||
uint8_t offset = 0;
|
||||
|
||||
// 1. Frame header
|
||||
frame.header = ((targetNode->path.pathLen > 0) ? ROUTE_TYPE_DIRECT : ROUTE_TYPE_FLOOD) | PAYLOAD_TYPE_ANON_REQ | PAYLOAD_VERSION_0;
|
||||
|
||||
// 2. Payload header (unencrypted)
|
||||
frame.payload[offset++] = targetNode->pubKey[0];
|
||||
|
||||
memcpy (frame.payload + offset, persistent.pubkey, 32);
|
||||
offset += 32;
|
||||
|
||||
// 3. Build plaintext payload
|
||||
uint8_t plaintext[32];
|
||||
uint8_t p = 0;
|
||||
|
||||
uint32_t last_seen_rt = RTC_GetCounter();
|
||||
plaintext[p++] = (last_seen_rt >> 0) & 0xFF;
|
||||
plaintext[p++] = (last_seen_rt >> 8) & 0xFF;
|
||||
plaintext[p++] = (last_seen_rt >> 16) & 0xFF;
|
||||
plaintext[p++] = (last_seen_rt >> 24) & 0xFF;
|
||||
|
||||
if (targetNode->type == NODE_TYPE_ROOM_SERVER) {
|
||||
plaintext[p++] = (sync >> 0) & 0xFF;
|
||||
plaintext[p++] = (sync >> 8) & 0xFF;
|
||||
plaintext[p++] = (sync >> 16) & 0xFF;
|
||||
plaintext[p++] = (sync >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
if (passwordLen > 16) {
|
||||
passwordLen = 16;
|
||||
}
|
||||
memcpy (plaintext + p, password, passwordLen);
|
||||
p += passwordLen;
|
||||
|
||||
size_t outputLen;
|
||||
// 4. Encrypt + MAC
|
||||
encrypt_then_mac (
|
||||
targetNode->secret,
|
||||
32,
|
||||
plaintext,
|
||||
p,
|
||||
frame.payload + offset,
|
||||
&outputLen);
|
||||
|
||||
offset += outputLen;
|
||||
|
||||
// 5. Finalize and send
|
||||
frame.payloadLen = offset;
|
||||
memcpy(&(frame.path), &(targetNode->path), sizeof(frame.path));
|
||||
|
||||
hexdump ("Anon payload", frame.payload, frame.payloadLen);
|
||||
|
||||
sendFrame (frame);
|
||||
}
|
||||
|
||||
AnonymousRequestPayload decodeAnonReq (FrameStruct frame) {
|
||||
uint8_t index = 0;
|
||||
AnonymousRequestPayload anonReq;
|
||||
anonReq.destinationHash = frame.payload[index++];
|
||||
memcpy (anonReq.pubKey, &(frame.payload[index]), sizeof (anonReq.pubKey));
|
||||
index += sizeof (anonReq.pubKey);
|
||||
anonReq.cipherMAC = frame.payload[index];
|
||||
anonReq.cipherMAC |= frame.payload[index + 1] << 8;
|
||||
NodeEntry *foundNode = getNode (anonReq.pubKey[0]);
|
||||
if (foundNode == NULL) {
|
||||
foundNode = getNextNode();
|
||||
|
||||
strcpy (foundNode->name, "Anonymous node");
|
||||
memcpy (foundNode->pubKey, anonReq.pubKey, sizeof (foundNode->pubKey));
|
||||
ed25519_key_exchange ((unsigned char *)foundNode->secret, anonReq.pubKey, persistent.privkey);
|
||||
foundNode->gps_latitude = 0;
|
||||
foundNode->gps_longitude = 0;
|
||||
// ADD PATH
|
||||
foundNode->type = 0;
|
||||
foundNode->last_seen_lt = RTC_GetCounter();
|
||||
}
|
||||
mac_then_decrypt (foundNode->secret, 32, &(frame.payload[index]), frame.payloadLen - index, anonReq.payload);
|
||||
anonReq.payloadLen = frame.payloadLen - index - 2;
|
||||
uint8_t index2 = 0;
|
||||
foundNode->last_seen_rt = anonReq.payload[index2++];
|
||||
foundNode->last_seen_rt |= anonReq.payload[index2++] << 8;
|
||||
foundNode->last_seen_rt |= anonReq.payload[index2++] << 16;
|
||||
foundNode->last_seen_rt |= anonReq.payload[index2++] << 24;
|
||||
|
||||
if (persistent.nodeType == NODE_TYPE_ROOM_SERVER) {
|
||||
foundNode->sync_timestamp = anonReq.payload[index2++];
|
||||
foundNode->sync_timestamp |= anonReq.payload[index2++] << 8;
|
||||
foundNode->sync_timestamp |= anonReq.payload[index2++] << 16;
|
||||
foundNode->sync_timestamp |= anonReq.payload[index2++] << 24;
|
||||
}
|
||||
|
||||
uint8_t passwordLen = anonReq.payloadLen - index2;
|
||||
if (passwordLen > 16) {
|
||||
passwordLen = 16;
|
||||
}
|
||||
uint8_t passwordBuf[16];
|
||||
memcpy (passwordBuf, &(anonReq.payload[index2]), passwordLen);
|
||||
if (memcmp (passwordBuf, persistent.password, sizeof (persistent.password)) == 0) {
|
||||
foundNode->authenticated = 1;
|
||||
Response resp;
|
||||
resp.tag = RTC_GetCounter();
|
||||
uint8_t index3 = 0;
|
||||
uint32_t randOut = rand();
|
||||
resp.data[index3++] = RESP_SERVER_LOGIN_OK;
|
||||
resp.data[index3++] = 0;//legacy
|
||||
resp.data[index3++] = 1;//isadmin
|
||||
resp.data[index3++] = PERM_ACL_ADMIN;//permissions
|
||||
resp.data[index3++] = randOut & 0xFF;//rng
|
||||
resp.data[index3++] = (randOut >> 8) & 0xFF;
|
||||
resp.data[index3++] = (randOut >> 16) & 0xFF;
|
||||
resp.data[index3++] = (randOut >> 24) & 0xFF;
|
||||
resp.data[index3++] = FIRMWARE_VER_LEVEL;
|
||||
resp.dataLen = index3;
|
||||
sendEncryptedResponse(foundNode, &resp);
|
||||
}
|
||||
|
||||
return anonReq;
|
||||
}
|
||||
11
User/meshcore/packets/anonymous.h
Normal file
11
User/meshcore/packets/anonymous.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef ANONYMOUS_HEADER
|
||||
#define ANONYMOUS_HEADER
|
||||
|
||||
#include "meshcore/packetstructs.h"
|
||||
#include "lib/config.h"
|
||||
|
||||
AnonymousRequestPayload decodeAnonReq (FrameStruct frame);
|
||||
|
||||
void sendAnonymousRequest (NodeEntry *targetNode, const uint8_t *password, uint32_t sync);
|
||||
|
||||
#endif
|
||||
76
User/meshcore/packets/control.c
Normal file
76
User/meshcore/packets/control.c
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "meshcore/meshframing.h"
|
||||
#include "meshcore/packetstructs.h"
|
||||
#include "control.h"
|
||||
#include "string.h"
|
||||
|
||||
#define TAG "Control"
|
||||
|
||||
void sendDiscoverRequest(const DiscoverRequestPayload *discReq) {
|
||||
|
||||
FrameStruct frame;
|
||||
uint8_t offset = 0;
|
||||
|
||||
// Build payload
|
||||
frame.payload[offset++] = (discReq->prefixOnly & 0x01) | CONTROL_DATA_FLAG_TYPE_NODE_DISCOVER_REQ;
|
||||
|
||||
frame.payload[offset++] = discReq->typeFilter;
|
||||
|
||||
frame.payload[offset++] = (discReq->tag >> 0) & 0xFF;
|
||||
frame.payload[offset++] = (discReq->tag >> 8) & 0xFF;
|
||||
frame.payload[offset++] = (discReq->tag >> 16) & 0xFF;
|
||||
frame.payload[offset++] = (discReq->tag >> 24) & 0xFF;
|
||||
|
||||
// optional `since`
|
||||
if (discReq->since != 0) { // or another condition if you want to always include
|
||||
frame.payload[offset++] = (discReq->since >> 0) & 0xFF;
|
||||
frame.payload[offset++] = (discReq->since >> 8) & 0xFF;
|
||||
frame.payload[offset++] = (discReq->since >> 16) & 0xFF;
|
||||
frame.payload[offset++] = (discReq->since >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
frame.payloadLen = offset;
|
||||
|
||||
sendFrame(frame);
|
||||
}
|
||||
|
||||
|
||||
void decodeControlFrame(FrameStruct frame) {
|
||||
uint8_t index = 0;
|
||||
uint8_t type = frame.payload[index] & 0xF0;
|
||||
if (type == CONTROL_DATA_FLAG_TYPE_NODE_DISCOVER_REQ) {
|
||||
DiscoverRequestPayload discReq;
|
||||
discReq.prefixOnly = frame.payload[index++] & 0x01;
|
||||
|
||||
discReq.typeFilter = frame.payload[index++];
|
||||
|
||||
discReq.tag = frame.payload[index++];
|
||||
discReq.tag |= frame.payload[index++] << 8;
|
||||
discReq.tag |= frame.payload[index++] << 16;
|
||||
discReq.tag |= frame.payload[index++] << 24;
|
||||
|
||||
if (index < frame.payloadLen) {
|
||||
discReq.since = frame.payload[index++];
|
||||
discReq.since |= frame.payload[index++] << 8;
|
||||
discReq.since |= frame.payload[index++] << 16;
|
||||
discReq.since |= frame.payload[index++] << 24;
|
||||
}
|
||||
|
||||
} else if (type == CONTROL_DATA_FLAG_DISCOVER_RESP) {
|
||||
DiscoverResponsePayload discResp;
|
||||
discResp.nodeType = frame.payload[index++] & 0x0F;
|
||||
|
||||
discResp.snr = frame.payload[index++];
|
||||
|
||||
discResp.tag = frame.payload[index++];
|
||||
discResp.tag |= frame.payload[index++] << 8;
|
||||
discResp.tag |= frame.payload[index++] << 16;
|
||||
discResp.tag |= frame.payload[index++] << 24;
|
||||
|
||||
uint8_t remainingLen = frame.payloadLen - index;
|
||||
|
||||
uint8_t pubKeyLen = (remainingLen > 8) ? sizeof(discResp.pubkey) : 8;
|
||||
memcpy(discResp.pubkey, &(frame.payload[index]), pubKeyLen);
|
||||
index += pubKeyLen;
|
||||
|
||||
}
|
||||
}
|
||||
8
User/meshcore/packets/control.h
Normal file
8
User/meshcore/packets/control.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef CONTROL_HEADER
|
||||
#define CONTROL_HEADER
|
||||
|
||||
#include "meshcore/packetstructs.h"
|
||||
|
||||
void decodeControlFrame(FrameStruct frame);
|
||||
|
||||
#endif
|
||||
3
User/meshcore/packets/custom.c
Normal file
3
User/meshcore/packets/custom.c
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "meshcore/packetstructs.h"
|
||||
|
||||
#define TAG "Custom"
|
||||
6
User/meshcore/packets/custom.h
Normal file
6
User/meshcore/packets/custom.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef CUSTOM_HEADER
|
||||
#define CUSTOM_HEADER
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
309
User/meshcore/packets/encrypted.c
Normal file
309
User/meshcore/packets/encrypted.c
Normal file
@@ -0,0 +1,309 @@
|
||||
#include "lib/config.h"
|
||||
#include "meshcore/meshframing.h"
|
||||
#include "meshcore/packets/ack.h"
|
||||
#include "meshcore/packetstructs.h"
|
||||
#include "meshcore/stats.h"
|
||||
#include "util/hexdump.h"
|
||||
#include "util/log.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "encrypted.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
|
||||
#define TAG "EncryptedMessage"
|
||||
|
||||
void sendEncryptedFrame (NodeEntry *targetNode, uint8_t payloadType, const uint8_t *plain, size_t plainLen) {
|
||||
FrameStruct frame;
|
||||
uint8_t offset = 0;
|
||||
|
||||
// 1. Header
|
||||
frame.header =
|
||||
ROUTE_TYPE_FLOOD | //currently flood
|
||||
payloadType |
|
||||
PAYLOAD_VERSION_0;
|
||||
|
||||
// 2. Destination + source
|
||||
frame.payload[offset++] = targetNode->pubKey[0];
|
||||
frame.payload[offset++] = persistent.pubkey[0];
|
||||
|
||||
// 4. Encrypt + MAC
|
||||
size_t encLen;
|
||||
encrypt_then_mac (
|
||||
targetNode->secret,
|
||||
32,
|
||||
plain,
|
||||
plainLen,
|
||||
frame.payload + offset,
|
||||
&encLen);
|
||||
|
||||
offset += encLen;
|
||||
|
||||
// 5. Finalize
|
||||
frame.payloadLen = offset;
|
||||
memcpy (&frame.path, &targetNode->path, sizeof (frame.path));
|
||||
|
||||
hexdump ("Encrypted frame", frame.payload, frame.payloadLen);
|
||||
sendFrame (frame);
|
||||
}
|
||||
|
||||
void sendEncryptedTextMessage (NodeEntry *targetNode, const PlainTextMessagePayload *msg) {
|
||||
if (targetNode == NULL) {
|
||||
ESP_LOGW(TAG, "Node is null");
|
||||
return;
|
||||
}
|
||||
if (targetNode->last_seen_lt == 0) {
|
||||
ESP_LOGW(TAG, "Node is not populated");
|
||||
return;
|
||||
}
|
||||
uint8_t buf[256];
|
||||
uint8_t index = 0;
|
||||
|
||||
uint8_t msgLen = strlen(msg->message) + 1;
|
||||
buf[index++] = msg->timestamp;
|
||||
buf[index++] = msg->timestamp >> 8;
|
||||
buf[index++] = msg->timestamp >> 16;
|
||||
buf[index++] = msg->timestamp >> 24;
|
||||
|
||||
buf[index++] = (msg->textType << 2) | (msg->attempt & 0x03);
|
||||
memcpy (&buf[index], msg->message, msgLen);
|
||||
|
||||
sendEncryptedFrame (
|
||||
targetNode,
|
||||
PAYLOAD_TYPE_TXT_MSG,
|
||||
buf,
|
||||
index + msgLen);
|
||||
}
|
||||
|
||||
void sendEncryptedResponse (NodeEntry *targetNode, const Response *resp) {
|
||||
uint8_t buf[256];
|
||||
uint8_t index = 0;
|
||||
|
||||
buf[index++] = resp->tag;
|
||||
buf[index++] = resp->tag >> 8;
|
||||
buf[index++] = resp->tag >> 16;
|
||||
buf[index++] = resp->tag >> 24;
|
||||
|
||||
memcpy (&buf[index], resp->data, resp->dataLen);
|
||||
|
||||
sendEncryptedFrame (
|
||||
targetNode,
|
||||
PAYLOAD_TYPE_RESPONSE,
|
||||
buf,
|
||||
index);
|
||||
}
|
||||
|
||||
void sendEncryptedRequest (NodeEntry *targetNode, const Request *req) {
|
||||
uint8_t buf[256];
|
||||
uint8_t index = 0;
|
||||
|
||||
buf[index++] = req->timestamp;
|
||||
buf[index++] = req->timestamp >> 8;
|
||||
buf[index++] = req->timestamp >> 16;
|
||||
buf[index++] = req->timestamp >> 24;
|
||||
|
||||
buf[index++] = req->requestType;
|
||||
memcpy (&buf[index], req->data, req->dataLen);
|
||||
|
||||
sendEncryptedFrame (
|
||||
targetNode,
|
||||
PAYLOAD_TYPE_REQ,
|
||||
buf,
|
||||
index);
|
||||
}
|
||||
|
||||
void sendEncryptedPathPayload (NodeEntry *targetNode, const ReturnedPathPayload *path) {
|
||||
uint8_t buf[256];
|
||||
uint8_t index = 0;
|
||||
|
||||
buf[index++] = path->path.pathLen;
|
||||
memcpy (&buf[index], path->path.path, path->path.pathLen);
|
||||
index += path->path.pathLen;
|
||||
|
||||
buf[index++] = path->extra.type;
|
||||
memcpy (&buf[index], path->extra.data,
|
||||
sizeof (path->extra.data));
|
||||
|
||||
sendEncryptedFrame (
|
||||
targetNode,
|
||||
PAYLOAD_TYPE_PATH,
|
||||
buf,
|
||||
index);
|
||||
}
|
||||
|
||||
void printRequest (const Request *req) {
|
||||
printf ("Request:\n");
|
||||
printf (" Timestamp: %u\n", req->timestamp);
|
||||
printf (" Type: 0x%02X\n", req->requestType);
|
||||
printf (" Data: ");
|
||||
for (int i = 0; i < req->dataLen; i++) {
|
||||
printf ("%02X ", req->data[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
void printResponse (const Response *resp) {
|
||||
printf ("Response:\n");
|
||||
printf (" Tag: %u\n", resp->tag);
|
||||
printf (" Data: ");
|
||||
for (int i = 0; i < resp->dataLen; i++) {
|
||||
printf ("%02X ", resp->data[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
void printPlainTextMessage (const PlainTextMessagePayload *msg) {
|
||||
printf ("PlainTextMessage:\n");
|
||||
printf (" Timestamp: %u\n", msg->timestamp);
|
||||
printf (" Attempt: %u\n", msg->attempt);
|
||||
printf (" TextType: %u\n", msg->textType);
|
||||
printf (" Message: %.*s\n", (int)strlen (msg->message), msg->message);
|
||||
}
|
||||
|
||||
void printReturnedPathPayload (const ReturnedPathPayload *path) {
|
||||
printf ("ReturnedPathPayload:\n");
|
||||
printf (" Path Length: %u\n", path->path.pathLen);
|
||||
printf (" Path: ");
|
||||
for (int i = 0; i < path->path.pathLen; i++) {
|
||||
printf ("%02X ", path->path.path[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
printf (" Extra Type: %u\n", path->extra.type);
|
||||
printf (" Extra Data: ");
|
||||
for (int i = 0; i < sizeof (path->extra.data); i++) {
|
||||
printf ("%02X ", path->extra.data[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
void printEncryptedPayload (const EncryptedPayloadStruct *enc) {
|
||||
printf ("EncryptedPayload:\n");
|
||||
printf (" Type: 0x%02X\n", enc->type);
|
||||
printf (" DestinationHash: 0x%02X\n", enc->destinationHash);
|
||||
printf (" SourceHash: 0x%02X\n", enc->sourceHash);
|
||||
printf (" CipherMAC: 0x%04X\n", enc->cipherMAC);
|
||||
printf (" PayloadLen: %zu\n", enc->payloadLen);
|
||||
printf (" Payload: ");
|
||||
for (size_t i = 0; i < enc->payloadLen; i++) {
|
||||
printf ("%02X ", enc->payload[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
EncryptedPayloadStruct decodeEncryptedPayload (FrameStruct frame) {
|
||||
EncryptedPayloadStruct enc;
|
||||
memset (&enc, 0, sizeof (enc));
|
||||
enc.type = frame.header & PAYLOAD_TYPE_MASK;
|
||||
unsigned char index = 0;
|
||||
|
||||
enc.destinationHash = frame.payload[index++];
|
||||
enc.sourceHash = frame.payload[index++];
|
||||
enc.cipherMAC = frame.payload[index];
|
||||
enc.cipherMAC |= frame.payload[index + 1] << 8;
|
||||
|
||||
if (enc.destinationHash != persistent.pubkey[0]) {
|
||||
return enc;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Finding remote node, sourceHash is %d", enc.sourceHash);
|
||||
|
||||
NodeEntry *remNode = getNode (enc.sourceHash);
|
||||
|
||||
enc.remNode = remNode;
|
||||
|
||||
|
||||
if (remNode == NULL) {
|
||||
ESP_LOGW(TAG, "Node not in DB");
|
||||
return enc;
|
||||
}
|
||||
ESP_LOGI(TAG, "Found node with index %d", remNode - persistent.contacts);
|
||||
|
||||
|
||||
if (mac_then_decrypt (remNode->secret, 32, &(frame.payload[index]), frame.payloadLen - index, enc.payload) != 0) {
|
||||
ESP_LOGW (TAG, "HMAC failed on encrypted message %s", remNode->name);
|
||||
} else {
|
||||
enc.payloadLen = frame.payloadLen - HMAC_SIZE;
|
||||
ESP_LOGI(TAG, "HMAC success from %s, %u bytes long", remNode->name, enc.payloadLen);
|
||||
sendDiscreteAck(enc.payload, 5 + strlen((char *)&enc.payload[5]), remNode->pubKey);
|
||||
}
|
||||
|
||||
return enc;
|
||||
}
|
||||
|
||||
void parseEncryptedPayload (EncryptedPayloadStruct enc) {
|
||||
// printEncryptedPayload(&enc);
|
||||
|
||||
printf ("EncryptedPayload:\n");
|
||||
printf (" Type: 0x%02X\n", enc.type);
|
||||
printf (" DestinationHash: 0x%02X\n", enc.destinationHash);
|
||||
printf (" SourceHash: 0x%02X\n", enc.sourceHash);
|
||||
printf (" CipherMAC: 0x%04X\n", enc.cipherMAC);
|
||||
printf (" PayloadLen: %u\n", enc.payloadLen);
|
||||
printf (" Payload: ");
|
||||
hexdump("Full payload buffer", enc.payload, sizeof(enc.payload));
|
||||
printf ("\n");
|
||||
|
||||
uint8_t index = 0;
|
||||
if (enc.type == PAYLOAD_TYPE_PATH) {
|
||||
|
||||
ReturnedPathPayload retPath;
|
||||
retPath.path.pathLen = enc.payload[index++];
|
||||
if (retPath.path.pathLen > 64) {
|
||||
ESP_LOGW (TAG, "Path too long\n");
|
||||
return;
|
||||
}
|
||||
memcpy (retPath.path.path, &(enc.payload[index]), retPath.path.pathLen);
|
||||
index += retPath.path.pathLen;
|
||||
retPath.extra.type = enc.payload[index++];
|
||||
memcpy (retPath.extra.data, &(enc.payload[index]), enc.payloadLen - index);
|
||||
|
||||
} else if (enc.type == PAYLOAD_TYPE_REQ) {
|
||||
Request req;
|
||||
req.timestamp = enc.payload[index++];
|
||||
req.timestamp |= enc.payload[index++] << 8;
|
||||
req.timestamp |= enc.payload[index++] << 16;
|
||||
req.timestamp |= enc.payload[index++] << 24;
|
||||
req.requestType = enc.payload[index++];
|
||||
req.dataLen = enc.payloadLen - index;
|
||||
memcpy (req.data, &(enc.payload[index]), req.dataLen);
|
||||
printRequest (&req);
|
||||
switch (req.requestType) {
|
||||
Response resp;
|
||||
resp.tag = RTC_GetCounter();
|
||||
memcpy(resp.data, &stats, sizeof(stats));
|
||||
resp.dataLen = sizeof(stats);
|
||||
sendEncryptedResponse(enc.remNode, &resp);
|
||||
break;
|
||||
case REQUEST_KEEPALIVE:
|
||||
break;
|
||||
case REQUEST_GET_TELEMETRY_DATA:
|
||||
break;
|
||||
case REQUEST_GET_MIN_MAX_AVG:
|
||||
break;
|
||||
case REQUEST_GET_ACCESS_LIST:
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (enc.type == PAYLOAD_TYPE_RESPONSE) {
|
||||
Response resp;
|
||||
resp.tag = enc.payload[index++];
|
||||
resp.tag |= enc.payload[index++] << 8;
|
||||
resp.tag |= enc.payload[index++] << 16;
|
||||
resp.tag |= enc.payload[index++] << 24;
|
||||
resp.dataLen = enc.payloadLen - index;
|
||||
memcpy (resp.data, &(enc.payload[index]), resp.dataLen);
|
||||
printResponse (&resp);
|
||||
|
||||
} else if (enc.type == PAYLOAD_TYPE_TXT_MSG) {
|
||||
PlainTextMessagePayload plaintext;
|
||||
plaintext.timestamp = enc.payload[index++];
|
||||
plaintext.timestamp |= enc.payload[index++] << 8;
|
||||
plaintext.timestamp |= enc.payload[index++] << 16;
|
||||
plaintext.timestamp |= enc.payload[index++] << 24;
|
||||
plaintext.attempt = enc.payload[index] & 0x03;
|
||||
plaintext.textType = enc.payload[index++] >> 2;
|
||||
memcpy (plaintext.message, &(enc.payload[index]), enc.payloadLen - index);
|
||||
printPlainTextMessage (&plaintext);
|
||||
}
|
||||
}
|
||||
25
User/meshcore/packets/encrypted.h
Normal file
25
User/meshcore/packets/encrypted.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef ENCRYPTED_HEADER
|
||||
#define ENCRYPTED_HEADER
|
||||
|
||||
#include "lib/config.h"
|
||||
#include "meshcore/meshframing.h"
|
||||
#include "meshcore/packetstructs.h"
|
||||
#include "util/log.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
void sendEncryptedFrame (NodeEntry *targetNode, uint8_t payloadType, const uint8_t *plain, size_t plainLen);
|
||||
|
||||
void sendEncryptedTextMessage (NodeEntry *targetNode, const PlainTextMessagePayload *msg);
|
||||
|
||||
void sendEncryptedResponse (NodeEntry *targetNode, const Response *resp);
|
||||
|
||||
void sendEncryptedRequest (NodeEntry *targetNode, const Request *req);
|
||||
|
||||
void sendEncryptedPathPayload (NodeEntry *targetNode, const ReturnedPathPayload *path);
|
||||
|
||||
EncryptedPayloadStruct decodeEncryptedPayload (FrameStruct frame);
|
||||
|
||||
void parseEncryptedPayload (EncryptedPayloadStruct enc);
|
||||
|
||||
#endif
|
||||
108
User/meshcore/packets/group.c
Normal file
108
User/meshcore/packets/group.c
Normal file
@@ -0,0 +1,108 @@
|
||||
#include "ch32v30x_rtc.h"
|
||||
#include "meshcore/meshframing.h"
|
||||
#include "meshcore/packetstructs.h"
|
||||
#include "group.h"
|
||||
#include "lib/config.h"
|
||||
#include "util/hexdump.h"
|
||||
#include "util/log.h"
|
||||
#include "string.h"
|
||||
|
||||
#define TAG "GroupMessage"
|
||||
|
||||
void sendGroupMessage (GroupTextMessage msg) {
|
||||
|
||||
msg.channelHash = persistent.aesKeys[msg.keyIndex][0];
|
||||
|
||||
msg.flags = 0;
|
||||
msg.timestamp = RTC_GetCounter();
|
||||
|
||||
FrameStruct frame;
|
||||
frame.header = ROUTE_TYPE_FLOOD | PAYLOAD_TYPE_GRP_TXT | PAYLOAD_VERSION_0;
|
||||
frame.path.pathLen = 0;
|
||||
size_t offset = 0;
|
||||
memset (frame.payload, 0, sizeof (frame.payload));
|
||||
frame.payload[offset++] = msg.channelHash;
|
||||
|
||||
uint8_t cipherBuf[176];
|
||||
size_t offset2 = 0;
|
||||
memcpy (cipherBuf, (const void *)&(msg.timestamp), 4);
|
||||
offset2 += 4;
|
||||
cipherBuf[offset2++] = msg.flags;
|
||||
size_t textSize = offset2 + strlen ((const char *)msg.text);
|
||||
if (textSize > 175) {
|
||||
textSize = 175;
|
||||
}
|
||||
memcpy (cipherBuf + offset2, msg.text, textSize);
|
||||
offset2 += textSize;
|
||||
|
||||
size_t olen = 0;
|
||||
hexdump ("TxDumpDec", cipherBuf, offset2);
|
||||
encrypt_then_mac (&(persistent.aesKeys[msg.keyIndex][1]), 16, cipherBuf, offset2, &(frame.payload[offset]), &olen);
|
||||
|
||||
frame.payloadLen = olen + 1;
|
||||
|
||||
sendFrame (frame);
|
||||
return;
|
||||
}
|
||||
|
||||
void makeSendGroupMessage (char *txt, uint8_t keyIndex) {
|
||||
GroupTextMessage msg;
|
||||
strcpy((char *) msg.text, persistent.nodeName);
|
||||
strcat ((char *)msg.text, ": ");
|
||||
strcat ((char *)msg.text, txt);
|
||||
msg.keyIndex = keyIndex;
|
||||
sendGroupMessage (msg);
|
||||
return;
|
||||
}
|
||||
|
||||
GroupTextMessage decodeGroupMessage (FrameStruct frame) {
|
||||
GroupTextMessage msg;
|
||||
memset (&msg, 0, sizeof (msg));
|
||||
if ((frame.header & PAYLOAD_TYPE_MASK) != PAYLOAD_TYPE_GRP_TXT) {
|
||||
ESP_LOGW (TAG, "Not a group text");
|
||||
return msg;
|
||||
}
|
||||
unsigned char index = 0;
|
||||
msg.channelHash = frame.payload[index++];
|
||||
unsigned char tmp[184];
|
||||
|
||||
|
||||
unsigned char decrypted = 0;
|
||||
for (unsigned char i = 0; i < AESKeyCount; i++) {
|
||||
|
||||
if (msg.channelHash != persistent.aesKeys[i][0]) {
|
||||
ESP_LOGW (TAG, "Hash %d does not equal %d", persistent.aesKeys[i][0], msg.channelHash);
|
||||
continue;
|
||||
}
|
||||
|
||||
ESP_LOGW (TAG, "Hash does equal %d", msg.channelHash);
|
||||
|
||||
if (mac_then_decrypt (persistent.aesKeys[i] + 1, 16, frame.payload + index, frame.payloadLen - index, tmp) != 0) {
|
||||
ESP_LOGW (TAG, "HMAC failed on grouphash key %d not matching %d", persistent.aesKeys[i][0], msg.channelHash);
|
||||
continue;
|
||||
}
|
||||
hexdump ("RxDumpDec", tmp, frame.payloadLen - index);
|
||||
decrypted = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (!decrypted) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
unsigned char plaintextLen = frame.payloadLen - index;
|
||||
index = 0;
|
||||
|
||||
memcpy (&msg.timestamp, tmp + index, 4);
|
||||
index += 4;
|
||||
msg.flags = tmp[index++];
|
||||
|
||||
memcpy (msg.text, tmp + index, plaintextLen - index);
|
||||
return msg;
|
||||
}
|
||||
|
||||
void printGroupMessage (GroupTextMessage msg) {
|
||||
printf ("Message with channel hash %d, flags %d: %s\n", msg.channelHash,
|
||||
msg.flags, msg.text);
|
||||
}
|
||||
15
User/meshcore/packets/group.h
Normal file
15
User/meshcore/packets/group.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef GROUP_HEADER
|
||||
#define GROUP_HEADER
|
||||
|
||||
#include "stdint.h"
|
||||
#include "meshcore/packetstructs.h"
|
||||
|
||||
void sendGroupMessage (GroupTextMessage msg);
|
||||
|
||||
void makeSendGroupMessage (char *txt, uint8_t keyIndex);
|
||||
|
||||
GroupTextMessage decodeGroupMessage (FrameStruct frame);
|
||||
|
||||
void printGroupMessage (GroupTextMessage msg);
|
||||
|
||||
#endif
|
||||
4
User/meshcore/packets/multipart.c
Normal file
4
User/meshcore/packets/multipart.c
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "meshcore/packetstructs.h"
|
||||
#include "multipart.h"
|
||||
|
||||
#define TAG "Multipart"
|
||||
4
User/meshcore/packets/multipart.h
Normal file
4
User/meshcore/packets/multipart.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#ifndef MULTIPART_HEADER
|
||||
#define MULTIPART_HEADER
|
||||
|
||||
#endif
|
||||
4
User/meshcore/packets/trace.c
Normal file
4
User/meshcore/packets/trace.c
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "meshcore/packetstructs.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define TAG "Trace"
|
||||
6
User/meshcore/packets/trace.h
Normal file
6
User/meshcore/packets/trace.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef TRACE_HEADER
|
||||
#define TRACE_HEADER
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -6,6 +6,21 @@
|
||||
#define PAYLOAD_TYPE_MASK 0x3C
|
||||
#define PAYLOAD_VERSION_MASK 0xC0
|
||||
|
||||
#define DONT_RETRANSMIT_HEADER 0xFF
|
||||
|
||||
#define RESP_SERVER_LOGIN_OK 0
|
||||
|
||||
#define FIRMWARE_VER_LEVEL 1
|
||||
|
||||
#define PERM_ACL_ROLE_MASK 3 // lower 2 bits
|
||||
#define PERM_ACL_GUEST 0
|
||||
#define PERM_ACL_READ_ONLY 1
|
||||
#define PERM_ACL_READ_WRITE 2
|
||||
#define PERM_ACL_ADMIN 3
|
||||
|
||||
|
||||
#define MAX_PATH_LEN 64
|
||||
|
||||
typedef enum RouteType {
|
||||
ROUTE_TYPE_TRANSPORT_FLOOD = 0x00,
|
||||
ROUTE_TYPE_FLOOD = 0x01,
|
||||
@@ -13,7 +28,6 @@ typedef enum RouteType {
|
||||
ROUTE_TYPE_TRANSPORT_DIRECT = 0x03,
|
||||
} RouteType;
|
||||
|
||||
|
||||
typedef enum PayloadType {
|
||||
PAYLOAD_TYPE_REQ = 0x00 << 2,
|
||||
PAYLOAD_TYPE_RESPONSE = 0x01 << 2,
|
||||
@@ -26,9 +40,31 @@ typedef enum PayloadType {
|
||||
PAYLOAD_TYPE_PATH = 0x08 << 2,
|
||||
PAYLOAD_TYPE_TRACE = 0x09 << 2,
|
||||
PAYLOAD_TYPE_MULTIPART = 0x0A << 2,
|
||||
PAYLOAD_TYPE_CONTROL = 0x0B << 2,
|
||||
PAYLOAD_TYPE_RAW_CUSTOM = 0x0F << 2,
|
||||
} PayloadType;
|
||||
|
||||
typedef struct DiscoverRequestPayload {
|
||||
uint8_t prefixOnly;
|
||||
uint8_t typeFilter;
|
||||
uint32_t tag;
|
||||
uint32_t since;
|
||||
} DiscoverRequestPayload;
|
||||
|
||||
typedef struct DiscoverResponsePayload {
|
||||
uint8_t nodeType;
|
||||
int8_t snr;
|
||||
uint32_t tag;
|
||||
uint8_t pubkey[32];
|
||||
} DiscoverResponsePayload;
|
||||
|
||||
typedef struct AnonymousRequestPayload {
|
||||
uint8_t destinationHash;
|
||||
uint8_t pubKey[32];
|
||||
uint16_t cipherMAC;
|
||||
uint8_t payloadLen;
|
||||
uint8_t payload[149];
|
||||
} AnonymousRequestPayload;
|
||||
|
||||
typedef enum PayloadVersion {
|
||||
PAYLOAD_VERSION_0 = 0 << 6,
|
||||
@@ -37,14 +73,17 @@ typedef enum PayloadVersion {
|
||||
PAYLOAD_VERSION_3 = 3 << 6,
|
||||
} PayloadVersion;
|
||||
|
||||
typedef struct Path {
|
||||
uint8_t pathLen;
|
||||
uint8_t path[MAX_PATH_LEN];
|
||||
} Path;
|
||||
|
||||
typedef struct FrameStruct {
|
||||
unsigned char header;
|
||||
unsigned char transportCodes[4];
|
||||
unsigned char pathLen;
|
||||
unsigned char path[64];
|
||||
unsigned char payloadLen;
|
||||
unsigned char payload[184];
|
||||
uint8_t header;
|
||||
uint8_t transportCodes[4];
|
||||
Path path;
|
||||
uint8_t payloadLen;
|
||||
uint8_t payload[184];
|
||||
} FrameStruct;
|
||||
|
||||
typedef enum RequestType {
|
||||
@@ -55,14 +94,50 @@ typedef enum RequestType {
|
||||
REQUEST_GET_ACCESS_LIST = 0x05,
|
||||
} RequestType;
|
||||
|
||||
typedef struct Request {
|
||||
uint32_t timestamp;
|
||||
uint8_t requestType;
|
||||
uint8_t dataLen;
|
||||
uint8_t data[180]; // hopefully correct len
|
||||
} Request;
|
||||
|
||||
typedef struct Response {
|
||||
uint32_t tag; // sender timestamp
|
||||
uint8_t dataLen;
|
||||
uint8_t data[180]; // hopefully correct len
|
||||
} Response;
|
||||
|
||||
typedef struct Node {
|
||||
uint8_t pubKey[32];
|
||||
char name[32];
|
||||
int32_t latitude;
|
||||
int32_t longitude;
|
||||
int32_t lastSeen;
|
||||
char flags;
|
||||
} Node;
|
||||
|
||||
typedef struct EncryptedPayloadStruct {
|
||||
FrameStruct rawFrame;
|
||||
unsigned char destinationHash;
|
||||
unsigned char sourceHash;
|
||||
unsigned char payload[180];
|
||||
uint8_t destinationHash;
|
||||
uint8_t sourceHash;
|
||||
uint16_t cipherMAC;
|
||||
uint8_t payloadLen;
|
||||
uint8_t payload[180];
|
||||
uint8_t type;
|
||||
NodeEntry *remNode;
|
||||
} EncryptedPayloadStruct;
|
||||
|
||||
typedef enum NodeType {
|
||||
NODE_TYPE_CHAT_NODE = 1,
|
||||
NODE_TYPE_REPEATER = 2,
|
||||
NODE_TYPE_ROOM_SERVER = 3,
|
||||
NODE_TYPE_SENSOR = 4
|
||||
} NodeType;
|
||||
|
||||
typedef enum ControlDataFlags {
|
||||
CONTROL_DATA_FLAG_TYPE_NODE_DISCOVER_REQ = 0x80,
|
||||
CONTROL_DATA_FLAG_DISCOVER_RESP = 0x90
|
||||
} ControlDataFlags;
|
||||
|
||||
typedef enum AdvertisementPayloadFlags {
|
||||
ADVERTISEMENT_FLAG_IS_CHAT_NODE = 0x01,
|
||||
ADVERTISEMENT_FLAG_IS_REAPEATER = 0x02,
|
||||
@@ -75,46 +150,58 @@ typedef enum AdvertisementPayloadFlags {
|
||||
} AdvertisementPayloadFlags;
|
||||
|
||||
typedef struct AdvertisementPayload {
|
||||
unsigned char pubKey[32];
|
||||
uint8_t pubKey[32];
|
||||
int32_t timestamp;
|
||||
unsigned char signature[64];
|
||||
unsigned char dataFlags;
|
||||
uint8_t signature[64];
|
||||
uint8_t dataFlags;
|
||||
int32_t latitude;
|
||||
int32_t longitude;
|
||||
int16_t rfu1;
|
||||
int16_t rfu2;
|
||||
char nodeName[128];
|
||||
char nodeName[32];
|
||||
|
||||
} AdvertisementPayload;
|
||||
|
||||
typedef struct ReturnedPathPayload {
|
||||
unsigned char destinationHash;
|
||||
unsigned char sourceHash;
|
||||
unsigned char pathLen;
|
||||
typedef struct Extra {
|
||||
uint8_t type;
|
||||
uint8_t data[180]; // hopefully long enough
|
||||
} Extra;
|
||||
|
||||
typedef struct ReturnedPathPayload {
|
||||
Path path;
|
||||
Extra extra;
|
||||
} ReturnedPathPayload;
|
||||
|
||||
typedef struct RequestPayload {
|
||||
unsigned char destinationHash;
|
||||
unsigned char sourceHash;
|
||||
} RequestPayload;
|
||||
|
||||
typedef struct ResponsePayload {
|
||||
unsigned char destinationHash;
|
||||
unsigned char sourceHash;
|
||||
} ResponsePayload;
|
||||
|
||||
typedef struct PlainTextMessagePayload {
|
||||
unsigned char destinationHash;
|
||||
unsigned char sourceHash;
|
||||
uint32_t timestamp;
|
||||
uint8_t textType;
|
||||
uint8_t attempt;
|
||||
uint8_t message[180]; // hopefully long enough
|
||||
} PlainTextMessagePayload;
|
||||
|
||||
typedef struct GroupTextMessage {
|
||||
unsigned char channelHash;
|
||||
unsigned char keyIndex;
|
||||
uint8_t channelHash;
|
||||
uint8_t keyIndex;
|
||||
int32_t timestamp;
|
||||
unsigned char flags;
|
||||
unsigned char text[190];
|
||||
uint8_t flags;
|
||||
uint8_t text[190];
|
||||
} GroupTextMessage;
|
||||
|
||||
typedef struct RepeaterStats {
|
||||
uint16_t millivolts;
|
||||
uint16_t txQueueLength;
|
||||
int16_t noiseFloor;
|
||||
int16_t lastRSSI;
|
||||
uint32_t packetsReceivedCount;
|
||||
uint32_t packetsSentCount;
|
||||
uint32_t totalAirTimeSeconds;
|
||||
uint32_t totalUpTimeSeconds;
|
||||
uint32_t sentFloodCount, sentDirectCount;
|
||||
uint32_t receivedFloodCount, receivedDirectCount;
|
||||
uint16_t err_events; // was 'n_full_events'
|
||||
int16_t lastSNR; // x 4
|
||||
uint16_t n_direct_dups, n_flood_dups;
|
||||
uint32_t total_rx_air_time_secs;
|
||||
} RepeaterStats;
|
||||
|
||||
#endif
|
||||
|
||||
3
User/meshcore/stats.c
Normal file
3
User/meshcore/stats.c
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "stats.h"
|
||||
|
||||
RepeaterStats stats;
|
||||
7
User/meshcore/stats.h
Normal file
7
User/meshcore/stats.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef STATS_HEADER
|
||||
#define STATS_HEADER
|
||||
#include "meshcore/packetstructs.h"
|
||||
|
||||
extern RepeaterStats stats;
|
||||
|
||||
#endif
|
||||
24
User/util/hexdump.c
Normal file
24
User/util/hexdump.c
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "stdio.h"
|
||||
#include <ctype.h>
|
||||
#include "hexdump.h"
|
||||
|
||||
void hexdump (const char *label, const uint8_t *data, size_t len) {
|
||||
if (label)
|
||||
printf ("%s (len=%u):\n", label, len);
|
||||
|
||||
for (size_t i = 0; i < len; i += 16) {
|
||||
printf ("%04u ", i); // offset
|
||||
for (size_t j = 0; j < 16; j++) {
|
||||
if (i + j < len)
|
||||
printf ("%02X ", data[i + j]);
|
||||
else
|
||||
printf (" "); // pad spacing
|
||||
}
|
||||
printf (" ");
|
||||
for (size_t j = 0; j < 16 && i + j < len; j++) {
|
||||
uint8_t c = data[i + j];
|
||||
printf ("%c", isprint (c) ? c : '.');
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
9
User/util/hexdump.h
Normal file
9
User/util/hexdump.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef HEXDUMP_HEADER
|
||||
#define HEXDUMP_HEADER
|
||||
|
||||
|
||||
#include "stddef.h"
|
||||
#include "stdint.h"
|
||||
void hexdump (const char *label, const uint8_t *data, size_t len);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user