Annotation of embedaddon/strongswan/src/libstrongswan/plugins/drbg/drbg_hmac.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2016-2019 Andreas Steffen
        !             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 "drbg_hmac.h"
        !            17: 
        !            18: #define MAX_DRBG_REQUESTS      0xfffffffe      /* 2^32 - 2 */
        !            19: #define MAX_DRBG_BYTES         0x00010000      /* 2^19 bits = 2^16 bytes */
        !            20: 
        !            21: typedef struct private_drbg_hmac_t private_drbg_hmac_t;
        !            22: 
        !            23: /**
        !            24:  * Private data of an drbg_prf_t object.
        !            25:  */
        !            26: struct private_drbg_hmac_t {
        !            27: 
        !            28:        /**
        !            29:         * Public drbg_prf_t interface.
        !            30:         */
        !            31:        drbg_hmac_t public;
        !            32: 
        !            33:        /**
        !            34:         * DRBG type.
        !            35:         */
        !            36:        drbg_type_t type;
        !            37: 
        !            38:        /**
        !            39:         * Security strength in bits.
        !            40:         */
        !            41:        uint32_t strength;
        !            42: 
        !            43:        /**
        !            44:         * Number of requests for pseudorandom bits
        !            45:         */
        !            46:        size_t reseed_counter;
        !            47: 
        !            48:        /**
        !            49:         * Maximum number of requests for pseudorandom bits
        !            50:         */
        !            51:        size_t max_requests;
        !            52: 
        !            53:        /**
        !            54:         * True entropy source
        !            55:         */
        !            56:        rng_t *entropy;
        !            57: 
        !            58:        /**
        !            59:         * HMAC PRF used by the DRBG
        !            60:         */
        !            61:        prf_t *prf;
        !            62: 
        !            63:        /**
        !            64:         * Internal state of HMAC: key
        !            65:         */
        !            66:        chunk_t key;
        !            67: 
        !            68:        /**
        !            69:         * Internal state of HMAC: value
        !            70:         */
        !            71:        chunk_t value;
        !            72: 
        !            73:        /**
        !            74:         * reference count
        !            75:         */
        !            76:        refcount_t ref;
        !            77: 
        !            78: };
        !            79: 
        !            80: METHOD(drbg_t, get_type, drbg_type_t,
        !            81:        private_drbg_hmac_t *this)
        !            82: {
        !            83:        return this->type;
        !            84: }
        !            85: 
        !            86: METHOD(drbg_t, get_strength, uint32_t,
        !            87:        private_drbg_hmac_t *this)
        !            88: {
        !            89:        return this->strength;
        !            90: }
        !            91: 
        !            92: /**
        !            93:  * Update the internal state of the HMAC_DRBG
        !            94:  */
        !            95: static bool update(private_drbg_hmac_t *this, chunk_t data)
        !            96: {
        !            97:        chunk_t ch_00 = chunk_from_chars(0x00);
        !            98:        chunk_t ch_01 = chunk_from_chars(0x01);
        !            99: 
        !           100:        if (!this->prf->set_key(this->prf, this->key) ||
        !           101:                !this->prf->get_bytes(this->prf, this->value, NULL) ||
        !           102:            !this->prf->get_bytes(this->prf, ch_00, NULL) ||
        !           103:            !this->prf->get_bytes(this->prf, data, this->key.ptr) ||
        !           104:                !this->prf->set_key(this->prf, this->key) ||
        !           105:            !this->prf->get_bytes(this->prf, this->value, this->value.ptr))
        !           106:        {
        !           107:                return FALSE;
        !           108:        }
        !           109: 
        !           110:        if (data.len > 0)
        !           111:        {
        !           112:                if (!this->prf->set_key(this->prf, this->key) ||
        !           113:                        !this->prf->get_bytes(this->prf, this->value, NULL) ||
        !           114:                        !this->prf->get_bytes(this->prf, ch_01, NULL) ||
        !           115:                        !this->prf->get_bytes(this->prf, data, this->key.ptr) ||
        !           116:                        !this->prf->set_key(this->prf, this->key) ||
        !           117:                        !this->prf->get_bytes(this->prf, this->value, this->value.ptr))
        !           118:                {
        !           119:                        return FALSE;
        !           120:                }
        !           121:        }
        !           122:        DBG4(DBG_LIB, "HMAC_DRBG K: %B", &this->key);
        !           123:        DBG4(DBG_LIB, "HMAC_DRBG V: %B", &this->value);
        !           124: 
        !           125:        return TRUE;
        !           126: }
        !           127: 
        !           128: METHOD(drbg_t, reseed, bool,
        !           129:        private_drbg_hmac_t *this)
        !           130: {
        !           131:        chunk_t seed;
        !           132:        bool success;
        !           133: 
        !           134:        seed = chunk_alloc(this->strength / BITS_PER_BYTE);
        !           135:        DBG2(DBG_LIB, "DRBG requests %u bytes of entropy", seed.len);
        !           136: 
        !           137:        if (!this->entropy->get_bytes(this->entropy, seed.len, seed.ptr))
        !           138:        {
        !           139:                chunk_free(&seed);
        !           140:                return FALSE;
        !           141:        }
        !           142:        DBG4(DBG_LIB, "reseed: %B", &seed);
        !           143: 
        !           144:        success = update(this, seed);
        !           145:        chunk_clear(&seed);
        !           146: 
        !           147:        if (!success)
        !           148:        {
        !           149:                return FALSE;
        !           150:        }
        !           151:        this->reseed_counter = 1;
        !           152: 
        !           153:        return TRUE;
        !           154: }
        !           155: 
        !           156: METHOD(drbg_t, generate, bool,
        !           157:        private_drbg_hmac_t *this, uint32_t len, uint8_t *out)
        !           158: {
        !           159:        size_t delta;
        !           160:        chunk_t output;
        !           161: 
        !           162:        if (len > MAX_DRBG_BYTES)
        !           163:        {
        !           164:                DBG1(DBG_LIB, "DRBG cannot generate more than %d bytes", MAX_DRBG_BYTES);
        !           165:                return FALSE;
        !           166:        }
        !           167: 
        !           168:        if (this->reseed_counter > this->max_requests)
        !           169:        {
        !           170:                if (!reseed(this))
        !           171:                {
        !           172:                        return FALSE;
        !           173:                }
        !           174:        }
        !           175: 
        !           176:        DBG2(DBG_LIB, "DRBG generates %u pseudorandom bytes", len);
        !           177:        if (!out || len == 0)
        !           178:        {
        !           179:                return FALSE;
        !           180:        }
        !           181:        output = chunk_create(out, len);
        !           182: 
        !           183:        while (len)
        !           184:        {
        !           185:                if (!this->prf->get_bytes(this->prf, this->value, this->value.ptr))
        !           186:                {
        !           187:                        return FALSE;
        !           188:                }
        !           189:                delta = min(len, this->value.len);
        !           190:                memcpy(out, this->value.ptr, delta);
        !           191:                len -= delta;
        !           192:                out += delta;
        !           193:        }
        !           194:        DBG4(DBG_LIB, "HMAC_DRBG Out: %B", &output);
        !           195: 
        !           196:        if (!update(this, chunk_empty))
        !           197:        {
        !           198:                return FALSE;
        !           199:        }
        !           200:        this->reseed_counter++;
        !           201: 
        !           202:        return TRUE;
        !           203: }
        !           204: 
        !           205: METHOD(drbg_t, get_ref, drbg_t*,
        !           206:        private_drbg_hmac_t *this)
        !           207: {
        !           208:        ref_get(&this->ref);
        !           209:        return &this->public.interface;
        !           210: }
        !           211: 
        !           212: METHOD(drbg_t, destroy, void,
        !           213:        private_drbg_hmac_t *this)
        !           214: {
        !           215:        if (ref_put(&this->ref))
        !           216:        {
        !           217:                DESTROY_IF(this->entropy);
        !           218:                this->prf->destroy(this->prf);
        !           219:                chunk_clear(&this->key);
        !           220:                chunk_clear(&this->value);
        !           221:                free(this);
        !           222:        }
        !           223: }
        !           224: 
        !           225: /**
        !           226:  * See header
        !           227:  */
        !           228: drbg_hmac_t *drbg_hmac_create(drbg_type_t type, uint32_t strength,
        !           229:                                                          rng_t *entropy, chunk_t personalization_str)
        !           230: {
        !           231:        private_drbg_hmac_t *this;
        !           232:        pseudo_random_function_t prf_type = PRF_UNDEFINED;
        !           233:        size_t out_len, entropy_len;
        !           234:        uint32_t max_requests;
        !           235:        chunk_t seed;
        !           236:        prf_t * prf;
        !           237:        bool success;
        !           238: 
        !           239:        switch (type)
        !           240:        {
        !           241:                case DRBG_HMAC_SHA1:
        !           242:                        prf_type = PRF_HMAC_SHA1;
        !           243:                        break;
        !           244:                case DRBG_HMAC_SHA256:
        !           245:                        prf_type = PRF_HMAC_SHA2_256;
        !           246:                        break;
        !           247:                case DRBG_HMAC_SHA384:
        !           248:                        prf_type = PRF_HMAC_SHA2_384;
        !           249:                        break;
        !           250:                case DRBG_HMAC_SHA512:
        !           251:                        prf_type = PRF_HMAC_SHA2_512;
        !           252:                        break;
        !           253:                default:
        !           254:                        DBG1(DBG_LIB, "%N not supported", drbg_type_names, type);
        !           255:                        return NULL;
        !           256:        }
        !           257: 
        !           258:        prf = lib->crypto->create_prf(lib->crypto, prf_type);
        !           259:        if (!prf)
        !           260:        {
        !           261:                DBG1(DBG_LIB, "creation of %N for DRBG failed",
        !           262:                         pseudo_random_function_names, prf_type);
        !           263:                return NULL;
        !           264:        }
        !           265:        out_len = prf->get_key_size(prf);
        !           266: 
        !           267:        if (strength >  out_len * BITS_PER_BYTE)
        !           268:        {
        !           269:                DBG1(DBG_LIB, "%N not sufficient for security strength of % bits",
        !           270:                         pseudo_random_function_names, prf_type, strength);
        !           271:                prf->destroy(prf);
        !           272:                return NULL;
        !           273:        }
        !           274: 
        !           275:        max_requests = lib->settings->get_int(lib->settings,
        !           276:                                                                                  "%s.plugins.drbg.max_drbg_requests",
        !           277:                                                                                  MAX_DRBG_REQUESTS, lib->ns);
        !           278: 
        !           279:        INIT(this,
        !           280:                .public = {
        !           281:                        .interface = {
        !           282:                                .get_type = _get_type,
        !           283:                                .get_strength = _get_strength,
        !           284:                                .reseed = _reseed,
        !           285:                                .generate = _generate,
        !           286:                                .get_ref = _get_ref,
        !           287:                                .destroy = _destroy,
        !           288:                        },
        !           289:                },
        !           290:                .type = type,
        !           291:                .strength = strength,
        !           292:                .prf = prf,
        !           293:                .key = chunk_alloc(out_len),
        !           294:                .value = chunk_alloc(out_len),
        !           295:                .max_requests = max_requests,
        !           296:                .reseed_counter = 1,
        !           297:                .ref = 1,
        !           298:        );
        !           299: 
        !           300:        memset(this->key.ptr,   0x00, out_len);
        !           301:        memset(this->value.ptr, 0x01, out_len);
        !           302: 
        !           303:        entropy_len = (strength + strength/2) / BITS_PER_BYTE;
        !           304:        seed = chunk_alloc(entropy_len + personalization_str.len);
        !           305:        DBG2(DBG_LIB, "DRBG requests %u bytes of entropy", entropy_len);
        !           306: 
        !           307:        if (!entropy->get_bytes(entropy, entropy_len, seed.ptr))
        !           308:        {
        !           309:                chunk_free(&seed);
        !           310:                destroy(this);
        !           311:                return NULL;
        !           312:        }
        !           313:        memcpy(seed.ptr + entropy_len,
        !           314:                   personalization_str.ptr, personalization_str.len);
        !           315:        DBG4(DBG_LIB, "seed: %B", &seed);
        !           316: 
        !           317:        success = update(this, seed);
        !           318:        chunk_clear(&seed);
        !           319: 
        !           320:        if (!success)
        !           321:        {
        !           322:                destroy(this);
        !           323:                return NULL;
        !           324:        }
        !           325: 
        !           326:        /* ownership of entropy source is transferred to DRBG */
        !           327:        this->entropy = entropy;
        !           328: 
        !           329:        return &this->public;
        !           330: }

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