Intel® QAT加速卡之加密、哈希操作流程和示例

Intel® QAT 加密API介绍

文章主要讲述了Intel® QAT 加密API接口的说明,以及多种应用场景下的使用方法。

1. 概述

Intel® QAT加速卡API接口可以分为以下几类:

  • 通用类(common):这是由文件cpa_cy_common.h定义的。 主要包括用于QAT加速服务的初始化和关闭操作。
  • 实例管理(Instance Management):文件cpa_cy_im.h定义了用于管理实例的功能。
  • 对称算法API(Symmetric): 它是由以下几个文件中共同定义组成的。
    • cpa_cy_sym.h : 该文件中包含对称API,用于加密,获取哈希/消息摘要,“链式操作算法”(将密码和哈希合并到一个操作中)、身份验证。
    • cpa_sy_sym_dp.h :该文件中包含对称API,也可用于加密,获取哈希/消息摘要,“链式操作算法”(将密码和哈希合并到一个操作中)、身份验证。在数据面推荐使用这部分API接口,因为它们的开销比较小(即API向硬件发送请求和处理响应所消耗的周期比较少)。但是使用这类API接口需要遵守一些限制。
    • cpa_cy_key.h : 这部分API是SSL协议和TLS协议用来生成密钥的。
  • 非对称算法API(Asymmetric): 它是由以下几个文件中共同定义组成的。
    • cpa_cy_rsa.h : RSA算法API;
    • cpa_cy_dsa.h :数字签名算法(Digital Signature Algorithm)API;
    • cpa_cy_dh.h : DH算法API;
    • cpa_cy_ec.h :椭圆曲线加密算法API;
    • cpa_cy_ecdsa.h :椭圆差分DSA算法API;
    • cpa_cy_ecdh.h : 椭圆DH算法API;
    • cpa_cy_prime.h :素数测试API;
    • cpa_cy_ln.h :大数API
  • 随机数生成类(Random Bit Generation ,简称RBG ):这类API接口用来生成随机数的,但是不推荐使用,因为随机数可以通过CPU来产生。它有以下两个文件组成:
    • cpa_cy_drbg.h
    • cpa_cy_nrbg.h

加密操作使用了一些基本API接口,这些API接口定义了基本的数据类型供QAT加速服务使用。

1.1 会话(session)

对称类API是唯一使用到会话概念的API。会话的定义见下面章节。

1.2 优先级

加密对称API支持优先级。 优先级可以永久指定指定。对称API支持两种优先级:高优先级和普通优先级。
实现可以使用严格的优先级顺序,也可以使用基于加权轮询的优先级方案。

2. 对称加密接口

这部分主要讲述了如何使用对称加密接口执行各种各样的加密和哈希操作。

对称加密操作都遵循以下几个基本的操作步骤:

  • 如果采用异步处理方式,需要定义并实现一个回调函数
  • 发现并启动一个加密服务实例
  • 创建并初始化一个session
  • 在会话上调用对称操作(例如加解密操作,哈希散列操作)
  • 关闭会话
  • 停止加密服务实例

下面分别介绍三个涉及到的基本概念。

2.1 基本概念

  • 会话(session)
  • Place and Out-of-Place Support
  • Partial Support
2.1.1 会话

在对称API的情况下,会话作为一个句柄,用于描述要应用于多个缓冲区(buffers)的加密参数。这些buffers可能是用于加密单个文件,也可能是通过IPSec隧道的所有数据包或者与之相关的安全联盟。会话句柄包含以下几类数据:

  • 会话进行的操作,例如加密操作,哈希操作,或者两个操作;这种情况下需要设置算法执行顺序;

  • 所有的加密材料,包括加密算法、模式、密钥、密钥长度、方向(加密、解密)等;

  • 哈希操作材料,包括散列算法,模式(普通,嵌套或已认证)和摘要结果长度(允许截断);

    • 身份验证模式可以引用哈希消息身份验证码(HMAC),它要求还指定密钥及其长度。 它还可用于Galois计数器模式(GCM)和具有密码块链接消息身份验证代码(CCM)身份验证加密的计数器模式,在这种情况下,还指定了附加身份验证数据(AAD)长度。
    • 对于嵌套模式,将指定内部和外部前缀数据和长度,以及外部哈希算法。
