[dpdk-dev] [PATCH v4] crypto/openssl: add DES DOCSIS BPI support

Pablo de Lara pablo.de.lara.guarch at intel.com
Thu Mar 30 19:27:22 CEST 2017


Adds support in OpenSSL PMD for algorithm following the DOCSIS
specification, which combines DES-CBC for full DES blocks (8 bytes)
and DES-CFB for last runt block (less than 8 bytes).

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch at intel.com>
Acked-by: Deepak Kumar Jain <deepak.k.jain at intel.com>
Tested-by: Yang Gang <gangx.yang at intel.com>
---

Changes in v4:
- Updated release notes

Changes in v3:
- Rebased against dpdk-next-crypto latest code
- Fixed commit message (missing PMD word)
- Optimized code, using ECB XOR IV combination, instead of CFB,
  avoiding an extra crypto initialization

Changes in v2:
- Added patch dependency note
- Fixed the commit message

 doc/guides/cryptodevs/features/openssl.ini       |  18 +--
 doc/guides/cryptodevs/openssl.rst                |   1 +
 doc/guides/rel_notes/release_17_05.rst           |   6 +
 drivers/crypto/openssl/rte_openssl_pmd.c         | 137 +++++++++++++++++++++++
 drivers/crypto/openssl/rte_openssl_pmd_ops.c     |  20 ++++
 drivers/crypto/openssl/rte_openssl_pmd_private.h |   2 +
 test/test/test_cryptodev.c                       |  18 +++
 test/test/test_cryptodev_blockcipher.c           |   5 +
 test/test/test_cryptodev_blockcipher.h           |   3 +-
 test/test/test_cryptodev_des_test_vectors.h      | 137 +++++++++++++++++++++++
 10 files changed, 337 insertions(+), 10 deletions(-)

diff --git a/doc/guides/cryptodevs/features/openssl.ini b/doc/guides/cryptodevs/features/openssl.ini
index 189b71b..aeb2a50 100644
--- a/doc/guides/cryptodevs/features/openssl.ini
+++ b/doc/guides/cryptodevs/features/openssl.ini
@@ -11,15 +11,15 @@ Sym operation chaining = Y
 ; Supported crypto algorithms of the 'openssl' crypto driver.
 ;
 [Cipher]
-AES CBC (128) = Y
-AES CBC (192) = Y
-AES CBC (256) = Y
-AES CTR (128) = Y
-AES CTR (192) = Y
-AES CTR (256) = Y
-3DES CBC      = Y
-3DES CTR      = Y
-
+AES CBC (128)  = Y
+AES CBC (192)  = Y
+AES CBC (256)  = Y
+AES CTR (128)  = Y
+AES CTR (192)  = Y
+AES CTR (256)  = Y
+3DES CBC       = Y
+3DES CTR       = Y
+DES DOCSIS BPI = Y
 ;
 ; Supported authentication algorithms of the 'openssl' crypto driver.
 ;
diff --git a/doc/guides/cryptodevs/openssl.rst b/doc/guides/cryptodevs/openssl.rst
index 3a28c9d..e341915 100644
--- a/doc/guides/cryptodevs/openssl.rst
+++ b/doc/guides/cryptodevs/openssl.rst
@@ -49,6 +49,7 @@ Supported cipher algorithms:
 * ``RTE_CRYPTO_CIPHER_AES_CTR``
 * ``RTE_CRYPTO_CIPHER_3DES_CTR``
 * ``RTE_CRYPTO_CIPHER_AES_GCM``
+* ``RTE_CRYPTO_CIPHER_DES_DOCSISBPI``
 
 Supported authentication algorithms:
 * ``RTE_CRYPTO_AUTH_AES_GMAC``
diff --git a/doc/guides/rel_notes/release_17_05.rst b/doc/guides/rel_notes/release_17_05.rst
index 7623786..fc24931 100644
--- a/doc/guides/rel_notes/release_17_05.rst
+++ b/doc/guides/rel_notes/release_17_05.rst
@@ -74,6 +74,12 @@ New Features
 
   * AES DOCSIS BPI algorithm.
 
+* **Updated the OpenSSL PMD.**
+
+  The OpenSSL PMD has been updated with additional support for:
+
+  * DES DOCSIS BPI algorithm.
+
 Resolved Issues
 ---------------
 
diff --git a/drivers/crypto/openssl/rte_openssl_pmd.c b/drivers/crypto/openssl/rte_openssl_pmd.c
index 09173b2..5046eac 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd.c
@@ -42,6 +42,8 @@
 
 #include "rte_openssl_pmd_private.h"
 
