-
Notifications
You must be signed in to change notification settings - Fork 89
MPEG CENC in CBCS mode
The intel-ipsec-mb library can be used to accelerate MPEG Common Encryption (CENC) in “cbcs” mode by leverage SIMD instructions to process multiple buffers in parallel. Currently SSE and AVX instruction sets are supported to encrypt / decrypt either 4 or 8 buffers concurrently using the 1:9 crypt:skip pattern.
AES-CBCS is done through the library’s asynchronous API (“job” API). The application submits multiple jobs to the library to be processed and jobs are returned in order. When the jobs are returned, depends on the underlying implementation and size of the jobs. Please refer to the Fast Multi-buffer IPsec Implementations on Intel® Architecture Processors whitepaper for more information on the job API and multi-buffer processing.
The design of AES-CBC encryption specifies that every block to be encrypted has a dependency on the previous block. This means only single blocks can be encrypted at a time. In order to maximize throughput, multi-buffer job scheduling is used to encrypt multiple buffers in parallel. The library will wait until there are enough jobs (buffers to be processed) submitted before beginning encryption. As jobs are submitted, the multi-buffer manager (job scheduler) inserts each job into a “lane”. Until all lanes are populated, the API will return NULL. Once all lanes have been filled, jobs will start to be processed and for every new job submitted, a completed job will be returned. Jobs are returned in the same order that they were submitted. If there are no more jobs to be submitted, existing jobs can be flushed (i.e. forced to completion) from the multi-buffer manager.
AES-CBC decryption does not have the same dependency as encryption. For this reason, decryption can be done using a single-buffer implementation to decrypt multiple blocks of a single buffer in parallel. Every job submitted is processed and returned immediately. No job scheduling is required.
Below is a sample application to demonstrate how to use of AES-CBCS in 1:9 pattern and also to highlight the order that jobs are submitted and returned. In this example, the SSE implementation is used. This implementation supports processing 4 buffers in parallel for encryption by setting the following job (IMB_JOB structure) fields:
cipher_mode = IMB_CIPHER_CBCS_1_9
cipher_direction = IMB_DIR_ENCRYPT
chain_order = IMB_ORDER_CIPHER_HASH
For decryption, set the job fields to:
cipher_mode = IMB_CIPHER_CBCS_1_9
cipher_direction = IMB_DIR_DECRYPT
chain_order = IMB_ORDER_HASH_CIPHER
Other IMB_JOB fields of note:
hash_alg
should be set to IMB_AUTH_NULL if no authentication is being performed. In this case the chain_order field does not matter.
msg_len_to_cipher_in_bytes
set to the full length of the buffer to be processed.
src
pointer to first block to be encrypted/decrypted.
dst
pointer to output buffer (CBCS assumes in place processing (i.e. same in/out buffer)
#include <stdio.h>
#include <stdint.h>
#include <intel-ipsec-mb.h>
int main(int argc, char **argv)
{
IMB_MGR *p_mgr = NULL;
IMB_JOB *job = NULL;
uint64_t flags = 0;
uint32_t enc_keys[11*4] __attribute__((aligned(16))); // 16 byte keys * 11 rounds
uint32_t dec_keys[11*4] __attribute__((aligned(16)));
uint8_t buf[1024];
int i, num_jobs = 10, jobs_rx = 0;
uint8_t aes_key[16] = {0}; // 128b key
uint8_t iv[16] = {0}; // 128b key
/* allocate multi-buffer manager */
p_mgr = alloc_mb_mgr(flags);
if (p_mgr == NULL)
{
printf("Error allocating MB_MGR structure!\n");
return EXIT_FAILURE;
}
/* initialize SSE mb_mgr */
init_mb_mgr_sse(p_mgr);
/* expand aes-128 key */
IMB_AES_KEYEXP_128(p_mgr, aes_key, enc_keys, dec_keys);
/* flush the scheduler */
while ((job = IMB_FLUSH_JOB(p_mgr))!= NULL)
;
/* submit jobs */
printf("Submitting %d jobs...\n", num_jobs);
for (i = 0; i < num_jobs; i++)
{
job = IMB_GET_NEXT_JOB(p_mgr);
job->cipher_direction = IMB_DIR_ENCRYPT; // or IMB_DIR_DECRYPT
job->chain_order = IMB_ORDER_CIPHER_HASH; //HASH_CIPHER for DECRYPT
job->dst = buf;
job->src = buf;
job->cipher_mode = IMB_CIPHER_CBCS_1_9;
job->enc_keys = enc_keys;
job->dec_keys = dec_keys;
job->key_len_in_bytes = 16;
job->iv = iv;
job->iv_len_in_bytes = 16;
job->cipher_start_src_offset_in_bytes = 0;
job->msg_len_to_cipher_in_bytes = sizeof(buf);
job->hash_alg = IMB_AUTH_NULL;
printf("Submitting job %i\n", i);
job = IMB_SUBMIT_JOB(p_mgr);
if (job == NULL) {
printf("Recieved NULL\n");
} else {
jobs_rx++;
printf("Recieved job!\n");
}
}
/* flush the scheduler */
printf("Flushing scheduler...\n");
while ((job = IMB_FLUSH_JOB(p_mgr)) != NULL) {
jobs_rx++;
printf("Got flushed job\n");
}
printf("Received %d jobs total!\n", jobs_rx);
free_mb_mgr(p_mgr);
}
The above application outputs the following:
| ENCRYPTION | DECRYPTION |
|------------------------|------------------------|
| Submitting 10 jobs... | Submitting 10 jobs... |
| Submitting job 0 | Submitting job 0 |
| Recieved NULL | Recieved job! |
| Submitting job 1 | Submitting job 1 |
| Recieved NULL | Recieved job! |
| Submitting job 2 | Submitting job 2 |
| Recieved NULL | Recieved job! |
| Submitting job 3 | Submitting job 3 |
| Recieved job! | Recieved job! |
| Submitting job 4 | Submitting job 4 |
| Recieved job! | Recieved job! |
| Submitting job 5 | Submitting job 5 |
| Recieved job! | Recieved job! |
| Submitting job 6 | Submitting job 6 |
| Recieved job! | Recieved job! |
| Submitting job 7 | Submitting job 7 |
| Recieved job! | Recieved job! |
| Submitting job 8 | Submitting job 8 |
| Recieved job! | Recieved job! |
| Submitting job 9 | Submitting job 9 |
| Recieved job! | Recieved job! |
| Flushing scheduler... | Flushing scheduler... |
| Got flushed job | Received 10 jobs total!|
| Got flushed job | |
| Got flushed job | |
| Received 10 jobs total!| |