Annotation of embedaddon/strongswan/src/libstrongswan/plugins/drbg/drbg_ctr.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_ctr.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_ctr_t private_drbg_ctr_t;
                     22: 
                     23: /**
                     24:  * Private data of an drbg_ctr_t object.
                     25:  */
                     26: struct private_drbg_ctr_t {
                     27: 
                     28:        /**
                     29:         * Public drbg_ctr_t interface.
                     30:         */
                     31:        drbg_ctr_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:        uint32_t reseed_counter;
                     47: 
                     48:        /**
                     49:         * Maximum number of requests for pseudorandom bits
                     50:         */
                     51:        uint32_t max_requests;
                     52: 
                     53:        /**
                     54:         * True entropy source
                     55:         */
                     56:        rng_t *entropy;
                     57: 
                     58:        /**
                     59:         * Block cipher in counter mode used by the DRBG
                     60:         */
                     61:        crypter_t *crypter;
                     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_ctr_t *this)
                     82: {
                     83:        return this->type;
                     84: }
                     85: 
                     86: METHOD(drbg_t, get_strength, uint32_t,
                     87:        private_drbg_ctr_t *this)
                     88: {
                     89:        return this->strength;
                     90: }
                     91: 
                     92: static bool encrypt_ctr(private_drbg_ctr_t *this, chunk_t out)
                     93: {
                     94:        chunk_t bl = chunk_alloca(this->value.len);
                     95:        chunk_t block;
                     96:        size_t delta, pos = 0;
                     97: 
                     98:        if (!this->crypter->set_key(this->crypter, this->key))
                     99:        {
                    100:                return FALSE;
                    101:        }
                    102: 
                    103:        while (pos < out.len)
                    104:        {
                    105:                /* Increment counter by one */
                    106:                chunk_increment(this->value);
                    107: 
                    108:                /* Copy current counter to input block */
                    109:                delta = out.len - pos;
                    110:                block = (delta < this->value.len) ?
                    111:                                         bl : chunk_create(out.ptr + pos, this->value.len);
                    112:                memcpy(block.ptr, this->value.ptr, this->value.len);
                    113: 
                    114:                /* ECB encryption */
                    115:                if (!this->crypter->encrypt(this->crypter, block, chunk_empty, NULL))
                    116:                {
                    117:                        return FALSE;
                    118:                }
                    119: 
                    120:                /* Partial output block at the end? */
                    121:                if (delta < this->value.len)
                    122:                {
                    123:                        memcpy(out.ptr + pos, block.ptr, delta);
                    124:                }
                    125:                pos += this->value.len;
                    126:        }
                    127: 
                    128:        return TRUE;
                    129: }
                    130: 
                    131: /**
                    132:  * Update the internal state of the CTR_DRBG
                    133:  */
                    134: static bool update(private_drbg_ctr_t *this, chunk_t data)
                    135: {
                    136:        chunk_t temp;
                    137: 
                    138:        if (data.len && data.len != (this->key.len + this->value.len))
                    139:        {
                    140:                return FALSE;
                    141:        }
                    142:        temp = chunk_alloca(this->key.len + this->value.len);
                    143: 
                    144:        if (!encrypt_ctr(this, temp))
                    145:        {
                    146:                return FALSE;
                    147:        }
                    148:        /* Apply data */
                    149:        memxor(temp.ptr, data.ptr, data.len);
                    150: 
                    151:        /* Copy new key and value */
                    152:        memcpy(this->key.ptr, temp.ptr, this->key.len);
                    153:        memcpy(this->value.ptr, temp.ptr + this->key.len, this->value.len);
                    154:        memwipe(temp.ptr, temp.len);
                    155:        DBG4(DBG_LIB, "CTR_DRBG K: %B", &this->key);
                    156:        DBG4(DBG_LIB, "CTR_DRBG V: %B", &this->value);
                    157: 
                    158:        return TRUE;
                    159: }
                    160: 
                    161: METHOD(drbg_t, reseed, bool,
                    162:        private_drbg_ctr_t *this)
                    163: {
                    164:        chunk_t seed;
                    165:        bool success;
                    166: 
                    167:        seed = chunk_alloc(this->key.len + this->value.len);
                    168:        DBG2(DBG_LIB, "DRBG requests %u bytes of entropy", seed.len);
                    169: 
                    170:        if (!this->entropy->get_bytes(this->entropy, seed.len, seed.ptr))
                    171:        {
                    172:                chunk_free(&seed);
                    173:                return FALSE;
                    174:        }
                    175:        DBG4(DBG_LIB, "reseed: %B", &seed);
                    176: 
                    177:        success = update(this, seed);
                    178:        chunk_clear(&seed);
                    179: 
                    180:        if (!success)
                    181:        {
                    182:                return FALSE;
                    183:        }
                    184:        this->reseed_counter = 1;
                    185: 
                    186:        return TRUE;
                    187: }
                    188: 
                    189: METHOD(drbg_t, generate, bool,
                    190:        private_drbg_ctr_t *this, uint32_t len, uint8_t *out)
                    191: {
                    192:        chunk_t output;
                    193: 
                    194:        if (len > MAX_DRBG_BYTES)
                    195:        {
                    196:                DBG1(DBG_LIB, "DRBG cannot generate more than %d bytes", MAX_DRBG_BYTES);
                    197:                return FALSE;
                    198:        }
                    199: 
                    200:        if (this->reseed_counter > this->max_requests)
                    201:        {
                    202:                if (!reseed(this))
                    203:                {
                    204:                        return FALSE;
                    205:                }
                    206:        }
                    207: 
                    208:        DBG2(DBG_LIB, "DRBG generates %u pseudorandom bytes", len);
                    209:        if (!out || len == 0)
                    210:        {
                    211:                return FALSE;
                    212:        }
                    213:        output = chunk_create(out, len);
                    214: 
                    215:        if (!encrypt_ctr(this, output))
                    216:        {
                    217:                return FALSE;
                    218:        }
                    219:        DBG4(DBG_LIB, "CTR_DRBG Out: %B", &output);
                    220: 
                    221:        if (!update(this, chunk_empty))
                    222:        {
                    223:                return FALSE;
                    224:        }
                    225:        this->reseed_counter++;
                    226: 
                    227:        return TRUE;
                    228: }
                    229: 
                    230: METHOD(drbg_t, get_ref, drbg_t*,
                    231:        private_drbg_ctr_t *this)
                    232: {
                    233:        ref_get(&this->ref);
                    234:        return &this->public.interface;
                    235: }
                    236: 
                    237: METHOD(drbg_t, destroy, void,
                    238:        private_drbg_ctr_t *this)
                    239: {
                    240:        if (ref_put(&this->ref))
                    241:        {
                    242:                DESTROY_IF(this->entropy);
                    243:                this->crypter->destroy(this->crypter);
                    244:                chunk_clear(&this->key);
                    245:                chunk_clear(&this->value);
                    246:                free(this);
                    247:        }
                    248: }
                    249: 
                    250: /**
                    251:  * See header
                    252:  */
                    253: drbg_ctr_t *drbg_ctr_create(drbg_type_t type, uint32_t strength,
                    254:                                                        rng_t *entropy, chunk_t personalization_str)
                    255: {
                    256:        private_drbg_ctr_t *this;
                    257:        encryption_algorithm_t crypter_type;
                    258:        crypter_t *crypter;
                    259:        chunk_t seed;
                    260:        size_t key_len, out_len, seed_len;
                    261:        uint32_t max_requests;
                    262:        bool success;
                    263: 
                    264:        switch (type)
                    265:        {
                    266:                case DRBG_CTR_AES128:
                    267:                        crypter_type = ENCR_AES_ECB;
                    268:                        key_len = 16;
                    269:                        break;
                    270:                case DRBG_CTR_AES192:
                    271:                        crypter_type = ENCR_AES_ECB;
                    272:                        key_len = 24;
                    273:                        break;
                    274:                case DRBG_CTR_AES256:
                    275:                        crypter_type = ENCR_AES_ECB;
                    276:                        key_len = 32;
                    277:                        break;
                    278:                default:
                    279:                        DBG1(DBG_LIB, "%N not supported", drbg_type_names, type);
                    280:                        return NULL;
                    281:        }
                    282: 
                    283:        if (strength >  key_len * BITS_PER_BYTE)
                    284:        {
                    285:                DBG1(DBG_LIB, "%d bit block encryption key not sufficient for security "
1.1.1.2 ! misho     286:                         "strength of %u bits", key_len * BITS_PER_BYTE, strength);
1.1       misho     287:                return NULL;
                    288:        }
                    289: 
                    290:        crypter = lib->crypto->create_crypter(lib->crypto, crypter_type, key_len);
                    291:        if (!crypter)
                    292:        {
                    293:                DBG1(DBG_LIB, "creation of %N for DRBG failed",
                    294:                         encryption_algorithm_names, crypter_type);
                    295:                return NULL;
                    296:        }
                    297:        out_len = crypter->get_block_size(crypter);
                    298:        seed_len = key_len + out_len;
                    299: 
                    300:        if (personalization_str.len > seed_len)
                    301:        {
                    302:                DBG1(DBG_LIB, "personalization string length of %d bytes is larger "
1.1.1.2 ! misho     303:                         "than seed length of %u bytes", personalization_str.len, seed_len);
1.1       misho     304:                crypter->destroy(crypter);
                    305:                return NULL;
                    306:        }
                    307: 
                    308:        max_requests = lib->settings->get_int(lib->settings,
                    309:                                                                                  "%s.plugins.drbg.max_drbg_requests",
                    310:                                                                                  MAX_DRBG_REQUESTS, lib->ns);
                    311: 
                    312:        INIT(this,
                    313:                .public = {
                    314:                        .interface = {
                    315:                                .get_type = _get_type,
                    316:                                .get_strength = _get_strength,
                    317:                                .reseed = _reseed,
                    318:                                .generate = _generate,
                    319:                                .get_ref = _get_ref,
                    320:                                .destroy = _destroy,
                    321:                        },
                    322:                },
                    323:                .type = type,
                    324:                .strength = strength,
                    325:                .crypter = crypter,
                    326:                .key = chunk_alloc(key_len),
                    327:                .value = chunk_alloc(out_len),
                    328:                .max_requests = max_requests,
                    329:                .reseed_counter = 1,
                    330:                .ref = 1,
                    331:        );
                    332: 
                    333:        memset(this->key.ptr,   0x00, key_len);
                    334:        memset(this->value.ptr, 0x00, out_len);
                    335: 
                    336:        seed = chunk_alloc(seed_len);
                    337:        DBG2(DBG_LIB, "DRBG requests %u bytes of entropy", seed_len);
                    338: 
                    339:        if (!entropy->get_bytes(entropy, seed.len, seed.ptr))
                    340:        {
                    341:                chunk_free(&seed);
                    342:                destroy(this);
                    343:                return NULL;
                    344:        }
                    345:        memxor(seed.ptr, personalization_str.ptr, personalization_str.len);
                    346:        DBG4(DBG_LIB, "seed: %B", &seed);
                    347: 
                    348:        success = update(this, seed);
                    349:        chunk_clear(&seed);
                    350: 
                    351:        if (!success)
                    352:        {
                    353:                destroy(this);
                    354:                return NULL;
                    355:        }
                    356: 
                    357:        /* ownership of entropy source is transferred to DRBG */
                    358:        this->entropy = entropy;
                    359: 
                    360:        return &this->public;
                    361: }

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