+#define DES_BLOCK_SIZE 8
+
 static int cryptodev_openssl_remove(const char *name);
 
 /*----------------------------------------------------------------------------*/
@@ -289,7 +291,21 @@ openssl_set_session_cipher_parameters(struct openssl_session *sess,
 				sess->cipher.key.data) != 0)
 			return -EINVAL;
 		break;
+	case RTE_CRYPTO_CIPHER_DES_DOCSISBPI:
+		sess->cipher.algo = xform->cipher.algo;
+		sess->chain_order = OPENSSL_CHAIN_CIPHER_BPI;
+		sess->cipher.ctx = EVP_CIPHER_CTX_new();
+		sess->cipher.evp_algo = EVP_des_cbc();
 
+		sess->cipher.bpi_ctx = EVP_CIPHER_CTX_new();
+		/* IV will be ECB encrypted whether direction is encrypt or decrypt */
+		if (EVP_EncryptInit_ex(sess->cipher.bpi_ctx, EVP_des_ecb(),
+				NULL, xform->cipher.key.data, 0) != 1)
+			return -EINVAL;
+
+		get_cipher_key(xform->cipher.key.data, sess->cipher.key.length,
+			sess->cipher.key.data);
+		break;
 	default:
 		sess->cipher.algo = RTE_CRYPTO_CIPHER_NULL;
 		return -EINVAL;
@@ -407,6 +423,9 @@ openssl_reset_session(struct openssl_session *sess)
 {
 	EVP_CIPHER_CTX_free(sess->cipher.ctx);
 
+	if (sess->chain_order == OPENSSL_CHAIN_CIPHER_BPI)
+		EVP_CIPHER_CTX_free(sess->cipher.bpi_ctx);
+
 	switch (sess->auth.mode) {
 	case OPENSSL_AUTH_AS_AUTH:
 		EVP_MD_CTX_destroy(sess->auth.auth.ctx);
@@ -577,6 +596,29 @@ process_openssl_cipher_encrypt(struct rte_mbuf *mbuf_src, uint8_t *dst,
 	return -EINVAL;
 }
 
+/** Process standard openssl cipher encryption */
+static int
+process_openssl_cipher_bpi_encrypt(uint8_t *src, uint8_t *dst,
+		uint8_t *iv, int srclen,
+		EVP_CIPHER_CTX *ctx)
+{
+	uint8_t i;
+	uint8_t encrypted_iv[DES_BLOCK_SIZE];
+	int encrypted_ivlen;
+
+	if (EVP_EncryptUpdate(ctx, encrypted_iv, &encrypted_ivlen,
+			iv, DES_BLOCK_SIZE) <= 0)
+		goto process_cipher_encrypt_err;
+
+	for (i = 0; i < srclen; i++)
+		*(dst + i) = *(src + i) ^ (encrypted_iv[i]);
+
+	return 0;
+
+process_cipher_encrypt_err:
+	OPENSSL_LOG_ERR("Process openssl cipher bpi encrypt failed");
+	return -EINVAL;
+}
 /** Process standard openssl cipher decryption */
 static int
 process_openssl_cipher_decrypt(struct rte_mbuf *mbuf_src, uint8_t *dst,
@@ -969,6 +1011,98 @@ process_openssl_cipher_op
 		op->status = RTE_CRYPTO_OP_STATUS_ERROR;
 }
 
+/** Process cipher operation */
+static void
+process_openssl_docsis_bpi_op(struct rte_crypto_op *op,
+		struct openssl_session *sess, struct rte_mbuf *mbuf_src,
+		struct rte_mbuf *mbuf_dst)
+{
+	uint8_t *src, *dst, *iv;
+	uint8_t block_size, last_block_len;
+	int srclen, status = 0;
+
+	srclen = op->sym->cipher.data.length;
+	src = rte_pktmbuf_mtod_offset(mbuf_src, uint8_t *,
+			op->sym->cipher.data.offset);
+	dst = rte_pktmbuf_mtod_offset(mbuf_dst, uint8_t *,
+			op->sym->cipher.data.offset);
+
+	iv = op->sym->cipher.iv.data;
+
+	block_size = DES_BLOCK_SIZE;
+
+	last_block_len = srclen % block_size;
+	if (sess->cipher.direction == RTE_CRYPTO_CIPHER_OP_ENCRYPT) {
+		/* Encrypt only with ECB mode XOR IV */
+		if (srclen < block_size) {
+			status = process_openssl_cipher_bpi_encrypt(src, dst,
+					iv, srclen,
+					sess->cipher.bpi_ctx);
+		} else {
+			srclen -= last_block_len;
+			/* Encrypt with the block aligned stream with CBC mode */
+			status = process_openssl_cipher_encrypt(mbuf_src, dst,
+					op->sym->cipher.data.offset, iv,
+					sess->cipher.key.data, srclen,
+					sess->cipher.ctx, sess->cipher.evp_algo);
+			if (last_block_len) {
+				/* Point at last block */
+				dst += srclen;
+				/*
+				 * IV is the last encrypted block from
+				 * the previous operation
+				 */
+				iv = dst - block_size;
+				src += srclen;
+				srclen = last_block_len;
+				/* Encrypt the last frame with ECB mode */
+				status |= process_openssl_cipher_bpi_encrypt(src,
+						dst, iv,
+						srclen, sess->cipher.bpi_ctx);
+			}
+		}
+	} else {
+		/* Decrypt only with ECB mode (encrypt, as it is same operation) */
+		if (srclen < block_size) {
+			status = process_openssl_cipher_bpi_encrypt(src, dst,
+					iv,
+					srclen,
+					sess->cipher.bpi_ctx);
+		} else {
+			if (last_block_len) {
+				/* Point at last block */
+				dst += srclen - last_block_len;
+				src += srclen - last_block_len;
+				/*
+				 * IV is the last full block
+				 */
+				iv = src - block_size;
+				/*
+				 * Decrypt the last frame with ECB mode
+				 * (encrypt, as it is the same operation)
+				 */
+				status = process_openssl_cipher_bpi_encrypt(src,
+						dst, iv,
+						last_block_len, sess->cipher.bpi_ctx);
+				/* Prepare parameters for CBC mode op */
+				iv = op->sym->cipher.iv.data;
+				dst += last_block_len - srclen;
+				srclen -= last_block_len;
+			}
+
+			/* Decrypt with CBC mode */
+			status |= process_openssl_cipher_decrypt(mbuf_src, dst,
+					op->sym->cipher.data.offset, iv,
+					sess->cipher.key.data, srclen,
+					sess->cipher.ctx,
+					sess->cipher.evp_algo);
+		}
+	}
+
+	if (status != 0)
+		op->status = RTE_CRYPTO_OP_STATUS_ERROR;
+}
+
 /** Process auth operation */
 static void
 process_openssl_auth_op
@@ -1052,6 +1186,9 @@ process_op(const struct openssl_qp *qp, struct rte_crypto_op *op,
 	case OPENSSL_CHAIN_COMBINED:
 		process_openssl_combined_op(op, sess, msrc, mdst);
 		break;
+	case OPENSSL_CHAIN_CIPHER_BPI:
+		process_openssl_docsis_bpi_op(op, sess, msrc, mdst);
+		break;
 	default:
 		op->status = RTE_CRYPTO_OP_STATUS_ERROR;
 		break;
diff --git a/drivers/crypto/openssl/rte_openssl_pmd_ops.c b/drivers/crypto/openssl/rte_openssl_pmd_ops.c
index 131a37c..25d1a4b 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd_ops.c
+++ b/drivers/crypto/openssl/rte_openssl_pmd_ops.c
@@ -442,6 +442,26 @@ static const struct rte_cryptodev_capabilities openssl_pmd_capabilities[] = {
 			}, }
 		}, }
 	},
