Annotation of embedaddon/strongswan/src/libstrongswan/plugins/cmac/cmac.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2012 Tobias Brunner
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: 
                     16: #include <string.h>
                     17: 
                     18: #include "cmac.h"
                     19: 
                     20: #include <utils/debug.h>
                     21: #include <crypto/mac.h>
                     22: #include <crypto/prfs/mac_prf.h>
                     23: #include <crypto/signers/mac_signer.h>
                     24: 
                     25: typedef struct private_mac_t private_mac_t;
                     26: 
                     27: /**
                     28:  * Private data of a mac_t object.
                     29:  *
                     30:  * The variable names are the same as in the RFC.
                     31:  */
                     32: struct private_mac_t {
                     33: 
                     34:        /**
                     35:         * Public interface.
                     36:         */
                     37:        mac_t public;
                     38: 
                     39:        /**
                     40:         * Block size, in bytes
                     41:         */
                     42:        uint8_t b;
                     43: 
                     44:        /**
                     45:         * Crypter with key K
                     46:         */
                     47:        crypter_t *k;
                     48: 
                     49:        /**
                     50:         * K1
                     51:         */
                     52:        uint8_t *k1;
                     53: 
                     54:        /**
                     55:         * K2
                     56:         */
                     57:        uint8_t *k2;
                     58: 
                     59:        /**
                     60:         * T
                     61:         */
                     62:        uint8_t *t;
                     63: 
                     64:        /**
                     65:         * remaining, unprocessed bytes in append mode
                     66:         */
                     67:        uint8_t *remaining;
                     68: 
                     69:        /**
                     70:         * number of bytes in remaining
                     71:         */
                     72:        int remaining_bytes;
                     73: };
                     74: 
                     75: /**
                     76:  * process supplied data, but do not run final operation
                     77:  */
                     78: static bool update(private_mac_t *this, chunk_t data)
                     79: {
                     80:        chunk_t iv;
                     81: 
                     82:        if (this->remaining_bytes + data.len <= this->b)
                     83:        {       /* no complete block (or last block), just copy into remaining */
                     84:                memcpy(this->remaining + this->remaining_bytes, data.ptr, data.len);
                     85:                this->remaining_bytes += data.len;
                     86:                return TRUE;
                     87:        }
                     88: 
                     89:        iv = chunk_alloca(this->b);
                     90:        memset(iv.ptr, 0, iv.len);
                     91: 
                     92:        /* T := 0x00000000000000000000000000000000 (initially)
                     93:         * for each block M_i (except the last)
                     94:         *   X := T XOR M_i;
                     95:         *   T := AES-128(K, X);
                     96:         */
                     97: 
                     98:        /* append data to remaining bytes, process block M_1 */
                     99:        memcpy(this->remaining + this->remaining_bytes, data.ptr,
                    100:                   this->b - this->remaining_bytes);
                    101:        data = chunk_skip(data, this->b - this->remaining_bytes);
                    102:        memxor(this->t, this->remaining, this->b);
                    103:        if (!this->k->encrypt(this->k, chunk_create(this->t, this->b), iv, NULL))
                    104:        {
                    105:                return FALSE;
                    106:        }
                    107: 
                    108:        /* process blocks M_2 ... M_n-1 */
                    109:        while (data.len > this->b)
                    110:        {
                    111:                memcpy(this->remaining, data.ptr, this->b);
                    112:                data = chunk_skip(data, this->b);
                    113:                memxor(this->t, this->remaining, this->b);
                    114:                if (!this->k->encrypt(this->k, chunk_create(this->t, this->b), iv, NULL))
                    115:                {
                    116:                        return FALSE;
                    117:                }
                    118:        }
                    119: 
                    120:        /* store remaining bytes of block M_n */
                    121:        memcpy(this->remaining, data.ptr, data.len);
                    122:        this->remaining_bytes = data.len;
                    123: 
                    124:        return TRUE;
                    125: }
                    126: 
                    127: /**
                    128:  * process last block M_last
                    129:  */
                    130: static bool final(private_mac_t *this, uint8_t *out)
                    131: {
                    132:        chunk_t iv;
                    133: 
                    134:        iv = chunk_alloca(this->b);
                    135:        memset(iv.ptr, 0, iv.len);
                    136: 
                    137:        /* if last block is complete
                    138:         *   M_last := M_n XOR K1;
                    139:         * else
                    140:         *   M_last := padding(M_n) XOR K2;
                    141:         */
                    142:        if (this->remaining_bytes == this->b)
                    143:        {
                    144:                memxor(this->remaining, this->k1, this->b);
                    145:        }
                    146:        else
                    147:        {
                    148:                /* padding(x) = x || 10^i  where i is 128-8*r-1
                    149:                 * That is, padding(x) is the concatenation of x and a single '1',
                    150:                 * followed by the minimum number of '0's, so that the total length is
                    151:                 * equal to 128 bits.
                    152:                 */
                    153:                if (this->remaining_bytes < this->b)
                    154:                {
                    155:                        this->remaining[this->remaining_bytes] = 0x80;
                    156:                        while (++this->remaining_bytes < this->b)
                    157:                        {
                    158:                                this->remaining[this->remaining_bytes] = 0x00;
                    159:                        }
                    160:                }
                    161:                memxor(this->remaining, this->k2, this->b);
                    162:        }
                    163:        /* T := M_last XOR T;
                    164:         * T := AES-128(K,T);
                    165:         */
                    166:        memxor(this->t, this->remaining, this->b);
                    167:        if (!this->k->encrypt(this->k, chunk_create(this->t, this->b), iv, NULL))
                    168:        {
                    169:                return FALSE;
                    170:        }
                    171: 
                    172:        memcpy(out, this->t, this->b);
                    173: 
                    174:        /* reset state */
                    175:        memset(this->t, 0, this->b);
                    176:        this->remaining_bytes = 0;
                    177: 
                    178:        return TRUE;
                    179: }
                    180: 
                    181: METHOD(mac_t, get_mac, bool,
                    182:        private_mac_t *this, chunk_t data, uint8_t *out)
                    183: {
                    184:        /* update T, do not process last block */
                    185:        if (!update(this, data))
                    186:        {
                    187:                return FALSE;
                    188:        }
                    189: 
                    190:        if (out)
                    191:        {       /* if not in append mode, process last block and output result */
                    192:                return final(this, out);
                    193:        }
                    194:        return TRUE;
                    195: }
                    196: 
                    197: METHOD(mac_t, get_mac_size, size_t,
                    198:        private_mac_t *this)
                    199: {
                    200:        return this->b;
                    201: }
                    202: 
                    203: /**
                    204:  * Left-shift the given chunk by one bit.
                    205:  */
                    206: static void bit_shift(chunk_t chunk)
                    207: {
                    208:        size_t i;
                    209: 
                    210:        for (i = 0; i < chunk.len; i++)
                    211:        {
                    212:                chunk.ptr[i] <<= 1;
                    213:                if (i < chunk.len - 1 && chunk.ptr[i + 1] & 0x80)
                    214:                {
                    215:                        chunk.ptr[i] |= 0x01;
                    216:                }
                    217:        }
                    218: }
                    219: 
                    220: /**
                    221:  * Apply the following key derivation (in-place):
                    222:  * if MSB(C) == 0
                    223:  *   C := C << 1
                    224:  * else
                    225:  *   C := (C << 1) XOR 0x00000000000000000000000000000087
                    226:  */
                    227: static void derive_key(chunk_t chunk)
                    228: {
                    229:        if (chunk.ptr[0] & 0x80)
                    230:        {
                    231:                chunk_t rb;
                    232: 
                    233:                rb = chunk_alloca(chunk.len);
                    234:                memset(rb.ptr, 0, rb.len);
                    235:                rb.ptr[rb.len - 1] = 0x87;
                    236:                bit_shift(chunk);
                    237:                memxor(chunk.ptr, rb.ptr, chunk.len);
                    238:        }
                    239:        else
                    240:        {
                    241:                bit_shift(chunk);
                    242:        }
                    243: }
                    244: 
                    245: METHOD(mac_t, set_key, bool,
                    246:        private_mac_t *this, chunk_t key)
                    247: {
                    248:        chunk_t resized, iv, l;
                    249: 
                    250:        memset(this->t, 0, this->b);
                    251:        this->remaining_bytes = 0;
                    252: 
                    253:        /* we support variable keys as defined in RFC 4615 */
                    254:        if (key.len == this->b)
                    255:        {
                    256:                resized = key;
                    257:        }
                    258:        else
                    259:        {       /* use cmac recursively to resize longer or shorter keys */
                    260:                resized = chunk_alloca(this->b);
                    261:                memset(resized.ptr, 0, resized.len);
                    262:                if (!set_key(this, resized) ||
                    263:                        !get_mac(this, key, resized.ptr))
                    264:                {
                    265:                        return FALSE;
                    266:                }
                    267:        }
                    268: 
                    269:        /*
                    270:         * Rb = 0x00000000000000000000000000000087
                    271:         * L = 0x00000000000000000000000000000000 encrypted with K
                    272:         * if MSB(L) == 0
                    273:         *   K1 = L << 1
                    274:         * else
                    275:         *   K1 = (L << 1) XOR Rb
                    276:         * if MSB(K1) == 0
                    277:         *   K2 = K1 << 1
                    278:         * else
                    279:         *   K2 = (K1 << 1) XOR Rb
                    280:         */
                    281:        iv = chunk_alloca(this->b);
                    282:        memset(iv.ptr, 0, iv.len);
                    283:        l = chunk_alloca(this->b);
                    284:        memset(l.ptr, 0, l.len);
                    285:        if (!this->k->set_key(this->k, resized) ||
                    286:                !this->k->encrypt(this->k, l, iv, NULL))
                    287:        {
                    288:                return FALSE;
                    289:        }
                    290:        derive_key(l);
                    291:        memcpy(this->k1, l.ptr, l.len);
                    292:        derive_key(l);
                    293:        memcpy(this->k2, l.ptr, l.len);
                    294:        memwipe(l.ptr, l.len);
                    295: 
                    296:        return TRUE;
                    297: }
                    298: 
                    299: METHOD(mac_t, destroy, void,
                    300:        private_mac_t *this)
                    301: {
                    302:        this->k->destroy(this->k);
                    303:        memwipe(this->k1, this->b);
                    304:        free(this->k1);
                    305:        memwipe(this->k2, this->b);
                    306:        free(this->k2);
                    307:        free(this->t);
                    308:        free(this->remaining);
                    309:        free(this);
                    310: }
                    311: 
                    312: /*
                    313:  * Described in header
                    314:  */
                    315: mac_t *cmac_create(encryption_algorithm_t algo, size_t key_size)
                    316: {
                    317:        private_mac_t *this;
                    318:        crypter_t *crypter;
                    319:        uint8_t b;
                    320: 
                    321:        crypter = lib->crypto->create_crypter(lib->crypto, algo, key_size);
                    322:        if (!crypter)
                    323:        {
                    324:                return NULL;
                    325:        }
                    326:        b = crypter->get_block_size(crypter);
                    327:        /* input and output of crypter must be equal for cmac */
                    328:        if (b != key_size)
                    329:        {
                    330:                crypter->destroy(crypter);
                    331:                return NULL;
                    332:        }
                    333: 
                    334:        INIT(this,
                    335:                .public = {
                    336:                        .get_mac = _get_mac,
                    337:                        .get_mac_size = _get_mac_size,
                    338:                        .set_key = _set_key,
                    339:                        .destroy = _destroy,
                    340:                },
                    341:                .b = b,
                    342:                .k = crypter,
                    343:                .k1 = malloc(b),
                    344:                .k2 = malloc(b),
                    345:                .t = malloc(b),
                    346:                .remaining = malloc(b),
                    347:        );
                    348:        memset(this->t, 0, b);
                    349: 
                    350:        return &this->public;
                    351: }
                    352: 
                    353: /*
                    354:  * Described in header.
                    355:  */
                    356: prf_t *cmac_prf_create(pseudo_random_function_t algo)
                    357: {
                    358:        mac_t *cmac;
                    359: 
                    360:        switch (algo)
                    361:        {
                    362:                case PRF_AES128_CMAC:
                    363:                        cmac = cmac_create(ENCR_AES_CBC, 16);
                    364:                        break;
                    365:                default:
                    366:                        return NULL;
                    367:        }
                    368:        if (cmac)
                    369:        {
                    370:                return mac_prf_create(cmac);
                    371:        }
                    372:        return NULL;
                    373: }
                    374: 
                    375: /*
                    376:  * Described in header
                    377:  */
                    378: signer_t *cmac_signer_create(integrity_algorithm_t algo)
                    379: {
                    380:        size_t truncation;
                    381:        mac_t *cmac;
                    382: 
                    383:        switch (algo)
                    384:        {
                    385:                case AUTH_AES_CMAC_96:
                    386:                        cmac = cmac_create(ENCR_AES_CBC, 16);
                    387:                        truncation = 12;
                    388:                        break;
                    389:                default:
                    390:                        return NULL;
                    391:        }
                    392:        if (cmac)
                    393:        {
                    394:                return mac_signer_create(cmac, truncation);
                    395:        }
                    396:        return NULL;
                    397: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>