2.1.2 In-place and Out-of-place

In-Place操作意味着目标缓冲区与源缓冲区相同。 Out-of-Place操作意味着目标缓冲区与源缓冲区不同。

2.1.3 部分加密模式

官方提供的文档中,大多数示例都对完整的数据包进行操作。 此外,该API还支持在部分模式下运行; 例如,状态(例如密码状态)需要从一个分组/记录转发到下一个分组/记录。

  • 对于所有部分数据包,要散列或加密的数据大小必须是算法的块大小的倍数。
  • 对于哈希/身份验证,摘要验证标志仅适用于最后的部分数据包。
  • 对于链式算法,两次调用之间仅保持密码状态。 两次调用之间不保持哈希状态, 而是将为每个调用生成/验证哈希摘要。 对于所有部分数据包,要加密的数据大小必须是算法的块大小的倍数。 要散列的数据大小没有此限制。 如果两次调用之间需要同时保持密码状态和哈希状态,则无法使用链式算法。
2.1.4 加密操作

下面通过一个例子来说明对称API的用法。

quickassist\lookaside\access_layer\src\sample_code\functional\sym\cipher_sample

2.1.4.1 symCallback

如果要使用异步模式API,就必须提供一个回调函数。 异步操作完成后,会自动执行回调函数。 回调函数运行的上下文取决于实现。 例如,可以在Linux中断处理程序的下半部分的上下文中或在用户创建的轮询线程的上下文中调用它。 调用此函数的上下文对在回调函数中可以执行的处理施加了限制。例如,它声明该函数不应休眠(因为它可能在不允许休眠的上下文中被调用,例如Linux中断下半部)。

此功能可以执行适合应用程序的任何处理。 例如,它可以释放内存,继续处理解密的数据包等。在此示例中,该函数仅设置complete变量以表明它已被调用,如下所示。

static void symCallback(void *pCallbackTag,
        CpaStatus status,
        const CpaCySymOp operationType,
        void *pOpData,
        CpaBufferList *pDstBuffer,
        CpaBoolean verifyResult)
{
    PRINT_DBG("Callback called with status = %d.\n", status);

    if (NULL != pCallbackTag)
    {
        /* indicate that the function has been called */
        COMPLETE((struct COMPLETION_STRUCT *)pCallbackTag);
    }
}
2.1.4.2 cipherSample

这是加密操作的主要入口点。它演示了一些重要的API接口的调用顺序,包括执行一个、多个加密操作,拆除会话等。下面是几个重要的步骤:

  • 获取实例(Instance)
  • 设置地址转换函数
  • 启动会话
  • 创建并初始化加密会话
  • 内存申请
  • 构建加密操作数据
  • 执行加密操作
  • 等待完成
  • 等待未完成的操作
  • 删除加密会话
1)Getting an Instance

获取加密实例(Instance)的接口在此示例中是通过sampleCyGetInstance接口来实现的。它是一个比较简单的API接口,查询所有的Instance,但是只返回第一个Instance。它的实现如下:

#ifdef DO_CRYPTO
void
sampleCyGetInstance(CpaInstanceHandle* pCyInstHandle)
{
    CpaInstanceHandle cyInstHandles[MAX_INSTANCES];/*#define MAX_INSTANCES 1*/
    Cpa16U numInstances = 0;
    CpaStatus status = CPA_STATUS_SUCCESS;

    *pCyInstHandle = NULL;

    status = cpaCyGetNumInstances(&numInstances);/*获取instance的个数*/
    if ((status == CPA_STATUS_SUCCESS) && (numInstances > 0))
    {
        /*获取MAX_INSTANCES个示例,并返回第一个示例的句柄*/
        status = cpaCyGetInstances(MAX_INSTANCES, cyInstHandles);
        if (status == CPA_STATUS_SUCCESS)
        {
            *pCyInstHandle = cyInstHandles[0];
        }
    }

    if (0 == numInstances)
    {
        PRINT_ERR("No instances found for 'SSL'\n");
        PRINT_ERR("Please check your section names in the config file.\n");
        PRINT_ERR("Also make sure to use config file version 2.\n");
    }
   
}
#endif
2)Set Address Translation Function

