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

1.1       misho       1: /*
                      2:  * Copyright (C) 2015 Martin Willi
                      3:  * Copyright (C) 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 "chapoly_aead.h"
                     17: #include "chapoly_drv.h"
                     18: 
                     19: #include <crypto/iv/iv_gen_seq.h>
                     20: 
                     21: /* maximum plain message size */
                     22: #define P_MAX 247877906880
                     23: 
                     24: typedef struct private_chapoly_aead_t private_chapoly_aead_t;
                     25: 
                     26: /**
                     27:  * Private data of an chapoly_aead_t object.
                     28:  */
                     29: struct private_chapoly_aead_t {
                     30: 
                     31:        /**
                     32:         * Public chapoly_aead_t interface.
                     33:         */
                     34:        chapoly_aead_t public;
                     35: 
                     36:        /**
                     37:         * IV generator.
                     38:         */
                     39:        iv_gen_t *iv_gen;
                     40: 
                     41:        /**
                     42:         * Driver backend
                     43:         */
                     44:        chapoly_drv_t *drv;
                     45: };
                     46: 
                     47: /**
                     48:  * Include a partial block to ICV by padding it with zero bytes
                     49:  */
                     50: static bool poly_update_padded(private_chapoly_aead_t *this,
                     51:                                                           u_char *in, size_t len)
                     52: {
                     53:        u_char b[POLY_BLOCK_SIZE];
                     54: 
                     55:        memset(b, 0, sizeof(b));
                     56:        memcpy(b, in, len);
                     57: 
                     58:        return this->drv->poly(this->drv, b, 1);
                     59: }
                     60: 
                     61: /**
                     62:  * Include associated data with padding to ICV
                     63:  */
                     64: static bool poly_head(private_chapoly_aead_t *this, u_char *assoc, size_t len)
                     65: {
                     66:        u_int blocks, rem;
                     67: 
                     68:        blocks = len / POLY_BLOCK_SIZE;
                     69:        rem = len % POLY_BLOCK_SIZE;
                     70:        if (!this->drv->poly(this->drv, assoc, blocks))
                     71:        {
                     72:                return FALSE;
                     73:        }
                     74:        if (rem)
                     75:        {
                     76:                return poly_update_padded(this, assoc + blocks * POLY_BLOCK_SIZE, rem);
                     77:        }
                     78:        return TRUE;
                     79: }
                     80: 
                     81: /**
                     82:  * Include length fields to ICV
                     83:  */
                     84: static bool poly_tail(private_chapoly_aead_t *this, size_t alen, size_t clen)
                     85: {
                     86:        struct {
                     87:                uint64_t alen;
                     88:                uint64_t clen;
                     89:        } b;
                     90: 
                     91:        b.alen = htole64(alen);
                     92:        b.clen = htole64(clen);
                     93: 
                     94:        return this->drv->poly(this->drv, (u_char*)&b, 1);
                     95: }
                     96: 
                     97: /**
                     98:  * Perform ChaCha20 encryption inline and generate an ICV tag
                     99:  */
                    100: static bool do_encrypt(private_chapoly_aead_t *this, size_t len, u_char *data,
                    101:                                           u_char *iv, size_t alen, u_char *assoc, u_char *icv)
                    102: {
                    103:        u_int blocks, rem, prem;
                    104: 
                    105:        if (!this->drv->init(this->drv, iv) ||
                    106:                !poly_head(this, assoc, alen))
                    107:        {
                    108:                return FALSE;
                    109:        }
                    110:        blocks = len / CHACHA_BLOCK_SIZE;
                    111:        if (!this->drv->encrypt(this->drv, data, blocks))
                    112:        {
                    113:                return FALSE;
                    114:        }
                    115:        rem = len % CHACHA_BLOCK_SIZE;
                    116:        if (rem)
                    117:        {
                    118:                u_char stream[CHACHA_BLOCK_SIZE];
                    119: 
                    120:                data += blocks * CHACHA_BLOCK_SIZE;
                    121:                if (!this->drv->chacha(this->drv, stream))
                    122:                {
                    123:                        return FALSE;
                    124:                }
                    125:                memxor(data, stream, rem);
                    126: 
                    127:                blocks = rem / POLY_BLOCK_SIZE;
                    128:                if (!this->drv->poly(this->drv, data, blocks))
                    129:                {
                    130:                        return FALSE;
                    131:                }
                    132:                prem = rem % POLY_BLOCK_SIZE;
                    133:                if (prem)
                    134:                {
                    135:                        poly_update_padded(this, data + blocks * POLY_BLOCK_SIZE, prem);
                    136:                }
                    137:        }
                    138:        return poly_tail(this, alen, len) &&
                    139:                   this->drv->finish(this->drv, icv);
                    140: }
                    141: 
                    142: /**
                    143:  * Perform ChaCha20 decryption inline and generate an ICV tag
                    144:  */
                    145: static bool do_decrypt(private_chapoly_aead_t *this, size_t len, u_char *data,
                    146:                                           u_char *iv, size_t alen, u_char *assoc, u_char *icv)
                    147: {
                    148:        u_int blocks, rem, prem;
                    149: 
                    150:        if (!this->drv->init(this->drv, iv) ||
                    151:                !poly_head(this, assoc, alen))
                    152:        {
                    153:                return FALSE;
                    154:        }
                    155:        blocks = len / CHACHA_BLOCK_SIZE;
                    156:        if (!this->drv->decrypt(this->drv, data, blocks))
                    157:        {
                    158:                return FALSE;
                    159:        }
                    160:        rem = len % CHACHA_BLOCK_SIZE;
                    161:        if (rem)
                    162:        {
                    163:                u_char stream[CHACHA_BLOCK_SIZE];
                    164: 
                    165:                data += blocks * CHACHA_BLOCK_SIZE;
                    166: 
                    167:                blocks = rem / POLY_BLOCK_SIZE;
                    168:                if (!this->drv->poly(this->drv, data, blocks))
                    169:                {
                    170:                        return FALSE;
                    171:                }
                    172:                prem = rem % POLY_BLOCK_SIZE;
                    173:                if (prem)
                    174:                {
                    175:                        poly_update_padded(this, data + blocks * POLY_BLOCK_SIZE, prem);
                    176:                }
                    177:                if (!this->drv->chacha(this->drv, stream))
                    178:                {
                    179:                        return FALSE;
                    180:                }
                    181:                memxor(data, stream, rem);
                    182:        }
                    183:        return poly_tail(this, alen, len) &&
                    184:                   this->drv->finish(this->drv, icv);
                    185: }
                    186: 
                    187: METHOD(aead_t, encrypt, bool,
                    188:        private_chapoly_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
                    189:        chunk_t *encr)
                    190: {
                    191:        u_char *out;
                    192: 
                    193:        if (sizeof(plain.len) > sizeof(uint32_t) && plain.len > P_MAX)
                    194:        {
                    195:                return FALSE;
                    196:        }
                    197:        if (iv.len != CHACHA_IV_SIZE)
                    198:        {
                    199:                return FALSE;
                    200:        }
                    201:        out = plain.ptr;
                    202:        if (encr)
                    203:        {
                    204:                *encr = chunk_alloc(plain.len + POLY_ICV_SIZE);
                    205:                out = encr->ptr;
                    206:                memcpy(out, plain.ptr, plain.len);
                    207:        }
                    208:        do_encrypt(this, plain.len, out, iv.ptr, assoc.len, assoc.ptr,
                    209:                           out + plain.len);
                    210:        return TRUE;
                    211: }
                    212: 
                    213: METHOD(aead_t, decrypt, bool,
                    214:        private_chapoly_aead_t *this, chunk_t encr, chunk_t assoc, chunk_t iv,
                    215:        chunk_t *plain)
                    216: {
                    217:        u_char *out, icv[POLY_ICV_SIZE];
                    218:        if (iv.len != CHACHA_IV_SIZE || encr.len < POLY_ICV_SIZE)
                    219:        {
                    220:                return FALSE;
                    221:        }
                    222:        encr.len -= POLY_ICV_SIZE;
                    223:        if (sizeof(encr.len) > sizeof(uint32_t) && encr.len > P_MAX)
                    224:        {
                    225:                return FALSE;
                    226:        }
                    227:        out = encr.ptr;
                    228:        if (plain)
                    229:        {
                    230:                *plain = chunk_alloc(encr.len);
                    231:                out = plain->ptr;
                    232:                memcpy(out, encr.ptr, encr.len);
                    233:        }
                    234:        do_decrypt(this, encr.len, out, iv.ptr, assoc.len, assoc.ptr, icv);
                    235:        return memeq_const(icv, encr.ptr + encr.len, POLY_ICV_SIZE);
                    236: }
                    237: 
                    238: METHOD(aead_t, get_block_size, size_t,
                    239:        private_chapoly_aead_t *this)
                    240: {
                    241:        return 1;
                    242: }
                    243: 
                    244: METHOD(aead_t, get_icv_size, size_t,
                    245:        private_chapoly_aead_t *this)
                    246: {
                    247:        return POLY_ICV_SIZE;
                    248: }
                    249: 
                    250: METHOD(aead_t, get_iv_size, size_t,
                    251:        private_chapoly_aead_t *this)
                    252: {
                    253:        return CHACHA_IV_SIZE;
                    254: }
                    255: 
                    256: METHOD(aead_t, get_iv_gen, iv_gen_t*,
                    257:        private_chapoly_aead_t *this)
                    258: {
                    259:        return this->iv_gen;
                    260: }
                    261: 
                    262: METHOD(aead_t, get_key_size, size_t,
                    263:        private_chapoly_aead_t *this)
                    264: {
                    265:        return CHACHA_KEY_SIZE + CHACHA_SALT_SIZE;
                    266: }
                    267: 
                    268: METHOD(aead_t, set_key, bool,
                    269:        private_chapoly_aead_t *this, chunk_t key)
                    270: {
                    271:        if (key.len != CHACHA_KEY_SIZE + CHACHA_SALT_SIZE)
                    272:        {
                    273:                return FALSE;
                    274:        }
                    275:        return this->drv->set_key(this->drv, "expand 32-byte k",
                    276:                                                          key.ptr, key.ptr + CHACHA_KEY_SIZE);
                    277: }
                    278: 
                    279: METHOD(aead_t, destroy, void,
                    280:        private_chapoly_aead_t *this)
                    281: {
                    282:        this->drv->destroy(this->drv);
                    283:        this->iv_gen->destroy(this->iv_gen);
                    284:        free(this);
                    285: }
                    286: 
                    287: /**
                    288:  * See header
                    289:  */
                    290: chapoly_aead_t *chapoly_aead_create(encryption_algorithm_t algo,
                    291:                                                                        size_t key_size, size_t salt_size)
                    292: {
                    293:        private_chapoly_aead_t *this;
                    294:        chapoly_drv_t *drv;
                    295: 
                    296:        if (algo != ENCR_CHACHA20_POLY1305)
                    297:        {
                    298:                return NULL;
                    299:        }
                    300:        if (key_size && key_size != CHACHA_KEY_SIZE)
                    301:        {
                    302:                return NULL;
                    303:        }
                    304:        if (salt_size && salt_size != CHACHA_SALT_SIZE)
                    305:        {
                    306:                return NULL;
                    307:        }
                    308:        drv = chapoly_drv_probe();
                    309:        if (!drv)
                    310:        {
                    311:                return NULL;
                    312:        }
                    313: 
                    314:        INIT(this,
                    315:                .public = {
                    316:                        .aead = {
                    317:                                .encrypt = _encrypt,
                    318:                                .decrypt = _decrypt,
                    319:                                .get_block_size = _get_block_size,
                    320:                                .get_icv_size = _get_icv_size,
                    321:                                .get_iv_size = _get_iv_size,
                    322:                                .get_iv_gen = _get_iv_gen,
                    323:                                .get_key_size = _get_key_size,
                    324:                                .set_key = _set_key,
                    325:                                .destroy = _destroy,
                    326:                        },
                    327:                },
                    328:                .iv_gen = iv_gen_seq_create(),
                    329:                .drv = drv,
                    330:        );
                    331: 
                    332:        return &this->public;
                    333: }

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