2007-07-18 23:39:56

by tirumalareddy marri

[permalink] [raw]
Subject: Looking for comments on a Linux driver for HW accelerated Kasumi+F8+F9 algorithms.

Hi ,
I have created Linux driver for HW accelerated
kasumi, F8 and F9 algorithms. Could you please look at
the driver and provide comments about the usage. This
driver is acts as a character driver. Encryption API's
can be accessed from kernel and user space. My concern
is accessing the driver from user space is secure or
not.

If possible can some one please send me rules to
follow when we write a Linux security driver.
--------------------------- patch for the driver
-----------

--- may03_denx/drivers/crypto/Kconfig 2007-05-03
08:39:15.000000000 -0700
+++ 0323_denx/drivers/crypto/Kconfig 2007-05-15
13:40:56.789633768 -0700
@@ -37,6 +37,13 @@
If unsure say M. The compiled module will be
called padlock-aes.ko

+config CRYPTO_KASUMI
+ bool "Support for Kasumi driver"
+ depends on 440EPX
+ default N
+ help
+ Used in encrypting and decrypting data.
+
config CRYPTO_DEV_PADLOCK_SHA
tristate "PadLock driver for SHA1 and SHA256
algorithms"
depends on CRYPTO_DEV_PADLOCK
--- may03_denx/drivers/crypto/Makefile 2007-05-03
08:39:15.000000000 -0700
+++ 0323_denx/drivers/crypto/Makefile 2007-04-25
13:39:52.000000000 -0700
@@ -2,3 +2,4 @@
obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
+obj-$(CONFIG_KASUMI_CRYPTO) +=kasumi.o
--- may03_denx/drivers/crypto/kasumi.h 1969-12-31
16:00:00.000000000 -0800
+++ 0323_denx/drivers/crypto/kasumi.h 2007-05-15
15:16:27.046502312 -0700
@@ -0,0 +1,122 @@
+/**********************************************************************
+ *
+ * kasumi.h
+ * Cryptographic Driver APIs.
+ *
+ * Support for Kasumi F8 and F9 hardware crypto
engine.
+ * author: [email protected]
+ *
+ *
+ * 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.
+ *
+ *
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit
or implied warranties
+ * in respect of its properties, including, but not
limited to, correctness
+ * and/or fitness for purpose.
+ *
---------------------------------------------------------------------------
+ */
+#define MULTIPLE_DATA_ENC 1
+
+#define KASUMI_TEST 0
+
+/* Dynamic major number */
+#define KASUMI_MAJOR 0
+
+/* IOCTL numbers */
+#define KASUMI_IOCTL_ENCRYPT 0x100
+#define KASUMI_IOCTL_DECRYPT 0x101
+#define KASUMI_IOCTL_F8_MODE 0x102
+#define KASUMI_IOCTL_F9_MODE 0x103
+
+#define SDR0_SRST1 0x201
+#define DCR_PLB4A0 0x81
+#define DCR_UIC0_SR 0xC0
+#define DCR_UIC0_ER 0xC2
+
+/* Need to disable READ pipeline to avoid hang on PLB
bus */
+#define DISABLE_RD_PIPE_LINE 0xf9ffffff
+#define KASUMI_RESET_MSK 0x00002000
+#define KASU0_BASE 0x0E0180000ULL
+
+#define KASU0_DATA_IN0 0x0
+#define KASU0_DATA_OUT0 0x0
+#define KASU0_DATA_IN1 0x4
+#define KASU0_DATA_OUT1 0x4
+#define KASU0_CTRL 0x8
+#define KASU0_STATUS 0x8
+#define KASU0_MODE 0xc
+#define KASU0_KEY0 0x10
+#define KASU0_KEY1 0x14
+#define KASU0_KEY2 0x18
+#define KASU0_KEY3 0x1c
+#define KASU0_COUNT 0x20
+#define KASU0_CONFIG 0x24
+#define KASU0_FRESH 0x28
+
+#define KASUMI_DEC_MODE 0x02000000
+#define KASUMI_ENC_MODE 0x03000000
+#define KASUMI_F8_ENC_MODE 0x05000000
+#define KASUMI_F8_DEC_MODE 0x04000000
+#define KASUMI_F9_ENC_MODE 0x09000000
+#define KASUMI_F9_DEC_MODE 0x08000000
+
+#define KASUMI_DATA_READY 0x01000000
+
+#define KASUMI_VAL_KEYS 0x04000000
+#define KASUMI_VAL_MODE 0x02000000
+#define KASUMI_VAL_DATA 0x08000000
+#define KASUMI_VAL_CFG 0x10000000
+#define KASUMI_VAL_COUNT 0x20000000
+#define KASUMI_VAL_FRESH 0x40000000
+
+#define kasumi_byte_swap(x) ((((uint)x & 0xff000000)
>> 24) | \
+ (((uint)x & 0x00ff0000) >> 8) | \
+ (((uint)x & 0x0000ff00) << 8) | \
+ (((uint)x & 0x000000ff) << 24))
+
+struct kasumi_desc {
+ uint mode;
+ uint count;
+ uint config;
+ uint fresh;
+ uint key0;
+ uint key1;
+ uint key2;
+ uint key3;
+ uint *data_in;
+ uint *data_out;
+};
+struct kasumi_regs{
+ uint *ctrl;
+ uint *status;
+ uint *mode;
+ uint *key0;
+ uint *key1;
+ uint *key2;
+ uint *key3;
+ uint *data_in0;
+ uint *data_in1;
+ uint *data_out0;
+ uint *data_out1;
+ uint *count;
+ uint *config;
+ uint *fresh;
+};
+
+struct kasumi_f8_f9_desc {
+ struct kasumi_desc kd;
+ uint len;
+ uint bearer;
+ uint direction;
+};
+int kasumi_f9_encrypt(struct kasumi_desc *test, uint
len, uint direction);
+int kasumi_f8_encrypt(struct kasumi_desc *test, uint
len, uint bearer,
+ uint direction);
+int kasumi_decrypt(struct kasumi_desc *test);
+int kasumi_encrypt(struct kasumi_desc *test);
--- may03_denx/drivers/crypto/kasumi.c 1969-12-31
16:00:00.000000000 -0800
+++ 0323_denx/drivers/crypto/kasumi.c 2007-05-15
15:16:27.045502464 -0700
@@ -0,0 +1,898 @@
+/*
+ * Cryptographic Driver APIs.
+ *
+ * Support for Kasumi F8 and F9 hardware crypto
engine.
+ * author: [email protected]
+ *
+ *
+ * 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.
+ *
+ *
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit
or implied warranties
+ * in respect of its properties, including, but not
limited to, correctness
+ * and/or fitness for purpose.
+ *
---------------------------------------------------------------------------
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#include <linux/fcntl.h>
+#include <linux/cdev.h>
+#include <linux/seq_file.h>
+#include <linux/fs.h> /* everything... */
+
+#include <asm/system.h>
+#include <asm/uaccess.h> /* copy_*_user */
+
+#include <asm/ibm44x.h>
+#include "kasumi.h"
+
+static int kasumi_major = KASUMI_MAJOR;
+static uint data_in[512], data_out[512];
+static uint *kasumi_base;
+static struct kasumi_regs kreg;
+
+#ifdef KASUMI_TEST
+/*
+** Function to test KASUMI encrypt and decrypt modes
+*/
+static int kasumi_test(void)
+{
+ struct kasumi_desc test_in, test_out;
+ uint data_in0[2], data_in1[2], data_out0[2],
data_out1[2];
+
+ test_in.key0 = 0x9F45D62B;
+ test_in.key1 = 0x00B3C582;
+ test_in.key2 = 0x10492C95;
+ test_in.key3 = 0x48FF8148;
+ data_in0[0] = 0xEA024714;
+ data_in0[1] = 0xAD5C4D84;
+ test_in.data_in = &data_in0[0];
+ test_in.data_out = &data_out0[0];
+
+ printk(KERN_INFO "Encryption test\n");
+ kasumi_encrypt(&test_in);
+
+ test_out.key0 = 0x9F45D62B;
+ test_out.key1 = 0x00B3C582;
+ test_out.key2 = 0x10492C95;
+ test_out.key3 = 0x48FF8148;
+ test_out.data_in = &data_in1[0];
+ test_out.data_out = &data_out1[0];
+ test_out.data_in[0] = data_out0[0];
+ test_out.data_in[1] = data_out0[1];
+
+ printk(KERN_INFO "Decryption test\n");
+ kasumi_decrypt(&test_out);
+ printk(KERN_INFO "data_out0[0]=0x%x\n",
data_out0[0]);
+ printk(KERN_INFO "data_out0[1]=0x%x\n",
data_out0[1]);
+ printk(KERN_INFO "data_out1[0]=0x%x\n",
data_out1[0]);
+ printk(KERN_INFO "data_out1[1]=0x%x\n",
data_out1[1]);
+
+ if (data_in0[0] == data_out1[0])
+ printk(KERN_INFO " Data 0 matched\n");
+ else
+ printk(KERN_INFO " Data 0 NOT matched\n");
+ if (data_in0[1] == data_out1[1])
+ printk(KERN_INFO " Data 1 matched\n");
+ else
+ printk(KERN_INFO " Data 1 NOT matched\n");
+ return 0;
+}
+
+/*
+** Function to test F* mode of encryption
+*/
+static void kasumi_test_f8_1(void)
+{
+ int len = 0x31E, bearer = 0xc, direction = 1;
+ struct kasumi_desc test_in;
+ struct kasumi_desc test_out;
+ int i = 0;
+ uint data_in[32] = {
+ 0x7EC61272, 0x743BF161, 0x4726446A, 0x6C38CED1,
+ 0x66F6CA76, 0xEB543004, 0x4286346C, 0xEF130F92,
+ 0x922B0345, 0x0D3A9975, 0xE5BD2EA0, 0xEB55AD8E,
+ 0x1B199E3E, 0xC4316020, 0xE9A1B285, 0xE7627953,
+ 0x59B7BDFD, 0x39BEF4B2, 0x484583D5, 0xAFE082AE,
+ 0xE638BF5F, 0xD5A60619, 0x3901A08F, 0x4AB41AAB,
0x9B134880
+ };
+ uint data_cmp[32] = {
+ 0xD1E2DE70, 0xEEF86C69, 0x64FB542B, 0xC2D460AA,
+ 0xBFAA10A4, 0xA093262B, 0x7D199E70, 0x6FC2D489,
+ 0x15532969, 0x10F3A973, 0x012682E4, 0x1C4E2B02,
+ 0xBE2017B7, 0x253BBF93, 0x09DE5819, 0xCB42E819,
+ 0x56F4C99B, 0xC9765CAF, 0x53B1D0BB, 0x8279826A,
+ 0xDBBC5522, 0xE915C120, 0xA618A5A7, 0xF5E89708,
0x9339650F
+ };
+ uint data_out0[32];
+ uint data_out1[32];
+
+ test_in.key0 = 0x2BD6459F;
+ test_in.key1 = 0x82C5B300;
+ test_in.key2 = 0x952C4910;
+ test_in.key3 = 0x4881FF48;
+
+ test_in.count = 0x72A4F20F;
+
+ printk(KERN_INFO "in CFG=0x%x\n", test_in.config);
+ test_in.data_in = &data_in[0];
+ test_in.data_out = &data_out0[0];
+ kasumi_f8_encrypt(&test_in, len, bearer, direction);
+
+ i = 0;
+ for (i = 0; i < 32; i++) {
+ if (data_out0[i] != data_cmp[i])
+ printk(KERN_INFO
+ "data MISS match data recieved=0x%x
expected =0x%x\n\nn",
+ data_out0[i], data_cmp[i]);
+ else
+ printk(KERN_INFO "data MATCHED\n");
+
+ }
+}
+
+/*
+** Function to test F9 mode of encryption
+*/
+static void kasumi_test_f9(void)
+{
+ struct kasumi_desc test_in;
+ int i = 0;
+ uint direction = 0, len = 189;
+ uint data_in[6] = {
+ 0x6B227737,
+ 0x296F393C,
+ 0x8079353E,
+ 0xDC87E2E8,
+ 0x05D2EC49,
+ 0xA4F2D8E0
+ };
+ uint data_out[2];
+
+ test_in.key0 = 0x2BD6459F;
+ test_in.key1 = 0x82C5B300;
+ test_in.key2 = 0x952C4910;
+ test_in.key3 = 0x4881FF48;
+ test_in.fresh = 0x05D2EC49;
+ test_in.count = 0x38A6F056;
+
+ for (i = 0; i < 6; i++)
+ data_in[i] = kasumi_byte_swap(data_in[i]);
+ test_in.data_in = &data_in[0];
+ test_in.data_out = &data_out[0];
+ kasumi_f9_encrypt(&test_in, len, direction);
+ if (data_out[0] == 0xf63bd72c)
+ printk(KERN_INFO
+ " F9 test passed Expected data = 0x%x data
recieved=0x%x\n",
+ 0xf63bd72c, data_out[0]);
+ else
+ printk(KERN_INFO
+ " \n F9 test Failed Expected data = 0x%x
data recieved=0x%x\n",
+ 0xf63bd72c, data_out[0]);
+
+}
+#endif
+
+/*
+**FUNCTION:kasumi_encrypt_decrypt()
+** args: kd is kasumi descriptor which holds all the
requred data to do kasumi
+** mode encryption and decryption
+** Description: This function follows the kasumi
algorithm to encrypt and decrypt.
+** 1. Check for interrupt bit KDA(Kasumi Data
Availability)
+** 2. check for data availability bit in CTRL
register and write 1 to clear it
+** 3. Set keys
+** 4. set mode
+** 5. set inputdata
+** 6. validate keys , mode and data
+** 7. wait for the data availability and then read
the data.
+** This function can only do 64bit data encryption
at given time
+** Please check the test() in the comment section.
+*/
+static int kasumi_encrypt_decrypt(struct kasumi_desc
*kd)
+{
+ uint time_out = 100;
+
+ /*
+ * CTRL_STATUS[0] to reset the DATA out mechanism
+ */
+ printk(KERN_WARNING "kreg.ctrl 0x%x\n", kreg.ctrl);
+ out_be32(kreg.ctrl, in_be32(kreg.ctrl) |
KASUMI_DATA_READY);
+ /*
+ * Check for interrupt bit for data availability bit
set .
+ * if set clear it
+ */
+ if (mfdcr(DCR_UIC0_SR) & 0x08000000) {
+ mtdcr(DCR_UIC0_SR, (mfdcr(DCR_UIC0_SR) &
~0x08000000));
+ }
+
+ /*
+ * Check if KASUMI is ready for data input
+ */
+ if (!mfdcr(DCR_UIC0_SR) & 0x10000000)
+ printk(KERN_INFO "KASUMI is ready for data\n");
+
+ /*
+ * need keys
+ */
+ out_be32(kreg.key0, kd->key0);
+ out_be32(kreg.key1, kd->key1);
+ out_be32(kreg.key2, kd->key2);
+ out_be32(kreg.key3, kd->key3);
+ /*
+ * Check for correct mode
+ */
+ if ((kd->mode != KASUMI_ENC_MODE) && (kd->mode !=
KASUMI_DEC_MODE)) {
+ printk(KERN_INFO "KASUMI ERROR: invalid mode\n\n");
+ return -1;
+ }
+
+ /*
+ * set mode
+ */
+ out_be32(kreg.mode, kd->mode);
+ /*
+ * write data
+ */
+ if ((kd->data_in != NULL) && (kd->data_in)) {
+ out_be32(kreg.data_in0, kd->data_in[0]);
+ out_be32(kreg.data_in1, kd->data_in[1]);
+ } else {
+ printk(KERN_INFO "No data passed\n");
+ return -1;
+ }
+
+ /*
+ * validate data CTRL_STAT[4]
+ * Validate mode CTRL_STA[1] = 1
+ * vlaidatkeys keys CTRL_STAT[2] = 1
+ */
+ out_be32(kreg.ctrl, in_be32(kreg.ctrl) |
(KASUMI_VAL_DATA |
+ KASUMI_VAL_KEYS |
+ KASUMI_VAL_MODE));
+ /*
+ * Just in case DATA validation not finished
+ */
+ time_out = 100;
+ while (in_be32(kreg.ctrl) & KASUMI_VAL_DATA) {
+ time_out--;
+ mdelay(1);
+ if (time_out <= 0) {
+ printk(KERN_INFO
+ "ERROR: at line %d Timed out
KASU0_CTRL=0x%x\n",
+ __LINE__, in_be32(kreg.ctrl));
+ break;
+ }
+ }
+
+ /*
+ * Check if data available bit is set
+ */
+ if (!mfdcr(DCR_UIC0_SR) & 0x08000000)
+ printk(KERN_WARNING
+ "KASUMI data NOT available and NO KDA
interrupt occured\n");
+
+ /*
+ * Is data avaialbel
+ */
+ time_out = 100;
+ while (!(in_be32(kreg.status) & KASUMI_DATA_READY))
{
+ time_out--;
+ mdelay(1);
+ if (time_out <= 0) {
+ printk(KERN_INFO "line %d Timed out
KASU0_CTRL=0x%x\n",
+ __LINE__, in_be32(kreg.ctrl));
+ break;
+ }
+ }
+
+ if (!(in_be32(kreg.status) & KASUMI_DATA_READY))
+ printk(KERN_WARNING "Data is not ready\n");
+
+ kd->data_out[0] = in_be32(kreg.data_out0);
+ kd->data_out[1] = in_be32(kreg.data_out1);
+ return 0;
+}
+
+/*
+** Kasumi encryption function calls the
kasumi_encrypt_decrypt()
+**
+*/
+int kasumi_encrypt(struct kasumi_desc *test)
+{
+ test->mode = KASUMI_ENC_MODE;
+ if (kasumi_encrypt_decrypt(test) != 0) {
+ printk(KERN_INFO "kasumi_encrypt_decrypt returned
error");
+ return -1;
+ } else
+ return 0;
+
+}
+
+/*
+** Kasumi encryption function calls the
kasumi_encrypt_decrypt()
+**
+*/
+int kasumi_decrypt(struct kasumi_desc *test)
+{
+ test->mode = KASUMI_DEC_MODE;
+ if (kasumi_encrypt_decrypt(test) != 0) {
+ printk(KERN_INFO "kasumi_encrypt_decrypt returned
error");
+ return -1;
+ } else
+ return 0;
+
+}
+
+/*
+**
+**FUNCTION:kasumi_encrypt_decrypt()
+**args: kd is kasumi descriptor which holds all the
requred data to do kasumi mode encryption and
decryption
+**Description: This function follows the kasumi
algorithm to encrypt and decrypt.
+** 1. Check for interrupt bit KDA(Kasumi Data
Availability)
+** 2. check for data availability bit in CTRL
register and write 1 to clear it
+** 3. Set keys
+** 4. set mode
+** 5. set config
+** 6. set count
+** 7. set inputdata
+** 8. validate keys , mode , config , count and data
+** 9. wait for the data availability and then read
the data.
+** This function can encrypt block data
+** Please check the test_f8_1() in the comment
section.
+*/
+static int kasumi_f8_encrypt_decrypt(struct
kasumi_desc *kd)
+{
+ int time_out = 10000;
+ int len = 0;
+ int i = 0;
+
+ len = ((kd->config & 0xff) << 8) | ((kd->config &
0xff00) >> 8);
+ /*Reset data out mechanism */
+ /*CTRL_STATUS[0] to reset the DATA out mechanism */
+ out_be32(kreg.ctrl, in_be32(kreg.ctrl) |
KASUMI_DATA_READY);
+
+ if (mfdcr(DCR_UIC0_SR) & 0x08000000)
+ mtdcr(DCR_UIC0_SR, (mfdcr(DCR_UIC0_SR) &
~0x08000000));
+
+ if (!mfdcr(DCR_UIC0_SR) & 0x10000000)
+ printk(KERN_INFO "KASUMI is NOT ready for data\n");
+
+ /*need keys */
+
+ out_be32(kreg.key0, kd->key0);
+ out_be32(kreg.key1, kd->key1);
+ out_be32(kreg.key2, kd->key2);
+ out_be32(kreg.key3, kd->key3);
+ /*write config */
+ out_be32(kreg.config, kd->config);
+ /* Write count */
+ out_be32(kreg.count, kd->count);
+ /*set mode */
+ if (kd->mode != KASUMI_F8_ENC_MODE) {
+ printk(KERN_INFO "KASUMI Invalid mode\n");
+ return -1;
+ }
+
+ out_be32(kreg.mode, kd->mode);
+
+ /*
+ * write data
+ * validate data CTRL_STAT[4]
+ * Validate mode CTRL_STA[1] = 1
+ * vlaidatkeys keys CTRL_STAT[2] = 1
+ * vlaidatkeys count and config
+ */
+ out_be32(kreg.ctrl, in_be32(kreg.ctrl) |
(KASUMI_VAL_CFG |
+ KASUMI_VAL_COUNT |
+ KASUMI_VAL_KEYS |
+ KASUMI_VAL_MODE));
+ time_out = 100;
+ /*
+ ** Just in case DATA validation is not finished
+ */
+ while (in_be32(kreg.ctrl) & (KASUMI_VAL_CFG |
KASUMI_VAL_COUNT |
+ KASUMI_VAL_KEYS | KASUMI_VAL_MODE)) {
+ time_out--;
+ mdelay(1);
+ if (time_out <= 0) {
+ printk(KERN_INFO
+ " KASUMI:line %d Timed out
KASU0_CTRL=0x%x\n",
+ __LINE__, in_be32(kreg.ctrl));
+ break;
+ }
+
+ }
+
+ if (in_be32(kreg.ctrl)
+ & (KASUMI_VAL_CFG | KASUMI_VAL_COUNT |
+ KASUMI_VAL_KEYS | KASUMI_VAL_MODE))
+ printk(KERN_WARNING
+ " CFG COUNT KEYS MODE validation NOT
complete\n");
+ /*
+ ** Here we encode 64bits a time till whole block is
encrypted
+ */
+ while (len > 0) {
+ if ((&kd->data_in[i] != NULL) && (&kd->data_in[i +
1] != NULL)) {
+ out_be32(kreg.data_in0, kd->data_in[i]);
+ out_be32(kreg.data_in1, kd->data_in[i + 1]);
+ } else {
+ printk(KERN_INFO "No data passed\n");
+ break;
+ }
+
+ out_be32(kreg.ctrl, in_be32(kreg.ctrl) |
KASUMI_VAL_DATA);
+ time_out = 100;
+ while (in_be32(kreg.ctrl) & (KASUMI_VAL_DATA)) {
+ time_out--;
+ if (time_out <= 0) {
+ printk(KERN_INFO
+ "KASUMI: line %d Timed out
KASU0_CTRL=0x%x\n",
+ __LINE__, in_be32(kreg.ctrl));
+ break;
+ }
+ }
+
+ if (in_be32(kreg.ctrl) & (KASUMI_VAL_DATA))
+ printk(KERN_WARNING "Data validation NOT
complete\n");
+
+ time_out = 100;
+ while (!(in_be32(kreg.status) & KASUMI_DATA_READY))
{
+ mdelay(1);
+ time_out--;
+ if (time_out <= 0) {
+ printk(KERN_INFO
+ "line %d Timed out KASU0_CTRL=0x%x\n",
+ __LINE__, in_be32(kreg.ctrl));
+ break;
+ }
+
+ }
+
+ if (!(in_be32(kreg.status) & KASUMI_DATA_READY)) {
+ printk(KERN_WARNING "Data is not ready\n");
+ break;
+ }
+
+ kd->data_out[i] =
kasumi_byte_swap(in_be32(kreg.data_out0));
+ kd->data_out[i + 1] =
kasumi_byte_swap(in_be32(kreg.data_out1));
+ /*
+ ** CTRL_STATUS[0] to reset the DATA out mechanism
+ */
+ out_be32(kreg.ctrl, KASUMI_DATA_READY);
+ if (!mfdcr(DCR_UIC0_SR) & 0x10000000)
+ printk(KERN_WARNING "KASUMI is NOT ready for
data\n");
+
+ i += 2;
+ len = len - 64;
+ }
+
+ return 0;
+}
+
+/*
+** arg1: hte filled kasumi_desc structure pointer
+** arg2: len
+** arg3: bearer
+** arg4: direction
+*/
+int kasumi_f8_encrypt(struct kasumi_desc *test, uint
len, uint bearer,
+ uint direction)
+{
+ int i = 0;
+
+ test->config = (len << 16 | bearer << 1 |
direction);
+ test->mode = KASUMI_F8_ENC_MODE;
+ test->key0 = kasumi_byte_swap(test->key0);
+ test->key1 = kasumi_byte_swap(test->key1);
+ test->key2 = kasumi_byte_swap(test->key2);
+ test->key3 = kasumi_byte_swap(test->key3);
+ test->count = kasumi_byte_swap(test->count);
+ test->config = kasumi_byte_swap(test->config);
+ len = len / (32);
+
+ for (i = 0; i <= len; i++)
+ test->data_in[i] =
kasumi_byte_swap(test->data_in[i]);
+
+ if (kasumi_f8_encrypt_decrypt(test) != 0) {
+ printk(KERN_INFO
+ "kasumi_f8_encrypt_decrypt() returned
error\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+**
+**FUNCTION:kasumi_encrypt_decrypt()
+**args: kd is kasumi descriptor which holds all the
requred data to do kasumi mode encryption and
decryption
+**Description: This function follows the kasumi
algorithm to encrypt and decrypt.
+** 1. Check for interrupt bit KDA(Kasumi Data
Availability)
+** 2. check for data availability bit in CTRL
register and write 1 to clear it
+** 3. Set keys
+** 4. set mode
+** 5. set config
+** 6. set count
+** 7. set inputdata
+** 8. validate keys , mode , config , count and data
+** 9. wait for the data availability and then read
the data.
+** This function can encrypt block data
+** Please check the test_f9_1() in the comment
section.
+*/
+int kasumi_f9(struct kasumi_desc *kd)
+{
+ int time_out = 10000;
+ int len = 0;
+ int i = 0;
+
+ /*
+ ** Get the lenght of the block we are going to
encode
+ */
+ len = ((kd->config & 0xff) << 8) | ((kd->config &
0xff00) >> 8);
+
+ /*
+ ** CTRL_STATUS[0] to reset the DATA out mechanism
+ */
+ out_be32(kreg.ctrl, in_be32(kreg.ctrl) |
KASUMI_DATA_READY);
+ if (mfdcr(DCR_UIC0_SR) & 0x08000000)
+ mtdcr(DCR_UIC0_SR, (mfdcr(DCR_UIC0_SR) &
~0x08000000));
+
+ if (!(mfdcr(DCR_UIC0_SR) & 0x10000000))
+ printk(KERN_INFO "KASUMI is ready for data\n");
+
+ /*
+ ** need keys
+ */
+ out_be32(kreg.key0, kd->key0);
+ out_be32(kreg.key1, kd->key1);
+ out_be32(kreg.key2, kd->key2);
+ out_be32(kreg.key3, kd->key3);
+ /*
+ ** write config
+ */
+ out_be32(kreg.config, kd->config);
+ /*
+ ** Write count
+ */
+ out_be32(kreg.count, kd->count);
+ /*
+ ** set fresh
+ */
+ out_be32(kreg.fresh, kd->fresh);
+ /*
+ ** set mode
+ */
+ if (kd->mode != KASUMI_F9_ENC_MODE) {
+ printk(KERN_INFO "KASUMI Invalid mode\n");
+ return -1;
+ }
+
+ out_be32(kreg.mode, kd->mode);
+ /*
+ * write data
+ * validate data CTRL_STAT[4]
+ * Validate mode CTRL_STA[1] = 1
+ * vlaidatkeys keys CTRL_STAT[2] = 1
+ * vlaidatkeys count and config
+ */
+ out_be32(kreg.ctrl,
+ in_be32(kreg.ctrl) |
+ (KASUMI_VAL_CFG | KASUMI_VAL_COUNT |
KASUMI_VAL_KEYS |
+ KASUMI_VAL_MODE | KASUMI_VAL_FRESH));
+ time_out = 100;
+ /*
+ ** Just in case validation is not complete.
+ */
+ while (in_be32(kreg.ctrl) & (KASUMI_VAL_CFG |
+ KASUMI_VAL_COUNT | KASUMI_VAL_KEYS
+ | KASUMI_VAL_MODE | KASUMI_VAL_FRESH)) {
+ time_out--;
+ mdelay(1);
+ if (time_out <= 0) {
+ printk(KERN_INFO "line %d Timed out
KASU0_CTRL=0x%x\n",
+ __LINE__, in_be32(kreg.ctrl));
+ break;
+ }
+ }
+
+ if (in_be32(kreg.ctrl) & (KASUMI_VAL_CFG |
+ KASUMI_VAL_COUNT | KASUMI_VAL_KEYS
+ | KASUMI_VAL_MODE | KASUMI_VAL_FRESH))
+ printk(KERN_WARNING
+ " CFG COUNT KEYS MODE validation NOT
complete\n");
+
+ /*
+ ** Loop around this code till we encode all 64bit
data blocks
+ */
+ while (len > 0) {
+
+ if ((&kd->data_in[i] != NULL) && (&kd->data_in[i +
1] != NULL)) {
+ out_be32(kreg.data_in0, kd->data_in[i]);
+ out_be32(kreg.data_in1, kd->data_in[i + 1]);
+ } else {
+ printk(KERN_INFO "No data passed\n");
+ return -1;
+ }
+
+ out_be32(kreg.ctrl, in_be32(kreg.ctrl) |
KASUMI_VAL_DATA);
+ time_out = 100;
+
+ while (in_be32(kreg.ctrl) & (KASUMI_VAL_DATA)) {
+ time_out--;
+ mdelay(1);
+ if (time_out <= 0) {
+ printk(KERN_INFO
+ "line %d Timed out KASU0_CTRL=0x%x\n",
+ __LINE__, in_be32(kreg.ctrl));
+ break;
+ }
+ }
+
+ if (in_be32(kreg.ctrl) & (KASUMI_VAL_DATA)) {
+ printk(KERN_INFO "Data validation NOT
complete\n");
+ }
+
+ if (!(mfdcr(DCR_UIC0_SR) & 0x10000000))
+ printk(KERN_INFO "KASUMI is NOT ready for
data\n");
+
+ i += 2;
+ len = len - 64;
+ }
+
+ if (!(mfdcr(DCR_UIC0_SR) & 0x08000000))
+ printk(KERN_INFO
+ "KASUMI data NOT available and NO KDA
interrupt occured\n");
+
+ /*
+ ** Is data avaialbel
+ */
+ time_out = 100;
+ while (!(in_be32(kreg.status) & KASUMI_DATA_READY))
{
+ time_out--;
+ mdelay(1);
+ if (time_out <= 0) {
+ printk(KERN_INFO "line %d Timed out
KASU0_CTRL=0x%x\n",
+ __LINE__, in_be32(kreg.ctrl));
+ }
+
+ }
+
+ if (!(in_be32(kreg.status) & KASUMI_DATA_READY))
+ printk(KERN_WARNING "Data is not ready\n");
+ kd->data_out[0] =
kasumi_byte_swap(in_be32(kreg.data_out0));
+ kd->data_out[1] =
kasumi_byte_swap(in_be32(kreg.data_out1));
+ out_be32(kreg.ctrl, KASUMI_DATA_READY);
+ return 0;
+}
+
+/*
+** arg1: kasumi_desc structure
+** arg2: len
+** arg3: direction
+*/
+int kasumi_f9_encrypt(struct kasumi_desc *test, uint
len, uint direction)
+{
+ test->config = (len << 16 | direction);
+ test->config = (0x00BD0000);
+ test->mode = KASUMI_F9_ENC_MODE;
+ test->key0 = kasumi_byte_swap(test->key0);
+ test->key1 = kasumi_byte_swap(test->key1);
+ test->key2 = kasumi_byte_swap(test->key2);
+ test->key3 = kasumi_byte_swap(test->key3);
+ test->count = kasumi_byte_swap(test->count);
+ test->config = kasumi_byte_swap(test->config);
+ test->fresh = kasumi_byte_swap(test->fresh);
+
+ if (kasumi_f9(test) != 0) {
+ printk(KERN_INFO
+ "kasumi_f8_encrypt_decrypt() returned
error\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+**IOCTL function to let this driver usaed from user
space.
+**
+*/
+static int kasumi_ioctl(struct inode *inode, struct
file *filep,
+ unsigned int cmd, unsigned long arg)
+{
+ int kerr = 0;
+ struct kasumi_f8_f9_desc kd_f89;
+
+ kd_f89.kd.data_in = &data_in[0];
+ kd_f89.kd.data_out = &data_out[0];
+
+ switch (cmd) {
+ case KASUMI_IOCTL_ENCRYPT:
+ {
+ copy_from_user(&kd_f89,
+ (struct kasumi_f8_f9_desc __user *)arg,
+ sizeof(struct kasumi_f8_f9_desc));
+ kerr = kasumi_encrypt(&kd_f89.kd);
+ copy_to_user(&kd_f89,
+ (struct kasumi_f8_f9_desc __user *)arg,
+ sizeof(struct kasumi_f8_f9_desc));
+
+ if (kerr < 0)
+ return kerr;
+ return 0;
+ break;
+ }
+ case KASUMI_IOCTL_DECRYPT:
+ {
+ printk(KERN_INFO "kd_f89.kd.data_in[0]=0x%x\n",
+ kd_f89.kd.data_in[0]);
+ printk(KERN_INFO "kd_f89.kd.data_in[1]=0x%x\n",
+ kd_f89.kd.data_in[1]);
+ copy_from_user(&kd_f89,
+ (struct kasumi_f8_f9_desc __user *)arg,
+ sizeof(struct kasumi_f8_f9_desc));
+ kerr = kasumi_decrypt(&kd_f89.kd);
+ copy_to_user(&kd_f89,
+ (struct kasumi_f8_f9_desc __user *)arg,
+ sizeof(struct kasumi_f8_f9_desc));
+ if (kerr < 0)
+ return kerr;
+ break;
+ }
+ case KASUMI_IOCTL_F8_MODE:
+ {
+ copy_from_user(&kd_f89,
+ (struct kasumi_f8_f9_desc __user *)arg,
+ sizeof(struct kasumi_f8_f9_desc));
+ kerr =
+ kasumi_f8_encrypt(&kd_f89.kd, kd_f89.len,
+ kd_f89.bearer, kd_f89.direction);
+ copy_to_user(&kd_f89,
+ (struct kasumi_f8_f9_desc __user *)arg,
+ sizeof(struct kasumi_f8_f9_desc));
+ if (kerr < 0)
+ return kerr;
+ break;
+ }
+ case KASUMI_IOCTL_F9_MODE:
+ {
+ copy_from_user(&kd_f89,
+ (struct kasumi_f8_f9_desc __user *)arg,
+ sizeof(struct kasumi_f8_f9_desc));
+ kerr =
+ kasumi_f9_encrypt(&kd_f89.kd, kd_f89.len,
+ kd_f89.direction);
+ copy_to_user(&kd_f89,
+ (struct kasumi_f8_f9_desc __user *)arg,
+ sizeof(struct kasumi_f8_f9_desc));
+ if (kerr < 0)
+ return kerr;
+ break;
+ }
+ default:
+ return -ENOTTY;
+ }
+
+ return 0;
+}
+
+/*
+** file operations
+*/
+struct file_operations kasumi_fops = {
+ .ioctl = kasumi_ioctl,
+};
+
+/*
+** Moudle initialization
+**/
+int kasumi_init_module(void)
+{
+ int kerr = 0;
+ dev_t dev = MKDEV(kasumi_major, 0);
+ struct cdev *k_cdev = cdev_alloc();
+
+ printk(KERN_INFO "Loading Kasumi Driver\n");
+ if (kasumi_major)
+ kerr = register_chrdev_region(dev, 1, "kasumi");
+ else {
+ kerr = alloc_chrdev_region(&dev, 0, 1, "kasumi");
+ kasumi_major = MAJOR(dev);
+ }
+
+ if (kerr < 0) {
+ printk(KERN_ERR "KASUMI:Failed to get major
number");
+ return kerr;
+ }
+
+ cdev_init(k_cdev, &kasumi_fops);
+ k_cdev->owner = THIS_MODULE;
+ k_cdev->ops = &kasumi_fops;
+ kerr = cdev_add(k_cdev, MKDEV(kasumi_major, 0), 1);
+ if (kerr < 0)
+ return kerr;
+
+ /*
+ * setup register base address
+ */
+ kasumi_base = ioremap64(0x0E0180000ULL, 0x80);
+ if (!kasumi_base) {
+ printk(KERN_INFO "ioremap falied for address
0xE0180000\n");
+ return -1;
+ }
+
+ /*
+ **Register address assignments
+ **
+ */
+ kreg.ctrl = ((uint *) ((u8 *) kasumi_base +
KASU0_CTRL));
+ kreg.status = ((uint *) ((u8 *) kasumi_base +
KASU0_STATUS));
+ kreg.mode = ((uint *) ((u8 *) kasumi_base +
KASU0_MODE));
+ kreg.key0 = ((uint *) ((u8 *) kasumi_base +
KASU0_KEY0));
+ kreg.key1 = ((uint *) ((u8 *) kasumi_base +
KASU0_KEY1));
+ kreg.key2 = ((uint *) ((u8 *) kasumi_base +
KASU0_KEY2));
+ kreg.key3 = ((uint *) ((u8 *) kasumi_base +
KASU0_KEY3));
+ kreg.count = ((uint *) ((u8 *) kasumi_base +
KASU0_COUNT));
+ kreg.config = ((uint *) ((u8 *) kasumi_base +
KASU0_CONFIG));
+ kreg.fresh = ((uint *) ((u8 *) kasumi_base +
KASU0_FRESH));
+ kreg.data_in0 = ((uint *) ((u8 *) kasumi_base +
KASU0_DATA_IN0));
+ kreg.data_in1 = ((uint *) ((u8 *) kasumi_base +
KASU0_DATA_IN1));
+ kreg.data_out0 = ((uint *) ((u8 *) kasumi_base +
KASU0_DATA_OUT0));
+ kreg.data_out1 = ((uint *) ((u8 *) kasumi_base +
KASU0_DATA_OUT1));
+
+ /*
+ ** reset KASUMI core
+ */
+ SDR_WRITE(SDR0_SRST1, SDR_READ(SDR0_SRST1) |
KASUMI_RESET_MSK);
+ SDR_WRITE(SDR0_SRST1, SDR_READ(SDR0_SRST1) &
(~KASUMI_RESET_MSK));
+ /*
+ ** Disable the read pipe line. Otherwise it may
cause hang on PLB
+ */
+ mtdcr(DCR_PLB4A0, mfdcr(DCR_PLB4A0) &
DISABLE_RD_PIPE_LINE);
+ mtdcr(DCR_UIC0_ER, (mfdcr(DCR_UIC0_ER) |
0x18000000));
+
+ /*
+ ** Kasumi test
+ */
+#ifdef KASUMI_TEST
+ kasumi_test();
+ /*
+ ** f8 mode
+ */
+ kasumi_test_f8_1();
+ /*
+ ** f9 mode
+ */
+ kasumi_test_f9();
+#endif
+ return 0;
+}
+
+/*
+ * Cleanup module
+ */
+void kasumi_cleanup_module(void)
+{
+ iounmap(kasumi_base);
+ printk(KERN_INFO "Exiting Kasumi Driver\n");
+}
+
+EXPORT_SYMBOL(kasumi_f9_encrypt);
+EXPORT_SYMBOL(kasumi_f8_encrypt);
+EXPORT_SYMBOL(kasumi_encrypt);
+EXPORT_SYMBOL(kasumi_decrypt);
+module_init(kasumi_init_module);
+module_exit(kasumi_cleanup_module);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tirumala Marri <[email protected]>");
+MODULE_DESCRIPTION("Kasumi security engine driver");
----------------------
Thanks,
Tirumala Marri


2007-07-19 09:48:14

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: Looking for comments on a Linux driver for HW accelerated Kasumi+F8+F9 algorithms.

Hi.

On Wed, Jul 18, 2007 at 04:33:14PM -0700, tirumalareddy marri ([email protected]) wrote:
> Hi ,
> I have created Linux driver for HW accelerated
> kasumi, F8 and F9 algorithms. Could you please look at
> the driver and provide comments about the usage. This
> driver is acts as a character driver. Encryption API's
> can be accessed from kernel and user space. My concern
> is accessing the driver from user space is secure or
> not.
>
> If possible can some one please send me rules to
> follow when we write a Linux security driver.
> --------------------------- patch for the driver
> -----------

Sorry, but your patch looks horrible - your mailer broke alignment, you
do not follow Linux kernel coding standards. Please fix that first.

According to patch itself, do all 440epx have that engine, since you
access generic registers? Patch has too many debug prints in the hottest
path, either remove them or wrap into helper which allows to turn them
off - no one wants to read a message each time data is ready.
Encryption is not protected against simultaneous access - there will be
either bug or data corruption if several users simultaneously try to
perfrom a processing. There is number of missed checks of the returned
values of the functions which can fail. There is number of exported
symbols without appropriate in-kernel users - it is not allowed.

And userspace interface - I will not argue if it is good or bad, but be
ready to listen quite a few phrases about your taste.

I would suggest to create a generic userspace interface to deliver
crypto events to/frm userspace and bind it to cryptoapi. You also likely
want to create a cryptoapi driver to allow in-kernel subsystem to use
kasumi at least.

--
Evgeniy Polyakov