mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
Merge remote-tracking branch 'lsk/v3.10/topic/arm64-crypto' into linux-linaro-lsk
This commit is contained in:
@@ -179,6 +179,10 @@ config CRYPTO_ABLK_HELPER_X86
|
||||
depends on X86
|
||||
select CRYPTO_CRYPTD
|
||||
|
||||
config CRYPTO_ABLK_HELPER
|
||||
tristate
|
||||
select CRYPTO_CRYPTD
|
||||
|
||||
config CRYPTO_GLUE_HELPER_X86
|
||||
tristate
|
||||
depends on X86
|
||||
|
||||
@@ -101,3 +101,4 @@ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
|
||||
obj-$(CONFIG_XOR_BLOCKS) += xor.o
|
||||
obj-$(CONFIG_ASYNC_CORE) += async_tx/
|
||||
obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/
|
||||
obj-$(CONFIG_CRYPTO_ABLK_HELPER) += ablk_helper.o
|
||||
|
||||
150
crypto/ablk_helper.c
Normal file
150
crypto/ablk_helper.c
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Shared async block cipher helpers
|
||||
*
|
||||
* Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
|
||||
*
|
||||
* Based on aesni-intel_glue.c by:
|
||||
* Copyright (C) 2008, Intel Corp.
|
||||
* Author: Huang Ying <ying.huang@intel.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <crypto/algapi.h>
|
||||
#include <crypto/cryptd.h>
|
||||
#include <crypto/ablk_helper.h>
|
||||
#include <asm/simd.h>
|
||||
|
||||
int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
|
||||
unsigned int key_len)
|
||||
{
|
||||
struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm);
|
||||
struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base;
|
||||
int err;
|
||||
|
||||
crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
|
||||
crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm)
|
||||
& CRYPTO_TFM_REQ_MASK);
|
||||
err = crypto_ablkcipher_setkey(child, key, key_len);
|
||||
crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child)
|
||||
& CRYPTO_TFM_RES_MASK);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ablk_set_key);
|
||||
|
||||
int __ablk_encrypt(struct ablkcipher_request *req)
|
||||
{
|
||||
struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
|
||||
struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm);
|
||||
struct blkcipher_desc desc;
|
||||
|
||||
desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
|
||||
desc.info = req->info;
|
||||
desc.flags = 0;
|
||||
|
||||
return crypto_blkcipher_crt(desc.tfm)->encrypt(
|
||||
&desc, req->dst, req->src, req->nbytes);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__ablk_encrypt);
|
||||
|
||||
int ablk_encrypt(struct ablkcipher_request *req)
|
||||
{
|
||||
struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
|
||||
struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm);
|
||||
|
||||
if (!may_use_simd()) {
|
||||
struct ablkcipher_request *cryptd_req =
|
||||
ablkcipher_request_ctx(req);
|
||||
|
||||
memcpy(cryptd_req, req, sizeof(*req));
|
||||
ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
|
||||
|
||||
return crypto_ablkcipher_encrypt(cryptd_req);
|
||||
} else {
|
||||
return __ablk_encrypt(req);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ablk_encrypt);
|
||||
|
||||
int ablk_decrypt(struct ablkcipher_request *req)
|
||||
{
|
||||
struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
|
||||
struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm);
|
||||
|
||||
if (!may_use_simd()) {
|
||||
struct ablkcipher_request *cryptd_req =
|
||||
ablkcipher_request_ctx(req);
|
||||
|
||||
memcpy(cryptd_req, req, sizeof(*req));
|
||||
ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
|
||||
|
||||
return crypto_ablkcipher_decrypt(cryptd_req);
|
||||
} else {
|
||||
struct blkcipher_desc desc;
|
||||
|
||||
desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
|
||||
desc.info = req->info;
|
||||
desc.flags = 0;
|
||||
|
||||
return crypto_blkcipher_crt(desc.tfm)->decrypt(
|
||||
&desc, req->dst, req->src, req->nbytes);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ablk_decrypt);
|
||||
|
||||
void ablk_exit(struct crypto_tfm *tfm)
|
||||
{
|
||||
struct async_helper_ctx *ctx = crypto_tfm_ctx(tfm);
|
||||
|
||||
cryptd_free_ablkcipher(ctx->cryptd_tfm);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ablk_exit);
|
||||
|
||||
int ablk_init_common(struct crypto_tfm *tfm, const char *drv_name)
|
||||
{
|
||||
struct async_helper_ctx *ctx = crypto_tfm_ctx(tfm);
|
||||
struct cryptd_ablkcipher *cryptd_tfm;
|
||||
|
||||
cryptd_tfm = cryptd_alloc_ablkcipher(drv_name, 0, 0);
|
||||
if (IS_ERR(cryptd_tfm))
|
||||
return PTR_ERR(cryptd_tfm);
|
||||
|
||||
ctx->cryptd_tfm = cryptd_tfm;
|
||||
tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) +
|
||||
crypto_ablkcipher_reqsize(&cryptd_tfm->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ablk_init_common);
|
||||
|
||||
int ablk_init(struct crypto_tfm *tfm)
|
||||
{
|
||||
char drv_name[CRYPTO_MAX_ALG_NAME];
|
||||
|
||||
snprintf(drv_name, sizeof(drv_name), "__driver-%s",
|
||||
crypto_tfm_alg_driver_name(tfm));
|
||||
|
||||
return ablk_init_common(tfm, drv_name);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ablk_init);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -70,14 +70,12 @@ static inline u8 *blkcipher_get_spot(u8 *start, unsigned int len)
|
||||
return max(start, end_page);
|
||||
}
|
||||
|
||||
static inline unsigned int blkcipher_done_slow(struct crypto_blkcipher *tfm,
|
||||
struct blkcipher_walk *walk,
|
||||
static inline unsigned int blkcipher_done_slow(struct blkcipher_walk *walk,
|
||||
unsigned int bsize)
|
||||
{
|
||||
u8 *addr;
|
||||
unsigned int alignmask = crypto_blkcipher_alignmask(tfm);
|
||||
|
||||
addr = (u8 *)ALIGN((unsigned long)walk->buffer, alignmask + 1);
|
||||
addr = (u8 *)ALIGN((unsigned long)walk->buffer, walk->alignmask + 1);
|
||||
addr = blkcipher_get_spot(addr, bsize);
|
||||
scatterwalk_copychunks(addr, &walk->out, bsize, 1);
|
||||
return bsize;
|
||||
@@ -105,7 +103,6 @@ static inline unsigned int blkcipher_done_fast(struct blkcipher_walk *walk,
|
||||
int blkcipher_walk_done(struct blkcipher_desc *desc,
|
||||
struct blkcipher_walk *walk, int err)
|
||||
{
|
||||
struct crypto_blkcipher *tfm = desc->tfm;
|
||||
unsigned int nbytes = 0;
|
||||
|
||||
if (likely(err >= 0)) {
|
||||
@@ -117,7 +114,7 @@ int blkcipher_walk_done(struct blkcipher_desc *desc,
|
||||
err = -EINVAL;
|
||||
goto err;
|
||||
} else
|
||||
n = blkcipher_done_slow(tfm, walk, n);
|
||||
n = blkcipher_done_slow(walk, n);
|
||||
|
||||
nbytes = walk->total - n;
|
||||
err = 0;
|
||||
@@ -136,7 +133,7 @@ err:
|
||||
}
|
||||
|
||||
if (walk->iv != desc->info)
|
||||
memcpy(desc->info, walk->iv, crypto_blkcipher_ivsize(tfm));
|
||||
memcpy(desc->info, walk->iv, walk->ivsize);
|
||||
if (walk->buffer != walk->page)
|
||||
kfree(walk->buffer);
|
||||
if (walk->page)
|
||||
@@ -226,22 +223,20 @@ static inline int blkcipher_next_fast(struct blkcipher_desc *desc,
|
||||
static int blkcipher_walk_next(struct blkcipher_desc *desc,
|
||||
struct blkcipher_walk *walk)
|
||||
{
|
||||
struct crypto_blkcipher *tfm = desc->tfm;
|
||||
unsigned int alignmask = crypto_blkcipher_alignmask(tfm);
|
||||
unsigned int bsize;
|
||||
unsigned int n;
|
||||
int err;
|
||||
|
||||
n = walk->total;
|
||||
if (unlikely(n < crypto_blkcipher_blocksize(tfm))) {
|
||||
if (unlikely(n < walk->cipher_blocksize)) {
|
||||
desc->flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN;
|
||||
return blkcipher_walk_done(desc, walk, -EINVAL);
|
||||
}
|
||||
|
||||
walk->flags &= ~(BLKCIPHER_WALK_SLOW | BLKCIPHER_WALK_COPY |
|
||||
BLKCIPHER_WALK_DIFF);
|
||||
if (!scatterwalk_aligned(&walk->in, alignmask) ||
|
||||
!scatterwalk_aligned(&walk->out, alignmask)) {
|
||||
if (!scatterwalk_aligned(&walk->in, walk->alignmask) ||
|
||||
!scatterwalk_aligned(&walk->out, walk->alignmask)) {
|
||||
walk->flags |= BLKCIPHER_WALK_COPY;
|
||||
if (!walk->page) {
|
||||
walk->page = (void *)__get_free_page(GFP_ATOMIC);
|
||||
@@ -250,12 +245,12 @@ static int blkcipher_walk_next(struct blkcipher_desc *desc,
|
||||
}
|
||||
}
|
||||
|
||||
bsize = min(walk->blocksize, n);
|
||||
bsize = min(walk->walk_blocksize, n);
|
||||
n = scatterwalk_clamp(&walk->in, n);
|
||||
n = scatterwalk_clamp(&walk->out, n);
|
||||
|
||||
if (unlikely(n < bsize)) {
|
||||
err = blkcipher_next_slow(desc, walk, bsize, alignmask);
|
||||
err = blkcipher_next_slow(desc, walk, bsize, walk->alignmask);
|
||||
goto set_phys_lowmem;
|
||||
}
|
||||
|
||||
@@ -277,28 +272,26 @@ set_phys_lowmem:
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline int blkcipher_copy_iv(struct blkcipher_walk *walk,
|
||||
struct crypto_blkcipher *tfm,
|
||||
unsigned int alignmask)
|
||||
static inline int blkcipher_copy_iv(struct blkcipher_walk *walk)
|
||||
{
|
||||
unsigned bs = walk->blocksize;
|
||||
unsigned int ivsize = crypto_blkcipher_ivsize(tfm);
|
||||
unsigned aligned_bs = ALIGN(bs, alignmask + 1);
|
||||
unsigned int size = aligned_bs * 2 + ivsize + max(aligned_bs, ivsize) -
|
||||
(alignmask + 1);
|
||||
unsigned bs = walk->walk_blocksize;
|
||||
unsigned aligned_bs = ALIGN(bs, walk->alignmask + 1);
|
||||
unsigned int size = aligned_bs * 2 +
|
||||
walk->ivsize + max(aligned_bs, walk->ivsize) -
|
||||
(walk->alignmask + 1);
|
||||
u8 *iv;
|
||||
|
||||
size += alignmask & ~(crypto_tfm_ctx_alignment() - 1);
|
||||
size += walk->alignmask & ~(crypto_tfm_ctx_alignment() - 1);
|
||||
walk->buffer = kmalloc(size, GFP_ATOMIC);
|
||||
if (!walk->buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
iv = (u8 *)ALIGN((unsigned long)walk->buffer, alignmask + 1);
|
||||
iv = (u8 *)ALIGN((unsigned long)walk->buffer, walk->alignmask + 1);
|
||||
iv = blkcipher_get_spot(iv, bs) + aligned_bs;
|
||||
iv = blkcipher_get_spot(iv, bs) + aligned_bs;
|
||||
iv = blkcipher_get_spot(iv, ivsize);
|
||||
iv = blkcipher_get_spot(iv, walk->ivsize);
|
||||
|
||||
walk->iv = memcpy(iv, walk->iv, ivsize);
|
||||
walk->iv = memcpy(iv, walk->iv, walk->ivsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -306,7 +299,10 @@ int blkcipher_walk_virt(struct blkcipher_desc *desc,
|
||||
struct blkcipher_walk *walk)
|
||||
{
|
||||
walk->flags &= ~BLKCIPHER_WALK_PHYS;
|
||||
walk->blocksize = crypto_blkcipher_blocksize(desc->tfm);
|
||||
walk->walk_blocksize = crypto_blkcipher_blocksize(desc->tfm);
|
||||
walk->cipher_blocksize = walk->walk_blocksize;
|
||||
walk->ivsize = crypto_blkcipher_ivsize(desc->tfm);
|
||||
walk->alignmask = crypto_blkcipher_alignmask(desc->tfm);
|
||||
return blkcipher_walk_first(desc, walk);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blkcipher_walk_virt);
|
||||
@@ -315,7 +311,10 @@ int blkcipher_walk_phys(struct blkcipher_desc *desc,
|
||||
struct blkcipher_walk *walk)
|
||||
{
|
||||
walk->flags |= BLKCIPHER_WALK_PHYS;
|
||||
walk->blocksize = crypto_blkcipher_blocksize(desc->tfm);
|
||||
walk->walk_blocksize = crypto_blkcipher_blocksize(desc->tfm);
|
||||
walk->cipher_blocksize = walk->walk_blocksize;
|
||||
walk->ivsize = crypto_blkcipher_ivsize(desc->tfm);
|
||||
walk->alignmask = crypto_blkcipher_alignmask(desc->tfm);
|
||||
return blkcipher_walk_first(desc, walk);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blkcipher_walk_phys);
|
||||
@@ -323,9 +322,6 @@ EXPORT_SYMBOL_GPL(blkcipher_walk_phys);
|
||||
static int blkcipher_walk_first(struct blkcipher_desc *desc,
|
||||
struct blkcipher_walk *walk)
|
||||
{
|
||||
struct crypto_blkcipher *tfm = desc->tfm;
|
||||
unsigned int alignmask = crypto_blkcipher_alignmask(tfm);
|
||||
|
||||
if (WARN_ON_ONCE(in_irq()))
|
||||
return -EDEADLK;
|
||||
|
||||
@@ -335,8 +331,8 @@ static int blkcipher_walk_first(struct blkcipher_desc *desc,
|
||||
|
||||
walk->buffer = NULL;
|
||||
walk->iv = desc->info;
|
||||
if (unlikely(((unsigned long)walk->iv & alignmask))) {
|
||||
int err = blkcipher_copy_iv(walk, tfm, alignmask);
|
||||
if (unlikely(((unsigned long)walk->iv & walk->alignmask))) {
|
||||
int err = blkcipher_copy_iv(walk);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@@ -353,11 +349,28 @@ int blkcipher_walk_virt_block(struct blkcipher_desc *desc,
|
||||
unsigned int blocksize)
|
||||
{
|
||||
walk->flags &= ~BLKCIPHER_WALK_PHYS;
|
||||
walk->blocksize = blocksize;
|
||||
walk->walk_blocksize = blocksize;
|
||||
walk->cipher_blocksize = crypto_blkcipher_blocksize(desc->tfm);
|
||||
walk->ivsize = crypto_blkcipher_ivsize(desc->tfm);
|
||||
walk->alignmask = crypto_blkcipher_alignmask(desc->tfm);
|
||||
return blkcipher_walk_first(desc, walk);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blkcipher_walk_virt_block);
|
||||
|
||||
int blkcipher_aead_walk_virt_block(struct blkcipher_desc *desc,
|
||||
struct blkcipher_walk *walk,
|
||||
struct crypto_aead *tfm,
|
||||
unsigned int blocksize)
|
||||
{
|
||||
walk->flags &= ~BLKCIPHER_WALK_PHYS;
|
||||
walk->walk_blocksize = blocksize;
|
||||
walk->cipher_blocksize = crypto_aead_blocksize(tfm);
|
||||
walk->ivsize = crypto_aead_ivsize(tfm);
|
||||
walk->alignmask = crypto_aead_alignmask(tfm);
|
||||
return blkcipher_walk_first(desc, walk);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blkcipher_aead_walk_virt_block);
|
||||
|
||||
static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key,
|
||||
unsigned int keylen)
|
||||
{
|
||||
|
||||
14
include/asm-generic/simd.h
Normal file
14
include/asm-generic/simd.h
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
#include <linux/hardirq.h>
|
||||
|
||||
/*
|
||||
* may_use_simd - whether it is allowable at this time to issue SIMD
|
||||
* instructions or access the SIMD register file
|
||||
*
|
||||
* As architectures typically don't preserve the SIMD register file when
|
||||
* taking an interrupt, !in_interrupt() should be a reasonable default.
|
||||
*/
|
||||
static __must_check inline bool may_use_simd(void)
|
||||
{
|
||||
return !in_interrupt();
|
||||
}
|
||||
31
include/crypto/ablk_helper.h
Normal file
31
include/crypto/ablk_helper.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Shared async block cipher helpers
|
||||
*/
|
||||
|
||||
#ifndef _CRYPTO_ABLK_HELPER_H
|
||||
#define _CRYPTO_ABLK_HELPER_H
|
||||
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <crypto/cryptd.h>
|
||||
|
||||
struct async_helper_ctx {
|
||||
struct cryptd_ablkcipher *cryptd_tfm;
|
||||
};
|
||||
|
||||
extern int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
|
||||
unsigned int key_len);
|
||||
|
||||
extern int __ablk_encrypt(struct ablkcipher_request *req);
|
||||
|
||||
extern int ablk_encrypt(struct ablkcipher_request *req);
|
||||
|
||||
extern int ablk_decrypt(struct ablkcipher_request *req);
|
||||
|
||||
extern void ablk_exit(struct crypto_tfm *tfm);
|
||||
|
||||
extern int ablk_init_common(struct crypto_tfm *tfm, const char *drv_name);
|
||||
|
||||
extern int ablk_init(struct crypto_tfm *tfm);
|
||||
|
||||
#endif /* _CRYPTO_ABLK_HELPER_H */
|
||||
@@ -100,9 +100,12 @@ struct blkcipher_walk {
|
||||
void *page;
|
||||
u8 *buffer;
|
||||
u8 *iv;
|
||||
unsigned int ivsize;
|
||||
|
||||
int flags;
|
||||
unsigned int blocksize;
|
||||
unsigned int walk_blocksize;
|
||||
unsigned int cipher_blocksize;
|
||||
unsigned int alignmask;
|
||||
};
|
||||
|
||||
struct ablkcipher_walk {
|
||||
@@ -192,6 +195,10 @@ int blkcipher_walk_phys(struct blkcipher_desc *desc,
|
||||
int blkcipher_walk_virt_block(struct blkcipher_desc *desc,
|
||||
struct blkcipher_walk *walk,
|
||||
unsigned int blocksize);
|
||||
int blkcipher_aead_walk_virt_block(struct blkcipher_desc *desc,
|
||||
struct blkcipher_walk *walk,
|
||||
struct crypto_aead *tfm,
|
||||
unsigned int blocksize);
|
||||
|
||||
int ablkcipher_walk_done(struct ablkcipher_request *req,
|
||||
struct ablkcipher_walk *walk, int err);
|
||||
|
||||
Reference in New Issue
Block a user