初始版本
This commit is contained in:
150
external/cifra_AES128-EAX/cifra_cmac.c
vendored
Normal file
150
external/cifra_AES128-EAX/cifra_cmac.c
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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 "handy.h"
|
||||
#include "prp.h"
|
||||
#include "modes.h"
|
||||
#include "bitops.h"
|
||||
#include "blockwise.h"
|
||||
#include "gf128.h"
|
||||
#include "tassert.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void cf_cmac_init(cf_cmac *ctx, const cf_prp *prp, void *prpctx)
|
||||
{
|
||||
uint8_t L[CF_MAXBLOCK];
|
||||
assert(prp->blocksz == 16);
|
||||
|
||||
mem_clean(ctx, sizeof *ctx);
|
||||
|
||||
/* L = E_K(0^n) */
|
||||
mem_clean(L, prp->blocksz);
|
||||
prp->encrypt(prpctx, L, L);
|
||||
|
||||
/* B = 2L */
|
||||
cf_gf128 gf;
|
||||
cf_gf128_frombytes_be(L, gf);
|
||||
cf_gf128_double(gf, gf);
|
||||
cf_gf128_tobytes_be(gf, ctx->B);
|
||||
|
||||
/* P = 4L */
|
||||
cf_gf128_double(gf, gf);
|
||||
cf_gf128_tobytes_be(gf, ctx->P);
|
||||
|
||||
ctx->prp = prp;
|
||||
ctx->prpctx = prpctx;
|
||||
}
|
||||
|
||||
void cf_cmac_sign(cf_cmac *ctx, const uint8_t *data, size_t len, uint8_t out[CF_MAXBLOCK])
|
||||
{
|
||||
cf_cmac_stream stream;
|
||||
stream.cmac = *ctx;
|
||||
cf_cmac_stream_reset(&stream);
|
||||
cf_cmac_stream_update(&stream, data, len, 1);
|
||||
cf_cmac_stream_final(&stream, out);
|
||||
}
|
||||
|
||||
void cf_cmac_stream_init(cf_cmac_stream *ctx, const cf_prp *prp, void *prpctx)
|
||||
{
|
||||
cf_cmac_init(&ctx->cmac, prp, prpctx);
|
||||
cf_cmac_stream_reset(ctx);
|
||||
}
|
||||
|
||||
void cf_cmac_stream_reset(cf_cmac_stream *ctx)
|
||||
{
|
||||
uint8_t iv_zero[CF_MAXBLOCK] = { 0 };
|
||||
cf_cbc_init(&ctx->cbc, ctx->cmac.prp, ctx->cmac.prpctx, iv_zero);
|
||||
mem_clean(ctx->buffer, sizeof ctx->buffer);
|
||||
ctx->used = 0;
|
||||
ctx->processed = 0;
|
||||
ctx->finalised = 0;
|
||||
}
|
||||
|
||||
static void cmac_process(void *vctx, const uint8_t *block)
|
||||
{
|
||||
cf_cmac_stream *ctx = vctx;
|
||||
uint8_t output[CF_MAXBLOCK];
|
||||
cf_cbc_encrypt(&ctx->cbc, block, output, 1);
|
||||
ctx->processed += ctx->cmac.prp->blocksz;
|
||||
}
|
||||
|
||||
static void cmac_process_final(cf_cmac_stream *ctx, const uint8_t *block,
|
||||
const uint8_t *xor)
|
||||
{
|
||||
uint8_t input[CF_MAXBLOCK];
|
||||
uint8_t output[CF_MAXBLOCK];
|
||||
xor_bb(input, block, xor, ctx->cmac.prp->blocksz);
|
||||
cf_cbc_encrypt(&ctx->cbc, input, output, 1);
|
||||
ctx->processed += ctx->cmac.prp->blocksz;
|
||||
/* signature is in ctx->cbc.block. */
|
||||
}
|
||||
|
||||
static void cmac_process_final_nopad(void *vctx, const uint8_t *block)
|
||||
{
|
||||
cf_cmac_stream *ctx = vctx;
|
||||
cmac_process_final(ctx, block, ctx->cmac.B);
|
||||
ctx->finalised = 1;
|
||||
}
|
||||
|
||||
static void cmac_process_final_pad(void *vctx, const uint8_t *block)
|
||||
{
|
||||
cf_cmac_stream *ctx = vctx;
|
||||
cmac_process_final(ctx, block, ctx->cmac.P);
|
||||
ctx->finalised = 1;
|
||||
}
|
||||
|
||||
void cf_cmac_stream_update(cf_cmac_stream *ctx, const uint8_t *data, size_t len, int isfinal)
|
||||
{
|
||||
size_t blocksz = ctx->cmac.prp->blocksz;
|
||||
cf_blockwise_in_fn final_fn = cmac_process;
|
||||
int needpad = 0;
|
||||
|
||||
if (isfinal)
|
||||
{
|
||||
int whole_number_of_blocks = ((len + ctx->used) & 0xf) == 0;
|
||||
int empty_message = len == 0 && ctx->used == 0 && ctx->processed == 0;
|
||||
|
||||
assert(!ctx->finalised); /* finalised before? */
|
||||
assert(len != 0 || empty_message); /* we can't be told we're done after the fact. */
|
||||
|
||||
/* If we have a whole number of blocks, and at least 1 block, we XOR in B.
|
||||
* Otherwise, we need to pad and XOR in P. */
|
||||
if (whole_number_of_blocks && !empty_message)
|
||||
final_fn = cmac_process_final_nopad;
|
||||
else
|
||||
needpad = 1;
|
||||
}
|
||||
|
||||
/* Input data */
|
||||
cf_blockwise_accumulate_final(ctx->buffer, &ctx->used, blocksz,
|
||||
data, len,
|
||||
cmac_process,
|
||||
final_fn, ctx);
|
||||
|
||||
/* Input padding */
|
||||
if (needpad)
|
||||
{
|
||||
cf_blockwise_acc_pad(ctx->buffer, &ctx->used, blocksz,
|
||||
0x80, 0x00, 0x00, blocksz - ctx->used,
|
||||
cmac_process_final_pad, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void cf_cmac_stream_final(cf_cmac_stream *ctx, uint8_t out[CF_MAXBLOCK])
|
||||
{
|
||||
assert(ctx->finalised);
|
||||
memcpy(out, ctx->cbc.block, ctx->cmac.prp->blocksz);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user