From 6574e346e9b29a6abbe78cea2fc588a099c3d36b Mon Sep 17 00:00:00 2001
From: Nikos Mavrogiannopoulos <nmav@gnutls.org>
Date: Sun, 4 Dec 2011 17:36:24 +0100
Subject: [PATCH 162/291] cryptodev: added

---
 drivers/staging/crypto/cryptodev/.gitignore      |   1 +
 drivers/staging/crypto/cryptodev/lib/Makefile    |   9 ++
 drivers/staging/crypto/cryptodev/lib/benchmark   | Bin 0 -> 32357 bytes
 drivers/staging/crypto/cryptodev/lib/benchmark.c |  88 ++++++++++++
 drivers/staging/crypto/cryptodev/lib/benchmark.h |  18 +++
 drivers/staging/crypto/cryptodev/lib/combo.c     | 169 +++++++++++++++++++++++
 drivers/staging/crypto/cryptodev/lib/hash.c      | 160 +++++++++++++++++++++
 drivers/staging/crypto/cryptodev/lib/hash.h      |  20 +++
 drivers/staging/crypto/cryptodev/lib/main.c      |  61 ++++++++
 9 files changed, 526 insertions(+)
 create mode 100644 drivers/staging/crypto/cryptodev/lib/Makefile
 create mode 100755 drivers/staging/crypto/cryptodev/lib/benchmark
 create mode 100644 drivers/staging/crypto/cryptodev/lib/benchmark.c
 create mode 100644 drivers/staging/crypto/cryptodev/lib/benchmark.h
 create mode 100644 drivers/staging/crypto/cryptodev/lib/combo.c
 create mode 100644 drivers/staging/crypto/cryptodev/lib/hash.c
 create mode 100644 drivers/staging/crypto/cryptodev/lib/hash.h
 create mode 100644 drivers/staging/crypto/cryptodev/lib/main.c

diff --git a/drivers/staging/crypto/cryptodev/.gitignore b/drivers/staging/crypto/cryptodev/.gitignore
index b5513916f3b7..894394ec7980 100644
--- a/drivers/staging/crypto/cryptodev/.gitignore
+++ b/drivers/staging/crypto/cryptodev/.gitignore
@@ -21,3 +21,4 @@ version.h
 tests/cipher-aead
 tests/fullspeed
 examples/aes
