Annotation of embedaddon/strongswan/src/libstrongswan/plugins/openssl/openssl_crypter.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2008 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_crypter.h"
! 17:
! 18: #include <openssl/evp.h>
! 19:
! 20: typedef struct private_openssl_crypter_t private_openssl_crypter_t;
! 21:
! 22: /**
! 23: * Private data of openssl_crypter_t
! 24: */
! 25: struct private_openssl_crypter_t {
! 26:
! 27: /**
! 28: * Public part of this class.
! 29: */
! 30: openssl_crypter_t public;
! 31:
! 32: /*
! 33: * the key
! 34: */
! 35: chunk_t key;
! 36:
! 37: /*
! 38: * the cipher to use
! 39: */
! 40: const EVP_CIPHER *cipher;
! 41: };
! 42:
! 43: /**
! 44: * Look up an OpenSSL algorithm name and validate its key size
! 45: */
! 46: static char* lookup_algorithm(uint16_t ikev2_algo, size_t *key_size)
! 47: {
! 48: struct {
! 49: /* identifier specified in IKEv2 */
! 50: int ikev2_id;
! 51: /* name of the algorithm, as used in OpenSSL */
! 52: char *name;
! 53: /* default key size in bytes */
! 54: size_t key_def;
! 55: /* minimum key size */
! 56: size_t key_min;
! 57: /* maximum key size */
! 58: size_t key_max;
! 59: } mappings[] = {
! 60: {ENCR_DES, "des-cbc", 8, 8, 8},
! 61: {ENCR_3DES, "des-ede3-cbc", 24, 24, 24},
! 62: {ENCR_RC5, "rc5-cbc", 16, 5, 255},
! 63: {ENCR_IDEA, "idea-cbc", 16, 16, 16},
! 64: {ENCR_CAST, "cast5-cbc", 16, 5, 16},
! 65: {ENCR_BLOWFISH, "bf-cbc", 16, 5, 56},
! 66: };
! 67: int i;
! 68:
! 69: for (i = 0; i < countof(mappings); i++)
! 70: {
! 71: if (ikev2_algo == mappings[i].ikev2_id)
! 72: {
! 73: /* set the key size if it is not set */
! 74: if (*key_size == 0)
! 75: {
! 76: *key_size = mappings[i].key_def;
! 77: }
! 78: /* validate key size */
! 79: if (*key_size < mappings[i].key_min ||
! 80: *key_size > mappings[i].key_max)
! 81: {
! 82: return NULL;
! 83: }
! 84: return mappings[i].name;
! 85: }
! 86: }
! 87: return NULL;
! 88: }
! 89:
! 90: /**
! 91: * Do the actual en/decryption in an EVP context
! 92: */
! 93: static bool crypt(private_openssl_crypter_t *this, chunk_t data, chunk_t iv,
! 94: chunk_t *dst, int enc)
! 95: {
! 96: EVP_CIPHER_CTX *ctx;
! 97: int len;
! 98: u_char *out;
! 99: bool success = FALSE;
! 100:
! 101: out = data.ptr;
! 102: if (dst)
! 103: {
! 104: *dst = chunk_alloc(data.len);
! 105: out = dst->ptr;
! 106: }
! 107: ctx = EVP_CIPHER_CTX_new();
! 108: if (EVP_CipherInit_ex(ctx, this->cipher, NULL, NULL, NULL, enc) &&
! 109: EVP_CIPHER_CTX_set_padding(ctx, 0) /* disable padding */ &&
! 110: EVP_CIPHER_CTX_set_key_length(ctx, this->key.len) &&
! 111: EVP_CipherInit_ex(ctx, NULL, NULL, this->key.ptr, iv.ptr, enc) &&
! 112: EVP_CipherUpdate(ctx, out, &len, data.ptr, data.len) &&
! 113: /* since padding is disabled this does nothing */
! 114: EVP_CipherFinal_ex(ctx, out + len, &len))
! 115: {
! 116: success = TRUE;
! 117: }
! 118: EVP_CIPHER_CTX_free(ctx);
! 119: return success;
! 120: }
! 121:
! 122: METHOD(crypter_t, decrypt, bool,
! 123: private_openssl_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst)
! 124: {
! 125: return crypt(this, data, iv, dst, 0);
! 126: }
! 127:
! 128: METHOD(crypter_t, encrypt, bool,
! 129: private_openssl_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst)
! 130: {
! 131: return crypt(this, data, iv, dst, 1);
! 132: }
! 133:
! 134: METHOD(crypter_t, get_block_size, size_t,
! 135: private_openssl_crypter_t *this)
! 136: {
! 137: return EVP_CIPHER_block_size(this->cipher);
! 138: }
! 139:
! 140: METHOD(crypter_t, get_iv_size, size_t,
! 141: private_openssl_crypter_t *this)
! 142: {
! 143: return EVP_CIPHER_iv_length(this->cipher);
! 144: }
! 145:
! 146: METHOD(crypter_t, get_key_size, size_t,
! 147: private_openssl_crypter_t *this)
! 148: {
! 149: return this->key.len;
! 150: }
! 151:
! 152: METHOD(crypter_t, set_key, bool,
! 153: private_openssl_crypter_t *this, chunk_t key)
! 154: {
! 155: memcpy(this->key.ptr, key.ptr, min(key.len, this->key.len));
! 156: return TRUE;
! 157: }
! 158:
! 159: METHOD(crypter_t, destroy, void,
! 160: private_openssl_crypter_t *this)
! 161: {
! 162: chunk_clear(&this->key);
! 163: free(this);
! 164: }
! 165:
! 166: /*
! 167: * Described in header
! 168: */
! 169: openssl_crypter_t *openssl_crypter_create(encryption_algorithm_t algo,
! 170: size_t key_size)
! 171: {
! 172: private_openssl_crypter_t *this;
! 173:
! 174: INIT(this,
! 175: .public = {
! 176: .crypter = {
! 177: .encrypt = _encrypt,
! 178: .decrypt = _decrypt,
! 179: .get_block_size = _get_block_size,
! 180: .get_iv_size = _get_iv_size,
! 181: .get_key_size = _get_key_size,
! 182: .set_key = _set_key,
! 183: .destroy = _destroy,
! 184: },
! 185: },
! 186: );
! 187:
! 188: switch (algo)
! 189: {
! 190: case ENCR_NULL:
! 191: this->cipher = EVP_enc_null();
! 192: key_size = 0;
! 193: break;
! 194: case ENCR_AES_CBC:
! 195: switch (key_size)
! 196: {
! 197: case 0:
! 198: key_size = 16;
! 199: /* FALL */
! 200: case 16: /* AES 128 */
! 201: this->cipher = EVP_get_cipherbyname("aes-128-cbc");
! 202: break;
! 203: case 24: /* AES-192 */
! 204: this->cipher = EVP_get_cipherbyname("aes-192-cbc");
! 205: break;
! 206: case 32: /* AES-256 */
! 207: this->cipher = EVP_get_cipherbyname("aes-256-cbc");
! 208: break;
! 209: default:
! 210: free(this);
! 211: return NULL;
! 212: }
! 213: break;
! 214: case ENCR_AES_ECB:
! 215: switch (key_size)
! 216: {
! 217: case 0:
! 218: key_size = 16;
! 219: /* FALL */
! 220: case 16: /* AES 128 */
! 221: this->cipher = EVP_get_cipherbyname("aes-128-ecb");
! 222: break;
! 223: case 24: /* AES-192 */
! 224: this->cipher = EVP_get_cipherbyname("aes-192-ecb");
! 225: break;
! 226: case 32: /* AES-256 */
! 227: this->cipher = EVP_get_cipherbyname("aes-256-ecb");
! 228: break;
! 229: default:
! 230: free(this);
! 231: return NULL;
! 232: }
! 233: break;
! 234: case ENCR_CAMELLIA_CBC:
! 235: switch (key_size)
! 236: {
! 237: case 0:
! 238: key_size = 16;
! 239: /* FALL */
! 240: case 16: /* CAMELLIA 128 */
! 241: this->cipher = EVP_get_cipherbyname("camellia-128-cbc");
! 242: break;
! 243: case 24: /* CAMELLIA 192 */
! 244: this->cipher = EVP_get_cipherbyname("camellia-192-cbc");
! 245: break;
! 246: case 32: /* CAMELLIA 256 */
! 247: this->cipher = EVP_get_cipherbyname("camellia-256-cbc");
! 248: break;
! 249: default:
! 250: free(this);
! 251: return NULL;
! 252: }
! 253: break;
! 254: #ifndef OPENSSL_NO_DES
! 255: case ENCR_DES_ECB:
! 256: key_size = 8;
! 257: this->cipher = EVP_des_ecb();
! 258: break;
! 259: #endif
! 260: default:
! 261: {
! 262: char* name;
! 263:
! 264: name = lookup_algorithm(algo, &key_size);
! 265: if (!name)
! 266: {
! 267: /* algo unavailable or key_size invalid */
! 268: free(this);
! 269: return NULL;
! 270: }
! 271: this->cipher = EVP_get_cipherbyname(name);
! 272: break;
! 273: }
! 274: }
! 275:
! 276: if (!this->cipher)
! 277: {
! 278: /* OpenSSL does not support the requested algo */
! 279: free(this);
! 280: return NULL;
! 281: }
! 282:
! 283: this->key = chunk_alloc(key_size);
! 284:
! 285: return &this->public;
! 286: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>