设置Instance的地址转换函数

CpaStatus
cipherSample(void)
{
    ... ...
        
	if(CPA_STATUS_SUCCESS == status)
    {
       /*
        * Set the address translation function for the instance
        */
//<snippet name="virt2phys">
        status = cpaCySetAddressTranslation(cyInstHandle, sampleVirtToPhys);
//</snippet>
    }
    ... ...
        
}
3)Start up

启动加密服务Instance。

CpaStatus
cipherSample(void)
{
    ... ...
        
	status = cpaCyStartInstance(cyInstHandle);
    
    ... ...    
}    
4)Create and Initialize Cipher Session

接下来便是创建并初始化加密会话。首先需要填充会话初始化操作数据结构的相关字段。需要注意的是:存储会话数据的空间大小与具体实现有关,这就要求我们需要先通过API接口获取到需要的会话大小,然后在分配空间。这里有两个接口可以使用:

  • cpaCySymSessionCtxGetSize

这个函数始终返回最大会话大小。

  • cpaCySymSessionCtxGetDynamicSize

在满足特定的会话建立条件情况下,使用此函数可以返回比较小的内存空间大小。

CpaStatus
cipherSample(void)
{
    ... ...
        
    {
		sessionSetupData.sessionPriority =  CPA_CY_PRIORITY_NORMAL;
        sessionSetupData.symOperation =     CPA_CY_SYM_OP_CIPHER;
        sessionSetupData.cipherSetupData.cipherAlgorithm =
                                            CPA_CY_SYM_CIPHER_3DES_CBC;
        sessionSetupData.cipherSetupData.pCipherKey =
                                            sampleCipherKey;
        sessionSetupData.cipherSetupData.cipherKeyLenInBytes =
                                            sizeof(sampleCipherKey);
        sessionSetupData.cipherSetupData.cipherDirection =
                                            CPA_CY_SYM_CIPHER_DIRECTION_ENCRYPT;

        /* Determine size of session context to allocate */
        PRINT_DBG("cpaCySymSessionCtxGetSize\n");
        status = cpaCySymSessionCtxGetSize(cyInstHandle,
                    &sessionSetupData, &sessionCtxSize);/*获取会话空间大小*/
    }

    if (CPA_STATUS_SUCCESS == status)
    {
        /* Allocate session context */
        status = PHYS_CONTIG_ALLOC(&sessionCtx, sessionCtxSize);/*然后开始分配空间*/
    }


    /* Initialize the Cipher session */
    if (CPA_STATUS_SUCCESS == status)
    {
        PRINT_DBG("cpaCySymInitSession\n");/*初始化会话*/
        status = cpaCySymInitSession(cyInstHandle,
                            symCallback,        /* callback function */
                            &sessionSetupData,  /* session setup data */
                            sessionCtx);       /* output of the function*/
    }
    
    ... ...
}

在完成上述操作之后,便可以通过调用cipherPerformOp()来完成加密操作,下面继续说明cipherPerformOp中涉及的重要流程:


5)Memory Allocation

不同API实现需要不同大小的内存空间来存储与缓冲区列表关联的元数据。 查询相应的API获取到需要分配的空间的大小,然后为缓冲区元数据,缓冲区列表以及缓冲区本身分配空间。 此外,还必须为初始化向量分配内存。

static CpaStatus
cipherPerformOp(CpaInstanceHandle cyInstHandle, CpaCySymSessionCtx sessionCtx)
{
	... ...
        
	status = cpaCyBufferListGetMetaSize( cyInstHandle,
                numBuffers, &bufferMetaSize);

    if (CPA_STATUS_SUCCESS == status)
    {
        status = PHYS_CONTIG_ALLOC(&pBufferMeta, bufferMetaSize);
    }

    if (CPA_STATUS_SUCCESS == status)
    {
        status = OS_MALLOC(&pBufferList, bufferListMemSize);
    }

    if (CPA_STATUS_SUCCESS == status)
    {
        status = PHYS_CONTIG_ALLOC(&pSrcBuffer, bufferSize);
    }

    if (CPA_STATUS_SUCCESS == status)
    {
        status = PHYS_CONTIG_ALLOC(&pIvBuffer, sizeof(sampleCipherIv));
    }
    
    ... ...
}
6)Set up Cipher Operational Data

