Return to botan_aead.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / plugins / botan |
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