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>