This patch add core codes.
---
crypto/xcbc.c | 230 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/crypto.h | 21 ++++
2 files changed, 251 insertions(+), 0 deletions(-)
create mode 100644 crypto/xcbc.c
2473ccbfd89e4c20507caba721f44aa748a9bc6e
diff --git a/crypto/xcbc.c b/crypto/xcbc.c
new file mode 100644
index 0000000..9690dc9
--- /dev/null
+++ b/crypto/xcbc.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C)2005 USAGI/WIDE Project
+ *
+ * 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
+ *
+ * Author:
+ * Kazunori Miyazawa <[EMAIL PROTECTED]>
+ */
+
+#include <linux/crypto.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <asm/scatterlist.h>
+#include "internal.h"
+
+struct xcbc_ops {
+ unsigned int len;
+ u8 *prev;
+};
+
+int crypto_alloc_xcbc_block(struct crypto_tfm *tfm)
+{
+ struct xcbc_ops *ops;
+
+ BUG_ON(!crypto_tfm_alg_blocksize(tfm));
+
+ ops = kmalloc(sizeof(*ops) + crypto_tfm_alg_blocksize(tfm), GFP_KERNEL);
+ if (ops == NULL)
+ return -ENOMEM;
+ ops->len = 0;
+ ops->prev = (u8*)(ops + 1);
+
+ tfm->crt_cipher.cit_xcbc_block = ops;
+ tfm->crt_cipher.cit_xcbc_const = NULL;
+
+ return 0;
+}
+
+static int _crypto_xcbc_init(struct crypto_tfm *tfm, u8 *key, unsigned int
keylen)
+{
+ const unsigned int bsize = crypto_tfm_alg_blocksize(tfm);
+ u8 key1[bsize];
+ int err;
+
+ if (!(tfm->crt_cipher.cit_mode & CRYPTO_TFM_MODE_CBC))
+ return -EINVAL;
+
+ if (keylen != crypto_tfm_alg_blocksize(tfm))
+ return -EINVAL;
+
+ if ((err = crypto_cipher_setkey(tfm, key, keylen)))
+ return err;
+
+ tfm->__crt_alg->cra_cipher.cia_encrypt(crypto_tfm_ctx(tfm), key1,
+ (const u8*)tfm->crt_cipher.cit_xcbc_const);
+
+ return crypto_cipher_setkey(tfm, key1, bsize);
+
+}
+
+int crypto_xcbc_init(struct crypto_tfm *tfm, u8 *key, unsigned int keylen)
+{
+ struct xcbc_ops *ops = (struct xcbc_ops*)tfm->crt_cipher.cit_xcbc_block;
+
+ if (tfm->crt_cipher.cit_xcbc_const == NULL)
+ return -EINVAL;
+
+ ops->len = 0;
+ memset(ops->prev, 0, crypto_tfm_alg_blocksize(tfm));
+ memset(tfm->crt_cipher.cit_iv, 0, crypto_tfm_alg_blocksize(tfm));
+ return _crypto_xcbc_init(tfm, key, keylen);
+}
+
+void crypto_xcbc_update(struct crypto_tfm *tfm, struct scatterlist *sg,
unsigned int nsg)
+{
+ struct xcbc_ops *ops = (struct xcbc_ops*)tfm->crt_cipher.cit_xcbc_block;
+ const unsigned int bsize = crypto_tfm_alg_blocksize(tfm);
+ unsigned int i;
+
+ if (!(tfm->crt_cipher.cit_mode & CRYPTO_TFM_MODE_CBC))
+ return;
+
+ for(i = 0; i < nsg; i++) {
+
+ struct page *pg = sg[i].page;
+ unsigned int offset = sg[i].offset;
+ unsigned int slen = sg[i].length;
+
+ while (slen > 0) {
+ unsigned int len = min(slen, ((unsigned
int)(PAGE_SIZE)) - offset);
+ char *p = crypto_kmap(pg, 0) + offset;
+
+ /* checking the data can fill the block */
+ if ((ops->len + len) <= bsize) {
+ memcpy(ops->prev + ops->len, p, len);
+ ops->len += len;
+ slen -= len;
+
+ /* checking the rest of the page */
+ if (len + offset >= PAGE_SIZE) {
+ offset = 0;
+ pg++;
+ } else
+ offset += len;
+
+ crypto_kunmap(p, 0);
+ crypto_yield(tfm);
+ continue;
+ }
+
+ /* filling ops->prev with new data and encrypting it */
+ memcpy(ops->prev + ops->len, p, bsize - ops->len);
+ len -= bsize - ops->len;
+ p += bsize - ops->len;
+ tfm->crt_u.cipher.cit_xor_block(tfm->crt_cipher.cit_iv,
+ ops->prev);
+ tfm->__crt_alg->cra_cipher.cia_encrypt(
+ crypto_tfm_ctx(tfm), tfm->crt_cipher.cit_iv,
+ tfm->crt_cipher.cit_iv);
+
+ /* clearing the length */
+ ops->len = 0;
+
+ /* encrypting the rest of data */
+ while (len > bsize) {
+
tfm->crt_u.cipher.cit_xor_block(tfm->crt_cipher.cit_iv, p);
+ tfm->__crt_alg->cra_cipher.cia_encrypt(
+ crypto_tfm_ctx(tfm),
tfm->crt_cipher.cit_iv,
+ tfm->crt_cipher.cit_iv);
+ p += bsize;
+ len -= bsize;
+ }
+
+ /* keeping the surplus of blocksize */
+ if (len) {
+ memcpy(ops->prev, p, len);
+ ops->len = len;
+ }
+ crypto_kunmap(p, 0);
+ crypto_yield(tfm);
+ slen -= min(slen, ((unsigned int)(PAGE_SIZE)) - offset);
+ offset = 0;
+ pg++;
+ }
+ }
+}
+
+int crypto_xcbc_final(struct crypto_tfm *tfm, u8 *key, unsigned int keylen, u8
*out)
+{
+ struct xcbc_ops *ops = (struct xcbc_ops*)tfm->crt_cipher.cit_xcbc_block;
+ const unsigned int bsize = crypto_tfm_alg_blocksize(tfm);
+ int ret = 0;
+
+ if (!(tfm->crt_cipher.cit_mode & CRYPTO_TFM_MODE_CBC))
+ return -EINVAL;
+
+ if (keylen != bsize)
+ return -EINVAL;
+
+ if (ops->len == bsize) {
+ u8 key2[bsize];
+
+ if ((ret = crypto_cipher_setkey(tfm, key, keylen)))
+ return ret;
+
+ tfm->__crt_alg->cra_cipher.cia_encrypt(crypto_tfm_ctx(tfm),
key2,
+ (const
u8*)(tfm->crt_cipher.cit_xcbc_const+bsize));
+ tfm->crt_u.cipher.cit_xor_block(tfm->crt_cipher.cit_iv,
ops->prev);
+ tfm->crt_u.cipher.cit_xor_block(tfm->crt_cipher.cit_iv, key2);
+
+ _crypto_xcbc_init(tfm, key, keylen);
+
+ tfm->__crt_alg->cra_cipher.cia_encrypt(crypto_tfm_ctx(tfm),
out, tfm->crt_cipher.cit_iv);
+ } else {
+ u8 key3[bsize];
+ unsigned int rlen;
+ u8 *p = ops->prev + ops->len;
+ *p = 0x80;
+ p++;
+
+ rlen = bsize - ops->len -1;
+ if (rlen)
+ memset(p, 0, rlen);
+
+ if ((ret = crypto_cipher_setkey(tfm, key, keylen)))
+ return ret;
+
+ tfm->__crt_alg->cra_cipher.cia_encrypt(crypto_tfm_ctx(tfm),
key3,
+ (const
u8*)(tfm->crt_cipher.cit_xcbc_const+bsize*2));
+
+ tfm->crt_u.cipher.cit_xor_block(tfm->crt_cipher.cit_iv,
ops->prev);
+ tfm->crt_u.cipher.cit_xor_block(tfm->crt_cipher.cit_iv, key3);
+ _crypto_xcbc_init(tfm, key, keylen);
+ tfm->__crt_alg->cra_cipher.cia_encrypt(crypto_tfm_ctx(tfm),
out, tfm->crt_cipher.cit_iv);
+ }
+
+ return ret;
+}
+
+int crypto_xcbc(struct crypto_tfm *tfm, u8 *key, unsigned int keylen,
+ struct scatterlist *sg, unsigned int nsg, u8 *out)
+{
+ int ret = 0;
+
+ ret = crypto_xcbc_init(tfm, key, keylen);
+ if (ret)
+ return ret;
+ crypto_xcbc_update(tfm, sg, nsg);
+ ret = crypto_xcbc_final(tfm, key, keylen, out);
+
+ return ret;
+}
+
+EXPORT_SYMBOL_GPL(crypto_xcbc_init);
+EXPORT_SYMBOL_GPL(crypto_xcbc_update);
+EXPORT_SYMBOL_GPL(crypto_xcbc_final);
+EXPORT_SYMBOL_GPL(crypto_xcbc);
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index d88bf8a..75fe7bc 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -189,6 +189,17 @@ struct cipher_tfm {
struct scatterlist *src,
unsigned int nbytes, u8 *iv);
void (*cit_xor_block)(u8 *dst, const u8 *src);
+#ifdef CONFIG_CRYPTO_XCBC
+ /*
+ * XCBC needs 3 constants for the derived keys.
+ * Each lengh of those must equal the cipher
+ * block size so that cit_xcbc_const's length is
+ * 3 times of the blocksize and it contains
+ * concantinated constants.
+ */
+ u8 *cit_xcbc_const;
+ void *cit_xcbc_block;
+#endif
};
struct digest_tfm {
@@ -432,5 +443,15 @@ void crypto_hmac(struct crypto_tfm *tfm,
struct scatterlist *sg, unsigned int nsg, u8 *out);
#endif /* CONFIG_CRYPTO_HMAC */
+/*
+ * XCBC support
+ */
+#ifdef CONFIG_CRYPTO_XCBC
+int crypto_xcbc_init(struct crypto_tfm *tfm, u8 *key, unsigned int keylen);
+void crypto_xcbc_update(struct crypto_tfm *tfm, struct scatterlist *sg,
unsigned int nsg);
+int crypto_xcbc_final(struct crypto_tfm *tfm, u8 *key, unsigned int keylen, u8
*out);
+int crypto_xcbc(struct crypto_tfm *tfm, u8 *key, unsigned int keylen,
+ struct scatterlist *sg, unsigned int nsg, u8 *out);
+#endif /* CONFIG_CRYPTO_XCBC */
#endif /* _LINUX_CRYPTO_H */
--
Kazunori Miyazawa
Subject: [PATCH] add xcbc core codes
From: Kazunori MIYAZAWA <[EMAIL PROTECTED]>
Date: 1138249565 +0900
---
crypto/xcbc.c | 230 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/crypto.h | 21 ++++
2 files changed, 251 insertions(+), 0 deletions(-)
create mode 100644 crypto/xcbc.c
2473ccbfd89e4c20507caba721f44aa748a9bc6e
diff --git a/crypto/xcbc.c b/crypto/xcbc.c
new file mode 100644
index 0000000..9690dc9
--- /dev/null
+++ b/crypto/xcbc.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C)2005 USAGI/WIDE Project
+ *
+ * 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
+ *
+ * Author:
+ * Kazunori Miyazawa <[EMAIL PROTECTED]>
+ */
+
+#include <linux/crypto.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <asm/scatterlist.h>
+#include "internal.h"
+
+struct xcbc_ops {
+ unsigned int len;
+ u8 *prev;
+};
+
+int crypto_alloc_xcbc_block(struct crypto_tfm *tfm)
+{
+ struct xcbc_ops *ops;
+
+ BUG_ON(!crypto_tfm_alg_blocksize(tfm));
+
+ ops = kmalloc(sizeof(*ops) + crypto_tfm_alg_blocksize(tfm), GFP_KERNEL);
+ if (ops == NULL)
+ return -ENOMEM;
+ ops->len = 0;
+ ops->prev = (u8*)(ops + 1);
+
+ tfm->crt_cipher.cit_xcbc_block = ops;
+ tfm->crt_cipher.cit_xcbc_const = NULL;
+
+ return 0;
+}
+
+static int _crypto_xcbc_init(struct crypto_tfm *tfm, u8 *key, unsigned int
keylen)
+{
+ const unsigned int bsize = crypto_tfm_alg_blocksize(tfm);
+ u8 key1[bsize];
+ int err;
+
+ if (!(tfm->crt_cipher.cit_mode & CRYPTO_TFM_MODE_CBC))
+ return -EINVAL;
+
+ if (keylen != crypto_tfm_alg_blocksize(tfm))
+ return -EINVAL;
+
+ if ((err = crypto_cipher_setkey(tfm, key, keylen)))
+ return err;
+
+ tfm->__crt_alg->cra_cipher.cia_encrypt(crypto_tfm_ctx(tfm), key1,
+ (const u8*)tfm->crt_cipher.cit_xcbc_const);
+
+ return crypto_cipher_setkey(tfm, key1, bsize);
+
+}
+
+int crypto_xcbc_init(struct crypto_tfm *tfm, u8 *key, unsigned int keylen)
+{
+ struct xcbc_ops *ops = (struct xcbc_ops*)tfm->crt_cipher.cit_xcbc_block;
+
+ if (tfm->crt_cipher.cit_xcbc_const == NULL)
+ return -EINVAL;
+
+ ops->len = 0;
+ memset(ops->prev, 0, crypto_tfm_alg_blocksize(tfm));
+ memset(tfm->crt_cipher.cit_iv, 0, crypto_tfm_alg_blocksize(tfm));
+ return _crypto_xcbc_init(tfm, key, keylen);
+}
+
+void crypto_xcbc_update(struct crypto_tfm *tfm, struct scatterlist *sg,
unsigned int nsg)
+{
+ struct xcbc_ops *ops = (struct xcbc_ops*)tfm->crt_cipher.cit_xcbc_block;
+ const unsigned int bsize = crypto_tfm_alg_blocksize(tfm);
+ unsigned int i;
+
+ if (!(tfm->crt_cipher.cit_mode & CRYPTO_TFM_MODE_CBC))
+ return;
+
+ for(i = 0; i < nsg; i++) {
+
+ struct page *pg = sg[i].page;
+ unsigned int offset = sg[i].offset;
+ unsigned int slen = sg[i].length;
+
+ while (slen > 0) {
+ unsigned int len = min(slen, ((unsigned
int)(PAGE_SIZE)) - offset);
+ char *p = crypto_kmap(pg, 0) + offset;
+
+ /* checking the data can fill the block */
+ if ((ops->len + len) <= bsize) {
+ memcpy(ops->prev + ops->len, p, len);
+ ops->len += len;
+ slen -= len;
+
+ /* checking the rest of the page */
+ if (len + offset >= PAGE_SIZE) {
+ offset = 0;
+ pg++;
+ } else
+ offset += len;
+
+ crypto_kunmap(p, 0);
+ crypto_yield(tfm);
+ continue;
+ }
+
+ /* filling ops->prev with new data and encrypting it */
+ memcpy(ops->prev + ops->len, p, bsize - ops->len);
+ len -= bsize - ops->len;
+ p += bsize - ops->len;
+ tfm->crt_u.cipher.cit_xor_block(tfm->crt_cipher.cit_iv,
+ ops->prev);
+ tfm->__crt_alg->cra_cipher.cia_encrypt(
+ crypto_tfm_ctx(tfm), tfm->crt_cipher.cit_iv,
+ tfm->crt_cipher.cit_iv);
+
+ /* clearing the length */
+ ops->len = 0;
+
+ /* encrypting the rest of data */
+ while (len > bsize) {
+
tfm->crt_u.cipher.cit_xor_block(tfm->crt_cipher.cit_iv, p);
+ tfm->__crt_alg->cra_cipher.cia_encrypt(
+ crypto_tfm_ctx(tfm),
tfm->crt_cipher.cit_iv,
+ tfm->crt_cipher.cit_iv);
+ p += bsize;
+ len -= bsize;
+ }
+
+ /* keeping the surplus of blocksize */
+ if (len) {
+ memcpy(ops->prev, p, len);
+ ops->len = len;
+ }
+ crypto_kunmap(p, 0);
+ crypto_yield(tfm);
+ slen -= min(slen, ((unsigned int)(PAGE_SIZE)) - offset);
+ offset = 0;
+ pg++;
+ }
+ }
+}
+
+int crypto_xcbc_final(struct crypto_tfm *tfm, u8 *key, unsigned int keylen, u8
*out)
+{
+ struct xcbc_ops *ops = (struct xcbc_ops*)tfm->crt_cipher.cit_xcbc_block;
+ const unsigned int bsize = crypto_tfm_alg_blocksize(tfm);
+ int ret = 0;
+
+ if (!(tfm->crt_cipher.cit_mode & CRYPTO_TFM_MODE_CBC))
+ return -EINVAL;
+
+ if (keylen != bsize)
+ return -EINVAL;
+
+ if (ops->len == bsize) {
+ u8 key2[bsize];
+
+ if ((ret = crypto_cipher_setkey(tfm, key, keylen)))
+ return ret;
+
+ tfm->__crt_alg->cra_cipher.cia_encrypt(crypto_tfm_ctx(tfm),
key2,
+ (const
u8*)(tfm->crt_cipher.cit_xcbc_const+bsize));
+ tfm->crt_u.cipher.cit_xor_block(tfm->crt_cipher.cit_iv,
ops->prev);
+ tfm->crt_u.cipher.cit_xor_block(tfm->crt_cipher.cit_iv, key2);
+
+ _crypto_xcbc_init(tfm, key, keylen);
+
+ tfm->__crt_alg->cra_cipher.cia_encrypt(crypto_tfm_ctx(tfm),
out, tfm->crt_cipher.cit_iv);
+ } else {
+ u8 key3[bsize];
+ unsigned int rlen;
+ u8 *p = ops->prev + ops->len;
+ *p = 0x80;
+ p++;
+
+ rlen = bsize - ops->len -1;
+ if (rlen)
+ memset(p, 0, rlen);
+
+ if ((ret = crypto_cipher_setkey(tfm, key, keylen)))
+ return ret;
+
+ tfm->__crt_alg->cra_cipher.cia_encrypt(crypto_tfm_ctx(tfm),
key3,
+ (const
u8*)(tfm->crt_cipher.cit_xcbc_const+bsize*2));
+
+ tfm->crt_u.cipher.cit_xor_block(tfm->crt_cipher.cit_iv,
ops->prev);
+ tfm->crt_u.cipher.cit_xor_block(tfm->crt_cipher.cit_iv, key3);
+ _crypto_xcbc_init(tfm, key, keylen);
+ tfm->__crt_alg->cra_cipher.cia_encrypt(crypto_tfm_ctx(tfm),
out, tfm->crt_cipher.cit_iv);
+ }
+
+ return ret;
+}
+
+int crypto_xcbc(struct crypto_tfm *tfm, u8 *key, unsigned int keylen,
+ struct scatterlist *sg, unsigned int nsg, u8 *out)
+{
+ int ret = 0;
+
+ ret = crypto_xcbc_init(tfm, key, keylen);
+ if (ret)
+ return ret;
+ crypto_xcbc_update(tfm, sg, nsg);
+ ret = crypto_xcbc_final(tfm, key, keylen, out);
+
+ return ret;
+}
+
+EXPORT_SYMBOL_GPL(crypto_xcbc_init);
+EXPORT_SYMBOL_GPL(crypto_xcbc_update);
+EXPORT_SYMBOL_GPL(crypto_xcbc_final);
+EXPORT_SYMBOL_GPL(crypto_xcbc);
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index d88bf8a..75fe7bc 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -189,6 +189,17 @@ struct cipher_tfm {
struct scatterlist *src,
unsigned int nbytes, u8 *iv);
void (*cit_xor_block)(u8 *dst, const u8 *src);
+#ifdef CONFIG_CRYPTO_XCBC
+ /*
+ * XCBC needs 3 constants for the derived keys.
+ * Each lengh of those must equal the cipher
+ * block size so that cit_xcbc_const's length is
+ * 3 times of the blocksize and it contains
+ * concantinated constants.
+ */
+ u8 *cit_xcbc_const;
+ void *cit_xcbc_block;
+#endif
};
struct digest_tfm {
@@ -432,5 +443,15 @@ void crypto_hmac(struct crypto_tfm *tfm,
struct scatterlist *sg, unsigned int nsg, u8 *out);
#endif /* CONFIG_CRYPTO_HMAC */
+/*
+ * XCBC support
+ */
+#ifdef CONFIG_CRYPTO_XCBC
+int crypto_xcbc_init(struct crypto_tfm *tfm, u8 *key, unsigned int keylen);
+void crypto_xcbc_update(struct crypto_tfm *tfm, struct scatterlist *sg,
unsigned int nsg);
+int crypto_xcbc_final(struct crypto_tfm *tfm, u8 *key, unsigned int keylen, u8
*out);
+int crypto_xcbc(struct crypto_tfm *tfm, u8 *key, unsigned int keylen,
+ struct scatterlist *sg, unsigned int nsg, u8 *out);
+#endif /* CONFIG_CRYPTO_XCBC */
#endif /* _LINUX_CRYPTO_H */
--
1.1.3