crypto: add support for the cast5-128 cipher algorithm
authorDaniel P. Berrange <berrange@redhat.com>
Wed, 10 Feb 2016 17:07:42 +0000 (17:07 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Thu, 17 Mar 2016 14:41:15 +0000 (14:41 +0000)
A new cipher algorithm 'cast-5-128' is defined for the
Cast-5 algorithm with 128 bit key size. Smaller key sizes
are supported by Cast-5, but nothing in QEMU should use
them, so only 128 bit keys are permitted.

The nettle and gcrypt cipher backends are updated to
support the new cipher and a test vector added to the
cipher test suite. The new algorithm is enabled in the
LUKS block encryption driver.

Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Fam Zheng <famz@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
crypto/cipher-gcrypt.c
crypto/cipher-nettle.c
crypto/cipher.c
qapi/crypto.json
tests/test-crypto-cipher.c

index 56d4c9d10b78cad68df5841056af2f1725d3074a..aa1d8c58897f521b487f332c6f52706b285e6e14 100644 (file)
@@ -29,6 +29,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
     case QCRYPTO_CIPHER_ALG_AES_128:
     case QCRYPTO_CIPHER_ALG_AES_192:
     case QCRYPTO_CIPHER_ALG_AES_256:
+    case QCRYPTO_CIPHER_ALG_CAST5_128:
         return true;
     default:
         return false;
@@ -84,6 +85,10 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
         gcryalg = GCRY_CIPHER_AES256;
         break;
 
+    case QCRYPTO_CIPHER_ALG_CAST5_128:
+        gcryalg = GCRY_CIPHER_CAST5;
+        break;
+
     default:
         error_setg(errp, "Unsupported cipher algorithm %d", alg);
         return NULL;
@@ -113,7 +118,18 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
         ctx->blocksize = 8;
     } else {
         err = gcry_cipher_setkey(ctx->handle, key, nkey);
-        ctx->blocksize = 16;
+        switch (cipher->alg) {
+        case QCRYPTO_CIPHER_ALG_AES_128:
+        case QCRYPTO_CIPHER_ALG_AES_192:
+        case QCRYPTO_CIPHER_ALG_AES_256:
+            ctx->blocksize = 16;
+            break;
+        case QCRYPTO_CIPHER_ALG_CAST5_128:
+            ctx->blocksize = 8;
+            break;
+        default:
+            g_assert_not_reached();
+        }
     }
     if (err != 0) {
         error_setg(errp, "Cannot set key: %s",
index cd2675c0bca3aff7c0d4768d1523aa4620c759f2..cfa69cc5d76c72125689e8d2afe1893a0a9a0cdb 100644 (file)
@@ -23,6 +23,7 @@
 #include <nettle/aes.h>
 #include <nettle/des.h>
 #include <nettle/cbc.h>
+#include <nettle/cast128.h>
 
 #if CONFIG_NETTLE_VERSION_MAJOR < 3
 typedef nettle_crypt_func nettle_cipher_func;
@@ -63,6 +64,18 @@ static void des_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
     des_decrypt(ctx, length, dst, src);
 }
 
+static void cast128_encrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
+                                    uint8_t *dst, const uint8_t *src)
+{
+    cast128_encrypt(ctx, length, dst, src);
+}
+
+static void cast128_decrypt_wrapper(cipher_ctx_t ctx, cipher_length_t length,
+                                    uint8_t *dst, const uint8_t *src)
+{
+    cast128_decrypt(ctx, length, dst, src);
+}
+
 typedef struct QCryptoCipherNettle QCryptoCipherNettle;
 struct QCryptoCipherNettle {
     void *ctx_encrypt;
@@ -80,6 +93,7 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
     case QCRYPTO_CIPHER_ALG_AES_128:
     case QCRYPTO_CIPHER_ALG_AES_192:
     case QCRYPTO_CIPHER_ALG_AES_256:
+    case QCRYPTO_CIPHER_ALG_CAST5_128:
         return true;
     default:
         return false;
@@ -143,6 +157,18 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
 
         ctx->blocksize = AES_BLOCK_SIZE;
         break;
+
+    case QCRYPTO_CIPHER_ALG_CAST5_128:
+        ctx->ctx_encrypt = g_new0(struct cast128_ctx, 1);
+        ctx->ctx_decrypt = NULL; /* 1 ctx can do both */
+
+        cast5_set_key(ctx->ctx_encrypt, nkey, key);
+
+        ctx->alg_encrypt = cast128_encrypt_wrapper;
+        ctx->alg_decrypt = cast128_decrypt_wrapper;
+
+        ctx->blocksize = CAST128_BLOCK_SIZE;
+        break;
     default:
         error_setg(errp, "Unsupported cipher algorithm %d", alg);
         goto error;
index 076dff023cc5a46fe34ca519ddf0503b14540c8b..9e0a226d3c82559b4c044678c922808f150763d0 100644 (file)
@@ -27,6 +27,7 @@ static size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = {
     [QCRYPTO_CIPHER_ALG_AES_192] = 24,
     [QCRYPTO_CIPHER_ALG_AES_256] = 32,
     [QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
+    [QCRYPTO_CIPHER_ALG_CAST5_128] = 16,
 };
 
 static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
@@ -34,6 +35,7 @@ static size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
     [QCRYPTO_CIPHER_ALG_AES_192] = 16,
     [QCRYPTO_CIPHER_ALG_AES_256] = 16,
     [QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
+    [QCRYPTO_CIPHER_ALG_CAST5_128] = 8,
 };
 
 static bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX] = {
index 42b979a0d50fac8c6952fa131fd7464e37a4db5b..0550ee7803101a1013a63c78f353ef06d5a03940 100644 (file)
 # @aes-192: AES with 192 bit / 24 byte keys
 # @aes-256: AES with 256 bit / 32 byte keys
 # @des-rfb: RFB specific variant of single DES. Do not use except in VNC.
+# @cast5-128: Cast5 with 128 bit / 16 byte keys
 # Since: 2.6
 ##
 { 'enum': 'QCryptoCipherAlgorithm',
   'prefix': 'QCRYPTO_CIPHER_ALG',
-  'data': ['aes-128', 'aes-192', 'aes-256', 'des-rfb']}
+  'data': ['aes-128', 'aes-192', 'aes-256',
+           'des-rfb',
+           'cast5-128']}
 
 
 ##
index 7a073e96731d109fed51d06a6df2daa388c5e2df..a994ca925c8b106a0404b0053048e57776e94766 100644 (file)
@@ -165,6 +165,15 @@ static QCryptoCipherTestData test_data[] = {
             "ffd29f1bb5596ad94ea2d8e6196b7f09"
             "30d8ed0bf2773af36dd82a6280c20926",
     },
+    {
+        /* RFC 2144, Appendix B.1 */
+        .path = "/crypto/cipher/cast5-128",
+        .alg = QCRYPTO_CIPHER_ALG_CAST5_128,
+        .mode = QCRYPTO_CIPHER_MODE_ECB,
+        .key = "0123456712345678234567893456789A",
+        .plaintext = "0123456789abcdef",
+        .ciphertext = "238b4fe5847e44b2",
+    },
 };