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

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2010-2015 Martin Willi
        !             3:  * Copyright (C) 2010-2015 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 "aesni_ccm.h"
        !            17: #include "aesni_key.h"
        !            18: 
        !            19: #include <crypto/iv/iv_gen_seq.h>
        !            20: 
        !            21: #include <tmmintrin.h>
        !            22: 
        !            23: #define SALT_SIZE 3
        !            24: #define IV_SIZE 8
        !            25: #define NONCE_SIZE (SALT_SIZE + IV_SIZE) /* 11 */
        !            26: #define Q_SIZE (AES_BLOCK_SIZE - NONCE_SIZE - 1) /* 4 */
        !            27: 
        !            28: typedef struct private_aesni_ccm_t private_aesni_ccm_t;
        !            29: 
        !            30: /**
        !            31:  * CCM en/decryption method type
        !            32:  */
        !            33: typedef void (*aesni_ccm_fn_t)(private_aesni_ccm_t*, size_t, u_char*, u_char*,
        !            34:                                                           u_char*, size_t, u_char*, u_char*);
        !            35: 
        !            36: /**
        !            37:  * Private data of an aesni_ccm_t object.
        !            38:  */
        !            39: struct private_aesni_ccm_t {
        !            40: 
        !            41:        /**
        !            42:         * Public aesni_ccm_t interface.
        !            43:         */
        !            44:        aesni_ccm_t public;
        !            45: 
        !            46:        /**
        !            47:         * Encryption key schedule
        !            48:         */
        !            49:        aesni_key_t *key;
        !            50: 
        !            51:        /**
        !            52:         * IV generator.
        !            53:         */
        !            54:        iv_gen_t *iv_gen;
        !            55: 
        !            56:        /**
        !            57:         * Length of the integrity check value
        !            58:         */
        !            59:        size_t icv_size;
        !            60: 
        !            61:        /**
        !            62:         * Length of the key in bytes
        !            63:         */
        !            64:        size_t key_size;
        !            65: 
        !            66:        /**
        !            67:         * CCM encryption function
        !            68:         */
        !            69:        aesni_ccm_fn_t encrypt;
        !            70: 
        !            71:        /**
        !            72:         * CCM decryption function
        !            73:         */
        !            74:        aesni_ccm_fn_t decrypt;
        !            75: 
        !            76:        /**
        !            77:         * salt to add to nonce
        !            78:         */
        !            79:        u_char salt[SALT_SIZE];
        !            80: };
        !            81: 
        !            82: /**
        !            83:  * First block with control information
        !            84:  */
        !            85: typedef struct __attribute__((packed)) {
        !            86:        BITFIELD4(uint8_t,
        !            87:                /* size of p length field q, as q-1 */
        !            88:                q_len: 3,
        !            89:                /* size of our ICV t, as (t-2)/2 */
        !            90:                t_len: 3,
        !            91:                /* do we have associated data */
        !            92:                assoc: 1,
        !            93:                reserved: 1,
        !            94:        ) flags;
        !            95:        /* nonce value */
        !            96:        struct __attribute__((packed)) {
        !            97:                u_char salt[SALT_SIZE];
        !            98:                u_char iv[IV_SIZE];
        !            99:        } nonce;
        !           100:        /* length of plain text, q */
        !           101:        u_char q[Q_SIZE];
        !           102: } b0_t;
        !           103: 
        !           104: /**
        !           105:  * Counter block
        !           106:  */
        !           107: typedef struct __attribute__((packed)) {
        !           108:        BITFIELD3(uint8_t,
        !           109:                /* size of p length field q, as q-1 */
        !           110:                q_len: 3,
        !           111:                zero: 3,
        !           112:                reserved: 2,
        !           113:        ) flags;
        !           114:        /* nonce value */
        !           115:        struct __attribute__((packed)) {
        !           116:                u_char salt[SALT_SIZE];
        !           117:                u_char iv[IV_SIZE];
        !           118:        } nonce;
        !           119:        /* counter value */
        !           120:        u_char i[Q_SIZE];
        !           121: } ctr_t;
        !           122: 
        !           123: /**
        !           124:  * Build the first block B0
        !           125:  */
        !           126: static void build_b0(private_aesni_ccm_t *this, size_t len, size_t alen,
        !           127:                                         u_char *iv, void *out)
        !           128: {
        !           129:        b0_t *block = out;
        !           130: 
        !           131:        block->flags.reserved = 0;
        !           132:        block->flags.assoc = alen ? 1 : 0;
        !           133:        block->flags.t_len = (this->icv_size - 2) / 2;
        !           134:        block->flags.q_len = Q_SIZE - 1;
        !           135:        memcpy(block->nonce.salt, this->salt, SALT_SIZE);
        !           136:        memcpy(block->nonce.iv, iv, IV_SIZE);
        !           137:        htoun32(block->q, len);
        !           138: }
        !           139: 
        !           140: /**
        !           141:  * Build a counter block for counter i
        !           142:  */
        !           143: static void build_ctr(private_aesni_ccm_t *this, uint32_t i, u_char *iv,
        !           144:                                          void *out)
        !           145: {
        !           146:        ctr_t *ctr = out;
        !           147: 
        !           148:        ctr->flags.reserved = 0;
        !           149:        ctr->flags.zero = 0;
        !           150:        ctr->flags.q_len = Q_SIZE - 1;
        !           151:        memcpy(ctr->nonce.salt, this->salt, SALT_SIZE);
        !           152:        memcpy(ctr->nonce.iv, iv, IV_SIZE);
        !           153:        htoun32(ctr->i, i);
        !           154: }
        !           155: 
        !           156: /**
        !           157:  * Calculate the ICV for the b0 and associated data
        !           158:  */
        !           159: static __m128i icv_header(private_aesni_ccm_t *this, size_t len, u_char *iv,
        !           160:                                                  uint16_t alen, u_char *assoc)
        !           161: {
        !           162:        __m128i *ks, b, t, c;
        !           163:        u_int i, round, blocks, rem;
        !           164: 
        !           165:        ks = this->key->schedule;
        !           166:        build_b0(this, len, alen, iv, &b);
        !           167:        c = _mm_loadu_si128(&b);
        !           168:        c = _mm_xor_si128(c, ks[0]);
        !           169:        for (round = 1; round < this->key->rounds; round++)
        !           170:        {
        !           171:                c = _mm_aesenc_si128(c, ks[round]);
        !           172:        }
        !           173:        c = _mm_aesenclast_si128(c, ks[this->key->rounds]);
        !           174: 
        !           175:        if (alen)
        !           176:        {
        !           177:                blocks = (alen + sizeof(alen)) / AES_BLOCK_SIZE;
        !           178:                rem = (alen + sizeof(alen)) % AES_BLOCK_SIZE;
        !           179:                if (rem)
        !           180:                {
        !           181:                        blocks++;
        !           182:                }
        !           183:                for (i = 0; i < blocks; i++)
        !           184:                {
        !           185:                        if (i == 0)
        !           186:                        {       /* first block */
        !           187:                                memset(&b, 0, sizeof(b));
        !           188:                                htoun16(&b, alen);
        !           189:                                memcpy(((u_char*)&b) + sizeof(alen), assoc,
        !           190:                                           min(alen, sizeof(b) - sizeof(alen)));
        !           191:                                t = _mm_loadu_si128(&b);
        !           192:                        }
        !           193:                        else if (i == blocks - 1 && rem)
        !           194:                        {       /* last block with padding */
        !           195:                                memset(&b, 0, sizeof(b));
        !           196:                                memcpy(&b, ((__m128i*)(assoc - sizeof(alen))) + i, rem);
        !           197:                                t = _mm_loadu_si128(&b);
        !           198:                        }
        !           199:                        else
        !           200:                        {       /* full block */
        !           201:                                t = _mm_loadu_si128(((__m128i*)(assoc - sizeof(alen))) + i);
        !           202:                        }
        !           203:                        c = _mm_xor_si128(t, c);
        !           204:                        c = _mm_xor_si128(c, ks[0]);
        !           205:                        for (round = 1; round < this->key->rounds; round++)
        !           206:                        {
        !           207:                                c = _mm_aesenc_si128(c, ks[round]);
        !           208:                        }
        !           209:                        c = _mm_aesenclast_si128(c, ks[this->key->rounds]);
        !           210:                }
        !           211:        }
        !           212:        return c;
        !           213: }
        !           214: 
        !           215: /**
        !           216:  * En-/Decrypt the ICV, trim and store it
        !           217:  */
        !           218: static void crypt_icv(private_aesni_ccm_t *this, u_char *iv,
        !           219:                                          __m128i c, u_char *icv)
        !           220: {
        !           221:        __m128i *ks, b, t;
        !           222:        u_int round;
        !           223: 
        !           224:        ks = this->key->schedule;
        !           225:        build_ctr(this, 0, iv, &b);
        !           226: 
        !           227:        t = _mm_loadu_si128(&b);
        !           228:        t = _mm_xor_si128(t, ks[0]);
        !           229:        for (round = 1; round < this->key->rounds; round++)
        !           230:        {
        !           231:                t = _mm_aesenc_si128(t, ks[round]);
        !           232:        }
        !           233:        t = _mm_aesenclast_si128(t, ks[this->key->rounds]);
        !           234: 
        !           235:        t = _mm_xor_si128(t, c);
        !           236: 
        !           237:        _mm_storeu_si128(&b, t);
        !           238:        memcpy(icv, &b, this->icv_size);
        !           239: }
        !           240: 
        !           241: /**
        !           242:  * Do big-endian increment on x
        !           243:  */
        !           244: static inline __m128i increment_be(__m128i x)
        !           245: {
        !           246:        __m128i swap;
        !           247: 
        !           248:        swap = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
        !           249: 
        !           250:        x = _mm_shuffle_epi8(x, swap);
        !           251:        x = _mm_add_epi64(x, _mm_set_epi32(0, 0, 0, 1));
        !           252:        x = _mm_shuffle_epi8(x, swap);
        !           253: 
        !           254:        return x;
        !           255: }
        !           256: 
        !           257: /**
        !           258:  * Encrypt a remaining incomplete block
        !           259:  */
        !           260: static __m128i encrypt_ccm_rem(aesni_key_t *key, u_int rem, __m128i state,
        !           261:                                                           void *in, void *out, __m128i c)
        !           262: {
        !           263:        __m128i *ks, t, b, d;
        !           264:        u_int round;
        !           265: 
        !           266:        ks = key->schedule;
        !           267:        memset(&b, 0, sizeof(b));
        !           268:        memcpy(&b, in, rem);
        !           269:        d = _mm_loadu_si128(&b);
        !           270: 
        !           271:        c = _mm_xor_si128(d, c);
        !           272:        c = _mm_xor_si128(c, ks[0]);
        !           273:        t = _mm_xor_si128(state, ks[0]);
        !           274:        for (round = 1; round < key->rounds; round++)
        !           275:        {
        !           276:                c = _mm_aesenc_si128(c, ks[round]);
        !           277:                t = _mm_aesenc_si128(t, ks[round]);
        !           278:        }
        !           279:        c = _mm_aesenclast_si128(c, ks[key->rounds]);
        !           280:        t = _mm_aesenclast_si128(t, ks[key->rounds]);
        !           281: 
        !           282:        t = _mm_xor_si128(t, d);
        !           283:        _mm_storeu_si128(&b, t);
        !           284: 
        !           285:        memcpy(out, &b, rem);
        !           286: 
        !           287:        return c;
        !           288: }
        !           289: 
        !           290: /**
        !           291:  * Decrypt a remaining incomplete block
        !           292:  */
        !           293: static __m128i decrypt_ccm_rem(aesni_key_t *key, u_int rem, __m128i state,
        !           294:                                                           void *in, void *out, __m128i c)
        !           295: {
        !           296:        __m128i *ks, t, b, d;
        !           297:        u_int round;
        !           298: 
        !           299:        ks = key->schedule;
        !           300:        memset(&b, 0, sizeof(b));
        !           301:        memcpy(&b, in, rem);
        !           302:        d = _mm_loadu_si128(&b);
        !           303: 
        !           304:        t = _mm_xor_si128(state, ks[0]);
        !           305:        for (round = 1; round < key->rounds; round++)
        !           306:        {
        !           307:                t = _mm_aesenc_si128(t, ks[round]);
        !           308:        }
        !           309:        t = _mm_aesenclast_si128(t, ks[key->rounds]);
        !           310:        t = _mm_xor_si128(t, d);
        !           311:        _mm_storeu_si128(&b, t);
        !           312: 
        !           313:        memset((u_char*)&b + rem, 0, sizeof(b) - rem);
        !           314:        t = _mm_loadu_si128(&b);
        !           315:        c = _mm_xor_si128(t, c);
        !           316:        c = _mm_xor_si128(c, ks[0]);
        !           317:        for (round = 1; round < key->rounds; round++)
        !           318:        {
        !           319:                c = _mm_aesenc_si128(c, ks[round]);
        !           320:        }
        !           321:        c = _mm_aesenclast_si128(c, ks[key->rounds]);
        !           322: 
        !           323:        memcpy(out, &b, rem);
        !           324: 
        !           325:        return c;
        !           326: }
        !           327: 
        !           328: /**
        !           329:  * AES-128 CCM encryption/ICV generation
        !           330:  */
        !           331: static void encrypt_ccm128(private_aesni_ccm_t *this,
        !           332:                                                   size_t len, u_char *in, u_char *out, u_char *iv,
        !           333:                                                   size_t alen, u_char *assoc, u_char *icv)
        !           334: {
        !           335:        __m128i *ks, d, t, c, b, state, *bi, *bo;
        !           336:        u_int blocks, rem, i;
        !           337: 
        !           338:        c = icv_header(this, len, iv, alen, assoc);
        !           339:        build_ctr(this, 1, iv, &b);
        !           340:        state = _mm_load_si128(&b);
        !           341:        blocks = len / AES_BLOCK_SIZE;
        !           342:        rem = len % AES_BLOCK_SIZE;
        !           343:        bi = (__m128i*)in;
        !           344:        bo = (__m128i*)out;
        !           345: 
        !           346:        ks = this->key->schedule;
        !           347: 
        !           348:        for (i = 0; i < blocks; i++)
        !           349:        {
        !           350:                d = _mm_loadu_si128(bi + i);
        !           351: 
        !           352:                c = _mm_xor_si128(d, c);
        !           353:                c = _mm_xor_si128(c, ks[0]);
        !           354:                t = _mm_xor_si128(state, ks[0]);
        !           355: 
        !           356:                c = _mm_aesenc_si128(c, ks[1]);
        !           357:                t = _mm_aesenc_si128(t, ks[1]);
        !           358:                c = _mm_aesenc_si128(c, ks[2]);
        !           359:                t = _mm_aesenc_si128(t, ks[2]);
        !           360:                c = _mm_aesenc_si128(c, ks[3]);
        !           361:                t = _mm_aesenc_si128(t, ks[3]);
        !           362:                c = _mm_aesenc_si128(c, ks[4]);
        !           363:                t = _mm_aesenc_si128(t, ks[4]);
        !           364:                c = _mm_aesenc_si128(c, ks[5]);
        !           365:                t = _mm_aesenc_si128(t, ks[5]);
        !           366:                c = _mm_aesenc_si128(c, ks[6]);
        !           367:                t = _mm_aesenc_si128(t, ks[6]);
        !           368:                c = _mm_aesenc_si128(c, ks[7]);
        !           369:                t = _mm_aesenc_si128(t, ks[7]);
        !           370:                c = _mm_aesenc_si128(c, ks[8]);
        !           371:                t = _mm_aesenc_si128(t, ks[8]);
        !           372:                c = _mm_aesenc_si128(c, ks[9]);
        !           373:                t = _mm_aesenc_si128(t, ks[9]);
        !           374: 
        !           375:                c = _mm_aesenclast_si128(c, ks[10]);
        !           376:                t = _mm_aesenclast_si128(t, ks[10]);
        !           377: 
        !           378:                t = _mm_xor_si128(t, d);
        !           379:                _mm_storeu_si128(bo + i, t);
        !           380: 
        !           381:                state = increment_be(state);
        !           382:        }
        !           383: 
        !           384:        if (rem)
        !           385:        {
        !           386:                c = encrypt_ccm_rem(this->key, rem, state, bi + blocks, bo + blocks, c);
        !           387:        }
        !           388:        crypt_icv(this, iv, c, icv);
        !           389: }
        !           390: 
        !           391: /**
        !           392:  * AES-128 CCM decryption/ICV generation
        !           393:  */
        !           394: static void decrypt_ccm128(private_aesni_ccm_t *this,
        !           395:                                                   size_t len, u_char *in, u_char *out, u_char *iv,
        !           396:                                                   size_t alen, u_char *assoc, u_char *icv)
        !           397: {
        !           398:        __m128i *ks, d, t, c, b, state, *bi, *bo;
        !           399:        u_int blocks, rem, i;
        !           400: 
        !           401:        c = icv_header(this, len, iv, alen, assoc);
        !           402:        build_ctr(this, 1, iv, &b);
        !           403:        state = _mm_load_si128(&b);
        !           404:        blocks = len / AES_BLOCK_SIZE;
        !           405:        rem = len % AES_BLOCK_SIZE;
        !           406:        bi = (__m128i*)in;
        !           407:        bo = (__m128i*)out;
        !           408: 
        !           409:        ks = this->key->schedule;
        !           410: 
        !           411:        for (i = 0; i < blocks; i++)
        !           412:        {
        !           413:                d = _mm_loadu_si128(bi + i);
        !           414: 
        !           415:                t = _mm_xor_si128(state, ks[0]);
        !           416: 
        !           417:                t = _mm_aesenc_si128(t, ks[1]);
        !           418:                t = _mm_aesenc_si128(t, ks[2]);
        !           419:                t = _mm_aesenc_si128(t, ks[3]);
        !           420:                t = _mm_aesenc_si128(t, ks[4]);
        !           421:                t = _mm_aesenc_si128(t, ks[5]);
        !           422:                t = _mm_aesenc_si128(t, ks[6]);
        !           423:                t = _mm_aesenc_si128(t, ks[7]);
        !           424:                t = _mm_aesenc_si128(t, ks[8]);
        !           425:                t = _mm_aesenc_si128(t, ks[9]);
        !           426: 
        !           427:                t = _mm_aesenclast_si128(t, ks[10]);
        !           428:                t = _mm_xor_si128(t, d);
        !           429:                _mm_storeu_si128(bo + i, t);
        !           430: 
        !           431:                c = _mm_xor_si128(t, c);
        !           432:                c = _mm_xor_si128(c, ks[0]);
        !           433: 
        !           434:                c = _mm_aesenc_si128(c, ks[1]);
        !           435:                c = _mm_aesenc_si128(c, ks[2]);
        !           436:                c = _mm_aesenc_si128(c, ks[3]);
        !           437:                c = _mm_aesenc_si128(c, ks[4]);
        !           438:                c = _mm_aesenc_si128(c, ks[5]);
        !           439:                c = _mm_aesenc_si128(c, ks[6]);
        !           440:                c = _mm_aesenc_si128(c, ks[7]);
        !           441:                c = _mm_aesenc_si128(c, ks[8]);
        !           442:                c = _mm_aesenc_si128(c, ks[9]);
        !           443: 
        !           444:                c = _mm_aesenclast_si128(c, ks[10]);
        !           445: 
        !           446:                state = increment_be(state);
        !           447:        }
        !           448: 
        !           449:        if (rem)
        !           450:        {
        !           451:                c = decrypt_ccm_rem(this->key, rem, state, bi + blocks, bo + blocks, c);
        !           452:        }
        !           453:        crypt_icv(this, iv, c, icv);
        !           454: }
        !           455: 
        !           456: /**
        !           457:  * AES-192 CCM encryption/ICV generation
        !           458:  */
        !           459: static void encrypt_ccm192(private_aesni_ccm_t *this,
        !           460:                                                   size_t len, u_char *in, u_char *out, u_char *iv,
        !           461:                                                   size_t alen, u_char *assoc, u_char *icv)
        !           462: {
        !           463:        __m128i *ks, d, t, c, b, state, *bi, *bo;
        !           464:        u_int blocks, rem, i;
        !           465: 
        !           466:        c = icv_header(this, len, iv, alen, assoc);
        !           467:        build_ctr(this, 1, iv, &b);
        !           468:        state = _mm_load_si128(&b);
        !           469:        blocks = len / AES_BLOCK_SIZE;
        !           470:        rem = len % AES_BLOCK_SIZE;
        !           471:        bi = (__m128i*)in;
        !           472:        bo = (__m128i*)out;
        !           473: 
        !           474:        ks = this->key->schedule;
        !           475: 
        !           476:        for (i = 0; i < blocks; i++)
        !           477:        {
        !           478:                d = _mm_loadu_si128(bi + i);
        !           479: 
        !           480:                c = _mm_xor_si128(d, c);
        !           481:                c = _mm_xor_si128(c, ks[0]);
        !           482:                t = _mm_xor_si128(state, ks[0]);
        !           483: 
        !           484:                c = _mm_aesenc_si128(c, ks[1]);
        !           485:                t = _mm_aesenc_si128(t, ks[1]);
        !           486:                c = _mm_aesenc_si128(c, ks[2]);
        !           487:                t = _mm_aesenc_si128(t, ks[2]);
        !           488:                c = _mm_aesenc_si128(c, ks[3]);
        !           489:                t = _mm_aesenc_si128(t, ks[3]);
        !           490:                c = _mm_aesenc_si128(c, ks[4]);
        !           491:                t = _mm_aesenc_si128(t, ks[4]);
        !           492:                c = _mm_aesenc_si128(c, ks[5]);
        !           493:                t = _mm_aesenc_si128(t, ks[5]);
        !           494:                c = _mm_aesenc_si128(c, ks[6]);
        !           495:                t = _mm_aesenc_si128(t, ks[6]);
        !           496:                c = _mm_aesenc_si128(c, ks[7]);
        !           497:                t = _mm_aesenc_si128(t, ks[7]);
        !           498:                c = _mm_aesenc_si128(c, ks[8]);
        !           499:                t = _mm_aesenc_si128(t, ks[8]);
        !           500:                c = _mm_aesenc_si128(c, ks[9]);
        !           501:                t = _mm_aesenc_si128(t, ks[9]);
        !           502:                c = _mm_aesenc_si128(c, ks[10]);
        !           503:                t = _mm_aesenc_si128(t, ks[10]);
        !           504:                c = _mm_aesenc_si128(c, ks[11]);
        !           505:                t = _mm_aesenc_si128(t, ks[11]);
        !           506: 
        !           507:                c = _mm_aesenclast_si128(c, ks[12]);
        !           508:                t = _mm_aesenclast_si128(t, ks[12]);
        !           509: 
        !           510:                t = _mm_xor_si128(t, d);
        !           511:                _mm_storeu_si128(bo + i, t);
        !           512: 
        !           513:                state = increment_be(state);
        !           514:        }
        !           515: 
        !           516:        if (rem)
        !           517:        {
        !           518:                c = encrypt_ccm_rem(this->key, rem, state, bi + blocks, bo + blocks, c);
        !           519:        }
        !           520:        crypt_icv(this, iv, c, icv);
        !           521: }
        !           522: 
        !           523: /**
        !           524:  * AES-192 CCM decryption/ICV generation
        !           525:  */
        !           526: static void decrypt_ccm192(private_aesni_ccm_t *this,
        !           527:                                                   size_t len, u_char *in, u_char *out, u_char *iv,
        !           528:                                                   size_t alen, u_char *assoc, u_char *icv)
        !           529: {
        !           530:        __m128i *ks, d, t, c, b, state, *bi, *bo;
        !           531:        u_int blocks, rem, i;
        !           532: 
        !           533:        c = icv_header(this, len, iv, alen, assoc);
        !           534:        build_ctr(this, 1, iv, &b);
        !           535:        state = _mm_load_si128(&b);
        !           536:        blocks = len / AES_BLOCK_SIZE;
        !           537:        rem = len % AES_BLOCK_SIZE;
        !           538:        bi = (__m128i*)in;
        !           539:        bo = (__m128i*)out;
        !           540: 
        !           541:        ks = this->key->schedule;
        !           542: 
        !           543:        for (i = 0; i < blocks; i++)
        !           544:        {
        !           545:                d = _mm_loadu_si128(bi + i);
        !           546: 
        !           547:                t = _mm_xor_si128(state, ks[0]);
        !           548: 
        !           549:                t = _mm_aesenc_si128(t, ks[1]);
        !           550:                t = _mm_aesenc_si128(t, ks[2]);
        !           551:                t = _mm_aesenc_si128(t, ks[3]);
        !           552:                t = _mm_aesenc_si128(t, ks[4]);
        !           553:                t = _mm_aesenc_si128(t, ks[5]);
        !           554:                t = _mm_aesenc_si128(t, ks[6]);
        !           555:                t = _mm_aesenc_si128(t, ks[7]);
        !           556:                t = _mm_aesenc_si128(t, ks[8]);
        !           557:                t = _mm_aesenc_si128(t, ks[9]);
        !           558:                t = _mm_aesenc_si128(t, ks[10]);
        !           559:                t = _mm_aesenc_si128(t, ks[11]);
        !           560: 
        !           561:                t = _mm_aesenclast_si128(t, ks[12]);
        !           562:                t = _mm_xor_si128(t, d);
        !           563:                _mm_storeu_si128(bo + i, t);
        !           564: 
        !           565:                c = _mm_xor_si128(t, c);
        !           566:                c = _mm_xor_si128(c, ks[0]);
        !           567: 
        !           568:                c = _mm_aesenc_si128(c, ks[1]);
        !           569:                c = _mm_aesenc_si128(c, ks[2]);
        !           570:                c = _mm_aesenc_si128(c, ks[3]);
        !           571:                c = _mm_aesenc_si128(c, ks[4]);
        !           572:                c = _mm_aesenc_si128(c, ks[5]);
        !           573:                c = _mm_aesenc_si128(c, ks[6]);
        !           574:                c = _mm_aesenc_si128(c, ks[7]);
        !           575:                c = _mm_aesenc_si128(c, ks[8]);
        !           576:                c = _mm_aesenc_si128(c, ks[9]);
        !           577:                c = _mm_aesenc_si128(c, ks[10]);
        !           578:                c = _mm_aesenc_si128(c, ks[11]);
        !           579: 
        !           580:                c = _mm_aesenclast_si128(c, ks[12]);
        !           581: 
        !           582:                state = increment_be(state);
        !           583:        }
        !           584: 
        !           585:        if (rem)
        !           586:        {
        !           587:                c = decrypt_ccm_rem(this->key, rem, state, bi + blocks, bo + blocks, c);
        !           588:        }
        !           589:        crypt_icv(this, iv, c, icv);
        !           590: }
        !           591: 
        !           592: /**
        !           593:  * AES-256 CCM encryption/ICV generation
        !           594:  */
        !           595: static void encrypt_ccm256(private_aesni_ccm_t *this,
        !           596:                                                   size_t len, u_char *in, u_char *out, u_char *iv,
        !           597:                                                   size_t alen, u_char *assoc, u_char *icv)
        !           598: {
        !           599:        __m128i *ks, d, t, c, b, state, *bi, *bo;
        !           600:        u_int blocks, rem, i;
        !           601: 
        !           602:        c = icv_header(this, len, iv, alen, assoc);
        !           603:        build_ctr(this, 1, iv, &b);
        !           604:        state = _mm_load_si128(&b);
        !           605:        blocks = len / AES_BLOCK_SIZE;
        !           606:        rem = len % AES_BLOCK_SIZE;
        !           607:        bi = (__m128i*)in;
        !           608:        bo = (__m128i*)out;
        !           609: 
        !           610:        ks = this->key->schedule;
        !           611: 
        !           612:        for (i = 0; i < blocks; i++)
        !           613:        {
        !           614:                d = _mm_loadu_si128(bi + i);
        !           615: 
        !           616:                c = _mm_xor_si128(d, c);
        !           617:                c = _mm_xor_si128(c, ks[0]);
        !           618:                t = _mm_xor_si128(state, ks[0]);
        !           619: 
        !           620:                c = _mm_aesenc_si128(c, ks[1]);
        !           621:                t = _mm_aesenc_si128(t, ks[1]);
        !           622:                c = _mm_aesenc_si128(c, ks[2]);
        !           623:                t = _mm_aesenc_si128(t, ks[2]);
        !           624:                c = _mm_aesenc_si128(c, ks[3]);
        !           625:                t = _mm_aesenc_si128(t, ks[3]);
        !           626:                c = _mm_aesenc_si128(c, ks[4]);
        !           627:                t = _mm_aesenc_si128(t, ks[4]);
        !           628:                c = _mm_aesenc_si128(c, ks[5]);
        !           629:                t = _mm_aesenc_si128(t, ks[5]);
        !           630:                c = _mm_aesenc_si128(c, ks[6]);
        !           631:                t = _mm_aesenc_si128(t, ks[6]);
        !           632:                c = _mm_aesenc_si128(c, ks[7]);
        !           633:                t = _mm_aesenc_si128(t, ks[7]);
        !           634:                c = _mm_aesenc_si128(c, ks[8]);
        !           635:                t = _mm_aesenc_si128(t, ks[8]);
        !           636:                c = _mm_aesenc_si128(c, ks[9]);
        !           637:                t = _mm_aesenc_si128(t, ks[9]);
        !           638:                c = _mm_aesenc_si128(c, ks[10]);
        !           639:                t = _mm_aesenc_si128(t, ks[10]);
        !           640:                c = _mm_aesenc_si128(c, ks[11]);
        !           641:                t = _mm_aesenc_si128(t, ks[11]);
        !           642:                c = _mm_aesenc_si128(c, ks[12]);
        !           643:                t = _mm_aesenc_si128(t, ks[12]);
        !           644:                c = _mm_aesenc_si128(c, ks[13]);
        !           645:                t = _mm_aesenc_si128(t, ks[13]);
        !           646: 
        !           647:                c = _mm_aesenclast_si128(c, ks[14]);
        !           648:                t = _mm_aesenclast_si128(t, ks[14]);
        !           649: 
        !           650:                t = _mm_xor_si128(t, d);
        !           651:                _mm_storeu_si128(bo + i, t);
        !           652: 
        !           653:                state = increment_be(state);
        !           654:        }
        !           655: 
        !           656:        if (rem)
        !           657:        {
        !           658:                c = encrypt_ccm_rem(this->key, rem, state, bi + blocks, bo + blocks, c);
        !           659:        }
        !           660:        crypt_icv(this, iv, c, icv);
        !           661: }
        !           662: 
        !           663: /**
        !           664:  * AES-256 CCM decryption/ICV generation
        !           665:  */
        !           666: static void decrypt_ccm256(private_aesni_ccm_t *this,
        !           667:                                                   size_t len, u_char *in, u_char *out, u_char *iv,
        !           668:                                                   size_t alen, u_char *assoc, u_char *icv)
        !           669: {
        !           670:        __m128i *ks, d, t, c, b, state, *bi, *bo;
        !           671:        u_int blocks, rem, i;
        !           672: 
        !           673:        c = icv_header(this, len, iv, alen, assoc);
        !           674:        build_ctr(this, 1, iv, &b);
        !           675:        state = _mm_load_si128(&b);
        !           676:        blocks = len / AES_BLOCK_SIZE;
        !           677:        rem = len % AES_BLOCK_SIZE;
        !           678:        bi = (__m128i*)in;
        !           679:        bo = (__m128i*)out;
        !           680: 
        !           681:        ks = this->key->schedule;
        !           682: 
        !           683:        for (i = 0; i < blocks; i++)
        !           684:        {
        !           685:                d = _mm_loadu_si128(bi + i);
        !           686: 
        !           687:                t = _mm_xor_si128(state, ks[0]);
        !           688: 
        !           689:                t = _mm_aesenc_si128(t, ks[1]);
        !           690:                t = _mm_aesenc_si128(t, ks[2]);
        !           691:                t = _mm_aesenc_si128(t, ks[3]);
        !           692:                t = _mm_aesenc_si128(t, ks[4]);
        !           693:                t = _mm_aesenc_si128(t, ks[5]);
        !           694:                t = _mm_aesenc_si128(t, ks[6]);
        !           695:                t = _mm_aesenc_si128(t, ks[7]);
        !           696:                t = _mm_aesenc_si128(t, ks[8]);
        !           697:                t = _mm_aesenc_si128(t, ks[9]);
        !           698:                t = _mm_aesenc_si128(t, ks[10]);
        !           699:                t = _mm_aesenc_si128(t, ks[11]);
        !           700:                t = _mm_aesenc_si128(t, ks[12]);
        !           701:                t = _mm_aesenc_si128(t, ks[13]);
        !           702: 
        !           703:                t = _mm_aesenclast_si128(t, ks[14]);
        !           704:                t = _mm_xor_si128(t, d);
        !           705:                _mm_storeu_si128(bo + i, t);
        !           706: 
        !           707:                c = _mm_xor_si128(t, c);
        !           708:                c = _mm_xor_si128(c, ks[0]);
        !           709: 
        !           710:                c = _mm_aesenc_si128(c, ks[1]);
        !           711:                c = _mm_aesenc_si128(c, ks[2]);
        !           712:                c = _mm_aesenc_si128(c, ks[3]);
        !           713:                c = _mm_aesenc_si128(c, ks[4]);
        !           714:                c = _mm_aesenc_si128(c, ks[5]);
        !           715:                c = _mm_aesenc_si128(c, ks[6]);
        !           716:                c = _mm_aesenc_si128(c, ks[7]);
        !           717:                c = _mm_aesenc_si128(c, ks[8]);
        !           718:                c = _mm_aesenc_si128(c, ks[9]);
        !           719:                c = _mm_aesenc_si128(c, ks[10]);
        !           720:                c = _mm_aesenc_si128(c, ks[11]);
        !           721:                c = _mm_aesenc_si128(c, ks[12]);
        !           722:                c = _mm_aesenc_si128(c, ks[13]);
        !           723: 
        !           724:                c = _mm_aesenclast_si128(c, ks[14]);
        !           725: 
        !           726:                state = increment_be(state);
        !           727:        }
        !           728: 
        !           729:        if (rem)
        !           730:        {
        !           731:                c = decrypt_ccm_rem(this->key, rem, state, bi + blocks, bo + blocks, c);
        !           732:        }
        !           733:        crypt_icv(this, iv, c, icv);
        !           734: }
        !           735: 
        !           736: METHOD(aead_t, encrypt, bool,
        !           737:        private_aesni_ccm_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
        !           738:        chunk_t *encr)
        !           739: {
        !           740:        u_char *out;
        !           741: 
        !           742:        if (!this->key || iv.len != IV_SIZE)
        !           743:        {
        !           744:                return FALSE;
        !           745:        }
        !           746:        out = plain.ptr;
        !           747:        if (encr)
        !           748:        {
        !           749:                *encr = chunk_alloc(plain.len + this->icv_size);
        !           750:                out = encr->ptr;
        !           751:        }
        !           752:        this->encrypt(this, plain.len, plain.ptr, out, iv.ptr,
        !           753:                                  assoc.len, assoc.ptr, out + plain.len);
        !           754:        return TRUE;
        !           755: }
        !           756: 
        !           757: METHOD(aead_t, decrypt, bool,
        !           758:        private_aesni_ccm_t *this, chunk_t encr, chunk_t assoc, chunk_t iv,
        !           759:        chunk_t *plain)
        !           760: {
        !           761:        u_char *out, icv[this->icv_size];
        !           762: 
        !           763:        if (!this->key || iv.len != IV_SIZE || encr.len < this->icv_size)
        !           764:        {
        !           765:                return FALSE;
        !           766:        }
        !           767:        encr.len -= this->icv_size;
        !           768:        out = encr.ptr;
        !           769:        if (plain)
        !           770:        {
        !           771:                *plain = chunk_alloc(encr.len);
        !           772:                out = plain->ptr;
        !           773:        }
        !           774: 
        !           775:        this->decrypt(this, encr.len, encr.ptr, out, iv.ptr,
        !           776:                                  assoc.len, assoc.ptr, icv);
        !           777:        return memeq_const(icv, encr.ptr + encr.len, this->icv_size);
        !           778: }
        !           779: 
        !           780: METHOD(aead_t, get_block_size, size_t,
        !           781:        private_aesni_ccm_t *this)
        !           782: {
        !           783:        return 1;
        !           784: }
        !           785: 
        !           786: METHOD(aead_t, get_icv_size, size_t,
        !           787:        private_aesni_ccm_t *this)
        !           788: {
        !           789:        return this->icv_size;
        !           790: }
        !           791: 
        !           792: METHOD(aead_t, get_iv_size, size_t,
        !           793:        private_aesni_ccm_t *this)
        !           794: {
        !           795:        return IV_SIZE;
        !           796: }
        !           797: 
        !           798: METHOD(aead_t, get_iv_gen, iv_gen_t*,
        !           799:        private_aesni_ccm_t *this)
        !           800: {
        !           801:        return this->iv_gen;
        !           802: }
        !           803: 
        !           804: METHOD(aead_t, get_key_size, size_t,
        !           805:        private_aesni_ccm_t *this)
        !           806: {
        !           807:        return this->key_size + SALT_SIZE;
        !           808: }
        !           809: 
        !           810: METHOD(aead_t, set_key, bool,
        !           811:        private_aesni_ccm_t *this, chunk_t key)
        !           812: {
        !           813:        if (key.len != this->key_size + SALT_SIZE)
        !           814:        {
        !           815:                return FALSE;
        !           816:        }
        !           817: 
        !           818:        memcpy(this->salt, key.ptr + key.len - SALT_SIZE, SALT_SIZE);
        !           819:        key.len -= SALT_SIZE;
        !           820: 
        !           821:        DESTROY_IF(this->key);
        !           822:        this->key = aesni_key_create(TRUE, key);
        !           823:        return TRUE;
        !           824: }
        !           825: 
        !           826: METHOD(aead_t, destroy, void,
        !           827:        private_aesni_ccm_t *this)
        !           828: {
        !           829:        DESTROY_IF(this->key);
        !           830:        this->iv_gen->destroy(this->iv_gen);
        !           831:        free_align(this);
        !           832: }
        !           833: 
        !           834: /**
        !           835:  * See header
        !           836:  */
        !           837: aesni_ccm_t *aesni_ccm_create(encryption_algorithm_t algo,
        !           838:                                                          size_t key_size, size_t salt_size)
        !           839: {
        !           840:        private_aesni_ccm_t *this;
        !           841:        size_t icv_size;
        !           842: 
        !           843:        switch (key_size)
        !           844:        {
        !           845:                case 0:
        !           846:                        key_size = 16;
        !           847:                        break;
        !           848:                case 16:
        !           849:                case 24:
        !           850:                case 32:
        !           851:                        break;
        !           852:                default:
        !           853:                        return NULL;
        !           854:        }
        !           855:        if (salt_size && salt_size != SALT_SIZE)
        !           856:        {
        !           857:                /* currently not supported */
        !           858:                return NULL;
        !           859:        }
        !           860:        switch (algo)
        !           861:        {
        !           862:                case ENCR_AES_CCM_ICV8:
        !           863:                        algo = ENCR_AES_CBC;
        !           864:                        icv_size = 8;
        !           865:                        break;
        !           866:                case ENCR_AES_CCM_ICV12:
        !           867:                        algo = ENCR_AES_CBC;
        !           868:                        icv_size = 12;
        !           869:                        break;
        !           870:                case ENCR_AES_CCM_ICV16:
        !           871:                        algo = ENCR_AES_CBC;
        !           872:                        icv_size = 16;
        !           873:                        break;
        !           874:                default:
        !           875:                        return NULL;
        !           876:        }
        !           877: 
        !           878:        INIT_ALIGN(this, sizeof(__m128i),
        !           879:                .public = {
        !           880:                        .aead = {
        !           881:                                .encrypt = _encrypt,
        !           882:                                .decrypt = _decrypt,
        !           883:                                .get_block_size = _get_block_size,
        !           884:                                .get_icv_size = _get_icv_size,
        !           885:                                .get_iv_size = _get_iv_size,
        !           886:                                .get_iv_gen = _get_iv_gen,
        !           887:                                .get_key_size = _get_key_size,
        !           888:                                .set_key = _set_key,
        !           889:                                .destroy = _destroy,
        !           890:                        },
        !           891:                },
        !           892:                .key_size = key_size,
        !           893:                .iv_gen = iv_gen_seq_create(),
        !           894:                .icv_size = icv_size,
        !           895:        );
        !           896: 
        !           897:        switch (key_size)
        !           898:        {
        !           899:                case 16:
        !           900:                        this->encrypt = encrypt_ccm128;
        !           901:                        this->decrypt = decrypt_ccm128;
        !           902:                        break;
        !           903:                case 24:
        !           904:                        this->encrypt = encrypt_ccm192;
        !           905:                        this->decrypt = decrypt_ccm192;
        !           906:                        break;
        !           907:                case 32:
        !           908:                        this->encrypt = encrypt_ccm256;
        !           909:                        this->decrypt = decrypt_ccm256;
        !           910:                        break;
        !           911:        }
        !           912: 
        !           913:        return &this->public;
        !           914: }

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