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

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:        {
1.1.1.2 ! misho     269:                DBG1(DBG_LIB, "%N not sufficient for security strength of %u bits",
1.1       misho     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>