源缓冲区和初始化向量申请的内存中需要填充所需的数据。构造操作数据:填充执行加密算法是所需的操作数据的结构。

static CpaStatus
cipherPerformOp(CpaInstanceHandle cyInstHandle, CpaCySymSessionCtx sessionCtx)
{
	... ...
        
	if (CPA_STATUS_SUCCESS == status)
    {
        /*
             * Populate the structure containing the operational data needed
             * to run the algorithm:
             * - packet type information (the algorithm can operate on a full
             *   packet, perform a partial operation and maintain the state or
             *   complete the last part of a multi-part operation)
             * - the initialization vector and its length
             * - the offset in the source buffer
             * - the length of the source message
             */
        pOpData->sessionCtx = sessionCtx;
        pOpData->packetType = CPA_CY_SYM_PACKET_TYPE_FULL;
        pOpData->pIv = pIvBuffer;
        pOpData->ivLenInBytes = sizeof(sampleCipherIv);
        pOpData->cryptoStartSrcOffsetInBytes = 0;
        pOpData->messageLenToCipherInBytes = sizeof(sampleCipherSrc);
    }
    
    ... ...
}
7)Perform Cipher Operation

首先初始化complete信号量(通过此信号量可以知道执行的操作是否完成),然后执行加密操作。

static CpaStatus
cipherPerformOp(CpaInstanceHandle cyInstHandle, CpaCySymSessionCtx sessionCtx)
{
	... ...
        
	COMPLETION_INIT(&complete);

    status = cpaCySymPerformOp(cyInstHandle,
        (void *)&complete, /* data sent as is to the callback function*/
        pOpData,           /* operational data struct */
        pBufferList,       /* source buffer list */
        pBufferList,       /* same src & dst for an in-place operation*/
        NULL);
    
    ... ...  
}
8)Wait for Completion

通过信号量(PV操作)来判断加速卡是否完成所进行的操作()。

if (!COMPLETION_WAIT(&complete, TIMEOUT_MS)) {
    PRINT_ERR("timeout or interruption in cpaCySymPerformOp\n");
    status = CPA_STATUS_FAIL;
}
9)Wait for Outstanding Requests

在实际的使用过程中,一个会话上可能同时存在多个待处理的数据报文。因此在删除会话之前,通过调用次此函数等待会话上所有的操作的完成,之后再进行会话删除操作。

symSessionWaitForInflightReq(sessionCtx);
10)Remove Cipher Session
   sessionStatus = cpaCySymRemoveSession(cyInstHandle, sessionCtx);
  • 此时查询统计信息,这对于调试很有用。 请注意,某些实现还可以通过其他机制(例如/ proc虚拟文件系统)来获取统计信息。
  • 最后,通过释放内存,停止实例等进行清理。
  • 从Cryptographic API v2.2开始,实现了两个新功能:
    • cpaCySymUpdateSessioncpaCySymSessionInUse
    • 函数cpaCySymUpdateSession可用于更新会话的某些参数,例如密码密钥,密码方向和身份验证密钥。 cpaCySymSessionInUse,查询指定会话上是否有未完成的请求。
    • 如果有用户尝试删除的会话的未完成请求,则cpaCySymRemoveSession将失败。
    • 建议在删除会话之前使用cpaCySymSessionInUse等待所有未完成的请求完成。(这里和symSessionWaitForInflightReq函数的作用是一致的,根据官方提供的文档,symSessionWaitForInflightReq中调用到了cpaCySymSessionInUse)
11)Stop Polling and Stop Instance

停止进行轮询,停止instance。

    sampleCyStopPolling();

    PRINT_DBG("cpaCyStopInstance\n");
    cpaCyStopInstance(cyInstHandle);
2.1.5 Hash操作

该示例主要为了演示使用对称API进行哈希操作的用法。示例中使用MD5算法进行的哈希操作。进行哈希操作的流程与加密操作基本一致,这里再做进一步说明:

  • 获取实例(Instance)
  • 设置地址转换函数
  • 启动会话
  • 获取会话使用空间大小
  • 内存申请
  • 初始化会话信息
  • 执行哈希操作
    • 分配所需空间
    • 填充CpaCySymOpData、CpaBufferList数据结构
    • 执行对应操作
    • 比较计算的摘要信息是否一致。
  • 删除会话、释放内存

