Annotation of embedaddon/strongswan/src/libstrongswan/plugins/openssl/openssl_aead.c, revision 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>