Annotation of embedaddon/strongswan/src/libstrongswan/plugins/gcm/gcm_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 "gcm_aead.h"
        !            17: 
        !            18: #include <limits.h>
        !            19: #include <crypto/iv/iv_gen_seq.h>
        !            20: 
        !            21: #define BLOCK_SIZE 16
        !            22: #define NONCE_SIZE 12
        !            23: #define IV_SIZE 8
        !            24: #define SALT_SIZE (NONCE_SIZE - IV_SIZE)
        !            25: 
        !            26: typedef struct private_gcm_aead_t private_gcm_aead_t;
        !            27: 
        !            28: /**
        !            29:  * Private data of an gcm_aead_t object.
        !            30:  */
        !            31: struct private_gcm_aead_t {
        !            32: 
        !            33:        /**
        !            34:         * Public gcm_aead_t interface.
        !            35:         */
        !            36:        gcm_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:         * Size of the integrity check value
        !            50:         */
        !            51:        size_t icv_size;
        !            52: 
        !            53:        /**
        !            54:         * Salt value
        !            55:         */
        !            56:        char salt[SALT_SIZE];
        !            57: 
        !            58:        /**
        !            59:         * GHASH subkey H
        !            60:         */
        !            61:        char h[BLOCK_SIZE];
        !            62: };
        !            63: 
        !            64: /**
        !            65:  * Find a suitable word size and network order conversion functions
        !            66:  */
        !            67: #if ULONG_MAX == 18446744073709551615UL && defined(htobe64)
        !            68: #      define htobeword htobe64
        !            69: #      define bewordtoh be64toh
        !            70: #      define SHIFT_WORD_TYPE uint64_t
        !            71: #else
        !            72: #      define htobeword htonl
        !            73: #      define bewordtoh ntohl
        !            74: #      define SHIFT_WORD_TYPE uint32_t
        !            75: #endif
        !            76: 
        !            77: /**
        !            78:  * Bitshift a block right by one bit
        !            79:  */
        !            80: static void sr_block(char *block)
        !            81: {
        !            82:        int i;
        !            83:        SHIFT_WORD_TYPE *word = (SHIFT_WORD_TYPE*)block;
        !            84: 
        !            85:        for (i = 0; i < BLOCK_SIZE / sizeof(*word); i++)
        !            86:        {
        !            87:                word[i] = bewordtoh(word[i]);
        !            88:        }
        !            89:        for (i = BLOCK_SIZE / sizeof(*word) - 1; i >= 0; i--)
        !            90:        {
        !            91:                word[i] >>= 1;
        !            92:                if (i != 0)
        !            93:                {
        !            94:                        word[i] |= word[i - 1] << (sizeof(*word) * 8 - 1);
        !            95:                }
        !            96:        }
        !            97:        for (i = 0; i < BLOCK_SIZE / sizeof(*word); i++)
        !            98:        {
        !            99:                word[i] = htobeword(word[i]);
        !           100:        }
        !           101: }
        !           102: 
        !           103: /**
        !           104:  * Naive implementation of block multiplication in GF128, no tables
        !           105:  */
        !           106: static void mult_block(char *x, char *y, char *res)
        !           107: {
        !           108:        char z[BLOCK_SIZE], v[BLOCK_SIZE], r;
        !           109:        int bit, byte;
        !           110: 
        !           111:        r = 0xE1;
        !           112:        memset(z, 0, BLOCK_SIZE);
        !           113:        memcpy(v, y, BLOCK_SIZE);
        !           114: 
        !           115:        for (byte = 0; byte < BLOCK_SIZE; byte++)
        !           116:        {
        !           117:                for (bit = 7; bit >= 0; bit--)
        !           118:                {
        !           119:                        if (x[byte] & (1 << bit))
        !           120:                        {
        !           121:                                memxor(z, v, BLOCK_SIZE);
        !           122:                        }
        !           123:                        if (v[BLOCK_SIZE - 1] & 0x01)
        !           124:                        {
        !           125:                                sr_block(v);
        !           126:                                v[0] ^= r;
        !           127:                        }
        !           128:                        else
        !           129:                        {
        !           130:                                sr_block(v);
        !           131:                        }
        !           132:                }
        !           133:        }
        !           134:        memcpy(res, z, BLOCK_SIZE);
        !           135: }
        !           136: 
        !           137: /**
        !           138:  * GHASH function
        !           139:  */
        !           140: static void ghash(private_gcm_aead_t *this, chunk_t x, char *res)
        !           141: {
        !           142:        char y[BLOCK_SIZE];
        !           143: 
        !           144:        memset(y, 0, BLOCK_SIZE);
        !           145: 
        !           146:        while (x.len)
        !           147:        {
        !           148:                memxor(y, x.ptr, BLOCK_SIZE);
        !           149:                mult_block(y, this->h, y);
        !           150:                x = chunk_skip(x, BLOCK_SIZE);
        !           151:        }
        !           152:        memcpy(res, y, BLOCK_SIZE);
        !           153: }
        !           154: 
        !           155: /**
        !           156:  * GCTR function, en-/decrypts x inline
        !           157:  */
        !           158: static bool gctr(private_gcm_aead_t *this, char *icb, chunk_t x)
        !           159: {
        !           160:        char cb[BLOCK_SIZE], iv[BLOCK_SIZE], tmp[BLOCK_SIZE];
        !           161: 
        !           162:        memset(iv, 0, BLOCK_SIZE);
        !           163:        memcpy(cb, icb, BLOCK_SIZE);
        !           164: 
        !           165:        while (x.len)
        !           166:        {
        !           167:                memcpy(tmp, cb, BLOCK_SIZE);
        !           168:                if (!this->crypter->encrypt(this->crypter, chunk_from_thing(tmp),
        !           169:                                                                        chunk_from_thing(iv), NULL))
        !           170:                {
        !           171:                        return FALSE;
        !           172:                }
        !           173:                memxor(x.ptr, tmp, min(BLOCK_SIZE, x.len));
        !           174:                chunk_increment(chunk_from_thing(cb));
        !           175:                x = chunk_skip(x, BLOCK_SIZE);
        !           176:        }
        !           177:        return TRUE;
        !           178: }
        !           179: 
        !           180: /**
        !           181:  * Generate the block J0
        !           182:  */
        !           183: static void create_j(private_gcm_aead_t *this, char *iv, char *j)
        !           184: {
        !           185:        memcpy(j, this->salt, SALT_SIZE);
        !           186:        memcpy(j + SALT_SIZE, iv, IV_SIZE);
        !           187:        htoun32(j + SALT_SIZE + IV_SIZE, 1);
        !           188: }
        !           189: 
        !           190: /**
        !           191:  * Create GHASH subkey H
        !           192:  */
        !           193: static bool create_h(private_gcm_aead_t *this, char *h)
        !           194: {
        !           195:        char zero[BLOCK_SIZE];
        !           196: 
        !           197:        memset(zero, 0, BLOCK_SIZE);
        !           198:        memset(h, 0, BLOCK_SIZE);
        !           199: 
        !           200:        return this->crypter->encrypt(this->crypter, chunk_create(h, BLOCK_SIZE),
        !           201:                                                                  chunk_from_thing(zero), NULL);
        !           202: }
        !           203: 
        !           204: /**
        !           205:  * Encrypt/decrypt
        !           206:  */
        !           207: static bool crypt(private_gcm_aead_t *this, char *j, chunk_t in, chunk_t out)
        !           208: {
        !           209:        char icb[BLOCK_SIZE];
        !           210: 
        !           211:        memcpy(icb, j, BLOCK_SIZE);
        !           212:        chunk_increment(chunk_from_thing(icb));
        !           213: 
        !           214:        out.len = in.len;
        !           215:        if (in.ptr != out.ptr)
        !           216:        {
        !           217:                memcpy(out.ptr, in.ptr, in.len);
        !           218:        }
        !           219:        return gctr(this, icb, out);
        !           220: }
        !           221: 
        !           222: /**
        !           223:  * Create ICV
        !           224:  */
        !           225: static bool create_icv(private_gcm_aead_t *this, chunk_t assoc, chunk_t crypt,
        !           226:                                           char *j, char *icv)
        !           227: {
        !           228:        size_t assoc_pad, crypt_pad;
        !           229:        chunk_t chunk;
        !           230:        char s[BLOCK_SIZE], *pos;
        !           231: 
        !           232:        assoc_pad = (BLOCK_SIZE - (assoc.len % BLOCK_SIZE)) % BLOCK_SIZE;
        !           233:        crypt_pad = (BLOCK_SIZE - (crypt.len % BLOCK_SIZE)) % BLOCK_SIZE;
        !           234: 
        !           235:        /* concatenate data to a new chunk */
        !           236:        chunk = chunk_alloc(assoc.len + assoc_pad +
        !           237:                                                crypt.len + crypt_pad + BLOCK_SIZE);
        !           238:        pos = chunk.ptr;
        !           239:        /* add associated data */
        !           240:        memcpy(pos, assoc.ptr, assoc.len);
        !           241:        pos += assoc.len;
        !           242:        memset(pos, 0, assoc_pad);
        !           243:        pos += assoc_pad;
        !           244:        /* add encrypted data */
        !           245:        memcpy(pos, crypt.ptr, crypt.len);
        !           246:        pos += crypt.len;
        !           247:        memset(pos, 0, crypt_pad);
        !           248:        pos += crypt_pad;
        !           249:        /* write associated len */
        !           250:        memset(pos, 0, 4);
        !           251:        pos += 4;
        !           252:        htoun32(pos, assoc.len * 8);
        !           253:        pos += 4;
        !           254:        /* write encrypted length */
        !           255:        memset(pos, 0, 4);
        !           256:        pos += 4;
        !           257:        htoun32(pos, crypt.len * 8);
        !           258:        pos += 4;
        !           259: 
        !           260:        ghash(this, chunk, s);
        !           261:        free(chunk.ptr);
        !           262:        if (!gctr(this, j, chunk_from_thing(s)))
        !           263:        {
        !           264:                return FALSE;
        !           265:        }
        !           266:        memcpy(icv, s, this->icv_size);
        !           267:        return TRUE;
        !           268: }
        !           269: 
        !           270: /**
        !           271:  * Verify the ICV value
        !           272:  */
        !           273: static bool verify_icv(private_gcm_aead_t *this, chunk_t assoc, chunk_t crypt,
        !           274:                                           char *j, char *icv)
        !           275: {
        !           276:        char tmp[this->icv_size];
        !           277: 
        !           278:        return create_icv(this, assoc, crypt, j, tmp) &&
        !           279:                   memeq_const(tmp, icv, this->icv_size);
        !           280: }
        !           281: 
        !           282: METHOD(aead_t, encrypt, bool,
        !           283:        private_gcm_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
        !           284:        chunk_t *encrypted)
        !           285: {
        !           286:        char j[BLOCK_SIZE];
        !           287: 
        !           288:        create_j(this, iv.ptr, j);
        !           289: 
        !           290:        if (encrypted)
        !           291:        {
        !           292:                *encrypted = chunk_alloc(plain.len + this->icv_size);
        !           293:                return crypt(this, j, plain, *encrypted) &&
        !           294:                           create_icv(this, assoc,
        !           295:                                        chunk_create(encrypted->ptr, encrypted->len - this->icv_size),
        !           296:                                        j, encrypted->ptr + encrypted->len - this->icv_size);
        !           297:        }
        !           298:        return crypt(this, j, plain, plain) &&
        !           299:                   create_icv(this, assoc, plain, j, plain.ptr + plain.len);
        !           300: }
        !           301: 
        !           302: METHOD(aead_t, decrypt, bool,
        !           303:        private_gcm_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
        !           304:        chunk_t *plain)
        !           305: {
        !           306:        char j[BLOCK_SIZE];
        !           307: 
        !           308:        if (encrypted.len < this->icv_size)
        !           309:        {
        !           310:                return FALSE;
        !           311:        }
        !           312: 
        !           313:        create_j(this, iv.ptr, j);
        !           314: 
        !           315:        encrypted.len -= this->icv_size;
        !           316:        if (!verify_icv(this, assoc, encrypted, j, encrypted.ptr + encrypted.len))
        !           317:        {
        !           318:                return FALSE;
        !           319:        }
        !           320:        if (plain)
        !           321:        {
        !           322:                *plain = chunk_alloc(encrypted.len);
        !           323:                return crypt(this, j, encrypted, *plain);
        !           324:        }
        !           325:        return crypt(this, j, encrypted, encrypted);
        !           326: }
        !           327: 
        !           328: METHOD(aead_t, get_block_size, size_t,
        !           329:        private_gcm_aead_t *this)
        !           330: {
        !           331:        return 1;
        !           332: }
        !           333: 
        !           334: METHOD(aead_t, get_icv_size, size_t,
        !           335:        private_gcm_aead_t *this)
        !           336: {
        !           337:        return this->icv_size;
        !           338: }
        !           339: 
        !           340: METHOD(aead_t, get_iv_size, size_t,
        !           341:        private_gcm_aead_t *this)
        !           342: {
        !           343:        return IV_SIZE;
        !           344: }
        !           345: 
        !           346: METHOD(aead_t, get_iv_gen, iv_gen_t*,
        !           347:        private_gcm_aead_t *this)
        !           348: {
        !           349:        return this->iv_gen;
        !           350: }
        !           351: 
        !           352: METHOD(aead_t, get_key_size, size_t,
        !           353:        private_gcm_aead_t *this)
        !           354: {
        !           355:        return this->crypter->get_key_size(this->crypter) + SALT_SIZE;
        !           356: }
        !           357: 
        !           358: METHOD(aead_t, set_key, bool,
        !           359:        private_gcm_aead_t *this, chunk_t key)
        !           360: {
        !           361:        memcpy(this->salt, key.ptr + key.len - SALT_SIZE, SALT_SIZE);
        !           362:        key.len -= SALT_SIZE;
        !           363:        return this->crypter->set_key(this->crypter, key) &&
        !           364:                   create_h(this, this->h);
        !           365: }
        !           366: 
        !           367: METHOD(aead_t, destroy, void,
        !           368:        private_gcm_aead_t *this)
        !           369: {
        !           370:        this->crypter->destroy(this->crypter);
        !           371:        this->iv_gen->destroy(this->iv_gen);
        !           372:        free(this);
        !           373: }
        !           374: 
        !           375: /**
        !           376:  * See header
        !           377:  */
        !           378: gcm_aead_t *gcm_aead_create(encryption_algorithm_t algo,
        !           379:                                                        size_t key_size, size_t salt_size)
        !           380: {
        !           381:        private_gcm_aead_t *this;
        !           382:        size_t icv_size;
        !           383: 
        !           384:        switch (key_size)
        !           385:        {
        !           386:                case 0:
        !           387:                        key_size = 16;
        !           388:                        break;
        !           389:                case 16:
        !           390:                case 24:
        !           391:                case 32:
        !           392:                        break;
        !           393:                default:
        !           394:                        return NULL;
        !           395:        }
        !           396:        if (salt_size && salt_size != SALT_SIZE)
        !           397:        {
        !           398:                /* currently not supported */
        !           399:                return NULL;
        !           400:        }
        !           401:        switch (algo)
        !           402:        {
        !           403:                case ENCR_AES_GCM_ICV8:
        !           404:                        algo = ENCR_AES_CBC;
        !           405:                        icv_size = 8;
        !           406:                        break;
        !           407:                case ENCR_AES_GCM_ICV12:
        !           408:                        algo = ENCR_AES_CBC;
        !           409:                        icv_size = 12;
        !           410:                        break;
        !           411:                case ENCR_AES_GCM_ICV16:
        !           412:                        algo = ENCR_AES_CBC;
        !           413:                        icv_size = 16;
        !           414:                        break;
        !           415:                default:
        !           416:                        return NULL;
        !           417:        }
        !           418: 
        !           419:        INIT(this,
        !           420:                .public = {
        !           421:                        .aead = {
        !           422:                                .encrypt = _encrypt,
        !           423:                                .decrypt = _decrypt,
        !           424:                                .get_block_size = _get_block_size,
        !           425:                                .get_icv_size = _get_icv_size,
        !           426:                                .get_iv_size = _get_iv_size,
        !           427:                                .get_iv_gen = _get_iv_gen,
        !           428:                                .get_key_size = _get_key_size,
        !           429:                                .set_key = _set_key,
        !           430:                                .destroy = _destroy,
        !           431:                        },
        !           432:                },
        !           433:                .crypter = lib->crypto->create_crypter(lib->crypto, algo, key_size),
        !           434:                .iv_gen = iv_gen_seq_create(),
        !           435:                .icv_size = icv_size,
        !           436:        );
        !           437: 
        !           438:        if (!this->crypter)
        !           439:        {
        !           440:                free(this);
        !           441:                return NULL;
        !           442:        }
        !           443: 
        !           444:        return &this->public;
        !           445: }

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