Overview
The Linux kernel provides a complete cryptographic algorithm framework (Crypto API), supporting hardware acceleration and software implementation for various cryptographic operations. In actual driver development, we often need to integrate multiple cryptographic algorithms (such as SHA256, AES-CTR, RSA2048, etc.) into the same cryptographic hardware device, utilizing its dedicated computational capabilities to enhance system performance and reduce CPU load.
To maintain code maintainability and scalability, it is recommended to place different types of algorithm implementations in separate files and manage devices and algorithm registrations through a unified core module. A typical driver code organization structure is as follows:
$ tree
├── demo_crypto_core.c
├── demo_crypto_core.h
├── demo_crypto_hash.c
├── demo_crypto_cipher.c
├── demo_crypto_asym.c
- demo_crypto_core.c: Core crypto driver implementation, responsible for device registration, algorithm registration, etc.
- demo_crypto_core.h: Core crypto driver header file, defining crypto devices, algorithm instance abstractions, algorithm contexts, and request contexts, etc.
- demo_crypto_hash.c: Hash algorithm driver implementation.
- demo_crypto_cipher.c: Symmetric encryption algorithm driver implementation.
- demo_crypto_asym.c: Asymmetric encryption algorithm driver implementation.
This article focuses on the adaptation process and methods of the hash algorithm, detailing how to integrate the algorithm into the Crypto engine framework through a specific example (SHA256) and fully utilize hardware acceleration capabilities.
To simplify the example, this article uses SHA256 as an example, employing the software implementation in the kernel to simulate the hardware processing flow, emphasizing the general methods and key implementation steps for driver adaptation, which can be replaced with hardware operations in actual development.
Core Driver
demo_crypto_core.h
First, define the abstraction of the crypto device in the <span>demo_crypto_core.h</span> header file:
/* crypto device */
struct demo_crypto_dev {
struct device *dev;/* Device */
void __iomem *reg; /* Register base address */
int irq; /* Interrupt number */
struct crypto_engine *engine;/* Engine */
struct completion completion;/* Completion */
struct completion dma_completion;/* DMA completion */
irqreturn_t (*irq_handle)(int irq, void *dev_id); /* Interrupt handler */
};
Next, define an algorithm instance to specify the algorithms that need to be registered in the system.
/* Algorithm instance */
struct demo_crypto_alg {
struct demo_crypto_dev *crypto_dev;/* Crypto device */
const char *name; /* Algorithm name */
enum demo_alg_type type; /* Algorithm type */
u32 algo; /* Algorithm ID */
union {
struct ahash_alg hash;/* Hash algorithm */
struct skcipher_alg cipher;/* Symmetric encryption algorithm */
struct akcipher_alg asym;/* Asymmetric encryption algorithm */
} alg;
};
Then, define some structures required by specific algorithms, such as the hash algorithm, which needs to define context and request context:
/* Algorithm types */
enum demo_alg_type {
ALG_TYPE_HASH,
ALG_TYPE_CIPHER,
ALG_TYPE_ASYM,
};
/* Hash algorithms */
enum demo_hash_algo {
HASH_ALGO_MD5,
HASH_ALGO_SHA1,
HASH_ALGO_SHA224,
HASH_ALGO_SHA256,
HASH_ALGO_SHA384,
HASH_ALGO_SHA512,
HASH_ALGO_SM3,
};
/* Hash algorithm context */
struct demo_hash_ctx {
struct crypto_engine_ctx enginectx;/* Engine context */
struct demo_crypto_dev *crypto_dev;/* Crypto device */
/* for fallback */
struct crypto_ahash *fallback_tfm;/* Hash algorithm fallback */
};
#define HASH_BLOCK_SIZE_MAX 256
/* Hash algorithm request context */
struct demo_hash_rctx {
unsigned int total_len; /* Total request length */
struct scatterlist *sg;/* Scatterlist */
int nsg; /* Number of mapped scatterlists */
unsigned int sg_off; /* Current scatterlist offset */
u8 buf[HASH_BLOCK_SIZE_MAX] __aligned(sizeof(u32)); /* Cached data */
size_t buf_len; /* Cached data length */
/* for fallback request */
struct ahash_request fallback_req;/* Hash algorithm fallback request */
};
The structure <span>struct demo_hash_ctx</span> defines the context for transformation operations. It is important to note that <span>enginectx</span> must be the first member of the structure because the engine framework will force this context to be converted to <span>struct crypto_engine_ctx</span>, calling the request callback function implemented by the driver. The structure <span>struct demo_hash_rctx</span> defines the hash request context.
There is a very nice feature called algorithm fallback, which mainly addresses some hardware limitations, such as hardware engines not supporting fragmentation, DMA not supporting non-word-aligned addresses, etc. These can all be handled by the crypto framework’s fallback implementation.
Finally, define a macro to facilitate the subsequent definition of hash algorithm instances.
/* The kernel's default software implementation priority is 100. If hardware acceleration is needed, this needs to be increased, e.g., to 300 */
#define DEMO_CRYPTO_PRIORITY 300
/* Hash algorithm instance definition */
#define DEMO_HASH_ALGO_INIT(hash_algo, algo_name) {\
.name = #algo_name,\
.type = ALG_TYPE_HASH,\
.algo = HASH_ALGO_##hash_algo,\
.alg.hash = {\
.init = demo_hash_init,\
.update = demo_hash_update,\
.final = demo_hash_final,\
.finup = demo_hash_finup,\
.export = demo_hash_export,\
.import = demo_hash_import,\
.digest = demo_hash_digest,\
.halg = {\
.digestsize = hash_algo##_DIGEST_SIZE,\
.statesize = sizeof(struct demo_hash_rctx),\
.base = {\
.cra_name = #algo_name,\
.cra_driver_name = #algo_name"-demo",\
.cra_priority = DEMO_CRYPTO_PRIORITY,\
.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |\
CRYPTO_ALG_ASYNC |\
CRYPTO_ALG_NEED_FALLBACK,\
.cra_blocksize = hash_algo##_BLOCK_SIZE,\
.cra_ctxsize = sizeof(struct demo_hash_ctx),\
.cra_alignmask = 3,\
.cra_init = demo_hash_cra_init,\
.cra_exit = demo_hash_cra_exit,\
.cra_module = THIS_MODULE,\
} \
} \
} \
}
- name: Algorithm name
- type: Algorithm type
- algo: Specific hash algorithm, such as HASH_ALGO_SHA256, HASH_ALGO_MD5, etc.
- alg.hash: Function interfaces that the driver needs to implement, such as hash update, hash finish, and one-time digest calculation, etc.
- digestsize: Digest length
- statesize: Block size for intermediate state transformation.
- cra_name: Generic name of the transformation algorithm, such as sha256.
- cra_driver_name: Unique name of the transformation provider, such as sha256-demo.
- cra_priority: Priority of the transformation implementation, which needs to be greater than the kernel’s self-implementation priority of 100.
- cra_flags: Transformation flags, such as asynchronous flags, need for fallback processing, etc.
- cra_blocksize: Minimum block size for this transformation, such as 64 bytes for the sha256 algorithm.
- cra_ctxsize: Size of the transformation operation context, used to inform the kernel Crypto API of the memory size needed for the transformation context.
- cra_alignmask: Alignment mask for input and output data buffers, where the value 3 requires word alignment.
- cra_init: Initialize the cryptographic transformation object.
- cra_exit: Release the cryptographic transformation object.
- cra_module: Owner of the transformation implementation.
demo_crypto_core.c
The file <span>demo_crypto_core.c</span> is a standard platform device driver model, completing device registration, algorithm registration, interrupt handling, device release, and other functions. The code for device registration is as follows:
static int demo_crypto_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct demo_crypto_dev *crypto_dev;
int err;
/* Allocate device information structure */
crypto_dev = devm_kzalloc(dev, sizeof(*crypto_dev), GFP_KERNEL);
if (!crypto_dev) {
dev_err(dev, "Failed to allocate memory\n");
return -ENOMEM;
}
/* Map device resources to memory space */
crypto_dev->reg = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(crypto_dev->reg)) {
dev_err(dev, "Failed to map device registers\n");
err = PTR_ERR(crypto_dev->reg);
goto error;
}
/* Get device interrupt number */
crypto_dev->irq = platform_get_irq(pdev, 0);
if (crypto_dev->irq <= 0) {
dev_err(dev, "Failed to get irq %d\n", crypto_dev->irq);
err = crypto_dev->irq;
goto error;
}
/* Request interrupt handling */
err = devm_request_irq(dev, crypto_dev->irq, demo_crypto_irq_handle, IRQF_SHARED,
DRIVER_NAME, crypto_dev);
if (err) {
dev_err(dev, "Failed to request IRQ\n");
goto error;
}
/* Set device data */
crypto_dev->dev = dev;
platform_set_drvdata(pdev, crypto_dev);
/* Initialize cryptographic engine */
crypto_dev->engine = crypto_engine_alloc_init(dev, true);
if (!crypto_dev->engine) {
dev_err(dev, "Failed to allocate crypto engine\n");
err = -ENOMEM;
goto error;
}
/* Start cryptographic engine */
err = crypto_engine_start(crypto_dev->engine);
if (err) {
dev_err(dev, "Failed to start crypto engine\n");
goto error;
}
/* Initialize completion semaphore */
init_completion(&crypto_dev->completion);
init_completion(&crypto_dev->dma_completion);
/* Register cryptographic algorithms */
err = demo_crypto_register(crypto_dev);
if (err) {
dev_err(dev, "Failed to register crypto algorithms\n");
crypto_engine_exit(crypto_dev->engine);
goto error;
}
dev_info(dev, "Demo Crypto(%s) platform driver probed\n", DRIVER_VERSION);
return 0;
error:
if (crypto_dev) {
devm_kfree(dev, crypto_dev);
}
dev_err(dev, "Demo Crypto(%s) platform driver probe failed\n", DRIVER_VERSION);
return err;
}
During device registration, we will call <span>demo_crypto_register</span> to register cryptographic algorithms. Depending on the type of algorithm, different Crypto API interfaces are called for registration:
- Hash algorithm: crypto_register_ahash
- Symmetric encryption algorithm: crypto_register_skcipher
- Asymmetric encryption algorithm: crypto_register_akcipher
static int demo_crypto_register(struct demo_crypto_dev *crypto_dev)
{
unsigned int i, k;
int err = 0;
unsigned int algs_num;
struct demo_crypto_alg **algs = demo_crypto_get_algs(&algs_num);
dev_dbg(crypto_dev->dev, "%s\n", __func__);
for (i = 0; i < algs_num; i++) {
algs[i]->crypto_dev = crypto_dev;
if (algs[i]->type == ALG_TYPE_HASH) {
err = crypto_register_ahash(&algs[i]->alg.hash);
} elseif (algs[i]->type == ALG_TYPE_CIPHER) {
err = crypto_register_skcipher(&algs[i]->alg.cipher);
} elseif (algs[i]->type == ALG_TYPE_ASYM) {
err = crypto_register_akcipher(&algs[i]->alg.asym);
} else {
dev_err(crypto_dev->dev, "Unknown algorithm type %d\n", algs[i]->type);
}
if (err) {
goto error;
}
}
return 0;
error:
for (k = 0; k < i; k++) {
if (algs[k]->type == ALG_TYPE_HASH) {
crypto_unregister_ahash(&algs[k]->alg.hash);
} elseif (algs[k]->type == ALG_TYPE_CIPHER) {
crypto_unregister_skcipher(&algs[k]->alg.cipher);
} elseif (algs[k]->type == ALG_TYPE_ASYM) {
crypto_unregister_akcipher(&algs[k]->alg.asym);
} else {
// Other algorithm type unregistration handling
}
}
return err;
}
Additionally, we specifically define an array to store the algorithm instances that need to be registered in the system:
static struct demo_crypto_alg *crypto_algs[] = {
/* hash */
&demo_hash_sha256,
/* cipher */
&demo_cipher_aes_ecb,
/* asym */
&demo_asym_rsa,
Add other algorithms here
};
Hash Driver
Since our goal is to master the process and methods of writing hash hardware drivers, the hash algorithm SHA256 we intend to adapt uses the kernel’s implemented interface to simulate the work that needs to be completed for hardware acceleration engine driver adaptation. The hash driver needs to adapt the seven interfaces defined in the algorithm instance above:
- init: Initialize the hash context (called for each new request).
- update: Process input data blocks, updating the hash state (can be called multiple times).
- final: End the hash calculation, output the final digest.
- finup: A combination of
<span>update</span>+<span>final</span>, suitable for certain hardware that can only complete in one step. - digest: A combination of
<span>init</span>+<span>update</span>+<span>final</span>, completing all operations in one step. - export/import: Export/import the intermediate state of the hash, facilitating saving/restoring computation progress.
Since hardware acceleration engines typically complete one-time digest calculations, a common practice for driver adaptation is to only adapt the digest one-time hash interface, while other forms such as update and final are handled by the crypto framework for fallback processing, accumulating data, constructing new requests, and finally calling the digest interface. It is worth noting that when defining the algorithm instance, the fallback flag needs to be declared, i.e., adding <span>.cra_flags</span> with <span>CRYPTO_ALG_NEED_FALLBACK</span>.
Algorithm Instance Initialization and Release
First, the algorithm instance needs to be initialized, mainly setting up the software fallback scheme and engine request callback handling interfaces.
static int demo_hash_cra_init(struct crypto_tfm *tfm)
{
/* Get algorithm context */
struct demo_hash_ctx *ctx = crypto_tfm_ctx(tfm);
/* Get hash algorithm definition */
struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg);
struct demo_crypto_alg *algt;
/* Get algorithm instance and associate it with the crypto device */
algt = container_of(alg, struct demo_crypto_alg, alg.hash);
ctx->crypto_dev = algt->crypto_dev;
dev_dbg(ctx->crypto_dev->dev, "%s\n", __func__);
/* Fallback handling */
ctx->fallback_tfm = crypto_alloc_ahash(crypto_tfm_alg_name(tfm), 0,
CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(ctx->fallback_tfm)) {
dev_err(ctx->crypto_dev->dev, "Could not load fallback driver.\n");
return PTR_ERR(ctx->fallback_tfm);
}
/* Set request context size */
crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
sizeof(struct demo_hash_rctx) + crypto_ahash_reqsize(ctx->fallback_tfm));
/* Set engine request callback interface */
ctx->enginectx.op.do_one_request = demo_hash_do_one_request;
ctx->enginectx.op.prepare_request = demo_hash_prepare_request;
ctx->enginectx.op.unprepare_request = demo_hash_unprepare_request;
return 0;
}
In the hash algorithm instance release function, it is necessary to release the fallback processing transformation.
static void demo_hash_cra_exit(struct crypto_tfm *tfm)
{
struct demo_hash_ctx *ctx = crypto_tfm_ctx(tfm);
crypto_free_ahash(ctx->fallback_tfm);
}
Hash Interface
The hash interface only implements the digest one-time digest calculation, while others are handled by the crypto framework for fallback processing.
static int zero_message_process(struct ahash_request *req)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
int digest_size = crypto_ahash_digestsize(tfm);
switch (digest_size) {
case SHA1_DIGEST_SIZE:
memcpy(req->result, sha1_zero_message_hash, digest_size);
break;
case SHA256_DIGEST_SIZE:
memcpy(req->result, sha256_zero_message_hash, digest_size);
break;
case MD5_DIGEST_SIZE:
memcpy(req->result, md5_zero_message_hash, digest_size);
break;
default:
return -EINVAL;
}
return 0;
}
static int demo_hash_digest(struct ahash_request *req)
{
/* Get hash transformation */
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
/* Get hash algorithm request context */
// struct demo_hash_rctx *rctx = ahash_request_ctx(req);
/* Get hash algorithm context */
struct demo_hash_ctx *ctx = crypto_ahash_ctx(tfm);
dev_dbg(ctx->crypto_dev->dev, "%s\n", __func__);
/* Empty message, return fixed digest value */
if (!req->nbytes) {
return zero_message_process(req);
}
/* Transfer the request to the engine queue */
return crypto_transfer_hash_request_to_engine(ctx->crypto_dev->engine, req);
}
For empty message requests, a fixed digest value needs to be returned. Other hash requests are transferred to the engine queue for processing.
The remaining six hash interfaces are handled by the framework for fallback processing, such as the update interface implemented as follows:
static int demo_hash_update(struct ahash_request *req)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct demo_hash_rctx *rctx = ahash_request_ctx(req);
struct demo_hash_ctx *ctx = crypto_ahash_ctx(tfm);
dev_dbg(ctx->crypto_dev->dev, "%s\n", __func__);
ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
rctx->fallback_req.base.flags = req->base.flags &
CRYPTO_TFM_REQ_MAY_SLEEP;
rctx->fallback_req.nbytes = req->nbytes;
rctx->fallback_req.src = req->src;
return crypto_ahash_update(&rctx->fallback_req);
}
Request Processing
Once the cryptographic engine framework receives a request, it will queue it for processing, calling the callback interface. The core interface here is <span>do_one_request</span>:
static int demo_hash_do_one_request(struct crypto_engine *engine, void *areq)
{
int err;
unsigned int digest_size;
u32 algo;
/* Get the original hash request */
struct ahash_request *req = container_of(areq, struct ahash_request, base);
/* Get hash transformation */
struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
/* Get hash algorithm context */
struct demo_hash_ctx *ctx = crypto_ahash_ctx(tfm);
/* Get hash request context */
struct demo_hash_rctx *rctx = ahash_request_ctx(req);
/* Get crypto transformation */
struct crypto_tfm *crt = crypto_ahash_tfm(tfm);
/* Get crypto algorithm definition */
struct crypto_alg *base = crt->__crt_alg;
/* Get hash algorithm definition */
struct ahash_alg *alg = container_of(base, struct ahash_alg, halg.base);
struct demo_crypto_alg *algt;
/* Get hash algorithm instance */
algt = container_of(alg, struct demo_crypto_alg, alg.hash);
dev_dbg(ctx->crypto_dev->dev, "%s\n", __func__);
dev_dbg(ctx->crypto_dev->dev, "%s: algo: %s, req->nbytes = %d\n", __func__, algt->name, req->nbytes);
/* Get digest length */
digest_size = crypto_ahash_digestsize(tfm);
algo = algt->algo;
rctx->total_len = req->nbytes;
rctx->sg = req->src;
rctx->sg_off = 0;
rctx->buf_len = 0;
/* Calculate digest */
err = demo_hash_compute(ctx->crypto_dev, rctx, req->result);
if (err) {
dev_err(ctx->crypto_dev->dev, "Hash compute error: %d\n", err);
goto exit;
}
exit:
/* Complete hash request */
crypto_finalize_hash_request(ctx->crypto_dev->engine, req, err);
return 0;
}
The length of each request is <span>req->nbytes</span>, and the data is placed in the <span>req->src</span> scatterlist. Typically, if there is a hardware acceleration engine, it can start the hardware, trigger DMA transfer, and compute the hash. The computed output digest value is returned to the caller through <span>req->result</span>, and finally, the <span>crypto_finalize_hash_request</span> function must be called to complete the hash request; otherwise, it will cause the request to block.
Here, we use the software implementation to compute the message’s digest value. The hash request is a series of scatterlists, and hardware hash calculations typically require integer multiples of block sizes. Therefore, we need to converge the sg into a buffer through <span>demo_hash_append_sg</span> and then hand it over to the hardware for computation. The hash calculation calls the kernel’s software implementation interfaces:
- sha256_init: Hash initialization
- sha256_update: Hash data update
- sha256_final: Hash finish, output digest result
static void demo_hash_append_sg(struct demo_hash_rctx *rctx)
{
size_t count;
/* Continuously converge to the cache until full */
while ((rctx->buf_len < sizeof(rctx->buf)) && rctx->total_len) {
/* Take the minimum: remaining data length of current sg and new request data length */
count = min(rctx->sg->length - rctx->sg_off, rctx->total_len);
/* Take the minimum: remaining data length that can be stored in the cache */
count = min(count, sizeof(rctx->buf) - rctx->buf_len);
/* No available data in current sg */
if (count <= 0) {
/* Not the last sg, continue to the next */
if ((rctx->sg->length == 0) && !sg_is_last(rctx->sg)) {
rctx->sg = sg_next(rctx->sg);
continue;
} else {
/* Break the loop */
break;
}
}
/* Copy count data from sg at sg_off to buf */
scatterwalk_map_and_copy(rctx->buf + rctx->buf_len, rctx->sg,
rctx->sg_off, count, 0);
/* Update data length status */
rctx->buf_len += count;
rctx->sg_off += count;
rctx->total_len -= count;
/* Reached the length of current sg, indicating it has been processed */
if (rctx->sg_off == rctx->sg->length) {
/* Continue to the next sg */
rctx->sg = sg_next(rctx->sg);
/* If sg is NULL, it means all data has been processed */
if (rctx->sg) {
rctx->sg_off = 0;
} else {
rctx->total_len = 0;
}
}
}
}
static int demo_hash_compute(struct demo_crypto_dev *crypto_dev, struct demo_hash_rctx *rctx, u8 *digest)
{
int err = 0;
struct sha256_state state;
dev_dbg(crypto_dev->dev, "%s\n", __func__);
sha256_init(&state);
/* If the cache can be filled, process it */
while ((rctx->total_len >= sizeof(rctx->buf)) ||
(rctx->buf_len + rctx->total_len >= sizeof(rctx->buf))) {
demo_hash_append_sg(rctx);
sha256_update(&state, rctx->buf, rctx->buf_len);
rctx->buf_len = 0; /* Clear cache */
}
demo_hash_append_sg(rctx);
sha256_update(&state, rctx->buf, rctx->buf_len);
rctx->buf_len = 0;
sha256_final(&state, digest);
return err;
}
Finally, the definition of the hash algorithm instance needs to be placed in the cryptographic algorithm array <span>crypto_algs</span>. When we register the driver, we can register this SHA256 algorithm in the system.
struct demo_crypto_alg demo_hash_sha256 = DEMO_HASH_ALGO_INIT(SHA256, sha256);
Driver Testing
Compile the module to generate the files <span>demo_crypto.ko</span> and <span>crypto_engine.ko</span>. Then copy them to the target system, noting that the engine KO must be installed before the driver KO:
$ insmod crypto_engine.ko
$ insmod demo_crypto.ko
[75304.994703] demo-crypto 53050000.crypto: will run requests pump with realtime priority
[75305.009286] demo-crypto 53050000.crypto: Demo Crypto(V0.1) platform driver probed
If the hash algorithm driver has no issues and the functional test passes, it will print logs as above; otherwise, it will print specific failures. After the hash driver loads successfully, we can check if it has been registered successfully through the command:
$ cat /proc/crypto
name : sha256
driver : sha256-demo
module : demo_crypto
priority : 300
refcnt : 1
selftest : passed
internal : no
type : ahash
async : yes
blocksize : 64
digestsize : 32
......
If you want to see more test logs, you can adjust the print level. It can be seen that the system test framework will test all driver interface implementations, different message lengths, non-aligned buffers, and other scenarios:
$ echo 8 > /proc/sys/kernel/printk
$ insmod demo_crypto.ko
[75537.819875] demo-crypto 53050000.crypto: will run requests pump with realtime priority
[75537.828018] demo-crypto 53050000.crypto: demo_crypto_register
[75537.834100] demo-crypto 53050000.crypto: demo_hash_cra_init
[75537.841294] demo-crypto 53050000.crypto: demo_hash_init
[75537.846564] demo-crypto 53050000.crypto: demo_hash_update
[75537.852074] demo-crypto 53050000.crypto: demo_hash_final
[75537.857431] demo-crypto 53050000.crypto: demo_hash_init
[75537.863538] demo-crypto 53050000.crypto: demo_hash_finup
[75537.868917] demo-crypto 53050000.crypto: demo_hash_digest
[75537.874543] demo-crypto 53050000.crypto: demo_hash_init
[75537.879795] demo-crypto 53050000.crypto: demo_hash_update
[75537.885289] demo-crypto 53050000.crypto: demo_hash_final
[75537.890644] demo-crypto 53050000.crypto: demo_hash_digest
[75537.896121] demo-crypto 53050000.crypto: demo_hash_init
[75537.901399] demo-crypto 53050000.crypto: demo_hash_update
[75537.906806] demo-crypto 53050000.crypto: demo_hash_final
[75537.912179] demo-crypto 53050000.crypto: demo_hash_digest
[75537.917594] demo-crypto 53050000.crypto: demo_hash_digest
[75537.923042] demo-crypto 53050000.crypto: demo_hash_init
[75537.928278] demo-crypto 53050000.crypto: demo_hash_export
[75537.933718] demo-crypto 53050000.crypto: demo_hash_import
[75537.939123] demo-crypto 53050000.crypto: demo_hash_update
[75537.944559] demo-crypto 53050000.crypto: demo_hash_final
[75537.949899] demo-crypto 53050000.crypto: demo_hash_init
[75537.955169] demo-crypto 53050000.crypto: demo_hash_update
[75537.960578] demo-crypto 53050000.crypto: demo_hash_final
[75537.965946] demo-crypto 53050000.crypto: demo_hash_init
[75537.971232] demo-crypto 53050000.crypto: demo_hash_finup
[75537.976576] demo-crypto 53050000.crypto: demo_hash_digest
[75537.982050] demo-crypto 53050000.crypto: demo_hash_do_one_request
[75538.002549] demo-crypto 53050000.crypto: demo_hash_init
[75538.007791] demo-crypto 53050000.crypto: demo_hash_update
[75538.013900] demo-crypto 53050000.crypto: demo_hash_final
[75538.019261] demo-crypto 53050000.crypto: demo_hash_digest
[75538.024744] demo-crypto 53050000.crypto: demo_hash_do_one_request
[75538.030846] demo-crypto 53050000.crypto: demo_hash_do_one_request: algo: sha256, req->nbytes = 3
[75538.039671] demo-crypto 53050000.crypto: demo_hash_compute
[75538.045243] demo-crypto 53050000.crypto: demo_hash_init
[75538.050483] demo-crypto 53050000.crypto: demo_hash_update
[75538.055934] demo-crypto 53050000.crypto: demo_hash_final
[75538.061378] demo-crypto 53050000.crypto: demo_hash_digest
[75538.067827] demo-crypto 53050000.crypto: demo_hash_do_one_request
[75538.073278] demo-crypto 53050000.crypto: demo_hash_do_one_request: algo: sha256, req->nbytes = 3
[75538.079671] demo-crypto 53050000.crypto: demo_hash_compute
[75538.085243] demo-crypto 53050000.crypto: demo_hash_digest
[75538.090995] demo-crypto 53050000.crypto: demo_hash_do_one_request
[75538.096121] demo-crypto 53050000.crypto: demo_hash_do_one_request: algo: sha256, req->nbytes = 3
[75538.102602] demo-crypto 53050000.crypto: demo_hash_compute
[75538.108111] demo-crypto 53050000.crypto: demo_hash_init
[75538.113381] demo-crypto 53050000.crypto: demo_hash_update
[75538.118748] demo-crypto 53050000.crypto: demo_hash_update
[75538.124199] demo-crypto 53050000.crypto: demo_hash_final
[75538.129538] demo-crypto 53050000.crypto: demo_hash_digest
[75538.134997] demo-crypto 53050000.crypto: demo_hash_do_one_request
[75538.140097] demo-crypto 53050000.crypto: demo_hash_do_one_request: algo: sha256, req->nbytes = 56
[75538.146063] demo-crypto 53050000.crypto: demo_hash_compute
[75538.151633] demo-crypto 53050000.crypto: demo_hash_init
[75538.156872] demo-crypto 53050000.crypto: demo_hash_update
[75538.162351] demo-crypto 53050000.crypto: demo_hash_final
[75538.167762] demo-crypto 53050000.crypto: demo_hash_digest
[75538.173202] demo-crypto 53050000.crypto: demo_hash_do_one_request
[75538.178278] demo-crypto 53050000.crypto: demo_hash_do_one_request: algo: sha256, req->nbytes = 56
[75538.184714] demo-crypto 53050000.crypto: demo_hash_compute
[75538.190334] demo-crypto 53050000.crypto: demo_hash_digest
[75538.195992] demo-crypto 53050000.crypto: demo_hash_do_one_request
[75538.201097] demo-crypto 53050000.crypto: demo_hash_do_one_request: algo: sha256, req->nbytes = 56
[75538.207602] demo-crypto 53050000.crypto: demo_hash_compute
[75538.213202] demo-crypto 53050000.crypto: demo_hash_init
[75538.218535] demo-crypto 53050000.crypto: demo_hash_export
[75538.223202] demo-crypto 53050000.crypto: demo_hash_import
[75538.227722] demo-crypto 53050000.crypto: demo_hash_update
[75538.232351] demo-crypto 53050000.crypto: demo_hash_export
[75538.236872] demo-crypto 53050000.crypto: demo_hash_import
[75538.241202] demo-crypto 53050000.crypto: demo_hash_update
[75538.245722] demo-crypto 53050000.crypto: demo_hash_final
[75538.250202] demo-crypto 53050000.crypto: demo_hash_init
[75538.254722] demo-crypto 53050000.crypto: demo_hash_update
[75538.259202] demo-crypto 53050000.crypto: demo_hash_final
[75538.263722] demo-crypto 53050000.crypto: demo_hash_init
[75538.268202] demo-crypto 53050000.crypto: demo_hash_finup
[75538.272722] demo-crypto 53050000.crypto: demo_hash_digest
[75538.277202] demo-crypto 53050000.crypto: demo_hash_do_one_request
[75538.281722] demo-crypto 53050000.crypto: demo_hash_do_one_request: algo: sha256, req->nbytes = 1023
[75538.287202] demo-crypto 53050000.crypto: demo_hash_compute
[75538.292722] demo-crypto 53050000.crypto: demo_hash_init
[75538.297202] demo-crypto 53050000.crypto: demo_hash_update
[75538.301722] demo-crypto 53050000.crypto: demo_hash_final
[75538.306202] demo-crypto 53050000.crypto: demo_hash_digest
[75538.310722] demo-crypto 53050000.crypto: demo_hash_do_one_request
[75538.315202] demo-crypto 53050000.crypto: demo_hash_do_one_request: algo: sha256, req->nbytes = 1023
[75538.320722] demo-crypto 53050000.crypto: demo_hash_compute
[75538.325202] demo-crypto 53050000.crypto: demo_hash_init
[75538.329722] demo-crypto 53050000.crypto: demo_hash_update
[75538.334202] demo-crypto 53050000.crypto: demo_hash_update
[75538.338722] demo-crypto 53050000.crypto: demo_hash_final
[75538.343202] demo-crypto 53050000.crypto: demo_hash_digest
[75538.347722] demo-crypto 53050000.crypto: demo_hash_do_one_request
[75538.352202] demo-crypto 53050000.crypto: demo_hash_do_one_request: algo: sha256, req->nbytes = 1023
[75538.356722] demo-crypto 53050000.crypto: demo_hash_compute
[75538.361202] demo-crypto 53050000.crypto: demo_hash_digest
[75538.365722] demo-crypto 53050000.crypto: demo_hash_do_one_request
[75538.370202] demo-crypto 53050000.crypto: demo_hash_do_one_request: algo: sha256, req->nbytes = 1023
[75538.374722] demo-crypto 53050000.crypto: demo_hash_compute
[75538.379202] demo-crypto 53050000.crypto: demo_hash_init
[75538.383722] demo-crypto 53050000.crypto: demo_hash_export
[75538.388202] demo-crypto 53050000.crypto: demo_hash_import
[75538.392722] demo-crypto 53050000.crypto: demo_hash_update
[75538.397202] demo-crypto 53050000.crypto: demo_hash_export
[75538.401722] demo-crypto 53050000.crypto: demo_hash_import
[75538.406202] demo-crypto 53050000.crypto: demo_hash_update
[75538.410722] demo-crypto 53050000.crypto: demo_hash_final
[75538.415202] demo-crypto 53050000.crypto: demo_hash_init
[75538.419722] demo-crypto 53050000.crypto: demo_hash_update
[75538.424202] demo-crypto 53050000.crypto: demo_hash_final
[75538.428722] demo-crypto 53050000.crypto: demo_hash_init
[75538.433202] demo-crypto 53050000.crypto: demo_hash_finup
[75538.437722] demo-crypto 53050000.crypto: demo_hash_digest
[75538.442202] demo-crypto 53050000.crypto: demo_hash_do_one_request
[75538.446722] demo-crypto 53050000.crypto: demo_hash_do_one_request: algo: sha256, req->nbytes = 1023
[75538.451202] demo-crypto 53050000.crypto: demo_hash_compute
[75538.455722] demo-crypto 53050000.crypto: demo_hash_init
[75538.460202] demo-crypto 53050000.crypto: demo_hash_update
[75538.464722] demo-crypto 53050000.crypto: demo_hash_final
[75538.469202] demo-crypto 53050000.crypto: demo_hash_digest
[75538.473722] demo-crypto 53050000.crypto: demo_hash_do_one_request
[75538.478202] demo-crypto 53050000.crypto: demo_hash_do_one_request: algo: sha256, req->nbytes = 1023
[75538.482722] demo-crypto 53050000.crypto: demo_hash_compute
[75538.487202] demo-crypto 53050000.crypto: demo_hash_digest
[75538.491722] demo-crypto 53050000.crypto: demo_hash_do_one_request
[75538.496202] demo-crypto 53050000.crypto: demo_hash_do_one_request: algo: sha256, req->nbytes = 1023
[75538.500722] demo-crypto 53050000.crypto: demo_hash_compute