This commit is contained in:
2025-09-07 16:02:22 +02:00
commit 627acef32c
145 changed files with 74048 additions and 0 deletions

417
User/lib/cifra/aes.c Normal file
View 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
View 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
View 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
View 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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