hammer2 - further crypto cleanup
authorAlex Hornung <ahornung@gmail.com>
Fri, 10 Aug 2012 07:37:22 +0000 (08:37 +0100)
committerAlex Hornung <ahornung@gmail.com>
Fri, 10 Aug 2012 07:37:22 +0000 (08:37 +0100)
 * put the symmetric crypto algorithms (so far only GCM) into a table.
   The algorithm is currently chosen via a define (HAMMER2_CRYPTO_ALGO),
   but in the future it would be trivial to make it a runtime setting.

 * Link the crypto chunk size to HAMMER2_MSG_ALIGN, since we want the
   chunks as big as possible, but not so big that a message gets stuck.

sbin/hammer2/crypto.c
sbin/hammer2/network.h

index 43be4ac..fd5ac6f 100644 (file)
 static pthread_mutex_t *crypto_locks;
 int crypto_count;
 
 static pthread_mutex_t *crypto_locks;
 int crypto_count;
 
+static int hammer2_crypto_gcm_init(hammer2_ioq_t *, char *, int, char *, int, int);
+static int hammer2_crypto_gcm_encrypt_chunk(hammer2_ioq_t *, char *, char *, int, int *);
+static int hammer2_crypto_gcm_decrypt_chunk(hammer2_ioq_t *, char *, char *, int, int *);
+
+/*
+ * NOTE: the order of this table needs to match the HAMMER2_CRYPTO_ALGO_*_IDX
+ *       defines in network.h.
+ */
+static struct crypto_algo crypto_algos[] = {
+       {
+               .name      = "aes-256-gcm",
+               .keylen    = HAMMER2_CRYPTO_GCM_KEY_SIZE,
+               .taglen    = HAMMER2_CRYPTO_GCM_TAG_SIZE,
+               .init      = hammer2_crypto_gcm_init,
+               .enc_chunk = hammer2_crypto_gcm_encrypt_chunk,
+               .dec_chunk = hammer2_crypto_gcm_decrypt_chunk
+       },
+       { NULL, 0, 0, NULL, NULL, NULL }
+};
+
 static
 unsigned long
 hammer2_crypto_id_callback(void)
 static
 unsigned long
 hammer2_crypto_id_callback(void)
@@ -74,28 +94,28 @@ hammer2_crypto_setup(void)
 
 static
 int
 
 static
 int