qat1.5.l.1.13.0-19\quickassist\lookaside\access_layer\src\sample_code\functional\sym\hash_sample


  • 执行哈希操作的流程框架
CpaStatus
hashSample(void)
{
    CpaStatus status = CPA_STATUS_SUCCESS;
    Cpa32U sessionCtxSize = 0;
    CpaInstanceHandle cyInstHandle = NULL;
    CpaCySymSessionCtx sessionCtx = NULL;
    CpaCySymSessionSetupData sessionSetupData = {0};
    CpaCySymStats64 symStats = {0};

    /*
     * In this simplified version of instance discovery, we discover
     * exactly one instance of a crypto service.
     */
    sampleCyGetInstance(&cyInstHandle);
    if (cyInstHandle == NULL)
    {
        return CPA_STATUS_FAIL;
    }

    /* Start Cryptographic component */
    PRINT_DBG("cpaCyStartInstance\n");
    status = cpaCyStartInstance(cyInstHandle);

    if(CPA_STATUS_SUCCESS == status)
    {
       /*
        * Set the address translation function for the instance
        */
        status = cpaCySetAddressTranslation(cyInstHandle, sampleVirtToPhys);
    }

    if (CPA_STATUS_SUCCESS == status)
    {
       /*
        * If the instance is polled start the polling thread. Note that
        * how the polling is done is implementation-dependant.
        */
        sampleCyStartPolling(cyInstHandle);

       /*
        * We now populate the fields of the session operational data and create
        * the session.  Note that the size required to store a session is
        * implementation-dependent, so we query the API first to determine how
        * much memory to allocate, and then allocate that memory.
        */
//<snippet name="initSession">
        /* populate symmetric session data structure
         * for a plain hash operation */
        sessionSetupData.sessionPriority = CPA_CY_PRIORITY_NORMAL;
        sessionSetupData.symOperation = CPA_CY_SYM_OP_HASH;
        sessionSetupData.hashSetupData.hashAlgorithm = CPA_CY_SYM_HASH_MD5;
        sessionSetupData.hashSetupData.hashMode = CPA_CY_SYM_HASH_MODE_PLAIN;
        sessionSetupData.hashSetupData.digestResultLenInBytes = DIGEST_LENGTH;
        /* Place the digest result in a buffer unrelated to srcBuffer */
        sessionSetupData.digestIsAppended = CPA_FALSE;
        /* Generate the digest */
        sessionSetupData.verifyDigest = CPA_FALSE;
//</snippet>

        /* Determine size of session context to allocate */
        PRINT_DBG("cpaCySymSessionCtxGetSize\n");
        status = cpaCySymSessionCtxGetSize(cyInstHandle,
                    &sessionSetupData, &sessionCtxSize);
    }

    if (CPA_STATUS_SUCCESS == status)
    {
        /* Allocate session context */
        status = PHYS_CONTIG_ALLOC(&sessionCtx, sessionCtxSize);
    }

    if (CPA_STATUS_SUCCESS == status)
    {
        /* Initialize the Hash session */
        PRINT_DBG("cpaCySymInitSession\n");
        status = cpaCySymInitSession(cyInstHandle,
                    symCallback, &sessionSetupData, sessionCtx);
    }

    if (CPA_STATUS_SUCCESS == status)
    {
        CpaStatus sessionStatus = CPA_STATUS_SUCCESS;

        /* Perform Hash operation */
        status = hashPerformOp(cyInstHandle, sessionCtx);

        /* Remove the session - session init has already succeeded */
        PRINT_DBG("cpaCySymRemoveSession\n");
        sessionStatus = cpaCySymRemoveSession(
                            cyInstHandle, sessionCtx);

        /* maintain status of remove session only when status of all operations
         * before it are successful. */
        if (CPA_STATUS_SUCCESS == status)
        {
            status = sessionStatus;
        }
    }

    if (CPA_STATUS_SUCCESS == status)
    {
        /* Query symmetric statistics */
        status = cpaCySymQueryStats64(cyInstHandle, &symStats);

        if (CPA_STATUS_SUCCESS != status)
        {
            PRINT_ERR("cpaCySymQueryStats failed, status = %d\n", status);
        }
        else
        {
            PRINT_DBG("Number of symmetric operation completed: %llu\n",
                    (unsigned long long)symStats.numSymOpCompleted);
        }
    }

    /* Clean up */

    /* Free session Context */
    PHYS_CONTIG_FREE(sessionCtx);

    /* Stop the polling thread */
    sampleCyStopPolling();

    PRINT_DBG("cpaCyStopInstance\n");
    cpaCyStopInstance(cyInstHandle);

    if (CPA_STATUS_SUCCESS == status)
    {
        PRINT_DBG("Sample code ran successfully\n");
    }
    else
    {
        PRINT_DBG("Sample code failed with status of %d\n", status);
    }

    return status;
}
  • 哈希操作的详细步骤
