Init
This commit is contained in:
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
|
Reference in New Issue
Block a user