+	{	/* DES DOCSIS BPI */
+		.op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+		{.sym = {
+			.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+			{.cipher = {
+				.algo = RTE_CRYPTO_CIPHER_DES_DOCSISBPI,
+				.block_size = 8,
+				.key_size = {
+					.min = 8,
+					.max = 8,
+					.increment = 0
+				},
+				.iv_size = {
+					.min = 8,
+					.max = 8,
+					.increment = 0
+				}
+			}, }
+		}, }
+	},
 
 	RTE_CRYPTODEV_END_OF_CAPABILITIES_LIST()
 };
diff --git a/drivers/crypto/openssl/rte_openssl_pmd_private.h b/drivers/crypto/openssl/rte_openssl_pmd_private.h
index 65c5f97..4d820c5 100644
--- a/drivers/crypto/openssl/rte_openssl_pmd_private.h
+++ b/drivers/crypto/openssl/rte_openssl_pmd_private.h
@@ -62,6 +62,7 @@
 enum openssl_chain_order {
 	OPENSSL_CHAIN_ONLY_CIPHER,
 	OPENSSL_CHAIN_ONLY_AUTH,
+	OPENSSL_CHAIN_CIPHER_BPI,
 	OPENSSL_CHAIN_CIPHER_AUTH,
 	OPENSSL_CHAIN_AUTH_CIPHER,
 	OPENSSL_CHAIN_COMBINED,
@@ -127,6 +128,7 @@ struct openssl_session {
 		/**< pointer to EVP algorithm function */
 		EVP_CIPHER_CTX *ctx;
 		/**< pointer to EVP context structure */
+		EVP_CIPHER_CTX *bpi_ctx;
 	} cipher;
 
 	/** Authentication Parameters */
diff --git a/test/test/test_cryptodev.c b/test/test/test_cryptodev.c
index 493518d..a7218f4 100644
--- a/test/test/test_cryptodev.c
+++ b/test/test/test_cryptodev.c
@@ -4349,6 +4349,22 @@ test_DES_cipheronly_qat_all(void)
 }
 
 static int