+lib/benchmark
diff --git a/drivers/staging/crypto/cryptodev/lib/Makefile b/drivers/staging/crypto/cryptodev/lib/Makefile
new file mode 100644
index 000000000000..460b4ba41efe
--- /dev/null
+++ b/drivers/staging/crypto/cryptodev/lib/Makefile
@@ -0,0 +1,9 @@
+CFLAGS=-g -O2 -Wall -DDEBUG
+
+all: benchmark
+
+benchmark: benchmark.c hash.c main.c combo.c
+	gcc $(CFLAGS) -o $@ $^ -lssl
+
+clean:
+	rm -f *.o *~ benchmark
diff --git a/drivers/staging/crypto/cryptodev/lib/benchmark b/drivers/staging/crypto/cryptodev/lib/benchmark
new file mode 100755
index 0000000000000000000000000000000000000000..5d4f30e6e37897bf46d6ab170f2e87e1d42ecacf
GIT binary patch
diff --git a/drivers/staging/crypto/cryptodev/lib/benchmark.c b/drivers/staging/crypto/cryptodev/lib/benchmark.c
new file mode 100644
index 000000000000..37e9adedf669
--- /dev/null
+++ b/drivers/staging/crypto/cryptodev/lib/benchmark.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuTLS.
+ *
+ * GnuTLS 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuTLS 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 <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include "benchmark.h"
+
+int benchmark_must_finish = 0;
+
+static void
+alarm_handler (int signo)
+{
+  benchmark_must_finish = 1;
+}
+
+int start_benchmark(struct benchmark_st * st)
+{
+  int ret;
+  struct itimerval timer;
+  
+  memset(st, 0, sizeof(*st));
+
+  st->old_handler = signal (SIGPROF, alarm_handler);
+
+  ret = gettimeofday (&st->start, NULL);
+  if (ret < 0) {
+    perror("gettimeofday");
+    return -1;
+  }
+
+  benchmark_must_finish = 0;
+
+  memset(&timer, 0, sizeof(timer));
+  timer.it_value.tv_sec = 0;
+  timer.it_value.tv_usec = 100*1000;
+
+  ret = setitimer(ITIMER_PROF, &timer, NULL);
+  if (ret < 0) {
+    perror("setitimer");
+    return -1;
+  }
+  
+  return 0;
+}
+
+/* Returns -1 on error or 0 on success.
+ * elapsed: the elapsed time in milliseconds 
+ */
+int stop_benchmark(struct benchmark_st * st, unsigned long * elapsed)
+{
+  unsigned long msecs;
+  struct timeval stop;
+  int ret;
+
+  signal(SIGPROF, st->old_handler);
+
+  ret = gettimeofday (&stop, NULL);
+  if (ret < 0)
+    return -1;
+
+  msecs = (stop.tv_sec * 1000 + stop.tv_usec / 1000 -
+          (st->start.tv_sec * 1000 + st->start.tv_usec / (1000)));
+          
+  if (elapsed) *elapsed = msecs;
+
+  return 0;
+}
+
diff --git a/drivers/staging/crypto/cryptodev/lib/benchmark.h b/drivers/staging/crypto/cryptodev/lib/benchmark.h
new file mode 100644
index 000000000000..173552ec497f
--- /dev/null
+++ b/drivers/staging/crypto/cryptodev/lib/benchmark.h
@@ -0,0 +1,18 @@
+#include <sys/time.h>
+#include <time.h>
+#include <sys/time.h>
+#include <signal.h>
+
+typedef void (*sighandler_t)(int);
+
+struct benchmark_st
+{
+  struct timeval start;
+  sighandler_t old_handler;
+};
+
+extern int benchmark_must_finish;
+
+int start_benchmark(struct benchmark_st * st);
+int stop_benchmark(struct benchmark_st * st, unsigned long * elapsed);
+
diff --git a/drivers/staging/crypto/cryptodev/lib/combo.c b/drivers/staging/crypto/cryptodev/lib/combo.c
new file mode 100644
index 000000000000..29160ffd4749
--- /dev/null
+++ b/drivers/staging/crypto/cryptodev/lib/combo.c
@@ -0,0 +1,169 @@
+/*
+ * Demo on how to use /dev/crypto device for ciphering.
+ *
+ * Placed under public domain.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <crypto/cryptodev.h>
+#include "benchmark.h"
+#include "hash.h"
+
+int aead_ctx_init(struct cryptodev_ctx* ctx, int cipher, int hash, void* key, int key_size, int cfd)
+{
+#ifdef CIOCGSESSINFO
+	struct session_info_op siop;
+#endif
+
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->cfd = cfd;
+
+	ctx->sess.mac = hash;
+	ctx->sess.cipher = cipher;
+	ctx->sess.key = key;
+	ctx->sess.keylen = key_size;
+
+	if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) {
+		perror("ioctl(CIOCGSESSION)");
+		return -1;
+	}
+
+#ifdef CIOCGSESSINFO
+	memset(&siop, 0, sizeof(siop));
+	siop.ses = ctx->sess.ses;
+	if (ioctl(ctx->cfd, CIOCGSESSINFO, &siop)) {
+		perror("ioctl(CIOCGSESSINFO)");
+		return -1;
+	}
+	printf("Got %s-%s with drivers %s and %s\n",
+			siop.cipher_info.cra_name, siop.hash_info.cra_name, 
+			siop.cipher_info.cra_driver_name, siop.hash_info.cra_driver_name);
+	/*printf("Alignmask is %x\n", (unsigned int)siop.alignmask);*/
+	ctx->alignmask = siop.alignmask;
+#endif
+	return 0;
+}
+
+void aead_ctx_deinit(struct cryptodev_ctx* ctx) 
+{
+	if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses)) {
+		perror("ioctl(CIOCFSESSION)");
+	}
+}
+
+int
+aead_encrypt(struct cryptodev_ctx* ctx, const void* iv, const void* plaintext, void* ciphertext, size_t size, void* digest)
+{
+	struct crypt_auth_op cryp;
+	
+	memset(&cryp, 0, sizeof(cryp));
+
+	/* Encrypt data.in to data.encrypted */
+	cryp.ses = ctx->sess.ses;
+	cryp.len = size;
+	cryp.iv = (void*)iv;
+	cryp.iv_len = 16;
+	cryp.src = (void*)plaintext;
+	cryp.dst = (void*)ciphertext;
+	cryp.flags = COP_FLAG_AEAD_TLS_TYPE;
+
+	if (ioctl(ctx->cfd, CIOCAUTHCRYPT, &cryp)) {
+		perror("ioctl(CIOCAUTHCRYPT)");
+		return -1;
+	}
+
+	return 0;
+}
+
+static const int sizes[] = {64, 256, 512, 1024, 4096, 16*1024};
+
+
+int aead_test(int cipher, int mac, void* ukey, int ukey_size, 
+		void* user_ctx, void (*user_combo)(void* user_ctx, void* plaintext, void* ciphertext, int size, void* res))
+{
+	int cfd = -1, i, ret;
+	struct cryptodev_ctx ctx;
+	uint8_t digest[AALG_MAX_RESULT_LEN];
+	char text[16*1024];
+	char ctext[16*1024];
+	char iv[16];
+	unsigned long elapsed, counted;
+	double t1, t2;
+	struct benchmark_st bst;
+
+	/* Open the crypto device */
+	cfd = open("/dev/crypto", O_RDWR, 0);
+	if (cfd < 0) {
+		perror("open(/dev/crypto)");
+		return -1;
+	}
+
+	aead_ctx_init(&ctx, cipher, mac, ukey, ukey_size, cfd);
+	
+	for (i=0;i<sizeof(sizes)/sizeof(sizes[0]);i++) {
+		counted = 0;
+		ret = start_benchmark(&bst);
+		if (ret < 0) {
+			ret = -1;
+			goto finish;
+		}
+
+		do {
+			if (aead_encrypt(&ctx, iv, text, text, sizes[i], digest) < 0)
+				return -2;
+			counted += sizes[i];
+		} while(benchmark_must_finish==0);
+		
+		ret = stop_benchmark(&bst, &elapsed);
+		if (ret < 0) {
+			ret = -1;
+			goto finish;
+		}
+	
+		t1 = (double)counted/(double)elapsed;
+
+		/* now check the user function */
+		counted = 0;
+		ret = start_benchmark(&bst);
+		if (ret < 0) {
+			ret = -1;
+			goto finish;
+		}
+
+		do {
+			user_combo(user_ctx, text, ctext, sizes[i], digest);
+			counted += sizes[i];
+		} while(benchmark_must_finish==0);
+		
+		ret = stop_benchmark(&bst, &elapsed);
+		if (ret < 0) {
+			ret = -1;
+			goto finish;
+		}
+	
+		t2 = (double)counted/(double)elapsed;
+		
+		if (t1 > t2) {
+			ret = sizes[i];
+			goto finish;
+		}
+#ifdef DEBUG
+		printf("%d: kernel: %.4f bytes/msec, user: %.4f bytes/msec\n", sizes[i], t1, t2);
+#endif
+	}
+	
+	ret = -1;
+finish:
+	aead_ctx_deinit(&ctx);
+
+	/* Close the original descriptor */
+	if (close(cfd)) {
+		perror("close(cfd)");
+		return 1;
+	}
+	return ret;
+}
diff --git a/drivers/staging/crypto/cryptodev/lib/hash.c b/drivers/staging/crypto/cryptodev/lib/hash.c
new file mode 100644
index 000000000000..000d81b01165
--- /dev/null
+++ b/drivers/staging/crypto/cryptodev/lib/hash.c
@@ -0,0 +1,160 @@
+/*
+ * Demo on how to use /dev/crypto device for ciphering.
+ *
+ * Placed under public domain.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <crypto/cryptodev.h>
+#include "hash.h"
+#include "benchmark.h"
+
+int hash_ctx_init(struct cryptodev_ctx* ctx, int hash, int cfd)
+{
+#ifdef CIOCGSESSINFO
+	struct session_info_op siop;
+#endif
+
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->cfd = cfd;
+
+	ctx->sess.mac = hash;
+
+	if (ioctl(ctx->cfd, CIOCGSESSION, &ctx->sess)) {
+		perror("ioctl(CIOCGSESSION)");
+		return -1;
+	}
+
+#ifdef CIOCGSESSINFO
+	siop.ses = ctx->sess.ses;
+	if (ioctl(ctx->cfd, CIOCGSESSINFO, &siop)) {
+		perror("ioctl(CIOCGSESSINFO)");
+		return -1;
+	}
+	printf("Got %s with driver %s\n",
+			siop.hash_info.cra_name, siop.hash_info.cra_driver_name);
+	/*printf("Alignmask is %x\n", (unsigned int)siop.alignmask);*/
+	ctx->alignmask = siop.alignmask;
+#endif
+	return 0;
+}
+
+void hash_ctx_deinit(struct cryptodev_ctx* ctx) 
+{
+	if (ioctl(ctx->cfd, CIOCFSESSION, &ctx->sess.ses)) {
+		perror("ioctl(CIOCFSESSION)");
+	}
+}
+
+int
+hash(struct cryptodev_ctx* ctx, const void* text, size_t size, void* digest)
+{
+	struct crypt_op cryp;
+	
+	memset(&cryp, 0, sizeof(cryp));
+
+	/* Encrypt data.in to data.encrypted */
+	cryp.ses = ctx->sess.ses;
+	cryp.len = size;
+	cryp.src = (void*)text;
+	cryp.mac = digest;
+	if (ioctl(ctx->cfd, CIOCCRYPT, &cryp)) {
+		perror("ioctl(CIOCCRYPT)");
+		return -1;
+	}
+
+	return 0;
+}
+
+static const int sizes[] = {64, 256, 512, 1024, 4096, 16*1024};
+
+/* Worst case running time: around 1.2 secs
+ */
+int hash_test(int algo, void (*user_hash)(void* text, int size, void* res))
+{
+	int cfd = -1, i, ret;
+	struct cryptodev_ctx ctx;
+	uint8_t digest[AALG_MAX_RESULT_LEN];
+	char text[16*1024];
+	unsigned long elapsed, counted;
+	double t1, t2;
+	struct benchmark_st bst;
+
+	/* Open the crypto device */
+	cfd = open("/dev/crypto", O_RDWR, 0);
+	if (cfd < 0) {
+		perror("open(/dev/crypto)");
+		return -1;
+	}
+
+	hash_ctx_init(&ctx, algo, cfd);
+	
+	for (i=0;i<sizeof(sizes)/sizeof(sizes[0]);i++) {
+		counted = 0;
+		ret = start_benchmark(&bst);
+		if (ret < 0) {
+			ret = -1;
+			goto finish;
+		}
+
+		do {
+			hash(&ctx, text, sizes[i], digest);
+			counted += sizes[i];
+		} while(benchmark_must_finish==0);
+		
+		ret = stop_benchmark(&bst, &elapsed);
+		if (ret < 0) {
+			ret = -1;
+			goto finish;
+		}
+printf("counted: %ld\n", counted);
+printf("elapsed: %ld\n", elapsed);
+		t1 = (double)counted/(double)elapsed;
+
+		/* now check the user function */
+		ret = start_benchmark(&bst);
+		if (ret < 0) {
+			ret = -1;
+			goto finish;
+		}
+
+		counted = 0;
+
+		do {
+			user_hash(text, sizes[i], digest);
+			counted += sizes[i];
+		} while(benchmark_must_finish==0);
+		
+		ret = stop_benchmark(&bst, &elapsed);
+		if (ret < 0) {
+			ret = -1;
+			goto finish;
+		}
+	
+		t2 = (double)counted/(double)elapsed;
+		
+		if (t1 > t2) {
+			ret = sizes[i];
+			goto finish;
+		}
+#ifdef DEBUG
+		printf("%d: kernel: %.4f bytes/msec, user: %.4f bytes/msec\n", sizes[i], t1, t2);
+#endif
+	}
+	
+	ret = -1;
+finish:
+	hash_ctx_deinit(&ctx);
+
+	/* Close the original descriptor */
+	if (close(cfd)) {
+		perror("close(cfd)");
+		return 1;
+	}
+	return ret;
+}
+
diff --git a/drivers/staging/crypto/cryptodev/lib/hash.h b/drivers/staging/crypto/cryptodev/lib/hash.h
new file mode 100644
index 000000000000..1883beaaca57
--- /dev/null
+++ b/drivers/staging/crypto/cryptodev/lib/hash.h
@@ -0,0 +1,20 @@
+#ifndef HASH_H
+# define HASH_H
+
+#include <stdint.h>
+
+struct cryptodev_ctx {
+	int cfd;
+	struct session_op sess;
+	uint16_t alignmask;
+};
+
+int hash_ctx_init(struct cryptodev_ctx* ctx, int hash, int cfd);
+void hash_ctx_deinit(struct cryptodev_ctx* ctx);
+int hash(struct cryptodev_ctx* ctx, const void* text, size_t size, void* digest);
+int hash_test(int algo, void (*user_hash)(void* text, int size, void* res));
+
+int aead_test(int cipher, int mac, void* ukey, int ukey_size, 
+		void* user_ctx, void (*user_combo)(void* user_ctx, void* plaintext, void* ciphertext, int size, void* res));
+
+#endif
diff --git a/drivers/staging/crypto/cryptodev/lib/main.c b/drivers/staging/crypto/cryptodev/lib/main.c
new file mode 100644
index 000000000000..4e0474b65edb
--- /dev/null
+++ b/drivers/staging/crypto/cryptodev/lib/main.c
@@ -0,0 +1,61 @@
+/*
+ * Demo on how to use /dev/crypto device for ciphering.
+ *
+ * Placed under public domain.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <crypto/cryptodev.h>
+#include <openssl/sha.h>
+#include <openssl/aes.h>
+#include "hash.h"
+
+void sha_hash(void* text, int size, void* digest)
+{
+SHA_CTX ctx;
+
+	SHA_Init(&ctx);
+	
+	SHA_Update(&ctx, text, size);
+	
+	SHA_Final(digest, &ctx);
+}
+
+void aes_sha_combo(void* ctx, void* plaintext, void* ciphertext, int size, void* tag)
+{
+SHA_CTX sha_ctx;
+uint8_t iv[16];
+AES_KEY* key = ctx;
+
+	SHA_Init(&sha_ctx);
+	
+	SHA_Update(&sha_ctx, plaintext, size);
+	
+	SHA_Final(tag, &sha_ctx);
+	
+	AES_cbc_encrypt(plaintext, ciphertext, size, key, iv, 1);
+}
+
+int main()
+{
+int ret;
+AES_KEY key;
+uint8_t ukey[16];
+
+	ret = hash_test(CRYPTO_SHA1, sha_hash);
+	if (ret > 0)
+		printf("SHA1 in kernel outperforms user-space after %d input bytes\n", ret);
+	
+	memset(ukey, 0xaf, sizeof(ukey));
+	AES_set_encrypt_key(ukey, 16, &key);
+	
+	ret = aead_test(CRYPTO_AES_CBC, CRYPTO_SHA1, ukey, 16, &key, aes_sha_combo);
+	if (ret > 0)
+		printf("AES-SHA1 in kernel outperforms user-space after %d input bytes\n", ret);
+	
+	return 0;
+}
-- 
2.1.0

