Annotation of embedaddon/strongswan/src/libstrongswan/plugins/openssl/openssl_aead.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2013-2019 Tobias Brunner
! 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 <openssl/opensslv.h>
! 17:
! 18: #if OPENSSL_VERSION_NUMBER >= 0x1000100fL
! 19:
! 20: #include "openssl_aead.h"
! 21:
! 22: #include <openssl/evp.h>
! 23: #include <crypto/iv/iv_gen_seq.h>
! 24:
! 25: /* the generic AEAD identifiers were added with 1.1.0 */
! 26: #ifndef EVP_CTRL_AEAD_SET_IVLEN
! 27: #define EVP_CTRL_AEAD_SET_IVLEN EVP_CTRL_GCM_SET_IVLEN
! 28: #define EVP_CTRL_AEAD_SET_TAG EVP_CTRL_GCM_SET_TAG
! 29: #define EVP_CTRL_AEAD_GET_TAG EVP_CTRL_GCM_GET_TAG
! 30: #endif
! 31:
! 32: /** as defined in RFC 4106 */
! 33: #define IV_LEN 8
! 34: #define SALT_LEN 4
! 35: #define NONCE_LEN (IV_LEN + SALT_LEN)
! 36:
! 37: typedef struct private_aead_t private_aead_t;
! 38:
! 39: /**
! 40: * Private data of aead_t
! 41: */
! 42: struct private_aead_t {
! 43:
! 44: /**
! 45: * Public interface
! 46: */
! 47: aead_t public;
! 48:
! 49: /**
! 50: * The encryption key
! 51: */
! 52: chunk_t key;
! 53:
! 54: /**
! 55: * Salt value
! 56: */
! 57: char salt[SALT_LEN];
! 58:
! 59: /**
! 60: * Size of the integrity check value
! 61: */
! 62: size_t icv_size;
! 63:
! 64: /**
! 65: * IV generator
! 66: */
! 67: iv_gen_t *iv_gen;
! 68:
! 69: /**
! 70: * The cipher to use
! 71: */
! 72: const EVP_CIPHER *cipher;
! 73: };
! 74:
! 75: /**
! 76: * Do the actual en/decryption in an EVP context
! 77: */
! 78: static bool crypt(private_aead_t *this, chunk_t data, chunk_t assoc, chunk_t iv,
! 79: u_char *out, int enc)
! 80: {
! 81: EVP_CIPHER_CTX *ctx;
! 82: u_char nonce[NONCE_LEN];
! 83: bool success = FALSE;
! 84: int len;
! 85:
! 86: memcpy(nonce, this->salt, SALT_LEN);
! 87: memcpy(nonce + SALT_LEN, iv.ptr, IV_LEN);
! 88:
! 89: ctx = EVP_CIPHER_CTX_new();
! 90: EVP_CIPHER_CTX_set_padding(ctx, 0);
! 91: if (!EVP_CipherInit_ex(ctx, this->cipher, NULL, NULL, NULL, enc) ||
! 92: !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, NONCE_LEN, NULL) ||
! 93: !EVP_CipherInit_ex(ctx, NULL, NULL, this->key.ptr, nonce, enc))
! 94: {
! 95: goto done;
! 96: }
! 97: if (!enc && !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, this->icv_size,
! 98: data.ptr + data.len))
! 99: { /* set ICV for verification on decryption */
! 100: goto done;
! 101: }
! 102: if (assoc.len && !EVP_CipherUpdate(ctx, NULL, &len, assoc.ptr, assoc.len))
! 103: { /* set AAD if specified */
! 104: goto done;
! 105: }
! 106: if (!EVP_CipherUpdate(ctx, out, &len, data.ptr, data.len) ||
! 107: !EVP_CipherFinal_ex(ctx, out + len, &len))
! 108: { /* EVP_CipherFinal_ex fails if ICV is incorrect on decryption */
! 109: goto done;
! 110: }
! 111: if (enc && !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, this->icv_size,
! 112: out + data.len))
! 113: { /* copy back the ICV when encrypting */
! 114: goto done;
! 115: }
! 116: success = TRUE;
! 117:
! 118: done:
! 119: EVP_CIPHER_CTX_free(ctx);
! 120: return success;
! 121: }
! 122:
! 123: METHOD(aead_t, encrypt, bool,
! 124: private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
! 125: chunk_t *encrypted)
! 126: {
! 127: u_char *out;
! 128:
! 129: out = plain.ptr;
! 130: if (encrypted)
! 131: {
! 132: *encrypted = chunk_alloc(plain.len + this->icv_size);
! 133: out = encrypted->ptr;
! 134: }
! 135: return crypt(this, plain, assoc, iv, out, 1);
! 136: }
! 137:
! 138: METHOD(aead_t, decrypt, bool,
! 139: private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
! 140: chunk_t *plain)
! 141: {
! 142: u_char *out;
! 143:
! 144: if (encrypted.len < this->icv_size)
! 145: {
! 146: return FALSE;
! 147: }
! 148: encrypted.len -= this->icv_size;
! 149:
! 150: out = encrypted.ptr;
! 151: if (plain)
! 152: {
! 153: *plain = chunk_alloc(encrypted.len);
! 154: out = plain->ptr;
! 155: }
! 156: return crypt(this, encrypted, assoc, iv, out, 0);
! 157: }
! 158:
! 159: METHOD(aead_t, get_block_size, size_t,
! 160: private_aead_t *this)
! 161: {
! 162: return EVP_CIPHER_block_size(this->cipher);
! 163: }
! 164:
! 165: METHOD(aead_t, get_icv_size, size_t,
! 166: private_aead_t *this)
! 167: {
! 168: return this->icv_size;
! 169: }
! 170:
! 171: METHOD(aead_t, get_iv_size, size_t,
! 172: private_aead_t *this)
! 173: {
! 174: return IV_LEN;
! 175: }
! 176:
! 177: METHOD(aead_t, get_iv_gen, iv_gen_t*,
! 178: private_aead_t *this)
! 179: {
! 180: return this->iv_gen;
! 181: }
! 182:
! 183: METHOD(aead_t, get_key_size, size_t,
! 184: private_aead_t *this)
! 185: {
! 186: return this->key.len + SALT_LEN;
! 187: }
! 188:
! 189: METHOD(aead_t, set_key, bool,
! 190: private_aead_t *this, chunk_t key)
! 191: {
! 192: if (key.len != get_key_size(this))
! 193: {
! 194: return FALSE;
! 195: }
! 196: memcpy(this->salt, key.ptr + key.len - SALT_LEN, SALT_LEN);
! 197: memcpy(this->key.ptr, key.ptr, this->key.len);
! 198: return TRUE;
! 199: }
! 200:
! 201: METHOD(aead_t, destroy, void,
! 202: private_aead_t *this)
! 203: {
! 204: chunk_clear(&this->key);
! 205: this->iv_gen->destroy(this->iv_gen);
! 206: free(this);
! 207: }
! 208:
! 209: /*
! 210: * Described in header
! 211: */
! 212: aead_t *openssl_aead_create(encryption_algorithm_t algo,
! 213: size_t key_size, size_t salt_size)
! 214: {
! 215: private_aead_t *this;
! 216:
! 217: INIT(this,
! 218: .public = {
! 219: .encrypt = _encrypt,
! 220: .decrypt = _decrypt,
! 221: .get_block_size = _get_block_size,
! 222: .get_icv_size = _get_icv_size,
! 223: .get_iv_size = _get_iv_size,
! 224: .get_iv_gen = _get_iv_gen,
! 225: .get_key_size = _get_key_size,
! 226: .set_key = _set_key,
! 227: .destroy = _destroy,
! 228: },
! 229: );
! 230:
! 231: switch (algo)
! 232: {
! 233: case ENCR_AES_GCM_ICV8:
! 234: this->icv_size = 8;
! 235: break;
! 236: case ENCR_AES_GCM_ICV12:
! 237: this->icv_size = 12;
! 238: break;
! 239: case ENCR_AES_GCM_ICV16:
! 240: this->icv_size = 16;
! 241: break;
! 242: case ENCR_CHACHA20_POLY1305:
! 243: this->icv_size = 16;
! 244: break;
! 245: default:
! 246: free(this);
! 247: return NULL;
! 248: }
! 249:
! 250: if (salt_size && salt_size != SALT_LEN)
! 251: {
! 252: /* currently not supported */
! 253: free(this);
! 254: return NULL;
! 255: }
! 256:
! 257: switch (algo)
! 258: {
! 259: case ENCR_AES_GCM_ICV8:
! 260: case ENCR_AES_GCM_ICV12:
! 261: case ENCR_AES_GCM_ICV16:
! 262: switch (key_size)
! 263: {
! 264: case 0:
! 265: key_size = 16;
! 266: /* FALL */
! 267: case 16:
! 268: this->cipher = EVP_aes_128_gcm();
! 269: break;
! 270: case 24:
! 271: this->cipher = EVP_aes_192_gcm();
! 272: break;
! 273: case 32:
! 274: this->cipher = EVP_aes_256_gcm();
! 275: break;
! 276: default:
! 277: free(this);
! 278: return NULL;
! 279: }
! 280: break;
! 281: #if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_CHACHA)
! 282: case ENCR_CHACHA20_POLY1305:
! 283: switch (key_size)
! 284: {
! 285: case 0:
! 286: key_size = 32;
! 287: /* FALL */
! 288: case 32:
! 289: this->cipher = EVP_chacha20_poly1305();
! 290: break;
! 291: default:
! 292: free(this);
! 293: return NULL;
! 294: }
! 295: break;
! 296: #endif /* OPENSSL_NO_CHACHA */
! 297: default:
! 298: free(this);
! 299: return NULL;
! 300: }
! 301:
! 302: if (!this->cipher)
! 303: {
! 304: free(this);
! 305: return NULL;
! 306: }
! 307:
! 308: this->key = chunk_alloc(key_size);
! 309: this->iv_gen = iv_gen_seq_create();
! 310:
! 311: return &this->public;
! 312: }
! 313:
! 314: #endif /* OPENSSL_VERSION_NUMBER */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>