cryptodev: add auth IV
[dpdk.git] / examples / l2fwd-crypto / main.c
index 841ec6e..8da8dbd 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2015-2017 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -89,6 +89,10 @@ enum cdev_type {
 #define MAX_PKT_BURST 32
 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
 
+#define MAXIMUM_IV_LENGTH      16
+#define IV_OFFSET              (sizeof(struct rte_crypto_op) + \
+                               sizeof(struct rte_crypto_sym_op))
+
 /*
  * Configurable number of RX/TX ring descriptors
  */
@@ -135,6 +139,11 @@ struct l2fwd_key {
        phys_addr_t phys_addr;
 };
 
+struct l2fwd_iv {
+       uint8_t *data;
+       uint16_t length;
+};
+
 /** l2fwd crypto application command line options */
 struct l2fwd_crypto_options {
        unsigned portmask;
@@ -151,14 +160,18 @@ struct l2fwd_crypto_options {
        unsigned ckey_param;
        int ckey_random_size;
 
-       struct l2fwd_key iv;
-       unsigned iv_param;
-       int iv_random_size;
+       struct l2fwd_iv cipher_iv;
+       unsigned int cipher_iv_param;
+       int cipher_iv_random_size;
 
        struct rte_crypto_sym_xform auth_xform;
        uint8_t akey_param;
        int akey_random_size;
 
+       struct l2fwd_iv auth_iv;
+       unsigned int auth_iv_param;
+       int auth_iv_random_size;
+
        struct l2fwd_key aad;
        unsigned aad_param;
        int aad_random_size;
@@ -179,7 +192,8 @@ struct l2fwd_crypto_params {
        unsigned digest_length;
        unsigned block_size;
 
-       struct l2fwd_key iv;
+       struct l2fwd_iv cipher_iv;
+       struct l2fwd_iv auth_iv;
        struct l2fwd_key aad;
        struct rte_cryptodev_sym_session *session;
 
@@ -444,6 +458,18 @@ l2fwd_simple_crypto_enqueue(struct rte_mbuf *m,
        rte_crypto_op_attach_sym_session(op, cparams->session);
 
        if (cparams->do_hash) {
+               if (cparams->auth_iv.length) {
+                       uint8_t *iv_ptr = rte_crypto_op_ctod_offset(op,
+                                               uint8_t *,
+                                               IV_OFFSET +
+                                               cparams->cipher_iv.length);
+                       /*
+                        * Copy IV at the end of the crypto operation,
+                        * after the cipher IV, if added
+                        */
+                       rte_memcpy(iv_ptr, cparams->auth_iv.data,
+                                       cparams->auth_iv.length);
+               }
                if (!cparams->hash_verify) {
                        /* Append space for digest to end of packet */
                        op->sym->auth.digest.data = (uint8_t *)rte_pktmbuf_append(m,
@@ -480,9 +506,11 @@ l2fwd_simple_crypto_enqueue(struct rte_mbuf *m,
        }
 
        if (cparams->do_cipher) {
-               op->sym->cipher.iv.data = cparams->iv.data;
-               op->sym->cipher.iv.phys_addr = cparams->iv.phys_addr;
-               op->sym->cipher.iv.length = cparams->iv.length;
+               uint8_t *iv_ptr = rte_crypto_op_ctod_offset(op, uint8_t *,
+                                                       IV_OFFSET);
+               /* Copy IV at the end of the crypto operation */
+               rte_memcpy(iv_ptr, cparams->cipher_iv.data,
+                               cparams->cipher_iv.length);
 
                /* For wireless algorithms, offset/length must be in bits */
                if (cparams->cipher_algo == RTE_CRYPTO_CIPHER_SNOW3G_UEA2 ||
@@ -665,6 +693,18 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
                port_cparams[i].block_size = options->block_size;
 
                if (port_cparams[i].do_hash) {
+                       port_cparams[i].auth_iv.data = options->auth_iv.data;
+                       port_cparams[i].auth_iv.length = options->auth_iv.length;
+                       if (!options->auth_iv_param)
+                               generate_random_key(port_cparams[i].auth_iv.data,
+                                               port_cparams[i].auth_iv.length);
+                       /* Set IV parameters */
+                       if (options->auth_iv.length) {
+                               options->auth_xform.auth.iv.offset =
+                                       IV_OFFSET + options->cipher_iv.length;
+                               options->auth_xform.auth.iv.length =
+                                       options->auth_iv.length;
+                       }
                        port_cparams[i].digest_length =
                                        options->auth_xform.auth.digest_length;
                        if (options->auth_xform.auth.add_auth_data_length) {
@@ -688,14 +728,17 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
                }
 
                if (port_cparams[i].do_cipher) {
-                       port_cparams[i].iv.data = options->iv.data;
-                       port_cparams[i].iv.length = options->iv.length;
-                       port_cparams[i].iv.phys_addr = options->iv.phys_addr;
-                       if (!options->iv_param)
-                               generate_random_key(port_cparams[i].iv.data,
-                                               port_cparams[i].iv.length);
+                       port_cparams[i].cipher_iv.data = options->cipher_iv.data;
+                       port_cparams[i].cipher_iv.length = options->cipher_iv.length;
+                       if (!options->cipher_iv_param)
+                               generate_random_key(port_cparams[i].cipher_iv.data,
+                                               port_cparams[i].cipher_iv.length);
 
                        port_cparams[i].cipher_algo = options->cipher_xform.cipher.algo;
+                       /* Set IV parameters */
+                       options->cipher_xform.cipher.iv.offset = IV_OFFSET;
+                       options->cipher_xform.cipher.iv.length =
+                                               options->cipher_iv.length;
                }
 
                port_cparams[i].session = initialize_crypto_session(options,
@@ -849,13 +892,15 @@ l2fwd_crypto_usage(const char *prgname)
                "  --cipher_op ENCRYPT / DECRYPT\n"
                "  --cipher_key KEY (bytes separated with \":\")\n"
                "  --cipher_key_random_size SIZE: size of cipher key when generated randomly\n"
-               "  --iv IV (bytes separated with \":\")\n"
-               "  --iv_random_size SIZE: size of IV when generated randomly\n"
+               "  --cipher_iv IV (bytes separated with \":\")\n"
+               "  --cipher_iv_random_size SIZE: size of cipher IV when generated randomly\n"
 
                "  --auth_algo ALGO\n"
                "  --auth_op GENERATE / VERIFY\n"
                "  --auth_key KEY (bytes separated with \":\")\n"
                "  --auth_key_random_size SIZE: size of auth key when generated randomly\n"
+               "  --auth_iv IV (bytes separated with \":\")\n"
+               "  --auth_iv_random_size SIZE: size of auth IV when generated randomly\n"
                "  --aad AAD (bytes separated with \":\")\n"
                "  --aad_random_size SIZE: size of AAD when generated randomly\n"
                "  --digest_size SIZE: size of digest to be generated/verified\n"
@@ -1066,18 +1111,18 @@ l2fwd_crypto_parse_args_long_options(struct l2fwd_crypto_options *options,
        else if (strcmp(lgopts[option_index].name, "cipher_key_random_size") == 0)
                return parse_size(&options->ckey_random_size, optarg);
 
-       else if (strcmp(lgopts[option_index].name, "iv") == 0) {
-               options->iv_param = 1;
-               options->iv.length =
-                       parse_key(options->iv.data, optarg);
-               if (options->iv.length > 0)
+       else if (strcmp(lgopts[option_index].name, "cipher_iv") == 0) {
+               options->cipher_iv_param = 1;
+               options->cipher_iv.length =
+                       parse_key(options->cipher_iv.data, optarg);
+               if (options->cipher_iv.length > 0)
                        return 0;
                else
                        return -1;
        }
 
-       else if (strcmp(lgopts[option_index].name, "iv_random_size") == 0)
-               return parse_size(&options->iv_random_size, optarg);
+       else if (strcmp(lgopts[option_index].name, "cipher_iv_random_size") == 0)
+               return parse_size(&options->cipher_iv_random_size, optarg);
 
        /* Authentication options */
        else if (strcmp(lgopts[option_index].name, "auth_algo") == 0) {
@@ -1103,6 +1148,20 @@ l2fwd_crypto_parse_args_long_options(struct l2fwd_crypto_options *options,
                return parse_size(&options->akey_random_size, optarg);
        }
 
+
+       else if (strcmp(lgopts[option_index].name, "auth_iv") == 0) {
+               options->auth_iv_param = 1;
+               options->auth_iv.length =
+                       parse_key(options->auth_iv.data, optarg);
+               if (options->auth_iv.length > 0)
+                       return 0;
+               else
+                       return -1;
+       }
+
+       else if (strcmp(lgopts[option_index].name, "auth_iv_random_size") == 0)
+               return parse_size(&options->auth_iv_random_size, optarg);
+
        else if (strcmp(lgopts[option_index].name, "aad") == 0) {
                options->aad_param = 1;
                options->aad.length =
@@ -1221,9 +1280,9 @@ l2fwd_crypto_default_options(struct l2fwd_crypto_options *options)
        options->ckey_param = 0;
        options->ckey_random_size = -1;
        options->cipher_xform.cipher.key.length = 0;
-       options->iv_param = 0;
-       options->iv_random_size = -1;
-       options->iv.length = 0;
+       options->cipher_iv_param = 0;
+       options->cipher_iv_random_size = -1;
+       options->cipher_iv.length = 0;
 
        options->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_CBC;
        options->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
@@ -1234,6 +1293,9 @@ l2fwd_crypto_default_options(struct l2fwd_crypto_options *options)
        options->akey_param = 0;
        options->akey_random_size = -1;
        options->auth_xform.auth.key.length = 0;
+       options->auth_iv_param = 0;
+       options->auth_iv_random_size = -1;
+       options->auth_iv.length = 0;
        options->aad_param = 0;
        options->aad_random_size = -1;
        options->aad.length = 0;
@@ -1255,7 +1317,7 @@ display_cipher_info(struct l2fwd_crypto_options *options)
        rte_hexdump(stdout, "Cipher key:",
                        options->cipher_xform.cipher.key.data,
                        options->cipher_xform.cipher.key.length);
-       rte_hexdump(stdout, "IV:", options->iv.data, options->iv.length);
+       rte_hexdump(stdout, "IV:", options->cipher_iv.data, options->cipher_iv.length);
 }
 
 static void
@@ -1263,10 +1325,11 @@ display_auth_info(struct l2fwd_crypto_options *options)
 {
        printf("\n---- Authentication information ---\n");
        printf("Algorithm: %s\n",
-               rte_crypto_auth_algorithm_strings[options->auth_xform.cipher.algo]);
+               rte_crypto_auth_algorithm_strings[options->auth_xform.auth.algo]);
        rte_hexdump(stdout, "Auth key:",
                        options->auth_xform.auth.key.data,
                        options->auth_xform.auth.key.length);
+       rte_hexdump(stdout, "IV:", options->auth_iv.data, options->auth_iv.length);
        rte_hexdump(stdout, "AAD:", options->aad.data, options->aad.length);
 }
 
@@ -1304,8 +1367,11 @@ l2fwd_crypto_options_print(struct l2fwd_crypto_options *options)
        if (options->akey_param && (options->akey_random_size != -1))
                printf("Auth key already parsed, ignoring size of random key\n");
 
-       if (options->iv_param && (options->iv_random_size != -1))
-               printf("IV already parsed, ignoring size of random IV\n");
+       if (options->cipher_iv_param && (options->cipher_iv_random_size != -1))
+               printf("Cipher IV already parsed, ignoring size of random IV\n");
+
+       if (options->auth_iv_param && (options->auth_iv_random_size != -1))
+               printf("Auth IV already parsed, ignoring size of random IV\n");
 
        if (options->aad_param && (options->aad_random_size != -1))
                printf("AAD already parsed, ignoring size of random AAD\n");
@@ -1353,14 +1419,16 @@ l2fwd_crypto_parse_args(struct l2fwd_crypto_options *options,
                        { "cipher_op", required_argument, 0, 0 },
                        { "cipher_key", required_argument, 0, 0 },
                        { "cipher_key_random_size", required_argument, 0, 0 },
+                       { "cipher_iv", required_argument, 0, 0 },
+                       { "cipher_iv_random_size", required_argument, 0, 0 },
 
                        { "auth_algo", required_argument, 0, 0 },
                        { "auth_op", required_argument, 0, 0 },
                        { "auth_key", required_argument, 0, 0 },
                        { "auth_key_random_size", required_argument, 0, 0 },
+                       { "auth_iv", required_argument, 0, 0 },
+                       { "auth_iv_random_size", required_argument, 0, 0 },
 
-                       { "iv", required_argument, 0, 0 },
-                       { "iv_random_size", required_argument, 0, 0 },
                        { "aad", required_argument, 0, 0 },
                        { "aad_random_size", required_argument, 0, 0 },
                        { "digest_size", required_argument, 0, 0 },
@@ -1540,6 +1608,46 @@ check_supported_size(uint16_t length, uint16_t min, uint16_t max,
 
        return -1;
 }
+
+static int
+check_iv_param(const struct rte_crypto_param_range *iv_range_size,
+               unsigned int iv_param, int iv_random_size,
+               uint16_t *iv_length)
+{
+       /*
+        * Check if length of provided IV is supported
+        * by the algorithm chosen.
+        */
+       if (iv_param) {
+               if (check_supported_size(*iv_length,
+                               iv_range_size->min,
+                               iv_range_size->max,
+                               iv_range_size->increment)
+                                       != 0) {
+                       printf("Unsupported IV length\n");
+                       return -1;
+               }
+       /*
+        * Check if length of IV to be randomly generated
+        * is supported by the algorithm chosen.
+        */
+       } else if (iv_random_size != -1) {
+               if (check_supported_size(iv_random_size,
+                               iv_range_size->min,
+                               iv_range_size->max,
+                               iv_range_size->increment)
+                                       != 0) {
+                       printf("Unsupported IV length\n");
+                       return -1;
+               }
+               *iv_length = iv_random_size;
+       /* No size provided, use minimum size. */
+       } else
+               *iv_length = iv_range_size->min;
+
+       return 0;
+}
+
 static int
 initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
                uint8_t *enabled_cdevs)
@@ -1607,36 +1715,11 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
                        }
 
                        options->block_size = cap->sym.cipher.block_size;
-                       /*
-                        * Check if length of provided IV is supported
-                        * by the algorithm chosen.
-                        */
-                       if (options->iv_param) {
-                               if (check_supported_size(options->iv.length,
-                                               cap->sym.cipher.iv_size.min,
-                                               cap->sym.cipher.iv_size.max,
-                                               cap->sym.cipher.iv_size.increment)
-                                                       != 0) {
-                                       printf("Unsupported IV length\n");
-                                       return -1;
-                               }
-                       /*
-                        * Check if length of IV to be randomly generated
-                        * is supported by the algorithm chosen.
-                        */
-                       } else if (options->iv_random_size != -1) {
-                               if (check_supported_size(options->iv_random_size,
-                                               cap->sym.cipher.iv_size.min,
-                                               cap->sym.cipher.iv_size.max,
-                                               cap->sym.cipher.iv_size.increment)
-                                                       != 0) {
-                                       printf("Unsupported IV length\n");
-                                       return -1;
-                               }
-                               options->iv.length = options->iv_random_size;
-                       /* No size provided, use minimum size. */
-                       } else
-                               options->iv.length = cap->sym.cipher.iv_size.min;
+
+                       check_iv_param(&cap->sym.cipher.iv_size,
+                                       options->cipher_iv_param,
+                                       options->cipher_iv_random_size,
+                                       &options->cipher_iv.length);
 
                        /*
                         * Check if length of provided cipher key is supported
@@ -1706,6 +1789,10 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
                                continue;
                        }
 
+                       check_iv_param(&cap->sym.auth.iv_size,
+                                       options->auth_iv_param,
+                                       options->auth_iv_random_size,
+                                       &options->auth_iv.length);
                        /*
                         * Check if length of provided AAD is supported
                         * by the algorithm chosen.
@@ -1947,10 +2034,13 @@ reserve_key_memory(struct l2fwd_crypto_options *options)
        if (options->auth_xform.auth.key.data == NULL)
                rte_exit(EXIT_FAILURE, "Failed to allocate memory for auth key");
 
-       options->iv.data = rte_malloc("iv", MAX_KEY_SIZE, 0);
-       if (options->iv.data == NULL)
-               rte_exit(EXIT_FAILURE, "Failed to allocate memory for IV");
-       options->iv.phys_addr = rte_malloc_virt2phy(options->iv.data);
+       options->cipher_iv.data = rte_malloc("cipher iv", MAX_KEY_SIZE, 0);
+       if (options->cipher_iv.data == NULL)
+               rte_exit(EXIT_FAILURE, "Failed to allocate memory for cipher IV");
+
+       options->auth_iv.data = rte_malloc("auth iv", MAX_KEY_SIZE, 0);
+       if (options->auth_iv.data == NULL)
+               rte_exit(EXIT_FAILURE, "Failed to allocate memory for auth IV");
 
        options->aad.data = rte_malloc("aad", MAX_KEY_SIZE, 0);
        if (options->aad.data == NULL)
@@ -1993,7 +2083,7 @@ main(int argc, char **argv)
 
        /* create crypto op pool */
        l2fwd_crypto_op_pool = rte_crypto_op_pool_create("crypto_op_pool",
-                       RTE_CRYPTO_OP_TYPE_SYMMETRIC, NB_MBUF, 128, 0,
+                       RTE_CRYPTO_OP_TYPE_SYMMETRIC, NB_MBUF, 128, MAXIMUM_IV_LENGTH,
                        rte_socket_id());
        if (l2fwd_crypto_op_pool == NULL)
                rte_exit(EXIT_FAILURE, "Cannot create crypto op pool\n");