3721 words
19 minutes
dpdk-do-crypto
dpdk执行对称加解密aes-256-cbc
代码
#include <assert.h>#include <rte_config.h>#include <stdbool.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>
#include <rte_crypto.h>#include <rte_crypto_sym.h>#include <rte_cryptodev.h>#include <rte_eal.h>#include <rte_lcore.h>#include <rte_mbuf.h>#include <rte_mbuf_core.h>#include <rte_mempool.h>
#define CRYPTO_OP_POOL_NAME "crypto_op_pool"#define MBUF_POOL_NAME "data_mbuf_pool"#define SESS_POOL_NAME "sym_sess_pool"#define MBUFS_PER_POOL 2048#define CRYPTO_OPS_PER_POOL 2048#define SESS_PER_POOL 2048
#define MBUF_SIZE 16384
#define AES_KEY_SIZE 32 // 256 bits#define IV_SIZE 16 // 128 bits#define BLOCK_SIZE 16 // AES block size#define MAX_SESSIONS 10#define PMD_NAME "crypto_openssl"
static struct rte_mempool *crypto_op_pool = NULL;static struct rte_mempool *mbuf_pool = NULL;static struct rte_mempool *sess_pool = NULL;
static uint8_t aes_key[AES_KEY_SIZE] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f};static uint8_t iv_data[IV_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
int setup_cryptodev() { uint8_t cdev_ids[64] = {0}; int num_cdevs = rte_cryptodev_devices_get(PMD_NAME, cdev_ids, 64); assert(num_cdevs > 0 && "no cdev " PMD_NAME " found!"); uint8_t cdev_id = cdev_ids[0]; struct rte_cryptodev_config config = { .nb_queue_pairs = 1, .socket_id = rte_socket_id(), }; if (rte_cryptodev_configure(cdev_id, &config) < 0) { fprintf(stderr, "failed to configure crypto dev %u\n", cdev_id); return -1; }
struct rte_cryptodev_qp_conf qp_conf = { .nb_descriptors = 2048, }; if (rte_cryptodev_queue_pair_setup(cdev_id, 0, &qp_conf, rte_socket_id()) < 0) { fprintf(stderr, "failed to setup queue pair 0 on device %u\n", cdev_id); return -1; }
if (rte_cryptodev_start(cdev_id) < 0) { fprintf(stderr, "failed to start crypto dev %u\b", cdev_id); return -1; } return cdev_id;}
struct rte_crypto_sym_session *create_sym_encrypt_session(uint8_t cdev_id) { struct rte_crypto_cipher_xform cipher = { .algo = RTE_CRYPTO_CIPHER_AES_CBC, .op = RTE_CRYPTO_CIPHER_OP_ENCRYPT, .key.length = AES_KEY_SIZE, .key.data = aes_key, .iv.length = IV_SIZE, .iv.offset = sizeof(struct rte_crypto_op) + sizeof(struct rte_crypto_sym_op), };
struct rte_crypto_sym_xform xform = { .next = NULL, .type = RTE_CRYPTO_SYM_XFORM_CIPHER, .cipher = cipher, };
struct rte_crypto_sym_session *sess = rte_cryptodev_sym_session_create(cdev_id, &xform, sess_pool); if (!sess) { fprintf(stderr, "failed to create encrypt session for cdev :%u\n", cdev_id); return NULL; } return sess;}
struct rte_crypto_sym_session *create_sym_decrypt_session(uint8_t cdev_id) { struct rte_crypto_cipher_xform cipher = { .algo = RTE_CRYPTO_CIPHER_AES_CBC, .op = RTE_CRYPTO_CIPHER_OP_DECRYPT, .key.length = AES_KEY_SIZE, .key.data = aes_key, .iv.length = IV_SIZE, .iv.offset = sizeof(struct rte_crypto_op) + sizeof(struct rte_crypto_sym_op), };
struct rte_crypto_sym_xform xform = { .next = NULL, .type = RTE_CRYPTO_SYM_XFORM_CIPHER, .cipher = cipher, };
struct rte_crypto_sym_session *sess = rte_cryptodev_sym_session_create(cdev_id, &xform, sess_pool); if (!sess) { fprintf(stderr, "failed to create decrypt session for cdev :%u\n", cdev_id); return NULL; } return sess;}
static const char *rte_crypto_op_err_msg(const struct rte_crypto_op *op) { char *status_str; switch (op->status) { case RTE_CRYPTO_OP_STATUS_NOT_PROCESSED: status_str = "RTE_CRYPTO_OP_STATUS_NOT_PROCESSED"; break; case RTE_CRYPTO_OP_STATUS_AUTH_FAILED: status_str = "RTE_CRYPTO_OP_STATUS_AUTH_FAILED"; break; case RTE_CRYPTO_OP_STATUS_INVALID_SESSION: status_str = "RTE_CRYPTO_OP_STATUS_INVALID_SESSION"; break; case RTE_CRYPTO_OP_STATUS_INVALID_ARGS: status_str = "RTE_CRYPTO_OP_STATUS_INVALID_ARGS"; break; case RTE_CRYPTO_OP_STATUS_ERROR: status_str = "RTE_CRYPTO_OP_STATUS_ERROR"; break; default: printf("rte_crypto_op_err_msg, but no error\n"); status_str = NULL; } return status_str;}
bool do_encrypt(uint8_t cdev_id, struct rte_crypto_sym_session *sess, const char *plaintext, char **encrypted_text, size_t *encrypted_len) { bool success = false; size_t data_len = strlen(plaintext); uint8_t padding_len = BLOCK_SIZE - (data_len % BLOCK_SIZE); size_t total_len = data_len + padding_len;
// 1. alloc mbuf struct rte_mbuf *m = rte_pktmbuf_alloc(mbuf_pool); if (!m) { fprintf(stderr, "failed to alloc for mbuf\n"); goto cleanup; }
// 2. fill in data if (rte_pktmbuf_append(m, total_len) == 0) { fprintf(stderr, "mbuf append failed\n"); rte_pktmbuf_free(m); return false; } uint8_t *data_ptr = rte_pktmbuf_mtod(m, uint8_t *); memcpy(data_ptr, plaintext, data_len); memset(data_ptr + data_len, 0, padding_len);
// printf("Original plaintext (padded): '"); // for (size_t i = 0; i < total_len; i++) { // printf("%02x ", data_ptr[i]); // } // printf("\n"); printf("Data length: %zu (Padded: %zu)\n", data_len, total_len);
// 3. alloc crypto op struct rte_crypto_op *op = rte_crypto_op_alloc(crypto_op_pool, RTE_CRYPTO_OP_TYPE_SYMMETRIC); if (!op) { fprintf(stderr, "failed to alloc for op\n"); goto cleanup; }
// 4. configure op rte_crypto_op_attach_sym_session(op, sess); op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED; op->sym->m_src = m; op->sym->m_dst = NULL; op->sym->cipher.data.offset = 0; op->sym->cipher.data.length = total_len;
// 5. append IV after op->sym uint8_t *iv_ptr = rte_crypto_op_ctod_offset( op, uint8_t *, sizeof(struct rte_crypto_op) + sizeof(struct rte_crypto_sym_op)); memcpy(iv_ptr, iv_data, IV_SIZE);
// 6. enqueue struct rte_crypto_op *ops_enq[] = {op}; int enqueued = rte_cryptodev_enqueue_burst(cdev_id, 0, ops_enq, 1); printf("Enqueued %d ops\n", enqueued); printf("original op addr: %p\n", op);
// 7. dequeue struct rte_crypto_op *ops_deq[2] = {0}; int dequeued = 0; unsigned int retries = 0;
while (dequeued == 0 && retries < 100) { dequeued = rte_cryptodev_dequeue_burst(cdev_id, 0, ops_deq, 1); retries++; }
if (dequeued != 1) { fprintf(stderr, "failed to dequeue crypto op, dequeued :%d\n", dequeued); goto cleanup; }
// 8. check result struct rte_crypto_op *completed_op = ops_deq[0]; printf("completed_op addr: %p\n", completed_op); uint8_t *encrypted_ptr = NULL; if (completed_op->status == RTE_CRYPTO_OP_STATUS_SUCCESS) { encrypted_ptr = rte_pktmbuf_mtod(completed_op->sym->m_src, uint8_t *); printf("\n encryption success\n"); // printf("encrypted data (hex): "); // for (size_t i = 0; i < total_len; i++) { // printf("%02x ", encrypted_ptr[i]); // } // printf("\n"); } else { fprintf(stderr, "encryption failed with error: %s\n", rte_crypto_op_err_msg(completed_op)); goto cleanup; }
// 9. copy result to return *encrypted_text = (char *)malloc(total_len); if (!encrypted_text) { fprintf(stderr, "failed to alloc for encrypted!\n"); goto cleanup; } assert(encrypted_ptr); memcpy(*encrypted_text, encrypted_ptr, total_len); *encrypted_len = total_len;
success = true; // 10. free resource
cleanup: if (op) rte_crypto_op_free(op); if (m) rte_pktmbuf_free(m); return success;}
const char *do_decrypt(uint8_t cdev_id, struct rte_crypto_sym_session *sess, const char *encrypted_text, size_t total_len) { char *plaintext = NULL; struct rte_crypto_op *op = NULL; struct rte_mbuf *m = NULL;
// 1. alloc mbuf m = rte_pktmbuf_alloc(mbuf_pool); if (!m) { fprintf(stderr, "failed to alloc for mbuf\n"); goto cleanup; }
// 2. fill in data if (rte_pktmbuf_append(m, total_len) == 0) { fprintf(stderr, "mbuf append failed\n"); goto cleanup; } uint8_t *data_ptr = rte_pktmbuf_mtod(m, uint8_t *); memcpy(data_ptr, encrypted_text, total_len);
// 3. alloc crypto op op = rte_crypto_op_alloc(crypto_op_pool, RTE_CRYPTO_OP_TYPE_SYMMETRIC); if (!op) { fprintf(stderr, "failed to alloc for op\n"); goto cleanup; }
// 4. configure op rte_crypto_op_attach_sym_session(op, sess); op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED; op->sym->m_src = m; op->sym->m_dst = NULL; op->sym->cipher.data.offset = 0; op->sym->cipher.data.length = total_len;
// 5. append iv after op->sym uint8_t *iv_ptr = rte_crypto_op_ctod_offset( op, uint8_t *, sizeof(struct rte_crypto_op) + sizeof(struct rte_crypto_sym_op)); memcpy(iv_ptr, iv_data, IV_SIZE);
// 6. enqueue struct rte_crypto_op *ops_enq[] = {op}; int enqueued = rte_cryptodev_enqueue_burst(cdev_id, 0, ops_enq, 1); printf("Enqueued %d ops\n", enqueued); printf("original op addr: %p\n", op);
// 7. dequeue struct rte_crypto_op *ops_deq[2] = {0}; int dequeued = 0; unsigned int retries = 0;
while (dequeued == 0 && retries < 100) { dequeued = rte_cryptodev_dequeue_burst(cdev_id, 0, ops_deq, 1); retries++; }
if (dequeued != 1) { fprintf(stderr, "failed to dequeue crypto op, dequeued :%d\n", dequeued); goto cleanup; }
// 8. check result struct rte_crypto_op *completed_op = ops_deq[0]; printf("completed_op addr: %p\n", completed_op); uint8_t *decrypted_ptr = NULL; size_t decrypted_data_len = 0; if (completed_op->status == RTE_CRYPTO_OP_STATUS_SUCCESS) { decrypted_ptr = rte_pktmbuf_mtod(completed_op->sym->m_src, uint8_t *); decrypted_data_len = rte_pktmbuf_data_len(completed_op->sym->m_src); if (decrypted_data_len != total_len) { fprintf(stderr, "decrypted_data_len != total len\n"); } else { printf("decryption success\n"); } // printf("decrypted data (hex): "); // for (size_t i = 0; i < decrypted_data_len; i++) { // printf("%02x ", decrypted_ptr[i]); // } // printf("\n"); } else { fprintf(stderr, "decryption failed with error: %s\n", rte_crypto_op_err_msg(completed_op)); goto cleanup; }
// 9. copy result to return plaintext = (char *)malloc(decrypted_data_len); if (!plaintext) { fprintf(stderr, "failed to alloc for plaintext\n"); goto cleanup; } assert(decrypted_ptr); memcpy(plaintext, decrypted_ptr, decrypted_data_len);
cleanup: if (m) rte_pktmbuf_free(m); if (op) rte_crypto_op_free(op); return plaintext;}
const char* read_file(const char* file_path, size_t *out_len) { FILE* fp = fopen(file_path, "r"); if (!fp) { fprintf(stderr, "failed to open file: %s\n", file_path); return NULL; } if (fseek(fp, 0, SEEK_END) != 0) { fprintf(stderr, "failed to seek to file end\n"); goto cleanup; } long file_size = ftell(fp); if (file_size < 0) { fprintf(stderr, "failed to get file_size\n"); goto cleanup; } rewind(fp); char* buffer = (char*)malloc(file_size + 1); if (!buffer) { fprintf(stderr, "failed to alloc for buffer\n"); goto cleanup; } size_t read_bytes = fread(buffer, 1, file_size, fp); if (read_bytes != file_size) { fprintf(stderr, "failed to read into buffer, expected: %zu, got: %zu\n", file_size, read_bytes); goto cleanup; } buffer[file_size] = '\0'; fclose(fp); *out_len = file_size; return buffer;
cleanup: if (fp) fclose(fp); return NULL;}
int main(int argc, char **argv) { rte_eal_init(argc, argv);
// 1. cryptodev setup uint8_t cdev_id = setup_cryptodev(); if (cdev_id == (uint8_t)-1) { fprintf(stderr, "Error configure cryptodev\n"); goto cleanup; }
// 2. mbuf & crypto_op mempool alloc mbuf_pool = rte_pktmbuf_pool_create(MBUF_POOL_NAME, MBUFS_PER_POOL, 256, 0, MBUF_SIZE, rte_socket_id()); crypto_op_pool = rte_crypto_op_pool_create( CRYPTO_OP_POOL_NAME, RTE_CRYPTO_OP_TYPE_SYMMETRIC, CRYPTO_OPS_PER_POOL, 0, 0, rte_socket_id());
size_t priv_size = rte_cryptodev_sym_get_private_session_size(cdev_id); sess_pool = rte_cryptodev_sym_session_pool_create( SESS_POOL_NAME, SESS_PER_POOL, priv_size, 0, 0, rte_socket_id()); if (!mbuf_pool) { fprintf(stderr, "mbuf_pool alloc failed\n"); goto cleanup; } if (!crypto_op_pool) { fprintf(stderr, "crypto_op_pool alloc failed\n"); goto cleanup; } if (!sess_pool) { fprintf(stderr, "sess_pool alloc failed\n"); goto cleanup; }
// 3. create session struct rte_crypto_sym_session *encrypt_sess = create_sym_encrypt_session(cdev_id); struct rte_crypto_sym_session *decrypt_sess = create_sym_decrypt_session(cdev_id); if (!encrypt_sess || !decrypt_sess) { fprintf(stderr, "failed to create session\n"); goto cleanup; }
// 4. perform encrypt // const char *plaintext = // "This is a secrete message for AES-256-CBC encryption. hello world!"; size_t plaintext_len = 0; const char* plaintext = read_file(__FILE__, &plaintext_len); printf("*** plaintext len: %zu\n", plaintext_len); char *encrypted_text = NULL; size_t encrypted_len = 0; printf("---start encrypt---\n"); do_encrypt(cdev_id, encrypt_sess, plaintext, &encrypted_text, &encrypted_len); printf("---encrypt complete---\n"); printf("\n"); printf("---start decrypt---\n"); const char *decrypted_text = do_decrypt(cdev_id, decrypt_sess, encrypted_text, encrypted_len); printf("---decrypt complete---\n"); printf("---decrypted data---\n"); // printf("%s\n", decrypted_text);
printf("cleaning resources ...\n"); if (encrypted_text) free(encrypted_text); if (decrypted_text) free((void *)decrypted_text);
cleanup: if (encrypt_sess) rte_cryptodev_sym_session_free(cdev_id, encrypt_sess); if (decrypt_sess) rte_cryptodev_sym_session_free(cdev_id, decrypt_sess); if (mbuf_pool) rte_mempool_free(mbuf_pool); if (crypto_op_pool) rte_mempool_free(crypto_op_pool); if (sess_pool) rte_mempool_free(sess_pool); rte_cryptodev_stop(cdev_id); rte_eal_cleanup(); return 0;}cmake配置
cmake_minimum_required(VERSION 3.20)set(CMAKE_C_COMPILER clang)set(CMAKE_EXPORT_COMPILE_COMMANDS ON)set(CMAKE_C_STANDARD 23)set(CMAKE_C_STANDARD_REUIQRED ON)
project(dpdk_shared_mem_learning LANGUAGES C)
# use pkg-config to look up dpdkfind_package(PkgConfig REQUIRED)if(PKG_CONFIG_FOUND) pkg_check_modules(DPDK "libdpdk") if(DPDK_FOUND) list(JOIN DPDK_LIBRARY_DIRS ":" DPDK_RPATH) message(STATUS "found dpdk via pkg-config") else() message(WARNING "unable to find dpdk via pkg-config") endif()endif()
add_executable(encrypt encrypt.c)target_link_libraries(encrypt PRIVATE ${DPDK_LIBRARIES})运行命令
./build/encrypt -l 6-7 --vdev crypto_openssl期待输出
...EAL: Selected IOVA mode 'VA'CRYPTODEV: Creating cryptodev crypto_opensslCRYPTODEV: Initialisation parameters - name: crypto_openssl,socket id: 0, max queue pairs: 8---start encrypt---# 如果是读文件,则不会有下面这行输出,否则太长了Original plaintext (padded): '54 68 69 73 20 69 73 20 61 20 73 65 63 72 65 74 65 20 6d 65 73 73 61 67 65 20 66 6f 72 20 41 45 53 2d 32 35 36 2d 43 42 43 20 65 6e 63 72 79 70 74 69 6f 6e 2e 20 68 65 6c 6c 6f 20 77 6f 72 6c 64 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00Data length: 66 (Padded: 80)Enqueued 1 opsoriginal op addr: 0x1010b6700completed_op addr: 0x1010b6700
encryption success# 如果是读文件,则不会有下面这行输出,否则太长了encrypted data (hex): 86 1a 24 21 1a 42 0b c6 12 bc b2 e0 f1 1a 7c d6 91 8a f7 a1 f2 ad 09 2e e4 59 f5 7f a4 aa 64 98 06 cb 71 5d b5 95 3b cc 4e 2b 4c ba dc 64 98 8f 09 d2 71 88 4f 8c 03 ee e7 c6 6f a2 52 3f 59 a2 4a 66 e2 94 0f 96 67 54 a5 2c 95 35 99 53 e3 fe---encrypt complete---
---start decrypt---Enqueued 1 opsoriginal op addr: 0x1010b6800completed_op addr: 0x1010b6800decryption success# 如果是读文件,则不会有下面这行输出,否则太长了decrypted data (hex): 54 68 69 73 20 69 73 20 61 20 73 65 63 72 65 74 65 20 6d 65 73 73 61 67 65 20 66 6f 72 20 41 45 53 2d 32 35 36 2d 43 42 43 20 65 6e 63 72 79 70 74 69 6f 6e 2e 20 68 65 6c 6c 6f 20 77 6f 72 6c 64 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00---decrypt complete------decrypted data---This is a secrete message for AES-256-CBC encryption. hello world!cleaning resources ...dpdk执行非对称加解密rsa2048
代码
#include <stdio.h>#include <stdbool.h>#include <assert.h>#include <stdint.h>#include <stdlib.h>#include <string.h>
#include <openssl/pem.h>#include <openssl/rsa.h>#include <openssl/bn.h>#include <openssl/types.h>#include <openssl/evp.h>#include <openssl/core_names.h>
#include <rte_eal.h>#include <rte_malloc.h>#include <rte_mempool.h>#include <rte_crypto.h>#include <rte_cryptodev.h>#include <rte_crypto_asym.h>#include <rte_lcore.h>
#define ASYM_SESS_POOL_NAME "asym_sess_pool"#define ASYM_OP_POOL_NAME "asym_op_pool"#define ASYM_OPS_PER_POOL 2048#define MBUFS_PER_POOL 2048#define ASYM_SESS_PER_POOL 2048#define PMD_NAME "crypto_openssl"#define RSA_KEY_SIZE_BITS 2048#define RSA_KEY_SIZE_BYTES (RSA_KEY_SIZE_BITS / 8)
#define PUBLIC_KEY_FILE "public.pem"#define PRIVATE_KEY_FILE "private.pem"
static struct rte_mempool *asym_op_pool = NULL;static struct rte_mempool *asym_sess_pool = NULL;
typedef struct { // modules uint8_t n[RSA_KEY_SIZE_BYTES]; // public exponent uint8_t e[RSA_KEY_SIZE_BYTES]; // private exponent uint8_t d[RSA_KEY_SIZE_BYTES]; // exact len, since `E` might be smaller than 256 size_t e_len;} RsaKeyData;
bool load_rsa_key_components(RsaKeyData* data) { bool ret = false;
FILE* fp = fopen(PRIVATE_KEY_FILE, "r"); if (!fp) { fprintf(stderr, "Error: failed to open rsa private key file\n"); goto cleanup; }
// 1. read private key EVP_PKEY *pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL); fclose(fp); fp = NULL; if (!pkey) { fprintf(stderr, "failed to read RSA private key from PEM\n"); goto cleanup; }
// 2. check if is RSA! if (EVP_PKEY_id(pkey) != EVP_PKEY_RSA) { fprintf(stderr, "EVP_PKEY is not an RSA key\n"); goto cleanup; }
// 3. extract private key infos BIGNUM *n = NULL, *e = NULL, *d = NULL; // OSSL_PKEY_PARAM_RSA_N: modulus if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &n) != 1) { fprintf(stderr, "failed to extract modulus N\n"); goto cleanup; } // OSSL_PKEY_PARAM_RSA_E: public exponent if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &e) != 1) { fprintf(stderr, "failed to extract public exponent E\n"); goto cleanup; } // OSSL_PKEY_PARAM_RSA_D: private exponent if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_D, &d) != 1) { fprintf(stderr, "failed to extract private exponent D\n"); goto cleanup; }
// 4.transform BIGNUM into Big Endian mode
// Modulus (N) if (BN_bn2binpad(n, data->n, RSA_KEY_SIZE_BYTES) != RSA_KEY_SIZE_BYTES) { fprintf(stderr, "failed to convert N to binary\n"); goto cleanup; }
// Public Exponent (E) data->e_len = BN_bn2binpad(e, data->e, RSA_KEY_SIZE_BYTES); if (data->e_len <= 0) { fprintf(stderr, "failed to convert E to binary\n"); goto cleanup; }
// Private Exponent (D) if (BN_bn2binpad(d, data->d, RSA_KEY_SIZE_BYTES) != RSA_KEY_SIZE_BYTES) { fprintf(stderr, "failed to convert D to binary\n"); goto cleanup; }
ret = true;
cleanup: if (fp) fclose(fp); // 释放 BIGNUM 结构 (它们在 EVP_PKEY_get_bn_param 中被分配) if (n) BN_free(n); if (e) BN_free(e); if (d) BN_free(d); // 释放 EVP_PKEY if (pkey) EVP_PKEY_free(pkey); return ret;}
static const char* rte_crypto_op_err_msg(const struct rte_crypto_op *op) { switch (op->status) { case RTE_CRYPTO_OP_STATUS_SUCCESS: return "success"; case RTE_CRYPTO_OP_STATUS_NOT_PROCESSED: return "Not Processed"; case RTE_CRYPTO_OP_STATUS_AUTH_FAILED: return "auth failed"; case RTE_CRYPTO_OP_STATUS_INVALID_SESSION: return "invalid session"; case RTE_CRYPTO_OP_STATUS_INVALID_ARGS: return "invalid args"; case RTE_CRYPTO_OP_STATUS_ERROR: return "error"; default: return "unknown error"; }}
static int setup_cryptodev() { uint8_t cdev_ids[64] = {0}; int num_cdevs = rte_cryptodev_devices_get(PMD_NAME, cdev_ids, 64); assert(num_cdevs > 0 && "no cdev" PMD_NAME "found"); uint8_t cdev_id = cdev_ids[0];
struct rte_cryptodev_config config = { .nb_queue_pairs = 1, .socket_id = rte_socket_id(), }; if (rte_cryptodev_configure(cdev_id, &config) < 0) { fprintf(stderr, "failed to configure crypto dev: %u\n", cdev_id); return -1; }
struct rte_cryptodev_qp_conf qp_conf = { .nb_descriptors = 2048, }; if (rte_cryptodev_queue_pair_setup(cdev_id, 0, &qp_conf, rte_socket_id()) < 0) { fprintf(stderr, "failed to setup queue pair 0 on crypto dev: %u\n", cdev_id); return -1; }
if (rte_cryptodev_start(cdev_id) < 0) { fprintf(stderr, "failed to start crypto dev: %u\n", cdev_id); return -1; }
return cdev_id;}
static struct rte_cryptodev_asym_session *create_asym_session(uint8_t cdev_id, const RsaKeyData *key_data) { // xform for private key struct rte_crypto_rsa_xform rsa_xform = { .key_type = RTE_RSA_KEY_TYPE_EXP, .n = {.data = (uint8_t *)key_data->n, .length = RSA_KEY_SIZE_BYTES}, .e = {.data = (uint8_t *)key_data->e, .length = RSA_KEY_SIZE_BYTES}, .d = {.data = (uint8_t *)key_data->d, .length = RSA_KEY_SIZE_BYTES}, .padding.type = RTE_CRYPTO_RSA_PADDING_PKCS1_5, }; struct rte_crypto_asym_xform asym_xform = { .next = NULL, .xform_type = RTE_CRYPTO_ASYM_XFORM_RSA, .rsa = rsa_xform, }; struct rte_cryptodev_asym_session *sess = NULL; int ret = rte_cryptodev_asym_session_create(cdev_id, &asym_xform, asym_sess_pool, (void**)&sess); if (ret != 0 || !sess) { fprintf(stderr, "failed to create asym_session\n"); return NULL; } return sess;}
static bool do_asym_op(uint8_t cdev_id, struct rte_crypto_op *op) { struct rte_crypto_op *ops_enq[] = {op}; struct rte_crypto_op *ops_deq[1] = {NULL}; int enqueued = 0, dequeued = 0; unsigned int retires = 0;
// 1. enqueue enqueued = rte_cryptodev_enqueue_burst(cdev_id, 0, ops_enq, 1); if (enqueued != 1) { fprintf(stderr, "failed to enqueue op, retrying later\n"); return false; }
// 2. dequeue (poll for completion) while (dequeued == 0 && retires < 1000) { dequeued = rte_cryptodev_dequeue_burst(cdev_id, 0, ops_deq, 1); retires++; } if (dequeued != 1) { fprintf(stderr, "failed to dequeue crypto op\n"); return false; }
// 3. check result struct rte_crypto_op *completed_op = (struct rte_crypto_op*)ops_deq[0]; if (completed_op->status != RTE_CRYPTO_OP_STATUS_SUCCESS) { fprintf(stderr, "operation failed, status: %s\n", rte_crypto_op_err_msg(completed_op)); return false; }
return true;}
bool perform_rsa_test(uint8_t cdev_id, const RsaKeyData *key_data, struct rte_cryptodev_asym_session* sess) { bool ret = false;
// 1. data prepare const char* plaintext = "DPDK rsa2048 test message"; size_t plaintext_len = strlen(plaintext) + 1;
uint8_t *in_buf = rte_zmalloc("in_buf", RSA_KEY_SIZE_BYTES, 0); if (!in_buf) { fprintf(stderr, "failed to alloc for in_buf\n"); goto cleanup; } uint8_t *cipher_buf = rte_zmalloc("cipher_buf", RSA_KEY_SIZE_BYTES, 0); if (!cipher_buf) { fprintf(stderr, "failed to alloc for cipher_buf\n"); goto cleanup; } uint8_t *decrypt_buf = rte_zmalloc("decrypt_buf", RSA_KEY_SIZE_BYTES, 0); if (!decrypt_buf) { fprintf(stderr, "failed to alloc for decrypt buf\n"); goto cleanup; }
memcpy(in_buf, plaintext, plaintext_len > RSA_KEY_SIZE_BYTES ? RSA_KEY_SIZE_BYTES : plaintext_len); printf("original data (%zu bytes): %s\n", plaintext_len, plaintext);
// 3. alloc crypto op struct rte_crypto_op *op_enc = rte_crypto_op_alloc(asym_op_pool, RTE_CRYPTO_OP_TYPE_ASYMMETRIC); if (!op_enc) { fprintf(stderr, "failed to alloc for op_enc\n"); goto cleanup; } struct rte_crypto_op *op_dec = rte_crypto_op_alloc(asym_op_pool, RTE_CRYPTO_OP_TYPE_ASYMMETRIC); if (!op_dec) { fprintf(stderr, "failed to alloc for op_dec\n"); goto cleanup; }
// 4. fill op_enc rte_crypto_op_attach_asym_session(op_enc, sess); op_enc->asym->rsa.op_type = RTE_CRYPTO_ASYM_OP_ENCRYPT; op_enc->asym->rsa.message.data = in_buf; op_enc->asym->rsa.message.length = plaintext_len; op_enc->asym->rsa.cipher.data = cipher_buf; op_enc->asym->rsa.cipher.length = RSA_KEY_SIZE_BYTES;
// 5. do asym op encrypt if (!do_asym_op(cdev_id, op_enc)) { fprintf(stderr, "RSA encryption failed\n"); goto cleanup; } printf("Encryption successful, ciphertext length: %zu bytes\n", op_enc->asym->rsa.cipher.length);
// 6. do asym op decrypt rte_crypto_op_attach_asym_session(op_dec, sess); op_dec->asym->rsa.op_type = RTE_CRYPTO_ASYM_OP_DECRYPT; op_dec->asym->rsa.cipher.data = cipher_buf; op_dec->asym->rsa.cipher.length = RSA_KEY_SIZE_BYTES; op_dec->asym->rsa.message.data = decrypt_buf; op_dec->asym->rsa.message.length = RSA_KEY_SIZE_BYTES;
if (!do_asym_op(cdev_id, op_dec)) { fprintf(stderr, "RSA decryption failed\n"); goto cleanup; } size_t decrypted_len = op_dec->asym->rsa.message.length; printf("Decryption successful, plaintext length: %zu bytes\n", decrypted_len);
// 7. check result printf("Original message:\n%s\n", plaintext); printf("Decrypted message:\n"); char* decrypted_text = (char*)malloc(decrypted_len + 1); memcpy(decrypted_text, op_dec->asym->rsa.message.data, decrypted_len); decrypted_text[decrypted_len] = '\0'; printf("%s\n", decrypted_text); ret = true;
cleanup: if (in_buf) rte_free(in_buf); if (cipher_buf) rte_free(cipher_buf); if (decrypt_buf) rte_free(decrypt_buf); if (op_enc) rte_crypto_op_free(op_enc); if (op_dec) rte_crypto_op_free(op_dec); return ret;}
int main(int argc, char**argv) { // 1. read rsa data RsaKeyData *key_data = malloc(sizeof(RsaKeyData)); if (!load_rsa_key_components(key_data)) { fprintf(stderr, "failed to load rsa data\n"); goto cleanup; }
rte_eal_init(argc, argv);
// 2. cryptodev setup uint8_t cdev_id = setup_cryptodev(); if (cdev_id == (uint8_t)-1) { fprintf(stderr, "Error configure cryptodev\n"); goto cleanup; }
// 3. sess & crypto_op mempool alloc asym_op_pool = rte_crypto_op_pool_create( ASYM_OP_POOL_NAME, RTE_CRYPTO_OP_TYPE_ASYMMETRIC, ASYM_OPS_PER_POOL, 0, sizeof(struct rte_crypto_asym_op), rte_socket_id()); size_t priv_size = rte_cryptodev_asym_get_private_session_size(cdev_id); asym_sess_pool = rte_cryptodev_asym_session_pool_create(ASYM_SESS_POOL_NAME, ASYM_SESS_PER_POOL, 0, priv_size, rte_socket_id()); if (!asym_op_pool) { fprintf(stderr, "asym_op_pool alloc failed\n"); goto cleanup; } if (!asym_sess_pool) { fprintf(stderr, "failed to alloc asym_sess_pool\n"); goto cleanup; }
// 4. create session struct rte_cryptodev_asym_session *sess = create_asym_session(cdev_id, key_data);
// 5. perform test perform_rsa_test(cdev_id, key_data, sess);
printf("test complete, cleaning resource...\n");cleanup: if (sess) rte_cryptodev_asym_session_free(cdev_id, sess); if (asym_op_pool) rte_mempool_free(asym_op_pool); if (asym_sess_pool) rte_mempool_free(asym_sess_pool); rte_cryptodev_stop(cdev_id); rte_eal_cleanup(); return 0;}cmake配置
cmake_minimum_required(VERSION 3.20)set(CMAKE_C_COMPILER clang)set(CMAKE_EXPORT_COMPILE_COMMANDS ON)set(CMAKE_C_STANDARD 23)set(CMAKE_C_STANDARD_REUIQRED ON)
project(dpdk_shared_mem_learning LANGUAGES C)
# use pkg-config to look up dpdkfind_package(PkgConfig REQUIRED)if(PKG_CONFIG_FOUND) pkg_check_modules(DPDK "libdpdk") if(DPDK_FOUND) list(JOIN DPDK_LIBRARY_DIRS ":" DPDK_RPATH) message(STATUS "found dpdk via pkg-config") else() message(WARNING "unable to find dpdk via pkg-config") endif()endif()
add_executable(rsa_enc_dec rsa_enc_dec.c)target_link_libraries(rsa_enc_dec PRIVATE ${DPDK_LIBRARIES} crypto)生成公私钥
生成私钥
openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048生成公钥(可选),因为公钥是可以从private.pem中获取相关信息的
openssl rsa -in private.pem -pubout -out public.pem运行命令
./build/rsa_enc_dec -l 6-7 --vdev crypto_openssl期待输出
EAL: Detected CPU lcores: 320EAL: Detected NUMA nodes: 4EAL: Detected shared linkage of DPDKEAL: Multi-process socket /tmp/dpdk/rte/mp_socketEAL: Selected IOVA mode 'VA'CRYPTODEV: Creating cryptodev crypto_opensslCRYPTODEV: Initialisation parameters - name: crypto_openssl,socket id: 0, max queue pairs: 8original data (26 bytes): DPDK rsa2048 test messageEncryption successful, ciphertext length: 256 bytesDecryption successful, plaintext length: 26 bytesOriginal message:DPDK rsa2048 test messageDecrypted message:DPDK rsa2048 test messagetest complete, cleaning resource...CRYPTODEV: Closing crypto device crypto_openssldpdk使用rsa进行sign和verify
代码
包括main函数在内的其它所有函数同上,只有原来的perform_rsa_test现在变成了下面的这个perform_rsa_sign_verify_test
static bool perform_rsa_sign_verify_test(uint8_t cdev_id, const RsaKeyData *key_data, struct rte_cryptodev_asym_session *sess) { // 1. param check if (!key_data || !sess) { fprintf(stderr, "nullptr input\n"); return false; } bool ret = false;
// 2. prepare plaintext const char *plaintext = "DPDK rsa sign test message"; size_t plaintext_len = strlen(plaintext);
uint8_t *plain_buf = rte_zmalloc("msg_buf", RSA_KEY_SIZE_BYTES, 0); uint8_t *sign_buf = rte_zmalloc("sign_buf", RSA_KEY_SIZE_BYTES, 0); if (!plain_buf || !sign_buf) { fprintf(stderr, "failed to alloc for buf\n"); return false; } memcpy(plain_buf, plaintext, plaintext_len);
// 3. alloc crypto op struct rte_crypto_op *op = rte_crypto_op_alloc(asym_op_pool, RTE_CRYPTO_OP_TYPE_ASYMMETRIC); if (!op) { fprintf(stderr, "failed to alloc for crypto op"); goto cleanup; }
// 4. fill in op for sign rte_crypto_op_attach_asym_session(op, sess); op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED; op->asym->rsa.op_type = RTE_CRYPTO_ASYM_OP_SIGN; op->asym->rsa.message.data = plain_buf; op->asym->rsa.message.length = plaintext_len; op->asym->rsa.sign.data = sign_buf; op->asym->rsa.sign.length = RSA_KEY_SIZE_BYTES;
// 5. sign if (!do_asym_op(cdev_id, op)) { fprintf(stderr, "rsa sign failed\n"); goto cleanup; } printf("RSA sign success, signature generated\n");
// 6. fill in op for verify op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED; op->asym->rsa.op_type = RTE_CRYPTO_ASYM_OP_VERIFY; op->asym->rsa.sign.data = sign_buf; op->asym->rsa.sign.length = RSA_KEY_SIZE_BYTES; op->asym->rsa.message.data = plain_buf; op->asym->rsa.message.length = plaintext_len;
// 7. verify if (!do_asym_op(cdev_id, op)) { fprintf(stderr, "RSA verify failed\n"); goto cleanup; } else { printf("verify success\n"); ret = true; }
// 8. mallicious verify // signed data bytes reverted uint8_t *err_buf = rte_zmalloc("err_buf", RSA_KEY_SIZE_BYTES, 0); memcpy(err_buf, sign_buf, RSA_KEY_SIZE_BYTES); err_buf[0] ^= 0xff; op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED; op->asym->rsa.op_type = RTE_CRYPTO_ASYM_OP_VERIFY; op->asym->rsa.sign.data = err_buf; op->asym->rsa.sign.length = RSA_KEY_SIZE_BYTES; op->asym->rsa.message.data = plain_buf; op->asym->rsa.message.length = plaintext_len; bool err_res = do_asym_op(cdev_id, op); if (!err_res) { printf("mallicious verify FAILED as expected, status: %s\n", rte_crypto_op_err_msg(op)); } else { fprintf(stderr, "mallicious check failed\n"); ret = false; goto cleanup; }
cleanup: if (plain_buf) rte_free(plain_buf); if (sign_buf) rte_free(sign_buf); if (err_buf) rte_free(err_buf); if (op) rte_crypto_op_free(op); return ret;}期待输出
EAL: Selected IOVA mode 'VA'CRYPTODEV: Creating cryptodev crypto_opensslCRYPTODEV: Initialisation parameters - name: crypto_openssl,socket id: 0, max queue pairs: 8RSA sign success, signature generatedverify successoperation failed, status: errormallicious verify FAILED as expected, status: errortest complete, cleaning resource...CRYPTODEV: Closing crypto device crypto_openssl dpdk-do-crypto
https://blog.cassiusblack.top/posts/dpdk-do-crypto/