Annotation of embedaddon/strongswan/src/libstrongswan/plugins/openssl/openssl_aead.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2013-2019 Tobias Brunner
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      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 <openssl/opensslv.h>
                     17: 
                     18: #if OPENSSL_VERSION_NUMBER >= 0x1000100fL
                     19: 
                     20: #include "openssl_aead.h"
                     21: 
                     22: #include <openssl/evp.h>
                     23: #include <crypto/iv/iv_gen_seq.h>
                     24: 
                     25: /* the generic AEAD identifiers were added with 1.1.0 */
                     26: #ifndef EVP_CTRL_AEAD_SET_IVLEN
                     27: #define EVP_CTRL_AEAD_SET_IVLEN EVP_CTRL_GCM_SET_IVLEN
                     28: #define EVP_CTRL_AEAD_SET_TAG EVP_CTRL_GCM_SET_TAG
                     29: #define EVP_CTRL_AEAD_GET_TAG EVP_CTRL_GCM_GET_TAG
                     30: #endif
                     31: 
                     32: /** as defined in RFC 4106 */
                     33: #define IV_LEN         8
                     34: #define SALT_LEN       4
                     35: #define NONCE_LEN      (IV_LEN + SALT_LEN)
                     36: 
                     37: typedef struct private_aead_t private_aead_t;
                     38: 
                     39: /**
                     40:  * Private data of aead_t
                     41:  */
                     42: struct private_aead_t {
                     43: 
                     44:        /**
                     45:         * Public interface
                     46:         */
                     47:        aead_t public;
                     48: 
                     49:        /**
                     50:         * The encryption key
                     51:         */
                     52:        chunk_t key;
                     53: 
                     54:        /**
                     55:         * Salt value
                     56:         */
                     57:        char salt[SALT_LEN];
                     58: 
                     59:        /**
                     60:         * Size of the integrity check value
                     61:         */
                     62:        size_t icv_size;
                     63: 
                     64:        /**
                     65:         * IV generator
                     66:         */
                     67:        iv_gen_t *iv_gen;
                     68: 
                     69:        /**
                     70:         * The cipher to use
                     71:         */
                     72:        const EVP_CIPHER *cipher;
                     73: };
                     74: 
                     75: /**
                     76:  * Do the actual en/decryption in an EVP context
                     77:  */
                     78: static bool crypt(private_aead_t *this, chunk_t data, chunk_t assoc, chunk_t iv,
                     79:                                  u_char *out, int enc)
                     80: {
                     81:        EVP_CIPHER_CTX *ctx;
                     82:        u_char nonce[NONCE_LEN];
                     83:        bool success = FALSE;
                     84:        int len;
                     85: 
                     86:        memcpy(nonce, this->salt, SALT_LEN);
                     87:        memcpy(nonce + SALT_LEN, iv.ptr, IV_LEN);
                     88: 
                     89:        ctx = EVP_CIPHER_CTX_new();
                     90:        EVP_CIPHER_CTX_set_padding(ctx, 0);
                     91:        if (!EVP_CipherInit_ex(ctx, this->cipher, NULL, NULL, NULL, enc) ||
                     92:                !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, NONCE_LEN, NULL) ||
                     93:                !EVP_CipherInit_ex(ctx, NULL, NULL, this->key.ptr, nonce, enc))
                     94:        {
                     95:                goto done;
                     96:        }
                     97:        if (!enc && !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, this->icv_size,
                     98:                                                                         data.ptr + data.len))
                     99:        {       /* set ICV for verification on decryption */
                    100:                goto done;
                    101:        }
                    102:        if (assoc.len && !EVP_CipherUpdate(ctx, NULL, &len, assoc.ptr, assoc.len))
                    103:        {       /* set AAD if specified */
                    104:                goto done;
                    105:        }
                    106:        if (!EVP_CipherUpdate(ctx, out, &len, data.ptr, data.len) ||
                    107:                !EVP_CipherFinal_ex(ctx, out + len, &len))
                    108:        {       /* EVP_CipherFinal_ex fails if ICV is incorrect on decryption */
                    109:                goto done;
                    110:        }
                    111:        if (enc && !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, this->icv_size,
                    112:                                                                        out + data.len))
                    113:        {       /* copy back the ICV when encrypting */
                    114:                goto done;
                    115:        }
                    116:        success = TRUE;
                    117: 
                    118: done:
                    119:        EVP_CIPHER_CTX_free(ctx);
                    120:        return success;
                    121: }
                    122: 
                    123: METHOD(aead_t, encrypt, bool,
                    124:        private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
                    125:        chunk_t *encrypted)
                    126: {
                    127:        u_char *out;
                    128: 
                    129:        out = plain.ptr;
                    130:        if (encrypted)
                    131:        {
                    132:                *encrypted = chunk_alloc(plain.len + this->icv_size);
                    133:                out = encrypted->ptr;
                    134:        }
                    135:        return crypt(this, plain, assoc, iv, out, 1);
                    136: }
                    137: 
                    138: METHOD(aead_t, decrypt, bool,
                    139:        private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
                    140:        chunk_t *plain)
                    141: {
                    142:        u_char *out;
                    143: 
                    144:        if (encrypted.len < this->icv_size)
                    145:        {
                    146:                return FALSE;
                    147:        }
                    148:        encrypted.len -= this->icv_size;
                    149: 
                    150:        out = encrypted.ptr;
                    151:        if (plain)
                    152:        {
                    153:                *plain = chunk_alloc(encrypted.len);
                    154:                out = plain->ptr;
                    155:        }
                    156:        return crypt(this, encrypted, assoc, iv, out, 0);
                    157: }
                    158: 
                    159: METHOD(aead_t, get_block_size, size_t,
                    160:        private_aead_t *this)
                    161: {
                    162:        return EVP_CIPHER_block_size(this->cipher);
                    163: }
                    164: 
                    165: METHOD(aead_t, get_icv_size, size_t,
                    166:        private_aead_t *this)
                    167: {
                    168:        return this->icv_size;
                    169: }
                    170: 
                    171: METHOD(aead_t, get_iv_size, size_t,
                    172:        private_aead_t *this)
                    173: {
                    174:        return IV_LEN;
                    175: }
                    176: 
                    177: METHOD(aead_t, get_iv_gen, iv_gen_t*,
                    178:        private_aead_t *this)
                    179: {
                    180:        return this->iv_gen;
                    181: }
                    182: 
                    183: METHOD(aead_t, get_key_size, size_t,
                    184:        private_aead_t *this)
                    185: {
                    186:        return this->key.len + SALT_LEN;
                    187: }
                    188: 
                    189: METHOD(aead_t, set_key, bool,
                    190:        private_aead_t *this, chunk_t key)
                    191: {
                    192:        if (key.len != get_key_size(this))
                    193:        {
                    194:                return FALSE;
                    195:        }
                    196:        memcpy(this->salt, key.ptr + key.len - SALT_LEN, SALT_LEN);
                    197:        memcpy(this->key.ptr, key.ptr, this->key.len);
                    198:        return TRUE;
                    199: }
                    200: 
                    201: METHOD(aead_t, destroy, void,
                    202:        private_aead_t *this)
                    203: {
                    204:        chunk_clear(&this->key);
                    205:        this->iv_gen->destroy(this->iv_gen);
                    206:        free(this);
                    207: }
                    208: 
                    209: /*
                    210:  * Described in header
                    211:  */
                    212: aead_t *openssl_aead_create(encryption_algorithm_t algo,
                    213:                                                        size_t key_size, size_t salt_size)
                    214: {
                    215:        private_aead_t *this;
                    216: 
                    217:        INIT(this,
                    218:                .public = {
                    219:                        .encrypt = _encrypt,
                    220:                        .decrypt = _decrypt,
                    221:                        .get_block_size = _get_block_size,
                    222:                        .get_icv_size = _get_icv_size,
                    223:                        .get_iv_size = _get_iv_size,
                    224:                        .get_iv_gen = _get_iv_gen,
                    225:                        .get_key_size = _get_key_size,
                    226:                        .set_key = _set_key,
                    227:                        .destroy = _destroy,
                    228:                },
                    229:        );
                    230: 
                    231:        switch (algo)
                    232:        {
                    233:                case ENCR_AES_GCM_ICV8:
                    234:                        this->icv_size = 8;
                    235:                        break;
                    236:                case ENCR_AES_GCM_ICV12:
                    237:                        this->icv_size = 12;
                    238:                        break;
                    239:                case ENCR_AES_GCM_ICV16:
                    240:                        this->icv_size = 16;
                    241:                        break;
                    242:                case ENCR_CHACHA20_POLY1305:
                    243:                        this->icv_size = 16;
                    244:                        break;
                    245:                default:
                    246:                        free(this);
                    247:                        return NULL;
                    248:        }
                    249: 
                    250:        if (salt_size && salt_size != SALT_LEN)
                    251:        {
                    252:                /* currently not supported */
                    253:                free(this);
                    254:                return NULL;
                    255:        }
                    256: 
                    257:        switch (algo)
                    258:        {
                    259:                case ENCR_AES_GCM_ICV8:
                    260:                case ENCR_AES_GCM_ICV12:
                    261:                case ENCR_AES_GCM_ICV16:
                    262:                        switch (key_size)
                    263:                        {
                    264:                                case 0:
                    265:                                        key_size = 16;
                    266:                                        /* FALL */
                    267:                                case 16:
                    268:                                        this->cipher = EVP_aes_128_gcm();
                    269:                                        break;
                    270:                                case 24:
                    271:                                        this->cipher = EVP_aes_192_gcm();
                    272:                                        break;
                    273:                                case 32:
                    274:                                        this->cipher = EVP_aes_256_gcm();
                    275:                                        break;
                    276:                                default:
                    277:                                        free(this);
                    278:                                        return NULL;
                    279:                        }
                    280:                        break;
                    281: #if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_CHACHA)
                    282:                case ENCR_CHACHA20_POLY1305:
                    283:                        switch (key_size)
                    284:                        {
                    285:                                case 0:
                    286:                                        key_size = 32;
                    287:                                        /* FALL */
                    288:                                case 32:
                    289:                                        this->cipher = EVP_chacha20_poly1305();
                    290:                                        break;
                    291:                                default:
                    292:                                        free(this);
                    293:                                        return NULL;
                    294:                        }
                    295:                        break;
                    296: #endif /* OPENSSL_NO_CHACHA */
                    297:                default:
                    298:                        free(this);
                    299:                        return NULL;
                    300:        }
                    301: 
                    302:        if (!this->cipher)
                    303:        {
                    304:                free(this);
                    305:                return NULL;
                    306:        }
                    307: 
                    308:        this->key = chunk_alloc(key_size);
                    309:        this->iv_gen = iv_gen_seq_create();
                    310: 
                    311:        return &this->public;
                    312: }
                    313: 
                    314: #endif /* OPENSSL_VERSION_NUMBER */

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