+test_DES_docsis_openssl_all(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	int status;
+
+	status = test_blockcipher_all_tests(ts_params->mbuf_pool,
+		ts_params->op_mpool, ts_params->valid_devs[0],
+		RTE_CRYPTODEV_OPENSSL_PMD,
+		BLKCIPHER_DES_DOCSIS_TYPE);
+
+	TEST_ASSERT_EQUAL(status, 0, "Test failed");
+
+	return TEST_SUCCESS;
+}
+
+static int
 test_3DES_cipheronly_qat_all(void)
 {
 	struct crypto_testsuite_params *ts_params = &testsuite_params;
@@ -7713,6 +7729,8 @@ static struct unit_test_suite cryptodev_openssl_testsuite  = {
 		TEST_CASE_ST(ut_setup, ut_teardown,
 				test_3DES_cipheronly_openssl_all),
 		TEST_CASE_ST(ut_setup, ut_teardown,
+				test_DES_docsis_openssl_all),
+		TEST_CASE_ST(ut_setup, ut_teardown,
 				test_authonly_openssl_all),
 
 		/** AES GCM Authenticated Encryption */
diff --git a/test/test/test_cryptodev_blockcipher.c b/test/test/test_cryptodev_blockcipher.c
index 9d39b7d..9d6ebd6 100644
--- a/test/test/test_cryptodev_blockcipher.c
+++ b/test/test/test_cryptodev_blockcipher.c
@@ -633,6 +633,11 @@ test_blockcipher_all_tests(struct rte_mempool *mbuf_pool,
 		sizeof(des_cipheronly_test_cases[0]);
 		tcs = des_cipheronly_test_cases;
 		break;
+	case BLKCIPHER_DES_DOCSIS_TYPE:
+		n_test_cases = sizeof(des_docsis_test_cases) /
+		sizeof(des_docsis_test_cases[0]);
+		tcs = des_docsis_test_cases;
+		break;
 	case BLKCIPHER_AUTHONLY_TYPE:
 		n_test_cases = sizeof(hash_test_cases) /
 		sizeof(hash_test_cases[0]);
diff --git a/test/test/test_cryptodev_blockcipher.h b/test/test/test_cryptodev_blockcipher.h
index 6e37121..389558a 100644
--- a/test/test/test_cryptodev_blockcipher.h
+++ b/test/test/test_cryptodev_blockcipher.h
@@ -72,7 +72,8 @@ enum blockcipher_test_type {
 	BLKCIPHER_3DES_CHAIN_TYPE,	/* use triple_des_chain_test_cases[] */
 	BLKCIPHER_3DES_CIPHERONLY_TYPE,	/* triple_des_cipheronly_test_cases[] */
 	BLKCIPHER_AUTHONLY_TYPE,	/* use hash_test_cases[] */
-	BLKCIPHER_DES_CIPHERONLY_TYPE	/* use des_cipheronly_test_cases[] */
+	BLKCIPHER_DES_CIPHERONLY_TYPE,	/* use des_cipheronly_test_cases[] */
+	BLKCIPHER_DES_DOCSIS_TYPE	/* use des_docsis_test_cases[] */
 };
 
 struct blockcipher_test_case {
diff --git a/test/test/test_cryptodev_des_test_vectors.h b/test/test/test_cryptodev_des_test_vectors.h
index 388d87e..b29a49e 100644
--- a/test/test/test_cryptodev_des_test_vectors.h
+++ b/test/test/test_cryptodev_des_test_vectors.h
@@ -862,6 +862,143 @@ static const struct blockcipher_test_case des_cipheronly_test_cases[] = {
 
 };
 
+/* DES-DOCSIS-BPI test vectors */
+
+static const uint8_t plaintext_des_docsis_bpi_cfb[] = {
+	0x00, 0x01, 0x02, 0x88, 0xEE, 0x59, 0x7E
+};
+
+static const uint8_t ciphertext_des_docsis_bpi_cfb[] = {
+	0x17, 0x86, 0xA8, 0x03, 0xA0, 0x85, 0x75
+};
+
+static const uint8_t plaintext_des_docsis_bpi_cbc_cfb[] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x91,
+	0xD2, 0xD1, 0x9F
+};
+
+static const uint8_t ciphertext_des_docsis_bpi_cbc_cfb[] = {
+	0x0D, 0xDA, 0x5A, 0xCB, 0xD0, 0x5E, 0x55, 0x67,
+	0x51, 0x47, 0x46, 0x86, 0x8A, 0x71, 0xE5, 0x77,
+	0xEF, 0xAC, 0x88
+};
+
+/* Multiple of DES block size */
+static const struct blockcipher_test_data des_test_data_1 = {
+	.crypto_algo = RTE_CRYPTO_CIPHER_DES_DOCSISBPI,
+	.cipher_key = {
+		.data = {
+			0xE4, 0x23, 0x33, 0x8A, 0x35, 0x64, 0x61, 0xE2
+		},
+		.len = 8
+	},
+	.iv = {
+		.data = {
+			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
+		},
+		.len = 8
+	},
+	.plaintext = {
+		.data = plaintext_des,
+		.len = 512
+	},
+	.ciphertext = {
+		.data = ciphertext512_des,
+		.len = 512
+	},
+};
+
+/* Less than DES block size */
+static const struct blockcipher_test_data des_test_data_2 = {
+	.crypto_algo = RTE_CRYPTO_CIPHER_DES_DOCSISBPI,
+	.cipher_key = {
+		.data = {
+
+			0xE6, 0x60, 0x0F, 0xD8, 0x85, 0x2E, 0xF5, 0xAB
+		},
+		.len = 8
+	},
+	.iv = {
+		.data = {
+			0x81, 0x0E, 0x52, 0x8E, 0x1C, 0x5F, 0xDA, 0x1A
+		},
+		.len = 8
+	},
+	.plaintext = {
+		.data = plaintext_des_docsis_bpi_cfb,
+		.len = 7
+	},
+	.ciphertext = {
+		.data = ciphertext_des_docsis_bpi_cfb,
+		.len = 7
+	}
+};
+
+/* Not multiple of DES block size */
+static const struct blockcipher_test_data des_test_data_3 = {
+	.crypto_algo = RTE_CRYPTO_CIPHER_DES_DOCSISBPI,
+	.cipher_key = {
+		.data = {
+			0xE6, 0x60, 0x0F, 0xD8, 0x85, 0x2E, 0xF5, 0xAB
+		},
+		.len = 8
+	},
+	.iv = {
+		.data = {
+			0x81, 0x0E, 0x52, 0x8E, 0x1C, 0x5F, 0xDA, 0x1A
+		},
+		.len = 8
+	},
+	.plaintext = {
+		.data = plaintext_des_docsis_bpi_cbc_cfb,
+		.len = 19
+	},
+	.ciphertext = {
+		.data = ciphertext_des_docsis_bpi_cbc_cfb,
+		.len = 19
+	}
+};
+static const struct blockcipher_test_case des_docsis_test_cases[] = {
+	{
+		.test_descr = "DES-DOCSIS-BPI Full Block Encryption",
+		.test_data = &des_test_data_1,
+		.op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT,
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+	},
+	{
+		.test_descr = "DES-DOCSIS-BPI Runt Block Encryption",
+		.test_data = &des_test_data_2,
+		.op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT,
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+	},
+	{
+		.test_descr = "DES-DOCSIS-BPI Uneven Encryption",
+		.test_data = &des_test_data_3,
+		.op_mask = BLOCKCIPHER_TEST_OP_ENCRYPT,
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+	},
+	{
+		.test_descr = "DES-DOCSIS-BPI Full Block Decryption",
+		.test_data = &des_test_data_1,
+		.op_mask = BLOCKCIPHER_TEST_OP_DECRYPT,
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+	},
+	{
+		.test_descr = "DES-DOCSIS-BPI Runt Block Decryption",
+		.test_data = &des_test_data_2,
+		.op_mask = BLOCKCIPHER_TEST_OP_DECRYPT,
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+	},
+	{
+		.test_descr = "DES-DOCSIS-BPI Uneven Decryption",
+		.test_data = &des_test_data_3,
+		.op_mask = BLOCKCIPHER_TEST_OP_DECRYPT,
+		.pmd_mask = BLOCKCIPHER_TEST_TARGET_PMD_OPENSSL
+	}
+
+};
+
 static const struct blockcipher_test_case triple_des_chain_test_cases[] = {
 	{
 		.test_descr = "3DES-128-CBC HMAC-SHA1 Encryption Digest",
-- 
2.7.4



More information about the dev mailing list