Init
This commit is contained in:
25
User/lib/base64.c
Normal file
25
User/lib/base64.c
Normal file
@@ -0,0 +1,25 @@
|
||||
#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)
|
||||
{
|
||||
size_t out_len = 0;
|
||||
for (size_t i = 0; i < ilen; i += 3) {
|
||||
uint32_t triple = 0;
|
||||
int remain = ilen - i;
|
||||
|
||||
triple |= in[i] << 16;
|
||||
if (remain > 1) triple |= in[i + 1] << 8;
|
||||
if (remain > 2) triple |= in[i + 2];
|
||||
|
||||
out[out_len++] = b64_enc_table[(triple >> 18) & 0x3F];
|
||||
out[out_len++] = b64_enc_table[(triple >> 12) & 0x3F];
|
||||
out[out_len++] = (remain > 1) ? b64_enc_table[(triple >> 6) & 0x3F] : '=';
|
||||
out[out_len++] = (remain > 2) ? b64_enc_table[triple & 0x3F] : '=';
|
||||
}
|
||||
return 0;
|
||||
}
|
7
User/lib/base64.h
Normal file
7
User/lib/base64.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifdef B64_HEADER
|
||||
#define B64_HEADER
|
||||
#include <stddef.h>
|
||||
|
||||
int base64_encode(const uint8_t *in, size_t ilen, char *out);
|
||||
|
||||
#endif
|
417
User/lib/cifra/aes.c
Normal file
417
User/lib/cifra/aes.c
Normal file
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and 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
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cf_config.h"
|
||||
#include "aes.h"
|
||||
#include "handy.h"
|
||||
#include "bitops.h"
|
||||
#include "tassert.h"
|
||||
|
||||
static const uint8_t S[256] =
|
||||
{
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe,
|
||||
0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4,
|
||||
0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7,
|
||||
0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3,
|
||||
0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09,
|
||||
0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3,
|
||||
0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe,
|
||||
0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
|
||||
0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92,
|
||||
0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c,
|
||||
0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19,
|
||||
0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
|
||||
0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2,
|
||||
0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5,
|
||||
0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25,
|
||||
0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
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
|
||||
};
|
||||
|
||||
static const uint8_t Rcon[11] =
|
||||
{
|
||||
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)
|
||||
{
|
||||
return b0 << 24 | b1 << 16 | b2 << 8 | b3;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return Rcon[i] << 24;
|
||||
}
|
||||
|
||||
static uint32_t rot_word(uint32_t w)
|
||||
{
|
||||
/* Takes
|
||||
* word [a0,a1,a2,a3]
|
||||
* returns
|
||||
* word [a1,a2,a3,a0]
|
||||
*
|
||||
*/
|
||||
return rotl32(w, 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define word4(a, b, c, d) (((uint32_t)(a) << 24) | ((uint32_t)(b) << 16) | ((uint32_t)(c) << 8) | (d))
|
||||
#define byte(w, x) ((w >> ((3 - (x)) << 3)) & 0xff)
|
||||
#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)
|
||||
{
|
||||
uint8_t a = byte(w, 0),
|
||||
b = byte(w, 1),
|
||||
c = byte(w, 2),
|
||||
d = byte(w, 3);
|
||||
#if CF_CACHE_SIDE_CHANNEL_PROTECTION
|
||||
select_u8x4(&a, &b, &c, &d, sbox, 256);
|
||||
#else
|
||||
a = sbox[a];
|
||||
b = sbox[b];
|
||||
c = sbox[c];
|
||||
d = sbox[d];
|
||||
#endif
|
||||
return word4(a, b, c, d);
|
||||
}
|
||||
|
||||
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,
|
||||
n = nb * (ctx->rounds + 1);
|
||||
uint32_t *w = ctx->ks;
|
||||
|
||||
/* First words are just the key. */
|
||||
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++)
|
||||
{
|
||||
uint32_t temp = w[i - 1];
|
||||
|
||||
if (i_mod_nk == nk)
|
||||
{
|
||||
i_div_nk++;
|
||||
i_mod_nk = 0;
|
||||
}
|
||||
|
||||
if (i_mod_nk == 0)
|
||||
temp = sub_word(rot_word(temp), S) ^ round_constant(i_div_nk);
|
||||
else if (nk > 6 && i_mod_nk == 4)
|
||||
temp = sub_word(temp, S);
|
||||
|
||||
w[i] = w[i - nk] ^ temp;
|
||||
}
|
||||
}
|
||||
|
||||
void cf_aes_init(cf_aes_context *ctx, const uint8_t *key, size_t nkey)
|
||||
{
|
||||
memset(ctx, 0, sizeof *ctx);
|
||||
|
||||
switch (nkey)
|
||||
{
|
||||
#if CF_AES_MAXROUNDS >= AES128_ROUNDS
|
||||
case 16:
|
||||
ctx->rounds = AES128_ROUNDS;
|
||||
aes_schedule(ctx, key, nkey);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if CF_AES_MAXROUNDS >= AES192_ROUNDS
|
||||
case 24:
|
||||
ctx->rounds = AES192_ROUNDS;
|
||||
aes_schedule(ctx, key, nkey);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if CF_AES_MAXROUNDS >= AES256_ROUNDS
|
||||
case 32:
|
||||
ctx->rounds = AES256_ROUNDS;
|
||||
aes_schedule(ctx, key, nkey);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
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])
|
||||
{
|
||||
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])
|
||||
{
|
||||
uint32_t u, v, x, y;
|
||||
|
||||
u = word4(byte(state[0], 0),
|
||||
byte(state[1], 1),
|
||||
byte(state[2], 2),
|
||||
byte(state[3], 3));
|
||||
|
||||
v = word4(byte(state[1], 0),
|
||||
byte(state[2], 1),
|
||||
byte(state[3], 2),
|
||||
byte(state[0], 3));
|
||||
|
||||
x = word4(byte(state[2], 0),
|
||||
byte(state[3], 1),
|
||||
byte(state[0], 2),
|
||||
byte(state[1], 3));
|
||||
|
||||
y = word4(byte(state[3], 0),
|
||||
byte(state[0], 1),
|
||||
byte(state[1], 2),
|
||||
byte(state[2], 3));
|
||||
|
||||
state[0] = u;
|
||||
state[1] = v;
|
||||
state[2] = x;
|
||||
state[3] = y;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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])
|
||||
{
|
||||
state[0] = mix_column(state[0]);
|
||||
state[1] = mix_column(state[1]);
|
||||
state[2] = mix_column(state[2]);
|
||||
state[3] = mix_column(state[3]);
|
||||
}
|
||||
|
||||
void cf_aes_encrypt(const cf_aes_context *ctx,
|
||||
const uint8_t in[AES_BLOCKSZ],
|
||||
uint8_t out[AES_BLOCKSZ])
|
||||
{
|
||||
assert(ctx->rounds == AES128_ROUNDS ||
|
||||
ctx->rounds == AES192_ROUNDS ||
|
||||
ctx->rounds == AES256_ROUNDS);
|
||||
|
||||
uint32_t state[4] = {
|
||||
read32_be(in + 0),
|
||||
read32_be(in + 4),
|
||||
read32_be(in + 8),
|
||||
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++)
|
||||
{
|
||||
sub_block(state);
|
||||
shift_rows(state);
|
||||
mix_columns(state);
|
||||
add_round_key(state, round_keys);
|
||||
round_keys += 4;
|
||||
}
|
||||
|
||||
sub_block(state);
|
||||
shift_rows(state);
|
||||
add_round_key(state, round_keys);
|
||||
|
||||
write32_be(state[0], out + 0);
|
||||
write32_be(state[1], out + 4);
|
||||
write32_be(state[2], out + 8);
|
||||
write32_be(state[3], out + 12);
|
||||
}
|
||||
|
||||
#if CF_AES_ENCRYPT_ONLY == 0
|
||||
static const uint8_t S_inv[256] =
|
||||
{
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81,
|
||||
0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e,
|
||||
0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23,
|
||||
0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66,
|
||||
0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72,
|
||||
0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65,
|
||||
0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46,
|
||||
0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
|
||||
0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca,
|
||||
0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91,
|
||||
0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6,
|
||||
0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
|
||||
0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f,
|
||||
0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2,
|
||||
0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8,
|
||||
0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
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
|
||||
};
|
||||
|
||||
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])
|
||||
{
|
||||
uint32_t u, v, x, y;
|
||||
|
||||
u = word4(byte(state[0], 0),
|
||||
byte(state[3], 1),
|
||||
byte(state[2], 2),
|
||||
byte(state[1], 3));
|
||||
|
||||
v = word4(byte(state[1], 0),
|
||||
byte(state[0], 1),
|
||||
byte(state[3], 2),
|
||||
byte(state[2], 3));
|
||||
|
||||
x = word4(byte(state[2], 0),
|
||||
byte(state[1], 1),
|
||||
byte(state[0], 2),
|
||||
byte(state[3], 3));
|
||||
|
||||
y = word4(byte(state[3], 0),
|
||||
byte(state[2], 1),
|
||||
byte(state[1], 2),
|
||||
byte(state[0], 3));
|
||||
|
||||
state[0] = u;
|
||||
state[1] = v;
|
||||
state[2] = x;
|
||||
state[3] = y;
|
||||
}
|
||||
|
||||
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),
|
||||
x11 = x2 ^ x9,
|
||||
x13 = x4 ^ x9;
|
||||
|
||||
return x ^ x2 ^ x13 ^ rotr32(x11, 24) ^ rotr32(x13, 16) ^ rotr32(x9, 8);
|
||||
}
|
||||
|
||||
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]);
|
||||
state[3] = inv_mix_column(state[3]);
|
||||
}
|
||||
|
||||
void cf_aes_decrypt(const cf_aes_context *ctx,
|
||||
const uint8_t in[AES_BLOCKSZ],
|
||||
uint8_t out[AES_BLOCKSZ])
|
||||
{
|
||||
assert(ctx->rounds == AES128_ROUNDS ||
|
||||
ctx->rounds == AES192_ROUNDS ||
|
||||
ctx->rounds == AES256_ROUNDS);
|
||||
|
||||
uint32_t state[4] = {
|
||||
read32_be(in + 0),
|
||||
read32_be(in + 4),
|
||||
read32_be(in + 8),
|
||||
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--)
|
||||
{
|
||||
inv_shift_rows(state);
|
||||
inv_sub_block(state);
|
||||
add_round_key(state, round_keys);
|
||||
inv_mix_columns(state);
|
||||
round_keys -= 4;
|
||||
}
|
||||
|
||||
inv_shift_rows(state);
|
||||
inv_sub_block(state);
|
||||
add_round_key(state, round_keys);
|
||||
|
||||
write32_be(state[0], out + 0);
|
||||
write32_be(state[1], out + 4);
|
||||
write32_be(state[2], out + 8);
|
||||
write32_be(state[3], out + 12);
|
||||
}
|
||||
#else
|
||||
void cf_aes_decrypt(const cf_aes_context *ctx,
|
||||
const uint8_t in[AES_BLOCKSZ],
|
||||
uint8_t out[AES_BLOCKSZ])
|
||||
{
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
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
|
||||
};
|
||||
|
152
User/lib/cifra/aes.h
Normal file
152
User/lib/cifra/aes.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and 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
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The AES block cipher
|
||||
* ====================
|
||||
*
|
||||
* This is a small, simple implementation of AES. Key expansion is done
|
||||
* first, filling in a :c:type:`cf_aes_context`. Then encryption and
|
||||
* decryption can be performed as desired.
|
||||
*
|
||||
* Usually you don't want to use AES directly; you should use it via
|
||||
* a :doc:`block cipher mode <modes>`.
|
||||
*/
|
||||
|
||||
#ifndef AES_H
|
||||
#define AES_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "prp.h"
|
||||
|
||||
/* .. c:macro:: AES_BLOCKSZ
|
||||
* AES has a 128-bit block size. This quantity is in bytes.
|
||||
*/
|
||||
#define AES_BLOCKSZ 16
|
||||
|
||||
/* --- Size configuration --- */
|
||||
|
||||
/* .. c:macro:: AES128_ROUNDS
|
||||
* .. c:macro:: AES192_ROUNDS
|
||||
* .. c:macro:: AES256_ROUNDS
|
||||
*
|
||||
* Round counts for different key sizes.
|
||||
*/
|
||||
#define AES128_ROUNDS 10
|
||||
#define AES192_ROUNDS 12
|
||||
#define AES256_ROUNDS 14
|
||||
|
||||
/* .. c:macro:: CF_AES_MAXROUNDS
|
||||
*
|
||||
* You can reduce the maximum number of rounds this implementation
|
||||
* supports. This reduces the storage needed by :c:type:`cf_aes_context`.
|
||||
*
|
||||
* The default is :c:macro:`AES256_ROUNDS` and is good for all key
|
||||
* sizes.
|
||||
*/
|
||||
#ifndef CF_AES_MAXROUNDS
|
||||
# define CF_AES_MAXROUNDS AES256_ROUNDS
|
||||
#endif
|
||||
|
||||
/* .. c:macro:: CF_AES_ENCRYPT_ONLY
|
||||
*
|
||||
* Define this to 1 if you don't need to decrypt anything.
|
||||
* This saves space. :c:func:`cf_aes_decrypt` calls `abort(3)`.
|
||||
*/
|
||||
#ifndef CF_AES_ENCRYPT_ONLY
|
||||
# define CF_AES_ENCRYPT_ONLY 0
|
||||
#endif
|
||||
|
||||
/* .. c:type:: cf_aes_context
|
||||
* This type represents an expanded AES key. Create one
|
||||
* using :c:func:`cf_aes_init`, make use of one using
|
||||
* :c:func:`cf_aes_encrypt` or :c:func:`cf_aes_decrypt`.
|
||||
*
|
||||
* The contents of this structure are equivalent to the
|
||||
* original key material. You should clean the
|
||||
* contents of this structure with :c:func:`cf_aes_finish`
|
||||
* when you're done.
|
||||
*
|
||||
* .. c:member:: cf_aes_context.rounds
|
||||
*
|
||||
* Number of rounds to use, set by :c:func:`cf_aes_init`.
|
||||
*
|
||||
* This depends on the original key size, and will be
|
||||
* :c:macro:`AES128_ROUNDS`, :c:macro:`AES192_ROUNDS` or
|
||||
* :c:macro:`AES256_ROUNDS`.
|
||||
*
|
||||
* .. c:member:: cf_aes_context.ks
|
||||
*
|
||||
* Expanded key material. Filled in by :c:func:`cf_aes_init`.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t rounds;
|
||||
uint32_t ks[AES_BLOCKSZ / 4 * (CF_AES_MAXROUNDS + 1)];
|
||||
} cf_aes_context;
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* This function does AES key expansion. It destroys
|
||||
* existing contents of :c:data:`ctx`.
|
||||
*
|
||||
* :param ctx: expanded key context, filled in by this function.
|
||||
* :param key: pointer to key material, of :c:data:`nkey` bytes.
|
||||
* :param nkey: length of key material. Must be `16`, `24` or `32`.
|
||||
*/
|
||||
extern void cf_aes_init(cf_aes_context *ctx,
|
||||
const uint8_t *key,
|
||||
size_t nkey);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Encrypts the given block, from :c:data:`in` to :c:data:`out`.
|
||||
* These may alias.
|
||||
*
|
||||
* Fails at runtime if :c:data:`ctx` is invalid.
|
||||
*
|
||||
* :param ctx: expanded key context
|
||||
* :param in: input block (read)
|
||||
* :param out: output block (written)
|
||||
*/
|
||||
extern void cf_aes_encrypt(const cf_aes_context *ctx,
|
||||
const uint8_t in[AES_BLOCKSZ],
|
||||
uint8_t out[AES_BLOCKSZ]);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Decrypts the given block, from :c:data:`in` to :c:data:`out`.
|
||||
* These may alias.
|
||||
*
|
||||
* Fails at runtime if :c:data:`ctx` is invalid.
|
||||
*
|
||||
* :param ctx: expanded key context
|
||||
* :param in: input block (read)
|
||||
* :param out: output block (written)
|
||||
*/
|
||||
extern void cf_aes_decrypt(const cf_aes_context *ctx,
|
||||
const uint8_t in[AES_BLOCKSZ],
|
||||
uint8_t out[AES_BLOCKSZ]);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Erase scheduled key material.
|
||||
*
|
||||
* Call this when you're done to erase the round keys. */
|
||||
extern void cf_aes_finish(cf_aes_context *ctx);
|
||||
|
||||
/* .. c:var:: const cf_prp cf_aes
|
||||
* Abstract interface to AES. See :c:type:`cf_prp` for
|
||||
* more information. */
|
||||
extern const cf_prp cf_aes;
|
||||
|
||||
#endif
|
294
User/lib/cifra/bitops.h
Normal file
294
User/lib/cifra/bitops.h
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and 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
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef BITOPS_H
|
||||
#define BITOPS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* Assorted bitwise and common operations used in ciphers. */
|
||||
|
||||
/** Circularly rotate right x by n bits.
|
||||
* 0 > n > 32. */
|
||||
static inline uint32_t rotr32(uint32_t x, unsigned n)
|
||||
{
|
||||
return (x >> n) | (x << (32 - n));
|
||||
}
|
||||
|
||||
/** Circularly rotate left x by n bits.
|
||||
* 0 > n > 32. */
|
||||
static inline uint32_t rotl32(uint32_t x, unsigned n)
|
||||
{
|
||||
return (x << n) | (x >> (32 - n));
|
||||
}
|
||||
|
||||
/** Circularly rotate right x by n bits.
|
||||
* 0 > n > 64. */
|
||||
static inline uint64_t rotr64(uint64_t x, unsigned n)
|
||||
{
|
||||
return (x >> n) | (x << (64 - n));
|
||||
}
|
||||
|
||||
/** Circularly rotate left x by n bits.
|
||||
* 0 > n > 64. */
|
||||
static inline uint64_t rotl64(uint64_t x, unsigned n)
|
||||
{
|
||||
return (x << n) | (x >> (64 - n));
|
||||
}
|
||||
|
||||
/** Read 4 bytes from buf, as a 32-bit big endian quantity. */
|
||||
static inline uint32_t read32_be(const uint8_t buf[4])
|
||||
{
|
||||
return (buf[0] << 24) |
|
||||
(buf[1] << 16) |
|
||||
(buf[2] << 8) |
|
||||
(buf[3]);
|
||||
}
|
||||
|
||||
/** Read 4 bytes from buf, as a 32-bit little endian quantity. */
|
||||
static inline uint32_t read32_le(const uint8_t buf[4])
|
||||
{
|
||||
return (buf[3] << 24) |
|
||||
(buf[2] << 16) |
|
||||
(buf[1] << 8) |
|
||||
(buf[0]);
|
||||
}
|
||||
|
||||
/** Read 8 bytes from buf, as a 64-bit big endian quantity. */
|
||||
static inline uint64_t read64_be(const uint8_t buf[8])
|
||||
{
|
||||
uint32_t hi = read32_be(buf),
|
||||
lo = read32_be(buf + 4);
|
||||
return ((uint64_t)hi) << 32 |
|
||||
lo;
|
||||
}
|
||||
|
||||
/** Read 8 bytes from buf, as a 64-bit little endian quantity. */
|
||||
static inline uint64_t read64_le(const uint8_t buf[8])
|
||||
{
|
||||
uint32_t hi = read32_le(buf + 4),
|
||||
lo = read32_le(buf);
|
||||
return ((uint64_t)hi) << 32 |
|
||||
lo;
|
||||
}
|
||||
|
||||
/** Encode v as a 32-bit big endian quantity into buf. */
|
||||
static inline void write32_be(uint32_t v, uint8_t buf[4])
|
||||
{
|
||||
*buf++ = (v >> 24) & 0xff;
|
||||
*buf++ = (v >> 16) & 0xff;
|
||||
*buf++ = (v >> 8) & 0xff;
|
||||
*buf = v & 0xff;
|
||||
}
|
||||
|
||||
/** Encode v as a 32-bit little endian quantity into buf. */
|
||||
static inline void write32_le(uint32_t v, uint8_t buf[4])
|
||||
{
|
||||
*buf++ = v & 0xff;
|
||||
*buf++ = (v >> 8) & 0xff;
|
||||
*buf++ = (v >> 16) & 0xff;
|
||||
*buf = (v >> 24) & 0xff;
|
||||
}
|
||||
|
||||
/** Encode v as a 64-bit big endian quantity into buf. */
|
||||
static inline void write64_be(uint64_t v, uint8_t buf[8])
|
||||
{
|
||||
*buf++ = (v >> 56) & 0xff;
|
||||
*buf++ = (v >> 48) & 0xff;
|
||||
*buf++ = (v >> 40) & 0xff;
|
||||
*buf++ = (v >> 32) & 0xff;
|
||||
*buf++ = (v >> 24) & 0xff;
|
||||
*buf++ = (v >> 16) & 0xff;
|
||||
*buf++ = (v >> 8) & 0xff;
|
||||
*buf = v & 0xff;
|
||||
}
|
||||
|
||||
/** Encode v as a 64-bit little endian quantity into buf. */
|
||||
static inline void write64_le(uint64_t v, uint8_t buf[8])
|
||||
{
|
||||
*buf++ = v & 0xff;
|
||||
*buf++ = (v >> 8) & 0xff;
|
||||
*buf++ = (v >> 16) & 0xff;
|
||||
*buf++ = (v >> 24) & 0xff;
|
||||
*buf++ = (v >> 32) & 0xff;
|
||||
*buf++ = (v >> 40) & 0xff;
|
||||
*buf++ = (v >> 48) & 0xff;
|
||||
*buf = (v >> 56) & 0xff;
|
||||
}
|
||||
|
||||
/** out = in ^ b8.
|
||||
* out and in may alias. */
|
||||
static inline void xor_b8(uint8_t *out, const uint8_t *in, uint8_t b8, size_t len)
|
||||
{
|
||||
for (size_t i = 0; i < len; i++)
|
||||
out[i] = in[i] ^ b8;
|
||||
}
|
||||
|
||||
/** out = x ^ y.
|
||||
* out, x and y may alias. */
|
||||
static inline void xor_bb(uint8_t *out, const uint8_t *x, const uint8_t *y, size_t len)
|
||||
{
|
||||
for (size_t i = 0; i < len; i++)
|
||||
out[i] = x[i] ^ y[i];
|
||||
}
|
||||
|
||||
/* out ^= x
|
||||
* out and x may alias. */
|
||||
static inline void xor_words(uint32_t *out, const uint32_t *x, size_t nwords)
|
||||
{
|
||||
for (size_t i = 0; i < nwords; i++)
|
||||
out[i] ^= x[i];
|
||||
}
|
||||
|
||||
/** Produce 0xffffffff if x == y, zero otherwise, without branching. */
|
||||
static inline uint32_t mask_u32(uint32_t x, uint32_t y)
|
||||
{
|
||||
uint32_t diff = x ^ y;
|
||||
uint32_t diff_is_zero = ~diff & (diff - 1);
|
||||
return - (diff_is_zero >> 31);
|
||||
}
|
||||
|
||||
/** Product 0xff if x == y, zero otherwise, without branching. */
|
||||
static inline uint8_t mask_u8(uint32_t x, uint32_t y)
|
||||
{
|
||||
uint32_t diff = x ^ y;
|
||||
uint8_t diff_is_zero = ~diff & (diff - 1);
|
||||
return - (diff_is_zero >> 7);
|
||||
}
|
||||
|
||||
/** Select the ith entry from the given table of n values, in a side channel-silent
|
||||
* way. */
|
||||
static inline uint32_t select_u32(uint32_t i, volatile const uint32_t *tab, uint32_t n)
|
||||
{
|
||||
uint32_t r = 0;
|
||||
|
||||
for (uint32_t ii = 0; ii < n; ii++)
|
||||
{
|
||||
uint32_t mask = mask_u32(i, ii);
|
||||
r = (r & ~mask) | (tab[ii] & mask);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Select the ith entry from the given table of n values, in a side channel-silent
|
||||
* way. */
|
||||
static inline uint8_t select_u8(uint32_t i, volatile const uint8_t *tab, uint32_t n)
|
||||
{
|
||||
uint8_t r = 0;
|
||||
|
||||
for (uint32_t ii = 0; ii < n; ii++)
|
||||
{
|
||||
uint8_t mask = mask_u8(i, ii);
|
||||
r = (r & ~mask) | (tab[ii] & mask);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Select the ath, bth, cth and dth entries from the given table of n values,
|
||||
* placing the results into a, b, c and d. */
|
||||
static inline void select_u8x4(uint8_t *a, uint8_t *b, uint8_t *c, uint8_t *d,
|
||||
volatile const uint8_t *tab, uint32_t n)
|
||||
{
|
||||
uint8_t ra = 0,
|
||||
rb = 0,
|
||||
rc = 0,
|
||||
rd = 0;
|
||||
uint8_t mask;
|
||||
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
uint8_t item = tab[i];
|
||||
|
||||
mask = mask_u8(*a, i); ra = (ra & ~mask) | (item & mask);
|
||||
mask = mask_u8(*b, i); rb = (rb & ~mask) | (item & mask);
|
||||
mask = mask_u8(*c, i); rc = (rc & ~mask) | (item & mask);
|
||||
mask = mask_u8(*d, i); rd = (rd & ~mask) | (item & mask);
|
||||
}
|
||||
|
||||
*a = ra;
|
||||
*b = rb;
|
||||
*c = rc;
|
||||
*d = rd;
|
||||
}
|
||||
|
||||
/** out ^= if0 or if1, depending on the value of bit. */
|
||||
static inline void select_xor128(uint32_t out[4],
|
||||
const uint32_t if0[4],
|
||||
const uint32_t if1[4],
|
||||
uint8_t bit)
|
||||
{
|
||||
uint32_t mask1 = mask_u32(bit, 1);
|
||||
uint32_t mask0 = ~mask1;
|
||||
|
||||
out[0] ^= (if0[0] & mask0) | (if1[0] & mask1);
|
||||
out[1] ^= (if0[1] & mask0) | (if1[1] & mask1);
|
||||
out[2] ^= (if0[2] & mask0) | (if1[2] & mask1);
|
||||
out[3] ^= (if0[3] & mask0) | (if1[3] & mask1);
|
||||
}
|
||||
|
||||
/** Increments the integer stored at v (of non-zero length len)
|
||||
* with the least significant byte first. */
|
||||
static inline void incr_le(uint8_t *v, size_t len)
|
||||
{
|
||||
size_t i = 0;
|
||||
while (1)
|
||||
{
|
||||
if (++v[i] != 0)
|
||||
return;
|
||||
i++;
|
||||
if (i == len)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** Increments the integer stored at v (of non-zero length len)
|
||||
* with the most significant byte last. */
|
||||
static inline void incr_be(uint8_t *v, size_t len)
|
||||
{
|
||||
len--;
|
||||
while (1)
|
||||
{
|
||||
if (++v[len] != 0)
|
||||
return;
|
||||
if (len == 0)
|
||||
return;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
/** Copies len bytes from in to out, with in shifted left by offset bits
|
||||
* to the right. */
|
||||
static inline void copy_bytes_unaligned(uint8_t *out, const uint8_t *in, size_t len, uint8_t offset)
|
||||
{
|
||||
uint8_t byte_off = offset / 8;
|
||||
uint8_t bit_off = offset & 7;
|
||||
uint8_t rmask = (1 << bit_off) - 1;
|
||||
uint8_t lmask = ~rmask;
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
out[i] = (in[i + byte_off] << bit_off) & lmask;
|
||||
out[i] |= (in[i + byte_off + 1] >> (8 - bit_off)) & rmask;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t count_trailing_zeroes(uint32_t x)
|
||||
{
|
||||
return (uint32_t) __builtin_ctzl(x);
|
||||
}
|
||||
|
||||
#endif
|
195
User/lib/cifra/blockwise.c
Normal file
195
User/lib/cifra/blockwise.c
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and 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
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#include "blockwise.h"
|
||||
#include "bitops.h"
|
||||
#include "handy.h"
|
||||
#include "tassert.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void cf_blockwise_accumulate(uint8_t *partial, size_t *npartial, size_t nblock,
|
||||
const void *inp, size_t nbytes,
|
||||
cf_blockwise_in_fn process,
|
||||
void *ctx)
|
||||
{
|
||||
cf_blockwise_accumulate_final(partial, npartial, nblock,
|
||||
inp, nbytes,
|
||||
process, process, ctx);
|
||||
}
|
||||
|
||||
void cf_blockwise_accumulate_final(uint8_t *partial, size_t *npartial, size_t nblock,
|
||||
const void *inp, size_t nbytes,
|
||||
cf_blockwise_in_fn process,
|
||||
cf_blockwise_in_fn process_final,
|
||||
void *ctx)
|
||||
{
|
||||
const uint8_t *bufin = inp;
|
||||
assert(partial && *npartial < nblock);
|
||||
assert(inp || !nbytes);
|
||||
assert(process && ctx);
|
||||
|
||||
/* If we have partial data, copy in to buffer. */
|
||||
if (*npartial && nbytes)
|
||||
{
|
||||
size_t space = nblock - *npartial;
|
||||
size_t taken = MIN(space, nbytes);
|
||||
|
||||
memcpy(partial + *npartial, bufin, taken);
|
||||
|
||||
bufin += taken;
|
||||
nbytes -= taken;
|
||||
*npartial += taken;
|
||||
|
||||
/* If that gives us a full block, process it. */
|
||||
if (*npartial == nblock)
|
||||
{
|
||||
if (nbytes == 0)
|
||||
process_final(ctx, partial);
|
||||
else
|
||||
process(ctx, partial);
|
||||
*npartial = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* now nbytes < nblock or *npartial == 0. */
|
||||
|
||||
/* If we have a full block of data, process it directly. */
|
||||
while (nbytes >= nblock)
|
||||
{
|
||||
/* Partial buffer must be empty, or we're ignoring extant data */
|
||||
assert(*npartial == 0);
|
||||
|
||||
if (nbytes == nblock)
|
||||
process_final(ctx, bufin);
|
||||
else
|
||||
process(ctx, bufin);
|
||||
bufin += nblock;
|
||||
nbytes -= nblock;
|
||||
}
|
||||
|
||||
/* Finally, if we have remaining data, buffer it. */
|
||||
while (nbytes)
|
||||
{
|
||||
size_t space = nblock - *npartial;
|
||||
size_t taken = MIN(space, nbytes);
|
||||
|
||||
memcpy(partial + *npartial, bufin, taken);
|
||||
|
||||
bufin += taken;
|
||||
nbytes -= taken;
|
||||
*npartial += taken;
|
||||
|
||||
/* If we started with *npartial, we must have copied it
|
||||
* in first. */
|
||||
assert(*npartial < nblock);
|
||||
}
|
||||
}
|
||||
|
||||
void cf_blockwise_xor(uint8_t *partial, size_t *npartial, size_t nblock,
|
||||
const void *inp, void *outp, size_t nbytes,
|
||||
cf_blockwise_out_fn process, void *ctx)
|
||||
{
|
||||
const uint8_t *inb = inp;
|
||||
uint8_t *outb = outp;
|
||||
|
||||
assert(partial && *npartial < nblock);
|
||||
assert(inp || !nbytes);
|
||||
assert(process && ctx);
|
||||
|
||||
while (nbytes)
|
||||
{
|
||||
/* If we're out of material, and need more, produce a block. */
|
||||
if (*npartial == 0)
|
||||
{
|
||||
process(ctx, partial);
|
||||
*npartial = nblock;
|
||||
}
|
||||
|
||||
size_t offset = nblock - *npartial;
|
||||
size_t taken = MIN(*npartial, nbytes);
|
||||
xor_bb(outb, inb, partial + offset, taken);
|
||||
*npartial -= taken;
|
||||
nbytes -= taken;
|
||||
outb += taken;
|
||||
inb += taken;
|
||||
}
|
||||
}
|
||||
|
||||
void cf_blockwise_acc_byte(uint8_t *partial, size_t *npartial,
|
||||
size_t nblock,
|
||||
uint8_t byte, size_t nbytes,
|
||||
cf_blockwise_in_fn process,
|
||||
void *ctx)
|
||||
{
|
||||
/* only memset the whole of the block once */
|
||||
int filled = 0;
|
||||
|
||||
while (nbytes)
|
||||
{
|
||||
size_t start = *npartial;
|
||||
size_t count = MIN(nbytes, nblock - start);
|
||||
|
||||
if (!filled)
|
||||
memset(partial + start, byte, count);
|
||||
|
||||
if (start == 0 && count == nblock)
|
||||
filled = 1;
|
||||
|
||||
if (start + count == nblock)
|
||||
{
|
||||
process(ctx, partial);
|
||||
*npartial = 0;
|
||||
} else {
|
||||
*npartial += count;
|
||||
}
|
||||
|
||||
nbytes -= count;
|
||||
}
|
||||
}
|
||||
|
||||
void cf_blockwise_acc_pad(uint8_t *partial, size_t *npartial,
|
||||
size_t nblock,
|
||||
uint8_t fbyte, uint8_t mbyte, uint8_t lbyte,
|
||||
size_t nbytes,
|
||||
cf_blockwise_in_fn process,
|
||||
void *ctx)
|
||||
{
|
||||
|
||||
switch (nbytes)
|
||||
{
|
||||
case 0: break;
|
||||
case 1: fbyte ^= lbyte;
|
||||
cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
|
||||
break;
|
||||
case 2:
|
||||
cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
|
||||
cf_blockwise_accumulate(partial, npartial, nblock, &lbyte, 1, process, ctx);
|
||||
break;
|
||||
default:
|
||||
cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
|
||||
|
||||
/* If the middle and last bytes differ, then process the last byte separately.
|
||||
* Otherwise, just extend the middle block size. */
|
||||
if (lbyte != mbyte)
|
||||
{
|
||||
cf_blockwise_acc_byte(partial, npartial, nblock, mbyte, nbytes - 2, process, ctx);
|
||||
cf_blockwise_accumulate(partial, npartial, nblock, &lbyte, 1, process, ctx);
|
||||
} else {
|
||||
cf_blockwise_acc_byte(partial, npartial, nblock, mbyte, nbytes - 1, process, ctx);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
147
User/lib/cifra/blockwise.h
Normal file
147
User/lib/cifra/blockwise.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and 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
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef BLOCKWISE_H
|
||||
#define BLOCKWISE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* Processing function for cf_blockwise_accumulate. */
|
||||
typedef void (*cf_blockwise_in_fn)(void *ctx, const uint8_t *data);
|
||||
|
||||
/* Processing function for cf_blockwise_xor. */
|
||||
typedef void (*cf_blockwise_out_fn)(void *ctx, uint8_t *data);
|
||||
|
||||
/* This function manages the common abstraction of accumulating input in
|
||||
* a buffer, and processing it when a full block is available.
|
||||
*
|
||||
* partial is the buffer (maintained by the caller)
|
||||
* on entry, npartial is the currently valid count of used bytes on
|
||||
* the front of partial.
|
||||
* on exit, npartial is updated to reflect the status of partial.
|
||||
* nblock is the blocksize to accumulate -- partial must be at least
|
||||
* this long!
|
||||
* input is the new data to process, of length nbytes.
|
||||
* process is the processing function, passed ctx and a pointer
|
||||
* to the data to process (always exactly nblock bytes long!)
|
||||
* which may not neccessarily be the same as partial.
|
||||
*/
|
||||
void cf_blockwise_accumulate(uint8_t *partial, size_t *npartial,
|
||||
size_t nblock,
|
||||
const void *input, size_t nbytes,
|
||||
cf_blockwise_in_fn process,
|
||||
void *ctx);
|
||||
|
||||
/* This function manages the common abstraction of accumulating input in
|
||||
* a buffer, and processing it when a full block is available.
|
||||
* This version supports calling a different processing function for
|
||||
* the last block.
|
||||
*
|
||||
* partial is the buffer (maintained by the caller)
|
||||
* on entry, npartial is the currently valid count of used bytes on
|
||||
* the front of partial.
|
||||
* on exit, npartial is updated to reflect the status of partial.
|
||||
* nblock is the blocksize to accumulate -- partial must be at least
|
||||
* this long!
|
||||
* input is the new data to process, of length nbytes.
|
||||
* process is the processing function, passed ctx and a pointer
|
||||
* to the data to process (always exactly nblock bytes long!)
|
||||
* which may not neccessarily be the same as partial.
|
||||
* process_final is called last (but may not be called at all if
|
||||
* all input is buffered).
|
||||
*/
|
||||
void cf_blockwise_accumulate_final(uint8_t *partial, size_t *npartial,
|
||||
size_t nblock,
|
||||
const void *input, size_t nbytes,
|
||||
cf_blockwise_in_fn process,
|
||||
cf_blockwise_in_fn process_final,
|
||||
void *ctx);
|
||||
|
||||
/* This function manages XORing an input stream with a keystream
|
||||
* to produce an output stream. The keystream is produced in blocks
|
||||
* (ala a block cipher in counter mode).
|
||||
*
|
||||
* partial is the keystream buffer (maintained by the caller)
|
||||
* on entry, *npartial is the currently valid count of bytes in partial:
|
||||
* unused bytes are at the *end*. So *npartial = 4 means the last four
|
||||
* bytes of partial are usable as keystream.
|
||||
* on exit, npartial is updated to reflect the new state of partial.
|
||||
* nblock is the blocksize to accumulate -- partial must be at least
|
||||
* this long!
|
||||
* input is the new data to process, of length nbytes.
|
||||
* output is where to write input xored with the keystream -- also length
|
||||
* nbytes.
|
||||
* process is the processing function, passed ctx and partial which it
|
||||
* should fill with fresh key stream.
|
||||
*/
|
||||
void cf_blockwise_xor(uint8_t *partial, size_t *npartial,
|
||||
size_t nblock,
|
||||
const void *input, void *output, size_t nbytes,
|
||||
cf_blockwise_out_fn newblock,
|
||||
void *ctx);
|
||||
|
||||
/* This function processes a single byte a number of times. It's useful
|
||||
* for padding, and more efficient than calling cf_blockwise_accumulate
|
||||
* a bunch of times.
|
||||
*
|
||||
* partial is the buffer (maintained by the caller)
|
||||
* on entry, npartial is the currently valid count of used bytes on
|
||||
* the front of partial.
|
||||
* on exit, npartial is updated to reflect the status of partial.
|
||||
* nblock is the blocksize to accumulate -- partial must be at least
|
||||
* this long!
|
||||
* process is the processing function, passed ctx and a pointer
|
||||
* to the data to process (always exactly nblock bytes long!)
|
||||
* which may not neccessarily be the same as partial.
|
||||
* byte is the byte to process, nbytes times.
|
||||
*/
|
||||
void cf_blockwise_acc_byte(uint8_t *partial, size_t *npartial,
|
||||
size_t nblock,
|
||||
uint8_t byte, size_t nbytes,
|
||||
cf_blockwise_in_fn process,
|
||||
void *ctx);
|
||||
|
||||
/* This function attempts to process patterns of bytes common in
|
||||
* block cipher padding.
|
||||
*
|
||||
* This takes three bytes:
|
||||
* - a first byte, fbyte,
|
||||
* - a middle byte, mbyte,
|
||||
* - a last byte, lbyte.
|
||||
*
|
||||
* If nbytes is zero, nothing happens.
|
||||
* If nbytes is one, the byte fbyte ^ lbyte is processed.
|
||||
* If nbytes is two, the fbyte then lbyte are processed.
|
||||
* If nbytes is three or more, fbyte, then one or more mbytes, then fbyte
|
||||
* is processed.
|
||||
*
|
||||
* partial is the buffer (maintained by the caller)
|
||||
* on entry, npartial is the currently valid count of used bytes on
|
||||
* the front of partial.
|
||||
* on exit, npartial is updated to reflect the status of partial.
|
||||
* nblock is the blocksize to accumulate -- partial must be at least
|
||||
* this long!
|
||||
* process is the processing function, passed ctx and a pointer
|
||||
* to the data to process (always exactly nblock bytes long!)
|
||||
* which may not neccessarily be the same as partial.
|
||||
*/
|
||||
void cf_blockwise_acc_pad(uint8_t *partial, size_t *npartial,
|
||||
size_t nblock,
|
||||
uint8_t fbyte, uint8_t mbyte, uint8_t lbyte,
|
||||
size_t nbytes,
|
||||
cf_blockwise_in_fn process,
|
||||
void *ctx);
|
||||
|
||||
#endif
|
59
User/lib/cifra/cf_config.h
Normal file
59
User/lib/cifra/cf_config.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and 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
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef CF_CONFIG_H
|
||||
#define CF_CONFIG_H
|
||||
|
||||
/**
|
||||
* Library configuration
|
||||
* =====================
|
||||
*/
|
||||
|
||||
/* .. c:macro:: CF_SIDE_CHANNEL_PROTECTION
|
||||
* Define this as 1 if you need all available side channel protections.
|
||||
* **This option may alter the ABI**.
|
||||
*
|
||||
* This has a non-trivial performance penalty. Where a
|
||||
* side-channel free option is cheap or free (like checking
|
||||
* a MAC) this is always done in a side-channel free way.
|
||||
*
|
||||
* The default is **on** for all available protections.
|
||||
*/
|
||||
#ifndef CF_SIDE_CHANNEL_PROTECTION
|
||||
# define CF_SIDE_CHANNEL_PROTECTION 1
|
||||
#endif
|
||||
|
||||
/* .. c:macro:: CF_TIME_SIDE_CHANNEL_PROTECTION
|
||||
* Define this as 1 if you need timing/branch prediction side channel
|
||||
* protection.
|
||||
*
|
||||
* You probably want this. The default is on. */
|
||||
#ifndef CF_TIME_SIDE_CHANNEL_PROTECTION
|
||||
# define CF_TIME_SIDE_CHANNEL_PROTECTION CF_SIDE_CHANNEL_PROTECTION
|
||||
#endif
|
||||
|
||||
/* .. c:macro:: CF_CACHE_SIDE_CHANNEL_PROTECTION
|
||||
* Define this as 1 if you need cache side channel protection.
|
||||
*
|
||||
* If you have a microcontroller with no cache, you can turn this off
|
||||
* without negative effects.
|
||||
*
|
||||
* The default is on. This will have some performance impact,
|
||||
* especially on AES.
|
||||
*/
|
||||
#ifndef CF_CACHE_SIDE_CHANNEL_PROTECTION
|
||||
# define CF_CACHE_SIDE_CHANNEL_PROTECTION CF_SIDE_CHANNEL_PROTECTION
|
||||
#endif
|
||||
|
||||
#endif
|
28
User/lib/cifra/chash.c
Normal file
28
User/lib/cifra/chash.c
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and 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
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#include "chash.h"
|
||||
#include "handy.h"
|
||||
#include "tassert.h"
|
||||
|
||||
void cf_hash(const cf_chash *h, const void *m, size_t nm, uint8_t *out)
|
||||
{
|
||||
cf_chash_ctx ctx;
|
||||
assert(h);
|
||||
h->init(&ctx);
|
||||
h->update(&ctx, m, nm);
|
||||
h->digest(&ctx, out);
|
||||
mem_clean(&ctx, sizeof ctx);
|
||||
}
|
||||
|
137
User/lib/cifra/chash.h
Normal file
137
User/lib/cifra/chash.h
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and 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
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef CHASH_H
|
||||
#define CHASH_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* General hash function description
|
||||
* =================================
|
||||
* This allows us to make use of hash functions without depending
|
||||
* on a specific one. This is useful in implementing, for example,
|
||||
* :doc:`HMAC <hmac>`.
|
||||
*/
|
||||
|
||||
/* .. c:type:: cf_chash_init
|
||||
* Hashing initialisation function type.
|
||||
*
|
||||
* Functions of this type should initialise the context in preparation
|
||||
* for hashing a message with `cf_chash_update` functions.
|
||||
*
|
||||
* :rtype: void
|
||||
* :param ctx: hash function-specific context structure.
|
||||
*/
|
||||
typedef void (*cf_chash_init)(void *ctx);
|
||||
|
||||
/* .. c:type:: cf_chash_update
|
||||
* Hashing data processing function type.
|
||||
*
|
||||
* Functions of this type hash `count` bytes of data at `data`,
|
||||
* updating the contents of `ctx`.
|
||||
*
|
||||
* :rtype: void
|
||||
* :param ctx: hash function-specific context structure.
|
||||
* :param data: input data to hash.
|
||||
* :param count: number of bytes to hash.
|
||||
*/
|
||||
typedef void (*cf_chash_update)(void *ctx, const void *data, size_t count);
|
||||
|
||||
/* .. c:type:: cf_chash_digest
|
||||
* Hashing completion function type.
|
||||
*
|
||||
* Functions of this type complete a hashing operation,
|
||||
* writing :c:member:`cf_chash.hashsz` bytes to `hash`.
|
||||
*
|
||||
* This function does not change `ctx` -- any padding which needs doing
|
||||
* must be done seperately (in a copy of `ctx`, say).
|
||||
*
|
||||
* This means you can interlave `_update` and `_digest` calls to
|
||||
* learn `H(A)` and `H(A || B)` without hashing `A` twice.
|
||||
*
|
||||
* :rtype: void
|
||||
* :param ctx: hash function-specific context structure.
|
||||
* :param hash: location to write hash result.
|
||||
*/
|
||||
typedef void (*cf_chash_digest)(const void *ctx, uint8_t *hash);
|
||||
|
||||
/* .. c:type:: cf_chash
|
||||
* This type describes an incremental hash function in an abstract way.
|
||||
*
|
||||
* .. c:member:: cf_chash.hashsz
|
||||
* The hash function's output, in bytes.
|
||||
*
|
||||
* .. c:member:: cf_chash.blocksz
|
||||
* The hash function's internal block size, in bytes.
|
||||
*
|
||||
* .. c:member:: cf_chash.init
|
||||
* Context initialisation function.
|
||||
*
|
||||
* .. c:member:: cf_chash:update
|
||||
* Data processing function.
|
||||
*
|
||||
* .. c:member:: cf_chash:digest
|
||||
* Completion function.
|
||||
*
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
size_t hashsz;
|
||||
size_t blocksz;
|
||||
|
||||
cf_chash_init init;
|
||||
cf_chash_update update;
|
||||
cf_chash_digest digest;
|
||||
} cf_chash;
|
||||
|
||||
/* .. c:macro:: CF_CHASH_MAXCTX
|
||||
* The maximum size of a :c:type:`cf_chash_ctx`. This allows
|
||||
* use to put a structure in automatic storage that can
|
||||
* store working data for any supported hash function. */
|
||||
#define CF_CHASH_MAXCTX 390
|
||||
|
||||
/* .. c:macro:: CF_CHASH_MAXBLK
|
||||
* Maximum hash function block size (in bytes). */
|
||||
#define CF_CHASH_MAXBLK 128
|
||||
|
||||
/* .. c:macro:: CF_MAXHASH
|
||||
* Maximum hash function output (in bytes). */
|
||||
#define CF_MAXHASH 64
|
||||
|
||||
/* .. c:type:: cf_chash_ctx
|
||||
* A type usable with any `cf_chash` as a context. */
|
||||
typedef union
|
||||
{
|
||||
uint8_t ctx[CF_CHASH_MAXCTX];
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
} cf_chash_ctx;
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* One shot hashing: `out = h(m)`.
|
||||
*
|
||||
* Using the hash function `h`, `nm` bytes at `m` are hashed and `h->hashsz` bytes
|
||||
* of result is written to the buffer `out`.
|
||||
*
|
||||
* :param h: hash function description.
|
||||
* :param m: message buffer.
|
||||
* :param nm: message length.
|
||||
* :param out: hash result buffer (written).
|
||||
*/
|
||||
void cf_hash(const cf_chash *h, const void *m, size_t nm, uint8_t *out);
|
||||
|
||||
#endif
|
86
User/lib/cifra/handy.h
Normal file
86
User/lib/cifra/handy.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef HANDY_H
|
||||
#define HANDY_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Handy CPP defines and C inline functions.
|
||||
*/
|
||||
|
||||
/* Evaluates to the number of items in array-type variable arr. */
|
||||
#define ARRAYCOUNT(arr) (sizeof arr / sizeof arr[0])
|
||||
|
||||
/* Normal MIN/MAX macros. Evaluate argument expressions only once. */
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) \
|
||||
({ typeof (x) __x = (x); \
|
||||
typeof (y) __y = (y); \
|
||||
__x < __y ? __x : __y; })
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(x, y) \
|
||||
({ typeof (x) __x = (x); \
|
||||
typeof (y) __y = (y); \
|
||||
__x > __y ? __x : __y; })
|
||||
#endif
|
||||
|
||||
/* Swap two values. Uses GCC type inference magic. */
|
||||
#ifndef SWAP
|
||||
#define SWAP(x, y) \
|
||||
do { \
|
||||
typeof (x) __tmp = (x); \
|
||||
(x) = (y); \
|
||||
(y) = __tmp; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/** Stringify its argument. */
|
||||
#define STRINGIFY(x) STRINGIFY_(x)
|
||||
#define STRINGIFY_(x) #x
|
||||
|
||||
/* Error handling macros.
|
||||
*
|
||||
* These expect a zero = success, non-zero = error convention.
|
||||
*/
|
||||
|
||||
/** Error: return.
|
||||
*
|
||||
* If the expression fails, return the error from this function. */
|
||||
#define ER(expr) do { typeof (expr) err_ = (expr); if (err_) return err_; } while (0)
|
||||
|
||||
/** Error: goto.
|
||||
*
|
||||
* If the expression fails, goto x_err. Assumes defn of label
|
||||
* x_err and 'error_type err'. */
|
||||
#define EG(expr) do { err = (expr); if (err) goto x_err; } while (0)
|
||||
|
||||
/** Like memset(ptr, 0, len), but not allowed to be removed by
|
||||
* compilers. */
|
||||
static inline void mem_clean(volatile void *v, size_t len)
|
||||
{
|
||||
if (len)
|
||||
{
|
||||
memset((void *) v, 0, len);
|
||||
(void) *((volatile uint8_t *) v);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns 1 if len bytes at va equal len bytes at vb, 0 if they do not.
|
||||
* Does not leak length of common prefix through timing. */
|
||||
static inline unsigned mem_eq(const void *va, const void *vb, size_t len)
|
||||
{
|
||||
const volatile uint8_t *a = va;
|
||||
const volatile uint8_t *b = vb;
|
||||
uint8_t diff = 0;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
diff |= *a++ ^ *b++;
|
||||
}
|
||||
|
||||
return !diff;
|
||||
}
|
||||
|
||||
#endif
|
106
User/lib/cifra/hmac.c
Normal file
106
User/lib/cifra/hmac.c
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and 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
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#include "hmac.h"
|
||||
#include "chash.h"
|
||||
#include "bitops.h"
|
||||
#include "handy.h"
|
||||
#include "tassert.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void cf_hmac_init(cf_hmac_ctx *ctx,
|
||||
const cf_chash *hash,
|
||||
const uint8_t *key, size_t nkey)
|
||||
{
|
||||
assert(ctx);
|
||||
assert(hash);
|
||||
|
||||
mem_clean(ctx, sizeof *ctx);
|
||||
ctx->hash = hash;
|
||||
|
||||
/* Prepare key: */
|
||||
uint8_t k[CF_CHASH_MAXBLK];
|
||||
|
||||
/* Shorten long keys. */
|
||||
if (nkey > hash->blocksz)
|
||||
{
|
||||
/* Standard doesn't cover case where blocksz < hashsz.
|
||||
* FIPS186-1 seems to want to append a negative number of zero bytes.
|
||||
* In any case, we only have a k buffer of CF_CHASH_MAXBLK! */
|
||||
assert(hash->hashsz <= hash->blocksz);
|
||||
|
||||
cf_hash(hash, key, nkey, k);
|
||||
key = k;
|
||||
nkey = hash->hashsz;
|
||||
}
|
||||
|
||||
/* Right zero-pad short keys. */
|
||||
if (k != key)
|
||||
memcpy(k, key, nkey);
|
||||
if (hash->blocksz > nkey)
|
||||
memset(k + nkey, 0, hash->blocksz - nkey);
|
||||
|
||||
/* Start inner hash computation */
|
||||
uint8_t blk[CF_CHASH_MAXBLK];
|
||||
|
||||
xor_b8(blk, k, 0x36, hash->blocksz);
|
||||
hash->init(&ctx->inner);
|
||||
hash->update(&ctx->inner, blk, hash->blocksz);
|
||||
|
||||
/* And outer. */
|
||||
xor_b8(blk, k, 0x5c, hash->blocksz);
|
||||
hash->init(&ctx->outer);
|
||||
hash->update(&ctx->outer, blk, hash->blocksz);
|
||||
|
||||
mem_clean(blk, sizeof blk);
|
||||
mem_clean(k, sizeof k);
|
||||
}
|
||||
|
||||
void cf_hmac_update(cf_hmac_ctx *ctx, const void *data, size_t ndata)
|
||||
{
|
||||
assert(ctx && ctx->hash);
|
||||
|
||||
ctx->hash->update(&ctx->inner, data, ndata);
|
||||
}
|
||||
|
||||
void cf_hmac_finish(cf_hmac_ctx *ctx, uint8_t *out)
|
||||
{
|
||||
assert(ctx && ctx->hash);
|
||||
assert(out);
|
||||
|
||||
uint8_t innerh[CF_MAXHASH];
|
||||
ctx->hash->digest(&ctx->inner, innerh);
|
||||
|
||||
ctx->hash->update(&ctx->outer, innerh, ctx->hash->hashsz);
|
||||
ctx->hash->digest(&ctx->outer, out);
|
||||
|
||||
mem_clean(ctx, sizeof *ctx);
|
||||
}
|
||||
|
||||
void cf_hmac(const uint8_t *key, size_t nkey,
|
||||
const uint8_t *msg, size_t nmsg,
|
||||
uint8_t *out,
|
||||
const cf_chash *hash)
|
||||
{
|
||||
cf_hmac_ctx ctx;
|
||||
|
||||
assert(out);
|
||||
assert(hash);
|
||||
|
||||
cf_hmac_init(&ctx, hash, key, nkey);
|
||||
cf_hmac_update(&ctx, msg, nmsg);
|
||||
cf_hmac_finish(&ctx, out);
|
||||
}
|
||||
|
78
User/lib/cifra/hmac.h
Normal file
78
User/lib/cifra/hmac.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and 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
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef HMAC_H
|
||||
#define HMAC_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "chash.h"
|
||||
|
||||
/**
|
||||
* HMAC
|
||||
* ====
|
||||
* This is a one-shot and incremental interface to computing
|
||||
* HMAC with any hash function.
|
||||
*
|
||||
* (Note: HMAC with SHA3 is possible, but is probably not a
|
||||
* sensible thing to want.)
|
||||
*/
|
||||
|
||||
/* .. c:type:: cf_hmac_ctx
|
||||
* HMAC incremental interface context.
|
||||
*
|
||||
* .. c:member:: cf_hmac_ctx.hash
|
||||
* Hash function description.
|
||||
*
|
||||
* .. c:member:: cf_hmac_ctx.inner
|
||||
* Inner hash computation.
|
||||
*
|
||||
* .. c:member:: cf_hmac_ctx.outer
|
||||
* Outer hash computation.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
const cf_chash *hash;
|
||||
cf_chash_ctx inner;
|
||||
cf_chash_ctx outer;
|
||||
} cf_hmac_ctx;
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Set up ctx for computing a HMAC using the given hash and key. */
|
||||
void cf_hmac_init(cf_hmac_ctx *ctx,
|
||||
const cf_chash *hash,
|
||||
const uint8_t *key, size_t nkey);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Input data. */
|
||||
void cf_hmac_update(cf_hmac_ctx *ctx,
|
||||
const void *data, size_t ndata);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finish and compute HMAC.
|
||||
* `ctx->hash->hashsz` bytes are written to `out`. */
|
||||
void cf_hmac_finish(cf_hmac_ctx *ctx, uint8_t *out);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* One shot interface: compute `HMAC_hash(key, msg)`, writing the
|
||||
* answer (which is `hash->hashsz` long) to `out`.
|
||||
*
|
||||
* This function does not fail. */
|
||||
void cf_hmac(const uint8_t *key, size_t nkey,
|
||||
const uint8_t *msg, size_t nmsg,
|
||||
uint8_t *out,
|
||||
const cf_chash *hash);
|
||||
|
||||
#endif
|
64
User/lib/cifra/prp.h
Normal file
64
User/lib/cifra/prp.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and 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
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef PRP_H
|
||||
#define PRP_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* General block cipher description
|
||||
* ================================
|
||||
* This allows us to implement block cipher modes which can work
|
||||
* with different block ciphers.
|
||||
*/
|
||||
|
||||
/* .. c:type:: cf_prp_block
|
||||
* Block processing function type.
|
||||
*
|
||||
* The `in` and `out` blocks may alias.
|
||||
*
|
||||
* :rtype: void
|
||||
* :param ctx: block cipher-specific context object.
|
||||
* :param in: input block.
|
||||
* :param out: output block.
|
||||
*/
|
||||
typedef void (*cf_prp_block)(void *ctx, const uint8_t *in, uint8_t *out);
|
||||
|
||||
/* .. c:type:: cf_prp
|
||||
* Describes an PRP in a general way.
|
||||
*
|
||||
* .. c:member:: cf_prp.blocksz
|
||||
* Block size in bytes. Must be no more than :c:macro:`CF_MAXBLOCK`.
|
||||
*
|
||||
* .. c:member:: cf_prp.encrypt
|
||||
* Block encryption function.
|
||||
*
|
||||
* .. c:member:: cf_prp.decrypt
|
||||
* Block decryption function.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
size_t blocksz;
|
||||
cf_prp_block encrypt;
|
||||
cf_prp_block decrypt;
|
||||
} cf_prp;
|
||||
|
||||
/* .. c:macro:: CF_MAXBLOCK
|
||||
* The maximum block cipher blocksize we support, in bytes.
|
||||
*/
|
||||
#define CF_MAXBLOCK 16
|
||||
|
||||
#endif
|
235
User/lib/cifra/sha2.h
Normal file
235
User/lib/cifra/sha2.h
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and 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
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef SHA2_H
|
||||
#define SHA2_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "chash.h"
|
||||
|
||||
/**
|
||||
* SHA224/SHA256
|
||||
* =============
|
||||
*/
|
||||
|
||||
/* .. c:macro:: CF_SHA224_HASHSZ
|
||||
* The output size of SHA224: 28 bytes. */
|
||||
#define CF_SHA224_HASHSZ 28
|
||||
|
||||
/* .. c:macro:: CF_SHA224_BLOCKSZ
|
||||
* The block size of SHA224: 64 bytes. */
|
||||
#define CF_SHA224_BLOCKSZ 64
|
||||
|
||||
/* .. c:macro:: CF_SHA256_HASHSZ
|
||||
* The output size of SHA256: 32 bytes. */
|
||||
#define CF_SHA256_HASHSZ 32
|
||||
|
||||
/* .. c:macro:: CF_SHA256_BLOCKSZ
|
||||
* The block size of SHA256: 64 bytes. */
|
||||
#define CF_SHA256_BLOCKSZ 64
|
||||
|
||||
/* .. c:type:: cf_sha256_context
|
||||
* Incremental SHA256 hashing context.
|
||||
*
|
||||
* .. c:member:: cf_sha256_context.H
|
||||
* Intermediate values.
|
||||
*
|
||||
* .. c:member:: cf_sha256_context.partial
|
||||
* Unprocessed input.
|
||||
*
|
||||
* .. c:member:: cf_sha256_context.npartial
|
||||
* Number of bytes of unprocessed input.
|
||||
*
|
||||
* .. c:member:: cf_sha256_context.blocks
|
||||
* Number of full blocks processed.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t H[8]; /* State. */
|
||||
uint8_t partial[CF_SHA256_BLOCKSZ]; /* Partial block of input. */
|
||||
uint32_t blocks; /* Number of full blocks processed into H. */
|
||||
size_t npartial; /* Number of bytes in prefix of partial. */
|
||||
} cf_sha256_context;
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Sets up `ctx` ready to hash a new message.
|
||||
*/
|
||||
extern void cf_sha256_init(cf_sha256_context *ctx);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Hashes `nbytes` at `data`. Copies the data if there isn't enough to make
|
||||
* a full block.
|
||||
*/
|
||||
extern void cf_sha256_update(cf_sha256_context *ctx, const void *data, size_t nbytes);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finishes the hash operation, writing `CF_SHA256_HASHSZ` bytes to `hash`.
|
||||
*
|
||||
* This leaves `ctx` unchanged.
|
||||
*/
|
||||
extern void cf_sha256_digest(const cf_sha256_context *ctx, uint8_t hash[CF_SHA256_HASHSZ]);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finishes the hash operation, writing `CF_SHA256_HASHSZ` bytes to `hash`.
|
||||
*
|
||||
* This destroys `ctx`, but uses less stack than :c:func:`cf_sha256_digest`.
|
||||
*/
|
||||
extern void cf_sha256_digest_final(cf_sha256_context *ctx, uint8_t hash[CF_SHA256_HASHSZ]);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Sets up `ctx` ready to hash a new message.
|
||||
*
|
||||
* nb. SHA224 uses SHA256's underlying types.
|
||||
*/
|
||||
extern void cf_sha224_init(cf_sha256_context *ctx);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Hashes `nbytes` at `data`. Copies the data if there isn't enough to make
|
||||
* a full block.
|
||||
*/
|
||||
extern void cf_sha224_update(cf_sha256_context *ctx, const void *data, size_t nbytes);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finishes the hash operation, writing `CF_SHA224_HASHSZ` bytes to `hash`.
|
||||
*
|
||||
* This leaves `ctx` unchanged.
|
||||
*/
|
||||
extern void cf_sha224_digest(const cf_sha256_context *ctx, uint8_t hash[CF_SHA224_HASHSZ]);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finishes the hash operation, writing `CF_SHA224_HASHSZ` bytes to `hash`.
|
||||
*
|
||||
* This destroys `ctx`, but uses less stack than :c:func:`cf_sha224_digest`.
|
||||
*/
|
||||
extern void cf_sha224_digest_final(cf_sha256_context *ctx, uint8_t hash[CF_SHA224_HASHSZ]);
|
||||
|
||||
/* .. c:var:: cf_sha224
|
||||
* Abstract interface to SHA224. See :c:type:`cf_chash` for more information.
|
||||
*/
|
||||
extern const cf_chash cf_sha224;
|
||||
|
||||
/* .. c:var:: cf_sha256
|
||||
* Abstract interface to SHA256. See :c:type:`cf_chash` for more information.
|
||||
*/
|
||||
extern const cf_chash cf_sha256;
|
||||
|
||||
/**
|
||||
* SHA384/SHA512
|
||||
* =============
|
||||
*/
|
||||
|
||||
/* .. c:macro:: CF_SHA384_HASHSZ
|
||||
* The output size of SHA384: 48 bytes. */
|
||||
#define CF_SHA384_HASHSZ 48
|
||||
|
||||
/* .. c:macro:: CF_SHA384_BLOCKSZ
|
||||
* The block size of SHA384: 128 bytes. */
|
||||
#define CF_SHA384_BLOCKSZ 128
|
||||
|
||||
/* .. c:macro:: CF_SHA512_HASHSZ
|
||||
* The output size of SHA512: 64 bytes. */
|
||||
#define CF_SHA512_HASHSZ 64
|
||||
|
||||
/* .. c:macro:: CF_SHA512_BLOCKSZ
|
||||
* The block size of SHA512: 128 bytes. */
|
||||
#define CF_SHA512_BLOCKSZ 128
|
||||
|
||||
/* .. c:type:: cf_sha512_context
|
||||
* Incremental SHA512 hashing context.
|
||||
*
|
||||
* .. c:member:: cf_sha512_context.H
|
||||
* Intermediate values.
|
||||
*
|
||||
* .. c:member:: cf_sha512_context.partial
|
||||
* Unprocessed input.
|
||||
*
|
||||
* .. c:member:: cf_sha512_context.npartial
|
||||
* Number of bytes of unprocessed input.
|
||||
*
|
||||
* .. c:member:: cf_sha512_context.blocks
|
||||
* Number of full blocks processed.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint64_t H[8];
|
||||
uint8_t partial[CF_SHA512_BLOCKSZ];
|
||||
uint32_t blocks;
|
||||
size_t npartial;
|
||||
} cf_sha512_context;
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Sets up `ctx` ready to hash a new message.
|
||||
*/
|
||||
extern void cf_sha512_init(cf_sha512_context *ctx);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Hashes `nbytes` at `data`. Copies the data if there isn't enough to make
|
||||
* a full block.
|
||||
*/
|
||||
extern void cf_sha512_update(cf_sha512_context *ctx, const void *data, size_t nbytes);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finishes the hash operation, writing `CF_SHA512_HASHSZ` bytes to `hash`.
|
||||
*
|
||||
* This leaves `ctx` unchanged.
|
||||
*/
|
||||
extern void cf_sha512_digest(const cf_sha512_context *ctx, uint8_t hash[CF_SHA512_HASHSZ]);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finishes the hash operation, writing `CF_SHA512_HASHSZ` bytes to `hash`.
|
||||
*
|
||||
* This destroys `ctx`, but uses less stack than :c:func:`cf_sha512_digest`.
|
||||
*/
|
||||
extern void cf_sha512_digest_final(cf_sha512_context *ctx, uint8_t hash[CF_SHA512_HASHSZ]);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Sets up `ctx` ready to hash a new message.
|
||||
*
|
||||
* nb. SHA384 uses SHA512's underlying types.
|
||||
*/
|
||||
extern void cf_sha384_init(cf_sha512_context *ctx);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Hashes `nbytes` at `data`. Copies the data if there isn't enough to make
|
||||
* a full block.
|
||||
*/
|
||||
extern void cf_sha384_update(cf_sha512_context *ctx, const void *data, size_t nbytes);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finishes the hash operation, writing `CF_SHA384_HASHSZ` bytes to `hash`.
|
||||
*
|
||||
* This leaves `ctx` unchanged.
|
||||
*/
|
||||
extern void cf_sha384_digest(const cf_sha512_context *ctx, uint8_t hash[CF_SHA384_HASHSZ]);
|
||||
|
||||
/* .. c:function:: $DECL
|
||||
* Finishes the hash operation, writing `CF_SHA384_HASHSZ` bytes to `hash`.
|
||||
*
|
||||
* This destroys `ctx`, but uses less stack than :c:func:`cf_sha384_digest`.
|
||||
*/
|
||||
extern void cf_sha384_digest_final(cf_sha512_context *ctx, uint8_t hash[CF_SHA384_HASHSZ]);
|
||||
|
||||
/* .. c:var:: cf_sha384
|
||||
* Abstract interface to SHA384. See :c:type:`cf_chash` for more information.
|
||||
*/
|
||||
extern const cf_chash cf_sha384;
|
||||
|
||||
/* .. c:var:: cf_sha512
|
||||
* Abstract interface to SHA512. See :c:type:`cf_chash` for more information.
|
||||
*/
|
||||
extern const cf_chash cf_sha512;
|
||||
|
||||
#endif
|
231
User/lib/cifra/sha256.c
Normal file
231
User/lib/cifra/sha256.c
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and 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
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "sha2.h"
|
||||
#include "blockwise.h"
|
||||
#include "bitops.h"
|
||||
#include "handy.h"
|
||||
#include "tassert.h"
|
||||
|
||||
static const uint32_t K[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
# define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
|
||||
# define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
# define BSIG0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22))
|
||||
# define BSIG1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25))
|
||||
# define SSIG0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3))
|
||||
# define SSIG1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10))
|
||||
|
||||
void cf_sha256_init(cf_sha256_context *ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof *ctx);
|
||||
ctx->H[0] = 0x6a09e667;
|
||||
ctx->H[1] = 0xbb67ae85;
|
||||
ctx->H[2] = 0x3c6ef372;
|
||||
ctx->H[3] = 0xa54ff53a;
|
||||
ctx->H[4] = 0x510e527f;
|
||||
ctx->H[5] = 0x9b05688c;
|
||||
ctx->H[6] = 0x1f83d9ab;
|
||||
ctx->H[7] = 0x5be0cd19;
|
||||
}
|
||||
|
||||
void cf_sha224_init(cf_sha256_context *ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof *ctx);
|
||||
ctx->H[0] = 0xc1059ed8;
|
||||
ctx->H[1] = 0x367cd507;
|
||||
ctx->H[2] = 0x3070dd17;
|
||||
ctx->H[3] = 0xf70e5939;
|
||||
ctx->H[4] = 0xffc00b31;
|
||||
ctx->H[5] = 0x68581511;
|
||||
ctx->H[6] = 0x64f98fa7;
|
||||
ctx->H[7] = 0xbefa4fa4;
|
||||
}
|
||||
|
||||
static void sha256_update_block(void *vctx, const uint8_t *inp)
|
||||
{
|
||||
cf_sha256_context *ctx = vctx;
|
||||
|
||||
/* This is a 16-word window into the whole W array. */
|
||||
uint32_t W[16];
|
||||
|
||||
uint32_t a = ctx->H[0],
|
||||
b = ctx->H[1],
|
||||
c = ctx->H[2],
|
||||
d = ctx->H[3],
|
||||
e = ctx->H[4],
|
||||
f = ctx->H[5],
|
||||
g = ctx->H[6],
|
||||
h = ctx->H[7],
|
||||
Wt;
|
||||
|
||||
for (size_t t = 0; t < 64; t++)
|
||||
{
|
||||
/* For W[0..16] we process the input into W.
|
||||
* For W[16..64] we compute the next W value:
|
||||
*
|
||||
* W[t] = SSIG1(W[t - 2]) + W[t - 7] + SSIG0(W[t - 15]) + W[t - 16];
|
||||
*
|
||||
* But all W indices are reduced mod 16 into our window.
|
||||
*/
|
||||
if (t < 16)
|
||||
{
|
||||
W[t] = Wt = read32_be(inp);
|
||||
inp += 4;
|
||||
} else {
|
||||
Wt = SSIG1(W[(t - 2) % 16]) +
|
||||
W[(t - 7) % 16] +
|
||||
SSIG0(W[(t - 15) % 16]) +
|
||||
W[(t - 16) % 16];
|
||||
W[t % 16] = Wt;
|
||||
}
|
||||
|
||||
uint32_t T1 = h + BSIG1(e) + CH(e, f, g) + K[t] + Wt;
|
||||
uint32_t T2 = BSIG0(a) + MAJ(a, b, c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + T1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = T1 + T2;
|
||||
}
|
||||
|
||||
ctx->H[0] += a;
|
||||
ctx->H[1] += b;
|
||||
ctx->H[2] += c;
|
||||
ctx->H[3] += d;
|
||||
ctx->H[4] += e;
|
||||
ctx->H[5] += f;
|
||||
ctx->H[6] += g;
|
||||
ctx->H[7] += h;
|
||||
|
||||
ctx->blocks++;
|
||||
}
|
||||
|
||||
void cf_sha256_update(cf_sha256_context *ctx, const void *data, size_t nbytes)
|
||||
{
|
||||
cf_blockwise_accumulate(ctx->partial, &ctx->npartial, sizeof ctx->partial,
|
||||
data, nbytes,
|
||||
sha256_update_block, ctx);
|
||||
}
|
||||
|
||||
void cf_sha224_update(cf_sha256_context *ctx, const void *data, size_t nbytes)
|
||||
{
|
||||
cf_sha256_update(ctx, data, nbytes);
|
||||
}
|
||||
|
||||
void cf_sha256_digest(const cf_sha256_context *ctx, uint8_t hash[CF_SHA256_HASHSZ])
|
||||
{
|
||||
/* We copy the context, so the finalisation doesn't effect the caller's
|
||||
* context. This means the caller can do:
|
||||
*
|
||||
* x = init()
|
||||
* x.update('hello')
|
||||
* h1 = x.digest()
|
||||
* x.update(' world')
|
||||
* h2 = x.digest()
|
||||
*
|
||||
* to get h1 = H('hello') and h2 = H('hello world')
|
||||
*
|
||||
* This wouldn't work if we applied MD-padding to *ctx.
|
||||
*/
|
||||
|
||||
cf_sha256_context ours = *ctx;
|
||||
cf_sha256_digest_final(&ours, hash);
|
||||
}
|
||||
|
||||
void cf_sha256_digest_final(cf_sha256_context *ctx, uint8_t hash[CF_SHA256_HASHSZ])
|
||||
{
|
||||
uint64_t digested_bytes = ctx->blocks;
|
||||
digested_bytes = digested_bytes * CF_SHA256_BLOCKSZ + ctx->npartial;
|
||||
uint64_t digested_bits = digested_bytes * 8;
|
||||
|
||||
size_t padbytes = CF_SHA256_BLOCKSZ - ((digested_bytes + 8) % CF_SHA256_BLOCKSZ);
|
||||
|
||||
/* Hash 0x80 00 ... block first. */
|
||||
cf_blockwise_acc_pad(ctx->partial, &ctx->npartial, sizeof ctx->partial,
|
||||
0x80, 0x00, 0x00, padbytes,
|
||||
sha256_update_block, ctx);
|
||||
|
||||
/* Now hash length. */
|
||||
uint8_t buf[8];
|
||||
write64_be(digested_bits, buf);
|
||||
cf_sha256_update(ctx, buf, 8);
|
||||
|
||||
/* We ought to have got our padding calculation right! */
|
||||
assert(ctx->npartial == 0);
|
||||
|
||||
write32_be(ctx->H[0], hash + 0);
|
||||
write32_be(ctx->H[1], hash + 4);
|
||||
write32_be(ctx->H[2], hash + 8);
|
||||
write32_be(ctx->H[3], hash + 12);
|
||||
write32_be(ctx->H[4], hash + 16);
|
||||
write32_be(ctx->H[5], hash + 20);
|
||||
write32_be(ctx->H[6], hash + 24);
|
||||
write32_be(ctx->H[7], hash + 28);
|
||||
|
||||
memset(ctx, 0, sizeof *ctx);
|
||||
}
|
||||
|
||||
void cf_sha224_digest(const cf_sha256_context *ctx, uint8_t hash[CF_SHA224_HASHSZ])
|
||||
{
|
||||
uint8_t full[CF_SHA256_HASHSZ];
|
||||
cf_sha256_digest(ctx, full);
|
||||
memcpy(hash, full, CF_SHA224_HASHSZ);
|
||||
}
|
||||
|
||||
void cf_sha224_digest_final(cf_sha256_context *ctx, uint8_t hash[CF_SHA224_HASHSZ])
|
||||
{
|
||||
uint8_t full[CF_SHA256_HASHSZ];
|
||||
cf_sha256_digest_final(ctx, full);
|
||||
memcpy(hash, full, CF_SHA224_HASHSZ);
|
||||
}
|
||||
|
||||
const cf_chash cf_sha224 = {
|
||||
.hashsz = CF_SHA224_HASHSZ,
|
||||
.blocksz = CF_SHA256_BLOCKSZ,
|
||||
.init = (cf_chash_init) cf_sha224_init,
|
||||
.update = (cf_chash_update) cf_sha224_update,
|
||||
.digest = (cf_chash_digest) cf_sha224_digest
|
||||
};
|
||||
|
||||
const cf_chash cf_sha256 = {
|
||||
.hashsz = CF_SHA256_HASHSZ,
|
||||
.blocksz = CF_SHA256_BLOCKSZ,
|
||||
.init = (cf_chash_init) cf_sha256_init,
|
||||
.update = (cf_chash_update) cf_sha256_update,
|
||||
.digest = (cf_chash_digest) cf_sha256_digest
|
||||
};
|
||||
|
32
User/lib/cifra/tassert.h
Normal file
32
User/lib/cifra/tassert.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* cifra - embedded cryptography library
|
||||
* Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
|
||||
*
|
||||
* To the extent possible under law, the author(s) have dedicated all
|
||||
* copyright and related and 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
|
||||
* <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#ifndef TASSERT_H
|
||||
#define TASSERT_H
|
||||
|
||||
/* Tiny assert
|
||||
* -----------
|
||||
*
|
||||
* This is an assert(3) definition which doesn't include any
|
||||
* strings, but just branches to abort(3) on failure.
|
||||
*/
|
||||
|
||||
#ifndef FULL_FAT_ASSERT
|
||||
# include <stdlib.h>
|
||||
# define assert(expr) do { if (!(expr)) abort(); } while (0)
|
||||
#else
|
||||
# include <assert.h>
|
||||
#endif
|
||||
|
||||
#endif
|
26
User/lib/config.c
Normal file
26
User/lib/config.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "config.h"
|
||||
#include "ch32v30x_flash.h"
|
||||
|
||||
PersistentData_t persistent;
|
||||
|
||||
void loadConfig() {
|
||||
memcpy (&persistent, FLASH_USER_PAGE_ADDR, sizeof (persistent));
|
||||
uint32_t crcSum = *((uint32_t *)(((uint8_t *)&persistent) + (sizeof (persistent) - 2)));
|
||||
memset ((((uint8_t *)&persistent) + (sizeof (persistent) - sizeof(crcSum))), 0, 4);
|
||||
CRC_ResetDR();
|
||||
uint32_t currentSum = CRC_CalcBlockCRC ((uint32_t *)&persistent, sizeof (persistent) - 2);
|
||||
|
||||
if (currentSum != crcSum) {
|
||||
memset (&persistent, 0, sizeof (persistent));
|
||||
}
|
||||
}
|
||||
|
||||
void saveConfig() {
|
||||
CRC_ResetDR();
|
||||
uint32_t currentSum = CRC_CalcBlockCRC ((uint32_t *)&persistent, sizeof (persistent) - 2);
|
||||
memcpy ((((uint8_t *)&persistent) + (sizeof (persistent) - sizeof(currentSum))), (uint8_t *)currentSum, 4);
|
||||
FLASH_Unlock();
|
||||
FLASH_ErasePage_Fast (1919);
|
||||
FLASH_ProgramPage_Fast (1919, (uint32_t *)&persistent);
|
||||
FLASH_Lock();
|
||||
}
|
22
User/lib/config.h
Normal file
22
User/lib/config.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef CONFIG_HEADER
|
||||
#define CONFIG_HEADER
|
||||
#include "stdint.h"
|
||||
#include "string.h"
|
||||
|
||||
#define FLASH_USER_PAGE_ADDR ((const void *)(0x08077F00))
|
||||
|
||||
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];
|
||||
uint32_t crc32; // integrity check
|
||||
} PersistentData_t;
|
||||
|
||||
extern PersistentData_t persistent;
|
||||
|
||||
void saveConfig();
|
||||
void loadConfig();
|
||||
#endif
|
536
User/lib/monocypher/monocypher-ed25519.c
Normal file
536
User/lib/monocypher/monocypher-ed25519.c
Normal file
@@ -0,0 +1,536 @@
|
||||
// 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<73><6E>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
|
144
User/lib/monocypher/monocypher-ed25519.h
Normal file
144
User/lib/monocypher/monocypher-ed25519.h
Normal file
@@ -0,0 +1,144 @@
|
||||
// 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
|
2956
User/lib/monocypher/monocypher.c
Normal file
2956
User/lib/monocypher/monocypher.c
Normal file
File diff suppressed because it is too large
Load Diff
321
User/lib/monocypher/monocypher.h
Normal file
321
User/lib/monocypher/monocypher.h
Normal file
@@ -0,0 +1,321 @@
|
||||
// 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
|
255
User/lib/rtc/rtc.c
Normal file
255
User/lib/rtc/rtc.c
Normal file
@@ -0,0 +1,255 @@
|
||||
#include "stdint.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "rtc.h"
|
||||
|
||||
_calendar_obj calendar;
|
||||
|
||||
|
||||
uint8_t const table_week[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
|
||||
const uint8_t mon_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_NVIC_Config
|
||||
*
|
||||
* @brief Initializes RTC Int.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void RTC_NVIC_Config (void) {
|
||||
NVIC_InitTypeDef NVIC_InitStructure = {0};
|
||||
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
|
||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||
NVIC_Init (&NVIC_InitStructure);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn Is_Leap_Year
|
||||
*
|
||||
* @brief Judging whether it is a leap year.
|
||||
*
|
||||
* @param year
|
||||
*
|
||||
* @return 1 - Yes
|
||||
* 0 - No
|
||||
*/
|
||||
uint8_t Is_Leap_Year (u16 year) {
|
||||
if (year % 4 == 0) {
|
||||
if (year % 100 == 0) {
|
||||
if (year % 400 == 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
} else
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Set
|
||||
*
|
||||
* @brief Set Time.
|
||||
*
|
||||
* @param Struct of _calendar_obj
|
||||
*
|
||||
* @return 1 - error
|
||||
* 0 - success
|
||||
*/
|
||||
uint8_t RTC_Set (u16 syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec) {
|
||||
u16 t;
|
||||
u32 seccount = 0;
|
||||
if (syear < 1970 || syear > 2099)
|
||||
return 1;
|
||||
for (t = 1970; t < syear; t++) {
|
||||
if (Is_Leap_Year (t))
|
||||
seccount += 31622400;
|
||||
else
|
||||
seccount += 31536000;
|
||||
}
|
||||
smon -= 1;
|
||||
for (t = 0; t < smon; t++) {
|
||||
seccount += (u32)mon_table[t] * 86400;
|
||||
if (Is_Leap_Year (syear) && t == 1)
|
||||
seccount += 86400;
|
||||
}
|
||||
seccount += (u32)(sday - 1) * 86400;
|
||||
seccount += (u32)hour * 3600;
|
||||
seccount += (u32)min * 60;
|
||||
seccount += sec;
|
||||
|
||||
RCC_APB1PeriphClockCmd (RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
|
||||
PWR_BackupAccessCmd (ENABLE);
|
||||
RTC_SetCounter (seccount);
|
||||
RTC_WaitForLastTask();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Alarm_Set
|
||||
*
|
||||
* @brief Set Alarm Time.
|
||||
*
|
||||
* @param Struct of _calendar_obj
|
||||
*
|
||||
* @return 1 - error
|
||||
* 0 - success
|
||||
*/
|
||||
uint8_t RTC_Alarm_Set (u16 syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec) {
|
||||
u16 t;
|
||||
u32 seccount = 0;
|
||||
if (syear < 1970 || syear > 2099)
|
||||
return 1;
|
||||
for (t = 1970; t < syear; t++) {
|
||||
if (Is_Leap_Year (t))
|
||||
seccount += 31622400;
|
||||
else
|
||||
seccount += 31536000;
|
||||
}
|
||||
smon -= 1;
|
||||
for (t = 0; t < smon; t++) {
|
||||
seccount += (u32)mon_table[t] * 86400;
|
||||
if (Is_Leap_Year (syear) && t == 1)
|
||||
seccount += 86400;
|
||||
}
|
||||
seccount += (u32)(sday - 1) * 86400;
|
||||
seccount += (u32)hour * 3600;
|
||||
seccount += (u32)min * 60;
|
||||
seccount += sec;
|
||||
|
||||
RCC_APB1PeriphClockCmd (RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
|
||||
PWR_BackupAccessCmd (ENABLE);
|
||||
RTC_SetAlarm (seccount);
|
||||
RTC_WaitForLastTask();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Get_Week
|
||||
*
|
||||
* @brief Get the current day of the week.
|
||||
*
|
||||
* @param year/month/day
|
||||
*
|
||||
* @return week
|
||||
*/
|
||||
uint8_t RTC_Get_Week (u16 year, uint8_t month, uint8_t day) {
|
||||
u16 temp2;
|
||||
uint8_t yearH, yearL;
|
||||
|
||||
yearH = year / 100;
|
||||
yearL = year % 100;
|
||||
if (yearH > 19)
|
||||
yearL += 100;
|
||||
temp2 = yearL + yearL / 4;
|
||||
temp2 = temp2 % 7;
|
||||
temp2 = temp2 + day + table_week[month - 1];
|
||||
if (yearL % 4 == 0 && month < 3)
|
||||
temp2--;
|
||||
return (temp2 % 7);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Get
|
||||
*
|
||||
* @brief Get current time.
|
||||
*
|
||||
* @return 1 - error
|
||||
* 0 - success
|
||||
*/
|
||||
uint8_t RTC_Get (void) {
|
||||
static u16 daycnt = 0;
|
||||
u32 timecount = 0;
|
||||
u32 temp = 0;
|
||||
u16 temp1 = 0;
|
||||
timecount = RTC_GetCounter();
|
||||
temp = timecount / 86400;
|
||||
if (daycnt != temp) {
|
||||
daycnt = temp;
|
||||
temp1 = 1970;
|
||||
while (temp >= 365) {
|
||||
if (Is_Leap_Year (temp1)) {
|
||||
if (temp >= 366)
|
||||
temp -= 366;
|
||||
else {
|
||||
break;
|
||||
}
|
||||
} else
|
||||
temp -= 365;
|
||||
temp1++;
|
||||
}
|
||||
calendar.w_year = temp1;
|
||||
temp1 = 0;
|
||||
while (temp >= 28) {
|
||||
if (Is_Leap_Year (calendar.w_year) && temp1 == 1) {
|
||||
if (temp >= 29)
|
||||
temp -= 29;
|
||||
else
|
||||
break;
|
||||
} else {
|
||||
if (temp >= mon_table[temp1])
|
||||
temp -= mon_table[temp1];
|
||||
else
|
||||
break;
|
||||
}
|
||||
temp1++;
|
||||
}
|
||||
calendar.w_month = temp1 + 1;
|
||||
calendar.w_date = temp + 1;
|
||||
}
|
||||
temp = timecount % 86400;
|
||||
calendar.hour = temp / 3600;
|
||||
calendar.min = (temp % 3600) / 60;
|
||||
calendar.sec = (temp % 3600) % 60;
|
||||
calendar.week = RTC_Get_Week (calendar.w_year, calendar.w_month, calendar.w_date);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Init
|
||||
*
|
||||
* @brief Initializes RTC collection.
|
||||
*
|
||||
* @return 1 - Init Fail
|
||||
* 0 - Init Success
|
||||
*/
|
||||
uint8_t RTC_Init (void) {
|
||||
uint8_t temp = 0;
|
||||
RCC_APB1PeriphClockCmd (RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
|
||||
PWR_BackupAccessCmd (ENABLE);
|
||||
RTC_ClearITPendingBit (RTC_IT_ALR);
|
||||
RTC_ClearITPendingBit (RTC_IT_SEC);
|
||||
|
||||
/* Is it the first configuration */
|
||||
|
||||
BKP_DeInit();
|
||||
RCC_LSEConfig (RCC_LSE_ON);
|
||||
while (RCC_GetFlagStatus (RCC_FLAG_LSERDY) == RESET && temp < 250) {
|
||||
temp++;
|
||||
vTaskDelay (pdMS_TO_TICKS (20));
|
||||
}
|
||||
if (temp >= 250)
|
||||
return 1;
|
||||
RCC_RTCCLKConfig (RCC_RTCCLKSource_LSE);
|
||||
RCC_RTCCLKCmd (ENABLE);
|
||||
RTC_WaitForLastTask();
|
||||
RTC_WaitForSynchro();
|
||||
RTC_ITConfig (RTC_IT_SEC, DISABLE);
|
||||
RTC_ITConfig (RTC_IT_ALR, DISABLE);
|
||||
RTC_ITConfig (RTC_IT_OW, DISABLE);
|
||||
RTC_WaitForLastTask();
|
||||
RTC_EnterConfigMode();
|
||||
RTC_SetPrescaler (32767);
|
||||
RTC_WaitForLastTask();
|
||||
RTC_Set (2025, 9, 7, 11, 33, 30); /* Setup Time */
|
||||
RTC_ExitConfigMode();
|
||||
BKP_WriteBackupRegister (BKP_DR1, 0XA1A1);
|
||||
|
||||
RTC_NVIC_Config();
|
||||
RTC_Get();
|
||||
|
||||
return 0;
|
||||
}
|
95
User/lib/rtc/rtc.h
Normal file
95
User/lib/rtc/rtc.h
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "stdint.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
volatile uint8_t hour;
|
||||
volatile uint8_t min;
|
||||
volatile uint8_t sec;
|
||||
|
||||
volatile uint16_t w_year;
|
||||
volatile uint8_t w_month;
|
||||
volatile uint8_t w_date;
|
||||
volatile uint8_t week;
|
||||
} _calendar_obj;
|
||||
|
||||
extern _calendar_obj calendar;
|
||||
|
||||
|
||||
extern uint8_t const table_week[12];
|
||||
extern const uint8_t mon_table[12];
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_NVIC_Config
|
||||
*
|
||||
* @brief Initializes RTC Int.
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void RTC_NVIC_Config (void);
|
||||
/*********************************************************************
|
||||
* @fn Is_Leap_Year
|
||||
*
|
||||
* @brief Judging whether it is a leap year.
|
||||
*
|
||||
* @param year
|
||||
*
|
||||
* @return 1 - Yes
|
||||
* 0 - No
|
||||
*/
|
||||
uint8_t Is_Leap_Year (u16 year);
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Set
|
||||
*
|
||||
* @brief Set Time.
|
||||
*
|
||||
* @param Struct of _calendar_obj
|
||||
*
|
||||
* @return 1 - error
|
||||
* 0 - success
|
||||
*/
|
||||
uint8_t RTC_Set (u16 syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec) ;
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Alarm_Set
|
||||
*
|
||||
* @brief Set Alarm Time.
|
||||
*
|
||||
* @param Struct of _calendar_obj
|
||||
*
|
||||
* @return 1 - error
|
||||
* 0 - success
|
||||
*/
|
||||
uint8_t RTC_Alarm_Set (u16 syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec) ;
|
||||
/*********************************************************************
|
||||
* @fn RTC_Get_Week
|
||||
*
|
||||
* @brief Get the current day of the week.
|
||||
*
|
||||
* @param year/month/day
|
||||
*
|
||||
* @return week
|
||||
*/
|
||||
uint8_t RTC_Get_Week (u16 year, uint8_t month, uint8_t day) ;
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Get
|
||||
*
|
||||
* @brief Get current time.
|
||||
*
|
||||
* @return 1 - error
|
||||
* 0 - success
|
||||
*/
|
||||
uint8_t RTC_Get (void) ;
|
||||
|
||||
/*********************************************************************
|
||||
* @fn RTC_Init
|
||||
*
|
||||
* @brief Initializes RTC collection.
|
||||
*
|
||||
* @return 1 - Init Fail
|
||||
* 0 - Init Success
|
||||
*/
|
||||
uint8_t RTC_Init (void);
|
Reference in New Issue
Block a user