Annotation of embedaddon/strongswan/src/libstrongswan/plugins/botan/botan_aead.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2018 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * Copyright (C) 2018 Atanas Filyanov
! 6: * Rohde & Schwarz Cybersecurity GmbH
! 7: *
! 8: * Permission is hereby granted, free of charge, to any person obtaining a copy
! 9: * of this software and associated documentation files (the "Software"), to deal
! 10: * in the Software without restriction, including without limitation the rights
! 11: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
! 12: * copies of the Software, and to permit persons to whom the Software is
! 13: * furnished to do so, subject to the following conditions:
! 14: *
! 15: * The above copyright notice and this permission notice shall be included in
! 16: * all copies or substantial portions of the Software.
! 17: *
! 18: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
! 19: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! 20: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
! 21: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
! 22: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
! 23: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
! 24: * THE SOFTWARE.
! 25: */
! 26:
! 27: #include "botan_aead.h"
! 28:
! 29: #include <botan/build.h>
! 30:
! 31: #if (defined(BOTAN_HAS_AES) && \
! 32: (defined(BOTAN_HAS_AEAD_GCM) || defined(BOTAN_HAS_AEAD_CCM))) || \
! 33: defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305)
! 34:
! 35: #include <crypto/iv/iv_gen_seq.h>
! 36:
! 37: #include <botan/ffi.h>
! 38:
! 39: /**
! 40: * As defined in RFC 4106 (GCM) and RFC 7634 (ChaPoly)
! 41: */
! 42: #define IV_LEN 8
! 43: #define SALT_LEN 4
! 44: #define CHAPOLY_KEY_LEN 32
! 45: /**
! 46: * As defined in RFC 4309
! 47: */
! 48: #define CCM_SALT_LEN 3
! 49:
! 50: typedef struct private_aead_t private_aead_t;
! 51:
! 52: struct private_aead_t {
! 53:
! 54: /**
! 55: * Public interface
! 56: */
! 57: aead_t public;
! 58:
! 59: /**
! 60: * The encryption key
! 61: */
! 62: chunk_t key;
! 63:
! 64: /**
! 65: * Salt value
! 66: */
! 67: chunk_t salt;
! 68:
! 69: /**
! 70: * Size of the integrity check value
! 71: */
! 72: size_t icv_size;
! 73:
! 74: /**
! 75: * IV generator
! 76: */
! 77: iv_gen_t *iv_gen;
! 78:
! 79: /**
! 80: * The cipher to use
! 81: */
! 82: const char* cipher_name;
! 83: };
! 84:
! 85: /**
! 86: * Do the actual en/decryption
! 87: */
! 88: static bool do_crypt(private_aead_t *this, chunk_t data, chunk_t assoc,
! 89: chunk_t iv, u_char *out, uint32_t init_flag)
! 90: {
! 91: botan_cipher_t cipher;
! 92: size_t output_written = 0, input_consumed = 0;
! 93: chunk_t nonce;
! 94:
! 95: if (botan_cipher_init(&cipher, this->cipher_name, init_flag))
! 96: {
! 97: return FALSE;
! 98: }
! 99:
! 100: if (botan_cipher_set_key(cipher, this->key.ptr, this->key.len))
! 101: {
! 102: botan_cipher_destroy(cipher);
! 103: return FALSE;
! 104: }
! 105:
! 106: if (assoc.len &&
! 107: botan_cipher_set_associated_data(cipher, assoc.ptr, assoc.len))
! 108: {
! 109: botan_cipher_destroy(cipher);
! 110: return FALSE;
! 111: }
! 112:
! 113: nonce = chunk_cata("cc", this->salt, iv);
! 114:
! 115: if (botan_cipher_start(cipher, nonce.ptr, nonce.len))
! 116: {
! 117: botan_cipher_destroy(cipher);
! 118: return FALSE;
! 119: }
! 120:
! 121: if (init_flag == BOTAN_CIPHER_INIT_FLAG_ENCRYPT)
! 122: {
! 123: if (botan_cipher_update(cipher, BOTAN_CIPHER_UPDATE_FLAG_FINAL,
! 124: out, data.len + this->icv_size, &output_written,
! 125: data.ptr, data.len, &input_consumed))
! 126: {
! 127: botan_cipher_destroy(cipher);
! 128: return FALSE;
! 129: }
! 130: }
! 131: else if (init_flag == BOTAN_CIPHER_INIT_FLAG_DECRYPT)
! 132: {
! 133: if (botan_cipher_update(cipher, BOTAN_CIPHER_UPDATE_FLAG_FINAL,
! 134: out, data.len, &output_written, data.ptr,
! 135: data.len + this->icv_size, &input_consumed))
! 136: {
! 137: botan_cipher_destroy(cipher);
! 138: return FALSE;
! 139: }
! 140: }
! 141:
! 142: botan_cipher_destroy(cipher);
! 143:
! 144: return TRUE;
! 145: }
! 146:
! 147: METHOD(aead_t, encrypt, bool,
! 148: private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
! 149: chunk_t *encrypted)
! 150: {
! 151: u_char *out;
! 152:
! 153: out = plain.ptr;
! 154: if (encrypted)
! 155: {
! 156: *encrypted = chunk_alloc(plain.len + this->icv_size);
! 157: out = encrypted->ptr;
! 158: }
! 159: return do_crypt(this, plain, assoc, iv, out,
! 160: BOTAN_CIPHER_INIT_FLAG_ENCRYPT);
! 161: }
! 162:
! 163: METHOD(aead_t, decrypt, bool,
! 164: private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
! 165: chunk_t *plain)
! 166: {
! 167: u_char *out;
! 168:
! 169: if (encrypted.len < this->icv_size)
! 170: {
! 171: return FALSE;
! 172: }
! 173: encrypted.len -= this->icv_size;
! 174:
! 175: out = encrypted.ptr;
! 176: if (plain)
! 177: {
! 178: *plain = chunk_alloc(encrypted.len);
! 179: out = plain->ptr;
! 180: }
! 181: return do_crypt(this, encrypted, assoc, iv, out,
! 182: BOTAN_CIPHER_INIT_FLAG_DECRYPT);
! 183: }
! 184:
! 185: METHOD(aead_t, get_block_size, size_t,
! 186: private_aead_t *this)
! 187: {
! 188: return 1;
! 189: }
! 190:
! 191: METHOD(aead_t, get_icv_size, size_t,
! 192: private_aead_t *this)
! 193: {
! 194: return this->icv_size;
! 195: }
! 196:
! 197: METHOD(aead_t, get_iv_size, size_t,
! 198: private_aead_t *this)
! 199: {
! 200: return IV_LEN;
! 201: }
! 202:
! 203: METHOD(aead_t, get_iv_gen, iv_gen_t*,
! 204: private_aead_t *this)
! 205: {
! 206: return this->iv_gen;
! 207: }
! 208:
! 209: METHOD(aead_t, get_key_size, size_t,
! 210: private_aead_t *this)
! 211: {
! 212: return this->key.len + this->salt.len;
! 213: }
! 214:
! 215: METHOD(aead_t, set_key, bool,
! 216: private_aead_t *this, chunk_t key)
! 217: {
! 218: if (key.len != get_key_size(this))
! 219: {
! 220: return FALSE;
! 221: }
! 222: memcpy(this->salt.ptr, key.ptr + key.len - this->salt.len, this->salt.len);
! 223: memcpy(this->key.ptr, key.ptr, this->key.len);
! 224: return TRUE;
! 225: }
! 226:
! 227: METHOD(aead_t, destroy, void,
! 228: private_aead_t *this)
! 229: {
! 230: chunk_clear(&this->key);
! 231: chunk_clear(&this->salt);
! 232: this->iv_gen->destroy(this->iv_gen);
! 233: free(this);
! 234: }
! 235:
! 236: #ifdef BOTAN_HAS_AES
! 237: #if defined(BOTAN_HAS_AEAD_GCM) || defined(BOTAN_HAS_AEAD_GCM)
! 238:
! 239: static struct {
! 240: encryption_algorithm_t algo;
! 241: size_t key_size;
! 242: char *name;
! 243: size_t icv_size;
! 244: } aes_modes[] = {
! 245: { ENCR_AES_GCM_ICV8, 16, "AES-128/GCM(8)", 8 },
! 246: { ENCR_AES_GCM_ICV8, 24, "AES-192/GCM(8)", 8 },
! 247: { ENCR_AES_GCM_ICV8, 32, "AES-256/GCM(8)", 8 },
! 248: { ENCR_AES_GCM_ICV12, 16, "AES-128/GCM(12)", 12 },
! 249: { ENCR_AES_GCM_ICV12, 24, "AES-192/GCM(12)", 12 },
! 250: { ENCR_AES_GCM_ICV12, 32, "AES-256/GCM(12)", 12 },
! 251: { ENCR_AES_GCM_ICV16, 16, "AES-128/GCM(16)", 16 },
! 252: { ENCR_AES_GCM_ICV16, 24, "AES-192/GCM(16)", 16 },
! 253: { ENCR_AES_GCM_ICV16, 32, "AES-256/GCM(16)", 16 },
! 254: { ENCR_AES_CCM_ICV8, 16, "AES-128/CCM(8,4)", 8 },
! 255: { ENCR_AES_CCM_ICV8, 24, "AES-192/CCM(8,4)", 8 },
! 256: { ENCR_AES_CCM_ICV8, 32, "AES-256/CCM(8,4)", 8 },
! 257: { ENCR_AES_CCM_ICV12, 16, "AES-128/CCM(12,4)", 12 },
! 258: { ENCR_AES_CCM_ICV12, 24, "AES-192/CCM(12,4)", 12 },
! 259: { ENCR_AES_CCM_ICV12, 32, "AES-256/CCM(12,4)", 12 },
! 260: { ENCR_AES_CCM_ICV16, 16, "AES-128/CCM(16,4)", 16 },
! 261: { ENCR_AES_CCM_ICV16, 24, "AES-192/CCM(16,4)", 16 },
! 262: { ENCR_AES_CCM_ICV16, 32, "AES-256/CCM(16,4)", 16 },
! 263: };
! 264:
! 265: /**
! 266: * Determine the cipher name and ICV size for the given algorithm and key size
! 267: */
! 268: static bool determine_aes_params(private_aead_t *this,
! 269: encryption_algorithm_t algo, size_t key_size)
! 270: {
! 271: int i;
! 272:
! 273: for (i = 0; i < countof(aes_modes); i++)
! 274: {
! 275: if (aes_modes[i].algo == algo &&
! 276: aes_modes[i].key_size == key_size)
! 277: {
! 278: this->cipher_name = aes_modes[i].name;
! 279: this->icv_size = aes_modes[i].icv_size;
! 280: return TRUE;
! 281: }
! 282: }
! 283: return FALSE;
! 284: }
! 285:
! 286: #endif
! 287: #endif
! 288:
! 289: /**
! 290: * Check the given salt size, set it if not set
! 291: */
! 292: static bool check_salt_size(size_t expected, size_t *salt_size)
! 293: {
! 294: if (*salt_size)
! 295: {
! 296: return *salt_size == expected;
! 297: }
! 298: *salt_size = expected;
! 299: return TRUE;
! 300: }
! 301:
! 302: /*
! 303: * Described in header
! 304: */
! 305: aead_t *botan_aead_create(encryption_algorithm_t algo, size_t key_size,
! 306: size_t salt_size)
! 307: {
! 308: private_aead_t *this;
! 309:
! 310: INIT(this,
! 311: .public = {
! 312: .encrypt = _encrypt,
! 313: .decrypt = _decrypt,
! 314: .get_block_size = _get_block_size,
! 315: .get_icv_size = _get_icv_size,
! 316: .get_iv_size = _get_iv_size,
! 317: .get_iv_gen = _get_iv_gen,
! 318: .get_key_size = _get_key_size,
! 319: .set_key = _set_key,
! 320: .destroy = _destroy,
! 321: },
! 322: );
! 323:
! 324: switch (algo)
! 325: {
! 326: #ifdef BOTAN_HAS_AES
! 327: #ifdef BOTAN_HAS_AEAD_GCM
! 328: case ENCR_AES_GCM_ICV8:
! 329: case ENCR_AES_GCM_ICV12:
! 330: case ENCR_AES_GCM_ICV16:
! 331: if (!key_size)
! 332: {
! 333: key_size = 16;
! 334: }
! 335: if (!check_salt_size(SALT_LEN, &salt_size) ||
! 336: !determine_aes_params(this, algo, key_size))
! 337: {
! 338: free(this);
! 339: return NULL;
! 340: }
! 341: break;
! 342: #endif
! 343: #ifdef BOTAN_HAS_AEAD_CCM
! 344: case ENCR_AES_CCM_ICV8:
! 345: case ENCR_AES_CCM_ICV12:
! 346: case ENCR_AES_CCM_ICV16:
! 347: if (!key_size)
! 348: {
! 349: key_size = 16;
! 350: }
! 351: if (!check_salt_size(CCM_SALT_LEN, &salt_size) ||
! 352: !determine_aes_params(this, algo, key_size))
! 353: {
! 354: free(this);
! 355: return NULL;
! 356: }
! 357: break;
! 358: #endif
! 359: #endif
! 360: #ifdef BOTAN_HAS_AEAD_CHACHA20_POLY1305
! 361: case ENCR_CHACHA20_POLY1305:
! 362: if (!key_size)
! 363: {
! 364: key_size = CHAPOLY_KEY_LEN;
! 365: }
! 366: if (key_size != CHAPOLY_KEY_LEN ||
! 367: !check_salt_size(SALT_LEN, &salt_size))
! 368: {
! 369: free(this);
! 370: return NULL;
! 371: }
! 372: this->cipher_name = "ChaCha20Poly1305";
! 373: this->icv_size = 16;
! 374: break;
! 375: #endif
! 376: default:
! 377: free(this);
! 378: return NULL;
! 379: }
! 380:
! 381: this->key = chunk_alloc(key_size);
! 382: this->salt = chunk_alloc(salt_size);
! 383: this->iv_gen = iv_gen_seq_create();
! 384:
! 385: return &this->public;
! 386: }
! 387:
! 388: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>