Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
Pull crypto update from Herbert Xu: "Here is the crypto update for 4.6: API: - Convert remaining crypto_hash users to shash or ahash, also convert blkcipher/ablkcipher users to skcipher. - Remove crypto_hash interface. - Remove crypto_pcomp interface. - Add crypto engine for async cipher drivers. - Add akcipher documentation. - Add skcipher documentation. Algorithms: - Rename crypto/crc32 to avoid name clash with lib/crc32. - Fix bug in keywrap where we zero the wrong pointer. Drivers: - Support T5/M5, T7/M7 SPARC CPUs in n2 hwrng driver. - Add PIC32 hwrng driver. - Support BCM6368 in bcm63xx hwrng driver. - Pack structs for 32-bit compat users in qat. - Use crypto engine in omap-aes. - Add support for sama5d2x SoCs in atmel-sha. - Make atmel-sha available again. - Make sahara hashing available again. - Make ccp hashing available again. - Make sha1-mb available again. - Add support for multiple devices in ccp. - Improve DMA performance in caam. - Add hashing support to rockchip" * 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (116 commits) crypto: qat - remove redundant arbiter configuration crypto: ux500 - fix checks of error code returned by devm_ioremap_resource() crypto: atmel - fix checks of error code returned by devm_ioremap_resource() crypto: qat - Change the definition of icp_qat_uof_regtype hwrng: exynos - use __maybe_unused to hide pm functions crypto: ccp - Add abstraction for device-specific calls crypto: ccp - CCP versioning support crypto: ccp - Support for multiple CCPs crypto: ccp - Remove check for x86 family and model crypto: ccp - memset request context to zero during import lib/mpi: use "static inline" instead of "extern inline" lib/mpi: avoid assembler warning hwrng: bcm63xx - fix non device tree compatibility crypto: testmgr - allow rfc3686 aes-ctr variants in fips mode. crypto: qat - The AE id should be less than the maximal AE number lib/mpi: Endianness fix crypto: rockchip - add hash support for crypto engine in rk3288 crypto: xts - fix compile errors crypto: doc - add skcipher API documentation crypto: doc - update AEAD AD handling ...
This commit is contained in:
@@ -84,15 +84,6 @@ config CRYPTO_RNG_DEFAULT
|
||||
tristate
|
||||
select CRYPTO_DRBG_MENU
|
||||
|
||||
config CRYPTO_PCOMP
|
||||
tristate
|
||||
select CRYPTO_PCOMP2
|
||||
select CRYPTO_ALGAPI
|
||||
|
||||
config CRYPTO_PCOMP2
|
||||
tristate
|
||||
select CRYPTO_ALGAPI2
|
||||
|
||||
config CRYPTO_AKCIPHER2
|
||||
tristate
|
||||
select CRYPTO_ALGAPI2
|
||||
@@ -122,7 +113,6 @@ config CRYPTO_MANAGER2
|
||||
select CRYPTO_AEAD2
|
||||
select CRYPTO_HASH2
|
||||
select CRYPTO_BLKCIPHER2
|
||||
select CRYPTO_PCOMP2
|
||||
select CRYPTO_AKCIPHER2
|
||||
|
||||
config CRYPTO_USER
|
||||
@@ -227,6 +217,9 @@ config CRYPTO_GLUE_HELPER_X86
|
||||
depends on X86
|
||||
select CRYPTO_ALGAPI
|
||||
|
||||
config CRYPTO_ENGINE
|
||||
tristate
|
||||
|
||||
comment "Authenticated Encryption with Associated Data"
|
||||
|
||||
config CRYPTO_CCM
|
||||
@@ -1506,15 +1499,6 @@ config CRYPTO_DEFLATE
|
||||
|
||||
You will most probably want this if using IPSec.
|
||||
|
||||
config CRYPTO_ZLIB
|
||||
tristate "Zlib compression algorithm"
|
||||
select CRYPTO_PCOMP
|
||||
select ZLIB_INFLATE
|
||||
select ZLIB_DEFLATE
|
||||
select NLATTR
|
||||
help
|
||||
This is the zlib algorithm.
|
||||
|
||||
config CRYPTO_LZO
|
||||
tristate "LZO compression algorithm"
|
||||
select CRYPTO_ALGAPI
|
||||
@@ -1595,6 +1579,7 @@ endif # if CRYPTO_DRBG_MENU
|
||||
|
||||
config CRYPTO_JITTERENTROPY
|
||||
tristate "Jitterentropy Non-Deterministic Random Number Generator"
|
||||
select CRYPTO_RNG
|
||||
help
|
||||
The Jitterentropy RNG is a noise that is intended
|
||||
to provide seed to another RNG. The RNG does not
|
||||
|
@@ -7,6 +7,7 @@ crypto-y := api.o cipher.o compress.o memneq.o
|
||||
|
||||
obj-$(CONFIG_CRYPTO_WORKQUEUE) += crypto_wq.o
|
||||
|
||||
obj-$(CONFIG_CRYPTO_ENGINE) += crypto_engine.o
|
||||
obj-$(CONFIG_CRYPTO_FIPS) += fips.o
|
||||
|
||||
crypto_algapi-$(CONFIG_PROC_FS) += proc.o
|
||||
@@ -28,7 +29,6 @@ crypto_hash-y += ahash.o
|
||||
crypto_hash-y += shash.o
|
||||
obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o
|
||||
|
||||
obj-$(CONFIG_CRYPTO_PCOMP2) += pcompress.o
|
||||
obj-$(CONFIG_CRYPTO_AKCIPHER2) += akcipher.o
|
||||
|
||||
$(obj)/rsapubkey-asn1.o: $(obj)/rsapubkey-asn1.c $(obj)/rsapubkey-asn1.h
|
||||
@@ -99,10 +99,9 @@ obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o
|
||||
obj-$(CONFIG_CRYPTO_CHACHA20) += chacha20_generic.o
|
||||
obj-$(CONFIG_CRYPTO_POLY1305) += poly1305_generic.o
|
||||
obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
|
||||
obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o
|
||||
obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
|
||||
obj-$(CONFIG_CRYPTO_CRC32C) += crc32c_generic.o
|
||||
obj-$(CONFIG_CRYPTO_CRC32) += crc32.o
|
||||
obj-$(CONFIG_CRYPTO_CRC32) += crc32_generic.o
|
||||
obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_common.o crct10dif_generic.o
|
||||
obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o
|
||||
obj-$(CONFIG_CRYPTO_LZO) += lzo.o
|
||||
|
@@ -166,24 +166,6 @@ int crypto_ahash_walk_first(struct ahash_request *req,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_ahash_walk_first);
|
||||
|
||||
int crypto_hash_walk_first_compat(struct hash_desc *hdesc,
|
||||
struct crypto_hash_walk *walk,
|
||||
struct scatterlist *sg, unsigned int len)
|
||||
{
|
||||
walk->total = len;
|
||||
|
||||
if (!walk->total) {
|
||||
walk->entrylen = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
walk->alignmask = crypto_hash_alignmask(hdesc->tfm);
|
||||
walk->sg = sg;
|
||||
walk->flags = hdesc->flags & CRYPTO_TFM_REQ_MASK;
|
||||
|
||||
return hash_walk_new_entry(walk);
|
||||
}
|
||||
|
||||
static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key,
|
||||
unsigned int keylen)
|
||||
{
|
||||
@@ -542,6 +524,12 @@ struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_alloc_ahash);
|
||||
|
||||
int crypto_has_ahash(const char *alg_name, u32 type, u32 mask)
|
||||
{
|
||||
return crypto_type_has_alg(alg_name, &crypto_ahash_type, type, mask);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_has_ahash);
|
||||
|
||||
static int ahash_prepare_alg(struct ahash_alg *alg)
|
||||
{
|
||||
struct crypto_alg *base = &alg->halg.base;
|
||||
|
@@ -987,6 +987,21 @@ unsigned int crypto_alg_extsize(struct crypto_alg *alg)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_alg_extsize);
|
||||
|
||||
int crypto_type_has_alg(const char *name, const struct crypto_type *frontend,
|
||||
u32 type, u32 mask)
|
||||
{
|
||||
int ret = 0;
|
||||
struct crypto_alg *alg = crypto_find_alg(name, frontend, type, mask);
|
||||
|
||||
if (!IS_ERR(alg)) {
|
||||
crypto_mod_put(alg);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_type_has_alg);
|
||||
|
||||
static int __init crypto_algapi_init(void)
|
||||
{
|
||||
crypto_init_proc();
|
||||
|
@@ -131,7 +131,7 @@ static struct shash_alg alg = {
|
||||
.digestsize = CHKSUM_DIGEST_SIZE,
|
||||
.base = {
|
||||
.cra_name = "crc32",
|
||||
.cra_driver_name = "crc32-table",
|
||||
.cra_driver_name = "crc32-generic",
|
||||
.cra_priority = 100,
|
||||
.cra_blocksize = CHKSUM_BLOCK_SIZE,
|
||||
.cra_ctxsize = sizeof(u32),
|
||||
@@ -157,3 +157,4 @@ MODULE_AUTHOR("Alexander Boyko <alexander_boyko@xyratex.com>");
|
||||
MODULE_DESCRIPTION("CRC32 calculations wrapper for lib/crc32");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_CRYPTO("crc32");
|
||||
MODULE_ALIAS_CRYPTO("crc32-generic");
|
355
crypto/crypto_engine.c
Normal file
355
crypto/crypto_engine.c
Normal file
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* Handle async block request by crypto hardware engine.
|
||||
*
|
||||
* Copyright (C) 2016 Linaro, Inc.
|
||||
*
|
||||
* Author: Baolin Wang <baolin.wang@linaro.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
#include "internal.h"
|
||||
|
||||
#define CRYPTO_ENGINE_MAX_QLEN 10
|
||||
|
||||
void crypto_finalize_request(struct crypto_engine *engine,
|
||||
struct ablkcipher_request *req, int err);
|
||||
|
||||
/**
|
||||
* crypto_pump_requests - dequeue one request from engine queue to process
|
||||
* @engine: the hardware engine
|
||||
* @in_kthread: true if we are in the context of the request pump thread
|
||||
*
|
||||
* This function checks if there is any request in the engine queue that
|
||||
* needs processing and if so call out to the driver to initialize hardware
|
||||
* and handle each request.
|
||||
*/
|
||||
static void crypto_pump_requests(struct crypto_engine *engine,
|
||||
bool in_kthread)
|
||||
{
|
||||
struct crypto_async_request *async_req, *backlog;
|
||||
struct ablkcipher_request *req;
|
||||
unsigned long flags;
|
||||
bool was_busy = false;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&engine->queue_lock, flags);
|
||||
|
||||
/* Make sure we are not already running a request */
|
||||
if (engine->cur_req)
|
||||
goto out;
|
||||
|
||||
/* If another context is idling then defer */
|
||||
if (engine->idling) {
|
||||
queue_kthread_work(&engine->kworker, &engine->pump_requests);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check if the engine queue is idle */
|
||||
if (!crypto_queue_len(&engine->queue) || !engine->running) {
|
||||
if (!engine->busy)
|
||||
goto out;
|
||||
|
||||
/* Only do teardown in the thread */
|
||||
if (!in_kthread) {
|
||||
queue_kthread_work(&engine->kworker,
|
||||
&engine->pump_requests);
|
||||
goto out;
|
||||
}
|
||||
|
||||
engine->busy = false;
|
||||
engine->idling = true;
|
||||
spin_unlock_irqrestore(&engine->queue_lock, flags);
|
||||
|
||||
if (engine->unprepare_crypt_hardware &&
|
||||
engine->unprepare_crypt_hardware(engine))
|
||||
pr_err("failed to unprepare crypt hardware\n");
|
||||
|
||||
spin_lock_irqsave(&engine->queue_lock, flags);
|
||||
engine->idling = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get the fist request from the engine queue to handle */
|
||||
backlog = crypto_get_backlog(&engine->queue);
|
||||
async_req = crypto_dequeue_request(&engine->queue);
|
||||
if (!async_req)
|
||||
goto out;
|
||||
|
||||
req = ablkcipher_request_cast(async_req);
|
||||
|
||||
engine->cur_req = req;
|
||||
if (backlog)
|
||||
backlog->complete(backlog, -EINPROGRESS);
|
||||
|
||||
if (engine->busy)
|
||||
was_busy = true;
|
||||
else
|
||||
engine->busy = true;
|
||||
|
||||
spin_unlock_irqrestore(&engine->queue_lock, flags);
|
||||
|
||||
/* Until here we get the request need to be encrypted successfully */
|
||||
if (!was_busy && engine->prepare_crypt_hardware) {
|
||||
ret = engine->prepare_crypt_hardware(engine);
|
||||
if (ret) {
|
||||
pr_err("failed to prepare crypt hardware\n");
|
||||
goto req_err;
|
||||
}
|
||||
}
|
||||
|
||||
if (engine->prepare_request) {
|
||||
ret = engine->prepare_request(engine, engine->cur_req);
|
||||
if (ret) {
|
||||
pr_err("failed to prepare request: %d\n", ret);
|
||||
goto req_err;
|
||||
}
|
||||
engine->cur_req_prepared = true;
|
||||
}
|
||||
|
||||
ret = engine->crypt_one_request(engine, engine->cur_req);
|
||||
if (ret) {
|
||||
pr_err("failed to crypt one request from queue\n");
|
||||
goto req_err;
|
||||
}
|
||||
return;
|
||||
|
||||
req_err:
|
||||
crypto_finalize_request(engine, engine->cur_req, ret);
|
||||
return;
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&engine->queue_lock, flags);
|
||||
}
|
||||
|
||||
static void crypto_pump_work(struct kthread_work *work)
|
||||
{
|
||||
struct crypto_engine *engine =
|
||||
container_of(work, struct crypto_engine, pump_requests);
|
||||
|
||||
crypto_pump_requests(engine, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* crypto_transfer_request - transfer the new request into the engine queue
|
||||
* @engine: the hardware engine
|
||||
* @req: the request need to be listed into the engine queue
|
||||
*/
|
||||
int crypto_transfer_request(struct crypto_engine *engine,
|
||||
struct ablkcipher_request *req, bool need_pump)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&engine->queue_lock, flags);
|
||||
|
||||
if (!engine->running) {
|
||||
spin_unlock_irqrestore(&engine->queue_lock, flags);
|
||||
return -ESHUTDOWN;
|
||||
}
|
||||
|
||||
ret = ablkcipher_enqueue_request(&engine->queue, req);
|
||||
|
||||
if (!engine->busy && need_pump)
|
||||
queue_kthread_work(&engine->kworker, &engine->pump_requests);
|
||||
|
||||
spin_unlock_irqrestore(&engine->queue_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_transfer_request);
|
||||
|
||||
/**
|
||||
* crypto_transfer_request_to_engine - transfer one request to list into the
|
||||
* engine queue
|
||||
* @engine: the hardware engine
|
||||
* @req: the request need to be listed into the engine queue
|
||||
*/
|
||||
int crypto_transfer_request_to_engine(struct crypto_engine *engine,
|
||||
struct ablkcipher_request *req)
|
||||
{
|
||||
return crypto_transfer_request(engine, req, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_transfer_request_to_engine);
|
||||
|
||||
/**
|
||||
* crypto_finalize_request - finalize one request if the request is done
|
||||
* @engine: the hardware engine
|
||||
* @req: the request need to be finalized
|
||||
* @err: error number
|
||||
*/
|
||||
void crypto_finalize_request(struct crypto_engine *engine,
|
||||
struct ablkcipher_request *req, int err)
|
||||
{
|
||||
unsigned long flags;
|
||||
bool finalize_cur_req = false;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&engine->queue_lock, flags);
|
||||
if (engine->cur_req == req)
|
||||
finalize_cur_req = true;
|
||||
spin_unlock_irqrestore(&engine->queue_lock, flags);
|
||||
|
||||
if (finalize_cur_req) {
|
||||
if (engine->cur_req_prepared && engine->unprepare_request) {
|
||||
ret = engine->unprepare_request(engine, req);
|
||||
if (ret)
|
||||
pr_err("failed to unprepare request\n");
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&engine->queue_lock, flags);
|
||||
engine->cur_req = NULL;
|
||||
engine->cur_req_prepared = false;
|
||||
spin_unlock_irqrestore(&engine->queue_lock, flags);
|
||||
}
|
||||
|
||||
req->base.complete(&req->base, err);
|
||||
|
||||
queue_kthread_work(&engine->kworker, &engine->pump_requests);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_finalize_request);
|
||||
|
||||
/**
|
||||
* crypto_engine_start - start the hardware engine
|
||||
* @engine: the hardware engine need to be started
|
||||
*
|
||||
* Return 0 on success, else on fail.
|
||||
*/
|
||||
int crypto_engine_start(struct crypto_engine *engine)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&engine->queue_lock, flags);
|
||||
|
||||
if (engine->running || engine->busy) {
|
||||
spin_unlock_irqrestore(&engine->queue_lock, flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
engine->running = true;
|
||||
spin_unlock_irqrestore(&engine->queue_lock, flags);
|
||||
|
||||
queue_kthread_work(&engine->kworker, &engine->pump_requests);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_engine_start);
|
||||
|
||||
/**
|
||||
* crypto_engine_stop - stop the hardware engine
|
||||
* @engine: the hardware engine need to be stopped
|
||||
*
|
||||
* Return 0 on success, else on fail.
|
||||
*/
|
||||
int crypto_engine_stop(struct crypto_engine *engine)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned limit = 500;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&engine->queue_lock, flags);
|
||||
|
||||
/*
|
||||
* If the engine queue is not empty or the engine is on busy state,
|
||||
* we need to wait for a while to pump the requests of engine queue.
|
||||
*/
|
||||
while ((crypto_queue_len(&engine->queue) || engine->busy) && limit--) {
|
||||
spin_unlock_irqrestore(&engine->queue_lock, flags);
|
||||
msleep(20);
|
||||
spin_lock_irqsave(&engine->queue_lock, flags);
|
||||
}
|
||||
|
||||
if (crypto_queue_len(&engine->queue) || engine->busy)
|
||||
ret = -EBUSY;
|
||||
else
|
||||
engine->running = false;
|
||||
|
||||
spin_unlock_irqrestore(&engine->queue_lock, flags);
|
||||
|
||||
if (ret)
|
||||
pr_warn("could not stop engine\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_engine_stop);
|
||||
|
||||
/**
|
||||
* crypto_engine_alloc_init - allocate crypto hardware engine structure and
|
||||
* initialize it.
|
||||
* @dev: the device attached with one hardware engine
|
||||
* @rt: whether this queue is set to run as a realtime task
|
||||
*
|
||||
* This must be called from context that can sleep.
|
||||
* Return: the crypto engine structure on success, else NULL.
|
||||
*/
|
||||
struct crypto_engine *crypto_engine_alloc_init(struct device *dev, bool rt)
|
||||
{
|
||||
struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
|
||||
struct crypto_engine *engine;
|
||||
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
engine = devm_kzalloc(dev, sizeof(*engine), GFP_KERNEL);
|
||||
if (!engine)
|
||||
return NULL;
|
||||
|
||||
engine->rt = rt;
|
||||
engine->running = false;
|
||||
engine->busy = false;
|
||||
engine->idling = false;
|
||||
engine->cur_req_prepared = false;
|
||||
engine->priv_data = dev;
|
||||
snprintf(engine->name, sizeof(engine->name),
|
||||
"%s-engine", dev_name(dev));
|
||||
|
||||
crypto_init_queue(&engine->queue, CRYPTO_ENGINE_MAX_QLEN);
|
||||
spin_lock_init(&engine->queue_lock);
|
||||
|
||||
init_kthread_worker(&engine->kworker);
|
||||
engine->kworker_task = kthread_run(kthread_worker_fn,
|
||||
&engine->kworker, "%s",
|
||||
engine->name);
|
||||
if (IS_ERR(engine->kworker_task)) {
|
||||
dev_err(dev, "failed to create crypto request pump task\n");
|
||||
return NULL;
|
||||
}
|
||||
init_kthread_work(&engine->pump_requests, crypto_pump_work);
|
||||
|
||||
if (engine->rt) {
|
||||
dev_info(dev, "will run requests pump with realtime priority\n");
|
||||
sched_setscheduler(engine->kworker_task, SCHED_FIFO, ¶m);
|
||||
}
|
||||
|
||||
return engine;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_engine_alloc_init);
|
||||
|
||||
/**
|
||||
* crypto_engine_exit - free the resources of hardware engine when exit
|
||||
* @engine: the hardware engine need to be freed
|
||||
*
|
||||
* Return 0 for success.
|
||||
*/
|
||||
int crypto_engine_exit(struct crypto_engine *engine)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = crypto_engine_stop(engine);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
flush_kthread_worker(&engine->kworker);
|
||||
kthread_stop(engine->kworker_task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_engine_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Crypto hardware engine framework");
|
@@ -219,48 +219,6 @@ static inline unsigned short drbg_sec_strength(drbg_flag_t flags)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* FIPS 140-2 continuous self test
|
||||
* The test is performed on the result of one round of the output
|
||||
* function. Thus, the function implicitly knows the size of the
|
||||
* buffer.
|
||||
*
|
||||
* @drbg DRBG handle
|
||||
* @buf output buffer of random data to be checked
|
||||
*
|
||||
* return:
|
||||
* true on success
|
||||
* false on error
|
||||
*/
|
||||
static bool drbg_fips_continuous_test(struct drbg_state *drbg,
|
||||
const unsigned char *buf)
|
||||
{
|
||||
#ifdef CONFIG_CRYPTO_FIPS
|
||||
int ret = 0;
|
||||
/* skip test if we test the overall system */
|
||||
if (list_empty(&drbg->test_data.list))
|
||||
return true;
|
||||
/* only perform test in FIPS mode */
|
||||
if (0 == fips_enabled)
|
||||
return true;
|
||||
if (!drbg->fips_primed) {
|
||||
/* Priming of FIPS test */
|
||||
memcpy(drbg->prev, buf, drbg_blocklen(drbg));
|
||||
drbg->fips_primed = true;
|
||||
/* return false due to priming, i.e. another round is needed */
|
||||
return false;
|
||||
}
|
||||
ret = memcmp(drbg->prev, buf, drbg_blocklen(drbg));
|
||||
if (!ret)
|
||||
panic("DRBG continuous self test failed\n");
|
||||
memcpy(drbg->prev, buf, drbg_blocklen(drbg));
|
||||
/* the test shall pass when the two compared values are not equal */
|
||||
return ret != 0;
|
||||
#else
|
||||
return true;
|
||||
#endif /* CONFIG_CRYPTO_FIPS */
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an integer into a byte representation of this integer.
|
||||
* The byte representation is big-endian
|
||||
@@ -603,11 +561,6 @@ static int drbg_ctr_generate(struct drbg_state *drbg,
|
||||
}
|
||||
outlen = (drbg_blocklen(drbg) < (buflen - len)) ?
|
||||
drbg_blocklen(drbg) : (buflen - len);
|
||||
if (!drbg_fips_continuous_test(drbg, drbg->scratchpad)) {
|
||||
/* 10.2.1.5.2 step 6 */
|
||||
crypto_inc(drbg->V, drbg_blocklen(drbg));
|
||||
continue;
|
||||
}
|
||||
/* 10.2.1.5.2 step 4.3 */
|
||||
memcpy(buf + len, drbg->scratchpad, outlen);
|
||||
len += outlen;
|
||||
@@ -733,8 +686,6 @@ static int drbg_hmac_generate(struct drbg_state *drbg,
|
||||
return ret;
|
||||
outlen = (drbg_blocklen(drbg) < (buflen - len)) ?
|
||||
drbg_blocklen(drbg) : (buflen - len);
|
||||
if (!drbg_fips_continuous_test(drbg, drbg->V))
|
||||
continue;
|
||||
|
||||
/* 10.1.2.5 step 4.2 */
|
||||
memcpy(buf + len, drbg->V, outlen);
|
||||
@@ -963,10 +914,6 @@ static int drbg_hash_hashgen(struct drbg_state *drbg,
|
||||
}
|
||||
outlen = (drbg_blocklen(drbg) < (buflen - len)) ?
|
||||
drbg_blocklen(drbg) : (buflen - len);
|
||||
if (!drbg_fips_continuous_test(drbg, dst)) {
|
||||
crypto_inc(src, drbg_statelen(drbg));
|
||||
continue;
|
||||
}
|
||||
/* 10.1.1.4 step hashgen 4.2 */
|
||||
memcpy(buf + len, dst, outlen);
|
||||
len += outlen;
|
||||
@@ -1201,11 +1148,6 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg)
|
||||
drbg->reseed_ctr = 0;
|
||||
drbg->d_ops = NULL;
|
||||
drbg->core = NULL;
|
||||
#ifdef CONFIG_CRYPTO_FIPS
|
||||
kzfree(drbg->prev);
|
||||
drbg->prev = NULL;
|
||||
drbg->fips_primed = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1244,12 +1186,6 @@ static inline int drbg_alloc_state(struct drbg_state *drbg)
|
||||
drbg->C = kmalloc(drbg_statelen(drbg), GFP_KERNEL);
|
||||
if (!drbg->C)
|
||||
goto err;
|
||||
#ifdef CONFIG_CRYPTO_FIPS
|
||||
drbg->prev = kmalloc(drbg_blocklen(drbg), GFP_KERNEL);
|
||||
if (!drbg->prev)
|
||||
goto err;
|
||||
drbg->fips_primed = false;
|
||||
#endif
|
||||
/* scratchpad is only generated for CTR and Hash */
|
||||
if (drbg->core->flags & DRBG_HMAC)
|
||||
sb_size = 0;
|
||||
|
@@ -104,6 +104,9 @@ int crypto_probing_notify(unsigned long val, void *v);
|
||||
|
||||
unsigned int crypto_alg_extsize(struct crypto_alg *alg);
|
||||
|
||||
int crypto_type_has_alg(const char *name, const struct crypto_type *frontend,
|
||||
u32 type, u32 mask);
|
||||
|
||||
static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg)
|
||||
{
|
||||
atomic_inc(&alg->cra_refcnt);
|
||||
|
@@ -212,7 +212,7 @@ static int crypto_kw_decrypt(struct blkcipher_desc *desc,
|
||||
SEMIBSIZE))
|
||||
ret = -EBADMSG;
|
||||
|
||||
memzero_explicit(&block, sizeof(struct crypto_kw_block));
|
||||
memzero_explicit(block, sizeof(struct crypto_kw_block));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -297,7 +297,7 @@ static int crypto_kw_encrypt(struct blkcipher_desc *desc,
|
||||
/* establish the IV for the caller to pick up */
|
||||
memcpy(desc->info, block->A, SEMIBSIZE);
|
||||
|
||||
memzero_explicit(&block, sizeof(struct crypto_kw_block));
|
||||
memzero_explicit(block, sizeof(struct crypto_kw_block));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -522,6 +522,7 @@ static int mcryptd_create_hash(struct crypto_template *tmpl, struct rtattr **tb,
|
||||
inst->alg.halg.base.cra_flags = type;
|
||||
|
||||
inst->alg.halg.digestsize = salg->digestsize;
|
||||
inst->alg.halg.statesize = salg->statesize;
|
||||
inst->alg.halg.base.cra_ctxsize = sizeof(struct mcryptd_hash_ctx);
|
||||
|
||||
inst->alg.halg.base.cra_init = mcryptd_hash_init_tfm;
|
||||
|
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Cryptographic API.
|
||||
*
|
||||
* Partial (de)compression operations.
|
||||
*
|
||||
* Copyright 2008 Sony Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/cryptouser.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#include <crypto/compress.h>
|
||||
#include <crypto/internal/compress.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
static int crypto_pcomp_init(struct crypto_tfm *tfm, u32 type, u32 mask)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crypto_pcomp_init_tfm(struct crypto_tfm *tfm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET
|
||||
static int crypto_pcomp_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
struct crypto_report_comp rpcomp;
|
||||
|
||||
strncpy(rpcomp.type, "pcomp", sizeof(rpcomp.type));
|
||||
if (nla_put(skb, CRYPTOCFGA_REPORT_COMPRESS,
|
||||
sizeof(struct crypto_report_comp), &rpcomp))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
#else
|
||||
static int crypto_pcomp_report(struct sk_buff *skb, struct crypto_alg *alg)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void crypto_pcomp_show(struct seq_file *m, struct crypto_alg *alg)
|
||||
__attribute__ ((unused));
|
||||
static void crypto_pcomp_show(struct seq_file *m, struct crypto_alg *alg)
|
||||
{
|
||||
seq_printf(m, "type : pcomp\n");
|
||||
}
|
||||
|
||||
static const struct crypto_type crypto_pcomp_type = {
|
||||
.extsize = crypto_alg_extsize,
|
||||
.init = crypto_pcomp_init,
|
||||
.init_tfm = crypto_pcomp_init_tfm,
|
||||
#ifdef CONFIG_PROC_FS
|
||||
.show = crypto_pcomp_show,
|
||||
#endif
|
||||
.report = crypto_pcomp_report,
|
||||
.maskclear = ~CRYPTO_ALG_TYPE_MASK,
|
||||
.maskset = CRYPTO_ALG_TYPE_MASK,
|
||||
.type = CRYPTO_ALG_TYPE_PCOMPRESS,
|
||||
.tfmsize = offsetof(struct crypto_pcomp, base),
|
||||
};
|
||||
|
||||
struct crypto_pcomp *crypto_alloc_pcomp(const char *alg_name, u32 type,
|
||||
u32 mask)
|
||||
{
|
||||
return crypto_alloc_tfm(alg_name, &crypto_pcomp_type, type, mask);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_alloc_pcomp);
|
||||
|
||||
int crypto_register_pcomp(struct pcomp_alg *alg)
|
||||
{
|
||||
struct crypto_alg *base = &alg->base;
|
||||
|
||||
base->cra_type = &crypto_pcomp_type;
|
||||
base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
|
||||
base->cra_flags |= CRYPTO_ALG_TYPE_PCOMPRESS;
|
||||
|
||||
return crypto_register_alg(base);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_register_pcomp);
|
||||
|
||||
int crypto_unregister_pcomp(struct pcomp_alg *alg)
|
||||
{
|
||||
return crypto_unregister_alg(&alg->base);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(crypto_unregister_pcomp);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Partial (de)compression type");
|
||||
MODULE_AUTHOR("Sony Corporation");
|
147
crypto/shash.c
147
crypto/shash.c
@@ -368,151 +368,6 @@ int crypto_init_shash_ops_async(struct crypto_tfm *tfm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shash_compat_setkey(struct crypto_hash *tfm, const u8 *key,
|
||||
unsigned int keylen)
|
||||
{
|
||||
struct shash_desc **descp = crypto_hash_ctx(tfm);
|
||||
struct shash_desc *desc = *descp;
|
||||
|
||||
return crypto_shash_setkey(desc->tfm, key, keylen);
|
||||
}
|
||||
|
||||
static int shash_compat_init(struct hash_desc *hdesc)
|
||||
{
|
||||
struct shash_desc **descp = crypto_hash_ctx(hdesc->tfm);
|
||||
struct shash_desc *desc = *descp;
|
||||
|
||||
desc->flags = hdesc->flags;
|
||||
|
||||
return crypto_shash_init(desc);
|
||||
}
|
||||
|
||||
static int shash_compat_update(struct hash_desc *hdesc, struct scatterlist *sg,
|
||||
unsigned int len)
|
||||
{
|
||||
struct shash_desc **descp = crypto_hash_ctx(hdesc->tfm);
|
||||
struct shash_desc *desc = *descp;
|
||||
struct crypto_hash_walk walk;
|
||||
int nbytes;
|
||||
|
||||
for (nbytes = crypto_hash_walk_first_compat(hdesc, &walk, sg, len);
|
||||
nbytes > 0; nbytes = crypto_hash_walk_done(&walk, nbytes))
|
||||
nbytes = crypto_shash_update(desc, walk.data, nbytes);
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static int shash_compat_final(struct hash_desc *hdesc, u8 *out)
|
||||
{
|
||||
struct shash_desc **descp = crypto_hash_ctx(hdesc->tfm);
|
||||
|
||||
return crypto_shash_final(*descp, out);
|
||||
}
|
||||
|
||||
static int shash_compat_digest(struct hash_desc *hdesc, struct scatterlist *sg,
|
||||
unsigned int nbytes, u8 *out)
|
||||
{
|
||||
unsigned int offset = sg->offset;
|
||||
int err;
|
||||
|
||||
if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) {
|
||||
struct shash_desc **descp = crypto_hash_ctx(hdesc->tfm);
|
||||
struct shash_desc *desc = *descp;
|
||||
void *data;
|
||||
|
||||
desc->flags = hdesc->flags;
|
||||
|
||||
data = kmap_atomic(sg_page(sg));
|
||||
err = crypto_shash_digest(desc, data + offset, nbytes, out);
|
||||
kunmap_atomic(data);
|
||||
crypto_yield(desc->flags);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = shash_compat_init(hdesc);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = shash_compat_update(hdesc, sg, nbytes);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = shash_compat_final(hdesc, out);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void crypto_exit_shash_ops_compat(struct crypto_tfm *tfm)
|
||||
{
|
||||
struct shash_desc **descp = crypto_tfm_ctx(tfm);
|
||||
struct shash_desc *desc = *descp;
|
||||
|
||||
crypto_free_shash(desc->tfm);
|
||||
kzfree(desc);
|
||||
}
|
||||
|
||||
static int crypto_init_shash_ops_compat(struct crypto_tfm *tfm)
|
||||
{
|
||||
struct hash_tfm *crt = &tfm->crt_hash;
|
||||
struct crypto_alg *calg = tfm->__crt_alg;
|
||||
struct shash_alg *alg = __crypto_shash_alg(calg);
|
||||
struct shash_desc **descp = crypto_tfm_ctx(tfm);
|
||||
struct crypto_shash *shash;
|
||||
struct shash_desc *desc;
|
||||
|
||||
if (!crypto_mod_get(calg))
|
||||
return -EAGAIN;
|
||||
|
||||
shash = crypto_create_tfm(calg, &crypto_shash_type);
|
||||
if (IS_ERR(shash)) {
|
||||
crypto_mod_put(calg);
|
||||
return PTR_ERR(shash);
|
||||
}
|
||||
|
||||
desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(shash),
|
||||
GFP_KERNEL);
|
||||
if (!desc) {
|
||||
crypto_free_shash(shash);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*descp = desc;
|
||||
desc->tfm = shash;
|
||||
tfm->exit = crypto_exit_shash_ops_compat;
|
||||
|
||||
crt->init = shash_compat_init;
|
||||
crt->update = shash_compat_update;
|
||||
crt->final = shash_compat_final;
|
||||
crt->digest = shash_compat_digest;
|
||||
crt->setkey = shash_compat_setkey;
|
||||
|
||||
crt->digestsize = alg->digestsize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crypto_init_shash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
|
||||
{
|
||||
switch (mask & CRYPTO_ALG_TYPE_MASK) {
|
||||
case CRYPTO_ALG_TYPE_HASH_MASK:
|
||||
return crypto_init_shash_ops_compat(tfm);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static unsigned int crypto_shash_ctxsize(struct crypto_alg *alg, u32 type,
|
||||
u32 mask)
|
||||
{
|
||||
switch (mask & CRYPTO_ALG_TYPE_MASK) {
|
||||
case CRYPTO_ALG_TYPE_HASH_MASK:
|
||||
return sizeof(struct shash_desc *);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int crypto_shash_init_tfm(struct crypto_tfm *tfm)
|
||||
{
|
||||
struct crypto_shash *hash = __crypto_shash_cast(tfm);
|
||||
@@ -559,9 +414,7 @@ static void crypto_shash_show(struct seq_file *m, struct crypto_alg *alg)
|
||||
}
|
||||
|
||||
static const struct crypto_type crypto_shash_type = {
|
||||
.ctxsize = crypto_shash_ctxsize,
|
||||
.extsize = crypto_alg_extsize,
|
||||
.init = crypto_init_shash_ops,
|
||||
.init_tfm = crypto_shash_init_tfm,
|
||||
#ifdef CONFIG_PROC_FS
|
||||
.show = crypto_shash_show,
|
||||
|
@@ -118,7 +118,7 @@ static int crypto_init_skcipher_ops_blkcipher(struct crypto_tfm *tfm)
|
||||
skcipher->decrypt = skcipher_decrypt_blkcipher;
|
||||
|
||||
skcipher->ivsize = crypto_blkcipher_ivsize(blkcipher);
|
||||
skcipher->has_setkey = calg->cra_blkcipher.max_keysize;
|
||||
skcipher->keysize = calg->cra_blkcipher.max_keysize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -211,7 +211,7 @@ static int crypto_init_skcipher_ops_ablkcipher(struct crypto_tfm *tfm)
|
||||
skcipher->ivsize = crypto_ablkcipher_ivsize(ablkcipher);
|
||||
skcipher->reqsize = crypto_ablkcipher_reqsize(ablkcipher) +
|
||||
sizeof(struct ablkcipher_request);
|
||||
skcipher->has_setkey = calg->cra_ablkcipher.max_keysize;
|
||||
skcipher->keysize = calg->cra_ablkcipher.max_keysize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
239
crypto/tcrypt.c
239
crypto/tcrypt.c
@@ -554,164 +554,6 @@ out:
|
||||
crypto_free_blkcipher(tfm);
|
||||
}
|
||||
|
||||
static int test_hash_jiffies_digest(struct hash_desc *desc,
|
||||
struct scatterlist *sg, int blen,
|
||||
char *out, int secs)
|
||||
{
|
||||
unsigned long start, end;
|
||||
int bcount;
|
||||
int ret;
|
||||
|
||||
for (start = jiffies, end = start + secs * HZ, bcount = 0;
|
||||
time_before(jiffies, end); bcount++) {
|
||||
ret = crypto_hash_digest(desc, sg, blen, out);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
printk("%6u opers/sec, %9lu bytes/sec\n",
|
||||
bcount / secs, ((long)bcount * blen) / secs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_hash_jiffies(struct hash_desc *desc, struct scatterlist *sg,
|
||||
int blen, int plen, char *out, int secs)
|
||||
{
|
||||
unsigned long start, end;
|
||||
int bcount, pcount;
|
||||
int ret;
|
||||
|
||||
if (plen == blen)
|
||||
return test_hash_jiffies_digest(desc, sg, blen, out, secs);
|
||||
|
||||
for (start = jiffies, end = start + secs * HZ, bcount = 0;
|
||||
time_before(jiffies, end); bcount++) {
|
||||
ret = crypto_hash_init(desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
for (pcount = 0; pcount < blen; pcount += plen) {
|
||||
ret = crypto_hash_update(desc, sg, plen);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
/* we assume there is enough space in 'out' for the result */
|
||||
ret = crypto_hash_final(desc, out);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
printk("%6u opers/sec, %9lu bytes/sec\n",
|
||||
bcount / secs, ((long)bcount * blen) / secs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_hash_cycles_digest(struct hash_desc *desc,
|
||||
struct scatterlist *sg, int blen, char *out)
|
||||
{
|
||||
unsigned long cycles = 0;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
/* Warm-up run. */
|
||||
for (i = 0; i < 4; i++) {
|
||||
ret = crypto_hash_digest(desc, sg, blen, out);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The real thing. */
|
||||
for (i = 0; i < 8; i++) {
|
||||
cycles_t start, end;
|
||||
|
||||
start = get_cycles();
|
||||
|
||||
ret = crypto_hash_digest(desc, sg, blen, out);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
end = get_cycles();
|
||||
|
||||
cycles += end - start;
|
||||
}
|
||||
|
||||
out:
|
||||
local_irq_enable();
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
printk("%6lu cycles/operation, %4lu cycles/byte\n",
|
||||
cycles / 8, cycles / (8 * blen));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_hash_cycles(struct hash_desc *desc, struct scatterlist *sg,
|
||||
int blen, int plen, char *out)
|
||||
{
|
||||
unsigned long cycles = 0;
|
||||
int i, pcount;
|
||||
int ret;
|
||||
|
||||
if (plen == blen)
|
||||
return test_hash_cycles_digest(desc, sg, blen, out);
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
/* Warm-up run. */
|
||||
for (i = 0; i < 4; i++) {
|
||||
ret = crypto_hash_init(desc);
|
||||
if (ret)
|
||||
goto out;
|
||||
for (pcount = 0; pcount < blen; pcount += plen) {
|
||||
ret = crypto_hash_update(desc, sg, plen);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
ret = crypto_hash_final(desc, out);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The real thing. */
|
||||
for (i = 0; i < 8; i++) {
|
||||
cycles_t start, end;
|
||||
|
||||
start = get_cycles();
|
||||
|
||||
ret = crypto_hash_init(desc);
|
||||
if (ret)
|
||||
goto out;
|
||||
for (pcount = 0; pcount < blen; pcount += plen) {
|
||||
ret = crypto_hash_update(desc, sg, plen);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
ret = crypto_hash_final(desc, out);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
end = get_cycles();
|
||||
|
||||
cycles += end - start;
|
||||
}
|
||||
|
||||
out:
|
||||
local_irq_enable();
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
printk("%6lu cycles/operation, %4lu cycles/byte\n",
|
||||
cycles / 8, cycles / (8 * blen));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_hash_sg_init(struct scatterlist *sg)
|
||||
{
|
||||
int i;
|
||||
@@ -723,69 +565,6 @@ static void test_hash_sg_init(struct scatterlist *sg)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_hash_speed(const char *algo, unsigned int secs,
|
||||
struct hash_speed *speed)
|
||||
{
|
||||
struct scatterlist sg[TVMEMSIZE];
|
||||
struct crypto_hash *tfm;
|
||||
struct hash_desc desc;
|
||||
static char output[1024];
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
tfm = crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC);
|
||||
|
||||
if (IS_ERR(tfm)) {
|
||||
printk(KERN_ERR "failed to load transform for %s: %ld\n", algo,
|
||||
PTR_ERR(tfm));
|
||||
return;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "\ntesting speed of %s (%s)\n", algo,
|
||||
get_driver_name(crypto_hash, tfm));
|
||||
|
||||
desc.tfm = tfm;
|
||||
desc.flags = 0;
|
||||
|
||||
if (crypto_hash_digestsize(tfm) > sizeof(output)) {
|
||||
printk(KERN_ERR "digestsize(%u) > outputbuffer(%zu)\n",
|
||||
crypto_hash_digestsize(tfm), sizeof(output));
|
||||
goto out;
|
||||
}
|
||||
|
||||
test_hash_sg_init(sg);
|
||||
for (i = 0; speed[i].blen != 0; i++) {
|
||||
if (speed[i].blen > TVMEMSIZE * PAGE_SIZE) {
|
||||
printk(KERN_ERR
|
||||
"template (%u) too big for tvmem (%lu)\n",
|
||||
speed[i].blen, TVMEMSIZE * PAGE_SIZE);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (speed[i].klen)
|
||||
crypto_hash_setkey(tfm, tvmem[0], speed[i].klen);
|
||||
|
||||
printk(KERN_INFO "test%3u "
|
||||
"(%5u byte blocks,%5u bytes per update,%4u updates): ",
|
||||
i, speed[i].blen, speed[i].plen, speed[i].blen / speed[i].plen);
|
||||
|
||||
if (secs)
|
||||
ret = test_hash_jiffies(&desc, sg, speed[i].blen,
|
||||
speed[i].plen, output, secs);
|
||||
else
|
||||
ret = test_hash_cycles(&desc, sg, speed[i].blen,
|
||||
speed[i].plen, output);
|
||||
|
||||
if (ret) {
|
||||
printk(KERN_ERR "hashing failed ret=%d\n", ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
crypto_free_hash(tfm);
|
||||
}
|
||||
|
||||
static inline int do_one_ahash_op(struct ahash_request *req, int ret)
|
||||
{
|
||||
if (ret == -EINPROGRESS || ret == -EBUSY) {
|
||||
@@ -945,8 +724,8 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_ahash_speed(const char *algo, unsigned int secs,
|
||||
struct hash_speed *speed)
|
||||
static void test_ahash_speed_common(const char *algo, unsigned int secs,
|
||||
struct hash_speed *speed, unsigned mask)
|
||||
{
|
||||
struct scatterlist sg[TVMEMSIZE];
|
||||
struct tcrypt_result tresult;
|
||||
@@ -955,7 +734,7 @@ static void test_ahash_speed(const char *algo, unsigned int secs,
|
||||
char *output;
|
||||
int i, ret;
|
||||
|
||||
tfm = crypto_alloc_ahash(algo, 0, 0);
|
||||
tfm = crypto_alloc_ahash(algo, 0, mask);
|
||||
if (IS_ERR(tfm)) {
|
||||
pr_err("failed to load transform for %s: %ld\n",
|
||||
algo, PTR_ERR(tfm));
|
||||
@@ -1021,6 +800,18 @@ out:
|
||||
crypto_free_ahash(tfm);
|
||||
}
|
||||
|
||||
static void test_ahash_speed(const char *algo, unsigned int secs,
|
||||
struct hash_speed *speed)
|
||||
{
|
||||
return test_ahash_speed_common(algo, secs, speed, 0);
|
||||
}
|
||||
|
||||
static void test_hash_speed(const char *algo, unsigned int secs,
|
||||
struct hash_speed *speed)
|
||||
{
|
||||
return test_ahash_speed_common(algo, secs, speed, CRYPTO_ALG_ASYNC);
|
||||
}
|
||||
|
||||
static inline int do_one_acipher_op(struct ablkcipher_request *req, int ret)
|
||||
{
|
||||
if (ret == -EINPROGRESS || ret == -EBUSY) {
|
||||
|
401
crypto/testmgr.c
401
crypto/testmgr.c
@@ -96,13 +96,6 @@ struct comp_test_suite {
|
||||
} comp, decomp;
|
||||
};
|
||||
|
||||
struct pcomp_test_suite {
|
||||
struct {
|
||||
struct pcomp_testvec *vecs;
|
||||
unsigned int count;
|
||||
} comp, decomp;
|
||||
};
|
||||
|
||||
struct hash_test_suite {
|
||||
struct hash_testvec *vecs;
|
||||
unsigned int count;
|
||||
@@ -133,7 +126,6 @@ struct alg_test_desc {
|
||||
struct aead_test_suite aead;
|
||||
struct cipher_test_suite cipher;
|
||||
struct comp_test_suite comp;
|
||||
struct pcomp_test_suite pcomp;
|
||||
struct hash_test_suite hash;
|
||||
struct cprng_test_suite cprng;
|
||||
struct drbg_test_suite drbg;
|
||||
@@ -198,6 +190,61 @@ static int wait_async_op(struct tcrypt_result *tr, int ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ahash_partial_update(struct ahash_request **preq,
|
||||
struct crypto_ahash *tfm, struct hash_testvec *template,
|
||||
void *hash_buff, int k, int temp, struct scatterlist *sg,
|
||||
const char *algo, char *result, struct tcrypt_result *tresult)
|
||||
{
|
||||
char *state;
|
||||
struct ahash_request *req;
|
||||
int statesize, ret = -EINVAL;
|
||||
|
||||
req = *preq;
|
||||
statesize = crypto_ahash_statesize(
|
||||
crypto_ahash_reqtfm(req));
|
||||
state = kmalloc(statesize, GFP_KERNEL);
|
||||
if (!state) {
|
||||
pr_err("alt: hash: Failed to alloc state for %s\n", algo);
|
||||
goto out_nostate;
|
||||
}
|
||||
ret = crypto_ahash_export(req, state);
|
||||
if (ret) {
|
||||
pr_err("alt: hash: Failed to export() for %s\n", algo);
|
||||
goto out;
|
||||
}
|
||||
ahash_request_free(req);
|
||||
req = ahash_request_alloc(tfm, GFP_KERNEL);
|
||||
if (!req) {
|
||||
pr_err("alg: hash: Failed to alloc request for %s\n", algo);
|
||||
goto out_noreq;
|
||||
}
|
||||
ahash_request_set_callback(req,
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG,
|
||||
tcrypt_complete, tresult);
|
||||
|
||||
memcpy(hash_buff, template->plaintext + temp,
|
||||
template->tap[k]);
|
||||
sg_init_one(&sg[0], hash_buff, template->tap[k]);
|
||||
ahash_request_set_crypt(req, sg, result, template->tap[k]);
|
||||
ret = crypto_ahash_import(req, state);
|
||||
if (ret) {
|
||||
pr_err("alg: hash: Failed to import() for %s\n", algo);
|
||||
goto out;
|
||||
}
|
||||
ret = wait_async_op(tresult, crypto_ahash_update(req));
|
||||
if (ret)
|
||||
goto out;
|
||||
*preq = req;
|
||||
ret = 0;
|
||||
goto out_noreq;
|
||||
out:
|
||||
ahash_request_free(req);
|
||||
out_noreq:
|
||||
kfree(state);
|
||||
out_nostate:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
|
||||
unsigned int tcount, bool use_digest,
|
||||
const int align_offset)
|
||||
@@ -385,6 +432,84 @@ static int __test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
|
||||
}
|
||||
}
|
||||
|
||||
/* partial update exercise */
|
||||
j = 0;
|
||||
for (i = 0; i < tcount; i++) {
|
||||
/* alignment tests are only done with continuous buffers */
|
||||
if (align_offset != 0)
|
||||
break;
|
||||
|
||||
if (template[i].np < 2)
|
||||
continue;
|
||||
|
||||
j++;
|
||||
memset(result, 0, MAX_DIGEST_SIZE);
|
||||
|
||||
ret = -EINVAL;
|
||||
hash_buff = xbuf[0];
|
||||
memcpy(hash_buff, template[i].plaintext,
|
||||
template[i].tap[0]);
|
||||
sg_init_one(&sg[0], hash_buff, template[i].tap[0]);
|
||||
|
||||
if (template[i].ksize) {
|
||||
crypto_ahash_clear_flags(tfm, ~0);
|
||||
if (template[i].ksize > MAX_KEYLEN) {
|
||||
pr_err("alg: hash: setkey failed on test %d for %s: key size %d > %d\n",
|
||||
j, algo, template[i].ksize, MAX_KEYLEN);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
memcpy(key, template[i].key, template[i].ksize);
|
||||
ret = crypto_ahash_setkey(tfm, key, template[i].ksize);
|
||||
if (ret) {
|
||||
pr_err("alg: hash: setkey failed on test %d for %s: ret=%d\n",
|
||||
j, algo, -ret);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ahash_request_set_crypt(req, sg, result, template[i].tap[0]);
|
||||
ret = wait_async_op(&tresult, crypto_ahash_init(req));
|
||||
if (ret) {
|
||||
pr_err("alt: hash: init failed on test %d for %s: ret=%d\n",
|
||||
j, algo, -ret);
|
||||
goto out;
|
||||
}
|
||||
ret = wait_async_op(&tresult, crypto_ahash_update(req));
|
||||
if (ret) {
|
||||
pr_err("alt: hash: update failed on test %d for %s: ret=%d\n",
|
||||
j, algo, -ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
temp = template[i].tap[0];
|
||||
for (k = 1; k < template[i].np; k++) {
|
||||
ret = ahash_partial_update(&req, tfm, &template[i],
|
||||
hash_buff, k, temp, &sg[0], algo, result,
|
||||
&tresult);
|
||||
if (ret) {
|
||||
pr_err("hash: partial update failed on test %d for %s: ret=%d\n",
|
||||
j, algo, -ret);
|
||||
goto out_noreq;
|
||||
}
|
||||
temp += template[i].tap[k];
|
||||
}
|
||||
ret = wait_async_op(&tresult, crypto_ahash_final(req));
|
||||
if (ret) {
|
||||
pr_err("alt: hash: final failed on test %d for %s: ret=%d\n",
|
||||
j, algo, -ret);
|
||||
goto out;
|
||||
}
|
||||
if (memcmp(result, template[i].digest,
|
||||
crypto_ahash_digestsize(tfm))) {
|
||||
pr_err("alg: hash: Partial Test %d failed for %s\n",
|
||||
j, algo);
|
||||
hexdump(result, crypto_ahash_digestsize(tfm));
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
@@ -488,6 +613,8 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
|
||||
aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
|
||||
tcrypt_complete, &result);
|
||||
|
||||
iv_len = crypto_aead_ivsize(tfm);
|
||||
|
||||
for (i = 0, j = 0; i < tcount; i++) {
|
||||
if (template[i].np)
|
||||
continue;
|
||||
@@ -508,7 +635,6 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
|
||||
|
||||
memcpy(input, template[i].input, template[i].ilen);
|
||||
memcpy(assoc, template[i].assoc, template[i].alen);
|
||||
iv_len = crypto_aead_ivsize(tfm);
|
||||
if (template[i].iv)
|
||||
memcpy(iv, template[i].iv, iv_len);
|
||||
else
|
||||
@@ -617,7 +743,7 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
|
||||
j++;
|
||||
|
||||
if (template[i].iv)
|
||||
memcpy(iv, template[i].iv, MAX_IVLEN);
|
||||
memcpy(iv, template[i].iv, iv_len);
|
||||
else
|
||||
memset(iv, 0, MAX_IVLEN);
|
||||
|
||||
@@ -1293,183 +1419,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int test_pcomp(struct crypto_pcomp *tfm,
|
||||
struct pcomp_testvec *ctemplate,
|
||||
struct pcomp_testvec *dtemplate, int ctcount,
|
||||
int dtcount)
|
||||
{
|
||||
const char *algo = crypto_tfm_alg_driver_name(crypto_pcomp_tfm(tfm));
|
||||
unsigned int i;
|
||||
char result[COMP_BUF_SIZE];
|
||||
int res;
|
||||
|
||||
for (i = 0; i < ctcount; i++) {
|
||||
struct comp_request req;
|
||||
unsigned int produced = 0;
|
||||
|
||||
res = crypto_compress_setup(tfm, ctemplate[i].params,
|
||||
ctemplate[i].paramsize);
|
||||
if (res) {
|
||||
pr_err("alg: pcomp: compression setup failed on test "
|
||||
"%d for %s: error=%d\n", i + 1, algo, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = crypto_compress_init(tfm);
|
||||
if (res) {
|
||||
pr_err("alg: pcomp: compression init failed on test "
|
||||
"%d for %s: error=%d\n", i + 1, algo, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
memset(result, 0, sizeof(result));
|
||||
|
||||
req.next_in = ctemplate[i].input;
|
||||
req.avail_in = ctemplate[i].inlen / 2;
|
||||
req.next_out = result;
|
||||
req.avail_out = ctemplate[i].outlen / 2;
|
||||
|
||||
res = crypto_compress_update(tfm, &req);
|
||||
if (res < 0 && (res != -EAGAIN || req.avail_in)) {
|
||||
pr_err("alg: pcomp: compression update failed on test "
|
||||
"%d for %s: error=%d\n", i + 1, algo, res);
|
||||
return res;
|
||||
}
|
||||
if (res > 0)
|
||||
produced += res;
|
||||
|
||||
/* Add remaining input data */
|
||||
req.avail_in += (ctemplate[i].inlen + 1) / 2;
|
||||
|
||||
res = crypto_compress_update(tfm, &req);
|
||||
if (res < 0 && (res != -EAGAIN || req.avail_in)) {
|
||||
pr_err("alg: pcomp: compression update failed on test "
|
||||
"%d for %s: error=%d\n", i + 1, algo, res);
|
||||
return res;
|
||||
}
|
||||
if (res > 0)
|
||||
produced += res;
|
||||
|
||||
/* Provide remaining output space */
|
||||
req.avail_out += COMP_BUF_SIZE - ctemplate[i].outlen / 2;
|
||||
|
||||
res = crypto_compress_final(tfm, &req);
|
||||
if (res < 0) {
|
||||
pr_err("alg: pcomp: compression final failed on test "
|
||||
"%d for %s: error=%d\n", i + 1, algo, res);
|
||||
return res;
|
||||
}
|
||||
produced += res;
|
||||
|
||||
if (COMP_BUF_SIZE - req.avail_out != ctemplate[i].outlen) {
|
||||
pr_err("alg: comp: Compression test %d failed for %s: "
|
||||
"output len = %d (expected %d)\n", i + 1, algo,
|
||||
COMP_BUF_SIZE - req.avail_out,
|
||||
ctemplate[i].outlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (produced != ctemplate[i].outlen) {
|
||||
pr_err("alg: comp: Compression test %d failed for %s: "
|
||||
"returned len = %u (expected %d)\n", i + 1,
|
||||
algo, produced, ctemplate[i].outlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (memcmp(result, ctemplate[i].output, ctemplate[i].outlen)) {
|
||||
pr_err("alg: pcomp: Compression test %d failed for "
|
||||
"%s\n", i + 1, algo);
|
||||
hexdump(result, ctemplate[i].outlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < dtcount; i++) {
|
||||
struct comp_request req;
|
||||
unsigned int produced = 0;
|
||||
|
||||
res = crypto_decompress_setup(tfm, dtemplate[i].params,
|
||||
dtemplate[i].paramsize);
|
||||
if (res) {
|
||||
pr_err("alg: pcomp: decompression setup failed on "
|
||||
"test %d for %s: error=%d\n", i + 1, algo, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = crypto_decompress_init(tfm);
|
||||
if (res) {
|
||||
pr_err("alg: pcomp: decompression init failed on test "
|
||||
"%d for %s: error=%d\n", i + 1, algo, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
memset(result, 0, sizeof(result));
|
||||
|
||||
req.next_in = dtemplate[i].input;
|
||||
req.avail_in = dtemplate[i].inlen / 2;
|
||||
req.next_out = result;
|
||||
req.avail_out = dtemplate[i].outlen / 2;
|
||||
|
||||
res = crypto_decompress_update(tfm, &req);
|
||||
if (res < 0 && (res != -EAGAIN || req.avail_in)) {
|
||||
pr_err("alg: pcomp: decompression update failed on "
|
||||
"test %d for %s: error=%d\n", i + 1, algo, res);
|
||||
return res;
|
||||
}
|
||||
if (res > 0)
|
||||
produced += res;
|
||||
|
||||
/* Add remaining input data */
|
||||
req.avail_in += (dtemplate[i].inlen + 1) / 2;
|
||||
|
||||
res = crypto_decompress_update(tfm, &req);
|
||||
if (res < 0 && (res != -EAGAIN || req.avail_in)) {
|
||||
pr_err("alg: pcomp: decompression update failed on "
|
||||
"test %d for %s: error=%d\n", i + 1, algo, res);
|
||||
return res;
|
||||
}
|
||||
if (res > 0)
|
||||
produced += res;
|
||||
|
||||
/* Provide remaining output space */
|
||||
req.avail_out += COMP_BUF_SIZE - dtemplate[i].outlen / 2;
|
||||
|
||||
res = crypto_decompress_final(tfm, &req);
|
||||
if (res < 0 && (res != -EAGAIN || req.avail_in)) {
|
||||
pr_err("alg: pcomp: decompression final failed on "
|
||||
"test %d for %s: error=%d\n", i + 1, algo, res);
|
||||
return res;
|
||||
}
|
||||
if (res > 0)
|
||||
produced += res;
|
||||
|
||||
if (COMP_BUF_SIZE - req.avail_out != dtemplate[i].outlen) {
|
||||
pr_err("alg: comp: Decompression test %d failed for "
|
||||
"%s: output len = %d (expected %d)\n", i + 1,
|
||||
algo, COMP_BUF_SIZE - req.avail_out,
|
||||
dtemplate[i].outlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (produced != dtemplate[i].outlen) {
|
||||
pr_err("alg: comp: Decompression test %d failed for "
|
||||
"%s: returned len = %u (expected %d)\n", i + 1,
|
||||
algo, produced, dtemplate[i].outlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (memcmp(result, dtemplate[i].output, dtemplate[i].outlen)) {
|
||||
pr_err("alg: pcomp: Decompression test %d failed for "
|
||||
"%s\n", i + 1, algo);
|
||||
hexdump(result, dtemplate[i].outlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int test_cprng(struct crypto_rng *tfm, struct cprng_testvec *template,
|
||||
unsigned int tcount)
|
||||
{
|
||||
@@ -1640,28 +1589,6 @@ static int alg_test_comp(const struct alg_test_desc *desc, const char *driver,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int alg_test_pcomp(const struct alg_test_desc *desc, const char *driver,
|
||||
u32 type, u32 mask)
|
||||
{
|
||||
struct crypto_pcomp *tfm;
|
||||
int err;
|
||||
|
||||
tfm = crypto_alloc_pcomp(driver, type, mask);
|
||||
if (IS_ERR(tfm)) {
|
||||
pr_err("alg: pcomp: Failed to load transform for %s: %ld\n",
|
||||
driver, PTR_ERR(tfm));
|
||||
return PTR_ERR(tfm);
|
||||
}
|
||||
|
||||
err = test_pcomp(tfm, desc->suite.pcomp.comp.vecs,
|
||||
desc->suite.pcomp.decomp.vecs,
|
||||
desc->suite.pcomp.comp.count,
|
||||
desc->suite.pcomp.decomp.count);
|
||||
|
||||
crypto_free_pcomp(tfm);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int alg_test_hash(const struct alg_test_desc *desc, const char *driver,
|
||||
u32 type, u32 mask)
|
||||
{
|
||||
@@ -2081,7 +2008,6 @@ static const struct alg_test_desc alg_test_descs[] = {
|
||||
}, {
|
||||
.alg = "ansi_cprng",
|
||||
.test = alg_test_cprng,
|
||||
.fips_allowed = 1,
|
||||
.suite = {
|
||||
.cprng = {
|
||||
.vecs = ansi_cprng_aes_tv_template,
|
||||
@@ -2132,6 +2058,7 @@ static const struct alg_test_desc alg_test_descs[] = {
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha1),cbc(des3_ede))",
|
||||
.test = alg_test_aead,
|
||||
.fips_allowed = 1,
|
||||
.suite = {
|
||||
.aead = {
|
||||
.enc = {
|
||||
@@ -2142,6 +2069,10 @@ static const struct alg_test_desc alg_test_descs[] = {
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha1),ctr(aes))",
|
||||
.test = alg_test_null,
|
||||
.fips_allowed = 1,
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha1),ecb(cipher_null))",
|
||||
.test = alg_test_aead,
|
||||
@@ -2161,6 +2092,10 @@ static const struct alg_test_desc alg_test_descs[] = {
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha1),rfc3686(ctr(aes)))",
|
||||
.test = alg_test_null,
|
||||
.fips_allowed = 1,
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha224),cbc(des))",
|
||||
.test = alg_test_aead,
|
||||
@@ -2177,6 +2112,7 @@ static const struct alg_test_desc alg_test_descs[] = {
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha224),cbc(des3_ede))",
|
||||
.test = alg_test_aead,
|
||||
.fips_allowed = 1,
|
||||
.suite = {
|
||||
.aead = {
|
||||
.enc = {
|
||||
@@ -2190,6 +2126,7 @@ static const struct alg_test_desc alg_test_descs[] = {
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha256),cbc(aes))",
|
||||
.test = alg_test_aead,
|
||||
.fips_allowed = 1,
|
||||
.suite = {
|
||||
.aead = {
|
||||
.enc = {
|
||||
@@ -2216,6 +2153,7 @@ static const struct alg_test_desc alg_test_descs[] = {
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha256),cbc(des3_ede))",
|
||||
.test = alg_test_aead,
|
||||
.fips_allowed = 1,
|
||||
.suite = {
|
||||
.aead = {
|
||||
.enc = {
|
||||
@@ -2226,6 +2164,14 @@ static const struct alg_test_desc alg_test_descs[] = {
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha256),ctr(aes))",
|
||||
.test = alg_test_null,
|
||||
.fips_allowed = 1,
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha256),rfc3686(ctr(aes)))",
|
||||
.test = alg_test_null,
|
||||
.fips_allowed = 1,
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha384),cbc(des))",
|
||||
.test = alg_test_aead,
|
||||
@@ -2242,6 +2188,7 @@ static const struct alg_test_desc alg_test_descs[] = {
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha384),cbc(des3_ede))",
|
||||
.test = alg_test_aead,
|
||||
.fips_allowed = 1,
|
||||
.suite = {
|
||||
.aead = {
|
||||
.enc = {
|
||||
@@ -2252,8 +2199,17 @@ static const struct alg_test_desc alg_test_descs[] = {
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha384),ctr(aes))",
|
||||
.test = alg_test_null,
|
||||
.fips_allowed = 1,
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha384),rfc3686(ctr(aes)))",
|
||||
.test = alg_test_null,
|
||||
.fips_allowed = 1,
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha512),cbc(aes))",
|
||||
.fips_allowed = 1,
|
||||
.test = alg_test_aead,
|
||||
.suite = {
|
||||
.aead = {
|
||||
@@ -2281,6 +2237,7 @@ static const struct alg_test_desc alg_test_descs[] = {
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha512),cbc(des3_ede))",
|
||||
.test = alg_test_aead,
|
||||
.fips_allowed = 1,
|
||||
.suite = {
|
||||
.aead = {
|
||||
.enc = {
|
||||
@@ -2291,6 +2248,14 @@ static const struct alg_test_desc alg_test_descs[] = {
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha512),ctr(aes))",
|
||||
.test = alg_test_null,
|
||||
.fips_allowed = 1,
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha512),rfc3686(ctr(aes)))",
|
||||
.test = alg_test_null,
|
||||
.fips_allowed = 1,
|
||||
}, {
|
||||
.alg = "cbc(aes)",
|
||||
.test = alg_test_skcipher,
|
||||
@@ -3840,22 +3805,6 @@ static const struct alg_test_desc alg_test_descs[] = {
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
.alg = "zlib",
|
||||
.test = alg_test_pcomp,
|
||||
.fips_allowed = 1,
|
||||
.suite = {
|
||||
.pcomp = {
|
||||
.comp = {
|
||||
.vecs = zlib_comp_tv_template,
|
||||
.count = ZLIB_COMP_TEST_VECTORS
|
||||
},
|
||||
.decomp = {
|
||||
.vecs = zlib_decomp_tv_template,
|
||||
.count = ZLIB_DECOMP_TEST_VECTORS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
144
crypto/testmgr.h
144
crypto/testmgr.h
@@ -25,9 +25,6 @@
|
||||
#define _CRYPTO_TESTMGR_H
|
||||
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/zlib.h>
|
||||
|
||||
#include <crypto/compress.h>
|
||||
|
||||
#define MAX_DIGEST_SIZE 64
|
||||
#define MAX_TAP 8
|
||||
@@ -32268,14 +32265,6 @@ struct comp_testvec {
|
||||
char output[COMP_BUF_SIZE];
|
||||
};
|
||||
|
||||
struct pcomp_testvec {
|
||||
const void *params;
|
||||
unsigned int paramsize;
|
||||
int inlen, outlen;
|
||||
char input[COMP_BUF_SIZE];
|
||||
char output[COMP_BUF_SIZE];
|
||||
};
|
||||
|
||||
/*
|
||||
* Deflate test vectors (null-terminated strings).
|
||||
* Params: winbits=-11, Z_DEFAULT_COMPRESSION, MAX_MEM_LEVEL.
|
||||
@@ -32356,139 +32345,6 @@ static struct comp_testvec deflate_decomp_tv_template[] = {
|
||||
},
|
||||
};
|
||||
|
||||
#define ZLIB_COMP_TEST_VECTORS 2
|
||||
#define ZLIB_DECOMP_TEST_VECTORS 2
|
||||
|
||||
static const struct {
|
||||
struct nlattr nla;
|
||||
int val;
|
||||
} deflate_comp_params[] = {
|
||||
{
|
||||
.nla = {
|
||||
.nla_len = NLA_HDRLEN + sizeof(int),
|
||||
.nla_type = ZLIB_COMP_LEVEL,
|
||||
},
|
||||
.val = Z_DEFAULT_COMPRESSION,
|
||||
}, {
|
||||
.nla = {
|
||||
.nla_len = NLA_HDRLEN + sizeof(int),
|
||||
.nla_type = ZLIB_COMP_METHOD,
|
||||
},
|
||||
.val = Z_DEFLATED,
|
||||
}, {
|
||||
.nla = {
|
||||
.nla_len = NLA_HDRLEN + sizeof(int),
|
||||
.nla_type = ZLIB_COMP_WINDOWBITS,
|
||||
},
|
||||
.val = -11,
|
||||
}, {
|
||||
.nla = {
|
||||
.nla_len = NLA_HDRLEN + sizeof(int),
|
||||
.nla_type = ZLIB_COMP_MEMLEVEL,
|
||||
},
|
||||
.val = MAX_MEM_LEVEL,
|
||||
}, {
|
||||
.nla = {
|
||||
.nla_len = NLA_HDRLEN + sizeof(int),
|
||||
.nla_type = ZLIB_COMP_STRATEGY,
|
||||
},
|
||||
.val = Z_DEFAULT_STRATEGY,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct {
|
||||
struct nlattr nla;
|
||||
int val;
|
||||
} deflate_decomp_params[] = {
|
||||
{
|
||||
.nla = {
|
||||
.nla_len = NLA_HDRLEN + sizeof(int),
|
||||
.nla_type = ZLIB_DECOMP_WINDOWBITS,
|
||||
},
|
||||
.val = -11,
|
||||
}
|
||||
};
|
||||
|
||||
static struct pcomp_testvec zlib_comp_tv_template[] = {
|
||||
{
|
||||
.params = &deflate_comp_params,
|
||||
.paramsize = sizeof(deflate_comp_params),
|
||||
.inlen = 70,
|
||||
.outlen = 38,
|
||||
.input = "Join us now and share the software "
|
||||
"Join us now and share the software ",
|
||||
.output = "\xf3\xca\xcf\xcc\x53\x28\x2d\x56"
|
||||
"\xc8\xcb\x2f\x57\x48\xcc\x4b\x51"
|
||||
"\x28\xce\x48\x2c\x4a\x55\x28\xc9"
|
||||
"\x48\x55\x28\xce\x4f\x2b\x29\x07"
|
||||
"\x71\xbc\x08\x2b\x01\x00",
|
||||
}, {
|
||||
.params = &deflate_comp_params,
|
||||
.paramsize = sizeof(deflate_comp_params),
|
||||
.inlen = 191,
|
||||
.outlen = 122,
|
||||
.input = "This document describes a compression method based on the DEFLATE"
|
||||
"compression algorithm. This document defines the application of "
|
||||
"the DEFLATE algorithm to the IP Payload Compression Protocol.",
|
||||
.output = "\x5d\x8d\x31\x0e\xc2\x30\x10\x04"
|
||||
"\xbf\xb2\x2f\xc8\x1f\x10\x04\x09"
|
||||
"\x89\xc2\x85\x3f\x70\xb1\x2f\xf8"
|
||||
"\x24\xdb\x67\xd9\x47\xc1\xef\x49"
|
||||
"\x68\x12\x51\xae\x76\x67\xd6\x27"
|
||||
"\x19\x88\x1a\xde\x85\xab\x21\xf2"
|
||||
"\x08\x5d\x16\x1e\x20\x04\x2d\xad"
|
||||
"\xf3\x18\xa2\x15\x85\x2d\x69\xc4"
|
||||
"\x42\x83\x23\xb6\x6c\x89\x71\x9b"
|
||||
"\xef\xcf\x8b\x9f\xcf\x33\xca\x2f"
|
||||
"\xed\x62\xa9\x4c\x80\xff\x13\xaf"
|
||||
"\x52\x37\xed\x0e\x52\x6b\x59\x02"
|
||||
"\xd9\x4e\xe8\x7a\x76\x1d\x02\x98"
|
||||
"\xfe\x8a\x87\x83\xa3\x4f\x56\x8a"
|
||||
"\xb8\x9e\x8e\x5c\x57\xd3\xa0\x79"
|
||||
"\xfa\x02",
|
||||
},
|
||||
};
|
||||
|
||||
static struct pcomp_testvec zlib_decomp_tv_template[] = {
|
||||
{
|
||||
.params = &deflate_decomp_params,
|
||||
.paramsize = sizeof(deflate_decomp_params),
|
||||
.inlen = 122,
|
||||
.outlen = 191,
|
||||
.input = "\x5d\x8d\x31\x0e\xc2\x30\x10\x04"
|
||||
"\xbf\xb2\x2f\xc8\x1f\x10\x04\x09"
|
||||
"\x89\xc2\x85\x3f\x70\xb1\x2f\xf8"
|
||||
"\x24\xdb\x67\xd9\x47\xc1\xef\x49"
|
||||
"\x68\x12\x51\xae\x76\x67\xd6\x27"
|
||||
"\x19\x88\x1a\xde\x85\xab\x21\xf2"
|
||||
"\x08\x5d\x16\x1e\x20\x04\x2d\xad"
|
||||
"\xf3\x18\xa2\x15\x85\x2d\x69\xc4"
|
||||
"\x42\x83\x23\xb6\x6c\x89\x71\x9b"
|
||||
"\xef\xcf\x8b\x9f\xcf\x33\xca\x2f"
|
||||
"\xed\x62\xa9\x4c\x80\xff\x13\xaf"
|
||||
"\x52\x37\xed\x0e\x52\x6b\x59\x02"
|
||||
"\xd9\x4e\xe8\x7a\x76\x1d\x02\x98"
|
||||
"\xfe\x8a\x87\x83\xa3\x4f\x56\x8a"
|
||||
"\xb8\x9e\x8e\x5c\x57\xd3\xa0\x79"
|
||||
"\xfa\x02",
|
||||
.output = "This document describes a compression method based on the DEFLATE"
|
||||
"compression algorithm. This document defines the application of "
|
||||
"the DEFLATE algorithm to the IP Payload Compression Protocol.",
|
||||
}, {
|
||||
.params = &deflate_decomp_params,
|
||||
.paramsize = sizeof(deflate_decomp_params),
|
||||
.inlen = 38,
|
||||
.outlen = 70,
|
||||
.input = "\xf3\xca\xcf\xcc\x53\x28\x2d\x56"
|
||||
"\xc8\xcb\x2f\x57\x48\xcc\x4b\x51"
|
||||
"\x28\xce\x48\x2c\x4a\x55\x28\xc9"
|
||||
"\x48\x55\x28\xce\x4f\x2b\x29\x07"
|
||||
"\x71\xbc\x08\x2b\x01\x00",
|
||||
.output = "Join us now and share the software "
|
||||
"Join us now and share the software ",
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* LZO test vectors (null-terminated strings).
|
||||
*/
|
||||
|
11
crypto/xts.c
11
crypto/xts.c
@@ -35,16 +35,11 @@ static int setkey(struct crypto_tfm *parent, const u8 *key,
|
||||
{
|
||||
struct priv *ctx = crypto_tfm_ctx(parent);
|
||||
struct crypto_cipher *child = ctx->tweak;
|
||||
u32 *flags = &parent->crt_flags;
|
||||
int err;
|
||||
|
||||
/* key consists of keys of equal size concatenated, therefore
|
||||
* the length must be even */
|
||||
if (keylen % 2) {
|
||||
/* tell the user why there was an error */
|
||||
*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
|
||||
return -EINVAL;
|
||||
}
|
||||
err = xts_check_key(parent, key, keylen);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* we need two cipher instances: one to compute the initial 'tweak'
|
||||
* by encrypting the IV (usually the 'plain' iv) and the other
|
||||
|
381
crypto/zlib.c
381
crypto/zlib.c
@@ -1,381 +0,0 @@
|
||||
/*
|
||||
* Cryptographic API.
|
||||
*
|
||||
* Zlib algorithm
|
||||
*
|
||||
* Copyright 2008 Sony Corporation
|
||||
*
|
||||
* Based on deflate.c, which is
|
||||
* Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* FIXME: deflate transforms will require up to a total of about 436k of kernel
|
||||
* memory on i386 (390k for compression, the rest for decompression), as the
|
||||
* current zlib kernel code uses a worst case pre-allocation system by default.
|
||||
* This needs to be fixed so that the amount of memory required is properly
|
||||
* related to the winbits and memlevel parameters.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/zlib.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/net.h>
|
||||
|
||||
#include <crypto/internal/compress.h>
|
||||
|
||||
#include <net/netlink.h>
|
||||
|
||||
|
||||
struct zlib_ctx {
|
||||
struct z_stream_s comp_stream;
|
||||
struct z_stream_s decomp_stream;
|
||||
int decomp_windowBits;
|
||||
};
|
||||
|
||||
|
||||
static void zlib_comp_exit(struct zlib_ctx *ctx)
|
||||
{
|
||||
struct z_stream_s *stream = &ctx->comp_stream;
|
||||
|
||||
if (stream->workspace) {
|
||||
zlib_deflateEnd(stream);
|
||||
vfree(stream->workspace);
|
||||
stream->workspace = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void zlib_decomp_exit(struct zlib_ctx *ctx)
|
||||
{
|
||||
struct z_stream_s *stream = &ctx->decomp_stream;
|
||||
|
||||
if (stream->workspace) {
|
||||
zlib_inflateEnd(stream);
|
||||
vfree(stream->workspace);
|
||||
stream->workspace = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int zlib_init(struct crypto_tfm *tfm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void zlib_exit(struct crypto_tfm *tfm)
|
||||
{
|
||||
struct zlib_ctx *ctx = crypto_tfm_ctx(tfm);
|
||||
|
||||
zlib_comp_exit(ctx);
|
||||
zlib_decomp_exit(ctx);
|
||||
}
|
||||
|
||||
|
||||
static int zlib_compress_setup(struct crypto_pcomp *tfm, const void *params,
|
||||
unsigned int len)
|
||||
{
|
||||
struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
|
||||
struct z_stream_s *stream = &ctx->comp_stream;
|
||||
struct nlattr *tb[ZLIB_COMP_MAX + 1];
|
||||
int window_bits, mem_level;
|
||||
size_t workspacesize;
|
||||
int ret;
|
||||
|
||||
ret = nla_parse(tb, ZLIB_COMP_MAX, params, len, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
zlib_comp_exit(ctx);
|
||||
|
||||
window_bits = tb[ZLIB_COMP_WINDOWBITS]
|
||||
? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS])
|
||||
: MAX_WBITS;
|
||||
mem_level = tb[ZLIB_COMP_MEMLEVEL]
|
||||
? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
|
||||
: DEF_MEM_LEVEL;
|
||||
|
||||
workspacesize = zlib_deflate_workspacesize(window_bits, mem_level);
|
||||
stream->workspace = vzalloc(workspacesize);
|
||||
if (!stream->workspace)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = zlib_deflateInit2(stream,
|
||||
tb[ZLIB_COMP_LEVEL]
|
||||
? nla_get_u32(tb[ZLIB_COMP_LEVEL])
|
||||
: Z_DEFAULT_COMPRESSION,
|
||||
tb[ZLIB_COMP_METHOD]
|
||||
? nla_get_u32(tb[ZLIB_COMP_METHOD])
|
||||
: Z_DEFLATED,
|
||||
window_bits,
|
||||
mem_level,
|
||||
tb[ZLIB_COMP_STRATEGY]
|
||||
? nla_get_u32(tb[ZLIB_COMP_STRATEGY])
|
||||
: Z_DEFAULT_STRATEGY);
|
||||
if (ret != Z_OK) {
|
||||
vfree(stream->workspace);
|
||||
stream->workspace = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zlib_compress_init(struct crypto_pcomp *tfm)
|
||||
{
|
||||
int ret;
|
||||
struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
|
||||
struct z_stream_s *stream = &dctx->comp_stream;
|
||||
|
||||
ret = zlib_deflateReset(stream);
|
||||
if (ret != Z_OK)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zlib_compress_update(struct crypto_pcomp *tfm,
|
||||
struct comp_request *req)
|
||||
{
|
||||
int ret;
|
||||
struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
|
||||
struct z_stream_s *stream = &dctx->comp_stream;
|
||||
|
||||
pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
|
||||
stream->next_in = req->next_in;
|
||||
stream->avail_in = req->avail_in;
|
||||
stream->next_out = req->next_out;
|
||||
stream->avail_out = req->avail_out;
|
||||
|
||||
ret = zlib_deflate(stream, Z_NO_FLUSH);
|
||||
switch (ret) {
|
||||
case Z_OK:
|
||||
break;
|
||||
|
||||
case Z_BUF_ERROR:
|
||||
pr_debug("zlib_deflate could not make progress\n");
|
||||
return -EAGAIN;
|
||||
|
||||
default:
|
||||
pr_debug("zlib_deflate failed %d\n", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = req->avail_out - stream->avail_out;
|
||||
pr_debug("avail_in %lu, avail_out %lu (consumed %lu, produced %u)\n",
|
||||
stream->avail_in, stream->avail_out,
|
||||
req->avail_in - stream->avail_in, ret);
|
||||
req->next_in = stream->next_in;
|
||||
req->avail_in = stream->avail_in;
|
||||
req->next_out = stream->next_out;
|
||||
req->avail_out = stream->avail_out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int zlib_compress_final(struct crypto_pcomp *tfm,
|
||||
struct comp_request *req)
|
||||
{
|
||||
int ret;
|
||||
struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
|
||||
struct z_stream_s *stream = &dctx->comp_stream;
|
||||
|
||||
pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
|
||||
stream->next_in = req->next_in;
|
||||
stream->avail_in = req->avail_in;
|
||||
stream->next_out = req->next_out;
|
||||
stream->avail_out = req->avail_out;
|
||||
|
||||
ret = zlib_deflate(stream, Z_FINISH);
|
||||
if (ret != Z_STREAM_END) {
|
||||
pr_debug("zlib_deflate failed %d\n", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = req->avail_out - stream->avail_out;
|
||||
pr_debug("avail_in %lu, avail_out %lu (consumed %lu, produced %u)\n",
|
||||
stream->avail_in, stream->avail_out,
|
||||
req->avail_in - stream->avail_in, ret);
|
||||
req->next_in = stream->next_in;
|
||||
req->avail_in = stream->avail_in;
|
||||
req->next_out = stream->next_out;
|
||||
req->avail_out = stream->avail_out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int zlib_decompress_setup(struct crypto_pcomp *tfm, const void *params,
|
||||
unsigned int len)
|
||||
{
|
||||
struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
|
||||
struct z_stream_s *stream = &ctx->decomp_stream;
|
||||
struct nlattr *tb[ZLIB_DECOMP_MAX + 1];
|
||||
int ret = 0;
|
||||
|
||||
ret = nla_parse(tb, ZLIB_DECOMP_MAX, params, len, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
zlib_decomp_exit(ctx);
|
||||
|
||||
ctx->decomp_windowBits = tb[ZLIB_DECOMP_WINDOWBITS]
|
||||
? nla_get_u32(tb[ZLIB_DECOMP_WINDOWBITS])
|
||||
: DEF_WBITS;
|
||||
|
||||
stream->workspace = vzalloc(zlib_inflate_workspacesize());
|
||||
if (!stream->workspace)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = zlib_inflateInit2(stream, ctx->decomp_windowBits);
|
||||
if (ret != Z_OK) {
|
||||
vfree(stream->workspace);
|
||||
stream->workspace = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zlib_decompress_init(struct crypto_pcomp *tfm)
|
||||
{
|
||||
int ret;
|
||||
struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
|
||||
struct z_stream_s *stream = &dctx->decomp_stream;
|
||||
|
||||
ret = zlib_inflateReset(stream);
|
||||
if (ret != Z_OK)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zlib_decompress_update(struct crypto_pcomp *tfm,
|
||||
struct comp_request *req)
|
||||
{
|
||||
int ret;
|
||||
struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
|
||||
struct z_stream_s *stream = &dctx->decomp_stream;
|
||||
|
||||
pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
|
||||
stream->next_in = req->next_in;
|
||||
stream->avail_in = req->avail_in;
|
||||
stream->next_out = req->next_out;
|
||||
stream->avail_out = req->avail_out;
|
||||
|
||||
ret = zlib_inflate(stream, Z_SYNC_FLUSH);
|
||||
switch (ret) {
|
||||
case Z_OK:
|
||||
case Z_STREAM_END:
|
||||
break;
|
||||
|
||||
case Z_BUF_ERROR:
|
||||
pr_debug("zlib_inflate could not make progress\n");
|
||||
return -EAGAIN;
|
||||
|
||||
default:
|
||||
pr_debug("zlib_inflate failed %d\n", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = req->avail_out - stream->avail_out;
|
||||
pr_debug("avail_in %lu, avail_out %lu (consumed %lu, produced %u)\n",
|
||||
stream->avail_in, stream->avail_out,
|
||||
req->avail_in - stream->avail_in, ret);
|
||||
req->next_in = stream->next_in;
|
||||
req->avail_in = stream->avail_in;
|
||||
req->next_out = stream->next_out;
|
||||
req->avail_out = stream->avail_out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int zlib_decompress_final(struct crypto_pcomp *tfm,
|
||||
struct comp_request *req)
|
||||
{
|
||||
int ret;
|
||||
struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
|
||||
struct z_stream_s *stream = &dctx->decomp_stream;
|
||||
|
||||
pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
|
||||
stream->next_in = req->next_in;
|
||||
stream->avail_in = req->avail_in;
|
||||
stream->next_out = req->next_out;
|
||||
stream->avail_out = req->avail_out;
|
||||
|
||||
if (dctx->decomp_windowBits < 0) {
|
||||
ret = zlib_inflate(stream, Z_SYNC_FLUSH);
|
||||
/*
|
||||
* Work around a bug in zlib, which sometimes wants to taste an
|
||||
* extra byte when being used in the (undocumented) raw deflate
|
||||
* mode. (From USAGI).
|
||||
*/
|
||||
if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
|
||||
const void *saved_next_in = stream->next_in;
|
||||
u8 zerostuff = 0;
|
||||
|
||||
stream->next_in = &zerostuff;
|
||||
stream->avail_in = 1;
|
||||
ret = zlib_inflate(stream, Z_FINISH);
|
||||
stream->next_in = saved_next_in;
|
||||
stream->avail_in = 0;
|
||||
}
|
||||
} else
|
||||
ret = zlib_inflate(stream, Z_FINISH);
|
||||
if (ret != Z_STREAM_END) {
|
||||
pr_debug("zlib_inflate failed %d\n", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = req->avail_out - stream->avail_out;
|
||||
pr_debug("avail_in %lu, avail_out %lu (consumed %lu, produced %u)\n",
|
||||
stream->avail_in, stream->avail_out,
|
||||
req->avail_in - stream->avail_in, ret);
|
||||
req->next_in = stream->next_in;
|
||||
req->avail_in = stream->avail_in;
|
||||
req->next_out = stream->next_out;
|
||||
req->avail_out = stream->avail_out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static struct pcomp_alg zlib_alg = {
|
||||
.compress_setup = zlib_compress_setup,
|
||||
.compress_init = zlib_compress_init,
|
||||
.compress_update = zlib_compress_update,
|
||||
.compress_final = zlib_compress_final,
|
||||
.decompress_setup = zlib_decompress_setup,
|
||||
.decompress_init = zlib_decompress_init,
|
||||
.decompress_update = zlib_decompress_update,
|
||||
.decompress_final = zlib_decompress_final,
|
||||
|
||||
.base = {
|
||||
.cra_name = "zlib",
|
||||
.cra_flags = CRYPTO_ALG_TYPE_PCOMPRESS,
|
||||
.cra_ctxsize = sizeof(struct zlib_ctx),
|
||||
.cra_module = THIS_MODULE,
|
||||
.cra_init = zlib_init,
|
||||
.cra_exit = zlib_exit,
|
||||
}
|
||||
};
|
||||
|
||||
static int __init zlib_mod_init(void)
|
||||
{
|
||||
return crypto_register_pcomp(&zlib_alg);
|
||||
}
|
||||
|
||||
static void __exit zlib_mod_fini(void)
|
||||
{
|
||||
crypto_unregister_pcomp(&zlib_alg);
|
||||
}
|
||||
|
||||
module_init(zlib_mod_init);
|
||||
module_exit(zlib_mod_fini);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Zlib Compression Algorithm");
|
||||
MODULE_AUTHOR("Sony Corporation");
|
||||
MODULE_ALIAS_CRYPTO("zlib");
|
Reference in New Issue
Block a user