]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
openssl: Add support for AES and Camellia in CTR mode
authorTobias Brunner <tobias@strongswan.org>
Tue, 31 May 2022 14:03:43 +0000 (16:03 +0200)
committerTobias Brunner <tobias@strongswan.org>
Mon, 18 Jul 2022 11:01:22 +0000 (13:01 +0200)
src/libstrongswan/plugins/openssl/openssl_crypter.c
src/libstrongswan/plugins/openssl/openssl_plugin.c

index f2d93a6810ab04494d9f237e733637e04f32c3dc..21056d98d161bfc2f61b4689327f5cae4c185cca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2008-2022 Tobias Brunner
  *
  * Copyright (C) secunet Security Networks AG
  *
 
 typedef struct private_openssl_crypter_t private_openssl_crypter_t;
 
+/**
+ * These are as defined by RFC 3686
+ */
+#define CTR_NONCE_LEN  4
+#define CTR_IV_LEN             8
+
 /**
  * Private data of openssl_crypter_t
  */
@@ -31,12 +37,17 @@ struct private_openssl_crypter_t {
        openssl_crypter_t public;
 
        /*
-        * the key
+        * The key
         */
        chunk_t key;
 
+       /**
+        * Nonce value (CTR mode)
+        */
+       chunk_t nonce;
+
        /*
-        * the cipher to use
+        * The cipher to use
         */
        const EVP_CIPHER *cipher;
 };
