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开始,实现了两个新功能:
- cpaCySymUpdateSession 和cpaCySymSessionInUse
- 函数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;
}
}
}
Intel® QAT加速卡之加密、哈希操作流程和示例的更多相关文章
- Intel® QAT 加速卡之IPSec示例
Intel QAT 加速卡之IPSec示例 文章目录 Intel QAT 加速卡之IPSec示例 1. QAT处理IPSec入站报文 2. QAT处理IPSec出站报文 3. 组织架构 4. 示例源码 ...
- Intel® QAT加速卡之逻辑实例
Intel QAT加速卡逻辑实例 1. QAT相关的名词组织关系 在本手册中描述的平台上,处理器可以连接到一个或多个英特尔通信芯片组8925至8955系列(PCH)设备. 从软件角度来看,每个PCH设 ...
- Intel® QAT加速卡之性能简介
Intel QuickAssist Adapter 8950 设备简介 支持英特尔QuickAssist技术的英特尔QuickAssist适配器提供加密加速和压缩加速服务. 1. Key featur ...
- Intel® QAT加速卡之Linux上编程说明
QAT Software for Linux 1. Introduction 该程序员指南提供了有关软件体系结构和使用指南的信息. 相关的英特尔QAT软件库文档中记录了有关使用英特尔QuickAssi ...
- Intel® QAT加速卡之同步异步模式
QAT 的两种操作模式 Intel QAT API同时支持同步和异步两种操作模式. 为了获得最佳性能,该应用程序应能够向加速引擎提交多个未完成的请求. 提交多个未完成的请求可最大程度地减少加速引擎上的 ...
- Intel® QAT加速卡之Ring & Ring Bank
1. QAT的应用模式 Intel 通讯系列芯片对于每种受支持的加速服务(加密,数据压缩),都支持以下应用模式: 内核模式,其中应用程序和加速服务都在内核中运行空间. 用户空间直接访问在用户空间中运行 ...
- Intel® QAT加速卡之编程demo框架
QAT demo流程框架 示例一: 代码路径:qat1.5.l.1.13.0-19\quickassist\lookaside\access_layer\src\sample_code\functio ...
- Intel® QAT 加速卡之数据面流程(图)
QAT数据面流程 sessionSetupData数据结构 pOpData数据结构
- .Net 加密 哈希
一.DES加解密 DES一共就有4个参数参与运作:明文.密文.密钥.向量.其中这4者的关系可以理解为: 密文=明文+密钥+向量: 明文=密文-密钥-向量: 为什么要向量这个参数呢?因为如果有一篇文章, ...
随机推荐
- 开机时自动启动的AutoHotkey脚本 2019年10月09日
;;; 开机时自动启动的AutoHotkey脚本 2019年10月09日;; http://www.autoahk.com/archives/16600; https://www.cnblogs.co ...
- ASP.NET Corec初步使用Quartz.NET
一.什么是Quartz.NET? Quartz.NET 是一个功能齐全的开源作业调度系统,可用于从最小的应用程序到大型企业系统. Quartz.NET是纯净的,它是一个.Net程序集,是非常流行的Ja ...
- Cloud-init的安装和使用 --以ubuntu-server-14.04-amd64为例
by hyc 1.Cloud-init安装 已有了一个安装好系统的镜像. 镜像名:ubuntu-test-14.04-server-amd64.img 用户名:user 密码:1 主机名:ubuntu ...
- TCP实现聊天
TCP实现聊天 IO流关闭是简写的,正常写要判断是否为null 客户端:(最好捕获异常) 1.连接服务器Socket 2.发送消息 package net.TCPChat; import java.i ...
- Android Hello World程序开发过程
按照Building Your First App,详细过程如下: 安装SDK(如果网速慢,需要用离线安装的方法,见笔记 离线安装Android SDK的方法 ): 采用命令行开发方法(不用装Ecli ...
- Golang语言系列-10-包
包 自定义包 package _0calc import ( "fmt" ) /* [Go语言的包] 在工程化的Go语言开发项目中,Go语言的源码复用是建立在包(package)基 ...
- MySQL-08-索引简介
B树 基于不同的查找算法分类介绍 B*Tree B-tree B+Tree 在范围查询方面提供了更好的性能(> < >= <= like) 索引简介 索引作用 提供了类似于书中 ...
- 【笔记】scikit-learn中的Scaler(归一化)
scikit-learn中的数据归一化 在机器学习使用数据归一化的时候有一个重要的注意事项 我们对训练数据进行均值和方差的处理,得到mean_train以及std_train,但是在对测试数据进行归一 ...
- Python - typing 模块 —— Callable
前言 typing 是在 python 3.5 才有的模块 前置学习 Python 类型提示:https://www.cnblogs.com/poloyy/p/15145380.html 常用类型提示 ...
- BuildPack 打包
无需 dockerfile,使用 buildpacks 打包镜像 书接上文,聪明如你已经发现项目中没有定义 dockerfile,但我们依然能打镜像,是如何做到的呢?正如上面提到的 gradle 的 ...