-_gcm_init(hammer2_ioq_t *ioq, char *key, int klen, char *iv_fixed, int ivlen,
-         int enc)
+hammer2_crypto_gcm_init(hammer2_ioq_t *ioq, char *key, int klen,
+                       char *iv_fixed, int ivlen, int enc)
 {
        int i, ok;
 
 {
        int i, ok;
 
-       if (klen < 32 /* 256 bits */ || ivlen < 4 /* 32 bits */) {
+       if (klen < HAMMER2_CRYPTO_GCM_KEY_SIZE ||
+           ivlen < HAMMER2_CRYPTO_GCM_IV_FIXED_SIZE) {
                if (DebugOpt)
                        fprintf(stderr, "Not enough key or iv material\n");
                return -1;
        }
 
        printf("%s key: ", enc ? "Encryption" : "Decryption");
                if (DebugOpt)
                        fprintf(stderr, "Not enough key or iv material\n");
                return -1;
        }
 
        printf("%s key: ", enc ? "Encryption" : "Decryption");
-       for (i = 0; i < HAMMER2_AES_KEY_SIZE; ++i)
+       for (i = 0; i < HAMMER2_CRYPTO_GCM_KEY_SIZE; ++i)
                printf("%02x", (unsigned char)key[i]);
        printf("\n");
 
        printf("%s iv:  ", enc ? "Encryption" : "Decryption");
                printf("%02x", (unsigned char)key[i]);
        printf("\n");
 
        printf("%s iv:  ", enc ? "Encryption" : "Decryption");
-       for (i = 0; i < HAMMER2_CRYPTO_IV_FIXED_SIZE; ++i)
+       for (i = 0; i < HAMMER2_CRYPTO_GCM_IV_FIXED_SIZE; ++i)
                printf("%02x", (unsigned char)iv_fixed[i]);
        printf(" (fixed part only)\n");
 
                printf("%02x", (unsigned char)iv_fixed[i]);
        printf(" (fixed part only)\n");
 
-
        EVP_CIPHER_CTX_init(&ioq->ctx);
 
        if (enc)
        EVP_CIPHER_CTX_init(&ioq->ctx);
 
        if (enc)
@@ -126,12 +146,12 @@ _gcm_init(hammer2_ioq_t *ioq, char *key, int klen, char *iv_fixed, int ivlen,
         * traffic.
         */
        ok = EVP_CIPHER_CTX_ctrl(&ioq->ctx, EVP_CTRL_GCM_SET_IVLEN,
         * traffic.
         */
        ok = EVP_CIPHER_CTX_ctrl(&ioq->ctx, EVP_CTRL_GCM_SET_IVLEN,
-                                HAMMER2_CRYPTO_IV_SIZE, NULL);
+                                HAMMER2_CRYPTO_GCM_IV_SIZE, NULL);
        if (!ok)
                goto fail;
 
        if (!ok)
                goto fail;
 
-       memset(ioq->iv, 0, HAMMER2_CRYPTO_IV_SIZE);
-       memcpy(ioq->iv, iv_fixed, HAMMER2_CRYPTO_IV_FIXED_SIZE);
+       memset(ioq->iv, 0, HAMMER2_CRYPTO_GCM_IV_SIZE);
+       memcpy(ioq->iv, iv_fixed, HAMMER2_CRYPTO_GCM_IV_FIXED_SIZE);
 
        /*
         * Strictly speaking, padding is irrelevant with a counter mode
 
        /*
         * Strictly speaking, padding is irrelevant with a counter mode
@@ -163,13 +183,9 @@ _gcm_iv_increment(char *iv)
         * unique to the session and a 64 bit integer counter.
         */
 
         * unique to the session and a 64 bit integer counter.
         */
 
-       uint64_t *c = (uint64_t *)(&iv[HAMMER2_CRYPTO_IV_FIXED_SIZE]);
+       uint64_t *c = (uint64_t *)(&iv[HAMMER2_CRYPTO_GCM_IV_FIXED_SIZE]);
 
        /* Increment invocation field integer counter */
 
        /* Increment invocation field integer counter */
-       /*
-        * XXX: this should ideally be an atomic update, but we don't have
-        * an atomic_fetchadd_64 for i386 yet
-        */
        *c = htobe64(be64toh(*c)+1);
 
        /*
        *c = htobe64(be64toh(*c)+1);
 
        /*
@@ -181,13 +197,10 @@ _gcm_iv_increment(char *iv)
 
 static
 int
 
 static
 int
-hammer2_crypto_encrypt_chunk(hammer2_ioq_t *ioq, char *ct, char *pt,
-                            int in_size, int *out_size)
+hammer2_crypto_gcm_encrypt_chunk(hammer2_ioq_t *ioq, char *ct, char *pt,
+                                int in_size, int *out_size)
 {
        int ok;
 {
        int ok;
-#ifdef CRYPTO_DEBUG
-       int i;
-#endif
        int u_len, f_len;
 
        *out_size = 0;
        int u_len, f_len;
 
        *out_size = 0;
@@ -207,40 +220,18 @@ hammer2_crypto_encrypt_chunk(hammer2_ioq_t *ioq, char *ct, char *pt,
 
        /* Retrieve auth tag */
        ok = EVP_CIPHER_CTX_ctrl(&ioq->ctx, EVP_CTRL_GCM_GET_TAG,
 
        /* Retrieve auth tag */
        ok = EVP_CIPHER_CTX_ctrl(&ioq->ctx, EVP_CTRL_GCM_GET_TAG,
-                                HAMMER2_CRYPTO_TAG_SIZE,
+                                HAMMER2_CRYPTO_GCM_TAG_SIZE,
                                 ct + u_len + f_len);
        if (!ok)
                goto fail;
 
                                 ct + u_len + f_len);
        if (!ok)
                goto fail;
 
-#ifdef CRYPTO_DEBUG
-       printf("enc_chunk iv: ");
-       for (i = 0; i < HAMMER2_CRYPTO_IV_SIZE; i++)
-               printf("%02x", (unsigned char)ioq->iv[i]);
-       printf("\n");
-
-       printf("enc_chunk pt: ");
-       for (i = 0; i < in_size; i++)
-               printf("%02x", (unsigned char)pt[i]);
-       printf("\n");
-
-       printf("enc_chunk ct: ");
-       for (i = 0; i < in_size; i++)
-               printf("%02x", (unsigned char)ct[i]);
-       printf("\n");
-
-       printf("enc_chunk tag: ");
-       for (i = 0; i < HAMMER2_CRYPTO_TAG_SIZE; i++)
-               printf("%02x", (unsigned char)ct[i + u_len + f_len]);
-       printf("\n");
-#endif
-
        ok = _gcm_iv_increment(ioq->iv);
        if (!ok) {
                ioq->error = HAMMER2_IOQ_ERROR_IVWRAP;
                goto fail_out;
        }
 
        ok = _gcm_iv_increment(ioq->iv);
        if (!ok) {
                ioq->error = HAMMER2_IOQ_ERROR_IVWRAP;
                goto fail_out;
        }
 
-       *out_size = u_len + f_len + HAMMER2_CRYPTO_TAG_SIZE;
+       *out_size = u_len + f_len + HAMMER2_CRYPTO_GCM_TAG_SIZE;
 
        return 0;
 
 
        return 0;
 
@@ -254,13 +245,10 @@ fail_out:
 
 static
 int
 
 static
 int
-hammer2_crypto_decrypt_chunk(hammer2_ioq_t *ioq, char *ct, char *pt,
-                            int out_size, int *consume_size)
+hammer2_crypto_gcm_decrypt_chunk(hammer2_ioq_t *ioq, char *ct, char *pt,
+                                int out_size, int *consume_size)
 {
        int ok;
 {
        int ok;
-#ifdef CRYPTO_DEBUG
-       int i;
-#endif
        int u_len, f_len;
 
        *consume_size = 0;
        int u_len, f_len;
 
        *consume_size = 0;
@@ -272,25 +260,8 @@ hammer2_crypto_decrypt_chunk(hammer2_ioq_t *ioq, char *ct, char *pt,
                goto fail_out;
        }
 
                goto fail_out;
        }
 
-#ifdef CRYPTO_DEBUG
-       printf("dec_chunk iv: ");
-       for (i = 0; i < HAMMER2_CRYPTO_IV_SIZE; i++)
-               printf("%02x", (unsigned char)ioq->iv[i]);
-       printf("\n");
-
-       printf("dec_chunk ct: ");
-       for (i = 0; i < out_size; i++)
-               printf("%02x", (unsigned char)ct[i]);
-       printf("\n");
-
-       printf("dec_chunk tag: ");
-       for (i = 0; i < HAMMER2_CRYPTO_TAG_SIZE; i++)
-               printf("%02x", (unsigned char)ct[out_size + i]);
-       printf("\n");
-#endif
-
        ok = EVP_CIPHER_CTX_ctrl(&ioq->ctx, EVP_CTRL_GCM_SET_TAG,
        ok = EVP_CIPHER_CTX_ctrl(&ioq->ctx, EVP_CTRL_GCM_SET_TAG,
-                                HAMMER2_CRYPTO_TAG_SIZE,
+                                HAMMER2_CRYPTO_GCM_TAG_SIZE,
                                 ct + out_size);
        if (!ok) {
                ioq->error = HAMMER2_IOQ_ERROR_ALGO;
                                 ct + out_size);
        if (!ok) {
                ioq->error = HAMMER2_IOQ_ERROR_ALGO;
@@ -311,14 +282,7 @@ hammer2_crypto_decrypt_chunk(hammer2_ioq_t *ioq, char *ct, char *pt,
                goto fail_out;
        }
 
                goto fail_out;
        }
 
-       *consume_size = u_len + f_len + HAMMER2_CRYPTO_TAG_SIZE;
-
-#ifdef CRYPTO_DEBUG
-       printf("dec_chunk pt: ");
-       for (i = 0; i < out_size; i++)
-               printf("%02x", (unsigned char)pt[i]);
-       printf("\n");
-#endif
+       *consume_size = u_len + f_len + HAMMER2_CRYPTO_GCM_TAG_SIZE;
 
        return 0;
 
 
        return 0;
 
@@ -669,21 +633,22 @@ keyxchgfail:
        if (n != 0)
                goto keyxchgfail;
 
        if (n != 0)
                goto keyxchgfail;
 
-       assert(HAMMER2_AES_KEY_SIZE * 2 == sizeof(handrx.sess));
        /*
         * Use separate session keys and session fixed IVs for receive and
         * transmit.
         */
        /*
         * Use separate session keys and session fixed IVs for receive and
         * transmit.
         */
-       error = _gcm_init(&iocom->ioq_rx, handrx.sess, HAMMER2_AES_KEY_SIZE,
-           handrx.sess + HAMMER2_AES_KEY_SIZE,
-           sizeof(handrx.sess) - HAMMER2_AES_KEY_SIZE,
+       error = crypto_algos[HAMMER2_CRYPTO_ALGO].init(&iocom->ioq_rx, handrx.sess,
+           crypto_algos[HAMMER2_CRYPTO_ALGO].keylen,
+           handrx.sess + crypto_algos[HAMMER2_CRYPTO_ALGO].keylen,
+           sizeof(handrx.sess) - crypto_algos[HAMMER2_CRYPTO_ALGO].keylen,
            0 /* decryption */);
        if (error)
                goto keyxchgfail;
 
            0 /* decryption */);
        if (error)
                goto keyxchgfail;
 
-       error = _gcm_init(&iocom->ioq_tx, handtx.sess, HAMMER2_AES_KEY_SIZE,
-           handtx.sess + HAMMER2_AES_KEY_SIZE,
-           sizeof(handtx.sess) - HAMMER2_AES_KEY_SIZE,
+       error = crypto_algos[HAMMER2_CRYPTO_ALGO].init(&iocom->ioq_tx, handtx.sess,
+           crypto_algos[HAMMER2_CRYPTO_ALGO].keylen,
+           handtx.sess + crypto_algos[HAMMER2_CRYPTO_ALGO].keylen,
+           sizeof(handtx.sess) - crypto_algos[HAMMER2_CRYPTO_ALGO].keylen,
            1 /* encryption */);
        if (error)
                goto keyxchgfail;
            1 /* encryption */);
        if (error)
                goto keyxchgfail;
@@ -723,13 +688,16 @@ hammer2_crypto_decrypt(hammer2_iocom_t *iocom __unused, hammer2_ioq_t *ioq)
        if (p_len == 0)
                return;
 
        if (p_len == 0)
                return;
 
-       while (p_len >= HAMMER2_CRYPTO_TAG_SIZE + HAMMER2_CRYPTO_CHUNK_SIZE) {
+       while (p_len >= crypto_algos[HAMMER2_CRYPTO_ALGO].taglen +
+           HAMMER2_CRYPTO_CHUNK_SIZE) {
                bcopy(ioq->buf + ioq->fifo_cdn, buf,
                bcopy(ioq->buf + ioq->fifo_cdn, buf,
-                     HAMMER2_CRYPTO_TAG_SIZE + HAMMER2_CRYPTO_CHUNK_SIZE);
-               error = hammer2_crypto_decrypt_chunk(ioq, buf,
-                                                    ioq->buf + ioq->fifo_cdx,
-                                                    HAMMER2_CRYPTO_CHUNK_SIZE,
-                                                    &used);
+                     crypto_algos[HAMMER2_CRYPTO_ALGO].taglen +
+                     HAMMER2_CRYPTO_CHUNK_SIZE);
+               error = crypto_algos[HAMMER2_CRYPTO_ALGO].dec_chunk(
+                   ioq, buf,
+                   ioq->buf + ioq->fifo_cdx,
+                   HAMMER2_CRYPTO_CHUNK_SIZE,
+                   &used);
 #ifdef CRYPTO_DEBUG
                printf("dec: p_len: %d, used: %d, fifo_cdn: %ju, fifo_cdx: %ju\n",
                       p_len, used, ioq->fifo_cdn, ioq->fifo_cdx);
 #ifdef CRYPTO_DEBUG
                printf("dec: p_len: %d, used: %d, fifo_cdn: %ju, fifo_cdx: %ju\n",
                       p_len, used, ioq->fifo_cdn, ioq->fifo_cdx);
@@ -763,11 +731,13 @@ hammer2_crypto_encrypt(hammer2_iocom_t *iocom __unused, hammer2_ioq_t *ioq,
        for (i = 0; i < n && nmax; ++i) {
                used = 0;
                p_len = iov[i].iov_len;
        for (i = 0; i < n && nmax; ++i) {
                used = 0;
                p_len = iov[i].iov_len;
-               assert((p_len & HAMMER2_AES_KEY_MASK) == 0);
+               assert((p_len & HAMMER2_MSG_ALIGNMASK) == 0);
 
                while (p_len >= HAMMER2_CRYPTO_CHUNK_SIZE &&
 
                while (p_len >= HAMMER2_CRYPTO_CHUNK_SIZE &&
-                   nmax >= HAMMER2_CRYPTO_CHUNK_SIZE + HAMMER2_CRYPTO_TAG_SIZE) {
-                       error = hammer2_crypto_encrypt_chunk(ioq,
+                   nmax >= HAMMER2_CRYPTO_CHUNK_SIZE +
+                   (size_t)crypto_algos[HAMMER2_CRYPTO_ALGO].taglen) {
+                       error = crypto_algos[HAMMER2_CRYPTO_ALGO].enc_chunk(
+                           ioq,
                            ioq->buf + ioq->fifo_cdx,
                            (char *)iov[i].iov_base + used,
                            HAMMER2_CRYPTO_CHUNK_SIZE, &ct_used);
                            ioq->buf + ioq->fifo_cdx,
                            (char *)iov[i].iov_base + used,
                            HAMMER2_CRYPTO_CHUNK_SIZE, &ct_used);
index 6b1b166..028f822 100644 (file)
@@ -84,18 +84,21 @@ struct hammer2_handshake {
 
 typedef struct hammer2_handshake hammer2_handshake_t;
 
 
 typedef struct hammer2_handshake hammer2_handshake_t;
 
-/*
- * NOTE: HAMMER2_MSG_ALIGN (64) must be a multiple of HAMMER2_AES_KEY_SIZE.
- */
-#define HAMMER2_AES_KEY_SIZE   32
-#define HAMMER2_AES_KEY_MASK   (HAMMER2_AES_KEY_SIZE - 1)
-#define HAMMER2_AES_TYPE       aes_256_cbc
-#define HAMMER2_AES_TYPE_EVP   EVP_aes_256_cbc()
-#define HAMMER2_AES_TYPE_STR   #HAMMER2_AES_TYPE
-#define HAMMER2_CRYPTO_IV_SIZE 12
-#define HAMMER2_CRYPTO_IV_FIXED_SIZE   4
-#define HAMMER2_CRYPTO_CHUNK_SIZE      64
-#define HAMMER2_CRYPTO_TAG_SIZE                16
+
+#define HAMMER2_CRYPTO_CHUNK_SIZE              HAMMER2_MSG_ALIGN
+#define HAMMER2_MAX_IV_SIZE                    32
+
+#define HAMMER2_CRYPTO_GCM_IV_FIXED_SIZE       4
+#define HAMMER2_CRYPTO_GCM_IV_SIZE             12
+#define HAMMER2_CRYPTO_GCM_KEY_SIZE            32
+#define HAMMER2_CRYPTO_GCM_TAG_SIZE            16
+
+#define HAMMER2_CRYPTO_ALGO_GCM_IDX            0
+
+#define HAMMER2_CRYPTO_ALGO                    HAMMER2_CRYPTO_ALGO_GCM_IDX
+
+
+
 
 /***************************************************************************
  *                             LOW LEVEL MESSAGING                        *
 
 /***************************************************************************
  *                             LOW LEVEL MESSAGING                        *
@@ -206,7 +209,7 @@ struct hammer2_ioq {
        int             seq;                    /* salt sequencer */
        int             msgcount;
        EVP_CIPHER_CTX  ctx;
        int             seq;                    /* salt sequencer */
        int             msgcount;
        EVP_CIPHER_CTX  ctx;
-       char            iv[HAMMER2_AES_KEY_SIZE]; /* encrypt or decrypt iv[] */
+       char            iv[HAMMER2_MAX_IV_SIZE]; /* encrypt or decrypt iv[] */
        hammer2_msg_t   *msg;
        hammer2_msg_queue_t msgq;
        char            buf[HAMMER2_MSGBUF_SIZE]; /* staging buffer */
        hammer2_msg_t   *msg;
        hammer2_msg_queue_t msgq;
        char            buf[HAMMER2_MSGBUF_SIZE]; /* staging buffer */
@@ -284,7 +287,6 @@ struct hammer2_iocom {
        int     flags;
        int     rxmisc;
        int     txmisc;
        int     flags;
        int     rxmisc;
        int     txmisc;
-       char    sess[HAMMER2_AES_KEY_SIZE];     /* aes_256_cbc key */
        struct hammer2_router *router;
        pthread_mutex_t mtx;                    /* mutex for state*tree/rmsgq */
 };
        struct hammer2_router *router;
        pthread_mutex_t mtx;                    /* mutex for state*tree/rmsgq */
 };
@@ -301,3 +303,26 @@ typedef struct hammer2_iocom hammer2_iocom_t;
 #define HAMMER2_IOCOMF_AWWORK  0x00000080      /* immediate work pending */
 #define HAMMER2_IOCOMF_SWORK   0x00000100      /* immediate work pending */
 #define HAMMER2_IOCOMF_CRYPTED 0x00000200      /* encrypt enabled */
 #define HAMMER2_IOCOMF_AWWORK  0x00000080      /* immediate work pending */
 #define HAMMER2_IOCOMF_SWORK   0x00000100      /* immediate work pending */
 #define HAMMER2_IOCOMF_CRYPTED 0x00000200      /* encrypt enabled */
+
+
+
+
+
+
+
+/*
+ * Crypto algorithm table and related typedefs.
+ */
+
+typedef int (*algo_init_fn)(hammer2_ioq_t *, char *, int, char *, int, int);
+typedef int (*algo_enc_fn)(hammer2_ioq_t *, char *, char *, int, int *);
+typedef int (*algo_dec_fn)(hammer2_ioq_t *, char *, char *, int, int *);
+
+struct crypto_algo {
+       const char      *name;
+       int             keylen;
+       int             taglen;
+       algo_init_fn    init;
+       algo_enc_fn     enc_chunk;
+       algo_dec_fn     dec_chunk;
+};