static CpaStatus
hashPerformOp(CpaInstanceHandle cyInstHandle, CpaCySymSessionCtx sessionCtx)
{
    CpaStatus status = CPA_STATUS_SUCCESS;
    Cpa8U  *pBufferMeta = NULL;
    Cpa32U bufferMetaSize = 0;
    CpaBufferList *pBufferList = NULL;
    CpaFlatBuffer *pFlatBuffer = NULL;
    CpaCySymOpData *pOpData = NULL;
    Cpa32U bufferSize = sizeof(vectorData) + DIGEST_LENGTH;
    Cpa32U numBuffers = 1;  /* only using 1 buffer in this case */
    /* allocate memory for bufferlist and array of flat buffers in a contiguous
     * area and carve it up to reduce number of memory allocations required. */
    Cpa32U bufferListMemSize = sizeof(CpaBufferList) + (numBuffers * sizeof(CpaFlatBuffer));
    Cpa8U  *pSrcBuffer = NULL;
    Cpa8U  *pDigestBuffer = NULL;

    /* The following variables are allocated on the stack because we block
     * until the callback comes back. If a non-blocking approach was to be
     * used then these variables should be dynamically allocated */
    struct COMPLETION_STRUCT complete;

    /* get meta information size */
    PRINT_DBG("cpaCyBufferListGetMetaSize\n");
    status = cpaCyBufferListGetMetaSize( cyInstHandle, numBuffers, &bufferMetaSize);

    if (CPA_STATUS_SUCCESS == status)
    {
        status = PHYS_CONTIG_ALLOC(&pBufferMeta, bufferMetaSize);
    }

    if (CPA_STATUS_SUCCESS == status)
    {
        status = OS_MALLOC(&pBufferList, bufferListMemSize);
    }

    if (CPA_STATUS_SUCCESS == status)
    {
        status = PHYS_CONTIG_ALLOC(&pSrcBuffer, bufferSize);
    }

    if (CPA_STATUS_SUCCESS == status)
    {
        /* copy vector into buffer */
        memcpy(pSrcBuffer, vectorData, sizeof(vectorData));

        pDigestBuffer = pSrcBuffer + sizeof(vectorData);/*填充摘要部分的起始地址*/
        /* increment by sizeof(CpaBufferList) to get at the
         * array of flatbuffers */
        pFlatBuffer = (CpaFlatBuffer *) (pBufferList + 1);

        pBufferList->pBuffers = pFlatBuffer;
        pBufferList->numBuffers = 1;
        pBufferList->pPrivateMetaData = pBufferMeta;

        pFlatBuffer->dataLenInBytes = bufferSize;
        pFlatBuffer->pData = pSrcBuffer;

        status = OS_MALLOC(&pOpData, sizeof(CpaCySymOpData));
    }

    if (CPA_STATUS_SUCCESS == status)
    {
//<snippet name="opData">
        pOpData->sessionCtx = sessionCtx;
        pOpData->packetType = CPA_CY_SYM_PACKET_TYPE_FULL;
        pOpData->hashStartSrcOffsetInBytes = 0;
        pOpData->messageLenToHashInBytes = sizeof(vectorData);
        pOpData->pDigestResult = pDigestBuffer;
//</snippet>
    }

    if (CPA_STATUS_SUCCESS == status)
    {
        /** initialisation for callback; the "complete" variable is used by the
         * callback function to indicate it has been called*/
        COMPLETION_INIT((&complete));

        PRINT_DBG("cpaCySymPerformOp\n");

        /** Perform symmetric operation */
        status = cpaCySymPerformOp(cyInstHandle,
                (void *)&complete, /* data sent as is to the callback function*/
                pOpData,           /* operational data struct */
                pBufferList,       /* source buffer list */
                pBufferList,       /* same src & dst for an in-place operation*/
                NULL);

        if (CPA_STATUS_SUCCESS != status)
        {
            PRINT_ERR("cpaCySymPerformOp failed. (status = %d)\n", status);
        }

        if (CPA_STATUS_SUCCESS == status)
        {
            /** wait until the completion of the operation*/
            if (!COMPLETION_WAIT((&complete), TIMEOUT_MS))
            {
                PRINT_ERR("timeout or interruption in cpaCySymPerformOp\n");
                status = CPA_STATUS_FAIL;
            }
        }

        if (CPA_STATUS_SUCCESS == status)
        {
            if (0 == memcmp(digest, pOpData->pDigestResult, DIGEST_LENGTH))
            {
                PRINT_DBG("Digest matches expected output\n");
            }
            else
            {
                PRINT_DBG("Digest does not match expected output\n");
                status = CPA_STATUS_FAIL;
            }
        }
    }

    /* At this stage, the callback function should have returned,
     * so it is safe to free the memory */
    PHYS_CONTIG_FREE(pSrcBuffer);
    OS_FREE(pBufferList);
    PHYS_CONTIG_FREE(pBufferMeta);
    OS_FREE(pOpData);

    COMPLETION_DESTROY(&complete);

    return status;
}

