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

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2010 Martin Willi
        !             3:  * Copyright (C) 2010 revosec AG
        !             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 "ccm_aead.h"
        !            17: 
        !            18: #include <crypto/iv/iv_gen_seq.h>
        !            19: 
        !            20: #define BLOCK_SIZE 16
        !            21: #define SALT_SIZE 3
        !            22: #define IV_SIZE 8
        !            23: #define NONCE_SIZE (SALT_SIZE + IV_SIZE) /* 11 */
        !            24: #define Q_SIZE (BLOCK_SIZE - NONCE_SIZE - 1) /* 4 */
        !            25: 
        !            26: typedef struct private_ccm_aead_t private_ccm_aead_t;
        !            27: 
        !            28: /**
        !            29:  * Private data of an ccm_aead_t object.
        !            30:  */
        !            31: struct private_ccm_aead_t {
        !            32: 
        !            33:        /**
        !            34:         * Public ccm_aead_t interface.
        !            35:         */
        !            36:        ccm_aead_t public;
        !            37: 
        !            38:        /**
        !            39:         * Underlying CBC crypter.
        !            40:         */
        !            41:        crypter_t *crypter;
        !            42: 
        !            43:        /**
        !            44:         * IV generator.
        !            45:         */
        !            46:        iv_gen_t *iv_gen;
        !            47: 
        !            48:        /**
        !            49:         * Length of the integrity check value
        !            50:         */
        !            51:        size_t icv_size;
        !            52: 
        !            53:        /**
        !            54:         * salt to add to nonce
        !            55:         */
        !            56:        u_char salt[SALT_SIZE];
        !            57: };
        !            58: 
        !            59: /**
        !            60:  * First block with control information
        !            61:  */
        !            62: typedef struct __attribute__((packed)) {
        !            63:        BITFIELD4(uint8_t,
        !            64:                /* size of p length field q, as q-1 */
        !            65:                q_len: 3,
        !            66:                /* size of our ICV t, as (t-2)/2 */
        !            67:                t_len: 3,
        !            68:                /* do we have associated data */
        !            69:                assoc: 1,
        !            70:                reserved: 1,
        !            71:        ) flags;
        !            72:        /* nonce value */
        !            73:        struct __attribute__((packed)) {
        !            74:                u_char salt[SALT_SIZE];
        !            75:                u_char iv[IV_SIZE];
        !            76:        } nonce;
        !            77:        /* length of plain text, q */
        !            78:        u_char q[Q_SIZE];
        !            79: } b0_t;
        !            80: 
        !            81: /**
        !            82:  * Counter block
        !            83:  */
        !            84: typedef struct __attribute__((packed)) {
        !            85:        BITFIELD3(uint8_t,
        !            86:                /* size of p length field q, as q-1 */
        !            87:                q_len: 3,
        !            88:                zero: 3,
        !            89:                reserved: 2,
        !            90:        ) flags;
        !            91:        /* nonce value */
        !            92:        struct __attribute__((packed)) {
        !            93:                u_char salt[SALT_SIZE];
        !            94:                u_char iv[IV_SIZE];
        !            95:        } nonce;
        !            96:        /* counter value */
        !            97:        u_char i[Q_SIZE];
        !            98: } ctr_t;
        !            99: 
        !           100: /**
        !           101:  * Build the first block B0
        !           102:  */
        !           103: static void build_b0(private_ccm_aead_t *this, chunk_t plain, chunk_t assoc,
        !           104:                                         chunk_t iv, char *out)
        !           105: {
        !           106:        b0_t *block = (b0_t*)out;
        !           107: 
        !           108:        block->flags.reserved = 0;
        !           109:        block->flags.assoc = assoc.len ? 1 : 0;
        !           110:        block->flags.t_len = (this->icv_size - 2) / 2;
        !           111:        block->flags.q_len = Q_SIZE - 1;
        !           112:        memcpy(block->nonce.salt, this->salt, SALT_SIZE);
        !           113:        memcpy(block->nonce.iv, iv.ptr, IV_SIZE);
        !           114:        htoun32(block->q, plain.len);
        !           115: }
        !           116: 
        !           117: /**
        !           118:  * Build a counter block for counter i
        !           119:  */
        !           120: static void build_ctr(private_ccm_aead_t *this, uint32_t i, chunk_t iv,
        !           121:                                          char *out)
        !           122: {
        !           123:        ctr_t *ctr = (ctr_t*)out;
        !           124: 
        !           125:        ctr->flags.reserved = 0;
        !           126:        ctr->flags.zero = 0;
        !           127:        ctr->flags.q_len = Q_SIZE - 1;
        !           128:        memcpy(ctr->nonce.salt, this->salt, SALT_SIZE);
        !           129:        memcpy(ctr->nonce.iv, iv.ptr, IV_SIZE);
        !           130:        htoun32(ctr->i, i);
        !           131: }
        !           132: 
        !           133: /**
        !           134:  * En-/Decrypt data
        !           135:  */
        !           136: static bool crypt_data(private_ccm_aead_t *this, chunk_t iv,
        !           137:                                           chunk_t in, chunk_t out)
        !           138: {
        !           139:        char ctr[BLOCK_SIZE];
        !           140:        char zero[BLOCK_SIZE];
        !           141:        char block[BLOCK_SIZE];
        !           142: 
        !           143:        build_ctr(this, 1, iv, ctr);
        !           144:        memset(zero, 0, BLOCK_SIZE);
        !           145: 
        !           146:        while (in.len > 0)
        !           147:        {
        !           148:                memcpy(block, ctr, BLOCK_SIZE);
        !           149:                if (!this->crypter->encrypt(this->crypter, chunk_from_thing(block),
        !           150:                                                                        chunk_from_thing(zero), NULL))
        !           151:                {
        !           152:                        return FALSE;
        !           153:                }
        !           154:                chunk_increment(chunk_from_thing(ctr));
        !           155: 
        !           156:                if (in.ptr != out.ptr)
        !           157:                {
        !           158:                        memcpy(out.ptr, in.ptr, min(in.len, BLOCK_SIZE));
        !           159:                }
        !           160:                memxor(out.ptr, block, min(in.len, BLOCK_SIZE));
        !           161:                in = chunk_skip(in, BLOCK_SIZE);
        !           162:                out = chunk_skip(out, BLOCK_SIZE);
        !           163:        }
        !           164:        return TRUE;
        !           165: }
        !           166: 
        !           167: /**
        !           168:  * En-/Decrypt the ICV
        !           169:  */
        !           170: static bool crypt_icv(private_ccm_aead_t *this, chunk_t iv, char *icv)
        !           171: {
        !           172:        char ctr[BLOCK_SIZE];
        !           173:        char zero[BLOCK_SIZE];
        !           174: 
        !           175:        build_ctr(this, 0, iv, ctr);
        !           176:        memset(zero, 0, BLOCK_SIZE);
        !           177: 
        !           178:        if (!this->crypter->encrypt(this->crypter, chunk_from_thing(ctr),
        !           179:                                                                chunk_from_thing(zero), NULL))
        !           180:        {
        !           181:                return FALSE;
        !           182:        }
        !           183:        memxor(icv, ctr, this->icv_size);
        !           184:        return TRUE;
        !           185: }
        !           186: 
        !           187: /**
        !           188:  * Create the ICV
        !           189:  */
        !           190: static bool create_icv(private_ccm_aead_t *this, chunk_t plain, chunk_t assoc,
        !           191:                                           chunk_t iv, char *icv)
        !           192: {
        !           193:        char zero[BLOCK_SIZE];
        !           194:        chunk_t chunk;
        !           195:        char *pos;
        !           196:        int r, len;
        !           197: 
        !           198:        memset(zero, 0, BLOCK_SIZE);
        !           199: 
        !           200:        /* calculate number of blocks, including b0 */
        !           201:        r = 1;
        !           202:        if (assoc.len)
        !           203:        {       /* assoc gets a 2 byte length header, gets padded to BLOCK_SIZE */
        !           204:                r += (2 + assoc.len + BLOCK_SIZE - 1) / BLOCK_SIZE;
        !           205:        }
        !           206:        /* plain text gets padded to BLOCK_SIZE */
        !           207:        r += (plain.len + BLOCK_SIZE - 1) / BLOCK_SIZE;
        !           208: 
        !           209:        /* concatenate data to a new chunk */
        !           210:        chunk = chunk_alloc(r * BLOCK_SIZE);
        !           211:        /* write control block */
        !           212:        build_b0(this, plain, assoc, iv, chunk.ptr);
        !           213:        pos = chunk.ptr + BLOCK_SIZE;
        !           214:        /* append associated data, with length header */
        !           215:        if (assoc.len)
        !           216:        {
        !           217:                /* currently we support two byte headers only (up to 2^16-2^8 bytes) */
        !           218:                htoun16(pos, assoc.len);
        !           219:                memcpy(pos + 2, assoc.ptr, assoc.len);
        !           220:                pos += 2 + assoc.len;
        !           221:                /* padding */
        !           222:                len = (BLOCK_SIZE - ((2 + assoc.len) % BLOCK_SIZE)) % BLOCK_SIZE;
        !           223:                memset(pos, 0, len);
        !           224:                pos += len;
        !           225:        }
        !           226:        /* write plain data */
        !           227:        memcpy(pos, plain.ptr, plain.len);
        !           228:        pos += plain.len;
        !           229:        /* padding */
        !           230:        len = (BLOCK_SIZE - (plain.len % BLOCK_SIZE)) % BLOCK_SIZE;
        !           231: 
        !           232:        memset(pos, 0, len);
        !           233: 
        !           234:        /* encrypt inline with CBC, zero IV */
        !           235:        if (!this->crypter->encrypt(this->crypter, chunk,
        !           236:                                                                chunk_from_thing(zero), NULL))
        !           237:        {
        !           238:                free(chunk.ptr);
        !           239:                return FALSE;
        !           240:        }
        !           241:        /* copy last icv_size bytes as ICV to output */
        !           242:        memcpy(icv, chunk.ptr + chunk.len - BLOCK_SIZE, this->icv_size);
        !           243: 
        !           244:        free(chunk.ptr);
        !           245: 
        !           246:        /* encrypt the ICV value */
        !           247:        return crypt_icv(this, iv, icv);
        !           248: }
        !           249: 
        !           250: /**
        !           251:  * Verify the ICV
        !           252:  */
        !           253: static bool verify_icv(private_ccm_aead_t *this, chunk_t plain, chunk_t assoc,
        !           254:                                           chunk_t iv, char *icv)
        !           255: {
        !           256:        char buf[this->icv_size];
        !           257: 
        !           258:        return create_icv(this, plain, assoc, iv, buf) &&
        !           259:                   memeq_const(buf, icv, this->icv_size);
        !           260: }
        !           261: 
        !           262: METHOD(aead_t, encrypt, bool,
        !           263:        private_ccm_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
        !           264:        chunk_t *encrypted)
        !           265: {
        !           266:        if (encrypted)
        !           267:        {
        !           268:                *encrypted = chunk_alloc(plain.len + this->icv_size);
        !           269:                return create_icv(this, plain, assoc, iv, encrypted->ptr + plain.len) &&
        !           270:                           crypt_data(this, iv, plain, *encrypted);
        !           271:        }
        !           272:        return create_icv(this, plain, assoc, iv, plain.ptr + plain.len) &&
        !           273:                   crypt_data(this, iv, plain, plain);
        !           274: }
        !           275: 
        !           276: METHOD(aead_t, decrypt, bool,
        !           277:        private_ccm_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
        !           278:        chunk_t *plain)
        !           279: {
        !           280:        if (encrypted.len < this->icv_size)
        !           281:        {
        !           282:                return FALSE;
        !           283:        }
        !           284:        encrypted.len -= this->icv_size;
        !           285:        if (plain)
        !           286:        {
        !           287:                *plain = chunk_alloc(encrypted.len);
        !           288:                return crypt_data(this, iv, encrypted, *plain) &&
        !           289:                           verify_icv(this, *plain, assoc, iv,
        !           290:                                                  encrypted.ptr + encrypted.len);
        !           291:        }
        !           292:        return crypt_data(this, iv, encrypted, encrypted) &&
        !           293:                   verify_icv(this, encrypted, assoc, iv,
        !           294:                                          encrypted.ptr + encrypted.len);
        !           295: }
        !           296: 
        !           297: METHOD(aead_t, get_block_size, size_t,
        !           298:        private_ccm_aead_t *this)
        !           299: {
        !           300:        return 1;
        !           301: }
        !           302: 
        !           303: METHOD(aead_t, get_icv_size, size_t,
        !           304:        private_ccm_aead_t *this)
        !           305: {
        !           306:        return this->icv_size;
        !           307: }
        !           308: 
        !           309: METHOD(aead_t, get_iv_size, size_t,
        !           310:        private_ccm_aead_t *this)
        !           311: {
        !           312:        return IV_SIZE;
        !           313: }
        !           314: 
        !           315: METHOD(aead_t, get_iv_gen, iv_gen_t*,
        !           316:        private_ccm_aead_t *this)
        !           317: {
        !           318:        return this->iv_gen;
        !           319: }
        !           320: 
        !           321: METHOD(aead_t, get_key_size, size_t,
        !           322:        private_ccm_aead_t *this)
        !           323: {
        !           324:        return this->crypter->get_key_size(this->crypter) + SALT_SIZE;
        !           325: }
        !           326: 
        !           327: METHOD(aead_t, set_key, bool,
        !           328:        private_ccm_aead_t *this, chunk_t key)
        !           329: {
        !           330:        memcpy(this->salt, key.ptr + key.len - SALT_SIZE, SALT_SIZE);
        !           331:        key.len -= SALT_SIZE;
        !           332:        return this->crypter->set_key(this->crypter, key);
        !           333: }
        !           334: 
        !           335: METHOD(aead_t, destroy, void,
        !           336:        private_ccm_aead_t *this)
        !           337: {
        !           338:        this->crypter->destroy(this->crypter);
        !           339:        this->iv_gen->destroy(this->iv_gen);
        !           340:        free(this);
        !           341: }
        !           342: 
        !           343: /**
        !           344:  * See header
        !           345:  */
        !           346: ccm_aead_t *ccm_aead_create(encryption_algorithm_t algo,
        !           347:                                                        size_t key_size, size_t salt_size)
        !           348: {
        !           349:        private_ccm_aead_t *this;
        !           350:        size_t icv_size;
        !           351: 
        !           352:        switch (key_size)
        !           353:        {
        !           354:                case 0:
        !           355:                        key_size = 16;
        !           356:                        break;
        !           357:                case 16:
        !           358:                case 24:
        !           359:                case 32:
        !           360:                        break;
        !           361:                default:
        !           362:                        return NULL;
        !           363:        }
        !           364:        if (salt_size && salt_size != SALT_SIZE)
        !           365:        {
        !           366:                /* currently not supported */
        !           367:                return NULL;
        !           368:        }
        !           369:        switch (algo)
        !           370:        {
        !           371:                case ENCR_AES_CCM_ICV8:
        !           372:                        algo = ENCR_AES_CBC;
        !           373:                        icv_size = 8;
        !           374:                        break;
        !           375:                case ENCR_AES_CCM_ICV12:
        !           376:                        algo = ENCR_AES_CBC;
        !           377:                        icv_size = 12;
        !           378:                        break;
        !           379:                case ENCR_AES_CCM_ICV16:
        !           380:                        algo = ENCR_AES_CBC;
        !           381:                        icv_size = 16;
        !           382:                        break;
        !           383:                case ENCR_CAMELLIA_CCM_ICV8:
        !           384:                        algo = ENCR_CAMELLIA_CBC;
        !           385:                        icv_size = 8;
        !           386:                        break;
        !           387:                case ENCR_CAMELLIA_CCM_ICV12:
        !           388:                        algo = ENCR_CAMELLIA_CBC;
        !           389:                        icv_size = 12;
        !           390:                        break;
        !           391:                case ENCR_CAMELLIA_CCM_ICV16:
        !           392:                        algo = ENCR_CAMELLIA_CBC;
        !           393:                        icv_size = 16;
        !           394:                        break;
        !           395:                default:
        !           396:                        return NULL;
        !           397:        }
        !           398: 
        !           399:        INIT(this,
        !           400:                .public = {
        !           401:                        .aead = {
        !           402:                                .encrypt = _encrypt,
        !           403:                                .decrypt = _decrypt,
        !           404:                                .get_block_size = _get_block_size,
        !           405:                                .get_icv_size = _get_icv_size,
        !           406:                                .get_iv_size = _get_iv_size,
        !           407:                                .get_iv_gen = _get_iv_gen,
        !           408:                                .get_key_size = _get_key_size,
        !           409:                                .set_key = _set_key,
        !           410:                                .destroy = _destroy,
        !           411:                        },
        !           412:                },
        !           413:                .crypter = lib->crypto->create_crypter(lib->crypto, algo, key_size),
        !           414:                .iv_gen = iv_gen_seq_create(),
        !           415:                .icv_size = icv_size,
        !           416:        );
        !           417: 
        !           418:        if (!this->crypter)
        !           419:        {
        !           420:                free(this);
        !           421:                return NULL;
        !           422:        }
        !           423: 
        !           424:        return &this->public;
        !           425: }

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