Annotation of embedaddon/strongswan/src/libstrongswan/plugins/wolfssl/wolfssl_aead.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
                      3:  *
                      4:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      5:  * of this software and associated documentation files (the "Software"), to deal
                      6:  * in the Software without restriction, including without limitation the rights
                      7:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                      8:  * copies of the Software, and to permit persons to whom the Software is
                      9:  * furnished to do so, subject to the following conditions:
                     10:  *
                     11:  * The above copyright notice and this permission notice shall be included in
                     12:  * all copies or substantial portions of the Software.
                     13:  *
                     14:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     15:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
                     17:  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     18:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     19:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     20:  * THE SOFTWARE.
                     21:  */
                     22: 
                     23: #include "wolfssl_common.h"
                     24: 
                     25: #if (!defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AESCCM))) || \
                     26:                                                                (defined(HAVE_CHACHA) && defined(HAVE_POLY1305))
                     27: 
                     28: #include "wolfssl_aead.h"
                     29: 
                     30: #include <wolfssl/wolfcrypt/aes.h>
                     31: #include <wolfssl/wolfcrypt/chacha.h>
                     32: #include <wolfssl/wolfcrypt/chacha20_poly1305.h>
                     33: #include <crypto/iv/iv_gen_seq.h>
                     34: 
                     35: /** as defined in RFC 4106 */
                     36: #define IV_LEN                 8
                     37: #define GCM_SALT_LEN   4
                     38: #define GCM_NONCE_LEN  (GCM_SALT_LEN + IV_LEN)
                     39: 
                     40: #define CCM_SALT_LEN   3
                     41: #define CCM_NONCE_LEN  (CCM_SALT_LEN + IV_LEN)
                     42: 
                     43: typedef struct private_aead_t private_aead_t;
                     44: 
                     45: /**
                     46:  * Private data of aead_t
                     47:  */
                     48: struct private_aead_t {
                     49: 
                     50:        /**
                     51:         * Public interface
                     52:         */
                     53:        aead_t public;
                     54: 
                     55:        /**
                     56:         * The encryption key
                     57:         */
                     58:        chunk_t key;
                     59: 
                     60:        /**
                     61:         * Salt value
                     62:         */
                     63:        chunk_t salt;
                     64: 
                     65:        /**
                     66:         * Size of the integrity check value
                     67:         */
                     68:        size_t icv_size;
                     69: 
                     70:        /**
                     71:         * IV generator
                     72:         */
                     73:        iv_gen_t *iv_gen;
                     74: 
                     75:        /**
                     76:         * The cipher to use
                     77:         */
                     78:        union {
                     79: #if !defined(NO_AES) && (defined(HAVE_AESGCM) || defined(HAVE_AESCCM))
                     80:                Aes aes;
                     81: #endif
                     82:        } cipher;
                     83: 
                     84:        /**
                     85:         * The cipher to use
                     86:         */
                     87:        encryption_algorithm_t alg;
                     88: };
                     89: 
                     90: METHOD(aead_t, encrypt, bool,
                     91:        private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
                     92:        chunk_t *encrypted)
                     93: {
                     94:        chunk_t nonce;
                     95:        u_char *out;
                     96:        bool success = FALSE;
                     97:        int ret;
                     98: 
                     99:        out = plain.ptr;
                    100:        if (encrypted)
                    101:        {
                    102:                *encrypted = chunk_alloc(plain.len + this->icv_size);
                    103:                out = encrypted->ptr;
                    104:        }
                    105: 
                    106:        nonce = chunk_cata("cc", this->salt, iv);
                    107: 
                    108:        switch (this->alg)
                    109:        {
                    110: #if !defined(NO_AES) && defined(HAVE_AESGCM)
                    111:                case ENCR_AES_GCM_ICV8:
                    112:                case ENCR_AES_GCM_ICV12:
                    113:                case ENCR_AES_GCM_ICV16:
                    114:                        ret = wc_AesGcmSetKey(&this->cipher.aes, this->key.ptr,
                    115:                                                                  this->key.len);
                    116:                        if (ret == 0)
                    117:                        {
                    118:                                ret = wc_AesGcmEncrypt(&this->cipher.aes, out, plain.ptr,
                    119:                                                plain.len, nonce.ptr, GCM_NONCE_LEN, out + plain.len,
                    120:                                                this->icv_size, assoc.ptr, assoc.len);
                    121:                        }
                    122:                        success = (ret == 0);
                    123:                        break;
                    124: #endif
                    125: #if !defined(NO_AES) && defined(HAVE_AESCCM)
                    126:                case ENCR_AES_CCM_ICV8:
                    127:                case ENCR_AES_CCM_ICV12:
                    128:                case ENCR_AES_CCM_ICV16:
                    129:                        /* wc_AesCcmEncrypt fails if the pointer is NULL */
                    130:                        if (!plain.ptr && !plain.len)
                    131:                        {
                    132:                                plain.ptr = nonce.ptr;
                    133:                        }
                    134:                        ret = wc_AesCcmSetKey(&this->cipher.aes, this->key.ptr,
                    135:                                                                  this->key.len);
                    136:                        if (ret == 0)
                    137:                        {
                    138:                                ret = wc_AesCcmEncrypt(&this->cipher.aes, out, plain.ptr,
                    139:                                                plain.len, nonce.ptr, CCM_NONCE_LEN, out + plain.len,
                    140:                                                this->icv_size, assoc.ptr, assoc.len);
                    141:                        }
                    142:                        success = (ret == 0);
                    143:                        break;
                    144: #endif
                    145: #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
                    146:                case ENCR_CHACHA20_POLY1305:
                    147:                        ret = wc_ChaCha20Poly1305_Encrypt(this->key.ptr, nonce.ptr,
                    148:                                                assoc.ptr, assoc.len, plain.ptr, plain.len, out,
                    149:                                                out + plain.len);
                    150:                        success = (ret == 0);
                    151:                        break;
                    152: #endif
                    153:                default:
                    154:                        break;
                    155:        }
                    156: 
                    157:        memwipe(nonce.ptr, nonce.len);
                    158:        return success;
                    159: }
                    160: 
                    161: METHOD(aead_t, decrypt, bool,
                    162:        private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
                    163:        chunk_t *plain)
                    164: {
                    165:        chunk_t nonce;
                    166:        u_char *out;
                    167:        bool success = FALSE;
                    168:        int ret = 0;
                    169: 
                    170:        if (encrypted.len < this->icv_size)
                    171:        {
                    172:                return FALSE;
                    173:        }
                    174:        encrypted.len -= this->icv_size;
                    175: 
                    176:        out = encrypted.ptr;
                    177:        if (plain)
                    178:        {
                    179:                *plain = chunk_alloc(encrypted.len);
                    180:                out = plain->ptr;
                    181:        }
                    182: 
                    183:        nonce = chunk_cata("cc", this->salt, iv);
                    184: 
                    185:        switch (this->alg)
                    186:        {
                    187: #if !defined(NO_AES) && defined(HAVE_AESGCM)
                    188:                case ENCR_AES_GCM_ICV8:
                    189:                case ENCR_AES_GCM_ICV12:
                    190:                case ENCR_AES_GCM_ICV16:
                    191:                        ret = wc_AesGcmSetKey(&this->cipher.aes, this->key.ptr,
                    192:                                                                  this->key.len);
                    193:                        if (ret == 0)
                    194:                        {
                    195:                                ret = wc_AesGcmDecrypt(&this->cipher.aes, out, encrypted.ptr,
                    196:                                                        encrypted.len, nonce.ptr, GCM_NONCE_LEN,
                    197:                                                        encrypted.ptr + encrypted.len, this->icv_size,
                    198:                                                        assoc.ptr, assoc.len);
                    199:                        }
                    200:                        success = (ret == 0);
                    201:                        break;
                    202: #endif
                    203: #if !defined(NO_AES) && defined(HAVE_AESCCM)
                    204:                case ENCR_AES_CCM_ICV8:
                    205:                case ENCR_AES_CCM_ICV12:
                    206:                case ENCR_AES_CCM_ICV16:
                    207:                        /* wc_AesCcmDecrypt() fails if the pointers are NULL */
                    208:                        if (!encrypted.ptr && !encrypted.len)
                    209:                        {
                    210:                                encrypted.ptr = nonce.ptr;
                    211:                        }
                    212:                        if (!out && !encrypted.len)
                    213:                        {
                    214:                                out = nonce.ptr;
                    215:                        }
                    216:                        ret = wc_AesCcmSetKey(&this->cipher.aes, this->key.ptr,
                    217:                                                                  this->key.len);
                    218:                        if (ret == 0)
                    219:                        {
                    220:                                ret = wc_AesCcmDecrypt(&this->cipher.aes, out, encrypted.ptr,
                    221:                                                        encrypted.len, nonce.ptr, CCM_NONCE_LEN,
                    222:                                                        encrypted.ptr + encrypted.len, this->icv_size,
                    223:                                                        assoc.ptr, assoc.len);
                    224:                        }
                    225:                        success = (ret == 0);
                    226:                        break;
                    227: #endif
                    228: #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
                    229:                case ENCR_CHACHA20_POLY1305:
                    230:                        ret = wc_ChaCha20Poly1305_Decrypt(this->key.ptr, nonce.ptr,
                    231:                                                        assoc.ptr, assoc.len, encrypted.ptr, encrypted.len,
                    232:                                                        encrypted.ptr + encrypted.len, out);
                    233:                        success = (ret == 0);
                    234:                        break;
                    235: #endif
                    236:                default:
                    237:                        break;
                    238:        }
                    239: 
                    240:        memwipe(nonce.ptr, nonce.len);
                    241:        return success;
                    242: }
                    243: 
                    244: METHOD(aead_t, get_block_size, size_t,
                    245:        private_aead_t *this)
                    246: {
                    247:        /* all AEAD algorithms are streaming */
                    248:        return 1;
                    249: }
                    250: 
                    251: METHOD(aead_t, get_icv_size, size_t,
                    252:        private_aead_t *this)
                    253: {
                    254:        return this->icv_size;
                    255: }
                    256: 
                    257: METHOD(aead_t, get_iv_size, size_t,
                    258:        private_aead_t *this)
                    259: {
                    260:        return IV_LEN;
                    261: }
                    262: 
                    263: METHOD(aead_t, get_iv_gen, iv_gen_t*,
                    264:        private_aead_t *this)
                    265: {
                    266:        return this->iv_gen;
                    267: }
                    268: 
                    269: METHOD(aead_t, get_key_size, size_t,
                    270:        private_aead_t *this)
                    271: {
                    272:        return this->key.len + this->salt.len;
                    273: }
                    274: 
                    275: METHOD(aead_t, set_key, bool,
                    276:        private_aead_t *this, chunk_t key)
                    277: {
                    278:        if (key.len != get_key_size(this))
                    279:        {
                    280:                return FALSE;
                    281:        }
                    282:        memcpy(this->salt.ptr, key.ptr + key.len - this->salt.len, this->salt.len);
                    283:        memcpy(this->key.ptr, key.ptr, this->key.len);
                    284:        return TRUE;
                    285: }
                    286: 
                    287: METHOD(aead_t, destroy, void,
                    288:        private_aead_t *this)
                    289: {
                    290:        chunk_clear(&this->key);
                    291:        chunk_clear(&this->salt);
                    292:        switch (this->alg)
                    293:        {
                    294: #if !defined(NO_AES) && defined(HAVE_AESGCM)
                    295:                case ENCR_AES_GCM_ICV8:
                    296:                case ENCR_AES_GCM_ICV12:
                    297:                case ENCR_AES_GCM_ICV16:
                    298:                        wc_AesFree(&this->cipher.aes);
                    299:                        break;
                    300: #endif
                    301: #if !defined(NO_AES) && defined(HAVE_AESCCM)
                    302:                case ENCR_AES_CCM_ICV8:
                    303:                case ENCR_AES_CCM_ICV12:
                    304:                case ENCR_AES_CCM_ICV16:
                    305:                        wc_AesFree(&this->cipher.aes);
                    306:                        break;
                    307: #endif
                    308:                default:
                    309:                        break;
                    310:        }
                    311:        this->iv_gen->destroy(this->iv_gen);
                    312:        free(this);
                    313: }
                    314: 
                    315: /*
                    316:  * Described in header
                    317:  */
                    318: aead_t *wolfssl_aead_create(encryption_algorithm_t algo,
                    319:                                                        size_t key_size, size_t salt_size)
                    320: {
                    321:        private_aead_t *this;
                    322:        size_t expected_salt_size;
                    323: 
                    324:        INIT(this,
                    325:                .public = {
                    326:                        .encrypt = _encrypt,
                    327:                        .decrypt = _decrypt,
                    328:                        .get_block_size = _get_block_size,
                    329:                        .get_icv_size = _get_icv_size,
                    330:                        .get_iv_size = _get_iv_size,
                    331:                        .get_iv_gen = _get_iv_gen,
                    332:                        .get_key_size = _get_key_size,
                    333:                        .set_key = _set_key,
                    334:                        .destroy = _destroy,
                    335:                },
                    336:                .alg = algo,
                    337:        );
                    338: 
                    339:        switch (algo)
                    340:        {
                    341: #if !defined(NO_AES) && defined(HAVE_AESGCM)
                    342:        #if WOLFSSL_MIN_AUTH_TAG_SZ <= 8
                    343:                case ENCR_AES_GCM_ICV8:
                    344:                        this->icv_size = 8;
                    345:                        break;
                    346:        #endif
                    347:        #if WOLFSSL_MIN_AUTH_TAG_SZ <= 12
                    348:                case ENCR_AES_GCM_ICV12:
                    349:                        this->icv_size = 12;
                    350:                        break;
                    351:        #endif
                    352:                case ENCR_AES_GCM_ICV16:
                    353:                        this->icv_size = 16;
                    354:                        break;
                    355: #endif
                    356: #if !defined(NO_AES) && defined(HAVE_AESCCM)
                    357:                case ENCR_AES_CCM_ICV8:
                    358:                        this->icv_size = 8;
                    359:                        break;
                    360:                case ENCR_AES_CCM_ICV12:
                    361:                        this->icv_size = 12;
                    362:                        break;
                    363:                case ENCR_AES_CCM_ICV16:
                    364:                        this->icv_size = 16;
                    365:                        break;
                    366: #endif
                    367: #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
                    368:                case ENCR_CHACHA20_POLY1305:
                    369:                        this->icv_size = 16;
                    370:                        break;
                    371: #endif
                    372:                default:
                    373:                        free(this);
                    374:                        return NULL;
                    375:        }
                    376: 
                    377:        switch (algo)
                    378:        {
                    379: #if !defined(NO_AES) && defined(HAVE_AESGCM)
                    380:                case ENCR_AES_GCM_ICV8:
                    381:                case ENCR_AES_GCM_ICV12:
                    382:                case ENCR_AES_GCM_ICV16:
                    383:                        switch (key_size)
                    384:                        {
                    385:                                case 0:
                    386:                                        key_size = 16;
                    387:                                        /* FALL */
                    388:                                case 16:
                    389:                                case 24:
                    390:                                case 32:
                    391:                                        expected_salt_size = GCM_SALT_LEN;
                    392:                                        if (wc_AesInit(&this->cipher.aes, NULL, INVALID_DEVID) != 0)
                    393:                                        {
                    394:                                                DBG1(DBG_LIB, "AES Init failed, aead create failed");
                    395:                                                free(this);
                    396:                                                return NULL;
                    397:                                        }
                    398:                                        break;
                    399:                                default:
                    400:                                        free(this);
                    401:                                        return NULL;
                    402:                        }
                    403:                        break;
                    404: #endif
                    405: #if !defined(NO_AES) && defined(HAVE_AESCCM)
                    406:                case ENCR_AES_CCM_ICV8:
                    407:                case ENCR_AES_CCM_ICV12:
                    408:                case ENCR_AES_CCM_ICV16:
                    409:                        switch (key_size)
                    410:                        {
                    411:                                case 0:
                    412:                                        key_size = 16;
                    413:                                        /* FALL */
                    414:                                case 16:
                    415:                                case 24:
                    416:                                case 32:
                    417:                                        expected_salt_size = CCM_SALT_LEN;
                    418:                                        if (wc_AesInit(&this->cipher.aes, NULL, INVALID_DEVID) != 0)
                    419:                                        {
                    420:                                                DBG1(DBG_LIB, "AES Init failed, aead create failed");
                    421:                                                free(this);
                    422:                                                return NULL;
                    423:                                        }
                    424:                                        break;
                    425:                                default:
                    426:                                        free(this);
                    427:                                        return NULL;
                    428:                        }
                    429:                        break;
                    430: #endif
                    431: #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
                    432:                case ENCR_CHACHA20_POLY1305:
                    433:                        switch (key_size)
                    434:                        {
                    435:                                case 0:
                    436:                                        key_size = 32;
                    437:                                        /* FALL */
                    438:                                case 32:
                    439:                                        expected_salt_size = 4;
                    440:                                        break;
                    441:                                default:
                    442:                                        free(this);
                    443:                                        return NULL;
                    444:                        }
                    445:                        break;
                    446: #endif
                    447:                default:
                    448:                        free(this);
                    449:                        return NULL;
                    450:        }
                    451: 
                    452:        if (salt_size && salt_size != expected_salt_size)
                    453:        {
                    454:                /* currently not supported */
                    455:                free(this);
                    456:                return NULL;
                    457:        }
                    458: 
                    459:        this->key = chunk_alloc(key_size);
                    460:        this->salt = chunk_alloc(expected_salt_size);
                    461:        this->iv_gen = iv_gen_seq_create();
                    462: 
                    463:        return &this->public;
                    464: }
                    465: 
                    466: #endif

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