2.1.6 Hash a File

对一个文件进行哈希操作的处理流程与上述的哈希操作流程基本一致,只是在计算数据时有所不同:为了执行对文件进行哈希的操作,将数据从文件读取到源缓冲区,并在packetType设置为CPA_CY_SYM_PACKET_TYPE_PARTIAL的情况下重复调用对称API。 到达文件末尾时,将使用packetType设置为CPA_CY_SYM_PACKET_TYPE_PARTIAL_LAST, 然后调用API计算最后的一包数据。 哈希值仅在最后一次调用时产生API。

if (CPA_STATUS_SUCCESS == status)
{
       /** initialisation for callback; the "complete" variable is used by the
         * callback function to indicate it has been called*/
        COMPLETION_INIT((&complete));

//<snippet name="hashFile">
       while(!feof(srcFile))
       {
            /* read from file into src buffer */
            pBufferList->pBuffers->dataLenInBytes =
                    fread(pSrcBuffer, 1, SAMPLE_BUFF_SIZE, srcFile);

            /* If we have reached the end of file set the last partial flag */
/****************************************************************/       
            if(feof(srcFile))
            {
                pOpData->packetType = CPA_CY_SYM_PACKET_TYPE_LAST_PARTIAL;
            }
            else
            {
                pOpData->packetType = CPA_CY_SYM_PACKET_TYPE_PARTIAL;
            }
 /****************************************************************/
           pOpData->sessionCtx = sessionCtx;
            pOpData->hashStartSrcOffsetInBytes = 0;
            pOpData->messageLenToHashInBytes = pBufferList->pBuffers->dataLenInBytes;
            pOpData->pDigestResult = pDigestBuffer;

            PRINT_DBG("cpaCySymPerformOp\n");
            /** Perform symmetric operation */
            status = cpaCySymPerformOp(cyInstHandle,
                (void *)&complete, /* data sent as is to the callback function*/
                pOpData,           /* operational data struct */
                pBufferList,       /* source buffer list */
                pBufferList,       /* same src & dst for an in-place operation*/
                NULL);

            if (CPA_STATUS_SUCCESS != status)
            {
               PRINT_ERR("cpaCySymPerformOp failed. (status = %d)\n", status);
               break;
            }

            if (CPA_STATUS_SUCCESS == status)
            {
                /** wait until the completion of the operation*/
                if (!COMPLETION_WAIT((&complete), TIMEOUT_MS))
                {
                   PRINT_ERR("timeout or interruption in cpaCySymPerformOp\n");
                   status = CPA_STATUS_FAIL;
                   break;
                }
            }
}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叨陪鲤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值