immortalwrt/package/kernel/lantiq/ltq-deu/src/ifxmips_aes.c
Adrian Schmutzler b510ab513e kernel: drop outdated kernel version switches for local code
This drops kernel version switches for versions not supported by
OpenWrt master at the moment. This only adjusts local code, but
doesn't touch patches to existing external packages.

Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de>
2020-05-17 18:35:51 +02:00

958 lines
33 KiB
C

/******************************************************************************
**
** FILE NAME : ifxmips_aes.c
** PROJECT : IFX UEIP
** MODULES : DEU Module
**
** DATE : September 8, 2009
** AUTHOR : Mohammad Firdaus
** DESCRIPTION : Data Encryption Unit Driver for AES Algorithm
** COPYRIGHT : Copyright (c) 2009
** Infineon Technologies AG
** Am Campeon 1-12, 85579 Neubiberg, Germany
**
** 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.
**
** HISTORY
** $Date $Author $Comment
** 08,Sept 2009 Mohammad Firdaus Initial UEIP release
*******************************************************************************/
/*!
\defgroup IFX_DEU IFX_DEU_DRIVERS
\ingroup API
\brief ifx DEU driver module
*/
/*!
\file ifxmips_aes.c
\ingroup IFX_DEU
\brief AES Encryption Driver main file
*/
/*!
\defgroup IFX_AES_FUNCTIONS IFX_AES_FUNCTIONS
\ingroup IFX_DEU
\brief IFX AES driver Functions
*/
/* Project Header Files */
#if defined(CONFIG_MODVERSIONS)
#define MODVERSIONS
#include <linux/modeversions>
#endif
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/crypto.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <asm/byteorder.h>
#include <crypto/algapi.h>
#include "ifxmips_deu.h"
#if defined(CONFIG_DANUBE)
#include "ifxmips_deu_danube.h"
extern int ifx_danube_pre_1_4;
#elif defined(CONFIG_AR9)
#include "ifxmips_deu_ar9.h"
#elif defined(CONFIG_VR9) || defined(CONFIG_AR10)
#include "ifxmips_deu_vr9.h"
#else
#error "Unkown platform"
#endif
/* DMA related header and variables */
spinlock_t aes_lock;
#define CRTCL_SECT_INIT spin_lock_init(&aes_lock)
#define CRTCL_SECT_START spin_lock_irqsave(&aes_lock, flag)
#define CRTCL_SECT_END spin_unlock_irqrestore(&aes_lock, flag)
/* Definition of constants */
#define AES_START IFX_AES_CON
#define AES_MIN_KEY_SIZE 16
#define AES_MAX_KEY_SIZE 32
#define AES_BLOCK_SIZE 16
#define CTR_RFC3686_NONCE_SIZE 4
#define CTR_RFC3686_IV_SIZE 8
#define CTR_RFC3686_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + CTR_RFC3686_NONCE_SIZE)
#ifdef CRYPTO_DEBUG
extern char debug_level;
#define DPRINTF(level, format, args...) if (level < debug_level) printk(KERN_INFO "[%s %s %d]: " format, __FILE__, __func__, __LINE__, ##args);
#else
#define DPRINTF(level, format, args...)
#endif /* CRYPTO_DEBUG */
/* Function decleration */
int aes_chip_init(void);
u32 endian_swap(u32 input);
u32 input_swap(u32 input);
u32* memory_alignment(const u8 *arg, u32 *buff_alloc, int in_out, int nbytes);
void aes_dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes);
void des_dma_memory_copy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes);
int aes_memory_allocate(int value);
int des_memory_allocate(int value);
void memory_release(u32 *addr);
extern void ifx_deu_aes (void *ctx_arg, uint8_t *out_arg, const uint8_t *in_arg,
uint8_t *iv_arg, size_t nbytes, int encdec, int mode);
/* End of function decleration */
struct aes_ctx {
int key_length;
u32 buf[AES_MAX_KEY_SIZE];
u8 nonce[CTR_RFC3686_NONCE_SIZE];
};
extern int disable_deudma;
extern int disable_multiblock;
/*! \fn int aes_set_key (struct crypto_tfm *tfm, const uint8_t *in_key, unsigned int key_len)
* \ingroup IFX_AES_FUNCTIONS
* \brief sets the AES keys
* \param tfm linux crypto algo transform
* \param in_key input key
* \param key_len key lengths of 16, 24 and 32 bytes supported
* \return -EINVAL - bad key length, 0 - SUCCESS
*/
int aes_set_key (struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len)
{
struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
unsigned long *flags = (unsigned long *) &tfm->crt_flags;
//printk("set_key in %s\n", __FILE__);
//aes_chip_init();
if (key_len != 16 && key_len != 24 && key_len != 32) {
*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
return -EINVAL;
}
ctx->key_length = key_len;
DPRINTF(0, "ctx @%p, key_len %d, ctx->key_length %d\n", ctx, key_len, ctx->key_length);
memcpy ((u8 *) (ctx->buf), in_key, key_len);
return 0;
}
/*! \fn void ifx_deu_aes (void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, size_t nbytes, int encdec, int mode)
* \ingroup IFX_AES_FUNCTIONS
* \brief main interface to AES hardware
* \param ctx_arg crypto algo context
* \param out_arg output bytestream
* \param in_arg input bytestream
* \param iv_arg initialization vector
* \param nbytes length of bytestream
* \param encdec 1 for encrypt; 0 for decrypt
* \param mode operation mode such as ebc, cbc, ctr
*
*/
void ifx_deu_aes (void *ctx_arg, u8 *out_arg, const u8 *in_arg,
u8 *iv_arg, size_t nbytes, int encdec, int mode)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
volatile struct aes_t *aes = (volatile struct aes_t *) AES_START;
struct aes_ctx *ctx = (struct aes_ctx *)ctx_arg;
u32 *in_key = ctx->buf;
unsigned long flag;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
int key_len = ctx->key_length;
int i = 0;
int byte_cnt = nbytes;
CRTCL_SECT_START;
/* 128, 192 or 256 bit key length */
aes->controlr.K = key_len / 8 - 2;
if (key_len == 128 / 8) {
aes->K3R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 0));
aes->K2R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 1));
aes->K1R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 2));
aes->K0R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 3));
}
else if (key_len == 192 / 8) {
aes->K5R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 0));
aes->K4R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 1));
aes->K3R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 2));
aes->K2R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 3));
aes->K1R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 4));
aes->K0R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 5));
}
else if (key_len == 256 / 8) {
aes->K7R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 0));
aes->K6R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 1));
aes->K5R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 2));
aes->K4R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 3));
aes->K3R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 4));
aes->K2R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 5));
aes->K1R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 6));
aes->K0R = DEU_ENDIAN_SWAP(*((u32 *) in_key + 7));
}
else {
printk (KERN_ERR "[%s %s %d]: Invalid key_len : %d\n", __FILE__, __func__, __LINE__, key_len);
CRTCL_SECT_END;
return;// -EINVAL;
}
/* let HW pre-process DEcryption key in any case (even if
ENcryption is used). Key Valid (KV) bit is then only
checked in decryption routine! */
aes->controlr.PNK = 1;
aes->controlr.E_D = !encdec; //encryption
aes->controlr.O = mode; //0 ECB 1 CBC 2 OFB 3 CFB 4 CTR
//aes->controlr.F = 128; //default; only for CFB and OFB modes; change only for customer-specific apps
if (mode > 0) {
aes->IV3R = DEU_ENDIAN_SWAP(*(u32 *) iv_arg);
aes->IV2R = DEU_ENDIAN_SWAP(*((u32 *) iv_arg + 1));
aes->IV1R = DEU_ENDIAN_SWAP(*((u32 *) iv_arg + 2));
aes->IV0R = DEU_ENDIAN_SWAP(*((u32 *) iv_arg + 3));
};
i = 0;
while (byte_cnt >= 16) {
aes->ID3R = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + (i * 4) + 0));
aes->ID2R = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + (i * 4) + 1));
aes->ID1R = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + (i * 4) + 2));
aes->ID0R = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + (i * 4) + 3)); /* start crypto */
while (aes->controlr.BUS) {
// this will not take long
}
*((volatile u32 *) out_arg + (i * 4) + 0) = aes->OD3R;
*((volatile u32 *) out_arg + (i * 4) + 1) = aes->OD2R;
*((volatile u32 *) out_arg + (i * 4) + 2) = aes->OD1R;
*((volatile u32 *) out_arg + (i * 4) + 3) = aes->OD0R;
i++;
byte_cnt -= 16;
}
/* To handle all non-aligned bytes (not aligned to 16B size) */
if (byte_cnt) {
aes->ID3R = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + (i * 4) + 0));
aes->ID2R = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + (i * 4) + 1));
aes->ID1R = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + (i * 4) + 2));
aes->ID0R = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + (i * 4) + 3)); /* start crypto */
while (aes->controlr.BUS) {
}
*((volatile u32 *) out_arg + (i * 4) + 0) = aes->OD3R;
*((volatile u32 *) out_arg + (i * 4) + 1) = aes->OD2R;
*((volatile u32 *) out_arg + (i * 4) + 2) = aes->OD1R;
*((volatile u32 *) out_arg + (i * 4) + 3) = aes->OD0R;
/* to ensure that the extended pages are clean */
memset (out_arg + (i * 16) + (nbytes % AES_BLOCK_SIZE), 0,
(AES_BLOCK_SIZE - (nbytes % AES_BLOCK_SIZE)));
}
//tc.chen : copy iv_arg back
if (mode > 0) {
*((u32 *) iv_arg) = DEU_ENDIAN_SWAP(aes->IV3R);
*((u32 *) iv_arg + 1) = DEU_ENDIAN_SWAP(aes->IV2R);
*((u32 *) iv_arg + 2) = DEU_ENDIAN_SWAP(aes->IV1R);
*((u32 *) iv_arg + 3) = DEU_ENDIAN_SWAP(aes->IV0R);
}
CRTCL_SECT_END;
}
/*!
* \fn int ctr_rfc3686_aes_set_key (struct crypto_tfm *tfm, const uint8_t *in_key, unsigned int key_len)
* \ingroup IFX_AES_FUNCTIONS
* \brief sets RFC3686 key
* \param tfm linux crypto algo transform
* \param in_key input key
* \param key_len key lengths of 20, 28 and 36 bytes supported; last 4 bytes is nonce
* \return 0 - SUCCESS
* -EINVAL - bad key length
*/
int ctr_rfc3686_aes_set_key (struct crypto_tfm *tfm, const uint8_t *in_key, unsigned int key_len)
{
struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
unsigned long *flags = (unsigned long *)&tfm->crt_flags;
//printk("ctr_rfc3686_aes_set_key in %s\n", __FILE__);
memcpy(ctx->nonce, in_key + (key_len - CTR_RFC3686_NONCE_SIZE),
CTR_RFC3686_NONCE_SIZE);
key_len -= CTR_RFC3686_NONCE_SIZE; // remove 4 bytes of nonce
if (key_len != 16 && key_len != 24 && key_len != 32) {
*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
return -EINVAL;
}
ctx->key_length = key_len;
memcpy ((u8 *) (ctx->buf), in_key, key_len);
return 0;
}
/*! \fn void ifx_deu_aes (void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode)
* \ingroup IFX_AES_FUNCTIONS
* \brief main interface with deu hardware in DMA mode
* \param ctx_arg crypto algo context
* \param out_arg output bytestream
* \param in_arg input bytestream
* \param iv_arg initialization vector
* \param nbytes length of bytestream
* \param encdec 1 for encrypt; 0 for decrypt
* \param mode operation mode such as ebc, cbc, ctr
*/
//definitions from linux/include/crypto.h:
//#define CRYPTO_TFM_MODE_ECB 0x00000001
//#define CRYPTO_TFM_MODE_CBC 0x00000002
//#define CRYPTO_TFM_MODE_CFB 0x00000004
//#define CRYPTO_TFM_MODE_CTR 0x00000008
//#define CRYPTO_TFM_MODE_OFB 0x00000010 // not even defined
//but hardware definition: 0 ECB 1 CBC 2 OFB 3 CFB 4 CTR
/*! \fn void ifx_deu_aes_ecb (void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
* \ingroup IFX_AES_FUNCTIONS
* \brief sets AES hardware to ECB mode
* \param ctx crypto algo context
* \param dst output bytestream
* \param src input bytestream
* \param iv initialization vector
* \param nbytes length of bytestream
* \param encdec 1 for encrypt; 0 for decrypt
* \param inplace not used
*/
void ifx_deu_aes_ecb (void *ctx, uint8_t *dst, const uint8_t *src,
uint8_t *iv, size_t nbytes, int encdec, int inplace)
{
ifx_deu_aes (ctx, dst, src, NULL, nbytes, encdec, 0);
}
/*! \fn void ifx_deu_aes_cbc (void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
* \ingroup IFX_AES_FUNCTIONS
* \brief sets AES hardware to CBC mode
* \param ctx crypto algo context
* \param dst output bytestream
* \param src input bytestream
* \param iv initialization vector
* \param nbytes length of bytestream
* \param encdec 1 for encrypt; 0 for decrypt
* \param inplace not used
*/
void ifx_deu_aes_cbc (void *ctx, uint8_t *dst, const uint8_t *src,
uint8_t *iv, size_t nbytes, int encdec, int inplace)
{
ifx_deu_aes (ctx, dst, src, iv, nbytes, encdec, 1);
}
/*! \fn void ifx_deu_aes_ofb (void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
* \ingroup IFX_AES_FUNCTIONS
* \brief sets AES hardware to OFB mode
* \param ctx crypto algo context
* \param dst output bytestream
* \param src input bytestream
* \param iv initialization vector
* \param nbytes length of bytestream
* \param encdec 1 for encrypt; 0 for decrypt
* \param inplace not used
*/
void ifx_deu_aes_ofb (void *ctx, uint8_t *dst, const uint8_t *src,
uint8_t *iv, size_t nbytes, int encdec, int inplace)
{
ifx_deu_aes (ctx, dst, src, iv, nbytes, encdec, 2);
}
/*! \fn void ifx_deu_aes_cfb (void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
* \ingroup IFX_AES_FUNCTIONS
* \brief sets AES hardware to CFB mode
* \param ctx crypto algo context
* \param dst output bytestream
* \param src input bytestream
* \param iv initialization vector
* \param nbytes length of bytestream
* \param encdec 1 for encrypt; 0 for decrypt
* \param inplace not used
*/
void ifx_deu_aes_cfb (void *ctx, uint8_t *dst, const uint8_t *src,
uint8_t *iv, size_t nbytes, int encdec, int inplace)
{
ifx_deu_aes (ctx, dst, src, iv, nbytes, encdec, 3);
}
/*! \fn void ifx_deu_aes_ctr (void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace)
* \ingroup IFX_AES_FUNCTIONS
* \brief sets AES hardware to CTR mode
* \param ctx crypto algo context
* \param dst output bytestream
* \param src input bytestream
* \param iv initialization vector
* \param nbytes length of bytestream
* \param encdec 1 for encrypt; 0 for decrypt
* \param inplace not used
*/
void ifx_deu_aes_ctr (void *ctx, uint8_t *dst, const uint8_t *src,
uint8_t *iv, size_t nbytes, int encdec, int inplace)
{
ifx_deu_aes (ctx, dst, src, iv, nbytes, encdec, 4);
}
/*! \fn void aes_encrypt (struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in)
* \ingroup IFX_AES_FUNCTIONS
* \brief encrypt AES_BLOCK_SIZE of data
* \param tfm linux crypto algo transform
* \param out output bytestream
* \param in input bytestream
*/
void aes_encrypt (struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in)
{
struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
ifx_deu_aes (ctx, out, in, NULL, AES_BLOCK_SIZE,
CRYPTO_DIR_ENCRYPT, 0);
}
/*! \fn void aes_decrypt (struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in)
* \ingroup IFX_AES_FUNCTIONS
* \brief decrypt AES_BLOCK_SIZE of data
* \param tfm linux crypto algo transform
* \param out output bytestream
* \param in input bytestream
*/
void aes_decrypt (struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in)
{
struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
ifx_deu_aes (ctx, out, in, NULL, AES_BLOCK_SIZE,
CRYPTO_DIR_DECRYPT, 0);
}
/*
* \brief AES function mappings
*/
struct crypto_alg ifxdeu_aes_alg = {
.cra_name = "aes",
.cra_driver_name = "ifxdeu-aes",
.cra_priority = 300,
.cra_flags = CRYPTO_ALG_TYPE_CIPHER,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct aes_ctx),
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(ifxdeu_aes_alg.cra_list),
.cra_u = {
.cipher = {
.cia_min_keysize = AES_MIN_KEY_SIZE,
.cia_max_keysize = AES_MAX_KEY_SIZE,
.cia_setkey = aes_set_key,
.cia_encrypt = aes_encrypt,
.cia_decrypt = aes_decrypt,
}
}
};
/*! \fn int ecb_aes_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
* \ingroup IFX_AES_FUNCTIONS
* \brief ECB AES encrypt using linux crypto blkcipher
* \param desc blkcipher descriptor
* \param dst output scatterlist
* \param src input scatterlist
* \param nbytes data size in bytes
* \return err
*/
int ecb_aes_encrypt(struct blkcipher_desc *desc,
struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes)
{
struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
struct blkcipher_walk walk;
int err;
unsigned int enc_bytes;
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
while ((nbytes = enc_bytes = walk.nbytes)) {
enc_bytes -= (nbytes % AES_BLOCK_SIZE);
ifx_deu_aes_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr,
NULL, enc_bytes, CRYPTO_DIR_ENCRYPT, 0);
nbytes &= AES_BLOCK_SIZE - 1;
err = blkcipher_walk_done(desc, &walk, nbytes);
}
return err;
}
/*! \fn int ecb_aes_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
* \ingroup IFX_AES_FUNCTIONS
* \brief ECB AES decrypt using linux crypto blkcipher
* \param desc blkcipher descriptor
* \param dst output scatterlist
* \param src input scatterlist
* \param nbytes data size in bytes
* \return err
*/
int ecb_aes_decrypt(struct blkcipher_desc *desc,
struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes)
{
struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
struct blkcipher_walk walk;
int err;
unsigned int dec_bytes;
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
while ((nbytes = dec_bytes = walk.nbytes)) {
dec_bytes -= (nbytes % AES_BLOCK_SIZE);
ifx_deu_aes_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr,
NULL, dec_bytes, CRYPTO_DIR_DECRYPT, 0);
nbytes &= AES_BLOCK_SIZE - 1;
err = blkcipher_walk_done(desc, &walk, nbytes);
}
return err;
}
/*
* \brief AES function mappings
*/
struct crypto_alg ifxdeu_ecb_aes_alg = {
.cra_name = "ecb(aes)",
.cra_driver_name = "ifxdeu-ecb(aes)",
.cra_priority = 400,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct aes_ctx),
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(ifxdeu_ecb_aes_alg.cra_list),
.cra_u = {
.blkcipher = {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.setkey = aes_set_key,
.encrypt = ecb_aes_encrypt,
.decrypt = ecb_aes_decrypt,
}
}
};
/*! \fn int cbc_aes_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
* \ingroup IFX_AES_FUNCTIONS
* \brief CBC AES encrypt using linux crypto blkcipher
* \param desc blkcipher descriptor
* \param dst output scatterlist
* \param src input scatterlist
* \param nbytes data size in bytes
* \return err
*/
int cbc_aes_encrypt(struct blkcipher_desc *desc,
struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes)
{
struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
struct blkcipher_walk walk;
int err;
unsigned int enc_bytes;
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
while ((nbytes = enc_bytes = walk.nbytes)) {
u8 *iv = walk.iv;
enc_bytes -= (nbytes % AES_BLOCK_SIZE);
ifx_deu_aes_cbc(ctx, walk.dst.virt.addr, walk.src.virt.addr,
iv, enc_bytes, CRYPTO_DIR_ENCRYPT, 0);
nbytes &= AES_BLOCK_SIZE - 1;
err = blkcipher_walk_done(desc, &walk, nbytes);
}
return err;
}
/*! \fn int cbc_aes_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
* \ingroup IFX_AES_FUNCTIONS
* \brief CBC AES decrypt using linux crypto blkcipher
* \param desc blkcipher descriptor
* \param dst output scatterlist
* \param src input scatterlist
* \param nbytes data size in bytes
* \return err
*/
int cbc_aes_decrypt(struct blkcipher_desc *desc,
struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes)
{
struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
struct blkcipher_walk walk;
int err;
unsigned int dec_bytes;
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
while ((nbytes = dec_bytes = walk.nbytes)) {
u8 *iv = walk.iv;
dec_bytes -= (nbytes % AES_BLOCK_SIZE);
ifx_deu_aes_cbc(ctx, walk.dst.virt.addr, walk.src.virt.addr,
iv, dec_bytes, CRYPTO_DIR_DECRYPT, 0);
nbytes &= AES_BLOCK_SIZE - 1;
err = blkcipher_walk_done(desc, &walk, nbytes);
}
return err;
}
/*
* \brief AES function mappings
*/
struct crypto_alg ifxdeu_cbc_aes_alg = {
.cra_name = "cbc(aes)",
.cra_driver_name = "ifxdeu-cbc(aes)",
.cra_priority = 400,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct aes_ctx),
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(ifxdeu_cbc_aes_alg.cra_list),
.cra_u = {
.blkcipher = {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
.setkey = aes_set_key,
.encrypt = cbc_aes_encrypt,
.decrypt = cbc_aes_decrypt,
}
}
};
/*! \fn int ctr_basic_aes_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
* \ingroup IFX_AES_FUNCTIONS
* \brief Counter mode AES encrypt using linux crypto blkcipher
* \param desc blkcipher descriptor
* \param dst output scatterlist
* \param src input scatterlist
* \param nbytes data size in bytes
* \return err
*/
int ctr_basic_aes_encrypt(struct blkcipher_desc *desc,
struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes)
{
struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
struct blkcipher_walk walk;
int err;
unsigned int enc_bytes;
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
while ((nbytes = enc_bytes = walk.nbytes)) {
u8 *iv = walk.iv;
enc_bytes -= (nbytes % AES_BLOCK_SIZE);
ifx_deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr,
iv, enc_bytes, CRYPTO_DIR_ENCRYPT, 0);
nbytes &= AES_BLOCK_SIZE - 1;
err = blkcipher_walk_done(desc, &walk, nbytes);
}
return err;
}
/*! \fn int ctr_basic_aes_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
* \ingroup IFX_AES_FUNCTIONS
* \brief Counter mode AES decrypt using linux crypto blkcipher
* \param desc blkcipher descriptor
* \param dst output scatterlist
* \param src input scatterlist
* \param nbytes data size in bytes
* \return err
*/
int ctr_basic_aes_decrypt(struct blkcipher_desc *desc,
struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes)
{
struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
struct blkcipher_walk walk;
int err;
unsigned int dec_bytes;
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
while ((nbytes = dec_bytes = walk.nbytes)) {
u8 *iv = walk.iv;
dec_bytes -= (nbytes % AES_BLOCK_SIZE);
ifx_deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr,
iv, dec_bytes, CRYPTO_DIR_DECRYPT, 0);
nbytes &= AES_BLOCK_SIZE - 1;
err = blkcipher_walk_done(desc, &walk, nbytes);
}
return err;
}
/*
* \brief AES function mappings
*/
struct crypto_alg ifxdeu_ctr_basic_aes_alg = {
.cra_name = "ctr(aes)",
.cra_driver_name = "ifxdeu-ctr(aes)",
.cra_priority = 400,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct aes_ctx),
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(ifxdeu_ctr_basic_aes_alg.cra_list),
.cra_u = {
.blkcipher = {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
.setkey = aes_set_key,
.encrypt = ctr_basic_aes_encrypt,
.decrypt = ctr_basic_aes_decrypt,
}
}
};
/*! \fn int ctr_rfc3686_aes_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
* \ingroup IFX_AES_FUNCTIONS
* \brief Counter mode AES (rfc3686) encrypt using linux crypto blkcipher
* \param desc blkcipher descriptor
* \param dst output scatterlist
* \param src input scatterlist
* \param nbytes data size in bytes
* \return err
*/
int ctr_rfc3686_aes_encrypt(struct blkcipher_desc *desc,
struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes)
{
struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
struct blkcipher_walk walk;
int err, bsize = nbytes;
u8 rfc3686_iv[16];
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
/* set up counter block */
memcpy(rfc3686_iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE);
memcpy(rfc3686_iv + CTR_RFC3686_NONCE_SIZE, walk.iv, CTR_RFC3686_IV_SIZE);
/* initialize counter portion of counter block */
*(__be32 *)(rfc3686_iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) =
cpu_to_be32(1);
/* scatterlist source is the same size as request size, just process once */
if (nbytes == walk.nbytes) {
ifx_deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr,
rfc3686_iv, nbytes, CRYPTO_DIR_ENCRYPT, 0);
nbytes -= walk.nbytes;
err = blkcipher_walk_done(desc, &walk, nbytes);
return err;
}
while ((nbytes = walk.nbytes) && (walk.nbytes >= AES_BLOCK_SIZE)) {
ifx_deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr,
rfc3686_iv, nbytes, CRYPTO_DIR_ENCRYPT, 0);
nbytes -= walk.nbytes;
bsize -= walk.nbytes;
err = blkcipher_walk_done(desc, &walk, nbytes);
}
/* to handle remaining bytes < AES_BLOCK_SIZE */
if (walk.nbytes) {
ifx_deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr,
rfc3686_iv, walk.nbytes, CRYPTO_DIR_ENCRYPT, 0);
err = blkcipher_walk_done(desc, &walk, 0);
}
return err;
}
/*! \fn int ctr_rfc3686_aes_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes)
* \ingroup IFX_AES_FUNCTIONS
* \brief Counter mode AES (rfc3686) decrypt using linux crypto blkcipher
* \param desc blkcipher descriptor
* \param dst output scatterlist
* \param src input scatterlist
* \param nbytes data size in bytes
* \return err
*/
int ctr_rfc3686_aes_decrypt(struct blkcipher_desc *desc,
struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes)
{
struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
struct blkcipher_walk walk;
int err, bsize = nbytes;
u8 rfc3686_iv[16];
blkcipher_walk_init(&walk, dst, src, nbytes);
err = blkcipher_walk_virt(desc, &walk);
/* set up counter block */
memcpy(rfc3686_iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE);
memcpy(rfc3686_iv + CTR_RFC3686_NONCE_SIZE, walk.iv, CTR_RFC3686_IV_SIZE);
/* initialize counter portion of counter block */
*(__be32 *)(rfc3686_iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) =
cpu_to_be32(1);
/* scatterlist source is the same size as request size, just process once */
if (nbytes == walk.nbytes) {
ifx_deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr,
rfc3686_iv, nbytes, CRYPTO_DIR_ENCRYPT, 0);
nbytes -= walk.nbytes;
err = blkcipher_walk_done(desc, &walk, nbytes);
return err;
}
while ((nbytes = walk.nbytes) % (walk.nbytes >= AES_BLOCK_SIZE)) {
ifx_deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr,
rfc3686_iv, nbytes, CRYPTO_DIR_DECRYPT, 0);
nbytes -= walk.nbytes;
bsize -= walk.nbytes;
err = blkcipher_walk_done(desc, &walk, nbytes);
}
/* to handle remaining bytes < AES_BLOCK_SIZE */
if (walk.nbytes) {
ifx_deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr,
rfc3686_iv, walk.nbytes, CRYPTO_DIR_ENCRYPT, 0);
err = blkcipher_walk_done(desc, &walk, 0);
}
return err;
}
/*
* \brief AES function mappings
*/
struct crypto_alg ifxdeu_ctr_rfc3686_aes_alg = {
.cra_name = "rfc3686(ctr(aes))",
.cra_driver_name = "ifxdeu-ctr-rfc3686(aes)",
.cra_priority = 400,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct aes_ctx),
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(ifxdeu_ctr_rfc3686_aes_alg.cra_list),
.cra_u = {
.blkcipher = {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = CTR_RFC3686_MAX_KEY_SIZE,
.ivsize = CTR_RFC3686_IV_SIZE,
.setkey = ctr_rfc3686_aes_set_key,
.encrypt = ctr_rfc3686_aes_encrypt,
.decrypt = ctr_rfc3686_aes_decrypt,
}
}
};
/*! \fn int ifxdeu_init_aes (void)
* \ingroup IFX_AES_FUNCTIONS
* \brief function to initialize AES driver
* \return ret
*/
int ifxdeu_init_aes (void)
{
int ret = -ENOSYS;
if ((ret = crypto_register_alg(&ifxdeu_aes_alg)))
goto aes_err;
if ((ret = crypto_register_alg(&ifxdeu_ecb_aes_alg)))
goto ecb_aes_err;
if ((ret = crypto_register_alg(&ifxdeu_cbc_aes_alg)))
goto cbc_aes_err;
if ((ret = crypto_register_alg(&ifxdeu_ctr_basic_aes_alg)))
goto ctr_basic_aes_err;
if ((ret = crypto_register_alg(&ifxdeu_ctr_rfc3686_aes_alg)))
goto ctr_rfc3686_aes_err;
aes_chip_init ();
CRTCL_SECT_INIT;
printk (KERN_NOTICE "IFX DEU AES initialized%s%s.\n", disable_multiblock ? "" : " (multiblock)", disable_deudma ? "" : " (DMA)");
return ret;
ctr_rfc3686_aes_err:
crypto_unregister_alg(&ifxdeu_ctr_rfc3686_aes_alg);
printk (KERN_ERR "IFX ctr_rfc3686_aes initialization failed!\n");
return ret;
ctr_basic_aes_err:
crypto_unregister_alg(&ifxdeu_ctr_basic_aes_alg);
printk (KERN_ERR "IFX ctr_basic_aes initialization failed!\n");
return ret;
cbc_aes_err:
crypto_unregister_alg(&ifxdeu_cbc_aes_alg);
printk (KERN_ERR "IFX cbc_aes initialization failed!\n");
return ret;
ecb_aes_err:
crypto_unregister_alg(&ifxdeu_ecb_aes_alg);
printk (KERN_ERR "IFX aes initialization failed!\n");
return ret;
aes_err:
printk(KERN_ERR "IFX DEU AES initialization failed!\n");
return ret;
}
/*! \fn void ifxdeu_fini_aes (void)
* \ingroup IFX_AES_FUNCTIONS
* \brief unregister aes driver
*/
void ifxdeu_fini_aes (void)
{
crypto_unregister_alg (&ifxdeu_aes_alg);
crypto_unregister_alg (&ifxdeu_ecb_aes_alg);
crypto_unregister_alg (&ifxdeu_cbc_aes_alg);
crypto_unregister_alg (&ifxdeu_ctr_basic_aes_alg);
crypto_unregister_alg (&ifxdeu_ctr_rfc3686_aes_alg);
}