Annotation of embedaddon/strongswan/src/libstrongswan/plugins/xcbc/xcbc.c, revision 1.1

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

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