/* bcal-omac.c */ /* This file is part of the AVR-Crypto-Lib. Copyright (C) 2010 Daniel Otte (daniel.otte@rub.de) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include "bcal-basic.h" #include "bcal-cmac.h" #include "memxor.h" static uint8_t left_shift_be_block(void* block, uint8_t blocksize_B){ uint8_t c1=0, c2; do{ --blocksize_B; c2 = (((uint8_t*)block)[blocksize_B])>>7; (((uint8_t*)block)[blocksize_B]) <<= 1; (((uint8_t*)block)[blocksize_B]) |= c1; c1 = c2; }while(blocksize_B); return c1; } static const uint8_t const_128 = 0x87; static const uint8_t const_64 = 0x1b; uint8_t bcal_cmac_init(const bcdesc_t* desc, const void* key, uint16_t keysize_b, bcal_cmac_ctx_t* ctx){ uint8_t r; ctx->desc = (bcdesc_t*)desc; ctx->blocksize_B = bcal_cipher_getBlocksize_b(desc)/8; if (ctx->blocksize_B!=128/8 && ctx->blocksize_B!=64/8){ return 0x13; } ctx->accu = malloc(ctx->blocksize_B); if(ctx->accu==NULL){ return 0x14; } ctx->k1 = malloc(ctx->blocksize_B); if(ctx->k1==NULL){ return 0x15; } ctx->k2 = malloc(ctx->blocksize_B); if(ctx->k2==NULL){ return 0x16; } ctx->lastblock = malloc(ctx->blocksize_B); if(ctx->lastblock==NULL){ return 0x17; } r = bcal_cipher_init(desc, key, keysize_b, &(ctx->cctx)); if(r){ return r; } if(ctx->blocksize_B==128/8){ r = const_128; }else{ r = const_64; } /* subkey computation */ memset(ctx->accu, 0x00, ctx->blocksize_B); memset(ctx->k1, 0x00, ctx->blocksize_B); bcal_cipher_enc(ctx->k1, &(ctx->cctx)); if(left_shift_be_block(ctx->k1, ctx->blocksize_B)){ ctx->k1[ctx->blocksize_B-1] ^= r; } memcpy(ctx->k2, ctx->k1, ctx->blocksize_B); if(left_shift_be_block(ctx->k2, ctx->blocksize_B)){ ctx->k2[ctx->blocksize_B-1] ^= r; } ctx->last_set=0; return 0; } void bcal_cmac_free(bcal_cmac_ctx_t* ctx){ free(ctx->accu); free(ctx->k1); free(ctx->k2); bcal_cipher_free(&(ctx->cctx)); } void bcal_cmac_nextBlock (bcal_cmac_ctx_t* ctx, const void* block){ if(ctx->last_set){ memxor(ctx->accu, ctx->lastblock, ctx->blocksize_B); bcal_cipher_enc(ctx->accu, &(ctx->cctx)); } memcpy(ctx->lastblock, block, ctx->blocksize_B); ctx->last_set=1; } void bcal_cmac_lastBlock(bcal_cmac_ctx_t* ctx, const void* block, uint16_t length_b){ uint16_t blocksize_b; blocksize_b = ctx->blocksize_B*8; while(length_b>=blocksize_b){ bcal_cmac_nextBlock(ctx, block); block = (uint8_t*)block + ctx->blocksize_B; length_b -= blocksize_b; } if(ctx->last_set==0){ memxor(ctx->accu, block, (length_b+7)/8); memxor(ctx->accu, ctx->k2, ctx->blocksize_B); ctx->accu[length_b/8] ^= 0x80>>(length_b&7); }else{ if(length_b==0){ memxor(ctx->accu, ctx->lastblock, ctx->blocksize_B); memxor(ctx->accu, ctx->k1, ctx->blocksize_B); }else{ memxor(ctx->accu, ctx->lastblock, ctx->blocksize_B); bcal_cipher_enc(ctx->accu, &(ctx->cctx)); memxor(ctx->accu, block, (length_b+7)/8); memxor(ctx->accu, ctx->k2, ctx->blocksize_B); ctx->accu[length_b/8] ^= 0x80>>(length_b&7); } } bcal_cipher_enc(ctx->accu, &(ctx->cctx)); } void bcal_cmac_ctx2mac(void* dest, uint16_t length_b, const bcal_cmac_ctx_t* ctx){ memcpy(dest, ctx->accu, length_b/8); if(length_b&7){ ((uint8_t*)dest)[length_b/8] &= 0xff>>(length_b&7); ((uint8_t*)dest)[length_b/8] |= (0xff00>>(length_b&7))&(ctx->accu[length_b/8]); } } void bcal_cmac(void* dest, uint16_t out_length_b, const void* block, uint32_t length_b, bcal_cmac_ctx_t* ctx){ uint16_t blocksize_b; blocksize_b = ctx->blocksize_B*8; while(length_b>blocksize_b){ bcal_cmac_nextBlock(ctx, block); block = (uint8_t*)block + ctx->blocksize_B; length_b -= blocksize_b; } bcal_cmac_lastBlock(ctx, block, length_b); bcal_cmac_ctx2mac(dest, out_length_b, ctx); }