Implemented AES/Camellia counter mode in gcrypt
authorMartin Willi <martin@revosec.ch>
Fri, 13 Aug 2010 12:11:38 +0000 (14:11 +0200)
committerMartin Willi <martin@revosec.ch>
Fri, 13 Aug 2010 15:11:53 +0000 (17:11 +0200)
src/libstrongswan/crypto/crypters/crypter.h
src/libstrongswan/plugins/gcrypt/gcrypt_crypter.c
src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c

index 70697e2..6596d46 100644 (file)
@@ -42,6 +42,7 @@ enum encryption_algorithm_t {
        ENCR_DES_IV32 =            9,
        ENCR_NULL =               11,
        ENCR_AES_CBC =            12,
+       /** CTR as specified for IPsec (RFC5930/RFC3686), nonce appended to key */
        ENCR_AES_CTR =            13,
        ENCR_AES_CCM_ICV8 =       14,
        ENCR_AES_CCM_ICV12 =      15,
@@ -51,6 +52,7 @@ enum encryption_algorithm_t {
        ENCR_AES_GCM_ICV16 =      20,
        ENCR_NULL_AUTH_AES_GMAC = 21,
        ENCR_CAMELLIA_CBC =       23,
+       /* CTR as specified for IPsec (RFC5529), nonce appended to key */
        ENCR_CAMELLIA_CTR =       24,
        ENCR_CAMELLIA_CCM_ICV8 =  25,
        ENCR_CAMELLIA_CCM_ICV12 = 26,
@@ -109,6 +111,10 @@ struct crypter_t {
        /**
         * Get the block size of the crypto algorithm.
         *
+        * get_block_size() returns the smallest block the crypter can handle,
+        * not the block size of the underlying crypto algorithm. For counter mode,
+        * it is usually 1.
+        *
         * @return                              block size in bytes
         */
        size_t (*get_block_size) (crypter_t *this);
@@ -123,6 +129,10 @@ struct crypter_t {
        /**
         * Get the key size of the crypto algorithm.
         *
+        * get_key_size() might return a key length different from the key
+        * size passed to the factory constructor. For Counter Mode, the nonce
+        * is handled as a part of the key material and is passed to set_key().
+        *
         * @return                              key size in bytes
         */
        size_t (*get_key_size) (crypter_t *this);
index db8bfea..1d849bc 100644 (file)
@@ -40,12 +40,43 @@ struct private_gcrypt_crypter_t {
         * gcrypt algorithm identifier
         */
        int alg;
+
+       /**
+        * are we using counter mode?
+        */
+       bool ctr_mode;
+
+       /**
+        * counter state
+        */
+       struct {
+               char nonce[4];
+               char iv[8];
+               u_int32_t counter;
+       } __attribute__((packed)) ctr;
 };
 
+/**
+ * Set the IV for en/decryption
+ */
+static void set_iv(private_gcrypt_crypter_t *this, chunk_t iv)
+{
+       if (this->ctr_mode)
+       {
+               memcpy(this->ctr.iv, iv.ptr, sizeof(this->ctr.iv));
+               this->ctr.counter = htonl(1);
+               gcry_cipher_setctr(this->h, &this->ctr, sizeof(this->ctr));
+       }
+       else
+       {
+               gcry_cipher_setiv(this->h, iv.ptr, iv.len);
+       }
+}
+
 METHOD(crypter_t, decrypt, void,
        private_gcrypt_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst)
 {
-       gcry_cipher_setiv(this->h, iv.ptr, iv.len);
+       set_iv(this, iv);
 
        if (dst)
        {
@@ -61,7 +92,7 @@ METHOD(crypter_t, decrypt, void,
 METHOD(crypter_t, encrypt, void,
        private_gcrypt_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst)
 {
-       gcry_cipher_setiv(this->h, iv.ptr, iv.len);
+       set_iv(this, iv);
 
        if (dst)
        {
@@ -79,6 +110,10 @@ METHOD(crypter_t, get_block_size, size_t,
 {
        size_t len = 0;
 
+       if (this->ctr_mode)
+       {       /* counter mode does not need any padding */
+               return 1;
+       }
        gcry_cipher_algo_info(this->alg, GCRYCTL_GET_BLKLEN, NULL, &len);
        return len;
 }
@@ -88,6 +123,10 @@ METHOD(crypter_t, get_iv_size, size_t,
 {
        size_t len = 0;
 
+       if (this->ctr_mode)
+       {
+               return sizeof(this->ctr.iv);
+       }
        gcry_cipher_algo_info(this->alg, GCRYCTL_GET_BLKLEN, NULL, &len);
        return len;
 }
@@ -98,12 +137,23 @@ METHOD(crypter_t, get_key_size, size_t,
        size_t len = 0;
 
        gcry_cipher_algo_info(this->alg, GCRYCTL_GET_KEYLEN, NULL, &len);
+       if (this->ctr_mode)
+       {
+               return len + sizeof(this->ctr.nonce);
+       }
        return len;
 }
 
 METHOD(crypter_t, set_key, void,
        private_gcrypt_crypter_t *this, chunk_t key)
 {
+       if (this->ctr_mode)
+       {
+               /* last 4 bytes are the nonce */
+               memcpy(this->ctr.nonce, key.ptr + key.len - sizeof(this->ctr.nonce),
+                          sizeof(this->ctr.nonce));
+               key.len -= sizeof(this->ctr.nonce);
+       }
        gcry_cipher_setkey(this->h, key.ptr, key.len);
 }
 
@@ -150,8 +200,8 @@ gcrypt_crypter_t *gcrypt_crypter_create(encryption_algorithm_t algo,
                        }
                        gcrypt_alg = GCRY_CIPHER_BLOWFISH;
                        break;
-               /* case ENCR_AES_CTR:
-                       mode = GCRY_CIPHER_MODE_CTR; */
+               case ENCR_AES_CTR:
+                       mode = GCRY_CIPHER_MODE_CTR;
                        /* fall */
                case ENCR_AES_CBC:
                        switch (key_size)
@@ -169,8 +219,8 @@ gcrypt_crypter_t *gcrypt_crypter_create(encryption_algorithm_t algo,
                                        return NULL;
                        }
                        break;
-               /* case ENCR_CAMELLIA_CTR:
-                       mode = GCRY_CIPHER_MODE_CTR; */
+               case ENCR_CAMELLIA_CTR:
+                       mode = GCRY_CIPHER_MODE_CTR;
                        /* fall */
                case ENCR_CAMELLIA_CBC:
                        switch (key_size)
@@ -234,6 +284,7 @@ gcrypt_crypter_t *gcrypt_crypter_create(encryption_algorithm_t algo,
                        .destroy = _destroy,
                },
                .alg = gcrypt_alg,
+               .ctr_mode = mode == GCRY_CIPHER_MODE_CTR,
        );
 
        err = gcry_cipher_open(&this->h, gcrypt_alg, mode, 0);
index 99f9f2f..cc13f55 100644 (file)
@@ -170,8 +170,14 @@ plugin_t *gcrypt_plugin_create()
                                        (crypter_constructor_t)gcrypt_crypter_create);
        lib->crypto->add_crypter(lib->crypto, ENCR_AES_CBC,
                                        (crypter_constructor_t)gcrypt_crypter_create);
+       lib->crypto->add_crypter(lib->crypto, ENCR_AES_CTR,
+                                       (crypter_constructor_t)gcrypt_crypter_create);
+#ifdef HAVE_GCRY_CIPHER_CAMELLIA
        lib->crypto->add_crypter(lib->crypto, ENCR_CAMELLIA_CBC,
                                        (crypter_constructor_t)gcrypt_crypter_create);
+       lib->crypto->add_crypter(lib->crypto, ENCR_CAMELLIA_CTR,
+                                       (crypter_constructor_t)gcrypt_crypter_create);
+#endif /* HAVE_GCRY_CIPHER_CAMELLIA */
        lib->crypto->add_crypter(lib->crypto, ENCR_SERPENT_CBC,
                                        (crypter_constructor_t)gcrypt_crypter_create);
        lib->crypto->add_crypter(lib->crypto, ENCR_TWOFISH_CBC,