@@ -96,9 +107,24 @@ static bool crypt(private_openssl_crypter_t *this, chunk_t data, chunk_t iv,
 {
        EVP_CIPHER_CTX *ctx;
        int len;
-       u_char *out;
+       u_char iv_buf[EVP_CIPHER_iv_length(this->cipher)], *iv_ptr = iv_buf, *out;
        bool success = FALSE;
 
+       if (this->nonce.len && (this->nonce.len + iv.len) <= sizeof(iv_buf))
+       {
+               memset(iv_buf, 0, sizeof(iv_buf));
+               memcpy(iv_buf, this->nonce.ptr, this->nonce.len);
+               memcpy(iv_buf + this->nonce.len, iv.ptr, iv.len);
+               iv_buf[sizeof(iv_buf) - 1] = 1;
+       }
+       else if (iv.len == sizeof(iv_buf))
+       {
+               iv_ptr = iv.ptr;
+       }
+       else
+       {
+               return FALSE;
+       }
        out = data.ptr;
        if (dst)
        {
@@ -109,7 +135,7 @@ static bool crypt(private_openssl_crypter_t *this, chunk_t data, chunk_t iv,
        if (EVP_CipherInit_ex(ctx, this->cipher, NULL, NULL, NULL, enc) &&
                EVP_CIPHER_CTX_set_padding(ctx, 0) /* disable padding */ &&
                EVP_CIPHER_CTX_set_key_length(ctx, this->key.len) &&
-               EVP_CipherInit_ex(ctx, NULL, NULL, this->key.ptr, iv.ptr, enc) &&
+               EVP_CipherInit_ex(ctx, NULL, NULL, this->key.ptr, iv_ptr, enc) &&
                EVP_CipherUpdate(ctx, out, &len, data.ptr, data.len) &&
                /* since padding is disabled this does nothing */
                EVP_CipherFinal_ex(ctx, out + len, &len))
@@ -141,19 +167,28 @@ METHOD(crypter_t, get_block_size, size_t,
 METHOD(crypter_t, get_iv_size, size_t,
        private_openssl_crypter_t *this)
 {
+       if (this->nonce.len)
+       {
+               return CTR_IV_LEN;
+       }
        return EVP_CIPHER_iv_length(this->cipher);
 }
 
 METHOD(crypter_t, get_key_size, size_t,
        private_openssl_crypter_t *this)
 {
-       return this->key.len;
+       return this->key.len + this->nonce.len;
 }
 
 METHOD(crypter_t, set_key, bool,
        private_openssl_crypter_t *this, chunk_t key)
 {
-       memcpy(this->key.ptr, key.ptr, min(key.len, this->key.len));
+       if (key.len != get_key_size(this))
+       {
+               return FALSE;
+       }
+       memcpy(this->nonce.ptr, key.ptr + key.len - this->nonce.len, this->nonce.len);
+       memcpy(this->key.ptr, key.ptr, this->key.len);
        return TRUE;
 }
 
@@ -161,6 +196,7 @@ METHOD(crypter_t, destroy, void,
        private_openssl_crypter_t *this)
 {
        chunk_clear(&this->key);
+       chunk_clear(&this->nonce);
        free(this);
 }
 
@@ -171,6 +207,7 @@ openssl_crypter_t *openssl_crypter_create(encryption_algorithm_t algo,
                                                                                                  size_t key_size)
 {
        private_openssl_crypter_t *this;
+       size_t nonce_size = 0;
 
        INIT(this,
                .public = {
@@ -212,6 +249,27 @@ openssl_crypter_t *openssl_crypter_create(encryption_algorithm_t algo,
                                        return NULL;
                        }
                        break;
+               case ENCR_AES_CTR:
+                       switch (key_size)
+                       {
+                               case 0:
+                                       key_size = 16;
+                                       /* FALL */
+                               case 16:        /* AES 128 */
+                                       this->cipher = EVP_get_cipherbyname("aes-128-ctr");
+                                       break;
+                               case 24:        /* AES-192 */
+                                       this->cipher = EVP_get_cipherbyname("aes-192-ctr");
+                                       break;
+                               case 32:        /* AES-256 */
+                                       this->cipher = EVP_get_cipherbyname("aes-256-ctr");
+                                       break;
+                               default:
+                                       free(this);
+                                       return NULL;
+                       }
+                       nonce_size = CTR_NONCE_LEN;
+                       break;
                case ENCR_AES_ECB:
                        switch (key_size)
                        {
@@ -272,6 +330,27 @@ openssl_crypter_t *openssl_crypter_create(encryption_algorithm_t algo,
                                        return NULL;
                        }
                        break;
+               case ENCR_CAMELLIA_CTR:
+                       switch (key_size)
+                       {
+                               case 0:
+                                       key_size = 16;
+                                       /* FALL */
+                               case 16:        /* CAMELLIA 128 */
+                                       this->cipher = EVP_get_cipherbyname("camellia-128-ctr");
+                                       break;
+                               case 24:        /* CAMELLIA 192 */
+                                       this->cipher = EVP_get_cipherbyname("camellia-192-ctr");
+                                       break;
+                               case 32:        /* CAMELLIA 256 */
+                                       this->cipher = EVP_get_cipherbyname("camellia-256-ctr");
+                                       break;
+                               default:
+                                       free(this);
+                                       return NULL;
+                       }
+                       nonce_size = CTR_NONCE_LEN;
+                       break;
 #ifndef OPENSSL_NO_DES
                case ENCR_DES_ECB:
                        key_size = 8;
@@ -302,6 +381,7 @@ openssl_crypter_t *openssl_crypter_create(encryption_algorithm_t algo,
        }
 
        this->key = chunk_alloc(key_size);
+       this->nonce = chunk_alloc(nonce_size);
 
        return &this->public;
 }
index 972d63e35285180facf35286af3bfa05b75fc2ff..439fae9a7f44b50dba9ee0b1f98d69f2bcdea22b 100644 (file)
@@ -382,6 +382,9 @@ METHOD(plugin_t, get_features, int,
                        PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CBC, 16),
                        PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CBC, 24),
                        PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CBC, 32),
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CTR, 16),
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CTR, 24),
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_AES_CTR, 32),
                        PLUGIN_PROVIDE(CRYPTER, ENCR_AES_ECB, 16),
                        PLUGIN_PROVIDE(CRYPTER, ENCR_AES_ECB, 24),
                        PLUGIN_PROVIDE(CRYPTER, ENCR_AES_ECB, 32),
@@ -393,6 +396,9 @@ METHOD(plugin_t, get_features, int,
                        PLUGIN_PROVIDE(CRYPTER, ENCR_CAMELLIA_CBC, 16),
                        PLUGIN_PROVIDE(CRYPTER, ENCR_CAMELLIA_CBC, 24),
                        PLUGIN_PROVIDE(CRYPTER, ENCR_CAMELLIA_CBC, 32),
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_CAMELLIA_CTR, 16),
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_CAMELLIA_CTR, 24),
+                       PLUGIN_PROVIDE(CRYPTER, ENCR_CAMELLIA_CTR, 32),
 #endif
 #ifndef OPENSSL_NO_RC5
                        PLUGIN_PROVIDE(CRYPTER, ENCR_RC5, 0),